autosnippet 3.3.6 → 3.3.7

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 (107) hide show
  1. package/dashboard/dist/assets/icons-FHns2ypa.js +1 -0
  2. package/dashboard/dist/assets/index-BRJv5Y3r.js +135 -0
  3. package/dashboard/dist/assets/index-DzoB7kxK.css +1 -0
  4. package/dashboard/dist/index.html +3 -3
  5. package/dist/bin/cli.js +1 -0
  6. package/dist/lib/agent/AgentRuntime.d.ts +2 -2
  7. package/dist/lib/agent/AgentRuntime.js +26 -18
  8. package/dist/lib/agent/domain/ChatAgentTasks.js +4 -0
  9. package/dist/lib/agent/forced-summary.js +7 -2
  10. package/dist/lib/cli/AiScanService.js +4 -4
  11. package/dist/lib/core/discovery/ConfigWatcher.d.ts +64 -0
  12. package/dist/lib/core/discovery/ConfigWatcher.js +336 -0
  13. package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +30 -0
  14. package/dist/lib/core/discovery/CustomConfigDiscoverer.js +1305 -0
  15. package/dist/lib/core/discovery/DiscovererPreference.d.ts +44 -0
  16. package/dist/lib/core/discovery/DiscovererPreference.js +141 -0
  17. package/dist/lib/core/discovery/DiscovererRegistry.d.ts +10 -1
  18. package/dist/lib/core/discovery/DiscovererRegistry.js +42 -2
  19. package/dist/lib/core/discovery/ProjectDiscoverer.d.ts +19 -0
  20. package/dist/lib/core/discovery/index.d.ts +2 -0
  21. package/dist/lib/core/discovery/index.js +4 -0
  22. package/dist/lib/core/discovery/parsers/CMakeParser.d.ts +32 -0
  23. package/dist/lib/core/discovery/parsers/CMakeParser.js +148 -0
  24. package/dist/lib/core/discovery/parsers/GradleDslParser.d.ts +43 -0
  25. package/dist/lib/core/discovery/parsers/GradleDslParser.js +171 -0
  26. package/dist/lib/core/discovery/parsers/JsonConfigParser.d.ts +45 -0
  27. package/dist/lib/core/discovery/parsers/JsonConfigParser.js +122 -0
  28. package/dist/lib/core/discovery/parsers/RubyDslParser.d.ts +49 -0
  29. package/dist/lib/core/discovery/parsers/RubyDslParser.js +282 -0
  30. package/dist/lib/core/discovery/parsers/StarlarkParser.d.ts +33 -0
  31. package/dist/lib/core/discovery/parsers/StarlarkParser.js +229 -0
  32. package/dist/lib/core/discovery/parsers/YamlConfigParser.d.ts +37 -0
  33. package/dist/lib/core/discovery/parsers/YamlConfigParser.js +212 -0
  34. package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +7 -1
  35. package/dist/lib/domain/knowledge/KnowledgeEntry.js +17 -3
  36. package/dist/lib/external/ai/AiProvider.d.ts +12 -0
  37. package/dist/lib/external/ai/AiProvider.js +24 -0
  38. package/dist/lib/external/ai/AiProviderManager.d.ts +101 -0
  39. package/dist/lib/external/ai/AiProviderManager.js +193 -0
  40. package/dist/lib/external/ai/providers/ClaudeProvider.js +11 -0
  41. package/dist/lib/external/ai/providers/GoogleGeminiProvider.js +18 -0
  42. package/dist/lib/external/ai/providers/MockProvider.d.ts +21 -3
  43. package/dist/lib/external/ai/providers/MockProvider.js +290 -14
  44. package/dist/lib/external/ai/providers/OpenAiProvider.js +16 -0
  45. package/dist/lib/external/lark/LarkTransport.d.ts +5 -1
  46. package/dist/lib/external/lark/LarkTransport.js +10 -2
  47. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.d.ts +20 -0
  48. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.js +432 -0
  49. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +16 -8
  50. package/dist/lib/external/mcp/handlers/bootstrap/refine.js +8 -0
  51. package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +9 -0
  52. package/dist/lib/external/mcp/handlers/bootstrap-external.js +2 -0
  53. package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
  54. package/dist/lib/external/mcp/handlers/consolidated.js +2 -1
  55. package/dist/lib/external/mcp/handlers/dimension-complete-external.js +2 -1
  56. package/dist/lib/external/mcp/handlers/evolve-external.js +5 -2
  57. package/dist/lib/external/mcp/handlers/knowledge.js +5 -4
  58. package/dist/lib/http/routes/ai.js +111 -30
  59. package/dist/lib/http/routes/candidates.js +11 -4
  60. package/dist/lib/http/routes/commands.js +10 -1
  61. package/dist/lib/http/routes/health.js +11 -0
  62. package/dist/lib/http/routes/modules.js +27 -0
  63. package/dist/lib/http/routes/recipes.js +7 -0
  64. package/dist/lib/http/utils/routeHelpers.js +2 -1
  65. package/dist/lib/injection/ServiceContainer.d.ts +6 -5
  66. package/dist/lib/injection/ServiceContainer.js +11 -27
  67. package/dist/lib/injection/ServiceMap.d.ts +2 -0
  68. package/dist/lib/injection/modules/AiModule.d.ts +6 -9
  69. package/dist/lib/injection/modules/AiModule.js +82 -39
  70. package/dist/lib/injection/modules/PanoramaModule.js +1 -1
  71. package/dist/lib/service/cleanup/CleanupService.d.ts +54 -7
  72. package/dist/lib/service/cleanup/CleanupService.js +284 -37
  73. package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +6 -0
  74. package/dist/lib/service/knowledge/CodeEntityGraph.js +16 -0
  75. package/dist/lib/service/knowledge/KnowledgeService.js +23 -10
  76. package/dist/lib/service/module/ModuleService.js +10 -19
  77. package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +10 -1
  78. package/dist/lib/service/panorama/CouplingAnalyzer.js +44 -2
  79. package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +1 -1
  80. package/dist/lib/service/panorama/DimensionAnalyzer.js +31 -17
  81. package/dist/lib/service/panorama/LayerInferrer.d.ts +16 -1
  82. package/dist/lib/service/panorama/LayerInferrer.js +118 -1
  83. package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +9 -0
  84. package/dist/lib/service/panorama/ModuleDiscoverer.js +58 -2
  85. package/dist/lib/service/panorama/PanoramaAggregator.d.ts +6 -2
  86. package/dist/lib/service/panorama/PanoramaAggregator.js +84 -6
  87. package/dist/lib/service/panorama/PanoramaScanner.js +28 -0
  88. package/dist/lib/service/panorama/PanoramaService.js +10 -5
  89. package/dist/lib/service/panorama/PanoramaTypes.d.ts +38 -0
  90. package/dist/lib/service/panorama/RoleRefiner.d.ts +2 -0
  91. package/dist/lib/service/panorama/RoleRefiner.js +41 -0
  92. package/dist/lib/service/panorama/TechStackProfiler.d.ts +13 -0
  93. package/dist/lib/service/panorama/TechStackProfiler.js +191 -0
  94. package/dist/lib/service/skills/SignalCollector.d.ts +1 -0
  95. package/dist/lib/service/skills/SignalCollector.js +6 -5
  96. package/dist/lib/service/vector/ContextualEnricher.d.ts +1 -0
  97. package/dist/lib/service/vector/ContextualEnricher.js +4 -0
  98. package/dist/lib/shared/LanguageService.js +3 -0
  99. package/dist/lib/shared/developer-identity.d.ts +18 -0
  100. package/dist/lib/shared/developer-identity.js +62 -0
  101. package/dist/lib/shared/schemas/http-requests.d.ts +8 -17
  102. package/dist/lib/shared/schemas/http-requests.js +9 -6
  103. package/dist/lib/types/knowledge-wire.d.ts +1 -0
  104. package/package.json +1 -1
  105. package/dashboard/dist/assets/icons-D1aVZYFW.js +0 -1
  106. package/dashboard/dist/assets/index-CxHOu8Hd.css +0 -1
  107. package/dashboard/dist/assets/index-DDdAOpYT.js +0 -128
@@ -1,47 +1,323 @@
1
1
  /**
2
- * MockProvider - 测试用 AI 提供商
3
- * 返回固定/随机数据,不发网络请求
2
+ * MockProvider Smart Mock AI 提供商
3
+ *
4
+ * 不发网络请求,但根据 prompt 内容智能匹配场景,返回符合格式的仿真响应。
5
+ * 用于让用户在没有 API Key 的情况下体验 AutoSnippet 完整工作流。
6
+ *
7
+ * 智能匹配场景:
8
+ * 1. probe / ping → "pong"
9
+ * 2. 重复度检测 (DUPLICATE/SIMILAR/UNIQUE) → "UNIQUE"
10
+ * 3. 对话压缩总结 → 从消息中提取关键词
11
+ * 4. 代码上下文化 (<chunk>) → 从代码提取函数/类名
12
+ * 5. 候选润色 (JSON 9字段) → 原样回传输入字段
13
+ * 6. 维度摘要 (dimensionDigest) → 模板化 JSON
14
+ * 7. 风格检查建议 → 空数组
15
+ * 8. Agent 路由分类 → functionCall classify_intent
16
+ * 9. 通用 fallback → 语义化占位文本
17
+ *
18
+ * 模拟延迟: 50-200ms 随机延迟,营造 "AI 思考" 体验
4
19
  */
5
- import { AiProvider } from '../AiProvider.js';
20
+ import { AiProvider, } from '../AiProvider.js';
21
+ // ── 工具函数 ──────────────────────────────────────────────
22
+ /** 模拟延迟 (50-200ms) */
23
+ function mockDelay() {
24
+ const ms = 50 + Math.floor(Math.random() * 150);
25
+ return new Promise((resolve) => setTimeout(resolve, ms));
26
+ }
27
+ /** 模拟 token 用量 */
28
+ function mockUsage(prompt, response) {
29
+ return {
30
+ inputTokens: Math.ceil(prompt.length / 4),
31
+ outputTokens: Math.ceil(response.length / 4),
32
+ totalTokens: Math.ceil(prompt.length / 4) + Math.ceil(response.length / 4),
33
+ };
34
+ }
35
+ /** 从代码片段中提取函数/类/结构名称 */
36
+ function extractCodeSymbols(code) {
37
+ const symbols = [];
38
+ // Swift/TS class/struct/protocol/enum
39
+ for (const m of code.matchAll(/(?:class|struct|protocol|enum|interface|type)\s+(\w+)/g)) {
40
+ symbols.push(m[1]);
41
+ }
42
+ // func/function
43
+ for (const m of code.matchAll(/(?:func|function)\s+(\w+)/g)) {
44
+ symbols.push(m[1]);
45
+ }
46
+ // property patterns
47
+ for (const m of code.matchAll(/(?:let|var|const)\s+(\w+)/g)) {
48
+ if (m[1].length > 3) {
49
+ symbols.push(m[1]);
50
+ }
51
+ }
52
+ return [...new Set(symbols)].slice(0, 8);
53
+ }
54
+ /** 从 prompt 中尝试提取 JSON 输入(用于润色回传) */
55
+ function extractJsonFromPrompt(prompt) {
56
+ try {
57
+ const match = prompt.match(/\{[\s\S]*?"description"[\s\S]*?\}/);
58
+ if (match) {
59
+ return JSON.parse(match[0]);
60
+ }
61
+ }
62
+ catch {
63
+ /* parse failed */
64
+ }
65
+ return null;
66
+ }
67
+ // ── MockProvider ─────────────────────────────────────────
6
68
  export class MockProvider extends AiProvider {
7
69
  callLog;
8
70
  responses;
9
71
  constructor(config = {}) {
10
72
  super(config);
11
73
  this.name = 'mock';
12
- this.model = 'mock-model';
74
+ this.model = 'mock-smart';
13
75
  this.responses = config.responses || {};
14
76
  this.callLog = [];
15
77
  }
78
+ // ── 核心: chat() 智能路由 ──────────────────────────────
16
79
  async chat(prompt, context = {}) {
17
- this.callLog.push({ method: 'chat', prompt, context });
80
+ this.callLog.push({ method: 'chat', prompt: prompt.slice(0, 200), context });
81
+ await mockDelay();
82
+ // 0. 用户注入的固定响应(单元测试用)
18
83
  if (this.responses.chat) {
19
84
  return this.responses.chat;
20
85
  }
21
- return `Mock response for: ${prompt.slice(0, 80)}`;
86
+ const p = prompt.toLowerCase();
87
+ // 1. Probe / ping
88
+ if (p === 'ping' || p.includes('ping')) {
89
+ return 'pong';
90
+ }
91
+ // 2. 重复度检测 — "请回答: DUPLICATE / SIMILAR / UNIQUE"
92
+ if (p.includes('duplicate') && p.includes('similar') && p.includes('unique')) {
93
+ return 'UNIQUE';
94
+ }
95
+ // 3. 对话压缩总结 — "请用 2-3 句话总结"
96
+ if (p.includes('总结以下对话') || p.includes('summarize the following')) {
97
+ const lines = prompt
98
+ .split('\n')
99
+ .filter((l) => l.startsWith('[user]') || l.startsWith('[assistant]'));
100
+ const topics = lines
101
+ .slice(0, 3)
102
+ .map((l) => l.slice(0, 60))
103
+ .join(';');
104
+ return `[Mock 摘要] 对话涉及: ${topics || '项目开发相关讨论'}。用户和助手讨论了代码实现和架构设计。`;
105
+ }
106
+ // 4. 代码上下文化 — <chunk>...</chunk>
107
+ if (p.includes('<chunk>')) {
108
+ const chunkMatch = prompt.match(/<chunk>([\s\S]*?)<\/chunk>/);
109
+ if (chunkMatch) {
110
+ const symbols = extractCodeSymbols(chunkMatch[1]);
111
+ if (symbols.length > 0) {
112
+ return `This chunk defines ${symbols.slice(0, 3).join(', ')} which handles ${symbols.length > 3 ? symbols.slice(3, 5).join(' and ') : 'core logic'} in the module.`;
113
+ }
114
+ return 'This chunk contains utility code for the module.';
115
+ }
116
+ }
117
+ // 5. 候选润色 — "知识库条目润色助手" + JSON 输出
118
+ if (p.includes('知识库条目润色') || p.includes('润色助手')) {
119
+ const existing = extractJsonFromPrompt(prompt);
120
+ if (existing) {
121
+ return JSON.stringify(existing);
122
+ }
123
+ return JSON.stringify({
124
+ description: '[Mock] 保持原内容不变',
125
+ pattern: '',
126
+ markdown: '',
127
+ rationale: '',
128
+ tags: [],
129
+ confidence: 0.8,
130
+ aiInsight: null,
131
+ agentNotes: null,
132
+ relations: {},
133
+ });
134
+ }
135
+ // 6. 维度摘要 — "dimensionDigest"
136
+ if (p.includes('dimensiondigest') || p.includes('dimension digest')) {
137
+ const dimMatch = prompt.match(/维度[::]\s*["']?(\w[\w-]+)/i) ||
138
+ prompt.match(/dimension[::]\s*["']?(\w[\w-]+)/i);
139
+ const dimId = dimMatch?.[1] || 'unknown';
140
+ const countMatch = prompt.match(/提交了\s*(\d+)\s*个候选/);
141
+ const count = countMatch ? parseInt(countMatch[1], 10) : 3;
142
+ return `\`\`\`json
143
+ ${JSON.stringify({
144
+ dimensionDigest: {
145
+ summary: `[Mock] ${dimId} 维度分析完成,基于项目代码结构生成了 ${count} 个候选知识。`,
146
+ candidateCount: count,
147
+ keyFindings: ['项目采用模块化架构设计', '发现多个核心设计模式', '代码风格整体一致'],
148
+ crossRefs: {},
149
+ gaps: ['部分模块缺少充分的文档注释'],
150
+ remainingTasks: [],
151
+ },
152
+ }, null, 2)}
153
+ \`\`\``;
154
+ }
155
+ // 7. 风格检查建议 — "violation" + "suggestion"
156
+ if (p.includes('violation') && p.includes('suggestion')) {
157
+ return '[]';
158
+ }
159
+ // 8. 分析报告 — "Markdown 格式" + "代码分析报告"
160
+ if (p.includes('代码分析报告') || p.includes('分析报告')) {
161
+ const symbols = extractCodeSymbols(prompt);
162
+ return `## Mock 代码分析报告
163
+
164
+ ### 核心发现
165
+
166
+ 1. **模块结构**: 项目采用分层架构,${symbols.length > 0 ? `核心类型包括 ${symbols.slice(0, 3).join('、')}` : '各模块职责清晰'}
167
+ 2. **设计模式**: 广泛使用协议/接口抽象和依赖注入
168
+ 3. **代码质量**: 类型安全处理规范,错误处理完善
169
+
170
+ ### 文件分析
171
+
172
+ 分析的文件展现了良好的代码组织,模块间通过明确的接口通信。
173
+
174
+ > ⚠️ 此报告由 Mock AI 生成,仅包含模板化分析结果。`;
175
+ }
176
+ // 9. 通用 fallback — 语义化占位
177
+ const symbols = extractCodeSymbols(prompt);
178
+ const topic = symbols.length > 0
179
+ ? `关于 ${symbols.slice(0, 3).join('、')} 的分析`
180
+ : `对 ${prompt.slice(0, 40).replace(/\n/g, ' ')} 的回复`;
181
+ return `[Mock AI] ${topic}。此响应由 Mock 模式生成,非真实 AI 分析结果。`;
182
+ }
183
+ // ── chatWithTools() — 智能函数调用模拟 ─────────────────
184
+ async chatWithTools(prompt, opts = {}) {
185
+ this.callLog.push({
186
+ method: 'chatWithTools',
187
+ prompt: prompt.slice(0, 200),
188
+ toolChoice: opts.toolChoice,
189
+ });
190
+ await mockDelay();
191
+ const schemas = (opts.toolSchemas || []);
192
+ const schemaNames = schemas.map((s) => s.name);
193
+ // toolChoice='none' → 纯文本回复(维度摘要、最终总结等)
194
+ if (opts.toolChoice === 'none') {
195
+ const text = await this.chat(prompt, {
196
+ systemPrompt: opts.systemPrompt,
197
+ temperature: opts.temperature,
198
+ maxTokens: opts.maxTokens,
199
+ });
200
+ return { text, functionCalls: null, usage: mockUsage(prompt, text) };
201
+ }
202
+ // Agent 路由分类 — classify_intent tool
203
+ if (schemaNames.includes('classify_intent')) {
204
+ const response = JSON.stringify({ type: 'general', confidence: 0.9 });
205
+ return {
206
+ text: null,
207
+ functionCalls: [
208
+ {
209
+ id: `mock-fc-${Date.now()}`,
210
+ name: 'classify_intent',
211
+ args: { type: 'general', confidence: 0.9 },
212
+ },
213
+ ],
214
+ usage: mockUsage(prompt, response),
215
+ };
216
+ }
217
+ // 有 tool schemas → 返回文本(让 AgentRuntime 的文本解析处理)
218
+ // Mock 不模拟复杂的多步工具调用链 — bootstrap 走 lightweight pipeline
219
+ if (schemas.length > 0) {
220
+ const text = `[Mock] 我已完成对项目代码的分析。基于代码结构,发现了几个关键的设计模式和架构约定。
221
+
222
+ 以下是主要发现:
223
+ 1. 项目采用模块化分层架构
224
+ 2. 核心模块使用依赖注入模式
225
+ 3. 错误处理遵循统一的类型安全约定
226
+
227
+ > 此分析由 Mock AI 生成,结果基于模板。切换到真实 AI Provider 可获得深度项目分析。`;
228
+ return { text, functionCalls: null, usage: mockUsage(prompt, text) };
229
+ }
230
+ // 无 tools → 纯文本
231
+ const text = await this.chat(prompt, {
232
+ systemPrompt: opts.systemPrompt,
233
+ temperature: opts.temperature,
234
+ maxTokens: opts.maxTokens,
235
+ });
236
+ return { text, functionCalls: null, usage: mockUsage(prompt, text) };
22
237
  }
238
+ // ── chatWithStructuredOutput() — 结构化 JSON 模拟 ──────
239
+ async chatWithStructuredOutput(prompt, opts = {}) {
240
+ this.callLog.push({ method: 'chatWithStructuredOutput', prompt: prompt.slice(0, 200) });
241
+ await mockDelay();
242
+ const p = prompt.toLowerCase();
243
+ // 候选润色 → 尝试回传 prompt 中的 JSON
244
+ if (p.includes('润色') || p.includes('refine')) {
245
+ const existing = extractJsonFromPrompt(prompt);
246
+ if (existing) {
247
+ return existing;
248
+ }
249
+ return {
250
+ description: '[Mock] 保持原内容',
251
+ pattern: '',
252
+ markdown: '',
253
+ rationale: '',
254
+ tags: [],
255
+ confidence: 0.8,
256
+ aiInsight: null,
257
+ agentNotes: null,
258
+ relations: {},
259
+ };
260
+ }
261
+ // 风格检查 → 空数组
262
+ if (opts.openChar === '[' || p.includes('violation')) {
263
+ return [];
264
+ }
265
+ // 通用 → 尝试从 prompt 中提取已有 JSON,否则返回空对象
266
+ const existing = extractJsonFromPrompt(prompt);
267
+ return existing || {};
268
+ }
269
+ // ── summarize() — 代码摘要 ─────────────────────────────
23
270
  async summarize(code) {
24
271
  this.callLog.push({ method: 'summarize', code: code?.slice(0, 80) });
272
+ await mockDelay();
25
273
  if (this.responses.summarize) {
26
274
  return this.responses.summarize;
27
275
  }
276
+ const symbols = extractCodeSymbols(code || '');
277
+ const lang = code?.includes('func ')
278
+ ? 'swift'
279
+ : code?.includes('function ')
280
+ ? 'typescript'
281
+ : code?.includes('def ')
282
+ ? 'python'
283
+ : 'unknown';
28
284
  return {
29
- title: 'Mock Summary',
30
- description: `Summary of ${code?.length || 0} chars`,
31
- language: 'unknown',
32
- patterns: [],
33
- keyAPIs: [],
285
+ title: symbols.length > 0 ? `${symbols[0]} 模块` : 'Mock Summary',
286
+ description: symbols.length > 0
287
+ ? `定义了 ${symbols.slice(0, 3).join('')} 等 ${symbols.length} 个核心类型`
288
+ : `Summary of ${code?.length || 0} chars`,
289
+ language: lang,
290
+ patterns: symbols.slice(0, 3).map((s) => `${s} pattern`),
291
+ keyAPIs: symbols.slice(0, 4),
34
292
  };
35
293
  }
294
+ // ── embed() — 确定性伪向量 ─────────────────────────────
36
295
  async embed(text) {
37
296
  this.callLog.push({ method: 'embed', text: Array.isArray(text) ? text.length : 1 });
297
+ // 使用基于内容的确定性哈希生成向量(相似文本产生相似向量)
38
298
  const dim = 768;
39
- const makeVector = () => Array.from({ length: dim }, () => Math.random() * 2 - 1);
299
+ const makeVector = (input) => {
300
+ let hash = 0;
301
+ for (let i = 0; i < input.length; i++) {
302
+ hash = ((hash << 5) - hash + input.charCodeAt(i)) | 0;
303
+ }
304
+ return Array.from({ length: dim }, (_, i) => {
305
+ // 基于 hash + 位置的伪随机,范围 [-1, 1]
306
+ const x = Math.sin(hash * 0.001 + i * 0.7127) * 43758.5453;
307
+ return (x - Math.floor(x)) * 2 - 1;
308
+ });
309
+ };
40
310
  if (Array.isArray(text)) {
41
- return text.map(() => makeVector());
311
+ return text.map((t) => makeVector(t));
42
312
  }
43
- return makeVector();
313
+ return makeVector(text);
314
+ }
315
+ // ── probe() — 连接检测 ────────────────────────────────
316
+ async probe() {
317
+ this.callLog.push({ method: 'probe' });
318
+ return true;
44
319
  }
320
+ // ── 辅助方法 ──────────────────────────────────────────
45
321
  /** 获取调用日志(测试断言用) */
46
322
  getCalls() {
47
323
  return this.callLog;
@@ -42,6 +42,14 @@ export class OpenAiProvider extends AiProvider {
42
42
  max_tokens: maxTokens,
43
43
  };
44
44
  const data = await this._post(`${this.baseUrl}/chat/completions`, body);
45
+ // 提取 token 用量
46
+ if (data?.usage) {
47
+ this._emitTokenUsage({
48
+ inputTokens: data.usage.prompt_tokens || 0,
49
+ outputTokens: data.usage.completion_tokens || 0,
50
+ totalTokens: data.usage.total_tokens || 0,
51
+ });
52
+ }
45
53
  return data?.choices?.[0]?.message?.content || '';
46
54
  });
47
55
  }
@@ -197,6 +205,14 @@ export class OpenAiProvider extends AiProvider {
197
205
  response_format: { type: 'json_object' },
198
206
  };
199
207
  const data = await this._post(`${this.baseUrl}/chat/completions`, body);
208
+ // 提取 token 用量
209
+ if (data?.usage) {
210
+ this._emitTokenUsage({
211
+ inputTokens: data.usage.prompt_tokens || 0,
212
+ outputTokens: data.usage.completion_tokens || 0,
213
+ totalTokens: data.usage.total_tokens || 0,
214
+ });
215
+ }
200
216
  const text = data?.choices?.[0]?.message?.content || '';
201
217
  if (!text) {
202
218
  return null;
@@ -21,6 +21,10 @@ import type { AgentRuntime } from '#agent/AgentRuntime.js';
21
21
  interface AgentFactory {
22
22
  createLark(opts: RuntimeOverrides): AgentRuntime;
23
23
  createRemoteExec(opts: RuntimeOverrides): AgentRuntime;
24
+ getAiProviderInfo(): {
25
+ name: string;
26
+ model?: string;
27
+ };
24
28
  }
25
29
  interface RuntimeOverrides {
26
30
  lang?: string;
@@ -34,7 +38,7 @@ interface ProgressEvent {
34
38
  interface LarkTransportConfig {
35
39
  agentFactory: AgentFactory;
36
40
  replyFn: (messageId: string, text: string) => Promise<void>;
37
- sendFn: (text: string) => Promise<void | boolean>;
41
+ sendFn: (text: string) => Promise<undefined | boolean>;
38
42
  sendImageFn?: (caption: string) => Promise<{
39
43
  success: boolean;
40
44
  message: string;
@@ -276,6 +276,10 @@ export class LarkTransport {
276
276
  }
277
277
  /** 远程命令执行 — 使用 remote-exec preset(含 SafetyPolicy 命令白名单) */
278
278
  async #handleRemoteExec(command, messageId, chatId, senderId, senderName) {
279
+ if (this.#agentFactory.getAiProviderInfo().name === 'mock') {
280
+ await this.#reply(messageId, '⚠️ AI 服务未配置,当前为 Mock 模式。请先配置 API Key。');
281
+ return;
282
+ }
279
283
  await this.#reply(messageId, `⚡ 正在执行: \`${command.slice(0, 60)}\`...`);
280
284
  try {
281
285
  const history = this.#getHistory(chatId);
@@ -316,6 +320,10 @@ export class LarkTransport {
316
320
  }
317
321
  /** Bot Agent 知识任务 — 服务端 AgentRuntime 直接处理 */
318
322
  async #handleBotAgent(text, messageId, chatId, senderId, senderName) {
323
+ if (this.#agentFactory.getAiProviderInfo().name === 'mock') {
324
+ await this.#reply(messageId, '⚠️ AI 服务未配置,当前为 Mock 模式。请先配置 API Key。');
325
+ return;
326
+ }
319
327
  // 进度提示
320
328
  await this.#reply(messageId, '🤔 正在思考...');
321
329
  try {
@@ -453,8 +461,8 @@ export class LarkTransport {
453
461
  const history = this.#conversationHistory.get(chatId);
454
462
  history.push({ role, content });
455
463
  // 限制内存历史长度
456
- if (history.length > _a.MAX_HISTORY * 2) {
457
- history.splice(0, history.length - _a.MAX_HISTORY * 2);
464
+ if (history?.length > _a.MAX_HISTORY * 2) {
465
+ history?.splice(0, history?.length - _a.MAX_HISTORY * 2);
458
466
  }
459
467
  }
460
468
  // ═══════════════════════════════════════════════════
@@ -0,0 +1,20 @@
1
+ /**
2
+ * mock-pipeline.ts — Mock AI Bootstrap 轻量管线
3
+ *
4
+ * 当 AI Provider 为 mock 时,利用 Phase 1-4 已收集的真实数据
5
+ * (AST、依赖图、文件列表、Panorama) 为每个维度生成模板化候选知识。
6
+ *
7
+ * 不调用 AI,但走完完整的 submit → dimension_complete 流程,
8
+ * 使 Dashboard 能正常展示知识库、健康雷达等 UI。
9
+ *
10
+ * @module pipeline/mock-pipeline
11
+ */
12
+ import type { DimensionDef } from '#types/project-snapshot.js';
13
+ import type { PipelineFillView } from '#types/snapshot-views.js';
14
+ /**
15
+ * fillDimensionsMock — Mock AI 轻量管线
16
+ *
17
+ * 利用 Phase 1-4 的真实数据(AST、文件列表、Panorama)自动生成候选知识,
18
+ * 不调用任何 AI API,但走完 submit → dimension_complete 的完整流程。
19
+ */
20
+ export declare function fillDimensionsMock(view: PipelineFillView, dimensions: DimensionDef[]): Promise<void>;