@drawcall/create 0.2.0 → 0.2.1
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.
- package/dist/shell.js +34 -6
- package/package.json +1 -1
package/dist/shell.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import { createInterface } from "node:readline";
|
|
3
2
|
import { delimiter, dirname, join, resolve } from "node:path";
|
|
4
3
|
import which from "which";
|
|
5
4
|
import { Context, Effect, Layer } from "effect";
|
|
@@ -64,16 +63,43 @@ const live = (env, logger) => ({
|
|
|
64
63
|
env: buildSubprocessEnv(cwd, env),
|
|
65
64
|
stdio: ["ignore", "pipe", "pipe"]
|
|
66
65
|
});
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
const onLine = (line) => {
|
|
67
|
+
captured.push(line);
|
|
68
|
+
Effect.runSync(logger.captured(line));
|
|
69
|
+
};
|
|
70
|
+
// Capture per stream, collapsing carriage-return redraws to their final frame: a harness
|
|
71
|
+
// progress spinner ("⠧ Processing 16m") rewrites one line with \r thousands of times, which
|
|
72
|
+
// would otherwise flood the log and bury real events. Emitting only on \n (a \r resets the
|
|
73
|
+
// line buffer) keeps each line whole and turns a slow step into a visible time gap between
|
|
74
|
+
// log lines instead of spinner spam. Real output lines are unaffected.
|
|
75
|
+
const flushers = [];
|
|
69
76
|
for (const stream of [child.stdout, child.stderr]) {
|
|
70
77
|
if (!stream)
|
|
71
78
|
continue;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
let pending = "";
|
|
80
|
+
stream.setEncoding("utf8");
|
|
81
|
+
stream.on("data", (chunk) => {
|
|
82
|
+
for (const ch of chunk) {
|
|
83
|
+
if (ch === "\n") {
|
|
84
|
+
onLine(pending);
|
|
85
|
+
pending = "";
|
|
86
|
+
}
|
|
87
|
+
else if (ch === "\r") {
|
|
88
|
+
pending = "";
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
pending += ch;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
flushers.push(() => {
|
|
96
|
+
if (pending.length > 0) {
|
|
97
|
+
onLine(pending);
|
|
98
|
+
pending = "";
|
|
99
|
+
}
|
|
75
100
|
});
|
|
76
101
|
}
|
|
102
|
+
const flushStreams = () => flushers.forEach((flush) => flush());
|
|
77
103
|
let timedOut = false;
|
|
78
104
|
let killTimer;
|
|
79
105
|
const timeout = timeoutMs === undefined
|
|
@@ -92,6 +118,7 @@ const live = (env, logger) => ({
|
|
|
92
118
|
};
|
|
93
119
|
child.once("error", (error) => {
|
|
94
120
|
cleanup();
|
|
121
|
+
flushStreams();
|
|
95
122
|
// spawn failed (command not found, etc.): surface as a non-zero exit with the error text so
|
|
96
123
|
// the caller can classify it like any other failure.
|
|
97
124
|
captured.push(String(error.message ?? error));
|
|
@@ -99,6 +126,7 @@ const live = (env, logger) => ({
|
|
|
99
126
|
});
|
|
100
127
|
child.once("exit", (code, signal) => {
|
|
101
128
|
cleanup();
|
|
129
|
+
flushStreams();
|
|
102
130
|
const exitCode = timedOut ? TIMEOUT_EXIT_CODE : signal ? 1 : (code ?? 1);
|
|
103
131
|
const elapsed = Math.round((Date.now() - startedAt) / 1000);
|
|
104
132
|
const failure = !timedOut && exitCode !== 0 ? ` — exit ${exitCode}` : "";
|