@cremini/skillpack 1.2.9 → 1.2.10
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/cli.js +108 -58
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,26 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/job-schedule.ts
|
|
13
|
+
function normalizeJobCron(cron2) {
|
|
14
|
+
if (typeof cron2 !== "string") {
|
|
15
|
+
return void 0;
|
|
16
|
+
}
|
|
17
|
+
const normalized = cron2.trim();
|
|
18
|
+
return normalized ? normalized : void 0;
|
|
19
|
+
}
|
|
20
|
+
function hasJobSchedule(jobOrCron) {
|
|
21
|
+
if (typeof jobOrCron === "string" || jobOrCron == null) {
|
|
22
|
+
return !!normalizeJobCron(jobOrCron);
|
|
23
|
+
}
|
|
24
|
+
return !!normalizeJobCron(jobOrCron.cron);
|
|
25
|
+
}
|
|
26
|
+
var init_job_schedule = __esm({
|
|
27
|
+
"src/job-schedule.ts"() {
|
|
28
|
+
"use strict";
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
12
32
|
// src/job-config.ts
|
|
13
33
|
import fs2 from "fs";
|
|
14
34
|
import path2 from "path";
|
|
@@ -27,9 +47,9 @@ function validateScheduledJobConfig(value, sourceLabel, index) {
|
|
|
27
47
|
`Invalid job config from ${sourceLabel}: "jobs[${index}].name" is required`
|
|
28
48
|
);
|
|
29
49
|
}
|
|
30
|
-
if (typeof job.cron !== "string"
|
|
50
|
+
if (job.cron !== void 0 && typeof job.cron !== "string") {
|
|
31
51
|
throw new Error(
|
|
32
|
-
`Invalid job config from ${sourceLabel}: "jobs[${index}].cron"
|
|
52
|
+
`Invalid job config from ${sourceLabel}: "jobs[${index}].cron" must be a string`
|
|
33
53
|
);
|
|
34
54
|
}
|
|
35
55
|
if (typeof job.prompt !== "string" || !job.prompt.trim()) {
|
|
@@ -87,18 +107,25 @@ function validateJobFileShape(value, sourceLabel) {
|
|
|
87
107
|
function normalizeJobFile(jobFile) {
|
|
88
108
|
return {
|
|
89
109
|
jobs: jobFile.jobs.map((job) => ({
|
|
90
|
-
|
|
91
|
-
cron: job.cron.trim(),
|
|
92
|
-
prompt: job.prompt,
|
|
93
|
-
notify: {
|
|
94
|
-
adapter: job.notify.adapter.trim(),
|
|
95
|
-
channelId: job.notify.channelId.trim()
|
|
96
|
-
},
|
|
97
|
-
...job.enabled !== void 0 ? { enabled: job.enabled } : {},
|
|
98
|
-
...job.timezone !== void 0 ? { timezone: job.timezone.trim() } : {}
|
|
110
|
+
...normalizeScheduledJobConfig(job)
|
|
99
111
|
}))
|
|
100
112
|
};
|
|
101
113
|
}
|
|
114
|
+
function normalizeScheduledJobConfig(job) {
|
|
115
|
+
const normalizedCron = normalizeJobCron(job.cron);
|
|
116
|
+
const normalizedTimezone = typeof job.timezone === "string" && job.timezone.trim() ? job.timezone.trim() : void 0;
|
|
117
|
+
return {
|
|
118
|
+
name: job.name.trim(),
|
|
119
|
+
...normalizedCron ? { cron: normalizedCron } : {},
|
|
120
|
+
prompt: job.prompt,
|
|
121
|
+
notify: {
|
|
122
|
+
adapter: job.notify.adapter.trim(),
|
|
123
|
+
channelId: job.notify.channelId.trim()
|
|
124
|
+
},
|
|
125
|
+
...normalizedCron && job.enabled !== void 0 ? { enabled: job.enabled } : {},
|
|
126
|
+
...normalizedCron && normalizedTimezone ? { timezone: normalizedTimezone } : {}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
102
129
|
function loadJobFile(workDir) {
|
|
103
130
|
const filePath = getJobFilePath(workDir);
|
|
104
131
|
if (!fs2.existsSync(filePath)) {
|
|
@@ -119,6 +146,7 @@ var JOB_FILE;
|
|
|
119
146
|
var init_job_config = __esm({
|
|
120
147
|
"src/job-config.ts"() {
|
|
121
148
|
"use strict";
|
|
149
|
+
init_job_schedule();
|
|
122
150
|
JOB_FILE = "job.json";
|
|
123
151
|
}
|
|
124
152
|
});
|
|
@@ -1402,11 +1430,15 @@ function isValidTimezone(tz) {
|
|
|
1402
1430
|
function isValidJobName(name) {
|
|
1403
1431
|
return VALID_JOB_NAME.test(name) && name.length <= 64;
|
|
1404
1432
|
}
|
|
1433
|
+
function isRecurringJob(jobConfig) {
|
|
1434
|
+
return hasJobSchedule(jobConfig);
|
|
1435
|
+
}
|
|
1405
1436
|
var VALID_JOB_NAME, SchedulerAdapter;
|
|
1406
1437
|
var init_scheduler = __esm({
|
|
1407
1438
|
"src/runtime/adapters/scheduler.ts"() {
|
|
1408
1439
|
"use strict";
|
|
1409
1440
|
init_job_config();
|
|
1441
|
+
init_job_schedule();
|
|
1410
1442
|
VALID_JOB_NAME = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
|
|
1411
1443
|
SchedulerAdapter = class {
|
|
1412
1444
|
name = "scheduler";
|
|
@@ -1423,10 +1455,13 @@ var init_scheduler = __esm({
|
|
|
1423
1455
|
const jobConfigs = loadJobFile(this.rootDir).jobs;
|
|
1424
1456
|
let scheduledCount = 0;
|
|
1425
1457
|
let disabledCount = 0;
|
|
1458
|
+
let oneTimeCount = 0;
|
|
1426
1459
|
for (const jc of jobConfigs) {
|
|
1427
1460
|
const result = this.registerJob(jc);
|
|
1428
1461
|
if (result.registered) {
|
|
1429
|
-
if (jc
|
|
1462
|
+
if (!isRecurringJob(jc)) {
|
|
1463
|
+
oneTimeCount++;
|
|
1464
|
+
} else if (jc.enabled === false) {
|
|
1430
1465
|
disabledCount++;
|
|
1431
1466
|
} else {
|
|
1432
1467
|
scheduledCount++;
|
|
@@ -1436,6 +1471,7 @@ var init_scheduler = __esm({
|
|
|
1436
1471
|
const parts = [];
|
|
1437
1472
|
if (scheduledCount > 0) parts.push(`${scheduledCount} active`);
|
|
1438
1473
|
if (disabledCount > 0) parts.push(`${disabledCount} disabled`);
|
|
1474
|
+
if (oneTimeCount > 0) parts.push(`${oneTimeCount} one-time`);
|
|
1439
1475
|
if (parts.length > 0) {
|
|
1440
1476
|
console.log(`[SchedulerAdapter] Started with ${parts.join(", ")} job(s)`);
|
|
1441
1477
|
} else {
|
|
@@ -1450,43 +1486,43 @@ var init_scheduler = __esm({
|
|
|
1450
1486
|
* Does NOT persist – callers decide when to persist.
|
|
1451
1487
|
*/
|
|
1452
1488
|
registerJob(jobConfig) {
|
|
1453
|
-
|
|
1454
|
-
|
|
1489
|
+
const normalizedConfig = normalizeScheduledJobConfig(jobConfig);
|
|
1490
|
+
const normalizedCron = normalizeJobCron(normalizedConfig.cron);
|
|
1491
|
+
if (!isValidJobName(normalizedConfig.name)) {
|
|
1492
|
+
const msg = `[Scheduler] Invalid job name "${normalizedConfig.name}": must match ${VALID_JOB_NAME} and be \u226464 chars`;
|
|
1455
1493
|
console.error(msg);
|
|
1456
1494
|
return { registered: false, message: msg };
|
|
1457
1495
|
}
|
|
1458
|
-
if (
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1496
|
+
if (normalizedCron) {
|
|
1497
|
+
if (!cron.validate(normalizedCron)) {
|
|
1498
|
+
const msg = `[Scheduler] Invalid cron expression for job "${normalizedConfig.name}": ${normalizedCron}`;
|
|
1499
|
+
console.error(msg);
|
|
1500
|
+
return { registered: false, message: msg };
|
|
1501
|
+
}
|
|
1502
|
+
if (normalizedConfig.timezone && !isValidTimezone(normalizedConfig.timezone)) {
|
|
1503
|
+
const msg = `[Scheduler] Invalid timezone for job "${normalizedConfig.name}": ${normalizedConfig.timezone}`;
|
|
1504
|
+
console.error(msg);
|
|
1505
|
+
return { registered: false, message: msg };
|
|
1506
|
+
}
|
|
1467
1507
|
}
|
|
1468
|
-
this.removeFromMap(
|
|
1508
|
+
this.removeFromMap(normalizedConfig.name);
|
|
1469
1509
|
let task = null;
|
|
1470
|
-
if (
|
|
1471
|
-
task =
|
|
1472
|
-
|
|
1473
|
-
()
|
|
1474
|
-
void this.runJob(jobConfig);
|
|
1475
|
-
},
|
|
1476
|
-
{
|
|
1477
|
-
timezone: jobConfig.timezone
|
|
1478
|
-
}
|
|
1510
|
+
if (normalizedCron && normalizedConfig.enabled !== false) {
|
|
1511
|
+
task = this.createCronTask(normalizedConfig);
|
|
1512
|
+
console.log(
|
|
1513
|
+
`[Scheduler] Job "${normalizedConfig.name}" scheduled: ${normalizedCron}${normalizedConfig.timezone ? ` (${normalizedConfig.timezone})` : ""}`
|
|
1479
1514
|
);
|
|
1515
|
+
} else if (normalizedCron) {
|
|
1480
1516
|
console.log(
|
|
1481
|
-
`[Scheduler] Job "${
|
|
1517
|
+
`[Scheduler] Job "${normalizedConfig.name}" registered (disabled)`
|
|
1482
1518
|
);
|
|
1483
1519
|
} else {
|
|
1484
1520
|
console.log(
|
|
1485
|
-
`[Scheduler] Job "${
|
|
1521
|
+
`[Scheduler] Job "${normalizedConfig.name}" registered as one-time (manual trigger only)`
|
|
1486
1522
|
);
|
|
1487
1523
|
}
|
|
1488
|
-
this.jobs.set(
|
|
1489
|
-
config:
|
|
1524
|
+
this.jobs.set(normalizedConfig.name, {
|
|
1525
|
+
config: normalizedConfig,
|
|
1490
1526
|
task,
|
|
1491
1527
|
running: false,
|
|
1492
1528
|
notifyFailed: false
|
|
@@ -1599,10 +1635,11 @@ var init_scheduler = __esm({
|
|
|
1599
1635
|
return { success: false, message: result.message };
|
|
1600
1636
|
}
|
|
1601
1637
|
this.persistJobs();
|
|
1602
|
-
const
|
|
1638
|
+
const recurring = isRecurringJob(jobConfig);
|
|
1639
|
+
const enabled = recurring ? jobConfig.enabled !== false : true;
|
|
1603
1640
|
return {
|
|
1604
1641
|
success: true,
|
|
1605
|
-
message: enabled ? `Job "${jobConfig.name}" created and scheduled.` : `Job "${jobConfig.name}" created (disabled).`
|
|
1642
|
+
message: recurring ? enabled ? `Job "${jobConfig.name}" created and scheduled.` : `Job "${jobConfig.name}" created (disabled).` : `Job "${jobConfig.name}" created as a one-time task.`
|
|
1606
1643
|
};
|
|
1607
1644
|
}
|
|
1608
1645
|
/**
|
|
@@ -1647,17 +1684,15 @@ var init_scheduler = __esm({
|
|
|
1647
1684
|
if (!job) {
|
|
1648
1685
|
return { success: false, message: `Job "${name}" not found.` };
|
|
1649
1686
|
}
|
|
1687
|
+
if (!isRecurringJob(job.config)) {
|
|
1688
|
+
return {
|
|
1689
|
+
success: false,
|
|
1690
|
+
message: `Job "${name}" does not have a schedule and cannot be enabled or disabled.`
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1650
1693
|
job.config.enabled = enabled;
|
|
1651
1694
|
if (enabled && !job.task) {
|
|
1652
|
-
job.task =
|
|
1653
|
-
job.config.cron,
|
|
1654
|
-
() => {
|
|
1655
|
-
void this.runJob(job.config);
|
|
1656
|
-
},
|
|
1657
|
-
{
|
|
1658
|
-
timezone: job.config.timezone
|
|
1659
|
-
}
|
|
1660
|
-
);
|
|
1695
|
+
job.task = this.createCronTask(job.config);
|
|
1661
1696
|
} else if (enabled && job.task) {
|
|
1662
1697
|
job.task.start();
|
|
1663
1698
|
} else if (!enabled && job.task) {
|
|
@@ -1703,13 +1738,13 @@ var init_scheduler = __esm({
|
|
|
1703
1738
|
for (const [, job] of this.jobs) {
|
|
1704
1739
|
result.push({
|
|
1705
1740
|
name: job.config.name,
|
|
1706
|
-
cron: job.config.cron,
|
|
1741
|
+
...job.config.cron ? { cron: job.config.cron } : {},
|
|
1707
1742
|
prompt: job.config.prompt,
|
|
1708
1743
|
notify: job.config.notify,
|
|
1709
|
-
enabled: job.config.enabled !== false,
|
|
1710
|
-
timezone: job.config.timezone,
|
|
1711
|
-
lastRunAt: job.lastRunAt,
|
|
1712
|
-
lastError: job.lastError,
|
|
1744
|
+
enabled: isRecurringJob(job.config) ? job.config.enabled !== false : true,
|
|
1745
|
+
...job.config.timezone ? { timezone: job.config.timezone } : {},
|
|
1746
|
+
...job.lastRunAt ? { lastRunAt: job.lastRunAt } : {},
|
|
1747
|
+
...job.lastError ? { lastError: job.lastError } : {},
|
|
1713
1748
|
running: job.running,
|
|
1714
1749
|
notifyFailed: job.notifyFailed
|
|
1715
1750
|
});
|
|
@@ -1749,6 +1784,21 @@ var init_scheduler = __esm({
|
|
|
1749
1784
|
this.jobs.clear();
|
|
1750
1785
|
console.log("[SchedulerAdapter] All jobs stopped.");
|
|
1751
1786
|
}
|
|
1787
|
+
createCronTask(jobConfig) {
|
|
1788
|
+
const cronExpr = normalizeJobCron(jobConfig.cron);
|
|
1789
|
+
if (!cronExpr) {
|
|
1790
|
+
throw new Error(`Job "${jobConfig.name}" does not have a valid cron expression`);
|
|
1791
|
+
}
|
|
1792
|
+
return cron.schedule(
|
|
1793
|
+
cronExpr,
|
|
1794
|
+
() => {
|
|
1795
|
+
void this.runJob(jobConfig);
|
|
1796
|
+
},
|
|
1797
|
+
{
|
|
1798
|
+
timezone: jobConfig.timezone
|
|
1799
|
+
}
|
|
1800
|
+
);
|
|
1801
|
+
}
|
|
1752
1802
|
};
|
|
1753
1803
|
}
|
|
1754
1804
|
});
|
|
@@ -4615,20 +4665,20 @@ var WebAdapter = class {
|
|
|
4615
4665
|
return;
|
|
4616
4666
|
}
|
|
4617
4667
|
const { name, cron: cronExpr, prompt, notify, enabled, timezone } = req.body;
|
|
4618
|
-
if (!name || !
|
|
4668
|
+
if (!name || !prompt || !notify?.adapter || !notify?.channelId) {
|
|
4619
4669
|
res.status(400).json({
|
|
4620
4670
|
success: false,
|
|
4621
|
-
message: "Required fields: name,
|
|
4671
|
+
message: "Required fields: name, prompt, notify.adapter, notify.channelId"
|
|
4622
4672
|
});
|
|
4623
4673
|
return;
|
|
4624
4674
|
}
|
|
4625
4675
|
const result = scheduler.addJob({
|
|
4626
4676
|
name,
|
|
4627
|
-
cron: cronExpr,
|
|
4677
|
+
...typeof cronExpr === "string" ? { cron: cronExpr } : {},
|
|
4628
4678
|
prompt,
|
|
4629
4679
|
notify,
|
|
4630
|
-
enabled
|
|
4631
|
-
timezone
|
|
4680
|
+
...typeof enabled === "boolean" ? { enabled } : {},
|
|
4681
|
+
...typeof timezone === "string" ? { timezone } : {}
|
|
4632
4682
|
});
|
|
4633
4683
|
res.json(result);
|
|
4634
4684
|
});
|