blockend-cli 1.4.1 → 1.4.2
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 +119 -14
- package/package.json +11 -10
- package/LICENSE +0 -21
package/dist/index.js
CHANGED
|
@@ -362,11 +362,117 @@ async function addCommand(blockName, options = {}) {
|
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
// src/commands/init.ts
|
|
365
|
-
import path2, { join as
|
|
365
|
+
import path2, { join as join7 } from "path";
|
|
366
366
|
import fs2 from "fs/promises";
|
|
367
|
-
import { existsSync } from "fs";
|
|
367
|
+
import { existsSync as existsSync4 } from "fs";
|
|
368
368
|
import { intro as intro2, outro as outro2, select as select2, text, confirm as confirm2, spinner as spinner2, isCancel as isCancel2 } from "@clack/prompts";
|
|
369
|
-
|
|
369
|
+
|
|
370
|
+
// src/detectors/index.ts
|
|
371
|
+
import { join as join6 } from "path";
|
|
372
|
+
|
|
373
|
+
// src/detectors/readers/package.ts
|
|
374
|
+
import { readFile } from "fs/promises";
|
|
375
|
+
import { join as join2 } from "path";
|
|
376
|
+
async function readPackageJson(cwd) {
|
|
377
|
+
const pkgPath = join2(cwd, "package.json");
|
|
378
|
+
try {
|
|
379
|
+
const content = await readFile(pkgPath, "utf-8");
|
|
380
|
+
return JSON.parse(content);
|
|
381
|
+
} catch {
|
|
382
|
+
throw new Error(`No package.json found at ${pkgPath}. Run blockend from your project root.`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/detectors/readers/tsconfig.ts
|
|
387
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
388
|
+
import { existsSync } from "fs";
|
|
389
|
+
import { join as join3 } from "path";
|
|
390
|
+
async function readTsConfig(cwd) {
|
|
391
|
+
const tsconfigPath = join3(cwd, "tsconfig.json");
|
|
392
|
+
if (!existsSync(tsconfigPath)) return null;
|
|
393
|
+
try {
|
|
394
|
+
const content = await readFile2(tsconfigPath, "utf-8");
|
|
395
|
+
const cleanLines = content.split(/\r?\n/).filter((line) => {
|
|
396
|
+
const trimmed = line.trim();
|
|
397
|
+
return !trimmed.startsWith("//") && !trimmed.startsWith("/*");
|
|
398
|
+
}).join("\n").replace(/,(\s*[}\]])/g, "$1");
|
|
399
|
+
return JSON.parse(cleanLines);
|
|
400
|
+
} catch {
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// src/detectors/readers/filesystem.ts
|
|
406
|
+
import { existsSync as existsSync2 } from "fs";
|
|
407
|
+
import { join as join4 } from "path";
|
|
408
|
+
async function inferSrcDir(cwd) {
|
|
409
|
+
const candidates = ["src", "app", "lib"];
|
|
410
|
+
for (const dir of candidates) {
|
|
411
|
+
if (existsSync2(join4(cwd, dir))) {
|
|
412
|
+
return join4(cwd, dir);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return cwd;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// src/detectors/framework.ts
|
|
419
|
+
function detectFramework(deps) {
|
|
420
|
+
if ("fastify" in deps) return "fastify";
|
|
421
|
+
if ("hono" in deps) return "hono";
|
|
422
|
+
if ("express" in deps) return "express";
|
|
423
|
+
if ("next" in deps) return "next";
|
|
424
|
+
return "none";
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// src/detectors/runtime.ts
|
|
428
|
+
function detectRuntime(deps) {
|
|
429
|
+
if ("@types/bun" in deps || "bun-types" in deps) return "bun";
|
|
430
|
+
return "node";
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// src/detectors/package-manager.ts
|
|
434
|
+
import { existsSync as existsSync3 } from "fs";
|
|
435
|
+
import { join as join5 } from "path";
|
|
436
|
+
function detectPackageManager(cwd) {
|
|
437
|
+
if (existsSync3(join5(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
438
|
+
if (existsSync3(join5(cwd, "bun.lockb"))) return "bun";
|
|
439
|
+
if (existsSync3(join5(cwd, "yarn.lock"))) return "yarn";
|
|
440
|
+
return "npm";
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// src/detectors/index.ts
|
|
444
|
+
async function detectProject(cwd) {
|
|
445
|
+
const [pkg, tsConfig] = await Promise.all([readPackageJson(cwd), readTsConfig(cwd)]);
|
|
446
|
+
const allDeps = {
|
|
447
|
+
...pkg.dependencies,
|
|
448
|
+
...pkg.devDependencies,
|
|
449
|
+
...pkg.peerDependencies
|
|
450
|
+
};
|
|
451
|
+
const srcDir = await inferSrcDir(cwd);
|
|
452
|
+
return {
|
|
453
|
+
root: cwd,
|
|
454
|
+
language: tsConfig !== null ? "typescript" : "javascript",
|
|
455
|
+
runtime: detectRuntime(allDeps),
|
|
456
|
+
framework: detectFramework(allDeps),
|
|
457
|
+
packageManager: detectPackageManager(cwd),
|
|
458
|
+
hasRedis: "ioredis" in allDeps || "redis" in allDeps,
|
|
459
|
+
hasPrisma: "@prisma/client" in allDeps,
|
|
460
|
+
hasDrizzle: "drizzle-orm" in allDeps,
|
|
461
|
+
aliasMap: tsConfig?.compilerOptions?.paths ? flattenTsPaths(tsConfig.compilerOptions.paths) : {},
|
|
462
|
+
srcDir,
|
|
463
|
+
// Default blocks directory: srcDir/lib/blocks
|
|
464
|
+
blocksDir: join6(srcDir, "lib", "blocks")
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
function flattenTsPaths(paths) {
|
|
468
|
+
const result = {};
|
|
469
|
+
for (const [alias, targets] of Object.entries(paths)) {
|
|
470
|
+
if (targets[0]) {
|
|
471
|
+
result[alias.replace("/*", "/")] = targets[0].replace("/*", "/");
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return result;
|
|
475
|
+
}
|
|
370
476
|
|
|
371
477
|
// src/ui/theme.ts
|
|
372
478
|
import pc2 from "picocolors";
|
|
@@ -405,9 +511,9 @@ var format = {
|
|
|
405
511
|
|
|
406
512
|
// src/commands/init.ts
|
|
407
513
|
async function resolveTsConfigPaths(cwd) {
|
|
408
|
-
const possiblePaths = [
|
|
514
|
+
const possiblePaths = [join7(cwd, "tsconfig.json"), join7(cwd, "jsconfig.json")];
|
|
409
515
|
for (const configPath of possiblePaths) {
|
|
410
|
-
if (
|
|
516
|
+
if (existsSync4(configPath)) {
|
|
411
517
|
try {
|
|
412
518
|
const rawContent = await fs2.readFile(configPath, "utf-8");
|
|
413
519
|
const cleanJsonContent = rawContent.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, "$1");
|
|
@@ -438,7 +544,7 @@ function outputInitResult(json, result) {
|
|
|
438
544
|
async function initCommand(options = {}) {
|
|
439
545
|
const { yes = false, json = false } = options;
|
|
440
546
|
const cwd = process.cwd();
|
|
441
|
-
const configPath =
|
|
547
|
+
const configPath = join7(cwd, "blockend.json");
|
|
442
548
|
if (!json) {
|
|
443
549
|
console.log(`
|
|
444
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
|
|
@@ -450,7 +556,7 @@ async function initCommand(options = {}) {
|
|
|
450
556
|
`);
|
|
451
557
|
intro2(theme.brand.primary(" Blockend \xB7 Intelligent Backend Blocks Setup "));
|
|
452
558
|
}
|
|
453
|
-
if (
|
|
559
|
+
if (existsSync4(configPath)) {
|
|
454
560
|
let action;
|
|
455
561
|
if (yes) {
|
|
456
562
|
action = "overwrite";
|
|
@@ -484,7 +590,7 @@ async function initCommand(options = {}) {
|
|
|
484
590
|
const s = spinner2();
|
|
485
591
|
if (!json) s.start("Scanning project layout...");
|
|
486
592
|
const context = await detectProject(cwd);
|
|
487
|
-
const hasSrcDir =
|
|
593
|
+
const hasSrcDir = existsSync4(join7(cwd, "src"));
|
|
488
594
|
const tsConfig = await resolveTsConfigPaths(cwd);
|
|
489
595
|
if (!json) s.stop(format.success("Project architecture scanned"));
|
|
490
596
|
let framework = context.framework;
|
|
@@ -610,13 +716,12 @@ async function initCommand(options = {}) {
|
|
|
610
716
|
}
|
|
611
717
|
|
|
612
718
|
// src/commands/detect.ts
|
|
613
|
-
import { detectProject as detectProject2 } from "@blockend/detector";
|
|
614
719
|
import { outro as outro3 } from "@clack/prompts";
|
|
615
720
|
import pc3 from "picocolors";
|
|
616
721
|
async function detectCommand(options = {}) {
|
|
617
722
|
const { json = false } = options;
|
|
618
723
|
try {
|
|
619
|
-
const context = await
|
|
724
|
+
const context = await detectProject(process.cwd());
|
|
620
725
|
if (json) {
|
|
621
726
|
process.stdout.write(JSON.stringify(context, null, 2) + "\n");
|
|
622
727
|
return;
|
|
@@ -649,7 +754,7 @@ async function detectCommand(options = {}) {
|
|
|
649
754
|
}
|
|
650
755
|
|
|
651
756
|
// src/commands/list.ts
|
|
652
|
-
import { dirname as dirname2, join as
|
|
757
|
+
import { dirname as dirname2, join as join8 } from "path";
|
|
653
758
|
import fs3 from "fs/promises";
|
|
654
759
|
import pc4 from "picocolors";
|
|
655
760
|
import { outro as outro4, spinner as spinner3 } from "@clack/prompts";
|
|
@@ -660,7 +765,7 @@ var MANIFEST_URL2 = `https://raw.githubusercontent.com/${REPO_OWNER2}/${REPO_NAM
|
|
|
660
765
|
async function findUp2(filename, startDir) {
|
|
661
766
|
let dir = startDir;
|
|
662
767
|
while (true) {
|
|
663
|
-
const checkPath =
|
|
768
|
+
const checkPath = join8(dir, filename);
|
|
664
769
|
try {
|
|
665
770
|
await fs3.access(checkPath);
|
|
666
771
|
return checkPath;
|
|
@@ -762,7 +867,7 @@ Available backend blocks for ${pc4.magenta(envKey)}:`);
|
|
|
762
867
|
}
|
|
763
868
|
|
|
764
869
|
// src/commands/mcp.ts
|
|
765
|
-
import path3, { join as
|
|
870
|
+
import path3, { join as join9 } from "path";
|
|
766
871
|
import fs4 from "fs/promises";
|
|
767
872
|
import pc5 from "picocolors";
|
|
768
873
|
import { outro as outro5, spinner as spinner4, select as select3, confirm as confirm3 } from "@clack/prompts";
|
|
@@ -890,7 +995,7 @@ async function mcpInitCommand(options) {
|
|
|
890
995
|
outro5(pc5.red(`\u2716 Unsupported client identifier profile: ${options.client}`));
|
|
891
996
|
return;
|
|
892
997
|
}
|
|
893
|
-
const absoluteConfigTarget =
|
|
998
|
+
const absoluteConfigTarget = join9(cwd, meta.relativePath);
|
|
894
999
|
if (options.dryRun) {
|
|
895
1000
|
console.log(
|
|
896
1001
|
pc5.cyan(`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blockend-cli",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
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",
|
|
@@ -14,6 +14,13 @@
|
|
|
14
14
|
"dist",
|
|
15
15
|
"README.md"
|
|
16
16
|
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup src/index.ts --format esm --dts --clean --out-dir dist",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:watch": "vitest",
|
|
22
|
+
"prepublishOnly": "pnpm build"
|
|
23
|
+
},
|
|
17
24
|
"keywords": [
|
|
18
25
|
"blockend",
|
|
19
26
|
"backend",
|
|
@@ -59,6 +66,7 @@
|
|
|
59
66
|
"engines": {
|
|
60
67
|
"node": ">=20"
|
|
61
68
|
},
|
|
69
|
+
"packageManager": "pnpm@10.33.2",
|
|
62
70
|
"dependencies": {
|
|
63
71
|
"@clack/prompts": "^1.5.1",
|
|
64
72
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
@@ -66,18 +74,11 @@
|
|
|
66
74
|
"commander": "^15.0.0",
|
|
67
75
|
"execa": "^9.6.1",
|
|
68
76
|
"picocolors": "^1.1.1",
|
|
69
|
-
"zod": "^4.4.3"
|
|
70
|
-
"@blockend/detector": "0.1.0"
|
|
77
|
+
"zod": "^4.4.3"
|
|
71
78
|
},
|
|
72
79
|
"devDependencies": {
|
|
73
80
|
"@types/node": "^25.9.3",
|
|
74
81
|
"tsup": "^8.5.1",
|
|
75
82
|
"vitest": "^1.6.1"
|
|
76
|
-
},
|
|
77
|
-
"scripts": {
|
|
78
|
-
"build": "tsup src/index.ts --format esm --dts --clean --out-dir dist",
|
|
79
|
-
"typecheck": "tsc --noEmit",
|
|
80
|
-
"test": "vitest run",
|
|
81
|
-
"test:watch": "vitest"
|
|
82
83
|
}
|
|
83
|
-
}
|
|
84
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Noor ul Hassan
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|