noninteractive 0.3.27 → 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.
@@ -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.30",
383
408
  type: "module",
384
409
  bin: {
385
410
  noninteractive: "./bin/noninteractive.js"
@@ -721,8 +746,8 @@ make sure the command exists. examples:`);
721
746
  } else {
722
747
  console.log(`
723
748
  [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`);
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)`);
726
751
  console.log(` npx noninteractive stop ${name} # stop the session`);
727
752
  }
728
753
  return;
@@ -739,8 +764,8 @@ make sure the command exists. examples:`);
739
764
  } catch {}
740
765
  }
741
766
  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`);
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)`);
744
769
  console.log(` npx noninteractive stop ${name} # stop the session`);
745
770
  }
746
771
  async function read(name, wait, timeout, noOpen = false) {
@@ -784,9 +809,11 @@ async function send(name, text, wait, timeout, noOpen = false) {
784
809
  if (res.output !== undefined)
785
810
  process.stdout.write(stripAnsi(res.output));
786
811
  handleUrls(res, noOpen);
787
- if (res.exited)
812
+ if (res.exited) {
788
813
  console.log(`
789
814
  [exited ${res.exitCode}]`);
815
+ console.log(`[session complete \u2014 output above is final, no need to read again]`);
816
+ }
790
817
  } else {
791
818
  await sendMessage(sock, { action: "send", data: text });
792
819
  console.log(`[sent to '${name}' \u2014 run "npx noninteractive read ${name}" to see the result]`);
@@ -852,7 +879,23 @@ async function main() {
852
879
  cwd = startArgs[cwdIdx + 1];
853
880
  startArgs.splice(cwdIdx, 2);
854
881
  }
855
- const filtered = startArgs.filter((a) => a !== "--no-open");
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
+ }
856
899
  if (filtered.length < 1) {
857
900
  console.error(`usage: noninteractive start [--name <session>] [--cwd <dir>] <cmd> [args...]
858
901
 
@@ -947,8 +990,11 @@ example: npx noninteractive stop vercel`);
947
990
  hint: use --name for session name, --cwd for working directory.`);
948
991
  process.exit(1);
949
992
  }
993
+ if (mutableArgs.includes("--")) {
994
+ console.error(`hint: the -- separator is not needed. just put the command after the flags.`);
995
+ }
950
996
  const noOpen = mutableArgs.includes("--no-open");
951
- const filteredArgs = mutableArgs.filter((a) => a !== "--no-open");
997
+ const filteredArgs = mutableArgs.filter((a) => a !== "--no-open" && a !== "--");
952
998
  console.log(`[installing and running: npx ${filteredArgs.join(" ")}]`);
953
999
  return start(["npx", "--yes", ...filteredArgs], noOpen, sessionName, cwd);
954
1000
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "noninteractive",
3
- "version": "0.3.27",
3
+ "version": "0.3.30",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "noninteractive": "./bin/noninteractive.js"