@learnpack/learnpack 5.0.43 → 5.0.45
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/init.js +12 -61
- package/lib/utils/creatorUtilities.d.ts +3 -1
- package/lib/utils/creatorUtilities.js +75 -11
- package/oclif.manifest.json +1 -1
- package/package.json +2 -1
- package/src/commands/init.ts +13 -74
- package/src/utils/creatorUtilities.ts +85 -12
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.
|
24
|
+
@learnpack/learnpack/5.0.45 win32-x64 node-v22.14.0
|
25
25
|
$ learnpack --help [COMMAND]
|
26
26
|
USAGE
|
27
27
|
$ learnpack COMMAND
|
@@ -79,7 +79,7 @@ DESCRIPTION
|
|
79
79
|
12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
|
80
80
|
```
|
81
81
|
|
82
|
-
_See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
82
|
+
_See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.45/src\commands\audit.ts)_
|
83
83
|
|
84
84
|
## `learnpack breakToken`
|
85
85
|
|
@@ -94,7 +94,7 @@ OPTIONS
|
|
94
94
|
-y, --yes Skip all prompts and initialize an empty project
|
95
95
|
```
|
96
96
|
|
97
|
-
_See code: [src\commands\breakToken.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
97
|
+
_See code: [src\commands\breakToken.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.45/src\commands\breakToken.ts)_
|
98
98
|
|
99
99
|
## `learnpack clean`
|
100
100
|
|
@@ -109,7 +109,7 @@ DESCRIPTION
|
|
109
109
|
Extra documentation goes here
|
110
110
|
```
|
111
111
|
|
112
|
-
_See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
112
|
+
_See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.45/src\commands\clean.ts)_
|
113
113
|
|
114
114
|
## `learnpack download [PACKAGE]`
|
115
115
|
|
@@ -127,7 +127,7 @@ DESCRIPTION
|
|
127
127
|
Extra documentation goes here
|
128
128
|
```
|
129
129
|
|
130
|
-
_See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
130
|
+
_See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.45/src\commands\download.ts)_
|
131
131
|
|
132
132
|
## `learnpack help [COMMAND]`
|
133
133
|
|
@@ -159,7 +159,7 @@ OPTIONS
|
|
159
159
|
-y, --yes Skip all prompts and initialize an empty project
|
160
160
|
```
|
161
161
|
|
162
|
-
_See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
162
|
+
_See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.45/src\commands\init.ts)_
|
163
163
|
|
164
164
|
## `learnpack login [PACKAGE]`
|
165
165
|
|
@@ -177,7 +177,7 @@ DESCRIPTION
|
|
177
177
|
Extra documentation goes here
|
178
178
|
```
|
179
179
|
|
180
|
-
_See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
180
|
+
_See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.45/src\commands\login.ts)_
|
181
181
|
|
182
182
|
## `learnpack logout [PACKAGE]`
|
183
183
|
|
@@ -195,7 +195,7 @@ DESCRIPTION
|
|
195
195
|
Extra documentation goes here
|
196
196
|
```
|
197
197
|
|
198
|
-
_See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
198
|
+
_See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.45/src\commands\logout.ts)_
|
199
199
|
|
200
200
|
## `learnpack plugins`
|
201
201
|
|
@@ -327,7 +327,7 @@ OPTIONS
|
|
327
327
|
-s, --strict strict mode
|
328
328
|
```
|
329
329
|
|
330
|
-
_See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
330
|
+
_See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.45/src\commands\publish.ts)_
|
331
331
|
|
332
332
|
## `learnpack start`
|
333
333
|
|
@@ -349,7 +349,7 @@ OPTIONS
|
|
349
349
|
-y, --yes Skip all prompts and initialize an empty project
|
350
350
|
```
|
351
351
|
|
352
|
-
_See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
352
|
+
_See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.45/src\commands\start.ts)_
|
353
353
|
|
354
354
|
## `learnpack test [EXERCISESLUG]`
|
355
355
|
|
@@ -366,7 +366,7 @@ OPTIONS
|
|
366
366
|
-y, --yes Skip all prompts and initialize an empty project
|
367
367
|
```
|
368
368
|
|
369
|
-
_See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
369
|
+
_See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.45/src\commands\test.ts)_
|
370
370
|
|
371
371
|
## `learnpack translate`
|
372
372
|
|
@@ -380,7 +380,7 @@ OPTIONS
|
|
380
380
|
-y, --yes Skip all prompts and initialize an empty project
|
381
381
|
```
|
382
382
|
|
383
|
-
_See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
383
|
+
_See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.45/src\commands\translate.ts)_
|
384
384
|
<!-- commandsstop -->
|
385
385
|
|
386
386
|
> > > > > > > 0cb3e56d84c197f9d008836bb573eade212b7e57
|
package/lib/commands/init.js
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
const command_1 = require("@oclif/command");
|
4
4
|
const BaseCommand_1 = require("../utils/BaseCommand");
|
5
|
+
const ora_1 = require("ora");
|
5
6
|
// eslint-disable-next-line
|
6
7
|
const fs = require("fs-extra");
|
7
8
|
const prompts = require("prompts");
|
@@ -102,6 +103,7 @@ const initializeInteractiveCreation = async (rigoToken, courseInfo) => {
|
|
102
103
|
let currentDescription = "";
|
103
104
|
let currentDifficulty = "";
|
104
105
|
while (!isReady) {
|
106
|
+
const spinner = (0, ora_1.default)("Thinking...").start();
|
105
107
|
let wholeInfo = courseInfo;
|
106
108
|
wholeInfo += `
|
107
109
|
Current title: ${currentTitle}
|
@@ -112,6 +114,7 @@ const initializeInteractiveCreation = async (rigoToken, courseInfo) => {
|
|
112
114
|
courseInfo: wholeInfo,
|
113
115
|
prevInteractions: prevInteractions,
|
114
116
|
});
|
117
|
+
spinner.succeed("Done!");
|
115
118
|
currentSteps = res.parsed.listOfSteps;
|
116
119
|
isReady = res.parsed.ready;
|
117
120
|
if (res.parsed.title && currentTitle !== res.parsed.title) {
|
@@ -152,60 +155,6 @@ const initializeInteractiveCreation = async (rigoToken, courseInfo) => {
|
|
152
155
|
process.emitWarning = (warning) => {
|
153
156
|
console_1.default.debug("A Warning was emitted by Node.js: ", warning);
|
154
157
|
};
|
155
|
-
const appendContentIndex = async () => {
|
156
|
-
const choices = await prompts([
|
157
|
-
{
|
158
|
-
type: "confirm",
|
159
|
-
name: "contentIndex",
|
160
|
-
message: "Do you have a content index for this tutorial?",
|
161
|
-
},
|
162
|
-
]);
|
163
|
-
if (choices.contentIndex) {
|
164
|
-
await (0, creatorUtilities_1.createFileOnDesktop)("content_index.txt");
|
165
|
-
console_1.default.info("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.");
|
166
|
-
const isReady = await prompts([
|
167
|
-
{
|
168
|
-
type: "confirm",
|
169
|
-
name: "isReady",
|
170
|
-
message: "Are you ready to continue?",
|
171
|
-
},
|
172
|
-
]);
|
173
|
-
if (!isReady.isReady) {
|
174
|
-
console_1.default.error("Please make the necessary changes and try again.");
|
175
|
-
process.exit(1);
|
176
|
-
}
|
177
|
-
const contentIndex = (0, creatorUtilities_1.getDesktopFile)("content_index.txt");
|
178
|
-
return contentIndex;
|
179
|
-
}
|
180
|
-
return null;
|
181
|
-
};
|
182
|
-
const appendAIRules = async () => {
|
183
|
-
const choices = await prompts([
|
184
|
-
{
|
185
|
-
type: "confirm",
|
186
|
-
name: "airules",
|
187
|
-
message: "Do you want to add any specific rules for the AI? (e.g. no code exercises, no quizzes, etc, a particular writting style, etc)",
|
188
|
-
},
|
189
|
-
]);
|
190
|
-
if (choices.airules) {
|
191
|
-
await (0, creatorUtilities_1.createFileOnDesktop)("airules.txt");
|
192
|
-
console_1.default.info("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.");
|
193
|
-
const isReady = await prompts([
|
194
|
-
{
|
195
|
-
type: "confirm",
|
196
|
-
name: "isReady",
|
197
|
-
message: "Are you ready to continue?",
|
198
|
-
},
|
199
|
-
]);
|
200
|
-
if (!isReady.isReady) {
|
201
|
-
console_1.default.error("Please make the necessary changes and try again.");
|
202
|
-
process.exit(1);
|
203
|
-
}
|
204
|
-
const airules = (0, creatorUtilities_1.getDesktopFile)("airules.txt");
|
205
|
-
return airules;
|
206
|
-
}
|
207
|
-
return null;
|
208
|
-
};
|
209
158
|
const handleAILogic = async (tutorialDir, packageInfo) => {
|
210
159
|
fs.removeSync(path.join(tutorialDir, "exercises", "01-hello-world"));
|
211
160
|
let sessionPayload = await session_1.default.getPayload();
|
@@ -232,15 +181,17 @@ const handleAILogic = async (tutorialDir, packageInfo) => {
|
|
232
181
|
console_1.default.error("It seems you cannot generate tutorials with AI. Make sure you creator subscription is up to date here: https://4geeks.com/profile/subscriptions. If you believe there is an issue you can always contact support@4geeks.com");
|
233
182
|
process.exit(1);
|
234
183
|
}
|
235
|
-
const isCreator = await
|
236
|
-
if (!isCreator) {
|
237
|
-
|
238
|
-
|
239
|
-
|
184
|
+
// const isCreator = await hasCreatorPermission(rigoToken)
|
185
|
+
// if (!isCreator) {
|
186
|
+
// Console.error(
|
187
|
+
// "👀 Oops! You need to be a creator to use our specialized AI. Please contact support"
|
188
|
+
// )
|
189
|
+
// process.exit(1)
|
190
|
+
// }
|
240
191
|
console_1.default.success("🎉 Let's begin this learning journey!");
|
241
192
|
const { targetAudience, estimatedDuration } = await whichTargetAudienceAndEstimatedDuration();
|
242
|
-
const contentIndex = await appendContentIndex();
|
243
|
-
const airules = await appendAIRules();
|
193
|
+
const contentIndex = await (0, creatorUtilities_1.appendContentIndex)();
|
194
|
+
const airules = await (0, creatorUtilities_1.appendAIRules)();
|
244
195
|
let packageContext = `
|
245
196
|
\n
|
246
197
|
Title: "${packageInfo.title.us}"
|
@@ -49,7 +49,7 @@ export declare const makePackageInfo: (choices: any) => {
|
|
49
49
|
slug: any;
|
50
50
|
};
|
51
51
|
export declare function estimateDuration(listOfSteps: string[]): number;
|
52
|
-
export declare function createFileOnDesktop(fileName: string): Promise<void>;
|
52
|
+
export declare function createFileOnDesktop(fileName: string, content: string): Promise<void>;
|
53
53
|
export declare function getDesktopFile(fileName: string): string;
|
54
54
|
export declare function extractTextFromMarkdown(mdContent: string): string;
|
55
55
|
export declare const saveTranslatedReadme: (exercise: string, languageCode: string, readme: string) => Promise<void>;
|
@@ -90,4 +90,6 @@ export declare function fleschKincaidGrade(text: string): TFKGLResult;
|
|
90
90
|
*/
|
91
91
|
export declare function countSentences(text: string): number;
|
92
92
|
export declare function howManyDifficultParagraphs(paragraphs: TFKGLResult[], maxFKGL: number): number;
|
93
|
+
export declare const appendContentIndex: () => Promise<string | null>;
|
94
|
+
export declare const appendAIRules: () => Promise<string | null>;
|
93
95
|
export {};
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.saveTranslatedReadme = exports.makePackageInfo = exports.getExInfo = exports.estimateReadingTime = void 0;
|
3
|
+
exports.appendAIRules = exports.appendContentIndex = exports.saveTranslatedReadme = exports.makePackageInfo = exports.getExInfo = exports.estimateReadingTime = void 0;
|
4
4
|
exports.checkReadability = checkReadability;
|
5
5
|
exports.extractImagesFromMarkdown = extractImagesFromMarkdown;
|
6
6
|
exports.getFilenameFromUrl = getFilenameFromUrl;
|
@@ -26,6 +26,7 @@ const path_1 = require("path");
|
|
26
26
|
const child_process_1 = require("child_process");
|
27
27
|
const util_1 = require("util");
|
28
28
|
const yaml = require("js-yaml");
|
29
|
+
const prompts = require("prompts");
|
29
30
|
const estimateReadingTime = (text, wordsPerMinute = 150) => {
|
30
31
|
const words = text.trim().split(/\s+/).length;
|
31
32
|
const minutes = words / wordsPerMinute;
|
@@ -161,19 +162,10 @@ function estimateDuration(listOfSteps) {
|
|
161
162
|
}
|
162
163
|
const writeFilePromise = (0, util_1.promisify)(fs.writeFile);
|
163
164
|
const execPromise = (0, util_1.promisify)(child_process_1.exec);
|
164
|
-
|
165
|
-
|
166
|
-
Introduction to AI: Explain what is AI and its applications
|
167
|
-
Introduction to Machine Learning: Explain what is machine learning and its applications
|
168
|
-
What is an AI Model: Explain what is an AI model and its applications
|
169
|
-
How to use an AI Model: Different APIs, local models, etc.
|
170
|
-
How to build an AI Model: Fine-tuning, data collection, cleaning and more.
|
171
|
-
`;
|
172
|
-
async function createFileOnDesktop(fileName) {
|
165
|
+
async function createFileOnDesktop(fileName, content) {
|
173
166
|
try {
|
174
167
|
const desktopPath = (0, path_1.join)((0, os_1.homedir)(), "Desktop");
|
175
168
|
const filePath = (0, path_1.join)(desktopPath, fileName);
|
176
|
-
const content = example_content.trim();
|
177
169
|
await writeFilePromise(filePath, content);
|
178
170
|
console.log(`File created successfully at: ${filePath}`);
|
179
171
|
await openFile(filePath);
|
@@ -333,3 +325,75 @@ function countSentences(text) {
|
|
333
325
|
function howManyDifficultParagraphs(paragraphs, maxFKGL) {
|
334
326
|
return paragraphs.filter(paragraph => paragraph.fkgl > maxFKGL).length;
|
335
327
|
}
|
328
|
+
const example_content = `Write or paste your table of content below this line, each topic should be defined on a new line, here is an example:
|
329
|
+
|
330
|
+
Introduction to AI: Explain what is AI and its applications
|
331
|
+
Introduction to Machine Learning: Explain what is machine learning and its applications
|
332
|
+
What is an AI Model: Explain what is an AI model and its applications
|
333
|
+
How to use an AI Model: Different APIs, local models, etc.
|
334
|
+
How to build an AI Model: Fine-tuning, data collection, cleaning and more.
|
335
|
+
`;
|
336
|
+
const appendContentIndex = async () => {
|
337
|
+
const choices = await prompts([
|
338
|
+
{
|
339
|
+
type: "confirm",
|
340
|
+
name: "contentIndex",
|
341
|
+
message: "Do you have a content index for this tutorial?",
|
342
|
+
},
|
343
|
+
]);
|
344
|
+
if (choices.contentIndex) {
|
345
|
+
await createFileOnDesktop("content_index.txt", example_content);
|
346
|
+
console_1.default.info("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.");
|
347
|
+
const isReady = await prompts([
|
348
|
+
{
|
349
|
+
type: "confirm",
|
350
|
+
name: "isReady",
|
351
|
+
message: "Are you ready to continue?",
|
352
|
+
},
|
353
|
+
]);
|
354
|
+
if (!isReady.isReady) {
|
355
|
+
console_1.default.error("Please make the necessary changes and try again.");
|
356
|
+
process.exit(1);
|
357
|
+
}
|
358
|
+
const contentIndex = getDesktopFile("content_index.txt");
|
359
|
+
return contentIndex;
|
360
|
+
}
|
361
|
+
return null;
|
362
|
+
};
|
363
|
+
exports.appendContentIndex = appendContentIndex;
|
364
|
+
const example_airules = `
|
365
|
+
Write with an engaging tone, use simple words and avoid complex sentences.
|
366
|
+
Write in first person, as if you are talking to the reader.
|
367
|
+
Add mental maps to help the reader understand the content.
|
368
|
+
Add diagrams to help the reader understand the content.
|
369
|
+
No code exercises required
|
370
|
+
|
371
|
+
`;
|
372
|
+
const appendAIRules = async () => {
|
373
|
+
const choices = await prompts([
|
374
|
+
{
|
375
|
+
type: "confirm",
|
376
|
+
name: "airules",
|
377
|
+
message: "Do you want to add any specific rules for the AI? (e.g. no code exercises, no quizzes, etc, a particular writting style, etc)",
|
378
|
+
},
|
379
|
+
]);
|
380
|
+
if (choices.airules) {
|
381
|
+
await createFileOnDesktop("airules.txt", example_airules);
|
382
|
+
console_1.default.info("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.");
|
383
|
+
const isReady = await prompts([
|
384
|
+
{
|
385
|
+
type: "confirm",
|
386
|
+
name: "isReady",
|
387
|
+
message: "Are you ready to continue?",
|
388
|
+
},
|
389
|
+
]);
|
390
|
+
if (!isReady.isReady) {
|
391
|
+
console_1.default.error("Please make the necessary changes and try again.");
|
392
|
+
process.exit(1);
|
393
|
+
}
|
394
|
+
const airules = getDesktopFile("airules.txt");
|
395
|
+
return airules;
|
396
|
+
}
|
397
|
+
return null;
|
398
|
+
};
|
399
|
+
exports.appendAIRules = appendAIRules;
|
package/oclif.manifest.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":"5.0.
|
1
|
+
{"version":"5.0.45","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":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false}},"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":{"strict":{"name":"strict","type":"boolean","char":"s","description":"strict mode","allowNo":false},"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.45",
|
5
5
|
"author": "Alejandro Sanchez @alesanchezr",
|
6
6
|
"contributors": [
|
7
7
|
{
|
@@ -47,6 +47,7 @@
|
|
47
47
|
"node-emoji": "^1.10.0",
|
48
48
|
"node-fetch": "^2.7.0",
|
49
49
|
"node-persist": "^3.1.0",
|
50
|
+
"ora": "^8.2.0",
|
50
51
|
"prompts": "^2.3.2",
|
51
52
|
"shelljs": "^0.8.4",
|
52
53
|
"socket.io": "^4.4.1",
|
package/src/commands/init.ts
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
import { flags } from "@oclif/command"
|
2
2
|
import BaseCommand from "../utils/BaseCommand"
|
3
|
+
import ora from "ora"
|
4
|
+
|
3
5
|
// eslint-disable-next-line
|
4
6
|
import * as fs from "fs-extra"
|
5
7
|
import * as prompts from "prompts"
|
@@ -31,8 +33,8 @@ import {
|
|
31
33
|
getFilenameFromUrl,
|
32
34
|
makePackageInfo,
|
33
35
|
estimateDuration,
|
34
|
-
|
35
|
-
|
36
|
+
appendContentIndex,
|
37
|
+
appendAIRules,
|
36
38
|
} from "../utils/creatorUtilities"
|
37
39
|
import SessionManager from "../managers/session"
|
38
40
|
|
@@ -186,6 +188,7 @@ const initializeInteractiveCreation = async (
|
|
186
188
|
let currentDifficulty = ""
|
187
189
|
|
188
190
|
while (!isReady) {
|
191
|
+
const spinner = ora("Thinking...").start()
|
189
192
|
let wholeInfo = courseInfo
|
190
193
|
wholeInfo += `
|
191
194
|
Current title: ${currentTitle}
|
@@ -196,6 +199,7 @@ const initializeInteractiveCreation = async (
|
|
196
199
|
courseInfo: wholeInfo,
|
197
200
|
prevInteractions: prevInteractions,
|
198
201
|
})
|
202
|
+
spinner.succeed("Done!")
|
199
203
|
currentSteps = res.parsed.listOfSteps
|
200
204
|
isReady = res.parsed.ready
|
201
205
|
if (res.parsed.title && currentTitle !== res.parsed.title) {
|
@@ -244,71 +248,6 @@ process.emitWarning = (warning: string) => {
|
|
244
248
|
Console.debug("A Warning was emitted by Node.js: ", warning)
|
245
249
|
}
|
246
250
|
|
247
|
-
const appendContentIndex = async () => {
|
248
|
-
const choices = await prompts([
|
249
|
-
{
|
250
|
-
type: "confirm",
|
251
|
-
name: "contentIndex",
|
252
|
-
message: "Do you have a content index for this tutorial?",
|
253
|
-
},
|
254
|
-
])
|
255
|
-
if (choices.contentIndex) {
|
256
|
-
await createFileOnDesktop("content_index.txt")
|
257
|
-
Console.info(
|
258
|
-
"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."
|
259
|
-
)
|
260
|
-
const isReady = await prompts([
|
261
|
-
{
|
262
|
-
type: "confirm",
|
263
|
-
name: "isReady",
|
264
|
-
message: "Are you ready to continue?",
|
265
|
-
},
|
266
|
-
])
|
267
|
-
if (!isReady.isReady) {
|
268
|
-
Console.error("Please make the necessary changes and try again.")
|
269
|
-
process.exit(1)
|
270
|
-
}
|
271
|
-
|
272
|
-
const contentIndex = getDesktopFile("content_index.txt")
|
273
|
-
return contentIndex
|
274
|
-
}
|
275
|
-
|
276
|
-
return null
|
277
|
-
}
|
278
|
-
|
279
|
-
const appendAIRules = async () => {
|
280
|
-
const choices = await prompts([
|
281
|
-
{
|
282
|
-
type: "confirm",
|
283
|
-
name: "airules",
|
284
|
-
message:
|
285
|
-
"Do you want to add any specific rules for the AI? (e.g. no code exercises, no quizzes, etc, a particular writting style, etc)",
|
286
|
-
},
|
287
|
-
])
|
288
|
-
if (choices.airules) {
|
289
|
-
await createFileOnDesktop("airules.txt")
|
290
|
-
Console.info(
|
291
|
-
"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."
|
292
|
-
)
|
293
|
-
const isReady = await prompts([
|
294
|
-
{
|
295
|
-
type: "confirm",
|
296
|
-
name: "isReady",
|
297
|
-
message: "Are you ready to continue?",
|
298
|
-
},
|
299
|
-
])
|
300
|
-
if (!isReady.isReady) {
|
301
|
-
Console.error("Please make the necessary changes and try again.")
|
302
|
-
process.exit(1)
|
303
|
-
}
|
304
|
-
|
305
|
-
const airules = getDesktopFile("airules.txt")
|
306
|
-
return airules
|
307
|
-
}
|
308
|
-
|
309
|
-
return null
|
310
|
-
}
|
311
|
-
|
312
251
|
const handleAILogic = async (tutorialDir: string, packageInfo: PackageInfo) => {
|
313
252
|
fs.removeSync(path.join(tutorialDir, "exercises", "01-hello-world"))
|
314
253
|
|
@@ -349,13 +288,13 @@ const handleAILogic = async (tutorialDir: string, packageInfo: PackageInfo) => {
|
|
349
288
|
process.exit(1)
|
350
289
|
}
|
351
290
|
|
352
|
-
const isCreator = await hasCreatorPermission(rigoToken)
|
353
|
-
if (!isCreator) {
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
}
|
291
|
+
// const isCreator = await hasCreatorPermission(rigoToken)
|
292
|
+
// if (!isCreator) {
|
293
|
+
// Console.error(
|
294
|
+
// "👀 Oops! You need to be a creator to use our specialized AI. Please contact support"
|
295
|
+
// )
|
296
|
+
// process.exit(1)
|
297
|
+
// }
|
359
298
|
|
360
299
|
Console.success("🎉 Let's begin this learning journey!")
|
361
300
|
|
@@ -12,6 +12,7 @@ import { exec } from "child_process"
|
|
12
12
|
import { promisify } from "util"
|
13
13
|
|
14
14
|
import * as yaml from "js-yaml"
|
15
|
+
import * as prompts from "prompts"
|
15
16
|
|
16
17
|
type TEstimateReadingTimeReturns = {
|
17
18
|
minutes: number
|
@@ -207,22 +208,11 @@ export function estimateDuration(listOfSteps: string[]): number {
|
|
207
208
|
const writeFilePromise = promisify(fs.writeFile)
|
208
209
|
const execPromise = promisify(exec)
|
209
210
|
|
210
|
-
|
211
|
-
|
212
|
-
Introduction to AI: Explain what is AI and its applications
|
213
|
-
Introduction to Machine Learning: Explain what is machine learning and its applications
|
214
|
-
What is an AI Model: Explain what is an AI model and its applications
|
215
|
-
How to use an AI Model: Different APIs, local models, etc.
|
216
|
-
How to build an AI Model: Fine-tuning, data collection, cleaning and more.
|
217
|
-
`
|
218
|
-
|
219
|
-
export async function createFileOnDesktop(fileName: string) {
|
211
|
+
export async function createFileOnDesktop(fileName: string, content: string) {
|
220
212
|
try {
|
221
213
|
const desktopPath = join(homedir(), "Desktop")
|
222
214
|
const filePath = join(desktopPath, fileName)
|
223
215
|
|
224
|
-
const content = example_content.trim()
|
225
|
-
|
226
216
|
await writeFilePromise(filePath, content)
|
227
217
|
console.log(`File created successfully at: ${filePath}`)
|
228
218
|
|
@@ -419,3 +409,86 @@ export function howManyDifficultParagraphs(
|
|
419
409
|
): number {
|
420
410
|
return paragraphs.filter(paragraph => paragraph.fkgl > maxFKGL).length
|
421
411
|
}
|
412
|
+
|
413
|
+
const example_content = `Write or paste your table of content below this line, each topic should be defined on a new line, here is an example:
|
414
|
+
|
415
|
+
Introduction to AI: Explain what is AI and its applications
|
416
|
+
Introduction to Machine Learning: Explain what is machine learning and its applications
|
417
|
+
What is an AI Model: Explain what is an AI model and its applications
|
418
|
+
How to use an AI Model: Different APIs, local models, etc.
|
419
|
+
How to build an AI Model: Fine-tuning, data collection, cleaning and more.
|
420
|
+
`
|
421
|
+
|
422
|
+
export const appendContentIndex = async () => {
|
423
|
+
const choices = await prompts([
|
424
|
+
{
|
425
|
+
type: "confirm",
|
426
|
+
name: "contentIndex",
|
427
|
+
message: "Do you have a content index for this tutorial?",
|
428
|
+
},
|
429
|
+
])
|
430
|
+
if (choices.contentIndex) {
|
431
|
+
await createFileOnDesktop("content_index.txt", example_content)
|
432
|
+
Console.info(
|
433
|
+
"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."
|
434
|
+
)
|
435
|
+
const isReady = await prompts([
|
436
|
+
{
|
437
|
+
type: "confirm",
|
438
|
+
name: "isReady",
|
439
|
+
message: "Are you ready to continue?",
|
440
|
+
},
|
441
|
+
])
|
442
|
+
if (!isReady.isReady) {
|
443
|
+
Console.error("Please make the necessary changes and try again.")
|
444
|
+
process.exit(1)
|
445
|
+
}
|
446
|
+
|
447
|
+
const contentIndex = getDesktopFile("content_index.txt")
|
448
|
+
return contentIndex
|
449
|
+
}
|
450
|
+
|
451
|
+
return null
|
452
|
+
}
|
453
|
+
|
454
|
+
const example_airules = `
|
455
|
+
Write with an engaging tone, use simple words and avoid complex sentences.
|
456
|
+
Write in first person, as if you are talking to the reader.
|
457
|
+
Add mental maps to help the reader understand the content.
|
458
|
+
Add diagrams to help the reader understand the content.
|
459
|
+
No code exercises required
|
460
|
+
|
461
|
+
`
|
462
|
+
|
463
|
+
export const appendAIRules = async () => {
|
464
|
+
const choices = await prompts([
|
465
|
+
{
|
466
|
+
type: "confirm",
|
467
|
+
name: "airules",
|
468
|
+
message:
|
469
|
+
"Do you want to add any specific rules for the AI? (e.g. no code exercises, no quizzes, etc, a particular writting style, etc)",
|
470
|
+
},
|
471
|
+
])
|
472
|
+
if (choices.airules) {
|
473
|
+
await createFileOnDesktop("airules.txt", example_airules)
|
474
|
+
Console.info(
|
475
|
+
"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."
|
476
|
+
)
|
477
|
+
const isReady = await prompts([
|
478
|
+
{
|
479
|
+
type: "confirm",
|
480
|
+
name: "isReady",
|
481
|
+
message: "Are you ready to continue?",
|
482
|
+
},
|
483
|
+
])
|
484
|
+
if (!isReady.isReady) {
|
485
|
+
Console.error("Please make the necessary changes and try again.")
|
486
|
+
process.exit(1)
|
487
|
+
}
|
488
|
+
|
489
|
+
const airules = getDesktopFile("airules.txt")
|
490
|
+
return airules
|
491
|
+
}
|
492
|
+
|
493
|
+
return null
|
494
|
+
}
|