lua-cli 2.5.4 ā 2.5.6
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/dist/api/developer.api.service.d.ts +54 -0
- package/dist/api/developer.api.service.js +51 -0
- package/dist/api/skills.api.service.d.ts +16 -0
- package/dist/api/skills.api.service.js +23 -0
- package/dist/commands/compile.d.ts +7 -0
- package/dist/commands/compile.js +18 -0
- package/dist/commands/deploy.js +8 -1
- package/dist/commands/env.js +42 -26
- package/dist/commands/init.js +197 -14
- package/dist/commands/logs.js +4 -2
- package/dist/commands/push.js +12 -2
- package/dist/interfaces/skills.d.ts +51 -0
- package/dist/interfaces/skills.js +5 -0
- package/dist/utils/files.d.ts +4 -0
- package/dist/utils/files.js +27 -0
- package/dist/utils/init-agent.d.ts +13 -0
- package/dist/utils/init-agent.js +13 -0
- package/dist/utils/skill-management.d.ts +20 -0
- package/dist/utils/skill-management.js +159 -0
- package/package.json +1 -1
- package/template/package.json +1 -1
- package/template/package-lock.json +0 -3781
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { HttpClient } from "../common/http.client.js";
|
|
2
|
+
import { ApiResponse } from "../interfaces/common.js";
|
|
3
|
+
/**
|
|
4
|
+
* Environment variables response structure from the API
|
|
5
|
+
* The actual environment variables are nested in the 'data' property
|
|
6
|
+
*/
|
|
7
|
+
interface EnvironmentVariablesResponse {
|
|
8
|
+
data: Record<string, string>;
|
|
9
|
+
_id?: string;
|
|
10
|
+
agentId?: string;
|
|
11
|
+
createdAt?: string;
|
|
12
|
+
updatedAt?: string;
|
|
13
|
+
__v?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Developer API calls for agent management and configuration
|
|
17
|
+
*/
|
|
18
|
+
export default class DeveloperApi extends HttpClient {
|
|
19
|
+
private apiKey;
|
|
20
|
+
private agentId;
|
|
21
|
+
/**
|
|
22
|
+
* Creates an instance of DeveloperApi
|
|
23
|
+
* @param baseUrl - The base URL for the API
|
|
24
|
+
* @param apiKey - The API key for authentication
|
|
25
|
+
* @param agentId - The unique identifier of the agent
|
|
26
|
+
*/
|
|
27
|
+
constructor(baseUrl: string, apiKey: string, agentId: string);
|
|
28
|
+
/**
|
|
29
|
+
* Retrieves all environment variables for the agent in production
|
|
30
|
+
* The response includes metadata (_id, agentId, timestamps) and the actual env vars in the 'data' property
|
|
31
|
+
* @returns Promise resolving to an ApiResponse containing environment variables and metadata
|
|
32
|
+
* @throws Error if the API request fails or the agent is not found
|
|
33
|
+
*/
|
|
34
|
+
getEnvironmentVariables(): Promise<ApiResponse<EnvironmentVariablesResponse>>;
|
|
35
|
+
/**
|
|
36
|
+
* Updates all environment variables for the agent in production
|
|
37
|
+
* This operation replaces all existing environment variables with the provided set
|
|
38
|
+
* @param envData - Object containing environment variable key-value pairs
|
|
39
|
+
* @returns Promise resolving to an ApiResponse with the updated environment variables and metadata
|
|
40
|
+
* @throws Error if the API request fails or the agent is not found
|
|
41
|
+
*/
|
|
42
|
+
updateEnvironmentVariables(envData: Record<string, string>): Promise<ApiResponse<EnvironmentVariablesResponse>>;
|
|
43
|
+
/**
|
|
44
|
+
* Deletes a specific environment variable by key
|
|
45
|
+
* @param key - The environment variable key to delete
|
|
46
|
+
* @returns Promise resolving to an ApiResponse with confirmation
|
|
47
|
+
* @throws Error if the API request fails, the agent is not found, or the key doesn't exist
|
|
48
|
+
*/
|
|
49
|
+
deleteEnvironmentVariable(key: string): Promise<ApiResponse<{
|
|
50
|
+
message: string;
|
|
51
|
+
key: string;
|
|
52
|
+
}>>;
|
|
53
|
+
}
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { HttpClient } from "../common/http.client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Developer API calls for agent management and configuration
|
|
4
|
+
*/
|
|
5
|
+
export default class DeveloperApi extends HttpClient {
|
|
6
|
+
/**
|
|
7
|
+
* Creates an instance of DeveloperApi
|
|
8
|
+
* @param baseUrl - The base URL for the API
|
|
9
|
+
* @param apiKey - The API key for authentication
|
|
10
|
+
* @param agentId - The unique identifier of the agent
|
|
11
|
+
*/
|
|
12
|
+
constructor(baseUrl, apiKey, agentId) {
|
|
13
|
+
super(baseUrl);
|
|
14
|
+
this.apiKey = apiKey;
|
|
15
|
+
this.agentId = agentId;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Retrieves all environment variables for the agent in production
|
|
19
|
+
* The response includes metadata (_id, agentId, timestamps) and the actual env vars in the 'data' property
|
|
20
|
+
* @returns Promise resolving to an ApiResponse containing environment variables and metadata
|
|
21
|
+
* @throws Error if the API request fails or the agent is not found
|
|
22
|
+
*/
|
|
23
|
+
async getEnvironmentVariables() {
|
|
24
|
+
return this.httpGet(`/developer/agents/${this.agentId}/env`, {
|
|
25
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Updates all environment variables for the agent in production
|
|
30
|
+
* This operation replaces all existing environment variables with the provided set
|
|
31
|
+
* @param envData - Object containing environment variable key-value pairs
|
|
32
|
+
* @returns Promise resolving to an ApiResponse with the updated environment variables and metadata
|
|
33
|
+
* @throws Error if the API request fails or the agent is not found
|
|
34
|
+
*/
|
|
35
|
+
async updateEnvironmentVariables(envData) {
|
|
36
|
+
return this.httpPost(`/developer/agents/${this.agentId}/env`, envData, {
|
|
37
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Deletes a specific environment variable by key
|
|
42
|
+
* @param key - The environment variable key to delete
|
|
43
|
+
* @returns Promise resolving to an ApiResponse with confirmation
|
|
44
|
+
* @throws Error if the API request fails, the agent is not found, or the key doesn't exist
|
|
45
|
+
*/
|
|
46
|
+
async deleteEnvironmentVariable(key) {
|
|
47
|
+
return this.httpDelete(`/developer/agents/${this.agentId}/env/${key}`, {
|
|
48
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DevVersionResponse, UpdateDevVersionResponse } from "../interfaces/dev.js";
|
|
2
2
|
import { HttpClient } from "../common/http.client.js";
|
|
3
3
|
import { ApiResponse } from "../interfaces/common.js";
|
|
4
|
+
import { GetSkillsResponse, DeleteSkillResponse } from "../interfaces/skills.js";
|
|
4
5
|
/**
|
|
5
6
|
* Skill API calls
|
|
6
7
|
*/
|
|
@@ -14,6 +15,12 @@ export default class SkillApi extends HttpClient {
|
|
|
14
15
|
* @param agentId - The unique identifier of the agent
|
|
15
16
|
*/
|
|
16
17
|
constructor(baseUrl: string, apiKey: string, agentId: string);
|
|
18
|
+
/**
|
|
19
|
+
* Retrieves all skills for the agent
|
|
20
|
+
* @returns Promise resolving to an ApiResponse containing an array of skills with their versions and tools
|
|
21
|
+
* @throws Error if the API request fails or the agent is not found
|
|
22
|
+
*/
|
|
23
|
+
getSkills(): Promise<ApiResponse<GetSkillsResponse>>;
|
|
17
24
|
/**
|
|
18
25
|
* Creates a new skill for the agent
|
|
19
26
|
* @param skillData - The skill data including name, description, and optional context
|
|
@@ -74,4 +81,13 @@ export default class SkillApi extends HttpClient {
|
|
|
74
81
|
activeVersionId: string;
|
|
75
82
|
publishedAt: string;
|
|
76
83
|
}>>;
|
|
84
|
+
/**
|
|
85
|
+
* Deletes a skill and all its versions, or deactivates it if it has versions
|
|
86
|
+
* @param skillId - The unique identifier of the skill to delete
|
|
87
|
+
* @returns Promise resolving to an ApiResponse with deletion status
|
|
88
|
+
* - If deleted is true: skill was successfully deleted
|
|
89
|
+
* - If deleted is false and deactivated is true: skill has versions and was deactivated instead
|
|
90
|
+
* @throws Error if the skill is not found or the delete operation fails
|
|
91
|
+
*/
|
|
92
|
+
deleteSkill(skillId: string): Promise<ApiResponse<DeleteSkillResponse>>;
|
|
77
93
|
}
|
|
@@ -14,6 +14,16 @@ export default class SkillApi extends HttpClient {
|
|
|
14
14
|
this.apiKey = apiKey;
|
|
15
15
|
this.agentId = agentId;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Retrieves all skills for the agent
|
|
19
|
+
* @returns Promise resolving to an ApiResponse containing an array of skills with their versions and tools
|
|
20
|
+
* @throws Error if the API request fails or the agent is not found
|
|
21
|
+
*/
|
|
22
|
+
async getSkills() {
|
|
23
|
+
return this.httpGet(`/developer/skills/${this.agentId}`, {
|
|
24
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
17
27
|
/**
|
|
18
28
|
* Creates a new skill for the agent
|
|
19
29
|
* @param skillData - The skill data including name, description, and optional context
|
|
@@ -85,4 +95,17 @@ export default class SkillApi extends HttpClient {
|
|
|
85
95
|
Authorization: `Bearer ${this.apiKey}`,
|
|
86
96
|
});
|
|
87
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Deletes a skill and all its versions, or deactivates it if it has versions
|
|
100
|
+
* @param skillId - The unique identifier of the skill to delete
|
|
101
|
+
* @returns Promise resolving to an ApiResponse with deletion status
|
|
102
|
+
* - If deleted is true: skill was successfully deleted
|
|
103
|
+
* - If deleted is false and deactivated is true: skill has versions and was deactivated instead
|
|
104
|
+
* @throws Error if the skill is not found or the delete operation fails
|
|
105
|
+
*/
|
|
106
|
+
async deleteSkill(skillId) {
|
|
107
|
+
return this.httpDelete(`/developer/skills/${this.agentId}/${skillId}`, {
|
|
108
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
88
111
|
}
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* 4. Extracts execute code and schemas from bundled tools
|
|
13
13
|
* 5. Bundles the main index file
|
|
14
14
|
* 6. Creates deployment data in both new and legacy formats
|
|
15
|
+
* 7. Syncs lua.skill.yaml with deploy.json (removes deleted skills from YAML)
|
|
16
|
+
* 8. Syncs server with YAML (deletes/deactivates skills not in YAML)
|
|
15
17
|
*
|
|
16
18
|
* Output:
|
|
17
19
|
* - dist/deployment.json - New deployment format with tool references
|
|
@@ -19,6 +21,11 @@
|
|
|
19
21
|
* - dist/index.js - Main skill entry point
|
|
20
22
|
* - .lua/deploy.json - Legacy deployment format with compressed tools
|
|
21
23
|
* - .lua/*.js - Individual uncompressed tool files for debugging
|
|
24
|
+
* - lua.skill.yaml - Updated to match compiled skills
|
|
25
|
+
*
|
|
26
|
+
* Server Sync:
|
|
27
|
+
* - Skills deleted from code are removed from YAML
|
|
28
|
+
* - Skills not in YAML are deleted from server (or deactivated if they have versions)
|
|
22
29
|
*
|
|
23
30
|
* @returns Promise that resolves when compilation is complete
|
|
24
31
|
*/
|
package/dist/commands/compile.js
CHANGED
|
@@ -10,6 +10,8 @@ import { findIndexFile } from '../utils/compile.js';
|
|
|
10
10
|
import { detectTools } from '../utils/tool-detection.js';
|
|
11
11
|
import { bundleTool, bundleMainIndex, extractExecuteCode } from '../utils/bundling.js';
|
|
12
12
|
import { createDeploymentData, createLegacyDeploymentData } from '../utils/deployment.js';
|
|
13
|
+
import { syncYamlWithDeployJson, syncServerSkillsWithYaml } from '../utils/skill-management.js';
|
|
14
|
+
import { readSkillConfig } from '../utils/files.js';
|
|
13
15
|
import { COMPILE_DIRS, COMPILE_FILES } from '../config/compile.constants.js';
|
|
14
16
|
/**
|
|
15
17
|
* Main compile command - orchestrates the entire skill compilation process.
|
|
@@ -21,6 +23,8 @@ import { COMPILE_DIRS, COMPILE_FILES } from '../config/compile.constants.js';
|
|
|
21
23
|
* 4. Extracts execute code and schemas from bundled tools
|
|
22
24
|
* 5. Bundles the main index file
|
|
23
25
|
* 6. Creates deployment data in both new and legacy formats
|
|
26
|
+
* 7. Syncs lua.skill.yaml with deploy.json (removes deleted skills from YAML)
|
|
27
|
+
* 8. Syncs server with YAML (deletes/deactivates skills not in YAML)
|
|
24
28
|
*
|
|
25
29
|
* Output:
|
|
26
30
|
* - dist/deployment.json - New deployment format with tool references
|
|
@@ -28,6 +32,11 @@ import { COMPILE_DIRS, COMPILE_FILES } from '../config/compile.constants.js';
|
|
|
28
32
|
* - dist/index.js - Main skill entry point
|
|
29
33
|
* - .lua/deploy.json - Legacy deployment format with compressed tools
|
|
30
34
|
* - .lua/*.js - Individual uncompressed tool files for debugging
|
|
35
|
+
* - lua.skill.yaml - Updated to match compiled skills
|
|
36
|
+
*
|
|
37
|
+
* Server Sync:
|
|
38
|
+
* - Skills deleted from code are removed from YAML
|
|
39
|
+
* - Skills not in YAML are deleted from server (or deactivated if they have versions)
|
|
31
40
|
*
|
|
32
41
|
* @returns Promise that resolves when compilation is complete
|
|
33
42
|
*/
|
|
@@ -52,6 +61,15 @@ export async function compileCommand() {
|
|
|
52
61
|
// Step 5: Create deployment data in both formats
|
|
53
62
|
await createDeploymentData(tools, distDir);
|
|
54
63
|
await createLegacyDeploymentData(tools, luaDir, indexFile);
|
|
64
|
+
// Step 6: Sync YAML with deploy.json
|
|
65
|
+
writeProgress("š Syncing YAML with deploy.json...");
|
|
66
|
+
const deployJsonPath = path.join(luaDir, COMPILE_FILES.DEPLOY_JSON);
|
|
67
|
+
const config = readSkillConfig();
|
|
68
|
+
await syncYamlWithDeployJson(deployJsonPath, config);
|
|
69
|
+
// Step 7: Sync server with YAML (delete skills not in YAML)
|
|
70
|
+
writeProgress("š Syncing server with YAML...");
|
|
71
|
+
const updatedConfig = readSkillConfig(); // Re-read config after YAML sync
|
|
72
|
+
await syncServerSkillsWithYaml(updatedConfig);
|
|
55
73
|
writeSuccess(`ā
Skill compiled successfully - ${tools.length} tools bundled`);
|
|
56
74
|
}, "compilation");
|
|
57
75
|
}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -7,6 +7,7 @@ import { readSkillConfig } from '../utils/files.js';
|
|
|
7
7
|
import { withErrorHandling, writeProgress, writeSuccess, writeInfo } from '../utils/cli.js';
|
|
8
8
|
import { sortVersionsByDate, promptVersionSelection, confirmDeployment, validateDeployConfig, validateVersionsAvailable, promptSkillSelection, getAvailableSkills, } from '../utils/deploy-helpers.js';
|
|
9
9
|
import { fetchVersions, publishVersion } from '../utils/deploy-api.js';
|
|
10
|
+
import { updateSkillVersionInYaml } from '../utils/push-helpers.js';
|
|
10
11
|
/**
|
|
11
12
|
* Main deploy command - deploys a skill version to production.
|
|
12
13
|
*
|
|
@@ -82,6 +83,12 @@ export async function deployCommand() {
|
|
|
82
83
|
// Step 7: Publish the selected version
|
|
83
84
|
writeProgress("š Publishing version...");
|
|
84
85
|
const publishResponse = await publishVersion(apiKey, config.agent.agentId, selectedSkill.skillId, selectedVersion);
|
|
85
|
-
|
|
86
|
+
const deployedVersion = publishResponse.activeVersionId;
|
|
87
|
+
writeSuccess(`ā
Version ${deployedVersion} of "${selectedSkill.name}" deployed successfully`);
|
|
88
|
+
// Step 8: Update YAML with the deployed version
|
|
89
|
+
if (deployedVersion !== selectedSkill.version) {
|
|
90
|
+
writeInfo(`š Updating YAML with deployed version: ${deployedVersion}`);
|
|
91
|
+
updateSkillVersionInYaml(selectedSkill.name, deployedVersion);
|
|
92
|
+
}
|
|
86
93
|
}, "deployment");
|
|
87
94
|
}
|
package/dist/commands/env.js
CHANGED
|
@@ -10,6 +10,7 @@ import { readSkillConfig } from '../utils/files.js';
|
|
|
10
10
|
import { withErrorHandling, writeProgress, writeSuccess } from '../utils/cli.js';
|
|
11
11
|
import { BASE_URLS } from '../config/constants.js';
|
|
12
12
|
import { validateConfig, validateAgentConfig, } from '../utils/dev-helpers.js';
|
|
13
|
+
import DeveloperApi from '../api/developer.api.service.js';
|
|
13
14
|
/**
|
|
14
15
|
* Main env command - manages environment variables
|
|
15
16
|
*
|
|
@@ -57,6 +58,7 @@ export async function envCommand() {
|
|
|
57
58
|
}
|
|
58
59
|
await checkApiKey(apiKey);
|
|
59
60
|
context.apiKey = apiKey;
|
|
61
|
+
context.developerApi = new DeveloperApi(BASE_URLS.API, apiKey, agentId);
|
|
60
62
|
writeProgress("ā
Authenticated");
|
|
61
63
|
}
|
|
62
64
|
// Step 4: Start management loop
|
|
@@ -160,19 +162,22 @@ function loadSandboxEnvVariables() {
|
|
|
160
162
|
*/
|
|
161
163
|
async function loadProductionEnvVariables(context) {
|
|
162
164
|
try {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
});
|
|
170
|
-
if (!response.ok) {
|
|
171
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
165
|
+
if (!context.developerApi) {
|
|
166
|
+
throw new Error('Developer API not initialized');
|
|
167
|
+
}
|
|
168
|
+
const response = await context.developerApi.getEnvironmentVariables();
|
|
169
|
+
if (!response.success) {
|
|
170
|
+
throw new Error(response.error?.message || 'Failed to load environment variables');
|
|
172
171
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
172
|
+
// The API returns environment variables nested in a 'data' property
|
|
173
|
+
// Response structure: { success: true, data: { data: { KEY: "value", ... }, _id: "...", ... } }
|
|
174
|
+
const envData = response.data?.data || response.data;
|
|
175
|
+
if (envData && typeof envData === 'object') {
|
|
176
|
+
// Filter out metadata fields like _id, agentId, createdAt, updatedAt, __v
|
|
177
|
+
const metadataKeys = ['_id', 'agentId', 'data', 'createdAt', 'updatedAt', '__v'];
|
|
178
|
+
return Object.entries(envData)
|
|
179
|
+
.filter(([key]) => !metadataKeys.includes(key))
|
|
180
|
+
.map(([key, value]) => ({
|
|
176
181
|
key,
|
|
177
182
|
value: String(value)
|
|
178
183
|
}));
|
|
@@ -231,23 +236,18 @@ function saveSandboxEnvVariables(variables) {
|
|
|
231
236
|
*/
|
|
232
237
|
async function saveProductionEnvVariables(context, variables) {
|
|
233
238
|
try {
|
|
239
|
+
if (!context.developerApi) {
|
|
240
|
+
throw new Error('Developer API not initialized');
|
|
241
|
+
}
|
|
234
242
|
const envData = {};
|
|
235
243
|
variables.forEach(v => {
|
|
236
244
|
if (v.key.trim()) {
|
|
237
245
|
envData[v.key.trim()] = v.value;
|
|
238
246
|
}
|
|
239
247
|
});
|
|
240
|
-
const response = await
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
'accept': 'application/json',
|
|
244
|
-
'Authorization': `Bearer ${context.apiKey}`,
|
|
245
|
-
'Content-Type': 'application/json'
|
|
246
|
-
},
|
|
247
|
-
body: JSON.stringify(envData)
|
|
248
|
-
});
|
|
249
|
-
if (!response.ok) {
|
|
250
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
248
|
+
const response = await context.developerApi.updateEnvironmentVariables(envData);
|
|
249
|
+
if (!response.success) {
|
|
250
|
+
throw new Error(response.error?.message || 'Failed to save environment variables');
|
|
251
251
|
}
|
|
252
252
|
return true;
|
|
253
253
|
}
|
|
@@ -383,14 +383,30 @@ async function deleteVariable(context, currentVariables) {
|
|
|
383
383
|
console.log("\nā¹ļø Deletion cancelled.\n");
|
|
384
384
|
return;
|
|
385
385
|
}
|
|
386
|
-
|
|
387
|
-
writeProgress("š Saving...");
|
|
386
|
+
writeProgress("š Deleting...");
|
|
388
387
|
let success = false;
|
|
389
388
|
if (context.environment === 'sandbox') {
|
|
389
|
+
const updatedVariables = currentVariables.filter(v => v.key !== selectedKey);
|
|
390
390
|
success = saveSandboxEnvVariables(updatedVariables);
|
|
391
391
|
}
|
|
392
392
|
else {
|
|
393
|
-
|
|
393
|
+
// Use the dedicated delete API endpoint for production
|
|
394
|
+
if (!context.developerApi) {
|
|
395
|
+
console.error("ā Developer API not initialized");
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
try {
|
|
399
|
+
const response = await context.developerApi.deleteEnvironmentVariable(selectedKey);
|
|
400
|
+
if (response.success) {
|
|
401
|
+
success = true;
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
console.error(`ā ${response.error?.message || 'Failed to delete variable'}`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
console.error('ā Error deleting production env variable:', error);
|
|
409
|
+
}
|
|
394
410
|
}
|
|
395
411
|
if (success) {
|
|
396
412
|
writeSuccess(`ā
Variable "${selectedKey}" deleted successfully`);
|
package/dist/commands/init.js
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
* Init Command
|
|
3
3
|
* Orchestrates the initialization of a new Lua skill project
|
|
4
4
|
*/
|
|
5
|
+
import inquirer from 'inquirer';
|
|
5
6
|
import { loadApiKey, checkApiKey } from "../services/auth.js";
|
|
6
|
-
import { withErrorHandling, writeProgress, writeSuccess, } from "../utils/cli.js";
|
|
7
|
+
import { withErrorHandling, writeProgress, writeSuccess, writeInfo, writeError, } from "../utils/cli.js";
|
|
7
8
|
import { promptAgentChoice, promptOrganizationSelection, promptAgentSelection, promptMetadataCollection, promptFeatureConfiguration, promptBusinessConfiguration, } from "../utils/init-prompts.js";
|
|
8
|
-
import { fetchAgentTypes, selectBaseAgentType, createNewAgent, } from "../utils/init-agent.js";
|
|
9
|
+
import { fetchAgentTypes, selectBaseAgentType, createNewAgent, fetchExistingAgentDetails, } from "../utils/init-agent.js";
|
|
9
10
|
import { initializeProject, installDependencies, clearLinesIfNeeded, } from "../utils/init-helpers.js";
|
|
11
|
+
import { readSkillYaml, updateYamlAgent } from "../utils/files.js";
|
|
10
12
|
/**
|
|
11
13
|
* Main init command - initializes a new Lua skill project.
|
|
12
14
|
*
|
|
@@ -40,40 +42,114 @@ export async function initCommand() {
|
|
|
40
42
|
}
|
|
41
43
|
const userData = await checkApiKey(apiKey);
|
|
42
44
|
writeProgress("ā
Authenticated");
|
|
43
|
-
// Step 2:
|
|
45
|
+
// Step 2: Check for existing YAML file
|
|
46
|
+
const existingYaml = readSkillYaml();
|
|
47
|
+
const yamlExists = existingYaml !== null;
|
|
48
|
+
if (yamlExists) {
|
|
49
|
+
const existingAgentId = existingYaml?.agent?.agentId;
|
|
50
|
+
if (existingAgentId) {
|
|
51
|
+
// Check if user has access to this agent
|
|
52
|
+
const hasAccess = checkUserHasAccessToAgent(userData, existingAgentId);
|
|
53
|
+
if (!hasAccess) {
|
|
54
|
+
writeError("\nā ļø You don't have access to the agent in this project");
|
|
55
|
+
writeInfo(` Agent ID: ${existingAgentId}\n`);
|
|
56
|
+
const { action } = await inquirer.prompt([
|
|
57
|
+
{
|
|
58
|
+
type: 'list',
|
|
59
|
+
name: 'action',
|
|
60
|
+
message: 'What would you like to do?',
|
|
61
|
+
choices: [
|
|
62
|
+
{ name: 'š§ Contact the agent admin to request access', value: 'contact' },
|
|
63
|
+
{ name: 'š Switch to a different agent', value: 'switch' },
|
|
64
|
+
{ name: 'ā Cancel', value: 'cancel' }
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
]);
|
|
68
|
+
if (action === 'contact') {
|
|
69
|
+
writeInfo("\nš” Please contact the agent administrator to grant you access.");
|
|
70
|
+
writeInfo(` Agent ID: ${existingAgentId}\n`);
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
if (action === 'cancel') {
|
|
74
|
+
writeInfo("\nā Initialization cancelled.\n");
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
// User chose to switch agent - update existing YAML only
|
|
78
|
+
await handleAgentSwitch(userData, apiKey, existingYaml);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// User has access - ask if they want to switch anyway
|
|
83
|
+
writeInfo("\nš Found existing project configuration");
|
|
84
|
+
writeInfo(` Current Agent ID: ${existingAgentId}\n`);
|
|
85
|
+
const { wantSwitch } = await inquirer.prompt([
|
|
86
|
+
{
|
|
87
|
+
type: 'confirm',
|
|
88
|
+
name: 'wantSwitch',
|
|
89
|
+
message: 'Do you want to switch this project to a different agent?',
|
|
90
|
+
default: false
|
|
91
|
+
}
|
|
92
|
+
]);
|
|
93
|
+
if (wantSwitch) {
|
|
94
|
+
// User wants to switch agent - update existing YAML only
|
|
95
|
+
await handleAgentSwitch(userData, apiKey, existingYaml);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
writeInfo("\nā
Keeping current agent configuration\n");
|
|
100
|
+
process.exit(0);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Step 3: Choose between existing or new agent
|
|
44
106
|
const agentChoice = await promptAgentChoice();
|
|
45
107
|
let selectedAgent;
|
|
46
108
|
let selectedOrg;
|
|
47
109
|
let persona;
|
|
48
110
|
let welcomeMessage;
|
|
111
|
+
let skipProjectInit = false;
|
|
49
112
|
if (agentChoice === "existing") {
|
|
50
|
-
// Step
|
|
51
|
-
const result = await selectExistingAgent(userData);
|
|
113
|
+
// Step 4a: Select existing agent
|
|
114
|
+
const result = await selectExistingAgent(userData, apiKey);
|
|
52
115
|
selectedAgent = result.agent;
|
|
53
116
|
selectedOrg = result.org;
|
|
117
|
+
persona = result.persona;
|
|
118
|
+
welcomeMessage = result.welcomeMessage;
|
|
54
119
|
}
|
|
55
120
|
else {
|
|
56
|
-
// Step
|
|
121
|
+
// Step 4b: Create new agent
|
|
57
122
|
const result = await createNewAgentFlow(apiKey);
|
|
58
123
|
selectedAgent = result.agent;
|
|
59
124
|
selectedOrg = result.org;
|
|
60
125
|
persona = result.persona;
|
|
61
126
|
welcomeMessage = result.welcomeMessage;
|
|
62
127
|
}
|
|
63
|
-
// Step
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
128
|
+
// Step 5: Initialize or update project
|
|
129
|
+
if (yamlExists) {
|
|
130
|
+
// Update existing YAML only
|
|
131
|
+
writeInfo("š Updating existing lua.skill.yaml with new agent...");
|
|
132
|
+
updateYamlAgent(selectedAgent.agentId, selectedOrg.id, persona, welcomeMessage);
|
|
133
|
+
writeSuccess("ā
lua.skill.yaml updated successfully!");
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// Full project initialization
|
|
137
|
+
const currentDir = initializeProject(selectedAgent.agentId, selectedOrg.id, persona, welcomeMessage);
|
|
138
|
+
// Step 6: Install dependencies
|
|
139
|
+
await installDependencies(currentDir);
|
|
140
|
+
writeSuccess("ā
Lua skill project initialized successfully!");
|
|
141
|
+
}
|
|
68
142
|
}, "initialization");
|
|
69
143
|
}
|
|
70
144
|
/**
|
|
71
145
|
* Handles the flow for selecting an existing agent.
|
|
146
|
+
* Fetches the agent details from the server to get persona and welcomeMessage.
|
|
72
147
|
*
|
|
73
148
|
* @param userData - User's data
|
|
74
|
-
* @
|
|
149
|
+
* @param apiKey - User's API key
|
|
150
|
+
* @returns Selected agent, organization, and optional persona/welcome message
|
|
75
151
|
*/
|
|
76
|
-
async function selectExistingAgent(userData) {
|
|
152
|
+
async function selectExistingAgent(userData, apiKey) {
|
|
77
153
|
// Extract organizations
|
|
78
154
|
const orgs = userData.admin.orgs;
|
|
79
155
|
if (!orgs || orgs.length === 0) {
|
|
@@ -83,7 +159,14 @@ async function selectExistingAgent(userData) {
|
|
|
83
159
|
const selectedOrg = await promptOrganizationSelection(orgs);
|
|
84
160
|
// Select agent from organization
|
|
85
161
|
const selectedAgent = await promptAgentSelection(selectedOrg);
|
|
86
|
-
|
|
162
|
+
// Fetch agent details to get persona and welcomeMessage
|
|
163
|
+
const agentDetails = await fetchExistingAgentDetails(apiKey, selectedAgent.agentId);
|
|
164
|
+
return {
|
|
165
|
+
agent: selectedAgent,
|
|
166
|
+
org: selectedOrg,
|
|
167
|
+
persona: agentDetails.persona,
|
|
168
|
+
welcomeMessage: agentDetails.welcomeMessage
|
|
169
|
+
};
|
|
87
170
|
}
|
|
88
171
|
/**
|
|
89
172
|
* Handles the flow for creating a new agent.
|
|
@@ -115,3 +198,103 @@ async function createNewAgentFlow(apiKey) {
|
|
|
115
198
|
const result = await createNewAgent(apiKey, selectedAgentType, businessConfig, metadata, features);
|
|
116
199
|
return result;
|
|
117
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* Check if user has access to a specific agent
|
|
203
|
+
*/
|
|
204
|
+
function checkUserHasAccessToAgent(userData, agentId) {
|
|
205
|
+
const orgs = userData.admin.orgs;
|
|
206
|
+
for (const org of orgs) {
|
|
207
|
+
const agent = org.agents.find((a) => a.agentId === agentId);
|
|
208
|
+
if (agent) {
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Handle switching to a different agent
|
|
216
|
+
*/
|
|
217
|
+
async function handleAgentSwitch(userData, apiKey, existingYaml) {
|
|
218
|
+
writeInfo("\nš Let's switch to a different agent...\n");
|
|
219
|
+
// Prompt for agent choice
|
|
220
|
+
const agentChoice = await promptAgentChoice();
|
|
221
|
+
let selectedAgent;
|
|
222
|
+
let selectedOrg;
|
|
223
|
+
let persona;
|
|
224
|
+
let welcomeMessage;
|
|
225
|
+
if (agentChoice === "existing") {
|
|
226
|
+
// Select existing agent
|
|
227
|
+
const result = await selectExistingAgent(userData, apiKey);
|
|
228
|
+
selectedAgent = result.agent;
|
|
229
|
+
selectedOrg = result.org;
|
|
230
|
+
persona = result.persona;
|
|
231
|
+
welcomeMessage = result.welcomeMessage;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
// Create new agent
|
|
235
|
+
const result = await createNewAgentFlow(apiKey);
|
|
236
|
+
selectedAgent = result.agent;
|
|
237
|
+
selectedOrg = result.org;
|
|
238
|
+
persona = result.persona;
|
|
239
|
+
welcomeMessage = result.welcomeMessage;
|
|
240
|
+
}
|
|
241
|
+
// Ask about persona and welcome message
|
|
242
|
+
const finalPersona = await promptPersonaReplacement(existingYaml, persona);
|
|
243
|
+
const finalWelcomeMessage = await promptWelcomeMessageReplacement(existingYaml, welcomeMessage);
|
|
244
|
+
// Update existing YAML file with new agent
|
|
245
|
+
writeInfo("\nš Updating lua.skill.yaml with new agent...");
|
|
246
|
+
updateYamlAgent(selectedAgent.agentId, selectedOrg.id, finalPersona, finalWelcomeMessage);
|
|
247
|
+
writeSuccess("ā
lua.skill.yaml updated successfully!");
|
|
248
|
+
writeInfo("\nš” Your project now uses the new agent. Run 'lua compile' to update your skills.\n");
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Prompt user about replacing existing persona
|
|
252
|
+
*/
|
|
253
|
+
async function promptPersonaReplacement(existingYaml, newPersona) {
|
|
254
|
+
const existingPersona = existingYaml?.agent?.persona;
|
|
255
|
+
// If no existing persona, use new one
|
|
256
|
+
if (!existingPersona) {
|
|
257
|
+
return newPersona;
|
|
258
|
+
}
|
|
259
|
+
// If no new persona, keep existing
|
|
260
|
+
if (!newPersona) {
|
|
261
|
+
return existingPersona;
|
|
262
|
+
}
|
|
263
|
+
// Both exist - ask user
|
|
264
|
+
writeInfo("\nš Persona Configuration:");
|
|
265
|
+
writeInfo(" Existing persona found in project");
|
|
266
|
+
const { replacePersona } = await inquirer.prompt([
|
|
267
|
+
{
|
|
268
|
+
type: 'confirm',
|
|
269
|
+
name: 'replacePersona',
|
|
270
|
+
message: 'Replace existing persona with the new agent\'s persona?',
|
|
271
|
+
default: false
|
|
272
|
+
}
|
|
273
|
+
]);
|
|
274
|
+
return replacePersona ? newPersona : existingPersona;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Prompt user about replacing existing welcome message
|
|
278
|
+
*/
|
|
279
|
+
async function promptWelcomeMessageReplacement(existingYaml, newWelcomeMessage) {
|
|
280
|
+
const existingWelcomeMessage = existingYaml?.agent?.welcomeMessage;
|
|
281
|
+
// If no existing welcome message, use new one
|
|
282
|
+
if (!existingWelcomeMessage) {
|
|
283
|
+
return newWelcomeMessage;
|
|
284
|
+
}
|
|
285
|
+
// If no new welcome message, keep existing
|
|
286
|
+
if (!newWelcomeMessage) {
|
|
287
|
+
return existingWelcomeMessage;
|
|
288
|
+
}
|
|
289
|
+
// Both exist - ask user
|
|
290
|
+
writeInfo(" Existing welcome message found in project");
|
|
291
|
+
const { replaceWelcomeMessage } = await inquirer.prompt([
|
|
292
|
+
{
|
|
293
|
+
type: 'confirm',
|
|
294
|
+
name: 'replaceWelcomeMessage',
|
|
295
|
+
message: 'Replace existing welcome message with the new agent\'s welcome message?',
|
|
296
|
+
default: false
|
|
297
|
+
}
|
|
298
|
+
]);
|
|
299
|
+
return replaceWelcomeMessage ? newWelcomeMessage : existingWelcomeMessage;
|
|
300
|
+
}
|
package/dist/commands/logs.js
CHANGED
|
@@ -160,7 +160,9 @@ function displayLogs(logs, pagination, title) {
|
|
|
160
160
|
writeInfo("No logs found.");
|
|
161
161
|
return;
|
|
162
162
|
}
|
|
163
|
-
logs
|
|
163
|
+
// Reverse logs so latest appears at the bottom (oldest first, newest last)
|
|
164
|
+
const reversedLogs = [...logs].reverse();
|
|
165
|
+
reversedLogs.forEach((log, index) => {
|
|
164
166
|
const timestamp = new Date(log.timestamp).toLocaleString();
|
|
165
167
|
const icon = getLogIcon(log.subType);
|
|
166
168
|
const color = getLogColor(log.subType);
|
|
@@ -179,7 +181,7 @@ function displayLogs(logs, pagination, title) {
|
|
|
179
181
|
? log.message.substring(0, 200) + '...'
|
|
180
182
|
: log.message;
|
|
181
183
|
console.log(` ${message}`);
|
|
182
|
-
if (index <
|
|
184
|
+
if (index < reversedLogs.length - 1) {
|
|
183
185
|
console.log(chalk.gray(` ${'-'.repeat(78)}`));
|
|
184
186
|
}
|
|
185
187
|
});
|