@learnpack/learnpack 5.0.27 → 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 +27 -11
- package/lib/commands/breakToken.d.ts +10 -0
- package/lib/commands/breakToken.js +23 -0
- package/lib/commands/init.js +78 -44
- package/lib/commands/publish.js +29 -2
- 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/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 +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 +36 -0
- package/src/commands/init.ts +113 -55
- package/src/commands/publish.ts +34 -2
- 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/managers/session.ts +11 -0
- package/src/models/session.ts +1 -0
- package/src/utils/api.ts +60 -12
- package/src/utils/creatorUtilities.ts +101 -7
- package/src/utils/rigoActions.ts +30 -0
@@ -279,9 +279,7 @@ throw new Error("File not found: " + filePath)
|
|
279
279
|
TelemetryManager.registerStepEvent(exercise.position, "open_step", {})
|
280
280
|
}
|
281
281
|
|
282
|
-
if (configObject.config?.editor.agent
|
283
|
-
eventManager.enqueue(dispatcher.events.START_EXERCISE, exercise)
|
284
|
-
} else {
|
282
|
+
if (configObject.config?.editor.agent !== "os") {
|
285
283
|
dispatcher.enqueue(dispatcher.events.START_EXERCISE, req.params.slug)
|
286
284
|
}
|
287
285
|
|
package/src/managers/session.ts
CHANGED
@@ -167,6 +167,17 @@ const Session: ISession = {
|
|
167
167
|
this.token = null
|
168
168
|
Console.success("You have logged out")
|
169
169
|
},
|
170
|
+
breakToken: async function () {
|
171
|
+
const payload = await this.getPayload()
|
172
|
+
if (payload) {
|
173
|
+
this.token = "asdasdasdasd"
|
174
|
+
await storage.setItem("bc-payload", {
|
175
|
+
...payload,
|
176
|
+
token: "asdasdsad",
|
177
|
+
})
|
178
|
+
Console.success("Token broken successfully")
|
179
|
+
}
|
180
|
+
},
|
170
181
|
}
|
171
182
|
|
172
183
|
export default Session
|
package/src/models/session.ts
CHANGED
package/src/utils/api.ts
CHANGED
@@ -79,13 +79,12 @@ const login = async (identification: string, password: string) => {
|
|
79
79
|
await cli.wait(1000)
|
80
80
|
const url = `${HOST}/v1/auth/login/`
|
81
81
|
|
82
|
-
const
|
83
|
-
|
84
|
-
|
85
|
-
password: password,
|
86
|
-
}),
|
87
|
-
method: "post",
|
82
|
+
const res = await axios.post(url, {
|
83
|
+
email: identification,
|
84
|
+
password: password,
|
88
85
|
})
|
86
|
+
const data = res.data
|
87
|
+
|
89
88
|
cli.action.stop("ready")
|
90
89
|
let rigoPayload = null
|
91
90
|
try {
|
@@ -320,7 +319,7 @@ export const countConsumables = (
|
|
320
319
|
return consumable ? consumable.balance.unit : 0
|
321
320
|
}
|
322
321
|
|
323
|
-
export const
|
322
|
+
export const getConsumable = async (
|
324
323
|
token: string,
|
325
324
|
consumableSlug: TConsumableSlug = "ai-generation"
|
326
325
|
): Promise<any> => {
|
@@ -333,18 +332,65 @@ export const getConsumables = async (
|
|
333
332
|
try {
|
334
333
|
const response = await axios.get(url, { headers })
|
335
334
|
|
336
|
-
const
|
337
|
-
response.data,
|
338
|
-
consumableSlug
|
339
|
-
)
|
335
|
+
const count = countConsumables(response.data, consumableSlug)
|
340
336
|
|
341
|
-
return {
|
337
|
+
return { count }
|
342
338
|
} catch (error) {
|
343
339
|
console.error("Error fetching consumables:", error)
|
344
340
|
throw error
|
345
341
|
}
|
346
342
|
}
|
347
343
|
|
344
|
+
export interface TAcademy {
|
345
|
+
id: number
|
346
|
+
name: string
|
347
|
+
slug: string
|
348
|
+
timezone: string
|
349
|
+
}
|
350
|
+
|
351
|
+
export const listUserAcademies = async (
|
352
|
+
breathecodeToken: string
|
353
|
+
): Promise<TAcademy[]> => {
|
354
|
+
const url = "https://breathecode.herokuapp.com/v1/auth/user/me"
|
355
|
+
|
356
|
+
try {
|
357
|
+
const response = await axios.get(url, {
|
358
|
+
headers: {
|
359
|
+
Authorization: `Token ${breathecodeToken}`,
|
360
|
+
},
|
361
|
+
})
|
362
|
+
|
363
|
+
const data = response.data
|
364
|
+
|
365
|
+
const academiesMap = new Map<number, TAcademy>()
|
366
|
+
for (const role of data.roles) {
|
367
|
+
const academy = role.academy
|
368
|
+
if (!academiesMap.has(academy.id)) {
|
369
|
+
academiesMap.set(academy.id, academy)
|
370
|
+
}
|
371
|
+
}
|
372
|
+
|
373
|
+
return [...academiesMap.values()]
|
374
|
+
} catch (error) {
|
375
|
+
console.error("Failed to fetch user academies:", error)
|
376
|
+
return []
|
377
|
+
}
|
378
|
+
}
|
379
|
+
|
380
|
+
export const validateToken = async (token: string) => {
|
381
|
+
const url = "https://breathecode.herokuapp.com/v1/auth/user/me"
|
382
|
+
const headers = {
|
383
|
+
Authorization: `Token ${token}`,
|
384
|
+
}
|
385
|
+
|
386
|
+
try {
|
387
|
+
const response = await axios.get(url, { headers })
|
388
|
+
return response.data
|
389
|
+
} catch {
|
390
|
+
return false
|
391
|
+
}
|
392
|
+
}
|
393
|
+
|
348
394
|
export default {
|
349
395
|
login,
|
350
396
|
publish,
|
@@ -354,4 +400,6 @@ export default {
|
|
354
400
|
getAllPackages,
|
355
401
|
sendBatchTelemetry,
|
356
402
|
sendStreamTelemetry,
|
403
|
+
listUserAcademies,
|
404
|
+
validateToken,
|
357
405
|
}
|
@@ -1,6 +1,11 @@
|
|
1
1
|
// eslint-disable-next-line
|
2
2
|
const frontMatter = require("front-matter")
|
3
3
|
import * as path from "path"
|
4
|
+
import * as fs from "fs"
|
5
|
+
import { homedir } from "os"
|
6
|
+
import { join } from "path"
|
7
|
+
import { exec } from "child_process"
|
8
|
+
import { promisify } from "util"
|
4
9
|
|
5
10
|
import * as yaml from "js-yaml"
|
6
11
|
|
@@ -49,10 +54,18 @@ export type PackageInfo = {
|
|
49
54
|
|
50
55
|
export function checkReadingTime(
|
51
56
|
markdown: string,
|
52
|
-
wordsPerMinute =
|
53
|
-
|
57
|
+
wordsPerMinute = 200,
|
58
|
+
maxMinutes = 1
|
59
|
+
): {
|
60
|
+
newMarkdown: string
|
61
|
+
exceedsThreshold: boolean
|
62
|
+
minutes: number
|
63
|
+
body: string
|
64
|
+
} {
|
54
65
|
const parsed = frontMatter(markdown)
|
66
|
+
|
55
67
|
const readingTime = estimateReadingTime(parsed.body, wordsPerMinute)
|
68
|
+
|
56
69
|
let attributes = parsed.attributes ? parsed.attributes : {}
|
57
70
|
|
58
71
|
if (typeof parsed.attributes !== "object") {
|
@@ -64,15 +77,26 @@ export function checkReadingTime(
|
|
64
77
|
readingTime,
|
65
78
|
}
|
66
79
|
|
67
|
-
|
68
|
-
|
80
|
+
let yamlFrontMatter = ""
|
81
|
+
try {
|
82
|
+
yamlFrontMatter = yaml.dump(updatedAttributes).trim()
|
83
|
+
} catch {
|
84
|
+
return {
|
85
|
+
newMarkdown: "",
|
86
|
+
exceedsThreshold: false,
|
87
|
+
minutes: 0,
|
88
|
+
body: "",
|
89
|
+
}
|
90
|
+
}
|
69
91
|
|
70
92
|
// Reconstruct the markdown with the front matter
|
71
93
|
const newMarkdown = `---\n${yamlFrontMatter}\n---\n\n${parsed.body}`
|
72
94
|
|
73
95
|
return {
|
74
96
|
newMarkdown,
|
75
|
-
exceedsThreshold: readingTime.minutes >
|
97
|
+
exceedsThreshold: readingTime.minutes > maxMinutes,
|
98
|
+
minutes: readingTime.minutes,
|
99
|
+
body: parsed.body,
|
76
100
|
}
|
77
101
|
}
|
78
102
|
|
@@ -130,8 +154,8 @@ export function getFilenameFromUrl(url: string) {
|
|
130
154
|
export const makePackageInfo = (choices: any) => {
|
131
155
|
const packageInfo = {
|
132
156
|
grading: choices.grading,
|
133
|
-
difficulty:
|
134
|
-
duration:
|
157
|
+
difficulty: "beginner",
|
158
|
+
duration: 5,
|
135
159
|
description: {
|
136
160
|
us: choices.description,
|
137
161
|
},
|
@@ -145,3 +169,73 @@ export const makePackageInfo = (choices: any) => {
|
|
145
169
|
}
|
146
170
|
return packageInfo
|
147
171
|
}
|
172
|
+
|
173
|
+
export function estimateDuration(listOfSteps: string[]): number {
|
174
|
+
let duration = 0
|
175
|
+
|
176
|
+
for (const step of listOfSteps) {
|
177
|
+
if (step.includes("[READ:")) {
|
178
|
+
duration += 1
|
179
|
+
} else if (step.includes("[QUIZ:")) {
|
180
|
+
duration += 2
|
181
|
+
} else if (step.includes("[CODE:")) {
|
182
|
+
duration += 3
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
return duration
|
187
|
+
}
|
188
|
+
|
189
|
+
const writeFilePromise = promisify(fs.writeFile)
|
190
|
+
const execPromise = promisify(exec)
|
191
|
+
|
192
|
+
const example_content = `
|
193
|
+
00.1 - Introduction to AI [READ: Small introduction to important concepts such as AI, machine learning, and their applications]
|
194
|
+
01.1 - Introduction to Machine Learning [READ: Small introduction to important concepts such as AI, machine learning, and their applications]
|
195
|
+
01.2 - Introduction to Deep Learning [QUIZ: Small introduction to important concepts such as AI, machine learning, and their applications]
|
196
|
+
02.1 - Test your knowledge [CODE: Code problem to solve]
|
197
|
+
`
|
198
|
+
|
199
|
+
export async function createFileOnDesktop() {
|
200
|
+
try {
|
201
|
+
const desktopPath = join(homedir(), "Desktop")
|
202
|
+
const filePath = join(desktopPath, "content_index.txt")
|
203
|
+
|
204
|
+
const content = example_content.trim()
|
205
|
+
|
206
|
+
await writeFilePromise(filePath, content)
|
207
|
+
console.log(`File created successfully at: ${filePath}`)
|
208
|
+
|
209
|
+
await openFile(filePath)
|
210
|
+
} catch (error) {
|
211
|
+
console.error("Error:", error)
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
async function openFile(filePath: string) {
|
216
|
+
const platform = process.platform
|
217
|
+
let command
|
218
|
+
|
219
|
+
if (platform === "win32") {
|
220
|
+
command = `start "" "${filePath}"`
|
221
|
+
} else if (platform === "darwin") {
|
222
|
+
command = `open "${filePath}"`
|
223
|
+
} else {
|
224
|
+
command = `xdg-open "${filePath}"`
|
225
|
+
}
|
226
|
+
|
227
|
+
try {
|
228
|
+
await execPromise(command)
|
229
|
+
console.log("File opened successfully.")
|
230
|
+
} catch (error) {
|
231
|
+
console.error("Error opening the file:", error)
|
232
|
+
}
|
233
|
+
}
|
234
|
+
|
235
|
+
export function getContentIndex() {
|
236
|
+
const desktopPath = join(homedir(), "Desktop")
|
237
|
+
const filePath = join(desktopPath, "content_index.txt")
|
238
|
+
|
239
|
+
const content = fs.readFileSync(filePath, "utf8")
|
240
|
+
return content
|
241
|
+
}
|
package/src/utils/rigoActions.ts
CHANGED
@@ -293,3 +293,33 @@ export async function createPreviewReadme(
|
|
293
293
|
})
|
294
294
|
fs.writeFileSync(path.join(tutorialDir, readmeFilename), readmeContent.answer)
|
295
295
|
}
|
296
|
+
|
297
|
+
// {"lesson": "The text of the lesson", "number_of_words": "Words lenght of the lesson", "expected_number_words": "The expected number of words"}
|
298
|
+
|
299
|
+
type TReduceReadmeInputs = {
|
300
|
+
lesson: string
|
301
|
+
number_of_words: string
|
302
|
+
expected_number_words: string
|
303
|
+
}
|
304
|
+
export async function reduceReadme(
|
305
|
+
rigoToken: string,
|
306
|
+
inputs: TReduceReadmeInputs
|
307
|
+
) {
|
308
|
+
try {
|
309
|
+
const response = await axios.post(
|
310
|
+
`${RIGOBOT_HOST}/v1/prompting/completion/588/`,
|
311
|
+
{ inputs, include_purpose_objective: false, execute_async: false },
|
312
|
+
{
|
313
|
+
headers: {
|
314
|
+
"Content-Type": "application/json",
|
315
|
+
Authorization: "Token " + rigoToken,
|
316
|
+
},
|
317
|
+
}
|
318
|
+
)
|
319
|
+
|
320
|
+
return response.data
|
321
|
+
} catch (error) {
|
322
|
+
Console.debug(error)
|
323
|
+
return null
|
324
|
+
}
|
325
|
+
}
|