speccore 8.3.332 → 8.3.340
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.
- package/.agents/skills/spec-ask/SKILL.md +4 -0
- package/.agents/skills/spec-unitize/SKILL.md +9 -1
- package/.agents/skills/speccore-router/SKILL.md +12 -9
- package/dist/cli.js +63 -19
- package/dist/cli.js.map +1 -1
- package/dist/commands/ask.d.ts.map +1 -1
- package/dist/commands/ask.js +6 -0
- package/dist/commands/ask.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +10 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/doc2spec.d.ts +44 -1
- package/dist/commands/doc2spec.d.ts.map +1 -1
- package/dist/commands/doc2spec.js +257 -5
- package/dist/commands/doc2spec.js.map +1 -1
- package/dist/commands/execute.js +116 -64
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/help.js +1 -0
- package/dist/commands/help.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +71 -40
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/iteration/create.d.ts.map +1 -1
- package/dist/commands/iteration/create.js +72 -10
- package/dist/commands/iteration/create.js.map +1 -1
- package/dist/commands/iteration/taskify.d.ts.map +1 -1
- package/dist/commands/iteration/taskify.js +133 -35
- package/dist/commands/iteration/taskify.js.map +1 -1
- package/dist/commands/pr.d.ts.map +1 -1
- package/dist/commands/pr.js +26 -2
- package/dist/commands/pr.js.map +1 -1
- package/dist/commands/prompts.d.ts +6 -0
- package/dist/commands/prompts.d.ts.map +1 -1
- package/dist/commands/prompts.js +19 -10
- package/dist/commands/prompts.js.map +1 -1
- package/dist/commands/status-panel.d.ts.map +1 -1
- package/dist/commands/status-panel.js +23 -34
- package/dist/commands/status-panel.js.map +1 -1
- package/dist/commands/unitize.d.ts +3 -0
- package/dist/commands/unitize.d.ts.map +1 -1
- package/dist/commands/unitize.js +32 -9
- package/dist/commands/unitize.js.map +1 -1
- package/dist/commands/welcome.d.ts.map +1 -1
- package/dist/commands/welcome.js +41 -0
- package/dist/commands/welcome.js.map +1 -1
- package/dist/core/ask-context.d.ts.map +1 -1
- package/dist/core/ask-context.js +14 -3
- package/dist/core/ask-context.js.map +1 -1
- package/dist/core/ask-engine.d.ts.map +1 -1
- package/dist/core/ask-engine.js +39 -7
- package/dist/core/ask-engine.js.map +1 -1
- package/dist/core/environment-config.d.ts +11 -0
- package/dist/core/environment-config.d.ts.map +1 -1
- package/dist/core/environment-config.js +22 -0
- package/dist/core/environment-config.js.map +1 -1
- package/dist/core/git-integration.d.ts +1 -9
- package/dist/core/git-integration.d.ts.map +1 -1
- package/dist/core/git-integration.js +126 -12
- package/dist/core/git-integration.js.map +1 -1
- package/dist/core/global-knowledge.d.ts.map +1 -1
- package/dist/core/global-knowledge.js +24 -10
- package/dist/core/global-knowledge.js.map +1 -1
- package/dist/core/handoff-generator.d.ts.map +1 -1
- package/dist/core/handoff-generator.js +3 -1
- package/dist/core/handoff-generator.js.map +1 -1
- package/dist/core/intent-recognition.d.ts.map +1 -1
- package/dist/core/intent-recognition.js +63 -5
- package/dist/core/intent-recognition.js.map +1 -1
- package/dist/core/knowledge-graph.d.ts.map +1 -1
- package/dist/core/knowledge-graph.js +6 -4
- package/dist/core/knowledge-graph.js.map +1 -1
- package/dist/core/name-validator.d.ts.map +1 -1
- package/dist/core/name-validator.js +41 -20
- package/dist/core/name-validator.js.map +1 -1
- package/dist/core/pinyin-initials.d.ts +10 -0
- package/dist/core/pinyin-initials.d.ts.map +1 -0
- package/dist/core/pinyin-initials.js +44 -0
- package/dist/core/pinyin-initials.js.map +1 -0
- package/dist/core/reindex-engine.js +4 -4
- package/dist/core/reindex-engine.js.map +1 -1
- package/dist/core/skeleton-residue.d.ts +13 -0
- package/dist/core/skeleton-residue.d.ts.map +1 -1
- package/dist/core/skeleton-residue.js +83 -14
- package/dist/core/skeleton-residue.js.map +1 -1
- package/dist/core/spec-merger.d.ts.map +1 -1
- package/dist/core/spec-merger.js +3 -2
- package/dist/core/spec-merger.js.map +1 -1
- package/dist/core/state.d.ts +10 -0
- package/dist/core/state.d.ts.map +1 -1
- package/dist/core/state.js +20 -1
- package/dist/core/state.js.map +1 -1
- package/dist/core/task-paths.d.ts +12 -0
- package/dist/core/task-paths.d.ts.map +1 -1
- package/dist/core/task-paths.js +33 -1
- package/dist/core/task-paths.js.map +1 -1
- package/dist/core/unified-config.d.ts +7 -1
- package/dist/core/unified-config.d.ts.map +1 -1
- package/dist/core/unified-config.js +41 -2
- package/dist/core/unified-config.js.map +1 -1
- package/dist/core/unit-staffing.d.ts +21 -4
- package/dist/core/unit-staffing.d.ts.map +1 -1
- package/dist/core/unit-staffing.js +59 -12
- package/dist/core/unit-staffing.js.map +1 -1
- package/dist/core/validator.d.ts.map +1 -1
- package/dist/core/validator.js +45 -5
- package/dist/core/validator.js.map +1 -1
- package/dist/core/verify-report-aggregator.d.ts.map +1 -1
- package/dist/core/verify-report-aggregator.js +19 -2
- package/dist/core/verify-report-aggregator.js.map +1 -1
- package/dist/utils/task-utils.d.ts +4 -1
- package/dist/utils/task-utils.d.ts.map +1 -1
- package/dist/utils/task-utils.js +30 -4
- package/dist/utils/task-utils.js.map +1 -1
- package/package.json +4 -3
- package/templates/ci/github-actions.yml +1 -1
- package/templates/deploy-examples.yaml +33 -5
- package/templates/html/speccore-ask-explain.html +1 -1
- package/templates/html/speccore-ask-guide.html +1 -1
- package/templates/html/speccore-ask-match.html +1 -1
- package/templates/html/speccore-ask-pipeline.html +1 -1
- package/templates/html/speccore-ask-result.html +1 -1
- package/templates/html/speccore-help.html +2 -2
- package/templates/speccore-yml-example.yml +170 -50
- package/templates/verify-spec-example.yaml +66 -1
|
@@ -8,6 +8,8 @@ const context_1 = require("../../core/context");
|
|
|
8
8
|
const global_counters_1 = require("../../core/global-counters");
|
|
9
9
|
const next_steps_1 = require("../../core/next-steps");
|
|
10
10
|
const spec_paths_1 = require("../../core/spec-paths");
|
|
11
|
+
const unit_staffing_1 = require("../../core/unit-staffing");
|
|
12
|
+
const unified_config_1 = require("../../core/unified-config");
|
|
11
13
|
async function iterationCreateCommand(options) {
|
|
12
14
|
if (!options.name) {
|
|
13
15
|
logger_1.logger.error('Iteration name is required. Use --name <name>');
|
|
@@ -61,6 +63,58 @@ async function iterationCreateCommand(options) {
|
|
|
61
63
|
throw error;
|
|
62
64
|
}
|
|
63
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* v8.3.337+: 从全局 PROJECT.yaml git 段带出当前值快照
|
|
68
|
+
*
|
|
69
|
+
* 创建迭代时自动初始化迭代级 Git 配置(默认分支/分支格式照抄全局当前值),
|
|
70
|
+
* 全自动执行等无人值守场景读迭代 PROJECT_GRAPH.md 即有具体值;
|
|
71
|
+
* 全局未显式声明或值含表格破坏字符(|/换行)时退回「继承全局配置」占位符。
|
|
72
|
+
*/
|
|
73
|
+
async function loadIterationGitSnapshot() {
|
|
74
|
+
const INHERIT = '继承全局配置';
|
|
75
|
+
try {
|
|
76
|
+
const raw = await (0, unified_config_1.loadRawProjectConfig)();
|
|
77
|
+
const g = raw?.git;
|
|
78
|
+
const defaultBase = typeof g?.default_base === 'string' && g.default_base.trim() && !/[|\r\n]/.test(g.default_base)
|
|
79
|
+
? g.default_base.trim()
|
|
80
|
+
: INHERIT;
|
|
81
|
+
const branchFormat = typeof g?.branch_format === 'string' && g.branch_format.trim() && !/[|\r\n]/.test(g.branch_format)
|
|
82
|
+
? g.branch_format.trim()
|
|
83
|
+
: INHERIT;
|
|
84
|
+
return { defaultBase, branchFormat };
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return { defaultBase: INHERIT, branchFormat: INHERIT };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* v8.3.337+: 从全局 TEAM.md 全员基座带出成员快照行
|
|
92
|
+
*
|
|
93
|
+
* 创建迭代时自动预填成员信息(岗位/方向/比例/在项目照抄基座当前值),
|
|
94
|
+
* 自动化场景直接读迭代 STAFFING.md 即有完整名单;基座后续变更不影响
|
|
95
|
+
* 本迭代(快照语义),差异化调整直接编辑本文件。基座缺失/空表/读取失败
|
|
96
|
+
* 均静默降级为空表,不阻塞迭代创建。
|
|
97
|
+
*/
|
|
98
|
+
async function buildStaffingRows() {
|
|
99
|
+
try {
|
|
100
|
+
const teamPath = (0, path_1.join)('.speccore', 'PROJECT', 'TEAM.md');
|
|
101
|
+
if (!(await (0, fs_extra_1.pathExists)(teamPath)))
|
|
102
|
+
return '';
|
|
103
|
+
const members = (0, unit_staffing_1.parseStaffingTable)(await (0, fs_extra_1.readFile)(teamPath, 'utf-8'));
|
|
104
|
+
if (members.length === 0)
|
|
105
|
+
return '';
|
|
106
|
+
return members.map((m) => {
|
|
107
|
+
const roles = (m.roles ?? []).join(',');
|
|
108
|
+
const dirs = (m.directions ?? []).join(',');
|
|
109
|
+
const cap = m.capacity ?? 100;
|
|
110
|
+
const status = m.status === 'inactive' ? '否' : '是';
|
|
111
|
+
return `| ${m.name} | ${roles} | ${dirs} | ${cap}% | ${status} |`;
|
|
112
|
+
}).join('\n');
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return '';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
64
118
|
async function createIterationFiles(iterationDir, fullName, options) {
|
|
65
119
|
// 010-requirements/README.md — 目录规范说明
|
|
66
120
|
await (0, fs_extra_1.writeFile)((0, path_1.join)(iterationDir, '010-requirements', 'README.md'), `# 需求文档目录规范
|
|
@@ -231,6 +285,8 @@ research/
|
|
|
231
285
|
## 5. 风险与应对
|
|
232
286
|
`);
|
|
233
287
|
// PROJECT_GRAPH.md
|
|
288
|
+
// v8.3.337+: Git 配置表格创建时从全局 PROJECT.yaml 带出快照(自动化可直接读迭代级配置)
|
|
289
|
+
const gitSnapshot = await loadIterationGitSnapshot();
|
|
234
290
|
await (0, fs_extra_1.writeFile)((0, path_1.join)(iterationDir, '000-overview', 'PROJECT_GRAPH.md'), `# 本期任务总览
|
|
235
291
|
|
|
236
292
|
> 迭代:${fullName}
|
|
@@ -240,14 +296,14 @@ research/
|
|
|
240
296
|
|
|
241
297
|
## Git 配置
|
|
242
298
|
|
|
243
|
-
>
|
|
244
|
-
>
|
|
299
|
+
> 创建时从全局 PROJECT.yaml 带出当前值快照;任务级 .meta/git-config 又覆盖本处。
|
|
300
|
+
> 填「继承全局配置」或留空则使用上一级配置;编辑本表可覆盖全局值。
|
|
245
301
|
|
|
246
302
|
| 配置项 | 值 | 说明 |
|
|
247
303
|
| :--- | :--- | :--- |
|
|
248
|
-
| 默认分支 |
|
|
304
|
+
| 默认分支 | ${gitSnapshot.defaultBase} | 主分支名(main/master) |
|
|
249
305
|
| 分支前缀 | | 如 2060708,追加到分支名中 |
|
|
250
|
-
| 分支格式 |
|
|
306
|
+
| 分支格式 | ${gitSnapshot.branchFormat} | 模板:{type}/{prefix}{name}-{hash4} |
|
|
251
307
|
| 自动拉取 | 继承全局配置 | 创建分支前是否 git pull |
|
|
252
308
|
| 远程名称 | 继承全局配置 | 远程仓库名(origin) |
|
|
253
309
|
|
|
@@ -271,22 +327,28 @@ graph TD
|
|
|
271
327
|
| | | | |
|
|
272
328
|
`);
|
|
273
329
|
// STAFFING.md — 人员排期配置(差异覆盖层,全员基座在 .speccore/PROJECT/TEAM.md)
|
|
330
|
+
// v8.3.337+: 创建时自动从基座带出成员快照行(岗位/方向/比例/在项目照抄),
|
|
331
|
+
// 自动化场景直接读本文件即有完整名单;基座缺失/空表则生成空表。
|
|
332
|
+
const staffingRows = await buildStaffingRows();
|
|
274
333
|
await (0, fs_extra_1.writeFile)((0, path_1.join)(iterationDir, 'STAFFING.md'), `# ${options.name} 人员排期配置
|
|
275
334
|
|
|
276
335
|
> 迭代: ${options.name}${options.owner ? ` | 负责人: ${options.owner}` : ''}
|
|
277
|
-
> 全员基座: .speccore/PROJECT/TEAM.md
|
|
336
|
+
> 全员基座: .speccore/PROJECT/TEAM.md(全局名册,创建时自动带出成员快照)
|
|
278
337
|
|
|
279
338
|
## 人员列表
|
|
280
339
|
|
|
281
|
-
| 成员 | 平台方向 | 投入比例 |
|
|
282
|
-
| :--- | :--- | :--- | :--- |
|
|
283
|
-
| | | | |
|
|
340
|
+
| 成员 | 岗位 | 平台方向 | 投入比例 | 在项目 |
|
|
341
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
342
|
+
${staffingRows || '| | | | | |'}
|
|
284
343
|
|
|
285
344
|
> 说明:
|
|
286
|
-
> -
|
|
345
|
+
> - **创建时自动带出基座快照**(v8.3.337+): 岗位/方向/比例/在项目照抄全局 TEAM.md 当前值;此后基座变更不影响本迭代
|
|
346
|
+
> - **本文件只写差异**: 与基座同名的成员整体覆盖其岗位/方向/比例;基座成员未列出的默认参与本迭代
|
|
347
|
+
> - **岗位**(v8.3.337+): web / 后端 / 移动端 / 测试 / 产品,多个用逗号分隔(留空则继承基座)
|
|
287
348
|
> - **平台方向**: 后台 / 小程序 / Web / APP,多个用逗号分隔(也可直接写标准端名)
|
|
288
349
|
> - **投入比例**: 0-100%,用于 taskify 时自动分配和负荷均衡;写 0% 表示本迭代不参与
|
|
289
|
-
> -
|
|
350
|
+
> - **在项目**(v8.3.337+ 口径): 是(缺省)/ 否——只看是否在项目,不看在职与否;留空则继承基座
|
|
351
|
+
> - **通配**(v8.3.339+): 岗位/平台方向可写星号 *(或 all / 全部 / 所有 / 全栈),表示全栈/所有方向;通配与具体值并列时以通配为准
|
|
290
352
|
> - 编辑此文件后重新运行 taskify 即可更新默认分配
|
|
291
353
|
`);
|
|
292
354
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/iteration/create.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/iteration/create.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"taskify.d.ts","sourceRoot":"","sources":["../../../src/commands/iteration/taskify.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"taskify.d.ts","sourceRoot":"","sources":["../../../src/commands/iteration/taskify.ts"],"names":[],"mappings":"AAuJA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAY9D;AA8ED,MAAM,WAAW,uBAAuB;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAqLD,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAk0C7F"}
|
|
@@ -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
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
237
|
+
* v8.3.337+: 解析模块目录名——功能单元目录名直接对齐(与 features/、020-specs/ 一致),
|
|
238
|
+
* 去掉 Task-NNN 计数器序号。非目录名格式(自创英文名/中文名)返回空,回退原 topic 链。
|
|
239
|
+
* 目录名格式校验:小写字母/数字/连字符组成(功能单元命名 v8.3.271+ 契约)。
|
|
238
240
|
*/
|
|
239
|
-
function
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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**: \`${
|
|
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
|
-
|
|
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
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 均不满足),
|