lua-cli 2.5.8 → 3.0.0-alpha.1
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 +210 -0
- package/dist/api/job.api.service.js +200 -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 +98 -0
- package/dist/api/postprocessor.api.service.js +76 -0
- package/dist/api/preprocessor.api.service.d.ts +98 -0
- package/dist/api/preprocessor.api.service.js +76 -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 +156 -41
- package/dist/api-exports.js +182 -21
- package/dist/cli/command-definitions.js +75 -5
- package/dist/commands/compile.js +124 -5
- 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 +684 -5
- package/dist/commands/test.d.ts +9 -18
- package/dist/commands/test.js +558 -82
- package/dist/commands/webhooks.d.ts +18 -0
- package/dist/commands/webhooks.js +424 -0
- package/dist/common/job.instance.d.ts +77 -0
- package/dist/common/job.instance.js +108 -0
- package/dist/common/user.instance.d.ts +1 -0
- package/dist/common/user.instance.js +9 -0
- package/dist/config/constants.d.ts +2 -2
- package/dist/config/constants.js +4 -4
- package/dist/interfaces/agent.d.ts +2 -1
- package/dist/interfaces/chat.d.ts +22 -0
- package/dist/interfaces/index.d.ts +10 -0
- package/dist/interfaces/index.js +7 -0
- package/dist/interfaces/jobs.d.ts +172 -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 +502 -0
- package/dist/types/skill.js +477 -0
- package/dist/utils/agent-management.d.ts +25 -0
- package/dist/utils/agent-management.js +67 -0
- package/dist/utils/bundling.d.ts +31 -1
- package/dist/utils/bundling.js +653 -10
- package/dist/utils/compile.d.ts +63 -0
- package/dist/utils/compile.js +691 -36
- package/dist/utils/deployment.d.ts +2 -1
- package/dist/utils/deployment.js +16 -2
- 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/preprocessor-management.d.ts +9 -0
- package/dist/utils/preprocessor-management.js +118 -0
- package/dist/utils/sandbox.d.ts +61 -1
- package/dist/utils/sandbox.js +283 -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/AGENT_CONFIGURATION.md +251 -0
- package/template/COMPLEX_JOB_EXAMPLES.md +795 -0
- package/template/DYNAMIC_JOB_CREATION.md +371 -0
- package/template/README.md +30 -2
- package/template/WEBHOOKS_JOBS_QUICKSTART.md +318 -0
- package/template/WEBHOOK_JOB_EXAMPLES.md +817 -0
- package/template/src/index-agent-example.ts +201 -0
- package/template/src/index.ts +39 -0
- 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/postprocessors/ResponseFormatter.ts +151 -0
- package/template/src/preprocessors/MessageFilter.ts +91 -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
|
@@ -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
|
}
|