@learnpack/learnpack 5.0.6 → 5.0.7

Sign up to get free protection for your applications and to get access to all the features.
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.6 win32-x64 node-v20.16.0
24
+ @learnpack/learnpack/5.0.7 win32-x64 node-v20.16.0
25
25
  $ learnpack --help [COMMAND]
26
26
  USAGE
27
27
  $ learnpack COMMAND
@@ -75,7 +75,7 @@ DESCRIPTION
75
75
  12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
76
76
  ```
77
77
 
78
- _See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.6/src\commands\audit.ts)_
78
+ _See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.7/src\commands\audit.ts)_
79
79
 
80
80
  ## `learnpack clean`
81
81
 
@@ -90,7 +90,7 @@ DESCRIPTION
90
90
  Extra documentation goes here
91
91
  ```
92
92
 
93
- _See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.6/src\commands\clean.ts)_
93
+ _See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.7/src\commands\clean.ts)_
94
94
 
95
95
  ## `learnpack download [PACKAGE]`
96
96
 
@@ -108,7 +108,7 @@ DESCRIPTION
108
108
  Extra documentation goes here
109
109
  ```
110
110
 
111
- _See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.6/src\commands\download.ts)_
111
+ _See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.7/src\commands\download.ts)_
112
112
 
113
113
  ## `learnpack help [COMMAND]`
114
114
 
@@ -139,7 +139,7 @@ OPTIONS
139
139
  -h, --grading show CLI help
140
140
  ```
141
141
 
142
- _See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.6/src\commands\init.ts)_
142
+ _See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.7/src\commands\init.ts)_
143
143
 
144
144
  ## `learnpack login [PACKAGE]`
145
145
 
@@ -157,7 +157,7 @@ DESCRIPTION
157
157
  Extra documentation goes here
158
158
  ```
159
159
 
160
- _See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.6/src\commands\login.ts)_
160
+ _See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.7/src\commands\login.ts)_
161
161
 
162
162
  ## `learnpack logout [PACKAGE]`
163
163
 
@@ -175,7 +175,7 @@ DESCRIPTION
175
175
  Extra documentation goes here
176
176
  ```
177
177
 
178
- _See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.6/src\commands\logout.ts)_
178
+ _See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.7/src\commands\logout.ts)_
179
179
 
180
180
  ## `learnpack plugins`
181
181
 
@@ -306,7 +306,7 @@ OPTIONS
306
306
  -h, --help show CLI help
307
307
  ```
308
308
 
309
- _See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.6/src\commands\publish.ts)_
309
+ _See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.7/src\commands\publish.ts)_
310
310
 
311
311
  ## `learnpack start`
312
312
 
@@ -327,7 +327,7 @@ OPTIONS
327
327
  -w, --watch Watch for file changes
328
328
  ```
329
329
 
330
- _See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.6/src\commands\start.ts)_
330
+ _See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.7/src\commands\start.ts)_
331
331
 
332
332
  ## `learnpack test [EXERCISESLUG]`
333
333
 
@@ -341,7 +341,7 @@ ARGUMENTS
341
341
  EXERCISESLUG The name of the exercise to test
342
342
  ```
343
343
 
344
- _See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.6/src\commands\test.ts)_
344
+ _See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.7/src\commands\test.ts)_
345
345
 
346
346
  ## `learnpack translate`
347
347
 
@@ -352,7 +352,7 @@ USAGE
352
352
  $ learnpack translate
353
353
  ```
354
354
 
355
- _See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.6/src\commands\translate.ts)_
355
+ _See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.7/src\commands\translate.ts)_
356
356
  <!-- commandsstop -->
357
357
 
358
358
  > > > > > > > 0cb3e56d84c197f9d008836bb573eade212b7e57
@@ -6,7 +6,6 @@ const BaseCommand_1 = require("../utils/BaseCommand");
6
6
  const fs = require("fs-extra");
7
7
  const prompts = require("prompts");
8
8
  const cli_ux_1 = require("cli-ux");
9
- const eta = require("eta");
10
9
  const api_1 = require("../utils/api");
11
10
  const console_1 = require("../utils/console");
12
11
  const errors_1 = require("../utils/errors");
@@ -39,6 +38,14 @@ function extractImagesFromMarkdown(markdown) {
39
38
  function getFilenameFromUrl(url) {
40
39
  return path.basename(url);
41
40
  }
41
+ async function createPreviewReadme(tutorialDir, packageInfo, rigoToken, readmeContents) {
42
+ const readmeFilename = `README.md`;
43
+ const readmeContent = await (0, rigoActions_1.generateCourseIntroduction)(rigoToken, {
44
+ course_title: packageInfo.title.us,
45
+ lessons_context: readmeContents.join("\n"),
46
+ });
47
+ fs.writeFileSync(path.join(tutorialDir, readmeFilename), readmeContent.answer);
48
+ }
42
49
  const handleAILogic = async (tutorialDir, packageInfo) => {
43
50
  console_1.default.info("Almost there! First you need to login to use the AI creator");
44
51
  fs.removeSync(path.join(tutorialDir, "exercises", "01-hello-world"));
@@ -150,6 +157,8 @@ const handleAILogic = async (tutorialDir, packageInfo) => {
150
157
  });
151
158
  await Promise.all(imagePromises);
152
159
  console_1.default.info("Images generated successfully! 🎉 Your tutorial will be ready soon!");
160
+ console_1.default.info("Creating preview readme...");
161
+ await createPreviewReadme(tutorialDir, packageInfo, rigoToken, readmeContents);
153
162
  return true;
154
163
  };
155
164
  class InitComand extends BaseCommand_1.default {
@@ -250,9 +259,25 @@ class InitComand extends BaseCommand_1.default {
250
259
  // Creating README files
251
260
  for (const language of languages) {
252
261
  const readmeFilename = `README${language !== "en" ? `.${language}` : ""}`;
253
- const readmeTemplatePath = path.resolve(templatesDir, `${readmeFilename}.ejs`);
254
- const readmeContent = eta.render(fs.readFileSync(readmeTemplatePath, "utf-8"), packageInfo);
255
- fs.writeFileSync(path.join(tutorialDir, `${readmeFilename}.md`), readmeContent);
262
+ // const readmeTemplatePath = path.resolve(
263
+ // templatesDir,
264
+ // `${readmeFilename}.ejs`
265
+ // )
266
+ // const readmeObject = {
267
+ // title: packageInfo.title.us,
268
+ // description: packageInfo.description.us,
269
+ // grading: packageInfo.grading,
270
+ // difficulty: packageInfo.difficulty,
271
+ // duration: packageInfo.duration,
272
+ // }
273
+ // const readmeContent = eta.render(
274
+ // fs.readFileSync(readmeTemplatePath, "utf-8"),
275
+ // readmeObject
276
+ // )
277
+ // fs.writeFileSync(
278
+ // path.join(tutorialDir, `${readmeFilename}.md`),
279
+ // readmeContent
280
+ // )
256
281
  if (fs.existsSync(path.join(tutorialDir, `${readmeFilename}.ejs`)))
257
282
  fs.removeSync(path.join(tutorialDir, `${readmeFilename}.ejs`));
258
283
  }
@@ -17,4 +17,9 @@ type TTranslateInputs = {
17
17
  output_language: string;
18
18
  };
19
19
  export declare const translateExercise: (token: string, inputs: TTranslateInputs) => Promise<any>;
20
+ type TGenerateCourseIntroductionInputs = {
21
+ course_title: string;
22
+ lessons_context: string;
23
+ };
24
+ export declare const generateCourseIntroduction: (token: string, inputs: TGenerateCourseIntroductionInputs) => Promise<any>;
20
25
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.translateExercise = exports.generateImage = exports.hasCreatorPermission = exports.createReadme = exports.getExercisesNames = void 0;
3
+ exports.generateCourseIntroduction = exports.translateExercise = exports.generateImage = exports.hasCreatorPermission = exports.createReadme = exports.getExercisesNames = void 0;
4
4
  exports.downloadImage = downloadImage;
5
5
  const axios_1 = require("axios");
6
6
  const fs_1 = require("fs");
@@ -96,3 +96,17 @@ const translateExercise = async (token, inputs) => {
96
96
  return response.data;
97
97
  };
98
98
  exports.translateExercise = translateExercise;
99
+ const generateCourseIntroduction = async (token, inputs) => {
100
+ const response = await axios_1.default.post(`${RIGOBOT_HOST}/v1/prompting/completion/192/`, {
101
+ inputs: inputs,
102
+ include_purpose_objective: false,
103
+ execute_async: false,
104
+ }, {
105
+ headers: {
106
+ "Content-Type": "application/json",
107
+ Authorization: "Token " + token,
108
+ },
109
+ });
110
+ return response.data;
111
+ };
112
+ exports.generateCourseIntroduction = generateCourseIntroduction;
@@ -1 +1 @@
1
- {"version":"5.0.6","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":[]},"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":{"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":{"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":{},"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":{},"args":[]}}}
1
+ {"version":"5.0.7","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":[]},"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":{"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":{"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":{},"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":{},"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.6",
4
+ "version": "5.0.7",
5
5
  "author": "Alejandro Sanchez @alesanchezr",
6
6
  "contributors": [
7
7
  {
@@ -17,6 +17,7 @@ import {
17
17
  getExercisesNames,
18
18
  generateImage,
19
19
  downloadImage,
20
+ generateCourseIntroduction,
20
21
  } from "../utils/rigoActions"
21
22
 
22
23
  const slugify = (text: string) => {
@@ -52,6 +53,21 @@ function getFilenameFromUrl(url: string) {
52
53
  return path.basename(url)
53
54
  }
54
55
 
56
+ async function createPreviewReadme(
57
+ tutorialDir: string,
58
+ packageInfo: PackageInfo,
59
+ rigoToken: string,
60
+ readmeContents: string[]
61
+ ) {
62
+ const readmeFilename = `README.md`
63
+
64
+ const readmeContent = await generateCourseIntroduction(rigoToken, {
65
+ course_title: packageInfo.title.us,
66
+ lessons_context: readmeContents.join("\n"),
67
+ })
68
+ fs.writeFileSync(path.join(tutorialDir, readmeFilename), readmeContent.answer)
69
+ }
70
+
55
71
  type PackageInfo = {
56
72
  grading: string
57
73
  difficulty: string
@@ -213,6 +229,10 @@ const handleAILogic = async (tutorialDir: string, packageInfo: PackageInfo) => {
213
229
  "Images generated successfully! 🎉 Your tutorial will be ready soon!"
214
230
  )
215
231
 
232
+ Console.info("Creating preview readme...")
233
+
234
+ await createPreviewReadme(tutorialDir, packageInfo, rigoToken, readmeContents)
235
+
216
236
  return true
217
237
  }
218
238
 
@@ -334,18 +354,26 @@ class InitComand extends BaseCommand {
334
354
  // Creating README files
335
355
  for (const language of languages) {
336
356
  const readmeFilename = `README${language !== "en" ? `.${language}` : ""}`
337
- const readmeTemplatePath = path.resolve(
338
- templatesDir,
339
- `${readmeFilename}.ejs`
340
- )
341
- const readmeContent = eta.render(
342
- fs.readFileSync(readmeTemplatePath, "utf-8"),
343
- packageInfo
344
- )
345
- fs.writeFileSync(
346
- path.join(tutorialDir, `${readmeFilename}.md`),
347
- readmeContent
348
- )
357
+ // const readmeTemplatePath = path.resolve(
358
+ // templatesDir,
359
+ // `${readmeFilename}.ejs`
360
+ // )
361
+
362
+ // const readmeObject = {
363
+ // title: packageInfo.title.us,
364
+ // description: packageInfo.description.us,
365
+ // grading: packageInfo.grading,
366
+ // difficulty: packageInfo.difficulty,
367
+ // duration: packageInfo.duration,
368
+ // }
369
+ // const readmeContent = eta.render(
370
+ // fs.readFileSync(readmeTemplatePath, "utf-8"),
371
+ // readmeObject
372
+ // )
373
+ // fs.writeFileSync(
374
+ // path.join(tutorialDir, `${readmeFilename}.md`),
375
+ // readmeContent
376
+ // )
349
377
  if (fs.existsSync(path.join(tutorialDir, `${readmeFilename}.ejs`)))
350
378
  fs.removeSync(path.join(tutorialDir, `${readmeFilename}.ejs`))
351
379
  }
@@ -1,249 +1,249 @@
1
- /* eslint-disable arrow-parens */
2
- /* eslint-disable unicorn/no-array-for-each */
3
- import { flags } from "@oclif/command"
4
- import SessionCommand from "../utils/SessionCommand"
5
- import SessionManager from "../managers/session"
6
- import * as fs from "fs"
7
- import * as path from "path"
8
- import * as archiver from "archiver"
9
- import axios from "axios"
10
- import FormData = require("form-data")
11
- import Console from "../utils/console"
12
- import {
13
- decompress,
14
- downloadEditor,
15
- checkIfDirectoryExists,
16
- } from "../managers/file"
17
-
18
- const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
19
- // const RIGOBOT_HOST =
20
- // "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
21
- const uploadZipEndpont = RIGOBOT_HOST + "/v1/learnpack/upload"
22
-
23
- export default class BuildCommand extends SessionCommand {
24
- static description =
25
- "Builds the project by copying necessary files and directories into a zip file"
26
-
27
- static flags = {
28
- help: flags.help({ char: "h" }),
29
- }
30
-
31
- async init() {
32
- const { flags } = this.parse(BuildCommand)
33
- await this.initSession(flags)
34
- }
35
-
36
- async run() {
37
- const buildDir = path.join(process.cwd(), "build")
38
- // this.configManager?.clean()
39
-
40
- const configObject = this.configManager?.get()
41
- // Console.success("Package cleaned successfully, ready to publish")
42
-
43
- if (configObject) {
44
- // build exerises
45
- Console.debug("Building exercises")
46
- this.configManager?.buildIndex()
47
- }
48
-
49
- let sessionPayload = await SessionManager.getPayload()
50
- if (!sessionPayload || !sessionPayload.rigobot) {
51
- Console.error("You must be logged in to upload a LearnPack package")
52
- try {
53
- sessionPayload = await SessionManager.login()
54
- } catch (error) {
55
- Console.error("Error trying to authenticate")
56
- Console.error((error as TypeError).message || (error as string))
57
- }
58
- }
59
-
60
- const rigoToken = sessionPayload.rigobot.key
61
- // const rigoToken = "417d612d226a1606ad3a4e94b1881a9f0124b667"
62
-
63
- // Read learn.json to get the slug
64
- const learnJsonPath = path.join(process.cwd(), "learn.json")
65
- if (!fs.existsSync(learnJsonPath)) {
66
- this.error("learn.json not found")
67
- }
68
-
69
- const learnJson = JSON.parse(fs.readFileSync(learnJsonPath, "utf-8"))
70
-
71
- const zipFilePath = path.join(process.cwd(), `${learnJson.slug}.zip`)
72
-
73
- // Ensure build directory exists
74
- if (!fs.existsSync(buildDir)) {
75
- fs.mkdirSync(buildDir)
76
- }
77
-
78
- if (configObject) {
79
- const { config } = configObject
80
- const appAlreadyExists = checkIfDirectoryExists(`${config?.dirPath}/_app`)
81
-
82
- if (!appAlreadyExists) {
83
- // download app and decompress
84
- await downloadEditor(
85
- config?.editor.version,
86
- `${config?.dirPath}/app.tar.gz`
87
- )
88
-
89
- Console.info("Decompressing LearnPack UI, this may take a minute...")
90
- await decompress(
91
- `${config?.dirPath}/app.tar.gz`,
92
- `${config?.dirPath}/_app/`
93
- )
94
- }
95
- }
96
-
97
- // Copy config.json
98
- const configPath = path.join(process.cwd(), ".learn", "config.json")
99
- if (fs.existsSync(configPath)) {
100
- fs.copyFileSync(configPath, path.join(buildDir, "config.json"))
101
- } else {
102
- this.error("config.json not found")
103
- }
104
-
105
- // Copy .learn/assets directory, if it exists else create it
106
- const assetsDir = path.join(process.cwd(), ".learn", "assets")
107
- if (fs.existsSync(assetsDir)) {
108
- this.copyDirectory(assetsDir, path.join(buildDir, ".learn", "assets"))
109
- } else {
110
- fs.mkdirSync(path.join(buildDir, ".learn", "assets"), { recursive: true })
111
- }
112
-
113
- // Copy .learn/_app directory files to the same level as config.json
114
- const appDir = path.join(process.cwd(), ".learn", "_app")
115
- if (fs.existsSync(appDir)) {
116
- this.copyDirectory(appDir, buildDir)
117
- } else {
118
- this.error(".learn/_app directory not found")
119
- }
120
-
121
- // After copying the _app directory
122
- const indexHtmlPath = path.join(appDir, "index.html")
123
- const buildIndexHtmlPath = path.join(buildDir, "index.html")
124
-
125
- if (fs.existsSync(indexHtmlPath)) {
126
- let indexHtmlContent = fs.readFileSync(indexHtmlPath, "utf-8")
127
-
128
- const description = learnJson.description.us || "LearnPack is awesome!"
129
- const title =
130
- learnJson.title.us || "LearnPack: Interactive Learning as a Service"
131
-
132
- const previewUrl =
133
- learnJson.preview ||
134
- "https://raw.githubusercontent.com/learnpack/ide/refs/heads/master/public/learnpack.svg"
135
- // Replace placeholders and the <title>Old title </title> tag for a new tag with the title
136
- indexHtmlContent = indexHtmlContent
137
- .replace(/{{description}}/g, description)
138
- .replace(/<title>.*<\/title>/, `<title>${title}</title>`)
139
- .replace(/{{title}}/g, title)
140
- .replace(/{{preview}}/g, previewUrl)
141
-
142
- // Write the modified content to the build directory
143
- fs.writeFileSync(buildIndexHtmlPath, indexHtmlContent)
144
- } else {
145
- this.error("index.html not found in _app directory")
146
- }
147
-
148
- // Copy exercises directory
149
- const exercisesDir = path.join(process.cwd(), "exercises")
150
- const learnExercisesDir = path.join(process.cwd(), ".learn", "exercises")
151
-
152
- if (fs.existsSync(exercisesDir)) {
153
- this.copyDirectory(exercisesDir, path.join(buildDir, "exercises"))
154
- } else if (fs.existsSync(learnExercisesDir)) {
155
- this.copyDirectory(learnExercisesDir, path.join(buildDir, "exercises"))
156
- } else {
157
- this.error("exercises directory not found in either location")
158
- }
159
-
160
- // Copy learn.json
161
- fs.copyFileSync(learnJsonPath, path.join(buildDir, "learn.json"))
162
-
163
- // Create zip file
164
- const output = fs.createWriteStream(zipFilePath)
165
- const archive = archiver("zip", {
166
- zlib: { level: 9 },
167
- })
168
-
169
- output.on("close", async () => {
170
- this.log(
171
- `Build completed: ${zipFilePath} (${archive.pointer()} total bytes)`
172
- )
173
- // Remove build directory after zip is created
174
- // this.removeDirectory(buildDir)
175
- Console.debug("Zip file saved in project root")
176
-
177
- const formData = new FormData()
178
- formData.append("file", fs.createReadStream(zipFilePath))
179
- formData.append("config", JSON.stringify(learnJson))
180
-
181
- try {
182
- const res = await axios.post(uploadZipEndpont, formData, {
183
- headers: {
184
- ...formData.getHeaders(),
185
- Authorization: `Token ${rigoToken}`,
186
- },
187
- })
188
- console.log(res.data)
189
- // Remove the zip file after uploading
190
- fs.unlinkSync(zipFilePath)
191
- } catch (error) {
192
- if (axios.isAxiosError(error)) {
193
- if (error.response && error.response.status === 403) {
194
- console.error("Error 403:", error.response.data.error)
195
- } else if (error.response && error.response.status === 400) {
196
- console.error(error.response.data.error)
197
- } else {
198
- console.error("Error uploading file:", error)
199
- }
200
- } else {
201
- console.error("Error uploading file:", error)
202
- }
203
-
204
- fs.unlinkSync(zipFilePath)
205
- }
206
- })
207
-
208
- archive.on("error", (err: any) => {
209
- throw err
210
- })
211
-
212
- archive.pipe(output)
213
- archive.directory(buildDir, false)
214
- await archive.finalize()
215
- }
216
-
217
- copyDirectory(src: string, dest: string) {
218
- if (!fs.existsSync(dest)) {
219
- fs.mkdirSync(dest, { recursive: true })
220
- }
221
-
222
- const entries = fs.readdirSync(src, { withFileTypes: true })
223
-
224
- for (const entry of entries) {
225
- const srcPath = path.join(src, entry.name)
226
- const destPath = path.join(dest, entry.name)
227
-
228
- if (entry.isDirectory()) {
229
- this.copyDirectory(srcPath, destPath)
230
- } else {
231
- fs.copyFileSync(srcPath, destPath)
232
- }
233
- }
234
- }
235
-
236
- removeDirectory(dir: string) {
237
- if (fs.existsSync(dir)) {
238
- fs.readdirSync(dir).forEach((file) => {
239
- const currentPath = path.join(dir, file)
240
- if (fs.lstatSync(currentPath).isDirectory()) {
241
- this.removeDirectory(currentPath)
242
- } else {
243
- fs.unlinkSync(currentPath)
244
- }
245
- })
246
- fs.rmdirSync(dir)
247
- }
248
- }
249
- }
1
+ /* eslint-disable arrow-parens */
2
+ /* eslint-disable unicorn/no-array-for-each */
3
+ import { flags } from "@oclif/command"
4
+ import SessionCommand from "../utils/SessionCommand"
5
+ import SessionManager from "../managers/session"
6
+ import * as fs from "fs"
7
+ import * as path from "path"
8
+ import * as archiver from "archiver"
9
+ import axios from "axios"
10
+ import FormData = require("form-data")
11
+ import Console from "../utils/console"
12
+ import {
13
+ decompress,
14
+ downloadEditor,
15
+ checkIfDirectoryExists,
16
+ } from "../managers/file"
17
+
18
+ const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
19
+ // const RIGOBOT_HOST =
20
+ // "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
21
+ const uploadZipEndpont = RIGOBOT_HOST + "/v1/learnpack/upload"
22
+
23
+ export default class BuildCommand extends SessionCommand {
24
+ static description =
25
+ "Builds the project by copying necessary files and directories into a zip file"
26
+
27
+ static flags = {
28
+ help: flags.help({ char: "h" }),
29
+ }
30
+
31
+ async init() {
32
+ const { flags } = this.parse(BuildCommand)
33
+ await this.initSession(flags)
34
+ }
35
+
36
+ async run() {
37
+ const buildDir = path.join(process.cwd(), "build")
38
+ // this.configManager?.clean()
39
+
40
+ const configObject = this.configManager?.get()
41
+ // Console.success("Package cleaned successfully, ready to publish")
42
+
43
+ if (configObject) {
44
+ // build exerises
45
+ Console.debug("Building exercises")
46
+ this.configManager?.buildIndex()
47
+ }
48
+
49
+ let sessionPayload = await SessionManager.getPayload()
50
+ if (!sessionPayload || !sessionPayload.rigobot) {
51
+ Console.error("You must be logged in to upload a LearnPack package")
52
+ try {
53
+ sessionPayload = await SessionManager.login()
54
+ } catch (error) {
55
+ Console.error("Error trying to authenticate")
56
+ Console.error((error as TypeError).message || (error as string))
57
+ }
58
+ }
59
+
60
+ const rigoToken = sessionPayload.rigobot.key
61
+ // const rigoToken = "417d612d226a1606ad3a4e94b1881a9f0124b667"
62
+
63
+ // Read learn.json to get the slug
64
+ const learnJsonPath = path.join(process.cwd(), "learn.json")
65
+ if (!fs.existsSync(learnJsonPath)) {
66
+ this.error("learn.json not found")
67
+ }
68
+
69
+ const learnJson = JSON.parse(fs.readFileSync(learnJsonPath, "utf-8"))
70
+
71
+ const zipFilePath = path.join(process.cwd(), `${learnJson.slug}.zip`)
72
+
73
+ // Ensure build directory exists
74
+ if (!fs.existsSync(buildDir)) {
75
+ fs.mkdirSync(buildDir)
76
+ }
77
+
78
+ if (configObject) {
79
+ const { config } = configObject
80
+ const appAlreadyExists = checkIfDirectoryExists(`${config?.dirPath}/_app`)
81
+
82
+ if (!appAlreadyExists) {
83
+ // download app and decompress
84
+ await downloadEditor(
85
+ config?.editor.version,
86
+ `${config?.dirPath}/app.tar.gz`
87
+ )
88
+
89
+ Console.info("Decompressing LearnPack UI, this may take a minute...")
90
+ await decompress(
91
+ `${config?.dirPath}/app.tar.gz`,
92
+ `${config?.dirPath}/_app/`
93
+ )
94
+ }
95
+ }
96
+
97
+ // Copy config.json
98
+ const configPath = path.join(process.cwd(), ".learn", "config.json")
99
+ if (fs.existsSync(configPath)) {
100
+ fs.copyFileSync(configPath, path.join(buildDir, "config.json"))
101
+ } else {
102
+ this.error("config.json not found")
103
+ }
104
+
105
+ // Copy .learn/assets directory, if it exists else create it
106
+ const assetsDir = path.join(process.cwd(), ".learn", "assets")
107
+ if (fs.existsSync(assetsDir)) {
108
+ this.copyDirectory(assetsDir, path.join(buildDir, ".learn", "assets"))
109
+ } else {
110
+ fs.mkdirSync(path.join(buildDir, ".learn", "assets"), { recursive: true })
111
+ }
112
+
113
+ // Copy .learn/_app directory files to the same level as config.json
114
+ const appDir = path.join(process.cwd(), ".learn", "_app")
115
+ if (fs.existsSync(appDir)) {
116
+ this.copyDirectory(appDir, buildDir)
117
+ } else {
118
+ this.error(".learn/_app directory not found")
119
+ }
120
+
121
+ // After copying the _app directory
122
+ const indexHtmlPath = path.join(appDir, "index.html")
123
+ const buildIndexHtmlPath = path.join(buildDir, "index.html")
124
+
125
+ if (fs.existsSync(indexHtmlPath)) {
126
+ let indexHtmlContent = fs.readFileSync(indexHtmlPath, "utf-8")
127
+
128
+ const description = learnJson.description.us || "LearnPack is awesome!"
129
+ const title =
130
+ learnJson.title.us || "LearnPack: Interactive Learning as a Service"
131
+
132
+ const previewUrl =
133
+ learnJson.preview ||
134
+ "https://raw.githubusercontent.com/learnpack/ide/refs/heads/master/public/learnpack.svg"
135
+ // Replace placeholders and the <title>Old title </title> tag for a new tag with the title
136
+ indexHtmlContent = indexHtmlContent
137
+ .replace(/{{description}}/g, description)
138
+ .replace(/<title>.*<\/title>/, `<title>${title}</title>`)
139
+ .replace(/{{title}}/g, title)
140
+ .replace(/{{preview}}/g, previewUrl)
141
+
142
+ // Write the modified content to the build directory
143
+ fs.writeFileSync(buildIndexHtmlPath, indexHtmlContent)
144
+ } else {
145
+ this.error("index.html not found in _app directory")
146
+ }
147
+
148
+ // Copy exercises directory
149
+ const exercisesDir = path.join(process.cwd(), "exercises")
150
+ const learnExercisesDir = path.join(process.cwd(), ".learn", "exercises")
151
+
152
+ if (fs.existsSync(exercisesDir)) {
153
+ this.copyDirectory(exercisesDir, path.join(buildDir, "exercises"))
154
+ } else if (fs.existsSync(learnExercisesDir)) {
155
+ this.copyDirectory(learnExercisesDir, path.join(buildDir, "exercises"))
156
+ } else {
157
+ this.error("exercises directory not found in either location")
158
+ }
159
+
160
+ // Copy learn.json
161
+ fs.copyFileSync(learnJsonPath, path.join(buildDir, "learn.json"))
162
+
163
+ // Create zip file
164
+ const output = fs.createWriteStream(zipFilePath)
165
+ const archive = archiver("zip", {
166
+ zlib: { level: 9 },
167
+ })
168
+
169
+ output.on("close", async () => {
170
+ this.log(
171
+ `Build completed: ${zipFilePath} (${archive.pointer()} total bytes)`
172
+ )
173
+ // Remove build directory after zip is created
174
+ // this.removeDirectory(buildDir)
175
+ Console.debug("Zip file saved in project root")
176
+
177
+ const formData = new FormData()
178
+ formData.append("file", fs.createReadStream(zipFilePath))
179
+ formData.append("config", JSON.stringify(learnJson))
180
+
181
+ try {
182
+ const res = await axios.post(uploadZipEndpont, formData, {
183
+ headers: {
184
+ ...formData.getHeaders(),
185
+ Authorization: `Token ${rigoToken}`,
186
+ },
187
+ })
188
+ console.log(res.data)
189
+ // Remove the zip file after uploading
190
+ fs.unlinkSync(zipFilePath)
191
+ } catch (error) {
192
+ if (axios.isAxiosError(error)) {
193
+ if (error.response && error.response.status === 403) {
194
+ console.error("Error 403:", error.response.data.error)
195
+ } else if (error.response && error.response.status === 400) {
196
+ console.error(error.response.data.error)
197
+ } else {
198
+ console.error("Error uploading file:", error)
199
+ }
200
+ } else {
201
+ console.error("Error uploading file:", error)
202
+ }
203
+
204
+ fs.unlinkSync(zipFilePath)
205
+ }
206
+ })
207
+
208
+ archive.on("error", (err: any) => {
209
+ throw err
210
+ })
211
+
212
+ archive.pipe(output)
213
+ archive.directory(buildDir, false)
214
+ await archive.finalize()
215
+ }
216
+
217
+ copyDirectory(src: string, dest: string) {
218
+ if (!fs.existsSync(dest)) {
219
+ fs.mkdirSync(dest, { recursive: true })
220
+ }
221
+
222
+ const entries = fs.readdirSync(src, { withFileTypes: true })
223
+
224
+ for (const entry of entries) {
225
+ const srcPath = path.join(src, entry.name)
226
+ const destPath = path.join(dest, entry.name)
227
+
228
+ if (entry.isDirectory()) {
229
+ this.copyDirectory(srcPath, destPath)
230
+ } else {
231
+ fs.copyFileSync(srcPath, destPath)
232
+ }
233
+ }
234
+ }
235
+
236
+ removeDirectory(dir: string) {
237
+ if (fs.existsSync(dir)) {
238
+ fs.readdirSync(dir).forEach((file) => {
239
+ const currentPath = path.join(dir, file)
240
+ if (fs.lstatSync(currentPath).isDirectory()) {
241
+ this.removeDirectory(currentPath)
242
+ } else {
243
+ fs.unlinkSync(currentPath)
244
+ }
245
+ })
246
+ fs.rmdirSync(dir)
247
+ }
248
+ }
249
+ }
@@ -145,3 +145,30 @@ export const translateExercise = async (
145
145
 
146
146
  return response.data
147
147
  }
148
+
149
+ type TGenerateCourseIntroductionInputs = {
150
+ course_title: string
151
+ lessons_context: string
152
+ }
153
+
154
+ export const generateCourseIntroduction = async (
155
+ token: string,
156
+ inputs: TGenerateCourseIntroductionInputs
157
+ ) => {
158
+ const response = await axios.post(
159
+ `${RIGOBOT_HOST}/v1/prompting/completion/192/`,
160
+ {
161
+ inputs: inputs,
162
+ include_purpose_objective: false,
163
+ execute_async: false,
164
+ },
165
+ {
166
+ headers: {
167
+ "Content-Type": "application/json",
168
+ Authorization: "Token " + token,
169
+ },
170
+ }
171
+ )
172
+
173
+ return response.data
174
+ }