noninteractive 0.3.26 → 0.3.30
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/bin/noninteractive.js +66 -16
- package/package.json +1 -1
package/bin/noninteractive.js
CHANGED
|
@@ -172,11 +172,14 @@ function runDaemon(sessionName, executable, args) {
|
|
|
172
172
|
let outputBuffer = "";
|
|
173
173
|
let processExited = false;
|
|
174
174
|
let exitCode = null;
|
|
175
|
+
let lastReadLength = 0;
|
|
175
176
|
const detectedUrls = new Set;
|
|
176
177
|
const reportedUrls = new Set;
|
|
177
178
|
const waiters = [];
|
|
178
179
|
let notifyDebounce = null;
|
|
179
180
|
const NOTIFY_SETTLE_MS = 50;
|
|
181
|
+
let lastStdinWrite = 0;
|
|
182
|
+
const INPUT_SETTLE_MS = 150;
|
|
180
183
|
function notifyWaiters() {
|
|
181
184
|
if (waiters.length === 0)
|
|
182
185
|
return;
|
|
@@ -282,14 +285,17 @@ function runDaemon(sessionName, executable, args) {
|
|
|
282
285
|
} catch {}
|
|
283
286
|
});
|
|
284
287
|
});
|
|
285
|
-
function respondWithOutput(socket) {
|
|
288
|
+
function respondWithOutput(socket, updateSnapshot = true) {
|
|
286
289
|
readInterceptedUrls();
|
|
290
|
+
if (updateSnapshot)
|
|
291
|
+
lastReadLength = outputBuffer.length;
|
|
287
292
|
const newUrls = Array.from(detectedUrls).filter((u) => !reportedUrls.has(u));
|
|
288
293
|
for (const u of newUrls)
|
|
289
294
|
reportedUrls.add(u);
|
|
290
295
|
socket.end(JSON.stringify({
|
|
291
296
|
ok: true,
|
|
292
297
|
output: outputBuffer,
|
|
298
|
+
outputLength: outputBuffer.length,
|
|
293
299
|
exited: processExited,
|
|
294
300
|
exitCode,
|
|
295
301
|
...newUrls.length > 0 ? { urls: newUrls } : {}
|
|
@@ -311,12 +317,26 @@ function runDaemon(sessionName, executable, args) {
|
|
|
311
317
|
};
|
|
312
318
|
waiters.push(waiter);
|
|
313
319
|
}
|
|
320
|
+
function writeToStdin(data) {
|
|
321
|
+
lastStdinWrite = Date.now();
|
|
322
|
+
stdin?.write(data);
|
|
323
|
+
}
|
|
324
|
+
function withSettleDelay(fn) {
|
|
325
|
+
const now = Date.now();
|
|
326
|
+
const elapsed = now - lastStdinWrite;
|
|
327
|
+
const delay = Math.max(0, INPUT_SETTLE_MS - elapsed);
|
|
328
|
+
if (delay > 0) {
|
|
329
|
+
setTimeout(fn, delay);
|
|
330
|
+
} else {
|
|
331
|
+
fn();
|
|
332
|
+
}
|
|
333
|
+
}
|
|
314
334
|
function handle(msg, socket) {
|
|
315
335
|
switch (msg.action) {
|
|
316
336
|
case "read":
|
|
317
337
|
if (msg.wait) {
|
|
318
338
|
const timeout = msg.timeout ?? 30000;
|
|
319
|
-
waitForNewOutput(socket,
|
|
339
|
+
waitForNewOutput(socket, lastReadLength, timeout);
|
|
320
340
|
} else {
|
|
321
341
|
respondWithOutput(socket);
|
|
322
342
|
}
|
|
@@ -326,8 +346,11 @@ function runDaemon(sessionName, executable, args) {
|
|
|
326
346
|
socket.end(JSON.stringify({ ok: false, error: "process exited" }));
|
|
327
347
|
break;
|
|
328
348
|
}
|
|
329
|
-
|
|
330
|
-
|
|
349
|
+
withSettleDelay(() => {
|
|
350
|
+
writeToStdin(msg.data);
|
|
351
|
+
lastReadLength = outputBuffer.length;
|
|
352
|
+
socket.end(JSON.stringify({ ok: true }));
|
|
353
|
+
});
|
|
331
354
|
break;
|
|
332
355
|
case "sendread": {
|
|
333
356
|
if (processExited) {
|
|
@@ -336,8 +359,10 @@ function runDaemon(sessionName, executable, args) {
|
|
|
336
359
|
}
|
|
337
360
|
const beforeLength = outputBuffer.length;
|
|
338
361
|
const timeout = msg.timeout ?? 30000;
|
|
339
|
-
|
|
340
|
-
|
|
362
|
+
withSettleDelay(() => {
|
|
363
|
+
writeToStdin(msg.data);
|
|
364
|
+
waitForNewOutput(socket, beforeLength, timeout);
|
|
365
|
+
});
|
|
341
366
|
break;
|
|
342
367
|
}
|
|
343
368
|
case "stop":
|
|
@@ -379,7 +404,7 @@ var init_daemon = __esm(() => {
|
|
|
379
404
|
var require_package = __commonJS((exports, module) => {
|
|
380
405
|
module.exports = {
|
|
381
406
|
name: "noninteractive",
|
|
382
|
-
version: "0.3.
|
|
407
|
+
version: "0.3.30",
|
|
383
408
|
type: "module",
|
|
384
409
|
bin: {
|
|
385
410
|
noninteractive: "./bin/noninteractive.js"
|
|
@@ -509,6 +534,9 @@ more examples:
|
|
|
509
534
|
npx noninteractive supabase init # session "supabase"
|
|
510
535
|
npx noninteractive start vercel login # explicit start for non-npx commands`;
|
|
511
536
|
function stripAnsi(s) {
|
|
537
|
+
const lastClear = Math.max(s.lastIndexOf("\x1B[2J"), s.lastIndexOf("\x1B[H\x1B[2J"));
|
|
538
|
+
if (lastClear !== -1)
|
|
539
|
+
s = s.slice(lastClear);
|
|
512
540
|
s = s.replace(/\x1b\[[012]?K/g, `
|
|
513
541
|
`);
|
|
514
542
|
let result = "";
|
|
@@ -700,12 +728,13 @@ make sure the command exists. examples:`);
|
|
|
700
728
|
console.error(` npx noninteractive start vercel login # run a command directly`);
|
|
701
729
|
process.exit(1);
|
|
702
730
|
}
|
|
703
|
-
|
|
731
|
+
const stripSpinners = (s) => s.replace(/[\u280B\u2819\u2839\u2838\u283C\u2834\u2826\u2827\u2807\u280F\u281B\u2833\u281E\u283D\u283B\u283F\u283E\u2837\u282F\u281F]/g, "").trim();
|
|
732
|
+
for (let i = 0;i < 150; i++) {
|
|
704
733
|
await new Promise((r) => setTimeout(r, 200));
|
|
705
734
|
try {
|
|
706
735
|
const res = await sendMessage(sock, { action: "read" });
|
|
707
736
|
handleUrls(res, noOpen);
|
|
708
|
-
const clean = stripAnsi(res.output ?? "")
|
|
737
|
+
const clean = stripSpinners(stripAnsi(res.output ?? ""));
|
|
709
738
|
if (clean.length > 10) {
|
|
710
739
|
process.stdout.write(stripAnsi(res.output));
|
|
711
740
|
if (res.exited) {
|
|
@@ -717,8 +746,8 @@ make sure the command exists. examples:`);
|
|
|
717
746
|
} else {
|
|
718
747
|
console.log(`
|
|
719
748
|
[session '${name}' started \u2014 read the output above, then use:]`);
|
|
720
|
-
console.log(` npx noninteractive send ${name} "<text>"
|
|
721
|
-
console.log(` npx noninteractive read ${name} --wait # wait for
|
|
749
|
+
console.log(` npx noninteractive send ${name} "<text>" # send and get response (waits by default)`);
|
|
750
|
+
console.log(` npx noninteractive read ${name} --wait # wait for NEW output (no sleep needed)`);
|
|
722
751
|
console.log(` npx noninteractive stop ${name} # stop the session`);
|
|
723
752
|
}
|
|
724
753
|
return;
|
|
@@ -735,8 +764,8 @@ make sure the command exists. examples:`);
|
|
|
735
764
|
} catch {}
|
|
736
765
|
}
|
|
737
766
|
console.log(`[session '${name}' started but no output yet \u2014 use:]`);
|
|
738
|
-
console.log(` npx noninteractive send ${name} "<text>"
|
|
739
|
-
console.log(` npx noninteractive read ${name} --wait # wait for
|
|
767
|
+
console.log(` npx noninteractive send ${name} "<text>" # send and get response (waits by default)`);
|
|
768
|
+
console.log(` npx noninteractive read ${name} --wait # wait for NEW output (no sleep needed)`);
|
|
740
769
|
console.log(` npx noninteractive stop ${name} # stop the session`);
|
|
741
770
|
}
|
|
742
771
|
async function read(name, wait, timeout, noOpen = false) {
|
|
@@ -780,9 +809,11 @@ async function send(name, text, wait, timeout, noOpen = false) {
|
|
|
780
809
|
if (res.output !== undefined)
|
|
781
810
|
process.stdout.write(stripAnsi(res.output));
|
|
782
811
|
handleUrls(res, noOpen);
|
|
783
|
-
if (res.exited)
|
|
812
|
+
if (res.exited) {
|
|
784
813
|
console.log(`
|
|
785
814
|
[exited ${res.exitCode}]`);
|
|
815
|
+
console.log(`[session complete \u2014 output above is final, no need to read again]`);
|
|
816
|
+
}
|
|
786
817
|
} else {
|
|
787
818
|
await sendMessage(sock, { action: "send", data: text });
|
|
788
819
|
console.log(`[sent to '${name}' \u2014 run "npx noninteractive read ${name}" to see the result]`);
|
|
@@ -848,7 +879,23 @@ async function main() {
|
|
|
848
879
|
cwd = startArgs[cwdIdx + 1];
|
|
849
880
|
startArgs.splice(cwdIdx, 2);
|
|
850
881
|
}
|
|
851
|
-
|
|
882
|
+
if (startArgs.includes("--")) {
|
|
883
|
+
console.error(`hint: the -- separator is not needed. just put the command after the flags.`);
|
|
884
|
+
}
|
|
885
|
+
const filtered = startArgs.filter((a) => a !== "--no-open" && a !== "--");
|
|
886
|
+
if (filtered.includes("--help") || filtered.includes("-h")) {
|
|
887
|
+
console.log(`usage: noninteractive start [--name <session>] [--cwd <dir>] <cmd> [args...]
|
|
888
|
+
|
|
889
|
+
examples:
|
|
890
|
+
npx noninteractive start npx eslint --init
|
|
891
|
+
npx noninteractive start --name myeslint --cwd /tmp/project npx eslint --init
|
|
892
|
+
npx noninteractive start node server.js
|
|
893
|
+
|
|
894
|
+
flags:
|
|
895
|
+
--name <session> set session name (default: auto-derived from command)
|
|
896
|
+
--cwd <dir> set working directory for the command`);
|
|
897
|
+
process.exit(0);
|
|
898
|
+
}
|
|
852
899
|
if (filtered.length < 1) {
|
|
853
900
|
console.error(`usage: noninteractive start [--name <session>] [--cwd <dir>] <cmd> [args...]
|
|
854
901
|
|
|
@@ -943,8 +990,11 @@ example: npx noninteractive stop vercel`);
|
|
|
943
990
|
hint: use --name for session name, --cwd for working directory.`);
|
|
944
991
|
process.exit(1);
|
|
945
992
|
}
|
|
993
|
+
if (mutableArgs.includes("--")) {
|
|
994
|
+
console.error(`hint: the -- separator is not needed. just put the command after the flags.`);
|
|
995
|
+
}
|
|
946
996
|
const noOpen = mutableArgs.includes("--no-open");
|
|
947
|
-
const filteredArgs = mutableArgs.filter((a) => a !== "--no-open");
|
|
997
|
+
const filteredArgs = mutableArgs.filter((a) => a !== "--no-open" && a !== "--");
|
|
948
998
|
console.log(`[installing and running: npx ${filteredArgs.join(" ")}]`);
|
|
949
999
|
return start(["npx", "--yes", ...filteredArgs], noOpen, sessionName, cwd);
|
|
950
1000
|
}
|