lua-cli 2.5.8 ā 3.0.0-alpha.4
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/job.api.service.d.ts +219 -0
- package/dist/api/job.api.service.js +216 -0
- package/dist/api/lazy-instances.d.ts +24 -0
- package/dist/api/lazy-instances.js +48 -0
- package/dist/api/postprocessor.api.service.d.ts +158 -0
- package/dist/api/postprocessor.api.service.js +111 -0
- package/dist/api/preprocessor.api.service.d.ts +158 -0
- package/dist/api/preprocessor.api.service.js +111 -0
- package/dist/api/user.data.api.service.d.ts +13 -0
- package/dist/api/user.data.api.service.js +20 -0
- package/dist/api/webhook.api.service.d.ts +151 -0
- package/dist/api/webhook.api.service.js +134 -0
- package/dist/api-exports.d.ts +176 -41
- package/dist/api-exports.js +195 -21
- package/dist/cli/command-definitions.js +75 -5
- package/dist/commands/chat.js +32 -5
- package/dist/commands/compile.js +140 -7
- package/dist/commands/dev.js +23 -2
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/index.js +4 -0
- package/dist/commands/init.js +53 -7
- package/dist/commands/jobs.d.ts +20 -0
- package/dist/commands/jobs.js +533 -0
- package/dist/commands/logs.js +2 -5
- package/dist/commands/postprocessors.d.ts +8 -0
- package/dist/commands/postprocessors.js +431 -0
- package/dist/commands/preprocessors.d.ts +8 -0
- package/dist/commands/preprocessors.js +431 -0
- package/dist/commands/push.js +686 -5
- package/dist/commands/test.d.ts +9 -18
- package/dist/commands/test.js +574 -82
- package/dist/commands/webhooks.d.ts +18 -0
- package/dist/commands/webhooks.js +424 -0
- package/dist/common/job.instance.d.ts +80 -0
- package/dist/common/job.instance.js +116 -0
- package/dist/common/user.instance.d.ts +1 -0
- package/dist/common/user.instance.js +9 -0
- package/dist/config/constants.d.ts +4 -3
- package/dist/config/constants.js +10 -8
- package/dist/interfaces/agent.d.ts +2 -1
- package/dist/interfaces/chat.d.ts +52 -1
- package/dist/interfaces/index.d.ts +10 -0
- package/dist/interfaces/index.js +7 -0
- package/dist/interfaces/jobs.d.ts +193 -0
- package/dist/interfaces/jobs.js +5 -0
- package/dist/interfaces/postprocessors.d.ts +35 -0
- package/dist/interfaces/postprocessors.js +4 -0
- package/dist/interfaces/preprocessors.d.ts +35 -0
- package/dist/interfaces/preprocessors.js +4 -0
- package/dist/interfaces/webhooks.d.ts +104 -0
- package/dist/interfaces/webhooks.js +5 -0
- package/dist/types/api-contracts.d.ts +5 -0
- package/dist/types/compile.types.d.ts +49 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/skill.d.ts +521 -0
- package/dist/types/skill.js +471 -0
- package/dist/utils/agent-management.d.ts +25 -0
- package/dist/utils/agent-management.js +67 -0
- package/dist/utils/bundling.d.ts +44 -5
- package/dist/utils/bundling.js +723 -23
- package/dist/utils/compile.d.ts +63 -0
- package/dist/utils/compile.js +712 -36
- package/dist/utils/deployment.d.ts +2 -1
- package/dist/utils/deployment.js +16 -2
- package/dist/utils/dev-api.d.ts +42 -2
- package/dist/utils/dev-api.js +177 -4
- package/dist/utils/dev-server.d.ts +1 -1
- package/dist/utils/dev-server.js +4 -4
- package/dist/utils/dynamic-job-bundler.d.ts +17 -0
- package/dist/utils/dynamic-job-bundler.js +143 -0
- package/dist/utils/init-agent.d.ts +3 -1
- package/dist/utils/init-agent.js +6 -4
- package/dist/utils/init-prompts.d.ts +2 -1
- package/dist/utils/init-prompts.js +14 -9
- package/dist/utils/job-management.d.ts +24 -0
- package/dist/utils/job-management.js +264 -0
- package/dist/utils/postprocessor-management.d.ts +9 -0
- package/dist/utils/postprocessor-management.js +118 -0
- package/dist/utils/pre-bundle-jobs.d.ts +26 -0
- package/dist/utils/pre-bundle-jobs.js +176 -0
- package/dist/utils/preprocessor-management.d.ts +9 -0
- package/dist/utils/preprocessor-management.js +118 -0
- package/dist/utils/sandbox-storage.d.ts +48 -0
- package/dist/utils/sandbox-storage.js +114 -0
- package/dist/utils/sandbox.d.ts +61 -1
- package/dist/utils/sandbox.js +299 -72
- package/dist/utils/tool-detection.d.ts +3 -2
- package/dist/utils/tool-detection.js +18 -4
- package/dist/utils/webhook-management.d.ts +24 -0
- package/dist/utils/webhook-management.js +256 -0
- package/package.json +1 -1
- package/template/README.md +30 -2
- package/template/lua.skill.yaml +47 -0
- package/template/package-lock.json +10505 -0
- package/template/package.json +2 -1
- package/template/src/index.ts +103 -2
- package/template/src/jobs/AbandonedBasketProcessorJob.ts +139 -0
- package/template/src/jobs/DailyCleanupJob.ts +100 -0
- package/template/src/jobs/DataMigrationJob.ts +133 -0
- package/template/src/jobs/HealthCheckJob.ts +87 -0
- package/template/src/tools/CreateInlineJob.ts +42 -0
- package/template/src/tools/GameScoreTrackerTool.ts +356 -0
- package/template/src/tools/SmartBasketTool.ts +188 -0
- package/template/src/webhooks/PaymentWebhook.ts +113 -0
- package/template/src/webhooks/UserEventWebhook.ts +77 -0
- package/API_REFERENCE.md +0 -1408
- package/CHANGELOG.md +0 -236
- package/CLI_REFERENCE.md +0 -908
- package/GETTING_STARTED.md +0 -1040
- package/INSTANCE_TYPES.md +0 -1158
- package/README.md +0 -865
- package/TEMPLATE_GUIDE.md +0 -1398
- package/USER_DATA_INSTANCE.md +0 -621
- package/template/TOOL_EXAMPLES.md +0 -655
package/dist/commands/index.d.ts
CHANGED
|
@@ -19,4 +19,8 @@ export { channelsCommand } from "./channels.js";
|
|
|
19
19
|
export { logsCommand } from "./logs.js";
|
|
20
20
|
export { completionCommand } from "./completion.js";
|
|
21
21
|
export { skillsCommand } from "./skills.js";
|
|
22
|
+
export { webhooksCommand } from "./webhooks.js";
|
|
23
|
+
export { jobsCommand } from "./jobs.js";
|
|
22
24
|
export { featuresCommand } from "./features.js";
|
|
25
|
+
export { preprocessorsCommand } from "./preprocessors.js";
|
|
26
|
+
export { postprocessorsCommand } from "./postprocessors.js";
|
package/dist/commands/index.js
CHANGED
|
@@ -19,4 +19,8 @@ export { channelsCommand } from "./channels.js";
|
|
|
19
19
|
export { logsCommand } from "./logs.js";
|
|
20
20
|
export { completionCommand } from "./completion.js";
|
|
21
21
|
export { skillsCommand } from "./skills.js";
|
|
22
|
+
export { webhooksCommand } from "./webhooks.js";
|
|
23
|
+
export { jobsCommand } from "./jobs.js";
|
|
22
24
|
export { featuresCommand } from "./features.js";
|
|
25
|
+
export { preprocessorsCommand } from "./preprocessors.js";
|
|
26
|
+
export { postprocessorsCommand } from "./postprocessors.js";
|
package/dist/commands/init.js
CHANGED
|
@@ -119,7 +119,7 @@ export async function initCommand() {
|
|
|
119
119
|
}
|
|
120
120
|
else {
|
|
121
121
|
// Step 4b: Create new agent
|
|
122
|
-
const result = await createNewAgentFlow(apiKey);
|
|
122
|
+
const result = await createNewAgentFlow(apiKey, userData);
|
|
123
123
|
selectedAgent = result.agent;
|
|
124
124
|
selectedOrg = result.org;
|
|
125
125
|
persona = result.persona;
|
|
@@ -172,14 +172,59 @@ async function selectExistingAgent(userData, apiKey) {
|
|
|
172
172
|
* Handles the flow for creating a new agent.
|
|
173
173
|
*
|
|
174
174
|
* @param apiKey - User's API key
|
|
175
|
+
* @param userData - User data containing organizations
|
|
175
176
|
* @returns Created agent, organization, and optional persona/welcome message
|
|
176
177
|
*/
|
|
177
|
-
async function createNewAgentFlow(apiKey) {
|
|
178
|
+
async function createNewAgentFlow(apiKey, userData) {
|
|
178
179
|
// Fetch and select agent type
|
|
179
180
|
const agentTypes = await fetchAgentTypes(apiKey);
|
|
180
181
|
const selectedAgentType = selectBaseAgentType(agentTypes);
|
|
182
|
+
// Ask about organization selection FIRST
|
|
183
|
+
const { orgChoice } = await inquirer.prompt([
|
|
184
|
+
{
|
|
185
|
+
type: 'list',
|
|
186
|
+
name: 'orgChoice',
|
|
187
|
+
message: 'Organization:',
|
|
188
|
+
choices: [
|
|
189
|
+
{ name: 'š¢ Use existing organization', value: 'existing' },
|
|
190
|
+
{ name: 'ā Create new organization', value: 'create' }
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
]);
|
|
194
|
+
let orgId;
|
|
195
|
+
let orgName;
|
|
196
|
+
let usingExistingOrg = false;
|
|
197
|
+
if (orgChoice === 'existing') {
|
|
198
|
+
// Select from existing organizations
|
|
199
|
+
const orgs = userData.admin?.orgs || [];
|
|
200
|
+
if (orgs.length === 0) {
|
|
201
|
+
writeInfo("\nā ļø No existing organizations found. Creating new organization instead.\n");
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const selectedOrg = await promptOrganizationSelection(orgs);
|
|
205
|
+
orgId = selectedOrg.id;
|
|
206
|
+
usingExistingOrg = true;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (!orgId) {
|
|
210
|
+
// Create new organization - ask for org name
|
|
211
|
+
const { organizationName } = await inquirer.prompt([
|
|
212
|
+
{
|
|
213
|
+
type: 'input',
|
|
214
|
+
name: 'organizationName',
|
|
215
|
+
message: 'Organization name:',
|
|
216
|
+
validate: (input) => {
|
|
217
|
+
if (!input || input.trim() === '') {
|
|
218
|
+
return 'Organization name is required';
|
|
219
|
+
}
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
]);
|
|
224
|
+
orgName = organizationName.trim();
|
|
225
|
+
}
|
|
181
226
|
// Collect required metadata
|
|
182
|
-
let linesToClear =
|
|
227
|
+
let linesToClear = 2; // orgChoice + (org selection OR org name)
|
|
183
228
|
const metadata = selectedAgentType.requiredSubAgentMetadata?.length
|
|
184
229
|
? await promptMetadataCollection(selectedAgentType.requiredSubAgentMetadata)
|
|
185
230
|
: {};
|
|
@@ -190,12 +235,13 @@ async function createNewAgentFlow(apiKey) {
|
|
|
190
235
|
: {};
|
|
191
236
|
linesToClear += availableFeatures.length;
|
|
192
237
|
// Collect business configuration
|
|
193
|
-
|
|
194
|
-
|
|
238
|
+
// If using existing org, don't ask for business name (use org name)
|
|
239
|
+
const businessConfig = await promptBusinessConfiguration(usingExistingOrg);
|
|
240
|
+
linesToClear += usingExistingOrg ? 4 : 5; // Skip businessName prompt if using existing org
|
|
195
241
|
// Clear all prompts
|
|
196
242
|
clearLinesIfNeeded(linesToClear);
|
|
197
243
|
// Create the agent
|
|
198
|
-
const result = await createNewAgent(apiKey, selectedAgentType, businessConfig, metadata, features);
|
|
244
|
+
const result = await createNewAgent(apiKey, selectedAgentType, businessConfig, metadata, features, orgId, orgName);
|
|
199
245
|
return result;
|
|
200
246
|
}
|
|
201
247
|
/**
|
|
@@ -232,7 +278,7 @@ async function handleAgentSwitch(userData, apiKey, existingYaml) {
|
|
|
232
278
|
}
|
|
233
279
|
else {
|
|
234
280
|
// Create new agent
|
|
235
|
-
const result = await createNewAgentFlow(apiKey);
|
|
281
|
+
const result = await createNewAgentFlow(apiKey, userData);
|
|
236
282
|
selectedAgent = result.agent;
|
|
237
283
|
selectedOrg = result.org;
|
|
238
284
|
persona = result.persona;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jobs Command
|
|
3
|
+
* Manages agent scheduled jobs for sandbox and production environments
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Main jobs command - manages agent jobs
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - View deployed jobs
|
|
10
|
+
* - View job versions
|
|
11
|
+
* - Deploy job versions to production
|
|
12
|
+
* - Activate/deactivate, pause/resume jobs
|
|
13
|
+
* - Trigger jobs manually
|
|
14
|
+
* - View execution history
|
|
15
|
+
*
|
|
16
|
+
* Note: For local testing, use `lua test job`
|
|
17
|
+
*
|
|
18
|
+
* @returns Promise that resolves when command completes
|
|
19
|
+
*/
|
|
20
|
+
export declare function jobsCommand(): Promise<void>;
|
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jobs Command
|
|
3
|
+
* Manages agent scheduled jobs for sandbox and production environments
|
|
4
|
+
*/
|
|
5
|
+
import { loadApiKey, checkApiKey } from '../services/auth.js';
|
|
6
|
+
import { readSkillConfig } from '../utils/files.js';
|
|
7
|
+
import { withErrorHandling, writeProgress, writeSuccess, writeInfo } from '../utils/cli.js';
|
|
8
|
+
import { BASE_URLS } from '../config/constants.js';
|
|
9
|
+
import { safePrompt } from '../utils/prompt-handler.js';
|
|
10
|
+
import { validateConfig, validateAgentConfig, } from '../utils/dev-helpers.js';
|
|
11
|
+
import JobApi from '../api/job.api.service.js';
|
|
12
|
+
/**
|
|
13
|
+
* Main jobs command - manages agent jobs
|
|
14
|
+
*
|
|
15
|
+
* Features:
|
|
16
|
+
* - View deployed jobs
|
|
17
|
+
* - View job versions
|
|
18
|
+
* - Deploy job versions to production
|
|
19
|
+
* - Activate/deactivate, pause/resume jobs
|
|
20
|
+
* - Trigger jobs manually
|
|
21
|
+
* - View execution history
|
|
22
|
+
*
|
|
23
|
+
* Note: For local testing, use `lua test job`
|
|
24
|
+
*
|
|
25
|
+
* @returns Promise that resolves when command completes
|
|
26
|
+
*/
|
|
27
|
+
export async function jobsCommand() {
|
|
28
|
+
return withErrorHandling(async () => {
|
|
29
|
+
// Step 1: Load configuration
|
|
30
|
+
const config = readSkillConfig();
|
|
31
|
+
validateConfig(config);
|
|
32
|
+
validateAgentConfig(config);
|
|
33
|
+
const agentId = config.agent.agentId;
|
|
34
|
+
// Step 2: Authenticate
|
|
35
|
+
const apiKey = await loadApiKey();
|
|
36
|
+
if (!apiKey) {
|
|
37
|
+
console.error("ā No API key found. Please run 'lua auth configure' to set up your API key.");
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
await checkApiKey(apiKey);
|
|
41
|
+
writeProgress("ā
Authenticated");
|
|
42
|
+
const context = {
|
|
43
|
+
environment: 'production',
|
|
44
|
+
agentId,
|
|
45
|
+
apiKey,
|
|
46
|
+
};
|
|
47
|
+
// Start job management
|
|
48
|
+
await manageProductionJobs(context, config);
|
|
49
|
+
}, "jobs");
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Manage production jobs - view, deploy, pause/resume, trigger
|
|
53
|
+
*/
|
|
54
|
+
async function manageProductionJobs(context, config) {
|
|
55
|
+
let continueManaging = true;
|
|
56
|
+
while (continueManaging) {
|
|
57
|
+
console.log("\n" + "=".repeat(60));
|
|
58
|
+
console.log("š Production Jobs");
|
|
59
|
+
console.log("=".repeat(60) + "\n");
|
|
60
|
+
const actionAnswer = await safePrompt([
|
|
61
|
+
{
|
|
62
|
+
type: 'list',
|
|
63
|
+
name: 'action',
|
|
64
|
+
message: 'What would you like to do?',
|
|
65
|
+
choices: [
|
|
66
|
+
{ name: 'šļø View deployed jobs', value: 'view' },
|
|
67
|
+
{ name: 'š View job versions', value: 'versions' },
|
|
68
|
+
{ name: 'š Deploy a version', value: 'deploy' },
|
|
69
|
+
{ name: 'ā
Activate a job', value: 'activate' },
|
|
70
|
+
{ name: 'š« Deactivate a job', value: 'deactivate' },
|
|
71
|
+
{ name: 'ā” Trigger job now', value: 'trigger' },
|
|
72
|
+
{ name: 'š View execution history', value: 'history' },
|
|
73
|
+
{ name: 'ā Exit', value: 'exit' }
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
]);
|
|
77
|
+
if (!actionAnswer)
|
|
78
|
+
return;
|
|
79
|
+
const { action } = actionAnswer;
|
|
80
|
+
switch (action) {
|
|
81
|
+
case 'view':
|
|
82
|
+
await viewDeployedJobs(context, config);
|
|
83
|
+
break;
|
|
84
|
+
case 'versions':
|
|
85
|
+
await viewJobVersions(context, config);
|
|
86
|
+
break;
|
|
87
|
+
case 'deploy':
|
|
88
|
+
await deployJobVersion(context, config);
|
|
89
|
+
break;
|
|
90
|
+
case 'activate':
|
|
91
|
+
await activateJob(context, config);
|
|
92
|
+
break;
|
|
93
|
+
case 'deactivate':
|
|
94
|
+
await deactivateJob(context, config);
|
|
95
|
+
break;
|
|
96
|
+
case 'trigger':
|
|
97
|
+
await triggerJob(context, config);
|
|
98
|
+
break;
|
|
99
|
+
case 'history':
|
|
100
|
+
await viewExecutionHistory(context, config);
|
|
101
|
+
break;
|
|
102
|
+
case 'exit':
|
|
103
|
+
continueManaging = false;
|
|
104
|
+
console.log("\nš Goodbye!\n");
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* View deployed jobs in production
|
|
111
|
+
*/
|
|
112
|
+
async function viewDeployedJobs(context, config) {
|
|
113
|
+
writeProgress("š Loading job information...");
|
|
114
|
+
try {
|
|
115
|
+
const jobs = config.jobs || [];
|
|
116
|
+
if (jobs.length === 0) {
|
|
117
|
+
console.log("\nā¹ļø No jobs found in configuration.\n");
|
|
118
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
console.log("\n" + "=".repeat(60));
|
|
122
|
+
console.log("āļø Production Jobs");
|
|
123
|
+
console.log("=".repeat(60) + "\n");
|
|
124
|
+
for (const job of jobs) {
|
|
125
|
+
try {
|
|
126
|
+
const response = await fetch(`${BASE_URLS.API}/developer/jobs/${context.agentId}/${job.jobId}`, {
|
|
127
|
+
method: 'GET',
|
|
128
|
+
headers: {
|
|
129
|
+
'Authorization': `Bearer ${context.apiKey}`,
|
|
130
|
+
'Content-Type': 'application/json'
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
if (response.ok) {
|
|
134
|
+
const data = await response.json();
|
|
135
|
+
const jobData = data.data || data;
|
|
136
|
+
console.log(`ā° ${job.name}`);
|
|
137
|
+
console.log(` Job ID: ${job.jobId}`);
|
|
138
|
+
console.log(` Status: ${jobData.status || 'active'}`);
|
|
139
|
+
if (jobData.schedule) {
|
|
140
|
+
console.log(` Schedule: ${formatSchedule(jobData.schedule)}`);
|
|
141
|
+
}
|
|
142
|
+
if (jobData.lastRunAt) {
|
|
143
|
+
const lastRun = new Date(jobData.lastRunAt);
|
|
144
|
+
console.log(` Last Run: ${lastRun.toLocaleString()}`);
|
|
145
|
+
}
|
|
146
|
+
if (jobData.nextRunAt) {
|
|
147
|
+
const nextRun = new Date(jobData.nextRunAt);
|
|
148
|
+
console.log(` Next Run: ${nextRun.toLocaleString()}`);
|
|
149
|
+
}
|
|
150
|
+
console.log();
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
console.log(`ā° ${job.name}`);
|
|
154
|
+
console.log(` Job ID: ${job.jobId}`);
|
|
155
|
+
console.log(` Status: Unable to fetch info`);
|
|
156
|
+
console.log();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
console.log(`ā° ${job.name}`);
|
|
161
|
+
console.log(` Job ID: ${job.jobId}`);
|
|
162
|
+
console.log(` Status: Error loading info`);
|
|
163
|
+
console.log();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
console.log("=".repeat(60) + "\n");
|
|
167
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
console.error('ā Error loading job information:', error);
|
|
171
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* View all versions for a specific job
|
|
176
|
+
*/
|
|
177
|
+
async function viewJobVersions(context, config) {
|
|
178
|
+
const jobs = config.jobs || [];
|
|
179
|
+
if (jobs.length === 0) {
|
|
180
|
+
console.log("\nā¹ļø No jobs found in configuration.\n");
|
|
181
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
// Prompt to select a job
|
|
185
|
+
const jobAnswer = await safePrompt([
|
|
186
|
+
{
|
|
187
|
+
type: 'list',
|
|
188
|
+
name: 'selectedJob',
|
|
189
|
+
message: 'Select a job to view versions:',
|
|
190
|
+
choices: jobs.map((job) => ({
|
|
191
|
+
name: `${job.name} (${job.jobId})`,
|
|
192
|
+
value: job
|
|
193
|
+
}))
|
|
194
|
+
}
|
|
195
|
+
]);
|
|
196
|
+
if (!jobAnswer)
|
|
197
|
+
return;
|
|
198
|
+
const selectedJob = jobAnswer.selectedJob;
|
|
199
|
+
writeProgress(`š Loading versions for ${selectedJob.name}...`);
|
|
200
|
+
try {
|
|
201
|
+
const jobApi = new JobApi(BASE_URLS.API, context.apiKey, context.agentId);
|
|
202
|
+
const response = await jobApi.getJobVersions(selectedJob.jobId);
|
|
203
|
+
if (!response.success || !response.data) {
|
|
204
|
+
throw new Error(response.error?.message || 'Failed to fetch versions');
|
|
205
|
+
}
|
|
206
|
+
const versions = response.data.versions || [];
|
|
207
|
+
const activeVersionId = response.data.activeVersionId;
|
|
208
|
+
if (versions.length === 0) {
|
|
209
|
+
console.log(`\nā¹ļø No versions found for ${selectedJob.name}.\n`);
|
|
210
|
+
console.log("š” Push a version first using 'lua push job'.\n");
|
|
211
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
// Sort versions by date (newest first)
|
|
215
|
+
const sortedVersions = versions.sort((a, b) => {
|
|
216
|
+
const dateA = new Date(a.createdAt).getTime();
|
|
217
|
+
const dateB = new Date(b.createdAt).getTime();
|
|
218
|
+
return dateB - dateA;
|
|
219
|
+
});
|
|
220
|
+
console.log("\n" + "=".repeat(60));
|
|
221
|
+
console.log(`š Versions for ${selectedJob.name}`);
|
|
222
|
+
console.log("=".repeat(60) + "\n");
|
|
223
|
+
sortedVersions.forEach((version) => {
|
|
224
|
+
const isActive = version.jobId === activeVersionId;
|
|
225
|
+
const date = new Date(version.createdAt);
|
|
226
|
+
console.log(`${isActive ? 'ā' : ' '} Version ${version.version}`);
|
|
227
|
+
console.log(` Created: ${date.toLocaleString()}`);
|
|
228
|
+
if (version.schedule) {
|
|
229
|
+
console.log(` Schedule: ${formatSchedule(version.schedule)}`);
|
|
230
|
+
}
|
|
231
|
+
console.log();
|
|
232
|
+
});
|
|
233
|
+
console.log("=".repeat(60) + "\n");
|
|
234
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
console.error('\nā Error loading versions:', error);
|
|
238
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Deploy a job version to production
|
|
243
|
+
*/
|
|
244
|
+
async function deployJobVersion(context, config) {
|
|
245
|
+
const jobs = config.jobs || [];
|
|
246
|
+
if (jobs.length === 0) {
|
|
247
|
+
console.log("\nā¹ļø No jobs found in configuration.\n");
|
|
248
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
// Prompt to select a job
|
|
252
|
+
const jobAnswer = await safePrompt([
|
|
253
|
+
{
|
|
254
|
+
type: 'list',
|
|
255
|
+
name: 'selectedJob',
|
|
256
|
+
message: 'Select a job to deploy:',
|
|
257
|
+
choices: jobs.map((job) => ({
|
|
258
|
+
name: `${job.name} (${job.jobId})`,
|
|
259
|
+
value: job
|
|
260
|
+
}))
|
|
261
|
+
}
|
|
262
|
+
]);
|
|
263
|
+
if (!jobAnswer)
|
|
264
|
+
return;
|
|
265
|
+
const selectedJob = jobAnswer.selectedJob;
|
|
266
|
+
writeProgress(`š Loading versions for ${selectedJob.name}...`);
|
|
267
|
+
try {
|
|
268
|
+
const jobApi = new JobApi(BASE_URLS.API, context.apiKey, context.agentId);
|
|
269
|
+
const response = await jobApi.getJobVersions(selectedJob.jobId);
|
|
270
|
+
if (!response.success || !response.data) {
|
|
271
|
+
throw new Error(response.error?.message || 'Failed to fetch versions');
|
|
272
|
+
}
|
|
273
|
+
const versions = response.data.versions || [];
|
|
274
|
+
const activeVersionId = response.data.activeVersionId;
|
|
275
|
+
if (versions.length === 0) {
|
|
276
|
+
console.log(`\nā¹ļø No versions found for ${selectedJob.name}.\n`);
|
|
277
|
+
console.log("š” Push a version first using 'lua push job'.\n");
|
|
278
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
// Sort versions by date (newest first)
|
|
282
|
+
const sortedVersions = versions.sort((a, b) => {
|
|
283
|
+
const dateA = new Date(a.createdAt).getTime();
|
|
284
|
+
const dateB = new Date(b.createdAt).getTime();
|
|
285
|
+
return dateB - dateA;
|
|
286
|
+
});
|
|
287
|
+
// Prompt to select a version
|
|
288
|
+
const versionAnswer = await safePrompt([
|
|
289
|
+
{
|
|
290
|
+
type: 'list',
|
|
291
|
+
name: 'selectedVersion',
|
|
292
|
+
message: 'Select a version to deploy:',
|
|
293
|
+
choices: sortedVersions.map((version) => {
|
|
294
|
+
const isActive = version.jobId === activeVersionId;
|
|
295
|
+
const date = new Date(version.createdAt);
|
|
296
|
+
return {
|
|
297
|
+
name: `Version ${version.version} (${date.toLocaleDateString()})${isActive ? ' ā CURRENT' : ''}`,
|
|
298
|
+
value: version
|
|
299
|
+
};
|
|
300
|
+
})
|
|
301
|
+
}
|
|
302
|
+
]);
|
|
303
|
+
if (!versionAnswer)
|
|
304
|
+
return;
|
|
305
|
+
const selectedVersion = versionAnswer.selectedVersion;
|
|
306
|
+
// Show warning
|
|
307
|
+
console.log("\nā ļø WARNING: You are about to deploy to PRODUCTION!");
|
|
308
|
+
console.log("ā ļø This will affect ALL users immediately.\n");
|
|
309
|
+
console.log(`Job: ${selectedJob.name}`);
|
|
310
|
+
console.log(`Version: ${selectedVersion.version}`);
|
|
311
|
+
console.log(`Schedule: ${formatSchedule(selectedJob.schedule)}\n`);
|
|
312
|
+
const confirmAnswer = await safePrompt([
|
|
313
|
+
{
|
|
314
|
+
type: 'confirm',
|
|
315
|
+
name: 'confirm',
|
|
316
|
+
message: 'Are you absolutely sure you want to deploy this version?',
|
|
317
|
+
default: false
|
|
318
|
+
}
|
|
319
|
+
]);
|
|
320
|
+
if (!confirmAnswer || !confirmAnswer.confirm) {
|
|
321
|
+
console.log("\nā Deployment cancelled.\n");
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
writeProgress("š Deploying version...");
|
|
325
|
+
// Reuse the same jobApi instance
|
|
326
|
+
const deployResponse = await jobApi.publishJobVersion(selectedJob.jobId, selectedVersion.version);
|
|
327
|
+
if (!deployResponse.success) {
|
|
328
|
+
console.error(`\nā Deploy Error: ${deployResponse.error?.message || 'Unknown error'}\n`);
|
|
329
|
+
throw new Error(deployResponse.error?.message || 'Failed to publish job version');
|
|
330
|
+
}
|
|
331
|
+
writeSuccess(`\nā
Version ${selectedVersion.version} of "${selectedJob.name}" deployed successfully to production\n`);
|
|
332
|
+
writeInfo("š” The new version is now active and will run on schedule.");
|
|
333
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
console.error('\nā Error deploying version:', error);
|
|
337
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async function activateJob(context, config) {
|
|
341
|
+
const jobs = config.jobs || [];
|
|
342
|
+
if (jobs.length === 0) {
|
|
343
|
+
console.log("\nā¹ļø No jobs found.\n");
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const jobAnswer = await safePrompt([
|
|
347
|
+
{
|
|
348
|
+
type: 'list',
|
|
349
|
+
name: 'selectedJob',
|
|
350
|
+
message: 'Select a job to activate:',
|
|
351
|
+
choices: jobs.map((job) => ({
|
|
352
|
+
name: `${job.name} (${job.jobId})`,
|
|
353
|
+
value: job
|
|
354
|
+
}))
|
|
355
|
+
}
|
|
356
|
+
]);
|
|
357
|
+
if (!jobAnswer)
|
|
358
|
+
return;
|
|
359
|
+
writeProgress(`š Activating job "${jobAnswer.selectedJob.name}"...`);
|
|
360
|
+
const jobApi = new JobApi(BASE_URLS.API, context.apiKey, context.agentId);
|
|
361
|
+
const response = await jobApi.activateJob(jobAnswer.selectedJob.jobId);
|
|
362
|
+
if (response.success) {
|
|
363
|
+
writeSuccess(`ā
Job "${jobAnswer.selectedJob.name}" activated successfully`);
|
|
364
|
+
writeInfo("š” The job is now enabled and will run on schedule.");
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
console.error(`ā Failed to activate job: ${response.error?.message || 'Unknown error'}`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
async function deactivateJob(context, config) {
|
|
371
|
+
const jobs = config.jobs || [];
|
|
372
|
+
if (jobs.length === 0) {
|
|
373
|
+
console.log("\nā¹ļø No jobs found.\n");
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
const jobAnswer = await safePrompt([
|
|
377
|
+
{
|
|
378
|
+
type: 'list',
|
|
379
|
+
name: 'selectedJob',
|
|
380
|
+
message: 'Select a job to deactivate:',
|
|
381
|
+
choices: jobs.map((job) => ({
|
|
382
|
+
name: `${job.name} (${job.jobId})`,
|
|
383
|
+
value: job
|
|
384
|
+
}))
|
|
385
|
+
}
|
|
386
|
+
]);
|
|
387
|
+
if (!jobAnswer)
|
|
388
|
+
return;
|
|
389
|
+
// Confirm deactivation
|
|
390
|
+
const confirmAnswer = await safePrompt([
|
|
391
|
+
{
|
|
392
|
+
type: 'confirm',
|
|
393
|
+
name: 'confirm',
|
|
394
|
+
message: `Are you sure you want to deactivate "${jobAnswer.selectedJob.name}"? It will stop running on schedule.`,
|
|
395
|
+
default: false
|
|
396
|
+
}
|
|
397
|
+
]);
|
|
398
|
+
if (!confirmAnswer || !confirmAnswer.confirm) {
|
|
399
|
+
console.log("\nā Deactivation cancelled.\n");
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
writeProgress(`š Deactivating job "${jobAnswer.selectedJob.name}"...`);
|
|
403
|
+
const jobApi = new JobApi(BASE_URLS.API, context.apiKey, context.agentId);
|
|
404
|
+
const response = await jobApi.deactivateJob(jobAnswer.selectedJob.jobId);
|
|
405
|
+
if (response.success) {
|
|
406
|
+
writeSuccess(`ā
Job "${jobAnswer.selectedJob.name}" deactivated successfully`);
|
|
407
|
+
writeInfo("š” The job is now disabled and will not run.");
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
console.error(`ā Failed to deactivate job: ${response.error?.message || 'Unknown error'}`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
async function triggerJob(context, config) {
|
|
414
|
+
const jobs = config.jobs || [];
|
|
415
|
+
if (jobs.length === 0) {
|
|
416
|
+
console.log("\nā¹ļø No jobs found.\n");
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
const jobAnswer = await safePrompt([
|
|
420
|
+
{
|
|
421
|
+
type: 'list',
|
|
422
|
+
name: 'selectedJob',
|
|
423
|
+
message: 'Select a job to trigger:',
|
|
424
|
+
choices: jobs.map((job) => ({
|
|
425
|
+
name: `${job.name} (${job.jobId})`,
|
|
426
|
+
value: job
|
|
427
|
+
}))
|
|
428
|
+
}
|
|
429
|
+
]);
|
|
430
|
+
if (!jobAnswer)
|
|
431
|
+
return;
|
|
432
|
+
writeProgress("ā” Triggering job...");
|
|
433
|
+
const jobApi = new JobApi(BASE_URLS.API, context.apiKey, context.agentId);
|
|
434
|
+
const response = await jobApi.triggerJob(jobAnswer.selectedJob.jobId);
|
|
435
|
+
if (response.success && response.data) {
|
|
436
|
+
writeSuccess(`ā
Job "${jobAnswer.selectedJob.name}" triggered successfully`);
|
|
437
|
+
writeInfo(`š Execution ID: ${response.data.executionId || 'N/A'}`);
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
console.error(`ā Failed to trigger job: ${response.error?.message || 'Unknown error'}`);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* View execution history for a job
|
|
445
|
+
*/
|
|
446
|
+
async function viewExecutionHistory(context, config) {
|
|
447
|
+
const jobs = config.jobs || [];
|
|
448
|
+
if (jobs.length === 0) {
|
|
449
|
+
console.log("\nā¹ļø No jobs found in configuration.\n");
|
|
450
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
// Prompt to select a job
|
|
454
|
+
const jobAnswer = await safePrompt([
|
|
455
|
+
{
|
|
456
|
+
type: 'list',
|
|
457
|
+
name: 'selectedJob',
|
|
458
|
+
message: 'Select a job to view execution history:',
|
|
459
|
+
choices: jobs.map((job) => ({
|
|
460
|
+
name: `${job.name} (${job.jobId})`,
|
|
461
|
+
value: job
|
|
462
|
+
}))
|
|
463
|
+
}
|
|
464
|
+
]);
|
|
465
|
+
if (!jobAnswer)
|
|
466
|
+
return;
|
|
467
|
+
const selectedJob = jobAnswer.selectedJob;
|
|
468
|
+
writeProgress(`š Loading execution history for ${selectedJob.name}...`);
|
|
469
|
+
try {
|
|
470
|
+
const jobApi = new JobApi(BASE_URLS.API, context.apiKey, context.agentId);
|
|
471
|
+
const response = await jobApi.getJobExecutions(selectedJob.jobId, 20); // Get last 20 executions
|
|
472
|
+
if (!response.success || !response.data) {
|
|
473
|
+
throw new Error(response.error?.message || 'Failed to fetch execution history');
|
|
474
|
+
}
|
|
475
|
+
const executions = response.data.executions || [];
|
|
476
|
+
if (executions.length === 0) {
|
|
477
|
+
console.log(`\nā¹ļø No execution history found for ${selectedJob.name}.\n`);
|
|
478
|
+
console.log("š” The job hasn't run yet or has no recorded executions.\n");
|
|
479
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
console.log("\n" + "=".repeat(60));
|
|
483
|
+
console.log(`š Execution History for ${selectedJob.name}`);
|
|
484
|
+
console.log("=".repeat(60) + "\n");
|
|
485
|
+
executions.forEach((execution, index) => {
|
|
486
|
+
const startedAt = new Date(execution.startedAt);
|
|
487
|
+
const status = execution.status;
|
|
488
|
+
const statusEmoji = status === 'completed' ? 'ā
' :
|
|
489
|
+
status === 'failed' ? 'ā' :
|
|
490
|
+
status === 'running' ? 'š' : 'ā³';
|
|
491
|
+
console.log(`${index + 1}. ${statusEmoji} ${status.toUpperCase()}`);
|
|
492
|
+
console.log(` Execution ID: ${execution.executionId}`);
|
|
493
|
+
console.log(` Started: ${startedAt.toLocaleString()}`);
|
|
494
|
+
if (execution.completedAt) {
|
|
495
|
+
const completedAt = new Date(execution.completedAt);
|
|
496
|
+
const duration = completedAt.getTime() - startedAt.getTime();
|
|
497
|
+
console.log(` Completed: ${completedAt.toLocaleString()}`);
|
|
498
|
+
console.log(` Duration: ${Math.round(duration / 1000)}s`);
|
|
499
|
+
}
|
|
500
|
+
if (execution.result) {
|
|
501
|
+
console.log(` Result: ${JSON.stringify(execution.result).substring(0, 100)}...`);
|
|
502
|
+
}
|
|
503
|
+
if (execution.error) {
|
|
504
|
+
console.log(` Error: ${execution.error}`);
|
|
505
|
+
}
|
|
506
|
+
console.log();
|
|
507
|
+
});
|
|
508
|
+
console.log("=".repeat(60) + "\n");
|
|
509
|
+
console.log(`Showing last ${executions.length} executions\n`);
|
|
510
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
511
|
+
}
|
|
512
|
+
catch (error) {
|
|
513
|
+
console.error('\nā Error loading execution history:', error);
|
|
514
|
+
await safePrompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Format schedule object for display
|
|
519
|
+
*/
|
|
520
|
+
function formatSchedule(schedule) {
|
|
521
|
+
if (!schedule)
|
|
522
|
+
return 'Not configured';
|
|
523
|
+
switch (schedule.type) {
|
|
524
|
+
case 'cron':
|
|
525
|
+
return `Cron: ${schedule.expression}${schedule.timezone ? ` (${schedule.timezone})` : ''}`;
|
|
526
|
+
case 'once':
|
|
527
|
+
return `Once at: ${new Date(schedule.executeAt).toLocaleString()}`;
|
|
528
|
+
case 'interval':
|
|
529
|
+
return `Every ${schedule.seconds} seconds`;
|
|
530
|
+
default:
|
|
531
|
+
return 'Unknown schedule type';
|
|
532
|
+
}
|
|
533
|
+
}
|
package/dist/commands/logs.js
CHANGED
|
@@ -176,11 +176,8 @@ function displayLogs(logs, pagination, title) {
|
|
|
176
176
|
if (log.duration !== undefined) {
|
|
177
177
|
console.log(chalk.gray(` Duration: ${log.duration}ms`));
|
|
178
178
|
}
|
|
179
|
-
// Display message
|
|
180
|
-
|
|
181
|
-
? log.message.substring(0, 200) + '...'
|
|
182
|
-
: log.message;
|
|
183
|
-
console.log(` ${message}`);
|
|
179
|
+
// Display full message without truncation
|
|
180
|
+
console.log(` ${log.message}`);
|
|
184
181
|
if (index < reversedLogs.length - 1) {
|
|
185
182
|
console.log(chalk.gray(` ${'-'.repeat(78)}`));
|
|
186
183
|
}
|