grimoire-wizard 0.5.1 → 0.6.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.md +66 -51
- package/dist/cli.js +509 -70
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +114 -12
- package/dist/index.js +511 -71
- package/dist/index.js.map +1 -1
- package/examples/yaml/demo.yaml +54 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -42,7 +42,7 @@ function parseWizardConfig(raw) {
|
|
|
42
42
|
const result = wizardConfigSchema.parse(raw);
|
|
43
43
|
return result;
|
|
44
44
|
}
|
|
45
|
-
var conditionSchema, validationRuleSchema, selectOptionSchema, separatorOptionSchema, selectChoiceSchema, baseStepFields, textStepSchema, selectStepSchema, multiSelectStepSchema, confirmStepSchema, passwordStepSchema, numberStepSchema, searchStepSchema, editorStepSchema, pathStepSchema, toggleStepSchema, messageStepSchema, noteStepSchema, stepConfigSchema, hexColorSchema, themeConfigSchema, preFlightCheckSchema, actionConfigSchema, wizardConfigSchema;
|
|
45
|
+
var conditionSchema, validationRuleSchema, selectOptionSchema, separatorOptionSchema, selectChoiceSchema, stepReviewConfigSchema, baseStepFields, textStepSchema, selectStepSchema, multiSelectStepSchema, confirmStepSchema, passwordStepSchema, numberStepSchema, searchStepSchema, editorStepSchema, pathStepSchema, toggleStepSchema, messageStepSchema, noteStepSchema, browserStepSchema, stepConfigSchema, hexColorSchema, progressBarConfigSchema, themeConfigSchema, preFlightCheckSchema, actionConfigSchema, wizardConfigSchema;
|
|
46
46
|
var init_schema = __esm({
|
|
47
47
|
"src/schema.ts"() {
|
|
48
48
|
"use strict";
|
|
@@ -90,6 +90,11 @@ var init_schema = __esm({
|
|
|
90
90
|
separator: z.string()
|
|
91
91
|
});
|
|
92
92
|
selectChoiceSchema = z.union([selectOptionSchema, separatorOptionSchema]);
|
|
93
|
+
stepReviewConfigSchema = z.object({
|
|
94
|
+
hide: z.boolean().optional(),
|
|
95
|
+
label: z.string().optional(),
|
|
96
|
+
format: z.enum(["none", "uppercase", "lowercase", "capitalize"]).optional()
|
|
97
|
+
}).optional();
|
|
93
98
|
baseStepFields = {
|
|
94
99
|
id: z.string(),
|
|
95
100
|
message: z.string(),
|
|
@@ -98,7 +103,8 @@ var init_schema = __esm({
|
|
|
98
103
|
when: conditionSchema.optional(),
|
|
99
104
|
keepValuesOnPrevious: z.boolean().optional(),
|
|
100
105
|
required: z.boolean().optional(),
|
|
101
|
-
group: z.string().optional()
|
|
106
|
+
group: z.string().optional(),
|
|
107
|
+
review: stepReviewConfigSchema
|
|
102
108
|
};
|
|
103
109
|
textStepSchema = z.object({
|
|
104
110
|
...baseStepFields,
|
|
@@ -115,7 +121,8 @@ var init_schema = __esm({
|
|
|
115
121
|
default: z.string().optional(),
|
|
116
122
|
routes: z.record(z.string(), z.string()).optional(),
|
|
117
123
|
pageSize: z.number().int().positive().optional(),
|
|
118
|
-
loop: z.boolean().optional()
|
|
124
|
+
loop: z.boolean().optional(),
|
|
125
|
+
columns: z.number().int().min(1).max(8).optional()
|
|
119
126
|
});
|
|
120
127
|
multiSelectStepSchema = z.object({
|
|
121
128
|
...baseStepFields,
|
|
@@ -126,7 +133,8 @@ var init_schema = __esm({
|
|
|
126
133
|
min: z.number().int().nonnegative().optional(),
|
|
127
134
|
max: z.number().int().positive().optional(),
|
|
128
135
|
pageSize: z.number().int().positive().optional(),
|
|
129
|
-
loop: z.boolean().optional()
|
|
136
|
+
loop: z.boolean().optional(),
|
|
137
|
+
columns: z.number().int().min(1).max(8).optional()
|
|
130
138
|
});
|
|
131
139
|
confirmStepSchema = z.object({
|
|
132
140
|
...baseStepFields,
|
|
@@ -154,7 +162,8 @@ var init_schema = __esm({
|
|
|
154
162
|
default: z.string().optional(),
|
|
155
163
|
placeholder: z.string().optional(),
|
|
156
164
|
pageSize: z.number().int().positive().optional(),
|
|
157
|
-
loop: z.boolean().optional()
|
|
165
|
+
loop: z.boolean().optional(),
|
|
166
|
+
columns: z.number().int().min(1).max(8).optional()
|
|
158
167
|
});
|
|
159
168
|
editorStepSchema = z.object({
|
|
160
169
|
...baseStepFields,
|
|
@@ -182,7 +191,14 @@ var init_schema = __esm({
|
|
|
182
191
|
});
|
|
183
192
|
noteStepSchema = z.object({
|
|
184
193
|
...baseStepFields,
|
|
185
|
-
type: z.literal("note")
|
|
194
|
+
type: z.literal("note"),
|
|
195
|
+
style: z.enum(["info", "warning", "error", "success", "code", "banner"]).optional()
|
|
196
|
+
});
|
|
197
|
+
browserStepSchema = z.object({
|
|
198
|
+
...baseStepFields,
|
|
199
|
+
type: z.literal("browser"),
|
|
200
|
+
url: z.string(),
|
|
201
|
+
fallback: z.string().optional()
|
|
186
202
|
});
|
|
187
203
|
stepConfigSchema = z.discriminatedUnion("type", [
|
|
188
204
|
textStepSchema,
|
|
@@ -196,12 +212,19 @@ var init_schema = __esm({
|
|
|
196
212
|
pathStepSchema,
|
|
197
213
|
toggleStepSchema,
|
|
198
214
|
messageStepSchema,
|
|
199
|
-
noteStepSchema
|
|
215
|
+
noteStepSchema,
|
|
216
|
+
browserStepSchema
|
|
200
217
|
]);
|
|
201
218
|
hexColorSchema = z.string().regex(
|
|
202
219
|
/^#[0-9a-fA-F]{6}$/,
|
|
203
220
|
"Must be a 6-digit hex color (e.g., #FF0000)"
|
|
204
221
|
);
|
|
222
|
+
progressBarConfigSchema = z.object({
|
|
223
|
+
width: z.number().int().positive().max(200).optional(),
|
|
224
|
+
filledColor: hexColorSchema.optional(),
|
|
225
|
+
emptyColor: hexColorSchema.optional(),
|
|
226
|
+
style: z.enum(["blocks", "line", "dots", "arrow"]).optional()
|
|
227
|
+
}).optional();
|
|
205
228
|
themeConfigSchema = z.object({
|
|
206
229
|
preset: z.enum(["default", "catppuccin", "dracula", "nord", "tokyonight", "monokai"]).optional(),
|
|
207
230
|
tokens: z.object({
|
|
@@ -211,7 +234,12 @@ var init_schema = __esm({
|
|
|
211
234
|
warning: hexColorSchema.optional(),
|
|
212
235
|
info: hexColorSchema.optional(),
|
|
213
236
|
muted: hexColorSchema.optional(),
|
|
214
|
-
accent: hexColorSchema.optional()
|
|
237
|
+
accent: hexColorSchema.optional(),
|
|
238
|
+
highlight: hexColorSchema.optional(),
|
|
239
|
+
highlightBg: hexColorSchema.optional(),
|
|
240
|
+
pointer: hexColorSchema.optional(),
|
|
241
|
+
checked: hexColorSchema.optional(),
|
|
242
|
+
dimmed: hexColorSchema.optional()
|
|
215
243
|
}).optional(),
|
|
216
244
|
icons: z.object({
|
|
217
245
|
step: z.string().optional(),
|
|
@@ -225,12 +253,15 @@ var init_schema = __esm({
|
|
|
225
253
|
frames: z.array(z.string()).min(1),
|
|
226
254
|
interval: z.number().positive().optional()
|
|
227
255
|
})
|
|
228
|
-
]).optional()
|
|
256
|
+
]).optional(),
|
|
257
|
+
spinnerElapsed: z.boolean().optional(),
|
|
258
|
+
progressBar: progressBarConfigSchema
|
|
229
259
|
});
|
|
230
260
|
preFlightCheckSchema = z.object({
|
|
231
261
|
name: z.string(),
|
|
232
262
|
run: z.string(),
|
|
233
|
-
message: z.string()
|
|
263
|
+
message: z.string(),
|
|
264
|
+
showOutput: z.boolean().optional()
|
|
234
265
|
});
|
|
235
266
|
actionConfigSchema = z.object({
|
|
236
267
|
name: z.string().optional(),
|
|
@@ -243,7 +274,13 @@ var init_schema = __esm({
|
|
|
243
274
|
version: z.string().optional(),
|
|
244
275
|
description: z.string().optional(),
|
|
245
276
|
review: z.boolean().optional(),
|
|
246
|
-
icon: z.string().optional()
|
|
277
|
+
icon: z.string().optional(),
|
|
278
|
+
iconSize: z.union([z.enum(["small", "medium", "large"]), z.number().int().positive()]).optional(),
|
|
279
|
+
font: z.string().min(1).optional(),
|
|
280
|
+
banner: z.union([z.string(), z.function()]).optional(),
|
|
281
|
+
subtitle: z.string().optional(),
|
|
282
|
+
clearBetweenSteps: z.boolean().optional(),
|
|
283
|
+
checksStyle: z.enum(["spinner", "tasklist"]).optional()
|
|
247
284
|
}),
|
|
248
285
|
theme: themeConfigSchema.optional(),
|
|
249
286
|
steps: z.array(stepConfigSchema).min(1),
|
|
@@ -501,6 +538,7 @@ async function loadWithInheritance(filePath, seen) {
|
|
|
501
538
|
async function loadWizardConfig(filePath) {
|
|
502
539
|
const config = await loadWithInheritance(filePath, /* @__PURE__ */ new Set());
|
|
503
540
|
detectCycles(config);
|
|
541
|
+
config._configFilePath = resolve(filePath);
|
|
504
542
|
return config;
|
|
505
543
|
}
|
|
506
544
|
function parseWizardYAML(yamlString) {
|
|
@@ -713,7 +751,8 @@ function wizardReducer(state, transition, config) {
|
|
|
713
751
|
errors: { ...state.errors, [state.currentStepId]: validationError }
|
|
714
752
|
};
|
|
715
753
|
}
|
|
716
|
-
const
|
|
754
|
+
const isDisplayOnly = currentStep.type === "note" || currentStep.type === "message" || currentStep.type === "browser";
|
|
755
|
+
const updatedAnswers = isDisplayOnly ? { ...state.answers } : {
|
|
717
756
|
...state.answers,
|
|
718
757
|
[state.currentStepId]: transition.value
|
|
719
758
|
};
|
|
@@ -921,7 +960,12 @@ var DEFAULT_TOKENS = {
|
|
|
921
960
|
warning: "#FFD93D",
|
|
922
961
|
info: "#4D96FF",
|
|
923
962
|
muted: "#888888",
|
|
924
|
-
accent: "#C084FC"
|
|
963
|
+
accent: "#C084FC",
|
|
964
|
+
highlight: "#5B9BD5",
|
|
965
|
+
highlightBg: "#1E1E2E",
|
|
966
|
+
pointer: "#C084FC",
|
|
967
|
+
checked: "#6BCB77",
|
|
968
|
+
dimmed: "#555555"
|
|
925
969
|
};
|
|
926
970
|
var DEFAULT_ICONS = {
|
|
927
971
|
step: "\u25CF",
|
|
@@ -929,6 +973,25 @@ var DEFAULT_ICONS = {
|
|
|
929
973
|
stepPending: "\u25CB",
|
|
930
974
|
pointer: "\u203A"
|
|
931
975
|
};
|
|
976
|
+
var PROGRESS_BAR_CHARS = {
|
|
977
|
+
blocks: { filled: "\u2588", empty: "\u2591" },
|
|
978
|
+
line: { filled: "\u2500", empty: "\u2500" },
|
|
979
|
+
dots: { filled: "\u2022", empty: "\xB7" },
|
|
980
|
+
arrow: { filled: "\u2550", empty: "\u2500" }
|
|
981
|
+
};
|
|
982
|
+
function resolveProgressBar(config, tokens) {
|
|
983
|
+
const style = config?.style ?? "blocks";
|
|
984
|
+
const chars = PROGRESS_BAR_CHARS[style];
|
|
985
|
+
const filledHex = config?.filledColor ?? tokens?.success ?? DEFAULT_TOKENS.success;
|
|
986
|
+
const emptyHex = config?.emptyColor ?? tokens?.muted ?? DEFAULT_TOKENS.muted;
|
|
987
|
+
return {
|
|
988
|
+
width: config?.width ?? 20,
|
|
989
|
+
filledColor: chalk.hex(filledHex),
|
|
990
|
+
emptyColor: chalk.hex(emptyHex),
|
|
991
|
+
style,
|
|
992
|
+
chars
|
|
993
|
+
};
|
|
994
|
+
}
|
|
932
995
|
function resolveTheme(themeConfig) {
|
|
933
996
|
const presetTokens = themeConfig?.preset ? THEME_PRESETS[themeConfig.preset] : void 0;
|
|
934
997
|
const tokens = { ...DEFAULT_TOKENS, ...presetTokens, ...themeConfig?.tokens };
|
|
@@ -941,9 +1004,16 @@ function resolveTheme(themeConfig) {
|
|
|
941
1004
|
info: chalk.hex(tokens.info),
|
|
942
1005
|
muted: chalk.hex(tokens.muted),
|
|
943
1006
|
accent: chalk.hex(tokens.accent),
|
|
1007
|
+
highlight: chalk.hex(tokens.highlight),
|
|
1008
|
+
highlightBg: chalk.bgHex(tokens.highlightBg),
|
|
1009
|
+
pointer: chalk.hex(tokens.pointer),
|
|
1010
|
+
checked: chalk.hex(tokens.checked),
|
|
1011
|
+
dimmed: chalk.hex(tokens.dimmed),
|
|
944
1012
|
bold: chalk.bold,
|
|
945
1013
|
icons,
|
|
946
|
-
spinner: resolveSpinner(themeConfig?.spinner)
|
|
1014
|
+
spinner: resolveSpinner(themeConfig?.spinner),
|
|
1015
|
+
spinnerElapsed: themeConfig?.spinnerElapsed ?? false,
|
|
1016
|
+
progressBar: resolveProgressBar(themeConfig?.progressBar, tokens)
|
|
947
1017
|
};
|
|
948
1018
|
}
|
|
949
1019
|
|
|
@@ -969,7 +1039,7 @@ function resolveEnvDefaultBoolean(value) {
|
|
|
969
1039
|
}
|
|
970
1040
|
|
|
971
1041
|
// src/runner.ts
|
|
972
|
-
import { execSync } from "child_process";
|
|
1042
|
+
import { execSync, execFileSync } from "child_process";
|
|
973
1043
|
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
974
1044
|
import { pathToFileURL } from "url";
|
|
975
1045
|
|
|
@@ -987,11 +1057,11 @@ import {
|
|
|
987
1057
|
} from "@inquirer/prompts";
|
|
988
1058
|
var InquirerRenderer = class {
|
|
989
1059
|
renderStepHeader(stepIndex, totalVisible, message, theme, description) {
|
|
990
|
-
const
|
|
991
|
-
const filledCount = totalVisible > 0 ? Math.round(stepIndex / totalVisible *
|
|
992
|
-
const remainingCount =
|
|
993
|
-
const filledBar =
|
|
994
|
-
const remainingBar =
|
|
1060
|
+
const pb = theme.progressBar;
|
|
1061
|
+
const filledCount = totalVisible > 0 ? Math.round(stepIndex / totalVisible * pb.width) : 0;
|
|
1062
|
+
const remainingCount = pb.width - filledCount;
|
|
1063
|
+
const filledBar = pb.filledColor(pb.chars.filled.repeat(filledCount));
|
|
1064
|
+
const remainingBar = pb.emptyColor(pb.chars.empty.repeat(remainingCount));
|
|
995
1065
|
const counter = theme.muted(`Step ${String(stepIndex + 1)}/${String(totalVisible)}`);
|
|
996
1066
|
const stepMessage = theme.muted(`\u2014 ${message}`);
|
|
997
1067
|
console.log(`
|
|
@@ -1000,6 +1070,39 @@ var InquirerRenderer = class {
|
|
|
1000
1070
|
console.log(` ${theme.muted(description)}`);
|
|
1001
1071
|
}
|
|
1002
1072
|
}
|
|
1073
|
+
renderNote(step, theme) {
|
|
1074
|
+
const title = step.message;
|
|
1075
|
+
const body = step.description ?? "";
|
|
1076
|
+
const style = step.style ?? "info";
|
|
1077
|
+
const { colorFn, icon } = getNoteStyleConfig(style, theme);
|
|
1078
|
+
if (style === "banner") {
|
|
1079
|
+
const width = Math.max(4, (process.stdout.columns ?? 60) - 4);
|
|
1080
|
+
const rule = colorFn("\u2500".repeat(width));
|
|
1081
|
+
console.log();
|
|
1082
|
+
console.log(` ${rule}`);
|
|
1083
|
+
console.log(` ${colorFn(icon)} ${theme.bold(title)}`);
|
|
1084
|
+
if (body) console.log(` ${theme.muted(body)}`);
|
|
1085
|
+
console.log(` ${rule}`);
|
|
1086
|
+
console.log();
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
const border = colorFn("\u2502");
|
|
1090
|
+
const topRule = colorFn(`\u250C${"\u2500".repeat(2)}`);
|
|
1091
|
+
const bottomRule = colorFn(`\u2514${"\u2500".repeat(2)}`);
|
|
1092
|
+
console.log();
|
|
1093
|
+
console.log(` ${topRule} ${colorFn(icon)} ${theme.bold(title)}`);
|
|
1094
|
+
if (body) {
|
|
1095
|
+
for (const line of body.split("\n")) {
|
|
1096
|
+
if (style === "code") {
|
|
1097
|
+
console.log(` ${border} ${theme.muted(line)}`);
|
|
1098
|
+
} else {
|
|
1099
|
+
console.log(` ${border} ${line}`);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
console.log(` ${bottomRule}`);
|
|
1104
|
+
console.log();
|
|
1105
|
+
}
|
|
1003
1106
|
async renderText(step, state, theme) {
|
|
1004
1107
|
const existingAnswer = state.answers[step.id];
|
|
1005
1108
|
const defaultValue = typeof existingAnswer === "string" ? existingAnswer : step.default;
|
|
@@ -1012,7 +1115,7 @@ var InquirerRenderer = class {
|
|
|
1012
1115
|
async renderSelect(step, state, theme) {
|
|
1013
1116
|
const existingAnswer = state.answers[step.id];
|
|
1014
1117
|
const defaultValue = typeof existingAnswer === "string" ? existingAnswer : step.default;
|
|
1015
|
-
const
|
|
1118
|
+
const rawChoices = step.options.map((opt) => {
|
|
1016
1119
|
if ("separator" in opt) {
|
|
1017
1120
|
return new Separator(opt.separator);
|
|
1018
1121
|
}
|
|
@@ -1023,19 +1126,27 @@ var InquirerRenderer = class {
|
|
|
1023
1126
|
disabled: opt.disabled
|
|
1024
1127
|
};
|
|
1025
1128
|
});
|
|
1129
|
+
const itemChoices = rawChoices.filter((c) => !(c instanceof Separator));
|
|
1130
|
+
const columnedItems = step.columns ? applyColumns(itemChoices, step.columns) : itemChoices;
|
|
1131
|
+
let itemIdx = 0;
|
|
1132
|
+
const choices = rawChoices.map((c) => c instanceof Separator ? c : columnedItems[itemIdx++] ?? c);
|
|
1026
1133
|
return select({
|
|
1027
1134
|
message: step.message,
|
|
1028
1135
|
choices,
|
|
1029
1136
|
default: defaultValue,
|
|
1030
1137
|
pageSize: step.pageSize,
|
|
1031
1138
|
loop: step.loop,
|
|
1032
|
-
theme: {
|
|
1139
|
+
theme: {
|
|
1140
|
+
prefix: { idle: theme.icons.pointer, done: theme.icons.stepDone },
|
|
1141
|
+
icon: { cursor: theme.icons.pointer },
|
|
1142
|
+
style: { disabled: theme.dimmed }
|
|
1143
|
+
}
|
|
1033
1144
|
});
|
|
1034
1145
|
}
|
|
1035
1146
|
async renderMultiSelect(step, state, theme) {
|
|
1036
1147
|
const existingAnswer = state.answers[step.id];
|
|
1037
1148
|
const previousSelections = Array.isArray(existingAnswer) ? existingAnswer.filter((v) => typeof v === "string") : step.default;
|
|
1038
|
-
const
|
|
1149
|
+
const rawChoices = step.options.map((opt) => {
|
|
1039
1150
|
if ("separator" in opt) {
|
|
1040
1151
|
return new Separator(opt.separator);
|
|
1041
1152
|
}
|
|
@@ -1046,12 +1157,20 @@ var InquirerRenderer = class {
|
|
|
1046
1157
|
disabled: opt.disabled
|
|
1047
1158
|
};
|
|
1048
1159
|
});
|
|
1160
|
+
const itemChoices = rawChoices.filter((c) => !(c instanceof Separator));
|
|
1161
|
+
const columnedItems = step.columns ? applyColumns(itemChoices, step.columns) : itemChoices;
|
|
1162
|
+
let itemIdx = 0;
|
|
1163
|
+
const choices = rawChoices.map((c) => c instanceof Separator ? c : columnedItems[itemIdx++] ?? c);
|
|
1049
1164
|
return checkbox({
|
|
1050
1165
|
message: step.message,
|
|
1051
1166
|
choices,
|
|
1052
1167
|
pageSize: step.pageSize,
|
|
1053
1168
|
loop: step.loop,
|
|
1054
|
-
theme: {
|
|
1169
|
+
theme: {
|
|
1170
|
+
prefix: { idle: theme.icons.pointer, done: theme.icons.stepDone },
|
|
1171
|
+
icon: { cursor: theme.icons.pointer, checked: theme.checked("\u2714"), unchecked: theme.muted("\u25CB") },
|
|
1172
|
+
style: { disabledChoice: theme.dimmed }
|
|
1173
|
+
}
|
|
1055
1174
|
});
|
|
1056
1175
|
}
|
|
1057
1176
|
async renderConfirm(step, state, theme) {
|
|
@@ -1083,15 +1202,17 @@ var InquirerRenderer = class {
|
|
|
1083
1202
|
return result ?? defaultValue ?? 0;
|
|
1084
1203
|
}
|
|
1085
1204
|
async renderSearch(step, _state, theme) {
|
|
1205
|
+
const message = step.placeholder ? `${step.message} ${theme.muted(`(${step.placeholder})`)}` : step.message;
|
|
1086
1206
|
return search({
|
|
1087
|
-
message
|
|
1207
|
+
message,
|
|
1088
1208
|
source: (input3) => {
|
|
1089
1209
|
const term = (input3 ?? "").toLowerCase();
|
|
1090
|
-
|
|
1210
|
+
const filtered = step.options.filter((opt) => "value" in opt).filter((opt) => !opt.disabled && opt.label.toLowerCase().includes(term)).map((opt) => ({
|
|
1091
1211
|
name: opt.label,
|
|
1092
1212
|
value: opt.value,
|
|
1093
1213
|
description: opt.hint
|
|
1094
1214
|
}));
|
|
1215
|
+
return step.columns ? applyColumns(filtered, step.columns) : filtered;
|
|
1095
1216
|
},
|
|
1096
1217
|
pageSize: step.pageSize,
|
|
1097
1218
|
theme: { prefix: { idle: theme.icons.pointer, done: theme.icons.stepDone } }
|
|
@@ -1159,6 +1280,42 @@ ${theme.muted("\u2500".repeat(40))}`);
|
|
|
1159
1280
|
process.stdout.write("\x1B[2J\x1B[0f");
|
|
1160
1281
|
}
|
|
1161
1282
|
};
|
|
1283
|
+
var NOTE_STYLE_MAP = {
|
|
1284
|
+
info: { tokenKey: "info", icon: "\u2139" },
|
|
1285
|
+
warning: { tokenKey: "warning", icon: "\u26A0" },
|
|
1286
|
+
error: { tokenKey: "error", icon: "\u2716" },
|
|
1287
|
+
success: { tokenKey: "success", icon: "\u2714" },
|
|
1288
|
+
code: { tokenKey: "muted", icon: "\u276F" },
|
|
1289
|
+
banner: { tokenKey: "primary", icon: "\u2605" }
|
|
1290
|
+
};
|
|
1291
|
+
function getNoteStyleConfig(style, theme) {
|
|
1292
|
+
const entry = NOTE_STYLE_MAP[style];
|
|
1293
|
+
return {
|
|
1294
|
+
colorFn: theme[entry.tokenKey],
|
|
1295
|
+
icon: entry.icon
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
function applyColumns(items, columns) {
|
|
1299
|
+
const cols = Math.max(1, Math.floor(columns));
|
|
1300
|
+
if (cols <= 1) return items;
|
|
1301
|
+
if (items.length === 0) return items;
|
|
1302
|
+
const maxLabel = Math.max(...items.map((i) => i.name.length));
|
|
1303
|
+
const colWidth = maxLabel + 4;
|
|
1304
|
+
const grouped = [];
|
|
1305
|
+
for (let i = 0; i < items.length; i += cols) {
|
|
1306
|
+
grouped.push(items.slice(i, i + cols));
|
|
1307
|
+
}
|
|
1308
|
+
const result = [];
|
|
1309
|
+
for (const row of grouped) {
|
|
1310
|
+
for (let c = 0; c < row.length; c++) {
|
|
1311
|
+
const item = row[c];
|
|
1312
|
+
const isLast = c === row.length - 1;
|
|
1313
|
+
const paddedName = isLast ? item.name : item.name.padEnd(colWidth);
|
|
1314
|
+
result.push({ ...item, name: paddedName });
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
return result;
|
|
1318
|
+
}
|
|
1162
1319
|
|
|
1163
1320
|
// src/template.ts
|
|
1164
1321
|
function resolveTemplate(template, answers) {
|
|
@@ -1192,19 +1349,71 @@ function renderBanner(name, theme, options) {
|
|
|
1192
1349
|
const icon = options?.icon;
|
|
1193
1350
|
const prefix = icon ? `${icon} ` : "";
|
|
1194
1351
|
if (options?.plain) {
|
|
1195
|
-
|
|
1352
|
+
const line = ` ${prefix}${theme.bold(name)}`;
|
|
1353
|
+
return options?.subtitle ? `${line}
|
|
1354
|
+
${theme.muted(options.subtitle)}` : line;
|
|
1355
|
+
}
|
|
1356
|
+
if (options?.banner) {
|
|
1357
|
+
const bannerStr = (typeof options.banner === "function" ? options.banner(theme) : options.banner).replace(/\n$/, "");
|
|
1358
|
+
const raw = bannerStr.split("\n");
|
|
1359
|
+
const mid = Math.floor(raw.length / 2);
|
|
1360
|
+
const bannerLines = raw.map((l, i) => {
|
|
1361
|
+
if (icon && i === mid) return ` ${icon} ${l}`;
|
|
1362
|
+
return icon ? ` ${l}` : ` ${l}`;
|
|
1363
|
+
}).join("\n");
|
|
1364
|
+
const colored = typeof options.banner === "function" ? bannerLines : GRIMOIRE_GRADIENT(bannerLines);
|
|
1365
|
+
return options?.subtitle ? `${colored}
|
|
1366
|
+
${theme.muted(options.subtitle)}` : colored;
|
|
1196
1367
|
}
|
|
1197
1368
|
try {
|
|
1198
|
-
const
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1369
|
+
const requestedFont = options?.font ?? "Small";
|
|
1370
|
+
let art;
|
|
1371
|
+
try {
|
|
1372
|
+
art = figlet.textSync(name, { font: requestedFont, horizontalLayout: "default" });
|
|
1373
|
+
} catch {
|
|
1374
|
+
art = figlet.textSync(name, { font: "Small", horizontalLayout: "default" });
|
|
1375
|
+
}
|
|
1376
|
+
const artLines = art.split("\n");
|
|
1377
|
+
const lines = artLines.map((line, i) => {
|
|
1378
|
+
const iconStr = getIconForLine(icon, options?.iconSize, i, artLines.length);
|
|
1379
|
+
if (iconStr !== void 0) {
|
|
1380
|
+
return ` ${iconStr}${line}`;
|
|
1381
|
+
}
|
|
1382
|
+
return icon ? ` ${line}` : ` ${line}`;
|
|
1383
|
+
}).join("\n");
|
|
1384
|
+
const colored = GRIMOIRE_GRADIENT(lines);
|
|
1385
|
+
return options?.subtitle ? `${colored}
|
|
1386
|
+
${theme.muted(options.subtitle)}` : colored;
|
|
1206
1387
|
} catch {
|
|
1207
|
-
|
|
1388
|
+
const line = ` ${prefix}${theme.bold(name)}`;
|
|
1389
|
+
return options?.subtitle ? `${line}
|
|
1390
|
+
${theme.muted(options.subtitle)}` : line;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
function getIconForLine(icon, iconSize, lineIndex, totalLines) {
|
|
1394
|
+
if (!icon) return void 0;
|
|
1395
|
+
const mid = Math.floor(totalLines / 2);
|
|
1396
|
+
const span = resolveIconSpan(iconSize, totalLines);
|
|
1397
|
+
const halfSpan = Math.floor(span / 2);
|
|
1398
|
+
const start = Math.max(0, mid - halfSpan);
|
|
1399
|
+
const end = Math.min(totalLines - 1, start + span - 1);
|
|
1400
|
+
if (lineIndex >= start && lineIndex <= end) {
|
|
1401
|
+
return lineIndex === mid ? `${icon} ` : ` `;
|
|
1402
|
+
}
|
|
1403
|
+
return void 0;
|
|
1404
|
+
}
|
|
1405
|
+
function resolveIconSpan(iconSize, totalLines) {
|
|
1406
|
+
if (typeof iconSize === "number") {
|
|
1407
|
+
const clamped = Math.max(1, Math.floor(isFinite(iconSize) ? iconSize : 1));
|
|
1408
|
+
return Math.min(clamped, totalLines);
|
|
1409
|
+
}
|
|
1410
|
+
switch (iconSize ?? "small") {
|
|
1411
|
+
case "small":
|
|
1412
|
+
return 1;
|
|
1413
|
+
case "medium":
|
|
1414
|
+
return 3;
|
|
1415
|
+
case "large":
|
|
1416
|
+
return totalLines;
|
|
1208
1417
|
}
|
|
1209
1418
|
}
|
|
1210
1419
|
|
|
@@ -1443,7 +1652,14 @@ function emitEvent(renderer, event, theme) {
|
|
|
1443
1652
|
renderer.onEvent(event, theme);
|
|
1444
1653
|
}
|
|
1445
1654
|
}
|
|
1446
|
-
function runPreFlightChecks(checks, theme, renderer) {
|
|
1655
|
+
function runPreFlightChecks(checks, theme, renderer, checksStyle) {
|
|
1656
|
+
if (checksStyle === "tasklist") {
|
|
1657
|
+
runPreFlightChecksTasklist(checks, theme, renderer);
|
|
1658
|
+
} else {
|
|
1659
|
+
runPreFlightChecksSpinner(checks, theme, renderer);
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
function runPreFlightChecksSpinner(checks, theme, renderer) {
|
|
1447
1663
|
if (renderer) emitEvent(renderer, { type: "checks:start", checks }, theme);
|
|
1448
1664
|
for (const check of checks) {
|
|
1449
1665
|
if (renderer) emitEvent(renderer, { type: "spinner:start", message: check.name }, theme);
|
|
@@ -1461,20 +1677,69 @@ function runPreFlightChecks(checks, theme, renderer) {
|
|
|
1461
1677
|
}
|
|
1462
1678
|
console.log();
|
|
1463
1679
|
}
|
|
1680
|
+
function runPreFlightChecksTasklist(checks, theme, renderer) {
|
|
1681
|
+
if (!process.stdout.isTTY) {
|
|
1682
|
+
runPreFlightChecksSpinner(checks, theme, renderer);
|
|
1683
|
+
return;
|
|
1684
|
+
}
|
|
1685
|
+
if (renderer) emitEvent(renderer, { type: "checks:start", checks, mode: "tasklist" }, theme);
|
|
1686
|
+
const statuses = checks.map(() => "pending");
|
|
1687
|
+
const icons = theme.icons;
|
|
1688
|
+
function renderTasklist() {
|
|
1689
|
+
process.stdout.write(`\x1B[${checks.length}A\x1B[0G`);
|
|
1690
|
+
for (let i = 0; i < checks.length; i++) {
|
|
1691
|
+
const check = checks[i];
|
|
1692
|
+
const s = statuses[i];
|
|
1693
|
+
let icon;
|
|
1694
|
+
if (s === "pass") icon = theme.success(icons.stepDone);
|
|
1695
|
+
else if (s === "fail") icon = theme.error("\u2717");
|
|
1696
|
+
else if (s === "running") icon = theme.info("\u280B");
|
|
1697
|
+
else icon = theme.muted(icons.stepPending);
|
|
1698
|
+
process.stdout.write(` ${icon} ${check.name}\x1B[K
|
|
1699
|
+
`);
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
for (let i = 0; i < checks.length; i++) {
|
|
1703
|
+
process.stdout.write(` ${theme.muted(icons.stepPending)} ${checks[i].name}
|
|
1704
|
+
`);
|
|
1705
|
+
}
|
|
1706
|
+
let failedCheck;
|
|
1707
|
+
for (let i = 0; i < checks.length; i++) {
|
|
1708
|
+
const check = checks[i];
|
|
1709
|
+
statuses[i] = "running";
|
|
1710
|
+
renderTasklist();
|
|
1711
|
+
try {
|
|
1712
|
+
execSync(check.run, { stdio: "pipe" });
|
|
1713
|
+
statuses[i] = "pass";
|
|
1714
|
+
renderTasklist();
|
|
1715
|
+
if (renderer) emitEvent(renderer, { type: "check:pass", name: check.name }, theme);
|
|
1716
|
+
} catch {
|
|
1717
|
+
statuses[i] = "fail";
|
|
1718
|
+
renderTasklist();
|
|
1719
|
+
failedCheck = check;
|
|
1720
|
+
if (renderer) emitEvent(renderer, { type: "check:fail", name: check.name, message: check.message }, theme);
|
|
1721
|
+
break;
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
renderTasklist();
|
|
1725
|
+
console.log();
|
|
1726
|
+
if (failedCheck) {
|
|
1727
|
+
throw new Error(`Pre-flight check failed: ${failedCheck.name} \u2014 ${failedCheck.message}`);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
var MOCK_MISS = /* @__PURE__ */ Symbol("mock-miss");
|
|
1464
1731
|
function getMockValue(step, mockAnswers) {
|
|
1465
1732
|
if (step.id in mockAnswers) {
|
|
1466
1733
|
return mockAnswers[step.id];
|
|
1467
1734
|
}
|
|
1468
|
-
if (step.type === "message" || step.type === "note") {
|
|
1735
|
+
if (step.type === "message" || step.type === "note" || step.type === "browser") {
|
|
1469
1736
|
return true;
|
|
1470
1737
|
}
|
|
1471
1738
|
const defaultValue = getStepDefault(step);
|
|
1472
1739
|
if (defaultValue !== void 0) {
|
|
1473
1740
|
return defaultValue;
|
|
1474
1741
|
}
|
|
1475
|
-
|
|
1476
|
-
`Mock mode: no answer provided for step "${step.id}" and no default available`
|
|
1477
|
-
);
|
|
1742
|
+
return MOCK_MISS;
|
|
1478
1743
|
}
|
|
1479
1744
|
function getStepDefault(step) {
|
|
1480
1745
|
switch (step.type) {
|
|
@@ -1494,6 +1759,7 @@ function getStepDefault(step) {
|
|
|
1494
1759
|
case "password":
|
|
1495
1760
|
case "message":
|
|
1496
1761
|
case "note":
|
|
1762
|
+
case "browser":
|
|
1497
1763
|
return void 0;
|
|
1498
1764
|
}
|
|
1499
1765
|
}
|
|
@@ -1529,9 +1795,34 @@ async function runWizard(config, options) {
|
|
|
1529
1795
|
registerPlugin(plugin);
|
|
1530
1796
|
}
|
|
1531
1797
|
}
|
|
1798
|
+
let cancelFired = false;
|
|
1799
|
+
const performCancel = async () => {
|
|
1800
|
+
if (cancelFired) return;
|
|
1801
|
+
cancelFired = true;
|
|
1802
|
+
state = wizardReducer(state, { type: "CANCEL" }, config);
|
|
1803
|
+
const passwordStepIds = config.steps.filter((s) => s.type === "password").map((s) => s.id);
|
|
1804
|
+
saveProgress(config.meta.name, {
|
|
1805
|
+
currentStepId: state.currentStepId,
|
|
1806
|
+
answers: state.answers,
|
|
1807
|
+
history: state.history
|
|
1808
|
+
}, void 0, passwordStepIds);
|
|
1809
|
+
try {
|
|
1810
|
+
await options?.onCancel?.(state);
|
|
1811
|
+
} catch {
|
|
1812
|
+
}
|
|
1813
|
+
emitEvent(renderer, { type: "session:end", answers: state.answers, cancelled: true }, theme);
|
|
1814
|
+
if (!quiet) console.log(theme.warning("\n Wizard cancelled.\n"));
|
|
1815
|
+
};
|
|
1816
|
+
const signalHandler = !isMock ? () => {
|
|
1817
|
+
performCancel().finally(() => process.exit(130));
|
|
1818
|
+
} : void 0;
|
|
1819
|
+
if (signalHandler) {
|
|
1820
|
+
process.once("SIGINT", signalHandler);
|
|
1821
|
+
process.once("SIGTERM", signalHandler);
|
|
1822
|
+
}
|
|
1532
1823
|
try {
|
|
1533
1824
|
if (!isMock && config.checks && config.checks.length > 0) {
|
|
1534
|
-
runPreFlightChecks(config.checks, theme, renderer);
|
|
1825
|
+
runPreFlightChecks(config.checks, theme, renderer, config.meta.checksStyle);
|
|
1535
1826
|
}
|
|
1536
1827
|
if (!quiet) {
|
|
1537
1828
|
printWizardHeader(config, theme, options?.plain);
|
|
@@ -1541,7 +1832,62 @@ async function runWizard(config, options) {
|
|
|
1541
1832
|
let needsReview = true;
|
|
1542
1833
|
while (needsReview) {
|
|
1543
1834
|
let previousGroup;
|
|
1835
|
+
let stepsCompleted = 0;
|
|
1544
1836
|
while (state.status === "running") {
|
|
1837
|
+
if (!isMock && config.meta.clearBetweenSteps && stepsCompleted > 0) {
|
|
1838
|
+
renderer.clear();
|
|
1839
|
+
if (!quiet) {
|
|
1840
|
+
printWizardHeader(config, theme, options?.plain);
|
|
1841
|
+
}
|
|
1842
|
+
previousGroup = void 0;
|
|
1843
|
+
}
|
|
1844
|
+
let nextStepOverride;
|
|
1845
|
+
const createHookContext = (stateOverride) => ({
|
|
1846
|
+
answers: { ...(stateOverride ?? state).answers },
|
|
1847
|
+
state: stateOverride ?? state,
|
|
1848
|
+
showNote: (title, body) => {
|
|
1849
|
+
emitEvent(renderer, { type: "note", title, body }, theme);
|
|
1850
|
+
if (!("onEvent" in renderer) && process.stdout.isTTY) {
|
|
1851
|
+
console.log(`
|
|
1852
|
+
${theme.bold(title)}`);
|
|
1853
|
+
if (body) console.log(` ${theme.muted(body)}`);
|
|
1854
|
+
console.log();
|
|
1855
|
+
}
|
|
1856
|
+
},
|
|
1857
|
+
setNextStep: (stepId) => {
|
|
1858
|
+
nextStepOverride = stepId;
|
|
1859
|
+
},
|
|
1860
|
+
openBrowser: async (url) => {
|
|
1861
|
+
if (isMock) return;
|
|
1862
|
+
try {
|
|
1863
|
+
new URL(url);
|
|
1864
|
+
} catch {
|
|
1865
|
+
return;
|
|
1866
|
+
}
|
|
1867
|
+
if (process.platform === "darwin") {
|
|
1868
|
+
execFileSync("open", [url], { stdio: "ignore" });
|
|
1869
|
+
} else if (process.platform === "win32") {
|
|
1870
|
+
execFileSync("powershell", ["-NoProfile", "-Command", `Start-Process '${url.replace(/'/g, "''")}'`], { stdio: "ignore" });
|
|
1871
|
+
} else {
|
|
1872
|
+
execFileSync("xdg-open", [url], { stdio: "ignore" });
|
|
1873
|
+
}
|
|
1874
|
+
},
|
|
1875
|
+
prompt: async (promptConfig) => {
|
|
1876
|
+
if (isMock) {
|
|
1877
|
+
if (promptConfig.default !== void 0) return promptConfig.default;
|
|
1878
|
+
throw new Error("Mock mode: context.prompt() requires a default value");
|
|
1879
|
+
}
|
|
1880
|
+
const contextState = stateOverride ?? state;
|
|
1881
|
+
const tempStep = {
|
|
1882
|
+
id: "__hook_prompt__",
|
|
1883
|
+
message: promptConfig.message,
|
|
1884
|
+
type: promptConfig.type,
|
|
1885
|
+
...promptConfig.type === "select" ? { options: promptConfig.options } : {},
|
|
1886
|
+
default: promptConfig.default
|
|
1887
|
+
};
|
|
1888
|
+
return renderStep(renderer, tempStep, contextState, theme);
|
|
1889
|
+
}
|
|
1890
|
+
});
|
|
1545
1891
|
const visibleSteps = getVisibleSteps(config, state.answers);
|
|
1546
1892
|
const currentStep = config.steps.find((s) => s.id === state.currentStepId);
|
|
1547
1893
|
if (!currentStep) {
|
|
@@ -1564,9 +1910,13 @@ async function runWizard(config, options) {
|
|
|
1564
1910
|
emitEvent(renderer, { type: "step:start", stepId: currentStep.id, stepIndex, totalVisible: visibleSteps.length, step: currentStep }, theme);
|
|
1565
1911
|
if (currentStep.type === "note") {
|
|
1566
1912
|
emitEvent(renderer, { type: "note", title: resolvedMessage, body: resolvedDescription ?? "" }, theme);
|
|
1913
|
+
if (!isMock && "style" in currentStep && currentStep.style && "renderNote" in renderer && !("onEvent" in renderer)) {
|
|
1914
|
+
const resolvedStep2 = { ...currentStep, message: resolvedMessage, description: resolvedDescription };
|
|
1915
|
+
renderer.renderNote(resolvedStep2, theme);
|
|
1916
|
+
}
|
|
1567
1917
|
}
|
|
1568
1918
|
if (options?.onBeforeStep) {
|
|
1569
|
-
await options.onBeforeStep(currentStep.id, currentStep,
|
|
1919
|
+
await options.onBeforeStep(currentStep.id, currentStep, createHookContext());
|
|
1570
1920
|
}
|
|
1571
1921
|
const pluginStep = getPluginStep(currentStep.type);
|
|
1572
1922
|
const resolvedStep = pluginStep ? currentStep : resolveStepDefaults(currentStep, cachedAnswers);
|
|
@@ -1583,7 +1933,19 @@ async function runWizard(config, options) {
|
|
|
1583
1933
|
}
|
|
1584
1934
|
}
|
|
1585
1935
|
try {
|
|
1586
|
-
|
|
1936
|
+
let value;
|
|
1937
|
+
if (isMock) {
|
|
1938
|
+
const mockResult = getMockValue(finalStep, mockAnswers);
|
|
1939
|
+
if (mockResult === MOCK_MISS) {
|
|
1940
|
+
throw new Error(
|
|
1941
|
+
`Mock mode: no answer provided for step "${finalStep.id}" and no default available`
|
|
1942
|
+
);
|
|
1943
|
+
} else {
|
|
1944
|
+
value = mockResult;
|
|
1945
|
+
}
|
|
1946
|
+
} else {
|
|
1947
|
+
value = pluginStep ? await pluginStep.render(toStepRecord(finalStep), state, theme) : await renderStep(renderer, finalStep, state, theme);
|
|
1948
|
+
}
|
|
1587
1949
|
if (pluginStep?.validate) {
|
|
1588
1950
|
const pluginError = pluginStep.validate(value, toStepRecord(templatedStep));
|
|
1589
1951
|
if (pluginError) {
|
|
@@ -1624,28 +1986,31 @@ async function runWizard(config, options) {
|
|
|
1624
1986
|
}
|
|
1625
1987
|
}
|
|
1626
1988
|
if (options?.onAfterStep) {
|
|
1627
|
-
await options.onAfterStep(currentStep.id, value, nextState);
|
|
1989
|
+
await options.onAfterStep(currentStep.id, value, createHookContext(nextState));
|
|
1990
|
+
}
|
|
1991
|
+
if (nextStepOverride) {
|
|
1992
|
+
if (nextStepOverride === "__done__") {
|
|
1993
|
+
state = { ...nextState, status: "done" };
|
|
1994
|
+
} else {
|
|
1995
|
+
const targetExists = config.steps.some((s) => s.id === nextStepOverride);
|
|
1996
|
+
if (!targetExists) {
|
|
1997
|
+
throw new Error(`setNextStep: step "${nextStepOverride}" does not exist`);
|
|
1998
|
+
}
|
|
1999
|
+
state = { ...nextState, status: "running", currentStepId: nextStepOverride };
|
|
2000
|
+
}
|
|
2001
|
+
nextStepOverride = void 0;
|
|
2002
|
+
} else {
|
|
2003
|
+
state = nextState;
|
|
1628
2004
|
}
|
|
1629
|
-
state = nextState;
|
|
1630
2005
|
emitEvent(renderer, { type: "step:complete", stepId: currentStep.id, value, step: currentStep }, theme);
|
|
1631
2006
|
if (mruEnabled && isSelectLikeStep(currentStep.type)) {
|
|
1632
2007
|
recordSelection(config.meta.name, currentStep.id, value);
|
|
1633
2008
|
}
|
|
1634
2009
|
options?.onStepComplete?.(currentStep.id, value, state);
|
|
2010
|
+
stepsCompleted++;
|
|
1635
2011
|
} catch (error) {
|
|
1636
2012
|
if (!isMock && isUserCancel(error)) {
|
|
1637
|
-
|
|
1638
|
-
options?.onCancel?.(state);
|
|
1639
|
-
const passwordStepIds = config.steps.filter((s) => s.type === "password").map((s) => s.id);
|
|
1640
|
-
saveProgress(config.meta.name, {
|
|
1641
|
-
currentStepId: state.currentStepId,
|
|
1642
|
-
answers: state.answers,
|
|
1643
|
-
history: state.history
|
|
1644
|
-
}, void 0, passwordStepIds);
|
|
1645
|
-
emitEvent(renderer, { type: "session:end", answers: state.answers, cancelled: true }, theme);
|
|
1646
|
-
if (!quiet) {
|
|
1647
|
-
console.log(theme.warning("\n Wizard cancelled.\n"));
|
|
1648
|
-
}
|
|
2013
|
+
await performCancel();
|
|
1649
2014
|
return state.answers;
|
|
1650
2015
|
}
|
|
1651
2016
|
throw error;
|
|
@@ -1654,10 +2019,14 @@ async function runWizard(config, options) {
|
|
|
1654
2019
|
if (config.meta.review && !isMock && state.status === "done") {
|
|
1655
2020
|
const reviewLines = [];
|
|
1656
2021
|
for (const step of config.steps) {
|
|
2022
|
+
if (step.review?.hide) continue;
|
|
2023
|
+
if (step.type === "note" || step.type === "message") continue;
|
|
1657
2024
|
const answer = state.answers[step.id];
|
|
1658
2025
|
if (answer === void 0) continue;
|
|
1659
|
-
const
|
|
1660
|
-
|
|
2026
|
+
const label = step.review?.label ?? step.id;
|
|
2027
|
+
const raw = step.type === "password" ? "****" : Array.isArray(answer) ? answer.map(String).join(", ") : String(answer);
|
|
2028
|
+
const display = formatReviewValue(raw, step.review?.format);
|
|
2029
|
+
reviewLines.push(`${label}: ${display}`);
|
|
1661
2030
|
}
|
|
1662
2031
|
emitEvent(renderer, { type: "note", title: "Review your answers", body: reviewLines.join("\n") }, theme);
|
|
1663
2032
|
console.log(`
|
|
@@ -1677,12 +2046,16 @@ async function runWizard(config, options) {
|
|
|
1677
2046
|
} else {
|
|
1678
2047
|
const { select: selectPrompt } = await import("@inquirer/prompts");
|
|
1679
2048
|
const stepsWithAnswers = config.steps.filter(
|
|
1680
|
-
(s) => state.answers[s.id] !== void 0 && s.type !== "note" && s.type !== "message"
|
|
2049
|
+
(s) => state.answers[s.id] !== void 0 && s.type !== "note" && s.type !== "message" && !s.review?.hide
|
|
1681
2050
|
);
|
|
2051
|
+
if (stepsWithAnswers.length === 0) {
|
|
2052
|
+
needsReview = false;
|
|
2053
|
+
break;
|
|
2054
|
+
}
|
|
1682
2055
|
const stepToRevisit = await selectPrompt({
|
|
1683
2056
|
message: "Which step would you like to change?",
|
|
1684
2057
|
choices: stepsWithAnswers.map((s) => ({
|
|
1685
|
-
name: `${s.id}: ${s.type === "password" ? "****" : String(state.answers[s.id] ?? "")}`,
|
|
2058
|
+
name: `${s.review?.label ?? s.id}: ${s.type === "password" ? "****" : String(state.answers[s.id] ?? "")}`,
|
|
1686
2059
|
value: s.id
|
|
1687
2060
|
}))
|
|
1688
2061
|
});
|
|
@@ -1725,6 +2098,10 @@ async function runWizard(config, options) {
|
|
|
1725
2098
|
}
|
|
1726
2099
|
return state.answers;
|
|
1727
2100
|
} finally {
|
|
2101
|
+
if (signalHandler) {
|
|
2102
|
+
process.removeListener("SIGINT", signalHandler);
|
|
2103
|
+
process.removeListener("SIGTERM", signalHandler);
|
|
2104
|
+
}
|
|
1728
2105
|
if (userPlugins) {
|
|
1729
2106
|
clearPlugins();
|
|
1730
2107
|
}
|
|
@@ -1764,6 +2141,18 @@ function renderStep(renderer, step, state, theme) {
|
|
|
1764
2141
|
return Promise.resolve(true);
|
|
1765
2142
|
case "note":
|
|
1766
2143
|
return Promise.resolve(true);
|
|
2144
|
+
case "browser": {
|
|
2145
|
+
const resolvedUrl = resolveTemplate(step.url, state.answers);
|
|
2146
|
+
console.log(`
|
|
2147
|
+
${theme.info("\u2192")} ${step.message}`);
|
|
2148
|
+
console.log(` ${theme.muted(resolvedUrl)}`);
|
|
2149
|
+
openUrl(resolvedUrl);
|
|
2150
|
+
if (step.fallback) {
|
|
2151
|
+
console.log(` ${theme.muted(step.fallback)}`);
|
|
2152
|
+
}
|
|
2153
|
+
console.log();
|
|
2154
|
+
return Promise.resolve(true);
|
|
2155
|
+
}
|
|
1767
2156
|
}
|
|
1768
2157
|
}
|
|
1769
2158
|
function resolveStepDefaults(step, cachedAnswers) {
|
|
@@ -1815,6 +2204,7 @@ function resolveStepDefaults(step, cachedAnswers) {
|
|
|
1815
2204
|
case "password":
|
|
1816
2205
|
case "message":
|
|
1817
2206
|
case "note":
|
|
2207
|
+
case "browser":
|
|
1818
2208
|
return step;
|
|
1819
2209
|
}
|
|
1820
2210
|
}
|
|
@@ -1824,7 +2214,7 @@ function getCachedDefault(stepId, cachedAnswers) {
|
|
|
1824
2214
|
}
|
|
1825
2215
|
function applyTemplateDefaults(step, templateAnswers) {
|
|
1826
2216
|
if (!(step.id in templateAnswers)) return step;
|
|
1827
|
-
if (step.type === "password" || step.type === "message" || step.type === "note") return step;
|
|
2217
|
+
if (step.type === "password" || step.type === "message" || step.type === "note" || step.type === "browser") return step;
|
|
1828
2218
|
const value = templateAnswers[step.id];
|
|
1829
2219
|
switch (step.type) {
|
|
1830
2220
|
case "text":
|
|
@@ -1914,6 +2304,7 @@ function resolveStepTemplates(step, answers) {
|
|
|
1914
2304
|
case "toggle":
|
|
1915
2305
|
case "message":
|
|
1916
2306
|
case "note":
|
|
2307
|
+
case "browser":
|
|
1917
2308
|
return {
|
|
1918
2309
|
...step,
|
|
1919
2310
|
description: step.description ? resolveTemplate(step.description, answers) : void 0
|
|
@@ -1971,18 +2362,50 @@ async function executeActions(actions, answers, theme, renderer) {
|
|
|
1971
2362
|
}
|
|
1972
2363
|
function printWizardHeader(config, theme, plain) {
|
|
1973
2364
|
console.log();
|
|
1974
|
-
console.log(renderBanner(config.meta.name, theme, {
|
|
2365
|
+
console.log(renderBanner(config.meta.name, theme, {
|
|
2366
|
+
plain,
|
|
2367
|
+
icon: config.meta.icon,
|
|
2368
|
+
iconSize: config.meta.iconSize,
|
|
2369
|
+
font: config.meta.font,
|
|
2370
|
+
banner: config.meta.banner,
|
|
2371
|
+
subtitle: config.meta.subtitle
|
|
2372
|
+
}));
|
|
1975
2373
|
if (config.meta.description) {
|
|
1976
2374
|
console.log(` ${theme.muted(config.meta.description)}`);
|
|
1977
2375
|
}
|
|
1978
2376
|
console.log();
|
|
1979
2377
|
}
|
|
2378
|
+
function openUrl(url) {
|
|
2379
|
+
try {
|
|
2380
|
+
if (process.platform === "darwin") {
|
|
2381
|
+
execFileSync("open", [url], { stdio: "ignore" });
|
|
2382
|
+
} else if (process.platform === "win32") {
|
|
2383
|
+
const safeUrl = url.replace(/'/g, "''");
|
|
2384
|
+
execFileSync("powershell", ["-NoProfile", "-Command", `Start-Process '${safeUrl}'`], { stdio: "ignore" });
|
|
2385
|
+
} else {
|
|
2386
|
+
execFileSync("xdg-open", [url], { stdio: "ignore" });
|
|
2387
|
+
}
|
|
2388
|
+
} catch {
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
1980
2391
|
function isUserCancel(error) {
|
|
1981
2392
|
if (error instanceof Error) {
|
|
1982
2393
|
return error.message.includes("User force closed") || error.name === "ExitPromptError";
|
|
1983
2394
|
}
|
|
1984
2395
|
return false;
|
|
1985
2396
|
}
|
|
2397
|
+
function formatReviewValue(value, format) {
|
|
2398
|
+
switch (format) {
|
|
2399
|
+
case "uppercase":
|
|
2400
|
+
return value.toUpperCase();
|
|
2401
|
+
case "lowercase":
|
|
2402
|
+
return value.toLowerCase();
|
|
2403
|
+
case "capitalize":
|
|
2404
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
2405
|
+
default:
|
|
2406
|
+
return value;
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
1986
2409
|
|
|
1987
2410
|
// src/define.ts
|
|
1988
2411
|
function defineWizard(config) {
|
|
@@ -2106,8 +2529,9 @@ var InkRenderer = class {
|
|
|
2106
2529
|
return result ?? defaultValue ?? 0;
|
|
2107
2530
|
}
|
|
2108
2531
|
async renderSearch(step, _state, theme) {
|
|
2532
|
+
const message = step.placeholder ? `${step.message} ${theme.muted(`(${step.placeholder})`)}` : step.message;
|
|
2109
2533
|
return search2({
|
|
2110
|
-
message
|
|
2534
|
+
message,
|
|
2111
2535
|
source: (term) => {
|
|
2112
2536
|
const query = (term ?? "").toLowerCase();
|
|
2113
2537
|
return step.options.filter((opt) => "value" in opt).filter((opt) => !opt.disabled && opt.label.toLowerCase().includes(query)).map((opt) => ({
|
|
@@ -2211,6 +2635,8 @@ var S_BAR_H = u("\u2500", "-");
|
|
|
2211
2635
|
var ClackRenderer = class extends InquirerRenderer {
|
|
2212
2636
|
spinnerInterval;
|
|
2213
2637
|
spinnerFrameIndex = 0;
|
|
2638
|
+
spinnerStartTime = 0;
|
|
2639
|
+
checksMode = void 0;
|
|
2214
2640
|
renderStepHeader() {
|
|
2215
2641
|
}
|
|
2216
2642
|
renderGroupHeader() {
|
|
@@ -2267,18 +2693,25 @@ var ClackRenderer = class extends InquirerRenderer {
|
|
|
2267
2693
|
this.stopSpinner(event.message, theme);
|
|
2268
2694
|
break;
|
|
2269
2695
|
case "checks:start":
|
|
2270
|
-
|
|
2696
|
+
this.checksMode = event.mode === "tasklist" ? "tasklist" : "spinner";
|
|
2697
|
+
if (this.checksMode !== "tasklist") {
|
|
2698
|
+
process.stdout.write(`${chalk2.gray(S_BAR)}
|
|
2271
2699
|
`);
|
|
2272
|
-
|
|
2700
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.bold("Running checks...")}
|
|
2273
2701
|
`);
|
|
2702
|
+
}
|
|
2274
2703
|
break;
|
|
2275
2704
|
case "check:pass":
|
|
2276
|
-
|
|
2705
|
+
if (this.checksMode !== "tasklist") {
|
|
2706
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.success(S_STEP_SUBMIT)} ${event.name}
|
|
2277
2707
|
`);
|
|
2708
|
+
}
|
|
2278
2709
|
break;
|
|
2279
2710
|
case "check:fail":
|
|
2280
|
-
|
|
2711
|
+
if (this.checksMode !== "tasklist") {
|
|
2712
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.error(S_STEP_ERROR)} ${event.name}: ${event.message}
|
|
2281
2713
|
`);
|
|
2714
|
+
}
|
|
2282
2715
|
break;
|
|
2283
2716
|
case "actions:start":
|
|
2284
2717
|
process.stdout.write(`${chalk2.gray(S_BAR)}
|
|
@@ -2345,11 +2778,17 @@ var ClackRenderer = class extends InquirerRenderer {
|
|
|
2345
2778
|
`);
|
|
2346
2779
|
}
|
|
2347
2780
|
startSpinner(message, theme) {
|
|
2781
|
+
if (this.spinnerInterval) {
|
|
2782
|
+
clearInterval(this.spinnerInterval);
|
|
2783
|
+
this.spinnerInterval = void 0;
|
|
2784
|
+
}
|
|
2348
2785
|
this.spinnerFrameIndex = 0;
|
|
2786
|
+
this.spinnerStartTime = Date.now();
|
|
2349
2787
|
const { frames, interval } = theme.spinner;
|
|
2350
2788
|
this.spinnerInterval = setInterval(() => {
|
|
2351
2789
|
const frame = frames[this.spinnerFrameIndex % frames.length];
|
|
2352
|
-
|
|
2790
|
+
const elapsed = theme.spinnerElapsed ? ` ${chalk2.gray(`(${((Date.now() - this.spinnerStartTime) / 1e3).toFixed(1)}s)`)}` : "";
|
|
2791
|
+
process.stdout.write(`\r${chalk2.gray(S_BAR)} ${chalk2.cyan(frame ?? "")} ${message}${elapsed}`);
|
|
2353
2792
|
this.spinnerFrameIndex++;
|
|
2354
2793
|
}, interval);
|
|
2355
2794
|
}
|
|
@@ -2359,7 +2798,7 @@ var ClackRenderer = class extends InquirerRenderer {
|
|
|
2359
2798
|
this.spinnerInterval = void 0;
|
|
2360
2799
|
}
|
|
2361
2800
|
const finalMessage = message ?? "Done";
|
|
2362
|
-
process.stdout.write(`\r${chalk2.gray(S_BAR)} ${theme.success(S_STEP_SUBMIT)} ${finalMessage}
|
|
2801
|
+
process.stdout.write(`\r${chalk2.gray(S_BAR)} ${theme.success(S_STEP_SUBMIT)} ${finalMessage}\x1B[K
|
|
2363
2802
|
`);
|
|
2364
2803
|
}
|
|
2365
2804
|
};
|
|
@@ -2452,6 +2891,7 @@ export {
|
|
|
2452
2891
|
DEFAULT_SPINNER,
|
|
2453
2892
|
InkRenderer,
|
|
2454
2893
|
InquirerRenderer,
|
|
2894
|
+
applyColumns,
|
|
2455
2895
|
clearCache,
|
|
2456
2896
|
clearMruData,
|
|
2457
2897
|
clearPlugins,
|