@mycodemap/mycodemap 0.2.0 → 0.3.4

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.
Files changed (99) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/dist/cli/commands/ship/analyzer.d.ts +26 -0
  3. package/dist/cli/commands/ship/analyzer.d.ts.map +1 -0
  4. package/dist/cli/commands/ship/analyzer.js +143 -0
  5. package/dist/cli/commands/ship/analyzer.js.map +1 -0
  6. package/dist/cli/commands/ship/checker.d.ts +20 -0
  7. package/dist/cli/commands/ship/checker.d.ts.map +1 -0
  8. package/dist/cli/commands/ship/checker.js +86 -0
  9. package/dist/cli/commands/ship/checker.js.map +1 -0
  10. package/dist/cli/commands/ship/index.d.ts +17 -0
  11. package/dist/cli/commands/ship/index.d.ts.map +1 -0
  12. package/dist/cli/commands/ship/index.js +51 -0
  13. package/dist/cli/commands/ship/index.js.map +1 -0
  14. package/dist/cli/commands/ship/monitor.d.ts +19 -0
  15. package/dist/cli/commands/ship/monitor.d.ts.map +1 -0
  16. package/dist/cli/commands/ship/monitor.js +105 -0
  17. package/dist/cli/commands/ship/monitor.js.map +1 -0
  18. package/dist/cli/commands/ship/pipeline.d.ts +23 -0
  19. package/dist/cli/commands/ship/pipeline.d.ts.map +1 -0
  20. package/dist/cli/commands/ship/pipeline.js +146 -0
  21. package/dist/cli/commands/ship/pipeline.js.map +1 -0
  22. package/dist/cli/commands/ship/publisher.d.ts +11 -0
  23. package/dist/cli/commands/ship/publisher.d.ts.map +1 -0
  24. package/dist/cli/commands/ship/publisher.js +75 -0
  25. package/dist/cli/commands/ship/publisher.js.map +1 -0
  26. package/dist/cli/commands/ship/rules/confidence-rules.d.ts +48 -0
  27. package/dist/cli/commands/ship/rules/confidence-rules.d.ts.map +1 -0
  28. package/dist/cli/commands/ship/rules/confidence-rules.js +122 -0
  29. package/dist/cli/commands/ship/rules/confidence-rules.js.map +1 -0
  30. package/dist/cli/commands/ship/rules/quality-rules.d.ts +25 -0
  31. package/dist/cli/commands/ship/rules/quality-rules.d.ts.map +1 -0
  32. package/dist/cli/commands/ship/rules/quality-rules.js +134 -0
  33. package/dist/cli/commands/ship/rules/quality-rules.js.map +1 -0
  34. package/dist/cli/commands/ship/rules/version-rules.d.ts +24 -0
  35. package/dist/cli/commands/ship/rules/version-rules.d.ts.map +1 -0
  36. package/dist/cli/commands/ship/rules/version-rules.js +75 -0
  37. package/dist/cli/commands/ship/rules/version-rules.js.map +1 -0
  38. package/dist/cli/commands/ship/versioner.d.ts +12 -0
  39. package/dist/cli/commands/ship/versioner.d.ts.map +1 -0
  40. package/dist/cli/commands/ship/versioner.js +92 -0
  41. package/dist/cli/commands/ship/versioner.js.map +1 -0
  42. package/dist/cli/index.js +9 -0
  43. package/dist/cli/index.js.map +1 -1
  44. package/docs/PUBLISHING.md +344 -34
  45. package/docs/ai-guide/COMMANDS.md +34 -0
  46. package/docs/rules/pre-release-checklist.md +426 -0
  47. package/package.json +8 -2
  48. package/scripts/.githooks/commit-msg +31 -0
  49. package/scripts/.githooks/pre-commit +55 -0
  50. package/scripts/benchmark.ts +209 -0
  51. package/scripts/hooks/commit-msg +24 -0
  52. package/scripts/hooks/install-hooks.sh +29 -0
  53. package/scripts/hooks/pre-commit +60 -0
  54. package/scripts/pre-release-check.js +717 -0
  55. package/scripts/release.sh +142 -0
  56. package/scripts/run-benchmark.sh +29 -0
  57. package/scripts/validate-ai-docs.js +294 -0
  58. package/scripts/validate-docs.js +238 -0
  59. package/scripts/validate-pack.js +86 -0
  60. package/dist/ai/claude.d.ts +0 -38
  61. package/dist/ai/claude.d.ts.map +0 -1
  62. package/dist/ai/claude.js +0 -169
  63. package/dist/ai/claude.js.map +0 -1
  64. package/dist/ai/codex.d.ts +0 -38
  65. package/dist/ai/codex.d.ts.map +0 -1
  66. package/dist/ai/codex.js +0 -169
  67. package/dist/ai/codex.js.map +0 -1
  68. package/dist/ai/factory.d.ts +0 -48
  69. package/dist/ai/factory.d.ts.map +0 -1
  70. package/dist/ai/factory.js +0 -95
  71. package/dist/ai/factory.js.map +0 -1
  72. package/dist/ai/index.d.ts +0 -12
  73. package/dist/ai/index.d.ts.map +0 -1
  74. package/dist/ai/index.js +0 -29
  75. package/dist/ai/index.js.map +0 -1
  76. package/dist/ai/provider.d.ts +0 -70
  77. package/dist/ai/provider.d.ts.map +0 -1
  78. package/dist/ai/provider.js +0 -31
  79. package/dist/ai/provider.js.map +0 -1
  80. package/dist/ai/subagent-caller.d.ts +0 -90
  81. package/dist/ai/subagent-caller.d.ts.map +0 -1
  82. package/dist/ai/subagent-caller.js +0 -280
  83. package/dist/ai/subagent-caller.js.map +0 -1
  84. package/dist/ai/types.d.ts +0 -70
  85. package/dist/ai/types.d.ts.map +0 -1
  86. package/dist/ai/types.js +0 -5
  87. package/dist/ai/types.js.map +0 -1
  88. package/dist/generator/ai-overview.d.ts +0 -51
  89. package/dist/generator/ai-overview.d.ts.map +0 -1
  90. package/dist/generator/ai-overview.js +0 -160
  91. package/dist/generator/ai-overview.js.map +0 -1
  92. package/dist/orchestrator/ai-feed-generator.d.ts +0 -210
  93. package/dist/orchestrator/ai-feed-generator.d.ts.map +0 -1
  94. package/dist/orchestrator/ai-feed-generator.js +0 -377
  95. package/dist/orchestrator/ai-feed-generator.js.map +0 -1
  96. package/docs/archive/test-report-symbol-search.md +0 -384
  97. package/docs/archive/test-scenario-4-complexity-analysis.md +0 -460
  98. package/docs/archive/test_report_scenario5.md +0 -615
  99. package/docs/archive/test_scenario_3_impact_analysis_report.md +0 -520
@@ -0,0 +1,142 @@
1
+ #!/bin/bash
2
+ # [META] since:2026-03 | owner:release-team | stable:true
3
+ # [WHY] 发布助手脚本 - 简化版本发布流程
4
+
5
+ set -e
6
+
7
+ # 颜色定义
8
+ RED='\033[0;31m'
9
+ GREEN='\033[0;32m'
10
+ YELLOW='\033[1;33m'
11
+ BLUE='\033[0;34m'
12
+ NC='\033[0m' # No Color
13
+
14
+ # 帮助信息
15
+ show_help() {
16
+ echo "用法: ./scripts/release.sh [选项]"
17
+ echo ""
18
+ echo "选项:"
19
+ echo " patch 发布 patch 版本 (0.2.0 -> 0.2.1)"
20
+ echo " minor 发布 minor 版本 (0.2.0 -> 0.3.0)"
21
+ echo " major 发布 major 版本 (0.2.0 -> 1.0.0)"
22
+ echo " <版本> 指定具体版本号 (例如: 0.2.1)"
23
+ echo " --help 显示此帮助信息"
24
+ echo ""
25
+ echo "示例:"
26
+ echo " ./scripts/release.sh patch # 发布 patch 版本"
27
+ echo " ./scripts/release.sh 0.3.0 # 发布指定版本"
28
+ }
29
+
30
+ # 检查参数
31
+ if [ $# -eq 0 ] || [ "$1" == "--help" ]; then
32
+ show_help
33
+ exit 0
34
+ fi
35
+
36
+ VERSION_TYPE=$1
37
+
38
+ # 检查是否在 git 仓库中
39
+ if ! git rev-parse --git-dir > /dev/null 2>&1; then
40
+ echo -e "${RED}❌ 错误: 当前目录不是 git 仓库${NC}"
41
+ exit 1
42
+ fi
43
+
44
+ # 检查工作区是否干净
45
+ if [ -n "$(git status --porcelain)" ]; then
46
+ echo -e "${YELLOW}⚠️ 警告: 工作区有未提交的修改${NC}"
47
+ git status --short
48
+ echo ""
49
+ read -p "是否继续? (y/N): " confirm
50
+ if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
51
+ echo -e "${RED}❌ 发布已取消${NC}"
52
+ exit 1
53
+ fi
54
+ echo ""
55
+ fi
56
+
57
+ # 获取当前版本
58
+ CURRENT_VERSION=$(node -p "require('./package.json').version")
59
+ echo -e "${BLUE}📦 当前版本: $CURRENT_VERSION${NC}"
60
+
61
+ # 计算新版本
62
+ case $VERSION_TYPE in
63
+ patch)
64
+ NEW_VERSION=$(npm version patch --no-git-tag-version)
65
+ NEW_VERSION=${NEW_VERSION#v}
66
+ ;;
67
+ minor)
68
+ NEW_VERSION=$(npm version minor --no-git-tag-version)
69
+ NEW_VERSION=${NEW_VERSION#v}
70
+ ;;
71
+ major)
72
+ NEW_VERSION=$(npm version major --no-git-tag-version)
73
+ NEW_VERSION=${NEW_VERSION#v}
74
+ ;;
75
+ *)
76
+ # 验证版本号格式
77
+ if ! echo "$VERSION_TYPE" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' > /dev/null; then
78
+ echo -e "${RED}❌ 错误: 无效的版本号格式: $VERSION_TYPE${NC}"
79
+ echo "版本号必须符合 semver 格式,例如: 0.2.1, 1.0.0"
80
+ exit 1
81
+ fi
82
+ NEW_VERSION=$VERSION_TYPE
83
+ npm version $NEW_VERSION --no-git-tag-version --allow-same-version 2>/dev/null || true
84
+ ;;
85
+ esac
86
+
87
+ echo -e "${GREEN}🚀 新版本: $NEW_VERSION${NC}"
88
+ echo ""
89
+
90
+ # 确认发布
91
+ read -p "确认发布 v$NEW_VERSION? (y/N): " confirm
92
+ if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
93
+ # 恢复 package.json
94
+ git checkout package.json package-lock.json 2>/dev/null || true
95
+ echo -e "${RED}❌ 发布已取消${NC}"
96
+ exit 1
97
+ fi
98
+
99
+ echo ""
100
+ echo -e "${BLUE}📋 发布步骤:${NC}"
101
+ echo ""
102
+
103
+ # 步骤 1: 运行检查
104
+ echo -e "${BLUE}1/5 运行代码检查...${NC}"
105
+ npm run check:all
106
+ echo -e "${GREEN} ✅ 检查通过${NC}"
107
+ echo ""
108
+
109
+ # 步骤 2: 提交版本更新
110
+ echo -e "${BLUE}2/5 提交版本更新...${NC}"
111
+ git add package.json package-lock.json
112
+ git commit -m "[RELEASE] bump version to v$NEW_VERSION"
113
+ echo -e "${GREEN} ✅ 已提交版本更新${NC}"
114
+ echo ""
115
+
116
+ # 步骤 3: 创建标签
117
+ echo -e "${BLUE}3/5 创建 git tag...${NC}"
118
+ git tag -a "v$NEW_VERSION" -m "Release v$NEW_VERSION"
119
+ echo -e "${GREEN} ✅ 已创建标签: v$NEW_VERSION${NC}"
120
+ echo ""
121
+
122
+ # 步骤 4: 推送
123
+ echo -e "${BLUE}4/5 推送到远程仓库...${NC}"
124
+ git push origin HEAD
125
+ git push origin "v$NEW_VERSION"
126
+ echo -e "${GREEN} ✅ 已推送到远程${NC}"
127
+ echo ""
128
+
129
+ # 步骤 5: 完成
130
+ echo -e "${GREEN}5/5 🎉 发布流程已触发!${NC}"
131
+ echo ""
132
+ echo -e "${BLUE}GitHub Actions 将会自动:${NC}"
133
+ echo " • 构建项目"
134
+ echo " • 运行测试"
135
+ echo " • 发布到 NPM"
136
+ echo " • 创建 GitHub Release"
137
+ echo ""
138
+ echo -e "${BLUE}查看发布状态:${NC}"
139
+ echo " https://github.com/$(git remote get-url origin | sed 's/.*github.com[:/]//;s/.git$//')/actions"
140
+ echo ""
141
+ echo -e "${BLUE}NPM 包页面:${NC}"
142
+ echo " https://www.npmjs.com/package/@mycodemap/mycodemap"
@@ -0,0 +1,29 @@
1
+ #!/bin/bash
2
+ # [META] CodeMap 基准测试运行脚本
3
+ # [WHY] 基准测试运行时间长,需要单独执行而非包含在常规测试中
4
+
5
+ set -e
6
+
7
+ echo "==================================="
8
+ echo "CodeMap 基准测试"
9
+ echo "==================================="
10
+ echo ""
11
+ echo "注意:此测试运行 30 个查询,每个查询最多 5 秒"
12
+ echo "预计总时间:30 秒 - 2 分钟"
13
+ echo ""
14
+
15
+ # 确保已构建
16
+ echo "[1/2] 检查构建状态..."
17
+ if [ ! -d "dist" ]; then
18
+ echo " 需要构建项目..."
19
+ npm run build
20
+ fi
21
+
22
+ # 运行基准测试
23
+ echo "[2/2] 运行基准测试..."
24
+ npx vitest run --config vitest.benchmark.config.ts "$@"
25
+
26
+ echo ""
27
+ echo "==================================="
28
+ echo "基准测试完成"
29
+ echo "==================================="
@@ -0,0 +1,294 @@
1
+ // [META] since:2026-03-22 | owner:docs-team | stable:true
2
+ // [WHY] 验证 AI 友好文档的完整性和合规性
3
+
4
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ const rootDir = path.resolve(__dirname, '..');
10
+
11
+ // AI 文档清单
12
+ const requiredAIDocs = [
13
+ { file: 'llms.txt', minLength: 50 }, // 标准 llms.txt 格式
14
+ { file: 'AI_GUIDE.md', minLength: 100 },
15
+ { file: 'AI_DISCOVERY.md', minLength: 100 },
16
+ { file: 'ai-document-index.yaml', minLength: 50 },
17
+ { file: 'docs/ai-guide/README.md', minLength: 50 },
18
+ { file: 'docs/ai-guide/QUICKSTART.md', minLength: 50 },
19
+ { file: 'docs/ai-guide/COMMANDS.md', minLength: 100 },
20
+ { file: 'docs/ai-guide/OUTPUT.md', minLength: 100 },
21
+ { file: 'docs/ai-guide/PATTERNS.md', minLength: 100 },
22
+ { file: 'docs/ai-guide/PROMPTS.md', minLength: 100 },
23
+ { file: 'docs/ai-guide/INTEGRATION.md', minLength: 100 },
24
+ ];
25
+
26
+ // IDE 特定的可选文档
27
+ const optionalIDEFiles = [
28
+ { file: '.cursorrules', description: 'Cursor IDE rules' },
29
+ { file: '.github/copilot-instructions.md', description: 'GitHub Copilot instructions' },
30
+ ];
31
+
32
+ // AI 友好性检查清单
33
+ // 注意:不是所有文档都需要所有检查项
34
+ const aiFriendlyChecks = [
35
+ { pattern: /^##+\s+/m, name: '层级标题(##)', requiredFor: 'all' },
36
+ { pattern: /\|.*\|.*\|/, name: '表格(速查表)', requiredFor: 'all' },
37
+ { pattern: /```(bash|typescript|json|python)/, name: '可执行代码块', requiredFor: ['AI_GUIDE.md', 'QUICKSTART.md', 'COMMANDS.md', 'PATTERNS.md', 'PROMPTS.md', 'INTEGRATION.md'] },
38
+ { pattern: /interface\s+\w+|type\s+\w+|function\s+\w+/, name: '代码定义', requiredFor: ['OUTPUT.md', 'PATTERNS.md', 'INTEGRATION.md'] },
39
+ { pattern: /决策树|流程图|速查表|提示词|模板|模式|示例/, name: 'AI 友好关键词', requiredFor: 'all' },
40
+ ];
41
+
42
+ function readText(filePath) {
43
+ const absolutePath = path.join(rootDir, filePath);
44
+ if (!existsSync(absolutePath)) {
45
+ return null;
46
+ }
47
+ return readFileSync(absolutePath, 'utf8');
48
+ }
49
+
50
+ function checkRequiredDocs(failures) {
51
+ console.log('Checking required AI documents...\n');
52
+
53
+ for (const { file, minLength } of requiredAIDocs) {
54
+ const content = readText(file);
55
+
56
+ if (!content) {
57
+ failures.push(`Missing required AI doc: ${file}`);
58
+ continue;
59
+ }
60
+
61
+ const lines = content.split('\n').length;
62
+ if (lines < minLength) {
63
+ failures.push(`${file} is too short (${lines} lines, min ${minLength})`);
64
+ }
65
+
66
+ console.log(` ✅ ${file} (${lines} lines)`);
67
+ }
68
+
69
+ // 检查可选 IDE 文件
70
+ console.log('\nChecking optional IDE-specific files...\n');
71
+ for (const { file, description } of optionalIDEFiles) {
72
+ const content = readText(file);
73
+ if (content) {
74
+ const lines = content.split('\n').length;
75
+ console.log(` ✅ ${file} (${lines} lines) - ${description}`);
76
+ } else {
77
+ console.log(` ⚠️ ${file} - ${description} (optional, not found)`);
78
+ }
79
+ }
80
+ }
81
+
82
+ function checkAIFriendliness(failures) {
83
+ console.log('\nChecking AI friendliness...\n');
84
+
85
+ const aiDocs = requiredAIDocs.map(d => d.file);
86
+
87
+ for (const doc of aiDocs) {
88
+ const content = readText(doc);
89
+ if (!content) continue;
90
+
91
+ const docName = path.basename(doc);
92
+ const docFailures = [];
93
+
94
+ // llms.txt 文件检查标准格式
95
+ if (doc === 'llms.txt') {
96
+ // 检查 llms.txt 标准结构 (支持中英文)
97
+ const hasH1 = /^#\s+\w+/m.test(content);
98
+ const hasSummary = /^>\s+/m.test(content);
99
+ const hasDocsSection = /##\s*(?:文档|Docs|快速开始|Quick Start)/i.test(content);
100
+
101
+ if (!hasH1) docFailures.push('missing H1 title (llms.txt standard)');
102
+ if (!hasSummary) docFailures.push('missing blockquote summary (llms.txt standard)');
103
+ if (!hasDocsSection) docFailures.push('missing ## Docs/文档 section (llms.txt standard)');
104
+
105
+ if (docFailures.length > 0) {
106
+ failures.push(`${doc}: ${docFailures.join(', ')}`);
107
+ console.log(` ❌ ${doc}`);
108
+ docFailures.forEach(f => console.log(` - ${f}`));
109
+ } else {
110
+ console.log(` ✅ ${doc} (llms.txt standard format)`);
111
+ }
112
+ continue;
113
+ }
114
+
115
+ // YAML 文件有独立的检查标准
116
+ if (doc.endsWith('.yaml') || doc.endsWith('.yml')) {
117
+ // 检查 YAML 基本结构
118
+ if (!content.includes('project:') || !content.includes('documentation:')) {
119
+ docFailures.push('missing required YAML structure');
120
+ }
121
+ if (docFailures.length > 0) {
122
+ failures.push(`${doc}: ${docFailures.join(', ')}`);
123
+ console.log(` ❌ ${doc}`);
124
+ docFailures.forEach(f => console.log(` - ${f}`));
125
+ } else {
126
+ console.log(` ✅ ${doc} (YAML format)`);
127
+ }
128
+ continue;
129
+ }
130
+
131
+ for (const { pattern, name, requiredFor } of aiFriendlyChecks) {
132
+ // 检查此文档是否需要此项
133
+ const isRequired = requiredFor === 'all' ||
134
+ (Array.isArray(requiredFor) && requiredFor.includes(docName));
135
+
136
+ if (!isRequired) continue;
137
+
138
+ if (!pattern.test(content)) {
139
+ docFailures.push(`missing ${name}`);
140
+ }
141
+ }
142
+
143
+ if (docFailures.length > 0) {
144
+ failures.push(`${doc}: ${docFailures.join(', ')}`);
145
+ console.log(` ❌ ${doc}`);
146
+ docFailures.forEach(f => console.log(` - ${f}`));
147
+ } else {
148
+ console.log(` ✅ ${doc}`);
149
+ }
150
+ }
151
+ }
152
+
153
+ function checkCrossReferences(failures) {
154
+ console.log('\nChecking cross-references...\n');
155
+
156
+ // README.md 必须链接到 AI_GUIDE.md
157
+ const readme = readText('README.md');
158
+ if (readme) {
159
+ if (!readme.includes('AI_GUIDE.md')) {
160
+ failures.push('README.md must reference AI_GUIDE.md');
161
+ console.log(' ❌ README.md missing AI_GUIDE.md link');
162
+ } else {
163
+ console.log(' ✅ README.md links to AI_GUIDE.md');
164
+ }
165
+ }
166
+
167
+ // AGENTS.md 必须包含 AI 文档规范
168
+ const agents = readText('AGENTS.md');
169
+ if (agents) {
170
+ if (!agents.includes('AI 友好')) {
171
+ failures.push('AGENTS.md must contain AI-friendly doc requirements');
172
+ console.log(' ❌ AGENTS.md missing AI-friendly requirements');
173
+ } else {
174
+ console.log(' ✅ AGENTS.md contains AI-friendly requirements');
175
+ }
176
+ }
177
+
178
+ // CLAUDE.md 必须链接到 AI 文档
179
+ const claude = readText('CLAUDE.md');
180
+ if (claude) {
181
+ if (!claude.includes('AI_GUIDE.md') || !claude.includes('docs/ai-guide/')) {
182
+ failures.push('CLAUDE.md must reference AI docs');
183
+ console.log(' ❌ CLAUDE.md missing AI docs references');
184
+ } else {
185
+ console.log(' ✅ CLAUDE.md links to AI docs');
186
+ }
187
+ }
188
+
189
+ // AI_GUIDE.md 必须链接到 AI_DISCOVERY.md 和 ai-document-index.yaml
190
+ const aiGuide = readText('AI_GUIDE.md');
191
+ if (aiGuide) {
192
+ if (!aiGuide.includes('AI_DISCOVERY.md')) {
193
+ failures.push('AI_GUIDE.md must reference AI_DISCOVERY.md');
194
+ console.log(' ❌ AI_GUIDE.md missing AI_DISCOVERY.md link');
195
+ } else {
196
+ console.log(' ✅ AI_GUIDE.md links to AI_DISCOVERY.md');
197
+ }
198
+
199
+ if (!aiGuide.includes('ai-document-index.yaml')) {
200
+ failures.push('AI_GUIDE.md must reference ai-document-index.yaml');
201
+ console.log(' ❌ AI_GUIDE.md missing ai-document-index.yaml link');
202
+ } else {
203
+ console.log(' ✅ AI_GUIDE.md links to ai-document-index.yaml');
204
+ }
205
+ }
206
+
207
+ // llms.txt 必须链接到主要 AI 文档
208
+ const llmsTxt = readText('llms.txt');
209
+ if (llmsTxt) {
210
+ const requiredLinks = ['AI_GUIDE.md', 'ai-document-index.yaml'];
211
+ const missingLinks = requiredLinks.filter(link => !llmsTxt.includes(link));
212
+
213
+ if (missingLinks.length > 0) {
214
+ failures.push(`llms.txt must reference: ${missingLinks.join(', ')}`);
215
+ console.log(` ❌ llms.txt missing links: ${missingLinks.join(', ')}`);
216
+ } else {
217
+ console.log(' ✅ llms.txt links to AI_GUIDE.md and ai-document-index.yaml');
218
+ }
219
+ }
220
+ }
221
+
222
+ function checkPromptsLibrary(failures) {
223
+ console.log('\nChecking prompts library...\n');
224
+
225
+ const promptsFile = readText('docs/ai-guide/PROMPTS.md');
226
+ if (!promptsFile) {
227
+ failures.push('PROMPTS.md is required for AI prompts library');
228
+ return;
229
+ }
230
+
231
+ // 检查是否包含常见的提示词模板
232
+ const requiredPrompts = [
233
+ { pattern: /项目理解|理解项目/, name: '项目理解模板' },
234
+ { pattern: /变更影响|影响分析/, name: '变更影响分析模板' },
235
+ { pattern: /代码搜索|查找.*代码/, name: '代码搜索模板' },
236
+ { pattern: /重构|refactor/i, name: '重构评估模板' },
237
+ ];
238
+
239
+ for (const { pattern, name } of requiredPrompts) {
240
+ if (!pattern.test(promptsFile)) {
241
+ failures.push(`PROMPTS.md missing: ${name}`);
242
+ console.log(` ❌ Missing: ${name}`);
243
+ } else {
244
+ console.log(` ✅ Has: ${name}`);
245
+ }
246
+ }
247
+ }
248
+
249
+ function checkDecisionTrees(failures) {
250
+ console.log('\nChecking decision trees...\n');
251
+
252
+ const quickstart = readText('docs/ai-guide/QUICKSTART.md');
253
+ if (quickstart) {
254
+ // 检查是否有决策树(流程图或层级结构)
255
+ const hasDecisionTree = /开始.*\n.*↓\n|决策树|流程图/.test(quickstart);
256
+
257
+ if (!hasDecisionTree) {
258
+ failures.push('QUICKSTART.md must contain decision tree');
259
+ console.log(' ❌ QUICKSTART.md missing decision tree');
260
+ } else {
261
+ console.log(' ✅ QUICKSTART.md has decision tree');
262
+ }
263
+ }
264
+ }
265
+
266
+ function validateAIDocs() {
267
+ console.log('========================================');
268
+ console.log('AI Documentation Guardrails Check');
269
+ console.log('========================================\n');
270
+
271
+ const failures = [];
272
+
273
+ checkRequiredDocs(failures);
274
+ checkAIFriendliness(failures);
275
+ checkCrossReferences(failures);
276
+ checkPromptsLibrary(failures);
277
+ checkDecisionTrees(failures);
278
+
279
+ console.log('\n========================================');
280
+
281
+ if (failures.length > 0) {
282
+ console.error('\n❌ AI documentation guardrails failed:\n');
283
+ for (const failure of failures) {
284
+ console.error(` - ${failure}`);
285
+ }
286
+ console.log('\n========================================');
287
+ process.exit(1);
288
+ }
289
+
290
+ console.log('\n✅ All AI documentation guardrails passed!\n');
291
+ console.log('========================================');
292
+ }
293
+
294
+ validateAIDocs();
@@ -0,0 +1,238 @@
1
+ // [META] since:2026-03 | owner:docs-team | stable:true
2
+ // [WHY] Validate high-signal documentation facts against the current repository guardrails
3
+
4
+ import { existsSync, readFileSync } from 'node:fs';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ const defaultRootDir = path.resolve(__dirname, '..');
10
+
11
+ function parseRootDir(argv) {
12
+ const rootFlagIndex = argv.indexOf('--root');
13
+ if (rootFlagIndex === -1) {
14
+ return defaultRootDir;
15
+ }
16
+
17
+ const rootValue = argv[rootFlagIndex + 1];
18
+ if (!rootValue) {
19
+ console.error('ERROR: --root requires a directory path');
20
+ process.exit(1);
21
+ }
22
+
23
+ return path.resolve(rootValue);
24
+ }
25
+
26
+ function readText(rootDir, relativePath, failures) {
27
+ const absolutePath = path.join(rootDir, relativePath);
28
+ if (!existsSync(absolutePath)) {
29
+ failures.push(`Missing required file: ${relativePath}`);
30
+ return '';
31
+ }
32
+
33
+ return readFileSync(absolutePath, 'utf8');
34
+ }
35
+
36
+ function expectIncludes(text, snippet, label, failures) {
37
+ if (!text.includes(snippet)) {
38
+ failures.push(`${label} is missing expected snippet: ${snippet}`);
39
+ }
40
+ }
41
+
42
+ function expectNotIncludes(text, snippet, label, failures) {
43
+ if (text.includes(snippet)) {
44
+ failures.push(`${label} still contains outdated snippet: ${snippet}`);
45
+ }
46
+ }
47
+
48
+ function validatePackageScripts(rootDir, failures) {
49
+ const packageJsonText = readText(rootDir, 'package.json', failures);
50
+ if (!packageJsonText) {
51
+ return;
52
+ }
53
+
54
+ let packageJson;
55
+ try {
56
+ packageJson = JSON.parse(packageJsonText);
57
+ } catch {
58
+ failures.push('package.json is not valid JSON');
59
+ return;
60
+ }
61
+
62
+ const docsCheck = packageJson.scripts?.['docs:check'];
63
+ if (!docsCheck || !docsCheck.includes('validate-docs.js')) {
64
+ failures.push('package.json scripts.docs:check must include "validate-docs.js"');
65
+ }
66
+ }
67
+
68
+ function validateAnalyzeDocs(rootDir, failures) {
69
+ const readme = readText(rootDir, 'README.md', failures);
70
+ const cliSource = readText(rootDir, 'src/cli/index.ts', failures);
71
+
72
+ if (!readme || !cliSource) {
73
+ return;
74
+ }
75
+
76
+ const requiredCliSnippets = [
77
+ ".option('-i, --intent <type>'",
78
+ ".option('-t, --targets <paths...>'",
79
+ ".option('-k, --keywords <words...>'",
80
+ ".option('--include-tests'"
81
+ ];
82
+
83
+ for (const snippet of requiredCliSnippets) {
84
+ expectIncludes(cliSource, snippet, 'src/cli/index.ts', failures);
85
+ }
86
+
87
+ const requiredReadmeExamples = [
88
+ 'mycodemap analyze -i overview -t src/orchestrator',
89
+ 'mycodemap analyze -i impact -t src/cli/index.ts --include-tests',
90
+ 'mycodemap analyze -i dependency -t src/cli/index.ts',
91
+ 'mycodemap analyze -i search -k UnifiedResult'
92
+ ];
93
+
94
+ for (const example of requiredReadmeExamples) {
95
+ expectIncludes(readme, example, 'README.md analyze examples', failures);
96
+ }
97
+
98
+ const outdatedReadmeExamples = [
99
+ 'mycodemap analyze "',
100
+ 'mycodemap analyze --intent impact --file',
101
+ 'mycodemap analyze --intent dependency --file',
102
+ 'mycodemap analyze --intent search "'
103
+ ];
104
+
105
+ for (const example of outdatedReadmeExamples) {
106
+ expectNotIncludes(readme, example, 'README.md analyze examples', failures);
107
+ }
108
+ }
109
+
110
+ function validateTestingDocs(rootDir, failures) {
111
+ const testingRule = readText(rootDir, 'docs/rules/testing.md', failures);
112
+ const vitestConfig = readText(rootDir, 'vitest.config.ts', failures);
113
+ const benchmarkConfig = readText(rootDir, 'vitest.benchmark.config.ts', failures);
114
+
115
+ if (!testingRule || !vitestConfig || !benchmarkConfig) {
116
+ return;
117
+ }
118
+
119
+ const sharedSnippets = [
120
+ "include: ['src/**/*.test.ts']",
121
+ "exclude: ['node_modules', 'dist', 'refer/**/*.test.ts']",
122
+ 'testTimeout: 10000',
123
+ 'hookTimeout: 10000'
124
+ ];
125
+
126
+ for (const snippet of sharedSnippets) {
127
+ expectIncludes(vitestConfig, snippet, 'vitest.config.ts', failures);
128
+ expectIncludes(testingRule, snippet, 'docs/rules/testing.md', failures);
129
+ }
130
+
131
+ expectIncludes(benchmarkConfig, "include: ['refer/benchmark-quality.test.ts']", 'vitest.benchmark.config.ts', failures);
132
+ expectIncludes(testingRule, '`refer/benchmark-quality.test.ts`', 'docs/rules/testing.md', failures);
133
+ expectIncludes(testingRule, '`vitest.benchmark.config.ts`', 'docs/rules/testing.md', failures);
134
+ }
135
+
136
+ function validateGuardrailDocs(rootDir, failures) {
137
+ const readme = readText(rootDir, 'README.md', failures);
138
+ const engineeringRule = readText(rootDir, 'docs/rules/engineering-with-codex-openai.md', failures);
139
+ const validationRule = readText(rootDir, 'docs/rules/validation.md', failures);
140
+ const ciWorkflow = readText(rootDir, '.github/workflows/ci-gateway.yml', failures);
141
+ const preCommitHook = readText(rootDir, '.githooks/pre-commit', failures);
142
+
143
+ if (readme) {
144
+ const requiredReadmeGuardrails = [
145
+ 'npm run docs:check',
146
+ 'mycodemap ci check-docs-sync'
147
+ ];
148
+
149
+ for (const snippet of requiredReadmeGuardrails) {
150
+ expectIncludes(readme, snippet, 'README.md guardrail commands', failures);
151
+ }
152
+ }
153
+
154
+ if (engineeringRule) {
155
+ const requiredReferences = [
156
+ '.githooks/pre-commit',
157
+ '.githooks/commit-msg',
158
+ '.github/workflows/ci-gateway.yml',
159
+ '.github/workflows/publish.yml',
160
+ 'npm run docs:check'
161
+ ];
162
+
163
+ for (const reference of requiredReferences) {
164
+ expectIncludes(engineeringRule, reference, 'docs/rules/engineering-with-codex-openai.md', failures);
165
+ }
166
+ }
167
+
168
+ if (validationRule) {
169
+ expectIncludes(validationRule, 'npm run docs:check', 'docs/rules/validation.md', failures);
170
+ }
171
+
172
+ if (ciWorkflow) {
173
+ expectIncludes(ciWorkflow, 'run: npm run docs:check', '.github/workflows/ci-gateway.yml', failures);
174
+ expectIncludes(ciWorkflow, 'run: npm run typecheck', '.github/workflows/ci-gateway.yml', failures);
175
+ expectIncludes(ciWorkflow, 'run: npm run build', '.github/workflows/ci-gateway.yml', failures);
176
+ expectIncludes(ciWorkflow, 'run: node dist/cli/index.js ci check-docs-sync', '.github/workflows/ci-gateway.yml', failures);
177
+ expectIncludes(ciWorkflow, 'node dist/cli/index.js generate', '.github/workflows/ci-gateway.yml', failures);
178
+ }
179
+
180
+ if (preCommitHook) {
181
+ expectIncludes(preCommitHook, 'npm run docs:check', '.githooks/pre-commit', failures);
182
+ }
183
+ }
184
+
185
+ function validateAssistantDocs(rootDir, failures) {
186
+ const assistantGuide = readText(rootDir, 'docs/AI_ASSISTANT_SETUP.md', failures);
187
+ const setupGuide = readText(rootDir, 'docs/SETUP_GUIDE.md', failures);
188
+
189
+ if (assistantGuide) {
190
+ const requiredAssistantSnippets = [
191
+ 'npm run docs:check',
192
+ 'mycodemap ci check-docs-sync',
193
+ 'docs/rules/engineering-with-codex-openai.md'
194
+ ];
195
+
196
+ for (const snippet of requiredAssistantSnippets) {
197
+ expectIncludes(assistantGuide, snippet, 'docs/AI_ASSISTANT_SETUP.md', failures);
198
+ }
199
+ }
200
+
201
+ if (setupGuide) {
202
+ const requiredSetupSnippets = [
203
+ 'npm run docs:check',
204
+ 'npm run typecheck',
205
+ 'npx mycodemap ci check-docs-sync',
206
+ 'npx mycodemap ci check-commit-size --range origin/main..HEAD',
207
+ 'npx mycodemap ci assess-risk --threshold=0.7',
208
+ 'npx mycodemap ci check-output-contract --schema-version v1.0.0 --top-k 8 --max-tokens 160',
209
+ 'git diff --exit-code .mycodemap/ai-feed.txt'
210
+ ];
211
+
212
+ for (const snippet of requiredSetupSnippets) {
213
+ expectIncludes(setupGuide, snippet, 'docs/SETUP_GUIDE.md', failures);
214
+ }
215
+ }
216
+ }
217
+
218
+ function validateDocs(rootDir) {
219
+ const failures = [];
220
+
221
+ validatePackageScripts(rootDir, failures);
222
+ validateAnalyzeDocs(rootDir, failures);
223
+ validateTestingDocs(rootDir, failures);
224
+ validateGuardrailDocs(rootDir, failures);
225
+ validateAssistantDocs(rootDir, failures);
226
+
227
+ if (failures.length > 0) {
228
+ console.error('ERROR: documentation guardrails failed');
229
+ for (const failure of failures) {
230
+ console.error(`- ${failure}`);
231
+ }
232
+ process.exit(1);
233
+ }
234
+
235
+ console.log('Documentation guardrails passed');
236
+ }
237
+
238
+ validateDocs(parseRootDir(process.argv.slice(2)));