@bicorne/task-flow 0.1.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/LICENSE +21 -0
- package/README.md +252 -0
- package/SKILL.md +250 -0
- package/assets/.harnessrc +10 -0
- package/assets/PHASE-task.json.example +50 -0
- package/assets/design.md +69 -0
- package/assets/hooks.json +15 -0
- package/assets/product-requirement.md +82 -0
- package/assets/schema.json +127 -0
- package/assets/tasks.md +26 -0
- package/dist/commands/analyze.d.ts +32 -0
- package/dist/commands/analyze.js +338 -0
- package/dist/commands/archive.d.ts +11 -0
- package/dist/commands/archive.js +53 -0
- package/dist/commands/design.d.ts +38 -0
- package/dist/commands/design.js +492 -0
- package/dist/commands/extract.d.ts +31 -0
- package/dist/commands/extract.js +477 -0
- package/dist/commands/init.d.ts +24 -0
- package/dist/commands/init.js +165 -0
- package/dist/commands/merge/index.d.ts +17 -0
- package/dist/commands/merge/index.js +322 -0
- package/dist/commands/merge/merger.d.ts +18 -0
- package/dist/commands/merge/merger.js +151 -0
- package/dist/commands/merge/types.d.ts +67 -0
- package/dist/commands/merge/types.js +6 -0
- package/dist/commands/merge/validators.d.ts +14 -0
- package/dist/commands/merge/validators.js +147 -0
- package/dist/commands/merge.d.ts +7 -0
- package/dist/commands/merge.js +15 -0
- package/dist/commands/start.d.ts +32 -0
- package/dist/commands/start.js +265 -0
- package/dist/commands/status.d.ts +15 -0
- package/dist/commands/status.js +143 -0
- package/dist/commands/sync.d.ts +11 -0
- package/dist/commands/sync.js +58 -0
- package/dist/commands/tasks-gen/doc-parser.d.ts +7 -0
- package/dist/commands/tasks-gen/doc-parser.js +259 -0
- package/dist/commands/tasks-gen/generators.d.ts +33 -0
- package/dist/commands/tasks-gen/generators.js +141 -0
- package/dist/commands/tasks-gen/index.d.ts +30 -0
- package/dist/commands/tasks-gen/index.js +345 -0
- package/dist/commands/tasks-gen/parsers.d.ts +29 -0
- package/dist/commands/tasks-gen/parsers.js +272 -0
- package/dist/commands/tasks-gen/templates.d.ts +8 -0
- package/dist/commands/tasks-gen/templates.js +37 -0
- package/dist/commands/tasks-gen/types.d.ts +71 -0
- package/dist/commands/tasks-gen/types.js +17 -0
- package/dist/commands/tasks-gen/validators.d.ts +14 -0
- package/dist/commands/tasks-gen/validators.js +54 -0
- package/dist/commands/tasks.d.ts +9 -0
- package/dist/commands/tasks.js +22 -0
- package/dist/commands/worktree.d.ts +28 -0
- package/dist/commands/worktree.js +275 -0
- package/dist/hooks/check-prd-exists.d.ts +20 -0
- package/dist/hooks/check-prd-exists.js +61 -0
- package/dist/hooks/check-worktree-conflict.d.ts +34 -0
- package/dist/hooks/check-worktree-conflict.js +107 -0
- package/dist/hooks/hook-runner/executor.d.ts +18 -0
- package/dist/hooks/hook-runner/executor.js +143 -0
- package/dist/hooks/hook-runner/index.d.ts +64 -0
- package/dist/hooks/hook-runner/index.js +220 -0
- package/dist/hooks/hook-runner/loader.d.ts +23 -0
- package/dist/hooks/hook-runner/loader.js +126 -0
- package/dist/hooks/hook-runner/types.d.ts +59 -0
- package/dist/hooks/hook-runner/types.js +6 -0
- package/dist/hooks/hook-runner.d.ts +9 -0
- package/dist/hooks/hook-runner.js +30 -0
- package/dist/hooks/phase-complete-detector.d.ts +35 -0
- package/dist/hooks/phase-complete-detector.js +203 -0
- package/dist/hooks/phase-gate-validator.d.ts +76 -0
- package/dist/hooks/phase-gate-validator.js +407 -0
- package/dist/hooks/save-checkpoint.d.ts +43 -0
- package/dist/hooks/save-checkpoint.js +144 -0
- package/dist/hooks/start-mcp-servers.d.ts +50 -0
- package/dist/hooks/start-mcp-servers.js +75 -0
- package/dist/hooks/stop-mcp-servers.d.ts +40 -0
- package/dist/hooks/stop-mcp-servers.js +58 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +238 -0
- package/dist/lib/archive.d.ts +31 -0
- package/dist/lib/archive.js +226 -0
- package/dist/lib/config.d.ts +93 -0
- package/dist/lib/config.js +251 -0
- package/dist/lib/constants.d.ts +222 -0
- package/dist/lib/constants.js +247 -0
- package/dist/lib/interactive.d.ts +31 -0
- package/dist/lib/interactive.js +166 -0
- package/dist/lib/mcp-client.d.ts +156 -0
- package/dist/lib/mcp-client.js +370 -0
- package/dist/lib/state.d.ts +119 -0
- package/dist/lib/state.js +293 -0
- package/dist/slash/executor.d.ts +22 -0
- package/dist/slash/executor.js +259 -0
- package/dist/slash/index.d.ts +11 -0
- package/dist/slash/index.js +45 -0
- package/dist/slash/parser.d.ts +24 -0
- package/dist/slash/parser.js +101 -0
- package/dist/slash/registry.d.ts +22 -0
- package/dist/slash/registry.js +155 -0
- package/dist/spec/openspec-to-task/builders.d.ts +107 -0
- package/dist/spec/openspec-to-task/builders.js +138 -0
- package/dist/spec/openspec-to-task/index.d.ts +20 -0
- package/dist/spec/openspec-to-task/index.js +182 -0
- package/dist/spec/openspec-to-task/parsers.d.ts +65 -0
- package/dist/spec/openspec-to-task/parsers.js +232 -0
- package/dist/spec/openspec-to-task/types.d.ts +49 -0
- package/dist/spec/openspec-to-task/types.js +6 -0
- package/dist/spec/sync-openspec-to-task.d.ts +7 -0
- package/dist/spec/sync-openspec-to-task.js +21 -0
- package/dist/spec/sync-task-to-openspec.d.ts +27 -0
- package/dist/spec/sync-task-to-openspec.js +288 -0
- package/dist/types/ai-context.d.ts +108 -0
- package/dist/types/ai-context.js +9 -0
- package/package.json +66 -0
- package/references/AI-CONVERSATION-TUTORIAL.md +270 -0
- package/references/CLI-TUTORIAL.md +447 -0
- package/references/GIT-WORKTREE-SOP.md +109 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* commands/tasks-gen/doc-parser.ts
|
|
3
|
+
* Parse PRD and design documents to extract tasks
|
|
4
|
+
*/
|
|
5
|
+
import { Task } from './types';
|
|
6
|
+
export declare function parseDocumentsToTasks(prdContent: string, designContent: string | null, _changeName: string): Task[];
|
|
7
|
+
export declare function extractProjectName(prdContent: string): string;
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* commands/tasks-gen/doc-parser.ts
|
|
4
|
+
* Parse PRD and design documents to extract tasks
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.parseDocumentsToTasks = parseDocumentsToTasks;
|
|
8
|
+
exports.extractProjectName = extractProjectName;
|
|
9
|
+
const PRIORITY_MAP = {
|
|
10
|
+
P0: 'high',
|
|
11
|
+
P1: 'medium',
|
|
12
|
+
P2: 'low',
|
|
13
|
+
p0: 'high',
|
|
14
|
+
p1: 'medium',
|
|
15
|
+
p2: 'low',
|
|
16
|
+
};
|
|
17
|
+
function extractSection(content, sectionTitle) {
|
|
18
|
+
const lines = content.split(/\r?\n/);
|
|
19
|
+
const sectionStartRegex = new RegExp(`^(#{2,})\\s+${sectionTitle}`, 'i');
|
|
20
|
+
let startIndex = -1;
|
|
21
|
+
let endIndex = lines.length;
|
|
22
|
+
let sectionLevel = 0;
|
|
23
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
24
|
+
const line = lines[i] || '';
|
|
25
|
+
const match = line.match(sectionStartRegex);
|
|
26
|
+
if (match) {
|
|
27
|
+
startIndex = i;
|
|
28
|
+
sectionLevel = match[1]?.length || 2;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (startIndex !== -1) {
|
|
32
|
+
const nextSectionMatch = line.match(/^(#{1,})\s+/);
|
|
33
|
+
if (nextSectionMatch) {
|
|
34
|
+
const nextLevel = nextSectionMatch[1]?.length || 0;
|
|
35
|
+
if (nextLevel <= sectionLevel) {
|
|
36
|
+
endIndex = i;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (startIndex === -1) {
|
|
43
|
+
return '';
|
|
44
|
+
}
|
|
45
|
+
return lines.slice(startIndex, endIndex).join('\n');
|
|
46
|
+
}
|
|
47
|
+
function sanitizeCell(cell) {
|
|
48
|
+
return cell
|
|
49
|
+
.replace(/<br\s*\/?>/gi, '\n')
|
|
50
|
+
.replace(/<[^>]+>/g, '')
|
|
51
|
+
.trim();
|
|
52
|
+
}
|
|
53
|
+
function parseFeatureTable(section) {
|
|
54
|
+
const features = [];
|
|
55
|
+
const lines = section.split(/\r?\n/);
|
|
56
|
+
let featureCounter = 0;
|
|
57
|
+
let headerIndices = {};
|
|
58
|
+
for (const line of lines) {
|
|
59
|
+
const trimmed = line.trim();
|
|
60
|
+
if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (trimmed.includes('---')) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const cells = trimmed
|
|
67
|
+
.split('|')
|
|
68
|
+
.map((cell) => sanitizeCell(cell.trim()))
|
|
69
|
+
.filter((cell) => cell.length > 0);
|
|
70
|
+
if (cells.some((cell) => cell.includes('功能名称') || cell.includes('优先级'))) {
|
|
71
|
+
headerIndices = {};
|
|
72
|
+
cells.forEach((cell, idx) => {
|
|
73
|
+
const lower = cell.toLowerCase();
|
|
74
|
+
if (lower.includes('功能名称') || lower.includes('feature') || lower.includes('名称')) {
|
|
75
|
+
headerIndices.name = idx;
|
|
76
|
+
}
|
|
77
|
+
if (lower.includes('优先级') || lower.includes('priority')) {
|
|
78
|
+
headerIndices.priority = idx;
|
|
79
|
+
}
|
|
80
|
+
if (lower.includes('描述') || lower.includes('description')) {
|
|
81
|
+
headerIndices.description = idx;
|
|
82
|
+
}
|
|
83
|
+
if (lower.includes('验收') || lower.includes('acceptance') || lower.includes('标准')) {
|
|
84
|
+
headerIndices.acceptanceCriteria = idx;
|
|
85
|
+
}
|
|
86
|
+
if (lower.includes('编号') || lower.includes('id') || lower.includes('#')) {
|
|
87
|
+
headerIndices.id = idx;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (cells.length >= 2) {
|
|
93
|
+
featureCounter += 1;
|
|
94
|
+
const nameIdx = headerIndices.name ?? 0;
|
|
95
|
+
const priorityIdx = headerIndices.priority ?? (nameIdx + 1);
|
|
96
|
+
const descIdx = headerIndices.description ?? (priorityIdx + 1);
|
|
97
|
+
const acIdx = headerIndices.acceptanceCriteria ?? (descIdx + 1);
|
|
98
|
+
const feature = {
|
|
99
|
+
id: headerIndices.id !== undefined ? (cells[headerIndices.id] ?? `F-${featureCounter}`) : `F-${featureCounter}`,
|
|
100
|
+
name: cells[nameIdx] ?? `Feature ${featureCounter}`,
|
|
101
|
+
priority: cells[priorityIdx] ?? 'medium',
|
|
102
|
+
description: cells[descIdx] ?? '',
|
|
103
|
+
acceptanceCriteria: cells[acIdx] ?? '',
|
|
104
|
+
};
|
|
105
|
+
features.push(feature);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return features;
|
|
109
|
+
}
|
|
110
|
+
function parseDesignDocument(designContent) {
|
|
111
|
+
const design = {
|
|
112
|
+
modules: [],
|
|
113
|
+
apis: [],
|
|
114
|
+
dataModels: [],
|
|
115
|
+
};
|
|
116
|
+
const archSection = extractSection(designContent, '架构设计');
|
|
117
|
+
const moduleMatches = archSection.match(/[-*]\s+(.+)/g);
|
|
118
|
+
if (moduleMatches) {
|
|
119
|
+
design.modules = moduleMatches.map((m) => m.replace(/^[-*]\s+/, '').trim());
|
|
120
|
+
}
|
|
121
|
+
const apiSection = extractSection(designContent, '接口设计');
|
|
122
|
+
const apiMatches = apiSection.match(/[-*]\s+(.+)/g);
|
|
123
|
+
if (apiMatches) {
|
|
124
|
+
design.apis = apiMatches.map((m) => m.replace(/^[-*]\s+/, '').trim());
|
|
125
|
+
}
|
|
126
|
+
const dataSection = extractSection(designContent, '数据模型');
|
|
127
|
+
const dataMatches = dataSection.match(/[-*]\s+(.+)/g);
|
|
128
|
+
if (dataMatches) {
|
|
129
|
+
design.dataModels = dataMatches.map((m) => m.replace(/^[-*]\s+/, '').trim());
|
|
130
|
+
}
|
|
131
|
+
return design;
|
|
132
|
+
}
|
|
133
|
+
function inferPhase(priority) {
|
|
134
|
+
const normalizedPriority = PRIORITY_MAP[priority] || priority;
|
|
135
|
+
switch (normalizedPriority) {
|
|
136
|
+
case 'high':
|
|
137
|
+
return 2;
|
|
138
|
+
case 'medium':
|
|
139
|
+
return 3;
|
|
140
|
+
case 'low':
|
|
141
|
+
return 4;
|
|
142
|
+
default:
|
|
143
|
+
return 3;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function inferFiles(feature, _design) {
|
|
147
|
+
const files = [];
|
|
148
|
+
const featureLower = (feature.name + ' ' + feature.description).toLowerCase();
|
|
149
|
+
if (featureLower.includes('api') || featureLower.includes('接口')) {
|
|
150
|
+
files.push('src/api/');
|
|
151
|
+
}
|
|
152
|
+
if (featureLower.includes('数据') || featureLower.includes('database') || featureLower.includes('model')) {
|
|
153
|
+
files.push('src/models/');
|
|
154
|
+
}
|
|
155
|
+
if (featureLower.includes('页面') || featureLower.includes('page') || featureLower.includes('ui')) {
|
|
156
|
+
files.push('src/pages/');
|
|
157
|
+
}
|
|
158
|
+
if (featureLower.includes('组件') || featureLower.includes('component')) {
|
|
159
|
+
files.push('src/components/');
|
|
160
|
+
}
|
|
161
|
+
if (featureLower.includes('工具') || featureLower.includes('util') || featureLower.includes('helper')) {
|
|
162
|
+
files.push('src/utils/');
|
|
163
|
+
}
|
|
164
|
+
if (files.length === 0) {
|
|
165
|
+
files.push('src/');
|
|
166
|
+
}
|
|
167
|
+
return files;
|
|
168
|
+
}
|
|
169
|
+
function parseDocumentsToTasks(prdContent, designContent, _changeName) {
|
|
170
|
+
const tasks = [];
|
|
171
|
+
const design = designContent ? parseDesignDocument(designContent) : { modules: [], apis: [], dataModels: [] };
|
|
172
|
+
const hasArchitectureTask = design.modules.length > 0 || designContent;
|
|
173
|
+
if (hasArchitectureTask) {
|
|
174
|
+
tasks.push({
|
|
175
|
+
id: 'PHASE-1-1-1',
|
|
176
|
+
phase: 1,
|
|
177
|
+
subphase: 1,
|
|
178
|
+
sequence: 1,
|
|
179
|
+
title: '搭建基础架构',
|
|
180
|
+
type: 'feat',
|
|
181
|
+
priority: 'high',
|
|
182
|
+
status: 'pending',
|
|
183
|
+
dependencies: [],
|
|
184
|
+
spec: {
|
|
185
|
+
description: '根据技术规格搭建项目基础架构',
|
|
186
|
+
files: ['src/'],
|
|
187
|
+
context: design.modules,
|
|
188
|
+
},
|
|
189
|
+
acceptance_criteria: ['架构符合设计文档', '模块划分清晰'],
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
const featureSection = extractSection(prdContent, '(详细功能需求|功能需求)');
|
|
193
|
+
const features = parseFeatureTable(featureSection);
|
|
194
|
+
const phaseTaskCount = {};
|
|
195
|
+
for (const feature of features) {
|
|
196
|
+
const phase = inferPhase(feature.priority);
|
|
197
|
+
if (!phaseTaskCount[phase]) {
|
|
198
|
+
phaseTaskCount[phase] = 1;
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
phaseTaskCount[phase] += 1;
|
|
202
|
+
}
|
|
203
|
+
const taskId = `PHASE-${phase}-${phase}-${phaseTaskCount[phase]}`;
|
|
204
|
+
const files = inferFiles(feature, design);
|
|
205
|
+
const priority = PRIORITY_MAP[feature.priority] || 'medium';
|
|
206
|
+
const task = {
|
|
207
|
+
id: taskId,
|
|
208
|
+
phase,
|
|
209
|
+
subphase: phase,
|
|
210
|
+
sequence: phaseTaskCount[phase],
|
|
211
|
+
title: feature.name,
|
|
212
|
+
type: 'feat',
|
|
213
|
+
priority: priority,
|
|
214
|
+
status: 'pending',
|
|
215
|
+
dependencies: hasArchitectureTask ? ['PHASE-1-1-1'] : [],
|
|
216
|
+
spec: {
|
|
217
|
+
description: feature.description || feature.name,
|
|
218
|
+
files,
|
|
219
|
+
context: [],
|
|
220
|
+
},
|
|
221
|
+
acceptance_criteria: feature.acceptanceCriteria
|
|
222
|
+
? feature.acceptanceCriteria.split(/\n/).filter((s) => s.length > 0)
|
|
223
|
+
: ['功能正常工作', '测试通过'],
|
|
224
|
+
};
|
|
225
|
+
tasks.push(task);
|
|
226
|
+
}
|
|
227
|
+
const nonFuncSection = extractSection(prdContent, '非功能性需求');
|
|
228
|
+
if (nonFuncSection && nonFuncSection.length > 50) {
|
|
229
|
+
const lastTaskId = tasks.length > 0 ? tasks[tasks.length - 1]?.id : undefined;
|
|
230
|
+
tasks.push({
|
|
231
|
+
id: `PHASE-5-5-1`,
|
|
232
|
+
phase: 5,
|
|
233
|
+
subphase: 5,
|
|
234
|
+
sequence: 1,
|
|
235
|
+
title: '非功能性需求实现',
|
|
236
|
+
type: 'feat',
|
|
237
|
+
priority: 'medium',
|
|
238
|
+
status: 'pending',
|
|
239
|
+
dependencies: lastTaskId ? [lastTaskId] : [],
|
|
240
|
+
spec: {
|
|
241
|
+
description: '实现性能、安全、可用性等非功能性需求',
|
|
242
|
+
files: ['src/'],
|
|
243
|
+
context: [],
|
|
244
|
+
},
|
|
245
|
+
acceptance_criteria: ['性能达标', '安全检查通过', '可用性要求满足'],
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
return tasks;
|
|
249
|
+
}
|
|
250
|
+
function extractProjectName(prdContent) {
|
|
251
|
+
const lines = prdContent.split(/\r?\n/);
|
|
252
|
+
for (const line of lines) {
|
|
253
|
+
const headingMatch = line.match(/^#\s+(.+)$/);
|
|
254
|
+
if (headingMatch) {
|
|
255
|
+
return headingMatch[1] || 'Unknown Project';
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return 'Unknown Project';
|
|
259
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* commands/tasks-gen/generators.ts
|
|
3
|
+
* Task file generation utilities
|
|
4
|
+
*/
|
|
5
|
+
import { Task } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Generate a single phase JSON object
|
|
8
|
+
*/
|
|
9
|
+
export declare function generatePhaseJson(task: Task, changeName: string, allTaskIds?: string[]): Record<string, unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* Generate manifest JSON
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateManifestJson(changeName: string, tasks: Task[], options?: {
|
|
14
|
+
type?: string;
|
|
15
|
+
priority?: string;
|
|
16
|
+
}): Record<string, unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* Generate phase JSON files for all tasks
|
|
19
|
+
*/
|
|
20
|
+
export declare function generatePhaseFiles(tasksDir: string, tasks: Task[], changeName: string): {
|
|
21
|
+
generatedFiles: string[];
|
|
22
|
+
allTaskIds: string[];
|
|
23
|
+
error?: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Generate manifest JSON file
|
|
27
|
+
*/
|
|
28
|
+
export declare function generateManifestFile(manifestPath: string, changeName: string, tasks: Task[], options?: {
|
|
29
|
+
type?: string;
|
|
30
|
+
priority?: string;
|
|
31
|
+
}): {
|
|
32
|
+
error?: string;
|
|
33
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* commands/tasks-gen/generators.ts
|
|
4
|
+
* Task file generation utilities
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.generatePhaseJson = generatePhaseJson;
|
|
41
|
+
exports.generateManifestJson = generateManifestJson;
|
|
42
|
+
exports.generatePhaseFiles = generatePhaseFiles;
|
|
43
|
+
exports.generateManifestFile = generateManifestFile;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
/**
|
|
47
|
+
* Generate a single phase JSON object
|
|
48
|
+
*/
|
|
49
|
+
function generatePhaseJson(task, changeName, allTaskIds = []) {
|
|
50
|
+
const dependencies = task.dependencies || [];
|
|
51
|
+
const invalidDependencies = dependencies.filter((depId) => !allTaskIds.includes(depId));
|
|
52
|
+
if (invalidDependencies.length > 0) {
|
|
53
|
+
console.warn(`[TASKS] Warning: Invalid dependencies found: ${invalidDependencies.join(', ')}`);
|
|
54
|
+
console.warn(`[TASKS] Available task IDs: ${allTaskIds.join(', ')}`);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
id: task.id,
|
|
58
|
+
type: task.type,
|
|
59
|
+
title: task.title,
|
|
60
|
+
priority: task.priority,
|
|
61
|
+
phase: task.phase,
|
|
62
|
+
dependencies: dependencies.filter((depId) => allTaskIds.includes(depId)),
|
|
63
|
+
docs_to_read: task.docs_to_read || [
|
|
64
|
+
`spec/changes/${changeName}/product-requirement.md`,
|
|
65
|
+
`spec/changes/${changeName}/design.md`,
|
|
66
|
+
],
|
|
67
|
+
spec: {
|
|
68
|
+
description: task.spec.description || task.title,
|
|
69
|
+
files: task.spec.files.length > 0 ? task.spec.files : ['src/README.md'],
|
|
70
|
+
context: task.spec.context || [],
|
|
71
|
+
},
|
|
72
|
+
acceptance_criteria: task.acceptance_criteria && task.acceptance_criteria.length > 0
|
|
73
|
+
? task.acceptance_criteria
|
|
74
|
+
: ['功能正常工作'],
|
|
75
|
+
implementation: task.implementation || {
|
|
76
|
+
steps: [],
|
|
77
|
+
notes: '',
|
|
78
|
+
},
|
|
79
|
+
validation: task.validation || {
|
|
80
|
+
commands: [],
|
|
81
|
+
manual_checks: [],
|
|
82
|
+
},
|
|
83
|
+
status: task.status,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Generate manifest JSON
|
|
88
|
+
*/
|
|
89
|
+
function generateManifestJson(changeName, tasks, options = {}) {
|
|
90
|
+
return {
|
|
91
|
+
version: '1.0',
|
|
92
|
+
taskId: changeName,
|
|
93
|
+
type: options.type || 'feat',
|
|
94
|
+
priority: options.priority || 'medium',
|
|
95
|
+
title: changeName,
|
|
96
|
+
changeName,
|
|
97
|
+
totalTasks: tasks.length,
|
|
98
|
+
phases: [...new Set(tasks.map((t) => t.phase))].sort((a, b) => a - b),
|
|
99
|
+
mergeStrategy: {
|
|
100
|
+
type: 'squash',
|
|
101
|
+
deleteBranch: true,
|
|
102
|
+
deleteWorktree: true,
|
|
103
|
+
},
|
|
104
|
+
createdAt: new Date().toISOString(),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Generate phase JSON files for all tasks
|
|
109
|
+
*/
|
|
110
|
+
function generatePhaseFiles(tasksDir, tasks, changeName) {
|
|
111
|
+
try {
|
|
112
|
+
fs.mkdirSync(tasksDir, { recursive: true });
|
|
113
|
+
const allTaskIds = tasks.map((t) => t.id);
|
|
114
|
+
const generatedFiles = [];
|
|
115
|
+
for (const task of tasks) {
|
|
116
|
+
const taskJsonPath = path.resolve(tasksDir, `${task.id}.json`);
|
|
117
|
+
const taskJson = generatePhaseJson(task, changeName, allTaskIds);
|
|
118
|
+
fs.writeFileSync(taskJsonPath, JSON.stringify(taskJson, null, 2), 'utf8');
|
|
119
|
+
generatedFiles.push(taskJsonPath);
|
|
120
|
+
}
|
|
121
|
+
return { generatedFiles, allTaskIds };
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
125
|
+
return { generatedFiles: [], allTaskIds: [], error: errorMessage };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Generate manifest JSON file
|
|
130
|
+
*/
|
|
131
|
+
function generateManifestFile(manifestPath, changeName, tasks, options = {}) {
|
|
132
|
+
try {
|
|
133
|
+
const manifestJson = generateManifestJson(changeName, tasks, options);
|
|
134
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifestJson, null, 2), 'utf8');
|
|
135
|
+
return {};
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
139
|
+
return { error: errorMessage };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* commands/tasks-gen/index.ts
|
|
3
|
+
* Generate PHASE-*.json files from product-requirement.md and design.md
|
|
4
|
+
* Supports AI input via stdin or --input parameter
|
|
5
|
+
*/
|
|
6
|
+
import { TasksGenOptions, TasksGenResult } from './types';
|
|
7
|
+
import { parseTasksMd } from './parsers';
|
|
8
|
+
import { generatePhaseJson, generateManifestJson } from './generators';
|
|
9
|
+
/**
|
|
10
|
+
* Generate task files from AI input or tasks.md
|
|
11
|
+
*/
|
|
12
|
+
export declare function generateTasks(options?: TasksGenOptions): Promise<TasksGenResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Main entry point
|
|
15
|
+
*/
|
|
16
|
+
export declare function main(): void;
|
|
17
|
+
declare const _default: {
|
|
18
|
+
generateTasks: typeof generateTasks;
|
|
19
|
+
parseTasksMd: typeof parseTasksMd;
|
|
20
|
+
generatePhaseJson: typeof generatePhaseJson;
|
|
21
|
+
generateManifestJson: typeof generateManifestJson;
|
|
22
|
+
TASK_SCHEMA: {
|
|
23
|
+
required: string[];
|
|
24
|
+
idPattern: RegExp;
|
|
25
|
+
types: string[];
|
|
26
|
+
priorities: string[];
|
|
27
|
+
statuses: string[];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export default _default;
|