@thanh01.pmt/curriculum-kit 1.4.17 → 1.4.20
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/{gateSettings-L3FR2-MO.d.cts → gateSettings-DabOqP6_.d.cts} +94 -1
- package/dist/{gateSettings-L3FR2-MO.d.ts → gateSettings-DabOqP6_.d.ts} +94 -1
- package/dist/index.cjs +876 -141
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +253 -112
- package/dist/index.d.ts +253 -112
- package/dist/index.mjs +870 -143
- package/dist/index.mjs.map +1 -1
- package/dist/workflow/index.cjs +359 -1
- 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 +359 -1
- package/dist/workflow/index.mjs.map +1 -1
- package/package.json +23 -22
- package/LICENSE +0 -21
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MilestoneInput, LessonPlan, CurriculumQualityReport, ActivityLab, CodeLab, SelfLab, DiagnosticQuiz, SlideDeck, Handout, Worksheet, TeacherGuide, Extension, ProjectRoadmap } from '../schemas/index.cjs';
|
|
2
2
|
import { M as ModelResolutionOptions } from '../provider-factory-DxzOVEmh.cjs';
|
|
3
3
|
import { G as GitPublishOptions, a as GitPublishResult, S as SupabasePublishOptions, b as SupabasePublishResult } from '../supabasePublisher-C627qXFT.cjs';
|
|
4
|
-
import { S as SingleArtifactRequest, a as SingleArtifactResult } from '../gateSettings-
|
|
5
|
-
export { b as CurriculumArtifactType, C as CurriculumGateMode, D as DEFAULT_GATE_SETTINGS, G as GateSettings, R as ResolvedGateSettings, g as gateModeFor, p as parseGateSettings, r as resolveGateSettings } from '../gateSettings-
|
|
4
|
+
import { S as SingleArtifactRequest, a as SingleArtifactResult } from '../gateSettings-DabOqP6_.cjs';
|
|
5
|
+
export { b as CurriculumArtifactType, C as CurriculumGateMode, D as DEFAULT_GATE_SETTINGS, G as GateSettings, R as ResolvedGateSettings, g as gateModeFor, p as parseGateSettings, r as resolveGateSettings } from '../gateSettings-DabOqP6_.cjs';
|
|
6
6
|
import * as workflow from 'workflow';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import { F as FrameworkPack, C as CoverageGateReport } from '../standardsCoverageGate-DR5YTtlt.cjs';
|
package/dist/workflow/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MilestoneInput, LessonPlan, CurriculumQualityReport, ActivityLab, CodeLab, SelfLab, DiagnosticQuiz, SlideDeck, Handout, Worksheet, TeacherGuide, Extension, ProjectRoadmap } from '../schemas/index.js';
|
|
2
2
|
import { M as ModelResolutionOptions } from '../provider-factory-DxzOVEmh.js';
|
|
3
3
|
import { G as GitPublishOptions, a as GitPublishResult, S as SupabasePublishOptions, b as SupabasePublishResult } from '../supabasePublisher-C627qXFT.js';
|
|
4
|
-
import { S as SingleArtifactRequest, a as SingleArtifactResult } from '../gateSettings-
|
|
5
|
-
export { b as CurriculumArtifactType, C as CurriculumGateMode, D as DEFAULT_GATE_SETTINGS, G as GateSettings, R as ResolvedGateSettings, g as gateModeFor, p as parseGateSettings, r as resolveGateSettings } from '../gateSettings-
|
|
4
|
+
import { S as SingleArtifactRequest, a as SingleArtifactResult } from '../gateSettings-DabOqP6_.js';
|
|
5
|
+
export { b as CurriculumArtifactType, C as CurriculumGateMode, D as DEFAULT_GATE_SETTINGS, G as GateSettings, R as ResolvedGateSettings, g as gateModeFor, p as parseGateSettings, r as resolveGateSettings } from '../gateSettings-DabOqP6_.js';
|
|
6
6
|
import * as workflow from 'workflow';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import { F as FrameworkPack, C as CoverageGateReport } from '../standardsCoverageGate-DR5YTtlt.js';
|
package/dist/workflow/index.mjs
CHANGED
|
@@ -18869,8 +18869,272 @@ ${lines.join("\n")}
|
|
|
18869
18869
|
- For example: if canonical section is "Computational Thinking Focus", your heading must be "## [REQUIRED] ${headings["Computational Thinking Focus"] || "Computational Thinking Focus"}".`;
|
|
18870
18870
|
}
|
|
18871
18871
|
|
|
18872
|
+
// src/services/curriculumHorizon.ts
|
|
18873
|
+
init_errors();
|
|
18874
|
+
var DETAILED_BRIDGE_WINDOW = 2;
|
|
18875
|
+
var BOUNDARY_PEEK_WINDOW = 2;
|
|
18876
|
+
function parseAllSessions(plan, frameworkMarkdown) {
|
|
18877
|
+
if (plan) {
|
|
18878
|
+
const rawSessions = Array.isArray(plan.sessions) ? plan.sessions : Array.isArray(plan) ? plan : [];
|
|
18879
|
+
if (rawSessions.length > 0) {
|
|
18880
|
+
return rawSessions.map((s, idx) => ({
|
|
18881
|
+
id: s.id || `L${String(idx + 1).padStart(2, "0")}`,
|
|
18882
|
+
order: typeof s.order === "number" ? s.order : idx + 1,
|
|
18883
|
+
title: s.title || "",
|
|
18884
|
+
prose_objective: s.prose_objective || s.objective || "",
|
|
18885
|
+
new_keywords: Array.isArray(s.new_keywords) ? s.new_keywords : Array.isArray(s.keywords) ? s.keywords : [],
|
|
18886
|
+
prerequisite_keywords: Array.isArray(s.prerequisite_keywords) ? s.prerequisite_keywords : [],
|
|
18887
|
+
depth_assignments: Array.isArray(s.depth_assignments) ? s.depth_assignments : []
|
|
18888
|
+
}));
|
|
18889
|
+
}
|
|
18890
|
+
}
|
|
18891
|
+
if (frameworkMarkdown && typeof frameworkMarkdown === "string") {
|
|
18892
|
+
const lines = frameworkMarkdown.split("\n");
|
|
18893
|
+
let headerCols = [];
|
|
18894
|
+
const sessions = [];
|
|
18895
|
+
for (const line of lines) {
|
|
18896
|
+
const trimmed = line.trim();
|
|
18897
|
+
if (!trimmed.startsWith("|")) continue;
|
|
18898
|
+
const cols = trimmed.split("|").slice(1, -1).map((c) => c.trim());
|
|
18899
|
+
const lower = cols.map((c) => c.toLowerCase());
|
|
18900
|
+
if (lower.some((c) => c.includes("lesson code") || c === "m\xE3 b\xE0i" || c.includes("m\xE3 b\xE0i h\u1ECDc"))) {
|
|
18901
|
+
headerCols = cols;
|
|
18902
|
+
continue;
|
|
18903
|
+
}
|
|
18904
|
+
if (/^[-: |]+$/.test(trimmed.slice(1, -1))) continue;
|
|
18905
|
+
if (cols.length < 3) continue;
|
|
18906
|
+
let lessonCode = "";
|
|
18907
|
+
let title = "";
|
|
18908
|
+
let objective = "";
|
|
18909
|
+
let concept = "";
|
|
18910
|
+
let keywordsStr = "";
|
|
18911
|
+
if (headerCols.length > 0) {
|
|
18912
|
+
const col = (name) => {
|
|
18913
|
+
const idx = headerCols.findIndex((h) => h.toLowerCase().includes(name));
|
|
18914
|
+
return idx >= 0 ? cols[idx] || "" : "";
|
|
18915
|
+
};
|
|
18916
|
+
lessonCode = (col("lesson code") || col("m\xE3 b\xE0i") || cols[1] || "").replace(/\*\*/g, "").trim();
|
|
18917
|
+
title = (col("title") || col("t\xEAn") || cols[2] || "").replace(/\*\*/g, "").trim();
|
|
18918
|
+
objective = col("learning objective") || col("objective") || col("m\u1EE5c ti\xEAu") || "";
|
|
18919
|
+
concept = col("key concept") || col("concept") || col("kh\xE1i ni\u1EC7m") || "";
|
|
18920
|
+
keywordsStr = col("keywords") || col("t\u1EEB kh\xF3a") || "";
|
|
18921
|
+
} else {
|
|
18922
|
+
lessonCode = (cols[1] || "").replace(/\*\*/g, "").trim();
|
|
18923
|
+
title = (cols[2] || "").replace(/\*\*/g, "").trim();
|
|
18924
|
+
objective = cols[5] || "";
|
|
18925
|
+
concept = cols[4] || "";
|
|
18926
|
+
}
|
|
18927
|
+
if (lessonCode && /^[A-Za-z0-9_\-]+$/.test(lessonCode)) {
|
|
18928
|
+
const keywords = keywordsStr ? keywordsStr.split(/[,;\n]/).map((k) => k.trim().replace(/^`|`$/g, "")).filter(Boolean) : concept ? concept.split(/[,;\n]/).map((k) => k.trim().replace(/^`|`$/g, "")).filter(Boolean) : [];
|
|
18929
|
+
sessions.push({
|
|
18930
|
+
id: lessonCode,
|
|
18931
|
+
order: sessions.length + 1,
|
|
18932
|
+
title: title || lessonCode,
|
|
18933
|
+
prose_objective: objective,
|
|
18934
|
+
new_keywords: keywords
|
|
18935
|
+
});
|
|
18936
|
+
}
|
|
18937
|
+
}
|
|
18938
|
+
if (sessions.length > 0) {
|
|
18939
|
+
return sessions;
|
|
18940
|
+
}
|
|
18941
|
+
}
|
|
18942
|
+
return [];
|
|
18943
|
+
}
|
|
18944
|
+
async function extractCurriculumHorizon(opts) {
|
|
18945
|
+
const { plan, frameworkMarkdown, targetLessonId, storage, projectId } = opts;
|
|
18946
|
+
const sessions = parseAllSessions(plan, frameworkMarkdown);
|
|
18947
|
+
if (sessions.length === 0) {
|
|
18948
|
+
throw new CurriculumError({
|
|
18949
|
+
errorCode: "ERR_LESSON_NOT_IN_SOT",
|
|
18950
|
+
lessonId: targetLessonId,
|
|
18951
|
+
message: `[CurriculumHorizon] No sessions could be parsed from CURRICULUM_PLAN.json or CURRICULUM_FRAMEWORK.md. Fail fast \u2014 cannot construct curriculum horizon without SOT.`,
|
|
18952
|
+
suggestedAction: "Ensure CURRICULUM_PLAN.json or CURRICULUM_FRAMEWORK.md is generated and contains valid sessions.",
|
|
18953
|
+
retryable: false
|
|
18954
|
+
});
|
|
18955
|
+
}
|
|
18956
|
+
const targetCodePattern = new RegExp("^" + targetLessonId.replace(/_/g, "[_-]") + "$", "i");
|
|
18957
|
+
const targetIndex = sessions.findIndex(
|
|
18958
|
+
(s) => s.id === targetLessonId || targetCodePattern.test(s.id)
|
|
18959
|
+
);
|
|
18960
|
+
if (targetIndex < 0) {
|
|
18961
|
+
throw new CurriculumError({
|
|
18962
|
+
errorCode: "ERR_LESSON_NOT_IN_SOT",
|
|
18963
|
+
lessonId: targetLessonId,
|
|
18964
|
+
message: `[CurriculumHorizon] Lesson "${targetLessonId}" was not found among the ${sessions.length} planned sessions. Fail fast \u2014 refusing to generate unanchored lesson.`,
|
|
18965
|
+
suggestedAction: `Check lesson id against planned sessions: [${sessions.map((s) => s.id).join(", ")}]`,
|
|
18966
|
+
retryable: false
|
|
18967
|
+
});
|
|
18968
|
+
}
|
|
18969
|
+
const currentSession = sessions[targetIndex];
|
|
18970
|
+
const compactEnd = Math.max(0, targetIndex - DETAILED_BRIDGE_WINDOW);
|
|
18971
|
+
const compactSessions = sessions.slice(0, compactEnd);
|
|
18972
|
+
const masteredKeywords = Array.from(
|
|
18973
|
+
new Set(
|
|
18974
|
+
compactSessions.flatMap((s) => s.new_keywords || []).map((k) => k.trim()).filter(Boolean)
|
|
18975
|
+
)
|
|
18976
|
+
);
|
|
18977
|
+
const masteredConcepts = Array.from(
|
|
18978
|
+
new Set(
|
|
18979
|
+
compactSessions.map((s) => s.title || s.prose_objective || "").map((t) => t.trim()).filter(Boolean)
|
|
18980
|
+
)
|
|
18981
|
+
);
|
|
18982
|
+
const bridgeStart = Math.max(0, targetIndex - DETAILED_BRIDGE_WINDOW);
|
|
18983
|
+
const bridgeSessions = sessions.slice(bridgeStart, targetIndex);
|
|
18984
|
+
const detailedBridge = [];
|
|
18985
|
+
for (const session of bridgeSessions) {
|
|
18986
|
+
const bridgeIndex = sessions.indexOf(session) + 1;
|
|
18987
|
+
const bridge = {
|
|
18988
|
+
lessonId: session.id,
|
|
18989
|
+
lessonIndex: bridgeIndex,
|
|
18990
|
+
title: session.title,
|
|
18991
|
+
proseObjective: session.prose_objective,
|
|
18992
|
+
keywords: session.new_keywords || []
|
|
18993
|
+
};
|
|
18994
|
+
if (storage && projectId) {
|
|
18995
|
+
try {
|
|
18996
|
+
const candidates = [
|
|
18997
|
+
`_content/${session.id.replace(/_L\d+$/, "")}/LESSON_${session.id}.md`,
|
|
18998
|
+
`_content/LESSON_${session.id}.md`,
|
|
18999
|
+
`LESSON_${session.id}.md`
|
|
19000
|
+
];
|
|
19001
|
+
let lessonMd = "";
|
|
19002
|
+
for (const c of candidates) {
|
|
19003
|
+
try {
|
|
19004
|
+
const raw = await storage.readArtifact(projectId, c);
|
|
19005
|
+
if (raw) {
|
|
19006
|
+
lessonMd = raw;
|
|
19007
|
+
break;
|
|
19008
|
+
}
|
|
19009
|
+
} catch {
|
|
19010
|
+
}
|
|
19011
|
+
}
|
|
19012
|
+
if (lessonMd) {
|
|
19013
|
+
const ledger = extractSymbolLedger(lessonMd);
|
|
19014
|
+
if (ledger.primarySymbol || ledger.entryFileName || ledger.keySymbols.length > 0) {
|
|
19015
|
+
bridge.symbolLedger = {
|
|
19016
|
+
primaryStructOrClass: ledger.primarySymbol,
|
|
19017
|
+
mainEntryFile: ledger.entryFileName,
|
|
19018
|
+
keyVariables: ledger.keySymbols
|
|
19019
|
+
};
|
|
19020
|
+
}
|
|
19021
|
+
}
|
|
19022
|
+
} catch {
|
|
19023
|
+
}
|
|
19024
|
+
}
|
|
19025
|
+
detailedBridge.push(bridge);
|
|
19026
|
+
}
|
|
19027
|
+
const peekStart = targetIndex + 1;
|
|
19028
|
+
const peekEnd = Math.min(sessions.length, peekStart + BOUNDARY_PEEK_WINDOW);
|
|
19029
|
+
const boundaryPeek = sessions.slice(peekStart, peekEnd).map((s, idx) => ({
|
|
19030
|
+
lessonId: s.id,
|
|
19031
|
+
lessonIndex: peekStart + idx + 1,
|
|
19032
|
+
title: s.title,
|
|
19033
|
+
keywords: s.new_keywords || []
|
|
19034
|
+
}));
|
|
19035
|
+
return {
|
|
19036
|
+
targetLessonId,
|
|
19037
|
+
targetLessonIndex: targetIndex + 1,
|
|
19038
|
+
totalLessons: sessions.length,
|
|
19039
|
+
targetTitle: currentSession.title,
|
|
19040
|
+
targetKeywords: currentSession.new_keywords || [],
|
|
19041
|
+
compactMasterySet: {
|
|
19042
|
+
masteredKeywords,
|
|
19043
|
+
masteredConcepts
|
|
19044
|
+
},
|
|
19045
|
+
detailedBridge,
|
|
19046
|
+
boundaryPeek
|
|
19047
|
+
};
|
|
19048
|
+
}
|
|
19049
|
+
function renderHorizonPromptBlock(horizon) {
|
|
19050
|
+
const {
|
|
19051
|
+
targetLessonId,
|
|
19052
|
+
targetLessonIndex,
|
|
19053
|
+
totalLessons,
|
|
19054
|
+
targetTitle,
|
|
19055
|
+
targetKeywords,
|
|
19056
|
+
compactMasterySet,
|
|
19057
|
+
detailedBridge,
|
|
19058
|
+
boundaryPeek
|
|
19059
|
+
} = horizon;
|
|
19060
|
+
const lines = [
|
|
19061
|
+
`# \u{1F9ED} CURRICULUM HORIZON & SCAFFOLDING MATRIX (Lesson ${targetLessonIndex}/${totalLessons}: "${targetTitle}" [${targetLessonId}])`
|
|
19062
|
+
];
|
|
19063
|
+
if (compactMasterySet.masteredKeywords.length > 0 || compactMasterySet.masteredConcepts.length > 0) {
|
|
19064
|
+
const rawKeywords = compactMasterySet.masteredKeywords;
|
|
19065
|
+
const displayedKeywords = rawKeywords.length > 20 ? rawKeywords.slice(-20) : rawKeywords;
|
|
19066
|
+
const vocab = displayedKeywords.map((k) => `\`${k}\``).join(", ");
|
|
19067
|
+
const moreSuffix = rawKeywords.length > 20 ? ` *(+${rawKeywords.length - 20} earlier terms)*` : "";
|
|
19068
|
+
const concepts = compactMasterySet.masteredConcepts.length > 0 ? `
|
|
19069
|
+
- **Prior Concept Foundations:** ${compactMasterySet.masteredConcepts.slice(-3).join("; ")}` : "";
|
|
19070
|
+
lines.push(
|
|
19071
|
+
`
|
|
19072
|
+
## 1. \u{1F393} MASTERED VOCABULARY (Prior Lessons 1..${Math.max(1, targetLessonIndex - 3)} \u2014 Compact Set):`,
|
|
19073
|
+
`- **Mastered Terms & Syntax:** ${vocab || "(Core fundamentals)"}${moreSuffix}${concepts}`
|
|
19074
|
+
);
|
|
19075
|
+
} else if (targetLessonIndex === 1) {
|
|
19076
|
+
lines.push(
|
|
19077
|
+
`
|
|
19078
|
+
## 1. \u{1F393} PRIOR KNOWLEDGE FRONTIER:`,
|
|
19079
|
+
`- **Entry Point:** Inaugural lesson (Lesson 1/${totalLessons}). Students have no prior course vocabulary. All concepts must be introduced from baseline.`
|
|
19080
|
+
);
|
|
19081
|
+
}
|
|
19082
|
+
if (detailedBridge.length > 0) {
|
|
19083
|
+
lines.push(`
|
|
19084
|
+
## 2. \u{1F309} IMMEDIATE PREDECESSOR CONTEXT (Bridge Lessons):`);
|
|
19085
|
+
for (const bridge of detailedBridge) {
|
|
19086
|
+
lines.push(`### Lesson ${bridge.lessonIndex} (${bridge.lessonId}): ${bridge.title}`);
|
|
19087
|
+
if (bridge.proseObjective) {
|
|
19088
|
+
const obj = bridge.proseObjective.length > 120 ? bridge.proseObjective.slice(0, 117) + "..." : bridge.proseObjective;
|
|
19089
|
+
lines.push(`- **Objective:** ${obj}`);
|
|
19090
|
+
}
|
|
19091
|
+
if (bridge.keywords.length > 0) {
|
|
19092
|
+
lines.push(`- **Keywords:** ${bridge.keywords.map((k) => `\`${k}\``).join(", ")}`);
|
|
19093
|
+
}
|
|
19094
|
+
if (bridge.symbolLedger) {
|
|
19095
|
+
const parts = [];
|
|
19096
|
+
if (bridge.symbolLedger.primaryStructOrClass) {
|
|
19097
|
+
parts.push(`Primary Struct: \`${bridge.symbolLedger.primaryStructOrClass}\``);
|
|
19098
|
+
}
|
|
19099
|
+
if (bridge.symbolLedger.mainEntryFile) {
|
|
19100
|
+
parts.push(`Entry File: \`${bridge.symbolLedger.mainEntryFile}\``);
|
|
19101
|
+
}
|
|
19102
|
+
if (bridge.symbolLedger.keyVariables?.length) {
|
|
19103
|
+
parts.push(`Symbols: ${bridge.symbolLedger.keyVariables.map((v) => `\`${v}\``).join(", ")}`);
|
|
19104
|
+
}
|
|
19105
|
+
if (parts.length > 0) {
|
|
19106
|
+
lines.push(`- **Code Symbol Ledger:** ${parts.join(" | ")}`);
|
|
19107
|
+
}
|
|
19108
|
+
}
|
|
19109
|
+
}
|
|
19110
|
+
lines.push(
|
|
19111
|
+
`\u{1F449} INSTRUCTION: Seamlessly connect the opening Hook and Guided Practice by referencing the student's recent work from Lesson ${detailedBridge[detailedBridge.length - 1]?.lessonIndex}.`
|
|
19112
|
+
);
|
|
19113
|
+
}
|
|
19114
|
+
const currentKeywordsStr = targetKeywords.length > 0 ? targetKeywords.map((k) => `\`${k}\``).join(", ") : "`Current Lesson Concepts`";
|
|
19115
|
+
lines.push(
|
|
19116
|
+
`
|
|
19117
|
+
## 3. \u{1F3AF} ALLOWED DESIGN SPACE (Positive-Only Allow List):`,
|
|
19118
|
+
`- **Student Toolkit:** Mastered Vocabulary + Immediate Bridge Keywords + Current Lesson Scope (${currentKeywordsStr}).`,
|
|
19119
|
+
`- **MANDATE:** ALL extension challenges (EXT), hands-on activities (ACT), and assessment questions (QUIZ) MUST be 100% solvable using ONLY items within this toolkit. Do NOT require unintroduced APIs!`
|
|
19120
|
+
);
|
|
19121
|
+
if (boundaryPeek.length > 0) {
|
|
19122
|
+
const nextLesson = boundaryPeek[0];
|
|
19123
|
+
const nextKeywords = nextLesson.keywords.length > 0 ? nextLesson.keywords.map((k) => `\`${k}\``).join(", ") : "upcoming features";
|
|
19124
|
+
lines.push(
|
|
19125
|
+
`
|
|
19126
|
+
## 4. \u{1F6A7} BOUNDARY (Next Lesson Peek):`,
|
|
19127
|
+
`- **Upcoming Lesson ${nextLesson.lessonIndex} ("${nextLesson.title}"):** Introduces ${nextKeywords}.`,
|
|
19128
|
+
`- **BOUNDARY MANDATE:** These concepts are NOT yet available to the student. Do not introduce or require these future concepts.`
|
|
19129
|
+
);
|
|
19130
|
+
}
|
|
19131
|
+
return lines.join("\n");
|
|
19132
|
+
}
|
|
19133
|
+
|
|
18872
19134
|
// src/services/contextBuilder.ts
|
|
18873
19135
|
var DEFAULT_LESSON_PRIORITIES = [
|
|
19136
|
+
"Symbol & Identifier Ledger",
|
|
19137
|
+
"Artifact Contract",
|
|
18874
19138
|
"A. Lesson Design Plan",
|
|
18875
19139
|
"B. Lesson Flow",
|
|
18876
19140
|
"Learning Objectives & Evidence",
|
|
@@ -19089,6 +19353,12 @@ function normalizeHeading(str) {
|
|
|
19089
19353
|
return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
19090
19354
|
}
|
|
19091
19355
|
function findCanonicalFuzzy(norm) {
|
|
19356
|
+
if (norm.includes("symbol") || norm.includes("identifier ledger") || norm.includes("dinh danh")) {
|
|
19357
|
+
return "Symbol & Identifier Ledger";
|
|
19358
|
+
}
|
|
19359
|
+
if (norm.includes("artifact contract") || norm.includes("hop dong hoc lieu")) {
|
|
19360
|
+
return "Artifact Contract";
|
|
19361
|
+
}
|
|
19092
19362
|
if (norm.includes("lesson design plan") || norm.includes("ke hoach thiet ke")) {
|
|
19093
19363
|
return "A. Lesson Design Plan";
|
|
19094
19364
|
}
|
|
@@ -19139,6 +19409,54 @@ function deriveArtifactTypeFromFileName(fileName) {
|
|
|
19139
19409
|
const token = base.match(/^([A-Z][A-Z0-9_]*?)(?=_|$)/);
|
|
19140
19410
|
return token ? token[1] : void 0;
|
|
19141
19411
|
}
|
|
19412
|
+
function extractSymbolLedger(lessonMarkdown) {
|
|
19413
|
+
const result = {
|
|
19414
|
+
keySymbols: [],
|
|
19415
|
+
rawBlock: ""
|
|
19416
|
+
};
|
|
19417
|
+
if (!lessonMarkdown) return result;
|
|
19418
|
+
const ledgerMatch = lessonMarkdown.match(/###?\s*(?:Symbol & Identifier Ledger|Bảng Định Danh|Artifact Contract)[\s\S]*?(?=\n##|\n---|$)/i);
|
|
19419
|
+
if (ledgerMatch) {
|
|
19420
|
+
result.rawBlock = ledgerMatch[0].trim();
|
|
19421
|
+
}
|
|
19422
|
+
const structMatch = lessonMarkdown.match(/(?:Primary Struct|Primary Class|Primary Function|Main Component|Primary Module|Struct chính|Class chính|Hàm chính)[:\s*`]+([A-Za-z0-9_]+)/i);
|
|
19423
|
+
if (structMatch) {
|
|
19424
|
+
result.primarySymbol = structMatch[1];
|
|
19425
|
+
result.keySymbols.push(structMatch[1]);
|
|
19426
|
+
} else {
|
|
19427
|
+
const codeStructMatch = lessonMarkdown.match(/(?:struct|class|interface|type|def|function)\s+([A-Za-z0-9_]+)/);
|
|
19428
|
+
if (codeStructMatch) {
|
|
19429
|
+
const sym = codeStructMatch[1];
|
|
19430
|
+
result.primarySymbol = sym;
|
|
19431
|
+
result.keySymbols.push(sym);
|
|
19432
|
+
}
|
|
19433
|
+
}
|
|
19434
|
+
const fileMatch = lessonMarkdown.match(/(?:Entry File|Source File|Target File|Tên file mã nguồn)[:\s*`]+([A-Za-z0-9_\-\.]+\.[a-z0-9_]+)/i);
|
|
19435
|
+
if (fileMatch) {
|
|
19436
|
+
result.entryFileName = fileMatch[1];
|
|
19437
|
+
} else {
|
|
19438
|
+
const codeFileComment = lessonMarkdown.match(/(?:\/\/\s*|#\s*|\/\*\s*)([A-Za-z0-9_\-]+\.[a-zA-Z0-9]+)/);
|
|
19439
|
+
if (codeFileComment) {
|
|
19440
|
+
result.entryFileName = codeFileComment[1];
|
|
19441
|
+
}
|
|
19442
|
+
}
|
|
19443
|
+
return result;
|
|
19444
|
+
}
|
|
19445
|
+
|
|
19446
|
+
// src/services/knowledgeExpositionService.ts
|
|
19447
|
+
function buildDomainLexiconGuardrail(techStack, hardwarePlatform) {
|
|
19448
|
+
const targetTech = (techStack).trim();
|
|
19449
|
+
const targetHw = (hardwarePlatform || "").trim();
|
|
19450
|
+
const platformAnchor = [targetTech, targetHw].filter(Boolean).join(" | ");
|
|
19451
|
+
if (!platformAnchor) {
|
|
19452
|
+
return `- \u{1F512} TECHNICAL DOMAIN ANCHOR: Strictly adhere to the declared curriculum domain. Use ONLY native, standard, idiomatic syntax and mechanisms. Strictly FORBIDDEN from using foreign paradigms, cross-domain jargon, or hallucinated APIs.`;
|
|
19453
|
+
}
|
|
19454
|
+
return `- \u{1F512} STRICT DOMAIN & TECHNICAL PLATFORM ANCHOR:
|
|
19455
|
+
\u2022 Declared Platform: "${platformAnchor}"
|
|
19456
|
+
\u2022 NATIVE PARADIGM ONLY: You MUST strictly use standard, idiomatic syntax, conventions, naming patterns, and mental models of "${platformAnchor}".
|
|
19457
|
+
\u2022 ANTI-CONTAMINATION INVARIANT: Strictly FORBIDDEN from importing or using syntax, units, keywords, tags, or concepts from unrelated/foreign ecosystems (e.g., do NOT leak Web/HTML/CSS tags or units into native mobile/embedded stacks, do NOT leak dynamic scripting into statically typed systems, do NOT use hardware/circuit terminology in pure-software courses).
|
|
19458
|
+
\u2022 REAL APIS ONLY: Every method, modifier, property, and API referenced must exist in the standard SDK of "${platformAnchor}".`;
|
|
19459
|
+
}
|
|
19142
19460
|
init_errors();
|
|
19143
19461
|
|
|
19144
19462
|
// src/services/lessonProductionService.ts
|
|
@@ -19364,6 +19682,29 @@ async function generateSingleArtifact(req) {
|
|
|
19364
19682
|
const artifactSpecializedPrompt = getArtifactSpecializedInvariants(artifactType, {
|
|
19365
19683
|
...req,
|
|
19366
19684
|
studentCount});
|
|
19685
|
+
const techStack = req.config?.techStack || req.hardwarePlatform?.[0] || "Declared Technical Domain";
|
|
19686
|
+
const domainGuardrail = buildDomainLexiconGuardrail(techStack, hwStr);
|
|
19687
|
+
const symbolLedger = contextSot.lessonPlan ? extractSymbolLedger(contextSot.lessonPlan) : null;
|
|
19688
|
+
const symbolLedgerPrompt = symbolLedger?.primarySymbol ? `
|
|
19689
|
+
7. MANDATORY CODE SYMBOL REGISTRY (Inherited from Canonical LESSON):
|
|
19690
|
+
- Primary Struct / Class: \`${symbolLedger.primarySymbol}\`
|
|
19691
|
+
- Entry Source File: \`${symbolLedger.entryFileName || symbolLedger.primarySymbol + ".swift"}\`
|
|
19692
|
+
- Key Identifiers to inherit: ${symbolLedger.keySymbols.map((s) => `\`${s}\``).join(", ")}
|
|
19693
|
+
- INVARIANT: You MUST use these exact identifier names in all code examples, exercises, and starter templates. Do NOT invent conflicting struct or class names.` : "";
|
|
19694
|
+
let horizon = contextSot.horizon || null;
|
|
19695
|
+
if (!horizon && (contextSot.plan || contextSot.framework) && lessonId) {
|
|
19696
|
+
try {
|
|
19697
|
+
horizon = await extractCurriculumHorizon({
|
|
19698
|
+
plan: contextSot.plan,
|
|
19699
|
+
frameworkMarkdown: contextSot.framework,
|
|
19700
|
+
targetLessonId: lessonId
|
|
19701
|
+
});
|
|
19702
|
+
} catch {
|
|
19703
|
+
}
|
|
19704
|
+
}
|
|
19705
|
+
const horizonPrompt = horizon ? `
|
|
19706
|
+
|
|
19707
|
+
${renderHorizonPromptBlock(horizon)}` : "";
|
|
19367
19708
|
const systemPrompt = `You are ${meta.persona}, an expert Curriculum & Pedagogical Specialist in the Curriculum OS Multi-Agent Team.
|
|
19368
19709
|
Your task is to author a canonical, publication-grade learning artifact of type "${artifactType.toUpperCase()}".
|
|
19369
19710
|
|
|
@@ -19374,7 +19715,10 @@ ${headingDirective}
|
|
|
19374
19715
|
3. PEDAGOGICAL GROUNDING: Strictly align with the ${pedagogy.toUpperCase()} model, Bloom's Revised Taxonomy, and IEEE/ACM CS2023 guidelines.
|
|
19375
19716
|
4. SCAFFOLDING LEVEL: "${scaffoldingLevel.toUpperCase()}".${scaffoldingRule}
|
|
19376
19717
|
5. TARGET AUDIENCE: ${gradeLevel ? `Grade ${gradeLevel}, ` : ""}${targetAge} on ${hwStr}.${deviceRule}${classDynamicsRule}${extraContextRule}
|
|
19377
|
-
6.
|
|
19718
|
+
6. DOMAIN & TECH STACK GUARDRAILS:
|
|
19719
|
+
${domainGuardrail}
|
|
19720
|
+
${symbolLedgerPrompt}
|
|
19721
|
+
8. OUTPUT INTEGRITY: Output clean Markdown starting directly with YAML frontmatter. Do not wrap entire response in triple backticks.${artifactSpecializedPrompt}${horizonPrompt}${mediaPolicy ? `
|
|
19378
19722
|
|
|
19379
19723
|
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).
|
|
19380
19724
|
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.` : ""}`;
|
|
@@ -19854,6 +20198,20 @@ ${includeUnitTests ? "- Unit Testing: Provide automated assertions or test runne
|
|
|
19854
20198
|
1. **CLASS-SCALED INVENTORY FOR ${studentCount} STUDENTS**:
|
|
19855
20199
|
- Exact quantities calculated for ${studentCount} students.
|
|
19856
20200
|
- Component specifications, estimated unit cost, and affordable alternatives.`;
|
|
20201
|
+
case "ext": {
|
|
20202
|
+
const zpdCeilingRule = `- \u{1F3AF} CURRICULUM HORIZON ALLOWED SPACE & BOUNDARY MANDATE:
|
|
20203
|
+
\u2022 SCOPE LOCK: All extension challenges MUST be 100% solvable using ONLY items from the student's Mastered Vocabulary and Current Lesson Scope.
|
|
20204
|
+
\u2022 STRICTLY FORBIDDEN: NEVER introduce unintroduced APIs or mechanisms from upcoming lessons (No complex event buses, No remote network/API calls, No persistent databases, No async concurrency, No out-of-scope hardware/sensors unless explicitly part of the allowed toolkit).`;
|
|
20205
|
+
return `
|
|
20206
|
+
### \u{1F680} EXTENSION CHALLENGE ARCHITECTURE INVARIANTS:
|
|
20207
|
+
${zpdCeilingRule}
|
|
20208
|
+
1. **STRUCTURED 3-TIER CHALLENGES**:
|
|
20209
|
+
- Challenge 1 (Mission Briefing): High-stakes real-world scenario applying today's concepts.
|
|
20210
|
+
- Challenge 2 (Architectural Constraints & Edge Cases): Deeper technical rules without violating prerequisite boundaries.
|
|
20211
|
+
- Challenge 3 (Extension Milestones): Progressive milestones (Level 1: Novice \u2192 Level 2: Advanced \u2192 Level 3: Master).
|
|
20212
|
+
2. **METACOGNITIVE & ENGINEERING TRADE-OFFS**:
|
|
20213
|
+
- Explicit reflection prompts evaluating architectural choices, code maintainability, and design patterns.`;
|
|
20214
|
+
}
|
|
19857
20215
|
case "lesson": {
|
|
19858
20216
|
const lessonDuration = cfg.lessonDuration || 90;
|
|
19859
20217
|
const pedagogicalModel = cfg.pedagogicalModel || req.pedagogy || "5e";
|