code-abyss 1.6.16 → 1.7.1

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.
Files changed (97) hide show
  1. package/README.md +8 -6
  2. package/bin/install.js +59 -163
  3. package/bin/lib/ccline.js +82 -0
  4. package/bin/lib/utils.js +61 -0
  5. package/package.json +5 -2
  6. package/skills/SKILL.md +24 -16
  7. package/skills/domains/ai/SKILL.md +2 -2
  8. package/skills/domains/ai/prompt-and-eval.md +279 -0
  9. package/skills/domains/architecture/SKILL.md +2 -3
  10. package/skills/domains/architecture/security-arch.md +87 -0
  11. package/skills/domains/data-engineering/SKILL.md +188 -26
  12. package/skills/domains/development/SKILL.md +1 -4
  13. package/skills/domains/devops/SKILL.md +3 -5
  14. package/skills/domains/devops/performance.md +63 -0
  15. package/skills/domains/devops/testing.md +97 -0
  16. package/skills/domains/frontend-design/SKILL.md +12 -3
  17. package/skills/domains/frontend-design/claymorphism/SKILL.md +117 -0
  18. package/skills/domains/frontend-design/claymorphism/references/tokens.css +52 -0
  19. package/skills/domains/frontend-design/engineering.md +287 -0
  20. package/skills/domains/frontend-design/glassmorphism/SKILL.md +138 -0
  21. package/skills/domains/frontend-design/glassmorphism/references/tokens.css +32 -0
  22. package/skills/domains/frontend-design/liquid-glass/SKILL.md +135 -0
  23. package/skills/domains/frontend-design/liquid-glass/references/tokens.css +81 -0
  24. package/skills/domains/frontend-design/neubrutalism/SKILL.md +141 -0
  25. package/skills/domains/frontend-design/neubrutalism/references/tokens.css +44 -0
  26. package/skills/domains/infrastructure/SKILL.md +174 -34
  27. package/skills/domains/mobile/SKILL.md +211 -21
  28. package/skills/domains/orchestration/SKILL.md +1 -0
  29. package/skills/domains/security/SKILL.md +4 -6
  30. package/skills/domains/security/blue-team.md +57 -0
  31. package/skills/domains/security/red-team.md +54 -0
  32. package/skills/domains/security/threat-intel.md +50 -0
  33. package/skills/orchestration/multi-agent/SKILL.md +195 -46
  34. package/skills/run_skill.js +139 -0
  35. package/skills/tools/gen-docs/SKILL.md +6 -4
  36. package/skills/tools/gen-docs/scripts/doc_generator.js +363 -0
  37. package/skills/tools/lib/shared.js +98 -0
  38. package/skills/tools/verify-change/SKILL.md +8 -6
  39. package/skills/tools/verify-change/scripts/change_analyzer.js +289 -0
  40. package/skills/tools/verify-module/SKILL.md +6 -4
  41. package/skills/tools/verify-module/scripts/module_scanner.js +171 -0
  42. package/skills/tools/verify-quality/SKILL.md +5 -3
  43. package/skills/tools/verify-quality/scripts/quality_checker.js +337 -0
  44. package/skills/tools/verify-security/SKILL.md +7 -5
  45. package/skills/tools/verify-security/scripts/security_scanner.js +283 -0
  46. package/skills/__pycache__/run_skill.cpython-312.pyc +0 -0
  47. package/skills/domains/COVERAGE_PLAN.md +0 -232
  48. package/skills/domains/ai/model-evaluation.md +0 -790
  49. package/skills/domains/ai/prompt-engineering.md +0 -703
  50. package/skills/domains/architecture/compliance.md +0 -299
  51. package/skills/domains/architecture/data-security.md +0 -184
  52. package/skills/domains/data-engineering/data-pipeline.md +0 -762
  53. package/skills/domains/data-engineering/data-quality.md +0 -894
  54. package/skills/domains/data-engineering/stream-processing.md +0 -791
  55. package/skills/domains/development/dart.md +0 -963
  56. package/skills/domains/development/kotlin.md +0 -834
  57. package/skills/domains/development/php.md +0 -659
  58. package/skills/domains/development/swift.md +0 -755
  59. package/skills/domains/devops/e2e-testing.md +0 -914
  60. package/skills/domains/devops/performance-testing.md +0 -734
  61. package/skills/domains/devops/testing-strategy.md +0 -667
  62. package/skills/domains/frontend-design/build-tools.md +0 -743
  63. package/skills/domains/frontend-design/performance.md +0 -734
  64. package/skills/domains/frontend-design/testing.md +0 -699
  65. package/skills/domains/infrastructure/gitops.md +0 -735
  66. package/skills/domains/infrastructure/iac.md +0 -855
  67. package/skills/domains/infrastructure/kubernetes.md +0 -1018
  68. package/skills/domains/mobile/android-dev.md +0 -979
  69. package/skills/domains/mobile/cross-platform.md +0 -795
  70. package/skills/domains/mobile/ios-dev.md +0 -931
  71. package/skills/domains/security/secrets-management.md +0 -834
  72. package/skills/domains/security/supply-chain.md +0 -931
  73. package/skills/domains/security/threat-modeling.md +0 -828
  74. package/skills/run_skill.py +0 -153
  75. package/skills/tests/README.md +0 -225
  76. package/skills/tests/SUMMARY.md +0 -362
  77. package/skills/tests/__init__.py +0 -3
  78. package/skills/tests/__pycache__/test_change_analyzer.cpython-312.pyc +0 -0
  79. package/skills/tests/__pycache__/test_doc_generator.cpython-312.pyc +0 -0
  80. package/skills/tests/__pycache__/test_module_scanner.cpython-312.pyc +0 -0
  81. package/skills/tests/__pycache__/test_quality_checker.cpython-312.pyc +0 -0
  82. package/skills/tests/__pycache__/test_security_scanner.cpython-312.pyc +0 -0
  83. package/skills/tests/test_change_analyzer.py +0 -558
  84. package/skills/tests/test_doc_generator.py +0 -538
  85. package/skills/tests/test_module_scanner.py +0 -376
  86. package/skills/tests/test_quality_checker.py +0 -516
  87. package/skills/tests/test_security_scanner.py +0 -426
  88. package/skills/tools/gen-docs/scripts/__pycache__/doc_generator.cpython-312.pyc +0 -0
  89. package/skills/tools/gen-docs/scripts/doc_generator.py +0 -520
  90. package/skills/tools/verify-change/scripts/__pycache__/change_analyzer.cpython-312.pyc +0 -0
  91. package/skills/tools/verify-change/scripts/change_analyzer.py +0 -529
  92. package/skills/tools/verify-module/scripts/__pycache__/module_scanner.cpython-312.pyc +0 -0
  93. package/skills/tools/verify-module/scripts/module_scanner.py +0 -321
  94. package/skills/tools/verify-quality/scripts/__pycache__/quality_checker.cpython-312.pyc +0 -0
  95. package/skills/tools/verify-quality/scripts/quality_checker.py +0 -481
  96. package/skills/tools/verify-security/scripts/__pycache__/security_scanner.cpython-312.pyc +0 -0
  97. package/skills/tools/verify-security/scripts/security_scanner.py +0 -374
@@ -1,481 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- 代码质量检查器
4
- 检测代码复杂度、重复代码、命名规范、函数长度等
5
- """
6
-
7
- import os
8
- import re
9
- import sys
10
- import json
11
- import ast
12
- from pathlib import Path
13
- from dataclasses import dataclass, field
14
- from typing import List, Dict, Optional, Set, Tuple
15
- from enum import Enum
16
- from collections import defaultdict
17
-
18
-
19
- class Severity(Enum):
20
- ERROR = "error"
21
- WARNING = "warning"
22
- INFO = "info"
23
-
24
-
25
- @dataclass
26
- class Issue:
27
- severity: Severity
28
- category: str
29
- message: str
30
- file_path: str
31
- line_number: Optional[int] = None
32
- suggestion: Optional[str] = None
33
-
34
-
35
- @dataclass
36
- class FileMetrics:
37
- path: str
38
- lines: int = 0
39
- code_lines: int = 0
40
- comment_lines: int = 0
41
- blank_lines: int = 0
42
- functions: int = 0
43
- classes: int = 0
44
- max_complexity: int = 0
45
- avg_function_length: float = 0
46
-
47
-
48
- @dataclass
49
- class QualityResult:
50
- scan_path: str
51
- files_scanned: int = 0
52
- total_lines: int = 0
53
- total_code_lines: int = 0
54
- issues: List[Issue] = field(default_factory=list)
55
- file_metrics: List[FileMetrics] = field(default_factory=list)
56
-
57
- @property
58
- def passed(self) -> bool:
59
- return not any(i.severity == Severity.ERROR for i in self.issues)
60
-
61
- @property
62
- def error_count(self) -> int:
63
- return sum(1 for i in self.issues if i.severity == Severity.ERROR)
64
-
65
- @property
66
- def warning_count(self) -> int:
67
- return sum(1 for i in self.issues if i.severity == Severity.WARNING)
68
-
69
-
70
- # 质量规则配置
71
- MAX_LINE_LENGTH = 120
72
- MAX_FUNCTION_LENGTH = 50
73
- MAX_FILE_LENGTH = 500
74
- MAX_COMPLEXITY = 10
75
- MAX_PARAMETERS = 5
76
- MIN_FUNCTION_NAME_LENGTH = 2
77
- MAX_FUNCTION_NAME_LENGTH = 40
78
- PYTHON_SPECIAL_METHODS = {"setUp", "tearDown", "setUpClass", "tearDownClass", "setUpModule", "tearDownModule"}
79
-
80
-
81
- class PythonAnalyzer(ast.NodeVisitor):
82
- """Python AST 分析器"""
83
-
84
- def __init__(self, file_path: str, source: str):
85
- self.file_path = file_path
86
- self.source = source
87
- self.lines = source.split('\n')
88
- self.issues: List[Issue] = []
89
- self.functions: List[Dict] = []
90
- self.classes: List[Dict] = []
91
- self.complexity = 0
92
-
93
- def analyze(self) -> Tuple[List[Issue], List[Dict], List[Dict], int]:
94
- try:
95
- tree = ast.parse(self.source)
96
- self.visit(tree)
97
- except SyntaxError as e:
98
- self.issues.append(Issue(
99
- severity=Severity.ERROR,
100
- category="语法",
101
- message=f"语法错误: {e.msg}",
102
- file_path=self.file_path,
103
- line_number=e.lineno
104
- ))
105
- return self.issues, self.functions, self.classes, self.complexity
106
-
107
- def visit_FunctionDef(self, node):
108
- self._analyze_function(node)
109
- self.generic_visit(node)
110
-
111
- def visit_AsyncFunctionDef(self, node):
112
- self._analyze_function(node)
113
- self.generic_visit(node)
114
-
115
- def visit_ClassDef(self, node):
116
- self.classes.append({
117
- "name": node.name,
118
- "line": node.lineno,
119
- "methods": len([n for n in node.body if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef))])
120
- })
121
-
122
- # 检查类名
123
- if not re.match(r'^[A-Z][a-zA-Z0-9]*$', node.name):
124
- self.issues.append(Issue(
125
- severity=Severity.WARNING,
126
- category="命名",
127
- message=f"类名 '{node.name}' 不符合 PascalCase 规范",
128
- file_path=self.file_path,
129
- line_number=node.lineno,
130
- suggestion="类名应使用 PascalCase,如 MyClassName"
131
- ))
132
-
133
- self.generic_visit(node)
134
-
135
- def _analyze_function(self, node):
136
- func_info = {
137
- "name": node.name,
138
- "line": node.lineno,
139
- "length": self._get_function_length(node),
140
- "complexity": self._calculate_complexity(node),
141
- "parameters": len(node.args.args)
142
- }
143
- self.functions.append(func_info)
144
- self.complexity = max(self.complexity, func_info["complexity"])
145
-
146
- # 检查函数长度
147
- if func_info["length"] > MAX_FUNCTION_LENGTH:
148
- self.issues.append(Issue(
149
- severity=Severity.WARNING,
150
- category="复杂度",
151
- message=f"函数 '{node.name}' 过长 ({func_info['length']} 行 > {MAX_FUNCTION_LENGTH})",
152
- file_path=self.file_path,
153
- line_number=node.lineno,
154
- suggestion="考虑拆分为多个小函数"
155
- ))
156
-
157
- # 检查复杂度
158
- if func_info["complexity"] > MAX_COMPLEXITY:
159
- self.issues.append(Issue(
160
- severity=Severity.WARNING,
161
- category="复杂度",
162
- message=f"函数 '{node.name}' 圈复杂度过高 ({func_info['complexity']} > {MAX_COMPLEXITY})",
163
- file_path=self.file_path,
164
- line_number=node.lineno,
165
- suggestion="减少嵌套层级,提取子函数"
166
- ))
167
-
168
- # 检查参数数量
169
- if func_info["parameters"] > MAX_PARAMETERS:
170
- self.issues.append(Issue(
171
- severity=Severity.WARNING,
172
- category="设计",
173
- message=f"函数 '{node.name}' 参数过多 ({func_info['parameters']} > {MAX_PARAMETERS})",
174
- file_path=self.file_path,
175
- line_number=node.lineno,
176
- suggestion="考虑使用配置对象或数据类封装参数"
177
- ))
178
-
179
- # 检查函数命名
180
- if not node.name.startswith('_') and node.name not in PYTHON_SPECIAL_METHODS and not node.name.startswith('visit_'):
181
- if not re.match(r'^[a-z][a-z0-9_]*$', node.name):
182
- self.issues.append(Issue(
183
- severity=Severity.INFO,
184
- category="命名",
185
- message=f"函数名 '{node.name}' 不符合 snake_case 规范",
186
- file_path=self.file_path,
187
- line_number=node.lineno,
188
- suggestion="函数名应使用 snake_case,如 my_function_name"
189
- ))
190
-
191
- if len(node.name) < MIN_FUNCTION_NAME_LENGTH:
192
- self.issues.append(Issue(
193
- severity=Severity.WARNING,
194
- category="命名",
195
- message=f"函数名 '{node.name}' 过短",
196
- file_path=self.file_path,
197
- line_number=node.lineno,
198
- suggestion="使用更具描述性的函数名"
199
- ))
200
-
201
- def _get_function_length(self, node) -> int:
202
- if hasattr(node, 'end_lineno'):
203
- return node.end_lineno - node.lineno + 1
204
- return len(ast.unparse(node).split('\n'))
205
-
206
- def _calculate_complexity(self, node) -> int:
207
- """计算圈复杂度"""
208
- complexity = 1
209
-
210
- for child in ast.walk(node):
211
- if isinstance(child, (ast.If, ast.While, ast.For, ast.AsyncFor)):
212
- complexity += 1
213
- elif isinstance(child, ast.ExceptHandler):
214
- complexity += 1
215
- elif isinstance(child, (ast.And, ast.Or)):
216
- complexity += 1
217
- elif isinstance(child, ast.comprehension):
218
- complexity += 1
219
- if child.ifs:
220
- complexity += len(child.ifs)
221
-
222
- return complexity
223
-
224
-
225
- def analyze_python_file(file_path: Path) -> Tuple[FileMetrics, List[Issue]]:
226
- """分析 Python 文件"""
227
- metrics = FileMetrics(path=str(file_path))
228
- issues = []
229
-
230
- try:
231
- content = file_path.read_text(encoding='utf-8', errors='ignore')
232
- lines = content.split('\n')
233
- except Exception as e:
234
- issues.append(Issue(
235
- severity=Severity.ERROR,
236
- category="文件",
237
- message=f"无法读取文件: {e}",
238
- file_path=str(file_path)
239
- ))
240
- return metrics, issues
241
-
242
- # 基础行数统计
243
- metrics.lines = len(lines)
244
- in_multiline_string = False
245
-
246
- for i, line in enumerate(lines, 1):
247
- stripped = line.strip()
248
-
249
- if not stripped:
250
- metrics.blank_lines += 1
251
- elif stripped.startswith('#'):
252
- metrics.comment_lines += 1
253
- elif '"""' in stripped or "'''" in stripped:
254
- if stripped.count('"""') == 2 or stripped.count("'''") == 2:
255
- metrics.comment_lines += 1
256
- else:
257
- in_multiline_string = not in_multiline_string
258
- metrics.comment_lines += 1
259
- elif in_multiline_string:
260
- metrics.comment_lines += 1
261
- else:
262
- metrics.code_lines += 1
263
-
264
- # 检查行长度
265
- if len(line) > MAX_LINE_LENGTH:
266
- issues.append(Issue(
267
- severity=Severity.INFO,
268
- category="格式",
269
- message=f"行过长 ({len(line)} > {MAX_LINE_LENGTH})",
270
- file_path=str(file_path),
271
- line_number=i
272
- ))
273
-
274
- # 检查文件长度
275
- if metrics.code_lines > MAX_FILE_LENGTH:
276
- issues.append(Issue(
277
- severity=Severity.WARNING,
278
- category="复杂度",
279
- message=f"文件过长 ({metrics.code_lines} 行代码 > {MAX_FILE_LENGTH})",
280
- file_path=str(file_path),
281
- suggestion="考虑拆分为多个模块"
282
- ))
283
-
284
- # AST 分析
285
- analyzer = PythonAnalyzer(str(file_path), content)
286
- ast_issues, functions, classes, complexity = analyzer.analyze()
287
- issues.extend(ast_issues)
288
-
289
- metrics.functions = len(functions)
290
- metrics.classes = len(classes)
291
- metrics.max_complexity = complexity
292
-
293
- if functions:
294
- metrics.avg_function_length = sum(f["length"] for f in functions) / len(functions)
295
-
296
- return metrics, issues
297
-
298
-
299
- def analyze_generic_file(file_path: Path) -> Tuple[FileMetrics, List[Issue]]:
300
- """分析通用代码文件"""
301
- metrics = FileMetrics(path=str(file_path))
302
- issues = []
303
-
304
- try:
305
- content = file_path.read_text(encoding='utf-8', errors='ignore')
306
- lines = content.split('\n')
307
- except Exception:
308
- return metrics, issues
309
-
310
- metrics.lines = len(lines)
311
-
312
- comment_patterns = {
313
- '.js': '//',
314
- '.ts': '//',
315
- '.go': '//',
316
- '.java': '//',
317
- '.c': '//',
318
- '.cpp': '//',
319
- '.rs': '//',
320
- }
321
-
322
- suffix = file_path.suffix.lower()
323
- comment_prefix = comment_patterns.get(suffix, '//')
324
-
325
- for i, line in enumerate(lines, 1):
326
- stripped = line.strip()
327
-
328
- if not stripped:
329
- metrics.blank_lines += 1
330
- elif stripped.startswith(comment_prefix) or stripped.startswith('/*') or stripped.startswith('*'):
331
- metrics.comment_lines += 1
332
- else:
333
- metrics.code_lines += 1
334
-
335
- if len(line) > MAX_LINE_LENGTH:
336
- issues.append(Issue(
337
- severity=Severity.INFO,
338
- category="格式",
339
- message=f"行过长 ({len(line)} > {MAX_LINE_LENGTH})",
340
- file_path=str(file_path),
341
- line_number=i
342
- ))
343
-
344
- if metrics.code_lines > MAX_FILE_LENGTH:
345
- issues.append(Issue(
346
- severity=Severity.WARNING,
347
- category="复杂度",
348
- message=f"文件过长 ({metrics.code_lines} 行代码 > {MAX_FILE_LENGTH})",
349
- file_path=str(file_path),
350
- suggestion="考虑拆分为多个模块"
351
- ))
352
-
353
- return metrics, issues
354
-
355
-
356
- def scan_directory(path: str, exclude_dirs: List[str] = None) -> QualityResult:
357
- """扫描目录"""
358
- scan_path = Path(path).resolve()
359
- result = QualityResult(scan_path=str(scan_path))
360
-
361
- if exclude_dirs is None:
362
- exclude_dirs = ['.git', 'node_modules', '__pycache__', '.venv', 'venv', 'dist', 'build', '.tox']
363
-
364
- code_extensions = {'.py', '.js', '.ts', '.go', '.java', '.rs', '.c', '.cpp'}
365
-
366
- for file_path in scan_path.rglob('*'):
367
- if any(ex in file_path.parts for ex in exclude_dirs):
368
- continue
369
-
370
- if file_path.is_file() and file_path.suffix.lower() in code_extensions:
371
- result.files_scanned += 1
372
-
373
- if file_path.suffix.lower() == '.py':
374
- metrics, issues = analyze_python_file(file_path)
375
- else:
376
- metrics, issues = analyze_generic_file(file_path)
377
-
378
- result.file_metrics.append(metrics)
379
- result.issues.extend(issues)
380
- result.total_lines += metrics.lines
381
- result.total_code_lines += metrics.code_lines
382
-
383
- return result
384
-
385
-
386
- def format_report(result: QualityResult, verbose: bool = False) -> str:
387
- """格式化报告"""
388
- lines = []
389
- lines.append("=" * 60)
390
- lines.append("代码质量检查报告")
391
- lines.append("=" * 60)
392
-
393
- lines.append(f"\n扫描路径: {result.scan_path}")
394
- lines.append(f"扫描文件: {result.files_scanned}")
395
- lines.append(f"总行数: {result.total_lines}")
396
- lines.append(f"代码行数: {result.total_code_lines}")
397
- lines.append(f"检查结果: {'✓ 通过' if result.passed else '✗ 需要关注'}")
398
- lines.append(f"错误: {result.error_count} | 警告: {result.warning_count}")
399
-
400
- if result.issues:
401
- lines.append("\n" + "-" * 40)
402
- lines.append("问题列表:")
403
- lines.append("-" * 40)
404
-
405
- # 按类别分组
406
- by_category = defaultdict(list)
407
- for issue in result.issues:
408
- by_category[issue.category].append(issue)
409
-
410
- severity_icons = {"error": "✗", "warning": "⚠", "info": "ℹ"}
411
-
412
- for category, issues in sorted(by_category.items()):
413
- lines.append(f"\n【{category}】({len(issues)} 个)")
414
- for issue in issues[:10]: # 每类最多显示 10 个
415
- icon = severity_icons[issue.severity.value]
416
- loc = f":{issue.line_number}" if issue.line_number else ""
417
- lines.append(f" {icon} {issue.file_path}{loc}")
418
- lines.append(f" {issue.message}")
419
- if verbose and issue.suggestion:
420
- lines.append(f" 💡 {issue.suggestion}")
421
-
422
- if len(issues) > 10:
423
- lines.append(f" ... 及其他 {len(issues) - 10} 个问题")
424
-
425
- if verbose and result.file_metrics:
426
- # 找出最复杂的文件
427
- complex_files = sorted(result.file_metrics, key=lambda m: m.max_complexity, reverse=True)[:5]
428
- if complex_files and complex_files[0].max_complexity > 0:
429
- lines.append("\n" + "-" * 40)
430
- lines.append("复杂度最高的文件:")
431
- lines.append("-" * 40)
432
- for m in complex_files:
433
- if m.max_complexity > 0:
434
- lines.append(f" {m.path}: 复杂度 {m.max_complexity}, {m.functions} 个函数")
435
-
436
- lines.append("\n" + "=" * 60)
437
- return "\n".join(lines)
438
-
439
-
440
- def main():
441
- import argparse
442
-
443
- parser = argparse.ArgumentParser(description="代码质量检查器")
444
- parser.add_argument("path", nargs="?", default=".", help="扫描路径")
445
- parser.add_argument("-v", "--verbose", action="store_true", help="详细输出")
446
- parser.add_argument("--json", action="store_true", help="JSON 格式输出")
447
-
448
- args = parser.parse_args()
449
-
450
- result = scan_directory(args.path)
451
-
452
- if args.json:
453
- output = {
454
- "scan_path": result.scan_path,
455
- "files_scanned": result.files_scanned,
456
- "total_lines": result.total_lines,
457
- "total_code_lines": result.total_code_lines,
458
- "passed": result.passed,
459
- "error_count": result.error_count,
460
- "warning_count": result.warning_count,
461
- "issues": [
462
- {
463
- "severity": i.severity.value,
464
- "category": i.category,
465
- "message": i.message,
466
- "file_path": i.file_path,
467
- "line_number": i.line_number,
468
- "suggestion": i.suggestion
469
- }
470
- for i in result.issues
471
- ]
472
- }
473
- print(json.dumps(output, ensure_ascii=False, indent=2))
474
- else:
475
- print(format_report(result, args.verbose))
476
-
477
- sys.exit(0 if result.passed else 1)
478
-
479
-
480
- if __name__ == "__main__":
481
- main()