blockend-cli 1.4.2 → 1.4.3
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/dist/index.js +122 -142
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { defineCommand, runMain } from "citty";
|
|
|
7
7
|
import path, { join, dirname } from "path";
|
|
8
8
|
import fs from "fs/promises";
|
|
9
9
|
import { exec } from "child_process";
|
|
10
|
-
import { intro, outro, select, spinner, confirm, isCancel } from "@clack/prompts";
|
|
10
|
+
import { intro, outro, select, spinner, confirm, isCancel, log } from "@clack/prompts";
|
|
11
11
|
import pc from "picocolors";
|
|
12
12
|
var REPO_OWNER = "codewithnuh";
|
|
13
13
|
var REPO_NAME = "blockend";
|
|
@@ -18,7 +18,7 @@ function outputError(json, message) {
|
|
|
18
18
|
if (json) {
|
|
19
19
|
process.stdout.write(JSON.stringify({ success: false, error: message }) + "\n");
|
|
20
20
|
} else {
|
|
21
|
-
|
|
21
|
+
log.error(message);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
function outputResult(json, result) {
|
|
@@ -26,7 +26,7 @@ function outputResult(json, result) {
|
|
|
26
26
|
process.stdout.write(JSON.stringify(result) + "\n");
|
|
27
27
|
} else {
|
|
28
28
|
if (result.success) {
|
|
29
|
-
outro(pc.
|
|
29
|
+
outro(pc.green(`\u2728 ${result.message}`));
|
|
30
30
|
} else {
|
|
31
31
|
outro(pc.yellow(`\u2139 ${result.message}`));
|
|
32
32
|
}
|
|
@@ -34,7 +34,7 @@ function outputResult(json, result) {
|
|
|
34
34
|
}
|
|
35
35
|
function handleCancel(value) {
|
|
36
36
|
if (isCancel(value)) {
|
|
37
|
-
outro(pc.
|
|
37
|
+
outro(pc.dim("Operation cancelled."));
|
|
38
38
|
process.exit(0);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -56,7 +56,8 @@ async function findUp(filename, startDir) {
|
|
|
56
56
|
async function addCommand(blockName, options = {}) {
|
|
57
57
|
const { yes = false, json = false } = options;
|
|
58
58
|
if (!json) {
|
|
59
|
-
|
|
59
|
+
console.log("");
|
|
60
|
+
intro(`${pc.bgCyan(pc.black(" blockend "))} ${pc.dim("add")}`);
|
|
60
61
|
}
|
|
61
62
|
const cwd = process.cwd();
|
|
62
63
|
const configPath = await findUp("blockend.json", cwd);
|
|
@@ -70,42 +71,35 @@ async function addCommand(blockName, options = {}) {
|
|
|
70
71
|
const configFile = await fs.readFile(configPath, "utf-8");
|
|
71
72
|
config = JSON.parse(configFile);
|
|
72
73
|
} catch (error) {
|
|
73
|
-
outputError(json, "Failed to parse blockend.json
|
|
74
|
-
if (!json)
|
|
74
|
+
outputError(json, "Failed to parse blockend.json.");
|
|
75
|
+
if (!json) log.error(pc.dim(String(error)));
|
|
75
76
|
return;
|
|
76
77
|
}
|
|
77
78
|
if (config.language !== "typescript") {
|
|
78
79
|
if (json) {
|
|
79
|
-
outputError(
|
|
80
|
-
json,
|
|
81
|
-
"Blockend forces modern architectural standards. Registry exclusively supports TypeScript."
|
|
82
|
-
);
|
|
80
|
+
outputError(json, "Registry exclusively supports TypeScript projects.");
|
|
83
81
|
} else {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
`
|
|
87
|
-
\u2139 Blockend forces modern architectural standards. Registry exclusively supports TypeScript.`
|
|
88
|
-
)
|
|
89
|
-
);
|
|
82
|
+
log.warn("Blockend currently only supports TypeScript projects.");
|
|
83
|
+
outro(pc.dim("Exiting."));
|
|
90
84
|
}
|
|
91
85
|
return;
|
|
92
86
|
}
|
|
93
87
|
const s = spinner();
|
|
94
88
|
if (!json) {
|
|
95
|
-
s.start("
|
|
89
|
+
s.start("Fetching registry...");
|
|
96
90
|
}
|
|
97
91
|
let registry;
|
|
98
92
|
try {
|
|
99
93
|
const response = await fetch(MANIFEST_URL);
|
|
100
94
|
if (!response.ok) throw new Error(`HTTP Error Status: ${response.status}`);
|
|
101
95
|
registry = await response.json();
|
|
102
|
-
if (!json) s.stop(
|
|
96
|
+
if (!json) s.stop("Registry synced.");
|
|
103
97
|
} catch (error) {
|
|
104
98
|
if (!json) {
|
|
105
|
-
s.stop(
|
|
106
|
-
|
|
99
|
+
s.stop("Failed to fetch registry.");
|
|
100
|
+
log.error(pc.dim(String(error)));
|
|
107
101
|
} else {
|
|
108
|
-
outputError(json, "Failed to fetch the component registry from GitHub
|
|
102
|
+
outputError(json, "Failed to fetch the component registry from GitHub.");
|
|
109
103
|
}
|
|
110
104
|
return;
|
|
111
105
|
}
|
|
@@ -125,32 +119,34 @@ async function addCommand(blockName, options = {}) {
|
|
|
125
119
|
return;
|
|
126
120
|
}
|
|
127
121
|
if (!targetBlock) {
|
|
128
|
-
const
|
|
122
|
+
const filteredBlocks = Object.entries(blockMap).filter(([_, block]) => {
|
|
129
123
|
if (!block) return false;
|
|
130
124
|
const hasAdapter = block.adapters?.[envKey] !== void 0;
|
|
131
125
|
const hasEnvironment = block.environments?.[envKey] !== void 0;
|
|
132
126
|
return hasAdapter || hasEnvironment;
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}));
|
|
137
|
-
if (availableOptions.length === 0) {
|
|
127
|
+
});
|
|
128
|
+
if (filteredBlocks.length === 0) {
|
|
129
|
+
const msg = `No backend blocks are currently available for: ${envKey}.`;
|
|
138
130
|
if (json) {
|
|
139
|
-
outputError(
|
|
140
|
-
json,
|
|
141
|
-
`No backend blocks are currently available for your framework layer: [${envKey}].`
|
|
142
|
-
);
|
|
131
|
+
outputError(json, msg);
|
|
143
132
|
} else {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
`\u26A0 No backend blocks are currently available for your framework layer: [${envKey}].`
|
|
147
|
-
)
|
|
148
|
-
);
|
|
133
|
+
log.warn(msg);
|
|
134
|
+
outro(pc.dim("Exiting."));
|
|
149
135
|
}
|
|
150
136
|
return;
|
|
151
137
|
}
|
|
138
|
+
const maxKeyLength = Math.max(...filteredBlocks.map(([key]) => key.length), 0);
|
|
139
|
+
const availableOptions = filteredBlocks.map(([key, block], index) => {
|
|
140
|
+
const paddedKey = key.padEnd(maxKeyLength + 4, " ");
|
|
141
|
+
const maxDescWidth = 60;
|
|
142
|
+
const optimizedDescription = block.description.length > maxDescWidth ? `${block.description.slice(0, maxDescWidth)}...` : block.description;
|
|
143
|
+
return {
|
|
144
|
+
value: key,
|
|
145
|
+
label: `${pc.dim(`${index + 1}.`)} ${pc.bold(pc.cyan(paddedKey))}${pc.dim(optimizedDescription)}`
|
|
146
|
+
};
|
|
147
|
+
});
|
|
152
148
|
const selectBlockPrompt = await select({
|
|
153
|
-
message: "Which
|
|
149
|
+
message: "Which block would you like to add?",
|
|
154
150
|
options: availableOptions
|
|
155
151
|
});
|
|
156
152
|
handleCancel(selectBlockPrompt);
|
|
@@ -158,24 +154,18 @@ async function addCommand(blockName, options = {}) {
|
|
|
158
154
|
}
|
|
159
155
|
const blockMeta = blockMap[targetBlock];
|
|
160
156
|
if (!blockMeta) {
|
|
161
|
-
outputError(json, `Block "${targetBlock}" does not exist in the
|
|
157
|
+
outputError(json, `Block "${targetBlock}" does not exist in the registry.`);
|
|
162
158
|
return;
|
|
163
159
|
}
|
|
164
160
|
const adapterContext = blockMeta.adapters?.[envKey] ?? blockMeta.environments?.[envKey];
|
|
165
161
|
if (!adapterContext) {
|
|
166
|
-
outputError(
|
|
167
|
-
json,
|
|
168
|
-
`The block "${targetBlock}" does not support your environment layout: ${envKey}`
|
|
169
|
-
);
|
|
162
|
+
outputError(json, `The block "${targetBlock}" does not support your environment: ${envKey}`);
|
|
170
163
|
return;
|
|
171
164
|
}
|
|
172
165
|
let selectedVariant;
|
|
173
166
|
const variantKeys = Object.keys(adapterContext.variants || {});
|
|
174
167
|
if (variantKeys.length === 0) {
|
|
175
|
-
outputError(
|
|
176
|
-
json,
|
|
177
|
-
`No architecture storage layout variants found for block framework: ${envKey}`
|
|
178
|
-
);
|
|
168
|
+
outputError(json, `No storage variants found for block environment: ${envKey}`);
|
|
179
169
|
return;
|
|
180
170
|
}
|
|
181
171
|
if (yes) {
|
|
@@ -186,7 +176,7 @@ async function addCommand(blockName, options = {}) {
|
|
|
186
176
|
selectedVariant = variantKeys[0];
|
|
187
177
|
} else {
|
|
188
178
|
const selectVariantPrompt = await select({
|
|
189
|
-
message: "
|
|
179
|
+
message: "Select a storage variant:",
|
|
190
180
|
options: variantKeys.map((vKey) => ({
|
|
191
181
|
value: vKey,
|
|
192
182
|
label: vKey.toUpperCase()
|
|
@@ -203,7 +193,7 @@ async function addCommand(blockName, options = {}) {
|
|
|
203
193
|
const targetFolder = path.resolve(rootDir, physicalPath, targetBlock);
|
|
204
194
|
const packageJsonPath = await findUp("package.json", rootDir);
|
|
205
195
|
if (!packageJsonPath) {
|
|
206
|
-
outputError(json, "Could not locate package.json in your current directory
|
|
196
|
+
outputError(json, "Could not locate package.json in your current directory.");
|
|
207
197
|
return;
|
|
208
198
|
}
|
|
209
199
|
const packageJsonDir = dirname(packageJsonPath);
|
|
@@ -212,8 +202,8 @@ async function addCommand(blockName, options = {}) {
|
|
|
212
202
|
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
213
203
|
packageJson = JSON.parse(packageJsonContent);
|
|
214
204
|
} catch (error) {
|
|
215
|
-
outputError(json, "Failed parsing
|
|
216
|
-
if (!json)
|
|
205
|
+
outputError(json, "Failed parsing package.json.");
|
|
206
|
+
if (!json) log.error(pc.dim(String(error)));
|
|
217
207
|
return;
|
|
218
208
|
}
|
|
219
209
|
const installedDeps = {
|
|
@@ -226,19 +216,16 @@ async function addCommand(blockName, options = {}) {
|
|
|
226
216
|
if (hasMissingDeps) {
|
|
227
217
|
const allMissingNames = [...missingProdDeps, ...missingDevDeps];
|
|
228
218
|
if (!json) {
|
|
229
|
-
|
|
230
|
-
pc.yellow(`
|
|
231
|
-
\u26A0\uFE0F Missing required infrastructure packages: ${allMissingNames.join(", ")}`)
|
|
232
|
-
);
|
|
219
|
+
log.warn(`Missing dependencies: ${pc.cyan(allMissingNames.join(", "))}`);
|
|
233
220
|
}
|
|
234
221
|
const shouldInstallPrompt = yes ? true : await confirm({
|
|
235
|
-
message: "
|
|
222
|
+
message: "Install missing dependencies?",
|
|
236
223
|
initialValue: true
|
|
237
224
|
});
|
|
238
225
|
if (!yes) handleCancel(shouldInstallPrompt);
|
|
239
226
|
if (shouldInstallPrompt) {
|
|
240
227
|
const packageManager = await fs.access(join(packageJsonDir, "pnpm-lock.yaml")).then(() => "pnpm").catch(() => "npm");
|
|
241
|
-
if (!json) s.start(`
|
|
228
|
+
if (!json) s.start(`Installing via ${packageManager}...`);
|
|
242
229
|
try {
|
|
243
230
|
const installTasks = [];
|
|
244
231
|
if (missingProdDeps.length > 0) {
|
|
@@ -252,8 +239,7 @@ async function addCommand(blockName, options = {}) {
|
|
|
252
239
|
);
|
|
253
240
|
}
|
|
254
241
|
for (const installCmd of installTasks) {
|
|
255
|
-
if (!json) s.
|
|
256
|
-
`));
|
|
242
|
+
if (!json) s.message(`Executing: ${installCmd}`);
|
|
257
243
|
await new Promise((resolve, reject) => {
|
|
258
244
|
const child = exec(installCmd, { cwd: packageJsonDir });
|
|
259
245
|
child.stdout?.on("data", (data) => {
|
|
@@ -269,13 +255,12 @@ async function addCommand(blockName, options = {}) {
|
|
|
269
255
|
});
|
|
270
256
|
}
|
|
271
257
|
if (!json) {
|
|
272
|
-
s.
|
|
273
|
-
s.stop();
|
|
258
|
+
s.stop("Dependencies installed.");
|
|
274
259
|
}
|
|
275
260
|
} catch (error) {
|
|
276
261
|
if (!json) {
|
|
277
|
-
s.stop(
|
|
278
|
-
|
|
262
|
+
s.stop("Installation failed.");
|
|
263
|
+
log.error(pc.dim(String(error)));
|
|
279
264
|
} else {
|
|
280
265
|
outputError(json, "Automated dependency installation failed.");
|
|
281
266
|
}
|
|
@@ -317,7 +302,7 @@ async function addCommand(blockName, options = {}) {
|
|
|
317
302
|
}
|
|
318
303
|
if (fileExistsConflict) {
|
|
319
304
|
const overwritePrompt = yes ? true : await confirm({
|
|
320
|
-
message:
|
|
305
|
+
message: `Files for "${targetBlock}" already exist. Overwrite?`,
|
|
321
306
|
initialValue: false
|
|
322
307
|
});
|
|
323
308
|
if (!yes) handleCancel(overwritePrompt);
|
|
@@ -331,7 +316,7 @@ async function addCommand(blockName, options = {}) {
|
|
|
331
316
|
}
|
|
332
317
|
}
|
|
333
318
|
if (!json) {
|
|
334
|
-
s.start(`Downloading
|
|
319
|
+
s.start(`Downloading ${targetBlock}...`);
|
|
335
320
|
}
|
|
336
321
|
try {
|
|
337
322
|
for (const fileMap of filesToDownload) {
|
|
@@ -343,20 +328,20 @@ async function addCommand(blockName, options = {}) {
|
|
|
343
328
|
await fs.mkdir(dirname(localWriteLocation), { recursive: true });
|
|
344
329
|
await fs.writeFile(localWriteLocation, fileContent, "utf-8");
|
|
345
330
|
}
|
|
346
|
-
if (!json) s.stop(
|
|
331
|
+
if (!json) s.stop("Files copied.");
|
|
347
332
|
outputResult(json, {
|
|
348
333
|
success: true,
|
|
349
334
|
block: targetBlock,
|
|
350
335
|
filesWritten: filesToDownload.map((f) => join(targetFolder, f.target)),
|
|
351
336
|
dependenciesInstalled: [...missingProdDeps, ...missingDevDeps],
|
|
352
|
-
message: `
|
|
337
|
+
message: `Block added to ${physicalPath}/${targetBlock}`
|
|
353
338
|
});
|
|
354
339
|
} catch (error) {
|
|
355
340
|
if (!json) {
|
|
356
|
-
s.stop(
|
|
357
|
-
|
|
341
|
+
s.stop("Failed to write files.");
|
|
342
|
+
log.error(pc.dim(String(error)));
|
|
358
343
|
} else {
|
|
359
|
-
outputError(json, "Fatal error occurred while
|
|
344
|
+
outputError(json, "Fatal error occurred while writing block files.");
|
|
360
345
|
}
|
|
361
346
|
}
|
|
362
347
|
}
|
|
@@ -365,7 +350,8 @@ async function addCommand(blockName, options = {}) {
|
|
|
365
350
|
import path2, { join as join7 } from "path";
|
|
366
351
|
import fs2 from "fs/promises";
|
|
367
352
|
import { existsSync as existsSync4 } from "fs";
|
|
368
|
-
import { intro as intro2, outro as outro2, select as select2, text, confirm as confirm2, spinner as spinner2, isCancel as isCancel2 } from "@clack/prompts";
|
|
353
|
+
import { intro as intro2, outro as outro2, select as select2, text, confirm as confirm2, spinner as spinner2, isCancel as isCancel2, log as log2 } from "@clack/prompts";
|
|
354
|
+
import pc3 from "picocolors";
|
|
369
355
|
|
|
370
356
|
// src/detectors/index.ts
|
|
371
357
|
import { join as join6 } from "path";
|
|
@@ -478,7 +464,7 @@ function flattenTsPaths(paths) {
|
|
|
478
464
|
import pc2 from "picocolors";
|
|
479
465
|
var theme = {
|
|
480
466
|
brand: {
|
|
481
|
-
primary: pc2.
|
|
467
|
+
primary: pc2.cyan,
|
|
482
468
|
title: pc2.bold,
|
|
483
469
|
logo: pc2.white
|
|
484
470
|
},
|
|
@@ -491,7 +477,7 @@ var theme = {
|
|
|
491
477
|
success: pc2.green,
|
|
492
478
|
warning: pc2.yellow,
|
|
493
479
|
error: pc2.red,
|
|
494
|
-
info: pc2.
|
|
480
|
+
info: pc2.cyan
|
|
495
481
|
},
|
|
496
482
|
emphasis: {
|
|
497
483
|
strong: pc2.bold,
|
|
@@ -502,11 +488,12 @@ var theme = {
|
|
|
502
488
|
// src/ui/format.ts
|
|
503
489
|
var format = {
|
|
504
490
|
title: (text2) => theme.brand.primary(theme.brand.title(text2)),
|
|
505
|
-
success: (text2) => theme.state.success(
|
|
506
|
-
error: (text2) => theme.state.error(
|
|
491
|
+
success: (text2) => theme.state.success(text2),
|
|
492
|
+
error: (text2) => theme.state.error(text2),
|
|
507
493
|
warning: (text2) => theme.state.warning(text2),
|
|
508
494
|
muted: (text2) => theme.text.muted(text2),
|
|
509
|
-
info: (text2) => theme.state.info(text2)
|
|
495
|
+
info: (text2) => theme.state.info(text2),
|
|
496
|
+
highlight: (text2) => theme.brand.primary(text2)
|
|
510
497
|
};
|
|
511
498
|
|
|
512
499
|
// src/commands/init.ts
|
|
@@ -531,7 +518,8 @@ function outputInitError(json, message) {
|
|
|
531
518
|
if (json) {
|
|
532
519
|
process.stdout.write(JSON.stringify({ success: false, error: message }) + "\n");
|
|
533
520
|
} else {
|
|
534
|
-
|
|
521
|
+
log2.error(format.error(message));
|
|
522
|
+
process.exit(1);
|
|
535
523
|
}
|
|
536
524
|
}
|
|
537
525
|
function outputInitResult(json, result) {
|
|
@@ -546,15 +534,8 @@ async function initCommand(options = {}) {
|
|
|
546
534
|
const cwd = process.cwd();
|
|
547
535
|
const configPath = join7(cwd, "blockend.json");
|
|
548
536
|
if (!json) {
|
|
549
|
-
console.log(
|
|
550
|
-
|
|
551
|
-
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
|
|
552
|
-
\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551
|
|
553
|
-
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551
|
|
554
|
-
\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
|
|
555
|
-
\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D
|
|
556
|
-
`);
|
|
557
|
-
intro2(theme.brand.primary(" Blockend \xB7 Intelligent Backend Blocks Setup "));
|
|
537
|
+
console.log("");
|
|
538
|
+
intro2(`${pc3.bgCyan(pc3.black(" blockend "))} ${theme.text.muted("setup")}`);
|
|
558
539
|
}
|
|
559
540
|
if (existsSync4(configPath)) {
|
|
560
541
|
let action;
|
|
@@ -562,21 +543,21 @@ async function initCommand(options = {}) {
|
|
|
562
543
|
action = "overwrite";
|
|
563
544
|
} else {
|
|
564
545
|
const actionPrompt = await select2({
|
|
565
|
-
message: "blockend.json already exists. What
|
|
546
|
+
message: "A blockend.json configuration already exists. What would you like to do?",
|
|
566
547
|
options: [
|
|
567
|
-
{ value: "keep", label: "Keep existing
|
|
568
|
-
{ value: "overwrite", label: "Overwrite
|
|
569
|
-
{ value: "regenerate", label: "Delete and regenerate" }
|
|
548
|
+
{ value: "keep", label: "Keep existing (cancel setup)" },
|
|
549
|
+
{ value: "overwrite", label: "Overwrite current configuration" },
|
|
550
|
+
{ value: "regenerate", label: "Delete and regenerate from scratch" }
|
|
570
551
|
]
|
|
571
552
|
});
|
|
572
553
|
if (isCancel2(actionPrompt) || actionPrompt === "keep") {
|
|
573
554
|
if (json) {
|
|
574
555
|
outputInitResult(json, {
|
|
575
556
|
success: false,
|
|
576
|
-
message: "
|
|
557
|
+
message: "Setup cancelled. Existing config preserved."
|
|
577
558
|
});
|
|
578
559
|
} else {
|
|
579
|
-
outro2(format.muted("
|
|
560
|
+
outro2(format.muted("Setup cancelled. Existing config preserved."));
|
|
580
561
|
}
|
|
581
562
|
return;
|
|
582
563
|
}
|
|
@@ -584,22 +565,22 @@ async function initCommand(options = {}) {
|
|
|
584
565
|
}
|
|
585
566
|
if (action === "regenerate") {
|
|
586
567
|
await fs2.unlink(configPath);
|
|
587
|
-
if (!json)
|
|
568
|
+
if (!json) log2.warn("Existing configuration deleted.");
|
|
588
569
|
}
|
|
589
570
|
}
|
|
590
571
|
const s = spinner2();
|
|
591
|
-
if (!json) s.start("Scanning project
|
|
572
|
+
if (!json) s.start("Scanning project architecture...");
|
|
592
573
|
const context = await detectProject(cwd);
|
|
593
574
|
const hasSrcDir = existsSync4(join7(cwd, "src"));
|
|
594
575
|
const tsConfig = await resolveTsConfigPaths(cwd);
|
|
595
|
-
if (!json) s.stop(
|
|
576
|
+
if (!json) s.stop("Project scanned.");
|
|
596
577
|
let framework = context.framework;
|
|
597
578
|
if (!framework) {
|
|
598
579
|
if (yes) {
|
|
599
580
|
framework = "express";
|
|
600
581
|
} else {
|
|
601
582
|
const frameworkSelect = await select2({
|
|
602
|
-
message: "
|
|
583
|
+
message: "Which framework does this project use?",
|
|
603
584
|
options: [
|
|
604
585
|
{ value: "express", label: "Express.js" },
|
|
605
586
|
{ value: "fastify", label: "Fastify" },
|
|
@@ -609,32 +590,30 @@ async function initCommand(options = {}) {
|
|
|
609
590
|
});
|
|
610
591
|
if (isCancel2(frameworkSelect)) {
|
|
611
592
|
if (json) {
|
|
612
|
-
outputInitResult(json, { success: false, message: "
|
|
593
|
+
outputInitResult(json, { success: false, message: "Setup cancelled." });
|
|
613
594
|
} else {
|
|
614
|
-
outro2(format.muted("
|
|
595
|
+
outro2(format.muted("Setup cancelled."));
|
|
615
596
|
}
|
|
616
597
|
return;
|
|
617
598
|
}
|
|
618
599
|
framework = frameworkSelect;
|
|
619
600
|
}
|
|
620
601
|
} else if (!json) {
|
|
621
|
-
|
|
622
|
-
`${format.success("\u2714")} Framework environment detected: ${theme.state.info(framework)}`
|
|
623
|
-
);
|
|
602
|
+
log2.info(`Framework detected: ${theme.state.info(framework)}`);
|
|
624
603
|
}
|
|
625
604
|
const defaultDir = hasSrcDir ? "src/blocks" : "blocks";
|
|
626
605
|
let rawPhysicalInput = defaultDir;
|
|
627
606
|
if (!yes) {
|
|
628
607
|
const directoryPrompt = await text({
|
|
629
|
-
message: "
|
|
608
|
+
message: "Where would you like to install blocks?",
|
|
630
609
|
placeholder: defaultDir,
|
|
631
610
|
initialValue: defaultDir,
|
|
632
611
|
validate(value) {
|
|
633
|
-
if (value?.trim().length === 0) return "
|
|
612
|
+
if (value?.trim().length === 0) return "Directory path cannot be empty.";
|
|
634
613
|
}
|
|
635
614
|
});
|
|
636
615
|
if (isCancel2(directoryPrompt)) {
|
|
637
|
-
outro2(format.muted("
|
|
616
|
+
outro2(format.muted("Setup cancelled."));
|
|
638
617
|
return;
|
|
639
618
|
}
|
|
640
619
|
rawPhysicalInput = String(directoryPrompt).trim();
|
|
@@ -677,7 +656,7 @@ async function initCommand(options = {}) {
|
|
|
677
656
|
includeRedis = true;
|
|
678
657
|
} else {
|
|
679
658
|
const redisConfirm = await confirm2({
|
|
680
|
-
message: "Redis detected. Enable Redis-backed
|
|
659
|
+
message: "Redis detected in project. Enable Redis-backed variants?",
|
|
681
660
|
initialValue: true
|
|
682
661
|
});
|
|
683
662
|
if (!isCancel2(redisConfirm)) {
|
|
@@ -697,27 +676,28 @@ async function initCommand(options = {}) {
|
|
|
697
676
|
blocks: finalPath
|
|
698
677
|
}
|
|
699
678
|
};
|
|
700
|
-
if (!json) s.start("
|
|
679
|
+
if (!json) s.start("Writing configuration...");
|
|
701
680
|
try {
|
|
702
681
|
await fs2.writeFile(configPath, JSON.stringify(configPayload, null, 2), "utf-8");
|
|
703
|
-
if (!json) s.stop(
|
|
682
|
+
if (!json) s.stop("Configuration saved.");
|
|
704
683
|
outputInitResult(json, {
|
|
705
684
|
success: true,
|
|
706
|
-
message: "
|
|
685
|
+
message: "Blockend initialized successfully! Run: npx blockend add <block>",
|
|
707
686
|
config: configPayload
|
|
708
687
|
});
|
|
709
688
|
} catch {
|
|
710
689
|
if (!json) {
|
|
711
|
-
s.stop(
|
|
690
|
+
s.stop("Failed");
|
|
691
|
+
outputInitError(false, "Failed to write configuration file.");
|
|
712
692
|
} else {
|
|
713
|
-
outputInitError(
|
|
693
|
+
outputInitError(true, "Failed to write architectural layout configuration map.");
|
|
714
694
|
}
|
|
715
695
|
}
|
|
716
696
|
}
|
|
717
697
|
|
|
718
698
|
// src/commands/detect.ts
|
|
719
699
|
import { outro as outro3 } from "@clack/prompts";
|
|
720
|
-
import
|
|
700
|
+
import pc4 from "picocolors";
|
|
721
701
|
async function detectCommand(options = {}) {
|
|
722
702
|
const { json = false } = options;
|
|
723
703
|
try {
|
|
@@ -727,27 +707,27 @@ async function detectCommand(options = {}) {
|
|
|
727
707
|
return;
|
|
728
708
|
}
|
|
729
709
|
console.log();
|
|
730
|
-
console.log(
|
|
710
|
+
console.log(pc4.bold(" Detected project configuration:"));
|
|
731
711
|
console.log();
|
|
732
|
-
console.log(` Framework: ${
|
|
733
|
-
console.log(` Language: ${
|
|
734
|
-
console.log(` Package manager: ${
|
|
735
|
-
console.log(` Source dir: ${
|
|
712
|
+
console.log(` Framework: ${pc4.cyan(context.framework)}`);
|
|
713
|
+
console.log(` Language: ${pc4.cyan(context.language)}`);
|
|
714
|
+
console.log(` Package manager: ${pc4.cyan(context.packageManager)}`);
|
|
715
|
+
console.log(` Source dir: ${pc4.dim(context.srcDir)}`);
|
|
736
716
|
console.log(
|
|
737
|
-
` Redis: ${context.hasRedis ?
|
|
717
|
+
` Redis: ${context.hasRedis ? pc4.green("detected") : pc4.dim("not found")}`
|
|
738
718
|
);
|
|
739
719
|
console.log(
|
|
740
|
-
` Prisma: ${context.hasPrisma ?
|
|
720
|
+
` Prisma: ${context.hasPrisma ? pc4.green("detected") : pc4.dim("not found")}`
|
|
741
721
|
);
|
|
742
722
|
console.log(
|
|
743
|
-
` Drizzle: ${context.hasDrizzle ?
|
|
723
|
+
` Drizzle: ${context.hasDrizzle ? pc4.green("detected") : pc4.dim("not found")}`
|
|
744
724
|
);
|
|
745
725
|
console.log();
|
|
746
726
|
} catch (error) {
|
|
747
727
|
if (json) {
|
|
748
728
|
process.stdout.write(JSON.stringify({ success: false, error: String(error) }) + "\n");
|
|
749
729
|
} else {
|
|
750
|
-
outro3(
|
|
730
|
+
outro3(pc4.red(`\u2716 Detection failed: ${String(error)}`));
|
|
751
731
|
}
|
|
752
732
|
process.exit(1);
|
|
753
733
|
}
|
|
@@ -756,7 +736,7 @@ async function detectCommand(options = {}) {
|
|
|
756
736
|
// src/commands/list.ts
|
|
757
737
|
import { dirname as dirname2, join as join8 } from "path";
|
|
758
738
|
import fs3 from "fs/promises";
|
|
759
|
-
import
|
|
739
|
+
import pc5 from "picocolors";
|
|
760
740
|
import { outro as outro4, spinner as spinner3 } from "@clack/prompts";
|
|
761
741
|
var REPO_OWNER2 = "codewithnuh";
|
|
762
742
|
var REPO_NAME2 = "blockend";
|
|
@@ -787,7 +767,7 @@ async function listCommand(options = {}) {
|
|
|
787
767
|
JSON.stringify({ success: false, error: "blockend.json not found." }) + "\n"
|
|
788
768
|
);
|
|
789
769
|
} else {
|
|
790
|
-
outro4(
|
|
770
|
+
outro4(pc5.red("\u2716 blockend.json not found. Run 'npx blockend init' first."));
|
|
791
771
|
}
|
|
792
772
|
return;
|
|
793
773
|
}
|
|
@@ -801,7 +781,7 @@ async function listCommand(options = {}) {
|
|
|
801
781
|
JSON.stringify({ success: false, error: "Failed to parse configuration matrix." }) + "\n"
|
|
802
782
|
);
|
|
803
783
|
} else {
|
|
804
|
-
outro4(
|
|
784
|
+
outro4(pc5.red("\u2716 Failed to parse blockend.json layout configuration."));
|
|
805
785
|
}
|
|
806
786
|
return;
|
|
807
787
|
}
|
|
@@ -815,14 +795,14 @@ async function listCommand(options = {}) {
|
|
|
815
795
|
const response = await fetch(MANIFEST_URL2);
|
|
816
796
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
817
797
|
registry = await response.json();
|
|
818
|
-
if (!json) s.stop(
|
|
798
|
+
if (!json) s.stop(pc5.green("\u2714 Synced available block registries."));
|
|
819
799
|
} catch {
|
|
820
800
|
if (json) {
|
|
821
801
|
process.stdout.write(
|
|
822
802
|
JSON.stringify({ success: false, error: "Network sync failure." }) + "\n"
|
|
823
803
|
);
|
|
824
804
|
} else {
|
|
825
|
-
s.stop(
|
|
805
|
+
s.stop(pc5.red("\u2716 Failed to fetch the component registry from GitHub network paths."));
|
|
826
806
|
}
|
|
827
807
|
return;
|
|
828
808
|
}
|
|
@@ -851,15 +831,15 @@ async function listCommand(options = {}) {
|
|
|
851
831
|
);
|
|
852
832
|
} else {
|
|
853
833
|
console.log(`
|
|
854
|
-
Available backend blocks for ${
|
|
834
|
+
Available backend blocks for ${pc5.magenta(envKey)}:`);
|
|
855
835
|
if (blocksForEnv.length === 0) {
|
|
856
|
-
console.log(
|
|
836
|
+
console.log(pc5.dim(" No blocks found for this framework."));
|
|
857
837
|
} else {
|
|
858
838
|
blocksForEnv.forEach((b) => {
|
|
859
839
|
console.log(`
|
|
860
|
-
${
|
|
861
|
-
console.log(` ${
|
|
862
|
-
console.log(` Storage Variants: ${b.variants.map((v) =>
|
|
840
|
+
${pc5.cyan(b.name)}`);
|
|
841
|
+
console.log(` ${pc5.dim(b.description)}`);
|
|
842
|
+
console.log(` Storage Variants: ${b.variants.map((v) => pc5.yellow(v)).join(", ")}`);
|
|
863
843
|
});
|
|
864
844
|
console.log();
|
|
865
845
|
}
|
|
@@ -869,7 +849,7 @@ Available backend blocks for ${pc4.magenta(envKey)}:`);
|
|
|
869
849
|
// src/commands/mcp.ts
|
|
870
850
|
import path3, { join as join9 } from "path";
|
|
871
851
|
import fs4 from "fs/promises";
|
|
872
|
-
import
|
|
852
|
+
import pc6 from "picocolors";
|
|
873
853
|
import { outro as outro5, spinner as spinner4, select as select3, confirm as confirm3 } from "@clack/prompts";
|
|
874
854
|
var CLIENT_MATRIX = {
|
|
875
855
|
claude: {
|
|
@@ -992,22 +972,22 @@ async function mcpInitCommand(options) {
|
|
|
992
972
|
}
|
|
993
973
|
const meta = CLIENT_MATRIX[chosenClient];
|
|
994
974
|
if (!meta) {
|
|
995
|
-
outro5(
|
|
975
|
+
outro5(pc6.red(`\u2716 Unsupported client identifier profile: ${options.client}`));
|
|
996
976
|
return;
|
|
997
977
|
}
|
|
998
978
|
const absoluteConfigTarget = join9(cwd, meta.relativePath);
|
|
999
979
|
if (options.dryRun) {
|
|
1000
980
|
console.log(
|
|
1001
|
-
|
|
1002
|
-
\u2139 Dry-run mode active. Intended path location: ${
|
|
981
|
+
pc6.cyan(`
|
|
982
|
+
\u2139 Dry-run mode active. Intended path location: ${pc6.dim(meta.relativePath)}`)
|
|
1003
983
|
);
|
|
1004
984
|
if (meta.format === "json") {
|
|
1005
985
|
const jsonConfig = meta.isCustomSchema ? { "mcp.mcpServers": { blockend: BLOCKEND_SERVER } } : { mcpServers: { blockend: BLOCKEND_SERVER } };
|
|
1006
|
-
console.log(
|
|
986
|
+
console.log(pc6.gray(JSON.stringify(jsonConfig, null, 2)));
|
|
1007
987
|
} else {
|
|
1008
|
-
console.log(
|
|
988
|
+
console.log(pc6.gray(generateToml(BLOCKEND_SERVER)));
|
|
1009
989
|
}
|
|
1010
|
-
outro5(
|
|
990
|
+
outro5(pc6.green("\u2714 Dry run evaluation complete."));
|
|
1011
991
|
return;
|
|
1012
992
|
}
|
|
1013
993
|
let fileConflict = false;
|
|
@@ -1022,12 +1002,12 @@ async function mcpInitCommand(options) {
|
|
|
1022
1002
|
initialValue: false
|
|
1023
1003
|
});
|
|
1024
1004
|
if (!shouldOverwrite || typeof shouldOverwrite === "symbol") {
|
|
1025
|
-
outro5(
|
|
1005
|
+
outro5(pc6.yellow("\u2139 Operations halted. Project layout revisions preserved."));
|
|
1026
1006
|
return;
|
|
1027
1007
|
}
|
|
1028
1008
|
}
|
|
1029
1009
|
const s = spinner4();
|
|
1030
|
-
s.start(`Writing localized project configurations inside ${
|
|
1010
|
+
s.start(`Writing localized project configurations inside ${pc6.dim(meta.relativePath)}...`);
|
|
1031
1011
|
try {
|
|
1032
1012
|
await fs4.mkdir(path3.dirname(absoluteConfigTarget), { recursive: true });
|
|
1033
1013
|
if (meta.format === "json") {
|
|
@@ -1052,11 +1032,11 @@ async function mcpInitCommand(options) {
|
|
|
1052
1032
|
await fs4.writeFile(absoluteConfigTarget, generateToml(BLOCKEND_SERVER), "utf-8");
|
|
1053
1033
|
}
|
|
1054
1034
|
s.stop(
|
|
1055
|
-
|
|
1035
|
+
pc6.green(`\u2714 Local workspace integration fully complete! File target: ${meta.relativePath}`)
|
|
1056
1036
|
);
|
|
1057
1037
|
} catch (error) {
|
|
1058
|
-
s.stop(
|
|
1059
|
-
console.error(
|
|
1038
|
+
s.stop(pc6.red("\u2716 Fatal crash reading or creating local configuration maps."));
|
|
1039
|
+
console.error(pc6.dim(String(error)));
|
|
1060
1040
|
}
|
|
1061
1041
|
}
|
|
1062
1042
|
|
package/package.json
CHANGED