autosnippet 3.3.5 → 3.3.7
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/dashboard/dist/assets/icons-FHns2ypa.js +1 -0
- package/dashboard/dist/assets/index-BRJv5Y3r.js +135 -0
- package/dashboard/dist/assets/index-DzoB7kxK.css +1 -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 +137 -9
- package/dist/lib/agent/AgentFactory.d.ts +0 -17
- package/dist/lib/agent/AgentFactory.js +1 -25
- package/dist/lib/agent/AgentRuntime.d.ts +2 -2
- package/dist/lib/agent/AgentRuntime.js +26 -18
- 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/ChatAgentTasks.js +4 -0
- 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/forced-summary.js +7 -2
- 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 +5 -5
- package/dist/lib/cli/KnowledgeSyncService.js +1 -1
- package/dist/lib/core/AstAnalyzer.d.ts +1 -0
- package/dist/lib/core/discovery/ConfigWatcher.d.ts +64 -0
- package/dist/lib/core/discovery/ConfigWatcher.js +336 -0
- package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +30 -0
- package/dist/lib/core/discovery/CustomConfigDiscoverer.js +1305 -0
- package/dist/lib/core/discovery/DiscovererPreference.d.ts +44 -0
- package/dist/lib/core/discovery/DiscovererPreference.js +141 -0
- package/dist/lib/core/discovery/DiscovererRegistry.d.ts +10 -1
- package/dist/lib/core/discovery/DiscovererRegistry.js +42 -2
- package/dist/lib/core/discovery/ProjectDiscoverer.d.ts +19 -0
- package/dist/lib/core/discovery/index.d.ts +2 -0
- package/dist/lib/core/discovery/index.js +4 -0
- package/dist/lib/core/discovery/parsers/CMakeParser.d.ts +32 -0
- package/dist/lib/core/discovery/parsers/CMakeParser.js +148 -0
- package/dist/lib/core/discovery/parsers/GradleDslParser.d.ts +43 -0
- package/dist/lib/core/discovery/parsers/GradleDslParser.js +171 -0
- package/dist/lib/core/discovery/parsers/JsonConfigParser.d.ts +45 -0
- package/dist/lib/core/discovery/parsers/JsonConfigParser.js +122 -0
- package/dist/lib/core/discovery/parsers/RubyDslParser.d.ts +49 -0
- package/dist/lib/core/discovery/parsers/RubyDslParser.js +282 -0
- package/dist/lib/core/discovery/parsers/StarlarkParser.d.ts +33 -0
- package/dist/lib/core/discovery/parsers/StarlarkParser.js +229 -0
- package/dist/lib/core/discovery/parsers/YamlConfigParser.d.ts +37 -0
- package/dist/lib/core/discovery/parsers/YamlConfigParser.js +212 -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 +40 -112
- package/dist/lib/domain/knowledge/KnowledgeEntry.js +44 -9
- 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/external/ai/AiProvider.d.ts +12 -0
- package/dist/lib/external/ai/AiProvider.js +24 -0
- package/dist/lib/external/ai/AiProviderManager.d.ts +101 -0
- package/dist/lib/external/ai/AiProviderManager.js +193 -0
- package/dist/lib/external/ai/providers/ClaudeProvider.js +11 -0
- package/dist/lib/external/ai/providers/GoogleGeminiProvider.js +18 -0
- package/dist/lib/external/ai/providers/MockProvider.d.ts +21 -3
- package/dist/lib/external/ai/providers/MockProvider.js +290 -14
- package/dist/lib/external/ai/providers/OpenAiProvider.js +16 -0
- package/dist/lib/external/lark/LarkTransport.d.ts +5 -1
- package/dist/lib/external/lark/LarkTransport.js +10 -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/mock-pipeline.d.ts +20 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.js +432 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.d.ts +99 -12
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +188 -169
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +7 -17
- package/dist/lib/external/mcp/handlers/bootstrap/refine.js +8 -0
- 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 +23 -10
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +41 -51
- package/dist/lib/external/mcp/handlers/bootstrap-internal.d.ts +2 -0
- package/dist/lib/external/mcp/handlers/bootstrap-internal.js +117 -82
- package/dist/lib/external/mcp/handlers/consolidated.d.ts +4 -4
- package/dist/lib/external/mcp/handlers/consolidated.js +108 -332
- package/dist/lib/external/mcp/handlers/dimension-complete-external.js +71 -2
- package/dist/lib/external/mcp/handlers/evolve-external.d.ts +54 -0
- package/dist/lib/external/mcp/handlers/evolve-external.js +229 -0
- package/dist/lib/external/mcp/handlers/knowledge.js +30 -5
- 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 +58 -2
- package/dist/lib/http/routes/ai.js +111 -30
- package/dist/lib/http/routes/candidates.js +11 -4
- package/dist/lib/http/routes/commands.js +10 -1
- package/dist/lib/http/routes/health.js +11 -0
- package/dist/lib/http/routes/knowledge.js +122 -1
- package/dist/lib/http/routes/modules.js +52 -3
- package/dist/lib/http/routes/panorama.js +16 -4
- package/dist/lib/http/routes/recipes.js +7 -0
- package/dist/lib/http/utils/routeHelpers.js +2 -1
- 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.d.ts +6 -5
- package/dist/lib/injection/ServiceContainer.js +64 -25
- package/dist/lib/injection/ServiceMap.d.ts +10 -1
- package/dist/lib/injection/modules/AiModule.d.ts +6 -9
- package/dist/lib/injection/modules/AiModule.js +82 -39
- package/dist/lib/injection/modules/KnowledgeModule.js +15 -1
- package/dist/lib/injection/modules/PanoramaModule.js +1 -1
- 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 +5 -0
- package/dist/lib/service/bootstrap/UiStartupTasks.js +20 -0
- 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 +132 -0
- package/dist/lib/service/cleanup/CleanupService.js +571 -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/ProposalExecutor.d.ts +4 -0
- package/dist/lib/service/evolution/ProposalExecutor.js +77 -13
- 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/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/knowledge/CodeEntityGraph.d.ts +6 -0
- package/dist/lib/service/knowledge/CodeEntityGraph.js +16 -0
- 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 +67 -14
- package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +225 -0
- package/dist/lib/service/knowledge/RecipeProductionGateway.js +384 -0
- package/dist/lib/service/module/ModuleService.js +10 -19
- package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +10 -1
- package/dist/lib/service/panorama/CouplingAnalyzer.js +44 -2
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +4 -3
- package/dist/lib/service/panorama/DimensionAnalyzer.js +40 -151
- package/dist/lib/service/panorama/LayerInferrer.d.ts +16 -1
- package/dist/lib/service/panorama/LayerInferrer.js +118 -1
- package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +9 -0
- package/dist/lib/service/panorama/ModuleDiscoverer.js +58 -2
- package/dist/lib/service/panorama/PanoramaAggregator.d.ts +6 -2
- package/dist/lib/service/panorama/PanoramaAggregator.js +84 -6
- package/dist/lib/service/panorama/PanoramaScanner.js +28 -0
- package/dist/lib/service/panorama/PanoramaService.js +10 -5
- package/dist/lib/service/panorama/PanoramaTypes.d.ts +38 -0
- package/dist/lib/service/panorama/RoleRefiner.d.ts +2 -0
- package/dist/lib/service/panorama/RoleRefiner.js +41 -0
- package/dist/lib/service/panorama/TechStackProfiler.d.ts +13 -0
- package/dist/lib/service/panorama/TechStackProfiler.js +191 -0
- 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/service/skills/SignalCollector.d.ts +1 -0
- package/dist/lib/service/skills/SignalCollector.js +6 -5
- package/dist/lib/service/vector/ContextualEnricher.d.ts +1 -0
- package/dist/lib/service/vector/ContextualEnricher.js +4 -0
- package/dist/lib/shared/LanguageService.js +3 -0
- package/dist/lib/shared/developer-identity.d.ts +18 -0
- package/dist/lib/shared/developer-identity.js +62 -0
- package/dist/lib/shared/schemas/common.d.ts +4 -4
- package/dist/lib/shared/schemas/http-requests.d.ts +20 -18
- package/dist/lib/shared/schemas/http-requests.js +17 -6
- package/dist/lib/shared/schemas/mcp-tools.d.ts +32 -2
- package/dist/lib/shared/schemas/mcp-tools.js +38 -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 +132 -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
|
@@ -25,6 +25,15 @@ const logger = Logger.getInstance();
|
|
|
25
25
|
function getContainer() {
|
|
26
26
|
return getServiceContainer();
|
|
27
27
|
}
|
|
28
|
+
/** 检查 AI Provider 是否可用(非 mock),不可用则抛 ValidationError */
|
|
29
|
+
function requireAiReady() {
|
|
30
|
+
const container = getContainer();
|
|
31
|
+
const manager = container.singletons?._aiProviderManager;
|
|
32
|
+
if (manager?.isMock) {
|
|
33
|
+
throw new ValidationError('AI Provider 未配置,当前为 Mock 模式。请先在 .env 中配置 API Key。');
|
|
34
|
+
}
|
|
35
|
+
return container;
|
|
36
|
+
}
|
|
28
37
|
// ═══════════════════════════════════════════════════════
|
|
29
38
|
// UI 语言偏好 — 前端 ↔ 服务端同步
|
|
30
39
|
// ═══════════════════════════════════════════════════════
|
|
@@ -76,22 +85,19 @@ router.get('/providers', async (req, res) => {
|
|
|
76
85
|
});
|
|
77
86
|
/**
|
|
78
87
|
* GET /api/v1/ai/config
|
|
79
|
-
* 获取当前 AI
|
|
88
|
+
* 获取当前 AI 配置(优先从 AiProviderManager 读取)
|
|
80
89
|
*/
|
|
81
90
|
router.get('/config', async (req, res) => {
|
|
82
91
|
const container = getServiceContainer();
|
|
83
|
-
const
|
|
92
|
+
const manager = container.singletons?._aiProviderManager;
|
|
84
93
|
res.json({
|
|
85
94
|
success: true,
|
|
86
|
-
data: {
|
|
87
|
-
provider: p?.name || '',
|
|
88
|
-
model: p?.model || '',
|
|
89
|
-
},
|
|
95
|
+
data: { provider: manager.name, model: manager.model, isMock: manager.isMock },
|
|
90
96
|
});
|
|
91
97
|
});
|
|
92
98
|
/**
|
|
93
99
|
* POST /api/v1/ai/config
|
|
94
|
-
* 更新 AI
|
|
100
|
+
* 更新 AI 配置(切换提供商/模型)— 通过 AiProviderManager 统一热切换
|
|
95
101
|
*/
|
|
96
102
|
router.post('/config', validate(AiConfigBody), async (req, res) => {
|
|
97
103
|
const { provider, model } = req.body;
|
|
@@ -106,18 +112,13 @@ router.post('/config', validate(AiConfigBody), async (req, res) => {
|
|
|
106
112
|
catch (error) {
|
|
107
113
|
throw new ValidationError(`Invalid provider: ${error.message}`);
|
|
108
114
|
}
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
catch (err) {
|
|
119
|
-
logger.debug('DI container 同步 AI provider 失败', { error: err.message });
|
|
120
|
-
}
|
|
115
|
+
// 通过 reloadAiProvider → AiProviderManager.switchProvider() 统一热切换
|
|
116
|
+
const container = getServiceContainer();
|
|
117
|
+
container.reloadAiProvider(newProvider);
|
|
118
|
+
logger.info('AI provider switched via AiProviderManager', {
|
|
119
|
+
provider: provider.toLowerCase(),
|
|
120
|
+
model: newProvider.model,
|
|
121
|
+
});
|
|
121
122
|
res.json({
|
|
122
123
|
success: true,
|
|
123
124
|
data: {
|
|
@@ -127,13 +128,58 @@ router.post('/config', validate(AiConfigBody), async (req, res) => {
|
|
|
127
128
|
},
|
|
128
129
|
});
|
|
129
130
|
});
|
|
131
|
+
/**
|
|
132
|
+
* POST /api/v1/ai/mock/cleanup
|
|
133
|
+
* 清理 Mock 模式产生的候选数据
|
|
134
|
+
*/
|
|
135
|
+
router.post('/mock/cleanup', async (_req, res) => {
|
|
136
|
+
const container = getContainer();
|
|
137
|
+
const knowledgeService = container.get('knowledgeService');
|
|
138
|
+
const dbConn = container.get('database');
|
|
139
|
+
const rawDb = dbConn.getDb();
|
|
140
|
+
// 查找所有 mock 来源的候选
|
|
141
|
+
const mockSources = ['mock-bootstrap', 'mock-pipeline'];
|
|
142
|
+
let totalDeleted = 0;
|
|
143
|
+
for (const source of mockSources) {
|
|
144
|
+
const rows = rawDb
|
|
145
|
+
.prepare('SELECT id FROM knowledge_entries WHERE source = ?')
|
|
146
|
+
.all(source);
|
|
147
|
+
for (const row of rows) {
|
|
148
|
+
try {
|
|
149
|
+
await knowledgeService.delete(row.id, { userId: 'system:mock-cleanup' });
|
|
150
|
+
totalDeleted++;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
logger.debug(`Mock cleanup: failed to delete ${row.id}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// 清理 mock 相关的 semantic_memories
|
|
158
|
+
try {
|
|
159
|
+
rawDb
|
|
160
|
+
.prepare("DELETE FROM semantic_memories WHERE source = 'bootstrap' AND metadata LIKE '%mock%'")
|
|
161
|
+
.run();
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// 表可能不存在
|
|
165
|
+
}
|
|
166
|
+
logger.info(`Mock cleanup completed: ${totalDeleted} entries deleted`);
|
|
167
|
+
const rt = getRealtimeService();
|
|
168
|
+
if (rt) {
|
|
169
|
+
rt.broadcastEvent('mock-cleanup-completed', { deleted: totalDeleted });
|
|
170
|
+
}
|
|
171
|
+
res.json({
|
|
172
|
+
success: true,
|
|
173
|
+
data: { deleted: totalDeleted },
|
|
174
|
+
});
|
|
175
|
+
});
|
|
130
176
|
/**
|
|
131
177
|
* POST /api/v1/ai/summarize
|
|
132
178
|
* AI 摘要生成
|
|
133
179
|
*/
|
|
134
180
|
router.post('/summarize', validate(AiSummarizeBody), async (req, res) => {
|
|
135
181
|
const { code, language } = req.body;
|
|
136
|
-
const container =
|
|
182
|
+
const container = requireAiReady();
|
|
137
183
|
const factory = container.get('agentFactory');
|
|
138
184
|
const result = await factory.scanKnowledge({
|
|
139
185
|
label: 'code',
|
|
@@ -158,7 +204,7 @@ router.post('/translate', validate(AiTranslateBody), async (req, res) => {
|
|
|
158
204
|
});
|
|
159
205
|
}
|
|
160
206
|
try {
|
|
161
|
-
const container =
|
|
207
|
+
const container = requireAiReady();
|
|
162
208
|
const factory = container.get('agentFactory');
|
|
163
209
|
const result = await factory.translateToEnglish(summary, usageGuide);
|
|
164
210
|
if (result?.error) {
|
|
@@ -197,7 +243,7 @@ router.post('/translate', validate(AiTranslateBody), async (req, res) => {
|
|
|
197
243
|
*/
|
|
198
244
|
router.post('/chat', validate(AiChatBody), async (req, res) => {
|
|
199
245
|
const { prompt, history, lang, conversationId } = req.body;
|
|
200
|
-
const container =
|
|
246
|
+
const container = requireAiReady();
|
|
201
247
|
const factory = container.get('agentFactory');
|
|
202
248
|
// ── 对话持久化: 从 ConversationStore 加载历史 ──
|
|
203
249
|
let convStore = null;
|
|
@@ -309,7 +355,7 @@ router.post('/chat', validate(AiChatBody), async (req, res) => {
|
|
|
309
355
|
*/
|
|
310
356
|
router.post('/agent/tool', validate(AiToolBody), async (req, res) => {
|
|
311
357
|
const { tool, params } = req.body;
|
|
312
|
-
const container =
|
|
358
|
+
const container = requireAiReady();
|
|
313
359
|
const factory = container.get('agentFactory');
|
|
314
360
|
const result = await factory.invokeAgent(tool, params);
|
|
315
361
|
res.json({ success: true, data: result });
|
|
@@ -332,7 +378,7 @@ const DAG_TASK_HANDLERS = {
|
|
|
332
378
|
};
|
|
333
379
|
router.post('/agent/task', validate(AiTaskBody), async (req, res) => {
|
|
334
380
|
const { task, params } = req.body;
|
|
335
|
-
const container =
|
|
381
|
+
const container = requireAiReady();
|
|
336
382
|
const factory = container.get('agentFactory');
|
|
337
383
|
// 优先尝试 DAG 任务
|
|
338
384
|
const dagHandler = DAG_TASK_HANDLERS[task];
|
|
@@ -530,7 +576,7 @@ router.post('/env-config', validate(AiEnvConfigBody), async (req, res) => {
|
|
|
530
576
|
for (const [k, v] of Object.entries(updates)) {
|
|
531
577
|
process.env[k] = String(v);
|
|
532
578
|
}
|
|
533
|
-
// 尝试热切换 AI Provider
|
|
579
|
+
// 尝试热切换 AI Provider(通过 AiProviderManager 统一处理)
|
|
534
580
|
try {
|
|
535
581
|
const newProvider = createProvider({
|
|
536
582
|
provider: provider.toLowerCase(),
|
|
@@ -538,7 +584,7 @@ router.post('/env-config', validate(AiEnvConfigBody), async (req, res) => {
|
|
|
538
584
|
});
|
|
539
585
|
const container = getServiceContainer();
|
|
540
586
|
container.reloadAiProvider(newProvider);
|
|
541
|
-
logger.info('AI provider hot-swapped after env update', {
|
|
587
|
+
logger.info('AI provider hot-swapped via AiProviderManager after env update', {
|
|
542
588
|
provider,
|
|
543
589
|
model: newProvider.model,
|
|
544
590
|
});
|
|
@@ -576,7 +622,7 @@ router.post('/env-config', validate(AiEnvConfigBody), async (req, res) => {
|
|
|
576
622
|
*/
|
|
577
623
|
router.post('/chat/stream', validate(AiStreamBody), async (req, res) => {
|
|
578
624
|
const { prompt, history, lang } = req.body;
|
|
579
|
-
const container =
|
|
625
|
+
const container = requireAiReady();
|
|
580
626
|
const factory = container.get('agentFactory');
|
|
581
627
|
const session = createStreamSession('chat');
|
|
582
628
|
logger.debug('SSE session created', { sessionId: session.sessionId });
|
|
@@ -626,18 +672,53 @@ router.post('/chat/stream', validate(AiStreamBody), async (req, res) => {
|
|
|
626
672
|
runtime
|
|
627
673
|
.execute(message)
|
|
628
674
|
.then((result) => {
|
|
675
|
+
const replyText = result.reply || '';
|
|
629
676
|
// 发送最终文本
|
|
630
|
-
if (
|
|
677
|
+
if (replyText) {
|
|
631
678
|
const textId = `text_${Date.now()}`;
|
|
632
679
|
session.send({ type: 'text:start', id: textId, role: 'assistant' });
|
|
633
|
-
session.send({ type: 'text:delta', id: textId, delta:
|
|
680
|
+
session.send({ type: 'text:delta', id: textId, delta: replyText });
|
|
634
681
|
session.send({ type: 'text:end', id: textId });
|
|
635
682
|
}
|
|
683
|
+
else {
|
|
684
|
+
logger.warn('SSE session: empty reply from AgentRuntime', {
|
|
685
|
+
sessionId: session.sessionId,
|
|
686
|
+
iterations: result.iterations,
|
|
687
|
+
toolCalls: result.toolCalls?.length || 0,
|
|
688
|
+
});
|
|
689
|
+
}
|
|
636
690
|
session.end({
|
|
637
|
-
text:
|
|
691
|
+
text: replyText || '抱歉,AI 未能生成有效回复。请重试或换个问题。',
|
|
638
692
|
toolCalls: result.toolCalls || [],
|
|
639
693
|
iterations: result.iterations || 0,
|
|
640
694
|
});
|
|
695
|
+
// ── Token 用量持久化(streaming) ──
|
|
696
|
+
try {
|
|
697
|
+
const tokenUsage = result.tokenUsage;
|
|
698
|
+
if (tokenUsage) {
|
|
699
|
+
const tokenStore = container.get('tokenUsageStore');
|
|
700
|
+
const aiProvider = container.singletons?.aiProvider;
|
|
701
|
+
tokenStore.record({
|
|
702
|
+
source: 'user',
|
|
703
|
+
provider: aiProvider?.name ?? undefined,
|
|
704
|
+
model: aiProvider?.model ?? undefined,
|
|
705
|
+
inputTokens: tokenUsage.input || 0,
|
|
706
|
+
outputTokens: tokenUsage.output || 0,
|
|
707
|
+
durationMs: result.durationMs || 0,
|
|
708
|
+
toolCalls: result.toolCalls?.length || 0,
|
|
709
|
+
});
|
|
710
|
+
try {
|
|
711
|
+
const realtime = getRealtimeService();
|
|
712
|
+
realtime?.broadcastTokenUsageUpdated?.();
|
|
713
|
+
}
|
|
714
|
+
catch {
|
|
715
|
+
/* ignore */
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
catch {
|
|
720
|
+
/* token tracking should never break streaming */
|
|
721
|
+
}
|
|
641
722
|
logger.debug('SSE session completed', {
|
|
642
723
|
sessionId: session.sessionId,
|
|
643
724
|
events: session.buffer.length,
|
|
@@ -55,6 +55,13 @@ router.post('/enrich', validate(EnrichBody), async (req, res) => {
|
|
|
55
55
|
let enrichedCount = 0;
|
|
56
56
|
const results = [];
|
|
57
57
|
if (aiProvider) {
|
|
58
|
+
// Mock 模式下跳过 AI enrichment
|
|
59
|
+
if (aiProvider.name === 'mock') {
|
|
60
|
+
return void res.json({
|
|
61
|
+
success: true,
|
|
62
|
+
data: { enriched: 0, total: candidates.length, results: [], mock: true },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
58
65
|
let enriched = [];
|
|
59
66
|
try {
|
|
60
67
|
// 获取用户语言偏好
|
|
@@ -418,8 +425,8 @@ router.post('/refine-preview', validate(RefinePreviewBody), async (req, res) =>
|
|
|
418
425
|
const container = getServiceContainer();
|
|
419
426
|
const knowledgeService = container.get('knowledgeService');
|
|
420
427
|
const aiProvider = container.get('aiProvider');
|
|
421
|
-
if (!aiProvider) {
|
|
422
|
-
throw new ValidationError('AI
|
|
428
|
+
if (!aiProvider || aiProvider.name === 'mock') {
|
|
429
|
+
throw new ValidationError('AI Provider 未配置,当前为 Mock 模式。请先配置 API Key。');
|
|
423
430
|
}
|
|
424
431
|
const entry = await knowledgeService.get(candidateId);
|
|
425
432
|
if (!entry) {
|
|
@@ -459,8 +466,8 @@ router.post('/refine-preview-stream', validate(RefinePreviewBody), async (req, r
|
|
|
459
466
|
const container = getServiceContainer();
|
|
460
467
|
const knowledgeService = container.get('knowledgeService');
|
|
461
468
|
const aiProvider = container.get('aiProvider');
|
|
462
|
-
if (!aiProvider) {
|
|
463
|
-
throw new ValidationError('AI
|
|
469
|
+
if (!aiProvider || aiProvider.name === 'mock') {
|
|
470
|
+
throw new ValidationError('AI Provider 未配置,当前为 Mock 模式。请先配置 API Key。');
|
|
464
471
|
}
|
|
465
472
|
const entry = await knowledgeService.get(candidateId);
|
|
466
473
|
if (!entry) {
|
|
@@ -29,6 +29,15 @@ router.post('/spm-map', async (req, res) => {
|
|
|
29
29
|
*/
|
|
30
30
|
router.post('/embed', async (req, res) => {
|
|
31
31
|
const container = getServiceContainer();
|
|
32
|
+
// Mock 模式下向量构建需要 embedding — 拒绝执行
|
|
33
|
+
const manager = container.singletons?._aiProviderManager;
|
|
34
|
+
if (manager?.isMock) {
|
|
35
|
+
res.status(400).json({
|
|
36
|
+
success: false,
|
|
37
|
+
message: 'AI Provider 未配置,当前为 Mock 模式。Embedding 不可用。',
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
32
41
|
// 优先使用 VectorService (新架构), 降级到 indexingPipeline (旧架构)
|
|
33
42
|
const vectorService = container.services.vectorService ? container.get('vectorService') : null;
|
|
34
43
|
let result;
|
|
@@ -80,7 +89,7 @@ router.get('/status', async (req, res) => {
|
|
|
80
89
|
spmMap: { available: false },
|
|
81
90
|
};
|
|
82
91
|
try {
|
|
83
|
-
const
|
|
92
|
+
const _indexingPipeline = container.get('indexingPipeline');
|
|
84
93
|
status.index.ready = true; // IndexingPipeline is available
|
|
85
94
|
}
|
|
86
95
|
catch {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** 健康检查端点 */
|
|
2
2
|
import express from 'express';
|
|
3
|
+
import { getDeveloperIdentity } from '../../shared/developer-identity.js';
|
|
3
4
|
const router = express.Router();
|
|
4
5
|
/**
|
|
5
6
|
* GET /api/v1/health
|
|
@@ -25,4 +26,14 @@ router.get('/ready', (req, res) => {
|
|
|
25
26
|
timestamp: Math.floor(Date.now() / 1000),
|
|
26
27
|
});
|
|
27
28
|
});
|
|
29
|
+
/**
|
|
30
|
+
* GET /api/v1/health/identity
|
|
31
|
+
* 当前开发者身份(从 git config / 环境变量解析)
|
|
32
|
+
*/
|
|
33
|
+
router.get('/identity', (_req, res) => {
|
|
34
|
+
res.json({
|
|
35
|
+
success: true,
|
|
36
|
+
developer: getDeveloperIdentity(),
|
|
37
|
+
});
|
|
38
|
+
});
|
|
28
39
|
export default router;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import express from 'express';
|
|
7
7
|
import { ioLimit } from '#shared/concurrency.js';
|
|
8
|
-
import { BatchPublishBody, CreateKnowledgeBody, DeprecateKnowledgeBody, KnowledgeUsageBody, UpdateKnowledgeBody, } from '#shared/schemas/http-requests.js';
|
|
8
|
+
import { BatchDeleteBody, BatchDeprecateBody, BatchPublishBody, CreateKnowledgeBody, DeprecateKnowledgeBody, KnowledgeUsageBody, UpdateKnowledgeBody, } from '#shared/schemas/http-requests.js';
|
|
9
9
|
import Logger from '../../infrastructure/logging/Logger.js';
|
|
10
10
|
import { getServiceContainer } from '../../injection/ServiceContainer.js';
|
|
11
11
|
import { validate } from '../middleware/validate.js';
|
|
@@ -140,6 +140,28 @@ router.get('/lifecycle', async (req, res) => {
|
|
|
140
140
|
}
|
|
141
141
|
res.json({ success: true, data: lifecycle });
|
|
142
142
|
});
|
|
143
|
+
/**
|
|
144
|
+
* POST /api/v1/knowledge/quality/refresh-all
|
|
145
|
+
* 批量重新计算所有条目的质量评分
|
|
146
|
+
*/
|
|
147
|
+
router.post('/quality/refresh-all', async (_req, res) => {
|
|
148
|
+
const container = getServiceContainer();
|
|
149
|
+
const knowledgeService = container.get('knowledgeService');
|
|
150
|
+
const result = await knowledgeService.list({}, { page: 1, pageSize: 10000 });
|
|
151
|
+
const all = result.data;
|
|
152
|
+
let updated = 0;
|
|
153
|
+
let failed = 0;
|
|
154
|
+
for (const entry of all) {
|
|
155
|
+
try {
|
|
156
|
+
await knowledgeService.updateQuality(entry.id);
|
|
157
|
+
updated++;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
failed++;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
res.json({ success: true, data: { updated, failed, total: all.length } });
|
|
164
|
+
});
|
|
143
165
|
/**
|
|
144
166
|
* GET /api/v1/knowledge/:id
|
|
145
167
|
* 获取知识条目详情
|
|
@@ -229,6 +251,54 @@ router.patch('/:id/reactivate', requirePermission('knowledge', 'update'), async
|
|
|
229
251
|
const entry = await knowledgeService.reactivate(id, context);
|
|
230
252
|
res.json({ success: true, data: sanitizeForAPI(entry) });
|
|
231
253
|
});
|
|
254
|
+
/**
|
|
255
|
+
* PATCH /api/v1/knowledge/:id/stage
|
|
256
|
+
* 暂存 (pending → staging)
|
|
257
|
+
*/
|
|
258
|
+
router.patch('/:id/stage', requirePermission('knowledge', 'update'), async (req, res) => {
|
|
259
|
+
const id = String(req.params.id);
|
|
260
|
+
const container = getServiceContainer();
|
|
261
|
+
const knowledgeService = container.get('knowledgeService');
|
|
262
|
+
const context = getContext(req);
|
|
263
|
+
const entry = await knowledgeService.stage(id, context);
|
|
264
|
+
res.json({ success: true, data: sanitizeForAPI(entry) });
|
|
265
|
+
});
|
|
266
|
+
/**
|
|
267
|
+
* PATCH /api/v1/knowledge/:id/evolve
|
|
268
|
+
* 进化 (active → evolving)
|
|
269
|
+
*/
|
|
270
|
+
router.patch('/:id/evolve', requirePermission('knowledge', 'update'), async (req, res) => {
|
|
271
|
+
const id = String(req.params.id);
|
|
272
|
+
const container = getServiceContainer();
|
|
273
|
+
const knowledgeService = container.get('knowledgeService');
|
|
274
|
+
const context = getContext(req);
|
|
275
|
+
const entry = await knowledgeService.evolve(id, context);
|
|
276
|
+
res.json({ success: true, data: sanitizeForAPI(entry) });
|
|
277
|
+
});
|
|
278
|
+
/**
|
|
279
|
+
* PATCH /api/v1/knowledge/:id/decay
|
|
280
|
+
* 衰退 (active|evolving → decaying)
|
|
281
|
+
*/
|
|
282
|
+
router.patch('/:id/decay', requirePermission('knowledge', 'update'), async (req, res) => {
|
|
283
|
+
const id = String(req.params.id);
|
|
284
|
+
const container = getServiceContainer();
|
|
285
|
+
const knowledgeService = container.get('knowledgeService');
|
|
286
|
+
const context = getContext(req);
|
|
287
|
+
const entry = await knowledgeService.decay(id, context);
|
|
288
|
+
res.json({ success: true, data: sanitizeForAPI(entry) });
|
|
289
|
+
});
|
|
290
|
+
/**
|
|
291
|
+
* PATCH /api/v1/knowledge/:id/restore
|
|
292
|
+
* 恢复为已发布 (decaying|evolving → active)
|
|
293
|
+
*/
|
|
294
|
+
router.patch('/:id/restore', requirePermission('knowledge', 'update'), async (req, res) => {
|
|
295
|
+
const id = String(req.params.id);
|
|
296
|
+
const container = getServiceContainer();
|
|
297
|
+
const knowledgeService = container.get('knowledgeService');
|
|
298
|
+
const context = getContext(req);
|
|
299
|
+
const entry = await knowledgeService.restore(id, context);
|
|
300
|
+
res.json({ success: true, data: sanitizeForAPI(entry) });
|
|
301
|
+
});
|
|
232
302
|
/* ═══ 批量操作 ═══════════════════════════════════════════ */
|
|
233
303
|
/**
|
|
234
304
|
* POST /api/v1/knowledge/batch-publish
|
|
@@ -258,6 +328,57 @@ router.post('/batch-publish', requirePermission('knowledge', 'publish'), validat
|
|
|
258
328
|
},
|
|
259
329
|
});
|
|
260
330
|
});
|
|
331
|
+
/**
|
|
332
|
+
* POST /api/v1/knowledge/batch-delete
|
|
333
|
+
* 批量删除知识条目
|
|
334
|
+
*/
|
|
335
|
+
router.post('/batch-delete', requirePermission('knowledge', 'delete'), validate(BatchDeleteBody), async (req, res) => {
|
|
336
|
+
const { ids } = req.body;
|
|
337
|
+
const container = getServiceContainer();
|
|
338
|
+
const knowledgeService = container.get('knowledgeService');
|
|
339
|
+
const context = getContext(req);
|
|
340
|
+
const results = await Promise.allSettled(ids.map((id) => ioLimit(() => knowledgeService.delete(id, context))));
|
|
341
|
+
const deleted = results.filter((r) => r.status === 'fulfilled').length;
|
|
342
|
+
const failed = results
|
|
343
|
+
.map((r, i) => (r.status === 'rejected' ? { id: ids[i], error: r.reason?.message } : null))
|
|
344
|
+
.filter(Boolean);
|
|
345
|
+
res.json({
|
|
346
|
+
success: true,
|
|
347
|
+
data: {
|
|
348
|
+
total: ids.length,
|
|
349
|
+
deletedCount: deleted,
|
|
350
|
+
failureCount: failed.length,
|
|
351
|
+
failed,
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
/**
|
|
356
|
+
* POST /api/v1/knowledge/batch-deprecate
|
|
357
|
+
* 批量废弃知识条目 (active → deprecated)
|
|
358
|
+
*/
|
|
359
|
+
router.post('/batch-deprecate', requirePermission('knowledge', 'publish'), validate(BatchDeprecateBody), async (req, res) => {
|
|
360
|
+
const { ids, reason } = req.body;
|
|
361
|
+
const container = getServiceContainer();
|
|
362
|
+
const knowledgeService = container.get('knowledgeService');
|
|
363
|
+
const context = getContext(req);
|
|
364
|
+
const results = await Promise.allSettled(ids.map((id) => ioLimit(() => knowledgeService.deprecate(id, reason || 'batch deprecate', context))));
|
|
365
|
+
const deprecated = results
|
|
366
|
+
.filter((r) => r.status === 'fulfilled')
|
|
367
|
+
.map((r) => sanitizeForAPI(r.value));
|
|
368
|
+
const failed = results
|
|
369
|
+
.map((r, i) => (r.status === 'rejected' ? { id: ids[i], error: r.reason?.message } : null))
|
|
370
|
+
.filter(Boolean);
|
|
371
|
+
res.json({
|
|
372
|
+
success: true,
|
|
373
|
+
data: {
|
|
374
|
+
deprecated,
|
|
375
|
+
failed,
|
|
376
|
+
total: ids.length,
|
|
377
|
+
successCount: deprecated.length,
|
|
378
|
+
failureCount: failed.length,
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
});
|
|
261
382
|
/* ═══ 使用 / 质量 ═══════════════════════════════════════ */
|
|
262
383
|
/**
|
|
263
384
|
* POST /api/v1/knowledge/:id/usage
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 所有端点通过 container.get('moduleService') 获取 ModuleService 实例
|
|
6
6
|
*/
|
|
7
7
|
import express from 'express';
|
|
8
|
-
import { ModuleBootstrapBody, ScanFolderBody, ScanProjectBody, ScanTargetBody, } from '#shared/schemas/http-requests.js';
|
|
8
|
+
import { ModuleBootstrapBody, ModuleRescanBody, ScanFolderBody, ScanProjectBody, ScanTargetBody, } from '#shared/schemas/http-requests.js';
|
|
9
9
|
import Logger from '../../infrastructure/logging/Logger.js';
|
|
10
10
|
import { getServiceContainer } from '../../injection/ServiceContainer.js';
|
|
11
11
|
import { validate } from '../middleware/validate.js';
|
|
@@ -416,14 +416,17 @@ router.get('/project-info', async (req, res) => {
|
|
|
416
416
|
router.post('/bootstrap', validate(ModuleBootstrapBody), async (req, res) => {
|
|
417
417
|
const { maxFiles, skipGuard, contentMaxLines } = req.body || {};
|
|
418
418
|
const container = getServiceContainer();
|
|
419
|
-
const agentFactory = container.get('agentFactory');
|
|
420
419
|
logger.info('Bootstrap cold start initiated (ModuleService path)');
|
|
421
|
-
|
|
420
|
+
// 直接调用 bootstrap-internal handler(统一编排管线)
|
|
421
|
+
const { bootstrapKnowledge } = await import('#external/mcp/handlers/bootstrap-internal.js');
|
|
422
|
+
const raw = await bootstrapKnowledge({ container, logger }, {
|
|
422
423
|
maxFiles: maxFiles || 500,
|
|
423
424
|
skipGuard: skipGuard || false,
|
|
424
425
|
contentMaxLines: contentMaxLines || 120,
|
|
425
426
|
loadSkills: true,
|
|
426
427
|
});
|
|
428
|
+
const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
429
|
+
const bootstrapResult = parsed?.data || parsed;
|
|
427
430
|
res.json({
|
|
428
431
|
success: true,
|
|
429
432
|
data: {
|
|
@@ -456,4 +459,50 @@ router.get('/bootstrap/status', async (req, res) => {
|
|
|
456
459
|
data: taskManager.getSessionStatus(),
|
|
457
460
|
});
|
|
458
461
|
});
|
|
462
|
+
/**
|
|
463
|
+
* POST /api/v1/modules/bootstrap/cancel
|
|
464
|
+
* 取消正在运行的 bootstrap / rescan 异步填充会话
|
|
465
|
+
*/
|
|
466
|
+
router.post('/bootstrap/cancel', async (req, res) => {
|
|
467
|
+
const container = getServiceContainer();
|
|
468
|
+
let taskManager = null;
|
|
469
|
+
try {
|
|
470
|
+
taskManager = container.get('bootstrapTaskManager');
|
|
471
|
+
}
|
|
472
|
+
catch {
|
|
473
|
+
/* not registered */
|
|
474
|
+
}
|
|
475
|
+
if (!taskManager) {
|
|
476
|
+
return void res.json({ success: true, message: 'No bootstrap task manager initialized' });
|
|
477
|
+
}
|
|
478
|
+
if (!taskManager.isRunning) {
|
|
479
|
+
return void res.json({ success: true, message: 'No active bootstrap session' });
|
|
480
|
+
}
|
|
481
|
+
const reason = req.body?.reason || 'Cancelled by user via Dashboard';
|
|
482
|
+
taskManager.abortSession(reason);
|
|
483
|
+
logger.info('Bootstrap session cancelled via HTTP', { reason });
|
|
484
|
+
res.json({
|
|
485
|
+
success: true,
|
|
486
|
+
data: taskManager.getSessionStatus(),
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
/**
|
|
490
|
+
* POST /api/v1/modules/rescan
|
|
491
|
+
* 增量扫描:保留已有 Recipe,重新分析项目,补齐缺失知识
|
|
492
|
+
* 使用内部 Agent pipeline 自动完成知识补齐
|
|
493
|
+
*/
|
|
494
|
+
router.post('/rescan', validate(ModuleRescanBody), async (req, res) => {
|
|
495
|
+
const { reason, dimensions } = req.body || {};
|
|
496
|
+
const container = getServiceContainer();
|
|
497
|
+
logger.info('Rescan (internal) initiated from Dashboard', { reason, dimensions });
|
|
498
|
+
// 直接调用 rescan-internal handler(统一编排管线)
|
|
499
|
+
const { rescanInternal } = await import('#external/mcp/handlers/rescan-internal.js');
|
|
500
|
+
const raw = await rescanInternal({ container, logger }, { reason: reason || 'dashboard-rescan', dimensions });
|
|
501
|
+
const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
502
|
+
const result = parsed?.data || parsed;
|
|
503
|
+
res.json({
|
|
504
|
+
success: true,
|
|
505
|
+
data: result,
|
|
506
|
+
});
|
|
507
|
+
});
|
|
459
508
|
export default router;
|
|
@@ -14,7 +14,7 @@ const router = express.Router();
|
|
|
14
14
|
* GET /api/v1/panorama
|
|
15
15
|
* 返回项目全景概览(层级、模块、覆盖率)
|
|
16
16
|
*/
|
|
17
|
-
router.get('/', async (
|
|
17
|
+
router.get('/', async (req, res) => {
|
|
18
18
|
try {
|
|
19
19
|
const container = getServiceContainer();
|
|
20
20
|
const panoramaService = container.get('panoramaService');
|
|
@@ -25,6 +25,9 @@ router.get('/', async (_req, res) => {
|
|
|
25
25
|
});
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
+
if (req.query.refresh === 'true' && typeof panoramaService.invalidate === 'function') {
|
|
29
|
+
panoramaService.invalidate();
|
|
30
|
+
}
|
|
28
31
|
if (typeof panoramaService.ensureData === 'function') {
|
|
29
32
|
await panoramaService.ensureData();
|
|
30
33
|
}
|
|
@@ -42,7 +45,7 @@ router.get('/', async (_req, res) => {
|
|
|
42
45
|
* GET /api/v1/panorama/health
|
|
43
46
|
* 返回全景健康度评分
|
|
44
47
|
*/
|
|
45
|
-
router.get('/health', async (
|
|
48
|
+
router.get('/health', async (req, res) => {
|
|
46
49
|
try {
|
|
47
50
|
const container = getServiceContainer();
|
|
48
51
|
const panoramaService = container.get('panoramaService');
|
|
@@ -53,6 +56,9 @@ router.get('/health', async (_req, res) => {
|
|
|
53
56
|
});
|
|
54
57
|
return;
|
|
55
58
|
}
|
|
59
|
+
if (req.query.refresh === 'true' && typeof panoramaService.invalidate === 'function') {
|
|
60
|
+
panoramaService.invalidate();
|
|
61
|
+
}
|
|
56
62
|
if (typeof panoramaService.ensureData === 'function') {
|
|
57
63
|
await panoramaService.ensureData();
|
|
58
64
|
}
|
|
@@ -70,7 +76,7 @@ router.get('/health', async (_req, res) => {
|
|
|
70
76
|
* GET /api/v1/panorama/gaps
|
|
71
77
|
* 返回知识空白区列表
|
|
72
78
|
*/
|
|
73
|
-
router.get('/gaps', async (
|
|
79
|
+
router.get('/gaps', async (req, res) => {
|
|
74
80
|
try {
|
|
75
81
|
const container = getServiceContainer();
|
|
76
82
|
const panoramaService = container.get('panoramaService');
|
|
@@ -81,6 +87,9 @@ router.get('/gaps', async (_req, res) => {
|
|
|
81
87
|
});
|
|
82
88
|
return;
|
|
83
89
|
}
|
|
90
|
+
if (req.query.refresh === 'true' && typeof panoramaService.invalidate === 'function') {
|
|
91
|
+
panoramaService.invalidate();
|
|
92
|
+
}
|
|
84
93
|
if (typeof panoramaService.ensureData === 'function') {
|
|
85
94
|
await panoramaService.ensureData();
|
|
86
95
|
}
|
|
@@ -98,7 +107,7 @@ router.get('/gaps', async (_req, res) => {
|
|
|
98
107
|
* GET /api/v1/panorama/coverage
|
|
99
108
|
* 返回各模块知识覆盖率热力图数据
|
|
100
109
|
*/
|
|
101
|
-
router.get('/coverage', async (
|
|
110
|
+
router.get('/coverage', async (req, res) => {
|
|
102
111
|
try {
|
|
103
112
|
const container = getServiceContainer();
|
|
104
113
|
const panoramaService = container.get('panoramaService');
|
|
@@ -109,6 +118,9 @@ router.get('/coverage', async (_req, res) => {
|
|
|
109
118
|
});
|
|
110
119
|
return;
|
|
111
120
|
}
|
|
121
|
+
if (req.query.refresh === 'true' && typeof panoramaService.invalidate === 'function') {
|
|
122
|
+
panoramaService.invalidate();
|
|
123
|
+
}
|
|
112
124
|
if (typeof panoramaService.ensureData === 'function') {
|
|
113
125
|
await panoramaService.ensureData();
|
|
114
126
|
}
|
|
@@ -70,6 +70,13 @@ router.post('/discover-relations', async (req, res) => {
|
|
|
70
70
|
data: { status: 'error', error: 'AgentFactory 不可用,请检查 AI Provider 配置' },
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
|
+
// Mock 模式下跳过 AI 关系发现
|
|
74
|
+
if (agentFactory.getAiProviderInfo?.()?.name === 'mock') {
|
|
75
|
+
return void res.json({
|
|
76
|
+
success: true,
|
|
77
|
+
data: { status: 'error', error: 'AI Provider 未配置,当前为 Mock 模式。请先配置 API Key。' },
|
|
78
|
+
});
|
|
79
|
+
}
|
|
73
80
|
// 快速检查:至少需要 2 条活跃 Recipe
|
|
74
81
|
try {
|
|
75
82
|
const knowledgeService = container.get('knowledgeService');
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
* 提取自各路由文件中的重复实现
|
|
4
4
|
*/
|
|
5
5
|
import { KnowledgeEntry } from '../../domain/knowledge/KnowledgeEntry.js';
|
|
6
|
+
import { getDeveloperIdentity } from '../../shared/developer-identity.js';
|
|
6
7
|
/**
|
|
7
8
|
* 从请求中提取操作上下文(用户身份、IP、UA)
|
|
8
9
|
* @returns }
|
|
9
10
|
*/
|
|
10
11
|
export function getContext(req) {
|
|
11
12
|
return {
|
|
12
|
-
userId: String(req.headers['x-user-id'] ||
|
|
13
|
+
userId: String(req.headers['x-user-id'] || getDeveloperIdentity()),
|
|
13
14
|
ip: req.ip || '',
|
|
14
15
|
userAgent: req.headers['user-agent'] || '',
|
|
15
16
|
};
|