@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.
Files changed (75) hide show
  1. package/README.md +409 -409
  2. package/lib/commands/audit.js +15 -15
  3. package/lib/commands/breakToken.js +19 -19
  4. package/lib/commands/clean.js +3 -3
  5. package/lib/commands/init.js +41 -41
  6. package/lib/commands/logout.js +3 -3
  7. package/lib/commands/serve.js +32 -17
  8. package/lib/creatorDist/assets/{index-C1pv1wUb.js → index-BfLyIQVh.js} +10351 -10227
  9. package/lib/creatorDist/assets/{index-B4khtb0r.css → index-C39zeF3W.css} +3 -3
  10. package/lib/creatorDist/index.html +2 -2
  11. package/lib/managers/config/index.js +77 -77
  12. package/lib/utils/api.js +1 -0
  13. package/lib/utils/creatorUtilities.js +14 -14
  14. package/package.json +1 -1
  15. package/src/commands/audit.ts +487 -487
  16. package/src/commands/breakToken.ts +67 -67
  17. package/src/commands/clean.ts +30 -30
  18. package/src/commands/init.ts +650 -650
  19. package/src/commands/logout.ts +38 -38
  20. package/src/commands/publish.ts +522 -522
  21. package/src/commands/serve.ts +38 -28
  22. package/src/commands/start.ts +333 -333
  23. package/src/commands/translate.ts +123 -123
  24. package/src/creator/README.md +54 -54
  25. package/src/creator/eslint.config.js +28 -28
  26. package/src/creator/src/components/syllabus/ContentIndex.tsx +1 -1
  27. package/src/creator/src/i18n.ts +28 -28
  28. package/src/creator/src/index.css +217 -217
  29. package/src/creator/src/locales/en.json +1 -0
  30. package/src/creator/src/locales/es.json +1 -0
  31. package/src/creator/src/utils/configTypes.ts +122 -122
  32. package/src/creator/src/utils/constants.ts +13 -13
  33. package/src/creator/src/utils/creatorUtils.ts +46 -46
  34. package/src/creator/src/utils/eventBus.ts +2 -2
  35. package/src/creator/src/utils/lib.ts +468 -468
  36. package/src/creator/src/utils/rigo.ts +26 -26
  37. package/src/creator/src/utils/socket.ts +61 -61
  38. package/src/creator/src/utils/store.ts +222 -222
  39. package/src/creator/src/vite-env.d.ts +1 -1
  40. package/src/creator/vite.config.ts +13 -13
  41. package/src/creatorDist/assets/{index-C1pv1wUb.js → index-BfLyIQVh.js} +10351 -10227
  42. package/src/creatorDist/assets/{index-B4khtb0r.css → index-C39zeF3W.css} +3 -3
  43. package/src/creatorDist/index.html +2 -2
  44. package/src/managers/config/defaults.ts +49 -49
  45. package/src/managers/config/exercise.ts +364 -364
  46. package/src/managers/config/index.ts +775 -775
  47. package/src/managers/file.ts +236 -236
  48. package/src/managers/server/routes.ts +554 -554
  49. package/src/managers/session.ts +182 -182
  50. package/src/managers/telemetry.ts +188 -188
  51. package/src/models/action.ts +13 -13
  52. package/src/models/config-manager.ts +28 -28
  53. package/src/models/config.ts +106 -106
  54. package/src/models/creator.ts +40 -40
  55. package/src/models/exercise-obj.ts +30 -30
  56. package/src/models/session.ts +39 -39
  57. package/src/models/socket.ts +61 -61
  58. package/src/models/status.ts +16 -16
  59. package/src/ui/_app/app.css +1 -1
  60. package/src/ui/_app/app.js +435 -414
  61. package/src/ui/_app/learnpack.svg +7 -7
  62. package/src/ui/app.tar.gz +0 -0
  63. package/src/utils/BaseCommand.ts +56 -56
  64. package/src/utils/api.ts +31 -30
  65. package/src/utils/audit.ts +392 -392
  66. package/src/utils/checkNotInstalled.ts +267 -267
  67. package/src/utils/configBuilder.ts +82 -82
  68. package/src/utils/convertCreds.js +34 -34
  69. package/src/utils/creatorUtilities.ts +504 -504
  70. package/src/utils/incrementVersion.js +74 -74
  71. package/src/utils/misc.ts +58 -58
  72. package/src/utils/rigoActions.ts +500 -500
  73. package/src/utils/sidebarGenerator.ts +195 -195
  74. package/src/utils/templates/isolated/exercises/01-hello-world/README.es.md +26 -26
  75. package/src/utils/templates/isolated/exercises/01-hello-world/README.md +26 -26
@@ -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() {
@@ -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'}),
@@ -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);
@@ -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'}),
@@ -105,9 +105,7 @@ const uploadInitialReadme = async (bucket, exSlug, targetDir, packageContext) =>
105
105
  :rigo
106
106
  \`\`\`
107
107
  `;
108
- const readmeFilename = `README.${packageContext.language && packageContext.language !== "en" ?
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(bucket, rigoToken, steps, packageContext, exercise, tutorialDir, courseSlug, purposeSlug, lastLesson = "") {
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(bucket, rigoToken, syllabusJson.lessons, syllabusJson.courseInfo, exercise, `courses/${courseSlug}`, courseSlug, syllabusJson.courseInfo.purpose, previousReadme +
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(bucket, rigoToken, syllabusJson.lessons, syllabusJson.courseInfo, nextExercise, `courses/${courseSlug}`, courseSlug, syllabusJson.courseInfo.purpose, readme.parsed.content + "\n\n" + feedback);
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(bucket, rigoToken, syllabus.lessons, syllabus.courseInfo, firstLesson, tutorialDir, courseSlug, syllabus.courseInfo.purpose, lastResult);
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(bucket, rigoToken, syllabusJson.lessons, syllabusJson.courseInfo, firstLessonToGenerate, `courses/${courseSlug}`, courseSlug, syllabusJson.courseInfo.purpose, JSON.stringify(lastGeneratedLesson) +
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({ error: error.message || "Unable to fetch file" });
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
- const { data: meta } = await axios_1.default.get("https://www.youtube.com/oembed", {
1156
- params: { url: decoded, format: "json" },
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.status(500).json({ error: error.message || "Failed to fetch link" });
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) => {