lua-cli 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Lua AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,176 @@
1
+ # Lua CLI
2
+
3
+ A command-line interface for the Lua AI platform that helps you manage agents, organizations, and skills with ease.
4
+
5
+ ## Features
6
+
7
+ - 🔐 **Secure Authentication**: Support for both API key and email-based OTP authentication
8
+ - đŸĸ **Organization Management**: Select and manage multiple organizations
9
+ - 🤖 **Agent Management**: Choose from available agents within your organizations
10
+ - đŸ› ī¸ **Skill Development**: Initialize new Lua skills with proper configuration
11
+ - 🔑 **API Key Management**: Securely store, view, and manage your API keys
12
+ - đŸ“Ļ **Template System**: Quick project setup with pre-configured templates
13
+
14
+ ## Installation
15
+
16
+ Install the Lua CLI globally using npm:
17
+
18
+ ```bash
19
+ npm install -g lua-cli
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ 1. **Configure your authentication:**
25
+ ```bash
26
+ lua configure
27
+ ```
28
+ Choose between API key or email authentication methods.
29
+
30
+ 2. **Initialize a new skill project:**
31
+ ```bash
32
+ lua init
33
+ ```
34
+ Select your organization and agent, then provide skill details.
35
+
36
+ 3. **View your API key:**
37
+ ```bash
38
+ lua apiKey
39
+ ```
40
+
41
+ 4. **List your agents:**
42
+ ```bash
43
+ lua agents
44
+ ```
45
+
46
+ 5. **Delete your stored credentials:**
47
+ ```bash
48
+ lua destroy
49
+ ```
50
+
51
+ ## Commands
52
+
53
+ ### `lua configure`
54
+
55
+ Set up your authentication credentials. You can choose between:
56
+
57
+ - **API Key**: Direct API key input
58
+ - **Email**: Email-based OTP authentication
59
+
60
+ ```bash
61
+ lua configure
62
+ ```
63
+
64
+ ### `lua init`
65
+
66
+ Initialize a new Lua skill project in the current directory.
67
+
68
+ ```bash
69
+ lua init
70
+ ```
71
+
72
+ This command will:
73
+ - Fetch your organizations and agents from the API
74
+ - Let you select an organization by name
75
+ - Let you choose an agent from the selected organization
76
+ - Prompt for skill name and description
77
+ - Create a `lua.skill.toml` configuration file
78
+ - Copy template files to the current directory
79
+
80
+ ### `lua apiKey`
81
+
82
+ Display your stored API key (with confirmation prompt).
83
+
84
+ ```bash
85
+ lua apiKey
86
+ ```
87
+
88
+ ### `lua agents`
89
+
90
+ Fetch and display your agents from the HeyLua API.
91
+
92
+ ```bash
93
+ lua agents
94
+ ```
95
+
96
+ ### `lua destroy`
97
+
98
+ Delete your stored API key and credentials.
99
+
100
+ ```bash
101
+ lua destroy
102
+ ```
103
+
104
+ ## Configuration File
105
+
106
+ The `lua.skill.toml` file is created when you run `lua init`:
107
+
108
+ ```toml
109
+ [agent]
110
+ agentId = "your-agent-id"
111
+ orgId = "your-organization-id"
112
+
113
+ [skill]
114
+ name = "Your Skill Name"
115
+ description = "Description of your skill"
116
+ ```
117
+
118
+ ## Authentication Methods
119
+
120
+ ### API Key Authentication
121
+
122
+ 1. Run `lua configure`
123
+ 2. Select "API Key"
124
+ 3. Enter your API key when prompted
125
+ 4. The key is validated and stored securely
126
+
127
+ ### Email Authentication
128
+
129
+ 1. Run `lua configure`
130
+ 2. Select "Email"
131
+ 3. Enter your email address
132
+ 4. Check your email for the OTP code
133
+ 5. Enter the 6-digit OTP code
134
+ 6. An API key is automatically generated and stored
135
+
136
+ ## Security
137
+
138
+ - All API keys are stored securely using your system's credential manager
139
+ - Email authentication uses OTP (One-Time Password) for secure verification
140
+ - Confirmation prompts prevent accidental exposure of sensitive information
141
+ - No credentials are stored in plain text
142
+
143
+ ## Requirements
144
+
145
+ - Node.js 16.0.0 or higher
146
+ - Valid Lua AI platform account
147
+
148
+ ## Development
149
+
150
+ To contribute to this project:
151
+
152
+ 1. Clone the repository
153
+ 2. Install dependencies: `npm install`
154
+ 3. Build the project: `npm run build`
155
+ 4. Make your changes
156
+ 5. Test your changes
157
+ 6. Submit a pull request
158
+
159
+ ## License
160
+
161
+ MIT License - see [LICENSE](LICENSE) file for details.
162
+
163
+ ## Support
164
+
165
+ For support and questions:
166
+ - Create an issue on [GitHub](https://github.com/heylua/lua-cli/issues)
167
+ - Contact: stefan@heylua.ai
168
+
169
+ ## Changelog
170
+
171
+ ### 1.0.0
172
+ - Initial release
173
+ - API key and email authentication
174
+ - Organization and agent management
175
+ - Skill project initialization
176
+ - Secure credential storage
package/dist/index.js ADDED
@@ -0,0 +1,348 @@
1
+ #!/usr/bin/env node
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";
9
+ 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
+ program
125
+ .command("init")
126
+ .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
+ });
191
+ program
192
+ .command("destroy")
193
+ .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
+ });
221
+ program
222
+ .command("configure")
223
+ .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
+ });
302
+ program
303
+ .command("apiKey")
304
+ .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
+ });
327
+ program
328
+ .command("agents")
329
+ .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
+ });
348
+ program.parse(process.argv);
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "lua-cli",
3
+ "version": "1.0.0",
4
+ "description": "Command-line interface for Lua AI platform - manage agents, organizations, and skills",
5
+ "main": "dist/index.js",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "prepublishOnly": "npm run build",
9
+ "test": "echo \"Error: no test specified\" && exit 1"
10
+ },
11
+ "keywords": [
12
+ "lua",
13
+ "ai",
14
+ "cli",
15
+ "command-line",
16
+ "automation",
17
+ "agents",
18
+ "api",
19
+ "typescript"
20
+ ],
21
+ "author": "Stefan Kruger <stefan@heylua.ai>",
22
+ "license": "MIT",
23
+ "type": "module",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/heylua/lua-cli.git"
27
+ },
28
+ "homepage": "https://github.com/heylua/lua-cli#readme",
29
+ "bugs": {
30
+ "url": "https://github.com/heylua/lua-cli/issues"
31
+ },
32
+ "engines": {
33
+ "node": ">=16.0.0"
34
+ },
35
+ "files": [
36
+ "dist/**/*",
37
+ "template/**/*",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "dependencies": {
42
+ "commander": "^14.0.1",
43
+ "inquirer": "^12.9.6",
44
+ "keytar": "^7.9.0",
45
+ "node-fetch": "^3.3.2"
46
+ },
47
+ "devDependencies": {
48
+ "@types/inquirer": "^9.0.9",
49
+ "@types/node": "^24.5.1",
50
+ "@types/node-fetch": "^2.6.13",
51
+ "ts-node": "^10.9.2",
52
+ "typescript": "^5.9.2"
53
+ },
54
+ "bin": {
55
+ "lua": "dist/index.js"
56
+ }
57
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "lua-skill",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "license": "ISC",
6
+ "author": "",
7
+ "type": "commonjs",
8
+ "main": "index.ts",
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ }
12
+ }