grimoire-wizard 0.3.1 → 0.4.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 +173 -18
- package/dist/cli.js +503 -97
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +107 -3
- package/dist/index.js +832 -367
- package/dist/index.js.map +1 -1
- package/examples/json/all-features.json +66 -0
- package/examples/json/appstore-screenshot-wizard.json +362 -0
- package/examples/json/appstore-upload.json +104 -0
- package/examples/json/basic.json +72 -0
- package/examples/json/batch-generate.json +186 -0
- package/examples/json/brief-builder.json +519 -0
- package/examples/json/conditional.json +155 -0
- package/examples/json/cost-analyzer.json +83 -0
- package/examples/json/demo.json +130 -0
- package/examples/json/scraper-selector.json +63 -0
- package/examples/json/themed-catppuccin.json +39 -0
- package/examples/json/themed.json +103 -0
- package/examples/json/with-checks.json +47 -0
- package/examples/yaml/appstore-screenshot-wizard.yaml +321 -0
- package/examples/yaml/appstore-upload.yaml +84 -0
- package/examples/yaml/batch-generate.yaml +156 -0
- package/examples/yaml/brief-builder.yaml +429 -0
- package/examples/yaml/cost-analyzer.yaml +69 -0
- package/examples/yaml/pipeline.yaml +35 -0
- package/examples/yaml/scraper-selector.yaml +52 -0
- package/examples/yaml/themed-catppuccin.yaml +31 -0
- package/package.json +1 -1
- /package/examples/{all-features.yaml → yaml/all-features.yaml} +0 -0
- /package/examples/{base.yaml → yaml/base.yaml} +0 -0
- /package/examples/{basic.yaml → yaml/basic.yaml} +0 -0
- /package/examples/{conditional.yaml → yaml/conditional.yaml} +0 -0
- /package/examples/{demo.yaml → yaml/demo.yaml} +0 -0
- /package/examples/{ebay-mcp-setup.yaml → yaml/ebay-mcp-setup.yaml} +0 -0
- /package/examples/{extended.yaml → yaml/extended.yaml} +0 -0
- /package/examples/{themed.yaml → yaml/themed.yaml} +0 -0
- /package/examples/{with-checks.yaml → yaml/with-checks.yaml} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,283 +1,15 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res) => function __init() {
|
|
4
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
+
};
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
|
|
1
11
|
// src/schema.ts
|
|
2
12
|
import { z } from "zod";
|
|
3
|
-
var conditionSchema = z.lazy(() => {
|
|
4
|
-
const fieldEquals = z.object({ field: z.string(), equals: z.unknown() }).strict();
|
|
5
|
-
const fieldNotEquals = z.object({ field: z.string(), notEquals: z.unknown() }).strict();
|
|
6
|
-
const fieldIncludes = z.object({ field: z.string(), includes: z.unknown() }).strict();
|
|
7
|
-
const fieldNotIncludes = z.object({ field: z.string(), notIncludes: z.unknown() }).strict();
|
|
8
|
-
const fieldGreaterThan = z.object({ field: z.string(), greaterThan: z.number() }).strict();
|
|
9
|
-
const fieldLessThan = z.object({ field: z.string(), lessThan: z.number() }).strict();
|
|
10
|
-
const fieldIsEmpty = z.object({ field: z.string(), isEmpty: z.literal(true) }).strict();
|
|
11
|
-
const fieldIsNotEmpty = z.object({ field: z.string(), isNotEmpty: z.literal(true) }).strict();
|
|
12
|
-
const allCondition = z.object({ all: z.array(conditionSchema) }).strict();
|
|
13
|
-
const anyCondition = z.object({ any: z.array(conditionSchema) }).strict();
|
|
14
|
-
const notCondition = z.object({ not: conditionSchema }).strict();
|
|
15
|
-
return z.union([
|
|
16
|
-
fieldEquals,
|
|
17
|
-
fieldNotEquals,
|
|
18
|
-
fieldIncludes,
|
|
19
|
-
fieldNotIncludes,
|
|
20
|
-
fieldGreaterThan,
|
|
21
|
-
fieldLessThan,
|
|
22
|
-
fieldIsEmpty,
|
|
23
|
-
fieldIsNotEmpty,
|
|
24
|
-
allCondition,
|
|
25
|
-
anyCondition,
|
|
26
|
-
notCondition
|
|
27
|
-
]);
|
|
28
|
-
});
|
|
29
|
-
var validationRuleSchema = z.discriminatedUnion("rule", [
|
|
30
|
-
z.object({ rule: z.literal("required"), message: z.string().optional() }),
|
|
31
|
-
z.object({ rule: z.literal("minLength"), value: z.number(), message: z.string().optional() }),
|
|
32
|
-
z.object({ rule: z.literal("maxLength"), value: z.number(), message: z.string().optional() }),
|
|
33
|
-
z.object({ rule: z.literal("pattern"), value: z.string(), message: z.string().optional() }),
|
|
34
|
-
z.object({ rule: z.literal("min"), value: z.number(), message: z.string().optional() }),
|
|
35
|
-
z.object({ rule: z.literal("max"), value: z.number(), message: z.string().optional() })
|
|
36
|
-
]);
|
|
37
|
-
var selectOptionSchema = z.object({
|
|
38
|
-
value: z.string(),
|
|
39
|
-
label: z.string(),
|
|
40
|
-
hint: z.string().optional(),
|
|
41
|
-
disabled: z.union([z.boolean(), z.string()]).optional()
|
|
42
|
-
});
|
|
43
|
-
var separatorOptionSchema = z.object({
|
|
44
|
-
separator: z.string()
|
|
45
|
-
});
|
|
46
|
-
var selectChoiceSchema = z.union([selectOptionSchema, separatorOptionSchema]);
|
|
47
|
-
var baseStepFields = {
|
|
48
|
-
id: z.string(),
|
|
49
|
-
message: z.string(),
|
|
50
|
-
description: z.string().optional(),
|
|
51
|
-
next: z.string().optional(),
|
|
52
|
-
when: conditionSchema.optional(),
|
|
53
|
-
keepValuesOnPrevious: z.boolean().optional(),
|
|
54
|
-
required: z.boolean().optional(),
|
|
55
|
-
group: z.string().optional()
|
|
56
|
-
};
|
|
57
|
-
var textStepSchema = z.object({
|
|
58
|
-
...baseStepFields,
|
|
59
|
-
type: z.literal("text"),
|
|
60
|
-
placeholder: z.string().optional(),
|
|
61
|
-
default: z.string().optional(),
|
|
62
|
-
validate: z.array(validationRuleSchema).optional()
|
|
63
|
-
});
|
|
64
|
-
var selectStepSchema = z.object({
|
|
65
|
-
...baseStepFields,
|
|
66
|
-
type: z.literal("select"),
|
|
67
|
-
options: z.array(selectChoiceSchema).min(1).optional(),
|
|
68
|
-
optionsFrom: z.string().optional(),
|
|
69
|
-
default: z.string().optional(),
|
|
70
|
-
routes: z.record(z.string(), z.string()).optional(),
|
|
71
|
-
pageSize: z.number().int().positive().optional(),
|
|
72
|
-
loop: z.boolean().optional()
|
|
73
|
-
});
|
|
74
|
-
var multiSelectStepSchema = z.object({
|
|
75
|
-
...baseStepFields,
|
|
76
|
-
type: z.literal("multiselect"),
|
|
77
|
-
options: z.array(selectChoiceSchema).min(1).optional(),
|
|
78
|
-
optionsFrom: z.string().optional(),
|
|
79
|
-
default: z.array(z.string()).optional(),
|
|
80
|
-
min: z.number().int().nonnegative().optional(),
|
|
81
|
-
max: z.number().int().positive().optional(),
|
|
82
|
-
pageSize: z.number().int().positive().optional(),
|
|
83
|
-
loop: z.boolean().optional()
|
|
84
|
-
});
|
|
85
|
-
var confirmStepSchema = z.object({
|
|
86
|
-
...baseStepFields,
|
|
87
|
-
type: z.literal("confirm"),
|
|
88
|
-
default: z.boolean().optional()
|
|
89
|
-
});
|
|
90
|
-
var passwordStepSchema = z.object({
|
|
91
|
-
...baseStepFields,
|
|
92
|
-
type: z.literal("password"),
|
|
93
|
-
validate: z.array(validationRuleSchema).optional()
|
|
94
|
-
});
|
|
95
|
-
var numberStepSchema = z.object({
|
|
96
|
-
...baseStepFields,
|
|
97
|
-
type: z.literal("number"),
|
|
98
|
-
default: z.number().optional(),
|
|
99
|
-
min: z.number().optional(),
|
|
100
|
-
max: z.number().optional(),
|
|
101
|
-
step: z.number().positive().optional()
|
|
102
|
-
});
|
|
103
|
-
var searchStepSchema = z.object({
|
|
104
|
-
...baseStepFields,
|
|
105
|
-
type: z.literal("search"),
|
|
106
|
-
options: z.array(selectChoiceSchema).min(1).optional(),
|
|
107
|
-
optionsFrom: z.string().optional(),
|
|
108
|
-
default: z.string().optional(),
|
|
109
|
-
placeholder: z.string().optional(),
|
|
110
|
-
pageSize: z.number().int().positive().optional(),
|
|
111
|
-
loop: z.boolean().optional()
|
|
112
|
-
});
|
|
113
|
-
var editorStepSchema = z.object({
|
|
114
|
-
...baseStepFields,
|
|
115
|
-
type: z.literal("editor"),
|
|
116
|
-
default: z.string().optional(),
|
|
117
|
-
validate: z.array(validationRuleSchema).optional()
|
|
118
|
-
});
|
|
119
|
-
var pathStepSchema = z.object({
|
|
120
|
-
...baseStepFields,
|
|
121
|
-
type: z.literal("path"),
|
|
122
|
-
default: z.string().optional(),
|
|
123
|
-
placeholder: z.string().optional(),
|
|
124
|
-
validate: z.array(validationRuleSchema).optional()
|
|
125
|
-
});
|
|
126
|
-
var toggleStepSchema = z.object({
|
|
127
|
-
...baseStepFields,
|
|
128
|
-
type: z.literal("toggle"),
|
|
129
|
-
default: z.boolean().optional(),
|
|
130
|
-
active: z.string().optional(),
|
|
131
|
-
inactive: z.string().optional()
|
|
132
|
-
});
|
|
133
|
-
var messageStepSchema = z.object({
|
|
134
|
-
...baseStepFields,
|
|
135
|
-
type: z.literal("message")
|
|
136
|
-
});
|
|
137
|
-
var stepConfigSchema = z.discriminatedUnion("type", [
|
|
138
|
-
textStepSchema,
|
|
139
|
-
selectStepSchema,
|
|
140
|
-
multiSelectStepSchema,
|
|
141
|
-
confirmStepSchema,
|
|
142
|
-
passwordStepSchema,
|
|
143
|
-
numberStepSchema,
|
|
144
|
-
searchStepSchema,
|
|
145
|
-
editorStepSchema,
|
|
146
|
-
pathStepSchema,
|
|
147
|
-
toggleStepSchema,
|
|
148
|
-
messageStepSchema
|
|
149
|
-
]);
|
|
150
|
-
var hexColorSchema = z.string().regex(
|
|
151
|
-
/^#[0-9a-fA-F]{6}$/,
|
|
152
|
-
"Must be a 6-digit hex color (e.g., #FF0000)"
|
|
153
|
-
);
|
|
154
|
-
var themeConfigSchema = z.object({
|
|
155
|
-
tokens: z.object({
|
|
156
|
-
primary: hexColorSchema.optional(),
|
|
157
|
-
success: hexColorSchema.optional(),
|
|
158
|
-
error: hexColorSchema.optional(),
|
|
159
|
-
warning: hexColorSchema.optional(),
|
|
160
|
-
info: hexColorSchema.optional(),
|
|
161
|
-
muted: hexColorSchema.optional(),
|
|
162
|
-
accent: hexColorSchema.optional()
|
|
163
|
-
}).optional(),
|
|
164
|
-
icons: z.object({
|
|
165
|
-
step: z.string().optional(),
|
|
166
|
-
stepDone: z.string().optional(),
|
|
167
|
-
stepPending: z.string().optional(),
|
|
168
|
-
pointer: z.string().optional()
|
|
169
|
-
}).optional()
|
|
170
|
-
});
|
|
171
|
-
var preFlightCheckSchema = z.object({
|
|
172
|
-
name: z.string(),
|
|
173
|
-
run: z.string(),
|
|
174
|
-
message: z.string()
|
|
175
|
-
});
|
|
176
|
-
var actionConfigSchema = z.object({
|
|
177
|
-
name: z.string().optional(),
|
|
178
|
-
run: z.string(),
|
|
179
|
-
when: conditionSchema.optional()
|
|
180
|
-
});
|
|
181
|
-
var wizardConfigSchema = z.object({
|
|
182
|
-
meta: z.object({
|
|
183
|
-
name: z.string(),
|
|
184
|
-
version: z.string().optional(),
|
|
185
|
-
description: z.string().optional()
|
|
186
|
-
}),
|
|
187
|
-
theme: themeConfigSchema.optional(),
|
|
188
|
-
steps: z.array(stepConfigSchema).min(1),
|
|
189
|
-
output: z.object({
|
|
190
|
-
format: z.enum(["json", "env", "yaml"]),
|
|
191
|
-
path: z.string().optional()
|
|
192
|
-
}).optional(),
|
|
193
|
-
extends: z.string().optional(),
|
|
194
|
-
checks: z.array(preFlightCheckSchema).optional(),
|
|
195
|
-
actions: z.array(actionConfigSchema).optional()
|
|
196
|
-
}).superRefine((config, ctx) => {
|
|
197
|
-
const stepIds = /* @__PURE__ */ new Set();
|
|
198
|
-
for (const step of config.steps) {
|
|
199
|
-
if (stepIds.has(step.id)) {
|
|
200
|
-
ctx.addIssue({
|
|
201
|
-
code: z.ZodIssueCode.custom,
|
|
202
|
-
message: `Duplicate step ID: "${step.id}"`,
|
|
203
|
-
path: ["steps"]
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
stepIds.add(step.id);
|
|
207
|
-
}
|
|
208
|
-
config.steps.forEach((step, i) => {
|
|
209
|
-
if (step.next && step.next !== "__done__" && !stepIds.has(step.next)) {
|
|
210
|
-
ctx.addIssue({
|
|
211
|
-
code: z.ZodIssueCode.custom,
|
|
212
|
-
message: `Step "${step.id}" references unknown next step: "${step.next}"`,
|
|
213
|
-
path: ["steps", i, "next"]
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
if (step.type === "select" && step.routes) {
|
|
217
|
-
for (const [key, target] of Object.entries(step.routes)) {
|
|
218
|
-
if (target !== "__done__" && !stepIds.has(target)) {
|
|
219
|
-
ctx.addIssue({
|
|
220
|
-
code: z.ZodIssueCode.custom,
|
|
221
|
-
message: `Step "${step.id}" route "${key}" references unknown step: "${target}"`,
|
|
222
|
-
path: ["steps", i, "routes", key]
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
if (step.when) {
|
|
228
|
-
collectConditionFieldIssues(step.when, stepIds, ctx, ["steps", i, "when"]);
|
|
229
|
-
}
|
|
230
|
-
if (step.type === "select" && step.routes && step.options) {
|
|
231
|
-
const optionValues = /* @__PURE__ */ new Set();
|
|
232
|
-
for (const o of step.options) {
|
|
233
|
-
if ("value" in o) {
|
|
234
|
-
optionValues.add(o.value);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
for (const routeKey of Object.keys(step.routes)) {
|
|
238
|
-
if (!optionValues.has(routeKey)) {
|
|
239
|
-
ctx.addIssue({
|
|
240
|
-
code: z.ZodIssueCode.custom,
|
|
241
|
-
message: `Step "${step.id}" route key "${routeKey}" does not match any option value`,
|
|
242
|
-
path: ["steps", i, "routes", routeKey]
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
if (step.type === "select" || step.type === "multiselect" || step.type === "search") {
|
|
248
|
-
const hasOptions = step.options !== void 0;
|
|
249
|
-
const hasOptionsFrom = step.optionsFrom !== void 0;
|
|
250
|
-
if (hasOptions && hasOptionsFrom) {
|
|
251
|
-
ctx.addIssue({
|
|
252
|
-
code: z.ZodIssueCode.custom,
|
|
253
|
-
message: `Step "${step.id}" has both "options" and "optionsFrom" \u2014 only one is allowed`,
|
|
254
|
-
path: ["steps", i]
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
if (!hasOptions && !hasOptionsFrom) {
|
|
258
|
-
ctx.addIssue({
|
|
259
|
-
code: z.ZodIssueCode.custom,
|
|
260
|
-
message: `Step "${step.id}" must have either "options" or "optionsFrom"`,
|
|
261
|
-
path: ["steps", i]
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
if ((step.type === "number" || step.type === "multiselect") && step.min !== void 0 && step.max !== void 0 && step.min > step.max) {
|
|
266
|
-
ctx.addIssue({
|
|
267
|
-
code: z.ZodIssueCode.custom,
|
|
268
|
-
message: `Step "${step.id}" has min (${String(step.min)}) greater than max (${String(step.max)})`,
|
|
269
|
-
path: ["steps", i]
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
if (config.actions) {
|
|
274
|
-
config.actions.forEach((action, i) => {
|
|
275
|
-
if (action.when) {
|
|
276
|
-
collectConditionFieldIssues(action.when, stepIds, ctx, ["actions", i, "when"]);
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
13
|
function collectConditionFieldIssues(condition, validIds, ctx, path) {
|
|
282
14
|
if ("field" in condition) {
|
|
283
15
|
const fieldRoot = condition.field.split(".")[0];
|
|
@@ -310,13 +42,308 @@ function parseWizardConfig(raw) {
|
|
|
310
42
|
const result = wizardConfigSchema.parse(raw);
|
|
311
43
|
return result;
|
|
312
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;
|
|
46
|
+
var init_schema = __esm({
|
|
47
|
+
"src/schema.ts"() {
|
|
48
|
+
"use strict";
|
|
49
|
+
conditionSchema = z.lazy(() => {
|
|
50
|
+
const fieldEquals = z.object({ field: z.string(), equals: z.unknown() }).strict();
|
|
51
|
+
const fieldNotEquals = z.object({ field: z.string(), notEquals: z.unknown() }).strict();
|
|
52
|
+
const fieldIncludes = z.object({ field: z.string(), includes: z.unknown() }).strict();
|
|
53
|
+
const fieldNotIncludes = z.object({ field: z.string(), notIncludes: z.unknown() }).strict();
|
|
54
|
+
const fieldGreaterThan = z.object({ field: z.string(), greaterThan: z.number() }).strict();
|
|
55
|
+
const fieldLessThan = z.object({ field: z.string(), lessThan: z.number() }).strict();
|
|
56
|
+
const fieldIsEmpty = z.object({ field: z.string(), isEmpty: z.literal(true) }).strict();
|
|
57
|
+
const fieldIsNotEmpty = z.object({ field: z.string(), isNotEmpty: z.literal(true) }).strict();
|
|
58
|
+
const allCondition = z.object({ all: z.array(conditionSchema) }).strict();
|
|
59
|
+
const anyCondition = z.object({ any: z.array(conditionSchema) }).strict();
|
|
60
|
+
const notCondition = z.object({ not: conditionSchema }).strict();
|
|
61
|
+
return z.union([
|
|
62
|
+
fieldEquals,
|
|
63
|
+
fieldNotEquals,
|
|
64
|
+
fieldIncludes,
|
|
65
|
+
fieldNotIncludes,
|
|
66
|
+
fieldGreaterThan,
|
|
67
|
+
fieldLessThan,
|
|
68
|
+
fieldIsEmpty,
|
|
69
|
+
fieldIsNotEmpty,
|
|
70
|
+
allCondition,
|
|
71
|
+
anyCondition,
|
|
72
|
+
notCondition
|
|
73
|
+
]);
|
|
74
|
+
});
|
|
75
|
+
validationRuleSchema = z.discriminatedUnion("rule", [
|
|
76
|
+
z.object({ rule: z.literal("required"), message: z.string().optional() }),
|
|
77
|
+
z.object({ rule: z.literal("minLength"), value: z.number(), message: z.string().optional() }),
|
|
78
|
+
z.object({ rule: z.literal("maxLength"), value: z.number(), message: z.string().optional() }),
|
|
79
|
+
z.object({ rule: z.literal("pattern"), value: z.string(), message: z.string().optional() }),
|
|
80
|
+
z.object({ rule: z.literal("min"), value: z.number(), message: z.string().optional() }),
|
|
81
|
+
z.object({ rule: z.literal("max"), value: z.number(), message: z.string().optional() })
|
|
82
|
+
]);
|
|
83
|
+
selectOptionSchema = z.object({
|
|
84
|
+
value: z.string(),
|
|
85
|
+
label: z.string(),
|
|
86
|
+
hint: z.string().optional(),
|
|
87
|
+
disabled: z.union([z.boolean(), z.string()]).optional()
|
|
88
|
+
});
|
|
89
|
+
separatorOptionSchema = z.object({
|
|
90
|
+
separator: z.string()
|
|
91
|
+
});
|
|
92
|
+
selectChoiceSchema = z.union([selectOptionSchema, separatorOptionSchema]);
|
|
93
|
+
baseStepFields = {
|
|
94
|
+
id: z.string(),
|
|
95
|
+
message: z.string(),
|
|
96
|
+
description: z.string().optional(),
|
|
97
|
+
next: z.string().optional(),
|
|
98
|
+
when: conditionSchema.optional(),
|
|
99
|
+
keepValuesOnPrevious: z.boolean().optional(),
|
|
100
|
+
required: z.boolean().optional(),
|
|
101
|
+
group: z.string().optional()
|
|
102
|
+
};
|
|
103
|
+
textStepSchema = z.object({
|
|
104
|
+
...baseStepFields,
|
|
105
|
+
type: z.literal("text"),
|
|
106
|
+
placeholder: z.string().optional(),
|
|
107
|
+
default: z.string().optional(),
|
|
108
|
+
validate: z.array(validationRuleSchema).optional()
|
|
109
|
+
});
|
|
110
|
+
selectStepSchema = z.object({
|
|
111
|
+
...baseStepFields,
|
|
112
|
+
type: z.literal("select"),
|
|
113
|
+
options: z.array(selectChoiceSchema).min(1).optional(),
|
|
114
|
+
optionsFrom: z.string().optional(),
|
|
115
|
+
default: z.string().optional(),
|
|
116
|
+
routes: z.record(z.string(), z.string()).optional(),
|
|
117
|
+
pageSize: z.number().int().positive().optional(),
|
|
118
|
+
loop: z.boolean().optional()
|
|
119
|
+
});
|
|
120
|
+
multiSelectStepSchema = z.object({
|
|
121
|
+
...baseStepFields,
|
|
122
|
+
type: z.literal("multiselect"),
|
|
123
|
+
options: z.array(selectChoiceSchema).min(1).optional(),
|
|
124
|
+
optionsFrom: z.string().optional(),
|
|
125
|
+
default: z.array(z.string()).optional(),
|
|
126
|
+
min: z.number().int().nonnegative().optional(),
|
|
127
|
+
max: z.number().int().positive().optional(),
|
|
128
|
+
pageSize: z.number().int().positive().optional(),
|
|
129
|
+
loop: z.boolean().optional()
|
|
130
|
+
});
|
|
131
|
+
confirmStepSchema = z.object({
|
|
132
|
+
...baseStepFields,
|
|
133
|
+
type: z.literal("confirm"),
|
|
134
|
+
default: z.boolean().optional()
|
|
135
|
+
});
|
|
136
|
+
passwordStepSchema = z.object({
|
|
137
|
+
...baseStepFields,
|
|
138
|
+
type: z.literal("password"),
|
|
139
|
+
validate: z.array(validationRuleSchema).optional()
|
|
140
|
+
});
|
|
141
|
+
numberStepSchema = z.object({
|
|
142
|
+
...baseStepFields,
|
|
143
|
+
type: z.literal("number"),
|
|
144
|
+
default: z.number().optional(),
|
|
145
|
+
min: z.number().optional(),
|
|
146
|
+
max: z.number().optional(),
|
|
147
|
+
step: z.number().positive().optional()
|
|
148
|
+
});
|
|
149
|
+
searchStepSchema = z.object({
|
|
150
|
+
...baseStepFields,
|
|
151
|
+
type: z.literal("search"),
|
|
152
|
+
options: z.array(selectChoiceSchema).min(1).optional(),
|
|
153
|
+
optionsFrom: z.string().optional(),
|
|
154
|
+
default: z.string().optional(),
|
|
155
|
+
placeholder: z.string().optional(),
|
|
156
|
+
pageSize: z.number().int().positive().optional(),
|
|
157
|
+
loop: z.boolean().optional()
|
|
158
|
+
});
|
|
159
|
+
editorStepSchema = z.object({
|
|
160
|
+
...baseStepFields,
|
|
161
|
+
type: z.literal("editor"),
|
|
162
|
+
default: z.string().optional(),
|
|
163
|
+
validate: z.array(validationRuleSchema).optional()
|
|
164
|
+
});
|
|
165
|
+
pathStepSchema = z.object({
|
|
166
|
+
...baseStepFields,
|
|
167
|
+
type: z.literal("path"),
|
|
168
|
+
default: z.string().optional(),
|
|
169
|
+
placeholder: z.string().optional(),
|
|
170
|
+
validate: z.array(validationRuleSchema).optional()
|
|
171
|
+
});
|
|
172
|
+
toggleStepSchema = z.object({
|
|
173
|
+
...baseStepFields,
|
|
174
|
+
type: z.literal("toggle"),
|
|
175
|
+
default: z.boolean().optional(),
|
|
176
|
+
active: z.string().optional(),
|
|
177
|
+
inactive: z.string().optional()
|
|
178
|
+
});
|
|
179
|
+
messageStepSchema = z.object({
|
|
180
|
+
...baseStepFields,
|
|
181
|
+
type: z.literal("message")
|
|
182
|
+
});
|
|
183
|
+
noteStepSchema = z.object({
|
|
184
|
+
...baseStepFields,
|
|
185
|
+
type: z.literal("note")
|
|
186
|
+
});
|
|
187
|
+
stepConfigSchema = z.discriminatedUnion("type", [
|
|
188
|
+
textStepSchema,
|
|
189
|
+
selectStepSchema,
|
|
190
|
+
multiSelectStepSchema,
|
|
191
|
+
confirmStepSchema,
|
|
192
|
+
passwordStepSchema,
|
|
193
|
+
numberStepSchema,
|
|
194
|
+
searchStepSchema,
|
|
195
|
+
editorStepSchema,
|
|
196
|
+
pathStepSchema,
|
|
197
|
+
toggleStepSchema,
|
|
198
|
+
messageStepSchema,
|
|
199
|
+
noteStepSchema
|
|
200
|
+
]);
|
|
201
|
+
hexColorSchema = z.string().regex(
|
|
202
|
+
/^#[0-9a-fA-F]{6}$/,
|
|
203
|
+
"Must be a 6-digit hex color (e.g., #FF0000)"
|
|
204
|
+
);
|
|
205
|
+
themeConfigSchema = z.object({
|
|
206
|
+
preset: z.enum(["default", "catppuccin", "dracula", "nord", "tokyonight", "monokai"]).optional(),
|
|
207
|
+
tokens: z.object({
|
|
208
|
+
primary: hexColorSchema.optional(),
|
|
209
|
+
success: hexColorSchema.optional(),
|
|
210
|
+
error: hexColorSchema.optional(),
|
|
211
|
+
warning: hexColorSchema.optional(),
|
|
212
|
+
info: hexColorSchema.optional(),
|
|
213
|
+
muted: hexColorSchema.optional(),
|
|
214
|
+
accent: hexColorSchema.optional()
|
|
215
|
+
}).optional(),
|
|
216
|
+
icons: z.object({
|
|
217
|
+
step: z.string().optional(),
|
|
218
|
+
stepDone: z.string().optional(),
|
|
219
|
+
stepPending: z.string().optional(),
|
|
220
|
+
pointer: z.string().optional()
|
|
221
|
+
}).optional()
|
|
222
|
+
});
|
|
223
|
+
preFlightCheckSchema = z.object({
|
|
224
|
+
name: z.string(),
|
|
225
|
+
run: z.string(),
|
|
226
|
+
message: z.string()
|
|
227
|
+
});
|
|
228
|
+
actionConfigSchema = z.object({
|
|
229
|
+
name: z.string().optional(),
|
|
230
|
+
run: z.string(),
|
|
231
|
+
when: conditionSchema.optional()
|
|
232
|
+
});
|
|
233
|
+
wizardConfigSchema = z.object({
|
|
234
|
+
meta: z.object({
|
|
235
|
+
name: z.string(),
|
|
236
|
+
version: z.string().optional(),
|
|
237
|
+
description: z.string().optional(),
|
|
238
|
+
review: z.boolean().optional()
|
|
239
|
+
}),
|
|
240
|
+
theme: themeConfigSchema.optional(),
|
|
241
|
+
steps: z.array(stepConfigSchema).min(1),
|
|
242
|
+
output: z.object({
|
|
243
|
+
format: z.enum(["json", "env", "yaml"]),
|
|
244
|
+
path: z.string().optional()
|
|
245
|
+
}).optional(),
|
|
246
|
+
extends: z.string().optional(),
|
|
247
|
+
checks: z.array(preFlightCheckSchema).optional(),
|
|
248
|
+
actions: z.array(actionConfigSchema).optional()
|
|
249
|
+
}).superRefine((config, ctx) => {
|
|
250
|
+
const stepIds = /* @__PURE__ */ new Set();
|
|
251
|
+
for (const step of config.steps) {
|
|
252
|
+
if (stepIds.has(step.id)) {
|
|
253
|
+
ctx.addIssue({
|
|
254
|
+
code: z.ZodIssueCode.custom,
|
|
255
|
+
message: `Duplicate step ID: "${step.id}"`,
|
|
256
|
+
path: ["steps"]
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
stepIds.add(step.id);
|
|
260
|
+
}
|
|
261
|
+
config.steps.forEach((step, i) => {
|
|
262
|
+
if (step.next && step.next !== "__done__" && !stepIds.has(step.next)) {
|
|
263
|
+
ctx.addIssue({
|
|
264
|
+
code: z.ZodIssueCode.custom,
|
|
265
|
+
message: `Step "${step.id}" references unknown next step: "${step.next}"`,
|
|
266
|
+
path: ["steps", i, "next"]
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
if (step.type === "select" && step.routes) {
|
|
270
|
+
for (const [key, target] of Object.entries(step.routes)) {
|
|
271
|
+
if (target !== "__done__" && !stepIds.has(target)) {
|
|
272
|
+
ctx.addIssue({
|
|
273
|
+
code: z.ZodIssueCode.custom,
|
|
274
|
+
message: `Step "${step.id}" route "${key}" references unknown step: "${target}"`,
|
|
275
|
+
path: ["steps", i, "routes", key]
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (step.when) {
|
|
281
|
+
collectConditionFieldIssues(step.when, stepIds, ctx, ["steps", i, "when"]);
|
|
282
|
+
}
|
|
283
|
+
if (step.type === "select" && step.routes && step.options) {
|
|
284
|
+
const optionValues = /* @__PURE__ */ new Set();
|
|
285
|
+
for (const o of step.options) {
|
|
286
|
+
if ("value" in o) {
|
|
287
|
+
optionValues.add(o.value);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
for (const routeKey of Object.keys(step.routes)) {
|
|
291
|
+
if (!optionValues.has(routeKey)) {
|
|
292
|
+
ctx.addIssue({
|
|
293
|
+
code: z.ZodIssueCode.custom,
|
|
294
|
+
message: `Step "${step.id}" route key "${routeKey}" does not match any option value`,
|
|
295
|
+
path: ["steps", i, "routes", routeKey]
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (step.type === "select" || step.type === "multiselect" || step.type === "search") {
|
|
301
|
+
const hasOptions = step.options !== void 0;
|
|
302
|
+
const hasOptionsFrom = step.optionsFrom !== void 0;
|
|
303
|
+
if (hasOptions && hasOptionsFrom) {
|
|
304
|
+
ctx.addIssue({
|
|
305
|
+
code: z.ZodIssueCode.custom,
|
|
306
|
+
message: `Step "${step.id}" has both "options" and "optionsFrom" \u2014 only one is allowed`,
|
|
307
|
+
path: ["steps", i]
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
if (!hasOptions && !hasOptionsFrom) {
|
|
311
|
+
ctx.addIssue({
|
|
312
|
+
code: z.ZodIssueCode.custom,
|
|
313
|
+
message: `Step "${step.id}" must have either "options" or "optionsFrom"`,
|
|
314
|
+
path: ["steps", i]
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if ((step.type === "number" || step.type === "multiselect") && step.min !== void 0 && step.max !== void 0 && step.min > step.max) {
|
|
319
|
+
ctx.addIssue({
|
|
320
|
+
code: z.ZodIssueCode.custom,
|
|
321
|
+
message: `Step "${step.id}" has min (${String(step.min)}) greater than max (${String(step.max)})`,
|
|
322
|
+
path: ["steps", i]
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
if (config.actions) {
|
|
327
|
+
config.actions.forEach((action, i) => {
|
|
328
|
+
if (action.when) {
|
|
329
|
+
collectConditionFieldIssues(action.when, stepIds, ctx, ["actions", i, "when"]);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
});
|
|
313
336
|
|
|
314
337
|
// src/parser.ts
|
|
338
|
+
var parser_exports = {};
|
|
339
|
+
__export(parser_exports, {
|
|
340
|
+
loadWizardConfig: () => loadWizardConfig,
|
|
341
|
+
parseWizardYAML: () => parseWizardYAML
|
|
342
|
+
});
|
|
315
343
|
import { cosmiconfig } from "cosmiconfig";
|
|
316
344
|
import { readFileSync } from "fs";
|
|
317
345
|
import { dirname, resolve, isAbsolute } from "path";
|
|
318
346
|
import { parse as parseYAML } from "yaml";
|
|
319
|
-
var DONE_SENTINEL = "__done__";
|
|
320
347
|
function buildStepGraph(steps) {
|
|
321
348
|
const graph = /* @__PURE__ */ new Map();
|
|
322
349
|
for (let i = 0; i < steps.length; i++) {
|
|
@@ -395,7 +422,6 @@ function mergeConfigs(parent, child) {
|
|
|
395
422
|
actions: child.actions ?? parent.actions
|
|
396
423
|
};
|
|
397
424
|
}
|
|
398
|
-
var OPTION_STEP_TYPES = /* @__PURE__ */ new Set(["select", "multiselect", "search"]);
|
|
399
425
|
function resolveOptionsFromSteps(raw, configDir) {
|
|
400
426
|
const steps = raw["steps"];
|
|
401
427
|
if (!Array.isArray(steps)) return;
|
|
@@ -491,6 +517,19 @@ function parseWizardYAML(yamlString) {
|
|
|
491
517
|
detectCycles(config);
|
|
492
518
|
return config;
|
|
493
519
|
}
|
|
520
|
+
var DONE_SENTINEL, OPTION_STEP_TYPES;
|
|
521
|
+
var init_parser = __esm({
|
|
522
|
+
"src/parser.ts"() {
|
|
523
|
+
"use strict";
|
|
524
|
+
init_schema();
|
|
525
|
+
DONE_SENTINEL = "__done__";
|
|
526
|
+
OPTION_STEP_TYPES = /* @__PURE__ */ new Set(["select", "multiselect", "search"]);
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
// src/index.ts
|
|
531
|
+
init_schema();
|
|
532
|
+
init_parser();
|
|
494
533
|
|
|
495
534
|
// src/conditions.ts
|
|
496
535
|
function isRecord(value) {
|
|
@@ -770,6 +809,67 @@ function applyValidationRule(rule, value) {
|
|
|
770
809
|
|
|
771
810
|
// src/theme.ts
|
|
772
811
|
import chalk from "chalk";
|
|
812
|
+
|
|
813
|
+
// src/themes/presets.ts
|
|
814
|
+
var THEME_PRESETS = {
|
|
815
|
+
default: {
|
|
816
|
+
primary: "#7C3AED",
|
|
817
|
+
success: "#10B981",
|
|
818
|
+
error: "#EF4444",
|
|
819
|
+
warning: "#F59E0B",
|
|
820
|
+
info: "#3B82F6",
|
|
821
|
+
muted: "#6B7280",
|
|
822
|
+
accent: "#8B5CF6"
|
|
823
|
+
},
|
|
824
|
+
catppuccin: {
|
|
825
|
+
primary: "#cba6f7",
|
|
826
|
+
success: "#a6e3a1",
|
|
827
|
+
error: "#f38ba8",
|
|
828
|
+
warning: "#fab387",
|
|
829
|
+
info: "#74c7ec",
|
|
830
|
+
muted: "#6c7086",
|
|
831
|
+
accent: "#f5c2e7"
|
|
832
|
+
},
|
|
833
|
+
dracula: {
|
|
834
|
+
primary: "#bd93f9",
|
|
835
|
+
success: "#50fa7b",
|
|
836
|
+
error: "#ff5555",
|
|
837
|
+
warning: "#ffb86c",
|
|
838
|
+
info: "#8be9fd",
|
|
839
|
+
muted: "#6272a4",
|
|
840
|
+
accent: "#ff79c6"
|
|
841
|
+
},
|
|
842
|
+
nord: {
|
|
843
|
+
primary: "#88c0d0",
|
|
844
|
+
success: "#a3be8c",
|
|
845
|
+
error: "#bf616a",
|
|
846
|
+
warning: "#ebcb8b",
|
|
847
|
+
info: "#81a1c1",
|
|
848
|
+
muted: "#4c566a",
|
|
849
|
+
accent: "#b48ead"
|
|
850
|
+
},
|
|
851
|
+
tokyonight: {
|
|
852
|
+
primary: "#7aa2f7",
|
|
853
|
+
success: "#9ece6a",
|
|
854
|
+
error: "#f7768e",
|
|
855
|
+
warning: "#e0af68",
|
|
856
|
+
info: "#7dcfff",
|
|
857
|
+
muted: "#565f89",
|
|
858
|
+
accent: "#bb9af7"
|
|
859
|
+
},
|
|
860
|
+
monokai: {
|
|
861
|
+
primary: "#ab9df2",
|
|
862
|
+
success: "#a9dc76",
|
|
863
|
+
error: "#ff6188",
|
|
864
|
+
warning: "#ffd866",
|
|
865
|
+
info: "#78dce8",
|
|
866
|
+
muted: "#727072",
|
|
867
|
+
accent: "#fc9867"
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
var PRESET_NAMES = Object.keys(THEME_PRESETS);
|
|
871
|
+
|
|
872
|
+
// src/theme.ts
|
|
773
873
|
var DEFAULT_TOKENS = {
|
|
774
874
|
primary: "#5B9BD5",
|
|
775
875
|
success: "#6BCB77",
|
|
@@ -786,7 +886,8 @@ var DEFAULT_ICONS = {
|
|
|
786
886
|
pointer: "\u203A"
|
|
787
887
|
};
|
|
788
888
|
function resolveTheme(themeConfig) {
|
|
789
|
-
const
|
|
889
|
+
const presetTokens = themeConfig?.preset ? THEME_PRESETS[themeConfig.preset] : void 0;
|
|
890
|
+
const tokens = { ...DEFAULT_TOKENS, ...presetTokens, ...themeConfig?.tokens };
|
|
790
891
|
const icons = { ...DEFAULT_ICONS, ...themeConfig?.icons };
|
|
791
892
|
return {
|
|
792
893
|
primary: chalk.hex(tokens.primary),
|
|
@@ -1131,14 +1232,66 @@ function clearCache(wizardName, customDir) {
|
|
|
1131
1232
|
}
|
|
1132
1233
|
}
|
|
1133
1234
|
|
|
1134
|
-
// src/
|
|
1135
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2,
|
|
1235
|
+
// src/progress.ts
|
|
1236
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
1136
1237
|
import { join as join2 } from "path";
|
|
1137
1238
|
import { homedir as homedir2 } from "os";
|
|
1138
|
-
var
|
|
1239
|
+
var DEFAULT_PROGRESS_DIR = join2(homedir2(), ".config", "grimoire", "progress");
|
|
1240
|
+
function getProgressFilePath(wizardName, customDir) {
|
|
1241
|
+
const dir = customDir ?? DEFAULT_PROGRESS_DIR;
|
|
1242
|
+
return join2(dir, `${slugify(wizardName)}.json`);
|
|
1243
|
+
}
|
|
1244
|
+
function saveProgress(wizardName, state, customDir, excludeStepIds) {
|
|
1245
|
+
try {
|
|
1246
|
+
const dir = customDir ?? DEFAULT_PROGRESS_DIR;
|
|
1247
|
+
mkdirSync2(dir, { recursive: true });
|
|
1248
|
+
const excludeSet = new Set(excludeStepIds ?? []);
|
|
1249
|
+
const filteredAnswers = {};
|
|
1250
|
+
for (const [key, value] of Object.entries(state.answers)) {
|
|
1251
|
+
if (!excludeSet.has(key)) {
|
|
1252
|
+
filteredAnswers[key] = value;
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
const progress = {
|
|
1256
|
+
currentStepId: state.currentStepId,
|
|
1257
|
+
answers: filteredAnswers,
|
|
1258
|
+
history: state.history,
|
|
1259
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1260
|
+
};
|
|
1261
|
+
const filePath = getProgressFilePath(wizardName, customDir);
|
|
1262
|
+
writeFileSync2(filePath, JSON.stringify(progress, null, 2) + "\n", "utf-8");
|
|
1263
|
+
} catch {
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
function loadProgress(wizardName, customDir) {
|
|
1267
|
+
try {
|
|
1268
|
+
const filePath = getProgressFilePath(wizardName, customDir);
|
|
1269
|
+
const raw = readFileSync3(filePath, "utf-8");
|
|
1270
|
+
const parsed = JSON.parse(raw);
|
|
1271
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) && "currentStepId" in parsed && "answers" in parsed && "history" in parsed && "savedAt" in parsed) {
|
|
1272
|
+
return parsed;
|
|
1273
|
+
}
|
|
1274
|
+
return null;
|
|
1275
|
+
} catch {
|
|
1276
|
+
return null;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
function clearProgress(wizardName, customDir) {
|
|
1280
|
+
try {
|
|
1281
|
+
const filePath = getProgressFilePath(wizardName, customDir);
|
|
1282
|
+
unlinkSync2(filePath);
|
|
1283
|
+
} catch {
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
// src/mru.ts
|
|
1288
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync } from "fs";
|
|
1289
|
+
import { join as join3 } from "path";
|
|
1290
|
+
import { homedir as homedir3 } from "os";
|
|
1291
|
+
var MRU_DIR = join3(homedir3(), ".config", "grimoire", "mru");
|
|
1139
1292
|
function getMruFilePath(wizardName) {
|
|
1140
1293
|
const safeName = wizardName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1141
|
-
return
|
|
1294
|
+
return join3(MRU_DIR, `${safeName}.json`);
|
|
1142
1295
|
}
|
|
1143
1296
|
function loadMruData(wizardName) {
|
|
1144
1297
|
const filePath = getMruFilePath(wizardName);
|
|
@@ -1146,7 +1299,7 @@ function loadMruData(wizardName) {
|
|
|
1146
1299
|
if (!existsSync(filePath)) {
|
|
1147
1300
|
return {};
|
|
1148
1301
|
}
|
|
1149
|
-
const raw =
|
|
1302
|
+
const raw = readFileSync4(filePath, "utf-8");
|
|
1150
1303
|
const parsed = JSON.parse(raw);
|
|
1151
1304
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
1152
1305
|
return {};
|
|
@@ -1159,8 +1312,8 @@ function loadMruData(wizardName) {
|
|
|
1159
1312
|
function saveMruData(wizardName, data) {
|
|
1160
1313
|
const filePath = getMruFilePath(wizardName);
|
|
1161
1314
|
try {
|
|
1162
|
-
|
|
1163
|
-
|
|
1315
|
+
mkdirSync3(MRU_DIR, { recursive: true });
|
|
1316
|
+
writeFileSync3(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
1164
1317
|
} catch {
|
|
1165
1318
|
}
|
|
1166
1319
|
}
|
|
@@ -1216,20 +1369,28 @@ function clearMruData(wizardName) {
|
|
|
1216
1369
|
const filePath = getMruFilePath(wizardName);
|
|
1217
1370
|
try {
|
|
1218
1371
|
if (existsSync(filePath)) {
|
|
1219
|
-
|
|
1372
|
+
writeFileSync3(filePath, "{}", "utf-8");
|
|
1220
1373
|
}
|
|
1221
1374
|
} catch {
|
|
1222
1375
|
}
|
|
1223
1376
|
}
|
|
1224
1377
|
|
|
1225
1378
|
// src/runner.ts
|
|
1226
|
-
function
|
|
1379
|
+
function emitEvent(renderer, event, theme) {
|
|
1380
|
+
if (renderer.onEvent) {
|
|
1381
|
+
renderer.onEvent(event, theme);
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
function runPreFlightChecks(checks, theme, renderer) {
|
|
1385
|
+
if (renderer) emitEvent(renderer, { type: "checks:start", checks }, theme);
|
|
1227
1386
|
for (const check of checks) {
|
|
1228
1387
|
try {
|
|
1229
1388
|
execSync(check.run, { stdio: "pipe" });
|
|
1230
1389
|
console.log(` ${theme.success("\u2713")} ${check.name}`);
|
|
1390
|
+
if (renderer) emitEvent(renderer, { type: "check:pass", name: check.name }, theme);
|
|
1231
1391
|
} catch {
|
|
1232
1392
|
console.log(` ${theme.error("\u2717")} ${check.name}: ${check.message}`);
|
|
1393
|
+
if (renderer) emitEvent(renderer, { type: "check:fail", name: check.name, message: check.message }, theme);
|
|
1233
1394
|
throw new Error(`Pre-flight check failed: ${check.name} \u2014 ${check.message}`);
|
|
1234
1395
|
}
|
|
1235
1396
|
}
|
|
@@ -1239,7 +1400,7 @@ function getMockValue(step, mockAnswers) {
|
|
|
1239
1400
|
if (step.id in mockAnswers) {
|
|
1240
1401
|
return mockAnswers[step.id];
|
|
1241
1402
|
}
|
|
1242
|
-
if (step.type === "message") {
|
|
1403
|
+
if (step.type === "message" || step.type === "note") {
|
|
1243
1404
|
return true;
|
|
1244
1405
|
}
|
|
1245
1406
|
const defaultValue = getStepDefault(step);
|
|
@@ -1267,6 +1428,7 @@ function getStepDefault(step) {
|
|
|
1267
1428
|
return step.default;
|
|
1268
1429
|
case "password":
|
|
1269
1430
|
case "message":
|
|
1431
|
+
case "note":
|
|
1270
1432
|
return void 0;
|
|
1271
1433
|
}
|
|
1272
1434
|
}
|
|
@@ -1280,6 +1442,21 @@ async function runWizard(config, options) {
|
|
|
1280
1442
|
const cacheDir = typeof options?.cache === "object" ? options.cache.dir : void 0;
|
|
1281
1443
|
const mruEnabled = !isMock && options?.mru !== false;
|
|
1282
1444
|
let state = createWizardState(config);
|
|
1445
|
+
const resumeEnabled = !isMock && options?.resume !== false;
|
|
1446
|
+
if (resumeEnabled) {
|
|
1447
|
+
const saved = loadProgress(config.meta.name);
|
|
1448
|
+
if (saved) {
|
|
1449
|
+
const stepExists = config.steps.some((s) => s.id === saved.currentStepId);
|
|
1450
|
+
if (stepExists) {
|
|
1451
|
+
state = {
|
|
1452
|
+
...state,
|
|
1453
|
+
currentStepId: saved.currentStepId,
|
|
1454
|
+
answers: { ...state.answers, ...saved.answers },
|
|
1455
|
+
history: saved.history
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1283
1460
|
const cachedAnswers = cacheEnabled ? loadCachedAnswers(config.meta.name, cacheDir) : void 0;
|
|
1284
1461
|
const userPlugins = options?.plugins;
|
|
1285
1462
|
if (userPlugins) {
|
|
@@ -1289,103 +1466,169 @@ async function runWizard(config, options) {
|
|
|
1289
1466
|
}
|
|
1290
1467
|
try {
|
|
1291
1468
|
if (!isMock && config.checks && config.checks.length > 0) {
|
|
1292
|
-
runPreFlightChecks(config.checks, theme);
|
|
1469
|
+
runPreFlightChecks(config.checks, theme, renderer);
|
|
1293
1470
|
}
|
|
1294
1471
|
if (!quiet) {
|
|
1295
1472
|
printWizardHeader(config, theme, options?.plain);
|
|
1296
1473
|
}
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1474
|
+
const visibleStepsForCount = getVisibleSteps(config, state.answers);
|
|
1475
|
+
emitEvent(renderer, { type: "session:start", wizard: config.meta.name, description: config.meta.description, totalSteps: visibleStepsForCount.length }, theme);
|
|
1476
|
+
let needsReview = true;
|
|
1477
|
+
while (needsReview) {
|
|
1478
|
+
let previousGroup;
|
|
1479
|
+
while (state.status === "running") {
|
|
1480
|
+
const visibleSteps = getVisibleSteps(config, state.answers);
|
|
1481
|
+
const currentStep = config.steps.find((s) => s.id === state.currentStepId);
|
|
1482
|
+
if (!currentStep) {
|
|
1483
|
+
throw new Error(`Current step not found: "${state.currentStepId}"`);
|
|
1484
|
+
}
|
|
1305
1485
|
if (currentStep.group !== void 0 && currentStep.group !== previousGroup) {
|
|
1306
1486
|
const resolvedGroup = resolveTemplate(currentStep.group, state.answers);
|
|
1307
|
-
|
|
1487
|
+
if (!isMock) {
|
|
1488
|
+
renderer.renderGroupHeader(resolvedGroup, theme);
|
|
1489
|
+
}
|
|
1490
|
+
emitEvent(renderer, { type: "group:start", group: resolvedGroup }, theme);
|
|
1308
1491
|
}
|
|
1309
1492
|
previousGroup = currentStep.group;
|
|
1310
1493
|
const stepIndex = visibleSteps.findIndex((s) => s.id === state.currentStepId);
|
|
1311
1494
|
const resolvedMessage = resolveTemplate(currentStep.message, state.answers);
|
|
1312
1495
|
const resolvedDescription = currentStep.description ? resolveTemplate(currentStep.description, state.answers) : void 0;
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
const
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1496
|
+
if (!isMock) {
|
|
1497
|
+
renderer.renderStepHeader(stepIndex, visibleSteps.length, resolvedMessage, theme, resolvedDescription);
|
|
1498
|
+
}
|
|
1499
|
+
emitEvent(renderer, { type: "step:start", stepId: currentStep.id, stepIndex, totalVisible: visibleSteps.length, step: currentStep }, theme);
|
|
1500
|
+
if (currentStep.type === "note") {
|
|
1501
|
+
emitEvent(renderer, { type: "note", title: resolvedMessage, body: resolvedDescription ?? "" }, theme);
|
|
1502
|
+
}
|
|
1503
|
+
if (options?.onBeforeStep) {
|
|
1504
|
+
await options.onBeforeStep(currentStep.id, currentStep, state);
|
|
1505
|
+
}
|
|
1506
|
+
const pluginStep = getPluginStep(currentStep.type);
|
|
1507
|
+
const resolvedStep = pluginStep ? currentStep : resolveStepDefaults(currentStep, cachedAnswers);
|
|
1508
|
+
const withTemplate = options?.templateAnswers ? applyTemplateDefaults(resolvedStep, options.templateAnswers) : resolvedStep;
|
|
1509
|
+
const templatedStep = resolveStepTemplates(withTemplate, state.answers);
|
|
1510
|
+
const mruStep = mruEnabled ? applyMruOrdering(templatedStep, config.meta.name) : templatedStep;
|
|
1511
|
+
try {
|
|
1512
|
+
const value = isMock ? getMockValue(mruStep, mockAnswers) : pluginStep ? await pluginStep.render(toStepRecord(mruStep), state, theme) : await renderStep(renderer, mruStep, state, theme);
|
|
1513
|
+
if (pluginStep?.validate) {
|
|
1514
|
+
const pluginError = pluginStep.validate(value, toStepRecord(templatedStep));
|
|
1515
|
+
if (pluginError) {
|
|
1516
|
+
if (isMock) {
|
|
1517
|
+
throw new Error(
|
|
1518
|
+
`Mock mode: validation failed for step "${currentStep.id}": ${pluginError}`
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
1521
|
+
console.log(theme.error(`
|
|
1522
|
+
${pluginError}
|
|
1523
|
+
`));
|
|
1524
|
+
continue;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
const nextState = wizardReducer(state, { type: "NEXT", value }, config);
|
|
1528
|
+
if (nextState.errors[currentStep.id]) {
|
|
1529
|
+
const errorMsg = resolveTemplate(nextState.errors[currentStep.id] ?? "", state.answers);
|
|
1530
|
+
emitEvent(renderer, { type: "step:error", stepId: currentStep.id, error: errorMsg }, theme);
|
|
1328
1531
|
if (isMock) {
|
|
1329
1532
|
throw new Error(
|
|
1330
|
-
`Mock mode: validation failed for step "${currentStep.id}": ${
|
|
1533
|
+
`Mock mode: validation failed for step "${currentStep.id}": ${errorMsg}`
|
|
1331
1534
|
);
|
|
1332
1535
|
}
|
|
1333
1536
|
console.log(theme.error(`
|
|
1334
|
-
${
|
|
1537
|
+
${errorMsg}
|
|
1335
1538
|
`));
|
|
1539
|
+
state = { ...nextState, errors: {} };
|
|
1336
1540
|
continue;
|
|
1337
1541
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
if (isMock) {
|
|
1343
|
-
throw new Error(
|
|
1344
|
-
`Mock mode: validation failed for step "${currentStep.id}": ${errorMsg}`
|
|
1345
|
-
);
|
|
1346
|
-
}
|
|
1347
|
-
console.log(theme.error(`
|
|
1348
|
-
${errorMsg}
|
|
1349
|
-
`));
|
|
1350
|
-
state = { ...nextState, errors: {} };
|
|
1351
|
-
continue;
|
|
1352
|
-
}
|
|
1353
|
-
if (!isMock && options?.asyncValidate) {
|
|
1354
|
-
const asyncError = await options.asyncValidate(currentStep.id, value, nextState.answers);
|
|
1355
|
-
if (asyncError !== null) {
|
|
1356
|
-
console.log(theme.error(`
|
|
1542
|
+
if (!isMock && options?.asyncValidate) {
|
|
1543
|
+
const asyncError = await options.asyncValidate(currentStep.id, value, nextState.answers);
|
|
1544
|
+
if (asyncError !== null) {
|
|
1545
|
+
console.log(theme.error(`
|
|
1357
1546
|
${asyncError}
|
|
1358
1547
|
`));
|
|
1359
|
-
|
|
1360
|
-
|
|
1548
|
+
state = { ...nextState, errors: {} };
|
|
1549
|
+
continue;
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
if (options?.onAfterStep) {
|
|
1553
|
+
await options.onAfterStep(currentStep.id, value, nextState);
|
|
1554
|
+
}
|
|
1555
|
+
state = nextState;
|
|
1556
|
+
emitEvent(renderer, { type: "step:complete", stepId: currentStep.id, value, step: currentStep }, theme);
|
|
1557
|
+
if (mruEnabled && isSelectLikeStep(currentStep.type)) {
|
|
1558
|
+
recordSelection(config.meta.name, currentStep.id, value);
|
|
1361
1559
|
}
|
|
1560
|
+
options?.onStepComplete?.(currentStep.id, value, state);
|
|
1561
|
+
} catch (error) {
|
|
1562
|
+
if (!isMock && isUserCancel(error)) {
|
|
1563
|
+
state = wizardReducer(state, { type: "CANCEL" }, config);
|
|
1564
|
+
options?.onCancel?.(state);
|
|
1565
|
+
const passwordStepIds = config.steps.filter((s) => s.type === "password").map((s) => s.id);
|
|
1566
|
+
saveProgress(config.meta.name, {
|
|
1567
|
+
currentStepId: state.currentStepId,
|
|
1568
|
+
answers: state.answers,
|
|
1569
|
+
history: state.history
|
|
1570
|
+
}, void 0, passwordStepIds);
|
|
1571
|
+
emitEvent(renderer, { type: "session:end", answers: state.answers, cancelled: true }, theme);
|
|
1572
|
+
if (!quiet) {
|
|
1573
|
+
console.log(theme.warning("\n Wizard cancelled.\n"));
|
|
1574
|
+
}
|
|
1575
|
+
return state.answers;
|
|
1576
|
+
}
|
|
1577
|
+
throw error;
|
|
1362
1578
|
}
|
|
1363
|
-
|
|
1364
|
-
|
|
1579
|
+
}
|
|
1580
|
+
if (config.meta.review && !isMock && state.status === "done") {
|
|
1581
|
+
const reviewLines = [];
|
|
1582
|
+
for (const step of config.steps) {
|
|
1583
|
+
const answer = state.answers[step.id];
|
|
1584
|
+
if (answer === void 0) continue;
|
|
1585
|
+
const display = step.type === "password" ? "****" : Array.isArray(answer) ? answer.map(String).join(", ") : String(answer);
|
|
1586
|
+
reviewLines.push(`${step.id}: ${display}`);
|
|
1365
1587
|
}
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1588
|
+
emitEvent(renderer, { type: "note", title: "Review your answers", body: reviewLines.join("\n") }, theme);
|
|
1589
|
+
console.log(`
|
|
1590
|
+
${theme.bold("Review your answers:")}
|
|
1591
|
+
`);
|
|
1592
|
+
for (const line of reviewLines) {
|
|
1593
|
+
console.log(` ${line}`);
|
|
1369
1594
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1595
|
+
console.log();
|
|
1596
|
+
const { confirm: confirmPrompt } = await import("@inquirer/prompts");
|
|
1597
|
+
const ok = await confirmPrompt({
|
|
1598
|
+
message: "Everything look right?",
|
|
1599
|
+
default: true
|
|
1600
|
+
});
|
|
1601
|
+
if (ok) {
|
|
1602
|
+
needsReview = false;
|
|
1603
|
+
} else {
|
|
1604
|
+
const { select: selectPrompt } = await import("@inquirer/prompts");
|
|
1605
|
+
const stepsWithAnswers = config.steps.filter(
|
|
1606
|
+
(s) => state.answers[s.id] !== void 0 && s.type !== "note" && s.type !== "message"
|
|
1607
|
+
);
|
|
1608
|
+
const stepToRevisit = await selectPrompt({
|
|
1609
|
+
message: "Which step would you like to change?",
|
|
1610
|
+
choices: stepsWithAnswers.map((s) => ({
|
|
1611
|
+
name: `${s.id}: ${s.type === "password" ? "****" : String(state.answers[s.id] ?? "")}`,
|
|
1612
|
+
value: s.id
|
|
1613
|
+
}))
|
|
1614
|
+
});
|
|
1615
|
+
state = {
|
|
1616
|
+
...state,
|
|
1617
|
+
currentStepId: stepToRevisit,
|
|
1618
|
+
status: "running"
|
|
1619
|
+
};
|
|
1379
1620
|
}
|
|
1380
|
-
|
|
1621
|
+
} else {
|
|
1622
|
+
needsReview = false;
|
|
1381
1623
|
}
|
|
1382
1624
|
}
|
|
1383
1625
|
if (state.status === "done" && !quiet) {
|
|
1384
1626
|
renderer.renderSummary(state.answers, config.steps, theme);
|
|
1385
1627
|
}
|
|
1386
1628
|
if (state.status === "done" && config.actions && config.actions.length > 0 && !isMock) {
|
|
1387
|
-
await executeActions(config.actions, state.answers, theme);
|
|
1629
|
+
await executeActions(config.actions, state.answers, theme, renderer);
|
|
1388
1630
|
}
|
|
1631
|
+
emitEvent(renderer, { type: "session:end", answers: state.answers, cancelled: state.status === "cancelled" }, theme);
|
|
1389
1632
|
if (state.status === "done" && cacheEnabled) {
|
|
1390
1633
|
const passwordStepIds = new Set(
|
|
1391
1634
|
config.steps.filter((s) => s.type === "password").map((s) => s.id)
|
|
@@ -1398,6 +1641,9 @@ async function runWizard(config, options) {
|
|
|
1398
1641
|
}
|
|
1399
1642
|
saveCachedAnswers(config.meta.name, answersToCache, cacheDir);
|
|
1400
1643
|
}
|
|
1644
|
+
if (state.status === "done") {
|
|
1645
|
+
clearProgress(config.meta.name);
|
|
1646
|
+
}
|
|
1401
1647
|
return state.answers;
|
|
1402
1648
|
} finally {
|
|
1403
1649
|
if (userPlugins) {
|
|
@@ -1437,6 +1683,8 @@ function renderStep(renderer, step, state, theme) {
|
|
|
1437
1683
|
case "message":
|
|
1438
1684
|
renderer.renderMessage(step, state, theme);
|
|
1439
1685
|
return Promise.resolve(true);
|
|
1686
|
+
case "note":
|
|
1687
|
+
return Promise.resolve(true);
|
|
1440
1688
|
}
|
|
1441
1689
|
}
|
|
1442
1690
|
function resolveStepDefaults(step, cachedAnswers) {
|
|
@@ -1487,6 +1735,7 @@ function resolveStepDefaults(step, cachedAnswers) {
|
|
|
1487
1735
|
}
|
|
1488
1736
|
case "password":
|
|
1489
1737
|
case "message":
|
|
1738
|
+
case "note":
|
|
1490
1739
|
return step;
|
|
1491
1740
|
}
|
|
1492
1741
|
}
|
|
@@ -1496,7 +1745,7 @@ function getCachedDefault(stepId, cachedAnswers) {
|
|
|
1496
1745
|
}
|
|
1497
1746
|
function applyTemplateDefaults(step, templateAnswers) {
|
|
1498
1747
|
if (!(step.id in templateAnswers)) return step;
|
|
1499
|
-
if (step.type === "password" || step.type === "message") return step;
|
|
1748
|
+
if (step.type === "password" || step.type === "message" || step.type === "note") return step;
|
|
1500
1749
|
const value = templateAnswers[step.id];
|
|
1501
1750
|
switch (step.type) {
|
|
1502
1751
|
case "text":
|
|
@@ -1585,13 +1834,15 @@ function resolveStepTemplates(step, answers) {
|
|
|
1585
1834
|
case "confirm":
|
|
1586
1835
|
case "toggle":
|
|
1587
1836
|
case "message":
|
|
1837
|
+
case "note":
|
|
1588
1838
|
return {
|
|
1589
1839
|
...step,
|
|
1590
1840
|
description: step.description ? resolveTemplate(step.description, answers) : void 0
|
|
1591
1841
|
};
|
|
1592
1842
|
}
|
|
1593
1843
|
}
|
|
1594
|
-
async function executeActions(actions, answers, theme) {
|
|
1844
|
+
async function executeActions(actions, answers, theme, renderer) {
|
|
1845
|
+
if (renderer) emitEvent(renderer, { type: "actions:start" }, theme);
|
|
1595
1846
|
console.log(`
|
|
1596
1847
|
${theme.bold("Running actions...")}
|
|
1597
1848
|
`);
|
|
@@ -1605,8 +1856,10 @@ async function executeActions(actions, answers, theme) {
|
|
|
1605
1856
|
try {
|
|
1606
1857
|
execSync(resolvedCommand, { stdio: "pipe" });
|
|
1607
1858
|
console.log(` ${theme.success("\u2713")} ${label}`);
|
|
1859
|
+
if (renderer) emitEvent(renderer, { type: "action:pass", name: label }, theme);
|
|
1608
1860
|
} catch {
|
|
1609
1861
|
console.log(` ${theme.error("\u2717")} ${label}`);
|
|
1862
|
+
if (renderer) emitEvent(renderer, { type: "action:fail", name: label }, theme);
|
|
1610
1863
|
throw new Error(`Action failed: ${label}`);
|
|
1611
1864
|
}
|
|
1612
1865
|
}
|
|
@@ -1827,21 +2080,201 @@ var InkRenderer = class {
|
|
|
1827
2080
|
}
|
|
1828
2081
|
};
|
|
1829
2082
|
|
|
2083
|
+
// src/renderers/clack.ts
|
|
2084
|
+
import chalk2 from "chalk";
|
|
2085
|
+
|
|
2086
|
+
// src/renderers/symbols.ts
|
|
2087
|
+
function isUnicodeSupported() {
|
|
2088
|
+
if (process.platform === "win32") {
|
|
2089
|
+
return Boolean(process.env["WT_SESSION"]) || process.env["TERM_PROGRAM"] === "vscode";
|
|
2090
|
+
}
|
|
2091
|
+
return process.env["TERM"] !== "linux";
|
|
2092
|
+
}
|
|
2093
|
+
var unicode = isUnicodeSupported();
|
|
2094
|
+
var u = (unicodeChar, fallback) => unicode ? unicodeChar : fallback;
|
|
2095
|
+
var S_BAR_START = u("\u250C", "T");
|
|
2096
|
+
var S_BAR = u("\u2502", "|");
|
|
2097
|
+
var S_BAR_END = u("\u2514", "\u2014");
|
|
2098
|
+
var S_STEP_ACTIVE = u("\u25C6", "*");
|
|
2099
|
+
var S_STEP_SUBMIT = u("\u25C7", "o");
|
|
2100
|
+
var S_STEP_CANCEL = u("\u25A0", "x");
|
|
2101
|
+
var S_STEP_ERROR = u("\u25B2", "x");
|
|
2102
|
+
var S_CORNER_TR = u("\u256E", "+");
|
|
2103
|
+
var S_CORNER_BR = u("\u256F", "+");
|
|
2104
|
+
var S_BAR_H = u("\u2500", "-");
|
|
2105
|
+
var S_SPINNER_FRAMES = unicode ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"];
|
|
2106
|
+
|
|
2107
|
+
// src/renderers/clack.ts
|
|
2108
|
+
var ClackRenderer = class extends InquirerRenderer {
|
|
2109
|
+
spinnerInterval;
|
|
2110
|
+
spinnerFrameIndex = 0;
|
|
2111
|
+
renderStepHeader() {
|
|
2112
|
+
}
|
|
2113
|
+
renderGroupHeader() {
|
|
2114
|
+
}
|
|
2115
|
+
renderSummary(answers, steps, theme) {
|
|
2116
|
+
const entries = [];
|
|
2117
|
+
for (const step of steps) {
|
|
2118
|
+
const answer = answers[step.id];
|
|
2119
|
+
if (answer === void 0) continue;
|
|
2120
|
+
const display = Array.isArray(answer) ? answer.map(String).join(", ") : String(answer);
|
|
2121
|
+
entries.push({ id: step.id, display });
|
|
2122
|
+
}
|
|
2123
|
+
if (entries.length === 0) return;
|
|
2124
|
+
const title = "Summary";
|
|
2125
|
+
const lines = entries.map((e) => `${e.id}: ${e.display}`);
|
|
2126
|
+
this.writeNoteBox(title, lines, theme);
|
|
2127
|
+
}
|
|
2128
|
+
onEvent(event, theme) {
|
|
2129
|
+
switch (event.type) {
|
|
2130
|
+
case "session:start":
|
|
2131
|
+
this.handleSessionStart(event, theme);
|
|
2132
|
+
break;
|
|
2133
|
+
case "session:end":
|
|
2134
|
+
this.handleSessionEnd(event, theme);
|
|
2135
|
+
break;
|
|
2136
|
+
case "step:start":
|
|
2137
|
+
process.stdout.write(`${chalk2.gray(S_BAR)}
|
|
2138
|
+
`);
|
|
2139
|
+
break;
|
|
2140
|
+
case "step:complete":
|
|
2141
|
+
this.handleStepComplete(event, theme);
|
|
2142
|
+
break;
|
|
2143
|
+
case "step:error":
|
|
2144
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.error(`${S_STEP_ERROR} ${event.error}`)}
|
|
2145
|
+
`);
|
|
2146
|
+
break;
|
|
2147
|
+
case "step:back":
|
|
2148
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.muted("\u21A9 Back")}
|
|
2149
|
+
`);
|
|
2150
|
+
break;
|
|
2151
|
+
case "group:start":
|
|
2152
|
+
process.stdout.write(`${chalk2.gray(S_BAR)}
|
|
2153
|
+
`);
|
|
2154
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.accent(event.group)}
|
|
2155
|
+
`);
|
|
2156
|
+
break;
|
|
2157
|
+
case "note":
|
|
2158
|
+
this.writeNoteBox(event.title, event.body.split("\n"), theme);
|
|
2159
|
+
break;
|
|
2160
|
+
case "spinner:start":
|
|
2161
|
+
this.startSpinner(event.message, theme);
|
|
2162
|
+
break;
|
|
2163
|
+
case "spinner:stop":
|
|
2164
|
+
this.stopSpinner(event.message, theme);
|
|
2165
|
+
break;
|
|
2166
|
+
case "checks:start":
|
|
2167
|
+
process.stdout.write(`${chalk2.gray(S_BAR)}
|
|
2168
|
+
`);
|
|
2169
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.bold("Running checks...")}
|
|
2170
|
+
`);
|
|
2171
|
+
break;
|
|
2172
|
+
case "check:pass":
|
|
2173
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.success(S_STEP_SUBMIT)} ${event.name}
|
|
2174
|
+
`);
|
|
2175
|
+
break;
|
|
2176
|
+
case "check:fail":
|
|
2177
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.error(S_STEP_ERROR)} ${event.name}: ${event.message}
|
|
2178
|
+
`);
|
|
2179
|
+
break;
|
|
2180
|
+
case "actions:start":
|
|
2181
|
+
process.stdout.write(`${chalk2.gray(S_BAR)}
|
|
2182
|
+
`);
|
|
2183
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.bold("Running actions...")}
|
|
2184
|
+
`);
|
|
2185
|
+
break;
|
|
2186
|
+
case "action:pass":
|
|
2187
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.success(S_STEP_SUBMIT)} ${event.name}
|
|
2188
|
+
`);
|
|
2189
|
+
break;
|
|
2190
|
+
case "action:fail":
|
|
2191
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.error(S_STEP_ERROR)} ${event.name}
|
|
2192
|
+
`);
|
|
2193
|
+
break;
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
handleSessionStart(event, theme) {
|
|
2197
|
+
process.stdout.write(`${chalk2.gray(S_BAR_START)} ${theme.bold(event.wizard)}
|
|
2198
|
+
`);
|
|
2199
|
+
if (event.description) {
|
|
2200
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${theme.muted(event.description)}
|
|
2201
|
+
`);
|
|
2202
|
+
}
|
|
2203
|
+
process.stdout.write(`${chalk2.gray(S_BAR)}
|
|
2204
|
+
`);
|
|
2205
|
+
}
|
|
2206
|
+
handleSessionEnd(event, theme) {
|
|
2207
|
+
if (event.cancelled) {
|
|
2208
|
+
process.stdout.write(`${theme.warning(S_STEP_CANCEL)} Cancelled
|
|
2209
|
+
`);
|
|
2210
|
+
} else {
|
|
2211
|
+
process.stdout.write(`${chalk2.gray(S_BAR_END)} ${theme.success("You're all set!")}
|
|
2212
|
+
`);
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
handleStepComplete(event, theme) {
|
|
2216
|
+
const displayValue = event.step.type === "password" ? "****" : this.formatValue(event.value);
|
|
2217
|
+
process.stdout.write(
|
|
2218
|
+
`${chalk2.gray(S_STEP_SUBMIT)} ${event.step.message} ${chalk2.gray("\xB7")} ${theme.muted(displayValue)}
|
|
2219
|
+
`
|
|
2220
|
+
);
|
|
2221
|
+
}
|
|
2222
|
+
formatValue(value) {
|
|
2223
|
+
if (Array.isArray(value)) return value.map(String).join(", ");
|
|
2224
|
+
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
2225
|
+
return String(value);
|
|
2226
|
+
}
|
|
2227
|
+
writeNoteBox(title, lines, _theme) {
|
|
2228
|
+
const maxLen = Math.max(title.length, ...lines.map((l) => l.length));
|
|
2229
|
+
const padded = maxLen + 2;
|
|
2230
|
+
const topLine = `${S_BAR_H.repeat(padded - title.length - 1)}${S_CORNER_TR}`;
|
|
2231
|
+
const bottomLine = `${S_BAR_H.repeat(padded)}${S_CORNER_BR}`;
|
|
2232
|
+
process.stdout.write(`${chalk2.gray(S_BAR)}
|
|
2233
|
+
`);
|
|
2234
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${chalk2.gray(`\u256D${S_BAR_H} ${title} ${topLine}`)}
|
|
2235
|
+
`);
|
|
2236
|
+
for (const line of lines) {
|
|
2237
|
+
const pad = " ".repeat(maxLen - line.length);
|
|
2238
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${chalk2.gray(S_BAR)} ${line}${pad} ${chalk2.gray(S_BAR)}
|
|
2239
|
+
`);
|
|
2240
|
+
}
|
|
2241
|
+
process.stdout.write(`${chalk2.gray(S_BAR)} ${chalk2.gray(`\u256E${bottomLine}`)}
|
|
2242
|
+
`);
|
|
2243
|
+
}
|
|
2244
|
+
startSpinner(message, _theme) {
|
|
2245
|
+
this.spinnerFrameIndex = 0;
|
|
2246
|
+
this.spinnerInterval = setInterval(() => {
|
|
2247
|
+
const frame = S_SPINNER_FRAMES[this.spinnerFrameIndex % S_SPINNER_FRAMES.length];
|
|
2248
|
+
process.stdout.write(`\r${chalk2.gray(S_BAR)} ${chalk2.cyan(frame ?? "")} ${message}`);
|
|
2249
|
+
this.spinnerFrameIndex++;
|
|
2250
|
+
}, 80);
|
|
2251
|
+
}
|
|
2252
|
+
stopSpinner(message, theme) {
|
|
2253
|
+
if (this.spinnerInterval) {
|
|
2254
|
+
clearInterval(this.spinnerInterval);
|
|
2255
|
+
this.spinnerInterval = void 0;
|
|
2256
|
+
}
|
|
2257
|
+
const finalMessage = message ?? "Done";
|
|
2258
|
+
process.stdout.write(`\r${chalk2.gray(S_BAR)} ${theme.success(S_STEP_SUBMIT)} ${finalMessage}
|
|
2259
|
+
`);
|
|
2260
|
+
}
|
|
2261
|
+
};
|
|
2262
|
+
|
|
1830
2263
|
// src/templates.ts
|
|
1831
|
-
import { mkdirSync as
|
|
1832
|
-
import { join as
|
|
1833
|
-
import { homedir as
|
|
1834
|
-
var TEMPLATES_DIR =
|
|
2264
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, readdirSync as readdirSync2, existsSync as existsSync2 } from "fs";
|
|
2265
|
+
import { join as join4 } from "path";
|
|
2266
|
+
import { homedir as homedir4 } from "os";
|
|
2267
|
+
var TEMPLATES_DIR = join4(homedir4(), ".config", "grimoire", "templates");
|
|
1835
2268
|
function getWizardTemplateDir(wizardName) {
|
|
1836
|
-
return
|
|
2269
|
+
return join4(TEMPLATES_DIR, slugify(wizardName));
|
|
1837
2270
|
}
|
|
1838
2271
|
function getTemplateFilePath(wizardName, templateName) {
|
|
1839
|
-
return
|
|
2272
|
+
return join4(getWizardTemplateDir(wizardName), `${slugify(templateName)}.json`);
|
|
1840
2273
|
}
|
|
1841
2274
|
function saveTemplate(wizardName, templateName, answers, excludeKeys) {
|
|
1842
2275
|
try {
|
|
1843
2276
|
const dir = getWizardTemplateDir(wizardName);
|
|
1844
|
-
|
|
2277
|
+
mkdirSync4(dir, { recursive: true });
|
|
1845
2278
|
const filePath = getTemplateFilePath(wizardName, templateName);
|
|
1846
2279
|
let answersToSave = answers;
|
|
1847
2280
|
if (excludeKeys && excludeKeys.length > 0) {
|
|
@@ -1850,14 +2283,14 @@ function saveTemplate(wizardName, templateName, answers, excludeKeys) {
|
|
|
1850
2283
|
Object.entries(answers).filter(([k]) => !excluded.has(k))
|
|
1851
2284
|
);
|
|
1852
2285
|
}
|
|
1853
|
-
|
|
2286
|
+
writeFileSync4(filePath, JSON.stringify(answersToSave, null, 2) + "\n", "utf-8");
|
|
1854
2287
|
} catch {
|
|
1855
2288
|
}
|
|
1856
2289
|
}
|
|
1857
2290
|
function loadTemplate(wizardName, templateName) {
|
|
1858
2291
|
try {
|
|
1859
2292
|
const filePath = getTemplateFilePath(wizardName, templateName);
|
|
1860
|
-
const raw =
|
|
2293
|
+
const raw = readFileSync5(filePath, "utf-8");
|
|
1861
2294
|
const parsed = JSON.parse(raw);
|
|
1862
2295
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
1863
2296
|
return parsed;
|
|
@@ -1879,16 +2312,45 @@ function listTemplates(wizardName) {
|
|
|
1879
2312
|
function deleteTemplate(wizardName, templateName) {
|
|
1880
2313
|
try {
|
|
1881
2314
|
const filePath = getTemplateFilePath(wizardName, templateName);
|
|
1882
|
-
|
|
2315
|
+
unlinkSync3(filePath);
|
|
1883
2316
|
} catch {
|
|
1884
2317
|
}
|
|
1885
2318
|
}
|
|
2319
|
+
|
|
2320
|
+
// src/pipeline.ts
|
|
2321
|
+
async function runPipeline(steps, globalOptions) {
|
|
2322
|
+
const results = {};
|
|
2323
|
+
let accumulated = {};
|
|
2324
|
+
for (const step of steps) {
|
|
2325
|
+
let config;
|
|
2326
|
+
if (typeof step.config === "string") {
|
|
2327
|
+
const { loadWizardConfig: loadWizardConfig2 } = await Promise.resolve().then(() => (init_parser(), parser_exports));
|
|
2328
|
+
config = await loadWizardConfig2(step.config);
|
|
2329
|
+
} else {
|
|
2330
|
+
config = step.config;
|
|
2331
|
+
}
|
|
2332
|
+
if (step.when && !evaluateCondition(step.when, accumulated)) {
|
|
2333
|
+
continue;
|
|
2334
|
+
}
|
|
2335
|
+
const answers = await runWizard(config, {
|
|
2336
|
+
...globalOptions,
|
|
2337
|
+
...step.options,
|
|
2338
|
+
mockAnswers: step.mockAnswers,
|
|
2339
|
+
templateAnswers: accumulated
|
|
2340
|
+
});
|
|
2341
|
+
results[config.meta.name] = answers;
|
|
2342
|
+
accumulated = { ...accumulated, ...answers };
|
|
2343
|
+
}
|
|
2344
|
+
return results;
|
|
2345
|
+
}
|
|
1886
2346
|
export {
|
|
2347
|
+
ClackRenderer,
|
|
1887
2348
|
InkRenderer,
|
|
1888
2349
|
InquirerRenderer,
|
|
1889
2350
|
clearCache,
|
|
1890
2351
|
clearMruData,
|
|
1891
2352
|
clearPlugins,
|
|
2353
|
+
clearProgress,
|
|
1892
2354
|
createWizardState,
|
|
1893
2355
|
defineWizard,
|
|
1894
2356
|
deleteTemplate,
|
|
@@ -1900,6 +2362,7 @@ export {
|
|
|
1900
2362
|
isStepVisible,
|
|
1901
2363
|
listTemplates,
|
|
1902
2364
|
loadCachedAnswers,
|
|
2365
|
+
loadProgress,
|
|
1903
2366
|
loadTemplate,
|
|
1904
2367
|
loadWizardConfig,
|
|
1905
2368
|
parseWizardConfig,
|
|
@@ -1911,9 +2374,11 @@ export {
|
|
|
1911
2374
|
resolveNextStep,
|
|
1912
2375
|
resolveTemplate,
|
|
1913
2376
|
resolveTheme,
|
|
2377
|
+
runPipeline,
|
|
1914
2378
|
runPreFlightChecks,
|
|
1915
2379
|
runWizard,
|
|
1916
2380
|
saveCachedAnswers,
|
|
2381
|
+
saveProgress,
|
|
1917
2382
|
saveTemplate,
|
|
1918
2383
|
slugify,
|
|
1919
2384
|
validateStepAnswer,
|