create-nexora-next 0.1.0

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.
@@ -0,0 +1,50 @@
1
+ import { execSync } from 'child_process'
2
+
3
+ /**
4
+ * Run a shell command with live output, throwing on failure.
5
+ * @param {string} cmd
6
+ * @param {string} cwd
7
+ */
8
+ export function run(cmd, cwd) {
9
+ execSync(cmd, { cwd, stdio: 'inherit' })
10
+ }
11
+
12
+ /**
13
+ * Run silently, capturing output. Returns stdout string.
14
+ * @param {string} cmd
15
+ * @param {string} cwd
16
+ */
17
+ export function runSilent(cmd, cwd) {
18
+ return execSync(cmd, { cwd, stdio: 'pipe' }).toString().trim()
19
+ }
20
+
21
+ /**
22
+ * Returns the install command for the given package manager.
23
+ * @param {'npm'|'pnpm'|'bun'|'yarn'} pm
24
+ * @param {string[]} deps
25
+ * @param {boolean} dev
26
+ */
27
+ export function installCmd(pm, deps, dev = false) {
28
+ const flag = dev
29
+ ? pm === 'npm' ? '--save-dev' : '-D'
30
+ : ''
31
+ const pkgs = deps.join(' ')
32
+ switch (pm) {
33
+ case 'yarn': return `yarn add ${flag} ${pkgs}`.trim()
34
+ case 'pnpm': return `pnpm add ${flag} ${pkgs}`.trim()
35
+ case 'bun': return `bun add ${flag} ${pkgs}`.trim()
36
+ default: return `npm install ${flag} ${pkgs}`.trim()
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Returns the exec command (npx / pnpx / bunx).
42
+ * @param {'npm'|'pnpm'|'bun'|'yarn'} pm
43
+ */
44
+ export function execCmd(pm) {
45
+ switch (pm) {
46
+ case 'pnpm': return 'pnpx'
47
+ case 'bun': return 'bunx'
48
+ default: return 'npx'
49
+ }
50
+ }
@@ -0,0 +1,43 @@
1
+ import * as p from '@clack/prompts'
2
+ import pc from 'picocolors'
3
+
4
+ /**
5
+ * Wraps a step function with automatic retry-on-failure UX.
6
+ * If the step throws, shows the error, prompts "Fix it and press Enter to retry",
7
+ * and loops until success or the user cancels.
8
+ *
9
+ * @param {string} label Human-readable step name (shown in spinner)
10
+ * @param {()=>Promise<void>|void} fn The step to execute
11
+ */
12
+ export async function safeStep(label, fn) {
13
+ while (true) {
14
+ const spinner = p.spinner()
15
+ spinner.start(label)
16
+ try {
17
+ await fn()
18
+ spinner.stop(pc.green(`✓ ${label}`))
19
+ return
20
+ } catch (err) {
21
+ spinner.stop(pc.red(`✗ ${label} failed`))
22
+
23
+ const message = err?.message || String(err)
24
+ p.log.error(pc.red(message))
25
+ p.log.warn(
26
+ pc.yellow(
27
+ `Fix the issue above, then press ${pc.bold('Enter')} to retry — or Ctrl+C to abort.`,
28
+ ),
29
+ )
30
+
31
+ const retry = await p.confirm({
32
+ message: 'Ready to retry?',
33
+ initialValue: true,
34
+ })
35
+
36
+ if (p.isCancel(retry) || !retry) {
37
+ p.cancel('Setup aborted.')
38
+ process.exit(1)
39
+ }
40
+ // loop again
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,38 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+
4
+ /**
5
+ * Write content to a file, creating parent directories as needed.
6
+ * @param {string} filePath Absolute path
7
+ * @param {string} content
8
+ */
9
+ export function writeFile(filePath, content) {
10
+ fs.mkdirSync(path.dirname(filePath), { recursive: true })
11
+ fs.writeFileSync(filePath, content, 'utf8')
12
+ }
13
+
14
+ /**
15
+ * Append content to an existing file.
16
+ * @param {string} filePath Absolute path
17
+ * @param {string} content
18
+ */
19
+ export function appendFile(filePath, content) {
20
+ fs.appendFileSync(filePath, content, 'utf8')
21
+ }
22
+
23
+ /**
24
+ * Create a directory (and all parents) if it doesn't exist.
25
+ * @param {string} dirPath Absolute path
26
+ */
27
+ export function mkdir(dirPath) {
28
+ fs.mkdirSync(dirPath, { recursive: true })
29
+ }
30
+
31
+ /**
32
+ * Check whether a path exists.
33
+ * @param {string} p
34
+ * @returns {boolean}
35
+ */
36
+ export function exists(p) {
37
+ return fs.existsSync(p)
38
+ }