@mycodemap/mycodemap 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +164 -6
- package/README.md +407 -141
- package/dist/cli/commands/ci.d.ts +7 -1
- package/dist/cli/commands/ci.d.ts.map +1 -1
- package/dist/cli/commands/ci.js +38 -0
- package/dist/cli/commands/ci.js.map +1 -1
- package/dist/cli/commands/cycles.d.ts.map +1 -1
- package/dist/cli/commands/cycles.js +2 -0
- package/dist/cli/commands/cycles.js.map +1 -1
- package/dist/cli/commands/export.d.ts +6 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +108 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +96 -0
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +3 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/logs.d.ts +5 -0
- package/dist/cli/commands/logs.d.ts.map +1 -0
- package/dist/cli/commands/logs.js +189 -0
- package/dist/cli/commands/logs.js.map +1 -0
- package/dist/cli/commands/report.d.ts +12 -0
- package/dist/cli/commands/report.d.ts.map +1 -0
- package/dist/cli/commands/report.js +158 -0
- package/dist/cli/commands/report.js.map +1 -0
- package/dist/cli/commands/server.d.ts +9 -0
- package/dist/cli/commands/server.d.ts.map +1 -0
- package/dist/cli/commands/server.js +68 -0
- package/dist/cli/commands/server.js.map +1 -0
- package/dist/cli/commands/watch-foreground.d.ts.map +1 -1
- package/dist/cli/commands/watch-foreground.js +2 -0
- package/dist/cli/commands/watch-foreground.js.map +1 -1
- package/dist/cli/commands/watch.d.ts.map +1 -1
- package/dist/cli/commands/watch.js +2 -0
- package/dist/cli/commands/watch.js.map +1 -1
- package/dist/cli/first-run-guide.d.ts +23 -0
- package/dist/cli/first-run-guide.d.ts.map +1 -0
- package/dist/cli/first-run-guide.js +83 -0
- package/dist/cli/first-run-guide.js.map +1 -0
- package/dist/cli/index.js +85 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/platform-check.d.ts +21 -0
- package/dist/cli/platform-check.d.ts.map +1 -0
- package/dist/cli/platform-check.js +94 -0
- package/dist/cli/platform-check.js.map +1 -0
- package/dist/cli/tree-sitter-check.d.ts +35 -0
- package/dist/cli/tree-sitter-check.d.ts.map +1 -0
- package/dist/cli/tree-sitter-check.js +133 -0
- package/dist/cli/tree-sitter-check.js.map +1 -0
- package/dist/cli/utils/sanitize.d.ts +54 -0
- package/dist/cli/utils/sanitize.d.ts.map +1 -0
- package/dist/cli/utils/sanitize.js +131 -0
- package/dist/cli/utils/sanitize.js.map +1 -0
- package/dist/cli-new/commands/export.d.ts +15 -0
- package/dist/cli-new/commands/export.d.ts.map +1 -0
- package/dist/cli-new/commands/export.js +107 -0
- package/dist/cli-new/commands/export.js.map +1 -0
- package/dist/cli-new/commands/query.d.ts +14 -0
- package/dist/cli-new/commands/query.d.ts.map +1 -0
- package/dist/cli-new/commands/query.js +120 -0
- package/dist/cli-new/commands/query.js.map +1 -0
- package/dist/cli-new/commands/server.d.ts +13 -0
- package/dist/cli-new/commands/server.d.ts.map +1 -0
- package/dist/cli-new/commands/server.js +94 -0
- package/dist/cli-new/commands/server.js.map +1 -0
- package/dist/cli-new/index.d.ts +11 -0
- package/dist/cli-new/index.d.ts.map +1 -0
- package/dist/cli-new/index.js +63 -0
- package/dist/cli-new/index.js.map +1 -0
- package/dist/cli-new/types/index.d.ts +88 -0
- package/dist/cli-new/types/index.d.ts.map +1 -0
- package/dist/cli-new/types/index.js +7 -0
- package/dist/cli-new/types/index.js.map +1 -0
- package/dist/domain/entities/CodeGraph.d.ts +134 -0
- package/dist/domain/entities/CodeGraph.d.ts.map +1 -0
- package/dist/domain/entities/CodeGraph.js +316 -0
- package/dist/domain/entities/CodeGraph.js.map +1 -0
- package/dist/domain/entities/Dependency.d.ts +78 -0
- package/dist/domain/entities/Dependency.d.ts.map +1 -0
- package/dist/domain/entities/Dependency.js +132 -0
- package/dist/domain/entities/Dependency.js.map +1 -0
- package/dist/domain/entities/Module.d.ts +75 -0
- package/dist/domain/entities/Module.d.ts.map +1 -0
- package/dist/domain/entities/Module.js +151 -0
- package/dist/domain/entities/Module.js.map +1 -0
- package/dist/domain/entities/Project.d.ts +50 -0
- package/dist/domain/entities/Project.d.ts.map +1 -0
- package/dist/domain/entities/Project.js +99 -0
- package/dist/domain/entities/Project.js.map +1 -0
- package/dist/domain/entities/Symbol.d.ts +75 -0
- package/dist/domain/entities/Symbol.d.ts.map +1 -0
- package/dist/domain/entities/Symbol.js +130 -0
- package/dist/domain/entities/Symbol.js.map +1 -0
- package/dist/domain/events/DomainEvent.d.ts +76 -0
- package/dist/domain/events/DomainEvent.d.ts.map +1 -0
- package/dist/domain/events/DomainEvent.js +153 -0
- package/dist/domain/events/DomainEvent.js.map +1 -0
- package/dist/domain/index.d.ts +10 -0
- package/dist/domain/index.d.ts.map +1 -0
- package/dist/domain/index.js +18 -0
- package/dist/domain/index.js.map +1 -0
- package/dist/domain/repositories/CodeGraphRepository.d.ts +58 -0
- package/dist/domain/repositories/CodeGraphRepository.d.ts.map +1 -0
- package/dist/domain/repositories/CodeGraphRepository.js +37 -0
- package/dist/domain/repositories/CodeGraphRepository.js.map +1 -0
- package/dist/domain/services/CodeGraphBuilder.d.ts +50 -0
- package/dist/domain/services/CodeGraphBuilder.d.ts.map +1 -0
- package/dist/domain/services/CodeGraphBuilder.js +121 -0
- package/dist/domain/services/CodeGraphBuilder.js.map +1 -0
- package/dist/infrastructure/parser/implementations/GoParser.d.ts +25 -0
- package/dist/infrastructure/parser/implementations/GoParser.d.ts.map +1 -0
- package/dist/infrastructure/parser/implementations/GoParser.js +158 -0
- package/dist/infrastructure/parser/implementations/GoParser.js.map +1 -0
- package/dist/infrastructure/parser/implementations/PythonParser.d.ts +30 -0
- package/dist/infrastructure/parser/implementations/PythonParser.d.ts.map +1 -0
- package/dist/infrastructure/parser/implementations/PythonParser.js +201 -0
- package/dist/infrastructure/parser/implementations/PythonParser.js.map +1 -0
- package/dist/infrastructure/parser/implementations/TypeScriptParser.d.ts +63 -0
- package/dist/infrastructure/parser/implementations/TypeScriptParser.d.ts.map +1 -0
- package/dist/infrastructure/parser/implementations/TypeScriptParser.js +420 -0
- package/dist/infrastructure/parser/implementations/TypeScriptParser.js.map +1 -0
- package/dist/infrastructure/parser/index.d.ts +13 -0
- package/dist/infrastructure/parser/index.d.ts.map +1 -0
- package/dist/infrastructure/parser/index.js +32 -0
- package/dist/infrastructure/parser/index.js.map +1 -0
- package/dist/infrastructure/parser/interfaces/ParserBase.d.ts +124 -0
- package/dist/infrastructure/parser/interfaces/ParserBase.d.ts.map +1 -0
- package/dist/infrastructure/parser/interfaces/ParserBase.js +200 -0
- package/dist/infrastructure/parser/interfaces/ParserBase.js.map +1 -0
- package/dist/infrastructure/parser/registry/ParserRegistry.d.ts +68 -0
- package/dist/infrastructure/parser/registry/ParserRegistry.d.ts.map +1 -0
- package/dist/infrastructure/parser/registry/ParserRegistry.js +116 -0
- package/dist/infrastructure/parser/registry/ParserRegistry.js.map +1 -0
- package/dist/infrastructure/repositories/CodeGraphRepositoryImpl.d.ts +44 -0
- package/dist/infrastructure/repositories/CodeGraphRepositoryImpl.d.ts.map +1 -0
- package/dist/infrastructure/repositories/CodeGraphRepositoryImpl.js +129 -0
- package/dist/infrastructure/repositories/CodeGraphRepositoryImpl.js.map +1 -0
- package/dist/infrastructure/repositories/index.d.ts +3 -0
- package/dist/infrastructure/repositories/index.d.ts.map +1 -0
- package/dist/infrastructure/repositories/index.js +7 -0
- package/dist/infrastructure/repositories/index.js.map +1 -0
- package/dist/infrastructure/storage/StorageFactory.d.ts +53 -0
- package/dist/infrastructure/storage/StorageFactory.d.ts.map +1 -0
- package/dist/infrastructure/storage/StorageFactory.js +150 -0
- package/dist/infrastructure/storage/StorageFactory.js.map +1 -0
- package/dist/infrastructure/storage/adapters/FileSystemStorage.d.ts +52 -0
- package/dist/infrastructure/storage/adapters/FileSystemStorage.d.ts.map +1 -0
- package/dist/infrastructure/storage/adapters/FileSystemStorage.js +315 -0
- package/dist/infrastructure/storage/adapters/FileSystemStorage.js.map +1 -0
- package/dist/infrastructure/storage/adapters/KuzuDBStorage.d.ts +52 -0
- package/dist/infrastructure/storage/adapters/KuzuDBStorage.d.ts.map +1 -0
- package/dist/infrastructure/storage/adapters/KuzuDBStorage.js +235 -0
- package/dist/infrastructure/storage/adapters/KuzuDBStorage.js.map +1 -0
- package/dist/infrastructure/storage/adapters/MemoryStorage.d.ts +37 -0
- package/dist/infrastructure/storage/adapters/MemoryStorage.d.ts.map +1 -0
- package/dist/infrastructure/storage/adapters/MemoryStorage.js +229 -0
- package/dist/infrastructure/storage/adapters/MemoryStorage.js.map +1 -0
- package/dist/infrastructure/storage/adapters/Neo4jStorage.d.ts +49 -0
- package/dist/infrastructure/storage/adapters/Neo4jStorage.d.ts.map +1 -0
- package/dist/infrastructure/storage/adapters/Neo4jStorage.js +222 -0
- package/dist/infrastructure/storage/adapters/Neo4jStorage.js.map +1 -0
- package/dist/infrastructure/storage/index.d.ts +6 -0
- package/dist/infrastructure/storage/index.d.ts.map +1 -0
- package/dist/infrastructure/storage/index.js +13 -0
- package/dist/infrastructure/storage/index.js.map +1 -0
- package/dist/infrastructure/storage/interfaces/StorageBase.d.ts +76 -0
- package/dist/infrastructure/storage/interfaces/StorageBase.d.ts.map +1 -0
- package/dist/infrastructure/storage/interfaces/StorageBase.js +116 -0
- package/dist/infrastructure/storage/interfaces/StorageBase.js.map +1 -0
- package/dist/interface/config/index.d.ts +102 -0
- package/dist/interface/config/index.d.ts.map +1 -0
- package/dist/interface/config/index.js +7 -0
- package/dist/interface/config/index.js.map +1 -0
- package/dist/interface/types/index.d.ts +425 -0
- package/dist/interface/types/index.d.ts.map +1 -0
- package/dist/interface/types/index.js +8 -0
- package/dist/interface/types/index.js.map +1 -0
- package/dist/interface/types/parser.d.ts +103 -0
- package/dist/interface/types/parser.d.ts.map +1 -0
- package/dist/interface/types/parser.js +7 -0
- package/dist/interface/types/parser.js.map +1 -0
- package/dist/interface/types/storage.d.ts +98 -0
- package/dist/interface/types/storage.d.ts.map +1 -0
- package/dist/interface/types/storage.js +7 -0
- package/dist/interface/types/storage.js.map +1 -0
- package/dist/orchestrator/test-linker.js +1 -1
- package/dist/orchestrator/test-linker.js.map +1 -1
- package/dist/server/CodeMapServer.d.ts +51 -0
- package/dist/server/CodeMapServer.d.ts.map +1 -0
- package/dist/server/CodeMapServer.js +146 -0
- package/dist/server/CodeMapServer.js.map +1 -0
- package/dist/server/handlers/AnalysisHandler.d.ts +82 -0
- package/dist/server/handlers/AnalysisHandler.d.ts.map +1 -0
- package/dist/server/handlers/AnalysisHandler.js +196 -0
- package/dist/server/handlers/AnalysisHandler.js.map +1 -0
- package/dist/server/handlers/QueryHandler.d.ts +57 -0
- package/dist/server/handlers/QueryHandler.d.ts.map +1 -0
- package/dist/server/handlers/QueryHandler.js +260 -0
- package/dist/server/handlers/QueryHandler.js.map +1 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +13 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/routes/api.d.ts +8 -0
- package/dist/server/routes/api.d.ts.map +1 -0
- package/dist/server/routes/api.js +372 -0
- package/dist/server/routes/api.js.map +1 -0
- package/dist/server/types/index.d.ts +171 -0
- package/dist/server/types/index.d.ts.map +1 -0
- package/dist/server/types/index.js +7 -0
- package/dist/server/types/index.js.map +1 -0
- package/dist/types/index.d.ts +6 -372
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +9 -3
- package/dist/types/index.js.map +1 -1
- package/docs/AI_ASSISTANT_SETUP.md +811 -0
- package/docs/PUBLISHING.md +162 -0
- package/docs/README.md +37 -0
- package/docs/SETUP_GUIDE.md +493 -0
- package/docs/ai-guide/COMMANDS.md +369 -0
- package/docs/ai-guide/INTEGRATION.md +513 -0
- package/docs/ai-guide/OUTPUT.md +465 -0
- package/docs/ai-guide/PATTERNS.md +409 -0
- package/docs/ai-guide/PROMPTS.md +414 -0
- package/docs/ai-guide/QUICKSTART.md +114 -0
- package/docs/ai-guide/README.md +66 -0
- package/docs/archive/AI_INTEGRATION_GUIDE_ARCHIVED.md +391 -0
- package/docs/archive/ARCHIVE.md +39 -0
- package/docs/archive/MYCLAUDE_GUIDE.md +305 -0
- package/docs/archive/PUBLISH_NPM_DESIGN_V1.md +1699 -0
- package/docs/archive/PUBLISH_NPM_DESIGN_V2.md +396 -0
- package/docs/archive/README.md +29 -0
- package/docs/archive/TASK_DESIGN_COVERAGE_REPORT.md +320 -0
- package/docs/archive/TEST_SUMMARY.md +140 -0
- package/docs/archive/comprehensive_test_report.md +337 -0
- package/docs/archive/design-docs/CI_GATEWAY_DESIGN.md +790 -0
- package/docs/archive/design-docs/PUBLISH_NPM_DESIGN_FINAL.md +491 -0
- package/docs/archive/design-docs/REFACTOR_ARCHITECTURE_OVERVIEW.md +558 -0
- package/docs/archive/design-docs/REFACTOR_CONFIDENCE_DESIGN.md +250 -0
- package/docs/archive/design-docs/REFACTOR_GIT_ANALYZER_DESIGN.md +791 -0
- package/docs/archive/design-docs/REFACTOR_ORCHESTRATOR_DESIGN.md +1071 -0
- package/docs/archive/design-docs/REFACTOR_RESULT_FUSION_DESIGN.md +321 -0
- package/docs/archive/design-docs/REFACTOR_TEST_LINKER_DESIGN.md +317 -0
- package/docs/archive/myclaude.md +1084 -0
- package/docs/archive/plans/2026-03-14-go-language-support-design.md +92 -0
- package/docs/archive/product-specs/REFACTOR_REQUIREMENTS.md +976 -0
- package/docs/archive/scenario-2-deps-analysis.md +353 -0
- package/docs/archive/test-report-symbol-search.md +384 -0
- package/docs/archive/test-scenario-4-complexity-analysis.md +460 -0
- package/docs/archive/test_report_scenario5.md +615 -0
- package/docs/archive/test_scenario_3_impact_analysis_report.md +520 -0
- package/docs/design-docs/README.md +26 -0
- package/docs/exec-plans/MVP3-IMPLEMENTATION-ROADMAP.md +524 -0
- package/docs/exec-plans/README.md +29 -0
- package/docs/exec-plans/active/.gitkeep +0 -0
- package/docs/exec-plans/completed/.gitkeep +0 -0
- package/docs/exec-plans/completed/2026-03-03-deps-path-extension-fix.md +186 -0
- package/docs/exec-plans/completed/2026-03-03-post-task-plan.md +135 -0
- package/docs/exec-plans/completed/harness-engineering-rollout.md +184 -0
- package/docs/exec-plans/tech-debt/.gitkeep +0 -0
- package/docs/exec-plans/tech-debt/2026-03-15-lint-guardrail-gap.md +30 -0
- package/docs/generated/README.md +19 -0
- package/docs/product-specs/MVP3-ARCHITECTURE-COMPARISON.md +504 -0
- package/docs/product-specs/MVP3-ARCHITECTURE-REDESIGN-PRD.md +322 -0
- package/docs/product-specs/MVP3-ARCHITECTURE-REDESIGN-TECH-PRD.md +1374 -0
- package/docs/product-specs/README.md +22 -0
- package/docs/references/README.md +15 -0
- package/docs/references/tmp.md +527 -0
- package/docs/rules/README.md +16 -0
- package/docs/rules/architecture-guardrails.md +349 -0
- package/docs/rules/code-quality-redlines.md +321 -0
- package/docs/rules/deployment.md +23 -0
- package/docs/rules/engineering-with-codex-openai.md +202 -0
- package/docs/rules/testing.md +73 -0
- package/docs/rules/validation.md +39 -0
- package/examples/README.md +61 -0
- package/examples/claude/codemap-skill.md +94 -0
- package/examples/codex/codemap-agent.md +66 -0
- package/examples/copilot/copilot-instructions.md +24 -0
- package/examples/kimi/codemap-skill.md +92 -0
- package/package.json +22 -7
|
@@ -0,0 +1,791 @@
|
|
|
1
|
+
# Git 分析器详细设计
|
|
2
|
+
|
|
3
|
+
> 归档时间:2026-03-15
|
|
4
|
+
> 归档原因:历史重构设计稿,文件头与 AI feed 等细节已由现行规则和实现收敛。
|
|
5
|
+
> 当前依据:`ARCHITECTURE.md`、`docs/rules/engineering-with-codex-openai.md`、`src/orchestrator/git-analyzer.ts`
|
|
6
|
+
> 状态:仅供历史对照,不作为当前执行依据。
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
> 版本: 2.5
|
|
10
|
+
> 所属模块: 编排层 - Git 分析器
|
|
11
|
+
> 更新日期: 2026-02-28
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 1. 功能定位
|
|
16
|
+
|
|
17
|
+
在影响分析场景中,分析文件的修改历史,评估修改风险。
|
|
18
|
+
|
|
19
|
+
**新增功能 (v2.4)**:
|
|
20
|
+
- 极简 Commit 格式验证 `[TAG]` 格式
|
|
21
|
+
- AI 饲料生成器 (`.mycodemap/ai-feed.txt`)
|
|
22
|
+
- 文件头注释扫描 `[META]`/`[WHY]`/`[DEPS]`
|
|
23
|
+
- 基于 GRAVITY/HEAT/IMPACT 的危险置信度计算
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 2. 数据结构设计
|
|
28
|
+
|
|
29
|
+
### 2.1 提交信息
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// src/orchestrator/git-analyzer.ts
|
|
33
|
+
|
|
34
|
+
interface CommitInfo {
|
|
35
|
+
hash: string;
|
|
36
|
+
message: string;
|
|
37
|
+
date: Date;
|
|
38
|
+
author: string;
|
|
39
|
+
files: string[];
|
|
40
|
+
tag?: CommitTag; // [TAG] 解析结果 (v2.4新增)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// v2.4 新增: 极简 Commit Tag
|
|
44
|
+
interface CommitTag {
|
|
45
|
+
type: 'BUGFIX' | 'FEATURE' | 'REFACTOR' | 'CONFIG' | 'DOCS' | 'DELETE' | 'UNKNOWN';
|
|
46
|
+
scope: string; // 模块名,如 "git-analyzer"
|
|
47
|
+
subject: string; // 提交描述
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2.2 风险评分 (v2.4 重构)
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
interface RiskScore {
|
|
55
|
+
level: 'high' | 'medium' | 'low';
|
|
56
|
+
score: number; // 0-1 综合分数
|
|
57
|
+
|
|
58
|
+
// 维度评分
|
|
59
|
+
gravity: number; // 依赖复杂度 (出度+入度)
|
|
60
|
+
heat: HeatScore; // 时间维度活跃度
|
|
61
|
+
impact: number; // 影响面 (被依赖数)
|
|
62
|
+
|
|
63
|
+
riskFactors: string[]; // 风险因素说明
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// v2.4 新增: 热度评分
|
|
67
|
+
interface HeatScore {
|
|
68
|
+
freq30d: number; // 30天内修改次数
|
|
69
|
+
lastType: string; // 最后提交标签 [BUGFIX]等
|
|
70
|
+
lastDate: Date | null; // 最后修改日期
|
|
71
|
+
stability: boolean; // 是否稳定 (沉积岩 vs 火山灰)
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 2.3 AI 饲料数据结构 (v2.4 新增)
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// src/orchestrator/ai-feed-generator.ts
|
|
79
|
+
|
|
80
|
+
interface AIFeed {
|
|
81
|
+
file: string;
|
|
82
|
+
gravity: number; // 依赖复杂度分数
|
|
83
|
+
heat: HeatScore; // 时间维度
|
|
84
|
+
meta: FileMeta; // 文件元数据
|
|
85
|
+
deps: string[]; // 依赖的文件
|
|
86
|
+
dependents: string[]; // 被哪些文件依赖
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface FileMeta {
|
|
90
|
+
since?: string; // 创建时间 2024-01
|
|
91
|
+
owner?: string; // 负责人/团队
|
|
92
|
+
stable?: boolean; // 是否稳定
|
|
93
|
+
why?: string; // 存在理由 (苏格拉底问题)
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 2.4 文件头注释格式 (v2.4 新增)
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// src/orchestrator/file-header-scanner.ts
|
|
101
|
+
|
|
102
|
+
interface FileHeader {
|
|
103
|
+
meta?: {
|
|
104
|
+
since?: string;
|
|
105
|
+
owner?: string;
|
|
106
|
+
stable?: boolean;
|
|
107
|
+
};
|
|
108
|
+
why?: string; // [WHY] 回答
|
|
109
|
+
deps?: string[]; // [DEPS] 关键依赖
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 扫描规则:
|
|
113
|
+
// - 检查文件前10行
|
|
114
|
+
// - 正则匹配: \/\/ \[META\] (.+)
|
|
115
|
+
// - 正则匹配: \/\/ \[WHY\] (.+)
|
|
116
|
+
// - 正则匹配: \/\/ \[DEPS\] (.+)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 3. 接口设计
|
|
122
|
+
|
|
123
|
+
### 3.1 Git 分析器类
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
class GitAnalyzer {
|
|
127
|
+
/**
|
|
128
|
+
* 查找相关提交
|
|
129
|
+
* 支持两种模式:关键词搜索 + 文件搜索
|
|
130
|
+
*/
|
|
131
|
+
async findRelatedCommits(
|
|
132
|
+
keywords: string[],
|
|
133
|
+
files: string[],
|
|
134
|
+
options: { maxCommits: number; projectRoot: string }
|
|
135
|
+
): Promise<CommitInfo[]> {
|
|
136
|
+
const commits: CommitInfo[] = [];
|
|
137
|
+
|
|
138
|
+
// 1. 关键词搜索(提交信息)
|
|
139
|
+
if (keywords.length > 0) {
|
|
140
|
+
const keywordResults = await this.searchByKeywords(keywords, options.maxCommits);
|
|
141
|
+
commits.push(...keywordResults);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 2. 文件搜索(修改过的文件)
|
|
145
|
+
if (files.length > 0) {
|
|
146
|
+
const fileResults = await this.searchByFiles(files, options.maxCommits);
|
|
147
|
+
commits.push(...fileResults);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 3. 去重 + 排序(按日期)
|
|
151
|
+
const unique = new Map<string, CommitInfo>();
|
|
152
|
+
for (const commit of commits) {
|
|
153
|
+
if (!unique.has(commit.hash)) {
|
|
154
|
+
unique.set(commit.hash, commit);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return Array.from(unique.values())
|
|
159
|
+
.sort((a, b) => b.date.getTime() - a.date.getTime())
|
|
160
|
+
.slice(0, options.maxCommits);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// v2.4 新增: 解析极简 Commit Tag
|
|
164
|
+
parseCommitTag(message: string): CommitTag | undefined {
|
|
165
|
+
const match = message.match(/^\[(BUGFIX|FEATURE|REFACTOR|CONFIG|DOCS|DELETE)\]\s*(.+?)?:(.+)$/);
|
|
166
|
+
if (!match) return undefined;
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
type: match[1] as CommitTag['type'],
|
|
170
|
+
scope: match[2]?.trim() || 'general',
|
|
171
|
+
subject: match[3].trim()
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 3.2 关键词搜索
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
private async searchByKeywords(
|
|
181
|
+
keywords: string[],
|
|
182
|
+
limit: number
|
|
183
|
+
): Promise<CommitInfo[]> {
|
|
184
|
+
// 使用 execFile + 参数数组避免命令注入
|
|
185
|
+
// 同时限制关键词长度防止过度匹配
|
|
186
|
+
const sanitizedKeywords = keywords
|
|
187
|
+
.slice(0, 5) // 最多 5 个关键词
|
|
188
|
+
.map(k => k.slice(0, 100)) // 每个关键词最多 100 字符
|
|
189
|
+
.filter(k => /^[a-zA-Z0-9_\-\.]+$/.test(k)); // 仅允许安全字符
|
|
190
|
+
|
|
191
|
+
if (sanitizedKeywords.length === 0) return [];
|
|
192
|
+
|
|
193
|
+
const pattern = sanitizedKeywords.join('|');
|
|
194
|
+
const { stdout } = await execFile('git', [
|
|
195
|
+
'log', '--all', `--grep=${pattern}`,
|
|
196
|
+
'--format=%H|%s|%ai|%an',
|
|
197
|
+
'-n', String(limit)
|
|
198
|
+
]);
|
|
199
|
+
|
|
200
|
+
return this.parseGitLog(stdout);
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### 3.3 文件搜索
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
private async searchByFiles(
|
|
208
|
+
files: string[],
|
|
209
|
+
limit: number
|
|
210
|
+
): Promise<CommitInfo[]> {
|
|
211
|
+
// git --follow 语义仅支持单路径,多文件需逐个查询后合并
|
|
212
|
+
const allCommits: CommitInfo[] = [];
|
|
213
|
+
|
|
214
|
+
for (const file of files) {
|
|
215
|
+
try {
|
|
216
|
+
const { stdout } = await execFile('git', [
|
|
217
|
+
'log', '--follow', '--format=%H|%s|%ai|%an', '--name-only',
|
|
218
|
+
'-n', String(limit), '--', file
|
|
219
|
+
]);
|
|
220
|
+
const fileCommits = this.parseGitLogWithFiles(stdout);
|
|
221
|
+
allCommits.push(...fileCommits);
|
|
222
|
+
} catch {
|
|
223
|
+
// 单文件查询失败时跳过
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 按哈希去重
|
|
228
|
+
const unique = new Map<string, CommitInfo>();
|
|
229
|
+
for (const commit of allCommits) {
|
|
230
|
+
if (!unique.has(commit.hash)) {
|
|
231
|
+
unique.set(commit.hash, commit);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return Array.from(unique.values());
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### 3.4 风险评分计算 (v2.4 重构)
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
/**
|
|
243
|
+
* 计算风险评分 (v2.4 重构版)
|
|
244
|
+
* 基于 GRAVITY / HEAT / IMPACT 三维模型
|
|
245
|
+
*/
|
|
246
|
+
calculateRiskScore(
|
|
247
|
+
targetFiles: string[],
|
|
248
|
+
commits: CommitInfo[],
|
|
249
|
+
feedData: AIFeed[] // AI 饲料数据
|
|
250
|
+
): RiskScore {
|
|
251
|
+
// 1. 获取文件饲料数据
|
|
252
|
+
const fileFeeds = feedData.filter(f => targetFiles.includes(f.file));
|
|
253
|
+
|
|
254
|
+
// 2. 计算 GRAVITY (依赖复杂度)
|
|
255
|
+
const avgGravity = fileFeeds.reduce((sum, f) => sum + f.gravity, 0) /
|
|
256
|
+
(fileFeeds.length || 1);
|
|
257
|
+
const gravityScore = Math.min(avgGravity / 20, 1); // 归一化到 0-1
|
|
258
|
+
|
|
259
|
+
// 3. 计算 HEAT (时间维度)
|
|
260
|
+
const totalFreq = fileFeeds.reduce((sum, f) => sum + f.heat.freq30d, 0);
|
|
261
|
+
const avgFreq = totalFreq / (fileFeeds.length || 1);
|
|
262
|
+
const freqScore = Math.min(avgFreq / 10, 1);
|
|
263
|
+
|
|
264
|
+
// 标签风险权重
|
|
265
|
+
const tagWeights: Record<string, number> = {
|
|
266
|
+
'BUGFIX': 0.9, // 修复过的代码 = 有风险
|
|
267
|
+
'REFACTOR': 0.8, // 重构过的代码
|
|
268
|
+
'FEATURE': 0.7, // 新功能
|
|
269
|
+
'CONFIG': 0.5,
|
|
270
|
+
'DOCS': 0.2,
|
|
271
|
+
'DELETE': 0.1,
|
|
272
|
+
'UNKNOWN': 0.5
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
const lastTypes = fileFeeds.map(f => f.heat.lastType);
|
|
276
|
+
const avgTagRisk = lastTypes.reduce((sum, t) => sum + (tagWeights[t] || 0.5), 0) /
|
|
277
|
+
(lastTypes.length || 1);
|
|
278
|
+
|
|
279
|
+
// 4. 计算 IMPACT (影响面)
|
|
280
|
+
const totalDependents = fileFeeds.reduce((sum, f) => sum + f.dependents.length, 0);
|
|
281
|
+
const impactScore = Math.min(totalDependents / 50, 1);
|
|
282
|
+
|
|
283
|
+
// 5. 稳定性调整(与需求文档一致:不稳定文件增加风险)
|
|
284
|
+
const unstableCount = fileFeeds.filter(f => f.meta.stable === false).length;
|
|
285
|
+
const unstableRatio = unstableCount / (fileFeeds.length || 1);
|
|
286
|
+
const stabilityBoost = unstableRatio * 0.15;
|
|
287
|
+
|
|
288
|
+
// 6. 综合评分(单一真源:../product-specs/REFACTOR_REQUIREMENTS.md 8.6)
|
|
289
|
+
const totalScore = Math.min(
|
|
290
|
+
Math.max(
|
|
291
|
+
gravityScore * 0.30 +
|
|
292
|
+
freqScore * 0.15 +
|
|
293
|
+
avgTagRisk * 0.10 +
|
|
294
|
+
stabilityBoost +
|
|
295
|
+
impactScore * 0.10,
|
|
296
|
+
0
|
|
297
|
+
),
|
|
298
|
+
1
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
const riskFactors: string[] = [];
|
|
302
|
+
if (gravityScore > 0.7) riskFactors.push('高依赖复杂度');
|
|
303
|
+
if (freqScore > 0.7) riskFactors.push('近期频繁修改');
|
|
304
|
+
if (avgTagRisk > 0.7) riskFactors.push('历史问题较多(BUGFIX频繁)');
|
|
305
|
+
if (impactScore > 0.7) riskFactors.push('影响面广');
|
|
306
|
+
if (unstableCount > 0) riskFactors.push('模块标记为不稳定');
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
level: totalScore > 0.7 ? 'high' : totalScore > 0.4 ? 'medium' : 'low',
|
|
310
|
+
score: totalScore,
|
|
311
|
+
gravity: gravityScore,
|
|
312
|
+
heat: {
|
|
313
|
+
freq30d: Math.round(avgFreq),
|
|
314
|
+
lastType: lastTypes[0] || 'UNKNOWN',
|
|
315
|
+
lastDate: fileFeeds[0]?.heat.lastDate || null,
|
|
316
|
+
stability: unstableCount === 0
|
|
317
|
+
},
|
|
318
|
+
impact: impactScore,
|
|
319
|
+
riskFactors
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### 3.5 日志解析
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
private parseGitLog(stdout: string): CommitInfo[] {
|
|
328
|
+
return stdout.trim().split('\n')
|
|
329
|
+
.filter(line => line.trim())
|
|
330
|
+
.map(line => {
|
|
331
|
+
const [hash, message, date, author] = line.split('|');
|
|
332
|
+
return {
|
|
333
|
+
hash,
|
|
334
|
+
message,
|
|
335
|
+
date: new Date(date),
|
|
336
|
+
author,
|
|
337
|
+
files: [],
|
|
338
|
+
tag: this.parseCommitTag(message) // v2.4 新增
|
|
339
|
+
};
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## 4. AI 饲料生成器 (v2.4 新增)
|
|
347
|
+
|
|
348
|
+
### 4.1 核心类设计
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
// src/orchestrator/ai-feed-generator.ts
|
|
352
|
+
|
|
353
|
+
class AIFeedGenerator {
|
|
354
|
+
private gitAnalyzer: GitAnalyzer;
|
|
355
|
+
private headerScanner: FileHeaderScanner;
|
|
356
|
+
|
|
357
|
+
constructor(gitAnalyzer: GitAnalyzer) {
|
|
358
|
+
this.gitAnalyzer = gitAnalyzer;
|
|
359
|
+
this.headerScanner = new FileHeaderScanner();
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* 生成 AI 饲料
|
|
364
|
+
* 集成到 codemap generate 命令
|
|
365
|
+
*/
|
|
366
|
+
async generate(projectRoot: string): Promise<AIFeed[]> {
|
|
367
|
+
const files = await globby(['src/**/*.ts'], { cwd: projectRoot });
|
|
368
|
+
const feed: AIFeed[] = [];
|
|
369
|
+
|
|
370
|
+
// 第一遍:收集基础信息
|
|
371
|
+
for (const file of files) {
|
|
372
|
+
const fullPath = path.join(projectRoot, file);
|
|
373
|
+
feed.push({
|
|
374
|
+
file,
|
|
375
|
+
gravity: 0,
|
|
376
|
+
heat: this.scanGitHistory(file, projectRoot),
|
|
377
|
+
meta: this.headerScanner.scan(fullPath),
|
|
378
|
+
deps: [],
|
|
379
|
+
dependents: []
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// 第二遍:计算依赖关系
|
|
384
|
+
const fileMap = new Map(feed.map(f => [f.file, f]));
|
|
385
|
+
|
|
386
|
+
for (const item of feed) {
|
|
387
|
+
const fullPath = path.join(projectRoot, item.file);
|
|
388
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
389
|
+
|
|
390
|
+
// 扫描 import 语句
|
|
391
|
+
const imports = [...content.matchAll(/from ['"](\.\.?\/.+?)['"]/g)]
|
|
392
|
+
.map(m => m[1] + '.ts');
|
|
393
|
+
|
|
394
|
+
item.deps = imports;
|
|
395
|
+
item.gravity = imports.length;
|
|
396
|
+
|
|
397
|
+
// 反向建立 dependents
|
|
398
|
+
for (const imp of imports) {
|
|
399
|
+
const target = fileMap.get(imp);
|
|
400
|
+
if (target) target.dependents.push(item.file);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// 重新计算 gravity (出度 + 入度)
|
|
405
|
+
for (const item of feed) {
|
|
406
|
+
item.gravity = item.deps.length + item.dependents.length;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return feed.sort((a, b) => b.gravity - a.gravity);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* 输出 AI 饲料文件
|
|
414
|
+
*/
|
|
415
|
+
writeFeedFile(feed: AIFeed[], outputPath: string): void {
|
|
416
|
+
let output = `# CODEMAP AI FEED\n`;
|
|
417
|
+
output += `# Generated: ${new Date().toISOString()}\n\n`;
|
|
418
|
+
|
|
419
|
+
for (const f of feed) {
|
|
420
|
+
output += `FILE: ${f.file}\n`;
|
|
421
|
+
output += `GRAVITY: ${f.gravity} | HEAT: ${f.heat.freq30d}/${f.heat.lastType}/${f.heat.lastDate || 'never'}\n`;
|
|
422
|
+
output += `META: since=${f.meta.since || 'unknown'} stable=${f.meta.stable} why=${f.meta.why || 'none'}\n`;
|
|
423
|
+
output += `IMPACT: ${f.dependents.length} files depend on this\n`;
|
|
424
|
+
output += `DEPS: ${f.deps.join(', ') || 'none'}\n`;
|
|
425
|
+
output += `---\n`;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
fs.writeFileSync(outputPath, output);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
private scanGitHistory(filePath: string, projectRoot: string): HeatScore {
|
|
432
|
+
try {
|
|
433
|
+
const log = execSync(
|
|
434
|
+
`git log --since="30 days ago" --pretty=format:"%s" -- "${filePath}"`,
|
|
435
|
+
{ cwd: projectRoot, encoding: 'utf-8' }
|
|
436
|
+
);
|
|
437
|
+
const commits = log.split('\n').filter(Boolean);
|
|
438
|
+
|
|
439
|
+
const last = commits[0] || '';
|
|
440
|
+
const typeMatch = last.match(/^\[(\w+)\]/);
|
|
441
|
+
|
|
442
|
+
return {
|
|
443
|
+
freq30d: commits.length,
|
|
444
|
+
lastType: typeMatch ? typeMatch[1] : 'UNKNOWN',
|
|
445
|
+
lastDate: execSync(
|
|
446
|
+
`git log -1 --pretty=format:"%ci" -- "${filePath}"`,
|
|
447
|
+
{ cwd: projectRoot, encoding: 'utf-8' }
|
|
448
|
+
).split(' ')[0] || null,
|
|
449
|
+
stability: commits.length < 3 // 30天内少于3次视为稳定
|
|
450
|
+
};
|
|
451
|
+
} catch {
|
|
452
|
+
return { freq30d: 0, lastType: 'NEW', lastDate: null, stability: true };
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### 4.2 文件头注释扫描器
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
// src/orchestrator/file-header-scanner.ts
|
|
462
|
+
|
|
463
|
+
class FileHeaderScanner {
|
|
464
|
+
/**
|
|
465
|
+
* 扫描文件头注释
|
|
466
|
+
* 只读取文件前10行
|
|
467
|
+
*/
|
|
468
|
+
scan(filePath: string): FileMeta {
|
|
469
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
470
|
+
const lines = content.split('\n').slice(0, 10);
|
|
471
|
+
const header = lines.join('\n');
|
|
472
|
+
|
|
473
|
+
// 解析 [META]
|
|
474
|
+
const metaMatch = header.match(/\/\/ \[META\] (.+)/);
|
|
475
|
+
const meta: FileMeta = {};
|
|
476
|
+
|
|
477
|
+
if (metaMatch) {
|
|
478
|
+
const metaStr = metaMatch[1];
|
|
479
|
+
meta.since = metaStr.match(/since:(\S+)/)?.[1];
|
|
480
|
+
meta.owner = metaStr.match(/owner:(\S+)/)?.[1];
|
|
481
|
+
meta.stable = metaStr.includes('stable:true');
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// 解析 [WHY]
|
|
485
|
+
const whyMatch = header.match(/\/\/ \[WHY\] (.+)/);
|
|
486
|
+
if (whyMatch) {
|
|
487
|
+
meta.why = whyMatch[1].trim();
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// 解析 [DEPS]
|
|
491
|
+
const depsMatch = header.match(/\/\/ \[DEPS\] (.+)/);
|
|
492
|
+
if (depsMatch) {
|
|
493
|
+
meta.deps = depsMatch[1].split(',').map(d => d.trim());
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return meta;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* 验证文件头是否完整
|
|
501
|
+
* CI 门禁使用
|
|
502
|
+
*/
|
|
503
|
+
validate(filePath: string): { valid: boolean; missing: string[] } {
|
|
504
|
+
const meta = this.scan(filePath);
|
|
505
|
+
const missing: string[] = [];
|
|
506
|
+
|
|
507
|
+
if (!meta.since) missing.push('[META] since');
|
|
508
|
+
if (!meta.why) missing.push('[WHY]');
|
|
509
|
+
|
|
510
|
+
return { valid: missing.length === 0, missing };
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
517
|
+
## 5. 极简 Commit 格式验证 (v2.4 新增)
|
|
518
|
+
|
|
519
|
+
### 5.1 Commit Tag 正则
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
// src/orchestrator/commit-validator.ts
|
|
523
|
+
|
|
524
|
+
const COMMIT_TAG_REGEX = /^\[(BUGFIX|FEATURE|REFACTOR|CONFIG|DOCS|DELETE)\]\s*(.+?)?:(.+)$/;
|
|
525
|
+
|
|
526
|
+
const TAG_DESCRIPTIONS: Record<string, string> = {
|
|
527
|
+
'BUGFIX': '修复问题',
|
|
528
|
+
'FEATURE': '新功能',
|
|
529
|
+
'REFACTOR': '重构',
|
|
530
|
+
'CONFIG': '配置变更',
|
|
531
|
+
'DOCS': '文档',
|
|
532
|
+
'DELETE': '删除代码'
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
class CommitValidator {
|
|
536
|
+
/**
|
|
537
|
+
* 验证 commit message 格式
|
|
538
|
+
* 用于 Git Hook 和 CI
|
|
539
|
+
*/
|
|
540
|
+
validate(message: string): { valid: boolean; error?: string } {
|
|
541
|
+
const lines = message.split('\n');
|
|
542
|
+
const firstLine = lines[0].trim();
|
|
543
|
+
|
|
544
|
+
// 检查第一行格式
|
|
545
|
+
const match = firstLine.match(COMMIT_TAG_REGEX);
|
|
546
|
+
if (!match) {
|
|
547
|
+
return {
|
|
548
|
+
valid: false,
|
|
549
|
+
error: this.formatError('提交信息必须以大写标签开头')
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const [, tag, scope, subject] = match;
|
|
554
|
+
|
|
555
|
+
// 验证标签有效性
|
|
556
|
+
if (!TAG_DESCRIPTIONS[tag]) {
|
|
557
|
+
return {
|
|
558
|
+
valid: false,
|
|
559
|
+
error: `无效的标签: [${tag}]`
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// scope 不能为空(极简方案要求强制 scope)
|
|
564
|
+
if (!scope || scope.trim() === '') {
|
|
565
|
+
return {
|
|
566
|
+
valid: false,
|
|
567
|
+
error: 'scope 不能为空,格式: [TAG] scope: message'
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// subject 不能为空
|
|
572
|
+
if (!subject || subject.trim() === '') {
|
|
573
|
+
return {
|
|
574
|
+
valid: false,
|
|
575
|
+
error: '提交描述不能为空'
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
return { valid: true };
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
private formatError(msg: string): string {
|
|
583
|
+
const tags = Object.entries(TAG_DESCRIPTIONS)
|
|
584
|
+
.map(([tag, desc]) => ` [${tag}] ${desc}`)
|
|
585
|
+
.join('\n');
|
|
586
|
+
|
|
587
|
+
return `${msg}\n\n允许的格式:\n${tags}\n\n示例:\n [BUGFIX] git-analyzer: fix risk score calculation\n [FEATURE] orchestrator: add confidence scoring`;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
---
|
|
593
|
+
|
|
594
|
+
## 6. 风险评分策略 (v2.4 更新)
|
|
595
|
+
|
|
596
|
+
### 6.1 三维评估模型
|
|
597
|
+
|
|
598
|
+
> **注意**: 风险评分公式以 `../product-specs/REFACTOR_REQUIREMENTS.md` 为单一真源。
|
|
599
|
+
> 此处实现应与需求文档保持一致。
|
|
600
|
+
|
|
601
|
+
| 维度 | 指标 | 计算方式 | 权重 |
|
|
602
|
+
|------|------|----------|------|
|
|
603
|
+
| **GRAVITY** | 依赖复杂度 | (出度 + 入度) / 20 | 30% |
|
|
604
|
+
| **HEAT.freq30d** | 修改频率 | 30天修改次数 / 10 | 15% |
|
|
605
|
+
| **HEAT.lastType** | 最后提交标签 | 标签风险值 | 10% |
|
|
606
|
+
| **IMPACT** | 影响面 | 被依赖文件数 / 50 | 10% |
|
|
607
|
+
| **STABILITY** | 稳定性 | 不稳定文件比例 * 0.15 | 15% |
|
|
608
|
+
|
|
609
|
+
### 6.2 标签风险权重
|
|
610
|
+
|
|
611
|
+
| 标签 | 风险值 | 说明 |
|
|
612
|
+
|------|--------|------|
|
|
613
|
+
| BUGFIX | 0.9 | 修复过的代码 = 曾经有问题 |
|
|
614
|
+
| REFACTOR | 0.8 | 重构过的代码 = 复杂度较高 |
|
|
615
|
+
| FEATURE | 0.7 | 新功能 = 可能不稳定 |
|
|
616
|
+
| CONFIG | 0.5 | 配置变更 = 中等风险 |
|
|
617
|
+
| DOCS | 0.2 | 文档 = 低风险 |
|
|
618
|
+
| DELETE | 0.1 | 删除代码 = 极低风险 |
|
|
619
|
+
| UNKNOWN | 0.5 | 未知 = 默认中等风险 |
|
|
620
|
+
|
|
621
|
+
### 6.3 风险等级
|
|
622
|
+
|
|
623
|
+
- `high`: 综合分数 > 0.7
|
|
624
|
+
- `medium`: 综合分数 > 0.4
|
|
625
|
+
- `low`: 综合分数 ≤ 0.4
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
629
|
+
## 7. 模块依赖
|
|
630
|
+
|
|
631
|
+
```
|
|
632
|
+
Git 分析器 (git-analyzer.ts)
|
|
633
|
+
│
|
|
634
|
+
├── 依赖: execFile (子进程)
|
|
635
|
+
│
|
|
636
|
+
├── AI 饲料生成器 (ai-feed-generator.ts)
|
|
637
|
+
│ ├── 依赖: FileHeaderScanner
|
|
638
|
+
│ ├── 依赖: GitAnalyzer
|
|
639
|
+
│ └── 输出: .mycodemap/ai-feed.txt
|
|
640
|
+
│
|
|
641
|
+
├── Commit 验证器 (commit-validator.ts)
|
|
642
|
+
│ └── 用于: Git Hook / CI
|
|
643
|
+
│
|
|
644
|
+
└── 被以下模块使用:
|
|
645
|
+
└── AnalyzeCommand (analyze.ts)
|
|
646
|
+
└── CI Gateway (ci-gateway.ts)
|
|
647
|
+
└── WorkflowOrchestrator (workflow-orchestrator.ts) (v2.5 新增)
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
## 10. 工作流上下文集成 (v2.5 规划)
|
|
653
|
+
|
|
654
|
+
### 10.1 Git 历史在工作流中的角色
|
|
655
|
+
|
|
656
|
+
在工作流编排中,Git 分析器提供每个阶段的上下文信息:
|
|
657
|
+
|
|
658
|
+
```typescript
|
|
659
|
+
// 工作流阶段的 Git 分析配置
|
|
660
|
+
|
|
661
|
+
const PHASE_GIT_CONFIG: Record<WorkflowPhase, GitAnalysisConfig> = {
|
|
662
|
+
reference: {
|
|
663
|
+
// 参考搜索:查找相关提交作为参考
|
|
664
|
+
analysisType: 'find-similar-commits',
|
|
665
|
+
maxCommits: 10,
|
|
666
|
+
includeHistory: true,
|
|
667
|
+
extractPatterns: ['*.ts']
|
|
668
|
+
},
|
|
669
|
+
impact: {
|
|
670
|
+
// 影响分析:查找目标文件的修改历史
|
|
671
|
+
analysisType: 'file-history',
|
|
672
|
+
maxCommits: 20,
|
|
673
|
+
includeHistory: true,
|
|
674
|
+
extractPatterns: ['*.ts']
|
|
675
|
+
},
|
|
676
|
+
risk: {
|
|
677
|
+
// 风险评估:计算文件热度
|
|
678
|
+
analysisType: 'heat-analysis',
|
|
679
|
+
maxCommits: 30,
|
|
680
|
+
includeHistory: true,
|
|
681
|
+
timeWindow: '30d'
|
|
682
|
+
},
|
|
683
|
+
implementation: {
|
|
684
|
+
// 代码实现:记录实现意图
|
|
685
|
+
analysisType: 'none',
|
|
686
|
+
maxCommits: 0,
|
|
687
|
+
includeHistory: false
|
|
688
|
+
},
|
|
689
|
+
commit: {
|
|
690
|
+
// 提交:验证 Commit 格式
|
|
691
|
+
analysisType: 'validate-commit',
|
|
692
|
+
maxCommits: 1,
|
|
693
|
+
includeHistory: false
|
|
694
|
+
},
|
|
695
|
+
ci: {
|
|
696
|
+
// CI:完整历史分析
|
|
697
|
+
analysisType: 'full-analysis',
|
|
698
|
+
maxCommits: 50,
|
|
699
|
+
includeHistory: true
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
### 10.2 工作流 Git 分析器集成
|
|
705
|
+
|
|
706
|
+
```typescript
|
|
707
|
+
class WorkflowGitAnalyzer {
|
|
708
|
+
private analyzer: GitAnalyzer;
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* 根据当前阶段执行 Git 分析
|
|
712
|
+
*/
|
|
713
|
+
async analyzeForPhase(
|
|
714
|
+
phase: WorkflowPhase,
|
|
715
|
+
targetFiles: string[],
|
|
716
|
+
context: WorkflowContext
|
|
717
|
+
): Promise<GitAnalysisResult> {
|
|
718
|
+
const config = PHASE_GIT_CONFIG[phase];
|
|
719
|
+
|
|
720
|
+
if (config.analysisType === 'none') {
|
|
721
|
+
return { type: 'skipped', results: [] };
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// 从上下文获取历史结果(避免重复分析)
|
|
725
|
+
const cachedHistory = context.artifacts.get('impact')?.metadata?.gitHistory;
|
|
726
|
+
if (cachedHistory && phase !== 'risk') {
|
|
727
|
+
return { type: 'cached', results: cachedHistory };
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// 执行新的分析
|
|
731
|
+
switch (config.analysisType) {
|
|
732
|
+
case 'find-similar-commits':
|
|
733
|
+
return this.analyzer.findRelatedCommits(
|
|
734
|
+
context.task.split(' '),
|
|
735
|
+
targetFiles,
|
|
736
|
+
{ maxCommits: config.maxCommits, projectRoot: process.cwd() }
|
|
737
|
+
);
|
|
738
|
+
|
|
739
|
+
case 'file-history':
|
|
740
|
+
return this.analyzer.findRelatedCommits(
|
|
741
|
+
[],
|
|
742
|
+
targetFiles,
|
|
743
|
+
{ maxCommits: config.maxCommits, projectRoot: process.cwd() }
|
|
744
|
+
);
|
|
745
|
+
|
|
746
|
+
case 'heat-analysis':
|
|
747
|
+
return this.analyzer.calculateFileHeat(targetFiles);
|
|
748
|
+
|
|
749
|
+
case 'validate-commit':
|
|
750
|
+
return this.analyzer.validateCommit(context.task);
|
|
751
|
+
|
|
752
|
+
default:
|
|
753
|
+
return { type: 'none', results: [] };
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
---
|
|
760
|
+
|
|
761
|
+
## 8. 风险与缓解
|
|
762
|
+
|
|
763
|
+
| 风险 | 影响 | 缓解措施 |
|
|
764
|
+
|------|------|----------|
|
|
765
|
+
| Git 分析慢 | 大项目卡顿 | 限制提交数量 + 缓存 |
|
|
766
|
+
| git --follow 多文件问题 | 仅支持单文件 | 逐文件查询后合并 |
|
|
767
|
+
| 命令注入 | 安全漏洞 | 使用 execFile + 输入验证 |
|
|
768
|
+
| Commit 格式不兼容 | 迁移成本 | 提供 `codemap migrate` 命令批量转换 |
|
|
769
|
+
| 文件头注释遗漏 | CI 频繁失败 | `codemap generate --fix` 自动添加模板 |
|
|
770
|
+
|
|
771
|
+
---
|
|
772
|
+
|
|
773
|
+
## 9. 附录: AI 饲料示例
|
|
774
|
+
|
|
775
|
+
```text
|
|
776
|
+
# CODEMAP AI FEED
|
|
777
|
+
# Generated: 2026-02-28T19:30:00Z
|
|
778
|
+
|
|
779
|
+
FILE: src/orchestrator/git-analyzer.ts
|
|
780
|
+
GRAVITY: 15 | HEAT: 5/BUGFIX/2026-02-19
|
|
781
|
+
META: since=2024-03 stable=false why=分析Git历史,评估文件修改风险
|
|
782
|
+
IMPACT: 8 files depend on this
|
|
783
|
+
DEPS: src/types/index.ts, src/utils/exec.ts
|
|
784
|
+
---
|
|
785
|
+
FILE: src/utils/date.ts
|
|
786
|
+
GRAVITY: 0 | HEAT: 0/NEW/never
|
|
787
|
+
META: since=2023-06 stable=true why=日期工具函数,项目早期沉淀
|
|
788
|
+
IMPACT: 0 files depend on this
|
|
789
|
+
DEPS: none
|
|
790
|
+
---
|
|
791
|
+
```
|