trx 1.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.
Files changed (2) hide show
  1. package/package.json +12 -0
  2. package/trx.js +154 -0
package/package.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "trx",
3
+ "version": "1.1.0",
4
+ "description": "",
5
+ "license": "ISC",
6
+ "author": "",
7
+ "type": "commonjs",
8
+ "main": "trx.js",
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ }
12
+ }
package/trx.js ADDED
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn } = require("child_process");
4
+ const process = require("process");
5
+
6
+ /* ─────────────── COLORS ─────────────── */
7
+
8
+ const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
9
+
10
+ const C = useColor ? {
11
+ reset: "\x1b[0m",
12
+ dim: "\x1b[2m",
13
+ bold: "\x1b[1m",
14
+
15
+ red: "\x1b[31m",
16
+ brightRed: "\x1b[91m",
17
+ green: "\x1b[32m",
18
+ yellow: "\x1b[33m",
19
+ blue: "\x1b[34m",
20
+ magenta: "\x1b[35m",
21
+ cyan: "\x1b[36m",
22
+ gray: "\x1b[90m",
23
+
24
+ PROC: "\x1b[36m",
25
+ OUT: "\x1b[90m",
26
+ ERR: "\x1b[31m",
27
+ TIME: "\x1b[35m",
28
+ OK: "\x1b[32m",
29
+ FAIL: "\x1b[91m"
30
+ } : Object.fromEntries(
31
+ ["reset","dim","bold","red","brightRed","green","yellow","blue","magenta","cyan","gray",
32
+ "PROC","OUT","ERR","TIME","OK","FAIL"].map(k => [k, ""])
33
+ );
34
+
35
+ /* ─────────────── UTILS ─────────────── */
36
+
37
+ const now = () =>
38
+ new Date().toISOString().split("T")[1].replace("Z", "");
39
+
40
+ function formatElapsed(sec) {
41
+ if (sec < 60) return `${sec}s`;
42
+ const m = Math.floor(sec / 60);
43
+ const s = sec % 60;
44
+ return `${m}m ${s}s`;
45
+ }
46
+
47
+ function banner(cmd) {
48
+ console.log(`
49
+ ${C.cyan}${C.bold}┌─[ TERMTTRACE ]────────────────────────────────────────┐${C.reset}
50
+ ${C.cyan}│${C.reset} ${C.gray}Command:${C.reset} ${C.bold}${cmd}${C.reset}
51
+ ${C.cyan}└────────────────────────────────────────────────────────┘${C.reset}
52
+ `.trim());
53
+ }
54
+
55
+ function log(type, icon, message) {
56
+ clearSpinner();
57
+ console.log(
58
+ `${C.dim}[${now()}]${C.reset} ${C[type]}${icon} ${message}${C.reset}`
59
+ );
60
+ }
61
+
62
+ function die(msg) {
63
+ console.error(`${C.FAIL}${msg}${C.reset}`);
64
+ process.exit(1);
65
+ }
66
+
67
+ /* ─────────────── SPINNER ─────────────── */
68
+
69
+ const frames = ["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];
70
+ let spinnerIndex = 0;
71
+ let spinnerTimer = null;
72
+ let startTime = null;
73
+
74
+ function startSpinner() {
75
+ startTime = Date.now();
76
+ spinnerTimer = setInterval(() => {
77
+ const elapsedSec = Math.floor((Date.now() - startTime) / 1000);
78
+ const frame = frames[spinnerIndex++ % frames.length];
79
+ const time = formatElapsed(elapsedSec);
80
+
81
+ process.stdout.write(
82
+ `\r${C.cyan}${frame}${C.reset} ${C.gray}running…${C.reset} ${C.magenta}${time}${C.reset} `
83
+ );
84
+ }, 120);
85
+ }
86
+
87
+ function clearSpinner() {
88
+ if (spinnerTimer) {
89
+ clearInterval(spinnerTimer);
90
+ spinnerTimer = null;
91
+ process.stdout.write("\r\x1b[2K");
92
+ }
93
+ }
94
+
95
+ /* ─────────────── ARGUMENTS ─────────────── */
96
+
97
+ const args = process.argv.slice(2);
98
+ if (!args.length) {
99
+ die("Usage: termtrace <command> [args...]");
100
+ }
101
+
102
+ const command = args.join(" ");
103
+
104
+ /* ─────────────── EXECUTION ─────────────── */
105
+
106
+ banner(command);
107
+ log("PROC", "⚡", "process spawned");
108
+
109
+ startSpinner();
110
+
111
+ const child = spawn(command, {
112
+ stdio: ["inherit", "pipe", "pipe"],
113
+ shell: true
114
+ });
115
+
116
+ child.stdout.on("data", (data) => {
117
+ data
118
+ .toString()
119
+ .split("\n")
120
+ .filter(Boolean)
121
+ .forEach(line => log("OUT", "›", line));
122
+ });
123
+
124
+ child.stderr.on("data", (data) => {
125
+ data
126
+ .toString()
127
+ .split("\n")
128
+ .filter(Boolean)
129
+ .forEach(line => log("ERR", "✖", line));
130
+ });
131
+
132
+ child.on("exit", (code, signal) => {
133
+ clearSpinner();
134
+
135
+ const elapsedSec = Math.floor((Date.now() - startTime) / 1000);
136
+ const elapsed = formatElapsed(elapsedSec);
137
+
138
+ if (signal) {
139
+ log("FAIL", "☠", `killed by signal ${signal}`);
140
+ } else if (code === 0) {
141
+ log("OK", "✔", "process completed successfully");
142
+ } else {
143
+ log("FAIL", "✖", `exit code ${code}`);
144
+ }
145
+
146
+ log("TIME", "⏱", `total time ${elapsed}`);
147
+ process.exit(code ?? 1);
148
+ });
149
+
150
+ child.on("error", (err) => {
151
+ clearSpinner();
152
+ log("FAIL", "☠", err.message);
153
+ process.exit(1);
154
+ });