@thanh01.pmt/curriculum-kit 1.4.43 → 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 +228 -684
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -31
- package/dist/index.d.ts +8 -31
- package/dist/index.mjs +226 -678
- 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 = {
|
|
@@ -29492,10 +29040,10 @@ init_slideProductionWorkflow();
|
|
|
29492
29040
|
var LocalWorkspaceManager = class {
|
|
29493
29041
|
baseDir;
|
|
29494
29042
|
constructor(baseDir) {
|
|
29495
|
-
this.baseDir = baseDir ||
|
|
29043
|
+
this.baseDir = baseDir || path4__default.default.resolve(process.cwd(), "output", "workspace-jobs");
|
|
29496
29044
|
}
|
|
29497
29045
|
getJobDirectory(jobId) {
|
|
29498
|
-
return
|
|
29046
|
+
return path4__default.default.join(this.baseDir, jobId);
|
|
29499
29047
|
}
|
|
29500
29048
|
async initJobWorkspace(jobId, initialInfo) {
|
|
29501
29049
|
const jobDir = this.getJobDirectory(jobId);
|
|
@@ -29518,9 +29066,9 @@ var LocalWorkspaceManager = class {
|
|
|
29518
29066
|
}
|
|
29519
29067
|
async saveArtifact(jobId, milestoneSlug, filename, content, artifactType) {
|
|
29520
29068
|
const jobDir = this.getJobDirectory(jobId);
|
|
29521
|
-
const targetDir =
|
|
29069
|
+
const targetDir = path4__default.default.join(jobDir, milestoneSlug);
|
|
29522
29070
|
await fsPromises__default.default.mkdir(targetDir, { recursive: true });
|
|
29523
|
-
const filePath =
|
|
29071
|
+
const filePath = path4__default.default.join(targetDir, filename);
|
|
29524
29072
|
await fsPromises__default.default.writeFile(filePath, content, "utf-8");
|
|
29525
29073
|
const stat = await fsPromises__default.default.stat(filePath);
|
|
29526
29074
|
const manifest = await this.getManifest(jobId);
|
|
@@ -29528,7 +29076,7 @@ var LocalWorkspaceManager = class {
|
|
|
29528
29076
|
manifest.artifacts.push({
|
|
29529
29077
|
milestoneId: milestoneSlug,
|
|
29530
29078
|
artifactType,
|
|
29531
|
-
filePath:
|
|
29079
|
+
filePath: path4__default.default.relative(jobDir, filePath),
|
|
29532
29080
|
sizeBytes: stat.size,
|
|
29533
29081
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
29534
29082
|
});
|
|
@@ -29538,7 +29086,7 @@ var LocalWorkspaceManager = class {
|
|
|
29538
29086
|
return filePath;
|
|
29539
29087
|
}
|
|
29540
29088
|
async getManifest(jobId) {
|
|
29541
|
-
const manifestPath =
|
|
29089
|
+
const manifestPath = path4__default.default.join(this.getJobDirectory(jobId), "manifest.json");
|
|
29542
29090
|
try {
|
|
29543
29091
|
const data = await fsPromises__default.default.readFile(manifestPath, "utf-8");
|
|
29544
29092
|
return JSON.parse(data);
|
|
@@ -29547,7 +29095,7 @@ var LocalWorkspaceManager = class {
|
|
|
29547
29095
|
}
|
|
29548
29096
|
}
|
|
29549
29097
|
async saveManifest(jobId, manifest) {
|
|
29550
|
-
const manifestPath =
|
|
29098
|
+
const manifestPath = path4__default.default.join(this.getJobDirectory(jobId), "manifest.json");
|
|
29551
29099
|
manifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
29552
29100
|
await fsPromises__default.default.writeFile(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
29553
29101
|
}
|
|
@@ -29588,12 +29136,12 @@ async function publishToGitHub(options) {
|
|
|
29588
29136
|
async function scanDir(currentDir) {
|
|
29589
29137
|
const entries = await fsPromises__default.default.readdir(currentDir, { withFileTypes: true });
|
|
29590
29138
|
for (const entry of entries) {
|
|
29591
|
-
const fullPath =
|
|
29139
|
+
const fullPath = path4__default.default.join(currentDir, entry.name);
|
|
29592
29140
|
if (entry.isDirectory()) {
|
|
29593
29141
|
await scanDir(fullPath);
|
|
29594
29142
|
} else if (entry.isFile() && !entry.name.startsWith(".")) {
|
|
29595
29143
|
const content = await fsPromises__default.default.readFile(fullPath, "utf-8");
|
|
29596
|
-
const relPath =
|
|
29144
|
+
const relPath = path4__default.default.relative(options.localJobDir, fullPath);
|
|
29597
29145
|
filesToUpload.push({ path: relPath, content });
|
|
29598
29146
|
}
|
|
29599
29147
|
}
|
|
@@ -31699,13 +31247,13 @@ var MediaLedger = class {
|
|
|
31699
31247
|
filePath;
|
|
31700
31248
|
entries = /* @__PURE__ */ new Map();
|
|
31701
31249
|
constructor(projectDir, lessonId) {
|
|
31702
|
-
this.filePath =
|
|
31250
|
+
this.filePath = path4__default.default.join(projectDir, "_media", `ledger-${lessonId.toUpperCase()}.jsonl`);
|
|
31703
31251
|
this.load();
|
|
31704
31252
|
}
|
|
31705
31253
|
load() {
|
|
31706
31254
|
this.entries.clear();
|
|
31707
|
-
if (!
|
|
31708
|
-
const lines =
|
|
31255
|
+
if (!fs3__default.default.existsSync(this.filePath)) return;
|
|
31256
|
+
const lines = fs3__default.default.readFileSync(this.filePath, "utf-8").split("\n");
|
|
31709
31257
|
for (const line of lines) {
|
|
31710
31258
|
const trimmed = line.trim();
|
|
31711
31259
|
if (!trimmed) continue;
|
|
@@ -31717,8 +31265,8 @@ var MediaLedger = class {
|
|
|
31717
31265
|
}
|
|
31718
31266
|
}
|
|
31719
31267
|
persist() {
|
|
31720
|
-
|
|
31721
|
-
|
|
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");
|
|
31722
31270
|
}
|
|
31723
31271
|
/** Agent tạo artifact ghi entry mới (hoặc cập nhật nếu slug đã có và chưa done) */
|
|
31724
31272
|
upsert(input) {
|
|
@@ -31900,8 +31448,8 @@ async function fulfillMediaLedger(options) {
|
|
|
31900
31448
|
const maxRetries = options.maxRetries ?? 2;
|
|
31901
31449
|
const approved = ledger.listByStatus("approved");
|
|
31902
31450
|
const result = { done: [], failed: [], skipped: [] };
|
|
31903
|
-
const mediaDir =
|
|
31904
|
-
|
|
31451
|
+
const mediaDir = path4__default.default.join(projectDir, "_media");
|
|
31452
|
+
fs3__default.default.mkdirSync(mediaDir, { recursive: true });
|
|
31905
31453
|
const mode = policy.mode ?? "auto";
|
|
31906
31454
|
const canSearch = mode === "search_only" || mode === "auto";
|
|
31907
31455
|
const canGen = mode === "gen_only" || mode === "auto";
|
|
@@ -31983,7 +31531,7 @@ async function fulfillMediaLedger(options) {
|
|
|
31983
31531
|
});
|
|
31984
31532
|
const ext = image.mimeType === "image/jpeg" ? "jpg" : "png";
|
|
31985
31533
|
const filename = `${entry.slug}-${Date.now()}.${ext}`;
|
|
31986
|
-
|
|
31534
|
+
fs3__default.default.writeFileSync(path4__default.default.join(mediaDir, filename), Buffer.from(image.base64, "base64"));
|
|
31987
31535
|
ledger.setStatus(entry.slug, "done", { relPath: `_media/${filename}`, provider: image.provider });
|
|
31988
31536
|
result.done.push(entry.slug);
|
|
31989
31537
|
options.onProgress?.(entry.slug, "done", `source: ${image.provider}`);
|
|
@@ -32014,7 +31562,6 @@ function renderMediaPlaceholder(entry) {
|
|
|
32014
31562
|
return `> \u{1F5BC}\uFE0F [\u1EA2nh \u0111ang ch\u1EDD: ${entry.name} \u2014 s\u1EBD \u0111\u01B0\u1EE3c t\u1EA1o sau khi duy\u1EC7t media]`;
|
|
32015
31563
|
}
|
|
32016
31564
|
|
|
32017
|
-
exports.ACT_TEMPLATE = ACT_TEMPLATE;
|
|
32018
31565
|
exports.ARTIFACT_DEPENDENCY_ROUTING = ARTIFACT_DEPENDENCY_ROUTING;
|
|
32019
31566
|
exports.ARTIFACT_EXECUTION_ORDER = ARTIFACT_EXECUTION_ORDER;
|
|
32020
31567
|
exports.AcademicAuditor = AcademicAuditor;
|
|
@@ -32036,7 +31583,6 @@ exports.BloomLevelSchema = BloomLevelSchema;
|
|
|
32036
31583
|
exports.BloomTaxonomyEvaluator = BloomTaxonomyEvaluator;
|
|
32037
31584
|
exports.BronzeTierSchema = BronzeTierSchema;
|
|
32038
31585
|
exports.CERConclusionSchema = CERConclusionSchema;
|
|
32039
|
-
exports.CODE_LAB_TEMPLATE = CODE_LAB_TEMPLATE;
|
|
32040
31586
|
exports.CURRICULUM_SLASH_COMMANDS = CURRICULUM_SLASH_COMMANDS;
|
|
32041
31587
|
exports.CardTierEnum = CardTierEnum;
|
|
32042
31588
|
exports.ChoiceBoardRubricRowSchema = ChoiceBoardRubricRowSchema;
|
|
@@ -32111,7 +31657,6 @@ exports.JUDGE_ESCALATE_THRESHOLD = JUDGE_ESCALATE_THRESHOLD;
|
|
|
32111
31657
|
exports.JudgeCriterionSchema = JudgeCriterionSchema;
|
|
32112
31658
|
exports.LAYER_IDLE_BUDGET_MS = LAYER_IDLE_BUDGET_MS;
|
|
32113
31659
|
exports.LAYER_TOTAL_BUDGET_MS = LAYER_TOTAL_BUDGET_MS;
|
|
32114
|
-
exports.LESSON_PLAN_TEMPLATE = LESSON_PLAN_TEMPLATE;
|
|
32115
31660
|
exports.LLMJudgeEngine = LLMJudgeEngine;
|
|
32116
31661
|
exports.LabTierTaskSchema = LabTierTaskSchema;
|
|
32117
31662
|
exports.LearningObjectiveInputSchema = LearningObjectiveInputSchema;
|
|
@@ -32153,7 +31698,6 @@ exports.ProjectGraphAuditSchema = ProjectGraphAuditSchema;
|
|
|
32153
31698
|
exports.ProjectGraphSchema = ProjectGraphSchema;
|
|
32154
31699
|
exports.ProjectInstructionSchema = ProjectInstructionSchema;
|
|
32155
31700
|
exports.ProjectProfileSchema = ProjectProfileSchema;
|
|
32156
|
-
exports.QUIZ_TEMPLATE = QUIZ_TEMPLATE;
|
|
32157
31701
|
exports.QualityAuditVerdictSchema = QualityAuditVerdictSchema;
|
|
32158
31702
|
exports.QuizOptionSchema = QuizOptionSchema;
|
|
32159
31703
|
exports.RecordProvenanceSchema = RecordProvenanceSchema;
|
|
@@ -32166,7 +31710,6 @@ exports.RotationStationSchema = RotationStationSchema;
|
|
|
32166
31710
|
exports.RubricCriteriaSchema = RubricCriteriaSchema;
|
|
32167
31711
|
exports.RubricSchema = RubricSchema;
|
|
32168
31712
|
exports.SATELLITE_LESSON_PRIORITIES = SATELLITE_LESSON_PRIORITIES;
|
|
32169
|
-
exports.SELF_LAB_TEMPLATE = SELF_LAB_TEMPLATE;
|
|
32170
31713
|
exports.SLIDE_CANONICAL_METHODOLOGY = SLIDE_CANONICAL_METHODOLOGY;
|
|
32171
31714
|
exports.STANDARD_REF_REGEX = STANDARD_REF_REGEX;
|
|
32172
31715
|
exports.STANDARD_SOT_FILES = STANDARD_SOT_FILES;
|
|
@@ -32342,6 +31885,7 @@ exports.isTranslationDue = isTranslationDue;
|
|
|
32342
31885
|
exports.lintAndSanitizeArtifact = lintAndSanitizeArtifact;
|
|
32343
31886
|
exports.lintCurriculumFramework = lintCurriculumFramework;
|
|
32344
31887
|
exports.lintFrameworkPack = lintFrameworkPack;
|
|
31888
|
+
exports.loadAuthoringTemplate = loadAuthoringTemplate;
|
|
32345
31889
|
exports.loadCurriculumTemplate = loadCurriculumTemplate;
|
|
32346
31890
|
exports.loadSotTemplate = loadSotTemplate;
|
|
32347
31891
|
exports.normalizePlanningGraph = normalizePlanningGraph;
|