@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.
- package/README.md +12 -12
- package/lib/commands/breakToken.js +11 -3
- package/lib/commands/init.js +69 -38
- package/lib/commands/publish.js +1 -1
- package/lib/commands/start.js +9 -12
- package/lib/managers/config/index.js +77 -77
- package/lib/managers/server/routes.js +1 -5
- package/lib/utils/creatorUtilities.d.ts +7 -2
- package/lib/utils/creatorUtilities.js +88 -6
- package/lib/utils/rigoActions.d.ts +6 -0
- package/lib/utils/rigoActions.js +16 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/commands/breakToken.ts +13 -2
- package/src/commands/init.ts +103 -46
- package/src/commands/publish.ts +1 -1
- package/src/commands/start.ts +10 -14
- package/src/managers/config/index.ts +715 -715
- package/src/managers/server/routes.ts +1 -3
- package/src/utils/creatorUtilities.ts +241 -147
- package/src/utils/rigoActions.ts +30 -0
@@ -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 =
|
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
|
-
|
42
|
-
|
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 >
|
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:
|
97
|
-
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 {};
|
package/lib/utils/rigoActions.js
CHANGED
@@ -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
|
+
}
|
package/oclif.manifest.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":"5.0.
|
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.
|
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
|
-
|
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
|
|
package/src/commands/init.ts
CHANGED
@@ -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
|
-
|
143
|
-
|
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 } =
|
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
|
-
|
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
|
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.
|
190
|
-
|
191
|
-
|
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(
|
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
|
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:
|
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
|
-
|
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 {
|
package/src/commands/publish.ts
CHANGED
@@ -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
|
|
package/src/commands/start.ts
CHANGED
@@ -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
|
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
|
}
|