openmatrix 0.1.50 → 0.1.52

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.
@@ -4,4 +4,26 @@ export declare class TaskParser {
4
4
  private extractTitle;
5
5
  private extractDescription;
6
6
  private extractSection;
7
+ /**
8
+ * 从纯文本中智能提取 goals
9
+ *
10
+ * 策略优先级:
11
+ * 1. 有序列表 (1. xxx, 2. xxx)
12
+ * 2. 无序列表 (- xxx, * xxx)
13
+ * 3. 分号/换行分隔的多行描述
14
+ * 4. 将标题作为唯一 goal
15
+ */
16
+ private extractGoalsFromPlainText;
17
+ /**
18
+ * 提取有序列表项
19
+ */
20
+ private extractOrderedItems;
21
+ /**
22
+ * 提取无序列表项
23
+ */
24
+ private extractUnorderedItems;
25
+ /**
26
+ * 从文本中提取句子作为 goals
27
+ */
28
+ private extractSentences;
7
29
  }
@@ -8,12 +8,20 @@ class TaskParser {
8
8
  const constraints = this.extractSection(content, '约束');
9
9
  const deliverables = this.extractSection(content, '交付物');
10
10
  const description = this.extractDescription(content);
11
+ // Fallback: 当 markdown section 未提取到 goals 时,智能提取
12
+ const finalGoals = goals.length > 0
13
+ ? goals
14
+ : this.extractGoalsFromPlainText(content, title);
15
+ // Fallback: 当无 deliverables 时,从 goals 推断
16
+ const finalDeliverables = deliverables.length > 0
17
+ ? deliverables
18
+ : finalGoals.map(g => `${g} 的实现`);
11
19
  return {
12
20
  title,
13
- description,
14
- goals: [...new Set(goals)], // 去重
15
- constraints: [...new Set(constraints)], // 去重
16
- deliverables: [...new Set(deliverables)], // 去重
21
+ description: description || (finalGoals.length > 0 ? finalGoals[0] : title),
22
+ goals: [...new Set(finalGoals)],
23
+ constraints: [...new Set(constraints)],
24
+ deliverables: [...new Set(finalDeliverables)],
17
25
  rawContent: content
18
26
  };
19
27
  }
@@ -22,34 +30,39 @@ class TaskParser {
22
30
  return match ? match[1].trim() : 'Untitled Task';
23
31
  }
24
32
  extractDescription(content) {
25
- // Remove title and sections, get first paragraph
26
- let desc = content
27
- .replace(/^#\s+.+$/m, '')
28
- .replace(/^##\s+.+$/gm, '')
29
- .replace(/^- .+$/gm, '')
30
- .trim();
31
- // Get first non-empty line
33
+ // Remove title line
34
+ let desc = content.replace(/^#\s+.+$/m, '').trim();
35
+ // Remove section headers
36
+ desc = desc.replace(/^##\s+.+$/gm, '').trim();
37
+ // Get first non-empty, non-list line as description
32
38
  const lines = desc.split('\n').filter(l => l.trim());
33
- return lines.length > 0 ? lines[0].trim() : '';
39
+ for (const line of lines) {
40
+ const trimmed = line.trim();
41
+ // Skip list items, section headers
42
+ if (/^[-*]\s+/.test(trimmed))
43
+ continue;
44
+ if (/^\d+\.\s+/.test(trimmed))
45
+ continue;
46
+ if (trimmed.length > 0) {
47
+ return trimmed;
48
+ }
49
+ }
50
+ return '';
34
51
  }
35
52
  extractSection(content, sectionName) {
36
- // Split content into lines and find the section
37
53
  const lines = content.split('\n');
38
54
  const items = [];
39
55
  let inSection = false;
40
56
  for (const line of lines) {
41
- // Check if we're entering the target section
42
57
  if (line.match(new RegExp(`^##\\s+${sectionName}\\s*$`))) {
43
58
  inSection = true;
44
59
  continue;
45
60
  }
46
- // Check if we've hit another section
47
61
  if (line.match(/^##\s+/)) {
48
62
  if (inSection)
49
- break; // Exit if we were in the target section
63
+ break;
50
64
  continue;
51
65
  }
52
- // Extract list items if we're in the target section
53
66
  if (inSection) {
54
67
  const itemMatch = line.match(/^-\s+(.+)$/);
55
68
  if (itemMatch) {
@@ -59,5 +72,92 @@ class TaskParser {
59
72
  }
60
73
  return items;
61
74
  }
75
+ /**
76
+ * 从纯文本中智能提取 goals
77
+ *
78
+ * 策略优先级:
79
+ * 1. 有序列表 (1. xxx, 2. xxx)
80
+ * 2. 无序列表 (- xxx, * xxx)
81
+ * 3. 分号/换行分隔的多行描述
82
+ * 4. 将标题作为唯一 goal
83
+ */
84
+ extractGoalsFromPlainText(content, title) {
85
+ const goals = [];
86
+ const cleanContent = content
87
+ .replace(/^#\s+.+$/m, '') // 去标题
88
+ .replace(/^##\s+.+$/gm, '') // 去section标题
89
+ .trim();
90
+ // 策略1: 有序列表 (1. xxx, 2. xxx, ...)
91
+ const orderedItems = this.extractOrderedItems(cleanContent);
92
+ if (orderedItems.length > 0) {
93
+ return orderedItems;
94
+ }
95
+ // 策略2: 无序列表 (- xxx, * xxx)
96
+ const unorderedItems = this.extractUnorderedItems(cleanContent);
97
+ if (unorderedItems.length > 0) {
98
+ return unorderedItems;
99
+ }
100
+ // 策略3: 多行文本,按句号/分号拆分为多个 goal
101
+ const sentences = this.extractSentences(cleanContent);
102
+ if (sentences.length > 1) {
103
+ return sentences;
104
+ }
105
+ // 策略4: 单个句子作为唯一 goal
106
+ if (sentences.length === 1 && sentences[0].length > 0) {
107
+ return sentences;
108
+ }
109
+ // 策略5: 将标题作为唯一 goal
110
+ if (title && title !== 'Untitled Task') {
111
+ return [title];
112
+ }
113
+ return goals;
114
+ }
115
+ /**
116
+ * 提取有序列表项
117
+ */
118
+ extractOrderedItems(text) {
119
+ const items = [];
120
+ const lines = text.split('\n');
121
+ for (const line of lines) {
122
+ const match = line.trim().match(/^\d+[.、)\s]+(.+)$/);
123
+ if (match) {
124
+ const item = match[1].trim();
125
+ if (item.length > 0) {
126
+ items.push(item);
127
+ }
128
+ }
129
+ }
130
+ return items;
131
+ }
132
+ /**
133
+ * 提取无序列表项
134
+ */
135
+ extractUnorderedItems(text) {
136
+ const items = [];
137
+ const lines = text.split('\n');
138
+ for (const line of lines) {
139
+ const match = line.trim().match(/^[-*]\s+(.+)$/);
140
+ if (match) {
141
+ const item = match[1].trim();
142
+ if (item.length > 0) {
143
+ items.push(item);
144
+ }
145
+ }
146
+ }
147
+ return items;
148
+ }
149
+ /**
150
+ * 从文本中提取句子作为 goals
151
+ */
152
+ extractSentences(text) {
153
+ if (!text || text.trim().length === 0)
154
+ return [];
155
+ // 按中文句号、英文句号、分号拆分
156
+ const sentences = text
157
+ .split(/[。;\n]/)
158
+ .map(s => s.replace(/[.;]/g, '').trim())
159
+ .filter(s => s.length > 2); // 过滤太短的片段
160
+ return sentences;
161
+ }
62
162
  }
63
163
  exports.TaskParser = TaskParser;
@@ -1,4 +1,4 @@
1
- import type { ParsedTask } from '../types/index.js';
1
+ import type { ParsedTask, QualityConfig } from '../types/index.js';
2
2
  export interface TaskBreakdown {
3
3
  taskId: string;
4
4
  title: string;
@@ -21,6 +21,8 @@ export interface UserAnswers {
21
21
  e2eTests?: boolean;
22
22
  /** E2E 测试类型 (web/mobile/gui) */
23
23
  e2eType?: 'web' | 'mobile' | 'gui';
24
+ /** 质量级别 */
25
+ qualityLevel?: 'fast' | 'balanced' | 'strict';
24
26
  }
25
27
  /**
26
28
  * TaskPlanner - 任务拆解器
@@ -31,9 +33,12 @@ export interface UserAnswers {
31
33
  * 3. 验收标准注入 (从用户回答中提取)
32
34
  * 4. 用户上下文注入 (将用户回答注入任务描述)
33
35
  * 5. 依赖关系分析 (自动分析任务间依赖)
36
+ * 6. 并行执行 (独立任务互不依赖)
37
+ * 7. 质量级别感知 (根据配置调整测试覆盖率)
34
38
  */
35
39
  export declare class TaskPlanner {
36
40
  private userAnswers;
41
+ private taskCounter;
37
42
  constructor(userAnswers?: UserAnswers);
38
43
  /**
39
44
  * 设置用户回答
@@ -41,45 +46,32 @@ export declare class TaskPlanner {
41
46
  setUserAnswers(answers: UserAnswers): void;
42
47
  /**
43
48
  * Break down a parsed task into sub-tasks
49
+ */
50
+ breakdown(parsedTask: ParsedTask, answers: Record<string, string>, qualityConfig?: QualityConfig, plan?: string): TaskBreakdown[];
51
+ /**
52
+ * 判断是否需要设计阶段
44
53
  *
45
- * 增强版: 生成更细粒度的任务,包含设计、开发、测试配对
54
+ * 条件: 多个 goal,或 goal 包含复杂关键词
46
55
  */
47
- breakdown(parsedTask: ParsedTask, answers: Record<string, string>): TaskBreakdown[];
56
+ private needsDesignPhase;
48
57
  /**
49
- * 提取用户上下文
58
+ * 获取测试覆盖率目标
50
59
  */
51
- private extractUserContext;
60
+ private getCoverageTarget;
52
61
  /**
53
- * 解析数组类型的回答
62
+ * 提取用户上下文
54
63
  */
64
+ private extractUserContext;
55
65
  private parseArrayAnswer;
56
66
  /**
57
- * 构建任务描述 (注入用户上下文)
67
+ * 构建全局上下文块(注入到每个子任务描述中)
58
68
  */
69
+ private buildGlobalContext;
59
70
  private buildTaskDescription;
60
- /**
61
- * 构建测试任务描述
62
- */
63
71
  private buildTestDescription;
64
- /**
65
- * 构建 E2E 测试任务描述
66
- */
67
72
  private buildE2ETestDescription;
68
- /**
69
- * 获取 E2E 测试类型配置
70
- */
71
73
  private getE2ETypeConfig;
72
- /**
73
- * 生成用户流程测试用例
74
- */
75
74
  private generateUserFlows;
76
- /**
77
- * 解析覆盖率数值
78
- */
79
- private parseCoverage;
80
- /**
81
- * 生成验收标准
82
- */
83
75
  private generateAcceptanceCriteria;
84
76
  private generateTaskId;
85
77
  private determinePriority;