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.
Files changed (115) hide show
  1. package/README.md +12 -12
  2. package/bin/cli.js +53 -40
  3. package/config/constitution.yaml +9 -2
  4. package/dashboard/dist/assets/{icons-CH-H9x0E.js → icons-D4IWpDIk.js} +105 -100
  5. package/dashboard/dist/assets/index-CWBNcF9z.css +1 -0
  6. package/dashboard/dist/assets/index-DHtzhbuG.js +120 -0
  7. package/dashboard/dist/index.html +3 -3
  8. package/lib/cli/AiScanService.js +35 -36
  9. package/lib/cli/KnowledgeSyncService.js +345 -0
  10. package/lib/cli/SetupService.js +8 -26
  11. package/lib/cli/UpgradeService.js +28 -0
  12. package/lib/core/gateway/GatewayActionRegistry.js +48 -58
  13. package/lib/domain/index.js +16 -11
  14. package/lib/domain/knowledge/KnowledgeEntry.js +289 -0
  15. package/lib/domain/knowledge/KnowledgeRepository.js +123 -0
  16. package/lib/domain/knowledge/Lifecycle.js +99 -0
  17. package/lib/domain/knowledge/index.js +27 -0
  18. package/lib/domain/knowledge/values/Constraints.js +128 -0
  19. package/lib/domain/knowledge/values/Content.js +69 -0
  20. package/lib/domain/knowledge/values/Quality.js +81 -0
  21. package/lib/domain/knowledge/values/Reasoning.js +70 -0
  22. package/lib/domain/knowledge/values/Relations.js +142 -0
  23. package/lib/domain/knowledge/values/Stats.js +72 -0
  24. package/lib/domain/knowledge/values/index.js +9 -0
  25. package/lib/external/ai/AiProvider.js +85 -11
  26. package/lib/external/mcp/McpServer.js +7 -5
  27. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +18 -2
  28. package/lib/external/mcp/handlers/bootstrap.js +116 -11
  29. package/lib/external/mcp/handlers/browse.js +76 -73
  30. package/lib/external/mcp/handlers/candidate.js +26 -275
  31. package/lib/external/mcp/handlers/guard.js +2 -0
  32. package/lib/external/mcp/handlers/knowledge.js +267 -0
  33. package/lib/external/mcp/handlers/structure.js +25 -23
  34. package/lib/external/mcp/handlers/system.js +10 -12
  35. package/lib/external/mcp/tools.js +134 -140
  36. package/lib/http/HttpServer.js +14 -8
  37. package/lib/http/routes/ai.js +4 -3
  38. package/lib/http/routes/extract.js +48 -4
  39. package/lib/http/routes/knowledge.js +246 -0
  40. package/lib/http/routes/search.js +12 -17
  41. package/lib/infrastructure/database/migrations/016_unified_knowledge_entries.js +395 -0
  42. package/lib/infrastructure/database/migrations/017_camelcase_knowledge_entries.js +107 -0
  43. package/lib/infrastructure/external/XcodeAutomation.js +187 -103
  44. package/lib/injection/ServiceContainer.js +69 -60
  45. package/lib/repository/knowledge/KnowledgeRepository.impl.js +338 -0
  46. package/lib/service/automation/DirectiveDetector.js +2 -3
  47. package/lib/service/automation/FileWatcher.js +59 -28
  48. package/lib/service/automation/XcodeIntegration.js +931 -156
  49. package/lib/service/automation/handlers/AlinkHandler.js +5 -4
  50. package/lib/service/automation/handlers/CreateHandler.js +53 -19
  51. package/lib/service/automation/handlers/DraftHandler.js +1 -1
  52. package/lib/service/automation/handlers/GuardHandler.js +183 -20
  53. package/lib/service/automation/handlers/SearchHandler.js +25 -22
  54. package/lib/service/candidate/SimilarityService.js +2 -2
  55. package/lib/service/chat/AnalystAgent.js +9 -0
  56. package/lib/service/chat/CandidateGuardrail.js +22 -11
  57. package/lib/service/chat/ChatAgent.js +132 -54
  58. package/lib/service/chat/ContextWindow.js +5 -5
  59. package/lib/service/chat/HandoffProtocol.js +1 -0
  60. package/lib/service/chat/ProducerAgent.js +40 -13
  61. package/lib/service/chat/ReasoningLayer.js +854 -0
  62. package/lib/service/chat/ReasoningTrace.js +329 -0
  63. package/lib/service/chat/tools.js +308 -205
  64. package/lib/service/cursor/CursorDeliveryPipeline.js +279 -0
  65. package/lib/service/cursor/KnowledgeCompressor.js +87 -0
  66. package/lib/service/cursor/RulesGenerator.js +168 -0
  67. package/lib/service/cursor/SkillsSyncer.js +268 -0
  68. package/lib/service/cursor/TokenBudget.js +58 -0
  69. package/lib/service/cursor/TopicClassifier.js +141 -0
  70. package/lib/service/guard/GuardCheckEngine.js +99 -10
  71. package/lib/service/guard/GuardService.js +57 -46
  72. package/lib/service/knowledge/ConfidenceRouter.js +159 -0
  73. package/lib/service/knowledge/KnowledgeFileWriter.js +595 -0
  74. package/lib/service/knowledge/KnowledgeService.js +802 -0
  75. package/lib/service/recipe/RecipeParser.js +3 -12
  76. package/lib/service/search/SearchEngine.js +67 -22
  77. package/lib/service/skills/SignalCollector.js +14 -9
  78. package/lib/service/skills/SkillAdvisor.js +13 -11
  79. package/lib/service/snippet/SnippetFactory.js +5 -5
  80. package/lib/service/spm/SpmService.js +15 -48
  81. package/lib/shared/RecipeReadinessChecker.js +6 -11
  82. package/package.json +1 -1
  83. package/scripts/install-cursor-skill.js +0 -6
  84. package/scripts/migrate-md-to-knowledge.mjs +364 -0
  85. package/skills/autosnippet-analysis/SKILL.md +15 -7
  86. package/skills/autosnippet-candidates/SKILL.md +8 -8
  87. package/skills/autosnippet-coldstart/SKILL.md +8 -4
  88. package/skills/autosnippet-concepts/SKILL.md +7 -6
  89. package/skills/autosnippet-create/SKILL.md +13 -13
  90. package/skills/autosnippet-intent/SKILL.md +3 -2
  91. package/skills/autosnippet-lifecycle/SKILL.md +5 -5
  92. package/skills/autosnippet-recipes/SKILL.md +18 -6
  93. package/templates/constitution.yaml +1 -1
  94. package/templates/copilot-instructions.md +6 -6
  95. package/templates/recipes-setup/README.md +3 -3
  96. package/dashboard/dist/assets/index-CqJRvYRL.js +0 -197
  97. package/dashboard/dist/assets/index-DICm9PNa.css +0 -1
  98. package/lib/cli/CandidateSyncService.js +0 -261
  99. package/lib/cli/SyncService.js +0 -356
  100. package/lib/domain/candidate/Candidate.js +0 -196
  101. package/lib/domain/candidate/CandidateRepository.js +0 -107
  102. package/lib/domain/candidate/Reasoning.js +0 -52
  103. package/lib/domain/recipe/Recipe.js +0 -421
  104. package/lib/domain/recipe/RecipeRepository.js +0 -54
  105. package/lib/domain/types/CandidateStatus.js +0 -52
  106. package/lib/http/routes/candidates.js +0 -559
  107. package/lib/http/routes/recipes.js +0 -397
  108. package/lib/repository/candidate/CandidateRepository.impl.js +0 -230
  109. package/lib/repository/recipe/RecipeRepository.impl.js +0 -498
  110. package/lib/service/candidate/CandidateAggregator.js +0 -52
  111. package/lib/service/candidate/CandidateFileWriter.js +0 -383
  112. package/lib/service/candidate/CandidateService.js +0 -1001
  113. package/lib/service/recipe/RecipeFileWriter.js +0 -514
  114. package/lib/service/recipe/RecipeService.js +0 -786
  115. package/lib/service/recipe/RecipeStatsTracker.js +0 -148
@@ -0,0 +1,329 @@
1
+ /**
2
+ * ReasoningTrace — 单次 execute() 的完整推理链记录
3
+ *
4
+ * 记录每轮 ReAct 循环的四要素:
5
+ * Thought → AI 在执行工具前的推理文本
6
+ * Action → 调用了什么工具、什么参数
7
+ * Observation → 工具返回的结构化观察
8
+ * Reflection → 周期性自我评估
9
+ *
10
+ * 设计原则:
11
+ * - 纯数据收集,不影响主循环控制流
12
+ * - 零 token 开销 — 不向 LLM 上下文注入额外内容
13
+ * - 可序列化 — toJSON() 用于审计日志和 API 返回
14
+ *
15
+ * @module ReasoningTrace
16
+ */
17
+
18
+ /**
19
+ * @typedef {Object} Round
20
+ * @property {number} iteration — 轮次编号
21
+ * @property {string|null} thought — AI 的推理文本
22
+ * @property {Array<{tool: string, params: object}>} actions — 本轮工具调用
23
+ * @property {Array<{tool: string, gotNewInfo: boolean, resultType: string, keyFacts: string[], resultSize: number}>} observations — 结构化观察
24
+ * @property {string|null} reflection — 反思内容
25
+ * @property {object|null} roundSummary — 轮次摘要
26
+ * @property {number} startTime — 轮次开始时间
27
+ * @property {number|null} endTime — 轮次结束时间
28
+ */
29
+
30
+ /**
31
+ * @typedef {Object} PlanStep
32
+ * @property {string} description — 步骤描述
33
+ * @property {'pending'|'done'|'skipped'} status — 当前状态
34
+ * @property {string[]} keywords — 从描述中提取的匹配关键词
35
+ */
36
+
37
+ /**
38
+ * @typedef {Object} Plan
39
+ * @property {string} text — 原始计划文本
40
+ * @property {Array<PlanStep>} steps — 解析出的步骤列表
41
+ * @property {number} createdAtIteration — 创建于第几轮
42
+ * @property {number} lastUpdatedAtIteration — 最近更新于第几轮
43
+ */
44
+
45
+ export class ReasoningTrace {
46
+ /** @type {Array<Round>} */
47
+ #rounds = [];
48
+ /** @type {Round|null} */
49
+ #currentRound = null;
50
+ /** @type {Plan|null} */
51
+ #plan = null;
52
+ /** @type {Array<Plan>} */
53
+ #planHistory = [];
54
+
55
+ /**
56
+ * 开始新一轮推理
57
+ * @param {number} iteration — 轮次编号
58
+ */
59
+ startRound(iteration) {
60
+ if (this.#currentRound) this.endRound(); // 安全关闭上一轮
61
+ this.#currentRound = {
62
+ iteration,
63
+ thought: null,
64
+ actions: [],
65
+ observations: [],
66
+ reflection: null,
67
+ roundSummary: null,
68
+ startTime: Date.now(),
69
+ endTime: null,
70
+ };
71
+ }
72
+
73
+ /**
74
+ * 记录 AI 的推理文本(从 aiResult.text 提取)
75
+ * @param {string} text
76
+ */
77
+ setThought(text) {
78
+ if (this.#currentRound && text) {
79
+ this.#currentRound.thought = text;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * 记录一次工具调用
85
+ * @param {string} toolName
86
+ * @param {object} params
87
+ */
88
+ addAction(toolName, params) {
89
+ this.#currentRound?.actions.push({ tool: toolName, params });
90
+ }
91
+
92
+ /**
93
+ * 记录一次工具结果的结构化观察
94
+ * @param {string} toolName
95
+ * @param {object} meta — { gotNewInfo, resultType, resultSize, keyFacts }
96
+ */
97
+ addObservation(toolName, meta) {
98
+ this.#currentRound?.observations.push({ tool: toolName, ...meta });
99
+ }
100
+
101
+ /**
102
+ * 记录反思内容
103
+ * @param {string} text
104
+ */
105
+ setReflection(text) {
106
+ if (this.#currentRound && text) {
107
+ this.#currentRound.reflection = text;
108
+ }
109
+ }
110
+
111
+ /**
112
+ * 记录轮次摘要
113
+ * @param {object} summary — { newInfoCount, totalCalls, submits, cumulativeFiles, cumulativePatterns }
114
+ */
115
+ setRoundSummary(summary) {
116
+ if (this.#currentRound) {
117
+ this.#currentRound.roundSummary = summary;
118
+ }
119
+ }
120
+
121
+ /**
122
+ * 结束当前轮次
123
+ */
124
+ endRound() {
125
+ if (this.#currentRound) {
126
+ this.#currentRound.endTime = Date.now();
127
+ this.#rounds.push(this.#currentRound);
128
+ this.#currentRound = null;
129
+ }
130
+ }
131
+
132
+ // ─── 分析方法 ──────────────────────────────────────────
133
+
134
+ /**
135
+ * 获取所有有 Thought 的轮次
136
+ * @returns {Array<{iteration: number, thought: string}>}
137
+ */
138
+ getThoughts() {
139
+ return this.#rounds
140
+ .filter(r => r.thought)
141
+ .map(r => ({ iteration: r.iteration, thought: r.thought }));
142
+ }
143
+
144
+ /**
145
+ * 获取最近 N 轮的紧凑摘要(用于 Reflection 注入)
146
+ * @param {number} [n=3] — 回看轮数
147
+ * @returns {object|null}
148
+ */
149
+ getRecentSummary(n = 3) {
150
+ const recent = this.#rounds.slice(-n);
151
+ if (recent.length === 0) return null;
152
+
153
+ const thoughts = recent
154
+ .filter(r => r.thought)
155
+ .map(r => r.thought.length > 100 ? r.thought.substring(0, 100) + '…' : r.thought);
156
+
157
+ const tools = recent.flatMap(r => r.actions.map(a => a.tool));
158
+
159
+ const newInfoCount = recent.reduce((c, r) =>
160
+ c + r.observations.filter(o => o.gotNewInfo).length, 0
161
+ );
162
+ const totalObs = recent.reduce((c, r) => c + r.observations.length, 0);
163
+
164
+ return {
165
+ roundCount: recent.length,
166
+ thoughts,
167
+ toolCalls: tools,
168
+ newInfoRatio: totalObs > 0 ? newInfoCount / totalObs : 0,
169
+ lastIteration: recent[recent.length - 1].iteration,
170
+ };
171
+ }
172
+
173
+ /**
174
+ * 统计指标
175
+ * @returns {object}
176
+ */
177
+ getStats() {
178
+ return {
179
+ totalRounds: this.#rounds.length,
180
+ thoughtCount: this.#rounds.filter(r => r.thought).length,
181
+ totalActions: this.#rounds.reduce((c, r) => c + r.actions.length, 0),
182
+ totalObservations: this.#rounds.reduce((c, r) => c + r.observations.length, 0),
183
+ reflectionCount: this.#rounds.filter(r => r.reflection).length,
184
+ totalDurationMs: this.#rounds.reduce((d, r) =>
185
+ d + ((r.endTime || Date.now()) - r.startTime), 0
186
+ ),
187
+ };
188
+ }
189
+
190
+ // ─── Planning 方法 ──────────────────────────────────────
191
+
192
+ /**
193
+ * 设置初始计划
194
+ * @param {string} planText — AI 输出的计划文本
195
+ * @param {number} iteration — 创建轮次
196
+ */
197
+ setPlan(planText, iteration) {
198
+ this.#plan = {
199
+ text: planText,
200
+ steps: this.#parsePlanSteps(planText),
201
+ createdAtIteration: iteration,
202
+ lastUpdatedAtIteration: iteration,
203
+ };
204
+ }
205
+
206
+ /**
207
+ * 更新计划(replan 后调用)
208
+ * @param {string} replanText — AI 输出的新计划文本
209
+ * @param {number} iteration — 更新轮次
210
+ */
211
+ updatePlan(replanText, iteration) {
212
+ if (!this.#plan) {
213
+ this.setPlan(replanText, iteration);
214
+ return;
215
+ }
216
+ this.#planHistory.push({ ...this.#plan, steps: this.#plan.steps.map(s => ({ ...s })) });
217
+ this.#plan.text = replanText;
218
+ this.#plan.steps = this.#parsePlanSteps(replanText);
219
+ this.#plan.lastUpdatedAtIteration = iteration;
220
+ }
221
+
222
+ /**
223
+ * 获取当前计划(只读副本)
224
+ * @returns {Plan|null}
225
+ */
226
+ getPlan() {
227
+ if (!this.#plan) return null;
228
+ return {
229
+ ...this.#plan,
230
+ steps: this.#plan.steps.map(s => ({ ...s })),
231
+ };
232
+ }
233
+
234
+ /**
235
+ * 获取计划步骤的可变引用(内部用于匹配更新状态)
236
+ * @returns {Array<PlanStep>}
237
+ */
238
+ getPlanStepsMutable() {
239
+ return this.#plan?.steps || [];
240
+ }
241
+
242
+ /**
243
+ * 获取计划历史
244
+ * @returns {Array<Plan>}
245
+ */
246
+ getPlanHistory() {
247
+ return this.#planHistory.map(p => ({ ...p, steps: p.steps.map(s => ({ ...s })) }));
248
+ }
249
+
250
+ /**
251
+ * 获取当前轮次的 actions (供 Planning 匹配使用)
252
+ * @returns {Array<{tool: string, params: object}>}
253
+ */
254
+ getCurrentRoundActions() {
255
+ return this.#currentRound?.actions || [];
256
+ }
257
+
258
+ /**
259
+ * 获取当前轮次的 iteration 编号
260
+ * @returns {number|null}
261
+ */
262
+ getCurrentIteration() {
263
+ return this.#currentRound?.iteration || null;
264
+ }
265
+
266
+ // ─── 私有: Plan 解析 ──────────────────────────────────
267
+
268
+ /**
269
+ * 从 AI 文本中解析计划步骤(编号列表提取)
270
+ * @param {string} text
271
+ * @returns {Array<PlanStep>}
272
+ * @private
273
+ */
274
+ #parsePlanSteps(text) {
275
+ if (!text) return [];
276
+ const lines = text.split('\n');
277
+ const steps = [];
278
+ for (const line of lines) {
279
+ // 匹配: 1. xxx / - xxx / * xxx / 1) xxx
280
+ const m = line.match(/^\s*(?:\d+[\.\)]\s*|[-*]\s+)(.+)/);
281
+ if (m && m[1].trim().length > 5) {
282
+ steps.push({
283
+ description: m[1].trim(),
284
+ status: 'pending',
285
+ keywords: this.#extractKeywords(m[1]),
286
+ });
287
+ }
288
+ }
289
+ return steps;
290
+ }
291
+
292
+ /**
293
+ * 从步骤描述中提取关键词(用于模糊匹配工具调用)
294
+ * @param {string} text
295
+ * @returns {string[]}
296
+ * @private
297
+ */
298
+ #extractKeywords(text) {
299
+ // 提取反引号/引号内的标识符
300
+ const quoted = [...text.matchAll(/[`"']([A-Za-z_]\w{2,})[`"']/g)].map(m => m[1]);
301
+ // 提取 CamelCase 词
302
+ const camelCase = [...text.matchAll(/\b([A-Z][a-z]+(?:[A-Z][a-z]+)+)\b/g)].map(m => m[0]);
303
+ // 提取全大写缩写 (如 API, HTTP, URL)
304
+ const acronyms = [...text.matchAll(/\b([A-Z]{2,}[a-z]\w+)\b/g)].map(m => m[0]);
305
+ return [...new Set([...quoted, ...camelCase, ...acronyms])];
306
+ }
307
+
308
+ /**
309
+ * 可序列化输出
310
+ * @returns {object}
311
+ */
312
+ toJSON() {
313
+ return {
314
+ rounds: this.#rounds.map(r => ({ ...r })),
315
+ stats: this.getStats(),
316
+ ...(this.#plan ? {
317
+ plan: {
318
+ text: this.#plan.text,
319
+ steps: this.#plan.steps.map(s => ({ ...s })),
320
+ createdAtIteration: this.#plan.createdAtIteration,
321
+ lastUpdatedAtIteration: this.#plan.lastUpdatedAtIteration,
322
+ },
323
+ planHistory: this.#planHistory.length,
324
+ } : {}),
325
+ };
326
+ }
327
+ }
328
+
329
+ export default ReasoningTrace;