create-agentic-monorepo 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +211 -0
- package/dist/args-D-klo3P0.mjs +769 -0
- package/dist/main.mjs +885 -0
- package/dist/wizard-BFRKuEqB.mjs +332 -0
- package/package.json +36 -0
- package/template.json +1 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { a as toOverrides, c as isValidName, l as presets, n as parseApps, o as CreatorError, s as catalog, u as resolveOptions } from "./args-D-klo3P0.mjs";
|
|
2
|
+
import { basename, resolve } from "node:path";
|
|
3
|
+
import { createInterface } from "node:readline/promises";
|
|
4
|
+
import { box, cancel, confirm, intro, isCancel, multiselect, outro, select, text } from "@clack/prompts";
|
|
5
|
+
//#region src/wizard.ts
|
|
6
|
+
const presetChoices = presets.map((preset) => ({
|
|
7
|
+
value: preset.id,
|
|
8
|
+
label: preset.label,
|
|
9
|
+
hint: preset.hint
|
|
10
|
+
}));
|
|
11
|
+
const appChoices = catalog.filter((entry) => entry.status === "available" && (entry.id === "web" || entry.id === "cli" || entry.id === "mac")).map((entry) => ({
|
|
12
|
+
value: entry.id,
|
|
13
|
+
label: entry.label,
|
|
14
|
+
hint: entry.requirements.join(", ")
|
|
15
|
+
}));
|
|
16
|
+
function cancelled() {
|
|
17
|
+
throw new CreatorError("CANCELLED", "Creation cancelled");
|
|
18
|
+
}
|
|
19
|
+
function checkSignal(signal) {
|
|
20
|
+
if (signal.aborted) cancelled();
|
|
21
|
+
}
|
|
22
|
+
function checked(value) {
|
|
23
|
+
if (isCancel(value)) cancelled();
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
function currentSelection(config, overrides) {
|
|
27
|
+
return overrides.preset !== void 0 || overrides.apps !== void 0 || config.preset !== void 0 || config.apps !== void 0;
|
|
28
|
+
}
|
|
29
|
+
function setSelection(overrides, preset) {
|
|
30
|
+
delete overrides.apps;
|
|
31
|
+
overrides.preset = preset;
|
|
32
|
+
}
|
|
33
|
+
function setApps(overrides, apps) {
|
|
34
|
+
delete overrides.preset;
|
|
35
|
+
overrides.apps = apps;
|
|
36
|
+
}
|
|
37
|
+
function selectedSummary(options) {
|
|
38
|
+
const components = options.components.join(", ");
|
|
39
|
+
return `Apps: ${options.apps.length === 0 ? "none" : options.apps.join(", ")}\nComponents: ${components}\nInstall: ${options.install ? "yes" : "no"}\nGit: ${options.git ? "yes" : "no"}`;
|
|
40
|
+
}
|
|
41
|
+
function resolveForWizard(config, overrides, destination) {
|
|
42
|
+
return resolveOptions(config, overrides, basename(resolve(destination)));
|
|
43
|
+
}
|
|
44
|
+
async function richText(message, placeholder, signal) {
|
|
45
|
+
checkSignal(signal);
|
|
46
|
+
return checked(await text({
|
|
47
|
+
message,
|
|
48
|
+
placeholder,
|
|
49
|
+
validate: (value) => (value ?? "").trim().length === 0 ? "Enter a value" : void 0
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
async function richChoice(message, options, signal) {
|
|
53
|
+
checkSignal(signal);
|
|
54
|
+
const promptOptions = options.map((option) => option.hint === void 0 ? {
|
|
55
|
+
value: option.value,
|
|
56
|
+
label: option.label
|
|
57
|
+
} : {
|
|
58
|
+
value: option.value,
|
|
59
|
+
label: option.label,
|
|
60
|
+
hint: option.hint
|
|
61
|
+
});
|
|
62
|
+
return checked(await select({
|
|
63
|
+
message,
|
|
64
|
+
options: promptOptions
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
async function askRichDestination(args, signal) {
|
|
68
|
+
if (args.destination !== void 0) return args.destination;
|
|
69
|
+
return richText("Where should the repository be created?", "my-product", signal);
|
|
70
|
+
}
|
|
71
|
+
async function askRichName(destination, overrides, signal) {
|
|
72
|
+
if (overrides.name !== void 0) return;
|
|
73
|
+
const suggested = basename(resolve(destination));
|
|
74
|
+
if (isValidName(suggested)) return;
|
|
75
|
+
overrides.name = await richText(`Choose a valid package name (suggested: ${suggested})`, "my-product", signal);
|
|
76
|
+
}
|
|
77
|
+
async function askRichSelection(config, overrides, signal) {
|
|
78
|
+
if (currentSelection(config, overrides)) return;
|
|
79
|
+
const choice = await richChoice("Choose a starter", [...presetChoices, {
|
|
80
|
+
value: "custom",
|
|
81
|
+
label: "Custom combination",
|
|
82
|
+
hint: "Choose apps and Rust independently"
|
|
83
|
+
}], signal);
|
|
84
|
+
if (choice === "custom") {
|
|
85
|
+
setApps(overrides, checked(await multiselect({
|
|
86
|
+
message: "Choose applications",
|
|
87
|
+
options: appChoices,
|
|
88
|
+
required: false
|
|
89
|
+
})));
|
|
90
|
+
overrides.rust = checked(await confirm({
|
|
91
|
+
message: "Include the independent Rust search-index library?",
|
|
92
|
+
initialValue: false
|
|
93
|
+
}));
|
|
94
|
+
} else setSelection(overrides, choice);
|
|
95
|
+
}
|
|
96
|
+
async function askRichSetup(config, overrides, signal) {
|
|
97
|
+
const installSupplied = overrides.install !== void 0 || config.install !== void 0;
|
|
98
|
+
const gitSupplied = overrides.git !== void 0 || config.git !== void 0;
|
|
99
|
+
if (installSupplied && gitSupplied) return;
|
|
100
|
+
if (!installSupplied && !gitSupplied) {
|
|
101
|
+
const choice = await richChoice("How should setup run?", [
|
|
102
|
+
{
|
|
103
|
+
value: "both",
|
|
104
|
+
label: "Install dependencies and initialize Git",
|
|
105
|
+
hint: "Recommended"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
value: "install",
|
|
109
|
+
label: "Install dependencies only"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
value: "git",
|
|
113
|
+
label: "Initialize Git only"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
value: "none",
|
|
117
|
+
label: "Files only"
|
|
118
|
+
}
|
|
119
|
+
], signal);
|
|
120
|
+
overrides.install = choice === "both" || choice === "install";
|
|
121
|
+
overrides.git = choice === "both" || choice === "git";
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (!installSupplied) overrides.install = checked(await confirm({
|
|
125
|
+
message: "Install dependencies?",
|
|
126
|
+
initialValue: false
|
|
127
|
+
}));
|
|
128
|
+
if (!gitSupplied) overrides.git = checked(await confirm({
|
|
129
|
+
message: "Initialize local Git?",
|
|
130
|
+
initialValue: false
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
function withoutSelection(config) {
|
|
134
|
+
const result = { ...config };
|
|
135
|
+
delete result.preset;
|
|
136
|
+
delete result.apps;
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
function withoutSetup(config) {
|
|
140
|
+
const result = { ...config };
|
|
141
|
+
delete result.install;
|
|
142
|
+
delete result.git;
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
async function richWizard(input) {
|
|
146
|
+
const { args, config, signal } = input;
|
|
147
|
+
intro("Agentic Monorepo");
|
|
148
|
+
process.stderr.write("A clear foundation for your next product.\n");
|
|
149
|
+
const destination = await askRichDestination(args, signal);
|
|
150
|
+
const overrides = { ...toOverrides(args) };
|
|
151
|
+
await askRichName(destination, overrides, signal);
|
|
152
|
+
await askRichSelection(config, overrides, signal);
|
|
153
|
+
await askRichSetup(config, overrides, signal);
|
|
154
|
+
while (true) {
|
|
155
|
+
checkSignal(signal);
|
|
156
|
+
let resolved;
|
|
157
|
+
try {
|
|
158
|
+
resolved = resolveForWizard(config, overrides, destination);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
if (error instanceof CreatorError && error.code === "INVALID_ARGUMENT" && overrides.name === void 0) {
|
|
161
|
+
overrides.name = await richText("Choose a valid package name", "my-product", signal);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
box(selectedSummary(resolved), "Review");
|
|
167
|
+
const action = await richChoice("Ready to create?", [
|
|
168
|
+
{
|
|
169
|
+
value: "create",
|
|
170
|
+
label: "Create repository"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
value: "starter",
|
|
174
|
+
label: "Change starter"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
value: "location",
|
|
178
|
+
label: "Change location/name"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
value: "setup",
|
|
182
|
+
label: "Change setup"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
value: "cancel",
|
|
186
|
+
label: "Cancel"
|
|
187
|
+
}
|
|
188
|
+
], signal);
|
|
189
|
+
if (action === "create") {
|
|
190
|
+
outro("Creating repository");
|
|
191
|
+
return {
|
|
192
|
+
destination,
|
|
193
|
+
overrides
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if (action === "cancel") {
|
|
197
|
+
cancel("Creation cancelled");
|
|
198
|
+
cancelled();
|
|
199
|
+
}
|
|
200
|
+
if (action === "starter") {
|
|
201
|
+
delete overrides.preset;
|
|
202
|
+
delete overrides.apps;
|
|
203
|
+
await askRichSelection(withoutSelection(config), overrides, signal);
|
|
204
|
+
} else if (action === "location") {
|
|
205
|
+
const next = await richText("Where should the repository be created?", destination, signal);
|
|
206
|
+
overrides.name = await richText("Root package name", overrides.name ?? basename(resolve(next)), signal);
|
|
207
|
+
return {
|
|
208
|
+
destination: next,
|
|
209
|
+
overrides
|
|
210
|
+
};
|
|
211
|
+
} else {
|
|
212
|
+
delete overrides.install;
|
|
213
|
+
delete overrides.git;
|
|
214
|
+
await askRichSetup(withoutSetup(config), overrides, signal);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async function plainQuestion(rl, message, signal) {
|
|
219
|
+
checkSignal(signal);
|
|
220
|
+
try {
|
|
221
|
+
const answer = await rl.question(`${message}\n> `);
|
|
222
|
+
if (answer.trim().length === 0) return plainQuestion(rl, message, signal);
|
|
223
|
+
return answer.trim();
|
|
224
|
+
} catch {
|
|
225
|
+
cancelled();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async function plainChoice(rl, message, choices, signal) {
|
|
229
|
+
process.stderr.write(`\n${message}\n`);
|
|
230
|
+
choices.forEach((choice, index) => process.stderr.write(` ${index + 1}) ${choice}\n`));
|
|
231
|
+
while (true) {
|
|
232
|
+
const answer = await plainQuestion(rl, "Choose a number", signal);
|
|
233
|
+
const selected = Number(answer);
|
|
234
|
+
if (Number.isInteger(selected) && selected >= 1 && selected <= choices.length) return selected - 1;
|
|
235
|
+
process.stderr.write(`Enter a number from 1 to ${choices.length}.\n`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async function plainWizard(input) {
|
|
239
|
+
const { args, config, signal } = input;
|
|
240
|
+
const rl = createInterface({
|
|
241
|
+
input: process.stdin,
|
|
242
|
+
output: process.stderr,
|
|
243
|
+
terminal: false
|
|
244
|
+
});
|
|
245
|
+
try {
|
|
246
|
+
process.stderr.write("Agentic Monorepo\nA clear foundation for your next product.\n");
|
|
247
|
+
const destination = args.destination ?? await plainQuestion(rl, "Where should the repository be created?", signal);
|
|
248
|
+
const overrides = { ...toOverrides(args) };
|
|
249
|
+
if (overrides.name === void 0) {
|
|
250
|
+
const suggested = basename(resolve(destination));
|
|
251
|
+
if (!isValidName(suggested)) overrides.name = await plainQuestion(rl, `Root package name (suggested: ${suggested})`, signal);
|
|
252
|
+
}
|
|
253
|
+
if (!currentSelection(config, overrides)) {
|
|
254
|
+
const index = await plainChoice(rl, "Choose a starter", [...presetChoices.map((p) => `${p.label} — ${p.hint}`), "Custom combination"], signal);
|
|
255
|
+
if (index === presets.length) {
|
|
256
|
+
setApps(overrides, parseApps(await plainQuestion(rl, "Applications (web,cli,mac or none)", signal)));
|
|
257
|
+
overrides.rust = await plainChoice(rl, "Include Rust?", ["No", "Yes"], signal) === 1;
|
|
258
|
+
} else setSelection(overrides, presets[index]?.id ?? "web");
|
|
259
|
+
}
|
|
260
|
+
await askPlainSetup(rl, config, overrides, signal);
|
|
261
|
+
while (true) {
|
|
262
|
+
let resolved;
|
|
263
|
+
try {
|
|
264
|
+
resolved = resolveForWizard(config, overrides, destination);
|
|
265
|
+
} catch (error) {
|
|
266
|
+
if (error instanceof CreatorError && error.code === "INVALID_ARGUMENT" && overrides.name === void 0) {
|
|
267
|
+
overrides.name = await plainQuestion(rl, "Root package name", signal);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
throw error;
|
|
271
|
+
}
|
|
272
|
+
process.stderr.write(`\nReview\n${selectedSummary(resolved)}\nDestination: ${resolve(destination)}\n`);
|
|
273
|
+
const action = await plainChoice(rl, "Next action", [
|
|
274
|
+
"Create repository",
|
|
275
|
+
"Change starter",
|
|
276
|
+
"Change location/name",
|
|
277
|
+
"Change setup",
|
|
278
|
+
"Cancel"
|
|
279
|
+
], signal);
|
|
280
|
+
if (action === 0) return {
|
|
281
|
+
destination,
|
|
282
|
+
overrides
|
|
283
|
+
};
|
|
284
|
+
if (action === 4) cancelled();
|
|
285
|
+
if (action === 1) {
|
|
286
|
+
delete overrides.preset;
|
|
287
|
+
delete overrides.apps;
|
|
288
|
+
const index = await plainChoice(rl, "Choose a starter", [...presetChoices.map((p) => p.label), "Custom combination"], signal);
|
|
289
|
+
if (index === presets.length) {
|
|
290
|
+
setApps(overrides, parseApps(await plainQuestion(rl, "Applications (web,cli,mac or none)", signal)));
|
|
291
|
+
overrides.rust = await plainChoice(rl, "Include Rust?", ["No", "Yes"], signal) === 1;
|
|
292
|
+
} else setSelection(overrides, presets[index]?.id ?? "web");
|
|
293
|
+
} else if (action === 2) {
|
|
294
|
+
const next = await plainQuestion(rl, "Where should the repository be created?", signal);
|
|
295
|
+
overrides.name = await plainQuestion(rl, "Root package name", signal);
|
|
296
|
+
return {
|
|
297
|
+
destination: next,
|
|
298
|
+
overrides
|
|
299
|
+
};
|
|
300
|
+
} else {
|
|
301
|
+
delete overrides.install;
|
|
302
|
+
delete overrides.git;
|
|
303
|
+
await askPlainSetup(rl, withoutSetup(config), overrides, signal);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
} finally {
|
|
307
|
+
rl.close();
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
async function askPlainSetup(rl, config, overrides, signal) {
|
|
311
|
+
const installSupplied = overrides.install !== void 0 || config.install !== void 0;
|
|
312
|
+
const gitSupplied = overrides.git !== void 0 || config.git !== void 0;
|
|
313
|
+
if (installSupplied && gitSupplied) return;
|
|
314
|
+
if (!installSupplied && !gitSupplied) {
|
|
315
|
+
const index = await plainChoice(rl, "How should setup run?", [
|
|
316
|
+
"Install and Git",
|
|
317
|
+
"Install only",
|
|
318
|
+
"Git only",
|
|
319
|
+
"Files only"
|
|
320
|
+
], signal);
|
|
321
|
+
overrides.install = index === 0 || index === 1;
|
|
322
|
+
overrides.git = index === 0 || index === 2;
|
|
323
|
+
} else {
|
|
324
|
+
if (!installSupplied) overrides.install = await plainChoice(rl, "Install dependencies?", ["No", "Yes"], signal) === 1;
|
|
325
|
+
if (!gitSupplied) overrides.git = await plainChoice(rl, "Initialize local Git?", ["No", "Yes"], signal) === 1;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
async function runWizard(input) {
|
|
329
|
+
return input.plain ? plainWizard(input) : richWizard(input);
|
|
330
|
+
}
|
|
331
|
+
//#endregion
|
|
332
|
+
export { runWizard };
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-agentic-monorepo",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Create an Agentic Monorepo starter repository.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22.13.0"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/fayez-nazzal/agentic-monorepo.git"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/fayez-nazzal/agentic-monorepo#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/fayez-nazzal/agentic-monorepo/issues"
|
|
17
|
+
},
|
|
18
|
+
"bin": {
|
|
19
|
+
"create-agentic-monorepo": "dist/main.mjs"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"template.json",
|
|
24
|
+
"LICENSE",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@clack/prompts": "1.7.0",
|
|
29
|
+
"picocolors": "1.1.1",
|
|
30
|
+
"yaml": "2.9.0",
|
|
31
|
+
"cross-spawn": "7.0.6"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
}
|
|
36
|
+
}
|