@pwddd/skills-scanner 3.0.11 → 3.0.13
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/index.ts +2 -4
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/commands.ts +1 -1
- package/src/cron.ts +140 -12
package/index.ts
CHANGED
|
@@ -171,7 +171,8 @@ export default function register(api: OpenClawPluginApi) {
|
|
|
171
171
|
// Register cron job (only in Gateway mode)
|
|
172
172
|
const isGatewayMode = !!(api as any).runtime;
|
|
173
173
|
if (isGatewayMode) {
|
|
174
|
-
|
|
174
|
+
const runtime = (api as any).runtime;
|
|
175
|
+
await ensureCronJob(api.logger, runtime);
|
|
175
176
|
}
|
|
176
177
|
|
|
177
178
|
api.logger.info("[skills-scanner] ─────────────────────────────────────");
|
|
@@ -396,6 +397,3 @@ export default function register(api: OpenClawPluginApi) {
|
|
|
396
397
|
|
|
397
398
|
api.logger.info("[skills-scanner] ✅ Plugin registered");
|
|
398
399
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/src/commands.ts
CHANGED
package/src/cron.ts
CHANGED
|
@@ -9,16 +9,123 @@ const CRON_JOB_NAME = "skills-daily-report";
|
|
|
9
9
|
const CRON_SCHEDULE = "0 8 * * *";
|
|
10
10
|
const CRON_TIMEZONE = "Asia/Shanghai";
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Detect the correct OpenClaw command (openclaw vs npx openclaw)
|
|
14
|
+
*/
|
|
15
|
+
function getOpenClawCommand(): string {
|
|
16
|
+
// 1. Check environment variable
|
|
17
|
+
if (process.env.OPENCLAW_CLI_PATH) {
|
|
18
|
+
return process.env.OPENCLAW_CLI_PATH;
|
|
19
|
+
}
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
// 2. Check if running via npx
|
|
22
|
+
const argv1 = process.argv[1];
|
|
23
|
+
if (argv1?.includes("npx") || argv1?.includes("_npx")) {
|
|
24
|
+
return "npx openclaw";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (process.env.npm_execpath?.includes("npx")) {
|
|
28
|
+
return "npx openclaw";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 3. Try global openclaw command
|
|
32
|
+
try {
|
|
33
|
+
execSync("openclaw --version", {
|
|
34
|
+
encoding: "utf-8",
|
|
35
|
+
timeout: 3000,
|
|
36
|
+
stdio: "pipe"
|
|
37
|
+
});
|
|
38
|
+
return "openclaw";
|
|
39
|
+
} catch {
|
|
40
|
+
// openclaw command not available
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 4. Try npx as fallback
|
|
44
|
+
try {
|
|
45
|
+
execSync("npx openclaw --version", {
|
|
46
|
+
encoding: "utf-8",
|
|
47
|
+
timeout: 5000,
|
|
48
|
+
stdio: "pipe"
|
|
49
|
+
});
|
|
50
|
+
return "npx openclaw";
|
|
51
|
+
} catch {
|
|
52
|
+
// npx also not available
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 5. Default to openclaw (will fail with clear error)
|
|
56
|
+
return "openclaw";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Create cron job via Gateway API (most reliable)
|
|
61
|
+
*/
|
|
62
|
+
async function ensureCronJobViaAPI(runtime: any, logger: any): Promise<boolean> {
|
|
63
|
+
if (!runtime?.cron) {
|
|
64
|
+
logger.debug("[skills-scanner] Cron API not available");
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const state = loadState() as any;
|
|
70
|
+
|
|
71
|
+
// Check if job already exists
|
|
72
|
+
const jobs = await runtime.cron.list({ includeDisabled: true });
|
|
73
|
+
const existing = jobs.find((j: any) => j.name === CRON_JOB_NAME);
|
|
74
|
+
|
|
75
|
+
if (existing) {
|
|
76
|
+
logger.info(`[skills-scanner] ✅ Job already exists: ${existing.id}`);
|
|
77
|
+
if (state.cronJobId !== existing.id) {
|
|
78
|
+
saveState({ ...state, cronJobId: existing.id });
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Create new job
|
|
84
|
+
logger.info("[skills-scanner] 📝 Creating cron job via API...");
|
|
85
|
+
const job = await runtime.cron.add({
|
|
86
|
+
name: CRON_JOB_NAME,
|
|
87
|
+
enabled: true,
|
|
88
|
+
schedule: {
|
|
89
|
+
kind: "cron",
|
|
90
|
+
expr: CRON_SCHEDULE,
|
|
91
|
+
tz: CRON_TIMEZONE
|
|
92
|
+
},
|
|
93
|
+
payload: {
|
|
94
|
+
kind: "agentTurn",
|
|
95
|
+
message: "Please run /skills-scanner scan --report and send results to this channel"
|
|
96
|
+
},
|
|
97
|
+
delivery: {
|
|
98
|
+
mode: "announce",
|
|
99
|
+
channel: "last"
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
saveState({ ...state, cronJobId: job.id });
|
|
104
|
+
logger.info(`[skills-scanner] ✅ Job created successfully via API: ${job.id}`);
|
|
105
|
+
logger.info(
|
|
106
|
+
`[skills-scanner] 📅 Schedule: Daily at ${CRON_SCHEDULE.split(" ")[1]}:${CRON_SCHEDULE.split(" ")[0]} (${CRON_TIMEZONE})`
|
|
107
|
+
);
|
|
108
|
+
logger.info("[skills-scanner] 📬 Reports will be delivered to the last active channel");
|
|
109
|
+
return true;
|
|
110
|
+
} catch (err: any) {
|
|
111
|
+
logger.warn(`[skills-scanner] API creation failed: ${err.message}`);
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Create cron job via CLI (fallback)
|
|
118
|
+
*/
|
|
119
|
+
async function ensureCronJobViaCLI(logger: any): Promise<void> {
|
|
120
|
+
const openclawCmd = getOpenClawCommand();
|
|
121
|
+
logger.info(`[skills-scanner] Using CLI command: ${openclawCmd}`);
|
|
122
|
+
|
|
123
|
+
const state = loadState() as any;
|
|
17
124
|
|
|
18
125
|
try {
|
|
19
126
|
let jobs: any[] = [];
|
|
20
127
|
try {
|
|
21
|
-
const listResult = execSync(
|
|
128
|
+
const listResult = execSync(`${openclawCmd} cron list --format json`, {
|
|
22
129
|
encoding: "utf-8",
|
|
23
130
|
timeout: 5000,
|
|
24
131
|
});
|
|
@@ -26,7 +133,7 @@ export async function ensureCronJob(logger: any): Promise<void> {
|
|
|
26
133
|
} catch (listErr: any) {
|
|
27
134
|
logger.debug("[skills-scanner] JSON format not supported, trying text parsing");
|
|
28
135
|
try {
|
|
29
|
-
const listResult = execSync(
|
|
136
|
+
const listResult = execSync(`${openclawCmd} cron list`, {
|
|
30
137
|
encoding: "utf-8",
|
|
31
138
|
timeout: 5000,
|
|
32
139
|
});
|
|
@@ -57,7 +164,7 @@ export async function ensureCronJob(logger: any): Promise<void> {
|
|
|
57
164
|
for (let i = 1; i < existingJobs.length; i++) {
|
|
58
165
|
const jobId = existingJobs[i].id || existingJobs[i].jobId;
|
|
59
166
|
try {
|
|
60
|
-
execSync(
|
|
167
|
+
execSync(`${openclawCmd} cron remove ${jobId}`, {
|
|
61
168
|
encoding: "utf-8",
|
|
62
169
|
timeout: 5000,
|
|
63
170
|
});
|
|
@@ -82,7 +189,7 @@ export async function ensureCronJob(logger: any): Promise<void> {
|
|
|
82
189
|
if (needsUpdate) {
|
|
83
190
|
logger.info(`[skills-scanner] 🔄 Job config changed, updating...`);
|
|
84
191
|
try {
|
|
85
|
-
execSync(
|
|
192
|
+
execSync(`${openclawCmd} cron remove ${jobId}`, {
|
|
86
193
|
encoding: "utf-8",
|
|
87
194
|
timeout: 5000,
|
|
88
195
|
});
|
|
@@ -106,12 +213,12 @@ export async function ensureCronJob(logger: any): Promise<void> {
|
|
|
106
213
|
}
|
|
107
214
|
}
|
|
108
215
|
|
|
109
|
-
logger.info("[skills-scanner] 📝 Creating cron job...");
|
|
216
|
+
logger.info("[skills-scanner] 📝 Creating cron job via CLI...");
|
|
110
217
|
|
|
111
218
|
// Create cron job with --announce and --channel last
|
|
112
219
|
// This will deliver to the last place the agent replied
|
|
113
220
|
const cronCmd = [
|
|
114
|
-
|
|
221
|
+
`${openclawCmd} cron add`,
|
|
115
222
|
`--name "${CRON_JOB_NAME}"`,
|
|
116
223
|
`--cron "${CRON_SCHEDULE}"`,
|
|
117
224
|
`--tz "${CRON_TIMEZONE}"`,
|
|
@@ -151,11 +258,11 @@ export async function ensureCronJob(logger: any): Promise<void> {
|
|
|
151
258
|
err.message.includes("command not found") ||
|
|
152
259
|
err.message.includes("ENOENT")
|
|
153
260
|
) {
|
|
154
|
-
logger.error(
|
|
261
|
+
logger.error(`[skills-scanner] ❌ ${openclawCmd} command not found, please check installation`);
|
|
155
262
|
} else {
|
|
156
263
|
logger.info("[skills-scanner] 💡 Please manually register cron job:");
|
|
157
264
|
logger.info("[skills-scanner]");
|
|
158
|
-
logger.info(
|
|
265
|
+
logger.info(`[skills-scanner] ${openclawCmd} cron add \\`);
|
|
159
266
|
logger.info(`[skills-scanner] --name "${CRON_JOB_NAME}" \\`);
|
|
160
267
|
logger.info(`[skills-scanner] --cron "${CRON_SCHEDULE}" \\`);
|
|
161
268
|
logger.info(`[skills-scanner] --tz "${CRON_TIMEZONE}" \\`);
|
|
@@ -172,3 +279,24 @@ export async function ensureCronJob(logger: any): Promise<void> {
|
|
|
172
279
|
}
|
|
173
280
|
}
|
|
174
281
|
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Ensure cron job exists (tries API first, falls back to CLI)
|
|
285
|
+
*/
|
|
286
|
+
export async function ensureCronJob(logger: any, runtime?: any): Promise<void> {
|
|
287
|
+
logger.info("[skills-scanner] ─────────────────────────────────────");
|
|
288
|
+
logger.info("[skills-scanner] 🕐 Checking cron job...");
|
|
289
|
+
|
|
290
|
+
// Try API first (most reliable)
|
|
291
|
+
if (runtime) {
|
|
292
|
+
const success = await ensureCronJobViaAPI(runtime, logger);
|
|
293
|
+
if (success) {
|
|
294
|
+
logger.info("[skills-scanner] ✅ Cron job configured via API");
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
logger.info("[skills-scanner] Falling back to CLI method...");
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Fallback to CLI
|
|
301
|
+
await ensureCronJobViaCLI(logger);
|
|
302
|
+
}
|