code-yangzz 1.0.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.
Files changed (108) hide show
  1. package/README.md +102 -0
  2. package/agents/meta-artisan.md +164 -0
  3. package/agents/meta-conductor.md +482 -0
  4. package/agents/meta-genesis.md +165 -0
  5. package/agents/meta-librarian.md +213 -0
  6. package/agents/meta-prism.md +268 -0
  7. package/agents/meta-scout.md +173 -0
  8. package/agents/meta-sentinel.md +161 -0
  9. package/agents/meta-warden.md +304 -0
  10. package/bin/install.js +390 -0
  11. package/bin/lib/utils.js +72 -0
  12. package/bin/lib/watermark.js +176 -0
  13. package/config/CLAUDE.md +363 -0
  14. package/config/settings.json +120 -0
  15. package/hooks/block-dangerous-bash.mjs +36 -0
  16. package/hooks/post-console-log-warn.mjs +27 -0
  17. package/hooks/post-format.mjs +24 -0
  18. package/hooks/post-typecheck.mjs +27 -0
  19. package/hooks/pre-git-push-confirm.mjs +19 -0
  20. package/hooks/stop-completion-guard.mjs +159 -0
  21. package/hooks/stop-console-log-audit.mjs +44 -0
  22. package/hooks/subagent-context.mjs +27 -0
  23. package/hooks/user-prompt-submit.js +233 -0
  24. package/package.json +36 -0
  25. package/prompt-optimizer/prompt-optimizer-meta.md +159 -0
  26. package/skills/agent-teams/SKILL.md +215 -0
  27. package/skills/domains/ai/SKILL.md +34 -0
  28. package/skills/domains/ai/agent-dev.md +242 -0
  29. package/skills/domains/ai/llm-security.md +288 -0
  30. package/skills/domains/ai/prompt-and-eval.md +279 -0
  31. package/skills/domains/ai/rag-system.md +542 -0
  32. package/skills/domains/architecture/SKILL.md +42 -0
  33. package/skills/domains/architecture/api-design.md +225 -0
  34. package/skills/domains/architecture/caching.md +298 -0
  35. package/skills/domains/architecture/cloud-native.md +285 -0
  36. package/skills/domains/architecture/message-queue.md +328 -0
  37. package/skills/domains/architecture/security-arch.md +297 -0
  38. package/skills/domains/data-engineering/SKILL.md +207 -0
  39. package/skills/domains/development/SKILL.md +46 -0
  40. package/skills/domains/development/cpp.md +246 -0
  41. package/skills/domains/development/go.md +323 -0
  42. package/skills/domains/development/java.md +277 -0
  43. package/skills/domains/development/python.md +288 -0
  44. package/skills/domains/development/rust.md +313 -0
  45. package/skills/domains/development/shell.md +313 -0
  46. package/skills/domains/development/typescript.md +277 -0
  47. package/skills/domains/devops/SKILL.md +39 -0
  48. package/skills/domains/devops/cost-optimization.md +271 -0
  49. package/skills/domains/devops/database.md +217 -0
  50. package/skills/domains/devops/devsecops.md +198 -0
  51. package/skills/domains/devops/git-workflow.md +181 -0
  52. package/skills/domains/devops/observability.md +279 -0
  53. package/skills/domains/devops/performance.md +335 -0
  54. package/skills/domains/devops/testing.md +283 -0
  55. package/skills/domains/frontend-design/SKILL.md +38 -0
  56. package/skills/domains/frontend-design/agents/openai.yaml +4 -0
  57. package/skills/domains/frontend-design/claymorphism/SKILL.md +119 -0
  58. package/skills/domains/frontend-design/claymorphism/references/tokens.css +52 -0
  59. package/skills/domains/frontend-design/component-patterns.md +202 -0
  60. package/skills/domains/frontend-design/engineering.md +287 -0
  61. package/skills/domains/frontend-design/glassmorphism/SKILL.md +140 -0
  62. package/skills/domains/frontend-design/glassmorphism/references/tokens.css +32 -0
  63. package/skills/domains/frontend-design/liquid-glass/SKILL.md +137 -0
  64. package/skills/domains/frontend-design/liquid-glass/references/tokens.css +81 -0
  65. package/skills/domains/frontend-design/neubrutalism/SKILL.md +143 -0
  66. package/skills/domains/frontend-design/neubrutalism/references/tokens.css +44 -0
  67. package/skills/domains/frontend-design/state-management.md +680 -0
  68. package/skills/domains/frontend-design/ui-aesthetics.md +110 -0
  69. package/skills/domains/frontend-design/ux-principles.md +156 -0
  70. package/skills/domains/infrastructure/SKILL.md +200 -0
  71. package/skills/domains/mobile/SKILL.md +224 -0
  72. package/skills/domains/orchestration/SKILL.md +29 -0
  73. package/skills/domains/orchestration/multi-agent.md +263 -0
  74. package/skills/domains/security/SKILL.md +72 -0
  75. package/skills/domains/security/blue-team.md +436 -0
  76. package/skills/domains/security/code-audit.md +265 -0
  77. package/skills/domains/security/pentest.md +226 -0
  78. package/skills/domains/security/red-team.md +374 -0
  79. package/skills/domains/security/threat-intel.md +372 -0
  80. package/skills/domains/security/vuln-research.md +369 -0
  81. package/skills/meta-theory/SKILL.md +878 -0
  82. package/skills/meta-theory/references/create-agent.md +248 -0
  83. package/skills/meta-theory/references/dev-governance.md +1108 -0
  84. package/skills/meta-theory/references/intent-amplification.md +190 -0
  85. package/skills/meta-theory/references/meta-theory.md +346 -0
  86. package/skills/meta-theory/references/rhythm-orchestration.md +257 -0
  87. package/skills/meta-theory/references/ten-step-governance.md +285 -0
  88. package/skills/orchestration/multi-agent/SKILL.md +493 -0
  89. package/skills/run_skill.js +128 -0
  90. package/skills/tools/gen-docs/SKILL.md +115 -0
  91. package/skills/tools/gen-docs/agents/openai.yaml +4 -0
  92. package/skills/tools/gen-docs/scripts/doc_generator.js +435 -0
  93. package/skills/tools/lib/shared.js +98 -0
  94. package/skills/tools/override-refusal/SKILL.md +55 -0
  95. package/skills/tools/override-refusal/agents/openai.yaml +4 -0
  96. package/skills/tools/override-refusal/scripts/refusal_rewriter.js +229 -0
  97. package/skills/tools/verify-change/SKILL.md +139 -0
  98. package/skills/tools/verify-change/agents/openai.yaml +4 -0
  99. package/skills/tools/verify-change/scripts/change_analyzer.js +289 -0
  100. package/skills/tools/verify-module/SKILL.md +126 -0
  101. package/skills/tools/verify-module/agents/openai.yaml +4 -0
  102. package/skills/tools/verify-module/scripts/module_scanner.js +171 -0
  103. package/skills/tools/verify-quality/SKILL.md +159 -0
  104. package/skills/tools/verify-quality/agents/openai.yaml +4 -0
  105. package/skills/tools/verify-quality/scripts/quality_checker.js +337 -0
  106. package/skills/tools/verify-security/SKILL.md +142 -0
  107. package/skills/tools/verify-security/agents/openai.yaml +4 -0
  108. package/skills/tools/verify-security/scripts/security_scanner.js +283 -0
@@ -0,0 +1,159 @@
1
+ ---
2
+ name: verify-quality
3
+ description: 代码质量校验关卡。检测复杂度、重复代码、命名规范、函数长度等质量指标。当用户提到代码质量、复杂度检查、代码异味、重构建议、lint检查、代码规范时使用。在复杂模块、重构完成时自动触发。
4
+ license: MIT
5
+ compatibility: node>=18
6
+ user-invocable: true
7
+ disable-model-invocation: false
8
+ allowed-tools: Bash, Read, Glob
9
+ argument-hint: <扫描路径>
10
+ ---
11
+
12
+ # ⚖ 校验关卡 · 代码质量
13
+
14
+ ## 核心原则
15
+
16
+ ```
17
+ 代码质量 = 可读性 + 可维护性 + 可测试性
18
+ 劣质代码是技术债,技术债是
19
+ 复杂度是 bug 的温床
20
+ ```
21
+
22
+ ## 自动检查
23
+
24
+ 运行质量检查脚本(跨平台):
25
+
26
+ ```bash
27
+ # 在 skill 目录下运行
28
+ node scripts/quality_checker.js <扫描路径>
29
+ node scripts/quality_checker.js <扫描路径> -v # 详细模式
30
+ node scripts/quality_checker.js <扫描路径> --json # JSON 输出
31
+ ```
32
+
33
+ ## 检测指标
34
+
35
+ ### 复杂度指标
36
+
37
+ | 指标 | 阈值 | 超标后果 |
38
+ |------|------|----------|
39
+ | **圈复杂度** | ≤ 10 | 🟠 警告,建议拆分 |
40
+ | **函数长度** | ≤ 50 行 | 🟠 警告,建议拆分 |
41
+ | **文件长度** | ≤ 500 行 | 🟡 提示,考虑拆分 |
42
+ | **参数数量** | ≤ 5 | 🟠 警告,考虑封装 |
43
+ | **嵌套深度** | ≤ 4 | 🟠 警告,建议重构 |
44
+ | **行长度** | ≤ 120 | 🔵 提示 |
45
+
46
+ ### 命名规范
47
+
48
+ | 类型 | 规范 | 示例 |
49
+ |------|------|------|
50
+ | **类名** | PascalCase | `UserService`, `HttpClient` |
51
+ | **函数名** | snake_case | `get_user`, `process_data` |
52
+ | **常量** | UPPER_SNAKE | `MAX_RETRY`, `DEFAULT_TIMEOUT` |
53
+ | **变量** | snake_case | `user_id`, `total_count` |
54
+
55
+ ### 代码异味
56
+
57
+ | 异味 | 说明 | 严重度 |
58
+ |------|------|--------|
59
+ | 重复代码 | 相似代码块 > 10 行 | 🟠 High |
60
+ | 过长参数列表 | 参数 > 5 个 | 🟡 Medium |
61
+ | 魔法数字 | 未命名的常量 | 🟡 Medium |
62
+ | 死代码 | 未使用的函数/变量 | 🔵 Low |
63
+ | 注释代码 | 被注释的代码块 | 🔵 Low |
64
+
65
+ ## 自动触发时机
66
+
67
+ | 场景 | 触发条件 |
68
+ |------|----------|
69
+ | 复杂模块 | 代码行数 > 200 |
70
+ | 重构完成 | 重构任务完成时 |
71
+ | 代码审查 | PR/MR 审查时 |
72
+ | 提交前 | 代码提交前检查 |
73
+
74
+ ## 校验流程
75
+
76
+ ```
77
+ 1. 扫描代码文件
78
+ 2. 计算复杂度指标
79
+ 3. 检测代码异味
80
+ 4. 验证命名规范
81
+ 5. 输出质量校验报告
82
+ ```
83
+
84
+ ## 校验报告格式
85
+
86
+ ```
87
+ ## 代码质量校验报告
88
+
89
+ ✓ 通过 | ✗ 未通过
90
+
91
+ ### 复杂度指标
92
+ - 平均函数复杂度: N
93
+ - 超标函数数: N
94
+ - 最大文件行数: N
95
+
96
+ ### 代码异味
97
+ - 🟠 High: N
98
+ - 🟡 Medium: N
99
+ - 🔵 Low: N
100
+
101
+ ### 问题清单
102
+
103
+ | 文件 | 行号 | 类型 | 严重度 | 描述 |
104
+ |------|------|------|--------|------|
105
+ | ... | ... | ... | ... | ... |
106
+
107
+ ### 结论
108
+ 可交付 / 需重构后交付
109
+ ```
110
+
111
+ ## 重构建议
112
+
113
+ ### 降低复杂度
114
+
115
+ ```python
116
+ # 🔴 高复杂度 - 不稳
117
+ def process(data):
118
+ if condition1:
119
+ if condition2:
120
+ if condition3:
121
+ # 深层嵌套
122
+ pass
123
+
124
+ # ✅ 低复杂度 - 稳固
125
+ def process(data):
126
+ if not condition1:
127
+ return
128
+ if not condition2:
129
+ return
130
+ if not condition3:
131
+ return
132
+ # 主逻辑
133
+ ```
134
+
135
+ ### 消除重复
136
+
137
+ ```python
138
+ # 🔴 重复代码 - 异端
139
+ def func1():
140
+ # 10行相同逻辑
141
+ pass
142
+
143
+ def func2():
144
+ # 10行相同逻辑
145
+ pass
146
+
147
+ # ✅ 提取公共函数 - 正道
148
+ def common_logic():
149
+ # 公共逻辑
150
+ pass
151
+
152
+ def func1():
153
+ common_logic()
154
+
155
+ def func2():
156
+ common_logic()
157
+ ```
158
+
159
+ ---
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Verify Quality"
3
+ short_description: "代码质量校验关卡"
4
+ default_prompt: "Read the skill at skills/tools/verify-quality/SKILL.md, then run: node skills/run_skill.js verify-quality $ARGUMENTS"
@@ -0,0 +1,337 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const { parseCliArgs, buildReport, hasFatal } = require(path.join(__dirname, '..', '..', 'lib', 'shared.js'));
7
+
8
+ // 质量规则配置
9
+ const MAX_LINE_LENGTH = 120;
10
+ const MAX_FUNCTION_LENGTH = 50;
11
+ const MAX_FILE_LENGTH = 500;
12
+ const MAX_COMPLEXITY = 10;
13
+ const MAX_PARAMETERS = 5;
14
+ const MIN_FUNCTION_NAME_LENGTH = 2;
15
+
16
+ const EXCLUDE_DIRS = new Set(['.git', 'node_modules', '__pycache__', '.venv', 'venv', 'dist', 'build', '.tox']);
17
+ const CODE_EXTENSIONS = new Set(['.py', '.js', '.ts', '.go', '.java', '.rs', '.c', '.cpp']);
18
+
19
+ const COMMENT_PREFIXES = {
20
+ '.js': '//', '.ts': '//', '.go': '//', '.java': '//',
21
+ '.c': '//', '.cpp': '//', '.rs': '//',
22
+ };
23
+
24
+ // --- Analysis ---
25
+
26
+ function analyzeGenericFile(filePath) {
27
+ const metrics = {
28
+ path: filePath, lines: 0, code_lines: 0, comment_lines: 0,
29
+ blank_lines: 0, functions: 0, classes: 0,
30
+ max_complexity: 0, avg_function_length: 0,
31
+ };
32
+ const issues = [];
33
+ let content;
34
+ try {
35
+ content = fs.readFileSync(filePath, 'utf-8');
36
+ } catch { return { metrics, issues }; }
37
+
38
+ const lines = content.split('\n');
39
+ metrics.lines = lines.length;
40
+ const prefix = COMMENT_PREFIXES[
41
+ path.extname(filePath).toLowerCase()
42
+ ] || '//';
43
+
44
+ for (let i = 0; i < lines.length; i++) {
45
+ const stripped = lines[i].trim();
46
+ if (!stripped) metrics.blank_lines++;
47
+ else if (
48
+ stripped.startsWith(prefix) ||
49
+ stripped.startsWith('/*') ||
50
+ stripped.startsWith('*')
51
+ ) metrics.comment_lines++;
52
+ else metrics.code_lines++;
53
+
54
+ if (lines[i].length > MAX_LINE_LENGTH) {
55
+ issues.push({
56
+ severity: 'info', category: '格式',
57
+ message: `行过长 (${lines[i].length} > ${MAX_LINE_LENGTH})`,
58
+ file_path: filePath, line_number: i + 1,
59
+ suggestion: null,
60
+ });
61
+ }
62
+ }
63
+
64
+ if (metrics.code_lines > MAX_FILE_LENGTH) {
65
+ issues.push({
66
+ severity: 'warning', category: '复杂度',
67
+ message: `文件过长 (${metrics.code_lines} 行代码 > ${MAX_FILE_LENGTH})`,
68
+ file_path: filePath, suggestion: '考虑拆分为多个模块',
69
+ line_number: null,
70
+ });
71
+ }
72
+
73
+ return { metrics, issues };
74
+ }
75
+
76
+ function analyzePythonFile(filePath) {
77
+ const metrics = {
78
+ path: filePath, lines: 0, code_lines: 0, comment_lines: 0,
79
+ blank_lines: 0, functions: 0, classes: 0,
80
+ max_complexity: 0, avg_function_length: 0,
81
+ };
82
+ const issues = [];
83
+ let content;
84
+ try {
85
+ content = fs.readFileSync(filePath, 'utf-8');
86
+ } catch (e) {
87
+ issues.push({
88
+ severity: 'error', category: '文件',
89
+ message: `无法读取文件: ${e.message}`,
90
+ file_path: filePath, line_number: null, suggestion: null,
91
+ });
92
+ return { metrics, issues };
93
+ }
94
+
95
+ const lines = content.split('\n');
96
+ metrics.lines = lines.length;
97
+ let inMultiline = false;
98
+
99
+ for (let i = 0; i < lines.length; i++) {
100
+ const stripped = lines[i].trim();
101
+ if (!stripped) { metrics.blank_lines++; }
102
+ else if (stripped.startsWith('#')) { metrics.comment_lines++; }
103
+ else if (stripped.includes('"""') || stripped.includes("'''")) {
104
+ const dq = (stripped.match(/"""/g) || []).length;
105
+ const sq = (stripped.match(/'''/g) || []).length;
106
+ if (dq === 2 || sq === 2) { metrics.comment_lines++; }
107
+ else { inMultiline = !inMultiline; metrics.comment_lines++; }
108
+ } else if (inMultiline) { metrics.comment_lines++; }
109
+ else { metrics.code_lines++; }
110
+
111
+ if (lines[i].length > MAX_LINE_LENGTH) {
112
+ issues.push({
113
+ severity: 'info', category: '格式',
114
+ message: `行过长 (${lines[i].length} > ${MAX_LINE_LENGTH})`,
115
+ file_path: filePath, line_number: i + 1,
116
+ suggestion: null,
117
+ });
118
+ }
119
+ }
120
+
121
+ if (metrics.code_lines > MAX_FILE_LENGTH) {
122
+ issues.push({
123
+ severity: 'warning', category: '复杂度',
124
+ message: `文件过长 (${metrics.code_lines} 行代码 > ${MAX_FILE_LENGTH})`,
125
+ file_path: filePath, suggestion: '考虑拆分为多个模块',
126
+ line_number: null,
127
+ });
128
+ }
129
+
130
+ // Regex-based Python analysis (no AST available in Node)
131
+ const funcRegex = /^( *)(?:async\s+)?def\s+(\w+)\s*\(([^)]*)\)/gm;
132
+ const classRegex = /^( *)class\s+(\w+)/gm;
133
+ const functions = [];
134
+ let match;
135
+
136
+ while ((match = funcRegex.exec(content)) !== null) {
137
+ const lineNum = content.substring(0, match.index).split('\n').length;
138
+ const name = match[2];
139
+ const indent = match[1].length;
140
+ const params = match[3].trim()
141
+ ? match[3].split(',').map(p => p.trim())
142
+ .filter(p => p && p !== 'self' && p !== 'cls')
143
+ : [];
144
+
145
+ // Calculate function length by finding next line at same or lesser indent
146
+ const funcLines = lines.slice(lineNum); // lines after def
147
+ let length = 1;
148
+ for (let j = 1; j < funcLines.length; j++) {
149
+ const l = funcLines[j];
150
+ if (l.trim() === '') { length++; continue; }
151
+ const curIndent = l.match(/^(\s*)/)[1].length;
152
+ if (curIndent <= indent && l.trim() !== '') break;
153
+ length++;
154
+ }
155
+
156
+ // Estimate complexity from function body
157
+ const bodyLines = lines.slice(lineNum, lineNum + length - 1);
158
+ let complexity = 1;
159
+ for (const bl of bodyLines) {
160
+ const s = bl.trim();
161
+ if (/^(if|elif|while|for)\s/.test(s) || /^(if|elif|while|for)\(/.test(s)) complexity++;
162
+ if (/^except(\s|:)/.test(s)) complexity++;
163
+ if (/\s(and|or)\s/.test(s)) complexity++;
164
+ if (/\sfor\s/.test(s) && /\sin\s/.test(s) && (s.includes('[') || s.includes('('))) complexity++;
165
+ }
166
+
167
+ functions.push({ name, line: lineNum, length, complexity, parameters: params.length });
168
+ metrics.max_complexity = Math.max(metrics.max_complexity, complexity);
169
+
170
+ // Check function length
171
+ if (length > MAX_FUNCTION_LENGTH) {
172
+ issues.push({
173
+ severity: 'warning', category: '复杂度',
174
+ message: `函数 '${name}' 过长 (${length} 行 > ${MAX_FUNCTION_LENGTH})`,
175
+ file_path: filePath, line_number: lineNum,
176
+ suggestion: '考虑拆分为多个小函数',
177
+ });
178
+ }
179
+ // Check complexity
180
+ if (complexity > MAX_COMPLEXITY) {
181
+ issues.push({
182
+ severity: 'warning', category: '复杂度',
183
+ message: `函数 '${name}' 圈复杂度过高 (${complexity} > ${MAX_COMPLEXITY})`,
184
+ file_path: filePath, line_number: lineNum,
185
+ suggestion: '减少嵌套层级,提取子函数',
186
+ });
187
+ }
188
+ // Check parameter count
189
+ if (params.length > MAX_PARAMETERS) {
190
+ issues.push({
191
+ severity: 'warning', category: '设计',
192
+ message: `函数 '${name}' 参数过多 (${params.length} > ${MAX_PARAMETERS})`,
193
+ file_path: filePath, line_number: lineNum,
194
+ suggestion: '考虑使用配置对象或数据类封装参数',
195
+ });
196
+ }
197
+ // Check naming
198
+ const SPECIAL = new Set([
199
+ 'setUp', 'tearDown', 'setUpClass',
200
+ 'tearDownClass', 'setUpModule', 'tearDownModule',
201
+ ]);
202
+ if (!name.startsWith('_') && !SPECIAL.has(name) && !name.startsWith('visit_')) {
203
+ if (!/^[a-z][a-z0-9_]*$/.test(name)) {
204
+ issues.push({
205
+ severity: 'info', category: '命名',
206
+ message: `函数名 '${name}' 不符合 snake_case 规范`,
207
+ file_path: filePath, line_number: lineNum,
208
+ suggestion: '函数名应使用 snake_case',
209
+ });
210
+ }
211
+ }
212
+ if (name.length < MIN_FUNCTION_NAME_LENGTH) {
213
+ issues.push({
214
+ severity: 'warning', category: '命名',
215
+ message: `函数名 '${name}' 过短`,
216
+ file_path: filePath, line_number: lineNum,
217
+ suggestion: '使用更具描述性的函数名',
218
+ });
219
+ }
220
+ }
221
+
222
+ while ((match = classRegex.exec(content)) !== null) {
223
+ const lineNum = content.substring(0, match.index).split('\n').length;
224
+ const name = match[2];
225
+ metrics.classes++;
226
+ if (!/^[A-Z][a-zA-Z0-9]*$/.test(name)) {
227
+ issues.push({
228
+ severity: 'warning', category: '命名',
229
+ message: `类名 '${name}' 不符合 PascalCase 规范`,
230
+ file_path: filePath, line_number: lineNum,
231
+ suggestion: '类名应使用 PascalCase,如 MyClassName',
232
+ });
233
+ }
234
+ }
235
+
236
+ metrics.functions = functions.length;
237
+ if (functions.length > 0) {
238
+ metrics.avg_function_length = functions.reduce((s, f) => s + f.length, 0) / functions.length;
239
+ }
240
+
241
+ return { metrics, issues };
242
+ }
243
+
244
+ // --- Directory scan ---
245
+
246
+ function scanDirectory(scanPath, excludeDirs) {
247
+ const resolved = path.resolve(scanPath);
248
+ const exclude = excludeDirs || EXCLUDE_DIRS;
249
+ const result = {
250
+ scan_path: resolved, files_scanned: 0,
251
+ total_lines: 0, total_code_lines: 0,
252
+ issues: [], file_metrics: [],
253
+ };
254
+
255
+ function walk(dir) {
256
+ let entries;
257
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
258
+ for (const entry of entries) {
259
+ if (exclude.has(entry.name)) continue;
260
+ const full = path.join(dir, entry.name);
261
+ if (entry.isDirectory()) { walk(full); continue; }
262
+ const ext = path.extname(entry.name).toLowerCase();
263
+ if (!CODE_EXTENSIONS.has(ext)) continue;
264
+
265
+ result.files_scanned++;
266
+ const { metrics, issues } = ext === '.py' ? analyzePythonFile(full) : analyzeGenericFile(full);
267
+ result.file_metrics.push(metrics);
268
+ result.issues.push(...issues);
269
+ result.total_lines += metrics.lines;
270
+ result.total_code_lines += metrics.code_lines;
271
+ }
272
+ }
273
+
274
+ walk(resolved);
275
+ return result;
276
+ }
277
+
278
+ // --- Reporting ---
279
+
280
+ function passed(result) { return !hasFatal(result.issues); }
281
+
282
+ function formatReport(result, verbose) {
283
+ const errs = result.issues.filter(i => i.severity === 'error').length;
284
+ const warns = result.issues.filter(i => i.severity === 'warning').length;
285
+ const fields = {
286
+ '扫描路径': result.scan_path,
287
+ '扫描文件': result.files_scanned,
288
+ '总行数': result.total_lines,
289
+ '代码行数': result.total_code_lines,
290
+ '检查结果': passed(result) ? '✓ 通过' : '✗ 需要关注',
291
+ '统计': `错误: ${errs} | 警告: ${warns}`,
292
+ };
293
+ let report = buildReport(
294
+ '代码质量检查报告', fields, result.issues, verbose, 'category'
295
+ );
296
+
297
+ if (verbose && result.file_metrics.length) {
298
+ const complex = result.file_metrics
299
+ .filter(m => m.max_complexity > 0)
300
+ .sort((a, b) => b.max_complexity - a.max_complexity)
301
+ .slice(0, 5);
302
+ if (complex.length) {
303
+ const lines = ['\n' + '-'.repeat(40), '复杂度最高的文件:', '-'.repeat(40)];
304
+ for (const m of complex) lines.push(` ${m.path}: 复杂度 ${m.max_complexity}, ${m.functions} 个函数`);
305
+ report += '\n' + lines.join('\n');
306
+ }
307
+ }
308
+ return report;
309
+ }
310
+
311
+ // --- CLI ---
312
+
313
+ function main() {
314
+ const opts = parseCliArgs(process.argv);
315
+
316
+ const result = scanDirectory(opts.target);
317
+
318
+ if (opts.json) {
319
+ const output = {
320
+ scan_path: result.scan_path,
321
+ files_scanned: result.files_scanned,
322
+ total_lines: result.total_lines,
323
+ total_code_lines: result.total_code_lines,
324
+ passed: passed(result),
325
+ error_count: result.issues.filter(i => i.severity === 'error').length,
326
+ warning_count: result.issues.filter(i => i.severity === 'warning').length,
327
+ issues: result.issues
328
+ };
329
+ console.log(JSON.stringify(output, null, 2));
330
+ } else {
331
+ console.log(formatReport(result, opts.verbose));
332
+ }
333
+
334
+ process.exit(passed(result) ? 0 : 1);
335
+ }
336
+
337
+ main();
@@ -0,0 +1,142 @@
1
+ ---
2
+ name: verify-security
3
+ description: 安全校验关卡。自动扫描代码安全漏洞,检测危险模式,确保安全决策有文档记录。当用户提到安全扫描、漏洞检测、安全审计、代码安全、OWASP、注入检测、敏感信息泄露时使用。在新建模块、安全相关变更、攻防任务、重构完成时自动触发。
4
+ license: MIT
5
+ compatibility: node>=18
6
+ user-invocable: true
7
+ disable-model-invocation: false
8
+ allowed-tools: Bash, Read, Grep
9
+ argument-hint: <扫描路径>
10
+ ---
11
+
12
+ # ⚖ 校验关卡 · 安全校验
13
+
14
+ ## 核心原则
15
+
16
+ ```
17
+ 安全即,破则劫败
18
+ 安全决策必须可追溯
19
+ Critical/High 问题必须修复后才能交付
20
+ ```
21
+
22
+ ## 自动扫描
23
+
24
+ 运行安全扫描脚本(跨平台):
25
+
26
+ ```bash
27
+ # 在 skill 目录下运行
28
+ node scripts/security_scanner.js <扫描路径>
29
+ node scripts/security_scanner.js <扫描路径> -v # 详细模式
30
+ node scripts/security_scanner.js <扫描路径> --json # JSON 输出
31
+ node scripts/security_scanner.js <扫描路径> --exclude vendor # 排除目录
32
+ ```
33
+
34
+ ## 检测范围
35
+
36
+ ### 自动检测的漏洞类型
37
+
38
+ | 类别 | 检测项 | 严重度 |
39
+ |------|--------|--------|
40
+ | **注入** | SQL 注入、命令注入、代码注入 | 🔴 Critical |
41
+ | **敏感信息** | 硬编码密钥、AWS Key、私钥 | 🔴 Critical |
42
+ | **XSS** | innerHTML、dangerouslySetInnerHTML | 🟠 High |
43
+ | **反序列化** | pickle.loads、yaml.load | 🟠 High |
44
+ | **路径遍历** | 未验证的文件路径操作 | 🟠 High |
45
+ | **SSRF** | 未验证的 URL 请求 | 🟠 High |
46
+ | **XXE** | 不安全的 XML 解析 | 🟠 High |
47
+ | **弱加密** | MD5、SHA1 用于安全场景 | 🟡 Medium |
48
+ | **不安全随机** | random 模块用于安全场景 | 🟡 Medium |
49
+ | **调试代码** | console.log、print、debugger | 🔵 Low |
50
+
51
+ ### 文档层面检查
52
+
53
+ 安全相关代码必须在 DESIGN.md 中记录:
54
+
55
+ - [ ] **威胁模型** — 防御哪些攻击
56
+ - [ ] **安全决策** — 为何选择此方案
57
+ - [ ] **安全边界** — 信任边界在哪里
58
+ - [ ] **已知风险** — 接受了哪些风险
59
+
60
+ ## 危险模式速查
61
+
62
+ ### Python
63
+ ```python
64
+ # 🔴 危险 - 触犯
65
+ eval(), exec(), os.system()
66
+ subprocess(..., shell=True)
67
+ pickle.loads(), yaml.load()
68
+ cursor.execute(f"SELECT * FROM t WHERE id = {id}")
69
+
70
+ # ✅ 安全替代 - 稳固
71
+ ast.literal_eval()
72
+ subprocess([...], shell=False)
73
+ yaml.safe_load()
74
+ cursor.execute("SELECT * FROM t WHERE id = %s", (id,))
75
+ ```
76
+
77
+ ### JavaScript
78
+ ```javascript
79
+ // 🔴 危险 - 触犯
80
+ eval(), innerHTML, document.write()
81
+ new Function(userInput)
82
+
83
+ // ✅ 安全替代 - 稳固
84
+ JSON.parse(), textContent
85
+ 模板引擎自动转义
86
+ ```
87
+
88
+ ### Go
89
+ ```go
90
+ // 🔴 危险 - 触犯
91
+ exec.Command("sh", "-c", userInput)
92
+ template.HTML(userInput)
93
+
94
+ // ✅ 安全替代 - 稳固
95
+ exec.Command("cmd", args...)
96
+ html/template 自动转义
97
+ ```
98
+
99
+ ## 校验流程
100
+
101
+ ```
102
+ 1. 运行 security_scanner.js 自动扫描
103
+ 2. 分析扫描结果,按严重度排序
104
+ 3. 检查安全决策是否有文档记录
105
+ 4. 输出安全校验报告
106
+ 5. Critical/High 问题必须修复后才能交付
107
+ ```
108
+
109
+ ## 自动触发时机
110
+
111
+ | 场景 | 触发条件 |
112
+ |------|----------|
113
+ | 新建模块 | 模块创建完成时 |
114
+ | 安全相关变更 | 涉及认证、授权、加密、输入处理 |
115
+ | 攻防任务 | 红队/蓝队任务完成时 |
116
+ | 重构完成 | 重构任务完成时 |
117
+ | 提交前 | 代码提交前检查 |
118
+
119
+ ## 校验报告格式
120
+
121
+ ```
122
+ ## 安全校验报告
123
+
124
+ ✓ 通过 | ✗ 未通过
125
+
126
+ - 🔴 Critical: N
127
+ - 🟠 High: N
128
+ - 🟡 Medium: N
129
+ - 🔵 Low: N
130
+
131
+ ### 发现问题
132
+
133
+ | 文件 | 行号 | 类型 | 严重度 | 描述 |
134
+ |------|------|------|--------|------|
135
+ | ... | ... | ... | ... | ... |
136
+
137
+ ### 结论
138
+
139
+ 可交付 / 需修复后交付
140
+ ```
141
+
142
+ ---
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Verify Security"
3
+ short_description: "安全校验关卡"
4
+ default_prompt: "Read the skill at skills/tools/verify-security/SKILL.md, then run: node skills/run_skill.js verify-security $ARGUMENTS"