@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.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import fs3 from 'fs';
|
|
2
|
+
import path4 from 'path';
|
|
3
3
|
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
|
4
4
|
import { createOpenAI } from '@ai-sdk/openai';
|
|
5
5
|
import { createDeepSeek } from '@ai-sdk/deepseek';
|
|
@@ -7,11 +7,11 @@ import { z } from 'zod';
|
|
|
7
7
|
import { generateObject, streamObject, streamText, generateText } from 'ai';
|
|
8
8
|
import pRetry from 'p-retry';
|
|
9
9
|
import { jsonrepair } from 'jsonrepair';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
10
11
|
import pLimit from 'p-limit';
|
|
11
12
|
import fsPromises from 'fs/promises';
|
|
12
13
|
import crypto, { createHash } from 'crypto';
|
|
13
14
|
import { createClient } from '@supabase/supabase-js';
|
|
14
|
-
import { fileURLToPath } from 'url';
|
|
15
15
|
import { Octokit } from '@octokit/rest';
|
|
16
16
|
|
|
17
17
|
var __defProp = Object.defineProperty;
|
|
@@ -165,18 +165,18 @@ function resolveApiKey(keyName, explicitKey) {
|
|
|
165
165
|
try {
|
|
166
166
|
const currentDir = process.cwd();
|
|
167
167
|
const envPaths = [
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
168
|
+
path4.resolve(currentDir, ".env.local"),
|
|
169
|
+
path4.resolve(currentDir, ".env"),
|
|
170
|
+
path4.resolve(currentDir, "apps/web/.env.local"),
|
|
171
|
+
path4.resolve(currentDir, "packages/learnwell-platform/.env"),
|
|
172
|
+
path4.resolve(currentDir, "..", ".env.local"),
|
|
173
|
+
path4.resolve(currentDir, "..", ".env"),
|
|
174
|
+
path4.resolve(currentDir, "../..", ".env.local"),
|
|
175
|
+
path4.resolve(currentDir, "../..", ".env")
|
|
176
176
|
];
|
|
177
177
|
for (const envPath of envPaths) {
|
|
178
|
-
if (
|
|
179
|
-
const content =
|
|
178
|
+
if (fs3.existsSync(envPath)) {
|
|
179
|
+
const content = fs3.readFileSync(envPath, "utf-8");
|
|
180
180
|
for (const line of content.split("\n")) {
|
|
181
181
|
const trimmed = line.trim();
|
|
182
182
|
if (trimmed && !trimmed.startsWith("#") && trimmed.startsWith(keyName + "=")) {
|
|
@@ -3932,467 +3932,105 @@ var RoadmapInputSchema = z.object({
|
|
|
3932
3932
|
|
|
3933
3933
|
// src/ai/index.ts
|
|
3934
3934
|
init_provider_factory();
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
---
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
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
|
-
## [OPTIONAL] Teacher Notes
|
|
4035
|
-
- **Common Pitfalls:**
|
|
4036
|
-
{{COMMON_PITFALLS}}
|
|
4037
|
-
- **Troubleshooting:**
|
|
4038
|
-
{{TROUBLESHOOTING_ROWS}}
|
|
4039
|
-
|
|
4040
|
-
---
|
|
4041
|
-
|
|
4042
|
-
## [REQUIRED] Artifact Linkage (Master Index)
|
|
4043
|
-
> List all satellite files used in this lesson.
|
|
4044
|
-
|
|
4045
|
-
| Artifact File | Role in the Classroom | When to Use |
|
|
4046
|
-
|---|---|---|
|
|
4047
|
-
| \`GUIDE_{{LESSON_ID}}.md\` | Detailed Teaching Script | Teacher preparation |
|
|
4048
|
-
| \`SLIDE_{{LESSON_ID}}.md\` | Presentation Content | Throughout the session |
|
|
4049
|
-
| \`HANDOUT_{{LESSON_ID}}.md\` | Theory Summary for Students | During EXPLAIN phase |
|
|
4050
|
-
| \`ACT_{{LESSON_ID}}.md\` | Detailed Learning Activity Operations | During EXPLORE / ELABORATE / checkpoint phases |
|
|
4051
|
-
| \`WKS_{{LESSON_ID}}.md\` | Individual Worksheet | Wrap-up or Homework |
|
|
4052
|
-
| \`QUIZ_{{LESSON_ID}}.md\` | Assessment Rubric | During EVALUATE phase |
|
|
4053
|
-
| \`EXT_{{LESSON_ID}}.md\` | Enrichment Materials | For "Gold" students |
|
|
4054
|
-
`.trim();
|
|
4055
|
-
|
|
4056
|
-
// src/templates/actTemplate.ts
|
|
4057
|
-
var ACT_TEMPLATE = `
|
|
4058
|
-
---
|
|
4059
|
-
id: "{{ID}}"
|
|
4060
|
-
title: "{{TITLE}}"
|
|
4061
|
-
type: "ACT"
|
|
4062
|
-
created_by: "Curriculum OS Builder"
|
|
4063
|
-
phase: "{{PHASE}}"
|
|
4064
|
-
deliverable: "P3-T2"
|
|
4065
|
-
version: "{{VERSION}}"
|
|
4066
|
-
date: "{{DATE}}"
|
|
4067
|
-
template_contract: "artifact-template-v1"
|
|
4068
|
-
template_required_sections:
|
|
4069
|
-
- "Computational Thinking Focus"
|
|
4070
|
-
- "Materials & Setup"
|
|
4071
|
-
- "Constraints & Safety"
|
|
4072
|
-
- "Active Learning Workflow"
|
|
4073
|
-
- "3-Tier Differentiation"
|
|
4074
|
-
- "Reflection"
|
|
4075
|
-
---
|
|
4076
|
-
<!-- INJECT_BODY -->
|
|
4077
|
-
|
|
4078
|
-
# INQUIRY-BASED ACTIVITY: {{TITLE}}
|
|
4079
|
-
_Milestone: {{MILESTONE_ID}} | Module: {{MODULE_NAME}} | Lesson: {{LESSON_ID}}_
|
|
4080
|
-
|
|
4081
|
-
## [REQUIRED] Computational Thinking Focus
|
|
4082
|
-
- **Problem Statement (Real-world Scenario):** {{PROBLEM_STATEMENT}}
|
|
4083
|
-
- **Decomposition:**
|
|
4084
|
-
{{DECOMPOSITION_STEPS}}
|
|
4085
|
-
- **Algorithm Design:** {{ALGORITHM_DESIGN}}
|
|
4086
|
-
|
|
4087
|
-
## [REQUIRED] Materials & Setup
|
|
4088
|
-
- **Reference Material:** Students should use the **HANDOUT** for this lesson as their primary technical reference (lifeline).
|
|
4089
|
-
- **Hardware/Software:**
|
|
4090
|
-
<!-- [HARDWARE_BOM] -->
|
|
4091
|
-
{{HARDWARE_ITEMS}}
|
|
4092
|
-
<!-- [/HARDWARE_BOM] -->
|
|
4093
|
-
- **Software:** {{SOFTWARE_ITEMS}}
|
|
4094
|
-
- **Consumables:** {{CONSUMABLES}}
|
|
4095
|
-
- **Other Resources:** {{OTHER_RESOURCES}}
|
|
4096
|
-
|
|
4097
|
-
## [REQUIRED] Constraints & Safety
|
|
4098
|
-
- \u26A0\uFE0F **Technical/Safety:** {{SAFETY_WARNING}}
|
|
4099
|
-
- \u{1F4A1} **Design Constraint:** {{DESIGN_CONSTRAINT}}
|
|
4100
|
-
|
|
4101
|
-
## [REQUIRED] Active Learning Workflow
|
|
4102
|
-
|
|
4103
|
-
### Phase 1: Planning & Design \u2014 {{PHASE1_DURATION}} mins
|
|
4104
|
-
- **Student Task:** Hand-draw (or draft in words) the algorithm flowchart or connection architecture before touching the computer/devices.
|
|
4105
|
-
- **Teacher Action:** Walk around to check the logic of each group. Ask inquiry questions:
|
|
4106
|
-
{{PHASE1_INQUIRY_QUESTIONS}}
|
|
4107
|
-
|
|
4108
|
-
### Phase 2: Implementation & Discovery \u2014 {{PHASE2_DURATION}} mins
|
|
4109
|
-
- **Student Task:** Apply the knowledge from the **HANDOUT** to realize the plan designed in Phase 1. Encourage self-inquiry and documentation lookup.
|
|
4110
|
-
- **Teacher Action:** Avoid "hand-holding." Only intervene if a group has been stuck for more than 5 minutes.
|
|
4111
|
-
{{PHASE2_GUIDANCE_BLOCK}}
|
|
4112
|
-
|
|
4113
|
-
### Phase 3: Debugging & Testing \u2014 {{PHASE3_DURATION}} mins
|
|
4114
|
-
- **Testing:** Students run their system.
|
|
4115
|
-
- **Error Analysis:** Ask students to record any error codes or unexpected behaviors and compare them with the Troubleshooting table in the Handout.
|
|
4116
|
-
{{PHASE3_TESTING_STEPS}}
|
|
4117
|
-
|
|
4118
|
-
## [REQUIRED] 3-Tier Differentiation
|
|
4119
|
-
> MUST design tasks in 3 tiers to support diverse learner groups. Bronze is the minimum requirement for all students.
|
|
4120
|
-
- \u{1F949} **Bronze (Foundational):** {{DIFFERENTIATION_BRONZE}}
|
|
4121
|
-
- \u{1F948} **Silver (Application):** {{DIFFERENTIATION_SILVER}}
|
|
4122
|
-
- \u{1F947} **Gold (Enrichment/Creative):** {{DIFFERENTIATION_GOLD}}
|
|
4123
|
-
|
|
4124
|
-
## [REQUIRED] Reflection
|
|
4125
|
-
- **Discussion Question:** {{REFLECTION_QUESTION}}
|
|
4126
|
-
`.trim();
|
|
4127
|
-
|
|
4128
|
-
// src/templates/codeLabTemplate.ts
|
|
4129
|
-
var CODE_LAB_TEMPLATE = `
|
|
4130
|
-
---
|
|
4131
|
-
id: "{{ID}}"
|
|
4132
|
-
title: "{{TITLE}}"
|
|
4133
|
-
type: "LAB"
|
|
4134
|
-
created_by: "Curriculum OS Builder"
|
|
4135
|
-
phase: "{{PHASE}}"
|
|
4136
|
-
deliverable: "P3-T2"
|
|
4137
|
-
version: "{{VERSION}}"
|
|
4138
|
-
date: "{{DATE}}"
|
|
4139
|
-
---
|
|
4140
|
-
<!-- INJECT_BODY -->
|
|
4141
|
-
|
|
4142
|
-
# \u{1F468}\u200D\u{1F4BB} CODE LAB: {{TITLE}}
|
|
4143
|
-
_Milestone: {{MILESTONE_ID}} | Tech Stack: {{TECH_STACK}}_
|
|
4144
|
-
|
|
4145
|
-
## \u{1F3AF} Overview
|
|
4146
|
-
This lab focuses on the practical implementation of core technical concepts, bridging theory into working, robust, and testable code.
|
|
4147
|
-
|
|
4148
|
-
## \u{1F6E0}\uFE0F Environment & Setup
|
|
4149
|
-
- **Language / Framework:** {{LANGUAGE_FRAMEWORK}}
|
|
4150
|
-
- **IDE / Editor:** {{IDE_EDITOR}}
|
|
4151
|
-
- **Required Libraries:** {{REQUIRED_LIBRARIES}}
|
|
4152
|
-
- **Hardware / Connection Setup:** {{HARDWARE_ENV_CONNECTION}}
|
|
4153
|
-
|
|
4154
|
-
## \u{1F4DD} Lab Tasks (3-Tier Differentiation)
|
|
4155
|
-
|
|
4156
|
-
### \u{1F949} Bronze (Foundational) \u2014 {{BRONZE_MINS}} mins
|
|
4157
|
-
**Objective:** {{BRONZE_OBJECTIVE}}
|
|
4158
|
-
- **Task:** {{BRONZE_TASK}}
|
|
4159
|
-
- **Requirement:** {{BRONZE_REQUIREMENT}}
|
|
4160
|
-
|
|
4161
|
-
### \u{1F948} Silver (Application) \u2014 {{SILVER_MINS}} mins
|
|
4162
|
-
**Objective:** {{SILVER_OBJECTIVE}}
|
|
4163
|
-
- **Task:** {{SILVER_TASK}}
|
|
4164
|
-
- **Requirement:** {{SILVER_REQUIREMENT}}
|
|
4165
|
-
|
|
4166
|
-
### \u{1F947} Gold (Enrichment/Creative) \u2014 {{GOLD_MINS}} mins
|
|
4167
|
-
**Objective:** {{GOLD_OBJECTIVE}}
|
|
4168
|
-
- **Task:** {{GOLD_TASK}}
|
|
4169
|
-
- **Requirement:** {{GOLD_REQUIREMENT}}
|
|
4170
|
-
|
|
4171
|
-
## \u{1F4BB} Technical Reference ([SME_MANDATE])
|
|
4172
|
-
<!-- [SME_MANDATE] -->
|
|
4173
|
-
> Any code provided in this section is verified for syntax accuracy and runtime execution.
|
|
4174
|
-
|
|
4175
|
-
### Starter Code Template
|
|
4176
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4177
|
-
{{STARTER_CODE}}
|
|
4178
|
-
\`\`\`
|
|
4179
|
-
|
|
4180
|
-
### Solution Code
|
|
4181
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4182
|
-
{{SOLUTION_CODE}}
|
|
4183
|
-
\`\`\`
|
|
4184
|
-
<!-- [/SME_MANDATE] -->
|
|
4185
|
-
|
|
4186
|
-
## \u{1F50D} Troubleshooting & Debugging Matrix
|
|
4187
|
-
| Issue | Potential Cause | Solution |
|
|
4188
|
-
| :--- | :--- | :--- |
|
|
4189
|
-
{{TROUBLESHOOTING_ROWS}}
|
|
4190
|
-
|
|
4191
|
-
## \u{1F3C1} Submission & Verification Checklist
|
|
4192
|
-
{{CHECKLIST_ITEMS}}
|
|
4193
|
-
`.trim();
|
|
4194
|
-
|
|
4195
|
-
// src/templates/quizTemplate.ts
|
|
4196
|
-
var QUIZ_TEMPLATE = `
|
|
4197
|
-
---
|
|
4198
|
-
id: "{{ID}}"
|
|
4199
|
-
title: "{{TITLE}}"
|
|
4200
|
-
type: "QUIZ"
|
|
4201
|
-
language: "{{LANGUAGE}}"
|
|
4202
|
-
total_questions: {{TOTAL_QUESTIONS}}
|
|
4203
|
-
passing_score_pct: {{PASSING_SCORE_PCT}}
|
|
4204
|
-
---
|
|
4205
|
-
|
|
4206
|
-
# \u{1F9E0} Diagnostic & Active Recall Quiz: {{TITLE}}
|
|
4207
|
-
|
|
4208
|
-
> \u23F1\uFE0F **Recommended Time:** ~10-15 mins
|
|
4209
|
-
> \u{1F3AF} **Passing Score:** {{PASSING_SCORE_PCT}}%
|
|
4210
|
-
> \u{1F4A1} **Purpose:** Test your conceptual understanding, catch hidden misconceptions, and evaluate architectural trade-offs.
|
|
4211
|
-
|
|
4212
|
-
---
|
|
4213
|
-
|
|
4214
|
-
{{QUESTIONS_SECTION}}
|
|
4215
|
-
|
|
4216
|
-
---
|
|
4217
|
-
|
|
4218
|
-
## \u{1F511} Comprehensive Answer Key & Deep Explanation (Expand after completing)
|
|
4219
|
-
<details>
|
|
4220
|
-
<summary><b>\u{1F449} Click to View Full Explanations & Common Pitfall Analysis</b></summary>
|
|
4221
|
-
|
|
4222
|
-
{{ANSWER_KEY_SECTION}}
|
|
4223
|
-
</details>
|
|
4224
|
-
`.trim();
|
|
4225
|
-
|
|
4226
|
-
// src/templates/selfLabTemplate.ts
|
|
4227
|
-
var SELF_LAB_TEMPLATE = `
|
|
4228
|
-
---
|
|
4229
|
-
id: "{{ID}}"
|
|
4230
|
-
title: "{{TITLE}}"
|
|
4231
|
-
type: "SELF_LAB"
|
|
4232
|
-
language: "{{LANGUAGE}}"
|
|
4233
|
-
difficulty: "{{DIFFICULTY}}"
|
|
4234
|
-
estimated_minutes: {{ESTIMATED_MINUTES}}
|
|
4235
|
-
tech_stack: {{TECH_STACK}}
|
|
4236
|
-
---
|
|
4237
|
-
|
|
4238
|
-
# \u{1F680} Self-Paced Hands-On Lab: {{TITLE}}
|
|
4239
|
-
|
|
4240
|
-
> \u23F1\uFE0F **Estimated Duration:** ~{{ESTIMATED_MINUTES}} mins
|
|
4241
|
-
> \u{1F3AF} **Difficulty Level:** {{DIFFICULTY_UPPER}}
|
|
4242
|
-
> \u{1F9F0} **Tech Stack:** {{TECH_STACK_STR}}
|
|
4243
|
-
> \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!
|
|
4244
|
-
|
|
4245
|
-
---
|
|
4246
|
-
|
|
4247
|
-
## \u{1F4CB} Mission Briefing & Environment Setup
|
|
4248
|
-
{{MISSION_BRIEFING}}
|
|
4249
|
-
|
|
4250
|
-
### \u{1F6EB} Preflight Checklist
|
|
4251
|
-
{{PREFLIGHT_CHECKLIST}}
|
|
4252
|
-
|
|
4253
|
-
---
|
|
4254
|
-
|
|
4255
|
-
## \u{1F3AF} Progressive Challenges (3-Tier Differentiation)
|
|
4256
|
-
|
|
4257
|
-
### \u{1F949} Challenge 1: Foundational Core (Bronze) \u2014 ~{{BRONZE_MINS}} mins
|
|
4258
|
-
**Objective:** {{BRONZE_OBJECTIVE}}
|
|
4259
|
-
|
|
4260
|
-
#### Tasks & Implementation Details:
|
|
4261
|
-
{{BRONZE_TASKS}}
|
|
4262
|
-
|
|
4263
|
-
#### \u{1F9EA} Self-Verification Command:
|
|
4264
|
-
\`\`\`bash
|
|
4265
|
-
{{BRONZE_VERIFY_COMMAND}}
|
|
4266
|
-
\`\`\`
|
|
4267
|
-
*Expected Terminal Output:*
|
|
4268
|
-
\`\`\`text
|
|
4269
|
-
{{BRONZE_EXPECTED_OUTPUT}}
|
|
4270
|
-
\`\`\`
|
|
4271
|
-
|
|
4272
|
-
#### \u{1F4A1} Progressive Hints (Expand only if stuck):
|
|
4273
|
-
<details>
|
|
4274
|
-
<summary><b>\u{1F4A1} Hint Level 1: Conceptual Clue (H\u01B0\u1EDBng t\u01B0 duy)</b></summary>
|
|
4275
|
-
|
|
4276
|
-
{{BRONZE_HINT_1}}
|
|
4277
|
-
</details>
|
|
4278
|
-
|
|
4279
|
-
<details>
|
|
4280
|
-
<summary><b>\u{1F50D} Hint Level 2: Structural Skeleton (Khung code m\u1EABu)</b></summary>
|
|
4281
|
-
|
|
4282
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4283
|
-
{{BRONZE_HINT_2}}
|
|
4284
|
-
\`\`\`
|
|
4285
|
-
</details>
|
|
4286
|
-
|
|
4287
|
-
<details>
|
|
4288
|
-
<summary><b>\u{1F6A8} Hint Level 3: Full Solution & Explanation (L\u1EDDi gi\u1EA3i tr\u1ECDn v\u1EB9n)</b></summary>
|
|
4289
|
-
|
|
4290
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4291
|
-
{{BRONZE_HINT_3_CODE}}
|
|
4292
|
-
\`\`\`
|
|
4293
|
-
|
|
4294
|
-
**Why this solution works:**
|
|
4295
|
-
{{BRONZE_HINT_3_EXPLANATION}}
|
|
4296
|
-
</details>
|
|
4297
|
-
|
|
4298
|
-
---
|
|
4299
|
-
|
|
4300
|
-
### \u{1F948} Challenge 2: Logic & Error Handling (Silver) \u2014 ~{{SILVER_MINS}} mins
|
|
4301
|
-
**Objective:** {{SILVER_OBJECTIVE}}
|
|
4302
|
-
|
|
4303
|
-
#### Tasks & Implementation Details:
|
|
4304
|
-
{{SILVER_TASKS}}
|
|
4305
|
-
|
|
4306
|
-
#### \u{1F9EA} Self-Verification Command:
|
|
4307
|
-
\`\`\`bash
|
|
4308
|
-
{{SILVER_VERIFY_COMMAND}}
|
|
4309
|
-
\`\`\`
|
|
4310
|
-
*Expected Terminal Output:*
|
|
4311
|
-
\`\`\`text
|
|
4312
|
-
{{SILVER_EXPECTED_OUTPUT}}
|
|
4313
|
-
\`\`\`
|
|
4314
|
-
|
|
4315
|
-
#### \u{1F4A1} Progressive Hints (Expand only if stuck):
|
|
4316
|
-
<details>
|
|
4317
|
-
<summary><b>\u{1F4A1} Hint Level 1: Conceptual Clue (H\u01B0\u1EDBng t\u01B0 duy)</b></summary>
|
|
4318
|
-
|
|
4319
|
-
{{SILVER_HINT_1}}
|
|
4320
|
-
</details>
|
|
4321
|
-
|
|
4322
|
-
<details>
|
|
4323
|
-
<summary><b>\u{1F50D} Hint Level 2: Structural Skeleton (Khung code m\u1EABu)</b></summary>
|
|
4324
|
-
|
|
4325
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4326
|
-
{{SILVER_HINT_2}}
|
|
4327
|
-
\`\`\`
|
|
4328
|
-
</details>
|
|
4329
|
-
|
|
4330
|
-
<details>
|
|
4331
|
-
<summary><b>\u{1F6A8} Hint Level 3: Full Solution & Explanation (L\u1EDDi gi\u1EA3i tr\u1ECDn v\u1EB9n)</b></summary>
|
|
4332
|
-
|
|
4333
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4334
|
-
{{SILVER_HINT_3_CODE}}
|
|
4335
|
-
\`\`\`
|
|
4336
|
-
|
|
4337
|
-
**Why this solution works:**
|
|
4338
|
-
{{SILVER_HINT_3_EXPLANATION}}
|
|
4339
|
-
</details>
|
|
4340
|
-
|
|
4341
|
-
---
|
|
4342
|
-
|
|
4343
|
-
### \u{1F947} Challenge 3: Edge Cases & Optimization (Gold) \u2014 ~{{GOLD_MINS}} mins
|
|
4344
|
-
**Objective:** {{GOLD_OBJECTIVE}}
|
|
4345
|
-
|
|
4346
|
-
#### Tasks & Implementation Details:
|
|
4347
|
-
{{GOLD_TASKS}}
|
|
4348
|
-
|
|
4349
|
-
#### \u{1F9EA} Self-Verification Command:
|
|
4350
|
-
\`\`\`bash
|
|
4351
|
-
{{GOLD_VERIFY_COMMAND}}
|
|
4352
|
-
\`\`\`
|
|
4353
|
-
*Expected Terminal Output:*
|
|
4354
|
-
\`\`\`text
|
|
4355
|
-
{{GOLD_EXPECTED_OUTPUT}}
|
|
4356
|
-
\`\`\`
|
|
4357
|
-
|
|
4358
|
-
#### \u{1F4A1} Progressive Hints (Expand only if stuck):
|
|
4359
|
-
<details>
|
|
4360
|
-
<summary><b>\u{1F4A1} Hint Level 1: Conceptual Clue (H\u01B0\u1EDBng t\u01B0 duy)</b></summary>
|
|
4361
|
-
|
|
4362
|
-
{{GOLD_HINT_1}}
|
|
4363
|
-
</details>
|
|
4364
|
-
|
|
4365
|
-
<details>
|
|
4366
|
-
<summary><b>\u{1F50D} Hint Level 2: Structural Skeleton (Khung code m\u1EABu)</b></summary>
|
|
4367
|
-
|
|
4368
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4369
|
-
{{GOLD_HINT_2}}
|
|
4370
|
-
\`\`\`
|
|
4371
|
-
</details>
|
|
4372
|
-
|
|
4373
|
-
<details>
|
|
4374
|
-
<summary><b>\u{1F6A8} Hint Level 3: Full Solution & Explanation (L\u1EDDi gi\u1EA3i tr\u1ECDn v\u1EB9n)</b></summary>
|
|
4375
|
-
|
|
4376
|
-
\`\`\`{{CODE_LANGUAGE}}
|
|
4377
|
-
{{GOLD_HINT_3_CODE}}
|
|
4378
|
-
\`\`\`
|
|
4379
|
-
|
|
4380
|
-
**Why this solution works:**
|
|
4381
|
-
{{GOLD_HINT_3_EXPLANATION}}
|
|
4382
|
-
</details>
|
|
4383
|
-
|
|
4384
|
-
---
|
|
4385
|
-
|
|
4386
|
-
## \u{1F50D} Self-Learner Troubleshooting Matrix
|
|
4387
|
-
| Symptom / Error Message | Root Cause | Exact Fix |
|
|
4388
|
-
| :--- | :--- | :--- |
|
|
4389
|
-
{{TROUBLESHOOTING_ROWS}}
|
|
4390
|
-
|
|
4391
|
-
---
|
|
4392
|
-
|
|
4393
|
-
## \u{1F3C1} Final Lab Submission & Mastery Checklist
|
|
4394
|
-
{{FINAL_CHECKLIST}}
|
|
4395
|
-
`.trim();
|
|
3935
|
+
function stripTemplateFrontmatter(raw) {
|
|
3936
|
+
let body = raw;
|
|
3937
|
+
if (body.startsWith("---")) {
|
|
3938
|
+
const end = body.indexOf("\n---", 3);
|
|
3939
|
+
if (end !== -1) body = body.slice(end + 4);
|
|
3940
|
+
}
|
|
3941
|
+
return body.split("\n").filter((l) => l.trim() !== "<!-- INJECT_BODY -->").join("\n").replace(/^\s*\n/, "").trimEnd();
|
|
3942
|
+
}
|
|
3943
|
+
function extractRequiredSections(raw) {
|
|
3944
|
+
const lines = raw.split("\n");
|
|
3945
|
+
const start = lines.findIndex((l) => /^template_required_sections:\s*$/.test(l.trim()));
|
|
3946
|
+
if (start === -1) return null;
|
|
3947
|
+
const items = [];
|
|
3948
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
3949
|
+
const line = lines[i] ?? "";
|
|
3950
|
+
if (line.trim() === "") continue;
|
|
3951
|
+
if (!/^\s+-\s/.test(line)) break;
|
|
3952
|
+
items.push(line.trim().replace(/^-\s+/, "").replace(/^["']|["']$/g, ""));
|
|
3953
|
+
}
|
|
3954
|
+
return items.length > 0 ? items : null;
|
|
3955
|
+
}
|
|
3956
|
+
function normalizeHeading(h) {
|
|
3957
|
+
return h.replace(/\[(REQUIRED|OPTIONAL|CONDITIONAL)\]\s*/gi, "").replace(/\s+/g, " ").trim();
|
|
3958
|
+
}
|
|
3959
|
+
function extractBodySections(raw) {
|
|
3960
|
+
const body = stripTemplateFrontmatter(raw);
|
|
3961
|
+
return body.split("\n").filter((l) => l.startsWith("## ")).map((l) => normalizeHeading(l.slice(3).trim())).filter((s) => s.length > 0);
|
|
3962
|
+
}
|
|
3963
|
+
var KIT_TEMPLATE_FALLBACK_DIRS = [
|
|
3964
|
+
// Packaged with the npm bundle (dist/templates) — resolves from node_modules.
|
|
3965
|
+
"templates",
|
|
3966
|
+
// Repo checkout layouts.
|
|
3967
|
+
"docs/refs/templates"
|
|
3968
|
+
];
|
|
3969
|
+
var _moduleDir = (() => {
|
|
3970
|
+
try {
|
|
3971
|
+
if (typeof import.meta !== "undefined" && typeof import.meta.url === "string") {
|
|
3972
|
+
return path4.dirname(fileURLToPath(import.meta.url));
|
|
3973
|
+
}
|
|
3974
|
+
} catch {
|
|
3975
|
+
}
|
|
3976
|
+
return typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
3977
|
+
})();
|
|
3978
|
+
function candidateDirs(explicitDir) {
|
|
3979
|
+
const dirs = [];
|
|
3980
|
+
if (explicitDir) dirs.push(explicitDir);
|
|
3981
|
+
if (process.env.CURRICULUM_TEMPLATES_DIR) dirs.push(process.env.CURRICULUM_TEMPLATES_DIR);
|
|
3982
|
+
dirs.push(path4.resolve(process.cwd(), "_templates"));
|
|
3983
|
+
for (const rel of KIT_TEMPLATE_FALLBACK_DIRS) {
|
|
3984
|
+
dirs.push(path4.resolve(_moduleDir, rel));
|
|
3985
|
+
dirs.push(path4.resolve(process.cwd(), rel));
|
|
3986
|
+
dirs.push(path4.resolve(process.cwd(), "packages/curriculum-kit", rel));
|
|
3987
|
+
}
|
|
3988
|
+
return dirs;
|
|
3989
|
+
}
|
|
3990
|
+
function findTemplatePath(templateName, explicitDir) {
|
|
3991
|
+
for (const dir of candidateDirs(explicitDir)) {
|
|
3992
|
+
const p = path4.join(dir, templateName);
|
|
3993
|
+
if (!fs3.existsSync(p)) continue;
|
|
3994
|
+
try {
|
|
3995
|
+
fs3.accessSync(p, fs3.constants.R_OK);
|
|
3996
|
+
return p;
|
|
3997
|
+
} catch {
|
|
3998
|
+
}
|
|
3999
|
+
}
|
|
4000
|
+
return null;
|
|
4001
|
+
}
|
|
4002
|
+
function resolveArtifactTemplate(templateName, opts) {
|
|
4003
|
+
const p = findTemplatePath(templateName, opts?.templatesDir);
|
|
4004
|
+
if (!p) return null;
|
|
4005
|
+
try {
|
|
4006
|
+
const raw = fs3.readFileSync(p, "utf-8");
|
|
4007
|
+
return {
|
|
4008
|
+
content: stripTemplateFrontmatter(raw),
|
|
4009
|
+
sections: extractRequiredSections(raw) ?? extractBodySections(raw),
|
|
4010
|
+
sourcePath: p
|
|
4011
|
+
};
|
|
4012
|
+
} catch {
|
|
4013
|
+
return null;
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
function loadCurriculumTemplate(templateName, templatesDir) {
|
|
4017
|
+
const p = findTemplatePath(templateName, templatesDir);
|
|
4018
|
+
if (!p) return "";
|
|
4019
|
+
try {
|
|
4020
|
+
return fs3.readFileSync(p, "utf-8");
|
|
4021
|
+
} catch {
|
|
4022
|
+
return "";
|
|
4023
|
+
}
|
|
4024
|
+
}
|
|
4025
|
+
function loadAuthoringTemplate(templateName, templatesDir) {
|
|
4026
|
+
const p = findTemplatePath(templateName, templatesDir);
|
|
4027
|
+
if (!p) return "";
|
|
4028
|
+
try {
|
|
4029
|
+
return stripTemplateFrontmatter(fs3.readFileSync(p, "utf-8"));
|
|
4030
|
+
} catch {
|
|
4031
|
+
return "";
|
|
4032
|
+
}
|
|
4033
|
+
}
|
|
4396
4034
|
|
|
4397
4035
|
// src/ai/prompts/lessonMasterPrompt.ts
|
|
4398
4036
|
function buildLessonMasterPrompt(input) {
|
|
@@ -4446,7 +4084,7 @@ Build a deep, rigorous, and highly pedagogical Master Lesson Plan (LESSON) that
|
|
|
4446
4084
|
# MANDATORY TEMPLATE STRUCTURE
|
|
4447
4085
|
You MUST generate structured data that will render directly into this exact Markdown template:
|
|
4448
4086
|
---
|
|
4449
|
-
${
|
|
4087
|
+
${loadAuthoringTemplate("LESSON_5E_template.md") ?? "[TEMPLATE FILE NOT FOUND: LESSON_5E_template.md]"}
|
|
4450
4088
|
---
|
|
4451
4089
|
|
|
4452
4090
|
# INPUT PARAMETERS
|
|
@@ -4524,7 +4162,7 @@ Transform the exact pedagogical flow and activities from the Master Lesson Plan
|
|
|
4524
4162
|
# MANDATORY TEMPLATE STRUCTURE
|
|
4525
4163
|
You MUST generate data aligned with this Markdown template:
|
|
4526
4164
|
---
|
|
4527
|
-
${
|
|
4165
|
+
${loadAuthoringTemplate("ACT_template.md") ?? "[TEMPLATE FILE NOT FOUND: ACT_template.md]"}
|
|
4528
4166
|
---
|
|
4529
4167
|
|
|
4530
4168
|
# CANONICAL MASTER LESSON CONTEXT (SOURCE OF TRUTH)
|
|
@@ -4619,7 +4257,7 @@ Generate complete, verified source code that satisfies the lesson objectives and
|
|
|
4619
4257
|
# MANDATORY TEMPLATE STRUCTURE
|
|
4620
4258
|
You MUST generate data aligned with this Markdown template:
|
|
4621
4259
|
---
|
|
4622
|
-
${
|
|
4260
|
+
${loadAuthoringTemplate("LAB_TEMPLATE.md") ?? "[TEMPLATE FILE NOT FOUND: LAB_TEMPLATE.md]"}
|
|
4623
4261
|
---
|
|
4624
4262
|
|
|
4625
4263
|
# CANONICAL LESSON CONTEXT (SOURCE OF TRUTH)
|
|
@@ -5314,7 +4952,7 @@ Build a complete, engaging Self-Paced Hands-On Lab (SELF_LAB) for autonomous lea
|
|
|
5314
4952
|
# MANDATORY TEMPLATE STRUCTURE
|
|
5315
4953
|
You MUST generate data aligned with this Markdown template:
|
|
5316
4954
|
---
|
|
5317
|
-
${
|
|
4955
|
+
${loadAuthoringTemplate("SELF_LAB_template.md") ?? "[TEMPLATE FILE NOT FOUND: SELF_LAB_template.md]"}
|
|
5318
4956
|
---
|
|
5319
4957
|
|
|
5320
4958
|
# INPUT PARAMETERS
|
|
@@ -5451,7 +5089,7 @@ Use this mapping to determine which Bloom level each question truly targets. Mat
|
|
|
5451
5089
|
# MANDATORY TEMPLATE STRUCTURE
|
|
5452
5090
|
You MUST generate data aligned with this Markdown template:
|
|
5453
5091
|
---
|
|
5454
|
-
${
|
|
5092
|
+
${loadAuthoringTemplate("QUIZ_v4.6_template.md") ?? "[TEMPLATE FILE NOT FOUND: QUIZ_v4.6_template.md]"}
|
|
5455
5093
|
---
|
|
5456
5094
|
|
|
5457
5095
|
# INPUT PARAMETERS
|
|
@@ -7748,13 +7386,13 @@ async function generateSelfPacedBundle(input) {
|
|
|
7748
7386
|
if (input.outputDirectory) {
|
|
7749
7387
|
await fsPromises.mkdir(input.outputDirectory, { recursive: true });
|
|
7750
7388
|
await Promise.all([
|
|
7751
|
-
fsPromises.writeFile(
|
|
7752
|
-
fsPromises.writeFile(
|
|
7753
|
-
fsPromises.writeFile(
|
|
7754
|
-
fsPromises.writeFile(
|
|
7755
|
-
fsPromises.writeFile(
|
|
7756
|
-
fsPromises.writeFile(
|
|
7757
|
-
fsPromises.writeFile(
|
|
7389
|
+
fsPromises.writeFile(path4.join(input.outputDirectory, "INSTRUCTION.md"), instructionMd, "utf-8"),
|
|
7390
|
+
fsPromises.writeFile(path4.join(input.outputDirectory, "SELF_LAB.md"), selfLabMd, "utf-8"),
|
|
7391
|
+
fsPromises.writeFile(path4.join(input.outputDirectory, "QUIZ.md"), quizMd, "utf-8"),
|
|
7392
|
+
fsPromises.writeFile(path4.join(input.outputDirectory, "QUIZ.json"), JSON.stringify(quiz, null, 2), "utf-8"),
|
|
7393
|
+
fsPromises.writeFile(path4.join(input.outputDirectory, "CHEAT_SHEET.md"), cheatSheetMd, "utf-8"),
|
|
7394
|
+
fsPromises.writeFile(path4.join(input.outputDirectory, "LAB.md"), codeLabMd, "utf-8"),
|
|
7395
|
+
fsPromises.writeFile(path4.join(input.outputDirectory, "bundle.json"), JSON.stringify(bundle, null, 2), "utf-8")
|
|
7758
7396
|
]);
|
|
7759
7397
|
}
|
|
7760
7398
|
return {
|
|
@@ -8155,15 +7793,15 @@ var STANDARD_SOT_FILES = [
|
|
|
8155
7793
|
"ALIGNMENT_MATRIX.md"
|
|
8156
7794
|
];
|
|
8157
7795
|
function atomicWriteFileSync(targetPath, content) {
|
|
8158
|
-
const dir =
|
|
8159
|
-
if (!
|
|
8160
|
-
const tmpPath =
|
|
7796
|
+
const dir = path4.dirname(targetPath);
|
|
7797
|
+
if (!fs3.existsSync(dir)) fs3.mkdirSync(dir, { recursive: true });
|
|
7798
|
+
const tmpPath = path4.join(dir, `.${path4.basename(targetPath)}.${process.pid}.${Date.now()}.${crypto.randomBytes(4).toString("hex")}.tmp`);
|
|
8161
7799
|
try {
|
|
8162
|
-
|
|
8163
|
-
|
|
7800
|
+
fs3.writeFileSync(tmpPath, content, "utf-8");
|
|
7801
|
+
fs3.renameSync(tmpPath, targetPath);
|
|
8164
7802
|
} catch (err) {
|
|
8165
7803
|
try {
|
|
8166
|
-
if (
|
|
7804
|
+
if (fs3.existsSync(tmpPath)) fs3.unlinkSync(tmpPath);
|
|
8167
7805
|
} catch {
|
|
8168
7806
|
}
|
|
8169
7807
|
throw err;
|
|
@@ -8172,51 +7810,51 @@ function atomicWriteFileSync(targetPath, content) {
|
|
|
8172
7810
|
var FileSystemCurriculumAdapter = class {
|
|
8173
7811
|
baseDir;
|
|
8174
7812
|
constructor(options = {}) {
|
|
8175
|
-
this.baseDir = options.baseDir ||
|
|
7813
|
+
this.baseDir = options.baseDir || path4.resolve(process.cwd(), "output", "projects");
|
|
8176
7814
|
}
|
|
8177
7815
|
getProjectDir(projectId) {
|
|
8178
7816
|
const raw = (projectId || "").replace("proj_", "");
|
|
8179
|
-
const directPath =
|
|
8180
|
-
if (
|
|
8181
|
-
const fullIdPath =
|
|
8182
|
-
if (
|
|
7817
|
+
const directPath = path4.join(this.baseDir, raw);
|
|
7818
|
+
if (fs3.existsSync(directPath)) return directPath;
|
|
7819
|
+
const fullIdPath = path4.join(this.baseDir, projectId);
|
|
7820
|
+
if (fs3.existsSync(fullIdPath)) return fullIdPath;
|
|
8183
7821
|
return directPath;
|
|
8184
7822
|
}
|
|
8185
7823
|
/** Ensures the resolved path stays within the project directory (prevents path traversal). */
|
|
8186
7824
|
assertInsideProject(projectDir, targetPath) {
|
|
8187
|
-
const resolvedProject =
|
|
8188
|
-
const resolvedTarget =
|
|
8189
|
-
if (!resolvedTarget.startsWith(resolvedProject +
|
|
7825
|
+
const resolvedProject = path4.resolve(projectDir);
|
|
7826
|
+
const resolvedTarget = path4.resolve(targetPath);
|
|
7827
|
+
if (!resolvedTarget.startsWith(resolvedProject + path4.sep) && resolvedTarget !== resolvedProject) {
|
|
8190
7828
|
throw new Error(`[FileSystemCurriculumAdapter] Path traversal blocked: ${targetPath} is outside project directory ${projectDir}`);
|
|
8191
7829
|
}
|
|
8192
7830
|
}
|
|
8193
7831
|
async projectExists(projectId) {
|
|
8194
|
-
return
|
|
7832
|
+
return fs3.existsSync(this.getProjectDir(projectId));
|
|
8195
7833
|
}
|
|
8196
7834
|
async readSotDocument(projectId, filename) {
|
|
8197
7835
|
const projectDir = this.getProjectDir(projectId);
|
|
8198
7836
|
const possiblePaths = [
|
|
8199
|
-
|
|
8200
|
-
|
|
7837
|
+
path4.join(projectDir, "_sot", filename),
|
|
7838
|
+
path4.join(projectDir, filename)
|
|
8201
7839
|
];
|
|
8202
7840
|
for (const p of possiblePaths) {
|
|
8203
|
-
if (
|
|
8204
|
-
return
|
|
7841
|
+
if (fs3.existsSync(p) && fs3.statSync(p).isFile()) {
|
|
7842
|
+
return fs3.readFileSync(p, "utf-8");
|
|
8205
7843
|
}
|
|
8206
7844
|
}
|
|
8207
7845
|
return null;
|
|
8208
7846
|
}
|
|
8209
7847
|
async listSotDocuments(projectId) {
|
|
8210
7848
|
const projectDir = this.getProjectDir(projectId);
|
|
8211
|
-
const sotDir =
|
|
7849
|
+
const sotDir = path4.join(projectDir, "_sot");
|
|
8212
7850
|
const discoveredFiles = new Set(STANDARD_SOT_FILES);
|
|
8213
|
-
if (
|
|
7851
|
+
if (fs3.existsSync(sotDir)) {
|
|
8214
7852
|
try {
|
|
8215
|
-
const diskFiles =
|
|
7853
|
+
const diskFiles = fs3.readdirSync(sotDir);
|
|
8216
7854
|
for (const f of diskFiles) {
|
|
8217
7855
|
if (f.startsWith(".") || f.endsWith(".review.json")) continue;
|
|
8218
|
-
const fullPath =
|
|
8219
|
-
if (
|
|
7856
|
+
const fullPath = path4.join(sotDir, f);
|
|
7857
|
+
if (fs3.statSync(fullPath).isFile()) {
|
|
8220
7858
|
discoveredFiles.add(f);
|
|
8221
7859
|
}
|
|
8222
7860
|
}
|
|
@@ -8224,9 +7862,9 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8224
7862
|
}
|
|
8225
7863
|
}
|
|
8226
7864
|
return Array.from(discoveredFiles).map((filename) => {
|
|
8227
|
-
const p =
|
|
8228
|
-
if (p &&
|
|
8229
|
-
const stats =
|
|
7865
|
+
const p = fs3.existsSync(path4.join(sotDir, filename)) ? path4.join(sotDir, filename) : fs3.existsSync(path4.join(projectDir, filename)) ? path4.join(projectDir, filename) : null;
|
|
7866
|
+
if (p && fs3.existsSync(p)) {
|
|
7867
|
+
const stats = fs3.statSync(p);
|
|
8230
7868
|
return {
|
|
8231
7869
|
name: filename.replace(/\.(md|json)$/i, "").replace(/_/g, " "),
|
|
8232
7870
|
filename,
|
|
@@ -8244,18 +7882,18 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8244
7882
|
}
|
|
8245
7883
|
async readArtifact(projectId, relPathOrIdentifier) {
|
|
8246
7884
|
const projectDir = this.getProjectDir(projectId);
|
|
8247
|
-
const directCandidate =
|
|
7885
|
+
const directCandidate = path4.join(projectDir, relPathOrIdentifier);
|
|
8248
7886
|
this.assertInsideProject(projectDir, directCandidate);
|
|
8249
7887
|
const possiblePaths = [
|
|
8250
7888
|
directCandidate,
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
|
|
7889
|
+
path4.join(projectDir, "_sot", relPathOrIdentifier),
|
|
7890
|
+
path4.join(projectDir, "lessons", relPathOrIdentifier),
|
|
7891
|
+
path4.join(projectDir, "_sot", path4.basename(relPathOrIdentifier)),
|
|
7892
|
+
path4.join(projectDir, "lessons", path4.basename(relPathOrIdentifier))
|
|
8255
7893
|
];
|
|
8256
7894
|
for (const p of possiblePaths) {
|
|
8257
|
-
if (
|
|
8258
|
-
return
|
|
7895
|
+
if (fs3.existsSync(p) && fs3.statSync(p).isFile()) {
|
|
7896
|
+
return fs3.readFileSync(p, "utf-8");
|
|
8259
7897
|
}
|
|
8260
7898
|
}
|
|
8261
7899
|
if (relPathOrIdentifier.includes(".md") || relPathOrIdentifier.includes("/")) {
|
|
@@ -8264,8 +7902,8 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8264
7902
|
const lessonMatch = relPathOrIdentifier.match(/U\d+_M\d+_L\d+/i);
|
|
8265
7903
|
if (lessonMatch) {
|
|
8266
7904
|
const lessonId = lessonMatch[0].toUpperCase();
|
|
8267
|
-
const lessonDir =
|
|
8268
|
-
if (
|
|
7905
|
+
const lessonDir = path4.join(projectDir, "lessons", lessonId);
|
|
7906
|
+
if (fs3.existsSync(lessonDir) && fs3.statSync(lessonDir).isDirectory()) {
|
|
8269
7907
|
const lower = relPathOrIdentifier.toLowerCase();
|
|
8270
7908
|
let artifactPrefix = "LESSON";
|
|
8271
7909
|
if (lower.includes("act") || lower.includes("lab") || lower.includes("th\u1EF1c h\xE0nh")) {
|
|
@@ -8285,9 +7923,9 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8285
7923
|
} else if (lower.includes("ext") || lower.includes("extension")) {
|
|
8286
7924
|
artifactPrefix = "EXT";
|
|
8287
7925
|
}
|
|
8288
|
-
const candidateFile =
|
|
8289
|
-
if (
|
|
8290
|
-
return
|
|
7926
|
+
const candidateFile = path4.join(lessonDir, `${artifactPrefix}_${lessonId}.md`);
|
|
7927
|
+
if (fs3.existsSync(candidateFile)) {
|
|
7928
|
+
return fs3.readFileSync(candidateFile, "utf-8");
|
|
8291
7929
|
}
|
|
8292
7930
|
}
|
|
8293
7931
|
}
|
|
@@ -8295,22 +7933,22 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8295
7933
|
}
|
|
8296
7934
|
async saveArtifact(projectId, relPath, content) {
|
|
8297
7935
|
const projectDir = this.getProjectDir(projectId);
|
|
8298
|
-
const targetPath =
|
|
7936
|
+
const targetPath = path4.join(projectDir, relPath);
|
|
8299
7937
|
this.assertInsideProject(projectDir, targetPath);
|
|
8300
|
-
const targetDir =
|
|
8301
|
-
if (!
|
|
8302
|
-
|
|
7938
|
+
const targetDir = path4.dirname(targetPath);
|
|
7939
|
+
if (!fs3.existsSync(targetDir)) {
|
|
7940
|
+
fs3.mkdirSync(targetDir, { recursive: true });
|
|
8303
7941
|
}
|
|
8304
|
-
if (
|
|
7942
|
+
if (fs3.existsSync(targetPath)) {
|
|
8305
7943
|
try {
|
|
8306
|
-
const oldContent =
|
|
7944
|
+
const oldContent = fs3.readFileSync(targetPath, "utf-8");
|
|
8307
7945
|
if (oldContent !== content) {
|
|
8308
|
-
const historyDir =
|
|
8309
|
-
|
|
8310
|
-
atomicWriteFileSync(
|
|
8311
|
-
const versions =
|
|
7946
|
+
const historyDir = path4.join(projectDir, ".history", relPath);
|
|
7947
|
+
fs3.mkdirSync(historyDir, { recursive: true });
|
|
7948
|
+
atomicWriteFileSync(path4.join(historyDir, `${Date.now()}.md`), oldContent);
|
|
7949
|
+
const versions = fs3.readdirSync(historyDir).filter((f) => f.endsWith(".md")).sort();
|
|
8312
7950
|
while (versions.length > 10) {
|
|
8313
|
-
|
|
7951
|
+
fs3.unlinkSync(path4.join(historyDir, versions.shift()));
|
|
8314
7952
|
}
|
|
8315
7953
|
}
|
|
8316
7954
|
} catch (histErr) {
|
|
@@ -8318,24 +7956,24 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8318
7956
|
}
|
|
8319
7957
|
}
|
|
8320
7958
|
atomicWriteFileSync(targetPath, content);
|
|
8321
|
-
const filename =
|
|
7959
|
+
const filename = path4.basename(relPath);
|
|
8322
7960
|
const match = filename.match(/(LESSON|ACT|QUIZ|SLIDE|GUIDE|HANDOUT|WKS|EXT)_(U\d+_M\d+_L\d+)\.md/i);
|
|
8323
7961
|
if (match) {
|
|
8324
7962
|
const lessonId = match[2].toUpperCase();
|
|
8325
|
-
atomicWriteFileSync(
|
|
8326
|
-
const legacyContentDir =
|
|
8327
|
-
if (
|
|
8328
|
-
atomicWriteFileSync(
|
|
7963
|
+
atomicWriteFileSync(path4.join(projectDir, "lessons", lessonId, filename), content);
|
|
7964
|
+
const legacyContentDir = path4.join(projectDir, "_content", lessonId);
|
|
7965
|
+
if (fs3.existsSync(legacyContentDir)) {
|
|
7966
|
+
atomicWriteFileSync(path4.join(legacyContentDir, filename), content);
|
|
8329
7967
|
}
|
|
8330
7968
|
}
|
|
8331
7969
|
}
|
|
8332
7970
|
async listLessons(projectId) {
|
|
8333
|
-
const lessonsDir =
|
|
8334
|
-
if (!
|
|
8335
|
-
const lessonFolders =
|
|
7971
|
+
const lessonsDir = path4.join(this.getProjectDir(projectId), "lessons");
|
|
7972
|
+
if (!fs3.existsSync(lessonsDir)) return [];
|
|
7973
|
+
const lessonFolders = fs3.readdirSync(lessonsDir).filter((f) => !f.startsWith("."));
|
|
8336
7974
|
return lessonFolders.map((folder) => {
|
|
8337
|
-
const lDir =
|
|
8338
|
-
const isDir =
|
|
7975
|
+
const lDir = path4.join(lessonsDir, folder);
|
|
7976
|
+
const isDir = fs3.statSync(lDir).isDirectory();
|
|
8339
7977
|
if (!isDir) {
|
|
8340
7978
|
return {
|
|
8341
7979
|
lessonId: folder,
|
|
@@ -8344,7 +7982,7 @@ var FileSystemCurriculumAdapter = class {
|
|
|
8344
7982
|
artifacts: []
|
|
8345
7983
|
};
|
|
8346
7984
|
}
|
|
8347
|
-
const artifacts =
|
|
7985
|
+
const artifacts = fs3.readdirSync(lDir).filter((f) => !f.startsWith("."));
|
|
8348
7986
|
return {
|
|
8349
7987
|
lessonId: folder,
|
|
8350
7988
|
artifactsCount: artifacts.length,
|
|
@@ -8390,10 +8028,10 @@ ${lessonTable}
|
|
|
8390
8028
|
}
|
|
8391
8029
|
async getPipelineState(projectId) {
|
|
8392
8030
|
const projectDir = this.getProjectDir(projectId);
|
|
8393
|
-
const stateFile =
|
|
8394
|
-
if (
|
|
8031
|
+
const stateFile = path4.join(projectDir, "_pipeline", "state.json");
|
|
8032
|
+
if (fs3.existsSync(stateFile)) {
|
|
8395
8033
|
try {
|
|
8396
|
-
const raw =
|
|
8034
|
+
const raw = fs3.readFileSync(stateFile, "utf-8");
|
|
8397
8035
|
const parsed = JSON.parse(raw);
|
|
8398
8036
|
if (parsed && typeof parsed === "object" && parsed.tasks) {
|
|
8399
8037
|
return parsed;
|
|
@@ -8410,11 +8048,11 @@ ${lessonTable}
|
|
|
8410
8048
|
}
|
|
8411
8049
|
async savePipelineState(projectId, state) {
|
|
8412
8050
|
const projectDir = this.getProjectDir(projectId);
|
|
8413
|
-
const pipelineDir =
|
|
8414
|
-
if (!
|
|
8415
|
-
|
|
8051
|
+
const pipelineDir = path4.join(projectDir, "_pipeline");
|
|
8052
|
+
if (!fs3.existsSync(pipelineDir)) {
|
|
8053
|
+
fs3.mkdirSync(pipelineDir, { recursive: true });
|
|
8416
8054
|
}
|
|
8417
|
-
const stateFile =
|
|
8055
|
+
const stateFile = path4.join(pipelineDir, "state.json");
|
|
8418
8056
|
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8419
8057
|
atomicWriteFileSync(stateFile, JSON.stringify(state, null, 2));
|
|
8420
8058
|
}
|
|
@@ -8437,9 +8075,9 @@ ${lessonTable}
|
|
|
8437
8075
|
async deleteArtifact(projectId, relPath) {
|
|
8438
8076
|
try {
|
|
8439
8077
|
const projectDir = this.getProjectDir(projectId);
|
|
8440
|
-
const targetPath =
|
|
8078
|
+
const targetPath = path4.join(projectDir, relPath);
|
|
8441
8079
|
this.assertInsideProject(projectDir, targetPath);
|
|
8442
|
-
if (
|
|
8080
|
+
if (fs3.existsSync(targetPath)) fs3.rmSync(targetPath, { force: true });
|
|
8443
8081
|
} catch {
|
|
8444
8082
|
}
|
|
8445
8083
|
}
|
|
@@ -9189,19 +8827,19 @@ function buildStandardStackMarkdown(opts) {
|
|
|
9189
8827
|
|
|
9190
8828
|
// src/services/sotGeneratorService.ts
|
|
9191
8829
|
var __filename$1 = typeof import.meta?.url === "string" && typeof fileURLToPath === "function" ? fileURLToPath(import.meta.url) : "";
|
|
9192
|
-
var __dirname2 = __filename$1 ?
|
|
8830
|
+
var __dirname2 = __filename$1 ? path4.dirname(__filename$1) : process.cwd();
|
|
9193
8831
|
function loadSotTemplate(templateFileName) {
|
|
9194
8832
|
const possiblePaths = [
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
8833
|
+
path4.resolve(__dirname2, "../../docs/refs/templates", templateFileName),
|
|
8834
|
+
path4.resolve(process.cwd(), "packages/curriculum-kit/docs/refs/templates", templateFileName),
|
|
8835
|
+
path4.resolve(process.cwd(), "../learnwell-platform/packages/curriculum-kit/docs/refs/templates", templateFileName),
|
|
8836
|
+
path4.resolve("/Users/tonypham/MEGA/WebApp/WIP/learnwell-platform/packages/curriculum-kit/docs/refs/templates", templateFileName),
|
|
8837
|
+
path4.resolve("/Users/tonypham/MEGA/ai-platform/learning-artifact-gen-ui/_templates", templateFileName)
|
|
9200
8838
|
];
|
|
9201
8839
|
for (const p of possiblePaths) {
|
|
9202
|
-
if (
|
|
8840
|
+
if (fs3.existsSync(p)) {
|
|
9203
8841
|
try {
|
|
9204
|
-
return
|
|
8842
|
+
return fs3.readFileSync(p, "utf-8");
|
|
9205
8843
|
} catch {
|
|
9206
8844
|
}
|
|
9207
8845
|
}
|
|
@@ -10216,7 +9854,7 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
|
|
|
10216
9854
|
if (s.canonicalKey && !byCanonical.has(s.canonicalKey)) {
|
|
10217
9855
|
byCanonical.set(s.canonicalKey, s);
|
|
10218
9856
|
}
|
|
10219
|
-
const norm2 =
|
|
9857
|
+
const norm2 = normalizeHeading2(s.cleanTitle);
|
|
10220
9858
|
if (!byCleanTitle.has(norm2)) {
|
|
10221
9859
|
byCleanTitle.set(norm2, s);
|
|
10222
9860
|
}
|
|
@@ -10266,7 +9904,7 @@ ${truncated}`;
|
|
|
10266
9904
|
blocks.push(metaBlock);
|
|
10267
9905
|
let sectionAware = false;
|
|
10268
9906
|
for (const key of priorities) {
|
|
10269
|
-
const sec = byCanonical.get(key) || byCleanTitle.get(
|
|
9907
|
+
const sec = byCanonical.get(key) || byCleanTitle.get(normalizeHeading2(key));
|
|
10270
9908
|
if (!sec) continue;
|
|
10271
9909
|
sectionAware = true;
|
|
10272
9910
|
if (!tryAdd(sec.cleanTitle, sec.body, key)) break;
|
|
@@ -10348,15 +9986,15 @@ function parseMarkdownSections(markdown, slcMap, artifactType) {
|
|
|
10348
9986
|
const maps = artifactType && slcMap[artifactType] ? [slcMap[artifactType]] : Object.values(slcMap);
|
|
10349
9987
|
for (const m of maps) {
|
|
10350
9988
|
for (const [canonical, localized] of Object.entries(m)) {
|
|
10351
|
-
reverseMap.set(
|
|
10352
|
-
reverseMap.set(
|
|
9989
|
+
reverseMap.set(normalizeHeading2(localized), canonical);
|
|
9990
|
+
reverseMap.set(normalizeHeading2(canonical), canonical);
|
|
10353
9991
|
}
|
|
10354
9992
|
}
|
|
10355
9993
|
}
|
|
10356
9994
|
const flush = () => {
|
|
10357
9995
|
if (!currentHeading) return;
|
|
10358
9996
|
const cleanTitle = currentHeading.replace(/^#{1,4}\s+/, "").trim();
|
|
10359
|
-
const norm2 =
|
|
9997
|
+
const norm2 = normalizeHeading2(cleanTitle);
|
|
10360
9998
|
const canonicalKey = reverseMap.get(norm2) || findCanonicalFuzzy(norm2);
|
|
10361
9999
|
sections.push({
|
|
10362
10000
|
rawHeading: currentHeading,
|
|
@@ -10380,7 +10018,7 @@ function parseMarkdownSections(markdown, slcMap, artifactType) {
|
|
|
10380
10018
|
flush();
|
|
10381
10019
|
return sections;
|
|
10382
10020
|
}
|
|
10383
|
-
function
|
|
10021
|
+
function normalizeHeading2(str) {
|
|
10384
10022
|
return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
10385
10023
|
}
|
|
10386
10024
|
function findCanonicalFuzzy(norm2) {
|
|
@@ -25449,96 +25087,6 @@ function evaluateActivityAlignment(canonicalExcerpt, generatedContent, now = /*
|
|
|
25449
25087
|
const passed = matchedTokens.length > 0;
|
|
25450
25088
|
return { checked: true, passed, matchedTokens: matchedTokens.slice(0, 10), missingTokens: missingTokens.slice(0, 10), mode };
|
|
25451
25089
|
}
|
|
25452
|
-
function stripTemplateFrontmatter(raw) {
|
|
25453
|
-
let body = raw;
|
|
25454
|
-
if (body.startsWith("---")) {
|
|
25455
|
-
const end = body.indexOf("\n---", 3);
|
|
25456
|
-
if (end !== -1) body = body.slice(end + 4);
|
|
25457
|
-
}
|
|
25458
|
-
return body.split("\n").filter((l) => l.trim() !== "<!-- INJECT_BODY -->").join("\n").replace(/^\s*\n/, "").trimEnd();
|
|
25459
|
-
}
|
|
25460
|
-
function extractRequiredSections(raw) {
|
|
25461
|
-
const lines = raw.split("\n");
|
|
25462
|
-
const start = lines.findIndex((l) => /^template_required_sections:\s*$/.test(l.trim()));
|
|
25463
|
-
if (start === -1) return null;
|
|
25464
|
-
const items = [];
|
|
25465
|
-
for (let i = start + 1; i < lines.length; i++) {
|
|
25466
|
-
const line = lines[i] ?? "";
|
|
25467
|
-
if (line.trim() === "") continue;
|
|
25468
|
-
if (!/^\s+-\s/.test(line)) break;
|
|
25469
|
-
items.push(line.trim().replace(/^-\s+/, "").replace(/^["']|["']$/g, ""));
|
|
25470
|
-
}
|
|
25471
|
-
return items.length > 0 ? items : null;
|
|
25472
|
-
}
|
|
25473
|
-
function normalizeHeading2(h) {
|
|
25474
|
-
return h.replace(/\[(REQUIRED|OPTIONAL|CONDITIONAL)\]\s*/gi, "").replace(/\s+/g, " ").trim();
|
|
25475
|
-
}
|
|
25476
|
-
function extractBodySections(raw) {
|
|
25477
|
-
const body = stripTemplateFrontmatter(raw);
|
|
25478
|
-
return body.split("\n").filter((l) => l.startsWith("## ")).map((l) => normalizeHeading2(l.slice(3).trim())).filter((s) => s.length > 0);
|
|
25479
|
-
}
|
|
25480
|
-
var KIT_TEMPLATE_FALLBACK_DIRS = [
|
|
25481
|
-
// Packaged with the npm bundle (dist/templates) — resolves from node_modules.
|
|
25482
|
-
"templates",
|
|
25483
|
-
// Repo checkout layouts.
|
|
25484
|
-
"docs/refs/templates"
|
|
25485
|
-
];
|
|
25486
|
-
var _moduleDir = (() => {
|
|
25487
|
-
try {
|
|
25488
|
-
if (typeof import.meta !== "undefined" && typeof import.meta.url === "string") {
|
|
25489
|
-
return path3.dirname(fileURLToPath(import.meta.url));
|
|
25490
|
-
}
|
|
25491
|
-
} catch {
|
|
25492
|
-
}
|
|
25493
|
-
return typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
25494
|
-
})();
|
|
25495
|
-
function candidateDirs(explicitDir) {
|
|
25496
|
-
const dirs = [];
|
|
25497
|
-
if (explicitDir) dirs.push(explicitDir);
|
|
25498
|
-
if (process.env.CURRICULUM_TEMPLATES_DIR) dirs.push(process.env.CURRICULUM_TEMPLATES_DIR);
|
|
25499
|
-
dirs.push(path3.resolve(process.cwd(), "_templates"));
|
|
25500
|
-
for (const rel of KIT_TEMPLATE_FALLBACK_DIRS) {
|
|
25501
|
-
dirs.push(path3.resolve(_moduleDir, rel));
|
|
25502
|
-
dirs.push(path3.resolve(process.cwd(), rel));
|
|
25503
|
-
dirs.push(path3.resolve(process.cwd(), "packages/curriculum-kit", rel));
|
|
25504
|
-
}
|
|
25505
|
-
return dirs;
|
|
25506
|
-
}
|
|
25507
|
-
function findTemplatePath(templateName, explicitDir) {
|
|
25508
|
-
for (const dir of candidateDirs(explicitDir)) {
|
|
25509
|
-
const p = path3.join(dir, templateName);
|
|
25510
|
-
if (!fs2.existsSync(p)) continue;
|
|
25511
|
-
try {
|
|
25512
|
-
fs2.accessSync(p, fs2.constants.R_OK);
|
|
25513
|
-
return p;
|
|
25514
|
-
} catch {
|
|
25515
|
-
}
|
|
25516
|
-
}
|
|
25517
|
-
return null;
|
|
25518
|
-
}
|
|
25519
|
-
function resolveArtifactTemplate(templateName, opts) {
|
|
25520
|
-
const p = findTemplatePath(templateName, opts?.templatesDir);
|
|
25521
|
-
if (!p) return null;
|
|
25522
|
-
try {
|
|
25523
|
-
const raw = fs2.readFileSync(p, "utf-8");
|
|
25524
|
-
return {
|
|
25525
|
-
content: stripTemplateFrontmatter(raw),
|
|
25526
|
-
sections: extractRequiredSections(raw) ?? extractBodySections(raw),
|
|
25527
|
-
sourcePath: p
|
|
25528
|
-
};
|
|
25529
|
-
} catch {
|
|
25530
|
-
return null;
|
|
25531
|
-
}
|
|
25532
|
-
}
|
|
25533
|
-
function loadCurriculumTemplate(templateName, templatesDir) {
|
|
25534
|
-
const p = findTemplatePath(templateName, templatesDir);
|
|
25535
|
-
if (!p) return "";
|
|
25536
|
-
try {
|
|
25537
|
-
return fs2.readFileSync(p, "utf-8");
|
|
25538
|
-
} catch {
|
|
25539
|
-
return "";
|
|
25540
|
-
}
|
|
25541
|
-
}
|
|
25542
25090
|
|
|
25543
25091
|
// src/services/lessonProductionService.ts
|
|
25544
25092
|
var LESSON_TEMPLATE_BY_PEDAGOGY = {
|
|
@@ -25550,10 +25098,11 @@ var LESSON_TEMPLATE_BY_PEDAGOGY = {
|
|
|
25550
25098
|
function buildArtifactPrompt(parts, opts) {
|
|
25551
25099
|
const resolved = resolveArtifactTemplate(parts.templateFile, opts);
|
|
25552
25100
|
const body = resolved?.content ?? parts.epilogue ?? "";
|
|
25553
|
-
|
|
25554
|
-
|
|
25555
|
-
` : "\
|
|
25556
|
-
|
|
25101
|
+
return `${parts.directive}
|
|
25102
|
+
|
|
25103
|
+
===== ARTIFACT TEMPLATE: ${parts.templateFile} ${resolved ? `(loaded from ${resolved.sourcePath})` : "(\u26A0\uFE0F NOT FOUND \u2014 inline fallback scaffold in use)"} =====
|
|
25104
|
+
|
|
25105
|
+
${body}`;
|
|
25557
25106
|
}
|
|
25558
25107
|
var NO_VERBATIM_COPYING = `
|
|
25559
25108
|
VERBATIM SOURCING RULE: When a section in the template says to extract a table
|
|
@@ -25753,6 +25302,10 @@ type: "${artifactType}"
|
|
|
25753
25302
|
and respect the template's OWNERSHIP note: each fact lives in exactly ONE
|
|
25754
25303
|
section \u2014 never restate satellite lists, resources, or assessment content
|
|
25755
25304
|
across sections, and never embed KX-owned question banks or self-check text.
|
|
25305
|
+
3. In the Learning Objectives table, carry the Standard ID from the [STANDARDS
|
|
25306
|
+
STATEMENTS] context into the same row as its LO (e.g. "CSTA: 1B-AP-10")
|
|
25307
|
+
when a matching standard exists.
|
|
25308
|
+
4. Every code sample must be 100% syntax-valid and executable.
|
|
25756
25309
|
3. Use the exact vocabulary of the canonical knowledge context for every
|
|
25757
25310
|
concept and term.
|
|
25758
25311
|
${NO_VERBATIM_COPYING}`;
|
|
@@ -29475,10 +29028,10 @@ init_slideProductionWorkflow();
|
|
|
29475
29028
|
var LocalWorkspaceManager = class {
|
|
29476
29029
|
baseDir;
|
|
29477
29030
|
constructor(baseDir) {
|
|
29478
|
-
this.baseDir = baseDir ||
|
|
29031
|
+
this.baseDir = baseDir || path4.resolve(process.cwd(), "output", "workspace-jobs");
|
|
29479
29032
|
}
|
|
29480
29033
|
getJobDirectory(jobId) {
|
|
29481
|
-
return
|
|
29034
|
+
return path4.join(this.baseDir, jobId);
|
|
29482
29035
|
}
|
|
29483
29036
|
async initJobWorkspace(jobId, initialInfo) {
|
|
29484
29037
|
const jobDir = this.getJobDirectory(jobId);
|
|
@@ -29501,9 +29054,9 @@ var LocalWorkspaceManager = class {
|
|
|
29501
29054
|
}
|
|
29502
29055
|
async saveArtifact(jobId, milestoneSlug, filename, content, artifactType) {
|
|
29503
29056
|
const jobDir = this.getJobDirectory(jobId);
|
|
29504
|
-
const targetDir =
|
|
29057
|
+
const targetDir = path4.join(jobDir, milestoneSlug);
|
|
29505
29058
|
await fsPromises.mkdir(targetDir, { recursive: true });
|
|
29506
|
-
const filePath =
|
|
29059
|
+
const filePath = path4.join(targetDir, filename);
|
|
29507
29060
|
await fsPromises.writeFile(filePath, content, "utf-8");
|
|
29508
29061
|
const stat = await fsPromises.stat(filePath);
|
|
29509
29062
|
const manifest = await this.getManifest(jobId);
|
|
@@ -29511,7 +29064,7 @@ var LocalWorkspaceManager = class {
|
|
|
29511
29064
|
manifest.artifacts.push({
|
|
29512
29065
|
milestoneId: milestoneSlug,
|
|
29513
29066
|
artifactType,
|
|
29514
|
-
filePath:
|
|
29067
|
+
filePath: path4.relative(jobDir, filePath),
|
|
29515
29068
|
sizeBytes: stat.size,
|
|
29516
29069
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
29517
29070
|
});
|
|
@@ -29521,7 +29074,7 @@ var LocalWorkspaceManager = class {
|
|
|
29521
29074
|
return filePath;
|
|
29522
29075
|
}
|
|
29523
29076
|
async getManifest(jobId) {
|
|
29524
|
-
const manifestPath =
|
|
29077
|
+
const manifestPath = path4.join(this.getJobDirectory(jobId), "manifest.json");
|
|
29525
29078
|
try {
|
|
29526
29079
|
const data = await fsPromises.readFile(manifestPath, "utf-8");
|
|
29527
29080
|
return JSON.parse(data);
|
|
@@ -29530,7 +29083,7 @@ var LocalWorkspaceManager = class {
|
|
|
29530
29083
|
}
|
|
29531
29084
|
}
|
|
29532
29085
|
async saveManifest(jobId, manifest) {
|
|
29533
|
-
const manifestPath =
|
|
29086
|
+
const manifestPath = path4.join(this.getJobDirectory(jobId), "manifest.json");
|
|
29534
29087
|
manifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
29535
29088
|
await fsPromises.writeFile(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
29536
29089
|
}
|
|
@@ -29571,12 +29124,12 @@ async function publishToGitHub(options) {
|
|
|
29571
29124
|
async function scanDir(currentDir) {
|
|
29572
29125
|
const entries = await fsPromises.readdir(currentDir, { withFileTypes: true });
|
|
29573
29126
|
for (const entry of entries) {
|
|
29574
|
-
const fullPath =
|
|
29127
|
+
const fullPath = path4.join(currentDir, entry.name);
|
|
29575
29128
|
if (entry.isDirectory()) {
|
|
29576
29129
|
await scanDir(fullPath);
|
|
29577
29130
|
} else if (entry.isFile() && !entry.name.startsWith(".")) {
|
|
29578
29131
|
const content = await fsPromises.readFile(fullPath, "utf-8");
|
|
29579
|
-
const relPath =
|
|
29132
|
+
const relPath = path4.relative(options.localJobDir, fullPath);
|
|
29580
29133
|
filesToUpload.push({ path: relPath, content });
|
|
29581
29134
|
}
|
|
29582
29135
|
}
|
|
@@ -31682,13 +31235,13 @@ var MediaLedger = class {
|
|
|
31682
31235
|
filePath;
|
|
31683
31236
|
entries = /* @__PURE__ */ new Map();
|
|
31684
31237
|
constructor(projectDir, lessonId) {
|
|
31685
|
-
this.filePath =
|
|
31238
|
+
this.filePath = path4.join(projectDir, "_media", `ledger-${lessonId.toUpperCase()}.jsonl`);
|
|
31686
31239
|
this.load();
|
|
31687
31240
|
}
|
|
31688
31241
|
load() {
|
|
31689
31242
|
this.entries.clear();
|
|
31690
|
-
if (!
|
|
31691
|
-
const lines =
|
|
31243
|
+
if (!fs3.existsSync(this.filePath)) return;
|
|
31244
|
+
const lines = fs3.readFileSync(this.filePath, "utf-8").split("\n");
|
|
31692
31245
|
for (const line of lines) {
|
|
31693
31246
|
const trimmed = line.trim();
|
|
31694
31247
|
if (!trimmed) continue;
|
|
@@ -31700,8 +31253,8 @@ var MediaLedger = class {
|
|
|
31700
31253
|
}
|
|
31701
31254
|
}
|
|
31702
31255
|
persist() {
|
|
31703
|
-
|
|
31704
|
-
|
|
31256
|
+
fs3.mkdirSync(path4.dirname(this.filePath), { recursive: true });
|
|
31257
|
+
fs3.writeFileSync(this.filePath, Array.from(this.entries.values()).map((e) => JSON.stringify(e)).join("\n") + "\n", "utf-8");
|
|
31705
31258
|
}
|
|
31706
31259
|
/** Agent tạo artifact ghi entry mới (hoặc cập nhật nếu slug đã có và chưa done) */
|
|
31707
31260
|
upsert(input) {
|
|
@@ -31883,8 +31436,8 @@ async function fulfillMediaLedger(options) {
|
|
|
31883
31436
|
const maxRetries = options.maxRetries ?? 2;
|
|
31884
31437
|
const approved = ledger.listByStatus("approved");
|
|
31885
31438
|
const result = { done: [], failed: [], skipped: [] };
|
|
31886
|
-
const mediaDir =
|
|
31887
|
-
|
|
31439
|
+
const mediaDir = path4.join(projectDir, "_media");
|
|
31440
|
+
fs3.mkdirSync(mediaDir, { recursive: true });
|
|
31888
31441
|
const mode = policy.mode ?? "auto";
|
|
31889
31442
|
const canSearch = mode === "search_only" || mode === "auto";
|
|
31890
31443
|
const canGen = mode === "gen_only" || mode === "auto";
|
|
@@ -31966,7 +31519,7 @@ async function fulfillMediaLedger(options) {
|
|
|
31966
31519
|
});
|
|
31967
31520
|
const ext = image.mimeType === "image/jpeg" ? "jpg" : "png";
|
|
31968
31521
|
const filename = `${entry.slug}-${Date.now()}.${ext}`;
|
|
31969
|
-
|
|
31522
|
+
fs3.writeFileSync(path4.join(mediaDir, filename), Buffer.from(image.base64, "base64"));
|
|
31970
31523
|
ledger.setStatus(entry.slug, "done", { relPath: `_media/${filename}`, provider: image.provider });
|
|
31971
31524
|
result.done.push(entry.slug);
|
|
31972
31525
|
options.onProgress?.(entry.slug, "done", `source: ${image.provider}`);
|
|
@@ -31997,6 +31550,6 @@ function renderMediaPlaceholder(entry) {
|
|
|
31997
31550
|
return `> \u{1F5BC}\uFE0F [\u1EA2nh \u0111ang ch\u1EDD: ${entry.name} \u2014 s\u1EBD \u0111\u01B0\u1EE3c t\u1EA1o sau khi duy\u1EC7t media]`;
|
|
31998
31551
|
}
|
|
31999
31552
|
|
|
32000
|
-
export {
|
|
31553
|
+
export { ARTIFACT_DEPENDENCY_ROUTING, ARTIFACT_EXECUTION_ORDER, AcademicAuditor, ActionableRepairActionSchema, ActionableRepairPromptSchema, ActiveLearningWorkflowSchema, ActivityLabSchema, ActivitySeqRowSchema, ActivityStepSchema, ArtifactContractRowSchema, AssessmentMapRowSchema, AssessmentObjectiveSchema, BLOOM_ACTION_VERBS, BUNDLED_STANDARDS_PACK_IDS, BellRingerDaySchema, BellRingerSchema, BloomHintSchema, BloomLevelSchema, BloomTaxonomyEvaluator, BronzeTierSchema, CERConclusionSchema, CURRICULUM_SLASH_COMMANDS, CardTierEnum, ChoiceBoardRubricRowSchema, ChoiceBoardSchema, ChoiceRuleSchema, ChoiceSquareSchema, ClassificationSchema, CodeHardwareFeasibilityEvaluator, CodeLabSchema, CodeSnippetSchema, CompetencyRubricRowSchema, ComputationalThinkingSchema, ConceptPrerequisiteEdgeSchema, ConceptSpiralEncounterSchema, ConstructiveAlignmentEvaluator, CoreConceptSchema, CourseObjectiveSchema, CoverageReportSchema, CrossArtifactDriftEvaluator, CurriculumArtifactSchema, CurriculumError, CurriculumPlanSchema, CurriculumQualityReportSchema, DEFAULT_ARTIFACT_STREAM_IDLE_MS, DEFAULT_ARTIFACT_STREAM_TOTAL_MS, DEFAULT_ENABLED_PROVIDERS, DEFAULT_GATE_SETTINGS, DEFAULT_KX_PRIORITIES, DEFAULT_LESSON_PRIORITIES, DEFAULT_OVERHEAD_RATIO, DEFAULT_STREAM_IDLE_MS, DEFAULT_STREAM_TOTAL_MS, DEFAULT_VIETNAMESE_SECTION_HEADINGS, DependencyEdgeSchema, DepthAssignmentSchema, DepthLevelSchema, DeterministicPipelineRunner, DeterministicStructuralLinter, DiagnosticQuestionSchema, DiagnosticQuizSchema, EDPPhaseEnum, ENVIRONMENT_PROVISIONING_MODELS, EXPOSITION_REL, EntryLevelSchema, ExitTicketBugHuntSchema, ExitTicketMetacognitionSchema, ExitTicketQuickItemSchema, ExitTicketRecallPromptSchema, ExitTicketSchema, ExperimentalDesignSchema, ExpositionApprovalError, ExtensionChallengeSchema, ExtensionSchema, FileSystemCurriculumAdapter, FiveEFlowPhaseSchema, FiveEInstructionalEvaluator, FiveEPhaseEnum, FrameworkMappingSchema, FrameworkPackManifestSchema, FrameworkPackSchema, FrameworkStatementSchema, GeneratedSlideArraySchema, GeneratedSlideSchema, GlossaryQuickRefRowSchema, GlossarySchema, GlossaryTermSchema, GoldTierSchema, GradeBandSchema, GraphicOrganizerItemSchema, GraphicOrganizerSchema, HandoutSchema, HandoutSectionSchema, HybridBlueprintArraySchema, HybridBlueprintItemSchema, HybridDeckSlideArraySchema, HybridDeckSlideSchema, HybridPipelineError, InstructionSectionSchema, InstructionStepSchema, JUDGE_AUTO_APPROVE_THRESHOLD, JUDGE_ESCALATE_THRESHOLD, JudgeCriterionSchema, LAYER_IDLE_BUDGET_MS, LAYER_TOTAL_BUDGET_MS, LLMJudgeEngine, LabTierTaskSchema, LearningObjectiveInputSchema, LearningObjectiveRowSchema, LessonEntitySchema, LessonFlowPhaseSchema, LessonPlan5ESchema, LessonPlanEDPSchema, LessonPlanSchema, LessonSectionSchema, LocalWorkspaceManager, MAX_AUTONOMOUS_REPAIR_TURNS, MAX_IN_SESSION_SETUP_MINUTES, MAX_NEW_CONCEPTS_PER_SESSION_ADULT, MAX_NEW_CONCEPTS_PER_SESSION_K12, MacroPedagogyPlanAuditSchema, MappingKindSchema, MarpSlideSchema, MasteryGateSchema, MediaError, MediaLedger, MentorCheatsheetSchema, MilestoneInputSchema, MisconceptionEvaluator, MisconceptionSchema, ModelPolicyResolver, NVIDIA_MODELS, NodeKindSchema, OrganizerTypeEnum, PhaseInputSchema, PlanConstraintsSchema, PlannerInputSchema, PlanningGraphSchema, PlanningNodeSchema, PrerequisiteDecisionEntrySchema, PrerequisiteDecisionSchema, ProductGoalSchema, ProgressiveHintsSchema, ProjectGraphAuditSchema, ProjectGraphSchema, ProjectInstructionSchema, ProjectProfileSchema, QualityAuditVerdictSchema, QuizOptionSchema, RecordProvenanceSchema, ResourceMapRowSchema, ReviewGameExportRowSchema, ReviewGameQuestionSchema, ReviewGameSchema, RoadmapInputSchema, RotationStationSchema, RubricCriteriaSchema, RubricSchema, SATELLITE_LESSON_PRIORITIES, SLIDE_CANONICAL_METHODOLOGY, STANDARD_REF_REGEX, STANDARD_SOT_FILES, STUDENT_FRICTION_MULTIPLIER, ScaffoldDecisionEntrySchema, ScaffoldDecisionSchema, ScienceLabSchema, ScoringRubricRowSchema, SelfLabSchema, SelfPacedBundleSchema, SelfPacedChallengeSchema, SessionPlanSchema, SessionZpdStatusSchema, SilverTierSchema, SlideBlueprintArraySchema, SlideBlueprintItemSchema, SlideDeckSchema, StandardizedTermRowSchema, StandardsRegistryAdapter, StationRecordRowSchema, StationRotationSchema, StationTypeEnum, SupabaseCurriculumAdapter, TaskCardSchema, TaskCardsSchema, TeacherGuideSchema, TeachingScriptPhaseSchema, TierLevelEnum, TierObjectiveSchema, TieredPracticeSchema, TranslationPolicySchema, TroubleshootingEntrySchema, TroubleshootingRowSchema, UnitPlanSchema, UserJourneySchema, WalkingSkeletonSchema, WorksheetItemSchema, WorksheetItemTypeEnum, WorksheetPartSchema, WorksheetSchema, ZpdVerdictSchema, activityTools, analystTools, analyzeProjectCreationIntent, assertAcyclic, assessorTools, assignDepths, atomicWriteFileSync, auditCurriculumPlanFlow, auditCurriculumQualityFlow, auditProjectGraphFlow, auditQualityReport, buildActivityPrompt, buildArtifactPrompt, buildCodeLabPrompt, buildConceptPrerequisites, buildCurriculumContext, buildCurriculumPlan, buildCurriculumPlanJudgePrompt, buildDeliveryPackages, buildDiagnosticQuizPrompt, buildDomainLexiconGuardrail, buildExpositionContext, buildExpositionExcerpt, buildExtensionPrompt, buildHandoutPrompt, buildHeadingDirective, buildHtmlDeckSlidePrompt, buildImagePrompt, buildJudgePrompt, buildLanguageDirective, buildLessonEntityJson, buildLessonExcerpt, buildLessonMasterPrompt, buildMarpMarkdownSlidePrompt, buildMasteryGates, buildProjectGraphJudgePrompt, buildProjectInstructionPrompt, buildSatelliteContext, buildSectionAwareExcerpt, buildSelfLabPrompt, buildSessionSliceContext, buildSlidesPrompt, buildStandardStackMarkdown, buildStandardsContext, buildStandardsContextBlock, buildTeacherGuidePrompt, buildWalkingSkeleton, buildWorksheetPrompt, checkSessionZpd, closeTruncatedJson, computeConceptSpiralProgression, computeContentHash, computePackingSpec, conductPreliminaryResearch, contentTools, convertRoadmapToFoundationSot, createAiInferenceError, createContextMissingError, createCurriculumStorage, createIdleAbortController, createStreamAbortController, createStreamAbortSignal, createStreamChunkExtractor, curateMediaLedger, designerTools, detectProjectPedagogy, dropCyclicConceptEdges, emitUsage, ensureExpositionForLesson, ensureKnowledgeExposition, entityRowAssignedTo, evaluateActivityAlignment, evaluateStandardsCoverage, executeCurriculumCommand, executeSlideProductionWorkflow, exportAllProjectQuizzes, expositionCacheKey, extractActivityContractRows, extractAssessmentMap, extractBodySections, extractCurriculumHorizon, extractJsonArray, extractRequiredSections, extractScopeSequenceRows, extractSectionHeadingsFromSLC, extractSessionSlice, extractStandardRefs, extractStreamChunk, extractSymbolLedger, extractThoughtAndContent, extractTieredScaffoldingBlock, findStandardStatement, formatQuizzesToCsv, fulfillMediaLedger, gateModeFor, generateActivityFlow, generateCodeLabFlow, generateDiagnosticQuizFlow, generateEducationalImage, generateExtensionFlow, generateHandoutFlow, generateLessonMasterFlow, generateMilestoneCurriculumBundle, generatePhase1SotArtifacts, generatePhase2SotArtifacts, generateProjectInstruction, generateProjectInstructionFlow, generateRoadmapCurriculum, generateSelfLabFlow, generateSelfPacedBundle, generateSingleArtifact, generateSlidesFlow, generateTeacherGuideFlow, generateWorksheetFlow, getAIModel, getArtifactMetadata, getDesignatedFallbackChain, getDesignatedFallbackConfig, getLessonMetadata, getProjectArtifactScope, getProjectStatusReport, getSmartResumeContext, glossaryTermsForSession, illustratorTools, importRoadmapToProject, ingestProjectGraphIntoProject, initializeProjectInStorage, injectMediaIntoMarkdown, isActivityAlignmentLogOnly, isExpositionFresh, isModelAllowed, isProviderEnabled, isTranslationDue, lintAndSanitizeArtifact, lintCurriculumFramework, lintFrameworkPack, loadAuthoringTemplate, loadCurriculumTemplate, loadSotTemplate, normalizePlanningGraph, normalizeSlcContract, packagerTools, parseAllSessions, parseGateSettings, parseQuizMarkdown, parseRoadmapJsonToProjectPayload, produceBatchLessons, produceSingleLesson, publishToGitHub, publishToSupabase, rankGenCandidates, renderAssignedRowsTable, renderEntitySlotsForType, renderFrameworkFromPlan, renderHorizonPromptBlock, renderMediaPlaceholder, researcherTools, resolveApiKey, resolveArtifactTemplate, resolveGateSettings, resolveStandardsPacks, resolveStreamBudget, resolveTargetLanguageCode, resolveTranslationTargets, reviewerTools, runCurriculumAIInference, safeParseJson, searchEducationalImages, searchEducationalVideos, selectStatementsForLesson, serializeActivityToMarkdown, serializeCodeLabToMarkdown, serializeDiagnosticQuizToMarkdown, serializeHandoutToMarkdown, serializeLessonToMarkdown, serializeProjectInstructionToMarkdown, serializeSelfLabToMarkdown, slugifyProjectName, streamCurriculumAIInference, streamCurriculumAIInferenceWithTools, streamDiagnosticQuizFlow, streamLLMWithFallback, streamLayerPrefillWithFallback, streamLessonMasterFlow, streamSelfLabFlow, stripLlmJsonWrappers, stripTemplateFrontmatter, targetLanguageDisplayName, techSmeTools, topoSort, uploadAssetToBucket, validateArtifactDependencies, validateCurriculumPlan, validateFrameworkPack, validateHorizonCompliance, validateHybridDeckSlides, validateMarkdownTables, validateMermaidSyntax, withAutoRepair };
|
|
32001
31554
|
//# sourceMappingURL=index.mjs.map
|
|
32002
31555
|
//# sourceMappingURL=index.mjs.map
|