autosnippet 3.3.4 → 3.3.6
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/README.md +174 -83
- package/config/constitution.yaml +2 -0
- package/dashboard/dist/assets/icons-D1aVZYFW.js +1 -0
- package/dashboard/dist/assets/index-CxHOu8Hd.css +1 -0
- package/dashboard/dist/assets/index-DDdAOpYT.js +128 -0
- package/dashboard/dist/index.html +3 -3
- package/dist/bin/api-server.js +1 -0
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +136 -9
- package/dist/lib/agent/AgentFactory.d.ts +0 -17
- package/dist/lib/agent/AgentFactory.js +1 -25
- package/dist/lib/agent/capabilities.d.ts +11 -0
- package/dist/lib/agent/capabilities.js +29 -5
- package/dist/lib/agent/context/ExplorationTracker.js +10 -1
- package/dist/lib/agent/context/exploration/ExplorationStrategies.d.ts +2 -0
- package/dist/lib/agent/context/exploration/ExplorationStrategies.js +2 -2
- package/dist/lib/agent/domain/insight-analyst.d.ts +47 -3
- package/dist/lib/agent/domain/insight-analyst.js +111 -11
- package/dist/lib/agent/domain/insight-evolver.d.ts +69 -0
- package/dist/lib/agent/domain/insight-evolver.js +230 -0
- package/dist/lib/agent/domain/insight-gate.d.ts +42 -0
- package/dist/lib/agent/domain/insight-gate.js +41 -0
- package/dist/lib/agent/domain/insight-producer.d.ts +27 -2
- package/dist/lib/agent/domain/insight-producer.js +60 -5
- package/dist/lib/agent/domain/scan-prompts.js +10 -7
- package/dist/lib/agent/memory/ActiveContext.d.ts +2 -28
- package/dist/lib/agent/memory/MemoryCoordinator.d.ts +2 -2
- package/dist/lib/agent/memory/SessionStore.d.ts +6 -12
- package/dist/lib/agent/memory/SessionStore.js +9 -15
- package/dist/lib/agent/memory/memory-flush-contract.d.ts +49 -0
- package/dist/lib/agent/memory/memory-flush-contract.js +16 -0
- package/dist/lib/agent/memory/session-store-schema.d.ts +20 -0
- package/dist/lib/agent/memory/session-store-schema.js +41 -0
- package/dist/lib/agent/presets.d.ts +89 -1
- package/dist/lib/agent/presets.js +53 -5
- package/dist/lib/agent/tools/_shared.d.ts +7 -15
- package/dist/lib/agent/tools/_shared.js +20 -21
- package/dist/lib/agent/tools/composite.d.ts +25 -22
- package/dist/lib/agent/tools/composite.js +108 -109
- package/dist/lib/agent/tools/evolution-tools.d.ts +145 -0
- package/dist/lib/agent/tools/evolution-tools.js +161 -0
- package/dist/lib/agent/tools/index.d.ts +163 -92
- package/dist/lib/agent/tools/index.js +9 -1
- package/dist/lib/agent/tools/lifecycle.d.ts +7 -1
- package/dist/lib/agent/tools/lifecycle.js +59 -75
- package/dist/lib/cli/AiScanService.js +1 -1
- package/dist/lib/cli/KnowledgeSyncService.d.ts +5 -1
- package/dist/lib/cli/KnowledgeSyncService.js +6 -3
- package/dist/lib/core/AstAnalyzer.d.ts +1 -0
- package/dist/lib/{service/bootstrap/DimensionCopyRegistry.d.ts → domain/dimension/DimensionCopy.d.ts} +2 -2
- package/dist/lib/{service/bootstrap/DimensionCopyRegistry.js → domain/dimension/DimensionCopy.js} +22 -72
- package/dist/lib/domain/dimension/DimensionRegistry.d.ts +54 -0
- package/dist/lib/domain/dimension/DimensionRegistry.js +620 -0
- package/dist/lib/domain/dimension/DimensionSop.d.ts +55 -0
- package/dist/lib/domain/dimension/DimensionSop.js +1604 -0
- package/dist/lib/domain/dimension/UnifiedDimension.d.ts +61 -0
- package/dist/lib/domain/dimension/UnifiedDimension.js +53 -0
- package/dist/lib/domain/dimension/index.d.ts +10 -0
- package/dist/lib/domain/dimension/index.js +9 -0
- package/dist/lib/domain/knowledge/FieldSpec.d.ts +1 -1
- package/dist/lib/domain/knowledge/FieldSpec.js +29 -16
- package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +33 -111
- package/dist/lib/domain/knowledge/KnowledgeEntry.js +27 -6
- package/dist/lib/domain/knowledge/KnowledgeRepository.d.ts +1 -0
- package/dist/lib/domain/knowledge/KnowledgeRepository.js +3 -0
- package/dist/lib/domain/knowledge/Lifecycle.js +1 -1
- package/dist/lib/domain/knowledge/StyleGuide.d.ts +1 -1
- package/dist/lib/domain/knowledge/StyleGuide.js +1 -1
- package/dist/lib/domain/knowledge/UnifiedValidator.js +15 -0
- package/dist/lib/domain/knowledge/values/Stats.d.ts +1 -1
- package/dist/lib/domain/knowledge/values/Stats.js +2 -2
- package/dist/lib/external/mcp/McpServer.js +4 -0
- package/dist/lib/external/mcp/handlers/TargetClassifier.d.ts +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/BootstrapSession.d.ts +8 -16
- package/dist/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +10 -10
- package/dist/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.d.ts +7 -0
- package/dist/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.js +20 -0
- package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.d.ts +52 -132
- package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +204 -17
- package/dist/lib/external/mcp/handlers/bootstrap/base-dimensions.d.ts +11 -75
- package/dist/lib/external/mcp/handlers/bootstrap/base-dimensions.js +40 -191
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.d.ts +13 -78
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +30 -52
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.d.ts +0 -1
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.d.ts +99 -12
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +172 -161
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +7 -17
- package/dist/lib/external/mcp/handlers/bootstrap/shared/async-fill-helpers.d.ts +46 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/async-fill-helpers.js +58 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/audit-helpers.d.ts +25 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/audit-helpers.js +47 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +50 -12
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +30 -10
- package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-text.js +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/shared/handler-types.d.ts +24 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/handler-types.js +14 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/panorama-utils.d.ts +14 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/panorama-utils.js +48 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/session-helpers.d.ts +21 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/session-helpers.js +45 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/skill-generator.d.ts +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/shared/target-file-map.d.ts +27 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/target-file-map.js +44 -0
- package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +14 -10
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +39 -51
- package/dist/lib/external/mcp/handlers/bootstrap-internal.d.ts +2 -0
- package/dist/lib/external/mcp/handlers/bootstrap-internal.js +115 -82
- package/dist/lib/external/mcp/handlers/consolidated.d.ts +4 -4
- package/dist/lib/external/mcp/handlers/consolidated.js +115 -162
- package/dist/lib/external/mcp/handlers/dimension-complete-external.js +69 -1
- package/dist/lib/external/mcp/handlers/evolve-external.d.ts +54 -0
- package/dist/lib/external/mcp/handlers/evolve-external.js +226 -0
- package/dist/lib/external/mcp/handlers/knowledge.js +26 -2
- package/dist/lib/external/mcp/handlers/rescan-external.d.ts +76 -0
- package/dist/lib/external/mcp/handlers/rescan-external.js +335 -0
- package/dist/lib/external/mcp/handlers/rescan-internal.d.ts +120 -0
- package/dist/lib/external/mcp/handlers/rescan-internal.js +359 -0
- package/dist/lib/external/mcp/handlers/search.d.ts +6 -5
- package/dist/lib/external/mcp/handlers/search.js +6 -5
- package/dist/lib/external/mcp/handlers/types.d.ts +2 -1
- package/dist/lib/external/mcp/handlers/wiki-external.js +2 -2
- package/dist/lib/external/mcp/tools.d.ts +8 -18
- package/dist/lib/external/mcp/tools.js +60 -3
- package/dist/lib/http/routes/knowledge.js +122 -1
- package/dist/lib/http/routes/modules.js +25 -3
- package/dist/lib/http/routes/panorama.js +16 -4
- package/dist/lib/infrastructure/cache/CacheCoordinator.d.ts +41 -0
- package/dist/lib/infrastructure/cache/CacheCoordinator.js +105 -0
- package/dist/lib/infrastructure/database/migrations/006_lifecycle_transition_events.d.ts +7 -0
- package/dist/lib/infrastructure/database/migrations/006_lifecycle_transition_events.js +28 -0
- package/dist/lib/infrastructure/vector/HnswVectorAdapter.js +1 -1
- package/dist/lib/injection/ServiceContainer.js +55 -0
- package/dist/lib/injection/ServiceMap.d.ts +8 -1
- package/dist/lib/injection/modules/InfraModule.js +4 -1
- package/dist/lib/injection/modules/KnowledgeModule.js +38 -1
- package/dist/lib/repository/evolution/ProposalRepository.d.ts +99 -0
- package/dist/lib/repository/evolution/ProposalRepository.js +255 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +4 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +16 -1
- package/dist/lib/service/bootstrap/BootstrapEventEmitter.d.ts +3 -2
- package/dist/lib/service/bootstrap/BootstrapEventEmitter.js +1 -1
- package/dist/lib/service/bootstrap/DeliveryVerifier.d.ts +51 -0
- package/dist/lib/service/bootstrap/DeliveryVerifier.js +163 -0
- package/dist/lib/service/bootstrap/UiStartupTasks.d.ts +22 -4
- package/dist/lib/service/bootstrap/UiStartupTasks.js +73 -5
- package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +54 -0
- package/dist/lib/service/bootstrap/bootstrap-event-types.js +10 -0
- package/dist/lib/service/cleanup/CleanupService.d.ts +85 -0
- package/dist/lib/service/cleanup/CleanupService.js +324 -0
- package/dist/lib/service/delivery/AgentInstructionsGenerator.js +39 -43
- package/dist/lib/service/delivery/FileProtection.d.ts +20 -0
- package/dist/lib/service/delivery/FileProtection.js +54 -0
- package/dist/lib/service/delivery/SkillsSyncer.js +16 -21
- package/dist/lib/service/evolution/ContentPatcher.d.ts +44 -0
- package/dist/lib/service/evolution/ContentPatcher.js +310 -0
- package/dist/lib/service/evolution/DecayDetector.d.ts +4 -3
- package/dist/lib/service/evolution/DecayDetector.js +97 -22
- package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +4 -2
- package/dist/lib/service/evolution/KnowledgeMetabolism.js +29 -2
- package/dist/lib/service/evolution/ProposalExecutor.d.ts +66 -0
- package/dist/lib/service/evolution/ProposalExecutor.js +424 -0
- package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +64 -0
- package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +458 -0
- package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +89 -0
- package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +492 -0
- package/dist/lib/service/evolution/StagingManager.js +5 -3
- package/dist/lib/service/evolution/createSupersedeProposal.d.ts +44 -0
- package/dist/lib/service/evolution/createSupersedeProposal.js +81 -0
- package/dist/lib/service/guard/ComplianceReporter.d.ts +4 -0
- package/dist/lib/service/guard/ComplianceReporter.js +51 -0
- package/dist/lib/service/guard/GuardCheckEngine.js +5 -4
- package/dist/lib/service/guard/GuardCrossFileChecks.js +2 -0
- package/dist/lib/service/guard/ReverseGuard.d.ts +1 -1
- package/dist/lib/service/guard/ReverseGuard.js +32 -2
- package/dist/lib/service/knowledge/ConfidenceRouter.js +1 -1
- package/dist/lib/service/knowledge/KnowledgeService.d.ts +11 -1
- package/dist/lib/service/knowledge/KnowledgeService.js +44 -4
- package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +225 -0
- package/dist/lib/service/knowledge/RecipeProductionGateway.js +384 -0
- package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +2 -0
- package/dist/lib/service/knowledge/SourceRefReconciler.js +48 -0
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +3 -2
- package/dist/lib/service/panorama/DimensionAnalyzer.js +15 -140
- package/dist/lib/service/search/BM25Scorer.d.ts +2 -2
- package/dist/lib/service/search/SearchEngine.d.ts +11 -10
- package/dist/lib/service/search/SearchEngine.js +38 -36
- package/dist/lib/service/search/SearchTypes.d.ts +14 -8
- package/dist/lib/service/search/SearchTypes.js +1 -1
- package/dist/lib/service/search/tokenizer.d.ts +1 -1
- package/dist/lib/service/search/tokenizer.js +2 -2
- package/dist/lib/shared/schemas/common.d.ts +4 -4
- package/dist/lib/shared/schemas/http-requests.d.ts +12 -1
- package/dist/lib/shared/schemas/http-requests.js +8 -0
- package/dist/lib/shared/schemas/mcp-tools.d.ts +33 -2
- package/dist/lib/shared/schemas/mcp-tools.js +42 -0
- package/dist/lib/types/evolution.d.ts +135 -0
- package/dist/lib/types/evolution.js +6 -0
- package/dist/lib/types/graph-shared.d.ts +25 -0
- package/dist/lib/types/graph-shared.js +7 -0
- package/dist/lib/types/knowledge-wire.d.ts +131 -0
- package/dist/lib/types/knowledge-wire.js +7 -0
- package/dist/lib/types/project-snapshot-builder.d.ts +19 -0
- package/dist/lib/types/project-snapshot-builder.js +189 -0
- package/dist/lib/types/project-snapshot.d.ts +399 -0
- package/dist/lib/types/project-snapshot.js +17 -0
- package/dist/lib/types/search-wire.d.ts +46 -0
- package/dist/lib/types/search-wire.js +7 -0
- package/dist/lib/types/snapshot-views.d.ts +58 -0
- package/dist/lib/types/snapshot-views.js +103 -0
- package/package.json +1 -1
- package/skills/autosnippet-recipes/SKILL.md +1 -1
- package/templates/instructions/agent-static.md +2 -0
- package/templates/instructions/conventions.md +3 -1
- package/templates/recipes-setup/README.md +2 -2
- package/dashboard/dist/assets/icons-BJ2mUBi8.js +0 -1
- package/dashboard/dist/assets/index-B659K9t5.js +0 -128
- package/dashboard/dist/assets/index-NCm40PMD.css +0 -1
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.d.ts +0 -169
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +0 -727
- package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.d.ts +0 -370
- package/dist/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.js +0 -821
|
@@ -1,727 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* noAiFallback.js — AI 不可用时的规则化降级知识提取
|
|
3
|
-
*
|
|
4
|
-
* 当 AgentRuntime / AI Provider 不可用时,从 Phase 1-4 的结构化数据中
|
|
5
|
-
* 提取基础知识候选和 Project Skill,覆盖以下维度:
|
|
6
|
-
*
|
|
7
|
-
* ✅ project-profile — 从 langStats + depGraph + targets 构建项目技术画像
|
|
8
|
-
* ✅ architecture — 从 depGraph + targets 推断层级/模块关系
|
|
9
|
-
* ✅ code-standard — 从 AST 统计推断命名约定和代码风格
|
|
10
|
-
* ✅ best-practice — 从 Guard 违规推断反模式
|
|
11
|
-
* ✅ agent-guidelines — 从 Guard 高频违规 + 语言特性生成 Agent 注意事项
|
|
12
|
-
*
|
|
13
|
-
* 产出质量标注为 `source: 'rule-based-fallback'`,区别于 AI 分析产出。
|
|
14
|
-
*/
|
|
15
|
-
import Logger from '#infra/logging/Logger.js';
|
|
16
|
-
const logger = Logger.getInstance();
|
|
17
|
-
/**
|
|
18
|
-
* 主入口 — 当 AI 不可用时调用
|
|
19
|
-
*
|
|
20
|
-
* @param fillContext 与 fillDimensionsV3 相同的上下文
|
|
21
|
-
* @returns >}
|
|
22
|
-
*/
|
|
23
|
-
export async function runNoAiFallback(fillContext) {
|
|
24
|
-
const {
|
|
25
|
-
// ctx and projectRoot are part of fillContext API but unused in fallback path
|
|
26
|
-
dimensions, depGraphData, guardAudit, langStats, primaryLang, astProjectSummary, taskManager, sessionId, } = fillContext;
|
|
27
|
-
const t0 = Date.now();
|
|
28
|
-
logger.info('[Bootstrap-fallback] Starting rule-based fallback (no AI)');
|
|
29
|
-
const candidates = [];
|
|
30
|
-
const skills = [];
|
|
31
|
-
const report = {
|
|
32
|
-
dimensionsProcessed: 0,
|
|
33
|
-
candidatesCreated: 0,
|
|
34
|
-
skillsCreated: 0,
|
|
35
|
-
errors: [],
|
|
36
|
-
};
|
|
37
|
-
// ── 收集原始数据 ──
|
|
38
|
-
const allFiles = fillContext.allFiles || [];
|
|
39
|
-
const targetFileMap = fillContext.targetFileMap || {};
|
|
40
|
-
const allTargets = Object.keys(targetFileMap);
|
|
41
|
-
// ── 1. Project Profile ──
|
|
42
|
-
try {
|
|
43
|
-
const profile = _buildProjectProfile({
|
|
44
|
-
langStats,
|
|
45
|
-
primaryLang,
|
|
46
|
-
depGraphData,
|
|
47
|
-
allTargets,
|
|
48
|
-
allFiles,
|
|
49
|
-
astProjectSummary,
|
|
50
|
-
});
|
|
51
|
-
if (profile) {
|
|
52
|
-
candidates.push(profile);
|
|
53
|
-
skills.push(_wrapAsSkill('project-profile', '项目技术画像', profile.content.markdown));
|
|
54
|
-
report.candidatesCreated++;
|
|
55
|
-
report.skillsCreated++;
|
|
56
|
-
}
|
|
57
|
-
_markDimDone(taskManager, sessionId, 'project-profile', 'fallback');
|
|
58
|
-
}
|
|
59
|
-
catch (e) {
|
|
60
|
-
report.errors.push({
|
|
61
|
-
dim: 'project-profile',
|
|
62
|
-
error: e instanceof Error ? e.message : String(e),
|
|
63
|
-
});
|
|
64
|
-
_markDimDone(taskManager, sessionId, 'project-profile', 'error');
|
|
65
|
-
}
|
|
66
|
-
// ── 2. Architecture ──
|
|
67
|
-
try {
|
|
68
|
-
const arch = _buildArchitecture({
|
|
69
|
-
depGraphData,
|
|
70
|
-
allTargets,
|
|
71
|
-
targetFileMap,
|
|
72
|
-
primaryLang,
|
|
73
|
-
astProjectSummary,
|
|
74
|
-
});
|
|
75
|
-
if (arch) {
|
|
76
|
-
candidates.push(arch);
|
|
77
|
-
skills.push(_wrapAsSkill('architecture', '模块架构', arch.content.markdown));
|
|
78
|
-
report.candidatesCreated++;
|
|
79
|
-
report.skillsCreated++;
|
|
80
|
-
}
|
|
81
|
-
_markDimDone(taskManager, sessionId, 'architecture', 'fallback');
|
|
82
|
-
}
|
|
83
|
-
catch (e) {
|
|
84
|
-
report.errors.push({ dim: 'architecture', error: e instanceof Error ? e.message : String(e) });
|
|
85
|
-
_markDimDone(taskManager, sessionId, 'architecture', 'error');
|
|
86
|
-
}
|
|
87
|
-
// ── 3. Code Standard ──
|
|
88
|
-
try {
|
|
89
|
-
const standard = _buildCodeStandard({ astProjectSummary, primaryLang, allFiles });
|
|
90
|
-
if (standard) {
|
|
91
|
-
candidates.push(standard);
|
|
92
|
-
skills.push(_wrapAsSkill('code-standard', '代码规范', standard.content.markdown));
|
|
93
|
-
report.candidatesCreated++;
|
|
94
|
-
report.skillsCreated++;
|
|
95
|
-
}
|
|
96
|
-
_markDimDone(taskManager, sessionId, 'code-standard', 'fallback');
|
|
97
|
-
}
|
|
98
|
-
catch (e) {
|
|
99
|
-
report.errors.push({ dim: 'code-standard', error: e instanceof Error ? e.message : String(e) });
|
|
100
|
-
_markDimDone(taskManager, sessionId, 'code-standard', 'error');
|
|
101
|
-
}
|
|
102
|
-
// ── 4. Best Practice (from Guard violations) ──
|
|
103
|
-
try {
|
|
104
|
-
const bp = _buildBestPractice({ guardAudit, primaryLang });
|
|
105
|
-
if (bp) {
|
|
106
|
-
candidates.push(bp);
|
|
107
|
-
skills.push(_wrapAsSkill('best-practice', '最佳实践', bp.content.markdown));
|
|
108
|
-
report.candidatesCreated++;
|
|
109
|
-
report.skillsCreated++;
|
|
110
|
-
}
|
|
111
|
-
_markDimDone(taskManager, sessionId, 'best-practice', 'fallback');
|
|
112
|
-
}
|
|
113
|
-
catch (e) {
|
|
114
|
-
report.errors.push({ dim: 'best-practice', error: e instanceof Error ? e.message : String(e) });
|
|
115
|
-
_markDimDone(taskManager, sessionId, 'best-practice', 'error');
|
|
116
|
-
}
|
|
117
|
-
// ── 5. Agent Guidelines ──
|
|
118
|
-
try {
|
|
119
|
-
const guidelines = _buildAgentGuidelines({ guardAudit, primaryLang, astProjectSummary });
|
|
120
|
-
if (guidelines) {
|
|
121
|
-
candidates.push(guidelines);
|
|
122
|
-
skills.push(_wrapAsSkill('agent-guidelines', '项目开发强制规范', guidelines.content.markdown));
|
|
123
|
-
report.candidatesCreated++;
|
|
124
|
-
report.skillsCreated++;
|
|
125
|
-
}
|
|
126
|
-
_markDimDone(taskManager, sessionId, 'agent-guidelines', 'fallback');
|
|
127
|
-
}
|
|
128
|
-
catch (e) {
|
|
129
|
-
report.errors.push({
|
|
130
|
-
dim: 'agent-guidelines',
|
|
131
|
-
error: e instanceof Error ? e.message : String(e),
|
|
132
|
-
});
|
|
133
|
-
_markDimDone(taskManager, sessionId, 'agent-guidelines', 'error');
|
|
134
|
-
}
|
|
135
|
-
// ── 标记剩余未处理维度 ──
|
|
136
|
-
const processedDims = new Set([
|
|
137
|
-
'project-profile',
|
|
138
|
-
'architecture',
|
|
139
|
-
'code-standard',
|
|
140
|
-
'best-practice',
|
|
141
|
-
'agent-guidelines',
|
|
142
|
-
]);
|
|
143
|
-
for (const dim of dimensions) {
|
|
144
|
-
if (!processedDims.has(dim.id)) {
|
|
145
|
-
_markDimDone(taskManager, sessionId, dim.id, 'skipped-no-ai');
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
report.dimensionsProcessed = processedDims.size;
|
|
149
|
-
const elapsed = Date.now() - t0;
|
|
150
|
-
logger.info(`[Bootstrap-fallback] Complete: ${report.candidatesCreated} candidates, ${report.skillsCreated} skills in ${elapsed}ms`);
|
|
151
|
-
return { candidates, skills, report };
|
|
152
|
-
}
|
|
153
|
-
// ═══════════════════════════════════════════════════════════
|
|
154
|
-
// 维度构建器
|
|
155
|
-
// ═══════════════════════════════════════════════════════════
|
|
156
|
-
function _buildProjectProfile({ langStats, primaryLang, depGraphData, allTargets, allFiles, astProjectSummary, }) {
|
|
157
|
-
const lines = ['## 项目技术画像', ''];
|
|
158
|
-
// 语言统计
|
|
159
|
-
const sortedLangs = Object.entries(langStats || {})
|
|
160
|
-
.sort(([, a], [, b]) => b - a)
|
|
161
|
-
.slice(0, 8);
|
|
162
|
-
if (sortedLangs.length > 0) {
|
|
163
|
-
lines.push('### 语言分布', '');
|
|
164
|
-
lines.push('| 语言 | 文件数 | 占比 |');
|
|
165
|
-
lines.push('|------|--------|------|');
|
|
166
|
-
const total = sortedLangs.reduce((s, [, c]) => s + c, 0);
|
|
167
|
-
for (const [lang, count] of sortedLangs) {
|
|
168
|
-
lines.push(`| ${lang} | ${count} | ${((count / total) * 100).toFixed(1)}% |`);
|
|
169
|
-
}
|
|
170
|
-
lines.push('');
|
|
171
|
-
}
|
|
172
|
-
// 模块结构
|
|
173
|
-
if (allTargets.length > 0) {
|
|
174
|
-
lines.push(`### 模块结构`, '');
|
|
175
|
-
lines.push(`项目包含 **${allTargets.length}** 个模块/Target:`, '');
|
|
176
|
-
for (const t of allTargets.slice(0, 15)) {
|
|
177
|
-
const tName = t;
|
|
178
|
-
const fileCount = Array.isArray(allFiles)
|
|
179
|
-
? allFiles.filter((f) => f.targetName === tName).length
|
|
180
|
-
: 0;
|
|
181
|
-
lines.push(`- \`${tName}\` (${fileCount} files)`);
|
|
182
|
-
}
|
|
183
|
-
if (allTargets.length > 15) {
|
|
184
|
-
lines.push(`- ...及 ${allTargets.length - 15} 个其他模块`);
|
|
185
|
-
}
|
|
186
|
-
lines.push('');
|
|
187
|
-
}
|
|
188
|
-
// 依赖关系
|
|
189
|
-
if (depGraphData && depGraphData.edges.length > 0) {
|
|
190
|
-
lines.push('### 依赖关系', '');
|
|
191
|
-
lines.push(`共 ${depGraphData.edges.length} 条模块间依赖关系。`, '');
|
|
192
|
-
}
|
|
193
|
-
// AST 统计
|
|
194
|
-
if (astProjectSummary) {
|
|
195
|
-
lines.push('### 代码结构统计', '');
|
|
196
|
-
const m = astProjectSummary.projectMetrics || {};
|
|
197
|
-
lines.push(`- 类/结构体: ${astProjectSummary.classes?.length || 0}`);
|
|
198
|
-
lines.push(`- 协议/接口: ${astProjectSummary.protocols?.length || 0}`);
|
|
199
|
-
lines.push(`- 方法总数: ${m.totalMethods || 0}`);
|
|
200
|
-
if (m.maxNestingDepth) {
|
|
201
|
-
lines.push(`- 最大嵌套深度: ${m.maxNestingDepth}`);
|
|
202
|
-
}
|
|
203
|
-
if (m.complexMethods && m.complexMethods.length > 0) {
|
|
204
|
-
lines.push(`- 高复杂度方法: ${m.complexMethods.length}`);
|
|
205
|
-
}
|
|
206
|
-
if (m.longMethods && m.longMethods.length > 0) {
|
|
207
|
-
lines.push(`- 过长方法 (>50 行): ${m.longMethods.length}`);
|
|
208
|
-
}
|
|
209
|
-
lines.push('');
|
|
210
|
-
}
|
|
211
|
-
// 生成 coreCode (P3): 技术栈摘要
|
|
212
|
-
const codeParts = [];
|
|
213
|
-
if (sortedLangs.length > 0) {
|
|
214
|
-
codeParts.push('// 语言分布');
|
|
215
|
-
for (const [lang, count] of sortedLangs.slice(0, 5)) {
|
|
216
|
-
codeParts.push(`// ${lang}: ${count} files`);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
if (astProjectSummary) {
|
|
220
|
-
codeParts.push(`// 类: ${astProjectSummary.classes?.length || 0}, 协议: ${astProjectSummary.protocols?.length || 0}, 方法: ${astProjectSummary.projectMetrics?.totalMethods || 0}`);
|
|
221
|
-
}
|
|
222
|
-
if (allTargets.length > 0) {
|
|
223
|
-
codeParts.push(`// Target: ${allTargets
|
|
224
|
-
.slice(0, 8)
|
|
225
|
-
.map((t) => t)
|
|
226
|
-
.join(', ')}`);
|
|
227
|
-
}
|
|
228
|
-
const markdown = lines.join('\n');
|
|
229
|
-
if (markdown.length < 50) {
|
|
230
|
-
return null;
|
|
231
|
-
}
|
|
232
|
-
return _makeCandidate({
|
|
233
|
-
title: `项目技术画像 — ${primaryLang}`,
|
|
234
|
-
knowledgeType: 'architecture',
|
|
235
|
-
category: 'Architecture',
|
|
236
|
-
language: primaryLang,
|
|
237
|
-
markdown,
|
|
238
|
-
rationale: '基于 Bootstrap 扫描的文件统计、AST 分析和依赖图谱自动生成',
|
|
239
|
-
coreCode: codeParts.join('\n'),
|
|
240
|
-
trigger: '项目技术画像',
|
|
241
|
-
doClause: '了解项目技术栈和模块结构后再开始编码',
|
|
242
|
-
dontClause: '',
|
|
243
|
-
whenClause: '初次接触项目或需要了解全局架构时',
|
|
244
|
-
sources: ['bootstrap-scan'],
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
function _buildArchitecture({ depGraphData, allTargets, targetFileMap, primaryLang, astProjectSummary, }) {
|
|
248
|
-
if (!(depGraphData && depGraphData.edges.length) && allTargets.length < 2) {
|
|
249
|
-
return null;
|
|
250
|
-
}
|
|
251
|
-
const lines = ['## 模块架构', ''];
|
|
252
|
-
// 依赖图
|
|
253
|
-
if (depGraphData && depGraphData.edges.length > 0) {
|
|
254
|
-
lines.push('### 模块依赖关系', '');
|
|
255
|
-
lines.push('```');
|
|
256
|
-
const seen = new Set();
|
|
257
|
-
for (const e of depGraphData.edges.slice(0, 30)) {
|
|
258
|
-
const from = typeof e.from === 'string' ? e.from : e.source;
|
|
259
|
-
const to = typeof e.to === 'string' ? e.to : e.target;
|
|
260
|
-
if (from && to) {
|
|
261
|
-
const key = `${from} → ${to}`;
|
|
262
|
-
if (!seen.has(key)) {
|
|
263
|
-
lines.push(key);
|
|
264
|
-
seen.add(key);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
lines.push('```');
|
|
269
|
-
lines.push('');
|
|
270
|
-
// 入度/出度分析
|
|
271
|
-
const inDeg = {};
|
|
272
|
-
const outDeg = {};
|
|
273
|
-
for (const e of depGraphData.edges) {
|
|
274
|
-
const from = typeof e.from === 'string' ? e.from : e.source;
|
|
275
|
-
const to = typeof e.to === 'string' ? e.to : e.target;
|
|
276
|
-
if (from) {
|
|
277
|
-
outDeg[from] = (outDeg[from] || 0) + 1;
|
|
278
|
-
}
|
|
279
|
-
if (to) {
|
|
280
|
-
inDeg[to] = (inDeg[to] || 0) + 1;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
// 核心模块(被依赖最多)
|
|
284
|
-
const coreModules = Object.entries(inDeg)
|
|
285
|
-
.sort(([, a], [, b]) => b - a)
|
|
286
|
-
.slice(0, 5);
|
|
287
|
-
if (coreModules.length > 0) {
|
|
288
|
-
lines.push('### 核心模块(被依赖最多)', '');
|
|
289
|
-
for (const [mod, deg] of coreModules) {
|
|
290
|
-
lines.push(`- \`${mod}\` — 被 ${deg} 个模块依赖`);
|
|
291
|
-
}
|
|
292
|
-
lines.push('');
|
|
293
|
-
}
|
|
294
|
-
// 叶子模块(不被任何模块依赖)
|
|
295
|
-
const leafModules = allTargets.filter((t) => !inDeg[t] && outDeg[t]);
|
|
296
|
-
if (leafModules.length > 0) {
|
|
297
|
-
lines.push('### 叶子模块(仅依赖他人)', '');
|
|
298
|
-
for (const mod of leafModules.slice(0, 8)) {
|
|
299
|
-
lines.push(`- \`${mod}\``);
|
|
300
|
-
}
|
|
301
|
-
lines.push('');
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
// P5: ObjC Category 信息
|
|
305
|
-
const categories = astProjectSummary?.categories || [];
|
|
306
|
-
if (categories.length > 0) {
|
|
307
|
-
lines.push('### ObjC Category 扩展', '');
|
|
308
|
-
// 按基类分组
|
|
309
|
-
const byBase = {};
|
|
310
|
-
for (const cat of categories) {
|
|
311
|
-
const base = cat.className || cat.baseClass || cat.name?.split('(')[0] || 'Unknown';
|
|
312
|
-
if (!byBase[base]) {
|
|
313
|
-
byBase[base] = [];
|
|
314
|
-
}
|
|
315
|
-
byBase[base].push(cat);
|
|
316
|
-
}
|
|
317
|
-
const sortedBases = Object.entries(byBase).sort(([, a], [, b]) => b.length - a.length);
|
|
318
|
-
lines.push(`共 **${categories.length}** 个 Category,分布在 **${sortedBases.length}** 个基类上:`, '');
|
|
319
|
-
for (const [base, cats] of sortedBases.slice(0, 10)) {
|
|
320
|
-
const catNames = cats
|
|
321
|
-
.map((c) => c.categoryName || c.name || '')
|
|
322
|
-
.filter(Boolean)
|
|
323
|
-
.slice(0, 5)
|
|
324
|
-
.join(', ');
|
|
325
|
-
const loc = cats[0]?.file ? ` (来源: ${_basename(cats[0].file)})` : '';
|
|
326
|
-
lines.push(`- \`${base}\` — ${cats.length} 个 Category${catNames ? `: ${catNames}` : ''}${loc}`);
|
|
327
|
-
}
|
|
328
|
-
if (sortedBases.length > 10) {
|
|
329
|
-
lines.push(`- ...及 ${sortedBases.length - 10} 个其他基类`);
|
|
330
|
-
}
|
|
331
|
-
lines.push('');
|
|
332
|
-
}
|
|
333
|
-
// 生成代码块 (P3)
|
|
334
|
-
const codeLines = [];
|
|
335
|
-
if (depGraphData && depGraphData.edges.length > 0) {
|
|
336
|
-
codeLines.push(`// 模块依赖关系 (共 ${depGraphData.edges.length} 条)`);
|
|
337
|
-
const seen = new Set();
|
|
338
|
-
for (const e of depGraphData.edges.slice(0, 15)) {
|
|
339
|
-
const from = typeof e.from === 'string' ? e.from : e.source;
|
|
340
|
-
const to = typeof e.to === 'string' ? e.to : e.target;
|
|
341
|
-
if (from && to) {
|
|
342
|
-
const key = `${from} -> ${to}`;
|
|
343
|
-
if (!seen.has(key)) {
|
|
344
|
-
codeLines.push(key);
|
|
345
|
-
seen.add(key);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
const markdown = lines.join('\n');
|
|
351
|
-
if (markdown.length < 80) {
|
|
352
|
-
return null;
|
|
353
|
-
}
|
|
354
|
-
return _makeCandidate({
|
|
355
|
-
title: '模块架构与依赖关系',
|
|
356
|
-
knowledgeType: 'architecture',
|
|
357
|
-
category: 'Architecture',
|
|
358
|
-
language: primaryLang,
|
|
359
|
-
markdown,
|
|
360
|
-
rationale: '基于项目依赖图谱和模块扫描自动生成',
|
|
361
|
-
coreCode: codeLines.length > 1 ? codeLines.join('\n') : '',
|
|
362
|
-
trigger: '模块架构',
|
|
363
|
-
doClause: '遵循现有模块边界,新功能放入对应模块',
|
|
364
|
-
dontClause: '',
|
|
365
|
-
whenClause: '新建文件或模块时',
|
|
366
|
-
sources: ['bootstrap-scan'],
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
function _buildCodeStandard({ astProjectSummary, primaryLang, allFiles, }) {
|
|
370
|
-
if (!astProjectSummary) {
|
|
371
|
-
return null;
|
|
372
|
-
}
|
|
373
|
-
const lines = ['## 代码规范发现', ''];
|
|
374
|
-
const classes = astProjectSummary.classes || [];
|
|
375
|
-
const methods = [];
|
|
376
|
-
// 从 file 级聚合方法
|
|
377
|
-
if (astProjectSummary.files) {
|
|
378
|
-
for (const f of astProjectSummary.files) {
|
|
379
|
-
if (f.methods) {
|
|
380
|
-
methods.push(...f.methods);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
// 命名模式分析
|
|
385
|
-
let usedSuffixes = [];
|
|
386
|
-
if (classes.length > 0) {
|
|
387
|
-
lines.push('### 类命名模式', '');
|
|
388
|
-
// 检测常见后缀
|
|
389
|
-
const suffixCounts = {};
|
|
390
|
-
const COMMON_SUFFIXES = [
|
|
391
|
-
'Service',
|
|
392
|
-
'Manager',
|
|
393
|
-
'Controller',
|
|
394
|
-
'Handler',
|
|
395
|
-
'Provider',
|
|
396
|
-
'Repository',
|
|
397
|
-
'Factory',
|
|
398
|
-
'Helper',
|
|
399
|
-
'Utils',
|
|
400
|
-
'ViewModel',
|
|
401
|
-
'View',
|
|
402
|
-
'Model',
|
|
403
|
-
'Store',
|
|
404
|
-
'Client',
|
|
405
|
-
'Adapter',
|
|
406
|
-
'Impl',
|
|
407
|
-
];
|
|
408
|
-
for (const cls of classes) {
|
|
409
|
-
for (const sfx of COMMON_SUFFIXES) {
|
|
410
|
-
if (cls.name?.endsWith(sfx)) {
|
|
411
|
-
suffixCounts[sfx] = (suffixCounts[sfx] || 0) + 1;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
usedSuffixes = Object.entries(suffixCounts)
|
|
416
|
-
.filter(([, c]) => c > 0)
|
|
417
|
-
.sort(([, a], [, b]) => b - a);
|
|
418
|
-
if (usedSuffixes.length > 0) {
|
|
419
|
-
lines.push('| 后缀约定 | 类数量 | 推断角色 |');
|
|
420
|
-
lines.push('|----------|--------|----------|');
|
|
421
|
-
const roleMap = {
|
|
422
|
-
Service: '业务服务',
|
|
423
|
-
Manager: '管理器',
|
|
424
|
-
Controller: '控制器/路由',
|
|
425
|
-
Handler: '事件/请求处理',
|
|
426
|
-
Provider: '数据/功能提供者',
|
|
427
|
-
Repository: '数据访问',
|
|
428
|
-
Factory: '工厂',
|
|
429
|
-
Helper: '辅助工具',
|
|
430
|
-
Utils: '工具类',
|
|
431
|
-
ViewModel: '视图模型',
|
|
432
|
-
View: '视图/UI',
|
|
433
|
-
Model: '数据模型',
|
|
434
|
-
Store: '状态存储',
|
|
435
|
-
Client: 'API 客户端',
|
|
436
|
-
Adapter: '适配器',
|
|
437
|
-
Impl: '接口实现',
|
|
438
|
-
};
|
|
439
|
-
for (const [sfx, count] of usedSuffixes) {
|
|
440
|
-
lines.push(`| *${sfx} | ${count} | ${roleMap[sfx] || sfx} |`);
|
|
441
|
-
}
|
|
442
|
-
lines.push('');
|
|
443
|
-
}
|
|
444
|
-
lines.push(`共发现 **${classes.length}** 个类/结构体。`, '');
|
|
445
|
-
}
|
|
446
|
-
// 代码质量指标
|
|
447
|
-
const metrics = astProjectSummary.projectMetrics;
|
|
448
|
-
if (metrics) {
|
|
449
|
-
lines.push('### 代码质量指标', '');
|
|
450
|
-
if (metrics.avgMethodsPerClass) {
|
|
451
|
-
lines.push(`- 平均方法数/类: ${metrics.avgMethodsPerClass.toFixed(1)}`);
|
|
452
|
-
}
|
|
453
|
-
if (metrics.complexMethods && metrics.complexMethods.length > 0) {
|
|
454
|
-
lines.push(`- 高圈复杂度方法: ${metrics.complexMethods.length} 个`);
|
|
455
|
-
for (const m of metrics.complexMethods.slice(0, 5)) {
|
|
456
|
-
const loc = m.file ? ` (来源: ${_basename(m.file)}${m.line ? `:${m.line}` : ''})` : '';
|
|
457
|
-
lines.push(` - \`${m.className ? `${m.className}.` : ''}${m.name}\` — complexity ${m.complexity}${loc}`);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
if (metrics.longMethods && metrics.longMethods.length > 0) {
|
|
461
|
-
lines.push(`- 过长方法: ${metrics.longMethods.length} 个`);
|
|
462
|
-
for (const m of metrics.longMethods.slice(0, 5)) {
|
|
463
|
-
const bodyLen = m.lines || m.bodyLines || '?';
|
|
464
|
-
const loc = m.file ? ` (来源: ${_basename(m.file)}${m.line ? `:${m.line}` : ''})` : '';
|
|
465
|
-
lines.push(` - \`${m.className ? `${m.className}.` : ''}${m.name}\` — ${bodyLen} 行${loc}`);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
lines.push('');
|
|
469
|
-
}
|
|
470
|
-
// 收集源文件引用 (P4)
|
|
471
|
-
const sourceFiles = new Set();
|
|
472
|
-
if (metrics) {
|
|
473
|
-
for (const m of (metrics.longMethods || []).concat(metrics.complexMethods || [])) {
|
|
474
|
-
if (m.file) {
|
|
475
|
-
sourceFiles.add(m.file);
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
// 生成 coreCode (P3): 命名规范摘要
|
|
480
|
-
const codeLines = [];
|
|
481
|
-
if (usedSuffixes?.length > 0) {
|
|
482
|
-
codeLines.push('// 命名约定示例');
|
|
483
|
-
for (const [sfx, count] of usedSuffixes.slice(0, 6)) {
|
|
484
|
-
codeLines.push(`// *${sfx} → ${count} 个类使用此后缀`);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
if (metrics && metrics.longMethods && metrics.longMethods.length > 0) {
|
|
488
|
-
codeLines.push('');
|
|
489
|
-
codeLines.push('// 过长方法示例 (应重构)');
|
|
490
|
-
for (const m of metrics.longMethods.slice(0, 3)) {
|
|
491
|
-
const bodyLen = m.lines || m.bodyLines || '?';
|
|
492
|
-
codeLines.push(`// ${m.className ? `${m.className}.` : ''}${m.name} — ${bodyLen} 行`);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
const markdown = lines.join('\n');
|
|
496
|
-
if (markdown.length < 80) {
|
|
497
|
-
return null;
|
|
498
|
-
}
|
|
499
|
-
return _makeCandidate({
|
|
500
|
-
title: '代码规范与命名约定',
|
|
501
|
-
knowledgeType: 'code-standard',
|
|
502
|
-
category: 'Architecture',
|
|
503
|
-
language: primaryLang,
|
|
504
|
-
markdown,
|
|
505
|
-
rationale: '基于 AST 分析的类名、方法统计和代码复杂度指标自动生成',
|
|
506
|
-
coreCode: codeLines.join('\n'),
|
|
507
|
-
trigger: '代码规范',
|
|
508
|
-
doClause: '遵循项目现有命名约定,新类名使用已有后缀模式',
|
|
509
|
-
dontClause: '不要写超过 50 行的方法,不要超过 4 层嵌套',
|
|
510
|
-
whenClause: '新建类或方法时',
|
|
511
|
-
sources: sourceFiles.size > 0 ? [...sourceFiles].slice(0, 10) : ['bootstrap-scan'],
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
function _buildBestPractice({ guardAudit, primaryLang, }) {
|
|
515
|
-
if (!guardAudit?.files?.length) {
|
|
516
|
-
return null;
|
|
517
|
-
}
|
|
518
|
-
// 聚合所有违规
|
|
519
|
-
const ruleStats = {};
|
|
520
|
-
for (const f of guardAudit.files) {
|
|
521
|
-
for (const v of f.violations || []) {
|
|
522
|
-
if (!ruleStats[v.ruleId]) {
|
|
523
|
-
ruleStats[v.ruleId] = {
|
|
524
|
-
count: 0,
|
|
525
|
-
severity: v.severity,
|
|
526
|
-
message: v.message,
|
|
527
|
-
files: new Set(),
|
|
528
|
-
fixSuggestion: v.fixSuggestion || null,
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
ruleStats[v.ruleId].count++;
|
|
532
|
-
ruleStats[v.ruleId].files.add(f.filePath);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
const sortedRules = Object.entries(ruleStats).sort(([, a], [, b]) => b.count - a.count);
|
|
536
|
-
if (sortedRules.length === 0) {
|
|
537
|
-
return null;
|
|
538
|
-
}
|
|
539
|
-
const lines = ['## 最佳实践(基于 Guard 审计)', ''];
|
|
540
|
-
lines.push(`Bootstrap 扫描发现 **${guardAudit.summary?.totalViolations || 0}** 个违规,` +
|
|
541
|
-
`涉及 **${sortedRules.length}** 条规则:`, '');
|
|
542
|
-
lines.push('### 高频违规(应优先修复)', '');
|
|
543
|
-
lines.push('| 规则 | 严重性 | 违规数 | 影响文件数 | 说明 |');
|
|
544
|
-
lines.push('|------|--------|--------|-----------|------|');
|
|
545
|
-
for (const [ruleId, stat] of sortedRules.slice(0, 15)) {
|
|
546
|
-
lines.push(`| \`${ruleId}\` | ${stat.severity} | ${stat.count} | ${stat.files.size} | ${stat.message} |`);
|
|
547
|
-
}
|
|
548
|
-
lines.push('');
|
|
549
|
-
// 修复建议
|
|
550
|
-
const withFix = sortedRules.filter(([, s]) => s.fixSuggestion);
|
|
551
|
-
if (withFix.length > 0) {
|
|
552
|
-
lines.push('### 修复建议', '');
|
|
553
|
-
for (const [ruleId, stat] of withFix.slice(0, 10)) {
|
|
554
|
-
lines.push(`- **${ruleId}**: ${stat.fixSuggestion}`);
|
|
555
|
-
}
|
|
556
|
-
lines.push('');
|
|
557
|
-
}
|
|
558
|
-
// 收集违规文件路径 (P4)
|
|
559
|
-
const violationFiles = new Set();
|
|
560
|
-
for (const f of guardAudit.files) {
|
|
561
|
-
if (f.violations?.length > 0 && f.filePath) {
|
|
562
|
-
violationFiles.add(f.filePath);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
// 生成 coreCode (P3): Guard 规则摘要
|
|
566
|
-
const codeLines = ['// Guard 高频违规规则'];
|
|
567
|
-
for (const [ruleId, stat] of sortedRules.slice(0, 5)) {
|
|
568
|
-
codeLines.push(`// ${ruleId}: ${stat.message} (${stat.count}次)`);
|
|
569
|
-
}
|
|
570
|
-
const markdown = lines.join('\n');
|
|
571
|
-
return _makeCandidate({
|
|
572
|
-
title: '最佳实践与常见问题',
|
|
573
|
-
knowledgeType: 'best-practice',
|
|
574
|
-
category: 'Service',
|
|
575
|
-
language: primaryLang,
|
|
576
|
-
markdown,
|
|
577
|
-
rationale: '基于 Guard 静态审计发现的违规模式和修复建议自动生成',
|
|
578
|
-
coreCode: codeLines.join('\n'),
|
|
579
|
-
trigger: 'Guard 审计结果',
|
|
580
|
-
doClause: '修复 Guard 标记的违规,特别是 error 级别',
|
|
581
|
-
dontClause: '不要忽略 Guard 警告,不要引入已知反模式',
|
|
582
|
-
whenClause: '修改现有代码或新建文件时',
|
|
583
|
-
sources: violationFiles.size > 0 ? [...violationFiles].slice(0, 10) : ['bootstrap-scan'],
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
|
-
function _buildAgentGuidelines({ guardAudit, primaryLang, astProjectSummary, }) {
|
|
587
|
-
const lines = ['## Agent 开发注意事项', ''];
|
|
588
|
-
lines.push('> 以下规则基于项目静态分析自动生成,AI Agent 在本项目中编写代码时应遵守。', '');
|
|
589
|
-
// 从 Guard 高频违规推断
|
|
590
|
-
if (guardAudit?.files?.length) {
|
|
591
|
-
const ruleStats = {};
|
|
592
|
-
for (const f of guardAudit.files) {
|
|
593
|
-
for (const v of f.violations || []) {
|
|
594
|
-
ruleStats[v.ruleId] = ruleStats[v.ruleId] || {
|
|
595
|
-
count: 0,
|
|
596
|
-
message: v.message,
|
|
597
|
-
severity: v.severity,
|
|
598
|
-
};
|
|
599
|
-
ruleStats[v.ruleId].count++;
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
const topErrors = Object.entries(ruleStats)
|
|
603
|
-
.filter(([, s]) => s.severity === 'error')
|
|
604
|
-
.sort(([, a], [, b]) => b.count - a.count)
|
|
605
|
-
.slice(0, 8);
|
|
606
|
-
const topWarnings = Object.entries(ruleStats)
|
|
607
|
-
.filter(([, s]) => s.severity === 'warning')
|
|
608
|
-
.sort(([, a], [, b]) => b.count - a.count)
|
|
609
|
-
.slice(0, 8);
|
|
610
|
-
if (topErrors.length > 0) {
|
|
611
|
-
lines.push('### 必须(must)- 基于 error 级违规', '');
|
|
612
|
-
for (const [ruleId, stat] of topErrors) {
|
|
613
|
-
lines.push(`- ❌ **${ruleId}**: ${stat.message} (项目中出现 ${stat.count} 次)`);
|
|
614
|
-
}
|
|
615
|
-
lines.push('');
|
|
616
|
-
}
|
|
617
|
-
if (topWarnings.length > 0) {
|
|
618
|
-
lines.push('### 建议(should)- 基于 warning 级违规', '');
|
|
619
|
-
for (const [ruleId, stat] of topWarnings) {
|
|
620
|
-
lines.push(`- ⚠️ **${ruleId}**: ${stat.message} (${stat.count} 处)`);
|
|
621
|
-
}
|
|
622
|
-
lines.push('');
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
// 从 AST 复杂度推断
|
|
626
|
-
if (astProjectSummary?.projectMetrics) {
|
|
627
|
-
const m = astProjectSummary.projectMetrics;
|
|
628
|
-
lines.push('### 代码质量约束', '');
|
|
629
|
-
if (m.maxNestingDepth != null && m.maxNestingDepth >= 5) {
|
|
630
|
-
lines.push(`- 当前项目最大嵌套深度 ${m.maxNestingDepth} — 新代码应避免超过 4 层嵌套`);
|
|
631
|
-
}
|
|
632
|
-
if (m.complexMethods && m.complexMethods.length > 0) {
|
|
633
|
-
const avgComplexity = m.complexMethods.reduce((s, c) => s + (c.complexity ?? 0), 0) /
|
|
634
|
-
m.complexMethods.length;
|
|
635
|
-
lines.push(`- 已有 ${m.complexMethods.length} 个高复杂度方法 (avg ${avgComplexity.toFixed(1)}) — 新方法圈复杂度应 <10`);
|
|
636
|
-
}
|
|
637
|
-
if (m.longMethods && m.longMethods.length > 0) {
|
|
638
|
-
lines.push(`- 已有 ${m.longMethods.length} 个过长方法 — 新方法建议 <50 行`);
|
|
639
|
-
}
|
|
640
|
-
lines.push('');
|
|
641
|
-
}
|
|
642
|
-
const markdown = lines.join('\n');
|
|
643
|
-
if (markdown.length < 100) {
|
|
644
|
-
return null;
|
|
645
|
-
}
|
|
646
|
-
// 生成 coreCode (P3)
|
|
647
|
-
const codeLines = ['// Agent 强制规则'];
|
|
648
|
-
if (astProjectSummary?.projectMetrics &&
|
|
649
|
-
(astProjectSummary.projectMetrics.maxNestingDepth ?? 0) >= 5) {
|
|
650
|
-
codeLines.push(`// 最大嵌套: ${astProjectSummary.projectMetrics.maxNestingDepth} → 新代码应 <4`);
|
|
651
|
-
}
|
|
652
|
-
if (astProjectSummary?.projectMetrics?.longMethods &&
|
|
653
|
-
astProjectSummary.projectMetrics.longMethods.length > 0) {
|
|
654
|
-
codeLines.push(`// 过长方法: ${astProjectSummary.projectMetrics.longMethods.length} 个 → 新方法应 <50行`);
|
|
655
|
-
}
|
|
656
|
-
return _makeCandidate({
|
|
657
|
-
title: 'Agent 开发注意事项',
|
|
658
|
-
knowledgeType: 'boundary-constraint',
|
|
659
|
-
category: 'Architecture',
|
|
660
|
-
language: primaryLang,
|
|
661
|
-
markdown,
|
|
662
|
-
rationale: '基于 Guard 错误级违规和 AST 复杂度指标自动生成的 Agent 约束',
|
|
663
|
-
coreCode: codeLines.join('\n'),
|
|
664
|
-
trigger: 'Agent 开发规范',
|
|
665
|
-
doClause: '新代码嵌套不超过 4 层,方法不超过 50 行,圈复杂度 <10',
|
|
666
|
-
dontClause: '不要引入 Guard 已标记的反模式',
|
|
667
|
-
whenClause: '在本项目中编写任何代码时',
|
|
668
|
-
sources: ['bootstrap-scan'],
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
// ═══════════════════════════════════════════════════════════
|
|
672
|
-
// 工具函数
|
|
673
|
-
// ═══════════════════════════════════════════════════════════
|
|
674
|
-
/** 从绝对/相对路径取文件名 */
|
|
675
|
-
function _basename(fp) {
|
|
676
|
-
if (!fp) {
|
|
677
|
-
return '';
|
|
678
|
-
}
|
|
679
|
-
const idx = fp.lastIndexOf('/');
|
|
680
|
-
return idx >= 0 ? fp.slice(idx + 1) : fp;
|
|
681
|
-
}
|
|
682
|
-
function _makeCandidate({ title, knowledgeType, category, language, markdown, rationale, coreCode, trigger, doClause, dontClause, whenClause, sources, }) {
|
|
683
|
-
return {
|
|
684
|
-
title,
|
|
685
|
-
content: { pattern: coreCode || '', markdown, rationale },
|
|
686
|
-
language: language || '',
|
|
687
|
-
category,
|
|
688
|
-
knowledgeType,
|
|
689
|
-
source: 'bootstrap-fallback',
|
|
690
|
-
difficulty: 'beginner',
|
|
691
|
-
scope: 'project-specific',
|
|
692
|
-
trigger: trigger || title,
|
|
693
|
-
doClause: doClause || '',
|
|
694
|
-
dontClause: dontClause || '',
|
|
695
|
-
whenClause: whenClause || '',
|
|
696
|
-
coreCode: coreCode || '',
|
|
697
|
-
reasoning: {
|
|
698
|
-
whyStandard: rationale,
|
|
699
|
-
sources: sources || ['bootstrap-scan'],
|
|
700
|
-
confidence: 0.6,
|
|
701
|
-
},
|
|
702
|
-
};
|
|
703
|
-
}
|
|
704
|
-
function _wrapAsSkill(dimId, label, markdown) {
|
|
705
|
-
return {
|
|
706
|
-
dimId,
|
|
707
|
-
name: `project-${dimId}`,
|
|
708
|
-
description: `Auto-generated from bootstrap scan (no-AI fallback): ${label}`,
|
|
709
|
-
content: [
|
|
710
|
-
`# ${label}`,
|
|
711
|
-
'',
|
|
712
|
-
'> Auto-generated by Bootstrap fallback (rule-based, no AI). Quality: basic.',
|
|
713
|
-
'',
|
|
714
|
-
markdown,
|
|
715
|
-
].join('\n'),
|
|
716
|
-
};
|
|
717
|
-
}
|
|
718
|
-
function _markDimDone(taskManager, sessionId, dimId, type) {
|
|
719
|
-
try {
|
|
720
|
-
if (taskManager && sessionId) {
|
|
721
|
-
taskManager.markTaskCompleted(dimId, { type, reason: type });
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
catch {
|
|
725
|
-
/* non-critical */
|
|
726
|
-
}
|
|
727
|
-
}
|