@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,423 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AutoSpec Hook: Layer 1 Validator
|
|
5
|
+
*
|
|
6
|
+
* 统一的 Layer 1 验证管理 Hook,合并了三个相关功能:
|
|
7
|
+
* - PreToolUse: Layer 1 强制检查(原 layer1-mandatory.js)
|
|
8
|
+
* - PostToolUse: Layer 1 结果捕获(原 layer1-post-check.js)
|
|
9
|
+
* - PostToolUse: 质量指标追踪(原 pipeline-quality-tracker.js)
|
|
10
|
+
*
|
|
11
|
+
* 职责:
|
|
12
|
+
* 1. 阻止未执行 Layer 1 验证就标记阶段完成
|
|
13
|
+
* 2. 捕获 Layer 1 验证命令的执行结果
|
|
14
|
+
* 3. 追踪质量指标到 metrics.json
|
|
15
|
+
*
|
|
16
|
+
* Security Level: CRITICAL - fail-closed
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { createHookLogger, safeJsonParse, handleHookError, readStdin, findProjectRootAsync, fileExists } from './lib/hook-logger.js';
|
|
20
|
+
import { recordHookExecution } from './lib/hook-error-recorder.js';
|
|
21
|
+
import {
|
|
22
|
+
detectValidationType,
|
|
23
|
+
isLayer1Validation,
|
|
24
|
+
extractTestMetrics,
|
|
25
|
+
} from './lib/validation-patterns.js';
|
|
26
|
+
import {
|
|
27
|
+
getState,
|
|
28
|
+
readStateField,
|
|
29
|
+
hasLayer1Execution,
|
|
30
|
+
getMetrics,
|
|
31
|
+
updateMetrics,
|
|
32
|
+
updateStageMetrics,
|
|
33
|
+
incrementTotalMetric,
|
|
34
|
+
incrementStageMetric,
|
|
35
|
+
addErrorEntry,
|
|
36
|
+
} from './lib/hook-state-manager.js';
|
|
37
|
+
import { getTraceId, recordEvent } from './lib/trace-context.js';
|
|
38
|
+
import { analyzeFailures, requiresHumanConfirmation } from './lib/test-failure-analyzer.js';
|
|
39
|
+
|
|
40
|
+
const logger = createHookLogger('layer1-validator');
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 分析测试失败
|
|
44
|
+
*/
|
|
45
|
+
async function analyzeTestFailure(testOutput, command) {
|
|
46
|
+
try {
|
|
47
|
+
// 构建测试结果对象
|
|
48
|
+
const testResult = {
|
|
49
|
+
success: false,
|
|
50
|
+
output: testOutput || '',
|
|
51
|
+
command: command
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// 调用本地 analyzer 分析失败原因
|
|
55
|
+
const analysis = analyzeFailures(testResult);
|
|
56
|
+
return analysis;
|
|
57
|
+
} catch (e) {
|
|
58
|
+
logger.debug('Test analysis failed', { error: e.message });
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* PreToolUse 处理:Layer 1 强制检查
|
|
65
|
+
* 阻止未执行 Layer 1 验证就标记阶段完成
|
|
66
|
+
*/
|
|
67
|
+
async function handlePreToolUse(input, projectRoot) {
|
|
68
|
+
const toolName = input.tool_name;
|
|
69
|
+
if (toolName !== 'Write' && toolName !== 'Edit') {
|
|
70
|
+
logger.debug('Not a write/edit operation, skipping', { toolName });
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check if this is an attempt to update state.json
|
|
75
|
+
const filePath = (input.tool_input?.file_path || '').replace(/\\/g, '/');
|
|
76
|
+
if (!filePath.includes('state.json') && !filePath.includes('.autospec/state')) {
|
|
77
|
+
logger.debug('Not a state.json operation, skipping', { filePath });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
logger.debug('Intercepting state.json modification');
|
|
82
|
+
|
|
83
|
+
// Check if state exists
|
|
84
|
+
const currentState = getState(projectRoot, true);
|
|
85
|
+
if (!currentState) {
|
|
86
|
+
logger.debug('state.json does not exist yet, allowing');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Get new content (if Edit, get replacement text; if Write, get content)
|
|
91
|
+
let newContent = '';
|
|
92
|
+
if (toolName === 'Write') {
|
|
93
|
+
newContent = input.tool_input?.content || '';
|
|
94
|
+
} else if (toolName === 'Edit') {
|
|
95
|
+
newContent = input.tool_input?.new_string || '';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Check if we're marking a stage as complete
|
|
99
|
+
const isMarkingComplete = newContent.includes('completed') ||
|
|
100
|
+
newContent.includes('"status": "completed"');
|
|
101
|
+
|
|
102
|
+
if (!isMarkingComplete) {
|
|
103
|
+
logger.debug('Not a completion update, allowing');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
logger.info('Detected stage completion attempt');
|
|
108
|
+
|
|
109
|
+
// Check what stage is being marked complete
|
|
110
|
+
const stageMatch = newContent.match(/stage0?(\d)/i) ||
|
|
111
|
+
newContent.match(/"stage": "?(\d+)"?/);
|
|
112
|
+
const stageNum = stageMatch ? stageMatch[1] : null;
|
|
113
|
+
|
|
114
|
+
logger.debug('Checking stage', { stageNum });
|
|
115
|
+
|
|
116
|
+
// Stage 1 (requirement) doesn't always need Layer 1 (it's analysis, not code)
|
|
117
|
+
// But stages 3+ (implementation, review, testing) definitely need Layer 1
|
|
118
|
+
if (stageNum && parseInt(stageNum) >= 3) {
|
|
119
|
+
const currentStageKey = 'stage' + (parseInt(stageNum) < 10 ? '0' : '') + stageNum;
|
|
120
|
+
|
|
121
|
+
// 使用 state-utils 检查 Layer 1 执行记录
|
|
122
|
+
const hasLayer1 = hasLayer1Execution(projectRoot, currentStageKey);
|
|
123
|
+
|
|
124
|
+
logger.debug('Layer 1 check', { stage: currentStageKey, hasLayer1 });
|
|
125
|
+
|
|
126
|
+
if (!hasLayer1) {
|
|
127
|
+
logger.info('BLOCKED: No Layer 1 execution for stage completion', { stage: stageNum });
|
|
128
|
+
|
|
129
|
+
const output = {
|
|
130
|
+
hookSpecificOutput: {
|
|
131
|
+
hookEventName: 'PreToolUse',
|
|
132
|
+
permissionDecision: 'deny',
|
|
133
|
+
permissionDecisionReason:
|
|
134
|
+
`[AutoSpec Layer 1 Validator] ❌ BLOCKED - DP6 Violation\n` +
|
|
135
|
+
`Attempting to mark Stage ${stageNum} as completed without Layer 1 validation.\n\n` +
|
|
136
|
+
`Constitution DP6 requires: "Layer 1 must be real execution"\n` +
|
|
137
|
+
`Required steps before completion:\n` +
|
|
138
|
+
` - /autospec:validate (runs build, test, lint)\n` +
|
|
139
|
+
` - Or: Bash commands for build/test with real execution\n\n` +
|
|
140
|
+
`Layer 1 results not found in state.json for this stage.\n` +
|
|
141
|
+
`Run validation first, then mark complete.`
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
process.stdout.write(JSON.stringify(output));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
logger.debug('Allowing state update');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* PostToolUse 处理:Layer 1 结果捕获 + 质量指标追踪
|
|
153
|
+
* 使用 state-utils.js 进行状态管理
|
|
154
|
+
*/
|
|
155
|
+
async function handlePostToolUse(input, projectRoot) {
|
|
156
|
+
const toolName = input.tool_name;
|
|
157
|
+
const toolInput = input.tool_input || {};
|
|
158
|
+
const response = input.tool_response || {};
|
|
159
|
+
|
|
160
|
+
logger.debug('Tracking Layer 1 metrics');
|
|
161
|
+
|
|
162
|
+
// Only track when a pipeline is active
|
|
163
|
+
const currentState = getState(projectRoot, true);
|
|
164
|
+
if (!currentState) {
|
|
165
|
+
logger.debug('No active pipeline (state.json not found), skipping');
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Load current stage
|
|
170
|
+
const currentStage = String(currentState.currentStage || '');
|
|
171
|
+
|
|
172
|
+
let updated = false;
|
|
173
|
+
let contextMessage = '';
|
|
174
|
+
|
|
175
|
+
// ========== Layer 1 验证命令检测(Bash 命令)==========
|
|
176
|
+
if (toolName === 'Bash') {
|
|
177
|
+
const command = toolInput.command || '';
|
|
178
|
+
const validationType = detectValidationType(command);
|
|
179
|
+
|
|
180
|
+
if (validationType) {
|
|
181
|
+
const exitCode = response.exitCode ?? (response.error ? 1 : 0);
|
|
182
|
+
const passed = exitCode === 0;
|
|
183
|
+
|
|
184
|
+
// 检查是否为该阶段的首次 Layer 1 尝试
|
|
185
|
+
const metrics = getMetrics(projectRoot, true);
|
|
186
|
+
const stageMetrics = metrics?.stages?.[currentStage] || {};
|
|
187
|
+
const isFirstAttempt = !stageMetrics.layer1FirstAttempts || stageMetrics.layer1FirstAttempts === 0;
|
|
188
|
+
|
|
189
|
+
// 记录首次尝试
|
|
190
|
+
if (isFirstAttempt) {
|
|
191
|
+
incrementStageMetric(projectRoot, currentStage, 'layer1FirstAttempts');
|
|
192
|
+
incrementTotalMetric(projectRoot, 'layer1FirstAttempts');
|
|
193
|
+
logger.debug('First Layer 1 attempt for stage', { stage: currentStage });
|
|
194
|
+
|
|
195
|
+
// 如果首次通过,记录
|
|
196
|
+
if (passed) {
|
|
197
|
+
incrementStageMetric(projectRoot, currentStage, 'layer1FirstPass');
|
|
198
|
+
incrementTotalMetric(projectRoot, 'layer1FirstPass');
|
|
199
|
+
logger.info('First attempt Layer 1 PASS', { stage: currentStage });
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// 更新指标 - 使用 state-utils
|
|
204
|
+
if (passed) {
|
|
205
|
+
incrementTotalMetric(projectRoot, 'layer1Pass');
|
|
206
|
+
if (currentStage) incrementStageMetric(projectRoot, currentStage, 'layer1Pass');
|
|
207
|
+
logger.debug('Layer 1 validation passed', { stage: currentStage });
|
|
208
|
+
} else {
|
|
209
|
+
incrementTotalMetric(projectRoot, 'layer1Fail');
|
|
210
|
+
if (currentStage) incrementStageMetric(projectRoot, currentStage, 'layer1Fail');
|
|
211
|
+
|
|
212
|
+
// 添加错误记录
|
|
213
|
+
addErrorEntry(projectRoot, {
|
|
214
|
+
type: 'layer1_fail',
|
|
215
|
+
command: command.substring(0, 100),
|
|
216
|
+
stage: currentStage
|
|
217
|
+
}, currentStage);
|
|
218
|
+
|
|
219
|
+
logger.info('Layer 1 validation failed', { stage: currentStage, exitCode });
|
|
220
|
+
|
|
221
|
+
// 使用 test 模块分析测试失败原因
|
|
222
|
+
if (validationType === 'test') {
|
|
223
|
+
const testOutput = response.stdout || response.stderr || '';
|
|
224
|
+
const analysis = await analyzeTestFailure(testOutput, command);
|
|
225
|
+
|
|
226
|
+
if (analysis && analysis.errors && analysis.errors.length > 0) {
|
|
227
|
+
// 构建详细的错误分析消息
|
|
228
|
+
let analysisDetails = `\n\n[Test Module Analysis]\n`;
|
|
229
|
+
analysisDetails += `Error Type: ${analysis.errorType || 'unknown'}\n`;
|
|
230
|
+
analysisDetails += `Severity: ${analysis.severity || 'medium'}\n`;
|
|
231
|
+
|
|
232
|
+
if (analysis.errors && analysis.errors.length > 0) {
|
|
233
|
+
analysisDetails += `\nDetected Errors:\n`;
|
|
234
|
+
for (const err of analysis.errors.slice(0, 5)) {
|
|
235
|
+
analysisDetails += ` - [${err.type}] ${err.message}\n`;
|
|
236
|
+
if (err.file) analysisDetails += ` File: ${err.file}\n`;
|
|
237
|
+
if (err.line) analysisDetails += ` Line: ${err.line}\n`;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (analysis.suggestions && analysis.suggestions.length > 0) {
|
|
242
|
+
analysisDetails += `\nSuggested Fixes:\n`;
|
|
243
|
+
for (const suggestion of analysis.suggestions.slice(0, 3)) {
|
|
244
|
+
analysisDetails += ` - ${suggestion}\n`;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// 检查是否需要人工确认
|
|
249
|
+
const needsHuman = analysis.requiresHumanConfirmation || false;
|
|
250
|
+
if (needsHuman) {
|
|
251
|
+
analysisDetails += `\n⚠️ Human confirmation recommended for this failure.`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// 提示 AI 可以调用深度分析 skill
|
|
255
|
+
analysisDetails += `\n\n[AI Analysis Available]
|
|
256
|
+
For comprehensive test diagnostics and quality assessment:
|
|
257
|
+
- Read framework/skills/support/ai-test-diagnostics.md
|
|
258
|
+
- Then use Agent tool with the test output for detailed diagnosis and improvement suggestions`;
|
|
259
|
+
|
|
260
|
+
contextMessage = analysisDetails;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Alert on consecutive failures
|
|
265
|
+
const metrics = getMetrics(projectRoot, true);
|
|
266
|
+
const recentErrors = metrics?.totals?.errors?.filter(e => e.type === 'layer1_fail') || [];
|
|
267
|
+
if (recentErrors.length >= 3) {
|
|
268
|
+
contextMessage = (contextMessage ? contextMessage + '\n\n' : '') +
|
|
269
|
+
`[AutoSpec Quality Alert] Layer 1 has failed ${recentErrors.length} times in this pipeline.\n` +
|
|
270
|
+
`Consider: Is this a systemic issue? Check design assumptions or environment setup.`;
|
|
271
|
+
logger.info('Consecutive failures alert triggered', { count: recentErrors.length });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// 生成上下文消息(原 layer1-post-check 功能)
|
|
276
|
+
const status = passed ? 'PASS' : 'FAIL';
|
|
277
|
+
let validationMessage =
|
|
278
|
+
`[AutoSpec Layer 1] Validation command detected: ${command.substring(0, 80)}\n` +
|
|
279
|
+
`Type: ${validationType} | Result: ${status}\n`;
|
|
280
|
+
|
|
281
|
+
if (passed) {
|
|
282
|
+
validationMessage += `Layer 1 PASS — proceed to Layer 2 review if applicable.`;
|
|
283
|
+
} else {
|
|
284
|
+
validationMessage +=
|
|
285
|
+
`Layer 1 FAIL — DO NOT proceed to Layer 2 review.\n` +
|
|
286
|
+
`[CP6 Error Analysis Required] Before retrying, analyze the root cause:\n` +
|
|
287
|
+
` 1. Is this a code bug? → Fix the specific issue\n` +
|
|
288
|
+
` 2. Is this a design gap? → Flag for design-stage rollback\n` +
|
|
289
|
+
` 3. Is this an environment issue? → Mark as BLOCKED\n` +
|
|
290
|
+
`Record this failure in the stage results for practice-log (error pattern tracking).`;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
contextMessage = contextMessage ? contextMessage + '\n\n' + validationMessage : validationMessage;
|
|
294
|
+
updated = true;
|
|
295
|
+
|
|
296
|
+
// 记录事件到 trace 日志
|
|
297
|
+
const traceId = getTraceId(projectRoot);
|
|
298
|
+
if (traceId) {
|
|
299
|
+
recordEvent(projectRoot, passed ? 'layer1_pass' : 'layer1_fail', {
|
|
300
|
+
source: 'layer1-validator',
|
|
301
|
+
stage: currentStage,
|
|
302
|
+
tool: 'Bash',
|
|
303
|
+
action: 'validation',
|
|
304
|
+
data: {
|
|
305
|
+
command: command.substring(0, 100),
|
|
306
|
+
validationType,
|
|
307
|
+
exitCode,
|
|
308
|
+
isFirstAttempt,
|
|
309
|
+
firstPass: isFirstAttempt && passed
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ========== Agent 调用追踪 ==========
|
|
317
|
+
if (toolName === 'Agent') {
|
|
318
|
+
incrementTotalMetric(projectRoot, 'agentCalls');
|
|
319
|
+
if (currentStage) incrementStageMetric(projectRoot, currentStage, 'agentCalls');
|
|
320
|
+
|
|
321
|
+
const agentResult = response.error ? 'fail' : 'success';
|
|
322
|
+
if (agentResult === 'success') {
|
|
323
|
+
incrementTotalMetric(projectRoot, 'agentSuccess');
|
|
324
|
+
if (currentStage) incrementStageMetric(projectRoot, currentStage, 'agentSuccess');
|
|
325
|
+
} else {
|
|
326
|
+
incrementTotalMetric(projectRoot, 'agentFail');
|
|
327
|
+
if (currentStage) incrementStageMetric(projectRoot, currentStage, 'agentFail');
|
|
328
|
+
}
|
|
329
|
+
logger.debug('Agent call tracked', { result: agentResult, stage: currentStage });
|
|
330
|
+
updated = true;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ========== 用户干预追踪 ==========
|
|
334
|
+
if (toolName === 'AskUserQuestion') {
|
|
335
|
+
incrementTotalMetric(projectRoot, 'humanInterventions');
|
|
336
|
+
logger.debug('Human intervention tracked');
|
|
337
|
+
updated = true;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Metrics are automatically saved by state-utils functions
|
|
341
|
+
if (updated) {
|
|
342
|
+
logger.debug('Metrics updated via state-utils');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Output context message if any alert was triggered
|
|
346
|
+
if (contextMessage) {
|
|
347
|
+
const output = {
|
|
348
|
+
hookSpecificOutput: {
|
|
349
|
+
hookEventName: 'PostToolUse',
|
|
350
|
+
additionalContext: contextMessage
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
process.stdout.write(JSON.stringify(output));
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* 主函数
|
|
359
|
+
*/
|
|
360
|
+
async function main() {
|
|
361
|
+
const startTime = Date.now();
|
|
362
|
+
let input;
|
|
363
|
+
let projectRoot = null;
|
|
364
|
+
|
|
365
|
+
try {
|
|
366
|
+
const rawInput = await readStdin(1000);
|
|
367
|
+
input = safeJsonParse(rawInput, null, 'hook input');
|
|
368
|
+
|
|
369
|
+
if (!input) {
|
|
370
|
+
logger.debug('Empty or invalid input, skipping');
|
|
371
|
+
process.exit(0);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Find project root
|
|
375
|
+
const cwd = input.cwd || process.cwd();
|
|
376
|
+
projectRoot = await findProjectRootAsync(cwd);
|
|
377
|
+
|
|
378
|
+
if (!projectRoot) {
|
|
379
|
+
logger.debug('No .autospec directory found, skipping');
|
|
380
|
+
process.exit(0);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// 根据事件类型分发到不同处理函数
|
|
384
|
+
const eventName = input.event_name;
|
|
385
|
+
|
|
386
|
+
if (eventName === 'PreToolUse') {
|
|
387
|
+
await handlePreToolUse(input, projectRoot);
|
|
388
|
+
} else if (eventName === 'PostToolUse') {
|
|
389
|
+
await handlePostToolUse(input, projectRoot);
|
|
390
|
+
} else {
|
|
391
|
+
logger.debug('Unknown event type, skipping', { eventName });
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// 记录成功执行
|
|
395
|
+
recordHookExecution(projectRoot, 'layer1-validator', input, null, Date.now() - startTime, true);
|
|
396
|
+
process.exit(0);
|
|
397
|
+
|
|
398
|
+
} catch (err) {
|
|
399
|
+
// 使用增强的错误处理
|
|
400
|
+
const result = handleHookError('layer1-validator', err, {
|
|
401
|
+
eventName: input?.event_name || 'Unknown',
|
|
402
|
+
projectRoot,
|
|
403
|
+
input
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// 记录失败的执行
|
|
407
|
+
if (projectRoot) {
|
|
408
|
+
recordHookExecution(projectRoot, 'layer1-validator', input, result, Date.now() - startTime, false);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
process.stdout.write(JSON.stringify(result.hookSpecificOutput));
|
|
412
|
+
|
|
413
|
+
// 关键 hook:根据错误类型决定退出码
|
|
414
|
+
// fail-closed: 如果 shouldBlock 为 true,使用 exit(2) 阻止操作
|
|
415
|
+
if (result.shouldBlock) {
|
|
416
|
+
process.exit(2);
|
|
417
|
+
} else {
|
|
418
|
+
process.exit(0);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
main();
|