@learnpack/learnpack 5.0.29 → 5.0.31

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 CHANGED
@@ -21,7 +21,7 @@ $ npm install -g @learnpack/learnpack
21
21
  $ learnpack COMMAND
22
22
  running command...
23
23
  $ learnpack (-v|--version|version)
24
- @learnpack/learnpack/5.0.29 win32-x64 node-v20.16.0
24
+ @learnpack/learnpack/5.0.31 win32-x64 node-v20.16.0
25
25
  $ learnpack --help [COMMAND]
26
26
  USAGE
27
27
  $ learnpack COMMAND
@@ -76,7 +76,7 @@ DESCRIPTION
76
76
  12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
77
77
  ```
78
78
 
79
- _See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.29/src\commands\audit.ts)_
79
+ _See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.31/src\commands\audit.ts)_
80
80
 
81
81
  ## `learnpack breakToken`
82
82
 
@@ -91,7 +91,7 @@ OPTIONS
91
91
  -y, --yes Skip all prompts and initialize an empty project
92
92
  ```
93
93
 
94
- _See code: [src\commands\breakToken.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.29/src\commands\breakToken.ts)_
94
+ _See code: [src\commands\breakToken.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.31/src\commands\breakToken.ts)_
95
95
 
96
96
  ## `learnpack clean`
97
97
 
@@ -106,7 +106,7 @@ DESCRIPTION
106
106
  Extra documentation goes here
107
107
  ```
108
108
 
109
- _See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.29/src\commands\clean.ts)_
109
+ _See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.31/src\commands\clean.ts)_
110
110
 
111
111
  ## `learnpack download [PACKAGE]`
112
112
 
@@ -124,7 +124,7 @@ DESCRIPTION
124
124
  Extra documentation goes here
125
125
  ```
126
126
 
127
- _See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.29/src\commands\download.ts)_
127
+ _See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.31/src\commands\download.ts)_
128
128
 
129
129
  ## `learnpack help [COMMAND]`
130
130
 
@@ -156,7 +156,7 @@ OPTIONS
156
156
  -y, --yes Skip all prompts and initialize an empty project
157
157
  ```
158
158
 
159
- _See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.29/src\commands\init.ts)_
159
+ _See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.31/src\commands\init.ts)_
160
160
 
161
161
  ## `learnpack login [PACKAGE]`
162
162
 
@@ -174,7 +174,7 @@ DESCRIPTION
174
174
  Extra documentation goes here
175
175
  ```
176
176
 
177
- _See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.29/src\commands\login.ts)_
177
+ _See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.31/src\commands\login.ts)_
178
178
 
179
179
  ## `learnpack logout [PACKAGE]`
180
180
 
@@ -192,7 +192,7 @@ DESCRIPTION
192
192
  Extra documentation goes here
193
193
  ```
194
194
 
195
- _See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.29/src\commands\logout.ts)_
195
+ _See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.31/src\commands\logout.ts)_
196
196
 
197
197
  ## `learnpack plugins`
198
198
 
@@ -323,7 +323,7 @@ OPTIONS
323
323
  -h, --help show CLI help
324
324
  ```
325
325
 
326
- _See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.29/src\commands\publish.ts)_
326
+ _See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.31/src\commands\publish.ts)_
327
327
 
328
328
  ## `learnpack start`
329
329
 
@@ -345,7 +345,7 @@ OPTIONS
345
345
  -y, --yes Skip all prompts and initialize an empty project
346
346
  ```
347
347
 
348
- _See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.29/src\commands\start.ts)_
348
+ _See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.31/src\commands\start.ts)_
349
349
 
350
350
  ## `learnpack test [EXERCISESLUG]`
351
351
 
@@ -362,7 +362,7 @@ OPTIONS
362
362
  -y, --yes Skip all prompts and initialize an empty project
363
363
  ```
364
364
 
365
- _See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.29/src\commands\test.ts)_
365
+ _See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.31/src\commands\test.ts)_
366
366
 
367
367
  ## `learnpack translate`
368
368
 
@@ -376,7 +376,7 @@ OPTIONS
376
376
  -y, --yes Skip all prompts and initialize an empty project
377
377
  ```
378
378
 
379
- _See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.29/src\commands\translate.ts)_
379
+ _See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.31/src\commands\translate.ts)_
380
380
  <!-- commandsstop -->
381
381
 
382
382
  > > > > > > > 0cb3e56d84c197f9d008836bb573eade212b7e57
@@ -329,21 +329,21 @@ class AuditCommand extends SessionCommand_1.default {
329
329
  }
330
330
  }
331
331
  }
332
- AuditCommand.description = `learnpack audit is the command in charge of creating an auditory of the repository
333
- ...
334
- learnpack audit checks for the following information in a repository:
335
- 1. The configuration object has slug, repository and description. (Error)
336
- 2. The command learnpack clean has been run. (Error)
337
- 3. If a markdown or test file doesn't have any content. (Error)
338
- 4. The links are accessing to valid servers. (Error)
339
- 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)
340
- 6. The external images are working (If they are pointing to a valid server). (Error)
341
- 7. The exercises directory names are valid. (Error)
342
- 8. If an exercise doesn't have a README file. (Error)
343
- 9. The exercises array (Of the config file) has content. (Error)
344
- 10. The exercses have the same translations. (Warning)
345
- 11. The .gitignore file exists. (Warning)
346
- 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
332
+ AuditCommand.description = `learnpack audit is the command in charge of creating an auditory of the repository
333
+ ...
334
+ learnpack audit checks for the following information in a repository:
335
+ 1. The configuration object has slug, repository and description. (Error)
336
+ 2. The command learnpack clean has been run. (Error)
337
+ 3. If a markdown or test file doesn't have any content. (Error)
338
+ 4. The links are accessing to valid servers. (Error)
339
+ 5. The relative images are working (If they have the shortest path to the image or if the images exists in the assets). (Error)
340
+ 6. The external images are working (If they are pointing to a valid server). (Error)
341
+ 7. The exercises directory names are valid. (Error)
342
+ 8. If an exercise doesn't have a README file. (Error)
343
+ 9. The exercises array (Of the config file) has content. (Error)
344
+ 10. The exercses have the same translations. (Warning)
345
+ 11. The .gitignore file exists. (Warning)
346
+ 12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
347
347
  `;
348
348
  AuditCommand.flags = {
349
349
  // name: flags.string({char: 'n', description: 'name to print'}),
@@ -20,6 +20,16 @@ const durationByKind = {
20
20
  quiz: 2,
21
21
  read: 1,
22
22
  };
23
+ const whichTargetAudience = async () => {
24
+ const res = await prompts([
25
+ {
26
+ type: "text",
27
+ name: "targetAudience",
28
+ message: "What is the target audience for this tutorial?",
29
+ },
30
+ ]);
31
+ return res.targetAudience;
32
+ };
23
33
  const initializeInteractiveCreation = async (rigoToken, courseInfo) => {
24
34
  let prevInteractions = "";
25
35
  let isReady = false;
@@ -105,9 +115,14 @@ const appendContentIndex = async () => {
105
115
  const handleAILogic = async (tutorialDir, packageInfo) => {
106
116
  fs.removeSync(path.join(tutorialDir, "exercises", "01-hello-world"));
107
117
  let sessionPayload = await session_1.default.getPayload();
108
- if (!sessionPayload ||
109
- !sessionPayload.rigobot ||
110
- (sessionPayload.token && !(await api_1.default.validateToken(sessionPayload.token)))) {
118
+ const sessionExists = sessionPayload && sessionPayload.rigobot;
119
+ const isValidToken = sessionExists && sessionPayload.rigobot.key ?
120
+ await (0, rigoActions_1.isValidRigoToken)(sessionPayload.rigobot.key) :
121
+ false;
122
+ const isValidBreathecodeToken = sessionExists && sessionPayload.token ?
123
+ await api_1.default.validateToken(sessionPayload.token) :
124
+ false;
125
+ if (!sessionExists || !isValidBreathecodeToken || !isValidToken) {
111
126
  console_1.default.info("Almost there! First you need to login with 4Geeks.com to use AI Generation tool for creators. You can create a new account here: https://4geeks.com/creators");
112
127
  try {
113
128
  sessionPayload = await session_1.default.login();
@@ -129,14 +144,20 @@ const handleAILogic = async (tutorialDir, packageInfo) => {
129
144
  process.exit(1);
130
145
  }
131
146
  console_1.default.success("🎉 Let's begin this learning journey!");
147
+ const targetAudience = await whichTargetAudience();
132
148
  const contentIndex = await appendContentIndex();
133
149
  let packageContext = `
134
150
  \n
135
- Title: ${packageInfo.title.us}
136
- Description: ${packageInfo.description.us}
151
+ Title: "${packageInfo.title.us}"
152
+ Description: "${packageInfo.description.us}"
153
+ Target Audience: "${targetAudience}"
137
154
 
138
155
  ${contentIndex ?
139
- `Content Index submitted by the user, use this to guide your creation: ${contentIndex}` :
156
+ `Content Index submitted by the user, use this to guide your creation. Keep in mind that your tutorial should contain these topics:
157
+ ---
158
+ ${contentIndex}
159
+ ---
160
+ ` :
140
161
  ""}
141
162
 
142
163
  `;
@@ -146,9 +167,9 @@ const handleAILogic = async (tutorialDir, packageInfo) => {
146
167
  packageInfo.duration = duration;
147
168
  packageInfo.difficulty = difficulty;
148
169
  packageContext = `
149
- Title: ${title}
150
- Description: ${description}
151
-
170
+ Title: "${title}"
171
+ Description: "${description}"
172
+ Target Audience: "${targetAudience}"
152
173
  List of exercises: ${steps.join(", ")}
153
174
  `;
154
175
  const exercisesDir = path.join(tutorialDir, "exercises");
@@ -238,16 +259,19 @@ const getChoices = async (empty) => {
238
259
  {
239
260
  type: "select",
240
261
  name: "grading",
241
- message: "Is the auto-grading going to be isolated or incremental?",
262
+ message: "How are you going to grade students or yourself?",
242
263
  choices: [
243
264
  {
244
- title: "Incremental: Build on top of each other like a tutorial",
245
- value: "incremental",
265
+ title: "No grading: No feedback or testing whatsoever, similar to a an interactive book.",
266
+ value: null,
246
267
  },
247
- { title: "Isolated: Small separated exercises", value: "isolated" },
248
268
  {
249
- title: "No grading: No feedback or testing whatsoever",
250
- value: null,
269
+ title: "Isolated: Each step is a new separate exercise",
270
+ value: "isolated",
271
+ },
272
+ {
273
+ title: "Step by step: Each step builds on top of each other like an incremental tutorial",
274
+ value: "incremental",
251
275
  },
252
276
  ],
253
277
  },
@@ -1,27 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- // import {Command, flags} from '@oclif/command'
4
- // import { prompt } from "enquirer"
5
- // import fetch from 'node-fetch'
6
3
  const SessionCommand_1 = require("../utils/SessionCommand");
7
4
  const session_1 = require("../managers/session");
8
- // import Console from '../utils/console'
9
- // import { replace } from 'node-emoji'
10
- // import { validURL } from "../utils/validators"
11
- // const BaseCommand from '../utils/BaseCommand');
5
+ const console_1 = require("../utils/console");
12
6
  class LogoutCommand extends SessionCommand_1.default {
13
7
  async init() {
14
8
  const { flags } = this.parse(LogoutCommand);
15
- await this.initSession(flags);
9
+ // await this.initSession(flags)
10
+ console_1.default.debug("Logout command");
16
11
  }
17
12
  async run() {
18
13
  // const {flags, args} = this.parse(LogoutCommand)
19
14
  session_1.default.destroy();
20
15
  }
21
16
  }
22
- LogoutCommand.description = `Describe the command here
23
- ...
24
- Extra documentation goes here
17
+ LogoutCommand.description = `Describe the command here
18
+ ...
19
+ Extra documentation goes here
25
20
  `;
26
21
  LogoutCommand.flags = {
27
22
  // name: flags.string({char: 'n', description: 'name to print'}),
@@ -94,14 +94,11 @@ class StartCommand extends SessionCommand_1.default {
94
94
  });
95
95
  socket_1.default.on("open_window", (data) => {
96
96
  console_1.default.debug("Opening window: ", data);
97
- console.log("config.os", config.os);
98
97
  // cli.open(data.url); This uses XDG under the ground
99
98
  if (config.os !== "linux" || (config.os === "linux" && hasXDG)) {
100
- console.log("Opening window with XDG");
101
99
  osOperations_1.eventManager.enqueue(dispatcher.events.OPEN_WINDOW, data);
102
100
  }
103
101
  else {
104
- console.log("Opening window without XDG");
105
102
  dispatcher.enqueue(dispatcher.events.OPEN_WINDOW, data);
106
103
  }
107
104
  socket_1.default.log("open_window", "", undefined, data.url);
@@ -7,6 +7,7 @@ const prompts = require("prompts");
7
7
  const rigoActions_1 = require("../utils/rigoActions");
8
8
  const session_1 = require("../managers/session");
9
9
  const console_1 = require("../utils/console");
10
+ const creatorUtilities_1 = require("../utils/creatorUtilities");
10
11
  // This function list the names of the exercise directories inside the ./exercises folder, if the exercises folder doesn't exist, it will look for the ./.learn/exercises folder
11
12
  const listExercises = async () => {
12
13
  const exercisesDir = path.join(process.cwd(), "exercises");
@@ -21,18 +22,10 @@ const listExercises = async () => {
21
22
  return fs.statSync(path.join(learnExercisesDir, file)).isDirectory();
22
23
  });
23
24
  };
24
- const cleanReadme = (readme) => {
25
- // Replace <text> and </text> with nothing
26
- return readme.replace(/<text>/g, "").replace(/<\/text>/g, "");
27
- };
28
25
  const getReadmeForExercise = async (exercise) => {
29
26
  const readmePath = path.join(process.cwd(), "exercises", exercise, "README.md");
30
27
  return fs.readFileSync(readmePath, "utf8");
31
28
  };
32
- const saveTranslatedReadme = async (exercise, languageCode, readme) => {
33
- const readmePath = path.join(process.cwd(), "exercises", exercise, `README.${languageCode}.md`);
34
- fs.writeFileSync(readmePath, cleanReadme(readme));
35
- };
36
29
  class BuildCommand extends SessionCommand_1.default {
37
30
  async init() {
38
31
  const { flags } = this.parse(BuildCommand);
@@ -86,8 +79,7 @@ class BuildCommand extends SessionCommand_1.default {
86
79
  text_to_translate: readme,
87
80
  output_language: language,
88
81
  });
89
- console.log(response, "RESPONSE");
90
- await saveTranslatedReadme(exercise, response.parsed.output_language_code, response.parsed.translation);
82
+ await (0, creatorUtilities_1.saveTranslatedReadme)(exercise, response.parsed.output_language_code, response.parsed.translation);
91
83
  console_1.default.success(`Translated ${exercise} to ${language} successfully`);
92
84
  }));
93
85
  }));
@@ -372,6 +372,31 @@ exports.default = async ({ grading, mode, disableGrading, version, }) => {
372
372
  [(0, exercise_1.exercise)(((_b = configObj === null || configObj === void 0 ? void 0 : configObj.config) === null || _b === void 0 ? void 0 : _b.exercisesPath) || "", 0, configObj)];
373
373
  this.save();
374
374
  },
375
+ createExercise: (slug, content, language) => {
376
+ var _a;
377
+ try {
378
+ const dirPath = `${(_a = configObj.config) === null || _a === void 0 ? void 0 : _a.exercisesPath}/${slug}`;
379
+ if (!fs.existsSync(dirPath))
380
+ fs.mkdirSync(dirPath, { recursive: true });
381
+ const isEnglish = language === "us" || language === "en";
382
+ const fileName = isEnglish ? "README.md" : `README.${language}.md`;
383
+ fs.writeFileSync(`${dirPath}/${fileName}`, content);
384
+ return true;
385
+ }
386
+ catch (error) {
387
+ console_1.default.error("Error creating exercise: ", error);
388
+ return false;
389
+ }
390
+ },
391
+ deleteExercise: (slug) => {
392
+ var _a;
393
+ const dirPath = `${(_a = configObj.config) === null || _a === void 0 ? void 0 : _a.exercisesPath}/${slug}`;
394
+ if (fs.existsSync(dirPath)) {
395
+ fs.rmSync(dirPath, { recursive: true, force: true });
396
+ return true;
397
+ }
398
+ return false;
399
+ },
375
400
  watchIndex: function (onChange) {
376
401
  var _a;
377
402
  if (configObj.config && !configObj.config.exercisesPath)
@@ -423,66 +448,66 @@ function deepMerge(...sources) {
423
448
  return acc;
424
449
  }
425
450
  const buildAgentWarning = (current, suggested) => {
426
- const message = `# Agent mismatch!\n
427
-
428
- In LearnPack, the agent is in charge of running the LearnPack interface.
429
-
430
- You're currently using LearnPack through \`${current}\` but the suggested agent is \`${suggested}\`.
431
-
432
- We recommend strongly recommend changing your agent.
433
-
434
- ${stepsToChangeAgent(suggested)}
451
+ const message = `# Agent mismatch!\n
452
+
453
+ In LearnPack, the agent is in charge of running the LearnPack interface.
454
+
455
+ You're currently using LearnPack through \`${current}\` but the suggested agent is \`${suggested}\`.
456
+
457
+ We recommend strongly recommend changing your agent.
458
+
459
+ ${stepsToChangeAgent(suggested)}
435
460
  `;
436
461
  return message;
437
462
  };
438
463
  const stepsToChangeAgent = (agent) => {
439
464
  if (agent === "vscode") {
440
- return `
441
- # Steps to Change Agent to VSCode
442
-
443
- 1. **Install VSCode**:
444
- - Visit the [VSCode website](https://code.visualstudio.com/Download) and download the latest version.
445
- - Follow the installation instructions for your operating system.
446
-
447
- 2. **Install LearnPack VSCode Extension**:
448
- - Open VSCode.
449
- - Go to the Extensions view by clicking on the Extensions icon in the Activity Bar on the side of the window or by pressing \`Ctrl+Shift+X\`.
450
- - Search for "LearnPack" and click "Install".
451
- - If the extension is already installed but disabled, enable it.
452
-
453
- 3. **Run LearnPack in VSCode**:
454
- - Open your terminal in VSCode.
455
- - Navigate to your LearnPack project directory.
456
- - Run the following command:
457
- \`\`\`sh
458
- learnpack start
459
- \`\`\`
460
-
461
- We strongly recommend using VSCode for a better learning experience.
465
+ return `
466
+ # Steps to Change Agent to VSCode
467
+
468
+ 1. **Install VSCode**:
469
+ - Visit the [VSCode website](https://code.visualstudio.com/Download) and download the latest version.
470
+ - Follow the installation instructions for your operating system.
471
+
472
+ 2. **Install LearnPack VSCode Extension**:
473
+ - Open VSCode.
474
+ - Go to the Extensions view by clicking on the Extensions icon in the Activity Bar on the side of the window or by pressing \`Ctrl+Shift+X\`.
475
+ - Search for "LearnPack" and click "Install".
476
+ - If the extension is already installed but disabled, enable it.
477
+
478
+ 3. **Run LearnPack in VSCode**:
479
+ - Open your terminal in VSCode.
480
+ - Navigate to your LearnPack project directory.
481
+ - Run the following command:
482
+ \`\`\`sh
483
+ learnpack start
484
+ \`\`\`
485
+
486
+ We strongly recommend using VSCode for a better learning experience.
462
487
  `;
463
488
  }
464
489
  if (agent === "os") {
465
- return `
466
- # Steps to Change Agent to OS
467
-
468
- This learning package was designed to run outside of VSCode. We strongly recommend closing VSCode and running the package independently.
469
-
470
- 1. **Close VSCode**:
471
- - Save your work and close the VSCode application.
472
-
473
- 2. **Open a New Terminal**:
474
- - Open a terminal or command prompt on your operating system.
475
-
476
- 3. **Navigate to Your LearnPack Project Directory**:
477
- - Use the \`cd\` command to navigate to the directory where your LearnPack project is located.
478
-
479
- 4. **Run LearnPack**:
480
- - Run the following command to start LearnPack:
481
- \`\`\`sh
482
- learnpack start
483
- \`\`\`
484
-
485
- We strongly recommend running the package independently for a better learning experience.
490
+ return `
491
+ # Steps to Change Agent to OS
492
+
493
+ This learning package was designed to run outside of VSCode. We strongly recommend closing VSCode and running the package independently.
494
+
495
+ 1. **Close VSCode**:
496
+ - Save your work and close the VSCode application.
497
+
498
+ 2. **Open a New Terminal**:
499
+ - Open a terminal or command prompt on your operating system.
500
+
501
+ 3. **Navigate to Your LearnPack Project Directory**:
502
+ - Use the \`cd\` command to navigate to the directory where your LearnPack project is located.
503
+
504
+ 4. **Run LearnPack**:
505
+ - Run the following command to start LearnPack:
506
+ \`\`\`sh
507
+ learnpack start
508
+ \`\`\`
509
+
510
+ We strongly recommend running the package independently for a better learning experience.
486
511
  `;
487
512
  }
488
513
  return "";
@@ -508,31 +533,31 @@ const isExtensionInstalled = (extensionName) => {
508
533
  const result = shell.exec("code --list-extensions", { silent: true });
509
534
  return result.stdout.split("\n").includes(extensionName);
510
535
  };
511
- const EXTENSION_INSTALLATION_STEPS = `
512
- # Steps to Install LearnPack VSCode Extension
513
-
514
- 1. **Open VSCode**:
515
- - Launch the Visual Studio Code application on your computer.
516
-
517
- 2. **Go to Extensions View**:
518
- - Click on the Extensions icon in the Activity Bar on the side of the window.
519
- - Alternatively, you can open the Extensions view by pressing \`Ctrl+Shift+X\`.
520
-
521
- 3. **Search for LearnPack**:
522
- - In the Extensions view, type "LearnPack" into the search bar.
523
-
524
- 4. **Install the Extension**:
525
- - Find the "LearnPack" extension in the search results and click the "Install" button.
526
- - If the extension is already installed but disabled, click the "Enable" button.
527
-
528
- 5. **Verify Installation**:
529
- - Once installed, you can verify the installation by running the following command in the terminal:
530
- \`\`\`sh
531
- code --list-extensions | grep learn-pack.learnpack-vscode
532
- \`\`\`
533
- - If the extension is listed, it means the installation was successful.
534
-
535
- We strongly recommend using the LearnPack extension in VSCode for a better learning experience.
536
+ const EXTENSION_INSTALLATION_STEPS = `
537
+ # Steps to Install LearnPack VSCode Extension
538
+
539
+ 1. **Open VSCode**:
540
+ - Launch the Visual Studio Code application on your computer.
541
+
542
+ 2. **Go to Extensions View**:
543
+ - Click on the Extensions icon in the Activity Bar on the side of the window.
544
+ - Alternatively, you can open the Extensions view by pressing \`Ctrl+Shift+X\`.
545
+
546
+ 3. **Search for LearnPack**:
547
+ - In the Extensions view, type "LearnPack" into the search bar.
548
+
549
+ 4. **Install the Extension**:
550
+ - Find the "LearnPack" extension in the search results and click the "Install" button.
551
+ - If the extension is already installed but disabled, click the "Enable" button.
552
+
553
+ 5. **Verify Installation**:
554
+ - Once installed, you can verify the installation by running the following command in the terminal:
555
+ \`\`\`sh
556
+ code --list-extensions | grep learn-pack.learnpack-vscode
557
+ \`\`\`
558
+ - If the extension is listed, it means the installation was successful.
559
+
560
+ We strongly recommend using the LearnPack extension in VSCode for a better learning experience.
536
561
  `;
537
562
  /**
538
563
  * Installs the LearnPack VSCode extension if the 'code' command is available.
@@ -92,7 +92,7 @@ const download = (url, dest) => {
92
92
  });
93
93
  file.on("error", err => {
94
94
  file.close();
95
- if (err.code === "EEXIST") {
95
+ if (err.name === "EEXIST") {
96
96
  console_1.default.debug("File already exists");
97
97
  resolve("File already exists");
98
98
  }
@@ -11,6 +11,9 @@ const fileQueue_1 = require("../../utils/fileQueue");
11
11
  const exercise_1 = require("../config/exercise");
12
12
  const session_1 = require("../../managers/session");
13
13
  const telemetry_1 = require("../telemetry");
14
+ const creatorUtilities_1 = require("../../utils/creatorUtilities");
15
+ const rigoActions_1 = require("../../utils/rigoActions");
16
+ // import { eventManager } from "../../utils/osOperations"
14
17
  const withHandler = (func) => (req, res) => {
15
18
  try {
16
19
  func(req, res);
@@ -265,6 +268,71 @@ async function default_1(app, configObject, configManager) {
265
268
  res.end();
266
269
  }
267
270
  }));
271
+ app.delete("/exercise/:slug/delete", withHandler(async (req, res) => {
272
+ const exerciseDeleted = configManager.deleteExercise(req.params.slug);
273
+ if (exerciseDeleted) {
274
+ configManager.buildIndex();
275
+ res.json({ status: "ok" });
276
+ }
277
+ else {
278
+ res.status(500).json({ error: "Failed to delete exercise" });
279
+ }
280
+ }));
281
+ app.post("/actions/translate", jsonBodyParser, withHandler(async (req, res) => {
282
+ var _a;
283
+ const { exerciseSlugs, languages } = req.body;
284
+ const session = await session_1.default.getPayload();
285
+ const rigoToken = (_a = session === null || session === void 0 ? void 0 : session.rigobot) === null || _a === void 0 ? void 0 : _a.key;
286
+ if (!rigoToken) {
287
+ return res.status(400).json({ error: "RigoToken not found" });
288
+ }
289
+ const languagesToTranslate = languages.split(",");
290
+ try {
291
+ await Promise.all(exerciseSlugs.map(async (slug) => {
292
+ const exercise = configManager.getExercise(slug);
293
+ if (!exercise) {
294
+ throw new Error(`Exercise ${slug} not found`);
295
+ }
296
+ if (exercise.getReadme) {
297
+ const readme = exercise.getReadme(null);
298
+ await Promise.all(languagesToTranslate.map(async (language) => {
299
+ const response = await (0, rigoActions_1.translateExercise)(rigoToken, {
300
+ text_to_translate: readme.body,
301
+ output_language: language,
302
+ });
303
+ await (0, creatorUtilities_1.saveTranslatedReadme)(slug, response.parsed.output_language_code, response.parsed.translation);
304
+ console_1.default.success(`Translated ${slug} to ${language} successfully`);
305
+ }));
306
+ }
307
+ }));
308
+ configManager.buildIndex();
309
+ return res.status(200).json({ message: "Translated exercises" });
310
+ }
311
+ catch (error) {
312
+ console.log(error, "ERROR");
313
+ return res.status(400).json({ error: error.message });
314
+ }
315
+ }));
316
+ app.post("/exercise/:slug/create", jsonBodyParser, withHandler(async (req, res) => {
317
+ const { title, readme, language } = req.body;
318
+ const { slug } = req.params;
319
+ if (!title || !readme || !language) {
320
+ return res.status(400).json({ error: "Missing required fields" });
321
+ }
322
+ try {
323
+ const exerciseCreated = await configManager.createExercise(slug, readme, language);
324
+ if (exerciseCreated) {
325
+ configManager.buildIndex();
326
+ res.json({ status: "ok" });
327
+ }
328
+ else {
329
+ res.status(500).json({ error: "Failed to create exercise" });
330
+ }
331
+ }
332
+ catch (_a) {
333
+ res.status(500).json({ error: "Failed to create exercise" });
334
+ }
335
+ }));
268
336
  const textBodyParser = bodyParser.text();
269
337
  app.put("/exercise/:slug/file/:fileName", textBodyParser, withHandler((req, res) => {
270
338
  const exercise = configManager.getExercise(req.params.slug);
@@ -134,6 +134,9 @@ const Session = {
134
134
  }
135
135
  },
136
136
  destroy: async function () {
137
+ if (!this.sessionStarted) {
138
+ await this.initialize();
139
+ }
137
140
  await storage.clear();
138
141
  this.token = null;
139
142
  console_1.default.success("You have logged out");
@@ -13,6 +13,8 @@ export interface IConfigManager {
13
13
  getExercise: (slug: string | undefined) => IExercise;
14
14
  startExercise: (slug: string) => IExercise;
15
15
  reset: (slug: string) => void;
16
+ createExercise: (slug: string, content: string, language: string) => boolean;
17
+ deleteExercise: (slug: string) => boolean;
16
18
  buildIndex: () => boolean | void;
17
19
  watchIndex: (onChange: (...args: Array<any>) => void) => void;
18
20
  save: () => void;
@@ -46,4 +46,6 @@ export declare const makePackageInfo: (choices: any) => {
46
46
  export declare function estimateDuration(listOfSteps: string[]): number;
47
47
  export declare function createFileOnDesktop(): Promise<void>;
48
48
  export declare function getContentIndex(): string;
49
+ export declare function extractTextFromMarkdown(mdContent: string): string;
50
+ export declare const saveTranslatedReadme: (exercise: string, languageCode: string, readme: string) => Promise<void>;
49
51
  export {};