@learnpack/learnpack 5.0.26 → 5.0.28
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 +27 -11
- package/lib/commands/breakToken.d.ts +10 -0
- package/lib/commands/breakToken.js +15 -0
- package/lib/commands/init.js +64 -118
- package/lib/commands/publish.js +29 -2
- package/lib/managers/session.js +8 -0
- package/lib/models/session.d.ts +1 -0
- package/lib/utils/api.d.ts +11 -1
- package/lib/utils/api.js +49 -11
- package/lib/utils/creatorUtilities.d.ts +44 -0
- package/lib/utils/creatorUtilities.js +111 -0
- package/lib/utils/rigoActions.d.ts +3 -0
- package/lib/utils/rigoActions.js +11 -0
- package/oclif.manifest.json +1 -1
- package/package.json +3 -1
- package/src/commands/breakToken.ts +25 -0
- package/src/commands/init.ts +108 -179
- package/src/commands/publish.ts +34 -2
- package/src/managers/session.ts +11 -0
- package/src/models/session.ts +1 -0
- package/src/utils/api.ts +60 -12
- package/src/utils/creatorUtilities.ts +147 -0
- package/src/utils/rigoActions.ts +22 -4
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.28 win32-x64 node-v20.16.0
|
25
25
|
$ learnpack --help [COMMAND]
|
26
26
|
USAGE
|
27
27
|
$ learnpack COMMAND
|
@@ -33,6 +33,7 @@ USAGE
|
|
33
33
|
|
34
34
|
<!-- commands -->
|
35
35
|
* [`learnpack audit`](#learnpack-audit)
|
36
|
+
* [`learnpack breakToken`](#learnpack-breaktoken)
|
36
37
|
* [`learnpack clean`](#learnpack-clean)
|
37
38
|
* [`learnpack download [PACKAGE]`](#learnpack-download-package)
|
38
39
|
* [`learnpack help [COMMAND]`](#learnpack-help-command)
|
@@ -75,7 +76,22 @@ DESCRIPTION
|
|
75
76
|
12. If there is a file within the exercises folder but not inside of any particular exercise's folder. (Warning)
|
76
77
|
```
|
77
78
|
|
78
|
-
_See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
79
|
+
_See code: [src\commands\audit.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.28/src\commands\audit.ts)_
|
80
|
+
|
81
|
+
## `learnpack breakToken`
|
82
|
+
|
83
|
+
Break the token
|
84
|
+
|
85
|
+
```
|
86
|
+
USAGE
|
87
|
+
$ learnpack breakToken
|
88
|
+
|
89
|
+
OPTIONS
|
90
|
+
-h, --grading show CLI help
|
91
|
+
-y, --yes Skip all prompts and initialize an empty project
|
92
|
+
```
|
93
|
+
|
94
|
+
_See code: [src\commands\breakToken.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.28/src\commands\breakToken.ts)_
|
79
95
|
|
80
96
|
## `learnpack clean`
|
81
97
|
|
@@ -90,7 +106,7 @@ DESCRIPTION
|
|
90
106
|
Extra documentation goes here
|
91
107
|
```
|
92
108
|
|
93
|
-
_See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
109
|
+
_See code: [src\commands\clean.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.28/src\commands\clean.ts)_
|
94
110
|
|
95
111
|
## `learnpack download [PACKAGE]`
|
96
112
|
|
@@ -108,7 +124,7 @@ DESCRIPTION
|
|
108
124
|
Extra documentation goes here
|
109
125
|
```
|
110
126
|
|
111
|
-
_See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
127
|
+
_See code: [src\commands\download.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.28/src\commands\download.ts)_
|
112
128
|
|
113
129
|
## `learnpack help [COMMAND]`
|
114
130
|
|
@@ -140,7 +156,7 @@ OPTIONS
|
|
140
156
|
-y, --yes Skip all prompts and initialize an empty project
|
141
157
|
```
|
142
158
|
|
143
|
-
_See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
159
|
+
_See code: [src\commands\init.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.28/src\commands\init.ts)_
|
144
160
|
|
145
161
|
## `learnpack login [PACKAGE]`
|
146
162
|
|
@@ -158,7 +174,7 @@ DESCRIPTION
|
|
158
174
|
Extra documentation goes here
|
159
175
|
```
|
160
176
|
|
161
|
-
_See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
177
|
+
_See code: [src\commands\login.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.28/src\commands\login.ts)_
|
162
178
|
|
163
179
|
## `learnpack logout [PACKAGE]`
|
164
180
|
|
@@ -176,7 +192,7 @@ DESCRIPTION
|
|
176
192
|
Extra documentation goes here
|
177
193
|
```
|
178
194
|
|
179
|
-
_See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
195
|
+
_See code: [src\commands\logout.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.28/src\commands\logout.ts)_
|
180
196
|
|
181
197
|
## `learnpack plugins`
|
182
198
|
|
@@ -307,7 +323,7 @@ OPTIONS
|
|
307
323
|
-h, --help show CLI help
|
308
324
|
```
|
309
325
|
|
310
|
-
_See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
326
|
+
_See code: [src\commands\publish.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.28/src\commands\publish.ts)_
|
311
327
|
|
312
328
|
## `learnpack start`
|
313
329
|
|
@@ -329,7 +345,7 @@ OPTIONS
|
|
329
345
|
-y, --yes Skip all prompts and initialize an empty project
|
330
346
|
```
|
331
347
|
|
332
|
-
_See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
348
|
+
_See code: [src\commands\start.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.28/src\commands\start.ts)_
|
333
349
|
|
334
350
|
## `learnpack test [EXERCISESLUG]`
|
335
351
|
|
@@ -346,7 +362,7 @@ OPTIONS
|
|
346
362
|
-y, --yes Skip all prompts and initialize an empty project
|
347
363
|
```
|
348
364
|
|
349
|
-
_See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
365
|
+
_See code: [src\commands\test.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.28/src\commands\test.ts)_
|
350
366
|
|
351
367
|
## `learnpack translate`
|
352
368
|
|
@@ -360,7 +376,7 @@ OPTIONS
|
|
360
376
|
-y, --yes Skip all prompts and initialize an empty project
|
361
377
|
```
|
362
378
|
|
363
|
-
_See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.
|
379
|
+
_See code: [src\commands\translate.ts](https://github.com/learnpack/learnpack-cli/blob/v5.0.28/src\commands\translate.ts)_
|
364
380
|
<!-- commandsstop -->
|
365
381
|
|
366
382
|
> > > > > > > 0cb3e56d84c197f9d008836bb573eade212b7e57
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import BaseCommand from "../utils/BaseCommand";
|
2
|
+
declare class BreakTokenCommand extends BaseCommand {
|
3
|
+
static description: string;
|
4
|
+
static flags: {
|
5
|
+
grading: import("@oclif/parser/lib/flags").IBooleanFlag<void>;
|
6
|
+
yes: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
|
7
|
+
};
|
8
|
+
run(): Promise<void>;
|
9
|
+
}
|
10
|
+
export default BreakTokenCommand;
|
@@ -0,0 +1,15 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
const command_1 = require("@oclif/command");
|
4
|
+
const BaseCommand_1 = require("../utils/BaseCommand");
|
5
|
+
const session_1 = require("../managers/session");
|
6
|
+
class BreakTokenCommand extends BaseCommand_1.default {
|
7
|
+
async run() {
|
8
|
+
const { flags } = this.parse(BreakTokenCommand);
|
9
|
+
await session_1.default.breakToken();
|
10
|
+
process.exit(0);
|
11
|
+
}
|
12
|
+
}
|
13
|
+
BreakTokenCommand.description = "Break the token";
|
14
|
+
BreakTokenCommand.flags = Object.assign(Object.assign({}, BaseCommand_1.default.flags), { grading: command_1.flags.help({ char: "h" }) });
|
15
|
+
exports.default = BreakTokenCommand;
|
package/lib/commands/init.js
CHANGED
@@ -13,86 +13,34 @@ const errors_1 = require("../utils/errors");
|
|
13
13
|
const path = require("path");
|
14
14
|
const rigoActions_1 = require("../utils/rigoActions");
|
15
15
|
const api_2 = require("../utils/api");
|
16
|
-
const
|
17
|
-
|
18
|
-
.toString()
|
19
|
-
.normalize("NFD")
|
20
|
-
.replace(/[\u0300-\u036F]/g, "")
|
21
|
-
.toLowerCase()
|
22
|
-
.trim()
|
23
|
-
.replace(/\s+/g, "-")
|
24
|
-
.replace(/[^\w-]+/g, "");
|
25
|
-
};
|
26
|
-
const getExInfo = (title) => {
|
27
|
-
// Example title: '1.0 - Introduction to AI [READ: Small introduction to important concepts such as AI, machine learning, and their applications]'
|
28
|
-
let [exNumber, exTitle] = title.split(" - ");
|
29
|
-
// Extract kind and description
|
30
|
-
const kindMatch = exTitle.match(/\[(.*?):(.*?)]/);
|
31
|
-
const kind = kindMatch ? kindMatch[1].trim().toLowerCase() : "read";
|
32
|
-
const description = kindMatch ? kindMatch[2].trim() : "";
|
33
|
-
exNumber = exNumber.trim();
|
34
|
-
// Clean title
|
35
|
-
exTitle = exTitle.replace((kindMatch === null || kindMatch === void 0 ? void 0 : kindMatch[0]) || "", "").trim();
|
36
|
-
exTitle = slugify(exTitle);
|
37
|
-
return {
|
38
|
-
exNumber,
|
39
|
-
kind,
|
40
|
-
description,
|
41
|
-
exTitle,
|
42
|
-
};
|
43
|
-
};
|
44
|
-
function extractImagesFromMarkdown(markdown) {
|
45
|
-
const imageRegex = /!\[([^\]]*)]\(([^)]+)\)/g;
|
46
|
-
const images = [];
|
47
|
-
let match;
|
48
|
-
while ((match = imageRegex.exec(markdown)) !== null) {
|
49
|
-
const altText = match[1];
|
50
|
-
const url = match[2];
|
51
|
-
images.push({ alt: altText, url: url });
|
52
|
-
}
|
53
|
-
return images;
|
54
|
-
}
|
55
|
-
function getFilenameFromUrl(url) {
|
56
|
-
return path.basename(url);
|
57
|
-
}
|
58
|
-
const makePackageInfo = (choices) => {
|
59
|
-
const packageInfo = {
|
60
|
-
grading: choices.grading,
|
61
|
-
difficulty: choices.difficulty,
|
62
|
-
duration: parseInt(choices.duration),
|
63
|
-
description: {
|
64
|
-
us: choices.description,
|
65
|
-
},
|
66
|
-
title: {
|
67
|
-
us: choices.title,
|
68
|
-
},
|
69
|
-
slug: choices.title
|
70
|
-
.toLowerCase()
|
71
|
-
.replace(/ /g, "-")
|
72
|
-
.replace(/[^\w-]+/g, ""),
|
73
|
-
};
|
74
|
-
return packageInfo;
|
75
|
-
};
|
76
|
-
async function createPreviewReadme(tutorialDir, packageInfo, rigoToken, readmeContents) {
|
77
|
-
const readmeFilename = `README.md`;
|
78
|
-
const readmeContent = await (0, rigoActions_1.generateCourseIntroduction)(rigoToken, {
|
79
|
-
course_title: packageInfo.title.us,
|
80
|
-
lessons_context: readmeContents.join("\n"),
|
81
|
-
});
|
82
|
-
fs.writeFileSync(path.join(tutorialDir, readmeFilename), readmeContent.answer);
|
83
|
-
}
|
16
|
+
const creatorUtilities_1 = require("../utils/creatorUtilities");
|
17
|
+
const session_1 = require("../managers/session");
|
84
18
|
const initializeInteractiveCreation = async (rigoToken, courseInfo) => {
|
85
19
|
let prevInteractions = "";
|
86
20
|
let isReady = false;
|
87
21
|
let currentSteps = [];
|
22
|
+
let currentTitle = "";
|
23
|
+
let currentDescription = "";
|
88
24
|
while (!isReady) {
|
25
|
+
let wholeInfo = courseInfo;
|
26
|
+
wholeInfo += `
|
27
|
+
Current title: ${currentTitle}
|
28
|
+
Current description: ${currentDescription}
|
29
|
+
`;
|
89
30
|
// eslint-disable-next-line
|
90
31
|
const res = await (0, rigoActions_1.interactiveCreation)(rigoToken, {
|
91
|
-
courseInfo:
|
32
|
+
courseInfo: wholeInfo,
|
92
33
|
prevInteractions: prevInteractions,
|
93
34
|
});
|
94
35
|
currentSteps = res.parsed.listOfSteps;
|
95
36
|
isReady = res.parsed.ready;
|
37
|
+
if (res.parsed.title && currentTitle !== res.parsed.title) {
|
38
|
+
currentTitle = res.parsed.title;
|
39
|
+
}
|
40
|
+
if (res.parsed.description &&
|
41
|
+
currentDescription !== res.parsed.description) {
|
42
|
+
currentDescription = res.parsed.description;
|
43
|
+
}
|
96
44
|
if (!isReady) {
|
97
45
|
console.log(currentSteps);
|
98
46
|
console_1.default.info(`AI: ${res.parsed.aiMessage}`);
|
@@ -109,45 +57,32 @@ const initializeInteractiveCreation = async (rigoToken, courseInfo) => {
|
|
109
57
|
}
|
110
58
|
}
|
111
59
|
return {
|
112
|
-
currentSteps,
|
113
|
-
|
60
|
+
steps: currentSteps,
|
61
|
+
title: currentTitle,
|
62
|
+
description: currentDescription,
|
63
|
+
interactions: prevInteractions,
|
114
64
|
};
|
115
65
|
};
|
116
66
|
const handleAILogic = async (tutorialDir, packageInfo) => {
|
117
|
-
console_1.default.info("Almost there! First you need to login with 4Geeks.com to use AI Generation tool for creators. You can create a new account here: https://4geeks.com/creators");
|
118
67
|
fs.removeSync(path.join(tutorialDir, "exercises", "01-hello-world"));
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
message: "What's your password?",
|
132
|
-
validate: (value) => {
|
133
|
-
return value.length > 0;
|
134
|
-
},
|
135
|
-
},
|
136
|
-
]);
|
137
|
-
let sessionPayload;
|
138
|
-
try {
|
139
|
-
sessionPayload = await api_1.default.login(loginPrompts.email, loginPrompts.password);
|
140
|
-
}
|
141
|
-
catch (error) {
|
142
|
-
console_1.default.error("Error trying to authenticate");
|
143
|
-
console_1.default.error(error.message || error);
|
144
|
-
return;
|
68
|
+
let sessionPayload = await session_1.default.getPayload();
|
69
|
+
if (!sessionPayload ||
|
70
|
+
!sessionPayload.rigobot ||
|
71
|
+
(sessionPayload.token && !(await api_1.default.validateToken(sessionPayload.token)))) {
|
72
|
+
console_1.default.info("Almost there! First you need to login with 4Geeks.com to use AI Generation tool for creators. You can create a new account here: https://4geeks.com/creators");
|
73
|
+
try {
|
74
|
+
sessionPayload = await session_1.default.login();
|
75
|
+
}
|
76
|
+
catch (error) {
|
77
|
+
console_1.default.error("Error trying to authenticate");
|
78
|
+
console_1.default.error(error.message || error);
|
79
|
+
}
|
145
80
|
}
|
146
81
|
const rigoToken = sessionPayload.rigobot.key;
|
147
|
-
const
|
148
|
-
if (
|
149
|
-
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
|
150
|
-
process.exit(1)
|
82
|
+
const consumable = await (0, api_2.getConsumable)(sessionPayload.token, "ai-generation");
|
83
|
+
if (consumable.count === 0) {
|
84
|
+
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");
|
85
|
+
// process.exit(1)
|
151
86
|
}
|
152
87
|
const isCreator = await (0, rigoActions_1.hasCreatorPermission)(rigoToken);
|
153
88
|
if (!isCreator) {
|
@@ -155,42 +90,53 @@ const handleAILogic = async (tutorialDir, packageInfo) => {
|
|
155
90
|
process.exit(1);
|
156
91
|
}
|
157
92
|
console_1.default.success("🎉 Let's begin this learning journey!");
|
158
|
-
|
93
|
+
let packageContext = `
|
159
94
|
\n
|
160
|
-
The following information comes from user inputs
|
161
95
|
Title: ${packageInfo.title.us}
|
162
96
|
Description: ${packageInfo.description.us}
|
163
|
-
Grading: ${packageInfo.grading}
|
164
97
|
Difficulty: ${packageInfo.difficulty}
|
165
98
|
Duration: ${packageInfo.duration}
|
166
|
-
|
167
|
-
Use it to generate more relevant exercises
|
168
99
|
`;
|
169
|
-
const {
|
100
|
+
const { steps, title, description } = await initializeInteractiveCreation(rigoToken, packageContext);
|
101
|
+
packageInfo.title.us = title;
|
102
|
+
packageInfo.description.us = description;
|
103
|
+
packageContext = `
|
104
|
+
Title: ${title}
|
105
|
+
Description: ${description}
|
106
|
+
Difficulty: ${packageInfo.difficulty}
|
107
|
+
Estimated duration: ${packageInfo.duration}
|
108
|
+
List of exercises: ${steps.join(", ")}
|
109
|
+
`;
|
170
110
|
const exercisesDir = path.join(tutorialDir, "exercises");
|
171
111
|
fs.ensureDirSync(exercisesDir);
|
172
112
|
console_1.default.info("Creating lessons...");
|
173
|
-
for (const [index, exercise] of
|
174
|
-
const { exNumber, exTitle } = getExInfo(exercise);
|
113
|
+
for (const [index, exercise] of steps.entries()) {
|
114
|
+
const { exNumber, exTitle } = (0, creatorUtilities_1.getExInfo)(exercise);
|
175
115
|
const exerciseDir = path.join(exercisesDir, `${exNumber}-${exTitle}`);
|
176
116
|
fs.ensureDirSync(exerciseDir);
|
177
117
|
}
|
178
|
-
const exercisePromises =
|
179
|
-
const { exNumber, exTitle, kind, description } = getExInfo(exercise);
|
118
|
+
const exercisePromises = steps.map(async (exercise, index) => {
|
119
|
+
const { exNumber, exTitle, kind, description } = (0, creatorUtilities_1.getExInfo)(exercise);
|
180
120
|
const exerciseDir = path.join(exercisesDir, `${exNumber}-${exTitle}`);
|
181
121
|
const readme = await (0, rigoActions_1.readmeCreator)(rigoToken, {
|
182
122
|
title: `${exNumber} - ${exTitle}`,
|
183
123
|
output_lang: "en",
|
184
|
-
list_of_exercises:
|
124
|
+
list_of_exercises: steps.join(","),
|
185
125
|
tutorial_description: packageContext,
|
186
126
|
lesson_description: description,
|
187
127
|
kind: kind.toLowerCase(),
|
188
128
|
});
|
129
|
+
const { exceedsThreshold, newMarkdown } = (0, creatorUtilities_1.checkReadingTime)(readme.parsed.content, 200);
|
130
|
+
if (exceedsThreshold) {
|
131
|
+
console_1.default.error("The reading time exceeds the threshold");
|
132
|
+
console_1.default.info(`Please reduce the reading time of the lesson, current reading time is ${exceedsThreshold} minutes`);
|
133
|
+
}
|
189
134
|
const readmeFilename = "README.md";
|
190
|
-
fs.writeFileSync(path.join(exerciseDir, readmeFilename),
|
135
|
+
fs.writeFileSync(path.join(exerciseDir, readmeFilename), newMarkdown);
|
191
136
|
if (kind.toLowerCase() === "code") {
|
192
137
|
const codeFile = await (0, rigoActions_1.createCodeFile)(rigoToken, {
|
193
138
|
readme: readme.parsed.content,
|
139
|
+
tutorial_info: packageContext,
|
194
140
|
});
|
195
141
|
fs.writeFileSync(path.join(exerciseDir, `app.${codeFile.parsed.extension.replace(".", "")}`), codeFile.parsed.content);
|
196
142
|
}
|
@@ -201,11 +147,11 @@ const handleAILogic = async (tutorialDir, packageInfo) => {
|
|
201
147
|
console_1.default.success("Lessons created! 🎉");
|
202
148
|
console_1.default.info("Generating images for the lessons...");
|
203
149
|
for (const content of readmeContents) {
|
204
|
-
imagesArray = [...imagesArray, ...extractImagesFromMarkdown(content)];
|
150
|
+
imagesArray = [...imagesArray, ...(0, creatorUtilities_1.extractImagesFromMarkdown)(content)];
|
205
151
|
}
|
206
152
|
const imagePromises = imagesArray.map(async (image) => {
|
207
153
|
try {
|
208
|
-
const filename = getFilenameFromUrl(image.url);
|
154
|
+
const filename = (0, creatorUtilities_1.getFilenameFromUrl)(image.url);
|
209
155
|
const imagePath = path.join(tutorialDir, ".learn", "assets", filename);
|
210
156
|
const res = await (0, rigoActions_1.generateImage)(rigoToken, { prompt: image.alt });
|
211
157
|
await (0, rigoActions_1.downloadImage)(res.image_url, imagePath);
|
@@ -219,7 +165,7 @@ const handleAILogic = async (tutorialDir, packageInfo) => {
|
|
219
165
|
await Promise.all(imagePromises);
|
220
166
|
console_1.default.info("Images generated successfully! 🎉 Your tutorial will be ready soon!");
|
221
167
|
console_1.default.info("Creating preview readme...");
|
222
|
-
await createPreviewReadme(tutorialDir, packageInfo, rigoToken, readmeContents);
|
168
|
+
await (0, rigoActions_1.createPreviewReadme)(tutorialDir, packageInfo, rigoToken, readmeContents);
|
223
169
|
return true;
|
224
170
|
};
|
225
171
|
const getChoices = async (empty) => {
|
@@ -307,7 +253,7 @@ class InitComand extends BaseCommand_1.default {
|
|
307
253
|
const { flags } = this.parse(InitComand);
|
308
254
|
await alreadyInitialized();
|
309
255
|
const choices = await getChoices(flags.yes);
|
310
|
-
const packageInfo = makePackageInfo(choices);
|
256
|
+
const packageInfo = (0, creatorUtilities_1.makePackageInfo)(choices);
|
311
257
|
const tutorialDir = `./${packageInfo.slug}`;
|
312
258
|
fs.ensureDirSync(tutorialDir);
|
313
259
|
const templatesDir = path.resolve(__dirname, "../../src/utils/templates/" + (choices.grading || "no-grading"));
|
package/lib/commands/publish.js
CHANGED
@@ -13,6 +13,8 @@ const axios_1 = require("axios");
|
|
13
13
|
const FormData = require("form-data");
|
14
14
|
const console_1 = require("../utils/console");
|
15
15
|
const file_1 = require("../managers/file");
|
16
|
+
const api_1 = require("../utils/api");
|
17
|
+
const prompts = require("prompts");
|
16
18
|
const RIGOBOT_HOST = "https://rigobot.herokuapp.com";
|
17
19
|
// const RIGOBOT_HOST =
|
18
20
|
// "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
|
@@ -37,6 +39,26 @@ const runAudit = () => {
|
|
37
39
|
// Continuar con el proceso de build solo si `learnpack publish` fue exitoso
|
38
40
|
console_1.default.info("Learnpack publish completed successfully. Proceeding with build...");
|
39
41
|
};
|
42
|
+
const selectAcademy = async (academies) => {
|
43
|
+
if (academies.length === 0) {
|
44
|
+
return null;
|
45
|
+
}
|
46
|
+
if (academies.length === 1) {
|
47
|
+
return academies[0];
|
48
|
+
}
|
49
|
+
// prompts the user to select an academy to upload the assets
|
50
|
+
console_1.default.info("In which academy do you want to publish the asset?");
|
51
|
+
const response = await prompts({
|
52
|
+
type: "select",
|
53
|
+
name: "academy",
|
54
|
+
message: "Select an academy",
|
55
|
+
choices: academies.map((academy) => ({
|
56
|
+
title: academy.name,
|
57
|
+
value: academy,
|
58
|
+
})),
|
59
|
+
});
|
60
|
+
return response.academy;
|
61
|
+
};
|
40
62
|
class BuildCommand extends SessionCommand_1.default {
|
41
63
|
async init() {
|
42
64
|
const { flags } = this.parse(BuildCommand);
|
@@ -48,7 +70,9 @@ class BuildCommand extends SessionCommand_1.default {
|
|
48
70
|
// this.configManager?.clean()
|
49
71
|
const configObject = (_a = this.configManager) === null || _a === void 0 ? void 0 : _a.get();
|
50
72
|
let sessionPayload = await session_1.default.getPayload();
|
51
|
-
if (!sessionPayload ||
|
73
|
+
if (!sessionPayload ||
|
74
|
+
!sessionPayload.rigobot ||
|
75
|
+
(sessionPayload.token && !(await api_1.default.validateToken(sessionPayload.token)))) {
|
52
76
|
console_1.default.error("You must be logged in to upload a LearnPack package");
|
53
77
|
try {
|
54
78
|
sessionPayload = await session_1.default.login();
|
@@ -67,7 +91,10 @@ class BuildCommand extends SessionCommand_1.default {
|
|
67
91
|
console_1.default.debug("Building exercises");
|
68
92
|
(_c = this.configManager) === null || _c === void 0 ? void 0 : _c.buildIndex();
|
69
93
|
}
|
70
|
-
// const
|
94
|
+
// const academies = await api.listUserAcademies(sessionPayload.token)
|
95
|
+
// console.log(academies, "academies")
|
96
|
+
// const academy = await selectAcademy(academies)
|
97
|
+
// console.log(academy, "academy")
|
71
98
|
// Read learn.json to get the slug
|
72
99
|
const learnJsonPath = path.join(process.cwd(), "learn.json");
|
73
100
|
if (!fs.existsSync(learnJsonPath)) {
|
package/lib/managers/session.js
CHANGED
@@ -138,5 +138,13 @@ const Session = {
|
|
138
138
|
this.token = null;
|
139
139
|
console_1.default.success("You have logged out");
|
140
140
|
},
|
141
|
+
breakToken: async function () {
|
142
|
+
const payload = await this.getPayload();
|
143
|
+
if (payload) {
|
144
|
+
this.token = "asdasdasdasd";
|
145
|
+
await storage.setItem("bc-payload", Object.assign(Object.assign({}, payload), { token: "asdasdsad" }));
|
146
|
+
console_1.default.success("Token broken successfully");
|
147
|
+
}
|
148
|
+
},
|
141
149
|
};
|
142
150
|
exports.default = Session;
|
package/lib/models/session.d.ts
CHANGED
package/lib/utils/api.d.ts
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
type TConsumableSlug = "ai-conversation-message" | "ai-compilation" | "ai-tutorial-generation" | "ai-generation";
|
2
2
|
export declare const countConsumables: (consumables: any, consumableSlug?: TConsumableSlug) => any;
|
3
|
-
export declare const
|
3
|
+
export declare const getConsumable: (token: string, consumableSlug?: TConsumableSlug) => Promise<any>;
|
4
|
+
export interface TAcademy {
|
5
|
+
id: number;
|
6
|
+
name: string;
|
7
|
+
slug: string;
|
8
|
+
timezone: string;
|
9
|
+
}
|
10
|
+
export declare const listUserAcademies: (breathecodeToken: string) => Promise<TAcademy[]>;
|
11
|
+
export declare const validateToken: (token: string) => Promise<any>;
|
4
12
|
declare const _default: {
|
5
13
|
login: (identification: string, password: string) => Promise<any>;
|
6
14
|
publish: (config: any) => Promise<any>;
|
@@ -13,5 +21,7 @@ declare const _default: {
|
|
13
21
|
}) => Promise<any>;
|
14
22
|
sendBatchTelemetry: (url: string, body: any) => Promise<void>;
|
15
23
|
sendStreamTelemetry: (url: string, body: object) => Promise<void>;
|
24
|
+
listUserAcademies: (breathecodeToken: string) => Promise<TAcademy[]>;
|
25
|
+
validateToken: (token: string) => Promise<any>;
|
16
26
|
};
|
17
27
|
export default _default;
|
package/lib/utils/api.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.
|
3
|
+
exports.validateToken = exports.listUserAcademies = exports.getConsumable = exports.countConsumables = void 0;
|
4
4
|
const console_1 = require("../utils/console");
|
5
5
|
const storage = require("node-persist");
|
6
6
|
const cli_ux_1 = require("cli-ux");
|
@@ -63,13 +63,11 @@ const login = async (identification, password) => {
|
|
63
63
|
cli_ux_1.default.action.start(`Looking for credentials with ${identification}`);
|
64
64
|
await cli_ux_1.default.wait(1000);
|
65
65
|
const url = `${HOST}/v1/auth/login/`;
|
66
|
-
const
|
67
|
-
|
68
|
-
|
69
|
-
password: password,
|
70
|
-
}),
|
71
|
-
method: "post",
|
66
|
+
const res = await axios_1.default.post(url, {
|
67
|
+
email: identification,
|
68
|
+
password: password,
|
72
69
|
});
|
70
|
+
const data = res.data;
|
73
71
|
cli_ux_1.default.action.stop("ready");
|
74
72
|
let rigoPayload = null;
|
75
73
|
try {
|
@@ -258,22 +256,60 @@ const countConsumables = (consumables, consumableSlug = "ai-tutorial-generation"
|
|
258
256
|
return consumable ? consumable.balance.unit : 0;
|
259
257
|
};
|
260
258
|
exports.countConsumables = countConsumables;
|
261
|
-
const
|
259
|
+
const getConsumable = async (token, consumableSlug = "ai-generation") => {
|
262
260
|
const url = `${HOST}/v1/payments/me/service/consumable?virtual=true`;
|
263
261
|
const headers = {
|
264
262
|
Authorization: `Token ${token}`,
|
265
263
|
};
|
266
264
|
try {
|
267
265
|
const response = await axios_1.default.get(url, { headers });
|
268
|
-
const
|
269
|
-
return {
|
266
|
+
const count = (0, exports.countConsumables)(response.data, consumableSlug);
|
267
|
+
return { count };
|
270
268
|
}
|
271
269
|
catch (error) {
|
272
270
|
console.error("Error fetching consumables:", error);
|
273
271
|
throw error;
|
274
272
|
}
|
275
273
|
};
|
276
|
-
exports.
|
274
|
+
exports.getConsumable = getConsumable;
|
275
|
+
const listUserAcademies = async (breathecodeToken) => {
|
276
|
+
const url = "https://breathecode.herokuapp.com/v1/auth/user/me";
|
277
|
+
try {
|
278
|
+
const response = await axios_1.default.get(url, {
|
279
|
+
headers: {
|
280
|
+
Authorization: `Token ${breathecodeToken}`,
|
281
|
+
},
|
282
|
+
});
|
283
|
+
const data = response.data;
|
284
|
+
const academiesMap = new Map();
|
285
|
+
for (const role of data.roles) {
|
286
|
+
const academy = role.academy;
|
287
|
+
if (!academiesMap.has(academy.id)) {
|
288
|
+
academiesMap.set(academy.id, academy);
|
289
|
+
}
|
290
|
+
}
|
291
|
+
return [...academiesMap.values()];
|
292
|
+
}
|
293
|
+
catch (error) {
|
294
|
+
console.error("Failed to fetch user academies:", error);
|
295
|
+
return [];
|
296
|
+
}
|
297
|
+
};
|
298
|
+
exports.listUserAcademies = listUserAcademies;
|
299
|
+
const validateToken = async (token) => {
|
300
|
+
const url = "https://breathecode.herokuapp.com/v1/auth/user/me";
|
301
|
+
const headers = {
|
302
|
+
Authorization: `Token ${token}`,
|
303
|
+
};
|
304
|
+
try {
|
305
|
+
const response = await axios_1.default.get(url, { headers });
|
306
|
+
return response.data;
|
307
|
+
}
|
308
|
+
catch (_a) {
|
309
|
+
return false;
|
310
|
+
}
|
311
|
+
};
|
312
|
+
exports.validateToken = validateToken;
|
277
313
|
exports.default = {
|
278
314
|
login,
|
279
315
|
publish,
|
@@ -283,4 +319,6 @@ exports.default = {
|
|
283
319
|
getAllPackages,
|
284
320
|
sendBatchTelemetry,
|
285
321
|
sendStreamTelemetry,
|
322
|
+
listUserAcademies: exports.listUserAcademies,
|
323
|
+
validateToken: exports.validateToken,
|
286
324
|
};
|
@@ -0,0 +1,44 @@
|
|
1
|
+
type TEstimateReadingTimeReturns = {
|
2
|
+
minutes: number;
|
3
|
+
words: number;
|
4
|
+
};
|
5
|
+
export declare const estimateReadingTime: (text: string, wordsPerMinute?: number) => TEstimateReadingTimeReturns;
|
6
|
+
export type PackageInfo = {
|
7
|
+
grading: string;
|
8
|
+
difficulty: string;
|
9
|
+
duration: number;
|
10
|
+
description: {
|
11
|
+
us: string;
|
12
|
+
};
|
13
|
+
title: {
|
14
|
+
us: string;
|
15
|
+
};
|
16
|
+
};
|
17
|
+
export declare function checkReadingTime(markdown: string, wordsPerMinute?: number): {
|
18
|
+
newMarkdown: string;
|
19
|
+
exceedsThreshold: boolean;
|
20
|
+
};
|
21
|
+
export declare const getExInfo: (title: string) => {
|
22
|
+
exNumber: string;
|
23
|
+
kind: string;
|
24
|
+
description: string;
|
25
|
+
exTitle: string;
|
26
|
+
};
|
27
|
+
export declare function extractImagesFromMarkdown(markdown: string): {
|
28
|
+
alt: string;
|
29
|
+
url: string;
|
30
|
+
}[];
|
31
|
+
export declare function getFilenameFromUrl(url: string): string;
|
32
|
+
export declare const makePackageInfo: (choices: any) => {
|
33
|
+
grading: any;
|
34
|
+
difficulty: any;
|
35
|
+
duration: number;
|
36
|
+
description: {
|
37
|
+
us: any;
|
38
|
+
};
|
39
|
+
title: {
|
40
|
+
us: any;
|
41
|
+
};
|
42
|
+
slug: any;
|
43
|
+
};
|
44
|
+
export {};
|