@thanh01.pmt/curriculum-kit 1.4.43 → 1.4.45

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.
Files changed (121) hide show
  1. package/dist/ai/index.cjs +66 -470
  2. package/dist/ai/index.cjs.map +1 -1
  3. package/dist/ai/index.d.cts +77 -77
  4. package/dist/ai/index.d.ts +77 -77
  5. package/dist/ai/index.mjs +64 -469
  6. package/dist/ai/index.mjs.map +1 -1
  7. package/dist/index.cjs +478 -837
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +124 -58
  10. package/dist/index.d.ts +124 -58
  11. package/dist/index.mjs +470 -829
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/pipeline/index.cjs +99 -484
  14. package/dist/pipeline/index.cjs.map +1 -1
  15. package/dist/pipeline/index.mjs +97 -483
  16. package/dist/pipeline/index.mjs.map +1 -1
  17. package/dist/schemas/index.d.cts +1064 -1064
  18. package/dist/schemas/index.d.ts +1064 -1064
  19. package/dist/standards/index.d.cts +2 -2
  20. package/dist/standards/index.d.ts +2 -2
  21. package/dist/{standardsCoverageGate-49pJq5t8.d.cts → standardsCoverageGate-CLnq0d0s.d.cts} +12 -12
  22. package/dist/{standardsCoverageGate-49pJq5t8.d.ts → standardsCoverageGate-CLnq0d0s.d.ts} +12 -12
  23. package/dist/templates/ACT_template.md +18 -9
  24. package/dist/templates/ALIGNMENT_MATRIX_template.md +5 -0
  25. package/dist/templates/ART_DIRECTION_template.md +7 -0
  26. package/dist/templates/ASSET_MANIFEST_template.md +5 -0
  27. package/dist/templates/BASELINE_STANDARD.md +5 -0
  28. package/dist/templates/BELL_RINGER_template.md +13 -13
  29. package/dist/templates/CHANGELOG_template.md +3 -0
  30. package/dist/templates/CHOICE_BOARD_template.md +8 -5
  31. package/dist/templates/CODE_template.md +5 -6
  32. package/dist/templates/CONTENT_CONTINUITY_template.md +6 -0
  33. package/dist/templates/CONTENT_STYLE_GUIDE_template.md +4 -5
  34. package/dist/templates/CURRICULUM_FRAMEWORK_template.md +5 -6
  35. package/dist/templates/DEPENDENCY_MAP_template.md +3 -4
  36. package/dist/templates/EXIT_TICKET_template.md +8 -8
  37. package/dist/templates/EXT_template.md +3 -0
  38. package/dist/templates/GLOSSARY_template.md +1 -2
  39. package/dist/templates/GRAPHIC_ORGANIZER_template.md +8 -8
  40. package/dist/templates/GUIDE_template.md +5 -6
  41. package/dist/templates/HANDOUT_template.md +5 -6
  42. package/dist/templates/HANDOVER_DOCUMENT_template.md +8 -0
  43. package/dist/templates/KNOWLEDGE_EXPOSITION_template.md +16 -6
  44. package/dist/templates/LAB_TEMPLATE.md +78 -0
  45. package/dist/templates/LEARNER_PROFILE_template.md +4 -5
  46. package/dist/templates/LESSONS_LEARNED_template.md +8 -0
  47. package/dist/templates/LESSON_5E_template.md +24 -9
  48. package/dist/templates/LESSON_EDP_template.md +26 -10
  49. package/dist/templates/LESSON_GENERAL_template.md +22 -8
  50. package/dist/templates/OUTPUT_CONSTRAINTS_template.md +7 -0
  51. package/dist/templates/PACKAGING_SPEC_template.md +8 -0
  52. package/dist/templates/PILOT_FEEDBACK_template.md +6 -0
  53. package/dist/templates/PROJECT_BRIEF_template.md +8 -0
  54. package/dist/templates/PROJECT_STATUS_template.md +9 -0
  55. package/dist/templates/QUIZ_template.md +7 -0
  56. package/dist/templates/QUIZ_v4.6_template.md +4 -5
  57. package/dist/templates/REFERENCE_PACK_template.md +4 -0
  58. package/dist/templates/REVIEW_GAME_template.md +11 -8
  59. package/dist/templates/RUBRIC_template.md +2 -3
  60. package/dist/templates/SCIENCE_LAB_template.md +11 -5
  61. package/dist/templates/SECTION_LANGUAGE_CONTRACT_template.md +44 -0
  62. package/dist/templates/SELF_LAB_template.md +174 -0
  63. package/dist/templates/SLIDE_template.md +23 -0
  64. package/dist/templates/STATION_ROTATION_template.md +11 -11
  65. package/dist/templates/TASK_CARDS_template.md +8 -8
  66. package/dist/templates/TIERED_PRACTICE_template.md +14 -10
  67. package/dist/templates/UPDATE_ROADMAP_template.md +7 -0
  68. package/dist/templates/WKS_template.md +5 -6
  69. package/dist/workflow/index.cjs +250 -672
  70. package/dist/workflow/index.cjs.map +1 -1
  71. package/dist/workflow/index.d.cts +1 -1
  72. package/dist/workflow/index.d.ts +1 -1
  73. package/dist/workflow/index.mjs +248 -670
  74. package/dist/workflow/index.mjs.map +1 -1
  75. package/docs/refs/templates/ACT_template.md +18 -9
  76. package/docs/refs/templates/ALIGNMENT_MATRIX_template.md +5 -0
  77. package/docs/refs/templates/ART_DIRECTION_template.md +7 -0
  78. package/docs/refs/templates/ASSET_MANIFEST_template.md +5 -0
  79. package/docs/refs/templates/BASELINE_STANDARD.md +5 -0
  80. package/docs/refs/templates/BELL_RINGER_template.md +13 -13
  81. package/docs/refs/templates/CHANGELOG_template.md +3 -0
  82. package/docs/refs/templates/CHOICE_BOARD_template.md +8 -5
  83. package/docs/refs/templates/CODE_template.md +5 -6
  84. package/docs/refs/templates/CONTENT_CONTINUITY_template.md +6 -0
  85. package/docs/refs/templates/CONTENT_STYLE_GUIDE_template.md +4 -5
  86. package/docs/refs/templates/CURRICULUM_FRAMEWORK_template.md +5 -6
  87. package/docs/refs/templates/DEPENDENCY_MAP_template.md +3 -4
  88. package/docs/refs/templates/EXIT_TICKET_template.md +8 -8
  89. package/docs/refs/templates/EXT_template.md +3 -0
  90. package/docs/refs/templates/GLOSSARY_template.md +1 -2
  91. package/docs/refs/templates/GRAPHIC_ORGANIZER_template.md +8 -8
  92. package/docs/refs/templates/GUIDE_template.md +5 -6
  93. package/docs/refs/templates/HANDOUT_template.md +5 -6
  94. package/docs/refs/templates/HANDOVER_DOCUMENT_template.md +8 -0
  95. package/docs/refs/templates/KNOWLEDGE_EXPOSITION_template.md +16 -6
  96. package/docs/refs/templates/LAB_TEMPLATE.md +78 -0
  97. package/docs/refs/templates/LEARNER_PROFILE_template.md +4 -5
  98. package/docs/refs/templates/LESSONS_LEARNED_template.md +8 -0
  99. package/docs/refs/templates/LESSON_5E_template.md +24 -9
  100. package/docs/refs/templates/LESSON_EDP_template.md +26 -10
  101. package/docs/refs/templates/LESSON_GENERAL_template.md +22 -8
  102. package/docs/refs/templates/OUTPUT_CONSTRAINTS_template.md +7 -0
  103. package/docs/refs/templates/PACKAGING_SPEC_template.md +8 -0
  104. package/docs/refs/templates/PILOT_FEEDBACK_template.md +6 -0
  105. package/docs/refs/templates/PROJECT_BRIEF_template.md +8 -0
  106. package/docs/refs/templates/PROJECT_STATUS_template.md +9 -0
  107. package/docs/refs/templates/QUIZ_template.md +7 -0
  108. package/docs/refs/templates/QUIZ_v4.6_template.md +4 -5
  109. package/docs/refs/templates/REFERENCE_PACK_template.md +4 -0
  110. package/docs/refs/templates/REVIEW_GAME_template.md +11 -8
  111. package/docs/refs/templates/RUBRIC_template.md +2 -3
  112. package/docs/refs/templates/SCIENCE_LAB_template.md +11 -5
  113. package/docs/refs/templates/SECTION_LANGUAGE_CONTRACT_template.md +44 -0
  114. package/docs/refs/templates/SELF_LAB_template.md +174 -0
  115. package/docs/refs/templates/SLIDE_template.md +23 -0
  116. package/docs/refs/templates/STATION_ROTATION_template.md +11 -11
  117. package/docs/refs/templates/TASK_CARDS_template.md +8 -8
  118. package/docs/refs/templates/TIERED_PRACTICE_template.md +14 -10
  119. package/docs/refs/templates/UPDATE_ROADMAP_template.md +7 -0
  120. package/docs/refs/templates/WKS_template.md +5 -6
  121. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,8 +1,9 @@
1
- import fs2 from 'fs';
2
- import path3 from 'path';
1
+ import fs3 from 'fs';
2
+ import path4 from 'path';
3
3
  import { createGoogleGenerativeAI } from '@ai-sdk/google';
4
4
  import { createOpenAI } from '@ai-sdk/openai';
5
5
  import { createDeepSeek } from '@ai-sdk/deepseek';
6
+ import { fileURLToPath } from 'url';
6
7
  import { z } from 'zod';
7
8
  import { generateObject, streamObject, streamText, generateText } from 'ai';
8
9
  import pRetry from 'p-retry';
@@ -11,7 +12,6 @@ import pLimit from 'p-limit';
11
12
  import fsPromises from 'fs/promises';
12
13
  import crypto, { createHash } from 'crypto';
13
14
  import { createClient } from '@supabase/supabase-js';
14
- import { fileURLToPath } from 'url';
15
15
  import { Octokit } from '@octokit/rest';
16
16
 
17
17
  var __defProp = Object.defineProperty;
@@ -165,18 +165,18 @@ function resolveApiKey(keyName, explicitKey) {
165
165
  try {
166
166
  const currentDir = process.cwd();
167
167
  const envPaths = [
168
- path3.resolve(currentDir, ".env.local"),
169
- path3.resolve(currentDir, ".env"),
170
- path3.resolve(currentDir, "apps/web/.env.local"),
171
- path3.resolve(currentDir, "packages/learnwell-platform/.env"),
172
- path3.resolve(currentDir, "..", ".env.local"),
173
- path3.resolve(currentDir, "..", ".env"),
174
- path3.resolve(currentDir, "../..", ".env.local"),
175
- path3.resolve(currentDir, "../..", ".env")
168
+ path4.resolve(currentDir, ".env.local"),
169
+ path4.resolve(currentDir, ".env"),
170
+ path4.resolve(currentDir, "apps/web/.env.local"),
171
+ path4.resolve(currentDir, "packages/learnwell-platform/.env"),
172
+ path4.resolve(currentDir, "..", ".env.local"),
173
+ path4.resolve(currentDir, "..", ".env"),
174
+ path4.resolve(currentDir, "../..", ".env.local"),
175
+ path4.resolve(currentDir, "../..", ".env")
176
176
  ];
177
177
  for (const envPath of envPaths) {
178
- if (fs2.existsSync(envPath)) {
179
- const content = fs2.readFileSync(envPath, "utf-8");
178
+ if (fs3.existsSync(envPath)) {
179
+ const content = fs3.readFileSync(envPath, "utf-8");
180
180
  for (const line of content.split("\n")) {
181
181
  const trimmed = line.trim();
182
182
  if (trimmed && !trimmed.startsWith("#") && trimmed.startsWith(keyName + "=")) {
@@ -1166,6 +1166,229 @@ var init_provider_factory = __esm({
1166
1166
  };
1167
1167
  }
1168
1168
  });
1169
+ function stripTemplateFrontmatter(raw) {
1170
+ let body = raw;
1171
+ if (body.startsWith("---")) {
1172
+ const end = body.indexOf("\n---", 3);
1173
+ if (end !== -1) body = body.slice(end + 4);
1174
+ }
1175
+ return body.split("\n").filter((l) => l.trim() !== "<!-- INJECT_BODY -->").join("\n").replace(/^\s*\n/, "").trimEnd();
1176
+ }
1177
+ function extractRequiredSections(raw) {
1178
+ const lines = raw.split("\n");
1179
+ const start = lines.findIndex((l) => /^template_required_sections:\s*$/.test(l.trim()));
1180
+ if (start === -1) return null;
1181
+ const items = [];
1182
+ for (let i = start + 1; i < lines.length; i++) {
1183
+ const line = lines[i] ?? "";
1184
+ if (line.trim() === "") continue;
1185
+ if (!/^\s+-\s/.test(line)) break;
1186
+ items.push(line.trim().replace(/^-\s+/, "").replace(/^["']|["']$/g, ""));
1187
+ }
1188
+ return items.length > 0 ? items : null;
1189
+ }
1190
+ function stripHeadingKey(h) {
1191
+ return h.replace(/\[(REQUIRED|OPTIONAL|CONDITIONAL)\]\s*/gi, "").replace(/^\s*\d+[.)]\s+/, "").replace(/\s+/g, " ").trim();
1192
+ }
1193
+ function isVariableHeading(text) {
1194
+ return /\{\{[^}]*\}\}/.test(text) || /\[[^\]]+\]/.test(text);
1195
+ }
1196
+ function collectHeadings(body) {
1197
+ const out = [];
1198
+ let inFence = false;
1199
+ for (const line of body.split("\n")) {
1200
+ if (/^(```|~~~)/.test(line.trim())) {
1201
+ inFence = !inFence;
1202
+ continue;
1203
+ }
1204
+ if (inFence) continue;
1205
+ const m = line.match(/^(#{2,3})\s+(.*)$/);
1206
+ if (!m) continue;
1207
+ const text = m[2].trim();
1208
+ const optional = /^\[OPTIONAL\]/i.test(text);
1209
+ const name = stripHeadingKey(text);
1210
+ if (!name || isVariableHeading(name)) continue;
1211
+ out.push({ level: m[1].length, name, optional });
1212
+ }
1213
+ return out;
1214
+ }
1215
+ function extractEchoSections(raw) {
1216
+ const hs = collectHeadings(stripTemplateFrontmatter(raw));
1217
+ return {
1218
+ required: hs.filter((h) => !h.optional).map((h) => h.name),
1219
+ optional: hs.filter((h) => h.optional).map((h) => h.name)
1220
+ };
1221
+ }
1222
+ function extractConditionalSections(raw) {
1223
+ const body = stripTemplateFrontmatter(raw);
1224
+ return body.split("\n").filter((l) => /^#{2,3} .*\[CONDITIONAL\]/i.test(l)).map((l) => stripHeadingKey(l.replace(/^#{2,3}\s*/, "").trim())).filter((s) => s.length > 0 && !isVariableHeading(s));
1225
+ }
1226
+ function extractDeclaredLanguage(raw) {
1227
+ const m = raw.match(/^template_language:\s*["']?([a-zA-Z-]+)["']?\s*$/m);
1228
+ return m?.[1]?.toLowerCase() || "en";
1229
+ }
1230
+ function candidateDirs(explicitDir) {
1231
+ const dirs = [];
1232
+ if (explicitDir) dirs.push(explicitDir);
1233
+ if (process.env.CURRICULUM_TEMPLATES_DIR) dirs.push(process.env.CURRICULUM_TEMPLATES_DIR);
1234
+ dirs.push(path4.resolve(process.cwd(), "_templates"));
1235
+ for (const rel of KIT_TEMPLATE_FALLBACK_DIRS) {
1236
+ dirs.push(path4.resolve(_moduleDir, rel));
1237
+ dirs.push(path4.resolve(process.cwd(), rel));
1238
+ dirs.push(path4.resolve(process.cwd(), "packages/curriculum-kit", rel));
1239
+ }
1240
+ return dirs;
1241
+ }
1242
+ function findTemplatePath(templateName, explicitDir) {
1243
+ for (const dir of candidateDirs(explicitDir)) {
1244
+ const p = path4.join(dir, templateName);
1245
+ if (!fs3.existsSync(p)) continue;
1246
+ try {
1247
+ fs3.accessSync(p, fs3.constants.R_OK);
1248
+ return p;
1249
+ } catch {
1250
+ }
1251
+ }
1252
+ return null;
1253
+ }
1254
+ function resolveArtifactTemplate(templateName, opts) {
1255
+ const p = findTemplatePath(templateName, opts?.templatesDir);
1256
+ if (!p) return null;
1257
+ try {
1258
+ const raw = fs3.readFileSync(p, "utf-8");
1259
+ const echo = extractEchoSections(raw);
1260
+ return {
1261
+ content: stripTemplateFrontmatter(raw),
1262
+ sections: echo.required,
1263
+ optionalSections: echo.optional,
1264
+ sourcePath: p,
1265
+ conditionals: extractConditionalSections(raw),
1266
+ declaredLang: extractDeclaredLanguage(raw)
1267
+ };
1268
+ } catch {
1269
+ return null;
1270
+ }
1271
+ }
1272
+ function assembleTranslatedTemplate(templateName, translatedBody, targetLanguage, opts) {
1273
+ const raw = loadCurriculumTemplate(templateName, opts?.templatesDir);
1274
+ if (!raw || !translatedBody?.trim()) return null;
1275
+ const base = collectHeadings(stripTemplateFrontmatter(raw));
1276
+ const out = collectHeadings(translatedBody);
1277
+ if (base.length !== out.length) return null;
1278
+ for (let i = 0; i < base.length; i++) {
1279
+ if (base[i].level !== out[i].level || base[i].optional !== out[i].optional) return null;
1280
+ }
1281
+ const srcBody = stripTemplateFrontmatter(raw);
1282
+ for (const ph of new Set(srcBody.match(/\{\{[^}]+\}\}/g) ?? [])) {
1283
+ if (!translatedBody.includes(ph)) return null;
1284
+ }
1285
+ for (const mk of new Set(srcBody.match(/<!--\s*\[\/?[^\]]+\]\s*-->/g) ?? [])) {
1286
+ if (!translatedBody.includes(mk)) return null;
1287
+ }
1288
+ const lang = targetLanguage.trim().toLowerCase() || "en";
1289
+ const req = out.filter((h) => !h.optional).map((h) => h.name);
1290
+ let fmRaw = "";
1291
+ if (raw.startsWith("---")) {
1292
+ const end = raw.indexOf("\n---", 3);
1293
+ if (end !== -1) fmRaw = raw.slice(0, end + 4);
1294
+ }
1295
+ const fm = stampEchoOnFrontmatter(fmRaw || "---\n---", lang, req);
1296
+ return { raw: `${fm}
1297
+ ${translatedBody.trimStart()}`, sections: req, templateLanguage: lang };
1298
+ }
1299
+ function stampEchoOnFrontmatter(rawDoc, lang, sections) {
1300
+ const echoLines = ['template_language: "' + lang + '"', "template_required_sections:", ...sections.map((n) => ` - "${n.replace(/"/g, '\\"')}"`)];
1301
+ if (rawDoc.startsWith("---")) {
1302
+ const lines = rawDoc.split("\n");
1303
+ const closeIdx = lines.findIndex((l, i) => i > 0 && l.trim() === "---");
1304
+ if (closeIdx === -1) {
1305
+ return ["---", ...echoLines, "---", "", stripTemplateFrontmatter(rawDoc)].join("\n");
1306
+ }
1307
+ const kept = [];
1308
+ let skippingList = false;
1309
+ for (const l of lines.slice(0, closeIdx)) {
1310
+ const t = l.trim();
1311
+ if (/^template_required_sections:$/.test(t)) {
1312
+ skippingList = true;
1313
+ continue;
1314
+ }
1315
+ if (/^template_language:/.test(t)) continue;
1316
+ if (skippingList) {
1317
+ if (/^\s+-\s/.test(l)) continue;
1318
+ skippingList = false;
1319
+ }
1320
+ kept.push(l);
1321
+ }
1322
+ return [...kept, ...echoLines, "---", ...lines.slice(closeIdx + 1)].join("\n");
1323
+ }
1324
+ return ["---", ...echoLines, "---", "", rawDoc].join("\n");
1325
+ }
1326
+ async function translateTemplate(templateName, targetLanguage, runner, opts) {
1327
+ const raw = loadCurriculumTemplate(templateName, opts?.templatesDir);
1328
+ if (!raw) return null;
1329
+ const body = stripTemplateFrontmatter(raw);
1330
+ const placeholders = Array.from(new Set(body.match(/\{\{[^}]+\}\}/g) ?? []));
1331
+ const markers = Array.from(new Set(body.match(/<!--\s*\[\/?[^\]]+\]\s*-->/g) ?? []));
1332
+ const prompt = `Translate the following Markdown artifact TEMPLATE body into ${targetLanguage}.
1333
+ STRICT PRESERVATION RULES (violating any of these invalidates the output):
1334
+ 1. Keep the document structure EXACTLY: same number of headings, same order, same heading levels (## / ###).
1335
+ 2. Translate heading TEXT naturally, but a heading must remain a single static line: move nothing into or out of it. Headings never contain durations or placeholders \u2014 if a source heading carries "[X mins]"-style timing, the timing belongs on the line below the heading, not inside it.
1336
+ 3. Keep every placeholder token VERBATIM (do not translate or alter), including {{ XX }}-style duration tokens: ${placeholders.join(" ") || "(none)"}
1337
+ 4. Keep every HTML comment marker VERBATIM: ${markers.join(" ") || "(none)"}
1338
+ 5. Keep code blocks, file paths, technical identifiers (API names, protocols, component models) untranslated.
1339
+ 6. Translate ONLY natural-language prose, headings, and table headers into natural ${targetLanguage}.
1340
+ 7. Output ONLY the translated markdown \u2014 no explanations, no code fences around the whole document.
1341
+
1342
+ TEMPLATE BODY:
1343
+ ${body}`;
1344
+ let translatedBody;
1345
+ try {
1346
+ translatedBody = await runner(prompt);
1347
+ } catch {
1348
+ return null;
1349
+ }
1350
+ if (!translatedBody || translatedBody.length < body.length * 0.4) return null;
1351
+ translatedBody = translatedBody.trim().replace(/^```(?:markdown)?\n/, "").replace(/\n```$/, "");
1352
+ return assembleTranslatedTemplate(templateName, translatedBody, targetLanguage, opts);
1353
+ }
1354
+ function loadCurriculumTemplate(templateName, templatesDir) {
1355
+ const p = findTemplatePath(templateName, templatesDir);
1356
+ if (!p) return "";
1357
+ try {
1358
+ return fs3.readFileSync(p, "utf-8");
1359
+ } catch {
1360
+ return "";
1361
+ }
1362
+ }
1363
+ function loadAuthoringTemplate(templateName, templatesDir) {
1364
+ const p = findTemplatePath(templateName, templatesDir);
1365
+ if (!p) return "";
1366
+ try {
1367
+ return stripTemplateFrontmatter(fs3.readFileSync(p, "utf-8"));
1368
+ } catch {
1369
+ return "";
1370
+ }
1371
+ }
1372
+ var KIT_TEMPLATE_FALLBACK_DIRS, _moduleDir;
1373
+ var init_templateLoader = __esm({
1374
+ "src/services/templateLoader.ts"() {
1375
+ KIT_TEMPLATE_FALLBACK_DIRS = [
1376
+ // Packaged with the npm bundle (dist/templates) — resolves from node_modules.
1377
+ "templates",
1378
+ // Repo checkout layouts.
1379
+ "docs/refs/templates"
1380
+ ];
1381
+ _moduleDir = (() => {
1382
+ try {
1383
+ if (typeof import.meta !== "undefined" && typeof import.meta.url === "string") {
1384
+ return path4.dirname(fileURLToPath(import.meta.url));
1385
+ }
1386
+ } catch {
1387
+ }
1388
+ return typeof __dirname !== "undefined" ? __dirname : process.cwd();
1389
+ })();
1390
+ }
1391
+ });
1169
1392
 
1170
1393
  // src/pipeline/artifactLinter.ts
1171
1394
  var artifactLinter_exports = {};
@@ -1532,14 +1755,26 @@ function parseLessonFlow(lessonMarkdown) {
1532
1755
  }
1533
1756
  }
1534
1757
  }
1535
- const flowMatch = lessonMarkdown.match(/##\s*\[?REQUIRED\]?\s*B\.\s*Lesson Flow([\s\S]*?)$/i);
1758
+ const flowMatch = lessonMarkdown.match(/##\s*(?:\[?REQUIRED\]?\s*)?B\.\s*Lesson Flow([\s\S]*?)$/i);
1536
1759
  const flowSection = flowMatch ? flowMatch[1] : lessonMarkdown;
1537
- const phaseRegex = /###\s*(?:(\d+)\.\s*)?([^\n—\-]+)(?:[—\-]\s*\[?([^\]\n]+)\]?)?\s*\n([\s\S]*?)(?=(?:###\s*(?:\d+\.)?|$))/gi;
1760
+ const phaseRegex = /###\s*(?:(\d+)\.\s*)?([^\n]+)\n([\s\S]*?)(?=(?:###\s*(?:\d+\.)?|$))/gi;
1538
1761
  let pMatch;
1539
1762
  while ((pMatch = phaseRegex.exec(flowSection)) !== null) {
1540
- const rawPhaseName = pMatch[2].trim();
1541
- const timing = pMatch[3]?.trim();
1542
- const content = pMatch[4].trim();
1763
+ const headingText = pMatch[2].trim();
1764
+ const tailMatch = headingText.match(/[—–-]\s*\[?([^\]—–]+)\]?\s*$/);
1765
+ const tail = tailMatch?.[1]?.trim() ?? "";
1766
+ const rawPhaseName = stripHeadingKey(
1767
+ tailMatch && /mins?/i.test(tail) ? headingText.slice(0, tailMatch.index).trim() : headingText
1768
+ );
1769
+ let content = pMatch[3].trim();
1770
+ let timing;
1771
+ const durMatch2 = content.match(/^>?\s*\**Duration:?\**\s*([~0-9][^\n]*)/i);
1772
+ if (durMatch2) {
1773
+ timing = durMatch2[1].trim();
1774
+ content = content.replace(/^>?\s*\**Duration:?\**\s*[^\n]*\n?/i, "").trim();
1775
+ } else if (tail && /mins?/i.test(tail)) {
1776
+ timing = tail;
1777
+ }
1543
1778
  const codeSnippets = [];
1544
1779
  const codeRegex = /```(?:[a-zA-Z0-9_\-]+)?\s*\n([\s\S]*?)```/g;
1545
1780
  let cMatch;
@@ -1567,6 +1802,7 @@ function parseLessonFlow(lessonMarkdown) {
1567
1802
  }
1568
1803
  var init_lessonFlowParser = __esm({
1569
1804
  "src/parsers/lessonFlowParser.ts"() {
1805
+ init_templateLoader();
1570
1806
  }
1571
1807
  });
1572
1808
 
@@ -3933,468 +4169,8 @@ var RoadmapInputSchema = z.object({
3933
4169
  // src/ai/index.ts
3934
4170
  init_provider_factory();
3935
4171
 
3936
- // src/templates/lessonTemplate.ts
3937
- var LESSON_PLAN_TEMPLATE = `
3938
- ---
3939
- id: "{{ID}}"
3940
- title: "{{TITLE}}"
3941
- type: "LESSON_5E"
3942
- created_by: "Curriculum OS Builder"
3943
- phase: "{{PHASE}}"
3944
- deliverable: "P3-T1"
3945
- version: "{{VERSION}}"
3946
- date: "{{DATE}}"
3947
- prerequisite: []
3948
- template_contract: "lesson-plan-v2"
3949
- template_required_sections:
3950
- - "A. Lesson Design Plan"
3951
- - "Learning Objectives & Evidence"
3952
- - "Activity Sequence"
3953
- - "Resource Map"
3954
- - "Assessment Map"
3955
- - "Artifact Contract"
3956
- - "B. Lesson Flow"
3957
- ---
3958
- <!-- INJECT_BODY -->
3959
-
3960
- # LESSON [{{LESSON_ID}}]: {{TITLE}} (5E Model)
3961
-
3962
- ## [REQUIRED] A. Lesson Design Plan
3963
-
3964
- ### 1. Learning Objectives & Evidence
3965
- - **Estimated Duration:** {{DURATION}}
3966
- - **Materials & Equipment:** {{MATERIALS_SUMMARY}}
3967
- - **Keywords / Core Concepts:** {{KEYWORDS}}
3968
-
3969
- | LO | Objective (Bloom's) | Student Evidence | Success Criteria |
3970
- |---|---|---|---|
3971
- {{LEARNING_OBJECTIVES_TABLE_ROWS}}
3972
-
3973
- ### 2. Activity Sequence
3974
- > This is the canonical activity contract. Satellite artifacts must expand this sequence and must not invent a different one.
3975
-
3976
- | Seq | 5E Phase | Activity Type | Actor | Purpose | Student Action | Teacher Move | Output/Evidence | LO | Time | Artifact Contract |
3977
- |---|---|---|---|---|---|---|---|---|---|---|
3978
- {{ACTIVITY_SEQUENCE_TABLE_ROWS}}
3979
-
3980
- ### 3. Resource Map
3981
- | Resource | Used In Activity | Purpose | Owner Artifact |
3982
- |---|---|---|---|
3983
- {{RESOURCE_MAP_TABLE_ROWS}}
3984
-
3985
- ### 4. Assessment Map
3986
- | Evidence | Assessed By | Criteria | Follow-up If Missing |
3987
- |---|---|---|---|
3988
- {{ASSESSMENT_MAP_TABLE_ROWS}}
3989
-
3990
- ### 5. Artifact Contract
3991
- - **ACT must expand:** {{ACT_CONTRACT}}
3992
- - **GUIDE must support:** {{GUIDE_CONTRACT}}
3993
- - **SLIDE must visualize:** {{SLIDE_CONTRACT}}
3994
- - **HANDOUT must provide:** {{HANDOUT_CONTRACT}}
3995
- - **WKS must practice:** {{WKS_CONTRACT}}
3996
- - **QUIZ must assess:** {{QUIZ_CONTRACT}}
3997
- - **EXT must extend:** {{EXT_CONTRACT}}
3998
-
3999
- ---
4000
-
4001
- ## [REQUIRED] B. Lesson Flow
4002
-
4003
- ### 1. ENGAGE \u2014 {{ENGAGE_DURATION}} mins
4004
- - **Hook Scenario:** {{HOOK_SCENARIO}}
4005
- - **Open Question:** {{HOOK_OPEN_QUESTION}}
4006
- - **Transition:** {{HOOK_TRANSITION}}
4007
-
4008
- ### 2. EXPLORE \u2014 {{EXPLORE_DURATION}} mins
4009
- - **Activity Reference:** {{EXPLORE_ACTIVITY_REF}}
4010
- - **Student Discovery:** {{EXPLORE_STUDENT_DISCOVERY}}
4011
-
4012
- ### 3. EXPLAIN \u2014 {{EXPLAIN_DURATION}} mins
4013
- - **Definitions:**
4014
- {{EXPLAIN_DEFINITIONS}}
4015
- - **Visual Illustration (REQUIRED):**
4016
- {{EXPLAIN_VISUAL_ILLUSTRATION}}
4017
-
4018
- ### 4. ELABORATE \u2014 {{ELABORATE_DURATION}} mins
4019
- - **Tiered Scaffolding:**
4020
- - \u{1F949} **Bronze:** {{DIFFERENTIATION_BRONZE}}
4021
- - \u{1F948} **Silver:** {{DIFFERENTIATION_SILVER}}
4022
- - \u{1F947} **Gold:** {{DIFFERENTIATION_GOLD}}
4023
-
4024
- > **ACT Contract**: Detailed operational instructions must expand the Activity Sequence above and must not change the planned evidence target.
4025
-
4026
- ### 5. EVALUATE \u2014 {{EVALUATE_DURATION}} mins
4027
- - **Exit Ticket:** {{EXIT_TICKET_CONTENT}}
4028
- - **Closing:** {{CLOSING_REMARKS}}
4029
-
4030
- > **QUIZ Contract**: Detailed assessment criteria and rubrics must assess the evidence and success criteria defined in the Lesson Design Plan.
4031
-
4032
- ---
4033
-
4034
- ## [OPTIONAL] Teacher Notes
4035
- - **Common Pitfalls:**
4036
- {{COMMON_PITFALLS}}
4037
- - **Troubleshooting:**
4038
- {{TROUBLESHOOTING_ROWS}}
4039
-
4040
- ---
4041
-
4042
- ## [REQUIRED] Artifact Linkage (Master Index)
4043
- > List all satellite files used in this lesson.
4044
-
4045
- | Artifact File | Role in the Classroom | When to Use |
4046
- |---|---|---|
4047
- | \`GUIDE_{{LESSON_ID}}.md\` | Detailed Teaching Script | Teacher preparation |
4048
- | \`SLIDE_{{LESSON_ID}}.md\` | Presentation Content | Throughout the session |
4049
- | \`HANDOUT_{{LESSON_ID}}.md\` | Theory Summary for Students | During EXPLAIN phase |
4050
- | \`ACT_{{LESSON_ID}}.md\` | Detailed Learning Activity Operations | During EXPLORE / ELABORATE / checkpoint phases |
4051
- | \`WKS_{{LESSON_ID}}.md\` | Individual Worksheet | Wrap-up or Homework |
4052
- | \`QUIZ_{{LESSON_ID}}.md\` | Assessment Rubric | During EVALUATE phase |
4053
- | \`EXT_{{LESSON_ID}}.md\` | Enrichment Materials | For "Gold" students |
4054
- `.trim();
4055
-
4056
- // src/templates/actTemplate.ts
4057
- var ACT_TEMPLATE = `
4058
- ---
4059
- id: "{{ID}}"
4060
- title: "{{TITLE}}"
4061
- type: "ACT"
4062
- created_by: "Curriculum OS Builder"
4063
- phase: "{{PHASE}}"
4064
- deliverable: "P3-T2"
4065
- version: "{{VERSION}}"
4066
- date: "{{DATE}}"
4067
- template_contract: "artifact-template-v1"
4068
- template_required_sections:
4069
- - "Computational Thinking Focus"
4070
- - "Materials & Setup"
4071
- - "Constraints & Safety"
4072
- - "Active Learning Workflow"
4073
- - "3-Tier Differentiation"
4074
- - "Reflection"
4075
- ---
4076
- <!-- INJECT_BODY -->
4077
-
4078
- # INQUIRY-BASED ACTIVITY: {{TITLE}}
4079
- _Milestone: {{MILESTONE_ID}} | Module: {{MODULE_NAME}} | Lesson: {{LESSON_ID}}_
4080
-
4081
- ## [REQUIRED] Computational Thinking Focus
4082
- - **Problem Statement (Real-world Scenario):** {{PROBLEM_STATEMENT}}
4083
- - **Decomposition:**
4084
- {{DECOMPOSITION_STEPS}}
4085
- - **Algorithm Design:** {{ALGORITHM_DESIGN}}
4086
-
4087
- ## [REQUIRED] Materials & Setup
4088
- - **Reference Material:** Students should use the **HANDOUT** for this lesson as their primary technical reference (lifeline).
4089
- - **Hardware/Software:**
4090
- <!-- [HARDWARE_BOM] -->
4091
- {{HARDWARE_ITEMS}}
4092
- <!-- [/HARDWARE_BOM] -->
4093
- - **Software:** {{SOFTWARE_ITEMS}}
4094
- - **Consumables:** {{CONSUMABLES}}
4095
- - **Other Resources:** {{OTHER_RESOURCES}}
4096
-
4097
- ## [REQUIRED] Constraints & Safety
4098
- - \u26A0\uFE0F **Technical/Safety:** {{SAFETY_WARNING}}
4099
- - \u{1F4A1} **Design Constraint:** {{DESIGN_CONSTRAINT}}
4100
-
4101
- ## [REQUIRED] Active Learning Workflow
4102
-
4103
- ### Phase 1: Planning & Design \u2014 {{PHASE1_DURATION}} mins
4104
- - **Student Task:** Hand-draw (or draft in words) the algorithm flowchart or connection architecture before touching the computer/devices.
4105
- - **Teacher Action:** Walk around to check the logic of each group. Ask inquiry questions:
4106
- {{PHASE1_INQUIRY_QUESTIONS}}
4107
-
4108
- ### Phase 2: Implementation & Discovery \u2014 {{PHASE2_DURATION}} mins
4109
- - **Student Task:** Apply the knowledge from the **HANDOUT** to realize the plan designed in Phase 1. Encourage self-inquiry and documentation lookup.
4110
- - **Teacher Action:** Avoid "hand-holding." Only intervene if a group has been stuck for more than 5 minutes.
4111
- {{PHASE2_GUIDANCE_BLOCK}}
4112
-
4113
- ### Phase 3: Debugging & Testing \u2014 {{PHASE3_DURATION}} mins
4114
- - **Testing:** Students run their system.
4115
- - **Error Analysis:** Ask students to record any error codes or unexpected behaviors and compare them with the Troubleshooting table in the Handout.
4116
- {{PHASE3_TESTING_STEPS}}
4117
-
4118
- ## [REQUIRED] 3-Tier Differentiation
4119
- > MUST design tasks in 3 tiers to support diverse learner groups. Bronze is the minimum requirement for all students.
4120
- - \u{1F949} **Bronze (Foundational):** {{DIFFERENTIATION_BRONZE}}
4121
- - \u{1F948} **Silver (Application):** {{DIFFERENTIATION_SILVER}}
4122
- - \u{1F947} **Gold (Enrichment/Creative):** {{DIFFERENTIATION_GOLD}}
4123
-
4124
- ## [REQUIRED] Reflection
4125
- - **Discussion Question:** {{REFLECTION_QUESTION}}
4126
- `.trim();
4127
-
4128
- // src/templates/codeLabTemplate.ts
4129
- var CODE_LAB_TEMPLATE = `
4130
- ---
4131
- id: "{{ID}}"
4132
- title: "{{TITLE}}"
4133
- type: "LAB"
4134
- created_by: "Curriculum OS Builder"
4135
- phase: "{{PHASE}}"
4136
- deliverable: "P3-T2"
4137
- version: "{{VERSION}}"
4138
- date: "{{DATE}}"
4139
- ---
4140
- <!-- INJECT_BODY -->
4141
-
4142
- # \u{1F468}\u200D\u{1F4BB} CODE LAB: {{TITLE}}
4143
- _Milestone: {{MILESTONE_ID}} | Tech Stack: {{TECH_STACK}}_
4144
-
4145
- ## \u{1F3AF} Overview
4146
- This lab focuses on the practical implementation of core technical concepts, bridging theory into working, robust, and testable code.
4147
-
4148
- ## \u{1F6E0}\uFE0F Environment & Setup
4149
- - **Language / Framework:** {{LANGUAGE_FRAMEWORK}}
4150
- - **IDE / Editor:** {{IDE_EDITOR}}
4151
- - **Required Libraries:** {{REQUIRED_LIBRARIES}}
4152
- - **Hardware / Connection Setup:** {{HARDWARE_ENV_CONNECTION}}
4153
-
4154
- ## \u{1F4DD} Lab Tasks (3-Tier Differentiation)
4155
-
4156
- ### \u{1F949} Bronze (Foundational) \u2014 {{BRONZE_MINS}} mins
4157
- **Objective:** {{BRONZE_OBJECTIVE}}
4158
- - **Task:** {{BRONZE_TASK}}
4159
- - **Requirement:** {{BRONZE_REQUIREMENT}}
4160
-
4161
- ### \u{1F948} Silver (Application) \u2014 {{SILVER_MINS}} mins
4162
- **Objective:** {{SILVER_OBJECTIVE}}
4163
- - **Task:** {{SILVER_TASK}}
4164
- - **Requirement:** {{SILVER_REQUIREMENT}}
4165
-
4166
- ### \u{1F947} Gold (Enrichment/Creative) \u2014 {{GOLD_MINS}} mins
4167
- **Objective:** {{GOLD_OBJECTIVE}}
4168
- - **Task:** {{GOLD_TASK}}
4169
- - **Requirement:** {{GOLD_REQUIREMENT}}
4170
-
4171
- ## \u{1F4BB} Technical Reference ([SME_MANDATE])
4172
- <!-- [SME_MANDATE] -->
4173
- > Any code provided in this section is verified for syntax accuracy and runtime execution.
4174
-
4175
- ### Starter Code Template
4176
- \`\`\`{{CODE_LANGUAGE}}
4177
- {{STARTER_CODE}}
4178
- \`\`\`
4179
-
4180
- ### Solution Code
4181
- \`\`\`{{CODE_LANGUAGE}}
4182
- {{SOLUTION_CODE}}
4183
- \`\`\`
4184
- <!-- [/SME_MANDATE] -->
4185
-
4186
- ## \u{1F50D} Troubleshooting & Debugging Matrix
4187
- | Issue | Potential Cause | Solution |
4188
- | :--- | :--- | :--- |
4189
- {{TROUBLESHOOTING_ROWS}}
4190
-
4191
- ## \u{1F3C1} Submission & Verification Checklist
4192
- {{CHECKLIST_ITEMS}}
4193
- `.trim();
4194
-
4195
- // src/templates/quizTemplate.ts
4196
- var QUIZ_TEMPLATE = `
4197
- ---
4198
- id: "{{ID}}"
4199
- title: "{{TITLE}}"
4200
- type: "QUIZ"
4201
- language: "{{LANGUAGE}}"
4202
- total_questions: {{TOTAL_QUESTIONS}}
4203
- passing_score_pct: {{PASSING_SCORE_PCT}}
4204
- ---
4205
-
4206
- # \u{1F9E0} Diagnostic & Active Recall Quiz: {{TITLE}}
4207
-
4208
- > \u23F1\uFE0F **Recommended Time:** ~10-15 mins
4209
- > \u{1F3AF} **Passing Score:** {{PASSING_SCORE_PCT}}%
4210
- > \u{1F4A1} **Purpose:** Test your conceptual understanding, catch hidden misconceptions, and evaluate architectural trade-offs.
4211
-
4212
- ---
4213
-
4214
- {{QUESTIONS_SECTION}}
4215
-
4216
- ---
4217
-
4218
- ## \u{1F511} Comprehensive Answer Key & Deep Explanation (Expand after completing)
4219
- <details>
4220
- <summary><b>\u{1F449} Click to View Full Explanations & Common Pitfall Analysis</b></summary>
4221
-
4222
- {{ANSWER_KEY_SECTION}}
4223
- </details>
4224
- `.trim();
4225
-
4226
- // src/templates/selfLabTemplate.ts
4227
- var SELF_LAB_TEMPLATE = `
4228
- ---
4229
- id: "{{ID}}"
4230
- title: "{{TITLE}}"
4231
- type: "SELF_LAB"
4232
- language: "{{LANGUAGE}}"
4233
- difficulty: "{{DIFFICULTY}}"
4234
- estimated_minutes: {{ESTIMATED_MINUTES}}
4235
- tech_stack: {{TECH_STACK}}
4236
- ---
4237
-
4238
- # \u{1F680} Self-Paced Hands-On Lab: {{TITLE}}
4239
-
4240
- > \u23F1\uFE0F **Estimated Duration:** ~{{ESTIMATED_MINUTES}} mins
4241
- > \u{1F3AF} **Difficulty Level:** {{DIFFICULTY_UPPER}}
4242
- > \u{1F9F0} **Tech Stack:** {{TECH_STACK_STR}}
4243
- > \u{1F4A1} **Self-Learner Notice:** You are in full control of this lab. Follow the progressive challenges below. If you get stuck at any point, use the **Progressive Hints System** to get unstuck without ruining the learning experience!
4244
-
4245
- ---
4246
-
4247
- ## \u{1F4CB} Mission Briefing & Environment Setup
4248
- {{MISSION_BRIEFING}}
4249
-
4250
- ### \u{1F6EB} Preflight Checklist
4251
- {{PREFLIGHT_CHECKLIST}}
4252
-
4253
- ---
4254
-
4255
- ## \u{1F3AF} Progressive Challenges (3-Tier Differentiation)
4256
-
4257
- ### \u{1F949} Challenge 1: Foundational Core (Bronze) \u2014 ~{{BRONZE_MINS}} mins
4258
- **Objective:** {{BRONZE_OBJECTIVE}}
4259
-
4260
- #### Tasks & Implementation Details:
4261
- {{BRONZE_TASKS}}
4262
-
4263
- #### \u{1F9EA} Self-Verification Command:
4264
- \`\`\`bash
4265
- {{BRONZE_VERIFY_COMMAND}}
4266
- \`\`\`
4267
- *Expected Terminal Output:*
4268
- \`\`\`text
4269
- {{BRONZE_EXPECTED_OUTPUT}}
4270
- \`\`\`
4271
-
4272
- #### \u{1F4A1} Progressive Hints (Expand only if stuck):
4273
- <details>
4274
- <summary><b>\u{1F4A1} Hint Level 1: Conceptual Clue (H\u01B0\u1EDBng t\u01B0 duy)</b></summary>
4275
-
4276
- {{BRONZE_HINT_1}}
4277
- </details>
4278
-
4279
- <details>
4280
- <summary><b>\u{1F50D} Hint Level 2: Structural Skeleton (Khung code m\u1EABu)</b></summary>
4281
-
4282
- \`\`\`{{CODE_LANGUAGE}}
4283
- {{BRONZE_HINT_2}}
4284
- \`\`\`
4285
- </details>
4286
-
4287
- <details>
4288
- <summary><b>\u{1F6A8} Hint Level 3: Full Solution & Explanation (L\u1EDDi gi\u1EA3i tr\u1ECDn v\u1EB9n)</b></summary>
4289
-
4290
- \`\`\`{{CODE_LANGUAGE}}
4291
- {{BRONZE_HINT_3_CODE}}
4292
- \`\`\`
4293
-
4294
- **Why this solution works:**
4295
- {{BRONZE_HINT_3_EXPLANATION}}
4296
- </details>
4297
-
4298
- ---
4299
-
4300
- ### \u{1F948} Challenge 2: Logic & Error Handling (Silver) \u2014 ~{{SILVER_MINS}} mins
4301
- **Objective:** {{SILVER_OBJECTIVE}}
4302
-
4303
- #### Tasks & Implementation Details:
4304
- {{SILVER_TASKS}}
4305
-
4306
- #### \u{1F9EA} Self-Verification Command:
4307
- \`\`\`bash
4308
- {{SILVER_VERIFY_COMMAND}}
4309
- \`\`\`
4310
- *Expected Terminal Output:*
4311
- \`\`\`text
4312
- {{SILVER_EXPECTED_OUTPUT}}
4313
- \`\`\`
4314
-
4315
- #### \u{1F4A1} Progressive Hints (Expand only if stuck):
4316
- <details>
4317
- <summary><b>\u{1F4A1} Hint Level 1: Conceptual Clue (H\u01B0\u1EDBng t\u01B0 duy)</b></summary>
4318
-
4319
- {{SILVER_HINT_1}}
4320
- </details>
4321
-
4322
- <details>
4323
- <summary><b>\u{1F50D} Hint Level 2: Structural Skeleton (Khung code m\u1EABu)</b></summary>
4324
-
4325
- \`\`\`{{CODE_LANGUAGE}}
4326
- {{SILVER_HINT_2}}
4327
- \`\`\`
4328
- </details>
4329
-
4330
- <details>
4331
- <summary><b>\u{1F6A8} Hint Level 3: Full Solution & Explanation (L\u1EDDi gi\u1EA3i tr\u1ECDn v\u1EB9n)</b></summary>
4332
-
4333
- \`\`\`{{CODE_LANGUAGE}}
4334
- {{SILVER_HINT_3_CODE}}
4335
- \`\`\`
4336
-
4337
- **Why this solution works:**
4338
- {{SILVER_HINT_3_EXPLANATION}}
4339
- </details>
4340
-
4341
- ---
4342
-
4343
- ### \u{1F947} Challenge 3: Edge Cases & Optimization (Gold) \u2014 ~{{GOLD_MINS}} mins
4344
- **Objective:** {{GOLD_OBJECTIVE}}
4345
-
4346
- #### Tasks & Implementation Details:
4347
- {{GOLD_TASKS}}
4348
-
4349
- #### \u{1F9EA} Self-Verification Command:
4350
- \`\`\`bash
4351
- {{GOLD_VERIFY_COMMAND}}
4352
- \`\`\`
4353
- *Expected Terminal Output:*
4354
- \`\`\`text
4355
- {{GOLD_EXPECTED_OUTPUT}}
4356
- \`\`\`
4357
-
4358
- #### \u{1F4A1} Progressive Hints (Expand only if stuck):
4359
- <details>
4360
- <summary><b>\u{1F4A1} Hint Level 1: Conceptual Clue (H\u01B0\u1EDBng t\u01B0 duy)</b></summary>
4361
-
4362
- {{GOLD_HINT_1}}
4363
- </details>
4364
-
4365
- <details>
4366
- <summary><b>\u{1F50D} Hint Level 2: Structural Skeleton (Khung code m\u1EABu)</b></summary>
4367
-
4368
- \`\`\`{{CODE_LANGUAGE}}
4369
- {{GOLD_HINT_2}}
4370
- \`\`\`
4371
- </details>
4372
-
4373
- <details>
4374
- <summary><b>\u{1F6A8} Hint Level 3: Full Solution & Explanation (L\u1EDDi gi\u1EA3i tr\u1ECDn v\u1EB9n)</b></summary>
4375
-
4376
- \`\`\`{{CODE_LANGUAGE}}
4377
- {{GOLD_HINT_3_CODE}}
4378
- \`\`\`
4379
-
4380
- **Why this solution works:**
4381
- {{GOLD_HINT_3_EXPLANATION}}
4382
- </details>
4383
-
4384
- ---
4385
-
4386
- ## \u{1F50D} Self-Learner Troubleshooting Matrix
4387
- | Symptom / Error Message | Root Cause | Exact Fix |
4388
- | :--- | :--- | :--- |
4389
- {{TROUBLESHOOTING_ROWS}}
4390
-
4391
- ---
4392
-
4393
- ## \u{1F3C1} Final Lab Submission & Mastery Checklist
4394
- {{FINAL_CHECKLIST}}
4395
- `.trim();
4396
-
4397
4172
  // src/ai/prompts/lessonMasterPrompt.ts
4173
+ init_templateLoader();
4398
4174
  function buildLessonMasterPrompt(input) {
4399
4175
  const { milestone, language, topic, targetAudience, contextContinuity, standardsContext } = input;
4400
4176
  const learningObjectives = milestone.learning_objectives || [];
@@ -4446,7 +4222,7 @@ Build a deep, rigorous, and highly pedagogical Master Lesson Plan (LESSON) that
4446
4222
  # MANDATORY TEMPLATE STRUCTURE
4447
4223
  You MUST generate structured data that will render directly into this exact Markdown template:
4448
4224
  ---
4449
- ${LESSON_PLAN_TEMPLATE}
4225
+ ${loadAuthoringTemplate("LESSON_5E_template.md") ?? "[TEMPLATE FILE NOT FOUND: LESSON_5E_template.md]"}
4450
4226
  ---
4451
4227
 
4452
4228
  # INPUT PARAMETERS
@@ -4496,6 +4272,7 @@ Return a single valid JSON object matching the LessonPlanSchema with these exact
4496
4272
  }
4497
4273
 
4498
4274
  // src/ai/prompts/activityPrompt.ts
4275
+ init_templateLoader();
4499
4276
  function buildActivityPrompt(input) {
4500
4277
  const { lesson, language, hardwareBOM, softwareTools } = input;
4501
4278
  const loList = lesson.learningObjectives.map((lo) => `- [${lo.bloomLevel}] ${lo.code}: ${lo.name || ""} \u2014 ${lo.description}${lo.successCriteria ? ` (Evidence: ${lo.successCriteria})` : ""}`).join("\n");
@@ -4524,7 +4301,7 @@ Transform the exact pedagogical flow and activities from the Master Lesson Plan
4524
4301
  # MANDATORY TEMPLATE STRUCTURE
4525
4302
  You MUST generate data aligned with this Markdown template:
4526
4303
  ---
4527
- ${ACT_TEMPLATE}
4304
+ ${loadAuthoringTemplate("ACT_template.md") ?? "[TEMPLATE FILE NOT FOUND: ACT_template.md]"}
4528
4305
  ---
4529
4306
 
4530
4307
  # CANONICAL MASTER LESSON CONTEXT (SOURCE OF TRUTH)
@@ -4595,6 +4372,7 @@ Return a single JSON object matching ActivityLabSchema with these exact keys:
4595
4372
  }
4596
4373
 
4597
4374
  // src/ai/prompts/codeLabPrompt.ts
4375
+ init_templateLoader();
4598
4376
  function buildCodeLabPrompt(input) {
4599
4377
  const { lesson, activity, language, targetTechStack } = input;
4600
4378
  const techStackList = targetTechStack && targetTechStack.length > 0 ? targetTechStack : ["General Programming & Engineering"];
@@ -4619,7 +4397,7 @@ Generate complete, verified source code that satisfies the lesson objectives and
4619
4397
  # MANDATORY TEMPLATE STRUCTURE
4620
4398
  You MUST generate data aligned with this Markdown template:
4621
4399
  ---
4622
- ${CODE_LAB_TEMPLATE}
4400
+ ${loadAuthoringTemplate("LAB_TEMPLATE.md") ?? "[TEMPLATE FILE NOT FOUND: LAB_TEMPLATE.md]"}
4623
4401
  ---
4624
4402
 
4625
4403
  # CANONICAL LESSON CONTEXT (SOURCE OF TRUTH)
@@ -5284,6 +5062,7 @@ Please return a single JSON object matching these exact keys:
5284
5062
  }
5285
5063
 
5286
5064
  // src/ai/prompts/selfLabPrompt.ts
5065
+ init_templateLoader();
5287
5066
  function buildSelfLabPrompt(input) {
5288
5067
  const { milestone, projectGraph, language, targetTechStack, contextContinuity } = input;
5289
5068
  const techStackList = targetTechStack && targetTechStack.length > 0 ? targetTechStack : milestone.tech_keywords && milestone.tech_keywords.length > 0 ? milestone.tech_keywords : ["General Engineering"];
@@ -5314,7 +5093,7 @@ Build a complete, engaging Self-Paced Hands-On Lab (SELF_LAB) for autonomous lea
5314
5093
  # MANDATORY TEMPLATE STRUCTURE
5315
5094
  You MUST generate data aligned with this Markdown template:
5316
5095
  ---
5317
- ${SELF_LAB_TEMPLATE}
5096
+ ${loadAuthoringTemplate("SELF_LAB_template.md") ?? "[TEMPLATE FILE NOT FOUND: SELF_LAB_template.md]"}
5318
5097
  ---
5319
5098
 
5320
5099
  # INPUT PARAMETERS
@@ -5392,6 +5171,7 @@ Return a single valid JSON object matching SelfLabSchema with these exact keys:
5392
5171
  }
5393
5172
 
5394
5173
  // src/ai/prompts/diagnosticQuizPrompt.ts
5174
+ init_templateLoader();
5395
5175
  function buildDiagnosticQuizPrompt(input) {
5396
5176
  const { milestone, language, questionCount = 4, passingScorePct = 80 } = input;
5397
5177
  const learningObjectives = milestone.learning_objectives || [];
@@ -5451,7 +5231,7 @@ Use this mapping to determine which Bloom level each question truly targets. Mat
5451
5231
  # MANDATORY TEMPLATE STRUCTURE
5452
5232
  You MUST generate data aligned with this Markdown template:
5453
5233
  ---
5454
- ${QUIZ_TEMPLATE}
5234
+ ${loadAuthoringTemplate("QUIZ_v4.6_template.md") ?? "[TEMPLATE FILE NOT FOUND: QUIZ_v4.6_template.md]"}
5455
5235
  ---
5456
5236
 
5457
5237
  # INPUT PARAMETERS
@@ -6856,7 +6636,7 @@ ${cc.technicalDepth}`;
6856
6636
  const dataRows = cc.comparisonTable.rows.map((r) => `| ${r.join(" | ")} |`).join("\n");
6857
6637
  str += `
6858
6638
 
6859
- #### Comparison & Trade-off Analysis
6639
+ **Comparison & Trade-off Analysis**
6860
6640
  ${headerRow}
6861
6641
  ${dividerRow}
6862
6642
  ${dataRows}`;
@@ -6900,7 +6680,8 @@ ${learningObjectivesStr}
6900
6680
 
6901
6681
  ---
6902
6682
 
6903
- ## 1. ENGAGE (Hook & High-Stakes Scenario) \u2014 10-15 mins
6683
+ ## 1. ENGAGE (Hook & High-Stakes Scenario)
6684
+ > **Duration:** 10-15 mins
6904
6685
 
6905
6686
  ### Real-World Context: "${lesson.hookTitle || "The Incident"}"
6906
6687
  ${lesson.hookScenario}
@@ -6909,13 +6690,15 @@ ${lesson.hookQuestions && lesson.hookQuestions.length > 0 ? lesson.hookQuestions
6909
6690
 
6910
6691
  ---
6911
6692
 
6912
- ## 2. EXPLORE & EXPLAIN (Core Technical Concepts & Principles) \u2014 30-40 mins
6693
+ ## 2. EXPLORE & EXPLAIN (Core Technical Concepts & Principles)
6694
+ > **Duration:** 30-40 mins
6913
6695
 
6914
6696
  ${coreConceptsStr}
6915
6697
 
6916
6698
  ---
6917
6699
 
6918
- ## 3. GUIDED PRACTICE (Visual Architecture & Annotated Code) \u2014 20-25 mins
6700
+ ## 3. GUIDED PRACTICE (Visual Architecture & Annotated Code)
6701
+ > **Duration:** 20-25 mins
6919
6702
 
6920
6703
  ### System Architecture & Data Flow (Mermaid Diagram)
6921
6704
  ${mermaidBlock}
@@ -6929,7 +6712,8 @@ ${guidedPractice.codeSnippet}
6929
6712
 
6930
6713
  ---
6931
6714
 
6932
- ## 4. ELABORATE & INDEPENDENT PRACTICE (Technical Challenge & Scaffolding) \u2014 15-20 mins
6715
+ ## 4. ELABORATE & INDEPENDENT PRACTICE (Technical Challenge & Scaffolding)
6716
+ > **Duration:** 15-20 mins
6933
6717
 
6934
6718
  ### Engineering Challenge: "${lesson.independentPractice?.title || "System Optimization Challenge"}"
6935
6719
  ${lesson.independentPractice?.description || "Implement the core logic and test against simulated edge cases."}
@@ -6940,7 +6724,8 @@ ${lesson.independentPractice?.description || "Implement the core logic and test
6940
6724
 
6941
6725
  ---
6942
6726
 
6943
- ## 5. EVALUATE (Summary, Assessment & Metacognition) \u2014 5-10 mins
6727
+ ## 5. EVALUATE (Summary, Assessment & Metacognition)
6728
+ > **Duration:** 5-10 mins
6944
6729
 
6945
6730
  ### Exit Ticket (Bloom: Apply / Analyze)
6946
6731
  > **Scenario Question:** ${lesson.exitTicket.questionStem}
@@ -7033,12 +6818,16 @@ ${hardwareItems}
7033
6818
 
7034
6819
  ## [REQUIRED] Active Learning Workflow
7035
6820
 
7036
- ### Phase 1: Planning & Design \u2014 ${phase1.durationMinutes} mins
6821
+ ### Phase 1: Planning & Design
6822
+ > **Duration:** ${phase1.durationMinutes} mins
6823
+
7037
6824
  - **Student Task:** ${phase1.studentTask}
7038
6825
  - **Teacher Action:** ${phase1.teacherAction}
7039
6826
  ${phase1.inquiryQuestions.map((q) => ` - *Inquiry Question:* ${q}`).join("\n")}
7040
6827
 
7041
- ### Phase 2: Implementation & Discovery \u2014 ${phase2.durationMinutes} mins
6828
+ ### Phase 2: Implementation & Discovery
6829
+ > **Duration:** ${phase2.durationMinutes} mins
6830
+
7042
6831
  - **Student Task:** ${phase2.studentTask}
7043
6832
  - **Teacher Action:** ${phase2.teacherAction}
7044
6833
 
@@ -7046,7 +6835,9 @@ ${phase2.codeOrCommands.map((c) => `\`\`\`text
7046
6835
  ${c}
7047
6836
  \`\`\``).join("\n\n")}
7048
6837
 
7049
- ### Phase 3: Debugging & Testing \u2014 ${phase3.durationMinutes} mins
6838
+ ### Phase 3: Debugging & Testing
6839
+ > **Duration:** ${phase3.durationMinutes} mins
6840
+
7050
6841
  - **Testing:** ${phase3.testingSteps}
7051
6842
  - **Error Analysis:** ${phase3.errorAnalysis}
7052
6843
 
@@ -7101,22 +6892,28 @@ This lab focuses on the practical implementation of core technical concepts, bri
7101
6892
 
7102
6893
  ## \u{1F4DD} Lab Tasks (3-Tier Differentiation)
7103
6894
 
7104
- ### \u{1F949} Bronze (Foundational) \u2014 ${tasks.bronze.mins} mins
6895
+ ### \u{1F949} Bronze (Foundational)
6896
+ > **Duration:** ${tasks.bronze.mins} mins
6897
+
7105
6898
  **Objective:** ${tasks.bronze.objective}
7106
6899
  - **Task:** ${tasks.bronze.task}
7107
6900
  - **Requirement:** ${tasks.bronze.requirement}
7108
6901
 
7109
- ### \u{1F948} Silver (Application) \u2014 ${tasks.silver.mins} mins
6902
+ ### \u{1F948} Silver (Application)
6903
+ > **Duration:** ${tasks.silver.mins} mins
6904
+
7110
6905
  **Objective:** ${tasks.silver.objective}
7111
6906
  - **Task:** ${tasks.silver.task}
7112
6907
  - **Requirement:** ${tasks.silver.requirement}
7113
6908
 
7114
- ### \u{1F947} Gold (Enrichment/Creative) \u2014 ${tasks.gold.mins} mins
6909
+ ### \u{1F947} Gold (Enrichment/Creative)
6910
+ > **Duration:** ${tasks.gold.mins} mins
6911
+
7115
6912
  **Objective:** ${tasks.gold.objective}
7116
6913
  - **Task:** ${tasks.gold.task}
7117
6914
  - **Requirement:** ${tasks.gold.requirement}
7118
6915
 
7119
- ## \u{1F4BB} Technical Reference ([SME_MANDATE])
6916
+ ## \u{1F4BB} Technical Reference
7120
6917
  <!-- [SME_MANDATE] -->
7121
6918
  > Any code provided in this section is verified for syntax accuracy and runtime execution.
7122
6919
 
@@ -7254,7 +7051,9 @@ ${instruction.verificationChecklist.map((c) => `- [ ] ${c}`).join("\n")}
7254
7051
  function serializeSelfLabToMarkdown(lab) {
7255
7052
  const renderChallenge = (c, label) => {
7256
7053
  const tasksList = c.tasks.map((t) => `- ${t}`).join("\n");
7257
- return `### ${label}: ${c.title} \u2014 ~${c.estimatedMinutes} mins
7054
+ return `### ${label}: ${c.title}
7055
+ > **Duration:** ~${c.estimatedMinutes} mins
7056
+
7258
7057
  **Objective:** ${c.objective}
7259
7058
 
7260
7059
  #### Tasks & Implementation Details:
@@ -7748,13 +7547,13 @@ async function generateSelfPacedBundle(input) {
7748
7547
  if (input.outputDirectory) {
7749
7548
  await fsPromises.mkdir(input.outputDirectory, { recursive: true });
7750
7549
  await Promise.all([
7751
- fsPromises.writeFile(path3.join(input.outputDirectory, "INSTRUCTION.md"), instructionMd, "utf-8"),
7752
- fsPromises.writeFile(path3.join(input.outputDirectory, "SELF_LAB.md"), selfLabMd, "utf-8"),
7753
- fsPromises.writeFile(path3.join(input.outputDirectory, "QUIZ.md"), quizMd, "utf-8"),
7754
- fsPromises.writeFile(path3.join(input.outputDirectory, "QUIZ.json"), JSON.stringify(quiz, null, 2), "utf-8"),
7755
- fsPromises.writeFile(path3.join(input.outputDirectory, "CHEAT_SHEET.md"), cheatSheetMd, "utf-8"),
7756
- fsPromises.writeFile(path3.join(input.outputDirectory, "LAB.md"), codeLabMd, "utf-8"),
7757
- fsPromises.writeFile(path3.join(input.outputDirectory, "bundle.json"), JSON.stringify(bundle, null, 2), "utf-8")
7550
+ fsPromises.writeFile(path4.join(input.outputDirectory, "INSTRUCTION.md"), instructionMd, "utf-8"),
7551
+ fsPromises.writeFile(path4.join(input.outputDirectory, "SELF_LAB.md"), selfLabMd, "utf-8"),
7552
+ fsPromises.writeFile(path4.join(input.outputDirectory, "QUIZ.md"), quizMd, "utf-8"),
7553
+ fsPromises.writeFile(path4.join(input.outputDirectory, "QUIZ.json"), JSON.stringify(quiz, null, 2), "utf-8"),
7554
+ fsPromises.writeFile(path4.join(input.outputDirectory, "CHEAT_SHEET.md"), cheatSheetMd, "utf-8"),
7555
+ fsPromises.writeFile(path4.join(input.outputDirectory, "LAB.md"), codeLabMd, "utf-8"),
7556
+ fsPromises.writeFile(path4.join(input.outputDirectory, "bundle.json"), JSON.stringify(bundle, null, 2), "utf-8")
7758
7557
  ]);
7759
7558
  }
7760
7559
  return {
@@ -8155,15 +7954,15 @@ var STANDARD_SOT_FILES = [
8155
7954
  "ALIGNMENT_MATRIX.md"
8156
7955
  ];
8157
7956
  function atomicWriteFileSync(targetPath, content) {
8158
- const dir = path3.dirname(targetPath);
8159
- if (!fs2.existsSync(dir)) fs2.mkdirSync(dir, { recursive: true });
8160
- const tmpPath = path3.join(dir, `.${path3.basename(targetPath)}.${process.pid}.${Date.now()}.${crypto.randomBytes(4).toString("hex")}.tmp`);
7957
+ const dir = path4.dirname(targetPath);
7958
+ if (!fs3.existsSync(dir)) fs3.mkdirSync(dir, { recursive: true });
7959
+ const tmpPath = path4.join(dir, `.${path4.basename(targetPath)}.${process.pid}.${Date.now()}.${crypto.randomBytes(4).toString("hex")}.tmp`);
8161
7960
  try {
8162
- fs2.writeFileSync(tmpPath, content, "utf-8");
8163
- fs2.renameSync(tmpPath, targetPath);
7961
+ fs3.writeFileSync(tmpPath, content, "utf-8");
7962
+ fs3.renameSync(tmpPath, targetPath);
8164
7963
  } catch (err) {
8165
7964
  try {
8166
- if (fs2.existsSync(tmpPath)) fs2.unlinkSync(tmpPath);
7965
+ if (fs3.existsSync(tmpPath)) fs3.unlinkSync(tmpPath);
8167
7966
  } catch {
8168
7967
  }
8169
7968
  throw err;
@@ -8172,51 +7971,51 @@ function atomicWriteFileSync(targetPath, content) {
8172
7971
  var FileSystemCurriculumAdapter = class {
8173
7972
  baseDir;
8174
7973
  constructor(options = {}) {
8175
- this.baseDir = options.baseDir || path3.resolve(process.cwd(), "output", "projects");
7974
+ this.baseDir = options.baseDir || path4.resolve(process.cwd(), "output", "projects");
8176
7975
  }
8177
7976
  getProjectDir(projectId) {
8178
7977
  const raw = (projectId || "").replace("proj_", "");
8179
- const directPath = path3.join(this.baseDir, raw);
8180
- if (fs2.existsSync(directPath)) return directPath;
8181
- const fullIdPath = path3.join(this.baseDir, projectId);
8182
- if (fs2.existsSync(fullIdPath)) return fullIdPath;
7978
+ const directPath = path4.join(this.baseDir, raw);
7979
+ if (fs3.existsSync(directPath)) return directPath;
7980
+ const fullIdPath = path4.join(this.baseDir, projectId);
7981
+ if (fs3.existsSync(fullIdPath)) return fullIdPath;
8183
7982
  return directPath;
8184
7983
  }
8185
7984
  /** Ensures the resolved path stays within the project directory (prevents path traversal). */
8186
7985
  assertInsideProject(projectDir, targetPath) {
8187
- const resolvedProject = path3.resolve(projectDir);
8188
- const resolvedTarget = path3.resolve(targetPath);
8189
- if (!resolvedTarget.startsWith(resolvedProject + path3.sep) && resolvedTarget !== resolvedProject) {
7986
+ const resolvedProject = path4.resolve(projectDir);
7987
+ const resolvedTarget = path4.resolve(targetPath);
7988
+ if (!resolvedTarget.startsWith(resolvedProject + path4.sep) && resolvedTarget !== resolvedProject) {
8190
7989
  throw new Error(`[FileSystemCurriculumAdapter] Path traversal blocked: ${targetPath} is outside project directory ${projectDir}`);
8191
7990
  }
8192
7991
  }
8193
7992
  async projectExists(projectId) {
8194
- return fs2.existsSync(this.getProjectDir(projectId));
7993
+ return fs3.existsSync(this.getProjectDir(projectId));
8195
7994
  }
8196
7995
  async readSotDocument(projectId, filename) {
8197
7996
  const projectDir = this.getProjectDir(projectId);
8198
7997
  const possiblePaths = [
8199
- path3.join(projectDir, "_sot", filename),
8200
- path3.join(projectDir, filename)
7998
+ path4.join(projectDir, "_sot", filename),
7999
+ path4.join(projectDir, filename)
8201
8000
  ];
8202
8001
  for (const p of possiblePaths) {
8203
- if (fs2.existsSync(p) && fs2.statSync(p).isFile()) {
8204
- return fs2.readFileSync(p, "utf-8");
8002
+ if (fs3.existsSync(p) && fs3.statSync(p).isFile()) {
8003
+ return fs3.readFileSync(p, "utf-8");
8205
8004
  }
8206
8005
  }
8207
8006
  return null;
8208
8007
  }
8209
8008
  async listSotDocuments(projectId) {
8210
8009
  const projectDir = this.getProjectDir(projectId);
8211
- const sotDir = path3.join(projectDir, "_sot");
8010
+ const sotDir = path4.join(projectDir, "_sot");
8212
8011
  const discoveredFiles = new Set(STANDARD_SOT_FILES);
8213
- if (fs2.existsSync(sotDir)) {
8012
+ if (fs3.existsSync(sotDir)) {
8214
8013
  try {
8215
- const diskFiles = fs2.readdirSync(sotDir);
8014
+ const diskFiles = fs3.readdirSync(sotDir);
8216
8015
  for (const f of diskFiles) {
8217
8016
  if (f.startsWith(".") || f.endsWith(".review.json")) continue;
8218
- const fullPath = path3.join(sotDir, f);
8219
- if (fs2.statSync(fullPath).isFile()) {
8017
+ const fullPath = path4.join(sotDir, f);
8018
+ if (fs3.statSync(fullPath).isFile()) {
8220
8019
  discoveredFiles.add(f);
8221
8020
  }
8222
8021
  }
@@ -8224,9 +8023,9 @@ var FileSystemCurriculumAdapter = class {
8224
8023
  }
8225
8024
  }
8226
8025
  return Array.from(discoveredFiles).map((filename) => {
8227
- const p = fs2.existsSync(path3.join(sotDir, filename)) ? path3.join(sotDir, filename) : fs2.existsSync(path3.join(projectDir, filename)) ? path3.join(projectDir, filename) : null;
8228
- if (p && fs2.existsSync(p)) {
8229
- const stats = fs2.statSync(p);
8026
+ const p = fs3.existsSync(path4.join(sotDir, filename)) ? path4.join(sotDir, filename) : fs3.existsSync(path4.join(projectDir, filename)) ? path4.join(projectDir, filename) : null;
8027
+ if (p && fs3.existsSync(p)) {
8028
+ const stats = fs3.statSync(p);
8230
8029
  return {
8231
8030
  name: filename.replace(/\.(md|json)$/i, "").replace(/_/g, " "),
8232
8031
  filename,
@@ -8244,18 +8043,18 @@ var FileSystemCurriculumAdapter = class {
8244
8043
  }
8245
8044
  async readArtifact(projectId, relPathOrIdentifier) {
8246
8045
  const projectDir = this.getProjectDir(projectId);
8247
- const directCandidate = path3.join(projectDir, relPathOrIdentifier);
8046
+ const directCandidate = path4.join(projectDir, relPathOrIdentifier);
8248
8047
  this.assertInsideProject(projectDir, directCandidate);
8249
8048
  const possiblePaths = [
8250
8049
  directCandidate,
8251
- path3.join(projectDir, "_sot", relPathOrIdentifier),
8252
- path3.join(projectDir, "lessons", relPathOrIdentifier),
8253
- path3.join(projectDir, "_sot", path3.basename(relPathOrIdentifier)),
8254
- path3.join(projectDir, "lessons", path3.basename(relPathOrIdentifier))
8050
+ path4.join(projectDir, "_sot", relPathOrIdentifier),
8051
+ path4.join(projectDir, "lessons", relPathOrIdentifier),
8052
+ path4.join(projectDir, "_sot", path4.basename(relPathOrIdentifier)),
8053
+ path4.join(projectDir, "lessons", path4.basename(relPathOrIdentifier))
8255
8054
  ];
8256
8055
  for (const p of possiblePaths) {
8257
- if (fs2.existsSync(p) && fs2.statSync(p).isFile()) {
8258
- return fs2.readFileSync(p, "utf-8");
8056
+ if (fs3.existsSync(p) && fs3.statSync(p).isFile()) {
8057
+ return fs3.readFileSync(p, "utf-8");
8259
8058
  }
8260
8059
  }
8261
8060
  if (relPathOrIdentifier.includes(".md") || relPathOrIdentifier.includes("/")) {
@@ -8264,8 +8063,8 @@ var FileSystemCurriculumAdapter = class {
8264
8063
  const lessonMatch = relPathOrIdentifier.match(/U\d+_M\d+_L\d+/i);
8265
8064
  if (lessonMatch) {
8266
8065
  const lessonId = lessonMatch[0].toUpperCase();
8267
- const lessonDir = path3.join(projectDir, "lessons", lessonId);
8268
- if (fs2.existsSync(lessonDir) && fs2.statSync(lessonDir).isDirectory()) {
8066
+ const lessonDir = path4.join(projectDir, "lessons", lessonId);
8067
+ if (fs3.existsSync(lessonDir) && fs3.statSync(lessonDir).isDirectory()) {
8269
8068
  const lower = relPathOrIdentifier.toLowerCase();
8270
8069
  let artifactPrefix = "LESSON";
8271
8070
  if (lower.includes("act") || lower.includes("lab") || lower.includes("th\u1EF1c h\xE0nh")) {
@@ -8285,9 +8084,9 @@ var FileSystemCurriculumAdapter = class {
8285
8084
  } else if (lower.includes("ext") || lower.includes("extension")) {
8286
8085
  artifactPrefix = "EXT";
8287
8086
  }
8288
- const candidateFile = path3.join(lessonDir, `${artifactPrefix}_${lessonId}.md`);
8289
- if (fs2.existsSync(candidateFile)) {
8290
- return fs2.readFileSync(candidateFile, "utf-8");
8087
+ const candidateFile = path4.join(lessonDir, `${artifactPrefix}_${lessonId}.md`);
8088
+ if (fs3.existsSync(candidateFile)) {
8089
+ return fs3.readFileSync(candidateFile, "utf-8");
8291
8090
  }
8292
8091
  }
8293
8092
  }
@@ -8295,22 +8094,22 @@ var FileSystemCurriculumAdapter = class {
8295
8094
  }
8296
8095
  async saveArtifact(projectId, relPath, content) {
8297
8096
  const projectDir = this.getProjectDir(projectId);
8298
- const targetPath = path3.join(projectDir, relPath);
8097
+ const targetPath = path4.join(projectDir, relPath);
8299
8098
  this.assertInsideProject(projectDir, targetPath);
8300
- const targetDir = path3.dirname(targetPath);
8301
- if (!fs2.existsSync(targetDir)) {
8302
- fs2.mkdirSync(targetDir, { recursive: true });
8099
+ const targetDir = path4.dirname(targetPath);
8100
+ if (!fs3.existsSync(targetDir)) {
8101
+ fs3.mkdirSync(targetDir, { recursive: true });
8303
8102
  }
8304
- if (fs2.existsSync(targetPath)) {
8103
+ if (fs3.existsSync(targetPath)) {
8305
8104
  try {
8306
- const oldContent = fs2.readFileSync(targetPath, "utf-8");
8105
+ const oldContent = fs3.readFileSync(targetPath, "utf-8");
8307
8106
  if (oldContent !== content) {
8308
- const historyDir = path3.join(projectDir, ".history", relPath);
8309
- fs2.mkdirSync(historyDir, { recursive: true });
8310
- atomicWriteFileSync(path3.join(historyDir, `${Date.now()}.md`), oldContent);
8311
- const versions = fs2.readdirSync(historyDir).filter((f) => f.endsWith(".md")).sort();
8107
+ const historyDir = path4.join(projectDir, ".history", relPath);
8108
+ fs3.mkdirSync(historyDir, { recursive: true });
8109
+ atomicWriteFileSync(path4.join(historyDir, `${Date.now()}.md`), oldContent);
8110
+ const versions = fs3.readdirSync(historyDir).filter((f) => f.endsWith(".md")).sort();
8312
8111
  while (versions.length > 10) {
8313
- fs2.unlinkSync(path3.join(historyDir, versions.shift()));
8112
+ fs3.unlinkSync(path4.join(historyDir, versions.shift()));
8314
8113
  }
8315
8114
  }
8316
8115
  } catch (histErr) {
@@ -8318,24 +8117,24 @@ var FileSystemCurriculumAdapter = class {
8318
8117
  }
8319
8118
  }
8320
8119
  atomicWriteFileSync(targetPath, content);
8321
- const filename = path3.basename(relPath);
8120
+ const filename = path4.basename(relPath);
8322
8121
  const match = filename.match(/(LESSON|ACT|QUIZ|SLIDE|GUIDE|HANDOUT|WKS|EXT)_(U\d+_M\d+_L\d+)\.md/i);
8323
8122
  if (match) {
8324
8123
  const lessonId = match[2].toUpperCase();
8325
- atomicWriteFileSync(path3.join(projectDir, "lessons", lessonId, filename), content);
8326
- const legacyContentDir = path3.join(projectDir, "_content", lessonId);
8327
- if (fs2.existsSync(legacyContentDir)) {
8328
- atomicWriteFileSync(path3.join(legacyContentDir, filename), content);
8124
+ atomicWriteFileSync(path4.join(projectDir, "lessons", lessonId, filename), content);
8125
+ const legacyContentDir = path4.join(projectDir, "_content", lessonId);
8126
+ if (fs3.existsSync(legacyContentDir)) {
8127
+ atomicWriteFileSync(path4.join(legacyContentDir, filename), content);
8329
8128
  }
8330
8129
  }
8331
8130
  }
8332
8131
  async listLessons(projectId) {
8333
- const lessonsDir = path3.join(this.getProjectDir(projectId), "lessons");
8334
- if (!fs2.existsSync(lessonsDir)) return [];
8335
- const lessonFolders = fs2.readdirSync(lessonsDir).filter((f) => !f.startsWith("."));
8132
+ const lessonsDir = path4.join(this.getProjectDir(projectId), "lessons");
8133
+ if (!fs3.existsSync(lessonsDir)) return [];
8134
+ const lessonFolders = fs3.readdirSync(lessonsDir).filter((f) => !f.startsWith("."));
8336
8135
  return lessonFolders.map((folder) => {
8337
- const lDir = path3.join(lessonsDir, folder);
8338
- const isDir = fs2.statSync(lDir).isDirectory();
8136
+ const lDir = path4.join(lessonsDir, folder);
8137
+ const isDir = fs3.statSync(lDir).isDirectory();
8339
8138
  if (!isDir) {
8340
8139
  return {
8341
8140
  lessonId: folder,
@@ -8344,7 +8143,7 @@ var FileSystemCurriculumAdapter = class {
8344
8143
  artifacts: []
8345
8144
  };
8346
8145
  }
8347
- const artifacts = fs2.readdirSync(lDir).filter((f) => !f.startsWith("."));
8146
+ const artifacts = fs3.readdirSync(lDir).filter((f) => !f.startsWith("."));
8348
8147
  return {
8349
8148
  lessonId: folder,
8350
8149
  artifactsCount: artifacts.length,
@@ -8390,10 +8189,10 @@ ${lessonTable}
8390
8189
  }
8391
8190
  async getPipelineState(projectId) {
8392
8191
  const projectDir = this.getProjectDir(projectId);
8393
- const stateFile = path3.join(projectDir, "_pipeline", "state.json");
8394
- if (fs2.existsSync(stateFile)) {
8192
+ const stateFile = path4.join(projectDir, "_pipeline", "state.json");
8193
+ if (fs3.existsSync(stateFile)) {
8395
8194
  try {
8396
- const raw = fs2.readFileSync(stateFile, "utf-8");
8195
+ const raw = fs3.readFileSync(stateFile, "utf-8");
8397
8196
  const parsed = JSON.parse(raw);
8398
8197
  if (parsed && typeof parsed === "object" && parsed.tasks) {
8399
8198
  return parsed;
@@ -8410,11 +8209,11 @@ ${lessonTable}
8410
8209
  }
8411
8210
  async savePipelineState(projectId, state) {
8412
8211
  const projectDir = this.getProjectDir(projectId);
8413
- const pipelineDir = path3.join(projectDir, "_pipeline");
8414
- if (!fs2.existsSync(pipelineDir)) {
8415
- fs2.mkdirSync(pipelineDir, { recursive: true });
8212
+ const pipelineDir = path4.join(projectDir, "_pipeline");
8213
+ if (!fs3.existsSync(pipelineDir)) {
8214
+ fs3.mkdirSync(pipelineDir, { recursive: true });
8416
8215
  }
8417
- const stateFile = path3.join(pipelineDir, "state.json");
8216
+ const stateFile = path4.join(pipelineDir, "state.json");
8418
8217
  state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
8419
8218
  atomicWriteFileSync(stateFile, JSON.stringify(state, null, 2));
8420
8219
  }
@@ -8437,9 +8236,9 @@ ${lessonTable}
8437
8236
  async deleteArtifact(projectId, relPath) {
8438
8237
  try {
8439
8238
  const projectDir = this.getProjectDir(projectId);
8440
- const targetPath = path3.join(projectDir, relPath);
8239
+ const targetPath = path4.join(projectDir, relPath);
8441
8240
  this.assertInsideProject(projectDir, targetPath);
8442
- if (fs2.existsSync(targetPath)) fs2.rmSync(targetPath, { force: true });
8241
+ if (fs3.existsSync(targetPath)) fs3.rmSync(targetPath, { force: true });
8443
8242
  } catch {
8444
8243
  }
8445
8244
  }
@@ -9189,19 +8988,19 @@ function buildStandardStackMarkdown(opts) {
9189
8988
 
9190
8989
  // src/services/sotGeneratorService.ts
9191
8990
  var __filename$1 = typeof import.meta?.url === "string" && typeof fileURLToPath === "function" ? fileURLToPath(import.meta.url) : "";
9192
- var __dirname2 = __filename$1 ? path3.dirname(__filename$1) : process.cwd();
8991
+ var __dirname2 = __filename$1 ? path4.dirname(__filename$1) : process.cwd();
9193
8992
  function loadSotTemplate(templateFileName) {
9194
8993
  const possiblePaths = [
9195
- path3.resolve(__dirname2, "../../docs/refs/templates", templateFileName),
9196
- path3.resolve(process.cwd(), "packages/curriculum-kit/docs/refs/templates", templateFileName),
9197
- path3.resolve(process.cwd(), "../learnwell-platform/packages/curriculum-kit/docs/refs/templates", templateFileName),
9198
- path3.resolve("/Users/tonypham/MEGA/WebApp/WIP/learnwell-platform/packages/curriculum-kit/docs/refs/templates", templateFileName),
9199
- path3.resolve("/Users/tonypham/MEGA/ai-platform/learning-artifact-gen-ui/_templates", templateFileName)
8994
+ path4.resolve(__dirname2, "../../docs/refs/templates", templateFileName),
8995
+ path4.resolve(process.cwd(), "packages/curriculum-kit/docs/refs/templates", templateFileName),
8996
+ path4.resolve(process.cwd(), "../learnwell-platform/packages/curriculum-kit/docs/refs/templates", templateFileName),
8997
+ path4.resolve("/Users/tonypham/MEGA/WebApp/WIP/learnwell-platform/packages/curriculum-kit/docs/refs/templates", templateFileName),
8998
+ path4.resolve("/Users/tonypham/MEGA/ai-platform/learning-artifact-gen-ui/_templates", templateFileName)
9200
8999
  ];
9201
9000
  for (const p of possiblePaths) {
9202
- if (fs2.existsSync(p)) {
9001
+ if (fs3.existsSync(p)) {
9203
9002
  try {
9204
- return fs2.readFileSync(p, "utf-8");
9003
+ return fs3.readFileSync(p, "utf-8");
9205
9004
  } catch {
9206
9005
  }
9207
9006
  }
@@ -9617,6 +9416,7 @@ function gateModeFor(resolved, type) {
9617
9416
  }
9618
9417
 
9619
9418
  // src/services/languageDirective.ts
9419
+ init_templateLoader();
9620
9420
  function resolveTargetLanguageCode(language) {
9621
9421
  const raw = String(language || "vi").trim().toLowerCase();
9622
9422
  if (raw.startsWith("vi")) return "vi";
@@ -9657,137 +9457,58 @@ function matchesArtifactType(candidate, target) {
9657
9457
  if ((c === "EXT" || c === "EXTENSION") && (t === "EXT" || t === "EXTENSION")) return true;
9658
9458
  return false;
9659
9459
  }
9660
- var DEFAULT_VIETNAMESE_SECTION_HEADINGS = {
9661
- LEARNER_PROFILE: {
9662
- "Foundational Info": "Th\xF4ng tin N\u1EC1n t\u1EA3ng",
9663
- "Entry Level": "Tr\xECnh \u0111\u1ED9 \u0110\u1EA7u v\xE0o",
9664
- "Learning Context": "B\u1ED1i c\u1EA3nh H\u1ECDc t\u1EADp",
9665
- "Client Objectives": "M\u1EE5c ti\xEAu Kh\xE1ch h\xE0ng & Chu\u1EA9n \u0111\u1EA7u ra"
9666
- },
9667
- PROJECT_BRIEF: {
9668
- "Project Overview": "T\u1ED5ng quan D\u1EF1 \xE1n",
9669
- "Audience & Duration": "\u0110\u1ED1i t\u01B0\u1EE3ng & Th\u1EDDi l\u01B0\u1EE3ng",
9670
- "Learning Roadmap": "L\u1ED9 tr\xECnh H\u1ECDc t\u1EADp & C\u1ED9t m\u1ED1c",
9671
- "Artifact Scope": "Ph\u1EA1m vi S\u1EA3n ph\u1EA9m H\u1ECDc t\u1EADp"
9672
- },
9673
- CURRICULUM_FRAMEWORK: {
9674
- "Course Overview": "T\u1ED5ng quan Kh\xF3a h\u1ECDc",
9675
- "Global Learning Objectives": "M\u1EE5c ti\xEAu H\u1ECDc t\u1EADp To\xE0n di\u1EC7n",
9676
- "Structural Hierarchy (Unit & Module)": "C\u1EA5u tr\xFAc Kh\xF3a h\u1ECDc (Unit & Module)",
9677
- "Scope & Sequence (Detailed Roadmap)": "Ph\u1EA1m vi & Tr\xECnh t\u1EF1 Chi ti\u1EBFt"
9678
- },
9679
- CONTENT_STYLE_GUIDE: {
9680
- "Voice & Tone": "Gi\u1ECDng v\u0103n & Phong c\xE1ch",
9681
- "Standard Terminology (Glossary)": "Thu\u1EADt ng\u1EEF Chu\u1EA9n (B\u1EA3ng thu\u1EADt ng\u1EEF)",
9682
- "Examples & Context Rules": "Quy t\u1EAFc V\xED d\u1EE5 & Ng\u1EEF c\u1EA3nh",
9683
- "Lesson Content Standards": "Ti\xEAu chu\u1EA9n N\u1ED9i dung B\xE0i h\u1ECDc"
9684
- },
9685
- SECTION_LANGUAGE_CONTRACT: {
9686
- "Metadata & Scope": "Th\xF4ng tin & Ph\u1EA1m vi H\u1EE3p \u0111\u1ED3ng",
9687
- "Section Translation Matrix": "Ma tr\u1EADn Ti\xEAu \u0111\u1EC1 \u0110a ng\xF4n ng\u1EEF",
9688
- "Validation Rules": "Quy t\u1EAFc X\xE1c th\u1EF1c & Kh\xF3a Chu\u1EA9n"
9689
- },
9690
- KNOWLEDGE_EXPOSITION: {
9691
- "Session Scope": "Ph\u1EA1m vi Bu\u1ED5i h\u1ECDc",
9692
- "Key Terms": "Thu\u1EADt ng\u1EEF Then ch\u1ED1t",
9693
- "Concept Narratives": "Di\u1EC5n gi\u1EA3i Kh\xE1i ni\u1EC7m",
9694
- "Worked Micro-Examples": "V\xED d\u1EE5 M\u1EABu Chi ti\u1EBFt",
9695
- "Common Mistakes": "L\u1ED7i Th\u01B0\u1EDDng g\u1EB7p & Kh\u1EAFc ph\u1EE5c",
9696
- "Self-Check Questions": "C\xE2u h\u1ECFi T\u1EF1 ki\u1EC3m tra"
9697
- },
9698
- LESSON: {
9699
- "A. Lesson Design Plan": "A. K\u1EBF ho\u1EA1ch Thi\u1EBFt k\u1EBF B\xE0i h\u1ECDc",
9700
- "Learning Objectives & Evidence": "M\u1EE5c ti\xEAu H\u1ECDc t\u1EADp & B\u1EB1ng ch\u1EE9ng N\u0103ng l\u1EF1c",
9701
- "Activity Sequence": "Chu\u1ED7i Ho\u1EA1t \u0111\u1ED9ng D\u1EA1y & H\u1ECDc",
9702
- "Resource Map": "B\u1EA3n \u0111\u1ED3 T\xE0i nguy\xEAn & H\u1ECDc li\u1EC7u",
9703
- "Assessment Map": "B\u1EA3n \u0111\u1ED3 \u0110\xE1nh gi\xE1 N\u0103ng l\u1EF1c",
9704
- "Artifact Contract": "H\u1EE3p \u0111\u1ED3ng S\u1EA3n ph\u1EA9m \u0110\u1EA7u ra",
9705
- "B. Lesson Flow": "B. Ti\u1EBFn tr\xECnh Gi\u1EA3ng d\u1EA1y Chi ti\u1EBFt"
9706
- },
9707
- ACT: {
9708
- "Computational Thinking Focus": "Tr\u1ECDng t\xE2m T\u01B0 duy M\xE1y t\xEDnh",
9709
- "Materials & Setup": "V\u1EADt li\u1EC7u & Chu\u1EA9n b\u1ECB Thi\u1EBFt b\u1ECB",
9710
- "Constraints & Safety": "R\xE0ng bu\u1ED9c & An to\xE0n Ph\xF2ng th\u1EF1c h\xE0nh",
9711
- "Active Learning Workflow": "Quy tr\xECnh Ho\u1EA1t \u0111\u1ED9ng Tr\u1EA3i nghi\u1EC7m",
9712
- "3-Tier Differentiation": "Ph\xE2n h\xF3a H\u1ECDc t\u1EADp 3 T\u1EA7ng",
9713
- "Reflection": "T\u1ED5ng k\u1EBFt & \u0110\xFAc k\u1EBFt Tr\u1EA3i nghi\u1EC7m"
9714
- },
9715
- CODE: {
9716
- "Technical Overview & Architecture Blueprint": "T\u1ED5ng quan K\u1EF9 thu\u1EADt & B\u1EA3n thi\u1EBFt k\u1EBF Ki\u1EBFn tr\xFAc",
9717
- "Hardware Pinout & Wiring Configuration Matrix": "S\u01A1 \u0111\u1ED3 Ch\xE2n & Ma tr\u1EADn N\u1ED1i d\xE2y Ph\u1EA7n c\u1EE9ng",
9718
- "Starter Code Sandbox": "M\xE3 ngu\u1ED3n Kh\u1EDFi \u0111\u1EA7u (Starter Code)",
9719
- "Verified Reference Solution Code": "M\xE3 ngu\u1ED3n L\u1EDDi gi\u1EA3i Chu\u1EA9n (Reference Solution)",
9720
- "Automated Test / Verification Script": "K\u1ECBch b\u1EA3n Ki\u1EC3m th\u1EED T\u1EF1 \u0111\u1ED9ng",
9721
- "Common Syntax & Runtime Pitfalls Matrix": "Ma tr\u1EADn L\u1ED7i C\xFA ph\xE1p & Th\u1EDDi gian ch\u1EA1y Th\u01B0\u1EDDng g\u1EB7p"
9722
- },
9723
- CODE_LAB: {
9724
- "Technical Overview & Architecture Blueprint": "T\u1ED5ng quan K\u1EF9 thu\u1EADt & B\u1EA3n thi\u1EBFt k\u1EBF Ki\u1EBFn tr\xFAc",
9725
- "Hardware Pinout & Wiring Configuration Matrix": "S\u01A1 \u0111\u1ED3 Ch\xE2n & Ma tr\u1EADn N\u1ED1i d\xE2y Ph\u1EA7n c\u1EE9ng",
9726
- "Starter Code Sandbox": "M\xE3 ngu\u1ED3n Kh\u1EDFi \u0111\u1EA7u (Starter Code)",
9727
- "Verified Reference Solution Code": "M\xE3 ngu\u1ED3n L\u1EDDi gi\u1EA3i Chu\u1EA9n (Reference Solution)",
9728
- "Automated Test / Verification Script": "K\u1ECBch b\u1EA3n Ki\u1EC3m th\u1EED T\u1EF1 \u0111\u1ED9ng",
9729
- "Common Syntax & Runtime Pitfalls Matrix": "Ma tr\u1EADn L\u1ED7i C\xFA ph\xE1p & Th\u1EDDi gian ch\u1EA1y Th\u01B0\u1EDDng g\u1EB7p"
9730
- },
9731
- QUIZ: {
9732
- "Assessment Objectives": "M\u1EE5c ti\xEAu \u0110\xE1nh gi\xE1",
9733
- "Multiple-Choice Question Bank": "Ng\xE2n h\xE0ng C\xE2u h\u1ECFi Tr\u1EAFc nghi\u1EC7m",
9734
- "Code Analysis / Debugging Question": "C\xE2u h\u1ECFi Ph\xE2n t\xEDch M\xE3 ngu\u1ED3n & S\u1EEDa l\u1ED7i",
9735
- "Competency Rubric": "Thang \u0111o \u0110\xE1nh gi\xE1 N\u0103ng l\u1EF1c (Rubric)"
9736
- },
9737
- GUIDE: {
9738
- "Objectives & Preparation": "M\u1EE5c ti\xEAu & Chu\u1EA9n b\u1ECB Gi\u1EA3ng d\u1EA1y",
9739
- "Preparation Checklist & Workstation Setup": "Danh m\u1EE5c Ki\u1EC3m tra Chu\u1EA9n b\u1ECB & Tr\u1EA1m Th\u1EF1c h\xE0nh",
9740
- "Facilitation Script & Timeline": "K\u1ECBch b\u1EA3n \u0110i\u1EC1u ph\u1ED1i & Khung Th\u1EDDi gian",
9741
- "Common Misconceptions & Diagnostic Remediation Matrix": "Quan ni\u1EC7m Sai l\u1EA7m Th\u01B0\u1EDDng g\u1EB7p & Ma tr\u1EADn Kh\u1EAFc ph\u1EE5c",
9742
- "Differentiated Support Strategies": "Chi\u1EBFn l\u01B0\u1EE3c H\u1ED7 tr\u1EE3 Ph\xE2n h\xF3a"
9743
- },
9744
- HANDOUT: {
9745
- "Core Concepts": "Kh\xE1i ni\u1EC7m C\u1ED1t l\xF5i",
9746
- "Core Syntax & Mechanism Cheat Sheet": "B\u1EA3ng Tra c\u1EE9u C\xFA ph\xE1p & C\u01A1 ch\u1EBF Tr\u1ECDng t\xE2m",
9747
- "Visual Mental Model / Architecture Diagram": "M\xF4 h\xECnh T\u01B0 duy Tr\u1EF1c quan / S\u01A1 \u0111\u1ED3 Ki\u1EBFn tr\xFAc",
9748
- "Step-by-Step Practical Quick-Start Guide": "H\u01B0\u1EDBng d\u1EABn Th\u1EF1c h\xE0nh T\u1EEBng b\u01B0\u1EDBc",
9749
- "Self-Check Diagnostic Checklist": "B\u1EA3ng Ki\u1EC3m tra T\u1EF1 ch\u1EA9n \u0111o\xE1n"
9750
- },
9751
- WKS: {
9752
- "Part 1: Knowledge Check": "Ph\u1EA7n 1: Ki\u1EC3m tra Ki\u1EBFn th\u1EE9c",
9753
- "Part 2: Concept Tracing & Diagram Fill-in": "Ph\u1EA7n 2: L\u1EA7n v\u1EBFt Kh\xE1i ni\u1EC7m & \u0110i\u1EC1n S\u01A1 \u0111\u1ED3",
9754
- "Part 3: Code Analysis & Bug Hunting Challenge": "Ph\u1EA7n 3: Ph\xE2n t\xEDch M\xE3 & Th\u1EED th\xE1ch S\u0103n l\u1ED7i",
9755
- "Part 4: Synthesis & Problem-Solving Application": "Ph\u1EA7n 4: T\u1ED5ng h\u1EE3p & \u1EE8ng d\u1EE5ng Gi\u1EA3i quy\u1EBFt V\u1EA5n \u0111\u1EC1",
9756
- "Part 5: Self-Reflection & Learning Log": "Ph\u1EA7n 5: T\u1EF1 suy ng\u1EABm & Nh\u1EADt k\xFD H\u1ECDc t\u1EADp"
9757
- },
9758
- EXT: {
9759
- "For: Advanced Students / Extra Time": "D\xE0nh cho: H\u1ECDc sinh N\xE2ng cao / Ho\xE0n th\xE0nh S\u1EDBm",
9760
- "Challenge 1: Mission Briefing & Real-World High-Stakes Scenario": "Th\u1EED th\xE1ch 1: B\u1ED1i c\u1EA3nh Nhi\u1EC7m v\u1EE5 Th\u1EF1c t\u1EBF & K\u1ECBch b\u1EA3n \u1EE8ng d\u1EE5ng",
9761
- "Challenge 2: Advanced Architectural Constraints & Edge Cases": "Th\u1EED th\xE1ch 2: R\xE0ng bu\u1ED9c Ki\u1EBFn tr\xFAc N\xE2ng cao & Tr\u01B0\u1EDDng h\u1EE3p Bi\xEAn",
9762
- "Challenge 3: Extension Milestones": "Th\u1EED th\xE1ch 3: C\xE1c M\u1ED1c Nhi\u1EC7m v\u1EE5 N\xE2ng cao",
9763
- "Metacognitive Deep Dive & Engineering Trade-offs": "Suy ng\u1EABm Si\xEAu nh\u1EADn th\u1EE9c & \u0110\xE1nh \u0111\u1ED5i K\u1EF9 thu\u1EADt"
9764
- },
9765
- SLIDE: {
9766
- "Title & Agenda": "Ti\xEAu \u0111\u1EC1 & M\u1EE5c l\u1EE5c",
9767
- "Core Concepts": "Kh\xE1i ni\u1EC7m C\u1ED1t l\xF5i",
9768
- "Guided Demonstration": "H\u01B0\u1EDBng d\u1EABn Th\u1EF1c h\xE0nh & Th\u1ECB ph\u1EA1m",
9769
- "Hands-on Mission": "Nhi\u1EC7m v\u1EE5 Th\u1EF1c h\xE0nh Tr\u1EA3i nghi\u1EC7m",
9770
- "Summary & Next Steps": "T\u1ED5ng k\u1EBFt & \u0110\u1ECBnh h\u01B0\u1EDBng Ti\u1EBFp theo"
9771
- }
9460
+ var TEMPLATE_BY_TYPE = {
9461
+ LESSON: "LESSON_5E_template.md",
9462
+ LESSON_5E: "LESSON_5E_template.md",
9463
+ LESSON_EDP: "LESSON_EDP_template.md",
9464
+ LESSON_GENERAL: "LESSON_GENERAL_template.md",
9465
+ ACT: "ACT_template.md",
9466
+ CODE: "CODE_template.md",
9467
+ // JSON-first code lab shares the CODE label set (the serializer renders its
9468
+ // own headings; this lookup only feeds the SLC/directive fallback path).
9469
+ CODE_LAB: "CODE_template.md",
9470
+ QUIZ: "QUIZ_v4.6_template.md",
9471
+ GUIDE: "GUIDE_template.md",
9472
+ HANDOUT: "HANDOUT_template.md",
9473
+ WKS: "WKS_template.md",
9474
+ EXT: "EXT_template.md",
9475
+ SLIDE: "SLIDE_template.md",
9476
+ KNOWLEDGE_EXPOSITION: "KNOWLEDGE_EXPOSITION_template.md",
9477
+ LEARNER_PROFILE: "LEARNER_PROFILE_template.md",
9478
+ PROJECT_BRIEF: "PROJECT_BRIEF_template.md",
9479
+ CURRICULUM_FRAMEWORK: "CURRICULUM_FRAMEWORK_template.md",
9480
+ CONTENT_STYLE_GUIDE: "CONTENT_STYLE_GUIDE_template.md",
9481
+ SECTION_LANGUAGE_CONTRACT: "SECTION_LANGUAGE_CONTRACT_template.md"
9772
9482
  };
9483
+ function keepContractEntries(artifactType, mapping) {
9484
+ const templateFile = TEMPLATE_BY_TYPE[artifactType.trim().toUpperCase()];
9485
+ if (!templateFile) return mapping;
9486
+ const resolved = resolveArtifactTemplate(templateFile);
9487
+ if (!resolved) return mapping;
9488
+ const contract = new Set(resolved.sections.map(stripHeadingKey));
9489
+ const kept = {};
9490
+ for (const [k, v] of Object.entries(mapping)) {
9491
+ if (contract.has(stripHeadingKey(k))) kept[k] = v;
9492
+ }
9493
+ return kept;
9494
+ }
9773
9495
  function extractSectionHeadingsFromSLC(slcInput, artifactType, targetLanguage = "vi") {
9774
9496
  const upperType = artifactType.trim().toUpperCase();
9775
9497
  const getFallback = () => {
9776
- if (resolveTargetLanguageCode(targetLanguage) === "vi") {
9777
- for (const [key, mapping] of Object.entries(DEFAULT_VIETNAMESE_SECTION_HEADINGS)) {
9778
- if (matchesArtifactType(key, upperType)) {
9779
- return mapping;
9780
- }
9781
- }
9782
- }
9783
- return {};
9498
+ const templateFile = TEMPLATE_BY_TYPE[upperType];
9499
+ if (!templateFile) return {};
9500
+ const resolved = resolveArtifactTemplate(templateFile);
9501
+ if (!resolved) return {};
9502
+ return Object.fromEntries(resolved.sections.map((s) => [s, s]));
9784
9503
  };
9785
9504
  if (!slcInput) return getFallback();
9786
9505
  if (typeof slcInput === "object") {
9787
- if (slcInput[upperType] && Object.keys(slcInput[upperType]).length > 0) return slcInput[upperType];
9506
+ if (slcInput[upperType] && Object.keys(slcInput[upperType]).length > 0) {
9507
+ return keepContractEntries(upperType, slcInput[upperType]);
9508
+ }
9788
9509
  for (const [key, mapping] of Object.entries(slcInput)) {
9789
9510
  if (matchesArtifactType(key, upperType) && Object.keys(mapping).length > 0) {
9790
- return mapping;
9511
+ return keepContractEntries(upperType, mapping);
9791
9512
  }
9792
9513
  }
9793
9514
  return getFallback();
@@ -9815,24 +9536,33 @@ function extractSectionHeadingsFromSLC(slcInput, artifactType, targetLanguage =
9815
9536
  }
9816
9537
  }
9817
9538
  }
9818
- if (Object.keys(mapping).length > 0) return mapping;
9539
+ if (Object.keys(mapping).length > 0) return keepContractEntries(upperType, mapping);
9819
9540
  }
9820
9541
  }
9821
9542
  return getFallback();
9822
9543
  }
9823
- function buildHeadingDirective(artifactType, slcMarkdown, targetLanguage = "vi") {
9824
- const headings = extractSectionHeadingsFromSLC(slcMarkdown, artifactType, targetLanguage);
9544
+ function buildHeadingDirective(artifactType, slcMarkdown, targetLanguage = "vi", opts) {
9545
+ const upperType = artifactType.trim().toUpperCase();
9546
+ const templateFile = TEMPLATE_BY_TYPE[upperType];
9547
+ const resolved = templateFile ? resolveArtifactTemplate(templateFile, opts) : null;
9548
+ const baked = !!resolved && resolved.declaredLang !== "en";
9549
+ const headings = resolved ? Object.fromEntries(
9550
+ resolved.sections.map((s) => [
9551
+ s,
9552
+ baked ? s : extractSectionHeadingsFromSLC(slcMarkdown, upperType, targetLanguage)[s] || s
9553
+ ])
9554
+ ) : extractSectionHeadingsFromSLC(baked ? null : slcMarkdown, upperType, targetLanguage);
9825
9555
  if (Object.keys(headings).length === 0) {
9826
9556
  return "";
9827
9557
  }
9828
9558
  const lines = Object.entries(headings).map(
9829
- ([canonical, localized]) => ` - "${canonical}" -> Use Display Heading: "${localized}"`
9559
+ ([heading, display]) => heading === display ? ` - "${display}"` : ` - "${heading}" -> Use Display Heading: "${display}"`
9830
9560
  );
9831
- return `MANDATORY SECTION HEADINGS FROM SECTION_LANGUAGE_CONTRACT:
9832
- - The YAML frontmatter \`template_required_sections\` MUST preserve the exact English canonical keys.
9833
- - In the markdown body, section headers MUST use the EXACT Localized Display Labels below (do NOT translate or paraphrase):
9561
+ return `MANDATORY SECTION HEADINGS (SOURCE: RESOLVED ARTIFACT TEMPLATE):
9562
+ - Copy the template's YAML frontmatter \`template_required_sections\` list VERBATIM into the artifact frontmatter \u2014 never translate, reorder, or invent entries.
9563
+ - In the markdown body, section headers MUST be exactly the Display Headings below (do NOT translate, paraphrase, or re-marker them):
9834
9564
  ${lines.join("\n")}
9835
- - For example: if canonical section is "Computational Thinking Focus", your heading must be "## [REQUIRED] ${headings["Computational Thinking Focus"] || "Computational Thinking Focus"}".`;
9565
+ - Example: if the resolved template's heading is "${Object.values(headings)[0]}", your body heading must be exactly "## ${Object.values(headings)[0]}".`;
9836
9566
  }
9837
9567
 
9838
9568
  // src/services/curriculumHorizon.ts
@@ -10686,14 +10416,13 @@ function buildSystemPrompt(targetLanguage = "vi", techStack, hardwarePlatform) {
10686
10416
  function buildUserPrompt(session, plan, glossary, targetLanguage = "vi", slcMarkdown, refPack) {
10687
10417
  const depthLines = session.depth_assignments.map((d) => "- " + d.node_id + " [" + d.depth.toUpperCase() + "]: " + DEPTH_RULES[d.depth]).join("\n");
10688
10418
  const termLines = glossary.map((g) => "- " + g.term + (g.definition ? " \u2014 " + g.definition : "") + (g.example ? " (example: " + g.example + ")" : "")).join("\n");
10689
- const langCode = resolveTargetLanguageCode(targetLanguage);
10690
- const headings = extractSectionHeadingsFromSLC(slcMarkdown, "KNOWLEDGE_EXPOSITION");
10691
- const hScope = headings["Session Scope"] || (langCode === "vi" ? "Ph\u1EA1m vi Bu\u1ED5i h\u1ECDc" : "Session Scope");
10692
- const hTerms = headings["Key Terms"] || (langCode === "vi" ? "Thu\u1EADt ng\u1EEF Then ch\u1ED1t" : "Key Terms");
10693
- const hNarratives = headings["Concept Narratives"] || (langCode === "vi" ? "Di\u1EC5n gi\u1EA3i Kh\xE1i ni\u1EC7m" : "Concept Narratives");
10694
- const hExamples = headings["Worked Micro-Examples"] || (langCode === "vi" ? "V\xED d\u1EE5 M\u1EABu Chi ti\u1EBFt" : "Worked Micro-Examples");
10695
- const hMistakes = headings["Common Mistakes"] || (langCode === "vi" ? "L\u1ED7i Th\u01B0\u1EDDng g\u1EB7p & Kh\u1EAFc ph\u1EE5c" : "Common Mistakes");
10696
- const hQuestions = headings["Self-Check Questions"] || (langCode === "vi" ? "C\xE2u h\u1ECFi T\u1EF1 ki\u1EC3m tra" : "Self-Check Questions");
10419
+ const headings = extractSectionHeadingsFromSLC(slcMarkdown, "KNOWLEDGE_EXPOSITION", targetLanguage);
10420
+ const hScope = headings["Session Scope"] || "Session Scope";
10421
+ const hTerms = headings["Key Terms"] || "Key Terms";
10422
+ const hNarratives = headings["Concept Narratives"] || "Concept Narratives";
10423
+ const hExamples = headings["Worked Micro-Examples"] || "Worked Micro-Examples";
10424
+ const hMistakes = headings["Common Mistakes"] || "Common Mistakes";
10425
+ const hQuestions = headings["Self-Check Questions"] || "Self-Check Questions";
10697
10426
  const skeleton = `## ${hScope} / ## ${hTerms} / ## ${hNarratives} / ## ${hExamples} / ## ${hMistakes} / ## ${hQuestions}`;
10698
10427
  const headingDirective = buildHeadingDirective("KNOWLEDGE_EXPOSITION", slcMarkdown, targetLanguage);
10699
10428
  let refPackBlock = "";
@@ -25449,98 +25178,9 @@ function evaluateActivityAlignment(canonicalExcerpt, generatedContent, now = /*
25449
25178
  const passed = matchedTokens.length > 0;
25450
25179
  return { checked: true, passed, matchedTokens: matchedTokens.slice(0, 10), missingTokens: missingTokens.slice(0, 10), mode };
25451
25180
  }
25452
- function stripTemplateFrontmatter(raw) {
25453
- let body = raw;
25454
- if (body.startsWith("---")) {
25455
- const end = body.indexOf("\n---", 3);
25456
- if (end !== -1) body = body.slice(end + 4);
25457
- }
25458
- return body.split("\n").filter((l) => l.trim() !== "<!-- INJECT_BODY -->").join("\n").replace(/^\s*\n/, "").trimEnd();
25459
- }
25460
- function extractRequiredSections(raw) {
25461
- const lines = raw.split("\n");
25462
- const start = lines.findIndex((l) => /^template_required_sections:\s*$/.test(l.trim()));
25463
- if (start === -1) return null;
25464
- const items = [];
25465
- for (let i = start + 1; i < lines.length; i++) {
25466
- const line = lines[i] ?? "";
25467
- if (line.trim() === "") continue;
25468
- if (!/^\s+-\s/.test(line)) break;
25469
- items.push(line.trim().replace(/^-\s+/, "").replace(/^["']|["']$/g, ""));
25470
- }
25471
- return items.length > 0 ? items : null;
25472
- }
25473
- function normalizeHeading2(h) {
25474
- return h.replace(/\[(REQUIRED|OPTIONAL|CONDITIONAL)\]\s*/gi, "").replace(/\s+/g, " ").trim();
25475
- }
25476
- function extractBodySections(raw) {
25477
- const body = stripTemplateFrontmatter(raw);
25478
- return body.split("\n").filter((l) => l.startsWith("## ")).map((l) => normalizeHeading2(l.slice(3).trim())).filter((s) => s.length > 0);
25479
- }
25480
- var KIT_TEMPLATE_FALLBACK_DIRS = [
25481
- // Packaged with the npm bundle (dist/templates) — resolves from node_modules.
25482
- "templates",
25483
- // Repo checkout layouts.
25484
- "docs/refs/templates"
25485
- ];
25486
- var _moduleDir = (() => {
25487
- try {
25488
- if (typeof import.meta !== "undefined" && typeof import.meta.url === "string") {
25489
- return path3.dirname(fileURLToPath(import.meta.url));
25490
- }
25491
- } catch {
25492
- }
25493
- return typeof __dirname !== "undefined" ? __dirname : process.cwd();
25494
- })();
25495
- function candidateDirs(explicitDir) {
25496
- const dirs = [];
25497
- if (explicitDir) dirs.push(explicitDir);
25498
- if (process.env.CURRICULUM_TEMPLATES_DIR) dirs.push(process.env.CURRICULUM_TEMPLATES_DIR);
25499
- dirs.push(path3.resolve(process.cwd(), "_templates"));
25500
- for (const rel of KIT_TEMPLATE_FALLBACK_DIRS) {
25501
- dirs.push(path3.resolve(_moduleDir, rel));
25502
- dirs.push(path3.resolve(process.cwd(), rel));
25503
- dirs.push(path3.resolve(process.cwd(), "packages/curriculum-kit", rel));
25504
- }
25505
- return dirs;
25506
- }
25507
- function findTemplatePath(templateName, explicitDir) {
25508
- for (const dir of candidateDirs(explicitDir)) {
25509
- const p = path3.join(dir, templateName);
25510
- if (!fs2.existsSync(p)) continue;
25511
- try {
25512
- fs2.accessSync(p, fs2.constants.R_OK);
25513
- return p;
25514
- } catch {
25515
- }
25516
- }
25517
- return null;
25518
- }
25519
- function resolveArtifactTemplate(templateName, opts) {
25520
- const p = findTemplatePath(templateName, opts?.templatesDir);
25521
- if (!p) return null;
25522
- try {
25523
- const raw = fs2.readFileSync(p, "utf-8");
25524
- return {
25525
- content: stripTemplateFrontmatter(raw),
25526
- sections: extractRequiredSections(raw) ?? extractBodySections(raw),
25527
- sourcePath: p
25528
- };
25529
- } catch {
25530
- return null;
25531
- }
25532
- }
25533
- function loadCurriculumTemplate(templateName, templatesDir) {
25534
- const p = findTemplatePath(templateName, templatesDir);
25535
- if (!p) return "";
25536
- try {
25537
- return fs2.readFileSync(p, "utf-8");
25538
- } catch {
25539
- return "";
25540
- }
25541
- }
25542
25181
 
25543
25182
  // src/services/lessonProductionService.ts
25183
+ init_templateLoader();
25544
25184
  var LESSON_TEMPLATE_BY_PEDAGOGY = {
25545
25185
  edp: "LESSON_EDP_template.md",
25546
25186
  general: "LESSON_GENERAL_template.md",
@@ -29476,14 +29116,15 @@ function isTranslationDue(target, context) {
29476
29116
  }
29477
29117
 
29478
29118
  // src/services/index.ts
29119
+ init_templateLoader();
29479
29120
  init_slideProductionWorkflow();
29480
29121
  var LocalWorkspaceManager = class {
29481
29122
  baseDir;
29482
29123
  constructor(baseDir) {
29483
- this.baseDir = baseDir || path3.resolve(process.cwd(), "output", "workspace-jobs");
29124
+ this.baseDir = baseDir || path4.resolve(process.cwd(), "output", "workspace-jobs");
29484
29125
  }
29485
29126
  getJobDirectory(jobId) {
29486
- return path3.join(this.baseDir, jobId);
29127
+ return path4.join(this.baseDir, jobId);
29487
29128
  }
29488
29129
  async initJobWorkspace(jobId, initialInfo) {
29489
29130
  const jobDir = this.getJobDirectory(jobId);
@@ -29506,9 +29147,9 @@ var LocalWorkspaceManager = class {
29506
29147
  }
29507
29148
  async saveArtifact(jobId, milestoneSlug, filename, content, artifactType) {
29508
29149
  const jobDir = this.getJobDirectory(jobId);
29509
- const targetDir = path3.join(jobDir, milestoneSlug);
29150
+ const targetDir = path4.join(jobDir, milestoneSlug);
29510
29151
  await fsPromises.mkdir(targetDir, { recursive: true });
29511
- const filePath = path3.join(targetDir, filename);
29152
+ const filePath = path4.join(targetDir, filename);
29512
29153
  await fsPromises.writeFile(filePath, content, "utf-8");
29513
29154
  const stat = await fsPromises.stat(filePath);
29514
29155
  const manifest = await this.getManifest(jobId);
@@ -29516,7 +29157,7 @@ var LocalWorkspaceManager = class {
29516
29157
  manifest.artifacts.push({
29517
29158
  milestoneId: milestoneSlug,
29518
29159
  artifactType,
29519
- filePath: path3.relative(jobDir, filePath),
29160
+ filePath: path4.relative(jobDir, filePath),
29520
29161
  sizeBytes: stat.size,
29521
29162
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
29522
29163
  });
@@ -29526,7 +29167,7 @@ var LocalWorkspaceManager = class {
29526
29167
  return filePath;
29527
29168
  }
29528
29169
  async getManifest(jobId) {
29529
- const manifestPath = path3.join(this.getJobDirectory(jobId), "manifest.json");
29170
+ const manifestPath = path4.join(this.getJobDirectory(jobId), "manifest.json");
29530
29171
  try {
29531
29172
  const data = await fsPromises.readFile(manifestPath, "utf-8");
29532
29173
  return JSON.parse(data);
@@ -29535,7 +29176,7 @@ var LocalWorkspaceManager = class {
29535
29176
  }
29536
29177
  }
29537
29178
  async saveManifest(jobId, manifest) {
29538
- const manifestPath = path3.join(this.getJobDirectory(jobId), "manifest.json");
29179
+ const manifestPath = path4.join(this.getJobDirectory(jobId), "manifest.json");
29539
29180
  manifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
29540
29181
  await fsPromises.writeFile(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
29541
29182
  }
@@ -29576,12 +29217,12 @@ async function publishToGitHub(options) {
29576
29217
  async function scanDir(currentDir) {
29577
29218
  const entries = await fsPromises.readdir(currentDir, { withFileTypes: true });
29578
29219
  for (const entry of entries) {
29579
- const fullPath = path3.join(currentDir, entry.name);
29220
+ const fullPath = path4.join(currentDir, entry.name);
29580
29221
  if (entry.isDirectory()) {
29581
29222
  await scanDir(fullPath);
29582
29223
  } else if (entry.isFile() && !entry.name.startsWith(".")) {
29583
29224
  const content = await fsPromises.readFile(fullPath, "utf-8");
29584
- const relPath = path3.relative(options.localJobDir, fullPath);
29225
+ const relPath = path4.relative(options.localJobDir, fullPath);
29585
29226
  filesToUpload.push({ path: relPath, content });
29586
29227
  }
29587
29228
  }
@@ -31687,13 +31328,13 @@ var MediaLedger = class {
31687
31328
  filePath;
31688
31329
  entries = /* @__PURE__ */ new Map();
31689
31330
  constructor(projectDir, lessonId) {
31690
- this.filePath = path3.join(projectDir, "_media", `ledger-${lessonId.toUpperCase()}.jsonl`);
31331
+ this.filePath = path4.join(projectDir, "_media", `ledger-${lessonId.toUpperCase()}.jsonl`);
31691
31332
  this.load();
31692
31333
  }
31693
31334
  load() {
31694
31335
  this.entries.clear();
31695
- if (!fs2.existsSync(this.filePath)) return;
31696
- const lines = fs2.readFileSync(this.filePath, "utf-8").split("\n");
31336
+ if (!fs3.existsSync(this.filePath)) return;
31337
+ const lines = fs3.readFileSync(this.filePath, "utf-8").split("\n");
31697
31338
  for (const line of lines) {
31698
31339
  const trimmed = line.trim();
31699
31340
  if (!trimmed) continue;
@@ -31705,8 +31346,8 @@ var MediaLedger = class {
31705
31346
  }
31706
31347
  }
31707
31348
  persist() {
31708
- fs2.mkdirSync(path3.dirname(this.filePath), { recursive: true });
31709
- fs2.writeFileSync(this.filePath, Array.from(this.entries.values()).map((e) => JSON.stringify(e)).join("\n") + "\n", "utf-8");
31349
+ fs3.mkdirSync(path4.dirname(this.filePath), { recursive: true });
31350
+ fs3.writeFileSync(this.filePath, Array.from(this.entries.values()).map((e) => JSON.stringify(e)).join("\n") + "\n", "utf-8");
31710
31351
  }
31711
31352
  /** Agent tạo artifact ghi entry mới (hoặc cập nhật nếu slug đã có và chưa done) */
31712
31353
  upsert(input) {
@@ -31888,8 +31529,8 @@ async function fulfillMediaLedger(options) {
31888
31529
  const maxRetries = options.maxRetries ?? 2;
31889
31530
  const approved = ledger.listByStatus("approved");
31890
31531
  const result = { done: [], failed: [], skipped: [] };
31891
- const mediaDir = path3.join(projectDir, "_media");
31892
- fs2.mkdirSync(mediaDir, { recursive: true });
31532
+ const mediaDir = path4.join(projectDir, "_media");
31533
+ fs3.mkdirSync(mediaDir, { recursive: true });
31893
31534
  const mode = policy.mode ?? "auto";
31894
31535
  const canSearch = mode === "search_only" || mode === "auto";
31895
31536
  const canGen = mode === "gen_only" || mode === "auto";
@@ -31971,7 +31612,7 @@ async function fulfillMediaLedger(options) {
31971
31612
  });
31972
31613
  const ext = image.mimeType === "image/jpeg" ? "jpg" : "png";
31973
31614
  const filename = `${entry.slug}-${Date.now()}.${ext}`;
31974
- fs2.writeFileSync(path3.join(mediaDir, filename), Buffer.from(image.base64, "base64"));
31615
+ fs3.writeFileSync(path4.join(mediaDir, filename), Buffer.from(image.base64, "base64"));
31975
31616
  ledger.setStatus(entry.slug, "done", { relPath: `_media/${filename}`, provider: image.provider });
31976
31617
  result.done.push(entry.slug);
31977
31618
  options.onProgress?.(entry.slug, "done", `source: ${image.provider}`);
@@ -32002,6 +31643,6 @@ function renderMediaPlaceholder(entry) {
32002
31643
  return `> \u{1F5BC}\uFE0F [\u1EA2nh \u0111ang ch\u1EDD: ${entry.name} \u2014 s\u1EBD \u0111\u01B0\u1EE3c t\u1EA1o sau khi duy\u1EC7t media]`;
32003
31644
  }
32004
31645
 
32005
- export { ACT_TEMPLATE, ARTIFACT_DEPENDENCY_ROUTING, ARTIFACT_EXECUTION_ORDER, AcademicAuditor, ActionableRepairActionSchema, ActionableRepairPromptSchema, ActiveLearningWorkflowSchema, ActivityLabSchema, ActivitySeqRowSchema, ActivityStepSchema, ArtifactContractRowSchema, AssessmentMapRowSchema, AssessmentObjectiveSchema, BLOOM_ACTION_VERBS, BUNDLED_STANDARDS_PACK_IDS, BellRingerDaySchema, BellRingerSchema, BloomHintSchema, BloomLevelSchema, BloomTaxonomyEvaluator, BronzeTierSchema, CERConclusionSchema, CODE_LAB_TEMPLATE, CURRICULUM_SLASH_COMMANDS, CardTierEnum, ChoiceBoardRubricRowSchema, ChoiceBoardSchema, ChoiceRuleSchema, ChoiceSquareSchema, ClassificationSchema, CodeHardwareFeasibilityEvaluator, CodeLabSchema, CodeSnippetSchema, CompetencyRubricRowSchema, ComputationalThinkingSchema, ConceptPrerequisiteEdgeSchema, ConceptSpiralEncounterSchema, ConstructiveAlignmentEvaluator, CoreConceptSchema, CourseObjectiveSchema, CoverageReportSchema, CrossArtifactDriftEvaluator, CurriculumArtifactSchema, CurriculumError, CurriculumPlanSchema, CurriculumQualityReportSchema, DEFAULT_ARTIFACT_STREAM_IDLE_MS, DEFAULT_ARTIFACT_STREAM_TOTAL_MS, DEFAULT_ENABLED_PROVIDERS, DEFAULT_GATE_SETTINGS, DEFAULT_KX_PRIORITIES, DEFAULT_LESSON_PRIORITIES, DEFAULT_OVERHEAD_RATIO, DEFAULT_STREAM_IDLE_MS, DEFAULT_STREAM_TOTAL_MS, DEFAULT_VIETNAMESE_SECTION_HEADINGS, DependencyEdgeSchema, DepthAssignmentSchema, DepthLevelSchema, DeterministicPipelineRunner, DeterministicStructuralLinter, DiagnosticQuestionSchema, DiagnosticQuizSchema, EDPPhaseEnum, ENVIRONMENT_PROVISIONING_MODELS, EXPOSITION_REL, EntryLevelSchema, ExitTicketBugHuntSchema, ExitTicketMetacognitionSchema, ExitTicketQuickItemSchema, ExitTicketRecallPromptSchema, ExitTicketSchema, ExperimentalDesignSchema, ExpositionApprovalError, ExtensionChallengeSchema, ExtensionSchema, FileSystemCurriculumAdapter, FiveEFlowPhaseSchema, FiveEInstructionalEvaluator, FiveEPhaseEnum, FrameworkMappingSchema, FrameworkPackManifestSchema, FrameworkPackSchema, FrameworkStatementSchema, GeneratedSlideArraySchema, GeneratedSlideSchema, GlossaryQuickRefRowSchema, GlossarySchema, GlossaryTermSchema, GoldTierSchema, GradeBandSchema, GraphicOrganizerItemSchema, GraphicOrganizerSchema, HandoutSchema, HandoutSectionSchema, HybridBlueprintArraySchema, HybridBlueprintItemSchema, HybridDeckSlideArraySchema, HybridDeckSlideSchema, HybridPipelineError, InstructionSectionSchema, InstructionStepSchema, JUDGE_AUTO_APPROVE_THRESHOLD, JUDGE_ESCALATE_THRESHOLD, JudgeCriterionSchema, LAYER_IDLE_BUDGET_MS, LAYER_TOTAL_BUDGET_MS, LESSON_PLAN_TEMPLATE, LLMJudgeEngine, LabTierTaskSchema, LearningObjectiveInputSchema, LearningObjectiveRowSchema, LessonEntitySchema, LessonFlowPhaseSchema, LessonPlan5ESchema, LessonPlanEDPSchema, LessonPlanSchema, LessonSectionSchema, LocalWorkspaceManager, MAX_AUTONOMOUS_REPAIR_TURNS, MAX_IN_SESSION_SETUP_MINUTES, MAX_NEW_CONCEPTS_PER_SESSION_ADULT, MAX_NEW_CONCEPTS_PER_SESSION_K12, MacroPedagogyPlanAuditSchema, MappingKindSchema, MarpSlideSchema, MasteryGateSchema, MediaError, MediaLedger, MentorCheatsheetSchema, MilestoneInputSchema, MisconceptionEvaluator, MisconceptionSchema, ModelPolicyResolver, NVIDIA_MODELS, NodeKindSchema, OrganizerTypeEnum, PhaseInputSchema, PlanConstraintsSchema, PlannerInputSchema, PlanningGraphSchema, PlanningNodeSchema, PrerequisiteDecisionEntrySchema, PrerequisiteDecisionSchema, ProductGoalSchema, ProgressiveHintsSchema, ProjectGraphAuditSchema, ProjectGraphSchema, ProjectInstructionSchema, ProjectProfileSchema, QUIZ_TEMPLATE, QualityAuditVerdictSchema, QuizOptionSchema, RecordProvenanceSchema, ResourceMapRowSchema, ReviewGameExportRowSchema, ReviewGameQuestionSchema, ReviewGameSchema, RoadmapInputSchema, RotationStationSchema, RubricCriteriaSchema, RubricSchema, SATELLITE_LESSON_PRIORITIES, SELF_LAB_TEMPLATE, SLIDE_CANONICAL_METHODOLOGY, STANDARD_REF_REGEX, STANDARD_SOT_FILES, STUDENT_FRICTION_MULTIPLIER, ScaffoldDecisionEntrySchema, ScaffoldDecisionSchema, ScienceLabSchema, ScoringRubricRowSchema, SelfLabSchema, SelfPacedBundleSchema, SelfPacedChallengeSchema, SessionPlanSchema, SessionZpdStatusSchema, SilverTierSchema, SlideBlueprintArraySchema, SlideBlueprintItemSchema, SlideDeckSchema, StandardizedTermRowSchema, StandardsRegistryAdapter, StationRecordRowSchema, StationRotationSchema, StationTypeEnum, SupabaseCurriculumAdapter, TaskCardSchema, TaskCardsSchema, TeacherGuideSchema, TeachingScriptPhaseSchema, TierLevelEnum, TierObjectiveSchema, TieredPracticeSchema, TranslationPolicySchema, TroubleshootingEntrySchema, TroubleshootingRowSchema, UnitPlanSchema, UserJourneySchema, WalkingSkeletonSchema, WorksheetItemSchema, WorksheetItemTypeEnum, WorksheetPartSchema, WorksheetSchema, ZpdVerdictSchema, activityTools, analystTools, analyzeProjectCreationIntent, assertAcyclic, assessorTools, assignDepths, atomicWriteFileSync, auditCurriculumPlanFlow, auditCurriculumQualityFlow, auditProjectGraphFlow, auditQualityReport, buildActivityPrompt, buildArtifactPrompt, buildCodeLabPrompt, buildConceptPrerequisites, buildCurriculumContext, buildCurriculumPlan, buildCurriculumPlanJudgePrompt, buildDeliveryPackages, buildDiagnosticQuizPrompt, buildDomainLexiconGuardrail, buildExpositionContext, buildExpositionExcerpt, buildExtensionPrompt, buildHandoutPrompt, buildHeadingDirective, buildHtmlDeckSlidePrompt, buildImagePrompt, buildJudgePrompt, buildLanguageDirective, buildLessonEntityJson, buildLessonExcerpt, buildLessonMasterPrompt, buildMarpMarkdownSlidePrompt, buildMasteryGates, buildProjectGraphJudgePrompt, buildProjectInstructionPrompt, buildSatelliteContext, buildSectionAwareExcerpt, buildSelfLabPrompt, buildSessionSliceContext, buildSlidesPrompt, buildStandardStackMarkdown, buildStandardsContext, buildStandardsContextBlock, buildTeacherGuidePrompt, buildWalkingSkeleton, buildWorksheetPrompt, checkSessionZpd, closeTruncatedJson, computeConceptSpiralProgression, computeContentHash, computePackingSpec, conductPreliminaryResearch, contentTools, convertRoadmapToFoundationSot, createAiInferenceError, createContextMissingError, createCurriculumStorage, createIdleAbortController, createStreamAbortController, createStreamAbortSignal, createStreamChunkExtractor, curateMediaLedger, designerTools, detectProjectPedagogy, dropCyclicConceptEdges, emitUsage, ensureExpositionForLesson, ensureKnowledgeExposition, entityRowAssignedTo, evaluateActivityAlignment, evaluateStandardsCoverage, executeCurriculumCommand, executeSlideProductionWorkflow, exportAllProjectQuizzes, expositionCacheKey, extractActivityContractRows, extractAssessmentMap, extractBodySections, extractCurriculumHorizon, extractJsonArray, extractRequiredSections, extractScopeSequenceRows, extractSectionHeadingsFromSLC, extractSessionSlice, extractStandardRefs, extractStreamChunk, extractSymbolLedger, extractThoughtAndContent, extractTieredScaffoldingBlock, findStandardStatement, formatQuizzesToCsv, fulfillMediaLedger, gateModeFor, generateActivityFlow, generateCodeLabFlow, generateDiagnosticQuizFlow, generateEducationalImage, generateExtensionFlow, generateHandoutFlow, generateLessonMasterFlow, generateMilestoneCurriculumBundle, generatePhase1SotArtifacts, generatePhase2SotArtifacts, generateProjectInstruction, generateProjectInstructionFlow, generateRoadmapCurriculum, generateSelfLabFlow, generateSelfPacedBundle, generateSingleArtifact, generateSlidesFlow, generateTeacherGuideFlow, generateWorksheetFlow, getAIModel, getArtifactMetadata, getDesignatedFallbackChain, getDesignatedFallbackConfig, getLessonMetadata, getProjectArtifactScope, getProjectStatusReport, getSmartResumeContext, glossaryTermsForSession, illustratorTools, importRoadmapToProject, ingestProjectGraphIntoProject, initializeProjectInStorage, injectMediaIntoMarkdown, isActivityAlignmentLogOnly, isExpositionFresh, isModelAllowed, isProviderEnabled, isTranslationDue, lintAndSanitizeArtifact, lintCurriculumFramework, lintFrameworkPack, loadCurriculumTemplate, loadSotTemplate, normalizePlanningGraph, normalizeSlcContract, packagerTools, parseAllSessions, parseGateSettings, parseQuizMarkdown, parseRoadmapJsonToProjectPayload, produceBatchLessons, produceSingleLesson, publishToGitHub, publishToSupabase, rankGenCandidates, renderAssignedRowsTable, renderEntitySlotsForType, renderFrameworkFromPlan, renderHorizonPromptBlock, renderMediaPlaceholder, researcherTools, resolveApiKey, resolveArtifactTemplate, resolveGateSettings, resolveStandardsPacks, resolveStreamBudget, resolveTargetLanguageCode, resolveTranslationTargets, reviewerTools, runCurriculumAIInference, safeParseJson, searchEducationalImages, searchEducationalVideos, selectStatementsForLesson, serializeActivityToMarkdown, serializeCodeLabToMarkdown, serializeDiagnosticQuizToMarkdown, serializeHandoutToMarkdown, serializeLessonToMarkdown, serializeProjectInstructionToMarkdown, serializeSelfLabToMarkdown, slugifyProjectName, streamCurriculumAIInference, streamCurriculumAIInferenceWithTools, streamDiagnosticQuizFlow, streamLLMWithFallback, streamLayerPrefillWithFallback, streamLessonMasterFlow, streamSelfLabFlow, stripLlmJsonWrappers, stripTemplateFrontmatter, targetLanguageDisplayName, techSmeTools, topoSort, uploadAssetToBucket, validateArtifactDependencies, validateCurriculumPlan, validateFrameworkPack, validateHorizonCompliance, validateHybridDeckSlides, validateMarkdownTables, validateMermaidSyntax, withAutoRepair };
31646
+ export { ARTIFACT_DEPENDENCY_ROUTING, ARTIFACT_EXECUTION_ORDER, AcademicAuditor, ActionableRepairActionSchema, ActionableRepairPromptSchema, ActiveLearningWorkflowSchema, ActivityLabSchema, ActivitySeqRowSchema, ActivityStepSchema, ArtifactContractRowSchema, AssessmentMapRowSchema, AssessmentObjectiveSchema, BLOOM_ACTION_VERBS, BUNDLED_STANDARDS_PACK_IDS, BellRingerDaySchema, BellRingerSchema, BloomHintSchema, BloomLevelSchema, BloomTaxonomyEvaluator, BronzeTierSchema, CERConclusionSchema, CURRICULUM_SLASH_COMMANDS, CardTierEnum, ChoiceBoardRubricRowSchema, ChoiceBoardSchema, ChoiceRuleSchema, ChoiceSquareSchema, ClassificationSchema, CodeHardwareFeasibilityEvaluator, CodeLabSchema, CodeSnippetSchema, CompetencyRubricRowSchema, ComputationalThinkingSchema, ConceptPrerequisiteEdgeSchema, ConceptSpiralEncounterSchema, ConstructiveAlignmentEvaluator, CoreConceptSchema, CourseObjectiveSchema, CoverageReportSchema, CrossArtifactDriftEvaluator, CurriculumArtifactSchema, CurriculumError, CurriculumPlanSchema, CurriculumQualityReportSchema, DEFAULT_ARTIFACT_STREAM_IDLE_MS, DEFAULT_ARTIFACT_STREAM_TOTAL_MS, DEFAULT_ENABLED_PROVIDERS, DEFAULT_GATE_SETTINGS, DEFAULT_KX_PRIORITIES, DEFAULT_LESSON_PRIORITIES, DEFAULT_OVERHEAD_RATIO, DEFAULT_STREAM_IDLE_MS, DEFAULT_STREAM_TOTAL_MS, DependencyEdgeSchema, DepthAssignmentSchema, DepthLevelSchema, DeterministicPipelineRunner, DeterministicStructuralLinter, DiagnosticQuestionSchema, DiagnosticQuizSchema, EDPPhaseEnum, ENVIRONMENT_PROVISIONING_MODELS, EXPOSITION_REL, EntryLevelSchema, ExitTicketBugHuntSchema, ExitTicketMetacognitionSchema, ExitTicketQuickItemSchema, ExitTicketRecallPromptSchema, ExitTicketSchema, ExperimentalDesignSchema, ExpositionApprovalError, ExtensionChallengeSchema, ExtensionSchema, FileSystemCurriculumAdapter, FiveEFlowPhaseSchema, FiveEInstructionalEvaluator, FiveEPhaseEnum, FrameworkMappingSchema, FrameworkPackManifestSchema, FrameworkPackSchema, FrameworkStatementSchema, GeneratedSlideArraySchema, GeneratedSlideSchema, GlossaryQuickRefRowSchema, GlossarySchema, GlossaryTermSchema, GoldTierSchema, GradeBandSchema, GraphicOrganizerItemSchema, GraphicOrganizerSchema, HandoutSchema, HandoutSectionSchema, HybridBlueprintArraySchema, HybridBlueprintItemSchema, HybridDeckSlideArraySchema, HybridDeckSlideSchema, HybridPipelineError, InstructionSectionSchema, InstructionStepSchema, JUDGE_AUTO_APPROVE_THRESHOLD, JUDGE_ESCALATE_THRESHOLD, JudgeCriterionSchema, LAYER_IDLE_BUDGET_MS, LAYER_TOTAL_BUDGET_MS, LLMJudgeEngine, LabTierTaskSchema, LearningObjectiveInputSchema, LearningObjectiveRowSchema, LessonEntitySchema, LessonFlowPhaseSchema, LessonPlan5ESchema, LessonPlanEDPSchema, LessonPlanSchema, LessonSectionSchema, LocalWorkspaceManager, MAX_AUTONOMOUS_REPAIR_TURNS, MAX_IN_SESSION_SETUP_MINUTES, MAX_NEW_CONCEPTS_PER_SESSION_ADULT, MAX_NEW_CONCEPTS_PER_SESSION_K12, MacroPedagogyPlanAuditSchema, MappingKindSchema, MarpSlideSchema, MasteryGateSchema, MediaError, MediaLedger, MentorCheatsheetSchema, MilestoneInputSchema, MisconceptionEvaluator, MisconceptionSchema, ModelPolicyResolver, NVIDIA_MODELS, NodeKindSchema, OrganizerTypeEnum, PhaseInputSchema, PlanConstraintsSchema, PlannerInputSchema, PlanningGraphSchema, PlanningNodeSchema, PrerequisiteDecisionEntrySchema, PrerequisiteDecisionSchema, ProductGoalSchema, ProgressiveHintsSchema, ProjectGraphAuditSchema, ProjectGraphSchema, ProjectInstructionSchema, ProjectProfileSchema, QualityAuditVerdictSchema, QuizOptionSchema, RecordProvenanceSchema, ResourceMapRowSchema, ReviewGameExportRowSchema, ReviewGameQuestionSchema, ReviewGameSchema, RoadmapInputSchema, RotationStationSchema, RubricCriteriaSchema, RubricSchema, SATELLITE_LESSON_PRIORITIES, SLIDE_CANONICAL_METHODOLOGY, STANDARD_REF_REGEX, STANDARD_SOT_FILES, STUDENT_FRICTION_MULTIPLIER, ScaffoldDecisionEntrySchema, ScaffoldDecisionSchema, ScienceLabSchema, ScoringRubricRowSchema, SelfLabSchema, SelfPacedBundleSchema, SelfPacedChallengeSchema, SessionPlanSchema, SessionZpdStatusSchema, SilverTierSchema, SlideBlueprintArraySchema, SlideBlueprintItemSchema, SlideDeckSchema, StandardizedTermRowSchema, StandardsRegistryAdapter, StationRecordRowSchema, StationRotationSchema, StationTypeEnum, SupabaseCurriculumAdapter, TaskCardSchema, TaskCardsSchema, TeacherGuideSchema, TeachingScriptPhaseSchema, TierLevelEnum, TierObjectiveSchema, TieredPracticeSchema, TranslationPolicySchema, TroubleshootingEntrySchema, TroubleshootingRowSchema, UnitPlanSchema, UserJourneySchema, WalkingSkeletonSchema, WorksheetItemSchema, WorksheetItemTypeEnum, WorksheetPartSchema, WorksheetSchema, ZpdVerdictSchema, activityTools, analystTools, analyzeProjectCreationIntent, assembleTranslatedTemplate, assertAcyclic, assessorTools, assignDepths, atomicWriteFileSync, auditCurriculumPlanFlow, auditCurriculumQualityFlow, auditProjectGraphFlow, auditQualityReport, buildActivityPrompt, buildArtifactPrompt, buildCodeLabPrompt, buildConceptPrerequisites, buildCurriculumContext, buildCurriculumPlan, buildCurriculumPlanJudgePrompt, buildDeliveryPackages, buildDiagnosticQuizPrompt, buildDomainLexiconGuardrail, buildExpositionContext, buildExpositionExcerpt, buildExtensionPrompt, buildHandoutPrompt, buildHeadingDirective, buildHtmlDeckSlidePrompt, buildImagePrompt, buildJudgePrompt, buildLanguageDirective, buildLessonEntityJson, buildLessonExcerpt, buildLessonMasterPrompt, buildMarpMarkdownSlidePrompt, buildMasteryGates, buildProjectGraphJudgePrompt, buildProjectInstructionPrompt, buildSatelliteContext, buildSectionAwareExcerpt, buildSelfLabPrompt, buildSessionSliceContext, buildSlidesPrompt, buildStandardStackMarkdown, buildStandardsContext, buildStandardsContextBlock, buildTeacherGuidePrompt, buildWalkingSkeleton, buildWorksheetPrompt, checkSessionZpd, closeTruncatedJson, computeConceptSpiralProgression, computeContentHash, computePackingSpec, conductPreliminaryResearch, contentTools, convertRoadmapToFoundationSot, createAiInferenceError, createContextMissingError, createCurriculumStorage, createIdleAbortController, createStreamAbortController, createStreamAbortSignal, createStreamChunkExtractor, curateMediaLedger, designerTools, detectProjectPedagogy, dropCyclicConceptEdges, emitUsage, ensureExpositionForLesson, ensureKnowledgeExposition, entityRowAssignedTo, evaluateActivityAlignment, evaluateStandardsCoverage, executeCurriculumCommand, executeSlideProductionWorkflow, exportAllProjectQuizzes, expositionCacheKey, extractActivityContractRows, extractAssessmentMap, extractConditionalSections, extractCurriculumHorizon, extractDeclaredLanguage, extractEchoSections, extractJsonArray, extractRequiredSections, extractScopeSequenceRows, extractSectionHeadingsFromSLC, extractSessionSlice, extractStandardRefs, extractStreamChunk, extractSymbolLedger, extractThoughtAndContent, extractTieredScaffoldingBlock, findStandardStatement, formatQuizzesToCsv, fulfillMediaLedger, gateModeFor, generateActivityFlow, generateCodeLabFlow, generateDiagnosticQuizFlow, generateEducationalImage, generateExtensionFlow, generateHandoutFlow, generateLessonMasterFlow, generateMilestoneCurriculumBundle, generatePhase1SotArtifacts, generatePhase2SotArtifacts, generateProjectInstruction, generateProjectInstructionFlow, generateRoadmapCurriculum, generateSelfLabFlow, generateSelfPacedBundle, generateSingleArtifact, generateSlidesFlow, generateTeacherGuideFlow, generateWorksheetFlow, getAIModel, getArtifactMetadata, getDesignatedFallbackChain, getDesignatedFallbackConfig, getLessonMetadata, getProjectArtifactScope, getProjectStatusReport, getSmartResumeContext, glossaryTermsForSession, illustratorTools, importRoadmapToProject, ingestProjectGraphIntoProject, initializeProjectInStorage, injectMediaIntoMarkdown, isActivityAlignmentLogOnly, isExpositionFresh, isModelAllowed, isProviderEnabled, isTranslationDue, lintAndSanitizeArtifact, lintCurriculumFramework, lintFrameworkPack, loadAuthoringTemplate, loadCurriculumTemplate, loadSotTemplate, normalizePlanningGraph, normalizeSlcContract, packagerTools, parseAllSessions, parseGateSettings, parseQuizMarkdown, parseRoadmapJsonToProjectPayload, produceBatchLessons, produceSingleLesson, publishToGitHub, publishToSupabase, rankGenCandidates, renderAssignedRowsTable, renderEntitySlotsForType, renderFrameworkFromPlan, renderHorizonPromptBlock, renderMediaPlaceholder, researcherTools, resolveApiKey, resolveArtifactTemplate, resolveGateSettings, resolveStandardsPacks, resolveStreamBudget, resolveTargetLanguageCode, resolveTranslationTargets, reviewerTools, runCurriculumAIInference, safeParseJson, searchEducationalImages, searchEducationalVideos, selectStatementsForLesson, serializeActivityToMarkdown, serializeCodeLabToMarkdown, serializeDiagnosticQuizToMarkdown, serializeHandoutToMarkdown, serializeLessonToMarkdown, serializeProjectInstructionToMarkdown, serializeSelfLabToMarkdown, slugifyProjectName, streamCurriculumAIInference, streamCurriculumAIInferenceWithTools, streamDiagnosticQuizFlow, streamLLMWithFallback, streamLayerPrefillWithFallback, streamLessonMasterFlow, streamSelfLabFlow, stripHeadingKey, stripLlmJsonWrappers, stripTemplateFrontmatter, targetLanguageDisplayName, techSmeTools, topoSort, translateTemplate, uploadAssetToBucket, validateArtifactDependencies, validateCurriculumPlan, validateFrameworkPack, validateHorizonCompliance, validateHybridDeckSlides, validateMarkdownTables, validateMermaidSyntax, withAutoRepair };
32006
31647
  //# sourceMappingURL=index.mjs.map
32007
31648
  //# sourceMappingURL=index.mjs.map