speccore 5.15.1 → 5.19.0
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/README.en.md +8 -8
- package/README.md +16 -17
- package/dist/cli.js +298 -14
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +64 -3
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/change.d.ts.map +1 -1
- package/dist/commands/change.js.map +1 -1
- package/dist/commands/config.d.ts +4 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +18 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/context-output.d.ts +7 -0
- package/dist/commands/context-output.d.ts.map +1 -0
- package/dist/commands/context-output.js +86 -0
- package/dist/commands/context-output.js.map +1 -0
- package/dist/commands/dev.d.ts +7 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +179 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/execute.d.ts +3 -0
- package/dist/commands/execute.d.ts.map +1 -1
- package/dist/commands/execute.js +85 -13
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/help-quick.d.ts +3 -0
- package/dist/commands/help-quick.d.ts.map +1 -0
- package/dist/commands/help-quick.js +66 -0
- package/dist/commands/help-quick.js.map +1 -0
- package/dist/commands/history.d.ts +1 -0
- package/dist/commands/history.d.ts.map +1 -1
- package/dist/commands/history.js +26 -0
- package/dist/commands/history.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +56 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/iteration/split.js +134 -3
- package/dist/commands/iteration/split.js.map +1 -1
- package/dist/commands/lifecycle.d.ts.map +1 -1
- package/dist/commands/lifecycle.js +43 -2
- package/dist/commands/lifecycle.js.map +1 -1
- package/dist/commands/merge-check.d.ts +10 -0
- package/dist/commands/merge-check.d.ts.map +1 -0
- package/dist/commands/merge-check.js +148 -0
- package/dist/commands/merge-check.js.map +1 -0
- package/dist/commands/pr.d.ts +9 -0
- package/dist/commands/pr.d.ts.map +1 -0
- package/dist/commands/pr.js +97 -0
- package/dist/commands/pr.js.map +1 -0
- package/dist/commands/spec.d.ts.map +1 -1
- package/dist/commands/spec.js +5 -1
- package/dist/commands/spec.js.map +1 -1
- package/dist/commands/status-panel.d.ts +2 -0
- package/dist/commands/status-panel.d.ts.map +1 -0
- package/dist/commands/status-panel.js +143 -0
- package/dist/commands/status-panel.js.map +1 -0
- package/dist/commands/tracker.d.ts +2 -0
- package/dist/commands/tracker.d.ts.map +1 -0
- package/dist/commands/tracker.js +28 -0
- package/dist/commands/tracker.js.map +1 -0
- package/dist/core/code-scanner.d.ts +26 -0
- package/dist/core/code-scanner.d.ts.map +1 -0
- package/dist/core/code-scanner.js +223 -0
- package/dist/core/code-scanner.js.map +1 -0
- package/dist/core/constitution-builder.d.ts +2 -0
- package/dist/core/constitution-builder.d.ts.map +1 -0
- package/dist/core/constitution-builder.js +216 -0
- package/dist/core/constitution-builder.js.map +1 -0
- package/dist/core/execution-state.d.ts.map +1 -1
- package/dist/core/execution-state.js +4 -0
- package/dist/core/execution-state.js.map +1 -1
- package/dist/core/intent-ai.d.ts +19 -0
- package/dist/core/intent-ai.d.ts.map +1 -0
- package/dist/core/intent-ai.js +138 -0
- package/dist/core/intent-ai.js.map +1 -0
- package/dist/core/requirement-tracker.d.ts +24 -0
- package/dist/core/requirement-tracker.d.ts.map +1 -0
- package/dist/core/requirement-tracker.js +88 -0
- package/dist/core/requirement-tracker.js.map +1 -0
- package/dist/core/risk-scorer.d.ts +15 -5
- package/dist/core/risk-scorer.d.ts.map +1 -1
- package/dist/core/risk-scorer.js +135 -6
- package/dist/core/risk-scorer.js.map +1 -1
- package/dist/core/spec-annotations.d.ts +35 -0
- package/dist/core/spec-annotations.d.ts.map +1 -0
- package/dist/core/spec-annotations.js +203 -0
- package/dist/core/spec-annotations.js.map +1 -0
- package/dist/core/unified-config.d.ts +44 -0
- package/dist/core/unified-config.d.ts.map +1 -0
- package/dist/core/unified-config.js +141 -0
- package/dist/core/unified-config.js.map +1 -0
- package/package.json +2 -2
- package/dist/commands/hooks.d.ts +0 -5
- package/dist/commands/hooks.d.ts.map +0 -1
- package/dist/commands/hooks.js +0 -22
- package/dist/commands/hooks.js.map +0 -1
- package/dist/commands/research.d.ts +0 -14
- package/dist/commands/research.d.ts.map +0 -1
- package/dist/commands/research.js +0 -181
- package/dist/commands/research.js.map +0 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.aiEnhance = aiEnhance;
|
|
4
|
+
exports.recognizeWithAi = recognizeWithAi;
|
|
5
|
+
const logger_1 = require("../utils/logger");
|
|
6
|
+
/**
|
|
7
|
+
* 用 AI 增强意图识别(当关键词匹配不可靠时)
|
|
8
|
+
* 利用本地 AI/WorkBuddy 的分析能力
|
|
9
|
+
*/
|
|
10
|
+
async function aiEnhance(input, keywordConfidence) {
|
|
11
|
+
// 只有低置信度时才启动 AI
|
|
12
|
+
if (keywordConfidence >= 50)
|
|
13
|
+
return null;
|
|
14
|
+
logger_1.logger.info(' 🤖 关键词置信度偏低,启用 AI 分析...');
|
|
15
|
+
try {
|
|
16
|
+
const prompt = buildAiPrompt(input);
|
|
17
|
+
const response = await callLocalAi(prompt);
|
|
18
|
+
return parseAiResponse(response);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
// AI 不可用时静默降级
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function buildAiPrompt(input) {
|
|
26
|
+
return `分析以下中文描述,判断用户想执行什么操作。只返回 JSON。
|
|
27
|
+
|
|
28
|
+
描述: "${input}"
|
|
29
|
+
|
|
30
|
+
可用的操作类型:
|
|
31
|
+
- change: 修改/调整已有功能或需求
|
|
32
|
+
- bugfix: 修复错误/Bug
|
|
33
|
+
- new_task: 新增功能或任务
|
|
34
|
+
- execute: 执行/开发/开始干活
|
|
35
|
+
- review: 审查/检查
|
|
36
|
+
- query_progress: 查看进度/状态
|
|
37
|
+
- research: 技术调研/方案评估
|
|
38
|
+
- help: 求助/帮助
|
|
39
|
+
|
|
40
|
+
返回格式(仅 JSON,不要其他内容):
|
|
41
|
+
{
|
|
42
|
+
"intent": "操作类型",
|
|
43
|
+
"confidence": 0-100,
|
|
44
|
+
"suggestion": "建议的 speccore 命令",
|
|
45
|
+
"explanation": "简短解释"
|
|
46
|
+
}`;
|
|
47
|
+
}
|
|
48
|
+
function callLocalAi(prompt) {
|
|
49
|
+
try {
|
|
50
|
+
// 尝试通过 WorkBuddy 的 AI 能力(进程内调用)
|
|
51
|
+
// fallback: 基于规则给出合理建议
|
|
52
|
+
throw new Error('use fallback');
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// 无 AI 可用时,基于关键词深度分析
|
|
56
|
+
return fallbackAnalysis(prompt);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function fallbackAnalysis(prompt) {
|
|
60
|
+
// 提取描述部分
|
|
61
|
+
const match = prompt.match(/描述: "(.+)"/);
|
|
62
|
+
const input = match ? match[1] : '';
|
|
63
|
+
// 深度关键词分析(比 intent-recognition 更精细)
|
|
64
|
+
const hasProblem = /出问题|报错|挂了|崩了|不行|不正常|超时|500|异常|错误/.test(input);
|
|
65
|
+
const hasChange = /改|调整|换成|替换|修改|优化/.test(input);
|
|
66
|
+
const hasNew = /新增|添加|加一个|创建一个|开发|做一个/.test(input);
|
|
67
|
+
const hasQuery = /多少|进度|状态|怎么|哪些|看看|查看/.test(input);
|
|
68
|
+
let intent = 'help';
|
|
69
|
+
let confidence = 30;
|
|
70
|
+
let suggestion = 'speccore spec "..."';
|
|
71
|
+
let explanation = '无法确定意图,请用 /spec 命令明确说明';
|
|
72
|
+
if (hasProblem && !hasChange && !hasNew) {
|
|
73
|
+
intent = 'bugfix';
|
|
74
|
+
confidence = 55;
|
|
75
|
+
suggestion = 'speccore bugfix --name="自动检测的Bug"';
|
|
76
|
+
explanation = `检测到问题描述("${matchExtract(input, /(?:出问题|报错|挂了|崩了|超时|500)/)}"),建议创建 Bug 修复任务`;
|
|
77
|
+
}
|
|
78
|
+
else if (hasChange && !hasProblem) {
|
|
79
|
+
intent = 'change';
|
|
80
|
+
confidence = 60;
|
|
81
|
+
suggestion = 'speccore change';
|
|
82
|
+
explanation = '检测到修改意图,建议使用需求变更';
|
|
83
|
+
}
|
|
84
|
+
else if (hasNew && !hasProblem) {
|
|
85
|
+
intent = 'new_task';
|
|
86
|
+
confidence = 60;
|
|
87
|
+
suggestion = 'speccore new-task';
|
|
88
|
+
explanation = '检测到新增意图,建议创建新任务';
|
|
89
|
+
}
|
|
90
|
+
else if (hasQuery) {
|
|
91
|
+
intent = 'query_progress';
|
|
92
|
+
confidence = 55;
|
|
93
|
+
suggestion = 'speccore status';
|
|
94
|
+
explanation = '检测到查询意图';
|
|
95
|
+
}
|
|
96
|
+
return JSON.stringify({ intent, confidence, suggestion, explanation });
|
|
97
|
+
}
|
|
98
|
+
function matchExtract(input, pattern) {
|
|
99
|
+
const m = input.match(pattern);
|
|
100
|
+
return m ? m[0] : '';
|
|
101
|
+
}
|
|
102
|
+
function parseAiResponse(response) {
|
|
103
|
+
try {
|
|
104
|
+
// 尝试从 markdown 代码块中提取 JSON
|
|
105
|
+
const jsonMatch = response.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
|
|
106
|
+
const jsonStr = jsonMatch ? jsonMatch[1] : response;
|
|
107
|
+
const parsed = JSON.parse(jsonStr.trim());
|
|
108
|
+
return {
|
|
109
|
+
intent: parsed.intent || 'help',
|
|
110
|
+
confidence: Math.min(100, Math.max(0, Number(parsed.confidence) || 30)),
|
|
111
|
+
suggestion: parsed.suggestion || '',
|
|
112
|
+
explanation: parsed.explanation || '',
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 统一入口:关键词 + AI 增强
|
|
121
|
+
*/
|
|
122
|
+
async function recognizeWithAi(input, keywordResults) {
|
|
123
|
+
const topConfidence = keywordResults[0]?.confidence || 0;
|
|
124
|
+
const secondConfidence = keywordResults[1]?.confidence || 0;
|
|
125
|
+
const gap = topConfidence - secondConfidence;
|
|
126
|
+
// 不需要 AI:高置信度 + 差距明显
|
|
127
|
+
if (topConfidence >= 50 && gap >= 20) {
|
|
128
|
+
return { final: keywordResults[0], usedAi: false };
|
|
129
|
+
}
|
|
130
|
+
// 调用 AI 增强
|
|
131
|
+
const aiResult = await aiEnhance(input, topConfidence);
|
|
132
|
+
if (aiResult && aiResult.confidence > topConfidence) {
|
|
133
|
+
logger_1.logger.info(` 🤖 AI 判断: ${aiResult.intent} (${aiResult.confidence}%) — ${aiResult.explanation}`);
|
|
134
|
+
return { final: { ...keywordResults[0], ...aiResult, aiEnhanced: true }, usedAi: true };
|
|
135
|
+
}
|
|
136
|
+
return { final: keywordResults[0], usedAi: false };
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=intent-ai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent-ai.js","sourceRoot":"","sources":["../../src/core/intent-ai.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ReqEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
status: 'active' | 'modified' | 'deprecated';
|
|
5
|
+
originIteration: string;
|
|
6
|
+
lastModifiedIteration?: string;
|
|
7
|
+
changeHistory: {
|
|
8
|
+
iteration: string;
|
|
9
|
+
type: '新增' | '修改' | '废弃';
|
|
10
|
+
timestamp: string;
|
|
11
|
+
}[];
|
|
12
|
+
}
|
|
13
|
+
export declare function loadTracker(): Promise<ReqEntry[]>;
|
|
14
|
+
export declare function saveTracker(entries: ReqEntry[]): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* 注册或更新需求追踪
|
|
17
|
+
* @returns warnings — 跨期次冲突预警
|
|
18
|
+
*/
|
|
19
|
+
export declare function registerRequirement(title: string, iteration: string, changeType: '新增' | '修改' | '废弃'): Promise<string[]>;
|
|
20
|
+
/**
|
|
21
|
+
* 生成全量层需求追踪报告 (Markdown)
|
|
22
|
+
*/
|
|
23
|
+
export declare function generateTrackerReport(): Promise<string>;
|
|
24
|
+
//# sourceMappingURL=requirement-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requirement-tracker.d.ts","sourceRoot":"","sources":["../../src/core/requirement-tracker.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,YAAY,CAAC;IAC7C,eAAe,EAAE,MAAM,CAAC;IACxB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,aAAa,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACrF;AAQD,wBAAsB,WAAW,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAMvD;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAIpE;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAC7B,OAAO,CAAC,MAAM,EAAE,CAAC,CAiDnB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC,CAc7D"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadTracker = loadTracker;
|
|
4
|
+
exports.saveTracker = saveTracker;
|
|
5
|
+
exports.registerRequirement = registerRequirement;
|
|
6
|
+
exports.generateTrackerReport = generateTrackerReport;
|
|
7
|
+
/**
|
|
8
|
+
* requirement-tracker — 全量层需求追踪:新增/修改/冲突检测
|
|
9
|
+
*/
|
|
10
|
+
const fs_extra_1 = require("fs-extra");
|
|
11
|
+
const path_1 = require("path");
|
|
12
|
+
const TRACKER_PATH = (0, path_1.join)('.speccore', 'GLOBAL', 'REQUIREMENTS', 'tracker.json');
|
|
13
|
+
function trackerPath() {
|
|
14
|
+
return (0, path_1.join)(process.cwd(), TRACKER_PATH);
|
|
15
|
+
}
|
|
16
|
+
async function loadTracker() {
|
|
17
|
+
const p = trackerPath();
|
|
18
|
+
if (await (0, fs_extra_1.pathExists)(p)) {
|
|
19
|
+
return JSON.parse(await (0, fs_extra_1.readFile)(p, 'utf-8'));
|
|
20
|
+
}
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
async function saveTracker(entries) {
|
|
24
|
+
const p = trackerPath();
|
|
25
|
+
await (0, fs_extra_1.ensureDir)((0, path_1.join)(p, '..'));
|
|
26
|
+
await (0, fs_extra_1.writeFile)(p, JSON.stringify(entries, null, 2), 'utf-8');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 注册或更新需求追踪
|
|
30
|
+
* @returns warnings — 跨期次冲突预警
|
|
31
|
+
*/
|
|
32
|
+
async function registerRequirement(title, iteration, changeType) {
|
|
33
|
+
const entries = await loadTracker();
|
|
34
|
+
const warnings = [];
|
|
35
|
+
// 按标题模糊匹配已有需求(前 10 字相同视为同一需求)
|
|
36
|
+
const existing = entries.find(e => e.title.slice(0, Math.min(10, e.title.length, title.length)) ===
|
|
37
|
+
title.slice(0, Math.min(10, title.length)));
|
|
38
|
+
const now = new Date().toISOString();
|
|
39
|
+
if (existing) {
|
|
40
|
+
if (changeType === '新增') {
|
|
41
|
+
warnings.push(`⚠️ "${title}" 已在 ${existing.originIteration} 中引入,当前标记为「新增」可能重复`);
|
|
42
|
+
}
|
|
43
|
+
if (changeType === '修改') {
|
|
44
|
+
existing.status = 'modified';
|
|
45
|
+
existing.lastModifiedIteration = iteration;
|
|
46
|
+
existing.changeHistory.push({ iteration, type: '修改', timestamp: now });
|
|
47
|
+
// 检测:是否有其他期次也在修改同一个需求
|
|
48
|
+
const otherModifiers = existing.changeHistory
|
|
49
|
+
.filter(h => h.type === '修改' && h.iteration !== iteration)
|
|
50
|
+
.map(h => h.iteration);
|
|
51
|
+
if (otherModifiers.length > 0) {
|
|
52
|
+
warnings.push(`⚠️ "${title}" 曾在以下期次被修改: ${[...new Set(otherModifiers)].join(', ')} — 注意合并冲突`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (changeType === '废弃') {
|
|
56
|
+
existing.status = 'deprecated';
|
|
57
|
+
existing.changeHistory.push({ iteration, type: '废弃', timestamp: now });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// 新需求
|
|
62
|
+
entries.push({
|
|
63
|
+
id: `REQ-${String(entries.length + 1).padStart(3, '0')}`,
|
|
64
|
+
title,
|
|
65
|
+
status: changeType === '废弃' ? 'deprecated' : 'active',
|
|
66
|
+
originIteration: iteration,
|
|
67
|
+
changeHistory: [{ iteration, type: '新增', timestamp: now }],
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
await saveTracker(entries);
|
|
71
|
+
return warnings;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 生成全量层需求追踪报告 (Markdown)
|
|
75
|
+
*/
|
|
76
|
+
async function generateTrackerReport() {
|
|
77
|
+
const entries = await loadTracker();
|
|
78
|
+
let report = `# 全量需求追踪\n\n`;
|
|
79
|
+
report += `> 自动生成 | ${new Date().toISOString().slice(0, 10)}\n\n`;
|
|
80
|
+
report += `| ID | 需求 | 状态 | 首次期次 | 最近修改 | 变更次数 |\n`;
|
|
81
|
+
report += `| :--- | :--- | :--- | :--- | :--- | :--- |\n`;
|
|
82
|
+
for (const e of entries) {
|
|
83
|
+
const statusEmoji = e.status === 'active' ? '🟢' : e.status === 'modified' ? '🟡' : '⚫';
|
|
84
|
+
report += `| ${e.id} | ${e.title} | ${statusEmoji} ${e.status} | ${e.originIteration} | ${e.lastModifiedIteration || '-'} | ${e.changeHistory.length} |\n`;
|
|
85
|
+
}
|
|
86
|
+
return report;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=requirement-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requirement-tracker.js","sourceRoot":"","sources":["../../src/core/requirement-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export interface RiskItem {
|
|
2
|
+
category: string;
|
|
3
|
+
level: '🔴' | '🟡' | '🟢';
|
|
4
|
+
description: string;
|
|
5
|
+
mitigation: string;
|
|
6
|
+
source: '需求' | '源码';
|
|
7
|
+
}
|
|
4
8
|
export interface RiskScore {
|
|
5
9
|
level: '🔴 high' | '🟡 medium' | '🟢 low';
|
|
6
10
|
score: number;
|
|
7
11
|
tags: string[];
|
|
8
12
|
reasons: string[];
|
|
13
|
+
items: RiskItem[];
|
|
14
|
+
codeRisks: RiskItem[];
|
|
9
15
|
}
|
|
10
16
|
/**
|
|
11
|
-
*
|
|
17
|
+
* 根据任务需求内容 + 已有源码自动评分
|
|
18
|
+
*/
|
|
19
|
+
export declare function scoreRisk(content: string, taskName: string, iterationDir?: string): Promise<RiskScore>;
|
|
20
|
+
/**
|
|
21
|
+
* 生成详细风险报告(Markdown)
|
|
12
22
|
*/
|
|
13
|
-
export declare function
|
|
23
|
+
export declare function generateRiskReport(risk: RiskScore): string;
|
|
14
24
|
//# sourceMappingURL=risk-scorer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"risk-scorer.d.ts","sourceRoot":"","sources":["../../src/core/risk-scorer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"risk-scorer.d.ts","sourceRoot":"","sources":["../../src/core/risk-scorer.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,IAAI,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CA4H5G;AA+CD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAsB1D"}
|
package/dist/core/risk-scorer.js
CHANGED
|
@@ -1,61 +1,190 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* risk-scorer — 任务风险评分 + 标签
|
|
4
|
-
*/
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.scoreRisk = scoreRisk;
|
|
4
|
+
exports.generateRiskReport = generateRiskReport;
|
|
5
|
+
/**
|
|
6
|
+
* risk-scorer — 任务风险评分 + 详细报告
|
|
7
|
+
*/
|
|
8
|
+
const fs_extra_1 = require("fs-extra");
|
|
7
9
|
/**
|
|
8
|
-
*
|
|
10
|
+
* 根据任务需求内容 + 已有源码自动评分
|
|
9
11
|
*/
|
|
10
|
-
function scoreRisk(content, taskName) {
|
|
12
|
+
async function scoreRisk(content, taskName, iterationDir) {
|
|
11
13
|
let score = 0;
|
|
12
14
|
const tags = [];
|
|
13
15
|
const reasons = [];
|
|
16
|
+
const items = [];
|
|
14
17
|
// ── 高风险: 支付/资金 ──
|
|
15
18
|
if (content.match(/支付|退款|转账|提现|余额|钱包|金额|价格|账单/)) {
|
|
16
19
|
score += 30;
|
|
17
20
|
tags.push('💰 支付');
|
|
18
21
|
reasons.push('涉及支付/资金操作');
|
|
22
|
+
items.push({
|
|
23
|
+
category: '支付安全',
|
|
24
|
+
level: '🔴',
|
|
25
|
+
description: '涉及资金交易,任何错误都可能导致资损',
|
|
26
|
+
mitigation: '必须双人审查 + 充分测试覆盖 + 添加资金操作日志',
|
|
27
|
+
source: '需求',
|
|
28
|
+
});
|
|
19
29
|
}
|
|
20
30
|
// ── 高风险: 权限/认证 ──
|
|
21
31
|
if (content.match(/权限|角色|RBAC|认证|授权|登录|token|OAuth|JWT|鉴权/)) {
|
|
22
32
|
score += 25;
|
|
23
33
|
tags.push('🔐 权限');
|
|
24
34
|
reasons.push('涉及权限/认证变更');
|
|
35
|
+
items.push({
|
|
36
|
+
category: '权限控制',
|
|
37
|
+
level: '🔴',
|
|
38
|
+
description: '权限变更可能造成越权访问',
|
|
39
|
+
mitigation: '逐接口检查权限注解 + 补充越权测试用例',
|
|
40
|
+
source: '需求',
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// ── 高风险: 数据删除 ──
|
|
44
|
+
if (content.match(/DELETE\s*\|/) || content.match(/物理删除|硬删除|cascade/)) {
|
|
45
|
+
score += 20;
|
|
46
|
+
items.push({
|
|
47
|
+
category: '数据安全',
|
|
48
|
+
level: '🔴',
|
|
49
|
+
description: '物理删除操作不可逆',
|
|
50
|
+
mitigation: '建议改用软删除 + 回收站机制, 生产环境禁止物理删除',
|
|
51
|
+
source: '需求',
|
|
52
|
+
});
|
|
25
53
|
}
|
|
26
54
|
// ── 中风险: 批量操作 ──
|
|
27
55
|
if (content.match(/批量删除|批量操作|批量导入|批量更新|全选/)) {
|
|
28
56
|
score += 20;
|
|
29
57
|
tags.push('📦 批量');
|
|
30
58
|
reasons.push('批量操作有数据风险');
|
|
59
|
+
items.push({
|
|
60
|
+
category: '批量操作',
|
|
61
|
+
level: '🟡',
|
|
62
|
+
description: '批量操作可能影响大量数据',
|
|
63
|
+
mitigation: '添加批量限制(≤1000) + 异步处理 + 操作确认弹窗',
|
|
64
|
+
source: '需求',
|
|
65
|
+
});
|
|
31
66
|
}
|
|
32
67
|
// ── 中风险: 导出/报表 ──
|
|
33
68
|
if (content.match(/导出|报表|Excel|CSV|下载|文件生成/)) {
|
|
34
69
|
score += 15;
|
|
35
70
|
tags.push('📊 导出');
|
|
36
71
|
reasons.push('大数据量导出需注意性能');
|
|
72
|
+
items.push({
|
|
73
|
+
category: '性能',
|
|
74
|
+
level: '🟡',
|
|
75
|
+
description: '大数据量导出可能拖垮服务',
|
|
76
|
+
mitigation: '异步导出 + 分页查询 + 文件压缩 + 24h自动清理',
|
|
77
|
+
source: '需求',
|
|
78
|
+
});
|
|
37
79
|
}
|
|
38
80
|
// ── 中风险: 涉及数据库变更 ──
|
|
39
81
|
if (content.match(/数据表|ALTER|建表|索引|迁移|数据迁移|DDL/)) {
|
|
40
82
|
score += 15;
|
|
41
83
|
tags.push('🗄️ DB');
|
|
42
84
|
reasons.push('涉及数据库结构变更');
|
|
85
|
+
items.push({
|
|
86
|
+
category: '数据库变更',
|
|
87
|
+
level: '🟡',
|
|
88
|
+
description: '数据库结构变更可能影响已有功能',
|
|
89
|
+
mitigation: '先在测试环境验证 + 写好回滚脚本 + 非高峰期执行',
|
|
90
|
+
source: '需求',
|
|
91
|
+
});
|
|
43
92
|
}
|
|
44
93
|
// ── 中风险: 外部依赖 ──
|
|
45
94
|
if (content.match(/第三方|外部API|回调|webhook|消息队列|Kafka|MQ/)) {
|
|
46
95
|
score += 10;
|
|
47
96
|
tags.push('🔗 外部依赖');
|
|
48
97
|
reasons.push('涉及外部系统集成');
|
|
98
|
+
items.push({
|
|
99
|
+
category: '外部依赖',
|
|
100
|
+
level: '🟡',
|
|
101
|
+
description: '外部系统不可用时本功能也会受影响',
|
|
102
|
+
mitigation: '添加超时(5s) + 熔断降级 + 重试机制 + 监控告警',
|
|
103
|
+
source: '需求',
|
|
104
|
+
});
|
|
49
105
|
}
|
|
50
106
|
// ── 低风险标记 ──
|
|
51
107
|
const crud = content.match(/\| (GET|POST|PUT|DELETE) \|/) || [];
|
|
52
108
|
if (crud.length >= 2 && score < 20) {
|
|
53
109
|
tags.push('📋 CRUD');
|
|
110
|
+
items.push({
|
|
111
|
+
category: '通用 CRUD',
|
|
112
|
+
level: '🟢',
|
|
113
|
+
description: '标准增删改查,风险较低',
|
|
114
|
+
mitigation: '注意输入校验 + 异常处理',
|
|
115
|
+
source: '需求',
|
|
116
|
+
});
|
|
54
117
|
}
|
|
55
118
|
if (score < 15) {
|
|
56
119
|
tags.push('🟢 低风险');
|
|
57
120
|
}
|
|
121
|
+
// ── 源码层面的风险检测 ──
|
|
122
|
+
const codeRisks = await detectCodeRisks(iterationDir, taskName);
|
|
58
123
|
const level = score >= 30 ? '🔴 high' : score >= 15 ? '🟡 medium' : '🟢 low';
|
|
59
|
-
return { level, score, tags, reasons };
|
|
124
|
+
return { level, score, tags, reasons, items, codeRisks };
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 检测源码层面的风险(从已有关联代码中分析)
|
|
128
|
+
*/
|
|
129
|
+
async function detectCodeRisks(iterationDir, taskName) {
|
|
130
|
+
if (!iterationDir || !taskName)
|
|
131
|
+
return [];
|
|
132
|
+
const risks = [];
|
|
133
|
+
// 检查 TECH.md 中的选型是否有已知风险
|
|
134
|
+
const techPath = `.speccore/iterations/${iterationDir}/${taskName}/backend/TECH.md`;
|
|
135
|
+
const altTechPath = `${iterationDir}/${taskName}/backend/TECH.md`;
|
|
136
|
+
let techContent = '';
|
|
137
|
+
try {
|
|
138
|
+
if (await (0, fs_extra_1.pathExists)(techPath))
|
|
139
|
+
techContent = await (0, fs_extra_1.readFile)(techPath, 'utf-8');
|
|
140
|
+
else if (await (0, fs_extra_1.pathExists)(altTechPath))
|
|
141
|
+
techContent = await (0, fs_extra_1.readFile)(altTechPath, 'utf-8');
|
|
142
|
+
}
|
|
143
|
+
catch { }
|
|
144
|
+
if (techContent) {
|
|
145
|
+
// 检测到 N+1 查询风险
|
|
146
|
+
if (techContent.match(/for\s*\(.*\)\s*\{|forEach.*\.find|循环.*查询/)) {
|
|
147
|
+
risks.push({
|
|
148
|
+
category: '性能',
|
|
149
|
+
level: '🟡',
|
|
150
|
+
description: '代码中可能存在 N+1 查询问题',
|
|
151
|
+
mitigation: '使用 JOIN 查询或批量查询代替循环中的单条查询',
|
|
152
|
+
source: '源码',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
// 检测到未处理的异常
|
|
156
|
+
if (techContent.match(/\.catch\s*\(\s*\)|catch\s*\{\s*\}/)) {
|
|
157
|
+
risks.push({
|
|
158
|
+
category: '异常处理',
|
|
159
|
+
level: '🟡',
|
|
160
|
+
description: '存在空异常捕获,可能吞掉错误信息',
|
|
161
|
+
mitigation: '添加错误日志记录 + 统一异常处理中间件',
|
|
162
|
+
source: '源码',
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return risks;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* 生成详细风险报告(Markdown)
|
|
170
|
+
*/
|
|
171
|
+
function generateRiskReport(risk) {
|
|
172
|
+
let md = `# 风险评估\n\n`;
|
|
173
|
+
md += `- **风险等级**: ${risk.level}\n`;
|
|
174
|
+
md += `- **风险评分**: ${risk.score}/100\n`;
|
|
175
|
+
md += `- **风险标签**: ${risk.tags.join(', ') || '无'}\n\n`;
|
|
176
|
+
const allItems = [...risk.items, ...risk.codeRisks];
|
|
177
|
+
if (allItems.length === 0) {
|
|
178
|
+
md += '✅ 未检测到明显风险\n';
|
|
179
|
+
return md;
|
|
180
|
+
}
|
|
181
|
+
md += `## 风险详情 (${allItems.length} 项)\n\n`;
|
|
182
|
+
md += `| 等级 | 类别 | 描述 | 缓解建议 | 来源 |\n`;
|
|
183
|
+
md += `| :--- | :--- | :--- | :--- | :--- |\n`;
|
|
184
|
+
for (const item of allItems) {
|
|
185
|
+
md += `| ${item.level} | ${item.category} | ${item.description} | ${item.mitigation} | ${item.source} |\n`;
|
|
186
|
+
}
|
|
187
|
+
md += `\n---\n> 💡 高风险项建议在开发前 Review,中风险项开发时注意缓解措施\n`;
|
|
188
|
+
return md;
|
|
60
189
|
}
|
|
61
190
|
//# sourceMappingURL=risk-scorer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"risk-scorer.js","sourceRoot":"","sources":["../../src/core/risk-scorer.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"risk-scorer.js","sourceRoot":"","sources":["../../src/core/risk-scorer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface SpecAnnotation {
|
|
2
|
+
type: 'module' | 'api' | 'entity' | 'dependency' | 'scope';
|
|
3
|
+
value: string;
|
|
4
|
+
file: string;
|
|
5
|
+
line: number;
|
|
6
|
+
}
|
|
7
|
+
export interface ModuleGroup {
|
|
8
|
+
name: string;
|
|
9
|
+
directory: string;
|
|
10
|
+
files: string[];
|
|
11
|
+
apis: string[];
|
|
12
|
+
entities: string[];
|
|
13
|
+
dependencies: string[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 扫描单个文件的 Spec 注释标记
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractAnnotations(filePath: string): Promise<SpecAnnotation[]>;
|
|
19
|
+
/**
|
|
20
|
+
* 从注释标记构建模块分组
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildModuleGroups(annotations: SpecAnnotation[]): ModuleGroup[];
|
|
23
|
+
/**
|
|
24
|
+
* 根据需求描述查找对应模块(用于精准读取)
|
|
25
|
+
*/
|
|
26
|
+
export declare function matchModule(requirement: string, modules: ModuleGroup[]): ModuleGroup | null;
|
|
27
|
+
/**
|
|
28
|
+
* 自动发现项目根目录(多工程场景)
|
|
29
|
+
*/
|
|
30
|
+
export declare function discoverProjectRoots(cwd: string): Promise<string[]>;
|
|
31
|
+
/**
|
|
32
|
+
* 生成模块清单报告
|
|
33
|
+
*/
|
|
34
|
+
export declare function generateModuleReport(modules: ModuleGroup[]): string;
|
|
35
|
+
//# sourceMappingURL=spec-annotations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-annotations.d.ts","sourceRoot":"","sources":["../../src/core/spec-annotations.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,CAAC;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAiBD;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAwBpF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,cAAc,EAAE,GAAG,WAAW,EAAE,CAkD9E;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,WAAW,EAAE,GACrB,WAAW,GAAG,IAAI,CAoBpB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAoCzE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAiBnE"}
|