teamai-cli 0.16.8 → 0.17.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.
@@ -0,0 +1,232 @@
1
+ # Phase 4: 质量评估与迭代优化
2
+
3
+ > 辅助工具: `scripts/validate_kb.py` — 自动校验链接完整性、anchor 覆盖率、AI 快速理解表覆盖率、双向链接、README 索引收录率
4
+
5
+ ## 五维评估模型
6
+
7
+ | 维度 | 权重 | 达标标准 |
8
+ |------|------|---------|
9
+ | **覆盖率** | 25% | ≥ 90% 核心组件有文档 |
10
+ | **深度** | 25% | ≥ 80% 代码入口可直接定位 |
11
+ | **一致性** | 20% | 0 死链接,0 矛盾描述 |
12
+ | **AI 可用性** | 20% | RAG 检索准确率 ≥ 85% |
13
+ | **时效性** | 10% | 核心文档更新滞后 ≤ 30 天 |
14
+
15
+ ## 覆盖率检查
16
+
17
+ ```
18
+ □ 每个代码仓库有对应的组件设计文档?
19
+ □ 每个核心 API 有产品-代码映射?
20
+ □ 每个数据表在某份文档中有 Schema 说明?
21
+ □ 每个 MQ Exchange/Topic/Queue 在拓扑图中标注?
22
+ □ 每个错误码在映射表中?
23
+ □ 每个配置项在配置说明中?
24
+ □ 每个定时任务在某份文档中说明?
25
+ ```
26
+
27
+ ## RAG 检索测试用例
28
+
29
+ | 测试类型 | 示例问题 | 期望命中 |
30
+ |---------|---------|---------|
31
+ | 组件定位 | "{组件名}的代码入口在哪?" | 组件设计文档 |
32
+ | 流程追踪 | "{API名}的内部调用链路?" | 产品-代码映射 |
33
+ | 约束查询 | "{操作}的批量上限?" | 规则速查表 |
34
+ | 状态查询 | "处于{状态}时可执行什么操作?" | 状态互斥规则 |
35
+ | 错误排查 | "遇到{错误码}怎么排查?" | 反模式/排障记录 |
36
+ | 代码生成 | "写一个{功能}的 Handler" | SOP + 接口契约 |
37
+ | 概念辨析 | "{A}和{B}区别?" | 产品知识文库 |
38
+
39
+ ## 增量更新触发表
40
+
41
+ | 触发条件 | 更新动作 |
42
+ |---------|---------|
43
+ | 新增代码仓库 | 生成 Type-4 组件文档 |
44
+ | API 接口变更 | 更新 Type-5 映射 + Type-6 速查表 |
45
+ | 新增产品功能 | 更新 Type-2 业务架构 + Type-8a 知识文库 |
46
+ | 线上故障 | 新增 Type-8d 排障记录 + 更新 Type-8b 反模式 |
47
+ | 架构重构 | 更新 Type-1 架构总览 + 受影响 Type-4 |
48
+ | 配置变更 | 更新对应组件文档的配置章节 |
49
+
50
+ ## 版本管理规范
51
+
52
+ 每份文档底部维护变更记录:
53
+
54
+ ```markdown
55
+ ## 📝 文档更新记录
56
+
57
+ ### vX.Y (YYYY-MM-DD)
58
+ - ✅ **新增**: {新增内容描述}
59
+ - ✅ **修复**: {修复内容描述}
60
+ - ✅ **更新**: {更新内容描述}
61
+ - ⚠️ **废弃**: {废弃内容描述}
62
+ ```
63
+
64
+ ## 常见质量问题修复
65
+
66
+ | 问题 | 修复方法 |
67
+ |------|---------|
68
+ | 死链接 | 全局 grep `](` 链接,或运行 `scripts/validate_kb.py` |
69
+ | 术语不一致 | 建立术语表全局替换 |
70
+ | 代码入口过时 | 定期与代码仓库 diff |
71
+ | 约束值过时 | 定期与产品文档交叉比对 |
72
+ | AI 检索失败 | 补充 search-anchor 关键词 |
73
+ | 文档孤岛 | 补充双向链接 |
74
+
75
+ ---
76
+
77
+ ## 完整生成流水线 Checklist
78
+
79
+ ### Phase 0 Checklist: 源材料采集
80
+
81
+ ```
82
+ □ 所有核心代码仓库已克隆
83
+ □ 产品 API 文档已采集 (接口名/入参/出参/错误码)
84
+ □ 产品使用文档已采集 (使用限制/FAQ/计费说明)
85
+ □ 数据库 Schema 已提取 (DDL/表结构)
86
+ □ 流程编排配置已提取 (workflow_config 等)
87
+ □ Proto/IDL 文件已提取
88
+ □ 错误码定义已提取
89
+ ```
90
+
91
+ ### Phase 1 Checklist: 架构逆向工程
92
+
93
+ ```
94
+ □ 代码知识图谱已构建 (节点+边)
95
+ □ 架构分层已确定 (≥4 层)
96
+ □ 组件关系矩阵已构建 (N×N)
97
+ □ 核心调用链已追踪 (≥5 条核心 API)
98
+ □ MQ 拓扑已推断 (Exchange/Topic/Queue/Routing Key)
99
+ □ 数据库 ER 模型已构建
100
+ □ 术语表已整理 (内外部映射)
101
+ ```
102
+
103
+ ### Phase 2 Checklist: 文档生成
104
+
105
+ ```
106
+ □ [Type-1] 技术架构总览文档 (1份)
107
+ □ 包含读者导航指南
108
+ □ 包含 AI 检索路由规则
109
+ □ 包含核心链路时序图 (≥5 条)
110
+ □ 包含组件关系矩阵
111
+ □ 包含 AI 专用第 9 章
112
+ □ 包含术语表
113
+
114
+ □ [Type-2] 业务架构文档 (1份)
115
+ □ 包含产品能力矩阵
116
+ □ 包含计费模型(如适用)
117
+ □ 包含核心实体生命周期状态机
118
+
119
+ □ [Type-3] 部署架构文档 (1份)
120
+ □ 包含服务部署矩阵
121
+ □ 包含环境配置
122
+
123
+ □ [Type-4] 组件设计文档 (N份)
124
+ □ 每份包含 AI 快速理解表
125
+ □ 每份包含双向链接
126
+ □ 每份包含代码入口 (精确到函数)
127
+ □ 每份包含架构图 (ASCII Art)
128
+ □ 每份包含核心流程说明
129
+
130
+ □ [Type-5] 产品-代码映射文档
131
+ □ 覆盖所有核心 API
132
+ □ 每个 API 包含约束表
133
+ □ 每个 API 包含调用链路
134
+ □ 每个 API 包含错误码映射
135
+
136
+ □ [Type-6] 产品规则速查表
137
+ □ 覆盖所有规则类别
138
+ □ 约束值精确
139
+ □ 包含状态互斥矩阵
140
+
141
+ □ [Type-7] 业务开发规范 SOP
142
+ □ 包含可运行的代码模板
143
+ □ 包含错误码对照表
144
+ □ 包含 AI 评审 CheckList
145
+
146
+ □ [Type-8] 知识增强文档
147
+ □ [8a] 产品知识文库 (概念辨析)
148
+ □ [8b] 反模式与踩坑指南
149
+ □ [8c] RPC 接口契约
150
+ □ [8d] 排障案例记录
151
+ ```
152
+
153
+ ### Phase 3 Checklist: AI-Native 增强
154
+
155
+ ```
156
+ □ 所有组件文档包含 AI 快速理解表
157
+ □ 主架构文档包含检索路由规则
158
+ □ 所有文档包含 search-anchor
159
+ □ 双向链接网络完整 (0 死链接)
160
+ □ QA 对已生成 (10~20 个)
161
+ □ 文档优先级已定义
162
+ ```
163
+
164
+ ### Phase 3b Checklist: 图谱文档集 (Graph RAG)
165
+
166
+ ```
167
+ □ [G1] 组件依赖关系矩阵
168
+ □ N×N 通信矩阵完整
169
+ □ 正向/反向依赖索引
170
+ □ 外部服务依赖
171
+
172
+ □ [G2] 组件调用链路全景 + 状态机
173
+ □ 核心 API 端到端链路 (读+写)
174
+ □ 完整 mermaid 状态机流转图
175
+ □ 核心状态字段值流转路径表(如有内部状态码)
176
+ □ 用户可见状态↔内部状态映射关系(如有多层状态)
177
+ □ 操作-状态约束速查矩阵 (✅/❌)
178
+ □ AI 状态判断推理规则
179
+
180
+ □ [G3] 数据流与存储依赖图
181
+ □ 存储系统依赖矩阵
182
+ □ MQ 队列拓扑
183
+ □ 缓存策略矩阵
184
+
185
+ □ [G4] 错误码组件映射表
186
+ □ 错误码段分配表
187
+ □ 外部→内部错误码映射
188
+
189
+ □ [G5] 跨组件交互场景手册
190
+ □ ≥10 个场景的 mermaid 时序图
191
+ □ 每个场景有异常处理
192
+
193
+ □ [G6] 知识图谱三元组
194
+ □ Ontology 定义 (实体类型+关系类型)
195
+ □ 显式三元组 ≥100 条
196
+ □ 多跳依赖路径索引
197
+ □ 反向可达索引
198
+
199
+ □ [G7] 架构风险与影响面分析
200
+ □ 组件风险等级总表
201
+ □ 爆炸半径分析 (≥3 个关键组件)
202
+ □ 聚类分析
203
+ □ 变更风险评估矩阵
204
+
205
+ □ [G8] 核心配置参数索引
206
+ □ 分层配置架构图 (mermaid)
207
+ □ 每层配置参数表 (配置项/默认值/影响行为/变更风险/生效方式)
208
+ □ 配置变更影响面速查矩阵
209
+
210
+ □ [G9] 业务规则约束矩阵
211
+ □ 操作前置条件矩阵
212
+ □ 硬件约束详表
213
+ □ 迁移约束决策树 (mermaid)
214
+ □ 计费约束详表
215
+ □ 特殊实例类型约束汇总 (✅/❌/⚠️)
216
+ □ AI 推理规则速查 (mermaid 流程图)
217
+
218
+ □ 图谱目录 README.md 索引完整
219
+ □ 按问题类型查找表
220
+ □ 检索路由规则建议
221
+ ```
222
+
223
+ ### Phase 4 Checklist: 质量评估
224
+
225
+ ```
226
+ □ 覆盖率 ≥ 90%
227
+ □ 代码入口精确度 ≥ 80%
228
+ □ 死链接 = 0 (运行 validate_kb.py 确认)
229
+ □ RAG 检索准确率 ≥ 85%
230
+ □ 核心文档更新滞后 ≤ 30 天
231
+ □ 术语一致性检查通过
232
+ ```
@@ -0,0 +1,148 @@
1
+ # 知识库总览模板
2
+
3
+ > 用于生成 `<output_dir>/README.md`,在 Phase K2 批次5 生成(知识库顶层索引)。
4
+
5
+ ```markdown
6
+ # <项目名称> — 深度知识库
7
+ <!-- search-anchor: <项目名称>, <项目英文名>, 知识库, 架构总览, 快速导航, 组件文档, Graph RAG, 图谱 -->
8
+
9
+ > **AI 读取指引**:本目录是 AI-Native 知识库。请先阅读本文件了解全局和认知边界,
10
+ > 再按检索路由规则进入对应文档查阅详情。**禁止一次性读取整个知识库目录。**
11
+
12
+ ## 🤖 知识库检索路由指引(AI 专用)
13
+
14
+ ### 按问题类型快速导航
15
+
16
+ | 我想了解… | 应该读… | 路径 |
17
+ |---------|---------|------|
18
+ | 系统整体架构和分层 | 技术架构文档 | `./{项目名} 技术架构.md` |
19
+ | 某个组件的设计和实现 | 组件设计说明 | `./XX_{组件名}设计说明.md` |
20
+ | 组件之间的依赖关系 | G1 依赖矩阵 | `./graph/G1_*.md` |
21
+ | 某个 API 经过哪些模块 | G2 调用链路全景 | `./graph/G2_*.md` |
22
+ | 数据存在哪里、MQ 拓扑 | G3 数据流 | `./graph/G3_*.md` |
23
+ | 错误码是哪个模块的 | G4 错误码映射 | `./graph/G4_*.md` |
24
+ | 某个业务场景的完整流程 | G5 交互场景手册 | `./graph/G5_*.md` |
25
+ | A 间接依赖谁(多跳查询) | G6 知识图谱三元组 | `./graph/G6_*.md` |
26
+ | X 组件挂了影响多大 | G7 风险分析 | `./graph/G7_*.md` |
27
+ | 怎么修改某个配置 | G8 配置参数索引 | `./graph/G8_*.md` |
28
+ | 某个操作能不能执行 | G9 业务规则约束 | `./graph/G9_*.md` |
29
+ | 产品约束→代码位置映射 | 核心API映射文档 | `./XX_*产品代码映射.md` |
30
+ | 业务开发 SOP | 业务开发规范 | `./XX_*业务开发规范SOP.md` |
31
+
32
+ ### 检索规则
33
+
34
+ - **规则 1 — 先读索引后深入**:遇到不确定的组件,先读本文件找到正确路径,再深入组件文档
35
+ - **规则 2 — 组件内部问题查组件文档**:核心机制、代码入口、数据模型 → `XX_{组件名}设计说明.md`
36
+ - **规则 3 — 跨组件关系问题查图谱**:依赖矩阵、调用链路、影响面 → `graph/` 目录
37
+ - **规则 4 — 操作可行性问题查 G9**:约束矩阵 + 决策树 → `graph/G9_*.md`
38
+ - **规则 5 — `[UNVERIFIED]` 标注的内容不可用于代码生成**,需先人工确认
39
+ - **规则 6 — `AMBIGUOUS` 关系不可用于变更影响评估**,需先明确
40
+
41
+ ---
42
+
43
+ ## 🚧 认知边界声明(AI 必读)
44
+
45
+ > 本节声明此知识库**不知道什么**。AI 在回答问题时,如果涉及以下范围,
46
+ > **必须主动告知用户"此信息超出知识库覆盖范围,建议查看源代码/产品文档/联系团队"**,
47
+ > 而不是尝试推断或幻觉。
48
+
49
+ ### 覆盖范围
50
+
51
+ | 维度 | 覆盖 | 说明 |
52
+ |------|------|------|
53
+ | 代码基准 | `<commit SHA>` (`<tag>`) | 此版本**之后**的变更不在覆盖范围内 |
54
+ | 生成时间 | `<YYYY-MM-DDTHH:MM:SSZ>` | 知识库与代码的时间锚点 |
55
+ | 核心组件(P0) | <P0组件列表> | 文档深度最高,接口级覆盖 |
56
+ | 重要组件(P1) | <P1组件列表> | 文档深度中等,核心机制覆盖 |
57
+ | 辅助组件(P2) | <P2组件列表> | 文档深度有限,仅架构层面 |
58
+
59
+ ### 明确不覆盖(AI 不应尝试回答)
60
+
61
+ | 领域 | 原因 |
62
+ |------|------|
63
+ | 第三方 SDK/库内部实现 | 知识库只记录调用方式,不涉及第三方源码 |
64
+ | 运维/部署细节(ansible/k8s 配置) | 超出代码知识库范围,需查阅运维文档 |
65
+ | 非代码产出(UI 设计、产品 PRD 原文) | 仅 Type-5/6 桥梁文档有产品约束映射 |
66
+ | 历史架构变迁 | 仅反映当前代码基准版本的架构 |
67
+ | 性能基准数据 | 知识库不包含压测数据 |
68
+ | <项目特定不覆盖项> | <原因> |
69
+
70
+ ### 低可信度区域(AI 回答时需额外警告)
71
+
72
+ | 区域 | 原因 | 建议 |
73
+ |------|------|------|
74
+ | P2 辅助组件的内部细节 | 文档深度有限 | 引用时加"基于有限文档分析" |
75
+ | `[UNVERIFIED]` 标注内容 | 无法回溯到代码 | 必须告知用户"此信息未经代码验证" |
76
+ | `AMBIGUOUS` 关系 | 置信度 < 0.3 | 必须告知用户"此关系存在不确定性" |
77
+ | 产品文档缺失时的 Type-5/6 | 无产品文档输入 | 标注 `[PRODUCT_DOC_MISSING]` |
78
+
79
+ ### 知识库更新说明
80
+
81
+ - **增量更新**:使用 `code-to-knowledge --update` 可仅更新变更文件对应的文档
82
+ - **全量重建**:代码发生大规模重构时建议全量重建
83
+ - **上次更新**:`<ISO8601>`
84
+
85
+ ---
86
+
87
+ ## 项目简介
88
+
89
+ <!-- 1-3 句话:项目背景、核心业务目标、主要用户 -->
90
+
91
+ ## 技术栈
92
+
93
+ | 类别 | 技术 | 说明 |
94
+ |------|------|------|
95
+ | 语言 | Go / Python | ... |
96
+ | 框架 | go-zero / FastAPI | ... |
97
+ | 数据库 | MySQL / PostgreSQL | ... |
98
+ | 缓存 | Redis | ... |
99
+ | 消息队列 | Kafka / RabbitMQ | (如有) |
100
+
101
+ ## 知识库文档索引
102
+
103
+ ### 架构层文档
104
+ | 文档 | 类型 | 规模 | 说明 |
105
+ |------|------|------|------|
106
+ | {项目名} 技术架构.md | Type-1 | ~200KB | 架构总览 |
107
+ | {项目名} 业务架构.md | Type-2 | ~70KB | 产品能力+生命周期 |
108
+ | {项目名} 部署架构.md | Type-3 | ~40KB | 部署拓扑 |
109
+
110
+ ### 组件设计文档
111
+ | 编号 | 组件 | 架构层 | 核心度 | 规模 |
112
+ |------|------|--------|--------|------|
113
+ | 01 | <组件名> | <层级> | P0 | ~NKB |
114
+
115
+ ### 桥梁文档(有产品文档时生成)
116
+ | 文档 | 类型 | 说明 |
117
+ |------|------|------|
118
+ | 核心API产品代码映射 | Type-5 | 产品约束→代码位置 |
119
+ | 产品规则速查表 | Type-6 | 使用限制/FAQ→代码 |
120
+ | 业务开发规范SOP | Type-7 | 开发/变更操作规范 |
121
+
122
+ ### 图谱文档集(Graph RAG)
123
+ | 文档 | 用途 | 规模 |
124
+ |------|------|------|
125
+ | G1~G9 | 跨组件关系索引 | 详见 `graph/README.md` |
126
+
127
+ ## 知识库质量概览
128
+
129
+ | 指标 | 数值 | 状态 |
130
+ |------|------|------|
131
+ | 文档总数 | N 份 | — |
132
+ | 内容准确率(有代码引用) | X% | ✅/⚠️ |
133
+ | [UNVERIFIED] 比例 | X% | 目标<15% |
134
+ | 接口覆盖率(非 NONE 组件) | X% | 目标≥90% |
135
+ | AMBIGUOUS 关系数 | N 条 | 需人工确认 |
136
+
137
+ > 详细质量报告见 `_review/k4-quality-report.md`
138
+
139
+ ## 代码基准版本
140
+
141
+ > ⚠️ 本知识库基于以下版本代码生成,代码演进后请运行 `code-to-knowledge --update` 增量更新。
142
+
143
+ - **Commit**:`<git commit SHA>`
144
+ - **Tag**:`<tag 或 "无 tag">`
145
+ - **生成时间**:`<YYYY-MM-DDTHH:MM:SSZ>`
146
+
147
+ > 版本信息来源:`_review/metadata.json`
148
+ ```
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ scan_repo.py — 代码仓库结构扫描与统计工具
4
+
5
+ 用途: Phase 0 源材料采集阶段,快速扫描目标仓库/目录,输出:
6
+ 1. 目录结构树(2层深度)
7
+ 2. 代码统计(语言分布、文件数、总行数)
8
+ 3. 关键文件发现(入口文件、配置文件、Proto/IDL、错误码定义)
9
+ 4. 代码热点(文件行数 Top 20)
10
+
11
+ 使用方式:
12
+ python3 scan_repo.py /path/to/repo
13
+ python3 scan_repo.py /path/to/repo --depth 3 --top 30
14
+ """
15
+
16
+ import os
17
+ import sys
18
+ import argparse
19
+ from pathlib import Path
20
+ from collections import defaultdict, Counter
21
+
22
+ # 关键文件匹配模式
23
+ KEY_FILE_PATTERNS = {
24
+ "入口文件": [
25
+ "main.py", "main.go", "app.py", "app.ts", "app.js",
26
+ "server.py", "server.go", "wsgi.py", "manage.py",
27
+ "cmd/*/main.go", "index.ts", "index.js",
28
+ ],
29
+ "路由/Handler": [
30
+ "*handler*", "*router*", "*controller*", "*dispatch*",
31
+ "*route*", "*api.*", "*endpoint*",
32
+ ],
33
+ "配置文件": [
34
+ "*.yaml", "*.yml", "*.toml", "*.ini", "*.conf",
35
+ "*config*", "*.env", "*.env.*",
36
+ ],
37
+ "Proto/IDL": [
38
+ "*.proto", "*.thrift", "*.graphql", "*schema*",
39
+ ],
40
+ "数据库/模型": [
41
+ "*model*", "*dao*", "*repository*", "*migration*",
42
+ "*schema*", "*.sql", "*db*",
43
+ ],
44
+ "常量/错误码": [
45
+ "*const*", "*constant*", "*error*", "*code*",
46
+ "*enum*", "*define*", "*exception*",
47
+ ],
48
+ "测试文件": [
49
+ "*_test.*", "test_*", "*.spec.*", "*_spec.*",
50
+ ],
51
+ }
52
+
53
+ # 语言扩展名映射
54
+ LANG_MAP = {
55
+ ".py": "Python", ".go": "Go", ".js": "JavaScript", ".ts": "TypeScript",
56
+ ".java": "Java", ".rs": "Rust", ".rb": "Ruby", ".php": "PHP",
57
+ ".c": "C", ".cpp": "C++", ".h": "C/C++ Header",
58
+ ".proto": "Protobuf", ".thrift": "Thrift", ".graphql": "GraphQL",
59
+ ".sql": "SQL", ".sh": "Shell", ".bash": "Shell",
60
+ ".yaml": "YAML", ".yml": "YAML", ".toml": "TOML",
61
+ ".json": "JSON", ".xml": "XML", ".md": "Markdown",
62
+ }
63
+
64
+ # 忽略目录
65
+ IGNORE_DIRS = {
66
+ ".git", ".svn", "node_modules", "__pycache__", ".tox", ".mypy_cache",
67
+ "venv", ".venv", "env", ".env", "vendor", "dist", "build",
68
+ ".idea", ".vscode", ".eggs", "*.egg-info",
69
+ }
70
+
71
+
72
+ def should_ignore(path: Path) -> bool:
73
+ for part in path.parts:
74
+ if part in IGNORE_DIRS or part.endswith(".egg-info"):
75
+ return True
76
+ return False
77
+
78
+
79
+ def count_lines(filepath: Path) -> int:
80
+ try:
81
+ with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
82
+ return sum(1 for _ in f)
83
+ except (OSError, UnicodeDecodeError):
84
+ return 0
85
+
86
+
87
+ def match_pattern(filename: str, pattern: str) -> bool:
88
+ """简单的通配符匹配"""
89
+ import fnmatch
90
+ return fnmatch.fnmatch(filename.lower(), pattern.lower())
91
+
92
+
93
+ def scan_repository(repo_path: Path, depth: int = 2, top_n: int = 20):
94
+ """扫描仓库,返回统计结果"""
95
+
96
+ all_files = []
97
+ lang_stats = Counter() # 语言 -> (文件数, 行数)
98
+ lang_lines = Counter()
99
+ key_files = defaultdict(list)
100
+ dir_tree = []
101
+
102
+ # 遍历文件
103
+ for root, dirs, files in os.walk(repo_path):
104
+ rel_root = Path(root).relative_to(repo_path)
105
+
106
+ # 忽略目录
107
+ dirs[:] = [d for d in dirs if d not in IGNORE_DIRS and not d.endswith(".egg-info")]
108
+
109
+ # 目录树(限制深度)
110
+ level = len(rel_root.parts)
111
+ if level <= depth:
112
+ indent = " " * level
113
+ dirname = rel_root.parts[-1] if rel_root.parts else str(repo_path.name)
114
+ dir_tree.append(f"{indent}├── {dirname}/")
115
+
116
+ for fname in files:
117
+ fpath = Path(root) / fname
118
+ if should_ignore(fpath.relative_to(repo_path)):
119
+ continue
120
+
121
+ ext = fpath.suffix.lower()
122
+ lines = count_lines(fpath)
123
+ rel_path = str(fpath.relative_to(repo_path))
124
+
125
+ all_files.append((rel_path, ext, lines))
126
+
127
+ # 语言统计
128
+ lang = LANG_MAP.get(ext)
129
+ if lang:
130
+ lang_stats[lang] += 1
131
+ lang_lines[lang] += lines
132
+
133
+ # 关键文件匹配
134
+ for category, patterns in KEY_FILE_PATTERNS.items():
135
+ for pattern in patterns:
136
+ if match_pattern(fname, pattern):
137
+ key_files[category].append((rel_path, lines))
138
+ break
139
+
140
+ return all_files, lang_stats, lang_lines, key_files, dir_tree
141
+
142
+
143
+ def print_report(repo_path: Path, all_files, lang_stats, lang_lines, key_files, dir_tree, top_n: int):
144
+ """输出扫描报告"""
145
+
146
+ total_files = len(all_files)
147
+ total_lines = sum(f[2] for f in all_files)
148
+
149
+ print("=" * 70)
150
+ print(f" 代码仓库扫描报告: {repo_path.name}")
151
+ print(f" 路径: {repo_path}")
152
+ print("=" * 70)
153
+
154
+ # 1. 基本统计
155
+ print(f"\n## 1. 基本统计\n")
156
+ print(f"| 指标 | 数值 |")
157
+ print(f"|------|------|")
158
+ print(f"| 总文件数 | {total_files} |")
159
+ print(f"| 总代码行数 | {total_lines:,} |")
160
+ print(f"| 语言种类 | {len(lang_stats)} |")
161
+
162
+ # 2. 语言分布
163
+ print(f"\n## 2. 语言分布\n")
164
+ print(f"| 语言 | 文件数 | 代码行数 | 占比 |")
165
+ print(f"|------|--------|---------|------|")
166
+ for lang, count in lang_stats.most_common(15):
167
+ lines = lang_lines[lang]
168
+ pct = f"{lines / total_lines * 100:.1f}%" if total_lines > 0 else "0%"
169
+ print(f"| {lang} | {count} | {lines:,} | {pct} |")
170
+
171
+ # 3. 目录结构
172
+ print(f"\n## 3. 目录结构(前 30 行)\n")
173
+ print("```")
174
+ for line in dir_tree[:30]:
175
+ print(line)
176
+ if len(dir_tree) > 30:
177
+ print(f" ... ({len(dir_tree) - 30} more directories)")
178
+ print("```")
179
+
180
+ # 4. 关键文件发现
181
+ print(f"\n## 4. 关键文件发现\n")
182
+ for category, files in key_files.items():
183
+ if files:
184
+ print(f"\n### {category} ({len(files)} 个)\n")
185
+ # 去重并排序
186
+ seen = set()
187
+ for fpath, lines in sorted(files, key=lambda x: -x[1])[:10]:
188
+ if fpath not in seen:
189
+ seen.add(fpath)
190
+ print(f"- `{fpath}` ({lines:,} 行)")
191
+
192
+ # 5. 代码热点
193
+ print(f"\n## 5. 代码热点 (Top {top_n})\n")
194
+ print(f"| 排名 | 文件 | 行数 |")
195
+ print(f"|------|------|------|")
196
+ sorted_files = sorted(all_files, key=lambda x: -x[2])
197
+ for i, (fpath, ext, lines) in enumerate(sorted_files[:top_n], 1):
198
+ print(f"| {i} | `{fpath}` | {lines:,} |")
199
+
200
+ print(f"\n{'=' * 70}")
201
+ print(f" 扫描完成。共 {total_files} 个文件,{total_lines:,} 行代码。")
202
+ print(f"{'=' * 70}")
203
+
204
+
205
+ def main():
206
+ parser = argparse.ArgumentParser(description="代码仓库结构扫描与统计工具")
207
+ parser.add_argument("repo_path", help="要扫描的仓库/目录路径")
208
+ parser.add_argument("--depth", type=int, default=2, help="目录树深度 (默认 2)")
209
+ parser.add_argument("--top", type=int, default=20, help="代码热点 Top N (默认 20)")
210
+ args = parser.parse_args()
211
+
212
+ repo_path = Path(args.repo_path).resolve()
213
+ if not repo_path.is_dir():
214
+ print(f"错误: {repo_path} 不是有效目录", file=sys.stderr)
215
+ sys.exit(1)
216
+
217
+ all_files, lang_stats, lang_lines, key_files, dir_tree = scan_repository(
218
+ repo_path, depth=args.depth, top_n=args.top
219
+ )
220
+ print_report(repo_path, all_files, lang_stats, lang_lines, key_files, dir_tree, args.top)
221
+
222
+
223
+ if __name__ == "__main__":
224
+ main()