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

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.
@@ -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(
package/src/config.ts CHANGED
@@ -24,19 +24,6 @@ export const skillsScannerConfigSchema: OpenClawPluginConfigSchema = {
24
24
  };
25
25
  }
26
26
 
27
- // 验证 preInstallScan
28
- if (config.preInstallScan && !["on", "off"].includes(config.preInstallScan)) {
29
- return {
30
- success: false,
31
- error: {
32
- issues: [{
33
- path: ["preInstallScan"],
34
- message: "preInstallScan 必须是 on 或 off"
35
- }]
36
- }
37
- };
38
- }
39
-
40
27
  // 验证 onUnsafe
41
28
  if (config.onUnsafe && !["quarantine", "delete", "warn"].includes(config.onUnsafe)) {
42
29
  return {
@@ -72,12 +59,6 @@ export const skillsScannerConfigSchema: OpenClawPluginConfigSchema = {
72
59
  type: "string",
73
60
  format: "uri",
74
61
  },
75
- scanDirs: {
76
- label: "扫描目录",
77
- help: "要监控的 Skills 目录列表,支持 ~ 路径。默认监控 ~/.openclaw/skills 和 ~/.openclaw/workspace/skills",
78
- type: "array",
79
- items: { type: "string" },
80
- },
81
62
  behavioral: {
82
63
  label: "行为分析",
83
64
  help: "启用深度行为分析(较慢但更准确)。检测运行时行为模式,如网络请求、文件操作等",
@@ -97,13 +78,6 @@ export const skillsScannerConfigSchema: OpenClawPluginConfigSchema = {
97
78
  enum: ["strict", "balanced", "permissive"],
98
79
  default: "balanced",
99
80
  },
100
- preInstallScan: {
101
- label: "安装前扫描",
102
- help: "监听新 Skill 并自动扫描。启用后会实时监控 scanDirs 中的文件变化",
103
- type: "string",
104
- enum: ["on", "off"],
105
- default: "on",
106
- },
107
81
  onUnsafe: {
108
82
  label: "不安全处理",
109
83
  help: "warn=仅警告(推荐,不影响使用)/ quarantine=隔离到隔离区 / delete=直接删除(危险)",
@@ -123,18 +97,6 @@ export const skillsScannerConfigSchema: OpenClawPluginConfigSchema = {
123
97
  type: "boolean",
124
98
  default: true,
125
99
  },
126
- enablePromptInjectionGuard: {
127
- label: "提示注入防护",
128
- help: "启用提示注入攻击防护,检测并阻止恶意提示",
129
- type: "boolean",
130
- default: false,
131
- },
132
- enableHighRiskOperationGuard: {
133
- label: "高风险操作防护",
134
- help: "启用高风险操作防护,对敏感操作进行额外检查",
135
- type: "boolean",
136
- default: false,
137
- },
138
100
  scanTimeoutMs: {
139
101
  label: "扫描超时(毫秒)",
140
102
  help: "单次扫描的最大时长,超时后自动取消。默认 180000ms (3分钟)",
@@ -159,11 +121,9 @@ export const skillsScannerConfigSchema: OpenClawPluginConfigSchema = {
159
121
  export function generateConfigGuide(
160
122
  cfg: ScannerConfig,
161
123
  apiUrl: string,
162
- scanDirs: string[],
163
124
  behavioral: boolean,
164
125
  useLLM: boolean,
165
126
  policy: string,
166
- preInstallScan: string,
167
127
  onUnsafe: string
168
128
  ): string {
169
129
  return [
@@ -176,11 +136,10 @@ export function generateConfigGuide(
176
136
  "",
177
137
  "📋 当前配置:",
178
138
  ` • API 服务地址:${apiUrl}`,
179
- ` • 扫描目录:${scanDirs.length} 个(自动检测)`,
180
139
  ` • 行为分析:${behavioral ? "✅ 启用" : "❌ 禁用"}`,
181
140
  ` • LLM 分析:${useLLM ? "✅ 启用" : "❌ 禁用"}`,
182
141
  ` • 扫描策略:${policy}`,
183
- ` • 安装前扫描:${preInstallScan === "on" ? "✅ 启用" : "❌ 禁用"}`,
142
+ ` • 目录监控:❌ 已禁用(需手动扫描)`,
184
143
  ` • 不安全处理:${onUnsafe}`,
185
144
  "",
186
145
  "🔧 配置文件位置:",
@@ -196,11 +155,9 @@ export function generateConfigGuide(
196
155
  ' "enabled": true,',
197
156
  ' "config": {',
198
157
  ' "apiUrl": "https://110.vemic.com/skills-scanner",',
199
- ' "scanDirs": ["~/.openclaw/skills"],',
200
158
  ' "behavioral": false,',
201
159
  ' "useLLM": false,',
202
160
  ' "policy": "balanced",',
203
- ' "preInstallScan": "on",',
204
161
  ' "onUnsafe": "warn"',
205
162
  ' }',
206
163
  ' }',
@@ -212,12 +169,13 @@ export function generateConfigGuide(
212
169
  "💡 配置说明:",
213
170
  "",
214
171
  "1. apiUrl 默认 https://110.vemic.com/skills-scanner",
215
- "2. scanDirs 可添加多个目录(默认自动检测 ~/.openclaw/skills)",
216
- "3. behavioral false=快速扫描(推荐),true=深度分析",
217
- "4. useLLM false=不使用 LLM(推荐),true=语义分析",
218
- "5. policy strict / balanced(推荐)/ permissive",
219
- "6. preInstallScan on=监听新 Skill 并自动扫描(推荐),off=禁用",
220
- "7. onUnsafe warn=仅警告(推荐),quarantine=隔离,delete=删除",
172
+ "2. behavioral false=快速扫描(推荐),true=深度分析",
173
+ "3. useLLM false=不使用 LLM(推荐),true=语义分析",
174
+ "4. policy strict / balanced(推荐)/ permissive",
175
+ "5. onUnsafe warn=仅警告(推荐),quarantine=隔离,delete=删除",
176
+ "",
177
+ "⚠️ 注意:目录监控功能已禁用,请使用以下命令手动扫描:",
178
+ " /skills-scanner scan <路径>",
221
179
  "",
222
180
  "🚀 快速开始:",
223
181
  " 编辑配置文件后重启 Gateway",