@chongyan/autospec 1.0.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.
- package/LICENSE +21 -0
- package/README.en.md +472 -0
- package/README.md +476 -0
- package/bin/autospec.js +3 -0
- package/knowledge/README.md +144 -0
- package/knowledge/checklists/code.md +182 -0
- package/knowledge/checklists/design.md +196 -0
- package/knowledge/checklists/release.md +70 -0
- package/knowledge/checklists/requirement.md +169 -0
- package/knowledge/checklists/test.md +46 -0
- package/knowledge/config/README.en.md +44 -0
- package/knowledge/config/README.md +44 -0
- package/knowledge/config/role-composition.yaml +98 -0
- package/knowledge/config/role-extensions.yaml +140 -0
- package/knowledge/config/skill-compositions.yaml +142 -0
- package/knowledge/config/team-stage.yaml +95 -0
- package/knowledge/config/team-tasks.yaml +139 -0
- package/knowledge/config/team-triggers.yaml +198 -0
- package/knowledge/config/validation-patterns.yaml +137 -0
- package/knowledge/domain/README.md +115 -0
- package/knowledge/domain/flows/README.md +194 -0
- package/knowledge/domain/glossary.md +143 -0
- package/knowledge/domain/rules.md +138 -0
- package/knowledge/environment/README.en.md +36 -0
- package/knowledge/environment/README.md +87 -0
- package/knowledge/environment/component-knowledge.md +316 -0
- package/knowledge/environment/detection-patterns.yaml +502 -0
- package/knowledge/environment/middleware-knowledge.md +237 -0
- package/knowledge/environment/template-registry.md +321 -0
- package/knowledge/guides/domain-driven-design.md +345 -0
- package/knowledge/guides/knowledge-management.md +369 -0
- package/knowledge/guides/requirement-engineering.md +329 -0
- package/knowledge/guides/stages/ai-effect-evaluator.md +93 -0
- package/knowledge/guides/stages/code-implementer.md +205 -0
- package/knowledge/guides/stages/code-reviewer.md +111 -0
- package/knowledge/guides/stages/consistency-checker.md +177 -0
- package/knowledge/guides/stages/design-planner.md +401 -0
- package/knowledge/guides/stages/design-reviewer.md +83 -0
- package/knowledge/guides/stages/integration-test-runner.md +105 -0
- package/knowledge/guides/stages/release-checker.md +205 -0
- package/knowledge/guides/stages/requirement-analyzer.md +195 -0
- package/knowledge/guides/stages/requirement-reviewer.md +83 -0
- package/knowledge/guides/stages/security-reviewer.md +89 -0
- package/knowledge/guides/stages/test-context-analyzer.md +250 -0
- package/knowledge/guides/stages/test-generator.md +241 -0
- package/knowledge/guides/stages/test-planner.md +183 -0
- package/knowledge/guides/stages/test-reviewer.md +76 -0
- package/knowledge/guides/stages/unit-test-runner.md +83 -0
- package/knowledge/guides/support/ai-agent-analyzer.md +362 -0
- package/knowledge/guides/support/ai-anomaly-analyzer.md +213 -0
- package/knowledge/guides/support/ai-artifact-evaluator.md +192 -0
- package/knowledge/guides/support/ai-capability-analyzer.md +193 -0
- package/knowledge/guides/support/ai-component-analyzer.md +169 -0
- package/knowledge/guides/support/ai-data-validator.md +276 -0
- package/knowledge/guides/support/ai-evaluation-planner.md +374 -0
- package/knowledge/guides/support/ai-path-evaluator.md +274 -0
- package/knowledge/guides/support/ai-pipeline-evaluator.md +219 -0
- package/knowledge/guides/support/ai-rag-analyzer.md +339 -0
- package/knowledge/guides/support/ai-task-assessor.md +418 -0
- package/knowledge/guides/support/ai-test-diagnostics.md +133 -0
- package/knowledge/guides/support/complexity-assessor.md +268 -0
- package/knowledge/guides/support/component-discovery.md +183 -0
- package/knowledge/guides/support/environment-scanner.md +207 -0
- package/knowledge/guides/support/environment-validator.md +207 -0
- package/knowledge/guides/support/knowledge-generator.md +234 -0
- package/knowledge/guides/support/methodology-extractor.md +55 -0
- package/knowledge/guides/support/pipeline-protocol.md +438 -0
- package/knowledge/guides/support/practice-logger.md +359 -0
- package/knowledge/guides/support/scope-inference.md +174 -0
- package/knowledge/guides/support/skill-distiller.md +91 -0
- package/knowledge/guides/support/skill-updater.md +45 -0
- package/knowledge/guides/support/skill-validator.md +72 -0
- package/knowledge/guides/support/team-orchestrator.md +323 -0
- package/knowledge/guides/support/tech-stack-analyzer.md +139 -0
- package/knowledge/guides/support/test-runner.md +254 -0
- package/knowledge/guides/system-design.md +352 -0
- package/knowledge/organization/ai-native-team.md +318 -0
- package/knowledge/organization/team-metrics.md +228 -0
- package/knowledge/principles/constitution.md +134 -0
- package/knowledge/principles/core-principles.md +368 -0
- package/knowledge/principles/design-philosophy.md +877 -0
- package/knowledge/principles/evolution.md +553 -0
- package/knowledge/process/01-requirement.md +113 -0
- package/knowledge/process/02-design.md +123 -0
- package/knowledge/process/03-implementation.md +90 -0
- package/knowledge/process/04-review.md +80 -0
- package/knowledge/process/05-testing.md +90 -0
- package/knowledge/process/06-delivery.md +88 -0
- package/knowledge/process/README.en.md +38 -0
- package/knowledge/process/README.md +48 -0
- package/knowledge/process/ai-sdlc.md +475 -0
- package/knowledge/process/overview.md +319 -0
- package/knowledge/standards/code-review.md +876 -0
- package/knowledge/standards/coding-style.md +940 -0
- package/knowledge/standards/data-consistency.md +1085 -0
- package/knowledge/standards/document-versioning.md +210 -0
- package/knowledge/standards/risk-detection.md +186 -0
- package/knowledge/templates/ai-evaluation.md +150 -0
- package/knowledge/templates/api-design.md +117 -0
- package/knowledge/templates/database-design.md +132 -0
- package/knowledge/templates/domain-driven-design.md +321 -0
- package/knowledge/templates/product-proposal.md +201 -0
- package/knowledge/templates/system-design.md +227 -0
- package/knowledge/templates/task-breakdown.md +107 -0
- package/knowledge/templates/test-case.md +170 -0
- package/package.json +53 -0
- package/plugins/.claude-plugin/plugin.json +134 -0
- package/plugins/agents/roles/ai-engineer.md +129 -0
- package/plugins/agents/roles/backend-engineer.md +165 -0
- package/plugins/agents/roles/ceo.md +94 -0
- package/plugins/agents/roles/data-engineer.md +135 -0
- package/plugins/agents/roles/devops-engineer.md +181 -0
- package/plugins/agents/roles/frontend-engineer.md +129 -0
- package/plugins/agents/roles/product-owner.md +98 -0
- package/plugins/agents/roles/quality-engineer.md +129 -0
- package/plugins/agents/roles/security-engineer.md +180 -0
- package/plugins/agents/roles/tech-lead.md +97 -0
- package/plugins/agents/support/blind-comparator.md +88 -0
- package/plugins/agents/support/consistency-checker.md +103 -0
- package/plugins/agents/support/failure-diagnostician.md +141 -0
- package/plugins/agents/support/independent-reviewer.md +80 -0
- package/plugins/agents/support/safety-auditor.md +121 -0
- package/plugins/agents/support/skill-benchmarker.md +86 -0
- package/plugins/agents/support/skill-forger.md +105 -0
- package/plugins/agents/support/stage-gate-evaluator.md +121 -0
- package/plugins/agents/support/test-coverage-reviewer.md +73 -0
- package/plugins/benchmarks/templates/README.md +44 -0
- package/plugins/benchmarks/templates/commands/explore-template.yaml +48 -0
- package/plugins/benchmarks/templates/pipeline/agile-template.yaml +84 -0
- package/plugins/benchmarks/templates/pipeline/waterfall-template.yaml +106 -0
- package/plugins/benchmarks/templates/skills/requirement-analyzer-template.yaml +48 -0
- package/plugins/commands/README.en.md +96 -0
- package/plugins/commands/README.md +96 -0
- package/plugins/commands/apply.md +191 -0
- package/plugins/commands/archive.md +76 -0
- package/plugins/commands/env-export.md +79 -0
- package/plugins/commands/env-sync.md +640 -0
- package/plugins/commands/env-template.md +223 -0
- package/plugins/commands/env-update.md +264 -0
- package/plugins/commands/env-validate.md +176 -0
- package/plugins/commands/env.md +79 -0
- package/plugins/commands/explore.md +76 -0
- package/plugins/commands/field-evolve.md +536 -0
- package/plugins/commands/memory.md +249 -0
- package/plugins/commands/project-evolve.md +821 -0
- package/plugins/commands/propose.md +93 -0
- package/plugins/commands/review.md +140 -0
- package/plugins/commands/run.md +224 -0
- package/plugins/commands/status.md +62 -0
- package/plugins/commands/validate.md +108 -0
- package/plugins/hooks/README.en.md +56 -0
- package/plugins/hooks/README.md +56 -0
- package/plugins/hooks/ai-project-guard.js +329 -0
- package/plugins/hooks/artifact-evaluation-hook.js +237 -0
- package/plugins/hooks/constitution-guard.js +211 -0
- package/plugins/hooks/environment-autocommit.js +264 -0
- package/plugins/hooks/environment-manager.js +778 -0
- package/plugins/hooks/execution-tracker.js +354 -0
- package/plugins/hooks/frozen-zone-guard.js +140 -0
- package/plugins/hooks/layer1-validator.js +423 -0
- package/plugins/hooks/lib/artifact-evaluator.js +414 -0
- package/plugins/hooks/lib/benchmarks/change-detector.js +390 -0
- package/plugins/hooks/lib/benchmarks/evaluator.js +605 -0
- package/plugins/hooks/lib/benchmarks/integration-example.js +169 -0
- package/plugins/hooks/lib/data-and-ai-detector.js +275 -0
- package/plugins/hooks/lib/detection-pattern-loader.js +865 -0
- package/plugins/hooks/lib/directory-discovery.js +395 -0
- package/plugins/hooks/lib/environment-config-loader.js +341 -0
- package/plugins/hooks/lib/environment-detector.js +553 -0
- package/plugins/hooks/lib/environment-evolver.js +564 -0
- package/plugins/hooks/lib/environment-registry.js +813 -0
- package/plugins/hooks/lib/execution-path.js +427 -0
- package/plugins/hooks/lib/hook-error-recorder.js +245 -0
- package/plugins/hooks/lib/hook-logger.js +538 -0
- package/plugins/hooks/lib/hook-runner.js +97 -0
- package/plugins/hooks/lib/hook-runner.sh +44 -0
- package/plugins/hooks/lib/hook-state-manager.js +480 -0
- package/plugins/hooks/lib/memory-extractor.js +377 -0
- package/plugins/hooks/lib/memory-manager.js +673 -0
- package/plugins/hooks/lib/metrics-analyzer.js +489 -0
- package/plugins/hooks/lib/project-evolution/auto-fixer.js +511 -0
- package/plugins/hooks/lib/project-evolution/memory-manager.js +346 -0
- package/plugins/hooks/lib/project-evolution/pattern-detector.js +476 -0
- package/plugins/hooks/lib/project-evolution/semantic-indexer.js +480 -0
- package/plugins/hooks/lib/project-structure-detector.js +326 -0
- package/plugins/hooks/lib/rollback-tracker.js +346 -0
- package/plugins/hooks/lib/source-code-scanner.js +596 -0
- package/plugins/hooks/lib/technology-stack-detector.js +374 -0
- package/plugins/hooks/lib/test-failure-analyzer.js +375 -0
- package/plugins/hooks/lib/test-failure-fixer.js +268 -0
- package/plugins/hooks/lib/trace-context.js +277 -0
- package/plugins/hooks/lib/validation-patterns.js +415 -0
- package/plugins/hooks/memory-sync.js +171 -0
- package/plugins/hooks/pipeline-observer.js +413 -0
- package/plugins/hooks/scope-sentinel.js +204 -0
- package/plugins/hooks/trace-initialization.js +169 -0
- package/plugins/memory/templates/code-quality.yaml +149 -0
- package/plugins/memory/templates/multi-system.yaml +155 -0
- package/plugins/memory/templates/team-habits.yaml +119 -0
- package/plugins/memory/templates/testing.yaml +121 -0
- package/plugins/skills/README.en.md +47 -0
- package/plugins/skills/README.md +104 -0
- package/plugins/skills/benchmark-executor/README.md +93 -0
- package/plugins/skills/benchmark-executor/SKILL.md +647 -0
- package/plugins/skills/benchmark-generator/SKILL.md +349 -0
- package/plugins/skills/delivery-stage/SKILL.md +203 -0
- package/plugins/skills/design-stage/SKILL.md +216 -0
- package/plugins/skills/evolution-process/SKILL.md +291 -0
- package/plugins/skills/exploration-phase/SKILL.md +133 -0
- package/plugins/skills/implementation-stage/SKILL.md +179 -0
- package/plugins/skills/layer1-validation/SKILL.md +79 -0
- package/plugins/skills/pending-dashboard/SKILL.md +109 -0
- package/plugins/skills/project-evolution/SKILL.md +847 -0
- package/plugins/skills/requirement-stage/SKILL.md +183 -0
- package/plugins/skills/skill-forge/SKILL.md +223 -0
- package/plugins/skills/skill-forge/references/description-guide.md +92 -0
- package/plugins/skills/skill-forge/references/quality-rubric.md +104 -0
- package/plugins/skills/skill-forge/references/skill-template.md +106 -0
- package/plugins/skills/startup-guard/SKILL.md +38 -0
- package/plugins/skills/testing-stage/SKILL.md +195 -0
- package/scripts/cli/global-init.js +288 -0
- package/scripts/cli/global.js +324 -0
- package/scripts/cli/index.js +55 -0
- package/scripts/cli/init.js +382 -0
- package/scripts/cli/list.js +69 -0
- package/scripts/cli/org.js +340 -0
- package/scripts/cli/update.js +44 -0
- package/scripts/config/commands.config.js +145 -0
- package/scripts/config/hooks.config.js +197 -0
- package/scripts/evolution/evolution-router.js +273 -0
- package/scripts/evolution/evolution-signal-collector.js +307 -0
- package/scripts/evolution/knowledge-loader.js +346 -0
- package/scripts/evolution/marketplace.js +317 -0
- package/scripts/evolution/version-manager.js +371 -0
- package/scripts/install/agents.js +106 -0
- package/scripts/install/commands.js +133 -0
- package/scripts/install/constants.js +424 -0
- package/scripts/install/hook-logger.js +536 -0
- package/scripts/install/hooks.js +110 -0
- package/scripts/install/index.js +39 -0
- package/scripts/install/skills.js +95 -0
- package/scripts/postinstall.js +25 -0
- package/scripts/state.js +376 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Hooks 脚本目录
|
|
2
|
+
|
|
3
|
+
本目录包含所有 Claude Code hooks 脚本,随 init 过程复制到 `.autospec/plugins/hooks/` 目录。
|
|
4
|
+
|
|
5
|
+
## 目录结构
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
hooks/
|
|
9
|
+
├── trace-initialization.js # Trace ID 初始化
|
|
10
|
+
├── frozen-zone-guard.js # 冻结区保护
|
|
11
|
+
├── scope-sentinel.js # 范围防漂移
|
|
12
|
+
├── constitution-guard.js # 宪法门禁
|
|
13
|
+
├── layer1-validator.js # Layer 1 检查
|
|
14
|
+
├── environment-manager.js # 环境管理
|
|
15
|
+
├── ai-project-guard.js # AI 项目安全
|
|
16
|
+
├── execution-tracker.js # 执行追踪
|
|
17
|
+
├── artifact-evaluation-hook.js # 产出物评测
|
|
18
|
+
├── pipeline-observer.js # 流程观察
|
|
19
|
+
├── lib/ # 工具库
|
|
20
|
+
│ ├── source-code-scanner.js
|
|
21
|
+
│ ├── detection-pattern-loader.js
|
|
22
|
+
│ ├── validation-patterns.js
|
|
23
|
+
│ ├── hook-logger.js
|
|
24
|
+
│ ├── hook-state-manager.js
|
|
25
|
+
│ ├── trace-context.js
|
|
26
|
+
│ ├── rollback-tracker.js
|
|
27
|
+
│ ├── artifact-evaluator.js
|
|
28
|
+
│ ├── execution-path.js
|
|
29
|
+
│ └── metrics-analyzer.js
|
|
30
|
+
└── README.md # 本文件
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Hook 触发时机
|
|
34
|
+
|
|
35
|
+
| Hook | PreToolUse | PostToolUse | Stop |
|
|
36
|
+
|------|------------|-------------|------|
|
|
37
|
+
| trace-initialization | ✅ | | |
|
|
38
|
+
| frozen-zone-guard | ✅ | | |
|
|
39
|
+
| scope-sentinel | ✅ | | |
|
|
40
|
+
| constitution-guard | ✅ | | |
|
|
41
|
+
| layer1-validator | ✅ | ✅ | |
|
|
42
|
+
| environment-manager | ✅ | | ✅ |
|
|
43
|
+
| ai-project-guard | ✅ | ✅ | |
|
|
44
|
+
| execution-tracker | | ✅ | |
|
|
45
|
+
| artifact-evaluation-hook | | ✅ | |
|
|
46
|
+
| pipeline-observer | | ✅ | ✅ |
|
|
47
|
+
|
|
48
|
+
## 自闭环要求
|
|
49
|
+
|
|
50
|
+
本目录中的脚本必须自闭环,满足以下要求:
|
|
51
|
+
|
|
52
|
+
1. **只依赖 Node.js 内置模块**(fs, path 等)
|
|
53
|
+
2. **只依赖 `./lib/` 本地工具库**
|
|
54
|
+
3. **不依赖任何脚手架代码**
|
|
55
|
+
|
|
56
|
+
这样确保复制到 `.autospec/plugins/hooks/` 后可以独立运行。
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AutoSpec Hook: AI Project Guard
|
|
5
|
+
*
|
|
6
|
+
* AI 项目专项保护 Hook,合并了安全和效果验证功能:
|
|
7
|
+
* - PostToolUse: AI 安全检查(原 ai-security-guard.js)
|
|
8
|
+
* - PostToolUse: AI 效果验证(原 ai-effect-validator.js)
|
|
9
|
+
*
|
|
10
|
+
* 职责:
|
|
11
|
+
* 1. 检测 AI 项目(依赖/目录)
|
|
12
|
+
* 2. 安全检查:敏感操作、依赖安装、网络请求
|
|
13
|
+
* 3. 效果验证:测试/评估命令结果捕获
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { createHookLogger, safeJsonParse, handleHookError, readStdin, findProjectRootAsync, fileExists, globalHookCache } from './lib/hook-logger.js';
|
|
17
|
+
import {
|
|
18
|
+
checkCommandSecurity,
|
|
19
|
+
detectEvalCommands,
|
|
20
|
+
detectTestFramework,
|
|
21
|
+
extractTestMetrics,
|
|
22
|
+
extractLintMetrics,
|
|
23
|
+
extractTypeMetrics,
|
|
24
|
+
} from './lib/validation-patterns.js';
|
|
25
|
+
|
|
26
|
+
const logger = createHookLogger('ai-project-guard');
|
|
27
|
+
const projectTypeCache = globalHookCache;
|
|
28
|
+
|
|
29
|
+
// ========== AI 项目检测 ==========
|
|
30
|
+
|
|
31
|
+
const AI_PROJECT_INDICATORS = [
|
|
32
|
+
'requirements.txt', 'pyproject.toml', 'Pipfile',
|
|
33
|
+
'ml/', 'ai/', 'model/', 'rag/', 'agents/', 'prompts/',
|
|
34
|
+
'embeddings/', 'vectorstore/'
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const AI_DEPENDENCIES = [
|
|
38
|
+
'langchain', 'llamaindex', 'openai', 'anthropic',
|
|
39
|
+
'transformers', 'torch', 'tensorflow', 'huggingface',
|
|
40
|
+
'crewai', 'autogen', 'vanna'
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
const AI_DIRECTORIES = ['ml', 'ai', 'model', 'rag', 'agents', 'prompts', 'embeddings', 'vectorstore'];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 快速检测是否为 AI 项目
|
|
47
|
+
*/
|
|
48
|
+
async function detectAIProject(projectRoot) {
|
|
49
|
+
// 检查 AI 相关依赖文件
|
|
50
|
+
const aiDependencyFiles = ['requirements.txt', 'pyproject.toml', 'Pipfile', 'package.json'];
|
|
51
|
+
|
|
52
|
+
for (const file of aiDependencyFiles) {
|
|
53
|
+
const filePath = `${projectRoot}/${file}`;
|
|
54
|
+
if (await fileExists(filePath)) {
|
|
55
|
+
try {
|
|
56
|
+
const fs = await import('fs');
|
|
57
|
+
const content = await fs.promises.readFile(filePath, 'utf-8');
|
|
58
|
+
|
|
59
|
+
if (AI_DEPENDENCIES.some(ind => content.toLowerCase().includes(ind))) {
|
|
60
|
+
logger.debug('AI dependency detected', { file });
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
} catch (err) {
|
|
64
|
+
logger.debug('Failed to read dependency file', { file, error: err.message });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 检查 AI 相关目录
|
|
70
|
+
for (const dir of AI_DIRECTORIES) {
|
|
71
|
+
if (await fileExists(`${projectRoot}/${dir}`)) {
|
|
72
|
+
logger.debug('AI directory detected', { dir });
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 检查项目类型(带缓存)
|
|
82
|
+
*/
|
|
83
|
+
async function checkProjectType(projectRoot) {
|
|
84
|
+
const cacheKey = `ai-project:${projectRoot}`;
|
|
85
|
+
let isAIProject = projectTypeCache.get(cacheKey);
|
|
86
|
+
|
|
87
|
+
if (isAIProject === undefined) {
|
|
88
|
+
isAIProject = await detectAIProject(projectRoot);
|
|
89
|
+
projectTypeCache.set(cacheKey, isAIProject, 5 * 60 * 1000);
|
|
90
|
+
logger.debug('Project type detected', { isAIProject, projectRoot });
|
|
91
|
+
} else {
|
|
92
|
+
logger.debug('Using cached project type', { isAIProject });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return isAIProject;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ========== 安全检查 ==========
|
|
99
|
+
// 使用 validation-patterns.js 中的 checkCommandSecurity 函数
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 格式化安全报告
|
|
103
|
+
*/
|
|
104
|
+
function formatSecurityReport(issues, command) {
|
|
105
|
+
let report = `[AutoSpec AI-Security] 检测到 ${issues.length} 个安全问题\n`;
|
|
106
|
+
report += `命令:${command.slice(0, 80)}${command.length > 80 ? '...' : ''}\n\n`;
|
|
107
|
+
|
|
108
|
+
const bySeverity = { HIGH: [], MEDIUM: [], LOW: [] };
|
|
109
|
+
for (const issue of issues) {
|
|
110
|
+
bySeverity[issue.severity].push(issue);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
for (const severity of ['HIGH', 'MEDIUM', 'LOW']) {
|
|
114
|
+
if (bySeverity[severity].length > 0) {
|
|
115
|
+
const icons = { HIGH: '🚨', MEDIUM: '⚠️', LOW: 'ℹ️' };
|
|
116
|
+
report += `${icons[severity]} **${severity}** (${bySeverity[severity].length}个):\n`;
|
|
117
|
+
for (const issue of bySeverity[severity]) {
|
|
118
|
+
report += ` • ${issue.message}\n`;
|
|
119
|
+
report += ` 建议:${issue.recommendation}\n`;
|
|
120
|
+
}
|
|
121
|
+
report += '\n';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return report;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 处理安全检查
|
|
130
|
+
*/
|
|
131
|
+
async function handleSecurityCheck(input, projectRoot) {
|
|
132
|
+
const command = input.tool_input?.command || '';
|
|
133
|
+
if (!command) {
|
|
134
|
+
logger.debug('Empty command, skipping');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
logger.debug('Checking AI project command', { command: command.slice(0, 100) });
|
|
139
|
+
|
|
140
|
+
const securityIssues = checkCommandSecurity(command, projectRoot);
|
|
141
|
+
|
|
142
|
+
if (securityIssues.length === 0) {
|
|
143
|
+
logger.debug('No security issues detected');
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
logger.info('Security issues detected', { count: securityIssues.length });
|
|
148
|
+
|
|
149
|
+
const output = {
|
|
150
|
+
hookSpecificOutput: {
|
|
151
|
+
hookEventName: 'PostToolUse',
|
|
152
|
+
additionalContext: formatSecurityReport(securityIssues, command)
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
process.stdout.write(JSON.stringify(output));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ========== 效果验证 ==========
|
|
160
|
+
// 使用 validation-patterns.js 中的检测函数
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 收集评估结果 - 使用公共模块的指标提取函数
|
|
164
|
+
*/
|
|
165
|
+
function collectEvalResults(evalCommands, response) {
|
|
166
|
+
const results = [];
|
|
167
|
+
const exitCode = response.exitCode ?? (response.error ? 1 : 0);
|
|
168
|
+
const stdout = response.stdout || '';
|
|
169
|
+
const stderr = response.stderr || '';
|
|
170
|
+
|
|
171
|
+
for (const cmd of evalCommands) {
|
|
172
|
+
const result = {
|
|
173
|
+
type: cmd.type,
|
|
174
|
+
framework: cmd.framework,
|
|
175
|
+
pass: exitCode === 0,
|
|
176
|
+
exitCode: exitCode,
|
|
177
|
+
details: extractDetails(stdout, stderr)
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
if (cmd.type === 'test') {
|
|
181
|
+
result.metrics = extractTestMetrics(stdout, stderr);
|
|
182
|
+
} else if (cmd.type === 'lint') {
|
|
183
|
+
result.metrics = extractLintMetrics(stdout, stderr);
|
|
184
|
+
} else if (cmd.type === 'type_check') {
|
|
185
|
+
result.metrics = extractTypeMetrics(stdout, stderr);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
results.push(result);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return results;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 提取详细信息
|
|
196
|
+
*/
|
|
197
|
+
function extractDetails(stdout, stderr) {
|
|
198
|
+
const output = (stdout || '') + (stderr || '');
|
|
199
|
+
const lines = output.split('\n').filter(l => l.trim());
|
|
200
|
+
return lines.slice(-5).join('\n');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* 格式化评估报告
|
|
205
|
+
*/
|
|
206
|
+
function formatEvalReport(results) {
|
|
207
|
+
let report = '[AutoSpec AI-Effect] AI 效果验证\n';
|
|
208
|
+
report += `检测到 ${results.length} 个评估命令\n\n`;
|
|
209
|
+
|
|
210
|
+
let allPass = true;
|
|
211
|
+
for (const result of results) {
|
|
212
|
+
const status = result.pass ? '✅ PASS' : '❌ FAIL';
|
|
213
|
+
report += `### ${result.type.toUpperCase()}: ${status}\n`;
|
|
214
|
+
report += `Exit Code: ${result.exitCode}\n`;
|
|
215
|
+
|
|
216
|
+
if (result.framework) {
|
|
217
|
+
report += `Framework: ${result.framework}\n`;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (result.metrics && Object.keys(result.metrics).length > 0) {
|
|
221
|
+
report += '指标:\n';
|
|
222
|
+
for (const [key, value] of Object.entries(result.metrics)) {
|
|
223
|
+
report += ` - ${key}: ${value}\n`;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (!result.pass && result.details) {
|
|
228
|
+
report += '失败详情:\n```\n';
|
|
229
|
+
report += result.details.substring(0, 500) + '\n```\n';
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
report += '\n';
|
|
233
|
+
|
|
234
|
+
if (!result.pass) allPass = false;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (allPass && results.length > 0) {
|
|
238
|
+
report += '✅ 所有效果验证通过\n';
|
|
239
|
+
report += '可进入下一阶段或进行 Layer 2 审查\n';
|
|
240
|
+
} else if (results.length > 0) {
|
|
241
|
+
report += '❌ 效果验证未通过\n';
|
|
242
|
+
report += '[CP6] 错误即信号 - 请分析失败原因后再重试\n';
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return report;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* 处理效果验证
|
|
250
|
+
*/
|
|
251
|
+
async function handleEffectValidation(input, projectRoot) {
|
|
252
|
+
const command = input.tool_input?.command || '';
|
|
253
|
+
const response = input.tool_response || {};
|
|
254
|
+
|
|
255
|
+
const evalCommands = detectEvalCommands(command);
|
|
256
|
+
|
|
257
|
+
if (evalCommands.length === 0) {
|
|
258
|
+
logger.debug('No evaluation commands detected, skipping');
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
logger.debug('Evaluation commands detected', { count: evalCommands.length });
|
|
263
|
+
|
|
264
|
+
const evalResults = collectEvalResults(evalCommands, response);
|
|
265
|
+
|
|
266
|
+
const output = {
|
|
267
|
+
hookSpecificOutput: {
|
|
268
|
+
hookEventName: 'PostToolUse',
|
|
269
|
+
additionalContext: formatEvalReport(evalResults)
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
process.stdout.write(JSON.stringify(output));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* 主函数
|
|
278
|
+
*/
|
|
279
|
+
async function main() {
|
|
280
|
+
let input;
|
|
281
|
+
try {
|
|
282
|
+
const rawInput = await readStdin(1000);
|
|
283
|
+
input = safeJsonParse(rawInput, null, 'hook input');
|
|
284
|
+
|
|
285
|
+
if (!input) {
|
|
286
|
+
logger.debug('Empty or invalid input, skipping');
|
|
287
|
+
process.exit(0);
|
|
288
|
+
}
|
|
289
|
+
} catch (err) {
|
|
290
|
+
logger.error('Failed to parse input', { error: err.message });
|
|
291
|
+
process.exit(0);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// 只处理 Bash 命令
|
|
295
|
+
if (input.tool_name !== 'Bash') {
|
|
296
|
+
logger.debug('Not a Bash command, skipping', { toolName: input.tool_name });
|
|
297
|
+
process.exit(0);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Find project root
|
|
301
|
+
const cwd = input.cwd || process.cwd();
|
|
302
|
+
const projectRoot = await findProjectRootAsync(cwd);
|
|
303
|
+
|
|
304
|
+
if (!projectRoot) {
|
|
305
|
+
logger.debug('No project root found, skipping');
|
|
306
|
+
process.exit(0);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// 检查是否为 AI 项目
|
|
310
|
+
const isAIProject = await checkProjectType(projectRoot);
|
|
311
|
+
if (!isAIProject) {
|
|
312
|
+
logger.debug('Not an AI project, skipping');
|
|
313
|
+
process.exit(0);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// 执行安全检查和效果验证
|
|
317
|
+
await handleSecurityCheck(input, projectRoot);
|
|
318
|
+
await handleEffectValidation(input, projectRoot);
|
|
319
|
+
|
|
320
|
+
process.exit(0);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
main().catch((err) => {
|
|
324
|
+
const result = handleHookError('ai-project-guard', err, {
|
|
325
|
+
eventName: 'PostToolUse'
|
|
326
|
+
});
|
|
327
|
+
process.stdout.write(JSON.stringify(result.hookSpecificOutput));
|
|
328
|
+
process.exit(0);
|
|
329
|
+
});
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AutoSpec PostToolUse Hook: Artifact Evaluator
|
|
5
|
+
*
|
|
6
|
+
* 产出物评测 Hook
|
|
7
|
+
* - 触发时机:关键产出物生成后
|
|
8
|
+
* - 执行策略:
|
|
9
|
+
* - 结构检查:100% 执行
|
|
10
|
+
* - 一致性检测:100% 执行
|
|
11
|
+
* - AI 质量评估:采样执行(首次必评,后续 30% 采样)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { createHookLogger, safeJsonParse, handleHookError, readStdin, findProjectRootAsync } from './lib/hook-logger.js';
|
|
15
|
+
import {
|
|
16
|
+
isKeyArtifact,
|
|
17
|
+
detectArtifactType,
|
|
18
|
+
checkStructure,
|
|
19
|
+
recordArtifactEval,
|
|
20
|
+
calculateArtifactScore,
|
|
21
|
+
updateArtifactSummary,
|
|
22
|
+
shouldRunQualityEval
|
|
23
|
+
} from './lib/artifact-evaluator.js';
|
|
24
|
+
import { getTraceId, recordEvent } from './lib/trace-context.js';
|
|
25
|
+
import { getState, getMetrics, updateMetrics } from './lib/hook-state-manager.js';
|
|
26
|
+
|
|
27
|
+
const logger = createHookLogger('artifact-evaluation-hook');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 执行产出物评测
|
|
31
|
+
* @param {string} projectRoot - 项目根目录
|
|
32
|
+
* @param {string} artifactPath - 产出物路径
|
|
33
|
+
* @param {string} artifactType - 产出物类型
|
|
34
|
+
*/
|
|
35
|
+
async function evaluateArtifact(projectRoot, artifactPath, artifactType) {
|
|
36
|
+
const evaluations = {};
|
|
37
|
+
|
|
38
|
+
// 1. 结构完整性检查(100% 执行)
|
|
39
|
+
logger.info('执行结构完整性检查', { artifactPath, artifactType });
|
|
40
|
+
const structureResult = checkStructure(artifactPath, artifactType);
|
|
41
|
+
evaluations.structure = structureResult;
|
|
42
|
+
|
|
43
|
+
// 2. 一致性检测(如果有上游产物)
|
|
44
|
+
// 注:一致性检测需要多个产物,这里只标记需要检测
|
|
45
|
+
// 实际的一致性检测由 consistency-checker skill 执行
|
|
46
|
+
if (artifactType !== 'REQUIREMENT') {
|
|
47
|
+
evaluations.consistency = {
|
|
48
|
+
score: null,
|
|
49
|
+
status: 'pending',
|
|
50
|
+
message: '等待一致性检测'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 3. AI 质量评估(采样执行)
|
|
55
|
+
const qualityDecision = shouldRunQualityEval(projectRoot, artifactType);
|
|
56
|
+
if (qualityDecision.shouldEval) {
|
|
57
|
+
logger.info('触发 AI 质量评估', { reason: qualityDecision.reason });
|
|
58
|
+
evaluations.quality = {
|
|
59
|
+
score: null,
|
|
60
|
+
status: 'pending',
|
|
61
|
+
message: '等待 AI 评估',
|
|
62
|
+
triggerReason: qualityDecision.reason
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// 输出提示,让主流程知道需要执行 AI 评估
|
|
66
|
+
outputQualityEvalPrompt(artifactPath, artifactType);
|
|
67
|
+
} else {
|
|
68
|
+
logger.debug('跳过 AI 质量评估', { reason: qualityDecision.reason });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 4. 下游反馈(标记为待评估)
|
|
72
|
+
evaluations.feedback = {
|
|
73
|
+
score: null,
|
|
74
|
+
status: 'pending',
|
|
75
|
+
message: '等待下游阶段反馈'
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// 记录评测结果
|
|
79
|
+
recordArtifactEval(projectRoot, artifactPath, artifactType, evaluations);
|
|
80
|
+
|
|
81
|
+
// 计算当前可用评分
|
|
82
|
+
const currentScore = calculateArtifactScore(evaluations, artifactType);
|
|
83
|
+
|
|
84
|
+
// 更新产出物质量汇总
|
|
85
|
+
updateArtifactSummary(projectRoot);
|
|
86
|
+
|
|
87
|
+
// 低分告警
|
|
88
|
+
if (structureResult.score < 60) {
|
|
89
|
+
outputLowScoreWarning(artifactPath, structureResult.score, 'structure');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
evaluations,
|
|
94
|
+
currentScore
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 输出 AI 质量评估提示
|
|
100
|
+
*/
|
|
101
|
+
function outputQualityEvalPrompt(artifactPath, artifactType) {
|
|
102
|
+
const prompt = `
|
|
103
|
+
[AutoSpec] 产出物质量评估触发
|
|
104
|
+
|
|
105
|
+
产出物: ${artifactPath}
|
|
106
|
+
类型: ${artifactType}
|
|
107
|
+
|
|
108
|
+
建议执行 AI 质量评估:
|
|
109
|
+
1. 读取 framework/skills/support/ai-artifact-evaluator.md
|
|
110
|
+
2. 使用 Agent 工具执行评估
|
|
111
|
+
3. 将结果记录到 metrics.json
|
|
112
|
+
|
|
113
|
+
评估维度:
|
|
114
|
+
- 内容质量评分
|
|
115
|
+
- 与历史优秀案例对比
|
|
116
|
+
- 改进建议
|
|
117
|
+
`;
|
|
118
|
+
|
|
119
|
+
process.stdout.write(JSON.stringify({
|
|
120
|
+
hookSpecificOutput: {
|
|
121
|
+
hookEventName: 'PostToolUse',
|
|
122
|
+
additionalContext: prompt
|
|
123
|
+
}
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 输出低分告警
|
|
129
|
+
*/
|
|
130
|
+
function outputLowScoreWarning(artifactPath, score, evalType) {
|
|
131
|
+
const isSevere = score < 40;
|
|
132
|
+
const level = isSevere ? '🚨 严重' : '⚠️ 警告';
|
|
133
|
+
|
|
134
|
+
const warning = `
|
|
135
|
+
[AutoSpec ${level}] 产出物质量评分较低
|
|
136
|
+
|
|
137
|
+
产出物: ${artifactPath}
|
|
138
|
+
评测类型: ${evalType}
|
|
139
|
+
评分: ${score}/100
|
|
140
|
+
|
|
141
|
+
${isSevere ? `
|
|
142
|
+
**建议暂停当前流程**,产出物结构严重不完整:
|
|
143
|
+
- 检查产出物是否符合模板要求
|
|
144
|
+
- 确保必要章节完整
|
|
145
|
+
- 建议重新生成后再继续下一阶段
|
|
146
|
+
|
|
147
|
+
执行 /autospec:evaluate 获取详细评测报告。
|
|
148
|
+
` : `
|
|
149
|
+
建议:
|
|
150
|
+
- 检查产出物是否符合模板要求
|
|
151
|
+
- 确保必要章节完整
|
|
152
|
+
- 考虑重新生成或人工审查
|
|
153
|
+
`}
|
|
154
|
+
`;
|
|
155
|
+
|
|
156
|
+
process.stdout.write(JSON.stringify({
|
|
157
|
+
hookSpecificOutput: {
|
|
158
|
+
hookEventName: 'PostToolUse',
|
|
159
|
+
additionalContext: warning
|
|
160
|
+
}
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function main() {
|
|
165
|
+
let input;
|
|
166
|
+
try {
|
|
167
|
+
const rawInput = await readStdin(1000);
|
|
168
|
+
input = safeJsonParse(rawInput, null, 'hook input');
|
|
169
|
+
|
|
170
|
+
if (!input) {
|
|
171
|
+
logger.debug('Empty or invalid input, skipping');
|
|
172
|
+
process.exit(0);
|
|
173
|
+
}
|
|
174
|
+
} catch (err) {
|
|
175
|
+
logger.error('Failed to parse input', { error: err.message });
|
|
176
|
+
process.exit(0);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const toolName = input.tool_name;
|
|
180
|
+
|
|
181
|
+
// 只处理 Write 操作
|
|
182
|
+
if (toolName !== 'Write') {
|
|
183
|
+
process.exit(0);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const filePath = input.tool_input?.file_path || '';
|
|
187
|
+
|
|
188
|
+
// 检查是否为关键产出物
|
|
189
|
+
if (!isKeyArtifact(filePath)) {
|
|
190
|
+
logger.debug('Not a key artifact, skipping', { filePath });
|
|
191
|
+
process.exit(0);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const cwd = input.cwd || process.cwd();
|
|
195
|
+
const projectRoot = await findProjectRootAsync(cwd);
|
|
196
|
+
|
|
197
|
+
if (!projectRoot) {
|
|
198
|
+
logger.debug('No .autospec directory found, skipping');
|
|
199
|
+
process.exit(0);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// 检测产出物类型
|
|
203
|
+
const artifactType = detectArtifactType(filePath);
|
|
204
|
+
if (!artifactType) {
|
|
205
|
+
logger.debug('Unknown artifact type, skipping', { filePath });
|
|
206
|
+
process.exit(0);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
logger.info('Detected key artifact for evaluation', { filePath, artifactType });
|
|
210
|
+
|
|
211
|
+
// 执行评测
|
|
212
|
+
await evaluateArtifact(projectRoot, filePath, artifactType);
|
|
213
|
+
|
|
214
|
+
// 记录事件到 trace 日志
|
|
215
|
+
const traceId = getTraceId(projectRoot);
|
|
216
|
+
if (traceId) {
|
|
217
|
+
recordEvent(projectRoot, 'artifact_created', {
|
|
218
|
+
source: 'artifact-evaluation-hook',
|
|
219
|
+
tool: 'Write',
|
|
220
|
+
action: 'create_artifact',
|
|
221
|
+
data: {
|
|
222
|
+
artifactPath: filePath,
|
|
223
|
+
artifactType
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
process.exit(0);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
main().catch((err) => {
|
|
232
|
+
const result = handleHookError('artifact-evaluation-hook', err, {
|
|
233
|
+
eventName: 'PostToolUse'
|
|
234
|
+
});
|
|
235
|
+
process.stdout.write(JSON.stringify(result.hookSpecificOutput));
|
|
236
|
+
process.exit(0);
|
|
237
|
+
});
|