speccore 8.3.231 → 8.3.233
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 +2 -1
- package/.agents/skills/spec-unitize/SKILL.md +18 -0
- package/.agents/skills/speccore-router/SKILL.md +11 -1
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +46 -13
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/unitize.d.ts.map +1 -1
- package/dist/commands/unitize.js +6 -0
- package/dist/commands/unitize.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,7 +3,8 @@ name: spec-ask
|
|
|
3
3
|
description: >
|
|
4
4
|
SpecCore CLI 执行引擎。仅在用户明确要求通过 speccore 命令行工具执行以下操作时触发:
|
|
5
5
|
- analyze --prompt:生成迭代级/全局级 Spec 分析文档(ANALYSIS.md、TECH.md 等),不是单纯解释代码
|
|
6
|
-
- split
|
|
6
|
+
- unitize:切分需求文档为功能单元(features/,原 doc2spec --split)
|
|
7
|
+
- taskify:将功能单元拆分为开发任务并写入迭代目录(原 split)
|
|
7
8
|
- plan --prompt:制定执行计划并写入 Task 目录
|
|
8
9
|
- execute --prompt:执行开发任务并生成代码
|
|
9
10
|
- doc2spec:导入 PRD/Word 文档到迭代目录
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-unitize
|
|
3
|
+
description: >
|
|
4
|
+
SpecCore 切分需求专属 Skill。仅在用户明确提到 speccore、迭代、期次、Spec、
|
|
5
|
+
/unitize 等关键词,或明确要求通过 speccore 切分需求文档为功能单元(unitize)时使用。
|
|
6
|
+
在调用 speccore ask 之前,执行参数提取、前置校验(输入文件格式:.md 可直接切、
|
|
7
|
+
.docx/.pdf 需先 doc2spec 转换;端名须与 CONSTITUTION.md 端列表一致;
|
|
8
|
+
features/ 已有同名单元时重切会覆盖旧切片;多文档可批量 --files "a.md=端1,b.md"),
|
|
9
|
+
参数缺失时输出交互式提示(参数说明 + 使用示例)。
|
|
10
|
+
不处理一般性的"切分/拆分"讨论(如"帮我切一下这段文本"),只处理 speccore 上下文中的切分。
|
|
11
|
+
与 spec-taskify 的区别:unitize 切需求(文档→功能单元 features/),taskify 拆任务(功能单元→开发任务 Task-*)。
|
|
12
|
+
allowed-tools: ["Bash", "Read"]
|
|
13
|
+
disable-model-invocation: false
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
直接执行: execute_command("speccore ask '用户原话'")
|
|
17
|
+
|
|
18
|
+
不要输出命令文本,不要分析意图,一切交给 speccore ask。
|
|
@@ -3,7 +3,7 @@ name: speccore-router
|
|
|
3
3
|
description: >
|
|
4
4
|
SpecCore CLI 命令路由器。仅在用户明确提到 speccore、迭代、期次、Spec 等关键词,
|
|
5
5
|
或明确要求通过 speccore 命令行工具执行操作,且意图涉及以下概念时使用:
|
|
6
|
-
迭代管理、需求文档导入(doc2spec)、Spec 分析生成(analyze --prompt)、
|
|
6
|
+
迭代管理、需求文档导入(doc2spec)、需求切分(unitize)、Spec 分析生成(analyze --prompt)、
|
|
7
7
|
任务拆分(taskify)、执行计划(plan --prompt)、代码执行(execute --prompt)、
|
|
8
8
|
任务归档(done)、PR 提交(pr)、状态查看(status/dashboard/doctor)、智能级联(dev)。
|
|
9
9
|
将用户意图映射为 speccore CLI 命令,通过 execute_command 执行。
|
|
@@ -176,6 +176,15 @@ allowed-tools: ["Bash", "Read", "Write", "Edit"]
|
|
|
176
176
|
| 分析这个 PRD 文档 | file | **激活 spec-doc2spec Skill → 完整AI+Pandoc流程** |
|
|
177
177
|
| 帮我看看这个需求文档 | file | **激活 spec-doc2spec Skill** |
|
|
178
178
|
|
|
179
|
+
### 功能单元切分(unitize — 需求文档→功能单元)
|
|
180
|
+
| 用户说法 | 提取参数 | CLI 命令 / 行为 |
|
|
181
|
+
| :--- | :--- | :--- |
|
|
182
|
+
| 切分功能单元 / 单元化 | file?, iter? | **激活 spec-unitize Skill** |
|
|
183
|
+
| 切分需求文档 {file} | file, iter? | `speccore unitize --file {file} --iter {iter}` |
|
|
184
|
+
| 切分 {file}(.md)到 {iter} | file, iter | `speccore unitize --file {file} --iter {iter}` |
|
|
185
|
+
| 批量切分 {files} | files="a.md=端1,b.md" | `speccore unitize --files "{files}" --iter {iter}` |
|
|
186
|
+
| 切分 {file}(.docx/.pdf) | file | 先 `speccore doc2spec -f {file}` 转换再 unitize |
|
|
187
|
+
|
|
179
188
|
### 文档导出(spec2doc — AI排版)
|
|
180
189
|
| 用户说法 | 提取参数 | CLI 命令 / 行为 |
|
|
181
190
|
| :--- | :--- | :--- |
|
|
@@ -428,6 +437,7 @@ allowed-tools: ["Bash", "Read", "Write", "Edit"]
|
|
|
428
437
|
| 用户意图 | --prompt 命令 | --apply/--response |
|
|
429
438
|
| :--- | :--- | :--- |
|
|
430
439
|
| 导入需求 {file} | `speccore doc2spec --prompt -f {file}` | `--response '...'` |
|
|
440
|
+
| 切分功能单元 {file} | `speccore unitize --file {file} -I {iter}` | 直接执行(本地规则+AI 双路) |
|
|
431
441
|
| 分析 {iter} | `speccore analyze --prompt -I {iter}` | `--apply '...'` |
|
|
432
442
|
| 拆分 {iter} | `speccore iteration taskify --prompt -I {iter}` | `--response '...'` |
|
|
433
443
|
| 生成计划 {iter} | `speccore plan --prompt -I {iter}` | `--response '...'` |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAiFA,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,MAAM,GAAG,UAAU,CAAC;IACrD,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAmND,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/analyze.js
CHANGED
|
@@ -1895,19 +1895,26 @@ ${singlePrompt}`);
|
|
|
1895
1895
|
}
|
|
1896
1896
|
};
|
|
1897
1897
|
await checkDir(specDir);
|
|
1898
|
-
if (emptySkeletonDocs.length > 0) {
|
|
1899
|
-
|
|
1900
|
-
|
|
1898
|
+
if (emptySkeletonDocs.length > 0 || emptyTableDocs.length > 0) {
|
|
1899
|
+
// v8.3.233+: 结构化报告 + 兜底指引——报告给用户,可对有问题单元再次分析直到干净
|
|
1900
|
+
const iterName = (0, path_1.basename)(iterDir);
|
|
1901
|
+
const problemUnits = new Set();
|
|
1902
|
+
const mapUnit = (d) => {
|
|
1903
|
+
const seg = d.split('/')[0];
|
|
1904
|
+
if (seg && seg !== 'overview')
|
|
1905
|
+
problemUnits.add(seg);
|
|
1906
|
+
};
|
|
1907
|
+
emptySkeletonDocs.forEach(mapUnit);
|
|
1908
|
+
emptyTableDocs.forEach(mapUnit);
|
|
1909
|
+
process.stdout.write('\n[SPECCORE_SKELETON_REPORT]\n');
|
|
1910
|
+
logger_1.logger.warn(`⚠️ 质量检查: ${emptySkeletonDocs.length} 个空骨架 / ${emptyTableDocs.length} 个空表格`);
|
|
1901
1911
|
for (const d of emptySkeletonDocs)
|
|
1902
|
-
logger_1.logger.warn(` ❌
|
|
1903
|
-
logger_1.logger.info(' 💡 建议重新执行 analyze 补充这些文档');
|
|
1904
|
-
}
|
|
1905
|
-
if (emptyTableDocs.length > 0) {
|
|
1906
|
-
logger_1.logger.warn('');
|
|
1907
|
-
logger_1.logger.warn(`⚠️ 检测到 ${emptyTableDocs.length} 个文档含空表格(只有表头无数据):`);
|
|
1912
|
+
logger_1.logger.warn(` ❌ 空骨架: 020-specs/${d}`);
|
|
1908
1913
|
for (const d of emptyTableDocs)
|
|
1909
|
-
logger_1.logger.warn(`
|
|
1910
|
-
logger_1.logger.info(' 💡
|
|
1914
|
+
logger_1.logger.warn(` ⚠️ 空表格: 020-specs/${d}`);
|
|
1915
|
+
logger_1.logger.info(' 💡 兜底修复(循环直到干净):');
|
|
1916
|
+
logger_1.logger.info(` speccore analyze --resume-units -I ${iterName.replace(/^Iteration-/, '')}`);
|
|
1917
|
+
logger_1.logger.info(' (仍为骨架的单元会被重新纳入分析;也可 --unit <单元名> 定向重析)');
|
|
1911
1918
|
}
|
|
1912
1919
|
}
|
|
1913
1920
|
catch (e) {
|
|
@@ -6510,7 +6517,32 @@ async function loadUnitAnalyses(iteration) {
|
|
|
6510
6517
|
async function detectPendingUnits(iteration, allUnits) {
|
|
6511
6518
|
const completed = await loadUnitAnalyses(iteration);
|
|
6512
6519
|
const completedIds = new Set(completed.map(a => a.id));
|
|
6513
|
-
|
|
6520
|
+
const iterDir = `Iteration-${iteration.replace(/^Iteration-/, '')}`;
|
|
6521
|
+
const pending = [];
|
|
6522
|
+
for (const u of allUnits) {
|
|
6523
|
+
if (!completedIds.has(u.id)) {
|
|
6524
|
+
pending.push(u);
|
|
6525
|
+
continue;
|
|
6526
|
+
}
|
|
6527
|
+
// v8.3.233+: 完成记录存在但落盘内容仍为骨架 → 仍视为待分析(兜底:
|
|
6528
|
+
// 用户可对有问题的单元再次分析,直到无空骨架)
|
|
6529
|
+
if (await unitHasSkeletonOutput(iterDir, u))
|
|
6530
|
+
pending.push(u);
|
|
6531
|
+
}
|
|
6532
|
+
return pending;
|
|
6533
|
+
}
|
|
6534
|
+
/** v8.3.233+: 检查单元落盘规格是否仍为骨架/空内容(用于 pending 判定兜底,不写缓存) */
|
|
6535
|
+
async function unitHasSkeletonOutput(iterDir, unit) {
|
|
6536
|
+
const specDir = getUnitSpecDir(iterDir, unit);
|
|
6537
|
+
for (const f of ['REQUIREMENT.md', 'ANALYSIS.md', 'TECH.md']) {
|
|
6538
|
+
const fp = (0, path_1.join)(specDir, f);
|
|
6539
|
+
if (!(await (0, fs_extra_1.pathExists)(fp)))
|
|
6540
|
+
continue;
|
|
6541
|
+
const content = (await (0, fs_extra_2.readFile)(fp, 'utf-8')).trim();
|
|
6542
|
+
if (content && !content.includes('SPEC-SKELETON') && content.length >= 200)
|
|
6543
|
+
return false;
|
|
6544
|
+
}
|
|
6545
|
+
return true; // 三个候选全无效 → 视为骨架状态
|
|
6514
6546
|
}
|
|
6515
6547
|
/** 汇总所有单元分析为统一报告(带 [DOC:xxx] 标记) */
|
|
6516
6548
|
async function consolidateUnitAnalyses(iteration, units, analyses) {
|
|
@@ -6881,7 +6913,8 @@ async function runUnitDispatchLoop(iter, iterDir, units) {
|
|
|
6881
6913
|
return (0, dispatch_loop_1.runDispatchLoopRound)(steps, {
|
|
6882
6914
|
projectRoot: (0, task_utils_1.findProjectRoot)() || process.cwd(),
|
|
6883
6915
|
scope: `analyze-units:${iter}`,
|
|
6884
|
-
|
|
6916
|
+
// v8.3.233+: 一轮内最多 3 次尝试(初始 + 2 重试);循环外 resume 还可无限续跑
|
|
6917
|
+
maxRetries: 2,
|
|
6885
6918
|
});
|
|
6886
6919
|
}
|
|
6887
6920
|
/** 输出调度循环完成汇总 */
|