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.
Files changed (3) hide show
  1. package/dist/index.js +119 -14
  2. package/package.json +11 -10
  3. 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 join2 } from "path";
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
- import { detectProject } from "@blockend/detector";
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 = [join2(cwd, "tsconfig.json"), join2(cwd, "jsconfig.json")];
514
+ const possiblePaths = [join7(cwd, "tsconfig.json"), join7(cwd, "jsconfig.json")];
409
515
  for (const configPath of possiblePaths) {
410
- if (existsSync(configPath)) {
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 = join2(cwd, "blockend.json");
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 (existsSync(configPath)) {
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 = existsSync(join2(cwd, "src"));
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 detectProject2(process.cwd());
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 join3 } from "path";
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 = join3(dir, filename);
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 join4 } from "path";
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 = join4(cwd, meta.relativePath);
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.1",
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.