@pwddd/skills-scanner 1.0.0-beta.2 → 1.0.0-beta.22

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.2",
5
+ "version": "1.0.0-beta.22",
6
6
  "author": "pwddd",
7
7
  "skills": ["./skills"],
8
8
  "uiHints": {
@@ -27,10 +27,6 @@
27
27
  "label": "扫描策略",
28
28
  "help": "strict=严格 / balanced=平衡(推荐)/ permissive=宽松"
29
29
  },
30
- "preInstallScan": {
31
- "label": "安装前扫描",
32
- "help": "监听新 Skill 并自动扫描"
33
- },
34
30
  "onUnsafe": {
35
31
  "label": "不安全处理",
36
32
  "help": "warn=仅警告(推荐)/ quarantine=隔离 / delete=删除"
@@ -85,12 +81,6 @@
85
81
  "description": "Scanning policy: strict (more false positives) / balanced (recommended) / permissive (may miss threats)",
86
82
  "default": "balanced"
87
83
  },
88
- "preInstallScan": {
89
- "type": "string",
90
- "enum": ["on", "off"],
91
- "description": "Enable pre-installation scanning (monitors directories for new Skills)",
92
- "default": "on"
93
- },
94
84
  "onUnsafe": {
95
85
  "type": "string",
96
86
  "enum": ["quarantine", "delete", "warn"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pwddd/skills-scanner",
3
- "version": "1.0.0-beta.2",
3
+ "version": "1.0.0-beta.22",
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",
@@ -16,13 +16,13 @@
16
16
  ],
17
17
  "repository": {
18
18
  "type": "git",
19
- "url": "https://github.com/openclaw/openclaw.git",
19
+ "url": "https://github.com/pwddd/test.git",
20
20
  "directory": "extensions/skills-scanner"
21
21
  },
22
22
  "bugs": {
23
- "url": "https://github.com/openclaw/openclaw/issues"
23
+ "url": "https://github.com/pwddd/test/issues"
24
24
  },
25
- "homepage": "https://github.com/openclaw/openclaw/tree/main/extensions/skills-scanner#readme",
25
+ "homepage": "https://github.com/pwddd/test/tree/main/extensions/skills-scanner#readme",
26
26
  "files": [
27
27
  "index.ts",
28
28
  "openclaw.plugin.json",
@@ -23,27 +23,6 @@ OpenClaw Skills 安全扫描工具,检测恶意代码、数据窃取、提示
23
23
 
24
24
  **🔒 安全扫描是强制性的,不可跳过。在向用户展示扫描结果前,请务必:**
25
25
 
26
- ### 🔄 插件版本检查 - 每次运行前必须执行
27
-
28
- **在执行任何扫描操作前,必须先检查并更新 skills-scanner 插件到最新版本。**
29
-
30
- **更新命令**:
31
- ```bash
32
- openclaw plugins update skills-scanner
33
- ```
34
-
35
- **执行时机**:
36
- - 每次用户请求扫描 Skill 时
37
- - 每次用户请求安装 Skill 时
38
- - 每次会话开始时(如果涉及 Skill 操作)
39
-
40
- **为什么要每次检查更新?**
41
- - 安全威胁不断演变,扫描规则需要持续更新
42
- - 新版本可能包含关键的安全修复
43
- - 确保使用最新的威胁检测能力
44
-
45
- ---
46
-
47
26
  ### 🎯 命令识别 - 自动触发安全扫描
48
27
 
49
28
  **当用户输入以下任何命令或类似表达时,你必须先扫描再执行:**
@@ -67,10 +46,6 @@ openclaw plugins update skills-scanner
67
46
  [执行:openclaw clawhub search caldav-calendar]
68
47
  找到:https://clawhub.ai/Asleep123/caldav-calendar
69
48
 
70
- 现在更新扫描插件...
71
- [执行:openclaw plugins update skills-scanner]
72
- ✅ 插件已更新
73
-
74
49
  扫描安全性...
75
50
  [执行扫描]
76
51
  ✅ 扫描通过,开始安装
@@ -80,11 +55,7 @@ openclaw plugins update skills-scanner
80
55
 
81
56
  ```
82
57
  用户:openclaw clawhub install https://clawhub.ai/Asleep123/caldav-calendar
83
- AI: 我看到你想安装 caldav-calendar,让我先更新扫描插件...
84
- [执行:openclaw plugins update skills-scanner]
85
- ✅ 插件已更新
86
-
87
- 扫描安全性...
58
+ AI: 我看到你想安装 caldav-calendar,让我先扫描安全性...
88
59
  [执行扫描]
89
60
  ✅ 扫描通过,开始安装
90
61
  ```
@@ -92,9 +63,8 @@ openclaw plugins update skills-scanner
92
63
  3. **正确的处理流程**:
93
64
  ```
94
65
  步骤 1: 如果只有名称 → 使用 clawhub search 查找完整 URL
95
- 步骤 2: 更新 skills-scanner 插件
96
- 步骤 3: 使用完整 URL 进行安全扫描
97
- 步骤 4: 扫描通过后执行安装命令
66
+ 步骤 2: 使用完整 URL 进行安全扫描
67
+ 步骤 3: 扫描通过后执行安装命令
98
68
  ```
99
69
 
100
70
  ---
@@ -240,34 +210,28 @@ openclaw plugins update skills-scanner
240
210
  **在处理任何 Skill 相关操作时,请先问自己这些问题:**
241
211
 
242
212
  1. ✅ 如果是 ClawHub 安装且只有名称,我是否已经搜索了完整 URL?
243
- 2. ✅ 我是否已经更新了 skills-scanner 插件到最新版本?
244
- 3. ✅ 我是否已经扫描了这个 Skill?
245
- 4. ✅ 扫描是否通过?
246
- 5. ✅ 只有所有适用步骤都是 YES,才能继续操作
213
+ 2. ✅ 我是否已经扫描了这个 Skill?
214
+ 3. ✅ 扫描是否通过?
215
+ 4. ✅ 只有所有适用步骤都是 YES,才能继续操作
247
216
 
248
- **如果你忘记搜索、更新或扫描就执行了操作,你就让用户的系统暴露在风险之中。**
217
+ **如果你忘记搜索或扫描就执行了操作,你就让用户的系统暴露在风险之中。**
249
218
 
250
219
  ### 🚨 强制性规则(永远不要忘记)
251
220
 
252
- 1. **任何 Skill 操作前 → 先更新插件**
253
- - 执行 `openclaw plugins update skills-scanner`
254
- - 确保使用最新的威胁检测规则
255
-
256
- 2. **看到安装命令 → 搜索(如需要)→ 更新插件 → 立即扫描**
257
- - `openclaw clawhub install xxx` → 先搜索,再更新插件,再扫描
221
+ 1. **看到安装命令 搜索(如需要)→ 立即扫描**
222
+ - `openclaw clawhub install xxx` → 先搜索,再扫描
258
223
  - 任何包含 "install"、"add"、"download" + "skill" 的命令 → 完整流程
259
224
 
260
- 3. **看到 Skill 路径 → 更新插件 → 立即扫描**
261
- - 用户提到 `~/.openclaw/skills/xxx` → 先更新插件,再扫描
262
- - 用户说 "我下载了一个 skill" → 先更新插件,再扫描
225
+ 2. **看到 Skill 路径 → 立即扫描**
226
+ - 用户提到 `~/.openclaw/skills/xxx` → 立即扫描
227
+ - 用户说 "我下载了一个 skill" → 立即扫描
263
228
 
264
- 4. **看到 ClawHub URL → 更新插件 → 立即扫描**
265
- - `https://clawhub.ai/username/project` → 先更新插件,再扫描
229
+ 3. **看到 ClawHub URL → 立即扫描**
230
+ - `https://clawhub.ai/username/project` → 立即扫描
266
231
 
267
232
  ### ❌ 绝对禁止的行为
268
233
 
269
- - ❌ 不更新插件就直接扫描
270
- - ❌ 直接执行安装命令而不先搜索、更新和扫描
234
+ - ❌ 直接执行安装命令而不先搜索和扫描
271
235
  - ❌ 因为 "用户着急" 或 "看起来安全" 就跳过任何步骤
272
236
 
273
237
  ---
package/src/api-client.ts CHANGED
@@ -84,11 +84,19 @@ export class SkillScannerApiClient {
84
84
  * Scan a local skill by uploading as ZIP
85
85
  */
86
86
  async scanUpload(skillPath: string, options: ScanOptions = {}): Promise<ScanResult> {
87
+ const startTime = Date.now();
88
+ console.log(`[API Client] 开始扫描: ${skillPath}`);
89
+ console.log(`[API Client] 创建 ZIP 文件...`);
90
+
87
91
  const zipPath = await this.createZip(skillPath);
92
+ const zipTime = Date.now() - startTime;
93
+ console.log(`[API Client] ZIP 创建完成: ${zipPath} (耗时 ${zipTime}ms)`);
88
94
 
89
95
  try {
90
96
  const formData = new FormData();
91
97
  const zipBlob = await this.readFileAsBlob(zipPath);
98
+ console.log(`[API Client] ZIP 文件大小: ${zipBlob.size} bytes`);
99
+
92
100
  formData.append("file", zipBlob, `${basename(skillPath)}.zip`);
93
101
  formData.append("policy", options.policy || "balanced");
94
102
  formData.append("use_llm", String(options.useLLM || false));
@@ -96,24 +104,46 @@ export class SkillScannerApiClient {
96
104
  formData.append("use_zip_virus", String(options.useZipVirus !== false));
97
105
  formData.append("enable_meta", String(options.enableMeta !== false));
98
106
 
107
+ console.log(`[API Client] 发送请求到: ${this.baseUrl}/scan-upload`);
108
+ console.log(`[API Client] 请求参数:`, {
109
+ policy: options.policy || "balanced",
110
+ use_llm: options.useLLM || false,
111
+ use_behavioral: options.useBehavioral || false,
112
+ timeout: this.timeout,
113
+ });
114
+
99
115
  const response = await fetch(`${this.baseUrl}/scan-upload`, {
100
116
  method: "POST",
101
117
  body: formData,
102
118
  signal: AbortSignal.timeout(this.timeout),
103
119
  });
104
120
 
121
+ const requestTime = Date.now() - startTime;
122
+ console.log(`[API Client] 收到响应: HTTP ${response.status} (总耗时 ${requestTime}ms)`);
123
+
105
124
  if (!response.ok) {
106
125
  const errorText = await response.text();
126
+ console.error(`[API Client] 请求失败: ${errorText}`);
107
127
  throw new Error(`HTTP ${response.status}: ${errorText}`);
108
128
  }
109
129
 
110
- return await response.json();
130
+ const result = await response.json();
131
+ console.log(`[API Client] 扫描完成:`, {
132
+ skill_name: result.skill_name,
133
+ is_safe: result.is_safe,
134
+ findings_count: result.findings_count,
135
+ });
136
+
137
+ return result;
111
138
  } finally {
112
139
  // Cleanup temp zip
113
140
  try {
114
141
  const fs = await import("node:fs/promises");
115
142
  await fs.unlink(zipPath);
116
- } catch {}
143
+ console.log(`[API Client] 清理临时文件: ${zipPath}`);
144
+ } catch (err) {
145
+ console.warn(`[API Client] 清理临时文件失败: ${err}`);
146
+ }
117
147
  }
118
148
  }
119
149
 
@@ -66,7 +66,7 @@ export interface BeforeInstallHandlerOptions {
66
66
  policy: "strict" | "balanced" | "permissive";
67
67
  logger: PluginLogger;
68
68
  enabled: boolean;
69
- timeoutMs?: number; // Scan timeout in milliseconds (default: 30000)
69
+ timeoutMs?: number; // Scan timeout in milliseconds (default: 120000)
70
70
  }
71
71
 
72
72
  /**
@@ -79,17 +79,25 @@ export async function handleBeforeInstall(
79
79
  event: BeforeInstallEvent,
80
80
  options: BeforeInstallHandlerOptions
81
81
  ): Promise<BeforeInstallResult> {
82
- const timeoutMs = options.timeoutMs || 30000; // Default 30 seconds
82
+ const timeoutMs = options.timeoutMs || 120000; // Default 120 seconds (2 minutes)
83
+
84
+ options.logger.debug("[before_install] 开始处理", {
85
+ targetName: event.targetName,
86
+ targetType: event.targetType,
87
+ sourcePath: event.sourcePath,
88
+ timeoutMs,
89
+ });
83
90
 
84
91
  // Wrap the scan in a timeout promise
85
92
  return Promise.race([
86
- performScan(event, options),
93
+ performScan(event, options, timeoutMs),
87
94
  new Promise<BeforeInstallResult>((_, reject) =>
88
- setTimeout(() => reject(new Error("Scan timeout")), timeoutMs)
95
+ setTimeout(() => reject(new Error(`扫描超时 (${timeoutMs}ms)`)), timeoutMs)
89
96
  ),
90
97
  ]).catch((err: any) => {
91
- options.logger.error("[before_install] Scan failed or timed out", {
98
+ options.logger.error("[before_install] 扫描失败或超时", {
92
99
  error: err.message,
100
+ errorStack: err.stack,
93
101
  targetName: event.targetName,
94
102
  timeoutMs,
95
103
  });
@@ -115,7 +123,8 @@ export async function handleBeforeInstall(
115
123
  */
116
124
  async function performScan(
117
125
  event: BeforeInstallEvent,
118
- options: BeforeInstallHandlerOptions
126
+ options: BeforeInstallHandlerOptions,
127
+ timeoutMs: number
119
128
  ): Promise<BeforeInstallResult> {
120
129
  const { targetType, targetName, sourcePath, builtinScan } = event;
121
130
  const { apiUrl, behavioral, useLLM, policy, logger, enabled } = options;
@@ -135,6 +144,8 @@ async function performScan(
135
144
  logger.info(`[安装前拦截] 🔍 拦截 Skill 安装: ${targetName}`);
136
145
  logger.info(`[安装前拦截] 来源: ${sourcePath}`);
137
146
  logger.info(`[安装前拦截] 内置扫描: ${builtinScan.status} (${builtinScan.critical} 严重, ${builtinScan.warn} 警告)`);
147
+ logger.debug(`[安装前拦截] API URL: ${apiUrl}`);
148
+ logger.debug(`[安装前拦截] 超时设置: ${timeoutMs}ms`);
138
149
 
139
150
  // 首先检查内置扫描结果
140
151
  if (builtinScan.status === "error") {
@@ -158,13 +169,31 @@ async function performScan(
158
169
  // 运行增强扫描
159
170
  try {
160
171
  logger.info(`[安装前拦截] 🔬 正在运行增强安全扫描...`);
172
+ logger.debug(`[安装前拦截] 扫描参数`, {
173
+ mode: "scan",
174
+ target: sourcePath,
175
+ behavioral,
176
+ useLLM,
177
+ policy,
178
+ apiUrl,
179
+ timeoutMs,
180
+ });
181
+
182
+ const scanStartTime = Date.now();
161
183
 
162
184
  const scanResult = await runScan("scan", sourcePath, {
163
185
  behavioral,
164
186
  useLLM,
165
187
  policy,
166
188
  apiUrl,
167
- detailed: true
189
+ detailed: true,
190
+ timeoutMs: timeoutMs - 10000, // Reserve 10s for overhead
191
+ });
192
+
193
+ const scanDuration = Date.now() - scanStartTime;
194
+ logger.debug(`[安装前拦截] 扫描完成`, {
195
+ exitCode: scanResult.exitCode,
196
+ durationMs: scanDuration,
168
197
  });
169
198
 
170
199
  if (scanResult.exitCode === 0) {
@@ -183,7 +212,7 @@ async function performScan(
183
212
 
184
213
  // 扫描失败 - 阻止安装
185
214
  const severity = scanResult.data?.max_severity || "未知";
186
- const findingsCount = scanResult.data?.findings || 0;
215
+ const findingsCount = scanResult.data?.findings_count || 0;
187
216
 
188
217
  logger.warn(`[安装前拦截] ❌ ${targetName} 未通过安全扫描`);
189
218
  logger.warn(`[安装前拦截] 严重性: ${severity}, 发现数: ${findingsCount}`);
@@ -208,7 +237,11 @@ async function performScan(
208
237
 
209
238
  } catch (error: any) {
210
239
  // 扫描因错误失败 - 根据策略决定
211
- logger.error(`[安装前拦截] ⚠️ ${targetName} 扫描错误: ${error.message}`);
240
+ logger.error(`[安装前拦截] ⚠️ ${targetName} 扫描错误`, {
241
+ error: error.message,
242
+ errorStack: error.stack,
243
+ errorCode: error.code,
244
+ });
212
245
 
213
246
  // 在严格模式下,扫描错误时阻止
214
247
  if (policy === "strict") {
package/src/commands.ts CHANGED
@@ -5,28 +5,24 @@
5
5
  import { existsSync } from "node:fs";
6
6
  import { join, basename } from "node:path";
7
7
  import { runScan } from "./scanner.js";
8
- import { buildDailyReport } from "./report.js";
9
8
  import { loadState, saveState, expandPath } from "./state.js";
10
9
  import { generateConfigGuide } from "./config.js";
11
- import { ensureCronJobViaGateway, checkCronJobStatus } from "./cron-manager.js";
12
10
  import type { ScannerConfig, CommandResponse, PluginLogger } from "./types.js";
13
11
 
14
12
  export function createCommandHandlers(
15
13
  cfg: ScannerConfig,
16
14
  apiUrl: string,
17
- scanDirs: string[],
18
15
  behavioral: boolean,
19
16
  useLLM: boolean,
20
17
  policy: string,
21
- preInstallScan: string,
22
18
  onUnsafe: string,
23
19
  logger: PluginLogger,
24
- callGateway: (method: string, params: any) => Promise<any>
20
+ apiConfig?: any
25
21
  ) {
26
22
  async function handleScanCommand(args: string): Promise<CommandResponse> {
27
23
  if (!args) {
28
24
  return {
29
- text: "用法:`/skills-scanner scan <路径> [--detailed] [--behavioral] [--recursive] [--report]`\n或:`/skills-scanner scan clawhub <URL> [--detailed] [--behavioral]`",
25
+ text: "用法:`/skills-scanner scan <路径> [--detailed] [--behavioral] [--recursive]`\n或:`/skills-scanner scan clawhub <URL> [--detailed] [--behavioral]`",
30
26
  };
31
27
  }
32
28
 
@@ -57,23 +53,6 @@ export function createCommandHandlers(
57
53
  const detailed = parts.includes("--detailed");
58
54
  const useBehav = parts.includes("--behavioral") || behavioral;
59
55
  const recursive = parts.includes("--recursive");
60
- const isReport = parts.includes("--report");
61
-
62
- // Report mode: use configured scanDirs
63
- if (isReport) {
64
- if (scanDirs.length === 0) {
65
- return { text: "⚠️ 未找到可扫描目录,请检查配置" };
66
- }
67
- const report = await buildDailyReport(
68
- scanDirs,
69
- useBehav,
70
- apiUrl,
71
- useLLM,
72
- policy,
73
- logger
74
- );
75
- return { text: report };
76
- }
77
56
 
78
57
  // Regular scan mode: require path
79
58
  if (!targetPath) {
@@ -87,13 +66,31 @@ export function createCommandHandlers(
87
66
  const isSingleSkill = existsSync(join(targetPath, "SKILL.md"));
88
67
 
89
68
  if (isSingleSkill) {
69
+ logger.info(`[命令] 开始扫描单个 Skill: ${targetPath}`);
70
+ logger.debug(`[命令] 扫描参数`, {
71
+ mode: "scan",
72
+ targetPath,
73
+ detailed,
74
+ behavioral: useBehav,
75
+ apiUrl,
76
+ useLLM,
77
+ policy,
78
+ });
79
+
90
80
  const res = await runScan("scan", targetPath, {
91
81
  detailed,
92
82
  behavioral: useBehav,
93
83
  apiUrl,
94
84
  useLLM,
95
85
  policy,
86
+ timeoutMs: 180000, // 3 minutes
87
+ });
88
+
89
+ logger.info(`[命令] 扫描完成`, {
90
+ exitCode: res.exitCode,
91
+ hasData: !!res.data,
96
92
  });
93
+
97
94
  const icon = res.exitCode === 0 ? "✅" : "❌";
98
95
  return { text: `${icon} 扫描完成\n\`\`\`\n${res.output}\n\`\`\`` };
99
96
  } else {
@@ -117,12 +114,10 @@ export function createCommandHandlers(
117
114
  const lines = [
118
115
  "✅ *Skills Scanner 状态*",
119
116
  `API 地址:${apiUrl}`,
120
- `安装前扫描:${preInstallScan === "on" ? `✅ 监听中 (${onUnsafe})` : "⏭️ 已禁用"}`,
121
117
  `扫描策略:${policy}`,
122
118
  `LLM 分析:${useLLM ? "✅ 启用" : "❌ 禁用"}`,
123
119
  `行为分析:${behavioral ? "✅ 启用" : "❌ 禁用"}`,
124
120
  `上次扫描:${state.lastScanAt ? new Date(state.lastScanAt).toLocaleString("zh-CN") : "从未"}`,
125
- `扫描目录:\n${scanDirs.map((d) => ` 📁 ${d}`).join("\n")}`,
126
121
  ];
127
122
 
128
123
  // API health check
@@ -152,13 +147,7 @@ export function createCommandHandlers(
152
147
  saveState({ ...state, pendingAlerts: [] });
153
148
  }
154
149
 
155
- lines.push("", "✅ *定时任务*");
156
- if (state.cronJobId && state.cronJobId !== "manual-created") {
157
- lines.push(`状态:✅ 已注册 (${state.cronJobId})`);
158
- } else {
159
- lines.push("状态:❌ 未注册");
160
- lines.push("ℹ️ 使用 `/skills-scanner cron register` 注册");
161
- }
150
+ // 定时任务功能已移除
162
151
 
163
152
  return { text: lines.join("\n") };
164
153
  }
@@ -170,11 +159,9 @@ export function createCommandHandlers(
170
159
  const configGuide = generateConfigGuide(
171
160
  cfg,
172
161
  apiUrl,
173
- scanDirs,
174
162
  behavioral,
175
163
  useLLM,
176
164
  policy,
177
- preInstallScan,
178
165
  onUnsafe
179
166
  );
180
167
  return { text: "```\n" + configGuide + "\n```" };
@@ -189,66 +176,6 @@ export function createCommandHandlers(
189
176
  }
190
177
  }
191
178
 
192
- async function handleCronCommand(args: string): Promise<CommandResponse> {
193
- const action = args.trim().toLowerCase() || "status";
194
-
195
- if (action === "setup" || action === "register") {
196
- try {
197
- await ensureCronJobViaGateway({
198
- logger,
199
- callGateway,
200
- });
201
- return { text: "✅ 定时任务注册完成\n请查看日志了解详情" };
202
- } catch (err: any) {
203
- return { text: `⚠️ 定时任务注册失败:${err.message}` };
204
- }
205
- } else if (action === "unregister") {
206
- try {
207
- // 列出所有任务
208
- const listResult = await callGateway("cron.list", {});
209
- const jobs = Array.isArray(listResult?.jobs) ? listResult.jobs : [];
210
- const existingJobs = jobs.filter((job: any) => job.name === "skills-weekly-report");
211
-
212
- if (existingJobs.length === 0) {
213
- return { text: "ℹ️ 未找到已注册的定时任务" };
214
- }
215
-
216
- // 删除所有同名任务
217
- const deletedIds: string[] = [];
218
- for (const job of existingJobs) {
219
- const jobId = job.jobId || job.id;
220
- try {
221
- await callGateway("cron.remove", { jobId });
222
- deletedIds.push(jobId);
223
- } catch (err: any) {
224
- logger.warn(`删除任务 ${jobId} 失败: ${err.message}`);
225
- }
226
- }
227
-
228
- if (deletedIds.length > 0) {
229
- return {
230
- text: `✅ 已删除 ${deletedIds.length} 个定时任务\n${deletedIds.map(id => `- ${id}`).join("\n")}`,
231
- };
232
- } else {
233
- return { text: "⚠️ 删除失败,请查看日志" };
234
- }
235
- } catch (err: any) {
236
- return { text: `⚠️ 删除失败:${err.message}` };
237
- }
238
- } else {
239
- // status
240
- try {
241
- const statusText = await checkCronJobStatus({
242
- logger,
243
- callGateway,
244
- });
245
- return { text: statusText };
246
- } catch (err: any) {
247
- return { text: `⚠️ 查询状态失败:${err.message}` };
248
- }
249
- }
250
- }
251
-
252
179
  function getHelpText(): string {
253
180
  return [
254
181
  "✅ *Skills Scanner - 帮助*",
@@ -261,13 +188,11 @@ export function createCommandHandlers(
261
188
  "• `--detailed` - 显示详细发现",
262
189
  "• `--behavioral` - 启用行为分析",
263
190
  "• `--recursive` - 递归扫描子目录",
264
- "• `--report` - 生成日报格式",
265
191
  "",
266
192
  "示例:",
267
193
  "```",
268
194
  "/skills-scanner scan ~/.openclaw/skills/my-skill",
269
195
  "/skills-scanner scan ~/.openclaw/skills --recursive",
270
- "/skills-scanner scan ~/.openclaw/skills --report",
271
196
  "/skills-scanner scan clawhub https://clawhub.ai/username/project",
272
197
  "/skills-scanner scan clawhub https://clawhub.ai/username/project --detailed",
273
198
  "```",
@@ -275,7 +200,6 @@ export function createCommandHandlers(
275
200
  "═══ 其他命令 ═══",
276
201
  "• `/skills-scanner health` - 健康检查",
277
202
  "• `/skills-scanner config [show|reset]` - 配置管理",
278
- "• `/skills-scanner cron [register|unregister|status]` - 定时任务管理",
279
203
  ].join("\n");
280
204
  }
281
205
 
@@ -283,7 +207,6 @@ export function createCommandHandlers(
283
207
  handleScanCommand,
284
208
  handleHealthCommand,
285
209
  handleConfigCommand,
286
- handleCronCommand,
287
210
  getHelpText,
288
211
  };
289
212
  }
@@ -31,15 +31,6 @@ export function validateConfig(
31
31
  }
32
32
  }
33
33
 
34
- // Validate scan directories
35
- if (cfg.scanDirs && cfg.scanDirs.length > 0) {
36
- for (const dir of cfg.scanDirs) {
37
- if (!existsSync(dir)) {
38
- warnings.push(`Scan directory does not exist: ${dir}`);
39
- }
40
- }
41
- }
42
-
43
34
  // Validate policy
44
35
  if (cfg.policy && !["strict", "balanced", "permissive"].includes(cfg.policy)) {
45
36
  errors.push(
@@ -47,13 +38,6 @@ export function validateConfig(
47
38
  );
48
39
  }
49
40
 
50
- // Validate preInstallScan
51
- if (cfg.preInstallScan && !["on", "off"].includes(cfg.preInstallScan)) {
52
- errors.push(
53
- `Invalid preInstallScan: "${cfg.preInstallScan}". Must be "on" or "off"`
54
- );
55
- }
56
-
57
41
  // Validate onUnsafe
58
42
  if (cfg.onUnsafe && !["warn", "delete", "quarantine"].includes(cfg.onUnsafe)) {
59
43
  errors.push(