speccore 5.69.7 → 5.70.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 (59) hide show
  1. package/dist/commands/ask.d.ts.map +1 -1
  2. package/dist/commands/ask.js +0 -1
  3. package/dist/commands/ask.js.map +1 -1
  4. package/dist/commands/execute.d.ts.map +1 -1
  5. package/dist/commands/execute.js +48 -35
  6. package/dist/commands/execute.js.map +1 -1
  7. package/dist/commands/init.d.ts.map +1 -1
  8. package/dist/commands/init.js +53 -0
  9. package/dist/commands/init.js.map +1 -1
  10. package/dist/commands/pr.d.ts.map +1 -1
  11. package/dist/commands/pr.js +5 -0
  12. package/dist/commands/pr.js.map +1 -1
  13. package/dist/commands/welcome.js +1 -1
  14. package/dist/core/ask-config.d.ts +54 -0
  15. package/dist/core/ask-config.d.ts.map +1 -0
  16. package/dist/core/ask-config.js +145 -0
  17. package/dist/core/ask-config.js.map +1 -0
  18. package/dist/core/ask-context.d.ts +61 -0
  19. package/dist/core/ask-context.d.ts.map +1 -0
  20. package/dist/core/ask-context.js +187 -0
  21. package/dist/core/ask-context.js.map +1 -0
  22. package/dist/core/ask-engine.d.ts.map +1 -1
  23. package/dist/core/ask-engine.js +163 -64
  24. package/dist/core/ask-engine.js.map +1 -1
  25. package/dist/core/ask-host-ai.d.ts.map +1 -1
  26. package/dist/core/ask-host-ai.js +6 -0
  27. package/dist/core/ask-host-ai.js.map +1 -1
  28. package/dist/core/context.d.ts.map +1 -1
  29. package/dist/core/context.js +4 -1
  30. package/dist/core/context.js.map +1 -1
  31. package/dist/core/doc-validator.js +2 -2
  32. package/dist/core/doc-validator.js.map +1 -1
  33. package/dist/core/error-feedback.d.ts.map +1 -1
  34. package/dist/core/error-feedback.js.map +1 -1
  35. package/dist/core/intent-cache.d.ts +55 -0
  36. package/dist/core/intent-cache.d.ts.map +1 -0
  37. package/dist/core/intent-cache.js +162 -0
  38. package/dist/core/intent-cache.js.map +1 -0
  39. package/dist/core/prompt-builder.js +2 -2
  40. package/dist/core/prompt-builder.js.map +1 -1
  41. package/dist/core/schemas/context.schema.d.ts.map +1 -1
  42. package/dist/core/schemas/context.schema.js +1 -0
  43. package/dist/core/schemas/context.schema.js.map +1 -1
  44. package/dist/core/schemas/iteration.schema.d.ts.map +1 -1
  45. package/dist/core/schemas/iteration.schema.js +1 -0
  46. package/dist/core/schemas/iteration.schema.js.map +1 -1
  47. package/dist/core/schemas/platform.schema.d.ts.map +1 -1
  48. package/dist/core/schemas/platform.schema.js +1 -0
  49. package/dist/core/schemas/platform.schema.js.map +1 -1
  50. package/dist/core/schemas/task.schema.d.ts.map +1 -1
  51. package/dist/core/schemas/task.schema.js +1 -0
  52. package/dist/core/schemas/task.schema.js.map +1 -1
  53. package/dist/core/state.d.ts.map +1 -1
  54. package/dist/core/state.js +2 -1
  55. package/dist/core/state.js.map +1 -1
  56. package/dist/core/transaction.d.ts.map +1 -1
  57. package/dist/core/transaction.js +4 -0
  58. package/dist/core/transaction.js.map +1 -1
  59. package/package.json +1 -1
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ /**
3
+ * ask-context — Rich Context 构建器
4
+ *
5
+ * 为宿主AI / LLM 提供决策所需的完整上下文:
6
+ * 1. 本地引擎候选意图(让AI做选择题而非填空题)
7
+ * 2. 项目阶段与生命周期状态
8
+ * 3. 当前迭代/任务上下文
9
+ * 4. 最近命令历史(时间序列行为模式)
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.buildAskContext = buildAskContext;
13
+ exports.formatContextForHostAi = formatContextForHostAi;
14
+ const path_1 = require("path");
15
+ const context_1 = require("./context");
16
+ const logger_1 = require("../utils/logger");
17
+ // ═══════════════════════════════════════════════════════════
18
+ // Rich Context 构建入口
19
+ // ═══════════════════════════════════════════════════════════
20
+ /**
21
+ * 构建完整的 AskContext,供宿主AI / LLM 做语义判断
22
+ */
23
+ async function buildAskContext(input, localResults) {
24
+ const candidates = localResults.slice(0, 4).map(r => ({
25
+ intent: r.intent,
26
+ command: r.command,
27
+ confidence: r.confidence,
28
+ matchedTriggers: r.matchedTriggers.slice(0, 3),
29
+ extractedParams: r.extractedParams,
30
+ }));
31
+ const projectContext = await buildProjectContext();
32
+ return {
33
+ userInput: input,
34
+ localConfidence: localResults[0]?.confidence || 0,
35
+ localCandidates: candidates,
36
+ projectContext,
37
+ availableCommands: getAvailableCommandsForPhase(projectContext.phase),
38
+ };
39
+ }
40
+ // ═══════════════════════════════════════════════════════════
41
+ // 项目上下文构建
42
+ // ═══════════════════════════════════════════════════════════
43
+ async function buildProjectContext() {
44
+ const ctx = await (0, context_1.loadContext)();
45
+ const iteration = ctx.currentIteration || (await (0, context_1.detectActiveIteration)());
46
+ return {
47
+ phase: detectProjectPhase(),
48
+ currentIteration: iteration,
49
+ currentTask: ctx.currentTask || '',
50
+ recentCommands: (ctx.history || []).slice(-5).map(h => ({
51
+ command: h.command,
52
+ timestamp: h.timestamp,
53
+ iteration: h.iteration,
54
+ task: h.task,
55
+ })),
56
+ iterationStats: {
57
+ pending: ctx.pendingTasks || 0,
58
+ inProgress: ctx.inProgressTasks || 0,
59
+ completed: ctx.completedTasks || 0,
60
+ blocked: ctx.blockedTasks || 0,
61
+ },
62
+ };
63
+ }
64
+ // ═══════════════════════════════════════════════════════════
65
+ // 项目阶段检测
66
+ // ═══════════════════════════════════════════════════════════
67
+ /**
68
+ * 根据当前目录结构和上下文推断项目阶段
69
+ */
70
+ function detectProjectPhase() {
71
+ // 基于文件存在性推断阶段
72
+ const cwd = process.cwd();
73
+ // 检查是否有迭代目录
74
+ try {
75
+ const { readdirSync } = require('fs');
76
+ const dirs = readdirSync(cwd, { withFileTypes: true })
77
+ .filter((d) => d.isDirectory())
78
+ .map((d) => d.name);
79
+ const hasIterations = dirs.some((d) => d.startsWith('Iteration-'));
80
+ const hasSpeccore = dirs.includes('.speccore');
81
+ if (!hasSpeccore)
82
+ return 'init';
83
+ if (!hasIterations)
84
+ return 'analyze';
85
+ // 检查最新迭代的内容
86
+ const iterDirs = dirs.filter((d) => d.startsWith('Iteration-')).sort();
87
+ const latestIter = iterDirs[iterDirs.length - 1];
88
+ if (!latestIter)
89
+ return 'analyze';
90
+ const iterPath = (0, path_1.join)(cwd, latestIter);
91
+ const { existsSync } = require('fs');
92
+ const hasTasks = existsSync((0, path_1.join)(iterPath, '030-tasks'));
93
+ const hasSpecs = existsSync((0, path_1.join)(iterPath, '020-specs'));
94
+ const hasRequirements = existsSync((0, path_1.join)(iterPath, '010-requirements'));
95
+ if (!hasRequirements)
96
+ return 'init';
97
+ if (!hasSpecs)
98
+ return 'analyze';
99
+ if (!hasTasks)
100
+ return 'split';
101
+ // 检查是否有执行中的任务
102
+ if (hasTasks) {
103
+ try {
104
+ const taskDirs = readdirSync((0, path_1.join)(iterPath, '030-tasks'), { withFileTypes: true })
105
+ .filter((d) => d.isDirectory() && d.name.startsWith('Task-'));
106
+ if (taskDirs.length === 0)
107
+ return 'plan';
108
+ }
109
+ catch { }
110
+ }
111
+ return 'execute';
112
+ }
113
+ catch (e) {
114
+ logger_1.logger.debug(`阶段检测失败: ${e.message}`);
115
+ return 'unknown';
116
+ }
117
+ }
118
+ // ═══════════════════════════════════════════════════════════
119
+ // 阶段化命令推荐
120
+ // ═══════════════════════════════════════════════════════════
121
+ /**
122
+ * 根据项目阶段返回当前最相关的命令列表
123
+ * 用于缩小宿主AI的决策范围
124
+ */
125
+ function getAvailableCommandsForPhase(phase) {
126
+ const base = ['help', 'dashboard', 'context'];
127
+ switch (phase) {
128
+ case 'init':
129
+ return [...base, 'init', 'iteration create', 'doc2spec'];
130
+ case 'analyze':
131
+ return [...base, 'analyze', 'doc2spec', 'split', 'validate'];
132
+ case 'split':
133
+ return [...base, 'split', 'task new', 'plan', 'analyze'];
134
+ case 'plan':
135
+ return [...base, 'plan', 'execute', 'task new', 'validate'];
136
+ case 'execute':
137
+ return [...base, 'execute', 'plan', 'pr', 'done', 'change', 'sync'];
138
+ case 'done':
139
+ return [...base, 'done', 'pr', 'sync', 'spec2doc'];
140
+ default:
141
+ return base;
142
+ }
143
+ }
144
+ // ═══════════════════════════════════════════════════════════
145
+ // Context 序列化(用于文件协议 / stdout 标记)
146
+ // ═══════════════════════════════════════════════════════════
147
+ /**
148
+ * 将 AskContext 序列化为宿主AI可读的结构化文本
149
+ */
150
+ function formatContextForHostAi(context) {
151
+ const lines = [];
152
+ lines.push('## 用户输入');
153
+ lines.push(`"${context.userInput}"`);
154
+ lines.push('');
155
+ lines.push('## 本地引擎候选(按置信度排序)');
156
+ if (context.localCandidates.length === 0) {
157
+ lines.push('本地引擎未识别到匹配意图。');
158
+ }
159
+ else {
160
+ for (const c of context.localCandidates) {
161
+ const params = Object.entries(c.extractedParams)
162
+ .map(([k, v]) => `${k}=${v}`)
163
+ .join(', ');
164
+ lines.push(`- ${c.command} (${c.confidence}%) — 触发: ${c.matchedTriggers.join(', ')}${params ? ` | 参数: ${params}` : ''}`);
165
+ }
166
+ }
167
+ lines.push('');
168
+ lines.push('## 项目上下文');
169
+ const pc = context.projectContext;
170
+ lines.push(`- 当前阶段: ${pc.phase}`);
171
+ lines.push(`- 活跃迭代: ${pc.currentIteration || '无'}`);
172
+ lines.push(`- 当前任务: ${pc.currentTask || '无'}`);
173
+ lines.push(`- 任务统计: 待处理${pc.iterationStats.pending} / 进行中${pc.iterationStats.inProgress} / 已完成${pc.iterationStats.completed} / 阻塞${pc.iterationStats.blocked}`);
174
+ if (pc.recentCommands.length > 0) {
175
+ lines.push(`- 最近命令: ${pc.recentCommands.map(c => c.command).join(' → ')}`);
176
+ }
177
+ lines.push('');
178
+ lines.push('## 当前阶段推荐命令');
179
+ lines.push(context.availableCommands.join(', '));
180
+ lines.push('');
181
+ lines.push('## 你的任务');
182
+ lines.push('根据用户输入、本地引擎候选和项目上下文,判断最佳意图。');
183
+ lines.push('如果本地候选已足够明确,直接选择;如果模糊,结合项目阶段推断。');
184
+ lines.push('返回格式: {"intent": "...", "command": "...", "confidence": 95, "reasoning": "..."}');
185
+ return lines.join('\n');
186
+ }
187
+ //# sourceMappingURL=ask-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask-context.js","sourceRoot":"","sources":["../../src/core/ask-context.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ask-engine.d.ts","sourceRoot":"","sources":["../../src/core/ask-engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ask-engine.d.ts","sourceRoot":"","sources":["../../src/core/ask-engine.ts"],"names":[],"mappings":"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"}
@@ -47,6 +47,9 @@ const logger_1 = require("../utils/logger");
47
47
  const intent_recognition_1 = require("./intent-recognition");
48
48
  const ask_llm_1 = require("./ask-llm");
49
49
  const ask_host_ai_1 = require("./ask-host-ai");
50
+ const ask_config_1 = require("./ask-config");
51
+ const intent_cache_1 = require("./intent-cache");
52
+ const ask_context_1 = require("./ask-context");
50
53
  // ============================================================
51
54
  // 命令知识库
52
55
  // ============================================================
@@ -81,7 +84,7 @@ const COMMAND_KB = [
81
84
  usage: 'speccore dev [--auto] [--from <phase>] [--to <phase>]', examples: ['speccore dev --auto', 'speccore dev --from analyze --to execute'], related: ['execute', 'plan'], triggers: ['dev', '流水线', '自动', '级联'] },
82
85
  { name: 'task', aliases: ['tk'], description: '任务管理:创建/列表/状态。子命令: new, list, status',
83
86
  usage: 'speccore task new --name <name> [--id <id>] | speccore task list | speccore task status', examples: ['speccore task new --name "用户登录"', 'speccore task list'], related: ['plan', 'execute'], triggers: ['task', '任务列表', '查看任务', '列出任务'] },
84
- { name: 'schedule', aliases: ['sc'], description: '[暂未实现] 定时调度管理:创建/查看/取消/重试/守护进程',
87
+ { name: 'schedule', aliases: ['sc'], description: '[已废弃] 定时调度功能已废弃,请勿使用',
85
88
  usage: 'speccore schedule create --at "HH:mm" | speccore schedule list | speccore schedule cancel --id <id>',
86
89
  examples: ['speccore schedule list', 'speccore schedule retry --id sch-xxx'],
87
90
  related: ['plan', 'execute', 'task'], triggers: ['调度', '定时', 'schedule', '重调度', 'retry', '守护进程', 'daemon', '队列'] },
@@ -288,7 +291,7 @@ function handleGuide(input) {
288
291
  else if (/新功能|feature|登录|注册|支付|创建.*功能|做.*功能/i.test(input)) {
289
292
  matchedWorkflow = WORKFLOWS['new feature'];
290
293
  workflowName = '新功能开发全流程';
291
- throw new Error('FALLBACK_TO_MATCH');
294
+ return null;
292
295
  }
293
296
  else if (/批量|分批|batch|队列/i.test(input)) {
294
297
  matchedWorkflow = WORKFLOWS['batch execute'];
@@ -296,11 +299,11 @@ function handleGuide(input) {
296
299
  }
297
300
  else if (/创建.*迭代创建.*迭代/i.test(input)) {
298
301
  // 不应该进 guide 模式——让调用方降级到 match
299
- throw new Error('FALLBACK_TO_MATCH');
302
+ return null;
300
303
  }
301
304
  else {
302
- // 无匹配工作流 → 抛出,由 askEngine 降级到 handleMatch
303
- throw new Error('FALLBACK_TO_MATCH');
305
+ // 无匹配工作流 → 返回 null,由 askEngine 降级到 handleMatch
306
+ return null;
304
307
  }
305
308
  const steps = matchedWorkflow.map(s => ` ${s.order}. speccore ${s.command}${s.args ? ' ' + s.args : ''}` +
306
309
  `\n → ${s.explanation}`).join('\n\n');
@@ -333,10 +336,11 @@ function handleGuide(input) {
333
336
  async function handleMatch(input) {
334
337
  // 优先用 KB 精确匹配
335
338
  const kbMatch = matchCommandInKB(input);
339
+ const config = await (0, ask_config_1.loadAskConfig)();
336
340
  const results = await (0, intent_recognition_1.recognizeIntent)(input);
337
341
  const best = results[0];
338
342
  // 如果 KB 有匹配且置信度高于意图识别,用 KB(但要整合意图识别的参数)
339
- if (kbMatch && (!best || best.confidence < 70)) {
343
+ if (kbMatch && (!best || best.confidence < 60)) {
340
344
  const params = best?.extractedParams || {};
341
345
  let fullCommand = `speccore ${kbMatch.name}`;
342
346
  const paramNotes = [];
@@ -365,7 +369,7 @@ async function handleMatch(input) {
365
369
  return { mode: 'match', summary: '未识别到匹配命令', detail: '我无法完全理解你的意图。试试:\n speccore help — 查看命令列表\n 或更详细地描述你想做什么', commands: [] };
366
370
  }
367
371
  // ── 低置信度拒绝 ──
368
- if (best.confidence < 45) {
372
+ if (best.confidence < config.routing.lowThreshold) {
369
373
  return {
370
374
  mode: 'match',
371
375
  summary: '置信度过低',
@@ -394,11 +398,11 @@ async function handleMatch(input) {
394
398
  let fullCommand;
395
399
  const paramNotes = [];
396
400
  // task-create / iteration-create 需要子命令
397
- if (best.intent === 'task-create') {
401
+ if (best.command === 'task-create') {
398
402
  const name = params.name || params.desc || input.slice(0, 30);
399
403
  fullCommand = `speccore task new -n "${name}"`;
400
404
  }
401
- else if (best.intent === 'iteration-create') {
405
+ else if (best.command === 'iteration-create') {
402
406
  const name = params.name || input.slice(0, 20);
403
407
  fullCommand = `speccore iteration create -n "${name}"`;
404
408
  }
@@ -453,7 +457,7 @@ async function handleMatch(input) {
453
457
  summary: `匹配到: ${best.intent} (${best.confidence}%) → ${fullCommand}`,
454
458
  detail,
455
459
  commands: [best.command],
456
- autoExec: best.confidence >= 70 ? {
460
+ autoExec: best.confidence >= config.routing.highThreshold ? {
457
461
  command: fullCommand.replace(/^speccore /, '').split(' ')[0], // 主命令
458
462
  args: fullCommand.replace(/^speccore [a-z-]+ /, ''), // 子命令 + 参数
459
463
  confirm: true,
@@ -573,8 +577,16 @@ function handlePipeline(input) {
573
577
  } : undefined,
574
578
  };
575
579
  }
576
- // 默认返回 guide
577
- return handleGuide(input);
580
+ // 默认返回 guide(降级到 match 若 guide 无匹配)
581
+ const guideResult = handleGuide(input);
582
+ if (guideResult)
583
+ return guideResult;
584
+ return {
585
+ mode: 'match',
586
+ summary: '未匹配到编排模式',
587
+ detail: '无法识别为 Pipeline 模式,请尝试更具体的描述。',
588
+ commands: [],
589
+ };
578
590
  }
579
591
  function buildPipelineDetail(steps, input) {
580
592
  // fill template placeholders
@@ -833,7 +845,7 @@ async function synthesizeIntent(input) {
833
845
  // b) 置信度低于阈值
834
846
  // c) 参数严重缺失(如无任务名就创建任务)
835
847
  // 否则 AI 自主补全后直接执行
836
- const isProblematic = gaps.length > 0 || confidence < 70;
848
+ const isProblematic = gaps.length > 0 || confidence < 60;
837
849
  // 关键参数缺失 → 提问
838
850
  if (commands.includes('task') && !parsed.name && !parsed.type) {
839
851
  questions.push('请描述你要创建的任务类型和名称(如:创建一个登录功能的bug修复任务)');
@@ -863,8 +875,9 @@ async function synthesizeIntent(input) {
863
875
  };
864
876
  }
865
877
  async function askEngine(input) {
866
- // ── 第零层: 确定性操作直接路由 ──
867
- // 切换上下文 → context set(无歧义,直接执行)
878
+ // ═══════════════════════════════════════════════════════════
879
+ // 第零层: 确定性操作直接路由(零成本,最高优先级)
880
+ // ═══════════════════════════════════════════════════════════
868
881
  if (/切换.*[到至].*迭代|上下文.*切换|切换到/.test(input)) {
869
882
  const iterMatch = input.match(/Iteration[- ]?\S+|Q\d+|sample/i);
870
883
  const raw = iterMatch ? iterMatch[0] : '';
@@ -879,64 +892,150 @@ async function askEngine(input) {
879
892
  };
880
893
  }
881
894
  }
882
- // ── --rules 模式: 自有 LLM + 关键词匹配(显式触发)──
883
- if (input.includes('--rules')) {
884
- // 优先: 自有 LLM(需要配置 SPECCORE_LLM_KEY)
885
- if (process.env.SPECCORE_LLM_KEY) {
886
- try {
887
- const llmResult = await (0, ask_llm_1.askWithLlm)(input);
888
- if (llmResult && llmResult.commands.length > 0) {
889
- logger_1.logger.info(`🧠 自有 LLM: ${modeLabel(llmResult.mode)}`);
890
- llmResult._source = 'llm';
891
- return llmResult;
892
- }
895
+ // ═══════════════════════════════════════════════════════════
896
+ // 加载统一配置(环境变量 > ask.json > 默认值)
897
+ // ═══════════════════════════════════════════════════════════
898
+ const config = await (0, ask_config_1.loadAskConfig)();
899
+ // ═══════════════════════════════════════════════════════════
900
+ // 第一层: 意图缓存(零成本,高频意图越用越快)
901
+ // ═══════════════════════════════════════════════════════════
902
+ if (config.routing.cacheEnabled) {
903
+ const cached = await (0, intent_cache_1.getCachedIntent)(input);
904
+ if (cached) {
905
+ logger_1.logger.info(`💾 缓存命中: "${input.slice(0, 30)}..."`);
906
+ return cached;
907
+ }
908
+ }
909
+ // ═══════════════════════════════════════════════════════════
910
+ // 第二层: 本地意图引擎(关键词+正则+上下文)
911
+ // ═══════════════════════════════════════════════════════════
912
+ const mode = classifyMode(input);
913
+ let localResult;
914
+ let localCandidates = [];
915
+ switch (mode) {
916
+ case 'explain':
917
+ localResult = handleExplain(input);
918
+ break;
919
+ case 'guide': {
920
+ const guide = handleGuide(input);
921
+ localResult = guide || await handleMatch(input);
922
+ break;
923
+ }
924
+ case 'pipeline':
925
+ localResult = handlePipeline(input);
926
+ break;
927
+ default:
928
+ localCandidates = await (0, intent_recognition_1.recognizeIntent)(input);
929
+ localResult = await handleMatch(input);
930
+ }
931
+ // 计算本地置信度(explain/guide/pipeline 视为高置信度)
932
+ const localConfidence = localCandidates[0]?.confidence ||
933
+ (localResult.autoExec ? 85 : (mode === 'explain' || mode === 'pipeline') ? 90 : 55);
934
+ // --rules / forceHostAi 强制所有请求走 AI
935
+ const forceHostAi = input.includes('--rules') || config.rules.forceHostAi;
936
+ // ═══════════════════════════════════════════════════════════
937
+ // 第三层: 三段式动态路由策略
938
+ // ═══════════════════════════════════════════════════════════
939
+ //
940
+ // ┌─────────────────────────────────────────────────────┐
941
+ // │ ≥ highThreshold (70) │ 本地直接执行,不打扰 AI │
942
+ // │ lowThreshold~high │ 双路并行,取更优结果 │
943
+ // │ < lowThreshold (45) │ 直接交给 AI,本地只提参数 │
944
+ // └─────────────────────────────────────────────────────┘
945
+ // ── 段1: 高分区 ── 本地引擎直接执行,零AI成本 ──
946
+ if (!forceHostAi && localConfidence >= config.routing.highThreshold) {
947
+ if (config.routing.cacheEnabled)
948
+ await (0, intent_cache_1.cacheIntent)(input, localResult, 'local');
949
+ return localResult;
950
+ }
951
+ // ── 段2: 中分区 ── 双路并行,取更优结果 ──
952
+ if (!forceHostAi && localConfidence >= config.routing.lowThreshold) {
953
+ // 本地结果已就绪,同时触发宿主AI
954
+ const hostPromise = tryHostAiEnhanced(input, localCandidates);
955
+ const hostResult = await hostPromise;
956
+ if (hostResult && hostResult.commands.length > 0) {
957
+ // AI 返回有效结果 → 优先AI(语义理解更精准)
958
+ if (config.routing.cacheEnabled)
959
+ await (0, intent_cache_1.cacheIntent)(input, hostResult, 'host-ai');
960
+ return hostResult;
961
+ }
962
+ // AI 不可用或失败 → 回退本地
963
+ if (config.routing.cacheEnabled)
964
+ await (0, intent_cache_1.cacheIntent)(input, localResult, 'local');
965
+ return localResult;
966
+ }
967
+ // ── 段3: 低分区 ── 直接交给AI,本地只负责提取参数 ──
968
+ // 此时本地引擎置信度不足,优先AI语义判断
969
+ if (forceHostAi || config.routing.autoHostAi) {
970
+ if (mode === 'match' || mode === 'ambiguous') {
971
+ const hostResult = await tryHostAiEnhanced(input, localCandidates);
972
+ if (hostResult && hostResult.commands.length > 0) {
973
+ if (config.routing.cacheEnabled)
974
+ await (0, intent_cache_1.cacheIntent)(input, hostResult, 'host-ai');
975
+ return hostResult;
893
976
  }
894
- catch (e) {
895
- logger_1.logger.warn(`LLM 不可用: ${e.message}`);
977
+ // 自有LLM冗余(用户配置了provider时启用)
978
+ const llmResult = await tryLlmProviders(input, config);
979
+ if (llmResult) {
980
+ if (config.routing.cacheEnabled)
981
+ await (0, intent_cache_1.cacheIntent)(input, llmResult, 'llm');
982
+ return llmResult;
896
983
  }
897
984
  }
898
- // 兜底: 关键词匹配
899
- const mode = classifyMode(input);
900
- switch (mode) {
901
- case 'explain': return handleExplain(input);
902
- case 'guide': return handleGuide(input);
903
- case 'pipeline': return handlePipeline(input);
904
- default: return handleMatch(input);
905
- }
906
985
  }
907
- // ── 宿主 AI 文件协议(TRAE 等)──
986
+ // ── 兜底 ── 所有AI路径都失败,返回本地结果
987
+ return localResult;
988
+ }
989
+ // ═══════════════════════════════════════════════════════════
990
+ // 宿主AI增强(传入Rich Context)
991
+ // ═══════════════════════════════════════════════════════════
992
+ async function tryHostAiEnhanced(input, candidates) {
993
+ const context = await (0, ask_context_1.buildAskContext)(input, candidates);
908
994
  try {
909
- const hostResult = await (0, ask_host_ai_1.tryHostAi)('ask', input);
995
+ const hostResult = await (0, ask_host_ai_1.tryHostAi)('ask', input, {
996
+ ...context,
997
+ formattedContext: (0, ask_context_1.formatContextForHostAi)(context),
998
+ });
910
999
  if (hostResult) {
911
- logger_1.logger.info(`🤖 宿主 AI: ${modeLabel((hostResult.mode || 'match'))}`);
912
- hostResult._source = 'host';
1000
+ logger_1.logger.info(`🤖 宿主AI增强成功: ${hostResult.summary || hostResult.mode}`);
913
1001
  return hostResult;
914
1002
  }
915
1003
  }
916
- catch (e) { /* 不可用,继续 */ }
917
- // ── 输出知识库,交给宿主 AI 语义分析 ......
918
- const kb = COMMAND_KB.map(c => ` ${c.name}: ${c.description.padEnd(30)} → ${c.usage}`).join('\n');
919
- const pipelines = Object.entries(WORKFLOWS).map(([name, steps]) => ` ${name}: ${steps.map(s => s.command).join(' → ')}`).join('\n');
920
- return {
921
- mode: 'match',
922
- summary: '宿主 AI 语义分析',
923
- detail: [
924
- `## 用户输入`,
925
- `"${input}"`,
926
- ``,
927
- `## 可用操作`,
928
- kb,
929
- ``,
930
- `## 常用工作流`,
931
- pipelines,
932
- ``,
933
- `## 你的任务`,
934
- `根据用户输入和可用操作,判断用户意图,`,
935
- `直接 call speccore CLI 命令(如 analyze/plan/schedule/execute)执行。`,
936
- `需要 AI 参与的命令加 --prompt 标志。`,
937
- ].join('\n'),
938
- commands: [],
939
- };
1004
+ catch (e) {
1005
+ logger_1.logger.debug(`宿主AI增强失败: ${e.message}`);
1006
+ }
1007
+ return null;
1008
+ }
1009
+ // ═══════════════════════════════════════════════════════════
1010
+ // 多LLM冗余路由(用户配置了provider时启用,默认禁用)
1011
+ // ═══════════════════════════════════════════════════════════
1012
+ async function tryLlmProviders(input, config) {
1013
+ const enabledProviders = (config.llmProviders || [])
1014
+ .filter(p => p.enabled)
1015
+ .sort((a, b) => a.priority - b.priority);
1016
+ if (enabledProviders.length === 0)
1017
+ return null;
1018
+ for (const provider of enabledProviders) {
1019
+ try {
1020
+ // 注入provider配置到环境变量(临时)
1021
+ if (provider.endpoint)
1022
+ process.env.SPECCORE_LLM_ENDPOINT = provider.endpoint;
1023
+ if (provider.apiKey)
1024
+ process.env.SPECCORE_LLM_KEY = provider.apiKey;
1025
+ if (provider.model)
1026
+ process.env.SPECCORE_LLM_MODEL = provider.model;
1027
+ const llmResult = await (0, ask_llm_1.askWithLlm)(input);
1028
+ if (llmResult && llmResult.commands.length > 0) {
1029
+ logger_1.logger.info(`🧠 ${provider.name} 响应成功: ${llmResult.mode}`);
1030
+ llmResult._source = 'llm';
1031
+ return llmResult;
1032
+ }
1033
+ }
1034
+ catch (e) {
1035
+ logger_1.logger.warn(`${provider.name} 不可用: ${e.message}`);
1036
+ }
1037
+ }
1038
+ return null;
940
1039
  }
941
1040
  /** 用规则引擎补充 LLM 结果的内容 */
942
1041
  function enrichWithRules(llmResult, input) {