@learnpack/learnpack 2.1.26 → 2.1.28

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. package/README.md +10 -10
  2. package/lib/commands/start.js +15 -4
  3. package/lib/managers/file.d.ts +1 -0
  4. package/lib/managers/file.js +8 -1
  5. package/lib/managers/server/routes.js +48 -14
  6. package/lib/managers/session.d.ts +1 -1
  7. package/lib/managers/session.js +39 -12
  8. package/lib/managers/socket.d.ts +1 -1
  9. package/lib/managers/socket.js +57 -43
  10. package/lib/models/action.d.ts +1 -1
  11. package/lib/models/config.d.ts +1 -1
  12. package/lib/models/exercise-obj.d.ts +3 -0
  13. package/lib/models/session.d.ts +4 -1
  14. package/lib/models/socket.d.ts +7 -6
  15. package/lib/models/status.d.ts +1 -1
  16. package/lib/utils/api.d.ts +2 -0
  17. package/lib/utils/api.js +51 -6
  18. package/oclif.manifest.json +1 -1
  19. package/package.json +3 -1
  20. package/src/commands/audit.ts +113 -113
  21. package/src/commands/clean.ts +10 -10
  22. package/src/commands/download.ts +18 -18
  23. package/src/commands/init.ts +39 -39
  24. package/src/commands/login.ts +13 -13
  25. package/src/commands/logout.ts +9 -9
  26. package/src/commands/publish.ts +25 -25
  27. package/src/commands/start.ts +101 -75
  28. package/src/commands/test.ts +34 -34
  29. package/src/managers/config/allowed_files.ts +2 -2
  30. package/src/managers/config/defaults.ts +2 -2
  31. package/src/managers/config/exercise.ts +79 -79
  32. package/src/managers/config/index.ts +145 -145
  33. package/src/managers/file.ts +74 -65
  34. package/src/managers/server/index.ts +32 -31
  35. package/src/managers/server/routes.ts +139 -90
  36. package/src/managers/session.ts +53 -24
  37. package/src/managers/socket.ts +92 -79
  38. package/src/models/action.ts +8 -1
  39. package/src/models/config-manager.ts +2 -2
  40. package/src/models/config.ts +7 -2
  41. package/src/models/exercise-obj.ts +6 -3
  42. package/src/models/plugin-config.ts +2 -2
  43. package/src/models/session.ts +5 -2
  44. package/src/models/socket.ts +12 -6
  45. package/src/models/status.ts +15 -14
  46. package/src/plugin/command/compile.ts +10 -10
  47. package/src/plugin/command/test.ts +14 -14
  48. package/src/plugin/index.ts +5 -5
  49. package/src/plugin/plugin.ts +26 -26
  50. package/src/plugin/utils.ts +23 -23
  51. package/src/utils/BaseCommand.ts +16 -16
  52. package/src/utils/api.ts +143 -91
  53. package/src/utils/audit.ts +93 -96
  54. package/src/utils/exercisesQueue.ts +15 -15
  55. package/src/utils/fileQueue.ts +85 -85
  56. package/src/utils/watcher.ts +14 -14
@@ -1,5 +1,5 @@
1
- import * as shell from "shelljs";
2
- import { IPluginConfig } from "../models/plugin-config";
1
+ import * as shell from "shelljs"
2
+ import { IPluginConfig } from "../models/plugin-config"
3
3
  /**
4
4
  * Main Plugin Runner, it defines the behavior of a learnpack plugin
5
5
  * dividing it in "actions" like: Compile, test, etc.
@@ -7,88 +7,88 @@ import { IPluginConfig } from "../models/plugin-config";
7
7
  */
8
8
  export default (pluginConfig: IPluginConfig) => {
9
9
  return async (args: any) => {
10
- const { action, exercise, socket, configuration } = args;
10
+ const { action, exercise, socket, configuration } = args
11
11
 
12
12
  if (pluginConfig.language === undefined)
13
- throw new Error(`Missing language on the plugin configuration object`);
13
+ throw new Error(`Missing language on the plugin configuration object`)
14
14
 
15
15
  if (typeof action !== "string") {
16
- throw new TypeError("Missing action property on hook details");
16
+ throw new TypeError("Missing action property on hook details")
17
17
  }
18
18
 
19
19
  if (!exercise || exercise === undefined) {
20
- throw new Error("Missing exercise information");
20
+ throw new Error("Missing exercise information")
21
21
  }
22
22
 
23
23
  type actionType = "compile" | "test";
24
24
 
25
25
  // if the action does not exist I don't do anything
26
26
  if (pluginConfig[action as actionType] === undefined) {
27
- console.log(`Ignoring ${action}`);
28
- return () => null;
27
+ console.log(`Ignoring ${action}`)
28
+ return () => null
29
29
  }
30
30
 
31
31
  // ignore if the plugin language its not the same as the exercise language
32
32
  if (exercise.language !== pluginConfig.language) {
33
- return () => null;
33
+ return () => null
34
34
  }
35
35
 
36
36
  if (!exercise.files || exercise.files.length === 0) {
37
- throw new Error(`No files to process`);
37
+ throw new Error(`No files to process`)
38
38
  }
39
39
 
40
40
  try {
41
- const _action = pluginConfig[action as actionType];
41
+ const _action = pluginConfig[action as actionType]
42
42
 
43
43
  if (_action === null || typeof _action !== "object")
44
44
  throw new Error(
45
45
  `The ${pluginConfig.language} ${action} module must export an object configuration`
46
- );
46
+ )
47
47
  if (_action.validate === undefined)
48
48
  throw new Error(
49
49
  `Missing validate method for ${pluginConfig.language} ${action}`
50
- );
50
+ )
51
51
  if (_action.run === undefined)
52
52
  throw new Error(
53
53
  `Missing run method for ${pluginConfig.language} ${action}`
54
- );
54
+ )
55
55
  if (_action.dependencies !== undefined) {
56
56
  if (!Array.isArray(_action.dependencies))
57
57
  throw new Error(
58
58
  `${action}.dependencies must be an array of package names`
59
- );
59
+ )
60
60
 
61
61
  for (const packageName of _action.dependencies) {
62
62
  if (!shell.which(packageName)) {
63
63
  throw new Error(
64
64
  `🚫 You need to have ${packageName} installed to run test the exercises`
65
- );
65
+ )
66
66
  }
67
67
  }
68
68
  }
69
69
 
70
- const valid = await _action.validate({ exercise, configuration });
70
+ const valid = await _action.validate({ exercise, configuration })
71
71
  if (valid) {
72
72
  // look for the command standard implementation and execute it
73
- const execute = require("./command/" + action + ".js").default;
73
+ const execute = require("./command/" + action + ".js").default
74
74
  // no matter the command, the response must always be a stdout
75
75
  const stdout = await execute({
76
76
  ...args,
77
77
  action: _action,
78
78
  configuration,
79
- });
79
+ })
80
80
 
81
81
  // Map the action names to socket messaging standards
82
- const actionToSuccessMapper = { compile: "compiler", test: "testing" };
82
+ const actionToSuccessMapper = { compile: "compiler", test: "testing" }
83
83
 
84
- socket.success(actionToSuccessMapper[action as actionType], stdout);
85
- return stdout;
84
+ socket.success(actionToSuccessMapper[action as actionType], stdout)
85
+ return stdout
86
86
  }
87
87
  } catch (error: any) {
88
88
  if (error.type === undefined)
89
- socket.fatal(error);
89
+ socket.fatal(error)
90
90
  else
91
- socket.error(error.type, error.stdout);
91
+ socket.error(error.type, error.stdout)
92
92
  }
93
- };
94
- };
93
+ }
94
+ }
@@ -1,74 +1,74 @@
1
- import * as chalk from "chalk";
1
+ import * as chalk from "chalk"
2
2
 
3
3
  const getMatches = (reg: RegExp, content: string) => {
4
- const inputs = [];
5
- let m;
4
+ const inputs = []
5
+ let m
6
6
  while ((m = reg.exec(content)) !== null) {
7
7
  // This is necessary to avoid infinite loops with zero-width matches
8
8
  if (m.index === reg.lastIndex)
9
- reg.lastIndex++;
9
+ reg.lastIndex++
10
10
 
11
11
  // The result can be accessed through the `m`-variable.
12
- inputs.push(m[1] || null);
12
+ inputs.push(m[1] || null)
13
13
  }
14
14
 
15
- return inputs;
16
- };
15
+ return inputs
16
+ }
17
17
 
18
18
  const cleanStdout = (buffer: string, inputs: string[]) => {
19
19
  if (Array.isArray(inputs))
20
20
  for (let i = 0; i < inputs.length; i++)
21
21
  if (inputs[i])
22
- buffer = buffer.replace(inputs[i], "");
22
+ buffer = buffer.replace(inputs[i], "")
23
23
 
24
- return buffer;
25
- };
24
+ return buffer
25
+ }
26
26
 
27
27
  const indent = (string: string, options: any, count = 1) => {
28
28
  options = {
29
29
  indent: " ",
30
30
  includeEmptyLines: false,
31
31
  ...options,
32
- };
32
+ }
33
33
 
34
34
  if (typeof string !== "string") {
35
35
  throw new TypeError(
36
36
  `Expected \`input\` to be a \`string\`, got \`${typeof string}\``
37
- );
37
+ )
38
38
  }
39
39
 
40
40
  if (typeof count !== "number") {
41
41
  throw new TypeError(
42
42
  `Expected \`count\` to be a \`number\`, got \`${typeof count}\``
43
- );
43
+ )
44
44
  }
45
45
 
46
46
  if (count < 0) {
47
47
  throw new RangeError(
48
48
  `Expected \`count\` to be at least 0, got \`${count}\``
49
- );
49
+ )
50
50
  }
51
51
 
52
52
  if (typeof options.indent !== "string") {
53
53
  throw new TypeError(
54
54
  `Expected \`options.indent\` to be a \`string\`, got \`${typeof options.indent}\``
55
- );
55
+ )
56
56
  }
57
57
 
58
58
  if (count === 0) {
59
- return string;
59
+ return string
60
60
  }
61
61
 
62
- const regex = options.includeEmptyLines ? /^/gm : /^(?!\s*$)/gm;
62
+ const regex = options.includeEmptyLines ? /^/gm : /^(?!\s*$)/gm
63
63
 
64
- return string.replace(regex, options.indent.repeat(count));
65
- };
64
+ return string.replace(regex, options.indent.repeat(count))
65
+ }
66
66
 
67
67
  const Console = {
68
68
  // _debug: true,
69
69
  _debug: process.env.DEBUG === "true",
70
70
  startDebug: function () {
71
- this._debug = true;
71
+ this._debug = true
72
72
  },
73
73
  log: (msg: string, ...args: any[]) => console.log(chalk.gray(msg), ...args),
74
74
  error: (msg: string, ...args: any[]) =>
@@ -80,8 +80,8 @@ const Console = {
80
80
  help: (msg: string) =>
81
81
  console.log(`${chalk.white.bold("⚠ help:")} ${chalk.white(msg)}`),
82
82
  debug(...args: any[]) {
83
- this._debug && console.log(chalk.magentaBright(`⚠ debug: `), args);
83
+ this._debug && console.log(chalk.magentaBright(`⚠ debug: `), args)
84
84
  },
85
- };
85
+ }
86
86
 
87
- export default { getMatches, cleanStdout, indent, Console };
87
+ export default { getMatches, cleanStdout, indent, Console }
@@ -1,42 +1,42 @@
1
- import { Command } from "@oclif/command";
2
- import Console from "./console";
3
- import { createInterface } from "readline";
1
+ import { Command } from "@oclif/command"
2
+ import Console from "./console"
3
+ import { createInterface } from "readline"
4
4
  // import SessionManager from '../managers/session'
5
5
 
6
6
  class BaseCommand extends Command {
7
7
  async catch(err: any) {
8
- Console.debug("COMMAND CATCH", err);
8
+ Console.debug("COMMAND CATCH", err)
9
9
 
10
- throw err;
10
+ throw err
11
11
  }
12
12
 
13
13
  async init() {
14
- const { flags, args } = this.parse(BaseCommand);
15
- Console.debug("COMMAND INIT");
16
- Console.debug("These are your flags: ", flags);
17
- Console.debug("These are your args: ", args);
14
+ const { flags, args } = this.parse(BaseCommand)
15
+ Console.debug("COMMAND INIT")
16
+ Console.debug("These are your flags: ", flags)
17
+ Console.debug("These are your args: ", args)
18
18
 
19
19
  // quick fix for listening to the process termination on windows
20
20
  if (process.platform === "win32") {
21
21
  const rl = createInterface({
22
22
  input: process.stdin,
23
23
  output: process.stdout,
24
- });
24
+ })
25
25
 
26
26
  rl.on("SIGINT", function () {
27
27
  // process.emit('SIGINT')
28
28
  // process.emit('SIGINT')
29
- });
29
+ })
30
30
  }
31
31
 
32
32
  process.on("SIGINT", function () {
33
- Console.debug("Terminated (SIGINT)");
34
- process.exit();
35
- });
33
+ Console.debug("Terminated (SIGINT)")
34
+ process.exit()
35
+ })
36
36
  }
37
37
 
38
38
  async finally() {
39
- Console.debug("COMMAND FINALLY");
39
+ Console.debug("COMMAND FINALLY")
40
40
  // called after run and catch regardless of whether or not the command errored
41
41
  }
42
42
 
@@ -45,4 +45,4 @@ class BaseCommand extends Command {
45
45
  }
46
46
  }
47
47
 
48
- export default BaseCommand;
48
+ export default BaseCommand
package/src/utils/api.ts CHANGED
@@ -1,7 +1,8 @@
1
- import Console from "../utils/console";
2
- import * as storage from "node-persist";
3
- import cli from "cli-ux";
4
- const HOST = "https://learnpack.herokuapp.com";
1
+ import Console from "../utils/console"
2
+ import * as storage from "node-persist"
3
+ import cli from "cli-ux"
4
+ const HOST = "https://breathecode.herokuapp.com"
5
+ const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
5
6
 
6
7
  // eslint-disable-next-line
7
8
  const _fetch = require("node-fetch");
@@ -18,65 +19,107 @@ interface IOptions {
18
19
  }
19
20
 
20
21
  const fetch = async (url: string, options: IOptions = {}) => {
21
- const headers: IHeaders = { "Content-Type": "application/json" };
22
- let session = null;
22
+ const headers: IHeaders = { "Content-Type": "application/json" }
23
+ Console.log(`Fetching ${url}`)
24
+ let session = null
23
25
  try {
24
- session = await storage.getItem("bc-payload");
26
+ session = await storage.getItem("bc-payload")
25
27
  if (session.token && session.token !== "" && !url.includes("/token"))
26
- headers.Authorization = "Token " + session.token;
28
+ headers.Authorization = "Token " + session.token
27
29
  } catch {}
28
30
 
29
31
  try {
30
32
  const resp = await _fetch(url, {
31
33
  ...options,
32
34
  headers: { ...headers, ...options.headers },
33
- } as any);
35
+ } as any)
34
36
 
35
37
  if (resp.status >= 200 && resp.status < 300)
36
- return await resp.json();
38
+ return await resp.json()
37
39
  if (resp.status === 401)
38
- throw APIError("Invalid authentication credentials", 401);
40
+ throw APIError("Invalid authentication credentials", 401)
39
41
  else if (resp.status === 404)
40
- throw APIError("Package not found", 404);
42
+ throw APIError("Package not found", 404)
41
43
  else if (resp.status >= 500)
42
- throw APIError("Impossible to connect with the server", 500);
44
+ throw APIError("Impossible to connect with the server", 500)
43
45
  else if (resp.status >= 400) {
44
- const error = await resp.json();
46
+ const error = await resp.json()
45
47
  if (error.detail || error.error) {
46
- throw APIError(error.detail || error.error);
48
+ throw APIError(error.detail || error.error)
47
49
  } else if (error.nonFieldErrors) {
48
- throw APIError(error.nonFieldErrors[0], error);
50
+ throw APIError(error.nonFieldErrors[0], error)
49
51
  } else if (typeof error === "object") {
50
52
  if (Object.keys(error).length > 0) {
51
- const key = error[Object.keys(error)[0]];
52
- throw APIError(`${key}: ${error[key][0]}`, error);
53
+ const key = error[Object.keys(error)[0]]
54
+ throw APIError(`${key}: ${error[key][0]}`, error)
53
55
  }
54
56
  } else {
55
- throw APIError("Uknown error");
57
+ throw APIError("Uknown error")
56
58
  }
57
59
  } else
58
- throw APIError("Uknown error");
60
+ throw APIError("Uknown error")
59
61
  } catch (error) {
60
- Console.error((error as TypeError).message);
61
- throw error;
62
+ Console.error((error as TypeError).message)
63
+ throw error
62
64
  }
63
- };
65
+ }
64
66
 
65
67
  const login = async (identification: string, password: string) => {
66
68
  try {
67
- cli.action.start("Looking for credentials...");
68
- await cli.wait(1000);
69
- const data = await fetch(`${HOST}/v1/auth/token/`, {
70
- body: JSON.stringify({ identification, password }),
69
+ cli.action.start(`Looking for credentials with ${identification}`)
70
+ await cli.wait(1000)
71
+ const url = `${HOST}/v1/auth/login/`
72
+ // Console.log(url);
73
+ const data = await fetch(url, {
74
+ body: JSON.stringify({
75
+ email: identification,
76
+ password: password,
77
+ }),
71
78
  method: "post",
72
- });
73
- cli.action.stop("ready");
74
- return data;
79
+ })
80
+ cli.action.stop("ready")
81
+ const payload = await loginRigo(data.token)
82
+
83
+ return { ...data, rigobot: payload }
75
84
  } catch (error) {
76
- Console.error((error as TypeError).message);
77
- Console.debug(error);
85
+ cli.action.stop("error")
86
+ Console.error((error as TypeError).message)
87
+ Console.debug(error)
88
+ }
89
+ }
90
+
91
+ const loginRigo = async (token: string) => {
92
+ const rigoUrl = `${RIGOBOT_HOST}/v1/auth/me/token?breathecode_token=${token}`
93
+ const rigoResp = await _fetch(rigoUrl)
94
+ const rigobotJson = await rigoResp.json()
95
+ return rigobotJson
96
+ }
97
+
98
+ const getOpenAIToken = async () => {
99
+ const token = await storage.getItem("openai-token")
100
+ return token
101
+ }
102
+
103
+ const getRigoFeedback = async (readme: string, currentCode: string) => {
104
+ const payload = {
105
+ current_code: Buffer.from(currentCode).toString("base64"), // Encode currentCode as base64
106
+ tutorial: Buffer.from(readme).toString("base64"), // Encode readme as base64
78
107
  }
79
- };
108
+
109
+ const session = await storage.getItem("bc-payload")
110
+
111
+ const response = await _fetch(`${RIGOBOT_HOST}/v1/conversation/feedback/`, {
112
+ method: "POST",
113
+ headers: {
114
+ "Content-Type": "application/json",
115
+ Authorization: `Token ${session.rigobot.key}`,
116
+ },
117
+ body: JSON.stringify(payload),
118
+ })
119
+
120
+ const responseData = await response.json()
121
+ return responseData.feedback
122
+ }
80
123
 
81
124
  const publish = async (config: any) => {
82
125
  const keys = [
@@ -88,79 +131,79 @@ const publish = async (config: any) => {
88
131
  "repository",
89
132
  "author",
90
133
  "title",
91
- ];
134
+ ]
92
135
 
93
- const payload: { [key: string]: string } = {};
136
+ const payload: { [key: string]: string } = {}
94
137
  for (const k of keys)
95
- config[k] ? (payload[k] = config[k]) : null;
138
+ config[k] ? (payload[k] = config[k]) : null
96
139
  try {
97
- console.log("Package to publish:", payload);
98
- cli.action.start("Updating package information...");
99
- await cli.wait(1000);
140
+ console.log("Package to publish:", payload)
141
+ cli.action.start("Updating package information...")
142
+ await cli.wait(1000)
100
143
  const data = await fetch(`${HOST}/v1/package/${config.slug}`, {
101
144
  method: "PUT",
102
145
  body: JSON.stringify(payload),
103
- });
104
- cli.action.stop("ready");
105
- return data;
146
+ })
147
+ cli.action.stop("ready")
148
+ return data
106
149
  } catch (error) {
107
- console.log("payload", payload);
108
- Console.error((error as TypeError).message);
109
- Console.debug(error);
110
- throw error;
150
+ console.log("payload", payload)
151
+ Console.error((error as TypeError).message)
152
+ Console.debug(error)
153
+ throw error
111
154
  }
112
- };
155
+ }
113
156
 
114
157
  const update = async (config: any) => {
115
158
  try {
116
- cli.action.start("Updating package information...");
117
- await cli.wait(1000);
159
+ cli.action.start("Updating package information...")
160
+ await cli.wait(1000)
118
161
  const data = await fetch(`${HOST}/v1/package/`, {
119
162
  method: "POST",
120
163
  body: JSON.stringify(config),
121
- });
122
- cli.action.stop("ready");
123
- return data;
164
+ })
165
+ cli.action.stop("ready")
166
+ return data
124
167
  } catch (error) {
125
- Console.error((error as any).message);
126
- Console.debug(error);
127
- throw error;
168
+ Console.error((error as any).message)
169
+ Console.debug(error)
170
+ throw error
128
171
  }
129
- };
172
+ }
130
173
 
131
174
  const getPackage = async (slug: string) => {
132
175
  try {
133
- cli.action.start("Downloading package information...");
134
- await cli.wait(1000);
135
- const data = await fetch(`${HOST}/v1/package/${slug}`);
136
- cli.action.stop("ready");
137
- return data;
176
+ cli.action.start("Downloading package information...")
177
+ await cli.wait(1000)
178
+ const data = await fetch(`${HOST}/v1/package/${slug}`)
179
+ cli.action.stop("ready")
180
+ return data
138
181
  } catch (error) {
139
182
  if ((error as any).status === 404)
140
- Console.error(`Package ${slug} does not exist`);
183
+ Console.error(`Package ${slug} does not exist`)
141
184
  else
142
- Console.error(`Package ${slug} does not exist`);
143
- Console.debug(error);
144
- throw error;
185
+ Console.error(`Package ${slug} does not exist`)
186
+ Console.debug(error)
187
+ throw error
145
188
  }
146
- };
189
+ }
147
190
 
148
191
  const getLangs = async () => {
149
192
  try {
150
- cli.action.start("Downloading language options...");
151
- await cli.wait(1000);
152
- const data = await fetch(`${HOST}/v1/package/language`);
153
- cli.action.stop("ready");
154
- return data;
193
+ cli.action.start("Downloading language options...")
194
+ await cli.wait(1000)
195
+ const data = await fetch(`${HOST}/v1/package/language`)
196
+ cli.action.stop("ready")
197
+ return data
155
198
  } catch (error) {
156
199
  if ((error as any).status === 404)
157
- Console.error("Package slug does not exist");
200
+ Console.error("Package slug does not exist")
158
201
  else
159
- Console.error("Package slug does not exist");
160
- Console.debug(error);
161
- throw error;
202
+ Console.error("Package slug does not exist")
203
+ Console.debug(error)
204
+ throw error
162
205
  }
163
- };
206
+ }
164
207
 
165
208
  const getAllPackages = async ({
166
209
  lang = "",
@@ -170,25 +213,34 @@ const getAllPackages = async ({
170
213
  slug?: string;
171
214
  }) => {
172
215
  try {
173
- cli.action.start("Downloading packages...");
174
- await cli.wait(1000);
216
+ cli.action.start("Downloading packages...")
217
+ await cli.wait(1000)
175
218
  const data = await fetch(
176
219
  `${HOST}/v1/package/all?limit=100&language=${lang}&slug=${slug}`
177
- );
178
- cli.action.stop("ready");
179
- return data;
220
+ )
221
+ cli.action.stop("ready")
222
+ return data
180
223
  } catch (error) {
181
- Console.error(`Package ${slug} does not exist`);
182
- Console.debug(error);
183
- throw error;
224
+ Console.error(`Package ${slug} does not exist`)
225
+ Console.debug(error)
226
+ throw error
184
227
  }
185
- };
228
+ }
186
229
 
187
230
  const APIError = (error: TypeError | string, code?: number) => {
188
- const message: string = (error as TypeError).message || (error as string);
189
- const _err = new Error(message) as any;
190
- _err.status = code || 400;
191
- return _err;
192
- };
231
+ const message: string = (error as TypeError).message || (error as string)
232
+ const _err = new Error(message) as any
233
+ _err.status = code || 400
234
+ return _err
235
+ }
193
236
 
194
- export default { login, publish, update, getPackage, getLangs, getAllPackages };
237
+ export default {
238
+ login,
239
+ publish,
240
+ update,
241
+ getPackage,
242
+ getLangs,
243
+ getAllPackages,
244
+ getRigoFeedback,
245
+ getOpenAIToken,
246
+ }