@learnpack/learnpack 5.0.272 → 5.0.274
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/README.md +409 -409
- package/lib/commands/audit.js +15 -15
- package/lib/commands/breakToken.js +19 -19
- package/lib/commands/clean.js +3 -3
- package/lib/commands/init.js +41 -41
- package/lib/commands/logout.js +3 -3
- package/lib/commands/serve.js +32 -17
- package/lib/creatorDist/assets/{index-C1pv1wUb.js → index-BfLyIQVh.js} +10351 -10227
- package/lib/creatorDist/assets/{index-B4khtb0r.css → index-C39zeF3W.css} +3 -3
- package/lib/creatorDist/index.html +2 -2
- package/lib/managers/config/index.js +77 -77
- package/lib/utils/api.js +1 -0
- package/lib/utils/creatorUtilities.js +14 -14
- package/package.json +1 -1
- package/src/commands/audit.ts +487 -487
- package/src/commands/breakToken.ts +67 -67
- package/src/commands/clean.ts +30 -30
- package/src/commands/init.ts +650 -650
- package/src/commands/logout.ts +38 -38
- package/src/commands/publish.ts +522 -522
- package/src/commands/serve.ts +38 -28
- package/src/commands/start.ts +333 -333
- package/src/commands/translate.ts +123 -123
- package/src/creator/README.md +54 -54
- package/src/creator/eslint.config.js +28 -28
- package/src/creator/src/components/syllabus/ContentIndex.tsx +1 -1
- package/src/creator/src/i18n.ts +28 -28
- package/src/creator/src/index.css +217 -217
- package/src/creator/src/locales/en.json +1 -0
- package/src/creator/src/locales/es.json +1 -0
- package/src/creator/src/utils/configTypes.ts +122 -122
- package/src/creator/src/utils/constants.ts +13 -13
- package/src/creator/src/utils/creatorUtils.ts +46 -46
- package/src/creator/src/utils/eventBus.ts +2 -2
- package/src/creator/src/utils/lib.ts +468 -468
- package/src/creator/src/utils/rigo.ts +26 -26
- package/src/creator/src/utils/socket.ts +61 -61
- package/src/creator/src/utils/store.ts +222 -222
- package/src/creator/src/vite-env.d.ts +1 -1
- package/src/creator/vite.config.ts +13 -13
- package/src/creatorDist/assets/{index-C1pv1wUb.js → index-BfLyIQVh.js} +10351 -10227
- package/src/creatorDist/assets/{index-B4khtb0r.css → index-C39zeF3W.css} +3 -3
- package/src/creatorDist/index.html +2 -2
- package/src/managers/config/defaults.ts +49 -49
- package/src/managers/config/exercise.ts +364 -364
- package/src/managers/config/index.ts +775 -775
- package/src/managers/file.ts +236 -236
- package/src/managers/server/routes.ts +554 -554
- package/src/managers/session.ts +182 -182
- package/src/managers/telemetry.ts +188 -188
- package/src/models/action.ts +13 -13
- package/src/models/config-manager.ts +28 -28
- package/src/models/config.ts +106 -106
- package/src/models/creator.ts +40 -40
- package/src/models/exercise-obj.ts +30 -30
- package/src/models/session.ts +39 -39
- package/src/models/socket.ts +61 -61
- package/src/models/status.ts +16 -16
- package/src/ui/_app/app.css +1 -1
- package/src/ui/_app/app.js +435 -414
- package/src/ui/_app/learnpack.svg +7 -7
- package/src/ui/app.tar.gz +0 -0
- package/src/utils/BaseCommand.ts +56 -56
- package/src/utils/api.ts +31 -30
- package/src/utils/audit.ts +392 -392
- package/src/utils/checkNotInstalled.ts +267 -267
- package/src/utils/configBuilder.ts +82 -82
- package/src/utils/convertCreds.js +34 -34
- package/src/utils/creatorUtilities.ts +504 -504
- package/src/utils/incrementVersion.js +74 -74
- package/src/utils/misc.ts +58 -58
- package/src/utils/rigoActions.ts +500 -500
- package/src/utils/sidebarGenerator.ts +195 -195
- package/src/utils/templates/isolated/exercises/01-hello-world/README.es.md +26 -26
- package/src/utils/templates/isolated/exercises/01-hello-world/README.md +26 -26
package/lib/commands/audit.js
CHANGED
@@ -369,21 +369,21 @@ class AuditCommand extends SessionCommand_1.default {
|
|
369
369
|
}
|
370
370
|
}
|
371
371
|
}
|
372
|
-
AuditCommand.description = `learnpack audit is the command in charge of creating an auditory of the repository
|
373
|
-
...
|
374
|
-
learnpack audit checks for the following information in a repository:
|
375
|
-
1. The configuration object has slug, repository and description. (Error)
|
376
|
-
2. The command learnpack clean has been run. (Error)
|
377
|
-
3. If a markdown or test file doesn't have any content. (Error)
|
378
|
-
4. The links are accessing to valid servers. (Error)
|
379
|
-
5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)
|
380
|
-
6. The external images are working (If they are pointing to a valid server). (Error)
|
381
|
-
7. The exercises directory names are valid. (Error)
|
382
|
-
8. If an exercise doesn't have a README file. (Error)
|
383
|
-
9. The exercises array (Of the config file) has content. (Error)
|
384
|
-
10. The exercses have the same translations. (Warning)
|
385
|
-
11. The .gitignore file exists. (Warning)
|
386
|
-
12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
|
372
|
+
AuditCommand.description = `learnpack audit is the command in charge of creating an auditory of the repository
|
373
|
+
...
|
374
|
+
learnpack audit checks for the following information in a repository:
|
375
|
+
1. The configuration object has slug, repository and description. (Error)
|
376
|
+
2. The command learnpack clean has been run. (Error)
|
377
|
+
3. If a markdown or test file doesn't have any content. (Error)
|
378
|
+
4. The links are accessing to valid servers. (Error)
|
379
|
+
5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)
|
380
|
+
6. The external images are working (If they are pointing to a valid server). (Error)
|
381
|
+
7. The exercises directory names are valid. (Error)
|
382
|
+
8. If an exercise doesn't have a README file. (Error)
|
383
|
+
9. The exercises array (Of the config file) has content. (Error)
|
384
|
+
10. The exercses have the same translations. (Warning)
|
385
|
+
11. The .gitignore file exists. (Warning)
|
386
|
+
12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
|
387
387
|
`;
|
388
388
|
AuditCommand.flags = {
|
389
389
|
strict: command_1.flags.boolean({
|
@@ -4,25 +4,25 @@ const command_1 = require("@oclif/command");
|
|
4
4
|
const BaseCommand_1 = require("../utils/BaseCommand");
|
5
5
|
const console_1 = require("../utils/console");
|
6
6
|
const creatorUtilities_1 = require("../utils/creatorUtilities");
|
7
|
-
const exampleMd = `# How to Install Node.js
|
8
|
-
|
9
|
-
Node.js lets you run JavaScript outside a web browser.
|
10
|
-
|
11
|
-
## Step 1: Download Node.js
|
12
|
-
|
13
|
-
Get the Node.js installer from the [official site](https://nodejs.org/en/download/).
|
14
|
-
|
15
|
-
## Step 2: Install Node.js
|
16
|
-
|
17
|
-
Open the installer and follow the steps to finish.
|
18
|
-
|
19
|
-
## Step 3: Verify the Installation
|
20
|
-
|
21
|
-
Open a terminal and type:
|
22
|
-
|
23
|
-
\`\`\`bash
|
24
|
-
node -v
|
25
|
-
\`\`\`
|
7
|
+
const exampleMd = `# How to Install Node.js
|
8
|
+
|
9
|
+
Node.js lets you run JavaScript outside a web browser.
|
10
|
+
|
11
|
+
## Step 1: Download Node.js
|
12
|
+
|
13
|
+
Get the Node.js installer from the [official site](https://nodejs.org/en/download/).
|
14
|
+
|
15
|
+
## Step 2: Install Node.js
|
16
|
+
|
17
|
+
Open the installer and follow the steps to finish.
|
18
|
+
|
19
|
+
## Step 3: Verify the Installation
|
20
|
+
|
21
|
+
Open a terminal and type:
|
22
|
+
|
23
|
+
\`\`\`bash
|
24
|
+
node -v
|
25
|
+
\`\`\`
|
26
26
|
`;
|
27
27
|
class BreakTokenCommand extends BaseCommand_1.default {
|
28
28
|
async run() {
|
package/lib/commands/clean.js
CHANGED
@@ -16,9 +16,9 @@ class CleanCommand extends SessionCommand_1.default {
|
|
16
16
|
console_1.default.success("Package cleaned successfully, ready to publish");
|
17
17
|
}
|
18
18
|
}
|
19
|
-
CleanCommand.description = `Clean the configuration object
|
20
|
-
...
|
21
|
-
Extra documentation goes here
|
19
|
+
CleanCommand.description = `Clean the configuration object
|
20
|
+
...
|
21
|
+
Extra documentation goes here
|
22
22
|
`;
|
23
23
|
CleanCommand.flags = {
|
24
24
|
// name: flags.string({char: 'n', description: 'name to print'}),
|
package/lib/commands/init.js
CHANGED
@@ -107,9 +107,9 @@ const initializeInteractiveCreation = async (rigoToken, courseInfo) => {
|
|
107
107
|
while (!isReady) {
|
108
108
|
const spinner = (0, ora_1.default)("Thinking...").start();
|
109
109
|
let wholeInfo = courseInfo;
|
110
|
-
wholeInfo += `
|
111
|
-
Current title: ${currentTitle}
|
112
|
-
Current description: ${currentDescription}
|
110
|
+
wholeInfo += `
|
111
|
+
Current title: ${currentTitle}
|
112
|
+
Current description: ${currentDescription}
|
113
113
|
`;
|
114
114
|
// eslint-disable-next-line
|
115
115
|
const res = await (0, rigoActions_1.interactiveCreation)(rigoToken, {
|
@@ -200,56 +200,56 @@ const handleAILogic = async (tutorialDir, packageInfo) => {
|
|
200
200
|
fs.mkdirSync(rulesDir, { recursive: true });
|
201
201
|
fs.writeFileSync(path.join(rulesDir, "airules.txt"), airules);
|
202
202
|
}
|
203
|
-
let packageContext = `
|
204
|
-
\n
|
205
|
-
Title: "${packageInfo.title.us}"
|
206
|
-
Description: "${packageInfo.description.us}"
|
207
|
-
Target Audience: "${targetAudience}"
|
208
|
-
Estimated Duration: "${estimatedDuration} minutes"
|
209
|
-
|
203
|
+
let packageContext = `
|
204
|
+
\n
|
205
|
+
Title: "${packageInfo.title.us}"
|
206
|
+
Description: "${packageInfo.description.us}"
|
207
|
+
Target Audience: "${targetAudience}"
|
208
|
+
Estimated Duration: "${estimatedDuration} minutes"
|
209
|
+
|
210
210
|
${contentIndex ?
|
211
|
-
`Content Index submitted by the user, use this to guide your creation. Keep in mind that your tutorial should contain these topics:
|
212
|
-
---
|
213
|
-
${contentIndex}
|
214
|
-
---
|
211
|
+
`Content Index submitted by the user, use this to guide your creation. Keep in mind that your tutorial should contain these topics:
|
212
|
+
---
|
213
|
+
${contentIndex}
|
214
|
+
---
|
215
215
|
` :
|
216
|
-
""}
|
217
|
-
|
218
|
-
This is the duration for each type of step, use it to estimate the number of steps to create:
|
216
|
+
""}
|
217
|
+
|
218
|
+
This is the duration for each type of step, use it to estimate the number of steps to create:
|
219
219
|
${Object.entries(durationByKind)
|
220
220
|
.map(([key, value]) => `${key}: ${value} minutes`)
|
221
|
-
.join("\n")}
|
222
|
-
|
223
|
-
|
224
|
-
Within the estimated duration, is possible to have the following activities:
|
225
|
-
Format=
|
226
|
-
Activity: Maximum number of steps for duration
|
227
|
-
|
228
|
-
Estimated activities:
|
229
|
-
${JSON.stringify(estimateActivities(estimatedDuration))}
|
230
|
-
|
231
|
-
You should create a tutorial that is engaging and fun to follow.
|
232
|
-
|
233
|
-
|
221
|
+
.join("\n")}
|
222
|
+
|
223
|
+
|
224
|
+
Within the estimated duration, is possible to have the following activities:
|
225
|
+
Format=
|
226
|
+
Activity: Maximum number of steps for duration
|
227
|
+
|
228
|
+
Estimated activities:
|
229
|
+
${JSON.stringify(estimateActivities(estimatedDuration))}
|
230
|
+
|
231
|
+
You should create a tutorial that is engaging and fun to follow.
|
232
|
+
|
233
|
+
|
234
234
|
${airules ?
|
235
|
-
`
|
236
|
-
This is a list of rules you need to follow when creating the tutorial:
|
237
|
-
${airules}
|
235
|
+
`
|
236
|
+
This is a list of rules you need to follow when creating the tutorial:
|
237
|
+
${airules}
|
238
238
|
` :
|
239
|
-
""}
|
239
|
+
""}
|
240
240
|
`;
|
241
241
|
const { steps, title, description, duration, difficulty } = await initializeInteractiveCreation(rigoToken, packageContext);
|
242
242
|
packageInfo.title.us = title;
|
243
243
|
packageInfo.description.us = description;
|
244
244
|
packageInfo.duration = duration;
|
245
245
|
packageInfo.difficulty = difficulty;
|
246
|
-
packageContext = `
|
247
|
-
Title: "${title}"
|
248
|
-
Description: "${description}"
|
249
|
-
Target Audience: "${targetAudience}"
|
250
|
-
List of exercises: ${steps.join(", ")}
|
251
|
-
|
252
|
-
AI Rules: ${airules}
|
246
|
+
packageContext = `
|
247
|
+
Title: "${title}"
|
248
|
+
Description: "${description}"
|
249
|
+
Target Audience: "${targetAudience}"
|
250
|
+
List of exercises: ${steps.join(", ")}
|
251
|
+
|
252
|
+
AI Rules: ${airules}
|
253
253
|
`;
|
254
254
|
const exercisesDir = path.join(tutorialDir, "exercises");
|
255
255
|
fs.ensureDirSync(exercisesDir);
|
package/lib/commands/logout.js
CHANGED
@@ -14,9 +14,9 @@ class LogoutCommand extends SessionCommand_1.default {
|
|
14
14
|
session_1.default.destroy();
|
15
15
|
}
|
16
16
|
}
|
17
|
-
LogoutCommand.description = `Describe the command here
|
18
|
-
...
|
19
|
-
Extra documentation goes here
|
17
|
+
LogoutCommand.description = `Describe the command here
|
18
|
+
...
|
19
|
+
Extra documentation goes here
|
20
20
|
`;
|
21
21
|
LogoutCommand.flags = {
|
22
22
|
// name: flags.string({char: 'n', description: 'name to print'}),
|
package/lib/commands/serve.js
CHANGED
@@ -105,9 +105,7 @@ const uploadInitialReadme = async (bucket, exSlug, targetDir, packageContext) =>
|
|
105
105
|
:rigo
|
106
106
|
\`\`\`
|
107
107
|
`;
|
108
|
-
const readmeFilename = `README
|
109
|
-
`${packageContext.language}.` :
|
110
|
-
""}md`;
|
108
|
+
const readmeFilename = `README${(0, creatorUtilities_1.getReadmeExtension)(packageContext.language || "en")}`;
|
111
109
|
await uploadFileToBucket(bucket, isGeneratingText, `${targetDir}/${readmeFilename}`);
|
112
110
|
};
|
113
111
|
const cleanFormState = (formState) => {
|
@@ -134,12 +132,12 @@ const createMultiLangAsset = async (bucket, rigoToken, bcToken, courseSlug, cour
|
|
134
132
|
all_translations.push(asset.slug);
|
135
133
|
}
|
136
134
|
};
|
137
|
-
async function startExerciseGeneration(
|
135
|
+
async function startExerciseGeneration(rigoToken, steps, packageContext, exercise, courseSlug, purposeSlug, lastLesson = "") {
|
138
136
|
const exSlug = (0, creatorUtilities_2.slugify)(exercise.id + "-" + exercise.title);
|
139
137
|
console.log("Starting generation of", exSlug);
|
140
138
|
const webhookUrl = `${process.env.HOST}/webhooks/${courseSlug}/exercise-processor/${exercise.id}/${rigoToken}`;
|
141
139
|
console.log("WEBHOOK URL", webhookUrl);
|
142
|
-
await (0, rigoActions_1.readmeCreator)(rigoToken, {
|
140
|
+
const res = await (0, rigoActions_1.readmeCreator)(rigoToken, {
|
143
141
|
title: `${exercise.id} - ${exercise.title}`,
|
144
142
|
output_lang: packageContext.language || "en",
|
145
143
|
list_of_exercises: JSON.stringify(steps.map(step => step.id + "-" + step.title)),
|
@@ -148,6 +146,7 @@ async function startExerciseGeneration(bucket, rigoToken, steps, packageContext,
|
|
148
146
|
kind: exercise.type.toLowerCase(),
|
149
147
|
last_lesson: lastLesson,
|
150
148
|
}, purposeSlug, webhookUrl);
|
149
|
+
console.log("README CREATOR RES", res);
|
151
150
|
}
|
152
151
|
async function createInitialReadme(tutorialInfo, tutorialSlug, rigoToken) {
|
153
152
|
const webhookUrl = `${process.env.HOST}/webhooks/${tutorialSlug}/initial-readme-processor`;
|
@@ -433,7 +432,7 @@ class ServeCommand extends SessionCommand_1.default {
|
|
433
432
|
previousReadme = content.toString();
|
434
433
|
}
|
435
434
|
}
|
436
|
-
await startExerciseGeneration(
|
435
|
+
await startExerciseGeneration(rigoToken, syllabusJson.lessons, syllabusJson.courseInfo, exercise, courseSlug, syllabusJson.courseInfo.purpose, previousReadme +
|
437
436
|
"\n\nThe user provided the following feedback related to the content of the course so far: \n\n" +
|
438
437
|
feedback);
|
439
438
|
syllabusJson.lessons[parseInt(position)].status = "GENERATING";
|
@@ -506,7 +505,7 @@ class ServeCommand extends SessionCommand_1.default {
|
|
506
505
|
if (syllabusJson.feedback) {
|
507
506
|
feedback = `\n\nThe user added the following feedback with relation to the previous generations: ${syllabusJson.feedback}`;
|
508
507
|
}
|
509
|
-
startExerciseGeneration(
|
508
|
+
startExerciseGeneration(rigoToken, syllabusJson.lessons, syllabusJson.courseInfo, nextExercise, courseSlug, syllabusJson.courseInfo.purpose, readme.parsed.content + "\n\n" + feedback);
|
510
509
|
nextStarted = true;
|
511
510
|
}
|
512
511
|
else {
|
@@ -937,7 +936,7 @@ class ServeCommand extends SessionCommand_1.default {
|
|
937
936
|
await uploadFileToBucket(bucket, JSON.stringify(sidebar), `${tutorialDir}/.learn/sidebar.json`);
|
938
937
|
const firstLesson = syllabus.lessons[0];
|
939
938
|
const lastResult = "---";
|
940
|
-
await startExerciseGeneration(
|
939
|
+
await startExerciseGeneration(rigoToken, syllabus.lessons, syllabus.courseInfo, firstLesson, courseSlug, syllabus.courseInfo.purpose, lastResult);
|
941
940
|
await createInitialReadme(JSON.stringify(syllabus.courseInfo), courseSlug, rigoToken);
|
942
941
|
return res.json({
|
943
942
|
message: "Course generation started",
|
@@ -974,7 +973,7 @@ class ServeCommand extends SessionCommand_1.default {
|
|
974
973
|
const lastGeneratedLesson = findLast(syllabusJson.lessons, lesson => { var _a; return (_a = lesson.generated) !== null && _a !== void 0 ? _a : false; });
|
975
974
|
console.log("ABout to generate", notGeneratedLessons.length, "lessons");
|
976
975
|
const firstLessonToGenerate = notGeneratedLessons[0];
|
977
|
-
await startExerciseGeneration(
|
976
|
+
await startExerciseGeneration(rigoToken, syllabusJson.lessons, syllabusJson.courseInfo, firstLessonToGenerate, courseSlug, syllabusJson.courseInfo.purpose, JSON.stringify(lastGeneratedLesson) +
|
978
977
|
`\n\nThe user provided this feedback in relation to the course: ${feedback}`);
|
979
978
|
return res.json({
|
980
979
|
message: "Course continued",
|
@@ -1137,7 +1136,9 @@ class ServeCommand extends SessionCommand_1.default {
|
|
1137
1136
|
console.error("❌ Error fetching file:", error);
|
1138
1137
|
return res
|
1139
1138
|
.status(500)
|
1140
|
-
.json({
|
1139
|
+
.json({
|
1140
|
+
error: error.message || "Unable to fetch file",
|
1141
|
+
});
|
1141
1142
|
}
|
1142
1143
|
});
|
1143
1144
|
const YT_REGEX = /(?:youtube\.com\/watch\?v=|youtu\.be\/)([\w-]{11})/;
|
@@ -1149,20 +1150,32 @@ class ServeCommand extends SessionCommand_1.default {
|
|
1149
1150
|
const ytMatch = decoded.match(YT_REGEX);
|
1150
1151
|
if (ytMatch) {
|
1151
1152
|
const videoId = ytMatch[1];
|
1153
|
+
console.log("VIDEO ID", videoId);
|
1152
1154
|
// fetch metadata
|
1153
1155
|
const items = await youtube_transcript_1.YoutubeTranscript.fetchTranscript(videoId);
|
1156
|
+
console.log("ITEMS FROM YOUTUBE TRANSCRIPT", items);
|
1154
1157
|
const transcript = items.map(i => i.text).join(" ");
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
+
let meta = null;
|
1159
|
+
try {
|
1160
|
+
const { data: meta } = await axios_1.default.get("https://www.youtube.com/oembed", {
|
1161
|
+
params: { url: decoded, format: "json" },
|
1162
|
+
});
|
1163
|
+
console.log("META", meta);
|
1164
|
+
}
|
1165
|
+
catch (error) {
|
1166
|
+
console.error("ERROR FETCHING META", error);
|
1167
|
+
meta = null;
|
1168
|
+
}
|
1169
|
+
throw new Error("test");
|
1158
1170
|
return res.json({
|
1159
1171
|
url: decoded,
|
1160
|
-
title: meta.title,
|
1161
|
-
author: meta.author_name,
|
1162
|
-
thumbnail: meta.thumbnail_url,
|
1172
|
+
title: (meta === null || meta === void 0 ? void 0 : meta.title) || null,
|
1173
|
+
author: (meta === null || meta === void 0 ? void 0 : meta.author_name) || null,
|
1174
|
+
thumbnail: (meta === null || meta === void 0 ? void 0 : meta.thumbnail_url) || null,
|
1163
1175
|
transcript,
|
1164
1176
|
});
|
1165
1177
|
}
|
1178
|
+
console.log("NOT A YOUTUBE LINK", decoded);
|
1166
1179
|
const response = await axios_1.default.get(decoded, { responseType: "text" });
|
1167
1180
|
const html = response.data;
|
1168
1181
|
const title = getTitleFromHTML(html);
|
@@ -1176,7 +1189,9 @@ class ServeCommand extends SessionCommand_1.default {
|
|
1176
1189
|
}
|
1177
1190
|
catch (error) {
|
1178
1191
|
console.error("❌ /actions/fetch error:", error.message || error);
|
1179
|
-
res
|
1192
|
+
res
|
1193
|
+
.status(500)
|
1194
|
+
.json({ error: error.message || "Failed to fetch link" });
|
1180
1195
|
}
|
1181
1196
|
});
|
1182
1197
|
app.delete("/packages/:slug", async (req, res) => {
|