autosnippet 2.9.0 → 2.10.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 +4 -4
- package/bin/cli.js +5 -33
- package/config/constitution.yaml +9 -2
- package/dashboard/dist/assets/{icons-CH-H9x0E.js → icons-BkT3XrKf.js} +105 -100
- package/dashboard/dist/assets/index-BsB7DzW4.css +1 -0
- package/dashboard/dist/assets/index-DdmQMrJJ.js +155 -0
- package/dashboard/dist/index.html +3 -3
- package/lib/cli/AiScanService.js +13 -11
- package/lib/cli/KnowledgeSyncService.js +343 -0
- package/lib/cli/SetupService.js +8 -26
- package/lib/core/gateway/GatewayActionRegistry.js +48 -58
- package/lib/domain/index.js +16 -11
- package/lib/domain/knowledge/KnowledgeEntry.js +351 -0
- package/lib/domain/knowledge/KnowledgeRepository.js +123 -0
- package/lib/domain/knowledge/Lifecycle.js +109 -0
- package/lib/domain/knowledge/index.js +27 -0
- package/lib/domain/knowledge/values/Constraints.js +125 -0
- package/lib/domain/knowledge/values/Content.js +86 -0
- package/lib/domain/knowledge/values/Quality.js +93 -0
- package/lib/domain/knowledge/values/Reasoning.js +69 -0
- package/lib/domain/knowledge/values/Relations.js +168 -0
- package/lib/domain/knowledge/values/Stats.js +87 -0
- package/lib/domain/knowledge/values/index.js +9 -0
- package/lib/external/ai/AiProvider.js +48 -0
- package/lib/external/mcp/McpServer.js +7 -5
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +2 -2
- package/lib/external/mcp/handlers/bootstrap.js +116 -11
- package/lib/external/mcp/handlers/browse.js +77 -73
- package/lib/external/mcp/handlers/candidate.js +29 -276
- package/lib/external/mcp/handlers/guard.js +2 -0
- package/lib/external/mcp/handlers/knowledge.js +205 -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 +125 -138
- package/lib/http/HttpServer.js +4 -8
- 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/external/XcodeAutomation.js +187 -103
- package/lib/injection/ServiceContainer.js +49 -60
- package/lib/repository/knowledge/KnowledgeRepository.impl.js +373 -0
- package/lib/service/automation/DirectiveDetector.js +2 -3
- package/lib/service/automation/FileWatcher.js +67 -28
- package/lib/service/automation/XcodeIntegration.js +931 -156
- package/lib/service/automation/handlers/AlinkHandler.js +6 -4
- package/lib/service/automation/handlers/CreateHandler.js +53 -18
- package/lib/service/automation/handlers/GuardHandler.js +183 -20
- package/lib/service/automation/handlers/SearchHandler.js +35 -17
- package/lib/service/chat/CandidateGuardrail.js +1 -1
- package/lib/service/chat/ChatAgent.js +46 -45
- package/lib/service/chat/ContextWindow.js +5 -5
- package/lib/service/chat/ProducerAgent.js +7 -7
- package/lib/service/chat/tools.js +130 -123
- package/lib/service/guard/GuardCheckEngine.js +114 -10
- package/lib/service/guard/GuardService.js +59 -48
- package/lib/service/knowledge/ConfidenceRouter.js +159 -0
- package/lib/service/knowledge/KnowledgeFileWriter.js +602 -0
- package/lib/service/knowledge/KnowledgeService.js +725 -0
- package/lib/service/search/SearchEngine.js +92 -19
- package/lib/service/skills/SignalCollector.js +12 -7
- package/lib/service/skills/SkillAdvisor.js +13 -11
- package/lib/service/snippet/SnippetFactory.js +5 -5
- 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 +6 -6
- package/skills/autosnippet-coldstart/SKILL.md +7 -3
- 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 +16 -4
- 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
package/lib/domain/index.js
CHANGED
|
@@ -3,18 +3,23 @@
|
|
|
3
3
|
* 导出所有实体、值对象和仓储接口
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
//
|
|
7
|
-
export { Candidate } from './candidate/Candidate.js';
|
|
8
|
-
export { default as Reasoning } from './candidate/Reasoning.js';
|
|
9
|
-
export { CandidateStatus, isValidCandidateStatus, isValidStateTransition } from './types/CandidateStatus.js';
|
|
10
|
-
export { default as CandidateRepository } from './candidate/CandidateRepository.js';
|
|
11
|
-
|
|
12
|
-
// Recipe 相关(统一知识实体)
|
|
6
|
+
// Knowledge 统一知识实体 (V3)
|
|
13
7
|
export {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
KnowledgeEntry,
|
|
9
|
+
Lifecycle,
|
|
10
|
+
isValidTransition,
|
|
11
|
+
isValidLifecycle,
|
|
12
|
+
isCandidate as isLifecycleCandidate,
|
|
13
|
+
CANDIDATE_STATES,
|
|
14
|
+
inferKind as inferKindV3,
|
|
15
|
+
} from './knowledge/index.js';
|
|
16
|
+
export { Content } from './knowledge/values/Content.js';
|
|
17
|
+
export { Relations, RELATION_BUCKETS, RELATION_BUCKETS as RelationType } from './knowledge/values/Relations.js';
|
|
18
|
+
export { Constraints } from './knowledge/values/Constraints.js';
|
|
19
|
+
export { Reasoning as ReasoningV3 } from './knowledge/values/Reasoning.js';
|
|
20
|
+
export { Quality } from './knowledge/values/Quality.js';
|
|
21
|
+
export { Stats } from './knowledge/values/Stats.js';
|
|
22
|
+
export { KnowledgeRepository } from './knowledge/KnowledgeRepository.js';
|
|
18
23
|
|
|
19
24
|
// Snippet 相关
|
|
20
25
|
export { Snippet } from './snippet/Snippet.js';
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
import { Lifecycle, isValidTransition, isCandidate as isLifecycleCandidate, inferKind, normalizeLifecycle } from './Lifecycle.js';
|
|
3
|
+
import { Content, Relations, Constraints, Reasoning, Quality, Stats } from './values/index.js';
|
|
4
|
+
|
|
5
|
+
/* ═══════════════════════════════════════════════════════════
|
|
6
|
+
* KnowledgeEntry — 统一知识实体
|
|
7
|
+
*
|
|
8
|
+
* 合并原 Candidate + Recipe。
|
|
9
|
+
* lifecycle 状态决定其行为(3 状态简化版):
|
|
10
|
+
* pending → 待审核(新建条目初始状态)
|
|
11
|
+
* active → 已发布(被 Guard/Search/Export 消费)
|
|
12
|
+
* deprecated → 已废弃
|
|
13
|
+
* ═══════════════════════════════════════════════════════════ */
|
|
14
|
+
|
|
15
|
+
export class KnowledgeEntry {
|
|
16
|
+
/**
|
|
17
|
+
* @param {Object} props
|
|
18
|
+
*/
|
|
19
|
+
constructor(props = {}) {
|
|
20
|
+
// ── 标识 ──
|
|
21
|
+
this.id = props.id || uuidv4();
|
|
22
|
+
this.title = props.title || '';
|
|
23
|
+
this.trigger = props.trigger || '';
|
|
24
|
+
this.description = props.description || '';
|
|
25
|
+
|
|
26
|
+
// ── 生命周期 ──
|
|
27
|
+
this.lifecycle = normalizeLifecycle(props.lifecycle || Lifecycle.PENDING);
|
|
28
|
+
this.lifecycleHistory = props.lifecycleHistory || [];
|
|
29
|
+
this.autoApprovable = props.autoApprovable ?? props.probation ?? false;
|
|
30
|
+
|
|
31
|
+
// ── 语言与分类 ──
|
|
32
|
+
this.language = props.language || '';
|
|
33
|
+
this.category = props.category || '';
|
|
34
|
+
this.knowledgeType = props.knowledgeType || 'code-pattern';
|
|
35
|
+
this.kind = props.kind || inferKind(this.knowledgeType);
|
|
36
|
+
this.complexity = props.complexity || 'intermediate';
|
|
37
|
+
this.scope = props.scope || 'universal';
|
|
38
|
+
this.difficulty = props.difficulty || null;
|
|
39
|
+
this.tags = props.tags || [];
|
|
40
|
+
|
|
41
|
+
// ── 国际化文本 ──
|
|
42
|
+
this.summaryCn = props.summaryCn ?? '';
|
|
43
|
+
this.summaryEn = props.summaryEn ?? '';
|
|
44
|
+
this.usageGuideCn = props.usageGuideCn ?? '';
|
|
45
|
+
this.usageGuideEn = props.usageGuideEn ?? '';
|
|
46
|
+
|
|
47
|
+
// ── 值对象 ──
|
|
48
|
+
this.content = Content.from(props.content);
|
|
49
|
+
this.relations = Relations.from(props.relations);
|
|
50
|
+
this.constraints = Constraints.from(props.constraints);
|
|
51
|
+
this.reasoning = Reasoning.from(props.reasoning);
|
|
52
|
+
this.quality = Quality.from(props.quality);
|
|
53
|
+
this.stats = Stats.from(props.stats);
|
|
54
|
+
|
|
55
|
+
// ── 代码头文件 (ObjC/Swift) ──
|
|
56
|
+
this.headers = props.headers || [];
|
|
57
|
+
this.headerPaths = props.headerPaths || [];
|
|
58
|
+
this.moduleName = props.moduleName || '';
|
|
59
|
+
this.includeHeaders = props.includeHeaders ?? false;
|
|
60
|
+
|
|
61
|
+
// ── AI 润色 ──
|
|
62
|
+
this.agentNotes = props.agentNotes || null;
|
|
63
|
+
this.aiInsight = props.aiInsight || null;
|
|
64
|
+
|
|
65
|
+
// ── 审核 ──
|
|
66
|
+
this.reviewedBy = props.reviewedBy || null;
|
|
67
|
+
this.reviewedAt = props.reviewedAt || null;
|
|
68
|
+
this.rejectionReason = props.rejectionReason || null;
|
|
69
|
+
|
|
70
|
+
// ── 来源 ──
|
|
71
|
+
this.source = props.source || 'manual';
|
|
72
|
+
this.sourceFile = props.sourceFile || null;
|
|
73
|
+
this.sourceCandidateId = props.sourceCandidateId || null;
|
|
74
|
+
|
|
75
|
+
// ── 时间 ──
|
|
76
|
+
this.createdBy = props.createdBy || 'system';
|
|
77
|
+
this.createdAt = props.createdAt || Math.floor(Date.now() / 1000);
|
|
78
|
+
this.updatedAt = props.updatedAt || Math.floor(Date.now() / 1000);
|
|
79
|
+
this.publishedAt = props.publishedAt || null;
|
|
80
|
+
this.publishedBy = props.publishedBy || null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* ═══ 生命周期操作 ═══════════════════════════════════ */
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 发布 (pending → active)
|
|
87
|
+
* @param {string} publisher
|
|
88
|
+
* @returns {{ success: boolean, error?: string }}
|
|
89
|
+
*/
|
|
90
|
+
publish(publisher) {
|
|
91
|
+
if (!this.isValid()) {
|
|
92
|
+
return { success: false, error: '内容不完整,无法发布' };
|
|
93
|
+
}
|
|
94
|
+
const result = this._transition(Lifecycle.ACTIVE);
|
|
95
|
+
if (result.success) {
|
|
96
|
+
this.publishedAt = this._now();
|
|
97
|
+
this.publishedBy = publisher;
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 弃用 (pending|active → deprecated)
|
|
104
|
+
* @param {string} reason
|
|
105
|
+
* @returns {{ success: boolean, error?: string }}
|
|
106
|
+
*/
|
|
107
|
+
deprecate(reason) {
|
|
108
|
+
const result = this._transition(Lifecycle.DEPRECATED);
|
|
109
|
+
if (result.success) {
|
|
110
|
+
this.rejectionReason = reason;
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 重新激活 (deprecated → pending)
|
|
117
|
+
* @returns {{ success: boolean, error?: string }}
|
|
118
|
+
*/
|
|
119
|
+
reactivate() {
|
|
120
|
+
const result = this._transition(Lifecycle.PENDING);
|
|
121
|
+
if (result.success) {
|
|
122
|
+
this.rejectionReason = null;
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── 向后兼容的别名方法(旧代码可能引用) ──
|
|
128
|
+
|
|
129
|
+
/** @deprecated 简化后统一为 pending,无需 submit */
|
|
130
|
+
submit() { return { success: true }; }
|
|
131
|
+
|
|
132
|
+
/** @deprecated 简化后无需 approve,直接 publish */
|
|
133
|
+
approve(reviewer) { return this.publish(reviewer); }
|
|
134
|
+
|
|
135
|
+
/** @deprecated 简化后 reject = deprecate */
|
|
136
|
+
reject(reviewer, reason) { return this.deprecate(reason); }
|
|
137
|
+
|
|
138
|
+
/** @deprecated 简化后无需 toDraft */
|
|
139
|
+
toDraft() { return this.reactivate(); }
|
|
140
|
+
|
|
141
|
+
/** @deprecated 简化后 fastTrack = publish */
|
|
142
|
+
fastTrack(publisher) { return this.publish(publisher); }
|
|
143
|
+
|
|
144
|
+
/** @deprecated 简化后无需 autoApprove */
|
|
145
|
+
autoApprove() { return { success: true }; }
|
|
146
|
+
|
|
147
|
+
/* ═══ 谓词 ═══════════════════════════════════════════ */
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 是否处于候选阶段
|
|
151
|
+
* @returns {boolean}
|
|
152
|
+
*/
|
|
153
|
+
isCandidate() {
|
|
154
|
+
return isLifecycleCandidate(this.lifecycle);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 是否可被 Guard/Search/Export 消费
|
|
159
|
+
* @returns {boolean}
|
|
160
|
+
*/
|
|
161
|
+
isActive() {
|
|
162
|
+
return this.lifecycle === Lifecycle.ACTIVE;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 是否为 Guard 规则类型
|
|
167
|
+
* @returns {boolean}
|
|
168
|
+
*/
|
|
169
|
+
isRule() {
|
|
170
|
+
return this.kind === 'rule';
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* 内容是否有效
|
|
175
|
+
* @returns {boolean}
|
|
176
|
+
*/
|
|
177
|
+
isValid() {
|
|
178
|
+
return !!(this.title?.trim() && this.content.hasContent());
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* ═══ Guard 消费 ═══════════════════════════════════ */
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 返回此 Entry 中可被 GuardCheckEngine 消费的规则列表
|
|
185
|
+
* @returns {Array<Object>}
|
|
186
|
+
*/
|
|
187
|
+
getGuardRules() {
|
|
188
|
+
if (!this.isActive() || !this.isRule()) return [];
|
|
189
|
+
|
|
190
|
+
const regexRules = this.constraints.getRegexGuards().map(g => ({
|
|
191
|
+
id: g.id || this.id,
|
|
192
|
+
type: 'regex',
|
|
193
|
+
name: g.message || this.title,
|
|
194
|
+
message: g.message || this.description || this.title,
|
|
195
|
+
pattern: g.pattern,
|
|
196
|
+
languages: this.language ? [this.language] : [],
|
|
197
|
+
severity: g.severity || 'warning',
|
|
198
|
+
source: 'knowledge_entry',
|
|
199
|
+
fixSuggestion: g.fix_suggestion || null,
|
|
200
|
+
}));
|
|
201
|
+
|
|
202
|
+
const astRules = this.constraints.getAstGuards().map(g => ({
|
|
203
|
+
id: g.id || `${this.id}:ast`,
|
|
204
|
+
type: 'ast',
|
|
205
|
+
name: g.message || this.title,
|
|
206
|
+
message: g.message,
|
|
207
|
+
astQuery: g.ast_query,
|
|
208
|
+
languages: g.ast_query?.language ? [g.ast_query.language] : [],
|
|
209
|
+
severity: g.severity || 'warning',
|
|
210
|
+
source: 'knowledge_entry',
|
|
211
|
+
fixSuggestion: g.fix_suggestion || null,
|
|
212
|
+
}));
|
|
213
|
+
|
|
214
|
+
return [...regexRules, ...astRules];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/* ═══ 序列化 ═══════════════════════════════════════ */
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Domain → wire format JSON (统一格式,DB/MCP/API 共用)
|
|
221
|
+
*/
|
|
222
|
+
toJSON() {
|
|
223
|
+
return {
|
|
224
|
+
id: this.id,
|
|
225
|
+
title: this.title,
|
|
226
|
+
trigger: this.trigger,
|
|
227
|
+
description: this.description,
|
|
228
|
+
lifecycle: this.lifecycle,
|
|
229
|
+
lifecycle_history: this.lifecycleHistory,
|
|
230
|
+
auto_approvable: this.autoApprovable,
|
|
231
|
+
language: this.language,
|
|
232
|
+
category: this.category,
|
|
233
|
+
kind: this.kind,
|
|
234
|
+
knowledge_type: this.knowledgeType,
|
|
235
|
+
complexity: this.complexity,
|
|
236
|
+
scope: this.scope,
|
|
237
|
+
difficulty: this.difficulty,
|
|
238
|
+
tags: this.tags,
|
|
239
|
+
summary_cn: this.summaryCn,
|
|
240
|
+
summary_en: this.summaryEn,
|
|
241
|
+
usage_guide_cn: this.usageGuideCn,
|
|
242
|
+
usage_guide_en: this.usageGuideEn,
|
|
243
|
+
content: this.content.toJSON(),
|
|
244
|
+
relations: this.relations.toJSON(),
|
|
245
|
+
constraints: this.constraints.toJSON(),
|
|
246
|
+
reasoning: this.reasoning.toJSON(),
|
|
247
|
+
quality: this.quality.toJSON(),
|
|
248
|
+
stats: this.stats.toJSON(),
|
|
249
|
+
headers: this.headers,
|
|
250
|
+
header_paths: this.headerPaths,
|
|
251
|
+
module_name: this.moduleName,
|
|
252
|
+
include_headers: this.includeHeaders,
|
|
253
|
+
agent_notes: this.agentNotes,
|
|
254
|
+
ai_insight: this.aiInsight,
|
|
255
|
+
reviewed_by: this.reviewedBy,
|
|
256
|
+
reviewed_at: this.reviewedAt,
|
|
257
|
+
rejection_reason: this.rejectionReason,
|
|
258
|
+
source: this.source,
|
|
259
|
+
source_file: this.sourceFile,
|
|
260
|
+
source_candidate_id: this.sourceCandidateId,
|
|
261
|
+
created_by: this.createdBy,
|
|
262
|
+
created_at: this.createdAt,
|
|
263
|
+
updated_at: this.updatedAt,
|
|
264
|
+
published_at: this.publishedAt,
|
|
265
|
+
published_by: this.publishedBy,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* wire format → Domain
|
|
271
|
+
* @param {Object} data snake_case 格式数据
|
|
272
|
+
* @returns {KnowledgeEntry}
|
|
273
|
+
*/
|
|
274
|
+
static fromJSON(data) {
|
|
275
|
+
if (!data) return new KnowledgeEntry();
|
|
276
|
+
return new KnowledgeEntry({
|
|
277
|
+
id: data.id,
|
|
278
|
+
title: data.title,
|
|
279
|
+
trigger: data.trigger,
|
|
280
|
+
description: data.description,
|
|
281
|
+
lifecycle: data.lifecycle,
|
|
282
|
+
lifecycleHistory: data.lifecycle_history,
|
|
283
|
+
autoApprovable: data.auto_approvable ?? data.probation,
|
|
284
|
+
language: data.language,
|
|
285
|
+
category: data.category,
|
|
286
|
+
kind: data.kind,
|
|
287
|
+
knowledgeType: data.knowledge_type,
|
|
288
|
+
complexity: data.complexity,
|
|
289
|
+
scope: data.scope,
|
|
290
|
+
difficulty: data.difficulty,
|
|
291
|
+
tags: data.tags,
|
|
292
|
+
summaryCn: data.summary_cn,
|
|
293
|
+
summaryEn: data.summary_en,
|
|
294
|
+
usageGuideCn: data.usage_guide_cn,
|
|
295
|
+
usageGuideEn: data.usage_guide_en,
|
|
296
|
+
content: data.content,
|
|
297
|
+
relations: data.relations,
|
|
298
|
+
constraints: data.constraints,
|
|
299
|
+
reasoning: data.reasoning,
|
|
300
|
+
quality: data.quality,
|
|
301
|
+
stats: data.stats,
|
|
302
|
+
headers: data.headers,
|
|
303
|
+
headerPaths: data.header_paths,
|
|
304
|
+
moduleName: data.module_name,
|
|
305
|
+
includeHeaders: data.include_headers,
|
|
306
|
+
agentNotes: data.agent_notes,
|
|
307
|
+
aiInsight: data.ai_insight,
|
|
308
|
+
reviewedBy: data.reviewed_by,
|
|
309
|
+
reviewedAt: data.reviewed_at,
|
|
310
|
+
rejectionReason: data.rejection_reason,
|
|
311
|
+
source: data.source,
|
|
312
|
+
sourceFile: data.source_file,
|
|
313
|
+
sourceCandidateId: data.source_candidate_id,
|
|
314
|
+
createdBy: data.created_by,
|
|
315
|
+
createdAt: data.created_at,
|
|
316
|
+
updatedAt: data.updated_at,
|
|
317
|
+
publishedAt: data.published_at,
|
|
318
|
+
publishedBy: data.published_by,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/* ═══ 私有 ═══════════════════════════════════════════ */
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* @param {string} to
|
|
326
|
+
* @returns {{ success: boolean, error?: string }}
|
|
327
|
+
*/
|
|
328
|
+
_transition(to) {
|
|
329
|
+
if (!isValidTransition(this.lifecycle, to)) {
|
|
330
|
+
return {
|
|
331
|
+
success: false,
|
|
332
|
+
error: `Invalid lifecycle transition: ${this.lifecycle} → ${to}`,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
this.lifecycleHistory.push({
|
|
336
|
+
from: this.lifecycle,
|
|
337
|
+
to,
|
|
338
|
+
at: this._now(),
|
|
339
|
+
});
|
|
340
|
+
this.lifecycle = to;
|
|
341
|
+
this.updatedAt = this._now();
|
|
342
|
+
return { success: true };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** @returns {number} */
|
|
346
|
+
_now() {
|
|
347
|
+
return Math.floor(Date.now() / 1000);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export default KnowledgeEntry;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KnowledgeRepository — 统一知识实体仓储接口
|
|
3
|
+
*
|
|
4
|
+
* 替代 CandidateRepository + RecipeRepository。
|
|
5
|
+
* 实现类见 lib/repository/knowledge/KnowledgeRepository.impl.js
|
|
6
|
+
*/
|
|
7
|
+
export class KnowledgeRepository {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 创建 KnowledgeEntry
|
|
11
|
+
* @param {import('./KnowledgeEntry.js').KnowledgeEntry} entry
|
|
12
|
+
* @returns {Promise<import('./KnowledgeEntry.js').KnowledgeEntry>}
|
|
13
|
+
*/
|
|
14
|
+
async create(entry) {
|
|
15
|
+
throw new Error('Not implemented');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 根据 ID 获取
|
|
20
|
+
* @param {string} id
|
|
21
|
+
* @returns {Promise<import('./KnowledgeEntry.js').KnowledgeEntry|null>}
|
|
22
|
+
*/
|
|
23
|
+
async findById(id) {
|
|
24
|
+
throw new Error('Not implemented');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 分页查询
|
|
29
|
+
* @param {Object} filters - { lifecycle, kind, language, category, knowledge_type, source }
|
|
30
|
+
* @param {Object} options - { page, pageSize, orderBy, order }
|
|
31
|
+
* @returns {Promise<{ data: KnowledgeEntry[], pagination: Object }>}
|
|
32
|
+
*/
|
|
33
|
+
async findWithPagination(filters = {}, options = {}) {
|
|
34
|
+
throw new Error('Not implemented');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 根据生命周期状态查询
|
|
39
|
+
* @param {string} lifecycle
|
|
40
|
+
* @param {Object} pagination
|
|
41
|
+
* @returns {Promise<{ data: KnowledgeEntry[], pagination: Object }>}
|
|
42
|
+
*/
|
|
43
|
+
async findByLifecycle(lifecycle, pagination = {}) {
|
|
44
|
+
throw new Error('Not implemented');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 根据 kind 查询
|
|
49
|
+
* @param {string} kind - 'rule' | 'pattern' | 'fact'
|
|
50
|
+
* @param {Object} options - { page, pageSize, lifecycle }
|
|
51
|
+
* @returns {Promise<{ data: KnowledgeEntry[], pagination: Object }>}
|
|
52
|
+
*/
|
|
53
|
+
async findByKind(kind, options = {}) {
|
|
54
|
+
throw new Error('Not implemented');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 查询所有 active 的 rule 类型(Guard 消费热路径)
|
|
59
|
+
* @returns {Promise<KnowledgeEntry[]>}
|
|
60
|
+
*/
|
|
61
|
+
async findActiveRules() {
|
|
62
|
+
throw new Error('Not implemented');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 根据语言查询
|
|
67
|
+
* @param {string} language
|
|
68
|
+
* @param {Object} pagination
|
|
69
|
+
* @returns {Promise<{ data: KnowledgeEntry[], pagination: Object }>}
|
|
70
|
+
*/
|
|
71
|
+
async findByLanguage(language, pagination = {}) {
|
|
72
|
+
throw new Error('Not implemented');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 根据分类查询
|
|
77
|
+
* @param {string} category
|
|
78
|
+
* @param {Object} pagination
|
|
79
|
+
* @returns {Promise<{ data: KnowledgeEntry[], pagination: Object }>}
|
|
80
|
+
*/
|
|
81
|
+
async findByCategory(category, pagination = {}) {
|
|
82
|
+
throw new Error('Not implemented');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 搜索 (标题/内容/触发词/标签)
|
|
87
|
+
* @param {string} keyword
|
|
88
|
+
* @param {Object} pagination
|
|
89
|
+
* @returns {Promise<{ data: KnowledgeEntry[], pagination: Object }>}
|
|
90
|
+
*/
|
|
91
|
+
async search(keyword, pagination = {}) {
|
|
92
|
+
throw new Error('Not implemented');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 更新
|
|
97
|
+
* @param {string} id
|
|
98
|
+
* @param {Object} updates - wire format 的部分字段
|
|
99
|
+
* @returns {Promise<import('./KnowledgeEntry.js').KnowledgeEntry>}
|
|
100
|
+
*/
|
|
101
|
+
async update(id, updates) {
|
|
102
|
+
throw new Error('Not implemented');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 删除
|
|
107
|
+
* @param {string} id
|
|
108
|
+
* @returns {Promise<boolean>}
|
|
109
|
+
*/
|
|
110
|
+
async delete(id) {
|
|
111
|
+
throw new Error('Not implemented');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 获取统计信息
|
|
116
|
+
* @returns {Promise<Object>}
|
|
117
|
+
*/
|
|
118
|
+
async getStats() {
|
|
119
|
+
throw new Error('Not implemented');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export default KnowledgeRepository;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle — 知识实体生命周期状态机(3 状态简化版)
|
|
3
|
+
*
|
|
4
|
+
* pending — 待审核(所有新条目初始状态)
|
|
5
|
+
* active — 已发布(可被搜索/Guard/Export 消费)
|
|
6
|
+
* deprecated — 已废弃
|
|
7
|
+
*
|
|
8
|
+
* 仅开发者可执行 pending → active(发布)。
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export const Lifecycle = {
|
|
12
|
+
/** 待审核 */
|
|
13
|
+
PENDING: 'pending',
|
|
14
|
+
/** 已发布(可被搜索/Guard/Export 消费) */
|
|
15
|
+
ACTIVE: 'active',
|
|
16
|
+
/** 已弃用 */
|
|
17
|
+
DEPRECATED: 'deprecated',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// ── 向后兼容别名(旧数据中仍存在这些值) ──
|
|
21
|
+
export const LEGACY_LIFECYCLE_MAP = {
|
|
22
|
+
draft: Lifecycle.PENDING,
|
|
23
|
+
approved: Lifecycle.PENDING,
|
|
24
|
+
auto_approved: Lifecycle.PENDING,
|
|
25
|
+
rejected: Lifecycle.DEPRECATED,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** 候选阶段的所有状态 */
|
|
29
|
+
export const CANDIDATE_STATES = [
|
|
30
|
+
Lifecycle.PENDING,
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/** 合法状态转移表 */
|
|
34
|
+
const VALID_TRANSITIONS = {
|
|
35
|
+
[Lifecycle.PENDING]: [Lifecycle.ACTIVE, Lifecycle.DEPRECATED],
|
|
36
|
+
[Lifecycle.ACTIVE]: [Lifecycle.DEPRECATED],
|
|
37
|
+
[Lifecycle.DEPRECATED]: [Lifecycle.PENDING],
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 规范化生命周期值(兼容旧数据)
|
|
42
|
+
* @param {string} lifecycle
|
|
43
|
+
* @returns {string}
|
|
44
|
+
*/
|
|
45
|
+
export function normalizeLifecycle(lifecycle) {
|
|
46
|
+
if (Object.values(Lifecycle).includes(lifecycle)) return lifecycle;
|
|
47
|
+
return LEGACY_LIFECYCLE_MAP[lifecycle] || Lifecycle.PENDING;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 检查状态转移是否合法
|
|
52
|
+
* @param {string} from
|
|
53
|
+
* @param {string} to
|
|
54
|
+
* @returns {boolean}
|
|
55
|
+
*/
|
|
56
|
+
export function isValidTransition(from, to) {
|
|
57
|
+
const normalFrom = normalizeLifecycle(from);
|
|
58
|
+
const normalTo = normalizeLifecycle(to);
|
|
59
|
+
const allowed = VALID_TRANSITIONS[normalFrom];
|
|
60
|
+
return Array.isArray(allowed) && allowed.includes(normalTo);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 是否为合法的生命周期值(含旧值兼容)
|
|
65
|
+
* @param {string} lifecycle
|
|
66
|
+
* @returns {boolean}
|
|
67
|
+
*/
|
|
68
|
+
export function isValidLifecycle(lifecycle) {
|
|
69
|
+
return Object.values(Lifecycle).includes(lifecycle) || lifecycle in LEGACY_LIFECYCLE_MAP;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 是否处于候选阶段(待审核)
|
|
74
|
+
* @param {string} lifecycle
|
|
75
|
+
* @returns {boolean}
|
|
76
|
+
*/
|
|
77
|
+
export function isCandidate(lifecycle) {
|
|
78
|
+
const normalized = normalizeLifecycle(lifecycle);
|
|
79
|
+
return normalized === Lifecycle.PENDING;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* ── knowledgeType → kind 映射 ── */
|
|
83
|
+
|
|
84
|
+
const KIND_MAP = {
|
|
85
|
+
'code-standard': 'rule',
|
|
86
|
+
'code-style': 'rule',
|
|
87
|
+
'best-practice': 'rule',
|
|
88
|
+
'boundary-constraint': 'rule',
|
|
89
|
+
'code-pattern': 'pattern',
|
|
90
|
+
'architecture': 'pattern',
|
|
91
|
+
'solution': 'pattern',
|
|
92
|
+
'anti-pattern': 'pattern',
|
|
93
|
+
'code-relation': 'fact',
|
|
94
|
+
'inheritance': 'fact',
|
|
95
|
+
'call-chain': 'fact',
|
|
96
|
+
'data-flow': 'fact',
|
|
97
|
+
'module-dependency': 'fact',
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 从 knowledgeType 推导 kind
|
|
102
|
+
* @param {string} knowledgeType
|
|
103
|
+
* @returns {'rule'|'pattern'|'fact'}
|
|
104
|
+
*/
|
|
105
|
+
export function inferKind(knowledgeType) {
|
|
106
|
+
return KIND_MAP[knowledgeType] || 'pattern';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export default Lifecycle;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KnowledgeEntry 领域层统一导出
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// 实体
|
|
6
|
+
export { KnowledgeEntry } from './KnowledgeEntry.js';
|
|
7
|
+
|
|
8
|
+
// 生命周期
|
|
9
|
+
export {
|
|
10
|
+
Lifecycle,
|
|
11
|
+
isValidTransition,
|
|
12
|
+
isValidLifecycle,
|
|
13
|
+
isCandidate,
|
|
14
|
+
CANDIDATE_STATES,
|
|
15
|
+
inferKind,
|
|
16
|
+
} from './Lifecycle.js';
|
|
17
|
+
|
|
18
|
+
// 值对象
|
|
19
|
+
export { Content } from './values/Content.js';
|
|
20
|
+
export { Relations, RELATION_BUCKETS } from './values/Relations.js';
|
|
21
|
+
export { Constraints } from './values/Constraints.js';
|
|
22
|
+
export { Reasoning } from './values/Reasoning.js';
|
|
23
|
+
export { Quality } from './values/Quality.js';
|
|
24
|
+
export { Stats } from './values/Stats.js';
|
|
25
|
+
|
|
26
|
+
// Repository 接口
|
|
27
|
+
export { KnowledgeRepository } from './KnowledgeRepository.js';
|