@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/workflow/index.mjs
CHANGED
|
@@ -3,9 +3,9 @@ import path 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 { generateObject } from 'ai';
|
|
7
8
|
import { z } from 'zod';
|
|
8
|
-
import { fileURLToPath } from 'url';
|
|
9
9
|
import { defineHook, getStepMetadata, RetryableError, sleep } from 'workflow';
|
|
10
10
|
import fs3 from 'fs/promises';
|
|
11
11
|
import { Octokit } from '@octokit/rest';
|
|
@@ -1127,10 +1127,138 @@ var init_provider_factory = __esm({
|
|
|
1127
1127
|
};
|
|
1128
1128
|
}
|
|
1129
1129
|
});
|
|
1130
|
+
function stripTemplateFrontmatter(raw) {
|
|
1131
|
+
let body = raw;
|
|
1132
|
+
if (body.startsWith("---")) {
|
|
1133
|
+
const end = body.indexOf("\n---", 3);
|
|
1134
|
+
if (end !== -1) body = body.slice(end + 4);
|
|
1135
|
+
}
|
|
1136
|
+
return body.split("\n").filter((l) => l.trim() !== "<!-- INJECT_BODY -->").join("\n").replace(/^\s*\n/, "").trimEnd();
|
|
1137
|
+
}
|
|
1138
|
+
function stripHeadingKey(h) {
|
|
1139
|
+
return h.replace(/\[(REQUIRED|OPTIONAL|CONDITIONAL)\]\s*/gi, "").replace(/^\s*\d+[.)]\s+/, "").replace(/\s+/g, " ").trim();
|
|
1140
|
+
}
|
|
1141
|
+
function isVariableHeading(text) {
|
|
1142
|
+
return /\{\{[^}]*\}\}/.test(text) || /\[[^\]]+\]/.test(text);
|
|
1143
|
+
}
|
|
1144
|
+
function collectHeadings(body) {
|
|
1145
|
+
const out = [];
|
|
1146
|
+
let inFence = false;
|
|
1147
|
+
for (const line of body.split("\n")) {
|
|
1148
|
+
if (/^(```|~~~)/.test(line.trim())) {
|
|
1149
|
+
inFence = !inFence;
|
|
1150
|
+
continue;
|
|
1151
|
+
}
|
|
1152
|
+
if (inFence) continue;
|
|
1153
|
+
const m = line.match(/^(#{2,3})\s+(.*)$/);
|
|
1154
|
+
if (!m) continue;
|
|
1155
|
+
const text = m[2].trim();
|
|
1156
|
+
const optional = /^\[OPTIONAL\]/i.test(text);
|
|
1157
|
+
const name = stripHeadingKey(text);
|
|
1158
|
+
if (!name || isVariableHeading(name)) continue;
|
|
1159
|
+
out.push({ level: m[1].length, name, optional });
|
|
1160
|
+
}
|
|
1161
|
+
return out;
|
|
1162
|
+
}
|
|
1163
|
+
function extractEchoSections(raw) {
|
|
1164
|
+
const hs = collectHeadings(stripTemplateFrontmatter(raw));
|
|
1165
|
+
return {
|
|
1166
|
+
required: hs.filter((h) => !h.optional).map((h) => h.name),
|
|
1167
|
+
optional: hs.filter((h) => h.optional).map((h) => h.name)
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
function extractConditionalSections(raw) {
|
|
1171
|
+
const body = stripTemplateFrontmatter(raw);
|
|
1172
|
+
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));
|
|
1173
|
+
}
|
|
1174
|
+
function extractDeclaredLanguage(raw) {
|
|
1175
|
+
const m = raw.match(/^template_language:\s*["']?([a-zA-Z-]+)["']?\s*$/m);
|
|
1176
|
+
return m?.[1]?.toLowerCase() || "en";
|
|
1177
|
+
}
|
|
1178
|
+
function candidateDirs(explicitDir) {
|
|
1179
|
+
const dirs = [];
|
|
1180
|
+
if (process.env.CURRICULUM_TEMPLATES_DIR) dirs.push(process.env.CURRICULUM_TEMPLATES_DIR);
|
|
1181
|
+
dirs.push(path.resolve(process.cwd(), "_templates"));
|
|
1182
|
+
for (const rel of KIT_TEMPLATE_FALLBACK_DIRS) {
|
|
1183
|
+
dirs.push(path.resolve(_moduleDir, rel));
|
|
1184
|
+
dirs.push(path.resolve(process.cwd(), rel));
|
|
1185
|
+
dirs.push(path.resolve(process.cwd(), "packages/curriculum-kit", rel));
|
|
1186
|
+
}
|
|
1187
|
+
return dirs;
|
|
1188
|
+
}
|
|
1189
|
+
function findTemplatePath(templateName, explicitDir) {
|
|
1190
|
+
for (const dir of candidateDirs()) {
|
|
1191
|
+
const p = path.join(dir, templateName);
|
|
1192
|
+
if (!fs2.existsSync(p)) continue;
|
|
1193
|
+
try {
|
|
1194
|
+
fs2.accessSync(p, fs2.constants.R_OK);
|
|
1195
|
+
return p;
|
|
1196
|
+
} catch {
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
return null;
|
|
1200
|
+
}
|
|
1201
|
+
function resolveArtifactTemplate(templateName, opts) {
|
|
1202
|
+
const p = findTemplatePath(templateName);
|
|
1203
|
+
if (!p) return null;
|
|
1204
|
+
try {
|
|
1205
|
+
const raw = fs2.readFileSync(p, "utf-8");
|
|
1206
|
+
const echo = extractEchoSections(raw);
|
|
1207
|
+
return {
|
|
1208
|
+
content: stripTemplateFrontmatter(raw),
|
|
1209
|
+
sections: echo.required,
|
|
1210
|
+
optionalSections: echo.optional,
|
|
1211
|
+
sourcePath: p,
|
|
1212
|
+
conditionals: extractConditionalSections(raw),
|
|
1213
|
+
declaredLang: extractDeclaredLanguage(raw)
|
|
1214
|
+
};
|
|
1215
|
+
} catch {
|
|
1216
|
+
return null;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
function loadCurriculumTemplate(templateName, templatesDir) {
|
|
1220
|
+
const p = findTemplatePath(templateName);
|
|
1221
|
+
if (!p) return "";
|
|
1222
|
+
try {
|
|
1223
|
+
return fs2.readFileSync(p, "utf-8");
|
|
1224
|
+
} catch {
|
|
1225
|
+
return "";
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
function loadAuthoringTemplate(templateName, templatesDir) {
|
|
1229
|
+
const p = findTemplatePath(templateName);
|
|
1230
|
+
if (!p) return "";
|
|
1231
|
+
try {
|
|
1232
|
+
return stripTemplateFrontmatter(fs2.readFileSync(p, "utf-8"));
|
|
1233
|
+
} catch {
|
|
1234
|
+
return "";
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
var KIT_TEMPLATE_FALLBACK_DIRS, _moduleDir;
|
|
1238
|
+
var init_templateLoader = __esm({
|
|
1239
|
+
"src/services/templateLoader.ts"() {
|
|
1240
|
+
KIT_TEMPLATE_FALLBACK_DIRS = [
|
|
1241
|
+
// Packaged with the npm bundle (dist/templates) — resolves from node_modules.
|
|
1242
|
+
"templates",
|
|
1243
|
+
// Repo checkout layouts.
|
|
1244
|
+
"docs/refs/templates"
|
|
1245
|
+
];
|
|
1246
|
+
_moduleDir = (() => {
|
|
1247
|
+
try {
|
|
1248
|
+
if (typeof import.meta !== "undefined" && typeof import.meta.url === "string") {
|
|
1249
|
+
return path.dirname(fileURLToPath(import.meta.url));
|
|
1250
|
+
}
|
|
1251
|
+
} catch {
|
|
1252
|
+
}
|
|
1253
|
+
return typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
1254
|
+
})();
|
|
1255
|
+
}
|
|
1256
|
+
});
|
|
1130
1257
|
|
|
1131
1258
|
// src/parsers/lessonFlowParser.ts
|
|
1132
1259
|
var init_lessonFlowParser = __esm({
|
|
1133
1260
|
"src/parsers/lessonFlowParser.ts"() {
|
|
1261
|
+
init_templateLoader();
|
|
1134
1262
|
}
|
|
1135
1263
|
});
|
|
1136
1264
|
|
|
@@ -2744,72 +2872,9 @@ z.object({
|
|
|
2744
2872
|
}),
|
|
2745
2873
|
phases: z.array(PhaseInputSchema).default([])
|
|
2746
2874
|
});
|
|
2747
|
-
function stripTemplateFrontmatter(raw) {
|
|
2748
|
-
let body = raw;
|
|
2749
|
-
if (body.startsWith("---")) {
|
|
2750
|
-
const end = body.indexOf("\n---", 3);
|
|
2751
|
-
if (end !== -1) body = body.slice(end + 4);
|
|
2752
|
-
}
|
|
2753
|
-
return body.split("\n").filter((l) => l.trim() !== "<!-- INJECT_BODY -->").join("\n").replace(/^\s*\n/, "").trimEnd();
|
|
2754
|
-
}
|
|
2755
|
-
var KIT_TEMPLATE_FALLBACK_DIRS = [
|
|
2756
|
-
// Packaged with the npm bundle (dist/templates) — resolves from node_modules.
|
|
2757
|
-
"templates",
|
|
2758
|
-
// Repo checkout layouts.
|
|
2759
|
-
"docs/refs/templates"
|
|
2760
|
-
];
|
|
2761
|
-
var _moduleDir = (() => {
|
|
2762
|
-
try {
|
|
2763
|
-
if (typeof import.meta !== "undefined" && typeof import.meta.url === "string") {
|
|
2764
|
-
return path.dirname(fileURLToPath(import.meta.url));
|
|
2765
|
-
}
|
|
2766
|
-
} catch {
|
|
2767
|
-
}
|
|
2768
|
-
return typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
2769
|
-
})();
|
|
2770
|
-
function candidateDirs(explicitDir) {
|
|
2771
|
-
const dirs = [];
|
|
2772
|
-
if (process.env.CURRICULUM_TEMPLATES_DIR) dirs.push(process.env.CURRICULUM_TEMPLATES_DIR);
|
|
2773
|
-
dirs.push(path.resolve(process.cwd(), "_templates"));
|
|
2774
|
-
for (const rel of KIT_TEMPLATE_FALLBACK_DIRS) {
|
|
2775
|
-
dirs.push(path.resolve(_moduleDir, rel));
|
|
2776
|
-
dirs.push(path.resolve(process.cwd(), rel));
|
|
2777
|
-
dirs.push(path.resolve(process.cwd(), "packages/curriculum-kit", rel));
|
|
2778
|
-
}
|
|
2779
|
-
return dirs;
|
|
2780
|
-
}
|
|
2781
|
-
function findTemplatePath(templateName, explicitDir) {
|
|
2782
|
-
for (const dir of candidateDirs()) {
|
|
2783
|
-
const p = path.join(dir, templateName);
|
|
2784
|
-
if (!fs2.existsSync(p)) continue;
|
|
2785
|
-
try {
|
|
2786
|
-
fs2.accessSync(p, fs2.constants.R_OK);
|
|
2787
|
-
return p;
|
|
2788
|
-
} catch {
|
|
2789
|
-
}
|
|
2790
|
-
}
|
|
2791
|
-
return null;
|
|
2792
|
-
}
|
|
2793
|
-
function loadCurriculumTemplate(templateName, templatesDir) {
|
|
2794
|
-
const p = findTemplatePath(templateName);
|
|
2795
|
-
if (!p) return "";
|
|
2796
|
-
try {
|
|
2797
|
-
return fs2.readFileSync(p, "utf-8");
|
|
2798
|
-
} catch {
|
|
2799
|
-
return "";
|
|
2800
|
-
}
|
|
2801
|
-
}
|
|
2802
|
-
function loadAuthoringTemplate(templateName, templatesDir) {
|
|
2803
|
-
const p = findTemplatePath(templateName);
|
|
2804
|
-
if (!p) return "";
|
|
2805
|
-
try {
|
|
2806
|
-
return stripTemplateFrontmatter(fs2.readFileSync(p, "utf-8"));
|
|
2807
|
-
} catch {
|
|
2808
|
-
return "";
|
|
2809
|
-
}
|
|
2810
|
-
}
|
|
2811
2875
|
|
|
2812
2876
|
// src/ai/prompts/lessonMasterPrompt.ts
|
|
2877
|
+
init_templateLoader();
|
|
2813
2878
|
function buildLessonMasterPrompt(input) {
|
|
2814
2879
|
const { milestone, language, topic, targetAudience, contextContinuity, standardsContext } = input;
|
|
2815
2880
|
const learningObjectives = milestone.learning_objectives || [];
|
|
@@ -2911,6 +2976,7 @@ Return a single valid JSON object matching the LessonPlanSchema with these exact
|
|
|
2911
2976
|
}
|
|
2912
2977
|
|
|
2913
2978
|
// src/ai/prompts/activityPrompt.ts
|
|
2979
|
+
init_templateLoader();
|
|
2914
2980
|
function buildActivityPrompt(input) {
|
|
2915
2981
|
const { lesson, language, hardwareBOM, softwareTools } = input;
|
|
2916
2982
|
const loList = lesson.learningObjectives.map((lo) => `- [${lo.bloomLevel}] ${lo.code}: ${lo.name || ""} \u2014 ${lo.description}${lo.successCriteria ? ` (Evidence: ${lo.successCriteria})` : ""}`).join("\n");
|
|
@@ -3010,6 +3076,7 @@ Return a single JSON object matching ActivityLabSchema with these exact keys:
|
|
|
3010
3076
|
}
|
|
3011
3077
|
|
|
3012
3078
|
// src/ai/prompts/codeLabPrompt.ts
|
|
3079
|
+
init_templateLoader();
|
|
3013
3080
|
function buildCodeLabPrompt(input) {
|
|
3014
3081
|
const { lesson, activity, language, targetTechStack } = input;
|
|
3015
3082
|
const techStackList = targetTechStack && targetTechStack.length > 0 ? targetTechStack : ["General Programming & Engineering"];
|
|
@@ -3416,6 +3483,7 @@ Please return a single JSON object matching these exact keys:
|
|
|
3416
3483
|
}
|
|
3417
3484
|
|
|
3418
3485
|
// src/ai/prompts/selfLabPrompt.ts
|
|
3486
|
+
init_templateLoader();
|
|
3419
3487
|
function buildSelfLabPrompt(input) {
|
|
3420
3488
|
const { milestone, projectGraph, language, targetTechStack, contextContinuity } = input;
|
|
3421
3489
|
const techStackList = targetTechStack && targetTechStack.length > 0 ? targetTechStack : milestone.tech_keywords && milestone.tech_keywords.length > 0 ? milestone.tech_keywords : ["General Engineering"];
|
|
@@ -3524,6 +3592,7 @@ Return a single valid JSON object matching SelfLabSchema with these exact keys:
|
|
|
3524
3592
|
}
|
|
3525
3593
|
|
|
3526
3594
|
// src/ai/prompts/diagnosticQuizPrompt.ts
|
|
3595
|
+
init_templateLoader();
|
|
3527
3596
|
function buildDiagnosticQuizPrompt(input) {
|
|
3528
3597
|
const { milestone, language, questionCount = 4, passingScorePct = 80 } = input;
|
|
3529
3598
|
const learningObjectives = milestone.learning_objectives || [];
|
|
@@ -4073,7 +4142,7 @@ ${cc.technicalDepth}`;
|
|
|
4073
4142
|
const dataRows = cc.comparisonTable.rows.map((r) => `| ${r.join(" | ")} |`).join("\n");
|
|
4074
4143
|
str += `
|
|
4075
4144
|
|
|
4076
|
-
|
|
4145
|
+
**Comparison & Trade-off Analysis**
|
|
4077
4146
|
${headerRow}
|
|
4078
4147
|
${dividerRow}
|
|
4079
4148
|
${dataRows}`;
|
|
@@ -4117,7 +4186,8 @@ ${learningObjectivesStr}
|
|
|
4117
4186
|
|
|
4118
4187
|
---
|
|
4119
4188
|
|
|
4120
|
-
## 1. ENGAGE (Hook & High-Stakes Scenario)
|
|
4189
|
+
## 1. ENGAGE (Hook & High-Stakes Scenario)
|
|
4190
|
+
> **Duration:** 10-15 mins
|
|
4121
4191
|
|
|
4122
4192
|
### Real-World Context: "${lesson.hookTitle || "The Incident"}"
|
|
4123
4193
|
${lesson.hookScenario}
|
|
@@ -4126,13 +4196,15 @@ ${lesson.hookQuestions && lesson.hookQuestions.length > 0 ? lesson.hookQuestions
|
|
|
4126
4196
|
|
|
4127
4197
|
---
|
|
4128
4198
|
|
|
4129
|
-
## 2. EXPLORE & EXPLAIN (Core Technical Concepts & Principles)
|
|
4199
|
+
## 2. EXPLORE & EXPLAIN (Core Technical Concepts & Principles)
|
|
4200
|
+
> **Duration:** 30-40 mins
|
|
4130
4201
|
|
|
4131
4202
|
${coreConceptsStr}
|
|
4132
4203
|
|
|
4133
4204
|
---
|
|
4134
4205
|
|
|
4135
|
-
## 3. GUIDED PRACTICE (Visual Architecture & Annotated Code)
|
|
4206
|
+
## 3. GUIDED PRACTICE (Visual Architecture & Annotated Code)
|
|
4207
|
+
> **Duration:** 20-25 mins
|
|
4136
4208
|
|
|
4137
4209
|
### System Architecture & Data Flow (Mermaid Diagram)
|
|
4138
4210
|
${mermaidBlock}
|
|
@@ -4146,7 +4218,8 @@ ${guidedPractice.codeSnippet}
|
|
|
4146
4218
|
|
|
4147
4219
|
---
|
|
4148
4220
|
|
|
4149
|
-
## 4. ELABORATE & INDEPENDENT PRACTICE (Technical Challenge & Scaffolding)
|
|
4221
|
+
## 4. ELABORATE & INDEPENDENT PRACTICE (Technical Challenge & Scaffolding)
|
|
4222
|
+
> **Duration:** 15-20 mins
|
|
4150
4223
|
|
|
4151
4224
|
### Engineering Challenge: "${lesson.independentPractice?.title || "System Optimization Challenge"}"
|
|
4152
4225
|
${lesson.independentPractice?.description || "Implement the core logic and test against simulated edge cases."}
|
|
@@ -4157,7 +4230,8 @@ ${lesson.independentPractice?.description || "Implement the core logic and test
|
|
|
4157
4230
|
|
|
4158
4231
|
---
|
|
4159
4232
|
|
|
4160
|
-
## 5. EVALUATE (Summary, Assessment & Metacognition)
|
|
4233
|
+
## 5. EVALUATE (Summary, Assessment & Metacognition)
|
|
4234
|
+
> **Duration:** 5-10 mins
|
|
4161
4235
|
|
|
4162
4236
|
### Exit Ticket (Bloom: Apply / Analyze)
|
|
4163
4237
|
> **Scenario Question:** ${lesson.exitTicket.questionStem}
|
|
@@ -4250,12 +4324,16 @@ ${hardwareItems}
|
|
|
4250
4324
|
|
|
4251
4325
|
## [REQUIRED] Active Learning Workflow
|
|
4252
4326
|
|
|
4253
|
-
### Phase 1: Planning & Design
|
|
4327
|
+
### Phase 1: Planning & Design
|
|
4328
|
+
> **Duration:** ${phase1.durationMinutes} mins
|
|
4329
|
+
|
|
4254
4330
|
- **Student Task:** ${phase1.studentTask}
|
|
4255
4331
|
- **Teacher Action:** ${phase1.teacherAction}
|
|
4256
4332
|
${phase1.inquiryQuestions.map((q) => ` - *Inquiry Question:* ${q}`).join("\n")}
|
|
4257
4333
|
|
|
4258
|
-
### Phase 2: Implementation & Discovery
|
|
4334
|
+
### Phase 2: Implementation & Discovery
|
|
4335
|
+
> **Duration:** ${phase2.durationMinutes} mins
|
|
4336
|
+
|
|
4259
4337
|
- **Student Task:** ${phase2.studentTask}
|
|
4260
4338
|
- **Teacher Action:** ${phase2.teacherAction}
|
|
4261
4339
|
|
|
@@ -4263,7 +4341,9 @@ ${phase2.codeOrCommands.map((c) => `\`\`\`text
|
|
|
4263
4341
|
${c}
|
|
4264
4342
|
\`\`\``).join("\n\n")}
|
|
4265
4343
|
|
|
4266
|
-
### Phase 3: Debugging & Testing
|
|
4344
|
+
### Phase 3: Debugging & Testing
|
|
4345
|
+
> **Duration:** ${phase3.durationMinutes} mins
|
|
4346
|
+
|
|
4267
4347
|
- **Testing:** ${phase3.testingSteps}
|
|
4268
4348
|
- **Error Analysis:** ${phase3.errorAnalysis}
|
|
4269
4349
|
|
|
@@ -4318,22 +4398,28 @@ This lab focuses on the practical implementation of core technical concepts, bri
|
|
|
4318
4398
|
|
|
4319
4399
|
## \u{1F4DD} Lab Tasks (3-Tier Differentiation)
|
|
4320
4400
|
|
|
4321
|
-
### \u{1F949} Bronze (Foundational)
|
|
4401
|
+
### \u{1F949} Bronze (Foundational)
|
|
4402
|
+
> **Duration:** ${tasks.bronze.mins} mins
|
|
4403
|
+
|
|
4322
4404
|
**Objective:** ${tasks.bronze.objective}
|
|
4323
4405
|
- **Task:** ${tasks.bronze.task}
|
|
4324
4406
|
- **Requirement:** ${tasks.bronze.requirement}
|
|
4325
4407
|
|
|
4326
|
-
### \u{1F948} Silver (Application)
|
|
4408
|
+
### \u{1F948} Silver (Application)
|
|
4409
|
+
> **Duration:** ${tasks.silver.mins} mins
|
|
4410
|
+
|
|
4327
4411
|
**Objective:** ${tasks.silver.objective}
|
|
4328
4412
|
- **Task:** ${tasks.silver.task}
|
|
4329
4413
|
- **Requirement:** ${tasks.silver.requirement}
|
|
4330
4414
|
|
|
4331
|
-
### \u{1F947} Gold (Enrichment/Creative)
|
|
4415
|
+
### \u{1F947} Gold (Enrichment/Creative)
|
|
4416
|
+
> **Duration:** ${tasks.gold.mins} mins
|
|
4417
|
+
|
|
4332
4418
|
**Objective:** ${tasks.gold.objective}
|
|
4333
4419
|
- **Task:** ${tasks.gold.task}
|
|
4334
4420
|
- **Requirement:** ${tasks.gold.requirement}
|
|
4335
4421
|
|
|
4336
|
-
## \u{1F4BB} Technical Reference
|
|
4422
|
+
## \u{1F4BB} Technical Reference
|
|
4337
4423
|
<!-- [SME_MANDATE] -->
|
|
4338
4424
|
> Any code provided in this section is verified for syntax accuracy and runtime execution.
|
|
4339
4425
|
|
|
@@ -4408,7 +4494,9 @@ ${proTipsStr}
|
|
|
4408
4494
|
function serializeSelfLabToMarkdown(lab) {
|
|
4409
4495
|
const renderChallenge = (c, label) => {
|
|
4410
4496
|
const tasksList = c.tasks.map((t) => `- ${t}`).join("\n");
|
|
4411
|
-
return `### ${label}: ${c.title}
|
|
4497
|
+
return `### ${label}: ${c.title}
|
|
4498
|
+
> **Duration:** ~${c.estimatedMinutes} mins
|
|
4499
|
+
|
|
4412
4500
|
**Objective:** ${c.objective}
|
|
4413
4501
|
|
|
4414
4502
|
#### Tasks & Implementation Details:
|
|
@@ -18518,6 +18606,7 @@ var LLMJudgeEngine = class {
|
|
|
18518
18606
|
init_errors();
|
|
18519
18607
|
|
|
18520
18608
|
// src/services/languageDirective.ts
|
|
18609
|
+
init_templateLoader();
|
|
18521
18610
|
function resolveTargetLanguageCode(language) {
|
|
18522
18611
|
const raw = String(language || "vi").trim().toLowerCase();
|
|
18523
18612
|
if (raw.startsWith("vi")) return "vi";
|
|
@@ -18547,193 +18636,46 @@ function buildLanguageDirective(targetLanguage) {
|
|
|
18547
18636
|
${exampleLine}` : ""}
|
|
18548
18637
|
- 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.`;
|
|
18549
18638
|
}
|
|
18550
|
-
|
|
18551
|
-
|
|
18552
|
-
|
|
18553
|
-
|
|
18554
|
-
|
|
18555
|
-
|
|
18556
|
-
|
|
18557
|
-
|
|
18558
|
-
|
|
18559
|
-
|
|
18560
|
-
|
|
18561
|
-
|
|
18562
|
-
|
|
18563
|
-
|
|
18564
|
-
|
|
18565
|
-
|
|
18566
|
-
|
|
18567
|
-
|
|
18568
|
-
PROJECT_BRIEF:
|
|
18569
|
-
|
|
18570
|
-
|
|
18571
|
-
"Learning Roadmap": "L\u1ED9 tr\xECnh H\u1ECDc t\u1EADp & C\u1ED9t m\u1ED1c",
|
|
18572
|
-
"Artifact Scope": "Ph\u1EA1m vi S\u1EA3n ph\u1EA9m H\u1ECDc t\u1EADp"
|
|
18573
|
-
},
|
|
18574
|
-
CURRICULUM_FRAMEWORK: {
|
|
18575
|
-
"Course Overview": "T\u1ED5ng quan Kh\xF3a h\u1ECDc",
|
|
18576
|
-
"Global Learning Objectives": "M\u1EE5c ti\xEAu H\u1ECDc t\u1EADp To\xE0n di\u1EC7n",
|
|
18577
|
-
"Structural Hierarchy (Unit & Module)": "C\u1EA5u tr\xFAc Kh\xF3a h\u1ECDc (Unit & Module)",
|
|
18578
|
-
"Scope & Sequence (Detailed Roadmap)": "Ph\u1EA1m vi & Tr\xECnh t\u1EF1 Chi ti\u1EBFt"
|
|
18579
|
-
},
|
|
18580
|
-
CONTENT_STYLE_GUIDE: {
|
|
18581
|
-
"Voice & Tone": "Gi\u1ECDng v\u0103n & Phong c\xE1ch",
|
|
18582
|
-
"Standard Terminology (Glossary)": "Thu\u1EADt ng\u1EEF Chu\u1EA9n (B\u1EA3ng thu\u1EADt ng\u1EEF)",
|
|
18583
|
-
"Examples & Context Rules": "Quy t\u1EAFc V\xED d\u1EE5 & Ng\u1EEF c\u1EA3nh",
|
|
18584
|
-
"Lesson Content Standards": "Ti\xEAu chu\u1EA9n N\u1ED9i dung B\xE0i h\u1ECDc"
|
|
18585
|
-
},
|
|
18586
|
-
SECTION_LANGUAGE_CONTRACT: {
|
|
18587
|
-
"Metadata & Scope": "Th\xF4ng tin & Ph\u1EA1m vi H\u1EE3p \u0111\u1ED3ng",
|
|
18588
|
-
"Section Translation Matrix": "Ma tr\u1EADn Ti\xEAu \u0111\u1EC1 \u0110a ng\xF4n ng\u1EEF",
|
|
18589
|
-
"Validation Rules": "Quy t\u1EAFc X\xE1c th\u1EF1c & Kh\xF3a Chu\u1EA9n"
|
|
18590
|
-
},
|
|
18591
|
-
KNOWLEDGE_EXPOSITION: {
|
|
18592
|
-
"Session Scope": "Ph\u1EA1m vi Bu\u1ED5i h\u1ECDc",
|
|
18593
|
-
"Key Terms": "Thu\u1EADt ng\u1EEF Then ch\u1ED1t",
|
|
18594
|
-
"Concept Narratives": "Di\u1EC5n gi\u1EA3i Kh\xE1i ni\u1EC7m",
|
|
18595
|
-
"Worked Micro-Examples": "V\xED d\u1EE5 M\u1EABu Chi ti\u1EBFt",
|
|
18596
|
-
"Common Mistakes": "L\u1ED7i Th\u01B0\u1EDDng g\u1EB7p & Kh\u1EAFc ph\u1EE5c",
|
|
18597
|
-
"Self-Check Questions": "C\xE2u h\u1ECFi T\u1EF1 ki\u1EC3m tra"
|
|
18598
|
-
},
|
|
18599
|
-
LESSON: {
|
|
18600
|
-
"A. Lesson Design Plan": "A. K\u1EBF ho\u1EA1ch Thi\u1EBFt k\u1EBF B\xE0i h\u1ECDc",
|
|
18601
|
-
"Learning Objectives & Evidence": "M\u1EE5c ti\xEAu H\u1ECDc t\u1EADp & B\u1EB1ng ch\u1EE9ng N\u0103ng l\u1EF1c",
|
|
18602
|
-
"Activity Sequence": "Chu\u1ED7i Ho\u1EA1t \u0111\u1ED9ng D\u1EA1y & H\u1ECDc",
|
|
18603
|
-
"Resource Map": "B\u1EA3n \u0111\u1ED3 T\xE0i nguy\xEAn & H\u1ECDc li\u1EC7u",
|
|
18604
|
-
"Assessment Map": "B\u1EA3n \u0111\u1ED3 \u0110\xE1nh gi\xE1 N\u0103ng l\u1EF1c",
|
|
18605
|
-
"Artifact Contract": "H\u1EE3p \u0111\u1ED3ng S\u1EA3n ph\u1EA9m \u0110\u1EA7u ra",
|
|
18606
|
-
"B. Lesson Flow": "B. Ti\u1EBFn tr\xECnh Gi\u1EA3ng d\u1EA1y Chi ti\u1EBFt"
|
|
18607
|
-
},
|
|
18608
|
-
ACT: {
|
|
18609
|
-
"Computational Thinking Focus": "Tr\u1ECDng t\xE2m T\u01B0 duy M\xE1y t\xEDnh",
|
|
18610
|
-
"Materials & Setup": "V\u1EADt li\u1EC7u & Chu\u1EA9n b\u1ECB Thi\u1EBFt b\u1ECB",
|
|
18611
|
-
"Constraints & Safety": "R\xE0ng bu\u1ED9c & An to\xE0n Ph\xF2ng th\u1EF1c h\xE0nh",
|
|
18612
|
-
"Active Learning Workflow": "Quy tr\xECnh Ho\u1EA1t \u0111\u1ED9ng Tr\u1EA3i nghi\u1EC7m",
|
|
18613
|
-
"3-Tier Differentiation": "Ph\xE2n h\xF3a H\u1ECDc t\u1EADp 3 T\u1EA7ng",
|
|
18614
|
-
"Reflection": "T\u1ED5ng k\u1EBFt & \u0110\xFAc k\u1EBFt Tr\u1EA3i nghi\u1EC7m"
|
|
18615
|
-
},
|
|
18616
|
-
CODE: {
|
|
18617
|
-
"Technical Overview & Architecture Blueprint": "T\u1ED5ng quan K\u1EF9 thu\u1EADt & B\u1EA3n thi\u1EBFt k\u1EBF Ki\u1EBFn tr\xFAc",
|
|
18618
|
-
"Hardware Pinout & Wiring Configuration Matrix": "S\u01A1 \u0111\u1ED3 Ch\xE2n & Ma tr\u1EADn N\u1ED1i d\xE2y Ph\u1EA7n c\u1EE9ng",
|
|
18619
|
-
"Starter Code Sandbox": "M\xE3 ngu\u1ED3n Kh\u1EDFi \u0111\u1EA7u (Starter Code)",
|
|
18620
|
-
"Verified Reference Solution Code": "M\xE3 ngu\u1ED3n L\u1EDDi gi\u1EA3i Chu\u1EA9n (Reference Solution)",
|
|
18621
|
-
"Automated Test / Verification Script": "K\u1ECBch b\u1EA3n Ki\u1EC3m th\u1EED T\u1EF1 \u0111\u1ED9ng",
|
|
18622
|
-
"Common Syntax & Runtime Pitfalls Matrix": "Ma tr\u1EADn L\u1ED7i C\xFA ph\xE1p & Th\u1EDDi gian ch\u1EA1y Th\u01B0\u1EDDng g\u1EB7p"
|
|
18623
|
-
},
|
|
18624
|
-
CODE_LAB: {
|
|
18625
|
-
"Technical Overview & Architecture Blueprint": "T\u1ED5ng quan K\u1EF9 thu\u1EADt & B\u1EA3n thi\u1EBFt k\u1EBF Ki\u1EBFn tr\xFAc",
|
|
18626
|
-
"Hardware Pinout & Wiring Configuration Matrix": "S\u01A1 \u0111\u1ED3 Ch\xE2n & Ma tr\u1EADn N\u1ED1i d\xE2y Ph\u1EA7n c\u1EE9ng",
|
|
18627
|
-
"Starter Code Sandbox": "M\xE3 ngu\u1ED3n Kh\u1EDFi \u0111\u1EA7u (Starter Code)",
|
|
18628
|
-
"Verified Reference Solution Code": "M\xE3 ngu\u1ED3n L\u1EDDi gi\u1EA3i Chu\u1EA9n (Reference Solution)",
|
|
18629
|
-
"Automated Test / Verification Script": "K\u1ECBch b\u1EA3n Ki\u1EC3m th\u1EED T\u1EF1 \u0111\u1ED9ng",
|
|
18630
|
-
"Common Syntax & Runtime Pitfalls Matrix": "Ma tr\u1EADn L\u1ED7i C\xFA ph\xE1p & Th\u1EDDi gian ch\u1EA1y Th\u01B0\u1EDDng g\u1EB7p"
|
|
18631
|
-
},
|
|
18632
|
-
QUIZ: {
|
|
18633
|
-
"Assessment Objectives": "M\u1EE5c ti\xEAu \u0110\xE1nh gi\xE1",
|
|
18634
|
-
"Multiple-Choice Question Bank": "Ng\xE2n h\xE0ng C\xE2u h\u1ECFi Tr\u1EAFc nghi\u1EC7m",
|
|
18635
|
-
"Code Analysis / Debugging Question": "C\xE2u h\u1ECFi Ph\xE2n t\xEDch M\xE3 ngu\u1ED3n & S\u1EEDa l\u1ED7i",
|
|
18636
|
-
"Competency Rubric": "Thang \u0111o \u0110\xE1nh gi\xE1 N\u0103ng l\u1EF1c (Rubric)"
|
|
18637
|
-
},
|
|
18638
|
-
GUIDE: {
|
|
18639
|
-
"Objectives & Preparation": "M\u1EE5c ti\xEAu & Chu\u1EA9n b\u1ECB Gi\u1EA3ng d\u1EA1y",
|
|
18640
|
-
"Preparation Checklist & Workstation Setup": "Danh m\u1EE5c Ki\u1EC3m tra Chu\u1EA9n b\u1ECB & Tr\u1EA1m Th\u1EF1c h\xE0nh",
|
|
18641
|
-
"Facilitation Script & Timeline": "K\u1ECBch b\u1EA3n \u0110i\u1EC1u ph\u1ED1i & Khung Th\u1EDDi gian",
|
|
18642
|
-
"Common Misconceptions & Diagnostic Remediation Matrix": "Quan ni\u1EC7m Sai l\u1EA7m Th\u01B0\u1EDDng g\u1EB7p & Ma tr\u1EADn Kh\u1EAFc ph\u1EE5c",
|
|
18643
|
-
"Differentiated Support Strategies": "Chi\u1EBFn l\u01B0\u1EE3c H\u1ED7 tr\u1EE3 Ph\xE2n h\xF3a"
|
|
18644
|
-
},
|
|
18645
|
-
HANDOUT: {
|
|
18646
|
-
"Core Concepts": "Kh\xE1i ni\u1EC7m C\u1ED1t l\xF5i",
|
|
18647
|
-
"Core Syntax & Mechanism Cheat Sheet": "B\u1EA3ng Tra c\u1EE9u C\xFA ph\xE1p & C\u01A1 ch\u1EBF Tr\u1ECDng t\xE2m",
|
|
18648
|
-
"Visual Mental Model / Architecture Diagram": "M\xF4 h\xECnh T\u01B0 duy Tr\u1EF1c quan / S\u01A1 \u0111\u1ED3 Ki\u1EBFn tr\xFAc",
|
|
18649
|
-
"Step-by-Step Practical Quick-Start Guide": "H\u01B0\u1EDBng d\u1EABn Th\u1EF1c h\xE0nh T\u1EEBng b\u01B0\u1EDBc",
|
|
18650
|
-
"Self-Check Diagnostic Checklist": "B\u1EA3ng Ki\u1EC3m tra T\u1EF1 ch\u1EA9n \u0111o\xE1n"
|
|
18651
|
-
},
|
|
18652
|
-
WKS: {
|
|
18653
|
-
"Part 1: Knowledge Check": "Ph\u1EA7n 1: Ki\u1EC3m tra Ki\u1EBFn th\u1EE9c",
|
|
18654
|
-
"Part 2: Concept Tracing & Diagram Fill-in": "Ph\u1EA7n 2: L\u1EA7n v\u1EBFt Kh\xE1i ni\u1EC7m & \u0110i\u1EC1n S\u01A1 \u0111\u1ED3",
|
|
18655
|
-
"Part 3: Code Analysis & Bug Hunting Challenge": "Ph\u1EA7n 3: Ph\xE2n t\xEDch M\xE3 & Th\u1EED th\xE1ch S\u0103n l\u1ED7i",
|
|
18656
|
-
"Part 4: Synthesis & Problem-Solving Application": "Ph\u1EA7n 4: T\u1ED5ng h\u1EE3p & \u1EE8ng d\u1EE5ng Gi\u1EA3i quy\u1EBFt V\u1EA5n \u0111\u1EC1",
|
|
18657
|
-
"Part 5: Self-Reflection & Learning Log": "Ph\u1EA7n 5: T\u1EF1 suy ng\u1EABm & Nh\u1EADt k\xFD H\u1ECDc t\u1EADp"
|
|
18658
|
-
},
|
|
18659
|
-
EXT: {
|
|
18660
|
-
"For: Advanced Students / Extra Time": "D\xE0nh cho: H\u1ECDc sinh N\xE2ng cao / Ho\xE0n th\xE0nh S\u1EDBm",
|
|
18661
|
-
"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",
|
|
18662
|
-
"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",
|
|
18663
|
-
"Challenge 3: Extension Milestones": "Th\u1EED th\xE1ch 3: C\xE1c M\u1ED1c Nhi\u1EC7m v\u1EE5 N\xE2ng cao",
|
|
18664
|
-
"Metacognitive Deep Dive & Engineering Trade-offs": "Suy ng\u1EABm Si\xEAu nh\u1EADn th\u1EE9c & \u0110\xE1nh \u0111\u1ED5i K\u1EF9 thu\u1EADt"
|
|
18665
|
-
},
|
|
18666
|
-
SLIDE: {
|
|
18667
|
-
"Title & Agenda": "Ti\xEAu \u0111\u1EC1 & M\u1EE5c l\u1EE5c",
|
|
18668
|
-
"Core Concepts": "Kh\xE1i ni\u1EC7m C\u1ED1t l\xF5i",
|
|
18669
|
-
"Guided Demonstration": "H\u01B0\u1EDBng d\u1EABn Th\u1EF1c h\xE0nh & Th\u1ECB ph\u1EA1m",
|
|
18670
|
-
"Hands-on Mission": "Nhi\u1EC7m v\u1EE5 Th\u1EF1c h\xE0nh Tr\u1EA3i nghi\u1EC7m",
|
|
18671
|
-
"Summary & Next Steps": "T\u1ED5ng k\u1EBFt & \u0110\u1ECBnh h\u01B0\u1EDBng Ti\u1EBFp theo"
|
|
18672
|
-
}
|
|
18639
|
+
var TEMPLATE_BY_TYPE = {
|
|
18640
|
+
LESSON: "LESSON_5E_template.md",
|
|
18641
|
+
LESSON_5E: "LESSON_5E_template.md",
|
|
18642
|
+
LESSON_EDP: "LESSON_EDP_template.md",
|
|
18643
|
+
LESSON_GENERAL: "LESSON_GENERAL_template.md",
|
|
18644
|
+
ACT: "ACT_template.md",
|
|
18645
|
+
CODE: "CODE_template.md",
|
|
18646
|
+
// JSON-first code lab shares the CODE label set (the serializer renders its
|
|
18647
|
+
// own headings; this lookup only feeds the directive fallback path).
|
|
18648
|
+
CODE_LAB: "CODE_template.md",
|
|
18649
|
+
QUIZ: "QUIZ_v4.6_template.md",
|
|
18650
|
+
GUIDE: "GUIDE_template.md",
|
|
18651
|
+
HANDOUT: "HANDOUT_template.md",
|
|
18652
|
+
WKS: "WKS_template.md",
|
|
18653
|
+
EXT: "EXT_template.md",
|
|
18654
|
+
SLIDE: "SLIDE_template.md",
|
|
18655
|
+
KNOWLEDGE_EXPOSITION: "KNOWLEDGE_EXPOSITION_template.md",
|
|
18656
|
+
LEARNER_PROFILE: "LEARNER_PROFILE_template.md",
|
|
18657
|
+
PROJECT_BRIEF: "PROJECT_BRIEF_template.md",
|
|
18658
|
+
CURRICULUM_FRAMEWORK: "CURRICULUM_FRAMEWORK_template.md",
|
|
18659
|
+
CONTENT_STYLE_GUIDE: "CONTENT_STYLE_GUIDE_template.md"
|
|
18673
18660
|
};
|
|
18674
|
-
function
|
|
18675
|
-
const
|
|
18676
|
-
|
|
18677
|
-
|
|
18678
|
-
|
|
18679
|
-
|
|
18680
|
-
return mapping;
|
|
18681
|
-
}
|
|
18682
|
-
}
|
|
18683
|
-
}
|
|
18684
|
-
return {};
|
|
18685
|
-
};
|
|
18686
|
-
if (!slcInput) return getFallback();
|
|
18687
|
-
if (typeof slcInput === "object") {
|
|
18688
|
-
if (slcInput[upperType] && Object.keys(slcInput[upperType]).length > 0) return slcInput[upperType];
|
|
18689
|
-
for (const [key, mapping] of Object.entries(slcInput)) {
|
|
18690
|
-
if (matchesArtifactType(key, upperType) && Object.keys(mapping).length > 0) {
|
|
18691
|
-
return mapping;
|
|
18692
|
-
}
|
|
18693
|
-
}
|
|
18694
|
-
return getFallback();
|
|
18695
|
-
}
|
|
18696
|
-
const slcMarkdown = slcInput;
|
|
18697
|
-
const blocks = slcMarkdown.split(/\n(?=#{2,3}\s+[A-Z0-9_]+)/g);
|
|
18698
|
-
for (const block of blocks) {
|
|
18699
|
-
const headerMatch = block.match(/^#{2,3}\s+([A-Z0-9_]+)/);
|
|
18700
|
-
if (!headerMatch) continue;
|
|
18701
|
-
const blockType = headerMatch[1].trim().toUpperCase();
|
|
18702
|
-
if (matchesArtifactType(blockType, upperType)) {
|
|
18703
|
-
const mapping = {};
|
|
18704
|
-
const lines = block.split("\n");
|
|
18705
|
-
for (const line of lines) {
|
|
18706
|
-
const trimmed = line.trim();
|
|
18707
|
-
if (trimmed.startsWith("|") && !trimmed.includes("---")) {
|
|
18708
|
-
const cells = trimmed.split("|").map((c) => c.trim()).filter((_, idx, arr) => idx > 0 && idx < arr.length - 1);
|
|
18709
|
-
if (cells.length >= 2 && !cells[0].toLowerCase().includes("canonical") && !cells[1].toLowerCase().includes("localized")) {
|
|
18710
|
-
mapping[cells[0]] = cells[1];
|
|
18711
|
-
}
|
|
18712
|
-
} else {
|
|
18713
|
-
const bullet = line.match(/^[-*]\s+([^:]+):\s+(.+)$/);
|
|
18714
|
-
if (bullet) {
|
|
18715
|
-
mapping[bullet[1].trim()] = bullet[2].trim();
|
|
18716
|
-
}
|
|
18717
|
-
}
|
|
18718
|
-
}
|
|
18719
|
-
if (Object.keys(mapping).length > 0) return mapping;
|
|
18720
|
-
}
|
|
18721
|
-
}
|
|
18722
|
-
return getFallback();
|
|
18661
|
+
function extractSectionHeadings(artifactType, opts) {
|
|
18662
|
+
const templateFile = TEMPLATE_BY_TYPE[artifactType.trim().toUpperCase()];
|
|
18663
|
+
if (!templateFile) return {};
|
|
18664
|
+
const resolved = resolveArtifactTemplate(templateFile);
|
|
18665
|
+
if (!resolved) return {};
|
|
18666
|
+
return Object.fromEntries(resolved.sections.map((s) => [s, s]));
|
|
18723
18667
|
}
|
|
18724
|
-
function buildHeadingDirective(artifactType,
|
|
18725
|
-
const headings =
|
|
18668
|
+
function buildHeadingDirective(artifactType, opts) {
|
|
18669
|
+
const headings = extractSectionHeadings(artifactType);
|
|
18726
18670
|
if (Object.keys(headings).length === 0) {
|
|
18727
18671
|
return "";
|
|
18728
18672
|
}
|
|
18729
|
-
const lines = Object.
|
|
18730
|
-
|
|
18731
|
-
|
|
18732
|
-
|
|
18733
|
-
- The YAML frontmatter \`template_required_sections\` MUST preserve the exact English canonical keys.
|
|
18734
|
-
- In the markdown body, section headers MUST use the EXACT Localized Display Labels below (do NOT translate or paraphrase):
|
|
18673
|
+
const lines = Object.keys(headings).map((heading) => ` - "${heading}"`);
|
|
18674
|
+
return `MANDATORY SECTION HEADINGS (SOURCE: RESOLVED ARTIFACT TEMPLATE):
|
|
18675
|
+
- Copy the template's YAML frontmatter \`template_required_sections\` list VERBATIM into the artifact frontmatter \u2014 never translate, reorder, or invent entries.
|
|
18676
|
+
- In the markdown body, section headers MUST be exactly the Display Headings below (do NOT translate, paraphrase, or re-marker them):
|
|
18735
18677
|
${lines.join("\n")}
|
|
18736
|
-
-
|
|
18678
|
+
- Example: if the resolved template's heading is "${Object.values(headings)[0]}", your body heading must be exactly "## ${Object.values(headings)[0]}".`;
|
|
18737
18679
|
}
|
|
18738
18680
|
|
|
18739
18681
|
// src/services/curriculumHorizon.ts
|
|
@@ -19047,9 +18989,8 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
|
|
|
19047
18989
|
};
|
|
19048
18990
|
}
|
|
19049
18991
|
const minContentChars = opts.minContentChars !== void 0 ? opts.minContentChars : Math.min(400, source.length);
|
|
19050
|
-
const slcMap = normalizeSlcContract(opts.sectionLanguageContract);
|
|
19051
18992
|
const effectiveArtifactType = opts.artifactType || deriveArtifactTypeFromFileName(opts.fileName);
|
|
19052
|
-
const sections = parseMarkdownSections(source
|
|
18993
|
+
const sections = parseMarkdownSections(source);
|
|
19053
18994
|
const metaBlock = buildMetaBlock(source, effectiveArtifactType);
|
|
19054
18995
|
if (sections.length === 0) {
|
|
19055
18996
|
issues.push("parse:no-sections");
|
|
@@ -19172,48 +19113,16 @@ function buildLessonExcerpt(markdown, opts = {}) {
|
|
|
19172
19113
|
priorities: DEFAULT_LESSON_PRIORITIES
|
|
19173
19114
|
});
|
|
19174
19115
|
}
|
|
19175
|
-
function
|
|
19176
|
-
if (!slc) return void 0;
|
|
19177
|
-
if (typeof slc !== "string") return slc;
|
|
19178
|
-
const out = {};
|
|
19179
|
-
const blocks = slc.split(/\n(?=#{2,3}\s+[A-Z0-9_]+)/g);
|
|
19180
|
-
for (const block of blocks) {
|
|
19181
|
-
const header = block.match(/^#{2,3}\s+([A-Z0-9_]+)/);
|
|
19182
|
-
if (!header?.[1]) continue;
|
|
19183
|
-
const mapping = {};
|
|
19184
|
-
for (const line of block.split("\n")) {
|
|
19185
|
-
const t = line.trim();
|
|
19186
|
-
if (!t.startsWith("|") || t.includes("---")) continue;
|
|
19187
|
-
const cells = t.split("|").map((c) => c.trim()).filter((_, i, a) => i > 0 && i < a.length - 1);
|
|
19188
|
-
const [c0, c1] = cells;
|
|
19189
|
-
if (c0 && c1 && !c0.toLowerCase().includes("canonical") && !c1.toLowerCase().includes("localized")) {
|
|
19190
|
-
mapping[c0] = c1;
|
|
19191
|
-
}
|
|
19192
|
-
}
|
|
19193
|
-
if (Object.keys(mapping).length > 0) out[header[1]] = mapping;
|
|
19194
|
-
}
|
|
19195
|
-
return Object.keys(out).length > 0 ? out : void 0;
|
|
19196
|
-
}
|
|
19197
|
-
function parseMarkdownSections(markdown, slcMap, artifactType) {
|
|
19116
|
+
function parseMarkdownSections(markdown) {
|
|
19198
19117
|
const sections = [];
|
|
19199
19118
|
const lines = markdown.split("\n");
|
|
19200
19119
|
let currentHeading = "";
|
|
19201
19120
|
let currentBody = [];
|
|
19202
|
-
const reverseMap = /* @__PURE__ */ new Map();
|
|
19203
|
-
if (slcMap) {
|
|
19204
|
-
const maps = artifactType && slcMap[artifactType] ? [slcMap[artifactType]] : Object.values(slcMap);
|
|
19205
|
-
for (const m of maps) {
|
|
19206
|
-
for (const [canonical, localized] of Object.entries(m)) {
|
|
19207
|
-
reverseMap.set(normalizeHeading(localized), canonical);
|
|
19208
|
-
reverseMap.set(normalizeHeading(canonical), canonical);
|
|
19209
|
-
}
|
|
19210
|
-
}
|
|
19211
|
-
}
|
|
19212
19121
|
const flush = () => {
|
|
19213
19122
|
if (!currentHeading) return;
|
|
19214
19123
|
const cleanTitle = currentHeading.replace(/^#{1,4}\s+/, "").trim();
|
|
19215
19124
|
const norm = normalizeHeading(cleanTitle);
|
|
19216
|
-
const canonicalKey =
|
|
19125
|
+
const canonicalKey = findCanonicalFuzzy(norm);
|
|
19217
19126
|
sections.push({
|
|
19218
19127
|
rawHeading: currentHeading,
|
|
19219
19128
|
cleanTitle,
|
|
@@ -19312,7 +19221,7 @@ function buildMetaBlock(source, artifactType) {
|
|
|
19312
19221
|
function deriveArtifactTypeFromFileName(fileName) {
|
|
19313
19222
|
if (!fileName) return void 0;
|
|
19314
19223
|
const base = fileName.replace(/\.md$/i, "");
|
|
19315
|
-
const multiWord = base.match(/^(KNOWLEDGE_EXPOSITION|
|
|
19224
|
+
const multiWord = base.match(/^(KNOWLEDGE_EXPOSITION|CONTENT_STYLE_GUIDE|CURRICULUM_FRAMEWORK|LEARNER_PROFILE|PROJECT_BRIEF|REFERENCE_PACK|CURRICULUM_PLAN)/i);
|
|
19316
19225
|
if (multiWord) return multiWord[1].toUpperCase();
|
|
19317
19226
|
const token = base.match(/^([A-Z][A-Z0-9_]*?)(?=_|$)/);
|
|
19318
19227
|
return token ? token[1] : void 0;
|
|
@@ -19381,6 +19290,9 @@ z.object({
|
|
|
19381
19290
|
tieredScaffolding: z.object({ bronze: z.string().default(""), silver: z.string().default(""), gold: z.string().default("") }).default({ bronze: "", silver: "", gold: "" })
|
|
19382
19291
|
});
|
|
19383
19292
|
|
|
19293
|
+
// src/services/lessonProductionService.ts
|
|
19294
|
+
init_templateLoader();
|
|
19295
|
+
|
|
19384
19296
|
// src/services/singleArtifactService.ts
|
|
19385
19297
|
init_errors();
|
|
19386
19298
|
|
|
@@ -19546,11 +19458,7 @@ async function generateSingleArtifact(req) {
|
|
|
19546
19458
|
language.toLowerCase().includes("bilingual") || language.toLowerCase().includes("song");
|
|
19547
19459
|
const targetLang = resolveTargetLanguageCode(language);
|
|
19548
19460
|
const langDirective = buildLanguageDirective(language);
|
|
19549
|
-
const headingDirective = buildHeadingDirective(
|
|
19550
|
-
artifactType.toUpperCase(),
|
|
19551
|
-
req.sectionLanguageContract,
|
|
19552
|
-
targetLang
|
|
19553
|
-
);
|
|
19461
|
+
const headingDirective = buildHeadingDirective(artifactType.toUpperCase());
|
|
19554
19462
|
const availableSources = {
|
|
19555
19463
|
KNOWLEDGE_EXPOSITION: contextSot.exposition || researchContext,
|
|
19556
19464
|
CANONICAL_LESSON: contextSot.lessonPlan,
|
|
@@ -19617,11 +19525,10 @@ ${symbolLedgerPrompt}
|
|
|
19617
19525
|
|
|
19618
19526
|
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).
|
|
19619
19527
|
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.` : ""}`;
|
|
19620
|
-
const
|
|
19621
|
-
const
|
|
19622
|
-
const
|
|
19623
|
-
const
|
|
19624
|
-
const expositionExcerpt = contextSot.exposition ? buildExpositionExcerpt(contextSot.exposition, { budget: 6e3, sectionLanguageContract: slcContract }).excerpt : "";
|
|
19528
|
+
const frameworkExcerpt = contextSot.framework ? buildSectionAwareExcerpt(contextSot.framework, { budget: 2500 }).excerpt : "";
|
|
19529
|
+
const lessonPlanExcerpt = contextSot.lessonPlan ? buildLessonExcerpt(contextSot.lessonPlan, { budget: 8e3, artifactType: "LESSON" }).excerpt : "";
|
|
19530
|
+
const handoutExcerpt = contextSot.handout ? buildSectionAwareExcerpt(contextSot.handout, { budget: 2e3 }).excerpt : "";
|
|
19531
|
+
const expositionExcerpt = contextSot.exposition ? buildExpositionExcerpt(contextSot.exposition, { budget: 6e3 }).excerpt : "";
|
|
19625
19532
|
const userPrompt = `### CONTEXT GROUND TRUTH:
|
|
19626
19533
|
- Topic / Concept Domain: "${topic}"
|
|
19627
19534
|
- Lesson ID: "${lessonId || "ON_DEMAND"}"
|