speccore 8.3.280 → 8.3.282

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.
@@ -576,6 +576,8 @@ async function executeWithProgress(tasks, iteration, base, skip, options) {
576
576
  logger_1.logger.info(agentCtx);
577
577
  logger_1.logger.info('--- AGENT CONTEXT END ---');
578
578
  logger_1.logger.info('\n💡 复制以上内容粘贴到 ' + options.agent + ' 中即可生成代码');
579
+ // v8.3.281+: 指路真正的自动派单——--agent 只打包上下文,Qoder 环境自动执行走 execute 主流程
580
+ logger_1.logger.info(' ⚡ 自动执行: 由宿主 AI 以子进程方式调用 speccore execute --prompt(非 TTY)时,CLI 自动通过 Qoder SDK 派子 Agent 执行并落盘,无需复制粘贴');
579
581
  (0, operation_log_1.logOperation)('speccore execute --agent', options.agent);
580
582
  return;
581
583
  }
@@ -1781,14 +1783,31 @@ function buildAgentContext(tasks, agent) {
1781
1783
  ctx += `→ Know what rules, APIs, services exist\n\n`;
1782
1784
  // 2. Per-task context
1783
1785
  for (const task of tasks) {
1786
+ // v8.3.281+: 真实路径优先(scanTasks 记录的 path),AI 不再从 Iteration-* 通配符猜目录;
1787
+ // 子任务向上两级即 Task-xxx/(00-specs、_shared 所在)
1788
+ const subtaskDir = task.path || '';
1789
+ const isSubtask = !!(task.parentTaskId && subtaskDir);
1790
+ const taskRoot = isSubtask ? (0, path_1.join)(subtaskDir, '..', '..') : subtaskDir;
1784
1791
  ctx += `### Task: ${task.id} — ${task.name || task.id}\n`;
1792
+ if (task.feature)
1793
+ ctx += `功能单元: ${task.feature}(对齐锚点,对应 020-specs/${task.feature}/ 规格源)\n`;
1785
1794
  ctx += `Status: ${task.status} | Priority: ${task.priority} | Type: ${task.type}\n\n`;
1786
1795
  // Progressive loading order
1787
1796
  ctx += `**Read in this order (progressive disclosure):**\n`;
1788
- ctx += `1. \`Iteration-*/${task.id}/{platform}/{subtask}/TASK.md\` — 子任务概览(所有端平铺)\n`;
1789
- ctx += `2. \`Iteration-*/${task.id}/00-specs/REQ.md\` — 需求 + 验收标准\n`;
1790
- ctx += `3. \`Iteration-*/${task.id}/00-specs/TECH.md\` — 技术设计\n`;
1791
- ctx += `4. \`Iteration-*/${task.id}/_shared/API_CONTRACT.yaml\` — API 契约 (if exists)\n\n`;
1797
+ if (taskRoot) {
1798
+ const taskMdPath = isSubtask ? (0, path_1.join)(subtaskDir, 'TASK.md') : (0, path_1.join)(taskRoot, '_shared', 'TASK.md');
1799
+ ctx += `1. \`${taskMdPath}\` — 子任务概览(所有端平铺)\n`;
1800
+ ctx += `2. \`${(0, path_1.join)(taskRoot, '00-specs', 'REQ.md')}\` — 需求 + 验收标准\n`;
1801
+ ctx += `3. \`${(0, path_1.join)(taskRoot, '00-specs', 'TECH.md')}\` — 技术设计\n`;
1802
+ ctx += `4. \`${(0, path_1.join)(taskRoot, '_shared', 'API_CONTRACT.yaml')}\` — API 契约 (if exists)\n`;
1803
+ ctx += `5. \`${(0, path_1.join)(subtaskDir, 'REQ.md')}\` / \`${(0, path_1.join)(subtaskDir, 'TECH.md')}\` — 本端子任务规格(骨架,待 Step 2.5 覆盖)\n\n`;
1804
+ }
1805
+ else {
1806
+ ctx += `1. \`Iteration-*/${task.id}/{platform}/{subtask}/TASK.md\` — 子任务概览(所有端平铺)\n`;
1807
+ ctx += `2. \`Iteration-*/${task.id}/00-specs/REQ.md\` — 需求 + 验收标准\n`;
1808
+ ctx += `3. \`Iteration-*/${task.id}/00-specs/TECH.md\` — 技术设计\n`;
1809
+ ctx += `4. \`Iteration-*/${task.id}/_shared/API_CONTRACT.yaml\` — API 契约 (if exists)\n\n`;
1810
+ }
1792
1811
  ctx += `**Supplementary (read only if needed):**\n`;
1793
1812
  ctx += `- 子任务目录/TEST.md (测试用例) | 子任务目录/REVIEW.md (评审清单)\n`;
1794
1813
  ctx += `- 00-specs/SCHEMA.md (DB schema) | 子任务目录/ADR.md (架构决策)\n`;
@@ -1804,6 +1823,7 @@ function buildAgentContext(tasks, agent) {
1804
1823
  ctx += `- [ ] 已阅读 00-specs/REQ.md,理解需求和验收标准\n`;
1805
1824
  ctx += `- [ ] 已阅读 00-specs/TECH.md,理解技术方案\n`;
1806
1825
  ctx += `- [ ] 用 Write 覆盖本端子任务目录下预建的 REQ.md/TECH.md 骨架(含 SKELETON_MARKER 标记的文件),写出本端的专业规格,不得遗留骨架占位符\n`;
1826
+ ctx += `- [ ] 前端端覆盖 STATE.md/ROUTES.md/COMPONENT_TREE.md/STYLE_GUIDE.md 骨架(含 _待AI分析_ 占位或 AI-FILL 注释的文件),按实际设计填充状态结构/路由表/组件树/样式指南(v8.3.282+)\n`;
1807
1827
  ctx += `- [ ] 代码实现严格遵循 REQ.md 的验收标准和 TECH.md 的技术方案\n`;
1808
1828
  ctx += `- [ ] 如涉及 API 变更,确保前后端接口签名一致\n`;
1809
1829
  ctx += `- [ ] 完成后更新 TASK.md 状态(doing → done)\n\n`;
@@ -2480,6 +2500,9 @@ async function runPromptMode(iteration, options) {
2480
2500
  return;
2481
2501
  logger_1.logger.warn('⚠️ [llm] 自配 LLM 未生成代码,回退宿主模式');
2482
2502
  }
2503
+ // v8.3.281+: SDK 派单降级原因记录——此前仅 warn 到 stderr,外层 AI 主读 stdout 看不到,
2504
+ // 误以为派单成功,导致 prompt 无人消费(exitCode 10 死锁)。现将原因上主通道。
2505
+ let sdkFallbackReason = null;
2483
2506
  // v8.3.169+: 尝试通过 Qoder SDK 直接调度子 Agent(Qoder 环境且非 TTY 模式)
2484
2507
  if (!process.stdout.isTTY) {
2485
2508
  try {
@@ -2523,20 +2546,38 @@ async function runPromptMode(iteration, options) {
2523
2546
  process.exitCode = 0;
2524
2547
  return;
2525
2548
  }
2549
+ if (!dispatchResult) {
2550
+ // dispatchSubagent 返回 null:非 Qoder 宿主 / SDK 依赖缺失 / 鉴权未配置
2551
+ sdkFallbackReason = 'Qoder SDK 直连通道不可用(非 Qoder 宿主 / SDK 依赖缺失 / 鉴权未配置),已降级为标记模式';
2552
+ }
2553
+ else {
2554
+ sdkFallbackReason = dispatchResult.error
2555
+ ? `子 Agent 执行失败: ${dispatchResult.error}`
2556
+ : '子 Agent 执行失败(原因见上方日志),已降级为标记模式';
2557
+ }
2526
2558
  // 宿主 SDK 调度失败(success=false)→ auto 时回退自配 LLM
2527
2559
  if (aiProvider === 'auto' && await tryLlmExecute())
2528
2560
  return;
2529
2561
  }
2530
2562
  catch (e) {
2531
2563
  logger_1.logger.debug(`[execute] SDK 调度尝试失败: ${e.message}`);
2564
+ sdkFallbackReason = `SDK 调度异常: ${e.message}`;
2532
2565
  // 宿主异常 → auto 时回退自配 LLM
2533
2566
  if (aiProvider === 'auto' && await tryLlmExecute())
2534
2567
  return;
2535
2568
  }
2536
2569
  }
2570
+ else {
2571
+ sdkFallbackReason = '终端交互模式(TTY):SDK 自动派单仅在宿主 AI 子进程调用(非 TTY)时触发,建议由 AI 助手代为执行本命令';
2572
+ }
2537
2573
  // 输出到 stdout(Skill 通过 execute_command 捕获)
2538
2574
  // v8.3.166+: 在 prompt 前输出 subagent 标记
2575
+ // v8.3.281+: 降级原因上主通道,外层 AI 必读,防止 prompt 无人消费的 exitCode 10 死锁
2576
+ const fallbackHeader = sdkFallbackReason
2577
+ ? `[SPECCORE_SDK_FALLBACK] ${sdkFallbackReason}\n→ 请按下方 prompt 生成代码,完成后用 speccore execute --apply / --response 落盘\n\n`
2578
+ : '';
2539
2579
  const finalOutput = [
2580
+ fallbackHeader,
2540
2581
  `[SPECCORE_SESSION_AGENT: ${platformSubagent}]`,
2541
2582
  `[SPECCORE_CONTEXT_BUDGET: 12000]`,
2542
2583
  `[SPECCORE_CONTEXT_TYPE: ${options.platform ? 'platform-only' : 'full'}]`,