Commit 73a96e1

Anton Golub <antongolub@antongolub.com>
2025-11-03 15:45:52
feat: introduce `MAML` API (#1362)
* chore: up dev deps * feat: add `MAML` API closes #1361 * chore: bump version to `8.9.0` * build: inline `maml.js` libdefs * fix: reexport `MAML` API
1 parent 240a399
.github/ISSUE_TEMPLATE/idea.yaml → .github/ISSUE_TEMPLATE/idea.yml
File renamed without changes
build/3rd-party-licenses
@@ -95,6 +95,11 @@ jsonfile@6.1.0
   git@github.com:jprichardson/node-jsonfile.git
   MIT
 
+maml.js@0.0.3
+  Anton Medvedev <anton@medv.io>
+  git+https://github.com/maml-dev/maml.js.git
+  MIT
+
 merge2@1.4.1
   <unknown>
   git@github.com:teambition/merge2.git
build/index.cjs
@@ -13,6 +13,7 @@ const {
 // src/index.ts
 var index_exports = {};
 __export(index_exports, {
+  MAML: () => import_vendor2.MAML,
   VERSION: () => VERSION,
   YAML: () => import_vendor2.YAML,
   argv: () => argv,
@@ -54,7 +55,7 @@ var import_vendor = require("./vendor.cjs");
 
 // src/versions.ts
 var versions = {
-  zx: "8.8.5",
+  zx: "8.9.0",
   chalk: "5.6.2",
   depseek: "0.4.3",
   dotenv: "0.2.3",
@@ -264,6 +265,7 @@ function quiet(promise) {
 /* c8 ignore next 100 */
 // Annotate the CommonJS export names for ESM import in node:
 0 && (module.exports = {
+  MAML,
   VERSION,
   YAML,
   argv,
build/index.d.ts
@@ -4,7 +4,7 @@
 import { type ProcessPromise } from './core.js';
 export * from './core.js';
 export * from './goods.js';
-export { minimist, dotenv, fs, YAML, glob, glob as globby } from './vendor.js';
+export { minimist, dotenv, fs, YAML, MAML, glob, glob as globby } from './vendor.js';
 export declare const VERSION: string;
 export declare const version: string;
 /**
build/index.js
@@ -2,6 +2,7 @@
 import "./deno.js"
 import * as __module__ from "./index.cjs"
 const {
+  MAML,
   VERSION,
   YAML,
   argv,
@@ -52,6 +53,7 @@ const {
   within
 } = globalThis.Deno ? globalThis.require("./index.cjs") : __module__
 export {
+  MAML,
   VERSION,
   YAML,
   argv,
build/vendor-extra.cjs
@@ -403,7 +403,7 @@ var require_stringify = __commonJS({
     "use strict";
     var utils = require_utils();
     module2.exports = (ast, options = {}) => {
-      const stringify5 = (node, parent = {}) => {
+      const stringify6 = (node, parent = {}) => {
         const invalidBlock = options.escapeInvalid && utils.isInvalidBrace(parent);
         const invalidNode = node.invalid === true && options.escapeInvalid === true;
         let output = "";
@@ -418,12 +418,12 @@ var require_stringify = __commonJS({
         }
         if (node.nodes) {
           for (const child of node.nodes) {
-            output += stringify5(child);
+            output += stringify6(child);
           }
         }
         return output;
       };
-      return stringify5(ast);
+      return stringify6(ast);
     };
   }
 });
@@ -677,7 +677,7 @@ var require_fill_range = __commonJS({
       while (value[++index] === "0") ;
       return index > 0;
     };
-    var stringify5 = (start, end, options) => {
+    var stringify6 = (start, end, options) => {
       if (typeof start === "string" || typeof end === "string") {
         return true;
       }
@@ -772,7 +772,7 @@ var require_fill_range = __commonJS({
       step = Math.max(Math.abs(step), 1);
       let padded = zeros(startString) || zeros(endString) || zeros(stepString);
       let maxLen = padded ? Math.max(startString.length, endString.length, stepString.length) : 0;
-      let toNumber = padded === false && stringify5(start, end, options) === false;
+      let toNumber = padded === false && stringify6(start, end, options) === false;
       let format = options.transform || transform(toNumber);
       if (options.toRegex && step === 1) {
         return toRange(toMaxLen(start, maxLen), toMaxLen(end, maxLen), true, options);
@@ -906,7 +906,7 @@ var require_expand = __commonJS({
   "node_modules/braces/lib/expand.js"(exports2, module2) {
     "use strict";
     var fill = require_fill_range();
-    var stringify5 = require_stringify();
+    var stringify6 = require_stringify();
     var utils = require_utils();
     var append = (queue = "", stash = "", enclose = false) => {
       const result = [];
@@ -941,7 +941,7 @@ var require_expand = __commonJS({
           q = p2.queue;
         }
         if (node.invalid || node.dollar) {
-          q.push(append(q.pop(), stringify5(node, options)));
+          q.push(append(q.pop(), stringify6(node, options)));
           return;
         }
         if (node.type === "brace" && node.invalid !== true && node.nodes.length === 2) {
@@ -955,7 +955,7 @@ var require_expand = __commonJS({
           }
           let range = fill(...args, options);
           if (range.length === 0) {
-            range = stringify5(node, options);
+            range = stringify6(node, options);
           }
           q.push(append(q.pop(), range));
           node.nodes = [];
@@ -1100,7 +1100,7 @@ var require_constants = __commonJS({
 var require_parse = __commonJS({
   "node_modules/braces/lib/parse.js"(exports2, module2) {
     "use strict";
-    var stringify5 = require_stringify();
+    var stringify6 = require_stringify();
     var {
       MAX_LENGTH,
       CHAR_BACKSLASH,
@@ -1130,7 +1130,7 @@ var require_parse = __commonJS({
       CHAR_NO_BREAK_SPACE,
       CHAR_ZERO_WIDTH_NOBREAK_SPACE
     } = require_constants();
-    var parse3 = (input, options = {}) => {
+    var parse4 = (input, options = {}) => {
       if (typeof input !== "string") {
         throw new TypeError("Expected a string");
       }
@@ -1272,7 +1272,7 @@ var require_parse = __commonJS({
           if (block.ranges > 0) {
             block.ranges = 0;
             const open = block.nodes.shift();
-            block.nodes = [open, { type: "text", value: stringify5(block) }];
+            block.nodes = [open, { type: "text", value: stringify6(block) }];
           }
           push({ type: "comma", value });
           block.commas++;
@@ -1330,7 +1330,7 @@ var require_parse = __commonJS({
       push({ type: "eos" });
       return ast;
     };
-    module2.exports = parse3;
+    module2.exports = parse4;
   }
 });
 
@@ -1338,10 +1338,10 @@ var require_parse = __commonJS({
 var require_braces = __commonJS({
   "node_modules/braces/index.js"(exports2, module2) {
     "use strict";
-    var stringify5 = require_stringify();
+    var stringify6 = require_stringify();
     var compile = require_compile();
     var expand = require_expand();
-    var parse3 = require_parse();
+    var parse4 = require_parse();
     var braces = (input, options = {}) => {
       let output = [];
       if (Array.isArray(input)) {
@@ -1361,12 +1361,12 @@ var require_braces = __commonJS({
       }
       return output;
     };
-    braces.parse = (input, options = {}) => parse3(input, options);
+    braces.parse = (input, options = {}) => parse4(input, options);
     braces.stringify = (input, options = {}) => {
       if (typeof input === "string") {
-        return stringify5(braces.parse(input, options), options);
+        return stringify6(braces.parse(input, options), options);
       }
-      return stringify5(input, options);
+      return stringify6(input, options);
     };
     braces.compile = (input, options = {}) => {
       if (typeof input === "string") {
@@ -2013,7 +2013,7 @@ var require_parse2 = __commonJS({
     var syntaxError = (type, char) => {
       return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
     };
-    var parse3 = (input, options) => {
+    var parse4 = (input, options) => {
       if (typeof input !== "string") {
         throw new TypeError("Expected a string");
       }
@@ -2162,7 +2162,7 @@ var require_parse2 = __commonJS({
             output = token.close = `)$))${extglobStar}`;
           }
           if (token.inner.includes("*") && (rest = remaining()) && /^\.[^\\/.]+$/.test(rest)) {
-            const expression = parse3(rest, __spreadProps(__spreadValues({}, options), { fastpaths: false })).output;
+            const expression = parse4(rest, __spreadProps(__spreadValues({}, options), { fastpaths: false })).output;
             output = token.close = `)${expression})${extglobStar})`;
           }
           if (token.prev.type === "bos") {
@@ -2687,7 +2687,7 @@ var require_parse2 = __commonJS({
       }
       return state;
     };
-    parse3.fastpaths = (input, options) => {
+    parse4.fastpaths = (input, options) => {
       const opts = __spreadValues({}, options);
       const max = typeof opts.maxLength === "number" ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
       const len = input.length;
@@ -2753,7 +2753,7 @@ var require_parse2 = __commonJS({
       }
       return source;
     };
-    module2.exports = parse3;
+    module2.exports = parse4;
   }
 });
 
@@ -2763,7 +2763,7 @@ var require_picomatch = __commonJS({
     "use strict";
     var path3 = require("path");
     var scan = require_scan();
-    var parse3 = require_parse2();
+    var parse4 = require_parse2();
     var utils = require_utils2();
     var constants = require_constants2();
     var isObject = (val) => val && typeof val === "object" && !Array.isArray(val);
@@ -2851,7 +2851,7 @@ var require_picomatch = __commonJS({
     picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str);
     picomatch.parse = (pattern, options) => {
       if (Array.isArray(pattern)) return pattern.map((p2) => picomatch.parse(p2, options));
-      return parse3(pattern, __spreadProps(__spreadValues({}, options), { fastpaths: false }));
+      return parse4(pattern, __spreadProps(__spreadValues({}, options), { fastpaths: false }));
     };
     picomatch.scan = (input, options) => scan(input, options);
     picomatch.compileRe = (state, options, returnOutput = false, returnState = false) => {
@@ -2877,10 +2877,10 @@ var require_picomatch = __commonJS({
       }
       let parsed = { negated: false, fastpaths: true };
       if (options.fastpaths !== false && (input[0] === "." || input[0] === "*")) {
-        parsed.output = parse3.fastpaths(input, options);
+        parsed.output = parse4.fastpaths(input, options);
       }
       if (!parsed.output) {
-        parsed = parse3(input, options);
+        parsed = parse4(input, options);
       }
       return picomatch.compileRe(parsed, options, returnOutput, returnState);
     };
@@ -7863,7 +7863,7 @@ var require_ensure = __commonJS({
 var require_utils6 = __commonJS({
   "node_modules/jsonfile/utils.js"(exports2, module2) {
     "use strict";
-    function stringify5(obj, { EOL = "\n", finalEOL = true, replacer = null, spaces } = {}) {
+    function stringify6(obj, { EOL = "\n", finalEOL = true, replacer = null, spaces } = {}) {
       const EOF = finalEOL ? EOL : "";
       const str = JSON.stringify(obj, replacer, spaces);
       return str.replace(/\n/g, EOL) + EOF;
@@ -7872,7 +7872,7 @@ var require_utils6 = __commonJS({
       if (Buffer.isBuffer(content)) content = content.toString("utf8");
       return content.replace(/^\uFEFF/, "");
     }
-    module2.exports = { stringify: stringify5, stripBom };
+    module2.exports = { stringify: stringify6, stripBom };
   }
 });
 
@@ -7887,7 +7887,7 @@ var require_jsonfile = __commonJS({
       _fs2 = require("fs");
     }
     var universalify = require_universalify();
-    var { stringify: stringify5, stripBom } = require_utils6();
+    var { stringify: stringify6, stripBom } = require_utils6();
     function _readFile(_0) {
       return __async(this, arguments, function* (file, options = {}) {
         if (typeof options === "string") {
@@ -7934,14 +7934,14 @@ var require_jsonfile = __commonJS({
     function _writeFile(_0, _1) {
       return __async(this, arguments, function* (file, obj, options = {}) {
         const fs6 = options.fs || _fs2;
-        const str = stringify5(obj, options);
+        const str = stringify6(obj, options);
         yield universalify.fromCallback(fs6.writeFile)(file, str, options);
       });
     }
     var writeFile = universalify.fromPromise(_writeFile);
     function writeFileSync(file, obj, options = {}) {
       const fs6 = options.fs || _fs2;
-      const str = stringify5(obj, options);
+      const str = stringify6(obj, options);
       return fs6.writeFileSync(file, str, options);
     }
     var jsonfile = {
@@ -8005,11 +8005,11 @@ var require_output_file = __commonJS({
 var require_output_json = __commonJS({
   "node_modules/fs-extra/lib/json/output-json.js"(exports2, module2) {
     "use strict";
-    var { stringify: stringify5 } = require_utils6();
+    var { stringify: stringify6 } = require_utils6();
     var { outputFile } = require_output_file();
     function outputJson(_0, _1) {
       return __async(this, arguments, function* (file, data, options = {}) {
-        const str = stringify5(data, options);
+        const str = stringify6(data, options);
         yield outputFile(file, str, options);
       });
     }
@@ -8021,10 +8021,10 @@ var require_output_json = __commonJS({
 var require_output_json_sync = __commonJS({
   "node_modules/fs-extra/lib/json/output-json-sync.js"(exports2, module2) {
     "use strict";
-    var { stringify: stringify5 } = require_utils6();
+    var { stringify: stringify6 } = require_utils6();
     var { outputFileSync } = require_output_file();
     function outputJsonSync(file, data, options) {
-      const str = stringify5(data, options);
+      const str = stringify6(data, options);
       outputFileSync(file, str, options);
     }
     module2.exports = outputJsonSync;
@@ -12273,6 +12273,7 @@ var require_minimist = __commonJS({
 // src/vendor-extra.ts
 var vendor_extra_exports = {};
 __export(vendor_extra_exports, {
+  MAML: () => MAML,
   YAML: () => YAML,
   createRequire: () => createRequire,
   depseek: () => depseek,
@@ -14617,8 +14618,8 @@ var Pair = class _Pair {
 function stringifyCollection(collection, ctx, options) {
   var _a2;
   const flow = (_a2 = ctx.inFlow) != null ? _a2 : collection.flow;
-  const stringify5 = flow ? stringifyFlowCollection : stringifyBlockCollection;
-  return stringify5(collection, ctx, options);
+  const stringify6 = flow ? stringifyFlowCollection : stringifyBlockCollection;
+  return stringify6(collection, ctx, options);
 }
 function stringifyBlockCollection({ comment, items }, ctx, { blockItemPrefix, flowChars, itemIndent, onChompKeep, onComment }) {
   const { indent, options: { commentString } } = ctx;
@@ -19562,6 +19563,418 @@ function stringify3(value, replacer, options) {
 // node_modules/yaml/browser/index.js
 var browser_default = dist_exports;
 
+// node_modules/maml.js/build/index.js
+var build_exports = {};
+__export(build_exports, {
+  parse: () => parse2,
+  stringify: () => stringify4
+});
+
+// node_modules/maml.js/build/parse.js
+function parse2(source) {
+  if (typeof source !== "string")
+    throw TypeError("Source must be a string");
+  let pos = 0, lineNumber = 1, ch, done = false;
+  next();
+  const value = parseValue();
+  skipWhitespace();
+  if (!done) {
+    throw new SyntaxError(errorSnippet());
+  }
+  expectValue(value);
+  return value;
+  function next() {
+    if (pos < source.length) {
+      ch = source[pos];
+      pos++;
+    } else {
+      ch = "";
+      done = true;
+    }
+    if (ch === "\n") {
+      lineNumber++;
+    }
+  }
+  function lookahead2() {
+    return source.substring(pos, pos + 2);
+  }
+  function parseValue() {
+    var _a2, _b2, _c, _d, _e, _f, _g;
+    skipWhitespace();
+    return (_g = (_f = (_e = (_d = (_c = (_b2 = (_a2 = parseMultilineString()) != null ? _a2 : parseString()) != null ? _b2 : parseNumber()) != null ? _c : parseObject()) != null ? _d : parseArray()) != null ? _e : parseKeyword("true", true)) != null ? _f : parseKeyword("false", false)) != null ? _g : parseKeyword("null", null);
+  }
+  function parseString() {
+    if (ch !== '"')
+      return;
+    let str = "";
+    let escaped = false;
+    while (true) {
+      next();
+      if (escaped) {
+        if (ch === "u") {
+          next();
+          if (ch !== "{") {
+            throw new SyntaxError(errorSnippet(errorMap.u + " " + JSON.stringify(ch) + ' (expected "{")'));
+          }
+          let hex = "";
+          while (true) {
+            next();
+            if (ch === "}")
+              break;
+            if (!isHexDigit(ch)) {
+              throw new SyntaxError(errorSnippet(errorMap.u + " " + JSON.stringify(ch)));
+            }
+            hex += ch;
+            if (hex.length > 6) {
+              throw new SyntaxError(errorSnippet(errorMap.u + " (too many hex digits)"));
+            }
+          }
+          if (hex.length === 0) {
+            throw new SyntaxError(errorSnippet(errorMap.u));
+          }
+          const codePoint = parseInt(hex, 16);
+          if (codePoint > 1114111) {
+            throw new SyntaxError(errorSnippet(errorMap.u + " (out of range)"));
+          }
+          str += String.fromCodePoint(codePoint);
+        } else {
+          const escapedChar = escapeMap[ch];
+          if (!escapedChar) {
+            throw new SyntaxError(errorSnippet(errorMap.u + " " + JSON.stringify(ch)));
+          }
+          str += escapedChar;
+        }
+        escaped = false;
+      } else if (ch === "\\") {
+        escaped = true;
+      } else if (ch === '"') {
+        break;
+      } else if (ch === "\n") {
+        throw new SyntaxError(errorSnippet(`Use """ for multiline strings or escape newlines with "\\n"`));
+      } else if (ch < "") {
+        throw new SyntaxError(errorSnippet(`Unescaped control character ${JSON.stringify(ch)}`));
+      } else {
+        str += ch;
+      }
+    }
+    next();
+    return str;
+  }
+  function parseMultilineString() {
+    if (ch !== '"' || lookahead2() !== '""')
+      return;
+    next();
+    next();
+    next();
+    let hasLeadingNewline = false;
+    if (ch === "\n") {
+      hasLeadingNewline = true;
+      next();
+    }
+    let str = "";
+    while (!done) {
+      if (ch === '"' && lookahead2() === '""') {
+        next();
+        next();
+        next();
+        if (str === "" && !hasLeadingNewline) {
+          throw new SyntaxError(errorSnippet("Multiline strings cannot be empty"));
+        }
+        return str;
+      }
+      str += ch;
+      next();
+    }
+    throw new SyntaxError(errorSnippet());
+  }
+  function parseNumber() {
+    if (!isDigit(ch) && ch !== "-")
+      return;
+    let numStr = "";
+    let float3 = false;
+    if (ch === "-") {
+      numStr += ch;
+      next();
+      if (!isDigit(ch)) {
+        throw new SyntaxError(errorSnippet());
+      }
+    }
+    if (ch === "0") {
+      numStr += ch;
+      next();
+    } else {
+      while (isDigit(ch)) {
+        numStr += ch;
+        next();
+      }
+    }
+    if (ch === ".") {
+      float3 = true;
+      numStr += ch;
+      next();
+      if (!isDigit(ch)) {
+        throw new SyntaxError(errorSnippet());
+      }
+      while (isDigit(ch)) {
+        numStr += ch;
+        next();
+      }
+    }
+    if (ch === "e" || ch === "E") {
+      float3 = true;
+      numStr += ch;
+      next();
+      if (ch === "+" || ch === "-") {
+        numStr += ch;
+        next();
+      }
+      if (!isDigit(ch)) {
+        throw new SyntaxError(errorSnippet());
+      }
+      while (isDigit(ch)) {
+        numStr += ch;
+        next();
+      }
+    }
+    return float3 ? parseFloat(numStr) : toSafeNumber(numStr);
+  }
+  function parseObject() {
+    if (ch !== "{")
+      return;
+    next();
+    skipWhitespace();
+    const obj = {};
+    if (ch === "}") {
+      next();
+      return obj;
+    }
+    while (true) {
+      const keyPos = pos;
+      let key;
+      if (ch === '"') {
+        key = parseString();
+      } else {
+        key = parseKey();
+      }
+      if (Object.prototype.hasOwnProperty.call(obj, key)) {
+        pos = keyPos;
+        throw new SyntaxError(errorSnippet(`Duplicate key ${JSON.stringify(key)}`));
+      }
+      skipWhitespace();
+      if (ch !== ":") {
+        throw new SyntaxError(errorSnippet());
+      }
+      next();
+      const value2 = parseValue();
+      expectValue(value2);
+      obj[key] = value2;
+      const newlineAfterValue = skipWhitespace();
+      if (ch === "}") {
+        next();
+        return obj;
+      } else if (ch === ",") {
+        next();
+        skipWhitespace();
+        if (ch === "}") {
+          next();
+          return obj;
+        }
+      } else if (newlineAfterValue) {
+        continue;
+      } else {
+        throw new SyntaxError(errorSnippet("Expected comma or newline between key-value pairs"));
+      }
+    }
+  }
+  function parseKey() {
+    let identifier = "";
+    while (isKeyChar(ch)) {
+      identifier += ch;
+      next();
+    }
+    if (identifier === "") {
+      throw new SyntaxError(errorSnippet());
+    }
+    return identifier;
+  }
+  function parseArray() {
+    if (ch !== "[")
+      return;
+    next();
+    skipWhitespace();
+    const array = [];
+    if (ch === "]") {
+      next();
+      return array;
+    }
+    while (true) {
+      const value2 = parseValue();
+      expectValue(value2);
+      array.push(value2);
+      const newLineAfterValue = skipWhitespace();
+      if (ch === "]") {
+        next();
+        return array;
+      } else if (ch === ",") {
+        next();
+        skipWhitespace();
+        if (ch === "]") {
+          next();
+          return array;
+        }
+      } else if (newLineAfterValue) {
+        continue;
+      } else {
+        throw new SyntaxError(errorSnippet("Expected comma or newline between values"));
+      }
+    }
+  }
+  function parseKeyword(name, value2) {
+    if (ch !== name[0])
+      return;
+    for (let i = 1; i < name.length; i++) {
+      next();
+      if (ch !== name[i]) {
+        throw new SyntaxError(errorSnippet());
+      }
+    }
+    next();
+    if (isWhitespace(ch) || ch === "," || ch === "}" || ch === "]" || ch === void 0) {
+      return value2;
+    }
+    throw new SyntaxError(errorSnippet());
+  }
+  function skipWhitespace() {
+    let hasNewline = false;
+    while (isWhitespace(ch)) {
+      hasNewline || (hasNewline = ch === "\n");
+      next();
+    }
+    const hasNewlineAfterComment = skipComment();
+    return hasNewline || hasNewlineAfterComment;
+  }
+  function skipComment() {
+    if (ch === "#") {
+      while (!done && ch !== "\n") {
+        next();
+      }
+      return skipWhitespace();
+    }
+    return false;
+  }
+  function isWhitespace(ch2) {
+    return ch2 === " " || ch2 === "\n" || ch2 === "	" || ch2 === "\r";
+  }
+  function isHexDigit(ch2) {
+    return ch2 >= "0" && ch2 <= "9" || ch2 >= "A" && ch2 <= "F";
+  }
+  function isDigit(ch2) {
+    return ch2 >= "0" && ch2 <= "9";
+  }
+  function isKeyChar(ch2) {
+    return ch2 >= "A" && ch2 <= "Z" || ch2 >= "a" && ch2 <= "z" || ch2 >= "0" && ch2 <= "9" || ch2 === "_" || ch2 === "-";
+  }
+  function toSafeNumber(str) {
+    if (str == "-0")
+      return -0;
+    const num = Number(str);
+    return num >= Number.MIN_SAFE_INTEGER && num <= Number.MAX_SAFE_INTEGER ? num : BigInt(str);
+  }
+  function expectValue(value2) {
+    if (value2 === void 0) {
+      throw new SyntaxError(errorSnippet());
+    }
+  }
+  function errorSnippet(message = `Unexpected character ${JSON.stringify(ch)}`) {
+    if (!ch)
+      message = "Unexpected end of input";
+    const lines = source.substring(pos - 40, pos).split("\n");
+    let lastLine = lines.at(-1) || "";
+    let postfix = source.substring(pos, pos + 40).split("\n", 1).at(0) || "";
+    if (lastLine === "") {
+      lastLine = lines.at(-2) || "";
+      lastLine += " ";
+      lineNumber--;
+      postfix = "";
+    }
+    const snippet = `    ${lastLine}${postfix}
+`;
+    const pointer = `    ${".".repeat(Math.max(0, lastLine.length - 1))}^
+`;
+    return `${message} on line ${lineNumber}.
+
+${snippet}${pointer}`;
+  }
+}
+var escapeMap = {
+  '"': '"',
+  "\\": "\\",
+  n: "\n",
+  r: "\r",
+  t: "	"
+};
+var errorMap = {
+  u: "Invalid escape sequence"
+};
+
+// node_modules/maml.js/build/stringify.js
+function stringify4(value) {
+  return doStringify(value, 0);
+}
+function doStringify(value, level) {
+  const kind = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
+  switch (kind) {
+    case "string":
+      return JSON.stringify(value);
+    case "boolean":
+    case "bigint":
+    case "number":
+      return `${value}`;
+    case "null":
+    case "undefined":
+      return "null";
+    case "array": {
+      const len = value.length;
+      if (len === 0)
+        return "[]";
+      const childIndent = getIndent(level + 1);
+      const parentIndent = getIndent(level);
+      let out = "[\n";
+      for (let i = 0; i < len; i++) {
+        if (i > 0)
+          out += "\n";
+        out += childIndent + doStringify(value[i], level + 1);
+      }
+      return out + "\n" + parentIndent + "]";
+    }
+    case "object": {
+      const keys = Object.keys(value);
+      const len = keys.length;
+      if (len === 0)
+        return "{}";
+      const childIndent = getIndent(level + 1);
+      const parentIndent = getIndent(level);
+      let out = "{\n";
+      for (let i = 0; i < len; i++) {
+        if (i > 0)
+          out += "\n";
+        const key = keys[i];
+        out += childIndent + doKeyStringify(key) + ": " + doStringify(value[key], level + 1);
+      }
+      return out + "\n" + parentIndent + "}";
+    }
+    default:
+      throw new Error(`Unsupported value type: ${kind}`);
+  }
+}
+var KEY_RE = /^[A-Za-z0-9_-]+$/;
+function doKeyStringify(key) {
+  return KEY_RE.test(key) ? key : JSON.stringify(key);
+}
+function getIndent(level) {
+  return " ".repeat(2 * level);
+}
+
 // src/vendor-extra.ts
 var _fs = __toESM(require_lib(), 1);
 var import_create_require = __toESM(require_create_require(), 1);
@@ -19659,7 +20072,7 @@ var Q3 = "`";
 var KR = /^[a-zA-Z_]\w*$/;
 var SR = /\s/;
 var decoder = new import_node_util3.TextDecoder();
-var parse2 = (content) => {
+var parse3 = (content) => {
   const e = {};
   let k2 = "";
   let b = "";
@@ -19723,11 +20136,11 @@ var formatValue = (v2) => {
   if (!q1 && !q2 && !q3 && !s) return v2;
   if (!q1) return `${Q1}${v2}${Q1}`;
   if (!q2) return `${Q2}${v2}${Q2}`;
-  if (parse2(`V=${Q3}${v2}${Q3}`).V !== v2) throw new Error(`Invalid value: ${v2}`);
+  if (parse3(`V=${Q3}${v2}${Q3}`).V !== v2) throw new Error(`Invalid value: ${v2}`);
   return `${Q3}${v2}${Q3}`;
 };
-var stringify4 = (env) => Object.entries(env).map(([k2, v2]) => `${k2}=${formatValue(v2 || "")}`).join("\n");
-var _load = (read, ...files) => files.reverse().reduce((m2, f2) => Object.assign(m2, parse2(read(import_node_path4.default.resolve(f2)))), {});
+var stringify5 = (env) => Object.entries(env).map(([k2, v2]) => `${k2}=${formatValue(v2 || "")}`).join("\n");
+var _load = (read, ...files) => files.reverse().reduce((m2, f2) => Object.assign(m2, parse3(read(import_node_path4.default.resolve(f2)))), {});
 var load = (...files) => _load((file) => import_node_fs5.default.readFileSync(file, "utf8"), ...files);
 var loadSafe = (...files) => _load(
   (file) => import_node_fs5.default.existsSync(file) ? import_node_fs5.default.readFileSync(file, "utf8") : "",
@@ -19735,7 +20148,7 @@ var loadSafe = (...files) => _load(
 );
 var populate = (env, extra) => Object.assign(env, extra);
 var config = (def = DOTENV, ...files) => populate(process.env, loadSafe(def, ...files));
-var index_default = { parse: parse2, stringify: stringify4, load, loadSafe, config };
+var index_default = { parse: parse3, stringify: stringify5, load, loadSafe, config };
 
 // src/vendor-extra.ts
 var import_internals = require("./internals.cjs");
@@ -19763,12 +20176,14 @@ var depseek = wrap("depseek", depseekSync);
 var dotenv = wrap("dotenv", index_default);
 var fs5 = wrap("fs", _fs);
 var YAML = wrap("YAML", _YAML);
+var MAML = wrap("MAML", build_exports);
 var glob = wrap("glob", _glob);
 var nodeFetch = wrap("nodeFetch", r);
 var minimist = wrap("minimist", import_minimist.default);
 /* c8 ignore next 100 */
 // Annotate the CommonJS export names for ESM import in node:
 0 && (module.exports = {
+  MAML,
   YAML,
   createRequire,
   depseek,
build/vendor-extra.d.ts
@@ -322,6 +322,8 @@ declare function isDynamicPattern(patterns: string | readonly string[], options?
 declare function isGitIgnored(options?: GitignoreOptions): Promise<GlobbyFilterFunction>;
 declare function isGitIgnoredSync(options?: GitignoreOptions): GlobbyFilterFunction;
 declare function convertPathToPattern(source: string): FastGlob.Pattern;
+declare function parse(source: string): any;
+declare function stringify(value: any): string;
 declare const fetch$1: typeof globalThis.fetch;
 type TCodeRef = {
 	type: string;
@@ -467,6 +469,7 @@ export declare const depseek: typeof depseekSync;
 export declare const dotenv: typeof _default;
 declare const fs$1: typeof import("fs-extra");
 export declare const YAML: typeof _YAML;
+export declare const MAML: typeof _maml;
 export declare const glob: typeof _glob;
 export declare const nodeFetch: typeof fetch$1;
 declare const minimist$1: typeof minimist;
@@ -477,6 +480,10 @@ declare namespace minimist$1 {
 	}
 }
 
+declare namespace _maml {
+	export { parse, stringify };
+}
+
 export {
 	fs$1 as fs,
 	minimist$1 as minimist,
docs/api.md
@@ -397,7 +397,7 @@ The [path](https://nodejs.org/api/path.html) package.
 await $`mkdir ${path.join(basedir, 'output')}`
 ```
 
-## `yaml`
+## `YAML`
 
 The [yaml](https://www.npmjs.com/package/yaml) package.
 
@@ -405,6 +405,22 @@ The [yaml](https://www.npmjs.com/package/yaml) package.
 console.log(YAML.parse('foo: bar').foo)
 ```
 
+## `MAML`
+
+The [maml.js](https://www.npmjs.com/package/maml.js) package.
+
+```js
+const maml = `{
+  example: "MAML"
+  # Comments are supported
+  notes: """
+This is a multiline string.
+Keeps formatting as‑is.
+"""
+}`
+console.log(MAML.parse(maml).example) // MAML 
+```
+
 ## `dotenv`
 
 The [envapi](https://www.npmjs.com/package/envapi) package.  
scripts/build-dts.mjs
@@ -46,6 +46,7 @@ const entries = [
         '@webpod/ingrid',
         'depseek',
         'envapi',
+        'maml.js',
       ], // args['external-inlines'],
     },
     output,
src/index.ts
@@ -19,7 +19,15 @@ bus.lock()
 
 export * from './core.ts'
 export * from './goods.ts'
-export { minimist, dotenv, fs, YAML, glob, glob as globby } from './vendor.ts'
+export {
+  minimist,
+  dotenv,
+  fs,
+  YAML,
+  MAML,
+  glob,
+  glob as globby,
+} from './vendor.ts'
 
 export const VERSION: string = versions.zx || '0.0.0'
 export const version: string = VERSION
src/vendor-extra.ts
@@ -26,6 +26,7 @@ import {
   type Options as GlobbyOptions,
 } from 'globby'
 import * as _yaml from 'yaml'
+import * as _maml from 'maml.js'
 import * as _fs from 'fs-extra'
 import _createRequire from 'create-require'
 import { fetch as _nodeFetch, AbortController } from 'node-fetch-native'
@@ -126,6 +127,7 @@ export const depseek: typeof _depseek = wrap('depseek', _depseek)
 export const dotenv: typeof _dotenv = wrap('dotenv', _dotenv)
 export const fs: typeof import('fs-extra') = wrap('fs', _fs)
 export const YAML: typeof _YAML = wrap('YAML', _YAML)
+export const MAML: typeof _maml = wrap('MAML', _maml)
 export const glob: typeof _glob = wrap('glob', _glob)
 export const nodeFetch: typeof _nodeFetch = wrap('nodeFetch', _nodeFetch)
 
src/versions.ts
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 export const versions: Record<string, string> = {
-  zx: '8.8.5',
+  zx: '8.9.0',
   chalk: '5.6.2',
   depseek: '0.4.3',
   dotenv: '0.2.3',
test/export.test.js
@@ -158,6 +158,9 @@ describe('index', () => {
     assert.equal(typeof index.Fail.DOCS_URL, 'string', 'index.Fail.DOCS_URL')
     assert.equal(typeof index.Fail.ERRNO_CODES, 'object', 'index.Fail.ERRNO_CODES')
     assert.equal(typeof index.Fail.EXIT_CODES, 'object', 'index.Fail.EXIT_CODES')
+    assert.equal(typeof index.MAML, 'object', 'index.MAML')
+    assert.equal(typeof index.MAML.parse, 'function', 'index.MAML.parse')
+    assert.equal(typeof index.MAML.stringify, 'function', 'index.MAML.stringify')
     assert.equal(typeof index.ProcessOutput, 'function', 'index.ProcessOutput')
     assert.equal(typeof index.ProcessOutput.getErrorDetails, 'function', 'index.ProcessOutput.getErrorDetails')
     assert.equal(typeof index.ProcessOutput.getErrorMessage, 'function', 'index.ProcessOutput.getErrorMessage')
test/vendor.test.js
@@ -16,6 +16,7 @@ import assert from 'node:assert'
 import { test, describe } from 'node:test'
 import {
   YAML,
+  MAML,
   minimist,
   which,
   glob,
@@ -23,12 +24,45 @@ import {
 } from '../build/vendor.cjs'
 
 describe('vendor API', () => {
-  test('YAML.parse', () => {
-    assert.deepEqual(YAML.parse('a: b\n'), { a: 'b' })
+  describe('YAML', () => {
+    test('parse()', () => {
+      assert.deepEqual(YAML.parse('a: b\n'), { a: 'b' })
+    })
+    test('stringify()', () => {
+      assert.equal(YAML.stringify({ a: 'b' }), 'a: b\n')
+    })
   })
 
-  test('YAML.stringify', () => {
-    assert.equal(YAML.stringify({ a: 'b' }), 'a: b\n')
+  describe('MAML', () => {
+    test('parse()/stringify()', () => {
+      const maml = `{
+  project: "MAML"
+  tags: [
+    "minimal"
+    "readable"
+  ]
+  spec: {
+    version: 1
+    author: "Anton Medvedev"
+  }
+  notes: """
+This is a multiline string.
+Keeps formatting as‑is.
+"""
+}`
+      const obj = MAML.parse(maml)
+
+      assert.deepEqual(MAML.parse(MAML.stringify(obj)), obj)
+      assert.deepEqual(obj, {
+        project: 'MAML',
+        tags: ['minimal', 'readable'],
+        spec: {
+          version: 1,
+          author: 'Anton Medvedev',
+        },
+        notes: 'This is a multiline string.\nKeeps formatting as‑is.\n',
+      })
+    })
   })
 
   test('globby() works', async () => {
.size-limit.json
@@ -19,7 +19,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "128.81 kB",
+    "limit": "128.901 kB",
     "brotli": false,
     "gzip": false
   },
@@ -33,21 +33,21 @@
       "build/globals.js",
       "build/deno.js"
     ],
-    "limit": "820.20 kB",
+    "limit": "831.105 kB",
     "brotli": false,
     "gzip": false
   },
   {
     "name": "libdefs",
     "path": "build/*.d.ts",
-    "limit": "41.355 kB",
+    "limit": "41.56 kB",
     "brotli": false,
     "gzip": false
   },
   {
     "name": "vendor",
     "path": "build/vendor-*.{cjs,d.ts}",
-    "limit": "771.40 kB",
+    "limit": "783.35 kB",
     "brotli": false,
     "gzip": false
   },
@@ -66,7 +66,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "878.45 kB",
+    "limit": "889.66 kB",
     "brotli": false,
     "gzip": false
   }
lefthook.yml
@@ -2,7 +2,7 @@ pre-commit:
   parallel: true
   commands:
     format:
-      glob: '*.{js,ts,md,yml}'
+      glob: '*.{js,ts,md,yml,yaml}'
       run: npm run fmt && git add {staged_files}
 
 commit-msg:
package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "zx",
-  "version": "8.8.5",
+  "version": "8.9.0",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "zx",
-      "version": "8.8.5",
+      "version": "8.9.0",
       "license": "Apache-2.0",
       "bin": {
         "zx": "build/cli.js"
@@ -17,7 +17,7 @@
         "@size-limit/file": "11.2.0",
         "@types/fs-extra": "11.0.4",
         "@types/minimist": "1.2.5",
-        "@types/node": "24.7.2",
+        "@types/node": "24.10.0",
         "@types/which": "3.0.4",
         "@webpod/ingrid": "1.1.1",
         "@webpod/ps": "1.0.0",
@@ -28,7 +28,7 @@
         "depseek": "0.4.3",
         "dts-bundle-generator": "9.5.1",
         "envapi": "0.2.3",
-        "esbuild": "0.25.10",
+        "esbuild": "0.25.12",
         "esbuild-node-externals": "1.18.0",
         "esbuild-plugin-entry-chunks": "0.1.17",
         "esbuild-plugin-extract-helpers": "0.0.6",
@@ -40,8 +40,9 @@
         "get-port": "7.1.0",
         "globby": "15.0.0",
         "jsr": "0.13.5",
-        "lefthook": "1.13.6",
+        "lefthook": "2.0.2",
         "madge": "8.0.0",
+        "maml.js": "^0.0.3",
         "minimist": "1.2.8",
         "node-fetch-native": "1.6.7",
         "prettier": "3.6.2",
@@ -821,9 +822,9 @@
       }
     },
     "node_modules/@esbuild/aix-ppc64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz",
-      "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
+      "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
       "cpu": [
         "ppc64"
       ],
@@ -838,9 +839,9 @@
       }
     },
     "node_modules/@esbuild/android-arm": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz",
-      "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
+      "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
       "cpu": [
         "arm"
       ],
@@ -855,9 +856,9 @@
       }
     },
     "node_modules/@esbuild/android-arm64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz",
-      "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
+      "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
       "cpu": [
         "arm64"
       ],
@@ -872,9 +873,9 @@
       }
     },
     "node_modules/@esbuild/android-x64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz",
-      "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
+      "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
       "cpu": [
         "x64"
       ],
@@ -889,9 +890,9 @@
       }
     },
     "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz",
-      "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+      "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
       "cpu": [
         "arm64"
       ],
@@ -906,9 +907,9 @@
       }
     },
     "node_modules/@esbuild/darwin-x64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz",
-      "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
+      "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
       "cpu": [
         "x64"
       ],
@@ -923,9 +924,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz",
-      "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
+      "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
       "cpu": [
         "arm64"
       ],
@@ -940,9 +941,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz",
-      "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
+      "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
       "cpu": [
         "x64"
       ],
@@ -957,9 +958,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz",
-      "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
+      "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
       "cpu": [
         "arm"
       ],
@@ -974,9 +975,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz",
-      "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
+      "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
       "cpu": [
         "arm64"
       ],
@@ -991,9 +992,9 @@
       }
     },
     "node_modules/@esbuild/linux-ia32": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz",
-      "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
+      "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
       "cpu": [
         "ia32"
       ],
@@ -1008,9 +1009,9 @@
       }
     },
     "node_modules/@esbuild/linux-loong64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz",
-      "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
+      "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
       "cpu": [
         "loong64"
       ],
@@ -1025,9 +1026,9 @@
       }
     },
     "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz",
-      "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
+      "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
       "cpu": [
         "mips64el"
       ],
@@ -1042,9 +1043,9 @@
       }
     },
     "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz",
-      "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
+      "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
       "cpu": [
         "ppc64"
       ],
@@ -1059,9 +1060,9 @@
       }
     },
     "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz",
-      "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
+      "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
       "cpu": [
         "riscv64"
       ],
@@ -1076,9 +1077,9 @@
       }
     },
     "node_modules/@esbuild/linux-s390x": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz",
-      "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
+      "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
       "cpu": [
         "s390x"
       ],
@@ -1093,9 +1094,9 @@
       }
     },
     "node_modules/@esbuild/linux-x64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz",
-      "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
+      "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
       "cpu": [
         "x64"
       ],
@@ -1110,9 +1111,9 @@
       }
     },
     "node_modules/@esbuild/netbsd-arm64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz",
-      "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
+      "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
       "cpu": [
         "arm64"
       ],
@@ -1127,9 +1128,9 @@
       }
     },
     "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz",
-      "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
+      "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
       "cpu": [
         "x64"
       ],
@@ -1144,9 +1145,9 @@
       }
     },
     "node_modules/@esbuild/openbsd-arm64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz",
-      "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
+      "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
       "cpu": [
         "arm64"
       ],
@@ -1161,9 +1162,9 @@
       }
     },
     "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz",
-      "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
+      "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
       "cpu": [
         "x64"
       ],
@@ -1178,9 +1179,9 @@
       }
     },
     "node_modules/@esbuild/openharmony-arm64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz",
-      "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
+      "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
       "cpu": [
         "arm64"
       ],
@@ -1195,9 +1196,9 @@
       }
     },
     "node_modules/@esbuild/sunos-x64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz",
-      "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
+      "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
       "cpu": [
         "x64"
       ],
@@ -1212,9 +1213,9 @@
       }
     },
     "node_modules/@esbuild/win32-arm64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz",
-      "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
+      "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
       "cpu": [
         "arm64"
       ],
@@ -1229,9 +1230,9 @@
       }
     },
     "node_modules/@esbuild/win32-ia32": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz",
-      "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
+      "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
       "cpu": [
         "ia32"
       ],
@@ -1246,9 +1247,9 @@
       }
     },
     "node_modules/@esbuild/win32-x64": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz",
-      "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
+      "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
       "cpu": [
         "x64"
       ],
@@ -2126,13 +2127,13 @@
       "license": "MIT"
     },
     "node_modules/@types/node": {
-      "version": "24.7.2",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.2.tgz",
-      "integrity": "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==",
+      "version": "24.10.0",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz",
+      "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "undici-types": "~7.14.0"
+        "undici-types": "~7.16.0"
       }
     },
     "node_modules/@types/normalize-package-data": {
@@ -3778,9 +3779,9 @@
       }
     },
     "node_modules/esbuild": {
-      "version": "0.25.10",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz",
-      "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==",
+      "version": "0.25.12",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+      "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
       "dev": true,
       "hasInstallScript": true,
       "license": "MIT",
@@ -3791,32 +3792,32 @@
         "node": ">=18"
       },
       "optionalDependencies": {
-        "@esbuild/aix-ppc64": "0.25.10",
-        "@esbuild/android-arm": "0.25.10",
-        "@esbuild/android-arm64": "0.25.10",
-        "@esbuild/android-x64": "0.25.10",
-        "@esbuild/darwin-arm64": "0.25.10",
-        "@esbuild/darwin-x64": "0.25.10",
-        "@esbuild/freebsd-arm64": "0.25.10",
-        "@esbuild/freebsd-x64": "0.25.10",
-        "@esbuild/linux-arm": "0.25.10",
-        "@esbuild/linux-arm64": "0.25.10",
-        "@esbuild/linux-ia32": "0.25.10",
-        "@esbuild/linux-loong64": "0.25.10",
-        "@esbuild/linux-mips64el": "0.25.10",
-        "@esbuild/linux-ppc64": "0.25.10",
-        "@esbuild/linux-riscv64": "0.25.10",
-        "@esbuild/linux-s390x": "0.25.10",
-        "@esbuild/linux-x64": "0.25.10",
-        "@esbuild/netbsd-arm64": "0.25.10",
-        "@esbuild/netbsd-x64": "0.25.10",
-        "@esbuild/openbsd-arm64": "0.25.10",
-        "@esbuild/openbsd-x64": "0.25.10",
-        "@esbuild/openharmony-arm64": "0.25.10",
-        "@esbuild/sunos-x64": "0.25.10",
-        "@esbuild/win32-arm64": "0.25.10",
-        "@esbuild/win32-ia32": "0.25.10",
-        "@esbuild/win32-x64": "0.25.10"
+        "@esbuild/aix-ppc64": "0.25.12",
+        "@esbuild/android-arm": "0.25.12",
+        "@esbuild/android-arm64": "0.25.12",
+        "@esbuild/android-x64": "0.25.12",
+        "@esbuild/darwin-arm64": "0.25.12",
+        "@esbuild/darwin-x64": "0.25.12",
+        "@esbuild/freebsd-arm64": "0.25.12",
+        "@esbuild/freebsd-x64": "0.25.12",
+        "@esbuild/linux-arm": "0.25.12",
+        "@esbuild/linux-arm64": "0.25.12",
+        "@esbuild/linux-ia32": "0.25.12",
+        "@esbuild/linux-loong64": "0.25.12",
+        "@esbuild/linux-mips64el": "0.25.12",
+        "@esbuild/linux-ppc64": "0.25.12",
+        "@esbuild/linux-riscv64": "0.25.12",
+        "@esbuild/linux-s390x": "0.25.12",
+        "@esbuild/linux-x64": "0.25.12",
+        "@esbuild/netbsd-arm64": "0.25.12",
+        "@esbuild/netbsd-x64": "0.25.12",
+        "@esbuild/openbsd-arm64": "0.25.12",
+        "@esbuild/openbsd-x64": "0.25.12",
+        "@esbuild/openharmony-arm64": "0.25.12",
+        "@esbuild/sunos-x64": "0.25.12",
+        "@esbuild/win32-arm64": "0.25.12",
+        "@esbuild/win32-ia32": "0.25.12",
+        "@esbuild/win32-x64": "0.25.12"
       }
     },
     "node_modules/esbuild-node-externals": {
@@ -5056,9 +5057,9 @@
       }
     },
     "node_modules/lefthook": {
-      "version": "1.13.6",
-      "resolved": "https://registry.npmjs.org/lefthook/-/lefthook-1.13.6.tgz",
-      "integrity": "sha512-ojj4/4IJ29Xn4drd5emqVgilegAPN3Kf0FQM2p/9+lwSTpU+SZ1v4Ig++NF+9MOa99UKY8bElmVrLhnUUNFh5g==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/lefthook/-/lefthook-2.0.2.tgz",
+      "integrity": "sha512-2lrSva53G604ZWjK5kHYvDdwb5GzbhciIPWhebv0A8ceveqSsnG2JgVEt+DnhOPZ4VfNcXvt3/ohFBPNpuAlVw==",
       "dev": true,
       "hasInstallScript": true,
       "license": "MIT",
@@ -5066,22 +5067,22 @@
         "lefthook": "bin/index.js"
       },
       "optionalDependencies": {
-        "lefthook-darwin-arm64": "1.13.6",
-        "lefthook-darwin-x64": "1.13.6",
-        "lefthook-freebsd-arm64": "1.13.6",
-        "lefthook-freebsd-x64": "1.13.6",
-        "lefthook-linux-arm64": "1.13.6",
-        "lefthook-linux-x64": "1.13.6",
-        "lefthook-openbsd-arm64": "1.13.6",
-        "lefthook-openbsd-x64": "1.13.6",
-        "lefthook-windows-arm64": "1.13.6",
-        "lefthook-windows-x64": "1.13.6"
+        "lefthook-darwin-arm64": "2.0.2",
+        "lefthook-darwin-x64": "2.0.2",
+        "lefthook-freebsd-arm64": "2.0.2",
+        "lefthook-freebsd-x64": "2.0.2",
+        "lefthook-linux-arm64": "2.0.2",
+        "lefthook-linux-x64": "2.0.2",
+        "lefthook-openbsd-arm64": "2.0.2",
+        "lefthook-openbsd-x64": "2.0.2",
+        "lefthook-windows-arm64": "2.0.2",
+        "lefthook-windows-x64": "2.0.2"
       }
     },
     "node_modules/lefthook-darwin-arm64": {
-      "version": "1.13.6",
-      "resolved": "https://registry.npmjs.org/lefthook-darwin-arm64/-/lefthook-darwin-arm64-1.13.6.tgz",
-      "integrity": "sha512-m6Lb77VGc84/Qo21Lhq576pEvcgFCnvloEiP02HbAHcIXD0RTLy9u2yAInrixqZeaz13HYtdDaI7OBYAAdVt8A==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/lefthook-darwin-arm64/-/lefthook-darwin-arm64-2.0.2.tgz",
+      "integrity": "sha512-x/4AOinpMS2abZyA/krDd50cRPZit/6P670Z1mJjfS0+fPZkFw7AXpjxroiN0rgglg78vD7BwcA5331z4YZa5g==",
       "cpu": [
         "arm64"
       ],
@@ -5093,9 +5094,9 @@
       ]
     },
     "node_modules/lefthook-darwin-x64": {
-      "version": "1.13.6",
-      "resolved": "https://registry.npmjs.org/lefthook-darwin-x64/-/lefthook-darwin-x64-1.13.6.tgz",
-      "integrity": "sha512-CoRpdzanu9RK3oXR1vbEJA5LN7iB+c7hP+sONeQJzoOXuq4PNKVtEaN84Gl1BrVtCNLHWFAvCQaZPPiiXSy8qg==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/lefthook-darwin-x64/-/lefthook-darwin-x64-2.0.2.tgz",
+      "integrity": "sha512-MSb8XZBfmlNvCpuLiQqrJS+sPiSEAyuoHOMZOHjlceYqO0leVVw9YfePVcb4Vi/PqOYngTdJk83MmYvqhsSNTQ==",
       "cpu": [
         "x64"
       ],
@@ -5107,9 +5108,9 @@
       ]
     },
     "node_modules/lefthook-freebsd-arm64": {
-      "version": "1.13.6",
-      "resolved": "https://registry.npmjs.org/lefthook-freebsd-arm64/-/lefthook-freebsd-arm64-1.13.6.tgz",
-      "integrity": "sha512-X4A7yfvAJ68CoHTqP+XvQzdKbyd935sYy0bQT6Ajz7FL1g7hFiro8dqHSdPdkwei9hs8hXeV7feyTXbYmfjKQQ==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/lefthook-freebsd-arm64/-/lefthook-freebsd-arm64-2.0.2.tgz",
+      "integrity": "sha512-gewPsUPc3J/n2/RrhHLS9jtL3qK4HcTED25vfExhvFRW3eT1SDYaBbXnUUmB8SE0zE8Bl6AfEdT2zzZcPbOFuA==",
       "cpu": [
         "arm64"
       ],
@@ -5121,9 +5122,9 @@
       ]
     },
     "node_modules/lefthook-freebsd-x64": {
-      "version": "1.13.6",
-      "resolved": "https://registry.npmjs.org/lefthook-freebsd-x64/-/lefthook-freebsd-x64-1.13.6.tgz",
-      "integrity": "sha512-ai2m+Sj2kGdY46USfBrCqLKe9GYhzeq01nuyDYCrdGISePeZ6udOlD1k3lQKJGQCHb0bRz4St0r5nKDSh1x/2A==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/lefthook-freebsd-x64/-/lefthook-freebsd-x64-2.0.2.tgz",
+      "integrity": "sha512-fsLlaChiKAWiSavQO2LXPR8Z9OcBnyMDvmkIlXC0lG3SjBb9xbVdBdDVlcrsUyDCs5YstmGYHuzw6DfJYpAE1g==",
       "cpu": [
         "x64"
       ],
@@ -5135,9 +5136,9 @@
       ]
     },
     "node_modules/lefthook-linux-arm64": {
-      "version": "1.13.6",
-      "resolved": "https://registry.npmjs.org/lefthook-linux-arm64/-/lefthook-linux-arm64-1.13.6.tgz",
-      "integrity": "sha512-cbo4Wtdq81GTABvikLORJsAWPKAJXE8Q5RXsICFUVznh5PHigS9dFW/4NXywo0+jfFPCT6SYds2zz4tCx6DA0Q==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/lefthook-linux-arm64/-/lefthook-linux-arm64-2.0.2.tgz",
+      "integrity": "sha512-vNl3HiZud9T2nGHMngvLw3hSJgutjlN/Lzf5/5jKt/2IIuyd9L3UYktWC9HLUb03Zukr7jeaxG3+VxdAohQwAw==",
       "cpu": [
         "arm64"
       ],
@@ -5149,9 +5150,9 @@
       ]
     },
     "node_modules/lefthook-linux-x64": {
-      "version": "1.13.6",
-      "resolved": "https://registry.npmjs.org/lefthook-linux-x64/-/lefthook-linux-x64-1.13.6.tgz",
-      "integrity": "sha512-uJl9vjCIIBTBvMZkemxCE+3zrZHlRO7Oc+nZJ+o9Oea3fu+W82jwX7a7clw8jqNfaeBS+8+ZEQgiMHWCloTsGw==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/lefthook-linux-x64/-/lefthook-linux-x64-2.0.2.tgz",
+      "integrity": "sha512-0ghHMPu4fixIieS8V2k2yZHvcFd9pP0q+sIAIaWo8x7ce/AOQIXFCPHGPAOc8/wi5uVtfyEvCnhxIDKf+lHA2A==",
       "cpu": [
         "x64"
       ],
@@ -5163,9 +5164,9 @@
       ]
     },
     "node_modules/lefthook-openbsd-arm64": {
-      "version": "1.13.6",
-      "resolved": "https://registry.npmjs.org/lefthook-openbsd-arm64/-/lefthook-openbsd-arm64-1.13.6.tgz",
-      "integrity": "sha512-7r153dxrNRQ9ytRs2PmGKKkYdvZYFPre7My7XToSTiRu5jNCq++++eAKVkoyWPduk97dGIA+YWiEr5Noe0TK2A==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/lefthook-openbsd-arm64/-/lefthook-openbsd-arm64-2.0.2.tgz",
+      "integrity": "sha512-qfXnDM8jffut9rylvi3T+HOqlNRkFYqIDUXeVXlY7dmwCW4u2K46p0W4M3BmAVUeL/MRxBRnjze//Yy6aCbGQw==",
       "cpu": [
         "arm64"
       ],
@@ -5177,9 +5178,9 @@
       ]
     },
     "node_modules/lefthook-openbsd-x64": {
-      "version": "1.13.6",
-      "resolved": "https://registry.npmjs.org/lefthook-openbsd-x64/-/lefthook-openbsd-x64-1.13.6.tgz",
-      "integrity": "sha512-Z+UhLlcg1xrXOidK3aLLpgH7KrwNyWYE3yb7ITYnzJSEV8qXnePtVu8lvMBHs/myzemjBzeIr/U/+ipjclR06g==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/lefthook-openbsd-x64/-/lefthook-openbsd-x64-2.0.2.tgz",
+      "integrity": "sha512-RXqR0FiDTwsQv1X3QVsuBFneWeNXS+tmPFIX8F6Wz9yDPHF8+vBnkWCju6HdkTVTY71Ba5HbYGKEVDvscJkU7Q==",
       "cpu": [
         "x64"
       ],
@@ -5191,9 +5192,9 @@
       ]
     },
     "node_modules/lefthook-windows-arm64": {
-      "version": "1.13.6",
-      "resolved": "https://registry.npmjs.org/lefthook-windows-arm64/-/lefthook-windows-arm64-1.13.6.tgz",
-      "integrity": "sha512-Uxef6qoDxCmUNQwk8eBvddYJKSBFglfwAY9Y9+NnnmiHpWTjjYiObE9gT2mvGVpEgZRJVAatBXc+Ha5oDD/OgQ==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/lefthook-windows-arm64/-/lefthook-windows-arm64-2.0.2.tgz",
+      "integrity": "sha512-KfLKhiUPHP9Aea+9D7or2hgL9wtKEV+GHpx7LBg82ZhCXkAml6rop7mWsBgL80xPYLqMahKolZGO+8z5H6W4HQ==",
       "cpu": [
         "arm64"
       ],
@@ -5205,9 +5206,9 @@
       ]
     },
     "node_modules/lefthook-windows-x64": {
-      "version": "1.13.6",
-      "resolved": "https://registry.npmjs.org/lefthook-windows-x64/-/lefthook-windows-x64-1.13.6.tgz",
-      "integrity": "sha512-mOZoM3FQh3o08M8PQ/b3IYuL5oo36D9ehczIw1dAgp1Ly+Tr4fJ96A+4SEJrQuYeRD4mex9bR7Ps56I73sBSZA==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/lefthook-windows-x64/-/lefthook-windows-x64-2.0.2.tgz",
+      "integrity": "sha512-TdysWxGRNtuRg5bN6Uj00tZJIsHTrF/7FavoR5rp1sq21QJhJi36M4I3UVlmOKAUCKhibAIAauZWmX7yaW3eHA==",
       "cpu": [
         "x64"
       ],
@@ -5460,6 +5461,13 @@
       "dev": true,
       "license": "ISC"
     },
+    "node_modules/maml.js": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/maml.js/-/maml.js-0.0.3.tgz",
+      "integrity": "sha512-Vy1xhxfMJM+k+qN+N28ywWno9tuffufZqG+YcK3AiNvndzh83Z1ZV6QUQnzEjSfLutTa1f4VAdm9UslATePYEw==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/map-obj": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
@@ -7734,9 +7742,9 @@
       }
     },
     "node_modules/undici-types": {
-      "version": "7.14.0",
-      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
-      "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
+      "version": "7.16.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+      "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
       "dev": true,
       "license": "MIT"
     },
package.json
@@ -1,6 +1,6 @@
 {
   "name": "zx",
-  "version": "8.8.5",
+  "version": "8.9.0",
   "description": "A tool for writing better scripts",
   "type": "module",
   "main": "./build/index.cjs",
@@ -114,7 +114,7 @@
     "@size-limit/file": "11.2.0",
     "@types/fs-extra": "11.0.4",
     "@types/minimist": "1.2.5",
-    "@types/node": "24.7.2",
+    "@types/node": "24.10.0",
     "@types/which": "3.0.4",
     "@webpod/ingrid": "1.1.1",
     "@webpod/ps": "1.0.0",
@@ -125,7 +125,7 @@
     "depseek": "0.4.3",
     "dts-bundle-generator": "9.5.1",
     "envapi": "0.2.3",
-    "esbuild": "0.25.10",
+    "esbuild": "0.25.12",
     "esbuild-node-externals": "1.18.0",
     "esbuild-plugin-entry-chunks": "0.1.17",
     "esbuild-plugin-extract-helpers": "0.0.6",
@@ -137,8 +137,9 @@
     "get-port": "7.1.0",
     "globby": "15.0.0",
     "jsr": "0.13.5",
-    "lefthook": "1.13.6",
+    "lefthook": "2.0.2",
     "madge": "8.0.0",
+    "maml.js": "^0.0.3",
     "minimist": "1.2.8",
     "node-fetch-native": "1.6.7",
     "prettier": "3.6.2",