@duyquangnvx/create-agent-cli 0.11.1 → 0.12.0

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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ What changed in each release of `@duyquangnvx/agent-cli` (the Runtime) and `@duy
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## v0.12.0 (2026-10-23)
8
+
9
+ ### Added
10
+
11
+ - `ctx.spawn`'s `stdin` option writes a child's stdin: a string or bytes, or an `AsyncIterable<Uint8Array>` written as the child reads it, so a large input streams without being held in memory. Writing stops on `ctx.signal`; a stream that throws kills the child and fails the run with its error; a child that exits before reading it all is judged by its exit code. A fake `spawn` given to `runCli` receives it as `stdin`.
12
+
7
13
  ## v0.11.1 (2026-10-22)
8
14
 
9
15
  ### Changed
package/dist/bin.js CHANGED
@@ -6607,6 +6607,9 @@ const CMD_SHIM = /\.cmd$/i;
6607
6607
  const CMD_META = /([()\][%!^"`<>&|;, *?])/g;
6608
6608
  const PATH_SEPARATOR = /[\\/]/;
6609
6609
  const TRAILING_CR = /\r$/;
6610
+ function isWhole(input) {
6611
+ return typeof input === "string" || input instanceof Uint8Array;
6612
+ }
6610
6613
  function escapedForCmd(text) {
6611
6614
  return text.replace(CMD_META, "^$1");
6612
6615
  }
@@ -6671,11 +6674,36 @@ function lineSplitter(onLine) {
6671
6674
  }
6672
6675
  };
6673
6676
  }
6677
+ /** Settles once the child has taken what was written, or its stdin has closed. */
6678
+ function drained(stdin) {
6679
+ return new Promise((resolve) => {
6680
+ const done = () => {
6681
+ stdin.off("drain", done);
6682
+ stdin.off("close", done);
6683
+ resolve();
6684
+ };
6685
+ stdin.on("drain", done);
6686
+ stdin.on("close", done);
6687
+ });
6688
+ }
6689
+ /**
6690
+ * Writes `input` to the child's stdin and ends it, stopping once the child is gone or the run
6691
+ * aborts.
6692
+ */
6693
+ async function feed(stdin, input, signal) {
6694
+ stdin.on("error", () => void 0);
6695
+ const chunks = isWhole(input) ? [input] : input;
6696
+ for await (const chunk of chunks) {
6697
+ if (signal.aborted || stdin.destroyed) return;
6698
+ if (!stdin.write(chunk)) await drained(stdin);
6699
+ }
6700
+ stdin.end();
6701
+ }
6674
6702
  /**
6675
6703
  * Runs a child process to its end; it is killed on abort, and the promise settles only once it has
6676
6704
  * exited. A `detached` child leaves the terminal's process group on POSIX, and so its Ctrl-C.
6677
6705
  */
6678
- async function spawnChild(command, args, { cwd, env, signal, onLine, detached = false }) {
6706
+ async function spawnChild(command, args, { cwd, env, signal, onLine, stdin, detached = false }) {
6679
6707
  signal.throwIfAborted();
6680
6708
  const launch = process.platform === "win32" ? await windowsLaunch(command, args, env) : {
6681
6709
  command,
@@ -6690,7 +6718,7 @@ async function spawnChild(command, args, { cwd, env, signal, onLine, detached =
6690
6718
  shell: launch.shell,
6691
6719
  windowsHide: true,
6692
6720
  stdio: [
6693
- "ignore",
6721
+ stdin === void 0 ? "ignore" : "pipe",
6694
6722
  "pipe",
6695
6723
  "pipe"
6696
6724
  ],
@@ -6700,11 +6728,11 @@ async function spawnChild(command, args, { cwd, env, signal, onLine, detached =
6700
6728
  let stderr = "";
6701
6729
  const stdoutLines = lineSplitter(onLine);
6702
6730
  const stderrLines = lineSplitter(onLine);
6703
- child.stdout.setEncoding("utf8").on("data", (chunk) => {
6731
+ child.stdout?.setEncoding("utf8").on("data", (chunk) => {
6704
6732
  stdout += chunk;
6705
6733
  stdoutLines.push(chunk);
6706
6734
  });
6707
- child.stderr.setEncoding("utf8").on("data", (chunk) => {
6735
+ child.stderr?.setEncoding("utf8").on("data", (chunk) => {
6708
6736
  stderr += chunk;
6709
6737
  stderrLines.push(chunk);
6710
6738
  });
@@ -6713,6 +6741,11 @@ async function spawnChild(command, args, { cwd, env, signal, onLine, detached =
6713
6741
  stopped = stop(child);
6714
6742
  };
6715
6743
  signal.addEventListener("abort", kill, { once: true });
6744
+ let inputFailure;
6745
+ if (stdin !== void 0 && child.stdin !== null) feed(child.stdin, stdin, signal).catch((error) => {
6746
+ inputFailure = { error };
6747
+ kill();
6748
+ });
6716
6749
  child.on("error", (error) => {
6717
6750
  signal.removeEventListener("abort", kill);
6718
6751
  reject(error);
@@ -6723,6 +6756,11 @@ async function spawnChild(command, args, { cwd, env, signal, onLine, detached =
6723
6756
  stopped.then(() => reject(signal.reason));
6724
6757
  return;
6725
6758
  }
6759
+ if (inputFailure !== void 0) {
6760
+ const { error } = inputFailure;
6761
+ stopped.then(() => reject(error));
6762
+ return;
6763
+ }
6726
6764
  stdoutLines.end();
6727
6765
  stderrLines.end();
6728
6766
  resolve({
@@ -6749,23 +6787,42 @@ function missingError(command, cause) {
6749
6787
  hint: `install ${command}, then run the same command again`
6750
6788
  }, { cause });
6751
6789
  }
6790
+ function startError(command, error, fileError) {
6791
+ if (isMissingFile(error)) return missingError(command, error);
6792
+ return fileError(error, {
6793
+ path: command,
6794
+ access: "read"
6795
+ });
6796
+ }
6797
+ async function* reported(stream, onError) {
6798
+ try {
6799
+ yield* stream;
6800
+ } catch (error) {
6801
+ onError(error);
6802
+ throw error;
6803
+ }
6804
+ }
6805
+ /** `input`, a stream passing each error it throws to `onError` before the reader sees it. */
6806
+ function reporting(input, onError) {
6807
+ return input === void 0 || isWhole(input) ? input : reported(input, onError);
6808
+ }
6752
6809
  /** `ctx.spawn`: `spawn` bound to the run, its start failures classified by errno. */
6753
6810
  function contextSpawn(run, defaults, fileError) {
6754
6811
  return async (command, args = [], options = {}) => {
6812
+ let inputFailure;
6755
6813
  let result;
6756
6814
  try {
6757
6815
  result = await run(command, args, {
6758
6816
  cwd: options.cwd ?? defaults.cwd,
6759
6817
  env: options.env ?? defaults.env,
6760
6818
  signal: defaults.signal,
6761
- onLine: options.progress === true ? defaults.progress : void 0
6819
+ onLine: options.progress === true ? defaults.progress : void 0,
6820
+ stdin: reporting(options.stdin, (error) => {
6821
+ inputFailure = { error };
6822
+ })
6762
6823
  });
6763
6824
  } catch (error) {
6764
- if (isMissingFile(error)) throw missingError(command, error);
6765
- throw fileError(error, {
6766
- path: command,
6767
- access: "read"
6768
- });
6825
+ throw inputFailure?.error === error ? error : startError(command, error, fileError);
6769
6826
  }
6770
6827
  if (options.check === true && result.exitCode !== 0) throw failedError(command, result);
6771
6828
  return result;
@@ -9675,14 +9732,14 @@ async function runProcess(cli) {
9675
9732
  }
9676
9733
  //#endregion
9677
9734
  //#region package.json
9678
- var version$1 = "0.11.1";
9735
+ var version$1 = "0.12.0";
9679
9736
  var description = "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.";
9680
9737
  //#endregion
9681
9738
  //#region src/build.ts
9682
9739
  const build = {
9683
- "sha": "92df9c6",
9740
+ "sha": "cc95e77",
9684
9741
  "dirty": false,
9685
- "builtAt": "2026-10-22T10:48:39.000Z"
9742
+ "builtAt": "2026-10-23T01:20:23.000Z"
9686
9743
  };
9687
9744
  //#endregion
9688
9745
  //#region src/steps.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duyquangnvx/create-agent-cli",
3
- "version": "0.11.1",
3
+ "version": "0.12.0",
4
4
  "description": "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -19,7 +19,7 @@
19
19
  "access": "public"
20
20
  },
21
21
  "devDependencies": {
22
- "@duyquangnvx/agent-cli": "0.11.1",
22
+ "@duyquangnvx/agent-cli": "0.12.0",
23
23
  "tsdown": "0.23.0",
24
24
  "zod": "4.6.7"
25
25
  },