@master4n/master-cli 3.0.4 → 3.0.6
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/README.md +11 -1
- package/SECURITY.md +1 -1
- package/bin/index.js +2 -2
- package/bin/index.js.map +1 -1
- package/bin/utility/mcp-server.d.ts +8 -1
- package/llms.txt +3 -2
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import e from"yargs";import{format as t}from"util";import n,{resolve as o,normalize as r}from"path";import s,{readFileSync as i,writeFile as a,statSync as l}from"fs";import"assert";import{fileURLToPath as c}from"url";import d from"chalk";import m,{platform as u,homedir as p}from"node:os";import f from"fs-extra";import{execFile as h}from"node:child_process";import g from"fuzzy";import{parseToEpoch as y,getEpochNow as b,convertEpochToTimezone as v,convertEpoch as x}from"@master4n/temporal-transformer";import{promisify as w}from"node:util";import{platform as $}from"os";import{randomBytes as j,randomUUID as S,getHashes as N,createHash as k}from"node:crypto";import{readFile as E}from"node:fs/promises";import I from"node:path";import O,{existsSync as A}from"node:fs";import{createServer as T,createConnection as M}from"node:net";import{lookup as L,resolve4 as C,resolve6 as _,resolveCname as z,resolveMx as
|
|
2
|
+
import e from"yargs";import{format as t}from"util";import n,{resolve as o,normalize as r}from"path";import s,{readFileSync as i,writeFile as a,statSync as l}from"fs";import"assert";import{fileURLToPath as c}from"url";import d from"chalk";import m,{platform as u,homedir as p}from"node:os";import f from"fs-extra";import{execFile as h}from"node:child_process";import g from"fuzzy";import{parseToEpoch as y,getEpochNow as b,convertEpochToTimezone as v,convertEpoch as x}from"@master4n/temporal-transformer";import{promisify as w}from"node:util";import{platform as $}from"os";import{randomBytes as j,randomUUID as S,getHashes as N,createHash as k}from"node:crypto";import{readFile as E}from"node:fs/promises";import I from"node:path";import O,{existsSync as A}from"node:fs";import{createServer as T,createConnection as M}from"node:net";import{lookup as L,resolve4 as C,resolve6 as _,resolveCname as z,resolveMx as P,resolveTxt as R,resolveNs as F}from"node:dns/promises";import{createInterface as D}from"node:readline";function B(){return process.versions.electron&&!process.defaultApp?0:1}
|
|
3
3
|
/**
|
|
4
4
|
* @license
|
|
5
5
|
* Copyright (c) 2016, Contributors
|
|
@@ -32,5 +32,5 @@ var G,H,V;const Y=process&&process.env&&process.env.YARGS_MIN_NODE_VERSION?Numbe
|
|
|
32
32
|
* Copyright (c) 2016, Contributors
|
|
33
33
|
* SPDX-License-Identifier: ISC
|
|
34
34
|
*/
|
|
35
|
-
function(e){if(Array.isArray(e))return e.map(e=>"string"!=typeof e?e+"":e);e=e.trim();let t=0,n=null,o=null,r=null;const s=[];for(let i=0;i<e.length;i++)n=o,o=e.charAt(i)," "!==o||r?(o===r?r=null:"'"!==o&&'"'!==o||r||(r=o),s[t]||(s[t]=""),s[t]+=o):" "!==n&&t++;return s}(e),r="string"==typeof e,s=function(e){const t=[],n=Object.create(null);let o=!0;Object.keys(e).forEach(function(n){t.push([].concat(e[n],n))});for(;o;){o=!1;for(let e=0;e<t.length;e++)for(let n=e+1;n<t.length;n++){if(t[e].filter(function(e){return-1!==t[n].indexOf(e)}).length){t[e]=t[e].concat(t[n]),t.splice(n,1),o=!0;break}}}return t.forEach(function(e){const t=(e=e.filter(function(e,t,n){return n.indexOf(e)===t})).pop();void 0!==t&&"string"==typeof t&&(n[t]=e)}),n}(Object.assign(Object.create(null),n.alias)),i=Object.assign({"boolean-negation":!0,"camel-case-expansion":!0,"combine-arrays":!1,"dot-notation":!0,"duplicate-arguments-array":!0,"flatten-duplicate-arrays":!0,"greedy-arrays":!0,"halt-at-non-option":!1,"nargs-eats-options":!1,"negation-prefix":"no-","parse-numbers":!0,"parse-positional-numbers":!0,"populate--":!1,"set-placeholder-key":!1,"short-option-groups":!0,"strip-aliased":!1,"strip-dashed":!1,"unknown-options-as-args":!1},n.configuration),a=Object.assign(Object.create(null),n.default),l=n.configObjects||[],c=n.envPrefix,d=i["populate--"],m=d?"--":"_",u=Object.create(null),p=Object.create(null),f=n.__||W.format,h={aliases:Object.create(null),arrays:Object.create(null),bools:Object.create(null),strings:Object.create(null),numbers:Object.create(null),counts:Object.create(null),normalize:Object.create(null),configs:Object.create(null),nargs:Object.create(null),coercions:Object.create(null),keys:[]},g=/^-([0-9]+(\.[0-9]+)?|\.[0-9]+)$/,y=new RegExp("^--"+i["negation-prefix"]+"(.+)");[].concat(n.array||[]).filter(Boolean).forEach(function(e){const t="object"==typeof e?e.key:e,n=Object.keys(e).map(function(e){return{boolean:"bools",string:"strings",number:"numbers"}[e]}).filter(Boolean).pop();n&&(h[n][t]=!0),h.arrays[t]=!0,h.keys.push(t)}),[].concat(n.boolean||[]).filter(Boolean).forEach(function(e){h.bools[e]=!0,h.keys.push(e)}),[].concat(n.string||[]).filter(Boolean).forEach(function(e){h.strings[e]=!0,h.keys.push(e)}),[].concat(n.number||[]).filter(Boolean).forEach(function(e){h.numbers[e]=!0,h.keys.push(e)}),[].concat(n.count||[]).filter(Boolean).forEach(function(e){h.counts[e]=!0,h.keys.push(e)}),[].concat(n.normalize||[]).filter(Boolean).forEach(function(e){h.normalize[e]=!0,h.keys.push(e)}),"object"==typeof n.narg&&Object.entries(n.narg).forEach(([e,t])=>{"number"==typeof t&&(h.nargs[e]=t,h.keys.push(e))}),"object"==typeof n.coerce&&Object.entries(n.coerce).forEach(([e,t])=>{"function"==typeof t&&(h.coercions[e]=t,h.keys.push(e))}),void 0!==n.config&&(Array.isArray(n.config)||"string"==typeof n.config?[].concat(n.config).filter(Boolean).forEach(function(e){h.configs[e]=!0}):"object"==typeof n.config&&Object.entries(n.config).forEach(([e,t])=>{"boolean"!=typeof t&&"function"!=typeof t||(h.configs[e]=t)})),function(...e){e.forEach(function(e){Object.keys(e||{}).forEach(function(e){h.aliases[e]||(h.aliases[e]=[].concat(s[e]||[]),h.aliases[e].concat(e).forEach(function(t){if(/-/.test(t)&&i["camel-case-expansion"]){const n=U(t);n!==e&&-1===h.aliases[e].indexOf(n)&&(h.aliases[e].push(n),u[n]=!0)}}),h.aliases[e].concat(e).forEach(function(t){if(t.length>1&&/[A-Z]/.test(t)&&i["camel-case-expansion"]){const n=function(e,t){const n=e.toLowerCase();t=t||"-";let o="";for(let r=0;r<e.length;r++){const s=n.charAt(r),i=e.charAt(r);o+=s!==i&&r>0?`${t}${n.charAt(r)}`:i}return o}(t,"-");n!==e&&-1===h.aliases[e].indexOf(n)&&(h.aliases[e].push(n),u[n]=!0)}}),h.aliases[e].forEach(function(t){h.aliases[t]=[e].concat(h.aliases[e].filter(function(e){return t!==e}))}))})})}(n.key,s,n.default,h.arrays),Object.keys(a).forEach(function(e){(h.aliases[e]||[]).forEach(function(t){a[t]=a[e]})});let b=null;Object.keys(h.counts).find(e=>C(e,h.arrays)?(b=Error(f("Invalid configuration: %s, opts.count excludes opts.array.",e)),!0):!!C(e,h.nargs)&&(b=Error(f("Invalid configuration: %s, opts.count excludes opts.narg.",e)),!0));let v=[];const x=Object.assign(Object.create(null),{_:[]}),w={};for(let e=0;e<o.length;e++){const t=o[e],n=t.replace(/^-{3,}/,"---");let r,s,a,l,c,d;if("--"!==t&&/^-/.test(t)&&z(t))$(t);else{if(n.match(/^---+(=|$)/)){$(t);continue}if(t.match(/^--.+=/)||!i["short-option-groups"]&&t.match(/^-.+=/))l=t.match(/^--?([^=]+)=([\s\S]*)$/),null!==l&&Array.isArray(l)&&l.length>=3&&(C(l[1],h.arrays)?e=S(e,l[1],o,l[2]):!1!==C(l[1],h.nargs)?e=j(e,l[1],o,l[2]):N(l[1],l[2],!0));else if(t.match(y)&&i["boolean-negation"])l=t.match(y),null!==l&&Array.isArray(l)&&l.length>=2&&(s=l[1],N(s,!!C(s,h.arrays)&&[!1]));else if(t.match(/^--.+/)||!i["short-option-groups"]&&t.match(/^-[^-]+/))l=t.match(/^--?(.+)/),null!==l&&Array.isArray(l)&&l.length>=2&&(s=l[1],C(s,h.arrays)?e=S(e,s,o):!1!==C(s,h.nargs)?e=j(e,s,o):(c=o[e+1],void 0===c||c.match(/^-/)&&!c.match(g)||C(s,h.bools)||C(s,h.counts)?/^(true|false)$/.test(c)?(N(s,c),e++):N(s,R(s)):(N(s,c),e++)));else if(t.match(/^-.\..+=/))l=t.match(/^-([^=]+)=([\s\S]*)$/),null!==l&&Array.isArray(l)&&l.length>=3&&N(l[1],l[2]);else if(t.match(/^-.\..+/)&&!t.match(g))c=o[e+1],l=t.match(/^-(.\..+)/),null!==l&&Array.isArray(l)&&l.length>=2&&(s=l[1],void 0===c||c.match(/^-/)||C(s,h.bools)||C(s,h.counts)?N(s,R(s)):(N(s,c),e++));else if(t.match(/^-[^-]+/)&&!t.match(g)){a=t.slice(1,-1).split(""),r=!1;for(let n=0;n<a.length;n++){if(c=t.slice(n+2),a[n+1]&&"="===a[n+1]){d=t.slice(n+3),s=a[n],C(s,h.arrays)?e=S(e,s,o,d):!1!==C(s,h.nargs)?e=j(e,s,o,d):N(s,d),r=!0;break}if("-"!==c){if(/[A-Za-z]/.test(a[n])&&/^-?\d+(\.\d*)?(e-?\d+)?$/.test(c)&&!1===C(c,h.bools)){N(a[n],c),r=!0;break}if(a[n+1]&&a[n+1].match(/\W/)){N(a[n],c),r=!0;break}N(a[n],R(a[n]))}else N(a[n],c)}s=t.slice(-1)[0],r||"-"===s||(C(s,h.arrays)?e=S(e,s,o):!1!==C(s,h.nargs)?e=j(e,s,o):(c=o[e+1],void 0===c||/^(-|--)[^-]/.test(c)&&!c.match(g)||C(s,h.bools)||C(s,h.counts)?/^(true|false)$/.test(c)?(N(s,c),e++):N(s,R(s)):(N(s,c),e++)))}else if(t.match(/^-[0-9]$/)&&t.match(g)&&C(t.slice(1),h.bools))s=t.slice(1),N(s,R(s));else{if("--"===t){v=o.slice(e+1);break}if(i["halt-at-non-option"]){v=o.slice(e);break}$(t)}}}function $(e){const t=I("_",e);"string"!=typeof t&&"number"!=typeof t||x._.push(t)}function j(e,t,n,o){let r,s=C(t,h.nargs);if(s="number"!=typeof s||isNaN(s)?1:s,0===s)return P(o)||(b=Error(f("Argument unexpected for: %s",t))),N(t,R(t)),e;let a=P(o)?0:1;if(i["nargs-eats-options"])n.length-(e+1)+a<s&&(b=Error(f("Not enough arguments following: %s",t))),a=s;else{for(r=e+1;r<n.length&&(!n[r].match(/^-[^0-9]/)||n[r].match(g)||z(n[r]));r++)a++;a<s&&(b=Error(f("Not enough arguments following: %s",t)))}let l=Math.min(a,s);for(!P(o)&&l>0&&(N(t,o),l--),r=e+1;r<l+e+1;r++)N(t,n[r]);return e+l}function S(e,t,n,o){let s=[],l=o||n[e+1];const c=C(t,h.nargs);if(C(t,h.bools)&&!/^(true|false)$/.test(l))s.push(!0);else if(P(l)||P(o)&&/^-/.test(l)&&!g.test(l)&&!z(l)){if(void 0!==a[t]){const e=a[t];s=Array.isArray(e)?e:[e]}}else{P(o)||s.push(E(t,o,!0));for(let o=e+1;o<n.length&&!(!i["greedy-arrays"]&&s.length>0||c&&"number"==typeof c&&s.length>=c)&&(l=n[o],!/^-/.test(l)||g.test(l)||z(l));o++)e=o,s.push(E(t,l,r))}return"number"==typeof c&&(c&&s.length<c||isNaN(c)&&0===s.length)&&(b=Error(f("Not enough arguments following: %s",t))),N(t,s),e}function N(e,t,n=r){if(/-/.test(e)&&i["camel-case-expansion"]){const t=e.split(".").map(function(e){return U(e)}).join(".");k(e,t)}const o=E(e,t,n),s=e.split(".");if(L(x,s,o),h.aliases[e]&&h.aliases[e].forEach(function(e){const t=e.split(".");L(x,t,o)}),s.length>1&&i["dot-notation"]&&(h.aliases[s[0]]||[]).forEach(function(t){let n=t.split(".");const r=[].concat(s);r.shift(),n=n.concat(r),(h.aliases[e]||[]).includes(n.join("."))||L(x,n,o)}),C(e,h.normalize)&&!C(e,h.arrays)){[e].concat(h.aliases[e]||[]).forEach(function(e){Object.defineProperty(w,e,{enumerable:!0,get:()=>t,set(e){t="string"==typeof e?W.normalize(e):e}})})}}function k(e,t){h.aliases[e]&&h.aliases[e].length||(h.aliases[e]=[t],u[t]=!0),h.aliases[t]&&h.aliases[t].length||k(t,e)}function E(e,t,n){n&&(t=function(e){return"string"!=typeof e||"'"!==e[0]&&'"'!==e[0]||e[e.length-1]!==e[0]?e:e.substring(1,e.length-1)}(t)),(C(e,h.bools)||C(e,h.counts))&&"string"==typeof t&&(t="true"===t);let o=Array.isArray(t)?t.map(function(t){return I(e,t)}):I(e,t);return C(e,h.counts)&&(P(o)||"boolean"==typeof o)&&(o=q()),C(e,h.normalize)&&C(e,h.arrays)&&(o=Array.isArray(t)?t.map(e=>W.normalize(e)):W.normalize(t)),o}function I(e,t){if(!i["parse-positional-numbers"]&&"_"===e)return t;if(!C(e,h.strings)&&!C(e,h.bools)&&!Array.isArray(t)){(null!=(n=t)&&("number"==typeof n||!!/^0x[0-9a-f]+$/i.test(n)||!/^0[^.]/.test(n)&&/^[-]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(n))&&i["parse-numbers"]&&Number.isSafeInteger(Math.floor(parseFloat(`${t}`)))||!P(t)&&C(e,h.numbers))&&(t=Number(t))}var n;return t}function O(e,t){Object.keys(e).forEach(function(n){const o=e[n],r=t?t+"."+n:n;"object"==typeof o&&null!==o&&!Array.isArray(o)&&i["dot-notation"]?O(o,r):(!M(x,r.split("."))||C(r,h.arrays)&&i["combine-arrays"])&&N(r,o)})}function A(e,t){if(void 0===c)return;const n="string"==typeof c?c:"",o=W.env();Object.keys(o).forEach(function(r){if(""===n||0===r.lastIndexOf(n,0)){const s=r.split("__").map(function(e,t){return 0===t&&(e=e.substring(n.length)),U(e)});(t&&h.configs[s.join(".")]||!t)&&!M(e,s)&&N(s.join("."),o[r])}})}function T(e,t,n,o=!1){Object.keys(n).forEach(function(r){M(e,r.split("."))||(L(e,r.split("."),n[r]),o&&(p[r]=!0),(t[r]||[]).forEach(function(t){M(e,t.split("."))||L(e,t.split("."),n[r])}))})}function M(e,t){let n=e;i["dot-notation"]||(t=[t.join(".")]),t.slice(0,-1).forEach(function(e){n=n[e]||{}});const o=t[t.length-1];return"object"==typeof n&&o in n}function L(e,t,n){let o=e;i["dot-notation"]||(t=[t.join(".")]),t.slice(0,-1).forEach(function(e){e=Z(e),"object"==typeof o&&void 0===o[e]&&(o[e]={}),"object"!=typeof o[e]||Array.isArray(o[e])?(Array.isArray(o[e])?o[e].push({}):o[e]=[o[e],{}],o=o[e][o[e].length-1]):o=o[e]});const r=Z(t[t.length-1]),s=C(t.join("."),h.arrays),a=Array.isArray(n);let l=i["duplicate-arguments-array"];!l&&C(r,h.nargs)&&(l=!0,(!P(o[r])&&1===h.nargs[r]||Array.isArray(o[r])&&o[r].length===h.nargs[r])&&(o[r]=void 0)),n===q()?o[r]=q(o[r]):Array.isArray(o[r])?l&&s&&a?o[r]=i["flatten-duplicate-arrays"]?o[r].concat(n):(Array.isArray(o[r][0])?o[r]:[o[r]]).concat([n]):l||Boolean(s)!==Boolean(a)?o[r]=o[r].concat([n]):o[r]=n:void 0===o[r]&&s?o[r]=a?n:[n]:!l||void 0===o[r]||C(r,h.counts)||C(r,h.bools)?o[r]=n:o[r]=[o[r],n]}function C(e,t){const n=[].concat(h.aliases[e]||[],e),o=Object.keys(t),r=n.find(e=>o.includes(e));return!!r&&t[r]}function _(e){const t=Object.keys(h);return[].concat(t.map(e=>h[e])).some(function(t){return Array.isArray(t)?t.includes(e):t[e]})}function z(e){return i["unknown-options-as-args"]&&function(e){if(e=e.replace(/^-{3,}/,"--"),e.match(g))return!1;if(function(e){if(e.match(g)||!e.match(/^-[^-]+/))return!1;let t,n=!0;const o=e.slice(1).split("");for(let r=0;r<o.length;r++){if(t=e.slice(r+2),!_(o[r])){n=!1;break}if(o[r+1]&&"="===o[r+1]||"-"===t||/[A-Za-z]/.test(o[r])&&/^-?\d+(\.\d*)?(e-?\d+)?$/.test(t)||o[r+1]&&o[r+1].match(/\W/))break}return n}(e))return!1;return!function(e,...t){return[].concat(...t).some(function(t){const n=e.match(t);return n&&_(n[1])})}(e,/^-+([^=]+?)=[\s\S]*$/,y,/^-+([^=]+?)$/,/^-+([^=]+?)-$/,/^-+([^=]+?\d+)$/,/^-+([^=]+?)\W+.*$/)}(e)}function R(e){return C(e,h.bools)||C(e,h.counts)||!(`${e}`in a)?(t=function(e){let t=J.BOOLEAN;return C(e,h.strings)?t=J.STRING:C(e,h.numbers)?t=J.NUMBER:C(e,h.bools)?t=J.BOOLEAN:C(e,h.arrays)&&(t=J.ARRAY),t}(e),{[J.BOOLEAN]:!0,[J.STRING]:"",[J.NUMBER]:void 0,[J.ARRAY]:[]}[t]):a[e];var t}function P(e){return void 0===e}return A(x,!0),A(x,!1),function(e){const t=Object.create(null);T(t,h.aliases,a),Object.keys(h.configs).forEach(function(n){const o=e[n]||t[n];if(o)try{let e=null;const t=W.resolve(W.cwd(),o),r=h.configs[n];if("function"==typeof r){try{e=r(t)}catch(t){e=t}if(e instanceof Error)return void(b=e)}else e=W.require(t);O(e)}catch(t){"PermissionDenied"===t.name?b=t:e[n]&&(b=Error(f("Invalid JSON config file: %s",o)))}})}(x),void 0!==l&&l.forEach(function(e){O(e)}),T(x,h.aliases,a,!0),function(e){let t;const n=new Set;Object.keys(e).forEach(function(o){if(!n.has(o)&&(t=C(o,h.coercions),"function"==typeof t))try{const r=I(o,t(e[o]));[].concat(h.aliases[o]||[],o).forEach(t=>{n.add(t),e[t]=r})}catch(e){b=e}})}(x),i["set-placeholder-key"]&&function(e){h.keys.forEach(t=>{~t.indexOf(".")||void 0===e[t]&&(e[t]=void 0)})}(x),Object.keys(h.counts).forEach(function(e){M(x,e.split("."))||N(e,0)}),d&&v.length&&(x[m]=[]),v.forEach(function(e){x[m].push(e)}),i["camel-case-expansion"]&&i["strip-dashed"]&&Object.keys(x).filter(e=>"--"!==e&&e.includes("-")).forEach(e=>{delete x[e]}),i["strip-aliased"]&&[].concat(...Object.keys(s).map(e=>s[e])).forEach(e=>{i["camel-case-expansion"]&&e.includes("-")&&delete x[e.split(".").map(e=>U(e)).join(".")],delete x[e]}),{aliases:Object.assign({},h.aliases),argv:Object.assign(w,x),configuration:i,defaulted:Object.assign({},p),error:b,newAliases:Object.assign({},u)}}}({cwd:process.cwd,env:()=>Q,format:t,normalize:r,resolve:o,require:e=>{if("undefined"!=typeof require)return require(e);if(e.match(/\.json$/))return JSON.parse(i(e,"utf8"));throw Error("only .json config files are supported in ESM")}});var X={fs:{readFileSync:i,writeFile:a},format:t,resolve:o,exists:e=>{try{return l(e).isFile()}catch(e){return!1}}};let ee;class te{constructor(e){e=e||{},this.directory=e.directory||"./locales",this.updateFiles="boolean"!=typeof e.updateFiles||e.updateFiles,this.locale=e.locale||"en",this.fallbackToLanguage="boolean"!=typeof e.fallbackToLanguage||e.fallbackToLanguage,this.cache=Object.create(null),this.writeQueue=[]}__(...e){if("string"!=typeof arguments[0])return this._taggedLiteral(arguments[0],...arguments);const t=e.shift();let n=function(){};return"function"==typeof e[e.length-1]&&(n=e.pop()),n=n||function(){},this.cache[this.locale]||this._readLocaleFile(),!this.cache[this.locale][t]&&this.updateFiles?(this.cache[this.locale][t]=t,this._enqueueWrite({directory:this.directory,locale:this.locale,cb:n})):n(),ee.format.apply(ee.format,[this.cache[this.locale][t]||t].concat(e))}__n(){const e=Array.prototype.slice.call(arguments),t=e.shift(),n=e.shift(),o=e.shift();let r=function(){};"function"==typeof e[e.length-1]&&(r=e.pop()),this.cache[this.locale]||this._readLocaleFile();let s=1===o?t:n;if(this.cache[this.locale][t]){s=this.cache[this.locale][t][1===o?"one":"other"]}!this.cache[this.locale][t]&&this.updateFiles?(this.cache[this.locale][t]={one:t,other:n},this._enqueueWrite({directory:this.directory,locale:this.locale,cb:r})):r();const i=[s];return~s.indexOf("%d")&&i.push(o),ee.format.apply(ee.format,i.concat(e))}setLocale(e){this.locale=e}getLocale(){return this.locale}updateLocale(e){this.cache[this.locale]||this._readLocaleFile();for(const t in e)Object.prototype.hasOwnProperty.call(e,t)&&(this.cache[this.locale][t]=e[t])}_taggedLiteral(e,...t){let n="";return e.forEach(function(e,o){const r=t[o+1];n+=e,void 0!==r&&(n+="%s")}),this.__.apply(this,[n].concat([].slice.call(t,1)))}_enqueueWrite(e){this.writeQueue.push(e),1===this.writeQueue.length&&this._processWriteQueue()}_processWriteQueue(){const e=this,t=this.writeQueue[0],n=t.directory,o=t.locale,r=t.cb,s=this._resolveLocaleFile(n,o),i=JSON.stringify(this.cache[o],null,2);ee.fs.writeFile(s,i,"utf-8",function(t){e.writeQueue.shift(),e.writeQueue.length>0&&e._processWriteQueue(),r(t)})}_readLocaleFile(){let e={};const t=this._resolveLocaleFile(this.directory,this.locale);try{ee.fs.readFileSync&&(e=JSON.parse(ee.fs.readFileSync(t,"utf-8")))}catch(n){if(n instanceof SyntaxError&&(n.message="syntax error in "+t),"ENOENT"!==n.code)throw n;e={}}this.cache[this.locale]=e}_resolveLocaleFile(e,t){let n=ee.resolve(e,"./",t+".json");if(this.fallbackToLanguage&&!this._fileExistsSync(n)&&~t.lastIndexOf("_")){const o=ee.resolve(e,"./",t.split("_")[0]+".json");this._fileExistsSync(o)&&(n=o)}return n}_fileExistsSync(e){return ee.exists(e)}}let ne;try{ne=c(import.meta.url)}catch(e){ne=process.cwd()}ne.substring(0,ne.lastIndexOf("node_modules"))||process.cwd(),process.cwd,process.exit,process.nextTick,void 0!==process.stdout.columns&&process.stdout.columns,function(e,t){ee=t;const n=new te(e);n.__.bind(n),n.__n.bind(n),n.setLocale.bind(n),n.getLocale.bind(n),n.updateLocale.bind(n),n.locale}({directory:o(ne,"../../../locales"),updateFiles:!1},X);const oe=[{name:"capabilities",category:"discovery",summary:"Self-describing manifest of every command an agent can call",examples:["mfn capabilities --json"]},{name:"mcp",category:"discovery",summary:"Serve every command over the Model Context Protocol (stdio) for MCP clients",examples:["mfn mcp","mfn mcp --json"]},{name:"epoch",category:"time",summary:"Convert between epoch timestamps and dates (auto-detects unit)",examples:["mfn epoch 1622547800 --json","mfn epoch --from 2021-06-01T11:43:20Z --json"]},{name:"date",category:"time",summary:"Convert/format a date across timezones (defaults to now)",examples:["mfn date --json","mfn date 2024-07-04T15:30:30Z --tz America/New_York --json"]},{name:"decode",category:"crypto",summary:"Decode a JWT token (header + payload; signature not verified)",examples:["mfn decode -t <jwt> --json"]},{name:"kill",category:"net",summary:"Kill the process(es) listening on specific ports",examples:["mfn kill -p 3000 8080 -y --json"]},{name:"sc",category:"code",summary:"Find files/folders under the current directory (fuzzy match)",examples:["mfn sc service --json"]},{name:"cts",category:"code",summary:"Print (or export) a tree of the current working directory",examples:["mfn cts --json","mfn cts -t png"]},{name:"update",category:"discovery",summary:"Update the CLI or a specified package to the latest version",examples:["mfn update --json","mfn update <package> --json"]},{name:"id",category:"crypto",summary:"Generate identifiers (UUID v4/v7 or URL-safe nano id)",examples:["mfn id --json","mfn id -t uuid7 -n 3 --json"]},{name:"hash",category:"crypto",summary:"Hash a string, file, or stdin (md5/sha1/sha256/sha512)",examples:["mfn hash hello --json","mfn hash -a md5 -f ./file.txt --json"]},{name:"encode",category:"crypto",summary:"Encode/decode text (base64, base64url, hex, url)",examples:["mfn encode hello --json","mfn encode aGVsbG8= -d --json"]},{name:"random",category:"crypto",summary:"Generate secure random bytes or a password",examples:["mfn random --json","mfn random -p -l 32 --json"]},{name:"port",category:"net",summary:"Find a free port, or check whether a specific port is available",examples:["mfn port --json","mfn port -c 3000 --json"]},{name:"json",category:"data",summary:"Extract one value/keys/length from JSON without reading the whole document",examples:["mfn json scripts.build -f package.json --json","cat d.json | mfn json users[0].name --json"]},{name:"schema",category:"data",summary:"Infer the shape of a JSON document (paths + types) without dumping the data",examples:["mfn schema -f response.json --json","curl -s api/u | mfn schema --json"]},{name:"count",category:"text",summary:"Lines/words/chars/bytes + LLM token estimate of a file, stdin, or text",examples:["mfn count -f big.log --json","git diff | mfn count --json"]},{name:"lines",category:"text",summary:"Read an exact line range of a file (1-based) instead of the whole file",examples:["mfn lines src/app.ts -s 120 -n 30 --json"]},{name:"diff",category:"text",summary:"Line diff of two files as structured hunks (counts first, content optional)",examples:["mfn diff old.json new.json --json","mfn diff a.txt b.txt -s --json"]},{name:"freq",category:"text",summary:"Most frequent lines of a file/stdin (log analysis in one call)",examples:["mfn freq error.log -t 5 --json"]},{name:"case",category:"text",summary:"Convert strings between naming styles (camel, snake, kebab, pascal, …)",examples:["mfn case getUserName -t snake --json","mfn case my-component --json"]},{name:"escape",category:"text",summary:"Escape text exactly for shell, JSON, regex, HTML, or URL contexts",examples:['mfn escape "it\'s done" --json',"mfn escape 1.2.3 -a regex --json"]},{name:"calc",category:"data",summary:"Exact arithmetic — integer math in BigInt, no float drift, no guessing",examples:['mfn calc "2^53 + 1" --json','mfn calc "(3 + 4) * 5" --json']},{name:"semver",category:"data",summary:"Validate, compare, sort, or bump semantic versions per semver.org",examples:["mfn semver 1.10.0 1.9.2 --json","mfn semver 1.2.3 -b minor --json"]},{name:"cron",category:"time",summary:"Validate a cron expression, explain it, and compute the next run times",examples:['mfn cron "*/15 9-17 * * 1-5" --json','mfn cron "@daily" -n 1 --json']},{name:"regex",category:"text",summary:"Test a regular expression against text — verify instead of guessing",examples:['mfn regex "TODO[:!]?" -f src/app.ts --json']},{name:"url",category:"data",summary:"Parse a URL into components with decoded query parameters",examples:['mfn url "https://api.x.com/v2/users?id=42" --json']},{name:"have",category:"system",summary:"Check which tools are installed (path + version) in one call",examples:["mfn have node git docker --json"]},{name:"sys",category:"system",summary:"One-shot system facts: OS, node, CPU, memory, shell, timezone, paths",examples:["mfn sys --json"]},{name:"repo",category:"code",summary:"One-shot git summary: branch, dirty counts, ahead/behind, last commits",examples:["mfn repo --json","mfn repo -n 10 --json"]},{name:"env",category:"system",summary:"Inspect environment variables with automatic secret redaction",examples:["mfn env NODE_ENV PATH --json","mfn env -p NEXT_PUBLIC_ --json"]},{name:"size",category:"code",summary:"Total size + largest files/dirs under a directory in one call",examples:["mfn size --json","mfn size ./src -t 5 --json"]},{name:"ext",category:"code",summary:"File counts and bytes per extension — project composition at a glance",examples:["mfn ext --json"]},{name:"ip",category:"net",summary:"Local network interfaces and addresses (no ifconfig parsing)",examples:["mfn ip --json"]},{name:"outline",category:"code",summary:"Outline a source file: functions/classes/exports with line numbers",examples:["mfn outline src/app.ts --json","mfn outline README.md --json"]},{name:"imports",category:"code",summary:"List a file’s imports, or find every file that imports a module",examples:["mfn imports src/app.ts --json","mfn imports --who utility --json"]},{name:"replace",category:"code",summary:"Literal find/replace across files — dry-run by default, JSON change report",examples:['mfn replace "oldName" "newName" -g "src/**/*.ts" --json','mfn replace "v1" "v2" -g "**/*.md" --write --json']},{name:"recent",category:"code",summary:"Most recently modified files under a directory, with age",examples:["mfn recent --json","mfn recent ./src -t 5 --json"]},{name:"pkg",category:"code",summary:"Declared vs installed dependency versions — drift in one call",examples:["mfn pkg --json","mfn pkg typescript --json"]},{name:"dotenv",category:"system",summary:"Check .env against .env.example — missing/extra keys, values never shown",examples:["mfn dotenv --json","mfn dotenv -f .env.local -e .env.example --json"]},{name:"wait",category:"net",summary:"Block until a port, file, or URL is ready (with timeout) — no sleep loops",examples:["mfn wait -p 3000 -t 30 --json","mfn wait -u http://localhost:3000/health --json"]},{name:"ports",category:"net",summary:"List ALL listening TCP ports with their owning processes",examples:["mfn ports --json"]},{name:"http",category:"net",summary:"Probe a URL: status, headers, timing, capped body preview",examples:["mfn http https://api.github.com --json","mfn http localhost:3000/health --json"]},{name:"base",category:"data",summary:"Convert numbers between bases (hex/dec/bin/oct) exactly, BigInt-safe",examples:["mfn base 0xff --json","mfn base 255 --json"]},{name:"clip",category:"system",summary:"Read or write the system clipboard (pbcopy/xclip/clip.exe handled for you)",examples:["mfn clip --json","git diff | mfn clip --json"]},{name:"notify",category:"system",summary:"Desktop notification — tell the user a long task finished, hands-free",examples:['mfn notify "build finished" --json']},{name:"open",category:"system",summary:"Open a file or URL in the default app/browser (target validated first)",examples:["mfn open coverage/index.html --json"]},{name:"procs",category:"system",summary:"Search running processes by name: pid/cpu/mem in one call",examples:["mfn procs node --json","mfn procs -t 10 --json"]},{name:"disk",category:"system",summary:"Disk usage per mount (total/free/used%) without df parsing",examples:["mfn disk --json"]},{name:"trash",category:"system",summary:"Move files/dirs to the OS trash — reversible delete, never rm -rf",examples:["mfn trash old-build.log --json","mfn trash dist coverage --json"]},{name:"dns",category:"net",summary:"Resolve a hostname: A/AAAA/CNAME/MX/TXT/NS in one call",examples:["mfn dns github.com --json","mfn dns example.com -t mx --json"]}],re=[...new Set(oe.map(e=>e.category))];var se="@master4n/master-cli",ie="3.0.4";const ae=["add --json to any command for clean, machine-readable output","piping a command (no TTY) auto-emits JSON — great for agents & scripts","every command returns a stable exit code: 0 = ok, non-zero = failure","mfn <command> --help shows its flags and copy-paste examples","mfn capabilities --json lists every command an agent can call","mfn kill -p 3000 8080 -y frees stuck ports in one shot"],le=e=>d.hex(e)("─".repeat(62)),ce=()=>(new Date).toISOString();function de(){return{info:e=>console.error(`${d.blue("INFO")} [${d.magenta(ce())}] ${d.white(e)}`),warn:e=>console.error(`${d.yellow("WARN")} [${d.magenta(ce())}] ${d.white(e)}`),error:e=>console.error(`${d.red("ERROR")} [${d.magenta(ce())}] ${d.white(e)}`),debug:e=>console.error(`${d.cyan("DEBUG")} [${d.magenta(ce())}] ${d.white(e)}`)}}function me(){const e=m.homedir();return n.join(e,".mfn","cache")}const ue=e=>d.green(e);async function pe(e,t){await f.writeJson(t,e,{spaces:2})}!function(){const e=m.homedir(),t=n.join(e,".mfn","cache");if(!s.existsSync(t))try{s.mkdirSync(t,{recursive:!0,mode:448})}catch{}}(),await(async()=>{if(!(Boolean(process.stdout.isTTY)&&!process.argv.includes("--json")))return;const[{default:e},{default:t}]=await Promise.all([import("figlet"),import("boxen")]),n=await new Promise((t,n)=>{e("M4N-CLI",(e,o)=>e?n(e):t(o??""))}),o=t(d.hex("#27A244").bold(n),{padding:1,margin:{top:1,bottom:0,left:1,right:1},borderStyle:"round",borderColor:"#C1C110",dimBorder:!0}),r=function(){try{return(m.userInfo().username||"").replace(/[^\p{L}\p{N} ._-]/gu,"").slice(0,32)}catch{return""}}(),s=d.dim(" • "),i=[d.hex("#44bcd8").bold(`mfn v${ie}`),d.gray(`node ${process.version}`),d.gray(`${process.platform}/${process.arch}`),d.green.bold("AI-friendly")].join(s);let a="";try{const{getEpochNow:e}=await import("@master4n/temporal-transformer"),t=e();a=`${t.iso.replace("T"," ").slice(0,19)} ${d.dim(`(${t.timezone})`)}`}catch{}const l=new Map;for(const e of oe)l.set(e.category,(l.get(e.category)??0)+1);const c=[...l.entries()].map(([e,t])=>`${d.cyan(e)}${d.dim(`(${t})`)}`).join(d.dim(" · "))+d.dim(" → mfn capabilities"),u=ae[Math.floor(Math.random()*ae.length)],p=(e="")=>console.error(e);p(le("#C1C110")),p(o),p(" "+(r?d.magenta(`👋 Welcome, ${d.bold(r)}`):d.magenta("👋 Welcome"))+s+i),a&&p(" "+d.gray("🕒 ")+d.white(a)),p(""),p(" "+d.yellow.bold("🧰 tools ")+c),p(" "+d.yellow.bold("💡 tip ")+d.white(u)),p(" "+d.yellow.bold("🤖 help ")+d.white("mfn <command> --help")),p(le("#C1C110"))})();const fe=e(process.argv.slice(B()+1));const he=d.hex("#44bcd8").bold("mfn");var ge=fe.scriptName(he);const ye=()=>Boolean(process.stdout.isTTY),be=e=>e.option("json",{type:"boolean",default:!1,describe:"Emit a single machine-readable JSON object on stdout"}),ve=e=>Boolean(e?.json)||!ye(),xe=e=>{process.stdout.write(JSON.stringify(e)+"\n")};function we(e,t,n){ve(e)?xe({ok:!0,...t}):n()}function $e(e,t,n,o=1){ve(e)?xe({ok:!1,error:t,message:n}):console.error(n),process.exit(o)}const je=e=>ye()&&!e?.json;async function Se(){if(process.stdin.isTTY)return"";const e=[];for await(const t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf8")}function Ne(e,t,n=2){process.argv.includes("--json")||!ye()?process.stdout.write(JSON.stringify({ok:!1,error:e,message:t})+"\n"):console.error(t),process.exit(n)}const ke=de(),Ee=n.join(me(),"cts_ignore.json"),Ie=["node_modules",".git",".nx"];function Oe(e,t,o=""){let r,s="";try{r=f.readdirSync(e).filter(e=>!t.has(e)).sort()}catch{return`${o}└── [unreadable]\n`}return r.forEach((i,a)=>{const l=n.join(e,i),c=a===r.length-1;let d;try{d=f.statSync(l).isDirectory()}catch{d=!1}s+=`${o}${c?"└── ":"├── "}${i}\n`,d&&(s+=Oe(l,t,`${o}${c?" ":"│ "}`))}),s}const Ae={command:"cts",describe:"Print (or export) a tree of the current working directory",builder:e=>be(e).option("type",{alias:"t",describe:"Output format: text (stdout, default) or an image file",type:"string",choices:["text","svg","png","jpeg"],default:"text"}).option("ignore",{alias:"i",describe:"Folder names to ignore",type:"array"}).option("length",{alias:"l",describe:"Image height",type:"number",default:250}).option("breadth",{alias:"b",describe:"Image width",type:"number",default:200}).example("mfn cts","print the tree as text").example("mfn cts --json","tree as JSON").example("mfn cts -t png","export the tree to <dir>.png"),handler:async e=>{let t=e.ignore??[];t.length>0?await pe({ignores:t},Ee).catch(()=>{}):t=(await async function(){try{return await f.readJson(Ee)}catch(e){if("ENOENT"===e.code)return{ignores:[]};throw e}}()).ignores??[];const o=new Set([...Ie,...t]),r=process.cwd(),s=n.basename(r);let i;try{i=s+"\n"+Oe(r,o)}catch(t){return $e(e,"TreeError",`Failed to build tree for ${r}: ${t instanceof Error?t.message:String(t)}`)}const a=String(e.type);if("text"===a)return we(e,{root:s,path:r,format:"text",tree:i},()=>{process.stdout.write(i.endsWith("\n")?i:i+"\n")});if(!function(...e){for(const t of e)if(isNaN(t)||t<1||t>1e3)return!1;return!0}(e.length,e.breadth))return $e(e,"InvalidDimensions","Length & breadth must be numbers in 1..1000.",2);const l=`${s}.${a}`;try{const t=function(e,t,n){return`<svg xmlns="http://www.w3.org/2000/svg" width="${n}" height="${t}"><rect width="100%" height="100%" fill="white"/><g fill="black" font-family="monospace" font-size="12">${e.split("\n").map((e,t)=>`<text style="white-space: pre;" x="0" y="${20+20*t}">${e.replace(/&/g,"&").replace(/</g,"<")}</text>`).join("")}</g></svg>`}(i,e.length,e.breadth);if("svg"===a)f.outputFileSync(l,t);else{const{default:e}=await import("sharp");await e(Buffer.from(t))["png"===a?"png":"jpeg"]().toFile(l)}}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,"ExportFailed",`Failed to write ${l}: ${n}`)}we(e,{root:s,path:r,format:a,file:l},()=>ke.info(`Tree for ${s} written to ${l}`))}},Te=de(),Me=n.join(me(),"sc_ignore.json"),Le=["node_modules",".git","dist","build",".nx","coverage"];function Ce(e,t,o){const r=[],s=new Set([...Le,...t]),i=(t,a)=>{if(a>o)return;let l;try{l=f.readdirSync(t,{withFileTypes:!0})}catch{return}for(const o of l){if(s.has(o.name))continue;const l=n.join(t,o.name),c=n.relative(e,l);r.push(o.isDirectory()?c+n.sep:c),o.isDirectory()&&i(l,a+1)}};return i(e,0),r}const _e={command:"sc [pattern]",describe:"Find files/folders under the current directory (fuzzy match)",builder:e=>be(e).positional("pattern",{describe:"Fuzzy pattern to match against paths (omit to list all)",type:"string"}).option("ignore",{alias:"i",describe:"Additional directory names to ignore",type:"array"}).option("depth",{type:"number",default:6,describe:"Max recursion depth"}).option("limit",{type:"number",default:500,describe:"Max results returned"}).example("mfn sc service --json",'find paths matching "service"'),handler:async e=>{const t=process.cwd(),o=Number(e.depth),r=Number(e.limit);if(!Number.isInteger(o)||o<0)return $e(e,"InvalidDepth","--depth must be a non-negative integer.",2);if(!Number.isInteger(r)||r<1)return $e(e,"InvalidLimit","--limit must be a positive integer.",2);let s=e.ignore??[];if(s.length>0?await pe({ignores:s},Me).catch(()=>{}):s=(await async function(){try{return await f.readJson(Me)}catch(e){if("ENOENT"===e.code)return{ignores:[]};throw e}}()).ignores??[],void 0===e.pattern&&je(e))return async function(e,t,o,r,s){const{default:i}=await import("inquirer"),a=Ce(t,o,r),{pattern:l}=await i.prompt([{type:"input",name:"pattern",message:ue("Filter (fuzzy, blank = all):")}]),c=String(l??"").trim(),d=(c?g.filter(c,a).map(e=>e.original):a).slice(0,s);if(0===d.length)return we(e,{pattern:c||null,root:t,count:0,matches:[]},()=>Te.warn("No matches."));const{selected:m}=await i.prompt([{type:"list",name:"selected",message:ue("Select a path:"),choices:d,pageSize:15,loop:!1}]),u=f.statSync(n.join(t,m));we(e,{path:m,type:u.isDirectory()?"directory":"file"},()=>{Te.info(`${u.isDirectory()?"Directory":"File"}: ${m}`),u.isDirectory()&&Te.info(`cd ${m}`)})}(e,t,s,o,r);const i=Ce(t,s,o),a=e.pattern?g.filter(String(e.pattern),i).map(e=>e.original):i,l=a.slice(0,r);we(e,{pattern:e.pattern??null,root:t,count:l.length,truncated:a.length>l.length,matches:l},()=>{Te.info(`${l.length} match(es) under ${t}`);for(const e of l)console.log(e)})}},ze=de();function Re(e){const t=Buffer.from(e,"base64url").toString("utf-8");return JSON.parse(t)}const Pe={command:"decode",describe:"Decode a JWT token (header + payload; signature not verified)",builder:e=>be(e).option("token",{alias:"t",describe:'JWT token to decode (a leading "Bearer " is stripped)',type:"string",demandOption:!0}).example("mfn decode -t <jwt> --json","decode a JWT"),handler:e=>{const t=String(e.token).replace(/^Bearer\s+/i,"").trim().split(".");if(3!==t.length)return $e(e,"InvalidJWT","Invalid JWT structure: expected three dot-separated segments.",2);let n,o;try{n=Re(t[0]),o=Re(t[1])}catch(t){return $e(e,"DecodeError",`Could not decode JWT: ${t instanceof Error?t.message:String(t)}`,2)}const r=o?.exp;let s;if("number"==typeof r&&Number.isFinite(r)){const e=Math.round(r-Date.now()/1e3);s={exp:r,expired:e<=0,expiresInSeconds:e}}we(e,{header:n,payload:o,...s?{expiry:s}:{}},()=>{ze.info("Decoded JWT (signature NOT verified)"),console.log(d.cyanBright.bold("header:")),console.log(d.greenBright(JSON.stringify(n,null,2))),console.log(d.cyanBright.bold("payload:")),console.log(d.greenBright(JSON.stringify(o,null,2))),s&&console.log(d.cyanBright.bold("expiry: ")+(s.expired?d.red(`expired ${-s.expiresInSeconds}s ago`):d.green(`valid for ${s.expiresInSeconds}s`)))})}},Fe=de(),De="yyyy-MM-dd HH:mm:ss",Be=()=>Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC";function Ue(e){const t=e.format||De,n=e.tz||Be();let o,r,s;try{o=void 0!==e.from?y(String(e.from),e.inFormat,e.inTz).epochInMilliseconds:b().milliseconds}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,t instanceof Error?t.name:"ParseError",n,2)}try{r=v(o,"UTC",t),s=v(o,n,t)}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,t instanceof Error?t.name:"TimezoneError",n,2)}we(e,{epochInSeconds:Math.floor(o/1e3),epochInMilliseconds:o,iso:new Date(o).toISOString(),utc:r,zoned:s,timezone:n,format:t},()=>{Fe.info("Date conversion"),console.table([{UTC:r,[n]:s,Epoch_ms:o}])})}const Je={command:"date [from]",describe:"Convert/format a date across timezones (defaults to now)",builder:e=>be(e).positional("from",{describe:"Date string to convert (ISO 8601 unless --in-format given). Omit for now.",type:"string"}).option("tz",{type:"string",describe:"Target output timezone (IANA; default: local)"}).option("format",{type:"string",describe:`Output format (default: ${De})`}).option("in-format",{type:"string",describe:"Luxon parse format for the input"}).option("in-tz",{type:"string",describe:"Timezone used to interpret the input"}).example("mfn date --json","now, in UTC + local").example("mfn date 2024-07-04T15:30:30Z --tz America/New_York --json","convert to a timezone"),handler:async e=>{const t={from:e.from,inFormat:e["in-format"],inTz:e["in-tz"],tz:e.tz,format:e.format,json:e.json};if(void 0===e.from&&void 0===e.tz&&void 0===e.format&&je(e))return async function(e){const{default:t}=await import("inquirer"),n=await t.prompt([{type:"input",name:"from",message:ue("Date string (blank = now, ISO 8601):")},{type:"input",name:"tz",message:ue(`Target timezone (blank = ${Be()}):`)},{type:"input",name:"format",message:ue(`Output format (blank = ${De}):`)}]);Ue({...e,from:n.from?.trim()||void 0,tz:n.tz?.trim()||void 0,format:n.format?.trim()||void 0})}(t);Ue(t)}};const We=de();function qe(e,t){let n;try{n=x(t)}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,t instanceof Error?t.name:"InvalidEpoch",n,2)}const o={seconds:1e3,milliseconds:1,microseconds:.001,nanoseconds:1e-6}[n.epochUnit]??1;we(e,{epoch:n.epoch,unit:n.epochUnit,iso:new Date(Math.round(n.epoch*o)).toISOString(),utc:n.dateTimeInGMT,local:n.dateTime,timezone:n.timezone,relative:n.relative},()=>{We.info("Epoch → date"),console.table([{Epoch:`${n.epoch} (${n.epochUnit})`,Local:n.dateTime,GMT:n.dateTimeInGMT,Relative:n.relative}])})}function Ze(e,t,n,o){let r,s;try{r=y(t,n,o)}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,t instanceof Error?t.name:"ParseError",n,2)}try{s=x(r.epochInSeconds).relative}catch{s=void 0}we(e,{epochInSeconds:r.epochInSeconds,epochInMilliseconds:r.epochInMilliseconds,iso:new Date(r.epochInMilliseconds).toISOString(),utc:r.dateTimeInGMT,local:r.dateTime,timezone:r.timezone,relative:s},()=>{We.info("Date → epoch"),console.table([{Seconds:r.epochInSeconds,Milliseconds:r.epochInMilliseconds,Local:r.dateTime,GMT:r.dateTimeInGMT,Timezone:r.timezone}])})}const Ge={command:"epoch [value]",describe:"Convert between epoch timestamps and dates (auto-detects unit)",builder:e=>be(e).positional("value",{describe:"Epoch value to convert to a date (s / ms / µs / ns auto-detected)",type:"string"}).option("from",{type:"string",describe:"A date string to convert TO epoch (ISO 8601 unless --format given)"}).option("format",{type:"string",describe:'Luxon parse format for --from (e.g. "dd/MM/yyyy")'}).option("tz",{type:"string",describe:"IANA timezone used to interpret --from (default: local)"}).example("mfn epoch 1622547800 --json","epoch → date").example("mfn epoch --from 2021-06-01T11:43:20Z --json","date → epoch"),handler:async e=>{if(void 0!==e.from)return Ze(e,String(e.from),e.format,e.tz);if(void 0!==e.value&&null!==e.value){const t=String(e.value).trim();return""===t?$e(e,"MissingInput","Epoch value is empty. Provide a numeric epoch.",2):qe(e,Number(t))}if(je(e))return async function(e,t,n){const{default:o}=await import("inquirer"),{operation:r}=await o.prompt([{type:"rawlist",name:"operation",message:ue("What do you want to do?"),choices:[{name:"Convert epoch → human-readable date",value:"epochToDate"},{name:"Convert date string → epoch",value:"dateToEpoch"}]}]);if("epochToDate"===r){const{value:n}=await o.prompt([{type:"input",name:"value",message:ue("Enter epoch value:"),validate:e=>e.trim()&&!isNaN(Number(e))||"Enter a number"}]);t(e,Number(n))}else{const{input:t}=await o.prompt([{type:"input",name:"input",message:ue("Enter a date string (ISO 8601):"),validate:e=>Boolean(e.trim())||"Enter a date string"}]);n(e,t,void 0,e.tz)}}(e,qe,Ze);$e(e,"MissingInput","Provide an epoch <value>, or --from <dateString>. See `mfn epoch --help`.",2)}},He=de(),Ve=w(h),Ye=n.join(me(),"ports.json"),Ke="win32"===$();async function Qe(e){try{if(Ke){const{stdout:t}=await Ve("netstat",["-ano"]),n=t.split("\n").find(t=>t.includes(`:${e}`)&&/LISTENING/i.test(t)),o=n?n.trim().split(/\s+/).pop():null;return o?{port:e,pid:o}:null}const{stdout:t}=await Ve("lsof",["-i",`:${e}`]),n=t.split("\n").find(e=>/LISTEN/.test(e)),o=n?n.trim().split(/\s+/)[1]:null;return o?{port:e,pid:o}:null}catch{return null}}async function Xe(e){if(!/^\d+$/.test(e))throw new Error(`Refusing to kill non-numeric PID "${e}"`);if(Number(e)<=1)throw new Error(`Refusing to kill system PID ${e}`);Ke?await Ve("taskkill",["/PID",e,"/F"]):await Ve("kill",["-9",e])}const et={command:"kill",describe:"Kill the process(es) listening on specific ports",builder:e=>be(e).option("ports",{alias:"p",describe:"Port number(s) to free",type:"array"}).option("yes",{alias:"y",type:"boolean",default:!1,describe:"Kill all matching processes without the interactive prompt"}).example("mfn kill -p 3000 8080 -y --json","free ports 3000 and 8080"),handler:async e=>{const t=e.ports??[];let n=[];for(const o of t){const t=Number(o);if(!Number.isInteger(t)||t<1||t>65535)return $e(e,"InvalidPort",`Invalid port number: ${o} (expected an integer in 1..65535).`,2);n.push(t)}if(0===n.length){const t=je(e)?await async function(){try{return await f.readJson(Ye)}catch(e){if("ENOENT"===e.code)return{ports:[]};throw e}}():{ports:[]};if(!t.ports?.length)return $e(e,"NoPorts","No ports provided. Use -p <port...>. See `mfn kill --help`.",2);n=t.ports,He.info(`Using cached ports [${n.join(", ")}]`)}await pe({ports:n},Ye).catch(()=>{});const o=(await Promise.all(n.map(Qe))).filter(e=>null!==e),r=n.filter(e=>!o.some(t=>t.port===e));if(0===o.length)return we(e,{killed:[],failed:[],notFound:r},()=>He.info(`No processes listening on [${n.join(", ")}]`));let s=o;if(je(e)&&!e.yes){const{default:e}=await import("inquirer"),{pids:t}=await e.prompt([{type:"checkbox",name:"pids",message:ue("Select the processes to kill:"),choices:o.map(e=>({name:`Port ${e.port} → PID ${e.pid}`,value:e.pid}))}]);s=o.filter(e=>t.includes(e.pid))}const i=[],a=[];for(const e of s)try{await Xe(e.pid),i.push(e)}catch(t){a.push({...e,error:t instanceof Error?t.message:String(t)})}we(e,{killed:i,failed:a,notFound:r},()=>{for(const e of i)He.info(`Killed PID ${e.pid} on port ${e.port}`);for(const e of a)He.error(`Failed to kill PID ${e.pid} (port ${e.port}): ${e.error}`);r.length&&He.warn(`No process on [${r.join(", ")}]`)}),a.length>0&&process.exit(1)}},tt=de(),nt=w(h);const ot={command:"update [package]",describe:"Update the CLI or a specified package to the latest version",builder:e=>be(e).positional("package",{describe:"npm package to update globally (default: this CLI)",type:"string",default:"@master4n/master-cli"}).example("mfn update","update master-cli itself to the latest version").example("mfn update typescript --json","update a specific global package"),handler:async e=>{const t=String(e.package??"@master4n/master-cli"),n=je(e)?(await import("ora")).default():null,o=Date.now();n?.start(d.green(`updating/installing ${t}`));try{await async function(e){await nt("npm",["install","-g",e])}(t);const r=await async function(e){try{const{stdout:t}=await nt("npm",["view",e,"version"]);return t.trim()||null}catch{return null}}(t),s=Date.now()-o;n?.succeed(`${d.green(`updated ${t}`)} ${d.dim(`(${(s/1e3).toFixed(3)}s)`)}`),we(e,{package:t,version:r,durationMs:s},()=>{tt.info(`${t} updated/installed${r?` -> ${d.green(r)}`:""}`)})}catch(o){n?.fail(d.red(`failed updating ${t}`));const r=o instanceof Error?o.message:String(o);$e(e,"UpdateFailed",`Failed to update "${t}": ${r}`)}}},rt={command:"capabilities",describe:"List every command an agent can call (self-describing manifest)",builder:e=>be(e).example("mfn capabilities --json","machine-readable manifest"),handler:e=>{we(e,{name:se,version:ie,bin:"mfn",conventions:{json:"pass --json, or pipe (non-TTY auto-emits) — one {ok,...} object on stdout",exitCodes:{ok:0,error:1,usage:2},logs:"banners and logs go to stderr; stdout carries data only"},docs:{readme:"https://github.com/Master4Novice/master-cli#readme",llmsTxt:"https://raw.githubusercontent.com/Master4Novice/master-cli/master/llms.txt",agentNote:"llms.txt ships inside this npm package too — full agent contract and per-command flags"},categories:re,commands:oe.map(e=>({name:e.name,category:e.category,summary:e.summary,examples:e.examples}))},()=>{console.log(`${se} v${ie} (bin: mfn)`),console.log("Commands an agent can call headlessly:");for(const e of re){console.log(`\n [${e}]`);for(const t of oe.filter(t=>t.category===e))console.log(` ${t.name.padEnd(14)} ${t.summary}`)}console.log("\nConventions: --json for machine output · exit 0/1/2 · logs on stderr")})}};function st(e){switch(e){case"uuid":case"uuid4":return S();case"uuid7":return function(){const e=j(16);e.writeUIntBE(Date.now(),0,6),e[6]=15&e[6]|112,e[8]=63&e[8]|128;const t=e.toString("hex");return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`}();default:return""}}const it=1e5,at={command:"id",describe:"Generate identifiers (UUID v4/v7 or URL-safe nano id)",builder:e=>be(e).option("type",{alias:"t",describe:"Identifier type",type:"string",choices:["uuid","uuid4","uuid7","nano"],default:"uuid"}).option("count",{alias:"n",describe:"How many to generate",type:"number",default:1}).option("size",{describe:"Length for --type nano",type:"number",default:21}).example("mfn id --json","one UUID v4").example("mfn id -t uuid7 -n 3 --json","three time-ordered UUID v7").example("mfn id -t nano --size 12 --json","a 12-char URL-safe id"),handler:e=>{const t=String(e.type),n=Number(e.count),o=Number(e.size);if(!Number.isInteger(n)||n<1||n>it)return $e(e,"InvalidCount","--count must be an integer in 1..100000.",2);if("nano"===t&&(!Number.isInteger(o)||o<1||o>4096))return $e(e,"InvalidSize","--size must be an integer in 1..4096.",2);const r=Array.from({length:n},()=>"nano"===t?function(e){let t="";for(;t.length<e;){const n=j(e);for(let o=0;o<n.length&&t.length<e;o++)t+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"[63&n[o]]}return t}(o):st(t));we(e,{type:t,count:n,ids:r},()=>r.forEach(e=>console.log(e)))}},lt=[".ssh",".gnupg",".aws",".kube",".docker",".gcloud",".azure"],ct=[".netrc",".npmrc",".pgpass",".git-credentials","shadow","credentials","otr.private_key"],dt=[/^id_(rsa|dsa|ecdsa|ed25519)(\.|$)/i,/\.(pem|key|p12|pfx|keystore|jks|asc)$/i,/^\.env(\..+)?$/i];function mt(e){const t=I.resolve(e),n=t.split(I.sep).filter(Boolean),o=I.basename(t);return!!n.some(e=>lt.includes(e.toLowerCase()))||(!!ct.includes(o.toLowerCase())||dt.some(e=>e.test(o)))}function ut(e){if(mt(e))return!0;try{const t=O.realpathSync(e);if(t!==I.resolve(e)&&mt(t))return!0}catch{}return!1}const pt=e=>`Refusing to return the contents of "${e}" — it matches a credential/secret location (guardrail, no override; see SECURITY.md).`,ft=[[/-----BEGIN [A-Z ]*PRIVATE KEY-----/,"private key block"],[/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+/,"JWT"],[/\bAKIA[0-9A-Z]{16}\b/,"AWS access key id"],[/\b(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b/,"GitHub token"],[/\bgithub_pat_[A-Za-z0-9_]{22,}\b/,"GitHub fine-grained token"],[/\bsk-[A-Za-z0-9_-]{20,}\b/,"API secret key (sk-…)"],[/\bxox[abpsr]-[A-Za-z0-9-]{10,}\b/,"Slack token"],[/\bAIza[0-9A-Za-z_-]{35}\b/,"Google API key"],[/\bnpm_[A-Za-z0-9]{36}\b/,"npm token"]];function ht(e){for(const[t,n]of ft)if(t.test(e))return n;return null}function gt(e){let t=0,n=e;n=n.replace(/-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g,()=>(t++,"[redacted: private key block]"));for(const[e,o]of ft)n=n.replace(new RegExp(e,"g"),()=>(t++,`[redacted: ${o}]`));return n=n.split("\n").map(e=>{const n=e.trim();return n.length>=40&&/^[A-Za-z0-9+/_-]+={0,2}$/.test(n)&&!n.includes(" ")?(t++,e.replace(n,"[redacted: key material]")):e}).join("\n"),{text:n,redactedCount:t}}function yt(e){const t=e.hostname.toLowerCase().replace(/^\[|\]$/g,"");return"metadata.google.internal"===t||"metadata"===t||(!!/^169\.254\.\d{1,3}\.\d{1,3}$/.test(t)||("fd00:ec2::254"===t||"100.100.100.200"===t))}const bt=e=>`Refusing to request "${e}" — cloud metadata endpoints are blocked (credential-theft guardrail, no override; see SECURITY.md).`,vt=["md5","sha1","sha256","sha512"],xt={command:"hash [text]",describe:"Hash a string, file, or stdin (md5/sha1/sha256/sha512)",builder:e=>be(e).positional("text",{describe:"String to hash (or pipe via stdin, or use --file)",type:"string"}).option("algo",{alias:"a",describe:"Hash algorithm",type:"string",choices:vt,default:"sha256"}).option("file",{alias:"f",describe:"Hash the contents of this file instead",type:"string"}).option("encoding",{alias:"e",describe:"Digest encoding",type:"string",choices:["hex","base64","base64url"],default:"hex"}).example("mfn hash hello --json",'sha256 of "hello"').example("mfn hash -a md5 -f ./file.txt --json","md5 of a file").example("cat file | mfn hash --json","hash piped stdin"),handler:async e=>{const t=String(e.algo),n=String(e.encoding);let o,r;try{if(void 0!==e.file){if(ut(String(e.file)))return $e(e,"SensitivePath",pt(String(e.file)),2);o=await E(String(e.file)),r=`file:${e.file}`}else if(void 0!==e.text)o=Buffer.from(String(e.text),"utf8"),r="text";else{const t=await Se();if(!t)return $e(e,"MissingInput","Provide a string, --file <path>, or pipe stdin.",2);o=Buffer.from(t,"utf8"),r="stdin"}}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}if(!N().includes(t))return $e(e,"UnsupportedAlgo",`Algorithm "${t}" is not available.`,2);const s=k(t).update(o).digest(n);we(e,{algo:t,encoding:n,source:r,bytes:o.length,hash:s},()=>console.log(s))}};const wt={hex:/^[0-9a-fA-F]*$/,base64:/^[A-Za-z0-9+/]*={0,2}$/,base64url:/^[A-Za-z0-9_-]*$/};const $t={command:"encode [text]",describe:"Encode/decode text (base64, base64url, hex, url)",builder:e=>be(e).positional("text",{describe:"Text to (de/en)code (or pipe via stdin)",type:"string"}).option("as",{alias:"a",describe:"Codec",type:"string",choices:["base64","base64url","hex","url"],default:"base64"}).option("decode",{alias:"d",describe:"Decode instead of encode",type:"boolean",default:!1}).example("mfn encode hello --json",'base64-encode "hello"').example("mfn encode aGVsbG8= -d --json","base64-decode").example('mfn encode "a b&c" --as url --json',"url-encode"),handler:async e=>{const t=String(e.as),n=Boolean(e.decode);let o,r;if(void 0!==e.text)o=String(e.text);else if(o=(await Se()).replace(/\n$/,""),!o)return $e(e,"MissingInput","Provide text or pipe stdin.",2);try{r=n?function(e,t){if("url"===t)return decodeURIComponent(e);const n=wt[t],o="hex"===t?e:e.trim();if(!n.test(o)||"hex"===t&&o.length%2!=0)throw new Error(`not valid ${t}`);return Buffer.from(o,t).toString("utf8")}(o,t):function(e,t){switch(t){case"base64":return Buffer.from(e,"utf8").toString("base64");case"base64url":return Buffer.from(e,"utf8").toString("base64url");case"hex":return Buffer.from(e,"utf8").toString("hex");case"url":return encodeURIComponent(e)}}(o,t)}catch(o){return $e(e,"CodecError",`Could not ${n?"decode":"encode"} as ${t}: ${o instanceof Error?o.message:String(o)}`)}we(e,{operation:n?"decode":"encode",codec:t,input:o,output:r},()=>console.log(r))}};const jt=1048576,St={command:"random",describe:"Generate cryptographically secure random bytes or a password",builder:e=>be(e).option("bytes",{alias:"b",describe:"Number of random bytes",type:"number",default:32}).option("encoding",{alias:"e",describe:"Output encoding for bytes",type:"string",choices:["hex","base64","base64url"],default:"hex"}).option("password",{alias:"p",describe:"Generate a password instead of raw bytes",type:"boolean",default:!1}).option("length",{alias:"l",describe:"Password length",type:"number",default:24}).example("mfn random --json","32 secure random bytes as hex").example("mfn random -b 16 -e base64url --json","16 bytes, base64url").example("mfn random -p -l 32 --json","a 32-char password"),handler:e=>{if(e.password){const t=Number(e.length);if(!Number.isInteger(t)||t<1||t>4096)return $e(e,"InvalidLength","--length must be an integer in 1..4096.",2);const n=function(e,t){const n=t.length,o=Math.floor(256/n)*n;let r="";for(;r.length<e;)for(const s of j(2*e))if(s<o&&(r+=t[s%n],r.length===e))break;return r}(t,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*-_=+");return we(e,{kind:"password",length:t,value:n},()=>console.log(n))}const t=Number(e.bytes);if(!Number.isInteger(t)||t<1||t>jt)return $e(e,"InvalidBytes","--bytes must be an integer in 1..1048576.",2);const n=String(e.encoding),o=j(t).toString(n);we(e,{kind:"bytes",bytes:t,encoding:n,value:o},()=>console.log(o))}};function Nt(e,t){return new Promise(n=>{const o=M({port:e,host:t});o.setTimeout(500);const r=e=>{o.destroy(),n(e)};o.once("connect",()=>r(!0)),o.once("timeout",()=>r(!1)),o.once("error",()=>r(!1))})}function kt(){return new Promise((e,t)=>{const n=T();n.unref(),n.on("error",t),n.listen(0,()=>{const t=n.address(),o="object"==typeof t&&t?t.port:0;e({port:o,close:()=>n.close()})})})}const Et={command:"port",describe:"Find a free port, or check whether a specific port is available",builder:e=>be(e).option("check",{alias:"c",describe:"Check if this specific port is free",type:"number"}).option("count",{alias:"n",describe:"Return this many distinct free ports",type:"number",default:1}).example("mfn port --json","one free port").example("mfn port -n 3 --json","three free ports").example("mfn port -c 3000 --json","is port 3000 free?"),handler:async e=>{if(void 0!==e.check){const t=Number(e.check);if(!Number.isInteger(t)||t<1||t>65535)return $e(e,"InvalidPort","--check must be an integer in 1..65535.",2);const n=await async function(e){const[t,n]=await Promise.all([Nt(e,"127.0.0.1"),Nt(e,"::1")]);return!t&&!n}(t);return we(e,{port:t,available:n},()=>console.log(`${t} is ${n?"free":"in use"}`))}const t=Number(e.count);if(!Number.isInteger(t)||t<1)return $e(e,"InvalidCount","--count must be a positive integer.",2);const n=[];try{for(;n.length<t;){const e=await kt();n.push(e)}}catch(t){n.forEach(e=>e.close());return $e(e,"PortError",`Could not allocate a free port: ${t instanceof Error?t.message:String(t)}`)}const o=n.map(e=>e.port);n.forEach(e=>e.close()),we(e,{count:t,ports:o,port:o[0]},()=>o.forEach(e=>console.log(e)))}};const It={command:"json [query]",describe:"Extract a value from JSON (file or stdin) without reading the whole document",builder:e=>be(e).positional("query",{describe:"Dot/bracket path, e.g. scripts.build or users[0].name (omit for root)",type:"string"}).option("file",{alias:"f",describe:"Read JSON from this file (default: stdin)",type:"string"}).option("keys",{alias:"k",describe:"List the keys at the path instead of the value",type:"boolean",default:!1}).option("length",{alias:"l",describe:"Report array length / object key count at the path",type:"boolean",default:!1}).example("mfn json scripts.build -f package.json --json","one field from a file").example("cat data.json | mfn json users[0].name --json","one field from stdin").example("mfn json dependencies -f package.json --keys --json","just the keys"),handler:async e=>{let t,n;try{if(void 0!==e.file){if(ut(String(e.file)))return $e(e,"SensitivePath",pt(String(e.file)),2);t=await E(String(e.file),"utf8")}else if(t=await Se(),!t)return $e(e,"MissingInput","Provide --file <path> or pipe JSON via stdin.",2)}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}try{n=JSON.parse(t)}catch(t){return $e(e,"InvalidJSON",`Input is not valid JSON: ${t instanceof Error?t.message:String(t)}`)}const o=void 0!==e.query?String(e.query):"",{found:r,value:s}=o?function(e,t){const n=t.replace(/\[(\d+)\]/g,".$1").split(".").filter(e=>""!==e);let o=e;for(const e of n){if(null==o||"object"!=typeof o)return{found:!1,value:void 0};if(!(e in o))return{found:!1,value:void 0};o=o[e]}return{found:!0,value:o}}(n,o):{found:!0,value:n};if(!r)return $e(e,"PathNotFound",`No value at path "${o}".`);const i=null===(a=s)?"null":Array.isArray(a)?"array":typeof a;var a;if(e.keys){if("object"!==i&&"array"!==i)return $e(e,"NotAnObject",`Path "${o||"."}" is ${i}; --keys needs an object/array.`,2);const t=Object.keys(s);return we(e,{query:o||null,type:i,count:t.length,keys:t},()=>t.forEach(e=>console.log(e)))}if(e.length){const t="array"===i?s.length:"object"===i?Object.keys(s).length:"string"===i?s.length:null;return null===t?$e(e,"NoLength",`Path "${o||"."}" is ${i}; --length needs array/object/string.`,2):we(e,{query:o||null,type:i,length:t},()=>console.log(t))}const l="string"==typeof s?gt(s).text:s;we(e,{query:o||null,type:i,value:l},()=>console.log("string"==typeof l?l:JSON.stringify(l,null,2)))}},Ot=e=>Math.ceil(e.length/4),At={command:"count [text]",describe:"Count lines/words/chars/bytes + LLM token estimate (file, stdin, or text)",builder:e=>be(e).positional("text",{describe:"Text to measure (or use --file / pipe stdin)",type:"string"}).option("file",{alias:"f",describe:"Measure the contents of this file",type:"string"}).example("mfn count -f big.log --json","size facts before deciding to read a file").example("git diff | mfn count --json","how big is this diff, in tokens?"),handler:async e=>{let t,n,o;try{if(void 0!==e.file){const r=String(e.file);t=await E(r,"utf8"),o=Buffer.byteLength(t,"utf8"),n=`file:${r}`}else if(void 0!==e.text){const r=String(e.text);try{t=await E(r,"utf8"),n=`file:${r}`}catch{t=r,n="text"}o=Buffer.byteLength(t,"utf8")}else{if(t=await Se(),!t)return $e(e,"MissingInput","Provide text, --file <path>, or pipe stdin.",2);o=Buffer.byteLength(t,"utf8"),n="stdin"}}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}const r=0===t.length?0:t.split("\n").length-(t.endsWith("\n")?1:0),s=(t.match(/\S+/g)??[]).length,i={source:n,lines:r,words:s,chars:t.length,bytes:o,tokensEstimate:Ot(t)};we(e,i,()=>{console.log(`lines ${r} · words ${s} · chars ${t.length} · bytes ${o} · ~${i.tokensEstimate} tokens`)})}},Tt={command:"lines <file>",describe:"Read an exact line range of a file (1-based, inclusive) — not the whole file",builder:e=>be(e).positional("file",{describe:"File to read from",type:"string"}).option("start",{alias:"s",describe:"First line (1-based)",type:"number",default:1}).option("end",{alias:"e",describe:"Last line (inclusive; default start+99)",type:"number"}).option("count",{alias:"n",describe:"Number of lines from --start (alternative to --end)",type:"number"}).example("mfn lines src/app.ts -s 120 -n 30 --json","30 lines starting at line 120").example("mfn lines error.log -s 1 -e 50 --json","first 50 lines"),handler:async e=>{const t=Number(e.start);if(!Number.isInteger(t)||t<1)return $e(e,"InvalidStart","--start must be a positive integer (1-based).",2);if(void 0!==e.end&&void 0!==e.count)return $e(e,"ConflictingFlags","Use --end OR --count, not both.",2);let n;if(void 0!==e.end){if(n=Number(e.end),!Number.isInteger(n)||n<t)return $e(e,"InvalidEnd","--end must be an integer >= --start.",2)}else if(void 0!==e.count){const o=Number(e.count);if(!Number.isInteger(o)||o<1)return $e(e,"InvalidCount","--count must be a positive integer.",2);n=t+o-1}else n=t+99;if(n-t+1>2e3)return $e(e,"RangeTooLarge",`Range spans ${n-t+1} lines; max is 2000.`,2);const o=String(e.file);if(ut(o))return $e(e,"SensitivePath",pt(o),2);let r;try{r=await E(o,"utf8")}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}const s=r.split("\n"),i=r.endsWith("\n")?s.length-1:s.length;if(t>i)return $e(e,"OutOfRange",`--start ${t} is beyond the file (${i} lines).`,2);const a=Math.min(n,i),l=s.slice(t-1,a).map(e=>gt(e).text);we(e,{file:String(e.file),start:t,end:a,requestedEnd:n,totalLines:i,lineCount:l.length,content:l.join("\n")},()=>l.forEach((e,n)=>console.log(`${t+n}\t${e}`)))}},Mt=w(h),Lt="win32"===u(),Ct=/^[A-Za-z0-9][A-Za-z0-9_.+-]*$/;async function _t(e){try{const{stdout:t,stderr:n}=await Mt(e,["--version"],{timeout:3e3}),o=(t||n).split("\n")[0]?.trim();return o||null}catch{return null}}const zt={command:"have <tools...>",describe:"Check which tools are installed (path + version) in one call",builder:e=>be(e).positional("tools",{describe:"Command names to look up, e.g. node git docker",type:"string"}).example("mfn have node git docker --json","availability + versions in one shot").example("mfn have rg jq gh --json","check optional tooling before using it"),handler:async e=>{const t=e.tools.map(String);for(const n of t)if(!Ct.test(n))return $e(e,"InvalidToolName",`"${n}" is not a plain command name.`,2);const n=await Promise.all(t.map(async e=>{const t=await async function(e){try{const{stdout:t}=await Mt(Lt?"where":"which",[e]),n=t.split("\n")[0]?.trim();return n||null}catch{return null}}(e);return t?{name:e,found:!0,path:t,version:await _t(e)}:{name:e,found:!1,path:null,version:null}})),o=n.filter(e=>!e.found).map(e=>e.name);we(e,{count:n.length,allFound:0===o.length,missing:o,tools:n},()=>{for(const e of n)console.log(e.found?`✔ ${e.name} ${e.version??""} (${e.path})`:`✘ ${e.name} not found`)})}},Rt={command:"sys",describe:"One-shot system facts (OS, node, CPU, memory, shell, timezone, paths)",builder:e=>be(e).example("mfn sys --json","everything an agent usually probes with 5+ separate commands"),handler:e=>{const t=m.cpus(),n={platform:process.platform,arch:process.arch,osRelease:m.release(),osVersion:m.version(),hostname:m.hostname(),node:process.version,cpu:{model:t[0]?.model??"unknown",cores:t.length},memory:{totalBytes:m.totalmem(),freeBytes:m.freemem(),totalGB:Math.round(m.totalmem()/1024**3*10)/10,freeGB:Math.round(m.freemem()/1024**3*10)/10},user:m.userInfo().username,shell:process.env.SHELL||process.env.ComSpec||null,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,locale:Intl.DateTimeFormat().resolvedOptions().locale,homedir:m.homedir(),tmpdir:m.tmpdir(),cwd:process.cwd(),uptimeSeconds:Math.round(m.uptime())};we(e,n,()=>{console.log(`${n.platform}/${n.arch} · ${n.osVersion}`),console.log(`node ${n.node} · ${n.cpu.cores}× ${n.cpu.model}`),console.log(`memory ${n.memory.freeGB}/${n.memory.totalGB} GB free`),console.log(`user ${n.user} · shell ${n.shell??"?"} · tz ${n.timezone}`),console.log(`cwd ${n.cwd}`)})}},Pt=w(h);async function Ft(...e){try{const{stdout:t}=await Pt("git",e,{timeout:1e4});return t.trimEnd()}catch{return null}}const Dt={command:"repo",describe:"One-shot git repo summary (branch, dirty counts, ahead/behind, last commits)",builder:e=>be(e).option("commits",{alias:"n",describe:"How many recent commits to include",type:"number",default:5}).example("mfn repo --json","replaces git status + git log + git branch + git remote"),handler:async e=>{const t=Number(e.commits);if(!Number.isInteger(t)||t<0||t>100)return $e(e,"InvalidCount","--commits must be an integer in 0..100.",2);if("true"!==await Ft("rev-parse","--is-inside-work-tree"))return $e(e,"NotARepo",`Not inside a git repository: ${process.cwd()}`);const[n,o,r,s,i,a]=await Promise.all([Ft("rev-parse","--show-toplevel"),Ft("rev-parse","--abbrev-ref","HEAD"),Ft("status","--porcelain"),Ft("rev-list","--left-right","--count","@{upstream}...HEAD"),Ft("remote","-v"),t>0?Ft("log",`-${t}`,"--pretty=format:%h%x09%an%x09%ad%x09%s","--date=short"):Promise.resolve("")]),l=(r??"").split("\n").filter(Boolean),c=l.filter(e=>e.startsWith("??")).length,d=l.filter(e=>!e.startsWith("??")&&" "!==e[0]).length,m=l.filter(e=>!e.startsWith("??")&&" "!==e[1]).length;let u=null,p=null;if(s){const[e,t]=s.split("\t").map(Number);p=Number.isFinite(e)?e:null,u=Number.isFinite(t)?t:null}const f=Array.from(new Map((i??"").split("\n").filter(Boolean).map(e=>{const[t,n]=e.split(/\s+/);return[t,{name:t,url:n}]})).values()),h=(a??"").split("\n").filter(Boolean).map(e=>{const[t,n,o,...r]=e.split("\t");return{hash:t,author:n,date:o,subject:r.join("\t")}}),g=0===l.length;we(e,{root:n,branch:o,clean:g,staged:d,unstaged:m,untracked:c,ahead:u,behind:p,hasUpstream:null!==s,remotes:f,commits:h},()=>{console.log(`${n} (${o})`),console.log(g?"clean":`staged ${d} · unstaged ${m} · untracked ${c}`),null!==u&&console.log(`ahead ${u} · behind ${p}`);for(const e of h)console.log(`${e.hash} ${e.date} ${e.subject}`)})}};class Bt{s;i=0;constructor(e){this.s=e}parse(){const e=this.expr();if(this.skipWs(),this.i<this.s.length)throw new Error(`Unexpected "${this.s[this.i]}" at position ${this.i}`);return e}skipWs(){for(;" "===this.s[this.i];)this.i++}peek(){return this.skipWs(),this.s[this.i]??""}expr(){let e=this.term();for(let t=this.peek();"+"===t||"-"===t;t=this.peek())this.i++,e=Ut(e,this.term(),t);return e}term(){let e=this.factor();for(let t=this.peek();"*"===t||"/"===t||"%"===t;t=this.peek())this.i++,e=Ut(e,this.factor(),t);return e}factor(){const e=this.unary();return"^"===this.peek()?(this.i++,Ut(e,this.factor(),"^")):e}unary(){if("-"===this.peek()){this.i++;const e=this.unary();return{big:null===e.big?null:-e.big,float:-e.float}}return this.atom()}atom(){if("("===this.peek()){this.i++;const e=this.expr();if(")"!==this.peek())throw new Error("Missing closing parenthesis");return this.i++,e}this.skipWs();const e=/^\d+(\.\d+)?([eE][+-]?\d+)?/.exec(this.s.slice(this.i));if(!e)throw new Error(`Expected a number at position ${this.i}`);this.i+=e[0].length;return{big:!e[1]&&!e[2]?BigInt(e[0]):null,float:Number(e[0])}}}function Ut(e,t,n){const o="+"===n?e.float+t.float:"-"===n?e.float-t.float:"*"===n?e.float*t.float:"/"===n?e.float/t.float:"%"===n?e.float%t.float:Math.pow(e.float,t.float);if("/"===n&&0===t.float)throw new Error("Division by zero");if(null===e.big||null===t.big||"/"===n)return{big:null,float:o};if("^"===n){if(t.big<0n)return{big:null,float:o};if(t.big>4096n)throw new Error("Exponent too large (max 4096)");return{big:e.big**t.big,float:o}}if("%"===n&&0n===t.big)throw new Error("Modulo by zero");return{big:"+"===n?e.big+t.big:"-"===n?e.big-t.big:"*"===n?e.big*t.big:e.big%t.big,float:o}}const Jt={command:"calc <expression>",describe:"Exact arithmetic (+ - * / % ^, parens; integers use BigInt — no float drift)",builder:e=>be(e).positional("expression",{describe:'Expression, e.g. "2^64 - 1" or "(3 + 4) * 5"',type:"string"}).example('mfn calc "2^53 + 1" --json',"exact: 9007199254740993 (floats get this wrong)").example('mfn calc "1729 * 4096 % 7" --json',"integer arithmetic stays exact"),handler:e=>{const t=String(e.expression).trim();if(!t)return $e(e,"MissingInput","Provide an arithmetic expression.",2);if(t.length>1e3)return $e(e,"ExpressionTooLong","Expression exceeds 1000 characters.",2);let n;try{n=new Bt(t).parse()}catch(n){return $e(e,"ParseError",`Could not evaluate "${t}": ${n instanceof Error?n.message:String(n)}`,2)}const o=null!==n.big,r=o?n.big.toString():String(n.float);we(e,{expression:t,result:r,exact:o,float:n.float},()=>console.log(r))}},Wt=/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;function qt(e){const t=Wt.exec(e.trim());return t?{raw:e.trim(),major:Number(t[1]),minor:Number(t[2]),patch:Number(t[3]),prerelease:t[4]?t[4].split("."):[],build:t[5]??null}:null}function Zt(e,t){for(const n of["major","minor","patch"])if(e[n]!==t[n])return e[n]<t[n]?-1:1;if(0===e.prerelease.length&&0===t.prerelease.length)return 0;if(0===e.prerelease.length)return 1;if(0===t.prerelease.length)return-1;const n=Math.max(e.prerelease.length,t.prerelease.length);for(let o=0;o<n;o++){const n=e.prerelease[o],r=t.prerelease[o];if(void 0===n)return-1;if(void 0===r)return 1;const s=/^\d+$/.test(n),i=/^\d+$/.test(r);if(s&&i){if(Number(n)!==Number(r))return Number(n)<Number(r)?-1:1}else{if(s!==i)return s?-1:1;if(n!==r)return n<r?-1:1}}return 0}const Gt={command:"semver <versions...>",describe:"Validate, compare, sort, or bump semantic versions (exact, per semver.org)",builder:e=>be(e).positional("versions",{describe:"One or more versions",type:"string"}).option("bump",{alias:"b",describe:"Bump the (single) version",type:"string",choices:["major","minor","patch"]}).option("sort",{alias:"s",describe:"Sort all given versions ascending",type:"boolean",default:!1}).example("mfn semver 1.2.3 --json","validate + parse one version").example("mfn semver 1.10.0 1.9.2 --json","compare two (1.10.0 > 1.9.2 — string sort lies)").example("mfn semver 2.0.0-rc.1 2.0.0 --sort --json","prerelease ordering done right").example("mfn semver 1.2.3 -b minor --json","bump → 1.3.0"),handler:e=>{const t=e.versions.map(String),n=[];for(const o of t){const t=qt(o);if(!t)return $e(e,"InvalidVersion",`"${o}" is not a valid semantic version.`,2);n.push(t)}if(e.bump){if(1!==n.length)return $e(e,"TooManyVersions","--bump takes exactly one version.",2);const t=function(e,t){return"major"===t?`${e.major+1}.0.0`:"minor"===t?`${e.major}.${e.minor+1}.0`:`${e.major}.${e.minor}.${e.patch+1}`}(n[0],String(e.bump));return we(e,{input:n[0].raw,bump:e.bump,result:t},()=>console.log(t))}if(e.sort||n.length>2){const t=[...n].sort(Zt).map(e=>e.raw);return we(e,{count:t.length,sorted:t,latest:t[t.length-1]},()=>t.forEach(e=>console.log(e)))}if(2===n.length){const t=Zt(n[0],n[1]);return we(e,{a:n[0].raw,b:n[1].raw,comparison:t,relation:0===t?"equal":t<0?"a < b":"a > b",greater:t>=0?n[0].raw:n[1].raw},()=>console.log(0===t?"equal":t<0?`${n[1].raw} is greater`:`${n[0].raw} is greater`))}const o=n[0];we(e,{version:o.raw,valid:!0,major:o.major,minor:o.minor,patch:o.patch,prerelease:o.prerelease.length?o.prerelease.join("."):null,build:o.build,isPrerelease:o.prerelease.length>0},()=>console.log(`${o.major}.${o.minor}.${o.patch} valid`))}};const Ht=e=>e.charAt(0).toUpperCase()+e.slice(1),Vt={camel:e=>e.map((e,t)=>0===t?e:Ht(e)).join(""),pascal:e=>e.map(Ht).join(""),snake:e=>e.join("_"),kebab:e=>e.join("-"),constant:e=>e.join("_").toUpperCase(),dot:e=>e.join("."),path:e=>e.join("/"),title:e=>e.map(Ht).join(" "),sentence:e=>Ht(e.join(" ")),lower:e=>e.join(" "),upper:e=>e.join(" ").toUpperCase()},Yt=Object.keys(Vt),Kt=1e5,Qt={command:"case [text]",describe:"Convert a string between naming styles (camel, snake, kebab, pascal, …)",builder:e=>be(e).positional("text",{describe:"Text to convert (or pipe via stdin)",type:"string"}).option("to",{alias:"t",describe:"Target style (omit for all styles at once)",type:"string",choices:Yt}).example('mfn case "user profile id" -t camel --json',"→ userProfileId").example("mfn case getUserName -t snake --json","→ get_user_name").example("mfn case my-component --json","all styles in one call"),handler:async e=>{let t;if(void 0!==e.text)t=String(e.text);else if(t=(await Se()).replace(/\n$/,""),!t)return $e(e,"MissingInput","Provide text or pipe stdin.",2);if(t.length>Kt)return $e(e,"InputTooLarge","Input exceeds 100000 characters.",2);const n=function(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").split(/[\s_\-./]+/).filter(Boolean).map(e=>e.toLowerCase())}(t);if(0===n.length)return $e(e,"NoWords","Input contains no convertible words.",2);if(e.to){const o=String(e.to),r=Vt[o](n);return we(e,{input:t,style:o,output:r},()=>console.log(r))}const o=Object.fromEntries(Yt.map(e=>[e,Vt[e](n)]));we(e,{input:t,words:n,styles:o},()=>{for(const[e,t]of Object.entries(o))console.log(`${e.padEnd(9)} ${t}`)})}},Xt=[[0,59],[0,23],[1,31],[1,12],[0,6]],en="JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC".split(" "),tn="SUN MON TUE WED THU FRI SAT".split(" ");function nn(e,t){const n=e.toUpperCase();if(3===t){const e=en.indexOf(n);if(e>=0)return String(e+1)}if(4===t){const e=tn.indexOf(n);if(e>=0)return String(e)}return e}function on(e,t){const[n,o]=Xt[t],r=new Set;for(const s of e.split(",")){const[e,i]=s.split("/"),a=void 0===i?1:Number(i);if(!Number.isInteger(a)||a<1)throw new Error(`Invalid step "${i}" in "${s}"`);let l,c;if("*"===e||""===e)l=n,c=o;else if(e.includes("-")){const[n,o]=e.split("-").map(e=>Number(nn(e,t)));l=n,c=o}else l=c=Number(nn(e,t)),void 0!==i&&(c=o);if(!Number.isInteger(l)||!Number.isInteger(c))throw new Error(`Invalid value in "${s}"`);if(4===t&&(7===l&&(l=0),7===c&&(c=0)),l<n||c>o||l>c)throw new Error(`"${s}" out of range ${n}-${o}`);for(let e=l;e<=c;e+=a)r.add(e)}return r}const rn={"@yearly":"0 0 1 1 *","@annually":"0 0 1 1 *","@monthly":"0 0 1 * *","@weekly":"0 0 * * 0","@daily":"0 0 * * *","@midnight":"0 0 * * *","@hourly":"0 * * * *"};function sn(e,t){if(!e.month.has(t.getMonth()+1))return!1;const n=e.dayOfMonth.has(t.getDate()),o=e.dayOfWeek.has(t.getDay());return e.domRestricted&&e.dowRestricted?n||o:n&&o}const an={command:"cron <expression>",describe:"Validate a cron expression, explain it, and compute the next run times",builder:e=>be(e).positional("expression",{describe:"5-field cron (minute hour dom month dow) or @daily/@hourly/@weekly/…",type:"string"}).option("next",{alias:"n",describe:"How many upcoming run times to compute",type:"number",default:3}).example('mfn cron "*/15 9-17 * * 1-5" --json',"validate + explain + next runs").example('mfn cron "@daily" -n 1 --json',"when does @daily fire next?"),handler:e=>{const t=String(e.expression).trim(),n=Number(e.next);if(!Number.isInteger(n)||n<0||n>100)return $e(e,"InvalidCount","--next must be an integer in 0..100.",2);let o;try{o=function(e){const t=(rn[e.trim().toLowerCase()]??e.trim()).split(/\s+/);if(5!==t.length)throw new Error(`Expected 5 fields (minute hour dom month dow), got ${t.length}`);return{minute:on(t[0],0),hour:on(t[1],1),dayOfMonth:on(t[2],2),month:on(t[3],3),dayOfWeek:on(t[4],4),domRestricted:"*"!==t[2],dowRestricted:"*"!==t[4]}}(t)}catch(n){const o=n instanceof Error?n.message:String(n);return $e(e,"InvalidCron",`"${t}" is not valid cron: ${o}`,2)}const r=function(e,t,n){const o=[],r=new Date(t);r.setSeconds(0,0),r.setMinutes(r.getMinutes()+1);const s=new Date(t);for(s.setFullYear(s.getFullYear()+5);o.length<n&&r<=s;)sn(e,r)?e.hour.has(r.getHours())?e.minute.has(r.getMinutes())?(o.push(new Date(r)),r.setMinutes(r.getMinutes()+1)):r.setMinutes(r.getMinutes()+1):(r.setMinutes(0),r.setHours(r.getHours()+1)):(r.setHours(0,0,0,0),r.setDate(r.getDate()+1));return o}(o,new Date,n),s=function(e){const t=(e,t)=>e.size>t?"several values":[...e].sort((e,t)=>e-t).join(","),n=60===e.minute.size?"every minute":1===e.minute.size?`at minute ${t(e.minute,5)}`:`at minutes ${t(e.minute,8)}`,o=24===e.hour.size?"of every hour":1===e.hour.size?`past hour ${t(e.hour,5)}`:`past hours ${t(e.hour,8)}`,r=e.domRestricted?`on day-of-month ${t(e.dayOfMonth,8)}`:"",s=12===e.month.size?"":`in month ${t(e.month,6)}`,i=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];return[n,o,r,s,e.dowRestricted?`on ${[...e.dayOfWeek].sort((e,t)=>e-t).map(e=>i[e]).join(",")}`:""].filter(Boolean).join(" ")}(o),i=e=>{const t=(e,t=2)=>String(e).padStart(t,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())} ${t(e.getHours())}:${t(e.getMinutes())}:00`};we(e,{expression:t,valid:!0,description:s,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,next:r.map(e=>({local:i(e),iso:e.toISOString(),epochMs:e.getTime()}))},()=>{console.log(`${t} → ${s}`);for(const e of r)console.log(i(e))})}};const ln=2e4,cn={command:"diff <fileA> <fileB>",describe:"Line diff of two files as structured hunks (summary first, not a wall of text)",builder:e=>be(e).positional("fileA",{describe:"Old file",type:"string"}).positional("fileB",{describe:"New file",type:"string"}).option("summary",{alias:"s",describe:"Only counts + hunk locations (no line content)",type:"boolean",default:!1}).example("mfn diff old.json new.json --json","structured hunks").example("mfn diff a.txt b.txt -s --json","just how much changed, and where"),handler:async e=>{for(const t of[e.fileA,e.fileB])if(ut(String(t)))return $e(e,"SensitivePath",pt(String(t)),2);let t,n;try{[t,n]=await Promise.all([E(String(e.fileA),"utf8"),E(String(e.fileB),"utf8")])}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,"ReadError",n)}const o=t.split("\n"),r=n.split("\n");if(o.length>ln||r.length>ln)return $e(e,"FileTooLarge","diff is capped at 20000 lines per file.",2);const s=t===n,i=s?[]:function(e,t){const n=e.length,o=t.length,r=Array.from({length:n+1},()=>new Array(o+1).fill(0));for(let s=n-1;s>=0;s--)for(let n=o-1;n>=0;n--)r[s][n]=e[s]===t[n]?r[s+1][n+1]+1:Math.max(r[s+1][n],r[s][n+1]);const s=[];let i=0,a=0;for(;i<n||a<o;){if(i<n&&a<o&&e[i]===t[a]){i++,a++;continue}const l={aStart:i+1,aLines:0,bStart:a+1,bLines:0,removed:[],added:[]};for(;i<n&&(a>=o||r[i+1][a]>=r[i][a+1])&&(l.removed.push(e[i++]),l.aLines++,!(i<n&&a<o&&e[i]===t[a])););for(;a<o&&(i>=n||r[i+1][a]<r[i][a+1]||void 0===e[i]||e[i]!==t[a])&&!(i<n&&e[i]===t[a]);)l.added.push(t[a++]),l.bLines++;s.push(l)}return s}(o,r),a=i.reduce((e,t)=>e+t.removed.length,0),l=i.reduce((e,t)=>e+t.added.length,0),c=i.map(t=>e.summary?{aStart:t.aStart,aLines:t.aLines,bStart:t.bStart,bLines:t.bLines}:t);we(e,{fileA:String(e.fileA),fileB:String(e.fileB),identical:s,hunkCount:i.length,linesAdded:l,linesRemoved:a,hunks:c},()=>{if(s)return console.log("files are identical");console.log(`${i.length} hunk(s) · +${l} −${a}`);for(const t of i)console.log(`@@ -${t.aStart},${t.aLines} +${t.bStart},${t.bLines} @@`),e.summary||(t.removed.forEach(e=>console.log(`- ${e}`)),t.added.forEach(e=>console.log(`+ ${e}`)))})}},dn=/(key|token|secret|password|passwd|credential|auth|cookie|session|private|api)/i,mn=e=>e.length<=8?"••••":`${e.slice(0,3)}…${e.slice(-2)} (${e.length} chars, redacted)`,un=(e,t)=>dn.test(e)||null!==ht(t),pn={command:"env [names...]",describe:"Inspect environment variables with automatic secret redaction",builder:e=>be(e).positional("names",{describe:"Variable names to read (omit to list all names)",type:"string"}).option("prefix",{alias:"p",describe:"Only variables starting with this prefix",type:"string"}).example("mfn env NODE_ENV PATH --json","specific variables (secrets auto-redacted)").example("mfn env -p NEXT_PUBLIC_ --json","all NEXT_PUBLIC_* variables").example("mfn env --json","just the names — values omitted"),handler:e=>{const t=(e.names??[]).map(String),n=void 0!==e.prefix?String(e.prefix):null;if(t.length>0){const n=t.map(e=>{const t=process.env[e];if(void 0===t)return{name:e,set:!1,value:null,redacted:!1};const n=un(e,t);return{name:e,set:!0,value:n?mn(t):t,redacted:n}}),o=n.filter(e=>!e.set).map(e=>e.name);return we(e,{count:n.length,missing:o,vars:n},()=>{for(const e of n)console.log(e.set?`${e.name}=${e.value}`:`${e.name} (not set)`)})}const o=Object.keys(process.env).filter(e=>!n||e.startsWith(n)).sort();if(n){const t=o.map(e=>{const t=process.env[e]??"",n=un(e,t);return{name:e,set:!0,value:n?mn(t):t,redacted:n}});return we(e,{prefix:n,count:t.length,vars:t},()=>{for(const e of t)console.log(`${e.name}=${e.value}`)})}if(0===o.length)return $e(e,"NoMatch","No environment variables found.");we(e,{count:o.length,names:o},()=>o.forEach(e=>console.log(e)))}},fn=new Set(["node_modules",".git",".nx","dist","build","coverage"]);const hn=e=>e>=1024**3?`${(e/1024**3).toFixed(1)}G`:e>=1048576?`${(e/1048576).toFixed(1)}M`:e>=1024?`${(e/1024).toFixed(1)}K`:`${e}B`,gn={command:"size [dir]",describe:"Total size + largest files/dirs under a directory (one call, not du|sort|head)",builder:e=>be(e).positional("dir",{describe:"Directory to analyse (default: cwd)",type:"string"}).option("top",{alias:"t",describe:"How many largest files/dirs to list",type:"number",default:10}).option("ignore",{alias:"i",describe:"Additional directory names to ignore",type:"array"}).example("mfn size --json","where is the disk going in this project?").example("mfn size ./src -t 5 --json","five largest files under src"),handler:e=>{const t=Number(e.top);if(!Number.isInteger(t)||t<1||t>1e3)return $e(e,"InvalidTop","--top must be an integer in 1..1000.",2);const n=I.resolve(String(e.dir??process.cwd()));let o;try{o=O.statSync(n)}catch{return $e(e,"NotFound",`Directory not found: ${n}`,2)}if(!o.isDirectory())return $e(e,"NotADirectory",`${n} is not a directory.`,2);const{files:r,truncated:s}=function(e,t){const n=new Set([...fn,...t]),o=[];let r=!1;const s=t=>{if(o.length>=2e5)return void(r=!0);let i;try{i=O.readdirSync(t,{withFileTypes:!0})}catch{return}for(const r of i){if(n.has(r.name))continue;const i=I.join(t,r.name);if(r.isDirectory())s(i);else if(r.isFile())try{o.push({path:I.relative(e,i),bytes:O.statSync(i).size})}catch{}}};return s(e),{files:o,truncated:r}}(n,(e.ignore??[]).map(String)),i=r.reduce((e,t)=>e+t.bytes,0),a=new Map;for(const e of r){const t=e.path.split(I.sep)[0];a.set(t,(a.get(t)??0)+e.bytes)}const l=[...a.entries()].sort((e,t)=>t[1]-e[1]).slice(0,t).map(([e,t])=>({name:e,bytes:t,human:hn(t)})),c=[...r].sort((e,t)=>t.bytes-e.bytes).slice(0,t).map(e=>({path:e.path,bytes:e.bytes,human:hn(e.bytes)}));we(e,{root:n,fileCount:r.length,totalBytes:i,totalHuman:hn(i),truncated:s,largestFiles:c,byTopLevel:l},()=>{console.log(`${n}: ${hn(i)} across ${r.length} files`);for(const e of l)console.log(` ${e.human.padStart(8)} ${e.name}/`);console.log("largest files:");for(const e of c)console.log(` ${e.human.padStart(8)} ${e.path}`)})}},yn=new Set(["node_modules",".git",".nx","dist","build","coverage"]);const bn={command:"ext [dir]",describe:'File counts and bytes per extension — "what kind of project is this?" in one call',builder:e=>be(e).positional("dir",{describe:"Directory to analyse (default: cwd)",type:"string"}).option("ignore",{alias:"i",describe:"Additional directory names to ignore",type:"array"}).example("mfn ext --json","project composition by file type"),handler:e=>{const t=I.resolve(String(e.dir??process.cwd()));let n;try{n=O.statSync(t)}catch{return $e(e,"NotFound",`Directory not found: ${t}`,2)}if(!n.isDirectory())return $e(e,"NotADirectory",`${t} is not a directory.`,2);const{byExt:o,total:r,truncated:s}=function(e,t){const n=new Set([...yn,...t]),o=new Map;let r=0,s=!1;const i=e=>{if(r>=2e5)return void(s=!0);let t;try{t=O.readdirSync(e,{withFileTypes:!0})}catch{return}for(const s of t){if(n.has(s.name))continue;const t=I.join(e,s.name);if(s.isDirectory())i(t);else if(s.isFile()){const e=I.extname(s.name).toLowerCase()||"(none)";let n=0;try{n=O.statSync(t).size}catch{}const i=o.get(e)??{count:0,bytes:0};i.count++,i.bytes+=n,o.set(e,i),r++}}};return i(e),{byExt:o,total:r,truncated:s}}(t,(e.ignore??[]).map(String)),i=[...o.entries()].sort((e,t)=>t[1].count-e[1].count).map(([e,t])=>({ext:e,count:t.count,bytes:t.bytes}));we(e,{root:t,fileCount:r,truncated:s,extensions:i},()=>{console.log(`${r} files under ${t}`);for(const e of i.slice(0,20))console.log(` ${String(e.count).padStart(6)} ${e.ext}`)})}},vn={command:"freq [file]",describe:"Most frequent lines of a file/stdin (log analysis without sort|uniq -c|sort|head)",builder:e=>be(e).positional("file",{describe:"File to analyse (or pipe via stdin)",type:"string"}).option("top",{alias:"t",describe:"How many entries to return",type:"number",default:10}).option("min",{alias:"m",describe:"Only lines occurring at least this often",type:"number",default:1}).option("trim",{describe:"Trim whitespace before counting (default true)",type:"boolean",default:!0}).example("mfn freq error.log -t 5 --json","the 5 most repeated log lines").example("grep ERROR app.log | mfn freq --json","most frequent error messages"),handler:async e=>{const t=Number(e.top),n=Number(e.min);if(!Number.isInteger(t)||t<1||t>1e4)return $e(e,"InvalidTop","--top must be an integer in 1..10000.",2);if(!Number.isInteger(n)||n<1)return $e(e,"InvalidMin","--min must be a positive integer.",2);let o,r;try{if(void 0!==e.file){if(ut(String(e.file)))return $e(e,"SensitivePath",pt(String(e.file)),2);o=await E(String(e.file),"utf8"),r=`file:${e.file}`}else{if(o=await Se(),!o)return $e(e,"MissingInput","Provide a file or pipe stdin.",2);r="stdin"}}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}const s=new Map;let i=0;for(const t of o.split("\n")){const n=e.trim?t.trim():t;""!==n&&(i++,s.set(n,(s.get(n)??0)+1))}const a=[...s.entries()].filter(([,e])=>e>=n).sort((e,t)=>t[1]-e[1]||e[0].localeCompare(t[0])).slice(0,t).map(([e,t])=>({count:t,line:gt(e).text}));we(e,{source:r,totalLines:i,uniqueLines:s.size,returned:a.length,entries:a},()=>{for(const e of a)console.log(`${String(e.count).padStart(7)} ${e.line}`)})}},xn={command:"regex <pattern> [text]",describe:"Test a regular expression against text — verify instead of guessing",builder:e=>be(e).positional("pattern",{describe:"Regular expression (without surrounding slashes)",type:"string"}).positional("text",{describe:"Text to test (or --file / stdin)",type:"string"}).option("file",{alias:"f",describe:"Test against the contents of this file",type:"string"}).option("flags",{describe:"Regex flags (g is always added)",type:"string",default:""}).example('mfn regex "^v\\\\d+\\\\.\\\\d+" "v1.22.0" --json',"does it match?").example('mfn regex "TODO[:!]?" -f src/app.ts --json',"all matches with positions and groups"),handler:async e=>{const t=String(e.pattern);if(t.length>1e3)return $e(e,"PatternTooLong","Pattern exceeds 1000 characters.",2);const n=String(e.flags??"");if(!/^[imsuvy]*$/.test(n))return $e(e,"InvalidFlags","Flags may only contain i m s u v y (g is implicit).",2);let o,r,s;try{o=new RegExp(t,n.includes("g")?n:n+"g")}catch(t){return $e(e,"InvalidRegex",t instanceof Error?t.message:String(t),2)}try{if(void 0!==e.file){if(ut(String(e.file)))return $e(e,"SensitivePath",pt(String(e.file)),2);r=await E(String(e.file),"utf8"),s=`file:${e.file}`}else if(void 0!==e.text)r=String(e.text),s="text";else{if(r=await Se(),!r)return $e(e,"MissingInput","Provide text, --file <path>, or pipe stdin.",2);s="stdin"}}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}const i=[];let a=!1;for(const e of r.matchAll(o)){if(i.length>=1e3){a=!0;break}const t=r.slice(0,e.index).split("\n").length;if(i.push({match:gt(e[0]).text,index:e.index,line:t,groups:e.slice(1).map(e=>void 0===e?e:gt(e).text)}),""===e[0])break}we(e,{pattern:t,flags:o.flags,source:s,matched:i.length>0,count:i.length,truncated:a,matches:i},()=>{if(0===i.length)return console.log("no match");for(const e of i)console.log(`line ${e.line} @${e.index}: ${e.match}`)})}},wn={command:"url <value>",describe:"Parse a URL into components with decoded query parameters",builder:e=>be(e).positional("value",{describe:"URL to parse",type:"string"}).example('mfn url "https://api.x.com/v2/users?id=42&fields=name,bio" --json',"all components at once"),handler:e=>{const t=String(e.value);let n;try{n=new URL(t)}catch{return $e(e,"InvalidURL",`"${t}" is not a valid absolute URL (include the scheme).`,2)}const o={};for(const[e,t]of n.searchParams){const n=o[e];void 0===n?o[e]=t:Array.isArray(n)?n.push(t):o[e]=[n,t]}const r={href:n.href,protocol:n.protocol.replace(/:$/,""),username:n.username||null,host:n.host,hostname:n.hostname,port:n.port?Number(n.port):null,path:n.pathname,pathSegments:n.pathname.split("/").filter(Boolean),query:o,queryCount:[...n.searchParams.keys()].length,hash:n.hash?n.hash.slice(1):null,origin:n.origin};we(e,r,()=>{console.log(`${r.protocol}://${r.host}${r.path}`);for(const[e,t]of Object.entries(o))console.log(` ?${e} = ${JSON.stringify(t)}`);r.hash&&console.log(` #${r.hash}`)})}},$n={command:"ip",describe:"Local network interfaces and addresses (no network calls, no ifconfig parsing)",builder:e=>be(e).option("all",{alias:"a",describe:"Include internal/loopback interfaces",type:"boolean",default:!1}).example("mfn ip --json","external-facing local addresses").example("mfn ip -a --json","every interface including loopback"),handler:e=>{const t=m.networkInterfaces(),n=Object.entries(t).map(([t,n])=>({name:t,addresses:(n??[]).filter(t=>e.all||!t.internal).map(e=>({address:e.address,family:e.family,internal:e.internal,mac:e.mac,cidr:e.cidr}))})).filter(e=>e.addresses.length>0),o=n.flatMap(e=>e.addresses).find(e=>"IPv4"===e.family&&!e.internal)?.address??null;we(e,{primaryIPv4:o,count:n.length,interfaces:n},()=>{o&&console.log(`primary IPv4: ${o}`);for(const e of n)for(const t of e.addresses)console.log(`${e.name.padEnd(10)} ${t.family.padEnd(5)} ${t.address}`)})}},jn={shell:e=>`'${e.replace(/'/g,"'\\''")}'`,json:e=>JSON.stringify(e),regex:e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),html:e=>e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),url:e=>encodeURIComponent(e),string:e=>JSON.stringify(e).slice(1,-1)},Sn=Object.keys(jn),Nn=1e6,kn={command:"escape [text]",describe:"Escape text exactly for shell, JSON, regex, HTML, or URL contexts",builder:e=>be(e).positional("text",{describe:"Text to escape (or pipe via stdin)",type:"string"}).option("as",{alias:"a",describe:"Target context",type:"string",choices:Sn,default:"shell"}).example('mfn escape "it\'s done" --json',"safe single-quoted shell string").example('mfn escape "1.2.3" -a regex --json',"regex-literal: 1\\.2\\.3").example("mfn escape 'line1\nline2' -a json --json","paste-ready JSON string"),handler:async e=>{let t;if(void 0!==e.text)t=String(e.text);else if(t=(await Se()).replace(/\n$/,""),!t)return $e(e,"MissingInput","Provide text or pipe stdin.",2);if(t.length>Nn)return $e(e,"InputTooLarge","Input exceeds 1000000 characters.",2);const n=String(e.as),o=jn[n](t);we(e,{mode:n,input:t,output:o},()=>console.log(o))}};function En(e,t,n){if(n.size>=500)return;const o=null===(r=e)?"null":Array.isArray(r)?"array":typeof r;var r;const s=""===t?".":t;if(n.has(s)||n.set(s,new Set),n.get(s).add(o),"object"===o)for(const[o,r]of Object.entries(e))En(r,""===t?o:`${t}.${o}`,n);else if("array"===o){const o=e;n.get(s).delete("array"),n.get(s).add(`array(${o.length})`);for(const e of o.slice(0,50))En(e,`${t}[]`,n)}}const In={command:"schema [query]",describe:"Infer the shape of a JSON document (paths + types) without dumping the data",builder:e=>be(e).positional("query",{describe:"Optional dot-path to start from (see `mfn json`)",type:"string"}).option("file",{alias:"f",describe:"Read JSON from this file (default: stdin)",type:"string"}).example("mfn schema -f response.json --json","shape of a big API payload, not its content").example("curl -s api/users | mfn schema --json","what fields does this API return?"),handler:async e=>{let t,n;try{if(void 0!==e.file){if(ut(String(e.file)))return $e(e,"SensitivePath",pt(String(e.file)),2);t=await E(String(e.file),"utf8")}else if(t=await Se(),!t)return $e(e,"MissingInput","Provide --file <path> or pipe JSON via stdin.",2)}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}try{n=JSON.parse(t)}catch(t){return $e(e,"InvalidJSON",`Input is not valid JSON: ${t instanceof Error?t.message:String(t)}`)}if(e.query){const t=String(e.query).replace(/\[(\d+)\]/g,".$1").split(".").filter(Boolean);for(const o of t){if(null===n||"object"!=typeof n||!(o in n))return $e(e,"PathNotFound",`No value at path "${e.query}".`);n=n[o]}}const o=new Map;En(n,"",o);const r=[...o.entries()].map(([e,t])=>({path:e,type:[...t].sort().join(" | ")}));we(e,{source:e.file?`file:${e.file}`:"stdin",bytes:t.length,pathCount:r.length,truncated:o.size>=500,paths:r},()=>{for(const e of r)console.log(`${e.path.padEnd(40)} ${e.type}`)})}},On=[{kind:"function",re:/^(?<exp>export\s+)?(?:default\s+)?(?:async\s+)?function\s*\*?\s*(?<name>[A-Za-z_$][\w$]*)/},{kind:"class",re:/^(?<exp>export\s+)?(?:default\s+)?(?:abstract\s+)?class\s+(?<name>[A-Za-z_$][\w$]*)/},{kind:"interface",re:/^(?<exp>export\s+)?interface\s+(?<name>[A-Za-z_$][\w$]*)/},{kind:"type",re:/^(?<exp>export\s+)?type\s+(?<name>[A-Za-z_$][\w$]*)\s*=/},{kind:"enum",re:/^(?<exp>export\s+)?(?:const\s+)?enum\s+(?<name>[A-Za-z_$][\w$]*)/},{kind:"const",re:/^(?<exp>export\s+)?const\s+(?<name>[A-Za-z_$][\w$]*)\s*(?::[^=]+)?=\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*(?::[^=]+)?=>/},{kind:"variable",re:/^(?<exp>export\s+)(?:const|let|var)\s+(?<name>[A-Za-z_$][\w$]*)/}],An=[{kind:"function",re:/^(?:async\s+)?def\s+(?<name>[A-Za-z_][\w]*)/},{kind:"class",re:/^class\s+(?<name>[A-Za-z_][\w]*)/}],Tn=[{kind:"heading",re:/^(?<name>#{1,6}\s+.+)$/}],Mn={".ts":On,".tsx":On,".js":On,".jsx":On,".mjs":On,".cjs":On,".py":An,".go":[{kind:"function",re:/^func\s+(?:\([^)]+\)\s+)?(?<name>[A-Za-z_][\w]*)/},{kind:"type",re:/^type\s+(?<name>[A-Za-z_][\w]*)/}],".md":Tn,".markdown":Tn},Ln=Object.keys(Mn);const Cn={command:"outline <file>",describe:"Outline a source file — symbols + line numbers, not the whole file",builder:e=>be(e).positional("file",{describe:"Source file (.ts .js .tsx .py .go .md …)",type:"string"}).option("kind",{alias:"k",describe:"Only symbols of this kind (function, class, …)",type:"string"}).option("exported",{alias:"e",describe:"Only exported symbols (TS/JS)",type:"boolean",default:!1}).example("mfn outline src/app.ts --json","structure of a file in ~50 tokens").example("mfn outline src/app.ts -k function -e --json","just the exported functions"),handler:async e=>{const t=String(e.file),n=I.extname(t).toLowerCase();if(!Ln.includes(n))return $e(e,"UnsupportedType",`"${n||t}" is not outlineable. Supported: ${Ln.join(" ")}`,2);let o;try{o=await E(t,"utf8")}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,"ReadError",n)}let r=function(e,t){const n=Mn[t.toLowerCase()];if(!n)return[];const o=[],r=e.split("\n");for(let e=0;e<r.length;e++){const t=r[e],s=n===An?t.trimStart():t;for(const t of n){const r=t.re.exec(s);if(r?.groups?.name){o.push({line:e+1,kind:t.kind,name:r.groups.name.trim(),exported:Boolean(r.groups.exp)||n!==On});break}}}return o}(o,n);e.kind&&(r=r.filter(t=>t.kind===String(e.kind))),e.exported&&(r=r.filter(e=>e.exported));const s=o.split("\n").length;we(e,{file:t,totalLines:s,count:r.length,symbols:r},()=>{for(const e of r)console.log(`${String(e.line).padStart(5)} ${e.kind.padEnd(9)} ${e.name}`)})}},_n=/(?:import\s[\s\S]*?from\s*|import\s*\(\s*|require\s*\(\s*|export\s[\s\S]*?from\s*)['"]([^'"]+)['"]/g,zn=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs"]),Rn=new Set(["node_modules",".git","dist","build","coverage",".nx"]);function Pn(e){const t=new Set;for(const n of e.matchAll(_n))t.add(n[1]);return[...t]}const Fn={command:"imports [file]",describe:"List a file’s imports, or (--who <module>) every file importing a module",builder:e=>be(e).positional("file",{describe:"Source file to list imports of",type:"string"}).option("who",{alias:"w",describe:"Reverse mode: find files under cwd whose imports contain this string",type:"string"}).example("mfn imports src/app.ts --json","what does this file depend on?").example("mfn imports --who ../utility --json","who imports the utility module?"),handler:async e=>{if(void 0!==e.who){const t=String(e.who);if(!t)return $e(e,"MissingInput","--who needs a module name/substring.",2);const n=process.cwd(),o=[];for(const e of function(e){const t=[],n=e=>{if(t.length>=2e4)return;let o;try{o=O.readdirSync(e,{withFileTypes:!0})}catch{return}for(const r of o){if(Rn.has(r.name))continue;const o=I.join(e,r.name);r.isDirectory()?n(o):r.isFile()&&zn.has(I.extname(r.name))&&t.push(o)}};return n(e),t}(n)){let r;try{r=O.readFileSync(e,"utf8")}catch{continue}const s=Pn(r).filter(e=>e.includes(t));s.length>0&&o.push({file:I.relative(n,e),specifiers:s})}return we(e,{module:t,root:n,count:o.length,importers:o},()=>{for(const e of o)console.log(`${e.file} ← ${e.specifiers.join(", ")}`)})}if(void 0===e.file)return $e(e,"MissingInput","Provide a <file>, or use --who <module>.",2);const t=String(e.file);let n;try{n=await E(t,"utf8")}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}const o=Pn(n),r={relative:o.filter(e=>e.startsWith(".")),packages:o.filter(e=>!e.startsWith(".")&&!e.startsWith("node:")),builtin:o.filter(e=>e.startsWith("node:"))};we(e,{file:t,count:o.length,...r},()=>{for(const e of o)console.log(e)})}},Dn=new Set(["node_modules",".git","dist","build","coverage",".nx"]);const Bn={command:"replace <search> <replacement>",describe:"Literal find/replace across files — DRY-RUN by default, --write to apply",builder:e=>be(e).positional("search",{describe:"Literal text to find (not a regex)",type:"string"}).positional("replacement",{describe:"Literal replacement text",type:"string"}).option("glob",{alias:"g",describe:'File glob relative to cwd (e.g. "src/**/*.ts")',type:"string",demandOption:!0}).option("write",{alias:"w",describe:"Actually modify files (default: dry-run report)",type:"boolean",default:!1}).example('mfn replace oldName newName -g "src/**/*.ts" --json',"dry-run: where + how many").example('mfn replace oldName newName -g "src/**/*.ts" -w --json',"apply the replacement"),handler:e=>{const t=String(e.search),n=String(e.replacement);if(""===t)return $e(e,"MissingInput","Search text must not be empty.",2);if(t===n)return $e(e,"NoOp","Search and replacement are identical.",2);const o=process.cwd(),r=function(e){let t="",n=0;for(;n<e.length;){const o=e[n];if("*"===o)if("*"===e[n+1]){const o="/"===e[n+2];t+=o?"(?:.*/)?":".*",n+=o?3:2}else t+="[^/]*",n++;else"?"===o?(t+="[^/]",n++):(t+=/[.+^${}()|[\]\\]/.test(o)?"\\"+o:o,n++)}return new RegExp(`^${t}$`)}(String(e.glob).replace(/^\.\//,"")),s=new RegExp(t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g");const i=[];let a=0;const l=[];for(const c of function(e){const t=[],n=e=>{if(t.length>=1e4)return;let o;try{o=O.readdirSync(e,{withFileTypes:!0})}catch{return}for(const r of o){if(Dn.has(r.name))continue;const o=I.join(e,r.name);r.isDirectory()?n(o):r.isFile()&&t.push(o)}};return n(e),t}(o)){const d=I.relative(o,c).split(I.sep).join("/");if(!r.test(d))continue;let m;try{m=O.openSync(c,e.write?"r+":"r")}catch{continue}try{if(O.fstatSync(m).size>5242880)continue;const o=O.readFileSync(m,"utf8"),r=(o.match(s)??[]).length;if(0===r)continue;if(e.write){const e=o.split(t).join(n);O.ftruncateSync(m,0),O.writeSync(m,e,0,"utf8")}i.push({file:d,count:r}),a+=r}catch(t){e.write&&l.push({file:d,error:t instanceof Error?t.message:String(t)})}finally{O.closeSync(m)}}we(e,{search:t,replacement:n,glob:String(e.glob),mode:e.write?"written":"dry-run",fileCount:i.length,totalReplacements:a,changes:i,errors:l},()=>{console.log(`${e.write?"replaced":"would replace"} ${a} occurrence(s) in ${i.length} file(s)`);for(const e of i)console.log(` ${e.count}× ${e.file}`);!e.write&&i.length&&console.log("re-run with --write to apply")}),l.length>0&&process.exit(1)}},Un=new Set(["node_modules",".git","dist","build","coverage",".nx"]);function Jn(e){const t=Math.round(e/1e3);return t<60?`${t}s ago`:t<3600?`${Math.round(t/60)}m ago`:t<86400?`${Math.round(t/3600)}h ago`:`${Math.round(t/86400)}d ago`}const Wn={command:"recent [dir]",describe:"Most recently modified files under a directory, with age",builder:e=>be(e).positional("dir",{describe:"Directory to scan (default: cwd)",type:"string"}).option("top",{alias:"t",describe:"How many files to return",type:"number",default:10}).option("ignore",{alias:"i",describe:"Additional directory names to ignore",type:"array"}).example("mfn recent --json","what changed last in this project?").example("mfn recent ./src -t 5 --json","five most recent under src"),handler:e=>{const t=Number(e.top);if(!Number.isInteger(t)||t<1||t>1e3)return $e(e,"InvalidTop","--top must be an integer in 1..1000.",2);const n=I.resolve(String(e.dir??process.cwd()));let o;try{o=O.statSync(n)}catch{return $e(e,"NotFound",`Directory not found: ${n}`,2)}if(!o.isDirectory())return $e(e,"NotADirectory",`${n} is not a directory.`,2);const r=new Set([...Un,...(e.ignore??[]).map(String)]),s=[];let i=!1;const a=e=>{if(s.length>=2e5)return void(i=!0);let t;try{t=O.readdirSync(e,{withFileTypes:!0})}catch{return}for(const o of t){if(r.has(o.name))continue;const t=I.join(e,o.name);if(o.isDirectory())a(t);else if(o.isFile())try{const e=O.statSync(t);s.push({path:I.relative(n,t),mtimeMs:e.mtimeMs,bytes:e.size})}catch{}}};a(n);const l=Date.now(),c=s.sort((e,t)=>t.mtimeMs-e.mtimeMs).slice(0,t).map(e=>({path:e.path,bytes:e.bytes,modified:new Date(e.mtimeMs).toISOString(),age:Jn(l-e.mtimeMs)}));we(e,{root:n,fileCount:s.length,truncated:i,files:c},()=>{for(const e of c)console.log(`${e.age.padStart(8)} ${e.path}`)})}};function qn(e){try{return JSON.parse(O.readFileSync(e,"utf8"))}catch{return null}}function Zn(e,t){const n=I.join(e,"node_modules",...t.split("/"),"package.json");return qn(n)?.version??null}function Gn(e,t){if(null===t)return!1;const n=e.replace(/^[\^~>=<]+/,"");return e===t||(!(!/^\d/.test(n)||n!==t)||null)}const Hn={command:"pkg [name]",describe:"Declared vs installed dependency versions — drift and missing installs",builder:e=>be(e).positional("name",{describe:"One dependency to inspect (omit for all)",type:"string"}).example("mfn pkg --json","is node_modules in sync with package.json?").example("mfn pkg typescript --json","one dependency, declared vs actually installed"),handler:e=>{const t=process.cwd(),n=qn(I.join(t,"package.json"));if(!n)return $e(e,"NoPackageJson",`No readable package.json in ${t}`);const o=["dependencies","devDependencies","optionalDependencies","peerDependencies"],r=[];for(const s of o)for(const[o,i]of Object.entries(n[s]??{})){if(void 0!==e.name&&o!==String(e.name))continue;const n=Zn(t,o);r.push({name:o,declared:String(i),section:s,installed:n,satisfiesExact:Gn(String(i),n)})}if(void 0!==e.name&&0===r.length)return $e(e,"NotDeclared",`"${e.name}" is not declared in package.json.`);const s=r.filter(e=>null===e.installed).map(e=>e.name);we(e,{package:n.name??null,version:n.version??null,depCount:r.length,missing:s,allInstalled:0===s.length,deps:r},()=>{for(const e of r){const t=null===e.installed?"✘ missing":e.installed;console.log(`${e.name.padEnd(40)} ${e.declared.padEnd(12)} → ${t}`)}s.length&&console.log(`\n${s.length} not installed — run your installer`)})}};function Vn(e){const t=[];for(const n of e.split("\n")){const e=n.trim();if(!e||e.startsWith("#"))continue;const o=/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/.exec(e);o&&t.push(o[1])}return t}const Yn={command:"dotenv",describe:"Check .env against .env.example — missing/extra keys, values never shown",builder:e=>be(e).option("file",{alias:"f",describe:"Env file to check",type:"string",default:".env"}).option("example",{alias:"e",describe:"Reference file",type:"string",default:".env.example"}).example("mfn dotenv --json","is .env complete vs .env.example?").example("mfn dotenv -f .env.local -e .env.example --json","check a specific pair"),handler:e=>{const t=String(e.file),n=String(e.example);let o=null,r=null;try{o=O.readFileSync(t,"utf8")}catch{}try{r=O.readFileSync(n,"utf8")}catch{}if(null===o&&null===r)return $e(e,"NotFound",`Neither ${t} nor ${n} is readable in ${process.cwd()}.`);const s=null!==o?Vn(o):[],i=null!==r?Vn(r):[],a=new Set(s),l=new Set(i),c=i.filter(e=>!a.has(e)),d=s.filter(e=>!l.has(e)),m=null===r?null:0===c.length;we(e,{file:t,fileExists:null!==o,example:n,exampleExists:null!==r,fileKeyCount:s.length,exampleKeyCount:i.length,missing:c,extra:d,complete:m,note:"values are intentionally never read or returned"},()=>{null===o&&console.log(`${t} does not exist`),null===r&&console.log(`${n} does not exist`),!0===m&&console.log(`✔ ${t} has all ${i.length} keys from ${n}`),c.length&&console.log(`missing: ${c.join(", ")}`),d.length&&console.log(`extra (undocumented): ${d.join(", ")}`)})}},Kn=e=>new Promise(t=>setTimeout(t,e));const Qn={command:"wait",describe:"Block until a port, file, or URL is ready (or timeout) — replaces sleep loops",builder:e=>be(e).option("port",{alias:"p",describe:"TCP port to wait for (on 127.0.0.1)",type:"number"}).option("url",{alias:"u",describe:"Wait until this URL responds 2xx/3xx",type:"string"}).option("file",{alias:"f",describe:"Wait until this file exists",type:"string"}).option("timeout",{alias:"t",describe:"Max seconds to wait",type:"number",default:30}).option("interval",{describe:"Poll interval in ms",type:"number",default:250}).example("mfn wait -p 3000 -t 30 --json","dev server is accepting connections").example("mfn wait -u http://localhost:3000/health --json","health endpoint is green").example("mfn wait -f dist/bin/index.js --json","build artifact exists"),handler:async e=>{if(1!==[e.port,e.url,e.file].filter(e=>void 0!==e).length)return $e(e,"InvalidTarget","Provide exactly one of --port, --url, or --file.",2);const t=Number(e.timeout);if(!Number.isFinite(t)||t<=0||t>600)return $e(e,"InvalidTimeout","--timeout must be 1..600 seconds.",2);const n=Number(e.interval);if(!Number.isInteger(n)||n<50||n>1e4)return $e(e,"InvalidInterval","--interval must be 50..10000 ms.",2);let o,r;if(void 0!==e.port){const t=Number(e.port);if(!Number.isInteger(t)||t<1||t>65535)return $e(e,"InvalidPort","--port must be an integer in 1..65535.",2);o=`port:${t}`,r=()=>function(e,t="127.0.0.1"){return new Promise(n=>{const o=M({port:e,host:t});o.setTimeout(1e3);const r=e=>{o.destroy(),n(e)};o.once("connect",()=>r(!0)),o.once("timeout",()=>r(!1)),o.once("error",()=>r(!1))})}(t)}else if(void 0!==e.url){const t=String(e.url);if(!/^https?:\/\//.test(t))return $e(e,"InvalidURL","--url must start with http:// or https://.",2);try{if(yt(new URL(t)))return $e(e,"BlockedTarget",bt(t),2)}catch{return $e(e,"InvalidURL",`"${t}" is not a valid URL.`,2)}o=`url:${t}`,r=()=>async function(e){try{return(await fetch(e,{method:"GET",signal:AbortSignal.timeout(3e3)})).ok}catch{return!1}}(t)}else{const t=String(e.file);o=`file:${t}`,r=async()=>A(t)}const s=Date.now(),i=s+1e3*t;let a=0;for(;Date.now()<i;){if(a++,await r()){const t=Date.now()-s;return we(e,{target:o,ready:!0,waitedMs:t,attempts:a},()=>console.log(`${o} ready after ${t}ms (${a} checks)`))}await Kn(n)}$e(e,"Timeout",`${o} was not ready within ${t}s (${a} checks).`)}},Xn=w(h),eo="win32"===u();const to={command:"ports",describe:"List ALL listening TCP ports with their owning processes",builder:e=>be(e).option("min",{describe:"Only ports >= this value",type:"number",default:1}).example("mfn ports --json","every listener — which dev servers are running?").example("mfn ports --min 3000 --json","just the app-range ports"),handler:async e=>{const t=Number(e.min);if(!Number.isInteger(t)||t<1||t>65535)return $e(e,"InvalidMin","--min must be an integer in 1..65535.",2);let n;try{n=eo?await async function(){const{stdout:e}=await Xn("netstat",["-ano"],{timeout:1e4}),t=[];for(const n of e.split("\n")){if(!/LISTENING/i.test(n))continue;const e=n.trim().split(/\s+/),o=/^(.*):(\d+)$/.exec(e[1]??"");o&&t.push({port:Number(o[2]),pid:Number(e[e.length-1]),command:null,address:o[1]})}return t}():await async function(){let e;try{({stdout:e}=await Xn("lsof",["-iTCP","-sTCP:LISTEN","-P","-n"],{timeout:1e4}))}catch(e){if(1===e?.code&&!String(e?.stdout??"").trim())return[];throw e}const t=[];for(const n of e.split("\n").slice(1)){const e=n.trim().split(/\s+/);if(e.length<9)continue;const o=e[e.length-2].includes(":")?e[e.length-2]:e[8],r=/^(.*):(\d+)$/.exec(o);r&&t.push({port:Number(r[2]),pid:Number(e[1]),command:e[0],address:r[1]})}return t}()}catch(t){return $e(e,"ListError",`Could not list listeners: ${t instanceof Error?t.message:String(t)}`)}const o=new Map;for(const e of n){if(e.port<t)continue;const n=`${e.port}:${e.pid}`;o.has(n)||o.set(n,e)}const r=[...o.values()].sort((e,t)=>e.port-t.port);we(e,{count:r.length,listeners:r},()=>{for(const e of r)console.log(`${String(e.port).padStart(6)} pid ${String(e.pid).padEnd(8)} ${e.command??""}`)})}},no={command:"http <url>",describe:"Probe a URL: status, headers, timing, capped body preview (never a full dump)",builder:e=>be(e).positional("url",{describe:"URL to probe (scheme optional — http:// assumed)",type:"string"}).option("method",{alias:"m",describe:"HTTP method",type:"string",choices:["GET","HEAD"],default:"GET"}).option("timeout",{alias:"t",describe:"Timeout in seconds",type:"number",default:10}).option("header",{alias:"H",describe:'Request header(s), "Name: value"',type:"array"}).example("mfn http https://api.github.com --json","status + headers + timing").example("mfn http localhost:3000/health --json","is my dev server healthy?"),handler:async e=>{let t,n=String(e.url);/^https?:\/\//.test(n)||(n=`http://${n}`);try{t=new URL(n)}catch{return $e(e,"InvalidURL",`"${e.url}" is not a valid URL.`,2)}if(yt(t))return $e(e,"BlockedTarget",bt(String(t)),2);const o=Number(e.timeout);if(!Number.isFinite(o)||o<=0||o>120)return $e(e,"InvalidTimeout","--timeout must be 1..120 seconds.",2);const r={};for(const t of(e.header??[]).map(String)){const n=t.indexOf(":");if(n<1)return $e(e,"InvalidHeader",`Header "${t}" must be "Name: value".`,2);r[t.slice(0,n).trim()]=t.slice(n+1).trim()}const s=Date.now();let i;try{i=await fetch(t,{method:String(e.method),headers:r,redirect:"follow",signal:AbortSignal.timeout(1e3*o)})}catch(n){return $e(e,"RequestFailed",`${t}: ${n instanceof Error?n.cause?.message||n.message:String(n)}`)}const a=Date.now()-s;let l=null,c=null;if("HEAD"!==String(e.method))try{const e=await i.text();c=Buffer.byteLength(e,"utf8"),l=e.slice(0,2048)}catch{}const d={};i.headers.forEach((e,t)=>{d[t]="set-cookie"===t.toLowerCase()?"[redacted: session cookie]":e}),we(e,{url:i.url,method:String(e.method),status:i.status,statusText:i.statusText,ok:i.ok,redirected:i.redirected,timeMs:a,headers:d,bodyBytes:c,bodyPreview:l,bodyTruncated:null!==c&&c>2048},()=>{console.log(`${i.status} ${i.statusText} (${a}ms) ${i.url}`),console.log(`content-type: ${d["content-type"]??"?"}`),l&&console.log(l.slice(0,500))}),i.ok||process.exit(1)}};const oo={command:"base <value>",describe:"Convert a number between bases (hex/dec/bin/oct) exactly — BigInt, no rounding",builder:e=>be(e).positional("value",{describe:"Number: 0xff, 0b1010, 0o755, or decimal",type:"string"}).option("from",{alias:"f",describe:"Base of an unprefixed input",type:"string",choices:["hex","dec","bin","oct"]}).example("mfn base 0xff --json","hex → all bases").example("mfn base 255 --json","decimal → all bases").example("mfn base ff -f hex --json","unprefixed hex"),handler:e=>{const t=String(e.value);if(t.length>4096)return $e(e,"InputTooLarge","Input exceeds 4096 characters.",2);let n;try{n=function(e,t){const n=e.trim().toLowerCase().replace(/_/g,""),o=n.startsWith("-"),r=o?n.slice(1):n;let s,i;if(r.startsWith("0x")?(s=16,i=r.slice(2)):r.startsWith("0b")?(s=2,i=r.slice(2)):r.startsWith("0o")?(s=8,i=r.slice(2)):(s=t?{hex:16,dec:10,bin:2,oct:8}[t]:10,i=r),!i||!{2:/^[01]+$/,8:/^[0-7]+$/,10:/^[0-9]+$/,16:/^[0-9a-f]+$/}[s].test(i))throw new Error(`"${e}" is not a valid base-${s} number`);let a=0n;const l=BigInt(s);for(const e of i)a=a*l+BigInt(parseInt(e,16));return{value:o?-a:a,detectedBase:s}}(t,e.from?String(e.from):void 0)}catch(t){return $e(e,"InvalidNumber",t instanceof Error?t.message:String(t),2)}const o=n.value,r=o<0n?-o:o,s=o<0n?"-":"";we(e,{input:t,inputBase:n.detectedBase,dec:o.toString(10),hex:`${s}0x${r.toString(16)}`,bin:`${s}0b${r.toString(2)}`,oct:`${s}0o${r.toString(8)}`,bits:r.toString(2).length,exact:!0},()=>{console.log(`dec ${o.toString(10)}`),console.log(`hex ${s}0x${r.toString(16)}`),console.log(`bin ${s}0b${r.toString(2)}`),console.log(`oct ${s}0o${r.toString(8)}`)})}},ro=u(),so=1e6;function io(e,t,n){return new Promise((o,r)=>{const s=h(e,t,{timeout:5e3,maxBuffer:10485760},(e,t)=>e?r(e):o(t));void 0!==n&&s.stdin?.end(n)})}const ao={command:"clip [text]",describe:"Read or write the system clipboard (macOS/Windows/Linux)",builder:e=>be(e).positional("text",{describe:"Text to copy (or pipe stdin); omit to read",type:"string"}).option("read",{alias:"r",describe:"Force read mode even when stdin is piped",type:"boolean",default:!1}).example("mfn clip --json","read the clipboard").example('mfn clip "deploy done" --json',"copy text to the clipboard").example("git diff | mfn clip --json","copy a diff for the user to paste"),handler:async e=>{let t;if(!e.read)if(void 0!==e.text)t=String(e.text);else{const e=await Se();e&&(t=e)}try{if(void 0!==t)return t.length>so?$e(e,"InputTooLarge","Clipboard writes are capped at 1000000 chars.",2):(await async function(e){if("darwin"===ro)await io("pbcopy",[],e);else if("win32"===ro)await io("clip.exe",[],e);else try{await io("xclip",["-selection","clipboard"],e)}catch{await io("wl-copy",[],e)}}(t),we(e,{action:"write",chars:t.length},()=>console.log(`copied ${t.length} chars`)));const n=await async function(){if("darwin"===ro)return io("pbpaste",[]);if("win32"===ro)return io("powershell",["-NoProfile","-Command","Get-Clipboard -Raw"]);try{return await io("xclip",["-selection","clipboard","-o"])}catch{return io("wl-paste",["--no-newline"])}}(),o=ht(n);if(o)return we(e,{action:"read",chars:n.length,text:null,redacted:!0,reason:`clipboard contains a ${o} — content withheld (guardrail)`},()=>console.log(`[redacted: clipboard contains a ${o}]`));we(e,{action:"read",chars:n.length,text:n,redacted:!1},()=>console.log(n))}catch(t){return $e(e,"ClipboardUnavailable",`Clipboard tool failed (headless session? missing xclip/wl-clipboard?): ${t instanceof Error?t.message:String(t)}`)}}},lo=w(h),co=u(),mo=e=>e.replace(/\\/g,"\\\\").replace(/"/g,'\\"');const uo=2e3,po={command:"notify <message>",describe:"Send a desktop notification (macOS/Windows/Linux) — ping the user, hands-free",builder:e=>be(e).positional("message",{describe:"Notification body",type:"string"}).option("title",{alias:"t",describe:"Notification title",type:"string",default:"mfn"}).example('mfn notify "build finished" --json',"tell the user a long task is done").example('mfn notify "3 tests failing" -t "CI watch" --json',"titled notification"),handler:async e=>{const t=String(e.message),n=String(e.title);if(t.length>uo||n.length>uo)return $e(e,"InputTooLarge","Title/message are capped at 2000 chars.",2);try{await async function(e,t){if("darwin"===co){const n=`display notification "${mo(t)}" with title "${mo(e)}"`;await lo("osascript",["-e",n],{timeout:5e3})}else if("win32"===co){const n='$ErrorActionPreference=\'Stop\';[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null;$t=[Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02);$n=$t.GetElementsByTagName("text");$n.Item(0).AppendChild($t.CreateTextNode($env:MFN_NOTIFY_TITLE))|Out-Null;$n.Item(1).AppendChild($t.CreateTextNode($env:MFN_NOTIFY_MESSAGE))|Out-Null;[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("mfn").Show([Windows.UI.Notifications.ToastNotification]::new($t))';await lo("powershell",["-NoProfile","-Command",n],{timeout:1e4,env:{...process.env,MFN_NOTIFY_TITLE:e,MFN_NOTIFY_MESSAGE:t}})}else await lo("notify-send",[e,t],{timeout:5e3})}(n,t)}catch(t){return $e(e,"NotifyFailed",`Could not send a notification (headless session? missing notify-send?): ${t instanceof Error?t.message:String(t)}`)}we(e,{sent:!0,title:n,message:t},()=>console.log("notification sent"))}},fo=w(h),ho=u();const go={command:"open <target>",describe:"Open a file or URL in the default app/browser (validated first)",builder:e=>be(e).positional("target",{describe:"http(s) URL, or an existing file/directory",type:"string"}).example("mfn open https://github.com/Master4Novice/master-cli --json","show the user a page").example("mfn open coverage/index.html --json","open a report you just generated"),handler:async e=>{const t=String(e.target);let n,o=t;if(/^https?:\/\//i.test(t)){try{new URL(t)}catch{return $e(e,"InvalidURL",`"${t}" is not a valid URL.`,2)}n="url"}else{if(/^[a-z][a-z0-9+.-]*:/i.test(t))return $e(e,"UnsupportedScheme","Only http(s) URLs or local paths are allowed.",2);if(o=I.resolve(t),!A(o))return $e(e,"NotFound",`No such file or directory: ${o}`,2);n="file"}try{const t=await async function(e){return"darwin"===ho?(await fo("open",[e],{timeout:1e4}),"open"):"win32"===ho?(await fo("rundll32",["url.dll,FileProtocolHandler",e],{timeout:1e4}),"rundll32"):(await fo("xdg-open",[e],{timeout:1e4}),"xdg-open")}(o);we(e,{opened:!0,kind:n,target:o,opener:t},()=>console.log(`opened ${o}`))}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,"OpenFailed",`Could not open ${o}: ${n}`)}}},yo=w(h),bo="win32"===u();const vo={command:"procs [pattern]",describe:"Search running processes by name — pid/cpu/mem without ps|grep gymnastics",builder:e=>be(e).positional("pattern",{describe:"Case-insensitive substring of the command name",type:"string"}).option("top",{alias:"t",describe:"Max results (sorted by cpu, then mem)",type:"number",default:25}).example("mfn procs node --json","every node process with pid/cpu/mem").example("mfn procs --json","top 25 by cpu — what is this machine doing?"),handler:async e=>{const t=Number(e.top);if(!Number.isInteger(t)||t<1||t>5e3)return $e(e,"InvalidTop","--top must be an integer in 1..5000.",2);let n;try{n=bo?await async function(){const{stdout:e}=await yo("tasklist",["/FO","CSV","/NH"],{timeout:1e4,maxBuffer:20971520}),t=[];for(const n of e.split("\n")){const e=n.match(/"([^"]*)"/g)?.map(e=>e.slice(1,-1));if(!e||e.length<5)continue;const o=Number(e[4].replace(/[^\d]/g,""));t.push({pid:Number(e[1]),cpu:null,memMB:Number.isFinite(o)?Math.round(o/1024*10)/10:null,command:e[0]})}return t}():await async function(){const{stdout:e}=await yo("ps",["axo","pid=,pcpu=,rss=,comm="],{timeout:1e4,maxBuffer:20971520}),t=[];for(const n of e.split("\n")){const e=/^\s*(\d+)\s+([\d.]+)\s+(\d+)\s+(.+)$/.exec(n);e&&t.push({pid:Number(e[1]),cpu:Number(e[2]),memMB:Math.round(Number(e[3])/1024*10)/10,command:e[4].trim()})}return t}()}catch(t){return $e(e,"ListError",`Could not list processes: ${t instanceof Error?t.message:String(t)}`)}const o=void 0!==e.pattern?String(e.pattern).toLowerCase():null,r=o?n.filter(e=>e.command.toLowerCase().includes(o)):n,s=r.sort((e,t)=>(t.cpu??0)-(e.cpu??0)||(t.memMB??0)-(e.memMB??0)).slice(0,t);we(e,{pattern:o,total:n.length,matched:r.length,processes:s},()=>{for(const e of s){const t=null===e.cpu?" -":`${e.cpu.toFixed(1)}%`.padStart(6);console.log(`${String(e.pid).padStart(7)} ${t} ${String(e.memMB??"-").padStart(8)}M ${e.command}`)}})}},xo=w(h),wo="win32"===u();const $o=e=>e>=1024**4?`${(e/1024**4).toFixed(1)}T`:`${(e/1024**3).toFixed(1)}G`,jo={command:"disk",describe:"Disk usage per mount (total/free/used%) — df parsing done for you",builder:e=>be(e).option("all",{alias:"a",describe:"Include pseudo/small filesystems (< 1GB)",type:"boolean",default:!1}).example("mfn disk --json","is there room for this build?"),handler:async e=>{let t;try{t=wo?await async function(){const{stdout:e}=await xo("powershell",["-NoProfile","-Command","Get-CimInstance Win32_LogicalDisk | Select-Object DeviceID,Size,FreeSpace | ConvertTo-Json"],{timeout:15e3}),t=JSON.parse(e);return(Array.isArray(t)?t:[t]).filter(e=>Number(e.Size)>0).map(e=>({mount:String(e.DeviceID),filesystem:null,totalBytes:Number(e.Size),freeBytes:Number(e.FreeSpace),usedPercent:Math.round((Number(e.Size)-Number(e.FreeSpace))/Number(e.Size)*100)}))}():await async function(){const{stdout:e}=await xo("df",["-kP"],{timeout:1e4}),t=[];for(const n of e.split("\n").slice(1)){const e=n.trim().split(/\s+/);if(e.length<6)continue;const o=1024*Number(e[1]),r=1024*Number(e[3]);Number.isFinite(o)&&0!==o&&t.push({mount:e.slice(5).join(" "),filesystem:e[0],totalBytes:o,freeBytes:r,usedPercent:Math.round((o-r)/o*100)})}return t}()}catch(t){return $e(e,"DiskError",`Could not read disk usage: ${t instanceof Error?t.message:String(t)}`)}e.all||(t=t.filter(e=>e.totalBytes>=1024**3&&!/^\/(dev|proc|sys|run)/.test(e.mount))),t.sort((e,t)=>t.totalBytes-e.totalBytes),we(e,{count:t.length,mounts:t},()=>{for(const e of t)console.log(`${$o(e.totalBytes).padStart(8)} total ${$o(e.freeBytes).padStart(8)} free ${String(e.usedPercent).padStart(3)}% ${e.mount}`)})}},So=w(h),No=u();function ko(e,t){if(!O.existsSync(I.join(e,t)))return t;const n=I.extname(t),o=t.slice(0,t.length-n.length);for(let t=1;;t++){const r=`${o} ${t}${n}`;if(!O.existsSync(I.join(e,r)))return r}}function Eo(e){const t=I.join(p(),".Trash"),n=I.join(t,ko(t,I.basename(e)));return O.renameSync(e,n),n}function Io(e){const t=I.join(p(),".local","share","Trash");O.mkdirSync(I.join(t,"files"),{recursive:!0}),O.mkdirSync(I.join(t,"info"),{recursive:!0});const n=ko(I.join(t,"files"),I.basename(e)),o=(new Date).toISOString().slice(0,19);O.writeFileSync(I.join(t,"info",`${n}.trashinfo`),`[Trash Info]\nPath=${encodeURI(e)}\nDeletionDate=${o}\n`);const r=I.join(t,"files",n);return O.renameSync(e,r),r}async function Oo(e){if(await So("powershell",["-NoProfile","-Command",'$ErrorActionPreference=\'Stop\';Add-Type -AssemblyName Microsoft.VisualBasic;$p=$env:MFN_TRASH_PATH;if (Test-Path -LiteralPath $p -PathType Container) {[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteDirectory($p,"OnlyErrorDialogs","SendToRecycleBin")} else {[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($p,"OnlyErrorDialogs","SendToRecycleBin")}'],{timeout:15e3,env:{...process.env,MFN_TRASH_PATH:e}}),O.existsSync(e))throw new Error("Recycle Bin reported success but the path still exists");return"Recycle Bin"}const Ao={command:"trash <paths...>",describe:"Move files/dirs to the OS trash — reversible, never rm -rf",builder:e=>be(e).positional("paths",{describe:"Files or directories to trash",type:"string"}).example("mfn trash build-old.log --json","recoverable delete").example("mfn trash dist coverage --json","trash multiple paths in one call"),handler:async e=>{const t=e.paths.map(String),n=[],o=[];for(const e of t){const t=I.resolve(e);if(!O.existsSync(t)){o.push({path:t,error:"does not exist"});continue}let r,s,i;try{r=O.realpathSync(t),s=O.realpathSync(process.cwd()),i=O.realpathSync(p())}catch{r=t,s=process.cwd(),i=p()}if(r===I.parse(r).root||r===i||r===s||s.startsWith(r+I.sep))o.push({path:t,error:"refusing to trash root/home/cwd (or a parent of cwd)"});else try{const e="darwin"===No?Eo(t):"win32"===No?await Oo(t):Io(t);n.push({path:t,movedTo:e})}catch(e){o.push({path:t,error:e instanceof Error?e.message:String(e)})}}if(0===n.length&&o.length>0)return $e(e,"TrashFailed",o.map(e=>`${e.path}: ${e.error}`).join("; "));we(e,{trashed:n,failed:o,count:n.length},()=>{for(const e of n)console.log(`trashed ${e.path}`);for(const e of o)console.error(`failed ${e.path}: ${e.error}`)}),o.length>0&&process.exit(1)}},To=async e=>{try{return await e}catch{return null}},Mo={command:"dns <hostname>",describe:"Resolve a hostname: A/AAAA/CNAME/MX/TXT/NS in one call (no dig parsing)",builder:e=>be(e).positional("hostname",{describe:"Hostname to resolve",type:"string"}).option("type",{alias:"t",describe:"Single record type instead of the full sweep",type:"string",choices:["a","aaaa","cname","mx","txt","ns"]}).example("mfn dns github.com --json","all common records at once").example("mfn dns example.com -t mx --json","just the MX records"),handler:async e=>{const t=String(e.hostname).trim().toLowerCase();if(!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/.test(t))return $e(e,"InvalidHostname",`"${e.hostname}" is not a valid hostname.`,2);if(e.type){const n=String(e.type),o={a:()=>C(t),aaaa:()=>_(t),cname:()=>z(t),mx:()=>R(t),txt:()=>P(t),ns:()=>F(t)};try{const r=await o[n]();return we(e,{hostname:t,type:n,records:r},()=>console.log(JSON.stringify(r,null,2)))}catch(o){const r=o instanceof Error?o.message:String(o);return $e(e,"ResolveFailed",`${n.toUpperCase()} lookup for ${t}: ${r}`)}}const[n,o,r,s,i,a,l]=await Promise.all([To(L(t)),To(C(t)),To(_(t)),To(z(t)),To(R(t)),To(P(t)),To(F(t))]);if(!(n||o||r||s))return $e(e,"ResolveFailed",`${t} did not resolve (no A/AAAA/CNAME).`);we(e,{hostname:t,resolved:n?{address:n.address,family:`IPv${n.family}`}:null,a:o,aaaa:r,cname:s,mx:i,txt:a?a.map(e=>e.join("")):null,ns:l},()=>{n&&console.log(`${t} → ${n.address}`),o&&console.log(`A ${o.join(", ")}`),r&&console.log(`AAAA ${r.join(", ")}`),i&&console.log(`MX ${i.map(e=>`${e.priority} ${e.exchange}`).join(", ")}`),l&&console.log(`NS ${l.join(", ")}`)})}},Lo=2e5,Co={update:"installs npm packages globally — not exposed to MCP clients",mcp:"starting a server inside the server is never what you want"},_o=oe.map(e=>e.name).filter(e=>!(e in Co)),zo=[{name:"mfn_capabilities",description:"Machine-readable manifest of every mfn command (name, category, summary, examples). Call this first to discover what mfn can do.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"mfn_run",description:'Run one mfn command headlessly and return its single JSON result object. `command` is a name from mfn_capabilities (e.g. "epoch"); `args` are the documented CLI flags/positionals (e.g. ["1622547800"] or ["-f","data.json"]). `--json` is added automatically. Security guardrails are always on.',inputSchema:{type:"object",properties:{command:{type:"string",description:"Command name from mfn_capabilities",enum:_o},args:{type:"array",items:{type:"string"},description:"CLI arguments exactly as documented (flags and positionals)"}},required:["command"],additionalProperties:!1}},{name:"mfn_help",description:"Full --help text (flags, examples) for one mfn command.",inputSchema:{type:"object",properties:{command:{type:"string",description:"Command name from mfn_capabilities"}},required:["command"],additionalProperties:!1}}],Ro=e=>new Promise(t=>{h(process.execPath,[process.argv[1],...e],{timeout:12e4,maxBuffer:8388608,windowsHide:!0},(e,n)=>{const o=e?"number"==typeof e.code?e.code:1:0;t({code:o,stdout:String(n??"")})})}),Po=(e,t)=>{const n=e.length>Lo?e.slice(0,Lo)+"\n[truncated at 200000 chars]":e,o={content:[{type:"text",text:n}],isError:t};try{const e=JSON.parse(n);e&&"object"==typeof e&&!Array.isArray(e)&&(o.structuredContent=e)}catch{}return o},Fo=e=>({content:[{type:"text",text:JSON.stringify({ok:!1,error:"McpToolError",message:e})}],isError:!0});const Do="2025-06-18",Bo=e=>{process.stdout.write(JSON.stringify(e)+"\n")},Uo=(e,t)=>Bo({jsonrpc:"2.0",id:e,result:t}),Jo=(e,t,n)=>Bo({jsonrpc:"2.0",id:e,error:{code:t,message:n}});async function Wo(e){const{id:t,method:n,params:o}=e??{},r=null!=t;if("string"==typeof n){if(!n.startsWith("notifications/"))switch(n){case"initialize":{const e=o?.protocolVersion;return void Uo(t,{protocolVersion:"string"==typeof e?e:Do,capabilities:{tools:{}},serverInfo:{name:se,version:ie},instructions:`Wraps the mfn CLI (${oe.length} headless commands). Call mfn_capabilities first to discover commands, then mfn_run {command, args} to execute one — every result is a single JSON object ({ok:true,...} or {ok:false,error,message}). mfn_help returns per-command flags. Security guardrails (sensitive-path refusal, secret redaction, reversible deletes) are always on; \`update\` is not exposed.`})}case"ping":return void Uo(t,{});case"tools/list":return void Uo(t,{tools:zo});case"tools/call":{const e=String(o?.name??"");return zo.some(t=>t.name===e)?void Uo(t,await async function(e,t){if("mfn_capabilities"===e){const e=await Ro(["capabilities","--json"]);return Po(e.stdout.trim(),0!==e.code)}if("mfn_help"===e){const e=String(t?.command??"");if(!oe.some(t=>t.name===e))return Fo(`Unknown command "${e}". Call mfn_capabilities for the list.`);const n=await Ro([e,"--help"]);return Po(n.stdout.trim(),0!==n.code)}if("mfn_run"===e){const e=String(t?.command??"");if(e in Co)return Fo(`"${e}" is not available over MCP: ${Co[e]}.`);if(!oe.some(t=>t.name===e))return Fo(`Unknown command "${e}". Call mfn_capabilities for the list.`);const n=t?.args??[];if(!Array.isArray(n)||n.length>64)return Fo('"args" must be an array of at most 64 strings.');const o=n.map(String);if(o.some(e=>e.length>1e4||e.includes("\0")))return Fo("Each argument must be under 10000 chars with no NUL bytes.");const r=await Ro([e,...o,"--json"]),s=r.stdout.trim();return s?Po(s,0!==r.code):Fo(`"${e}" produced no output (exit ${r.code}).`)}return Fo(`Unknown tool "${e}".`)}(e,o?.arguments??{})):void Jo(t,-32602,`Unknown tool "${e}"`)}default:r&&Jo(t,-32601,`Method not found: ${n}`)}}else r&&Jo(t,-32600,"Invalid request: no method")}const qo={command:"mcp",describe:"Serve every mfn command over the Model Context Protocol (stdio) — for MCP clients without shell access",builder:e=>be(e).example("mfn mcp","start the MCP server (stdio, JSON-RPC per line)").example("mfn mcp --json","describe the server + client wiring (does not start it)"),handler:async e=>{e.json?we(e,{transport:"stdio",protocolVersion:Do,tools:zo.map(e=>e.name),commands:_o.length,denied:Object.keys(Co),clientConfig:{command:"npx",args:["-y","@master4n/master-cli","mcp"]},note:"Run `mfn mcp` (no flags) to start the server."},()=>{}):await async function(){process.stderr.write(`${se} v${ie} — MCP server ready (stdio)\n`);const e=D({input:process.stdin,crlfDelay:1/0});for await(const t of e){const e=t.trim();if(!e)continue;let n;try{n=JSON.parse(e)}catch{Jo(null,-32700,"Parse error: messages must be one JSON object per line");continue}try{await Wo(n)}catch(e){const t=e instanceof Error?e.message:String(e);Jo(n?.id??null,-32603,`Internal error: ${t}`)}}process.exit(0)}()}};function Zo(e,t,n){if(Math.abs(e.length-t.length)>n)return n+1;let o=Array.from({length:t.length+1},(e,t)=>t);for(let r=1;r<=e.length;r++){const s=[r];let i=r;for(let n=1;n<=t.length;n++)s[n]=Math.min(o[n]+1,s[n-1]+1,o[n-1]+(e[r-1]===t[n-1]?0:1)),i=Math.min(i,s[n]);if(i>n)return n+1;o=s}return o[t.length]}const Go=e=>function(e){return{add:(t,n,o,r)=>{e.command({command:t,describe:n,builder:o,handler:r})}}}(ge).add(e.command,e.describe,e.builder,e.handler);Go(rt),Go(qo),Go(at),Go(xt),Go($t),Go(St),Go(Ge),Go(Je),Go(Pe),Go(It),Go(In),Go(At),Go(Tt),Go(cn),Go(vn),Go(Qt),Go(kn),Go(Jt),Go(Gt),Go(an),Go(xn),Go(wn),Go(Cn),Go(Fn),Go(Bn),Go(Wn),Go(Hn),Go(Yn),Go(oo),Go(Et),Go(to),Go(et),Go(Qn),Go(no),Go(_e),Go(Ae),Go(zt),Go(Rt),Go(Dt),Go(pn),Go(gn),Go(bn),Go($n),Go(ao),Go(po),Go(go),Go(vo),Go(jo),Go(Ao),Go(Mo),Go(ot),ge.usage("mfn <command> [options]\n\nMaster CLI for developers and AI agents — headless, JSON-first commands that\nreplace boilerplate agents regenerate on every machine. Every command supports\n--json (machine output) and -h/--help (this text).").version(ie).alias("version","v").help().alias("help","h").epilogue("Discover every command (machine-readable): mfn capabilities --json\nAgent contract & examples: see llms.txt in this package.\nDocs: https://github.com/Master4Novice/master-cli#readme").wrap(null).strict().demandCommand(1,"No command given. Run `mfn capabilities` to list commands.").fail((e,t)=>{t&&Ne("CommandError",t.message||String(t),1),Ne("UsageError",function(e){const t=/^Unknown arguments?: (.+)$/.exec(e);if(!t)return e;const n=t[1].split(",").map(e=>e.trim()),o=process.argv.slice(2).find(e=>!e.startsWith("-")),r=n.find(e=>e===o);if(!r)return e;let s=null,i=3;for(const e of oe){const t=Zo(r,e.name,i);t<i&&(i=t,s=e.name)}return`Unknown command: ${r}.${s?` Did you mean "${s}"?`:""} Run \`mfn capabilities\` to list commands.`}(e||"Invalid command invocation."),2)}).parse();
|
|
35
|
+
function(e){if(Array.isArray(e))return e.map(e=>"string"!=typeof e?e+"":e);e=e.trim();let t=0,n=null,o=null,r=null;const s=[];for(let i=0;i<e.length;i++)n=o,o=e.charAt(i)," "!==o||r?(o===r?r=null:"'"!==o&&'"'!==o||r||(r=o),s[t]||(s[t]=""),s[t]+=o):" "!==n&&t++;return s}(e),r="string"==typeof e,s=function(e){const t=[],n=Object.create(null);let o=!0;Object.keys(e).forEach(function(n){t.push([].concat(e[n],n))});for(;o;){o=!1;for(let e=0;e<t.length;e++)for(let n=e+1;n<t.length;n++){if(t[e].filter(function(e){return-1!==t[n].indexOf(e)}).length){t[e]=t[e].concat(t[n]),t.splice(n,1),o=!0;break}}}return t.forEach(function(e){const t=(e=e.filter(function(e,t,n){return n.indexOf(e)===t})).pop();void 0!==t&&"string"==typeof t&&(n[t]=e)}),n}(Object.assign(Object.create(null),n.alias)),i=Object.assign({"boolean-negation":!0,"camel-case-expansion":!0,"combine-arrays":!1,"dot-notation":!0,"duplicate-arguments-array":!0,"flatten-duplicate-arrays":!0,"greedy-arrays":!0,"halt-at-non-option":!1,"nargs-eats-options":!1,"negation-prefix":"no-","parse-numbers":!0,"parse-positional-numbers":!0,"populate--":!1,"set-placeholder-key":!1,"short-option-groups":!0,"strip-aliased":!1,"strip-dashed":!1,"unknown-options-as-args":!1},n.configuration),a=Object.assign(Object.create(null),n.default),l=n.configObjects||[],c=n.envPrefix,d=i["populate--"],m=d?"--":"_",u=Object.create(null),p=Object.create(null),f=n.__||W.format,h={aliases:Object.create(null),arrays:Object.create(null),bools:Object.create(null),strings:Object.create(null),numbers:Object.create(null),counts:Object.create(null),normalize:Object.create(null),configs:Object.create(null),nargs:Object.create(null),coercions:Object.create(null),keys:[]},g=/^-([0-9]+(\.[0-9]+)?|\.[0-9]+)$/,y=new RegExp("^--"+i["negation-prefix"]+"(.+)");[].concat(n.array||[]).filter(Boolean).forEach(function(e){const t="object"==typeof e?e.key:e,n=Object.keys(e).map(function(e){return{boolean:"bools",string:"strings",number:"numbers"}[e]}).filter(Boolean).pop();n&&(h[n][t]=!0),h.arrays[t]=!0,h.keys.push(t)}),[].concat(n.boolean||[]).filter(Boolean).forEach(function(e){h.bools[e]=!0,h.keys.push(e)}),[].concat(n.string||[]).filter(Boolean).forEach(function(e){h.strings[e]=!0,h.keys.push(e)}),[].concat(n.number||[]).filter(Boolean).forEach(function(e){h.numbers[e]=!0,h.keys.push(e)}),[].concat(n.count||[]).filter(Boolean).forEach(function(e){h.counts[e]=!0,h.keys.push(e)}),[].concat(n.normalize||[]).filter(Boolean).forEach(function(e){h.normalize[e]=!0,h.keys.push(e)}),"object"==typeof n.narg&&Object.entries(n.narg).forEach(([e,t])=>{"number"==typeof t&&(h.nargs[e]=t,h.keys.push(e))}),"object"==typeof n.coerce&&Object.entries(n.coerce).forEach(([e,t])=>{"function"==typeof t&&(h.coercions[e]=t,h.keys.push(e))}),void 0!==n.config&&(Array.isArray(n.config)||"string"==typeof n.config?[].concat(n.config).filter(Boolean).forEach(function(e){h.configs[e]=!0}):"object"==typeof n.config&&Object.entries(n.config).forEach(([e,t])=>{"boolean"!=typeof t&&"function"!=typeof t||(h.configs[e]=t)})),function(...e){e.forEach(function(e){Object.keys(e||{}).forEach(function(e){h.aliases[e]||(h.aliases[e]=[].concat(s[e]||[]),h.aliases[e].concat(e).forEach(function(t){if(/-/.test(t)&&i["camel-case-expansion"]){const n=U(t);n!==e&&-1===h.aliases[e].indexOf(n)&&(h.aliases[e].push(n),u[n]=!0)}}),h.aliases[e].concat(e).forEach(function(t){if(t.length>1&&/[A-Z]/.test(t)&&i["camel-case-expansion"]){const n=function(e,t){const n=e.toLowerCase();t=t||"-";let o="";for(let r=0;r<e.length;r++){const s=n.charAt(r),i=e.charAt(r);o+=s!==i&&r>0?`${t}${n.charAt(r)}`:i}return o}(t,"-");n!==e&&-1===h.aliases[e].indexOf(n)&&(h.aliases[e].push(n),u[n]=!0)}}),h.aliases[e].forEach(function(t){h.aliases[t]=[e].concat(h.aliases[e].filter(function(e){return t!==e}))}))})})}(n.key,s,n.default,h.arrays),Object.keys(a).forEach(function(e){(h.aliases[e]||[]).forEach(function(t){a[t]=a[e]})});let b=null;Object.keys(h.counts).find(e=>C(e,h.arrays)?(b=Error(f("Invalid configuration: %s, opts.count excludes opts.array.",e)),!0):!!C(e,h.nargs)&&(b=Error(f("Invalid configuration: %s, opts.count excludes opts.narg.",e)),!0));let v=[];const x=Object.assign(Object.create(null),{_:[]}),w={};for(let e=0;e<o.length;e++){const t=o[e],n=t.replace(/^-{3,}/,"---");let r,s,a,l,c,d;if("--"!==t&&/^-/.test(t)&&z(t))$(t);else{if(n.match(/^---+(=|$)/)){$(t);continue}if(t.match(/^--.+=/)||!i["short-option-groups"]&&t.match(/^-.+=/))l=t.match(/^--?([^=]+)=([\s\S]*)$/),null!==l&&Array.isArray(l)&&l.length>=3&&(C(l[1],h.arrays)?e=S(e,l[1],o,l[2]):!1!==C(l[1],h.nargs)?e=j(e,l[1],o,l[2]):N(l[1],l[2],!0));else if(t.match(y)&&i["boolean-negation"])l=t.match(y),null!==l&&Array.isArray(l)&&l.length>=2&&(s=l[1],N(s,!!C(s,h.arrays)&&[!1]));else if(t.match(/^--.+/)||!i["short-option-groups"]&&t.match(/^-[^-]+/))l=t.match(/^--?(.+)/),null!==l&&Array.isArray(l)&&l.length>=2&&(s=l[1],C(s,h.arrays)?e=S(e,s,o):!1!==C(s,h.nargs)?e=j(e,s,o):(c=o[e+1],void 0===c||c.match(/^-/)&&!c.match(g)||C(s,h.bools)||C(s,h.counts)?/^(true|false)$/.test(c)?(N(s,c),e++):N(s,P(s)):(N(s,c),e++)));else if(t.match(/^-.\..+=/))l=t.match(/^-([^=]+)=([\s\S]*)$/),null!==l&&Array.isArray(l)&&l.length>=3&&N(l[1],l[2]);else if(t.match(/^-.\..+/)&&!t.match(g))c=o[e+1],l=t.match(/^-(.\..+)/),null!==l&&Array.isArray(l)&&l.length>=2&&(s=l[1],void 0===c||c.match(/^-/)||C(s,h.bools)||C(s,h.counts)?N(s,P(s)):(N(s,c),e++));else if(t.match(/^-[^-]+/)&&!t.match(g)){a=t.slice(1,-1).split(""),r=!1;for(let n=0;n<a.length;n++){if(c=t.slice(n+2),a[n+1]&&"="===a[n+1]){d=t.slice(n+3),s=a[n],C(s,h.arrays)?e=S(e,s,o,d):!1!==C(s,h.nargs)?e=j(e,s,o,d):N(s,d),r=!0;break}if("-"!==c){if(/[A-Za-z]/.test(a[n])&&/^-?\d+(\.\d*)?(e-?\d+)?$/.test(c)&&!1===C(c,h.bools)){N(a[n],c),r=!0;break}if(a[n+1]&&a[n+1].match(/\W/)){N(a[n],c),r=!0;break}N(a[n],P(a[n]))}else N(a[n],c)}s=t.slice(-1)[0],r||"-"===s||(C(s,h.arrays)?e=S(e,s,o):!1!==C(s,h.nargs)?e=j(e,s,o):(c=o[e+1],void 0===c||/^(-|--)[^-]/.test(c)&&!c.match(g)||C(s,h.bools)||C(s,h.counts)?/^(true|false)$/.test(c)?(N(s,c),e++):N(s,P(s)):(N(s,c),e++)))}else if(t.match(/^-[0-9]$/)&&t.match(g)&&C(t.slice(1),h.bools))s=t.slice(1),N(s,P(s));else{if("--"===t){v=o.slice(e+1);break}if(i["halt-at-non-option"]){v=o.slice(e);break}$(t)}}}function $(e){const t=I("_",e);"string"!=typeof t&&"number"!=typeof t||x._.push(t)}function j(e,t,n,o){let r,s=C(t,h.nargs);if(s="number"!=typeof s||isNaN(s)?1:s,0===s)return R(o)||(b=Error(f("Argument unexpected for: %s",t))),N(t,P(t)),e;let a=R(o)?0:1;if(i["nargs-eats-options"])n.length-(e+1)+a<s&&(b=Error(f("Not enough arguments following: %s",t))),a=s;else{for(r=e+1;r<n.length&&(!n[r].match(/^-[^0-9]/)||n[r].match(g)||z(n[r]));r++)a++;a<s&&(b=Error(f("Not enough arguments following: %s",t)))}let l=Math.min(a,s);for(!R(o)&&l>0&&(N(t,o),l--),r=e+1;r<l+e+1;r++)N(t,n[r]);return e+l}function S(e,t,n,o){let s=[],l=o||n[e+1];const c=C(t,h.nargs);if(C(t,h.bools)&&!/^(true|false)$/.test(l))s.push(!0);else if(R(l)||R(o)&&/^-/.test(l)&&!g.test(l)&&!z(l)){if(void 0!==a[t]){const e=a[t];s=Array.isArray(e)?e:[e]}}else{R(o)||s.push(E(t,o,!0));for(let o=e+1;o<n.length&&!(!i["greedy-arrays"]&&s.length>0||c&&"number"==typeof c&&s.length>=c)&&(l=n[o],!/^-/.test(l)||g.test(l)||z(l));o++)e=o,s.push(E(t,l,r))}return"number"==typeof c&&(c&&s.length<c||isNaN(c)&&0===s.length)&&(b=Error(f("Not enough arguments following: %s",t))),N(t,s),e}function N(e,t,n=r){if(/-/.test(e)&&i["camel-case-expansion"]){const t=e.split(".").map(function(e){return U(e)}).join(".");k(e,t)}const o=E(e,t,n),s=e.split(".");if(L(x,s,o),h.aliases[e]&&h.aliases[e].forEach(function(e){const t=e.split(".");L(x,t,o)}),s.length>1&&i["dot-notation"]&&(h.aliases[s[0]]||[]).forEach(function(t){let n=t.split(".");const r=[].concat(s);r.shift(),n=n.concat(r),(h.aliases[e]||[]).includes(n.join("."))||L(x,n,o)}),C(e,h.normalize)&&!C(e,h.arrays)){[e].concat(h.aliases[e]||[]).forEach(function(e){Object.defineProperty(w,e,{enumerable:!0,get:()=>t,set(e){t="string"==typeof e?W.normalize(e):e}})})}}function k(e,t){h.aliases[e]&&h.aliases[e].length||(h.aliases[e]=[t],u[t]=!0),h.aliases[t]&&h.aliases[t].length||k(t,e)}function E(e,t,n){n&&(t=function(e){return"string"!=typeof e||"'"!==e[0]&&'"'!==e[0]||e[e.length-1]!==e[0]?e:e.substring(1,e.length-1)}(t)),(C(e,h.bools)||C(e,h.counts))&&"string"==typeof t&&(t="true"===t);let o=Array.isArray(t)?t.map(function(t){return I(e,t)}):I(e,t);return C(e,h.counts)&&(R(o)||"boolean"==typeof o)&&(o=q()),C(e,h.normalize)&&C(e,h.arrays)&&(o=Array.isArray(t)?t.map(e=>W.normalize(e)):W.normalize(t)),o}function I(e,t){if(!i["parse-positional-numbers"]&&"_"===e)return t;if(!C(e,h.strings)&&!C(e,h.bools)&&!Array.isArray(t)){(null!=(n=t)&&("number"==typeof n||!!/^0x[0-9a-f]+$/i.test(n)||!/^0[^.]/.test(n)&&/^[-]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(n))&&i["parse-numbers"]&&Number.isSafeInteger(Math.floor(parseFloat(`${t}`)))||!R(t)&&C(e,h.numbers))&&(t=Number(t))}var n;return t}function O(e,t){Object.keys(e).forEach(function(n){const o=e[n],r=t?t+"."+n:n;"object"==typeof o&&null!==o&&!Array.isArray(o)&&i["dot-notation"]?O(o,r):(!M(x,r.split("."))||C(r,h.arrays)&&i["combine-arrays"])&&N(r,o)})}function A(e,t){if(void 0===c)return;const n="string"==typeof c?c:"",o=W.env();Object.keys(o).forEach(function(r){if(""===n||0===r.lastIndexOf(n,0)){const s=r.split("__").map(function(e,t){return 0===t&&(e=e.substring(n.length)),U(e)});(t&&h.configs[s.join(".")]||!t)&&!M(e,s)&&N(s.join("."),o[r])}})}function T(e,t,n,o=!1){Object.keys(n).forEach(function(r){M(e,r.split("."))||(L(e,r.split("."),n[r]),o&&(p[r]=!0),(t[r]||[]).forEach(function(t){M(e,t.split("."))||L(e,t.split("."),n[r])}))})}function M(e,t){let n=e;i["dot-notation"]||(t=[t.join(".")]),t.slice(0,-1).forEach(function(e){n=n[e]||{}});const o=t[t.length-1];return"object"==typeof n&&o in n}function L(e,t,n){let o=e;i["dot-notation"]||(t=[t.join(".")]),t.slice(0,-1).forEach(function(e){e=Z(e),"object"==typeof o&&void 0===o[e]&&(o[e]={}),"object"!=typeof o[e]||Array.isArray(o[e])?(Array.isArray(o[e])?o[e].push({}):o[e]=[o[e],{}],o=o[e][o[e].length-1]):o=o[e]});const r=Z(t[t.length-1]),s=C(t.join("."),h.arrays),a=Array.isArray(n);let l=i["duplicate-arguments-array"];!l&&C(r,h.nargs)&&(l=!0,(!R(o[r])&&1===h.nargs[r]||Array.isArray(o[r])&&o[r].length===h.nargs[r])&&(o[r]=void 0)),n===q()?o[r]=q(o[r]):Array.isArray(o[r])?l&&s&&a?o[r]=i["flatten-duplicate-arrays"]?o[r].concat(n):(Array.isArray(o[r][0])?o[r]:[o[r]]).concat([n]):l||Boolean(s)!==Boolean(a)?o[r]=o[r].concat([n]):o[r]=n:void 0===o[r]&&s?o[r]=a?n:[n]:!l||void 0===o[r]||C(r,h.counts)||C(r,h.bools)?o[r]=n:o[r]=[o[r],n]}function C(e,t){const n=[].concat(h.aliases[e]||[],e),o=Object.keys(t),r=n.find(e=>o.includes(e));return!!r&&t[r]}function _(e){const t=Object.keys(h);return[].concat(t.map(e=>h[e])).some(function(t){return Array.isArray(t)?t.includes(e):t[e]})}function z(e){return i["unknown-options-as-args"]&&function(e){if(e=e.replace(/^-{3,}/,"--"),e.match(g))return!1;if(function(e){if(e.match(g)||!e.match(/^-[^-]+/))return!1;let t,n=!0;const o=e.slice(1).split("");for(let r=0;r<o.length;r++){if(t=e.slice(r+2),!_(o[r])){n=!1;break}if(o[r+1]&&"="===o[r+1]||"-"===t||/[A-Za-z]/.test(o[r])&&/^-?\d+(\.\d*)?(e-?\d+)?$/.test(t)||o[r+1]&&o[r+1].match(/\W/))break}return n}(e))return!1;return!function(e,...t){return[].concat(...t).some(function(t){const n=e.match(t);return n&&_(n[1])})}(e,/^-+([^=]+?)=[\s\S]*$/,y,/^-+([^=]+?)$/,/^-+([^=]+?)-$/,/^-+([^=]+?\d+)$/,/^-+([^=]+?)\W+.*$/)}(e)}function P(e){return C(e,h.bools)||C(e,h.counts)||!(`${e}`in a)?(t=function(e){let t=J.BOOLEAN;return C(e,h.strings)?t=J.STRING:C(e,h.numbers)?t=J.NUMBER:C(e,h.bools)?t=J.BOOLEAN:C(e,h.arrays)&&(t=J.ARRAY),t}(e),{[J.BOOLEAN]:!0,[J.STRING]:"",[J.NUMBER]:void 0,[J.ARRAY]:[]}[t]):a[e];var t}function R(e){return void 0===e}return A(x,!0),A(x,!1),function(e){const t=Object.create(null);T(t,h.aliases,a),Object.keys(h.configs).forEach(function(n){const o=e[n]||t[n];if(o)try{let e=null;const t=W.resolve(W.cwd(),o),r=h.configs[n];if("function"==typeof r){try{e=r(t)}catch(t){e=t}if(e instanceof Error)return void(b=e)}else e=W.require(t);O(e)}catch(t){"PermissionDenied"===t.name?b=t:e[n]&&(b=Error(f("Invalid JSON config file: %s",o)))}})}(x),void 0!==l&&l.forEach(function(e){O(e)}),T(x,h.aliases,a,!0),function(e){let t;const n=new Set;Object.keys(e).forEach(function(o){if(!n.has(o)&&(t=C(o,h.coercions),"function"==typeof t))try{const r=I(o,t(e[o]));[].concat(h.aliases[o]||[],o).forEach(t=>{n.add(t),e[t]=r})}catch(e){b=e}})}(x),i["set-placeholder-key"]&&function(e){h.keys.forEach(t=>{~t.indexOf(".")||void 0===e[t]&&(e[t]=void 0)})}(x),Object.keys(h.counts).forEach(function(e){M(x,e.split("."))||N(e,0)}),d&&v.length&&(x[m]=[]),v.forEach(function(e){x[m].push(e)}),i["camel-case-expansion"]&&i["strip-dashed"]&&Object.keys(x).filter(e=>"--"!==e&&e.includes("-")).forEach(e=>{delete x[e]}),i["strip-aliased"]&&[].concat(...Object.keys(s).map(e=>s[e])).forEach(e=>{i["camel-case-expansion"]&&e.includes("-")&&delete x[e.split(".").map(e=>U(e)).join(".")],delete x[e]}),{aliases:Object.assign({},h.aliases),argv:Object.assign(w,x),configuration:i,defaulted:Object.assign({},p),error:b,newAliases:Object.assign({},u)}}}({cwd:process.cwd,env:()=>Q,format:t,normalize:r,resolve:o,require:e=>{if("undefined"!=typeof require)return require(e);if(e.match(/\.json$/))return JSON.parse(i(e,"utf8"));throw Error("only .json config files are supported in ESM")}});var X={fs:{readFileSync:i,writeFile:a},format:t,resolve:o,exists:e=>{try{return l(e).isFile()}catch(e){return!1}}};let ee;class te{constructor(e){e=e||{},this.directory=e.directory||"./locales",this.updateFiles="boolean"!=typeof e.updateFiles||e.updateFiles,this.locale=e.locale||"en",this.fallbackToLanguage="boolean"!=typeof e.fallbackToLanguage||e.fallbackToLanguage,this.cache=Object.create(null),this.writeQueue=[]}__(...e){if("string"!=typeof arguments[0])return this._taggedLiteral(arguments[0],...arguments);const t=e.shift();let n=function(){};return"function"==typeof e[e.length-1]&&(n=e.pop()),n=n||function(){},this.cache[this.locale]||this._readLocaleFile(),!this.cache[this.locale][t]&&this.updateFiles?(this.cache[this.locale][t]=t,this._enqueueWrite({directory:this.directory,locale:this.locale,cb:n})):n(),ee.format.apply(ee.format,[this.cache[this.locale][t]||t].concat(e))}__n(){const e=Array.prototype.slice.call(arguments),t=e.shift(),n=e.shift(),o=e.shift();let r=function(){};"function"==typeof e[e.length-1]&&(r=e.pop()),this.cache[this.locale]||this._readLocaleFile();let s=1===o?t:n;if(this.cache[this.locale][t]){s=this.cache[this.locale][t][1===o?"one":"other"]}!this.cache[this.locale][t]&&this.updateFiles?(this.cache[this.locale][t]={one:t,other:n},this._enqueueWrite({directory:this.directory,locale:this.locale,cb:r})):r();const i=[s];return~s.indexOf("%d")&&i.push(o),ee.format.apply(ee.format,i.concat(e))}setLocale(e){this.locale=e}getLocale(){return this.locale}updateLocale(e){this.cache[this.locale]||this._readLocaleFile();for(const t in e)Object.prototype.hasOwnProperty.call(e,t)&&(this.cache[this.locale][t]=e[t])}_taggedLiteral(e,...t){let n="";return e.forEach(function(e,o){const r=t[o+1];n+=e,void 0!==r&&(n+="%s")}),this.__.apply(this,[n].concat([].slice.call(t,1)))}_enqueueWrite(e){this.writeQueue.push(e),1===this.writeQueue.length&&this._processWriteQueue()}_processWriteQueue(){const e=this,t=this.writeQueue[0],n=t.directory,o=t.locale,r=t.cb,s=this._resolveLocaleFile(n,o),i=JSON.stringify(this.cache[o],null,2);ee.fs.writeFile(s,i,"utf-8",function(t){e.writeQueue.shift(),e.writeQueue.length>0&&e._processWriteQueue(),r(t)})}_readLocaleFile(){let e={};const t=this._resolveLocaleFile(this.directory,this.locale);try{ee.fs.readFileSync&&(e=JSON.parse(ee.fs.readFileSync(t,"utf-8")))}catch(n){if(n instanceof SyntaxError&&(n.message="syntax error in "+t),"ENOENT"!==n.code)throw n;e={}}this.cache[this.locale]=e}_resolveLocaleFile(e,t){let n=ee.resolve(e,"./",t+".json");if(this.fallbackToLanguage&&!this._fileExistsSync(n)&&~t.lastIndexOf("_")){const o=ee.resolve(e,"./",t.split("_")[0]+".json");this._fileExistsSync(o)&&(n=o)}return n}_fileExistsSync(e){return ee.exists(e)}}let ne;try{ne=c(import.meta.url)}catch(e){ne=process.cwd()}ne.substring(0,ne.lastIndexOf("node_modules"))||process.cwd(),process.cwd,process.exit,process.nextTick,void 0!==process.stdout.columns&&process.stdout.columns,function(e,t){ee=t;const n=new te(e);n.__.bind(n),n.__n.bind(n),n.setLocale.bind(n),n.getLocale.bind(n),n.updateLocale.bind(n),n.locale}({directory:o(ne,"../../../locales"),updateFiles:!1},X);const oe=[{name:"capabilities",category:"discovery",summary:"Self-describing manifest of every command an agent can call",examples:["mfn capabilities --json"]},{name:"mcp",category:"discovery",summary:"Serve every command over the Model Context Protocol (stdio) for MCP clients",examples:["mfn mcp","mfn mcp --json"]},{name:"epoch",category:"time",summary:"Convert between epoch timestamps and dates (auto-detects unit)",examples:["mfn epoch 1622547800 --json","mfn epoch --from 2021-06-01T11:43:20Z --json"]},{name:"date",category:"time",summary:"Convert/format a date across timezones (defaults to now)",examples:["mfn date --json","mfn date 2024-07-04T15:30:30Z --tz America/New_York --json"]},{name:"decode",category:"crypto",summary:"Decode a JWT token (header + payload; signature not verified)",examples:["mfn decode -t <jwt> --json"]},{name:"kill",category:"net",summary:"Kill the process(es) listening on specific ports",examples:["mfn kill -p 3000 8080 -y --json"]},{name:"sc",category:"code",summary:"Find files/folders under the current directory (fuzzy match)",examples:["mfn sc service --json"]},{name:"cts",category:"code",summary:"Print (or export) a tree of the current working directory",examples:["mfn cts --json","mfn cts -t png"]},{name:"update",category:"discovery",summary:"Update the CLI or a specified package to the latest version",examples:["mfn update --json","mfn update <package> --json"]},{name:"id",category:"crypto",summary:"Generate identifiers (UUID v4/v7 or URL-safe nano id)",examples:["mfn id --json","mfn id -t uuid7 -n 3 --json"]},{name:"hash",category:"crypto",summary:"Hash a string, file, or stdin (md5/sha1/sha256/sha512)",examples:["mfn hash hello --json","mfn hash -a md5 -f ./file.txt --json"]},{name:"encode",category:"crypto",summary:"Encode/decode text (base64, base64url, hex, url)",examples:["mfn encode hello --json","mfn encode aGVsbG8= -d --json"]},{name:"random",category:"crypto",summary:"Generate secure random bytes or a password",examples:["mfn random --json","mfn random -p -l 32 --json"]},{name:"port",category:"net",summary:"Find a free port, or check whether a specific port is available",examples:["mfn port --json","mfn port -c 3000 --json"]},{name:"json",category:"data",summary:"Extract one value/keys/length from JSON without reading the whole document",examples:["mfn json scripts.build -f package.json --json","cat d.json | mfn json users[0].name --json"]},{name:"schema",category:"data",summary:"Infer the shape of a JSON document (paths + types) without dumping the data",examples:["mfn schema -f response.json --json","curl -s api/u | mfn schema --json"]},{name:"count",category:"text",summary:"Lines/words/chars/bytes + LLM token estimate of a file, stdin, or text",examples:["mfn count -f big.log --json","git diff | mfn count --json"]},{name:"lines",category:"text",summary:"Read an exact line range of a file (1-based) instead of the whole file",examples:["mfn lines src/app.ts -s 120 -n 30 --json"]},{name:"diff",category:"text",summary:"Line diff of two files as structured hunks (counts first, content optional)",examples:["mfn diff old.json new.json --json","mfn diff a.txt b.txt -s --json"]},{name:"freq",category:"text",summary:"Most frequent lines of a file/stdin (log analysis in one call)",examples:["mfn freq error.log -t 5 --json"]},{name:"case",category:"text",summary:"Convert strings between naming styles (camel, snake, kebab, pascal, …)",examples:["mfn case getUserName -t snake --json","mfn case my-component --json"]},{name:"escape",category:"text",summary:"Escape text exactly for shell, JSON, regex, HTML, or URL contexts",examples:['mfn escape "it\'s done" --json',"mfn escape 1.2.3 -a regex --json"]},{name:"calc",category:"data",summary:"Exact arithmetic — integer math in BigInt, no float drift, no guessing",examples:['mfn calc "2^53 + 1" --json','mfn calc "(3 + 4) * 5" --json']},{name:"semver",category:"data",summary:"Validate, compare, sort, or bump semantic versions per semver.org",examples:["mfn semver 1.10.0 1.9.2 --json","mfn semver 1.2.3 -b minor --json"]},{name:"cron",category:"time",summary:"Validate a cron expression, explain it, and compute the next run times",examples:['mfn cron "*/15 9-17 * * 1-5" --json','mfn cron "@daily" -n 1 --json']},{name:"regex",category:"text",summary:"Test a regular expression against text — verify instead of guessing",examples:['mfn regex "TODO[:!]?" -f src/app.ts --json']},{name:"url",category:"data",summary:"Parse a URL into components with decoded query parameters",examples:['mfn url "https://api.x.com/v2/users?id=42" --json']},{name:"have",category:"system",summary:"Check which tools are installed (path + version) in one call",examples:["mfn have node git docker --json"]},{name:"sys",category:"system",summary:"One-shot system facts: OS, node, CPU, memory, shell, timezone, paths",examples:["mfn sys --json"]},{name:"repo",category:"code",summary:"One-shot git summary: branch, dirty counts, ahead/behind, last commits",examples:["mfn repo --json","mfn repo -n 10 --json"]},{name:"env",category:"system",summary:"Inspect environment variables with automatic secret redaction",examples:["mfn env NODE_ENV PATH --json","mfn env -p NEXT_PUBLIC_ --json"]},{name:"size",category:"code",summary:"Total size + largest files/dirs under a directory in one call",examples:["mfn size --json","mfn size ./src -t 5 --json"]},{name:"ext",category:"code",summary:"File counts and bytes per extension — project composition at a glance",examples:["mfn ext --json"]},{name:"ip",category:"net",summary:"Local network interfaces and addresses (no ifconfig parsing)",examples:["mfn ip --json"]},{name:"outline",category:"code",summary:"Outline a source file: functions/classes/exports with line numbers",examples:["mfn outline src/app.ts --json","mfn outline README.md --json"]},{name:"imports",category:"code",summary:"List a file’s imports, or find every file that imports a module",examples:["mfn imports src/app.ts --json","mfn imports --who utility --json"]},{name:"replace",category:"code",summary:"Literal find/replace across files — dry-run by default, JSON change report",examples:['mfn replace "oldName" "newName" -g "src/**/*.ts" --json','mfn replace "v1" "v2" -g "**/*.md" --write --json']},{name:"recent",category:"code",summary:"Most recently modified files under a directory, with age",examples:["mfn recent --json","mfn recent ./src -t 5 --json"]},{name:"pkg",category:"code",summary:"Declared vs installed dependency versions — drift in one call",examples:["mfn pkg --json","mfn pkg typescript --json"]},{name:"dotenv",category:"system",summary:"Check .env against .env.example — missing/extra keys, values never shown",examples:["mfn dotenv --json","mfn dotenv -f .env.local -e .env.example --json"]},{name:"wait",category:"net",summary:"Block until a port, file, or URL is ready (with timeout) — no sleep loops",examples:["mfn wait -p 3000 -t 30 --json","mfn wait -u http://localhost:3000/health --json"]},{name:"ports",category:"net",summary:"List ALL listening TCP ports with their owning processes",examples:["mfn ports --json"]},{name:"http",category:"net",summary:"Probe a URL: status, headers, timing, capped body preview",examples:["mfn http https://api.github.com --json","mfn http localhost:3000/health --json"]},{name:"base",category:"data",summary:"Convert numbers between bases (hex/dec/bin/oct) exactly, BigInt-safe",examples:["mfn base 0xff --json","mfn base 255 --json"]},{name:"clip",category:"system",summary:"Read or write the system clipboard (pbcopy/xclip/clip.exe handled for you)",examples:["mfn clip --json","git diff | mfn clip --json"]},{name:"notify",category:"system",summary:"Desktop notification — tell the user a long task finished, hands-free",examples:['mfn notify "build finished" --json']},{name:"open",category:"system",summary:"Open a file or URL in the default app/browser (target validated first)",examples:["mfn open coverage/index.html --json"]},{name:"procs",category:"system",summary:"Search running processes by name: pid/cpu/mem in one call",examples:["mfn procs node --json","mfn procs -t 10 --json"]},{name:"disk",category:"system",summary:"Disk usage per mount (total/free/used%) without df parsing",examples:["mfn disk --json"]},{name:"trash",category:"system",summary:"Move files/dirs to the OS trash — reversible delete, never rm -rf",examples:["mfn trash old-build.log --json","mfn trash dist coverage --json"]},{name:"dns",category:"net",summary:"Resolve a hostname: A/AAAA/CNAME/MX/TXT/NS in one call",examples:["mfn dns github.com --json","mfn dns example.com -t mx --json"]}],re=[...new Set(oe.map(e=>e.category))];var se="@master4n/master-cli",ie="3.0.6";const ae=["add --json to any command for clean, machine-readable output","piping a command (no TTY) auto-emits JSON — great for agents & scripts","every command returns a stable exit code: 0 = ok, non-zero = failure","mfn <command> --help shows its flags and copy-paste examples","mfn capabilities --json lists every command an agent can call","mfn kill -p 3000 8080 -y frees stuck ports in one shot"],le=e=>d.hex(e)("─".repeat(62)),ce=()=>(new Date).toISOString();function de(){return{info:e=>console.error(`${d.blue("INFO")} [${d.magenta(ce())}] ${d.white(e)}`),warn:e=>console.error(`${d.yellow("WARN")} [${d.magenta(ce())}] ${d.white(e)}`),error:e=>console.error(`${d.red("ERROR")} [${d.magenta(ce())}] ${d.white(e)}`),debug:e=>console.error(`${d.cyan("DEBUG")} [${d.magenta(ce())}] ${d.white(e)}`)}}function me(){const e=m.homedir();return n.join(e,".mfn","cache")}const ue=e=>d.green(e);async function pe(e,t){await f.writeJson(t,e,{spaces:2})}!function(){const e=m.homedir(),t=n.join(e,".mfn","cache");if(!s.existsSync(t))try{s.mkdirSync(t,{recursive:!0,mode:448})}catch{}}(),await(async()=>{if(!(Boolean(process.stdout.isTTY)&&!process.argv.includes("--json")))return;const[{default:e},{default:t}]=await Promise.all([import("figlet"),import("boxen")]),n=await new Promise((t,n)=>{e("M4N-CLI",(e,o)=>e?n(e):t(o??""))}),o=t(d.hex("#27A244").bold(n),{padding:1,margin:{top:1,bottom:0,left:1,right:1},borderStyle:"round",borderColor:"#C1C110",dimBorder:!0}),r=function(){try{return(m.userInfo().username||"").replace(/[^\p{L}\p{N} ._-]/gu,"").slice(0,32)}catch{return""}}(),s=d.dim(" • "),i=[d.hex("#44bcd8").bold(`mfn v${ie}`),d.gray(`node ${process.version}`),d.gray(`${process.platform}/${process.arch}`),d.green.bold("AI-friendly")].join(s);let a="";try{const{getEpochNow:e}=await import("@master4n/temporal-transformer"),t=e();a=`${t.iso.replace("T"," ").slice(0,19)} ${d.dim(`(${t.timezone})`)}`}catch{}const l=new Map;for(const e of oe)l.set(e.category,(l.get(e.category)??0)+1);const c=[...l.entries()].map(([e,t])=>`${d.cyan(e)}${d.dim(`(${t})`)}`).join(d.dim(" · "))+d.dim(" → mfn capabilities"),u=ae[Math.floor(Math.random()*ae.length)],p=(e="")=>console.error(e);p(le("#C1C110")),p(o),p(" "+(r?d.magenta(`👋 Welcome, ${d.bold(r)}`):d.magenta("👋 Welcome"))+s+i),a&&p(" "+d.gray("🕒 ")+d.white(a)),p(""),p(" "+d.yellow.bold("🧰 tools ")+c),p(" "+d.yellow.bold("💡 tip ")+d.white(u)),p(" "+d.yellow.bold("🤖 help ")+d.white("mfn <command> --help")),p(le("#C1C110"))})();const fe=e(process.argv.slice(B()+1));const he=d.hex("#44bcd8").bold("mfn");var ge=fe.scriptName(he);const ye=()=>Boolean(process.stdout.isTTY),be=e=>e.option("json",{type:"boolean",default:!1,describe:"Emit a single machine-readable JSON object on stdout"}),ve=e=>Boolean(e?.json)||!ye(),xe=e=>{process.stdout.write(JSON.stringify(e)+"\n")};function we(e,t,n){ve(e)?xe({ok:!0,...t}):n()}function $e(e,t,n,o=1){ve(e)?xe({ok:!1,error:t,message:n}):console.error(n),process.exit(o)}const je=e=>ye()&&!e?.json;async function Se(){if(process.stdin.isTTY)return"";const e=[];for await(const t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf8")}function Ne(e,t,n=2){process.argv.includes("--json")||!ye()?process.stdout.write(JSON.stringify({ok:!1,error:e,message:t})+"\n"):console.error(t),process.exit(n)}const ke=de(),Ee=n.join(me(),"cts_ignore.json"),Ie=["node_modules",".git",".nx"];function Oe(e,t,o=""){let r,s="";try{r=f.readdirSync(e).filter(e=>!t.has(e)).sort()}catch{return`${o}└── [unreadable]\n`}return r.forEach((i,a)=>{const l=n.join(e,i),c=a===r.length-1;let d;try{d=f.statSync(l).isDirectory()}catch{d=!1}s+=`${o}${c?"└── ":"├── "}${i}\n`,d&&(s+=Oe(l,t,`${o}${c?" ":"│ "}`))}),s}const Ae={command:"cts",describe:"Print (or export) a tree of the current working directory",builder:e=>be(e).option("type",{alias:"t",describe:"Output format: text (stdout, default) or an image file",type:"string",choices:["text","svg","png","jpeg"],default:"text"}).option("ignore",{alias:"i",describe:"Folder names to ignore",type:"array"}).option("length",{alias:"l",describe:"Image height",type:"number",default:250}).option("breadth",{alias:"b",describe:"Image width",type:"number",default:200}).example("mfn cts","print the tree as text").example("mfn cts --json","tree as JSON").example("mfn cts -t png","export the tree to <dir>.png"),handler:async e=>{let t=e.ignore??[];t.length>0?await pe({ignores:t},Ee).catch(()=>{}):t=(await async function(){try{return await f.readJson(Ee)}catch(e){if("ENOENT"===e.code)return{ignores:[]};throw e}}()).ignores??[];const o=new Set([...Ie,...t]),r=process.cwd(),s=n.basename(r);let i;try{i=s+"\n"+Oe(r,o)}catch(t){return $e(e,"TreeError",`Failed to build tree for ${r}: ${t instanceof Error?t.message:String(t)}`)}const a=String(e.type);if("text"===a)return we(e,{root:s,path:r,format:"text",tree:i},()=>{process.stdout.write(i.endsWith("\n")?i:i+"\n")});if(!function(...e){for(const t of e)if(isNaN(t)||t<1||t>1e3)return!1;return!0}(e.length,e.breadth))return $e(e,"InvalidDimensions","Length & breadth must be numbers in 1..1000.",2);const l=`${s}.${a}`;try{const t=function(e,t,n){return`<svg xmlns="http://www.w3.org/2000/svg" width="${n}" height="${t}"><rect width="100%" height="100%" fill="white"/><g fill="black" font-family="monospace" font-size="12">${e.split("\n").map((e,t)=>`<text style="white-space: pre;" x="0" y="${20+20*t}">${e.replace(/&/g,"&").replace(/</g,"<")}</text>`).join("")}</g></svg>`}(i,e.length,e.breadth);if("svg"===a)f.outputFileSync(l,t);else{const{default:e}=await import("sharp");await e(Buffer.from(t))["png"===a?"png":"jpeg"]().toFile(l)}}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,"ExportFailed",`Failed to write ${l}: ${n}`)}we(e,{root:s,path:r,format:a,file:l},()=>ke.info(`Tree for ${s} written to ${l}`))}},Te=de(),Me=n.join(me(),"sc_ignore.json"),Le=["node_modules",".git","dist","build",".nx","coverage"];function Ce(e,t,o){const r=[],s=new Set([...Le,...t]),i=(t,a)=>{if(a>o)return;let l;try{l=f.readdirSync(t,{withFileTypes:!0})}catch{return}for(const o of l){if(s.has(o.name))continue;const l=n.join(t,o.name),c=n.relative(e,l);r.push(o.isDirectory()?c+n.sep:c),o.isDirectory()&&i(l,a+1)}};return i(e,0),r}const _e={command:"sc [pattern]",describe:"Find files/folders under the current directory (fuzzy match)",builder:e=>be(e).positional("pattern",{describe:"Fuzzy pattern to match against paths (omit to list all)",type:"string"}).option("ignore",{alias:"i",describe:"Additional directory names to ignore",type:"array"}).option("depth",{type:"number",default:6,describe:"Max recursion depth"}).option("limit",{type:"number",default:500,describe:"Max results returned"}).example("mfn sc service --json",'find paths matching "service"'),handler:async e=>{const t=process.cwd(),o=Number(e.depth),r=Number(e.limit);if(!Number.isInteger(o)||o<0)return $e(e,"InvalidDepth","--depth must be a non-negative integer.",2);if(!Number.isInteger(r)||r<1)return $e(e,"InvalidLimit","--limit must be a positive integer.",2);let s=e.ignore??[];if(s.length>0?await pe({ignores:s},Me).catch(()=>{}):s=(await async function(){try{return await f.readJson(Me)}catch(e){if("ENOENT"===e.code)return{ignores:[]};throw e}}()).ignores??[],void 0===e.pattern&&je(e))return async function(e,t,o,r,s){const{default:i}=await import("inquirer"),a=Ce(t,o,r),{pattern:l}=await i.prompt([{type:"input",name:"pattern",message:ue("Filter (fuzzy, blank = all):")}]),c=String(l??"").trim(),d=(c?g.filter(c,a).map(e=>e.original):a).slice(0,s);if(0===d.length)return we(e,{pattern:c||null,root:t,count:0,matches:[]},()=>Te.warn("No matches."));const{selected:m}=await i.prompt([{type:"list",name:"selected",message:ue("Select a path:"),choices:d,pageSize:15,loop:!1}]),u=f.statSync(n.join(t,m));we(e,{path:m,type:u.isDirectory()?"directory":"file"},()=>{Te.info(`${u.isDirectory()?"Directory":"File"}: ${m}`),u.isDirectory()&&Te.info(`cd ${m}`)})}(e,t,s,o,r);const i=Ce(t,s,o),a=e.pattern?g.filter(String(e.pattern),i).map(e=>e.original):i,l=a.slice(0,r);we(e,{pattern:e.pattern??null,root:t,count:l.length,truncated:a.length>l.length,matches:l},()=>{Te.info(`${l.length} match(es) under ${t}`);for(const e of l)console.log(e)})}},ze=de();function Pe(e){const t=Buffer.from(e,"base64url").toString("utf-8");return JSON.parse(t)}const Re={command:"decode",describe:"Decode a JWT token (header + payload; signature not verified)",builder:e=>be(e).option("token",{alias:"t",describe:'JWT token to decode (a leading "Bearer " is stripped)',type:"string",demandOption:!0}).example("mfn decode -t <jwt> --json","decode a JWT"),handler:e=>{const t=String(e.token).replace(/^Bearer\s+/i,"").trim().split(".");if(3!==t.length)return $e(e,"InvalidJWT","Invalid JWT structure: expected three dot-separated segments.",2);let n,o;try{n=Pe(t[0]),o=Pe(t[1])}catch(t){return $e(e,"DecodeError",`Could not decode JWT: ${t instanceof Error?t.message:String(t)}`,2)}const r=o?.exp;let s;if("number"==typeof r&&Number.isFinite(r)){const e=Math.round(r-Date.now()/1e3);s={exp:r,expired:e<=0,expiresInSeconds:e}}we(e,{header:n,payload:o,...s?{expiry:s}:{}},()=>{ze.info("Decoded JWT (signature NOT verified)"),console.log(d.cyanBright.bold("header:")),console.log(d.greenBright(JSON.stringify(n,null,2))),console.log(d.cyanBright.bold("payload:")),console.log(d.greenBright(JSON.stringify(o,null,2))),s&&console.log(d.cyanBright.bold("expiry: ")+(s.expired?d.red(`expired ${-s.expiresInSeconds}s ago`):d.green(`valid for ${s.expiresInSeconds}s`)))})}},Fe=de(),De="yyyy-MM-dd HH:mm:ss",Be=()=>Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC";function Ue(e){const t=e.format||De,n=e.tz||Be();let o,r,s;try{o=void 0!==e.from?y(String(e.from),e.inFormat,e.inTz).epochInMilliseconds:b().milliseconds}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,t instanceof Error?t.name:"ParseError",n,2)}try{r=v(o,"UTC",t),s=v(o,n,t)}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,t instanceof Error?t.name:"TimezoneError",n,2)}we(e,{epochInSeconds:Math.floor(o/1e3),epochInMilliseconds:o,iso:new Date(o).toISOString(),utc:r,zoned:s,timezone:n,format:t},()=>{Fe.info("Date conversion"),console.table([{UTC:r,[n]:s,Epoch_ms:o}])})}const Je={command:"date [from]",describe:"Convert/format a date across timezones (defaults to now)",builder:e=>be(e).positional("from",{describe:"Date string to convert (ISO 8601 unless --in-format given). Omit for now.",type:"string"}).option("tz",{type:"string",describe:"Target output timezone (IANA; default: local)"}).option("format",{type:"string",describe:`Output format (default: ${De})`}).option("in-format",{type:"string",describe:"Luxon parse format for the input"}).option("in-tz",{type:"string",describe:"Timezone used to interpret the input"}).example("mfn date --json","now, in UTC + local").example("mfn date 2024-07-04T15:30:30Z --tz America/New_York --json","convert to a timezone"),handler:async e=>{const t={from:e.from,inFormat:e["in-format"],inTz:e["in-tz"],tz:e.tz,format:e.format,json:e.json};if(void 0===e.from&&void 0===e.tz&&void 0===e.format&&je(e))return async function(e){const{default:t}=await import("inquirer"),n=await t.prompt([{type:"input",name:"from",message:ue("Date string (blank = now, ISO 8601):")},{type:"input",name:"tz",message:ue(`Target timezone (blank = ${Be()}):`)},{type:"input",name:"format",message:ue(`Output format (blank = ${De}):`)}]);Ue({...e,from:n.from?.trim()||void 0,tz:n.tz?.trim()||void 0,format:n.format?.trim()||void 0})}(t);Ue(t)}};const We=de();function qe(e,t){let n;try{n=x(t)}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,t instanceof Error?t.name:"InvalidEpoch",n,2)}const o={seconds:1e3,milliseconds:1,microseconds:.001,nanoseconds:1e-6}[n.epochUnit]??1;we(e,{epoch:n.epoch,unit:n.epochUnit,iso:new Date(Math.round(n.epoch*o)).toISOString(),utc:n.dateTimeInGMT,local:n.dateTime,timezone:n.timezone,relative:n.relative},()=>{We.info("Epoch → date"),console.table([{Epoch:`${n.epoch} (${n.epochUnit})`,Local:n.dateTime,GMT:n.dateTimeInGMT,Relative:n.relative}])})}function Ze(e,t,n,o){let r,s;try{r=y(t,n,o)}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,t instanceof Error?t.name:"ParseError",n,2)}try{s=x(r.epochInSeconds).relative}catch{s=void 0}we(e,{epochInSeconds:r.epochInSeconds,epochInMilliseconds:r.epochInMilliseconds,iso:new Date(r.epochInMilliseconds).toISOString(),utc:r.dateTimeInGMT,local:r.dateTime,timezone:r.timezone,relative:s},()=>{We.info("Date → epoch"),console.table([{Seconds:r.epochInSeconds,Milliseconds:r.epochInMilliseconds,Local:r.dateTime,GMT:r.dateTimeInGMT,Timezone:r.timezone}])})}const Ge={command:"epoch [value]",describe:"Convert between epoch timestamps and dates (auto-detects unit)",builder:e=>be(e).positional("value",{describe:"Epoch value to convert to a date (s / ms / µs / ns auto-detected)",type:"string"}).option("from",{type:"string",describe:"A date string to convert TO epoch (ISO 8601 unless --format given)"}).option("format",{type:"string",describe:'Luxon parse format for --from (e.g. "dd/MM/yyyy")'}).option("tz",{type:"string",describe:"IANA timezone used to interpret --from (default: local)"}).example("mfn epoch 1622547800 --json","epoch → date").example("mfn epoch --from 2021-06-01T11:43:20Z --json","date → epoch"),handler:async e=>{if(void 0!==e.from)return Ze(e,String(e.from),e.format,e.tz);if(void 0!==e.value&&null!==e.value){const t=String(e.value).trim();return""===t?$e(e,"MissingInput","Epoch value is empty. Provide a numeric epoch.",2):qe(e,Number(t))}if(je(e))return async function(e,t,n){const{default:o}=await import("inquirer"),{operation:r}=await o.prompt([{type:"rawlist",name:"operation",message:ue("What do you want to do?"),choices:[{name:"Convert epoch → human-readable date",value:"epochToDate"},{name:"Convert date string → epoch",value:"dateToEpoch"}]}]);if("epochToDate"===r){const{value:n}=await o.prompt([{type:"input",name:"value",message:ue("Enter epoch value:"),validate:e=>e.trim()&&!isNaN(Number(e))||"Enter a number"}]);t(e,Number(n))}else{const{input:t}=await o.prompt([{type:"input",name:"input",message:ue("Enter a date string (ISO 8601):"),validate:e=>Boolean(e.trim())||"Enter a date string"}]);n(e,t,void 0,e.tz)}}(e,qe,Ze);$e(e,"MissingInput","Provide an epoch <value>, or --from <dateString>. See `mfn epoch --help`.",2)}},He=de(),Ve=w(h),Ye=n.join(me(),"ports.json"),Ke="win32"===$();async function Qe(e){try{if(Ke){const{stdout:t}=await Ve("netstat",["-ano"]),n=t.split("\n").find(t=>t.includes(`:${e}`)&&/LISTENING/i.test(t)),o=n?n.trim().split(/\s+/).pop():null;return o?{port:e,pid:o}:null}const{stdout:t}=await Ve("lsof",["-i",`:${e}`]),n=t.split("\n").find(e=>/LISTEN/.test(e)),o=n?n.trim().split(/\s+/)[1]:null;return o?{port:e,pid:o}:null}catch{return null}}async function Xe(e){if(!/^\d+$/.test(e))throw new Error(`Refusing to kill non-numeric PID "${e}"`);if(Number(e)<=1)throw new Error(`Refusing to kill system PID ${e}`);Ke?await Ve("taskkill",["/PID",e,"/F"]):await Ve("kill",["-9",e])}const et={command:"kill",describe:"Kill the process(es) listening on specific ports",builder:e=>be(e).option("ports",{alias:"p",describe:"Port number(s) to free",type:"array"}).option("yes",{alias:"y",type:"boolean",default:!1,describe:"Kill all matching processes without the interactive prompt"}).example("mfn kill -p 3000 8080 -y --json","free ports 3000 and 8080"),handler:async e=>{const t=e.ports??[];let n=[];for(const o of t){const t=Number(o);if(!Number.isInteger(t)||t<1||t>65535)return $e(e,"InvalidPort",`Invalid port number: ${o} (expected an integer in 1..65535).`,2);n.push(t)}if(0===n.length){const t=je(e)?await async function(){try{return await f.readJson(Ye)}catch(e){if("ENOENT"===e.code)return{ports:[]};throw e}}():{ports:[]};if(!t.ports?.length)return $e(e,"NoPorts","No ports provided. Use -p <port...>. See `mfn kill --help`.",2);n=t.ports,He.info(`Using cached ports [${n.join(", ")}]`)}await pe({ports:n},Ye).catch(()=>{});const o=(await Promise.all(n.map(Qe))).filter(e=>null!==e),r=n.filter(e=>!o.some(t=>t.port===e));if(0===o.length)return we(e,{killed:[],failed:[],notFound:r},()=>He.info(`No processes listening on [${n.join(", ")}]`));let s=o;if(je(e)&&!e.yes){const{default:e}=await import("inquirer"),{pids:t}=await e.prompt([{type:"checkbox",name:"pids",message:ue("Select the processes to kill:"),choices:o.map(e=>({name:`Port ${e.port} → PID ${e.pid}`,value:e.pid}))}]);s=o.filter(e=>t.includes(e.pid))}const i=[],a=[];for(const e of s)try{await Xe(e.pid),i.push(e)}catch(t){a.push({...e,error:t instanceof Error?t.message:String(t)})}we(e,{killed:i,failed:a,notFound:r},()=>{for(const e of i)He.info(`Killed PID ${e.pid} on port ${e.port}`);for(const e of a)He.error(`Failed to kill PID ${e.pid} (port ${e.port}): ${e.error}`);r.length&&He.warn(`No process on [${r.join(", ")}]`)}),a.length>0&&process.exit(1)}},tt=de(),nt=w(h);const ot={command:"update [package]",describe:"Update the CLI or a specified package to the latest version",builder:e=>be(e).positional("package",{describe:"npm package to update globally (default: this CLI)",type:"string",default:"@master4n/master-cli"}).example("mfn update","update master-cli itself to the latest version").example("mfn update typescript --json","update a specific global package"),handler:async e=>{const t=String(e.package??"@master4n/master-cli"),n=je(e)?(await import("ora")).default():null,o=Date.now();n?.start(d.green(`updating/installing ${t}`));try{await async function(e){await nt("npm",["install","-g",e])}(t);const r=await async function(e){try{const{stdout:t}=await nt("npm",["view",e,"version"]);return t.trim()||null}catch{return null}}(t),s=Date.now()-o;n?.succeed(`${d.green(`updated ${t}`)} ${d.dim(`(${(s/1e3).toFixed(3)}s)`)}`),we(e,{package:t,version:r,durationMs:s},()=>{tt.info(`${t} updated/installed${r?` -> ${d.green(r)}`:""}`)})}catch(o){n?.fail(d.red(`failed updating ${t}`));const r=o instanceof Error?o.message:String(o);$e(e,"UpdateFailed",`Failed to update "${t}": ${r}`)}}},rt={command:"capabilities",describe:"List every command an agent can call (self-describing manifest)",builder:e=>be(e).example("mfn capabilities --json","machine-readable manifest"),handler:e=>{we(e,{name:se,version:ie,bin:"mfn",conventions:{json:"pass --json, or pipe (non-TTY auto-emits) — one {ok,...} object on stdout",exitCodes:{ok:0,error:1,usage:2},logs:"banners and logs go to stderr; stdout carries data only"},docs:{readme:"https://github.com/Master4Novice/master-cli#readme",llmsTxt:"https://raw.githubusercontent.com/Master4Novice/master-cli/master/llms.txt",agentNote:"llms.txt ships inside this npm package too — full agent contract and per-command flags"},categories:re,commands:oe.map(e=>({name:e.name,category:e.category,summary:e.summary,examples:e.examples}))},()=>{console.log(`${se} v${ie} (bin: mfn)`),console.log("Commands an agent can call headlessly:");for(const e of re){console.log(`\n [${e}]`);for(const t of oe.filter(t=>t.category===e))console.log(` ${t.name.padEnd(14)} ${t.summary}`)}console.log("\nConventions: --json for machine output · exit 0/1/2 · logs on stderr")})}};function st(e){switch(e){case"uuid":case"uuid4":return S();case"uuid7":return function(){const e=j(16);e.writeUIntBE(Date.now(),0,6),e[6]=15&e[6]|112,e[8]=63&e[8]|128;const t=e.toString("hex");return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`}();default:return""}}const it=1e5,at={command:"id",describe:"Generate identifiers (UUID v4/v7 or URL-safe nano id)",builder:e=>be(e).option("type",{alias:"t",describe:"Identifier type",type:"string",choices:["uuid","uuid4","uuid7","nano"],default:"uuid"}).option("count",{alias:"n",describe:"How many to generate",type:"number",default:1}).option("size",{describe:"Length for --type nano",type:"number",default:21}).example("mfn id --json","one UUID v4").example("mfn id -t uuid7 -n 3 --json","three time-ordered UUID v7").example("mfn id -t nano --size 12 --json","a 12-char URL-safe id"),handler:e=>{const t=String(e.type),n=Number(e.count),o=Number(e.size);if(!Number.isInteger(n)||n<1||n>it)return $e(e,"InvalidCount","--count must be an integer in 1..100000.",2);if("nano"===t&&(!Number.isInteger(o)||o<1||o>4096))return $e(e,"InvalidSize","--size must be an integer in 1..4096.",2);const r=Array.from({length:n},()=>"nano"===t?function(e){let t="";for(;t.length<e;){const n=j(e);for(let o=0;o<n.length&&t.length<e;o++)t+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"[63&n[o]]}return t}(o):st(t));we(e,{type:t,count:n,ids:r},()=>r.forEach(e=>console.log(e)))}},lt=[".ssh",".gnupg",".aws",".kube",".docker",".gcloud",".azure"],ct=[".netrc",".npmrc",".pgpass",".git-credentials","shadow","credentials","otr.private_key"],dt=[/^id_(rsa|dsa|ecdsa|ed25519)(\.|$)/i,/\.(pem|key|p12|pfx|keystore|jks|asc)$/i,/^\.env(\..+)?$/i];function mt(e){const t=I.resolve(e),n=t.split(I.sep).filter(Boolean),o=I.basename(t);return!!n.some(e=>lt.includes(e.toLowerCase()))||(!!ct.includes(o.toLowerCase())||dt.some(e=>e.test(o)))}function ut(e){if(mt(e))return!0;try{const t=O.realpathSync(e);if(t!==I.resolve(e)&&mt(t))return!0}catch{}return!1}const pt=e=>`Refusing to return the contents of "${e}" — it matches a credential/secret location (guardrail, no override; see SECURITY.md).`,ft=[[/-----BEGIN [A-Z ]*PRIVATE KEY-----/,"private key block"],[/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+/,"JWT"],[/\bAKIA[0-9A-Z]{16}\b/,"AWS access key id"],[/\b(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b/,"GitHub token"],[/\bgithub_pat_[A-Za-z0-9_]{22,}\b/,"GitHub fine-grained token"],[/\bsk-[A-Za-z0-9_-]{20,}\b/,"API secret key (sk-…)"],[/\bxox[abpsr]-[A-Za-z0-9-]{10,}\b/,"Slack token"],[/\bAIza[0-9A-Za-z_-]{35}\b/,"Google API key"],[/\bnpm_[A-Za-z0-9]{36}\b/,"npm token"]];function ht(e){for(const[t,n]of ft)if(t.test(e))return n;return null}function gt(e){let t=0,n=e;n=n.replace(/-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g,()=>(t++,"[redacted: private key block]"));for(const[e,o]of ft)n=n.replace(new RegExp(e,"g"),()=>(t++,`[redacted: ${o}]`));return n=n.split("\n").map(e=>{const n=e.trim();return n.length>=40&&/^[A-Za-z0-9+/_-]+={0,2}$/.test(n)&&!n.includes(" ")?(t++,e.replace(n,"[redacted: key material]")):e}).join("\n"),{text:n,redactedCount:t}}function yt(e){const t=e.hostname.toLowerCase().replace(/^\[|\]$/g,"");return"metadata.google.internal"===t||"metadata"===t||(!!/^169\.254\.\d{1,3}\.\d{1,3}$/.test(t)||("fd00:ec2::254"===t||"100.100.100.200"===t))}const bt=e=>`Refusing to request "${e}" — cloud metadata endpoints are blocked (credential-theft guardrail, no override; see SECURITY.md).`,vt=["md5","sha1","sha256","sha512"],xt={command:"hash [text]",describe:"Hash a string, file, or stdin (md5/sha1/sha256/sha512)",builder:e=>be(e).positional("text",{describe:"String to hash (or pipe via stdin, or use --file)",type:"string"}).option("algo",{alias:"a",describe:"Hash algorithm",type:"string",choices:vt,default:"sha256"}).option("file",{alias:"f",describe:"Hash the contents of this file instead",type:"string"}).option("encoding",{alias:"e",describe:"Digest encoding",type:"string",choices:["hex","base64","base64url"],default:"hex"}).example("mfn hash hello --json",'sha256 of "hello"').example("mfn hash -a md5 -f ./file.txt --json","md5 of a file").example("cat file | mfn hash --json","hash piped stdin"),handler:async e=>{const t=String(e.algo),n=String(e.encoding);let o,r;try{if(void 0!==e.file){if(ut(String(e.file)))return $e(e,"SensitivePath",pt(String(e.file)),2);o=await E(String(e.file)),r=`file:${e.file}`}else if(void 0!==e.text)o=Buffer.from(String(e.text),"utf8"),r="text";else{const t=await Se();if(!t)return $e(e,"MissingInput","Provide a string, --file <path>, or pipe stdin.",2);o=Buffer.from(t,"utf8"),r="stdin"}}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}if(!N().includes(t))return $e(e,"UnsupportedAlgo",`Algorithm "${t}" is not available.`,2);const s=k(t).update(o).digest(n);we(e,{algo:t,encoding:n,source:r,bytes:o.length,hash:s},()=>console.log(s))}};const wt={hex:/^[0-9a-fA-F]*$/,base64:/^[A-Za-z0-9+/]*={0,2}$/,base64url:/^[A-Za-z0-9_-]*$/};const $t={command:"encode [text]",describe:"Encode/decode text (base64, base64url, hex, url)",builder:e=>be(e).positional("text",{describe:"Text to (de/en)code (or pipe via stdin)",type:"string"}).option("as",{alias:"a",describe:"Codec",type:"string",choices:["base64","base64url","hex","url"],default:"base64"}).option("decode",{alias:"d",describe:"Decode instead of encode",type:"boolean",default:!1}).example("mfn encode hello --json",'base64-encode "hello"').example("mfn encode aGVsbG8= -d --json","base64-decode").example('mfn encode "a b&c" --as url --json',"url-encode"),handler:async e=>{const t=String(e.as),n=Boolean(e.decode);let o,r;if(void 0!==e.text)o=String(e.text);else if(o=(await Se()).replace(/\n$/,""),!o)return $e(e,"MissingInput","Provide text or pipe stdin.",2);try{r=n?function(e,t){if("url"===t)return decodeURIComponent(e);const n=wt[t],o="hex"===t?e:e.trim();if(!n.test(o)||"hex"===t&&o.length%2!=0)throw new Error(`not valid ${t}`);return Buffer.from(o,t).toString("utf8")}(o,t):function(e,t){switch(t){case"base64":return Buffer.from(e,"utf8").toString("base64");case"base64url":return Buffer.from(e,"utf8").toString("base64url");case"hex":return Buffer.from(e,"utf8").toString("hex");case"url":return encodeURIComponent(e)}}(o,t)}catch(o){return $e(e,"CodecError",`Could not ${n?"decode":"encode"} as ${t}: ${o instanceof Error?o.message:String(o)}`)}we(e,{operation:n?"decode":"encode",codec:t,input:o,output:r},()=>console.log(r))}};const jt=1048576,St={command:"random",describe:"Generate cryptographically secure random bytes or a password",builder:e=>be(e).option("bytes",{alias:"b",describe:"Number of random bytes",type:"number",default:32}).option("encoding",{alias:"e",describe:"Output encoding for bytes",type:"string",choices:["hex","base64","base64url"],default:"hex"}).option("password",{alias:"p",describe:"Generate a password instead of raw bytes",type:"boolean",default:!1}).option("length",{alias:"l",describe:"Password length",type:"number",default:24}).example("mfn random --json","32 secure random bytes as hex").example("mfn random -b 16 -e base64url --json","16 bytes, base64url").example("mfn random -p -l 32 --json","a 32-char password"),handler:e=>{if(e.password){const t=Number(e.length);if(!Number.isInteger(t)||t<1||t>4096)return $e(e,"InvalidLength","--length must be an integer in 1..4096.",2);const n=function(e,t){const n=t.length,o=Math.floor(256/n)*n;let r="";for(;r.length<e;)for(const s of j(2*e))if(s<o&&(r+=t[s%n],r.length===e))break;return r}(t,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*-_=+");return we(e,{kind:"password",length:t,value:n},()=>console.log(n))}const t=Number(e.bytes);if(!Number.isInteger(t)||t<1||t>jt)return $e(e,"InvalidBytes","--bytes must be an integer in 1..1048576.",2);const n=String(e.encoding),o=j(t).toString(n);we(e,{kind:"bytes",bytes:t,encoding:n,value:o},()=>console.log(o))}};function Nt(e,t){return new Promise(n=>{const o=M({port:e,host:t});o.setTimeout(500);const r=e=>{o.destroy(),n(e)};o.once("connect",()=>r(!0)),o.once("timeout",()=>r(!1)),o.once("error",()=>r(!1))})}function kt(){return new Promise((e,t)=>{const n=T();n.unref(),n.on("error",t),n.listen(0,()=>{const t=n.address(),o="object"==typeof t&&t?t.port:0;e({port:o,close:()=>n.close()})})})}const Et={command:"port",describe:"Find a free port, or check whether a specific port is available",builder:e=>be(e).option("check",{alias:"c",describe:"Check if this specific port is free",type:"number"}).option("count",{alias:"n",describe:"Return this many distinct free ports",type:"number",default:1}).example("mfn port --json","one free port").example("mfn port -n 3 --json","three free ports").example("mfn port -c 3000 --json","is port 3000 free?"),handler:async e=>{if(void 0!==e.check){const t=Number(e.check);if(!Number.isInteger(t)||t<1||t>65535)return $e(e,"InvalidPort","--check must be an integer in 1..65535.",2);const n=await async function(e){const[t,n]=await Promise.all([Nt(e,"127.0.0.1"),Nt(e,"::1")]);return!t&&!n}(t);return we(e,{port:t,available:n},()=>console.log(`${t} is ${n?"free":"in use"}`))}const t=Number(e.count);if(!Number.isInteger(t)||t<1)return $e(e,"InvalidCount","--count must be a positive integer.",2);const n=[];try{for(;n.length<t;){const e=await kt();n.push(e)}}catch(t){n.forEach(e=>e.close());return $e(e,"PortError",`Could not allocate a free port: ${t instanceof Error?t.message:String(t)}`)}const o=n.map(e=>e.port);n.forEach(e=>e.close()),we(e,{count:t,ports:o,port:o[0]},()=>o.forEach(e=>console.log(e)))}};const It={command:"json [query]",describe:"Extract a value from JSON (file or stdin) without reading the whole document",builder:e=>be(e).positional("query",{describe:"Dot/bracket path, e.g. scripts.build or users[0].name (omit for root)",type:"string"}).option("file",{alias:"f",describe:"Read JSON from this file (default: stdin)",type:"string"}).option("keys",{alias:"k",describe:"List the keys at the path instead of the value",type:"boolean",default:!1}).option("length",{alias:"l",describe:"Report array length / object key count at the path",type:"boolean",default:!1}).example("mfn json scripts.build -f package.json --json","one field from a file").example("cat data.json | mfn json users[0].name --json","one field from stdin").example("mfn json dependencies -f package.json --keys --json","just the keys"),handler:async e=>{let t,n;try{if(void 0!==e.file){if(ut(String(e.file)))return $e(e,"SensitivePath",pt(String(e.file)),2);t=await E(String(e.file),"utf8")}else if(t=await Se(),!t)return $e(e,"MissingInput","Provide --file <path> or pipe JSON via stdin.",2)}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}try{n=JSON.parse(t)}catch(t){return $e(e,"InvalidJSON",`Input is not valid JSON: ${t instanceof Error?t.message:String(t)}`)}const o=void 0!==e.query?String(e.query):"",{found:r,value:s}=o?function(e,t){const n=t.replace(/\[(\d+)\]/g,".$1").split(".").filter(e=>""!==e);let o=e;for(const e of n){if(null==o||"object"!=typeof o)return{found:!1,value:void 0};if(!(e in o))return{found:!1,value:void 0};o=o[e]}return{found:!0,value:o}}(n,o):{found:!0,value:n};if(!r)return $e(e,"PathNotFound",`No value at path "${o}".`);const i=null===(a=s)?"null":Array.isArray(a)?"array":typeof a;var a;if(e.keys){if("object"!==i&&"array"!==i)return $e(e,"NotAnObject",`Path "${o||"."}" is ${i}; --keys needs an object/array.`,2);const t=Object.keys(s);return we(e,{query:o||null,type:i,count:t.length,keys:t},()=>t.forEach(e=>console.log(e)))}if(e.length){const t="array"===i?s.length:"object"===i?Object.keys(s).length:"string"===i?s.length:null;return null===t?$e(e,"NoLength",`Path "${o||"."}" is ${i}; --length needs array/object/string.`,2):we(e,{query:o||null,type:i,length:t},()=>console.log(t))}const l="string"==typeof s?gt(s).text:s;we(e,{query:o||null,type:i,value:l},()=>console.log("string"==typeof l?l:JSON.stringify(l,null,2)))}},Ot=e=>Math.ceil(e.length/4),At={command:"count [text]",describe:"Count lines/words/chars/bytes + LLM token estimate (file, stdin, or text)",builder:e=>be(e).positional("text",{describe:"Text to measure (or use --file / pipe stdin)",type:"string"}).option("file",{alias:"f",describe:"Measure the contents of this file",type:"string"}).example("mfn count -f big.log --json","size facts before deciding to read a file").example("git diff | mfn count --json","how big is this diff, in tokens?"),handler:async e=>{let t,n,o;try{if(void 0!==e.file){const r=String(e.file);t=await E(r,"utf8"),o=Buffer.byteLength(t,"utf8"),n=`file:${r}`}else if(void 0!==e.text){const r=String(e.text);try{t=await E(r,"utf8"),n=`file:${r}`}catch{t=r,n="text"}o=Buffer.byteLength(t,"utf8")}else{if(t=await Se(),!t)return $e(e,"MissingInput","Provide text, --file <path>, or pipe stdin.",2);o=Buffer.byteLength(t,"utf8"),n="stdin"}}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}const r=0===t.length?0:t.split("\n").length-(t.endsWith("\n")?1:0),s=(t.match(/\S+/g)??[]).length,i={source:n,lines:r,words:s,chars:t.length,bytes:o,tokensEstimate:Ot(t)};we(e,i,()=>{console.log(`lines ${r} · words ${s} · chars ${t.length} · bytes ${o} · ~${i.tokensEstimate} tokens`)})}},Tt={command:"lines <file>",describe:"Read an exact line range of a file (1-based, inclusive) — not the whole file",builder:e=>be(e).positional("file",{describe:"File to read from",type:"string"}).option("start",{alias:"s",describe:"First line (1-based)",type:"number",default:1}).option("end",{alias:"e",describe:"Last line (inclusive; default start+99)",type:"number"}).option("count",{alias:"n",describe:"Number of lines from --start (alternative to --end)",type:"number"}).example("mfn lines src/app.ts -s 120 -n 30 --json","30 lines starting at line 120").example("mfn lines error.log -s 1 -e 50 --json","first 50 lines"),handler:async e=>{const t=Number(e.start);if(!Number.isInteger(t)||t<1)return $e(e,"InvalidStart","--start must be a positive integer (1-based).",2);if(void 0!==e.end&&void 0!==e.count)return $e(e,"ConflictingFlags","Use --end OR --count, not both.",2);let n;if(void 0!==e.end){if(n=Number(e.end),!Number.isInteger(n)||n<t)return $e(e,"InvalidEnd","--end must be an integer >= --start.",2)}else if(void 0!==e.count){const o=Number(e.count);if(!Number.isInteger(o)||o<1)return $e(e,"InvalidCount","--count must be a positive integer.",2);n=t+o-1}else n=t+99;if(n-t+1>2e3)return $e(e,"RangeTooLarge",`Range spans ${n-t+1} lines; max is 2000.`,2);const o=String(e.file);if(ut(o))return $e(e,"SensitivePath",pt(o),2);let r;try{r=await E(o,"utf8")}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}const s=r.split("\n"),i=r.endsWith("\n")?s.length-1:s.length;if(t>i)return $e(e,"OutOfRange",`--start ${t} is beyond the file (${i} lines).`,2);const a=Math.min(n,i),l=s.slice(t-1,a).map(e=>gt(e).text);we(e,{file:String(e.file),start:t,end:a,requestedEnd:n,totalLines:i,lineCount:l.length,content:l.join("\n")},()=>l.forEach((e,n)=>console.log(`${t+n}\t${e}`)))}},Mt=w(h),Lt="win32"===u(),Ct=/^[A-Za-z0-9][A-Za-z0-9_.+-]*$/;async function _t(e){try{const{stdout:t,stderr:n}=await Mt(e,["--version"],{timeout:3e3}),o=(t||n).split("\n")[0]?.trim();return o||null}catch{return null}}const zt={command:"have <tools...>",describe:"Check which tools are installed (path + version) in one call",builder:e=>be(e).positional("tools",{describe:"Command names to look up, e.g. node git docker",type:"string"}).example("mfn have node git docker --json","availability + versions in one shot").example("mfn have rg jq gh --json","check optional tooling before using it"),handler:async e=>{const t=e.tools.map(String);for(const n of t)if(!Ct.test(n))return $e(e,"InvalidToolName",`"${n}" is not a plain command name.`,2);const n=await Promise.all(t.map(async e=>{const t=await async function(e){try{const{stdout:t}=await Mt(Lt?"where":"which",[e]),n=t.split("\n")[0]?.trim();return n||null}catch{return null}}(e);return t?{name:e,found:!0,path:t,version:await _t(e)}:{name:e,found:!1,path:null,version:null}})),o=n.filter(e=>!e.found).map(e=>e.name);we(e,{count:n.length,allFound:0===o.length,missing:o,tools:n},()=>{for(const e of n)console.log(e.found?`✔ ${e.name} ${e.version??""} (${e.path})`:`✘ ${e.name} not found`)})}},Pt={command:"sys",describe:"One-shot system facts (OS, node, CPU, memory, shell, timezone, paths)",builder:e=>be(e).example("mfn sys --json","everything an agent usually probes with 5+ separate commands"),handler:e=>{const t=m.cpus(),n={platform:process.platform,arch:process.arch,osRelease:m.release(),osVersion:m.version(),hostname:m.hostname(),node:process.version,cpu:{model:t[0]?.model??"unknown",cores:t.length},memory:{totalBytes:m.totalmem(),freeBytes:m.freemem(),totalGB:Math.round(m.totalmem()/1024**3*10)/10,freeGB:Math.round(m.freemem()/1024**3*10)/10},user:m.userInfo().username,shell:process.env.SHELL||process.env.ComSpec||null,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,locale:Intl.DateTimeFormat().resolvedOptions().locale,homedir:m.homedir(),tmpdir:m.tmpdir(),cwd:process.cwd(),uptimeSeconds:Math.round(m.uptime())};we(e,n,()=>{console.log(`${n.platform}/${n.arch} · ${n.osVersion}`),console.log(`node ${n.node} · ${n.cpu.cores}× ${n.cpu.model}`),console.log(`memory ${n.memory.freeGB}/${n.memory.totalGB} GB free`),console.log(`user ${n.user} · shell ${n.shell??"?"} · tz ${n.timezone}`),console.log(`cwd ${n.cwd}`)})}},Rt=w(h);async function Ft(...e){try{const{stdout:t}=await Rt("git",e,{timeout:1e4});return t.trimEnd()}catch{return null}}const Dt={command:"repo",describe:"One-shot git repo summary (branch, dirty counts, ahead/behind, last commits)",builder:e=>be(e).option("commits",{alias:"n",describe:"How many recent commits to include",type:"number",default:5}).example("mfn repo --json","replaces git status + git log + git branch + git remote"),handler:async e=>{const t=Number(e.commits);if(!Number.isInteger(t)||t<0||t>100)return $e(e,"InvalidCount","--commits must be an integer in 0..100.",2);if("true"!==await Ft("rev-parse","--is-inside-work-tree"))return $e(e,"NotARepo",`Not inside a git repository: ${process.cwd()}`);const[n,o,r,s,i,a]=await Promise.all([Ft("rev-parse","--show-toplevel"),Ft("rev-parse","--abbrev-ref","HEAD"),Ft("status","--porcelain"),Ft("rev-list","--left-right","--count","@{upstream}...HEAD"),Ft("remote","-v"),t>0?Ft("log",`-${t}`,"--pretty=format:%h%x09%an%x09%ad%x09%s","--date=short"):Promise.resolve("")]),l=(r??"").split("\n").filter(Boolean),c=l.filter(e=>e.startsWith("??")).length,d=l.filter(e=>!e.startsWith("??")&&" "!==e[0]).length,m=l.filter(e=>!e.startsWith("??")&&" "!==e[1]).length;let u=null,p=null;if(s){const[e,t]=s.split("\t").map(Number);p=Number.isFinite(e)?e:null,u=Number.isFinite(t)?t:null}const f=Array.from(new Map((i??"").split("\n").filter(Boolean).map(e=>{const[t,n]=e.split(/\s+/);return[t,{name:t,url:n}]})).values()),h=(a??"").split("\n").filter(Boolean).map(e=>{const[t,n,o,...r]=e.split("\t");return{hash:t,author:n,date:o,subject:r.join("\t")}}),g=0===l.length;we(e,{root:n,branch:o,clean:g,staged:d,unstaged:m,untracked:c,ahead:u,behind:p,hasUpstream:null!==s,remotes:f,commits:h},()=>{console.log(`${n} (${o})`),console.log(g?"clean":`staged ${d} · unstaged ${m} · untracked ${c}`),null!==u&&console.log(`ahead ${u} · behind ${p}`);for(const e of h)console.log(`${e.hash} ${e.date} ${e.subject}`)})}};class Bt{s;i=0;constructor(e){this.s=e}parse(){const e=this.expr();if(this.skipWs(),this.i<this.s.length)throw new Error(`Unexpected "${this.s[this.i]}" at position ${this.i}`);return e}skipWs(){for(;" "===this.s[this.i];)this.i++}peek(){return this.skipWs(),this.s[this.i]??""}expr(){let e=this.term();for(let t=this.peek();"+"===t||"-"===t;t=this.peek())this.i++,e=Ut(e,this.term(),t);return e}term(){let e=this.factor();for(let t=this.peek();"*"===t||"/"===t||"%"===t;t=this.peek())this.i++,e=Ut(e,this.factor(),t);return e}factor(){const e=this.unary();return"^"===this.peek()?(this.i++,Ut(e,this.factor(),"^")):e}unary(){if("-"===this.peek()){this.i++;const e=this.unary();return{big:null===e.big?null:-e.big,float:-e.float}}return this.atom()}atom(){if("("===this.peek()){this.i++;const e=this.expr();if(")"!==this.peek())throw new Error("Missing closing parenthesis");return this.i++,e}this.skipWs();const e=/^\d+(\.\d+)?([eE][+-]?\d+)?/.exec(this.s.slice(this.i));if(!e)throw new Error(`Expected a number at position ${this.i}`);this.i+=e[0].length;return{big:!e[1]&&!e[2]?BigInt(e[0]):null,float:Number(e[0])}}}function Ut(e,t,n){const o="+"===n?e.float+t.float:"-"===n?e.float-t.float:"*"===n?e.float*t.float:"/"===n?e.float/t.float:"%"===n?e.float%t.float:Math.pow(e.float,t.float);if("/"===n&&0===t.float)throw new Error("Division by zero");if(null===e.big||null===t.big||"/"===n)return{big:null,float:o};if("^"===n){if(t.big<0n)return{big:null,float:o};if(t.big>4096n)throw new Error("Exponent too large (max 4096)");return{big:e.big**t.big,float:o}}if("%"===n&&0n===t.big)throw new Error("Modulo by zero");return{big:"+"===n?e.big+t.big:"-"===n?e.big-t.big:"*"===n?e.big*t.big:e.big%t.big,float:o}}const Jt={command:"calc <expression>",describe:"Exact arithmetic (+ - * / % ^, parens; integers use BigInt — no float drift)",builder:e=>be(e).positional("expression",{describe:'Expression, e.g. "2^64 - 1" or "(3 + 4) * 5"',type:"string"}).example('mfn calc "2^53 + 1" --json',"exact: 9007199254740993 (floats get this wrong)").example('mfn calc "1729 * 4096 % 7" --json',"integer arithmetic stays exact"),handler:e=>{const t=String(e.expression).trim();if(!t)return $e(e,"MissingInput","Provide an arithmetic expression.",2);if(t.length>1e3)return $e(e,"ExpressionTooLong","Expression exceeds 1000 characters.",2);let n;try{n=new Bt(t).parse()}catch(n){return $e(e,"ParseError",`Could not evaluate "${t}": ${n instanceof Error?n.message:String(n)}`,2)}const o=null!==n.big,r=o?n.big.toString():String(n.float);we(e,{expression:t,result:r,exact:o,float:n.float},()=>console.log(r))}},Wt=/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;function qt(e){const t=Wt.exec(e.trim());return t?{raw:e.trim(),major:Number(t[1]),minor:Number(t[2]),patch:Number(t[3]),prerelease:t[4]?t[4].split("."):[],build:t[5]??null}:null}function Zt(e,t){for(const n of["major","minor","patch"])if(e[n]!==t[n])return e[n]<t[n]?-1:1;if(0===e.prerelease.length&&0===t.prerelease.length)return 0;if(0===e.prerelease.length)return 1;if(0===t.prerelease.length)return-1;const n=Math.max(e.prerelease.length,t.prerelease.length);for(let o=0;o<n;o++){const n=e.prerelease[o],r=t.prerelease[o];if(void 0===n)return-1;if(void 0===r)return 1;const s=/^\d+$/.test(n),i=/^\d+$/.test(r);if(s&&i){if(Number(n)!==Number(r))return Number(n)<Number(r)?-1:1}else{if(s!==i)return s?-1:1;if(n!==r)return n<r?-1:1}}return 0}const Gt={command:"semver <versions...>",describe:"Validate, compare, sort, or bump semantic versions (exact, per semver.org)",builder:e=>be(e).positional("versions",{describe:"One or more versions",type:"string"}).option("bump",{alias:"b",describe:"Bump the (single) version",type:"string",choices:["major","minor","patch"]}).option("sort",{alias:"s",describe:"Sort all given versions ascending",type:"boolean",default:!1}).example("mfn semver 1.2.3 --json","validate + parse one version").example("mfn semver 1.10.0 1.9.2 --json","compare two (1.10.0 > 1.9.2 — string sort lies)").example("mfn semver 2.0.0-rc.1 2.0.0 --sort --json","prerelease ordering done right").example("mfn semver 1.2.3 -b minor --json","bump → 1.3.0"),handler:e=>{const t=e.versions.map(String),n=[];for(const o of t){const t=qt(o);if(!t)return $e(e,"InvalidVersion",`"${o}" is not a valid semantic version.`,2);n.push(t)}if(e.bump){if(1!==n.length)return $e(e,"TooManyVersions","--bump takes exactly one version.",2);const t=function(e,t){return"major"===t?`${e.major+1}.0.0`:"minor"===t?`${e.major}.${e.minor+1}.0`:`${e.major}.${e.minor}.${e.patch+1}`}(n[0],String(e.bump));return we(e,{input:n[0].raw,bump:e.bump,result:t},()=>console.log(t))}if(e.sort||n.length>2){const t=[...n].sort(Zt).map(e=>e.raw);return we(e,{count:t.length,sorted:t,latest:t[t.length-1]},()=>t.forEach(e=>console.log(e)))}if(2===n.length){const t=Zt(n[0],n[1]);return we(e,{a:n[0].raw,b:n[1].raw,comparison:t,relation:0===t?"equal":t<0?"a < b":"a > b",greater:t>=0?n[0].raw:n[1].raw},()=>console.log(0===t?"equal":t<0?`${n[1].raw} is greater`:`${n[0].raw} is greater`))}const o=n[0];we(e,{version:o.raw,valid:!0,major:o.major,minor:o.minor,patch:o.patch,prerelease:o.prerelease.length?o.prerelease.join("."):null,build:o.build,isPrerelease:o.prerelease.length>0},()=>console.log(`${o.major}.${o.minor}.${o.patch} valid`))}};const Ht=e=>e.charAt(0).toUpperCase()+e.slice(1),Vt={camel:e=>e.map((e,t)=>0===t?e:Ht(e)).join(""),pascal:e=>e.map(Ht).join(""),snake:e=>e.join("_"),kebab:e=>e.join("-"),constant:e=>e.join("_").toUpperCase(),dot:e=>e.join("."),path:e=>e.join("/"),title:e=>e.map(Ht).join(" "),sentence:e=>Ht(e.join(" ")),lower:e=>e.join(" "),upper:e=>e.join(" ").toUpperCase()},Yt=Object.keys(Vt),Kt=1e5,Qt={command:"case [text]",describe:"Convert a string between naming styles (camel, snake, kebab, pascal, …)",builder:e=>be(e).positional("text",{describe:"Text to convert (or pipe via stdin)",type:"string"}).option("to",{alias:"t",describe:"Target style (omit for all styles at once)",type:"string",choices:Yt}).example('mfn case "user profile id" -t camel --json',"→ userProfileId").example("mfn case getUserName -t snake --json","→ get_user_name").example("mfn case my-component --json","all styles in one call"),handler:async e=>{let t;if(void 0!==e.text)t=String(e.text);else if(t=(await Se()).replace(/\n$/,""),!t)return $e(e,"MissingInput","Provide text or pipe stdin.",2);if(t.length>Kt)return $e(e,"InputTooLarge","Input exceeds 100000 characters.",2);const n=function(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").split(/[\s_\-./]+/).filter(Boolean).map(e=>e.toLowerCase())}(t);if(0===n.length)return $e(e,"NoWords","Input contains no convertible words.",2);if(e.to){const o=String(e.to),r=Vt[o](n);return we(e,{input:t,style:o,output:r},()=>console.log(r))}const o=Object.fromEntries(Yt.map(e=>[e,Vt[e](n)]));we(e,{input:t,words:n,styles:o},()=>{for(const[e,t]of Object.entries(o))console.log(`${e.padEnd(9)} ${t}`)})}},Xt=[[0,59],[0,23],[1,31],[1,12],[0,6]],en="JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC".split(" "),tn="SUN MON TUE WED THU FRI SAT".split(" ");function nn(e,t){const n=e.toUpperCase();if(3===t){const e=en.indexOf(n);if(e>=0)return String(e+1)}if(4===t){const e=tn.indexOf(n);if(e>=0)return String(e)}return e}function on(e,t){const[n,o]=Xt[t],r=new Set;for(const s of e.split(",")){const[e,i]=s.split("/"),a=void 0===i?1:Number(i);if(!Number.isInteger(a)||a<1)throw new Error(`Invalid step "${i}" in "${s}"`);let l,c;if("*"===e||""===e)l=n,c=o;else if(e.includes("-")){const[n,o]=e.split("-").map(e=>Number(nn(e,t)));l=n,c=o}else l=c=Number(nn(e,t)),void 0!==i&&(c=o);if(!Number.isInteger(l)||!Number.isInteger(c))throw new Error(`Invalid value in "${s}"`);if(4===t&&(7===l&&(l=0),7===c&&(c=0)),l<n||c>o||l>c)throw new Error(`"${s}" out of range ${n}-${o}`);for(let e=l;e<=c;e+=a)r.add(e)}return r}const rn={"@yearly":"0 0 1 1 *","@annually":"0 0 1 1 *","@monthly":"0 0 1 * *","@weekly":"0 0 * * 0","@daily":"0 0 * * *","@midnight":"0 0 * * *","@hourly":"0 * * * *"};function sn(e,t){if(!e.month.has(t.getMonth()+1))return!1;const n=e.dayOfMonth.has(t.getDate()),o=e.dayOfWeek.has(t.getDay());return e.domRestricted&&e.dowRestricted?n||o:n&&o}const an={command:"cron <expression>",describe:"Validate a cron expression, explain it, and compute the next run times",builder:e=>be(e).positional("expression",{describe:"5-field cron (minute hour dom month dow) or @daily/@hourly/@weekly/…",type:"string"}).option("next",{alias:"n",describe:"How many upcoming run times to compute",type:"number",default:3}).example('mfn cron "*/15 9-17 * * 1-5" --json',"validate + explain + next runs").example('mfn cron "@daily" -n 1 --json',"when does @daily fire next?"),handler:e=>{const t=String(e.expression).trim(),n=Number(e.next);if(!Number.isInteger(n)||n<0||n>100)return $e(e,"InvalidCount","--next must be an integer in 0..100.",2);let o;try{o=function(e){const t=(rn[e.trim().toLowerCase()]??e.trim()).split(/\s+/);if(5!==t.length)throw new Error(`Expected 5 fields (minute hour dom month dow), got ${t.length}`);return{minute:on(t[0],0),hour:on(t[1],1),dayOfMonth:on(t[2],2),month:on(t[3],3),dayOfWeek:on(t[4],4),domRestricted:"*"!==t[2],dowRestricted:"*"!==t[4]}}(t)}catch(n){const o=n instanceof Error?n.message:String(n);return $e(e,"InvalidCron",`"${t}" is not valid cron: ${o}`,2)}const r=function(e,t,n){const o=[],r=new Date(t);r.setSeconds(0,0),r.setMinutes(r.getMinutes()+1);const s=new Date(t);for(s.setFullYear(s.getFullYear()+5);o.length<n&&r<=s;)sn(e,r)?e.hour.has(r.getHours())?e.minute.has(r.getMinutes())?(o.push(new Date(r)),r.setMinutes(r.getMinutes()+1)):r.setMinutes(r.getMinutes()+1):(r.setMinutes(0),r.setHours(r.getHours()+1)):(r.setHours(0,0,0,0),r.setDate(r.getDate()+1));return o}(o,new Date,n),s=function(e){const t=(e,t)=>e.size>t?"several values":[...e].sort((e,t)=>e-t).join(","),n=60===e.minute.size?"every minute":1===e.minute.size?`at minute ${t(e.minute,5)}`:`at minutes ${t(e.minute,8)}`,o=24===e.hour.size?"of every hour":1===e.hour.size?`past hour ${t(e.hour,5)}`:`past hours ${t(e.hour,8)}`,r=e.domRestricted?`on day-of-month ${t(e.dayOfMonth,8)}`:"",s=12===e.month.size?"":`in month ${t(e.month,6)}`,i=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];return[n,o,r,s,e.dowRestricted?`on ${[...e.dayOfWeek].sort((e,t)=>e-t).map(e=>i[e]).join(",")}`:""].filter(Boolean).join(" ")}(o),i=e=>{const t=(e,t=2)=>String(e).padStart(t,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())} ${t(e.getHours())}:${t(e.getMinutes())}:00`};we(e,{expression:t,valid:!0,description:s,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,next:r.map(e=>({local:i(e),iso:e.toISOString(),epochMs:e.getTime()}))},()=>{console.log(`${t} → ${s}`);for(const e of r)console.log(i(e))})}};const ln=2e4,cn={command:"diff <fileA> <fileB>",describe:"Line diff of two files as structured hunks (summary first, not a wall of text)",builder:e=>be(e).positional("fileA",{describe:"Old file",type:"string"}).positional("fileB",{describe:"New file",type:"string"}).option("summary",{alias:"s",describe:"Only counts + hunk locations (no line content)",type:"boolean",default:!1}).example("mfn diff old.json new.json --json","structured hunks").example("mfn diff a.txt b.txt -s --json","just how much changed, and where"),handler:async e=>{for(const t of[e.fileA,e.fileB])if(ut(String(t)))return $e(e,"SensitivePath",pt(String(t)),2);let t,n;try{[t,n]=await Promise.all([E(String(e.fileA),"utf8"),E(String(e.fileB),"utf8")])}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,"ReadError",n)}const o=t.split("\n"),r=n.split("\n");if(o.length>ln||r.length>ln)return $e(e,"FileTooLarge","diff is capped at 20000 lines per file.",2);const s=t===n,i=s?[]:function(e,t){const n=e.length,o=t.length,r=Array.from({length:n+1},()=>new Array(o+1).fill(0));for(let s=n-1;s>=0;s--)for(let n=o-1;n>=0;n--)r[s][n]=e[s]===t[n]?r[s+1][n+1]+1:Math.max(r[s+1][n],r[s][n+1]);const s=[];let i=0,a=0;for(;i<n||a<o;){if(i<n&&a<o&&e[i]===t[a]){i++,a++;continue}const l={aStart:i+1,aLines:0,bStart:a+1,bLines:0,removed:[],added:[]};for(;i<n&&(a>=o||r[i+1][a]>=r[i][a+1])&&(l.removed.push(e[i++]),l.aLines++,!(i<n&&a<o&&e[i]===t[a])););for(;a<o&&(i>=n||r[i+1][a]<r[i][a+1]||void 0===e[i]||e[i]!==t[a])&&!(i<n&&e[i]===t[a]);)l.added.push(t[a++]),l.bLines++;s.push(l)}return s}(o,r),a=i.reduce((e,t)=>e+t.removed.length,0),l=i.reduce((e,t)=>e+t.added.length,0),c=i.map(t=>e.summary?{aStart:t.aStart,aLines:t.aLines,bStart:t.bStart,bLines:t.bLines}:t);we(e,{fileA:String(e.fileA),fileB:String(e.fileB),identical:s,hunkCount:i.length,linesAdded:l,linesRemoved:a,hunks:c},()=>{if(s)return console.log("files are identical");console.log(`${i.length} hunk(s) · +${l} −${a}`);for(const t of i)console.log(`@@ -${t.aStart},${t.aLines} +${t.bStart},${t.bLines} @@`),e.summary||(t.removed.forEach(e=>console.log(`- ${e}`)),t.added.forEach(e=>console.log(`+ ${e}`)))})}},dn=/(key|token|secret|password|passwd|credential|auth|cookie|session|private|api)/i,mn="••••",un=(e,t)=>dn.test(e)||null!==ht(t),pn={command:"env [names...]",describe:"Inspect environment variables with automatic secret redaction",builder:e=>be(e).positional("names",{describe:"Variable names to read (omit to list all names)",type:"string"}).option("prefix",{alias:"p",describe:"Only variables starting with this prefix",type:"string"}).example("mfn env NODE_ENV PATH --json","specific variables (secrets auto-redacted)").example("mfn env -p NEXT_PUBLIC_ --json","all NEXT_PUBLIC_* variables").example("mfn env --json","just the names — values omitted"),handler:e=>{const t=(e.names??[]).map(String),n=void 0!==e.prefix?String(e.prefix):null;if(t.length>0){const n=t.map(e=>{const t=process.env[e];if(void 0===t)return{name:e,set:!1,value:null,redacted:!1};return un(e,t)?{name:e,set:!0,value:mn,redacted:!0,chars:t.length}:{name:e,set:!0,value:t,redacted:!1}}),o=n.filter(e=>!e.set).map(e=>e.name);return we(e,{count:n.length,missing:o,vars:n},()=>{for(const e of n)console.log(e.set?`${e.name}=${e.value}`:`${e.name} (not set)`)})}const o=Object.keys(process.env).filter(e=>!n||e.startsWith(n)).sort();if(n){const t=o.map(e=>{const t=process.env[e]??"";return un(e,t)?{name:e,set:!0,value:mn,redacted:!0,chars:t.length}:{name:e,set:!0,value:t,redacted:!1}});return we(e,{prefix:n,count:t.length,vars:t},()=>{for(const e of t)console.log(`${e.name}=${e.value}`)})}if(0===o.length)return $e(e,"NoMatch","No environment variables found.");we(e,{count:o.length,names:o},()=>o.forEach(e=>console.log(e)))}},fn=new Set(["node_modules",".git",".nx","dist","build","coverage"]);const hn=e=>e>=1024**3?`${(e/1024**3).toFixed(1)}G`:e>=1048576?`${(e/1048576).toFixed(1)}M`:e>=1024?`${(e/1024).toFixed(1)}K`:`${e}B`,gn={command:"size [dir]",describe:"Total size + largest files/dirs under a directory (one call, not du|sort|head)",builder:e=>be(e).positional("dir",{describe:"Directory to analyse (default: cwd)",type:"string"}).option("top",{alias:"t",describe:"How many largest files/dirs to list",type:"number",default:10}).option("ignore",{alias:"i",describe:"Additional directory names to ignore",type:"array"}).example("mfn size --json","where is the disk going in this project?").example("mfn size ./src -t 5 --json","five largest files under src"),handler:e=>{const t=Number(e.top);if(!Number.isInteger(t)||t<1||t>1e3)return $e(e,"InvalidTop","--top must be an integer in 1..1000.",2);const n=I.resolve(String(e.dir??process.cwd()));let o;try{o=O.statSync(n)}catch{return $e(e,"NotFound",`Directory not found: ${n}`,2)}if(!o.isDirectory())return $e(e,"NotADirectory",`${n} is not a directory.`,2);const{files:r,truncated:s}=function(e,t){const n=new Set([...fn,...t]),o=[];let r=!1;const s=t=>{if(o.length>=2e5)return void(r=!0);let i;try{i=O.readdirSync(t,{withFileTypes:!0})}catch{return}for(const r of i){if(n.has(r.name))continue;const i=I.join(t,r.name);if(r.isDirectory())s(i);else if(r.isFile())try{o.push({path:I.relative(e,i),bytes:O.statSync(i).size})}catch{}}};return s(e),{files:o,truncated:r}}(n,(e.ignore??[]).map(String)),i=r.reduce((e,t)=>e+t.bytes,0),a=new Map;for(const e of r){const t=e.path.split(I.sep)[0];a.set(t,(a.get(t)??0)+e.bytes)}const l=[...a.entries()].sort((e,t)=>t[1]-e[1]).slice(0,t).map(([e,t])=>({name:e,bytes:t,human:hn(t)})),c=[...r].sort((e,t)=>t.bytes-e.bytes).slice(0,t).map(e=>({path:e.path,bytes:e.bytes,human:hn(e.bytes)}));we(e,{root:n,fileCount:r.length,totalBytes:i,totalHuman:hn(i),truncated:s,largestFiles:c,byTopLevel:l},()=>{console.log(`${n}: ${hn(i)} across ${r.length} files`);for(const e of l)console.log(` ${e.human.padStart(8)} ${e.name}/`);console.log("largest files:");for(const e of c)console.log(` ${e.human.padStart(8)} ${e.path}`)})}},yn=new Set(["node_modules",".git",".nx","dist","build","coverage"]);const bn={command:"ext [dir]",describe:'File counts and bytes per extension — "what kind of project is this?" in one call',builder:e=>be(e).positional("dir",{describe:"Directory to analyse (default: cwd)",type:"string"}).option("ignore",{alias:"i",describe:"Additional directory names to ignore",type:"array"}).example("mfn ext --json","project composition by file type"),handler:e=>{const t=I.resolve(String(e.dir??process.cwd()));let n;try{n=O.statSync(t)}catch{return $e(e,"NotFound",`Directory not found: ${t}`,2)}if(!n.isDirectory())return $e(e,"NotADirectory",`${t} is not a directory.`,2);const{byExt:o,total:r,truncated:s}=function(e,t){const n=new Set([...yn,...t]),o=new Map;let r=0,s=!1;const i=e=>{if(r>=2e5)return void(s=!0);let t;try{t=O.readdirSync(e,{withFileTypes:!0})}catch{return}for(const s of t){if(n.has(s.name))continue;const t=I.join(e,s.name);if(s.isDirectory())i(t);else if(s.isFile()){const e=I.extname(s.name).toLowerCase()||"(none)";let n=0;try{n=O.statSync(t).size}catch{}const i=o.get(e)??{count:0,bytes:0};i.count++,i.bytes+=n,o.set(e,i),r++}}};return i(e),{byExt:o,total:r,truncated:s}}(t,(e.ignore??[]).map(String)),i=[...o.entries()].sort((e,t)=>t[1].count-e[1].count).map(([e,t])=>({ext:e,count:t.count,bytes:t.bytes}));we(e,{root:t,fileCount:r,truncated:s,extensions:i},()=>{console.log(`${r} files under ${t}`);for(const e of i.slice(0,20))console.log(` ${String(e.count).padStart(6)} ${e.ext}`)})}},vn={command:"freq [file]",describe:"Most frequent lines of a file/stdin (log analysis without sort|uniq -c|sort|head)",builder:e=>be(e).positional("file",{describe:"File to analyse (or pipe via stdin)",type:"string"}).option("top",{alias:"t",describe:"How many entries to return",type:"number",default:10}).option("min",{alias:"m",describe:"Only lines occurring at least this often",type:"number",default:1}).option("trim",{describe:"Trim whitespace before counting (default true)",type:"boolean",default:!0}).example("mfn freq error.log -t 5 --json","the 5 most repeated log lines").example("grep ERROR app.log | mfn freq --json","most frequent error messages"),handler:async e=>{const t=Number(e.top),n=Number(e.min);if(!Number.isInteger(t)||t<1||t>1e4)return $e(e,"InvalidTop","--top must be an integer in 1..10000.",2);if(!Number.isInteger(n)||n<1)return $e(e,"InvalidMin","--min must be a positive integer.",2);let o,r;try{if(void 0!==e.file){if(ut(String(e.file)))return $e(e,"SensitivePath",pt(String(e.file)),2);o=await E(String(e.file),"utf8"),r=`file:${e.file}`}else{if(o=await Se(),!o)return $e(e,"MissingInput","Provide a file or pipe stdin.",2);r="stdin"}}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}const s=new Map;let i=0;for(const t of o.split("\n")){const n=e.trim?t.trim():t;""!==n&&(i++,s.set(n,(s.get(n)??0)+1))}const a=[...s.entries()].filter(([,e])=>e>=n).sort((e,t)=>t[1]-e[1]||e[0].localeCompare(t[0])).slice(0,t).map(([e,t])=>({count:t,line:gt(e).text}));we(e,{source:r,totalLines:i,uniqueLines:s.size,returned:a.length,entries:a},()=>{for(const e of a)console.log(`${String(e.count).padStart(7)} ${e.line}`)})}},xn={command:"regex <pattern> [text]",describe:"Test a regular expression against text — verify instead of guessing",builder:e=>be(e).positional("pattern",{describe:"Regular expression (without surrounding slashes)",type:"string"}).positional("text",{describe:"Text to test (or --file / stdin)",type:"string"}).option("file",{alias:"f",describe:"Test against the contents of this file",type:"string"}).option("flags",{describe:"Regex flags (g is always added)",type:"string",default:""}).example('mfn regex "^v\\\\d+\\\\.\\\\d+" "v1.22.0" --json',"does it match?").example('mfn regex "TODO[:!]?" -f src/app.ts --json',"all matches with positions and groups"),handler:async e=>{const t=String(e.pattern);if(t.length>1e3)return $e(e,"PatternTooLong","Pattern exceeds 1000 characters.",2);const n=String(e.flags??"");if(!/^[imsuvy]*$/.test(n))return $e(e,"InvalidFlags","Flags may only contain i m s u v y (g is implicit).",2);let o,r,s;try{o=new RegExp(t,n.includes("g")?n:n+"g")}catch(t){return $e(e,"InvalidRegex",t instanceof Error?t.message:String(t),2)}try{if(void 0!==e.file){if(ut(String(e.file)))return $e(e,"SensitivePath",pt(String(e.file)),2);r=await E(String(e.file),"utf8"),s=`file:${e.file}`}else if(void 0!==e.text)r=String(e.text),s="text";else{if(r=await Se(),!r)return $e(e,"MissingInput","Provide text, --file <path>, or pipe stdin.",2);s="stdin"}}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}const i=[];let a=!1;for(const e of r.matchAll(o)){if(i.length>=1e3){a=!0;break}const t=r.slice(0,e.index).split("\n").length;if(i.push({match:gt(e[0]).text,index:e.index,line:t,groups:e.slice(1).map(e=>void 0===e?e:gt(e).text)}),""===e[0])break}we(e,{pattern:t,flags:o.flags,source:s,matched:i.length>0,count:i.length,truncated:a,matches:i},()=>{if(0===i.length)return console.log("no match");for(const e of i)console.log(`line ${e.line} @${e.index}: ${e.match}`)})}},wn={command:"url <value>",describe:"Parse a URL into components with decoded query parameters",builder:e=>be(e).positional("value",{describe:"URL to parse",type:"string"}).example('mfn url "https://api.x.com/v2/users?id=42&fields=name,bio" --json',"all components at once"),handler:e=>{const t=String(e.value);let n;try{n=new URL(t)}catch{return $e(e,"InvalidURL",`"${t}" is not a valid absolute URL (include the scheme).`,2)}const o={};for(const[e,t]of n.searchParams){const n=o[e];void 0===n?o[e]=t:Array.isArray(n)?n.push(t):o[e]=[n,t]}const r={href:n.href,protocol:n.protocol.replace(/:$/,""),username:n.username||null,host:n.host,hostname:n.hostname,port:n.port?Number(n.port):null,path:n.pathname,pathSegments:n.pathname.split("/").filter(Boolean),query:o,queryCount:[...n.searchParams.keys()].length,hash:n.hash?n.hash.slice(1):null,origin:n.origin};we(e,r,()=>{console.log(`${r.protocol}://${r.host}${r.path}`);for(const[e,t]of Object.entries(o))console.log(` ?${e} = ${JSON.stringify(t)}`);r.hash&&console.log(` #${r.hash}`)})}},$n={command:"ip",describe:"Local network interfaces and addresses (no network calls, no ifconfig parsing)",builder:e=>be(e).option("all",{alias:"a",describe:"Include internal/loopback interfaces",type:"boolean",default:!1}).example("mfn ip --json","external-facing local addresses").example("mfn ip -a --json","every interface including loopback"),handler:e=>{const t=m.networkInterfaces(),n=Object.entries(t).map(([t,n])=>({name:t,addresses:(n??[]).filter(t=>e.all||!t.internal).map(e=>({address:e.address,family:e.family,internal:e.internal,mac:e.mac,cidr:e.cidr}))})).filter(e=>e.addresses.length>0),o=n.flatMap(e=>e.addresses).find(e=>"IPv4"===e.family&&!e.internal)?.address??null;we(e,{primaryIPv4:o,count:n.length,interfaces:n},()=>{o&&console.log(`primary IPv4: ${o}`);for(const e of n)for(const t of e.addresses)console.log(`${e.name.padEnd(10)} ${t.family.padEnd(5)} ${t.address}`)})}},jn={shell:e=>`'${e.replace(/'/g,"'\\''")}'`,json:e=>JSON.stringify(e),regex:e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),html:e=>e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),url:e=>encodeURIComponent(e),string:e=>JSON.stringify(e).slice(1,-1)},Sn=Object.keys(jn),Nn=1e6,kn={command:"escape [text]",describe:"Escape text exactly for shell, JSON, regex, HTML, or URL contexts",builder:e=>be(e).positional("text",{describe:"Text to escape (or pipe via stdin)",type:"string"}).option("as",{alias:"a",describe:"Target context",type:"string",choices:Sn,default:"shell"}).example('mfn escape "it\'s done" --json',"safe single-quoted shell string").example('mfn escape "1.2.3" -a regex --json',"regex-literal: 1\\.2\\.3").example("mfn escape 'line1\nline2' -a json --json","paste-ready JSON string"),handler:async e=>{let t;if(void 0!==e.text)t=String(e.text);else if(t=(await Se()).replace(/\n$/,""),!t)return $e(e,"MissingInput","Provide text or pipe stdin.",2);if(t.length>Nn)return $e(e,"InputTooLarge","Input exceeds 1000000 characters.",2);const n=String(e.as),o=jn[n](t);we(e,{mode:n,input:t,output:o},()=>console.log(o))}};function En(e,t,n){if(n.size>=500)return;const o=null===(r=e)?"null":Array.isArray(r)?"array":typeof r;var r;const s=""===t?".":t;if(n.has(s)||n.set(s,new Set),n.get(s).add(o),"object"===o)for(const[o,r]of Object.entries(e))En(r,""===t?o:`${t}.${o}`,n);else if("array"===o){const o=e;n.get(s).delete("array"),n.get(s).add(`array(${o.length})`);for(const e of o.slice(0,50))En(e,`${t}[]`,n)}}const In={command:"schema [query]",describe:"Infer the shape of a JSON document (paths + types) without dumping the data",builder:e=>be(e).positional("query",{describe:"Optional dot-path to start from (see `mfn json`)",type:"string"}).option("file",{alias:"f",describe:"Read JSON from this file (default: stdin)",type:"string"}).example("mfn schema -f response.json --json","shape of a big API payload, not its content").example("curl -s api/users | mfn schema --json","what fields does this API return?"),handler:async e=>{let t,n;try{if(void 0!==e.file){if(ut(String(e.file)))return $e(e,"SensitivePath",pt(String(e.file)),2);t=await E(String(e.file),"utf8")}else if(t=await Se(),!t)return $e(e,"MissingInput","Provide --file <path> or pipe JSON via stdin.",2)}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}try{n=JSON.parse(t)}catch(t){return $e(e,"InvalidJSON",`Input is not valid JSON: ${t instanceof Error?t.message:String(t)}`)}if(e.query){const t=String(e.query).replace(/\[(\d+)\]/g,".$1").split(".").filter(Boolean);for(const o of t){if(null===n||"object"!=typeof n||!(o in n))return $e(e,"PathNotFound",`No value at path "${e.query}".`);n=n[o]}}const o=new Map;En(n,"",o);const r=[...o.entries()].map(([e,t])=>({path:e,type:[...t].sort().join(" | ")}));we(e,{source:e.file?`file:${e.file}`:"stdin",bytes:t.length,pathCount:r.length,truncated:o.size>=500,paths:r},()=>{for(const e of r)console.log(`${e.path.padEnd(40)} ${e.type}`)})}},On=[{kind:"function",re:/^(?<exp>export\s+)?(?:default\s+)?(?:async\s+)?function\s*\*?\s*(?<name>[A-Za-z_$][\w$]*)/},{kind:"class",re:/^(?<exp>export\s+)?(?:default\s+)?(?:abstract\s+)?class\s+(?<name>[A-Za-z_$][\w$]*)/},{kind:"interface",re:/^(?<exp>export\s+)?interface\s+(?<name>[A-Za-z_$][\w$]*)/},{kind:"type",re:/^(?<exp>export\s+)?type\s+(?<name>[A-Za-z_$][\w$]*)\s*=/},{kind:"enum",re:/^(?<exp>export\s+)?(?:const\s+)?enum\s+(?<name>[A-Za-z_$][\w$]*)/},{kind:"const",re:/^(?<exp>export\s+)?const\s+(?<name>[A-Za-z_$][\w$]*)\s*(?::[^=]+)?=\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*(?::[^=]+)?=>/},{kind:"variable",re:/^(?<exp>export\s+)(?:const|let|var)\s+(?<name>[A-Za-z_$][\w$]*)/}],An=[{kind:"function",re:/^(?:async\s+)?def\s+(?<name>[A-Za-z_][\w]*)/},{kind:"class",re:/^class\s+(?<name>[A-Za-z_][\w]*)/}],Tn=[{kind:"heading",re:/^(?<name>#{1,6}\s+.+)$/}],Mn={".ts":On,".tsx":On,".js":On,".jsx":On,".mjs":On,".cjs":On,".py":An,".go":[{kind:"function",re:/^func\s+(?:\([^)]+\)\s+)?(?<name>[A-Za-z_][\w]*)/},{kind:"type",re:/^type\s+(?<name>[A-Za-z_][\w]*)/}],".md":Tn,".markdown":Tn},Ln=Object.keys(Mn);const Cn={command:"outline <file>",describe:"Outline a source file — symbols + line numbers, not the whole file",builder:e=>be(e).positional("file",{describe:"Source file (.ts .js .tsx .py .go .md …)",type:"string"}).option("kind",{alias:"k",describe:"Only symbols of this kind (function, class, …)",type:"string"}).option("exported",{alias:"e",describe:"Only exported symbols (TS/JS)",type:"boolean",default:!1}).example("mfn outline src/app.ts --json","structure of a file in ~50 tokens").example("mfn outline src/app.ts -k function -e --json","just the exported functions"),handler:async e=>{const t=String(e.file),n=I.extname(t).toLowerCase();if(!Ln.includes(n))return $e(e,"UnsupportedType",`"${n||t}" is not outlineable. Supported: ${Ln.join(" ")}`,2);let o;try{o=await E(t,"utf8")}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,"ReadError",n)}let r=function(e,t){const n=Mn[t.toLowerCase()];if(!n)return[];const o=[],r=e.split("\n");for(let e=0;e<r.length;e++){const t=r[e],s=n===An?t.trimStart():t;for(const t of n){const r=t.re.exec(s);if(r?.groups?.name){o.push({line:e+1,kind:t.kind,name:r.groups.name.trim(),exported:Boolean(r.groups.exp)||n!==On});break}}}return o}(o,n);e.kind&&(r=r.filter(t=>t.kind===String(e.kind))),e.exported&&(r=r.filter(e=>e.exported));const s=o.split("\n").length;we(e,{file:t,totalLines:s,count:r.length,symbols:r},()=>{for(const e of r)console.log(`${String(e.line).padStart(5)} ${e.kind.padEnd(9)} ${e.name}`)})}},_n=/(?:import\s[\s\S]*?from\s*|import\s*\(\s*|require\s*\(\s*|export\s[\s\S]*?from\s*)['"]([^'"]+)['"]/g,zn=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs"]),Pn=new Set(["node_modules",".git","dist","build","coverage",".nx"]);function Rn(e){const t=new Set;for(const n of e.matchAll(_n))t.add(n[1]);return[...t]}const Fn={command:"imports [file]",describe:"List a file’s imports, or (--who <module>) every file importing a module",builder:e=>be(e).positional("file",{describe:"Source file to list imports of",type:"string"}).option("who",{alias:"w",describe:"Reverse mode: find files under cwd whose imports contain this string",type:"string"}).example("mfn imports src/app.ts --json","what does this file depend on?").example("mfn imports --who ../utility --json","who imports the utility module?"),handler:async e=>{if(void 0!==e.who){const t=String(e.who);if(!t)return $e(e,"MissingInput","--who needs a module name/substring.",2);const n=process.cwd(),o=[];for(const e of function(e){const t=[],n=e=>{if(t.length>=2e4)return;let o;try{o=O.readdirSync(e,{withFileTypes:!0})}catch{return}for(const r of o){if(Pn.has(r.name))continue;const o=I.join(e,r.name);r.isDirectory()?n(o):r.isFile()&&zn.has(I.extname(r.name))&&t.push(o)}};return n(e),t}(n)){let r;try{r=O.readFileSync(e,"utf8")}catch{continue}const s=Rn(r).filter(e=>e.includes(t));s.length>0&&o.push({file:I.relative(n,e),specifiers:s})}return we(e,{module:t,root:n,count:o.length,importers:o},()=>{for(const e of o)console.log(`${e.file} ← ${e.specifiers.join(", ")}`)})}if(void 0===e.file)return $e(e,"MissingInput","Provide a <file>, or use --who <module>.",2);const t=String(e.file);let n;try{n=await E(t,"utf8")}catch(t){return $e(e,"ReadError",t instanceof Error?t.message:String(t))}const o=Rn(n),r={relative:o.filter(e=>e.startsWith(".")),packages:o.filter(e=>!e.startsWith(".")&&!e.startsWith("node:")),builtin:o.filter(e=>e.startsWith("node:"))};we(e,{file:t,count:o.length,...r},()=>{for(const e of o)console.log(e)})}},Dn=new Set(["node_modules",".git","dist","build","coverage",".nx"]);const Bn={command:"replace <search> <replacement>",describe:"Literal find/replace across files — DRY-RUN by default, --write to apply",builder:e=>be(e).positional("search",{describe:"Literal text to find (not a regex)",type:"string"}).positional("replacement",{describe:"Literal replacement text",type:"string"}).option("glob",{alias:"g",describe:'File glob relative to cwd (e.g. "src/**/*.ts")',type:"string",demandOption:!0}).option("write",{alias:"w",describe:"Actually modify files (default: dry-run report)",type:"boolean",default:!1}).example('mfn replace oldName newName -g "src/**/*.ts" --json',"dry-run: where + how many").example('mfn replace oldName newName -g "src/**/*.ts" -w --json',"apply the replacement"),handler:e=>{const t=String(e.search),n=String(e.replacement);if(""===t)return $e(e,"MissingInput","Search text must not be empty.",2);if(t===n)return $e(e,"NoOp","Search and replacement are identical.",2);const o=process.cwd(),r=function(e){let t="",n=0;for(;n<e.length;){const o=e[n];if("*"===o)if("*"===e[n+1]){const o="/"===e[n+2];t+=o?"(?:.*/)?":".*",n+=o?3:2}else t+="[^/]*",n++;else"?"===o?(t+="[^/]",n++):(t+=/[.+^${}()|[\]\\]/.test(o)?"\\"+o:o,n++)}return new RegExp(`^${t}$`)}(String(e.glob).replace(/^\.\//,"")),s=new RegExp(t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g");const i=[];let a=0;const l=[];for(const c of function(e){const t=[],n=e=>{if(t.length>=1e4)return;let o;try{o=O.readdirSync(e,{withFileTypes:!0})}catch{return}for(const r of o){if(Dn.has(r.name))continue;const o=I.join(e,r.name);r.isDirectory()?n(o):r.isFile()&&t.push(o)}};return n(e),t}(o)){const d=I.relative(o,c).split(I.sep).join("/");if(!r.test(d))continue;let m;try{m=O.openSync(c,e.write?"r+":"r")}catch{continue}try{if(O.fstatSync(m).size>5242880)continue;const o=O.readFileSync(m,"utf8"),r=(o.match(s)??[]).length;if(0===r)continue;if(e.write){const e=o.split(t).join(n);O.ftruncateSync(m,0),O.writeSync(m,e,0,"utf8")}i.push({file:d,count:r}),a+=r}catch(t){e.write&&l.push({file:d,error:t instanceof Error?t.message:String(t)})}finally{O.closeSync(m)}}we(e,{search:t,replacement:n,glob:String(e.glob),mode:e.write?"written":"dry-run",fileCount:i.length,totalReplacements:a,changes:i,errors:l},()=>{console.log(`${e.write?"replaced":"would replace"} ${a} occurrence(s) in ${i.length} file(s)`);for(const e of i)console.log(` ${e.count}× ${e.file}`);!e.write&&i.length&&console.log("re-run with --write to apply")}),l.length>0&&process.exit(1)}},Un=new Set(["node_modules",".git","dist","build","coverage",".nx"]);function Jn(e){const t=Math.round(e/1e3);return t<60?`${t}s ago`:t<3600?`${Math.round(t/60)}m ago`:t<86400?`${Math.round(t/3600)}h ago`:`${Math.round(t/86400)}d ago`}const Wn={command:"recent [dir]",describe:"Most recently modified files under a directory, with age",builder:e=>be(e).positional("dir",{describe:"Directory to scan (default: cwd)",type:"string"}).option("top",{alias:"t",describe:"How many files to return",type:"number",default:10}).option("ignore",{alias:"i",describe:"Additional directory names to ignore",type:"array"}).example("mfn recent --json","what changed last in this project?").example("mfn recent ./src -t 5 --json","five most recent under src"),handler:e=>{const t=Number(e.top);if(!Number.isInteger(t)||t<1||t>1e3)return $e(e,"InvalidTop","--top must be an integer in 1..1000.",2);const n=I.resolve(String(e.dir??process.cwd()));let o;try{o=O.statSync(n)}catch{return $e(e,"NotFound",`Directory not found: ${n}`,2)}if(!o.isDirectory())return $e(e,"NotADirectory",`${n} is not a directory.`,2);const r=new Set([...Un,...(e.ignore??[]).map(String)]),s=[];let i=!1;const a=e=>{if(s.length>=2e5)return void(i=!0);let t;try{t=O.readdirSync(e,{withFileTypes:!0})}catch{return}for(const o of t){if(r.has(o.name))continue;const t=I.join(e,o.name);if(o.isDirectory())a(t);else if(o.isFile())try{const e=O.statSync(t);s.push({path:I.relative(n,t),mtimeMs:e.mtimeMs,bytes:e.size})}catch{}}};a(n);const l=Date.now(),c=s.sort((e,t)=>t.mtimeMs-e.mtimeMs).slice(0,t).map(e=>({path:e.path,bytes:e.bytes,modified:new Date(e.mtimeMs).toISOString(),age:Jn(l-e.mtimeMs)}));we(e,{root:n,fileCount:s.length,truncated:i,files:c},()=>{for(const e of c)console.log(`${e.age.padStart(8)} ${e.path}`)})}};function qn(e){try{return JSON.parse(O.readFileSync(e,"utf8"))}catch{return null}}function Zn(e,t){const n=I.join(e,"node_modules",...t.split("/"),"package.json");return qn(n)?.version??null}function Gn(e,t){if(null===t)return!1;const n=e.replace(/^[\^~>=<]+/,"");return e===t||(!(!/^\d/.test(n)||n!==t)||null)}const Hn={command:"pkg [name]",describe:"Declared vs installed dependency versions — drift and missing installs",builder:e=>be(e).positional("name",{describe:"One dependency to inspect (omit for all)",type:"string"}).example("mfn pkg --json","is node_modules in sync with package.json?").example("mfn pkg typescript --json","one dependency, declared vs actually installed"),handler:e=>{const t=process.cwd(),n=qn(I.join(t,"package.json"));if(!n)return $e(e,"NoPackageJson",`No readable package.json in ${t}`);const o=["dependencies","devDependencies","optionalDependencies","peerDependencies"],r=[];for(const s of o)for(const[o,i]of Object.entries(n[s]??{})){if(void 0!==e.name&&o!==String(e.name))continue;const n=Zn(t,o);r.push({name:o,declared:String(i),section:s,installed:n,satisfiesExact:Gn(String(i),n)})}if(void 0!==e.name&&0===r.length)return $e(e,"NotDeclared",`"${e.name}" is not declared in package.json.`);const s=r.filter(e=>null===e.installed).map(e=>e.name);we(e,{package:n.name??null,version:n.version??null,depCount:r.length,missing:s,allInstalled:0===s.length,deps:r},()=>{for(const e of r){const t=null===e.installed?"✘ missing":e.installed;console.log(`${e.name.padEnd(40)} ${e.declared.padEnd(12)} → ${t}`)}s.length&&console.log(`\n${s.length} not installed — run your installer`)})}};function Vn(e){const t=[];for(const n of e.split("\n")){const e=n.trim();if(!e||e.startsWith("#"))continue;const o=/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/.exec(e);o&&t.push(o[1])}return t}const Yn={command:"dotenv",describe:"Check .env against .env.example — missing/extra keys, values never shown",builder:e=>be(e).option("file",{alias:"f",describe:"Env file to check",type:"string",default:".env"}).option("example",{alias:"e",describe:"Reference file",type:"string",default:".env.example"}).example("mfn dotenv --json","is .env complete vs .env.example?").example("mfn dotenv -f .env.local -e .env.example --json","check a specific pair"),handler:e=>{const t=String(e.file),n=String(e.example);let o=null,r=null;try{o=O.readFileSync(t,"utf8")}catch{}try{r=O.readFileSync(n,"utf8")}catch{}if(null===o&&null===r)return $e(e,"NotFound",`Neither ${t} nor ${n} is readable in ${process.cwd()}.`);const s=null!==o?Vn(o):[],i=null!==r?Vn(r):[],a=new Set(s),l=new Set(i),c=i.filter(e=>!a.has(e)),d=s.filter(e=>!l.has(e)),m=null===r?null:0===c.length;we(e,{file:t,fileExists:null!==o,example:n,exampleExists:null!==r,fileKeyCount:s.length,exampleKeyCount:i.length,missing:c,extra:d,complete:m,note:"values are intentionally never read or returned"},()=>{null===o&&console.log(`${t} does not exist`),null===r&&console.log(`${n} does not exist`),!0===m&&console.log(`✔ ${t} has all ${i.length} keys from ${n}`),c.length&&console.log(`missing: ${c.join(", ")}`),d.length&&console.log(`extra (undocumented): ${d.join(", ")}`)})}},Kn=e=>new Promise(t=>setTimeout(t,e));const Qn={command:"wait",describe:"Block until a port, file, or URL is ready (or timeout) — replaces sleep loops",builder:e=>be(e).option("port",{alias:"p",describe:"TCP port to wait for (on 127.0.0.1)",type:"number"}).option("url",{alias:"u",describe:"Wait until this URL responds 2xx/3xx",type:"string"}).option("file",{alias:"f",describe:"Wait until this file exists",type:"string"}).option("timeout",{alias:"t",describe:"Max seconds to wait",type:"number",default:30}).option("interval",{describe:"Poll interval in ms",type:"number",default:250}).example("mfn wait -p 3000 -t 30 --json","dev server is accepting connections").example("mfn wait -u http://localhost:3000/health --json","health endpoint is green").example("mfn wait -f dist/bin/index.js --json","build artifact exists"),handler:async e=>{if(1!==[e.port,e.url,e.file].filter(e=>void 0!==e).length)return $e(e,"InvalidTarget","Provide exactly one of --port, --url, or --file.",2);const t=Number(e.timeout);if(!Number.isFinite(t)||t<=0||t>600)return $e(e,"InvalidTimeout","--timeout must be 1..600 seconds.",2);const n=Number(e.interval);if(!Number.isInteger(n)||n<50||n>1e4)return $e(e,"InvalidInterval","--interval must be 50..10000 ms.",2);let o,r;if(void 0!==e.port){const t=Number(e.port);if(!Number.isInteger(t)||t<1||t>65535)return $e(e,"InvalidPort","--port must be an integer in 1..65535.",2);o=`port:${t}`,r=()=>function(e,t="127.0.0.1"){return new Promise(n=>{const o=M({port:e,host:t});o.setTimeout(1e3);const r=e=>{o.destroy(),n(e)};o.once("connect",()=>r(!0)),o.once("timeout",()=>r(!1)),o.once("error",()=>r(!1))})}(t)}else if(void 0!==e.url){const t=String(e.url);if(!/^https?:\/\//.test(t))return $e(e,"InvalidURL","--url must start with http:// or https://.",2);try{if(yt(new URL(t)))return $e(e,"BlockedTarget",bt(t),2)}catch{return $e(e,"InvalidURL",`"${t}" is not a valid URL.`,2)}o=`url:${t}`,r=()=>async function(e){try{return(await fetch(e,{method:"GET",signal:AbortSignal.timeout(3e3)})).ok}catch{return!1}}(t)}else{const t=String(e.file);o=`file:${t}`,r=async()=>A(t)}const s=Date.now(),i=s+1e3*t;let a=0;for(;Date.now()<i;){if(a++,await r()){const t=Date.now()-s;return we(e,{target:o,ready:!0,waitedMs:t,attempts:a},()=>console.log(`${o} ready after ${t}ms (${a} checks)`))}await Kn(n)}$e(e,"Timeout",`${o} was not ready within ${t}s (${a} checks).`)}},Xn=w(h),eo="win32"===u();const to={command:"ports",describe:"List ALL listening TCP ports with their owning processes",builder:e=>be(e).option("min",{describe:"Only ports >= this value",type:"number",default:1}).example("mfn ports --json","every listener — which dev servers are running?").example("mfn ports --min 3000 --json","just the app-range ports"),handler:async e=>{const t=Number(e.min);if(!Number.isInteger(t)||t<1||t>65535)return $e(e,"InvalidMin","--min must be an integer in 1..65535.",2);let n;try{n=eo?await async function(){const{stdout:e}=await Xn("netstat",["-ano"],{timeout:1e4}),t=[];for(const n of e.split("\n")){if(!/LISTENING/i.test(n))continue;const e=n.trim().split(/\s+/),o=/^(.*):(\d+)$/.exec(e[1]??"");o&&t.push({port:Number(o[2]),pid:Number(e[e.length-1]),command:null,address:o[1]})}return t}():await async function(){let e;try{({stdout:e}=await Xn("lsof",["-iTCP","-sTCP:LISTEN","-P","-n"],{timeout:1e4}))}catch(e){if(1===e?.code&&!String(e?.stdout??"").trim())return[];throw e}const t=[];for(const n of e.split("\n").slice(1)){const e=n.trim().split(/\s+/);if(e.length<9)continue;const o=e[e.length-2].includes(":")?e[e.length-2]:e[8],r=/^(.*):(\d+)$/.exec(o);r&&t.push({port:Number(r[2]),pid:Number(e[1]),command:e[0],address:r[1]})}return t}()}catch(t){return $e(e,"ListError",`Could not list listeners: ${t instanceof Error?t.message:String(t)}`)}const o=new Map;for(const e of n){if(e.port<t)continue;const n=`${e.port}:${e.pid}`;o.has(n)||o.set(n,e)}const r=[...o.values()].sort((e,t)=>e.port-t.port);we(e,{count:r.length,listeners:r},()=>{for(const e of r)console.log(`${String(e.port).padStart(6)} pid ${String(e.pid).padEnd(8)} ${e.command??""}`)})}},no={command:"http <url>",describe:"Probe a URL: status, headers, timing, capped body preview (never a full dump)",builder:e=>be(e).positional("url",{describe:"URL to probe (scheme optional — http:// assumed)",type:"string"}).option("method",{alias:"m",describe:"HTTP method",type:"string",choices:["GET","HEAD"],default:"GET"}).option("timeout",{alias:"t",describe:"Timeout in seconds",type:"number",default:10}).option("header",{alias:"H",describe:'Request header(s), "Name: value"',type:"array"}).example("mfn http https://api.github.com --json","status + headers + timing").example("mfn http localhost:3000/health --json","is my dev server healthy?"),handler:async e=>{let t,n=String(e.url);/^https?:\/\//.test(n)||(n=`http://${n}`);try{t=new URL(n)}catch{return $e(e,"InvalidURL",`"${e.url}" is not a valid URL.`,2)}if(yt(t))return $e(e,"BlockedTarget",bt(String(t)),2);const o=Number(e.timeout);if(!Number.isFinite(o)||o<=0||o>120)return $e(e,"InvalidTimeout","--timeout must be 1..120 seconds.",2);const r={};for(const t of(e.header??[]).map(String)){const n=t.indexOf(":");if(n<1)return $e(e,"InvalidHeader",`Header "${t}" must be "Name: value".`,2);r[t.slice(0,n).trim()]=t.slice(n+1).trim()}const s=Date.now();let i;try{i=await fetch(t,{method:String(e.method),headers:r,redirect:"follow",signal:AbortSignal.timeout(1e3*o)})}catch(n){return $e(e,"RequestFailed",`${t}: ${n instanceof Error?n.cause?.message||n.message:String(n)}`)}const a=Date.now()-s;let l=null,c=null;if("HEAD"!==String(e.method))try{const e=await i.text();c=Buffer.byteLength(e,"utf8"),l=e.slice(0,2048)}catch{}const d={};i.headers.forEach((e,t)=>{d[t]="set-cookie"===t.toLowerCase()?"[redacted: session cookie]":e}),we(e,{url:i.url,method:String(e.method),status:i.status,statusText:i.statusText,ok:i.ok,redirected:i.redirected,timeMs:a,headers:d,bodyBytes:c,bodyPreview:l,bodyTruncated:null!==c&&c>2048},()=>{console.log(`${i.status} ${i.statusText} (${a}ms) ${i.url}`),console.log(`content-type: ${d["content-type"]??"?"}`),l&&console.log(l.slice(0,500))}),i.ok||process.exit(1)}};const oo={command:"base <value>",describe:"Convert a number between bases (hex/dec/bin/oct) exactly — BigInt, no rounding",builder:e=>be(e).positional("value",{describe:"Number: 0xff, 0b1010, 0o755, or decimal",type:"string"}).option("from",{alias:"f",describe:"Base of an unprefixed input",type:"string",choices:["hex","dec","bin","oct"]}).example("mfn base 0xff --json","hex → all bases").example("mfn base 255 --json","decimal → all bases").example("mfn base ff -f hex --json","unprefixed hex"),handler:e=>{const t=String(e.value);if(t.length>4096)return $e(e,"InputTooLarge","Input exceeds 4096 characters.",2);let n;try{n=function(e,t){const n=e.trim().toLowerCase().replace(/_/g,""),o=n.startsWith("-"),r=o?n.slice(1):n;let s,i;if(r.startsWith("0x")?(s=16,i=r.slice(2)):r.startsWith("0b")?(s=2,i=r.slice(2)):r.startsWith("0o")?(s=8,i=r.slice(2)):(s=t?{hex:16,dec:10,bin:2,oct:8}[t]:10,i=r),!i||!{2:/^[01]+$/,8:/^[0-7]+$/,10:/^[0-9]+$/,16:/^[0-9a-f]+$/}[s].test(i))throw new Error(`"${e}" is not a valid base-${s} number`);let a=0n;const l=BigInt(s);for(const e of i)a=a*l+BigInt(parseInt(e,16));return{value:o?-a:a,detectedBase:s}}(t,e.from?String(e.from):void 0)}catch(t){return $e(e,"InvalidNumber",t instanceof Error?t.message:String(t),2)}const o=n.value,r=o<0n?-o:o,s=o<0n?"-":"";we(e,{input:t,inputBase:n.detectedBase,dec:o.toString(10),hex:`${s}0x${r.toString(16)}`,bin:`${s}0b${r.toString(2)}`,oct:`${s}0o${r.toString(8)}`,bits:r.toString(2).length,exact:!0},()=>{console.log(`dec ${o.toString(10)}`),console.log(`hex ${s}0x${r.toString(16)}`),console.log(`bin ${s}0b${r.toString(2)}`),console.log(`oct ${s}0o${r.toString(8)}`)})}},ro=u(),so=1e6;function io(e,t,n){return new Promise((o,r)=>{const s=h(e,t,{timeout:5e3,maxBuffer:10485760},(e,t)=>e?r(e):o(t));void 0!==n&&s.stdin?.end(n)})}const ao={command:"clip [text]",describe:"Read or write the system clipboard (macOS/Windows/Linux)",builder:e=>be(e).positional("text",{describe:"Text to copy (or pipe stdin); omit to read",type:"string"}).option("read",{alias:"r",describe:"Force read mode even when stdin is piped",type:"boolean",default:!1}).example("mfn clip --json","read the clipboard").example('mfn clip "deploy done" --json',"copy text to the clipboard").example("git diff | mfn clip --json","copy a diff for the user to paste"),handler:async e=>{let t;if(!e.read)if(void 0!==e.text)t=String(e.text);else{const e=await Se();e&&(t=e)}try{if(void 0!==t)return t.length>so?$e(e,"InputTooLarge","Clipboard writes are capped at 1000000 chars.",2):(await async function(e){if("darwin"===ro)await io("pbcopy",[],e);else if("win32"===ro)await io("clip.exe",[],e);else try{await io("xclip",["-selection","clipboard"],e)}catch{await io("wl-copy",[],e)}}(t),we(e,{action:"write",chars:t.length},()=>console.log(`copied ${t.length} chars`)));const n=await async function(){if("darwin"===ro)return io("pbpaste",[]);if("win32"===ro)return io("powershell",["-NoProfile","-Command","Get-Clipboard -Raw"]);try{return await io("xclip",["-selection","clipboard","-o"])}catch{return io("wl-paste",["--no-newline"])}}(),o=ht(n);if(o)return we(e,{action:"read",chars:n.length,text:null,redacted:!0,reason:`clipboard contains a ${o} — content withheld (guardrail)`},()=>console.log(`[redacted: clipboard contains a ${o}]`));we(e,{action:"read",chars:n.length,text:n,redacted:!1},()=>console.log(n))}catch(t){return $e(e,"ClipboardUnavailable",`Clipboard tool failed (headless session? missing xclip/wl-clipboard?): ${t instanceof Error?t.message:String(t)}`)}}},lo=w(h),co=u(),mo=e=>e.replace(/\\/g,"\\\\").replace(/"/g,'\\"');const uo=2e3,po={command:"notify <message>",describe:"Send a desktop notification (macOS/Windows/Linux) — ping the user, hands-free",builder:e=>be(e).positional("message",{describe:"Notification body",type:"string"}).option("title",{alias:"t",describe:"Notification title",type:"string",default:"mfn"}).example('mfn notify "build finished" --json',"tell the user a long task is done").example('mfn notify "3 tests failing" -t "CI watch" --json',"titled notification"),handler:async e=>{const t=String(e.message),n=String(e.title);if(t.length>uo||n.length>uo)return $e(e,"InputTooLarge","Title/message are capped at 2000 chars.",2);try{await async function(e,t){if("darwin"===co){const n=`display notification "${mo(t)}" with title "${mo(e)}"`;await lo("osascript",["-e",n],{timeout:5e3})}else if("win32"===co){const n='$ErrorActionPreference=\'Stop\';[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null;$t=[Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02);$n=$t.GetElementsByTagName("text");$n.Item(0).AppendChild($t.CreateTextNode($env:MFN_NOTIFY_TITLE))|Out-Null;$n.Item(1).AppendChild($t.CreateTextNode($env:MFN_NOTIFY_MESSAGE))|Out-Null;[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("mfn").Show([Windows.UI.Notifications.ToastNotification]::new($t))';await lo("powershell",["-NoProfile","-Command",n],{timeout:1e4,env:{...process.env,MFN_NOTIFY_TITLE:e,MFN_NOTIFY_MESSAGE:t}})}else await lo("notify-send",[e,t],{timeout:5e3})}(n,t)}catch(t){return $e(e,"NotifyFailed",`Could not send a notification (headless session? missing notify-send?): ${t instanceof Error?t.message:String(t)}`)}we(e,{sent:!0,title:n,message:t},()=>console.log("notification sent"))}},fo=w(h),ho=u();const go={command:"open <target>",describe:"Open a file or URL in the default app/browser (validated first)",builder:e=>be(e).positional("target",{describe:"http(s) URL, or an existing file/directory",type:"string"}).example("mfn open https://github.com/Master4Novice/master-cli --json","show the user a page").example("mfn open coverage/index.html --json","open a report you just generated"),handler:async e=>{const t=String(e.target);let n,o=t;if(/^https?:\/\//i.test(t)){try{new URL(t)}catch{return $e(e,"InvalidURL",`"${t}" is not a valid URL.`,2)}n="url"}else{if(/^[a-z][a-z0-9+.-]*:/i.test(t))return $e(e,"UnsupportedScheme","Only http(s) URLs or local paths are allowed.",2);if(o=I.resolve(t),!A(o))return $e(e,"NotFound",`No such file or directory: ${o}`,2);n="file"}try{const t=await async function(e){return"darwin"===ho?(await fo("open",[e],{timeout:1e4}),"open"):"win32"===ho?(await fo("rundll32",["url.dll,FileProtocolHandler",e],{timeout:1e4}),"rundll32"):(await fo("xdg-open",[e],{timeout:1e4}),"xdg-open")}(o);we(e,{opened:!0,kind:n,target:o,opener:t},()=>console.log(`opened ${o}`))}catch(t){const n=t instanceof Error?t.message:String(t);return $e(e,"OpenFailed",`Could not open ${o}: ${n}`)}}},yo=w(h),bo="win32"===u();const vo={command:"procs [pattern]",describe:"Search running processes by name — pid/cpu/mem without ps|grep gymnastics",builder:e=>be(e).positional("pattern",{describe:"Case-insensitive substring of the command name",type:"string"}).option("top",{alias:"t",describe:"Max results (sorted by cpu, then mem)",type:"number",default:25}).example("mfn procs node --json","every node process with pid/cpu/mem").example("mfn procs --json","top 25 by cpu — what is this machine doing?"),handler:async e=>{const t=Number(e.top);if(!Number.isInteger(t)||t<1||t>5e3)return $e(e,"InvalidTop","--top must be an integer in 1..5000.",2);let n;try{n=bo?await async function(){const{stdout:e}=await yo("tasklist",["/FO","CSV","/NH"],{timeout:1e4,maxBuffer:20971520}),t=[];for(const n of e.split("\n")){const e=n.match(/"([^"]*)"/g)?.map(e=>e.slice(1,-1));if(!e||e.length<5)continue;const o=Number(e[4].replace(/[^\d]/g,""));t.push({pid:Number(e[1]),cpu:null,memMB:Number.isFinite(o)?Math.round(o/1024*10)/10:null,command:e[0]})}return t}():await async function(){const{stdout:e}=await yo("ps",["axo","pid=,pcpu=,rss=,comm="],{timeout:1e4,maxBuffer:20971520}),t=[];for(const n of e.split("\n")){const e=/^\s*(\d+)\s+([\d.]+)\s+(\d+)\s+(.+)$/.exec(n);e&&t.push({pid:Number(e[1]),cpu:Number(e[2]),memMB:Math.round(Number(e[3])/1024*10)/10,command:e[4].trim()})}return t}()}catch(t){return $e(e,"ListError",`Could not list processes: ${t instanceof Error?t.message:String(t)}`)}const o=void 0!==e.pattern?String(e.pattern).toLowerCase():null,r=o?n.filter(e=>e.command.toLowerCase().includes(o)):n,s=r.sort((e,t)=>(t.cpu??0)-(e.cpu??0)||(t.memMB??0)-(e.memMB??0)).slice(0,t);we(e,{pattern:o,total:n.length,matched:r.length,processes:s},()=>{for(const e of s){const t=null===e.cpu?" -":`${e.cpu.toFixed(1)}%`.padStart(6);console.log(`${String(e.pid).padStart(7)} ${t} ${String(e.memMB??"-").padStart(8)}M ${e.command}`)}})}},xo=w(h),wo="win32"===u();const $o=e=>e>=1024**4?`${(e/1024**4).toFixed(1)}T`:`${(e/1024**3).toFixed(1)}G`,jo={command:"disk",describe:"Disk usage per mount (total/free/used%) — df parsing done for you",builder:e=>be(e).option("all",{alias:"a",describe:"Include pseudo/small filesystems (< 1GB)",type:"boolean",default:!1}).example("mfn disk --json","is there room for this build?"),handler:async e=>{let t;try{t=wo?await async function(){const{stdout:e}=await xo("powershell",["-NoProfile","-Command","Get-CimInstance Win32_LogicalDisk | Select-Object DeviceID,Size,FreeSpace | ConvertTo-Json"],{timeout:15e3}),t=JSON.parse(e);return(Array.isArray(t)?t:[t]).filter(e=>Number(e.Size)>0).map(e=>({mount:String(e.DeviceID),filesystem:null,totalBytes:Number(e.Size),freeBytes:Number(e.FreeSpace),usedPercent:Math.round((Number(e.Size)-Number(e.FreeSpace))/Number(e.Size)*100)}))}():await async function(){const{stdout:e}=await xo("df",["-kP"],{timeout:1e4}),t=[];for(const n of e.split("\n").slice(1)){const e=n.trim().split(/\s+/);if(e.length<6)continue;const o=1024*Number(e[1]),r=1024*Number(e[3]);Number.isFinite(o)&&0!==o&&t.push({mount:e.slice(5).join(" "),filesystem:e[0],totalBytes:o,freeBytes:r,usedPercent:Math.round((o-r)/o*100)})}return t}()}catch(t){return $e(e,"DiskError",`Could not read disk usage: ${t instanceof Error?t.message:String(t)}`)}e.all||(t=t.filter(e=>e.totalBytes>=1024**3&&!/^\/(dev|proc|sys|run)/.test(e.mount))),t.sort((e,t)=>t.totalBytes-e.totalBytes),we(e,{count:t.length,mounts:t},()=>{for(const e of t)console.log(`${$o(e.totalBytes).padStart(8)} total ${$o(e.freeBytes).padStart(8)} free ${String(e.usedPercent).padStart(3)}% ${e.mount}`)})}},So=w(h),No=u();function ko(e,t){if(!O.existsSync(I.join(e,t)))return t;const n=I.extname(t),o=t.slice(0,t.length-n.length);for(let t=1;;t++){const r=`${o} ${t}${n}`;if(!O.existsSync(I.join(e,r)))return r}}function Eo(e){const t=I.join(p(),".Trash"),n=I.join(t,ko(t,I.basename(e)));return O.renameSync(e,n),n}function Io(e){const t=I.join(p(),".local","share","Trash");O.mkdirSync(I.join(t,"files"),{recursive:!0}),O.mkdirSync(I.join(t,"info"),{recursive:!0});const n=ko(I.join(t,"files"),I.basename(e)),o=(new Date).toISOString().slice(0,19);O.writeFileSync(I.join(t,"info",`${n}.trashinfo`),`[Trash Info]\nPath=${encodeURI(e)}\nDeletionDate=${o}\n`);const r=I.join(t,"files",n);return O.renameSync(e,r),r}async function Oo(e){if(await So("powershell",["-NoProfile","-Command",'$ErrorActionPreference=\'Stop\';Add-Type -AssemblyName Microsoft.VisualBasic;$p=$env:MFN_TRASH_PATH;if (Test-Path -LiteralPath $p -PathType Container) {[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteDirectory($p,"OnlyErrorDialogs","SendToRecycleBin")} else {[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($p,"OnlyErrorDialogs","SendToRecycleBin")}'],{timeout:15e3,env:{...process.env,MFN_TRASH_PATH:e}}),O.existsSync(e))throw new Error("Recycle Bin reported success but the path still exists");return"Recycle Bin"}const Ao={command:"trash <paths...>",describe:"Move files/dirs to the OS trash — reversible, never rm -rf",builder:e=>be(e).positional("paths",{describe:"Files or directories to trash",type:"string"}).example("mfn trash build-old.log --json","recoverable delete").example("mfn trash dist coverage --json","trash multiple paths in one call"),handler:async e=>{const t=e.paths.map(String),n=[],o=[];for(const e of t){const t=I.resolve(e);if(!O.existsSync(t)){o.push({path:t,error:"does not exist"});continue}let r,s,i;try{r=O.realpathSync(t),s=O.realpathSync(process.cwd()),i=O.realpathSync(p())}catch{r=t,s=process.cwd(),i=p()}if(r===I.parse(r).root||r===i||r===s||s.startsWith(r+I.sep))o.push({path:t,error:"refusing to trash root/home/cwd (or a parent of cwd)"});else try{const e="darwin"===No?Eo(t):"win32"===No?await Oo(t):Io(t);n.push({path:t,movedTo:e})}catch(e){o.push({path:t,error:e instanceof Error?e.message:String(e)})}}if(0===n.length&&o.length>0)return $e(e,"TrashFailed",o.map(e=>`${e.path}: ${e.error}`).join("; "));we(e,{trashed:n,failed:o,count:n.length},()=>{for(const e of n)console.log(`trashed ${e.path}`);for(const e of o)console.error(`failed ${e.path}: ${e.error}`)}),o.length>0&&process.exit(1)}},To=async e=>{try{return await e}catch{return null}},Mo={command:"dns <hostname>",describe:"Resolve a hostname: A/AAAA/CNAME/MX/TXT/NS in one call (no dig parsing)",builder:e=>be(e).positional("hostname",{describe:"Hostname to resolve",type:"string"}).option("type",{alias:"t",describe:"Single record type instead of the full sweep",type:"string",choices:["a","aaaa","cname","mx","txt","ns"]}).example("mfn dns github.com --json","all common records at once").example("mfn dns example.com -t mx --json","just the MX records"),handler:async e=>{const t=String(e.hostname).trim().toLowerCase();if(!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/.test(t))return $e(e,"InvalidHostname",`"${e.hostname}" is not a valid hostname.`,2);if(e.type){const n=String(e.type),o={a:()=>C(t),aaaa:()=>_(t),cname:()=>z(t),mx:()=>P(t),txt:()=>R(t),ns:()=>F(t)};try{const r=await o[n]();return we(e,{hostname:t,type:n,records:r},()=>console.log(JSON.stringify(r,null,2)))}catch(o){const r=o instanceof Error?o.message:String(o);return $e(e,"ResolveFailed",`${n.toUpperCase()} lookup for ${t}: ${r}`)}}const[n,o,r,s,i,a,l]=await Promise.all([To(L(t)),To(C(t)),To(_(t)),To(z(t)),To(P(t)),To(R(t)),To(F(t))]);if(!(n||o||r||s))return $e(e,"ResolveFailed",`${t} did not resolve (no A/AAAA/CNAME).`);we(e,{hostname:t,resolved:n?{address:n.address,family:`IPv${n.family}`}:null,a:o,aaaa:r,cname:s,mx:i,txt:a?a.map(e=>e.join("")):null,ns:l},()=>{n&&console.log(`${t} → ${n.address}`),o&&console.log(`A ${o.join(", ")}`),r&&console.log(`AAAA ${r.join(", ")}`),i&&console.log(`MX ${i.map(e=>`${e.priority} ${e.exchange}`).join(", ")}`),l&&console.log(`NS ${l.join(", ")}`)})}},Lo=2e5,Co={update:"installs npm packages globally — not exposed to MCP clients",mcp:"starting a server inside the server is never what you want"},_o=oe.map(e=>e.name).filter(e=>!(e in Co)),zo=[{name:"mfn_capabilities",description:"Machine-readable manifest of every mfn command (name, category, summary, examples). Call this first to discover what mfn can do.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"mfn_run",description:'Run one mfn command headlessly and return its single JSON result object. `command` is a name from mfn_capabilities (e.g. "epoch"); `args` are the documented CLI flags/positionals (e.g. ["1622547800"] or ["-f","data.json"]). `--json` is added automatically. Security guardrails are always on.',inputSchema:{type:"object",properties:{command:{type:"string",description:"Command name from mfn_capabilities",enum:_o},args:{type:"array",items:{type:"string"},description:"CLI arguments exactly as documented (flags and positionals)"}},required:["command"],additionalProperties:!1}},{name:"mfn_help",description:"Full --help text (flags, examples) for one mfn command.",inputSchema:{type:"object",properties:{command:{type:"string",description:"Command name from mfn_capabilities"}},required:["command"],additionalProperties:!1}}],Po=e=>new Promise(t=>{h(process.execPath,[process.argv[1],...e],{timeout:12e4,maxBuffer:8388608,windowsHide:!0},(e,n)=>{const o=e?"number"==typeof e.code?e.code:1:0;t({code:o,stdout:String(n??"")})})}),Ro=(e,t)=>{const n=e.length>Lo?e.slice(0,Lo)+"\n[truncated at 200000 chars]":e,o={content:[{type:"text",text:n}],isError:t};try{const e=JSON.parse(n);e&&"object"==typeof e&&!Array.isArray(e)&&(o.structuredContent=e)}catch{}return o},Fo=e=>({content:[{type:"text",text:JSON.stringify({ok:!1,error:"McpToolError",message:e})}],isError:!0});const Do="2025-06-18",Bo=e=>{process.stdout.write(JSON.stringify(e)+"\n")},Uo=(e,t)=>Bo({jsonrpc:"2.0",id:e,result:t}),Jo=(e,t,n)=>Bo({jsonrpc:"2.0",id:e,error:{code:t,message:n}});async function Wo(e){const{id:t,method:n,params:o}=e??{},r=null!=t;if("string"==typeof n){if(!n.startsWith("notifications/"))switch(n){case"initialize":{const e=o?.protocolVersion;return void Uo(t,{protocolVersion:"string"==typeof e?e:Do,capabilities:{tools:{}},serverInfo:{name:se,version:ie},instructions:`Wraps the mfn CLI (${oe.length} headless commands). Call mfn_capabilities first to discover commands, then mfn_run {command, args} to execute one — every result is a single JSON object ({ok:true,...} or {ok:false,error,message}). mfn_help returns per-command flags. Security guardrails (sensitive-path refusal, secret redaction, reversible deletes) are always on; \`update\` is not exposed.`})}case"ping":return void Uo(t,{});case"tools/list":return void Uo(t,{tools:zo});case"tools/call":{const e=String(o?.name??"");return zo.some(t=>t.name===e)?void Uo(t,await async function(e,t){if("mfn_capabilities"===e){const e=await Po(["capabilities","--json"]);return Ro(e.stdout.trim(),0!==e.code)}if("mfn_help"===e){const e=String(t?.command??"");if(!oe.some(t=>t.name===e))return Fo(`Unknown command "${e}". Call mfn_capabilities for the list.`);const n=await Po([e,"--help"]);return Ro(n.stdout.trim(),0!==n.code)}if("mfn_run"===e){const e=String(t?.command??"");if(e in Co)return Fo(`"${e}" is not available over MCP: ${Co[e]}.`);if(!oe.some(t=>t.name===e))return Fo(`Unknown command "${e}". Call mfn_capabilities for the list.`);const n=t?.args??[];if(!Array.isArray(n)||n.length>64)return Fo('"args" must be an array of at most 64 strings.');const o=n.map(String);if(o.some(e=>e.length>1e4||e.includes("\0")))return Fo("Each argument must be under 10000 chars with no NUL bytes.");const r=await Po([e,...o,"--json"]),s=r.stdout.trim();return s?Ro(s,0!==r.code):Fo(`"${e}" produced no output (exit ${r.code}).`)}return Fo(`Unknown tool "${e}".`)}(e,o?.arguments??{})):void Jo(t,-32602,`Unknown tool "${e}"`)}default:r&&Jo(t,-32601,`Method not found: ${n}`)}}else r&&Jo(t,-32600,"Invalid request: no method")}const qo={command:"mcp",describe:"Serve every mfn command over the Model Context Protocol (stdio) — for MCP clients without shell access",builder:e=>be(e).example("mfn mcp","start the MCP server (stdio, JSON-RPC per line)").example("mfn mcp --json","describe the server + client wiring (does not start it)"),handler:async e=>{e.json?we(e,{transport:"stdio",protocolVersion:Do,tools:zo.map(e=>e.name),commands:_o.length,denied:Object.keys(Co),clientConfig:{command:"npx",args:["-y","@master4n/master-cli","mcp"]},note:"Run `mfn mcp` (no flags) to start the server."},()=>{}):await async function(){process.stderr.write(`${se} v${ie} — MCP server ready (stdio)\n`);const e=D({input:process.stdin,crlfDelay:1/0}),t=new Set;for await(const n of e){const e=n.trim();if(!e)continue;let o;try{o=JSON.parse(e)}catch{Jo(null,-32700,"Parse error: messages must be one JSON object per line");continue}const r=Wo(o).catch(e=>{const t=e instanceof Error?e.message:String(e);Jo(o?.id??null,-32603,`Internal error: ${t}`)}).finally(()=>t.delete(r));t.add(r)}await Promise.allSettled([...t]),process.exit(0)}()}};function Zo(e,t,n){if(Math.abs(e.length-t.length)>n)return n+1;let o=Array.from({length:t.length+1},(e,t)=>t);for(let r=1;r<=e.length;r++){const s=[r];let i=r;for(let n=1;n<=t.length;n++)s[n]=Math.min(o[n]+1,s[n-1]+1,o[n-1]+(e[r-1]===t[n-1]?0:1)),i=Math.min(i,s[n]);if(i>n)return n+1;o=s}return o[t.length]}const Go=e=>function(e){return{add:(t,n,o,r)=>{e.command({command:t,describe:n,builder:o,handler:r})}}}(ge).add(e.command,e.describe,e.builder,e.handler);Go(rt),Go(qo),Go(at),Go(xt),Go($t),Go(St),Go(Ge),Go(Je),Go(Re),Go(It),Go(In),Go(At),Go(Tt),Go(cn),Go(vn),Go(Qt),Go(kn),Go(Jt),Go(Gt),Go(an),Go(xn),Go(wn),Go(Cn),Go(Fn),Go(Bn),Go(Wn),Go(Hn),Go(Yn),Go(oo),Go(Et),Go(to),Go(et),Go(Qn),Go(no),Go(_e),Go(Ae),Go(zt),Go(Pt),Go(Dt),Go(pn),Go(gn),Go(bn),Go($n),Go(ao),Go(po),Go(go),Go(vo),Go(jo),Go(Ao),Go(Mo),Go(ot),ge.usage("mfn <command> [options]\n\nMaster CLI for developers and AI agents — headless, JSON-first commands that\nreplace boilerplate agents regenerate on every machine. Every command supports\n--json (machine output) and -h/--help (this text).").version(ie).alias("version","v").help().alias("help","h").epilogue("Discover every command (machine-readable): mfn capabilities --json\nAgent contract & examples: see llms.txt in this package.\nDocs: https://github.com/Master4Novice/master-cli#readme").wrap(null).strict().demandCommand(1,"No command given. Run `mfn capabilities` to list commands.").fail((e,t)=>{t&&Ne("CommandError",t.message||String(t),1),Ne("UsageError",function(e){const t=/^Unknown arguments?: (.+)$/.exec(e);if(!t)return e;const n=t[1].split(",").map(e=>e.trim()),o=process.argv.slice(2).find(e=>!e.startsWith("-")),r=n.find(e=>e===o);if(!r)return e;let s=null,i=3;for(const e of oe){const t=Zo(r,e.name,i);t<i&&(i=t,s=e.name)}return`Unknown command: ${r}.${s?` Did you mean "${s}"?`:""} Run \`mfn capabilities\` to list commands.`}(e||"Invalid command invocation."),2)}).parse();
|
|
36
36
|
//# sourceMappingURL=index.js.map
|