pm-workflow-studio 0.1.3 → 0.1.4
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/bin/pmflow.js +53 -33
- package/package.json +1 -1
package/bin/pmflow.js
CHANGED
|
@@ -69,6 +69,12 @@ const color = {
|
|
|
69
69
|
bold: (value) => (useColor ? `\u001b[1m${value}\u001b[0m` : value),
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
+
const symbol = {
|
|
73
|
+
pointer: useColor ? color.cyan("?") : "?",
|
|
74
|
+
done: useColor ? color.green("✔") : "✔",
|
|
75
|
+
arrow: useColor ? color.cyan("›") : "›",
|
|
76
|
+
};
|
|
77
|
+
|
|
72
78
|
function exists(target) {
|
|
73
79
|
return fs.existsSync(target);
|
|
74
80
|
}
|
|
@@ -179,55 +185,68 @@ function createPrompt() {
|
|
|
179
185
|
|
|
180
186
|
function printInteractiveHeader() {
|
|
181
187
|
console.log("");
|
|
182
|
-
console.log(color.
|
|
183
|
-
console.log(color.
|
|
184
|
-
console.log(color.cyan("│") + " 交互式创建产品工作室,命令参数仍然可用 " + color.cyan("│"));
|
|
185
|
-
console.log(color.cyan("└────────────────────────────────────────────┘"));
|
|
188
|
+
console.log(color.bold("PM Workflow Studio"));
|
|
189
|
+
console.log(color.dim("Create a Codex or Claude Code product workspace."));
|
|
186
190
|
console.log("");
|
|
187
191
|
}
|
|
188
192
|
|
|
189
|
-
function
|
|
190
|
-
|
|
191
|
-
|
|
193
|
+
function promptLine(label, defaultValue) {
|
|
194
|
+
const suffix = defaultValue ? ` ${color.dim(`(${defaultValue})`)}` : "";
|
|
195
|
+
return `${symbol.pointer} ${label}${suffix} ${symbol.arrow} `;
|
|
192
196
|
}
|
|
193
197
|
|
|
194
|
-
function
|
|
195
|
-
|
|
198
|
+
function printAnswer(label, value) {
|
|
199
|
+
console.log(`${symbol.done} ${label}: ${color.green(value)}`);
|
|
196
200
|
}
|
|
197
201
|
|
|
198
202
|
async function askText(prompt, label, defaultValue) {
|
|
199
|
-
const answer = await prompt.ask(
|
|
200
|
-
|
|
203
|
+
const answer = await prompt.ask(promptLine(label, defaultValue));
|
|
204
|
+
const value = answer || defaultValue;
|
|
205
|
+
printAnswer(label, value);
|
|
206
|
+
return value;
|
|
201
207
|
}
|
|
202
208
|
|
|
203
209
|
async function askAi(prompt, defaultValue) {
|
|
204
210
|
const choices = [
|
|
205
|
-
["1", "auto", "
|
|
206
|
-
["2", "codex", "
|
|
207
|
-
["3", "claude", "
|
|
211
|
+
["1", "auto", "Auto, choose by target directory"],
|
|
212
|
+
["2", "codex", "Codex, generate .codex + .agents"],
|
|
213
|
+
["3", "claude", "Claude Code, generate .claude"],
|
|
208
214
|
];
|
|
209
215
|
|
|
210
216
|
while (true) {
|
|
217
|
+
console.log(`${symbol.pointer} Select AI workspace ${color.dim(`(${defaultValue})`)}`);
|
|
211
218
|
for (const [key, value, description] of choices) {
|
|
212
|
-
const marker = value === defaultValue ? color.
|
|
219
|
+
const marker = value === defaultValue ? color.dim(" (default)") : "";
|
|
213
220
|
console.log(` ${key}. ${value.padEnd(6)} ${color.dim(description)}${marker}`);
|
|
214
221
|
}
|
|
215
|
-
const answer = await prompt.ask(
|
|
222
|
+
const answer = await prompt.ask(` ${symbol.arrow} `);
|
|
216
223
|
const normalized = answer ? answer.toLowerCase() : defaultValue;
|
|
217
224
|
const matched = choices.find(([key, value]) => normalized === key || normalized === value);
|
|
218
|
-
if (matched)
|
|
219
|
-
|
|
225
|
+
if (matched) {
|
|
226
|
+
printAnswer("AI workspace", matched[1]);
|
|
227
|
+
return matched[1];
|
|
228
|
+
}
|
|
229
|
+
console.log(color.dim(" Enter 1/2/3, or auto/codex/claude."));
|
|
220
230
|
}
|
|
221
231
|
}
|
|
222
232
|
|
|
223
233
|
async function askConfirm(prompt, label, defaultValue = true) {
|
|
224
234
|
const suffix = defaultValue ? "Y/n" : "y/N";
|
|
225
235
|
while (true) {
|
|
226
|
-
const answer = (await prompt.ask(
|
|
227
|
-
if (!answer)
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
236
|
+
const answer = (await prompt.ask(promptLine(label, suffix))).toLowerCase();
|
|
237
|
+
if (!answer) {
|
|
238
|
+
printAnswer(label, defaultValue ? "yes" : "no");
|
|
239
|
+
return defaultValue;
|
|
240
|
+
}
|
|
241
|
+
if (["y", "yes", "是", "确认"].includes(answer)) {
|
|
242
|
+
printAnswer(label, "yes");
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
if (["n", "no", "否", "取消"].includes(answer)) {
|
|
246
|
+
printAnswer(label, "no");
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
console.log(color.dim(" Enter y or n."));
|
|
231
250
|
}
|
|
232
251
|
}
|
|
233
252
|
|
|
@@ -240,20 +259,21 @@ async function runInteractiveInit(seedOptions = {}) {
|
|
|
240
259
|
try {
|
|
241
260
|
printInteractiveHeader();
|
|
242
261
|
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
const root = await askText(prompt, "项目目录", seedOptions.root || ".");
|
|
262
|
+
const name = await askText(prompt, "What is your product named?", seedOptions.name || "My Product");
|
|
263
|
+
const root = await askText(prompt, "Where should the project be created?", seedOptions.root || ".");
|
|
246
264
|
|
|
247
|
-
printStep(2, "AI 工作区结构");
|
|
248
265
|
const ai = await askAi(prompt, seedOptions.ai || "auto");
|
|
249
266
|
|
|
250
|
-
|
|
251
|
-
console.log(
|
|
252
|
-
console.log(`
|
|
253
|
-
console.log(`
|
|
254
|
-
|
|
267
|
+
console.log("");
|
|
268
|
+
console.log(color.bold("Summary"));
|
|
269
|
+
console.log(` Product: ${color.green(name)}`);
|
|
270
|
+
console.log(` Directory: ${color.green(path.resolve(root))}`);
|
|
271
|
+
console.log(` Workspace: ${color.green(ai)}`);
|
|
272
|
+
console.log("");
|
|
273
|
+
|
|
274
|
+
const confirmed = await askConfirm(prompt, "Create this workspace?", true);
|
|
255
275
|
if (!confirmed) {
|
|
256
|
-
console.log("
|
|
276
|
+
console.log(color.dim("Canceled."));
|
|
257
277
|
return;
|
|
258
278
|
}
|
|
259
279
|
|