@pwddd/skills-scanner 1.0.0-beta.8 โ†’ 1.0.0-beta.9

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.
@@ -2,7 +2,7 @@
2
2
  "id": "skills-scanner",
3
3
  "name": "Skills Scanner",
4
4
  "description": "Security scanner for OpenClaw Skills to detect potential threats",
5
- "version": "1.0.0-beta.8",
5
+ "version": "1.0.0-beta.9",
6
6
  "author": "pwddd",
7
7
  "skills": ["./skills"],
8
8
  "uiHints": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pwddd/skills-scanner",
3
- "version": "1.0.0-beta.8",
3
+ "version": "1.0.0-beta.9",
4
4
  "description": "OpenClaw Skills security scanner plugin - detect malicious code, data exfiltration, and prompt injection",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -58,130 +58,51 @@ function getOpenClawCommand(): string {
58
58
  }
59
59
 
60
60
  /**
61
- * Ensure cron job exists (create if not exists, update if config changed)
61
+ * Ensure cron job exists (only cleanup, no registration)
62
62
  */
63
63
  export async function ensureCronJob(options: CronManagerOptions): Promise<void> {
64
64
  const { logger } = options;
65
65
  const openclawCmd = getOpenClawCommand();
66
66
 
67
- logger.info(`[skills-scanner] Using CLI command: ${openclawCmd}`);
67
+ logger.info(`[skills-scanner] Cleaning up old cron jobs...`);
68
68
 
69
- // Test if command is available
70
69
  try {
71
- const testResult = execSync(`${openclawCmd} --version`, {
72
- encoding: "utf-8",
73
- timeout: 5000,
74
- stdio: "pipe"
75
- });
76
- logger.info(`[skills-scanner] Command test successful: ${testResult.trim()}`);
77
- } catch (testErr: any) {
78
- logger.error(`[skills-scanner] โŒ Command not available: ${testErr.message}`);
79
- logger.info(`[skills-scanner] ๐Ÿ’ก Please ensure OpenClaw is installed and accessible`);
80
- return;
81
- }
82
-
83
- try {
84
- // Get cron list output (text format)
85
- const listResult = execSync(`${openclawCmd} cron list`, {
86
- encoding: "utf-8",
87
- timeout: 5000,
88
- });
89
-
90
- // Parse text output to find existing jobs
91
- const lines = listResult.split("\n");
92
- const existingJobs: Array<{ id: string; name: string }> = [];
93
-
94
- for (const line of lines) {
95
- if (line.includes(CRON_JOB_NAME)) {
96
- const uuidMatch = line.match(/^([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/);
97
- if (uuidMatch) {
98
- existingJobs.push({ id: uuidMatch[1], name: CRON_JOB_NAME });
99
- }
70
+ // Use shell pipeline to get job IDs
71
+ const jobIds = execSync(
72
+ `${openclawCmd} cron list | grep ${CRON_JOB_NAME} | awk '{print $1}'`,
73
+ {
74
+ encoding: "utf-8",
75
+ timeout: 30000,
76
+ shell: "/bin/bash",
100
77
  }
101
- }
78
+ ).trim();
102
79
 
103
- // If any jobs exist, remove ALL of them and create a fresh one
104
- if (existingJobs.length > 0) {
105
- logger.info(`[skills-scanner] Found ${existingJobs.length} existing job(s), cleaning up...`);
106
-
107
- // Remove all existing jobs
108
- for (const job of existingJobs) {
109
- const jobId = job.id;
110
- try {
111
- execSync(`${openclawCmd} cron remove ${jobId}`, {
112
- encoding: "utf-8",
113
- timeout: 5000,
114
- });
115
- logger.info(`[skills-scanner] โœ… Removed job: ${jobId}`);
116
- } catch (removeErr: any) {
117
- logger.warn(`[skills-scanner] โš ๏ธ Failed to remove job ${jobId}: ${removeErr.message}`);
118
- }
119
- }
80
+ if (!jobIds) {
81
+ logger.info(`[skills-scanner] No old cron jobs to remove`);
82
+ return;
120
83
  }
121
84
 
122
- logger.info("[skills-scanner] ๐Ÿ“ Creating cron job via CLI...");
123
-
124
- // Create cron job with --announce and --channel last
125
- const cronCmd = [
126
- `${openclawCmd} cron add`,
127
- `--name "${CRON_JOB_NAME}"`,
128
- `--cron "${CRON_SCHEDULE}"`,
129
- `--tz "${CRON_TIMEZONE}"`,
130
- "--session isolated",
131
- '--message "่ฏทๆ‰ง่กŒ /skills-scanner scan --report ๅนถๅฐ†็ป“ๆžœๅ‘้€ๅˆฐๆœฌ้ข‘้“"',
132
- "--announce",
133
- "--channel last",
134
- ].join(" ");
135
-
136
- logger.info(`[skills-scanner] Executing: ${cronCmd}`);
137
-
138
- const result = execSync(cronCmd, { encoding: "utf-8", timeout: 10000 });
139
-
140
- const jobIdMatch =
141
- result.match(/Job ID[:\s]+([a-zA-Z0-9-]+)/i) ||
142
- result.match(/jobId[:\s]+([a-zA-Z0-9-]+)/i) ||
143
- result.match(/id[:\s]+([a-zA-Z0-9-]+)/i);
144
-
145
- if (jobIdMatch) {
146
- const cronJobId = jobIdMatch[1];
147
- logger.info(`[skills-scanner] โœ… Job created successfully: ${cronJobId}`);
148
- logger.info(`[skills-scanner] ๐Ÿ“… Schedule: Every Monday at 12:05 (${CRON_TIMEZONE})`);
149
- logger.info("[skills-scanner] ๐Ÿ“ฌ Reports will be delivered to the last active channel");
150
- } else {
151
- logger.info("[skills-scanner] โœ… Job creation command executed");
152
- logger.debug(`[skills-scanner] Output: ${result.trim()}`);
153
- }
154
- } catch (err: any) {
155
- logger.warn("[skills-scanner] โš ๏ธ Auto-registration failed");
156
- logger.warn(`[skills-scanner] Error: ${err.message || err}`);
85
+ const ids = jobIds.split("\n").filter(id => id.trim());
86
+ logger.info(`[skills-scanner] Found ${ids.length} job(s) to remove`);
157
87
 
158
- if (err.stderr) {
159
- logger.warn(`[skills-scanner] stderr: ${err.stderr}`);
160
- }
161
- if (err.stdout) {
162
- logger.warn(`[skills-scanner] stdout: ${err.stdout}`);
88
+ // Remove each job
89
+ let successCount = 0;
90
+ for (const jobId of ids) {
91
+ try {
92
+ execSync(`${openclawCmd} cron remove ${jobId}`, {
93
+ encoding: "utf-8",
94
+ timeout: 10000,
95
+ });
96
+ logger.info(`[skills-scanner] โœ… Removed job: ${jobId}`);
97
+ successCount++;
98
+ } catch (removeErr: any) {
99
+ logger.warn(`[skills-scanner] โš ๏ธ Failed to remove job ${jobId}: ${removeErr.message}`);
100
+ }
163
101
  }
164
102
 
165
- if (err.message.includes("permission") || err.message.includes("EACCES")) {
166
- logger.error("[skills-scanner] โŒ Permission denied, please run with admin privileges");
167
- } else if (
168
- err.message.includes("command not found") ||
169
- err.message.includes("ENOENT")
170
- ) {
171
- logger.error(`[skills-scanner] โŒ ${openclawCmd} command not found, please check installation`);
172
- } else {
173
- logger.info("[skills-scanner] ๐Ÿ’ก Please manually register cron job:");
174
- logger.info("[skills-scanner]");
175
- logger.info(`[skills-scanner] ${openclawCmd} cron add \\`);
176
- logger.info(`[skills-scanner] --name "${CRON_JOB_NAME}" \\`);
177
- logger.info(`[skills-scanner] --cron "${CRON_SCHEDULE}" \\`);
178
- logger.info(`[skills-scanner] --tz "${CRON_TIMEZONE}" \\`);
179
- logger.info("[skills-scanner] --session isolated \\");
180
- logger.info('[skills-scanner] --message "่ฏทๆ‰ง่กŒ /skills-scanner scan --report ๅนถๅฐ†็ป“ๆžœๅ‘้€ๅˆฐๆœฌ้ข‘้“" \\');
181
- logger.info("[skills-scanner] --announce \\");
182
- logger.info("[skills-scanner] --channel last");
183
- logger.info("[skills-scanner]");
184
- }
103
+ logger.info(`[skills-scanner] โœ… Cleanup complete: ${successCount}/${ids.length} removed`);
104
+ } catch (err: any) {
105
+ logger.warn(`[skills-scanner] โš ๏ธ Cleanup failed: ${err.message}`);
185
106
  }
186
107
  }
187
108
 
@@ -195,10 +116,10 @@ export async function cleanupCronJob(options: CronManagerOptions): Promise<void>
195
116
  logger.info(`[skills-scanner] ๐Ÿ—‘๏ธ Cleaning up cron job: ${CRON_JOB_NAME}`);
196
117
 
197
118
  try {
198
- // Get cron list output (text format)
119
+ // Get cron list output (text format) - increase timeout for large lists
199
120
  const listResult = execSync(`${openclawCmd} cron list`, {
200
121
  encoding: "utf-8",
201
- timeout: 5000,
122
+ timeout: 30000, // 30 seconds for large lists
202
123
  });
203
124
 
204
125
  if (!listResult.includes(CRON_JOB_NAME)) {