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.
Files changed (2) hide show
  1. package/dist/index.js +122 -142
  2. 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
- outro(pc.red(`\u2716 ${message}`));
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.cyan(`\u2728 ${result.message}`));
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.yellow("\u26A0 Operation cancelled. Exiting Blockend CLI cleanly."));
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
- intro(pc.bgBlack(pc.magenta(" Blockend Component Ingestion ")));
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 layout configuration.");
74
- if (!json) console.error(pc.dim(String(error)));
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
- outro(
85
- pc.yellow(
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("Connecting to remote Blockend Registry manifest...");
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(pc.green("\u2714 Remote manifest synchronization complete."));
96
+ if (!json) s.stop("Registry synced.");
103
97
  } catch (error) {
104
98
  if (!json) {
105
- s.stop(pc.red("\u2716 Failed to fetch the component registry from GitHub network paths."));
106
- console.error(pc.dim(String(error)));
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 network paths.");
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 availableOptions = Object.entries(blockMap).filter(([_, block]) => {
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
- }).map(([key, block]) => ({
134
- value: key,
135
- label: `${key} - ${pc.dim(block.description)}`
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
- outro(
145
- pc.yellow(
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 backend block would you like to inject?",
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 remote registry.`);
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: "Which architectural storage variant do you want to back this block?",
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 layout hierarchy.");
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 file data configurations from target package.json location.");
216
- if (!json) console.error(pc.dim(String(error)));
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
- console.log(
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: "Would you like the CLI to automatically install these dependencies?",
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(`Preparing native workspace via ${packageManager}...`);
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.stop(pc.cyan(`Executing: ${installCmd}
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.start(pc.green("\u2714 All dependencies synchronized successfully."));
273
- s.stop();
258
+ s.stop("Dependencies installed.");
274
259
  }
275
260
  } catch (error) {
276
261
  if (!json) {
277
- s.stop(pc.red("\u2716 Automated dependency installation failed. Please run setup manually."));
278
- console.error(pc.dim(String(error)));
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: `\u26A0 Components in [${targetBlock}] already exist. Overwrite custom revisions?`,
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 and building template adapter blocks [${targetBlock}]...`);
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(pc.green("\u2714 Component isolation structures written smoothly."));
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: `Source blocks written to ${physicalPath}/${targetBlock}/. Code ownership transferred!`
337
+ message: `Block added to ${physicalPath}/${targetBlock}`
353
338
  });
354
339
  } catch (error) {
355
340
  if (!json) {
356
- s.stop(pc.red("\u2716 Fatal error occurred while assembling file mappings."));
357
- console.error(pc.dim(String(error)));
341
+ s.stop("Failed to write files.");
342
+ log.error(pc.dim(String(error)));
358
343
  } else {
359
- outputError(json, "Fatal error occurred while assembling file mappings.");
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.blue,
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.blue
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(`\u2714 ${text2}`),
506
- error: (text2) => theme.state.error(`\u2716 ${text2}`),
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
- outro2(format.error(message));
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
- \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557
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 do you want to do?",
546
+ message: "A blockend.json configuration already exists. What would you like to do?",
566
547
  options: [
567
- { value: "keep", label: "Keep existing config (cancel init)" },
568
- { value: "overwrite", label: "Overwrite config" },
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: "Initialization cancelled. Existing config preserved."
557
+ message: "Setup cancelled. Existing config preserved."
577
558
  });
578
559
  } else {
579
- outro2(format.muted("Initialization cancelled. Existing config preserved."));
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) console.log(format.error("Existing config deleted"));
568
+ if (!json) log2.warn("Existing configuration deleted.");
588
569
  }
589
570
  }
590
571
  const s = spinner2();
591
- if (!json) s.start("Scanning project layout...");
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(format.success("Project architecture scanned"));
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: "Framework could not be auto-detected. Select framework environment manually:",
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: "Initialization cancelled." });
593
+ outputInitResult(json, { success: false, message: "Setup cancelled." });
613
594
  } else {
614
- outro2(format.muted("Initialization cancelled."));
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
- console.log(
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: "Configure the targeted physical directory destination for blocks:",
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 "Physical path location directory cannot be empty.";
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("Initialization cancelled."));
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 block variants automatically?",
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("Finalizing configuration...");
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(format.success("blockend.json ready"));
682
+ if (!json) s.stop("Configuration saved.");
704
683
  outputInitResult(json, {
705
684
  success: true,
706
- message: "\u2728 Blockend initialized successfully. Run: npx blockend add <block>",
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(format.error("Failed to write configuration"));
690
+ s.stop("Failed");
691
+ outputInitError(false, "Failed to write configuration file.");
712
692
  } else {
713
- outputInitError(json, "Failed to write architectural layout configuration map.");
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 pc3 from "picocolors";
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(pc3.bold(" Detected project configuration:"));
710
+ console.log(pc4.bold(" Detected project configuration:"));
731
711
  console.log();
732
- console.log(` Framework: ${pc3.cyan(context.framework)}`);
733
- console.log(` Language: ${pc3.cyan(context.language)}`);
734
- console.log(` Package manager: ${pc3.cyan(context.packageManager)}`);
735
- console.log(` Source dir: ${pc3.dim(context.srcDir)}`);
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 ? pc3.green("detected") : pc3.dim("not found")}`
717
+ ` Redis: ${context.hasRedis ? pc4.green("detected") : pc4.dim("not found")}`
738
718
  );
739
719
  console.log(
740
- ` Prisma: ${context.hasPrisma ? pc3.green("detected") : pc3.dim("not found")}`
720
+ ` Prisma: ${context.hasPrisma ? pc4.green("detected") : pc4.dim("not found")}`
741
721
  );
742
722
  console.log(
743
- ` Drizzle: ${context.hasDrizzle ? pc3.green("detected") : pc3.dim("not found")}`
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(pc3.red(`\u2716 Detection failed: ${String(error)}`));
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 pc4 from "picocolors";
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(pc4.red("\u2716 blockend.json not found. Run 'npx blockend init' first."));
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(pc4.red("\u2716 Failed to parse blockend.json layout configuration."));
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(pc4.green("\u2714 Synced available block registries."));
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(pc4.red("\u2716 Failed to fetch the component registry from GitHub network paths."));
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 ${pc4.magenta(envKey)}:`);
834
+ Available backend blocks for ${pc5.magenta(envKey)}:`);
855
835
  if (blocksForEnv.length === 0) {
856
- console.log(pc4.dim(" No blocks found for this framework."));
836
+ console.log(pc5.dim(" No blocks found for this framework."));
857
837
  } else {
858
838
  blocksForEnv.forEach((b) => {
859
839
  console.log(`
860
- ${pc4.cyan(b.name)}`);
861
- console.log(` ${pc4.dim(b.description)}`);
862
- console.log(` Storage Variants: ${b.variants.map((v) => pc4.yellow(v)).join(", ")}`);
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 pc5 from "picocolors";
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(pc5.red(`\u2716 Unsupported client identifier profile: ${options.client}`));
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
- pc5.cyan(`
1002
- \u2139 Dry-run mode active. Intended path location: ${pc5.dim(meta.relativePath)}`)
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(pc5.gray(JSON.stringify(jsonConfig, null, 2)));
986
+ console.log(pc6.gray(JSON.stringify(jsonConfig, null, 2)));
1007
987
  } else {
1008
- console.log(pc5.gray(generateToml(BLOCKEND_SERVER)));
988
+ console.log(pc6.gray(generateToml(BLOCKEND_SERVER)));
1009
989
  }
1010
- outro5(pc5.green("\u2714 Dry run evaluation complete."));
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(pc5.yellow("\u2139 Operations halted. Project layout revisions preserved."));
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 ${pc5.dim(meta.relativePath)}...`);
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
- pc5.green(`\u2714 Local workspace integration fully complete! File target: ${meta.relativePath}`)
1035
+ pc6.green(`\u2714 Local workspace integration fully complete! File target: ${meta.relativePath}`)
1056
1036
  );
1057
1037
  } catch (error) {
1058
- s.stop(pc5.red("\u2716 Fatal crash reading or creating local configuration maps."));
1059
- console.error(pc5.dim(String(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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blockend-cli",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "CLI for installing production-ready backend blocks into Next.js, Express, Hono, NestJS, and other Node.js applications.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",