@thanh01.pmt/curriculum-kit 1.4.42 → 1.4.44
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 +66 -470
- package/dist/ai/index.cjs.map +1 -1
- package/dist/ai/index.mjs +64 -469
- package/dist/ai/index.mjs.map +1 -1
- package/dist/index.cjs +237 -688
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -31
- package/dist/index.d.ts +12 -31
- package/dist/index.mjs +235 -682
- package/dist/index.mjs.map +1 -1
- package/dist/pipeline/index.cjs +66 -470
- package/dist/pipeline/index.cjs.map +1 -1
- package/dist/pipeline/index.mjs +64 -469
- package/dist/pipeline/index.mjs.map +1 -1
- package/dist/templates/LAB_TEMPLATE.md +61 -0
- package/dist/templates/SELF_LAB_template.md +167 -0
- package/dist/workflow/index.cjs +84 -528
- package/dist/workflow/index.cjs.map +1 -1
- package/dist/workflow/index.mjs +82 -526
- package/dist/workflow/index.mjs.map +1 -1
- package/docs/refs/templates/LAB_TEMPLATE.md +61 -0
- package/docs/refs/templates/SELF_LAB_template.md +167 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var fs3 = require('fs');
|
|
4
|
+
var path4 = require('path');
|
|
5
5
|
var google = require('@ai-sdk/google');
|
|
6
6
|
var openai = require('@ai-sdk/openai');
|
|
7
7
|
var deepseek = require('@ai-sdk/deepseek');
|
|
@@ -9,18 +9,18 @@ var zod = require('zod');
|
|
|
9
9
|
var ai = require('ai');
|
|
10
10
|
var pRetry = require('p-retry');
|
|
11
11
|
var jsonrepair = require('jsonrepair');
|
|
12
|
+
var url = require('url');
|
|
12
13
|
var pLimit = require('p-limit');
|
|
13
14
|
var fsPromises = require('fs/promises');
|
|
14
15
|
var crypto = require('crypto');
|
|
15
16
|
var supabaseJs = require('@supabase/supabase-js');
|
|
16
|
-
var url = require('url');
|
|
17
17
|
var rest = require('@octokit/rest');
|
|
18
18
|
|
|
19
19
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
20
20
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
21
|
|
|
22
|
-
var
|
|
23
|
-
var
|
|
22
|
+
var fs3__default = /*#__PURE__*/_interopDefault(fs3);
|
|
23
|
+
var path4__default = /*#__PURE__*/_interopDefault(path4);
|
|
24
24
|
var pRetry__default = /*#__PURE__*/_interopDefault(pRetry);
|
|
25
25
|
var pLimit__default = /*#__PURE__*/_interopDefault(pLimit);
|
|
26
26
|
var fsPromises__default = /*#__PURE__*/_interopDefault(fsPromises);
|
|
@@ -177,18 +177,18 @@ function resolveApiKey(keyName, explicitKey) {
|
|
|
177
177
|
try {
|
|
178
178
|
const currentDir = process.cwd();
|
|
179
179
|
const envPaths = [
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
180
|
+
path4__default.default.resolve(currentDir, ".env.local"),
|
|
181
|
+
path4__default.default.resolve(currentDir, ".env"),
|
|
182
|
+
path4__default.default.resolve(currentDir, "apps/web/.env.local"),
|
|
183
|
+
path4__default.default.resolve(currentDir, "packages/learnwell-platform/.env"),
|
|
184
|
+
path4__default.default.resolve(currentDir, "..", ".env.local"),
|
|
185
|
+
path4__default.default.resolve(currentDir, "..", ".env"),
|
|
186
|
+
path4__default.default.resolve(currentDir, "../..", ".env.local"),
|
|
187
|
+
path4__default.default.resolve(currentDir, "../..", ".env")
|
|
188
188
|
];
|
|
189
189
|
for (const envPath of envPaths) {
|
|
190
|
-
if (
|
|
191
|
-
const content =
|
|
190
|
+
if (fs3__default.default.existsSync(envPath)) {
|
|
191
|
+
const content = fs3__default.default.readFileSync(envPath, "utf-8");
|
|
192
192
|
for (const line of content.split("\n")) {
|
|
193
193
|
const trimmed = line.trim();
|
|
194
194
|
if (trimmed && !trimmed.startsWith("#") && trimmed.startsWith(keyName + "=")) {
|
|
@@ -3944,467 +3944,105 @@ var RoadmapInputSchema = zod.z.object({
|
|
|
3944
3944
|
|
|
3945
3945
|
// src/ai/index.ts
|
|
3946
3946
|
init_provider_factory();
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
---
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
{{
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
{
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
{
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
{
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
## [OPTIONAL] Teacher Notes
|
|
4047
|
-
- **Common Pitfalls:**
|
|
4048
|
-
{{COMMON_PITFALLS}}
|
|
4049
|
-
- **Troubleshooting:**
|
|
4050
|
-
{{TROUBLESHOOTING_ROWS}}
|
|
4051
|
-
|
|
4052
|
-
---
|
|
4053
|
-
|
|
4054
|
-
## [REQUIRED] Artifact Linkage (Master Index)
|
|
4055
|
-
> List all satellite files used in this lesson.
|
|
4056
|
-
|
|
4057
|
-
| Artifact File | Role in the Classroom | When to Use |
|
|
4058
|
-
|---|---|---|
|
|
4059
|
-
| \`GUIDE_{{LESSON_ID}}.md\` | Detailed Teaching Script | Teacher preparation |
|
|
4060
|
-
| \`SLIDE_{{LESSON_ID}}.md\` | Presentation Content | Throughout the session |
|
|
4061
|
-
| \`HANDOUT_{{LESSON_ID}}.md\` | Theory Summary for Students | During EXPLAIN phase |
|
|
4062
|
-
| \`ACT_{{LESSON_ID}}.md\` | Detailed Learning Activity Operations | During EXPLORE / ELABORATE / checkpoint phases |
|
|
4063
|
-
| \`WKS_{{LESSON_ID}}.md\` | Individual Worksheet | Wrap-up or Homework |
|
|
4064
|
-
| \`QUIZ_{{LESSON_ID}}.md\` | Assessment Rubric | During EVALUATE phase |
|
|
4065
|
-
| \`EXT_{{LESSON_ID}}.md\` | Enrichment Materials | For "Gold" students |
|
|
4066
|
-
`.trim();
|
|
4067
|
-
|
|
4068
|
-
// src/templates/actTemplate.ts
|
|
4069
|
-
var ACT_TEMPLATE = `
|
|
4070
|
-
---
|
|
4071
|
-
id: "{{ID}}"
|
|
4072
|
-
title: "{{TITLE}}"
|
|
4073
|
-
type: "ACT"
|
|
4074
|
-
created_by: "Curriculum OS Builder"
|
|
4075
|
-
phase: "{{PHASE}}"
|
|
4076
|
-
deliverable: "P3-T2"
|
|
4077
|
-
version: "{{VERSION}}"
|
|
4078
|
-
date: "{{DATE}}"
|
|
4079
|
-
template_contract: "artifact-template-v1"
|
|
4080
|
-
template_required_sections:
|
|
4081
|
-
- "Computational Thinking Focus"
|
|
4082
|
-
- "Materials & Setup"
|
|
4083
|
-
- "Constraints & Safety"
|
|
4084
|
-
- "Active Learning Workflow"
|
|
4085
|
-
- "3-Tier Differentiation"
|
|
4086
|
-
- "Reflection"
|
|
4087
|
-
---
|
|
4088
|
-
<!-- INJECT_BODY -->
|
|
4089
|
-
|
|
4090
|
-
# INQUIRY-BASED ACTIVITY: {{TITLE}}
|
|
4091
|
-
_Milestone: {{MILESTONE_ID}} | Module: {{MODULE_NAME}} | Lesson: {{LESSON_ID}}_
|
|
4092
|
-
|
|
4093
|
-
## [REQUIRED] Computational Thinking Focus
|
|
4094
|
-
- **Problem Statement (Real-world Scenario):** {{PROBLEM_STATEMENT}}
|
|
4095
|
-
- **Decomposition:**
|
|
4096
|
-
{{DECOMPOSITION_STEPS}}
|
|
4097
|
-
- **Algorithm Design:** {{ALGORITHM_DESIGN}}
|
|
4098
|
-
|
|
4099
|
-
## [REQUIRED] Materials & Setup
|
|
4100
|
-
- **Reference Material:** Students should use the **HANDOUT** for this lesson as their primary technical reference (lifeline).
|
|
4101
|
-
- **Hardware/Software:**
|
|
4102
|
-
<!-- [HARDWARE_BOM] -->
|
|
4103
|
-
{{HARDWARE_ITEMS}}
|
|
4104
|
-
<!-- [/HARDWARE_BOM] -->
|
|
4105
|
-
- **Software:** {{SOFTWARE_ITEMS}}
|
|
4106
|
-
- **Consumables:** {{CONSUMABLES}}
|
|
4107
|
-
- **Other Resources:** {{OTHER_RESOURCES}}
|
|
4108
|
-
|
|
4109
|
-
## [REQUIRED] Constraints & Safety
|
|
4110
|
-
- \u26A0\uFE0F **Technical/Safety:** {{SAFETY_WARNING}}
|
|
4111
|
-
- \u{1F4A1} **Design Constraint:** {{DESIGN_CONSTRAINT}}
|
|
4112
|
-
|
|
4113
|
-
## [REQUIRED] Active Learning Workflow
|
|
4114
|
-
|
|
4115
|
-
### Phase 1: Planning & Design \u2014 {{PHASE1_DURATION}} mins
|
|
4116
|
-
- **Student Task:** Hand-draw (or draft in words) the algorithm flowchart or connection architecture before touching the computer/devices.
|
|
4117
|
-
- **Teacher Action:** Walk around to check the logic of each group. Ask inquiry questions:
|
|
4118
|
-
{{PHASE1_INQUIRY_QUESTIONS}}
|
|
4119
|
-
|
|
4120
|
-
### Phase 2: Implementation & Discovery \u2014 {{PHASE2_DURATION}} mins
|
|
4121
|
-
- **Student Task:** Apply the knowledge from the **HANDOUT** to realize the plan designed in Phase 1. Encourage self-inquiry and documentation lookup.
|
|
4122
|
-
- **Teacher Action:** Avoid "hand-holding." Only intervene if a group has been stuck for more than 5 minutes.
|
|
4123
|
-
{{PHASE2_GUIDANCE_BLOCK}}
|
|
4124
|
-
|
|
4125
|
-
### Phase 3: Debugging & Testing \u2014 {{PHASE3_DURATION}} mins
|
|
4126
|
-
- **Testing:** Students run their system.
|
|
4127
|
-
- **Error Analysis:** Ask students to record any error codes or unexpected behaviors and compare them with the Troubleshooting table in the Handout.
|
|
4128
|
-
{{PHASE3_TESTING_STEPS}}
|
|
4129
|
-
|
|
4130
|
-
## [REQUIRED] 3-Tier Differentiation
|
|
4131
|
-
> MUST design tasks in 3 tiers to support diverse learner groups. Bronze is the minimum requirement for all students.
|
|
4132
|
-
- \u{1F949} **Bronze (Foundational):** {{DIFFERENTIATION_BRONZE}}
|
|
4133
|
-
- \u{1F948} **Silver (Application):** {{DIFFERENTIATION_SILVER}}
|
|
4134
|
-
- \u{1F947} **Gold (Enrichment/Creative):** {{DIFFERENTIATION_GOLD}}
|
|
4135
|
-
|
|
4136
|
-
## [REQUIRED] Reflection
|
|
4137
|
-
- **Discussion Question:** {{REFLECTION_QUESTION}}
|
|
4138
|
-
`.trim();
|
|
4139
|
-
|
|
4140
|
-
// src/templates/codeLabTemplate.ts
|
|
4141
|
-
var CODE_LAB_TEMPLATE = `
|
|
4142
|
-
---
|
|
4143
|
-
id: "{{ID}}"
|
|
4144
|
-
title: "{{TITLE}}"
|
|
4145
|
-
type: "LAB"
|
|
4146
|
-
created_by: "Curriculum OS Builder"
|
|
4147
|
-
phase: "{{PHASE}}"
|
|
4148
|
-
deliverable: "P3-T2"
|
|
4149
|
-
version: "{{VERSION}}"
|
|
4150
|
-
date: "{{DATE}}"
|
|
4151
|
-
---
|
|
4152
|
-
<!-- INJECT_BODY -->
|
|
4153
|
-
|
|
4154
|
-
# \u{1F468}\u200D\u{1F4BB} CODE LAB: {{TITLE}}
|
|
4155
|
-
_Milestone: {{MILESTONE_ID}} | Tech Stack: {{TECH_STACK}}_
|
|
4156
|
-
|
|
4157
|
-
## \u{1F3AF} Overview
|
|
4158
|
-
This lab focuses on the practical implementation of core technical concepts, bridging theory into working, robust, and testable code.
|
|
4159
|
-
|
|
4160
|
-
## \u{1F6E0}\uFE0F Environment & Setup
|
|
4161
|
-
- **Language / Framework:** {{LANGUAGE_FRAMEWORK}}
|
|
4162
|
-
- **IDE / Editor:** {{IDE_EDITOR}}
|
|
4163
|
-
- **Required Libraries:** {{REQUIRED_LIBRARIES}}
|
|
4164
|
-
- **Hardware / Connection Setup:** {{HARDWARE_ENV_CONNECTION}}
|
|
4165
|
-
|
|
4166
|
-
## \u{1F4DD} Lab Tasks (3-Tier Differentiation)
|
|
4167
|
-
|
|
4168
|
-
### \u{1F949} Bronze (Foundational) \u2014 {{BRONZE_MINS}} mins
|
|
4169
|
-
**Objective:** {{BRONZE_OBJECTIVE}}
|
|
4170
|
-
- **Task:** {{BRONZE_TASK}}
|
|
4171
|
-
- **Requirement:** {{BRONZE_REQUIREMENT}}
|
|
4172
|
-
|
|
4173
|
-
### \u{1F948} Silver (Application) \u2014 {{SILVER_MINS}} mins
|
|
4174
|
-
**Objective:** {{SILVER_OBJECTIVE}}
|
|
4175
|
-
- **Task:** {{SILVER_TASK}}
|
|
4176
|
-
- **Requirement:** {{SILVER_REQUIREMENT}}
|
|
4177
|
-
|
|
4178
|
-
### \u{1F947} Gold (Enrichment/Creative) \u2014 {{GOLD_MINS}} mins
|
|
4179
|
-
**Objective:** {{GOLD_OBJECTIVE}}
|
|
4180
|
-
- **Task:** {{GOLD_TASK}}
|
|
4181
|
-
- **Requirement:** {{GOLD_REQUIREMENT}}
|
|
4182
|
-
|
|
4183
|
-
## \u{1F4BB} Technical Reference ([SME_MANDATE])
|
|
4184
|
-
<!-- [SME_MANDATE] -->
|
|
4185
|
-
> Any code provided in this section is verified for syntax accuracy and runtime execution.
|
|
4186
|
-
|
|
4187
|
-
### Starter Code Template
|
|
4188
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4189
|
-
{{STARTER_CODE}}
|
|
4190
|
-
\`\`\`
|
|
4191
|
-
|
|
4192
|
-
### Solution Code
|
|
4193
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4194
|
-
{{SOLUTION_CODE}}
|
|
4195
|
-
\`\`\`
|
|
4196
|
-
<!-- [/SME_MANDATE] -->
|
|
4197
|
-
|
|
4198
|
-
## \u{1F50D} Troubleshooting & Debugging Matrix
|
|
4199
|
-
| Issue | Potential Cause | Solution |
|
|
4200
|
-
| :--- | :--- | :--- |
|
|
4201
|
-
{{TROUBLESHOOTING_ROWS}}
|
|
4202
|
-
|
|
4203
|
-
## \u{1F3C1} Submission & Verification Checklist
|
|
4204
|
-
{{CHECKLIST_ITEMS}}
|
|
4205
|
-
`.trim();
|
|
4206
|
-
|
|
4207
|
-
// src/templates/quizTemplate.ts
|
|
4208
|
-
var QUIZ_TEMPLATE = `
|
|
4209
|
-
---
|
|
4210
|
-
id: "{{ID}}"
|
|
4211
|
-
title: "{{TITLE}}"
|
|
4212
|
-
type: "QUIZ"
|
|
4213
|
-
language: "{{LANGUAGE}}"
|
|
4214
|
-
total_questions: {{TOTAL_QUESTIONS}}
|
|
4215
|
-
passing_score_pct: {{PASSING_SCORE_PCT}}
|
|
4216
|
-
---
|
|
4217
|
-
|
|
4218
|
-
# \u{1F9E0} Diagnostic & Active Recall Quiz: {{TITLE}}
|
|
4219
|
-
|
|
4220
|
-
> \u23F1\uFE0F **Recommended Time:** ~10-15 mins
|
|
4221
|
-
> \u{1F3AF} **Passing Score:** {{PASSING_SCORE_PCT}}%
|
|
4222
|
-
> \u{1F4A1} **Purpose:** Test your conceptual understanding, catch hidden misconceptions, and evaluate architectural trade-offs.
|
|
4223
|
-
|
|
4224
|
-
---
|
|
4225
|
-
|
|
4226
|
-
{{QUESTIONS_SECTION}}
|
|
4227
|
-
|
|
4228
|
-
---
|
|
4229
|
-
|
|
4230
|
-
## \u{1F511} Comprehensive Answer Key & Deep Explanation (Expand after completing)
|
|
4231
|
-
<details>
|
|
4232
|
-
<summary><b>\u{1F449} Click to View Full Explanations & Common Pitfall Analysis</b></summary>
|
|
4233
|
-
|
|
4234
|
-
{{ANSWER_KEY_SECTION}}
|
|
4235
|
-
</details>
|
|
4236
|
-
`.trim();
|
|
4237
|
-
|
|
4238
|
-
// src/templates/selfLabTemplate.ts
|
|
4239
|
-
var SELF_LAB_TEMPLATE = `
|
|
4240
|
-
---
|
|
4241
|
-
id: "{{ID}}"
|
|
4242
|
-
title: "{{TITLE}}"
|
|
4243
|
-
type: "SELF_LAB"
|
|
4244
|
-
language: "{{LANGUAGE}}"
|
|
4245
|
-
difficulty: "{{DIFFICULTY}}"
|
|
4246
|
-
estimated_minutes: {{ESTIMATED_MINUTES}}
|
|
4247
|
-
tech_stack: {{TECH_STACK}}
|
|
4248
|
-
---
|
|
4249
|
-
|
|
4250
|
-
# \u{1F680} Self-Paced Hands-On Lab: {{TITLE}}
|
|
4251
|
-
|
|
4252
|
-
> \u23F1\uFE0F **Estimated Duration:** ~{{ESTIMATED_MINUTES}} mins
|
|
4253
|
-
> \u{1F3AF} **Difficulty Level:** {{DIFFICULTY_UPPER}}
|
|
4254
|
-
> \u{1F9F0} **Tech Stack:** {{TECH_STACK_STR}}
|
|
4255
|
-
> \u{1F4A1} **Self-Learner Notice:** You are in full control of this lab. Follow the progressive challenges below. If you get stuck at any point, use the **Progressive Hints System** to get unstuck without ruining the learning experience!
|
|
4256
|
-
|
|
4257
|
-
---
|
|
4258
|
-
|
|
4259
|
-
## \u{1F4CB} Mission Briefing & Environment Setup
|
|
4260
|
-
{{MISSION_BRIEFING}}
|
|
4261
|
-
|
|
4262
|
-
### \u{1F6EB} Preflight Checklist
|
|
4263
|
-
{{PREFLIGHT_CHECKLIST}}
|
|
4264
|
-
|
|
4265
|
-
---
|
|
4266
|
-
|
|
4267
|
-
## \u{1F3AF} Progressive Challenges (3-Tier Differentiation)
|
|
4268
|
-
|
|
4269
|
-
### \u{1F949} Challenge 1: Foundational Core (Bronze) \u2014 ~{{BRONZE_MINS}} mins
|
|
4270
|
-
**Objective:** {{BRONZE_OBJECTIVE}}
|
|
4271
|
-
|
|
4272
|
-
#### Tasks & Implementation Details:
|
|
4273
|
-
{{BRONZE_TASKS}}
|
|
4274
|
-
|
|
4275
|
-
#### \u{1F9EA} Self-Verification Command:
|
|
4276
|
-
\`\`\`bash
|
|
4277
|
-
{{BRONZE_VERIFY_COMMAND}}
|
|
4278
|
-
\`\`\`
|
|
4279
|
-
*Expected Terminal Output:*
|
|
4280
|
-
\`\`\`text
|
|
4281
|
-
{{BRONZE_EXPECTED_OUTPUT}}
|
|
4282
|
-
\`\`\`
|
|
4283
|
-
|
|
4284
|
-
#### \u{1F4A1} Progressive Hints (Expand only if stuck):
|
|
4285
|
-
<details>
|
|
4286
|
-
<summary><b>\u{1F4A1} Hint Level 1: Conceptual Clue (H\u01B0\u1EDBng t\u01B0 duy)</b></summary>
|
|
4287
|
-
|
|
4288
|
-
{{BRONZE_HINT_1}}
|
|
4289
|
-
</details>
|
|
4290
|
-
|
|
4291
|
-
<details>
|
|
4292
|
-
<summary><b>\u{1F50D} Hint Level 2: Structural Skeleton (Khung code m\u1EABu)</b></summary>
|
|
4293
|
-
|
|
4294
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4295
|
-
{{BRONZE_HINT_2}}
|
|
4296
|
-
\`\`\`
|
|
4297
|
-
</details>
|
|
4298
|
-
|
|
4299
|
-
<details>
|
|
4300
|
-
<summary><b>\u{1F6A8} Hint Level 3: Full Solution & Explanation (L\u1EDDi gi\u1EA3i tr\u1ECDn v\u1EB9n)</b></summary>
|
|
4301
|
-
|
|
4302
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4303
|
-
{{BRONZE_HINT_3_CODE}}
|
|
4304
|
-
\`\`\`
|
|
4305
|
-
|
|
4306
|
-
**Why this solution works:**
|
|
4307
|
-
{{BRONZE_HINT_3_EXPLANATION}}
|
|
4308
|
-
</details>
|
|
4309
|
-
|
|
4310
|
-
---
|
|
4311
|
-
|
|
4312
|
-
### \u{1F948} Challenge 2: Logic & Error Handling (Silver) \u2014 ~{{SILVER_MINS}} mins
|
|
4313
|
-
**Objective:** {{SILVER_OBJECTIVE}}
|
|
4314
|
-
|
|
4315
|
-
#### Tasks & Implementation Details:
|
|
4316
|
-
{{SILVER_TASKS}}
|
|
4317
|
-
|
|
4318
|
-
#### \u{1F9EA} Self-Verification Command:
|
|
4319
|
-
\`\`\`bash
|
|
4320
|
-
{{SILVER_VERIFY_COMMAND}}
|
|
4321
|
-
\`\`\`
|
|
4322
|
-
*Expected Terminal Output:*
|
|
4323
|
-
\`\`\`text
|
|
4324
|
-
{{SILVER_EXPECTED_OUTPUT}}
|
|
4325
|
-
\`\`\`
|
|
4326
|
-
|
|
4327
|
-
#### \u{1F4A1} Progressive Hints (Expand only if stuck):
|
|
4328
|
-
<details>
|
|
4329
|
-
<summary><b>\u{1F4A1} Hint Level 1: Conceptual Clue (H\u01B0\u1EDBng t\u01B0 duy)</b></summary>
|
|
4330
|
-
|
|
4331
|
-
{{SILVER_HINT_1}}
|
|
4332
|
-
</details>
|
|
4333
|
-
|
|
4334
|
-
<details>
|
|
4335
|
-
<summary><b>\u{1F50D} Hint Level 2: Structural Skeleton (Khung code m\u1EABu)</b></summary>
|
|
4336
|
-
|
|
4337
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4338
|
-
{{SILVER_HINT_2}}
|
|
4339
|
-
\`\`\`
|
|
4340
|
-
</details>
|
|
4341
|
-
|
|
4342
|
-
<details>
|
|
4343
|
-
<summary><b>\u{1F6A8} Hint Level 3: Full Solution & Explanation (L\u1EDDi gi\u1EA3i tr\u1ECDn v\u1EB9n)</b></summary>
|
|
4344
|
-
|
|
4345
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4346
|
-
{{SILVER_HINT_3_CODE}}
|
|
4347
|
-
\`\`\`
|
|
4348
|
-
|
|
4349
|
-
**Why this solution works:**
|
|
4350
|
-
{{SILVER_HINT_3_EXPLANATION}}
|
|
4351
|
-
</details>
|
|
4352
|
-
|
|
4353
|
-
---
|
|
4354
|
-
|
|
4355
|
-
### \u{1F947} Challenge 3: Edge Cases & Optimization (Gold) \u2014 ~{{GOLD_MINS}} mins
|
|
4356
|
-
**Objective:** {{GOLD_OBJECTIVE}}
|
|
4357
|
-
|
|
4358
|
-
#### Tasks & Implementation Details:
|
|
4359
|
-
{{GOLD_TASKS}}
|
|
4360
|
-
|
|
4361
|
-
#### \u{1F9EA} Self-Verification Command:
|
|
4362
|
-
\`\`\`bash
|
|
4363
|
-
{{GOLD_VERIFY_COMMAND}}
|
|
4364
|
-
\`\`\`
|
|
4365
|
-
*Expected Terminal Output:*
|
|
4366
|
-
\`\`\`text
|
|
4367
|
-
{{GOLD_EXPECTED_OUTPUT}}
|
|
4368
|
-
\`\`\`
|
|
4369
|
-
|
|
4370
|
-
#### \u{1F4A1} Progressive Hints (Expand only if stuck):
|
|
4371
|
-
<details>
|
|
4372
|
-
<summary><b>\u{1F4A1} Hint Level 1: Conceptual Clue (H\u01B0\u1EDBng t\u01B0 duy)</b></summary>
|
|
4373
|
-
|
|
4374
|
-
{{GOLD_HINT_1}}
|
|
4375
|
-
</details>
|
|
4376
|
-
|
|
4377
|
-
<details>
|
|
4378
|
-
<summary><b>\u{1F50D} Hint Level 2: Structural Skeleton (Khung code m\u1EABu)</b></summary>
|
|
4379
|
-
|
|
4380
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4381
|
-
{{GOLD_HINT_2}}
|
|
4382
|
-
\`\`\`
|
|
4383
|
-
</details>
|
|
4384
|
-
|
|
4385
|
-
<details>
|
|
4386
|
-
<summary><b>\u{1F6A8} Hint Level 3: Full Solution & Explanation (L\u1EDDi gi\u1EA3i tr\u1ECDn v\u1EB9n)</b></summary>
|
|
4387
|
-
|
|
4388
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4389
|
-
{{GOLD_HINT_3_CODE}}
|
|
4390
|
-
\`\`\`
|
|
4391
|
-
|
|
4392
|
-
**Why this solution works:**
|
|
4393
|
-
{{GOLD_HINT_3_EXPLANATION}}
|
|
4394
|
-
</details>
|
|
4395
|
-
|
|
4396
|
-
---
|
|
4397
|
-
|
|
4398
|
-
## \u{1F50D} Self-Learner Troubleshooting Matrix
|
|
4399
|
-
| Symptom / Error Message | Root Cause | Exact Fix |
|
|
4400
|
-
| :--- | :--- | :--- |
|
|
4401
|
-
{{TROUBLESHOOTING_ROWS}}
|
|
4402
|
-
|
|
4403
|
-
---
|
|
4404
|
-
|
|
4405
|
-
## \u{1F3C1} Final Lab Submission & Mastery Checklist
|
|
4406
|
-
{{FINAL_CHECKLIST}}
|
|
4407
|
-
`.trim();
|
|
3947
|
+
function stripTemplateFrontmatter(raw) {
|
|
3948
|
+
let body = raw;
|
|
3949
|
+
if (body.startsWith("---")) {
|
|
3950
|
+
const end = body.indexOf("\n---", 3);
|
|
3951
|
+
if (end !== -1) body = body.slice(end + 4);
|
|
3952
|
+
}
|
|
3953
|
+
return body.split("\n").filter((l) => l.trim() !== "<!-- INJECT_BODY -->").join("\n").replace(/^\s*\n/, "").trimEnd();
|
|
3954
|
+
}
|
|
3955
|
+
function extractRequiredSections(raw) {
|
|
3956
|
+
const lines = raw.split("\n");
|
|
3957
|
+
const start = lines.findIndex((l) => /^template_required_sections:\s*$/.test(l.trim()));
|
|
3958
|
+
if (start === -1) return null;
|
|
3959
|
+
const items = [];
|
|
3960
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
3961
|
+
const line = lines[i] ?? "";
|
|
3962
|
+
if (line.trim() === "") continue;
|
|
3963
|
+
if (!/^\s+-\s/.test(line)) break;
|
|
3964
|
+
items.push(line.trim().replace(/^-\s+/, "").replace(/^["']|["']$/g, ""));
|
|
3965
|
+
}
|
|
3966
|
+
return items.length > 0 ? items : null;
|
|
3967
|
+
}
|
|
3968
|
+
function normalizeHeading(h) {
|
|
3969
|
+
return h.replace(/\[(REQUIRED|OPTIONAL|CONDITIONAL)\]\s*/gi, "").replace(/\s+/g, " ").trim();
|
|
3970
|
+
}
|
|
3971
|
+
function extractBodySections(raw) {
|
|
3972
|
+
const body = stripTemplateFrontmatter(raw);
|
|
3973
|
+
return body.split("\n").filter((l) => l.startsWith("## ")).map((l) => normalizeHeading(l.slice(3).trim())).filter((s) => s.length > 0);
|
|
3974
|
+
}
|
|
3975
|
+
var KIT_TEMPLATE_FALLBACK_DIRS = [
|
|
3976
|
+
// Packaged with the npm bundle (dist/templates) — resolves from node_modules.
|
|
3977
|
+
"templates",
|
|
3978
|
+
// Repo checkout layouts.
|
|
3979
|
+
"docs/refs/templates"
|
|
3980
|
+
];
|
|
3981
|
+
var _moduleDir = (() => {
|
|
3982
|
+
try {
|
|
3983
|
+
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }) !== "undefined" && typeof (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) === "string") {
|
|
3984
|
+
return path4__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
3985
|
+
}
|
|
3986
|
+
} catch {
|
|
3987
|
+
}
|
|
3988
|
+
return typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
3989
|
+
})();
|
|
3990
|
+
function candidateDirs(explicitDir) {
|
|
3991
|
+
const dirs = [];
|
|
3992
|
+
if (explicitDir) dirs.push(explicitDir);
|
|
3993
|
+
if (process.env.CURRICULUM_TEMPLATES_DIR) dirs.push(process.env.CURRICULUM_TEMPLATES_DIR);
|
|
3994
|
+
dirs.push(path4__default.default.resolve(process.cwd(), "_templates"));
|
|
3995
|
+
for (const rel of KIT_TEMPLATE_FALLBACK_DIRS) {
|
|
3996
|
+
dirs.push(path4__default.default.resolve(_moduleDir, rel));
|
|
3997
|
+
dirs.push(path4__default.default.resolve(process.cwd(), rel));
|
|
3998
|
+
dirs.push(path4__default.default.resolve(process.cwd(), "packages/curriculum-kit", rel));
|
|
3999
|
+
}
|
|
4000
|
+
return dirs;
|
|
4001
|
+
}
|
|
4002
|
+
function findTemplatePath(templateName, explicitDir) {
|
|
4003
|
+
for (const dir of candidateDirs(explicitDir)) {
|
|
4004
|
+
const p = path4__default.default.join(dir, templateName);
|
|
4005
|
+
if (!fs3__default.default.existsSync(p)) continue;
|
|
4006
|
+
try {
|
|
4007
|
+
fs3__default.default.accessSync(p, fs3__default.default.constants.R_OK);
|
|
4008
|
+
return p;
|
|
4009
|
+
} catch {
|
|
4010
|
+
}
|
|
4011
|
+
}
|
|
4012
|
+
return null;
|
|
4013
|
+
}
|
|
4014
|
+
function resolveArtifactTemplate(templateName, opts) {
|
|
4015
|
+
const p = findTemplatePath(templateName, opts?.templatesDir);
|
|
4016
|
+
if (!p) return null;
|
|
4017
|
+
try {
|
|
4018
|
+
const raw = fs3__default.default.readFileSync(p, "utf-8");
|
|
4019
|
+
return {
|
|
4020
|
+
content: stripTemplateFrontmatter(raw),
|
|
4021
|
+
sections: extractRequiredSections(raw) ?? extractBodySections(raw),
|
|
4022
|
+
sourcePath: p
|
|
4023
|
+
};
|
|
4024
|
+
} catch {
|
|
4025
|
+
return null;
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
function loadCurriculumTemplate(templateName, templatesDir) {
|
|
4029
|
+
const p = findTemplatePath(templateName, templatesDir);
|
|
4030
|
+
if (!p) return "";
|
|
4031
|
+
try {
|
|
4032
|
+
return fs3__default.default.readFileSync(p, "utf-8");
|
|
4033
|
+
} catch {
|
|
4034
|
+
return "";
|
|
4035
|
+
}
|
|
4036
|
+
}
|
|
4037
|
+
function loadAuthoringTemplate(templateName, templatesDir) {
|
|
4038
|
+
const p = findTemplatePath(templateName, templatesDir);
|
|
4039
|
+
if (!p) return "";
|
|
4040
|
+
try {
|
|
4041
|
+
return stripTemplateFrontmatter(fs3__default.default.readFileSync(p, "utf-8"));
|
|
4042
|
+
} catch {
|
|
4043
|
+
return "";
|
|
4044
|
+
}
|
|
4045
|
+
}
|
|
4408
4046
|
|
|
4409
4047
|
// src/ai/prompts/lessonMasterPrompt.ts
|
|
4410
4048
|
function buildLessonMasterPrompt(input) {
|
|
@@ -4458,7 +4096,7 @@ Build a deep, rigorous, and highly pedagogical Master Lesson Plan (LESSON) that
|
|
|
4458
4096
|
# MANDATORY TEMPLATE STRUCTURE
|
|
4459
4097
|
You MUST generate structured data that will render directly into this exact Markdown template:
|
|
4460
4098
|
---
|
|
4461
|
-
${
|
|
4099
|
+
${loadAuthoringTemplate("LESSON_5E_template.md") ?? "[TEMPLATE FILE NOT FOUND: LESSON_5E_template.md]"}
|
|
4462
4100
|
---
|
|
4463
4101
|
|
|
4464
4102
|
# INPUT PARAMETERS
|
|
@@ -4536,7 +4174,7 @@ Transform the exact pedagogical flow and activities from the Master Lesson Plan
|
|
|
4536
4174
|
# MANDATORY TEMPLATE STRUCTURE
|
|
4537
4175
|
You MUST generate data aligned with this Markdown template:
|
|
4538
4176
|
---
|
|
4539
|
-
${
|
|
4177
|
+
${loadAuthoringTemplate("ACT_template.md") ?? "[TEMPLATE FILE NOT FOUND: ACT_template.md]"}
|
|
4540
4178
|
---
|
|
4541
4179
|
|
|
4542
4180
|
# CANONICAL MASTER LESSON CONTEXT (SOURCE OF TRUTH)
|
|
@@ -4631,7 +4269,7 @@ Generate complete, verified source code that satisfies the lesson objectives and
|
|
|
4631
4269
|
# MANDATORY TEMPLATE STRUCTURE
|
|
4632
4270
|
You MUST generate data aligned with this Markdown template:
|
|
4633
4271
|
---
|
|
4634
|
-
${
|
|
4272
|
+
${loadAuthoringTemplate("LAB_TEMPLATE.md") ?? "[TEMPLATE FILE NOT FOUND: LAB_TEMPLATE.md]"}
|
|
4635
4273
|
---
|
|
4636
4274
|
|
|
4637
4275
|
# CANONICAL LESSON CONTEXT (SOURCE OF TRUTH)
|
|
@@ -5326,7 +4964,7 @@ Build a complete, engaging Self-Paced Hands-On Lab (SELF_LAB) for autonomous lea
|
|
|
5326
4964
|
# MANDATORY TEMPLATE STRUCTURE
|
|
5327
4965
|
You MUST generate data aligned with this Markdown template:
|
|
5328
4966
|
---
|
|
5329
|
-
${
|
|
4967
|
+
${loadAuthoringTemplate("SELF_LAB_template.md") ?? "[TEMPLATE FILE NOT FOUND: SELF_LAB_template.md]"}
|
|
5330
4968
|
---
|
|
5331
4969
|
|
|
5332
4970
|
# INPUT PARAMETERS
|
|
@@ -5463,7 +5101,7 @@ Use this mapping to determine which Bloom level each question truly targets. Mat
|
|
|
5463
5101
|
# MANDATORY TEMPLATE STRUCTURE
|
|
5464
5102
|
You MUST generate data aligned with this Markdown template:
|
|
5465
5103
|
---
|
|
5466
|
-
${
|
|
5104
|
+
${loadAuthoringTemplate("QUIZ_v4.6_template.md") ?? "[TEMPLATE FILE NOT FOUND: QUIZ_v4.6_template.md]"}
|
|
5467
5105
|
---
|
|
5468
5106
|
|
|
5469
5107
|
# INPUT PARAMETERS
|
|
@@ -7760,13 +7398,13 @@ async function generateSelfPacedBundle(input) {
|
|
|
7760
7398
|
if (input.outputDirectory) {
|
|
7761
7399
|
await fsPromises__default.default.mkdir(input.outputDirectory, { recursive: true });
|
|
7762
7400
|
await Promise.all([
|
|
7763
|
-
fsPromises__default.default.writeFile(
|
|
7764
|
-
fsPromises__default.default.writeFile(
|
|
7765
|
-
fsPromises__default.default.writeFile(
|
|
7766
|
-
fsPromises__default.default.writeFile(
|
|
7767
|
-
fsPromises__default.default.writeFile(
|
|
7768
|
-
fsPromises__default.default.writeFile(
|
|
7769
|
-
fsPromises__default.default.writeFile(
|
|
7401
|
+
fsPromises__default.default.writeFile(path4__default.default.join(input.outputDirectory, "INSTRUCTION.md"), instructionMd, "utf-8"),
|
|
7402
|
+
fsPromises__default.default.writeFile(path4__default.default.join(input.outputDirectory, "SELF_LAB.md"), selfLabMd, "utf-8"),
|
|
7403
|
+
fsPromises__default.default.writeFile(path4__default.default.join(input.outputDirectory, "QUIZ.md"), quizMd, "utf-8"),
|
|
7404
|
+
fsPromises__default.default.writeFile(path4__default.default.join(input.outputDirectory, "QUIZ.json"), JSON.stringify(quiz, null, 2), "utf-8"),
|
|
7405
|
+
fsPromises__default.default.writeFile(path4__default.default.join(input.outputDirectory, "CHEAT_SHEET.md"), cheatSheetMd, "utf-8"),
|
|
7406
|
+
fsPromises__default.default.writeFile(path4__default.default.join(input.outputDirectory, "LAB.md"), codeLabMd, "utf-8"),
|
|
7407
|
+
fsPromises__default.default.writeFile(path4__default.default.join(input.outputDirectory, "bundle.json"), JSON.stringify(bundle, null, 2), "utf-8")
|
|
7770
7408
|
]);
|
|
7771
7409
|
}
|
|
7772
7410
|
return {
|
|
@@ -8167,15 +7805,15 @@ var STANDARD_SOT_FILES = [
|
|
|
8167
7805
|
"ALIGNMENT_MATRIX.md"
|
|
8168
7806
|
];
|
|
8169
7807
|
function atomicWriteFileSync(targetPath, content) {
|
|
8170
|
-
const dir =
|
|
8171
|
-
if (!
|
|
8172
|
-
const tmpPath =
|
|
7808
|
+
const dir = path4__default.default.dirname(targetPath);
|
|
7809
|
+
if (!fs3__default.default.existsSync(dir)) fs3__default.default.mkdirSync(dir, { recursive: true });
|
|
7810
|
+
const tmpPath = path4__default.default.join(dir, `.${path4__default.default.basename(targetPath)}.${process.pid}.${Date.now()}.${crypto__default.default.randomBytes(4).toString("hex")}.tmp`);
|
|
8173
7811
|
try {
|
|
8174
|
-
|
|
8175
|
-
|
|
7812
|
+
fs3__default.default.writeFileSync(tmpPath, content, "utf-8");
|
|
7813
|
+
fs3__default.default.renameSync(tmpPath, targetPath);
|
|
8176
7814
|
} catch (err) {
|
|
8177
7815
|
try {
|
|
8178
|
-
if (
|
|
7816
|
+
if (fs3__default.default.existsSync(tmpPath)) fs3__default.default.unlinkSync(tmpPath);
|
|
8179
7817
|
} catch {
|
|
8180
7818
|
}
|
|
8181
7819
|
throw err;
|
|
@@ -8184,51 +7822,51 @@ function atomicWriteFileSync(targetPath, content) {
|
|
|
8184
7822
|
var FileSystemCurriculumAdapter = class {
|
|
8185
7823
|
baseDir;
|
|
8186
7824
|
constructor(options = {}) {
|
|
8187
|
-
this.baseDir = options.baseDir ||
|
|
7825
|
+
this.baseDir = options.baseDir || path4__default.default.resolve(process.cwd(), "output", "projects");
|
|
8188
7826
|
}
|
|
8189
7827
|
getProjectDir(projectId) {
|
|
8190
7828
|
const raw = (projectId || "").replace("proj_", "");
|
|
8191
|
-
const directPath =
|
|
8192
|
-
if (
|
|
8193
|
-
const fullIdPath =
|
|
8194
|
-
if (
|
|
7829
|
+
const directPath = path4__default.default.join(this.baseDir, raw);
|
|
7830
|
+
if (fs3__default.default.existsSync(directPath)) return directPath;
|
|
7831
|
+
const fullIdPath = path4__default.default.join(this.baseDir, projectId);
|
|
7832
|
+
if (fs3__default.default.existsSync(fullIdPath)) return fullIdPath;
|
|
8195
7833
|
return directPath;
|
|
8196
7834
|
}
|
|
8197
7835
|
/** Ensures the resolved path stays within the project directory (prevents path traversal). */
|
|
8198
7836
|
assertInsideProject(projectDir, targetPath) {
|
|
8199
|
-
const resolvedProject =
|
|
8200
|
-
const resolvedTarget =
|
|
8201
|
-
if (!resolvedTarget.startsWith(resolvedProject +
|
|
7837
|
+
const resolvedProject = path4__default.default.resolve(projectDir);
|
|
7838
|
+
const resolvedTarget = path4__default.default.resolve(targetPath);
|
|
7839
|
+
if (!resolvedTarget.startsWith(resolvedProject + path4__default.default.sep) && resolvedTarget !== resolvedProject) {
|
|
8202
7840
|
throw new Error(`[FileSystemCurriculumAdapter] Path traversal blocked: ${targetPath} is outside project directory ${projectDir}`);
|
|
8203
7841
|
}
|
|
8204
7842
|
}
|
|
8205
7843
|
async projectExists(projectId) {
|
|
8206
|
-
return
|
|
7844
|
+
return fs3__default.default.existsSync(this.getProjectDir(projectId));
|
|
8207
7845
|
}
|
|
8208
7846
|
async readSotDocument(projectId, filename) {
|
|
8209
7847
|
const projectDir = this.getProjectDir(projectId);
|
|
8210
7848
|
const possiblePaths = [
|
|
8211
|
-
|
|
8212
|
-
|
|
7849
|
+
path4__default.default.join(projectDir, "_sot", filename),
|
|
7850
|
+
path4__default.default.join(projectDir, filename)
|
|
8213
7851
|
];
|
|
8214
7852
|
for (const p of possiblePaths) {
|
|
8215
|
-
if (
|
|
8216
|
-
return
|
|
7853
|
+
if (fs3__default.default.existsSync(p) && fs3__default.default.statSync(p).isFile()) {
|
|
7854
|
+
return fs3__default.default.readFileSync(p, "utf-8");
|
|
8217
7855
|
}
|
|
8218
7856
|
}
|
|
8219
7857
|
return null;
|
|
8220
7858
|
}
|
|
8221
7859
|
async listSotDocuments(projectId) {
|
|
8222
7860
|
const projectDir = this.getProjectDir(projectId);
|
|
8223
|
-
const sotDir =
|
|
7861
|
+
const sotDir = path4__default.default.join(projectDir, "_sot");
|
|
8224
7862
|
const discoveredFiles = new Set(STANDARD_SOT_FILES);
|
|
8225
|
-
if (
|
|
7863
|
+
if (fs3__default.default.existsSync(sotDir)) {
|
|
8226
7864
|
try {
|
|
8227
|
-
const diskFiles =
|
|
7865
|
+
const diskFiles = fs3__default.default.readdirSync(sotDir);
|
|
8228
7866
|
for (const f of diskFiles) {
|
|
8229
7867
|
if (f.startsWith(".") || f.endsWith(".review.json")) continue;
|
|
8230
|
-
const fullPath =
|
|
8231
|
-
if (
|
|
7868
|
+
const fullPath = path4__default.default.join(sotDir, f);
|
|
7869
|
+
if (fs3__default.default.statSync(fullPath).isFile()) {
|
|
8232
7870
|
discoveredFiles.add(f);
|
|
8233
7871
|
}
|
|
8234
7872
|
}
|
|
@@ -8236,9 +7874,9 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8236
7874
|
}
|
|
8237
7875
|
}
|
|
8238
7876
|
return Array.from(discoveredFiles).map((filename) => {
|
|
8239
|
-
const p =
|
|
8240
|
-
if (p &&
|
|
8241
|
-
const stats =
|
|
7877
|
+
const p = fs3__default.default.existsSync(path4__default.default.join(sotDir, filename)) ? path4__default.default.join(sotDir, filename) : fs3__default.default.existsSync(path4__default.default.join(projectDir, filename)) ? path4__default.default.join(projectDir, filename) : null;
|
|
7878
|
+
if (p && fs3__default.default.existsSync(p)) {
|
|
7879
|
+
const stats = fs3__default.default.statSync(p);
|
|
8242
7880
|
return {
|
|
8243
7881
|
name: filename.replace(/\.(md|json)$/i, "").replace(/_/g, " "),
|
|
8244
7882
|
filename,
|
|
@@ -8256,18 +7894,18 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8256
7894
|
}
|
|
8257
7895
|
async readArtifact(projectId, relPathOrIdentifier) {
|
|
8258
7896
|
const projectDir = this.getProjectDir(projectId);
|
|
8259
|
-
const directCandidate =
|
|
7897
|
+
const directCandidate = path4__default.default.join(projectDir, relPathOrIdentifier);
|
|
8260
7898
|
this.assertInsideProject(projectDir, directCandidate);
|
|
8261
7899
|
const possiblePaths = [
|
|
8262
7900
|
directCandidate,
|
|
8263
|
-
|
|
8264
|
-
|
|
8265
|
-
|
|
8266
|
-
|
|
7901
|
+
path4__default.default.join(projectDir, "_sot", relPathOrIdentifier),
|
|
7902
|
+
path4__default.default.join(projectDir, "lessons", relPathOrIdentifier),
|
|
7903
|
+
path4__default.default.join(projectDir, "_sot", path4__default.default.basename(relPathOrIdentifier)),
|
|
7904
|
+
path4__default.default.join(projectDir, "lessons", path4__default.default.basename(relPathOrIdentifier))
|
|
8267
7905
|
];
|
|
8268
7906
|
for (const p of possiblePaths) {
|
|
8269
|
-
if (
|
|
8270
|
-
return
|
|
7907
|
+
if (fs3__default.default.existsSync(p) && fs3__default.default.statSync(p).isFile()) {
|
|
7908
|
+
return fs3__default.default.readFileSync(p, "utf-8");
|
|
8271
7909
|
}
|
|
8272
7910
|
}
|
|
8273
7911
|
if (relPathOrIdentifier.includes(".md") || relPathOrIdentifier.includes("/")) {
|
|
@@ -8276,8 +7914,8 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8276
7914
|
const lessonMatch = relPathOrIdentifier.match(/U\d+_M\d+_L\d+/i);
|
|
8277
7915
|
if (lessonMatch) {
|
|
8278
7916
|
const lessonId = lessonMatch[0].toUpperCase();
|
|
8279
|
-
const lessonDir =
|
|
8280
|
-
if (
|
|
7917
|
+
const lessonDir = path4__default.default.join(projectDir, "lessons", lessonId);
|
|
7918
|
+
if (fs3__default.default.existsSync(lessonDir) && fs3__default.default.statSync(lessonDir).isDirectory()) {
|
|
8281
7919
|
const lower = relPathOrIdentifier.toLowerCase();
|
|
8282
7920
|
let artifactPrefix = "LESSON";
|
|
8283
7921
|
if (lower.includes("act") || lower.includes("lab") || lower.includes("th\u1EF1c h\xE0nh")) {
|
|
@@ -8297,9 +7935,9 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8297
7935
|
} else if (lower.includes("ext") || lower.includes("extension")) {
|
|
8298
7936
|
artifactPrefix = "EXT";
|
|
8299
7937
|
}
|
|
8300
|
-
const candidateFile =
|
|
8301
|
-
if (
|
|
8302
|
-
return
|
|
7938
|
+
const candidateFile = path4__default.default.join(lessonDir, `${artifactPrefix}_${lessonId}.md`);
|
|
7939
|
+
if (fs3__default.default.existsSync(candidateFile)) {
|
|
7940
|
+
return fs3__default.default.readFileSync(candidateFile, "utf-8");
|
|
8303
7941
|
}
|
|
8304
7942
|
}
|
|
8305
7943
|
}
|
|
@@ -8307,22 +7945,22 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8307
7945
|
}
|
|
8308
7946
|
async saveArtifact(projectId, relPath, content) {
|
|
8309
7947
|
const projectDir = this.getProjectDir(projectId);
|
|
8310
|
-
const targetPath =
|
|
7948
|
+
const targetPath = path4__default.default.join(projectDir, relPath);
|
|
8311
7949
|
this.assertInsideProject(projectDir, targetPath);
|
|
8312
|
-
const targetDir =
|
|
8313
|
-
if (!
|
|
8314
|
-
|
|
7950
|
+
const targetDir = path4__default.default.dirname(targetPath);
|
|
7951
|
+
if (!fs3__default.default.existsSync(targetDir)) {
|
|
7952
|
+
fs3__default.default.mkdirSync(targetDir, { recursive: true });
|
|
8315
7953
|
}
|
|
8316
|
-
if (
|
|
7954
|
+
if (fs3__default.default.existsSync(targetPath)) {
|
|
8317
7955
|
try {
|
|
8318
|
-
const oldContent =
|
|
7956
|
+
const oldContent = fs3__default.default.readFileSync(targetPath, "utf-8");
|
|
8319
7957
|
if (oldContent !== content) {
|
|
8320
|
-
const historyDir =
|
|
8321
|
-
|
|
8322
|
-
atomicWriteFileSync(
|
|
8323
|
-
const versions =
|
|
7958
|
+
const historyDir = path4__default.default.join(projectDir, ".history", relPath);
|
|
7959
|
+
fs3__default.default.mkdirSync(historyDir, { recursive: true });
|
|
7960
|
+
atomicWriteFileSync(path4__default.default.join(historyDir, `${Date.now()}.md`), oldContent);
|
|
7961
|
+
const versions = fs3__default.default.readdirSync(historyDir).filter((f) => f.endsWith(".md")).sort();
|
|
8324
7962
|
while (versions.length > 10) {
|
|
8325
|
-
|
|
7963
|
+
fs3__default.default.unlinkSync(path4__default.default.join(historyDir, versions.shift()));
|
|
8326
7964
|
}
|
|
8327
7965
|
}
|
|
8328
7966
|
} catch (histErr) {
|
|
@@ -8330,24 +7968,24 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8330
7968
|
}
|
|
8331
7969
|
}
|
|
8332
7970
|
atomicWriteFileSync(targetPath, content);
|
|
8333
|
-
const filename =
|
|
7971
|
+
const filename = path4__default.default.basename(relPath);
|
|
8334
7972
|
const match = filename.match(/(LESSON|ACT|QUIZ|SLIDE|GUIDE|HANDOUT|WKS|EXT)_(U\d+_M\d+_L\d+)\.md/i);
|
|
8335
7973
|
if (match) {
|
|
8336
7974
|
const lessonId = match[2].toUpperCase();
|
|
8337
|
-
atomicWriteFileSync(
|
|
8338
|
-
const legacyContentDir =
|
|
8339
|
-
if (
|
|
8340
|
-
atomicWriteFileSync(
|
|
7975
|
+
atomicWriteFileSync(path4__default.default.join(projectDir, "lessons", lessonId, filename), content);
|
|
7976
|
+
const legacyContentDir = path4__default.default.join(projectDir, "_content", lessonId);
|
|
7977
|
+
if (fs3__default.default.existsSync(legacyContentDir)) {
|
|
7978
|
+
atomicWriteFileSync(path4__default.default.join(legacyContentDir, filename), content);
|
|
8341
7979
|
}
|
|
8342
7980
|
}
|
|
8343
7981
|
}
|
|
8344
7982
|
async listLessons(projectId) {
|
|
8345
|
-
const lessonsDir =
|
|
8346
|
-
if (!
|
|
8347
|
-
const lessonFolders =
|
|
7983
|
+
const lessonsDir = path4__default.default.join(this.getProjectDir(projectId), "lessons");
|
|
7984
|
+
if (!fs3__default.default.existsSync(lessonsDir)) return [];
|
|
7985
|
+
const lessonFolders = fs3__default.default.readdirSync(lessonsDir).filter((f) => !f.startsWith("."));
|
|
8348
7986
|
return lessonFolders.map((folder) => {
|
|
8349
|
-
const lDir =
|
|
8350
|
-
const isDir =
|
|
7987
|
+
const lDir = path4__default.default.join(lessonsDir, folder);
|
|
7988
|
+
const isDir = fs3__default.default.statSync(lDir).isDirectory();
|
|
8351
7989
|
if (!isDir) {
|
|
8352
7990
|
return {
|
|
8353
7991
|
lessonId: folder,
|
|
@@ -8356,7 +7994,7 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8356
7994
|
artifacts: []
|
|
8357
7995
|
};
|
|
8358
7996
|
}
|
|
8359
|
-
const artifacts =
|
|
7997
|
+
const artifacts = fs3__default.default.readdirSync(lDir).filter((f) => !f.startsWith("."));
|
|
8360
7998
|
return {
|
|
8361
7999
|
lessonId: folder,
|
|
8362
8000
|
artifactsCount: artifacts.length,
|
|
@@ -8402,10 +8040,10 @@ ${lessonTable}
|
|
|
8402
8040
|
}
|
|
8403
8041
|
async getPipelineState(projectId) {
|
|
8404
8042
|
const projectDir = this.getProjectDir(projectId);
|
|
8405
|
-
const stateFile =
|
|
8406
|
-
if (
|
|
8043
|
+
const stateFile = path4__default.default.join(projectDir, "_pipeline", "state.json");
|
|
8044
|
+
if (fs3__default.default.existsSync(stateFile)) {
|
|
8407
8045
|
try {
|
|
8408
|
-
const raw =
|
|
8046
|
+
const raw = fs3__default.default.readFileSync(stateFile, "utf-8");
|
|
8409
8047
|
const parsed = JSON.parse(raw);
|
|
8410
8048
|
if (parsed && typeof parsed === "object" && parsed.tasks) {
|
|
8411
8049
|
return parsed;
|
|
@@ -8422,11 +8060,11 @@ ${lessonTable}
|
|
|
8422
8060
|
}
|
|
8423
8061
|
async savePipelineState(projectId, state) {
|
|
8424
8062
|
const projectDir = this.getProjectDir(projectId);
|
|
8425
|
-
const pipelineDir =
|
|
8426
|
-
if (!
|
|
8427
|
-
|
|
8063
|
+
const pipelineDir = path4__default.default.join(projectDir, "_pipeline");
|
|
8064
|
+
if (!fs3__default.default.existsSync(pipelineDir)) {
|
|
8065
|
+
fs3__default.default.mkdirSync(pipelineDir, { recursive: true });
|
|
8428
8066
|
}
|
|
8429
|
-
const stateFile =
|
|
8067
|
+
const stateFile = path4__default.default.join(pipelineDir, "state.json");
|
|
8430
8068
|
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8431
8069
|
atomicWriteFileSync(stateFile, JSON.stringify(state, null, 2));
|
|
8432
8070
|
}
|
|
@@ -8449,9 +8087,9 @@ ${lessonTable}
|
|
|
8449
8087
|
async deleteArtifact(projectId, relPath) {
|
|
8450
8088
|
try {
|
|
8451
8089
|
const projectDir = this.getProjectDir(projectId);
|
|
8452
|
-
const targetPath =
|
|
8090
|
+
const targetPath = path4__default.default.join(projectDir, relPath);
|
|
8453
8091
|
this.assertInsideProject(projectDir, targetPath);
|
|
8454
|
-
if (
|
|
8092
|
+
if (fs3__default.default.existsSync(targetPath)) fs3__default.default.rmSync(targetPath, { force: true });
|
|
8455
8093
|
} catch {
|
|
8456
8094
|
}
|
|
8457
8095
|
}
|
|
@@ -9201,19 +8839,19 @@ function buildStandardStackMarkdown(opts) {
|
|
|
9201
8839
|
|
|
9202
8840
|
// src/services/sotGeneratorService.ts
|
|
9203
8841
|
var __filename$1 = typeof (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) === "string" && typeof url.fileURLToPath === "function" ? url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))) : "";
|
|
9204
|
-
var __dirname2 = __filename$1 ?
|
|
8842
|
+
var __dirname2 = __filename$1 ? path4__default.default.dirname(__filename$1) : process.cwd();
|
|
9205
8843
|
function loadSotTemplate(templateFileName) {
|
|
9206
8844
|
const possiblePaths = [
|
|
9207
|
-
|
|
9208
|
-
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
8845
|
+
path4__default.default.resolve(__dirname2, "../../docs/refs/templates", templateFileName),
|
|
8846
|
+
path4__default.default.resolve(process.cwd(), "packages/curriculum-kit/docs/refs/templates", templateFileName),
|
|
8847
|
+
path4__default.default.resolve(process.cwd(), "../learnwell-platform/packages/curriculum-kit/docs/refs/templates", templateFileName),
|
|
8848
|
+
path4__default.default.resolve("/Users/tonypham/MEGA/WebApp/WIP/learnwell-platform/packages/curriculum-kit/docs/refs/templates", templateFileName),
|
|
8849
|
+
path4__default.default.resolve("/Users/tonypham/MEGA/ai-platform/learning-artifact-gen-ui/_templates", templateFileName)
|
|
9212
8850
|
];
|
|
9213
8851
|
for (const p of possiblePaths) {
|
|
9214
|
-
if (
|
|
8852
|
+
if (fs3__default.default.existsSync(p)) {
|
|
9215
8853
|
try {
|
|
9216
|
-
return
|
|
8854
|
+
return fs3__default.default.readFileSync(p, "utf-8");
|
|
9217
8855
|
} catch {
|
|
9218
8856
|
}
|
|
9219
8857
|
}
|
|
@@ -10228,7 +9866,7 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
|
|
|
10228
9866
|
if (s.canonicalKey && !byCanonical.has(s.canonicalKey)) {
|
|
10229
9867
|
byCanonical.set(s.canonicalKey, s);
|
|
10230
9868
|
}
|
|
10231
|
-
const norm2 =
|
|
9869
|
+
const norm2 = normalizeHeading2(s.cleanTitle);
|
|
10232
9870
|
if (!byCleanTitle.has(norm2)) {
|
|
10233
9871
|
byCleanTitle.set(norm2, s);
|
|
10234
9872
|
}
|
|
@@ -10278,7 +9916,7 @@ ${truncated}`;
|
|
|
10278
9916
|
blocks.push(metaBlock);
|
|
10279
9917
|
let sectionAware = false;
|
|
10280
9918
|
for (const key of priorities) {
|
|
10281
|
-
const sec = byCanonical.get(key) || byCleanTitle.get(
|
|
9919
|
+
const sec = byCanonical.get(key) || byCleanTitle.get(normalizeHeading2(key));
|
|
10282
9920
|
if (!sec) continue;
|
|
10283
9921
|
sectionAware = true;
|
|
10284
9922
|
if (!tryAdd(sec.cleanTitle, sec.body, key)) break;
|
|
@@ -10360,15 +9998,15 @@ function parseMarkdownSections(markdown, slcMap, artifactType) {
|
|
|
10360
9998
|
const maps = artifactType && slcMap[artifactType] ? [slcMap[artifactType]] : Object.values(slcMap);
|
|
10361
9999
|
for (const m of maps) {
|
|
10362
10000
|
for (const [canonical, localized] of Object.entries(m)) {
|
|
10363
|
-
reverseMap.set(
|
|
10364
|
-
reverseMap.set(
|
|
10001
|
+
reverseMap.set(normalizeHeading2(localized), canonical);
|
|
10002
|
+
reverseMap.set(normalizeHeading2(canonical), canonical);
|
|
10365
10003
|
}
|
|
10366
10004
|
}
|
|
10367
10005
|
}
|
|
10368
10006
|
const flush = () => {
|
|
10369
10007
|
if (!currentHeading) return;
|
|
10370
10008
|
const cleanTitle = currentHeading.replace(/^#{1,4}\s+/, "").trim();
|
|
10371
|
-
const norm2 =
|
|
10009
|
+
const norm2 = normalizeHeading2(cleanTitle);
|
|
10372
10010
|
const canonicalKey = reverseMap.get(norm2) || findCanonicalFuzzy(norm2);
|
|
10373
10011
|
sections.push({
|
|
10374
10012
|
rawHeading: currentHeading,
|
|
@@ -10392,7 +10030,7 @@ function parseMarkdownSections(markdown, slcMap, artifactType) {
|
|
|
10392
10030
|
flush();
|
|
10393
10031
|
return sections;
|
|
10394
10032
|
}
|
|
10395
|
-
function
|
|
10033
|
+
function normalizeHeading2(str) {
|
|
10396
10034
|
return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
10397
10035
|
}
|
|
10398
10036
|
function findCanonicalFuzzy(norm2) {
|
|
@@ -25461,96 +25099,6 @@ function evaluateActivityAlignment(canonicalExcerpt, generatedContent, now = /*
|
|
|
25461
25099
|
const passed = matchedTokens.length > 0;
|
|
25462
25100
|
return { checked: true, passed, matchedTokens: matchedTokens.slice(0, 10), missingTokens: missingTokens.slice(0, 10), mode };
|
|
25463
25101
|
}
|
|
25464
|
-
function stripTemplateFrontmatter(raw) {
|
|
25465
|
-
let body = raw;
|
|
25466
|
-
if (body.startsWith("---")) {
|
|
25467
|
-
const end = body.indexOf("\n---", 3);
|
|
25468
|
-
if (end !== -1) body = body.slice(end + 4);
|
|
25469
|
-
}
|
|
25470
|
-
return body.split("\n").filter((l) => l.trim() !== "<!-- INJECT_BODY -->").join("\n").replace(/^\s*\n/, "").trimEnd();
|
|
25471
|
-
}
|
|
25472
|
-
function extractRequiredSections(raw) {
|
|
25473
|
-
const lines = raw.split("\n");
|
|
25474
|
-
const start = lines.findIndex((l) => /^template_required_sections:\s*$/.test(l.trim()));
|
|
25475
|
-
if (start === -1) return null;
|
|
25476
|
-
const items = [];
|
|
25477
|
-
for (let i = start + 1; i < lines.length; i++) {
|
|
25478
|
-
const line = lines[i] ?? "";
|
|
25479
|
-
if (line.trim() === "") continue;
|
|
25480
|
-
if (!/^\s+-\s/.test(line)) break;
|
|
25481
|
-
items.push(line.trim().replace(/^-\s+/, "").replace(/^["']|["']$/g, ""));
|
|
25482
|
-
}
|
|
25483
|
-
return items.length > 0 ? items : null;
|
|
25484
|
-
}
|
|
25485
|
-
function normalizeHeading2(h) {
|
|
25486
|
-
return h.replace(/\[(REQUIRED|OPTIONAL|CONDITIONAL)\]\s*/gi, "").replace(/\s+/g, " ").trim();
|
|
25487
|
-
}
|
|
25488
|
-
function extractBodySections(raw) {
|
|
25489
|
-
const body = stripTemplateFrontmatter(raw);
|
|
25490
|
-
return body.split("\n").filter((l) => l.startsWith("## ")).map((l) => normalizeHeading2(l.slice(3).trim())).filter((s) => s.length > 0);
|
|
25491
|
-
}
|
|
25492
|
-
var KIT_TEMPLATE_FALLBACK_DIRS = [
|
|
25493
|
-
// Packaged with the npm bundle (dist/templates) — resolves from node_modules.
|
|
25494
|
-
"templates",
|
|
25495
|
-
// Repo checkout layouts.
|
|
25496
|
-
"docs/refs/templates"
|
|
25497
|
-
];
|
|
25498
|
-
var _moduleDir = (() => {
|
|
25499
|
-
try {
|
|
25500
|
-
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }) !== "undefined" && typeof (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) === "string") {
|
|
25501
|
-
return path3__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
25502
|
-
}
|
|
25503
|
-
} catch {
|
|
25504
|
-
}
|
|
25505
|
-
return typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
25506
|
-
})();
|
|
25507
|
-
function candidateDirs(explicitDir) {
|
|
25508
|
-
const dirs = [];
|
|
25509
|
-
if (explicitDir) dirs.push(explicitDir);
|
|
25510
|
-
if (process.env.CURRICULUM_TEMPLATES_DIR) dirs.push(process.env.CURRICULUM_TEMPLATES_DIR);
|
|
25511
|
-
dirs.push(path3__default.default.resolve(process.cwd(), "_templates"));
|
|
25512
|
-
for (const rel of KIT_TEMPLATE_FALLBACK_DIRS) {
|
|
25513
|
-
dirs.push(path3__default.default.resolve(_moduleDir, rel));
|
|
25514
|
-
dirs.push(path3__default.default.resolve(process.cwd(), rel));
|
|
25515
|
-
dirs.push(path3__default.default.resolve(process.cwd(), "packages/curriculum-kit", rel));
|
|
25516
|
-
}
|
|
25517
|
-
return dirs;
|
|
25518
|
-
}
|
|
25519
|
-
function findTemplatePath(templateName, explicitDir) {
|
|
25520
|
-
for (const dir of candidateDirs(explicitDir)) {
|
|
25521
|
-
const p = path3__default.default.join(dir, templateName);
|
|
25522
|
-
if (!fs2__default.default.existsSync(p)) continue;
|
|
25523
|
-
try {
|
|
25524
|
-
fs2__default.default.accessSync(p, fs2__default.default.constants.R_OK);
|
|
25525
|
-
return p;
|
|
25526
|
-
} catch {
|
|
25527
|
-
}
|
|
25528
|
-
}
|
|
25529
|
-
return null;
|
|
25530
|
-
}
|
|
25531
|
-
function resolveArtifactTemplate(templateName, opts) {
|
|
25532
|
-
const p = findTemplatePath(templateName, opts?.templatesDir);
|
|
25533
|
-
if (!p) return null;
|
|
25534
|
-
try {
|
|
25535
|
-
const raw = fs2__default.default.readFileSync(p, "utf-8");
|
|
25536
|
-
return {
|
|
25537
|
-
content: stripTemplateFrontmatter(raw),
|
|
25538
|
-
sections: extractRequiredSections(raw) ?? extractBodySections(raw),
|
|
25539
|
-
sourcePath: p
|
|
25540
|
-
};
|
|
25541
|
-
} catch {
|
|
25542
|
-
return null;
|
|
25543
|
-
}
|
|
25544
|
-
}
|
|
25545
|
-
function loadCurriculumTemplate(templateName, templatesDir) {
|
|
25546
|
-
const p = findTemplatePath(templateName, templatesDir);
|
|
25547
|
-
if (!p) return "";
|
|
25548
|
-
try {
|
|
25549
|
-
return fs2__default.default.readFileSync(p, "utf-8");
|
|
25550
|
-
} catch {
|
|
25551
|
-
return "";
|
|
25552
|
-
}
|
|
25553
|
-
}
|
|
25554
25102
|
|
|
25555
25103
|
// src/services/lessonProductionService.ts
|
|
25556
25104
|
var LESSON_TEMPLATE_BY_PEDAGOGY = {
|
|
@@ -25562,10 +25110,11 @@ var LESSON_TEMPLATE_BY_PEDAGOGY = {
|
|
|
25562
25110
|
function buildArtifactPrompt(parts, opts) {
|
|
25563
25111
|
const resolved = resolveArtifactTemplate(parts.templateFile, opts);
|
|
25564
25112
|
const body = resolved?.content ?? parts.epilogue ?? "";
|
|
25565
|
-
|
|
25566
|
-
|
|
25567
|
-
` : "\
|
|
25568
|
-
|
|
25113
|
+
return `${parts.directive}
|
|
25114
|
+
|
|
25115
|
+
===== ARTIFACT TEMPLATE: ${parts.templateFile} ${resolved ? `(loaded from ${resolved.sourcePath})` : "(\u26A0\uFE0F NOT FOUND \u2014 inline fallback scaffold in use)"} =====
|
|
25116
|
+
|
|
25117
|
+
${body}`;
|
|
25569
25118
|
}
|
|
25570
25119
|
var NO_VERBATIM_COPYING = `
|
|
25571
25120
|
VERBATIM SOURCING RULE: When a section in the template says to extract a table
|
|
@@ -25765,6 +25314,10 @@ type: "${artifactType}"
|
|
|
25765
25314
|
and respect the template's OWNERSHIP note: each fact lives in exactly ONE
|
|
25766
25315
|
section \u2014 never restate satellite lists, resources, or assessment content
|
|
25767
25316
|
across sections, and never embed KX-owned question banks or self-check text.
|
|
25317
|
+
3. In the Learning Objectives table, carry the Standard ID from the [STANDARDS
|
|
25318
|
+
STATEMENTS] context into the same row as its LO (e.g. "CSTA: 1B-AP-10")
|
|
25319
|
+
when a matching standard exists.
|
|
25320
|
+
4. Every code sample must be 100% syntax-valid and executable.
|
|
25768
25321
|
3. Use the exact vocabulary of the canonical knowledge context for every
|
|
25769
25322
|
concept and term.
|
|
25770
25323
|
${NO_VERBATIM_COPYING}`;
|
|
@@ -29487,10 +29040,10 @@ init_slideProductionWorkflow();
|
|
|
29487
29040
|
var LocalWorkspaceManager = class {
|
|
29488
29041
|
baseDir;
|
|
29489
29042
|
constructor(baseDir) {
|
|
29490
|
-
this.baseDir = baseDir ||
|
|
29043
|
+
this.baseDir = baseDir || path4__default.default.resolve(process.cwd(), "output", "workspace-jobs");
|
|
29491
29044
|
}
|
|
29492
29045
|
getJobDirectory(jobId) {
|
|
29493
|
-
return
|
|
29046
|
+
return path4__default.default.join(this.baseDir, jobId);
|
|
29494
29047
|
}
|
|
29495
29048
|
async initJobWorkspace(jobId, initialInfo) {
|
|
29496
29049
|
const jobDir = this.getJobDirectory(jobId);
|
|
@@ -29513,9 +29066,9 @@ var LocalWorkspaceManager = class {
|
|
|
29513
29066
|
}
|
|
29514
29067
|
async saveArtifact(jobId, milestoneSlug, filename, content, artifactType) {
|
|
29515
29068
|
const jobDir = this.getJobDirectory(jobId);
|
|
29516
|
-
const targetDir =
|
|
29069
|
+
const targetDir = path4__default.default.join(jobDir, milestoneSlug);
|
|
29517
29070
|
await fsPromises__default.default.mkdir(targetDir, { recursive: true });
|
|
29518
|
-
const filePath =
|
|
29071
|
+
const filePath = path4__default.default.join(targetDir, filename);
|
|
29519
29072
|
await fsPromises__default.default.writeFile(filePath, content, "utf-8");
|
|
29520
29073
|
const stat = await fsPromises__default.default.stat(filePath);
|
|
29521
29074
|
const manifest = await this.getManifest(jobId);
|
|
@@ -29523,7 +29076,7 @@ var LocalWorkspaceManager = class {
|
|
|
29523
29076
|
manifest.artifacts.push({
|
|
29524
29077
|
milestoneId: milestoneSlug,
|
|
29525
29078
|
artifactType,
|
|
29526
|
-
filePath:
|
|
29079
|
+
filePath: path4__default.default.relative(jobDir, filePath),
|
|
29527
29080
|
sizeBytes: stat.size,
|
|
29528
29081
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
29529
29082
|
});
|
|
@@ -29533,7 +29086,7 @@ var LocalWorkspaceManager = class {
|
|
|
29533
29086
|
return filePath;
|
|
29534
29087
|
}
|
|
29535
29088
|
async getManifest(jobId) {
|
|
29536
|
-
const manifestPath =
|
|
29089
|
+
const manifestPath = path4__default.default.join(this.getJobDirectory(jobId), "manifest.json");
|
|
29537
29090
|
try {
|
|
29538
29091
|
const data = await fsPromises__default.default.readFile(manifestPath, "utf-8");
|
|
29539
29092
|
return JSON.parse(data);
|
|
@@ -29542,7 +29095,7 @@ var LocalWorkspaceManager = class {
|
|
|
29542
29095
|
}
|
|
29543
29096
|
}
|
|
29544
29097
|
async saveManifest(jobId, manifest) {
|
|
29545
|
-
const manifestPath =
|
|
29098
|
+
const manifestPath = path4__default.default.join(this.getJobDirectory(jobId), "manifest.json");
|
|
29546
29099
|
manifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
29547
29100
|
await fsPromises__default.default.writeFile(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
29548
29101
|
}
|
|
@@ -29583,12 +29136,12 @@ async function publishToGitHub(options) {
|
|
|
29583
29136
|
async function scanDir(currentDir) {
|
|
29584
29137
|
const entries = await fsPromises__default.default.readdir(currentDir, { withFileTypes: true });
|
|
29585
29138
|
for (const entry of entries) {
|
|
29586
|
-
const fullPath =
|
|
29139
|
+
const fullPath = path4__default.default.join(currentDir, entry.name);
|
|
29587
29140
|
if (entry.isDirectory()) {
|
|
29588
29141
|
await scanDir(fullPath);
|
|
29589
29142
|
} else if (entry.isFile() && !entry.name.startsWith(".")) {
|
|
29590
29143
|
const content = await fsPromises__default.default.readFile(fullPath, "utf-8");
|
|
29591
|
-
const relPath =
|
|
29144
|
+
const relPath = path4__default.default.relative(options.localJobDir, fullPath);
|
|
29592
29145
|
filesToUpload.push({ path: relPath, content });
|
|
29593
29146
|
}
|
|
29594
29147
|
}
|
|
@@ -31694,13 +31247,13 @@ var MediaLedger = class {
|
|
|
31694
31247
|
filePath;
|
|
31695
31248
|
entries = /* @__PURE__ */ new Map();
|
|
31696
31249
|
constructor(projectDir, lessonId) {
|
|
31697
|
-
this.filePath =
|
|
31250
|
+
this.filePath = path4__default.default.join(projectDir, "_media", `ledger-${lessonId.toUpperCase()}.jsonl`);
|
|
31698
31251
|
this.load();
|
|
31699
31252
|
}
|
|
31700
31253
|
load() {
|
|
31701
31254
|
this.entries.clear();
|
|
31702
|
-
if (!
|
|
31703
|
-
const lines =
|
|
31255
|
+
if (!fs3__default.default.existsSync(this.filePath)) return;
|
|
31256
|
+
const lines = fs3__default.default.readFileSync(this.filePath, "utf-8").split("\n");
|
|
31704
31257
|
for (const line of lines) {
|
|
31705
31258
|
const trimmed = line.trim();
|
|
31706
31259
|
if (!trimmed) continue;
|
|
@@ -31712,8 +31265,8 @@ var MediaLedger = class {
|
|
|
31712
31265
|
}
|
|
31713
31266
|
}
|
|
31714
31267
|
persist() {
|
|
31715
|
-
|
|
31716
|
-
|
|
31268
|
+
fs3__default.default.mkdirSync(path4__default.default.dirname(this.filePath), { recursive: true });
|
|
31269
|
+
fs3__default.default.writeFileSync(this.filePath, Array.from(this.entries.values()).map((e) => JSON.stringify(e)).join("\n") + "\n", "utf-8");
|
|
31717
31270
|
}
|
|
31718
31271
|
/** Agent tạo artifact ghi entry mới (hoặc cập nhật nếu slug đã có và chưa done) */
|
|
31719
31272
|
upsert(input) {
|
|
@@ -31895,8 +31448,8 @@ async function fulfillMediaLedger(options) {
|
|
|
31895
31448
|
const maxRetries = options.maxRetries ?? 2;
|
|
31896
31449
|
const approved = ledger.listByStatus("approved");
|
|
31897
31450
|
const result = { done: [], failed: [], skipped: [] };
|
|
31898
|
-
const mediaDir =
|
|
31899
|
-
|
|
31451
|
+
const mediaDir = path4__default.default.join(projectDir, "_media");
|
|
31452
|
+
fs3__default.default.mkdirSync(mediaDir, { recursive: true });
|
|
31900
31453
|
const mode = policy.mode ?? "auto";
|
|
31901
31454
|
const canSearch = mode === "search_only" || mode === "auto";
|
|
31902
31455
|
const canGen = mode === "gen_only" || mode === "auto";
|
|
@@ -31978,7 +31531,7 @@ async function fulfillMediaLedger(options) {
|
|
|
31978
31531
|
});
|
|
31979
31532
|
const ext = image.mimeType === "image/jpeg" ? "jpg" : "png";
|
|
31980
31533
|
const filename = `${entry.slug}-${Date.now()}.${ext}`;
|
|
31981
|
-
|
|
31534
|
+
fs3__default.default.writeFileSync(path4__default.default.join(mediaDir, filename), Buffer.from(image.base64, "base64"));
|
|
31982
31535
|
ledger.setStatus(entry.slug, "done", { relPath: `_media/${filename}`, provider: image.provider });
|
|
31983
31536
|
result.done.push(entry.slug);
|
|
31984
31537
|
options.onProgress?.(entry.slug, "done", `source: ${image.provider}`);
|
|
@@ -32009,7 +31562,6 @@ function renderMediaPlaceholder(entry) {
|
|
|
32009
31562
|
return `> \u{1F5BC}\uFE0F [\u1EA2nh \u0111ang ch\u1EDD: ${entry.name} \u2014 s\u1EBD \u0111\u01B0\u1EE3c t\u1EA1o sau khi duy\u1EC7t media]`;
|
|
32010
31563
|
}
|
|
32011
31564
|
|
|
32012
|
-
exports.ACT_TEMPLATE = ACT_TEMPLATE;
|
|
32013
31565
|
exports.ARTIFACT_DEPENDENCY_ROUTING = ARTIFACT_DEPENDENCY_ROUTING;
|
|
32014
31566
|
exports.ARTIFACT_EXECUTION_ORDER = ARTIFACT_EXECUTION_ORDER;
|
|
32015
31567
|
exports.AcademicAuditor = AcademicAuditor;
|
|
@@ -32031,7 +31583,6 @@ exports.BloomLevelSchema = BloomLevelSchema;
|
|
|
32031
31583
|
exports.BloomTaxonomyEvaluator = BloomTaxonomyEvaluator;
|
|
32032
31584
|
exports.BronzeTierSchema = BronzeTierSchema;
|
|
32033
31585
|
exports.CERConclusionSchema = CERConclusionSchema;
|
|
32034
|
-
exports.CODE_LAB_TEMPLATE = CODE_LAB_TEMPLATE;
|
|
32035
31586
|
exports.CURRICULUM_SLASH_COMMANDS = CURRICULUM_SLASH_COMMANDS;
|
|
32036
31587
|
exports.CardTierEnum = CardTierEnum;
|
|
32037
31588
|
exports.ChoiceBoardRubricRowSchema = ChoiceBoardRubricRowSchema;
|
|
@@ -32106,7 +31657,6 @@ exports.JUDGE_ESCALATE_THRESHOLD = JUDGE_ESCALATE_THRESHOLD;
|
|
|
32106
31657
|
exports.JudgeCriterionSchema = JudgeCriterionSchema;
|
|
32107
31658
|
exports.LAYER_IDLE_BUDGET_MS = LAYER_IDLE_BUDGET_MS;
|
|
32108
31659
|
exports.LAYER_TOTAL_BUDGET_MS = LAYER_TOTAL_BUDGET_MS;
|
|
32109
|
-
exports.LESSON_PLAN_TEMPLATE = LESSON_PLAN_TEMPLATE;
|
|
32110
31660
|
exports.LLMJudgeEngine = LLMJudgeEngine;
|
|
32111
31661
|
exports.LabTierTaskSchema = LabTierTaskSchema;
|
|
32112
31662
|
exports.LearningObjectiveInputSchema = LearningObjectiveInputSchema;
|
|
@@ -32148,7 +31698,6 @@ exports.ProjectGraphAuditSchema = ProjectGraphAuditSchema;
|
|
|
32148
31698
|
exports.ProjectGraphSchema = ProjectGraphSchema;
|
|
32149
31699
|
exports.ProjectInstructionSchema = ProjectInstructionSchema;
|
|
32150
31700
|
exports.ProjectProfileSchema = ProjectProfileSchema;
|
|
32151
|
-
exports.QUIZ_TEMPLATE = QUIZ_TEMPLATE;
|
|
32152
31701
|
exports.QualityAuditVerdictSchema = QualityAuditVerdictSchema;
|
|
32153
31702
|
exports.QuizOptionSchema = QuizOptionSchema;
|
|
32154
31703
|
exports.RecordProvenanceSchema = RecordProvenanceSchema;
|
|
@@ -32161,7 +31710,6 @@ exports.RotationStationSchema = RotationStationSchema;
|
|
|
32161
31710
|
exports.RubricCriteriaSchema = RubricCriteriaSchema;
|
|
32162
31711
|
exports.RubricSchema = RubricSchema;
|
|
32163
31712
|
exports.SATELLITE_LESSON_PRIORITIES = SATELLITE_LESSON_PRIORITIES;
|
|
32164
|
-
exports.SELF_LAB_TEMPLATE = SELF_LAB_TEMPLATE;
|
|
32165
31713
|
exports.SLIDE_CANONICAL_METHODOLOGY = SLIDE_CANONICAL_METHODOLOGY;
|
|
32166
31714
|
exports.STANDARD_REF_REGEX = STANDARD_REF_REGEX;
|
|
32167
31715
|
exports.STANDARD_SOT_FILES = STANDARD_SOT_FILES;
|
|
@@ -32337,6 +31885,7 @@ exports.isTranslationDue = isTranslationDue;
|
|
|
32337
31885
|
exports.lintAndSanitizeArtifact = lintAndSanitizeArtifact;
|
|
32338
31886
|
exports.lintCurriculumFramework = lintCurriculumFramework;
|
|
32339
31887
|
exports.lintFrameworkPack = lintFrameworkPack;
|
|
31888
|
+
exports.loadAuthoringTemplate = loadAuthoringTemplate;
|
|
32340
31889
|
exports.loadCurriculumTemplate = loadCurriculumTemplate;
|
|
32341
31890
|
exports.loadSotTemplate = loadSotTemplate;
|
|
32342
31891
|
exports.normalizePlanningGraph = normalizePlanningGraph;
|