@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,354 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AutoSpec PostToolUse Hook: Execution Tracker
|
|
5
|
+
*
|
|
6
|
+
* Tracks execution of key steps in the AutoSpec pipeline:
|
|
7
|
+
* - Skill loading
|
|
8
|
+
* - Agent invocation
|
|
9
|
+
* - Stage completion
|
|
10
|
+
* - Artifact generation
|
|
11
|
+
*
|
|
12
|
+
* 增强功能:
|
|
13
|
+
* - Trace ID 支持:所有事件关联到 traceId
|
|
14
|
+
* - 统一事件格式:标准化的事件结构
|
|
15
|
+
* - 双写机制:同时写入每日日志和 trace 日志
|
|
16
|
+
*
|
|
17
|
+
* Security Level: LOW - fail-open + logging
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { createHookLogger, safeJsonParse, handleHookError, readStdin, findProjectRootAsync } from './lib/hook-logger.js';
|
|
21
|
+
import { recordHookExecution } from './lib/hook-error-recorder.js';
|
|
22
|
+
import { getState } from './lib/hook-state-manager.js';
|
|
23
|
+
import { generateEventId, getTraceId, appendTraceEvent } from './lib/trace-context.js';
|
|
24
|
+
import fs from 'fs';
|
|
25
|
+
import path from 'path';
|
|
26
|
+
|
|
27
|
+
const logger = createHookLogger('execution-tracker');
|
|
28
|
+
|
|
29
|
+
// Key artifacts to track
|
|
30
|
+
const ARTIFACT_PATTERNS = {
|
|
31
|
+
// Requirement stage
|
|
32
|
+
'requirement.md': { stage: '01-require', type: 'deliverable' },
|
|
33
|
+
'review-requirement.md': { stage: '01-require', type: 'review' },
|
|
34
|
+
|
|
35
|
+
// Design stage
|
|
36
|
+
'design.md': { stage: '02-design', type: 'deliverable' },
|
|
37
|
+
'review-design.md': { stage: '02-design', type: 'review' },
|
|
38
|
+
|
|
39
|
+
// Implementation stage
|
|
40
|
+
'review-code.md': { stage: '03-implement', type: 'review' },
|
|
41
|
+
|
|
42
|
+
// Testing stage
|
|
43
|
+
'tests/': { stage: '05-testing', type: 'deliverable' },
|
|
44
|
+
'review-testing.md': { stage: '05-testing', type: 'review' },
|
|
45
|
+
'evaluation-report.md': { stage: '05-testing', type: 'evaluation' },
|
|
46
|
+
|
|
47
|
+
// Delivery stage
|
|
48
|
+
'consistency-report.md': { stage: '06-delivery', type: 'report' },
|
|
49
|
+
'safety-audit-': { stage: '06-delivery', type: 'audit' },
|
|
50
|
+
|
|
51
|
+
// Practice log
|
|
52
|
+
'practice-log/': { stage: 'evolution', type: 'log' }
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Execution log file
|
|
56
|
+
function getLogPath(projectRoot) {
|
|
57
|
+
const date = new Date().toISOString().split('T')[0];
|
|
58
|
+
return path.join(projectRoot, '.autospec', 'logs', `execution-${date}.json`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function ensureLogDir(projectRoot) {
|
|
62
|
+
const logDir = path.join(projectRoot, '.autospec', 'logs');
|
|
63
|
+
if (!fs.existsSync(logDir)) {
|
|
64
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function readLog(projectRoot) {
|
|
69
|
+
const logPath = getLogPath(projectRoot);
|
|
70
|
+
if (fs.existsSync(logPath)) {
|
|
71
|
+
try {
|
|
72
|
+
return JSON.parse(fs.readFileSync(logPath, 'utf-8'));
|
|
73
|
+
} catch {
|
|
74
|
+
return { entries: [], summary: {} };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { entries: [], summary: {} };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function writeLog(projectRoot, logData) {
|
|
81
|
+
const logPath = getLogPath(projectRoot);
|
|
82
|
+
ensureLogDir(projectRoot);
|
|
83
|
+
fs.writeFileSync(logPath, JSON.stringify(logData, null, 2), 'utf-8');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 创建标准化事件对象
|
|
88
|
+
* @param {string} projectRoot - 项目根目录
|
|
89
|
+
* @param {string} type - 事件类型
|
|
90
|
+
* @param {Object} data - 事件数据
|
|
91
|
+
* @returns {Object} 标准化事件对象
|
|
92
|
+
*/
|
|
93
|
+
function createEvent(projectRoot, type, data = {}) {
|
|
94
|
+
const state = getState(projectRoot);
|
|
95
|
+
const traceId = getTraceId(projectRoot);
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
eventId: generateEventId(),
|
|
99
|
+
traceId,
|
|
100
|
+
timestamp: new Date().toISOString(),
|
|
101
|
+
type,
|
|
102
|
+
source: 'execution-tracker',
|
|
103
|
+
stage: state?.currentStage || data.stage || null,
|
|
104
|
+
tool: data.tool || null,
|
|
105
|
+
action: data.action || null,
|
|
106
|
+
data: data.data || {},
|
|
107
|
+
metadata: {
|
|
108
|
+
projectRoot,
|
|
109
|
+
executionMode: state?.executionMode || 'interactive'
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function addEntry(logData, entry, projectRoot = null) {
|
|
115
|
+
// 创建标准化事件
|
|
116
|
+
const event = {
|
|
117
|
+
timestamp: new Date().toISOString(),
|
|
118
|
+
...entry
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// 如果有 projectRoot,添加 Trace ID
|
|
122
|
+
if (projectRoot) {
|
|
123
|
+
const traceId = getTraceId(projectRoot);
|
|
124
|
+
if (traceId) {
|
|
125
|
+
event.traceId = traceId;
|
|
126
|
+
event.eventId = generateEventId();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
logData.entries.push(event);
|
|
131
|
+
|
|
132
|
+
// Update summary
|
|
133
|
+
const stage = entry.stage || 'unknown';
|
|
134
|
+
if (!logData.summary[stage]) {
|
|
135
|
+
logData.summary[stage] = { count: 0, artifacts: [], reviews: [] };
|
|
136
|
+
}
|
|
137
|
+
logData.summary[stage].count++;
|
|
138
|
+
|
|
139
|
+
if (entry.artifacts) {
|
|
140
|
+
logData.summary[stage].artifacts.push(...entry.artifacts);
|
|
141
|
+
}
|
|
142
|
+
if (entry.reviewed) {
|
|
143
|
+
logData.summary[stage].reviews.push(entry.reviewed);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return event;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function detectArtifactType(filePath) {
|
|
150
|
+
for (const [pattern, info] of Object.entries(ARTIFACT_PATTERNS)) {
|
|
151
|
+
if (filePath.includes(pattern)) {
|
|
152
|
+
return info;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function main() {
|
|
159
|
+
let input;
|
|
160
|
+
try {
|
|
161
|
+
const rawInput = await readStdin(1000);
|
|
162
|
+
input = safeJsonParse(rawInput, null, 'hook input');
|
|
163
|
+
|
|
164
|
+
if (!input) {
|
|
165
|
+
logger.debug('Empty or invalid input, skipping');
|
|
166
|
+
process.exit(0);
|
|
167
|
+
}
|
|
168
|
+
} catch (err) {
|
|
169
|
+
logger.error('Failed to parse input', { error: err.message });
|
|
170
|
+
process.exit(0);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const toolName = input.tool_name;
|
|
174
|
+
|
|
175
|
+
// Track Write operations for artifact generation
|
|
176
|
+
if (toolName === 'Write') {
|
|
177
|
+
const filePath = input.tool_input?.file_path || '';
|
|
178
|
+
|
|
179
|
+
// Find project root
|
|
180
|
+
const cwd = input.cwd || process.cwd();
|
|
181
|
+
const projectRoot = await findProjectRootAsync(cwd);
|
|
182
|
+
|
|
183
|
+
if (!projectRoot) {
|
|
184
|
+
logger.debug('No .autospec directory found, skipping');
|
|
185
|
+
process.exit(0);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Check if this is a key artifact
|
|
189
|
+
const artifactInfo = detectArtifactType(filePath);
|
|
190
|
+
if (artifactInfo) {
|
|
191
|
+
logger.info('Detected key artifact', { filePath, ...artifactInfo });
|
|
192
|
+
|
|
193
|
+
// 读取文件内容用于调试和评测
|
|
194
|
+
let contentPreview = '';
|
|
195
|
+
let contentLength = 0;
|
|
196
|
+
try {
|
|
197
|
+
if (fs.existsSync(filePath)) {
|
|
198
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
199
|
+
contentLength = content.length;
|
|
200
|
+
// 截取前 500 字符作为预览
|
|
201
|
+
contentPreview = content.length > 500
|
|
202
|
+
? content.substring(0, 500) + '... [truncated]'
|
|
203
|
+
: content;
|
|
204
|
+
}
|
|
205
|
+
} catch (e) {
|
|
206
|
+
// 忽略读取错误
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const logData = readLog(projectRoot);
|
|
210
|
+
const event = addEntry(logData, {
|
|
211
|
+
event: 'artifact_created',
|
|
212
|
+
file: filePath,
|
|
213
|
+
stage: artifactInfo.stage,
|
|
214
|
+
type: artifactInfo.type,
|
|
215
|
+
// 增强:记录内容预览用于调试
|
|
216
|
+
contentPreview,
|
|
217
|
+
contentLength
|
|
218
|
+
}, projectRoot);
|
|
219
|
+
writeLog(projectRoot, logData);
|
|
220
|
+
|
|
221
|
+
// 同时写入 trace 日志(包含完整内容用于深度分析)
|
|
222
|
+
const traceEvent = createEvent(projectRoot, 'artifact_created', {
|
|
223
|
+
stage: artifactInfo.stage,
|
|
224
|
+
tool: 'Write',
|
|
225
|
+
action: 'create_artifact',
|
|
226
|
+
data: {
|
|
227
|
+
file: filePath,
|
|
228
|
+
artifactType: artifactInfo.type,
|
|
229
|
+
// 完整内容用于深度评测(仅关键文件)
|
|
230
|
+
fullContent: artifactInfo.type === 'deliverable' ? contentPreview : null,
|
|
231
|
+
contentLength
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
appendTraceEvent(projectRoot, traceEvent);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Track Agent tool usage for review invocations
|
|
239
|
+
if (toolName === 'Agent') {
|
|
240
|
+
const subagentType = input.tool_input?.subagent_type || '';
|
|
241
|
+
const prompt = input.tool_input?.prompt || '';
|
|
242
|
+
|
|
243
|
+
const cwd = input.cwd || process.cwd();
|
|
244
|
+
const projectRoot = await findProjectRootAsync(cwd);
|
|
245
|
+
|
|
246
|
+
if (projectRoot && subagentType) {
|
|
247
|
+
logger.info('Detected Agent invocation', { subagentType });
|
|
248
|
+
|
|
249
|
+
const logData = readLog(projectRoot);
|
|
250
|
+
|
|
251
|
+
// Determine what type of review this is
|
|
252
|
+
let reviewType = 'unknown';
|
|
253
|
+
if (subagentType.includes('reviewer')) {
|
|
254
|
+
reviewType = 'review';
|
|
255
|
+
} else if (subagentType.includes('consistency')) {
|
|
256
|
+
reviewType = 'consistency';
|
|
257
|
+
} else if (subagentType.includes('safety')) {
|
|
258
|
+
reviewType = 'safety';
|
|
259
|
+
} else if (subagentType.includes('diagnose')) {
|
|
260
|
+
reviewType = 'diagnosis';
|
|
261
|
+
} else if (subagentType.includes('ceo') || subagentType.includes('challenger')) {
|
|
262
|
+
reviewType = 'exploration';
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// 截取 prompt 关键信息用于调试和评测
|
|
266
|
+
const promptPreview = prompt.length > 500
|
|
267
|
+
? prompt.substring(0, 500) + '... [truncated]'
|
|
268
|
+
: prompt;
|
|
269
|
+
|
|
270
|
+
const event = addEntry(logData, {
|
|
271
|
+
event: 'agent_invoked',
|
|
272
|
+
subagent: subagentType,
|
|
273
|
+
reviewType,
|
|
274
|
+
stage: 'inferred_from_subagent',
|
|
275
|
+
// 增强:记录 prompt 预览用于调试和评测
|
|
276
|
+
promptPreview,
|
|
277
|
+
promptLength: prompt.length
|
|
278
|
+
}, projectRoot);
|
|
279
|
+
writeLog(projectRoot, logData);
|
|
280
|
+
|
|
281
|
+
// 同时写入 trace 日志(包含完整 prompt 用于深度分析)
|
|
282
|
+
const traceEvent = createEvent(projectRoot, 'agent_invoked', {
|
|
283
|
+
tool: 'Agent',
|
|
284
|
+
action: 'invoke_agent',
|
|
285
|
+
data: {
|
|
286
|
+
subagentType,
|
|
287
|
+
reviewType,
|
|
288
|
+
// 完整 prompt 用于深度评测
|
|
289
|
+
fullPrompt: prompt,
|
|
290
|
+
promptLength: prompt.length
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
appendTraceEvent(projectRoot, traceEvent);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Track Agent response (PostAgentCompletion hook would capture this)
|
|
298
|
+
// 注意:Agent 的 response 需要通过其他 hook 或日志系统捕获
|
|
299
|
+
// 这里我们记录 Agent 调用开始,等待 response hook 补充
|
|
300
|
+
|
|
301
|
+
// Track stage gate completions by checking state.json
|
|
302
|
+
if (toolName === 'Write' || toolName === 'Edit') {
|
|
303
|
+
const filePath = input.tool_input?.file_path || '';
|
|
304
|
+
|
|
305
|
+
if (filePath.includes('state.json')) {
|
|
306
|
+
const cwd = input.cwd || process.cwd();
|
|
307
|
+
const projectRoot = await findProjectRootAsync(cwd);
|
|
308
|
+
|
|
309
|
+
if (projectRoot) {
|
|
310
|
+
const statePath = path.join(projectRoot, '.autospec', 'runtime', 'state.json');
|
|
311
|
+
if (fs.existsSync(statePath)) {
|
|
312
|
+
try {
|
|
313
|
+
const state = JSON.parse(fs.readFileSync(statePath, 'utf-8'));
|
|
314
|
+
if (state.currentStage) {
|
|
315
|
+
logger.info('Stage transition detected', { stage: state.currentStage });
|
|
316
|
+
|
|
317
|
+
const logData = readLog(projectRoot);
|
|
318
|
+
const event = addEntry(logData, {
|
|
319
|
+
event: 'stage_completed',
|
|
320
|
+
stage: state.currentStage,
|
|
321
|
+
completedAt: state.completedAt
|
|
322
|
+
}, projectRoot);
|
|
323
|
+
writeLog(projectRoot, logData);
|
|
324
|
+
|
|
325
|
+
// 同时写入 trace 日志
|
|
326
|
+
const traceEvent = createEvent(projectRoot, 'stage_completed', {
|
|
327
|
+
stage: state.currentStage,
|
|
328
|
+
tool: toolName,
|
|
329
|
+
action: 'complete_stage',
|
|
330
|
+
data: {
|
|
331
|
+
completedAt: state.completedAt
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
appendTraceEvent(projectRoot, traceEvent);
|
|
335
|
+
}
|
|
336
|
+
} catch {
|
|
337
|
+
// Ignore state.json parsing errors
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
process.exit(0);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
main().catch((err) => {
|
|
348
|
+
const result = handleHookError('execution-tracker', err, {
|
|
349
|
+
eventName: 'PostToolUse'
|
|
350
|
+
});
|
|
351
|
+
process.stdout.write(JSON.stringify(result.hookSpecificOutput));
|
|
352
|
+
// Low 优先级 hook:fail-open
|
|
353
|
+
process.exit(0);
|
|
354
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AutoSpec PreToolUse Hook: Frozen Zone Guard
|
|
5
|
+
*
|
|
6
|
+
* Blocks writes/edits to frozen-zone files (constitution, evolution rules, core principles).
|
|
7
|
+
* See framework/evolution.md for zone definitions.
|
|
8
|
+
*
|
|
9
|
+
* Security Level: CRITICAL - fail-closed
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { createHookLogger, safeJsonParse, handleHookError, readStdin, findProjectRootAsync, matchesAnyPattern } from './lib/hook-logger.js';
|
|
13
|
+
import { recordHookExecution } from './lib/hook-error-recorder.js';
|
|
14
|
+
|
|
15
|
+
const logger = createHookLogger('frozen-zone-guard');
|
|
16
|
+
|
|
17
|
+
const FROZEN_PATTERNS = [
|
|
18
|
+
/constitution\.md$/,
|
|
19
|
+
/evolution\.md$/,
|
|
20
|
+
/design-philosophy\.md$/, // Core principles (DP1-DP3)
|
|
21
|
+
/pipeline\/overview\.md$/, // Startup gate + dual validation definitions
|
|
22
|
+
// 全局冻结区模式
|
|
23
|
+
/\.claude\/autospec\/knowledge\/principles\/constitution\.md$/,
|
|
24
|
+
/\.claude\/autospec\/knowledge\/principles\/evolution\.md$/,
|
|
25
|
+
/\.claude\/autospec\/knowledge\/principles\/design-philosophy\.md$/,
|
|
26
|
+
// 组织冻结区模式
|
|
27
|
+
/\.claude\/autospec\/orgs\/[^\/]+\/knowledge\/principles\//
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
// 检查是否为全局/组织路径
|
|
31
|
+
function isGlobalOrOrgPath(filePath) {
|
|
32
|
+
return filePath.includes('/.claude/autospec/') ||
|
|
33
|
+
filePath.includes('\\.claude\\autospec\\');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function main() {
|
|
37
|
+
const startTime = Date.now();
|
|
38
|
+
let input;
|
|
39
|
+
let projectRoot = null;
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const rawInput = await readStdin(1000);
|
|
43
|
+
input = safeJsonParse(rawInput, null, 'hook input');
|
|
44
|
+
|
|
45
|
+
if (!input) {
|
|
46
|
+
logger.debug('Empty or invalid input, skipping');
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const toolName = input.tool_name;
|
|
51
|
+
if (toolName !== 'Write' && toolName !== 'Edit') {
|
|
52
|
+
logger.debug('Not a write/edit operation, skipping', { toolName });
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const filePath = (input.tool_input?.file_path || '').replace(/\\/g, '/');
|
|
57
|
+
if (!filePath) {
|
|
58
|
+
logger.debug('No file path in input, skipping');
|
|
59
|
+
process.exit(0);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
logger.debug('Checking file', { filePath, toolName });
|
|
63
|
+
|
|
64
|
+
// Find project root
|
|
65
|
+
const cwd = input.cwd || process.cwd();
|
|
66
|
+
projectRoot = await findProjectRootAsync(cwd);
|
|
67
|
+
|
|
68
|
+
if (!projectRoot) {
|
|
69
|
+
logger.debug('No .autospec directory found, skipping');
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
logger.debug('Project root found', { projectRoot });
|
|
74
|
+
|
|
75
|
+
// Check if file is in framework directory or global/org directory
|
|
76
|
+
const inFramework = filePath.includes('.autospec/knowledge/') ||
|
|
77
|
+
filePath.includes('/knowledge/');
|
|
78
|
+
const inGlobalOrOrg = isGlobalOrOrgPath(filePath);
|
|
79
|
+
|
|
80
|
+
if (!inFramework && !inGlobalOrOrg) {
|
|
81
|
+
logger.debug('File not in framework or global/org directory, allowing', { filePath });
|
|
82
|
+
// 记录成功执行
|
|
83
|
+
recordHookExecution(projectRoot, 'frozen-zone-guard', input, null, Date.now() - startTime, true);
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
logger.debug('File in framework or global/org, checking frozen patterns', { filePath });
|
|
88
|
+
|
|
89
|
+
// Check against frozen patterns (for both framework and global/org paths)
|
|
90
|
+
if (matchesAnyPattern(filePath, FROZEN_PATTERNS)) {
|
|
91
|
+
logger.info('Blocked write to frozen zone', { filePath });
|
|
92
|
+
|
|
93
|
+
const output = {
|
|
94
|
+
hookSpecificOutput: {
|
|
95
|
+
hookEventName: 'PreToolUse',
|
|
96
|
+
permissionDecision: 'deny',
|
|
97
|
+
permissionDecisionReason:
|
|
98
|
+
`FROZEN ZONE: ${filePath} is protected by AutoSpec evolution rules. ` +
|
|
99
|
+
`This file can only be modified through a human-initiated change process. ` +
|
|
100
|
+
`See framework/evolution.md for details.`
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// 记录成功执行(阻止操作是预期行为)
|
|
105
|
+
recordHookExecution(projectRoot, 'frozen-zone-guard', input, output, Date.now() - startTime, true);
|
|
106
|
+
process.stdout.write(JSON.stringify(output));
|
|
107
|
+
process.exit(0);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
logger.debug('File not in frozen zone, allowing', { filePath });
|
|
111
|
+
// 记录成功执行
|
|
112
|
+
recordHookExecution(projectRoot, 'frozen-zone-guard', input, null, Date.now() - startTime, true);
|
|
113
|
+
process.exit(0);
|
|
114
|
+
|
|
115
|
+
} catch (err) {
|
|
116
|
+
// 使用增强的错误处理
|
|
117
|
+
const result = handleHookError('frozen-zone-guard', err, {
|
|
118
|
+
eventName: 'PreToolUse',
|
|
119
|
+
projectRoot,
|
|
120
|
+
input
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// 记录失败的执行
|
|
124
|
+
if (projectRoot) {
|
|
125
|
+
recordHookExecution(projectRoot, 'frozen-zone-guard', input, result, Date.now() - startTime, false);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
process.stdout.write(JSON.stringify(result.hookSpecificOutput));
|
|
129
|
+
|
|
130
|
+
// 关键 hook:根据错误类型决定退出码
|
|
131
|
+
// fail-closed: 如果 shouldBlock 为 true,使用 exit(2) 阻止操作
|
|
132
|
+
if (result.shouldBlock) {
|
|
133
|
+
process.exit(2);
|
|
134
|
+
} else {
|
|
135
|
+
process.exit(0);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
main();
|