@learnpack/learnpack 5.0.28 → 5.0.29

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.
@@ -4,9 +4,17 @@ exports.makePackageInfo = exports.getExInfo = exports.estimateReadingTime = void
4
4
  exports.checkReadingTime = checkReadingTime;
5
5
  exports.extractImagesFromMarkdown = extractImagesFromMarkdown;
6
6
  exports.getFilenameFromUrl = getFilenameFromUrl;
7
+ exports.estimateDuration = estimateDuration;
8
+ exports.createFileOnDesktop = createFileOnDesktop;
9
+ exports.getContentIndex = getContentIndex;
7
10
  // eslint-disable-next-line
8
11
  const frontMatter = require("front-matter");
9
12
  const path = require("path");
13
+ const fs = require("fs");
14
+ const os_1 = require("os");
15
+ const path_1 = require("path");
16
+ const child_process_1 = require("child_process");
17
+ const util_1 = require("util");
10
18
  const yaml = require("js-yaml");
11
19
  const estimateReadingTime = (text, wordsPerMinute = 150) => {
12
20
  const words = text.trim().split(/\s+/).length;
@@ -30,7 +38,7 @@ const estimateReadingTime = (text, wordsPerMinute = 150) => {
30
38
  };
31
39
  };
32
40
  exports.estimateReadingTime = estimateReadingTime;
33
- function checkReadingTime(markdown, wordsPerMinute = 150) {
41
+ function checkReadingTime(markdown, wordsPerMinute = 200, maxMinutes = 1) {
34
42
  const parsed = frontMatter(markdown);
35
43
  const readingTime = (0, exports.estimateReadingTime)(parsed.body, wordsPerMinute);
36
44
  let attributes = parsed.attributes ? parsed.attributes : {};
@@ -38,13 +46,25 @@ function checkReadingTime(markdown, wordsPerMinute = 150) {
38
46
  attributes = {};
39
47
  }
40
48
  const updatedAttributes = Object.assign(Object.assign({}, attributes), { readingTime });
41
- // Convert the front matter back to a proper YAML string
42
- const yamlFrontMatter = yaml.dump(updatedAttributes).trim();
49
+ let yamlFrontMatter = "";
50
+ try {
51
+ yamlFrontMatter = yaml.dump(updatedAttributes).trim();
52
+ }
53
+ catch (_a) {
54
+ return {
55
+ newMarkdown: "",
56
+ exceedsThreshold: false,
57
+ minutes: 0,
58
+ body: "",
59
+ };
60
+ }
43
61
  // Reconstruct the markdown with the front matter
44
62
  const newMarkdown = `---\n${yamlFrontMatter}\n---\n\n${parsed.body}`;
45
63
  return {
46
64
  newMarkdown,
47
- exceedsThreshold: readingTime.minutes > wordsPerMinute,
65
+ exceedsThreshold: readingTime.minutes > maxMinutes,
66
+ minutes: readingTime.minutes,
67
+ body: parsed.body,
48
68
  };
49
69
  }
50
70
  const slugify = (text) => {
@@ -93,8 +113,8 @@ function getFilenameFromUrl(url) {
93
113
  const makePackageInfo = (choices) => {
94
114
  const packageInfo = {
95
115
  grading: choices.grading,
96
- difficulty: choices.difficulty,
97
- duration: parseInt(choices.duration),
116
+ difficulty: "beginner",
117
+ duration: 5,
98
118
  description: {
99
119
  us: choices.description,
100
120
  },
@@ -109,3 +129,65 @@ const makePackageInfo = (choices) => {
109
129
  return packageInfo;
110
130
  };
111
131
  exports.makePackageInfo = makePackageInfo;
132
+ function estimateDuration(listOfSteps) {
133
+ let duration = 0;
134
+ for (const step of listOfSteps) {
135
+ if (step.includes("[READ:")) {
136
+ duration += 1;
137
+ }
138
+ else if (step.includes("[QUIZ:")) {
139
+ duration += 2;
140
+ }
141
+ else if (step.includes("[CODE:")) {
142
+ duration += 3;
143
+ }
144
+ }
145
+ return duration;
146
+ }
147
+ const writeFilePromise = (0, util_1.promisify)(fs.writeFile);
148
+ const execPromise = (0, util_1.promisify)(child_process_1.exec);
149
+ const example_content = `
150
+ 00.1 - Introduction to AI [READ: Small introduction to important concepts such as AI, machine learning, and their applications]
151
+ 01.1 - Introduction to Machine Learning [READ: Small introduction to important concepts such as AI, machine learning, and their applications]
152
+ 01.2 - Introduction to Deep Learning [QUIZ: Small introduction to important concepts such as AI, machine learning, and their applications]
153
+ 02.1 - Test your knowledge [CODE: Code problem to solve]
154
+ `;
155
+ async function createFileOnDesktop() {
156
+ try {
157
+ const desktopPath = (0, path_1.join)((0, os_1.homedir)(), "Desktop");
158
+ const filePath = (0, path_1.join)(desktopPath, "content_index.txt");
159
+ const content = example_content.trim();
160
+ await writeFilePromise(filePath, content);
161
+ console.log(`File created successfully at: ${filePath}`);
162
+ await openFile(filePath);
163
+ }
164
+ catch (error) {
165
+ console.error("Error:", error);
166
+ }
167
+ }
168
+ async function openFile(filePath) {
169
+ const platform = process.platform;
170
+ let command;
171
+ if (platform === "win32") {
172
+ command = `start "" "${filePath}"`;
173
+ }
174
+ else if (platform === "darwin") {
175
+ command = `open "${filePath}"`;
176
+ }
177
+ else {
178
+ command = `xdg-open "${filePath}"`;
179
+ }
180
+ try {
181
+ await execPromise(command);
182
+ console.log("File opened successfully.");
183
+ }
184
+ catch (error) {
185
+ console.error("Error opening the file:", error);
186
+ }
187
+ }
188
+ function getContentIndex() {
189
+ const desktopPath = (0, path_1.join)((0, os_1.homedir)(), "Desktop");
190
+ const filePath = (0, path_1.join)(desktopPath, "content_index.txt");
191
+ const content = fs.readFileSync(filePath, "utf8");
192
+ return content;
193
+ }
@@ -52,4 +52,10 @@ type TReadmeCreatorInputs = {
52
52
  };
53
53
  export declare const readmeCreator: (token: string, inputs: TReadmeCreatorInputs) => Promise<any>;
54
54
  export declare function createPreviewReadme(tutorialDir: string, packageInfo: PackageInfo, rigoToken: string, readmeContents: string[]): Promise<void>;
55
+ type TReduceReadmeInputs = {
56
+ lesson: string;
57
+ number_of_words: string;
58
+ expected_number_words: string;
59
+ };
60
+ export declare function reduceReadme(rigoToken: string, inputs: TReduceReadmeInputs): Promise<any>;
55
61
  export {};
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readmeCreator = exports.createCodingReadme = exports.createCodeFile = exports.interactiveCreation = exports.generateCourseIntroduction = exports.translateExercise = exports.generateImage = exports.hasCreatorPermission = exports.createReadme = void 0;
4
4
  exports.downloadImage = downloadImage;
5
5
  exports.createPreviewReadme = createPreviewReadme;
6
+ exports.reduceReadme = reduceReadme;
6
7
  const axios_1 = require("axios");
7
8
  const fs_1 = require("fs");
8
9
  const console_1 = require("../utils/console");
@@ -175,3 +176,18 @@ async function createPreviewReadme(tutorialDir, packageInfo, rigoToken, readmeCo
175
176
  });
176
177
  fs.writeFileSync(path.join(tutorialDir, readmeFilename), readmeContent.answer);
177
178
  }
179
+ async function reduceReadme(rigoToken, inputs) {
180
+ try {
181
+ const response = await axios_1.default.post(`${RIGOBOT_HOST}/v1/prompting/completion/588/`, { inputs, include_purpose_objective: false, execute_async: false }, {
182
+ headers: {
183
+ "Content-Type": "application/json",
184
+ Authorization: "Token " + rigoToken,
185
+ },
186
+ });
187
+ return response.data;
188
+ }
189
+ catch (error) {
190
+ console_1.default.debug(error);
191
+ return null;
192
+ }
193
+ }
@@ -1 +1 @@
1
- {"version":"5.0.28","commands":{"audit":{"id":"audit","description":"learnpack audit is the command in charge of creating an auditory of the repository\n...\nlearnpack audit checks for the following information in a repository:\n 1. The configuration object has slug, repository and description. (Error)\n 2. The command learnpack clean has been run. (Error)\n 3. If a markdown or test file doesn't have any content. (Error)\n 4. The links are accessing to valid servers. (Error)\n 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)\n 6. The external images are working (If they are pointing to a valid server). (Error)\n 7. The exercises directory names are valid. (Error)\n 8. If an exercise doesn't have a README file. (Error)\n 9. The exercises array (Of the config file) has content. (Error)\n 10. The exercses have the same translations. (Warning)\n 11. The .gitignore file exists. (Warning)\n 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"breakToken":{"id":"breakToken","description":"Break the token","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"clean":{"id":"clean","description":"Clean the configuration object\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"download":{"id":"download","description":"Describe the command here\n...\nExtra documentation goes here\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"init":{"id":"init","description":"Create a new learning package: Book, Tutorial or Exercise","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"logout":{"id":"logout","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"publish":{"id":"publish","description":"Builds the project by copying necessary files and directories into a zip file","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"start":{"id":"start","description":"Runs a small server with all the exercise instructions","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"disableGrading":{"name":"disableGrading","type":"boolean","char":"D","description":"disble grading functionality","allowNo":false},"watch":{"name":"watch","type":"boolean","char":"w","description":"Watch for file changes","allowNo":false},"editor":{"name":"editor","type":"option","char":"e","description":"[preview, extension]","options":["extension","preview"]},"version":{"name":"version","type":"option","char":"v","description":"E.g: 1.0.1"},"grading":{"name":"grading","type":"option","char":"g","description":"[isolated, incremental]","options":["isolated","incremental"]},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"test":{"id":"test","description":"Test exercises","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]},"translate":{"id":"translate","description":"List all the lessons, the user is able of select many of them to translate to the given languages","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[]}}}
1
+ {"version":"5.0.29","commands":{"audit":{"id":"audit","description":"learnpack audit is the command in charge of creating an auditory of the repository\n...\nlearnpack audit checks for the following information in a repository:\n 1. The configuration object has slug, repository and description. (Error)\n 2. The command learnpack clean has been run. (Error)\n 3. If a markdown or test file doesn't have any content. (Error)\n 4. The links are accessing to valid servers. (Error)\n 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)\n 6. The external images are working (If they are pointing to a valid server). (Error)\n 7. The exercises directory names are valid. (Error)\n 8. If an exercise doesn't have a README file. (Error)\n 9. The exercises array (Of the config file) has content. (Error)\n 10. The exercses have the same translations. (Warning)\n 11. The .gitignore file exists. (Warning)\n 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"breakToken":{"id":"breakToken","description":"Break the token","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"clean":{"id":"clean","description":"Clean the configuration object\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[]},"download":{"id":"download","description":"Describe the command here\n...\nExtra documentation goes here\n","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"init":{"id":"init","description":"Create a new learning package: Book, Tutorial or Exercise","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"grading":{"name":"grading","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"logout":{"id":"logout","description":"Describe the command here\n ...\n Extra documentation goes here\n ","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"package","description":"The unique string that identifies this package on learnpack","required":false,"hidden":false}]},"publish":{"id":"publish","description":"Builds the project by copying necessary files and directories into a zip file","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"start":{"id":"start","description":"Runs a small server with all the exercise instructions","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false},"port":{"name":"port","type":"option","char":"p","description":"server port"},"host":{"name":"host","type":"option","char":"h","description":"server host"},"disableGrading":{"name":"disableGrading","type":"boolean","char":"D","description":"disble grading functionality","allowNo":false},"watch":{"name":"watch","type":"boolean","char":"w","description":"Watch for file changes","allowNo":false},"editor":{"name":"editor","type":"option","char":"e","description":"[preview, extension]","options":["extension","preview"]},"version":{"name":"version","type":"option","char":"v","description":"E.g: 1.0.1"},"grading":{"name":"grading","type":"option","char":"g","description":"[isolated, incremental]","options":["isolated","incremental"]},"debug":{"name":"debug","type":"boolean","char":"d","description":"debugger mode for more verbage","allowNo":false}},"args":[]},"test":{"id":"test","description":"Test exercises","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[{"name":"exerciseSlug","description":"The name of the exercise to test","required":false,"hidden":false}]},"translate":{"id":"translate","description":"List all the lessons, the user is able of select many of them to translate to the given languages","pluginName":"@learnpack/learnpack","pluginType":"core","aliases":[],"flags":{"yes":{"name":"yes","type":"boolean","char":"y","description":"Skip all prompts and initialize an empty project","allowNo":false}},"args":[]}}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@learnpack/learnpack",
3
3
  "description": "Seamlessly build, sell and/or take interactive & auto-graded tutorials, start learning now or build a new tutorial to your audience.",
4
- "version": "5.0.28",
4
+ "version": "5.0.29",
5
5
  "author": "Alejandro Sanchez @alesanchezr",
6
6
  "contributors": [
7
7
  {
@@ -5,6 +5,7 @@ import * as fs from "fs-extra"
5
5
  import Console from "../utils/console"
6
6
 
7
7
  import SessionManager from "../managers/session"
8
+ import { createFileOnDesktop, getContentIndex } from "../utils/creatorUtilities"
8
9
 
9
10
  class BreakTokenCommand extends BaseCommand {
10
11
  static description = "Break the token"
@@ -17,8 +18,18 @@ class BreakTokenCommand extends BaseCommand {
17
18
  async run() {
18
19
  const { flags } = this.parse(BreakTokenCommand)
19
20
 
20
- await SessionManager.breakToken()
21
- process.exit(0)
21
+ // await SessionManager.breakToken()
22
+ await createFileOnDesktop()
23
+ Console.info(
24
+ "File created on desktop, please make the necessary changes and continue when ready"
25
+ )
26
+
27
+ // Wait for user to press enter
28
+ process.stdin.once("data", () => {
29
+ Console.info("File content:")
30
+ Console.info(getContentIndex())
31
+ process.exit(0)
32
+ })
22
33
  }
23
34
  }
24
35
 
@@ -19,6 +19,7 @@ import {
19
19
  createCodeFile,
20
20
  readmeCreator,
21
21
  createPreviewReadme,
22
+ reduceReadme,
22
23
  } from "../utils/rigoActions"
23
24
  import { getConsumable } from "../utils/api"
24
25
  import {
@@ -28,9 +29,18 @@ import {
28
29
  extractImagesFromMarkdown,
29
30
  getFilenameFromUrl,
30
31
  makePackageInfo,
32
+ estimateDuration,
33
+ getContentIndex,
34
+ createFileOnDesktop,
31
35
  } from "../utils/creatorUtilities"
32
36
  import SessionManager from "../managers/session"
33
37
 
38
+ const durationByKind: Record<string, number> = {
39
+ code: 3,
40
+ quiz: 2,
41
+ read: 1,
42
+ }
43
+
34
44
  const initializeInteractiveCreation = async (
35
45
  rigoToken: string,
36
46
  courseInfo: string
@@ -39,12 +49,16 @@ const initializeInteractiveCreation = async (
39
49
  title: string
40
50
  description: string
41
51
  interactions: string
52
+ difficulty: string
53
+ duration: number
42
54
  }> => {
43
55
  let prevInteractions = ""
44
56
  let isReady = false
45
57
  let currentSteps = []
46
58
  let currentTitle = ""
47
59
  let currentDescription = ""
60
+ let currentDifficulty = ""
61
+
48
62
  while (!isReady) {
49
63
  let wholeInfo = courseInfo
50
64
  wholeInfo += `
@@ -69,6 +83,10 @@ const initializeInteractiveCreation = async (
69
83
  currentDescription = res.parsed.description
70
84
  }
71
85
 
86
+ if (res.parsed.difficulty && currentDifficulty !== res.parsed.difficulty) {
87
+ currentDifficulty = res.parsed.difficulty
88
+ }
89
+
72
90
  if (!isReady) {
73
91
  console.log(currentSteps)
74
92
  Console.info(`AI: ${res.parsed.aiMessage}`)
@@ -85,14 +103,49 @@ const initializeInteractiveCreation = async (
85
103
  }
86
104
  }
87
105
 
106
+ const duration = estimateDuration(currentSteps)
88
107
  return {
89
108
  steps: currentSteps,
90
109
  title: currentTitle,
91
110
  description: currentDescription,
92
111
  interactions: prevInteractions,
112
+ difficulty: currentDifficulty,
113
+ duration,
93
114
  }
94
115
  }
95
116
 
117
+ const appendContentIndex = async () => {
118
+ const choices = await prompts([
119
+ {
120
+ type: "confirm",
121
+ name: "contentIndex",
122
+ message: "Do you have a content index for this tutorial?",
123
+ },
124
+ ])
125
+ if (choices.contentIndex) {
126
+ await createFileOnDesktop()
127
+ Console.info(
128
+ "Please make the necessary in the recently created file in your desktop, it should automatically open. Edit the file to match your expectations and save it. Keep the same name and structure as the example file. Continue when ready."
129
+ )
130
+ const isReady = await prompts([
131
+ {
132
+ type: "confirm",
133
+ name: "isReady",
134
+ message: "Are you ready to continue?",
135
+ },
136
+ ])
137
+ if (!isReady.isReady) {
138
+ Console.error("Please make the necessary changes and try again.")
139
+ process.exit(1)
140
+ }
141
+
142
+ const contentIndex = getContentIndex()
143
+ return contentIndex
144
+ }
145
+
146
+ return null
147
+ }
148
+
96
149
  const handleAILogic = async (tutorialDir: string, packageInfo: PackageInfo) => {
97
150
  fs.removeSync(path.join(tutorialDir, "exercises", "01-hello-world"))
98
151
 
@@ -135,26 +188,32 @@ const handleAILogic = async (tutorialDir: string, packageInfo: PackageInfo) => {
135
188
 
136
189
  Console.success("🎉 Let's begin this learning journey!")
137
190
 
191
+ const contentIndex = await appendContentIndex()
192
+
138
193
  let packageContext = `
139
194
  \n
140
195
  Title: ${packageInfo.title.us}
141
196
  Description: ${packageInfo.description.us}
142
- Difficulty: ${packageInfo.difficulty}
143
- Duration: ${packageInfo.duration}
197
+
198
+ ${
199
+ contentIndex ?
200
+ `Content Index submitted by the user, use this to guide your creation: ${contentIndex}` :
201
+ ""
202
+ }
203
+
144
204
  `
145
205
 
146
- const { steps, title, description } = await initializeInteractiveCreation(
147
- rigoToken,
148
- packageContext
149
- )
206
+ const { steps, title, description, duration, difficulty } =
207
+ await initializeInteractiveCreation(rigoToken, packageContext)
150
208
  packageInfo.title.us = title
151
209
  packageInfo.description.us = description
210
+ packageInfo.duration = duration
211
+ packageInfo.difficulty = difficulty
152
212
 
153
213
  packageContext = `
154
214
  Title: ${title}
155
215
  Description: ${description}
156
- Difficulty: ${packageInfo.difficulty}
157
- Estimated duration: ${packageInfo.duration}
216
+
158
217
  List of exercises: ${steps.join(", ")}
159
218
  `
160
219
  const exercisesDir = path.join(tutorialDir, "exercises")
@@ -180,21 +239,38 @@ const handleAILogic = async (tutorialDir: string, packageInfo: PackageInfo) => {
180
239
  kind: kind.toLowerCase(),
181
240
  })
182
241
 
183
- const { exceedsThreshold, newMarkdown } = checkReadingTime(
242
+ const duration = durationByKind[kind.toLowerCase()]
243
+ let readingTime = checkReadingTime(
184
244
  readme.parsed.content,
185
- 200
245
+ 200,
246
+ duration || 1
186
247
  )
187
248
 
188
- if (exceedsThreshold) {
189
- Console.error("The reading time exceeds the threshold")
190
- Console.info(
191
- `Please reduce the reading time of the lesson, current reading time is ${exceedsThreshold} minutes`
192
- )
249
+ if (readingTime.exceedsThreshold) {
250
+ // Console.info(
251
+ // `The reading time for the lesson ${exTitle} exceeds the threshold, reducing it...`
252
+ // )
253
+ const reducedReadme = await reduceReadme(rigoToken, {
254
+ lesson: readingTime.body,
255
+ number_of_words: readingTime.minutes.toString(),
256
+ expected_number_words: "200",
257
+ })
258
+
259
+ if (reducedReadme) {
260
+ readingTime = checkReadingTime(
261
+ reducedReadme.parsed.content,
262
+ 200,
263
+ duration || 1
264
+ )
265
+ }
193
266
  }
194
267
 
195
268
  const readmeFilename = "README.md"
196
269
 
197
- fs.writeFileSync(path.join(exerciseDir, readmeFilename), newMarkdown)
270
+ fs.writeFileSync(
271
+ path.join(exerciseDir, readmeFilename),
272
+ readingTime.newMarkdown
273
+ )
198
274
 
199
275
  if (kind.toLowerCase() === "code") {
200
276
  const codeFile = await createCodeFile(rigoToken, {
@@ -211,15 +287,14 @@ const handleAILogic = async (tutorialDir: string, packageInfo: PackageInfo) => {
211
287
  )
212
288
  }
213
289
 
214
- return readme.parsed.content
290
+ return readingTime.newMarkdown
215
291
  })
216
292
 
217
- let imagesArray: any[] = []
218
-
219
293
  const readmeContents = await Promise.all(exercisePromises)
220
-
221
294
  Console.success("Lessons created! 🎉")
295
+
222
296
  Console.info("Generating images for the lessons...")
297
+ let imagesArray: any[] = []
223
298
 
224
299
  for (const content of readmeContents) {
225
300
  imagesArray = [...imagesArray, ...extractImagesFromMarkdown(content)]
@@ -256,7 +331,7 @@ const getChoices = async (empty: boolean) => {
256
331
  title: "My Interactive Tutorial",
257
332
  description: "",
258
333
  difficulty: "beginner",
259
- duration: 1,
334
+ duration: 5,
260
335
  useAI: "no",
261
336
  grading: "isolated",
262
337
  }
@@ -294,30 +369,7 @@ const getChoices = async (empty: boolean) => {
294
369
  initial: "",
295
370
  message: "Description for your tutorial? Press enter to leave blank",
296
371
  },
297
- {
298
- type: "select",
299
- name: "difficulty",
300
- message: "How difficulty will be to complete the tutorial?",
301
- choices: [
302
- { title: "Begginer (no previous experience)", value: "beginner" },
303
- { title: "Easy (just a bit of experience required)", value: "easy" },
304
- {
305
- title: "Intermediate (you need experience)",
306
- value: "intermediate",
307
- },
308
- { title: "Hard (master the topic)", value: "hard" },
309
- ],
310
- },
311
- {
312
- type: "text",
313
- name: "duration",
314
- initial: "1",
315
- message: "How many hours avg it takes to complete (number)?",
316
- validate: (value: string) => {
317
- const n = Math.floor(Number(value))
318
- return n !== Number.POSITIVE_INFINITY && String(n) === value && n >= 0
319
- },
320
- },
372
+
321
373
  {
322
374
  type: "select",
323
375
  name: "useAI",
@@ -333,7 +385,12 @@ const getChoices = async (empty: boolean) => {
333
385
  },
334
386
  ])
335
387
 
336
- return choices
388
+ const completeChoices = {
389
+ ...choices,
390
+ difficulty: "beginner",
391
+ duration: 30,
392
+ }
393
+ return completeChoices
337
394
  }
338
395
 
339
396
  class InitComand extends BaseCommand {
@@ -117,7 +117,7 @@ export default class BuildCommand extends SessionCommand {
117
117
  }
118
118
 
119
119
  // const academies = await api.listUserAcademies(sessionPayload.token)
120
- // console.log(academies, "academies")
120
+ // // console.log(academies, "academies")
121
121
  // const academy = await selectAcademy(academies)
122
122
  // console.log(academy, "academy")
123
123
 
@@ -176,10 +176,12 @@ export default class StartCommand extends SessionCommand {
176
176
 
177
177
  const files = prioritizeHTMLFile(data.files)
178
178
 
179
- if (config.editor.agent === "os") {
179
+ if (config.editor.agent !== "os") {
180
+ // Console.info("Opening files for vscode agent")
180
181
  eventManager.enqueue(dispatcher.events.OPEN_FILES, files)
181
182
  } else {
182
- dispatcher.enqueue(dispatcher.events.OPEN_FILES, files)
183
+ // dispatcher.enqueue(dispatcher.events.OPEN_FILES, files)
184
+ Console.debug("Ignoring files for os agent")
183
185
  }
184
186
 
185
187
  socket.ready("Ready to compile...")
@@ -187,10 +189,14 @@ export default class StartCommand extends SessionCommand {
187
189
 
188
190
  socket.on("open_window", (data: TOpenWindowData) => {
189
191
  Console.debug("Opening window: ", data)
192
+ console.log("config.os", config.os)
193
+
190
194
  // cli.open(data.url); This uses XDG under the ground
191
195
  if (config.os !== "linux" || (config.os === "linux" && hasXDG)) {
196
+ console.log("Opening window with XDG")
192
197
  eventManager.enqueue(dispatcher.events.OPEN_WINDOW, data)
193
198
  } else {
199
+ console.log("Opening window without XDG")
194
200
  dispatcher.enqueue(dispatcher.events.OPEN_WINDOW, data)
195
201
  }
196
202
 
@@ -249,16 +255,6 @@ export default class StartCommand extends SessionCommand {
249
255
  })
250
256
  })
251
257
 
252
- // socket.on("quiz_submission", (data: any) => {
253
- // const { stepPosition, event, eventData } = data
254
- // TelemetryManager.registerStepEvent(stepPosition, event, eventData)
255
- // })
256
-
257
- // socket.on("ai_interaction", (data: any) => {
258
- // const { stepPosition, event, eventData } = data
259
- // TelemetryManager.registerStepEvent(stepPosition, event, eventData)
260
- // })
261
-
262
258
  socket.on("telemetry_event", (data: any) => {
263
259
  const { stepPosition, event, eventData } = data
264
260
 
@@ -358,9 +354,9 @@ export default class StartCommand extends SessionCommand {
358
354
 
359
355
  // start watching for file changes
360
356
  if (StartCommand.flags.watch)
361
- this.configManager.watchIndex(_filename => {
357
+ this.configManager.watchIndex((_filename, _fileContent) => {
362
358
  // Instead of reloading with socket.reload(), I just notify the frontend for the file change
363
- socket.emit("file_change", "ready", _filename)
359
+ socket.emit("file_change", "ready", [_filename, _fileContent])
364
360
  })
365
361
  }
366
362
  }