@pwddd/skills-scanner 1.0.5 → 1.1.0

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.

Potentially problematic release.


This version of @pwddd/skills-scanner might be problematic. Click here for more details.

Files changed (2) hide show
  1. package/index.ts +71 -32
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -73,7 +73,15 @@ function hasUv(): boolean {
73
73
  }
74
74
 
75
75
  function isVenvReady(): boolean {
76
- return existsSync(VENV_PYTHON);
76
+ if (!existsSync(VENV_PYTHON)) return false;
77
+
78
+ // 检查 cisco-ai-skill-scanner 是否真的安装
79
+ try {
80
+ execSync(`"${VENV_PYTHON}" -c "import skill_scanner"`, { stdio: 'ignore' });
81
+ return true;
82
+ } catch {
83
+ return false;
84
+ }
77
85
  }
78
86
 
79
87
  function expandPath(p: string): string {
@@ -106,24 +114,39 @@ function saveState(s: ScanState) {
106
114
 
107
115
  async function ensureDeps(logger: any): Promise<boolean> {
108
116
  if (isVenvReady()) {
109
- logger.info("[skills-scanner] Python 依赖已就绪");
117
+ logger.info("[skills-scanner] Python 依赖已就绪(cisco-ai-skill-scanner 已安装)");
110
118
  return true;
111
119
  }
120
+
112
121
  if (!hasUv()) {
113
122
  logger.warn("[skills-scanner] uv 未安装:brew install uv 或 curl -LsSf https://astral.sh/uv/install.sh | sh");
114
123
  return false;
115
124
  }
116
- logger.info("[skills-scanner] 首次启动,正在安装 cisco-ai-skill-scanner...");
125
+
126
+ logger.info("[skills-scanner] 正在安装 cisco-ai-skill-scanner...");
127
+
117
128
  try {
118
- // 创建 venv
119
- await execAsync(`uv venv "${join(SKILL_DIR, ".venv")}" --python 3.10`);
120
- // 激活 venv 并安装包
121
- await execAsync(`"${VENV_PYTHON}" -m pip install cisco-ai-skill-scanner`);
122
- logger.info("[skills-scanner] ✅ 依赖安装完成");
123
- return true;
129
+ // 创建 venv(如果不存在)
130
+ if (!existsSync(VENV_PYTHON)) {
131
+ logger.info("[skills-scanner] 创建 Python 虚拟环境...");
132
+ await execAsync(`uv venv "${join(SKILL_DIR, ".venv")}" --python 3.10`);
133
+ }
134
+
135
+ // 安装包
136
+ logger.info("[skills-scanner] 安装 cisco-ai-skill-scanner 包...");
137
+ await execAsync(`uv pip install --python "${VENV_PYTHON}" cisco-ai-skill-scanner`);
138
+
139
+ // 验证安装
140
+ if (isVenvReady()) {
141
+ logger.info("[skills-scanner] ✅ 依赖安装完成并验证成功");
142
+ return true;
143
+ } else {
144
+ logger.error("[skills-scanner] ❌ 安装完成但验证失败,包可能未正确安装");
145
+ return false;
146
+ }
124
147
  } catch (err: any) {
125
148
  logger.error(`[skills-scanner] ⚠️ 依赖安装失败: ${err.message}`);
126
- logger.error(`[skills-scanner] 请手动运行: uv pip install cisco-ai-skill-scanner`);
149
+ logger.error(`[skills-scanner] 请手动运行: uv pip install --python "${VENV_PYTHON}" cisco-ai-skill-scanner`);
127
150
  return false;
128
151
  }
129
152
  }
@@ -304,11 +327,25 @@ export default function register(api: any) {
304
327
  const preInstallScan = cfg.preInstallScan ?? "on";
305
328
  const onUnsafe = cfg.onUnsafe ?? "quarantine";
306
329
 
307
- // 向聊天发消息的辅助(用于 watcher 通知)——使用 registerCommand handler
308
- // 文档确认:registerCommand handler 可以直接 return { text },
309
- // watcher 是异步后台任务,没有 handler context。
310
- // 唯一有文档依据的方式:写入 event.messages(仅限 hook handler 内)。
311
- // 这里退而求其次:写到日志 + 持久化到 STATE_FILE,让用户可通过 /scan-status 查看。
330
+ api.logger.info("[skills-scanner] ═══════════════════════════════════════");
331
+ api.logger.info("[skills-scanner] Plugin 正在加载...");
332
+ api.logger.info(`[skills-scanner] 扫描目录: ${scanDirs.join(", ")}`);
333
+ api.logger.info(`[skills-scanner] Python venv 路径: ${VENV_PYTHON}`);
334
+ api.logger.info(`[skills-scanner] Python 依赖状态: ${isVenvReady() ? "✅ 已就绪" : "❌ 未安装"}`);
335
+
336
+ // 立即尝试安装依赖(不等待 service start)
337
+ if (!isVenvReady()) {
338
+ api.logger.info("[skills-scanner] 开始安装 Python 依赖...");
339
+ ensureDeps(api.logger).then(success => {
340
+ if (success) {
341
+ api.logger.info("[skills-scanner] ✅ 依赖安装成功(在 plugin 加载时)");
342
+ }
343
+ }).catch(err => {
344
+ api.logger.error(`[skills-scanner] 依赖安装失败: ${err.message}`);
345
+ });
346
+ }
347
+
348
+ // 向聊天发消息的辅助(用于 watcher 通知)
312
349
  function persistWatcherAlert(msg: string) {
313
350
  const state = loadState();
314
351
  const alerts: string[] = (state as any).pendingAlerts ?? [];
@@ -323,40 +360,42 @@ export default function register(api: any) {
323
360
  api.registerService({
324
361
  id: "skills-scanner-setup",
325
362
  start: async () => {
326
- api.logger.info("[skills-scanner] 🚀 Service starting...");
363
+ api.logger.info("[skills-scanner] ─────────────────────────────────────");
364
+ api.logger.info("[skills-scanner] 🚀 后台服务启动中...");
365
+
366
+ // 再次检查并安装依赖(防止 plugin 加载时安装失败)
327
367
  const depsReady = await ensureDeps(api.logger);
328
368
 
329
369
  if (!depsReady) {
330
370
  api.logger.error("[skills-scanner] ❌ 依赖安装失败,服务无法启动");
371
+ api.logger.error("[skills-scanner] 请手动运行: uv pip install --python \"" + VENV_PYTHON + "\" cisco-ai-skill-scanner");
331
372
  return;
332
373
  }
333
374
 
334
375
  if (preInstallScan === "on" && scanDirs.length > 0) {
376
+ api.logger.info(`[skills-scanner] 📁 启动文件监控: ${scanDirs.length} 个目录`);
335
377
  stopWatcher = startWatcher(scanDirs, onUnsafe, behavioral, persistWatcherAlert, api.logger);
378
+ api.logger.info("[skills-scanner] ✅ 文件监控已启动");
379
+ } else {
380
+ api.logger.info("[skills-scanner] ⏭️ 安装前扫描已禁用");
336
381
  }
382
+
383
+ api.logger.info("[skills-scanner] ─────────────────────────────────────");
384
+ },
385
+ stop: () => {
386
+ api.logger.info("[skills-scanner] 🛑 后台服务停止中...");
387
+ stopWatcher?.();
388
+ stopWatcher = null;
337
389
  },
338
- stop: () => { stopWatcher?.(); stopWatcher = null; },
339
390
  });
340
391
 
341
- // ── 2. Startup logging ────────────────────────────────────────────────────
342
- // 在 Gateway 启动时输出配置提示
343
- api.logger.info("[skills-scanner] Plugin 已加载");
344
- api.logger.info(`[skills-scanner] 安装前扫描:${preInstallScan === "on" ? `✅ 监听 ${scanDirs.length} 个目录` : "❌ 已禁用"}`);
345
-
346
- // 立即检查并安装依赖(不等待 service start)
347
- if (!isVenvReady()) {
348
- api.logger.info("[skills-scanner] 检测到 Python 依赖未安装,开始安装...");
349
- ensureDeps(api.logger).catch(err => {
350
- api.logger.error(`[skills-scanner] 依赖安装异常: ${err.message}`);
351
- });
352
- }
353
-
354
- // 检查是否需要注册 Cron Job
392
+ // ── 2. 启动日志和 Cron 提示 ───────────────────────────────────────────────
355
393
  const state = loadState() as any;
356
394
  if (!state.cronJobId) {
357
395
  api.logger.warn("[skills-scanner] ⚠️ 未检测到日报 Cron Job,请手动注册一次:");
358
396
  api.logger.info('[skills-scanner] openclaw cron add --name "skills-daily-report" --cron "0 8 * * *" --tz "Asia/Shanghai" --session isolated --message "请执行 /scan-report 并把结果发送到此渠道" --announce');
359
397
  }
398
+ api.logger.info("[skills-scanner] ═══════════════════════════════════════");
360
399
 
361
400
  // ── 3. /scan-skill ────────────────────────────────────────────────────────
362
401
  api.registerCommand({
@@ -508,5 +547,5 @@ export default function register(api: any) {
508
547
  });
509
548
  }, { commands: ["skills-scan"] });
510
549
 
511
- api.logger.info("[skills-scanner] Plugin 已注册 ✅");
550
+ api.logger.info("[skills-scanner] Plugin 注册完成");
512
551
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pwddd/skills-scanner",
3
- "version": "1.0.5",
3
+ "version": "1.1.0",
4
4
  "description": "OpenClaw Plugin:Skills 安全扫描、安装前拦截、安全日报",
5
5
  "main": "index.ts",
6
6
  "files": [