noninteractive 0.3.27 → 0.3.32
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 +84 -31
- 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.32",
|
|
383
408
|
type: "module",
|
|
384
409
|
bin: {
|
|
385
410
|
noninteractive: "./bin/noninteractive.js"
|
|
@@ -656,25 +681,28 @@ async function start(cmdArgs, noOpen = false, sessionName, cwd) {
|
|
|
656
681
|
const executable = cmdArgs[0];
|
|
657
682
|
const args = cmdArgs.slice(1);
|
|
658
683
|
const baseName = sessionName || deriveSessionName(executable, args);
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
while (true) {
|
|
684
|
+
const name = baseName;
|
|
685
|
+
{
|
|
662
686
|
const sock2 = socketPath(name);
|
|
663
687
|
try {
|
|
664
|
-
const res = await sendMessage(sock2, { action: "read" });
|
|
688
|
+
const res = await sendMessage(sock2, { action: "read" }, 2000);
|
|
665
689
|
if (res.ok) {
|
|
666
690
|
if (res.exited) {
|
|
667
691
|
try {
|
|
668
|
-
await sendMessage(sock2, { action: "stop" });
|
|
692
|
+
await sendMessage(sock2, { action: "stop" }, 2000);
|
|
669
693
|
} catch {}
|
|
670
|
-
|
|
694
|
+
} else {
|
|
695
|
+
console.error(`session '${name}' is already running. use a different --name or stop it first:`);
|
|
696
|
+
console.error(` npx noninteractive stop ${name}`);
|
|
697
|
+
process.exit(1);
|
|
671
698
|
}
|
|
672
|
-
suffix++;
|
|
673
|
-
name = `${baseName}-${suffix}`;
|
|
674
|
-
continue;
|
|
675
699
|
}
|
|
676
|
-
} catch {
|
|
677
|
-
|
|
700
|
+
} catch {
|
|
701
|
+
try {
|
|
702
|
+
const { unlinkSync: unlinkSync2 } = await import("fs");
|
|
703
|
+
unlinkSync2(sock2);
|
|
704
|
+
} catch {}
|
|
705
|
+
}
|
|
678
706
|
}
|
|
679
707
|
const sock = socketPath(name);
|
|
680
708
|
ensureSessionsDir();
|
|
@@ -714,15 +742,17 @@ make sure the command exists. examples:`);
|
|
|
714
742
|
process.stdout.write(stripAnsi(res.output));
|
|
715
743
|
if (res.exited) {
|
|
716
744
|
console.log(`
|
|
717
|
-
[session '${name}' exited ${res.exitCode}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
745
|
+
[session '${name}' exited ${res.exitCode}]`);
|
|
746
|
+
if (clean.length < 100 && i < 10) {
|
|
747
|
+
console.log(`hint: the first argument to "start" is the command to run, NOT a session name.`);
|
|
748
|
+
console.log(` npx noninteractive start npx vercel # run an npx package`);
|
|
749
|
+
console.log(` npx noninteractive start vercel login # run a command directly`);
|
|
750
|
+
}
|
|
721
751
|
} else {
|
|
722
752
|
console.log(`
|
|
723
|
-
[session '${name}' started \u2014
|
|
724
|
-
console.log(` npx noninteractive send ${name} "<text>"
|
|
725
|
-
console.log(` npx noninteractive read ${name} --wait #
|
|
753
|
+
[session '${name}' started \u2014 the first prompt is shown above. use:]`);
|
|
754
|
+
console.log(` npx noninteractive send ${name} "<text>" # send and get response (waits by default)`);
|
|
755
|
+
console.log(` npx noninteractive read ${name} --wait # only needed for long waits (e.g. OAuth, npm install)`);
|
|
726
756
|
console.log(` npx noninteractive stop ${name} # stop the session`);
|
|
727
757
|
}
|
|
728
758
|
return;
|
|
@@ -739,8 +769,8 @@ make sure the command exists. examples:`);
|
|
|
739
769
|
} catch {}
|
|
740
770
|
}
|
|
741
771
|
console.log(`[session '${name}' started but no output yet \u2014 use:]`);
|
|
742
|
-
console.log(` npx noninteractive send ${name} "<text>"
|
|
743
|
-
console.log(` npx noninteractive read ${name} --wait #
|
|
772
|
+
console.log(` npx noninteractive send ${name} "<text>" # send and get response (waits by default)`);
|
|
773
|
+
console.log(` npx noninteractive read ${name} --wait # only needed for long waits (e.g. OAuth, npm install)`);
|
|
744
774
|
console.log(` npx noninteractive stop ${name} # stop the session`);
|
|
745
775
|
}
|
|
746
776
|
async function read(name, wait, timeout, noOpen = false) {
|
|
@@ -756,9 +786,11 @@ async function read(name, wait, timeout, noOpen = false) {
|
|
|
756
786
|
if (res.output !== undefined)
|
|
757
787
|
process.stdout.write(stripAnsi(res.output));
|
|
758
788
|
handleUrls(res, noOpen);
|
|
759
|
-
if (res.exited)
|
|
789
|
+
if (res.exited) {
|
|
760
790
|
console.log(`
|
|
761
791
|
[exited ${res.exitCode}]`);
|
|
792
|
+
console.log(`[session complete \u2014 output above is final, no need to read again]`);
|
|
793
|
+
}
|
|
762
794
|
} catch {
|
|
763
795
|
const outputFile = sessionOutputFile(name);
|
|
764
796
|
if (existsSync2(outputFile)) {
|
|
@@ -784,9 +816,11 @@ async function send(name, text, wait, timeout, noOpen = false) {
|
|
|
784
816
|
if (res.output !== undefined)
|
|
785
817
|
process.stdout.write(stripAnsi(res.output));
|
|
786
818
|
handleUrls(res, noOpen);
|
|
787
|
-
if (res.exited)
|
|
819
|
+
if (res.exited) {
|
|
788
820
|
console.log(`
|
|
789
821
|
[exited ${res.exitCode}]`);
|
|
822
|
+
console.log(`[session complete \u2014 output above is final, no need to read again]`);
|
|
823
|
+
}
|
|
790
824
|
} else {
|
|
791
825
|
await sendMessage(sock, { action: "send", data: text });
|
|
792
826
|
console.log(`[sent to '${name}' \u2014 run "npx noninteractive read ${name}" to see the result]`);
|
|
@@ -852,7 +886,23 @@ async function main() {
|
|
|
852
886
|
cwd = startArgs[cwdIdx + 1];
|
|
853
887
|
startArgs.splice(cwdIdx, 2);
|
|
854
888
|
}
|
|
855
|
-
|
|
889
|
+
if (startArgs.includes("--")) {
|
|
890
|
+
console.error(`hint: the -- separator is not needed. just put the command after the flags.`);
|
|
891
|
+
}
|
|
892
|
+
const filtered = startArgs.filter((a) => a !== "--no-open" && a !== "--");
|
|
893
|
+
if (filtered.includes("--help") || filtered.includes("-h")) {
|
|
894
|
+
console.log(`usage: noninteractive start [--name <session>] [--cwd <dir>] <cmd> [args...]
|
|
895
|
+
|
|
896
|
+
examples:
|
|
897
|
+
npx noninteractive start npx eslint --init
|
|
898
|
+
npx noninteractive start --name myeslint --cwd /tmp/project npx eslint --init
|
|
899
|
+
npx noninteractive start node server.js
|
|
900
|
+
|
|
901
|
+
flags:
|
|
902
|
+
--name <session> set session name (default: auto-derived from command)
|
|
903
|
+
--cwd <dir> set working directory for the command`);
|
|
904
|
+
process.exit(0);
|
|
905
|
+
}
|
|
856
906
|
if (filtered.length < 1) {
|
|
857
907
|
console.error(`usage: noninteractive start [--name <session>] [--cwd <dir>] <cmd> [args...]
|
|
858
908
|
|
|
@@ -947,8 +997,11 @@ example: npx noninteractive stop vercel`);
|
|
|
947
997
|
hint: use --name for session name, --cwd for working directory.`);
|
|
948
998
|
process.exit(1);
|
|
949
999
|
}
|
|
1000
|
+
if (mutableArgs.includes("--")) {
|
|
1001
|
+
console.error(`hint: the -- separator is not needed. just put the command after the flags.`);
|
|
1002
|
+
}
|
|
950
1003
|
const noOpen = mutableArgs.includes("--no-open");
|
|
951
|
-
const filteredArgs = mutableArgs.filter((a) => a !== "--no-open");
|
|
1004
|
+
const filteredArgs = mutableArgs.filter((a) => a !== "--no-open" && a !== "--");
|
|
952
1005
|
console.log(`[installing and running: npx ${filteredArgs.join(" ")}]`);
|
|
953
1006
|
return start(["npx", "--yes", ...filteredArgs], noOpen, sessionName, cwd);
|
|
954
1007
|
}
|