@thanh01.pmt/curriculum-kit 1.4.23 → 1.4.24

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/index.mjs CHANGED
@@ -26191,7 +26191,22 @@ async function produceSingleLesson(storage, projectId, lessonId, options = {}) {
26191
26191
  const framework = await storage.readSotDocument(projectId, "CURRICULUM_FRAMEWORK.md") || "";
26192
26192
  const styleGuide = await storage.readSotDocument(projectId, "CONTENT_STYLE_GUIDE.md") || "";
26193
26193
  const refPack = await storage.readSotDocument(projectId, "REFERENCE_PACK.md") || "";
26194
+ let currentPlanHash;
26195
+ try {
26196
+ const planRaw0 = await storage.readArtifact(projectId, "_sot/CURRICULUM_PLAN.json");
26197
+ if (planRaw0) currentPlanHash = JSON.parse(planRaw0).plan_hash;
26198
+ } catch {
26199
+ }
26194
26200
  await storage.readSotDocument(projectId, "LEARNER_PROFILE.md") || "";
26201
+ const isStaleVsPlan = (content) => {
26202
+ if (!content || !currentPlanHash) return false;
26203
+ const m = content.match(/plan_hash:\s*"([0-9a-f]+)"/);
26204
+ return !!m && m[1] !== currentPlanHash;
26205
+ };
26206
+ const stampPlanHash = (content) => {
26207
+ if (!currentPlanHash || content.includes('plan_hash: "' + currentPlanHash + '"')) return content;
26208
+ return content + '\n---\nplan_hash: "' + currentPlanHash + '"\n- **Plan reference:** ' + currentPlanHash + "\n";
26209
+ };
26195
26210
  const slcMarkdown = options.sectionLanguageContract || await storage.readSotDocument(projectId, "SECTION_LANGUAGE_CONTRACT.md") || "";
26196
26211
  let targetLang = options.targetLanguage;
26197
26212
  if (!targetLang) {
@@ -26402,7 +26417,10 @@ ${sg}${standardsBlock}${glossaryBlock}${buildGroundTruthBlock()}${sessionSliceBl
26402
26417
  const lessonRelPath = `_content/${unitCode}/LESSON_${lessonCode}.md`;
26403
26418
  const existingLessonContent = await storage.readArtifact(projectId, lessonRelPath);
26404
26419
  let lessonContent = existingLessonContent || "";
26405
- if (artifactScope.includes("LESSON") && (!existingLessonContent || force)) {
26420
+ if (artifactScope.includes("LESSON") && (!existingLessonContent || force || isStaleVsPlan(existingLessonContent))) {
26421
+ if (existingLessonContent && !force && isStaleVsPlan(existingLessonContent)) {
26422
+ onProgress?.("@content", `[STALENESS] LESSON_${lessonCode} was generated under a different plan_hash \u2014 regenerating against the current plan.`);
26423
+ }
26406
26424
  onProgress?.("@content", `[1/4] Authoring Master Lesson Plan (${pedagogyLabel}): \`LESSON_${lessonCode}.md\` (${lessonTitle})...`);
26407
26425
  const dateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
26408
26426
  const mediaDirective = options.mediaPolicy && options.mediaPolicy.maxGenImagesPerArtifact > 0 ? `
@@ -26473,7 +26491,7 @@ Fix ALL issues above and output the complete corrected document.` }],
26473
26491
  } else {
26474
26492
  lessonContent = lintReport.autoFixedContent || rawLesson;
26475
26493
  }
26476
- await storage.saveArtifact(projectId, lessonRelPath, lessonContent);
26494
+ await storage.saveArtifact(projectId, lessonRelPath, stampPlanHash(lessonContent));
26477
26495
  producedArtifacts.push(`LESSON_${lessonCode}.md`);
26478
26496
  }
26479
26497
  const contentHash = lessonContent ? computeContentHash(lessonContent) : void 0;
@@ -26818,7 +26836,8 @@ ${lessonExcerpt}${symbolLedgerBlock}`;
26818
26836
  });
26819
26837
  };
26820
26838
  const actRelPath = `_content/${unitCode}/ACT_${lessonCode}.md`;
26821
- if (artifactScope.includes("ACT") && (!await storage.readArtifact(projectId, actRelPath) || force)) {
26839
+ const existingAct = await storage.readArtifact(projectId, actRelPath);
26840
+ if (artifactScope.includes("ACT") && (!existingAct || force || isStaleVsPlan(existingAct))) {
26822
26841
  onProgress?.("@activity", `[2/4] Authoring Hands-on Lab: \`ACT_${lessonCode}.md\`...`);
26823
26842
  const actDateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
26824
26843
  const actPrompt = `You are @activity (Lead Hands-on STEM & Laboratory Exercise Designer).
@@ -26878,7 +26897,7 @@ ${buildHeadingDirective("ACT", slcMarkdown, targetLang)}`;
26878
26897
  rawError: rawAct || "Empty AI response"
26879
26898
  });
26880
26899
  }
26881
- await storage.saveArtifact(projectId, actRelPath, rawAct);
26900
+ await storage.saveArtifact(projectId, actRelPath, stampPlanHash(rawAct));
26882
26901
  await storage.updateArtifactState(projectId, lessonCode, "ACT", {
26883
26902
  state: "completed",
26884
26903
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -26888,7 +26907,8 @@ ${buildHeadingDirective("ACT", slcMarkdown, targetLang)}`;
26888
26907
  await judgeSat("ACT", rawAct);
26889
26908
  }
26890
26909
  const quizRelPath = `_content/${unitCode}/QUIZ_${lessonCode}.md`;
26891
- if (artifactScope.includes("QUIZ") && (!await storage.readArtifact(projectId, quizRelPath) || force)) {
26910
+ const existingQuiz = await storage.readArtifact(projectId, quizRelPath);
26911
+ if (artifactScope.includes("QUIZ") && (!existingQuiz || force || isStaleVsPlan(existingQuiz))) {
26892
26912
  onProgress?.("@assessor", `[3/4] Authoring Assessment Bank: \`QUIZ_${lessonCode}.md\`...`);
26893
26913
  const quizDateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
26894
26914
  const quizPrompt = `You are @assessor (Lead Psychometrician & Competency Assessment Specialist).
@@ -26942,7 +26962,7 @@ ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
26942
26962
  rawError: rawQuiz || "Empty AI response"
26943
26963
  });
26944
26964
  }
26945
- await storage.saveArtifact(projectId, quizRelPath, rawQuiz);
26965
+ await storage.saveArtifact(projectId, quizRelPath, stampPlanHash(rawQuiz));
26946
26966
  await storage.updateArtifactState(projectId, lessonCode, "QUIZ", {
26947
26967
  state: "completed",
26948
26968
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -26952,7 +26972,8 @@ ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
26952
26972
  await judgeSat("QUIZ", rawQuiz);
26953
26973
  }
26954
26974
  const slideRelPath = `_content/${unitCode}/SLIDE_${lessonCode}.md`;
26955
- if (artifactScope.includes("SLIDE") && (!await storage.readArtifact(projectId, slideRelPath) || force)) {
26975
+ const existingSlide = await storage.readArtifact(projectId, slideRelPath);
26976
+ if (artifactScope.includes("SLIDE") && (!existingSlide || force || isStaleVsPlan(existingSlide))) {
26956
26977
  onProgress?.("@illustrator", `[4/4] Authoring Presentation Slide Deck: \`SLIDE_${lessonCode}.md\`...`);
26957
26978
  const isHtmlEngine = options.slidesEngine !== "marp";
26958
26979
  if (isHtmlEngine) {
@@ -26986,7 +27007,7 @@ ${buildHeadingDirective("QUIZ", slcMarkdown, targetLang)}`;
26986
27007
  let deckJson = workflowResult.deckJson;
26987
27008
  const markdownWrapper = workflowResult.markdownWrapper;
26988
27009
  let validation = presentationKitAi?.validateHtmlSlideDeck ? presentationKitAi.validateHtmlSlideDeck(deckJson, true) : deckJson && Array.isArray(deckJson.slides) ? { valid: true, score: 95, issues: [], slideCount: deckJson.slides.length} : { valid: false, score: 0, issues: [{ message: "Malformed JSON slide deck" }]};
26989
- await storage.saveArtifact(projectId, slideRelPath, markdownWrapper);
27010
+ await storage.saveArtifact(projectId, slideRelPath, stampPlanHash(markdownWrapper));
26990
27011
  producedArtifacts.push(`SLIDE_${lessonCode}.md`);
26991
27012
  if (deckJson) {
26992
27013
  const deckJsonStr = JSON.stringify(deckJson, null, 2);
@@ -27077,7 +27098,7 @@ footer: "Curriculum OS \u2022 ${lessonCode} (${pedagogyLabel})"
27077
27098
  rawError: rawSlide || "Empty AI response"
27078
27099
  });
27079
27100
  }
27080
- await storage.saveArtifact(projectId, slideRelPath, rawSlide);
27101
+ await storage.saveArtifact(projectId, slideRelPath, stampPlanHash(rawSlide));
27081
27102
  await storage.updateArtifactState(projectId, lessonCode, "SLIDE", {
27082
27103
  state: "completed",
27083
27104
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -27088,7 +27109,8 @@ footer: "Curriculum OS \u2022 ${lessonCode} (${pedagogyLabel})"
27088
27109
  }
27089
27110
  }
27090
27111
  const guideRelPath = `_content/${unitCode}/GUIDE_${lessonCode}.md`;
27091
- if (artifactScope.includes("GUIDE") && (!await storage.readArtifact(projectId, guideRelPath) || force)) {
27112
+ const existingGuide = await storage.readArtifact(projectId, guideRelPath);
27113
+ if (artifactScope.includes("GUIDE") && (!existingGuide || force || isStaleVsPlan(existingGuide))) {
27092
27114
  onProgress?.("@content", `Authoring Teacher Guide: \`GUIDE_${lessonCode}.md\`...`, { artifactType: "GUIDE" });
27093
27115
  const guideDateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
27094
27116
  const guidePrompt = `You are @content (Senior Curriculum Developer & Teacher Facilitation Specialist).
@@ -27128,7 +27150,7 @@ ${buildHeadingDirective("GUIDE", slcMarkdown, targetLang)}`;
27128
27150
  }
27129
27151
  );
27130
27152
  if (rawGuide && !rawGuide.startsWith("\u26A0\uFE0F") && rawGuide.length >= 200) {
27131
- await storage.saveArtifact(projectId, guideRelPath, rawGuide);
27153
+ await storage.saveArtifact(projectId, guideRelPath, stampPlanHash(rawGuide));
27132
27154
  await storage.updateArtifactState(projectId, lessonCode, "GUIDE", {
27133
27155
  state: "completed",
27134
27156
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -27139,7 +27161,8 @@ ${buildHeadingDirective("GUIDE", slcMarkdown, targetLang)}`;
27139
27161
  }
27140
27162
  }
27141
27163
  const handoutRelPath = `_content/${unitCode}/HANDOUT_${lessonCode}.md`;
27142
- if (artifactScope.includes("HANDOUT") && (!await storage.readArtifact(projectId, handoutRelPath) || force)) {
27164
+ const existingHandout = await storage.readArtifact(projectId, handoutRelPath);
27165
+ if (artifactScope.includes("HANDOUT") && (!existingHandout || force || isStaleVsPlan(existingHandout))) {
27143
27166
  onProgress?.("@content", `Authoring Student Handout: \`HANDOUT_${lessonCode}.md\`...`, { artifactType: "HANDOUT" });
27144
27167
  const handoutDateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
27145
27168
  const handoutPrompt = `You are @content (Educational Content Specialist).
@@ -27179,7 +27202,7 @@ ${buildHeadingDirective("HANDOUT", slcMarkdown, targetLang)}`;
27179
27202
  }
27180
27203
  );
27181
27204
  if (rawHandout && !rawHandout.startsWith("\u26A0\uFE0F") && rawHandout.length >= 200) {
27182
- await storage.saveArtifact(projectId, handoutRelPath, rawHandout);
27205
+ await storage.saveArtifact(projectId, handoutRelPath, stampPlanHash(rawHandout));
27183
27206
  await storage.updateArtifactState(projectId, lessonCode, "HANDOUT", {
27184
27207
  state: "completed",
27185
27208
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -27190,7 +27213,8 @@ ${buildHeadingDirective("HANDOUT", slcMarkdown, targetLang)}`;
27190
27213
  }
27191
27214
  }
27192
27215
  const wksRelPath = `_content/${unitCode}/WKS_${lessonCode}.md`;
27193
- if (artifactScope.includes("WKS") && (!await storage.readArtifact(projectId, wksRelPath) || force)) {
27216
+ const existingWks = await storage.readArtifact(projectId, wksRelPath);
27217
+ if (artifactScope.includes("WKS") && (!existingWks || force || isStaleVsPlan(existingWks))) {
27194
27218
  onProgress?.("@content", `Authoring Student Worksheet: \`WKS_${lessonCode}.md\`...`, { artifactType: "WKS" });
27195
27219
  const wksDateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
27196
27220
  const wksPrompt = `You are @content (Instructional Activity & Worksheet Designer).
@@ -27234,7 +27258,7 @@ ${buildHeadingDirective("WKS", slcMarkdown, targetLang)}`;
27234
27258
  }
27235
27259
  );
27236
27260
  if (rawWks && !rawWks.startsWith("\u26A0\uFE0F") && rawWks.length >= 200) {
27237
- await storage.saveArtifact(projectId, wksRelPath, rawWks);
27261
+ await storage.saveArtifact(projectId, wksRelPath, stampPlanHash(rawWks));
27238
27262
  await storage.updateArtifactState(projectId, lessonCode, "WKS", {
27239
27263
  state: "completed",
27240
27264
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -27245,7 +27269,8 @@ ${buildHeadingDirective("WKS", slcMarkdown, targetLang)}`;
27245
27269
  }
27246
27270
  }
27247
27271
  const codeRelPath = `_content/${unitCode}/CODE_${lessonCode}.md`;
27248
- if ((artifactScope.includes("CODE") || artifactScope.includes("CODE_LAB")) && (!await storage.readArtifact(projectId, codeRelPath) || force)) {
27272
+ const existingCode = await storage.readArtifact(projectId, codeRelPath);
27273
+ if ((artifactScope.includes("CODE") || artifactScope.includes("CODE_LAB")) && (!existingCode || force || isStaleVsPlan(existingCode))) {
27249
27274
  onProgress?.("@activity", `Authoring Executable Code Lab: \`CODE_${lessonCode}.md\`...`, { artifactType: "CODE" });
27250
27275
  const codeDateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
27251
27276
  const codePrompt = `You are @activity & @tech_sme (Lead Software Engineer & Technical SME).
@@ -27293,7 +27318,7 @@ ${buildHeadingDirective("CODE", slcMarkdown, targetLang)}`;
27293
27318
  }
27294
27319
  );
27295
27320
  if (rawCode && !rawCode.startsWith("\u26A0\uFE0F") && rawCode.length >= 200) {
27296
- await storage.saveArtifact(projectId, codeRelPath, rawCode);
27321
+ await storage.saveArtifact(projectId, codeRelPath, stampPlanHash(rawCode));
27297
27322
  await storage.updateArtifactState(projectId, lessonCode, "CODE", {
27298
27323
  state: "completed",
27299
27324
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -27309,7 +27334,8 @@ ${buildHeadingDirective("CODE", slcMarkdown, targetLang)}`;
27309
27334
  }
27310
27335
  }
27311
27336
  const extRelPath = `_content/${unitCode}/EXT_${lessonCode}.md`;
27312
- if (artifactScope.includes("EXT") && (!await storage.readArtifact(projectId, extRelPath) || force)) {
27337
+ const existingExt = await storage.readArtifact(projectId, extRelPath);
27338
+ if (artifactScope.includes("EXT") && (!existingExt || force || isStaleVsPlan(existingExt))) {
27313
27339
  onProgress?.("@activity", `Authoring Advanced Extension Challenge: \`EXT_${lessonCode}.md\`...`, { artifactType: "EXT" });
27314
27340
  const extDateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
27315
27341
  const isVi = targetLang === "vi";
@@ -27379,7 +27405,7 @@ ${buildHeadingDirective("EXT", slcMarkdown, targetLang)}`;
27379
27405
  }
27380
27406
  );
27381
27407
  if (rawExt && !rawExt.startsWith("\u26A0\uFE0F") && rawExt.length >= 200) {
27382
- await storage.saveArtifact(projectId, extRelPath, rawExt);
27408
+ await storage.saveArtifact(projectId, extRelPath, stampPlanHash(rawExt));
27383
27409
  await storage.updateArtifactState(projectId, lessonCode, "EXT", {
27384
27410
  state: "completed",
27385
27411
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),