@thanh01.pmt/curriculum-kit 1.4.44 → 1.4.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/index.cjs.map +1 -1
- package/dist/ai/index.mjs.map +1 -1
- package/dist/{gateSettings-oo5tCUS_.d.cts → gateSettings-JoqERuS1.d.cts} +0 -1
- package/dist/{gateSettings-oo5tCUS_.d.ts → gateSettings-JoqERuS1.d.ts} +0 -1
- package/dist/index.cjs +362 -395
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +111 -33
- package/dist/index.d.ts +111 -33
- package/dist/index.mjs +356 -392
- package/dist/index.mjs.map +1 -1
- package/dist/pipeline/index.cjs +33 -14
- package/dist/pipeline/index.cjs.map +1 -1
- package/dist/pipeline/index.mjs +33 -14
- package/dist/pipeline/index.mjs.map +1 -1
- package/dist/storage/index.cjs +0 -1
- package/dist/storage/index.cjs.map +1 -1
- package/dist/storage/index.mjs +0 -1
- package/dist/storage/index.mjs.map +1 -1
- package/dist/templates/ACT_template.md +18 -9
- package/dist/templates/ALIGNMENT_MATRIX_template.md +5 -0
- package/dist/templates/ART_DIRECTION_template.md +7 -0
- package/dist/templates/ASSET_MANIFEST_template.md +5 -0
- package/dist/templates/BASELINE_STANDARD.md +5 -0
- package/dist/templates/BELL_RINGER_template.md +13 -13
- package/dist/templates/CHANGELOG_template.md +3 -0
- package/dist/templates/CHOICE_BOARD_template.md +8 -5
- package/dist/templates/CODE_template.md +5 -6
- package/dist/templates/CONTENT_CONTINUITY_template.md +6 -0
- package/dist/templates/CONTENT_STYLE_GUIDE_template.md +4 -5
- package/dist/templates/CURRICULUM_FRAMEWORK_template.md +5 -6
- package/dist/templates/DEPENDENCY_MAP_template.md +3 -4
- package/dist/templates/EXIT_TICKET_template.md +8 -8
- package/dist/templates/EXT_template.md +3 -0
- package/dist/templates/GLOSSARY_template.md +1 -2
- package/dist/templates/GRAPHIC_ORGANIZER_template.md +8 -8
- package/dist/templates/GUIDE_template.md +5 -6
- package/dist/templates/HANDOUT_template.md +5 -6
- package/dist/templates/HANDOVER_DOCUMENT_template.md +8 -0
- package/dist/templates/KNOWLEDGE_EXPOSITION_template.md +16 -6
- package/dist/templates/LAB_TEMPLATE.md +20 -3
- package/dist/templates/LEARNER_PROFILE_template.md +4 -5
- package/dist/templates/LESSONS_LEARNED_template.md +8 -0
- package/dist/templates/LESSON_5E_template.md +24 -9
- package/dist/templates/LESSON_EDP_template.md +26 -10
- package/dist/templates/LESSON_GENERAL_template.md +22 -8
- package/dist/templates/OUTPUT_CONSTRAINTS_template.md +7 -0
- package/dist/templates/PACKAGING_SPEC_template.md +8 -0
- package/dist/templates/PILOT_FEEDBACK_template.md +6 -0
- package/dist/templates/PROJECT_BRIEF_template.md +8 -0
- package/dist/templates/PROJECT_STATUS_template.md +9 -0
- package/dist/templates/QUIZ_template.md +7 -0
- package/dist/templates/QUIZ_v4.6_template.md +4 -5
- package/dist/templates/REFERENCE_PACK_template.md +4 -0
- package/dist/templates/REVIEW_GAME_template.md +11 -8
- package/dist/templates/RUBRIC_template.md +2 -3
- package/dist/templates/SCIENCE_LAB_template.md +11 -5
- package/dist/templates/SELF_LAB_template.md +7 -0
- package/dist/templates/SLIDE_template.md +23 -0
- package/dist/templates/STATION_ROTATION_template.md +11 -11
- package/dist/templates/TASK_CARDS_template.md +8 -8
- package/dist/templates/TIERED_PRACTICE_template.md +14 -10
- package/dist/templates/UPDATE_ROADMAP_template.md +7 -0
- package/dist/templates/WKS_template.md +5 -6
- package/dist/workflow/index.cjs +214 -307
- package/dist/workflow/index.cjs.map +1 -1
- package/dist/workflow/index.d.cts +2 -2
- package/dist/workflow/index.d.ts +2 -2
- package/dist/workflow/index.mjs +214 -307
- package/dist/workflow/index.mjs.map +1 -1
- package/docs/refs/templates/ACT_template.md +18 -9
- package/docs/refs/templates/ALIGNMENT_MATRIX_template.md +5 -0
- package/docs/refs/templates/ART_DIRECTION_template.md +7 -0
- package/docs/refs/templates/ASSET_MANIFEST_template.md +5 -0
- package/docs/refs/templates/BASELINE_STANDARD.md +5 -0
- package/docs/refs/templates/BELL_RINGER_template.md +13 -13
- package/docs/refs/templates/CHANGELOG_template.md +3 -0
- package/docs/refs/templates/CHOICE_BOARD_template.md +8 -5
- package/docs/refs/templates/CODE_template.md +5 -6
- package/docs/refs/templates/CONTENT_CONTINUITY_template.md +6 -0
- package/docs/refs/templates/CONTENT_STYLE_GUIDE_template.md +4 -5
- package/docs/refs/templates/CURRICULUM_FRAMEWORK_template.md +5 -6
- package/docs/refs/templates/DEPENDENCY_MAP_template.md +3 -4
- package/docs/refs/templates/EXIT_TICKET_template.md +8 -8
- package/docs/refs/templates/EXT_template.md +3 -0
- package/docs/refs/templates/GLOSSARY_template.md +1 -2
- package/docs/refs/templates/GRAPHIC_ORGANIZER_template.md +8 -8
- package/docs/refs/templates/GUIDE_template.md +5 -6
- package/docs/refs/templates/HANDOUT_template.md +5 -6
- package/docs/refs/templates/HANDOVER_DOCUMENT_template.md +8 -0
- package/docs/refs/templates/KNOWLEDGE_EXPOSITION_template.md +16 -6
- package/docs/refs/templates/LAB_TEMPLATE.md +20 -3
- package/docs/refs/templates/LEARNER_PROFILE_template.md +4 -5
- package/docs/refs/templates/LESSONS_LEARNED_template.md +8 -0
- package/docs/refs/templates/LESSON_5E_template.md +24 -9
- package/docs/refs/templates/LESSON_EDP_template.md +26 -10
- package/docs/refs/templates/LESSON_GENERAL_template.md +22 -8
- package/docs/refs/templates/OUTPUT_CONSTRAINTS_template.md +7 -0
- package/docs/refs/templates/PACKAGING_SPEC_template.md +8 -0
- package/docs/refs/templates/PILOT_FEEDBACK_template.md +6 -0
- package/docs/refs/templates/PROJECT_BRIEF_template.md +8 -0
- package/docs/refs/templates/PROJECT_STATUS_template.md +9 -0
- package/docs/refs/templates/QUIZ_template.md +7 -0
- package/docs/refs/templates/QUIZ_v4.6_template.md +4 -5
- package/docs/refs/templates/REFERENCE_PACK_template.md +4 -0
- package/docs/refs/templates/REVIEW_GAME_template.md +11 -8
- package/docs/refs/templates/RUBRIC_template.md +2 -3
- package/docs/refs/templates/SCIENCE_LAB_template.md +11 -5
- package/docs/refs/templates/SELF_LAB_template.md +7 -0
- package/docs/refs/templates/SLIDE_template.md +23 -0
- package/docs/refs/templates/STATION_ROTATION_template.md +11 -11
- package/docs/refs/templates/TASK_CARDS_template.md +8 -8
- package/docs/refs/templates/TIERED_PRACTICE_template.md +14 -10
- package/docs/refs/templates/UPDATE_ROADMAP_template.md +7 -0
- package/docs/refs/templates/WKS_template.md +5 -6
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -5,11 +5,11 @@ var path4 = require('path');
|
|
|
5
5
|
var google = require('@ai-sdk/google');
|
|
6
6
|
var openai = require('@ai-sdk/openai');
|
|
7
7
|
var deepseek = require('@ai-sdk/deepseek');
|
|
8
|
+
var url = require('url');
|
|
8
9
|
var zod = require('zod');
|
|
9
10
|
var ai = require('ai');
|
|
10
11
|
var pRetry = require('p-retry');
|
|
11
12
|
var jsonrepair = require('jsonrepair');
|
|
12
|
-
var url = require('url');
|
|
13
13
|
var pLimit = require('p-limit');
|
|
14
14
|
var fsPromises = require('fs/promises');
|
|
15
15
|
var crypto = require('crypto');
|
|
@@ -1178,6 +1178,229 @@ var init_provider_factory = __esm({
|
|
|
1178
1178
|
};
|
|
1179
1179
|
}
|
|
1180
1180
|
});
|
|
1181
|
+
function stripTemplateFrontmatter(raw) {
|
|
1182
|
+
let body = raw;
|
|
1183
|
+
if (body.startsWith("---")) {
|
|
1184
|
+
const end = body.indexOf("\n---", 3);
|
|
1185
|
+
if (end !== -1) body = body.slice(end + 4);
|
|
1186
|
+
}
|
|
1187
|
+
return body.split("\n").filter((l) => l.trim() !== "<!-- INJECT_BODY -->").join("\n").replace(/^\s*\n/, "").trimEnd();
|
|
1188
|
+
}
|
|
1189
|
+
function extractRequiredSections(raw) {
|
|
1190
|
+
const lines = raw.split("\n");
|
|
1191
|
+
const start = lines.findIndex((l) => /^template_required_sections:\s*$/.test(l.trim()));
|
|
1192
|
+
if (start === -1) return null;
|
|
1193
|
+
const items = [];
|
|
1194
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
1195
|
+
const line = lines[i] ?? "";
|
|
1196
|
+
if (line.trim() === "") continue;
|
|
1197
|
+
if (!/^\s+-\s/.test(line)) break;
|
|
1198
|
+
items.push(line.trim().replace(/^-\s+/, "").replace(/^["']|["']$/g, ""));
|
|
1199
|
+
}
|
|
1200
|
+
return items.length > 0 ? items : null;
|
|
1201
|
+
}
|
|
1202
|
+
function stripHeadingKey(h) {
|
|
1203
|
+
return h.replace(/\[(REQUIRED|OPTIONAL|CONDITIONAL)\]\s*/gi, "").replace(/^\s*\d+[.)]\s+/, "").replace(/\s+/g, " ").trim();
|
|
1204
|
+
}
|
|
1205
|
+
function isVariableHeading(text) {
|
|
1206
|
+
return /\{\{[^}]*\}\}/.test(text) || /\[[^\]]+\]/.test(text);
|
|
1207
|
+
}
|
|
1208
|
+
function collectHeadings(body) {
|
|
1209
|
+
const out = [];
|
|
1210
|
+
let inFence = false;
|
|
1211
|
+
for (const line of body.split("\n")) {
|
|
1212
|
+
if (/^(```|~~~)/.test(line.trim())) {
|
|
1213
|
+
inFence = !inFence;
|
|
1214
|
+
continue;
|
|
1215
|
+
}
|
|
1216
|
+
if (inFence) continue;
|
|
1217
|
+
const m = line.match(/^(#{2,3})\s+(.*)$/);
|
|
1218
|
+
if (!m) continue;
|
|
1219
|
+
const text = m[2].trim();
|
|
1220
|
+
const optional = /^\[OPTIONAL\]/i.test(text);
|
|
1221
|
+
const name = stripHeadingKey(text);
|
|
1222
|
+
if (!name || isVariableHeading(name)) continue;
|
|
1223
|
+
out.push({ level: m[1].length, name, optional });
|
|
1224
|
+
}
|
|
1225
|
+
return out;
|
|
1226
|
+
}
|
|
1227
|
+
function extractEchoSections(raw) {
|
|
1228
|
+
const hs = collectHeadings(stripTemplateFrontmatter(raw));
|
|
1229
|
+
return {
|
|
1230
|
+
required: hs.filter((h) => !h.optional).map((h) => h.name),
|
|
1231
|
+
optional: hs.filter((h) => h.optional).map((h) => h.name)
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
function extractConditionalSections(raw) {
|
|
1235
|
+
const body = stripTemplateFrontmatter(raw);
|
|
1236
|
+
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));
|
|
1237
|
+
}
|
|
1238
|
+
function extractDeclaredLanguage(raw) {
|
|
1239
|
+
const m = raw.match(/^template_language:\s*["']?([a-zA-Z-]+)["']?\s*$/m);
|
|
1240
|
+
return m?.[1]?.toLowerCase() || "en";
|
|
1241
|
+
}
|
|
1242
|
+
function candidateDirs(explicitDir) {
|
|
1243
|
+
const dirs = [];
|
|
1244
|
+
if (explicitDir) dirs.push(explicitDir);
|
|
1245
|
+
if (process.env.CURRICULUM_TEMPLATES_DIR) dirs.push(process.env.CURRICULUM_TEMPLATES_DIR);
|
|
1246
|
+
dirs.push(path4__default.default.resolve(process.cwd(), "_templates"));
|
|
1247
|
+
for (const rel of KIT_TEMPLATE_FALLBACK_DIRS) {
|
|
1248
|
+
dirs.push(path4__default.default.resolve(_moduleDir, rel));
|
|
1249
|
+
dirs.push(path4__default.default.resolve(process.cwd(), rel));
|
|
1250
|
+
dirs.push(path4__default.default.resolve(process.cwd(), "packages/curriculum-kit", rel));
|
|
1251
|
+
}
|
|
1252
|
+
return dirs;
|
|
1253
|
+
}
|
|
1254
|
+
function findTemplatePath(templateName, explicitDir) {
|
|
1255
|
+
for (const dir of candidateDirs(explicitDir)) {
|
|
1256
|
+
const p = path4__default.default.join(dir, templateName);
|
|
1257
|
+
if (!fs3__default.default.existsSync(p)) continue;
|
|
1258
|
+
try {
|
|
1259
|
+
fs3__default.default.accessSync(p, fs3__default.default.constants.R_OK);
|
|
1260
|
+
return p;
|
|
1261
|
+
} catch {
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
return null;
|
|
1265
|
+
}
|
|
1266
|
+
function resolveArtifactTemplate(templateName, opts) {
|
|
1267
|
+
const p = findTemplatePath(templateName, opts?.templatesDir);
|
|
1268
|
+
if (!p) return null;
|
|
1269
|
+
try {
|
|
1270
|
+
const raw = fs3__default.default.readFileSync(p, "utf-8");
|
|
1271
|
+
const echo = extractEchoSections(raw);
|
|
1272
|
+
return {
|
|
1273
|
+
content: stripTemplateFrontmatter(raw),
|
|
1274
|
+
sections: echo.required,
|
|
1275
|
+
optionalSections: echo.optional,
|
|
1276
|
+
sourcePath: p,
|
|
1277
|
+
conditionals: extractConditionalSections(raw),
|
|
1278
|
+
declaredLang: extractDeclaredLanguage(raw)
|
|
1279
|
+
};
|
|
1280
|
+
} catch {
|
|
1281
|
+
return null;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
function assembleTranslatedTemplate(templateName, translatedBody, targetLanguage, opts) {
|
|
1285
|
+
const raw = loadCurriculumTemplate(templateName, opts?.templatesDir);
|
|
1286
|
+
if (!raw || !translatedBody?.trim()) return null;
|
|
1287
|
+
const base = collectHeadings(stripTemplateFrontmatter(raw));
|
|
1288
|
+
const out = collectHeadings(translatedBody);
|
|
1289
|
+
if (base.length !== out.length) return null;
|
|
1290
|
+
for (let i = 0; i < base.length; i++) {
|
|
1291
|
+
if (base[i].level !== out[i].level || base[i].optional !== out[i].optional) return null;
|
|
1292
|
+
}
|
|
1293
|
+
const srcBody = stripTemplateFrontmatter(raw);
|
|
1294
|
+
for (const ph of new Set(srcBody.match(/\{\{[^}]+\}\}/g) ?? [])) {
|
|
1295
|
+
if (!translatedBody.includes(ph)) return null;
|
|
1296
|
+
}
|
|
1297
|
+
for (const mk of new Set(srcBody.match(/<!--\s*\[\/?[^\]]+\]\s*-->/g) ?? [])) {
|
|
1298
|
+
if (!translatedBody.includes(mk)) return null;
|
|
1299
|
+
}
|
|
1300
|
+
const lang = targetLanguage.trim().toLowerCase() || "en";
|
|
1301
|
+
const req = out.filter((h) => !h.optional).map((h) => h.name);
|
|
1302
|
+
let fmRaw = "";
|
|
1303
|
+
if (raw.startsWith("---")) {
|
|
1304
|
+
const end = raw.indexOf("\n---", 3);
|
|
1305
|
+
if (end !== -1) fmRaw = raw.slice(0, end + 4);
|
|
1306
|
+
}
|
|
1307
|
+
const fm = stampEchoOnFrontmatter(fmRaw || "---\n---", lang, req);
|
|
1308
|
+
return { raw: `${fm}
|
|
1309
|
+
${translatedBody.trimStart()}`, sections: req, templateLanguage: lang };
|
|
1310
|
+
}
|
|
1311
|
+
function stampEchoOnFrontmatter(rawDoc, lang, sections) {
|
|
1312
|
+
const echoLines = ['template_language: "' + lang + '"', "template_required_sections:", ...sections.map((n) => ` - "${n.replace(/"/g, '\\"')}"`)];
|
|
1313
|
+
if (rawDoc.startsWith("---")) {
|
|
1314
|
+
const lines = rawDoc.split("\n");
|
|
1315
|
+
const closeIdx = lines.findIndex((l, i) => i > 0 && l.trim() === "---");
|
|
1316
|
+
if (closeIdx === -1) {
|
|
1317
|
+
return ["---", ...echoLines, "---", "", stripTemplateFrontmatter(rawDoc)].join("\n");
|
|
1318
|
+
}
|
|
1319
|
+
const kept = [];
|
|
1320
|
+
let skippingList = false;
|
|
1321
|
+
for (const l of lines.slice(0, closeIdx)) {
|
|
1322
|
+
const t = l.trim();
|
|
1323
|
+
if (/^template_required_sections:$/.test(t)) {
|
|
1324
|
+
skippingList = true;
|
|
1325
|
+
continue;
|
|
1326
|
+
}
|
|
1327
|
+
if (/^template_language:/.test(t)) continue;
|
|
1328
|
+
if (skippingList) {
|
|
1329
|
+
if (/^\s+-\s/.test(l)) continue;
|
|
1330
|
+
skippingList = false;
|
|
1331
|
+
}
|
|
1332
|
+
kept.push(l);
|
|
1333
|
+
}
|
|
1334
|
+
return [...kept, ...echoLines, "---", ...lines.slice(closeIdx + 1)].join("\n");
|
|
1335
|
+
}
|
|
1336
|
+
return ["---", ...echoLines, "---", "", rawDoc].join("\n");
|
|
1337
|
+
}
|
|
1338
|
+
async function translateTemplate(templateName, targetLanguage, runner, opts) {
|
|
1339
|
+
const raw = loadCurriculumTemplate(templateName, opts?.templatesDir);
|
|
1340
|
+
if (!raw) return null;
|
|
1341
|
+
const body = stripTemplateFrontmatter(raw);
|
|
1342
|
+
const placeholders = Array.from(new Set(body.match(/\{\{[^}]+\}\}/g) ?? []));
|
|
1343
|
+
const markers = Array.from(new Set(body.match(/<!--\s*\[\/?[^\]]+\]\s*-->/g) ?? []));
|
|
1344
|
+
const prompt = `Translate the following Markdown artifact TEMPLATE body into ${targetLanguage}.
|
|
1345
|
+
STRICT PRESERVATION RULES (violating any of these invalidates the output):
|
|
1346
|
+
1. Keep the document structure EXACTLY: same number of headings, same order, same heading levels (## / ###).
|
|
1347
|
+
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.
|
|
1348
|
+
3. Keep every placeholder token VERBATIM (do not translate or alter), including {{ XX }}-style duration tokens: ${placeholders.join(" ") || "(none)"}
|
|
1349
|
+
4. Keep every HTML comment marker VERBATIM: ${markers.join(" ") || "(none)"}
|
|
1350
|
+
5. Keep code blocks, file paths, technical identifiers (API names, protocols, component models) untranslated.
|
|
1351
|
+
6. Translate ONLY natural-language prose, headings, and table headers into natural ${targetLanguage}.
|
|
1352
|
+
7. Output ONLY the translated markdown \u2014 no explanations, no code fences around the whole document.
|
|
1353
|
+
|
|
1354
|
+
TEMPLATE BODY:
|
|
1355
|
+
${body}`;
|
|
1356
|
+
let translatedBody;
|
|
1357
|
+
try {
|
|
1358
|
+
translatedBody = await runner(prompt);
|
|
1359
|
+
} catch {
|
|
1360
|
+
return null;
|
|
1361
|
+
}
|
|
1362
|
+
if (!translatedBody || translatedBody.length < body.length * 0.4) return null;
|
|
1363
|
+
translatedBody = translatedBody.trim().replace(/^```(?:markdown)?\n/, "").replace(/\n```$/, "");
|
|
1364
|
+
return assembleTranslatedTemplate(templateName, translatedBody, targetLanguage, opts);
|
|
1365
|
+
}
|
|
1366
|
+
function loadCurriculumTemplate(templateName, templatesDir) {
|
|
1367
|
+
const p = findTemplatePath(templateName, templatesDir);
|
|
1368
|
+
if (!p) return "";
|
|
1369
|
+
try {
|
|
1370
|
+
return fs3__default.default.readFileSync(p, "utf-8");
|
|
1371
|
+
} catch {
|
|
1372
|
+
return "";
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
function loadAuthoringTemplate(templateName, templatesDir) {
|
|
1376
|
+
const p = findTemplatePath(templateName, templatesDir);
|
|
1377
|
+
if (!p) return "";
|
|
1378
|
+
try {
|
|
1379
|
+
return stripTemplateFrontmatter(fs3__default.default.readFileSync(p, "utf-8"));
|
|
1380
|
+
} catch {
|
|
1381
|
+
return "";
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
var KIT_TEMPLATE_FALLBACK_DIRS, _moduleDir;
|
|
1385
|
+
var init_templateLoader = __esm({
|
|
1386
|
+
"src/services/templateLoader.ts"() {
|
|
1387
|
+
KIT_TEMPLATE_FALLBACK_DIRS = [
|
|
1388
|
+
// Packaged with the npm bundle (dist/templates) — resolves from node_modules.
|
|
1389
|
+
"templates",
|
|
1390
|
+
// Repo checkout layouts.
|
|
1391
|
+
"docs/refs/templates"
|
|
1392
|
+
];
|
|
1393
|
+
_moduleDir = (() => {
|
|
1394
|
+
try {
|
|
1395
|
+
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }) !== "undefined" && typeof (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) === "string") {
|
|
1396
|
+
return path4__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
1397
|
+
}
|
|
1398
|
+
} catch {
|
|
1399
|
+
}
|
|
1400
|
+
return typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
1401
|
+
})();
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1181
1404
|
|
|
1182
1405
|
// src/pipeline/artifactLinter.ts
|
|
1183
1406
|
var artifactLinter_exports = {};
|
|
@@ -1544,14 +1767,26 @@ function parseLessonFlow(lessonMarkdown) {
|
|
|
1544
1767
|
}
|
|
1545
1768
|
}
|
|
1546
1769
|
}
|
|
1547
|
-
const flowMatch = lessonMarkdown.match(/##\s
|
|
1770
|
+
const flowMatch = lessonMarkdown.match(/##\s*(?:\[?REQUIRED\]?\s*)?B\.\s*Lesson Flow([\s\S]*?)$/i);
|
|
1548
1771
|
const flowSection = flowMatch ? flowMatch[1] : lessonMarkdown;
|
|
1549
|
-
const phaseRegex = /###\s*(?:(\d+)\.\s*)?([^\n
|
|
1772
|
+
const phaseRegex = /###\s*(?:(\d+)\.\s*)?([^\n]+)\n([\s\S]*?)(?=(?:###\s*(?:\d+\.)?|$))/gi;
|
|
1550
1773
|
let pMatch;
|
|
1551
1774
|
while ((pMatch = phaseRegex.exec(flowSection)) !== null) {
|
|
1552
|
-
const
|
|
1553
|
-
const
|
|
1554
|
-
const
|
|
1775
|
+
const headingText = pMatch[2].trim();
|
|
1776
|
+
const tailMatch = headingText.match(/[—–-]\s*\[?([^\]—–]+)\]?\s*$/);
|
|
1777
|
+
const tail = tailMatch?.[1]?.trim() ?? "";
|
|
1778
|
+
const rawPhaseName = stripHeadingKey(
|
|
1779
|
+
tailMatch && /mins?/i.test(tail) ? headingText.slice(0, tailMatch.index).trim() : headingText
|
|
1780
|
+
);
|
|
1781
|
+
let content = pMatch[3].trim();
|
|
1782
|
+
let timing;
|
|
1783
|
+
const durMatch2 = content.match(/^>?\s*\**Duration:?\**\s*([~0-9][^\n]*)/i);
|
|
1784
|
+
if (durMatch2) {
|
|
1785
|
+
timing = durMatch2[1].trim();
|
|
1786
|
+
content = content.replace(/^>?\s*\**Duration:?\**\s*[^\n]*\n?/i, "").trim();
|
|
1787
|
+
} else if (tail && /mins?/i.test(tail)) {
|
|
1788
|
+
timing = tail;
|
|
1789
|
+
}
|
|
1555
1790
|
const codeSnippets = [];
|
|
1556
1791
|
const codeRegex = /```(?:[a-zA-Z0-9_\-]+)?\s*\n([\s\S]*?)```/g;
|
|
1557
1792
|
let cMatch;
|
|
@@ -1579,6 +1814,7 @@ function parseLessonFlow(lessonMarkdown) {
|
|
|
1579
1814
|
}
|
|
1580
1815
|
var init_lessonFlowParser = __esm({
|
|
1581
1816
|
"src/parsers/lessonFlowParser.ts"() {
|
|
1817
|
+
init_templateLoader();
|
|
1582
1818
|
}
|
|
1583
1819
|
});
|
|
1584
1820
|
|
|
@@ -3944,107 +4180,9 @@ var RoadmapInputSchema = zod.z.object({
|
|
|
3944
4180
|
|
|
3945
4181
|
// src/ai/index.ts
|
|
3946
4182
|
init_provider_factory();
|
|
3947
|
-
function stripTemplateFrontmatter(raw) {
|
|
3948
|
-
let body = raw;
|
|
3949
|
-
if (body.startsWith("---")) {
|
|
3950
|
-
const end = body.indexOf("\n---", 3);
|
|
3951
|
-
if (end !== -1) body = body.slice(end + 4);
|
|
3952
|
-
}
|
|
3953
|
-
return body.split("\n").filter((l) => l.trim() !== "<!-- INJECT_BODY -->").join("\n").replace(/^\s*\n/, "").trimEnd();
|
|
3954
|
-
}
|
|
3955
|
-
function extractRequiredSections(raw) {
|
|
3956
|
-
const lines = raw.split("\n");
|
|
3957
|
-
const start = lines.findIndex((l) => /^template_required_sections:\s*$/.test(l.trim()));
|
|
3958
|
-
if (start === -1) return null;
|
|
3959
|
-
const items = [];
|
|
3960
|
-
for (let i = start + 1; i < lines.length; i++) {
|
|
3961
|
-
const line = lines[i] ?? "";
|
|
3962
|
-
if (line.trim() === "") continue;
|
|
3963
|
-
if (!/^\s+-\s/.test(line)) break;
|
|
3964
|
-
items.push(line.trim().replace(/^-\s+/, "").replace(/^["']|["']$/g, ""));
|
|
3965
|
-
}
|
|
3966
|
-
return items.length > 0 ? items : null;
|
|
3967
|
-
}
|
|
3968
|
-
function normalizeHeading(h) {
|
|
3969
|
-
return h.replace(/\[(REQUIRED|OPTIONAL|CONDITIONAL)\]\s*/gi, "").replace(/\s+/g, " ").trim();
|
|
3970
|
-
}
|
|
3971
|
-
function extractBodySections(raw) {
|
|
3972
|
-
const body = stripTemplateFrontmatter(raw);
|
|
3973
|
-
return body.split("\n").filter((l) => l.startsWith("## ")).map((l) => normalizeHeading(l.slice(3).trim())).filter((s) => s.length > 0);
|
|
3974
|
-
}
|
|
3975
|
-
var KIT_TEMPLATE_FALLBACK_DIRS = [
|
|
3976
|
-
// Packaged with the npm bundle (dist/templates) — resolves from node_modules.
|
|
3977
|
-
"templates",
|
|
3978
|
-
// Repo checkout layouts.
|
|
3979
|
-
"docs/refs/templates"
|
|
3980
|
-
];
|
|
3981
|
-
var _moduleDir = (() => {
|
|
3982
|
-
try {
|
|
3983
|
-
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }) !== "undefined" && typeof (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) === "string") {
|
|
3984
|
-
return path4__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
3985
|
-
}
|
|
3986
|
-
} catch {
|
|
3987
|
-
}
|
|
3988
|
-
return typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
3989
|
-
})();
|
|
3990
|
-
function candidateDirs(explicitDir) {
|
|
3991
|
-
const dirs = [];
|
|
3992
|
-
if (explicitDir) dirs.push(explicitDir);
|
|
3993
|
-
if (process.env.CURRICULUM_TEMPLATES_DIR) dirs.push(process.env.CURRICULUM_TEMPLATES_DIR);
|
|
3994
|
-
dirs.push(path4__default.default.resolve(process.cwd(), "_templates"));
|
|
3995
|
-
for (const rel of KIT_TEMPLATE_FALLBACK_DIRS) {
|
|
3996
|
-
dirs.push(path4__default.default.resolve(_moduleDir, rel));
|
|
3997
|
-
dirs.push(path4__default.default.resolve(process.cwd(), rel));
|
|
3998
|
-
dirs.push(path4__default.default.resolve(process.cwd(), "packages/curriculum-kit", rel));
|
|
3999
|
-
}
|
|
4000
|
-
return dirs;
|
|
4001
|
-
}
|
|
4002
|
-
function findTemplatePath(templateName, explicitDir) {
|
|
4003
|
-
for (const dir of candidateDirs(explicitDir)) {
|
|
4004
|
-
const p = path4__default.default.join(dir, templateName);
|
|
4005
|
-
if (!fs3__default.default.existsSync(p)) continue;
|
|
4006
|
-
try {
|
|
4007
|
-
fs3__default.default.accessSync(p, fs3__default.default.constants.R_OK);
|
|
4008
|
-
return p;
|
|
4009
|
-
} catch {
|
|
4010
|
-
}
|
|
4011
|
-
}
|
|
4012
|
-
return null;
|
|
4013
|
-
}
|
|
4014
|
-
function resolveArtifactTemplate(templateName, opts) {
|
|
4015
|
-
const p = findTemplatePath(templateName, opts?.templatesDir);
|
|
4016
|
-
if (!p) return null;
|
|
4017
|
-
try {
|
|
4018
|
-
const raw = fs3__default.default.readFileSync(p, "utf-8");
|
|
4019
|
-
return {
|
|
4020
|
-
content: stripTemplateFrontmatter(raw),
|
|
4021
|
-
sections: extractRequiredSections(raw) ?? extractBodySections(raw),
|
|
4022
|
-
sourcePath: p
|
|
4023
|
-
};
|
|
4024
|
-
} catch {
|
|
4025
|
-
return null;
|
|
4026
|
-
}
|
|
4027
|
-
}
|
|
4028
|
-
function loadCurriculumTemplate(templateName, templatesDir) {
|
|
4029
|
-
const p = findTemplatePath(templateName, templatesDir);
|
|
4030
|
-
if (!p) return "";
|
|
4031
|
-
try {
|
|
4032
|
-
return fs3__default.default.readFileSync(p, "utf-8");
|
|
4033
|
-
} catch {
|
|
4034
|
-
return "";
|
|
4035
|
-
}
|
|
4036
|
-
}
|
|
4037
|
-
function loadAuthoringTemplate(templateName, templatesDir) {
|
|
4038
|
-
const p = findTemplatePath(templateName, templatesDir);
|
|
4039
|
-
if (!p) return "";
|
|
4040
|
-
try {
|
|
4041
|
-
return stripTemplateFrontmatter(fs3__default.default.readFileSync(p, "utf-8"));
|
|
4042
|
-
} catch {
|
|
4043
|
-
return "";
|
|
4044
|
-
}
|
|
4045
|
-
}
|
|
4046
4183
|
|
|
4047
4184
|
// src/ai/prompts/lessonMasterPrompt.ts
|
|
4185
|
+
init_templateLoader();
|
|
4048
4186
|
function buildLessonMasterPrompt(input) {
|
|
4049
4187
|
const { milestone, language, topic, targetAudience, contextContinuity, standardsContext } = input;
|
|
4050
4188
|
const learningObjectives = milestone.learning_objectives || [];
|
|
@@ -4146,6 +4284,7 @@ Return a single valid JSON object matching the LessonPlanSchema with these exact
|
|
|
4146
4284
|
}
|
|
4147
4285
|
|
|
4148
4286
|
// src/ai/prompts/activityPrompt.ts
|
|
4287
|
+
init_templateLoader();
|
|
4149
4288
|
function buildActivityPrompt(input) {
|
|
4150
4289
|
const { lesson, language, hardwareBOM, softwareTools } = input;
|
|
4151
4290
|
const loList = lesson.learningObjectives.map((lo) => `- [${lo.bloomLevel}] ${lo.code}: ${lo.name || ""} \u2014 ${lo.description}${lo.successCriteria ? ` (Evidence: ${lo.successCriteria})` : ""}`).join("\n");
|
|
@@ -4245,6 +4384,7 @@ Return a single JSON object matching ActivityLabSchema with these exact keys:
|
|
|
4245
4384
|
}
|
|
4246
4385
|
|
|
4247
4386
|
// src/ai/prompts/codeLabPrompt.ts
|
|
4387
|
+
init_templateLoader();
|
|
4248
4388
|
function buildCodeLabPrompt(input) {
|
|
4249
4389
|
const { lesson, activity, language, targetTechStack } = input;
|
|
4250
4390
|
const techStackList = targetTechStack && targetTechStack.length > 0 ? targetTechStack : ["General Programming & Engineering"];
|
|
@@ -4934,6 +5074,7 @@ Please return a single JSON object matching these exact keys:
|
|
|
4934
5074
|
}
|
|
4935
5075
|
|
|
4936
5076
|
// src/ai/prompts/selfLabPrompt.ts
|
|
5077
|
+
init_templateLoader();
|
|
4937
5078
|
function buildSelfLabPrompt(input) {
|
|
4938
5079
|
const { milestone, projectGraph, language, targetTechStack, contextContinuity } = input;
|
|
4939
5080
|
const techStackList = targetTechStack && targetTechStack.length > 0 ? targetTechStack : milestone.tech_keywords && milestone.tech_keywords.length > 0 ? milestone.tech_keywords : ["General Engineering"];
|
|
@@ -5042,6 +5183,7 @@ Return a single valid JSON object matching SelfLabSchema with these exact keys:
|
|
|
5042
5183
|
}
|
|
5043
5184
|
|
|
5044
5185
|
// src/ai/prompts/diagnosticQuizPrompt.ts
|
|
5186
|
+
init_templateLoader();
|
|
5045
5187
|
function buildDiagnosticQuizPrompt(input) {
|
|
5046
5188
|
const { milestone, language, questionCount = 4, passingScorePct = 80 } = input;
|
|
5047
5189
|
const learningObjectives = milestone.learning_objectives || [];
|
|
@@ -6506,7 +6648,7 @@ ${cc.technicalDepth}`;
|
|
|
6506
6648
|
const dataRows = cc.comparisonTable.rows.map((r) => `| ${r.join(" | ")} |`).join("\n");
|
|
6507
6649
|
str += `
|
|
6508
6650
|
|
|
6509
|
-
|
|
6651
|
+
**Comparison & Trade-off Analysis**
|
|
6510
6652
|
${headerRow}
|
|
6511
6653
|
${dividerRow}
|
|
6512
6654
|
${dataRows}`;
|
|
@@ -6550,7 +6692,8 @@ ${learningObjectivesStr}
|
|
|
6550
6692
|
|
|
6551
6693
|
---
|
|
6552
6694
|
|
|
6553
|
-
## 1. ENGAGE (Hook & High-Stakes Scenario)
|
|
6695
|
+
## 1. ENGAGE (Hook & High-Stakes Scenario)
|
|
6696
|
+
> **Duration:** 10-15 mins
|
|
6554
6697
|
|
|
6555
6698
|
### Real-World Context: "${lesson.hookTitle || "The Incident"}"
|
|
6556
6699
|
${lesson.hookScenario}
|
|
@@ -6559,13 +6702,15 @@ ${lesson.hookQuestions && lesson.hookQuestions.length > 0 ? lesson.hookQuestions
|
|
|
6559
6702
|
|
|
6560
6703
|
---
|
|
6561
6704
|
|
|
6562
|
-
## 2. EXPLORE & EXPLAIN (Core Technical Concepts & Principles)
|
|
6705
|
+
## 2. EXPLORE & EXPLAIN (Core Technical Concepts & Principles)
|
|
6706
|
+
> **Duration:** 30-40 mins
|
|
6563
6707
|
|
|
6564
6708
|
${coreConceptsStr}
|
|
6565
6709
|
|
|
6566
6710
|
---
|
|
6567
6711
|
|
|
6568
|
-
## 3. GUIDED PRACTICE (Visual Architecture & Annotated Code)
|
|
6712
|
+
## 3. GUIDED PRACTICE (Visual Architecture & Annotated Code)
|
|
6713
|
+
> **Duration:** 20-25 mins
|
|
6569
6714
|
|
|
6570
6715
|
### System Architecture & Data Flow (Mermaid Diagram)
|
|
6571
6716
|
${mermaidBlock}
|
|
@@ -6579,7 +6724,8 @@ ${guidedPractice.codeSnippet}
|
|
|
6579
6724
|
|
|
6580
6725
|
---
|
|
6581
6726
|
|
|
6582
|
-
## 4. ELABORATE & INDEPENDENT PRACTICE (Technical Challenge & Scaffolding)
|
|
6727
|
+
## 4. ELABORATE & INDEPENDENT PRACTICE (Technical Challenge & Scaffolding)
|
|
6728
|
+
> **Duration:** 15-20 mins
|
|
6583
6729
|
|
|
6584
6730
|
### Engineering Challenge: "${lesson.independentPractice?.title || "System Optimization Challenge"}"
|
|
6585
6731
|
${lesson.independentPractice?.description || "Implement the core logic and test against simulated edge cases."}
|
|
@@ -6590,7 +6736,8 @@ ${lesson.independentPractice?.description || "Implement the core logic and test
|
|
|
6590
6736
|
|
|
6591
6737
|
---
|
|
6592
6738
|
|
|
6593
|
-
## 5. EVALUATE (Summary, Assessment & Metacognition)
|
|
6739
|
+
## 5. EVALUATE (Summary, Assessment & Metacognition)
|
|
6740
|
+
> **Duration:** 5-10 mins
|
|
6594
6741
|
|
|
6595
6742
|
### Exit Ticket (Bloom: Apply / Analyze)
|
|
6596
6743
|
> **Scenario Question:** ${lesson.exitTicket.questionStem}
|
|
@@ -6683,12 +6830,16 @@ ${hardwareItems}
|
|
|
6683
6830
|
|
|
6684
6831
|
## [REQUIRED] Active Learning Workflow
|
|
6685
6832
|
|
|
6686
|
-
### Phase 1: Planning & Design
|
|
6833
|
+
### Phase 1: Planning & Design
|
|
6834
|
+
> **Duration:** ${phase1.durationMinutes} mins
|
|
6835
|
+
|
|
6687
6836
|
- **Student Task:** ${phase1.studentTask}
|
|
6688
6837
|
- **Teacher Action:** ${phase1.teacherAction}
|
|
6689
6838
|
${phase1.inquiryQuestions.map((q) => ` - *Inquiry Question:* ${q}`).join("\n")}
|
|
6690
6839
|
|
|
6691
|
-
### Phase 2: Implementation & Discovery
|
|
6840
|
+
### Phase 2: Implementation & Discovery
|
|
6841
|
+
> **Duration:** ${phase2.durationMinutes} mins
|
|
6842
|
+
|
|
6692
6843
|
- **Student Task:** ${phase2.studentTask}
|
|
6693
6844
|
- **Teacher Action:** ${phase2.teacherAction}
|
|
6694
6845
|
|
|
@@ -6696,7 +6847,9 @@ ${phase2.codeOrCommands.map((c) => `\`\`\`text
|
|
|
6696
6847
|
${c}
|
|
6697
6848
|
\`\`\``).join("\n\n")}
|
|
6698
6849
|
|
|
6699
|
-
### Phase 3: Debugging & Testing
|
|
6850
|
+
### Phase 3: Debugging & Testing
|
|
6851
|
+
> **Duration:** ${phase3.durationMinutes} mins
|
|
6852
|
+
|
|
6700
6853
|
- **Testing:** ${phase3.testingSteps}
|
|
6701
6854
|
- **Error Analysis:** ${phase3.errorAnalysis}
|
|
6702
6855
|
|
|
@@ -6751,22 +6904,28 @@ This lab focuses on the practical implementation of core technical concepts, bri
|
|
|
6751
6904
|
|
|
6752
6905
|
## \u{1F4DD} Lab Tasks (3-Tier Differentiation)
|
|
6753
6906
|
|
|
6754
|
-
### \u{1F949} Bronze (Foundational)
|
|
6907
|
+
### \u{1F949} Bronze (Foundational)
|
|
6908
|
+
> **Duration:** ${tasks.bronze.mins} mins
|
|
6909
|
+
|
|
6755
6910
|
**Objective:** ${tasks.bronze.objective}
|
|
6756
6911
|
- **Task:** ${tasks.bronze.task}
|
|
6757
6912
|
- **Requirement:** ${tasks.bronze.requirement}
|
|
6758
6913
|
|
|
6759
|
-
### \u{1F948} Silver (Application)
|
|
6914
|
+
### \u{1F948} Silver (Application)
|
|
6915
|
+
> **Duration:** ${tasks.silver.mins} mins
|
|
6916
|
+
|
|
6760
6917
|
**Objective:** ${tasks.silver.objective}
|
|
6761
6918
|
- **Task:** ${tasks.silver.task}
|
|
6762
6919
|
- **Requirement:** ${tasks.silver.requirement}
|
|
6763
6920
|
|
|
6764
|
-
### \u{1F947} Gold (Enrichment/Creative)
|
|
6921
|
+
### \u{1F947} Gold (Enrichment/Creative)
|
|
6922
|
+
> **Duration:** ${tasks.gold.mins} mins
|
|
6923
|
+
|
|
6765
6924
|
**Objective:** ${tasks.gold.objective}
|
|
6766
6925
|
- **Task:** ${tasks.gold.task}
|
|
6767
6926
|
- **Requirement:** ${tasks.gold.requirement}
|
|
6768
6927
|
|
|
6769
|
-
## \u{1F4BB} Technical Reference
|
|
6928
|
+
## \u{1F4BB} Technical Reference
|
|
6770
6929
|
<!-- [SME_MANDATE] -->
|
|
6771
6930
|
> Any code provided in this section is verified for syntax accuracy and runtime execution.
|
|
6772
6931
|
|
|
@@ -6904,7 +7063,9 @@ ${instruction.verificationChecklist.map((c) => `- [ ] ${c}`).join("\n")}
|
|
|
6904
7063
|
function serializeSelfLabToMarkdown(lab) {
|
|
6905
7064
|
const renderChallenge = (c, label) => {
|
|
6906
7065
|
const tasksList = c.tasks.map((t) => `- ${t}`).join("\n");
|
|
6907
|
-
return `### ${label}: ${c.title}
|
|
7066
|
+
return `### ${label}: ${c.title}
|
|
7067
|
+
> **Duration:** ~${c.estimatedMinutes} mins
|
|
7068
|
+
|
|
6908
7069
|
**Objective:** ${c.objective}
|
|
6909
7070
|
|
|
6910
7071
|
#### Tasks & Implementation Details:
|
|
@@ -7798,7 +7959,6 @@ var STANDARD_SOT_FILES = [
|
|
|
7798
7959
|
"REFERENCE_PACK.md",
|
|
7799
7960
|
"PROJECT_GRAPH.json",
|
|
7800
7961
|
"HYBRID_GRAPH.json",
|
|
7801
|
-
"SECTION_LANGUAGE_CONTRACT.md",
|
|
7802
7962
|
"CURRICULUM_FRAMEWORK.md",
|
|
7803
7963
|
"CONTENT_STYLE_GUIDE.md",
|
|
7804
7964
|
"ART_DIRECTION.md",
|
|
@@ -9267,6 +9427,7 @@ function gateModeFor(resolved, type) {
|
|
|
9267
9427
|
}
|
|
9268
9428
|
|
|
9269
9429
|
// src/services/languageDirective.ts
|
|
9430
|
+
init_templateLoader();
|
|
9270
9431
|
function resolveTargetLanguageCode(language) {
|
|
9271
9432
|
const raw = String(language || "vi").trim().toLowerCase();
|
|
9272
9433
|
if (raw.startsWith("vi")) return "vi";
|
|
@@ -9296,193 +9457,46 @@ function buildLanguageDirective(targetLanguage) {
|
|
|
9296
9457
|
${exampleLine}` : ""}
|
|
9297
9458
|
- CJK / NON-LATIN SCRIPT BAN (ABSOLUTE): NEVER output characters from Chinese (\u6C49\u5B57), Japanese (\u304B\u306A/\u6F22\u5B57), or Korean (\uD55C\uAE00) scripts ANYWHERE in the document \u2014 not even a single glyph spliced inside a ${name} sentence. Observed past violations that are STRICTLY forbidden: \u6392\u67E5, \u5305\u542B, \u5BFC\u81F4, \u662F\u591A\u5C11, \u6280\u672F, \u771F\u673A, \u4F11\u606F, \u7EB8\u8D28. To express such meaning write it fully in ${name} or keep the ENGLISH technical term (e.g. write "t\u1EF1 ki\u1EC3m tra l\u1ED7i" / "self-debugging", "bao g\u1ED3m" / "includes"). A mechanical scanner rejects any document containing even one CJK character.`;
|
|
9298
9459
|
}
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
|
|
9314
|
-
|
|
9315
|
-
|
|
9316
|
-
|
|
9317
|
-
PROJECT_BRIEF:
|
|
9318
|
-
|
|
9319
|
-
|
|
9320
|
-
"Learning Roadmap": "L\u1ED9 tr\xECnh H\u1ECDc t\u1EADp & C\u1ED9t m\u1ED1c",
|
|
9321
|
-
"Artifact Scope": "Ph\u1EA1m vi S\u1EA3n ph\u1EA9m H\u1ECDc t\u1EADp"
|
|
9322
|
-
},
|
|
9323
|
-
CURRICULUM_FRAMEWORK: {
|
|
9324
|
-
"Course Overview": "T\u1ED5ng quan Kh\xF3a h\u1ECDc",
|
|
9325
|
-
"Global Learning Objectives": "M\u1EE5c ti\xEAu H\u1ECDc t\u1EADp To\xE0n di\u1EC7n",
|
|
9326
|
-
"Structural Hierarchy (Unit & Module)": "C\u1EA5u tr\xFAc Kh\xF3a h\u1ECDc (Unit & Module)",
|
|
9327
|
-
"Scope & Sequence (Detailed Roadmap)": "Ph\u1EA1m vi & Tr\xECnh t\u1EF1 Chi ti\u1EBFt"
|
|
9328
|
-
},
|
|
9329
|
-
CONTENT_STYLE_GUIDE: {
|
|
9330
|
-
"Voice & Tone": "Gi\u1ECDng v\u0103n & Phong c\xE1ch",
|
|
9331
|
-
"Standard Terminology (Glossary)": "Thu\u1EADt ng\u1EEF Chu\u1EA9n (B\u1EA3ng thu\u1EADt ng\u1EEF)",
|
|
9332
|
-
"Examples & Context Rules": "Quy t\u1EAFc V\xED d\u1EE5 & Ng\u1EEF c\u1EA3nh",
|
|
9333
|
-
"Lesson Content Standards": "Ti\xEAu chu\u1EA9n N\u1ED9i dung B\xE0i h\u1ECDc"
|
|
9334
|
-
},
|
|
9335
|
-
SECTION_LANGUAGE_CONTRACT: {
|
|
9336
|
-
"Metadata & Scope": "Th\xF4ng tin & Ph\u1EA1m vi H\u1EE3p \u0111\u1ED3ng",
|
|
9337
|
-
"Section Translation Matrix": "Ma tr\u1EADn Ti\xEAu \u0111\u1EC1 \u0110a ng\xF4n ng\u1EEF",
|
|
9338
|
-
"Validation Rules": "Quy t\u1EAFc X\xE1c th\u1EF1c & Kh\xF3a Chu\u1EA9n"
|
|
9339
|
-
},
|
|
9340
|
-
KNOWLEDGE_EXPOSITION: {
|
|
9341
|
-
"Session Scope": "Ph\u1EA1m vi Bu\u1ED5i h\u1ECDc",
|
|
9342
|
-
"Key Terms": "Thu\u1EADt ng\u1EEF Then ch\u1ED1t",
|
|
9343
|
-
"Concept Narratives": "Di\u1EC5n gi\u1EA3i Kh\xE1i ni\u1EC7m",
|
|
9344
|
-
"Worked Micro-Examples": "V\xED d\u1EE5 M\u1EABu Chi ti\u1EBFt",
|
|
9345
|
-
"Common Mistakes": "L\u1ED7i Th\u01B0\u1EDDng g\u1EB7p & Kh\u1EAFc ph\u1EE5c",
|
|
9346
|
-
"Self-Check Questions": "C\xE2u h\u1ECFi T\u1EF1 ki\u1EC3m tra"
|
|
9347
|
-
},
|
|
9348
|
-
LESSON: {
|
|
9349
|
-
"A. Lesson Design Plan": "A. K\u1EBF ho\u1EA1ch Thi\u1EBFt k\u1EBF B\xE0i h\u1ECDc",
|
|
9350
|
-
"Learning Objectives & Evidence": "M\u1EE5c ti\xEAu H\u1ECDc t\u1EADp & B\u1EB1ng ch\u1EE9ng N\u0103ng l\u1EF1c",
|
|
9351
|
-
"Activity Sequence": "Chu\u1ED7i Ho\u1EA1t \u0111\u1ED9ng D\u1EA1y & H\u1ECDc",
|
|
9352
|
-
"Resource Map": "B\u1EA3n \u0111\u1ED3 T\xE0i nguy\xEAn & H\u1ECDc li\u1EC7u",
|
|
9353
|
-
"Assessment Map": "B\u1EA3n \u0111\u1ED3 \u0110\xE1nh gi\xE1 N\u0103ng l\u1EF1c",
|
|
9354
|
-
"Artifact Contract": "H\u1EE3p \u0111\u1ED3ng S\u1EA3n ph\u1EA9m \u0110\u1EA7u ra",
|
|
9355
|
-
"B. Lesson Flow": "B. Ti\u1EBFn tr\xECnh Gi\u1EA3ng d\u1EA1y Chi ti\u1EBFt"
|
|
9356
|
-
},
|
|
9357
|
-
ACT: {
|
|
9358
|
-
"Computational Thinking Focus": "Tr\u1ECDng t\xE2m T\u01B0 duy M\xE1y t\xEDnh",
|
|
9359
|
-
"Materials & Setup": "V\u1EADt li\u1EC7u & Chu\u1EA9n b\u1ECB Thi\u1EBFt b\u1ECB",
|
|
9360
|
-
"Constraints & Safety": "R\xE0ng bu\u1ED9c & An to\xE0n Ph\xF2ng th\u1EF1c h\xE0nh",
|
|
9361
|
-
"Active Learning Workflow": "Quy tr\xECnh Ho\u1EA1t \u0111\u1ED9ng Tr\u1EA3i nghi\u1EC7m",
|
|
9362
|
-
"3-Tier Differentiation": "Ph\xE2n h\xF3a H\u1ECDc t\u1EADp 3 T\u1EA7ng",
|
|
9363
|
-
"Reflection": "T\u1ED5ng k\u1EBFt & \u0110\xFAc k\u1EBFt Tr\u1EA3i nghi\u1EC7m"
|
|
9364
|
-
},
|
|
9365
|
-
CODE: {
|
|
9366
|
-
"Technical Overview & Architecture Blueprint": "T\u1ED5ng quan K\u1EF9 thu\u1EADt & B\u1EA3n thi\u1EBFt k\u1EBF Ki\u1EBFn tr\xFAc",
|
|
9367
|
-
"Hardware Pinout & Wiring Configuration Matrix": "S\u01A1 \u0111\u1ED3 Ch\xE2n & Ma tr\u1EADn N\u1ED1i d\xE2y Ph\u1EA7n c\u1EE9ng",
|
|
9368
|
-
"Starter Code Sandbox": "M\xE3 ngu\u1ED3n Kh\u1EDFi \u0111\u1EA7u (Starter Code)",
|
|
9369
|
-
"Verified Reference Solution Code": "M\xE3 ngu\u1ED3n L\u1EDDi gi\u1EA3i Chu\u1EA9n (Reference Solution)",
|
|
9370
|
-
"Automated Test / Verification Script": "K\u1ECBch b\u1EA3n Ki\u1EC3m th\u1EED T\u1EF1 \u0111\u1ED9ng",
|
|
9371
|
-
"Common Syntax & Runtime Pitfalls Matrix": "Ma tr\u1EADn L\u1ED7i C\xFA ph\xE1p & Th\u1EDDi gian ch\u1EA1y Th\u01B0\u1EDDng g\u1EB7p"
|
|
9372
|
-
},
|
|
9373
|
-
CODE_LAB: {
|
|
9374
|
-
"Technical Overview & Architecture Blueprint": "T\u1ED5ng quan K\u1EF9 thu\u1EADt & B\u1EA3n thi\u1EBFt k\u1EBF Ki\u1EBFn tr\xFAc",
|
|
9375
|
-
"Hardware Pinout & Wiring Configuration Matrix": "S\u01A1 \u0111\u1ED3 Ch\xE2n & Ma tr\u1EADn N\u1ED1i d\xE2y Ph\u1EA7n c\u1EE9ng",
|
|
9376
|
-
"Starter Code Sandbox": "M\xE3 ngu\u1ED3n Kh\u1EDFi \u0111\u1EA7u (Starter Code)",
|
|
9377
|
-
"Verified Reference Solution Code": "M\xE3 ngu\u1ED3n L\u1EDDi gi\u1EA3i Chu\u1EA9n (Reference Solution)",
|
|
9378
|
-
"Automated Test / Verification Script": "K\u1ECBch b\u1EA3n Ki\u1EC3m th\u1EED T\u1EF1 \u0111\u1ED9ng",
|
|
9379
|
-
"Common Syntax & Runtime Pitfalls Matrix": "Ma tr\u1EADn L\u1ED7i C\xFA ph\xE1p & Th\u1EDDi gian ch\u1EA1y Th\u01B0\u1EDDng g\u1EB7p"
|
|
9380
|
-
},
|
|
9381
|
-
QUIZ: {
|
|
9382
|
-
"Assessment Objectives": "M\u1EE5c ti\xEAu \u0110\xE1nh gi\xE1",
|
|
9383
|
-
"Multiple-Choice Question Bank": "Ng\xE2n h\xE0ng C\xE2u h\u1ECFi Tr\u1EAFc nghi\u1EC7m",
|
|
9384
|
-
"Code Analysis / Debugging Question": "C\xE2u h\u1ECFi Ph\xE2n t\xEDch M\xE3 ngu\u1ED3n & S\u1EEDa l\u1ED7i",
|
|
9385
|
-
"Competency Rubric": "Thang \u0111o \u0110\xE1nh gi\xE1 N\u0103ng l\u1EF1c (Rubric)"
|
|
9386
|
-
},
|
|
9387
|
-
GUIDE: {
|
|
9388
|
-
"Objectives & Preparation": "M\u1EE5c ti\xEAu & Chu\u1EA9n b\u1ECB Gi\u1EA3ng d\u1EA1y",
|
|
9389
|
-
"Preparation Checklist & Workstation Setup": "Danh m\u1EE5c Ki\u1EC3m tra Chu\u1EA9n b\u1ECB & Tr\u1EA1m Th\u1EF1c h\xE0nh",
|
|
9390
|
-
"Facilitation Script & Timeline": "K\u1ECBch b\u1EA3n \u0110i\u1EC1u ph\u1ED1i & Khung Th\u1EDDi gian",
|
|
9391
|
-
"Common Misconceptions & Diagnostic Remediation Matrix": "Quan ni\u1EC7m Sai l\u1EA7m Th\u01B0\u1EDDng g\u1EB7p & Ma tr\u1EADn Kh\u1EAFc ph\u1EE5c",
|
|
9392
|
-
"Differentiated Support Strategies": "Chi\u1EBFn l\u01B0\u1EE3c H\u1ED7 tr\u1EE3 Ph\xE2n h\xF3a"
|
|
9393
|
-
},
|
|
9394
|
-
HANDOUT: {
|
|
9395
|
-
"Core Concepts": "Kh\xE1i ni\u1EC7m C\u1ED1t l\xF5i",
|
|
9396
|
-
"Core Syntax & Mechanism Cheat Sheet": "B\u1EA3ng Tra c\u1EE9u C\xFA ph\xE1p & C\u01A1 ch\u1EBF Tr\u1ECDng t\xE2m",
|
|
9397
|
-
"Visual Mental Model / Architecture Diagram": "M\xF4 h\xECnh T\u01B0 duy Tr\u1EF1c quan / S\u01A1 \u0111\u1ED3 Ki\u1EBFn tr\xFAc",
|
|
9398
|
-
"Step-by-Step Practical Quick-Start Guide": "H\u01B0\u1EDBng d\u1EABn Th\u1EF1c h\xE0nh T\u1EEBng b\u01B0\u1EDBc",
|
|
9399
|
-
"Self-Check Diagnostic Checklist": "B\u1EA3ng Ki\u1EC3m tra T\u1EF1 ch\u1EA9n \u0111o\xE1n"
|
|
9400
|
-
},
|
|
9401
|
-
WKS: {
|
|
9402
|
-
"Part 1: Knowledge Check": "Ph\u1EA7n 1: Ki\u1EC3m tra Ki\u1EBFn th\u1EE9c",
|
|
9403
|
-
"Part 2: Concept Tracing & Diagram Fill-in": "Ph\u1EA7n 2: L\u1EA7n v\u1EBFt Kh\xE1i ni\u1EC7m & \u0110i\u1EC1n S\u01A1 \u0111\u1ED3",
|
|
9404
|
-
"Part 3: Code Analysis & Bug Hunting Challenge": "Ph\u1EA7n 3: Ph\xE2n t\xEDch M\xE3 & Th\u1EED th\xE1ch S\u0103n l\u1ED7i",
|
|
9405
|
-
"Part 4: Synthesis & Problem-Solving Application": "Ph\u1EA7n 4: T\u1ED5ng h\u1EE3p & \u1EE8ng d\u1EE5ng Gi\u1EA3i quy\u1EBFt V\u1EA5n \u0111\u1EC1",
|
|
9406
|
-
"Part 5: Self-Reflection & Learning Log": "Ph\u1EA7n 5: T\u1EF1 suy ng\u1EABm & Nh\u1EADt k\xFD H\u1ECDc t\u1EADp"
|
|
9407
|
-
},
|
|
9408
|
-
EXT: {
|
|
9409
|
-
"For: Advanced Students / Extra Time": "D\xE0nh cho: H\u1ECDc sinh N\xE2ng cao / Ho\xE0n th\xE0nh S\u1EDBm",
|
|
9410
|
-
"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",
|
|
9411
|
-
"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",
|
|
9412
|
-
"Challenge 3: Extension Milestones": "Th\u1EED th\xE1ch 3: C\xE1c M\u1ED1c Nhi\u1EC7m v\u1EE5 N\xE2ng cao",
|
|
9413
|
-
"Metacognitive Deep Dive & Engineering Trade-offs": "Suy ng\u1EABm Si\xEAu nh\u1EADn th\u1EE9c & \u0110\xE1nh \u0111\u1ED5i K\u1EF9 thu\u1EADt"
|
|
9414
|
-
},
|
|
9415
|
-
SLIDE: {
|
|
9416
|
-
"Title & Agenda": "Ti\xEAu \u0111\u1EC1 & M\u1EE5c l\u1EE5c",
|
|
9417
|
-
"Core Concepts": "Kh\xE1i ni\u1EC7m C\u1ED1t l\xF5i",
|
|
9418
|
-
"Guided Demonstration": "H\u01B0\u1EDBng d\u1EABn Th\u1EF1c h\xE0nh & Th\u1ECB ph\u1EA1m",
|
|
9419
|
-
"Hands-on Mission": "Nhi\u1EC7m v\u1EE5 Th\u1EF1c h\xE0nh Tr\u1EA3i nghi\u1EC7m",
|
|
9420
|
-
"Summary & Next Steps": "T\u1ED5ng k\u1EBFt & \u0110\u1ECBnh h\u01B0\u1EDBng Ti\u1EBFp theo"
|
|
9421
|
-
}
|
|
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 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"
|
|
9422
9481
|
};
|
|
9423
|
-
function
|
|
9424
|
-
const
|
|
9425
|
-
|
|
9426
|
-
|
|
9427
|
-
|
|
9428
|
-
|
|
9429
|
-
|
|
9430
|
-
|
|
9431
|
-
|
|
9432
|
-
}
|
|
9433
|
-
return {};
|
|
9434
|
-
};
|
|
9435
|
-
if (!slcInput) return getFallback();
|
|
9436
|
-
if (typeof slcInput === "object") {
|
|
9437
|
-
if (slcInput[upperType] && Object.keys(slcInput[upperType]).length > 0) return slcInput[upperType];
|
|
9438
|
-
for (const [key, mapping] of Object.entries(slcInput)) {
|
|
9439
|
-
if (matchesArtifactType(key, upperType) && Object.keys(mapping).length > 0) {
|
|
9440
|
-
return mapping;
|
|
9441
|
-
}
|
|
9442
|
-
}
|
|
9443
|
-
return getFallback();
|
|
9444
|
-
}
|
|
9445
|
-
const slcMarkdown = slcInput;
|
|
9446
|
-
const blocks = slcMarkdown.split(/\n(?=#{2,3}\s+[A-Z0-9_]+)/g);
|
|
9447
|
-
for (const block of blocks) {
|
|
9448
|
-
const headerMatch = block.match(/^#{2,3}\s+([A-Z0-9_]+)/);
|
|
9449
|
-
if (!headerMatch) continue;
|
|
9450
|
-
const blockType = headerMatch[1].trim().toUpperCase();
|
|
9451
|
-
if (matchesArtifactType(blockType, upperType)) {
|
|
9452
|
-
const mapping = {};
|
|
9453
|
-
const lines = block.split("\n");
|
|
9454
|
-
for (const line of lines) {
|
|
9455
|
-
const trimmed = line.trim();
|
|
9456
|
-
if (trimmed.startsWith("|") && !trimmed.includes("---")) {
|
|
9457
|
-
const cells = trimmed.split("|").map((c) => c.trim()).filter((_, idx, arr) => idx > 0 && idx < arr.length - 1);
|
|
9458
|
-
if (cells.length >= 2 && !cells[0].toLowerCase().includes("canonical") && !cells[1].toLowerCase().includes("localized")) {
|
|
9459
|
-
mapping[cells[0]] = cells[1];
|
|
9460
|
-
}
|
|
9461
|
-
} else {
|
|
9462
|
-
const bullet = line.match(/^[-*]\s+([^:]+):\s+(.+)$/);
|
|
9463
|
-
if (bullet) {
|
|
9464
|
-
mapping[bullet[1].trim()] = bullet[2].trim();
|
|
9465
|
-
}
|
|
9466
|
-
}
|
|
9467
|
-
}
|
|
9468
|
-
if (Object.keys(mapping).length > 0) return mapping;
|
|
9469
|
-
}
|
|
9470
|
-
}
|
|
9471
|
-
return getFallback();
|
|
9472
|
-
}
|
|
9473
|
-
function buildHeadingDirective(artifactType, slcMarkdown, targetLanguage = "vi") {
|
|
9474
|
-
const headings = extractSectionHeadingsFromSLC(slcMarkdown, artifactType, targetLanguage);
|
|
9482
|
+
function extractSectionHeadings(artifactType, opts) {
|
|
9483
|
+
const templateFile = TEMPLATE_BY_TYPE[artifactType.trim().toUpperCase()];
|
|
9484
|
+
if (!templateFile) return {};
|
|
9485
|
+
const resolved = resolveArtifactTemplate(templateFile, opts);
|
|
9486
|
+
if (!resolved) return {};
|
|
9487
|
+
return Object.fromEntries(resolved.sections.map((s) => [s, s]));
|
|
9488
|
+
}
|
|
9489
|
+
function buildHeadingDirective(artifactType, opts) {
|
|
9490
|
+
const headings = extractSectionHeadings(artifactType, opts);
|
|
9475
9491
|
if (Object.keys(headings).length === 0) {
|
|
9476
9492
|
return "";
|
|
9477
9493
|
}
|
|
9478
|
-
const lines = Object.
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9482
|
-
- The YAML frontmatter \`template_required_sections\` MUST preserve the exact English canonical keys.
|
|
9483
|
-
- In the markdown body, section headers MUST use the EXACT Localized Display Labels below (do NOT translate or paraphrase):
|
|
9494
|
+
const lines = Object.keys(headings).map((heading) => ` - "${heading}"`);
|
|
9495
|
+
return `MANDATORY SECTION HEADINGS (SOURCE: RESOLVED ARTIFACT TEMPLATE):
|
|
9496
|
+
- Copy the template's YAML frontmatter \`template_required_sections\` list VERBATIM into the artifact frontmatter \u2014 never translate, reorder, or invent entries.
|
|
9497
|
+
- In the markdown body, section headers MUST be exactly the Display Headings below (do NOT translate, paraphrase, or re-marker them):
|
|
9484
9498
|
${lines.join("\n")}
|
|
9485
|
-
-
|
|
9499
|
+
- Example: if the resolved template's heading is "${Object.values(headings)[0]}", your body heading must be exactly "## ${Object.values(headings)[0]}".`;
|
|
9486
9500
|
}
|
|
9487
9501
|
|
|
9488
9502
|
// src/services/curriculumHorizon.ts
|
|
@@ -9841,9 +9855,8 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
|
|
|
9841
9855
|
};
|
|
9842
9856
|
}
|
|
9843
9857
|
const minContentChars = opts.minContentChars !== void 0 ? opts.minContentChars : Math.min(400, source.length);
|
|
9844
|
-
const slcMap = normalizeSlcContract(opts.sectionLanguageContract);
|
|
9845
9858
|
const effectiveArtifactType = opts.artifactType || deriveArtifactTypeFromFileName(opts.fileName);
|
|
9846
|
-
const sections = parseMarkdownSections(source
|
|
9859
|
+
const sections = parseMarkdownSections(source);
|
|
9847
9860
|
const metaBlock = buildMetaBlock(source, effectiveArtifactType);
|
|
9848
9861
|
if (sections.length === 0) {
|
|
9849
9862
|
issues.push("parse:no-sections");
|
|
@@ -9866,7 +9879,7 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
|
|
|
9866
9879
|
if (s.canonicalKey && !byCanonical.has(s.canonicalKey)) {
|
|
9867
9880
|
byCanonical.set(s.canonicalKey, s);
|
|
9868
9881
|
}
|
|
9869
|
-
const norm2 =
|
|
9882
|
+
const norm2 = normalizeHeading(s.cleanTitle);
|
|
9870
9883
|
if (!byCleanTitle.has(norm2)) {
|
|
9871
9884
|
byCleanTitle.set(norm2, s);
|
|
9872
9885
|
}
|
|
@@ -9916,7 +9929,7 @@ ${truncated}`;
|
|
|
9916
9929
|
blocks.push(metaBlock);
|
|
9917
9930
|
let sectionAware = false;
|
|
9918
9931
|
for (const key of priorities) {
|
|
9919
|
-
const sec = byCanonical.get(key) || byCleanTitle.get(
|
|
9932
|
+
const sec = byCanonical.get(key) || byCleanTitle.get(normalizeHeading(key));
|
|
9920
9933
|
if (!sec) continue;
|
|
9921
9934
|
sectionAware = true;
|
|
9922
9935
|
if (!tryAdd(sec.cleanTitle, sec.body, key)) break;
|
|
@@ -9966,48 +9979,16 @@ function buildLessonExcerpt(markdown, opts = {}) {
|
|
|
9966
9979
|
priorities: DEFAULT_LESSON_PRIORITIES
|
|
9967
9980
|
});
|
|
9968
9981
|
}
|
|
9969
|
-
function
|
|
9970
|
-
if (!slc) return void 0;
|
|
9971
|
-
if (typeof slc !== "string") return slc;
|
|
9972
|
-
const out = {};
|
|
9973
|
-
const blocks = slc.split(/\n(?=#{2,3}\s+[A-Z0-9_]+)/g);
|
|
9974
|
-
for (const block of blocks) {
|
|
9975
|
-
const header = block.match(/^#{2,3}\s+([A-Z0-9_]+)/);
|
|
9976
|
-
if (!header?.[1]) continue;
|
|
9977
|
-
const mapping = {};
|
|
9978
|
-
for (const line of block.split("\n")) {
|
|
9979
|
-
const t = line.trim();
|
|
9980
|
-
if (!t.startsWith("|") || t.includes("---")) continue;
|
|
9981
|
-
const cells = t.split("|").map((c) => c.trim()).filter((_, i, a) => i > 0 && i < a.length - 1);
|
|
9982
|
-
const [c0, c1] = cells;
|
|
9983
|
-
if (c0 && c1 && !c0.toLowerCase().includes("canonical") && !c1.toLowerCase().includes("localized")) {
|
|
9984
|
-
mapping[c0] = c1;
|
|
9985
|
-
}
|
|
9986
|
-
}
|
|
9987
|
-
if (Object.keys(mapping).length > 0) out[header[1]] = mapping;
|
|
9988
|
-
}
|
|
9989
|
-
return Object.keys(out).length > 0 ? out : void 0;
|
|
9990
|
-
}
|
|
9991
|
-
function parseMarkdownSections(markdown, slcMap, artifactType) {
|
|
9982
|
+
function parseMarkdownSections(markdown) {
|
|
9992
9983
|
const sections = [];
|
|
9993
9984
|
const lines = markdown.split("\n");
|
|
9994
9985
|
let currentHeading = "";
|
|
9995
9986
|
let currentBody = [];
|
|
9996
|
-
const reverseMap = /* @__PURE__ */ new Map();
|
|
9997
|
-
if (slcMap) {
|
|
9998
|
-
const maps = artifactType && slcMap[artifactType] ? [slcMap[artifactType]] : Object.values(slcMap);
|
|
9999
|
-
for (const m of maps) {
|
|
10000
|
-
for (const [canonical, localized] of Object.entries(m)) {
|
|
10001
|
-
reverseMap.set(normalizeHeading2(localized), canonical);
|
|
10002
|
-
reverseMap.set(normalizeHeading2(canonical), canonical);
|
|
10003
|
-
}
|
|
10004
|
-
}
|
|
10005
|
-
}
|
|
10006
9987
|
const flush = () => {
|
|
10007
9988
|
if (!currentHeading) return;
|
|
10008
9989
|
const cleanTitle = currentHeading.replace(/^#{1,4}\s+/, "").trim();
|
|
10009
|
-
const norm2 =
|
|
10010
|
-
const canonicalKey =
|
|
9990
|
+
const norm2 = normalizeHeading(cleanTitle);
|
|
9991
|
+
const canonicalKey = findCanonicalFuzzy(norm2);
|
|
10011
9992
|
sections.push({
|
|
10012
9993
|
rawHeading: currentHeading,
|
|
10013
9994
|
cleanTitle,
|
|
@@ -10030,7 +10011,7 @@ function parseMarkdownSections(markdown, slcMap, artifactType) {
|
|
|
10030
10011
|
flush();
|
|
10031
10012
|
return sections;
|
|
10032
10013
|
}
|
|
10033
|
-
function
|
|
10014
|
+
function normalizeHeading(str) {
|
|
10034
10015
|
return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
10035
10016
|
}
|
|
10036
10017
|
function findCanonicalFuzzy(norm2) {
|
|
@@ -10106,7 +10087,7 @@ function buildMetaBlock(source, artifactType) {
|
|
|
10106
10087
|
function deriveArtifactTypeFromFileName(fileName) {
|
|
10107
10088
|
if (!fileName) return void 0;
|
|
10108
10089
|
const base = fileName.replace(/\.md$/i, "");
|
|
10109
|
-
const multiWord = base.match(/^(KNOWLEDGE_EXPOSITION|
|
|
10090
|
+
const multiWord = base.match(/^(KNOWLEDGE_EXPOSITION|CONTENT_STYLE_GUIDE|CURRICULUM_FRAMEWORK|LEARNER_PROFILE|PROJECT_BRIEF|REFERENCE_PACK|CURRICULUM_PLAN)/i);
|
|
10110
10091
|
if (multiWord) return multiWord[1].toUpperCase();
|
|
10111
10092
|
const token = base.match(/^([A-Z][A-Z0-9_]*?)(?=_|$)/);
|
|
10112
10093
|
return token ? token[1] : void 0;
|
|
@@ -10333,19 +10314,18 @@ function buildSystemPrompt(targetLanguage = "vi", techStack, hardwarePlatform) {
|
|
|
10333
10314
|
langDirective
|
|
10334
10315
|
].join("\n");
|
|
10335
10316
|
}
|
|
10336
|
-
function buildUserPrompt(session, plan, glossary, targetLanguage = "vi",
|
|
10317
|
+
function buildUserPrompt(session, plan, glossary, targetLanguage = "vi", refPack) {
|
|
10337
10318
|
const depthLines = session.depth_assignments.map((d) => "- " + d.node_id + " [" + d.depth.toUpperCase() + "]: " + DEPTH_RULES[d.depth]).join("\n");
|
|
10338
10319
|
const termLines = glossary.map((g) => "- " + g.term + (g.definition ? " \u2014 " + g.definition : "") + (g.example ? " (example: " + g.example + ")" : "")).join("\n");
|
|
10339
|
-
const
|
|
10340
|
-
const
|
|
10341
|
-
const
|
|
10342
|
-
const
|
|
10343
|
-
const
|
|
10344
|
-
const
|
|
10345
|
-
const
|
|
10346
|
-
const hQuestions = headings["Self-Check Questions"] || (langCode === "vi" ? "C\xE2u h\u1ECFi T\u1EF1 ki\u1EC3m tra" : "Self-Check Questions");
|
|
10320
|
+
const headings = extractSectionHeadings("KNOWLEDGE_EXPOSITION");
|
|
10321
|
+
const hScope = headings["Session Scope"] || "Session Scope";
|
|
10322
|
+
const hTerms = headings["Key Terms"] || "Key Terms";
|
|
10323
|
+
const hNarratives = headings["Concept Narratives"] || "Concept Narratives";
|
|
10324
|
+
const hExamples = headings["Worked Micro-Examples"] || "Worked Micro-Examples";
|
|
10325
|
+
const hMistakes = headings["Common Mistakes"] || "Common Mistakes";
|
|
10326
|
+
const hQuestions = headings["Self-Check Questions"] || "Self-Check Questions";
|
|
10347
10327
|
const skeleton = `## ${hScope} / ## ${hTerms} / ## ${hNarratives} / ## ${hExamples} / ## ${hMistakes} / ## ${hQuestions}`;
|
|
10348
|
-
const headingDirective = buildHeadingDirective("KNOWLEDGE_EXPOSITION"
|
|
10328
|
+
const headingDirective = buildHeadingDirective("KNOWLEDGE_EXPOSITION");
|
|
10349
10329
|
let refPackBlock = "";
|
|
10350
10330
|
if (refPack && refPack.trim()) {
|
|
10351
10331
|
const refExcerpt = buildSectionAwareExcerpt(refPack, {
|
|
@@ -10411,7 +10391,7 @@ async function ensureKnowledgeExposition(options) {
|
|
|
10411
10391
|
skipToolchainList: true
|
|
10412
10392
|
// same RefPack excerpt already in [GROUND TRUTH]
|
|
10413
10393
|
});
|
|
10414
|
-
const originalUserPrompt = buildUserPrompt(session, plan, glossary, targetLanguage,
|
|
10394
|
+
const originalUserPrompt = buildUserPrompt(session, plan, glossary, targetLanguage, refPack) + (productSpecBlock ? "\n\n" + productSpecBlock : "");
|
|
10415
10395
|
const content = (await llmFn(
|
|
10416
10396
|
originalSystemPrompt,
|
|
10417
10397
|
originalUserPrompt
|
|
@@ -10549,7 +10529,6 @@ async function ensureExpositionForLesson(storage, projectId, lessonCode, options
|
|
|
10549
10529
|
plan,
|
|
10550
10530
|
glossary,
|
|
10551
10531
|
targetLanguage: targetLang,
|
|
10552
|
-
slcMarkdown: options.slcMarkdown,
|
|
10553
10532
|
techStack: tech,
|
|
10554
10533
|
hardwarePlatform: hw,
|
|
10555
10534
|
refPack: refPackContent,
|
|
@@ -24918,7 +24897,6 @@ function buildSatelliteContext(input) {
|
|
|
24918
24897
|
lessonContent,
|
|
24919
24898
|
lessonExcerpt,
|
|
24920
24899
|
expositionContent,
|
|
24921
|
-
slcMarkdown,
|
|
24922
24900
|
symbolLedgerBlock,
|
|
24923
24901
|
pedagogyLabel,
|
|
24924
24902
|
lessonEntity,
|
|
@@ -24954,7 +24932,6 @@ ${lessonExcerpt.excerpt}${symbolLedgerBlock}`;
|
|
|
24954
24932
|
const kxExcerpt = buildSectionAwareExcerpt(expositionContent, {
|
|
24955
24933
|
priorities: KX_SLOT_PRIORITIES[type] ?? ["Key Terms", "Concept Narratives", "Worked Micro-Examples"],
|
|
24956
24934
|
budget: 4500,
|
|
24957
|
-
sectionLanguageContract: slcMarkdown,
|
|
24958
24935
|
artifactType: "KNOWLEDGE_EXPOSITION"
|
|
24959
24936
|
});
|
|
24960
24937
|
parts.push(`
|
|
@@ -24986,7 +24963,6 @@ ${slots}`;
|
|
|
24986
24963
|
const excerpt = buildSectionAwareExcerpt(lessonContent, {
|
|
24987
24964
|
priorities: spec.priorities ?? ["Artifact Contract", "A. Lesson Design Plan", "B. Lesson Flow", "Learning Objectives & Evidence", "Activity Sequence"],
|
|
24988
24965
|
budget: spec.budget,
|
|
24989
|
-
sectionLanguageContract: slcMarkdown,
|
|
24990
24966
|
artifactType: "LESSON"
|
|
24991
24967
|
});
|
|
24992
24968
|
const excerptBlock = `
|
|
@@ -25101,6 +25077,7 @@ function evaluateActivityAlignment(canonicalExcerpt, generatedContent, now = /*
|
|
|
25101
25077
|
}
|
|
25102
25078
|
|
|
25103
25079
|
// src/services/lessonProductionService.ts
|
|
25080
|
+
init_templateLoader();
|
|
25104
25081
|
var LESSON_TEMPLATE_BY_PEDAGOGY = {
|
|
25105
25082
|
edp: "LESSON_EDP_template.md",
|
|
25106
25083
|
general: "LESSON_GENERAL_template.md",
|
|
@@ -25280,7 +25257,7 @@ ${nextRow}`
|
|
|
25280
25257
|
].filter(Boolean);
|
|
25281
25258
|
return parts.join("\n\n") || framework.slice(0, 1500);
|
|
25282
25259
|
}
|
|
25283
|
-
function buildLessonPrompt(pedagogy, lessonCode, unitCode, lessonTitle, concept, bloomLevel, dateStr, targetLanguage = "vi"
|
|
25260
|
+
function buildLessonPrompt(pedagogy, lessonCode, unitCode, lessonTitle, concept, bloomLevel, dateStr, targetLanguage = "vi") {
|
|
25284
25261
|
const templateFile = LESSON_TEMPLATE_BY_PEDAGOGY[pedagogy] ?? "LESSON_5E_template.md";
|
|
25285
25262
|
const artifactType = templateFile.replace("_template.md", "");
|
|
25286
25263
|
const contract = resolveArtifactTemplate(templateFile)?.sections ?? [];
|
|
@@ -25323,9 +25300,7 @@ type: "${artifactType}"
|
|
|
25323
25300
|
${NO_VERBATIM_COPYING}`;
|
|
25324
25301
|
const langDirective = buildLanguageDirective(targetLanguage);
|
|
25325
25302
|
const headingDirective = buildHeadingDirective(
|
|
25326
|
-
pedagogy === "edp" ? "LESSON_EDP" : pedagogy === "general" || pedagogy === "pbl" ? "LESSON_GENERAL" : "LESSON_5E"
|
|
25327
|
-
sectionLanguageContract,
|
|
25328
|
-
targetLanguage
|
|
25303
|
+
pedagogy === "edp" ? "LESSON_EDP" : pedagogy === "general" || pedagogy === "pbl" ? "LESSON_GENERAL" : "LESSON_5E"
|
|
25329
25304
|
);
|
|
25330
25305
|
const body = buildArtifactPrompt({ directive, templateFile });
|
|
25331
25306
|
return `${body}
|
|
@@ -25378,7 +25353,6 @@ async function produceSingleLesson(storage, projectId, lessonId, options = {}) {
|
|
|
25378
25353
|
if (!currentPlanHash || content.includes('plan_hash: "' + currentPlanHash + '"')) return content;
|
|
25379
25354
|
return content + '\n---\nplan_hash: "' + currentPlanHash + '"\n- **Plan reference:** ' + currentPlanHash + "\n";
|
|
25380
25355
|
};
|
|
25381
|
-
const slcMarkdown = options.sectionLanguageContract || await storage.readSotDocument(projectId, "SECTION_LANGUAGE_CONTRACT.md") || "";
|
|
25382
25356
|
let targetLang = options.targetLanguage;
|
|
25383
25357
|
if (!targetLang) {
|
|
25384
25358
|
try {
|
|
@@ -25401,13 +25375,11 @@ async function produceSingleLesson(storage, projectId, lessonId, options = {}) {
|
|
|
25401
25375
|
gates: resolveGateSettings(options.gateSettings),
|
|
25402
25376
|
force: options.force,
|
|
25403
25377
|
targetLanguage: targetLang,
|
|
25404
|
-
slcMarkdown,
|
|
25405
25378
|
customInference: options.customInference
|
|
25406
25379
|
});
|
|
25407
25380
|
if (exposition) {
|
|
25408
25381
|
const expoExcerpt = buildExpositionExcerpt(exposition.rawContent || exposition.context, {
|
|
25409
25382
|
budget: 6e3,
|
|
25410
|
-
sectionLanguageContract: slcMarkdown,
|
|
25411
25383
|
artifactType: "KNOWLEDGE_EXPOSITION"
|
|
25412
25384
|
});
|
|
25413
25385
|
expositionContext = expoExcerpt.excerpt || exposition.context;
|
|
@@ -25616,8 +25588,7 @@ Khi n\u1ED9i dung c\u1EA7n minh h\u1ECDa (diagram quy tr\xECnh, s\u01A1 \u0111\u
|
|
|
25616
25588
|
concept,
|
|
25617
25589
|
bloomLevel,
|
|
25618
25590
|
dateStr,
|
|
25619
|
-
targetLang
|
|
25620
|
-
slcMarkdown
|
|
25591
|
+
targetLang
|
|
25621
25592
|
) + mediaDirective;
|
|
25622
25593
|
const rawLesson = await runCurriculumAIInference(
|
|
25623
25594
|
[{ role: "user", content: lessonPrompt }],
|
|
@@ -25735,7 +25706,7 @@ ${yamlBlock.trim()}
|
|
|
25735
25706
|
});
|
|
25736
25707
|
}
|
|
25737
25708
|
const judgeObjectives = parseLessonObjectives(lessonContent, concept, bloomLevel);
|
|
25738
|
-
const judgeExpositionExcerpt = expositionContext ? buildExpositionExcerpt(expositionContext, { budget: 3e3,
|
|
25709
|
+
const judgeExpositionExcerpt = expositionContext ? buildExpositionExcerpt(expositionContext, { budget: 3e3, artifactType: "KNOWLEDGE_EXPOSITION" }).excerpt : void 0;
|
|
25739
25710
|
const judgeResult = await LLMJudgeEngine.evaluateArtifactWithLLM({
|
|
25740
25711
|
targetArtifactType: "LESSON",
|
|
25741
25712
|
lessonId: lessonCode,
|
|
@@ -25805,7 +25776,6 @@ ${currentContent}` }],
|
|
|
25805
25776
|
const repairedExcerptCheck = buildSectionAwareExcerpt(repairedRaw, {
|
|
25806
25777
|
priorities: DEFAULT_LESSON_PRIORITIES,
|
|
25807
25778
|
budget: 12e3,
|
|
25808
|
-
sectionLanguageContract: slcMarkdown,
|
|
25809
25779
|
artifactType: "LESSON"
|
|
25810
25780
|
});
|
|
25811
25781
|
if (repairedExcerptCheck.issues.includes("parse:no-priority-resolution")) {
|
|
@@ -25836,7 +25806,7 @@ ${currentContent}` }],
|
|
|
25836
25806
|
title: lessonTitle,
|
|
25837
25807
|
frameworkExcerpt: framework ? buildFrameworkExcerptForLesson(framework, lessonId) : void 0,
|
|
25838
25808
|
styleGuideExcerpt: effectiveStyleGuide || void 0,
|
|
25839
|
-
canonicalExposition: expositionContext ? buildExpositionExcerpt(expositionContext, { budget: 3e3,
|
|
25809
|
+
canonicalExposition: expositionContext ? buildExpositionExcerpt(expositionContext, { budget: 3e3, artifactType: "KNOWLEDGE_EXPOSITION" }).excerpt : void 0
|
|
25840
25810
|
}),
|
|
25841
25811
|
standardStatements: Object.keys(standardStatements).length > 0 ? standardStatements : void 0
|
|
25842
25812
|
});
|
|
@@ -25966,7 +25936,6 @@ ${currentContent}` }],
|
|
|
25966
25936
|
const lessonExcerptResult = buildSectionAwareExcerpt(lessonContent, {
|
|
25967
25937
|
priorities: SATELLITE_LESSON_PRIORITIES,
|
|
25968
25938
|
budget: 12e3,
|
|
25969
|
-
sectionLanguageContract: slcMarkdown,
|
|
25970
25939
|
artifactType: "LESSON"
|
|
25971
25940
|
});
|
|
25972
25941
|
const lessonExcerpt = lessonExcerptResult.excerpt;
|
|
@@ -25996,7 +25965,6 @@ ${currentContent}` }],
|
|
|
25996
25965
|
lessonContent,
|
|
25997
25966
|
lessonExcerpt: lessonExcerptResult,
|
|
25998
25967
|
expositionContent: expositionContext,
|
|
25999
|
-
slcMarkdown,
|
|
26000
25968
|
symbolLedgerBlock,
|
|
26001
25969
|
pedagogyLabel,
|
|
26002
25970
|
lessonEntity,
|
|
@@ -26110,7 +26078,7 @@ ${NO_VERBATIM_COPYING}`;
|
|
|
26110
26078
|
|
|
26111
26079
|
${languageDirective}
|
|
26112
26080
|
|
|
26113
|
-
${buildHeadingDirective("ACT"
|
|
26081
|
+
${buildHeadingDirective("ACT")}`;
|
|
26114
26082
|
const rawAct = await runCurriculumAIInference(
|
|
26115
26083
|
[{ role: "user", content: actPrompt }],
|
|
26116
26084
|
satelliteContextFor("ACT"),
|
|
@@ -26181,7 +26149,7 @@ ${NO_VERBATIM_COPYING}`;
|
|
|
26181
26149
|
|
|
26182
26150
|
${languageDirective}
|
|
26183
26151
|
|
|
26184
|
-
${buildHeadingDirective("QUIZ"
|
|
26152
|
+
${buildHeadingDirective("QUIZ")}`;
|
|
26185
26153
|
const rawQuiz = await runCurriculumAIInference(
|
|
26186
26154
|
[{ role: "user", content: quizPrompt }],
|
|
26187
26155
|
satelliteContextFor("QUIZ"),
|
|
@@ -26234,7 +26202,7 @@ ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
|
|
|
26234
26202
|
stylePresetId: "blue-professional",
|
|
26235
26203
|
language: targetLang || "Vietnamese",
|
|
26236
26204
|
languageDirective,
|
|
26237
|
-
headingDirective: buildHeadingDirective("SLIDE"
|
|
26205
|
+
headingDirective: buildHeadingDirective("SLIDE"),
|
|
26238
26206
|
groundContext: slideGroundContext,
|
|
26239
26207
|
productSpecBlock: productSpecBlock || void 0,
|
|
26240
26208
|
satelliteContext: satelliteContextFor("SLIDE"),
|
|
@@ -26317,7 +26285,7 @@ footer: "Curriculum OS \u2022 ${lessonCode} (${pedagogyLabel})"
|
|
|
26317
26285
|
lessonCode,
|
|
26318
26286
|
templateScaffold,
|
|
26319
26287
|
languageDirective,
|
|
26320
|
-
headingDirective: buildHeadingDirective("SLIDE"
|
|
26288
|
+
headingDirective: buildHeadingDirective("SLIDE")
|
|
26321
26289
|
});
|
|
26322
26290
|
const rawSlide = await runCurriculumAIInference(
|
|
26323
26291
|
[{ role: "user", content: slidePrompt }],
|
|
@@ -26386,7 +26354,7 @@ ${NO_VERBATIM_COPYING}`;
|
|
|
26386
26354
|
|
|
26387
26355
|
${languageDirective}
|
|
26388
26356
|
|
|
26389
|
-
${buildHeadingDirective("GUIDE"
|
|
26357
|
+
${buildHeadingDirective("GUIDE")}`;
|
|
26390
26358
|
const rawGuide = await runCurriculumAIInference(
|
|
26391
26359
|
[{ role: "user", content: guidePrompt }],
|
|
26392
26360
|
satelliteContextFor("GUIDE"),
|
|
@@ -26442,7 +26410,7 @@ ${NO_VERBATIM_COPYING}`;
|
|
|
26442
26410
|
|
|
26443
26411
|
${languageDirective}
|
|
26444
26412
|
|
|
26445
|
-
${buildHeadingDirective("HANDOUT"
|
|
26413
|
+
${buildHeadingDirective("HANDOUT")}`;
|
|
26446
26414
|
const rawHandout = await runCurriculumAIInference(
|
|
26447
26415
|
[{ role: "user", content: handoutPrompt }],
|
|
26448
26416
|
satelliteContextFor("HANDOUT"),
|
|
@@ -26498,7 +26466,7 @@ ${NO_VERBATIM_COPYING}`;
|
|
|
26498
26466
|
|
|
26499
26467
|
${languageDirective}
|
|
26500
26468
|
|
|
26501
|
-
${buildHeadingDirective("WKS"
|
|
26469
|
+
${buildHeadingDirective("WKS")}`;
|
|
26502
26470
|
const rawWks = await runCurriculumAIInference(
|
|
26503
26471
|
[{ role: "user", content: wksPrompt }],
|
|
26504
26472
|
satelliteContextFor("WKS"),
|
|
@@ -26561,7 +26529,7 @@ ${NO_VERBATIM_COPYING}`;
|
|
|
26561
26529
|
|
|
26562
26530
|
${languageDirective}
|
|
26563
26531
|
|
|
26564
|
-
${buildHeadingDirective("CODE"
|
|
26532
|
+
${buildHeadingDirective("CODE")}`;
|
|
26565
26533
|
const rawCode = await runCurriculumAIInference(
|
|
26566
26534
|
[{ role: "user", content: codePrompt }],
|
|
26567
26535
|
satelliteContextFor("CODE"),
|
|
@@ -26648,7 +26616,7 @@ ${zpdCeilingPrompt}
|
|
|
26648
26616
|
|
|
26649
26617
|
${languageDirective}
|
|
26650
26618
|
|
|
26651
|
-
${buildHeadingDirective("EXT"
|
|
26619
|
+
${buildHeadingDirective("EXT")}`;
|
|
26652
26620
|
const rawExt = await runCurriculumAIInference(
|
|
26653
26621
|
[{ role: "user", content: extPrompt }],
|
|
26654
26622
|
satelliteContextFor("EXT"),
|
|
@@ -27144,11 +27112,7 @@ async function generateSingleArtifact(req) {
|
|
|
27144
27112
|
language.toLowerCase().includes("bilingual") || language.toLowerCase().includes("song");
|
|
27145
27113
|
const targetLang = resolveTargetLanguageCode(language);
|
|
27146
27114
|
const langDirective = buildLanguageDirective(language);
|
|
27147
|
-
const headingDirective = buildHeadingDirective(
|
|
27148
|
-
artifactType.toUpperCase(),
|
|
27149
|
-
req.sectionLanguageContract,
|
|
27150
|
-
targetLang
|
|
27151
|
-
);
|
|
27115
|
+
const headingDirective = buildHeadingDirective(artifactType.toUpperCase());
|
|
27152
27116
|
const availableSources = {
|
|
27153
27117
|
KNOWLEDGE_EXPOSITION: contextSot.exposition || researchContext,
|
|
27154
27118
|
CANONICAL_LESSON: contextSot.lessonPlan,
|
|
@@ -27215,11 +27179,10 @@ ${symbolLedgerPrompt}
|
|
|
27215
27179
|
|
|
27216
27180
|
IMAGE PLANNING (media ledger) \u2014 QUOTA GEN: t\u1ED1i \u0111a ${mediaPolicy.maxGenImagesPerArtifact} \u1EA3nh AI cho artifact n\xE0y (\u1EA3nh search kho kh\xF4ng gi\u1EDBi h\u1EA1n).
|
|
27217
27181
|
Khi n\u1ED9i dung c\u1EA7n minh h\u1ECDa (diagram quy tr\xECnh, s\u01A1 \u0111\u1ED3 kh\xE1i ni\u1EC7m, step-by-step visual), ch\xE8n placeholder \u0111\xFAng format [IMAGE: slug] (slug ch\u1EEF th\u01B0\u1EDDng-g\u1EA1ch ngang, unique trong b\xE0i, vd img-for-loop-diagram) T\u1EA0I \u0110\xDANG CH\u1ED6 c\u1EA7n \u1EA3nh, tr\xEAn d\xF2ng ri\xEAng. KH\xD4NG t\u1EF1 sinh \u1EA3nh, KH\xD4NG d\xF9ng markdown image \u2014 placeholder s\u1EBD \u0111\u01B0\u1EE3c thay b\u1EB1ng \u1EA3nh th\u1EADt sau khi Media Curator duy\u1EC7t. Ch\u1EC9 \u0111\u1EB7t cho \u1EA3nh TH\u1EF0C S\u1EF0 c\u1EA7n thi\u1EBFt.` : ""}`;
|
|
27218
|
-
const
|
|
27219
|
-
const
|
|
27220
|
-
const
|
|
27221
|
-
const
|
|
27222
|
-
const expositionExcerpt = contextSot.exposition ? buildExpositionExcerpt(contextSot.exposition, { budget: 6e3, sectionLanguageContract: slcContract }).excerpt : "";
|
|
27182
|
+
const frameworkExcerpt = contextSot.framework ? buildSectionAwareExcerpt(contextSot.framework, { budget: 2500 }).excerpt : "";
|
|
27183
|
+
const lessonPlanExcerpt = contextSot.lessonPlan ? buildLessonExcerpt(contextSot.lessonPlan, { budget: 8e3, artifactType: "LESSON" }).excerpt : "";
|
|
27184
|
+
const handoutExcerpt = contextSot.handout ? buildSectionAwareExcerpt(contextSot.handout, { budget: 2e3 }).excerpt : "";
|
|
27185
|
+
const expositionExcerpt = contextSot.exposition ? buildExpositionExcerpt(contextSot.exposition, { budget: 6e3 }).excerpt : "";
|
|
27223
27186
|
const userPrompt = `### CONTEXT GROUND TRUTH:
|
|
27224
27187
|
- Topic / Concept Domain: "${topic}"
|
|
27225
27188
|
- Lesson ID: "${lessonId || "ON_DEMAND"}"
|
|
@@ -29036,6 +28999,7 @@ function isTranslationDue(target, context) {
|
|
|
29036
28999
|
}
|
|
29037
29000
|
|
|
29038
29001
|
// src/services/index.ts
|
|
29002
|
+
init_templateLoader();
|
|
29039
29003
|
init_slideProductionWorkflow();
|
|
29040
29004
|
var LocalWorkspaceManager = class {
|
|
29041
29005
|
baseDir;
|
|
@@ -31612,7 +31576,6 @@ exports.DEFAULT_LESSON_PRIORITIES = DEFAULT_LESSON_PRIORITIES;
|
|
|
31612
31576
|
exports.DEFAULT_OVERHEAD_RATIO = DEFAULT_OVERHEAD_RATIO;
|
|
31613
31577
|
exports.DEFAULT_STREAM_IDLE_MS = DEFAULT_STREAM_IDLE_MS;
|
|
31614
31578
|
exports.DEFAULT_STREAM_TOTAL_MS = DEFAULT_STREAM_TOTAL_MS;
|
|
31615
|
-
exports.DEFAULT_VIETNAMESE_SECTION_HEADINGS = DEFAULT_VIETNAMESE_SECTION_HEADINGS;
|
|
31616
31579
|
exports.DependencyEdgeSchema = DependencyEdgeSchema;
|
|
31617
31580
|
exports.DepthAssignmentSchema = DepthAssignmentSchema;
|
|
31618
31581
|
exports.DepthLevelSchema = DepthLevelSchema;
|
|
@@ -31752,6 +31715,7 @@ exports.ZpdVerdictSchema = ZpdVerdictSchema;
|
|
|
31752
31715
|
exports.activityTools = activityTools;
|
|
31753
31716
|
exports.analystTools = analystTools;
|
|
31754
31717
|
exports.analyzeProjectCreationIntent = analyzeProjectCreationIntent;
|
|
31718
|
+
exports.assembleTranslatedTemplate = assembleTranslatedTemplate;
|
|
31755
31719
|
exports.assertAcyclic = assertAcyclic;
|
|
31756
31720
|
exports.assessorTools = assessorTools;
|
|
31757
31721
|
exports.assignDepths = assignDepths;
|
|
@@ -31828,12 +31792,14 @@ exports.exportAllProjectQuizzes = exportAllProjectQuizzes;
|
|
|
31828
31792
|
exports.expositionCacheKey = expositionCacheKey;
|
|
31829
31793
|
exports.extractActivityContractRows = extractActivityContractRows;
|
|
31830
31794
|
exports.extractAssessmentMap = extractAssessmentMap;
|
|
31831
|
-
exports.
|
|
31795
|
+
exports.extractConditionalSections = extractConditionalSections;
|
|
31832
31796
|
exports.extractCurriculumHorizon = extractCurriculumHorizon;
|
|
31797
|
+
exports.extractDeclaredLanguage = extractDeclaredLanguage;
|
|
31798
|
+
exports.extractEchoSections = extractEchoSections;
|
|
31833
31799
|
exports.extractJsonArray = extractJsonArray;
|
|
31834
31800
|
exports.extractRequiredSections = extractRequiredSections;
|
|
31835
31801
|
exports.extractScopeSequenceRows = extractScopeSequenceRows;
|
|
31836
|
-
exports.
|
|
31802
|
+
exports.extractSectionHeadings = extractSectionHeadings;
|
|
31837
31803
|
exports.extractSessionSlice = extractSessionSlice;
|
|
31838
31804
|
exports.extractStandardRefs = extractStandardRefs;
|
|
31839
31805
|
exports.extractStreamChunk = extractStreamChunk;
|
|
@@ -31889,7 +31855,6 @@ exports.loadAuthoringTemplate = loadAuthoringTemplate;
|
|
|
31889
31855
|
exports.loadCurriculumTemplate = loadCurriculumTemplate;
|
|
31890
31856
|
exports.loadSotTemplate = loadSotTemplate;
|
|
31891
31857
|
exports.normalizePlanningGraph = normalizePlanningGraph;
|
|
31892
|
-
exports.normalizeSlcContract = normalizeSlcContract;
|
|
31893
31858
|
exports.packagerTools = packagerTools;
|
|
31894
31859
|
exports.parseAllSessions = parseAllSessions;
|
|
31895
31860
|
exports.parseGateSettings = parseGateSettings;
|
|
@@ -31934,11 +31899,13 @@ exports.streamLLMWithFallback = streamLLMWithFallback;
|
|
|
31934
31899
|
exports.streamLayerPrefillWithFallback = streamLayerPrefillWithFallback;
|
|
31935
31900
|
exports.streamLessonMasterFlow = streamLessonMasterFlow;
|
|
31936
31901
|
exports.streamSelfLabFlow = streamSelfLabFlow;
|
|
31902
|
+
exports.stripHeadingKey = stripHeadingKey;
|
|
31937
31903
|
exports.stripLlmJsonWrappers = stripLlmJsonWrappers;
|
|
31938
31904
|
exports.stripTemplateFrontmatter = stripTemplateFrontmatter;
|
|
31939
31905
|
exports.targetLanguageDisplayName = targetLanguageDisplayName;
|
|
31940
31906
|
exports.techSmeTools = techSmeTools;
|
|
31941
31907
|
exports.topoSort = topoSort;
|
|
31908
|
+
exports.translateTemplate = translateTemplate;
|
|
31942
31909
|
exports.uploadAssetToBucket = uploadAssetToBucket;
|
|
31943
31910
|
exports.validateArtifactDependencies = validateArtifactDependencies;
|
|
31944
31911
|
exports.validateCurriculumPlan = validateCurriculumPlan;
|