@thanh01.pmt/curriculum-kit 1.4.8 → 1.4.9
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/LICENSE +21 -0
- package/dist/index.cjs +59 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +59 -19
- package/dist/index.mjs.map +1 -1
- package/dist/storage/index.cjs +37 -8
- package/dist/storage/index.cjs.map +1 -1
- package/dist/storage/index.mjs +37 -8
- package/dist/storage/index.mjs.map +1 -1
- package/package.json +21 -22
package/dist/index.d.cts
CHANGED
|
@@ -540,6 +540,7 @@ declare function buildSessionSliceContext(plan: CurriculumPlan, lessonCode: stri
|
|
|
540
540
|
interface ProjectionMeta {
|
|
541
541
|
courseName: string;
|
|
542
542
|
shortDescription?: string;
|
|
543
|
+
targetLanguage?: string;
|
|
543
544
|
}
|
|
544
545
|
declare function renderFrameworkFromPlan(plan: CurriculumPlan, meta: ProjectionMeta): string;
|
|
545
546
|
/** Extract the glossary scope (terms per session) the EXPOSITION service consumes. */
|
package/dist/index.d.ts
CHANGED
|
@@ -540,6 +540,7 @@ declare function buildSessionSliceContext(plan: CurriculumPlan, lessonCode: stri
|
|
|
540
540
|
interface ProjectionMeta {
|
|
541
541
|
courseName: string;
|
|
542
542
|
shortDescription?: string;
|
|
543
|
+
targetLanguage?: string;
|
|
543
544
|
}
|
|
544
545
|
declare function renderFrameworkFromPlan(plan: CurriculumPlan, meta: ProjectionMeta): string;
|
|
545
546
|
/** Extract the glossary scope (terms per session) the EXPOSITION service consumes. */
|
package/dist/index.mjs
CHANGED
|
@@ -8406,13 +8406,16 @@ function computeContentHash(content) {
|
|
|
8406
8406
|
return "sha256:" + crypto.createHash("sha256").update(content.trim(), "utf-8").digest("hex");
|
|
8407
8407
|
}
|
|
8408
8408
|
var STANDARD_SOT_FILES = [
|
|
8409
|
-
"PROJECT_BRIEF.md",
|
|
8410
8409
|
"LEARNER_PROFILE.md",
|
|
8410
|
+
"PROJECT_BRIEF.md",
|
|
8411
|
+
"REFERENCE_PACK.md",
|
|
8412
|
+
"PROJECT_GRAPH.json",
|
|
8413
|
+
"HYBRID_GRAPH.json",
|
|
8414
|
+
"SECTION_LANGUAGE_CONTRACT.md",
|
|
8411
8415
|
"CURRICULUM_FRAMEWORK.md",
|
|
8412
|
-
"PROJECT_STATUS.md",
|
|
8413
8416
|
"CONTENT_STYLE_GUIDE.md",
|
|
8414
8417
|
"ART_DIRECTION.md",
|
|
8415
|
-
"
|
|
8418
|
+
"ALIGNMENT_MATRIX.md"
|
|
8416
8419
|
];
|
|
8417
8420
|
var FileSystemCurriculumAdapter = class {
|
|
8418
8421
|
baseDir;
|
|
@@ -8454,19 +8457,33 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8454
8457
|
async listSotDocuments(projectId) {
|
|
8455
8458
|
const projectDir = this.getProjectDir(projectId);
|
|
8456
8459
|
const sotDir = path3.join(projectDir, "_sot");
|
|
8457
|
-
|
|
8460
|
+
const discoveredFiles = new Set(STANDARD_SOT_FILES);
|
|
8461
|
+
if (fs2.existsSync(sotDir)) {
|
|
8462
|
+
try {
|
|
8463
|
+
const diskFiles = fs2.readdirSync(sotDir);
|
|
8464
|
+
for (const f of diskFiles) {
|
|
8465
|
+
if (f.startsWith(".") || f.endsWith(".review.json")) continue;
|
|
8466
|
+
const fullPath = path3.join(sotDir, f);
|
|
8467
|
+
if (fs2.statSync(fullPath).isFile()) {
|
|
8468
|
+
discoveredFiles.add(f);
|
|
8469
|
+
}
|
|
8470
|
+
}
|
|
8471
|
+
} catch {
|
|
8472
|
+
}
|
|
8473
|
+
}
|
|
8474
|
+
return Array.from(discoveredFiles).map((filename) => {
|
|
8458
8475
|
const p = fs2.existsSync(path3.join(sotDir, filename)) ? path3.join(sotDir, filename) : fs2.existsSync(path3.join(projectDir, filename)) ? path3.join(projectDir, filename) : null;
|
|
8459
8476
|
if (p && fs2.existsSync(p)) {
|
|
8460
8477
|
const stats = fs2.statSync(p);
|
|
8461
8478
|
return {
|
|
8462
|
-
name: filename.replace(
|
|
8479
|
+
name: filename.replace(/\.(md|json)$/i, "").replace(/_/g, " "),
|
|
8463
8480
|
filename,
|
|
8464
8481
|
exists: true,
|
|
8465
8482
|
sizeBytes: stats.size
|
|
8466
8483
|
};
|
|
8467
8484
|
}
|
|
8468
8485
|
return {
|
|
8469
|
-
name: filename.replace(
|
|
8486
|
+
name: filename.replace(/\.(md|json)$/i, "").replace(/_/g, " "),
|
|
8470
8487
|
filename,
|
|
8471
8488
|
exists: false,
|
|
8472
8489
|
sizeBytes: 0
|
|
@@ -8712,11 +8729,23 @@ var SupabaseCurriculumAdapter = class {
|
|
|
8712
8729
|
return null;
|
|
8713
8730
|
}
|
|
8714
8731
|
async listSotDocuments(projectId) {
|
|
8732
|
+
const discoveredFiles = new Set(STANDARD_SOT_FILES);
|
|
8733
|
+
try {
|
|
8734
|
+
const { data, error } = await this.client.storage.from(this.bucketName).list(`${projectId}/_sot`);
|
|
8735
|
+
if (!error && data) {
|
|
8736
|
+
for (const item of data) {
|
|
8737
|
+
if (item.name && !item.name.startsWith(".") && !item.name.endsWith(".review.json")) {
|
|
8738
|
+
discoveredFiles.add(item.name);
|
|
8739
|
+
}
|
|
8740
|
+
}
|
|
8741
|
+
}
|
|
8742
|
+
} catch {
|
|
8743
|
+
}
|
|
8715
8744
|
const results = [];
|
|
8716
|
-
for (const filename of
|
|
8745
|
+
for (const filename of discoveredFiles) {
|
|
8717
8746
|
const content = await this.readSotDocument(projectId, filename);
|
|
8718
8747
|
results.push({
|
|
8719
|
-
name: filename.replace(
|
|
8748
|
+
name: filename.replace(/\.(md|json)$/i, "").replace(/_/g, " "),
|
|
8720
8749
|
filename,
|
|
8721
8750
|
exists: !!content,
|
|
8722
8751
|
content: content || void 0,
|
|
@@ -9093,10 +9122,12 @@ async function auditQualityReport(storage, projectId) {
|
|
|
9093
9122
|
computedScore += Math.round(bloomPassCount / total * 20);
|
|
9094
9123
|
computedScore += Math.round(Math.min(syntaxExecutableCount, total) / total * 20);
|
|
9095
9124
|
computedScore += Math.round(scopeCompletenessCount / total * 20);
|
|
9125
|
+
const sotCompletedCount = status.sotReadiness.filter((s) => s.exists).length;
|
|
9126
|
+
const sotTotalCount = status.sotReadiness.length;
|
|
9096
9127
|
if (sotReady) {
|
|
9097
|
-
details.push(
|
|
9128
|
+
details.push(`\u2705 N\u1EC1n t\u1EA3ng SOT (${sotCompletedCount}/${sotTotalCount} t\xE0i li\u1EC7u) s\u1EB5n s\xE0ng.`);
|
|
9098
9129
|
} else {
|
|
9099
|
-
details.push(
|
|
9130
|
+
details.push(`\u26A0\uFE0F C\u1EA7n ho\xE0n thi\u1EC7n \u0111\u1EA7y \u0111\u1EE7 t\xE0i li\u1EC7u SOT c\u01A1 s\u1EDF (${sotCompletedCount}/${sotTotalCount}).`);
|
|
9100
9131
|
}
|
|
9101
9132
|
details.push(`\u{1F3AF} Ph\u1EA1m vi h\u1ECDc li\u1EC7u theo SOT (Artifact Scope): [${artifactScope.join(", ")}].`);
|
|
9102
9133
|
if (pedagogy5EPass) {
|
|
@@ -9112,7 +9143,7 @@ async function auditQualityReport(storage, projectId) {
|
|
|
9112
9143
|
details.push(`\u2705 \u0110\u1ED9 ph\u1EE7 \u0111\u1EA7y \u0111\u1EE7 c\xE1c h\u1ECDc li\u1EC7u trong Artifact Scope: ${scopeCompletenessCount}/${total} b\xE0i h\u1ECDc.`);
|
|
9113
9144
|
const rawMarkdownReport = `## \u{1F6E1}\uFE0F B\xC1O C\xC1O KI\u1EC2M \u0110\u1ECANH CH\u1EA4T L\u01AF\u1EE2NG (QUALITY AUDIT): \`${projectId.toUpperCase()}\`
|
|
9114
9145
|
- **\u0110i\u1EC3m th\u1EA9m \u0111\u1ECBnh ch\u1EA5t l\u01B0\u1EE3ng:** **${computedScore}/100**
|
|
9115
|
-
- **Tr\u1EA1ng th\xE1i SOT:** ${sotReady ?
|
|
9146
|
+
- **Tr\u1EA1ng th\xE1i SOT:** ${sotReady ? `\u2705 ${sotCompletedCount}/${sotTotalCount} File SOT ho\xE0n t\u1EA5t` : `\u26A0\uFE0F C\u1EA7n b\u1ED5 sung t\xE0i li\u1EC7u SOT thi\u1EBFu (${sotCompletedCount}/${sotTotalCount})`}.
|
|
9116
9147
|
- **Ph\u1EA1m vi h\u1ECDc li\u1EC7u (SOT Artifact Scope):** \`${artifactScope.join(", ")}\`
|
|
9117
9148
|
- **C\u1EA5u tr\xFAc S\u01B0 ph\u1EA1m (5E / EDP):** ${pedagogy5ECount}/${total} b\xE0i h\u1ECDc \u0111\u1EA1t chu\u1EA9n ph\xE2n pha.
|
|
9118
9149
|
- **Thang \u0111o nh\u1EADn th\u1EE9c Bloom:** ${bloomPassCount}/${total} b\xE0i h\u1ECDc \u0111\u1EA1t ma tr\u1EADn m\u1EE5c ti\xEAu.
|
|
@@ -9214,7 +9245,9 @@ function extractScopeSequenceRows(framework) {
|
|
|
9214
9245
|
const trimmed = line.trim();
|
|
9215
9246
|
if (!trimmed.startsWith("|")) continue;
|
|
9216
9247
|
const lower = trimmed.toLowerCase();
|
|
9217
|
-
|
|
9248
|
+
const hasCodeCol = lower.includes("lesson code") || lower.includes("m\xE3 b\xE0i") || lower.includes("m\xE3 b\xE0i h\u1ECDc");
|
|
9249
|
+
const hasObjCol = lower.includes("learning objective") || lower.includes("m\u1EE5c ti\xEAu") || lower.includes("m\u1EE5c ti\xEAu h\u1ECDc t\u1EADp");
|
|
9250
|
+
if (hasCodeCol && hasObjCol) {
|
|
9218
9251
|
headerFound = true;
|
|
9219
9252
|
continue;
|
|
9220
9253
|
}
|
|
@@ -27859,6 +27892,7 @@ var pad22 = (n) => String(n).padStart(2, "0");
|
|
|
27859
27892
|
var esc = (s) => s.replace(/\|/g, "/").replace(/\n/g, " ").trim();
|
|
27860
27893
|
var BLOOM_OF_DEPTH = { ulo: "Understand", cio: "Apply", sio: "Create" };
|
|
27861
27894
|
function renderFrameworkFromPlan(plan, meta) {
|
|
27895
|
+
const isVi = meta.targetLanguage === "vi";
|
|
27862
27896
|
const dateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
27863
27897
|
const totalSessions = plan.sessions.length;
|
|
27864
27898
|
const totalMinutes = plan.sessions.reduce(
|
|
@@ -27876,10 +27910,16 @@ function renderFrameworkFromPlan(plan, meta) {
|
|
|
27876
27910
|
const depthTops = [...new Set(s.depth_assignments.map((d) => d.depth))].map((d) => BLOOM_OF_DEPTH[d] ?? "Apply");
|
|
27877
27911
|
const bloom = depthTops[depthTops.length - 1] ?? "Apply";
|
|
27878
27912
|
const keyConcepts = s.new_keywords.length > 0 ? s.new_keywords.join(", ") : s.depth_assignments.map((d) => d.node_id).join(", ");
|
|
27879
|
-
const prereq = s.prerequisite_decisions.length > 0 ? s.prerequisite_decisions.filter((p) => p.decision === "taught_in_prior_lesson").length + " prior-taught, " + s.prerequisite_decisions.filter((p) => p.decision === "recap_in_lesson").length + " recap" : "None";
|
|
27913
|
+
const prereq = s.prerequisite_decisions.length > 0 ? s.prerequisite_decisions.filter((p) => p.decision === "taught_in_prior_lesson").length + " prior-taught, " + s.prerequisite_decisions.filter((p) => p.decision === "recap_in_lesson").length + " recap" : isVi ? "Kh\xF4ng" : "None";
|
|
27880
27914
|
const duration = s.knowledge_minutes + s.practice_minutes + s.overhead_minutes;
|
|
27881
27915
|
return "| " + pad22(i + 1) + " | " + s.id + " | " + esc(s.title) + " | " + s.unit_id + " | " + s.unit_id + "_M01 | " + esc(s.prose_objective) + " | " + esc(keyConcepts) + " | " + esc(s.exit_evidence[0] ?? "") + " | " + esc(prereq) + " | " + bloom + " | " + duration + " |";
|
|
27882
27916
|
}).join("\n");
|
|
27917
|
+
const courseOverviewHeader = isVi ? "## [REQUIRED] T\u1ED5ng quan Kh\xF3a h\u1ECDc" : "## [REQUIRED] Course Overview";
|
|
27918
|
+
const globalObjectivesHeader = isVi ? "## [REQUIRED] M\u1EE5c ti\xEAu H\u1ECDc t\u1EADp To\xE0n di\u1EC7n" : "## [REQUIRED] Global Learning Objectives";
|
|
27919
|
+
const structuralHierarchyHeader = isVi ? "## [REQUIRED] C\u1EA5u tr\xFAc Kh\xF3a h\u1ECDc (Unit & Module)" : "## [REQUIRED] Structural Hierarchy (Unit & Module)";
|
|
27920
|
+
const scopeSequenceHeader = isVi ? "## [REQUIRED] Ph\u1EA1m vi & Tr\xECnh t\u1EF1 Chi ti\u1EBFt (Scope & Sequence)" : "## [REQUIRED] Scope & Sequence (Detailed Roadmap)";
|
|
27921
|
+
const standardFormatHeader = isVi ? "## [REQUIRED] C\u1EA5u tr\xFAc B\xE0i h\u1ECDc Chu\u1EA9n" : "## [REQUIRED] Standard Lesson Format";
|
|
27922
|
+
const scopeTableHeader = isVi ? "| # | Lesson Code | Title | Unit | Module | Learning Objective (H\u1ECDc sinh l\xE0m \u0111\u01B0\u1EE3c g\xEC...) | Key Concepts (H\u1ECDc g\xEC) | Hands-on Deliverable (S\u1EA3n ph\u1EA9m bu\u1ED5i h\u1ECDc) | Prerequisites | Bloom | Duration (mins) |" : "| # | Lesson Code | Title | Unit | Module | Learning Objective (Students will be able to...) | Key Concepts (Hoc gi) | Hands-on Deliverable (Lam duoc gi) | Prerequisites | Bloom | Duration (mins) |";
|
|
27883
27923
|
return [
|
|
27884
27924
|
"---",
|
|
27885
27925
|
'id: "CURRICULUM-FRAMEWORK"',
|
|
@@ -27901,7 +27941,7 @@ function renderFrameworkFromPlan(plan, meta) {
|
|
|
27901
27941
|
"",
|
|
27902
27942
|
"_Projection of CURRICULUM_PLAN (hash " + plan.plan_hash + "). Approving this framework approves the per-session SCOPE recorded in the plan._",
|
|
27903
27943
|
"",
|
|
27904
|
-
|
|
27944
|
+
courseOverviewHeader,
|
|
27905
27945
|
"- **Official Course Name:** " + esc(meta.courseName),
|
|
27906
27946
|
meta.shortDescription ? "- **Short Description:** " + esc(meta.shortDescription) : "",
|
|
27907
27947
|
"- **Total Units:** " + plan.units.length,
|
|
@@ -27909,20 +27949,20 @@ function renderFrameworkFromPlan(plan, meta) {
|
|
|
27909
27949
|
"- **Total Duration:** ~" + totalHours + " hours (" + totalSessions + " sessions x " + plan.constraints.session_duration_minutes + " min).",
|
|
27910
27950
|
"- **Entry Level:** " + plan.constraints.entry_level + " (age band " + plan.constraints.age_band[0] + "-" + plan.constraints.age_band[1] + ").",
|
|
27911
27951
|
"",
|
|
27912
|
-
|
|
27952
|
+
globalObjectivesHeader,
|
|
27913
27953
|
...plan.course.objectives.map((o, i) => i + 1 + ". **[" + o.bloom + "]:** " + esc(o.statement)),
|
|
27914
27954
|
"",
|
|
27915
|
-
|
|
27955
|
+
structuralHierarchyHeader,
|
|
27916
27956
|
"| Unit | Module | Lessons | Module Objective | Lesson Codes |",
|
|
27917
27957
|
"|---|---|:---:|---|---|",
|
|
27918
27958
|
hierarchyRows || "| (none) | | | | |",
|
|
27919
27959
|
"",
|
|
27920
|
-
|
|
27921
|
-
|
|
27960
|
+
scopeSequenceHeader,
|
|
27961
|
+
scopeTableHeader,
|
|
27922
27962
|
"|:---:|:---:|---|---|---|---|---|---|---|:---:|:---:|",
|
|
27923
27963
|
scopeRows || "| 01 | U01_M01_L01 | (empty plan) | U01 | U01_M01 | - | - | - | None | Understand | " + plan.constraints.session_duration_minutes + " |",
|
|
27924
27964
|
"",
|
|
27925
|
-
|
|
27965
|
+
standardFormatHeader,
|
|
27926
27966
|
"- **Session duration:** " + plan.constraints.session_duration_minutes + " minutes (overhead " + String(plan.sessions[0]?.overhead_minutes ?? 0) + " min).",
|
|
27927
27967
|
"- **Knowledge/practice split per session:** see plan JSON (knowledge_minutes / practice_minutes).",
|
|
27928
27968
|
"- **Pedagogical flow:** 5E (Engage / Explore / Explain / Elaborate / Evaluate) unless policy overrides.",
|