autosnippet 2.9.0 → 2.11.0
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 +12 -12
- package/bin/cli.js +53 -40
- package/config/constitution.yaml +9 -2
- package/dashboard/dist/assets/{icons-CH-H9x0E.js → icons-D4IWpDIk.js} +105 -100
- package/dashboard/dist/assets/index-CWBNcF9z.css +1 -0
- package/dashboard/dist/assets/index-DHtzhbuG.js +120 -0
- package/dashboard/dist/index.html +3 -3
- package/lib/cli/AiScanService.js +35 -36
- package/lib/cli/KnowledgeSyncService.js +345 -0
- package/lib/cli/SetupService.js +8 -26
- package/lib/cli/UpgradeService.js +28 -0
- package/lib/core/gateway/GatewayActionRegistry.js +48 -58
- package/lib/domain/index.js +16 -11
- package/lib/domain/knowledge/KnowledgeEntry.js +289 -0
- package/lib/domain/knowledge/KnowledgeRepository.js +123 -0
- package/lib/domain/knowledge/Lifecycle.js +99 -0
- package/lib/domain/knowledge/index.js +27 -0
- package/lib/domain/knowledge/values/Constraints.js +128 -0
- package/lib/domain/knowledge/values/Content.js +69 -0
- package/lib/domain/knowledge/values/Quality.js +81 -0
- package/lib/domain/knowledge/values/Reasoning.js +70 -0
- package/lib/domain/knowledge/values/Relations.js +142 -0
- package/lib/domain/knowledge/values/Stats.js +72 -0
- package/lib/domain/knowledge/values/index.js +9 -0
- package/lib/external/ai/AiProvider.js +85 -11
- package/lib/external/mcp/McpServer.js +7 -5
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +18 -2
- package/lib/external/mcp/handlers/bootstrap.js +116 -11
- package/lib/external/mcp/handlers/browse.js +76 -73
- package/lib/external/mcp/handlers/candidate.js +26 -275
- package/lib/external/mcp/handlers/guard.js +2 -0
- package/lib/external/mcp/handlers/knowledge.js +267 -0
- package/lib/external/mcp/handlers/structure.js +25 -23
- package/lib/external/mcp/handlers/system.js +10 -12
- package/lib/external/mcp/tools.js +134 -140
- package/lib/http/HttpServer.js +14 -8
- package/lib/http/routes/ai.js +4 -3
- package/lib/http/routes/extract.js +48 -4
- package/lib/http/routes/knowledge.js +246 -0
- package/lib/http/routes/search.js +12 -17
- package/lib/infrastructure/database/migrations/016_unified_knowledge_entries.js +395 -0
- package/lib/infrastructure/database/migrations/017_camelcase_knowledge_entries.js +107 -0
- package/lib/infrastructure/external/XcodeAutomation.js +187 -103
- package/lib/injection/ServiceContainer.js +69 -60
- package/lib/repository/knowledge/KnowledgeRepository.impl.js +338 -0
- package/lib/service/automation/DirectiveDetector.js +2 -3
- package/lib/service/automation/FileWatcher.js +59 -28
- package/lib/service/automation/XcodeIntegration.js +931 -156
- package/lib/service/automation/handlers/AlinkHandler.js +5 -4
- package/lib/service/automation/handlers/CreateHandler.js +53 -19
- package/lib/service/automation/handlers/DraftHandler.js +1 -1
- package/lib/service/automation/handlers/GuardHandler.js +183 -20
- package/lib/service/automation/handlers/SearchHandler.js +25 -22
- package/lib/service/candidate/SimilarityService.js +2 -2
- package/lib/service/chat/AnalystAgent.js +9 -0
- package/lib/service/chat/CandidateGuardrail.js +22 -11
- package/lib/service/chat/ChatAgent.js +132 -54
- package/lib/service/chat/ContextWindow.js +5 -5
- package/lib/service/chat/HandoffProtocol.js +1 -0
- package/lib/service/chat/ProducerAgent.js +40 -13
- package/lib/service/chat/ReasoningLayer.js +854 -0
- package/lib/service/chat/ReasoningTrace.js +329 -0
- package/lib/service/chat/tools.js +308 -205
- package/lib/service/cursor/CursorDeliveryPipeline.js +279 -0
- package/lib/service/cursor/KnowledgeCompressor.js +87 -0
- package/lib/service/cursor/RulesGenerator.js +168 -0
- package/lib/service/cursor/SkillsSyncer.js +268 -0
- package/lib/service/cursor/TokenBudget.js +58 -0
- package/lib/service/cursor/TopicClassifier.js +141 -0
- package/lib/service/guard/GuardCheckEngine.js +99 -10
- package/lib/service/guard/GuardService.js +57 -46
- package/lib/service/knowledge/ConfidenceRouter.js +159 -0
- package/lib/service/knowledge/KnowledgeFileWriter.js +595 -0
- package/lib/service/knowledge/KnowledgeService.js +802 -0
- package/lib/service/recipe/RecipeParser.js +3 -12
- package/lib/service/search/SearchEngine.js +67 -22
- package/lib/service/skills/SignalCollector.js +14 -9
- package/lib/service/skills/SkillAdvisor.js +13 -11
- package/lib/service/snippet/SnippetFactory.js +5 -5
- package/lib/service/spm/SpmService.js +15 -48
- package/lib/shared/RecipeReadinessChecker.js +6 -11
- package/package.json +1 -1
- package/scripts/install-cursor-skill.js +0 -6
- package/scripts/migrate-md-to-knowledge.mjs +364 -0
- package/skills/autosnippet-analysis/SKILL.md +15 -7
- package/skills/autosnippet-candidates/SKILL.md +8 -8
- package/skills/autosnippet-coldstart/SKILL.md +8 -4
- package/skills/autosnippet-concepts/SKILL.md +7 -6
- package/skills/autosnippet-create/SKILL.md +13 -13
- package/skills/autosnippet-intent/SKILL.md +3 -2
- package/skills/autosnippet-lifecycle/SKILL.md +5 -5
- package/skills/autosnippet-recipes/SKILL.md +18 -6
- package/templates/constitution.yaml +1 -1
- package/templates/copilot-instructions.md +6 -6
- package/templates/recipes-setup/README.md +3 -3
- package/dashboard/dist/assets/index-CqJRvYRL.js +0 -197
- package/dashboard/dist/assets/index-DICm9PNa.css +0 -1
- package/lib/cli/CandidateSyncService.js +0 -261
- package/lib/cli/SyncService.js +0 -356
- package/lib/domain/candidate/Candidate.js +0 -196
- package/lib/domain/candidate/CandidateRepository.js +0 -107
- package/lib/domain/candidate/Reasoning.js +0 -52
- package/lib/domain/recipe/Recipe.js +0 -421
- package/lib/domain/recipe/RecipeRepository.js +0 -54
- package/lib/domain/types/CandidateStatus.js +0 -52
- package/lib/http/routes/candidates.js +0 -559
- package/lib/http/routes/recipes.js +0 -397
- package/lib/repository/candidate/CandidateRepository.impl.js +0 -230
- package/lib/repository/recipe/RecipeRepository.impl.js +0 -498
- package/lib/service/candidate/CandidateAggregator.js +0 -52
- package/lib/service/candidate/CandidateFileWriter.js +0 -383
- package/lib/service/candidate/CandidateService.js +0 -1001
- package/lib/service/recipe/RecipeFileWriter.js +0 -514
- package/lib/service/recipe/RecipeService.js +0 -786
- package/lib/service/recipe/RecipeStatsTracker.js +0 -148
|
@@ -1,18 +1,50 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* XcodeAutomation
|
|
2
|
+
* XcodeAutomation — Xcode AppleScript 自动化
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* 通过 osascript 向 Xcode 发送键盘事件,实现行级操作:
|
|
5
|
+
* 跳转行、选中行内容、剪切行、粘贴、在行首插入、删除行内容、保存文档。
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* 所有操作都带超时保护(OSASCRIPT_TIMEOUT),Xcode 未运行时安全跳过。
|
|
8
|
+
* 仅支持 macOS。
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
import { execSync, spawnSync } from 'node:child_process';
|
|
11
12
|
|
|
12
13
|
const OSASCRIPT_TIMEOUT = 5000;
|
|
13
14
|
|
|
15
|
+
// ─────────────────────────────────────────────
|
|
16
|
+
// 内部辅助
|
|
17
|
+
// ─────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 将行号限制为有效正整数(最小值 1)
|
|
21
|
+
* @param {number} n 原始行号
|
|
22
|
+
* @returns {number} 安全的 1-based 行号
|
|
23
|
+
*/
|
|
24
|
+
function _safeLine(n) {
|
|
25
|
+
return Number.isFinite(n) && n > 0 ? n : 1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 执行 osascript 并返回是否成功
|
|
30
|
+
* @param {string[]} args osascript 参数数组(每对 `-e`, `script`)
|
|
31
|
+
* @returns {boolean}
|
|
32
|
+
*/
|
|
33
|
+
function _run(args) {
|
|
34
|
+
try {
|
|
35
|
+
const res = spawnSync('osascript', args, { stdio: 'ignore', timeout: OSASCRIPT_TIMEOUT });
|
|
36
|
+
return res.status === 0;
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ─────────────────────────────────────────────
|
|
43
|
+
// 状态查询
|
|
44
|
+
// ─────────────────────────────────────────────
|
|
45
|
+
|
|
14
46
|
/**
|
|
15
|
-
* 检查 Xcode
|
|
47
|
+
* 检查 Xcode 是否正在运行(不会启动 Xcode)
|
|
16
48
|
*/
|
|
17
49
|
export function isXcodeRunning() {
|
|
18
50
|
if (process.platform !== 'darwin') return false;
|
|
@@ -29,7 +61,7 @@ export function isXcodeRunning() {
|
|
|
29
61
|
}
|
|
30
62
|
|
|
31
63
|
/**
|
|
32
|
-
* 检查 Xcode
|
|
64
|
+
* 检查 Xcode 是否为当前前台应用
|
|
33
65
|
*/
|
|
34
66
|
export function isXcodeFrontmost() {
|
|
35
67
|
if (!isXcodeRunning()) return false;
|
|
@@ -44,132 +76,184 @@ export function isXcodeFrontmost() {
|
|
|
44
76
|
}
|
|
45
77
|
}
|
|
46
78
|
|
|
79
|
+
// ─────────────────────────────────────────────
|
|
80
|
+
// 行操作
|
|
81
|
+
// ─────────────────────────────────────────────
|
|
82
|
+
|
|
47
83
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
84
|
+
* 跳转到指定行
|
|
85
|
+
*
|
|
86
|
+
* 按键序列:Cmd+L → 输入行号 → Return
|
|
87
|
+
*
|
|
88
|
+
* @param {number} lineNumber 1-based 行号
|
|
89
|
+
* @returns {boolean} 是否成功
|
|
90
|
+
*/
|
|
91
|
+
export function jumpToLineInXcode(lineNumber) {
|
|
92
|
+
if (!isXcodeRunning()) return false;
|
|
93
|
+
const n = _safeLine(lineNumber);
|
|
94
|
+
return _run([
|
|
95
|
+
'-e', 'tell application "Xcode" to activate',
|
|
96
|
+
'-e', 'delay 0.2',
|
|
97
|
+
'-e', 'tell application "System Events"',
|
|
98
|
+
'-e', ' keystroke "l" using command down',
|
|
99
|
+
'-e', ' delay 0.2',
|
|
100
|
+
'-e', ` keystroke "${String(n)}"`,
|
|
101
|
+
'-e', ' delay 0.2',
|
|
102
|
+
'-e', ' key code 36',
|
|
103
|
+
'-e', 'end tell',
|
|
104
|
+
]);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 剪切指定行的文本内容(不含换行符)
|
|
109
|
+
*
|
|
110
|
+
* 按键序列:Cmd+L 跳转 → Cmd+← 行首 → Cmd+Shift+→ 选到行尾 → Cmd+X 剪切
|
|
111
|
+
*
|
|
50
112
|
* @param {number} lineNumber 1-based 行号
|
|
51
113
|
* @returns {boolean} 是否成功
|
|
52
114
|
*/
|
|
53
115
|
export function cutLineInXcode(lineNumber) {
|
|
54
116
|
if (!isXcodeRunning()) return false;
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
];
|
|
74
|
-
const res = spawnSync('osascript', args, { stdio: 'ignore', timeout: OSASCRIPT_TIMEOUT });
|
|
75
|
-
return res.status === 0;
|
|
76
|
-
} catch {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
117
|
+
const n = _safeLine(lineNumber);
|
|
118
|
+
return _run([
|
|
119
|
+
'-e', 'tell application "Xcode" to activate',
|
|
120
|
+
'-e', 'delay 0.5',
|
|
121
|
+
'-e', 'tell application "System Events"',
|
|
122
|
+
'-e', ' keystroke "l" using command down', // Cmd+L: Go to Line
|
|
123
|
+
'-e', ' delay 0.5',
|
|
124
|
+
'-e', ` keystroke "${String(n)}"`, // 输入行号
|
|
125
|
+
'-e', ' delay 0.5',
|
|
126
|
+
'-e', ' key code 36', // Return
|
|
127
|
+
'-e', ' delay 0.5',
|
|
128
|
+
'-e', ' key code 123 using command down', // Cmd+← 行首
|
|
129
|
+
'-e', ' delay 0.5',
|
|
130
|
+
'-e', ' key code 124 using {command down, shift down}', // Cmd+Shift+→ 选到行尾
|
|
131
|
+
'-e', ' delay 0.5',
|
|
132
|
+
'-e', ' keystroke "x" using command down', // Cmd+X
|
|
133
|
+
'-e', 'end tell',
|
|
134
|
+
]);
|
|
79
135
|
}
|
|
80
136
|
|
|
81
137
|
/**
|
|
82
|
-
*
|
|
138
|
+
* 删除指定行的文本内容(保留空行,不删除行本身)
|
|
139
|
+
*
|
|
140
|
+
* 按键序列:Cmd+L 跳转 → Cmd+← 行首 → Cmd+Shift+→ 选到行尾 → Delete
|
|
141
|
+
*
|
|
83
142
|
* @param {number} lineNumber 1-based 行号
|
|
84
|
-
* @returns {boolean}
|
|
143
|
+
* @returns {boolean} 是否成功
|
|
85
144
|
*/
|
|
86
|
-
export function
|
|
145
|
+
export function deleteLineContentInXcode(lineNumber) {
|
|
87
146
|
if (!isXcodeRunning()) return false;
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
147
|
+
const n = _safeLine(lineNumber);
|
|
148
|
+
return _run([
|
|
149
|
+
'-e', 'tell application "Xcode" to activate',
|
|
150
|
+
'-e', 'delay 0.3',
|
|
151
|
+
'-e', 'tell application "System Events"',
|
|
152
|
+
'-e', ' keystroke "l" using command down',
|
|
153
|
+
'-e', ' delay 0.3',
|
|
154
|
+
'-e', ` keystroke "${String(n)}"`,
|
|
155
|
+
'-e', ' delay 0.3',
|
|
156
|
+
'-e', ' key code 36',
|
|
157
|
+
'-e', ' delay 0.3',
|
|
158
|
+
'-e', ' key code 123 using command down', // Cmd+← 行首
|
|
159
|
+
'-e', ' delay 0.2',
|
|
160
|
+
'-e', ' key code 124 using {command down, shift down}', // Cmd+Shift+→ 选到行尾
|
|
161
|
+
'-e', ' delay 0.2',
|
|
162
|
+
'-e', ' key code 51', // Delete 键
|
|
163
|
+
'-e', ' delay 0.3',
|
|
164
|
+
'-e', 'end tell',
|
|
165
|
+
]);
|
|
106
166
|
}
|
|
107
167
|
|
|
168
|
+
// ─────────────────────────────────────────────
|
|
169
|
+
// 粘贴操作
|
|
170
|
+
// ─────────────────────────────────────────────
|
|
171
|
+
|
|
108
172
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
173
|
+
* 执行粘贴(Cmd+V)
|
|
174
|
+
*
|
|
175
|
+
* 调用前须确保剪贴板已写入目标内容。
|
|
176
|
+
* @returns {boolean} 是否成功
|
|
111
177
|
*/
|
|
112
178
|
export function pasteInXcode() {
|
|
113
179
|
if (!isXcodeRunning()) return false;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
];
|
|
122
|
-
const res = spawnSync('osascript', args, { stdio: 'ignore', timeout: OSASCRIPT_TIMEOUT });
|
|
123
|
-
return res.status === 0;
|
|
124
|
-
} catch {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
180
|
+
return _run([
|
|
181
|
+
'-e', 'tell application "Xcode" to activate',
|
|
182
|
+
'-e', 'delay 0.2',
|
|
183
|
+
'-e', 'tell application "System Events"',
|
|
184
|
+
'-e', ' keystroke "v" using command down',
|
|
185
|
+
'-e', 'end tell',
|
|
186
|
+
]);
|
|
127
187
|
}
|
|
128
188
|
|
|
129
189
|
/**
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
190
|
+
* 选中当前行内容后粘贴替换
|
|
191
|
+
*
|
|
192
|
+
* 假设光标已在目标行(通常由 jumpToLineInXcode 定位后调用)。
|
|
193
|
+
* 按键序列:Cmd+← 行首 → Cmd+Shift+→ 选到行尾 → Cmd+V 粘贴替换
|
|
194
|
+
*
|
|
195
|
+
* @returns {boolean} 是否成功
|
|
134
196
|
*/
|
|
135
197
|
export function selectAndPasteInXcode() {
|
|
136
198
|
if (!isXcodeRunning()) return false;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
];
|
|
149
|
-
const res = spawnSync('osascript', args, { stdio: 'ignore', timeout: OSASCRIPT_TIMEOUT });
|
|
150
|
-
return res.status === 0;
|
|
151
|
-
} catch {
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
199
|
+
return _run([
|
|
200
|
+
'-e', 'tell application "Xcode" to activate',
|
|
201
|
+
'-e', 'delay 0.5',
|
|
202
|
+
'-e', 'tell application "System Events"',
|
|
203
|
+
'-e', ' key code 123 using command down', // Cmd+← 行首
|
|
204
|
+
'-e', ' delay 0.1',
|
|
205
|
+
'-e', ' key code 124 using {command down, shift down}', // Cmd+Shift+→ 选到行尾
|
|
206
|
+
'-e', ' delay 0.2',
|
|
207
|
+
'-e', ' keystroke "v" using command down', // Cmd+V 粘贴替换
|
|
208
|
+
'-e', 'end tell',
|
|
209
|
+
]);
|
|
154
210
|
}
|
|
155
211
|
|
|
212
|
+
/**
|
|
213
|
+
* 跳转到指定行行首并粘贴剪贴板内容
|
|
214
|
+
*
|
|
215
|
+
* 用于在 import 区域插入新行。
|
|
216
|
+
* 按键序列:Cmd+L → 输入行号 → Return → Cmd+← 行首 → Cmd+V 粘贴
|
|
217
|
+
*
|
|
218
|
+
* @param {number} lineNumber 1-based 行号
|
|
219
|
+
* @returns {boolean} 是否成功
|
|
220
|
+
*/
|
|
221
|
+
export function insertAtLineStartInXcode(lineNumber) {
|
|
222
|
+
if (!isXcodeRunning()) return false;
|
|
223
|
+
const n = _safeLine(lineNumber);
|
|
224
|
+
return _run([
|
|
225
|
+
'-e', 'tell application "Xcode" to activate',
|
|
226
|
+
'-e', 'delay 0.3',
|
|
227
|
+
'-e', 'tell application "System Events"',
|
|
228
|
+
'-e', ' keystroke "l" using command down', // Cmd+L: Go to Line
|
|
229
|
+
'-e', ' delay 0.3',
|
|
230
|
+
'-e', ` keystroke "${String(n)}"`, // 输入行号
|
|
231
|
+
'-e', ' delay 0.3',
|
|
232
|
+
'-e', ' key code 36', // Return
|
|
233
|
+
'-e', ' delay 0.3',
|
|
234
|
+
'-e', ' key code 123 using command down', // Cmd+← 行首
|
|
235
|
+
'-e', ' delay 0.2',
|
|
236
|
+
'-e', ' keystroke "v" using command down', // Cmd+V 粘贴
|
|
237
|
+
'-e', ' delay 0.3',
|
|
238
|
+
'-e', 'end tell',
|
|
239
|
+
]);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ─────────────────────────────────────────────
|
|
243
|
+
// 文档操作
|
|
244
|
+
// ─────────────────────────────────────────────
|
|
245
|
+
|
|
156
246
|
/**
|
|
157
247
|
* 保存 Xcode 当前活动文档(Cmd+S)
|
|
158
|
-
* @returns {boolean}
|
|
248
|
+
* @returns {boolean} 是否成功
|
|
159
249
|
*/
|
|
160
250
|
export function saveActiveDocumentInXcode() {
|
|
161
251
|
if (!isXcodeRunning()) return false;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
];
|
|
170
|
-
const res = spawnSync('osascript', args, { stdio: 'ignore', timeout: OSASCRIPT_TIMEOUT });
|
|
171
|
-
return res.status === 0;
|
|
172
|
-
} catch {
|
|
173
|
-
return false;
|
|
174
|
-
}
|
|
252
|
+
return _run([
|
|
253
|
+
'-e', 'tell application "Xcode" to activate',
|
|
254
|
+
'-e', 'delay 0.1',
|
|
255
|
+
'-e', 'tell application "System Events"',
|
|
256
|
+
'-e', ' keystroke "s" using command down',
|
|
257
|
+
'-e', 'end tell',
|
|
258
|
+
]);
|
|
175
259
|
}
|
|
@@ -6,10 +6,12 @@ import Gateway from '../core/gateway/Gateway.js';
|
|
|
6
6
|
import { readdirSync, statSync } from 'node:fs';
|
|
7
7
|
import { join as pathJoin, relative as pathRelative, extname as pathExtname } from 'node:path';
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { KnowledgeRepositoryImpl } from '../repository/knowledge/KnowledgeRepository.impl.js';
|
|
10
|
+
import { KnowledgeFileWriter } from '../service/knowledge/KnowledgeFileWriter.js';
|
|
11
|
+
import { KnowledgeSyncService } from '../cli/KnowledgeSyncService.js';
|
|
12
|
+
import { KnowledgeService } from '../service/knowledge/KnowledgeService.js';
|
|
13
|
+
import { ConfidenceRouter } from '../service/knowledge/ConfidenceRouter.js';
|
|
11
14
|
import { SnippetFactory } from '../service/snippet/SnippetFactory.js';
|
|
12
|
-
import { RecipeService } from '../service/recipe/RecipeService.js';
|
|
13
15
|
import { GuardService } from '../service/guard/GuardService.js';
|
|
14
16
|
import { KnowledgeGraphService } from '../service/knowledge/KnowledgeGraphService.js';
|
|
15
17
|
import { SearchEngine } from '../service/search/SearchEngine.js';
|
|
@@ -22,13 +24,9 @@ import { RetrievalFunnel } from '../service/search/RetrievalFunnel.js';
|
|
|
22
24
|
import { JsonVectorAdapter } from '../infrastructure/vector/JsonVectorAdapter.js';
|
|
23
25
|
import { IndexingPipeline } from '../infrastructure/vector/IndexingPipeline.js';
|
|
24
26
|
|
|
25
|
-
// ─── P1: Injection / Snippet
|
|
27
|
+
// ─── P1: Injection / Snippet ─────────────────
|
|
26
28
|
import { RecipeParser } from '../service/recipe/RecipeParser.js';
|
|
27
|
-
import { RecipeStatsTracker } from '../service/recipe/RecipeStatsTracker.js';
|
|
28
29
|
import { RecipeCandidateValidator } from '../service/recipe/RecipeCandidateValidator.js';
|
|
29
|
-
import { RecipeFileWriter } from '../service/recipe/RecipeFileWriter.js';
|
|
30
|
-
import { CandidateFileWriter } from '../service/candidate/CandidateFileWriter.js';
|
|
31
|
-
import { CandidateService } from '../service/candidate/CandidateService.js';
|
|
32
30
|
import { SnippetInstaller } from '../service/snippet/SnippetInstaller.js';
|
|
33
31
|
|
|
34
32
|
// ─── P1: Guard Advanced ──────────────────────────────
|
|
@@ -65,6 +63,9 @@ import { EventBus } from '../infrastructure/event/EventBus.js';
|
|
|
65
63
|
import { BootstrapTaskManager } from '../service/bootstrap/BootstrapTaskManager.js';
|
|
66
64
|
import { getRealtimeService as _getRealtimeService } from '../infrastructure/realtime/RealtimeService.js';
|
|
67
65
|
|
|
66
|
+
// ─── P3: Cursor Delivery Pipeline ──────────────────────
|
|
67
|
+
import { CursorDeliveryPipeline } from '../service/cursor/CursorDeliveryPipeline.js';
|
|
68
|
+
|
|
68
69
|
/**
|
|
69
70
|
* DependencyInjection 容器
|
|
70
71
|
* 管理所有应用层的仓储、服务和基础设施依赖的创建和注入
|
|
@@ -238,22 +239,31 @@ export class ServiceContainer {
|
|
|
238
239
|
* 注册仓储
|
|
239
240
|
*/
|
|
240
241
|
_registerRepositories() {
|
|
241
|
-
//
|
|
242
|
-
this.register('
|
|
243
|
-
if (!this.singletons.
|
|
242
|
+
// KnowledgeRepository (统一知识实体)
|
|
243
|
+
this.register('knowledgeRepository', () => {
|
|
244
|
+
if (!this.singletons.knowledgeRepository) {
|
|
244
245
|
const database = this.get('database');
|
|
245
|
-
this.singletons.
|
|
246
|
+
this.singletons.knowledgeRepository = new KnowledgeRepositoryImpl(database);
|
|
246
247
|
}
|
|
247
|
-
return this.singletons.
|
|
248
|
+
return this.singletons.knowledgeRepository;
|
|
248
249
|
});
|
|
249
250
|
|
|
250
|
-
//
|
|
251
|
-
this.register('
|
|
252
|
-
if (!this.singletons.
|
|
253
|
-
const
|
|
254
|
-
this.singletons.
|
|
251
|
+
// KnowledgeFileWriter (统一 .md 序列化/落盘)
|
|
252
|
+
this.register('knowledgeFileWriter', () => {
|
|
253
|
+
if (!this.singletons.knowledgeFileWriter) {
|
|
254
|
+
const projectRoot = this.singletons._projectRoot || process.cwd();
|
|
255
|
+
this.singletons.knowledgeFileWriter = new KnowledgeFileWriter(projectRoot);
|
|
256
|
+
}
|
|
257
|
+
return this.singletons.knowledgeFileWriter;
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// KnowledgeSyncService (统一 .md ↔ DB 同步)
|
|
261
|
+
this.register('knowledgeSyncService', () => {
|
|
262
|
+
if (!this.singletons.knowledgeSyncService) {
|
|
263
|
+
const projectRoot = this.singletons._projectRoot || process.cwd();
|
|
264
|
+
this.singletons.knowledgeSyncService = new KnowledgeSyncService(projectRoot);
|
|
255
265
|
}
|
|
256
|
-
return this.singletons.
|
|
266
|
+
return this.singletons.knowledgeSyncService;
|
|
257
267
|
});
|
|
258
268
|
}
|
|
259
269
|
|
|
@@ -261,54 +271,45 @@ export class ServiceContainer {
|
|
|
261
271
|
* 注册服务
|
|
262
272
|
*/
|
|
263
273
|
_registerServices() {
|
|
264
|
-
//
|
|
265
|
-
this.register('
|
|
266
|
-
if (!this.singletons.
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
const gateway = this.get('gateway');
|
|
270
|
-
const projectRoot = this.singletons._projectRoot || process.cwd();
|
|
271
|
-
const candidateFileWriter = new CandidateFileWriter(projectRoot);
|
|
272
|
-
const skillHooks = this.get('skillHooks');
|
|
273
|
-
this.singletons.candidateService = new CandidateService(
|
|
274
|
-
candidateRepository,
|
|
275
|
-
auditLogger,
|
|
276
|
-
gateway,
|
|
277
|
-
{ fileWriter: candidateFileWriter, skillHooks }
|
|
278
|
-
);
|
|
274
|
+
// ConfidenceRouter (V3: 知识条目自动审核路由)
|
|
275
|
+
this.register('confidenceRouter', () => {
|
|
276
|
+
if (!this.singletons.confidenceRouter) {
|
|
277
|
+
const qualityScorer = this.get('qualityScorer');
|
|
278
|
+
this.singletons.confidenceRouter = new ConfidenceRouter({}, qualityScorer);
|
|
279
279
|
}
|
|
280
|
-
return this.singletons.
|
|
280
|
+
return this.singletons.confidenceRouter;
|
|
281
281
|
});
|
|
282
282
|
|
|
283
|
-
//
|
|
284
|
-
this.register('
|
|
285
|
-
if (!this.singletons.
|
|
286
|
-
const
|
|
283
|
+
// KnowledgeService (V3: 统一知识服务)
|
|
284
|
+
this.register('knowledgeService', () => {
|
|
285
|
+
if (!this.singletons.knowledgeService) {
|
|
286
|
+
const knowledgeRepository = this.get('knowledgeRepository');
|
|
287
287
|
const auditLogger = this.get('auditLogger');
|
|
288
288
|
const gateway = this.get('gateway');
|
|
289
289
|
const knowledgeGraphService = this.get('knowledgeGraphService');
|
|
290
|
-
const
|
|
291
|
-
const fileWriter = new RecipeFileWriter(projectRoot);
|
|
290
|
+
const fileWriter = this.get('knowledgeFileWriter');
|
|
292
291
|
const skillHooks = this.get('skillHooks');
|
|
293
|
-
|
|
294
|
-
|
|
292
|
+
const confidenceRouter = this.get('confidenceRouter');
|
|
293
|
+
const qualityScorer = this.get('qualityScorer');
|
|
294
|
+
this.singletons.knowledgeService = new KnowledgeService(
|
|
295
|
+
knowledgeRepository,
|
|
295
296
|
auditLogger,
|
|
296
297
|
gateway,
|
|
297
298
|
knowledgeGraphService,
|
|
298
|
-
{ fileWriter, skillHooks }
|
|
299
|
+
{ fileWriter, skillHooks, confidenceRouter, qualityScorer }
|
|
299
300
|
);
|
|
300
301
|
}
|
|
301
|
-
return this.singletons.
|
|
302
|
+
return this.singletons.knowledgeService;
|
|
302
303
|
});
|
|
303
304
|
|
|
304
|
-
// GuardService (
|
|
305
|
+
// GuardService (V3: uses knowledgeRepository)
|
|
305
306
|
this.register('guardService', () => {
|
|
306
307
|
if (!this.singletons.guardService) {
|
|
307
|
-
const
|
|
308
|
+
const knowledgeRepository = this.get('knowledgeRepository');
|
|
308
309
|
const auditLogger = this.get('auditLogger');
|
|
309
310
|
const gateway = this.get('gateway');
|
|
310
311
|
this.singletons.guardService = new GuardService(
|
|
311
|
-
|
|
312
|
+
knowledgeRepository,
|
|
312
313
|
auditLogger,
|
|
313
314
|
gateway
|
|
314
315
|
);
|
|
@@ -394,15 +395,6 @@ export class ServiceContainer {
|
|
|
394
395
|
return this.singletons.recipeParser;
|
|
395
396
|
});
|
|
396
397
|
|
|
397
|
-
// RecipeStatsTracker
|
|
398
|
-
this.register('recipeStatsTracker', () => {
|
|
399
|
-
if (!this.singletons.recipeStatsTracker) {
|
|
400
|
-
const projectRoot = this.singletons._projectRoot || process.cwd();
|
|
401
|
-
this.singletons.recipeStatsTracker = new RecipeStatsTracker(projectRoot);
|
|
402
|
-
}
|
|
403
|
-
return this.singletons.recipeStatsTracker;
|
|
404
|
-
});
|
|
405
|
-
|
|
406
398
|
// RecipeCandidateValidator
|
|
407
399
|
this.register('recipeCandidateValidator', () => {
|
|
408
400
|
if (!this.singletons.recipeCandidateValidator) {
|
|
@@ -411,11 +403,11 @@ export class ServiceContainer {
|
|
|
411
403
|
return this.singletons.recipeCandidateValidator;
|
|
412
404
|
});
|
|
413
405
|
|
|
414
|
-
// SnippetFactory (
|
|
406
|
+
// SnippetFactory (V3: uses knowledgeRepository)
|
|
415
407
|
this.register('snippetFactory', () => {
|
|
416
408
|
if (!this.singletons.snippetFactory) {
|
|
417
|
-
const
|
|
418
|
-
this.singletons.snippetFactory = new SnippetFactory(
|
|
409
|
+
const knowledgeRepo = this.get('knowledgeRepository');
|
|
410
|
+
this.singletons.snippetFactory = new SnippetFactory(knowledgeRepo);
|
|
419
411
|
}
|
|
420
412
|
return this.singletons.snippetFactory;
|
|
421
413
|
});
|
|
@@ -473,6 +465,9 @@ export class ServiceContainer {
|
|
|
473
465
|
return this.singletons.qualityScorer;
|
|
474
466
|
});
|
|
475
467
|
|
|
468
|
+
// RecipeExtractor(语义标签提取)
|
|
469
|
+
this.register('recipeExtractor', () => this.singletons._recipeExtractor || null);
|
|
470
|
+
|
|
476
471
|
// FeedbackCollector
|
|
477
472
|
this.register('feedbackCollector', () => {
|
|
478
473
|
if (!this.singletons.feedbackCollector) {
|
|
@@ -546,6 +541,20 @@ export class ServiceContainer {
|
|
|
546
541
|
}
|
|
547
542
|
return this.singletons.skillHooks;
|
|
548
543
|
});
|
|
544
|
+
|
|
545
|
+
// CursorDeliveryPipeline (4 通道交付:知识库 → Cursor Rules/Skills)
|
|
546
|
+
this.register('cursorDeliveryPipeline', () => {
|
|
547
|
+
if (!this.singletons.cursorDeliveryPipeline) {
|
|
548
|
+
const knowledgeService = this.get('knowledgeService');
|
|
549
|
+
const projectRoot = this.singletons._projectRoot || process.cwd();
|
|
550
|
+
this.singletons.cursorDeliveryPipeline = new CursorDeliveryPipeline({
|
|
551
|
+
knowledgeService,
|
|
552
|
+
projectRoot,
|
|
553
|
+
logger: this.logger,
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
return this.singletons.cursorDeliveryPipeline;
|
|
557
|
+
});
|
|
549
558
|
}
|
|
550
559
|
|
|
551
560
|
/**
|