@stacksjs/cli 0.75.431 → 0.75.439

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 CHANGED
@@ -390,3 +390,21 @@ Many thanks to the following core technologies & people who have contributed to
390
390
  The MIT License (MIT). Please see [LICENSE](https://github.com/stacksjs/stacks/tree/main/LICENSE.md) for more information.
391
391
 
392
392
  Made with 💙
393
+
394
+ ## Native owned processes
395
+
396
+ `spawnOwnedProcess` from `@stacksjs/cli/owned-process` is a lightweight subpath
397
+ with no CLI bootstrap. It starts a controlled Bun owner, establishes a POSIX
398
+ process group or a Windows Job Object, then admits the requested command.
399
+ The owner clears `BUN_OPTIONS` and `NODE_OPTIONS`; the original command
400
+ environment is restored over the private IPC admission channel, never embedded
401
+ in owner argv. `started` resolves to the command PID. `exited` preserves its code and signal
402
+ and settles after descendant disposal. Consumer IPC is enabled only when an
403
+ `ipc` callback is requested; the native channel drains before exit is reported.
404
+ `stop()` is idempotent. Standard I/O and
405
+ consumer IPC are forwarded without executing a shell.
406
+
407
+ A caller inside a compiled CLI passes the installed Bun path as `ownerRuntime`.
408
+ POSIX children that deliberately leave their group are outside the contract;
409
+ this is lifecycle ownership rather than a sandbox. A native capability failure
410
+ rejects instead of weakening cleanup to the direct child.
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import Ye from"process";async function De(e,t={silent:!0}){let n=t.packageManage
4
4
  `);throw Error(`Command failed with exit code ${r.exitCode}: ${n.join(" ")}
5
5
  ${a}`)}return o}function Ke(e,t,n,r,o){if(b.debug(`exitHandler: ${e}, exitCode: ${n}, signalCode: ${r}`),o)b.debug("Process error:",o.message)}import{handleError as Et}from"@stacksjs/error-handling";import{log as b}from"@stacksjs/logging";import{ExitCode as Ae}from"@stacksjs/types";import{collect as vt}from"@stacksjs/collections";var g=!process.env.NO_COLOR&&(process.env.FORCE_COLOR?process.env.FORCE_COLOR!=="0":!!process.stdout?.isTTY),d={reset:g?"\x1B[0m":"",black:g?"\x1B[30m":"",red:g?"\x1B[31m":"",green:g?"\x1B[32m":"",yellow:g?"\x1B[33m":"",blue:g?"\x1B[34m":"",magenta:g?"\x1B[35m":"",cyan:g?"\x1B[36m":"",white:g?"\x1B[37m":"",gray:g?"\x1B[90m":"",lightRed:g?"\x1B[91m":"",lightGreen:g?"\x1B[92m":"",lightYellow:g?"\x1B[93m":"",lightBlue:g?"\x1B[94m":"",lightMagenta:g?"\x1B[95m":"",lightCyan:g?"\x1B[96m":"",lightGray:g?"\x1B[37m":"",bgBlack:g?"\x1B[40m":"",bgRed:g?"\x1B[41m":"",bgGreen:g?"\x1B[42m":"",bgYellow:g?"\x1B[43m":"",bgBlue:g?"\x1B[44m":"",bgMagenta:g?"\x1B[45m":"",bgCyan:g?"\x1B[46m":"",bgWhite:g?"\x1B[47m":"",bgGray:g?"\x1B[100m":"",bgLightRed:g?"\x1B[101m":"",bgLightGreen:g?"\x1B[102m":"",bgLightYellow:g?"\x1B[103m":"",bgLightBlue:g?"\x1B[104m":"",bgLightMagenta:g?"\x1B[105m":"",bgLightCyan:g?"\x1B[106m":"",bgLightGray:g?"\x1B[47m":"",bold:g?"\x1B[1m":"",dim:g?"\x1B[2m":"",italic:g?"\x1B[3m":"",underline:g?"\x1B[4m":"",inverse:g?"\x1B[7m":"",hidden:g?"\x1B[8m":"",strikethrough:g?"\x1B[9m":""},V="\x1B[",Ft="\x1B]8;;",St="\x1B]8;;\x07",Ue=(e)=>String(e);function O(e,t,n){return Math.min(Math.max(Math.floor(e),t),n)}function u(e,t=d.reset){return(n)=>{if(!g)return String(n);return`${e}${String(n)}${t}`}}function Bt(e){return e.replace(/\x1B\]8;;[^\x07]*(?:\x07|\x1B\\)/g,"").replace(/\x1B\]8;;(?:\x07|\x1B\\)/g,"")}function E(e){return Bt(e).replace(/\x1B\[[0-?]*[ -/]*[@-~]/g,"")}var He=E;function Ve(e){return Array.from(E(e)).length}var se=u(d.black),ae=u(d.red),P=u(d.green),le=u(d.yellow),ce=u(d.blue),ue=u(d.magenta),G=u(d.cyan),ge=u(d.white),L=u(d.gray),de=u(d.lightRed),me=u(d.lightGreen),fe=u(d.lightYellow),pe=u(d.lightBlue),he=u(d.lightMagenta),be=u(d.lightCyan),U=u(d.lightGray),ye=u(d.bgBlack),Ce=u(d.bgRed),xe=u(d.bgGreen),we=u(d.bgYellow),ke=u(d.bgBlue),$e=u(d.bgMagenta),N=u(d.bgCyan),ve=u(d.bgWhite),Fe=u(d.bgGray),Se=u(d.bgLightRed),Be=u(d.bgLightGreen),Oe=u(d.bgLightYellow),Le=u(d.bgLightBlue),Re=u(d.bgLightMagenta),Ie=u(d.bgLightCyan),H=u(d.bgLightGray),F=u(d.bold),R=u(d.dim),k=u(d.italic),Me=u(d.underline),Ee=u(d.inverse),Te=u(d.hidden),Pe=u(d.strikethrough),Ge=u(d.reset,"");function Je(e){return u(`${V}38;5;${O(e,0,255)}m`)}function Qe(e){return u(`${V}48;5;${O(e,0,255)}m`)}function Xe(e,t,n){return u(`${V}38;2;${O(e,0,255)};${O(t,0,255)};${O(n,0,255)}m`)}function Ze(e,t,n){return u(`${V}48;2;${O(e,0,255)};${O(t,0,255)};${O(n,0,255)}m`)}function et(e,t){let n=(o,i)=>{let a=String(o);if(!g)return a;return`${Ft}${i}\x07${a}${St}`};if(typeof t==="string")return n(e,t);let r=String(e);return(o)=>n(o,r)}var Ot={black:se,red:ae,green:P,yellow:le,blue:ce,magenta:ue,cyan:G,white:ge,gray:L,lightRed:de,lightGreen:me,lightYellow:fe,lightBlue:pe,lightMagenta:he,lightCyan:be,lightGray:U,bgBlack:ye,bgRed:Ce,bgGreen:xe,bgYellow:we,bgBlue:ke,bgMagenta:$e,bgCyan:N,bgWhite:ve,bgGray:Fe,bgLightRed:Se,bgLightGreen:Be,bgLightYellow:Oe,bgLightBlue:Le,bgLightMagenta:Re,bgLightCyan:Ie,bgLightGray:H,bold:F,dim:R,italic:k,underline:Me,inverse:Ee,hidden:Te,strikethrough:Pe,reset:Ge};function tt(e){return Ot[e]??Ue}function $r(e,t){if(typeof t==="function")return t(e);return tt(t)(e)}function Lt(){return g}var vr={black:se,red:ae,green:P,yellow:le,blue:ce,magenta:ue,cyan:G,white:ge,gray:L,lightRed:de,lightGreen:me,lightYellow:fe,lightBlue:pe,lightMagenta:he,lightCyan:be,lightGray:U,bgBlack:ye,bgRed:Ce,bgGreen:xe,bgYellow:we,bgBlue:ke,bgMagenta:$e,bgCyan:N,bgWhite:ve,bgGray:Fe,bgLightRed:Se,bgLightGreen:Be,bgLightYellow:Oe,bgLightBlue:Le,bgLightMagenta:Re,bgLightCyan:Ie,bgLightGray:H,bold:F,dim:R,italic:k,underline:Me,inverse:Ee,hidden:Te,strikethrough:Pe,reset:Ge,ansi256:Je,ansi256Bg:Qe,trueColor:Xe,trueColorBg:Ze,link:et,stripColors:He},Fr={black:se,red:ae,green:P,yellow:le,blue:ce,magenta:ue,cyan:G,white:ge,gray:L,lightRed:de,lightGreen:me,lightYellow:fe,lightBlue:pe,lightMagenta:he,lightCyan:be,lightGray:U,bgBlack:ye,bgRed:Ce,bgGreen:xe,bgYellow:we,bgBlue:ke,bgMagenta:$e,bgCyan:N,bgWhite:ve,bgGray:Fe,bgLightRed:Se,bgLightGreen:Be,bgLightYellow:Oe,bgLightBlue:Le,bgLightMagenta:Re,bgLightCyan:Ie,bgLightGray:H,bold:F,dim:R,italic:k,underline:Me,inverse:Ee,hidden:Te,strikethrough:Pe,reset:Ge,ansi256:Je,ansi256Bg:Qe,trueColor:Xe,trueColorBg:Ze,link:et,stripColors:He,grey:L,lightGrey:U,bgLightGrey:H,supportsColor:Lt};function Rt(e,t,n,r){let o=Ve(e);if(o>=t)return e;let i=r[0]||" ",a=t-o;if(n==="right")return`${i.repeat(a)}${e}`;if(n==="center"){let l=Math.floor(a/2),s=a-l;return`${i.repeat(l)}${e}${i.repeat(s)}`}return`${e}${i.repeat(a)}`}function J(e){return Math.max(0,...e.map(Ve))}function Q(e,t,n="left"){let r=String(e).split(/\r?\n/),o=typeof t==="object"?t:void 0,i=typeof t==="number"?t:o?.width??J(r),a=o?.align??n,l=o?.padChar??" ";return r.map((s)=>Rt(s,Math.max(0,i),a,l)).join(`
6
6
  `)}function Sr(e,t){return Q(e,t,"left")}function Br(e,t){let n=String(e).split(/\r?\n/);return Q(e,t??process.stdout?.columns??J(n),"right")}function Or(e,t){let n=String(e).split(/\r?\n/);return Q(e,t??process.stdout?.columns??J(n),"center")}var It={single:{topLeft:"\u250C",topRight:"\u2510",bottomLeft:"\u2514",bottomRight:"\u2518",horizontal:"\u2500",vertical:"\u2502"},double:{topLeft:"\u2554",topRight:"\u2557",bottomLeft:"\u255A",bottomRight:"\u255D",horizontal:"\u2550",vertical:"\u2551"},round:{topLeft:"\u256D",topRight:"\u256E",bottomLeft:"\u2570",bottomRight:"\u256F",horizontal:"\u2500",vertical:"\u2502"}};function rt(e,t={}){let n=String(e).split(/\r?\n/),r=It[t.borderStyle??"single"],o=Math.max(0,t.padding??1),i=Math.max(0,t.margin??0),a=t.align??"left",l=J(n),s=l+o*2,c=typeof t.borderColor==="function"?t.borderColor:t.borderColor?tt(t.borderColor):Ue,C=c((()=>{if(!t.title)return`${r.topLeft}${r.horizontal.repeat(s)}${r.topRight}`;let x=` ${E(String(t.title))} `.slice(0,s),S=r.horizontal.repeat(Math.max(0,s-x.length));return`${r.topLeft}${x}${S}${r.topRight}`})()),h=c(`${r.bottomLeft}${r.horizontal.repeat(s)}${r.bottomRight}`),y=n.map((p)=>{let x=Q(p,{align:a,width:l}),S=`${" ".repeat(o)}${x}${" ".repeat(o)}`;return`${c(r.vertical)}${S}${c(r.vertical)}`}),w=" ".repeat(i);return[C,...y,h].map((p)=>`${w}${p}`).join(`
7
- `)}var Lr=vt(["The best way to get started is to quit talking and begin doing.","The pessimist sees difficulty in every opportunity. The optimist sees opportunity in every difficulty.","Don\u2019t let yesterday take up too much of today.","You learn more from failure than from success. Don\u2019t let it stop you. Failure builds character.","It\u2019s not whether you get knocked down, it\u2019s whether you get up.","If you are working on something that you really care about, you don\u2019t have to be pushed. The vision pulls you.","People who are crazy enough to think they can change the world, are the ones who do.","Failure will never overtake me if my determination to succeed is strong enough.","Entrepreneurs are great at dealing with uncertainty and also very good at minimizing risk. That\u2019s the classic entrepreneur.","We may encounter many defeats but we must not be defeated.","Knowing is not enough; we must apply. Wishing is not enough; we must do.","Imagine your life is perfect in every respect; what would it look like?","We generate fears while we sit. We overcome them by action.","Whether you think you can or think you can\u2019t, you\u2019re right.","Security is mostly a superstition. Life is either a daring adventure or nothing."]);var nt="0.75.431";async function Ar(e,t){return new Promise((n)=>{if(t?.quiet===!1)console.log(),console.log(G(F("Stacks CLI"))+R(` v${nt}`)),console.log();if(b.info(`Running ${N(k(F(` ${e} `)))}`),t?.showPerformance===!1||t?.quiet)return n(0);return n(performance.now())})}function jr(e,t,n){let r={type:"success",useSeconds:!0,...t};return r.message=t?.message||e,new Promise((o)=>{if(n)return Et(n),o(Ae.FatalError);if(r?.startTime){let i=performance.now()-r.startTime;if(r.useSeconds)i=i/1000,i=Math.round(i*100)/100;if(r.quiet===!0)return o(Ae.Success);if(n)b.error(`[${i.toFixed(2)}${r.useSeconds?"s":"ms"}] Failed`);else if(r.type==="error")b.error(`[${i.toFixed(2)}${r.useSeconds?"s":"ms"}] ${r.message??"Failed"}`);else if(r.type==="warning")b.warn(`[${i.toFixed(2)}${r.useSeconds?"s":"ms"}] ${r.message??"Complete"}`);else if(r.type==="info")b.info(`${R(L(`[${i.toFixed(2)}${r.useSeconds?"s":"ms"}]`))} ${r.message??"Complete"}`);else b.success(`${R(L(F(`[${i.toFixed(2)}${r.useSeconds?"s":"ms"}]`)))} ${F(P(r.message??"Complete"))}`)}else if(r?.type==="info")b.info(e);else if(r?.type==="error")b.error(e);else if(r?.type==="warning")b.warn(e);else if(r?.type==="success"&&r?.quiet!==!0)b.success(e);b.flush().catch(()=>{}).then(()=>o(Ae.Success))})}import X from"process";function ot(e){if(!e)return!1;return e.startsWith("--")}function Tt(e){return e.startsWith("-")&&!ot(e)}function je(e){if(e==="true")return!0;if(e==="false")return!1;let t=Number.parseFloat(e);if(!Number.isNaN(t))return t;return e.replace(/"/g,"")}function Pt(e,t,n,r){let[o,i]=e.slice(2).split("=");if(i!==void 0)r[o]=je(i);else if(n+1<t.length&&!t[n+1]?.startsWith("-"))r[o]=t[n+1],n++;else r[o]=!0;return n}function Gt(e,t,n,r){let[o,i]=e.slice(1).split("=");if(o===void 0)return n;if(i!==void 0&&o!==void 0)for(let a=0;a<o.length;a++)r[o[a]]=je(i);else for(let a=0;a<o.length;a++)if(n+1<t.length&&a===o.length-1&&!t[n+1]?.startsWith("-"))r[o[a]]=je(t[n+1]),n++;else r[o[a]]=!0;return n}function At(e){if(e===void 0)e=X.argv.slice(2);let t=[],n={};for(let r=0;r<e.length;r++){let o=e[r];if(!o)continue;if(ot(o))r=Pt(o,e,r,n);else if(Tt(o))r=Gt(o,e,r,n);else t.push(o)}return{args:t,options:n}}function Dr(e){if(e===void 0)e=X.argv.slice(2);return At(e).args}function zr(e){e=e||{};let t={dryRun:!1,quiet:!1,verbose:!1},n=X.argv.slice(2);for(let r=0;r<n.length;r++){let o=n[r];if(o?.startsWith("--")){let a=o.substring(2).replace(/-([a-z])/gi,(l)=>l[1]?l[1].toUpperCase():"");if(r+1<n.length&&!n?.[r+1]?.startsWith("--"))if(n?.[r+1]==="true"||n?.[r+1]==="false")e[a]=n[r+1]==="true",r++;else e[a]=n[r+1],r++;else e[a]=!0}}if(Object.keys(e).length===0)return{};return{...t,...e}}function jt(e){let t=[];for(let[n,r]of Object.entries(e)){if(n==="--"||n==="_"||n==="forwardSignals"||r===!1||r===void 0||r===null)continue;if(typeof r==="object"&&!Array.isArray(r))continue;if(typeof r==="function"||typeof r==="symbol")continue;if(r===!0)t.push(`--${n}`);else t.push(`--${n}`,String(r))}return t}function Nt(e){if(Array.isArray(e)){if(e=Array.from(new Set(e)),Array.isArray(e)&&e[0]&&!e[0].startsWith("-"))e.shift();return e.join(" ")}if(typeof e==="object"&&e!==null)return jt(e).join(" ");return Nt(X.argv.slice(2))}async function qr(e,t){if(!Number.isSafeInteger(t.timeoutMs)||t.timeoutMs<1||t.timeoutMs>120000)throw Error("Invalid bounded process timeout");for(let f of[t.stdoutBytes,t.stderrBytes])if(!Number.isSafeInteger(f)||f<1||f>2000000)throw Error("Invalid bounded process output limit");let n=t.signal;if(n!==void 0&&!(n instanceof AbortSignal))throw TypeError("Invalid bounded process signal");let r=()=>Error(`${t.label} canceled`,{cause:n?.reason});if(n?.aborted)throw r();let o=process.platform!=="win32",i=Bun.spawn(e,{cwd:t.cwd,env:t.env??process.env,stdin:"ignore",stdout:"pipe",stderr:"pipe",detached:o}),a=[i.stdout.getReader(),i.stderr.getReader()],l=[],s,c=!1,m=!1,C="failed",h=[];function y(f){if(f?.code!=="ESRCH")h.push(f)}function w(){if(o)try{process.kill(-i.pid,"SIGKILL")}catch(f){y(f)}if(i.exitCode===null)try{i.kill("SIGKILL")}catch(f){y(f)}}function p(f,I="failed"){if(!c)s=f,c=!0,C=I;if(m)return;m=!0,w();for(let M of a)l.push(M.cancel().catch((z)=>{h.push(z)}))}let x=()=>p(r(),"canceled");async function S(f,I,M){let z=[],te=0;try{while(!0){let{done:_,value:re}=await f.read();if(_){let j=Buffer.concat(z,te);return t.strictUtf8===!0?new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(j):j.toString("utf8")}if(re.byteLength>I-te){let j=Error(`${t.label} ${M} exceeds byte limit`);throw p(j,`${M} exceeds byte limit`),j}te+=re.byteLength,z.push(re)}}catch(_){throw p(_,`${M} read failed`),_}}let mt=setTimeout(()=>p(Error(`${t.label} timed out`),"timed out"),t.timeoutMs),Ne=S(a[0],t.stdoutBytes,"stdout"),We=S(a[1],t.stderrBytes,"stderr");try{if(n?.addEventListener("abort",x,{once:!0}),n?.aborted)x();let[f,I,M]=await Promise.all([i.exited,Ne,We]);if(c)throw s;return{exitCode:f,stdout:I,stderr:M}}catch(f){throw p(f),s}finally{try{n?.removeEventListener("abort",x)}catch(f){h.push(f)}if(clearTimeout(mt),!m)w();if(i.exitCode===null)p(Error(`${t.label} interrupted`));await Promise.allSettled([i.exited,Ne,We,...l]);for(let f of a)try{f.releaseLock()}catch(I){h.push(I)}if(h.length)throw AggregateError(c?[s,...h]:h,`${t.label} ${c?`${C}; `:""}process cleanup failed`)}}import{writeSync as Wt}from"fs";import{format as Z}from"util";function Vr(...e){st(1,Z(...e))}function Jr(...e){st(2,Z(...e))}async function Qr(...e){await it(process.stdout,Z(...e))}async function Xr(...e){await it(process.stderr,Z(...e))}function it(e,t){return new Promise((n,r)=>{let o=(i)=>{e.off("error",o),r(i)};e.once("error",o);try{e.write(`${t}
7
+ `)}var Lr=vt(["The best way to get started is to quit talking and begin doing.","The pessimist sees difficulty in every opportunity. The optimist sees opportunity in every difficulty.","Don\u2019t let yesterday take up too much of today.","You learn more from failure than from success. Don\u2019t let it stop you. Failure builds character.","It\u2019s not whether you get knocked down, it\u2019s whether you get up.","If you are working on something that you really care about, you don\u2019t have to be pushed. The vision pulls you.","People who are crazy enough to think they can change the world, are the ones who do.","Failure will never overtake me if my determination to succeed is strong enough.","Entrepreneurs are great at dealing with uncertainty and also very good at minimizing risk. That\u2019s the classic entrepreneur.","We may encounter many defeats but we must not be defeated.","Knowing is not enough; we must apply. Wishing is not enough; we must do.","Imagine your life is perfect in every respect; what would it look like?","We generate fears while we sit. We overcome them by action.","Whether you think you can or think you can\u2019t, you\u2019re right.","Security is mostly a superstition. Life is either a daring adventure or nothing."]);var nt="0.75.439";async function Ar(e,t){return new Promise((n)=>{if(t?.quiet===!1)console.log(),console.log(G(F("Stacks CLI"))+R(` v${nt}`)),console.log();if(b.info(`Running ${N(k(F(` ${e} `)))}`),t?.showPerformance===!1||t?.quiet)return n(0);return n(performance.now())})}function jr(e,t,n){let r={type:"success",useSeconds:!0,...t};return r.message=t?.message||e,new Promise((o)=>{if(n)return Et(n),o(Ae.FatalError);if(r?.startTime){let i=performance.now()-r.startTime;if(r.useSeconds)i=i/1000,i=Math.round(i*100)/100;if(r.quiet===!0)return o(Ae.Success);if(n)b.error(`[${i.toFixed(2)}${r.useSeconds?"s":"ms"}] Failed`);else if(r.type==="error")b.error(`[${i.toFixed(2)}${r.useSeconds?"s":"ms"}] ${r.message??"Failed"}`);else if(r.type==="warning")b.warn(`[${i.toFixed(2)}${r.useSeconds?"s":"ms"}] ${r.message??"Complete"}`);else if(r.type==="info")b.info(`${R(L(`[${i.toFixed(2)}${r.useSeconds?"s":"ms"}]`))} ${r.message??"Complete"}`);else b.success(`${R(L(F(`[${i.toFixed(2)}${r.useSeconds?"s":"ms"}]`)))} ${F(P(r.message??"Complete"))}`)}else if(r?.type==="info")b.info(e);else if(r?.type==="error")b.error(e);else if(r?.type==="warning")b.warn(e);else if(r?.type==="success"&&r?.quiet!==!0)b.success(e);b.flush().catch(()=>{}).then(()=>o(Ae.Success))})}import X from"process";function ot(e){if(!e)return!1;return e.startsWith("--")}function Tt(e){return e.startsWith("-")&&!ot(e)}function je(e){if(e==="true")return!0;if(e==="false")return!1;let t=Number.parseFloat(e);if(!Number.isNaN(t))return t;return e.replace(/"/g,"")}function Pt(e,t,n,r){let[o,i]=e.slice(2).split("=");if(i!==void 0)r[o]=je(i);else if(n+1<t.length&&!t[n+1]?.startsWith("-"))r[o]=t[n+1],n++;else r[o]=!0;return n}function Gt(e,t,n,r){let[o,i]=e.slice(1).split("=");if(o===void 0)return n;if(i!==void 0&&o!==void 0)for(let a=0;a<o.length;a++)r[o[a]]=je(i);else for(let a=0;a<o.length;a++)if(n+1<t.length&&a===o.length-1&&!t[n+1]?.startsWith("-"))r[o[a]]=je(t[n+1]),n++;else r[o[a]]=!0;return n}function At(e){if(e===void 0)e=X.argv.slice(2);let t=[],n={};for(let r=0;r<e.length;r++){let o=e[r];if(!o)continue;if(ot(o))r=Pt(o,e,r,n);else if(Tt(o))r=Gt(o,e,r,n);else t.push(o)}return{args:t,options:n}}function Dr(e){if(e===void 0)e=X.argv.slice(2);return At(e).args}function zr(e){e=e||{};let t={dryRun:!1,quiet:!1,verbose:!1},n=X.argv.slice(2);for(let r=0;r<n.length;r++){let o=n[r];if(o?.startsWith("--")){let a=o.substring(2).replace(/-([a-z])/gi,(l)=>l[1]?l[1].toUpperCase():"");if(r+1<n.length&&!n?.[r+1]?.startsWith("--"))if(n?.[r+1]==="true"||n?.[r+1]==="false")e[a]=n[r+1]==="true",r++;else e[a]=n[r+1],r++;else e[a]=!0}}if(Object.keys(e).length===0)return{};return{...t,...e}}function jt(e){let t=[];for(let[n,r]of Object.entries(e)){if(n==="--"||n==="_"||n==="forwardSignals"||r===!1||r===void 0||r===null)continue;if(typeof r==="object"&&!Array.isArray(r))continue;if(typeof r==="function"||typeof r==="symbol")continue;if(r===!0)t.push(`--${n}`);else t.push(`--${n}`,String(r))}return t}function Nt(e){if(Array.isArray(e)){if(e=Array.from(new Set(e)),Array.isArray(e)&&e[0]&&!e[0].startsWith("-"))e.shift();return e.join(" ")}if(typeof e==="object"&&e!==null)return jt(e).join(" ");return Nt(X.argv.slice(2))}async function qr(e,t){if(!Number.isSafeInteger(t.timeoutMs)||t.timeoutMs<1||t.timeoutMs>120000)throw Error("Invalid bounded process timeout");for(let f of[t.stdoutBytes,t.stderrBytes])if(!Number.isSafeInteger(f)||f<1||f>2000000)throw Error("Invalid bounded process output limit");let n=t.signal;if(n!==void 0&&!(n instanceof AbortSignal))throw TypeError("Invalid bounded process signal");let r=()=>Error(`${t.label} canceled`,{cause:n?.reason});if(n?.aborted)throw r();let o=process.platform!=="win32",i=Bun.spawn(e,{cwd:t.cwd,env:t.env??process.env,stdin:"ignore",stdout:"pipe",stderr:"pipe",detached:o}),a=[i.stdout.getReader(),i.stderr.getReader()],l=[],s,c=!1,m=!1,C="failed",h=[];function y(f){if(f?.code!=="ESRCH")h.push(f)}function w(){if(o)try{process.kill(-i.pid,"SIGKILL")}catch(f){y(f)}if(i.exitCode===null)try{i.kill("SIGKILL")}catch(f){y(f)}}function p(f,I="failed"){if(!c)s=f,c=!0,C=I;if(m)return;m=!0,w();for(let M of a)l.push(M.cancel().catch((z)=>{h.push(z)}))}let x=()=>p(r(),"canceled");async function S(f,I,M){let z=[],te=0;try{while(!0){let{done:_,value:re}=await f.read();if(_){let j=Buffer.concat(z,te);return t.strictUtf8===!0?new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(j):j.toString("utf8")}if(re.byteLength>I-te){let j=Error(`${t.label} ${M} exceeds byte limit`);throw p(j,`${M} exceeds byte limit`),j}te+=re.byteLength,z.push(re)}}catch(_){throw p(_,`${M} read failed`),_}}let mt=setTimeout(()=>p(Error(`${t.label} timed out`),"timed out"),t.timeoutMs),Ne=S(a[0],t.stdoutBytes,"stdout"),We=S(a[1],t.stderrBytes,"stderr");try{if(n?.addEventListener("abort",x,{once:!0}),n?.aborted)x();let[f,I,M]=await Promise.all([i.exited,Ne,We]);if(c)throw s;return{exitCode:f,stdout:I,stderr:M}}catch(f){throw p(f),s}finally{try{n?.removeEventListener("abort",x)}catch(f){h.push(f)}if(clearTimeout(mt),!m)w();if(i.exitCode===null)p(Error(`${t.label} interrupted`));await Promise.allSettled([i.exited,Ne,We,...l]);for(let f of a)try{f.releaseLock()}catch(I){h.push(I)}if(h.length)throw AggregateError(c?[s,...h]:h,`${t.label} ${c?`${C}; `:""}process cleanup failed`)}}import{writeSync as Wt}from"fs";import{format as Z}from"util";function Vr(...e){st(1,Z(...e))}function Jr(...e){st(2,Z(...e))}async function Qr(...e){await it(process.stdout,Z(...e))}async function Xr(...e){await it(process.stderr,Z(...e))}function it(e,t){return new Promise((n,r)=>{let o=(i)=>{e.off("error",o),r(i)};e.once("error",o);try{e.write(`${t}
8
8
  `,"utf8",(i)=>{if(i)setImmediate(()=>e.off("error",o)),r(i);else e.off("error",o),n()})}catch(i){e.off("error",o),r(i)}})}function st(e,t){let n=Buffer.from(`${t}
9
9
  `),r=0;while(r<n.length)r+=Wt(e,n,r,n.length-r)}import v from"process";import{createInterface as Yt}from"readline";var rn=v.stdin.destroy;v.stdin.destroy=function(e){if(e)this.emit("error",e);return this};var W=null;function Dt(){if(!W){let e=v.stdin.isTTY&&v.stdout.isTTY;W=Yt({input:v.stdin,output:v.stdout,terminal:e}),W.once("close",()=>{W=null})}return W}var ee=Symbol("stdin-eof");function at(e){return new Promise((t)=>{let n=Dt(),r=!1,o=(l)=>{if(r)return;r=!0,n.off("close",i),n.off("SIGINT",a),t(l)},i=()=>o(ee),a=()=>{console.log(`
10
10
  `),v.exit(130)};n.once("close",i),n.once("SIGINT",a);try{n.question(e,o)}catch{o(ee)}})}function lt(){if(v.argv.includes("--no-interaction"))return!1;if(v.env.CI)return!1;return Boolean(v.stdin.isTTY&&v.stdout.isTTY)}async function Y(e){if(!lt())return"";let t=await at(e);return t===ee?"":t}function ct(e,t){let n=e.toLowerCase().trim();if(!n)return t;if(n==="y"||n==="yes")return!0;if(n==="n"||n==="no")return!1;return t}async function nn(e){let t=typeof e==="string"?{message:e}:e,n=t.initial??!1,r=n?" (Y/n) ":" (y/N) ";if(!lt())return null;let o=await at(`${t.message}${r}`);if(o===ee)return null;return ct(o,n)}async function zt(e){let t=typeof e==="string"?{message:e}:e,n=t.initial??!1,r=n?" (Y/n) ":" (y/N) ",o=await Y(`${t.message}${r}`);return ct(o,n)}async function _t(e){let t=typeof e==="string"?{message:e}:e,n=t.placeholder||t.initial||"",r=n?` (${n}) `:" ";return(await Y(`${t.message}${r}`)).trim()||t.initial||""}async function qt(e){console.log(e.message),e.choices.forEach((o,i)=>{let a=i===(e.initial??0)?">":" ";console.log(`${a} ${i+1}. ${o.label}`)});let t=await Y("Select (number): "),n=Number.parseInt(t.trim(),10)-1,r=e.choices[n]??e.choices[e.initial??0];if(!r)throw Error("select prompt: no choices available");return r.value}async function Kt(e){console.log(e.message),console.log("(Enter numbers separated by commas)"),e.choices.forEach((o,i)=>{console.log(` ${i+1}. ${o.label}`)});let n=(await Y("Select (e.g., 1,3,4): ")).split(",").map((o)=>Number.parseInt(o.trim(),10)-1),r=[];for(let o of n){let i=e.choices[o];if(i)r.push(i.value)}return r}async function Ut(e){return(await Y(`${(typeof e==="string"?{message:e}:e).message} `)).trim()}var on={text:_t,confirm:zt,select:qt,multiselect:Kt,password:Ut};import{handleError as Ht}from"@stacksjs/error-handling";async function Vt(e,t){let n={...t,stdin:t?.stdin??"inherit",verbose:t?.verbose??!1};return await ie(e,n)}async function cn(e,t){let n={...t,stdio:[t?.stdin??"inherit","pipe","pipe"],verbose:t?.verbose??!1};return await ie(e,n)}async function un(e,t){let n={...t,stdio:[t?.stdin??"inherit","pipe","pipe"],verbose:t?.verbose??!1};return await qe(e,n)}async function gn(e,t){let n=[];for(let r of e){let o=await Vt(r,t);if(o.isErr)throw Ht("Error during runCommands",o.error),o.error;n.push(o)}return n}import Jt from"process";var Qt=["SIGINT","SIGTERM","SIGHUP"],A=new Map,ut=!1;function Xt(){if(ut)return;ut=!0;for(let e of Qt)Jt.on(e,async()=>{for(let[t,n]of A)try{await n()}catch(r){console.error(`[signals] cleanup '${t}' threw:`,r)}})}function fn(e,t){return Xt(),A.set(e,t),()=>{if(A.get(e)===t)A.delete(e)}}function pn(e){A.delete(e)}function hn(){return[...A.keys()]}var gt=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],D=process.stdout.isTTY&&!process.env.CI;function Zt(e){let t=e||"",n=0,r=null,o=!1,i=()=>{if(D)process.stdout.write("\r\x1B[K")},a=()=>{if(!D)return;i();let l=gt[n];process.stdout.write(`${l} ${t}`),n=(n+1)%gt.length};return{start(l){if(l)t=l;if(o)return;if(o=!0,D)a(),r=setInterval(a,80);else if(t)console.log(` ${t}`)},stop(l){if(o=!1,r)clearInterval(r),r=null;if(i(),l)console.log(l)},update(l){if(t=l,!D&&o)console.log(` ${l}`)},succeed(l){let s=l||t;if(o=!1,r)clearInterval(r),r=null;i(),console.log(`\u2713 ${s}`)},fail(l){let s=l||t;if(o=!1,r)clearInterval(r),r=null;i(),console.error(`\u2717 ${s}`)},get text(){return t},set text(l){if(t=l,D&&o)a()},get isSpinning(){return o}}}async function yn(e,t,n){let r=Zt(e);r.start();try{let o=await t();return r.succeed(n?.successMessage||e),o}catch(o){throw r.fail(n?.failMessage||`Failed: ${e}`),o}}import T from"process";var dt="\r\x1B[2K";function er(){return{columns:T.stdout.columns??80,rows:T.stdout.rows??24}}function tr(){return Boolean(T.stdout.isTTY)&&!T.env.CI}function kn(e,t){console.log(rt(e,t===void 0?{}:{title:t}))}function $n(e,t={}){let r=(t.columns??[...new Set(e.flatMap((s)=>Object.keys(s)))]).map((s)=>typeof s==="string"?{key:s}:s);if(r.length===0)return"";let o=(s,c)=>{let m=s[c.key];return m===void 0||m===null?"":String(m)},i=r.map((s)=>{let c=t.header===!1?"":s.header??s.key;return Math.max(E(c).length,...e.map((m)=>E(o(m,s)).length))}),a=(s,c,m)=>{let C=Math.max(0,c-E(s).length);return m==="right"?" ".repeat(C)+s:s+" ".repeat(C)},l=[];if(t.header!==!1)l.push(r.map((s,c)=>a(s.header??s.key,i[c],s.align)).join(" ").trimEnd()),l.push(r.map((s,c)=>"-".repeat(i[c])).join(" "));for(let s of e)l.push(r.map((c,m)=>a(o(s,c),i[m],c.align)).join(" ").trimEnd());return l.join(`
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Spawn a command inside native ownership before any command instruction runs.
3
+ * POSIX owns an anchored process group; Windows owns an inherited Job Object.
4
+ * Deliberate POSIX setsid/breakaway is outside this lifecycle contract, not a sandbox.
5
+ */
6
+ export declare function spawnOwnedProcess(command: string[], options?: OwnedProcessOptions): OwnedProcess;
7
+ export declare interface OwnedProcessOptions {
8
+ ownerRuntime?: string
9
+ cwd?: string
10
+ env?: Record<string, string | undefined>
11
+ stdin?: 'ignore' | Blob
12
+ stdout?: 'pipe' | 'inherit' | 'ignore' | number
13
+ stderr?: 'pipe' | 'inherit' | 'ignore' | number
14
+ stopGraceMs?: number
15
+ ipc?: (message: unknown, pid: number) => void
16
+ }
17
+ export declare interface OwnedProcessExit { code: number, signal: string | null }
18
+ export declare interface OwnedProcess {
19
+ readonly pid: number
20
+ readonly started: Promise<number>
21
+ readonly exited: Promise<OwnedProcessExit>
22
+ readonly stdout: ReadableStream<Uint8Array> | null
23
+ readonly stderr: ReadableStream<Uint8Array> | null
24
+ stop: () => Promise<void>
25
+ }
@@ -0,0 +1,51 @@
1
+ // @bun
2
+ import{dlopen as G,FFIType as r,ptr as k}from"bun:ffi";import{mkdtempSync as T,rmSync as O,writeFileSync as L}from"fs";import{tmpdir as M}from"os";import{join as E}from"path";function A(){let d=G("kernel32.dll",{GetLastError:{args:[],returns:r.u32},CreateJobObjectW:{args:[r.ptr,r.ptr],returns:r.u64},SetInformationJobObject:{args:[r.u64,r.i32,r.ptr,r.u32],returns:r.i32},AssignProcessToJobObject:{args:[r.u64,r.u64],returns:r.i32},QueryInformationJobObject:{args:[r.u64,r.i32,r.ptr,r.u32,r.ptr],returns:r.i32},TerminateJobObject:{args:[r.u64,r.u32],returns:r.i32},OpenProcess:{args:[r.u32,r.i32,r.u32],returns:r.u64},CloseHandle:{args:[r.u64],returns:r.i32}}),n=d.symbols,c=(s,o)=>{if(!s)throw Error(`Native Windows process ${o} failed (Win32 ${n.GetLastError()})`)},a=n.CreateJobObjectW(null,null);try{c(a!==0n,"ownership creation");let s=new Uint8Array(144);new DataView(s.buffer).setUint32(16,8192,!0),c(n.SetInformationJobObject(a,9,k(s),s.byteLength),"ownership limits")}catch(s){if(a!==0n)n.CloseHandle(a);throw d.close(),s}return{assign(s){let o=n.OpenProcess(257,0,s);c(o!==0n,"owner handle");try{c(n.AssignProcessToJobObject(a,o),"ownership admission")}finally{c(n.CloseHandle(o),"owner handle disposal")}},terminate(){c(n.TerminateJobObject(a,1),"tree termination")},empty(){let s=new Uint8Array(48);return c(n.QueryInformationJobObject(a,1,k(s),s.byteLength,null),"ownership accounting"),new DataView(s.buffer).getUint32(40,!0)===0},close(){try{c(n.CloseHandle(a),"ownership disposal")}finally{d.close()}}}}function K(d,n={}){if(!d.length||d.some((e)=>typeof e!=="string"||e.includes("\x00")))throw TypeError("Owned process needs a valid command");let c=n.stopGraceMs??2000;if(!Number.isFinite(c)||c<0)throw RangeError("Process stop grace must be finite and nonnegative");let a={...n.env??process.env},s={...a};delete s.BUN_OPTIONS,delete s.NODE_OPTIONS;let o=null,p=T(E(M(),"stacks-process-owner-")),P=E(p,"bunfig.toml"),S=E(p,"noop.ts");try{L(S,`export {}
3
+ `),L(P,`preload = [${JSON.stringify(S)}]
4
+ `),o=process.platform==="win32"?A():null}catch(e){throw O(p,{recursive:!0,force:!0}),e}let x,h,I=new Promise((e,t)=>{x=e,h=t}),g,f,R=new Promise((e,t)=>{g=e,f=t});I.catch(()=>{}),R.catch(()=>{});let w=!1,l,m=0,b=!1,C=!1,N=`
5
+ let stopRequested = false
6
+ process.on('SIGTERM', () => {
7
+ if (stopRequested) return
8
+ stopRequested = true
9
+ process.send({ type: 'stop-request' })
10
+ })
11
+ setInterval(() => {}, 60000)
12
+ let launched = false
13
+ process.on('disconnect', () => {
14
+ if (process.platform !== 'win32') process.kill(-process.pid, 'SIGKILL')
15
+ else process.exit(1)
16
+ })
17
+ process.on('message', message => {
18
+ if (message?.start !== true || launched) return
19
+ launched = true
20
+ try {
21
+ let closeIPC
22
+ const ipcClosed = new Promise(resolve => { closeIPC = resolve })
23
+ let announced = false
24
+ const earlyMessages = []
25
+ const forward = (message, pid) => process.send({ type: 'message', pid, message })
26
+ const relay = message.ipc ? {
27
+ ipc(message, source) {
28
+ if (announced) forward(message, source.pid)
29
+ else earlyMessages.push({ message, pid: source.pid })
30
+ },
31
+ onDisconnect() { closeIPC() },
32
+ } : {}
33
+ const child = Bun.spawn(${JSON.stringify(d)}, {
34
+ env: message.environment,
35
+ stdin: 'inherit', stdout: 'inherit', stderr: 'inherit',
36
+ ...relay,
37
+ })
38
+ // Publish identity before any ready message, including native callbacks
39
+ // delivered before spawn returns. Exit alone does not establish IPC drain.
40
+ process.send({ type: 'started', pid: child.pid })
41
+ announced = true
42
+ for (const item of earlyMessages) forward(item.message, item.pid)
43
+ earlyMessages.length = 0
44
+ child.exited.then(async code => {
45
+ if (message.ipc) await ipcClosed
46
+ process.send({ type: 'exit', code, signal: child.signalCode })
47
+ })
48
+ } catch (error) { process.send({ type: 'failure', message: String(error) }) }
49
+ })
50
+ process.send({ type: 'ready' })
51
+ `,i,j;try{if(i=Bun.spawn([n.ownerRuntime??process.execPath,"--no-env-file",`--config=${P}`,"--eval",N],{cwd:n.cwd,env:s,stdin:n.stdin??"ignore",stdout:n.stdout??"pipe",stderr:n.stderr??"pipe",detached:!o,ipc(e){try{if(!e||typeof e!=="object")return;if(e.type==="ready"){if(C=!0,b&&!l)i.send({start:!0,environment:a,ipc:Boolean(n.ipc)})}else if(!b)return;else if(e.type==="stop-request")y();else if(e.type==="started"&&Number.isSafeInteger(e.pid)&&e.pid>0)m=e.pid,x(m);else if(e.type==="message"&&e.pid===m)n.ipc?.(e.message,m);else if(e.type==="exit"&&Number.isInteger(e.code))w=!0,g({code:e.code,signal:e.signal==null?null:String(e.signal)});else if(e.type==="failure")f(Error(`Owned command failed to start: ${e.message}`))}catch(t){f(t)}}}),j=()=>{if(o)i.kill("SIGKILL");else try{process.kill(-i.pid,"SIGKILL")}catch(e){if(e.code!=="ESRCH")throw e}},o?.assign(i.pid),b=!0,C)i.send({start:!0,environment:a,ipc:Boolean(n.ipc)})}catch(e){let t=[e];try{j?.()}catch(u){t.push(u)}try{o?.close()}catch(u){t.push(u)}try{O(p,{recursive:!0,force:!0})}catch(u){t.push(u)}if(t.length>1)throw AggregateError(t,"Owned process admission and cleanup failed");throw e}let v=(e)=>{try{return process.kill(-i.pid,e),!0}catch(t){if(t.code==="ESRCH")return!1;if(e===0&&t.code==="EPERM")return!0;throw t}},y=()=>{if(l)return l;return h(Error("Owned process stopped before command startup")),l=(async()=>{let e=[];try{if(o)o.terminate();else{if(!w&&c)v("SIGTERM"),await Bun.sleep(c);v("SIGKILL")}await i.exited;let t=performance.now()+2000;while(o?!o.empty():v(0)){if(performance.now()>=t)throw Error("Native owned process disposal could not be confirmed");await Bun.sleep(10)}}catch(t){e.push(t)}finally{try{o?.close()}catch(t){e.push(t)}try{O(p,{recursive:!0,force:!0})}catch(t){e.push(t)}}if(e.length)throw AggregateError(e,"Owned process cleanup failed")})(),l.catch(()=>{}),l};i.exited.then((e)=>{if(!l&&!w)f(Error(`Owned process host exited before command completion (${e})`));if(!w)g({code:e,signal:i.signalCode==null?null:String(i.signalCode)})});let J=R.then(async(e)=>(await y(),e),async(e)=>{h(e);try{await y()}catch(t){throw AggregateError([e,t],"Owned process failed and cleanup failed")}throw e});return J.catch(()=>{}),{pid:i.pid,started:I,exited:J,stdout:i.stdout instanceof ReadableStream?i.stdout:null,stderr:i.stderr instanceof ReadableStream?i.stderr:null,stop:y}}export{K as spawnOwnedProcess};
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/cli",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.431",
5
+ "version": "0.75.439",
6
6
  "description": "TypeScript framework for CLI artisans. Build beautiful console apps with ease.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -70,16 +70,16 @@
70
70
  },
71
71
  "dependencies": {
72
72
  "@stacksjs/clapp": "^0.2.12",
73
- "@stacksjs/collections": "0.75.431",
74
- "@stacksjs/error-handling": "0.75.431",
75
- "@stacksjs/logging": "0.75.431",
76
- "@stacksjs/types": "0.75.431"
73
+ "@stacksjs/collections": "0.75.439",
74
+ "@stacksjs/error-handling": "0.75.439",
75
+ "@stacksjs/logging": "0.75.439",
76
+ "@stacksjs/types": "0.75.439"
77
77
  },
78
78
  "devDependencies": {
79
- "@stacksjs/config": "0.75.431",
80
- "@stacksjs/path": "0.75.431",
81
- "@stacksjs/utils": "0.75.431",
82
- "@stacksjs/validation": "0.75.431",
79
+ "@stacksjs/config": "0.75.439",
80
+ "@stacksjs/path": "0.75.439",
81
+ "@stacksjs/utils": "0.75.439",
82
+ "@stacksjs/validation": "0.75.439",
83
83
  "better-dx": "^0.2.24"
84
84
  }
85
85
  }