@sandro-sikic/maker 1.0.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.
Files changed (2) hide show
  1. package/index.js +102 -0
  2. package/package.json +17 -0
package/index.js ADDED
@@ -0,0 +1,102 @@
1
+ const inquirer = require('inquirer');
2
+ const { spawn } = require('child_process');
3
+ const path = require('path');
4
+ const ora = require('ora');
5
+
6
+ function init() {
7
+ // Ensure we're running in an interactive terminal
8
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
9
+ console.error(
10
+ '\n️This TUI requires an interactive terminal. Run this in a terminal (not the Node REPL or a non-interactive/debug console).\n',
11
+ );
12
+ process.exit(1);
13
+ }
14
+ }
15
+
16
+ /**
17
+ * Run a shell command and stream output to the parent process while capturing the last N lines.
18
+ *
19
+ * Note: if you call `run(...)` without awaiting it (i.e. "run normally") it acts like a background
20
+ * task; if you `await run(...)` (use inside an async function) the caller will wait for completion
21
+ * and the call behaves like a foreground task.
22
+ *
23
+ * @param {string} command - Shell command to execute (will be run with `shell: true`).
24
+ * @param {Object} [opts]
25
+ * @param {number} [opts.maxLines=10000] - Maximum number of lines to retain in captured output.
26
+ * @returns {Promise<{output:string, stdout:string, stderr:string, code:number|null, isError:boolean, error:Error|null}>}
27
+ */
28
+ function run(command, opts = {}) {
29
+ const { maxLines = 10000 } = opts;
30
+ const normalized = path.normalize(command);
31
+ const split = normalized.split('/');
32
+ const convertedCommand = path.join(...split);
33
+
34
+ function trimToLastNLines(s, n) {
35
+ if (!s) return s;
36
+ const lines = s.split(/\r?\n/);
37
+ if (lines.length <= n) return s;
38
+ return lines.slice(-n).join('\n');
39
+ }
40
+
41
+ return new Promise((resolve) => {
42
+ const child = spawn(convertedCommand, { shell: true, stdio: 'pipe' });
43
+
44
+ let stdout = '';
45
+ let stderr = '';
46
+
47
+ // stream to parent stdout/stderr while also capturing (keep only last maxLines)
48
+ if (child.stdout) {
49
+ child.stdout.on('data', (chunk) => {
50
+ const s = chunk.toString();
51
+ stdout += s;
52
+ // trim if exceeded
53
+ if ((stdout.match(/\r?\n/g) || []).length > maxLines) {
54
+ stdout = trimToLastNLines(stdout, maxLines);
55
+ }
56
+ process.stdout.write(s);
57
+ });
58
+ }
59
+
60
+ if (child.stderr) {
61
+ child.stderr.on('data', (chunk) => {
62
+ const s = chunk.toString();
63
+ stderr += s;
64
+ if ((stderr.match(/\r?\n/g) || []).length > maxLines) {
65
+ stderr = trimToLastNLines(stderr, maxLines);
66
+ }
67
+ process.stderr.write(s);
68
+ });
69
+ }
70
+
71
+ child.on('error', (err) => {
72
+ // resolve with error info (non-throwing for convenience)
73
+ resolve({
74
+ output: stdout + stderr,
75
+ stdout,
76
+ stderr,
77
+ code: null,
78
+ isError: true,
79
+ error: err,
80
+ });
81
+ });
82
+
83
+ child.on('close', (code) => {
84
+ const isError = code !== 0;
85
+ resolve({
86
+ output: stdout + stderr,
87
+ stdout: trimToLastNLines(stdout, maxLines),
88
+ stderr: trimToLastNLines(stderr, maxLines),
89
+ code,
90
+ isError,
91
+ error: null,
92
+ });
93
+ });
94
+ });
95
+ }
96
+
97
+ module.exports = {
98
+ init,
99
+ run,
100
+ prompt: inquirer,
101
+ spinner: ora,
102
+ };
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@sandro-sikic/maker",
3
+ "version": "1.0.0",
4
+ "description": "A library to create dev cli",
5
+ "main": "index.js",
6
+ "author": "sandro-sikic",
7
+ "license": "ISC",
8
+ "dependencies": {
9
+ "@inquirer/prompts": "^8.2.0",
10
+ "ora": "^9.3.0"
11
+ },
12
+ "devDependencies": {
13
+ "archiver": "^5.3.1",
14
+ "pkg": "^5.8.1",
15
+ "rimraf": "^5.0.1"
16
+ }
17
+ }