aodw-skill 0.7.3
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/.aodw/01-core/ai-interaction-rules.md +218 -0
- package/.aodw/01-core/ai-knowledge-rules.md +302 -0
- package/.aodw/01-core/ai-project-overview-rules.md +284 -0
- package/.aodw/01-core/aodw-constitution-summary.md +20 -0
- package/.aodw/01-core/aodw-constitution.md +419 -0
- package/.aodw/01-core/csf-thinking-framework.md +373 -0
- package/.aodw/01-core/git-discipline.md +226 -0
- package/.aodw/01-core/module-doc-rules.md +90 -0
- package/.aodw/02-workflow/aodw-development-stages.md +235 -0
- package/.aodw/02-workflow/rt-id-generation-rules.md +267 -0
- package/.aodw/02-workflow/rt-manager-summary.md +15 -0
- package/.aodw/02-workflow/rt-manager.md +399 -0
- package/.aodw/02-workflow/spec-full-profile-summary.md +13 -0
- package/.aodw/02-workflow/spec-full-profile.md +391 -0
- package/.aodw/02-workflow/spec-lite-profile.md +313 -0
- package/.aodw/02-workflow/ui-workflow-rules.md +334 -0
- package/.aodw/03-standards/ai-coding-rules-common.md +89 -0
- package/.aodw/03-standards/ai-coding-rules.md +370 -0
- package/.aodw/03-standards/stacks/java-springboot/ai-coding-rules-backend.md +100 -0
- package/.aodw/03-standards/stacks/python-fastapi/ai-coding-rules-backend.md +612 -0
- package/.aodw/03-standards/stacks/react-typescript/ai-coding-rules-frontend.md +291 -0
- package/.aodw/03-standards/stacks/vue2/ai-coding-rules-frontend.md +97 -0
- package/.aodw/03-standards/ui-kit/ui-kit.md +163 -0
- package/.aodw/04-auditors/aodw-development-auditor-rules.md +470 -0
- package/.aodw/04-auditors/aodw-full-auditor-rules.md +365 -0
- package/.aodw/04-auditors/aodw-requirement-auditor-rules.md +408 -0
- package/.aodw/05-tooling/ai-tools-init-rules.md +465 -0
- package/.aodw/06-project/ai-overview.md +116 -0
- package/.aodw/06-project/modules-index.yaml +11 -0
- package/.aodw/07-optimization/token-usage-analysis.md +253 -0
- package/.aodw/README.md +26 -0
- package/.aodw/RELEASE-CHECKLIST.md +144 -0
- package/.aodw/config.yaml +2 -0
- package/.aodw/manifest.yaml +98 -0
- package/.aodw/templates/SOURCE-TO-DISTRIBUTION-GUIDE.md +276 -0
- package/.aodw/templates/TEMPLATE-APPLICATION-GUIDE.md +246 -0
- package/.aodw/templates/aodw-kernel-loader-template.md +70 -0
- package/.aodw/templates/audit-report-template.md +232 -0
- package/.aodw/templates/changelog-template.md +16 -0
- package/.aodw/templates/checklists/coding-standards-template.md +110 -0
- package/.aodw/templates/csf-review-template.md +201 -0
- package/.aodw/templates/impact-template.md +17 -0
- package/.aodw/templates/invariants-template.md +12 -0
- package/.aodw/templates/module-readme-template.md +39 -0
- package/.aodw/templates/plan-lite-template.md +11 -0
- package/.aodw/templates/rt-decision-template.md +13 -0
- package/.aodw/templates/rt-intake-template.md +33 -0
- package/.aodw/templates/rt-meta-template.yaml +43 -0
- package/.aodw/templates/spec-lite-template.md +17 -0
- package/.aodw/templates/tests-template.md +13 -0
- package/.aodw/templates/tools-config/README.md +80 -0
- package/.aodw/templates/tools-config/backend/black.config.template.toml +6 -0
- package/.aodw/templates/tools-config/backend/pre-commit.config.template.yaml +16 -0
- package/.aodw/templates/tools-config/backend/ruff.config.template.toml +23 -0
- package/.aodw/templates/tools-config/frontend/eslint.config.template.json +113 -0
- package/.aodw/templates/tools-config/frontend/prettier.config.template.json +10 -0
- package/.aodw/templates/tools-config/frontend/tsconfig.paths.template.json +11 -0
- package/.aodw/workflow-guide.md +51 -0
- package/AODW_Adapters/README.md +143 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-check.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-done.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-full.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-governance.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-impact.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-init.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-invariants.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-lite.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-module.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-new.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-open.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-pause.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-resume.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-tests.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw-upgrade.md +7 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/.agent/rules/aodw.md +35 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-check.md +16 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-done.md +16 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-full.md +14 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-governance.md +13 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-impact.md +13 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-init.md +13 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-invariants.md +13 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-lite.md +14 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-module.md +13 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-new.md +30 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-open.md +10 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-pause.md +12 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-resume.md +12 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-tests.md +13 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw-upgrade.md +12 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/antigravity/global_workflows/aodw.md +18 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/claude/CLAUDE.md +17 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-check.md +30 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-done.md +52 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-full.md +31 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-governance.md +34 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-impact.md +25 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-init.md +75 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-invariants.md +29 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-lite.md +23 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-module.md +24 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-new.md +70 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-open.md +19 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-pause.md +19 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-resume.md +20 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-tests.md +26 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw-upgrade.md +27 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/aodw.md +69 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/deploypromote.md +20 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/commands/featuretotester.md +32 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/deploy/feature_to_master_push_test_local.sh +390 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/deploy/promote_only.sh +210 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/deploy/rollback_prod.sh +99 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/cursor/.cursor/rules/aodw.mdc +26 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-check.md +29 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-done.md +52 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-full.md +30 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-governance.md +33 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-impact.md +24 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-init.md +75 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-invariants.md +28 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-lite.md +22 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-module.md +23 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-new.md +92 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-open.md +18 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-pause.md +18 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-resume.md +19 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-tests.md +25 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw-upgrade.md +26 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/.agent/rules/aodw.md +68 -0
- package/AODW_Adapters/_backup/v3.1.0-pre-refactor/gemini/GEMINI.md +17 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-analyze.md +15 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-complete.md +15 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-control.md +14 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-decide.md +16 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-governance.md +7 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-implement.md +16 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-init.md +7 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-intake.md +15 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-open.md +7 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-simplified.md +107 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/.agent/rules/aodw-verify.md +14 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-analyze.md +24 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-complete.md +23 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-control.md +21 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-decide.md +26 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-governance.md +13 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-implement.md +21 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-init.md +13 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-intake.md +28 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-open.md +10 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw-verify.md +20 -0
- package/AODW_Adapters/_backup/v4.0.0-simplified/antigravity/global_workflows/aodw.md +18 -0
- package/AODW_Adapters/antigravity/.agent/rules/aodw.md +74 -0
- package/AODW_Adapters/claude/CLAUDE.md +70 -0
- package/AODW_Adapters/cursor/.cursor/commands/README.md +37 -0
- package/AODW_Adapters/cursor/.cursor/rules/aodw.mdc +77 -0
- package/AODW_Adapters/gemini/.agent/rules/aodw-analyze.md +15 -0
- package/AODW_Adapters/gemini/.agent/rules/aodw-complete.md +15 -0
- package/AODW_Adapters/gemini/.agent/rules/aodw-control.md +14 -0
- package/AODW_Adapters/gemini/.agent/rules/aodw-decide.md +16 -0
- package/AODW_Adapters/gemini/.agent/rules/aodw-governance.md +33 -0
- package/AODW_Adapters/gemini/.agent/rules/aodw-implement.md +16 -0
- package/AODW_Adapters/gemini/.agent/rules/aodw-init.md +75 -0
- package/AODW_Adapters/gemini/.agent/rules/aodw-intake.md +15 -0
- package/AODW_Adapters/gemini/.agent/rules/aodw-open.md +18 -0
- package/AODW_Adapters/gemini/.agent/rules/aodw-verify.md +14 -0
- package/AODW_Adapters/gemini/.agent/rules/aodw.md +70 -0
- package/AODW_Adapters/gemini/GEMINI.md +17 -0
- package/AODW_Adapters/general/.github/copilot-instructions.md +34 -0
- package/AODW_Adapters/general/AGENTS.md +70 -0
- package/README.md +118 -0
- package/bin/aodw.js +627 -0
- package/bin/commands/init-overview.js +801 -0
- package/bin/commands/init-tools.js +811 -0
- package/bin/commands/new.js +235 -0
- package/bin/commands/serve.js +79 -0
- package/bin/processors/index.js +109 -0
- package/bin/update-adapters-from-template.js +89 -0
- package/bin/utils/config.js +56 -0
- package/docs/README.md +26 -0
- package/docs/adapter-evaluation.md +55 -0
- package/docs/backend-guidelines.md +335 -0
- package/docs/frontend-guidelines.md +266 -0
- package/docs/installation-variants.md +88 -0
- package/docs/migration-guide-0.2.0.md +250 -0
- package/docs/platform-matrix.md +83 -0
- package/package.json +40 -0
|
@@ -0,0 +1,801 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import yaml from 'js-yaml';
|
|
6
|
+
import inquirer from 'inquirer';
|
|
7
|
+
|
|
8
|
+
const CORE_DIR = process.env.AODW_CORE_DIR || '.aodw';
|
|
9
|
+
const OVERVIEW_FILE = `${CORE_DIR}/ai-overview.md`;
|
|
10
|
+
const MODULES_INDEX_FILE = `${CORE_DIR}/modules-index.yaml`;
|
|
11
|
+
|
|
12
|
+
// 检测技术栈
|
|
13
|
+
async function detectTechStack() {
|
|
14
|
+
const cwd = process.cwd();
|
|
15
|
+
const techStack = {
|
|
16
|
+
frontend: [],
|
|
17
|
+
backend: [],
|
|
18
|
+
database: [],
|
|
19
|
+
message_system: [],
|
|
20
|
+
cache: [],
|
|
21
|
+
deployment: [],
|
|
22
|
+
other: [],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// 检测前端技术栈
|
|
26
|
+
const packageJsonPath = path.join(cwd, 'package.json');
|
|
27
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
28
|
+
try {
|
|
29
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
30
|
+
|
|
31
|
+
// 检测框架
|
|
32
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
33
|
+
if (deps.react) techStack.frontend.push(`React ${deps.react}`);
|
|
34
|
+
if (deps.vue) techStack.frontend.push(`Vue ${deps.vue}`);
|
|
35
|
+
if (deps['@angular/core']) techStack.frontend.push(`Angular ${deps['@angular/core']}`);
|
|
36
|
+
if (deps.next) techStack.frontend.push(`Next.js ${deps.next}`);
|
|
37
|
+
if (deps.nuxt) techStack.frontend.push(`Nuxt.js ${deps.nuxt}`);
|
|
38
|
+
|
|
39
|
+
// 检测构建工具
|
|
40
|
+
if (deps.vite) techStack.frontend.push(`Vite ${deps.vite}`);
|
|
41
|
+
if (deps.webpack) techStack.frontend.push(`Webpack ${deps.webpack}`);
|
|
42
|
+
if (deps['@vitejs/plugin-react']) techStack.frontend.push('Vite (React)');
|
|
43
|
+
if (deps['@vitejs/plugin-vue']) techStack.frontend.push('Vite (Vue)');
|
|
44
|
+
|
|
45
|
+
// 检测语言
|
|
46
|
+
if (deps.typescript) techStack.frontend.push(`TypeScript ${deps.typescript}`);
|
|
47
|
+
// 检查 tsconfig.json 作为 TypeScript 的补充证据
|
|
48
|
+
if (fs.existsSync(path.join(cwd, 'tsconfig.json')) && !techStack.frontend.some(f => f.includes('TypeScript'))) {
|
|
49
|
+
techStack.frontend.push('TypeScript');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 检测状态管理
|
|
53
|
+
if (deps.redux) techStack.frontend.push(`Redux ${deps.redux}`);
|
|
54
|
+
if (deps['@reduxjs/toolkit']) techStack.frontend.push('Redux Toolkit');
|
|
55
|
+
if (deps.mobx) techStack.frontend.push(`MobX ${deps.mobx}`);
|
|
56
|
+
if (deps.zustand) techStack.frontend.push(`Zustand ${deps.zustand}`);
|
|
57
|
+
|
|
58
|
+
// 检测 UI 库
|
|
59
|
+
if (deps['@mui/material']) techStack.frontend.push('Material-UI');
|
|
60
|
+
if (deps['@ant-design/react']) techStack.frontend.push('Ant Design');
|
|
61
|
+
if (deps['antd']) techStack.frontend.push('Ant Design');
|
|
62
|
+
} catch (e) {
|
|
63
|
+
// ignore
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 检测后端技术栈
|
|
68
|
+
const pyprojectPath = path.join(cwd, 'pyproject.toml');
|
|
69
|
+
const requirementsPath = path.join(cwd, 'requirements.txt');
|
|
70
|
+
const requirementsInPath = path.join(cwd, 'requirements.in');
|
|
71
|
+
|
|
72
|
+
if (fs.existsSync(pyprojectPath)) {
|
|
73
|
+
try {
|
|
74
|
+
const content = fs.readFileSync(pyprojectPath, 'utf8');
|
|
75
|
+
// 检测 FastAPI(支持多种格式)
|
|
76
|
+
const fastapiPatterns = [
|
|
77
|
+
/fastapi\s*=\s*["']?([^"'\s,]+)["']?/,
|
|
78
|
+
/fastapi\s*==\s*["']?([^"'\s,]+)["']?/,
|
|
79
|
+
/fastapi\s*>=\s*["']?([^"'\s,]+)["']?/,
|
|
80
|
+
/"fastapi"\s*:\s*["']?([^"'\s,]+)["']?/,
|
|
81
|
+
];
|
|
82
|
+
for (const pattern of fastapiPatterns) {
|
|
83
|
+
const match = content.match(pattern);
|
|
84
|
+
if (match && match[1]) {
|
|
85
|
+
techStack.backend.push(`FastAPI ${match[1]}`);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// 如果没有找到版本号,但找到了 fastapi 关键字
|
|
90
|
+
if (content.includes('fastapi') && techStack.backend.length === 0) {
|
|
91
|
+
techStack.backend.push('FastAPI');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 检测 Python 版本
|
|
95
|
+
const pythonPatterns = [
|
|
96
|
+
/requires-python\s*=\s*["']?([^"'\s]+)["']?/,
|
|
97
|
+
/python_requires\s*=\s*["']?([^"'\s]+)["']?/,
|
|
98
|
+
];
|
|
99
|
+
for (const pattern of pythonPatterns) {
|
|
100
|
+
const pythonMatch = content.match(pattern);
|
|
101
|
+
if (pythonMatch && pythonMatch[1]) {
|
|
102
|
+
techStack.backend.push(`Python ${pythonMatch[1]}`);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 检测 Django
|
|
108
|
+
if (content.includes('django')) {
|
|
109
|
+
const djangoMatch = content.match(/django\s*=\s*["']?([^"'\s,]+)["']?/);
|
|
110
|
+
if (djangoMatch && djangoMatch[1]) {
|
|
111
|
+
techStack.backend.push(`Django ${djangoMatch[1]}`);
|
|
112
|
+
} else {
|
|
113
|
+
techStack.backend.push('Django');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 检测 Flask
|
|
118
|
+
if (content.includes('flask')) {
|
|
119
|
+
const flaskMatch = content.match(/flask\s*=\s*["']?([^"'\s,]+)["']?/);
|
|
120
|
+
if (flaskMatch && flaskMatch[1]) {
|
|
121
|
+
techStack.backend.push(`Flask ${flaskMatch[1]}`);
|
|
122
|
+
} else {
|
|
123
|
+
techStack.backend.push('Flask');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch (e) {
|
|
127
|
+
// ignore
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 从 requirements.in 或 requirements.txt 检测
|
|
132
|
+
const requirementsFiles = [requirementsInPath, requirementsPath];
|
|
133
|
+
for (const reqPath of requirementsFiles) {
|
|
134
|
+
if (fs.existsSync(reqPath)) {
|
|
135
|
+
try {
|
|
136
|
+
const content = fs.readFileSync(reqPath, 'utf8');
|
|
137
|
+
// 检测 FastAPI
|
|
138
|
+
if (content.includes('fastapi') && !techStack.backend.some(b => b.includes('FastAPI'))) {
|
|
139
|
+
const match = content.match(/fastapi[>=<]+([^\s\n]+)/);
|
|
140
|
+
techStack.backend.push(`FastAPI ${match ? match[1] : ''}`);
|
|
141
|
+
}
|
|
142
|
+
// 检测数据库驱动
|
|
143
|
+
if (content.includes('psycopg2') || content.includes('psycopg2-binary')) {
|
|
144
|
+
techStack.database.push('PostgreSQL');
|
|
145
|
+
}
|
|
146
|
+
if (content.includes('mysql') || content.includes('pymysql')) {
|
|
147
|
+
techStack.database.push('MySQL');
|
|
148
|
+
}
|
|
149
|
+
if (content.includes('redis') || content.includes('redis-py')) {
|
|
150
|
+
techStack.cache.push('Redis');
|
|
151
|
+
}
|
|
152
|
+
} catch (e) {
|
|
153
|
+
// ignore
|
|
154
|
+
}
|
|
155
|
+
break; // 只读取第一个存在的文件
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 检测数据库和基础设施(从 docker-compose.yml)
|
|
160
|
+
const dockerComposePath = path.join(cwd, 'docker-compose.yml');
|
|
161
|
+
const dockerComposeYmlPath = path.join(cwd, 'docker-compose.yaml');
|
|
162
|
+
const dockerFiles = [dockerComposePath, dockerComposeYmlPath];
|
|
163
|
+
|
|
164
|
+
for (const dockerPath of dockerFiles) {
|
|
165
|
+
if (fs.existsSync(dockerPath)) {
|
|
166
|
+
try {
|
|
167
|
+
const content = fs.readFileSync(dockerPath, 'utf8');
|
|
168
|
+
// 检测数据库
|
|
169
|
+
if (content.includes('postgres') || content.includes('postgresql')) {
|
|
170
|
+
if (!techStack.database.includes('PostgreSQL')) {
|
|
171
|
+
techStack.database.push('PostgreSQL');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (content.includes('mysql') && !content.includes('mariadb')) {
|
|
175
|
+
if (!techStack.database.includes('MySQL')) {
|
|
176
|
+
techStack.database.push('MySQL');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (content.includes('mariadb')) {
|
|
180
|
+
if (!techStack.database.includes('MariaDB')) {
|
|
181
|
+
techStack.database.push('MariaDB');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (content.includes('mongodb')) {
|
|
185
|
+
if (!techStack.database.includes('MongoDB')) {
|
|
186
|
+
techStack.database.push('MongoDB');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 检测缓存
|
|
191
|
+
if (content.includes('redis')) {
|
|
192
|
+
if (!techStack.cache.includes('Redis')) {
|
|
193
|
+
techStack.cache.push('Redis');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (content.includes('memcached')) {
|
|
197
|
+
if (!techStack.cache.includes('Memcached')) {
|
|
198
|
+
techStack.cache.push('Memcached');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// 检测消息队列
|
|
203
|
+
if (content.includes('rabbitmq')) {
|
|
204
|
+
if (!techStack.message_system.includes('RabbitMQ')) {
|
|
205
|
+
techStack.message_system.push('RabbitMQ');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (content.includes('kafka')) {
|
|
209
|
+
if (!techStack.message_system.includes('Kafka')) {
|
|
210
|
+
techStack.message_system.push('Kafka');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 检测部署相关
|
|
215
|
+
if (content.includes('nginx')) {
|
|
216
|
+
if (!techStack.deployment.includes('Nginx')) {
|
|
217
|
+
techStack.deployment.push('Nginx');
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
} catch (e) {
|
|
221
|
+
// ignore
|
|
222
|
+
}
|
|
223
|
+
break; // 只读取第一个存在的文件
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return techStack;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// 分析目录结构
|
|
231
|
+
async function analyzeDirectoryStructure() {
|
|
232
|
+
const cwd = process.cwd();
|
|
233
|
+
const structure = [];
|
|
234
|
+
const keyDirs = ['frontend', 'backend', 'apps', 'packages', 'src', 'lib', 'infra', 'docs', 'RT', CORE_DIR];
|
|
235
|
+
|
|
236
|
+
for (const dir of keyDirs) {
|
|
237
|
+
const dirPath = path.join(cwd, dir);
|
|
238
|
+
if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
|
239
|
+
// 尝试读取 README 或 package.json 来获取描述
|
|
240
|
+
let description = '';
|
|
241
|
+
const readmePath = path.join(dirPath, 'README.md');
|
|
242
|
+
if (fs.existsSync(readmePath)) {
|
|
243
|
+
const readme = fs.readFileSync(readmePath, 'utf8');
|
|
244
|
+
const firstLine = readme.split('\n')[0];
|
|
245
|
+
if (firstLine && !firstLine.startsWith('#')) {
|
|
246
|
+
description = firstLine.trim();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
structure.push({
|
|
251
|
+
path: `/${dir}`,
|
|
252
|
+
description: description || getDefaultDescription(dir),
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return structure;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 获取目录默认描述
|
|
261
|
+
function getDefaultDescription(dir) {
|
|
262
|
+
const descriptions = {
|
|
263
|
+
frontend: '前端应用',
|
|
264
|
+
backend: '后端 API',
|
|
265
|
+
apps: '应用目录',
|
|
266
|
+
packages: '共享代码包',
|
|
267
|
+
src: '源代码',
|
|
268
|
+
lib: '库文件',
|
|
269
|
+
infra: '基础设施与部署脚本',
|
|
270
|
+
docs: '文档',
|
|
271
|
+
RT: '每个 Request Ticket 的本地知识库',
|
|
272
|
+
[CORE_DIR]: 'AODW 配置与规则文件',
|
|
273
|
+
};
|
|
274
|
+
return descriptions[dir] || '';
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// 识别模块
|
|
278
|
+
async function detectModules() {
|
|
279
|
+
const cwd = process.cwd();
|
|
280
|
+
const modules = [];
|
|
281
|
+
const seenModules = new Set(); // 避免重复
|
|
282
|
+
|
|
283
|
+
// 常见的模块目录(按优先级排序)
|
|
284
|
+
const moduleDirs = [
|
|
285
|
+
'backend/app',
|
|
286
|
+
'backend/src',
|
|
287
|
+
'app',
|
|
288
|
+
'apps',
|
|
289
|
+
'src',
|
|
290
|
+
'frontend/src',
|
|
291
|
+
'frontend/app',
|
|
292
|
+
];
|
|
293
|
+
|
|
294
|
+
for (const baseDir of moduleDirs) {
|
|
295
|
+
const basePath = path.join(cwd, baseDir);
|
|
296
|
+
if (!fs.existsSync(basePath)) continue;
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
const entries = fs.readdirSync(basePath, { withFileTypes: true });
|
|
300
|
+
for (const entry of entries) {
|
|
301
|
+
if (!entry.isDirectory()) continue;
|
|
302
|
+
|
|
303
|
+
// 跳过隐藏目录和常见非模块目录
|
|
304
|
+
if (entry.name.startsWith('.') ||
|
|
305
|
+
['__pycache__', 'node_modules', '.git', 'dist', 'build'].includes(entry.name)) {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const modulePath = path.join(basePath, entry.name);
|
|
310
|
+
|
|
311
|
+
// 检查是否是模块(有 __init__.py、index.ts、index.js,或者是符合命名规范的目录)
|
|
312
|
+
const hasInit = fs.existsSync(path.join(modulePath, '__init__.py')) ||
|
|
313
|
+
fs.existsSync(path.join(modulePath, 'index.ts')) ||
|
|
314
|
+
fs.existsSync(path.join(modulePath, 'index.js')) ||
|
|
315
|
+
fs.existsSync(path.join(modulePath, 'index.tsx'));
|
|
316
|
+
|
|
317
|
+
// Python 模块:有 __init__.py 或符合命名规范
|
|
318
|
+
// TypeScript/JavaScript 模块:有 index 文件或符合命名规范
|
|
319
|
+
const isPythonModule = fs.existsSync(path.join(modulePath, '__init__.py'));
|
|
320
|
+
const isTSModule = fs.existsSync(path.join(modulePath, 'index.ts')) ||
|
|
321
|
+
fs.existsSync(path.join(modulePath, 'index.tsx'));
|
|
322
|
+
const isJSModule = fs.existsSync(path.join(modulePath, 'index.js'));
|
|
323
|
+
const isValidName = entry.name.match(/^[a-z][a-z0-9_]*$/); // 小写字母开头,可包含数字和下划线
|
|
324
|
+
|
|
325
|
+
if (hasInit || (isValidName && (isPythonModule || isTSModule || isJSModule))) {
|
|
326
|
+
// 避免重复添加
|
|
327
|
+
if (seenModules.has(entry.name)) continue;
|
|
328
|
+
seenModules.add(entry.name);
|
|
329
|
+
|
|
330
|
+
// 检查是否有 README
|
|
331
|
+
const readmePath = path.join(modulePath, 'README.md');
|
|
332
|
+
const moduleDocPath = path.join(cwd, 'docs/modules', `${entry.name}.md`);
|
|
333
|
+
|
|
334
|
+
// 尝试从 README 获取描述
|
|
335
|
+
let description = '';
|
|
336
|
+
if (fs.existsSync(readmePath)) {
|
|
337
|
+
try {
|
|
338
|
+
const readmeContent = fs.readFileSync(readmePath, 'utf8');
|
|
339
|
+
// 提取第一段非标题的描述
|
|
340
|
+
const lines = readmeContent.split('\n');
|
|
341
|
+
for (const line of lines) {
|
|
342
|
+
if (line.trim() && !line.startsWith('#') && line.length > 10) {
|
|
343
|
+
description = line.trim();
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
} catch (e) {
|
|
348
|
+
// ignore
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
modules.push({
|
|
353
|
+
name: entry.name,
|
|
354
|
+
root: path.relative(cwd, modulePath),
|
|
355
|
+
path: fs.existsSync(moduleDocPath) ? `docs/modules/${entry.name}.md` : null,
|
|
356
|
+
description: description || '',
|
|
357
|
+
detected: true,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
} catch (e) {
|
|
362
|
+
// ignore
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return modules;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// 读取现有 ai-overview.md
|
|
370
|
+
async function readExistingOverview() {
|
|
371
|
+
const filePath = path.join(process.cwd(), OVERVIEW_FILE);
|
|
372
|
+
if (!fs.existsSync(filePath)) {
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
377
|
+
|
|
378
|
+
// 解析 markdown,提取各个部分
|
|
379
|
+
const sections = {
|
|
380
|
+
techStack: extractSection(content, '## 1. 技术栈'),
|
|
381
|
+
architecture: extractSection(content, '## 2. 整体架构概览'),
|
|
382
|
+
directoryStructure: extractSection(content, '## 3. 目录结构'),
|
|
383
|
+
modules: extractSection(content, '## 4. 核心业务模块'),
|
|
384
|
+
invariants: extractSection(content, '## 5. 系统级 Invariants'),
|
|
385
|
+
moduleMapping: extractSection(content, '## 6. 模块 README 映射表'),
|
|
386
|
+
history: extractSection(content, '## 7. 历史关键变更'),
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
content,
|
|
391
|
+
sections,
|
|
392
|
+
hasUserContent: content.includes('<!-- USER-ADDED') || !content.includes('<!-- AUTO-DETECTED'),
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// 提取 markdown 章节
|
|
397
|
+
function extractSection(content, header) {
|
|
398
|
+
const headerIndex = content.indexOf(header);
|
|
399
|
+
if (headerIndex === -1) return null;
|
|
400
|
+
|
|
401
|
+
const nextHeaderIndex = content.indexOf('\n## ', headerIndex + header.length);
|
|
402
|
+
const sectionEnd = nextHeaderIndex === -1 ? content.length : nextHeaderIndex;
|
|
403
|
+
|
|
404
|
+
return content.substring(headerIndex, sectionEnd).trim();
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// 智能合并
|
|
408
|
+
async function mergeOverview(existing, detected) {
|
|
409
|
+
const merged = {
|
|
410
|
+
techStack: mergeTechStack(existing?.sections?.techStack, detected.techStack),
|
|
411
|
+
directoryStructure: mergeDirectoryStructure(existing?.sections?.directoryStructure, detected.directoryStructure),
|
|
412
|
+
modules: mergeModules(existing?.sections?.modules, detected.modules),
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
return merged;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// 合并技术栈
|
|
419
|
+
function mergeTechStack(existingSection, detected) {
|
|
420
|
+
// 如果存在用户内容,保留
|
|
421
|
+
if (existingSection && existingSection.includes('<!-- USER-ADDED')) {
|
|
422
|
+
return existingSection; // 保留用户内容
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// 生成新的技术栈部分
|
|
426
|
+
const lines = ['## 1. 技术栈', ''];
|
|
427
|
+
|
|
428
|
+
lines.push('<!-- AUTO-DETECTED: 以下内容由 aodw init-overview 自动检测 -->');
|
|
429
|
+
if (detected.frontend.length > 0) {
|
|
430
|
+
lines.push(`- 前端:${detected.frontend.join('、')}`);
|
|
431
|
+
} else {
|
|
432
|
+
lines.push('- 前端:');
|
|
433
|
+
}
|
|
434
|
+
if (detected.backend.length > 0) {
|
|
435
|
+
lines.push(`- 后端:${detected.backend.join('、')}`);
|
|
436
|
+
} else {
|
|
437
|
+
lines.push('- 后端:');
|
|
438
|
+
}
|
|
439
|
+
if (detected.database.length > 0) {
|
|
440
|
+
lines.push(`- 数据库:${detected.database.join('、')}`);
|
|
441
|
+
} else {
|
|
442
|
+
lines.push('- 数据库:');
|
|
443
|
+
}
|
|
444
|
+
if (detected.message_system.length > 0) {
|
|
445
|
+
lines.push(`- 消息系统:${detected.message_system.join('、')}`);
|
|
446
|
+
} else {
|
|
447
|
+
lines.push('- 消息系统:');
|
|
448
|
+
}
|
|
449
|
+
if (detected.cache.length > 0) {
|
|
450
|
+
lines.push(`- 缓存:${detected.cache.join('、')}`);
|
|
451
|
+
} else {
|
|
452
|
+
lines.push('- 缓存:');
|
|
453
|
+
}
|
|
454
|
+
if (detected.deployment.length > 0) {
|
|
455
|
+
lines.push(`- 运维 / 部署:${detected.deployment.join('、')}`);
|
|
456
|
+
} else {
|
|
457
|
+
lines.push('- 运维 / 部署:');
|
|
458
|
+
}
|
|
459
|
+
if (detected.other.length > 0) {
|
|
460
|
+
lines.push(`- 其他:${detected.other.join('、')}`);
|
|
461
|
+
} else {
|
|
462
|
+
lines.push('- 其他:');
|
|
463
|
+
}
|
|
464
|
+
lines.push('<!-- END AUTO-DETECTED -->');
|
|
465
|
+
lines.push('');
|
|
466
|
+
lines.push('(由 AI 或人工在首次接入 AODW 时填写,后续在架构变动时更新)');
|
|
467
|
+
|
|
468
|
+
return lines.join('\n');
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// 合并目录结构
|
|
472
|
+
function mergeDirectoryStructure(existingSection, detected) {
|
|
473
|
+
if (existingSection && existingSection.includes('<!-- USER-ADDED')) {
|
|
474
|
+
return existingSection;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const lines = [
|
|
478
|
+
'## 3. 目录结构(只列关键部分)',
|
|
479
|
+
'',
|
|
480
|
+
];
|
|
481
|
+
|
|
482
|
+
if (detected && detected.length > 0) {
|
|
483
|
+
lines.push('<!-- AUTO-DETECTED: 以下内容由 aodw init-overview 自动检测 -->');
|
|
484
|
+
detected.forEach(dir => {
|
|
485
|
+
lines.push(`- ${dir.path} - ${dir.description}`);
|
|
486
|
+
});
|
|
487
|
+
lines.push('<!-- END AUTO-DETECTED -->');
|
|
488
|
+
} else {
|
|
489
|
+
lines.push('请根据实际项目补充,例如:');
|
|
490
|
+
lines.push('');
|
|
491
|
+
lines.push('- `/apps/web` - 前端应用');
|
|
492
|
+
lines.push('- `/apps/api` - 后端 API');
|
|
493
|
+
lines.push('- `/packages/shared` - 共享代码(类型、工具等)');
|
|
494
|
+
lines.push('- `/infra` - 基础设施与部署脚本');
|
|
495
|
+
lines.push('- `/RT` - 每个 Request Ticket 的本地知识库');
|
|
496
|
+
lines.push(`- \`/${CORE_DIR}\` - AODW 配置与规则文件`);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
lines.push('');
|
|
500
|
+
lines.push('AI 在修改目录结构时,需要在此更新说明。');
|
|
501
|
+
|
|
502
|
+
return lines.join('\n');
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// 合并模块
|
|
506
|
+
function mergeModules(existingSection, detected) {
|
|
507
|
+
// 模块部分比较复杂,暂时保留现有内容或生成基础结构
|
|
508
|
+
if (existingSection && existingSection.includes('<!-- USER-ADDED')) {
|
|
509
|
+
return existingSection;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const lines = [
|
|
513
|
+
'## 4. 核心业务模块',
|
|
514
|
+
'',
|
|
515
|
+
'为每个重要业务模块列出简要说明(AI 可从模块 README 中提取信息汇总到这里)。',
|
|
516
|
+
'',
|
|
517
|
+
];
|
|
518
|
+
|
|
519
|
+
if (detected && detected.length > 0) {
|
|
520
|
+
lines.push('<!-- AUTO-DETECTED: 以下内容由 aodw init-overview 自动检测 -->');
|
|
521
|
+
detected.forEach((module, index) => {
|
|
522
|
+
lines.push(`### 4.${index + 1} ${module.name} 模块(${module.name} Module)`);
|
|
523
|
+
lines.push('');
|
|
524
|
+
lines.push(`- **职责**:${module.description || '(待补充)'}`);
|
|
525
|
+
lines.push(`- **关键路径**:\`${module.root}\``);
|
|
526
|
+
if (module.path) {
|
|
527
|
+
lines.push(`- **模块文档**:\`${module.path}\``);
|
|
528
|
+
}
|
|
529
|
+
lines.push('- **依赖关系**:(待补充)');
|
|
530
|
+
lines.push('- **关键约束**:(待补充)');
|
|
531
|
+
lines.push('');
|
|
532
|
+
});
|
|
533
|
+
lines.push('<!-- END AUTO-DETECTED -->');
|
|
534
|
+
} else {
|
|
535
|
+
lines.push('示例模板:');
|
|
536
|
+
lines.push('');
|
|
537
|
+
lines.push('### 4.1 用户模块(User Module)');
|
|
538
|
+
lines.push('');
|
|
539
|
+
lines.push('- **职责**:认证、授权、用户资料管理等');
|
|
540
|
+
lines.push('- **关键路径**:');
|
|
541
|
+
lines.push(' - Web UI:`apps/web/src/features/user/...`');
|
|
542
|
+
lines.push(' - API:`apps/api/src/users/...`');
|
|
543
|
+
lines.push('- **依赖关系**:');
|
|
544
|
+
lines.push(' - 调用:订单模块、通知模块等');
|
|
545
|
+
lines.push(' - 被调用:认证中间件等');
|
|
546
|
+
lines.push('- **关键约束**:');
|
|
547
|
+
lines.push(' - 不得在 controller 中直接访问数据库,必须通过 service / repository 层;');
|
|
548
|
+
lines.push(' - 密码与敏感字段必须加密或脱敏。');
|
|
549
|
+
lines.push('');
|
|
550
|
+
lines.push('### 4.2 订单模块(Order Module)');
|
|
551
|
+
lines.push('');
|
|
552
|
+
lines.push('(同样结构)');
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return lines.join('\n');
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// 生成架构概览部分
|
|
559
|
+
function generateArchitectureSection(existingSection) {
|
|
560
|
+
if (existingSection && existingSection.includes('<!-- USER-ADDED')) {
|
|
561
|
+
return existingSection;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
return `## 2. 整体架构概览
|
|
565
|
+
|
|
566
|
+
可以使用文字或 ASCII 图描述系统架构,例如:
|
|
567
|
+
|
|
568
|
+
\`\`\`text
|
|
569
|
+
[ Web / Mobile Client ]
|
|
570
|
+
|
|
|
571
|
+
[ API ]
|
|
572
|
+
|
|
|
573
|
+
[ Services / Domain ]
|
|
574
|
+
|
|
|
575
|
+
[ DB / MQ ]
|
|
576
|
+
\`\`\`
|
|
577
|
+
|
|
578
|
+
AI 应在理解架构后,将关键组件简要记录在此处。
|
|
579
|
+
`;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// 生成模块映射表部分
|
|
583
|
+
function generateModuleMappingSection(modules) {
|
|
584
|
+
let mappingText = '(待补充)';
|
|
585
|
+
|
|
586
|
+
if (modules && modules.length > 0) {
|
|
587
|
+
const mappings = modules
|
|
588
|
+
.filter(m => m.root)
|
|
589
|
+
.map(m => `${m.root}/** → ${m.path || 'docs/modules/' + m.name + '.md'}`)
|
|
590
|
+
.join('\n');
|
|
591
|
+
|
|
592
|
+
if (mappings) {
|
|
593
|
+
mappingText = mappings;
|
|
594
|
+
}
|
|
595
|
+
} else {
|
|
596
|
+
mappingText = 'apps/api/src/users/** → docs/modules/users.md\napps/api/src/orders/** → docs/modules/orders.md\napps/web/src/features/** → docs/modules/web-features.md';
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
return `## 6. 模块 README 映射表
|
|
600
|
+
|
|
601
|
+
为 AI 提供"代码目录 → 模块文档"的索引示例:
|
|
602
|
+
|
|
603
|
+
\`\`\`text
|
|
604
|
+
${mappingText}
|
|
605
|
+
\`\`\`
|
|
606
|
+
|
|
607
|
+
AI 在创建新模块或重构模块结构时,应同步维护此映射关系。
|
|
608
|
+
`;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// 生成 ai-overview.md
|
|
612
|
+
async function generateOverviewFile(merged, existing, modules) {
|
|
613
|
+
// 生成架构概览部分
|
|
614
|
+
const architectureSection = generateArchitectureSection(existing?.sections?.architecture);
|
|
615
|
+
|
|
616
|
+
// 生成模块映射表部分
|
|
617
|
+
const moduleMappingSection = generateModuleMappingSection(modules);
|
|
618
|
+
|
|
619
|
+
// 确保 merged 的各个部分都有默认值
|
|
620
|
+
const techStackSection = merged.techStack || '## 1. 技术栈\n\n- 前端:\n- 后端:\n- 数据库:\n- 消息系统:\n- 缓存:\n- 运维 / 部署:\n- 其他:\n\n(由 AI 或人工在首次接入 AODW 时填写,后续在架构变动时更新)';
|
|
621
|
+
|
|
622
|
+
const directoryStructureSection = merged.directoryStructure || `## 3. 目录结构(只列关键部分)\n\n请根据实际项目补充,例如:\n\n- \`/apps/web\` - 前端应用\n- \`/apps/api\` - 后端 API\n- \`/packages/shared\` - 共享代码(类型、工具等)\n- \`/infra\` - 基础设施与部署脚本\n- \`/RT\` - 每个 Request Ticket 的本地知识库\n- \`/${CORE_DIR}\` - AODW 配置与规则文件\n\nAI 在修改目录结构时,需要在此更新说明。`;
|
|
623
|
+
|
|
624
|
+
const modulesSection = merged.modules || '## 4. 核心业务模块\n\n为每个重要业务模块列出简要说明(AI 可从模块 README 中提取信息汇总到这里)。\n\n示例模板:\n\n### 4.1 用户模块(User Module)\n\n- **职责**:认证、授权、用户资料管理等\n- **关键路径**:\n - Web UI:`apps/web/src/features/user/...`\n - API:`apps/api/src/users/...`\n- **依赖关系**:\n - 调用:订单模块、通知模块等\n - 被调用:认证中间件等\n- **关键约束**:\n - 不得在 controller 中直接访问数据库,必须通过 service / repository 层;\n - 密码与敏感字段必须加密或脱敏。\n\n### 4.2 订单模块(Order Module)\n\n(同样结构)';
|
|
625
|
+
|
|
626
|
+
const template = `# AI System Overview
|
|
627
|
+
(本文件列出 AI 理解本系统所需的全局信息)
|
|
628
|
+
|
|
629
|
+
> 说明:本文件是骨架模板,AI 可以在后续 RT 中逐步补全。
|
|
630
|
+
> 修改架构或模块职责时,AI 必须同步更新本文件。
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
${techStackSection}
|
|
635
|
+
|
|
636
|
+
---
|
|
637
|
+
|
|
638
|
+
${architectureSection}
|
|
639
|
+
|
|
640
|
+
---
|
|
641
|
+
|
|
642
|
+
${directoryStructureSection}
|
|
643
|
+
|
|
644
|
+
---
|
|
645
|
+
|
|
646
|
+
${modulesSection}
|
|
647
|
+
|
|
648
|
+
---
|
|
649
|
+
|
|
650
|
+
## 5. 系统级 Invariants(不可破坏原则)
|
|
651
|
+
|
|
652
|
+
AI 在修改任何代码前必须确认不会违反以下约束:
|
|
653
|
+
|
|
654
|
+
- 不得绕过 service 层直接访问 DB;
|
|
655
|
+
- 不得无故更改对外 API 返回格式(除非走 Spec-Full 流程);
|
|
656
|
+
- 不得在热路径引入明显的性能退化;
|
|
657
|
+
- 不得引入明显的安全风险(如绕过认证、明文敏感信息)。
|
|
658
|
+
|
|
659
|
+
根据系统演进,这些 Invariants 可以在 RT 中进行讨论与更新。
|
|
660
|
+
|
|
661
|
+
---
|
|
662
|
+
|
|
663
|
+
${moduleMappingSection}
|
|
664
|
+
|
|
665
|
+
---
|
|
666
|
+
|
|
667
|
+
## 7. 历史关键变更(可选)
|
|
668
|
+
|
|
669
|
+
可记录一些对架构或业务影响较大的里程碑,例如:
|
|
670
|
+
|
|
671
|
+
- 2025-01:引入新订单系统;
|
|
672
|
+
- 2025-03:从单体拆分为微服务;
|
|
673
|
+
- 2025-05:迁移认证机制到 OAuth2。
|
|
674
|
+
|
|
675
|
+
这些信息便于 AI 理解系统随时间的演进。
|
|
676
|
+
`;
|
|
677
|
+
|
|
678
|
+
const filePath = path.join(process.cwd(), OVERVIEW_FILE);
|
|
679
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
680
|
+
await fs.writeFile(filePath, template, 'utf8');
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// 生成 modules-index.yaml
|
|
684
|
+
async function generateModulesIndex(modules) {
|
|
685
|
+
const index = {
|
|
686
|
+
version: 1,
|
|
687
|
+
last_updated: new Date().toISOString(),
|
|
688
|
+
last_updated_by: 'cli',
|
|
689
|
+
modules: modules && modules.length > 0 ? modules.map(m => ({
|
|
690
|
+
name: m.name,
|
|
691
|
+
path: m.path || null,
|
|
692
|
+
root: m.root,
|
|
693
|
+
description: m.description || `${m.name} 模块(自动检测)`,
|
|
694
|
+
source: 'detected',
|
|
695
|
+
detected_at: new Date().toISOString(),
|
|
696
|
+
})) : [],
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
const filePath = path.join(process.cwd(), MODULES_INDEX_FILE);
|
|
700
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
701
|
+
await fs.writeFile(filePath, yaml.dump(index), 'utf8');
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// 主函数
|
|
705
|
+
export async function initOverview(options = {}) {
|
|
706
|
+
const { update = true, force = false, scanOnly = false, interactive = true } = options;
|
|
707
|
+
|
|
708
|
+
console.log(chalk.blue('🔍 正在检测项目信息...\n'));
|
|
709
|
+
|
|
710
|
+
// Step 1: 检测项目信息
|
|
711
|
+
const techStack = await detectTechStack();
|
|
712
|
+
const directoryStructure = await analyzeDirectoryStructure();
|
|
713
|
+
const modules = await detectModules();
|
|
714
|
+
|
|
715
|
+
// 显示检测结果摘要
|
|
716
|
+
console.log(chalk.green('✔ 技术栈检测完成'));
|
|
717
|
+
const techStackSummary = [];
|
|
718
|
+
if (techStack.frontend.length > 0) techStackSummary.push(`前端: ${techStack.frontend.join(', ')}`);
|
|
719
|
+
if (techStack.backend.length > 0) techStackSummary.push(`后端: ${techStack.backend.join(', ')}`);
|
|
720
|
+
if (techStack.database.length > 0) techStackSummary.push(`数据库: ${techStack.database.join(', ')}`);
|
|
721
|
+
if (techStackSummary.length > 0) {
|
|
722
|
+
console.log(chalk.gray(` 检测到: ${techStackSummary.join(' | ')}`));
|
|
723
|
+
} else {
|
|
724
|
+
console.log(chalk.yellow(' 未检测到技术栈信息'));
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
console.log(chalk.green('✔ 目录结构分析完成'));
|
|
728
|
+
if (directoryStructure.length > 0) {
|
|
729
|
+
console.log(chalk.gray(` 检测到 ${directoryStructure.length} 个关键目录`));
|
|
730
|
+
} else {
|
|
731
|
+
console.log(chalk.yellow(' 未检测到关键目录'));
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
console.log(chalk.green('✔ 模块识别完成'));
|
|
735
|
+
if (modules.length > 0) {
|
|
736
|
+
console.log(chalk.gray(` 检测到 ${modules.length} 个模块: ${modules.map(m => m.name).join(', ')}`));
|
|
737
|
+
} else {
|
|
738
|
+
console.log(chalk.yellow(' 未检测到模块'));
|
|
739
|
+
}
|
|
740
|
+
console.log('');
|
|
741
|
+
|
|
742
|
+
if (scanOnly) {
|
|
743
|
+
console.log(chalk.blue('📊 检测结果详情:\n'));
|
|
744
|
+
console.log('技术栈:', JSON.stringify(techStack, null, 2));
|
|
745
|
+
console.log('目录结构:', JSON.stringify(directoryStructure, null, 2));
|
|
746
|
+
console.log('模块:', JSON.stringify(modules, null, 2));
|
|
747
|
+
console.log(chalk.gray('\n💡 运行 "aodw init-overview --update" 来应用这些更改'));
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Step 2: 读取现有文件
|
|
752
|
+
const existing = await readExistingOverview();
|
|
753
|
+
const isFirstTime = !existing;
|
|
754
|
+
|
|
755
|
+
if (isFirstTime) {
|
|
756
|
+
console.log(chalk.blue('📝 首次初始化,生成初始文件...\n'));
|
|
757
|
+
} else {
|
|
758
|
+
console.log(chalk.blue('📝 检测到已有文件,进入更新模式...\n'));
|
|
759
|
+
|
|
760
|
+
if (interactive && !force) {
|
|
761
|
+
// 显示检测到的变化
|
|
762
|
+
console.log(chalk.yellow('📊 检测到的变化:'));
|
|
763
|
+
// TODO: 显示具体变化
|
|
764
|
+
console.log(chalk.gray(' (变化详情)\n'));
|
|
765
|
+
|
|
766
|
+
const { confirm } = await inquirer.prompt([{
|
|
767
|
+
type: 'confirm',
|
|
768
|
+
name: 'confirm',
|
|
769
|
+
message: '是否更新文件?',
|
|
770
|
+
default: true,
|
|
771
|
+
}]);
|
|
772
|
+
|
|
773
|
+
if (!confirm) {
|
|
774
|
+
console.log(chalk.gray('已取消更新'));
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// Step 3: 智能合并
|
|
781
|
+
const merged = await mergeOverview(existing, {
|
|
782
|
+
techStack,
|
|
783
|
+
directoryStructure,
|
|
784
|
+
modules,
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
// Step 4: 生成文件
|
|
788
|
+
await generateOverviewFile(merged, existing, modules);
|
|
789
|
+
await generateModulesIndex(modules);
|
|
790
|
+
|
|
791
|
+
console.log(chalk.green(`✔ 已生成 ${OVERVIEW_FILE}`));
|
|
792
|
+
console.log(chalk.green(`✔ 已生成 ${MODULES_INDEX_FILE}\n`));
|
|
793
|
+
|
|
794
|
+
if (isFirstTime) {
|
|
795
|
+
console.log(chalk.blue('💡 提示:运行 "初始化项目概览" 命令可以让 AI 帮助完善架构描述和模块职责'));
|
|
796
|
+
} else {
|
|
797
|
+
console.log(chalk.blue('💡 提示:如需完善架构描述,可运行 "初始化项目概览" 命令'));
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
|