speccore 8.3.159 → 8.3.161

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 (50) hide show
  1. package/dist/cli.js +2 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/analyze.d.ts +16 -0
  4. package/dist/commands/analyze.d.ts.map +1 -1
  5. package/dist/commands/analyze.js +538 -316
  6. package/dist/commands/analyze.js.map +1 -1
  7. package/dist/commands/change.d.ts.map +1 -1
  8. package/dist/commands/change.js +14 -14
  9. package/dist/commands/change.js.map +1 -1
  10. package/dist/commands/execute.d.ts +1 -0
  11. package/dist/commands/execute.d.ts.map +1 -1
  12. package/dist/commands/execute.js +92 -10
  13. package/dist/commands/execute.js.map +1 -1
  14. package/dist/commands/init.d.ts.map +1 -1
  15. package/dist/commands/init.js +6 -2
  16. package/dist/commands/init.js.map +1 -1
  17. package/dist/commands/iteration/split.d.ts.map +1 -1
  18. package/dist/commands/iteration/split.js +299 -52
  19. package/dist/commands/iteration/split.js.map +1 -1
  20. package/dist/commands/plan.d.ts.map +1 -1
  21. package/dist/commands/plan.js +45 -36
  22. package/dist/commands/plan.js.map +1 -1
  23. package/dist/core/agent-adapter.d.ts +81 -0
  24. package/dist/core/agent-adapter.d.ts.map +1 -0
  25. package/dist/core/agent-adapter.js +425 -0
  26. package/dist/core/agent-adapter.js.map +1 -0
  27. package/dist/core/ask-engine.d.ts.map +1 -1
  28. package/dist/core/ask-engine.js +60 -0
  29. package/dist/core/ask-engine.js.map +1 -1
  30. package/dist/core/pipeline-engine.d.ts +49 -8
  31. package/dist/core/pipeline-engine.d.ts.map +1 -1
  32. package/dist/core/pipeline-engine.js +221 -34
  33. package/dist/core/pipeline-engine.js.map +1 -1
  34. package/dist/core/prompt-builder.d.ts +12 -3
  35. package/dist/core/prompt-builder.d.ts.map +1 -1
  36. package/dist/core/prompt-builder.js +238 -15
  37. package/dist/core/prompt-builder.js.map +1 -1
  38. package/dist/core/requirement-clarifier.d.ts.map +1 -1
  39. package/dist/core/requirement-clarifier.js +36 -3
  40. package/dist/core/requirement-clarifier.js.map +1 -1
  41. package/dist/core/schemas/task.schema.d.ts +2 -2
  42. package/dist/core/structured-extractor.d.ts +2 -0
  43. package/dist/core/structured-extractor.d.ts.map +1 -1
  44. package/dist/core/structured-extractor.js +61 -0
  45. package/dist/core/structured-extractor.js.map +1 -1
  46. package/dist/core/unified-retrieval.d.ts +2 -1
  47. package/dist/core/unified-retrieval.d.ts.map +1 -1
  48. package/dist/core/unified-retrieval.js +34 -15
  49. package/dist/core/unified-retrieval.js.map +1 -1
  50. package/package.json +1 -1
@@ -1,9 +1,43 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.loadGlobalContext = loadGlobalContext;
4
37
  exports.formatGlobalContext = formatGlobalContext;
5
38
  exports.buildPrompt = buildPrompt;
6
39
  exports.formatPrompt = formatPrompt;
40
+ exports.buildPromptText = buildPromptText;
7
41
  exports.extractInfoGaps = extractInfoGaps;
8
42
  exports.parseAiResponse = parseAiResponse;
9
43
  exports.outputNeedsInfo = outputNeedsInfo;
@@ -33,10 +67,14 @@ const synonyms_1 = require("../utils/synonyms");
33
67
  const vision_engine_1 = require("./vision-engine");
34
68
  // v6.93.0+: Prompt 插件系统
35
69
  const prompt_plugins_1 = require("./prompt-plugins");
70
+ // v8.3.160+: 子 Agent 适配层(统一注入角色定义和上下文裁剪)
71
+ const agent_adapter_1 = require("./agent-adapter");
36
72
  const techStackCache = new Map();
37
73
  const constitutionCache = new Map();
38
74
  const reqContentCache = new Map();
39
75
  const tocCache = new Map();
76
+ // v8.3.160+: 关键约束缓存(解决上下文漂移)
77
+ const keyConstraintsCache = new Map();
40
78
  /** 通用文件缓存读取 */
41
79
  async function cachedRead(cache, filePath, loader) {
42
80
  try {
@@ -87,6 +125,51 @@ async function loadTechStack(cwd) {
87
125
  return stack;
88
126
  });
89
127
  }
128
+ /**
129
+ * v8.3.160+: 从 CONSTITUTION.md 提取关键约束(解决上下文漂移)
130
+ * 提取命名规范、Git 策略、错误码、核心禁令等不可遗忘的约束
131
+ */
132
+ async function loadKeyConstraints(cwd) {
133
+ const constitutionPath = (0, path_1.join)(cwd, '.speccore', 'CONSTITUTION.md');
134
+ if (!await (0, fs_extra_1.pathExists)(constitutionPath))
135
+ return [];
136
+ return cachedRead(keyConstraintsCache, constitutionPath, async () => {
137
+ const content = await (0, fs_extra_1.readFile)(constitutionPath, 'utf-8');
138
+ const constraints = [];
139
+ // 提取核心禁令(⛔ 标记)
140
+ const banMatches = content.matchAll(/⛔\s*(.+)/g);
141
+ for (const match of banMatches) {
142
+ constraints.push(`禁止: ${match[1].trim()}`);
143
+ }
144
+ // 提取命名规范
145
+ const namingSection = content.match(/##\s*命名规范[\s\S]*?(?=##\s|#{3,}\s|$)/i);
146
+ if (namingSection) {
147
+ const lines = namingSection[0].split('\n')
148
+ .filter(l => l.trim().startsWith('-') || l.trim().startsWith('*'))
149
+ .map(l => `命名: ${l.trim().replace(/^[-*]\s*/, '')}`)
150
+ .slice(0, 6);
151
+ constraints.push(...lines);
152
+ }
153
+ // 提取 Git 分支策略
154
+ const gitMatch = content.match(/Git\s*分支[策略]*[::]\s*(.+)/i) ||
155
+ content.match(/分支策略[::]\s*(.+)/i);
156
+ if (gitMatch) {
157
+ constraints.push(`Git: ${gitMatch[1].trim()}`);
158
+ }
159
+ // 提取错误码体系
160
+ const errorMatch = content.match(/错误码[体系]*[::]\s*(.+)/i);
161
+ if (errorMatch) {
162
+ constraints.push(`错误码: ${errorMatch[1].trim()}`);
163
+ }
164
+ // 提取端名规范
165
+ const platformMatch = content.match(/端名[列表]*[::]\s*(.+)/i) ||
166
+ content.match(/平台[列表]*[::]\s*(.+)/i);
167
+ if (platformMatch) {
168
+ constraints.push(`端名: ${platformMatch[1].trim()}`);
169
+ }
170
+ return constraints.slice(0, 20); // 最多 20 条,控制 Token 预算
171
+ });
172
+ }
90
173
  /**
91
174
  * 定位 REQ.md 实际路径(支持新旧结构)
92
175
  */
@@ -1168,9 +1251,13 @@ function buildSplitInstruction() {
1168
1251
  ' - 哪些功能需要跨端协作?',
1169
1252
  ' - 数据如何在端之间流转?',
1170
1253
  '',
1171
- '4. **Read `020-specs/{功能模块}/{端名}/TECH.md`**(按功能模块×端组合读取)→ 了解各端技术方案',
1254
+ '4. **Read `020-specs/{功能模块}/{端名}/TECH.md`**(按需读取)→ 了解各端技术方案',
1172
1255
  ' - 先读 FUNCTION_MAP.md 获取功能模块清单',
1173
- ' - 再按 `020-specs/{功能模块}/{端名}/TECH.md` 读取该功能在各端的技术方案',
1256
+ ' - **分批策略(v8.3.160+)**:',
1257
+ ' - 如功能模块数量 ≤ 2:读取所有模块的 TECH.md,一次性拆分全部',
1258
+ ' - 如功能模块数量 > 2:先读取基础模块(认证/配置/数据库)的 TECH.md,优先拆分基础模块',
1259
+ ' - 然后读取 1-2 个核心功能模块的 TECH.md,拆分这些模块',
1260
+ ' - **不要一次性读取所有模块的 TECH.md**,避免上下文溢出',
1174
1261
  ' - 各端有哪些接口/页面?',
1175
1262
  ' - 各端技术栈和架构约束?',
1176
1263
  ' - **据此确定每个任务涉及哪些端**',
@@ -1264,6 +1351,16 @@ function buildSplitInstruction() {
1264
1351
  '- `techContent`:该任务的技术方案(Markdown 格式,含架构设计、核心逻辑、测试策略),直接写入 TECH.md',
1265
1352
  '- 内容是**子切面**:只包含该任务负责的部分,不是整个功能单元的内容',
1266
1353
  '',
1354
+ '### 分批续批(v8.3.160+)',
1355
+ '如果本次只拆分了部分功能模块,在 JSON 数组输出后追加续批标记:',
1356
+ '```',
1357
+ '[PENDING: 模块A, 模块B, 模块C]',
1358
+ '[SPECCORE_EXEC: speccore iteration split --prompt -I {迭代名}]',
1359
+ '```',
1360
+ '- `[PENDING: ...]`:列出未拆分的功能模块名称',
1361
+ '- `[SPECCORE_EXEC: ...]`:CLI 会自动读取并继续拆分剩余模块',
1362
+ '- 如果所有模块已拆分完毕,不要输出 PENDING 标记',
1363
+ '',
1267
1364
  '### 质量自检',
1268
1365
  '拆分完成后自查:',
1269
1366
  '□ 每个任务都满足原子任务定义?',
@@ -1438,15 +1535,35 @@ function getInstruction(command, context) {
1438
1535
  /**
1439
1536
  * 构建完整的 SpecCore Prompt
1440
1537
  */
1538
+ // v8.3.160+: 命令 → 默认子 Agent 角色映射
1539
+ const DEFAULT_SUBAGENT_MAP = {
1540
+ analyze: 'spec-analyzer',
1541
+ execute: 'spec-executor',
1542
+ split: 'task-decomposer',
1543
+ plan: 'schedule-planner',
1544
+ change: 'impact-analyst',
1545
+ };
1441
1546
  async function buildPrompt(command, options) {
1442
1547
  const cwd = options.cwd || (0, task_utils_1.findProjectRoot)() || process.cwd();
1443
1548
  const techStack = await loadTechStack(cwd);
1444
1549
  const taskDir = options.taskDir || '';
1445
- // P0-1: 统一读取 REQ.md,避免 loadApiSpecs/loadDataModels/loadBusinessRules 各读一次
1446
- const reqContent = taskDir ? await loadReqContent(cwd, taskDir) : null;
1447
- const apiSpecs = await loadApiSpecs(cwd, taskDir, reqContent || undefined);
1448
- const dataModels = await loadDataModels(cwd, taskDir, reqContent || undefined);
1449
- const businessRules = await loadBusinessRules(cwd, taskDir, reqContent || undefined);
1550
+ // v8.3.160+: 步骤级上下文预算(默认 12000)
1551
+ const contextBudget = options.contextBudget || 12000;
1552
+ // v8.3.160+: 根据 contextType 控制 REQ.md 加载深度
1553
+ // full: 加载全文 | incremental/platform-only/contract-only: 不加载(依赖前一步摘要或路径引用)
1554
+ const shouldLoadReqContent = !options.contextType || options.contextType === 'full';
1555
+ const reqContent = shouldLoadReqContent && taskDir ? await loadReqContent(cwd, taskDir) : null;
1556
+ // v8.3.160+: 规格加载策略与 REQ.md 保持一致
1557
+ const shouldLoadFullSpecs = shouldLoadReqContent;
1558
+ const apiSpecs = shouldLoadFullSpecs
1559
+ ? await loadApiSpecs(cwd, taskDir, reqContent || undefined)
1560
+ : [];
1561
+ const dataModels = shouldLoadFullSpecs
1562
+ ? await loadDataModels(cwd, taskDir, reqContent || undefined)
1563
+ : [];
1564
+ const businessRules = shouldLoadFullSpecs
1565
+ ? await loadBusinessRules(cwd, taskDir, reqContent || undefined)
1566
+ : [];
1450
1567
  // 统一检索层:同时查询文档 RAG + 代码切片 + 知识图谱
1451
1568
  let extraSpecs = [];
1452
1569
  // v8.3.123+: analyze/split 阶段也需要统一检索,从迭代需求提取查询词
@@ -1529,18 +1646,35 @@ async function buildPrompt(command, options) {
1529
1646
  }
1530
1647
  }
1531
1648
  }
1649
+ // v8.3.160+: 加载关键约束(每轮重注入,防止上下文漂移)
1650
+ const keyConstraints = await loadKeyConstraints(cwd);
1532
1651
  // v8.3.122+: execute / analyze 时深入读取关联源码(完整文件内容,不只是切片)
1533
1652
  // v8.3.122++: 同时注入知识图谱任务上下文,帮助 AI 理解代码关联关系
1534
- if ((command === 'execute' || command === 'analyze') && searchQuery) {
1653
+ // v8.3.160+: withCode 强制启用时,即使 searchQuery 为空也注入源码上下文
1654
+ const shouldInjectCode = (command === 'execute' || command === 'analyze') && (searchQuery || options.withCode);
1655
+ if (shouldInjectCode) {
1656
+ // 如果 withCode 为 true 但 searchQuery 为空,使用 task 或 iteration 作为默认查询
1657
+ if (!searchQuery && options.withCode) {
1658
+ searchQuery = options.task || options.iteration || 'global';
1659
+ }
1535
1660
  try {
1536
1661
  // v8.3.124+: execute 阶段优先注入结构化事实卡片(structured-data.json)
1662
+ // v8.3.160+: 如指定了 platform,优先读取分段文件 structured-data.{platform}.json
1537
1663
  // 这是最高优先级的改进:用结构化卡片替代原始源码,Token 效率提升 10-20 倍
1538
- const structuredDataPath = (0, path_1.join)(cwd, '.speccore', 'cache', 'structured-data.json');
1664
+ let structuredDataPath = (0, path_1.join)(cwd, '.speccore', 'cache', 'structured-data.json');
1665
+ let structured = null;
1539
1666
  let structuredCardsInjected = false;
1667
+ // 优先尝试平台分段文件
1668
+ if (options.platform) {
1669
+ const platformPath = (0, path_1.join)(cwd, '.speccore', 'cache', `structured-data.${options.platform}.json`);
1670
+ if (await (0, fs_extra_1.pathExists)(platformPath)) {
1671
+ structuredDataPath = platformPath;
1672
+ }
1673
+ }
1540
1674
  if (await (0, fs_extra_1.pathExists)(structuredDataPath)) {
1541
1675
  try {
1542
1676
  const sdContent = await (0, fs_extra_1.readFile)(structuredDataPath, 'utf-8');
1543
- const structured = JSON.parse(sdContent);
1677
+ structured = JSON.parse(sdContent);
1544
1678
  // v8.3.125+: 使用同义词扩展,解决 "登录" 与 "auth" 等跨语言/缩写不匹配
1545
1679
  const queryWords = [...(0, synonyms_1.expandSynonyms)((0, synonyms_1.extractNormalizedKeywords)(searchQuery))];
1546
1680
  const matchedApis = [];
@@ -1549,6 +1683,16 @@ async function buildPrompt(command, options) {
1549
1683
  const matchedRoutes = [];
1550
1684
  const matchedDtos = []; // v8.3.126+
1551
1685
  const matchedServices = []; // v8.3.126+
1686
+ // v8.3.160+: 兼容全量文件(endpoints)和分段文件(平台数据在顶层)两种格式
1687
+ const segPlatform = structured.platform || options.platform || 'unknown';
1688
+ if (!structured.endpoints && structured.apis !== undefined) {
1689
+ // 分段文件格式:包装为 endpoints 结构
1690
+ structured = {
1691
+ endpoints: { [segPlatform]: structured },
1692
+ dtos: structured.dtos || [],
1693
+ services: structured.services || [],
1694
+ };
1695
+ }
1552
1696
  for (const [platform, data] of Object.entries(structured.endpoints || {})) {
1553
1697
  // API 匹配
1554
1698
  for (const api of data.apis || []) {
@@ -1948,6 +2092,43 @@ async function buildPrompt(command, options) {
1948
2092
  projectPathsInfo = lines.join('\n');
1949
2093
  }
1950
2094
  }
2095
+ // v8.3.160+: analyze 命令路由到 buildMultiDocPrompt(统一入口)
2096
+ if (command === 'analyze' && options.analyzeOptions) {
2097
+ try {
2098
+ const { buildMultiDocPrompt } = await Promise.resolve().then(() => __importStar(require('../commands/analyze')));
2099
+ const ctx = {
2100
+ iteration: options.iteration,
2101
+ task: options.task,
2102
+ type: options.analyzeOptions.type,
2103
+ scope: options.analyzeOptions.scope,
2104
+ withCode: options.analyzeOptions.withCode,
2105
+ platform: options.platform,
2106
+ phase: options.analyzeOptions.phase,
2107
+ autoMode: options.analyzeOptions.autoMode,
2108
+ };
2109
+ const rawPrompt = await buildMultiDocPrompt('analyze', ctx, options.analyzeOptions);
2110
+ return {
2111
+ marker: '[SPECCORE_PROMPT]',
2112
+ version: '1.0',
2113
+ command,
2114
+ iteration: options.iteration || '',
2115
+ task: options.task,
2116
+ platform: options.platform,
2117
+ techStack,
2118
+ apiSpecs: [],
2119
+ dataModels: [],
2120
+ businessRules: [],
2121
+ extraSpecs: [],
2122
+ instruction: '',
2123
+ outputHint: '请返回 Markdown 格式的分析结果',
2124
+ rawPrompt,
2125
+ subagent: options.subagent || DEFAULT_SUBAGENT_MAP[command],
2126
+ };
2127
+ }
2128
+ catch (e) {
2129
+ logger_1.logger?.warn?.(`analyze Prompt 构建失败,回退到默认模板: ${e.message}`);
2130
+ }
2131
+ }
1951
2132
  // v6.93.0+: Prompt 插件系统 — 命令特定的增强逻辑由插件提供
1952
2133
  let rulesContent;
1953
2134
  let codeGraphSummary;
@@ -1978,6 +2159,25 @@ async function buildPrompt(command, options) {
1978
2159
  catch {
1979
2160
  // 插件执行失败静默跳过,不影响主流程
1980
2161
  }
2162
+ // v8.3.160+: 注入子 Agent 角色定义和上下文裁剪
2163
+ const subagent = options.subagent || DEFAULT_SUBAGENT_MAP[command];
2164
+ let agentContext;
2165
+ if (subagent) {
2166
+ try {
2167
+ const agentCtx = {
2168
+ subagent,
2169
+ iteration: options.iteration || '',
2170
+ contextBudget: options.contextBudget || 12000,
2171
+ contextType: options.contextType || 'full',
2172
+ cwd,
2173
+ };
2174
+ agentContext = await agent_adapter_1.defaultAdapter.prepareContext(agentCtx);
2175
+ logger_1.logger?.info?.(` 🤖 子 Agent 激活: ${subagent}`);
2176
+ }
2177
+ catch (e) {
2178
+ logger_1.logger?.debug?.('agent-adapter 注入失败:', e);
2179
+ }
2180
+ }
1981
2181
  return {
1982
2182
  marker: '[SPECCORE_PROMPT]',
1983
2183
  version: '1.0',
@@ -1995,12 +2195,16 @@ async function buildPrompt(command, options) {
1995
2195
  projectPaths: projectPathsInfo,
1996
2196
  rulesContent,
1997
2197
  codeGraphSummary,
2198
+ keyConstraints,
2199
+ contextBudget,
1998
2200
  instruction,
1999
2201
  outputHint: command === 'execute'
2000
2202
  ? '请返回格式: {"files": [{"path": "工程标识/相对路径", "content": "代码内容"}]}'
2001
2203
  : command === 'split'
2002
2204
  ? '请返回 JSON 数组格式的任务列表(参见拆分原则中的输出格式)'
2003
2205
  : '请返回 Markdown 格式的分析结果',
2206
+ agentContext,
2207
+ subagent,
2004
2208
  };
2005
2209
  }
2006
2210
  // ═══════════════════════════════════════════════════════════
@@ -2020,18 +2224,20 @@ function estimateTokens(text) {
2020
2224
  * 将 Prompt 序列化为 AI 可读的文本(输出到 stdout)
2021
2225
  * 带动态裁剪:超出预算时按优先级逐级简化
2022
2226
  */
2023
- function formatPrompt(prompt, maxTokens = 12000) {
2227
+ function formatPrompt(prompt, maxTokens) {
2228
+ // v8.3.160+: 使用步骤级上下文预算
2229
+ const budget = maxTokens ?? prompt.contextBudget ?? 12000;
2024
2230
  // 尝试完整构建
2025
2231
  let result = buildPromptText(prompt);
2026
2232
  let tokens = estimateTokens(result);
2027
- if (tokens <= maxTokens)
2233
+ if (tokens <= budget)
2028
2234
  return result;
2029
2235
  // Level 1: 简化全局上下文(只保留 INDEX.md,去掉 TOC 目录)
2030
2236
  if (prompt.globalContext) {
2031
2237
  const slimGlobal = { ...prompt.globalContext, toc: [] };
2032
2238
  result = buildPromptText({ ...prompt, globalContext: slimGlobal });
2033
2239
  tokens = estimateTokens(result);
2034
- if (tokens <= maxTokens) {
2240
+ if (tokens <= budget) {
2035
2241
  logger_1.logger?.info?.(` 🪶 Prompt 已简化:隐藏全局目录(-${estimateTokens(formatGlobalContext(prompt.globalContext, prompt.platform))} tokens)`);
2036
2242
  return result;
2037
2243
  }
@@ -2102,7 +2308,7 @@ function formatPrompt(prompt, maxTokens = 12000) {
2102
2308
  }
2103
2309
  result = buildPromptText({ ...prompt, extraSpecs: budgeted });
2104
2310
  tokens = estimateTokens(result);
2105
- if (tokens <= maxTokens) {
2311
+ if (tokens <= budget) {
2106
2312
  const removed = prompt.extraSpecs.length - budgeted.length;
2107
2313
  logger_1.logger?.info?.(` 🪶 Prompt 已简化:分层预算控制 (P1:${usedP1}/${BUDGET_P1} P2:${usedP2}/${BUDGET_P2} P3:${usedP3}/${BUDGET_P3}${removed > 0 ? ` 移除${removed}项` : ''})`);
2108
2314
  return result;
@@ -2112,7 +2318,7 @@ function formatPrompt(prompt, maxTokens = 12000) {
2112
2318
  if (prompt.taskContext) {
2113
2319
  result = buildPromptText({ ...prompt, taskContext: undefined });
2114
2320
  tokens = estimateTokens(result);
2115
- if (tokens <= maxTokens) {
2321
+ if (tokens <= budget) {
2116
2322
  logger_1.logger?.info?.(` 🪶 Prompt 已简化:隐藏任务关联链`);
2117
2323
  return result;
2118
2324
  }
@@ -2132,11 +2338,28 @@ function formatPrompt(prompt, maxTokens = 12000) {
2132
2338
  }
2133
2339
  /** 实际构建 prompt 文本(无裁剪逻辑) */
2134
2340
  function buildPromptText(prompt) {
2341
+ // v8.3.160+: analyze 命令使用 buildMultiDocPrompt 生成的原始 Prompt,直接返回
2342
+ if (prompt.rawPrompt) {
2343
+ return prompt.rawPrompt;
2344
+ }
2135
2345
  const lines = [];
2136
2346
  lines.push('[SPECCORE_PROMPT]');
2137
2347
  lines.push('');
2348
+ // v8.3.160+: 注入子 Agent 角色定义和上下文裁剪策略
2349
+ if (prompt.agentContext) {
2350
+ lines.push(prompt.agentContext);
2351
+ lines.push('');
2352
+ }
2138
2353
  lines.push(`# 任务: ${prompt.command} — ${prompt.task || prompt.iteration}`);
2139
2354
  lines.push('');
2355
+ // v8.3.160+: 关键约束重注入(必须放在最前面,防止上下文漂移)
2356
+ if (prompt.keyConstraints && prompt.keyConstraints.length > 0) {
2357
+ lines.push('## ⚠️ 核心约束(每轮必达)');
2358
+ for (const constraint of prompt.keyConstraints) {
2359
+ lines.push(`- ${constraint}`);
2360
+ }
2361
+ lines.push('');
2362
+ }
2140
2363
  // 技术栈
2141
2364
  if (Object.keys(prompt.techStack).length > 0) {
2142
2365
  lines.push('## 技术栈');