speccore 8.3.333 → 8.3.341

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 (309) hide show
  1. package/.agents/skills/spec-ask/SKILL.md +4 -0
  2. package/.agents/skills/spec-unitize/SKILL.md +9 -1
  3. package/.agents/skills/speccore-router/SKILL.md +12 -11
  4. package/README.en.md +3 -11
  5. package/README.md +3 -13
  6. package/dist/cli.js +64 -206
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands/analyze.d.ts.map +1 -1
  9. package/dist/commands/analyze.js +530 -481
  10. package/dist/commands/analyze.js.map +1 -1
  11. package/dist/commands/ask.d.ts.map +1 -1
  12. package/dist/commands/ask.js +6 -0
  13. package/dist/commands/ask.js.map +1 -1
  14. package/dist/commands/completion.d.ts.map +1 -1
  15. package/dist/commands/completion.js +9 -7
  16. package/dist/commands/completion.js.map +1 -1
  17. package/dist/commands/doc2spec.d.ts +44 -1
  18. package/dist/commands/doc2spec.d.ts.map +1 -1
  19. package/dist/commands/doc2spec.js +257 -5
  20. package/dist/commands/doc2spec.js.map +1 -1
  21. package/dist/commands/doctor.js +3 -3
  22. package/dist/commands/doctor.js.map +1 -1
  23. package/dist/commands/done.js +1 -5
  24. package/dist/commands/done.js.map +1 -1
  25. package/dist/commands/execute.js +118 -66
  26. package/dist/commands/execute.js.map +1 -1
  27. package/dist/commands/help.js +6 -54
  28. package/dist/commands/help.js.map +1 -1
  29. package/dist/commands/init.d.ts.map +1 -1
  30. package/dist/commands/init.js +71 -47
  31. package/dist/commands/init.js.map +1 -1
  32. package/dist/commands/iteration/create.d.ts.map +1 -1
  33. package/dist/commands/iteration/create.js +72 -10
  34. package/dist/commands/iteration/create.js.map +1 -1
  35. package/dist/commands/iteration/taskify.d.ts.map +1 -1
  36. package/dist/commands/iteration/taskify.js +133 -35
  37. package/dist/commands/iteration/taskify.js.map +1 -1
  38. package/dist/commands/pr.d.ts.map +1 -1
  39. package/dist/commands/pr.js +24 -2
  40. package/dist/commands/pr.js.map +1 -1
  41. package/dist/commands/prompts.d.ts +6 -0
  42. package/dist/commands/prompts.d.ts.map +1 -1
  43. package/dist/commands/prompts.js +19 -10
  44. package/dist/commands/prompts.js.map +1 -1
  45. package/dist/commands/search.js +1 -1
  46. package/dist/commands/search.js.map +1 -1
  47. package/dist/commands/status-panel.d.ts.map +1 -1
  48. package/dist/commands/status-panel.js +23 -34
  49. package/dist/commands/status-panel.js.map +1 -1
  50. package/dist/commands/unitize.d.ts +3 -0
  51. package/dist/commands/unitize.d.ts.map +1 -1
  52. package/dist/commands/unitize.js +32 -9
  53. package/dist/commands/unitize.js.map +1 -1
  54. package/dist/commands/update-env-configs.d.ts.map +1 -1
  55. package/dist/commands/update-env-configs.js +2 -1
  56. package/dist/commands/update-env-configs.js.map +1 -1
  57. package/dist/commands/update.d.ts +4 -0
  58. package/dist/commands/update.d.ts.map +1 -1
  59. package/dist/commands/update.js +41 -1
  60. package/dist/commands/update.js.map +1 -1
  61. package/dist/commands/welcome.d.ts.map +1 -1
  62. package/dist/commands/welcome.js +41 -0
  63. package/dist/commands/welcome.js.map +1 -1
  64. package/dist/core/analyze-engine.js +3 -3
  65. package/dist/core/analyze-engine.js.map +1 -1
  66. package/dist/core/arbitration/l3-human-arbiter.js +1 -1
  67. package/dist/core/arbitration/l3-human-arbiter.js.map +1 -1
  68. package/dist/core/arbitration/verdict-generator.js +1 -1
  69. package/dist/core/arbitration/verdict-generator.js.map +1 -1
  70. package/dist/core/ask-context.d.ts.map +1 -1
  71. package/dist/core/ask-context.js +14 -3
  72. package/dist/core/ask-context.js.map +1 -1
  73. package/dist/core/ask-engine.d.ts.map +1 -1
  74. package/dist/core/ask-engine.js +55 -49
  75. package/dist/core/ask-engine.js.map +1 -1
  76. package/dist/core/code-graph/reporter.d.ts.map +1 -1
  77. package/dist/core/code-graph/reporter.js +3 -12
  78. package/dist/core/code-graph/reporter.js.map +1 -1
  79. package/dist/core/code-graph/requirement-linker.js +1 -1
  80. package/dist/core/code-graph/requirement-linker.js.map +1 -1
  81. package/dist/core/code-scanner.js +1 -1
  82. package/dist/core/code-scanner.js.map +1 -1
  83. package/dist/core/deploy/engine.d.ts.map +1 -1
  84. package/dist/core/deploy/engine.js +58 -44
  85. package/dist/core/deploy/engine.js.map +1 -1
  86. package/dist/core/environment-config.d.ts +13 -0
  87. package/dist/core/environment-config.d.ts.map +1 -1
  88. package/dist/core/environment-config.js +28 -1
  89. package/dist/core/environment-config.js.map +1 -1
  90. package/dist/core/error-diagnosis.js +2 -2
  91. package/dist/core/error-diagnosis.js.map +1 -1
  92. package/dist/core/git-integration.d.ts +5 -7
  93. package/dist/core/git-integration.d.ts.map +1 -1
  94. package/dist/core/git-integration.js +137 -12
  95. package/dist/core/git-integration.js.map +1 -1
  96. package/dist/core/global-knowledge.d.ts.map +1 -1
  97. package/dist/core/global-knowledge.js +25 -11
  98. package/dist/core/global-knowledge.js.map +1 -1
  99. package/dist/core/handoff-generator.d.ts.map +1 -1
  100. package/dist/core/handoff-generator.js +3 -1
  101. package/dist/core/handoff-generator.js.map +1 -1
  102. package/dist/core/index-guard.d.ts.map +1 -1
  103. package/dist/core/index-guard.js +4 -26
  104. package/dist/core/index-guard.js.map +1 -1
  105. package/dist/core/intent-recognition.d.ts +1 -1
  106. package/dist/core/intent-recognition.d.ts.map +1 -1
  107. package/dist/core/intent-recognition.js +68 -68
  108. package/dist/core/intent-recognition.js.map +1 -1
  109. package/dist/core/knowledge-graph.d.ts.map +1 -1
  110. package/dist/core/knowledge-graph.js +6 -4
  111. package/dist/core/knowledge-graph.js.map +1 -1
  112. package/dist/core/name-validator.d.ts.map +1 -1
  113. package/dist/core/name-validator.js +41 -20
  114. package/dist/core/name-validator.js.map +1 -1
  115. package/dist/core/pinyin-initials.d.ts +10 -0
  116. package/dist/core/pinyin-initials.d.ts.map +1 -0
  117. package/dist/core/pinyin-initials.js +44 -0
  118. package/dist/core/pinyin-initials.js.map +1 -0
  119. package/dist/core/prompt-builder.js +1 -1
  120. package/dist/core/prompt-builder.js.map +1 -1
  121. package/dist/core/prompt-plugins/analyze-graph-plugin.js +1 -1
  122. package/dist/core/prompt-plugins/analyze-graph-plugin.js.map +1 -1
  123. package/dist/core/reindex-engine.js +4 -4
  124. package/dist/core/reindex-engine.js.map +1 -1
  125. package/dist/core/skeleton-residue.d.ts +13 -0
  126. package/dist/core/skeleton-residue.d.ts.map +1 -1
  127. package/dist/core/skeleton-residue.js +83 -14
  128. package/dist/core/skeleton-residue.js.map +1 -1
  129. package/dist/core/spec-merger.d.ts.map +1 -1
  130. package/dist/core/spec-merger.js +3 -2
  131. package/dist/core/spec-merger.js.map +1 -1
  132. package/dist/core/state.d.ts +10 -0
  133. package/dist/core/state.d.ts.map +1 -1
  134. package/dist/core/state.js +20 -1
  135. package/dist/core/state.js.map +1 -1
  136. package/dist/core/structured-extractor.d.ts +6 -0
  137. package/dist/core/structured-extractor.d.ts.map +1 -1
  138. package/dist/core/structured-extractor.js +6 -0
  139. package/dist/core/structured-extractor.js.map +1 -1
  140. package/dist/core/task-paths.d.ts +12 -0
  141. package/dist/core/task-paths.d.ts.map +1 -1
  142. package/dist/core/task-paths.js +33 -1
  143. package/dist/core/task-paths.js.map +1 -1
  144. package/dist/core/unified-config.d.ts +7 -1
  145. package/dist/core/unified-config.d.ts.map +1 -1
  146. package/dist/core/unified-config.js +70 -21
  147. package/dist/core/unified-config.js.map +1 -1
  148. package/dist/core/unit-staffing.d.ts +21 -4
  149. package/dist/core/unit-staffing.d.ts.map +1 -1
  150. package/dist/core/unit-staffing.js +59 -12
  151. package/dist/core/unit-staffing.js.map +1 -1
  152. package/dist/core/usage-analytics.js +1 -1
  153. package/dist/core/usage-analytics.js.map +1 -1
  154. package/dist/core/validator.d.ts.map +1 -1
  155. package/dist/core/validator.js +45 -5
  156. package/dist/core/validator.js.map +1 -1
  157. package/dist/core/verify-report-aggregator.d.ts.map +1 -1
  158. package/dist/core/verify-report-aggregator.js +19 -2
  159. package/dist/core/verify-report-aggregator.js.map +1 -1
  160. package/dist/utils/task-utils.d.ts +4 -1
  161. package/dist/utils/task-utils.d.ts.map +1 -1
  162. package/dist/utils/task-utils.js +30 -4
  163. package/dist/utils/task-utils.js.map +1 -1
  164. package/package.json +4 -3
  165. package/templates/deploy-examples.yaml +33 -5
  166. package/templates/html/speccore-ask-explain.html +1 -1
  167. package/templates/html/speccore-ask-guide.html +1 -1
  168. package/templates/html/speccore-ask-match.html +1 -1
  169. package/templates/html/speccore-ask-pipeline.html +1 -1
  170. package/templates/html/speccore-ask-result.html +1 -1
  171. package/templates/html/speccore-help.html +2 -2
  172. package/templates/speccore-yml-example.yml +174 -54
  173. package/templates/verify-spec-example.yaml +66 -1
  174. package/dist/commands/audit.d.ts +0 -12
  175. package/dist/commands/audit.d.ts.map +0 -1
  176. package/dist/commands/audit.js +0 -540
  177. package/dist/commands/audit.js.map +0 -1
  178. package/dist/commands/backup.d.ts +0 -18
  179. package/dist/commands/backup.d.ts.map +0 -1
  180. package/dist/commands/backup.js +0 -102
  181. package/dist/commands/backup.js.map +0 -1
  182. package/dist/commands/baseline.d.ts +0 -13
  183. package/dist/commands/baseline.d.ts.map +0 -1
  184. package/dist/commands/baseline.js +0 -227
  185. package/dist/commands/baseline.js.map +0 -1
  186. package/dist/commands/chain.d.ts +0 -55
  187. package/dist/commands/chain.d.ts.map +0 -1
  188. package/dist/commands/chain.js +0 -501
  189. package/dist/commands/chain.js.map +0 -1
  190. package/dist/commands/clarify.d.ts +0 -17
  191. package/dist/commands/clarify.d.ts.map +0 -1
  192. package/dist/commands/clarify.js +0 -351
  193. package/dist/commands/clarify.js.map +0 -1
  194. package/dist/commands/code-index.d.ts +0 -21
  195. package/dist/commands/code-index.d.ts.map +0 -1
  196. package/dist/commands/code-index.js +0 -193
  197. package/dist/commands/code-index.js.map +0 -1
  198. package/dist/commands/context.d.ts +0 -10
  199. package/dist/commands/context.d.ts.map +0 -1
  200. package/dist/commands/context.js +0 -213
  201. package/dist/commands/context.js.map +0 -1
  202. package/dist/commands/current.d.ts +0 -10
  203. package/dist/commands/current.d.ts.map +0 -1
  204. package/dist/commands/current.js +0 -53
  205. package/dist/commands/current.js.map +0 -1
  206. package/dist/commands/dev.d.ts +0 -18
  207. package/dist/commands/dev.d.ts.map +0 -1
  208. package/dist/commands/dev.js +0 -854
  209. package/dist/commands/dev.js.map +0 -1
  210. package/dist/commands/diff.d.ts +0 -10
  211. package/dist/commands/diff.d.ts.map +0 -1
  212. package/dist/commands/diff.js +0 -160
  213. package/dist/commands/diff.js.map +0 -1
  214. package/dist/commands/global-status.d.ts +0 -9
  215. package/dist/commands/global-status.d.ts.map +0 -1
  216. package/dist/commands/global-status.js +0 -135
  217. package/dist/commands/global-status.js.map +0 -1
  218. package/dist/commands/graph.d.ts +0 -25
  219. package/dist/commands/graph.d.ts.map +0 -1
  220. package/dist/commands/graph.js +0 -523
  221. package/dist/commands/graph.js.map +0 -1
  222. package/dist/commands/handover.d.ts +0 -11
  223. package/dist/commands/handover.d.ts.map +0 -1
  224. package/dist/commands/handover.js +0 -170
  225. package/dist/commands/handover.js.map +0 -1
  226. package/dist/commands/health.d.ts +0 -7
  227. package/dist/commands/health.d.ts.map +0 -1
  228. package/dist/commands/health.js +0 -80
  229. package/dist/commands/health.js.map +0 -1
  230. package/dist/commands/history.d.ts +0 -9
  231. package/dist/commands/history.d.ts.map +0 -1
  232. package/dist/commands/history.js +0 -117
  233. package/dist/commands/history.js.map +0 -1
  234. package/dist/commands/impact.d.ts +0 -12
  235. package/dist/commands/impact.d.ts.map +0 -1
  236. package/dist/commands/impact.js +0 -238
  237. package/dist/commands/impact.js.map +0 -1
  238. package/dist/commands/import.d.ts +0 -19
  239. package/dist/commands/import.d.ts.map +0 -1
  240. package/dist/commands/import.js +0 -673
  241. package/dist/commands/import.js.map +0 -1
  242. package/dist/commands/knowledge.d.ts +0 -6
  243. package/dist/commands/knowledge.d.ts.map +0 -1
  244. package/dist/commands/knowledge.js +0 -94
  245. package/dist/commands/knowledge.js.map +0 -1
  246. package/dist/commands/lifecycle.d.ts +0 -9
  247. package/dist/commands/lifecycle.d.ts.map +0 -1
  248. package/dist/commands/lifecycle.js +0 -288
  249. package/dist/commands/lifecycle.js.map +0 -1
  250. package/dist/commands/merge-check.d.ts +0 -10
  251. package/dist/commands/merge-check.d.ts.map +0 -1
  252. package/dist/commands/merge-check.js +0 -183
  253. package/dist/commands/merge-check.js.map +0 -1
  254. package/dist/commands/notify.d.ts +0 -13
  255. package/dist/commands/notify.d.ts.map +0 -1
  256. package/dist/commands/notify.js +0 -63
  257. package/dist/commands/notify.js.map +0 -1
  258. package/dist/commands/rag-index.d.ts +0 -19
  259. package/dist/commands/rag-index.d.ts.map +0 -1
  260. package/dist/commands/rag-index.js +0 -286
  261. package/dist/commands/rag-index.js.map +0 -1
  262. package/dist/commands/recommend.d.ts +0 -13
  263. package/dist/commands/recommend.d.ts.map +0 -1
  264. package/dist/commands/recommend.js +0 -37
  265. package/dist/commands/recommend.js.map +0 -1
  266. package/dist/commands/refresh.d.ts +0 -21
  267. package/dist/commands/refresh.d.ts.map +0 -1
  268. package/dist/commands/refresh.js +0 -211
  269. package/dist/commands/refresh.js.map +0 -1
  270. package/dist/commands/rollback.d.ts +0 -8
  271. package/dist/commands/rollback.d.ts.map +0 -1
  272. package/dist/commands/rollback.js +0 -113
  273. package/dist/commands/rollback.js.map +0 -1
  274. package/dist/commands/status.d.ts +0 -7
  275. package/dist/commands/status.d.ts.map +0 -1
  276. package/dist/commands/status.js +0 -262
  277. package/dist/commands/status.js.map +0 -1
  278. package/dist/commands/trace.d.ts +0 -12
  279. package/dist/commands/trace.d.ts.map +0 -1
  280. package/dist/commands/trace.js +0 -163
  281. package/dist/commands/trace.js.map +0 -1
  282. package/dist/commands/tracker.d.ts +0 -2
  283. package/dist/commands/tracker.d.ts.map +0 -1
  284. package/dist/commands/tracker.js +0 -28
  285. package/dist/commands/tracker.js.map +0 -1
  286. package/dist/commands/verdict.d.ts +0 -16
  287. package/dist/commands/verdict.d.ts.map +0 -1
  288. package/dist/commands/verdict.js +0 -189
  289. package/dist/commands/verdict.js.map +0 -1
  290. package/dist/commands/workspace.d.ts +0 -20
  291. package/dist/commands/workspace.d.ts.map +0 -1
  292. package/dist/commands/workspace.js +0 -142
  293. package/dist/commands/workspace.js.map +0 -1
  294. package/dist/core/constraint-set.d.ts +0 -67
  295. package/dist/core/constraint-set.d.ts.map +0 -1
  296. package/dist/core/constraint-set.js +0 -151
  297. package/dist/core/constraint-set.js.map +0 -1
  298. package/dist/core/smart-recommend.d.ts +0 -16
  299. package/dist/core/smart-recommend.d.ts.map +0 -1
  300. package/dist/core/smart-recommend.js +0 -149
  301. package/dist/core/smart-recommend.js.map +0 -1
  302. package/dist/core/task-type-registry.d.ts +0 -110
  303. package/dist/core/task-type-registry.d.ts.map +0 -1
  304. package/dist/core/task-type-registry.js +0 -334
  305. package/dist/core/task-type-registry.js.map +0 -1
  306. package/dist/utils/mermaid-render.d.ts +0 -39
  307. package/dist/utils/mermaid-render.d.ts.map +0 -1
  308. package/dist/utils/mermaid-render.js +0 -284
  309. package/dist/utils/mermaid-render.js.map +0 -1
@@ -48,6 +48,8 @@ const readline_1 = require("readline");
48
48
  const prompt_builder_1 = require("../../core/prompt-builder");
49
49
  const index_guard_1 = require("../../core/index-guard");
50
50
  const spec_paths_1 = require("../../core/spec-paths");
51
+ const task_paths_1 = require("../../core/task-paths");
52
+ const unit_staffing_1 = require("../../core/unit-staffing");
51
53
  const spec_skeleton_1 = require("../../core/spec-skeleton");
52
54
  const questions_1 = require("../../core/questions");
53
55
  const pipeline_engine_1 = require("../../core/pipeline-engine");
@@ -232,14 +234,26 @@ function buildTaskTopic(sec, taskType) {
232
234
  return (0, global_counters_1.toSlug)(sec.name);
233
235
  }
234
236
  /**
235
- * 生成子任务全局唯一 ID
236
- * 格式: Task-{父任务尾段}-{端名}
237
- * 例: Task-033-login-flow-booking-service(父任务 ID Task-033-login-flow 去 Task- 前缀后接端名)
237
+ * v8.3.337+: 解析模块目录名——功能单元目录名直接对齐(与 features/、020-specs/ 一致),
238
+ * 去掉 Task-NNN 计数器序号。非目录名格式(自创英文名/中文名)返回空,回退原 topic 链。
239
+ * 目录名格式校验:小写字母/数字/连字符组成(功能单元命名 v8.3.271+ 契约)。
238
240
  */
239
- function generateSubtaskId(parentTaskId, platform) {
240
- // v6.49.5+ / v8.3.10+:确定性格式 {taskId}-{platform},保证全项目唯一
241
- // 因为每个任务每个端只有一个子任务,所以 {taskId}-{platform} 已经唯一
242
- return `Task-${parentTaskId}-${platform}`;
241
+ function resolveModuleDirName(sec) {
242
+ const functionalUnit = sec?.functionalUnit || '';
243
+ if (functionalUnit && /^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(functionalUnit)) {
244
+ return functionalUnit;
245
+ }
246
+ return '';
247
+ }
248
+ /**
249
+ * 生成子任务目录名(v8.3.337+ 改造)
250
+ * 格式: Task-{模块名}——与模块目录名(功能单元名)一致,不再拼端名。
251
+ * 端名已由目录层级承载({模块}/{端}/{子任务}),拼入子任务 ID 是冗余;
252
+ * 多端同名子任务分处不同端目录无目录冲突,Git 分支重名由 createTaskBranch hash 兜底。
253
+ * 例: 模块 admin-web-01-yudingguanli → 子任务 Task-admin-web-01-yudingguanli
254
+ */
255
+ function generateSubtaskId(moduleDirName) {
256
+ return `Task-${moduleDirName}`;
243
257
  }
244
258
  /** 拆分约束常量(简化版:每个功能单元按涉及的端拆分,每端1个子任务) */
245
259
  const SPLIT_RULES = {
@@ -1084,9 +1098,15 @@ async function iterationTaskifyCommand(options) {
1084
1098
  const aiIdToTaskId = new Map();
1085
1099
  for (const sec of sections) {
1086
1100
  // v8.3.294+: bugfix 任务目录名拼「模块英文-内容英文」,其余类型保持原链
1101
+ // v8.3.337+: 模块目录名优先对齐功能单元目录名(无计数器),非目录名回退原链
1087
1102
  const taskType = sec._taskType || 'feature';
1088
1103
  const taskTopic = buildTaskTopic(sec, taskType);
1089
- const { id: taskId } = await (0, global_counters_1.nextTaskId)(sec.name, taskTopic);
1104
+ const moduleName = resolveModuleDirName(sec);
1105
+ let taskId;
1106
+ if (moduleName)
1107
+ taskId = moduleName;
1108
+ else
1109
+ taskId = (await (0, global_counters_1.nextTaskId)(sec.name, taskTopic)).id;
1090
1110
  sec._taskId = taskId;
1091
1111
  const aiId = sec._aiId;
1092
1112
  if (aiId)
@@ -1533,12 +1553,17 @@ async function iterationTaskifyCommand(options) {
1533
1553
  }
1534
1554
  logger_1.logger.info(`Found ${sections.length} sections to split`);
1535
1555
  logger_1.logger.info(`Platforms: ${platforms.join(', ')}`);
1536
- // ── 预分配任务 ID(确保所有路径使用计数器,避免编号重复) ──
1556
+ // ── 预分配任务 ID(v8.3.337+: 模块目录名优先对齐功能单元目录名)──
1537
1557
  for (const section of sections) {
1538
1558
  // v8.3.294+: bugfix 任务目录名拼「模块英文-内容英文」,其余类型保持原链
1539
1559
  const taskType = section._taskType || 'feature';
1540
1560
  const topic = buildTaskTopic(section, taskType);
1541
- const { id: taskId } = await (0, global_counters_1.nextTaskId)(section.name, topic);
1561
+ const moduleName = resolveModuleDirName(section);
1562
+ let taskId;
1563
+ if (moduleName)
1564
+ taskId = moduleName;
1565
+ else
1566
+ taskId = (await (0, global_counters_1.nextTaskId)(section.name, topic)).id;
1542
1567
  section._taskId = taskId;
1543
1568
  }
1544
1569
  // ── Strict mode: preview + confirm each task's split plan ──
@@ -1959,11 +1984,11 @@ async function createTaskFromSection(iterationDir, taskId, section, allPlatforms
1959
1984
  logger_1.logger.warn(` ⚠️ 未找到 020-specs/ 分析文档,任务级 REQ.md/TECH.md 将生成空模板`);
1960
1985
  logger_1.logger.warn(` 建议先运行: speccore analyze -I ${iterationName} --auto`);
1961
1986
  }
1962
- // 预生成所有端的子任务 ID(保证同一端在所有文件中 ID 一致)
1987
+ // 预生成所有端的子任务 ID(子任务名 = Task-{模块名},不拼端名)
1963
1988
  const taskNum = taskId.replace(/^Task-/, '');
1964
1989
  const subtaskIdMap = new Map();
1965
1990
  for (const p of taskPlatforms) {
1966
- subtaskIdMap.set(p, generateSubtaskId(taskNum, p));
1991
+ subtaskIdMap.set(p, generateSubtaskId(taskNum));
1967
1992
  }
1968
1993
  // ── 1. 任务目录指引(功能模块分组) ──
1969
1994
  await (0, fs_extra_1.ensureDir)(taskDir);
@@ -2565,7 +2590,7 @@ ${!isBk && docSet.hasComponentTree ? '| COMPONENT_TREE.md | ⏳ | ./COMPONENT_TR
2565
2590
  // 从端列表查找第一个后端端名作为 fallback(v6.48.0+)
2566
2591
  const allPlatforms = await (0, spec_paths_1.parsePlatformList)();
2567
2592
  const fallbackBackend = allPlatforms.find(p => p === 'backend' || p.startsWith('后台') || /-(service|api|server|backend)$/i.test(p)) || 'backend';
2568
- const fallbackSubtaskId = subtaskIdMap.get(fallbackBackend) || generateSubtaskId(taskNum, fallbackBackend);
2593
+ const fallbackSubtaskId = subtaskIdMap.get(fallbackBackend) || generateSubtaskId(taskNum);
2569
2594
  const autoSubtaskDir = (0, path_1.join)(taskDir, fallbackBackend, fallbackSubtaskId);
2570
2595
  await (0, fs_extra_1.ensureDir)((0, path_1.join)(autoSubtaskDir, '.meta'));
2571
2596
  await (0, fs_extra_1.writeFile)((0, path_1.join)(autoSubtaskDir, '.meta', 'type'), taskType);
@@ -2585,7 +2610,7 @@ ${!isBk && docSet.hasComponentTree ? '| COMPONENT_TREE.md | ⏳ | ./COMPONENT_TR
2585
2610
  await (0, fs_extra_1.writeFile)((0, path_1.join)(autoSubtaskDir, 'TASK.md'), `# ${section.name} — ${fallbackBackend}(自动补充)
2586
2611
 
2587
2612
  ## 子任务信息
2588
- - **子任务 ID**: \`${taskId}-${fallbackBackend}-auto\`
2613
+ - **子任务 ID**: \`${fallbackSubtaskId}-auto\`
2589
2614
  - **所属模块**: \`${taskId}\`
2590
2615
  - **功能单元**: ${featureName}
2591
2616
  - **端**: ${fallbackBackend}
@@ -2608,7 +2633,8 @@ ${!isBk && docSet.hasComponentTree ? '| COMPONENT_TREE.md | ⏳ | ./COMPONENT_TR
2608
2633
  if (docSet.hasMonitor)
2609
2634
  await (0, fs_extra_1.writeFile)((0, path_1.join)(autoSubtaskDir, 'MONITOR.md'), generateMonitorTemplate(section, monitorMaterial));
2610
2635
  taskPlatforms.push(fallbackBackend);
2611
- subtaskIdMap.set(fallbackBackend, `${taskId}-${fallbackBackend}-auto`);
2636
+ // 自动补充的后端子任务名也遵循 Task-{模块名}-auto(后缀区分自动补充来源)
2637
+ subtaskIdMap.set(fallbackBackend, `${fallbackSubtaskId}-auto`);
2612
2638
  }
2613
2639
  // ─ 5. 任务上下文 CONTEXT.md ─
2614
2640
  const sourceFile = section._sourceFile || '';
@@ -4131,6 +4157,8 @@ function readStaffing(iterationDir) {
4131
4157
  name: m.name,
4132
4158
  platforms: m.directions,
4133
4159
  capacity: m.capacity,
4160
+ roles: m.roles,
4161
+ initials: m.initials,
4134
4162
  }));
4135
4163
  return members.length > 0 ? members : null;
4136
4164
  }
@@ -4163,25 +4191,86 @@ async function resolveUnitOwnerFromMatrix(iterationDir, sectionName, platform) {
4163
4191
  return undefined;
4164
4192
  }
4165
4193
  /**
4166
- * 根据平台和负荷自动推荐负责人
4194
+ * 端名 → 需求岗位映射(v8.3.337+):按端名关键词推断技术岗位维度。
4195
+ * 用于 autoAssign 双维匹配——岗位(技术栈维度)+ 方向(业务端维度)正交筛选。
4196
+ */
4197
+ function platformToRoles(platform) {
4198
+ const p = platform.toLowerCase();
4199
+ const roles = [];
4200
+ if (/web|admin|h5|frontend|pc|小程序/.test(p))
4201
+ roles.push('web');
4202
+ if (/service|api|server|backend|后台/.test(p))
4203
+ roles.push('后端');
4204
+ if (/app|mobile|移动|android|ios/.test(p))
4205
+ roles.push('移动端');
4206
+ return roles;
4207
+ }
4208
+ /** 岗位别名归一(成员表自由填写:web/前端、后端/服务端、移动端/APP 同义) */
4209
+ const ROLE_ALIASES = {
4210
+ 'web': ['前端', 'frontend'],
4211
+ '后端': ['backend', '服务端', 'server'],
4212
+ '移动端': ['mobile', 'app'],
4213
+ };
4214
+ /** 成员岗位是否命中任务所需岗位之一(v8.3.339+: 通配成员恒命中) */
4215
+ function memberRoleMatches(memberRoles, needRoles) {
4216
+ if (needRoles.length === 0 || memberRoles.length === 0)
4217
+ return false;
4218
+ if (memberRoles.includes(unit_staffing_1.WILDCARD))
4219
+ return true; // 全栈成员岗位恒命中
4220
+ for (const need of needRoles) {
4221
+ const n = need.toLowerCase();
4222
+ const aliases = ROLE_ALIASES[n] ?? [];
4223
+ for (const r of memberRoles) {
4224
+ const rl = r.toLowerCase();
4225
+ if (rl === n || rl.includes(n) || n.includes(rl))
4226
+ return true;
4227
+ if (aliases.some((a) => rl.includes(a.toLowerCase()) || a.toLowerCase().includes(rl)))
4228
+ return true;
4229
+ }
4230
+ }
4231
+ return false;
4232
+ }
4233
+ /**
4234
+ * 根据平台和负荷自动推荐负责人(v8.3.337+ 双维匹配)
4235
+ *
4236
+ * 三级匹配(从严格到宽松,同级内取负荷最低者):
4237
+ * 1. 岗位+方向双命中(技术栈与业务端都对口)
4238
+ * 2. 仅方向命中(沿用 v8.3.319 语义)
4239
+ * 3. 仅岗位命中(方向未声明但技术栈对口)
4240
+ * 均无命中 → 未分配。已剔除「不在项目」成员(loadStaffing 过滤)。
4167
4241
  */
4168
4242
  function autoAssign(section, platforms, staffing) {
4169
4243
  const targetPlatform = section.platform || '';
4170
4244
  if (!targetPlatform || !staffing.length)
4171
4245
  return '未分配';
4172
- // 找到匹配平台的、负荷最低的人
4173
- let best = null;
4174
- let bestLoad = Infinity;
4175
- for (const m of staffing) {
4176
- if (m.capacity <= 0)
4177
- continue; // v8.3.319: 投入比例 0% = 本迭代不参与分配(如休假)
4178
- const platformMatch = m.platforms.some(p => targetPlatform.includes(p) || p.includes(targetPlatform));
4179
- if (platformMatch && m.capacity < bestLoad) {
4180
- best = m;
4181
- bestLoad = m.capacity;
4182
- }
4183
- }
4184
- return best ? best.name : '未分配';
4246
+ const needRoles = platformToRoles(targetPlatform);
4247
+ const pickLowest = (candidates) => {
4248
+ let best = null;
4249
+ let bestLoad = Infinity;
4250
+ for (const m of candidates) {
4251
+ if (m.capacity <= 0)
4252
+ continue; // v8.3.319: 投入比例 0% = 本迭代不参与分配(如休假)
4253
+ if (m.capacity < bestLoad) {
4254
+ best = m;
4255
+ bestLoad = m.capacity;
4256
+ }
4257
+ }
4258
+ return best;
4259
+ };
4260
+ const directionHit = (m) => m.platforms.includes(unit_staffing_1.WILDCARD) || // v8.3.339+: 通配方向恒命中(全栈成员兜底)
4261
+ m.platforms.some((p) => targetPlatform.includes(p) || p.includes(targetPlatform));
4262
+ const roleHit = (m) => memberRoleMatches(m.roles, needRoles);
4263
+ // 1. 岗位+方向双命中
4264
+ const dual = pickLowest(staffing.filter((m) => directionHit(m) && roleHit(m)));
4265
+ if (dual)
4266
+ return dual.name;
4267
+ // 2. 仅方向命中
4268
+ const dirOnly = pickLowest(staffing.filter(directionHit));
4269
+ if (dirOnly)
4270
+ return dirOnly.name;
4271
+ // 3. 仅岗位命中
4272
+ const roleOnly = pickLowest(staffing.filter(roleHit));
4273
+ return roleOnly ? roleOnly.name : '未分配';
4185
4274
  }
4186
4275
  /**
4187
4276
  * 分析章节复杂度,决定优先级和工时(简化版)
@@ -4249,24 +4338,27 @@ async function detectExistingTasks(iterDir) {
4249
4338
  // 优先从 030-tasks/ 扫描
4250
4339
  const scanDir = (0, path_1.join)(iterDir, '030-tasks');
4251
4340
  const targetDir = (await (0, fs_extra_1.pathExists)(scanDir)) ? scanDir : iterDir;
4252
- const scanRecursive = async (dir) => {
4341
+ // v8.3.337+: 新布局模块目录名=功能单元名(无 Task- 前缀),位于类型子目录直接层
4342
+ // (030-tasks/{type}/{模块})。depth ≤ 1 时按功能单元名识别为模块并停止深入,
4343
+ // 避免误把端目录/子任务目录当任务收集。旧布局 030-tasks/Task-* 仍按前缀识别。
4344
+ const scanRecursive = async (dir, depth) => {
4253
4345
  try {
4254
4346
  const entries = await (0, fs_extra_1.readdir)(dir, { withFileTypes: true });
4255
4347
  for (const e of entries) {
4256
4348
  if (e.isDirectory()) {
4257
- if (e.name.startsWith('Task-')) {
4349
+ if (e.name.startsWith('Task-') || (depth <= 1 && (0, task_paths_1.isTaskModuleDirName)(e.name))) {
4258
4350
  tasks.push(e.name);
4259
4351
  }
4260
4352
  else if (!e.name.startsWith('.')) {
4261
4353
  // 递归扫描类型子目录(feature/bugfix/refactor/research)
4262
- await scanRecursive((0, path_1.join)(dir, e.name));
4354
+ await scanRecursive((0, path_1.join)(dir, e.name), depth + 1);
4263
4355
  }
4264
4356
  }
4265
4357
  }
4266
4358
  }
4267
4359
  catch { }
4268
4360
  };
4269
- await scanRecursive(targetDir);
4361
+ await scanRecursive(targetDir, 0);
4270
4362
  return tasks;
4271
4363
  }
4272
4364
  /**
@@ -4294,7 +4386,8 @@ async function pruneTasksByModules(iterDir, modules) {
4294
4386
  if (!e.isDirectory())
4295
4387
  continue;
4296
4388
  const full = (0, path_1.join)(dir, e.name);
4297
- if (e.name.startsWith('Task-')) {
4389
+ // v8.3.337+: 新布局模块目录=功能单元名(无 Task- 前缀),同样按 .meta/feature 匹配
4390
+ if (e.name.startsWith('Task-') || (0, task_paths_1.isTaskModuleDirName)(e.name)) {
4298
4391
  let feature = '';
4299
4392
  try {
4300
4393
  feature = (await (0, fs_extra_1.readFile)((0, path_1.join)(full, '.meta', 'feature'), 'utf-8')).trim();
@@ -5054,7 +5147,12 @@ async function tryModuleDrivenSplit(iteration, iterationDir, options) {
5054
5147
  // 逐模块创建任务目录(按模块各自的涉及端)
5055
5148
  const createdSections = [];
5056
5149
  for (const mod of modules) {
5057
- const { id: taskId } = await (0, global_counters_1.nextTaskId)(mod.name, mod.slug);
5150
+ // v8.3.337+: 模块目录名优先对齐功能单元目录名(mod.name 即功能单元名)
5151
+ let taskId;
5152
+ if (mod.name && /^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(mod.name))
5153
+ taskId = mod.name;
5154
+ else
5155
+ taskId = (await (0, global_counters_1.nextTaskId)(mod.name, mod.slug)).id;
5058
5156
  const modPlatforms = mod.platforms.length > 0 ? mod.platforms : [...allPlatforms];
5059
5157
  // v8.3.249+: section.content 从 sourceFile(SOURCE.md 等)读取——此前硬编码空串,
5060
5158
  // 导致 REQ.md 四级回退全部落空(aiReq/analyzeReq/短 section.content 均不满足),