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.
Files changed (97) hide show
  1. package/README.md +4 -4
  2. package/bin/cli.js +5 -33
  3. package/config/constitution.yaml +9 -2
  4. package/dashboard/dist/assets/{icons-CH-H9x0E.js → icons-BkT3XrKf.js} +105 -100
  5. package/dashboard/dist/assets/index-BsB7DzW4.css +1 -0
  6. package/dashboard/dist/assets/index-DdmQMrJJ.js +155 -0
  7. package/dashboard/dist/index.html +3 -3
  8. package/lib/cli/AiScanService.js +13 -11
  9. package/lib/cli/KnowledgeSyncService.js +343 -0
  10. package/lib/cli/SetupService.js +8 -26
  11. package/lib/core/gateway/GatewayActionRegistry.js +48 -58
  12. package/lib/domain/index.js +16 -11
  13. package/lib/domain/knowledge/KnowledgeEntry.js +351 -0
  14. package/lib/domain/knowledge/KnowledgeRepository.js +123 -0
  15. package/lib/domain/knowledge/Lifecycle.js +109 -0
  16. package/lib/domain/knowledge/index.js +27 -0
  17. package/lib/domain/knowledge/values/Constraints.js +125 -0
  18. package/lib/domain/knowledge/values/Content.js +86 -0
  19. package/lib/domain/knowledge/values/Quality.js +93 -0
  20. package/lib/domain/knowledge/values/Reasoning.js +69 -0
  21. package/lib/domain/knowledge/values/Relations.js +168 -0
  22. package/lib/domain/knowledge/values/Stats.js +87 -0
  23. package/lib/domain/knowledge/values/index.js +9 -0
  24. package/lib/external/ai/AiProvider.js +48 -0
  25. package/lib/external/mcp/McpServer.js +7 -5
  26. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +2 -2
  27. package/lib/external/mcp/handlers/bootstrap.js +116 -11
  28. package/lib/external/mcp/handlers/browse.js +77 -73
  29. package/lib/external/mcp/handlers/candidate.js +29 -276
  30. package/lib/external/mcp/handlers/guard.js +2 -0
  31. package/lib/external/mcp/handlers/knowledge.js +205 -0
  32. package/lib/external/mcp/handlers/structure.js +25 -23
  33. package/lib/external/mcp/handlers/system.js +10 -12
  34. package/lib/external/mcp/tools.js +125 -138
  35. package/lib/http/HttpServer.js +4 -8
  36. package/lib/http/routes/extract.js +48 -4
  37. package/lib/http/routes/knowledge.js +246 -0
  38. package/lib/http/routes/search.js +12 -17
  39. package/lib/infrastructure/database/migrations/016_unified_knowledge_entries.js +395 -0
  40. package/lib/infrastructure/external/XcodeAutomation.js +187 -103
  41. package/lib/injection/ServiceContainer.js +49 -60
  42. package/lib/repository/knowledge/KnowledgeRepository.impl.js +373 -0
  43. package/lib/service/automation/DirectiveDetector.js +2 -3
  44. package/lib/service/automation/FileWatcher.js +67 -28
  45. package/lib/service/automation/XcodeIntegration.js +931 -156
  46. package/lib/service/automation/handlers/AlinkHandler.js +6 -4
  47. package/lib/service/automation/handlers/CreateHandler.js +53 -18
  48. package/lib/service/automation/handlers/GuardHandler.js +183 -20
  49. package/lib/service/automation/handlers/SearchHandler.js +35 -17
  50. package/lib/service/chat/CandidateGuardrail.js +1 -1
  51. package/lib/service/chat/ChatAgent.js +46 -45
  52. package/lib/service/chat/ContextWindow.js +5 -5
  53. package/lib/service/chat/ProducerAgent.js +7 -7
  54. package/lib/service/chat/tools.js +130 -123
  55. package/lib/service/guard/GuardCheckEngine.js +114 -10
  56. package/lib/service/guard/GuardService.js +59 -48
  57. package/lib/service/knowledge/ConfidenceRouter.js +159 -0
  58. package/lib/service/knowledge/KnowledgeFileWriter.js +602 -0
  59. package/lib/service/knowledge/KnowledgeService.js +725 -0
  60. package/lib/service/search/SearchEngine.js +92 -19
  61. package/lib/service/skills/SignalCollector.js +12 -7
  62. package/lib/service/skills/SkillAdvisor.js +13 -11
  63. package/lib/service/snippet/SnippetFactory.js +5 -5
  64. package/package.json +1 -1
  65. package/scripts/install-cursor-skill.js +0 -6
  66. package/scripts/migrate-md-to-knowledge.mjs +364 -0
  67. package/skills/autosnippet-analysis/SKILL.md +15 -7
  68. package/skills/autosnippet-candidates/SKILL.md +6 -6
  69. package/skills/autosnippet-coldstart/SKILL.md +7 -3
  70. package/skills/autosnippet-concepts/SKILL.md +7 -6
  71. package/skills/autosnippet-create/SKILL.md +13 -13
  72. package/skills/autosnippet-intent/SKILL.md +3 -2
  73. package/skills/autosnippet-lifecycle/SKILL.md +5 -5
  74. package/skills/autosnippet-recipes/SKILL.md +16 -4
  75. package/templates/constitution.yaml +1 -1
  76. package/templates/copilot-instructions.md +6 -6
  77. package/templates/recipes-setup/README.md +3 -3
  78. package/dashboard/dist/assets/index-CqJRvYRL.js +0 -197
  79. package/dashboard/dist/assets/index-DICm9PNa.css +0 -1
  80. package/lib/cli/CandidateSyncService.js +0 -261
  81. package/lib/cli/SyncService.js +0 -356
  82. package/lib/domain/candidate/Candidate.js +0 -196
  83. package/lib/domain/candidate/CandidateRepository.js +0 -107
  84. package/lib/domain/candidate/Reasoning.js +0 -52
  85. package/lib/domain/recipe/Recipe.js +0 -421
  86. package/lib/domain/recipe/RecipeRepository.js +0 -54
  87. package/lib/domain/types/CandidateStatus.js +0 -52
  88. package/lib/http/routes/candidates.js +0 -559
  89. package/lib/http/routes/recipes.js +0 -397
  90. package/lib/repository/candidate/CandidateRepository.impl.js +0 -230
  91. package/lib/repository/recipe/RecipeRepository.impl.js +0 -498
  92. package/lib/service/candidate/CandidateAggregator.js +0 -52
  93. package/lib/service/candidate/CandidateFileWriter.js +0 -383
  94. package/lib/service/candidate/CandidateService.js +0 -1001
  95. package/lib/service/recipe/RecipeFileWriter.js +0 -514
  96. package/lib/service/recipe/RecipeService.js +0 -786
  97. package/lib/service/recipe/RecipeStatsTracker.js +0 -148
@@ -3,18 +3,23 @@
3
3
  * 导出所有实体、值对象和仓储接口
4
4
  */
5
5
 
6
- // Candidate 相关
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
- Recipe, RecipeStatus, KnowledgeType, Complexity,
15
- RelationType, Kind, inferKind,
16
- } from './recipe/Recipe.js';
17
- export { default as RecipeRepository } from './recipe/RecipeRepository.js';
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';