feat: init 15673be7
Steve · 2025-04-26 20:39 4 file(s) · +438 −0
.gitignore (added) +41 −0
1 +
# bhvr/.gitignore
2 +
# dependencies
3 +
node_modules
4 +
.pnp
5 +
.pnp.js
6 +
7 +
# testing
8 +
coverage
9 +
10 +
# production
11 +
dist
12 +
build
13 +
14 +
# misc
15 +
.DS_Store
16 +
.env
17 +
.env.local
18 +
.env.development.local
19 +
.env.test.local
20 +
.env.production.local
21 +
.env*.local
22 +
23 +
# logs
24 +
npm-debug.log*
25 +
yarn-debug.log*
26 +
yarn-error.log*
27 +
pnpm-debug.log*
28 +
29 +
# editor directories and files
30 +
.idea
31 +
.vscode/*
32 +
!.vscode/extensions.json
33 +
!.vscode/settings.json
34 +
*.suo
35 +
*.ntvs*
36 +
*.njsproj
37 +
*.sln
38 +
*.sw?
39 +
40 +
# Bun
41 +
bun.lockb
bun.lock (added) +120 −0
1 +
{
2 +
  "lockfileVersion": 1,
3 +
  "workspaces": {
4 +
    "": {
5 +
      "name": "create-bhvr",
6 +
      "dependencies": {
7 +
        "chalk": "^5.3.0",
8 +
        "commander": "^11.1.0",
9 +
        "degit": "^2.8.4",
10 +
        "execa": "^7.1.1",
11 +
        "fs-extra": "^11.2.0",
12 +
        "ora": "^6.3.1",
13 +
        "prompts": "^2.4.2",
14 +
      },
15 +
    },
16 +
  },
17 +
  "packages": {
18 +
    "ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
19 +
20 +
    "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
21 +
22 +
    "bl": ["bl@5.1.0", "", { "dependencies": { "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ=="],
23 +
24 +
    "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
25 +
26 +
    "chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
27 +
28 +
    "cli-cursor": ["cli-cursor@4.0.0", "", { "dependencies": { "restore-cursor": "^4.0.0" } }, "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg=="],
29 +
30 +
    "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="],
31 +
32 +
    "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="],
33 +
34 +
    "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="],
35 +
36 +
    "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
37 +
38 +
    "defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="],
39 +
40 +
    "degit": ["degit@2.8.4", "", { "bin": { "degit": "degit" } }, "sha512-vqYuzmSA5I50J882jd+AbAhQtgK6bdKUJIex1JNfEUPENCgYsxugzKVZlFyMwV4i06MmnV47/Iqi5Io86zf3Ng=="],
41 +
42 +
    "execa": ["execa@7.2.0", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", "human-signals": "^4.3.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^3.0.7", "strip-final-newline": "^3.0.0" } }, "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA=="],
43 +
44 +
    "fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="],
45 +
46 +
    "get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="],
47 +
48 +
    "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
49 +
50 +
    "human-signals": ["human-signals@4.3.1", "", {}, "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ=="],
51 +
52 +
    "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
53 +
54 +
    "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
55 +
56 +
    "is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="],
57 +
58 +
    "is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
59 +
60 +
    "is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="],
61 +
62 +
    "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
63 +
64 +
    "jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="],
65 +
66 +
    "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
67 +
68 +
    "log-symbols": ["log-symbols@5.1.0", "", { "dependencies": { "chalk": "^5.0.0", "is-unicode-supported": "^1.1.0" } }, "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA=="],
69 +
70 +
    "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
71 +
72 +
    "mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
73 +
74 +
    "npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
75 +
76 +
    "onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="],
77 +
78 +
    "ora": ["ora@6.3.1", "", { "dependencies": { "chalk": "^5.0.0", "cli-cursor": "^4.0.0", "cli-spinners": "^2.6.1", "is-interactive": "^2.0.0", "is-unicode-supported": "^1.1.0", "log-symbols": "^5.1.0", "stdin-discarder": "^0.1.0", "strip-ansi": "^7.0.1", "wcwidth": "^1.0.1" } }, "sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ=="],
79 +
80 +
    "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
81 +
82 +
    "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
83 +
84 +
    "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
85 +
86 +
    "restore-cursor": ["restore-cursor@4.0.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg=="],
87 +
88 +
    "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
89 +
90 +
    "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
91 +
92 +
    "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
93 +
94 +
    "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
95 +
96 +
    "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
97 +
98 +
    "stdin-discarder": ["stdin-discarder@0.1.0", "", { "dependencies": { "bl": "^5.0.0" } }, "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ=="],
99 +
100 +
    "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
101 +
102 +
    "strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
103 +
104 +
    "strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
105 +
106 +
    "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="],
107 +
108 +
    "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
109 +
110 +
    "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="],
111 +
112 +
    "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
113 +
114 +
    "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
115 +
116 +
    "restore-cursor/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
117 +
118 +
    "restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
119 +
  }
120 +
}
index.js (added) +237 −0
1 +
#!/usr/bin/env node
2 +
3 +
import fs from 'fs-extra';
4 +
import path from 'path';
5 +
import { fileURLToPath } from 'url';
6 +
import prompts from 'prompts';
7 +
import { program } from 'commander';
8 +
import chalk from 'chalk';
9 +
import ora from 'ora';
10 +
import { execa } from 'execa';
11 +
import degit from 'degit';
12 +
13 +
const __filename = fileURLToPath(import.meta.url);
14 +
const __dirname = path.dirname(__filename);
15 +
16 +
// GitHub repository for the template
17 +
const DEFAULT_REPO = 'stevedylandev/bhvr'; // Replace with your actual repo
18 +
19 +
// Set up the CLI program
20 +
program
21 +
  .name('create-bhvr')
22 +
  .description('Create a bhvr monorepo starter project')
23 +
  .argument('[project-directory]', 'directory to create the project in')
24 +
  .option('-y, --yes', 'skip confirmation prompts')
25 +
  .option('--ts, --typescript', 'use TypeScript (default)')
26 +
  .option('--repo <repo>', 'specify a custom GitHub repository as source', DEFAULT_REPO)
27 +
  .option('--branch <branch>', 'specify a branch to use from the repository', 'main')
28 +
  .action(async (projectDirectory, options) => {
29 +
    try {
30 +
      const result = await createProject(projectDirectory, options);
31 +
      if (result) {
32 +
        console.log(chalk.green.bold('\n🎉 Project created successfully!'));
33 +
        console.log('\nNext steps:');
34 +
35 +
        if (!result.dependenciesInstalled) {
36 +
          console.log(chalk.cyan(`  cd ${result.projectName}`));
37 +
          console.log(chalk.cyan('  bun install'));
38 +
        } else {
39 +
          console.log(chalk.cyan(`  cd ${result.projectName}`));
40 +
        }
41 +
42 +
        console.log(chalk.cyan('  bun run dev:client   # Start the client'));
43 +
        console.log(chalk.cyan('  bun run dev:server   # Start the server in another terminal'));
44 +
        return
45 +
      }
46 +
    } catch (err) {
47 +
      console.error(chalk.red('Error creating project:'), err);
48 +
      process.exit(1);
49 +
    }
50 +
  });
51 +
52 +
program.parse();
53 +
54 +
async function createProject(projectDirectory, options) {
55 +
  // If project directory not provided, prompt for it
56 +
  let projectName = projectDirectory;
57 +
58 +
  if (!projectName && !options.yes) {
59 +
    const response = await prompts({
60 +
      type: 'text',
61 +
      name: 'projectName',
62 +
      message: 'What is the name of your project?',
63 +
      initial: 'my-bhvr-app'
64 +
    });
65 +
66 +
    if (!response.projectName) {
67 +
      console.log(chalk.yellow('Project creation cancelled.'));
68 +
      return null;
69 +
    }
70 +
71 +
    projectName = response.projectName;
72 +
  } else if (!projectName) {
73 +
    projectName = 'my-bhvr-app';
74 +
  }
75 +
76 +
  // Create the project directory
77 +
  const projectPath = path.resolve(process.cwd(), projectName);
78 +
79 +
  // Check if directory exists and is not empty
80 +
  if (fs.existsSync(projectPath)) {
81 +
    const files = fs.readdirSync(projectPath);
82 +
83 +
    if (files.length > 0 && !options.yes) {
84 +
      const { overwrite } = await prompts({
85 +
        type: 'confirm',
86 +
        name: 'overwrite',
87 +
        message: `The directory ${projectName} already exists and is not empty. Do you want to overwrite it?`,
88 +
        initial: false
89 +
      });
90 +
91 +
      if (!overwrite) {
92 +
        console.log(chalk.yellow('Project creation cancelled.'));
93 +
        return null;
94 +
      }
95 +
96 +
      // Clear directory if overwriting
97 +
      await fs.emptyDir(projectPath);
98 +
    }
99 +
  }
100 +
101 +
  // Create directory if it doesn't exist
102 +
  fs.ensureDirSync(projectPath);
103 +
104 +
  // Clone template from GitHub
105 +
  const repoPath = options.repo || DEFAULT_REPO;
106 +
  const branchSpecifier = options.branch ? `#${options.branch}` : '';
107 +
  const repoUrl = `${repoPath}${branchSpecifier}`;
108 +
109 +
  //console.log(chalk.blue(`\nCreating a new bhvr project in ${chalk.bold(projectPath)}`));
110 +
  //console.log(chalk.blue(`Downloading template from ${chalk.bold(repoUrl)}...`));
111 +
112 +
  const spinner = ora('Downloading template...').start();
113 +
114 +
  try {
115 +
    const emitter = degit(repoUrl, {
116 +
      cache: false,
117 +
      force: true,
118 +
      verbose: false,
119 +
    });
120 +
121 +
    await emitter.clone(projectPath);
122 +
    spinner.succeed('Template downloaded successfully');
123 +
124 +
    // Update package.json with project name
125 +
    const pkgJsonPath = path.join(projectPath, 'package.json');
126 +
    if (fs.existsSync(pkgJsonPath)) {
127 +
      const pkgJson = await fs.readJson(pkgJsonPath);
128 +
      pkgJson.name = projectName;
129 +
      await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
130 +
      console.log(chalk.blue('Updated package.json with project name'));
131 +
    }
132 +
133 +
    // Remove the .git directory if it exists
134 +
    const gitDir = path.join(projectPath, '.git');
135 +
    if (fs.existsSync(gitDir)) {
136 +
      await fs.remove(gitDir);
137 +
      console.log(chalk.blue('Removed .git directory'));
138 +
    }
139 +
140 +
    // Initialize git repository?
141 +
    let gitInitialized = false;
142 +
143 +
    if (!options.yes) {
144 +
      const gitResponse = await prompts({
145 +
        type: 'confirm',
146 +
        name: 'initGit',
147 +
        message: 'Initialize a git repository?',
148 +
        initial: true
149 +
      });
150 +
151 +
      if (gitResponse.initGit) {
152 +
        try {
153 +
          spinner.start('Initializing git repository...');
154 +
          await execa('git', ['init'], { cwd: projectPath });
155 +
          await execa('git', ['add', '.'], { cwd: projectPath });
156 +
          await execa('git', ['commit', '-m', 'Initial commit from create-bhvr'], { cwd: projectPath });
157 +
          spinner.succeed('Git repository initialized');
158 +
          gitInitialized = true;
159 +
        } catch (err) {
160 +
          spinner.fail('Failed to initialize git repository. Is git installed?');
161 +
          console.error(chalk.red('Git error:'), err.message);
162 +
        }
163 +
      }
164 +
    } else {
165 +
      // If using --yes, automatically initialize git
166 +
      try {
167 +
        spinner.start('Initializing git repository...');
168 +
        await execa('git', ['init'], { cwd: projectPath });
169 +
        await execa('git', ['add', '.'], { cwd: projectPath });
170 +
        await execa('git', ['commit', '-m', 'Initial commit from create-bhvr'], { cwd: projectPath });
171 +
        spinner.succeed('Git repository initialized');
172 +
        gitInitialized = true;
173 +
      } catch (err) {
174 +
        spinner.fail('Failed to initialize git repository. Is git installed?');
175 +
      }
176 +
    }
177 +
178 +
    // Install dependencies?
179 +
    let dependenciesInstalled = false;
180 +
181 +
    if (!options.yes) {
182 +
      const depsResponse = await prompts({
183 +
        type: 'confirm',
184 +
        name: 'installDeps',
185 +
        message: 'Install dependencies?',
186 +
        initial: true
187 +
      });
188 +
189 +
      if (depsResponse.installDeps) {
190 +
        spinner.start('Installing dependencies...');
191 +
        try {
192 +
          // Try with bun first
193 +
          await execa('bun', ['install'], { cwd: projectPath });
194 +
          spinner.succeed('Dependencies installed with bun');
195 +
          dependenciesInstalled = true;
196 +
        } catch (bunErr) {
197 +
          // If bun fails, try with npm
198 +
          try {
199 +
            spinner.text = 'Installing dependencies with npm...';
200 +
            await execa('npm', ['install'], { cwd: projectPath });
201 +
            spinner.succeed('Dependencies installed with npm');
202 +
            dependenciesInstalled = true;
203 +
          } catch (npmErr) {
204 +
            spinner.fail('Failed to install dependencies.');
205 +
            console.log(chalk.yellow('You can install them manually after navigating to the project directory.'));
206 +
          }
207 +
        }
208 +
      }
209 +
    } else {
210 +
      // If using --yes, automatically install dependencies
211 +
      spinner.start('Installing dependencies...');
212 +
      try {
213 +
        await execa('bun', ['install'], { cwd: projectPath });
214 +
        spinner.succeed('Dependencies installed with bun');
215 +
        dependenciesInstalled = true;
216 +
      } catch (bunErr) {
217 +
        try {
218 +
          spinner.text = 'Installing dependencies with npm...';
219 +
          await execa('npm', ['install'], { cwd: projectPath });
220 +
          spinner.succeed('Dependencies installed with npm');
221 +
          dependenciesInstalled = true;
222 +
        } catch (npmErr) {
223 +
          spinner.fail('Failed to install dependencies. You can install them manually later.');
224 +
        }
225 +
      }
226 +
    }
227 +
228 +
    return {
229 +
      projectName,
230 +
      gitInitialized,
231 +
      dependenciesInstalled
232 +
    };
233 +
  } catch (err) {
234 +
    spinner.fail('Failed to download template');
235 +
    throw err;
236 +
  }
237 +
}
package.json (added) +40 −0
1 +
{
2 +
  "name": "create-bhvr",
3 +
  "version": "0.0.5",
4 +
  "description": "Create a new bhvr monorepo starter project",
5 +
  "main": "index.js",
6 +
  "type": "module",
7 +
  "bin": {
8 +
    "create-vrhb": "index.js"
9 +
  },
10 +
  "files": [
11 +
    "index.js"
12 +
  ],
13 +
  "scripts": {
14 +
    "test": "echo \"Error: no test specified\" && exit 1"
15 +
  },
16 +
  "keywords": [
17 +
    "bun",
18 +
    "vite",
19 +
    "react",
20 +
    "hono",
21 +
    "monorepo",
22 +
    "starter",
23 +
    "template",
24 +
    "create"
25 +
  ],
26 +
  "author": "Steve Simkins",
27 +
  "license": "MIT",
28 +
  "dependencies": {
29 +
    "chalk": "^5.3.0",
30 +
    "commander": "^11.1.0",
31 +
    "fs-extra": "^11.2.0",
32 +
    "prompts": "^2.4.2",
33 +
    "degit": "^2.8.4",
34 +
    "ora": "^6.3.1",
35 +
    "execa": "^7.1.1"
36 +
  },
37 +
  "engines": {
38 +
    "node": ">=14.16"
39 +
  }
40 +
}