@bicorne/task-flow 0.1.0 → 0.2.1
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.md +337 -145
- package/SKILL.md +9 -5
- package/assets/.harnessrc +0 -1
- package/dist/commands/analyze.js +160 -318
- package/dist/commands/archive.js +44 -48
- package/dist/commands/design.js +225 -400
- package/dist/commands/extract.js +174 -303
- package/dist/commands/init.js +103 -148
- package/dist/commands/merge/index.js +184 -295
- package/dist/commands/merge/merger.js +112 -134
- package/dist/commands/merge/types.js +3 -5
- package/dist/commands/merge/validators.js +115 -132
- package/dist/commands/merge.js +46 -13
- package/dist/commands/start.js +155 -248
- package/dist/commands/status.js +68 -129
- package/dist/commands/sync.js +37 -53
- package/dist/commands/tasks-gen/doc-parser.js +148 -228
- package/dist/commands/tasks-gen/generators.js +104 -116
- package/dist/commands/tasks-gen/index.js +206 -314
- package/dist/commands/tasks-gen/parsers.js +131 -232
- package/dist/commands/tasks-gen/templates.js +9 -10
- package/dist/commands/tasks-gen/types.js +36 -14
- package/dist/commands/tasks-gen/validators.js +33 -49
- package/dist/commands/tasks.js +58 -20
- package/dist/commands/worktree.js +167 -249
- package/dist/hooks/check-prd-exists.js +45 -55
- package/dist/hooks/check-worktree-conflict.js +68 -101
- package/dist/hooks/hook-runner/executor.js +134 -126
- package/dist/hooks/hook-runner/index.js +181 -196
- package/dist/hooks/hook-runner/loader.js +74 -113
- package/dist/hooks/hook-runner/types.js +3 -5
- package/dist/hooks/hook-runner.js +94 -28
- package/dist/hooks/phase-complete-detector.js +125 -191
- package/dist/hooks/phase-gate-validator.js +315 -376
- package/dist/hooks/save-checkpoint.js +87 -130
- package/dist/hooks/start-mcp-servers.js +50 -65
- package/dist/hooks/stop-mcp-servers.js +40 -49
- package/dist/index.js +84 -153
- package/dist/lib/archive.js +126 -209
- package/dist/lib/config.d.ts +0 -2
- package/dist/lib/config.js +141 -230
- package/dist/lib/constants.js +155 -145
- package/dist/lib/interactive.js +98 -148
- package/dist/lib/mcp-client.js +197 -320
- package/dist/lib/state.js +142 -253
- package/dist/slash/executor.js +309 -233
- package/dist/slash/index.js +69 -43
- package/dist/slash/parser.js +84 -97
- package/dist/slash/registry.js +100 -88
- package/dist/spec/openspec-to-task/builders.js +96 -109
- package/dist/spec/openspec-to-task/index.js +112 -173
- package/dist/spec/openspec-to-task/parsers.js +148 -219
- package/dist/spec/openspec-to-task/types.js +3 -5
- package/dist/spec/sync-openspec-to-task.js +47 -19
- package/dist/spec/sync-task-to-openspec.js +241 -272
- package/dist/types/ai-context.js +3 -8
- package/package.json +9 -7
- package/references/CLI-TUTORIAL.md +4 -10
package/dist/commands/design.js
CHANGED
|
@@ -1,77 +1,165 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
-
if (k2 === undefined) k2 = k;
|
|
13
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
-
}
|
|
17
|
-
Object.defineProperty(o, k2, desc);
|
|
18
|
-
}) : (function(o, m, k, k2) {
|
|
19
|
-
if (k2 === undefined) k2 = k;
|
|
20
|
-
o[k2] = m[k];
|
|
21
|
-
}));
|
|
22
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
-
}) : function(o, v) {
|
|
25
|
-
o["default"] = v;
|
|
26
|
-
});
|
|
27
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
-
var ownKeys = function(o) {
|
|
29
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
-
var ar = [];
|
|
31
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
-
return ar;
|
|
33
|
-
};
|
|
34
|
-
return ownKeys(o);
|
|
35
|
-
};
|
|
36
|
-
return function (mod) {
|
|
37
|
-
if (mod && mod.__esModule) return mod;
|
|
38
|
-
var result = {};
|
|
39
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
-
__setModuleDefault(result, mod);
|
|
41
|
-
return result;
|
|
1
|
+
function e(t) {
|
|
2
|
+
return "function" != typeof WeakMap ? null : (e = function(e) {
|
|
3
|
+
return new WeakMap();
|
|
4
|
+
})(t);
|
|
5
|
+
}
|
|
6
|
+
function t(t, r) {
|
|
7
|
+
var n, o, s;
|
|
8
|
+
if (!r && t && t.__esModule) return t;
|
|
9
|
+
if (null === t || "object" != typeof t && "function" != typeof t) return {
|
|
10
|
+
default: t
|
|
42
11
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
12
|
+
if ((n = e(r)) && n.has(t)) return n.get(t);
|
|
13
|
+
for(var i in o = {
|
|
14
|
+
__proto__: null
|
|
15
|
+
}, s = Object.defineProperty && Object.getOwnPropertyDescriptor, t)if ("default" !== i && Object.prototype.hasOwnProperty.call(t, i)) {
|
|
16
|
+
var c = s ? Object.getOwnPropertyDescriptor(t, i) : null;
|
|
17
|
+
c && (c.get || c.set) ? Object.defineProperty(o, i, c) : o[i] = t[i];
|
|
18
|
+
}
|
|
19
|
+
return o.default = t, n && n.set(t, o), o;
|
|
20
|
+
}
|
|
21
|
+
function r(e) {
|
|
22
|
+
let t = e.split(/\r?\n/), r = {
|
|
23
|
+
title: '',
|
|
24
|
+
background: '',
|
|
25
|
+
goals: [],
|
|
26
|
+
scope: []
|
|
27
|
+
}, n = '', o = [];
|
|
28
|
+
for (let e of t){
|
|
29
|
+
if (e.startsWith('# ')) {
|
|
30
|
+
r.title = e.replace(/^#\s+/, '').trim();
|
|
56
31
|
continue;
|
|
57
32
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (!next || next.startsWith('--')) {
|
|
61
|
-
args[key] = true;
|
|
33
|
+
if (e.startsWith('## ')) {
|
|
34
|
+
n && o.length > 0 && (r[n] = o.join('\n').trim()), n = e.replace(/^##\s+/, '').trim().toLowerCase().replace(/\s+/g, '_'), o = [];
|
|
62
35
|
continue;
|
|
63
36
|
}
|
|
64
|
-
|
|
65
|
-
|
|
37
|
+
n && o.push(e);
|
|
38
|
+
}
|
|
39
|
+
return n && o.length > 0 && (r[n] = o.join('\n').trim()), r;
|
|
40
|
+
}
|
|
41
|
+
function n(e) {
|
|
42
|
+
let t = {};
|
|
43
|
+
for (let [r, n] of Object.entries({
|
|
44
|
+
techStack: /技术栈?[::]\s*(.+)/i,
|
|
45
|
+
framework: /框架?[::]\s*(.+)/i,
|
|
46
|
+
library: /库?[::]\s*(.+)/i,
|
|
47
|
+
performance: /性能?[::]\s*(.+)/i,
|
|
48
|
+
architecture: /架构?[::]\s*(.+)/i,
|
|
49
|
+
constraint: /约束?[::]\s*(.+)/i,
|
|
50
|
+
requirement: /要求?[::]\s*(.+)/i
|
|
51
|
+
})){
|
|
52
|
+
let o = e.match(n);
|
|
53
|
+
o && o[1] && (t[r] = o[1].trim());
|
|
66
54
|
}
|
|
67
|
-
return
|
|
55
|
+
return t;
|
|
68
56
|
}
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
57
|
+
async function o() {
|
|
58
|
+
console.log('\n[DESIGN] No valid context information provided.'), console.log('[DESIGN] Please provide additional technical design information:\n');
|
|
59
|
+
let e = await (0, f.input)({
|
|
60
|
+
message: 'Technology stack preferences (optional)',
|
|
61
|
+
default: ''
|
|
62
|
+
}), t = await (0, f.input)({
|
|
63
|
+
message: 'Architecture constraints (optional)',
|
|
64
|
+
default: ''
|
|
65
|
+
}), r = await (0, f.input)({
|
|
66
|
+
message: 'Performance requirements (optional)',
|
|
67
|
+
default: ''
|
|
68
|
+
}), n = await (0, f.input)({
|
|
69
|
+
message: 'Known technical risks (optional)',
|
|
70
|
+
default: ''
|
|
71
|
+
}), o = [];
|
|
72
|
+
return e && o.push(`技术栈: ${e}`), t && o.push(`架构: ${t}`), r && o.push(`性能: ${r}`), n && o.push(`风险: ${n}`), o.join('\n');
|
|
73
|
+
}
|
|
74
|
+
async function s(e = {}) {
|
|
75
|
+
let t, i, c, a = (0, g.loadConfig)({
|
|
76
|
+
cwd: e.cwd
|
|
77
|
+
}), l = (c = String(e.change || '').trim().replace(/[^a-zA-Z0-9-_]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '')).includes('..') || c.startsWith('/') ? '' : c;
|
|
78
|
+
if (!l) return {
|
|
79
|
+
success: !1,
|
|
80
|
+
reason: 'missing-change',
|
|
81
|
+
message: 'Missing required argument: --change <change-name>'
|
|
82
|
+
};
|
|
83
|
+
let f = a.projectRoot ? {
|
|
84
|
+
valid: !0
|
|
85
|
+
} : {
|
|
86
|
+
valid: !1,
|
|
87
|
+
reason: 'missing-project-root',
|
|
88
|
+
message: 'Config missing projectRoot'
|
|
89
|
+
};
|
|
90
|
+
if (!f.valid) return {
|
|
91
|
+
success: !1,
|
|
92
|
+
reason: f.reason,
|
|
93
|
+
message: f.message || 'Unknown config validation error'
|
|
94
|
+
};
|
|
95
|
+
let m = a.projectRoot || process.cwd(), d = a.specRootAbs || p.resolve(m, 'spec'), h = p.resolve(d, 'changes', l), w = p.resolve(h, 'product-requirement.md'), y = p.resolve(h, 'design.md');
|
|
96
|
+
if (!u.existsSync(w)) return {
|
|
97
|
+
success: !1,
|
|
98
|
+
reason: 'prd-not-found',
|
|
99
|
+
message: `product-requirement.md not found. Please create it first at: ${w}`
|
|
100
|
+
};
|
|
101
|
+
let k = r(u.readFileSync(w, 'utf8'));
|
|
102
|
+
if (e.contextFile) try {
|
|
103
|
+
let r = u.readFileSync(e.contextFile, 'utf8');
|
|
104
|
+
t = JSON.parse(r);
|
|
105
|
+
} catch (t) {
|
|
106
|
+
let e = t instanceof Error ? t.message : 'Unknown error';
|
|
107
|
+
return {
|
|
108
|
+
success: !1,
|
|
109
|
+
reason: 'invalid-context-file',
|
|
110
|
+
message: `Failed to parse context file: ${e}`
|
|
111
|
+
};
|
|
73
112
|
}
|
|
74
|
-
|
|
113
|
+
let x = {}, v = '', j = e.input;
|
|
114
|
+
if (!j && !process.stdin.isTTY && require.main === module) try {
|
|
115
|
+
let e = await new Promise((e, t)=>{
|
|
116
|
+
let r = [];
|
|
117
|
+
process.stdin.setEncoding('utf8'), process.stdin.on('readable', ()=>{
|
|
118
|
+
let e;
|
|
119
|
+
for(; null !== (e = process.stdin.read());)r.push(e);
|
|
120
|
+
}), process.stdin.on('end', ()=>{
|
|
121
|
+
e(r.join(''));
|
|
122
|
+
}), process.stdin.on('error', (e)=>{
|
|
123
|
+
t(e);
|
|
124
|
+
}), setTimeout(()=>{
|
|
125
|
+
0 === r.length && t(Error('Stdin timeout: no data received'));
|
|
126
|
+
}, 5000);
|
|
127
|
+
});
|
|
128
|
+
e.trim() && (j = e, console.log(`[DESIGN] Received ${e.length} bytes from stdin`));
|
|
129
|
+
} catch (t) {
|
|
130
|
+
let e = t instanceof Error ? t.message : 'Unknown error';
|
|
131
|
+
console.warn(`[DESIGN] Warning: Failed to read stdin: ${e}`);
|
|
132
|
+
}
|
|
133
|
+
if (e.context && (x = n(e.context)), t?.project.techStack) {
|
|
134
|
+
let e = t.project.techStack;
|
|
135
|
+
e.language && (x.language = e.language), e.framework && (x.framework = e.framework), e.runtime && (x.architecture = e.runtime);
|
|
136
|
+
}
|
|
137
|
+
t?.analysis?.architectureSummary && (x.architecture = t.analysis.architectureSummary), t?.task?.constraints && t.task.constraints.length > 0 && (x.constraint = t.task.constraints.join('; '));
|
|
138
|
+
let S = Object.keys(x).length > 0, $ = process.stdin.isTTY, P = require.main === module, _ = !e.skipPrompt && P && $;
|
|
139
|
+
if (!j && !S && !e.input) {
|
|
140
|
+
if (_) (v = await o()) && (x = n(v));
|
|
141
|
+
else if (!e.skipPrompt) {
|
|
142
|
+
var b;
|
|
143
|
+
let e, t = (e = [], (b = x).techStack || b.framework || e.push('Technology stack preferences (e.g., React, Vue, Node.js)'), b.architecture || e.push('Architecture constraints (e.g., microservices, monolith)'), b.performance || e.push('Performance requirements (e.g., response time < 100ms)'), b.risks || e.push('Known technical risks'), {
|
|
144
|
+
needsInfo: e.length > 0,
|
|
145
|
+
prompts: e,
|
|
146
|
+
message: e.length > 0 ? `Missing context information. Please provide via --context or --context-file:\n${e.map((e, t)=>` ${t + 1}. ${e}`).join('\n')}` : ''
|
|
147
|
+
});
|
|
148
|
+
return {
|
|
149
|
+
success: !1,
|
|
150
|
+
reason: 'missing-context',
|
|
151
|
+
message: t.message,
|
|
152
|
+
needsContext: !0,
|
|
153
|
+
contextPrompt: t.prompts,
|
|
154
|
+
changeName: l,
|
|
155
|
+
changeDir: h
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (j) i = j;
|
|
160
|
+
else {
|
|
161
|
+
let e;
|
|
162
|
+
if (e = p.resolve(__dirname, '../../assets/design.md'), i = u.existsSync(e) ? u.readFileSync(e, 'utf8') : `# 技术规格文档
|
|
75
163
|
|
|
76
164
|
## 文档基础信息
|
|
77
165
|
|
|
@@ -140,353 +228,90 @@ function loadTemplate() {
|
|
|
140
228
|
|
|
141
229
|
### 扩展性设计
|
|
142
230
|
<!-- 描述如何支持未来的扩展需求 -->
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const sanitized = String(input || '')
|
|
147
|
-
.trim()
|
|
148
|
-
.replace(/[^a-zA-Z0-9-_]/g, '-')
|
|
149
|
-
.replace(/-+/g, '-')
|
|
150
|
-
.replace(/^-|-$/g, '');
|
|
151
|
-
if (sanitized.includes('..') || sanitized.startsWith('/')) {
|
|
152
|
-
return '';
|
|
153
|
-
}
|
|
154
|
-
return sanitized;
|
|
155
|
-
}
|
|
156
|
-
function validateConfig(config) {
|
|
157
|
-
if (!config.projectRoot) {
|
|
158
|
-
return {
|
|
159
|
-
valid: false,
|
|
160
|
-
reason: 'missing-project-root',
|
|
161
|
-
message: 'Config missing projectRoot',
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
return { valid: true };
|
|
165
|
-
}
|
|
166
|
-
function extractPRDInfo(prdContent) {
|
|
167
|
-
const lines = prdContent.split(/\r?\n/);
|
|
168
|
-
const info = {
|
|
169
|
-
title: '',
|
|
170
|
-
background: '',
|
|
171
|
-
goals: [],
|
|
172
|
-
scope: [],
|
|
173
|
-
};
|
|
174
|
-
let currentSection = '';
|
|
175
|
-
let currentContent = [];
|
|
176
|
-
for (const line of lines) {
|
|
177
|
-
if (line.startsWith('# ')) {
|
|
178
|
-
info.title = line.replace(/^#\s+/, '').trim();
|
|
179
|
-
continue;
|
|
231
|
+
`, k.title && (i = i.replace('- **需求名称**: [待填写]', `- **需求名称**: ${k.title}`)), x.techStack) {
|
|
232
|
+
let e = `### 核心技术栈\n${x.techStack}`;
|
|
233
|
+
i = i.replace('<!-- 列出本次需求涉及的核心技术及选型理由 -->', `${e}\n<!-- 列出本次需求涉及的核心技术及选型理由 -->`);
|
|
180
234
|
}
|
|
181
|
-
if (
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
currentSection = line.replace(/^##\s+/, '').trim().toLowerCase().replace(/\s+/g, '_');
|
|
186
|
-
currentContent = [];
|
|
187
|
-
continue;
|
|
235
|
+
if (x.architecture) {
|
|
236
|
+
let e = `### 架构约束\n${x.architecture}`;
|
|
237
|
+
i = i.replace('<!-- 描述模块划分及职责边界 -->', `${e}\n<!-- 描述模块划分及职责边界 -->`);
|
|
188
238
|
}
|
|
189
|
-
if (
|
|
190
|
-
|
|
239
|
+
if (x.performance) {
|
|
240
|
+
let e = `### 性能要求\n${x.performance}`;
|
|
241
|
+
i = i.replace('<!-- 描述性能指标和优化策略 -->', `${e}\n<!-- 描述性能指标和优化策略 -->`);
|
|
191
242
|
}
|
|
192
243
|
}
|
|
193
|
-
if (
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
function extractContextInfo(context) {
|
|
199
|
-
const info = {};
|
|
200
|
-
const patterns = {
|
|
201
|
-
techStack: /技术栈?[::]\s*(.+)/i,
|
|
202
|
-
framework: /框架?[::]\s*(.+)/i,
|
|
203
|
-
library: /库?[::]\s*(.+)/i,
|
|
204
|
-
performance: /性能?[::]\s*(.+)/i,
|
|
205
|
-
architecture: /架构?[::]\s*(.+)/i,
|
|
206
|
-
constraint: /约束?[::]\s*(.+)/i,
|
|
207
|
-
requirement: /要求?[::]\s*(.+)/i,
|
|
244
|
+
if (u.existsSync(y) && !e.force) return {
|
|
245
|
+
success: !1,
|
|
246
|
+
reason: 'already-exists',
|
|
247
|
+
message: `design.md already exists: ${y}. Use --force to overwrite.`
|
|
208
248
|
};
|
|
209
|
-
for (const [key, pattern] of Object.entries(patterns)) {
|
|
210
|
-
const match = context.match(pattern);
|
|
211
|
-
if (match && match[1]) {
|
|
212
|
-
info[key] = match[1].trim();
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
return info;
|
|
216
|
-
}
|
|
217
|
-
function readStdin() {
|
|
218
|
-
return new Promise((resolve, reject) => {
|
|
219
|
-
const chunks = [];
|
|
220
|
-
process.stdin.setEncoding('utf8');
|
|
221
|
-
process.stdin.on('readable', () => {
|
|
222
|
-
let chunk;
|
|
223
|
-
while ((chunk = process.stdin.read()) !== null) {
|
|
224
|
-
chunks.push(chunk);
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
process.stdin.on('end', () => {
|
|
228
|
-
resolve(chunks.join(''));
|
|
229
|
-
});
|
|
230
|
-
process.stdin.on('error', (error) => {
|
|
231
|
-
reject(error);
|
|
232
|
-
});
|
|
233
|
-
setTimeout(() => {
|
|
234
|
-
if (chunks.length === 0) {
|
|
235
|
-
reject(new Error('Stdin timeout: no data received'));
|
|
236
|
-
}
|
|
237
|
-
}, 5000);
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
function checkMissingContext(contextInfo) {
|
|
241
|
-
const prompts = [];
|
|
242
|
-
if (!contextInfo.techStack && !contextInfo.framework) {
|
|
243
|
-
prompts.push('Technology stack preferences (e.g., React, Vue, Node.js)');
|
|
244
|
-
}
|
|
245
|
-
if (!contextInfo.architecture) {
|
|
246
|
-
prompts.push('Architecture constraints (e.g., microservices, monolith)');
|
|
247
|
-
}
|
|
248
|
-
if (!contextInfo.performance) {
|
|
249
|
-
prompts.push('Performance requirements (e.g., response time < 100ms)');
|
|
250
|
-
}
|
|
251
|
-
if (!contextInfo.risks) {
|
|
252
|
-
prompts.push('Known technical risks');
|
|
253
|
-
}
|
|
254
|
-
return {
|
|
255
|
-
needsInfo: prompts.length > 0,
|
|
256
|
-
prompts,
|
|
257
|
-
message: prompts.length > 0
|
|
258
|
-
? `Missing context information. Please provide via --context or --context-file:\n${prompts.map((p, i) => ` ${i + 1}. ${p}`).join('\n')}`
|
|
259
|
-
: '',
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
async function promptForMissingInfo() {
|
|
263
|
-
console.log('\n[DESIGN] No valid context information provided.');
|
|
264
|
-
console.log('[DESIGN] Please provide additional technical design information:\n');
|
|
265
|
-
const techStack = await (0, interactive_1.input)({
|
|
266
|
-
message: 'Technology stack preferences (optional)',
|
|
267
|
-
default: '',
|
|
268
|
-
});
|
|
269
|
-
const architecture = await (0, interactive_1.input)({
|
|
270
|
-
message: 'Architecture constraints (optional)',
|
|
271
|
-
default: '',
|
|
272
|
-
});
|
|
273
|
-
const performance = await (0, interactive_1.input)({
|
|
274
|
-
message: 'Performance requirements (optional)',
|
|
275
|
-
default: '',
|
|
276
|
-
});
|
|
277
|
-
const risks = await (0, interactive_1.input)({
|
|
278
|
-
message: 'Known technical risks (optional)',
|
|
279
|
-
default: '',
|
|
280
|
-
});
|
|
281
|
-
const parts = [];
|
|
282
|
-
if (techStack) {
|
|
283
|
-
parts.push(`技术栈: ${techStack}`);
|
|
284
|
-
}
|
|
285
|
-
if (architecture) {
|
|
286
|
-
parts.push(`架构: ${architecture}`);
|
|
287
|
-
}
|
|
288
|
-
if (performance) {
|
|
289
|
-
parts.push(`性能: ${performance}`);
|
|
290
|
-
}
|
|
291
|
-
if (risks) {
|
|
292
|
-
parts.push(`风险: ${risks}`);
|
|
293
|
-
}
|
|
294
|
-
return parts.join('\n');
|
|
295
|
-
}
|
|
296
|
-
async function generateDesign(options = {}) {
|
|
297
|
-
const config = (0, config_1.loadConfig)({ cwd: options.cwd });
|
|
298
|
-
const changeName = toChangeName(options.change);
|
|
299
|
-
if (!changeName) {
|
|
300
|
-
return {
|
|
301
|
-
success: false,
|
|
302
|
-
reason: 'missing-change',
|
|
303
|
-
message: 'Missing required argument: --change <change-name>',
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
const configValidation = validateConfig(config);
|
|
307
|
-
if (!configValidation.valid) {
|
|
308
|
-
return {
|
|
309
|
-
success: false,
|
|
310
|
-
reason: configValidation.reason,
|
|
311
|
-
message: configValidation.message || 'Unknown config validation error',
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
const projectRoot = config.projectRoot || process.cwd();
|
|
315
|
-
const specRoot = config.specRootAbs || path.resolve(projectRoot, 'spec');
|
|
316
|
-
const changeDir = path.resolve(specRoot, 'changes', changeName);
|
|
317
|
-
const prdPath = path.resolve(changeDir, 'product-requirement.md');
|
|
318
|
-
const designPath = path.resolve(changeDir, 'design.md');
|
|
319
|
-
if (!fs.existsSync(prdPath)) {
|
|
320
|
-
return {
|
|
321
|
-
success: false,
|
|
322
|
-
reason: 'prd-not-found',
|
|
323
|
-
message: `product-requirement.md not found. Please create it first at: ${prdPath}`,
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
const prdContent = fs.readFileSync(prdPath, 'utf8');
|
|
327
|
-
const prdInfo = extractPRDInfo(prdContent);
|
|
328
|
-
let contextData;
|
|
329
|
-
if (options.contextFile) {
|
|
330
|
-
try {
|
|
331
|
-
const contextContent = fs.readFileSync(options.contextFile, 'utf8');
|
|
332
|
-
contextData = JSON.parse(contextContent);
|
|
333
|
-
}
|
|
334
|
-
catch (error) {
|
|
335
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
336
|
-
return {
|
|
337
|
-
success: false,
|
|
338
|
-
reason: 'invalid-context-file',
|
|
339
|
-
message: `Failed to parse context file: ${errorMessage}`,
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
let contextInfo = {};
|
|
344
|
-
let additionalContext = '';
|
|
345
|
-
let aiInput = options.input;
|
|
346
|
-
if (!aiInput && !process.stdin.isTTY && require.main === module) {
|
|
347
|
-
try {
|
|
348
|
-
const stdinContent = await readStdin();
|
|
349
|
-
if (stdinContent.trim()) {
|
|
350
|
-
aiInput = stdinContent;
|
|
351
|
-
console.log(`[DESIGN] Received ${stdinContent.length} bytes from stdin`);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
catch (error) {
|
|
355
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
356
|
-
console.warn(`[DESIGN] Warning: Failed to read stdin: ${errorMessage}`);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
if (options.context) {
|
|
360
|
-
contextInfo = extractContextInfo(options.context);
|
|
361
|
-
}
|
|
362
|
-
if (contextData?.project.techStack) {
|
|
363
|
-
const ts = contextData.project.techStack;
|
|
364
|
-
if (ts.language) {
|
|
365
|
-
contextInfo.language = ts.language;
|
|
366
|
-
}
|
|
367
|
-
if (ts.framework) {
|
|
368
|
-
contextInfo.framework = ts.framework;
|
|
369
|
-
}
|
|
370
|
-
if (ts.runtime) {
|
|
371
|
-
contextInfo.architecture = ts.runtime;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
if (contextData?.analysis?.architectureSummary) {
|
|
375
|
-
contextInfo.architecture = contextData.analysis.architectureSummary;
|
|
376
|
-
}
|
|
377
|
-
if (contextData?.task?.constraints && contextData.task.constraints.length > 0) {
|
|
378
|
-
contextInfo.constraint = contextData.task.constraints.join('; ');
|
|
379
|
-
}
|
|
380
|
-
const hasValidContext = Object.keys(contextInfo).length > 0;
|
|
381
|
-
const isTTY = process.stdin.isTTY;
|
|
382
|
-
const isMainModule = require.main === module;
|
|
383
|
-
const shouldPrompt = !options.skipPrompt && isMainModule && isTTY;
|
|
384
|
-
if (!aiInput && !hasValidContext && !options.input) {
|
|
385
|
-
if (shouldPrompt) {
|
|
386
|
-
additionalContext = await promptForMissingInfo();
|
|
387
|
-
if (additionalContext) {
|
|
388
|
-
contextInfo = extractContextInfo(additionalContext);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
else if (!options.skipPrompt) {
|
|
392
|
-
const missing = checkMissingContext(contextInfo);
|
|
393
|
-
return {
|
|
394
|
-
success: false,
|
|
395
|
-
reason: 'missing-context',
|
|
396
|
-
message: missing.message,
|
|
397
|
-
needsContext: true,
|
|
398
|
-
contextPrompt: missing.prompts,
|
|
399
|
-
changeName,
|
|
400
|
-
changeDir,
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
let designContent;
|
|
405
|
-
if (aiInput) {
|
|
406
|
-
designContent = aiInput;
|
|
407
|
-
}
|
|
408
|
-
else {
|
|
409
|
-
designContent = loadTemplate();
|
|
410
|
-
if (prdInfo.title) {
|
|
411
|
-
designContent = designContent.replace('- **需求名称**: [待填写]', `- **需求名称**: ${prdInfo.title}`);
|
|
412
|
-
}
|
|
413
|
-
if (contextInfo.techStack) {
|
|
414
|
-
const techSection = `### 核心技术栈\n${contextInfo.techStack}`;
|
|
415
|
-
designContent = designContent.replace('<!-- 列出本次需求涉及的核心技术及选型理由 -->', `${techSection}\n<!-- 列出本次需求涉及的核心技术及选型理由 -->`);
|
|
416
|
-
}
|
|
417
|
-
if (contextInfo.architecture) {
|
|
418
|
-
const archSection = `### 架构约束\n${contextInfo.architecture}`;
|
|
419
|
-
designContent = designContent.replace('<!-- 描述模块划分及职责边界 -->', `${archSection}\n<!-- 描述模块划分及职责边界 -->`);
|
|
420
|
-
}
|
|
421
|
-
if (contextInfo.performance) {
|
|
422
|
-
const perfSection = `### 性能要求\n${contextInfo.performance}`;
|
|
423
|
-
designContent = designContent.replace('<!-- 描述性能指标和优化策略 -->', `${perfSection}\n<!-- 描述性能指标和优化策略 -->`);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
if (fs.existsSync(designPath) && !options.force) {
|
|
427
|
-
return {
|
|
428
|
-
success: false,
|
|
429
|
-
reason: 'already-exists',
|
|
430
|
-
message: `design.md already exists: ${designPath}. Use --force to overwrite.`,
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
249
|
try {
|
|
434
|
-
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
250
|
+
u.writeFileSync(y, i, 'utf8');
|
|
251
|
+
} catch (t) {
|
|
252
|
+
let e = t instanceof Error ? t.message : 'Unknown error';
|
|
438
253
|
return {
|
|
439
|
-
success:
|
|
254
|
+
success: !1,
|
|
440
255
|
reason: 'file-write-error',
|
|
441
|
-
message: `Failed to write design.md: ${
|
|
256
|
+
message: `Failed to write design.md: ${e}`
|
|
442
257
|
};
|
|
443
258
|
}
|
|
444
259
|
return {
|
|
445
|
-
success:
|
|
446
|
-
changeName,
|
|
447
|
-
changeDir,
|
|
448
|
-
designPath,
|
|
449
|
-
prdInfo
|
|
260
|
+
success: !0,
|
|
261
|
+
changeName: l,
|
|
262
|
+
changeDir: h,
|
|
263
|
+
designPath: y,
|
|
264
|
+
prdInfo: k
|
|
450
265
|
};
|
|
451
266
|
}
|
|
452
|
-
async function
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
console.error(`[DESIGN] ${result.message}`);
|
|
465
|
-
if (result.reason === 'missing-context' && result.contextPrompt) {
|
|
466
|
-
console.error('\n[DESIGN] To provide context, use one of:');
|
|
467
|
-
console.error(' --context "技术栈: React, 架构: 微前端"');
|
|
468
|
-
console.error(' --context-file /path/to/context.json');
|
|
469
|
-
console.error(' --skip-prompt (generate template without context)');
|
|
267
|
+
async function i() {
|
|
268
|
+
let e = function(e) {
|
|
269
|
+
let t = {};
|
|
270
|
+
for(let r = 2; r < e.length; r += 1){
|
|
271
|
+
let n = e[r] || '';
|
|
272
|
+
if (!n.startsWith('--')) continue;
|
|
273
|
+
let o = n.slice(2), s = e[r + 1] || '';
|
|
274
|
+
if (!s || s.startsWith('--')) {
|
|
275
|
+
t[o] = !0;
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
t[o] = s, r += 1;
|
|
470
279
|
}
|
|
471
|
-
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
console.log(' 2. Run: task-flow tasks --change <change-name>');
|
|
482
|
-
console.log('');
|
|
483
|
-
process.exit(0);
|
|
484
|
-
}
|
|
485
|
-
if (require.main === module) {
|
|
486
|
-
main();
|
|
280
|
+
return t;
|
|
281
|
+
}(process.argv), t = await s({
|
|
282
|
+
cwd: e.cwd,
|
|
283
|
+
change: e.change,
|
|
284
|
+
force: !0 === e.force,
|
|
285
|
+
input: e.input,
|
|
286
|
+
context: e.context,
|
|
287
|
+
contextFile: e['context-file'],
|
|
288
|
+
skipPrompt: !0 === e['skip-prompt']
|
|
289
|
+
});
|
|
290
|
+
t.success || (console.error(`[DESIGN] ${t.message}`), 'missing-context' === t.reason && t.contextPrompt && (console.error('\n[DESIGN] To provide context, use one of:'), console.error(' --context "技术栈: React, 架构: 微前端"'), console.error(' --context-file /path/to/context.json'), console.error(' --skip-prompt (generate template without context)')), process.exit(1)), console.log(''), console.log('[DESIGN] Technical specification generated successfully!'), console.log(` Change Name: ${t.changeName}`), console.log(` Directory: ${t.changeDir}`), console.log(` Design: ${t.designPath}`), console.log(''), console.log('Next steps:'), console.log(' 1. Review and edit design.md'), console.log(' 2. Run: task-flow tasks --change <change-name>'), console.log(''), process.exit(0);
|
|
487
291
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
292
|
+
"use strict";
|
|
293
|
+
Object.defineProperty(exports, "__esModule", {
|
|
294
|
+
value: !0
|
|
295
|
+
});
|
|
296
|
+
var c = exports, a = {
|
|
297
|
+
get default () {
|
|
298
|
+
return m;
|
|
299
|
+
},
|
|
300
|
+
get generateDesign () {
|
|
301
|
+
return s;
|
|
302
|
+
},
|
|
303
|
+
get main () {
|
|
304
|
+
return i;
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
for(var l in a)Object.defineProperty(c, l, {
|
|
308
|
+
enumerable: !0,
|
|
309
|
+
get: Object.getOwnPropertyDescriptor(a, l).get
|
|
310
|
+
});
|
|
311
|
+
let u = /*#__PURE__*/ t(require("fs")), p = /*#__PURE__*/ t(require("path")), g = require("../lib/config"), f = require("../lib/interactive");
|
|
312
|
+
require.main === module && i();
|
|
313
|
+
let m = {
|
|
314
|
+
generateDesign: s,
|
|
315
|
+
extractPRDInfo: r,
|
|
316
|
+
main: i
|
|
492
317
|
};
|