@learnpack/learnpack 5.0.21 → 5.0.23

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.
@@ -1 +1 @@
1
- {"version":"5.0.21","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":{"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.23","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":{"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.21",
4
+ "version": "5.0.23",
5
5
  "author": "Alejandro Sanchez @alesanchezr",
6
6
  "contributors": [
7
7
  {
@@ -13,13 +13,15 @@ import { ValidationError } from "../utils/errors"
13
13
  import * as path from "path"
14
14
  import {
15
15
  hasCreatorPermission,
16
- createReadme,
17
- getExercisesNames,
18
16
  generateImage,
19
17
  downloadImage,
20
18
  generateCourseIntroduction,
19
+ interactiveCreation,
20
+ createCodeFile,
21
+ readmeCreator,
21
22
  } from "../utils/rigoActions"
22
23
  import { getConsumables } from "../utils/api"
24
+
23
25
  const slugify = (text: string) => {
24
26
  return text
25
27
  .toString()
@@ -31,8 +33,26 @@ const slugify = (text: string) => {
31
33
  .replace(/[^\w-]+/g, "")
32
34
  }
33
35
 
34
- const getExNumber = (index: number) => {
35
- return index < 10 ? `0${index}` : `${index}`
36
+ const getExInfo = (title: string) => {
37
+ // Example title: '1.0 - Introduction to AI [READ: Small introduction to important concepts such as AI, machine learning, and their applications]'
38
+ let [exNumber, exTitle] = title.split(" - ")
39
+
40
+ // Extract kind and description
41
+ const kindMatch = exTitle.match(/\[(.*?):(.*?)]/)
42
+ const kind = kindMatch ? kindMatch[1].trim().toLowerCase() : "read"
43
+ const description = kindMatch ? kindMatch[2].trim() : ""
44
+
45
+ exNumber = exNumber.trim()
46
+ // Clean title
47
+ exTitle = exTitle.replace(kindMatch?.[0] || "", "").trim()
48
+ exTitle = slugify(exTitle)
49
+
50
+ return {
51
+ exNumber,
52
+ kind,
53
+ description,
54
+ exTitle,
55
+ }
36
56
  }
37
57
 
38
58
  function extractImagesFromMarkdown(markdown: string) {
@@ -99,6 +119,47 @@ type PackageInfo = {
99
119
  }
100
120
  }
101
121
 
122
+ const initializeInteractiveCreation = async (
123
+ rigoToken: string,
124
+ courseInfo: string
125
+ ): Promise<{
126
+ currentSteps: string[]
127
+ prevInteractions: string
128
+ }> => {
129
+ let prevInteractions = ""
130
+ let isReady = false
131
+ let currentSteps = []
132
+ while (!isReady) {
133
+ // eslint-disable-next-line
134
+ const res = await interactiveCreation(rigoToken, {
135
+ courseInfo: courseInfo,
136
+ prevInteractions: prevInteractions,
137
+ })
138
+ currentSteps = res.parsed.listOfSteps
139
+ isReady = res.parsed.ready
140
+
141
+ if (!isReady) {
142
+ console.log(currentSteps)
143
+ Console.info(`AI: ${res.parsed.aiMessage}`)
144
+ prevInteractions += `\nAI: ${res.parsed.aiMessage}`
145
+ // eslint-disable-next-line
146
+ const userMessage = await prompts([
147
+ {
148
+ type: "text",
149
+ name: "userMessage",
150
+ message: "Your message: ",
151
+ },
152
+ ])
153
+ prevInteractions += `\nUser: ${userMessage.userMessage}`
154
+ }
155
+ }
156
+
157
+ return {
158
+ currentSteps,
159
+ prevInteractions,
160
+ }
161
+ }
162
+
102
163
  const handleAILogic = async (tutorialDir: string, packageInfo: PackageInfo) => {
103
164
  Console.info(
104
165
  "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"
@@ -158,26 +219,6 @@ const handleAILogic = async (tutorialDir: string, packageInfo: PackageInfo) => {
158
219
 
159
220
  Console.success("🎉 Let's begin this learning journey!")
160
221
 
161
- const aiChoices = await prompts([
162
- {
163
- type: "text",
164
- name: "tutorialAbout",
165
- message:
166
- "What kind of tutorial do you want to create? Please expand a little on the content, the outcome and the goal of the tutorial",
167
- initial: "",
168
- },
169
- {
170
- type: "text",
171
- name: "exercisesNumber",
172
- message:
173
- "How many steps or exercises do you want? Please provide a number",
174
- validate: (value: string) => {
175
- const n = Math.floor(Number(value))
176
- return n !== Number.POSITIVE_INFINITY && String(n) === value && n > 0
177
- },
178
- },
179
- ])
180
-
181
222
  const packageContext = `
182
223
  \n
183
224
  The following information comes from user inputs
@@ -190,36 +231,33 @@ const handleAILogic = async (tutorialDir: string, packageInfo: PackageInfo) => {
190
231
  Use it to generate more relevant exercises
191
232
  `
192
233
 
193
- const inputs = {
194
- tutorial_about: aiChoices.tutorialAbout + packageContext,
195
- number_of_exercises: aiChoices.exercisesNumber,
196
- }
197
- Console.info("Creating lessons...")
198
- const res = await getExercisesNames(rigoToken, inputs)
234
+ const { currentSteps } = await initializeInteractiveCreation(
235
+ rigoToken,
236
+ packageContext
237
+ )
199
238
 
200
239
  const exercisesDir = path.join(tutorialDir, "exercises")
201
240
  fs.ensureDirSync(exercisesDir)
202
241
 
203
- for (const [index, exercise] of res.parsed.exercises.entries()) {
204
- const exerciseDir = path.join(
205
- exercisesDir,
206
- `${getExNumber(index)}-${slugify(exercise)}`
207
- )
242
+ Console.info("Creating lessons...")
243
+ for (const [index, exercise] of currentSteps.entries()) {
244
+ const { exNumber, exTitle } = getExInfo(exercise)
245
+ const exerciseDir = path.join(exercisesDir, `${exNumber}-${exTitle}`)
208
246
  fs.ensureDirSync(exerciseDir)
209
247
  }
210
248
 
211
- const exercisePromises = res.parsed.exercises.map(
249
+ const exercisePromises = currentSteps.map(
212
250
  async (exercise: any, index: number) => {
213
- const exerciseDir = path.join(
214
- exercisesDir,
215
- `${getExNumber(index)}-${slugify(exercise)}`
216
- )
251
+ const { exNumber, exTitle, kind, description } = getExInfo(exercise)
252
+ const exerciseDir = path.join(exercisesDir, `${exNumber}-${exTitle}`)
217
253
 
218
- const readme = await createReadme(rigoToken, {
219
- title: `\`${getExNumber(index)}\` ${exercise}`,
254
+ const readme = await readmeCreator(rigoToken, {
255
+ title: `${exNumber} - ${exTitle}`,
220
256
  output_lang: "en",
221
- list_of_exercises: res.parsed.exercises.join(","),
222
- tutorial_description: aiChoices.tutorialAbout,
257
+ list_of_exercises: currentSteps.join(","),
258
+ tutorial_description: packageContext,
259
+ lesson_description: description,
260
+ kind: kind.toLowerCase(),
223
261
  })
224
262
 
225
263
  const readmeFilename = "README.md"
@@ -228,6 +266,21 @@ const handleAILogic = async (tutorialDir: string, packageInfo: PackageInfo) => {
228
266
  path.join(exerciseDir, readmeFilename),
229
267
  readme.parsed.content
230
268
  )
269
+
270
+ if (kind.toLowerCase() === "code") {
271
+ const codeFile = await createCodeFile(rigoToken, {
272
+ readme: readme.parsed.content,
273
+ })
274
+
275
+ fs.writeFileSync(
276
+ path.join(
277
+ exerciseDir,
278
+ `app.${codeFile.parsed.extension.replace(".", "")}`
279
+ ),
280
+ codeFile.parsed.content
281
+ )
282
+ }
283
+
231
284
  return readme.parsed.content
232
285
  }
233
286
  )
@@ -1,4 +1,3 @@
1
- import { getExercisesNames } from "../utils/rigoActions"
2
1
  import SessionCommand from "../utils/SessionCommand"
3
2
  import * as fs from "fs"
4
3
  import * as path from "path"