lua-cli 1.0.0 → 1.1.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,65 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.1.0] - 2024-01-XX
9
+
10
+ ### Added
11
+ - **Email Authentication**: New email-based OTP authentication method in `lua configure`
12
+ - **API Key Display**: New `lua apiKey` command to view stored API key
13
+ - **Modular Architecture**: Complete codebase refactoring into organized modules
14
+ - **TypeScript Types**: Comprehensive type definitions for all API responses
15
+ - **Command Structure**: Individual command files for better maintainability
16
+
17
+ ### Changed
18
+ - **Project Structure**: Reorganized codebase into logical directories:
19
+ - `src/commands/` - Individual command implementations
20
+ - `src/services/` - API and authentication services
21
+ - `src/types/` - TypeScript interface definitions
22
+ - `src/utils/` - Utility functions
23
+ - **Main File**: Reduced `src/index.ts` from 392 lines to 39 lines
24
+ - **Authentication Flow**: Enhanced `lua configure` with dual authentication methods
25
+ - **Error Handling**: Improved error messages and validation throughout
26
+
27
+ ### Technical Improvements
28
+ - **Code Organization**: Separated concerns for better maintainability
29
+ - **Type Safety**: Added proper TypeScript interfaces for all API responses
30
+ - **Reusability**: Services can now be shared across multiple commands
31
+ - **Scalability**: Easy to add new commands without cluttering main file
32
+ - **Testing Ready**: Modular structure enables independent testing
33
+
34
+ ### Security
35
+ - **OTP Verification**: Secure email-based authentication with 6-digit codes
36
+ - **Token Management**: Proper handling of sign-in tokens and API key generation
37
+ - **Confirmation Prompts**: Added safety confirmations for sensitive operations
38
+
39
+ ## [1.0.0] - 2024-01-XX
40
+
41
+ ### Added
42
+ - **Initial Release**: First version of Lua CLI
43
+ - **API Key Authentication**: Direct API key input and validation
44
+ - **Project Initialization**: `lua init` command for creating new skill projects
45
+ - **Agent Management**: `lua agents` command to fetch and display agents
46
+ - **Credential Management**: `lua destroy` command to delete stored API keys
47
+ - **Template System**: Automatic template file copying for new projects
48
+ - **Secure Storage**: API keys stored using system credential manager
49
+ - **Interactive Prompts**: User-friendly command-line interface with inquirer
50
+ - **Organization Selection**: Choose from available organizations
51
+ - **Agent Selection**: Select agents within chosen organizations
52
+ - **TOML Configuration**: Generate `lua.skill.toml` configuration files
53
+
54
+ ### Features
55
+ - **Cross-platform**: Works on Windows, macOS, and Linux
56
+ - **Secure**: Uses keytar for secure credential storage
57
+ - **User-friendly**: Interactive prompts and clear error messages
58
+ - **Template-based**: Quick project setup with pre-configured templates
59
+ - **Validation**: Input validation for email addresses and OTP codes
60
+
61
+ ### Technical Details
62
+ - **Node.js**: Requires Node.js 16.0.0 or higher
63
+ - **TypeScript**: Built with TypeScript for type safety
64
+ - **Dependencies**: Uses commander, inquirer, keytar, and node-fetch
65
+ - **ES Modules**: Modern ES module syntax throughout
package/README.md CHANGED
@@ -168,9 +168,16 @@ For support and questions:
168
168
 
169
169
  ## Changelog
170
170
 
171
+ ### 1.1.0
172
+ - **Major Refactoring**: Complete codebase reorganization into modular structure
173
+ - **Email Authentication**: Added OTP-based email authentication
174
+ - **API Key Display**: New `lua apiKey` command
175
+ - **TypeScript Types**: Comprehensive type definitions
176
+ - **Improved Architecture**: Separated commands, services, and utilities
177
+
171
178
  ### 1.0.0
172
179
  - Initial release
173
- - API key and email authentication
180
+ - API key authentication
174
181
  - Organization and agent management
175
182
  - Skill project initialization
176
183
  - Secure credential storage
@@ -0,0 +1,20 @@
1
+ import fetch from "node-fetch";
2
+ import { loadApiKey } from "../services/auth.js";
3
+ export async function agentsCommand() {
4
+ const apiKey = await loadApiKey();
5
+ if (!apiKey) {
6
+ console.error("❌ No API key found. Run `lua configure` first.");
7
+ process.exit(1);
8
+ }
9
+ const response = await fetch("https://api.heylua.ai/admin", {
10
+ headers: {
11
+ Authorization: `Bearer ${apiKey}`,
12
+ },
13
+ });
14
+ if (!response.ok) {
15
+ console.error(`❌ Error ${response.status}: ${await response.text()}`);
16
+ process.exit(1);
17
+ }
18
+ const data = await response.json();
19
+ console.log("✅ Agents:", JSON.stringify(data, null, 2));
20
+ }
@@ -0,0 +1,24 @@
1
+ import inquirer from "inquirer";
2
+ import { loadApiKey } from "../services/auth.js";
3
+ export async function apiKeyCommand() {
4
+ const apiKey = await loadApiKey();
5
+ if (!apiKey) {
6
+ console.log("ℹ️ No API key found. Run `lua configure` first.");
7
+ return;
8
+ }
9
+ const { confirm } = await inquirer.prompt([
10
+ {
11
+ type: "confirm",
12
+ name: "confirm",
13
+ message: "This will display your API key. Are you sure you want to continue?",
14
+ default: false
15
+ }
16
+ ]);
17
+ if (confirm) {
18
+ console.log("🔑 Your API key:");
19
+ console.log(apiKey);
20
+ }
21
+ else {
22
+ console.log("ℹ️ API key display cancelled.");
23
+ }
24
+ }
@@ -0,0 +1,80 @@
1
+ import inquirer from "inquirer";
2
+ import { saveApiKey, checkApiKey, requestEmailOTP, verifyOTPAndGetToken, generateApiKey } from "../services/auth.js";
3
+ export async function configureCommand() {
4
+ // Choose authentication method
5
+ const { authMethod } = await inquirer.prompt([
6
+ {
7
+ type: "list",
8
+ name: "authMethod",
9
+ message: "Choose authentication method:",
10
+ choices: [
11
+ { name: "API Key", value: "api-key" },
12
+ { name: "Email", value: "email" }
13
+ ]
14
+ }
15
+ ]);
16
+ if (authMethod === "api-key") {
17
+ // Existing API key flow
18
+ const answers = await inquirer.prompt([
19
+ {
20
+ type: "password",
21
+ name: "apiKey",
22
+ message: "Enter your API key",
23
+ mask: "*",
24
+ },
25
+ ]);
26
+ const data = await checkApiKey(answers.apiKey);
27
+ if (!data) {
28
+ console.error("❌ Invalid API key");
29
+ process.exit(1);
30
+ }
31
+ await saveApiKey(answers.apiKey);
32
+ console.log("✅ API key saved securely.");
33
+ }
34
+ else if (authMethod === "email") {
35
+ // Email authentication flow
36
+ const { email } = await inquirer.prompt([
37
+ {
38
+ type: "input",
39
+ name: "email",
40
+ message: "Enter your email address:",
41
+ validate: (input) => {
42
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
43
+ return emailRegex.test(input) || "Please enter a valid email address";
44
+ }
45
+ }
46
+ ]);
47
+ console.log("📧 Sending OTP to your email...");
48
+ const otpSent = await requestEmailOTP(email);
49
+ if (!otpSent) {
50
+ console.error("❌ Failed to send OTP. Please try again.");
51
+ process.exit(1);
52
+ }
53
+ console.log("✅ OTP sent successfully!");
54
+ const { pin } = await inquirer.prompt([
55
+ {
56
+ type: "input",
57
+ name: "pin",
58
+ message: "Enter the OTP code:",
59
+ validate: (input) => {
60
+ return input.length === 6 || "OTP must be 6 digits";
61
+ }
62
+ }
63
+ ]);
64
+ console.log("🔐 Verifying OTP...");
65
+ const signInToken = await verifyOTPAndGetToken(email, pin);
66
+ if (!signInToken) {
67
+ console.error("❌ Invalid OTP. Please try again.");
68
+ process.exit(1);
69
+ }
70
+ console.log("✅ OTP verified successfully!");
71
+ console.log("🔑 Generating API key...");
72
+ const apiKey = await generateApiKey(signInToken);
73
+ if (!apiKey) {
74
+ console.error("❌ Failed to generate API key. Please try again.");
75
+ process.exit(1);
76
+ }
77
+ await saveApiKey(apiKey);
78
+ console.log("✅ API key generated and saved securely.");
79
+ }
80
+ }
@@ -0,0 +1,29 @@
1
+ import inquirer from "inquirer";
2
+ import { loadApiKey, deleteApiKey } from "../services/auth.js";
3
+ export async function destroyCommand() {
4
+ const apiKey = await loadApiKey();
5
+ if (!apiKey) {
6
+ console.log("ℹ️ No API key found to delete.");
7
+ return;
8
+ }
9
+ const { confirm } = await inquirer.prompt([
10
+ {
11
+ type: "confirm",
12
+ name: "confirm",
13
+ message: "Are you sure you want to delete your API key? This action cannot be undone.",
14
+ default: false
15
+ }
16
+ ]);
17
+ if (confirm) {
18
+ const deleted = await deleteApiKey();
19
+ if (deleted) {
20
+ console.log("✅ API key deleted successfully.");
21
+ }
22
+ else {
23
+ console.log("❌ Failed to delete API key.");
24
+ }
25
+ }
26
+ else {
27
+ console.log("ℹ️ API key deletion cancelled.");
28
+ }
29
+ }
@@ -0,0 +1,5 @@
1
+ export { configureCommand } from "./configure.js";
2
+ export { initCommand } from "./init.js";
3
+ export { destroyCommand } from "./destroy.js";
4
+ export { apiKeyCommand } from "./apiKey.js";
5
+ export { agentsCommand } from "./agents.js";
@@ -0,0 +1,69 @@
1
+ import inquirer from "inquirer";
2
+ import { fileURLToPath } from "url";
3
+ import path from "path";
4
+ import { loadApiKey, checkApiKey } from "../services/auth.js";
5
+ import { copyTemplateFiles, createSkillToml } from "../utils/files.js";
6
+ export async function initCommand() {
7
+ const apiKey = await loadApiKey();
8
+ if (!apiKey) {
9
+ console.error("❌ No API key found. Run `lua configure` first.");
10
+ process.exit(1);
11
+ }
12
+ // Get user data from API
13
+ const userData = await checkApiKey(apiKey);
14
+ // Extract organizations and create choices for selection
15
+ const orgs = userData.admin.orgs;
16
+ const orgChoices = orgs.map((org) => ({
17
+ name: org.registeredName,
18
+ value: org
19
+ }));
20
+ // Select organization
21
+ const { selectedOrg } = await inquirer.prompt([
22
+ {
23
+ type: "list",
24
+ name: "selectedOrg",
25
+ message: "Select an organization:",
26
+ choices: orgChoices
27
+ }
28
+ ]);
29
+ // Extract agents from selected organization
30
+ const agentChoices = selectedOrg.agents.map((agent) => ({
31
+ name: agent.name,
32
+ value: agent
33
+ }));
34
+ // Select agent
35
+ const { selectedAgent } = await inquirer.prompt([
36
+ {
37
+ type: "list",
38
+ name: "selectedAgent",
39
+ message: "Select an agent:",
40
+ choices: agentChoices
41
+ }
42
+ ]);
43
+ // Get skill details
44
+ const { skillName, skillDescription } = await inquirer.prompt([
45
+ {
46
+ type: "input",
47
+ name: "skillName",
48
+ message: "Enter a name for your skill:",
49
+ default: "My Lua Skill"
50
+ },
51
+ {
52
+ type: "input",
53
+ name: "skillDescription",
54
+ message: "Describe your skill:",
55
+ default: "A Lua skill for automation"
56
+ }
57
+ ]);
58
+ // Create lua.skill.toml file
59
+ createSkillToml(selectedAgent.agentId, selectedOrg.id, skillName, skillDescription);
60
+ console.log("✅ Created lua.skill.toml");
61
+ // Copy template files
62
+ const __filename = fileURLToPath(import.meta.url);
63
+ const __dirname = path.dirname(__filename);
64
+ const templateDir = path.join(__dirname, "..", "..", "template");
65
+ const currentDir = process.cwd();
66
+ copyTemplateFiles(templateDir, currentDir);
67
+ console.log("✅ Copied template files");
68
+ console.log("🎉 Lua skill project initialized successfully!");
69
+ }
package/dist/index.js CHANGED
@@ -1,348 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from "commander";
3
- import inquirer from "inquirer";
4
- import keytar from "keytar";
5
- import fetch from "node-fetch";
6
- import fs from "fs";
7
- import path from "path";
8
- import { fileURLToPath } from "url";
3
+ import { configureCommand, initCommand, destroyCommand, apiKeyCommand, agentsCommand } from "./commands/index.js";
9
4
  const program = new Command();
10
- const SERVICE = "lua-cli";
11
- const ACCOUNT = "api-key";
12
- async function saveApiKey(apiKey) {
13
- await keytar.setPassword(SERVICE, ACCOUNT, apiKey);
14
- }
15
- async function loadApiKey() {
16
- return keytar.getPassword(SERVICE, ACCOUNT);
17
- }
18
- async function deleteApiKey() {
19
- return keytar.deletePassword(SERVICE, ACCOUNT);
20
- }
21
- async function requestEmailOTP(email) {
22
- try {
23
- const response = await fetch("https://auth.heylua.ai/otp", {
24
- method: "POST",
25
- headers: {
26
- "accept": "application/json",
27
- "Content-Type": "application/json"
28
- },
29
- body: JSON.stringify({
30
- type: "email",
31
- email: email
32
- })
33
- });
34
- return response.ok;
35
- }
36
- catch (error) {
37
- console.error("❌ Error requesting OTP:", error);
38
- return false;
39
- }
40
- }
41
- async function verifyOTPAndGetToken(email, pin) {
42
- try {
43
- const response = await fetch("https://auth.heylua.ai/otp/verify", {
44
- method: "POST",
45
- headers: {
46
- "accept": "application/json",
47
- "Content-Type": "application/json"
48
- },
49
- body: JSON.stringify({
50
- pin: pin,
51
- type: "email",
52
- email: email
53
- })
54
- });
55
- if (!response.ok) {
56
- return null;
57
- }
58
- const data = await response.json();
59
- return data.signInToken;
60
- }
61
- catch (error) {
62
- console.error("❌ Error verifying OTP:", error);
63
- return null;
64
- }
65
- }
66
- async function generateApiKey(signInToken) {
67
- try {
68
- const response = await fetch("https://auth.heylua.ai/profile/apiKey", {
69
- method: "POST",
70
- headers: {
71
- "Authorization": `Bearer ${signInToken}`,
72
- "Content-Type": "application/json"
73
- },
74
- body: ""
75
- });
76
- if (!response.ok) {
77
- return null;
78
- }
79
- const data = await response.json();
80
- return data.apiKey;
81
- }
82
- catch (error) {
83
- console.error("❌ Error generating API key:", error);
84
- return null;
85
- }
86
- }
87
- async function checkApiKey(apiKey) {
88
- const response = await fetch("https://api.heylua.ai/admin", {
89
- headers: {
90
- Authorization: `Bearer ${apiKey}`,
91
- },
92
- });
93
- if (!response.ok) {
94
- console.error(`❌ Invalid API key`);
95
- process.exit(1);
96
- }
97
- return await response.json();
98
- }
99
- function copyTemplateFiles(templateDir, targetDir) {
100
- const files = fs.readdirSync(templateDir);
101
- for (const file of files) {
102
- const srcPath = path.join(templateDir, file);
103
- const destPath = path.join(targetDir, file);
104
- if (fs.statSync(srcPath).isDirectory()) {
105
- fs.mkdirSync(destPath, { recursive: true });
106
- copyTemplateFiles(srcPath, destPath);
107
- }
108
- else {
109
- fs.copyFileSync(srcPath, destPath);
110
- }
111
- }
112
- }
113
- function createSkillToml(agentId, orgId, skillName, skillDescription) {
114
- const tomlContent = `[agent]
115
- agentId = "${agentId}"
116
- orgId = "${orgId}"
117
-
118
- [skill]
119
- name = "${skillName}"
120
- description = "${skillDescription}"
121
- `;
122
- fs.writeFileSync("lua.skill.toml", tomlContent);
123
- }
124
5
  program
125
6
  .command("init")
126
7
  .description("Initialize a new Lua skill project")
127
- .action(async () => {
128
- const apiKey = await loadApiKey();
129
- if (!apiKey) {
130
- console.error("❌ No API key found. Run `lua configure` first.");
131
- process.exit(1);
132
- }
133
- // Get user data from API
134
- const userData = await checkApiKey(apiKey);
135
- // Extract organizations and create choices for selection
136
- const orgs = userData.admin.orgs;
137
- const orgChoices = orgs.map((org) => ({
138
- name: org.registeredName,
139
- value: org
140
- }));
141
- // Select organization
142
- const { selectedOrg } = await inquirer.prompt([
143
- {
144
- type: "list",
145
- name: "selectedOrg",
146
- message: "Select an organization:",
147
- choices: orgChoices
148
- }
149
- ]);
150
- // Extract agents from selected organization
151
- const agentChoices = selectedOrg.agents.map((agent) => ({
152
- name: agent.name,
153
- value: agent
154
- }));
155
- // Select agent
156
- const { selectedAgent } = await inquirer.prompt([
157
- {
158
- type: "list",
159
- name: "selectedAgent",
160
- message: "Select an agent:",
161
- choices: agentChoices
162
- }
163
- ]);
164
- // Get skill details
165
- const { skillName, skillDescription } = await inquirer.prompt([
166
- {
167
- type: "input",
168
- name: "skillName",
169
- message: "Enter a name for your skill:",
170
- default: "My Lua Skill"
171
- },
172
- {
173
- type: "input",
174
- name: "skillDescription",
175
- message: "Describe your skill:",
176
- default: "A Lua skill for automation"
177
- }
178
- ]);
179
- // Create lua.skill.toml file
180
- createSkillToml(selectedAgent.agentId, selectedOrg.id, skillName, skillDescription);
181
- console.log("✅ Created lua.skill.toml");
182
- // Copy template files
183
- const __filename = fileURLToPath(import.meta.url);
184
- const __dirname = path.dirname(__filename);
185
- const templateDir = path.join(__dirname, "..", "template");
186
- const currentDir = process.cwd();
187
- copyTemplateFiles(templateDir, currentDir);
188
- console.log("✅ Copied template files");
189
- console.log("🎉 Lua skill project initialized successfully!");
190
- });
8
+ .action(initCommand);
191
9
  program
192
10
  .command("destroy")
193
11
  .description("Delete your stored API key")
194
- .action(async () => {
195
- const apiKey = await loadApiKey();
196
- if (!apiKey) {
197
- console.log("ℹ️ No API key found to delete.");
198
- return;
199
- }
200
- const { confirm } = await inquirer.prompt([
201
- {
202
- type: "confirm",
203
- name: "confirm",
204
- message: "Are you sure you want to delete your API key? This action cannot be undone.",
205
- default: false
206
- }
207
- ]);
208
- if (confirm) {
209
- const deleted = await deleteApiKey();
210
- if (deleted) {
211
- console.log("✅ API key deleted successfully.");
212
- }
213
- else {
214
- console.log("❌ Failed to delete API key.");
215
- }
216
- }
217
- else {
218
- console.log("ℹ️ API key deletion cancelled.");
219
- }
220
- });
12
+ .action(destroyCommand);
221
13
  program
222
14
  .command("configure")
223
15
  .description("Set up your API key")
224
- .action(async () => {
225
- // Choose authentication method
226
- const { authMethod } = await inquirer.prompt([
227
- {
228
- type: "list",
229
- name: "authMethod",
230
- message: "Choose authentication method:",
231
- choices: [
232
- { name: "API Key", value: "api-key" },
233
- { name: "Email", value: "email" }
234
- ]
235
- }
236
- ]);
237
- if (authMethod === "api-key") {
238
- // Existing API key flow
239
- const answers = await inquirer.prompt([
240
- {
241
- type: "password",
242
- name: "apiKey",
243
- message: "Enter your API key",
244
- mask: "*",
245
- },
246
- ]);
247
- const data = await checkApiKey(answers.apiKey);
248
- if (!data) {
249
- console.error("❌ Invalid API key");
250
- process.exit(1);
251
- }
252
- await saveApiKey(answers.apiKey);
253
- console.log("✅ API key saved securely.");
254
- }
255
- else if (authMethod === "email") {
256
- // Email authentication flow
257
- const { email } = await inquirer.prompt([
258
- {
259
- type: "input",
260
- name: "email",
261
- message: "Enter your email address:",
262
- validate: (input) => {
263
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
264
- return emailRegex.test(input) || "Please enter a valid email address";
265
- }
266
- }
267
- ]);
268
- console.log("📧 Sending OTP to your email...");
269
- const otpSent = await requestEmailOTP(email);
270
- if (!otpSent) {
271
- console.error("❌ Failed to send OTP. Please try again.");
272
- process.exit(1);
273
- }
274
- console.log("✅ OTP sent successfully!");
275
- const { pin } = await inquirer.prompt([
276
- {
277
- type: "input",
278
- name: "pin",
279
- message: "Enter the OTP code:",
280
- validate: (input) => {
281
- return input.length === 6 || "OTP must be 6 digits";
282
- }
283
- }
284
- ]);
285
- console.log("🔐 Verifying OTP...");
286
- const signInToken = await verifyOTPAndGetToken(email, pin);
287
- if (!signInToken) {
288
- console.error("❌ Invalid OTP. Please try again.");
289
- process.exit(1);
290
- }
291
- console.log("✅ OTP verified successfully!");
292
- console.log("🔑 Generating API key...");
293
- const apiKey = await generateApiKey(signInToken);
294
- if (!apiKey) {
295
- console.error("❌ Failed to generate API key. Please try again.");
296
- process.exit(1);
297
- }
298
- await saveApiKey(apiKey);
299
- console.log("✅ API key generated and saved securely.");
300
- }
301
- });
16
+ .action(configureCommand);
302
17
  program
303
18
  .command("apiKey")
304
19
  .description("Display your stored API key")
305
- .action(async () => {
306
- const apiKey = await loadApiKey();
307
- if (!apiKey) {
308
- console.log("ℹ️ No API key found. Run `lua configure` first.");
309
- return;
310
- }
311
- const { confirm } = await inquirer.prompt([
312
- {
313
- type: "confirm",
314
- name: "confirm",
315
- message: "This will display your API key. Are you sure you want to continue?",
316
- default: false
317
- }
318
- ]);
319
- if (confirm) {
320
- console.log("🔑 Your API key:");
321
- console.log(apiKey);
322
- }
323
- else {
324
- console.log("ℹ️ API key display cancelled.");
325
- }
326
- });
20
+ .action(apiKeyCommand);
327
21
  program
328
22
  .command("agents")
329
23
  .description("Fetch agents from HeyLua API")
330
- .action(async () => {
331
- const apiKey = await loadApiKey();
332
- if (!apiKey) {
333
- console.error("❌ No API key found. Run `lua configure` first.");
334
- process.exit(1);
335
- }
336
- const response = await fetch("https://api.heylua.ai/admin", {
337
- headers: {
338
- Authorization: `Bearer ${apiKey}`,
339
- },
340
- });
341
- if (!response.ok) {
342
- console.error(`❌ Error ${response.status}: ${await response.text()}`);
343
- process.exit(1);
344
- }
345
- const data = await response.json();
346
- console.log("✅ Agents:", JSON.stringify(data, null, 2));
347
- });
24
+ .action(agentsCommand);
348
25
  program.parse(process.argv);
@@ -0,0 +1,91 @@
1
+ import keytar from "keytar";
2
+ import fetch from "node-fetch";
3
+ const SERVICE = "lua-cli";
4
+ const ACCOUNT = "api-key";
5
+ export async function saveApiKey(apiKey) {
6
+ await keytar.setPassword(SERVICE, ACCOUNT, apiKey);
7
+ }
8
+ export async function loadApiKey() {
9
+ return keytar.getPassword(SERVICE, ACCOUNT);
10
+ }
11
+ export async function deleteApiKey() {
12
+ return keytar.deletePassword(SERVICE, ACCOUNT);
13
+ }
14
+ export async function checkApiKey(apiKey) {
15
+ const response = await fetch("https://api.heylua.ai/admin", {
16
+ headers: {
17
+ Authorization: `Bearer ${apiKey}`,
18
+ },
19
+ });
20
+ if (!response.ok) {
21
+ console.error(`❌ Invalid API key`);
22
+ process.exit(1);
23
+ }
24
+ return await response.json();
25
+ }
26
+ export async function requestEmailOTP(email) {
27
+ try {
28
+ const response = await fetch("https://auth.heylua.ai/otp", {
29
+ method: "POST",
30
+ headers: {
31
+ "accept": "application/json",
32
+ "Content-Type": "application/json"
33
+ },
34
+ body: JSON.stringify({
35
+ type: "email",
36
+ email: email
37
+ })
38
+ });
39
+ return response.ok;
40
+ }
41
+ catch (error) {
42
+ console.error("❌ Error requesting OTP:", error);
43
+ return false;
44
+ }
45
+ }
46
+ export async function verifyOTPAndGetToken(email, pin) {
47
+ try {
48
+ const response = await fetch("https://auth.heylua.ai/otp/verify", {
49
+ method: "POST",
50
+ headers: {
51
+ "accept": "application/json",
52
+ "Content-Type": "application/json"
53
+ },
54
+ body: JSON.stringify({
55
+ pin: pin,
56
+ type: "email",
57
+ email: email
58
+ })
59
+ });
60
+ if (!response.ok) {
61
+ return null;
62
+ }
63
+ const data = await response.json();
64
+ return data.signInToken;
65
+ }
66
+ catch (error) {
67
+ console.error("❌ Error verifying OTP:", error);
68
+ return null;
69
+ }
70
+ }
71
+ export async function generateApiKey(signInToken) {
72
+ try {
73
+ const response = await fetch("https://auth.heylua.ai/profile/apiKey", {
74
+ method: "POST",
75
+ headers: {
76
+ "Authorization": `Bearer ${signInToken}`,
77
+ "Content-Type": "application/json"
78
+ },
79
+ body: ""
80
+ });
81
+ if (!response.ok) {
82
+ return null;
83
+ }
84
+ const data = await response.json();
85
+ return data.apiKey;
86
+ }
87
+ catch (error) {
88
+ console.error("❌ Error generating API key:", error);
89
+ return null;
90
+ }
91
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ export function copyTemplateFiles(templateDir, targetDir) {
4
+ const files = fs.readdirSync(templateDir);
5
+ for (const file of files) {
6
+ const srcPath = path.join(templateDir, file);
7
+ const destPath = path.join(targetDir, file);
8
+ if (fs.statSync(srcPath).isDirectory()) {
9
+ fs.mkdirSync(destPath, { recursive: true });
10
+ copyTemplateFiles(srcPath, destPath);
11
+ }
12
+ else {
13
+ fs.copyFileSync(srcPath, destPath);
14
+ }
15
+ }
16
+ }
17
+ export function createSkillToml(agentId, orgId, skillName, skillDescription) {
18
+ const tomlContent = `[agent]
19
+ agentId = "${agentId}"
20
+ orgId = "${orgId}"
21
+
22
+ [skill]
23
+ name = "${skillName}"
24
+ description = "${skillDescription}"
25
+ `;
26
+ fs.writeFileSync("lua.skill.toml", tomlContent);
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lua-cli",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Command-line interface for Lua AI platform - manage agents, organizations, and skills",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -36,6 +36,7 @@
36
36
  "dist/**/*",
37
37
  "template/**/*",
38
38
  "README.md",
39
+ "CHANGELOG.md",
39
40
  "LICENSE"
40
41
  ],
41
42
  "dependencies": {