autosnippet 3.3.0 → 3.3.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/dashboard/dist/assets/icons-BJ2mUBi8.js +1 -0
- package/dashboard/dist/assets/index-B659K9t5.js +128 -0
- package/dashboard/dist/assets/index-NCm40PMD.css +1 -0
- package/dashboard/dist/index.html +3 -3
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +284 -142
- package/dist/lib/agent/context/ExplorationTracker.d.ts +2 -0
- package/dist/lib/agent/context/ExplorationTracker.js +21 -3
- package/dist/lib/agent/core/ToolExecutionPipeline.d.ts +3 -1
- package/dist/lib/agent/core/ToolExecutionPipeline.js +8 -1
- package/dist/lib/agent/forge/DynamicComposer.d.ts +58 -0
- package/dist/lib/agent/forge/DynamicComposer.js +99 -0
- package/dist/lib/agent/forge/SandboxRunner.d.ts +60 -0
- package/dist/lib/agent/forge/SandboxRunner.js +251 -0
- package/dist/lib/agent/forge/TemporaryToolRegistry.d.ts +76 -0
- package/dist/lib/agent/forge/TemporaryToolRegistry.js +154 -0
- package/dist/lib/agent/forge/ToolForge.d.ts +92 -0
- package/dist/lib/agent/forge/ToolForge.js +239 -0
- package/dist/lib/agent/forge/ToolRequirementAnalyzer.d.ts +44 -0
- package/dist/lib/agent/forge/ToolRequirementAnalyzer.js +119 -0
- package/dist/lib/agent/tools/ToolRegistry.d.ts +2 -0
- package/dist/lib/agent/tools/ToolRegistry.js +4 -0
- package/dist/lib/agent/tools/composite.js +0 -1
- package/dist/lib/agent/tools/index.d.ts +2 -50
- package/dist/lib/agent/tools/index.js +2 -3
- package/dist/lib/agent/tools/lifecycle.d.ts +1 -58
- package/dist/lib/agent/tools/lifecycle.js +2 -75
- package/dist/lib/cli/KnowledgeSyncService.d.ts +26 -0
- package/dist/lib/cli/KnowledgeSyncService.js +33 -1
- package/dist/lib/cli/deploy/FileManifest.d.ts +0 -21
- package/dist/lib/cli/deploy/FileManifest.js +0 -11
- package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +10 -0
- package/dist/lib/domain/knowledge/KnowledgeEntry.js +2 -0
- package/dist/lib/domain/knowledge/Lifecycle.d.ts +19 -2
- package/dist/lib/domain/knowledge/Lifecycle.js +32 -6
- package/dist/lib/domain/knowledge/UnifiedValidator.d.ts +1 -5
- package/dist/lib/domain/knowledge/UnifiedValidator.js +7 -44
- package/dist/lib/domain/knowledge/values/Stats.d.ts +29 -0
- package/dist/lib/domain/knowledge/values/Stats.js +41 -0
- package/dist/lib/external/mcp/McpServer.d.ts +19 -38
- package/dist/lib/external/mcp/McpServer.js +145 -117
- package/dist/lib/external/mcp/autoApproveInjector.js +0 -2
- package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.d.ts +26 -1
- package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +41 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +49 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +3 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +27 -0
- package/dist/lib/external/mcp/handlers/bootstrap/skills.js +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +1 -0
- package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
- package/dist/lib/external/mcp/handlers/browse.d.ts +1 -0
- package/dist/lib/external/mcp/handlers/browse.js +2 -1
- package/dist/lib/external/mcp/handlers/consolidated.d.ts +117 -6
- package/dist/lib/external/mcp/handlers/consolidated.js +251 -71
- package/dist/lib/external/mcp/handlers/guard.d.ts +150 -0
- package/dist/lib/external/mcp/handlers/guard.js +239 -5
- package/dist/lib/external/mcp/handlers/knowledge.d.ts +0 -29
- package/dist/lib/external/mcp/handlers/knowledge.js +1 -76
- package/dist/lib/external/mcp/handlers/panorama.d.ts +36 -0
- package/dist/lib/external/mcp/handlers/panorama.js +156 -0
- package/dist/lib/external/mcp/handlers/system.d.ts +2 -54
- package/dist/lib/external/mcp/handlers/system.js +3 -113
- package/dist/lib/external/mcp/handlers/task.d.ts +13 -24
- package/dist/lib/external/mcp/handlers/task.js +218 -557
- package/dist/lib/external/mcp/handlers/types.d.ts +91 -8
- package/dist/lib/external/mcp/handlers/types.js +18 -1
- package/dist/lib/external/mcp/handlers/wiki-external.d.ts +18 -1
- package/dist/lib/external/mcp/handlers/wiki-external.js +16 -1
- package/dist/lib/external/mcp/tools.d.ts +18 -24
- package/dist/lib/external/mcp/tools.js +132 -159
- package/dist/lib/http/HttpServer.js +52 -0
- package/dist/lib/http/middleware/validate.js +7 -3
- package/dist/lib/http/routes/audit.d.ts +8 -0
- package/dist/lib/http/routes/audit.js +51 -0
- package/dist/lib/http/routes/guardReport.d.ts +10 -0
- package/dist/lib/http/routes/guardReport.js +143 -0
- package/dist/lib/http/routes/knowledge.js +32 -1
- package/dist/lib/http/routes/panorama.d.ts +11 -0
- package/dist/lib/http/routes/panorama.js +322 -0
- package/dist/lib/http/routes/signals.d.ts +10 -0
- package/dist/lib/http/routes/signals.js +104 -0
- package/dist/lib/http/routes/task.d.ts +2 -3
- package/dist/lib/http/routes/task.js +17 -347
- package/dist/lib/http/routes/violations.js +1 -1
- package/dist/lib/infrastructure/audit/AuditLogger.d.ts +6 -1
- package/dist/lib/infrastructure/audit/AuditLogger.js +14 -1
- package/dist/lib/infrastructure/database/drizzle/schema.d.ts +202 -504
- package/dist/lib/infrastructure/database/drizzle/schema.js +38 -69
- package/dist/lib/infrastructure/database/migrations/004_evolution_proposals.d.ts +8 -0
- package/dist/lib/infrastructure/database/migrations/004_evolution_proposals.js +43 -0
- package/dist/lib/infrastructure/database/migrations/005_recipe_source_refs.d.ts +9 -0
- package/dist/lib/infrastructure/database/migrations/005_recipe_source_refs.js +24 -0
- package/dist/lib/infrastructure/logging/Logger.d.ts +2 -0
- package/dist/lib/infrastructure/logging/Logger.js +34 -7
- package/dist/lib/infrastructure/monitoring/ErrorTracker.js +3 -1
- package/dist/lib/infrastructure/monitoring/PerformanceMonitor.d.ts +2 -2
- package/dist/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -10
- package/dist/lib/infrastructure/notification/LarkNotifier.d.ts +24 -0
- package/dist/lib/infrastructure/notification/LarkNotifier.js +97 -0
- package/dist/lib/infrastructure/report/ReportStore.d.ts +45 -0
- package/dist/lib/infrastructure/report/ReportStore.js +133 -0
- package/dist/lib/infrastructure/signal/SignalAggregator.d.ts +18 -0
- package/dist/lib/infrastructure/signal/SignalAggregator.js +84 -0
- package/dist/lib/infrastructure/signal/SignalBridge.d.ts +13 -0
- package/dist/lib/infrastructure/signal/SignalBridge.js +20 -0
- package/dist/lib/infrastructure/signal/SignalBus.d.ts +63 -0
- package/dist/lib/infrastructure/signal/SignalBus.js +106 -0
- package/dist/lib/infrastructure/signal/SignalTraceWriter.d.ts +36 -0
- package/dist/lib/infrastructure/signal/SignalTraceWriter.js +130 -0
- package/dist/lib/infrastructure/vector/HnswVectorAdapter.js +18 -2
- package/dist/lib/injection/ServiceContainer.js +8 -0
- package/dist/lib/injection/ServiceMap.d.ts +16 -10
- package/dist/lib/injection/modules/AgentModule.d.ts +1 -1
- package/dist/lib/injection/modules/AgentModule.js +7 -1
- package/dist/lib/injection/modules/AppModule.d.ts +1 -1
- package/dist/lib/injection/modules/AppModule.js +4 -13
- package/dist/lib/injection/modules/GuardModule.js +27 -2
- package/dist/lib/injection/modules/InfraModule.d.ts +0 -1
- package/dist/lib/injection/modules/InfraModule.js +9 -7
- package/dist/lib/injection/modules/KnowledgeModule.d.ts +5 -0
- package/dist/lib/injection/modules/KnowledgeModule.js +131 -0
- package/dist/lib/injection/modules/PanoramaModule.d.ts +18 -0
- package/dist/lib/injection/modules/PanoramaModule.js +76 -0
- package/dist/lib/injection/modules/SignalModule.d.ts +10 -0
- package/dist/lib/injection/modules/SignalModule.js +84 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +1 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +6 -0
- package/dist/lib/service/bootstrap/BootstrapTaskManager.d.ts +3 -1
- package/dist/lib/service/bootstrap/BootstrapTaskManager.js +20 -1
- package/dist/lib/service/bootstrap/UiStartupTasks.d.ts +45 -0
- package/dist/lib/service/bootstrap/UiStartupTasks.js +101 -0
- package/dist/lib/service/delivery/AgentInstructionsGenerator.js +4 -5
- package/dist/lib/service/delivery/CursorDeliveryPipeline.d.ts +3 -1
- package/dist/lib/service/delivery/CursorDeliveryPipeline.js +13 -10
- package/dist/lib/service/delivery/RulesGenerator.js +3 -2
- package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +114 -0
- package/dist/lib/service/evolution/ConsolidationAdvisor.js +542 -0
- package/dist/lib/service/evolution/ContradictionDetector.d.ts +54 -0
- package/dist/lib/service/evolution/ContradictionDetector.js +253 -0
- package/dist/lib/service/evolution/DecayDetector.d.ts +71 -0
- package/dist/lib/service/evolution/DecayDetector.js +244 -0
- package/dist/lib/service/evolution/EnhancementSuggester.d.ts +38 -0
- package/dist/lib/service/evolution/EnhancementSuggester.js +220 -0
- package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +82 -0
- package/dist/lib/service/evolution/KnowledgeMetabolism.js +167 -0
- package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +53 -0
- package/dist/lib/service/evolution/RedundancyAnalyzer.js +210 -0
- package/dist/lib/service/evolution/StagingManager.d.ts +57 -0
- package/dist/lib/service/evolution/StagingManager.js +201 -0
- package/dist/lib/service/guard/ComplianceReporter.d.ts +42 -2
- package/dist/lib/service/guard/ComplianceReporter.js +43 -5
- package/dist/lib/service/guard/CoverageAnalyzer.d.ts +54 -0
- package/dist/lib/service/guard/CoverageAnalyzer.js +149 -0
- package/dist/lib/service/guard/GuardCheckEngine.d.ts +42 -0
- package/dist/lib/service/guard/GuardCheckEngine.js +465 -14
- package/dist/lib/service/guard/GuardFeedbackLoop.d.ts +3 -0
- package/dist/lib/service/guard/GuardFeedbackLoop.js +9 -0
- package/dist/lib/service/guard/ReverseGuard.d.ts +73 -0
- package/dist/lib/service/guard/ReverseGuard.js +256 -0
- package/dist/lib/service/guard/RuleLearner.d.ts +12 -0
- package/dist/lib/service/guard/RuleLearner.js +38 -0
- package/dist/lib/service/guard/UncertaintyCollector.d.ts +83 -0
- package/dist/lib/service/guard/UncertaintyCollector.js +149 -0
- package/dist/lib/service/guard/ViolationsStore.d.ts +1 -0
- package/dist/lib/service/guard/ViolationsStore.js +33 -3
- package/dist/lib/service/knowledge/ConfidenceRouter.d.ts +13 -0
- package/dist/lib/service/knowledge/ConfidenceRouter.js +14 -0
- package/dist/lib/service/knowledge/KnowledgeService.js +22 -4
- package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +68 -0
- package/dist/lib/service/knowledge/SourceRefReconciler.js +309 -0
- package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +27 -0
- package/dist/lib/service/panorama/CouplingAnalyzer.js +192 -0
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +28 -0
- package/dist/lib/service/panorama/DimensionAnalyzer.js +320 -0
- package/dist/lib/service/panorama/LayerInferrer.d.ts +19 -0
- package/dist/lib/service/panorama/LayerInferrer.js +182 -0
- package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +24 -0
- package/dist/lib/service/panorama/ModuleDiscoverer.js +185 -0
- package/dist/lib/service/panorama/PanoramaAggregator.d.ts +29 -0
- package/dist/lib/service/panorama/PanoramaAggregator.js +228 -0
- package/dist/lib/service/panorama/PanoramaScanner.d.ts +52 -0
- package/dist/lib/service/panorama/PanoramaScanner.js +188 -0
- package/dist/lib/service/panorama/PanoramaService.d.ts +125 -0
- package/dist/lib/service/panorama/PanoramaService.js +363 -0
- package/dist/lib/service/panorama/PanoramaTypes.d.ts +134 -0
- package/dist/lib/service/panorama/PanoramaTypes.js +6 -0
- package/dist/lib/service/panorama/RoleRefiner.d.ts +48 -0
- package/dist/lib/service/panorama/RoleRefiner.js +535 -0
- package/dist/lib/service/search/BM25Scorer.d.ts +2 -2
- package/dist/lib/service/search/CoarseRanker.d.ts +7 -6
- package/dist/lib/service/search/CoarseRanker.js +11 -10
- package/dist/lib/service/search/FieldWeightedScorer.d.ts +81 -0
- package/dist/lib/service/search/FieldWeightedScorer.js +318 -0
- package/dist/lib/service/search/MultiSignalRanker.d.ts +3 -2
- package/dist/lib/service/search/MultiSignalRanker.js +17 -1
- package/dist/lib/service/search/SearchEngine.d.ts +9 -7
- package/dist/lib/service/search/SearchEngine.js +67 -10
- package/dist/lib/service/search/SearchTypes.d.ts +25 -3
- package/dist/lib/service/search/SearchTypes.js +6 -1
- package/dist/lib/service/signal/HitRecorder.d.ts +68 -0
- package/dist/lib/service/signal/HitRecorder.js +173 -0
- package/dist/lib/service/skills/SignalCollector.d.ts +3 -1
- package/dist/lib/service/skills/SignalCollector.js +31 -1
- package/dist/lib/service/task/IntentExtractor.d.ts +66 -0
- package/dist/lib/service/task/IntentExtractor.js +256 -0
- package/dist/lib/service/task/PrimeSearchPipeline.d.ts +54 -0
- package/dist/lib/service/task/PrimeSearchPipeline.js +113 -0
- package/dist/lib/service/vector/VectorService.d.ts +3 -0
- package/dist/lib/service/vector/VectorService.js +38 -4
- package/dist/lib/shared/schemas/mcp-tools.d.ts +41 -96
- package/dist/lib/shared/schemas/mcp-tools.js +59 -119
- package/dist/scripts/analyze-signals.d.ts +20 -0
- package/dist/scripts/analyze-signals.js +155 -0
- package/dist/scripts/diagnose-mcp.js +1 -1
- package/package.json +1 -1
- package/skills/autosnippet-create/SKILL.md +98 -89
- package/skills/autosnippet-devdocs/SKILL.md +55 -57
- package/templates/claude-code/hooks/autosnippet-session.sh +10 -15
- package/templates/cursor-hooks/hooks/session-start.sh +1 -1
- package/templates/guard-ci.yml +2 -2
- package/templates/instructions/agent-static.md +2 -1
- package/templates/instructions/conventions.md +5 -6
- package/templates/recipes-setup/README.md +1 -2
- package/templates/recipes-setup/_template.md +39 -39
- package/dashboard/dist/assets/icons-BofcEZ3f.js +0 -1
- package/dashboard/dist/assets/index-D0whuycy.css +0 -1
- package/dashboard/dist/assets/index-SiN1GChm.js +0 -128
- package/dist/lib/domain/task/Task.d.ts +0 -140
- package/dist/lib/domain/task/Task.js +0 -254
- package/dist/lib/domain/task/TaskDependency.d.ts +0 -23
- package/dist/lib/domain/task/TaskDependency.js +0 -34
- package/dist/lib/domain/task/TaskIdGenerator.d.ts +0 -40
- package/dist/lib/domain/task/TaskIdGenerator.js +0 -75
- package/dist/lib/domain/task/index.d.ts +0 -4
- package/dist/lib/domain/task/index.js +0 -4
- package/dist/lib/infrastructure/database/migrations/002_add_tasks.d.ts +0 -11
- package/dist/lib/infrastructure/database/migrations/002_add_tasks.js +0 -86
- package/dist/lib/repository/task/TaskRepository.impl.d.ts +0 -171
- package/dist/lib/repository/task/TaskRepository.impl.js +0 -347
- package/dist/lib/service/task/TaskGraphService.d.ts +0 -222
- package/dist/lib/service/task/TaskGraphService.js +0 -597
- package/dist/lib/service/task/TaskKnowledgeBridge.d.ts +0 -95
- package/dist/lib/service/task/TaskKnowledgeBridge.js +0 -298
- package/dist/lib/service/task/TaskReadyEngine.d.ts +0 -84
- package/dist/lib/service/task/TaskReadyEngine.js +0 -115
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IntentExtractor — Intake Layer
|
|
3
|
+
*
|
|
4
|
+
* Pure functions: extract intent signals from user query + active file.
|
|
5
|
+
* Builds multi-query set, infers language/module/scenario for search routing.
|
|
6
|
+
*
|
|
7
|
+
* @module service/task/IntentExtractor
|
|
8
|
+
*/
|
|
9
|
+
import { tokenize } from '#service/search/tokenizer.js';
|
|
10
|
+
// ── Universal Patterns (language-agnostic) ──────────
|
|
11
|
+
const UNIVERSAL_PATTERNS = [
|
|
12
|
+
/\b[A-Z][a-z]+(?:[A-Z][a-z]+)+\b/g, // CamelCase
|
|
13
|
+
/`([^`]+)`/g, // backtick code
|
|
14
|
+
/\b[\w-]+\.(?:ts|js|m|h|swift|py|java|go|rs|tsx|kt)\b/g, // file names
|
|
15
|
+
/@[\w-]+/g, // trigger references
|
|
16
|
+
];
|
|
17
|
+
// ── Language Extension Map ──────────────────────────
|
|
18
|
+
const LANG_MAP = {
|
|
19
|
+
m: 'objectivec',
|
|
20
|
+
h: 'objectivec',
|
|
21
|
+
mm: 'objectivec',
|
|
22
|
+
swift: 'swift',
|
|
23
|
+
ts: 'typescript',
|
|
24
|
+
tsx: 'typescript',
|
|
25
|
+
js: 'javascript',
|
|
26
|
+
jsx: 'javascript',
|
|
27
|
+
py: 'python',
|
|
28
|
+
go: 'go',
|
|
29
|
+
rs: 'rust',
|
|
30
|
+
java: 'java',
|
|
31
|
+
kt: 'kotlin',
|
|
32
|
+
};
|
|
33
|
+
// ── Cross-Language Synonym Groups ───────────────────
|
|
34
|
+
// Each group contains EN morphological variants + CN equivalents.
|
|
35
|
+
// Used to expand queries so English terms match Chinese recipe fields (and vice versa).
|
|
36
|
+
const SYNONYM_GROUPS = [
|
|
37
|
+
// Design patterns & DI
|
|
38
|
+
['inject', 'injection', '注入'],
|
|
39
|
+
['construct', 'constructor', '构造器', '构造函数'],
|
|
40
|
+
['depend', 'dependency', 'dependencies', '依赖'],
|
|
41
|
+
['protocol', '协议'],
|
|
42
|
+
['interface', '接口'],
|
|
43
|
+
['pattern', '模式'],
|
|
44
|
+
['factory', '工厂'],
|
|
45
|
+
['singleton', '单例'],
|
|
46
|
+
['delegate', '代理', '委托'],
|
|
47
|
+
['observe', 'observer', '观察者'],
|
|
48
|
+
['subscribe', 'subscription', '订阅'],
|
|
49
|
+
['repository', 'repo', '仓库'],
|
|
50
|
+
// Architecture
|
|
51
|
+
['module', '模块'],
|
|
52
|
+
['architect', 'architecture', '架构'],
|
|
53
|
+
['route', 'router', 'routing', '路由'],
|
|
54
|
+
['middleware', '中间件'],
|
|
55
|
+
['component', '组件'],
|
|
56
|
+
['lifecycle', '生命周期'],
|
|
57
|
+
['layer', '分层', '层'],
|
|
58
|
+
// Language features
|
|
59
|
+
['generic', 'generics', '泛型'],
|
|
60
|
+
['closure', '闭包'],
|
|
61
|
+
['callback', '回调'],
|
|
62
|
+
['extend', 'extension', '扩展'],
|
|
63
|
+
['inherit', 'inheritance', '继承'],
|
|
64
|
+
['abstract', 'abstraction', '抽象'],
|
|
65
|
+
['encapsulate', 'encapsulation', '封装'],
|
|
66
|
+
['polymorph', 'polymorphism', '多态'],
|
|
67
|
+
['implement', 'implementation', '实现'],
|
|
68
|
+
// Concurrency
|
|
69
|
+
['async', 'asynchronous', '异步'],
|
|
70
|
+
['sync', 'synchronous', '同步'],
|
|
71
|
+
['thread', 'threading', '线程'],
|
|
72
|
+
['concur', 'concurrency', '并发'],
|
|
73
|
+
// Common concepts
|
|
74
|
+
['network', '网络'],
|
|
75
|
+
['cache', 'caching', '缓存'],
|
|
76
|
+
['persist', 'persistence', '持久化'],
|
|
77
|
+
['serialize', 'serialization', '序列化'],
|
|
78
|
+
['validate', 'validation', '校验', '验证'],
|
|
79
|
+
['authenticate', 'authentication', '认证'],
|
|
80
|
+
['authorize', 'authorization', '授权'],
|
|
81
|
+
['config', 'configuration', '配置'],
|
|
82
|
+
['navigate', 'navigation', '导航'],
|
|
83
|
+
['animate', 'animation', '动画'],
|
|
84
|
+
['layout', '布局'],
|
|
85
|
+
['render', 'rendering', '渲染'],
|
|
86
|
+
['responsive', '响应式'],
|
|
87
|
+
['state', '状态'],
|
|
88
|
+
['toast', '提示'],
|
|
89
|
+
['error', '错误'],
|
|
90
|
+
['handle', 'handler', '处理'],
|
|
91
|
+
['service', '服务'],
|
|
92
|
+
['test', 'testing', '测试'],
|
|
93
|
+
];
|
|
94
|
+
/** Lookup: lowercased term → synonym expansions (excluding the term itself) */
|
|
95
|
+
const SYNONYM_LOOKUP = new Map();
|
|
96
|
+
for (const group of SYNONYM_GROUPS) {
|
|
97
|
+
for (const term of group) {
|
|
98
|
+
SYNONYM_LOOKUP.set(term.toLowerCase(), group.filter((t) => t !== term));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// ── Public API ──────────────────────────────────────
|
|
102
|
+
/**
|
|
103
|
+
* Extract intent signals from user query and active file.
|
|
104
|
+
* Pure function — no side effects, no DI.
|
|
105
|
+
*/
|
|
106
|
+
export function extract(userQuery, activeFile, language, termOpts) {
|
|
107
|
+
const queries = buildQueries(userQuery, activeFile, termOpts);
|
|
108
|
+
const keywordQueries = buildKeywordQueries(userQuery);
|
|
109
|
+
const inferredLang = language || (activeFile ? inferLanguage(activeFile) : null);
|
|
110
|
+
const module = activeFile ? inferFileContext(activeFile) : null;
|
|
111
|
+
const scenario = classifyScenario(userQuery);
|
|
112
|
+
return {
|
|
113
|
+
queries,
|
|
114
|
+
keywordQueries,
|
|
115
|
+
language: inferredLang,
|
|
116
|
+
module,
|
|
117
|
+
scenario,
|
|
118
|
+
raw: { userQuery, activeFile, language },
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Build multi-query set from user query + active file.
|
|
123
|
+
* Q1: raw query, Q2: extracted tech terms, Q3: file context.
|
|
124
|
+
* Q1 is enriched with cross-language synonyms to bridge EN↔CJK matching.
|
|
125
|
+
*/
|
|
126
|
+
export function buildQueries(userQuery, activeFile, termOpts) {
|
|
127
|
+
// Enrich raw query with cross-language synonyms
|
|
128
|
+
const synonyms = expandWithSynonyms(userQuery);
|
|
129
|
+
const enrichedQuery = synonyms ? `${userQuery} ${synonyms}` : userQuery;
|
|
130
|
+
const queries = [enrichedQuery];
|
|
131
|
+
const terms = extractTechTerms(userQuery, termOpts);
|
|
132
|
+
if (terms.length > 0) {
|
|
133
|
+
queries.push(terms.join(' '));
|
|
134
|
+
}
|
|
135
|
+
if (activeFile) {
|
|
136
|
+
const ctx = inferFileContext(activeFile);
|
|
137
|
+
if (ctx) {
|
|
138
|
+
queries.push(ctx);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return queries;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Build keyword-mode queries for cross-language synonym matching.
|
|
145
|
+
* Uses keyword mode to preserve raw FWS scores without CoarseRanker semantic normalization.
|
|
146
|
+
*/
|
|
147
|
+
export function buildKeywordQueries(userQuery) {
|
|
148
|
+
const expanded = expandWithSynonyms(userQuery);
|
|
149
|
+
return expanded ? [expanded] : [];
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Extract tech terms from query using universal patterns + dynamic project prefixes.
|
|
153
|
+
*/
|
|
154
|
+
export function extractTechTerms(query, opts = {}) {
|
|
155
|
+
const terms = new Set();
|
|
156
|
+
// 1. Universal patterns (always run)
|
|
157
|
+
for (const pattern of UNIVERSAL_PATTERNS) {
|
|
158
|
+
for (const match of query.matchAll(new RegExp(pattern.source, pattern.flags))) {
|
|
159
|
+
const term = match[1] || match[0];
|
|
160
|
+
if (term.length >= 3 && term.length <= 50) {
|
|
161
|
+
terms.add(term);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// 2. Project prefix patterns (dynamic)
|
|
166
|
+
const allPrefixes = [...(opts.projectPrefixes ?? []), ...(opts.platformPrefixes ?? [])];
|
|
167
|
+
const prefixPattern = buildPrefixPattern(allPrefixes);
|
|
168
|
+
if (prefixPattern) {
|
|
169
|
+
for (const match of query.matchAll(prefixPattern)) {
|
|
170
|
+
if (match[0].length >= 3 && match[0].length <= 50) {
|
|
171
|
+
terms.add(match[0]);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return [...terms].slice(0, 8);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Infer file context string from file path for search augmentation.
|
|
179
|
+
* Returns module path + class name, e.g. "Services/Network BDNetworkManager"
|
|
180
|
+
*/
|
|
181
|
+
export function inferFileContext(filePath) {
|
|
182
|
+
const parts = filePath.replace(/\\/g, '/').split('/');
|
|
183
|
+
const fileName = parts[parts.length - 1] || '';
|
|
184
|
+
// Extract class name (remove extension)
|
|
185
|
+
const className = fileName.replace(/\.\w+$/, '');
|
|
186
|
+
// Extract meaningful module path (skip root dir and file name)
|
|
187
|
+
const meaningful = parts
|
|
188
|
+
.slice(1, -1)
|
|
189
|
+
.filter((p) => !['src', 'lib', 'Sources', 'BiliDili', 'BiliDemo'].includes(p));
|
|
190
|
+
const module = meaningful.slice(0, 2).join('/');
|
|
191
|
+
const segments = [module, className].filter(Boolean);
|
|
192
|
+
return segments.length > 0 ? segments.join(' ') : null;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Infer language from file extension.
|
|
196
|
+
*/
|
|
197
|
+
export function inferLanguage(filePath) {
|
|
198
|
+
const ext = filePath.split('.').pop()?.toLowerCase();
|
|
199
|
+
return ext ? (LANG_MAP[ext] ?? null) : null;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Classify search scenario from user query (lightweight rule-based).
|
|
203
|
+
*/
|
|
204
|
+
export function classifyScenario(userQuery) {
|
|
205
|
+
const q = userQuery.toLowerCase();
|
|
206
|
+
if (/帮我[加写做实现创建]|implement|add|create|新[增加建]/.test(q)) {
|
|
207
|
+
return 'generate';
|
|
208
|
+
}
|
|
209
|
+
if (/检查|review|lint|合规|违规|guard|规[则范]/.test(q)) {
|
|
210
|
+
return 'lint';
|
|
211
|
+
}
|
|
212
|
+
if (/什么是|怎么[用做]|原理|explain|学习|理解|为什么/.test(q)) {
|
|
213
|
+
return 'learning';
|
|
214
|
+
}
|
|
215
|
+
return 'search';
|
|
216
|
+
}
|
|
217
|
+
// ── Internal Helpers ────────────────────────────────
|
|
218
|
+
/**
|
|
219
|
+
* Expand query tokens with cross-language synonyms.
|
|
220
|
+
* Tokenizes query, looks up each token in the synonym table,
|
|
221
|
+
* returns a query string of synonym expansions for cross-language matching.
|
|
222
|
+
*
|
|
223
|
+
* Strategy: return only cross-script synonyms (EN→CJK or CJK→EN).
|
|
224
|
+
* This keeps the expansion focused — the original script tokens are already in Q1.
|
|
225
|
+
*/
|
|
226
|
+
function expandWithSynonyms(query) {
|
|
227
|
+
const tokens = tokenize(query);
|
|
228
|
+
const crossScriptTerms = new Set();
|
|
229
|
+
// Detect query script: does it contain CJK?
|
|
230
|
+
const hasCJK = /[\u4e00-\u9fff\u3400-\u4dbf]/.test(query);
|
|
231
|
+
for (const token of tokens) {
|
|
232
|
+
const synonyms = SYNONYM_LOOKUP.get(token.toLowerCase());
|
|
233
|
+
if (!synonyms) {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
for (const syn of synonyms) {
|
|
237
|
+
const synIsCJK = /[\u4e00-\u9fff\u3400-\u4dbf]/.test(syn);
|
|
238
|
+
// Cross-script: EN query → add CJK synonyms; CJK query → add EN synonyms
|
|
239
|
+
if (hasCJK !== synIsCJK) {
|
|
240
|
+
crossScriptTerms.add(syn);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (crossScriptTerms.size === 0) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
return [...crossScriptTerms].slice(0, 12).join(' ');
|
|
248
|
+
}
|
|
249
|
+
function buildPrefixPattern(prefixes) {
|
|
250
|
+
if (prefixes.length === 0) {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
const sorted = [...prefixes].sort((a, b) => b.length - a.length);
|
|
254
|
+
const escaped = sorted.map((p) => p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
255
|
+
return new RegExp(`\\b(?:${escaped.join('|')})\\w{2,}\\b`, 'g');
|
|
256
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PrimeSearchPipeline — Enrichment Layer
|
|
3
|
+
*
|
|
4
|
+
* Multi-query parallel search + scenario routing + session history accumulation.
|
|
5
|
+
* Replaces TaskKnowledgeBridge with full search pipeline integration.
|
|
6
|
+
*
|
|
7
|
+
* @module service/task/PrimeSearchPipeline
|
|
8
|
+
*/
|
|
9
|
+
import type { SlimSearchResult } from '#service/search/SearchTypes.js';
|
|
10
|
+
import type { ExtractedIntent } from './IntentExtractor.js';
|
|
11
|
+
/** Slim search result (re-export for external use) */
|
|
12
|
+
export type { SlimSearchResult } from '#service/search/SearchTypes.js';
|
|
13
|
+
export interface PrimeSearchMeta {
|
|
14
|
+
queries: string[];
|
|
15
|
+
scenario: string;
|
|
16
|
+
language: string | null;
|
|
17
|
+
module: string | null;
|
|
18
|
+
resultCount: number;
|
|
19
|
+
filteredCount: number;
|
|
20
|
+
}
|
|
21
|
+
export interface PrimeSearchResult {
|
|
22
|
+
relatedKnowledge: SlimSearchResult[];
|
|
23
|
+
guardRules: SlimSearchResult[];
|
|
24
|
+
searchMeta: PrimeSearchMeta;
|
|
25
|
+
}
|
|
26
|
+
/** Minimal SearchEngine shape — duck-typed for DI flexibility */
|
|
27
|
+
interface SearchEngineLike {
|
|
28
|
+
search(query: string, options?: {
|
|
29
|
+
mode?: string;
|
|
30
|
+
limit?: number;
|
|
31
|
+
rank?: boolean;
|
|
32
|
+
context?: {
|
|
33
|
+
sessionHistory?: Array<{
|
|
34
|
+
content?: string;
|
|
35
|
+
}>;
|
|
36
|
+
language?: string;
|
|
37
|
+
intent?: string;
|
|
38
|
+
};
|
|
39
|
+
}): Promise<{
|
|
40
|
+
items?: unknown[];
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
export declare class PrimeSearchPipeline {
|
|
44
|
+
#private;
|
|
45
|
+
constructor(searchEngine: SearchEngineLike);
|
|
46
|
+
/**
|
|
47
|
+
* Core method: multi-query search + scenario routing + result merging.
|
|
48
|
+
*/
|
|
49
|
+
search(intent: ExtractedIntent): Promise<PrimeSearchResult | null>;
|
|
50
|
+
/**
|
|
51
|
+
* Reset session history (called on new session start).
|
|
52
|
+
*/
|
|
53
|
+
resetSession(): void;
|
|
54
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PrimeSearchPipeline — Enrichment Layer
|
|
3
|
+
*
|
|
4
|
+
* Multi-query parallel search + scenario routing + session history accumulation.
|
|
5
|
+
* Replaces TaskKnowledgeBridge with full search pipeline integration.
|
|
6
|
+
*
|
|
7
|
+
* @module service/task/PrimeSearchPipeline
|
|
8
|
+
*/
|
|
9
|
+
import { slimSearchResult } from '#service/search/SearchTypes.js';
|
|
10
|
+
// ── Constants ───────────────────────────────────────
|
|
11
|
+
const RELEVANCE_THRESHOLD = 0.01;
|
|
12
|
+
// ── PrimeSearchPipeline ─────────────────────────────
|
|
13
|
+
export class PrimeSearchPipeline {
|
|
14
|
+
#search;
|
|
15
|
+
#sessionQueries = [];
|
|
16
|
+
constructor(searchEngine) {
|
|
17
|
+
this.#search = searchEngine;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Core method: multi-query search + scenario routing + result merging.
|
|
21
|
+
*/
|
|
22
|
+
async search(intent) {
|
|
23
|
+
if (!intent.queries.length || !intent.queries[0]?.trim()) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
// Build ranking context
|
|
27
|
+
const context = {
|
|
28
|
+
language: intent.language ?? undefined,
|
|
29
|
+
intent: intent.scenario,
|
|
30
|
+
sessionHistory: this.#buildSessionHistory(),
|
|
31
|
+
};
|
|
32
|
+
// Multi-query parallel search (auto mode + keyword mode for cross-language)
|
|
33
|
+
const allResults = await this.#multiQuerySearch(intent.queries, intent.keywordQueries ?? [], context);
|
|
34
|
+
// Threshold filter
|
|
35
|
+
const filtered = allResults.filter((r) => (r.score ?? 0) >= RELEVANCE_THRESHOLD);
|
|
36
|
+
if (filtered.length === 0) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
// Classify: knowledge vs rules
|
|
40
|
+
const knowledge = filtered.filter((r) => r.kind !== 'rule').slice(0, 5);
|
|
41
|
+
const rules = filtered.filter((r) => r.kind === 'rule').slice(0, 3);
|
|
42
|
+
// Record search to session history
|
|
43
|
+
this.#sessionQueries.push(intent.raw.userQuery);
|
|
44
|
+
return {
|
|
45
|
+
relatedKnowledge: knowledge,
|
|
46
|
+
guardRules: rules,
|
|
47
|
+
searchMeta: {
|
|
48
|
+
queries: intent.queries,
|
|
49
|
+
scenario: intent.scenario,
|
|
50
|
+
language: intent.language,
|
|
51
|
+
module: intent.module,
|
|
52
|
+
resultCount: allResults.length,
|
|
53
|
+
filteredCount: filtered.length,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Reset session history (called on new session start).
|
|
59
|
+
*/
|
|
60
|
+
resetSession() {
|
|
61
|
+
this.#sessionQueries = [];
|
|
62
|
+
}
|
|
63
|
+
// ── Private ───────────────────────────────────────
|
|
64
|
+
/**
|
|
65
|
+
* Multi-query parallel search with Reciprocal Rank Fusion (RRF).
|
|
66
|
+
* Auto-mode queries use CoarseRanker; keyword queries use raw FWS scores.
|
|
67
|
+
* Results are fused by rank position, not absolute scores — robust across heterogeneous scorers.
|
|
68
|
+
*/
|
|
69
|
+
async #multiQuerySearch(autoQueries, keywordQueries, context) {
|
|
70
|
+
// Auto-mode searches (full CoarseRanker pipeline)
|
|
71
|
+
const autoPromises = autoQueries.map((q) => this.#search
|
|
72
|
+
.search(q, { mode: 'auto', limit: 8, rank: true, context })
|
|
73
|
+
.catch(() => ({ items: [] })));
|
|
74
|
+
// Keyword-mode searches (raw FWS scores — for cross-language synonym matching)
|
|
75
|
+
const kwPromises = keywordQueries.map((q) => this.#search
|
|
76
|
+
.search(q, { mode: 'keyword', limit: 8, rank: false })
|
|
77
|
+
.catch(() => ({ items: [] })));
|
|
78
|
+
const [autoResponses, kwResponses] = await Promise.all([
|
|
79
|
+
Promise.all(autoPromises),
|
|
80
|
+
Promise.all(kwPromises),
|
|
81
|
+
]);
|
|
82
|
+
const allResponses = [...autoResponses, ...kwResponses];
|
|
83
|
+
// Reciprocal Rank Fusion: RRF(d) = Σ 1/(k + rank)
|
|
84
|
+
const RRF_K = 60;
|
|
85
|
+
const rrfScores = new Map();
|
|
86
|
+
const itemById = new Map();
|
|
87
|
+
for (const resp of allResponses) {
|
|
88
|
+
const items = (resp.items || []);
|
|
89
|
+
for (let rank = 0; rank < items.length; rank++) {
|
|
90
|
+
const item = slimSearchResult(items[rank]);
|
|
91
|
+
rrfScores.set(item.id, (rrfScores.get(item.id) ?? 0) + 1 / (RRF_K + rank));
|
|
92
|
+
// Keep the richest metadata version
|
|
93
|
+
if (!itemById.has(item.id)) {
|
|
94
|
+
itemById.set(item.id, item);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Assign fused scores and sort
|
|
99
|
+
const results = [];
|
|
100
|
+
for (const [id, rrfScore] of rrfScores) {
|
|
101
|
+
const item = itemById.get(id);
|
|
102
|
+
item.score = rrfScore;
|
|
103
|
+
results.push(item);
|
|
104
|
+
}
|
|
105
|
+
return results.sort((a, b) => b.score - a.score);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Build sessionHistory for contextBoost (last 5 queries).
|
|
109
|
+
*/
|
|
110
|
+
#buildSessionHistory() {
|
|
111
|
+
return this.#sessionQueries.slice(-5).map((q) => ({ content: q }));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -109,6 +109,9 @@ export declare class VectorService {
|
|
|
109
109
|
/**
|
|
110
110
|
* 混合搜索 (Dense + Sparse RRF 融合)
|
|
111
111
|
* 通过 HybridRetriever 执行向量 + BM25 关键词并行检索
|
|
112
|
+
*
|
|
113
|
+
* Embed 失败时优雅降级: 跳过 Dense 路, 仅用 Sparse 结果进行 RRF 融合,
|
|
114
|
+
* 避免因网络问题导致整个搜索返回空结果。
|
|
112
115
|
*/
|
|
113
116
|
hybridSearch(query: string, opts?: {
|
|
114
117
|
topK?: number;
|
|
@@ -26,6 +26,11 @@ export class VectorService {
|
|
|
26
26
|
#syncDebounceMs;
|
|
27
27
|
#logger = Logger.getInstance();
|
|
28
28
|
#initialized = false;
|
|
29
|
+
// ── Embed circuit breaker ──
|
|
30
|
+
#embedConsecutiveFailures = 0;
|
|
31
|
+
#embedCircuitOpenUntil = 0;
|
|
32
|
+
static #EMBED_CIRCUIT_THRESHOLD = 3;
|
|
33
|
+
static #EMBED_CIRCUIT_COOLDOWN_MS = 60_000;
|
|
29
34
|
constructor(config) {
|
|
30
35
|
this.#vectorStore = config.vectorStore;
|
|
31
36
|
this.#indexingPipeline = config.indexingPipeline;
|
|
@@ -211,6 +216,9 @@ export class VectorService {
|
|
|
211
216
|
/**
|
|
212
217
|
* 混合搜索 (Dense + Sparse RRF 融合)
|
|
213
218
|
* 通过 HybridRetriever 执行向量 + BM25 关键词并行检索
|
|
219
|
+
*
|
|
220
|
+
* Embed 失败时优雅降级: 跳过 Dense 路, 仅用 Sparse 结果进行 RRF 融合,
|
|
221
|
+
* 避免因网络问题导致整个搜索返回空结果。
|
|
214
222
|
*/
|
|
215
223
|
async hybridSearch(query, opts = {}) {
|
|
216
224
|
if (!this.#embedProvider) {
|
|
@@ -226,11 +234,37 @@ export class VectorService {
|
|
|
226
234
|
}));
|
|
227
235
|
}
|
|
228
236
|
const { topK = 10, alpha = 0.5, sparseSearchFn = null } = opts;
|
|
237
|
+
// Embed query — circuit breaker skips embed after repeated failures
|
|
238
|
+
let queryVector = null;
|
|
239
|
+
const circuitOpen = Date.now() < this.#embedCircuitOpenUntil;
|
|
240
|
+
if (circuitOpen) {
|
|
241
|
+
this.#logger.debug('[VectorService] embed circuit open, skipping embed');
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
try {
|
|
245
|
+
const embedResult = await this.#embedProvider.embed(query);
|
|
246
|
+
queryVector = Array.isArray(embedResult[0])
|
|
247
|
+
? embedResult[0]
|
|
248
|
+
: embedResult;
|
|
249
|
+
this.#embedConsecutiveFailures = 0;
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
this.#embedConsecutiveFailures++;
|
|
253
|
+
if (this.#embedConsecutiveFailures >= VectorService.#EMBED_CIRCUIT_THRESHOLD) {
|
|
254
|
+
this.#embedCircuitOpenUntil = Date.now() + VectorService.#EMBED_CIRCUIT_COOLDOWN_MS;
|
|
255
|
+
this.#logger.warn('[VectorService] embed circuit OPEN — skipping embed for 60s', {
|
|
256
|
+
consecutiveFailures: this.#embedConsecutiveFailures,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
this.#logger.warn('[VectorService] embed failed, degrading to sparse-only', {
|
|
261
|
+
error: err instanceof Error ? err.message : String(err),
|
|
262
|
+
failCount: this.#embedConsecutiveFailures,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
229
267
|
try {
|
|
230
|
-
const embedResult = await this.#embedProvider.embed(query);
|
|
231
|
-
const queryVector = Array.isArray(embedResult[0])
|
|
232
|
-
? embedResult[0]
|
|
233
|
-
: embedResult;
|
|
234
268
|
const fused = await this.#hybridRetriever.search(query, queryVector, {
|
|
235
269
|
topK,
|
|
236
270
|
alpha,
|