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.
@@ -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, outputBuffer.length, timeout);
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
- stdin?.write(msg.data);
330
- socket.end(JSON.stringify({ ok: true }));
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
- stdin?.write(msg.data);
340
- waitForNewOutput(socket, beforeLength, timeout);
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.27",
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
- let name = baseName;
660
- let suffix = 1;
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
- break;
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
- break;
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} \u2014 the command failed]`);
718
- console.log(`hint: the first argument to "start" is the command to run, NOT a session name.`);
719
- console.log(` npx noninteractive start npx vercel # run an npx package`);
720
- console.log(` npx noninteractive start vercel login # run a command directly`);
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 read the output above, then use:]`);
724
- console.log(` npx noninteractive send ${name} "<text>" # send and get response`);
725
- console.log(` npx noninteractive read ${name} --wait # wait for new output`);
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>" # send and get response`);
743
- console.log(` npx noninteractive read ${name} --wait # wait for new output`);
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
- const filtered = startArgs.filter((a) => a !== "--no-open");
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "noninteractive",
3
- "version": "0.3.27",
3
+ "version": "0.3.32",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "noninteractive": "./bin/noninteractive.js"