@amr-m-abdelgawad/devctl 0.8.0 → 0.8.1
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/dist/devctl.js +97 -91
- package/package.json +1 -1
package/dist/devctl.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
var A=(e,t,r)=>()=>{if(e)try{t=e(e=0)}catch(n){r=[n]}if(r)throw r[0];return t};function Ng(e,t=""){if(t==="MetadataLookupWarning")return!0;return e.includes("MetadataLookupWarning")||e.startsWith("received unexpected error =")}function Ya(){if(Mg)return;Mg=!0;let e=process.emitWarning.bind(process);process.emitWarning=(t,...r)=>{let n=MR(r[0]),o=OR(t);if(Ng(o,n))return;e(t,...r)}}function Fg(){let e=process.stderr.write.bind(process.stderr);return process.stderr.write=(t,r,n)=>{let o=NR(t);if(Ng(o)){let i=typeof r==="function"?r:typeof n==="function"?n:void 0;if(typeof i==="function")i();return!0}if(typeof r==="function")return e(t,r);return e(t,r,n)},()=>{process.stderr.write=e}}function OR(e){if(typeof e==="string")return e;if(e instanceof Error)return e.message;return String(e)}function MR(e){if(typeof e==="string")return e;if(e&&typeof e==="object"&&"type"in e&&typeof e.type==="string")return e.type;return""}function NR(e){if(typeof e==="string")return e;if(e instanceof Uint8Array)return new TextDecoder().decode(e);return""}var Mg=!1;import{createHash as FR}from"crypto";import{resolve as $R}from"path";function Tr(e){let t=$R(e),r=process.platform==="win32"?t.toLowerCase():t;return FR("sha256").update(r).digest("hex").slice(0,HR)}var HR=16;var Ja=()=>{};function kd(e){let t=e.indexOf("Z-"),r=t>=0?e.slice(0,t+1):e,n=r.indexOf("T");if(n<0||!r.endsWith("Z"))return;let o=r.slice(0,n),i=r.slice(n+1,-1).replace(/-/g,":"),s=new Date(`${o}T${i}Z`);return Number.isNaN(s.getTime())?void 0:s}function Dd(e=process.platform){return e==="darwin"}function o1(e=process.platform){return Dd(e)?"cmd":"ctrl"}function hi(e,t=process.platform){return`${o1(t)}+${e}`}function i1(e=process.platform){return Dd(e)?"command":"ctrl"}function jt(e,t=process.platform){return`${i1(t)}+${e}`}function wo(e){return e.replace(/\bcmd\b/gi,"command")}function rn(e,t=process.platform){let r=Dd(t),n=Boolean(e.meta||e.super),o=Boolean(e.ctrl);return r?n&&!o:o&&!n}function kn(e=process.platform){return hi("c",e)}function s1(e=process.platform){return{leader:hi("x",e),command_list:hi("p",e),command:"/",help:"?",search:"f",quit:"q",services:"s",logs:"l",auth:"a",proxy:"p",doctor:"d",config:"c",setup:"u",refresh:"r",restart:"R",find:"f",fullscreen:"z",confirm:"enter",cancel:"esc",select:"space",interrupt:"escape",copy:kn(e)}}function Gg(){return{theme:"devctl",leader_timeout:2000,font_size:14,keybinds:{...a1},scroll_speed:3,scroll_acceleration:{enabled:!1},diff_style:"auto",cursor:{style:"block",blinking:!0},mouse:!0,attention:{enabled:!1,notifications:!0,sound:!0,volume:0.4,sound_pack:"default",sounds:{}},log_timestamps:!0,log_metadata:!0,mcp_enabled:!1}}function l1(e){if(e===""||e==="none")return[];return e.split(",").flatMap((t)=>{let r=t.trim();if(r===""||r==="none"||/\s/.test(r))return[];let n=r.toLowerCase().split("+"),o=n[n.length-1]??"";return[{name:o==="return"?"return":o,ctrl:n.includes("ctrl")||n.includes("control"),shift:n.includes("shift"),meta:n.includes("meta")||n.includes("cmd")||n.includes("super"),alt:n.includes("alt")||n.includes("option")}]})}function Hn(e,t){return l1(t).some((n)=>(e.name??"").toLowerCase()===n.name&&Boolean(e.ctrl)===n.ctrl&&Boolean(e.shift)===n.shift&&Boolean(e.meta||e.super)===n.meta&&Boolean(e.option??e.alt)===n.alt)}var Id=2000,gi=14,qg="DEVCTL_TUI_CONFIG",a1;var el=A(()=>{a1=s1()});function Ce(e,t,r){return{type:e,timestamp:new Date().toISOString(),service:t,payload:r}}class Nd{subs=new Map;nextID=0;buffer=[];maxBuf;constructor(e){this.maxBuf=e>0?e:1024}subscribe(e,t=[]){this.nextID+=1;let r=this.nextID;return this.subs.set(r,{types:new Set(t),handler:e}),()=>{this.subs.delete(r)}}publish(e){let t=e.timestamp===""?{...e,timestamp:new Date().toISOString()}:e;if(this.buffer.length>=this.maxBuf)this.buffer=this.buffer.slice(1);this.buffer.push(t);for(let r of this.subs.values())if(r.types.size===0||r.types.has(t.type))r.handler(t)}recent(){return[...this.buffer]}}var Yg="ServiceStarted",al="ServiceStopped",ll="ServiceFailed",Jg="ServiceStateChanged",Xg="ServiceHealthChanged",yi="LogReceived",bi="TokenRefreshed",ko="TokenRefreshFailed",Md="AuthenticationChanged",Qg="ProxyStarted",Zg="ProxyStopped",Cs="ProxyRequest",cl="ConfigurationChanged",Ts="ConfigurationReloadFailed",ev="SessionRecovered";var tv=5000,rv=500,Fd=16384,$d=65536,qt=1e6,Hd="TRACE",Ud="DEBUG",jd="INFO",Bd="WARN",Wd="ERROR",zd="FATAL",So="UNKNOWN";function ul(e){return e.length>16384?e.slice(0,16384):e}function Le(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function hr(e,t=0){if(t>=8)return nv(e);if(e===void 0)return null;if(typeof e==="string")return ul(e);if(e===null||typeof e==="boolean")return e;if(typeof e==="number")return Number.isFinite(e)?e:null;if(typeof e==="bigint")return Number(e);if(Array.isArray(e))return e.slice(0,32).map((r)=>hr(r,t+1));if(Le(e)){let r={},n=Object.entries(e).slice(0,64);for(let[o,i]of n)r[o]=hr(i,t+1);return r}return nv(e)}function Es(e){if(!Le(e))return{};let t={},r=Object.entries(e).slice(0,64);for(let[n,o]of r)t[n]=hr(o);return t}function gr(e){if(e===null)return"null";if(typeof e==="string")return e;if(typeof e==="number"||typeof e==="boolean")return String(e);try{return JSON.stringify(e)}catch{return"[unserializable]"}}function dl(e,t=0){if(t>=8)return gr(e);if(e===null||typeof e==="string"||typeof e==="number"||typeof e==="boolean")return gr(e);if(Array.isArray(e))return e.map((r)=>dl(r,t+1)).join(" ");return Object.entries(e).map(([r,n])=>`${r} ${dl(n,t+1)}`).join(" ")}function Gd(e,t=64){let r=[],n=Object.entries(e).slice(0,t);for(let[o,i]of n)r.push(`${o}=${g1(gr(i))}`);return r.join(" ")}function g1(e){if(e===""||/[\s="]/.test(e))return`"${e.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`;return e}function nv(e){if(typeof e==="string")return ul(e);try{return ul(JSON.stringify(e)??String(e))}catch{return ul(String(e))}}var pl=8,qd=64,ov=32;function ki(e){if(e>=_s&&e<=Kd)return zd;if(e>=Un)return Wd;if(e>=Co)return Bd;if(e>=xi)return jd;if(e>=Rs)return Ud;if(e>=wi)return Hd;return So}function Ps(e){let t=e.trim().toUpperCase();if(t===Hd||t==="TRACE")return wi;if(t===Ud||t==="DBG"||t==="DEBUG")return Rs;if(t===jd||t==="INFORMATION"||t==="NOTICE"||t==="INFORMATIONAL")return xi;if(t===Bd||t==="WARNING"||t==="WARN")return Co;if(t===Wd||t==="ERR"||t==="ERROR")return Un;if(t===zd||t==="CRITICAL"||t==="PANIC"||t==="EMERGENCY"||t==="ALERT"||t==="FATAL")return _s;return yt}function Br(e){if(typeof e==="number"&&Number.isFinite(e))return sv(e);if(typeof e==="string"&&e.trim()!==""){let t=Ps(e);if(t!==yt)return t;let r=Number(e);if(Number.isFinite(r))return sv(r)}return}function av(e){if(typeof e==="number"&&Number.isFinite(e))return iv(Math.floor(e));if(typeof e==="string"&&e.trim()!==""){let t=e.trim().toUpperCase(),r=Number(t);if(Number.isFinite(r))return iv(Math.floor(r));let n=t.startsWith("SEVERITY_NUMBER_")?t.slice(16):t,o=/^([A-Z]+?)([2-4])?$/.exec(n);if(o){let i=A1[o[1]??""];if(i!==void 0)return i+(o[2]?Number(o[2])-1:0)}}return yt}function iv(e){return e>=wi&&e<=Kd?e:yt}function Si(e){return e>=Un}function lv(e,t){let r=Ps(t);if(r===yt)return!0;return(e===yt?xi:e)>=r}function cv(e){return e===So?"\u2014":e}function sv(e){let t=P1[e];if(t!==void 0)return t;if(e>=wi&&e<=Kd)return Math.floor(e);return}function uv(e){if(e<=S1)return _s;if(e<=C1)return Un;if(e===T1)return Co;if(e===E1||e===R1)return xi;if(e===_1)return Rs;return}var yt=0,wi=1,Rs=5,xi=9,Co=13,Un=17,_s=21,Kd=24,v1=10,y1=20,b1=30,w1=40,x1=50,k1=60,S1=0,C1=3,T1=4,E1=5,R1=6,_1=7,P1,A1;var Ci=A(()=>{P1={[v1]:wi,[y1]:Rs,[b1]:xi,[w1]:Co,[x1]:Un,[k1]:_s};A1={TRACE:wi,DEBUG:Rs,INFO:xi,WARN:Co,ERROR:Un,FATAL:_s}});function sr(e){return pv(e,32)}function Sn(e){return pv(e,16)}function Vd(){return fv(16)}function hl(){return fv(8)}function Yd(e){let t=e.trim().split("-");if(t.length!==4)return;let[r,n,o,i]=t;if(r!=="00"||!n||!o||!i)return;if(!sr(n)||!Sn(o)||!/^[0-9a-f]{2}$/i.test(i))return;return{traceId:n.toLowerCase(),spanId:hl(),parentSpanId:o.toLowerCase(),traceFlags:Number.parseInt(i,16)}}function gl(e){let t=(e.traceFlags&255).toString(16).padStart(2,"0");return`00-${e.traceId}-${e.spanId}-${t}`}function dv(e){if(e.traceparent){let n=Yd(e.traceparent);if(n){let o=e.requestId&&e.requestId!==""?e.requestId:n.traceId;return{...n,requestId:o}}}let t=(e.requestId??"").trim(),r=Vd();return{traceId:r,spanId:hl(),traceFlags:1,requestId:t===""?r:t}}function pv(e,t){if(e.length!==t)return!1;return/^[0-9a-f]+$/i.test(e)}function fv(e){let t=new Uint8Array(e);crypto.getRandomValues(t);let r="";for(let n of t)r+="0123456789abcdef"[n>>4&15],r+="0123456789abcdef"[n&15];return r}var fl=32,ml=16,Gt="devctl.request_id";function Ti(e){if(!Le(e))return hr(e);if(typeof e.stringValue==="string")return e.stringValue;if(e.intValue!==void 0&&e.intValue!==null){let n=Number(e.intValue);if(Number.isSafeInteger(n))return n;return typeof e.intValue==="string"?e.intValue:String(e.intValue)}if(typeof e.doubleValue==="number")return e.doubleValue;if(typeof e.boolValue==="boolean")return e.boolValue;if(typeof e.bytesValue==="string")return e.bytesValue;let t=Le(e.arrayValue)?e.arrayValue.values:void 0;if(Array.isArray(t))return t.map((n)=>Ti(n));let r=Le(e.kvlistValue)?e.kvlistValue.values:void 0;if(Array.isArray(r))return jn(r);return hr(e)}function Jd(e){if(!Array.isArray(e)||e.length===0)return!1;return e.every((t)=>Le(t)&&typeof t.key==="string"&&t.value!==void 0)}function jn(e){let t={};if(!Jd(e))return t;for(let r of e){let n=r.key;if(typeof n==="string"&&n!=="")t[n]=Ti(r.value)}return t}function Xd(e,t){let r=Le(e)?jn(e.attributes):{},n=typeof r["service.name"]==="string"&&r["service.name"]!==""?r["service.name"]:t;return{...r,"service.name":n}}function Qd(e){if(!Le(e))return;let t=typeof e.name==="string"?e.name:"";if(t==="")return;let r=typeof e.version==="string"&&e.version!==""?e.version:void 0;return{name:t,version:r}}function nn(e){if(typeof e==="number"&&Number.isFinite(e)&&e>0)return e;if(typeof e==="string"&&e.trim()!==""){let t=Number(e);if(Number.isFinite(t)&&t>0)return t}return}var vl=()=>{};function gv(e){let t=e/qt,r=new Date(t);if(Number.isNaN(r.getTime()))return new Date(0).toISOString();return r.toISOString()}function vv(e){let t=Date.parse(e);if(Number.isNaN(t))return Date.now()*qt;return t*qt}function Kt(e){return D1(e.body,e.attributes)}function D1(e,t){let r=O1(e);if(typeof e==="string"&&e!==""){let i=mv(t,e);return i===""?e:`${e} ${i}`}if(r!=="")return r;let n=mv(t,""),o=Gd(bv(t,F1()),hv);if(n!==""&&o!=="")return`${n} ${o}`;if(n!=="")return n;return o}function yv(e,t){let r={};if(e!==""&&e!==null)r.body=e;if(Object.keys(t).length>0)r.attributes=t;try{return JSON.stringify(r,null,2)}catch{return gr(e)}}function As(e){return[Kt(e),dl(e.attributes),e.raw??"",e.service,e.traceId??"",e.spanId??"",e.identity??"",Ei(e)].join(" ")}function Ei(e){let t=e.attributes[Gt];if(typeof t==="string"&&t!=="")return t;return e.traceId??""}function O1(e){if(typeof e==="string")return e;if(e===null)return"";if(typeof e==="number"||typeof e==="boolean")return String(e);if(Array.isArray(e))return gr(e);return Gd(bv(e),hv)}function bv(e,t=new Set){let r={};for(let[n,o]of Object.entries(e))if(M1(n,o,t))r[n]=o;return r}function M1(e,t,r){if(r.has(e)||I1.has(e))return!1;if(t===null||t==="")return!1;if(typeof t==="object")return!1;if(typeof t==="string"&&(t.length>L1||sr(t)||Sn(t)))return!1;return!0}function Zd(e){return{method:yl(e,wv),route:yl(e,xv),status:yl(e,kv),namespaced:N1.some((t)=>yl(e,[t])!==void 0)}}function mv(e,t){let{method:r,route:n,status:o,namespaced:i}=Zd(e),s=[r,n,o].filter((l)=>l!==void 0&&l!=="");if(!i&&s.length<2)return"";return s.filter((l)=>t===""||!t.includes(l)).join(" ")}function F1(){return new Set([...wv,...xv,...kv])}function yl(e,t){for(let r of t){let n=e[r];if(typeof n==="string"&&n!=="")return n;if(typeof n==="number"&&Number.isFinite(n))return String(n)}return}var hv=6,L1=40,I1,wv,xv,kv,N1;var Ls=A(()=>{I1=new Set(["shape","seq","pid","ppid","tid","time","ts","timestamp","@timestamp","timeUnixNano","observedTimeUnixNano","trace_id","traceId","span_id","spanId","traceparent","ecs.version","version","host","facility","logger","caller","name","level","lvl","severity","severityText","severityNumber","severity_text",Gt]);wv=["http.request.method","http.method","method","request_method"],xv=["http.route","url.path","path","route","request_uri"],kv=["http.status_code","http.response.status_code","status","status_code"],N1=["http.request.method","http.method","http.route","url.path","http.status_code","http.response.status_code"]});class Rr{nameMarkers;patterns;constructor(e,t){this.nameMarkers=[...Sv,...e],this.patterns=t.flatMap((r)=>{try{return[new RegExp(r)]}catch{return[]}})}update(e,t){this.nameMarkers=[...Sv,...e],this.patterns=t.flatMap((r)=>{try{return[new RegExp(r)]}catch{return[]}})}isSecretName(e){let t=e.toUpperCase();return this.nameMarkers.some((r)=>t.includes(r.toUpperCase()))}redactValue(e,t){if(t==="")return t;if(this.isSecretName(e))return"********";if(this.patterns.some((r)=>r.test(t)))return"********";return t}redactMap(e){let t={};for(let[r,n]of Object.entries(e))t[r]=this.redactValue(r,n);return t}redactText(e){if(e==="")return e;let t=e;for(let r of this.patterns)t=t.replace(r,"********");return $1(t)}}function $1(e){let t=e.toLowerCase(),r="authorization: bearer ",n=t.indexOf("authorization: bearer ");if(n>=0)return Cv(e,n+22);let o=t.indexOf("bearer ");if(o<0)return e;return Cv(e,o+7)}function Cv(e,t){let r=t;while(r<e.length&&!H1(e[r]??""))r+=1;return e.slice(0,t)+"********"+e.slice(r)}function H1(e){return e===" "||e==="\t"||e===`
|
|
4
|
-
`||e==="\r"}var
|
|
5
|
-
`&&r!=="\r")return;e.index+=1}}function
|
|
6
|
-
`;if(e==="t")return"\t";if(e==="r")return"\r";return e}function Z1(e){return e!==void 0&&e>="0"&&e<="9"}function e_(e){return e>="0"&&e<="9"||e>="A"&&e<="Z"||e>="a"&&e<="z"||e==="_"}var Vt,rp,np;var Pv=A(()=>{Vt={ok:!1},rp=/-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/y,np=/[A-Za-z_][A-Za-z0-9_]*/y});function Ov(){return{name:"default",parse:(e)=>ap(e)}}function Mv(e){if(e.length<=Fd)return e;return e.slice(0,Fd)}function ap(e){let t=lp(e);if(t)return t;return{body:e,attributes:{},severityNumber:Dv(e),severityText:ki(Dv(e)),request_id:v_(e)||void 0,raw:e}}function lp(e){let t=n_(e);if(!t)return;return i_(t.value,t.raw)??l_(t.value,t.raw)??c_(t.value,t.raw)??u_(t.value,t.raw)}function n_(e){let t=e.trim();if(t.length>$d)return;if(t.startsWith("{")&&t.endsWith("}"))return Lv(t,t);let r=t.indexOf("{"),n=t.lastIndexOf("}");if(r<=0||n<=r)return;let o=t.slice(r,n+1);if(o.length>$d)return;return Lv(o,t)}function Lv(e,t){let r=o_(e)??Ev(e);if(!r)return;return{value:r,raw:t}}function o_(e){try{let t=JSON.parse(e);return Le(t)?t:void 0}catch{return}}function i_(e,t){if(!s_(e))return;let r=jn(e.attributes),n=e.body===void 0?a_(r):Ti(e.body),o=Br(e.severityNumber)??Br(e.severityText)??Br(e.severity_text),i=El(e,Sl,fl)??Iv(r,Sl),s=El(e,Cl,ml)??Iv(r,Cl);return{body:n,attributes:r,severityNumber:o,severityText:typeof e.severityText==="string"?e.severityText:void 0,traceId:i,spanId:s,timeUnixNano:nn(e.timeUnixNano),observedTimeUnixNano:nn(e.observedTimeUnixNano),raw:t}}function s_(e){if(e.timeUnixNano!==void 0||e.observedTimeUnixNano!==void 0)return!0;if(Le(e.body)&&(e.body.stringValue!==void 0||e.body.intValue!==void 0||e.body.doubleValue!==void 0||e.body.boolValue!==void 0))return!0;return Jd(e.attributes)}function a_(e){return Nv(e)??""}function l_(e,t){let r=Ro(e.metric_name);if(r===void 0)return;let n=Ro(e.metric_type),o=Ds(e.value);if(n===void 0&&o===void 0)return;let i=Ro(e.unit),s=o===void 0?void 0:i===void 0?String(o):`${o} ${i}`,a=Le(e.attributes)?Es(e.attributes):{},l=up([r,n,s,Nv(a)]),{attributes:c}=cp(e,["metric_name","metric_type","value","unit","attributes"]);return{body:l,attributes:{...c,...a},raw:t}}function c_(e,t){if(Tl(e,sp)!==void 0)return;let r=Ro(e.request),n=r===void 0?{}:m_(r),o=Ro(Eo(e,["request_method","method","http_method","verb"]))??n.method,i=Ro(Eo(e,["request_uri","uri","url","path","request_path","api_url"]))??n.uri,s=Ds(Eo(e,["status","status_code","statusCode","http_status","response_status"])),a=Ro(Eo(e,["remote_ip","remote_addr","client_ip"]));if(!(o!==void 0&&i!==void 0&&(s!==void 0||a!==void 0||r!==void 0))&&!(i!==void 0&&s!==void 0))return;let u=Ds(Eo(e,["body_bytes_sent","bytes_sent","bytes"])),d=Ds(Eo(e,["request_time","duration","duration_seconds"])),f=Ds(Eo(e,["request_time_ms","latency_ms","duration_ms"])),p=u===void 0?void 0:`${u}B`,m=f!==void 0?`${f}ms`:d===void 0?void 0:`${d}s`,{attributes:h,traceId:g,spanId:w,requestId:v,severityNumber:S}=cp(e,[]);return{body:up([a,o,i,s===void 0?void 0:String(s),p,m]),attributes:h,severityNumber:S??(s===void 0?void 0:f_(s)),traceId:g,spanId:w,request_id:v,raw:t}}function u_(e,t){let r=cp(e,[]),n=Fv(e,sp);return{body:n!==void 0?hr(n):e.body!==void 0&&e.body!==null?hr(e.body):hr(r.remainder),attributes:r.attributes,severityNumber:r.severityNumber,severityText:r.severityText,traceId:r.traceId,spanId:r.spanId,request_id:r.requestId,timeUnixNano:r.timeUnixNano,raw:t}}function cp(e,t){let r=new Set([...sp,...ip,...Sl,...Cl,...Av,"traceparent","trace_flags","traceFlags","timeUnixNano","observedTimeUnixNano","timestamp","time","@timestamp","ts","body",...t]),n=typeof e.short_message==="string",o=d_(e,n),i=Tl(e,ip),s=typeof e.traceparent==="string"?Yd(e.traceparent):void 0,a=El(e,Sl,fl)??s?.traceId,l=El(e,Cl,ml)??s?.parentSpanId,c=Tl(e,Av),u=nn(e.timeUnixNano)??p_(e),d={},f={};for(let[p,m]of Object.entries(e))if(!r.has(p)){let h=hr(m);d[p]=h,f[p]=h}if(c&&f[Gt]===void 0)f[Gt]=c;return{attributes:f,remainder:d,severityNumber:o,severityText:i,traceId:a,spanId:l,requestId:c,timeUnixNano:u}}function d_(e,t){for(let r of ip){let n=e[r];if(n!==void 0&&n!==null){if(t&&typeof n==="number"){let i=uv(n);if(i!==void 0)return i}let o=Br(n);if(o!==void 0)return o}}return}function p_(e){for(let t of["timestamp","time","@timestamp","ts"]){let r=e[t];if(typeof r==="string"&&r!==""){let n=Date.parse(r);if(!Number.isNaN(n))return n*1e6}if(typeof r==="number"&&Number.isFinite(r))return r>1000000000000000?r:r*qt}return}function Nv(e){let{method:t,route:r,status:n}=Zd(e),o=up([t,r,n]);return o===""?void 0:o}function f_(e){if(e>=r_)return Un;if(e>=t_)return Co;return}function m_(e){let t=e.trim().split(/\s+/);return{method:t[0],uri:t[1]}}function Tl(e,t){for(let r of t){let n=e[r];if(typeof n==="string"&&n.trim()!=="")return n}return}function Fv(e,t){for(let r of t)if(e[r]!==void 0&&e[r]!==null)return e[r];return}function Eo(e,t){return Fv(e,t)}function El(e,t,r){let n=Tl(e,t);if(!n)return;if(r===fl&&sr(n))return n.toLowerCase();if(r===ml&&Sn(n))return n.toLowerCase();return n}function Iv(e,t){for(let r of t){let n=e[r];if(typeof n==="string"&&n!=="")return n}return}function Ro(e){if(typeof e==="string"&&e.trim()!=="")return e;if(typeof e==="number"&&Number.isFinite(e))return String(e);return}function Ds(e){if(typeof e==="number"&&Number.isFinite(e))return e;if(typeof e==="string"&&e.trim()!==""){let t=Number(e);if(Number.isFinite(t))return t}return}function up(e){return e.filter((t)=>t!==void 0&&t!=="").join(" ")}function v_(e){return h_.exec(e)?.[1]??""}function Dv(e){return g_.find((r)=>r.re.test(e))?.level??yt}var sp,ip,Sl,Cl,Av,t_=400,r_=500,h_,g_;var $v=A(()=>{vl();Ls();Pv();Ci();sp=["message","msg","text","log","event","short_message","shortMessage"],ip=["level","severity","severityText","severity_text","levelname","loglevel","lvl"],Sl=["trace_id","traceId","traceid"],Cl=["span_id","spanId","spanid"],Av=["request_id","requestId","correlation_id","correlationId",Gt];h_=/(?:x-devctl-request-id|request[_-]?id)[=: ]+([A-Za-z0-9-]+)/i,g_=[{re:/\b(fatal|critical)\b/i,level:Br("FATAL")??yt},{re:/\b(error|err)\b/i,level:Br("ERROR")??yt},{re:/\b(warn|warning)\b/i,level:Br("WARN")??yt},{re:/\b(debug|dbg)\b/i,level:Br("DEBUG")??yt},{re:/\b(trace)\b/i,level:Br("TRACE")??yt},{re:/\b(info|information)\b/i,level:Br("INFO")??yt}]});function Os(e){let t=y_(e);if(t===void 0)return;return new RegExp(t)}function y_(e){if(e.length===0||e.length>200)return;let t={raw:e,i:0,out:[],quantifiers:0,depth:0,lastAtom:"none",groupQuant:[]};if(!Hv(t)||t.i!==e.length||t.depth!==0)return;return t.out.join("")}function Hv(e){while(e.i<e.raw.length){if(e.raw[e.i]===")")return!0;if(!b_(e))return!1}return!0}function b_(e){let t=e.raw[e.i]??"";if(t==="|")return Rl(e,"|","none");if(t==="^")return Rl(e,"^","none");if(t==="$")return Rl(e,"$","none");if(t===".")return Rl(e,".","atom");if(t==="(")return w_(e);if(t==="[")return k_(e);if(t==="*"||t==="+"||t==="?"||t==="{")return x_(e);if(t==="\\")return Uv(e);return e.out.push(RegExp.escape(t)),e.i+=1,e.lastAtom="atom",!0}function Rl(e,t,r){return e.out.push(t),e.i+=1,e.lastAtom=r,!0}function w_(e){if(e.i+=1,e.depth+=1,e.depth>2)return!1;if(e.groupQuant.push(!1),e.out.push("(?:"),!Hv(e)||e.raw[e.i]!==")")return!1;e.out.push(")"),e.i+=1,e.depth-=1;let t=e.groupQuant.pop()===!0;return e.lastAtom=t?"quantified-group":"atom",!0}function x_(e){let t=e.raw[e.i]??"";if(t==="{"||e.lastAtom==="none"||e.lastAtom==="quant"||e.lastAtom==="quantified-group")return!1;if(e.quantifiers>=8)return!1;if(t==="*")e.out.push("*");else if(t==="+")e.out.push("+");else if(t==="?")e.out.push("?");else return!1;e.i+=1,e.quantifiers+=1;let r=e.groupQuant.length-1;if(r>=0)e.groupQuant[r]=!0;if(e.raw[e.i]==="?")e.out.push("?"),e.i+=1;return e.lastAtom="quant",!0}function k_(e){if(e.i+=1,e.out.push("["),e.raw[e.i]==="^")e.out.push("^"),e.i+=1;if(e.raw[e.i]==="]")e.out.push(RegExp.escape("]")),e.i+=1;while(e.i<e.raw.length&&e.raw[e.i]!=="]"){let t=e.raw[e.i]??"";if(t==="\\"){if(!Uv(e))return!1}else if(t==="-")e.out.push("-"),e.i+=1;else e.out.push(RegExp.escape(t)),e.i+=1}if(e.raw[e.i]!=="]")return!1;return e.out.push("]"),e.i+=1,e.lastAtom="atom",!0}function Uv(e){let t=e.raw[e.i+1];if(t===void 0)return!1;if(t==="d")e.out.push("\\d");else if(t==="D")e.out.push("\\D");else if(t==="w")e.out.push("\\w");else if(t==="W")e.out.push("\\W");else if(t==="s")e.out.push("\\s");else if(t==="S")e.out.push("\\S");else if(t==="n")e.out.push("\\n");else if(t==="t")e.out.push("\\t");else if(t==="r")e.out.push("\\r");else if(t==="b")e.out.push("\\b");else if(t==="B")e.out.push("\\B");else e.out.push(RegExp.escape(t));return e.i+=2,e.lastAtom="atom",!0}function _i(e,t){if(e.services&&e.services.length>0&&!e.services.includes(t.service))return!1;if(e.level&&!lv(t.severityNumber,e.level))return!1;if(e.source&&t.source!==e.source)return!1;if(e.since&&t.timestamp<e.since)return!1;if(e.until&&t.timestamp>e.until)return!1;if(e.traceId&&t.traceId!==e.traceId)return!1;if(e.requestId&&Ei(t)!==e.requestId&&t.traceId!==e.requestId)return!1;if(e.attribute){let r=t.attributes[e.attribute.key];if(gr(r??null)!==e.attribute.value)return!1}return!0}function dp(e){if(!e.search)return()=>!0;if(e.regex){let r=Os(e.search);if(r)return(n)=>r.test(As(n))}let t=e.search.toLowerCase();return(r)=>As(r).toLowerCase().includes(t)}function pp(e){let t=dp(e);return(r)=>_i(e,r)&&t(r)}var jv=A(()=>{Ls();Ci()});function Bv(e){if(!Number.isInteger(e)||(e??0)<=0)return rv;return Math.min(e,tv)}var Wv=()=>{};var sn=A(()=>{Ci();vl();Ls();ep();Tv();$v();jv();Wv()});function T(e,t){return new et(e,t)}function ge(e,t,r){let n=r instanceof Error?r:Error(String(r));return new et(e,t,{cause:n})}function Ie(e,t,r,n=""){return new et(e,t,{hint:r,service:n})}function Al(e,t){return e instanceof et&&e.kind===t}function ny(e){if(e instanceof et)return e.exitCode();return 1}function oy(e){if(e instanceof et)return{error:I(e),kind:e.kind,hint:e.hint,service:e.service};return{error:I(e)}}function iy(e){if(typeof e==="string")return T("general",e);if(e.kind)return new et(e.kind,e.error.replace(`${e.kind}: `,""),{hint:e.hint,service:e.service});return T("general",e.error)}function I(e){if(e instanceof et){if(e.hint!=="")return`${ey(e)} \u2014 ${e.hint}`;return ey(e)}if(e instanceof Error)return e.message;return String(e)}function ey(e){let t=`${e.kind}: `;if(e.message.startsWith(t)){let r=e.message.slice(t.length),n=e.causeError?`: ${e.causeError.message}`:"";if(n!==""&&r.endsWith(n))return r.slice(0,r.length-n.length);return r}return e.message}var ty=1,ee="configuration",Po="configuration_missing",Pi="service_not_found",ry="dependency",Ge="process_start",Bn="authentication",Ao="authorization",zr="token",_l="impersonation",Pl="iap",ar="proxy",wp="health_check",$e="general",et;var ne=A(()=>{et=class et extends Error{kind;hint;service;causeError;constructor(e,t,r){super(r?.cause?`${e}: ${t}: ${r.cause.message}`:`${e}: ${t}`);this.name="DevctlError",this.kind=e,this.hint=r?.hint??"",this.service=r?.service??"",this.causeError=r?.cause}exitCode(){switch(this.kind){case"configuration":case"configuration_missing":case"service_not_found":case"dependency":return 2;case"authentication":case"token":case"iap":return 3;case"authorization":case"impersonation":return 4;case"process_start":return 5;case"health_check":return 6;case"proxy":return 7;default:return 1}}}});function Nl(e){return e>0?e:300}function Sp(){return{enabled:!1,paths:[],debounce_ms:300,ignore:[...Ns]}}function Cp(){return{enabled:void 0,host:"",port:""}}function Fs(){return{type:"",identity:{type:"",service_account:""},audience:"",service_account:"",client_id:"",client_secret:"",credentials:"",headers:{}}}function Wn(e){return(e.transport??"").toLowerCase()==="grpc"}function Li(){return{args:[],shell:!1}}function Tp(){return{vars:{},required:[],defaults:{}}}function Ep(){return{type:"",url:"",address:"",command:Li(),interval_seconds:0,timeout_seconds:0,start_period_seconds:0,unhealthy_threshold:3,healthy_reset_threshold:10}}function lr(e){return typeof e==="string"?e:e.service}function zn(e){return typeof e==="string"?"service_started":e.condition||"service_started"}function Fl(e){return zn(e)==="service_healthy"?`${lr(e)} (healthy)`:lr(e)}function Rp(){return{type:"",mode:"",service_account:"",config:{}}}function qn(){return{extends:"",description:"",command:Li(),shell:!1,working_dir:"",dependencies:[],ports:[],environment:Tp(),health:Ep(),identity:Rp(),logs:{stdout:!1,stderr:!1},restart:{policy:"",max_retries:0,backoff_seconds:0},startup:{wait_for_healthy:!1,timeout_seconds:0},capabilities:[],proxy:[],expose:Cp(),container:void 0,watch:Sp(),hooks:{pre_start:Li(),post_start:Li()}}}function Io(){return{version:1,project:{name:""},google:{project_id:"",region:""},profiles:{},templates:{},services:{},tasks:{},proxy:{enabled:!1,gateway:!1,credentials:"",listen:{host:Dt,port:0},token_endpoint:{enabled:!1,host:"",port:0},routes:[]},logs:{max_memory_events:Y_,persistence:{enabled:!0,directory:"~/.devctl/logs",retention_days:J_,max_session_logs:0}},telemetry:{otlp:{enabled:!1,listen:{host:Dt,port:K_}}},web:{enabled:!1,listen:{host:Dt,port:V_}},auth:{refresh_threshold_seconds:cy},shutdown:{grace_seconds:ly},ui:{theme:"system",keymap:{}},secrets:{extra_markers:[],extra_patterns:[]},doctor:{tools:[]},plugins:[],environment:{sources:[],secrets:{}},provenance:{},repoRoot:"",configPath:""}}function Gn(e){return e.args.length===0||e.args.length===1&&(e.args[0]??"").trim()===""}function Hs(e){if(e.type!=="")return e.type;return e.mode}function Tn(e){let t=Hs(e).toLowerCase();return t==="service"||t==="service_account"}function uy(e){let t=Hs(e).toLowerCase();return t==="user"||t===""}function $l(e){if(e.policy!==""){if(e.policy==="always"||e.policy==="on_failure"||e.policy==="never")return e.policy;return e.policy}if(e.enabled===!0)return"on_failure";return"never"}function Kn(e){let t=e.host===""?Dt:e.host;if(e.port===0)return t;return`${t}:${e.port}`}function dy(e){if(e.refresh_threshold_seconds<=0)return cy;return e.refresh_threshold_seconds}function Hl(e){if(e.stop_services_on_exit===void 0)return!0;return e.stop_services_on_exit}function Vn(e){if(e.grace_seconds<=0)return ly;return e.grace_seconds}function py(e){if(!e.logs.stdout&&!e.logs.stderr)return!0;return e.logs.stdout}function fy(e){if(!e.logs.stdout&&!e.logs.stderr)return!0;return e.logs.stderr}function Do(e,t){return e.find((r)=>r.name===t)}function my(e){return e[0]}var Ii=1,Dl="never",Ol="on_failure",Ml="always",Ns,K_=4318,V_=18900,$s=8080,ly=10,cy=300,Y_=50000,J_=14,Dt="127.0.0.1";var Ke=A(()=>{Ns=["**/node_modules/**","**/.git/**"]});var Yt=".devctl",_r="config.yaml";import{basename as X_}from"path";function Yn(e,t=""){return{name:X_(e),project:t,profile:"",sa:"",audience:"",proxyPort:$s}}function Ul(e,t=$s){let r=Number(e);return Number.isFinite(r)&&r>0?r:t}function hy(e){let t=e;return`# yaml-language-server: $schema=https://raw.githubusercontent.com/amr-m-abdelgawad/devctl/main/schema/devctl.config.schema.json
|
|
3
|
+
var A=(e,t,r)=>()=>{if(e)try{t=e(e=0)}catch(n){r=[n]}if(r)throw r[0];return t};function Fg(e,t=""){if(t==="MetadataLookupWarning")return!0;return e.includes("MetadataLookupWarning")||e.startsWith("received unexpected error =")}function Ya(){if(Ng)return;Ng=!0;let e=process.emitWarning.bind(process);process.emitWarning=(t,...r)=>{let n=F1(r[0]),o=N1(t);if(Fg(o,n))return;e(t,...r)}}function $g(){let e=process.stderr.write.bind(process.stderr);return process.stderr.write=(t,r,n)=>{let o=$1(t);if(Fg(o)){let i=typeof r==="function"?r:typeof n==="function"?n:void 0;if(typeof i==="function")i();return!0}if(typeof r==="function")return e(t,r);return e(t,r,n)},()=>{process.stderr.write=e}}function N1(e){if(typeof e==="string")return e;if(e instanceof Error)return e.message;return String(e)}function F1(e){if(typeof e==="string")return e;if(e&&typeof e==="object"&&"type"in e&&typeof e.type==="string")return e.type;return""}function $1(e){if(typeof e==="string")return e;if(e instanceof Uint8Array)return new TextDecoder().decode(e);return""}var Ng=!1;import{createHash as H1}from"crypto";import{resolve as U1}from"path";function Tr(e){let t=U1(e),r=process.platform==="win32"?t.toLowerCase():t;return H1("sha256").update(r).digest("hex").slice(0,j1)}var j1=16;var Ja=()=>{};function kd(e){let t=e.indexOf("Z-"),r=t>=0?e.slice(0,t+1):e,n=r.indexOf("T");if(n<0||!r.endsWith("Z"))return;let o=r.slice(0,n),i=r.slice(n+1,-1).replace(/-/g,":"),s=new Date(`${o}T${i}Z`);return Number.isNaN(s.getTime())?void 0:s}function Dd(e=process.platform){return e==="darwin"}function sR(e=process.platform){return Dd(e)?"cmd":"ctrl"}function hi(e,t=process.platform){return`${sR(t)}+${e}`}function aR(e=process.platform){return Dd(e)?"command":"ctrl"}function jt(e,t=process.platform){return`${aR(t)}+${e}`}function wo(e){return e.replace(/\bcmd\b/gi,"command")}function rn(e,t=process.platform){let r=Dd(t),n=Boolean(e.meta||e.super),o=Boolean(e.ctrl);return r?n&&!o:o&&!n}function kn(e=process.platform){return hi("c",e)}function lR(e=process.platform){return{leader:hi("x",e),command_list:hi("p",e),command:"/",help:"?",search:"f",quit:"q",services:"s",logs:"l",auth:"a",proxy:"p",doctor:"d",config:"c",setup:"u",refresh:"r",restart:"R",find:"f",fullscreen:"z",confirm:"enter",cancel:"esc",select:"space",interrupt:"escape",copy:kn(e)}}function Kg(){return{theme:"devctl",leader_timeout:2000,font_size:14,keybinds:{...cR},scroll_speed:3,scroll_acceleration:{enabled:!1},diff_style:"auto",cursor:{style:"block",blinking:!0},mouse:!0,attention:{enabled:!1,notifications:!0,sound:!0,volume:0.4,sound_pack:"default",sounds:{}},log_timestamps:!0,log_metadata:!0,mcp_enabled:!1}}function uR(e){if(e===""||e==="none")return[];return e.split(",").flatMap((t)=>{let r=t.trim();if(r===""||r==="none"||/\s/.test(r))return[];let n=r.toLowerCase().split("+"),o=n[n.length-1]??"";return[{name:o==="return"?"return":o,ctrl:n.includes("ctrl")||n.includes("control"),shift:n.includes("shift"),meta:n.includes("meta")||n.includes("cmd")||n.includes("super"),alt:n.includes("alt")||n.includes("option")}]})}function Hn(e,t){return uR(t).some((n)=>(e.name??"").toLowerCase()===n.name&&Boolean(e.ctrl)===n.ctrl&&Boolean(e.shift)===n.shift&&Boolean(e.meta||e.super)===n.meta&&Boolean(e.option??e.alt)===n.alt)}var Id=2000,gi=14,Gg="DEVCTL_TUI_CONFIG",cR;var el=A(()=>{cR=lR()});function Ce(e,t,r){return{type:e,timestamp:new Date().toISOString(),service:t,payload:r}}class Nd{subs=new Map;nextID=0;buffer=[];maxBuf;constructor(e){this.maxBuf=e>0?e:1024}subscribe(e,t=[]){this.nextID+=1;let r=this.nextID;return this.subs.set(r,{types:new Set(t),handler:e}),()=>{this.subs.delete(r)}}publish(e){let t=e.timestamp===""?{...e,timestamp:new Date().toISOString()}:e;if(this.buffer.length>=this.maxBuf)this.buffer=this.buffer.slice(1);this.buffer.push(t);for(let r of this.subs.values())if(r.types.size===0||r.types.has(t.type))r.handler(t)}recent(){return[...this.buffer]}}var Jg="ServiceStarted",al="ServiceStopped",ll="ServiceFailed",Xg="ServiceStateChanged",Qg="ServiceHealthChanged",yi="LogReceived",bi="TokenRefreshed",ko="TokenRefreshFailed",Md="AuthenticationChanged",Zg="ProxyStarted",ev="ProxyStopped",Cs="ProxyRequest",cl="ConfigurationChanged",Ts="ConfigurationReloadFailed",tv="SessionRecovered";var rv=5000,nv=500,Fd=16384,$d=65536,qt=1e6,Hd="TRACE",Ud="DEBUG",jd="INFO",Bd="WARN",Wd="ERROR",zd="FATAL",So="UNKNOWN";function ul(e){return e.length>16384?e.slice(0,16384):e}function Le(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function hr(e,t=0){if(t>=8)return ov(e);if(e===void 0)return null;if(typeof e==="string")return ul(e);if(e===null||typeof e==="boolean")return e;if(typeof e==="number")return Number.isFinite(e)?e:null;if(typeof e==="bigint")return Number(e);if(Array.isArray(e))return e.slice(0,32).map((r)=>hr(r,t+1));if(Le(e)){let r={},n=Object.entries(e).slice(0,64);for(let[o,i]of n)r[o]=hr(i,t+1);return r}return ov(e)}function Es(e){if(!Le(e))return{};let t={},r=Object.entries(e).slice(0,64);for(let[n,o]of r)t[n]=hr(o);return t}function gr(e){if(e===null)return"null";if(typeof e==="string")return e;if(typeof e==="number"||typeof e==="boolean")return String(e);try{return JSON.stringify(e)}catch{return"[unserializable]"}}function dl(e,t=0){if(t>=8)return gr(e);if(e===null||typeof e==="string"||typeof e==="number"||typeof e==="boolean")return gr(e);if(Array.isArray(e))return e.map((r)=>dl(r,t+1)).join(" ");return Object.entries(e).map(([r,n])=>`${r} ${dl(n,t+1)}`).join(" ")}function Gd(e,t=64){let r=[],n=Object.entries(e).slice(0,t);for(let[o,i]of n)r.push(`${o}=${yR(gr(i))}`);return r.join(" ")}function yR(e){if(e===""||/[\s="]/.test(e))return`"${e.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`;return e}function ov(e){if(typeof e==="string")return ul(e);try{return ul(JSON.stringify(e)??String(e))}catch{return ul(String(e))}}var pl=8,qd=64,iv=32;function ki(e){if(e>=_s&&e<=Kd)return zd;if(e>=Un)return Wd;if(e>=Co)return Bd;if(e>=xi)return jd;if(e>=Rs)return Ud;if(e>=wi)return Hd;return So}function Ps(e){let t=e.trim().toUpperCase();if(t===Hd||t==="TRACE")return wi;if(t===Ud||t==="DBG"||t==="DEBUG")return Rs;if(t===jd||t==="INFORMATION"||t==="NOTICE"||t==="INFORMATIONAL")return xi;if(t===Bd||t==="WARNING"||t==="WARN")return Co;if(t===Wd||t==="ERR"||t==="ERROR")return Un;if(t===zd||t==="CRITICAL"||t==="PANIC"||t==="EMERGENCY"||t==="ALERT"||t==="FATAL")return _s;return yt}function Br(e){if(typeof e==="number"&&Number.isFinite(e))return av(e);if(typeof e==="string"&&e.trim()!==""){let t=Ps(e);if(t!==yt)return t;let r=Number(e);if(Number.isFinite(r))return av(r)}return}function lv(e){if(typeof e==="number"&&Number.isFinite(e))return sv(Math.floor(e));if(typeof e==="string"&&e.trim()!==""){let t=e.trim().toUpperCase(),r=Number(t);if(Number.isFinite(r))return sv(Math.floor(r));let n=t.startsWith("SEVERITY_NUMBER_")?t.slice(16):t,o=/^([A-Z]+?)([2-4])?$/.exec(n);if(o){let i=IR[o[1]??""];if(i!==void 0)return i+(o[2]?Number(o[2])-1:0)}}return yt}function sv(e){return e>=wi&&e<=Kd?e:yt}function Si(e){return e>=Un}function cv(e,t){let r=Ps(t);if(r===yt)return!0;return(e===yt?xi:e)>=r}function uv(e){return e===So?"\u2014":e}function av(e){let t=LR[e];if(t!==void 0)return t;if(e>=wi&&e<=Kd)return Math.floor(e);return}function dv(e){if(e<=TR)return _s;if(e<=ER)return Un;if(e===RR)return Co;if(e===_R||e===PR)return xi;if(e===AR)return Rs;return}var yt=0,wi=1,Rs=5,xi=9,Co=13,Un=17,_s=21,Kd=24,bR=10,wR=20,xR=30,kR=40,SR=50,CR=60,TR=0,ER=3,RR=4,_R=5,PR=6,AR=7,LR,IR;var Ci=A(()=>{LR={[bR]:wi,[wR]:Rs,[xR]:xi,[kR]:Co,[SR]:Un,[CR]:_s};IR={TRACE:wi,DEBUG:Rs,INFO:xi,WARN:Co,ERROR:Un,FATAL:_s}});function sr(e){return fv(e,32)}function Sn(e){return fv(e,16)}function Vd(){return mv(16)}function hl(){return mv(8)}function Yd(e){let t=e.trim().split("-");if(t.length!==4)return;let[r,n,o,i]=t;if(r!=="00"||!n||!o||!i)return;if(!sr(n)||!Sn(o)||!/^[0-9a-f]{2}$/i.test(i))return;return{traceId:n.toLowerCase(),spanId:hl(),parentSpanId:o.toLowerCase(),traceFlags:Number.parseInt(i,16)}}function gl(e){let t=(e.traceFlags&255).toString(16).padStart(2,"0");return`00-${e.traceId}-${e.spanId}-${t}`}function pv(e){if(e.traceparent){let n=Yd(e.traceparent);if(n){let o=e.requestId&&e.requestId!==""?e.requestId:n.traceId;return{...n,requestId:o}}}let t=(e.requestId??"").trim(),r=Vd();return{traceId:r,spanId:hl(),traceFlags:1,requestId:t===""?r:t}}function fv(e,t){if(e.length!==t)return!1;return/^[0-9a-f]+$/i.test(e)}function mv(e){let t=new Uint8Array(e);crypto.getRandomValues(t);let r="";for(let n of t)r+="0123456789abcdef"[n>>4&15],r+="0123456789abcdef"[n&15];return r}var fl=32,ml=16,Gt="devctl.request_id";function Ti(e){if(!Le(e))return hr(e);if(typeof e.stringValue==="string")return e.stringValue;if(e.intValue!==void 0&&e.intValue!==null){let n=Number(e.intValue);if(Number.isSafeInteger(n))return n;return typeof e.intValue==="string"?e.intValue:String(e.intValue)}if(typeof e.doubleValue==="number")return e.doubleValue;if(typeof e.boolValue==="boolean")return e.boolValue;if(typeof e.bytesValue==="string")return e.bytesValue;let t=Le(e.arrayValue)?e.arrayValue.values:void 0;if(Array.isArray(t))return t.map((n)=>Ti(n));let r=Le(e.kvlistValue)?e.kvlistValue.values:void 0;if(Array.isArray(r))return jn(r);return hr(e)}function Jd(e){if(!Array.isArray(e)||e.length===0)return!1;return e.every((t)=>Le(t)&&typeof t.key==="string"&&t.value!==void 0)}function jn(e){let t={};if(!Jd(e))return t;for(let r of e){let n=r.key;if(typeof n==="string"&&n!=="")t[n]=Ti(r.value)}return t}function Xd(e,t){let r=Le(e)?jn(e.attributes):{},n=typeof r["service.name"]==="string"&&r["service.name"]!==""?r["service.name"]:t;return{...r,"service.name":n}}function Qd(e){if(!Le(e))return;let t=typeof e.name==="string"?e.name:"";if(t==="")return;let r=typeof e.version==="string"&&e.version!==""?e.version:void 0;return{name:t,version:r}}function nn(e){if(typeof e==="number"&&Number.isFinite(e)&&e>0)return e;if(typeof e==="string"&&e.trim()!==""){let t=Number(e);if(Number.isFinite(t)&&t>0)return t}return}var vl=()=>{};function vv(e){let t=e/qt,r=new Date(t);if(Number.isNaN(r.getTime()))return new Date(0).toISOString();return r.toISOString()}function yv(e){let t=Date.parse(e);if(Number.isNaN(t))return Date.now()*qt;return t*qt}function Kt(e){return MR(e.body,e.attributes)}function MR(e,t){let r=NR(e);if(typeof e==="string"&&e!==""){let i=hv(t,e);return i===""?e:`${e} ${i}`}if(r!=="")return r;let n=hv(t,""),o=Gd(wv(t,HR()),gv);if(n!==""&&o!=="")return`${n} ${o}`;if(n!=="")return n;return o}function bv(e,t){let r={};if(e!==""&&e!==null)r.body=e;if(Object.keys(t).length>0)r.attributes=t;try{return JSON.stringify(r,null,2)}catch{return gr(e)}}function As(e){return[Kt(e),dl(e.attributes),e.raw??"",e.service,e.traceId??"",e.spanId??"",e.identity??"",Ei(e)].join(" ")}function Ei(e){let t=e.attributes[Gt];if(typeof t==="string"&&t!=="")return t;return e.traceId??""}function NR(e){if(typeof e==="string")return e;if(e===null)return"";if(typeof e==="number"||typeof e==="boolean")return String(e);if(Array.isArray(e))return gr(e);return Gd(wv(e),gv)}function wv(e,t=new Set){let r={};for(let[n,o]of Object.entries(e))if(FR(n,o,t))r[n]=o;return r}function FR(e,t,r){if(r.has(e)||OR.has(e))return!1;if(t===null||t==="")return!1;if(typeof t==="object")return!1;if(typeof t==="string"&&(t.length>DR||sr(t)||Sn(t)))return!1;return!0}function Zd(e){return{method:yl(e,xv),route:yl(e,kv),status:yl(e,Sv),namespaced:$R.some((t)=>yl(e,[t])!==void 0)}}function hv(e,t){let{method:r,route:n,status:o,namespaced:i}=Zd(e),s=[r,n,o].filter((l)=>l!==void 0&&l!=="");if(!i&&s.length<2)return"";return s.filter((l)=>t===""||!t.includes(l)).join(" ")}function HR(){return new Set([...xv,...kv,...Sv])}function yl(e,t){for(let r of t){let n=e[r];if(typeof n==="string"&&n!=="")return n;if(typeof n==="number"&&Number.isFinite(n))return String(n)}return}var gv=6,DR=40,OR,xv,kv,Sv,$R;var Ls=A(()=>{OR=new Set(["shape","seq","pid","ppid","tid","time","ts","timestamp","@timestamp","timeUnixNano","observedTimeUnixNano","trace_id","traceId","span_id","spanId","traceparent","ecs.version","version","host","facility","logger","caller","name","level","lvl","severity","severityText","severityNumber","severity_text",Gt]);xv=["http.request.method","http.method","method","request_method"],kv=["http.route","url.path","path","route","request_uri"],Sv=["http.status_code","http.response.status_code","status","status_code"],$R=["http.request.method","http.method","http.route","url.path","http.status_code","http.response.status_code"]});class Rr{nameMarkers;patterns;constructor(e,t){this.nameMarkers=[...Cv,...e],this.patterns=t.flatMap((r)=>{try{return[new RegExp(r)]}catch{return[]}})}update(e,t){this.nameMarkers=[...Cv,...e],this.patterns=t.flatMap((r)=>{try{return[new RegExp(r)]}catch{return[]}})}isSecretName(e){let t=e.toUpperCase();return this.nameMarkers.some((r)=>t.includes(r.toUpperCase()))}redactValue(e,t){if(t==="")return t;if(this.isSecretName(e))return"********";if(this.patterns.some((r)=>r.test(t)))return"********";return t}redactMap(e){let t={};for(let[r,n]of Object.entries(e))t[r]=this.redactValue(r,n);return t}redactText(e){if(e==="")return e;let t=e;for(let r of this.patterns)t=t.replace(r,"********");return UR(t)}}function UR(e){let t=e.toLowerCase(),r="authorization: bearer ",n=t.indexOf("authorization: bearer ");if(n>=0)return Tv(e,n+22);let o=t.indexOf("bearer ");if(o<0)return e;return Tv(e,o+7)}function Tv(e,t){let r=t;while(r<e.length&&!jR(e[r]??""))r+=1;return e.slice(0,t)+"********"+e.slice(r)}function jR(e){return e===" "||e==="\t"||e===`
|
|
4
|
+
`||e==="\r"}var Cv,bl="********";var To=A(()=>{Cv=["PASSWORD","SECRET","TOKEN","PRIVATE_KEY","CLIENT_SECRET","API_KEY","CREDENTIAL","ACCESS_KEY","AUTH_KEY"]});function WR(e,t){if(t==="")return!1;if(e.isSecretName(t))return!0;let r=t.split(/[./:_-]/).filter((n)=>n!=="").pop()??t;return e.isSecretName(r)||BR.has(r.toLowerCase())}function wl(e,t,r="",n=0){if(n>=pl)return bl;if(WR(e,r))return bl;if(typeof t==="string")return e.redactText(t);if(t===null||typeof t==="number"||typeof t==="boolean")return t;if(Array.isArray(t))return t.slice(0,iv).map((s)=>wl(e,s,r,n+1));let o={},i=Object.entries(t).slice(0,qd);for(let[s,a]of i)o[s]=wl(e,a,s,n+1);return o}function Is(e,t){let r={},n=Object.entries(t).slice(0,qd);for(let[o,i]of n)r[o]=wl(e,i,o);return r}function xl(e,t){return{...t,body:wl(e,t.body),attributes:Is(e,t.attributes),resource:{...Is(e,t.resource),"service.name":t.resource["service.name"]},raw:t.raw===void 0?void 0:e.redactText(t.raw),identity:t.identity}}function kl(e,t){return{...t,attributes:Is(e,t.attributes),events:t.events.map((r)=>({...r,attributes:Is(e,r.attributes)})),resource:{...Is(e,t.resource),"service.name":t.resource["service.name"]},status:{...t.status,message:t.status.message===void 0?void 0:e.redactText(t.status.message)}}}var BR;var ep=A(()=>{To();BR=new Set(["authorization","password","passwd","cookie","set-cookie","api_key","apikey","token","secret","access_token","refresh_token","private_key","client_secret"])});function tp(e,t,r){let n=e.timestamp&&e.timestamp!==""?e.timestamp:vv(t.timeUnixNano??e.timeUnixNano??Date.now()*1e6),o=t.timeUnixNano??e.timeUnixNano??yv(n),i=zR(e,t),s={...Es(t.attributes??{}),...Es(e.attributes??{})},a=e.request_id||t.request_id;if(a&&s[Gt]===void 0)s[Gt]=a;let l=qR(e,t),c=(e.severityText||e.level||t.severityText||t.level||(l===yt?So:ki(l))).toUpperCase(),u=GR(e.traceId||t.traceId||(a&&sr(a)?a:void 0)),d=KR(e.spanId||t.spanId),{service:f,pid:p}=e,m=e.resource??t.resource??{"service.name":f,...p>0?{"process.pid":p}:{}};if(m["service.name"]===void 0)m["service.name"]=f;return{seq:r,timeUnixNano:o,observedTimeUnixNano:t.observedTimeUnixNano??e.observedTimeUnixNano,severityNumber:l,severityText:c,body:hr(i),attributes:s,traceId:u,spanId:d,traceFlags:e.traceFlags??t.traceFlags,resource:m,scope:e.scope??t.scope,service:f,source:e.source,raw:t.raw??e.raw,timestamp:n,stream:e.stream,identity:e.identity}}function zR(e,t){if(e.body!==void 0)return e.body;if(t.body!==void 0)return t.body;if(t.message!==void 0)return t.message;return e.message??""}function qR(e,t){if(e.severityNumber!==void 0&&e.severityNumber!==yt)return e.severityNumber;let r=e.severityText||e.level;if(r){let o=Ps(r);if(o!==yt)return o}if(t.severityNumber!==void 0&&t.severityNumber!==yt)return t.severityNumber;let n=t.severityText||t.level;if(n)return Ps(n);return yt}function GR(e){if(!e)return;return sr(e)?e.toLowerCase():e}function KR(e){if(!e)return;return Sn(e)?e.toLowerCase():e}var Ev=A(()=>{Ls();Ci()});function Wr(e){return{ok:!0,value:e}}function VR(e){let t={text:e,index:0},r=op(t,0);if(!r.ok)return;if(on(t),t.index!==e.length)return;return r.value}function Rv(e){let t=VR(e);return Le(t)?t:void 0}function op(e,t){if(on(e),t>=pl)return Vt;let r=e.text[e.index];if(r==="{")return YR(e,t);if(r==="[")return JR(e,t);if(r==="'"||r==='"')return _v(e);if(r==="-"||t_(r))return Pv(e);return QR(e)}function YR(e,t){if(e.index+=1,on(e),e.text[e.index]==="}")return e.index+=1,Wr({});let r={};while(e.index<e.text.length){let n=XR(e);if(n===void 0)return Vt;if(on(e),e.text[e.index]!==":")return Vt;e.index+=1;let o=op(e,t+1);if(!o.ok)return Vt;r[n]=o.value,on(e);let i=e.text[e.index];if(i===","){if(e.index+=1,on(e),e.text[e.index]==="}")return e.index+=1,Wr(r)}else if(i==="}")return e.index+=1,Wr(r);else return Vt}return Vt}function JR(e,t){if(e.index+=1,on(e),e.text[e.index]==="]")return e.index+=1,Wr([]);let r=[];while(e.index<e.text.length){let n=op(e,t+1);if(!n.ok)return Vt;r.push(n.value),on(e);let o=e.text[e.index];if(o===","){if(e.index+=1,on(e),e.text[e.index]==="]")return e.index+=1,Wr(r)}else if(o==="]")return e.index+=1,Wr(r);else return Vt}return Vt}function XR(e){on(e);let t=e.index,r=_v(e);if(r.ok)return r.value;e.index=t;let n=Pv(e);if(n.ok)return String(n.value);return e.index=t,ZR(e)}function _v(e){let t=e.text[e.index];if(t!=="'"&&t!=='"')return Vt;e.index+=1;let r="";while(e.index<e.text.length){let n=e.text[e.index];if(n===t)return e.index+=1,Wr(r);if(n==="\\"){e.index+=1;let o=e.text[e.index];if(o===void 0)return Vt;r+=e_(o),e.index+=1}else r+=n,e.index+=1}return Vt}function Pv(e){rp.lastIndex=e.index;let t=rp.exec(e.text);if(!t)return Vt;let r=Number(t[0]);if(!Number.isFinite(r))return Vt;return e.index=rp.lastIndex,Wr(r)}function QR(e){if(Ri(e,"True")||Ri(e,"true"))return Wr(!0);if(Ri(e,"False")||Ri(e,"false"))return Wr(!1);if(Ri(e,"None")||Ri(e,"null"))return Wr(null);return Vt}function ZR(e){np.lastIndex=e.index;let t=np.exec(e.text);if(!t)return;return e.index=np.lastIndex,t[0]}function Ri(e,t){if(!e.text.startsWith(t,e.index))return!1;let r=e.text[e.index+t.length];if(r!==void 0&&r_(r))return!1;return e.index+=t.length,!0}function on(e){let{text:t}=e;while(e.index<t.length){let r=t[e.index];if(r!==" "&&r!=="\t"&&r!==`
|
|
5
|
+
`&&r!=="\r")return;e.index+=1}}function e_(e){if(e==="n")return`
|
|
6
|
+
`;if(e==="t")return"\t";if(e==="r")return"\r";return e}function t_(e){return e!==void 0&&e>="0"&&e<="9"}function r_(e){return e>="0"&&e<="9"||e>="A"&&e<="Z"||e>="a"&&e<="z"||e==="_"}var Vt,rp,np;var Av=A(()=>{Vt={ok:!1},rp=/-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/y,np=/[A-Za-z_][A-Za-z0-9_]*/y});function Mv(){return{name:"default",parse:(e)=>ap(e)}}function Nv(e){if(e.length<=Fd)return e;return e.slice(0,Fd)}function ap(e){let t=lp(e);if(t)return t;return{body:e,attributes:{},severityNumber:Ov(e),severityText:ki(Ov(e)),request_id:b_(e)||void 0,raw:e}}function lp(e){let t=i_(e);if(!t)return;return a_(t.value,t.raw)??u_(t.value,t.raw)??d_(t.value,t.raw)??p_(t.value,t.raw)}function i_(e){let t=e.trim();if(t.length>$d)return;if(t.startsWith("{")&&t.endsWith("}"))return Iv(t,t);let r=t.indexOf("{"),n=t.lastIndexOf("}");if(r<=0||n<=r)return;let o=t.slice(r,n+1);if(o.length>$d)return;return Iv(o,t)}function Iv(e,t){let r=s_(e)??Rv(e);if(!r)return;return{value:r,raw:t}}function s_(e){try{let t=JSON.parse(e);return Le(t)?t:void 0}catch{return}}function a_(e,t){if(!l_(e))return;let r=jn(e.attributes),n=e.body===void 0?c_(r):Ti(e.body),o=Br(e.severityNumber)??Br(e.severityText)??Br(e.severity_text),i=El(e,Sl,fl)??Dv(r,Sl),s=El(e,Cl,ml)??Dv(r,Cl);return{body:n,attributes:r,severityNumber:o,severityText:typeof e.severityText==="string"?e.severityText:void 0,traceId:i,spanId:s,timeUnixNano:nn(e.timeUnixNano),observedTimeUnixNano:nn(e.observedTimeUnixNano),raw:t}}function l_(e){if(e.timeUnixNano!==void 0||e.observedTimeUnixNano!==void 0)return!0;if(Le(e.body)&&(e.body.stringValue!==void 0||e.body.intValue!==void 0||e.body.doubleValue!==void 0||e.body.boolValue!==void 0))return!0;return Jd(e.attributes)}function c_(e){return Fv(e)??""}function u_(e,t){let r=Ro(e.metric_name);if(r===void 0)return;let n=Ro(e.metric_type),o=Ds(e.value);if(n===void 0&&o===void 0)return;let i=Ro(e.unit),s=o===void 0?void 0:i===void 0?String(o):`${o} ${i}`,a=Le(e.attributes)?Es(e.attributes):{},l=up([r,n,s,Fv(a)]),{attributes:c}=cp(e,["metric_name","metric_type","value","unit","attributes"]);return{body:l,attributes:{...c,...a},raw:t}}function d_(e,t){if(Tl(e,sp)!==void 0)return;let r=Ro(e.request),n=r===void 0?{}:g_(r),o=Ro(Eo(e,["request_method","method","http_method","verb"]))??n.method,i=Ro(Eo(e,["request_uri","uri","url","path","request_path","api_url"]))??n.uri,s=Ds(Eo(e,["status","status_code","statusCode","http_status","response_status"])),a=Ro(Eo(e,["remote_ip","remote_addr","client_ip"]));if(!(o!==void 0&&i!==void 0&&(s!==void 0||a!==void 0||r!==void 0))&&!(i!==void 0&&s!==void 0))return;let u=Ds(Eo(e,["body_bytes_sent","bytes_sent","bytes"])),d=Ds(Eo(e,["request_time","duration","duration_seconds"])),f=Ds(Eo(e,["request_time_ms","latency_ms","duration_ms"])),p=u===void 0?void 0:`${u}B`,m=f!==void 0?`${f}ms`:d===void 0?void 0:`${d}s`,{attributes:h,traceId:g,spanId:w,requestId:v,severityNumber:S}=cp(e,[]);return{body:up([a,o,i,s===void 0?void 0:String(s),p,m]),attributes:h,severityNumber:S??(s===void 0?void 0:h_(s)),traceId:g,spanId:w,request_id:v,raw:t}}function p_(e,t){let r=cp(e,[]),n=$v(e,sp);return{body:n!==void 0?hr(n):e.body!==void 0&&e.body!==null?hr(e.body):hr(r.remainder),attributes:r.attributes,severityNumber:r.severityNumber,severityText:r.severityText,traceId:r.traceId,spanId:r.spanId,request_id:r.requestId,timeUnixNano:r.timeUnixNano,raw:t}}function cp(e,t){let r=new Set([...sp,...ip,...Sl,...Cl,...Lv,"traceparent","trace_flags","traceFlags","timeUnixNano","observedTimeUnixNano","timestamp","time","@timestamp","ts","body",...t]),n=typeof e.short_message==="string",o=f_(e,n),i=Tl(e,ip),s=typeof e.traceparent==="string"?Yd(e.traceparent):void 0,a=El(e,Sl,fl)??s?.traceId,l=El(e,Cl,ml)??s?.parentSpanId,c=Tl(e,Lv),u=nn(e.timeUnixNano)??m_(e),d={},f={};for(let[p,m]of Object.entries(e))if(!r.has(p)){let h=hr(m);d[p]=h,f[p]=h}if(c&&f[Gt]===void 0)f[Gt]=c;return{attributes:f,remainder:d,severityNumber:o,severityText:i,traceId:a,spanId:l,requestId:c,timeUnixNano:u}}function f_(e,t){for(let r of ip){let n=e[r];if(n!==void 0&&n!==null){if(t&&typeof n==="number"){let i=dv(n);if(i!==void 0)return i}let o=Br(n);if(o!==void 0)return o}}return}function m_(e){for(let t of["timestamp","time","@timestamp","ts"]){let r=e[t];if(typeof r==="string"&&r!==""){let n=Date.parse(r);if(!Number.isNaN(n))return n*1e6}if(typeof r==="number"&&Number.isFinite(r))return r>1000000000000000?r:r*qt}return}function Fv(e){let{method:t,route:r,status:n}=Zd(e),o=up([t,r,n]);return o===""?void 0:o}function h_(e){if(e>=o_)return Un;if(e>=n_)return Co;return}function g_(e){let t=e.trim().split(/\s+/);return{method:t[0],uri:t[1]}}function Tl(e,t){for(let r of t){let n=e[r];if(typeof n==="string"&&n.trim()!=="")return n}return}function $v(e,t){for(let r of t)if(e[r]!==void 0&&e[r]!==null)return e[r];return}function Eo(e,t){return $v(e,t)}function El(e,t,r){let n=Tl(e,t);if(!n)return;if(r===fl&&sr(n))return n.toLowerCase();if(r===ml&&Sn(n))return n.toLowerCase();return n}function Dv(e,t){for(let r of t){let n=e[r];if(typeof n==="string"&&n!=="")return n}return}function Ro(e){if(typeof e==="string"&&e.trim()!=="")return e;if(typeof e==="number"&&Number.isFinite(e))return String(e);return}function Ds(e){if(typeof e==="number"&&Number.isFinite(e))return e;if(typeof e==="string"&&e.trim()!==""){let t=Number(e);if(Number.isFinite(t))return t}return}function up(e){return e.filter((t)=>t!==void 0&&t!=="").join(" ")}function b_(e){return v_.exec(e)?.[1]??""}function Ov(e){return y_.find((r)=>r.re.test(e))?.level??yt}var sp,ip,Sl,Cl,Lv,n_=400,o_=500,v_,y_;var Hv=A(()=>{vl();Ls();Av();Ci();sp=["message","msg","text","log","event","short_message","shortMessage"],ip=["level","severity","severityText","severity_text","levelname","loglevel","lvl"],Sl=["trace_id","traceId","traceid"],Cl=["span_id","spanId","spanid"],Lv=["request_id","requestId","correlation_id","correlationId",Gt];v_=/(?:x-devctl-request-id|request[_-]?id)[=: ]+([A-Za-z0-9-]+)/i,y_=[{re:/\b(fatal|critical)\b/i,level:Br("FATAL")??yt},{re:/\b(error|err)\b/i,level:Br("ERROR")??yt},{re:/\b(warn|warning)\b/i,level:Br("WARN")??yt},{re:/\b(debug|dbg)\b/i,level:Br("DEBUG")??yt},{re:/\b(trace)\b/i,level:Br("TRACE")??yt},{re:/\b(info|information)\b/i,level:Br("INFO")??yt}]});function Os(e){let t=w_(e);if(t===void 0)return;return new RegExp(t)}function w_(e){if(e.length===0||e.length>200)return;let t={raw:e,i:0,out:[],quantifiers:0,depth:0,lastAtom:"none",groupQuant:[]};if(!Uv(t)||t.i!==e.length||t.depth!==0)return;return t.out.join("")}function Uv(e){while(e.i<e.raw.length){if(e.raw[e.i]===")")return!0;if(!x_(e))return!1}return!0}function x_(e){let t=e.raw[e.i]??"";if(t==="|")return Rl(e,"|","none");if(t==="^")return Rl(e,"^","none");if(t==="$")return Rl(e,"$","none");if(t===".")return Rl(e,".","atom");if(t==="(")return k_(e);if(t==="[")return C_(e);if(t==="*"||t==="+"||t==="?"||t==="{")return S_(e);if(t==="\\")return jv(e);return e.out.push(RegExp.escape(t)),e.i+=1,e.lastAtom="atom",!0}function Rl(e,t,r){return e.out.push(t),e.i+=1,e.lastAtom=r,!0}function k_(e){if(e.i+=1,e.depth+=1,e.depth>2)return!1;if(e.groupQuant.push(!1),e.out.push("(?:"),!Uv(e)||e.raw[e.i]!==")")return!1;e.out.push(")"),e.i+=1,e.depth-=1;let t=e.groupQuant.pop()===!0;return e.lastAtom=t?"quantified-group":"atom",!0}function S_(e){let t=e.raw[e.i]??"";if(t==="{"||e.lastAtom==="none"||e.lastAtom==="quant"||e.lastAtom==="quantified-group")return!1;if(e.quantifiers>=8)return!1;if(t==="*")e.out.push("*");else if(t==="+")e.out.push("+");else if(t==="?")e.out.push("?");else return!1;e.i+=1,e.quantifiers+=1;let r=e.groupQuant.length-1;if(r>=0)e.groupQuant[r]=!0;if(e.raw[e.i]==="?")e.out.push("?"),e.i+=1;return e.lastAtom="quant",!0}function C_(e){if(e.i+=1,e.out.push("["),e.raw[e.i]==="^")e.out.push("^"),e.i+=1;if(e.raw[e.i]==="]")e.out.push(RegExp.escape("]")),e.i+=1;while(e.i<e.raw.length&&e.raw[e.i]!=="]"){let t=e.raw[e.i]??"";if(t==="\\"){if(!jv(e))return!1}else if(t==="-")e.out.push("-"),e.i+=1;else e.out.push(RegExp.escape(t)),e.i+=1}if(e.raw[e.i]!=="]")return!1;return e.out.push("]"),e.i+=1,e.lastAtom="atom",!0}function jv(e){let t=e.raw[e.i+1];if(t===void 0)return!1;if(t==="d")e.out.push("\\d");else if(t==="D")e.out.push("\\D");else if(t==="w")e.out.push("\\w");else if(t==="W")e.out.push("\\W");else if(t==="s")e.out.push("\\s");else if(t==="S")e.out.push("\\S");else if(t==="n")e.out.push("\\n");else if(t==="t")e.out.push("\\t");else if(t==="r")e.out.push("\\r");else if(t==="b")e.out.push("\\b");else if(t==="B")e.out.push("\\B");else e.out.push(RegExp.escape(t));return e.i+=2,e.lastAtom="atom",!0}function _i(e,t){if(e.services&&e.services.length>0&&!e.services.includes(t.service))return!1;if(e.level&&!cv(t.severityNumber,e.level))return!1;if(e.source&&t.source!==e.source)return!1;if(e.since&&t.timestamp<e.since)return!1;if(e.until&&t.timestamp>e.until)return!1;if(e.traceId&&t.traceId!==e.traceId)return!1;if(e.requestId&&Ei(t)!==e.requestId&&t.traceId!==e.requestId)return!1;if(e.attribute){let r=t.attributes[e.attribute.key];if(gr(r??null)!==e.attribute.value)return!1}return!0}function dp(e){if(!e.search)return()=>!0;if(e.regex){let r=Os(e.search);if(r)return(n)=>r.test(As(n))}let t=e.search.toLowerCase();return(r)=>As(r).toLowerCase().includes(t)}function pp(e){let t=dp(e);return(r)=>_i(e,r)&&t(r)}var Bv=A(()=>{Ls();Ci()});function Wv(e){if(!Number.isInteger(e)||(e??0)<=0)return nv;return Math.min(e,rv)}var zv=()=>{};var sn=A(()=>{Ci();vl();Ls();ep();Ev();Hv();Bv();zv()});function T(e,t){return new et(e,t)}function ge(e,t,r){let n=r instanceof Error?r:Error(String(r));return new et(e,t,{cause:n})}function Ie(e,t,r,n=""){return new et(e,t,{hint:r,service:n})}function Al(e,t){return e instanceof et&&e.kind===t}function oy(e){if(e instanceof et)return e.exitCode();return 1}function iy(e){if(e instanceof et)return{error:I(e),kind:e.kind,hint:e.hint,service:e.service};return{error:I(e)}}function sy(e){if(typeof e==="string")return T("general",e);if(e.kind)return new et(e.kind,e.error.replace(`${e.kind}: `,""),{hint:e.hint,service:e.service});return T("general",e.error)}function I(e){if(e instanceof et){if(e.hint!=="")return`${ty(e)} \u2014 ${e.hint}`;return ty(e)}if(e instanceof Error)return e.message;return String(e)}function ty(e){let t=`${e.kind}: `;if(e.message.startsWith(t)){let r=e.message.slice(t.length),n=e.causeError?`: ${e.causeError.message}`:"";if(n!==""&&r.endsWith(n))return r.slice(0,r.length-n.length);return r}return e.message}var ry=1,ee="configuration",Po="configuration_missing",Pi="service_not_found",ny="dependency",Ge="process_start",Bn="authentication",Ao="authorization",zr="token",_l="impersonation",Pl="iap",ar="proxy",wp="health_check",$e="general",et;var ne=A(()=>{et=class et extends Error{kind;hint;service;causeError;constructor(e,t,r){super(r?.cause?`${e}: ${t}: ${r.cause.message}`:`${e}: ${t}`);this.name="DevctlError",this.kind=e,this.hint=r?.hint??"",this.service=r?.service??"",this.causeError=r?.cause}exitCode(){switch(this.kind){case"configuration":case"configuration_missing":case"service_not_found":case"dependency":return 2;case"authentication":case"token":case"iap":return 3;case"authorization":case"impersonation":return 4;case"process_start":return 5;case"health_check":return 6;case"proxy":return 7;default:return 1}}}});function Nl(e){return e>0?e:300}function Sp(){return{enabled:!1,paths:[],debounce_ms:300,ignore:[...Ns]}}function Cp(){return{enabled:void 0,host:"",port:""}}function Fs(){return{type:"",identity:{type:"",service_account:""},audience:"",service_account:"",client_id:"",client_secret:"",credentials:"",headers:{}}}function Wn(e){return(e.transport??"").toLowerCase()==="grpc"}function Li(){return{args:[],shell:!1}}function Tp(){return{vars:{},required:[],defaults:{}}}function Ep(){return{type:"",url:"",address:"",command:Li(),interval_seconds:0,timeout_seconds:0,start_period_seconds:0,unhealthy_threshold:3,healthy_reset_threshold:10}}function lr(e){return typeof e==="string"?e:e.service}function zn(e){return typeof e==="string"?"service_started":e.condition||"service_started"}function Fl(e){return zn(e)==="service_healthy"?`${lr(e)} (healthy)`:lr(e)}function Rp(){return{type:"",mode:"",service_account:"",config:{}}}function qn(){return{extends:"",description:"",command:Li(),shell:!1,working_dir:"",dependencies:[],ports:[],environment:Tp(),health:Ep(),identity:Rp(),logs:{stdout:!1,stderr:!1},restart:{policy:"",max_retries:0,backoff_seconds:0},startup:{wait_for_healthy:!1,timeout_seconds:0},capabilities:[],proxy:[],expose:Cp(),container:void 0,watch:Sp(),hooks:{pre_start:Li(),post_start:Li()}}}function Io(){return{version:1,project:{name:""},google:{project_id:"",region:""},profiles:{},templates:{},services:{},tasks:{},proxy:{enabled:!1,gateway:!1,credentials:"",listen:{host:Ot,port:0},token_endpoint:{enabled:!1,host:"",port:0},routes:[]},logs:{max_memory_events:X_,persistence:{enabled:!0,directory:"~/.devctl/logs",retention_days:Q_,max_session_logs:0}},telemetry:{otlp:{enabled:!1,listen:{host:Ot,port:Y_}}},web:{enabled:!1,listen:{host:Ot,port:J_}},auth:{refresh_threshold_seconds:uy},shutdown:{grace_seconds:cy},ui:{theme:"system",keymap:{}},secrets:{extra_markers:[],extra_patterns:[]},doctor:{tools:[]},plugins:[],environment:{sources:[],secrets:{}},provenance:{},repoRoot:"",configPath:""}}function Gn(e){return e.args.length===0||e.args.length===1&&(e.args[0]??"").trim()===""}function Hs(e){if(e.type!=="")return e.type;return e.mode}function Tn(e){let t=Hs(e).toLowerCase();return t==="service"||t==="service_account"}function dy(e){let t=Hs(e).toLowerCase();return t==="user"||t===""}function $l(e){if(e.policy!==""){if(e.policy==="always"||e.policy==="on_failure"||e.policy==="never")return e.policy;return e.policy}if(e.enabled===!0)return"on_failure";return"never"}function Kn(e){let t=e.host===""?Ot:e.host;if(e.port===0)return t;return`${t}:${e.port}`}function py(e){if(e.refresh_threshold_seconds<=0)return uy;return e.refresh_threshold_seconds}function Hl(e){if(e.stop_services_on_exit===void 0)return!0;return e.stop_services_on_exit}function Vn(e){if(e.grace_seconds<=0)return cy;return e.grace_seconds}function fy(e){if(!e.logs.stdout&&!e.logs.stderr)return!0;return e.logs.stdout}function my(e){if(!e.logs.stdout&&!e.logs.stderr)return!0;return e.logs.stderr}function Do(e,t){return e.find((r)=>r.name===t)}function hy(e){return e[0]}var Ii=1,Dl="never",Ol="on_failure",Ml="always",Ns,Y_=4318,J_=18900,$s=8080,cy=10,uy=300,X_=50000,Q_=14,Ot="127.0.0.1";var Ke=A(()=>{Ns=["**/node_modules/**","**/.git/**"]});var Yt=".devctl",_r="config.yaml";import{basename as Z_}from"path";function Yn(e,t=""){return{name:Z_(e),project:t,profile:"",sa:"",audience:"",proxyPort:$s}}function Ul(e,t=$s){let r=Number(e);return Number.isFinite(r)&&r>0?r:t}function gy(e){let t=e;return`# yaml-language-server: $schema=https://raw.githubusercontent.com/amr-m-abdelgawad/devctl/main/schema/devctl.config.schema.json
|
|
7
7
|
version: 1
|
|
8
8
|
|
|
9
9
|
project:
|
|
@@ -50,8 +50,8 @@ auth:
|
|
|
50
50
|
shutdown:
|
|
51
51
|
stop_services_on_exit: true
|
|
52
52
|
grace_seconds: 10
|
|
53
|
-
`}var Rt;var jl=A(()=>{Ke();Rt=[{id:"repo",title:"Repository",prompt:"Repository root"},{id:"name",title:"Environment",prompt:"Environment / project name"},{id:"project",title:"Google project",prompt:"Google Cloud project"},{id:"auth",title:"Authentication",prompt:"Run gcloud ADC login now? (y/N)"},{id:"sa",title:"Service account",prompt:"Service account email to record (optional)"},{id:"audience",title:"IAP",prompt:"IAP audience to record on a sample route (optional)"},{id:"port",title:"Ports",prompt:"Proxy listen port"},{id:"profile",title:"Profiles",prompt:"Default profile name (optional)"},{id:"write",title:"Validation",prompt:"Write starter configuration"}]});import{existsSync as Ap,mkdirSync as _p,statSync as
|
|
54
|
-
`)}var zl=A(()=>{Ke();jl();ne()});function
|
|
53
|
+
`}var Rt;var jl=A(()=>{Ke();Rt=[{id:"repo",title:"Repository",prompt:"Repository root"},{id:"name",title:"Environment",prompt:"Environment / project name"},{id:"project",title:"Google project",prompt:"Google Cloud project"},{id:"auth",title:"Authentication",prompt:"Run gcloud ADC login now? (y/N)"},{id:"sa",title:"Service account",prompt:"Service account email to record (optional)"},{id:"audience",title:"IAP",prompt:"IAP audience to record on a sample route (optional)"},{id:"port",title:"Ports",prompt:"Proxy listen port"},{id:"profile",title:"Profiles",prompt:"Default profile name (optional)"},{id:"write",title:"Validation",prompt:"Write starter configuration"}]});import{existsSync as Ap,mkdirSync as _p,statSync as eP,writeFileSync as tP}from"fs";import{createInterface as rP}from"readline/promises";import{stdin as nP,stdout as oP}from"process";import{basename as Bl,dirname as Pp,join as En,resolve as iP}from"path";function Lp(e,t){let r=e===""?process.cwd():e;if(t==="")return{repo:r,cfgPath:En(r,Yt,_r)};let n=iP(t);if(!(Ap(n)?eP(n).isDirectory():!/\.ya?ml$/i.test(n))){let i=Pp(n);return{repo:Bl(i)===Yt?Pp(i):i,cfgPath:n}}if(Bl(n)===Yt)return{repo:Pp(n),cfgPath:En(n,_r)};return{repo:n,cfgPath:En(n,Yt,_r)}}function vy(e,t=Bl(e),r="",n="",o=!1){let i=En(e,Yt,_r);if(!o&&Ap(i))throw T(ee,`configuration already exists at ${i}; not overwriting`);return Wl(e,{...Yn(e,r),name:t,profile:n}),i}async function yy(e,t,r="",n=!1){let{repo:o,cfgPath:i}=Lp(t,r);if(!n&&Ap(i)){Jt(`Found existing configuration at ${i}; nothing written.`),Jt("Pass --force to overwrite it, or edit it directly.");return}let s=rP({input:nP,output:oP}),a=async(h,g)=>{let w=g!==""?` [${g}]`:"",v=(await s.question(`${h}${w}: `)).trim();return v===""?g:v},l=0,c=()=>(l+=1,l);if(Jt(`devctl setup \u2014 ${Rt.length} steps`),Jt(""),r==="")await a(`${c()}. Repository root`,o);let u=Yn(o,""),d=await a(`${c()}. ${Rt[1]?.prompt}`,Bl(o));u.name=d;let f=await e.detectGoogle(""),p=await a(`${c()}. ${Rt[2]?.prompt}`,f.projectID);if(u.project=p,Jt(`${c()}. ${Rt[3]?.title}`),!f.adcAvailable){if(Jt(" ADC is not available. Run: gcloud auth application-default login"),(await a(" Run login now? (y/N)","n")).toLowerCase()==="y")try{await e.loginGoogle()}catch(g){Jt(` login failed: ${g instanceof Error?g.message:String(g)}`)}}else if(Jt(" \u2713 Application Default Credentials available"),f.userEmail!=="")Jt(` user: ${f.userEmail}`);u.sa=await a(`${c()}. ${Rt[4]?.prompt}`,""),u.audience=await a(`${c()}. ${Rt[5]?.prompt}`,"");let m=await a(`${c()}. ${Rt[6]?.prompt}`,String($s));u.proxyPort=Ul(m),u.profile=await a(`${c()}. ${Rt[7]?.prompt}`,""),s.close(),Wl(o,u),Jt(""),Jt(`Wrote starter configuration to ${i}`),Jt(`${c()}. Validation`);try{let h=e.load(o,""),g=await e.runDoctor.execute(h);Jt(e.formatDoctor(g))}catch(h){Jt(` configuration is not valid yet: ${h instanceof Error?h.message:String(h)}`),Jt(" edit .devctl/config.yaml and run `devctl config validate`")}}function Wl(e,t){let r=En(e,".devctl");_p(En(r,"services"),{recursive:!0}),_p(En(r,"profiles"),{recursive:!0}),_p(En(r,"proxy"),{recursive:!0}),tP(En(r,"config.yaml"),gy(t))}function Jt(e){process.stdout.write(`${e}
|
|
54
|
+
`)}var zl=A(()=>{Ke();jl();ne()});function vb(){return/\$\{(?:env\.)?([A-Za-z_][A-Za-z0-9_]*)\}/g}function Kp(e){return[...e.matchAll(vb())].map((t)=>t[1]??"")}function yb(e,t){let r=[];return{value:e.replace(vb(),(o,i)=>{let s=t[i];if(s===void 0||s==="")return r.push(i),"";return s}),missing:r}}function Xl(e){let t=e.trim();if(t===""||Kp(t).length===0)return;return t}function bb(e){return/^\$\{(?:env\.)?[A-Za-z_][A-Za-z0-9_]*\}$/.test(e.trim())}function Xn(e){return Object.entries(e.provenance).sort(([t],[r])=>t.localeCompare(r)).flatMap(([t,r])=>{let n=r[r.length-1];if(!n)return[];return[{path:t,value:_A(e,t),...n,shadowed:r.slice(0,-1)}]})}function _A(e,t){let r=e;for(let n of t.split(".")){if(typeof r!=="object"||r===null)return;r=r[n]}return r}function ec(e){if(Tn(e))return Pr({kind:jo,serviceAccount:e.service_account});if(dy(e)&&(e.type!==""||e.mode!==""))return Pr({kind:Zl});let t=(e.type||e.mode).toLowerCase();if(t!=="")return Pr({kind:t,providerConfig:e.config??{}});return Pr({kind:Mi})}function Pn(e){if(e.type.toLowerCase()==="none")return Pr({kind:Mi});let t=e.identity.type.toLowerCase(),r=e.identity.service_account||e.service_account;if(t==="service"||t==="service_account"||e.type==="service_account")return Pr({kind:jo,serviceAccount:r});if(e.type.toLowerCase()==="iap"&&t==="")return Pr({kind:Mi});if(e.type===""&&t==="")return Pr({kind:Mi});return Pr({kind:Zl})}function Pb(e){return e.kind===Zl||e.kind===jo}function Qn(e){if(e.tokenKey!=="")return e.tokenKey;if(e.kind===jo)return`sa:${e.serviceAccount}`;if(e.email!=="")return`user:${e.email}`;return"user"}function Pr(e={}){return{kind:Mi,email:"",serviceAccount:"",project:"",projectSource:"",adcAvailable:!1,providerConfig:{},tokenKey:"",...e}}function Xp(e){let t=new Map,r=(n,o)=>{if(n!=="")t.set(n,(t.get(n)??!1)||o)};for(let n of Object.values(e.services))if(Tn(n.identity)&&n.identity.service_account!=="")r(n.identity.service_account,!0);for(let n of e.proxy.routes){let o=n.auth.type.toLowerCase(),i=n.auth.identity.type.toLowerCase(),s=n.auth.identity.service_account||n.auth.service_account;if(i==="service"||i==="service_account"||o==="service_account")r(s,o!=="none")}return[...t.entries()].map(([n,o])=>({email:n,active:o})).sort((n,o)=>n.email.localeCompare(o.email))}function ln(e){return Xp(e).filter((t)=>t.active).map((t)=>t.email)}function Ab(e,t,r){let n=[];for(let o of t){let i=e.services[o];if(!i)continue;let s=ec(i.identity);if(Tn(i.identity)&&i.identity.service_account===""){n.push({name:o,message:"service account identity is not configured"});continue}if((Pb(s)||i.capabilities.some((l)=>l==="google_api"||l==="iap"||l==="service_identity"))&&!r)n.push({name:o,message:"ADC unavailable"})}return n}function zs(e){if(ln(e).length>0)return!0;if(e.proxy.routes.some((t)=>t.auth.type.toLowerCase()==="iap"))return!0;return Object.values(e.services).some((t)=>{if(Pb(ec(t.identity)))return!0;return t.capabilities.some((r)=>r==="google_api"||r==="iap"||r==="service_identity")})}function Qp(){return{name:"user",accepts:(e)=>!Tn(e),resolve:async(e,t)=>{if(e.type===""&&e.mode==="")return Pr({kind:Mi});return{...await t(),kind:Zl}}}}function Zp(){return{name:"service_account",accepts:(e)=>Tn(e),resolve:async(e,t)=>{if(e.service_account==="")throw T(_l,"service account identity is not configured");return{...await t(),kind:jo,serviceAccount:e.service_account}}}}async function Lb(e,t,r){if(r)for(let n=r.length-1;n>=0;n-=1){let o=r[n];if(o?.accepts(e))return o.resolve(e,t)}if(Tn(e))return Zp().resolve(e,t);return Qp().resolve(e,t)}var Zl="user",jo="service_account",Mi="none";var Gr=A(()=>{Ke();ne()});function vr(){return"devctl 0.8.1"}var Xt="0.8.1",Ys=1;function Jb(e){return e}function Ar(e){return e}function Ui(e){if(e.state===Ve&&e.health===Qt)return Lr;if(e.state===Ve&&e.health===He)return cn;return e.state}function Qs(e){return{name:e,state:Nt,health:Ft,pid:0,ports:{},restarts:0,last_error:"",identity:"",startTime:void 0,cpuPercent:void 0,memoryKB:void 0,profile:"",env_source:"daemon",orphaned:!1}}function Zb(e,t){let r={},n={};for(let a of Object.keys(t))r[a]=0;for(let a of Object.keys(t)){let l=e.services[a]?.dependencies??[];for(let c of l){let u=lr(c);if(!t[u])continue;n[u]=[...n[u]??[],a],r[a]=(r[a]??0)+1}}let o=[],i=Object.keys(t).length,s={};while(i>0){let a=Object.entries(r).filter(([l,c])=>c===0&&!s[l]).map(([l])=>l).sort();if(a.length===0)throw T(ny,"dependency cycle detected while planning startup");o.push(a);for(let l of a){s[l]=!0,i-=1;for(let c of n[l]??[])r[c]=(r[c]??0)-1}}return o}function ff(e,t){if(!e.services[t])throw T(Pi,`unknown service "${t}"`)}function dc(e,t,r){let n={},o=(a)=>{if(n[a])return;ff(e,a),n[a]=!0;for(let l of e.services[a]?.dependencies??[])o(lr(l))};for(let a of t)o(a);let i=Zb(e,n),s=[];return i.forEach((a,l)=>{for(let c of a)s.push({name:c,wave:l+1,dependencies:[...e.services[c]?.dependencies??[]]})}),{profile:r,steps:s,waves:i,blockers:[]}}function Go(e,t){let r={};for(let[i,s]of Object.entries(e.services))for(let a of s.dependencies){let l=lr(a);r[l]=[...r[l]??[],i]}let n={},o=(i)=>{if(n[i])return;ff(e,i),n[i]=!0;for(let s of r[i]??[])o(s)};for(let i of t)o(i);return Object.keys(n)}function ew(e,t){let r=[...Zb(e,t)].reverse().map((o)=>[...o].sort()),n=[];return r.forEach((o,i)=>{for(let s of o)n.push({name:s,wave:i+1,dependencies:[...e.services[s]?.dependencies??[]]})}),{steps:n,waves:r,profile:"",blockers:[]}}function pc(e,t){let r=Object.fromEntries(Go(e,t).map((n)=>[n,!0]));return ew(e,r)}function fc(e,t){let r={};for(let n of t)ff(e,n),r[n]=!0;return ew(e,r)}function tw(e){let t="";if(e.profile!=="")t+=`Profile: ${e.profile}
|
|
55
55
|
|
|
56
56
|
`;t+=`Plan:
|
|
57
57
|
|
|
@@ -59,7 +59,7 @@ shutdown:
|
|
|
59
59
|
`,r+=1;if((e.blockers??[]).length>0){t+=`
|
|
60
60
|
Blocked:
|
|
61
61
|
`;for(let n of e.blockers??[])t+=`- ${n.name}: ${n.message}
|
|
62
|
-
`}return t}function mc(e){return`${e.join(", ")} changed and only take effect after a full \`devctl down && devctl start\`, not a reload`}function
|
|
62
|
+
`}return t}function mc(e){return`${e.join(", ")} changed and only take effect after a full \`devctl down && devctl start\`, not a reload`}function AL(e,t,r){let n={};if(t!==""){let o=e.profiles[t];if(!o)throw T("configuration",`unknown profile "${t}"`);Object.assign(n,o.environment)}if(r.length>0)return{services:Xb(e,r),env:n};if(t==="")return{services:Object.keys(e.services),env:n};return{services:Xb(e,e.profiles[t]?.services??[]),env:n}}function LL(e){let t=Object.keys(e.profiles).sort();return Ar(t[0]??"")}function Ko(e,t){if(t==="")return{};return{...e.profiles[Ar(t)]?.environment??{}}}function hc(e,t){let r=t.services??[],n=t.profile??Ar("");if(r.length===0&&n===""){if(n=t.activeProfile||LL(e),n==="")throw T(ee,"no profile or services given; pass service names or add a profile")}let o=AL(e,n,r);return{services:o.services,env:o.env,profile:n}}function Xb(e,t){let r={},n=[];for(let o of t){if(r[o])continue;if(!e.services[o])throw T("service_not_found",`unknown service "${o}"`);r[o]=!0,n.push(o)}return n}var Qb="UNKNOWN",An="STARTING",Ve="RUNNING",Lr="HEALTHY",cn="UNHEALTHY",Kr="STOPPING",Nt="STOPPED",bt="FAILED",Ir="RESTARTING",Ft="UNKNOWN",Qt="HEALTHY",He="UNHEALTHY";var $t=A(()=>{Ke();ne()});function _w(e){if(e.newer)return`update available ${e.current} \u2192 ${e.latest} ${e.hint}`;if(e.latest!=="")return`${e.current} up to date`;return`${e.current} (latest unavailable)`}function Pw(e){let t=Ew(e.scriptPath),r=Ew(e.execPath);if(!e.standalone&&t.includes("/@amr-m-abdelgawad/devctl/")){if(t.includes("/_npx/"))return{kind:"npx",hint:"npx @amr-m-abdelgawad/devctl@latest"};let n=sI();return{kind:"npm",command:n,hint:n.join(" ")}}if(e.standalone&&r.toLowerCase().includes("/cellar/devctl/"))return{kind:"homebrew",command:["brew","reinstall","--formula","https://raw.githubusercontent.com/amr-m-abdelgawad/devctl/main/homebrew/devctl.rb"],hint:"brew reinstall --formula https://raw.githubusercontent.com/amr-m-abdelgawad/devctl/main/homebrew/devctl.rb"};if(e.standalone)return{kind:"release",hint:"re-download the matching GitHub Release binary \u2014 see docs/installation.md"};if(t.endsWith("/src/bin.ts"))return{kind:"source",hint:"git pull && cd app && bun install"};return{kind:"unknown",hint:`npm install --global ${"@amr-m-abdelgawad/devctl"}@latest # alternatives: Homebrew or the unsigned GitHub Release binaries \u2014 see docs/installation.md`}}function Aw(e,t){let r=Rw(e),n=Rw(t);for(let o=0;o<3;o+=1){let i=(r[o]??0)-(n[o]??0);if(i!==0)return i>0?1:-1}return 0}function sI(){return[process.platform==="win32"?"npm.cmd":"npm","install","--global","@amr-m-abdelgawad/devctl@latest"]}function Ew(e){return e.replaceAll("\\","/")}function Rw(e){return e.replace(/^v/,"").split(".").slice(0,3).map((t)=>{let r=Number.parseInt(t.replace(/[^0-9].*$/,""),10);return Number.isFinite(r)?r:0})}var kc="restart the daemon with `devctl down` then start again";function to(e){if(!Number.isInteger(e))return Gf;return Math.min(VD,Math.max(YD,e))}function Ex(e,t){if(t.length!==1||t<"0"||t>"9")return e;if(e.length>=JD)return t;return`${e}${t}`}function Rx(e){return e.slice(0,-1)}function _x(e,t){if(e==="")return to(t);let r=Number(e);if(!Number.isInteger(r))return to(t);return to(r)}function Xo(e){let t=Number.parseInt(Tr(e).slice(0,KD),16),r=Number.isFinite(t)?t%Tx:0;return Gf+r}function Px(e,t){return t===Xo(e)}var Gf=18700,Tx=600,TG,KD=8,VD=65535,YD=1024,JD=5;var Kf=A(()=>{Ja();TG=Gf+Tx-1});var ro;var sm=A(()=>{ro={procedure:`---
|
|
63
63
|
name: devctl-onboard
|
|
64
64
|
description: Survey a repository \u2014 its runnable services, docker-compose, Terraform, Kubernetes manifests, .env files, task runners \u2014 and author a validated .devctl configuration for it. Use when asked to onboard a repo to devctl, add or fix .devctl/config.yaml, generate devctl services/profiles/proxy routes, or diagnose why a devctl config fails to load.
|
|
65
65
|
---
|
|
@@ -369,7 +369,7 @@ the agent to set it up" a complete path. In that state \`get_status\` reports
|
|
|
369
369
|
arguments reports the missing configuration rather than a parse error. Draft,
|
|
370
370
|
validate the candidate text, write the files, then call \`reload_config\`: setup
|
|
371
371
|
mode clears on the reload that finds a valid configuration.
|
|
372
|
-
`,authoring:"# Authoring rules the loader enforces\n\nThe JSON Schema (`schema/devctl.config.schema.json`) describes the shape.\nThis file describes what the **loader and validator actually reject** \u2014 the\nrules that turn a schema-plausible config into one that fails at\n`devctl config validate`. Check anything you are unsure of here before writing.\n\n---\n\n## Unknown fields are rejected everywhere\n\nNot warned about \u2014 rejected, with the offending path named. These are the\ncomplete allowlists.\n\n**Top level:** `version` `project` `google` `profiles` `templates` `services`\n`tasks` `proxy` `logs` `auth` `shutdown` `ui` `secrets` `doctor` `plugins`\n`environment` `telemetry` `web`\n\n**Service** (and `templates.<name>`, same shape): `extends` `description`\n`command` `shell` `working_dir` `dependencies` `ports` `environment` `health`\n`identity` `logs` `restart` `startup` `capabilities` `proxy` `expose` `container` `watch` `hooks`\n\n| Section | Allowed keys |\n|---|---|\n| `project` | `name` |\n| `google` | `project_id` `region` |\n| `profiles.<name>` | `services` `environment` |\n| `service.health` | `type` `url` `address` `command` `interval_seconds` `timeout_seconds` `start_period_seconds` `unhealthy_threshold` `healthy_reset_threshold` |\n| `service.hooks` | `pre_start` `post_start` |\n| `service.container` | `image` `runtime` `ports` `env` `volumes` |\n| `service.watch` | `enabled` `paths` `debounce_ms` `ignore` |\n| `tasks.<name>` | `command` `shell` `working_dir` `dependencies` `environment` |\n| `service.identity` | `type` `mode` `service_account` |\n| `service.restart` | `enabled` `policy` `max_retries` `backoff_seconds` |\n| `service.startup` | `wait_for_healthy` `timeout_seconds` |\n| `service.logs` | `stdout` `stderr` |\n| `service.environment` | `required` `defaults` + arbitrary `KEY: value` pairs |\n| `service.expose` | `enabled` `host` `port` (or the `true` shorthand) |\n| `proxy` | `enabled` `gateway` `credentials` `listen` `token_endpoint` `routes` |\n| `proxy.listen` | `host` `port` |\n| `proxy.token_endpoint` | `enabled` `host` `port` |\n| `route` | `name` `transport` `listen` `match` `upstream` `auth` `response_headers` |\n| `route.match` | `host` `path` |\n| `route.upstream` | `url` `service` `port` |\n| `route.auth` | `type` `identity` `audience` `service_account` `client_id` `client_secret` `credentials` `headers` |\n| `logs` | `max_memory_events` `persistence` |\n| `logs.persistence` | `enabled` `directory` `retention_days` `max_session_logs` |\n| `telemetry` | `otlp` |\n| `telemetry.otlp` | `enabled` `listen` |\n| `web` | `enabled` `listen` |\n| `auth` | `refresh_threshold_seconds` |\n| `shutdown` | `stop_services_on_exit` `grace_seconds` |\n| `ui` | `theme` `keymap` |\n| `secrets` | `extra_markers` `extra_patterns` |\n| `doctor` | `tools` (each `{ name, command }`) |\n| `plugins[]` | `path` |\n| `environment` | `sources` `secrets` |\n\nThere is no `depends_on`, `build`, `replicas`, or `env_file`. Container fields\nbelong under `service.container`, not directly on the service.\n\n---\n\n## Required, at minimum\n\n- `version: 1`. Anything else: *unsupported config version N; no migration is\n available.*\n- **At least one service.** An empty or missing `services` map fails with *at\n least one service must be defined* \u2014 so a proxy-only or profiles-only config\n is not valid.\n- Every host service needs a non-empty `command`; a container service may rely on its image command.\n\n---\n\n## Ports\n\n- **Globally unique across all services.** Two services on `8000` gives\n *duplicate port 8000 used by api and worker*. This is the single most common\n failure when onboarding a repo whose services each assumed they owned the\n default port.\n- Range 1\u201365535.\n- Forms accepted: a named map (`ports: { http: 8000 }`, preferred), a list, a\n bare number, or `auto`. `auto` is exempt from the uniqueness check \u2014\n devctl allocates at start.\n- Name the port `http` when it serves HTTP.\n- Prefer the explicit `${services.X.ports.http}` reference form. The short\n `${services.X.port}` form is only unambiguous for a single-port service: once\n the service is running it prefers the assigned port named `http`, but when it\n resolves against the configuration it takes the **first port declared**,\n whatever its name. Two forms of the same reference disagreeing on a\n multi-port service is a genuinely confusing bug to chase.\n\n## References\n\n`${services.<name>.ports.<portname>}`, `${services.<name>.port}`,\n`${services.<name>.url}`, `${services.<name>.host}`, and `${identity.user}` (the\nrunning developer's detected Google email) are the supported forms. Anything\nelse \u2014 `${env.FOO}`, `${project.name}` \u2014 throws.\n\n- The referenced service must exist and the named port must be defined, or\n validation fails with *unresolvable reference*.\n- References resolve inside service `environment` values, `defaults`, profile\n environments and dotenv values, before the process starts.\n- Use them for every cross-service URL. Hard-coded ports silently break when a\n port changes or is switched to `auto`.\n\n## Dependencies\n\n- Must name a service that exists.\n- A service may not depend on itself.\n- Cycles are rejected: *dependency cycle: a \u2192 b \u2192 a*.\n- Direction: `dependencies` means \"start these first\". `start x` walks **up**\n and starts x's dependencies; `stop x` walks **down** and stops x's\n *dependents*, never its dependencies.\n- A string dependency uses `service_started`. Use `{ service: db, condition:\n service_healthy }` to wait for the dependency's configured health check.\n\n## Commands and `shell`\n\nA command whose argv contains any of `|` `||` `&&` `;` `>` `>>` `<` `&` is\nrejected unless `shell: true`:\n\n```yaml\n# rejected\ncommand: \"npm run build && npm start\"\n\n# correct\ncommand: \"npm run build && npm start\"\nshell: true\n\n# better \u2014 no shell needed\ncommand: [npm, start]\n```\n\nPrefer argv lists. A string command is split on whitespace, which mangles\narguments containing spaces.\n\n## `working_dir`\n\nRelative to the **repository root** \u2014 the directory containing `.devctl` \u2014 not\nthe process cwd, and not the `.devctl` directory itself.\n\n---\n\n## Health\n\n| `type` | Also requires |\n|---|---|\n| `http` | `url` \u2014 omit it and you get *health.url is required for http health checks* |\n| `tcp` | `address`, **or** at least one port defined on the service |\n| `command` | `health.command` (non-empty) |\n| `process` or omitted | nothing; only checks the pid is alive |\n\nAny other `type` is rejected \u2014 *health.type must be http, tcp, process, or\ncommand* \u2014 **unless** `plugins` is non-empty. That exemption is not approval:\nplugins load after validation, so the supervisor re-checks the type at boot and\nat reload. A custom type no plugin provides fails as a *reload rejection*, not\na config error, which is much harder to diagnose. Only use a custom type when\nyou can point at the plugin that registers it.\n\nDefaults when omitted: interval 2s, timeout 2s, start period 0s, unhealthy\nthreshold 3, healthy reset threshold 10. Failures during the start period do\nnot mark the service unhealthy or consume restart budget.\n\n## Identity\n\n- `type: user` (or omitted) needs nothing else.\n- `type: service_account` (or `service`) **requires** `service_account`, and it\n must contain `@` \u2014 *service_account must be an email*.\n- `mode` is an accepted alias of `type`.\n- Any other type behaves like a custom health type: allowed only with\n `plugins` set, re-checked at boot.\n\nNever fabricate an SA email. If Terraform interpolates it beyond what you can\nresolve, leave a clearly-marked placeholder and tell the user.\n\n## Restart\n\n`policy` must be `never`, `on_failure`, or `always`. `enabled: true` with no\npolicy behaves as `on_failure`.\n\n`max_retries` is a real budget: it resets on a manual stop/start/restart and\nafter a sustained healthy run, but an automatic health-triggered restart\npreserves it across its own cycle.\n\n## Capabilities\n\nDocumentation for doctor, not behaviour. Only these are accepted:\n`google` `google_api` `iap` `network` `service_identity` `local_http`.\nAnything else is rejected.\n\n---\n\n## Proxy\n\n- `proxy.listen.port` is **required** when `proxy.enabled: true`.\n- `proxy.listen.host` must be loopback (`127.0.0.1`, `localhost`, `::1`, or `127.0.0.0/8`). `0.0.0.0` and `::` are rejected.\n- `proxy.token_endpoint.host` must be loopback; `0.0.0.0` and `::` are rejected.\n- `telemetry.otlp` is **off by default**. When `enabled: true`, `listen.host` must be loopback (`0.0.0.0` / `::` rejected, same as the proxy). Default listen port is **4318**. Host services (not containers) get `OTEL_EXPORTER_OTLP_ENDPOINT` / `OTEL_EXPORTER_OTLP_PROTOCOL=http/json` / `OTEL_SERVICE_NAME` only when those variables are unset. JSON only \u2014 no protobuf or gRPC.\n- `web` is **off by default**. When `enabled: true`, `listen.host` must be loopback (`0.0.0.0` / `::` rejected). Default listen port is **18900**. It must not collide with `proxy.listen`, `proxy.token_endpoint`, `telemetry.otlp`, or a gRPC route listen port. The listener serves the local telemetry UI (`GET /api/*`) and loopback lifecycle control (`POST /api/control`, same mutating MCP tools except `exec_service`).\n- Every route needs a `name` and either `upstream.url` or `upstream.service`.\n A service reference must name a real service and an existing port (default\n port name is `http`). `service.expose` and `proxy.gateway` synthesize\n service-reference routes; they do nothing unless `proxy.enabled` is true.\n A hand-written route of the same name wins.\n- **Route names must be unique** \u2014 including names generated from per-service\n `proxy` fragments.\n- `auth.type: iap` requires **both** `audience` and `auth.identity.type`. A\n missing identity type on an IAP route is a configuration error, not a\n default.\n- Optional `client_id` plus `client_secret` mints the user IAP ID token with\n that OAuth client instead of ADC's default client. Put `${NAME}` or\n `${env.NAME}` in `client_secret` so the value is read from the environment\n at mint time (this is not service-env interpolation). These fields are\n invalid on non-IAP routes and on IAP routes whose identity is a service\n account.\n- An identity of `service` / `service_account` requires an SA email, from\n either `auth.identity.service_account` or the route's `auth.service_account`.\n- `auth.type: none` means no auth at all \u2014 any identity left on such a route is\n ignored entirely, and will not be probed at start or by doctor.\n\n### Per-service route fragments\n\nA service's `proxy` key is one route or a list. At load they append into the\n**same** global `proxy.routes` list, named `<service>` or `<service>-<n>`:\n\n```yaml\nservices:\n api:\n command: [python3, main.py]\n proxy:\n - match: { path: /api }\n upstream: { url: \"http://127.0.0.1:8000\" }\n```\n\nThat generates a route named `api`. So a service named `api` **and** a global\nroute named `api` collide \u2014 *duplicate route name api*. Watch for this when\nmixing both styles.\n\nMatching is host + optional path prefix. There is no path rewriting or\nstripping: the matched path is forwarded to the upstream as-is.\n\n---\n\n## Modular layout\n\nWhen the main file is `.devctl/config.yaml`, these merge in automatically:\n\n```\n.devctl/services/<name>.yaml \u2192 services.<name> (FILENAME is the key)\n.devctl/profiles/<name>.yaml \u2192 profiles.<name>\n.devctl/proxy/routes.yaml \u2192 proxy.routes (see the wrapper below)\n```\n\nA service or profile file contains that object's body **only** \u2014 no `services:`\nwrapper, no `version:`. Getting this wrong reads oddly: a `services:` wrapper\ninside `.devctl/services/api.yaml` reports\n`unknown fields: services.api.services`.\n\n`proxy/routes.yaml` is the exception: it accepts either a full `proxy:` wrapper\nor a bare top-level `routes:` list. Both append to the same global route list.\n\n```yaml\n# .devctl/proxy/routes.yaml \u2014 wrapper form, also lets you set proxy.listen here\nproxy:\n routes:\n - name: invoices-api\n match: { host: invoices-api.local }\n upstream: { url: \"http://127.0.0.1:18000\" }\n```\n\n```yaml\n# .devctl/proxy/routes.yaml \u2014 bare form, equivalent for routes alone\nroutes:\n - name: invoices-api\n match: { host: invoices-api.local }\n upstream: { url: \"http://127.0.0.1:18000\" }\n```\n\nPick one. Both keys in the same file append **both** lists, which trips the\nduplicate-route-name check.\n\nOverlays merge after the repo config, later wins:\nbuilt-in defaults \u2192 repo `.devctl` \u2192 `~/.devctl/config.local.yaml` \u2192\n`.devctl/config.local.yaml` \u2014 the repo-local overlay wins over the home one.\nOverlays are presence-aware:\n`false`, `0` and\nempty collections in an overlay do override, so `proxy.enabled: false` in a\nlocal overlay genuinely turns the proxy off.\n\n---\n\n## Environment\n\nMerge order \u2014 later sources win:\n\n```\nprocess \u2192 profile \u2192 dotenv \u2192 generated \u2192 keychain \u2192 secret_manager \u2192 defaults \u2192 vars \u2192 runtime\n```\n\n`process`, `defaults`, `vars` and `runtime` always run. Listing\n`environment.sources` **adds** optional sources (`profile`, `dotenv`,\n`generated`, `keychain`, `secret_manager`) to that always-on set \u2014 it does not\nreplace it, and it does not reorder anything.\n\n- `dotenv` reads repo root then `working_dir`: `.env`, `.env.development`,\n `.env.local`, `.env.<profile>`.\n- `keychain` and `secret_manager` throw when listed and the fetch fails, so\n only list them when the repo genuinely uses them.\n- `environment.required` on a service fails the start if those keys are still\n empty after the whole merge \u2014 the right place to encode \"this cannot run\n without X\".\n\nRuntime values devctl injects: `SERVICE_PORT`, `SERVICE_HOST`,\n`DEVCTL_PROXY_URL`, `DEVCTL_SERVICE_NAME`, `DEVCTL_ENVIRONMENT`,\n`DEVCTL_TOKEN_URL`, `DEVCTL_INTERNAL_TOKEN`. Do not define these yourself.\n\n---\n\n## Templates\n\n```yaml\ntemplates:\n python-http:\n health: { type: http, interval_seconds: 2, timeout_seconds: 1 }\n logs: { stdout: true, stderr: true }\n restart: { policy: on_failure, max_retries: 2, backoff_seconds: 1 }\n\nservices:\n api:\n extends: python-http\n command: [python3, main.py]\n health: { url: \"http://127.0.0.1:8000/health\" } # merged field-by-field\n```\n\n- `extends` must name a template that exists.\n- Nested sections merge **field by field**, so a service can override one\n health field without restating the rest.\n- A template is not a service and is never started.\n\n---\n\n## Reading validation output\n\nEvery message names its path. Fix the path it names.\n\n| Message | Meaning |\n|---|---|\n| `at least one service must be defined` | empty/missing `services` |\n| `duplicate port N used by X and Y` | two services pinned the same port |\n| `services.X.command is required` | missing or empty command |\n| `services.X.command contains shell metacharacters` | add `shell: true` or use argv |\n| `services.X.dependencies: unknown service \"Y\"` | typo, or Y lives in a file you did not create |\n| `dependency cycle: a \u2192 b \u2192 a` | remove an edge |\n| `services.X.health.url is required for http health checks` | add `url`, or change the type |\n| `services.X.identity.service_account must be an email` | placeholder left unresolved |\n| `services.X.environment.K: unresolvable reference ${\u2026}` | referenced service or port name does not exist |\n| `services.X.capabilities: unknown capability \"c\"` | only the six listed above are accepted |\n| `profiles.P references unknown service \"S\"` | profile lists a service that is not defined |\n| `proxy.routes[i]: duplicate route name N` | often a per-service fragment colliding with a global route |\n| `proxy.routes[i].auth.audience is required when auth.type is iap` | IAP needs both audience and identity.type |\n| `proxy.routes[i].auth.client_id is only valid when auth.type is iap` | `client_id` / secret only apply to IAP user routes |\n| `proxy.routes[i].auth.client_id is required when client_secret is set` | secret without client_id |\n| `proxy.routes[i].auth.client_secret is required when client_id is set` | client_id needs a secret |\n| `proxy.routes[i].auth.client_id is only valid with identity.type user` | SA IAP uses generateIdToken, not a user OAuth client |\n| `proxy.listen.port is required when proxy.enabled is true` | pin a port |\n| `unsupported config version N (expected 1)` | `version:` must be `1` |\n| `unknown fields: services.a.depends_on` | not in the allowlists at the top of this file \u2014 usually a compose or k8s spelling |\n\nEvery message above is the validator's exact wording. `devctl config validate`\nprints one per line and exits 2; a clean run prints `configuration is valid`\nand exits 0.\n",discovery:`# Discovery: repository signal \u2192 devctl service
|
|
372
|
+
`,authoring:"# Authoring rules the loader enforces\n\nThe JSON Schema (`schema/devctl.config.schema.json`) describes the shape.\nThis file describes what the **loader and validator actually reject** \u2014 the\nrules that turn a schema-plausible config into one that fails at\n`devctl config validate`. Check anything you are unsure of here before writing.\n\n---\n\n## Unknown fields are rejected everywhere\n\nNot warned about \u2014 rejected, with the offending path named. These are the\ncomplete allowlists.\n\n**Top level:** `version` `project` `google` `profiles` `templates` `services`\n`tasks` `proxy` `logs` `auth` `shutdown` `ui` `secrets` `doctor` `plugins`\n`environment` `telemetry` `web`\n\n**Service** (and `templates.<name>`, same shape): `extends` `description`\n`command` `shell` `working_dir` `dependencies` `ports` `environment` `health`\n`identity` `logs` `restart` `startup` `capabilities` `proxy` `expose` `container` `watch` `hooks`\n\n| Section | Allowed keys |\n|---|---|\n| `project` | `name` |\n| `google` | `project_id` `region` |\n| `profiles.<name>` | `services` `environment` |\n| `service.health` | `type` `url` `address` `command` `interval_seconds` `timeout_seconds` `start_period_seconds` `unhealthy_threshold` `healthy_reset_threshold` |\n| `service.hooks` | `pre_start` `post_start` |\n| `service.container` | `image` `runtime` `ports` `env` `volumes` |\n| `service.watch` | `enabled` `paths` `debounce_ms` `ignore` |\n| `tasks.<name>` | `command` `shell` `working_dir` `dependencies` `environment` |\n| `service.identity` | `type` `mode` `service_account` |\n| `service.restart` | `enabled` `policy` `max_retries` `backoff_seconds` |\n| `service.startup` | `wait_for_healthy` `timeout_seconds` |\n| `service.logs` | `stdout` `stderr` |\n| `service.environment` | `required` `defaults` + arbitrary `KEY: value` pairs |\n| `service.expose` | `enabled` `host` `port` (or the `true` shorthand) |\n| `proxy` | `enabled` `gateway` `credentials` `listen` `token_endpoint` `routes` |\n| `proxy.listen` | `host` `port` |\n| `proxy.token_endpoint` | `enabled` `host` `port` |\n| `route` | `name` `transport` `listen` `match` `upstream` `auth` `response_headers` |\n| `route.match` | `host` `path` |\n| `route.upstream` | `url` `service` `port` |\n| `route.auth` | `type` `identity` `audience` `service_account` `client_id` `client_secret` `credentials` `headers` |\n| `logs` | `max_memory_events` `persistence` |\n| `logs.persistence` | `enabled` `directory` `retention_days` `max_session_logs` |\n| `telemetry` | `otlp` |\n| `telemetry.otlp` | `enabled` `listen` |\n| `web` | `enabled` `listen` |\n| `auth` | `refresh_threshold_seconds` |\n| `shutdown` | `stop_services_on_exit` `grace_seconds` |\n| `ui` | `theme` `keymap` |\n| `secrets` | `extra_markers` `extra_patterns` |\n| `doctor` | `tools` (each `{ name, command }`) |\n| `plugins[]` | `path` |\n| `environment` | `sources` `secrets` |\n\nThere is no `depends_on`, `build`, `replicas`, or `env_file`. Container fields\nbelong under `service.container`, not directly on the service.\n\n---\n\n## Required, at minimum\n\n- `version: 1`. Anything else: *unsupported config version N; no migration is\n available.*\n- **At least one service.** An empty or missing `services` map fails with *at\n least one service must be defined* \u2014 so a proxy-only or profiles-only config\n is not valid.\n- Every host service needs a non-empty `command`; a container service may rely on its image command.\n\n---\n\n## Ports\n\n- **Globally unique across all services.** Two services on `8000` gives\n *duplicate port 8000 used by api and worker*. This is the single most common\n failure when onboarding a repo whose services each assumed they owned the\n default port.\n- Range 1\u201365535.\n- Forms accepted: a named map (`ports: { http: 8000 }`, preferred), a list, a\n bare number, or `auto`. `auto` is exempt from the uniqueness check \u2014\n devctl allocates at start.\n- Name the port `http` when it serves HTTP.\n- Prefer the explicit `${services.X.ports.http}` reference form. The short\n `${services.X.port}` form is only unambiguous for a single-port service: once\n the service is running it prefers the assigned port named `http`, but when it\n resolves against the configuration it takes the **first port declared**,\n whatever its name. Two forms of the same reference disagreeing on a\n multi-port service is a genuinely confusing bug to chase.\n\n## References\n\n`${services.<name>.ports.<portname>}`, `${services.<name>.port}`,\n`${services.<name>.url}`, `${services.<name>.host}`, and `${identity.user}` (the\nrunning developer's detected Google email) are the supported forms. Anything\nelse \u2014 `${env.FOO}`, `${project.name}` \u2014 throws.\n\n- The referenced service must exist and the named port must be defined, or\n validation fails with *unresolvable reference*.\n- References resolve inside service `environment` values, `defaults`, profile\n environments and dotenv values, before the process starts.\n- Use them for every cross-service URL. Hard-coded ports silently break when a\n port changes or is switched to `auto`.\n\n## Dependencies\n\n- Must name a service that exists.\n- A service may not depend on itself.\n- Cycles are rejected: *dependency cycle: a \u2192 b \u2192 a*.\n- Direction: `dependencies` means \"start these first\". `start x` walks **up**\n and starts x's dependencies; `stop x` walks **down** and stops x's\n *dependents*, never its dependencies.\n- A string dependency uses `service_started`. Use `{ service: db, condition:\n service_healthy }` to wait for the dependency's configured health check.\n\n## Commands and `shell`\n\nA command whose argv contains any of `|` `||` `&&` `;` `>` `>>` `<` `&` is\nrejected unless `shell: true`:\n\n```yaml\n# rejected\ncommand: \"npm run build && npm start\"\n\n# correct\ncommand: \"npm run build && npm start\"\nshell: true\n\n# better \u2014 no shell needed\ncommand: [npm, start]\n```\n\nPrefer argv lists. A string command is split on whitespace, which mangles\narguments containing spaces.\n\n## `working_dir`\n\nRelative to the **repository root** \u2014 the directory containing `.devctl` \u2014 not\nthe process cwd, and not the `.devctl` directory itself.\n\n---\n\n## Health\n\n| `type` | Also requires |\n|---|---|\n| `http` | `url` \u2014 omit it and you get *health.url is required for http health checks* |\n| `tcp` | `address`, **or** at least one port defined on the service |\n| `command` | `health.command` (non-empty) |\n| `process` or omitted | nothing; only checks the pid is alive |\n\nAny other `type` is rejected \u2014 *health.type must be http, tcp, process, or\ncommand* \u2014 **unless** `plugins` is non-empty. That exemption is not approval:\nplugins load after validation, so the supervisor re-checks the type at boot and\nat reload. A custom type no plugin provides fails as a *reload rejection*, not\na config error, which is much harder to diagnose. Only use a custom type when\nyou can point at the plugin that registers it.\n\nDefaults when omitted: interval 2s, timeout 2s, start period 0s, unhealthy\nthreshold 3, healthy reset threshold 10. Failures during the start period do\nnot mark the service unhealthy or consume restart budget.\n\n## Identity\n\n- `type: user` (or omitted) needs nothing else.\n- `type: service_account` (or `service`) **requires** `service_account`, and it\n must contain `@` \u2014 *service_account must be an email*.\n- `mode` is an accepted alias of `type`.\n- Any other type behaves like a custom health type: allowed only with\n `plugins` set, re-checked at boot.\n\nNever fabricate an SA email. If Terraform interpolates it beyond what you can\nresolve, leave a clearly-marked placeholder and tell the user.\n\n## Restart\n\n`policy` must be `never`, `on_failure`, or `always`. `enabled: true` with no\npolicy behaves as `on_failure`.\n\n`max_retries` is a real budget: it resets on a manual stop/start/restart and\nafter a sustained healthy run, but an automatic health-triggered restart\npreserves it across its own cycle.\n\n## Capabilities\n\nDocumentation for doctor, not behaviour. Only these are accepted:\n`google` `google_api` `iap` `network` `service_identity` `local_http`.\nAnything else is rejected.\n\n---\n\n## Proxy\n\n- `proxy.listen.port` is **required** when `proxy.enabled: true`.\n- `proxy.listen.host` must be loopback (`127.0.0.1`, `localhost`, `::1`, or `127.0.0.0/8`). `0.0.0.0` and `::` are rejected.\n- `proxy.token_endpoint.host` must be loopback; `0.0.0.0` and `::` are rejected.\n- `telemetry.otlp` is **off by default**. When `enabled: true`, `listen.host` must be loopback (`0.0.0.0` / `::` rejected, same as the proxy). Default listen port is **4318**. Host services (not containers) get `OTEL_EXPORTER_OTLP_ENDPOINT` / `OTEL_EXPORTER_OTLP_PROTOCOL=http/json` / `OTEL_SERVICE_NAME` only when those variables are unset. JSON only \u2014 no protobuf or gRPC.\n- `web` is **off by default**. When `enabled: true`, `listen.host` must be loopback (`0.0.0.0` / `::` rejected). Default listen port is **18900**. It must not collide with `proxy.listen`, `proxy.token_endpoint`, `telemetry.otlp`, or a gRPC route listen port. The listener serves the local telemetry UI (`GET /api/*`) and loopback lifecycle control (`POST /api/control`, same mutating MCP tools except `exec_service`). Request `Host` must be a loopback name; the port in `Host` may differ from the listen port (WSL / Dev Container forwarding).\n- Every route needs a `name` and either `upstream.url` or `upstream.service`.\n A service reference must name a real service and an existing port (default\n port name is `http`). `service.expose` and `proxy.gateway` synthesize\n service-reference routes; they do nothing unless `proxy.enabled` is true.\n A hand-written route of the same name wins.\n- **Route names must be unique** \u2014 including names generated from per-service\n `proxy` fragments.\n- `auth.type: iap` requires **both** `audience` and `auth.identity.type`. A\n missing identity type on an IAP route is a configuration error, not a\n default.\n- Optional `client_id` plus `client_secret` mints the user IAP ID token with\n that OAuth client instead of ADC's default client. Put `${NAME}` or\n `${env.NAME}` in `client_secret` so the value is read from the environment\n at mint time (this is not service-env interpolation). These fields are\n invalid on non-IAP routes and on IAP routes whose identity is a service\n account.\n- An identity of `service` / `service_account` requires an SA email, from\n either `auth.identity.service_account` or the route's `auth.service_account`.\n- `auth.type: none` means no auth at all \u2014 any identity left on such a route is\n ignored entirely, and will not be probed at start or by doctor.\n\n### Per-service route fragments\n\nA service's `proxy` key is one route or a list. At load they append into the\n**same** global `proxy.routes` list, named `<service>` or `<service>-<n>`:\n\n```yaml\nservices:\n api:\n command: [python3, main.py]\n proxy:\n - match: { path: /api }\n upstream: { url: \"http://127.0.0.1:8000\" }\n```\n\nThat generates a route named `api`. So a service named `api` **and** a global\nroute named `api` collide \u2014 *duplicate route name api*. Watch for this when\nmixing both styles.\n\nMatching is host + optional path prefix. There is no path rewriting or\nstripping: the matched path is forwarded to the upstream as-is.\n\n---\n\n## Modular layout\n\nWhen the main file is `.devctl/config.yaml`, these merge in automatically:\n\n```\n.devctl/services/<name>.yaml \u2192 services.<name> (FILENAME is the key)\n.devctl/profiles/<name>.yaml \u2192 profiles.<name>\n.devctl/proxy/routes.yaml \u2192 proxy.routes (see the wrapper below)\n```\n\nA service or profile file contains that object's body **only** \u2014 no `services:`\nwrapper, no `version:`. Getting this wrong reads oddly: a `services:` wrapper\ninside `.devctl/services/api.yaml` reports\n`unknown fields: services.api.services`.\n\n`proxy/routes.yaml` is the exception: it accepts either a full `proxy:` wrapper\nor a bare top-level `routes:` list. Both append to the same global route list.\n\n```yaml\n# .devctl/proxy/routes.yaml \u2014 wrapper form, also lets you set proxy.listen here\nproxy:\n routes:\n - name: invoices-api\n match: { host: invoices-api.local }\n upstream: { url: \"http://127.0.0.1:18000\" }\n```\n\n```yaml\n# .devctl/proxy/routes.yaml \u2014 bare form, equivalent for routes alone\nroutes:\n - name: invoices-api\n match: { host: invoices-api.local }\n upstream: { url: \"http://127.0.0.1:18000\" }\n```\n\nPick one. Both keys in the same file append **both** lists, which trips the\nduplicate-route-name check.\n\nOverlays merge after the repo config, later wins:\nbuilt-in defaults \u2192 repo `.devctl` \u2192 `~/.devctl/config.local.yaml` \u2192\n`.devctl/config.local.yaml` \u2014 the repo-local overlay wins over the home one.\nOverlays are presence-aware:\n`false`, `0` and\nempty collections in an overlay do override, so `proxy.enabled: false` in a\nlocal overlay genuinely turns the proxy off.\n\n---\n\n## Environment\n\nMerge order \u2014 later sources win:\n\n```\nprocess \u2192 profile \u2192 dotenv \u2192 generated \u2192 keychain \u2192 secret_manager \u2192 defaults \u2192 vars \u2192 runtime\n```\n\n`process`, `defaults`, `vars` and `runtime` always run. Listing\n`environment.sources` **adds** optional sources (`profile`, `dotenv`,\n`generated`, `keychain`, `secret_manager`) to that always-on set \u2014 it does not\nreplace it, and it does not reorder anything.\n\n- `dotenv` reads repo root then `working_dir`: `.env`, `.env.development`,\n `.env.local`, `.env.<profile>`.\n- `keychain` and `secret_manager` throw when listed and the fetch fails, so\n only list them when the repo genuinely uses them.\n- `environment.required` on a service fails the start if those keys are still\n empty after the whole merge \u2014 the right place to encode \"this cannot run\n without X\".\n\nRuntime values devctl injects: `SERVICE_PORT`, `SERVICE_HOST`,\n`DEVCTL_PROXY_URL`, `DEVCTL_SERVICE_NAME`, `DEVCTL_ENVIRONMENT`,\n`DEVCTL_TOKEN_URL`, `DEVCTL_INTERNAL_TOKEN`. Do not define these yourself.\n\n---\n\n## Templates\n\n```yaml\ntemplates:\n python-http:\n health: { type: http, interval_seconds: 2, timeout_seconds: 1 }\n logs: { stdout: true, stderr: true }\n restart: { policy: on_failure, max_retries: 2, backoff_seconds: 1 }\n\nservices:\n api:\n extends: python-http\n command: [python3, main.py]\n health: { url: \"http://127.0.0.1:8000/health\" } # merged field-by-field\n```\n\n- `extends` must name a template that exists.\n- Nested sections merge **field by field**, so a service can override one\n health field without restating the rest.\n- A template is not a service and is never started.\n\n---\n\n## Reading validation output\n\nEvery message names its path. Fix the path it names.\n\n| Message | Meaning |\n|---|---|\n| `at least one service must be defined` | empty/missing `services` |\n| `duplicate port N used by X and Y` | two services pinned the same port |\n| `services.X.command is required` | missing or empty command |\n| `services.X.command contains shell metacharacters` | add `shell: true` or use argv |\n| `services.X.dependencies: unknown service \"Y\"` | typo, or Y lives in a file you did not create |\n| `dependency cycle: a \u2192 b \u2192 a` | remove an edge |\n| `services.X.health.url is required for http health checks` | add `url`, or change the type |\n| `services.X.identity.service_account must be an email` | placeholder left unresolved |\n| `services.X.environment.K: unresolvable reference ${\u2026}` | referenced service or port name does not exist |\n| `services.X.capabilities: unknown capability \"c\"` | only the six listed above are accepted |\n| `profiles.P references unknown service \"S\"` | profile lists a service that is not defined |\n| `proxy.routes[i]: duplicate route name N` | often a per-service fragment colliding with a global route |\n| `proxy.routes[i].auth.audience is required when auth.type is iap` | IAP needs both audience and identity.type |\n| `proxy.routes[i].auth.client_id is only valid when auth.type is iap` | `client_id` / secret only apply to IAP user routes |\n| `proxy.routes[i].auth.client_id is required when client_secret is set` | secret without client_id |\n| `proxy.routes[i].auth.client_secret is required when client_id is set` | client_id needs a secret |\n| `proxy.routes[i].auth.client_id is only valid with identity.type user` | SA IAP uses generateIdToken, not a user OAuth client |\n| `proxy.listen.port is required when proxy.enabled is true` | pin a port |\n| `unsupported config version N (expected 1)` | `version:` must be `1` |\n| `unknown fields: services.a.depends_on` | not in the allowlists at the top of this file \u2014 usually a compose or k8s spelling |\n\nEvery message above is the validator's exact wording. `devctl config validate`\nprints one per line and exits 2; a clean run prints `configuration is valid`\nand exits 0.\n",discovery:`# Discovery: repository signal \u2192 devctl service
|
|
373
373
|
|
|
374
374
|
How to turn what a repository contains into the service list you draft from.
|
|
375
375
|
Read the signals in roughly this order \u2014 the earlier ones describe *how the
|
|
@@ -596,7 +596,7 @@ Rules for turning that into YAML:
|
|
|
596
596
|
a full one. Remember that a bare \`devctl start\` falls back to the first
|
|
597
597
|
configured profile, and the TUI's default is the first profile
|
|
598
598
|
alphabetically \u2014 so name them with that in mind.
|
|
599
|
-
`}});var
|
|
599
|
+
`}});var zx;var qx=A(()=>{zx=[{path:"docs/README.md",title:"devctl wiki",body:`# devctl wiki
|
|
600
600
|
|
|
601
601
|
\`devctl\` is a configuration-driven local development orchestrator. It starts and stops services, resolves environment, optional Google identity, an auth-aware proxy, health checks, and centralized logs \u2014 from a keyboard-first TUI, a CLI, or an optional MCP server for coding agents.
|
|
602
602
|
|
|
@@ -1923,15 +1923,17 @@ flowchart TB
|
|
|
1923
1923
|
ok --> proxy["Proxy"]
|
|
1924
1924
|
ok --> token["GET /token"]
|
|
1925
1925
|
ok --> mcp["MCP /mcp"]
|
|
1926
|
+
ok --> web["Web UI"]
|
|
1926
1927
|
\`\`\`
|
|
1927
1928
|
|
|
1928
|
-
|
|
1929
|
+
Four listeners, same bind rule. The web UI also checks that \`Host\` is a loopback name (\`127.0.0.0/8\`, \`localhost\`, \`::1\`) \u2014 the port may differ, so WSL / Dev Container forwarding still works \u2014 and \`POST /api/control\` needs a loopback \`http\` or \`https\` Origin or Referer. No login or token.
|
|
1929
1930
|
|
|
1930
1931
|
| Listener | Auth at the door |
|
|
1931
1932
|
|----------|------------------|
|
|
1932
1933
|
| **Proxy** | Route identity (user ADC or impersonated SA). Logs never include \`Authorization\` |
|
|
1933
1934
|
| **Token endpoint** | \`X-Devctl-Internal-Token\` + loopback peer only. Returns \`access_token\` to that caller |
|
|
1934
1935
|
| **MCP** | Off by default. Mutating tools need \`Authorization: Bearer\` (session token). Copied snippets include it; \`get_status\` does not |
|
|
1936
|
+
| **Web UI** | Loopback bind + loopback Host. Mutations need a loopback Origin/Referer |
|
|
1935
1937
|
|
|
1936
1938
|
Host child processes always get \`DEVCTL_INTERNAL_TOKEN\`. They only get \`DEVCTL_TOKEN_URL\` when \`proxy.token_endpoint.enabled\` is turned on (off by default) \u2014 never a raw Google token in the environment. Containers get neither value: the loopback token endpoint is not reachable as container loopback, and embedding the internal token in inspectable container metadata would add exposure without providing access. With the token endpoint off, a service that needs its own Google credential (rather than relying on the proxy to inject one on inbound requests) must get it another way, e.g. its own ADC discovery.
|
|
1937
1939
|
|
|
@@ -2308,10 +2310,14 @@ View a trace three ways:
|
|
|
2308
2310
|
A loopback Telemetry & Trace Explorer with the same lifecycle controls as the
|
|
2309
2311
|
TUI (\`start\` / \`stop\` / \`restart\` / profile start / proxy / reload / run task).
|
|
2310
2312
|
It is off until you enable it. It binds loopback only (no login or token, no
|
|
2311
|
-
CORS
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2313
|
+
CORS). The Host allowlist accepts loopback names (\`127.0.0.0/8\`, \`localhost\`,
|
|
2314
|
+
\`::1\`, including \`[::1]\`, a missing or remapped port, and \`https://localhost\`)
|
|
2315
|
+
so WSL, Dev Containers, and forwarded ports work; it still rejects machine
|
|
2316
|
+
hostnames and public origins. Mutating \`POST /api/control\` requires a loopback
|
|
2317
|
+
\`http\` or \`https\` \`Origin\` or \`Referer\` and \`Content-Type: application/json\`.
|
|
2318
|
+
The listener serves a bundled SPA plus \`GET /api/*\` shapers that match MCP
|
|
2319
|
+
redaction. Mutations go through \`POST /api/control\` to the same MCP tools
|
|
2320
|
+
(except \`exec_service\`).
|
|
2315
2321
|
|
|
2316
2322
|
\`\`\`yaml
|
|
2317
2323
|
web:
|
|
@@ -2367,7 +2373,7 @@ trace, and read the responsible service's span and logs \u2014 all redacted.
|
|
|
2367
2373
|
- [Proxy](proxy.md)
|
|
2368
2374
|
- [Configuration](configuration.md)
|
|
2369
2375
|
- [Security](security.md)
|
|
2370
|
-
`},{path:"docs/troubleshooting.md",title:"Troubleshooting",body:"# Troubleshooting\n\n| Symptom | What to do |\n|---------|------------|\n| `gcloud` not installed | Install the Cloud SDK only if you need Google identity. Local-only services still run |\n| ADC unavailable | `/auth login` or `gcloud auth application-default login`, then `devctl auth status` / `/auth refresh` |\n| Wrong project | Set `google.project_id` or check `gcloud config get-value core/project`. Identity shows the source |\n| Permission denied | Ask an admin for the missing IAM role; `devctl doctor` names the resource |\n| Cannot impersonate SA | Need `roles/iam.serviceAccountTokenCreator` on that service account (group binding preferred) |\n| IAP authentication failure | Confirm audience, IAP client, and that the identity matches the route. If `client_id` is set, the ADC refresh token must belong to that OAuth client |\n| Port already in use | Doctor lists the holder. Stop a leftover, or change config. Running your own services will also show as \u201Cin use\u201D |\n| Service crashes | Open Logs, filter `ERROR` (`e`), restart with `R` |\n| Health check failure | Confirm the health URL/port; `process` checks only PID liveness |\n| Proxy unavailable / missing listen port | Pin `proxy.listen.port` (required when `proxy.enabled` is true \u2014 validate exits **2**). Then `devctl proxy start` or TUI `n`. Starting with port `0` exits **7**. Bind is loopback only |\n| Token expired | Automatic refresh uses `auth.refresh_threshold_seconds`; run `devctl auth refresh`. Open Doctor if ADC itself expired |\n| Token audience incorrect | Set `auth.audience` on the IAP route; Doctor flags missing audiences |\n| IAP used a user token for an SA route | Confirm the route identity is `service_account`; Doctor probes impersonated IAP separately |\n| Leftover process after crash | Reopen `devctl` \u2014 adopt only when pid + command + cwd + startTime match `~/.devctl/state/<hash>/state.json`. A port-only leftover is never attached |\n| `devctl attach` fails | No supervisor. Use `devctl start` first; attach never starts one |\n| `devctl status` looks empty | If the socket is down, status prints persisted state and exits 0 when nothing is running. The TUI still starts a supervisor; leftover PIDs from the previous session appear on the idle dashboard |\n| Start exits 5 or 6 | 5 = spawn failed; 6 = health never passed. Doctor then Logs |\n| `start` brought up extra services | Empty start uses the active or first profile **alphabetically**, plus dependencies \u2014 YAML key order does not matter (demo: `backend`, not `data`). Pass `--profile` or explicit names to stay narrower |\n| Docker / Podman missing or daemon down | A service in config declares `container` (the demo's `postgres` always does, even if you never start `data`). Install and start that runtime, or drop the service. Default profiles do not start postgres |\n| Doctor offers to kill a busy port that is Docker | It should not: ports owned by a running container service are healthy, and Doctor never offers to terminate the Docker or Podman daemon. Re-run Doctor after the container is up |\n| MCP tools work but nothing starts | `get_status` reports `setup_mode: true` \u2014 there is no `.devctl` yet. Have the agent call `get_setup_guide`, `search_docs`, and `validate_config`, write the files, then `reload_config` |\n| `devctl exec --print-env` hides values | Secret-like names are redacted unless you also pass `--reveal` (TUI: `/exec <svc> --print-env --reveal` or `/reveal`). MCP `exec_service` never reveals them |\n| TUI env pane looks incomplete | It now loads the same resolved map as `devctl exec --print-env`. If the chip says `config fallback`, the daemon `exec` call failed \u2014 check `/daemon` and that the supervisor is up |\n| Supervisor will not start | `devctl daemon logs` or TUI `/daemon` is the bootstrap stderr, not the service log bus |\n| TUI stale / not updating | TUI follows the event bus (20\u201350ms batch). Quit and let a new supervisor start if an old one is still listening |\n| Reload needs a restart | `devctl reload` and `/reload` list services whose command, env, ports, or identity changed |\n| Configuration invalid | `devctl config validate` \u2014 unknown fields, cycles, and missing refs fail closed. TUI `v` / `/buffer` validates before write |\n| Config on disk is broken but the TUI still opens fine | Expected: it attached to an already-running daemon and is showing its `config_snapshot` (last-known-good), not a fresh reparse of the broken file. Fix the file and `/reload` |\n| `devctl update` says unavailable | GitHub Releases API could not be reached. For npm: `npm install --global @amr-m-abdelgawad/devctl@latest`. Homebrew and GitHub binaries: see [installation](installation.md) |\n| MCP agent cannot connect | Listener is off by default. `/mcp` or `devctl mcp --on`. URL is loopback only; snippets include the bearer token |\n| `devctl: command not found` | Run `npm install --global @amr-m-abdelgawad/devctl`, then ensure npm's global binary directory is on `PATH`. See [Installation](installation.md) |\n| Bundled Bun runtime was not installed | Reinstall the npm package without `--ignore-scripts`; Bun uses its install script to select the correct platform runtime |\n\nInternal `devctl` logs appear in the Logs screen with source `devctl`.\n\n## Related\n\n- [Doctor](doctor.md)\n- [Logs](logs.md)\n- [CLI](cli.md)\n- [How it fits together](overview.md)\n"},{path:"docs/tui.md",title:"TUI",body:"# TUI\n\nThe TUI is [OpenTUI](https://opentui.com/docs/) (`@opentui/core` + `@opentui/react`). It attaches to the supervisor and never owns child processes.\n\n```bash\ncd examples/demo-platform\nnpx @amr-m-abdelgawad/devctl@latest\n```\n\nFrom a source checkout (`bun` on PATH):\n\n```bash\ncd examples/demo-platform\nbun run ../../app/src/bin.ts\n```\n\nIf a supervisor session already exists, the TUI attaches to it. Preferences: `tui.json` / `DEVCTL_TUI_CONFIG` \u2014 see [Building from source](typescript.md).\n\n## First run\n\nWith no `.devctl` configuration the TUI opens **setup**: \u201CNo configuration found. Would you like to run setup? **[Enter] Setup [Esc] Exit**\u201D. Enter starts the same 9-step wizard as `devctl setup` (OpenTUI fields, then write and attach the daemon \u2014 no process restart). Invalid existing YAML still refuses overwrite.\n\nIf a `.devctl/config.yaml` exists but fails to parse or validate, the TUI shows **Configuration error** with the actual error instead \u2014 pressing Enter here does not run setup, since that would silently overwrite the file the error is about. Fix the file and restart devctl, or run `devctl config validate` for the same error from the CLI.\n\nWhen services exist but none are running, the dashboard empty state:\n\n- `enter` starts the default profile (first profile name alphabetically) after a plan overlay\n- `n` / `x` start or stop the highlighted row (or the space-selected set)\n- a **lifecycle panel** shows start and stop waves; later start waves wait for health and do not run if a wave fails\n- the panel stays open until `esc` so you can read the result\n- `o` picks a profile, then confirms start\n\n## Quit\n\n`q` / `/exit` / `esc` twice:\n\n| `shutdown.stop_services_on_exit` | Behavior |\n|----------------------------------|----------|\n| `true` | Stop managed services and leave |\n| `false` | Detach immediately |\n| unset | Confirm: `enter` stops services, `d` detaches (daemon stays), `k` stops the daemon and leaves services (`devctl down --keep-services`), `esc` stays |\n\n**Detach** (`d`) leaves the supervisor running. **`/down --keep-services`** (or quit `k`) stops the supervisor and persists PIDs so a later start can adopt them. **`/down`** stops services and the supervisor. `/stop` only stops selected services.\n\n## Interaction model\n\nKeyboard-first. Chords use **command** on macOS and **ctrl** on Linux and Windows. Help, the status bar, and empty-state hints label the modifier for the OS you are on.\n\n| Input | What it does |\n|-------|----------------|\n| `/` | Command overlay \u2014 ranked as you type (name, alias, fuzzy, then description). `/start api` still lists `start`. `\u2191`/`\u2193` to move, `enter` to run |\n| `command+p` / `ctrl+p` | Same command overlay as `/` |\n| `command+x` / `ctrl+x` | Leader key (2s), then a shortcut \u2014 keymap overlay |\n| `?` | Grouped help \u2014 `j`/`k` scroll when the list is taller than the terminal |\n| `tab` / `shift+tab` / `1`\u2013`4` | Cycle or jump the **four nav tabs**. Other screens are `/auth`, `/credentials`, `/doctor`, `/config`, `/profiles`, `/setup`, `/stats`, `/settings`, `/mcp`. On a secondary screen, `tab` returns to the dashboard. When the strip is wider than the terminal it slides (`\u2039` `\u203A`). |\n| `s` `l` `a` `p` `d` `c` `u` | Direct letter nav when no overlay owns keys (services, logs, identity, proxy, doctor, config, setup) |\n| `r` | Refresh snapshot (doctor `r` re-runs checks) |\n| `R` | Restart selected services |\n| `j` `k` / arrows | Move selection |\n| `enter` | Start (empty dashboard) or open service detail |\n| `space` | Multi-select a service |\n| `esc` | Back / close overlay. Twice (when nothing else is open) asks to quit |\n| `f` | Focus log search (`g` jumps to latest). Remap with `keybinds.search` |\n| `z` | Expand logs to fill the terminal. `z` or `esc` exits |\n| `w` | Cycle log wrap: wrap every line (default), clip with ellipsis, or unwrap only the selected row |\n| `command+c` / `ctrl+c` | Copy the highlighted selection (drag with the mouse). Remap with `keybinds.copy` |\n| `command+=` / `ctrl+=` (and `-` / `0`) | Display size (padding/row height, not the terminal font) |\n| `esc` `esc` | Twice to quit when no overlay or back target is open. The OS copy chord does not quit |\n| Mouse | Click nav, click a service, scroll logs (toggle in Settings) |\n\nThe status bar only lists keys that work **on the current screen**. There is no idle command row \u2014 `/` and the OS palette chord open the command overlay.\n\n## Nav tabs (4)\n\n1. dashboard \xB7 2. services \xB7 3. logs \xB7 4. proxy\n\nEverything else is a slash command (or a letter jump): `/auth`, `/credentials`, `/doctor`, `/config`, `/profiles`, `/setup`, `/stats`, `/settings`. **MCP** is `/mcp`, `/agent`, or Settings \u2192 **MCP \u2192 Settings page**.\n\n## Screens\n\n- **Dashboard** \u2014 services, proxy, live log tail. Identity lives on `/auth`; ADC status is in the header. When nothing is running, a **last session** panel shows leftover PIDs from the previous supervisor (same data `devctl status` prints when the socket is down)\n- **Services** \u2014 list plus a live inspector: status chips, two-column facts, then a scrollable **resolved** env pane (dotenv, profile, secrets, plugins, runtime ports). Narrow terminals stack the panes. `enter` opens the full detail screen\n- **Service detail** \u2014 same inspector; env pane is focused so `j`/`k` scroll. `/reveal` shows secrets. `n`/`x`/`R`/`l`\n- **Logs** \u2014 ANSI color codes are stripped so wrap uses visible width; messages wrap to the pane with OpenTUI word wrap. `w` cycles wrap all / clip / wrap selected. `\\\\` / `/split` opens a second pane on the same live stream (independent service filter, shared search). `/trace <id>` or Enter on a log details request id jumps search to that id. See [Logs](logs.md)\n- **Identity** \u2014 user, project, source, ADC, gcloud, configured SAs, impersonation AVAILABLE/UNAVAILABLE, IAP (no tokens). `/auth login` suspends the TUI, runs `gcloud auth application-default login` on the real terminal, then restores the TUI. `/auth logout` revokes ADC without leaving the screen\n- **Credentials** \u2014 store backend and entry names only. Tokens stay in the OS keychain or `~/.devctl/credentials`\n- **Proxy** \u2014 status + routes (match and upstream wrap instead of clipping); click a route for full details. `n` start / `x` stop\n- **Doctor** \u2014 re-runs on every visit; \u2713 / ! / \u2717 with hints. `enter` on a busy host port asks to stop that process; it never offers to kill the Docker or Podman daemon. `r` reruns\n- **Config** \u2014 merged view including **tasks**. `v` / `/buffer` opens a validate/save overlay on `cfg.configPath` (invalid YAML is not written; `esc` discards). `e` / `/edit` still opens `$EDITOR` / `DEVCTL_EDITOR`. `/diff` shows provenance (`devctl config diff`). `/reload` re-reads after an external edit\n- **Profiles** \u2014 members; `enter` selects and offers start\n- **Setup** \u2014 onboarding checklist. First-run with no config still opens here\n- **Settings** \u2014 grouped prefs: theme, display size, mouse, leader timeout, **MCP settings page**, about, reset. `\u2190`/`\u2192` writes the highlighted cycle or toggles mouse. Reset asks before restoring defaults. Saves to `~/.devctl/tui.json` unless `DEVCTL_TUI_CONFIG` is set\n- **MCP** \u2014 Listen `[ ON ]` / `[ OFF ]`, port stepper `\u2039 N \u203A`, per-agent **Copy JSON** / **Copy TOML**, and a **Tools** list grouped by purpose (inspect, logs, diagnostics, control, setup) with each tool marked `read` or `write`; `space` enables or disables the highlighted one, all on by default. Off by default. See [MCP](mcp.md)\n\n`/reveal` toggles secret env values for this session only. The header shows `secrets shown`.\n\n## Slash commands\n\n```text\n/start [service\u2026] start selection, args, or the current profile\n/stop [service\u2026]\n/down [--keep-services] stop the supervisor (and services unless --keep-services)\n/restart [--cascade|-c] named services only; cascade also restarts dependents\n R with dependents: Enter = named, c = cascade\n/run [task] one-off task; empty /run opens a picker. Output is in Logs under task:<name>\n/exec [service] -- <command\u2026>\n empty /exec opens a service picker, then type the command\n/exec <service> --print-env [--reveal]\n resolved env (dotenv, profile, secrets, plugins, ports), not config-only vars\n/logs /services /auth /credentials /proxy /mcp /doctor /config /profiles /setup\n/stats system and service statistics (sparklines when the supervisor has samples)\n/split second log pane (`\\\\`); `|` focuses the other pane\n/trace <id> set log search to a request_id / trace_id\n/dashboard return home\n/themes [name] picker with live preview; enter saves to ~/.devctl/tui.json\n/settings theme, mouse, display size, MCP page\n/filter toggle ERROR+\n/pause freeze the live log stream\n/reveal show or hide secret env values\n/wrap cycle log wrap (all / clip / selected)\n/copy copy visible logs to the clipboard\n/export [path] write filtered logs to ~/.devctl/exports (or the given path)\n/exports open the export folder\n/regex /since /until /history /edit /buffer\n/clear\n/refresh\n/reload reload .devctl\n/diff winning config sources and what they shadowed (`devctl config diff`)\n/import compose [path] [--write]\n/daemon supervisor bootstrap stderr (`devctl daemon logs`)\n/auth login|logout|refresh\n/update install a newer GitHub Release when the method is known (npm/Homebrew)\n/version current version, then the same update check (does not install)\n/exit /quit /q\n```\n\nAliases include `/up`, `/identity`, `/creds`, `/agent`, `/init`, `/home`, `/prefs`, `/task`, `/provenance`, `/bootstrap`. `/down` is no longer an alias of `/stop`.\n\n## Leader key\n\nDefault leader is `command+x` on macOS and `ctrl+x` elsewhere (2 second timeout). Then:\n\n```text\nn start x stop R restart (c cascade if dependents) s services l logs\na auth p proxy d doctor c config o profiles\nt themes e export r refresh i setup h dashboard\nq quit z fullscreen\n```\n\nOverride in `tui.json` (`keybinds`) or `DEVCTL_TUI_CONFIG`.\n\n## Layout\n\n- **Header** \u2014 product + version as text, then project and profile; chips only for running count, live proxy, MCP when on, ADC, and secrets-shown\n- **Nav** \u2014 the four primary tabs; the active tab is highlighted, not filled\n- **Body** \u2014 dashboard or a focused screen\n- **Command overlay** \u2014 `/` and `command+p` / `ctrl+p` open the same grouped list with a real OpenTUI input\n- **Status bar** \u2014 live/paused, last human result, contextual keys\n\nStatus is never color-only: `\u2713` healthy, `\u25CF` running, `!` warning, `\u2717` failed, `\u25CB` stopped.\n\n## Themes\n\n`/themes` opens a picker with live preview. Built-ins:\n\n- Product: `devctl` (default), `ember`\n- Common dark: `tokyonight`, `catppuccin`, `nord`, `gruvbox`, `kanagawa`, `dracula`, `onedark`, `monokai`, `rose-pine`, `everforest`, `github-dark`, `iceberg`, `ayu-dark`, `oxocarbon`, `night-owl`\n- Light: `catppuccin-latte`, `solarized-light`\n- Other: `solarized-dark`, `terminal` (black + VGA ANSI chrome; aliases `ansi`, `xterm`, `console`), `system` (follows macOS `AppleInterfaceStyle` / `COLORFGBG`; light uses Solarized Light)\n\nAliases: `mocha` \u2192 Catppuccin Mocha, `latte`, `one-dark`, `solarized` (dark), `rosepine`, `github`, `ayu`, `night owl`.\n\nMCP agent chips use brand colors (Claude terracotta, Cursor blue, Kilo gold, Codex green) with light/dark variants.\n\n## Related\n\n- [Logs](logs.md)\n- [MCP](mcp.md)\n- [Building from source](typescript.md)\n- [CLI](cli.md)\n"},{path:"docs/typescript.md",title:"Building from source",body:`# Building from source
|
|
2376
|
+
`},{path:"docs/troubleshooting.md",title:"Troubleshooting",body:"# Troubleshooting\n\n| Symptom | What to do |\n|---------|------------|\n| `gcloud` not installed | Install the Cloud SDK only if you need Google identity. Local-only services still run |\n| ADC unavailable | `/auth login` or `gcloud auth application-default login`, then `devctl auth status` / `/auth refresh` |\n| Wrong project | Set `google.project_id` or check `gcloud config get-value core/project`. Identity shows the source |\n| Permission denied | Ask an admin for the missing IAM role; `devctl doctor` names the resource |\n| Cannot impersonate SA | Need `roles/iam.serviceAccountTokenCreator` on that service account (group binding preferred) |\n| IAP authentication failure | Confirm audience, IAP client, and that the identity matches the route. If `client_id` is set, the ADC refresh token must belong to that OAuth client |\n| Port already in use | Doctor lists the holder. Stop a leftover, or change config. Running your own services will also show as \u201Cin use\u201D |\n| Service crashes | Open Logs, filter `ERROR` (`e`), restart with `R` |\n| Health check failure | Confirm the health URL/port; `process` checks only PID liveness |\n| Proxy unavailable / missing listen port | Pin `proxy.listen.port` (required when `proxy.enabled` is true \u2014 validate exits **2**). Then `devctl proxy start` or TUI `n`. Starting with port `0` exits **7**. Bind is loopback only |\n| Token expired | Automatic refresh uses `auth.refresh_threshold_seconds`; run `devctl auth refresh`. Open Doctor if ADC itself expired |\n| Token audience incorrect | Set `auth.audience` on the IAP route; Doctor flags missing audiences |\n| IAP used a user token for an SA route | Confirm the route identity is `service_account`; Doctor probes impersonated IAP separately |\n| Leftover process after crash | Reopen `devctl` \u2014 adopt only when pid + command + cwd + startTime match `~/.devctl/state/<hash>/state.json`. A port-only leftover is never attached |\n| `devctl attach` fails | No supervisor. Use `devctl start` first; attach never starts one |\n| `devctl status` looks empty | If the socket is down, status prints persisted state and exits 0 when nothing is running. The TUI still starts a supervisor; leftover PIDs from the previous session appear on the idle dashboard |\n| Start exits 5 or 6 | 5 = spawn failed; 6 = health never passed. Doctor then Logs |\n| `start` brought up extra services | Empty start uses the active or first profile **alphabetically**, plus dependencies \u2014 YAML key order does not matter (demo: `backend`, not `data`). Pass `--profile` or explicit names to stay narrower |\n| Docker / Podman missing or daemon down | A service in config declares `container` (the demo's `postgres` always does, even if you never start `data`). Install and start that runtime, or drop the service. Default profiles do not start postgres |\n| Doctor offers to kill a busy port that is Docker | It should not: ports owned by a running container service are healthy, and Doctor never offers to terminate the Docker or Podman daemon. Re-run Doctor after the container is up |\n| MCP tools work but nothing starts | `get_status` reports `setup_mode: true` \u2014 there is no `.devctl` yet. Have the agent call `get_setup_guide`, `search_docs`, and `validate_config`, write the files, then `reload_config` |\n| `devctl exec --print-env` hides values | Secret-like names are redacted unless you also pass `--reveal` (TUI: `/exec <svc> --print-env --reveal` or `/reveal`). MCP `exec_service` never reveals them |\n| TUI env pane looks incomplete | It now loads the same resolved map as `devctl exec --print-env`. If the chip says `config fallback`, the daemon `exec` call failed \u2014 check `/daemon` and that the supervisor is up |\n| Supervisor will not start | `devctl daemon logs` or TUI `/daemon` is the bootstrap stderr, not the service log bus |\n| TUI stale / not updating | TUI follows the event bus (20\u201350ms batch). Quit and let a new supervisor start if an old one is still listening |\n| Reload needs a restart | `devctl reload` and `/reload` list services whose command, env, ports, or identity changed |\n| Configuration invalid | `devctl config validate` \u2014 unknown fields, cycles, and missing refs fail closed. TUI `v` / `/buffer` validates before write |\n| Config on disk is broken but the TUI still opens fine | Expected: it attached to an already-running daemon and is showing its `config_snapshot` (last-known-good), not a fresh reparse of the broken file. Fix the file and `/reload` |\n| `devctl update` says unavailable | GitHub Releases API could not be reached. For npm: `npm install --global @amr-m-abdelgawad/devctl@latest`. Homebrew and GitHub binaries: see [installation](installation.md) |\n| MCP agent cannot connect | Listener is off by default. `/mcp` or `devctl mcp --on`. URL is loopback only; snippets include the bearer token |\n| Web UI shows `{\"error\":\"forbidden\"}` | The page Host header was not a loopback name. Use the printed `http://127.0.0.1:<port>/` (or `localhost` / `[::1]`), not a machine or Dev Container hostname. 0.8.0 required the Host port to match exactly, so WSL / Dev Container port forwarding and IPv6 `localhost` 403'd; upgrade to 0.8.1 |\n| `devctl: command not found` | Run `npm install --global @amr-m-abdelgawad/devctl`, then ensure npm's global binary directory is on `PATH`. See [Installation](installation.md) |\n| Bundled Bun runtime was not installed | Reinstall the npm package without `--ignore-scripts`; Bun uses its install script to select the correct platform runtime |\n\nInternal `devctl` logs appear in the Logs screen with source `devctl`.\n\n## Related\n\n- [Doctor](doctor.md)\n- [Logs](logs.md)\n- [CLI](cli.md)\n- [How it fits together](overview.md)\n"},{path:"docs/tui.md",title:"TUI",body:"# TUI\n\nThe TUI is [OpenTUI](https://opentui.com/docs/) (`@opentui/core` + `@opentui/react`). It attaches to the supervisor and never owns child processes.\n\n```bash\ncd examples/demo-platform\nnpx @amr-m-abdelgawad/devctl@latest\n```\n\nFrom a source checkout (`bun` on PATH):\n\n```bash\ncd examples/demo-platform\nbun run ../../app/src/bin.ts\n```\n\nIf a supervisor session already exists, the TUI attaches to it. Preferences: `tui.json` / `DEVCTL_TUI_CONFIG` \u2014 see [Building from source](typescript.md).\n\n## First run\n\nWith no `.devctl` configuration the TUI opens **setup**: \u201CNo configuration found. Would you like to run setup? **[Enter] Setup [Esc] Exit**\u201D. Enter starts the same 9-step wizard as `devctl setup` (OpenTUI fields, then write and attach the daemon \u2014 no process restart). Invalid existing YAML still refuses overwrite.\n\nIf a `.devctl/config.yaml` exists but fails to parse or validate, the TUI shows **Configuration error** with the actual error instead \u2014 pressing Enter here does not run setup, since that would silently overwrite the file the error is about. Fix the file and restart devctl, or run `devctl config validate` for the same error from the CLI.\n\nWhen services exist but none are running, the dashboard empty state:\n\n- `enter` starts the default profile (first profile name alphabetically) after a plan overlay\n- `n` / `x` start or stop the highlighted row (or the space-selected set)\n- a **lifecycle panel** shows start and stop waves; later start waves wait for health and do not run if a wave fails\n- the panel stays open until `esc` so you can read the result\n- `o` picks a profile, then confirms start\n\n## Quit\n\n`q` / `/exit` / `esc` twice:\n\n| `shutdown.stop_services_on_exit` | Behavior |\n|----------------------------------|----------|\n| `true` | Stop managed services and leave |\n| `false` | Detach immediately |\n| unset | Confirm: `enter` stops services, `d` detaches (daemon stays), `k` stops the daemon and leaves services (`devctl down --keep-services`), `esc` stays |\n\n**Detach** (`d`) leaves the supervisor running. **`/down --keep-services`** (or quit `k`) stops the supervisor and persists PIDs so a later start can adopt them. **`/down`** stops services and the supervisor. `/stop` only stops selected services.\n\n## Interaction model\n\nKeyboard-first. Chords use **command** on macOS and **ctrl** on Linux and Windows. Help, the status bar, and empty-state hints label the modifier for the OS you are on.\n\n| Input | What it does |\n|-------|----------------|\n| `/` | Command overlay \u2014 ranked as you type (name, alias, fuzzy, then description). `/start api` still lists `start`. `\u2191`/`\u2193` to move, `enter` to run |\n| `command+p` / `ctrl+p` | Same command overlay as `/` |\n| `command+x` / `ctrl+x` | Leader key (2s), then a shortcut \u2014 keymap overlay |\n| `?` | Grouped help \u2014 `j`/`k` scroll when the list is taller than the terminal |\n| `tab` / `shift+tab` / `1`\u2013`4` | Cycle or jump the **four nav tabs**. Other screens are `/auth`, `/credentials`, `/doctor`, `/config`, `/profiles`, `/setup`, `/stats`, `/settings`, `/mcp`. On a secondary screen, `tab` returns to the dashboard. When the strip is wider than the terminal it slides (`\u2039` `\u203A`). |\n| `s` `l` `a` `p` `d` `c` `u` | Direct letter nav when no overlay owns keys (services, logs, identity, proxy, doctor, config, setup) |\n| `r` | Refresh snapshot (doctor `r` re-runs checks) |\n| `R` | Restart selected services |\n| `j` `k` / arrows | Move selection |\n| `enter` | Start (empty dashboard) or open service detail |\n| `space` | Multi-select a service |\n| `esc` | Back / close overlay. Twice (when nothing else is open) asks to quit |\n| `f` | Focus log search (`g` jumps to latest). Remap with `keybinds.search` |\n| `z` | Expand logs to fill the terminal. `z` or `esc` exits |\n| `w` | Cycle log wrap: wrap every line (default), clip with ellipsis, or unwrap only the selected row |\n| `command+c` / `ctrl+c` | Copy the highlighted selection (drag with the mouse). Remap with `keybinds.copy` |\n| `command+=` / `ctrl+=` (and `-` / `0`) | Display size (padding/row height, not the terminal font) |\n| `esc` `esc` | Twice to quit when no overlay or back target is open. The OS copy chord does not quit |\n| Mouse | Click nav, click a service, scroll logs (toggle in Settings) |\n\nThe status bar only lists keys that work **on the current screen**. There is no idle command row \u2014 `/` and the OS palette chord open the command overlay.\n\n## Nav tabs (4)\n\n1. dashboard \xB7 2. services \xB7 3. logs \xB7 4. proxy\n\nEverything else is a slash command (or a letter jump): `/auth`, `/credentials`, `/doctor`, `/config`, `/profiles`, `/setup`, `/stats`, `/settings`. **MCP** is `/mcp`, `/agent`, or Settings \u2192 **MCP \u2192 Settings page**.\n\n## Screens\n\n- **Dashboard** \u2014 services, proxy, live log tail. Identity lives on `/auth`; ADC status is in the header. When nothing is running, a **last session** panel shows leftover PIDs from the previous supervisor (same data `devctl status` prints when the socket is down)\n- **Services** \u2014 list plus a live inspector: status chips, two-column facts, then a scrollable **resolved** env pane (dotenv, profile, secrets, plugins, runtime ports). Narrow terminals stack the panes. `enter` opens the full detail screen\n- **Service detail** \u2014 same inspector; env pane is focused so `j`/`k` scroll. `/reveal` shows secrets. `n`/`x`/`R`/`l`\n- **Logs** \u2014 ANSI color codes are stripped so wrap uses visible width; messages wrap to the pane with OpenTUI word wrap. `w` cycles wrap all / clip / wrap selected. `\\\\` / `/split` opens a second pane on the same live stream (independent service filter, shared search). `/trace <id>` or Enter on a log details request id jumps search to that id. See [Logs](logs.md)\n- **Identity** \u2014 user, project, source, ADC, gcloud, configured SAs, impersonation AVAILABLE/UNAVAILABLE, IAP (no tokens). `/auth login` suspends the TUI, runs `gcloud auth application-default login` on the real terminal, then restores the TUI. `/auth logout` revokes ADC without leaving the screen\n- **Credentials** \u2014 store backend and entry names only. Tokens stay in the OS keychain or `~/.devctl/credentials`\n- **Proxy** \u2014 status + routes (match and upstream wrap instead of clipping); click a route for full details. `n` start / `x` stop\n- **Doctor** \u2014 re-runs on every visit; \u2713 / ! / \u2717 with hints. `enter` on a busy host port asks to stop that process; it never offers to kill the Docker or Podman daemon. `r` reruns\n- **Config** \u2014 merged view including **tasks**. `v` / `/buffer` opens a validate/save overlay on `cfg.configPath` (invalid YAML is not written; `esc` discards). `e` / `/edit` still opens `$EDITOR` / `DEVCTL_EDITOR`. `/diff` shows provenance (`devctl config diff`). `/reload` re-reads after an external edit\n- **Profiles** \u2014 members; `enter` selects and offers start\n- **Setup** \u2014 onboarding checklist. First-run with no config still opens here\n- **Settings** \u2014 grouped prefs: theme, display size, mouse, leader timeout, **MCP settings page**, about, reset. `\u2190`/`\u2192` writes the highlighted cycle or toggles mouse. Reset asks before restoring defaults. Saves to `~/.devctl/tui.json` unless `DEVCTL_TUI_CONFIG` is set\n- **MCP** \u2014 Listen `[ ON ]` / `[ OFF ]`, port stepper `\u2039 N \u203A`, per-agent **Copy JSON** / **Copy TOML**, and a **Tools** list grouped by purpose (inspect, logs, diagnostics, control, setup) with each tool marked `read` or `write`; `space` enables or disables the highlighted one, all on by default. Off by default. See [MCP](mcp.md)\n\n`/reveal` toggles secret env values for this session only. The header shows `secrets shown`.\n\n## Slash commands\n\n```text\n/start [service\u2026] start selection, args, or the current profile\n/stop [service\u2026]\n/down [--keep-services] stop the supervisor (and services unless --keep-services)\n/restart [--cascade|-c] named services only; cascade also restarts dependents\n R with dependents: Enter = named, c = cascade\n/run [task] one-off task; empty /run opens a picker. Output is in Logs under task:<name>\n/exec [service] -- <command\u2026>\n empty /exec opens a service picker, then type the command\n/exec <service> --print-env [--reveal]\n resolved env (dotenv, profile, secrets, plugins, ports), not config-only vars\n/logs /services /auth /credentials /proxy /mcp /doctor /config /profiles /setup\n/stats system and service statistics (sparklines when the supervisor has samples)\n/split second log pane (`\\\\`); `|` focuses the other pane\n/trace <id> set log search to a request_id / trace_id\n/dashboard return home\n/themes [name] picker with live preview; enter saves to ~/.devctl/tui.json\n/settings theme, mouse, display size, MCP page\n/filter toggle ERROR+\n/pause freeze the live log stream\n/reveal show or hide secret env values\n/wrap cycle log wrap (all / clip / selected)\n/copy copy visible logs to the clipboard\n/export [path] write filtered logs to ~/.devctl/exports (or the given path)\n/exports open the export folder\n/regex /since /until /history /edit /buffer\n/clear\n/refresh\n/reload reload .devctl\n/diff winning config sources and what they shadowed (`devctl config diff`)\n/import compose [path] [--write]\n/daemon supervisor bootstrap stderr (`devctl daemon logs`)\n/auth login|logout|refresh\n/update install a newer GitHub Release when the method is known (npm/Homebrew)\n/version current version, then the same update check (does not install)\n/exit /quit /q\n```\n\nAliases include `/up`, `/identity`, `/creds`, `/agent`, `/init`, `/home`, `/prefs`, `/task`, `/provenance`, `/bootstrap`. `/down` is no longer an alias of `/stop`.\n\n## Leader key\n\nDefault leader is `command+x` on macOS and `ctrl+x` elsewhere (2 second timeout). Then:\n\n```text\nn start x stop R restart (c cascade if dependents) s services l logs\na auth p proxy d doctor c config o profiles\nt themes e export r refresh i setup h dashboard\nq quit z fullscreen\n```\n\nOverride in `tui.json` (`keybinds`) or `DEVCTL_TUI_CONFIG`.\n\n## Layout\n\n- **Header** \u2014 product + version as text, then project and profile; chips only for running count, live proxy, MCP when on, ADC, and secrets-shown\n- **Nav** \u2014 the four primary tabs; the active tab is highlighted, not filled\n- **Body** \u2014 dashboard or a focused screen\n- **Command overlay** \u2014 `/` and `command+p` / `ctrl+p` open the same grouped list with a real OpenTUI input\n- **Status bar** \u2014 live/paused, last human result, contextual keys\n\nStatus is never color-only: `\u2713` healthy, `\u25CF` running, `!` warning, `\u2717` failed, `\u25CB` stopped.\n\n## Themes\n\n`/themes` opens a picker with live preview. Built-ins:\n\n- Product: `devctl` (default), `ember`\n- Common dark: `tokyonight`, `catppuccin`, `nord`, `gruvbox`, `kanagawa`, `dracula`, `onedark`, `monokai`, `rose-pine`, `everforest`, `github-dark`, `iceberg`, `ayu-dark`, `oxocarbon`, `night-owl`\n- Light: `catppuccin-latte`, `solarized-light`\n- Other: `solarized-dark`, `terminal` (black + VGA ANSI chrome; aliases `ansi`, `xterm`, `console`), `system` (follows macOS `AppleInterfaceStyle` / `COLORFGBG`; light uses Solarized Light)\n\nAliases: `mocha` \u2192 Catppuccin Mocha, `latte`, `one-dark`, `solarized` (dark), `rosepine`, `github`, `ayu`, `night owl`.\n\nMCP agent chips use brand colors (Claude terracotta, Cursor blue, Kilo gold, Codex green) with light/dark variants.\n\n## Related\n\n- [Logs](logs.md)\n- [MCP](mcp.md)\n- [Building from source](typescript.md)\n- [CLI](cli.md)\n"},{path:"docs/typescript.md",title:"Building from source",body:`# Building from source
|
|
2371
2377
|
|
|
2372
2378
|
The application lives in \`app/\`. Runtime is [Bun](https://bun.sh). The TUI is [OpenTUI](https://opentui.com/docs/).
|
|
2373
2379
|
|
|
@@ -2467,63 +2473,63 @@ Integration tests that need Google stay skipped unless credentials are present.
|
|
|
2467
2473
|
- [TUI](tui.md)
|
|
2468
2474
|
- [How it fits together](overview.md)
|
|
2469
2475
|
- [Contributing](../CONTRIBUTING.md)
|
|
2470
|
-
`}]});function
|
|
2471
|
-
`),n=0,o=-1;for(let s=0;s<r.length;s++){let a=r.slice(s,s+
|
|
2472
|
-
`).toLowerCase(),l=0;for(let c of t)if(a.includes(c))l+=1;if(l>o)o=l,n=s}let i=r.slice(n,n+
|
|
2473
|
-
`).trim();if(i.length<=Wx)return i;return`${i.slice(0,Wx).trimEnd()}\u2026`}function SO(e){if(e===void 0||Number.isNaN(e))return dO;return Math.min(pO,Math.max(1,Math.floor(e)))}function Kx(e,t){let r=e.trim(),n=wO(r);if(n.length===0)throw Error("query is required");let o=SO(t),i=qx().map((s)=>({path:s.path,title:s.title,score:xO(s,n),snippet:kO(s.body,n)})).filter((s)=>s.score>0).sort((s,a)=>a.score-s.score||s.path.localeCompare(a.path)).slice(0,o);return{query:r,hits:i}}var dO=5,pO=10,fO=12,mO=8,hO=8,gO=15,Wx=400,zx=5,vO=2,yO=4;var Vx=A(()=>{im();Bx()});import{existsSync as CO,readFileSync as TO}from"fs";function Yx(e){return ma.find((r)=>r.name===e)?.mutates===!0&&!RO.has(e)}function no(e,t){return!(t??[]).includes(e)}function Jx(e){return ma.filter((t)=>no(t.name,e))}function Hc(e){return ma.some((t)=>t.name===e)}function Zo(e){return new Rr(e.secrets.extra_markers,e.secrets.extra_patterns)}function Uc(e){return Object.values(e.services).map((t)=>({name:t.name,state:t.state,health:t.health,ports:t.ports,pid:t.pid,last_error:t.last_error}))}function _O(e,t){let r=e.config(),n=r.services[t];if(!n)throw Error(`unknown service ${t}`);let i=e.status().services[t],s=Zo(r);return{name:t,state:i?.state,health:i?.health,pid:i?.pid,last_error:i?.last_error,command:n.command.args,cwd:n.working_dir,ports:i?.ports??Object.fromEntries(n.ports.map((a)=>[a.name,a.value])),environment:s.redactMap({...n.environment.defaults,...n.environment.vars}),container:n.container?{...n.container,env:s.redactMap(n.container.env)}:void 0}}function jc(e){return{session_id:e.session_id,repo_root:e.repo_root,profile:e.profile,setup_mode:e.setup_mode===!0?!0:void 0,identity:{user:e.identity.user,project:e.identity.project,adc:e.identity.adc,iap:e.identity.iap,service_accounts:e.identity.service_accounts,service_account_status:e.identity.service_account_status},proxy:{running:e.proxy.running,address:e.proxy.address,routes:e.proxy.routes,requestTotal:e.proxy.requestTotal,requestErrors:e.proxy.requestErrors,recentRequests:(e.proxy.recentRequests??[]).slice(0,20).map((t)=>({timestamp:t.timestamp,request_id:t.requestId,trace_id:t.traceId,method:t.method,path:t.path,route:t.route,status:t.status,duration_ms:t.durationMs,trace_duration_ms:t.traceDurationMs,error:t.error}))},logs:e.logs,mcp:e.mcp?{running:e.mcp.running,address:e.mcp.address,port:e.mcp.port}:{running:!1},web:e.web?{running:e.web.running,address:e.web.address,port:e.web.port}:{running:!1},stats_series:e.stats_series}}async function fa(e,t){let r=typeof t.service==="string"?t.service:"",n=typeof t.since==="string"?t.since:"",o=typeof t.cursor==="string"?t.cursor:void 0,i=typeof t.attribute_key==="string"?t.attribute_key:"",s=typeof t.attribute_value==="string"?t.attribute_value:"",a=await e.logsPage({services:r===""?[]:[r],level:typeof t.level==="string"?t.level:"",search:typeof t.search==="string"?t.search:"",source:typeof t.source==="string"?t.source:"",since:n,until:typeof t.until==="string"?t.until:"",requestId:typeof t.request_id==="string"?t.request_id:void 0,traceId:typeof t.trace_id==="string"?t.trace_id:void 0,attribute:i!==""&&s!==""?{key:i,value:s}:void 0,cursor:o,direction:o?"forward":void 0,limit:EO}),l=Zo(e.config());return{events:a.events.map((c)=>Xx(l,c)),truncated:a.hasPrev,has_more:a.hasNext,next_since:a.events[a.events.length-1]?.timestamp??n,next_cursor:a.nextCursor,session_changed:a.sessionChanged}}function Xx(e,t){let r=xl(e,t),n=r.resource["process.pid"];return{timestamp:r.timestamp,service:r.service,source:r.source,severityText:r.severityText,severityNumber:r.severityNumber,body:r.body,attributes:r.attributes,traceId:r.traceId,spanId:r.spanId,seq:r.seq,level:r.severityText,message:Kt(r),pid:typeof n==="number"?n:0}}function Qx(e,t){return{trace_id:t.traceId,request_id:t.requestId,spans:t.tree.spans.map((r)=>kl(e,r)),logs:t.events.map((r)=>Xx(e,r))}}async function lm(e,t){let r=typeof t.trace_id==="string"?t.trace_id:"";if(r==="")throw Error("trace_id is required");if(!e.getTrace)throw Error("trace store is unavailable");return Qx(Zo(e.config()),await e.getTrace(r))}async function cm(e,t){let r=typeof t.request_id==="string"?t.request_id:"";if(r==="")throw Error("request_id is required");if(!e.traceRequest)throw Error("trace store is unavailable");return Qx(Zo(e.config()),await e.traceRequest(r))}function um(e){return{running:e.proxy.running,total:e.proxy.requestTotal??0,errors:e.proxy.requestErrors??0,requests:(e.proxy.recentRequests??[]).map((t)=>({timestamp:t.timestamp,request_id:t.requestId,trace_id:t.traceId,method:t.method,path:t.path,route:t.route,status:t.status,duration_ms:t.durationMs,trace_duration_ms:t.traceDurationMs,error:t.error}))}}function dm(e){return Object.entries(e.profiles).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>({name:t,services:r.services}))}function Yi(e){return e.trim()===""?void 0:e}function PO(e){let t={name:e.name,match:e.match,upstream:e.upstream.url!==""?e.upstream.url:Yi(e.upstream.service??"")?`service:${e.upstream.service}${e.upstream.port?`/${e.upstream.port}`:""}`:"",auth:e.auth.type},r=Yi(e.auth.identity.type),n=Yi(e.auth.audience),o=Yi(e.auth.identity.service_account||e.auth.service_account),i=Yi(e.auth.client_id),s=Xl(e.auth.client_secret),a=Yi(e.auth.credentials??"");if(r)t.identity=r;if(n)t.audience=n;if(o)t.service_account=o;if(i)t.client_id=i;if(s)t.client_secret=s;if(a)t.credentials=a;let l=Object.keys(e.auth.headers??{});if(l.length>0)t.headers=l;return t}function Bc(e){let t=Object.entries(e.services).map(([r,n])=>({name:r,description:n.description,command:n.command.args,cwd:n.working_dir,ports:n.ports.map((o)=>({name:o.name,value:o.auto?0:o.value,auto:o.auto})),dependencies:n.dependencies,container:n.container?{image:n.container.image,runtime:n.container.runtime||"docker",ports:n.container.ports,volumes:n.container.volumes}:void 0}));return{project:e.project.name,config_path:e.configPath,repo_root:e.repoRoot,services:t,tasks:Object.entries(e.tasks).sort(([r],[n])=>r.localeCompare(n)).map(([r,n])=>({name:r,dependencies:n.dependencies})),proxy:{enabled:e.proxy.enabled,gateway:e.proxy.gateway,credentials:e.proxy.credentials,listen:{host:e.proxy.listen.host,port:e.proxy.listen.port},routes:e.proxy.routes.map((r)=>PO(r))}}}function AO(e){let t=Zo(e);return{entries:Xn(e).map((r)=>{let n=typeof r.value==="string"?r.value:JSON.stringify(r.value);return{...r,value:t.redactMap({[r.path]:n})[r.path]}})}}function $c(e){if(!Array.isArray(e))return[];return e.filter((t)=>typeof t==="string")}async function Wc(e,t,r){switch(t){case"list_services":return Uc(e.status());case"get_service":if(typeof r.name!=="string"||r.name==="")throw Error("name is required");return _O(e,r.name);case"get_status":return jc(e.status());case"get_logs":return fa(e,r);case"get_trace":return lm(e,r);case"trace_request":return cm(e,r);case"get_requests":return um(e.status());case"recent_errors":return fa(e,{...r,level:"ERROR"});case"list_profiles":return dm(e.config());case"get_config":return Bc(e.config());case"get_config_sources":return AO(e.config());case"run_doctor":return e.doctor();case"start_services":return e.start({services:$c(r.services),profile:typeof r.profile==="string"&&r.profile!==""?r.profile:void 0});case"stop_services":return await e.stop($c(r.services)),{ok:!0};case"restart_services":return await e.restart($c(r.services),r.cascade===!0),{ok:!0};case"reload_config":return e.reload();case"run_task":{if(typeof r.name!=="string"||r.name==="")throw Error("name is required");let n=await e.runTask(r.name),o=Zo(e.config());return{...n,stdout:o.redactText(n.stdout),stderr:o.redactText(n.stderr)}}case"start_proxy":return await e.startProxy(),{ok:!0};case"stop_proxy":return await e.stopProxy(),{ok:!0};case"exec_service":{if(typeof r.service!=="string"||r.service==="")throw Error("service is required");if(!e.exec)throw Error("exec is unavailable");let n=await e.exec(r.service,$c(r.command),r.print_env===!0),o=Zo(e.config());return{...n,stdout:o.redactText(n.stdout),stderr:o.redactText(n.stderr),environment:n.environment?o.redactMap(n.environment):void 0}}case"get_setup_guide":return LO(r);case"search_docs":return Kx(typeof r.query==="string"?r.query:"",typeof r.limit==="number"?r.limit:void 0);case"get_doc":return Gx(typeof r.path==="string"?r.path:"");case"validate_config":return IO(e,r);default:throw Error(`unknown tool ${t}`)}}function LO(e){let t=typeof e.section==="string"?e.section:"procedure",r=t in ro?t:"procedure";return{section:r,text:ro[r],sections:Object.keys(ro)}}function IO(e,t){let r=e.config();if(typeof t.text==="string"){let o=e.validateConfigText(t.text);return{valid:o.length===0,issues:o,source:"candidate",config_path:r.configPath}}if(!CO(r.configPath))return{valid:!1,issues:[`no configuration at ${r.configPath}`],source:"disk",config_path:r.configPath,setup_mode:!0};let n=e.validateConfigText(TO(r.configPath,"utf8"));return{valid:n.length===0,issues:n,source:"disk",config_path:r.configPath}}function Zx(e){return sm.includes(e)}async function e0(e,t){switch(t){case"devctl://status":return jc(e.status());case"devctl://services":return Uc(e.status());case"devctl://logs":return fa(e,{});case"devctl://config":return Bc(e.config());case"devctl://doctor":return e.doctor();default:throw Error(`unknown resource ${t}`)}}var EO=200,sm,am,ma,RO;var Ji=A(()=>{To();sn();Vx();im();sm=["devctl://status","devctl://services","devctl://logs","devctl://config","devctl://doctor"],am=["inspect","logs","diagnostics","control","setup"],ma=[{name:"list_services",label:"List services",summary:"Name, state, health, ports, pid",category:"inspect",description:"List services with state, health, ports, pid, and last error",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"get_service",label:"Service detail",summary:"One service with command, cwd, ports",category:"inspect",description:"One service plus command, cwd, and ports. Environment values are redacted.",inputSchema:{type:"object",properties:{name:{type:"string"}},required:["name"],additionalProperties:!1}},{name:"get_status",label:"Status",summary:"Profile, identity, proxy, log counts",category:"inspect",description:"Profile, session, identity flags (no tokens), proxy, and log counts",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"get_logs",label:"Read logs",summary:"Filtered log pages, secrets redacted",category:"logs",description:"Recent log records, optionally filtered. Capped at 200 events per page. Secrets are redacted. Pass cursor=next_cursor to page forward with no duplicate or same-millisecond-lost events; since/until are plain timestamp filters for a fresh query, not a follow cursor.",inputSchema:{type:"object",properties:{service:{type:"string"},level:{type:"string"},search:{type:"string"},source:{type:"string"},since:{type:"string",description:"Only events at or after this timestamp"},until:{type:"string",description:"Only events at or before this timestamp"},cursor:{type:"string",description:"Opaque cursor from a previous response's next_cursor; continues forward from exactly there"},request_id:{type:"string",description:"Filter by X-Devctl-Request-ID / devctl.request_id"},trace_id:{type:"string",description:"Filter by W3C trace id"},attribute_key:{type:"string",description:"Attribute key to match (with attribute_value)"},attribute_value:{type:"string",description:"Attribute value to match (with attribute_key)"}},additionalProperties:!1}},{name:"get_trace",label:"Get trace",summary:"Span tree and correlated logs",category:"logs",description:"Return the span tree and correlated log records for a W3C trace id. Secrets are redacted.",inputSchema:{type:"object",properties:{trace_id:{type:"string"}},required:["trace_id"],additionalProperties:!1}},{name:"trace_request",label:"Trace request",summary:"Trace for a proxy request id",category:"logs",description:"Resolve a proxy X-Devctl-Request-ID to its trace, then return the span tree and correlated logs. Secrets are redacted.",inputSchema:{type:"object",properties:{request_id:{type:"string"}},required:["request_id"],additionalProperties:!1}},{name:"get_requests",label:"Recent requests",summary:"Proxy request ring with trace ids",category:"inspect",description:"Recent proxy requests with method, path, status, duration, request id, and trace id.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"recent_errors",label:"Recent errors",summary:"Latest error-severity log records",category:"logs",description:"Latest error and fatal log records, capped at 200, secrets redacted. Same paging fields as get_logs.",inputSchema:{type:"object",properties:{service:{type:"string"},search:{type:"string"},source:{type:"string"},since:{type:"string"},until:{type:"string"},cursor:{type:"string"},request_id:{type:"string"},trace_id:{type:"string"}},additionalProperties:!1}},{name:"list_profiles",label:"List profiles",summary:"Configured profiles and their members",category:"inspect",description:"Configured profiles and their member services",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"get_config",label:"Read config",summary:"Merged project summary, no secret values",category:"inspect",description:"Merged project summary: services, routes, and proxy listen paths. Route auth includes type, identity, audience, and optional IAP client_id. client_secret is returned only as a ${ENV} template, never a resolved secret.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"get_config_sources",label:"Config sources",summary:"Winning and shadowed config sources",category:"inspect",description:"List effective configuration values with their winning source/layer and any shadowed sources. Secret-like values are redacted.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"run_doctor",label:"Run doctor",summary:"Environment diagnostics",category:"diagnostics",description:"Run environment diagnostics",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"start_services",label:"Start services",summary:"Start named services or a profile",category:"control",mutates:!0,description:"Start named services, or a profile when names are omitted. Empty start uses profile, then the active session profile, then the first configured profile \u2014 never every service.",inputSchema:{type:"object",properties:{services:{type:"array",items:{type:"string"}},profile:{type:"string",description:"Profile to start when services is omitted"}},additionalProperties:!1}},{name:"stop_services",label:"Stop services",summary:"Stop services and their dependents",category:"control",mutates:!0,description:"Stop named services, or all started services when names are omitted. Also stops every service that transitively depends on a named one (never a named service's own dependencies, which other running services may still need).",inputSchema:{type:"object",properties:{services:{type:"array",items:{type:"string"}}},additionalProperties:!1}},{name:"restart_services",label:"Restart services",summary:"Restart services, optionally cascading",category:"control",mutates:!0,description:"Restart named services. By default this touches only the named services, not anything that depends on them. Pass cascade=true to also restart their transitive dependents (the same set stop_services would affect).",inputSchema:{type:"object",properties:{services:{type:"array",items:{type:"string"}},cascade:{type:"boolean",description:"Also restart transitive dependents; default false restarts only the named services"}},additionalProperties:!1}},{name:"reload_config",label:"Reload config",summary:"Re-read .devctl configuration",category:"control",mutates:!0,description:"Reload .devctl configuration",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"run_task",label:"Run task",summary:"Run a named one-off task",category:"control",mutates:!0,description:"Run a named task from configuration. Output is also written to the log ring as task:<name>.",inputSchema:{type:"object",properties:{name:{type:"string"}},required:["name"],additionalProperties:!1}},{name:"start_proxy",label:"Start proxy",summary:"Start the local reverse proxy",category:"control",mutates:!0,description:"Start the local reverse proxy. Same as CLI `devctl proxy start` and TUI start on the proxy screen.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"stop_proxy",label:"Stop proxy",summary:"Stop the local reverse proxy",category:"control",mutates:!0,description:"Stop the local reverse proxy and leave it suppressed until start_proxy (or CLI/TUI start) runs again.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"exec_service",label:"Execute in service",summary:"Run a command in a resolved service context",category:"control",mutates:!0,description:"Run an arbitrary command with a service's fully resolved environment and working directory, whether or not it is running. Output and print_env values are redacted.",inputSchema:{type:"object",properties:{service:{type:"string"},command:{type:"array",items:{type:"string"}},print_env:{type:"boolean",description:"Return the resolved environment without executing a command"}},required:["service"],additionalProperties:!1}},{name:"get_setup_guide",label:"Setup guide",summary:"How to author a .devctl for this repo",category:"setup",description:"The devctl onboarding guide: how to survey a repository and author a .devctl configuration for it. Read section=procedure first; read section=authoring BEFORE writing any YAML (it carries the rules the loader rejects on, which the JSON Schema does not state); read section=discovery for mapping compose/package.json/pyproject/Terraform/k8s/.env to services. Write the files with your own editing tools \u2014 this server does not write them \u2014 then check your work with validate_config.",inputSchema:{type:"object",properties:{section:{type:"string",enum:["procedure","authoring","discovery"],description:"Which part of the guide to return; defaults to procedure"}},additionalProperties:!1}},{name:"search_docs",label:"Search docs",summary:"Search the embedded product documentation",category:"setup",description:"Search the compiled-in product documentation (docs/*.md plus the onboarding skill). Returns ranked pages with short snippets for discovery. To read a full page, pass a hit's `path` to get_doc. Use this for IAP, proxy, MCP, configuration, and similar topics; use get_setup_guide for the full onboarding procedure.",inputSchema:{type:"object",properties:{query:{type:"string",description:"Keywords or a short phrase to search for"},limit:{type:"integer",description:"Maximum hits to return (default 5, max 10)"}},required:["query"],additionalProperties:!1}},{name:"get_doc",label:"Get doc",summary:"Read a full documentation page",category:"setup",description:"Return the complete text of one embedded documentation page. Pass the `path` from a search_docs hit (e.g. docs/proxy.md) \u2014 search_docs only returns short snippets, so use this to read the whole page. A basename like proxy.md also resolves when unambiguous.",inputSchema:{type:"object",properties:{path:{type:"string",description:"Doc path from a search_docs hit, e.g. docs/proxy.md"}},required:["path"],additionalProperties:!1}},{name:"validate_config",label:"Validate config",summary:"Check configuration or a draft for errors",category:"setup",description:"Validate devctl configuration and return the exact issues the loader would report. With no arguments, validates what is on disk. Pass text to validate a candidate config.yaml before writing it \u2014 the candidate is run through the real load pipeline (modular services/profiles, overlays, templates), so it works even when no configuration exists yet. This is the only way to validate over MCP; there is no CLI round-trip needed.",inputSchema:{type:"object",properties:{text:{type:"string",description:"Candidate config.yaml contents to validate instead of the file on disk"}},additionalProperties:!1}}],RO=new Set(["exec_service"])});function p0(e){return{...e,runDoctor:(t,r,n)=>e.runDoctor.execute(t,r,n),startupPlan:(t,r,n)=>e.getStartupPlan.execute(t,r,n),shutdownPlan:(t,r)=>e.getShutdownPlan.execute(t,r),shutdownPlanExact:(t,r)=>fc(t,r),resolveStartRequest:(t,r)=>e.resolveStart.execute(t,{...r,profile:r.profile?Ar(r.profile):void 0,activeProfile:r.activeProfile===void 0?void 0:Ar(r.activeProfile)})}}var f0=A(()=>{$t()});function Kc(e){let t=e.toLowerCase().trim(),r=cM[t];if(r)return r;return _t.includes(t)?t:"devctl"}function uM(){if(process.env.DEVCTL_THEME_LIGHT==="1")return!0;if(process.env.DEVCTL_THEME_LIGHT==="0")return!1;if(process.platform==="darwin")try{let t=Bun.spawnSync(["defaults","read","-g","AppleInterfaceStyle"],{stdout:"pipe",stderr:"pipe"}),r=t.stdout.toString();if(t.exitCode===0&&r.toLowerCase().includes("dark"))return!1;if(t.exitCode!==0)return!0}catch{}let e=process.env.COLORFGBG??"";if(e.includes(";15")||e.endsWith(";7"))return!0;if(e.includes(";0")||e.endsWith(";8"))return!1;return!1}function m0(e){let t=Kc(e);if(t==="system"){if(uM())return{...gm["solarized-light"],name:"system"};return gm.system}return gm[t]}function Or(e){switch(e.toUpperCase()){case"HEALTHY":case"OK":return"\u2713";case"UNHEALTHY":case"WARNING":case"WARN":return"!";case"FAILED":case"ERROR":return"\u2717";case"STOPPED":case"UNKNOWN":return"\u25CB";case"RUNNING":case"STARTING":case"RESTARTING":return"\u25CF";default:return"\u25CB"}}function ei(e,t){return ba(e)>=ya?Vc:t}function ba(e){let t=e.startsWith("#")?e.slice(1):e,r=Number.parseInt(t,bM);if(Number.isNaN(r))return 0;let n=r>>wM&vm,o=r>>xM&vm,i=r&vm;return(n*hM+o*gM+i*vM)/yM}function kM(e){let t=fM;for(let r=0;r<e.length;r+=1)t^=e.charCodeAt(r),t=Math.imul(t,mM);return t>>>0}function Yc(e){return ba(e.background)>=ya}function bm(e){if(!e||!/^#[0-9a-f]{6}$/i.test(e))return!1;return ba(e)<ya}function Jc(e,t){let r=SM[e];return Yc(t)?r.light:r.dark}function h0(e,t){return ba(Jc(e,t))>=ya?CM:TM}function Ye(e,t){if(e===""||e==="all")return t.muted;let r=ba(t.background)>=ya?pM:dM;return r[kM(e)%r.length]??t.info}function EM(e,t){switch(t.toUpperCase()){case"ERROR":case"FATAL":return e.error;case"WARN":case"WARNING":return e.warning;case"INFO":return e.text;case"DEBUG":case"TRACE":return e.muted;default:return e.text}}function g0(e,t,r){if(r==="search")return e.search;if(r==="string")return e.accent;if(r==="number")return e.info;if(r==="keyword")return e.error;return EM(e,t)}function dt(e,t){switch(t.toUpperCase()){case"HEALTHY":case"OK":return e.success;case"UNHEALTHY":case"WARNING":case"WARN":return e.warning;case"FAILED":case"ERROR":return e.error;case"RUNNING":case"STARTING":case"RESTARTING":return e.primary;case"INFO":return e.info;case"FATAL":return e.error;case"DEBUG":case"TRACE":case"UNKNOWN":return e.muted;default:return e.muted}}var _t,ym,gm,cM,dM,pM,fM=2166136261,mM=16777619,hM=299,gM=587,vM=114,yM=1000,ya=160,bM=16,vm=255,wM=16,xM=8,Vc="#1A1A1A",SM,CM="#1A1A1A",TM="#F5F5F5";var rt=A(()=>{_t=["devctl","ember","tokyonight","catppuccin","catppuccin-latte","nord","gruvbox","kanagawa","dracula","onedark","monokai","solarized-dark","solarized-light","rose-pine","everforest","github-dark","iceberg","ayu-dark","oxocarbon","night-owl","terminal","voltage","voltage-light","ironclad","ironclad-light","signal","signal-light","system"],ym={devctl:"forest + mint, website palette",ember:"warm orange",tokyonight:"Tokyo Night storm blues",catppuccin:"Catppuccin Mocha","catppuccin-latte":"Catppuccin Latte (light)",nord:"Arctic Nord frost",gruvbox:"Gruvbox dark hard",kanagawa:"Kanagawa wave / gold",dracula:"classic Dracula purple",onedark:"Atom / VS Code One Dark",monokai:"Monokai Sublime","solarized-dark":"Solarized dark","solarized-light":"Solarized light","rose-pine":"Ros\xE9 Pine moon",everforest:"Everforest dark medium","github-dark":"GitHub dimmed canvas",iceberg:"Iceberg navy","ayu-dark":"Ayu Mirage-adjacent dark",oxocarbon:"IBM Oxocarbon","night-owl":"Sarah Drasner Night Owl",terminal:"black + VGA ANSI chrome",voltage:"max contrast, electric neon (dark)","voltage-light":"max contrast, electric neon (light)",ironclad:"max contrast, steel & amber (dark)","ironclad-light":"max contrast, steel & amber (light)",signal:"max contrast, traffic-light semantics (dark)","signal-light":"max contrast, traffic-light semantics (light)",system:"neutral dark (system default)"},gm={tokyonight:{name:"tokyonight",primary:"#82AAFF",accent:"#C792EA",error:"#FF5370",warning:"#FFCB6B",search:"#FFCB6B",success:"#C3E88D",info:"#89DDFF",text:"#F4F7FF",muted:"#A8B2CC",background:"#0F111A",panel:"#1A1B2E",element:"#24283B",highlight:"#2E3350",inverse:"#0F111A",border:"#3D4466",borderActive:"#82AAFF"},catppuccin:{name:"catppuccin",primary:"#89B4FA",accent:"#F5C2E7",error:"#F38BA8",warning:"#F9E2AF",search:"#F9E2AF",success:"#A6E3A1",info:"#89DCEB",text:"#E4E8F7",muted:"#A6A9BE",background:"#11111B",panel:"#1E1E2E",element:"#313244",highlight:"#45475A",inverse:"#11111B",border:"#585B70",borderActive:"#89B4FA"},"catppuccin-latte":{name:"catppuccin-latte",primary:"#1E66F5",accent:"#EA76CB",error:"#D20F39",warning:"#DF8E1D",search:"#DF8E1D",success:"#40A02B",info:"#179299",text:"#4C4F69",muted:"#6C6F85",background:"#EFF1F5",panel:"#E6E9EF",element:"#DCE0E8",highlight:"#CCD0DA",inverse:"#EFF1F5",border:"#9CA0B0",borderActive:"#1E66F5"},nord:{name:"nord",primary:"#88C0D0",accent:"#B48EAD",error:"#BF616A",warning:"#EBCB8B",search:"#EBCB8B",success:"#A3BE8C",info:"#8FBCBB",text:"#F2F5FA",muted:"#A4AEBF",background:"#2E3440",panel:"#3B4252",element:"#434C5E",highlight:"#4C566A",inverse:"#2E3440",border:"#5E6A7D",borderActive:"#88C0D0"},gruvbox:{name:"gruvbox",primary:"#FE8019",accent:"#FABD2F",error:"#FB4934",warning:"#FE8019",search:"#FE8019",success:"#B8BB26",info:"#8EC07C",text:"#F2E5BC",muted:"#C4B394",background:"#1D2021",panel:"#282828",element:"#3C3836",highlight:"#504945",inverse:"#1D2021",border:"#665C54",borderActive:"#FE8019"},kanagawa:{name:"kanagawa",primary:"#7FB4CA",accent:"#E6C384",error:"#E82424",warning:"#FFA066",search:"#FFA066",success:"#98BB6C",info:"#7FB4CA",text:"#E8E4C9",muted:"#B4C0D6",background:"#16161D",panel:"#1F1F28",element:"#2A2A37",highlight:"#363646",inverse:"#16161D",border:"#54546D",borderActive:"#E6C384"},dracula:{name:"dracula",primary:"#BD93F9",accent:"#FF79C6",error:"#FF5555",warning:"#F1FA8C",search:"#F1FA8C",success:"#50FA7B",info:"#8BE9FD",text:"#F8F8F2",muted:"#8B9DC9",background:"#21222C",panel:"#282A36",element:"#343746",highlight:"#44475A",inverse:"#21222C",border:"#6272A4",borderActive:"#BD93F9"},onedark:{name:"onedark",primary:"#61AFEF",accent:"#C678DD",error:"#E06C75",warning:"#E5C07B",search:"#E5C07B",success:"#98C379",info:"#56B6C2",text:"#ABB2BF",muted:"#9DA5B4",background:"#21252B",panel:"#282C34",element:"#2C323C",highlight:"#3E4451",inverse:"#21252B",border:"#4B5263",borderActive:"#61AFEF"},monokai:{name:"monokai",primary:"#66D9EF",accent:"#AE81FF",error:"#F92672",warning:"#E6DB74",search:"#E6DB74",success:"#A6E22E",info:"#66D9EF",text:"#F8F8F2",muted:"#A39E80",background:"#1D1E19",panel:"#272822",element:"#3E3D32",highlight:"#49483E",inverse:"#1D1E19",border:"#75715E",borderActive:"#F92672"},"solarized-dark":{name:"solarized-dark",primary:"#268BD2",accent:"#6C71C4",error:"#DC322F",warning:"#B58900",search:"#B58900",success:"#859900",info:"#2AA198",text:"#93A1A1",muted:"#586E75",background:"#002B36",panel:"#073642",element:"#0A4A58",highlight:"#1A5A68",inverse:"#002B36",border:"#586E75",borderActive:"#268BD2"},"solarized-light":{name:"solarized-light",primary:"#268BD2",accent:"#D33682",error:"#DC322F",warning:"#CB4B16",search:"#CB4B16",success:"#859900",info:"#2AA198",text:"#586E75",muted:"#839496",background:"#FDF6E3",panel:"#EEE8D5",element:"#E4DCC8",highlight:"#D5CDB6",inverse:"#FDF6E3",border:"#93A1A1",borderActive:"#268BD2"},"rose-pine":{name:"rose-pine",primary:"#C4A7E7",accent:"#EBBCBA",error:"#EB6F92",warning:"#F6C177",search:"#F6C177",success:"#31748F",info:"#9CCFD8",text:"#E0DEF4",muted:"#908CAA",background:"#191724",panel:"#1F1D2E",element:"#26233A",highlight:"#403D52",inverse:"#191724",border:"#6E6A86",borderActive:"#C4A7E7"},everforest:{name:"everforest",primary:"#7FBBB3",accent:"#D699B6",error:"#E67E80",warning:"#DBBC7F",search:"#DBBC7F",success:"#A7C080",info:"#83C092",text:"#D3C6AA",muted:"#9DA9A0",background:"#232A2E",panel:"#2D353B",element:"#343F44",highlight:"#3D484D",inverse:"#232A2E",border:"#4F585E",borderActive:"#A7C080"},"github-dark":{name:"github-dark",primary:"#58A6FF",accent:"#A371F7",error:"#F85149",warning:"#D29922",search:"#D29922",success:"#3FB950",info:"#79C0FF",text:"#E6EDF3",muted:"#8B949E",background:"#0D1117",panel:"#161B22",element:"#21262D",highlight:"#30363D",inverse:"#0D1117",border:"#30363D",borderActive:"#58A6FF"},iceberg:{name:"iceberg",primary:"#84A0C6",accent:"#A093C7",error:"#E27878",warning:"#E2A478",search:"#E2A478",success:"#B4BE82",info:"#89B8C2",text:"#C6C8D1",muted:"#9AA0B8",background:"#161821",panel:"#1E2132",element:"#2A3150",highlight:"#3D425B",inverse:"#161821",border:"#444B71",borderActive:"#84A0C6"},"ayu-dark":{name:"ayu-dark",primary:"#59C2FF",accent:"#FFB454",error:"#D95757",warning:"#FF8F40",search:"#FF8F40",success:"#C2D94C",info:"#95E6CB",text:"#B3B1AD",muted:"#8B939C",background:"#0A0E14",panel:"#0D1017",element:"#131721",highlight:"#1B212C",inverse:"#0A0E14",border:"#2D3640",borderActive:"#FFB454"},oxocarbon:{name:"oxocarbon",primary:"#78A9FF",accent:"#EE5396",error:"#FA4D56",warning:"#F1C21B",search:"#F1C21B",success:"#42BE65",info:"#3DDBD9",text:"#F2F4F8",muted:"#A8A8A8",background:"#161616",panel:"#262626",element:"#393939",highlight:"#525252",inverse:"#161616",border:"#6F6F6F",borderActive:"#78A9FF"},"night-owl":{name:"night-owl",primary:"#82AAFF",accent:"#C792EA",error:"#EF5350",warning:"#ECC48D",search:"#ECC48D",success:"#ADDB67",info:"#7FDBCA",text:"#D6DEEB",muted:"#8FA4A4",background:"#011627",panel:"#0B2942",element:"#1D3B53",highlight:"#1E4B6B",inverse:"#011627",border:"#5F7E97",borderActive:"#82AAFF"},terminal:{name:"terminal",primary:"#55FFFF",accent:"#FF55FF",error:"#FF5555",warning:"#FFFF55",search:"#FFFF55",success:"#55FF55",info:"#5555FF",text:"#C0C0C0",muted:"#808080",background:"#000000",panel:"#000000",element:"#000000",highlight:"#404040",inverse:"#000000",border:"#555555",borderActive:"#55FFFF"},voltage:{name:"voltage",primary:"#00E5FF",accent:"#FF3EA5",error:"#FF1744",warning:"#FFEA00",search:"#FFEA00",success:"#00E676",info:"#40C4FF",text:"#FFFFFF",muted:"#C0C0C0",background:"#000000",panel:"#000000",element:"#0D0D0D",highlight:"#262626",inverse:"#000000",border:"#808080",borderActive:"#FFFFFF"},"voltage-light":{name:"voltage-light",primary:"#0057B7",accent:"#C2185B",error:"#D50000",warning:"#FF6D00",search:"#FF6D00",success:"#2E7D32",info:"#00838F",text:"#000000",muted:"#424242",background:"#FFFFFF",panel:"#FFFFFF",element:"#EDEDED",highlight:"#D6D6D6",inverse:"#FFFFFF",border:"#616161",borderActive:"#000000"},ironclad:{name:"ironclad",primary:"#4FC3F7",accent:"#FFD54F",error:"#FF5252",warning:"#FFB300",search:"#FFB300",success:"#69F0AE",info:"#64B5F6",text:"#FFFFFF",muted:"#BDBDBD",background:"#000000",panel:"#000000",element:"#101010",highlight:"#242424",inverse:"#000000",border:"#757575",borderActive:"#4FC3F7"},"ironclad-light":{name:"ironclad-light",primary:"#01579B",accent:"#E65100",error:"#B71C1C",warning:"#EF6C00",search:"#EF6C00",success:"#1B5E20",info:"#0277BD",text:"#000000",muted:"#4A4A4A",background:"#FFFFFF",panel:"#FFFFFF",element:"#EFEFEF",highlight:"#DADADA",inverse:"#FFFFFF",border:"#6E6E6E",borderActive:"#01579B"},signal:{name:"signal",primary:"#29B6F6",accent:"#AB47BC",error:"#FF0000",warning:"#FFC400",search:"#FFC400",success:"#00E400",info:"#00B8D4",text:"#FFFFFF",muted:"#B3B3B3",background:"#000000",panel:"#000000",element:"#0A0A0A",highlight:"#202020",inverse:"#000000",border:"#8A8A8A",borderActive:"#29B6F6"},"signal-light":{name:"signal-light",primary:"#01579B",accent:"#6A1B9A",error:"#C62828",warning:"#F9A825",search:"#F9A825",success:"#2E7D32",info:"#00796B",text:"#000000",muted:"#3D3D3D",background:"#FFFFFF",panel:"#FFFFFF",element:"#ECECEC",highlight:"#D2D2D2",inverse:"#FFFFFF",border:"#5C5C5C",borderActive:"#01579B"},system:{name:"system",primary:"#60A5FA",accent:"#C084FC",error:"#F87171",warning:"#FBBF24",search:"#FBBF24",success:"#34D399",info:"#22D3EE",text:"#F9FAFB",muted:"#C4CAD3",background:"#030712",panel:"#111827",element:"#1F2937",highlight:"#374151",inverse:"#030712",border:"#4B5563",borderActive:"#60A5FA"},devctl:{name:"devctl",primary:"#77DDBA",accent:"#9EE9CF",error:"#F28B91",warning:"#E8C586",search:"#E8C586",success:"#91D6A0",info:"#8EC8D8",text:"#DEEEE5",muted:"#A4B9AE",background:"#15201D",panel:"#202923",element:"#293B32",highlight:"#365448",inverse:"#15201D",border:"#526D60",borderActive:"#77DDBA"},ember:{name:"ember",primary:"#FF9F43",accent:"#2EE6FF",error:"#FF4D6D",warning:"#FFE566",search:"#FFE566",success:"#3DFF9A",info:"#2EE6FF",text:"#F7F9FF",muted:"#B0B8CC",background:"#07090F",panel:"#12161F",element:"#1A2130",highlight:"#243044",inverse:"#0B0D12",border:"#334155",borderActive:"#FF9F43"}},cM={opencode:"ember",light:"system",mocha:"catppuccin",latte:"catppuccin-latte","one-dark":"onedark","one dark":"onedark",solarized:"solarized-dark",rosepine:"rose-pine","rose pine":"rose-pine",github:"github-dark",ayu:"ayu-dark","night owl":"night-owl",ansi:"terminal",xterm:"terminal",console:"terminal",classic:"terminal",vga:"terminal",contrast:"voltage","contrast-light":"voltage-light",hc:"voltage","hc-light":"voltage-light",a11y:"voltage","a11y-light":"voltage-light"};dM=["#7AA2F7","#9ECE6A","#E0AF68","#BB9AF7","#2AC3DE","#FF9E64","#F7768E","#73DACA","#C0CAF5","#FF79C6","#7DCFFF","#C3E88D"],pM=["#2E5AAC","#3D7A1F","#9A6B12","#6B3FA0","#0E7A86","#B85C1A","#B4234A","#1A7A6D","#4A5080","#9A3480","#1565C0","#4A7C19"];SM={claude:{dark:"#E08A6A",light:"#B54328"},cursor:{dark:"#B8D4FF",light:"#1E4EBF"},kilo:{dark:"#F0C94A",light:"#8A6400"},codex:{dark:"#4ADE80",light:"#0B7A4B"}}});var Vr=A(()=>{el()});function b0(e){return e!==void 0}function v0(e){let t=e/1000;if(Number.isInteger(t))return`${t}s`;return`${e}ms`}function km(e,t,r){let n=e.indexOf(t),i=((n<0?0:n)+r+e.length)%e.length;return e[i]??e[0]}function w0(e,t){let r=[..._t],n=r.includes(e)?e:xm;return km(r,n,t)}function x0(e,t){let r=[...RM],n=r.reduce((o,i)=>Math.abs(i-e)<Math.abs(o-e)?i:o,r[0]);return km(r,n,t)}function wa(e){let t=[...wm];return t.reduce((r,n)=>Math.abs(n-e)<Math.abs(r-e)?n:r,t[0])}function xa(e,t){return km([...wm],wa(e),t)}function ka(e){let t=wa(e),r=y0[t]??y0[gi];return{px:t,...r}}function Ln(e){return e.label==="compact"}function Sa(e){return e.steps<=2}function k0(e){return wm.map((r,n)=>n<e?"\u2588":"\u2591").join(" ")}function Xc(e){return ka(e).label}function S0(e){let t=e.locked?"Applies this session only. DEVCTL_TUI_CONFIG overrides the user file.":`Saved to ${e.configPath}.`;return[{id:"theme",group:"Appearance",kind:"cycle",name:"Theme",value:e.themeName,hint:"\u2190 \u2192 save enter picker",detail:`Arrows write the theme to the user file. Enter opens the picker. ${t}`},{id:"font",group:"Appearance",kind:"cycle",name:"Display size",value:Xc(e.fontSize),hint:"\u2190 \u2192 save",detail:`Scales content padding and list-row height. Default keeps a thin rule between chrome and panes. Compact sits toolbars flush against borders. Header, nav, and status stay one line. Does not change the terminal font. ${t}`},{id:"mouse",group:"Input",kind:"toggle",name:"Mouse",value:e.mouse?"on":"off",hint:"space or enter toggle",detail:`Clicks on nav and lists. Restart the TUI after a change. ${t}`},{id:"leader",group:"Input",kind:"cycle",name:"Leader",value:v0(e.leaderMs),hint:"\u2190 \u2192 save",detail:`How long ${jt("x")} waits for the next key. ${t}`},{id:"mcp",group:"MCP",kind:"page",name:"Settings page",value:e.mcpRunning?"running \u2192 /mcp":"off \u2192 /mcp",hint:"enter open the MCP page",detail:"Opens a dedicated MCP page (also /mcp or /agent). Start or stop the localhost server, change the port, and copy Claude, Cursor, Codex, and Kilo Code config."},{id:"file",group:"About",kind:"info",name:"File",value:e.configPath,hint:"read-only",detail:e.locked?`Using ${e.configPath} from DEVCTL_TUI_CONFIG.`:`User preferences live in ${e.configPath}.`},{id:"version",group:"About",kind:"info",name:"Version",value:Xt,hint:"read-only",detail:vr()},{id:"reset",group:"About",kind:"action",name:"Reset",value:"defaults",hint:"enter confirm reset",detail:`Restore theme ${xm}, display ${Xc(gi)}, mouse on, leader ${v0(Id)}. Enter asks first. ${t}`}]}function Qc(){return{theme:xm,mouse:!0,leader_timeout:Id,font_size:gi}}function C0(e){return["Appearance","Input","MCP","About"].flatMap((r)=>{let n=e.filter((o)=>o.group===r);if(n.length===0)return[];return[{group:r,items:n}]})}function Sm(e,t){if(e.length===0)return 0;return Math.min(Math.max(t,0),e.length-1)}function oo(e,t){return e[Sm(e,t)]}function Cm(e,t){return e??t}var RM,wm,xm="devctl",y0;var Mr=A(()=>{rt();Vr();RM=[1000,2000,3000],wm=[12,14,16,18,20,22];y0={12:{pad:0,rowH:1,gap:0,steps:1,label:"compact"},14:{pad:0,rowH:1,gap:0,steps:2,label:"default"},16:{pad:1,rowH:1,gap:1,steps:3,label:"comfortable"},18:{pad:1,rowH:2,gap:1,steps:4,label:"large"},20:{pad:2,rowH:2,gap:1,steps:5,label:"xl"},22:{pad:2,rowH:2,gap:2,steps:6,label:"xxl"}}});import{createContext as _M,useContext as PM}from"react";function ye(){return PM(Tm)}var Tm;var Ht=A(()=>{Mr();Vr();Tm=_M(ka(gi))});function ke(e,t){if(t<=0)return"";if(e.length<=t)return e;if(t===1)return"\u2026";return`${e.slice(0,t-1)}\u2026`}function j(e,t){if(t<=0)return"";if(t===1)return ke(e,1);return ke(e,t-1).padEnd(t)}function Qi(e,t=20){let r=Number.isFinite(e)?Math.min(1,Math.max(0,e)):0,n=Math.round(r*t);return"\u2588".repeat(n)+"\u2591".repeat(Math.max(0,t-n))}function Ca(e){if(!Number.isFinite(e)||e<Em)return"< 1s";let t=Math.floor(e/T0),r=Math.floor(e%T0/_m),n=Math.floor(e%_m/Rm),o=Math.floor(e%Rm/Em);if(t>0)return`${t}d ${r}h`;if(r>0)return`${r}h ${n}m`;if(n>0)return`${n}m ${String(o).padStart(2,"0")}s`;return`${o}s`}function Ta(e){if(!Number.isFinite(e)||e<0)return"\u2014";let t=e/AM;if(t>=E0)return`${(t/E0).toFixed(1)}G`;if(t>=1)return`${Math.round(t)}M`;return`${Math.round(e)}K`}function R0(e){if(!Number.isFinite(e)||e<0)return"\u2014";return`${e.toFixed(1)}%`}var Em=1000,Rm,_m,T0,AM=1024,E0=1024;var nt=A(()=>{Rm=60*Em,_m=60*Rm,T0=24*_m});function Am(e){return e>=DM}function Lm(e){return e>=OM}function Im(e){return e>=MM}function ru(e,t=0){return Math.max(1,e-P0-t*2)}function A0(e){let t=_0+Yr+Bt;if(Am(e))t+=dn;if(Lm(e))t+=eu;if(Im(e))t+=In;return Math.max(tu,e-t)}function nu(e,t,r){if(r)return e;let n=t.reduce((a,l)=>Math.max(a,l.length),0),o=Math.min(Pm,Math.max(tu,n+LM)),i=_0+Yr+Bt+o+P0+IM,s=Math.max(Zc,Math.floor(e*NM));return Math.min(s,Math.max(Zc,i))}function L0(e){if(!e)return"";return Object.keys(e.profiles).sort()[0]??""}function ou(e){if(!e)return!0;let t=Object.values(e.services);if(t.length===0)return!0;return!t.some((r)=>ri(r))}function Dm(e,t){if(e.length>0)return e;return[...t]}function iu(e,t){if(e.length>0)return[...e];return t===""?[]:[t]}function su(e){return e.command.args.join(" ")||"\u2014"}function Pa(e,t){let r=ti(t);if(r!=="")return r;if(e.ports.length===0)return"\u2014";return e.ports.map((n)=>`${n.name}:${n.auto?"auto":n.value}`).join(" ")}function au(e){let t=e.health.type||"none",r=e.health.url||e.health.address;return r===""?t:`${t} ${r}`}function lu(e,t){if(t?.identity)return t.identity;let r=e.identity.type||"none",n=e.identity.service_account;return n===""?r:`${r} ${n}`}function cu(e){let t=e.restart.policy||"none";if(e.restart.max_retries>0)return`${t} \xD7${e.restart.max_retries}`;return t}function I0(e,t,r,n,o){let i={...e.environment.defaults,...e.environment.vars},a=FM(o??i,t,r,n);return[...new Set([...Object.keys(a),...e.environment.required])].map((c)=>({key:c,value:a[c]??"",required:e.environment.required.includes(c),fromConfig:Object.prototype.hasOwnProperty.call(i,c)})).sort((c,u)=>c.fromConfig===u.fromConfig?c.key.localeCompare(u.key):c.fromConfig?-1:1)}function D0(e,t){if(!e||e.processes.length===0)return;if(t!==void 0&&t!==""&&e.session_id===t)return;return e}function ti(e){if(!e)return"";if(e.ports.http!==void 0)return String(e.ports.http);let t=Object.values(e.ports)[0];return t!==void 0?String(t):""}function yr(e){if(!e)return"STOPPED";return Ui(e)}function FM(e,t,r,n){if(t)return e;return new Rr(r,n).redactMap(e)}function Aa(e){return $M.has(e)}function ri(e){if(!e)return!1;return Aa(e.state)}var _0=8,Yr=12,dn=10,eu=8,In=8,Ea=9,Ra=7,_a=8,tu=12,Pm=40,Bt=2,LM=2,P0=2,IM=2,Zc=34,DM=48,OM=60,MM=72,NM=0.48,$M;var Ut=A(()=>{$t();To();$M=new Set(["RUNNING","STARTING","RESTARTING","HEALTHY","UNHEALTHY"])});function Zi(e){return cv(e===""?So:e)}function Nm(e,t,r){let n=r?M0:UM+M0+Math.max(0,t)*2;return Math.max(1,e-n)}function zM(e){if(e.startsWith('"')||e.startsWith("'"))return"string";if(/^\d+$/.test(e))return"number";return"keyword"}function du(e){return e.replace(qM,"")}function F0(e){try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e}}function $0(e){return yv(e.body,e.attributes)}function H0(e,t){let r=Math.max(1,t),n=du(e).replace(/\r\n/g,`
|
|
2476
|
+
`}]});function _O(){return[{path:"skills/devctl-onboard/SKILL.md",title:"Onboard procedure",body:ro.procedure},{path:"skills/devctl-onboard/references/authoring.md",title:"Onboard authoring",body:ro.authoring},{path:"skills/devctl-onboard/references/discovery.md",title:"Onboard discovery",body:ro.discovery}]}function Vx(){return[...zx,..._O()]}function Yx(e){let t=e.trim();if(t==="")throw Error("path is required");let r=Vx(),n=r.find((s)=>s.path===t),o=n?[n]:r.filter((s)=>s.path.endsWith(`/${t}`));if(o.length!==1)throw Error(`no unique doc for path "${t}"; available: ${r.map((s)=>s.path).join(", ")}`);let i=o[0];return{path:i.path,title:i.title,body:i.body}}function PO(e){return e.toLowerCase().split(/[^a-z0-9_]+/).filter((t)=>t.length>=EO)}function AO(e,t){let r=e.title.toLowerCase(),n=e.path.toLowerCase(),o=e.body.toLowerCase(),i=0;for(let a of t){if(r.includes(a))i+=kO;if(n.includes(a))i+=SO;let l=o.split(a).length-1;i+=Math.min(l,CO)}let s=t.join(" ");if(s.length>=RO&&o.includes(s))i+=TO;return i}function LO(e,t){let r=e.split(`
|
|
2477
|
+
`),n=0,o=-1;for(let s=0;s<r.length;s++){let a=r.slice(s,s+Kx).join(`
|
|
2478
|
+
`).toLowerCase(),l=0;for(let c of t)if(a.includes(c))l+=1;if(l>o)o=l,n=s}let i=r.slice(n,n+Kx).join(`
|
|
2479
|
+
`).trim();if(i.length<=Gx)return i;return`${i.slice(0,Gx).trimEnd()}\u2026`}function IO(e){if(e===void 0||Number.isNaN(e))return wO;return Math.min(xO,Math.max(1,Math.floor(e)))}function Jx(e,t){let r=e.trim(),n=PO(r);if(n.length===0)throw Error("query is required");let o=IO(t),i=Vx().map((s)=>({path:s.path,title:s.title,score:AO(s,n),snippet:LO(s.body,n)})).filter((s)=>s.score>0).sort((s,a)=>a.score-s.score||s.path.localeCompare(a.path)).slice(0,o);return{query:r,hits:i}}var wO=5,xO=10,kO=12,SO=8,CO=8,TO=15,Gx=400,Kx=5,EO=2,RO=4;var Xx=A(()=>{sm();qx()});import{existsSync as DO,readFileSync as OO}from"fs";function Qx(e){return ma.find((r)=>r.name===e)?.mutates===!0&&!NO.has(e)}function no(e,t){return!(t??[]).includes(e)}function Zx(e){return ma.filter((t)=>no(t.name,e))}function Hc(e){return ma.some((t)=>t.name===e)}function Zo(e){return new Rr(e.secrets.extra_markers,e.secrets.extra_patterns)}function Uc(e){return Object.values(e.services).map((t)=>({name:t.name,state:t.state,health:t.health,ports:t.ports,pid:t.pid,last_error:t.last_error}))}function FO(e,t){let r=e.config(),n=r.services[t];if(!n)throw Error(`unknown service ${t}`);let i=e.status().services[t],s=Zo(r);return{name:t,state:i?.state,health:i?.health,pid:i?.pid,last_error:i?.last_error,command:n.command.args,cwd:n.working_dir,ports:i?.ports??Object.fromEntries(n.ports.map((a)=>[a.name,a.value])),environment:s.redactMap({...n.environment.defaults,...n.environment.vars}),container:n.container?{...n.container,env:s.redactMap(n.container.env)}:void 0}}function jc(e){return{session_id:e.session_id,repo_root:e.repo_root,profile:e.profile,setup_mode:e.setup_mode===!0?!0:void 0,identity:{user:e.identity.user,project:e.identity.project,adc:e.identity.adc,iap:e.identity.iap,service_accounts:e.identity.service_accounts,service_account_status:e.identity.service_account_status},proxy:{running:e.proxy.running,address:e.proxy.address,routes:e.proxy.routes,requestTotal:e.proxy.requestTotal,requestErrors:e.proxy.requestErrors,recentRequests:(e.proxy.recentRequests??[]).slice(0,20).map((t)=>({timestamp:t.timestamp,request_id:t.requestId,trace_id:t.traceId,method:t.method,path:t.path,route:t.route,status:t.status,duration_ms:t.durationMs,trace_duration_ms:t.traceDurationMs,error:t.error}))},logs:e.logs,mcp:e.mcp?{running:e.mcp.running,address:e.mcp.address,port:e.mcp.port}:{running:!1},web:e.web?{running:e.web.running,address:e.web.address,port:e.web.port}:{running:!1},stats_series:e.stats_series}}async function fa(e,t){let r=typeof t.service==="string"?t.service:"",n=typeof t.since==="string"?t.since:"",o=typeof t.cursor==="string"?t.cursor:void 0,i=typeof t.attribute_key==="string"?t.attribute_key:"",s=typeof t.attribute_value==="string"?t.attribute_value:"",a=await e.logsPage({services:r===""?[]:[r],level:typeof t.level==="string"?t.level:"",search:typeof t.search==="string"?t.search:"",source:typeof t.source==="string"?t.source:"",since:n,until:typeof t.until==="string"?t.until:"",requestId:typeof t.request_id==="string"?t.request_id:void 0,traceId:typeof t.trace_id==="string"?t.trace_id:void 0,attribute:i!==""&&s!==""?{key:i,value:s}:void 0,cursor:o,direction:o?"forward":void 0,limit:MO}),l=Zo(e.config());return{events:a.events.map((c)=>e0(l,c)),truncated:a.hasPrev,has_more:a.hasNext,next_since:a.events[a.events.length-1]?.timestamp??n,next_cursor:a.nextCursor,session_changed:a.sessionChanged}}function e0(e,t){let r=xl(e,t),n=r.resource["process.pid"];return{timestamp:r.timestamp,service:r.service,source:r.source,severityText:r.severityText,severityNumber:r.severityNumber,body:r.body,attributes:r.attributes,traceId:r.traceId,spanId:r.spanId,seq:r.seq,level:r.severityText,message:Kt(r),pid:typeof n==="number"?n:0}}function t0(e,t){return{trace_id:t.traceId,request_id:t.requestId,spans:t.tree.spans.map((r)=>kl(e,r)),logs:t.events.map((r)=>e0(e,r))}}async function cm(e,t){let r=typeof t.trace_id==="string"?t.trace_id:"";if(r==="")throw Error("trace_id is required");if(!e.getTrace)throw Error("trace store is unavailable");return t0(Zo(e.config()),await e.getTrace(r))}async function um(e,t){let r=typeof t.request_id==="string"?t.request_id:"";if(r==="")throw Error("request_id is required");if(!e.traceRequest)throw Error("trace store is unavailable");return t0(Zo(e.config()),await e.traceRequest(r))}function dm(e){return{running:e.proxy.running,total:e.proxy.requestTotal??0,errors:e.proxy.requestErrors??0,requests:(e.proxy.recentRequests??[]).map((t)=>({timestamp:t.timestamp,request_id:t.requestId,trace_id:t.traceId,method:t.method,path:t.path,route:t.route,status:t.status,duration_ms:t.durationMs,trace_duration_ms:t.traceDurationMs,error:t.error}))}}function pm(e){return Object.entries(e.profiles).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>({name:t,services:r.services}))}function Yi(e){return e.trim()===""?void 0:e}function $O(e){let t={name:e.name,match:e.match,upstream:e.upstream.url!==""?e.upstream.url:Yi(e.upstream.service??"")?`service:${e.upstream.service}${e.upstream.port?`/${e.upstream.port}`:""}`:"",auth:e.auth.type},r=Yi(e.auth.identity.type),n=Yi(e.auth.audience),o=Yi(e.auth.identity.service_account||e.auth.service_account),i=Yi(e.auth.client_id),s=Xl(e.auth.client_secret),a=Yi(e.auth.credentials??"");if(r)t.identity=r;if(n)t.audience=n;if(o)t.service_account=o;if(i)t.client_id=i;if(s)t.client_secret=s;if(a)t.credentials=a;let l=Object.keys(e.auth.headers??{});if(l.length>0)t.headers=l;return t}function Bc(e){let t=Object.entries(e.services).map(([r,n])=>({name:r,description:n.description,command:n.command.args,cwd:n.working_dir,ports:n.ports.map((o)=>({name:o.name,value:o.auto?0:o.value,auto:o.auto})),dependencies:n.dependencies,container:n.container?{image:n.container.image,runtime:n.container.runtime||"docker",ports:n.container.ports,volumes:n.container.volumes}:void 0}));return{project:e.project.name,config_path:e.configPath,repo_root:e.repoRoot,services:t,tasks:Object.entries(e.tasks).sort(([r],[n])=>r.localeCompare(n)).map(([r,n])=>({name:r,dependencies:n.dependencies})),proxy:{enabled:e.proxy.enabled,gateway:e.proxy.gateway,credentials:e.proxy.credentials,listen:{host:e.proxy.listen.host,port:e.proxy.listen.port},routes:e.proxy.routes.map((r)=>$O(r))}}}function HO(e){let t=Zo(e);return{entries:Xn(e).map((r)=>{let n=typeof r.value==="string"?r.value:JSON.stringify(r.value);return{...r,value:t.redactMap({[r.path]:n})[r.path]}})}}function $c(e){if(!Array.isArray(e))return[];return e.filter((t)=>typeof t==="string")}async function Wc(e,t,r){switch(t){case"list_services":return Uc(e.status());case"get_service":if(typeof r.name!=="string"||r.name==="")throw Error("name is required");return FO(e,r.name);case"get_status":return jc(e.status());case"get_logs":return fa(e,r);case"get_trace":return cm(e,r);case"trace_request":return um(e,r);case"get_requests":return dm(e.status());case"recent_errors":return fa(e,{...r,level:"ERROR"});case"list_profiles":return pm(e.config());case"get_config":return Bc(e.config());case"get_config_sources":return HO(e.config());case"run_doctor":return e.doctor();case"start_services":return e.start({services:$c(r.services),profile:typeof r.profile==="string"&&r.profile!==""?r.profile:void 0});case"stop_services":return await e.stop($c(r.services)),{ok:!0};case"restart_services":return await e.restart($c(r.services),r.cascade===!0),{ok:!0};case"reload_config":return e.reload();case"run_task":{if(typeof r.name!=="string"||r.name==="")throw Error("name is required");let n=await e.runTask(r.name),o=Zo(e.config());return{...n,stdout:o.redactText(n.stdout),stderr:o.redactText(n.stderr)}}case"start_proxy":return await e.startProxy(),{ok:!0};case"stop_proxy":return await e.stopProxy(),{ok:!0};case"exec_service":{if(typeof r.service!=="string"||r.service==="")throw Error("service is required");if(!e.exec)throw Error("exec is unavailable");let n=await e.exec(r.service,$c(r.command),r.print_env===!0),o=Zo(e.config());return{...n,stdout:o.redactText(n.stdout),stderr:o.redactText(n.stderr),environment:n.environment?o.redactMap(n.environment):void 0}}case"get_setup_guide":return UO(r);case"search_docs":return Jx(typeof r.query==="string"?r.query:"",typeof r.limit==="number"?r.limit:void 0);case"get_doc":return Yx(typeof r.path==="string"?r.path:"");case"validate_config":return jO(e,r);default:throw Error(`unknown tool ${t}`)}}function UO(e){let t=typeof e.section==="string"?e.section:"procedure",r=t in ro?t:"procedure";return{section:r,text:ro[r],sections:Object.keys(ro)}}function jO(e,t){let r=e.config();if(typeof t.text==="string"){let o=e.validateConfigText(t.text);return{valid:o.length===0,issues:o,source:"candidate",config_path:r.configPath}}if(!DO(r.configPath))return{valid:!1,issues:[`no configuration at ${r.configPath}`],source:"disk",config_path:r.configPath,setup_mode:!0};let n=e.validateConfigText(OO(r.configPath,"utf8"));return{valid:n.length===0,issues:n,source:"disk",config_path:r.configPath}}function r0(e){return am.includes(e)}async function n0(e,t){switch(t){case"devctl://status":return jc(e.status());case"devctl://services":return Uc(e.status());case"devctl://logs":return fa(e,{});case"devctl://config":return Bc(e.config());case"devctl://doctor":return e.doctor();default:throw Error(`unknown resource ${t}`)}}var MO=200,am,lm,ma,NO;var Ji=A(()=>{To();sn();Xx();sm();am=["devctl://status","devctl://services","devctl://logs","devctl://config","devctl://doctor"],lm=["inspect","logs","diagnostics","control","setup"],ma=[{name:"list_services",label:"List services",summary:"Name, state, health, ports, pid",category:"inspect",description:"List services with state, health, ports, pid, and last error",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"get_service",label:"Service detail",summary:"One service with command, cwd, ports",category:"inspect",description:"One service plus command, cwd, and ports. Environment values are redacted.",inputSchema:{type:"object",properties:{name:{type:"string"}},required:["name"],additionalProperties:!1}},{name:"get_status",label:"Status",summary:"Profile, identity, proxy, log counts",category:"inspect",description:"Profile, session, identity flags (no tokens), proxy, and log counts",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"get_logs",label:"Read logs",summary:"Filtered log pages, secrets redacted",category:"logs",description:"Recent log records, optionally filtered. Capped at 200 events per page. Secrets are redacted. Pass cursor=next_cursor to page forward with no duplicate or same-millisecond-lost events; since/until are plain timestamp filters for a fresh query, not a follow cursor.",inputSchema:{type:"object",properties:{service:{type:"string"},level:{type:"string"},search:{type:"string"},source:{type:"string"},since:{type:"string",description:"Only events at or after this timestamp"},until:{type:"string",description:"Only events at or before this timestamp"},cursor:{type:"string",description:"Opaque cursor from a previous response's next_cursor; continues forward from exactly there"},request_id:{type:"string",description:"Filter by X-Devctl-Request-ID / devctl.request_id"},trace_id:{type:"string",description:"Filter by W3C trace id"},attribute_key:{type:"string",description:"Attribute key to match (with attribute_value)"},attribute_value:{type:"string",description:"Attribute value to match (with attribute_key)"}},additionalProperties:!1}},{name:"get_trace",label:"Get trace",summary:"Span tree and correlated logs",category:"logs",description:"Return the span tree and correlated log records for a W3C trace id. Secrets are redacted.",inputSchema:{type:"object",properties:{trace_id:{type:"string"}},required:["trace_id"],additionalProperties:!1}},{name:"trace_request",label:"Trace request",summary:"Trace for a proxy request id",category:"logs",description:"Resolve a proxy X-Devctl-Request-ID to its trace, then return the span tree and correlated logs. Secrets are redacted.",inputSchema:{type:"object",properties:{request_id:{type:"string"}},required:["request_id"],additionalProperties:!1}},{name:"get_requests",label:"Recent requests",summary:"Proxy request ring with trace ids",category:"inspect",description:"Recent proxy requests with method, path, status, duration, request id, and trace id.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"recent_errors",label:"Recent errors",summary:"Latest error-severity log records",category:"logs",description:"Latest error and fatal log records, capped at 200, secrets redacted. Same paging fields as get_logs.",inputSchema:{type:"object",properties:{service:{type:"string"},search:{type:"string"},source:{type:"string"},since:{type:"string"},until:{type:"string"},cursor:{type:"string"},request_id:{type:"string"},trace_id:{type:"string"}},additionalProperties:!1}},{name:"list_profiles",label:"List profiles",summary:"Configured profiles and their members",category:"inspect",description:"Configured profiles and their member services",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"get_config",label:"Read config",summary:"Merged project summary, no secret values",category:"inspect",description:"Merged project summary: services, routes, and proxy listen paths. Route auth includes type, identity, audience, and optional IAP client_id. client_secret is returned only as a ${ENV} template, never a resolved secret.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"get_config_sources",label:"Config sources",summary:"Winning and shadowed config sources",category:"inspect",description:"List effective configuration values with their winning source/layer and any shadowed sources. Secret-like values are redacted.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"run_doctor",label:"Run doctor",summary:"Environment diagnostics",category:"diagnostics",description:"Run environment diagnostics",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"start_services",label:"Start services",summary:"Start named services or a profile",category:"control",mutates:!0,description:"Start named services, or a profile when names are omitted. Empty start uses profile, then the active session profile, then the first configured profile \u2014 never every service.",inputSchema:{type:"object",properties:{services:{type:"array",items:{type:"string"}},profile:{type:"string",description:"Profile to start when services is omitted"}},additionalProperties:!1}},{name:"stop_services",label:"Stop services",summary:"Stop services and their dependents",category:"control",mutates:!0,description:"Stop named services, or all started services when names are omitted. Also stops every service that transitively depends on a named one (never a named service's own dependencies, which other running services may still need).",inputSchema:{type:"object",properties:{services:{type:"array",items:{type:"string"}}},additionalProperties:!1}},{name:"restart_services",label:"Restart services",summary:"Restart services, optionally cascading",category:"control",mutates:!0,description:"Restart named services. By default this touches only the named services, not anything that depends on them. Pass cascade=true to also restart their transitive dependents (the same set stop_services would affect).",inputSchema:{type:"object",properties:{services:{type:"array",items:{type:"string"}},cascade:{type:"boolean",description:"Also restart transitive dependents; default false restarts only the named services"}},additionalProperties:!1}},{name:"reload_config",label:"Reload config",summary:"Re-read .devctl configuration",category:"control",mutates:!0,description:"Reload .devctl configuration",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"run_task",label:"Run task",summary:"Run a named one-off task",category:"control",mutates:!0,description:"Run a named task from configuration. Output is also written to the log ring as task:<name>.",inputSchema:{type:"object",properties:{name:{type:"string"}},required:["name"],additionalProperties:!1}},{name:"start_proxy",label:"Start proxy",summary:"Start the local reverse proxy",category:"control",mutates:!0,description:"Start the local reverse proxy. Same as CLI `devctl proxy start` and TUI start on the proxy screen.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"stop_proxy",label:"Stop proxy",summary:"Stop the local reverse proxy",category:"control",mutates:!0,description:"Stop the local reverse proxy and leave it suppressed until start_proxy (or CLI/TUI start) runs again.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"exec_service",label:"Execute in service",summary:"Run a command in a resolved service context",category:"control",mutates:!0,description:"Run an arbitrary command with a service's fully resolved environment and working directory, whether or not it is running. Output and print_env values are redacted.",inputSchema:{type:"object",properties:{service:{type:"string"},command:{type:"array",items:{type:"string"}},print_env:{type:"boolean",description:"Return the resolved environment without executing a command"}},required:["service"],additionalProperties:!1}},{name:"get_setup_guide",label:"Setup guide",summary:"How to author a .devctl for this repo",category:"setup",description:"The devctl onboarding guide: how to survey a repository and author a .devctl configuration for it. Read section=procedure first; read section=authoring BEFORE writing any YAML (it carries the rules the loader rejects on, which the JSON Schema does not state); read section=discovery for mapping compose/package.json/pyproject/Terraform/k8s/.env to services. Write the files with your own editing tools \u2014 this server does not write them \u2014 then check your work with validate_config.",inputSchema:{type:"object",properties:{section:{type:"string",enum:["procedure","authoring","discovery"],description:"Which part of the guide to return; defaults to procedure"}},additionalProperties:!1}},{name:"search_docs",label:"Search docs",summary:"Search the embedded product documentation",category:"setup",description:"Search the compiled-in product documentation (docs/*.md plus the onboarding skill). Returns ranked pages with short snippets for discovery. To read a full page, pass a hit's `path` to get_doc. Use this for IAP, proxy, MCP, configuration, and similar topics; use get_setup_guide for the full onboarding procedure.",inputSchema:{type:"object",properties:{query:{type:"string",description:"Keywords or a short phrase to search for"},limit:{type:"integer",description:"Maximum hits to return (default 5, max 10)"}},required:["query"],additionalProperties:!1}},{name:"get_doc",label:"Get doc",summary:"Read a full documentation page",category:"setup",description:"Return the complete text of one embedded documentation page. Pass the `path` from a search_docs hit (e.g. docs/proxy.md) \u2014 search_docs only returns short snippets, so use this to read the whole page. A basename like proxy.md also resolves when unambiguous.",inputSchema:{type:"object",properties:{path:{type:"string",description:"Doc path from a search_docs hit, e.g. docs/proxy.md"}},required:["path"],additionalProperties:!1}},{name:"validate_config",label:"Validate config",summary:"Check configuration or a draft for errors",category:"setup",description:"Validate devctl configuration and return the exact issues the loader would report. With no arguments, validates what is on disk. Pass text to validate a candidate config.yaml before writing it \u2014 the candidate is run through the real load pipeline (modular services/profiles, overlays, templates), so it works even when no configuration exists yet. This is the only way to validate over MCP; there is no CLI round-trip needed.",inputSchema:{type:"object",properties:{text:{type:"string",description:"Candidate config.yaml contents to validate instead of the file on disk"}},additionalProperties:!1}}],NO=new Set(["exec_service"])});function m0(e){return{...e,runDoctor:(t,r,n)=>e.runDoctor.execute(t,r,n),startupPlan:(t,r,n)=>e.getStartupPlan.execute(t,r,n),shutdownPlan:(t,r)=>e.getShutdownPlan.execute(t,r),shutdownPlanExact:(t,r)=>fc(t,r),resolveStartRequest:(t,r)=>e.resolveStart.execute(t,{...r,profile:r.profile?Ar(r.profile):void 0,activeProfile:r.activeProfile===void 0?void 0:Ar(r.activeProfile)})}}var h0=A(()=>{$t()});function Kc(e){let t=e.toLowerCase().trim(),r=yM[t];if(r)return r;return Pt.includes(t)?t:"devctl"}function bM(){if(process.env.DEVCTL_THEME_LIGHT==="1")return!0;if(process.env.DEVCTL_THEME_LIGHT==="0")return!1;if(process.platform==="darwin")try{let t=Bun.spawnSync(["defaults","read","-g","AppleInterfaceStyle"],{stdout:"pipe",stderr:"pipe"}),r=t.stdout.toString();if(t.exitCode===0&&r.toLowerCase().includes("dark"))return!1;if(t.exitCode!==0)return!0}catch{}let e=process.env.COLORFGBG??"";if(e.includes(";15")||e.endsWith(";7"))return!0;if(e.includes(";0")||e.endsWith(";8"))return!1;return!1}function g0(e){let t=Kc(e);if(t==="system"){if(bM())return{...vm["solarized-light"],name:"system"};return vm.system}return vm[t]}function Or(e){switch(e.toUpperCase()){case"HEALTHY":case"OK":return"\u2713";case"UNHEALTHY":case"WARNING":case"WARN":return"!";case"FAILED":case"ERROR":return"\u2717";case"STOPPED":case"UNKNOWN":return"\u25CB";case"RUNNING":case"STARTING":case"RESTARTING":return"\u25CF";default:return"\u25CB"}}function ei(e,t){return ba(e)>=ya?Vc:t}function ba(e){let t=e.startsWith("#")?e.slice(1):e,r=Number.parseInt(t,_M);if(Number.isNaN(r))return 0;let n=r>>PM&ym,o=r>>AM&ym,i=r&ym;return(n*CM+o*TM+i*EM)/RM}function LM(e){let t=kM;for(let r=0;r<e.length;r+=1)t^=e.charCodeAt(r),t=Math.imul(t,SM);return t>>>0}function Yc(e){return ba(e.background)>=ya}function wm(e){if(!e||!/^#[0-9a-f]{6}$/i.test(e))return!1;return ba(e)<ya}function Jc(e,t){let r=IM[e];return Yc(t)?r.light:r.dark}function v0(e,t){return ba(Jc(e,t))>=ya?DM:OM}function Ye(e,t){if(e===""||e==="all")return t.muted;let r=ba(t.background)>=ya?xM:wM;return r[LM(e)%r.length]??t.info}function MM(e,t){switch(t.toUpperCase()){case"ERROR":case"FATAL":return e.error;case"WARN":case"WARNING":return e.warning;case"INFO":return e.text;case"DEBUG":case"TRACE":return e.muted;default:return e.text}}function y0(e,t,r){if(r==="search")return e.search;if(r==="string")return e.accent;if(r==="number")return e.info;if(r==="keyword")return e.error;return MM(e,t)}function dt(e,t){switch(t.toUpperCase()){case"HEALTHY":case"OK":return e.success;case"UNHEALTHY":case"WARNING":case"WARN":return e.warning;case"FAILED":case"ERROR":return e.error;case"RUNNING":case"STARTING":case"RESTARTING":return e.primary;case"INFO":return e.info;case"FATAL":return e.error;case"DEBUG":case"TRACE":case"UNKNOWN":return e.muted;default:return e.muted}}var Pt,bm,vm,yM,wM,xM,kM=2166136261,SM=16777619,CM=299,TM=587,EM=114,RM=1000,ya=160,_M=16,ym=255,PM=16,AM=8,Vc="#1A1A1A",IM,DM="#1A1A1A",OM="#F5F5F5";var rt=A(()=>{Pt=["devctl","ember","tokyonight","catppuccin","catppuccin-latte","nord","gruvbox","kanagawa","dracula","onedark","monokai","solarized-dark","solarized-light","rose-pine","everforest","github-dark","iceberg","ayu-dark","oxocarbon","night-owl","terminal","voltage","voltage-light","ironclad","ironclad-light","signal","signal-light","system"],bm={devctl:"forest + mint, website palette",ember:"warm orange",tokyonight:"Tokyo Night storm blues",catppuccin:"Catppuccin Mocha","catppuccin-latte":"Catppuccin Latte (light)",nord:"Arctic Nord frost",gruvbox:"Gruvbox dark hard",kanagawa:"Kanagawa wave / gold",dracula:"classic Dracula purple",onedark:"Atom / VS Code One Dark",monokai:"Monokai Sublime","solarized-dark":"Solarized dark","solarized-light":"Solarized light","rose-pine":"Ros\xE9 Pine moon",everforest:"Everforest dark medium","github-dark":"GitHub dimmed canvas",iceberg:"Iceberg navy","ayu-dark":"Ayu Mirage-adjacent dark",oxocarbon:"IBM Oxocarbon","night-owl":"Sarah Drasner Night Owl",terminal:"black + VGA ANSI chrome",voltage:"max contrast, electric neon (dark)","voltage-light":"max contrast, electric neon (light)",ironclad:"max contrast, steel & amber (dark)","ironclad-light":"max contrast, steel & amber (light)",signal:"max contrast, traffic-light semantics (dark)","signal-light":"max contrast, traffic-light semantics (light)",system:"neutral dark (system default)"},vm={tokyonight:{name:"tokyonight",primary:"#82AAFF",accent:"#C792EA",error:"#FF5370",warning:"#FFCB6B",search:"#FFCB6B",success:"#C3E88D",info:"#89DDFF",text:"#F4F7FF",muted:"#A8B2CC",background:"#0F111A",panel:"#1A1B2E",element:"#24283B",highlight:"#2E3350",inverse:"#0F111A",border:"#3D4466",borderActive:"#82AAFF"},catppuccin:{name:"catppuccin",primary:"#89B4FA",accent:"#F5C2E7",error:"#F38BA8",warning:"#F9E2AF",search:"#F9E2AF",success:"#A6E3A1",info:"#89DCEB",text:"#E4E8F7",muted:"#A6A9BE",background:"#11111B",panel:"#1E1E2E",element:"#313244",highlight:"#45475A",inverse:"#11111B",border:"#585B70",borderActive:"#89B4FA"},"catppuccin-latte":{name:"catppuccin-latte",primary:"#1E66F5",accent:"#EA76CB",error:"#D20F39",warning:"#DF8E1D",search:"#DF8E1D",success:"#40A02B",info:"#179299",text:"#4C4F69",muted:"#6C6F85",background:"#EFF1F5",panel:"#E6E9EF",element:"#DCE0E8",highlight:"#CCD0DA",inverse:"#EFF1F5",border:"#9CA0B0",borderActive:"#1E66F5"},nord:{name:"nord",primary:"#88C0D0",accent:"#B48EAD",error:"#BF616A",warning:"#EBCB8B",search:"#EBCB8B",success:"#A3BE8C",info:"#8FBCBB",text:"#F2F5FA",muted:"#A4AEBF",background:"#2E3440",panel:"#3B4252",element:"#434C5E",highlight:"#4C566A",inverse:"#2E3440",border:"#5E6A7D",borderActive:"#88C0D0"},gruvbox:{name:"gruvbox",primary:"#FE8019",accent:"#FABD2F",error:"#FB4934",warning:"#FE8019",search:"#FE8019",success:"#B8BB26",info:"#8EC07C",text:"#F2E5BC",muted:"#C4B394",background:"#1D2021",panel:"#282828",element:"#3C3836",highlight:"#504945",inverse:"#1D2021",border:"#665C54",borderActive:"#FE8019"},kanagawa:{name:"kanagawa",primary:"#7FB4CA",accent:"#E6C384",error:"#E82424",warning:"#FFA066",search:"#FFA066",success:"#98BB6C",info:"#7FB4CA",text:"#E8E4C9",muted:"#B4C0D6",background:"#16161D",panel:"#1F1F28",element:"#2A2A37",highlight:"#363646",inverse:"#16161D",border:"#54546D",borderActive:"#E6C384"},dracula:{name:"dracula",primary:"#BD93F9",accent:"#FF79C6",error:"#FF5555",warning:"#F1FA8C",search:"#F1FA8C",success:"#50FA7B",info:"#8BE9FD",text:"#F8F8F2",muted:"#8B9DC9",background:"#21222C",panel:"#282A36",element:"#343746",highlight:"#44475A",inverse:"#21222C",border:"#6272A4",borderActive:"#BD93F9"},onedark:{name:"onedark",primary:"#61AFEF",accent:"#C678DD",error:"#E06C75",warning:"#E5C07B",search:"#E5C07B",success:"#98C379",info:"#56B6C2",text:"#ABB2BF",muted:"#9DA5B4",background:"#21252B",panel:"#282C34",element:"#2C323C",highlight:"#3E4451",inverse:"#21252B",border:"#4B5263",borderActive:"#61AFEF"},monokai:{name:"monokai",primary:"#66D9EF",accent:"#AE81FF",error:"#F92672",warning:"#E6DB74",search:"#E6DB74",success:"#A6E22E",info:"#66D9EF",text:"#F8F8F2",muted:"#A39E80",background:"#1D1E19",panel:"#272822",element:"#3E3D32",highlight:"#49483E",inverse:"#1D1E19",border:"#75715E",borderActive:"#F92672"},"solarized-dark":{name:"solarized-dark",primary:"#268BD2",accent:"#6C71C4",error:"#DC322F",warning:"#B58900",search:"#B58900",success:"#859900",info:"#2AA198",text:"#93A1A1",muted:"#586E75",background:"#002B36",panel:"#073642",element:"#0A4A58",highlight:"#1A5A68",inverse:"#002B36",border:"#586E75",borderActive:"#268BD2"},"solarized-light":{name:"solarized-light",primary:"#268BD2",accent:"#D33682",error:"#DC322F",warning:"#CB4B16",search:"#CB4B16",success:"#859900",info:"#2AA198",text:"#586E75",muted:"#839496",background:"#FDF6E3",panel:"#EEE8D5",element:"#E4DCC8",highlight:"#D5CDB6",inverse:"#FDF6E3",border:"#93A1A1",borderActive:"#268BD2"},"rose-pine":{name:"rose-pine",primary:"#C4A7E7",accent:"#EBBCBA",error:"#EB6F92",warning:"#F6C177",search:"#F6C177",success:"#31748F",info:"#9CCFD8",text:"#E0DEF4",muted:"#908CAA",background:"#191724",panel:"#1F1D2E",element:"#26233A",highlight:"#403D52",inverse:"#191724",border:"#6E6A86",borderActive:"#C4A7E7"},everforest:{name:"everforest",primary:"#7FBBB3",accent:"#D699B6",error:"#E67E80",warning:"#DBBC7F",search:"#DBBC7F",success:"#A7C080",info:"#83C092",text:"#D3C6AA",muted:"#9DA9A0",background:"#232A2E",panel:"#2D353B",element:"#343F44",highlight:"#3D484D",inverse:"#232A2E",border:"#4F585E",borderActive:"#A7C080"},"github-dark":{name:"github-dark",primary:"#58A6FF",accent:"#A371F7",error:"#F85149",warning:"#D29922",search:"#D29922",success:"#3FB950",info:"#79C0FF",text:"#E6EDF3",muted:"#8B949E",background:"#0D1117",panel:"#161B22",element:"#21262D",highlight:"#30363D",inverse:"#0D1117",border:"#30363D",borderActive:"#58A6FF"},iceberg:{name:"iceberg",primary:"#84A0C6",accent:"#A093C7",error:"#E27878",warning:"#E2A478",search:"#E2A478",success:"#B4BE82",info:"#89B8C2",text:"#C6C8D1",muted:"#9AA0B8",background:"#161821",panel:"#1E2132",element:"#2A3150",highlight:"#3D425B",inverse:"#161821",border:"#444B71",borderActive:"#84A0C6"},"ayu-dark":{name:"ayu-dark",primary:"#59C2FF",accent:"#FFB454",error:"#D95757",warning:"#FF8F40",search:"#FF8F40",success:"#C2D94C",info:"#95E6CB",text:"#B3B1AD",muted:"#8B939C",background:"#0A0E14",panel:"#0D1017",element:"#131721",highlight:"#1B212C",inverse:"#0A0E14",border:"#2D3640",borderActive:"#FFB454"},oxocarbon:{name:"oxocarbon",primary:"#78A9FF",accent:"#EE5396",error:"#FA4D56",warning:"#F1C21B",search:"#F1C21B",success:"#42BE65",info:"#3DDBD9",text:"#F2F4F8",muted:"#A8A8A8",background:"#161616",panel:"#262626",element:"#393939",highlight:"#525252",inverse:"#161616",border:"#6F6F6F",borderActive:"#78A9FF"},"night-owl":{name:"night-owl",primary:"#82AAFF",accent:"#C792EA",error:"#EF5350",warning:"#ECC48D",search:"#ECC48D",success:"#ADDB67",info:"#7FDBCA",text:"#D6DEEB",muted:"#8FA4A4",background:"#011627",panel:"#0B2942",element:"#1D3B53",highlight:"#1E4B6B",inverse:"#011627",border:"#5F7E97",borderActive:"#82AAFF"},terminal:{name:"terminal",primary:"#55FFFF",accent:"#FF55FF",error:"#FF5555",warning:"#FFFF55",search:"#FFFF55",success:"#55FF55",info:"#5555FF",text:"#C0C0C0",muted:"#808080",background:"#000000",panel:"#000000",element:"#000000",highlight:"#404040",inverse:"#000000",border:"#555555",borderActive:"#55FFFF"},voltage:{name:"voltage",primary:"#00E5FF",accent:"#FF3EA5",error:"#FF1744",warning:"#FFEA00",search:"#FFEA00",success:"#00E676",info:"#40C4FF",text:"#FFFFFF",muted:"#C0C0C0",background:"#000000",panel:"#000000",element:"#0D0D0D",highlight:"#262626",inverse:"#000000",border:"#808080",borderActive:"#FFFFFF"},"voltage-light":{name:"voltage-light",primary:"#0057B7",accent:"#C2185B",error:"#D50000",warning:"#FF6D00",search:"#FF6D00",success:"#2E7D32",info:"#00838F",text:"#000000",muted:"#424242",background:"#FFFFFF",panel:"#FFFFFF",element:"#EDEDED",highlight:"#D6D6D6",inverse:"#FFFFFF",border:"#616161",borderActive:"#000000"},ironclad:{name:"ironclad",primary:"#4FC3F7",accent:"#FFD54F",error:"#FF5252",warning:"#FFB300",search:"#FFB300",success:"#69F0AE",info:"#64B5F6",text:"#FFFFFF",muted:"#BDBDBD",background:"#000000",panel:"#000000",element:"#101010",highlight:"#242424",inverse:"#000000",border:"#757575",borderActive:"#4FC3F7"},"ironclad-light":{name:"ironclad-light",primary:"#01579B",accent:"#E65100",error:"#B71C1C",warning:"#EF6C00",search:"#EF6C00",success:"#1B5E20",info:"#0277BD",text:"#000000",muted:"#4A4A4A",background:"#FFFFFF",panel:"#FFFFFF",element:"#EFEFEF",highlight:"#DADADA",inverse:"#FFFFFF",border:"#6E6E6E",borderActive:"#01579B"},signal:{name:"signal",primary:"#29B6F6",accent:"#AB47BC",error:"#FF0000",warning:"#FFC400",search:"#FFC400",success:"#00E400",info:"#00B8D4",text:"#FFFFFF",muted:"#B3B3B3",background:"#000000",panel:"#000000",element:"#0A0A0A",highlight:"#202020",inverse:"#000000",border:"#8A8A8A",borderActive:"#29B6F6"},"signal-light":{name:"signal-light",primary:"#01579B",accent:"#6A1B9A",error:"#C62828",warning:"#F9A825",search:"#F9A825",success:"#2E7D32",info:"#00796B",text:"#000000",muted:"#3D3D3D",background:"#FFFFFF",panel:"#FFFFFF",element:"#ECECEC",highlight:"#D2D2D2",inverse:"#FFFFFF",border:"#5C5C5C",borderActive:"#01579B"},system:{name:"system",primary:"#60A5FA",accent:"#C084FC",error:"#F87171",warning:"#FBBF24",search:"#FBBF24",success:"#34D399",info:"#22D3EE",text:"#F9FAFB",muted:"#C4CAD3",background:"#030712",panel:"#111827",element:"#1F2937",highlight:"#374151",inverse:"#030712",border:"#4B5563",borderActive:"#60A5FA"},devctl:{name:"devctl",primary:"#77DDBA",accent:"#9EE9CF",error:"#F28B91",warning:"#E8C586",search:"#E8C586",success:"#91D6A0",info:"#8EC8D8",text:"#DEEEE5",muted:"#A4B9AE",background:"#15201D",panel:"#202923",element:"#293B32",highlight:"#365448",inverse:"#15201D",border:"#526D60",borderActive:"#77DDBA"},ember:{name:"ember",primary:"#FF9F43",accent:"#2EE6FF",error:"#FF4D6D",warning:"#FFE566",search:"#FFE566",success:"#3DFF9A",info:"#2EE6FF",text:"#F7F9FF",muted:"#B0B8CC",background:"#07090F",panel:"#12161F",element:"#1A2130",highlight:"#243044",inverse:"#0B0D12",border:"#334155",borderActive:"#FF9F43"}},yM={opencode:"ember",light:"system",mocha:"catppuccin",latte:"catppuccin-latte","one-dark":"onedark","one dark":"onedark",solarized:"solarized-dark",rosepine:"rose-pine","rose pine":"rose-pine",github:"github-dark",ayu:"ayu-dark","night owl":"night-owl",ansi:"terminal",xterm:"terminal",console:"terminal",classic:"terminal",vga:"terminal",contrast:"voltage","contrast-light":"voltage-light",hc:"voltage","hc-light":"voltage-light",a11y:"voltage","a11y-light":"voltage-light"};wM=["#7AA2F7","#9ECE6A","#E0AF68","#BB9AF7","#2AC3DE","#FF9E64","#F7768E","#73DACA","#C0CAF5","#FF79C6","#7DCFFF","#C3E88D"],xM=["#2E5AAC","#3D7A1F","#9A6B12","#6B3FA0","#0E7A86","#B85C1A","#B4234A","#1A7A6D","#4A5080","#9A3480","#1565C0","#4A7C19"];IM={claude:{dark:"#E08A6A",light:"#B54328"},cursor:{dark:"#B8D4FF",light:"#1E4EBF"},kilo:{dark:"#F0C94A",light:"#8A6400"},codex:{dark:"#4ADE80",light:"#0B7A4B"}}});var Vr=A(()=>{el()});function x0(e){return e!==void 0}function b0(e){let t=e/1000;if(Number.isInteger(t))return`${t}s`;return`${e}ms`}function Sm(e,t,r){let n=e.indexOf(t),i=((n<0?0:n)+r+e.length)%e.length;return e[i]??e[0]}function k0(e,t){let r=[...Pt],n=r.includes(e)?e:km;return Sm(r,n,t)}function S0(e,t){let r=[...NM],n=r.reduce((o,i)=>Math.abs(i-e)<Math.abs(o-e)?i:o,r[0]);return Sm(r,n,t)}function wa(e){let t=[...xm];return t.reduce((r,n)=>Math.abs(n-e)<Math.abs(r-e)?n:r,t[0])}function xa(e,t){return Sm([...xm],wa(e),t)}function ka(e){let t=wa(e),r=w0[t]??w0[gi];return{px:t,...r}}function Ln(e){return e.label==="compact"}function Sa(e){return e.steps<=2}function C0(e){return xm.map((r,n)=>n<e?"\u2588":"\u2591").join(" ")}function Xc(e){return ka(e).label}function T0(e){let t=e.locked?"Applies this session only. DEVCTL_TUI_CONFIG overrides the user file.":`Saved to ${e.configPath}.`;return[{id:"theme",group:"Appearance",kind:"cycle",name:"Theme",value:e.themeName,hint:"\u2190 \u2192 save enter picker",detail:`Arrows write the theme to the user file. Enter opens the picker. ${t}`},{id:"font",group:"Appearance",kind:"cycle",name:"Display size",value:Xc(e.fontSize),hint:"\u2190 \u2192 save",detail:`Scales content padding and list-row height. Default keeps a thin rule between chrome and panes. Compact sits toolbars flush against borders. Header, nav, and status stay one line. Does not change the terminal font. ${t}`},{id:"mouse",group:"Input",kind:"toggle",name:"Mouse",value:e.mouse?"on":"off",hint:"space or enter toggle",detail:`Clicks on nav and lists. Restart the TUI after a change. ${t}`},{id:"leader",group:"Input",kind:"cycle",name:"Leader",value:b0(e.leaderMs),hint:"\u2190 \u2192 save",detail:`How long ${jt("x")} waits for the next key. ${t}`},{id:"mcp",group:"MCP",kind:"page",name:"Settings page",value:e.mcpRunning?"running \u2192 /mcp":"off \u2192 /mcp",hint:"enter open the MCP page",detail:"Opens a dedicated MCP page (also /mcp or /agent). Start or stop the localhost server, change the port, and copy Claude, Cursor, Codex, and Kilo Code config."},{id:"file",group:"About",kind:"info",name:"File",value:e.configPath,hint:"read-only",detail:e.locked?`Using ${e.configPath} from DEVCTL_TUI_CONFIG.`:`User preferences live in ${e.configPath}.`},{id:"version",group:"About",kind:"info",name:"Version",value:Xt,hint:"read-only",detail:vr()},{id:"reset",group:"About",kind:"action",name:"Reset",value:"defaults",hint:"enter confirm reset",detail:`Restore theme ${km}, display ${Xc(gi)}, mouse on, leader ${b0(Id)}. Enter asks first. ${t}`}]}function Qc(){return{theme:km,mouse:!0,leader_timeout:Id,font_size:gi}}function E0(e){return["Appearance","Input","MCP","About"].flatMap((r)=>{let n=e.filter((o)=>o.group===r);if(n.length===0)return[];return[{group:r,items:n}]})}function Cm(e,t){if(e.length===0)return 0;return Math.min(Math.max(t,0),e.length-1)}function oo(e,t){return e[Cm(e,t)]}function Tm(e,t){return e??t}var NM,xm,km="devctl",w0;var Mr=A(()=>{rt();Vr();NM=[1000,2000,3000],xm=[12,14,16,18,20,22];w0={12:{pad:0,rowH:1,gap:0,steps:1,label:"compact"},14:{pad:0,rowH:1,gap:0,steps:2,label:"default"},16:{pad:1,rowH:1,gap:1,steps:3,label:"comfortable"},18:{pad:1,rowH:2,gap:1,steps:4,label:"large"},20:{pad:2,rowH:2,gap:1,steps:5,label:"xl"},22:{pad:2,rowH:2,gap:2,steps:6,label:"xxl"}}});import{createContext as FM,useContext as $M}from"react";function ye(){return $M(Em)}var Em;var Ht=A(()=>{Mr();Vr();Em=FM(ka(gi))});function ke(e,t){if(t<=0)return"";if(e.length<=t)return e;if(t===1)return"\u2026";return`${e.slice(0,t-1)}\u2026`}function j(e,t){if(t<=0)return"";if(t===1)return ke(e,1);return ke(e,t-1).padEnd(t)}function Qi(e,t=20){let r=Number.isFinite(e)?Math.min(1,Math.max(0,e)):0,n=Math.round(r*t);return"\u2588".repeat(n)+"\u2591".repeat(Math.max(0,t-n))}function Ca(e){if(!Number.isFinite(e)||e<Rm)return"< 1s";let t=Math.floor(e/R0),r=Math.floor(e%R0/Pm),n=Math.floor(e%Pm/_m),o=Math.floor(e%_m/Rm);if(t>0)return`${t}d ${r}h`;if(r>0)return`${r}h ${n}m`;if(n>0)return`${n}m ${String(o).padStart(2,"0")}s`;return`${o}s`}function Ta(e){if(!Number.isFinite(e)||e<0)return"\u2014";let t=e/HM;if(t>=_0)return`${(t/_0).toFixed(1)}G`;if(t>=1)return`${Math.round(t)}M`;return`${Math.round(e)}K`}function P0(e){if(!Number.isFinite(e)||e<0)return"\u2014";return`${e.toFixed(1)}%`}var Rm=1000,_m,Pm,R0,HM=1024,_0=1024;var nt=A(()=>{_m=60*Rm,Pm=60*_m,R0=24*Pm});function Lm(e){return e>=BM}function Im(e){return e>=WM}function Dm(e){return e>=zM}function ru(e,t=0){return Math.max(1,e-L0-t*2)}function I0(e){let t=A0+Yr+Bt;if(Lm(e))t+=dn;if(Im(e))t+=eu;if(Dm(e))t+=In;return Math.max(tu,e-t)}function nu(e,t,r){if(r)return e;let n=t.reduce((a,l)=>Math.max(a,l.length),0),o=Math.min(Am,Math.max(tu,n+UM)),i=A0+Yr+Bt+o+L0+jM,s=Math.max(Zc,Math.floor(e*qM));return Math.min(s,Math.max(Zc,i))}function D0(e){if(!e)return"";return Object.keys(e.profiles).sort()[0]??""}function ou(e){if(!e)return!0;let t=Object.values(e.services);if(t.length===0)return!0;return!t.some((r)=>ri(r))}function Om(e,t){if(e.length>0)return e;return[...t]}function iu(e,t){if(e.length>0)return[...e];return t===""?[]:[t]}function su(e){return e.command.args.join(" ")||"\u2014"}function Pa(e,t){let r=ti(t);if(r!=="")return r;if(e.ports.length===0)return"\u2014";return e.ports.map((n)=>`${n.name}:${n.auto?"auto":n.value}`).join(" ")}function au(e){let t=e.health.type||"none",r=e.health.url||e.health.address;return r===""?t:`${t} ${r}`}function lu(e,t){if(t?.identity)return t.identity;let r=e.identity.type||"none",n=e.identity.service_account;return n===""?r:`${r} ${n}`}function cu(e){let t=e.restart.policy||"none";if(e.restart.max_retries>0)return`${t} \xD7${e.restart.max_retries}`;return t}function O0(e,t,r,n,o){let i={...e.environment.defaults,...e.environment.vars},a=GM(o??i,t,r,n);return[...new Set([...Object.keys(a),...e.environment.required])].map((c)=>({key:c,value:a[c]??"",required:e.environment.required.includes(c),fromConfig:Object.prototype.hasOwnProperty.call(i,c)})).sort((c,u)=>c.fromConfig===u.fromConfig?c.key.localeCompare(u.key):c.fromConfig?-1:1)}function M0(e,t){if(!e||e.processes.length===0)return;if(t!==void 0&&t!==""&&e.session_id===t)return;return e}function ti(e){if(!e)return"";if(e.ports.http!==void 0)return String(e.ports.http);let t=Object.values(e.ports)[0];return t!==void 0?String(t):""}function yr(e){if(!e)return"STOPPED";return Ui(e)}function GM(e,t,r,n){if(t)return e;return new Rr(r,n).redactMap(e)}function Aa(e){return KM.has(e)}function ri(e){if(!e)return!1;return Aa(e.state)}var A0=8,Yr=12,dn=10,eu=8,In=8,Ea=9,Ra=7,_a=8,tu=12,Am=40,Bt=2,UM=2,L0=2,jM=2,Zc=34,BM=48,WM=60,zM=72,qM=0.48,KM;var Ut=A(()=>{$t();To();KM=new Set(["RUNNING","STARTING","RESTARTING","HEALTHY","UNHEALTHY"])});function Zi(e){return uv(e===""?So:e)}function Fm(e,t,r){let n=r?F0:YM+F0+Math.max(0,t)*2;return Math.max(1,e-n)}function ZM(e){if(e.startsWith('"')||e.startsWith("'"))return"string";if(/^\d+$/.test(e))return"number";return"keyword"}function du(e){return e.replace(eN,"")}function H0(e){try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e}}function U0(e){return bv(e.body,e.attributes)}function j0(e,t){let r=Math.max(1,t),n=du(e).replace(/\r\n/g,`
|
|
2474
2480
|
`).replace(/\r/g,`
|
|
2475
2481
|
`).split(`
|
|
2476
|
-
`),o=[];for(let i of n)if(i.length<=r)o.push(i);else o.push(...GM(i,r));return o.length>0?o:[""]}function U0(e,t){return e==="all"||e==="focus"&&t}function pu(e){if(e==="clip")return"focus";if(e==="focus")return"all";return"clip"}function Fm(e,t,r,n=Jr){if(e.length===0)return{start:0,items:[],newer:0};if(!t){let a=Math.max(0,e.length-n);return{start:a,items:e.slice(a),newer:0}}let o=e.length-1,i=Math.max(0,Math.min(r,o)),s=e.slice(i,i+n);return{start:i,items:s,newer:Math.max(0,e.length-i-s.length)}}function fu(e,t=Jr){return Math.max(0,e-t)}function $m(e,t,r,n){let o=Math.max(t-1,0);if(e<0&&r>0)return{selected:0,startDelta:Math.max(-r,e)};if(e>o&&n>0)return{selected:o,startDelta:Math.min(n,e-o)};return{selected:Math.min(o,Math.max(0,e)),startDelta:0}}function mu(e){if(e==="all")return"wrap all";if(e==="focus")return"wrap selected";return"clip"}function GM(e,t){let r=[],n=e;while(n.length>t){let o=n.slice(0,t),i=KM(o);if(i>0)r.push(n.slice(0,i).trimEnd()),n=n.slice(i).trimStart();else r.push(n.slice(0,t)),n=n.slice(t)}if(n.length>0)r.push(n);return r}function KM(e){let t=e.lastIndexOf(" "),r=e.lastIndexOf("\t"),n=e.lastIndexOf(","),o=Math.max(t,r,n);if(o<Math.floor(e.length*BM))return-1;return e[o]===","?o+1:o}function VM(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function YM(e,t=!1){let r=e.trim();if(r==="")return;if(t){let n=Os(r);if(n)return new RegExp(n.source,n.flags.includes("g")?n.flags:`${n.flags}g`)}return new RegExp(VM(r),"gi")}function JM(e,t){let r=e.map((a)=>a.text).join(""),n=[];t.lastIndex=0;let o=t.exec(r);while(o){let a=o[0]??"";if(a.length>0)n.push({start:o.index,end:o.index+a.length});if(a.length===0)t.lastIndex+=1;o=t.exec(r)}if(n.length===0)return e;let i=[],s=0;for(let a of e){let l=s,c=s+a.text.length,u=0;for(let d of n){let f=Math.max(d.start,l),p=Math.min(d.end,c);if(p<=f)continue;let m=f-l,h=p-l;if(m>u)i.push({text:a.text.slice(u,m),kind:a.kind});i.push({text:a.text.slice(m,h),kind:"search"}),u=h}if(u<a.text.length)i.push({text:a.text.slice(u),kind:a.kind});s=c}return i.filter((a)=>a.text!=="")}function j0(e,t="",r=!1){let n=du(e),o=[],i=new RegExp(WM.source,"gi"),s=0,a=i.exec(n);while(a){let u=a[0]??"";if(a.index>s)o.push({text:n.slice(s,a.index),kind:"text"});o.push({text:u,kind:zM(u)}),s=a.index+u.length,a=i.exec(n)}if(s<n.length)o.push({text:n.slice(s),kind:"text"});let l=o.length===0?[{text:n,kind:"text"}]:o,c=YM(t,r);return c?JM(l,c):l}function B0(e,t){let r=t.reduce((s,a)=>Math.max(s,a.length),0),n=Om+Mm+HM+uu*jM,o=Math.max(O0,e-n),i=Math.max(O0,r);return Math.min(Pm,o,i)}function es(e){return XM.has(e)}function z0(e,t,r,n){let o=r===""?t:t.filter((a)=>a.timestamp>=r);if(o.length===0)return e;let i=Math.max(1,n);if(o.length>=i)return o.slice(-i);let s=Math.max(0,e.length+o.length-i);return e.slice(s).concat(o)}function q0(e,t){let r=t.length>0?t[t.length-1].seq:-1,n=e.filter((o)=>o.seq>r);return[...t,...n]}function G0(e,t){if(t.length===0)return e;let r=new Set(e.map((o)=>o.seq)),n=t.filter((o)=>!r.has(o.seq));return n.length===0?e:[...n,...e]}function Hm(e,t,r){return e&&t<=0&&r}function K0(e){return e.filter((t)=>Si(t.severityNumber)).length}function ni(e,t){let r=t.services?.filter((c)=>c!=="")??[],n=t.service??"",o=(t.search??"").trim(),i=t.source??"",s=t.since??"",a=t.until??"",l;if(o!=="")if(t.regex===!0){let c=Os(o);if(c)l=(u)=>c.test(u);else l=(u)=>u.toLowerCase().includes(o.toLowerCase())}else{let c=o.toLowerCase();l=(u)=>u.toLowerCase().includes(c)}return e.filter((c)=>{if(r.length>0&&!r.includes(c.service))return!1;if(n!==""&&c.service!==n)return!1;if(i!==""&&c.source!==i)return!1;if(t.systemLogs===!1&&es(c.source))return!1;if(s!==""&&c.timestamp<s)return!1;if(a!==""&&c.timestamp>a)return!1;if(t.traceId&&c.traceId!==t.traceId)return!1;if(t.errorOnly===!0&&!Si(c.severityNumber))return!1;if(!l)return!0;return l(As(c))||l(c.service)})}function QM(e,t){let r={};for(let i of e)r[i.service]=(r[i.service]??0)+1;let n=t.map((i)=>({name:i,count:r[i]??0})),o=Object.keys(r).filter((i)=>!t.includes(i)).sort().map((i)=>({name:i,count:r[i]??0}));return[...n,...o]}function V0(e,t,r=[]){let n=hu(e,t,r);return[{name:"",count:t.length},...QM(t,n)]}function ZM(e,t){let r=e.map((o)=>({name:o,count:t[o]??0})),n=Object.keys(t).filter((o)=>!e.includes(o)).sort().map((o)=>({name:o,count:t[o]??0}));return[...r,...n]}function Y0(e,t,r=[]){let n=Object.keys(t.byService).map((i)=>({service:i})),o=hu(e,n,r);return[{name:"",count:t.total},...ZM(o,t.byService)]}function J0(e,t){if(e<=0)return"none started";return`${e}/${t} running`}function hu(e,t,r=[]){let n=[...e],o=(i)=>{if(i!==""&&!n.includes(i))n.push(i)};for(let i of r)o(i);for(let i of t)o(i.service);return n}function Um(e,t,r){let n=["",...e],o=n.indexOf(t),s=((o<0?0:o)+r+n.length)%n.length;return n[s]??""}var N0=8,Om=9,Mm=8,O0=10,HM=16,uu=1,Jr=200,UM=2,M0=1,jM=2,BM=0.4,WM,qM,XM,W0;var br=A(()=>{sn();nt();Ut();WM=/("[^"]*"|'[^']*'|\b(?:ERROR|FATAL|WARN(?:ING)?|FAIL(?:ED)?)\b|\b\d{3,5}\b)/gi;qM=/\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-Z\\-_]/g;XM=new Set(["auth","devctl","proxy"]),W0=["devctl","mcp","auth"]});function ts(e){return e.length+tN}function X0(e,t){if(t<nN)return ke(e,3);if(t<rN)return ke(e,4);return e}function Q0(e,t,r){let n=e.length;if(n===0||r<=0)return{start:0,end:-1};let o=t>=0&&t<n?t:0,i=jm(e,o,r);if(i.start===0&&i.end===n-1)return i;let s=o>0?gu:0,a=o<n-1?gu:0,l=s+a,c=jm(e,o,Math.max(e[o]??0,r-l)),u=(s>0&&c.start===0?gu:0)+(a>0&&c.end===n-1?gu:0);if(u===0)return c;return jm(e,o,Math.max(e[o]??0,r-l+u))}function jm(e,t,r){let n=e.length,o=t,i=t,s=e[t]??0;if(s>=r)return{start:t,end:t};while(o>0||i<n-1){let a=o>0?e[o-1]??0:Number.POSITIVE_INFINITY,l=i<n-1?e[i+1]??0:Number.POSITIVE_INFINITY,c=o>0&&s+a<=r,u=i<n-1&&s+l<=r;if(!c&&!u)break;let d=t-(o-1),f=i+1-t;if(c&&(!u||d<=f))o-=1,s+=a;else if(u)i+=1,s+=l;else break}return{start:o,end:i}}function Z0(e){if(e==="detail")return oi.findIndex((t)=>t.id==="services");return oi.findIndex((t)=>t.id===e)}function ek(e,t){if(e==="doctor")return t.doctor;if(e==="settings")return t.settings;if(e==="profiles")return t.profiles;if(e==="dashboard"||e==="services")return t.services;if(e==="logs")return t.logs??0;if(e==="mcp")return t.mcp??0;if(e==="setup")return eN;if(e==="config")return t.config??0;return 0}function tk(e){if(e.length===1&&e>="1"&&e<="9")return oi[Number(e)-1]?.id;return}var eN=9,tN=2,gu=2,rN=80,nN=56,oi,io;var so=A(()=>{nt();oi=[{id:"dashboard",label:"dashboard"},{id:"services",label:"services"},{id:"logs",label:"logs"},{id:"proxy",label:"proxy"}];io=oi.map((e)=>e.id)});function ok(e,t=!0){let r=e<vu?rk+1:rk,n=t?cN:0;return r+n+aN+n+lN+n}function ao(e){return Math.max(iN,e-sN*2)}function ik(e){let t=e.width<oN,r=e.proxyOn?`\u25CF ${ke(e.proxyAddress,t?10:18)}`:"";return[{label:t?`${e.running}/${e.total}`:J0(e.running,e.total),tone:e.running>0?"success":"idle"},{label:r,tone:"info",hide:!e.proxyOn},{label:"MCP",tone:"info",hide:!e.mcpOn},{label:e.adc?t?"ADC":"ADC ok":t?"!ADC":"ADC missing",tone:e.adc?"success":"error"},{label:t?"sec":"secrets shown",tone:"warning",hide:!e.reveal}]}function nk(e){return e.key==="/"&&e.label==="command"}function uN(e){return e.key.length+e.label.length+3}function sk(e,t){let r=e.filter(nk),n=e.filter((s)=>!nk(s)),o=[],i=0;for(let s of[...r,...n]){let a=uN(s);if(i+a>t)break;o.push(s),i+=a}return o}function ns(e,t,r,n,o="center",i=!0){let s=Math.min(r,Math.max(1,e-4)),a=Math.min(ok(e,i),Math.max(0,t-1)),l=Math.min(n,Math.max(1,t-a)),c=Math.max(0,Math.min(Math.floor((e-s)/2),Math.max(0,e-s))),u=o==="bottom"?t-2-l:Math.floor((t-l)/2),d=Math.max(0,Math.min(u,t-l));return{left:c,top:d,width:s,height:l}}function ak(e){if(e==="")return"idle";if(pN.test(e))return"error";if(e.includes("session only"))return"warning";if(dN.test(e))return"success";return"info"}function lk(e,t,r){if(e==="restart-cascade")return{title:"Restart dependents?",body:`${r?.services?.join(", ")||"selected services"} has dependents. Enter restarts only the named services. Press c to cascade (same as /restart --cascade).`};if(e==="quit")return{title:"Quit",body:"Stop managed services and leave the TUI? Press d to detach (daemon stays). Press k to stop the daemon and leave services running (devctl down --keep-services)."};if(e==="reload")return{title:"Reload applied",body:t===""?"Configuration changed. Restart marked services?":`Restart required: ${t}`};if(e==="reset-prefs")return{title:"Reset preferences",body:"Restore theme, display size, mouse, and leader timeout to defaults? This overwrites your saved tui.json values."};if(e==="free-port"){let n=r?.port??0,o=r?.process||"process",i=r?.pid??0;return{title:`Free port ${n}`,body:`Stop ${o} (pid ${i}) so port ${n} can be used? This sends SIGTERM, then SIGKILL if it stays up.`}}return{title:"Start profile",body:t===""?"Start the configured services?":`Start profile ${t}?`}}function ck(e){if(e==="quit")return[{key:"enter",label:"stop services"},{key:"d",label:"detach"},{key:"k",label:"down, keep services"},{key:"esc",label:"stay"}];if(e==="restart-cascade")return[{key:"enter",label:"named only"},{key:"c",label:"cascade"},{key:"esc",label:"stay"}];return[{key:"enter",label:"confirm"},{key:"esc",label:"stay"}]}function uk(e){let t=e.payload?.error;return typeof t==="string"&&t!==""?t:"configuration reload failed"}var rs=100,vu=90,oN=60,iN=8,sN=6,rk=1,aN=1,lN=1,cN=1,v5,dN,pN;var wr=A(()=>{nt();br();so();v5=ok(vu-1);dN=/^(started|stopped|restarted|refreshed|cleared|copied|exported|jumped|proxy started|proxy stopped|secrets|re-running|theme |mouse |leader |display |restored)/i,pN=/\b(fail|error|unknown|not found|no configuration|blocked|already in use|is using port)\b/i});function yu(){return[{name:"start",aliases:["up"],desc:"Start selected services or the current profile",leader:"n",group:"services",usage:"<service>"},{name:"stop",aliases:[],desc:"Stop selected services",leader:"x",group:"services",usage:"<service>"},{name:"restart",aliases:[],desc:"Restart selected services",leader:"R",group:"services",usage:"<service>",suggest:[{token:"--cascade",desc:"Restart selected services and their dependents"}]},{name:"run",aliases:["task"],desc:"Run a one-off task; empty /run opens a picker",leader:"",group:"services",usage:"<task>"},{name:"exec",aliases:[],desc:"Run a command in a service context; empty /exec opens a picker",leader:"",group:"services",usage:"<service>"},{name:"services",aliases:["s"],desc:"Open the services screen",leader:"s",group:"nav"},{name:"logs",aliases:["l"],desc:"Open the log viewer",leader:"l",group:"nav"},{name:"auth",aliases:["identity","a"],desc:"Open identity",leader:"a",group:"nav",suggest:[{token:"login",desc:"Run gcloud ADC login"},{token:"logout",desc:"Revoke application-default credentials"},{token:"refresh",desc:"Probe identities"}]},{name:"credentials",aliases:["creds"],desc:"Open credential store status",leader:"",group:"nav"},{name:"reload",aliases:[],desc:"Reload configuration",leader:"",group:"ui"},{name:"proxy",aliases:["p"],desc:"Open the proxy screen",leader:"p",group:"nav"},{name:"mcp",aliases:["agent"],desc:"Open the MCP server screen for coding agents",leader:"",group:"nav"},{name:"doctor",aliases:["d"],desc:"Run environment diagnostics",leader:"d",group:"nav"},{name:"stats",aliases:["metrics"],desc:"View system and service statistics",leader:"m",group:"nav"},{name:"config",aliases:["c"],desc:"View merged configuration",leader:"c",group:"nav"},{name:"import",aliases:[],desc:"Preview or write a Compose mapping",leader:"",group:"ui",suggest:[{token:"compose",desc:"Preview a Compose mapping; add --write to save"}]},{name:"diff",aliases:["provenance"],desc:"Show winning config sources and what they shadowed",leader:"",group:"ui"},{name:"daemon",aliases:["bootstrap"],desc:"Show supervisor bootstrap logs (same file as devctl daemon logs)",leader:"",group:"app"},{name:"update",aliases:[],desc:"Install a newer GitHub Release when the install method is known",leader:"",group:"app"},{name:"profiles",aliases:["o"],desc:"Select a development profile",leader:"o",group:"nav"},{name:"setup",aliases:["init"],desc:"Open setup guidance",leader:"i",group:"nav"},{name:"dashboard",aliases:["home"],desc:"Return to the dashboard",leader:"h",group:"nav"},{name:"themes",aliases:["theme"],desc:"List available themes",leader:"t",group:"ui"},{name:"settings",aliases:["prefs","preferences"],desc:"Open TUI settings (theme, mouse, MCP page)",leader:"",group:"ui"},{name:"help",aliases:["?"],desc:"Show the help dialog",leader:"",group:"ui"},{name:"refresh",aliases:[],desc:"Refresh status and logs",leader:"r",group:"ui"},{name:"regex",aliases:[],desc:"Toggle regex log search",leader:"",group:"logs"},{name:"since",aliases:[],desc:"Filter logs after an ISO timestamp",leader:"",group:"logs",usage:"<timestamp>"},{name:"until",aliases:[],desc:"Filter logs before an ISO timestamp",leader:"",group:"logs",usage:"<timestamp>"},{name:"history",aliases:[],desc:"Load a persisted log session",leader:"",group:"logs",usage:"<session>"},{name:"edit",aliases:[],desc:"Open configuration in $EDITOR",leader:"",group:"ui"},{name:"buffer",aliases:[],desc:"Edit configuration in a validate/save buffer",leader:"",group:"ui"},{name:"pause",aliases:[],desc:"Pause or resume live logs",leader:"",group:"logs"},{name:"fullscreen",aliases:["zen","expand"],desc:"Expand logs to fill the terminal",leader:"z",group:"logs"},{name:"split",aliases:[],desc:"Split the logs screen into two service panes",leader:"",group:"logs"},{name:"trace",aliases:[],desc:"Search logs for a request or trace id",leader:"",group:"logs",usage:"<id>"},{name:"filter",aliases:[],desc:"Toggle ERROR+ log filter",leader:"",group:"logs"},{name:"system",aliases:["internal"],desc:"Show or hide internal auth/mcp/devctl/proxy logs",leader:"",group:"logs"},{name:"reveal",aliases:[],desc:"Reveal or hide secret environment values",leader:"",group:"ui"},{name:"wrap",aliases:[],desc:"Cycle log wrap: all lines, clip, or selected row",leader:"",group:"logs"},{name:"copy",aliases:[],desc:"Copy the highlighted selection to the clipboard",leader:"",group:"ui"},{name:"export",aliases:[],desc:"Write filtered logs to ~/.devctl/exports",leader:"e",group:"logs"},{name:"exports",aliases:["open-exports"],desc:"Open the log export folder",leader:"",group:"logs"},{name:"clear",aliases:["new"],desc:"Clear the on-screen log buffer",leader:"",group:"logs"},{name:"version",aliases:["v"],desc:"Show the current devctl version",leader:"",group:"app"},{name:"down",aliases:[],desc:"Stop the supervisor",leader:"",group:"app",suggest:[{token:"--keep-services",desc:"Stop the supervisor and leave processes running"}]},{name:"exit",aliases:["quit","q"],desc:"Exit (detach or stop services)",leader:"q",group:"app"}]}function ii(e){let t=e.trim().toLowerCase().replace(/^\//,""),r=t.indexOf(" ");return r===-1?t:t.slice(0,r)}function hk(e){let t=ii(e);if(t==="")return yu();return yu().map((r)=>({command:r,score:RN(r,t)})).filter((r)=>r.score>0).sort((r,n)=>n.score-r.score||r.command.name.localeCompare(n.command.name)).map((r)=>r.command)}function RN(e,t){if(t==="")return 1;let r=e.name.toLowerCase(),n=e.aliases.map((o)=>o.toLowerCase());return PN(r,n,t)||AN(r,n,t)||LN(r,n,t)||IN(r,n,t)||_N(e.suggest,t)||DN(e.desc.toLowerCase(),t)}function _N(e,t){if(!e||e.length===0)return 0;let r=e.map((n)=>n.token.toLowerCase());if(r.some((n)=>n===t||n.replace(/^-+/,"")===t))return pk;if(t.length<mk)return 0;return r.some((n)=>n.includes(t)||n.replace(/^-+/,"").startsWith(t))?fk:0}function PN(e,t,r){if(e===r)return fN;return t.includes(r)?mN:0}function AN(e,t,r){if(e.startsWith(r))return hN;if(t.some((i)=>i.startsWith(r)))return gN;let n=e.split("-");return n.length>1&&n.some((i)=>i.startsWith(r))?vN:0}function LN(e,t,r){if(r.length<mk)return 0;if(e.includes(r))return pk;return t.some((n)=>n.includes(r))?fk:0}function IN(e,t,r){if(r.length<kN)return 0;let n=dk(e,r);if(n>0)return yN+Math.min(n,EN);return t.some((o)=>dk(o,r)>0)?bN:0}function dk(e,t){let r=0,n=0,o=0;for(let i=0;i<t.length;i+=1){let s=t[i];if(s===void 0)return 0;let a=e.indexOf(s,r);if(a<0)return 0;if(r>0&&a===r)n+=1,o+=2+n;else n=0,o+=a===0?4:1;r=a+1}return o}function DN(e,t){if(t.length<SN)return 0;if(e.split(/[^a-z0-9+]+/).filter((n)=>n.length>=CN).some((n)=>n.startsWith(t)))return wN;return t.length>=TN&&e.includes(t)?xN:0}function pn(e){let t=e.trim().toLowerCase().replace(/^\//,"").split(" ")[0]??"";return yu().find((r)=>r.name===t||r.aliases.includes(t))}function Bm(e){return e.trim().replace(/^\//,"").split(/\s+/).slice(1).filter((r)=>r!=="")}function gk(e){return yu().find((r)=>r.leader===e)?.name??""}function vk(e){let t=e.includes("--cascade")||e.includes("-c");return{services:e.filter((n)=>n!=="--cascade"&&n!=="-c"),cascade:t}}function yk(e){let t=e.includes("--print-env"),r=e.includes("--reveal"),n=e.filter((o)=>o!=="--print-env"&&o!=="--reveal"&&o!=="--");return{service:n[0]??"",printEnv:t,reveal:r,command:n.slice(1)}}var fN=100,mN=90,hN=80,gN=70,vN=60,pk=50,fk=45,yN=30,bN=28,wN=20,xN=10,mk=2,kN=3,SN=4,CN=4,TN=4,EN=9;function kk(e){return e==="detail"?"services":e}function Sk(e){let t=io.indexOf(kk(e));if(t<0)return"dashboard";return io[(t+1)%io.length]??"dashboard"}function Ck(e){let t=io.indexOf(kk(e));if(t<0)return"dashboard";return io[(t-1+io.length)%io.length]??"dashboard"}function zm(e){return["services","nav","logs","ui","app","tasks"].flatMap((r)=>{let n=e.filter((o)=>o.group===r);if(n.length===0)return[];return[{group:r,items:n}]})}function bu(e){return e.hint?`${e.name} ${e.hint}`:e.name}function qm(e){return e.name}function Tk(e){if(e.hint)return`${e.hint} \xB7 ${e.desc}`;let t=[e.usage,...(e.suggest??[]).map((r)=>r.token)].filter((r)=>Boolean(r));if(t.length===0)return e.desc;return`${e.desc} \xB7 ${t.join(" \xB7 ")}`}function Ek(e){let t=e.reduce((n,o)=>Math.max(n,qm(o).length),0),r=Math.min(Wm,Math.max(t,1));return ON+r+MN}function Rk(e){return e.hint?`${e.name} ${e.hint} `:`${e.name} `}function _k(e,t){if(e.hint)return e.hint.split(/\s+/);return pn(t)?.name===e.name?Bm(t):[]}function bk(e,t){if(t==="")return!0;let r=t.toLowerCase(),n=e.toLowerCase();return n.startsWith(r)||n.includes(r)}function NN(e,t){if(e.name==="start"||e.name==="stop"||e.name==="restart")return(t.services??[]).map((r)=>({token:r,desc:`${e.name} ${r}`}));if(e.name==="run")return(t.tasks??[]).map((r)=>({token:r,desc:`run ${r}`}));if(e.name==="exec")return(t.services??[]).map((r)=>({token:r,desc:`exec in ${r}`}));return[]}function wk(e,t){return{...e,hint:t.token,desc:t.desc,usage:void 0,suggest:void 0}}function FN(e,t,r={}){let n=Bm(t).join(" "),o=t.trim().includes(" ")||t.endsWith(" "),i=ii(t),s=[];for(let a of e){if(s.push({...a,hint:void 0}),i==="")continue;let l=a.name===i||a.aliases.includes(i),c=l?n:i;for(let u of a.suggest??[])if(bk(u.token,c))s.push(wk(a,u));if(!l||!o)continue;for(let u of NN(a,r))if(bk(u.token,n))s.push(wk(a,u))}return s}function Pk(e,t={}){let r=hk(e),n=ii(e)===""?zm(r).flatMap((o)=>o.items):r;return FN(n,e,t)}function Gm(e,t,r,n){let o=ii(t),i=[...e].sort().map((s)=>({name:s,aliases:[],desc:n,leader:"",group:r}));if(o==="")return i;return i.filter((s)=>s.name.toLowerCase().includes(o))}function Ak(e,t,r=kn()){if(t==="slash")return[{key:"\u2191\u2193",label:"suggest"},{key:"tab",label:"complete"},{key:"enter",label:"run"},{key:"esc",label:"cancel"}];if(t==="themes")return[Nr,{key:"\u2191\u2193",label:"move"},{key:"enter",label:"save"},{key:"esc",label:"revert"}];if(t==="help")return[Nr,{key:"j/k",label:"scroll"},{key:"esc",label:"close"}];if(t==="trace")return[Nr,{key:"j/k",label:"span"},{key:"enter",label:"logs"},{key:wo(r),label:"copy"},{key:"esc",label:"close"}];if(t==="span-details")return[Nr,{key:"j/k",label:"scroll"},{key:"esc",label:"back"},{key:wo(r),label:"copy"}];if(t==="log-details"||t==="scroll-text")return[Nr,{key:"j/k",label:"scroll"},{key:wo(r),label:"copy"},{key:"esc",label:"close"}];if(t==="confirm")return[{key:"enter",label:"confirm"},{key:"esc",label:"stay"}];if(t==="plan")return[Nr,{key:"esc",label:"back to dashboard"},{key:"enter",label:"done"}];if(t==="leader")return[Nr,...Km()];if(t==="config-edit")return[{key:jt("s"),label:"save"},{key:"esc",label:"discard"}];return $N(e,r)}function Km(){return[{key:"n",label:"start"},{key:"x",label:"stop"},{key:"R",label:"restart"},{key:"s",label:"services"},{key:"l",label:"logs"},{key:"t",label:"themes"},{key:"q",label:"quit"}]}function $N(e,t){let r=[{key:wo(t),label:"copy"},Nr,{key:"?",label:"help"}];switch(e){case"dashboard":return[{key:"space",label:"select"},{key:"*",label:"all"},{key:"-",label:"none"},{key:"enter",label:"start or open"},{key:"n",label:"start"},{key:"x",label:"stop"},{key:"r",label:"refresh"},{key:"R",label:"restart"},{key:"\u2190\u2192",label:"log filter"},{key:"g",label:"latest"},{key:"z",label:"full logs"},{key:"i",label:"internal logs"},{key:jt("l"),label:"clear logs"},{key:"j/k",label:"move"},...r];case"services":return[{key:"enter",label:"detail"},{key:"space",label:"select"},{key:"*",label:"all"},{key:"-",label:"none"},{key:"n",label:"start"},{key:"x",label:"stop"},{key:"r",label:"refresh"},{key:"R",label:"restart"},...r];case"detail":return[{key:"j/k",label:"scroll env"},{key:"n",label:"start"},{key:"x",label:"stop"},{key:"o",label:"config"},{key:"l",label:"logs"},{key:"esc",label:"back"},...r];case"logs":return[{key:"\u2190\u2192",label:"filter"},{key:"e",label:"errors"},{key:"i",label:"internal logs"},{key:jt("l"),label:"clear logs"},{key:"g",label:"latest"},{key:"f",label:"search"},{key:"t",label:"time"},{key:"m",label:"meta"},{key:"w",label:"wrap"},{key:"j/k",label:"move"},{key:"p",label:"pause"},{key:"z",label:"full screen"},{key:"\\",label:"split"},{key:"/exports",label:"open folder"},...r];case"profiles":return[{key:"space",label:"set current"},{key:"enter",label:"set and start"},{key:"j/k",label:"move"},...r];case"proxy":return[{key:"n",label:"start proxy"},{key:"x",label:"stop proxy"},...r];case"mcp":return[{key:"j/k",label:"move"},{key:"space",label:"start or copy"},{key:"\u2190\u2192",label:"change port"},{key:"enter",label:"start or copy"},...r];case"config":return[{key:"enter",label:"run task"},{key:"v",label:"buffer"},{key:"e",label:"editor"},{key:"/diff",label:"sources"},{key:"/reload",label:"reload"},{key:"j/k",label:"scroll or select task"},...r];case"setup":return[{key:"j/k",label:"steps"},{key:"enter",label:"continue"},{key:"esc",label:"back"},{key:"esc\xD72",label:"quit"},...r];case"doctor":return[{key:"r",label:"run doctor again"},{key:"j/k",label:"move"},{key:"enter",label:"fix port"},...r];case"auth":return[{key:"r",label:"probe identities"},{key:"/auth login",label:"ADC login"},{key:"/auth logout",label:"revoke ADC"},{key:"/auth refresh",label:"probe"},...r];case"settings":return[{key:"j/k",label:"move"},{key:"\u2190\u2192",label:"save"},{key:"enter",label:"apply or open page"},{key:"space",label:"toggle"},...r];default:return[{key:"tab",label:"screens"},...r]}}function Lk(e,t,r){if(r<=t||e<t)return 0;return Math.min(e-t+1,r-t)}function xk(e,t,r){let n=e.slice(t,r+1),o=new Set(n.map((i)=>i.group));return n.length+o.size}function Ik(e,t,r){if(e.length===0)return[];let n=Math.min(Math.max(t,0),e.length-1),o=n,i=n;for(;;){let s=i+1<e.length&&xk(e,o,i+1)<=r,a=o>0&&xk(e,o-1,i)<=r;if(s)i+=1;else if(a)o-=1;else break}return e.slice(o,i+1)}function os(e,t){if(e.length===0)return;let r=Math.min(Math.max(t,0),e.length-1);return e[r]}var Nr,ON=3,MN=2,Wm=22;var si=A(()=>{Vr();so();Nr={key:"/",label:"command"}});function xu(e,t){let r=t??Object.keys(e?.services??{});return{running:r.filter((o)=>ri(e?.services[o])).length,total:r.length}}function Dk(e,t){let r=0,n=0,o=0,i=0,s=0,a=0;for(let l of e){let c=t?.services[l];if(c?.health==="HEALTHY")o+=1;let u=c?.state??"STOPPED";if(u==="FAILED")i+=1;else if(u==="STOPPING")s+=1;else if(u==="STARTING"||u==="RESTARTING")n+=1;else if(Aa(u))r+=1;else a+=1}return{total:e.length,live:r+n,running:r,starting:n,healthy:o,failed:i,stopping:s,stopped:a}}function Ok(e,t){if(!Number.isFinite(e)||!Number.isFinite(t)||t<=0)return 0;return e/t}function zN(e,t,r){if(!Number.isFinite(e))return"success";if(e>r)return"error";if(e>t)return"warning";return"success"}function qN(e,t){return zN(Ok(e,t),HN,UN)}function Xm(e,t=24){if(e.length===0||t<=0)return"";let r=e.length>t?e.slice(e.length-t):e,n=Math.max(...r,0);if(n<=0)return La[0]?.repeat(r.length)??"";return r.map((o)=>{let i=Number.isFinite(o)?Math.min(1,Math.max(0,o/n)):0,s=Math.min(La.length-1,Math.round(i*(La.length-1)));return La[s]??La[0]}).join("")}function GN(e,t){let r=t>0?e/t:1;if(r<BN)return"error";if(r<jN)return"warning";return"success"}function Vm(e){if(!Number.isFinite(e)||e<0)return"\u2014";return e.toFixed(2)}function KN(e){if(!Number.isFinite(e)||e<0)return"\u2014";return`${Math.round(e*100)}%`}function Mk(e,t=Date.now()){if(!e?.startTime)return"\u2014";let r=new Date(e.startTime).getTime();if(!Number.isFinite(r))return"\u2014";return Ca(t-r)}function Nk(e,t=WN){return Object.entries(e).sort((r,n)=>n[1]-r[1]||r[0].localeCompare(n[0])).slice(0,t)}function Fk(e,t=1){return Math.max(24,e-e2-t*2-t2-r2-n2)}function $k(e){let t=e>=VN,r=e>=YN,n=e>=JN,o=e>=XN,i=e>=QN,s=e>=ZN,a=Yr+Bt;if(t)a+=dn+Bt;if(r)a+=Ra+Bt;if(n)a+=_a+Bt;if(o)a+=Ea+Bt;if(i)a+=ku+Bt;if(s)a+=In;return{name:Math.max(tu,e-a),health:t,cpu:r,mem:n,up:o,rst:i,pid:s}}function Hk(e){let t=Number.isFinite(e)&&e>0?e:0;return{ratio:Math.min(1,t),label:KN(t)}}function Uk(e,t=s2){return`[${Qi(e.ratio,t)}] ${e.label.padStart(4)}`}function Qm(e,t){let r=e.reduce((c,u)=>Math.max(c,u.what.length),4),n=e.reduce((c,u)=>Math.max(c,u.reading.length),7),o=e.some((c)=>c.meter)?a2:0,i=is*(o>0?3:2),s=Math.min(o2,Math.max(Ym,r)),a=Math.min(i2,Math.max(Jm,n)),l=t-s-a-o-i;if(l<wu&&a>Jm)a=Math.max(Jm,a-(wu-l)),l=t-s-a-o-i;if(l<wu&&s>Ym)s=Math.max(Ym,s-(wu-l)),l=t-s-a-o-i;return{what:s,reading:a,meaning:Math.max(0,l),meter:o}}function jk(e){return l2.has((e?.health.type??"").toLowerCase())}function Bk(e){if(e==="darwin")return"macOS";if(e==="win32")return"Windows";if(e==="linux")return"Linux";return e||"this computer"}function Wk(e,t){let r=Math.max(1,t),n=qN(e,r),o=n==="error"?"overloaded":n==="warning"?"busy":"not busy",i=n==="error"?`${r} cores are queued up \u2014 last minute ${Vm(e)}`:n==="warning"?`${r} cores nearly full \u2014 last minute ${Vm(e)}`:`${r} cores. Last minute ${Vm(e)} (under ${r} is fine)`;return{what:"CPU work",reading:o,meaning:i,tone:n,meter:Hk(Ok(e,r))}}function zk(e,t){let r=GN(e,t),n=`${Ta(e)} of ${Ta(t)}`,o=r==="error"?"Almost no RAM left for new work":r==="warning"?"RAM is getting tight":"RAM the computer can still give out",i=t>0?Math.max(0,(t-e)/t):0;return{what:"RAM leftover",reading:n,meaning:o,tone:r,meter:Hk(i)}}function qk(e){let t=e?.state??"STOPPED";if(t==="FAILED")return"crashed";if(t==="STOPPING")return"stopping";if(t==="STARTING"||t==="RESTARTING")return"starting";if(Aa(t))return"up";return"off"}function Gk(e){if(!e||!Aa(e.state))return"\u2014";if(e.health==="HEALTHY")return"ready";if(e.health==="UNHEALTHY")return"failing";if(e.state==="STARTING"||e.state==="RESTARTING")return"waiting";return"checking"}function Kk(e){if(e==="keychain")return"password store";if(e==="file")return"local file";return e||"unknown store"}function Vk(e,t){let r=[{what:"Started",reading:String(e.live),meaning:e.live===0?"nothing is running yet":"process is up",tone:e.live>0?"success":"muted"}];if(t)r.push({what:"Ready",reading:String(e.healthy),meaning:e.live===0?"start services first":"passed their health check",tone:e.live>0&&e.healthy<e.live?"warning":e.healthy>0?"success":"muted"});if(e.starting>0)r.push({what:"Still starting",reading:String(e.starting),meaning:"not ready for traffic yet",tone:"warning"});if(e.stopping>0)r.push({what:"Stopping",reading:String(e.stopping),meaning:"shutting down",tone:"warning"});return r.push({what:"Crashed",reading:String(e.failed),meaning:e.failed>0?"open the service for the error":"none",tone:e.failed>0?"error":"muted"}),r.push({what:"Not started",reading:String(e.stopped),meaning:e.stopped>0?"off until you start them":"all are up",tone:"muted"}),r}var HN=0.85,UN=1.5,jN=0.2,BN=0.1,WN=5,La="\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588",VN=52,YN=64,JN=72,XN=82,QN=90,ZN=100,e2=2,t2=2,r2=2,n2=1,ku=8,Ym=8,o2=22,Jm=6,i2=28,wu=12,is=2,s2=10,a2=18,l2;var Su=A(()=>{nt();Ut();l2=new Set(["http","tcp","command"])});import{useEffect as c2,useRef as u2}from"react";import{jsxDEV as be,Fragment as p2}from"@opentui/react/jsx-dev-runtime";function d2(e,t){switch(t){case"primary":return{bg:e.primary,fg:ei(e.primary,e.inverse)};case"accent":return{bg:e.accent,fg:Yc(e)?Vc:ei(e.accent,e.inverse)};case"success":return{bg:e.success,fg:ei(e.success,e.inverse)};case"warning":return{bg:e.warning,fg:Yc(e)?Vc:ei(e.warning,e.inverse)};case"error":return{bg:e.error,fg:ei(e.error,e.inverse)};case"info":return{bg:e.info,fg:ei(e.info,e.inverse)};case"muted":return{bg:e.element,fg:e.text};case"ghost":return{bg:e.element,fg:e.muted};default:return{bg:e.element,fg:e.text}}}function Yk(e){let{palette:t,dir:r}=e;return be("box",{width:2,height:1,flexShrink:0,overflow:"hidden",children:be("text",{fg:t.muted,children:r==="left"?"\u2039":"\u203A"},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Zt(e){let{palette:t,children:r,backgroundColor:n,edge:o="bottom"}=e,i=ye(),s=e.ruled??!Ln(i),a=n??t.element,l=be("box",{flexShrink:0,flexDirection:"column",backgroundColor:a,overflow:"hidden",children:r},void 0,!1,void 0,this);if(!s)return l;return be("box",{flexShrink:0,flexDirection:"column",overflow:"hidden",border:[...o==="both"?["top","bottom"]:[o]],borderStyle:"single",borderColor:t.border,children:l},void 0,!1,void 0,this)}function Cu(e){let{palette:t,items:r,active:n,width:o,onPick:i,emphasis:s="ghost"}=e,a=r.map((d)=>ts(d.label)),l=Q0(a,n,Math.max(1,o)),c=l.start>0,u=l.end>=0&&l.end<r.length-1;return be("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[c?be(Yk,{palette:t,dir:"left"},void 0,!1,void 0,this):null,r.map((d,f)=>{if(f<l.start||f>l.end)return null;let p=f===n,m=s==="fill"&&p;return be(Ue,{palette:t,label:d.label,tone:m?"primary":"ghost",bg:m?void 0:p?t.highlight:t.element,fg:m?void 0:p?t.primary:d.color??t.muted,onMouseDown:()=>i(f)},d.id,!1,void 0,this)}),u?be(Yk,{palette:t,dir:"right"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function Ue(e){let{palette:t,label:r,tone:n="idle",fg:o,bg:i,onMouseDown:s}=e,a=d2(t,n);return be("box",{height:1,paddingLeft:1,paddingRight:1,backgroundColor:i??a.bg,overflow:"hidden",flexShrink:0,onMouseDown:s,children:be("text",{fg:o??a.fg,children:r},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function mt(e){let{palette:t,hints:r}=e;return be("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:r.map((n)=>be("box",{height:1,paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:be("text",{wrapMode:"none",children:[be("span",{fg:t.primary,children:n.key},void 0,!1,void 0,this),be("span",{fg:t.muted,children:` ${n.label}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},`${n.key}-${n.label}`,!1,void 0,this))},void 0,!1,void 0,this)}function wt(e){let{palette:t,items:r,hints:n,ruled:o=!0}=e,i=be("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[r.map((s,a)=>be(Ue,{palette:t,label:s.text,tone:s.tone,onMouseDown:s.onMouseDown},`${s.text}-${a}`,!1,void 0,this)),n&&n.length>0?be(p2,{children:[be("box",{flexGrow:1,backgroundColor:t.element},void 0,!1,void 0,this),be(mt,{palette:t,hints:n},void 0,!1,void 0,this)]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this);if(!o)return i;return be(Zt,{palette:t,backgroundColor:t.element,children:i},void 0,!1,void 0,this)}function ot(e){let{palette:t,title:r,termW:n,termH:o,preferW:i,preferH:s,anchor:a="center",borderColor:l,bottomTitle:c,gap:u,children:d}=e,f=Ln(ye()),p=ns(n,o,i,s,a,!f);return be("box",{position:"absolute",left:p.left,top:p.top,width:p.width,height:p.height,border:!0,borderStyle:Zm,borderColor:l??t.borderActive,backgroundColor:t.panel,padding:f?0:1,title:r,titleColor:t.primary,bottomTitle:c,gap:f?0:u,flexDirection:"column",overflow:"hidden",children:d},void 0,!1,void 0,this)}function Me(e){return{rootOptions:{flexGrow:1,height:"100%",overflow:"hidden",backgroundColor:e.panel},viewportOptions:{backgroundColor:e.panel},contentOptions:{backgroundColor:e.panel},scrollbarOptions:{trackOptions:{foregroundColor:e.primary,backgroundColor:e.element}}}}function je(e,t){if(!e)return;e.scrollBy({x:0,y:t})}function ss(e,t){let r=u2(null);return c2(()=>{let n=r.current;if(!n||e<0)return;let o=requestAnimationFrame(()=>{n.scrollChildIntoView(`${t}-${e}`)});return()=>cancelAnimationFrame(o)},[t,e]),r}function Pt(e){let t=ye(),r=Sa(t),n=e.scroll?be("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Me(e.palette),children:be("box",{flexDirection:"column",overflow:"hidden",children:e.children},void 0,!1,void 0,this)},void 0,!1,void 0,this):e.children;return be("box",{flexGrow:1,border:!0,borderStyle:Zm,borderColor:e.borderColor??e.palette.border,title:e.title,titleColor:e.palette.primary,paddingLeft:t.pad,paddingRight:t.pad,paddingTop:r?0:t.pad,paddingBottom:r?0:t.pad,backgroundColor:e.palette.panel,flexDirection:"column",overflow:"hidden",children:n},void 0,!1,void 0,this)}function ai(e){let{palette:t,label:r,value:n,tone:o="text"}=e,i=ye(),s=o==="success"?t.success:o==="warning"?t.warning:o==="error"?t.error:o==="muted"?t.muted:t.text;return be("box",{height:i.rowH,flexDirection:"row",overflow:"hidden",children:[be("box",{width:14,flexShrink:0,overflow:"hidden",children:be("text",{fg:t.muted,children:j(r,14)},void 0,!1,void 0,this)},void 0,!1,void 0,this),be("box",{flexGrow:1,overflow:"hidden",children:be("text",{fg:s,wrapMode:"none",children:n},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Tu(e){let{palette:t,title:r,body:n,hint:o}=e;return be("box",{paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",border:!0,borderStyle:Zm,borderColor:t.borderActive,titleColor:t.primary,children:[be("text",{fg:t.primary,children:r},void 0,!1,void 0,this),be("text",{fg:t.text,wrapMode:"word",children:n},void 0,!1,void 0,this),o?be("text",{fg:t.muted,wrapMode:"word",children:o},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var Zm="rounded";var Re=A(()=>{Ht();wr();nt();so();Mr();rt()});import{jsxDEV as Be,Fragment as m2}from"@opentui/react/jsx-dev-runtime";function Xk(e){let{palette:t,cfg:r,snap:n,google:o,profile:i,reveal:s,width:a}=e,l=xu(n,r?Object.keys(r.services):void 0),c=n?.proxy.running===!0,u=o?.adcAvailable===!0,d=a<vu,f=ke(r?.project.name||"local",d?18:22),p=ke(i||n?.profile||"no profile",16),m=ik({width:a,running:l.running,total:l.total,proxyOn:c,proxyAddress:n?.proxy.address??"",mcpOn:n?.mcp?.running===!0,adc:u,reveal:s}).filter((w)=>!w.hide&&w.label!=="").map((w)=>Be(Ue,{palette:t,label:w.label,tone:w.tone},w.label,!1,void 0,this)),h=Sa(ye()),g=Be("box",{height:1,flexGrow:1,overflow:"hidden",backgroundColor:t.panel,paddingLeft:1,children:Be("text",{wrapMode:"none",children:[Be("span",{fg:t.primary,children:vr()},void 0,!1,void 0,this),Be("span",{fg:t.muted,children:` ${f}`},void 0,!1,void 0,this),Be("span",{fg:t.accent,children:` ${p}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this);return Be(Zt,{palette:t,backgroundColor:t.panel,ruled:!h,children:Be("box",{height:d?2:1,flexDirection:"column",backgroundColor:t.panel,overflow:"hidden",children:[Be("box",{height:1,flexDirection:"row",overflow:"hidden",children:[g,d?null:m]},void 0,!0,void 0,this),d?Be("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.panel,children:m},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function Qk(e){let{palette:t,screen:r,width:n,onSelect:o}=e,i=n>=Jk+f2,s=i?Math.max(1,n-Jk):n,a=oi.map((c)=>({id:c.id,label:X0(c.label,s)})),l=Z0(r);return Be(Zt,{palette:t,backgroundColor:t.element,children:Be("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[Be(Cu,{palette:t,items:a,active:l,width:s,onPick:(c)=>{let u=oi[c];if(u)o(u.id)}},void 0,!1,void 0,this),i?Be(m2,{children:[Be("box",{flexGrow:1,backgroundColor:t.element},void 0,!1,void 0,this),Be(mt,{palette:t,hints:[Nr]},void 0,!1,void 0,this)]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function Zk(e){let{palette:t,screen:r,overlay:n,status:o,paused:i,errorOnly:s,width:a,copyKey:l}=e,c=Sa(ye()),u=Math.max(18,Math.floor(a*0.42)),d=sk(Ak(r,n,l),u),f=ak(o);return Be(Zt,{palette:t,backgroundColor:t.panel,edge:"top",ruled:!c,children:Be("box",{height:1,backgroundColor:t.panel,overflow:"hidden",children:Be(wt,{ruled:!1,palette:t,items:[{text:r,tone:"ghost"},{text:i?"PAUSED":"LIVE",tone:i?"warning":"success"},...s?[{text:"ERROR+",tone:"error"}]:[],...o===""?[]:[{text:ke(o,Math.max(16,a-u-28)),tone:f}]],hints:d},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function it(e){return Be("box",{flexGrow:1,padding:1,overflow:"hidden",children:Be(Tu,{palette:e.palette,title:e.title,body:e.body,hint:e.hint},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Eu(e){return Be("box",{flexGrow:1,padding:1,overflow:"hidden",children:Be("text",{fg:e.palette.text,children:e.label},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function eS(e){return Be("box",{flexGrow:1,padding:1,flexDirection:"column",overflow:"hidden",children:[Be("text",{fg:e.palette.error,children:e.title},void 0,!1,void 0,this),Be("text",{fg:e.palette.text,wrapMode:"word",children:e.body},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Jk,f2=8;var cr=A(()=>{Ht();wr();si();nt();so();Su();Re();Mr();Jk=Nr.key.length+Nr.label.length+3});function h2(){if(process.platform==="darwin")return[["pbcopy"]];if(process.platform==="win32")return[["clip"]];return[["wl-copy"],["xclip","-selection","clipboard"],["xsel","--clipboard","--input"]]}function g2(){return h2().filter((e)=>{let t=e[0];return typeof t==="string"&&Bun.which(t)!==null})}function v2(e){return`\x1B]52;c;${Buffer.from(e,"utf8").toString("base64")}\x07`}function tS(){if(process.platform==="linux")return"install wl-clipboard (Wayland) or xclip (X11)";return"no clipboard helper found"}async function Ru(e){let t=g2(),r;for(let n of t)try{await b2(n,e);return}catch(o){r=o instanceof Error?o:Error(String(o))}if(process.platform!=="win32")try{await y2(e);return}catch(n){r=n instanceof Error?n:Error(String(n))}throw Ie($e,"clipboard unavailable",r?`${tS()} (${r.message})`:tS())}async function y2(e){let t=v2(e);try{await Bun.write("/dev/tty",t)}catch{if(!process.stderr.write(t))throw Error("terminal clipboard write failed")}}async function b2(e,t){let r=Bun.spawn(e,{stdin:"pipe",stdout:"ignore",stderr:"ignore"});r.stdin.write(t),await r.stdin.end();let n=await r.exited;if(n!==0)throw Error(`${e[0]} exited ${n}`)}var eh=A(()=>{ne()});function ah(e){let t=Math.min(e.startUnixNano,e.endUnixNano),r=Math.max(e.startUnixNano,e.endUnixNano);return Math.max(0,(r-t)/qt)}function li(e){if(!Number.isFinite(e)||e<0)return"0ms";if(e>0&&e<1)return`${e.toFixed(1)}ms`;if(e<sS)return`${Math.round(e)}ms`;return`${(e/sS).toFixed(2)}s`}function uS(e){if(e==="server")return"\u25C0";if(e==="client")return"\u25B6";if(e==="producer")return"\u25B2";if(e==="consumer")return"\u25BC";return"\u25CF"}function lh(e){return`${uS(e)} ${e}`}function dS(e){if(e==="error")return"ERR";if(e==="ok")return"ok";return"\u2014"}function Pu(e){let t=new Map,r=new Set(e.spans.map((s)=>s.spanId));for(let s of e.spans){let a=s.parentSpanId&&r.has(s.parentSpanId)?s.parentSpanId:"",l=t.get(a)??[];l.push(s),t.set(a,l)}for(let s of t.values())s.sort((a,l)=>a.startUnixNano-l.startUnixNano||a.seq-l.seq);let n=[],o=new Set;nh(t,"",0,o,n);let i=[...e.spans].filter((s)=>!o.has(s.seq)).sort((s,a)=>s.startUnixNano-a.startUnixNano||s.seq-a.seq);for(let s of i)if(!o.has(s.seq))o.add(s.seq),n.push({span:s,depth:0}),nh(t,s.spanId,1,o,n);return n}function nh(e,t,r,n,o){let i=(e.get(t)??[]).filter((s)=>!n.has(s.seq));for(let s of i)n.add(s.seq),o.push({span:s,depth:Math.min(r,aS)}),nh(e,s.spanId,r+1,n,o)}function pS(e){if(e.spans.length===0)return{durationMs:0,spanCount:0,serviceCount:0,errorCount:0,services:[],startUnixNano:0,endUnixNano:0};let t=Math.min(e.spans[0].startUnixNano,e.spans[0].endUnixNano),r=Math.max(e.spans[0].startUnixNano,e.spans[0].endUnixNano),n=[],o=0;for(let i of e.spans){let s=Math.min(i.startUnixNano,i.endUnixNano),a=Math.max(i.startUnixNano,i.endUnixNano);if(s<t)t=s;if(a>r)r=a;let l=i.resource["service.name"];if(typeof l==="string"&&l!==""&&!n.includes(l))n.push(l);if(i.status.code==="error")o+=1}return{durationMs:Math.max(0,(r-t)/qt),spanCount:e.spans.length,serviceCount:n.length,errorCount:o,services:n,startUnixNano:t,endUnixNano:r}}function fS(e){return e.reduce((t,r)=>Math.max(t,r.depth),0)}function mS(e){return e.reduce((t,r)=>{let n=typeof r.span.resource["service.name"]==="string"?r.span.resource["service.name"]:"";return Math.max(t,n.length)},7)}function D2(e){let t=Math.max(0,Math.min(aS,e));return lS+cS+t*rh}function hS(e,t=0,r=nS){let n=Math.max(2,D2(t)),o=x2,i=e>=90?C2:e>=70?T2:nS,s=Math.max(rS,Math.min(i,r)),a=e>=oS?E2:R2,l=e>=oS?_2:P2,c=e-n-s-o;if(c<a+l){let m=a+l-c;s=Math.max(rS,s-m)}let u=Math.max(2,e-n-s-o),d=Math.max(l,Math.round(u*A2)),f=u-d;if(f<a)f=Math.min(a,Math.max(1,u-l)),d=Math.max(1,u-f);let p=n+s+o+f+d;if(p<e)d+=e-p;return{tree:n,service:s,name:Math.max(1,f),duration:o,bar:Math.max(1,d)}}function gS(e){return e.tree+e.service+e.name+e.duration}function vS(e,t,r=w2,n=!1){let o=Math.max(0,Math.floor((r-lS-cS)/rh)),i=Math.min(Math.max(0,e),o)*rh,s=`${n?"\u25B8":" "}${" ".repeat(i)}${uS(t)}`;return j(s,r)}function yS(e,t,r){if(r<=0)return{offset:0,width:1};let n=Math.min(e.startUnixNano,e.endUnixNano),o=Math.max(e.startUnixNano,e.endUnixNano),i=_u((n-t)/r),s=_u((o-t)/r);return{offset:i,width:Math.max(0,s-i)}}function O2(e,t,r){if(r<=0)return{start:0,end:0};let n=_u(e),o=_u(e+t),i=Math.floor(n*r),s=Math.ceil(o*r);if(s<=i)s=i+1;return i=Math.max(0,Math.min(r-1,i)),s=Math.max(i+1,Math.min(r,s)),{start:i,end:s}}function bS(e,t,r){if(r<=0)return{lead:"",fill:"",trail:""};let{start:n,end:o}=O2(e,t,r);return{lead:"\u2591".repeat(n),fill:"\u2588".repeat(o-n),trail:"\u2591".repeat(r-o)}}function wS(e,t){if(t<=0)return"";let r="0",n=li(e/2),o=li(e);if(t<r.length+n.length+o.length+2)return M2(o,t);let i=Math.max(r.length+1,Math.floor((t-n.length)/2)),s=Array.from({length:t},()=>"\u2500");return th(s,0,r),th(s,i,n),th(s,t-o.length,o),s.join("")}function xS(e){return{tree:j("",e.tree),service:j("SERVICE",e.service),name:j("SPAN",e.name),duration:j("DUR",e.duration),bar:j("TIME",e.bar)}}function Au(e,t){if(t<=0)return 0;return Math.max(0,Math.min(t-1,e))}function kS(e,t,r,n,o=S2){return e===r&&n-t<=o}function SS(e,t){return Math.max(0,(t-e.startUnixNano)/qt)}function CS(e){let t=e.spanCount===1?"1 span":`${e.spanCount} spans`,r=e.serviceCount===1?"1 service":`${e.serviceCount} services`,n=e.errorCount===0?"no errors":e.errorCount===1?"1 error":`${e.errorCount} errors`;return[{id:"dur",label:li(e.durationMs),tone:"primary"},{id:"spans",label:t,tone:"ghost"},{id:"svc",label:r,tone:"ghost"},{id:"err",label:n,tone:e.errorCount===0?"success":"error"}]}function TS(e,t){let r=[],n=0;for(let i of e){let s=i.label.length+iS;if(n+s>t)break;r.push(i),n+=s}if(r.length>0)return r;let o=e[0];return o?[{...o,label:ke(o.label,Math.max(1,t-iS))}]:[]}function ES(e,t){if(e.length===0||t<=0)return"";return ke(e.join(" \xB7 "),t)}function RS(e){return ke(k2,e)}function _S(e,t){return{w:Math.max(oh,e-2),h:Math.max(ih,t-1)}}function PS(e,t){let r=t>=L2,n=t>=I2,o=1+(r?1:0)+(n?1:0);return{listWidth:e,headerLines:o,showServices:r,showLegend:n,listHeight:Math.max(6,t-o)}}function _u(e){if(!Number.isFinite(e))return 0;return Math.min(1,Math.max(0,e))}function th(e,t,r){for(let n=0;n<r.length;n+=1){let o=t+n;if(o>=0&&o<e.length)e[o]=r[n]??"\u2500"}}function M2(e,t){if(e.length>=t)return e.slice(0,t);return e.padStart(t)}var oh=64,ih=16,w2=6,x2=7,sh=5,k2="\u25C0 server \u25B6 client \u25CF internal \u25B2 producer \u25BC consumer",S2=400,aS=16,rh=2,lS=1,cS=1,rS=6,C2=16,T2=14,nS=10,E2=12,R2=6,_2=14,P2=8,A2=0.55,oS=56,iS=2,L2=20,I2=16,sS=1000;var Lu=A(()=>{nt()});function ch(e){return e==="slash"||e==="config-edit"||e==="setup-wizard"}function AS(e,t){return Hn(e,t.keybinds.leader??hi("x"))}function LS(e,t){return Hn(e,t.keybinds.command_list??hi("p"))}function fn(e,t){return Hn(e,t.keybinds.command??"/")||e.name==="/"}function IS(e,t){return Hn(e,t.keybinds.help??"?")||e.sequence==="?"}function DS(e,t){return Hn(e,t.keybinds.search??"f")}function OS(e){return(e.name??"").toLowerCase()==="q"&&!e.ctrl&&!e.meta&&!e.super&&!e.alt&&!e.option}function MS(e){let t=e.name??"";return t==="R"||e.shift===!0&&t.toLowerCase()==="r"}function NS(e){return rn(e)&&(e.name??"").toLowerCase()==="l"}function FS(e,t){return Hn(e,t.keybinds.copy??kn())}function $S(e,t,r=N2){return t>0&&e-t<=r}function lo(e,t,r,n){return Hn(e,t.keybinds[r]??n)}function as(e){let t=(e.name??"").toLowerCase();return t==="pagedown"||rn(e)&&t==="d"}function ls(e){let t=(e.name??"").toLowerCase();return t==="pageup"||rn(e)&&t==="u"}var N2=2000;var Iu=A(()=>{Vr()});function cs(e){return`http://127.0.0.1:${e}/mcp`}function uh(e){if(e==="")return{};return{Authorization:`Bearer ${e}`}}function dh(e,t){return JSON.stringify({mcpServers:{devctl:{type:"http",url:e,headers:uh(t)}}},null,2)}function ph(e,t){return JSON.stringify({mcpServers:{devctl:{url:e,headers:uh(t)}}},null,2)}function fh(e,t){return JSON.stringify({mcp:{devctl:{type:"remote",url:e,headers:uh(t),enabled:!0}}},null,2)}function mh(e,t){let r=t===""?"":`
|
|
2482
|
+
`),o=[];for(let i of n)if(i.length<=r)o.push(i);else o.push(...tN(i,r));return o.length>0?o:[""]}function B0(e,t){return e==="all"||e==="focus"&&t}function pu(e){if(e==="clip")return"focus";if(e==="focus")return"all";return"clip"}function $m(e,t,r,n=Jr){if(e.length===0)return{start:0,items:[],newer:0};if(!t){let a=Math.max(0,e.length-n);return{start:a,items:e.slice(a),newer:0}}let o=e.length-1,i=Math.max(0,Math.min(r,o)),s=e.slice(i,i+n);return{start:i,items:s,newer:Math.max(0,e.length-i-s.length)}}function fu(e,t=Jr){return Math.max(0,e-t)}function Hm(e,t,r,n){let o=Math.max(t-1,0);if(e<0&&r>0)return{selected:0,startDelta:Math.max(-r,e)};if(e>o&&n>0)return{selected:o,startDelta:Math.min(n,e-o)};return{selected:Math.min(o,Math.max(0,e)),startDelta:0}}function mu(e){if(e==="all")return"wrap all";if(e==="focus")return"wrap selected";return"clip"}function tN(e,t){let r=[],n=e;while(n.length>t){let o=n.slice(0,t),i=rN(o);if(i>0)r.push(n.slice(0,i).trimEnd()),n=n.slice(i).trimStart();else r.push(n.slice(0,t)),n=n.slice(t)}if(n.length>0)r.push(n);return r}function rN(e){let t=e.lastIndexOf(" "),r=e.lastIndexOf("\t"),n=e.lastIndexOf(","),o=Math.max(t,r,n);if(o<Math.floor(e.length*XM))return-1;return e[o]===","?o+1:o}function nN(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function oN(e,t=!1){let r=e.trim();if(r==="")return;if(t){let n=Os(r);if(n)return new RegExp(n.source,n.flags.includes("g")?n.flags:`${n.flags}g`)}return new RegExp(nN(r),"gi")}function iN(e,t){let r=e.map((a)=>a.text).join(""),n=[];t.lastIndex=0;let o=t.exec(r);while(o){let a=o[0]??"";if(a.length>0)n.push({start:o.index,end:o.index+a.length});if(a.length===0)t.lastIndex+=1;o=t.exec(r)}if(n.length===0)return e;let i=[],s=0;for(let a of e){let l=s,c=s+a.text.length,u=0;for(let d of n){let f=Math.max(d.start,l),p=Math.min(d.end,c);if(p<=f)continue;let m=f-l,h=p-l;if(m>u)i.push({text:a.text.slice(u,m),kind:a.kind});i.push({text:a.text.slice(m,h),kind:"search"}),u=h}if(u<a.text.length)i.push({text:a.text.slice(u),kind:a.kind});s=c}return i.filter((a)=>a.text!=="")}function W0(e,t="",r=!1){let n=du(e),o=[],i=new RegExp(QM.source,"gi"),s=0,a=i.exec(n);while(a){let u=a[0]??"";if(a.index>s)o.push({text:n.slice(s,a.index),kind:"text"});o.push({text:u,kind:ZM(u)}),s=a.index+u.length,a=i.exec(n)}if(s<n.length)o.push({text:n.slice(s),kind:"text"});let l=o.length===0?[{text:n,kind:"text"}]:o,c=oN(t,r);return c?iN(l,c):l}function z0(e,t){let r=t.reduce((s,a)=>Math.max(s,a.length),0),n=Mm+Nm+VM+uu*JM,o=Math.max(N0,e-n),i=Math.max(N0,r);return Math.min(Am,o,i)}function es(e){return sN.has(e)}function G0(e,t,r,n){let o=r===""?t:t.filter((a)=>a.timestamp>=r);if(o.length===0)return e;let i=Math.max(1,n);if(o.length>=i)return o.slice(-i);let s=Math.max(0,e.length+o.length-i);return e.slice(s).concat(o)}function K0(e,t){let r=t.length>0?t[t.length-1].seq:-1,n=e.filter((o)=>o.seq>r);return[...t,...n]}function V0(e,t){if(t.length===0)return e;let r=new Set(e.map((o)=>o.seq)),n=t.filter((o)=>!r.has(o.seq));return n.length===0?e:[...n,...e]}function Um(e,t,r){return e&&t<=0&&r}function Y0(e){return e.filter((t)=>Si(t.severityNumber)).length}function ni(e,t){let r=t.services?.filter((c)=>c!=="")??[],n=t.service??"",o=(t.search??"").trim(),i=t.source??"",s=t.since??"",a=t.until??"",l;if(o!=="")if(t.regex===!0){let c=Os(o);if(c)l=(u)=>c.test(u);else l=(u)=>u.toLowerCase().includes(o.toLowerCase())}else{let c=o.toLowerCase();l=(u)=>u.toLowerCase().includes(c)}return e.filter((c)=>{if(r.length>0&&!r.includes(c.service))return!1;if(n!==""&&c.service!==n)return!1;if(i!==""&&c.source!==i)return!1;if(t.systemLogs===!1&&es(c.source))return!1;if(s!==""&&c.timestamp<s)return!1;if(a!==""&&c.timestamp>a)return!1;if(t.traceId&&c.traceId!==t.traceId)return!1;if(t.errorOnly===!0&&!Si(c.severityNumber))return!1;if(!l)return!0;return l(As(c))||l(c.service)})}function aN(e,t){let r={};for(let i of e)r[i.service]=(r[i.service]??0)+1;let n=t.map((i)=>({name:i,count:r[i]??0})),o=Object.keys(r).filter((i)=>!t.includes(i)).sort().map((i)=>({name:i,count:r[i]??0}));return[...n,...o]}function J0(e,t,r=[]){let n=hu(e,t,r);return[{name:"",count:t.length},...aN(t,n)]}function lN(e,t){let r=e.map((o)=>({name:o,count:t[o]??0})),n=Object.keys(t).filter((o)=>!e.includes(o)).sort().map((o)=>({name:o,count:t[o]??0}));return[...r,...n]}function X0(e,t,r=[]){let n=Object.keys(t.byService).map((i)=>({service:i})),o=hu(e,n,r);return[{name:"",count:t.total},...lN(o,t.byService)]}function Q0(e,t){if(e<=0)return"none started";return`${e}/${t} running`}function hu(e,t,r=[]){let n=[...e],o=(i)=>{if(i!==""&&!n.includes(i))n.push(i)};for(let i of r)o(i);for(let i of t)o(i.service);return n}function jm(e,t,r){let n=["",...e],o=n.indexOf(t),s=((o<0?0:o)+r+n.length)%n.length;return n[s]??""}var $0=8,Mm=9,Nm=8,N0=10,VM=16,uu=1,Jr=200,YM=2,F0=1,JM=2,XM=0.4,QM,eN,sN,q0;var br=A(()=>{sn();nt();Ut();QM=/("[^"]*"|'[^']*'|\b(?:ERROR|FATAL|WARN(?:ING)?|FAIL(?:ED)?)\b|\b\d{3,5}\b)/gi;eN=/\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-Z\\-_]/g;sN=new Set(["auth","devctl","proxy"]),q0=["devctl","mcp","auth"]});function ts(e){return e.length+uN}function Z0(e,t){if(t<pN)return ke(e,3);if(t<dN)return ke(e,4);return e}function ek(e,t,r){let n=e.length;if(n===0||r<=0)return{start:0,end:-1};let o=t>=0&&t<n?t:0,i=Bm(e,o,r);if(i.start===0&&i.end===n-1)return i;let s=o>0?gu:0,a=o<n-1?gu:0,l=s+a,c=Bm(e,o,Math.max(e[o]??0,r-l)),u=(s>0&&c.start===0?gu:0)+(a>0&&c.end===n-1?gu:0);if(u===0)return c;return Bm(e,o,Math.max(e[o]??0,r-l+u))}function Bm(e,t,r){let n=e.length,o=t,i=t,s=e[t]??0;if(s>=r)return{start:t,end:t};while(o>0||i<n-1){let a=o>0?e[o-1]??0:Number.POSITIVE_INFINITY,l=i<n-1?e[i+1]??0:Number.POSITIVE_INFINITY,c=o>0&&s+a<=r,u=i<n-1&&s+l<=r;if(!c&&!u)break;let d=t-(o-1),f=i+1-t;if(c&&(!u||d<=f))o-=1,s+=a;else if(u)i+=1,s+=l;else break}return{start:o,end:i}}function tk(e){if(e==="detail")return oi.findIndex((t)=>t.id==="services");return oi.findIndex((t)=>t.id===e)}function rk(e,t){if(e==="doctor")return t.doctor;if(e==="settings")return t.settings;if(e==="profiles")return t.profiles;if(e==="dashboard"||e==="services")return t.services;if(e==="logs")return t.logs??0;if(e==="mcp")return t.mcp??0;if(e==="setup")return cN;if(e==="config")return t.config??0;return 0}function nk(e){if(e.length===1&&e>="1"&&e<="9")return oi[Number(e)-1]?.id;return}var cN=9,uN=2,gu=2,dN=80,pN=56,oi,io;var so=A(()=>{nt();oi=[{id:"dashboard",label:"dashboard"},{id:"services",label:"services"},{id:"logs",label:"logs"},{id:"proxy",label:"proxy"}];io=oi.map((e)=>e.id)});function sk(e,t=!0){let r=e<vu?ok+1:ok,n=t?yN:0;return r+n+gN+n+vN+n}function ao(e){return Math.max(mN,e-hN*2)}function ak(e){let t=e.width<fN,r=e.proxyOn?`\u25CF ${ke(e.proxyAddress,t?10:18)}`:"";return[{label:t?`${e.running}/${e.total}`:Q0(e.running,e.total),tone:e.running>0?"success":"idle"},{label:r,tone:"info",hide:!e.proxyOn},{label:"MCP",tone:"info",hide:!e.mcpOn},{label:e.adc?t?"ADC":"ADC ok":t?"!ADC":"ADC missing",tone:e.adc?"success":"error"},{label:t?"sec":"secrets shown",tone:"warning",hide:!e.reveal}]}function ik(e){return e.key==="/"&&e.label==="command"}function bN(e){return e.key.length+e.label.length+3}function lk(e,t){let r=e.filter(ik),n=e.filter((s)=>!ik(s)),o=[],i=0;for(let s of[...r,...n]){let a=bN(s);if(i+a>t)break;o.push(s),i+=a}return o}function ns(e,t,r,n,o="center",i=!0){let s=Math.min(r,Math.max(1,e-4)),a=Math.min(sk(e,i),Math.max(0,t-1)),l=Math.min(n,Math.max(1,t-a)),c=Math.max(0,Math.min(Math.floor((e-s)/2),Math.max(0,e-s))),u=o==="bottom"?t-2-l:Math.floor((t-l)/2),d=Math.max(0,Math.min(u,t-l));return{left:c,top:d,width:s,height:l}}function ck(e){if(e==="")return"idle";if(xN.test(e))return"error";if(e.includes("session only"))return"warning";if(wN.test(e))return"success";return"info"}function uk(e,t,r){if(e==="restart-cascade")return{title:"Restart dependents?",body:`${r?.services?.join(", ")||"selected services"} has dependents. Enter restarts only the named services. Press c to cascade (same as /restart --cascade).`};if(e==="quit")return{title:"Quit",body:"Stop managed services and leave the TUI? Press d to detach (daemon stays). Press k to stop the daemon and leave services running (devctl down --keep-services)."};if(e==="reload")return{title:"Reload applied",body:t===""?"Configuration changed. Restart marked services?":`Restart required: ${t}`};if(e==="reset-prefs")return{title:"Reset preferences",body:"Restore theme, display size, mouse, and leader timeout to defaults? This overwrites your saved tui.json values."};if(e==="free-port"){let n=r?.port??0,o=r?.process||"process",i=r?.pid??0;return{title:`Free port ${n}`,body:`Stop ${o} (pid ${i}) so port ${n} can be used? This sends SIGTERM, then SIGKILL if it stays up.`}}return{title:"Start profile",body:t===""?"Start the configured services?":`Start profile ${t}?`}}function dk(e){if(e==="quit")return[{key:"enter",label:"stop services"},{key:"d",label:"detach"},{key:"k",label:"down, keep services"},{key:"esc",label:"stay"}];if(e==="restart-cascade")return[{key:"enter",label:"named only"},{key:"c",label:"cascade"},{key:"esc",label:"stay"}];return[{key:"enter",label:"confirm"},{key:"esc",label:"stay"}]}function pk(e){let t=e.payload?.error;return typeof t==="string"&&t!==""?t:"configuration reload failed"}var rs=100,vu=90,fN=60,mN=8,hN=6,ok=1,gN=1,vN=1,yN=1,E5,wN,xN;var wr=A(()=>{nt();br();so();E5=sk(vu-1);wN=/^(started|stopped|restarted|refreshed|cleared|copied|exported|jumped|proxy started|proxy stopped|secrets|re-running|theme |mouse |leader |display |restored)/i,xN=/\b(fail|error|unknown|not found|no configuration|blocked|already in use|is using port)\b/i});function yu(){return[{name:"start",aliases:["up"],desc:"Start selected services or the current profile",leader:"n",group:"services",usage:"<service>"},{name:"stop",aliases:[],desc:"Stop selected services",leader:"x",group:"services",usage:"<service>"},{name:"restart",aliases:[],desc:"Restart selected services",leader:"R",group:"services",usage:"<service>",suggest:[{token:"--cascade",desc:"Restart selected services and their dependents"}]},{name:"run",aliases:["task"],desc:"Run a one-off task; empty /run opens a picker",leader:"",group:"services",usage:"<task>"},{name:"exec",aliases:[],desc:"Run a command in a service context; empty /exec opens a picker",leader:"",group:"services",usage:"<service>"},{name:"services",aliases:["s"],desc:"Open the services screen",leader:"s",group:"nav"},{name:"logs",aliases:["l"],desc:"Open the log viewer",leader:"l",group:"nav"},{name:"auth",aliases:["identity","a"],desc:"Open identity",leader:"a",group:"nav",suggest:[{token:"login",desc:"Run gcloud ADC login"},{token:"logout",desc:"Revoke application-default credentials"},{token:"refresh",desc:"Probe identities"}]},{name:"credentials",aliases:["creds"],desc:"Open credential store status",leader:"",group:"nav"},{name:"reload",aliases:[],desc:"Reload configuration",leader:"",group:"ui"},{name:"proxy",aliases:["p"],desc:"Open the proxy screen",leader:"p",group:"nav"},{name:"mcp",aliases:["agent"],desc:"Open the MCP server screen for coding agents",leader:"",group:"nav"},{name:"doctor",aliases:["d"],desc:"Run environment diagnostics",leader:"d",group:"nav"},{name:"stats",aliases:["metrics"],desc:"View system and service statistics",leader:"m",group:"nav"},{name:"config",aliases:["c"],desc:"View merged configuration",leader:"c",group:"nav"},{name:"import",aliases:[],desc:"Preview or write a Compose mapping",leader:"",group:"ui",suggest:[{token:"compose",desc:"Preview a Compose mapping; add --write to save"}]},{name:"diff",aliases:["provenance"],desc:"Show winning config sources and what they shadowed",leader:"",group:"ui"},{name:"daemon",aliases:["bootstrap"],desc:"Show supervisor bootstrap logs (same file as devctl daemon logs)",leader:"",group:"app"},{name:"update",aliases:[],desc:"Install a newer GitHub Release when the install method is known",leader:"",group:"app"},{name:"profiles",aliases:["o"],desc:"Select a development profile",leader:"o",group:"nav"},{name:"setup",aliases:["init"],desc:"Open setup guidance",leader:"i",group:"nav"},{name:"dashboard",aliases:["home"],desc:"Return to the dashboard",leader:"h",group:"nav"},{name:"themes",aliases:["theme"],desc:"List available themes",leader:"t",group:"ui"},{name:"settings",aliases:["prefs","preferences"],desc:"Open TUI settings (theme, mouse, MCP page)",leader:"",group:"ui"},{name:"help",aliases:["?"],desc:"Show the help dialog",leader:"",group:"ui"},{name:"refresh",aliases:[],desc:"Refresh status and logs",leader:"r",group:"ui"},{name:"regex",aliases:[],desc:"Toggle regex log search",leader:"",group:"logs"},{name:"since",aliases:[],desc:"Filter logs after an ISO timestamp",leader:"",group:"logs",usage:"<timestamp>"},{name:"until",aliases:[],desc:"Filter logs before an ISO timestamp",leader:"",group:"logs",usage:"<timestamp>"},{name:"history",aliases:[],desc:"Load a persisted log session",leader:"",group:"logs",usage:"<session>"},{name:"edit",aliases:[],desc:"Open configuration in $EDITOR",leader:"",group:"ui"},{name:"buffer",aliases:[],desc:"Edit configuration in a validate/save buffer",leader:"",group:"ui"},{name:"pause",aliases:[],desc:"Pause or resume live logs",leader:"",group:"logs"},{name:"fullscreen",aliases:["zen","expand"],desc:"Expand logs to fill the terminal",leader:"z",group:"logs"},{name:"split",aliases:[],desc:"Split the logs screen into two service panes",leader:"",group:"logs"},{name:"trace",aliases:[],desc:"Search logs for a request or trace id",leader:"",group:"logs",usage:"<id>"},{name:"filter",aliases:[],desc:"Toggle ERROR+ log filter",leader:"",group:"logs"},{name:"system",aliases:["internal"],desc:"Show or hide internal auth/mcp/devctl/proxy logs",leader:"",group:"logs"},{name:"reveal",aliases:[],desc:"Reveal or hide secret environment values",leader:"",group:"ui"},{name:"wrap",aliases:[],desc:"Cycle log wrap: all lines, clip, or selected row",leader:"",group:"logs"},{name:"copy",aliases:[],desc:"Copy the highlighted selection to the clipboard",leader:"",group:"ui"},{name:"export",aliases:[],desc:"Write filtered logs to ~/.devctl/exports",leader:"e",group:"logs"},{name:"exports",aliases:["open-exports"],desc:"Open the log export folder",leader:"",group:"logs"},{name:"clear",aliases:["new"],desc:"Clear the on-screen log buffer",leader:"",group:"logs"},{name:"version",aliases:["v"],desc:"Show the current devctl version",leader:"",group:"app"},{name:"down",aliases:[],desc:"Stop the supervisor",leader:"",group:"app",suggest:[{token:"--keep-services",desc:"Stop the supervisor and leave processes running"}]},{name:"exit",aliases:["quit","q"],desc:"Exit (detach or stop services)",leader:"q",group:"app"}]}function ii(e){let t=e.trim().toLowerCase().replace(/^\//,""),r=t.indexOf(" ");return r===-1?t:t.slice(0,r)}function vk(e){let t=ii(e);if(t==="")return yu();return yu().map((r)=>({command:r,score:NN(r,t)})).filter((r)=>r.score>0).sort((r,n)=>n.score-r.score||r.command.name.localeCompare(n.command.name)).map((r)=>r.command)}function NN(e,t){if(t==="")return 1;let r=e.name.toLowerCase(),n=e.aliases.map((o)=>o.toLowerCase());return $N(r,n,t)||HN(r,n,t)||UN(r,n,t)||jN(r,n,t)||FN(e.suggest,t)||BN(e.desc.toLowerCase(),t)}function FN(e,t){if(!e||e.length===0)return 0;let r=e.map((n)=>n.token.toLowerCase());if(r.some((n)=>n===t||n.replace(/^-+/,"")===t))return mk;if(t.length<gk)return 0;return r.some((n)=>n.includes(t)||n.replace(/^-+/,"").startsWith(t))?hk:0}function $N(e,t,r){if(e===r)return kN;return t.includes(r)?SN:0}function HN(e,t,r){if(e.startsWith(r))return CN;if(t.some((i)=>i.startsWith(r)))return TN;let n=e.split("-");return n.length>1&&n.some((i)=>i.startsWith(r))?EN:0}function UN(e,t,r){if(r.length<gk)return 0;if(e.includes(r))return mk;return t.some((n)=>n.includes(r))?hk:0}function jN(e,t,r){if(r.length<LN)return 0;let n=fk(e,r);if(n>0)return RN+Math.min(n,MN);return t.some((o)=>fk(o,r)>0)?_N:0}function fk(e,t){let r=0,n=0,o=0;for(let i=0;i<t.length;i+=1){let s=t[i];if(s===void 0)return 0;let a=e.indexOf(s,r);if(a<0)return 0;if(r>0&&a===r)n+=1,o+=2+n;else n=0,o+=a===0?4:1;r=a+1}return o}function BN(e,t){if(t.length<IN)return 0;if(e.split(/[^a-z0-9+]+/).filter((n)=>n.length>=DN).some((n)=>n.startsWith(t)))return PN;return t.length>=ON&&e.includes(t)?AN:0}function pn(e){let t=e.trim().toLowerCase().replace(/^\//,"").split(" ")[0]??"";return yu().find((r)=>r.name===t||r.aliases.includes(t))}function Wm(e){return e.trim().replace(/^\//,"").split(/\s+/).slice(1).filter((r)=>r!=="")}function yk(e){return yu().find((r)=>r.leader===e)?.name??""}function bk(e){let t=e.includes("--cascade")||e.includes("-c");return{services:e.filter((n)=>n!=="--cascade"&&n!=="-c"),cascade:t}}function wk(e){let t=e.includes("--print-env"),r=e.includes("--reveal"),n=e.filter((o)=>o!=="--print-env"&&o!=="--reveal"&&o!=="--");return{service:n[0]??"",printEnv:t,reveal:r,command:n.slice(1)}}var kN=100,SN=90,CN=80,TN=70,EN=60,mk=50,hk=45,RN=30,_N=28,PN=20,AN=10,gk=2,LN=3,IN=4,DN=4,ON=4,MN=9;function Ck(e){return e==="detail"?"services":e}function Tk(e){let t=io.indexOf(Ck(e));if(t<0)return"dashboard";return io[(t+1)%io.length]??"dashboard"}function Ek(e){let t=io.indexOf(Ck(e));if(t<0)return"dashboard";return io[(t-1+io.length)%io.length]??"dashboard"}function qm(e){return["services","nav","logs","ui","app","tasks"].flatMap((r)=>{let n=e.filter((o)=>o.group===r);if(n.length===0)return[];return[{group:r,items:n}]})}function bu(e){return e.hint?`${e.name} ${e.hint}`:e.name}function Gm(e){return e.name}function Rk(e){if(e.hint)return`${e.hint} \xB7 ${e.desc}`;let t=[e.usage,...(e.suggest??[]).map((r)=>r.token)].filter((r)=>Boolean(r));if(t.length===0)return e.desc;return`${e.desc} \xB7 ${t.join(" \xB7 ")}`}function _k(e){let t=e.reduce((n,o)=>Math.max(n,Gm(o).length),0),r=Math.min(zm,Math.max(t,1));return WN+r+zN}function Pk(e){return e.hint?`${e.name} ${e.hint} `:`${e.name} `}function Ak(e,t){if(e.hint)return e.hint.split(/\s+/);return pn(t)?.name===e.name?Wm(t):[]}function xk(e,t){if(t==="")return!0;let r=t.toLowerCase(),n=e.toLowerCase();return n.startsWith(r)||n.includes(r)}function qN(e,t){if(e.name==="start"||e.name==="stop"||e.name==="restart")return(t.services??[]).map((r)=>({token:r,desc:`${e.name} ${r}`}));if(e.name==="run")return(t.tasks??[]).map((r)=>({token:r,desc:`run ${r}`}));if(e.name==="exec")return(t.services??[]).map((r)=>({token:r,desc:`exec in ${r}`}));return[]}function kk(e,t){return{...e,hint:t.token,desc:t.desc,usage:void 0,suggest:void 0}}function GN(e,t,r={}){let n=Wm(t).join(" "),o=t.trim().includes(" ")||t.endsWith(" "),i=ii(t),s=[];for(let a of e){if(s.push({...a,hint:void 0}),i==="")continue;let l=a.name===i||a.aliases.includes(i),c=l?n:i;for(let u of a.suggest??[])if(xk(u.token,c))s.push(kk(a,u));if(!l||!o)continue;for(let u of qN(a,r))if(xk(u.token,n))s.push(kk(a,u))}return s}function Lk(e,t={}){let r=vk(e),n=ii(e)===""?qm(r).flatMap((o)=>o.items):r;return GN(n,e,t)}function Km(e,t,r,n){let o=ii(t),i=[...e].sort().map((s)=>({name:s,aliases:[],desc:n,leader:"",group:r}));if(o==="")return i;return i.filter((s)=>s.name.toLowerCase().includes(o))}function Ik(e,t,r=kn()){if(t==="slash")return[{key:"\u2191\u2193",label:"suggest"},{key:"tab",label:"complete"},{key:"enter",label:"run"},{key:"esc",label:"cancel"}];if(t==="themes")return[Nr,{key:"\u2191\u2193",label:"move"},{key:"enter",label:"save"},{key:"esc",label:"revert"}];if(t==="help")return[Nr,{key:"j/k",label:"scroll"},{key:"esc",label:"close"}];if(t==="trace")return[Nr,{key:"j/k",label:"span"},{key:"enter",label:"logs"},{key:wo(r),label:"copy"},{key:"esc",label:"close"}];if(t==="span-details")return[Nr,{key:"j/k",label:"scroll"},{key:"esc",label:"back"},{key:wo(r),label:"copy"}];if(t==="log-details"||t==="scroll-text")return[Nr,{key:"j/k",label:"scroll"},{key:wo(r),label:"copy"},{key:"esc",label:"close"}];if(t==="confirm")return[{key:"enter",label:"confirm"},{key:"esc",label:"stay"}];if(t==="plan")return[Nr,{key:"esc",label:"back to dashboard"},{key:"enter",label:"done"}];if(t==="leader")return[Nr,...Vm()];if(t==="config-edit")return[{key:jt("s"),label:"save"},{key:"esc",label:"discard"}];return KN(e,r)}function Vm(){return[{key:"n",label:"start"},{key:"x",label:"stop"},{key:"R",label:"restart"},{key:"s",label:"services"},{key:"l",label:"logs"},{key:"t",label:"themes"},{key:"q",label:"quit"}]}function KN(e,t){let r=[{key:wo(t),label:"copy"},Nr,{key:"?",label:"help"}];switch(e){case"dashboard":return[{key:"space",label:"select"},{key:"*",label:"all"},{key:"-",label:"none"},{key:"enter",label:"start or open"},{key:"n",label:"start"},{key:"x",label:"stop"},{key:"r",label:"refresh"},{key:"R",label:"restart"},{key:"\u2190\u2192",label:"log filter"},{key:"g",label:"latest"},{key:"z",label:"full logs"},{key:"i",label:"internal logs"},{key:jt("l"),label:"clear logs"},{key:"j/k",label:"move"},...r];case"services":return[{key:"enter",label:"detail"},{key:"space",label:"select"},{key:"*",label:"all"},{key:"-",label:"none"},{key:"n",label:"start"},{key:"x",label:"stop"},{key:"r",label:"refresh"},{key:"R",label:"restart"},...r];case"detail":return[{key:"j/k",label:"scroll env"},{key:"n",label:"start"},{key:"x",label:"stop"},{key:"o",label:"config"},{key:"l",label:"logs"},{key:"esc",label:"back"},...r];case"logs":return[{key:"\u2190\u2192",label:"filter"},{key:"e",label:"errors"},{key:"i",label:"internal logs"},{key:jt("l"),label:"clear logs"},{key:"g",label:"latest"},{key:"f",label:"search"},{key:"t",label:"time"},{key:"m",label:"meta"},{key:"w",label:"wrap"},{key:"j/k",label:"move"},{key:"p",label:"pause"},{key:"z",label:"full screen"},{key:"\\",label:"split"},{key:"/exports",label:"open folder"},...r];case"profiles":return[{key:"space",label:"set current"},{key:"enter",label:"set and start"},{key:"j/k",label:"move"},...r];case"proxy":return[{key:"n",label:"start proxy"},{key:"x",label:"stop proxy"},...r];case"mcp":return[{key:"j/k",label:"move"},{key:"space",label:"start or copy"},{key:"\u2190\u2192",label:"change port"},{key:"enter",label:"start or copy"},...r];case"config":return[{key:"enter",label:"run task"},{key:"v",label:"buffer"},{key:"e",label:"editor"},{key:"/diff",label:"sources"},{key:"/reload",label:"reload"},{key:"j/k",label:"scroll or select task"},...r];case"setup":return[{key:"j/k",label:"steps"},{key:"enter",label:"continue"},{key:"esc",label:"back"},{key:"esc\xD72",label:"quit"},...r];case"doctor":return[{key:"r",label:"run doctor again"},{key:"j/k",label:"move"},{key:"enter",label:"fix port"},...r];case"auth":return[{key:"r",label:"probe identities"},{key:"/auth login",label:"ADC login"},{key:"/auth logout",label:"revoke ADC"},{key:"/auth refresh",label:"probe"},...r];case"settings":return[{key:"j/k",label:"move"},{key:"\u2190\u2192",label:"save"},{key:"enter",label:"apply or open page"},{key:"space",label:"toggle"},...r];default:return[{key:"tab",label:"screens"},...r]}}function Dk(e,t,r){if(r<=t||e<t)return 0;return Math.min(e-t+1,r-t)}function Sk(e,t,r){let n=e.slice(t,r+1),o=new Set(n.map((i)=>i.group));return n.length+o.size}function Ok(e,t,r){if(e.length===0)return[];let n=Math.min(Math.max(t,0),e.length-1),o=n,i=n;for(;;){let s=i+1<e.length&&Sk(e,o,i+1)<=r,a=o>0&&Sk(e,o-1,i)<=r;if(s)i+=1;else if(a)o-=1;else break}return e.slice(o,i+1)}function os(e,t){if(e.length===0)return;let r=Math.min(Math.max(t,0),e.length-1);return e[r]}var Nr,WN=3,zN=2,zm=22;var si=A(()=>{Vr();so();Nr={key:"/",label:"command"}});function xu(e,t){let r=t??Object.keys(e?.services??{});return{running:r.filter((o)=>ri(e?.services[o])).length,total:r.length}}function Mk(e,t){let r=0,n=0,o=0,i=0,s=0,a=0;for(let l of e){let c=t?.services[l];if(c?.health==="HEALTHY")o+=1;let u=c?.state??"STOPPED";if(u==="FAILED")i+=1;else if(u==="STOPPING")s+=1;else if(u==="STARTING"||u==="RESTARTING")n+=1;else if(Aa(u))r+=1;else a+=1}return{total:e.length,live:r+n,running:r,starting:n,healthy:o,failed:i,stopping:s,stopped:a}}function Nk(e,t){if(!Number.isFinite(e)||!Number.isFinite(t)||t<=0)return 0;return e/t}function ZN(e,t,r){if(!Number.isFinite(e))return"success";if(e>r)return"error";if(e>t)return"warning";return"success"}function e2(e,t){return ZN(Nk(e,t),VN,YN)}function Qm(e,t=24){if(e.length===0||t<=0)return"";let r=e.length>t?e.slice(e.length-t):e,n=Math.max(...r,0);if(n<=0)return La[0]?.repeat(r.length)??"";return r.map((o)=>{let i=Number.isFinite(o)?Math.min(1,Math.max(0,o/n)):0,s=Math.min(La.length-1,Math.round(i*(La.length-1)));return La[s]??La[0]}).join("")}function t2(e,t){let r=t>0?e/t:1;if(r<XN)return"error";if(r<JN)return"warning";return"success"}function Ym(e){if(!Number.isFinite(e)||e<0)return"\u2014";return e.toFixed(2)}function r2(e){if(!Number.isFinite(e)||e<0)return"\u2014";return`${Math.round(e*100)}%`}function Fk(e,t=Date.now()){if(!e?.startTime)return"\u2014";let r=new Date(e.startTime).getTime();if(!Number.isFinite(r))return"\u2014";return Ca(t-r)}function $k(e,t=QN){return Object.entries(e).sort((r,n)=>n[1]-r[1]||r[0].localeCompare(n[0])).slice(0,t)}function Hk(e,t=1){return Math.max(24,e-c2-t*2-u2-d2-p2)}function Uk(e){let t=e>=n2,r=e>=o2,n=e>=i2,o=e>=s2,i=e>=a2,s=e>=l2,a=Yr+Bt;if(t)a+=dn+Bt;if(r)a+=Ra+Bt;if(n)a+=_a+Bt;if(o)a+=Ea+Bt;if(i)a+=ku+Bt;if(s)a+=In;return{name:Math.max(tu,e-a),health:t,cpu:r,mem:n,up:o,rst:i,pid:s}}function jk(e){let t=Number.isFinite(e)&&e>0?e:0;return{ratio:Math.min(1,t),label:r2(t)}}function Bk(e,t=h2){return`[${Qi(e.ratio,t)}] ${e.label.padStart(4)}`}function Zm(e,t){let r=e.reduce((c,u)=>Math.max(c,u.what.length),4),n=e.reduce((c,u)=>Math.max(c,u.reading.length),7),o=e.some((c)=>c.meter)?g2:0,i=is*(o>0?3:2),s=Math.min(f2,Math.max(Jm,r)),a=Math.min(m2,Math.max(Xm,n)),l=t-s-a-o-i;if(l<wu&&a>Xm)a=Math.max(Xm,a-(wu-l)),l=t-s-a-o-i;if(l<wu&&s>Jm)s=Math.max(Jm,s-(wu-l)),l=t-s-a-o-i;return{what:s,reading:a,meaning:Math.max(0,l),meter:o}}function Wk(e){return v2.has((e?.health.type??"").toLowerCase())}function zk(e){if(e==="darwin")return"macOS";if(e==="win32")return"Windows";if(e==="linux")return"Linux";return e||"this computer"}function qk(e,t){let r=Math.max(1,t),n=e2(e,r),o=n==="error"?"overloaded":n==="warning"?"busy":"not busy",i=n==="error"?`${r} cores are queued up \u2014 last minute ${Ym(e)}`:n==="warning"?`${r} cores nearly full \u2014 last minute ${Ym(e)}`:`${r} cores. Last minute ${Ym(e)} (under ${r} is fine)`;return{what:"CPU work",reading:o,meaning:i,tone:n,meter:jk(Nk(e,r))}}function Gk(e,t){let r=t2(e,t),n=`${Ta(e)} of ${Ta(t)}`,o=r==="error"?"Almost no RAM left for new work":r==="warning"?"RAM is getting tight":"RAM the computer can still give out",i=t>0?Math.max(0,(t-e)/t):0;return{what:"RAM leftover",reading:n,meaning:o,tone:r,meter:jk(i)}}function Kk(e){let t=e?.state??"STOPPED";if(t==="FAILED")return"crashed";if(t==="STOPPING")return"stopping";if(t==="STARTING"||t==="RESTARTING")return"starting";if(Aa(t))return"up";return"off"}function Vk(e){if(!e||!Aa(e.state))return"\u2014";if(e.health==="HEALTHY")return"ready";if(e.health==="UNHEALTHY")return"failing";if(e.state==="STARTING"||e.state==="RESTARTING")return"waiting";return"checking"}function Yk(e){if(e==="keychain")return"password store";if(e==="file")return"local file";return e||"unknown store"}function Jk(e,t){let r=[{what:"Started",reading:String(e.live),meaning:e.live===0?"nothing is running yet":"process is up",tone:e.live>0?"success":"muted"}];if(t)r.push({what:"Ready",reading:String(e.healthy),meaning:e.live===0?"start services first":"passed their health check",tone:e.live>0&&e.healthy<e.live?"warning":e.healthy>0?"success":"muted"});if(e.starting>0)r.push({what:"Still starting",reading:String(e.starting),meaning:"not ready for traffic yet",tone:"warning"});if(e.stopping>0)r.push({what:"Stopping",reading:String(e.stopping),meaning:"shutting down",tone:"warning"});return r.push({what:"Crashed",reading:String(e.failed),meaning:e.failed>0?"open the service for the error":"none",tone:e.failed>0?"error":"muted"}),r.push({what:"Not started",reading:String(e.stopped),meaning:e.stopped>0?"off until you start them":"all are up",tone:"muted"}),r}var VN=0.85,YN=1.5,JN=0.2,XN=0.1,QN=5,La="\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588",n2=52,o2=64,i2=72,s2=82,a2=90,l2=100,c2=2,u2=2,d2=2,p2=1,ku=8,Jm=8,f2=22,Xm=6,m2=28,wu=12,is=2,h2=10,g2=18,v2;var Su=A(()=>{nt();Ut();v2=new Set(["http","tcp","command"])});import{useEffect as y2,useRef as b2}from"react";import{jsxDEV as be,Fragment as x2}from"@opentui/react/jsx-dev-runtime";function w2(e,t){switch(t){case"primary":return{bg:e.primary,fg:ei(e.primary,e.inverse)};case"accent":return{bg:e.accent,fg:Yc(e)?Vc:ei(e.accent,e.inverse)};case"success":return{bg:e.success,fg:ei(e.success,e.inverse)};case"warning":return{bg:e.warning,fg:Yc(e)?Vc:ei(e.warning,e.inverse)};case"error":return{bg:e.error,fg:ei(e.error,e.inverse)};case"info":return{bg:e.info,fg:ei(e.info,e.inverse)};case"muted":return{bg:e.element,fg:e.text};case"ghost":return{bg:e.element,fg:e.muted};default:return{bg:e.element,fg:e.text}}}function Xk(e){let{palette:t,dir:r}=e;return be("box",{width:2,height:1,flexShrink:0,overflow:"hidden",children:be("text",{fg:t.muted,children:r==="left"?"\u2039":"\u203A"},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Zt(e){let{palette:t,children:r,backgroundColor:n,edge:o="bottom"}=e,i=ye(),s=e.ruled??!Ln(i),a=n??t.element,l=be("box",{flexShrink:0,flexDirection:"column",backgroundColor:a,overflow:"hidden",children:r},void 0,!1,void 0,this);if(!s)return l;return be("box",{flexShrink:0,flexDirection:"column",overflow:"hidden",border:[...o==="both"?["top","bottom"]:[o]],borderStyle:"single",borderColor:t.border,children:l},void 0,!1,void 0,this)}function Cu(e){let{palette:t,items:r,active:n,width:o,onPick:i,emphasis:s="ghost"}=e,a=r.map((d)=>ts(d.label)),l=ek(a,n,Math.max(1,o)),c=l.start>0,u=l.end>=0&&l.end<r.length-1;return be("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[c?be(Xk,{palette:t,dir:"left"},void 0,!1,void 0,this):null,r.map((d,f)=>{if(f<l.start||f>l.end)return null;let p=f===n,m=s==="fill"&&p;return be(Ue,{palette:t,label:d.label,tone:m?"primary":"ghost",bg:m?void 0:p?t.highlight:t.element,fg:m?void 0:p?t.primary:d.color??t.muted,onMouseDown:()=>i(f)},d.id,!1,void 0,this)}),u?be(Xk,{palette:t,dir:"right"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function Ue(e){let{palette:t,label:r,tone:n="idle",fg:o,bg:i,onMouseDown:s}=e,a=w2(t,n);return be("box",{height:1,paddingLeft:1,paddingRight:1,backgroundColor:i??a.bg,overflow:"hidden",flexShrink:0,onMouseDown:s,children:be("text",{fg:o??a.fg,children:r},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function mt(e){let{palette:t,hints:r}=e;return be("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:r.map((n)=>be("box",{height:1,paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:be("text",{wrapMode:"none",children:[be("span",{fg:t.primary,children:n.key},void 0,!1,void 0,this),be("span",{fg:t.muted,children:` ${n.label}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},`${n.key}-${n.label}`,!1,void 0,this))},void 0,!1,void 0,this)}function wt(e){let{palette:t,items:r,hints:n,ruled:o=!0}=e,i=be("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[r.map((s,a)=>be(Ue,{palette:t,label:s.text,tone:s.tone,onMouseDown:s.onMouseDown},`${s.text}-${a}`,!1,void 0,this)),n&&n.length>0?be(x2,{children:[be("box",{flexGrow:1,backgroundColor:t.element},void 0,!1,void 0,this),be(mt,{palette:t,hints:n},void 0,!1,void 0,this)]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this);if(!o)return i;return be(Zt,{palette:t,backgroundColor:t.element,children:i},void 0,!1,void 0,this)}function ot(e){let{palette:t,title:r,termW:n,termH:o,preferW:i,preferH:s,anchor:a="center",borderColor:l,bottomTitle:c,gap:u,children:d}=e,f=Ln(ye()),p=ns(n,o,i,s,a,!f);return be("box",{position:"absolute",left:p.left,top:p.top,width:p.width,height:p.height,border:!0,borderStyle:eh,borderColor:l??t.borderActive,backgroundColor:t.panel,padding:f?0:1,title:r,titleColor:t.primary,bottomTitle:c,gap:f?0:u,flexDirection:"column",overflow:"hidden",children:d},void 0,!1,void 0,this)}function Me(e){return{rootOptions:{flexGrow:1,height:"100%",overflow:"hidden",backgroundColor:e.panel},viewportOptions:{backgroundColor:e.panel},contentOptions:{backgroundColor:e.panel},scrollbarOptions:{trackOptions:{foregroundColor:e.primary,backgroundColor:e.element}}}}function je(e,t){if(!e)return;e.scrollBy({x:0,y:t})}function ss(e,t){let r=b2(null);return y2(()=>{let n=r.current;if(!n||e<0)return;let o=requestAnimationFrame(()=>{n.scrollChildIntoView(`${t}-${e}`)});return()=>cancelAnimationFrame(o)},[t,e]),r}function At(e){let t=ye(),r=Sa(t),n=e.scroll?be("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Me(e.palette),children:be("box",{flexDirection:"column",overflow:"hidden",children:e.children},void 0,!1,void 0,this)},void 0,!1,void 0,this):e.children;return be("box",{flexGrow:1,border:!0,borderStyle:eh,borderColor:e.borderColor??e.palette.border,title:e.title,titleColor:e.palette.primary,paddingLeft:t.pad,paddingRight:t.pad,paddingTop:r?0:t.pad,paddingBottom:r?0:t.pad,backgroundColor:e.palette.panel,flexDirection:"column",overflow:"hidden",children:n},void 0,!1,void 0,this)}function ai(e){let{palette:t,label:r,value:n,tone:o="text"}=e,i=ye(),s=o==="success"?t.success:o==="warning"?t.warning:o==="error"?t.error:o==="muted"?t.muted:t.text;return be("box",{height:i.rowH,flexDirection:"row",overflow:"hidden",children:[be("box",{width:14,flexShrink:0,overflow:"hidden",children:be("text",{fg:t.muted,children:j(r,14)},void 0,!1,void 0,this)},void 0,!1,void 0,this),be("box",{flexGrow:1,overflow:"hidden",children:be("text",{fg:s,wrapMode:"none",children:n},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Tu(e){let{palette:t,title:r,body:n,hint:o}=e;return be("box",{paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",border:!0,borderStyle:eh,borderColor:t.borderActive,titleColor:t.primary,children:[be("text",{fg:t.primary,children:r},void 0,!1,void 0,this),be("text",{fg:t.text,wrapMode:"word",children:n},void 0,!1,void 0,this),o?be("text",{fg:t.muted,wrapMode:"word",children:o},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var eh="rounded";var Re=A(()=>{Ht();wr();nt();so();Mr();rt()});import{jsxDEV as Be,Fragment as S2}from"@opentui/react/jsx-dev-runtime";function Zk(e){let{palette:t,cfg:r,snap:n,google:o,profile:i,reveal:s,width:a}=e,l=xu(n,r?Object.keys(r.services):void 0),c=n?.proxy.running===!0,u=o?.adcAvailable===!0,d=a<vu,f=ke(r?.project.name||"local",d?18:22),p=ke(i||n?.profile||"no profile",16),m=ak({width:a,running:l.running,total:l.total,proxyOn:c,proxyAddress:n?.proxy.address??"",mcpOn:n?.mcp?.running===!0,adc:u,reveal:s}).filter((w)=>!w.hide&&w.label!=="").map((w)=>Be(Ue,{palette:t,label:w.label,tone:w.tone},w.label,!1,void 0,this)),h=Sa(ye()),g=Be("box",{height:1,flexGrow:1,overflow:"hidden",backgroundColor:t.panel,paddingLeft:1,children:Be("text",{wrapMode:"none",children:[Be("span",{fg:t.primary,children:vr()},void 0,!1,void 0,this),Be("span",{fg:t.muted,children:` ${f}`},void 0,!1,void 0,this),Be("span",{fg:t.accent,children:` ${p}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this);return Be(Zt,{palette:t,backgroundColor:t.panel,ruled:!h,children:Be("box",{height:d?2:1,flexDirection:"column",backgroundColor:t.panel,overflow:"hidden",children:[Be("box",{height:1,flexDirection:"row",overflow:"hidden",children:[g,d?null:m]},void 0,!0,void 0,this),d?Be("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.panel,children:m},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function eS(e){let{palette:t,screen:r,width:n,onSelect:o}=e,i=n>=Qk+k2,s=i?Math.max(1,n-Qk):n,a=oi.map((c)=>({id:c.id,label:Z0(c.label,s)})),l=tk(r);return Be(Zt,{palette:t,backgroundColor:t.element,children:Be("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[Be(Cu,{palette:t,items:a,active:l,width:s,onPick:(c)=>{let u=oi[c];if(u)o(u.id)}},void 0,!1,void 0,this),i?Be(S2,{children:[Be("box",{flexGrow:1,backgroundColor:t.element},void 0,!1,void 0,this),Be(mt,{palette:t,hints:[Nr]},void 0,!1,void 0,this)]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function tS(e){let{palette:t,screen:r,overlay:n,status:o,paused:i,errorOnly:s,width:a,copyKey:l}=e,c=Sa(ye()),u=Math.max(18,Math.floor(a*0.42)),d=lk(Ik(r,n,l),u),f=ck(o);return Be(Zt,{palette:t,backgroundColor:t.panel,edge:"top",ruled:!c,children:Be("box",{height:1,backgroundColor:t.panel,overflow:"hidden",children:Be(wt,{ruled:!1,palette:t,items:[{text:r,tone:"ghost"},{text:i?"PAUSED":"LIVE",tone:i?"warning":"success"},...s?[{text:"ERROR+",tone:"error"}]:[],...o===""?[]:[{text:ke(o,Math.max(16,a-u-28)),tone:f}]],hints:d},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function it(e){return Be("box",{flexGrow:1,padding:1,overflow:"hidden",children:Be(Tu,{palette:e.palette,title:e.title,body:e.body,hint:e.hint},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Eu(e){return Be("box",{flexGrow:1,padding:1,overflow:"hidden",children:Be("text",{fg:e.palette.text,children:e.label},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function rS(e){return Be("box",{flexGrow:1,padding:1,flexDirection:"column",overflow:"hidden",children:[Be("text",{fg:e.palette.error,children:e.title},void 0,!1,void 0,this),Be("text",{fg:e.palette.text,wrapMode:"word",children:e.body},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Qk,k2=8;var cr=A(()=>{Ht();wr();si();nt();so();Su();Re();Mr();Qk=Nr.key.length+Nr.label.length+3});function C2(){if(process.platform==="darwin")return[["pbcopy"]];if(process.platform==="win32")return[["clip"]];return[["wl-copy"],["xclip","-selection","clipboard"],["xsel","--clipboard","--input"]]}function T2(){return C2().filter((e)=>{let t=e[0];return typeof t==="string"&&Bun.which(t)!==null})}function E2(e){return`\x1B]52;c;${Buffer.from(e,"utf8").toString("base64")}\x07`}function nS(){if(process.platform==="linux")return"install wl-clipboard (Wayland) or xclip (X11)";return"no clipboard helper found"}async function Ru(e){let t=T2(),r;for(let n of t)try{await _2(n,e);return}catch(o){r=o instanceof Error?o:Error(String(o))}if(process.platform!=="win32")try{await R2(e);return}catch(n){r=n instanceof Error?n:Error(String(n))}throw Ie($e,"clipboard unavailable",r?`${nS()} (${r.message})`:nS())}async function R2(e){let t=E2(e);try{await Bun.write("/dev/tty",t)}catch{if(!process.stderr.write(t))throw Error("terminal clipboard write failed")}}async function _2(e,t){let r=Bun.spawn(e,{stdin:"pipe",stdout:"ignore",stderr:"ignore"});r.stdin.write(t),await r.stdin.end();let n=await r.exited;if(n!==0)throw Error(`${e[0]} exited ${n}`)}var th=A(()=>{ne()});function lh(e){let t=Math.min(e.startUnixNano,e.endUnixNano),r=Math.max(e.startUnixNano,e.endUnixNano);return Math.max(0,(r-t)/qt)}function li(e){if(!Number.isFinite(e)||e<0)return"0ms";if(e>0&&e<1)return`${e.toFixed(1)}ms`;if(e<lS)return`${Math.round(e)}ms`;return`${(e/lS).toFixed(2)}s`}function pS(e){if(e==="server")return"\u25C0";if(e==="client")return"\u25B6";if(e==="producer")return"\u25B2";if(e==="consumer")return"\u25BC";return"\u25CF"}function ch(e){return`${pS(e)} ${e}`}function fS(e){if(e==="error")return"ERR";if(e==="ok")return"ok";return"\u2014"}function Pu(e){let t=new Map,r=new Set(e.spans.map((s)=>s.spanId));for(let s of e.spans){let a=s.parentSpanId&&r.has(s.parentSpanId)?s.parentSpanId:"",l=t.get(a)??[];l.push(s),t.set(a,l)}for(let s of t.values())s.sort((a,l)=>a.startUnixNano-l.startUnixNano||a.seq-l.seq);let n=[],o=new Set;oh(t,"",0,o,n);let i=[...e.spans].filter((s)=>!o.has(s.seq)).sort((s,a)=>s.startUnixNano-a.startUnixNano||s.seq-a.seq);for(let s of i)if(!o.has(s.seq))o.add(s.seq),n.push({span:s,depth:0}),oh(t,s.spanId,1,o,n);return n}function oh(e,t,r,n,o){let i=(e.get(t)??[]).filter((s)=>!n.has(s.seq));for(let s of i)n.add(s.seq),o.push({span:s,depth:Math.min(r,cS)}),oh(e,s.spanId,r+1,n,o)}function mS(e){if(e.spans.length===0)return{durationMs:0,spanCount:0,serviceCount:0,errorCount:0,services:[],startUnixNano:0,endUnixNano:0};let t=Math.min(e.spans[0].startUnixNano,e.spans[0].endUnixNano),r=Math.max(e.spans[0].startUnixNano,e.spans[0].endUnixNano),n=[],o=0;for(let i of e.spans){let s=Math.min(i.startUnixNano,i.endUnixNano),a=Math.max(i.startUnixNano,i.endUnixNano);if(s<t)t=s;if(a>r)r=a;let l=i.resource["service.name"];if(typeof l==="string"&&l!==""&&!n.includes(l))n.push(l);if(i.status.code==="error")o+=1}return{durationMs:Math.max(0,(r-t)/qt),spanCount:e.spans.length,serviceCount:n.length,errorCount:o,services:n,startUnixNano:t,endUnixNano:r}}function hS(e){return e.reduce((t,r)=>Math.max(t,r.depth),0)}function gS(e){return e.reduce((t,r)=>{let n=typeof r.span.resource["service.name"]==="string"?r.span.resource["service.name"]:"";return Math.max(t,n.length)},7)}function B2(e){let t=Math.max(0,Math.min(cS,e));return uS+dS+t*nh}function vS(e,t=0,r=iS){let n=Math.max(2,B2(t)),o=A2,i=e>=90?D2:e>=70?O2:iS,s=Math.max(oS,Math.min(i,r)),a=e>=sS?M2:N2,l=e>=sS?F2:$2,c=e-n-s-o;if(c<a+l){let m=a+l-c;s=Math.max(oS,s-m)}let u=Math.max(2,e-n-s-o),d=Math.max(l,Math.round(u*H2)),f=u-d;if(f<a)f=Math.min(a,Math.max(1,u-l)),d=Math.max(1,u-f);let p=n+s+o+f+d;if(p<e)d+=e-p;return{tree:n,service:s,name:Math.max(1,f),duration:o,bar:Math.max(1,d)}}function yS(e){return e.tree+e.service+e.name+e.duration}function bS(e,t,r=P2,n=!1){let o=Math.max(0,Math.floor((r-uS-dS)/nh)),i=Math.min(Math.max(0,e),o)*nh,s=`${n?"\u25B8":" "}${" ".repeat(i)}${pS(t)}`;return j(s,r)}function wS(e,t,r){if(r<=0)return{offset:0,width:1};let n=Math.min(e.startUnixNano,e.endUnixNano),o=Math.max(e.startUnixNano,e.endUnixNano),i=_u((n-t)/r),s=_u((o-t)/r);return{offset:i,width:Math.max(0,s-i)}}function W2(e,t,r){if(r<=0)return{start:0,end:0};let n=_u(e),o=_u(e+t),i=Math.floor(n*r),s=Math.ceil(o*r);if(s<=i)s=i+1;return i=Math.max(0,Math.min(r-1,i)),s=Math.max(i+1,Math.min(r,s)),{start:i,end:s}}function xS(e,t,r){if(r<=0)return{lead:"",fill:"",trail:""};let{start:n,end:o}=W2(e,t,r);return{lead:"\u2591".repeat(n),fill:"\u2588".repeat(o-n),trail:"\u2591".repeat(r-o)}}function kS(e,t){if(t<=0)return"";let r="0",n=li(e/2),o=li(e);if(t<r.length+n.length+o.length+2)return z2(o,t);let i=Math.max(r.length+1,Math.floor((t-n.length)/2)),s=Array.from({length:t},()=>"\u2500");return rh(s,0,r),rh(s,i,n),rh(s,t-o.length,o),s.join("")}function SS(e){return{tree:j("",e.tree),service:j("SERVICE",e.service),name:j("SPAN",e.name),duration:j("DUR",e.duration),bar:j("TIME",e.bar)}}function Au(e,t){if(t<=0)return 0;return Math.max(0,Math.min(t-1,e))}function CS(e,t,r,n,o=I2){return e===r&&n-t<=o}function TS(e,t){return Math.max(0,(t-e.startUnixNano)/qt)}function ES(e){let t=e.spanCount===1?"1 span":`${e.spanCount} spans`,r=e.serviceCount===1?"1 service":`${e.serviceCount} services`,n=e.errorCount===0?"no errors":e.errorCount===1?"1 error":`${e.errorCount} errors`;return[{id:"dur",label:li(e.durationMs),tone:"primary"},{id:"spans",label:t,tone:"ghost"},{id:"svc",label:r,tone:"ghost"},{id:"err",label:n,tone:e.errorCount===0?"success":"error"}]}function RS(e,t){let r=[],n=0;for(let i of e){let s=i.label.length+aS;if(n+s>t)break;r.push(i),n+=s}if(r.length>0)return r;let o=e[0];return o?[{...o,label:ke(o.label,Math.max(1,t-aS))}]:[]}function _S(e,t){if(e.length===0||t<=0)return"";return ke(e.join(" \xB7 "),t)}function PS(e){return ke(L2,e)}function AS(e,t){return{w:Math.max(ih,e-2),h:Math.max(sh,t-1)}}function LS(e,t){let r=t>=U2,n=t>=j2,o=1+(r?1:0)+(n?1:0);return{listWidth:e,headerLines:o,showServices:r,showLegend:n,listHeight:Math.max(6,t-o)}}function _u(e){if(!Number.isFinite(e))return 0;return Math.min(1,Math.max(0,e))}function rh(e,t,r){for(let n=0;n<r.length;n+=1){let o=t+n;if(o>=0&&o<e.length)e[o]=r[n]??"\u2500"}}function z2(e,t){if(e.length>=t)return e.slice(0,t);return e.padStart(t)}var ih=64,sh=16,P2=6,A2=7,ah=5,L2="\u25C0 server \u25B6 client \u25CF internal \u25B2 producer \u25BC consumer",I2=400,cS=16,nh=2,uS=1,dS=1,oS=6,D2=16,O2=14,iS=10,M2=12,N2=6,F2=14,$2=8,H2=0.55,sS=56,aS=2,U2=20,j2=16,lS=1000;var Lu=A(()=>{nt()});function uh(e){return e==="slash"||e==="config-edit"||e==="setup-wizard"}function IS(e,t){return Hn(e,t.keybinds.leader??hi("x"))}function DS(e,t){return Hn(e,t.keybinds.command_list??hi("p"))}function fn(e,t){return Hn(e,t.keybinds.command??"/")||e.name==="/"}function OS(e,t){return Hn(e,t.keybinds.help??"?")||e.sequence==="?"}function MS(e,t){return Hn(e,t.keybinds.search??"f")}function NS(e){return(e.name??"").toLowerCase()==="q"&&!e.ctrl&&!e.meta&&!e.super&&!e.alt&&!e.option}function FS(e){let t=e.name??"";return t==="R"||e.shift===!0&&t.toLowerCase()==="r"}function $S(e){return rn(e)&&(e.name??"").toLowerCase()==="l"}function HS(e,t){return Hn(e,t.keybinds.copy??kn())}function US(e,t,r=q2){return t>0&&e-t<=r}function lo(e,t,r,n){return Hn(e,t.keybinds[r]??n)}function as(e){let t=(e.name??"").toLowerCase();return t==="pagedown"||rn(e)&&t==="d"}function ls(e){let t=(e.name??"").toLowerCase();return t==="pageup"||rn(e)&&t==="u"}var q2=2000;var Iu=A(()=>{Vr()});function cs(e){return`http://127.0.0.1:${e}/mcp`}function dh(e){if(e==="")return{};return{Authorization:`Bearer ${e}`}}function ph(e,t){return JSON.stringify({mcpServers:{devctl:{type:"http",url:e,headers:dh(t)}}},null,2)}function fh(e,t){return JSON.stringify({mcpServers:{devctl:{url:e,headers:dh(t)}}},null,2)}function mh(e,t){return JSON.stringify({mcp:{devctl:{type:"remote",url:e,headers:dh(t),enabled:!0}}},null,2)}function hh(e,t){let r=t===""?"":`
|
|
2477
2483
|
http_headers = { Authorization = "Bearer ${t}" }`;return`[mcp_servers.devctl]
|
|
2478
2484
|
url = "${e}"${r}
|
|
2479
|
-
`}function
|
|
2480
|
-
`)}import{jsxDEV as Y}from"@opentui/react/jsx-dev-runtime";function yh(){return am.flatMap((e)=>ma.filter((t)=>t.category===e))}function Ou(){return Du+yh().length}function WS(){return Ou()+BS}function Da(e){if(e<Du||e>=Ou())return;return yh()[e-Du]}function bh(e){let t=e-Ou();return t>=0&&t<BS?t:void 0}function zS(e){let{palette:t,snap:r,port:n,portDraft:o="",selected:i,onPick:s,onToggle:a,onCopy:l,onToggleTool:c}=e,u=ye(),d=r?.mcp?.running===!0,f=r?.mcp?.port??n,p=r?.mcp?.address??cs(f),m=r?.mcp?.token??"",h=Ia(p,m),g=r?.mcp?.disabled_tools??[],w=yh(),v=w.filter((_)=>!no(_.name,g)).length,S=h[bh(i)??-1],E=S??h[0];return Y(Pt,{palette:t,title:"mcp settings",children:[Y(wt,{palette:t,items:[{text:d?"RUNNING":"STOPPED",tone:d?"success":"idle"},{text:`127.0.0.1:${f}`,tone:"info"}]},void 0,!1,void 0,this),Y("box",{flexGrow:1,overflow:"hidden",children:Y("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:Y("box",{flexDirection:"column",overflow:"hidden",children:[Y(hh,{palette:t,text:"Server"},void 0,!1,void 0,this),Y(jS,{palette:t,active:i===gh,rowH:u.rowH,label:"Listen",value:d?"[ ON ]":"[ OFF ]",valueTone:d?"success":"muted",hint:d?"space or enter stop":"space or enter start",onPick:()=>s(gh),onActivate:a},void 0,!1,void 0,this),Y(jS,{palette:t,active:i===vh,rowH:u.rowH,label:"Port",value:`\u2039 ${o===""?n:o} \u203A`,valueTone:"info",hint:o===""?"\u2190 \u2192 change type digits enter apply":"typing\u2026 enter apply \u232B erase",onPick:()=>s(vh)},void 0,!1,void 0,this),Y("box",{height:1,overflow:"hidden",children:Y("text",{fg:t.muted,wrapMode:"none",children:d?"Listening on loopback. Agents use the URL and token in the JSON below.":"Server is stopped. Highlight Listen and press space to start it."},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y(hh,{palette:t,text:"Tools",extra:v===0?"all enabled":`${v} disabled`},void 0,!1,void 0,this),Y("box",{height:1,overflow:"hidden",children:Y("text",{fg:t.muted,wrapMode:"none",children:"Disabled tools are hidden from agents and refused if called anyway."},void 0,!1,void 0,this)},void 0,!1,void 0,this),am.map((_)=>{let y=w.filter((b)=>b.category===_);if(y.length===0)return null;return Y("box",{flexDirection:"column",overflow:"hidden",children:[Y("box",{height:1,marginTop:1,overflow:"hidden",children:Y("text",{fg:t.muted,wrapMode:"none",children:$2[_]??_},void 0,!1,void 0,this)},void 0,!1,void 0,this),y.map((b)=>{let k=Du+w.indexOf(b);return Y(j2,{palette:t,tool:b,enabled:no(b.name,g),active:i===k,rowH:u.rowH,onPick:()=>s(k),onToggle:()=>c(b)},b.name,!1,void 0,this)})]},_,!0,void 0,this)}),Y(hh,{palette:t,text:"Copy agent config",extra:"highlight a row, then enter or click Copy"},void 0,!1,void 0,this),h.map((_,y)=>{let b=Ou()+y;return Y(U2,{palette:t,snippet:_,active:i===b,rowH:u.rowH,onPick:()=>s(b),onCopy:()=>l(_)},_.kind,!1,void 0,this)}),Y(B2,{palette:t,snippet:E,selected:Boolean(S),brand:E?Jc(E.kind,t):t.muted},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y(Zt,{palette:t,backgroundColor:t.element,edge:"top",children:Y(mt,{palette:t,hints:H2(i,d)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function H2(e,t){if(e===gh)return[{key:"space",label:t?"stop server":"start server"},{key:"j/k",label:"move"}];if(e===vh)return[{key:"\u2190\u2192",label:"change port"},{key:"0-9",label:"type port"},{key:"enter",label:"apply port"},{key:"j/k",label:"move"}];if(Da(e))return[{key:"space",label:"enable / disable"},{key:"enter",label:"enable / disable"},{key:"j/k",label:"move"}];return[{key:"enter",label:"copy JSON"},{key:"space",label:"copy JSON"},{key:"j/k",label:"move"}]}function hh(e){let t=e.extra?` \xB7 ${e.extra}`:"";return Y("box",{height:1,marginTop:1,overflow:"hidden",children:Y("text",{wrapMode:"none",children:[Y("span",{fg:e.palette.primary,children:e.text},void 0,!1,void 0,this),Y("span",{fg:e.palette.muted,children:t},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function jS(e){let{palette:t,active:r,rowH:n,label:o,value:i,valueTone:s,hint:a,onPick:l,onActivate:c}=e,u=s==="success"?t.success:s==="info"?t.info:t.muted;return Y("box",{height:n,flexDirection:"row",overflow:"hidden",backgroundColor:r?t.highlight:t.panel,onMouseDown:()=>{if(r&&c){c();return}l()},children:[Y("box",{width:2,flexShrink:0,overflow:"hidden",children:Y("text",{fg:t.primary,children:r?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:us,flexShrink:0,overflow:"hidden",children:Y("text",{fg:r?t.primary:t.text,wrapMode:"none",children:j(o,us)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:US,flexShrink:0,overflow:"hidden",children:Y("text",{fg:u,wrapMode:"none",children:j(i,US)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{flexGrow:1,overflow:"hidden",children:Y("text",{fg:r?t.text:t.muted,wrapMode:"none",children:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function U2(e){let{palette:t,snippet:r,active:n,rowH:o,onPick:i,onCopy:s}=e,a=Jc(r.kind,t),l=h0(r.kind,t),c=r.language==="toml"?"Copy TOML":"Copy JSON";return Y("box",{height:o,flexDirection:"row",overflow:"hidden",backgroundColor:n?t.highlight:t.panel,onMouseDown:i,children:[Y("box",{width:2,flexShrink:0,overflow:"hidden",children:Y("text",{fg:a,children:n?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:us,flexShrink:0,overflow:"hidden",children:Y("text",{fg:a,wrapMode:"none",children:j(r.title,us)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{flexGrow:1,overflow:"hidden",children:Y("text",{fg:t.muted,wrapMode:"none",children:r.path},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y(Ue,{palette:t,label:c,bg:a,fg:l,onMouseDown:()=>{i(),s()}},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function j2(e){let{palette:t,tool:r,enabled:n,active:o,rowH:i,onPick:s,onToggle:a}=e;return Y("box",{height:i,flexDirection:"row",overflow:"hidden",backgroundColor:o?t.highlight:t.panel,onMouseDown:()=>{if(o){a();return}s()},children:[Y("box",{width:2,flexShrink:0,overflow:"hidden",children:Y("text",{fg:t.primary,children:o?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:5,flexShrink:0,overflow:"hidden",children:Y("text",{fg:n?t.success:t.muted,wrapMode:"none",children:n?" ON ":" OFF "},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:us+4,flexShrink:0,overflow:"hidden",children:Y("text",{fg:o?t.primary:n?t.text:t.muted,wrapMode:"none",children:j(r.label,us+4)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:7,flexShrink:0,overflow:"hidden",children:Y("text",{fg:r.mutates?t.warning:t.muted,wrapMode:"none",children:j(r.mutates?"write":"read",7)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{flexGrow:1,overflow:"hidden",children:Y("text",{fg:o?t.text:t.muted,wrapMode:"none",children:o?`space or enter ${n?"disable":"enable"} ${r.name}`:r.summary},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function B2(e){let{palette:t,snippet:r,selected:n,brand:o}=e;if(!r)return null;let i=r.hint?` \xB7 ${r.hint}`:"";return Y("box",{marginTop:1,flexDirection:"column",overflow:"hidden",children:[Y("text",{fg:o,wrapMode:"none",children:n?`${r.title} \xB7 paste into ${r.path}${i}`:`Preview ${r.title} \xB7 j/k to a copy row, then enter`},void 0,!1,void 0,this),Y("text",{fg:t.text,children:r.text},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var gh=0,vh=1,Du=2,BS=4,$2,us=14,US=14;var Oa=A(()=>{Ht();nt();Re();rt();Ji();$2={inspect:"Inspect",logs:"Logs",diagnostics:"Diagnostics",control:"Control",setup:"Setup"}});import{jsxDEV as We,Fragment as GS}from"@opentui/react/jsx-dev-runtime";function J2(e){return[{key:"\u2190\u2192",label:"filter services"},{key:"e",label:"ERROR+ only"},{key:"g",label:"jump to latest"},{key:"p",label:"pause stream"},{key:"z",label:"full-screen logs"},{key:"\\",label:"split panes"},{key:"|",label:"focus other pane"},{key:"/trace",label:"jump to request id"},{key:"f",label:"search"},{key:"t",label:"timestamps"},{key:"m",label:"metadata"},{key:"w",label:"wrap all / clip / wrap selected"},{key:"j/k",label:"move selection"},{key:wo(e),label:"copy selection"},{key:"/export",label:"write ~/.devctl/exports"},{key:"/exports",label:"open export folder"}]}function uo(e){return e+q2}function KS(e){let t=uo(xh.length),r=uo(kh.length),n=uo(e.logCount),o=uo(Sh.length),i=uo(Ch.length),s=Th+e.pad*2;if(e.stacked)return s+t+r+n+o+i+wh+(V2-1)*e.gap;let a=Math.max(t,r),l=Math.max(o,i);return s+a+n+l+wh+(Y2-1)*e.gap}function X2(e){return KS(e)-Th-e.pad*2}function Q2(e){return e-Th*2<z2}function VS(e){let{palette:t,termW:r,termH:n,copyKey:o=kn(),scrollRef:i}=e,s=Ln(ye()),a=Q2(r),l=s?0:1,c=s?0:1,u=J2(o),d={stacked:a,logCount:u.length,pad:l,gap:c},f=KS(d),p=X2(d);return We(ot,{palette:t,title:"help",bottomTitle:`${vr()} \xB7 j/k scroll \xB7 esc close`,termW:r,termH:n,preferW:W2,preferH:f,gap:0,children:We("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:We("box",{height:p,flexDirection:"column",flexShrink:0,overflow:"hidden",gap:c,children:[a?We(GS,{children:[We(co,{palette:t,title:"navigation",bindings:xh},void 0,!1,void 0,this),We(co,{palette:t,title:"services",bindings:kh},void 0,!1,void 0,this),We(co,{palette:t,title:"logs",bindings:u},void 0,!1,void 0,this),We(co,{palette:t,title:"commands",bindings:Sh},void 0,!1,void 0,this),We(co,{palette:t,title:"display",bindings:Ch},void 0,!1,void 0,this)]},void 0,!0,void 0,this):We(GS,{children:[We(qS,{palette:t,left:{title:"navigation",bindings:xh},right:{title:"services",bindings:kh}},void 0,!1,void 0,this),We(co,{palette:t,title:"logs",bindings:u},void 0,!1,void 0,this),We(qS,{palette:t,left:{title:"commands",bindings:Sh},right:{title:"display",bindings:Ch}},void 0,!1,void 0,this)]},void 0,!0,void 0,this),We("box",{height:wh,flexShrink:0,overflow:"hidden",paddingLeft:1,children:We("text",{fg:t.muted,wrapMode:"none",children:"~/.devctl/tui.json \xB7 DEVCTL_TUI_CONFIG"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function qS(e){let{palette:t,left:r,right:n}=e,o=Math.max(uo(r.bindings.length),uo(n.bindings.length));return We("box",{height:o,flexDirection:"row",flexShrink:0,overflow:"hidden",gap:K2,children:[We(co,{palette:t,title:r.title,bindings:r.bindings,height:o,stretch:!0},void 0,!1,void 0,this),We(co,{palette:t,title:n.title,bindings:n.bindings,height:o,stretch:!0},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function co(e){let{palette:t,title:r,bindings:n,stretch:o=!1}=e,i=e.height??uo(n.length),s=Z2(n);return We("box",{height:i,flexGrow:o?1:0,flexBasis:o?0:void 0,flexShrink:0,flexDirection:"column",overflow:"hidden",border:!0,borderStyle:"rounded",borderColor:t.border,title:r,titleColor:t.accent,children:n.map((a)=>We("box",{height:1,flexShrink:0,overflow:"hidden",paddingLeft:1,paddingRight:1,children:We(eF,{palette:t,binding:a,keyWidth:s},void 0,!1,void 0,this)},`${a.key}-${a.label}`,!1,void 0,this))},void 0,!1,void 0,this)}function Z2(e){return e.reduce((r,n)=>Math.max(r,n.key.length),0)+G2}function eF(e){let{palette:t,binding:r,keyWidth:n}=e;return We("box",{height:1,flexDirection:"row",overflow:"hidden",children:[We("box",{width:n,flexShrink:0,overflow:"hidden",children:We("text",{fg:t.primary,wrapMode:"none",children:j(r.key,n)},void 0,!1,void 0,this)},void 0,!1,void 0,this),We("box",{flexGrow:1,overflow:"hidden",children:We("text",{fg:t.text,wrapMode:"none",children:r.label},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var W2=78,z2=56,q2=2,Th=2,wh=1,Eh=8,G2=2,K2=2,V2=6,Y2=4,xh,kh,Sh,Ch;var Rh=A(()=>{Ht();nt();Re();Mr();Vr();xh=[{key:"tab",label:"next tab"},{key:"1-4",label:"dashboard services logs proxy"},{key:"s/l/a/p/d/c/u",label:"letter jump"},{key:"/",label:"command overlay \xB7 other screens"},{key:"j/k",label:"move selection"},{key:"esc",label:"back / close overlay"},{key:"esc \xD72",label:"quit"},{key:"q \xD72",label:"quit"}],kh=[{key:"enter",label:"start profile or open"},{key:"space",label:"multi-select"},{key:"n",label:"start"},{key:"x",label:"stop"},{key:"r",label:"refresh"},{key:"R",label:"restart (c cascade if dependents)"}];Sh=[{key:jt("c"),label:"copy highlighted selection"},{key:"/",label:"command overlay"},{key:jt("p"),label:"same overlay"},{key:jt("x"),label:"leader chord"},{key:"/settings",label:"preferences \xB7 MCP page"},{key:"/themes",label:"preview themes"},{key:"/diff",label:"config sources"},{key:"/mcp",label:"agent MCP server"}],Ch=[{key:jt("="),label:"larger"},{key:jt("-"),label:"smaller"},{key:"?",label:"this overlay"}]});function ci(e){e.setQuery(""),e.setSlashIndex(0),e.setSlashPicker("commands"),e.setOverlay("slash")}function YS(e,t){let{overlay:r,tui:n,height:o,closeOverlay:i,confirmKind:s,onQuit:a,confirmAction:l,planBusy:c,logDetailsScrollRef:u,traceScrollRef:d,traceDetailScrollRef:f,scrollTextScrollRef:p,routeDetailsScrollRef:m,planScrollRef:h,helpScrollRef:g,revertThemePreview:w,setPaletteIndex:v,setThemeName:S,paletteIndex:E,applyTheme:_,leaderTimer:y,setOverlay:b,runCommand:k,setConfigEditError:x,saveConfigBuffer:L,setSlashIndex:F,filtered:B,setQuery:K,slashIndex:V,submitSlash:X,advanceWizard:te}=e,R=(t.name??"").toLowerCase();if(r==="none")return!1;if(r==="setup-wizard"){if(R==="escape")return i(),!0;if(R==="return")return te?.(),!0;return ch(r)}if(r==="confirm"){if(R==="escape")return i(),!0;if(s==="quit"&&R==="d")return a(!0),!0;if(s==="quit"&&R==="k")return e.onDown(!0),!0;if(s==="restart-cascade"&&R==="c")return l("cascade"),!0;if(R==="return")l();return!0}if(r==="span-details"){if(fn(t,n))return ci(e),!0;if(R==="escape")return e.setOverlay("trace"),!0;if(R==="down"||R==="j")return je(f.current,n.scroll_speed),!0;if(R==="up"||R==="k")return je(f.current,-n.scroll_speed),!0;if(as(t))return je(f.current,ao(o)),!0;if(ls(t))return je(f.current,-ao(o)),!0;return!0}if(r==="log-details"||r==="scroll-text"||r==="trace"){if(fn(t,n))return ci(e),!0;if(R==="escape")return i(),!0;if(r==="log-details"&&R==="return"){let O=e.logDetail?.traceId?.trim()??"";if(O!=="")return e.openTrace(O),!0;let ae=e.logDetail?Ei(e.logDetail).trim():"";if(ae!=="")e.setLogSearch(ae),e.setScreen("logs"),e.closeOverlay(),e.setStatus(`tracing ${ae}`);return!0}if(r==="trace"&&R==="return")return e.openSpanLogs(),!0;if(r==="trace"&&(R==="down"||R==="j"))return e.setTraceSpanIndex((O)=>Math.min(Math.max(0,e.traceSpanCount-1),O+1)),!0;if(r==="trace"&&(R==="up"||R==="k"))return e.setTraceSpanIndex((O)=>Math.max(0,O-1)),!0;let U=r==="log-details"?u.current:r==="trace"?d.current:p.current;if(r!=="trace"&&(R==="down"||R==="j"))return je(U,n.scroll_speed),!0;if(r!=="trace"&&(R==="up"||R==="k"))return je(U,-n.scroll_speed),!0;if(as(t)){if(r==="trace")return e.setTraceSpanIndex((O)=>Math.min(Math.max(0,e.traceSpanCount-1),O+sh)),!0;return je(U,ao(o)),!0}if(ls(t)){if(r==="trace")return e.setTraceSpanIndex((O)=>Math.max(0,O-sh)),!0;return je(U,-ao(o)),!0}return!0}if(r==="route-details"){if(fn(t,n))return ci(e),!0;if(R==="escape"||R==="return")return i(),!0;if(R==="down"||R==="j")return je(m.current,n.scroll_speed),!0;if(R==="up"||R==="k")return je(m.current,-n.scroll_speed),!0;return!0}if(r==="plan"){if(fn(t,n))return ci(e),!0;if(R==="escape"||R==="return"&&!c)return i(),!0;if(R==="down"||R==="j")return je(h.current,n.scroll_speed),!0;if(R==="up"||R==="k")return je(h.current,-n.scroll_speed),!0;return!0}if(r==="help"){if(fn(t,n))return ci(e),!0;if(R==="escape")return i(),!0;if(R==="down"||R==="j")return je(g.current,1),!0;if(R==="up"||R==="k")return je(g.current,-1),!0;if(R==="pagedown"||as(t))return je(g.current,Eh),!0;if(R==="pageup"||ls(t))return je(g.current,-Eh),!0;return!0}if(r==="themes"){if(fn(t,n))return w(),ci(e),!0;if(R==="escape")return w(),i(),!0;if(R==="down"||R==="j")return v((U)=>{let O=Math.min(U+1,_t.length-1),ae=_t[O];if(ae)S(ae);return O}),!0;if(R==="up"||R==="k")return v((U)=>{let O=Math.max(0,U-1),ae=_t[O];if(ae)S(ae);return O}),!0;if(R==="return"){let U=_t[E%_t.length];if(U)_(U)}return!0}if(r==="leader"){if(fn(t,n)){if(y.current)clearTimeout(y.current);return ci(e),!0}if(y.current)clearTimeout(y.current);b("none");let U=gk(R),O=U?pn(U):void 0;if(O)k(O,[]);return!0}if(r==="config-edit"){if(R==="escape")return x(""),i(),!0;if(rn(t)&&R==="s")return L(),!0;return!0}if(ch(r)){if(R==="escape")return i(),!0;if(r==="slash"&&R==="down")return F((U)=>Math.min(Math.max(B.length-1,0),U+1)),!0;if(r==="slash"&&R==="up")return F((U)=>Math.max(0,U-1)),!0;if(r==="slash"&&R==="tab"){if(t.shift)return F((O)=>Math.max(0,O-1)),!0;let U=os(B,V);if(U)K(Rk(U));return!0}if(r==="slash"&&R==="return")return X(),!0;return!0}return!0}var JS=A(()=>{Lu();wr();si();Iu();Vr();Re();Rh();rt();sn()});var Mu=A(()=>{Gf()});function XS(e,t){if(t.length===0)return[];let r=new Set(t);return Go(e,t).filter((n)=>!r.has(n))}function QS(e,t,r){let n=r!==""&&e.profiles[r]?r:"";if(t.length>0)return{services:t,profile:n};if(n!=="")return{services:[...e.profiles[r]?.services??[]],profile:n};return{services:Object.keys(e.services),profile:""}}function Nu(e){return e.waves.flat().join(" \u2192 ")}function ZS(e){let t=Nu(e);if(t==="")return"Started selected services";return`Started ${t}`}function eC(e){let t=Nu(e);if(t==="")return"Stopped running services";return`Stopped ${t}`}function tC(e,t,r,n="start"){let o=r?.services[e],i=yr(o);if(o?.last_error&&n!=="stop")return o.last_error;if(n==="stop"){if(i==="STOPPED")return"stopped";if(i==="STOPPING")return"stopping now";if(i==="FAILED")return"already failed";return"queued"}if(i==="HEALTHY")return"ready";if(i==="STARTING")return"starting now";if(i==="RUNNING")return"up, waiting for health";if(i==="UNHEALTHY")return"unhealthy \u2014 retrying health check";if(i==="STOPPING")return"stopping first";if(i==="FAILED")return"failed \u2014 later waves will not start";let a=(t.steps.find((l)=>l.name===e)?.dependencies??[]).filter((l)=>{let c=yr(r?.services[lr(l)]);return zn(l)==="service_healthy"?c!=="HEALTHY":c==="STOPPED"||c==="FAILED"}).map(lr);if(a.length>0)return`waits for ${a.join(", ")}`;return"queued"}function Ma(e,t,r="start"){if(e.length===0)return"completed";let n=e.map((i)=>t?.services[i]);if(n.some((i)=>i?.state==="FAILED"))return"failed";if(r==="stop"){if(n.every((i)=>!i||i.state==="STOPPED"||i.state==="UNKNOWN"))return"completed";if(n.some((i)=>i?.state==="STOPPING"))return"active";return"queued"}let o=(i)=>Boolean(i&&(i.state==="HEALTHY"||i.health==="HEALTHY"||i.state==="RUNNING"&&i.health!=="UNHEALTHY"));if(n.every(o))return"completed";if(n.some((i)=>i?.state==="UNHEALTHY"||i?.health==="UNHEALTHY"))return"unhealthy";if(n.some((i)=>i?.state==="STARTING"||i?.state==="RUNNING"||i?.state==="RESTARTING"))return"active";return"queued"}function rC(e,t,r="start"){let o=e.waves.flat().length,i=0,s=0,a=0,l=0;for(let m=0;m<e.waves.length;m++){let h=e.waves[m]??[],g=Ma(h,t,r);if(g==="active"||g==="unhealthy"||g==="failed")l=m;else if(g==="completed"&&l===m&&m<e.waves.length-1)l=m+1;for(let w of h){let v=t?.services[w];if(r==="stop"?!v||v.state==="STOPPED"||v.state==="UNKNOWN":Boolean(v&&(v.state==="HEALTHY"||v.health==="HEALTHY"||v.state==="RUNNING"&&v.health!=="UNHEALTHY")))i++;else if(v?.state==="FAILED")s++;else if(v?.state==="STARTING"||v?.state==="RUNNING"||v?.state==="UNHEALTHY"||v?.health==="UNHEALTHY"||v?.state==="STOPPING"||v?.state==="RESTARTING")a++}}let c=o>0?Math.round(i/o*100):100,u=16,d=Math.round(c/100*u),f="\u2588".repeat(d)+"\u2591".repeat(Math.max(0,u-d)),p=i===o&&o>0;return{total:o,ready:i,active:a,failed:s,percent:c,progressBar:f,currentWaveIndex:l,totalWaves:e.waves.length,isComplete:p}}function nC(e,t,r){let n=r==="completed"?"\u2713 Completed":r==="failed"?"\u2717 Failed":r==="unhealthy"?"\u26A0 Unhealthy":r==="active"?"\u23F3 In Progress":"\u25CB Queued";return`${e==="stop"?t===0?"Wave 1 (Stop First)":`Wave ${t+1}`:t===0?"Wave 1 (Start First)":`Wave ${t+1}`} \xB7 ${n}`}function oC(e,t,r,n){let o=n?` \xB7 Profile ${n}`:"";if(r)return`${e==="stop"?"Shutdown":"Startup"} Failed (${r})`;if(t)return`${e==="stop"?"Stopping Services":e==="restart"?"Restarting Pipeline":"Starting Pipeline"}${o}`;return`${e==="stop"?"Shutdown Complete":"Startup Complete"}${o}`}function iC(e,t){if(e)return{primary:"Working\u2026 esc hide this panel (keeps running in background)",secondary:"Services are transitioning. You can dismiss anytime without stopping them."};if(t)return{primary:"enter or esc back to dashboard",secondary:"Execution stopped. Check logs or open Doctor to resolve errors."};return{primary:"enter or esc back to dashboard",secondary:"All waves finished. Click here or press enter to continue."}}var Fu=A(()=>{Ke();$t();Ut()});function sC(e,t){let r=(t.name??"").toLowerCase();if(e.screen==="mcp"&&e.listCursor===1&&r.length===1&&r>="0"&&r<="9")return e.setMcpPortDraft((n)=>Sx(n,r)),!0;return!1}function aC(e,t){let r=(t.name??"").toLowerCase(),{screen:n,overlay:o,tui:i,cfg:s,controller:a,profile:l,listCursor:c,names:u,listCount:d,height:f,checked:p,detailName:m,bootErrorMissing:h,bootError:g,logSearchFocused:w,logSources:v,logService:S,logShowTimestamps:E,logShowMeta:_,logWrap:y,showSystemLogs:b,logPinned:k,dashboardLogCursor:x,applyLogCursor:L,applyDashboardLogCursor:F,jumpToLatestLogs:B,toggleSystemLogs:K,clearLogs:V,setLogService:X,setLogShowTimestamps:te,setLogShowMeta:R,setPaused:U,setErrorOnly:O,setLogWrap:ae,beginStart:Ae,beginStop:se,beginRestart:z,applyMcpPortDraft:ue,toggleMcp:re,toggleMcpTool:pt,copyFocusedMcpSnippet:xt,persistMcpPort:le,restartMcpOnPort:Oe,setMcpPortDraft:Fe,settingRows:Qe,persistPrefs:kt,cycleSetting:at,toggleMouse:At,setDoctorTick:Se,refreshAuth:St,configScrollRef:gt,detailScrollRef:Ct,handleEnter:xr,setScreen:lt,setChecked:Lt,setStatus:Ze,setSelected:Tt,setProfile:ur,refresh:dr,toggleChecked:Zr,createStarterConfig:pr,startWizard:nr,setConfirmKind:kr,setConfirmDetail:Sr,setOverlay:Cr,openConfigBuffer:zt,runCommand:de}=e,Z=(n==="logs"||n==="dashboard")&&!w;if(Z&&(r==="left"||r==="["||n==="logs"&&r==="h")){X(Um(v,S,-1));return}if(Z&&(r==="right"||r==="]"||n==="logs"&&r==="l")){X(Um(v,S,1));return}if((n==="dashboard"||n==="setup")&&r==="o"){lt("profiles");return}if((n==="dashboard"||n==="services")&&(r==="*"||t.shift&&r==="8")){Lt([...u]),Ze(`Selected ${u.length} services`);return}if((n==="dashboard"||n==="services")&&(r==="-"||r==="_"||r==="minus")){Lt([]),Ze("Selection cleared");return}if((n==="dashboard"||n==="services")&&r==="n"){Ae(iu(p,u[c]??""),l);return}if((n==="dashboard"||n==="services")&&r==="x"){se(iu(p,u[c]??""));return}if((n==="dashboard"||n==="services"||n==="detail")&&MS(t)){let D=iu(p,u[c]??m);if(s&&XS(s,D).length>0){kr("restart-cascade"),Sr({services:D}),Cr("confirm");return}z(D,l);return}if((n==="dashboard"||n==="services")&&r==="r"){dr(),Ze("Refreshed");return}if(n==="auth"&&r==="r"){St();return}if(n==="logs"&&r==="t"){let D=!E;te(D),kt({log_timestamps:D},D?"timestamps on":"timestamps off");return}if(n==="logs"&&r==="m"){let D=!_;R(D),kt({log_metadata:D},D?"metadata on":"metadata off");return}if(r==="down"||r==="j"){if(n==="mcp"&&c===1)ue();if(n==="config"){if(d>0)Tt((D)=>Math.min(Math.max(d-1,0),D+1));je(gt.current,i.scroll_speed);return}if(n==="detail"){je(Ct.current,i.scroll_speed);return}if(n==="logs"){L(c+1);return}if(n==="dashboard"&&x>=0){F(x+1);return}Tt((D)=>Math.min(Math.max(d-1,0),D+1));return}if(r==="up"||r==="k"){if(n==="mcp"&&c===1)ue();if(n==="config"){if(d>0)Tt((D)=>Math.max(0,Math.min(D,Math.max(d-1,0))-1));je(gt.current,-i.scroll_speed);return}if(n==="detail"){je(Ct.current,-i.scroll_speed);return}if(n==="logs"){L(c-1);return}if(n==="dashboard"&&x>=0){F(x-1);return}Tt((D)=>Math.max(0,Math.min(D,Math.max(d-1,0))-1));return}if(as(t)){let D=ao(f);if(n==="config"){je(gt.current,D);return}if(n==="detail"){je(Ct.current,D);return}if(n==="logs"){L(c+D);return}if(n==="dashboard"&&(k||x>=0)){F(Math.max(0,x)+D);return}Tt((we)=>Math.min(Math.max(d-1,0),we+D));return}if(ls(t)){let D=ao(f);if(n==="config"){je(gt.current,-D);return}if(n==="detail"){je(Ct.current,-D);return}if(n==="logs"){L(c-D);return}if(n==="dashboard"&&(k||x>=0)){F(Math.max(0,x)-D);return}Tt((we)=>Math.max(0,we-D));return}if(n==="proxy"&&r==="n"){a?.proxyStart().then(async()=>{Ze("Proxy started"),await dr()});return}if(n==="proxy"&&r==="x"){a?.proxyStop().then(async()=>{Ze("Proxy stopped"),await dr()});return}if(n==="detail"&&m!==""){if(r==="n"){Ae([m],l);return}if(r==="x"){se([m]);return}if(r==="o"){lt("config");return}if(r==="l"){X(m),lt("logs");return}}if(n==="mcp"&&c===1&&(r==="left"||r==="h")){let D=to(ue()-1);le(D),Oe(D);return}if(n==="mcp"&&c===1&&(r==="right"||r==="l")){let D=to(ue()+1);le(D),Oe(D);return}if(n==="mcp"&&c===1&&(r==="backspace"||r==="delete")){Fe((D)=>Cx(D));return}if(n==="settings"&&(r==="left"||r==="h")){at(-1,c);return}if(n==="settings"&&(r==="right"||r==="l")){at(1,c);return}if(r==="space"){if(n==="profiles"){let ft=Object.keys(s?.profiles??{}).sort()[c];if(ft)ur(ft),Ze(`Profile ${ft}`);return}if(n==="mcp"){if(c===0){re();return}let we=Da(c);if(we){pt(we);return}xt(c);return}if(n==="logs")return;if(n==="settings"){if(oo(Qe,c)?.id==="mouse")At();return}let D=u[c];if(D)Zr(D);return}if(r==="return"){if(n==="setup"&&!a){if(!h){Ze(g||"Existing configuration is invalid \u2014 fix it and restart devctl.");return}nr();return}if(n==="setup"&&a){Ae([],l);return}xr();return}if(lo(t,i,"services","s")&&o==="none"&&n!=="logs"){lt("services");return}if(lo(t,i,"logs","l")&&o==="none"&&n!=="detail"&&n!=="logs"&&n!=="settings"){lt("logs");return}if(lo(t,i,"auth","a")&&o==="none"){lt("auth");return}if(lo(t,i,"proxy","p")&&o==="none"&&n!=="logs"){lt("proxy");return}if(lo(t,i,"doctor","d")&&o==="none"&&n!=="doctor"){lt("doctor");return}if(lo(t,i,"config","c")&&o==="none"){lt("config");return}if(lo(t,i,"setup","u")&&o==="none"){lt("setup");return}if(n==="config"&&r==="e"){de(pn("/edit")??{name:"edit",aliases:[],desc:"",leader:"",group:"ui"},[]);return}if(n==="config"&&r==="v"){zt();return}if(n==="doctor"&&r==="r"){Se((D)=>D+1),Ze("Re-running doctor");return}if(n==="logs"&&r==="p"){U((D)=>!D);return}if((n==="logs"||n==="dashboard")&&r==="g"){B();return}if((n==="logs"||n==="dashboard")&&r==="w"){let D=pu(y);ae(D),Ze(`Log ${mu(D)}`);return}if((n==="logs"||n==="dashboard")&&r==="e"){O((D)=>!D);return}if((n==="logs"||n==="dashboard")&&r==="i"){K(),Ze(b?"Hiding internal auth/mcp/devctl/proxy logs":"Showing internal logs");return}if((n==="logs"||n==="dashboard")&&NS(t))V()}var lC=A(()=>{Mu();wr();br();Fu();Ut();Iu();Re();Oa();Mr()});import{useKeyboard as tF}from"@opentui/react";import{useCallback as _h}from"react";function cC({tui:e,controller:t,cfg:r,snap:n,ui:o,logView:i,lifecycleActions:s,mcp:a,preferences:l,diagnostics:c,refs:u}){let{screen:d,onQuit:f,closeOverlay:p,confirmKind:m,confirmDetail:h,portTarget:g,profile:w,listCursor:v,names:S,runCommand:E,copySelection:_,setOverlay:y,setConfirmKind:b,setConfirmDetail:k,setPortTarget:x,setLogDetail:L,setProfile:F,setStatus:B,setSlashIndex:K,setQuery:V,setSlashPicker:X,setScreen:te,freePort:R,openDetail:U}=o,{logSlice:O,logSliceB:ae,logSearchFocused:Ae,logsFullscreen:se,setLogSearchFocused:z,setLogsFullscreen:ue,splitLogs:re,splitFocus:pt,toggleSplitLogs:xt,cycleSplitFocus:le,setActiveLogService:Oe,logService:Fe,logServiceB:Qe}=i,{beginStart:kt,beginRestart:at,planBusy:At}=s,{applyMcpPortDraft:Se,toggleMcp:St,toggleMcpTool:gt,copyFocusedMcpSnippet:Ct}=a,{settingRows:xr,activateSetting:lt,applyFont:Lt,applyReset:Ze,fontSize:Tt,revertThemePreview:ur,setThemeName:dr,leaderMs:Zr}=l,{doctor:pr}=c,{interruptArmedAt:nr,leaderTimer:kr}=u,Sr=_h(()=>{if(r?.shutdown.stop_services_on_exit===void 0){b("quit"),y("confirm");return}f(r.shutdown.stop_services_on_exit===!1)},[r,f,b,y]),Cr=_h((de)=>{if(m==="quit"){f(!1);return}if(m==="reload"){p();let Z=n?.restart_required??[];if(Z.length>0)at(Z,w);return}if(m==="restart-cascade"){let Z=h?.services??[];p(),at(Z,w,de==="cascade");return}if(m==="reset-prefs"){p(),Ze();return}if(m==="free-port"){let Z=g;if(p(),!Z)return;R(Z).then(()=>{B(`Stopped ${Z.command} (pid ${Z.pid}) on port ${Z.port}`),c.setDoctorTick((D)=>D+1)}).catch((D)=>{B(I(D))});return}p(),kt([],w)},[Ze,at,kt,p,h,m,c,R,f,g,w,B,n]),zt=_h(()=>{if(d==="logs"){let Z=(re&&pt===1?ae:O)[v];if(Z)L(Z),y("log-details");return}if(d==="profiles"){let D=Object.keys(r?.profiles??{}).sort()[v];if(D)F(D),b("start-profile"),y("confirm");return}if(d==="doctor"){let Z=pr?.checks[v];if(Z?.action?.kind==="free-port"){let D=Z.action.holder;x(D),k({port:D.port,pid:D.pid,process:D.command}),b("free-port"),y("confirm")}return}if(d==="mcp"){if(v===0){St();return}if(v===1){Se();return}let Z=Da(v);if(Z){gt(Z);return}Ct(v);return}if(d==="settings"){let Z=oo(xr,v);if(Z)lt(Z);return}if(d==="config"){let Z=Object.keys(r?.tasks??{}).sort()[v],D=pn("run");if(Z&&D)E(D,[Z]);return}if(d==="dashboard"&&ou(n)){kt([],w);return}let de=S[v];if(de&&(d==="dashboard"||d==="services"))U(de)},[lt,Se,kt,r,Ct,pr,v,O,ae,S,U,w,E,d,k,b,L,y,x,F,xr,n,pt,re,St,gt]);tF((de)=>{let Z=(de.name??"").toLowerCase();if(FS(de,e)){_();return}if(rn(de)&&(Z==="="||Z==="+"||Z==="plus")){Lt(xa(Tt,1));return}if(rn(de)&&(Z==="-"||Z==="_"||Z==="minus")){Lt(xa(Tt,-1));return}if(rn(de)&&Z==="0"){Lt(Qc().font_size);return}if(d==="logs"&&!Ae&&(de.sequence==="\\"||Z==="\\")){xt(),B(re?"Single log pane":"Split log panes");return}if(d==="logs"&&!Ae&&(de.sequence==="|"||Z==="|")){le();return}if(YS({...o,tui:e,confirmAction:Cr,planBusy:At,leaderTimer:kr,logDetailsScrollRef:u.logDetailsScrollRef,traceScrollRef:u.traceScrollRef,traceDetailScrollRef:u.traceDetailScrollRef,scrollTextScrollRef:u.scrollTextScrollRef,routeDetailsScrollRef:u.routeDetailsScrollRef,planScrollRef:u.planScrollRef,helpScrollRef:u.helpScrollRef,revertThemePreview:ur,setThemeName:dr},de))return;if(Ae){if(Z==="escape")z(!1);return}if(AS(de,e)){y("leader"),kr.current=setTimeout(()=>y("none"),Zr);return}if(LS(de,e)||fn(de,e)){V(""),K(0),X("commands"),y("slash");return}if(IS(de,e)){y("help");return}if(DS(de,e)||d==="logs"&&Z==="f"&&!de.ctrl&&!de.meta){te("logs"),z(!0);return}if(Z==="escape"||OS(de)){if(Z==="escape"){if(se){ue(!1);return}if(d==="detail"){te("services");return}if(d==="setup"&&t){te("dashboard");return}}let ft=Date.now();if($S(ft,nr.current)){nr.current=0,Sr();return}nr.current=ft,B(Z==="q"?"q again to quit":"Esc again to quit");return}if(Z==="z"&&(d==="logs"||d==="dashboard")&&!de.ctrl&&!de.meta){te("logs"),ue((ft)=>d==="logs"?!ft:!0);return}if(Z==="tab"){te(de.shift?Ck(d):Sk(d));return}let D={...o,tui:e,controller:t,cfg:r,snap:n,...i,...s,...a,...l,logService:re&&pt===1?Qe:Fe,setLogService:Oe,setDoctorTick:c.setDoctorTick,refreshAuth:c.refreshAuth,configScrollRef:u.configScrollRef,detailScrollRef:u.detailScrollRef,handleEnter:zt};if(sC(D,de))return;let we=tk(Z);if(we){te(we);return}aC(D,de)})}var uC=A(()=>{ne();si();so();Ut();Iu();Oa();Mr();Vr();JS();lC()});import{parse as rF,stringify as nF}from"yaml";function $u(e,t="imported"){let r=rF(e);if(!r||typeof r!=="object"||Array.isArray(r))throw Error("compose file is not a mapping");let n=r,o=ds(n.services)?n.services:{},i=[];if(n.networks!==void 0)i.push({service:"(root)",field:"networks",reason:dC.networks??"not modeled"});let s={},a=[];for(let[c,u]of Object.entries(o)){if(!ds(u))continue;let d=oF(c,u,i);if(s[c]=d.body,!d.container)a.push(c)}return{yaml:nF({version:1,project:{name:t},services:s,profiles:{default:{services:a}}}),dropped:i,services:Object.keys(s),profileServices:a}}function Hu(e){let t=[e.yaml.trimEnd(),"","Dropped fields:"];if(e.dropped.length===0)t.push("(none)");else{t.push("service\tfield\treason");for(let r of e.dropped)t.push(`${r.service} ${r.field} ${r.reason}`)}if(e.profileServices.length<e.services.length)t.push(""),t.push("Container services were omitted from profile default so first start does not require Docker.");return`${t.join(`
|
|
2485
|
+
`}function G2(e){return`codex mcp add --url ${e}`}function Ia(e,t){return[{kind:"claude",title:"Claude",path:".mcp.json",language:"json",text:ph(e,t),hint:"claude mcp add-json"},{kind:"cursor",title:"Cursor",path:".cursor/mcp.json",language:"json",text:fh(e,t)},{kind:"kilo",title:"Kilo Code",path:"kilo.jsonc",language:"json",text:mh(e,t)},{kind:"codex",title:"Codex",path:"~/.codex/config.toml",language:"toml",text:hh(e,t),hint:G2(e)}]}function jS(e,t){let r=[`URL ${e}`,""];for(let n of Ia(e,t))r.push(`# ${n.title} ${n.path}${n.hint?` (${n.hint})`:""}`),r.push(n.text.trimEnd()),r.push("");return r.join(`
|
|
2486
|
+
`)}import{jsxDEV as Y}from"@opentui/react/jsx-dev-runtime";function bh(){return lm.flatMap((e)=>ma.filter((t)=>t.category===e))}function Ou(){return Du+bh().length}function qS(){return Ou()+zS}function Da(e){if(e<Du||e>=Ou())return;return bh()[e-Du]}function wh(e){let t=e-Ou();return t>=0&&t<zS?t:void 0}function GS(e){let{palette:t,snap:r,port:n,portDraft:o="",selected:i,onPick:s,onToggle:a,onCopy:l,onToggleTool:c}=e,u=ye(),d=r?.mcp?.running===!0,f=r?.mcp?.port??n,p=r?.mcp?.address??cs(f),m=r?.mcp?.token??"",h=Ia(p,m),g=r?.mcp?.disabled_tools??[],w=bh(),v=w.filter((_)=>!no(_.name,g)).length,S=h[wh(i)??-1],E=S??h[0];return Y(At,{palette:t,title:"mcp settings",children:[Y(wt,{palette:t,items:[{text:d?"RUNNING":"STOPPED",tone:d?"success":"idle"},{text:`127.0.0.1:${f}`,tone:"info"}]},void 0,!1,void 0,this),Y("box",{flexGrow:1,overflow:"hidden",children:Y("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:Y("box",{flexDirection:"column",overflow:"hidden",children:[Y(gh,{palette:t,text:"Server"},void 0,!1,void 0,this),Y(WS,{palette:t,active:i===vh,rowH:u.rowH,label:"Listen",value:d?"[ ON ]":"[ OFF ]",valueTone:d?"success":"muted",hint:d?"space or enter stop":"space or enter start",onPick:()=>s(vh),onActivate:a},void 0,!1,void 0,this),Y(WS,{palette:t,active:i===yh,rowH:u.rowH,label:"Port",value:`\u2039 ${o===""?n:o} \u203A`,valueTone:"info",hint:o===""?"\u2190 \u2192 change type digits enter apply":"typing\u2026 enter apply \u232B erase",onPick:()=>s(yh)},void 0,!1,void 0,this),Y("box",{height:1,overflow:"hidden",children:Y("text",{fg:t.muted,wrapMode:"none",children:d?"Listening on loopback. Agents use the URL and token in the JSON below.":"Server is stopped. Highlight Listen and press space to start it."},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y(gh,{palette:t,text:"Tools",extra:v===0?"all enabled":`${v} disabled`},void 0,!1,void 0,this),Y("box",{height:1,overflow:"hidden",children:Y("text",{fg:t.muted,wrapMode:"none",children:"Disabled tools are hidden from agents and refused if called anyway."},void 0,!1,void 0,this)},void 0,!1,void 0,this),lm.map((_)=>{let y=w.filter((b)=>b.category===_);if(y.length===0)return null;return Y("box",{flexDirection:"column",overflow:"hidden",children:[Y("box",{height:1,marginTop:1,overflow:"hidden",children:Y("text",{fg:t.muted,wrapMode:"none",children:K2[_]??_},void 0,!1,void 0,this)},void 0,!1,void 0,this),y.map((b)=>{let k=Du+w.indexOf(b);return Y(J2,{palette:t,tool:b,enabled:no(b.name,g),active:i===k,rowH:u.rowH,onPick:()=>s(k),onToggle:()=>c(b)},b.name,!1,void 0,this)})]},_,!0,void 0,this)}),Y(gh,{palette:t,text:"Copy agent config",extra:"highlight a row, then enter or click Copy"},void 0,!1,void 0,this),h.map((_,y)=>{let b=Ou()+y;return Y(Y2,{palette:t,snippet:_,active:i===b,rowH:u.rowH,onPick:()=>s(b),onCopy:()=>l(_)},_.kind,!1,void 0,this)}),Y(X2,{palette:t,snippet:E,selected:Boolean(S),brand:E?Jc(E.kind,t):t.muted},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y(Zt,{palette:t,backgroundColor:t.element,edge:"top",children:Y(mt,{palette:t,hints:V2(i,d)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function V2(e,t){if(e===vh)return[{key:"space",label:t?"stop server":"start server"},{key:"j/k",label:"move"}];if(e===yh)return[{key:"\u2190\u2192",label:"change port"},{key:"0-9",label:"type port"},{key:"enter",label:"apply port"},{key:"j/k",label:"move"}];if(Da(e))return[{key:"space",label:"enable / disable"},{key:"enter",label:"enable / disable"},{key:"j/k",label:"move"}];return[{key:"enter",label:"copy JSON"},{key:"space",label:"copy JSON"},{key:"j/k",label:"move"}]}function gh(e){let t=e.extra?` \xB7 ${e.extra}`:"";return Y("box",{height:1,marginTop:1,overflow:"hidden",children:Y("text",{wrapMode:"none",children:[Y("span",{fg:e.palette.primary,children:e.text},void 0,!1,void 0,this),Y("span",{fg:e.palette.muted,children:t},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function WS(e){let{palette:t,active:r,rowH:n,label:o,value:i,valueTone:s,hint:a,onPick:l,onActivate:c}=e,u=s==="success"?t.success:s==="info"?t.info:t.muted;return Y("box",{height:n,flexDirection:"row",overflow:"hidden",backgroundColor:r?t.highlight:t.panel,onMouseDown:()=>{if(r&&c){c();return}l()},children:[Y("box",{width:2,flexShrink:0,overflow:"hidden",children:Y("text",{fg:t.primary,children:r?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:us,flexShrink:0,overflow:"hidden",children:Y("text",{fg:r?t.primary:t.text,wrapMode:"none",children:j(o,us)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:BS,flexShrink:0,overflow:"hidden",children:Y("text",{fg:u,wrapMode:"none",children:j(i,BS)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{flexGrow:1,overflow:"hidden",children:Y("text",{fg:r?t.text:t.muted,wrapMode:"none",children:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Y2(e){let{palette:t,snippet:r,active:n,rowH:o,onPick:i,onCopy:s}=e,a=Jc(r.kind,t),l=v0(r.kind,t),c=r.language==="toml"?"Copy TOML":"Copy JSON";return Y("box",{height:o,flexDirection:"row",overflow:"hidden",backgroundColor:n?t.highlight:t.panel,onMouseDown:i,children:[Y("box",{width:2,flexShrink:0,overflow:"hidden",children:Y("text",{fg:a,children:n?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:us,flexShrink:0,overflow:"hidden",children:Y("text",{fg:a,wrapMode:"none",children:j(r.title,us)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{flexGrow:1,overflow:"hidden",children:Y("text",{fg:t.muted,wrapMode:"none",children:r.path},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y(Ue,{palette:t,label:c,bg:a,fg:l,onMouseDown:()=>{i(),s()}},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function J2(e){let{palette:t,tool:r,enabled:n,active:o,rowH:i,onPick:s,onToggle:a}=e;return Y("box",{height:i,flexDirection:"row",overflow:"hidden",backgroundColor:o?t.highlight:t.panel,onMouseDown:()=>{if(o){a();return}s()},children:[Y("box",{width:2,flexShrink:0,overflow:"hidden",children:Y("text",{fg:t.primary,children:o?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:5,flexShrink:0,overflow:"hidden",children:Y("text",{fg:n?t.success:t.muted,wrapMode:"none",children:n?" ON ":" OFF "},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:us+4,flexShrink:0,overflow:"hidden",children:Y("text",{fg:o?t.primary:n?t.text:t.muted,wrapMode:"none",children:j(r.label,us+4)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:7,flexShrink:0,overflow:"hidden",children:Y("text",{fg:r.mutates?t.warning:t.muted,wrapMode:"none",children:j(r.mutates?"write":"read",7)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{flexGrow:1,overflow:"hidden",children:Y("text",{fg:o?t.text:t.muted,wrapMode:"none",children:o?`space or enter ${n?"disable":"enable"} ${r.name}`:r.summary},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function X2(e){let{palette:t,snippet:r,selected:n,brand:o}=e;if(!r)return null;let i=r.hint?` \xB7 ${r.hint}`:"";return Y("box",{marginTop:1,flexDirection:"column",overflow:"hidden",children:[Y("text",{fg:o,wrapMode:"none",children:n?`${r.title} \xB7 paste into ${r.path}${i}`:`Preview ${r.title} \xB7 j/k to a copy row, then enter`},void 0,!1,void 0,this),Y("text",{fg:t.text,children:r.text},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var vh=0,yh=1,Du=2,zS=4,K2,us=14,BS=14;var Oa=A(()=>{Ht();nt();Re();rt();Ji();K2={inspect:"Inspect",logs:"Logs",diagnostics:"Diagnostics",control:"Control",setup:"Setup"}});import{jsxDEV as We,Fragment as VS}from"@opentui/react/jsx-dev-runtime";function iF(e){return[{key:"\u2190\u2192",label:"filter services"},{key:"e",label:"ERROR+ only"},{key:"g",label:"jump to latest"},{key:"p",label:"pause stream"},{key:"z",label:"full-screen logs"},{key:"\\",label:"split panes"},{key:"|",label:"focus other pane"},{key:"/trace",label:"jump to request id"},{key:"f",label:"search"},{key:"t",label:"timestamps"},{key:"m",label:"metadata"},{key:"w",label:"wrap all / clip / wrap selected"},{key:"j/k",label:"move selection"},{key:wo(e),label:"copy selection"},{key:"/export",label:"write ~/.devctl/exports"},{key:"/exports",label:"open export folder"}]}function uo(e){return e+eF}function YS(e){let t=uo(kh.length),r=uo(Sh.length),n=uo(e.logCount),o=uo(Ch.length),i=uo(Th.length),s=Eh+e.pad*2;if(e.stacked)return s+t+r+n+o+i+xh+(nF-1)*e.gap;let a=Math.max(t,r),l=Math.max(o,i);return s+a+n+l+xh+(oF-1)*e.gap}function sF(e){return YS(e)-Eh-e.pad*2}function aF(e){return e-Eh*2<Z2}function JS(e){let{palette:t,termW:r,termH:n,copyKey:o=kn(),scrollRef:i}=e,s=Ln(ye()),a=aF(r),l=s?0:1,c=s?0:1,u=iF(o),d={stacked:a,logCount:u.length,pad:l,gap:c},f=YS(d),p=sF(d);return We(ot,{palette:t,title:"help",bottomTitle:`${vr()} \xB7 j/k scroll \xB7 esc close`,termW:r,termH:n,preferW:Q2,preferH:f,gap:0,children:We("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:We("box",{height:p,flexDirection:"column",flexShrink:0,overflow:"hidden",gap:c,children:[a?We(VS,{children:[We(co,{palette:t,title:"navigation",bindings:kh},void 0,!1,void 0,this),We(co,{palette:t,title:"services",bindings:Sh},void 0,!1,void 0,this),We(co,{palette:t,title:"logs",bindings:u},void 0,!1,void 0,this),We(co,{palette:t,title:"commands",bindings:Ch},void 0,!1,void 0,this),We(co,{palette:t,title:"display",bindings:Th},void 0,!1,void 0,this)]},void 0,!0,void 0,this):We(VS,{children:[We(KS,{palette:t,left:{title:"navigation",bindings:kh},right:{title:"services",bindings:Sh}},void 0,!1,void 0,this),We(co,{palette:t,title:"logs",bindings:u},void 0,!1,void 0,this),We(KS,{palette:t,left:{title:"commands",bindings:Ch},right:{title:"display",bindings:Th}},void 0,!1,void 0,this)]},void 0,!0,void 0,this),We("box",{height:xh,flexShrink:0,overflow:"hidden",paddingLeft:1,children:We("text",{fg:t.muted,wrapMode:"none",children:"~/.devctl/tui.json \xB7 DEVCTL_TUI_CONFIG"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function KS(e){let{palette:t,left:r,right:n}=e,o=Math.max(uo(r.bindings.length),uo(n.bindings.length));return We("box",{height:o,flexDirection:"row",flexShrink:0,overflow:"hidden",gap:rF,children:[We(co,{palette:t,title:r.title,bindings:r.bindings,height:o,stretch:!0},void 0,!1,void 0,this),We(co,{palette:t,title:n.title,bindings:n.bindings,height:o,stretch:!0},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function co(e){let{palette:t,title:r,bindings:n,stretch:o=!1}=e,i=e.height??uo(n.length),s=lF(n);return We("box",{height:i,flexGrow:o?1:0,flexBasis:o?0:void 0,flexShrink:0,flexDirection:"column",overflow:"hidden",border:!0,borderStyle:"rounded",borderColor:t.border,title:r,titleColor:t.accent,children:n.map((a)=>We("box",{height:1,flexShrink:0,overflow:"hidden",paddingLeft:1,paddingRight:1,children:We(cF,{palette:t,binding:a,keyWidth:s},void 0,!1,void 0,this)},`${a.key}-${a.label}`,!1,void 0,this))},void 0,!1,void 0,this)}function lF(e){return e.reduce((r,n)=>Math.max(r,n.key.length),0)+tF}function cF(e){let{palette:t,binding:r,keyWidth:n}=e;return We("box",{height:1,flexDirection:"row",overflow:"hidden",children:[We("box",{width:n,flexShrink:0,overflow:"hidden",children:We("text",{fg:t.primary,wrapMode:"none",children:j(r.key,n)},void 0,!1,void 0,this)},void 0,!1,void 0,this),We("box",{flexGrow:1,overflow:"hidden",children:We("text",{fg:t.text,wrapMode:"none",children:r.label},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Q2=78,Z2=56,eF=2,Eh=2,xh=1,Rh=8,tF=2,rF=2,nF=6,oF=4,kh,Sh,Ch,Th;var _h=A(()=>{Ht();nt();Re();Mr();Vr();kh=[{key:"tab",label:"next tab"},{key:"1-4",label:"dashboard services logs proxy"},{key:"s/l/a/p/d/c/u",label:"letter jump"},{key:"/",label:"command overlay \xB7 other screens"},{key:"j/k",label:"move selection"},{key:"esc",label:"back / close overlay"},{key:"esc \xD72",label:"quit"},{key:"q \xD72",label:"quit"}],Sh=[{key:"enter",label:"start profile or open"},{key:"space",label:"multi-select"},{key:"n",label:"start"},{key:"x",label:"stop"},{key:"r",label:"refresh"},{key:"R",label:"restart (c cascade if dependents)"}];Ch=[{key:jt("c"),label:"copy highlighted selection"},{key:"/",label:"command overlay"},{key:jt("p"),label:"same overlay"},{key:jt("x"),label:"leader chord"},{key:"/settings",label:"preferences \xB7 MCP page"},{key:"/themes",label:"preview themes"},{key:"/diff",label:"config sources"},{key:"/mcp",label:"agent MCP server"}],Th=[{key:jt("="),label:"larger"},{key:jt("-"),label:"smaller"},{key:"?",label:"this overlay"}]});function ci(e){e.setQuery(""),e.setSlashIndex(0),e.setSlashPicker("commands"),e.setOverlay("slash")}function XS(e,t){let{overlay:r,tui:n,height:o,closeOverlay:i,confirmKind:s,onQuit:a,confirmAction:l,planBusy:c,logDetailsScrollRef:u,traceScrollRef:d,traceDetailScrollRef:f,scrollTextScrollRef:p,routeDetailsScrollRef:m,planScrollRef:h,helpScrollRef:g,revertThemePreview:w,setPaletteIndex:v,setThemeName:S,paletteIndex:E,applyTheme:_,leaderTimer:y,setOverlay:b,runCommand:k,setConfigEditError:x,saveConfigBuffer:L,setSlashIndex:F,filtered:B,setQuery:K,slashIndex:V,submitSlash:X,advanceWizard:te}=e,R=(t.name??"").toLowerCase();if(r==="none")return!1;if(r==="setup-wizard"){if(R==="escape")return i(),!0;if(R==="return")return te?.(),!0;return uh(r)}if(r==="confirm"){if(R==="escape")return i(),!0;if(s==="quit"&&R==="d")return a(!0),!0;if(s==="quit"&&R==="k")return e.onDown(!0),!0;if(s==="restart-cascade"&&R==="c")return l("cascade"),!0;if(R==="return")l();return!0}if(r==="span-details"){if(fn(t,n))return ci(e),!0;if(R==="escape")return e.setOverlay("trace"),!0;if(R==="down"||R==="j")return je(f.current,n.scroll_speed),!0;if(R==="up"||R==="k")return je(f.current,-n.scroll_speed),!0;if(as(t))return je(f.current,ao(o)),!0;if(ls(t))return je(f.current,-ao(o)),!0;return!0}if(r==="log-details"||r==="scroll-text"||r==="trace"){if(fn(t,n))return ci(e),!0;if(R==="escape")return i(),!0;if(r==="log-details"&&R==="return"){let O=e.logDetail?.traceId?.trim()??"";if(O!=="")return e.openTrace(O),!0;let ae=e.logDetail?Ei(e.logDetail).trim():"";if(ae!=="")e.setLogSearch(ae),e.setScreen("logs"),e.closeOverlay(),e.setStatus(`tracing ${ae}`);return!0}if(r==="trace"&&R==="return")return e.openSpanLogs(),!0;if(r==="trace"&&(R==="down"||R==="j"))return e.setTraceSpanIndex((O)=>Math.min(Math.max(0,e.traceSpanCount-1),O+1)),!0;if(r==="trace"&&(R==="up"||R==="k"))return e.setTraceSpanIndex((O)=>Math.max(0,O-1)),!0;let U=r==="log-details"?u.current:r==="trace"?d.current:p.current;if(r!=="trace"&&(R==="down"||R==="j"))return je(U,n.scroll_speed),!0;if(r!=="trace"&&(R==="up"||R==="k"))return je(U,-n.scroll_speed),!0;if(as(t)){if(r==="trace")return e.setTraceSpanIndex((O)=>Math.min(Math.max(0,e.traceSpanCount-1),O+ah)),!0;return je(U,ao(o)),!0}if(ls(t)){if(r==="trace")return e.setTraceSpanIndex((O)=>Math.max(0,O-ah)),!0;return je(U,-ao(o)),!0}return!0}if(r==="route-details"){if(fn(t,n))return ci(e),!0;if(R==="escape"||R==="return")return i(),!0;if(R==="down"||R==="j")return je(m.current,n.scroll_speed),!0;if(R==="up"||R==="k")return je(m.current,-n.scroll_speed),!0;return!0}if(r==="plan"){if(fn(t,n))return ci(e),!0;if(R==="escape"||R==="return"&&!c)return i(),!0;if(R==="down"||R==="j")return je(h.current,n.scroll_speed),!0;if(R==="up"||R==="k")return je(h.current,-n.scroll_speed),!0;return!0}if(r==="help"){if(fn(t,n))return ci(e),!0;if(R==="escape")return i(),!0;if(R==="down"||R==="j")return je(g.current,1),!0;if(R==="up"||R==="k")return je(g.current,-1),!0;if(R==="pagedown"||as(t))return je(g.current,Rh),!0;if(R==="pageup"||ls(t))return je(g.current,-Rh),!0;return!0}if(r==="themes"){if(fn(t,n))return w(),ci(e),!0;if(R==="escape")return w(),i(),!0;if(R==="down"||R==="j")return v((U)=>{let O=Math.min(U+1,Pt.length-1),ae=Pt[O];if(ae)S(ae);return O}),!0;if(R==="up"||R==="k")return v((U)=>{let O=Math.max(0,U-1),ae=Pt[O];if(ae)S(ae);return O}),!0;if(R==="return"){let U=Pt[E%Pt.length];if(U)_(U)}return!0}if(r==="leader"){if(fn(t,n)){if(y.current)clearTimeout(y.current);return ci(e),!0}if(y.current)clearTimeout(y.current);b("none");let U=yk(R),O=U?pn(U):void 0;if(O)k(O,[]);return!0}if(r==="config-edit"){if(R==="escape")return x(""),i(),!0;if(rn(t)&&R==="s")return L(),!0;return!0}if(uh(r)){if(R==="escape")return i(),!0;if(r==="slash"&&R==="down")return F((U)=>Math.min(Math.max(B.length-1,0),U+1)),!0;if(r==="slash"&&R==="up")return F((U)=>Math.max(0,U-1)),!0;if(r==="slash"&&R==="tab"){if(t.shift)return F((O)=>Math.max(0,O-1)),!0;let U=os(B,V);if(U)K(Pk(U));return!0}if(r==="slash"&&R==="return")return X(),!0;return!0}return!0}var QS=A(()=>{Lu();wr();si();Iu();Vr();Re();_h();rt();sn()});var Mu=A(()=>{Kf()});function ZS(e,t){if(t.length===0)return[];let r=new Set(t);return Go(e,t).filter((n)=>!r.has(n))}function eC(e,t,r){let n=r!==""&&e.profiles[r]?r:"";if(t.length>0)return{services:t,profile:n};if(n!=="")return{services:[...e.profiles[r]?.services??[]],profile:n};return{services:Object.keys(e.services),profile:""}}function Nu(e){return e.waves.flat().join(" \u2192 ")}function tC(e){let t=Nu(e);if(t==="")return"Started selected services";return`Started ${t}`}function rC(e){let t=Nu(e);if(t==="")return"Stopped running services";return`Stopped ${t}`}function nC(e,t,r,n="start"){let o=r?.services[e],i=yr(o);if(o?.last_error&&n!=="stop")return o.last_error;if(n==="stop"){if(i==="STOPPED")return"stopped";if(i==="STOPPING")return"stopping now";if(i==="FAILED")return"already failed";return"queued"}if(i==="HEALTHY")return"ready";if(i==="STARTING")return"starting now";if(i==="RUNNING")return"up, waiting for health";if(i==="UNHEALTHY")return"unhealthy \u2014 retrying health check";if(i==="STOPPING")return"stopping first";if(i==="FAILED")return"failed \u2014 later waves will not start";let a=(t.steps.find((l)=>l.name===e)?.dependencies??[]).filter((l)=>{let c=yr(r?.services[lr(l)]);return zn(l)==="service_healthy"?c!=="HEALTHY":c==="STOPPED"||c==="FAILED"}).map(lr);if(a.length>0)return`waits for ${a.join(", ")}`;return"queued"}function Ma(e,t,r="start"){if(e.length===0)return"completed";let n=e.map((i)=>t?.services[i]);if(n.some((i)=>i?.state==="FAILED"))return"failed";if(r==="stop"){if(n.every((i)=>!i||i.state==="STOPPED"||i.state==="UNKNOWN"))return"completed";if(n.some((i)=>i?.state==="STOPPING"))return"active";return"queued"}let o=(i)=>Boolean(i&&(i.state==="HEALTHY"||i.health==="HEALTHY"||i.state==="RUNNING"&&i.health!=="UNHEALTHY"));if(n.every(o))return"completed";if(n.some((i)=>i?.state==="UNHEALTHY"||i?.health==="UNHEALTHY"))return"unhealthy";if(n.some((i)=>i?.state==="STARTING"||i?.state==="RUNNING"||i?.state==="RESTARTING"))return"active";return"queued"}function oC(e,t,r="start"){let o=e.waves.flat().length,i=0,s=0,a=0,l=0;for(let m=0;m<e.waves.length;m++){let h=e.waves[m]??[],g=Ma(h,t,r);if(g==="active"||g==="unhealthy"||g==="failed")l=m;else if(g==="completed"&&l===m&&m<e.waves.length-1)l=m+1;for(let w of h){let v=t?.services[w];if(r==="stop"?!v||v.state==="STOPPED"||v.state==="UNKNOWN":Boolean(v&&(v.state==="HEALTHY"||v.health==="HEALTHY"||v.state==="RUNNING"&&v.health!=="UNHEALTHY")))i++;else if(v?.state==="FAILED")s++;else if(v?.state==="STARTING"||v?.state==="RUNNING"||v?.state==="UNHEALTHY"||v?.health==="UNHEALTHY"||v?.state==="STOPPING"||v?.state==="RESTARTING")a++}}let c=o>0?Math.round(i/o*100):100,u=16,d=Math.round(c/100*u),f="\u2588".repeat(d)+"\u2591".repeat(Math.max(0,u-d)),p=i===o&&o>0;return{total:o,ready:i,active:a,failed:s,percent:c,progressBar:f,currentWaveIndex:l,totalWaves:e.waves.length,isComplete:p}}function iC(e,t,r){let n=r==="completed"?"\u2713 Completed":r==="failed"?"\u2717 Failed":r==="unhealthy"?"\u26A0 Unhealthy":r==="active"?"\u23F3 In Progress":"\u25CB Queued";return`${e==="stop"?t===0?"Wave 1 (Stop First)":`Wave ${t+1}`:t===0?"Wave 1 (Start First)":`Wave ${t+1}`} \xB7 ${n}`}function sC(e,t,r,n){let o=n?` \xB7 Profile ${n}`:"";if(r)return`${e==="stop"?"Shutdown":"Startup"} Failed (${r})`;if(t)return`${e==="stop"?"Stopping Services":e==="restart"?"Restarting Pipeline":"Starting Pipeline"}${o}`;return`${e==="stop"?"Shutdown Complete":"Startup Complete"}${o}`}function aC(e,t){if(e)return{primary:"Working\u2026 esc hide this panel (keeps running in background)",secondary:"Services are transitioning. You can dismiss anytime without stopping them."};if(t)return{primary:"enter or esc back to dashboard",secondary:"Execution stopped. Check logs or open Doctor to resolve errors."};return{primary:"enter or esc back to dashboard",secondary:"All waves finished. Click here or press enter to continue."}}var Fu=A(()=>{Ke();$t();Ut()});function lC(e,t){let r=(t.name??"").toLowerCase();if(e.screen==="mcp"&&e.listCursor===1&&r.length===1&&r>="0"&&r<="9")return e.setMcpPortDraft((n)=>Ex(n,r)),!0;return!1}function cC(e,t){let r=(t.name??"").toLowerCase(),{screen:n,overlay:o,tui:i,cfg:s,controller:a,profile:l,listCursor:c,names:u,listCount:d,height:f,checked:p,detailName:m,bootErrorMissing:h,bootError:g,logSearchFocused:w,logSources:v,logService:S,logShowTimestamps:E,logShowMeta:_,logWrap:y,showSystemLogs:b,logPinned:k,dashboardLogCursor:x,applyLogCursor:L,applyDashboardLogCursor:F,jumpToLatestLogs:B,toggleSystemLogs:K,clearLogs:V,setLogService:X,setLogShowTimestamps:te,setLogShowMeta:R,setPaused:U,setErrorOnly:O,setLogWrap:ae,beginStart:Ae,beginStop:se,beginRestart:z,applyMcpPortDraft:ue,toggleMcp:re,toggleMcpTool:pt,copyFocusedMcpSnippet:xt,persistMcpPort:le,restartMcpOnPort:Oe,setMcpPortDraft:Fe,settingRows:Qe,persistPrefs:kt,cycleSetting:at,toggleMouse:Lt,setDoctorTick:Se,refreshAuth:St,configScrollRef:gt,detailScrollRef:Ct,handleEnter:xr,setScreen:lt,setChecked:It,setStatus:Ze,setSelected:Tt,setProfile:ur,refresh:dr,toggleChecked:Zr,createStarterConfig:pr,startWizard:nr,setConfirmKind:kr,setConfirmDetail:Sr,setOverlay:Cr,openConfigBuffer:zt,runCommand:de}=e,Z=(n==="logs"||n==="dashboard")&&!w;if(Z&&(r==="left"||r==="["||n==="logs"&&r==="h")){X(jm(v,S,-1));return}if(Z&&(r==="right"||r==="]"||n==="logs"&&r==="l")){X(jm(v,S,1));return}if((n==="dashboard"||n==="setup")&&r==="o"){lt("profiles");return}if((n==="dashboard"||n==="services")&&(r==="*"||t.shift&&r==="8")){It([...u]),Ze(`Selected ${u.length} services`);return}if((n==="dashboard"||n==="services")&&(r==="-"||r==="_"||r==="minus")){It([]),Ze("Selection cleared");return}if((n==="dashboard"||n==="services")&&r==="n"){Ae(iu(p,u[c]??""),l);return}if((n==="dashboard"||n==="services")&&r==="x"){se(iu(p,u[c]??""));return}if((n==="dashboard"||n==="services"||n==="detail")&&FS(t)){let D=iu(p,u[c]??m);if(s&&ZS(s,D).length>0){kr("restart-cascade"),Sr({services:D}),Cr("confirm");return}z(D,l);return}if((n==="dashboard"||n==="services")&&r==="r"){dr(),Ze("Refreshed");return}if(n==="auth"&&r==="r"){St();return}if(n==="logs"&&r==="t"){let D=!E;te(D),kt({log_timestamps:D},D?"timestamps on":"timestamps off");return}if(n==="logs"&&r==="m"){let D=!_;R(D),kt({log_metadata:D},D?"metadata on":"metadata off");return}if(r==="down"||r==="j"){if(n==="mcp"&&c===1)ue();if(n==="config"){if(d>0)Tt((D)=>Math.min(Math.max(d-1,0),D+1));je(gt.current,i.scroll_speed);return}if(n==="detail"){je(Ct.current,i.scroll_speed);return}if(n==="logs"){L(c+1);return}if(n==="dashboard"&&x>=0){F(x+1);return}Tt((D)=>Math.min(Math.max(d-1,0),D+1));return}if(r==="up"||r==="k"){if(n==="mcp"&&c===1)ue();if(n==="config"){if(d>0)Tt((D)=>Math.max(0,Math.min(D,Math.max(d-1,0))-1));je(gt.current,-i.scroll_speed);return}if(n==="detail"){je(Ct.current,-i.scroll_speed);return}if(n==="logs"){L(c-1);return}if(n==="dashboard"&&x>=0){F(x-1);return}Tt((D)=>Math.max(0,Math.min(D,Math.max(d-1,0))-1));return}if(as(t)){let D=ao(f);if(n==="config"){je(gt.current,D);return}if(n==="detail"){je(Ct.current,D);return}if(n==="logs"){L(c+D);return}if(n==="dashboard"&&(k||x>=0)){F(Math.max(0,x)+D);return}Tt((we)=>Math.min(Math.max(d-1,0),we+D));return}if(ls(t)){let D=ao(f);if(n==="config"){je(gt.current,-D);return}if(n==="detail"){je(Ct.current,-D);return}if(n==="logs"){L(c-D);return}if(n==="dashboard"&&(k||x>=0)){F(Math.max(0,x)-D);return}Tt((we)=>Math.max(0,we-D));return}if(n==="proxy"&&r==="n"){a?.proxyStart().then(async()=>{Ze("Proxy started"),await dr()});return}if(n==="proxy"&&r==="x"){a?.proxyStop().then(async()=>{Ze("Proxy stopped"),await dr()});return}if(n==="detail"&&m!==""){if(r==="n"){Ae([m],l);return}if(r==="x"){se([m]);return}if(r==="o"){lt("config");return}if(r==="l"){X(m),lt("logs");return}}if(n==="mcp"&&c===1&&(r==="left"||r==="h")){let D=to(ue()-1);le(D),Oe(D);return}if(n==="mcp"&&c===1&&(r==="right"||r==="l")){let D=to(ue()+1);le(D),Oe(D);return}if(n==="mcp"&&c===1&&(r==="backspace"||r==="delete")){Fe((D)=>Rx(D));return}if(n==="settings"&&(r==="left"||r==="h")){at(-1,c);return}if(n==="settings"&&(r==="right"||r==="l")){at(1,c);return}if(r==="space"){if(n==="profiles"){let ft=Object.keys(s?.profiles??{}).sort()[c];if(ft)ur(ft),Ze(`Profile ${ft}`);return}if(n==="mcp"){if(c===0){re();return}let we=Da(c);if(we){pt(we);return}xt(c);return}if(n==="logs")return;if(n==="settings"){if(oo(Qe,c)?.id==="mouse")Lt();return}let D=u[c];if(D)Zr(D);return}if(r==="return"){if(n==="setup"&&!a){if(!h){Ze(g||"Existing configuration is invalid \u2014 fix it and restart devctl.");return}nr();return}if(n==="setup"&&a){Ae([],l);return}xr();return}if(lo(t,i,"services","s")&&o==="none"&&n!=="logs"){lt("services");return}if(lo(t,i,"logs","l")&&o==="none"&&n!=="detail"&&n!=="logs"&&n!=="settings"){lt("logs");return}if(lo(t,i,"auth","a")&&o==="none"){lt("auth");return}if(lo(t,i,"proxy","p")&&o==="none"&&n!=="logs"){lt("proxy");return}if(lo(t,i,"doctor","d")&&o==="none"&&n!=="doctor"){lt("doctor");return}if(lo(t,i,"config","c")&&o==="none"){lt("config");return}if(lo(t,i,"setup","u")&&o==="none"){lt("setup");return}if(n==="config"&&r==="e"){de(pn("/edit")??{name:"edit",aliases:[],desc:"",leader:"",group:"ui"},[]);return}if(n==="config"&&r==="v"){zt();return}if(n==="doctor"&&r==="r"){Se((D)=>D+1),Ze("Re-running doctor");return}if(n==="logs"&&r==="p"){U((D)=>!D);return}if((n==="logs"||n==="dashboard")&&r==="g"){B();return}if((n==="logs"||n==="dashboard")&&r==="w"){let D=pu(y);ae(D),Ze(`Log ${mu(D)}`);return}if((n==="logs"||n==="dashboard")&&r==="e"){O((D)=>!D);return}if((n==="logs"||n==="dashboard")&&r==="i"){K(),Ze(b?"Hiding internal auth/mcp/devctl/proxy logs":"Showing internal logs");return}if((n==="logs"||n==="dashboard")&&$S(t))V()}var uC=A(()=>{Mu();wr();br();Fu();Ut();Iu();Re();Oa();Mr()});import{useKeyboard as uF}from"@opentui/react";import{useCallback as Ph}from"react";function dC({tui:e,controller:t,cfg:r,snap:n,ui:o,logView:i,lifecycleActions:s,mcp:a,preferences:l,diagnostics:c,refs:u}){let{screen:d,onQuit:f,closeOverlay:p,confirmKind:m,confirmDetail:h,portTarget:g,profile:w,listCursor:v,names:S,runCommand:E,copySelection:_,setOverlay:y,setConfirmKind:b,setConfirmDetail:k,setPortTarget:x,setLogDetail:L,setProfile:F,setStatus:B,setSlashIndex:K,setQuery:V,setSlashPicker:X,setScreen:te,freePort:R,openDetail:U}=o,{logSlice:O,logSliceB:ae,logSearchFocused:Ae,logsFullscreen:se,setLogSearchFocused:z,setLogsFullscreen:ue,splitLogs:re,splitFocus:pt,toggleSplitLogs:xt,cycleSplitFocus:le,setActiveLogService:Oe,logService:Fe,logServiceB:Qe}=i,{beginStart:kt,beginRestart:at,planBusy:Lt}=s,{applyMcpPortDraft:Se,toggleMcp:St,toggleMcpTool:gt,copyFocusedMcpSnippet:Ct}=a,{settingRows:xr,activateSetting:lt,applyFont:It,applyReset:Ze,fontSize:Tt,revertThemePreview:ur,setThemeName:dr,leaderMs:Zr}=l,{doctor:pr}=c,{interruptArmedAt:nr,leaderTimer:kr}=u,Sr=Ph(()=>{if(r?.shutdown.stop_services_on_exit===void 0){b("quit"),y("confirm");return}f(r.shutdown.stop_services_on_exit===!1)},[r,f,b,y]),Cr=Ph((de)=>{if(m==="quit"){f(!1);return}if(m==="reload"){p();let Z=n?.restart_required??[];if(Z.length>0)at(Z,w);return}if(m==="restart-cascade"){let Z=h?.services??[];p(),at(Z,w,de==="cascade");return}if(m==="reset-prefs"){p(),Ze();return}if(m==="free-port"){let Z=g;if(p(),!Z)return;R(Z).then(()=>{B(`Stopped ${Z.command} (pid ${Z.pid}) on port ${Z.port}`),c.setDoctorTick((D)=>D+1)}).catch((D)=>{B(I(D))});return}p(),kt([],w)},[Ze,at,kt,p,h,m,c,R,f,g,w,B,n]),zt=Ph(()=>{if(d==="logs"){let Z=(re&&pt===1?ae:O)[v];if(Z)L(Z),y("log-details");return}if(d==="profiles"){let D=Object.keys(r?.profiles??{}).sort()[v];if(D)F(D),b("start-profile"),y("confirm");return}if(d==="doctor"){let Z=pr?.checks[v];if(Z?.action?.kind==="free-port"){let D=Z.action.holder;x(D),k({port:D.port,pid:D.pid,process:D.command}),b("free-port"),y("confirm")}return}if(d==="mcp"){if(v===0){St();return}if(v===1){Se();return}let Z=Da(v);if(Z){gt(Z);return}Ct(v);return}if(d==="settings"){let Z=oo(xr,v);if(Z)lt(Z);return}if(d==="config"){let Z=Object.keys(r?.tasks??{}).sort()[v],D=pn("run");if(Z&&D)E(D,[Z]);return}if(d==="dashboard"&&ou(n)){kt([],w);return}let de=S[v];if(de&&(d==="dashboard"||d==="services"))U(de)},[lt,Se,kt,r,Ct,pr,v,O,ae,S,U,w,E,d,k,b,L,y,x,F,xr,n,pt,re,St,gt]);uF((de)=>{let Z=(de.name??"").toLowerCase();if(HS(de,e)){_();return}if(rn(de)&&(Z==="="||Z==="+"||Z==="plus")){It(xa(Tt,1));return}if(rn(de)&&(Z==="-"||Z==="_"||Z==="minus")){It(xa(Tt,-1));return}if(rn(de)&&Z==="0"){It(Qc().font_size);return}if(d==="logs"&&!Ae&&(de.sequence==="\\"||Z==="\\")){xt(),B(re?"Single log pane":"Split log panes");return}if(d==="logs"&&!Ae&&(de.sequence==="|"||Z==="|")){le();return}if(XS({...o,tui:e,confirmAction:Cr,planBusy:Lt,leaderTimer:kr,logDetailsScrollRef:u.logDetailsScrollRef,traceScrollRef:u.traceScrollRef,traceDetailScrollRef:u.traceDetailScrollRef,scrollTextScrollRef:u.scrollTextScrollRef,routeDetailsScrollRef:u.routeDetailsScrollRef,planScrollRef:u.planScrollRef,helpScrollRef:u.helpScrollRef,revertThemePreview:ur,setThemeName:dr},de))return;if(Ae){if(Z==="escape")z(!1);return}if(IS(de,e)){y("leader"),kr.current=setTimeout(()=>y("none"),Zr);return}if(DS(de,e)||fn(de,e)){V(""),K(0),X("commands"),y("slash");return}if(OS(de,e)){y("help");return}if(MS(de,e)||d==="logs"&&Z==="f"&&!de.ctrl&&!de.meta){te("logs"),z(!0);return}if(Z==="escape"||NS(de)){if(Z==="escape"){if(se){ue(!1);return}if(d==="detail"){te("services");return}if(d==="setup"&&t){te("dashboard");return}}let ft=Date.now();if(US(ft,nr.current)){nr.current=0,Sr();return}nr.current=ft,B(Z==="q"?"q again to quit":"Esc again to quit");return}if(Z==="z"&&(d==="logs"||d==="dashboard")&&!de.ctrl&&!de.meta){te("logs"),ue((ft)=>d==="logs"?!ft:!0);return}if(Z==="tab"){te(de.shift?Ek(d):Tk(d));return}let D={...o,tui:e,controller:t,cfg:r,snap:n,...i,...s,...a,...l,logService:re&&pt===1?Qe:Fe,setLogService:Oe,setDoctorTick:c.setDoctorTick,refreshAuth:c.refreshAuth,configScrollRef:u.configScrollRef,detailScrollRef:u.detailScrollRef,handleEnter:zt};if(lC(D,de))return;let we=nk(Z);if(we){te(we);return}cC(D,de)})}var pC=A(()=>{ne();si();so();Ut();Iu();Oa();Mr();Vr();QS();uC()});import{parse as dF,stringify as pF}from"yaml";function $u(e,t="imported"){let r=dF(e);if(!r||typeof r!=="object"||Array.isArray(r))throw Error("compose file is not a mapping");let n=r,o=ds(n.services)?n.services:{},i=[];if(n.networks!==void 0)i.push({service:"(root)",field:"networks",reason:fC.networks??"not modeled"});let s={},a=[];for(let[c,u]of Object.entries(o)){if(!ds(u))continue;let d=fF(c,u,i);if(s[c]=d.body,!d.container)a.push(c)}return{yaml:pF({version:1,project:{name:t},services:s,profiles:{default:{services:a}}}),dropped:i,services:Object.keys(s),profileServices:a}}function Hu(e){let t=[e.yaml.trimEnd(),"","Dropped fields:"];if(e.dropped.length===0)t.push("(none)");else{t.push("service\tfield\treason");for(let r of e.dropped)t.push(`${r.service} ${r.field} ${r.reason}`)}if(e.profileServices.length<e.services.length)t.push(""),t.push("Container services were omitted from profile default so first start does not require Docker.");return`${t.join(`
|
|
2481
2487
|
`)}
|
|
2482
|
-
`}function
|
|
2488
|
+
`}function fF(e,t,r){for(let f of Object.keys(t)){let p=fC[f];if(p)r.push({service:e,field:f,reason:p})}let n={},o=mC(t.command);if(o)n.command=o;let i=typeof t.working_dir==="string"?t.working_dir:typeof t.workingDir==="string"?t.workingDir:"";if(i!=="")n.working_dir=i;let s=mF(t.depends_on);if(s.length>0)n.dependencies=s;let a=hF(t.environment);if(Object.keys(a).length>0)n.environment={defaults:a};let l=gF(t.ports);if(l.host.length>0)n.ports=l.host;let c=yF(t.healthcheck);if(c)n.health=c;let u=typeof t.image==="string"?t.image:"",d=u!=="";if(d)n.container={image:u,...l.container&&Object.keys(l.container).length>0?{ports:l.container}:{},...Object.keys(a).length>0?{env:a}:{}};return{body:n,container:d}}function mC(e){if(typeof e==="string"&&e.trim()!=="")return["sh","-c",e];if(Array.isArray(e)&&e.every((t)=>typeof t==="string"))return e;return}function mF(e){if(Array.isArray(e))return e.filter((t)=>typeof t==="string");if(ds(e))return Object.keys(e);return[]}function hF(e){let t={};if(Array.isArray(e)){for(let r of e){if(typeof r!=="string")continue;let n=r.indexOf("=");if(n===-1)t[r]="";else t[r.slice(0,n)]=r.slice(n+1)}return t}if(ds(e))for(let[r,n]of Object.entries(e))t[r]=n===void 0||n===null?"":String(n);return t}function gF(e){let t=[],r={};if(!Array.isArray(e))return{host:t,container:r};let n=0;for(let o of e){let i=vF(o);if(!i)continue;n+=1;let s=n===1?"http":`port${n}`;t.push({name:s,value:i.host}),r[s]=i.container}return{host:t,container:r}}function vF(e){if(typeof e==="number"&&Number.isFinite(e))return{host:e,container:e};if(typeof e==="string"){let r=e.replace(/\/(tcp|udp)$/i,"").split(":"),n=Number(r[r.length-1]),o=r.length>1?Number(r[r.length-2]):n;if(!Number.isFinite(n)||!Number.isFinite(o))return;return{host:o,container:n}}if(ds(e)){let t=Number(e.published??e.target),r=Number(e.target??e.published);if(!Number.isFinite(t)||!Number.isFinite(r))return;return{host:t,container:r}}return}function yF(e){if(!ds(e)||e.disable===!0)return;let t=mC(e.test);if(!t||t[0]==="CMD"&&t.length===1||t[0]==="NONE")return;let r=t[0]==="CMD"||t[0]==="CMD-SHELL"?t.slice(1):t;if(r.length===0)return;return{type:"command",command:r}}function ds(e){return Boolean(e)&&typeof e==="object"&&!Array.isArray(e)}var fC;var Ah=A(()=>{fC={build:"not modeled; use a local command or pre-built image",networks:"not modeled",deploy:"not modeled",replicas:"not modeled",env_file:"per-service env_file is dropped; set environment.sources at the project level",volumes:"not modeled on import",labels:"not modeled",restart:"use service.restart in authoring",expose:"use ports",privileged:"not modeled",user:"not modeled",entrypoint:"not modeled; command is mapped when present",hostname:"not modeled",extra_hosts:"not modeled",cap_add:"not modeled",cap_drop:"not modeled",mem_limit:"not modeled",cpus:"not modeled",scale:"not modeled"}});function hC(e){let t=Object.keys(e.services).length,r=Object.keys(e.profiles).length,n=e.proxy.routes.length,o=Object.keys(e.tasks).length,i=[{text:e.project.name||"unnamed",tone:"primary"},{text:`schema ${e.version}`,tone:"muted"},{text:`${t} service${t===1?"":"s"}`,tone:t>0?"info":"idle"},{text:`${r} profile${r===1?"":"s"}`,tone:r>0?"info":"idle"},{text:e.proxy.enabled?"proxy on":"proxy off",tone:e.proxy.enabled?"success":"idle"}];if(n>0)i.push({text:`${n} route${n===1?"":"s"}`,tone:"info"});if(o>0)i.push({text:`${o} task${o===1?"":"s"}`,tone:"info"});return i}function gC(e,t){return[{label:"path",value:e.configPath||"\u2014"},{label:"repo",value:e.repoRoot||"\u2014"},{label:"devctl",value:t},{label:"schema",value:String(e.version)}]}function vC(e){return[{label:"project",value:e.google.project_id||"(unset)",tone:e.google.project_id?"text":"muted"},{label:"region",value:e.google.region||"(unset)",tone:e.google.region?"text":"muted"}]}function yC(e){let t=bF(e);return[{label:"exit",value:t,tone:t==="ask on quit"?"warning":"text"},{label:"grace",value:`${e.shutdown.grace_seconds}s`},{label:"refresh",value:`${py(e.auth)}s`},{label:"env",value:e.environment.sources.join(", ")||"\u2014",tone:e.environment.sources.length>0?"text":"muted"},{label:"theme",value:e.ui.theme||"system"}]}function bC(e){let t=e.logs.persistence;return[{label:"memory",value:`${e.logs.max_memory_events} events`},{label:"persist",value:t.enabled?t.directory:"off",tone:t.enabled?"text":"muted"},{label:"keep",value:t.enabled?`${t.retention_days}d \xB7 ${t.max_session_logs||"\u221E"} sessions`:"\u2014"}]}function wC(e){return[{label:"listen",value:Kn(e.proxy.listen),tone:e.proxy.enabled?"text":"muted"},{label:"token",value:kF(e),tone:e.proxy.token_endpoint.enabled?"text":"muted"}]}function xC(e){return Object.keys(e.services).sort().map((t)=>{let r=e.services[t]??qn();return{name:t,extends:r.extends||"\u2014",command:su(r),ports:Pa(r),identity:lu(r),health:au(r),depends:r.dependencies.map(Fl).join(", ")||"\u2014",restart:cu(r)}})}function kC(e){return e.proxy.routes.map((t)=>({name:t.name||t.match.host||"(unnamed)",match:SF(t),upstream:t.upstream.url||"\u2014",auth:t.auth.type||"none",identity:CF(t)}))}function SC(e){return Object.keys(e.profiles).sort().map((t)=>{let r=e.profiles[t],n=Object.keys(r?.environment??{}).sort();return{name:t,services:r?.services.join(", ")||"\u2014",env:n.length>0?n.join(", "):"\u2014"}})}function CC(e){return Object.keys(e.templates).sort().map((t)=>({name:t,summary:TF(e.templates[t])}))}function TC(e){return Object.keys(e.tasks).sort().map((t)=>{let r=e.tasks[t],n=r?.command.args.join(" ")||"\u2014",o=r?.dependencies.join(", ");return{name:t,summary:o?`${n} depends ${o}`:n}})}function EC(e,t){let r=Xn(e);if(r.length===0)return"No provenance recorded for this configuration.";let n=new Rr(e.secrets.extra_markers,e.secrets.extra_patterns);return r.map((o)=>{let i=typeof o.value==="string"?o.value:JSON.stringify(o.value),s=t?i:n.redactMap({[o.path]:i})[o.path],a=o.shadowed.length===0?"":`
|
|
2483
2489
|
shadowed ${o.shadowed.map((l)=>`${l.layer} \xB7 ${l.source}`).join("; ")}`;return`${o.path}
|
|
2484
2490
|
${o.layer} \xB7 ${o.source}
|
|
2485
2491
|
${s??""}${a}`}).join(`
|
|
2486
2492
|
|
|
2487
|
-
`)}function
|
|
2493
|
+
`)}function RC(e){let t=e.doctor.tools.map((i)=>i.name||i.command).filter((i)=>i!==""),r=e.plugins.map((i)=>i.path).filter((i)=>i!==""),n=Object.keys(e.ui.keymap),o=[...e.secrets.extra_markers,...e.secrets.extra_patterns];return[{label:"doctor",value:t.join(", ")||"\u2014",tone:t.length>0?"text":"muted"},{label:"plugins",value:r.join(", ")||"\u2014",tone:r.length>0?"text":"muted"},{label:"keymap",value:n.length>0?`${n.length} override${n.length===1?"":"s"}`:"defaults",tone:n.length>0?"text":"muted"},{label:"secrets",value:o.length>0?o.join(", "):"defaults",tone:o.length>0?"text":"muted"}]}function bF(e){if(e.shutdown.stop_services_on_exit===void 0)return"ask on quit";return e.shutdown.stop_services_on_exit?"stop services":"detach"}function _C(e){let t=e.reduce((r,n)=>Math.max(r,n.name.length),0);return Math.min(xF,Math.max(wF,t))}function kF(e){let t=e.proxy.token_endpoint;if(!t.enabled)return"off";let r=t.host===""?"127.0.0.1":t.host;if(t.port===0)return r;return`${r}:${t.port}`}function SF(e){let t=e.match.host||"*",r=e.match.path;if(r==="")return t;return`${t}${r.startsWith("/")?r:`/${r}`}`}function CF(e){if(e.auth.identity.service_account!=="")return e.auth.identity.service_account;if(e.auth.service_account!=="")return e.auth.service_account;return e.auth.identity.type||"user"}function TF(e){if(!e)return"empty";let t=[];if(e.health.type!=="")t.push(`health ${e.health.type}`);if(e.restart.policy!=="")t.push(`restart ${e.restart.policy}`);if(e.logs.stdout||e.logs.stderr)t.push("logs");return t.join(" \xB7 ")||"empty"}var wF=8,xF=20,PC=80,ps=10;var Lh=A(()=>{Ke();To();Ut()});async function Uu(e,t){e.suspend();try{return await t()}finally{e.resume(),e.intermediateRender()}}import{useCallback as EF,useRef as RF}from"react";function AC({setOverlay:e,setQuery:t,setSlashPicker:r,checked:n,setConfirmKind:o,setStatus:i,persistTheme:s,setPaletteIndex:a,themeName:l,setScreen:c,setSelected:u,screen:d,renderer:f,cfg:p,setScrollText:m,reveal:h,controller:g,refresh:w,profile:v,setReveal:S,resolveEnvironment:E,openDetail:_,copySelection:y,lastExportPath:b,openConfigBuffer:k,onDown:x,workspace:L,logView:F,diagnostics:B,lifecycleActions:K}){let{loginGoogle:V,detectGoogle:X,logoutGoogle:te,bootstrapLogPath:R,fileExists:U,readTextFile:O,writeTextFile:ae,validateConfigText:Ae,resolveExportPath:se,writeLogExport:z,exportsDir:ue,openInFileManager:re,listSessions:pt,loadSessionEvents:xt,checkUpdate:le,applyUpdate:Oe,formatUpdateStatus:Fe}=L,{setLogService:Qe,setLogsFullscreen:kt,setPaused:at,setErrorOnly:Lt,toggleSystemLogs:Se,clearLogs:St,logWrap:gt,setLogWrap:Ct,logServices:xr,errorOnly:lt,logLevel:It,logSearch:Ze,logRegex:Tt,logSource:ur,filteredLogs:dr,setLogRegex:Zr,setLogSince:pr,setLogUntil:nr,setLogs:kr,setLogSearch:Sr,toggleSplitLogs:Cr}=F,{refreshAuth:zt,setGoogle:de}=B,{beginStart:Z,beginStop:D,beginRestart:we}=K,ft=RF(!1);return{runCommand:EF(async(ct,Pe)=>{if(ft.current)return;if(ft.current=!0,ct.name!=="start"&&ct.name!=="stop"&&ct.name!=="restart")e("none");t("");let vn=Om(Pe,n);try{switch(ct.name){case"exit":o("quit"),e("confirm");return;case"down":{let P=Pe.includes("--keep-services")||Pe.includes("-k");x(P);return}case"help":e("help");return;case"version":i(vr()),le().then((P)=>i(Fe(P))).catch((P)=>i(I(P)));return;case"update":i("checking for update\u2026"),le().then(async(P)=>{if(!P.newer||!P.command){i(Fe(P));return}i(`installing ${P.current} \u2192 ${P.latest} via ${P.kind}\u2026`);let H=await Oe(P.command);if(H.code!==0){i(`update failed (${H.code}): ${(H.stderr||H.stdout).trim()||P.hint}`);return}i(`updated to ${P.latest}; ${kc}`)}).catch((P)=>i(I(P)));return;case"themes":if(Pe[0]){s(Pe[0]);return}a(Math.max(0,Pt.indexOf(l))),t(""),e("themes");return;case"settings":c("settings"),u(0);return;case"dashboard":case"services":c(ct.name);return;case"logs":if(Pe[0])Qe(Pe[0]);c("logs");return;case"fullscreen":c("logs"),kt((P)=>d==="logs"?!P:!0);return;case"split":c("logs"),Cr(),i("Split log panes");return;case"trace":{let P=Pe.join(" ").trim();if(P===""){i("usage: /trace <request-or-trace-id>");return}Sr(P),c("logs"),i(`tracing ${P}`);return}case"auth":{let P=(Pe[0]??"").toLowerCase();if(P==="refresh"){c("auth"),await zt();return}if(P==="login"){c("auth"),i("starting gcloud ADC login\u2026");try{await Uu(f,()=>V()),de(await X(p?.google.project_id??"")),await zt(),i("ADC login complete")}catch(H){i(I(H))}return}if(P==="logout"){c("auth"),i("revoking ADC\u2026");try{await te(),de(await X(p?.google.project_id??"")),await zt(),i("ADC revoked")}catch(H){i(I(H))}return}c("auth");return}case"credentials":case"proxy":case"mcp":case"config":case"profiles":case"setup":c(ct.name);return;case"import":{let P=Pe[0]??"",H=Pe.includes("--write"),ir=Pe.find((fr)=>fr!=="compose"&&fr!=="--write")??"compose.yaml";if(P!=="compose"){i("usage: /import compose [path] [--write]");return}if(!U(ir)){i(`compose file not found: ${ir}`);return}let go=p?.repoRoot||process.cwd(),Hr=p?.configPath||`${go}/.devctl/config.yaml`;try{let fr=$u(O(ir),go.split("/").pop()??"imported"),yn=Ae(go,Hr,fr.yaml),bn=`${Hu(fr)}${yn.length>0?`
|
|
2488
2494
|
validation:
|
|
2489
2495
|
${yn.map((vo)=>` ${vo}`).join(`
|
|
2490
2496
|
`)}
|
|
2491
2497
|
`:""}`;if(H){if(yn.length>0){m({title:"compose import",body:bn}),e("scroll-text"),i("import is invalid; not written");return}if(U(Hr)){i(`configuration already exists at ${Hr}; not overwriting`);return}ae(Hr,fr.yaml),i(`wrote ${Hr}; /reload to apply`);return}m({title:"compose import (dry-run)",body:`${bn}
|
|
2492
|
-
Enter is preview only. /import compose ${ir} --write to save.`}),e("scroll-text")}catch(fr){i(I(fr))}return}case"diff":if(!p){i("no configuration loaded");return}m({title:"config sources",body:
|
|
2493
|
-
`)),n("Config buffer not saved");return}if(i(e.configPath,g),p(""),r("none"),!s){n(`Wrote ${e.configPath}`);return}s.reload().then((v)=>{if(n(v.restart_required.length===0?"Configuration saved and reloaded":`Saved; restart required: ${v.restart_required.join(", ")}`),v.restart_required.length>0)a("reload"),r("confirm");l()})},[e,u,s,l]);return{configEditRef:c,configEditText:u,configEditError:f,setConfigEditError:p,openConfigBuffer:m,saveConfigBuffer:h}}var DC=A(()=>{ne()});import{useEffect as xF}from"react";function OC({controller:e,cfg:t,paused:r,logSince:n,refresh:o,setLogs:i,setCfg:s,setConfigReloadError:a,setStatus:l}){return xF(()=>{if(!e)return;let c,u=!1,d=[],f=t&&t.logs.max_memory_events>0?t.logs.max_memory_events:50000,p=()=>{if(c=void 0,d.length>0){let h=d.splice(0,d.length);i((g)=>z0(g,h,n,f))}if(u)u=!1,o()},m=e.onEvent((h)=>{if(h.type===yi&&h.payload&&typeof h.payload==="object"&&"event"in h.payload){let g=h.payload.event;if(!r)d.push(g);if(!c)c=setTimeout(p,30);return}if(h.type===Ts){a(uk(h));return}if(h.type===cl)a(void 0),e.configSnapshot().then(s).catch((g)=>l(I(g)));if(u=!0,!c)c=setTimeout(p,30)});return()=>{if(m(),c)clearTimeout(c)}},[e,n,r,o]),{}}var MC=A(()=>{ne();wr();br()});import{useCallback as kF,useEffect as NC,useRef as FC,useState as fs}from"react";function $C({controller:e,workspace:t,cfg:r,snap:n,screen:o,configReloadError:i,setSnap:s,setStatus:a}){let{detectGoogle:l,runDoctor:c,loadPath:u}=t,[d,f]=fs(),[p,m]=fs(),[h,g]=fs(!1),[w,v]=fs(""),[S,E]=fs(0),[_,y]=fs({active:"Preparing diagnostics",checks:[]}),b=FC(void 0),k=FC(0),x=kF(async()=>{if(!e){a("Supervisor is not running");return}a("Probing configured identities\u2026");try{let L=await e.refreshAuth();s((V)=>V?{...V,identity:L}:V);let F=Object.values(L.service_account_status),B=F.filter((V)=>V==="available").length,K=F.filter((V)=>V==="unavailable").length;a(F.length===0?"Identity refreshed \u2014 no service accounts configured":`Identity refreshed \u2014 ${B} available${K>0?`, ${K} unavailable`:""}`)}catch(L){a(I(L))}},[e]);return NC(()=>{l(r?.google.project_id??"").then(f).catch((L)=>{a(I(L))})},[r?.google.project_id,n?.identity.project]),NC(()=>{if(o!=="doctor"||!r)return;let L=b.current,F=n?.session_id??"";if(L?.cfg===r&&L.tick===S&&L.sessionID===F&&L.reloadError===i)return;b.current={cfg:r,tick:S,sessionID:F,reloadError:i};let B=++k.current;g(!0),v(""),y({active:"Preparing diagnostics",checks:[]});let K;if(r.configPath!==""){K="";try{u(r.repoRoot,r.configPath)}catch(V){K=I(V)}}c(r,(V)=>{if(B===k.current)y(V)},{services:n?.services,proxyRunning:n?.proxy.running,repositoryConfigError:K}).then((V)=>{if(B!==k.current)return;m(V)}).catch((V)=>{if(B!==k.current)return;v(I(V))}).finally(()=>{if(B===k.current)g(!1)})},[o,r,S,n?.session_id,i]),{google:d,setGoogle:f,doctor:p,doctorLoading:h,doctorError:w,doctorProgress:_,setDoctorTick:E,refreshAuth:x}}var HC=A(()=>{ne()});import{useCallback as Lh,useState as ju}from"react";function UC({controller:e,workspace:t,cfg:r,snap:n,refresh:o,setStatus:i,setOverlay:s}){let{resolveStartRequest:a,startupPlan:l,shutdownPlan:c,shutdownPlanExact:u}=t,[d,f]=ju(),[p,m]=ju([]),[h,g]=ju(!1),[w,v]=ju("start"),S=Lh(async(y,b)=>{if(!e||!r){i("no configuration loaded");return}try{let k=y.length>0,x=a(r,{services:y,profile:k?void 0:b}),L=l(r,x.services,x.profile);v("start"),m(L.waves.flat().filter((K)=>ri(n?.services[K]))),f(L),s("plan"),g(!0);let F=x.services.filter((K)=>!ri(n?.services[K])),B=await e.start({services:F.length>0?F:x.services,profile:k?void 0:x.profile});await o(),g(!1),i(ZS(B))}catch(k){g(!1),await o(),i(I(k))}},[r,e,o,n]),E=Lh(async(y)=>{if(!e||!r){i("no configuration loaded");return}let b=y.length>0?y:Object.entries(n?.services??{}).filter(([,k])=>k.state!=="STOPPED"&&k.state!=="UNKNOWN").map(([k])=>k);if(b.length===0){i("nothing to stop");return}try{let k=c(r,b);v("stop"),m([]),f(k),s("plan"),g(!0),await e.stop(y),await o(),g(!1),i(eC(k))}catch(k){g(!1),await o(),i(I(k))}},[r,e,o,n]),_=Lh(async(y,b,k=!1)=>{if(!e||!r){i("no configuration loaded");return}try{let x=QS(r,y,b),L=k?c(r,x.services):u(r,x.services);v("restart"),m([]),f(L),s("plan"),g(!0),await e.restart(x.services,k),await o(),g(!1);let F=Nu(L);i(F===""?"Restarted selected services":`Restarted ${F}`)}catch(x){g(!1),await o(),i(I(x))}},[r,e,o]);return{plan:d,planInitiallyRunning:p,planBusy:h,lifecycle:w,beginStart:S,beginStop:E,beginRestart:_}}var jC=A(()=>{ne();Fu();Ut()});import{useCallback as Xr,useEffect as mn,useMemo as po,useRef as Na,useState as Ee}from"react";function WC(e,t,r,n,o){let i=$m(e,t.sliceLen,t.windowStart,t.windowNewer);if(i.startDelta!==0){r(Math.max(0,t.windowStart+i.startDelta)),n(!0),o(i.selected);return}let s=Math.max(t.sliceLen-1,0),a=t.sliceLen>0&&(i.selected<s||t.windowNewer>0);if(a&&!t.pinned)r(fu(t.filteredLen));n(a),o(i.selected)}function zC({controller:e,tui:t,names:r,screen:n,refresh:o,setStatus:i}){let[s,a]=Ee([]),[l,c]=Ee(!1),[u,d]=Ee(!1),[f,p]=Ee(!0),[m,h]=Ee(""),[g,w]=Ee(!1),[v,S]=Ee(0),[E,_]=Ee(""),[y,b]=Ee(""),[k,x]=Ee(""),[L,F]=Ee(""),[B,K]=Ee(!1),[V,X]=Ee(0),[te,R]=Ee(Jr-1),[U,O]=Ee(!1),[ae,Ae]=Ee(0),se=BC,[z,ue]=Ee(t.log_timestamps!==!1),[re,pt]=Ee(t.log_metadata!==!1),[xt,le]=Ee(()=>[...W0]),[Oe]=Ee(""),[Fe]=Ee(""),[Qe,kt]=Ee(!1),[at,At]=Ee("all"),[Se,St]=Ee(!1),[gt,Ct]=Ee(Jr-1),[xr,lt]=Ee(!1),[Lt,Ze]=Ee(-1),[Tt,ur]=Ee(),[dr,Zr]=Ee(""),[pr,nr]=Ee(!1),[kr,Sr]=Ee(!1),Cr=Na([]),[zt,de]=Ee(0),Z=po(()=>hu(r,s,xt),[r,s,xt]);mn(()=>{le((ce)=>{let vt=new Set(ce),Et=!1;for(let wn of s)if(wn.service!==""&&!r.includes(wn.service)&&!vt.has(wn.service))vt.add(wn.service),Et=!0;return Et?[...vt].sort():ce})},[s,r]);let D=po(()=>ni(s,{service:k,services:se,errorOnly:u,search:m,regex:Qe,source:Fe,since:E,until:y,systemLogs:f}),[u,Qe,m,k,se,E,Fe,y,s,f]),we=po(()=>Fm(D,Se,zt),[D,Se,zt]),ft=we.items,or=po(()=>ni(s,{service:L,services:se,errorOnly:u,search:m,regex:Qe,source:Fe,since:E,until:y,systemLogs:f}),[u,Qe,m,L,se,E,Fe,y,s,f]),ct=po(()=>Fm(or,U,ae),[or,U,ae]),Pe=ct.items,vn=Na(0);vn.current=D.length;let P=Na(0);P.current=or.length;let H=Na(!1);H.current=Se;let ir=Na(!1);ir.current=U,mn(()=>{Ze(-1),H.current=!1,St(!1),Ct(Math.max(0,Math.min(Jr,D.length)-1))},[u,m,k,f]),mn(()=>{ir.current=!1,O(!1),R(Math.max(0,Math.min(Jr,or.length)-1))},[u,m,L,f]),mn(()=>{if(n!=="logs")lt(!1)},[n]),mn(()=>{if(n!=="logs"||Se)return;Ct(Math.max(0,Math.min(Jr,D.length)-1))},[D.length,Se,n]),mn(()=>{if(n!=="logs"||U)return;R(Math.max(0,Math.min(Jr,or.length)-1))},[or.length,U,n]);let go=Xr(()=>{if(H.current)return;H.current=!0,de(fu(vn.current)),St(!0)},[]),Hr=Xr(()=>{if(ir.current)return;ir.current=!0,Ae(fu(P.current)),O(!0)},[]),fr=po(()=>({sliceLen:ft.length,windowStart:we.start,windowNewer:we.newer,filteredLen:D.length,pinned:Se}),[D.length,Se,ft.length,we.newer,we.start]),yn=po(()=>({sliceLen:Pe.length,windowStart:ct.start,windowNewer:ct.newer,filteredLen:or.length,pinned:U}),[or.length,U,Pe.length,ct.newer,ct.start]),bn=Xr((ce)=>WC(ce,fr,de,St,Ct),[fr]),vo=Xr((ce)=>WC(ce,yn,Ae,O,R),[yn]),sd=Xr((ce)=>{if(B&&V===1){vo(ce);return}bn(ce)},[bn,vo,V,B]),ad=Xr((ce)=>{let vt=ft.length,Et=$m(ce,vt,we.start,we.newer);if(Et.startDelta!==0)de(Math.max(0,we.start+Et.startDelta)),St(!0);Ze(Et.selected)},[ft.length,we.newer,we.start]),ve=Xr(()=>{if(H.current=!1,ir.current=!1,St(!1),O(!1),Ze(-1),n==="logs")Ct(Math.max(0,Math.min(Jr,D.length)-1)),R(Math.max(0,Math.min(Jr,or.length)-1));S((vt)=>vt+1);let ce=Math.max(we.newer,ct.newer);i(ce>0?`Jumped to latest (+${ce} new)`:"Jumped to latest logs")},[D.length,or.length,we.newer,ct.newer,n]),Mn=po(()=>({services:B?BC:k!==""?[k]:se,level:u?"ERROR":Oe,search:m,regex:Qe,source:Fe,since:E,until:y}),[u,Oe,Qe,m,k,se,E,Fe,y,B]),yo=Xr(async()=>{if(!e)return;try{ur(await e.logsStats(Mn))}catch(ce){i(I(ce))}},[e,Mn]),Ba=Xr(async()=>{if(!e||l)return;try{let ce=await e.logsPage(Mn);a((vt)=>q0(vt,ce.events)),Zr(ce.prevCursor),nr(ce.hasPrev),await yo()}catch(ce){i(I(ce))}},[e,Mn,l,yo]),bs=Xr(()=>{H.current=!1,ir.current=!1,a([]),_(new Date().toISOString()),St(!1),O(!1),i("Cleared on-screen log buffer")},[]),ld=Xr(()=>{p((ce)=>!ce)},[]);return mn(()=>{o().then(()=>Ba())},[o,Ba]),mn(()=>{Cr.current=s},[s]),mn(()=>{let ce=Hm(Se,we.start,pr),vt=B&&Hm(U,ct.start,pr);if(!e||kr||!ce&&!vt)return;Sr(!0),e.logsPage({...Mn,cursor:dr,direction:"backward"}).then((Et)=>{if(Et.sessionChanged){i("Daemon session changed \u2014 older log history is no longer available"),nr(!1);return}let wn=Cr.current,Wa=G0(wn,Et.events);a(Wa);let ws=Wa.length-wn.length;if(ws>0){if(Se)de((xs)=>xs+ws);if(U)Ae((xs)=>xs+ws)}Zr(Et.prevCursor),nr(Et.hasPrev)}).catch((Et)=>i(I(Et))).finally(()=>Sr(!1))},[e,Mn,kr,pr,Se,U,dr,we.start,ct.start,B]),mn(()=>{if(!e||l||n!=="logs")return;let ce=setInterval(()=>{yo()},SF);return()=>clearInterval(ce)},[e,l,yo,n]),{logs:s,setLogs:a,paused:l,setPaused:c,errorOnly:u,setErrorOnly:d,showSystemLogs:f,logSearch:m,setLogSearch:h,logSearchFocused:g,setLogSearchFocused:w,logFollow:v,logSince:E,setLogSince:_,setLogUntil:b,logService:k,setLogService:x,logServiceB:L,setLogServiceB:F,splitLogs:B,splitFocus:V,setSplitFocus:X,toggleSplitLogs:()=>{if(B){X(0),K(!1);return}if(L===""){let ce=r.find((vt)=>vt!==k);if(ce!==void 0)F(ce)}K(!0)},cycleSplitFocus:()=>X((ce)=>ce===0?1:0),setActiveLogService:(ce)=>{let vt=(Et)=>typeof ce==="function"?ce(Et):ce;if(B&&V===1){F(vt);return}x(vt)},logSliceB:Pe,logWindowB:ct,logSelectedB:te,logPinnedB:U,logServices:se,logShowTimestamps:z,setLogShowTimestamps:ue,logShowMeta:re,setLogShowMeta:pt,logLevel:Oe,logSource:Fe,logRegex:Qe,setLogRegex:kt,logWrap:at,setLogWrap:At,logPinned:Se,logSelected:gt,logsFullscreen:xr,setLogsFullscreen:lt,dashboardLogCursor:Lt,setDashboardLogCursor:Ze,logFacets:Tt,logSources:Z,filteredLogs:D,filteredLogsB:or,logWindow:we,logSlice:ft,pinLogView:go,pinLogViewB:Hr,applyLogCursor:sd,applyLogCursorA:bn,applyLogCursorB:vo,applyDashboardLogCursor:ad,jumpToLatestLogs:ve,clearLogs:bs,toggleSystemLogs:ld}}var BC,SF=2000;var qC=A(()=>{ne();br();BC=[]});import{useCallback as ui,useState as GC}from"react";function KC({tui:e,controller:t,cfg:r,persistPrefs:n,snap:o,refresh:i,setStatus:s}){let[a,l]=GC(""),[c,u]=GC(()=>e.mcp_port??Xo(t?.cfg.repoRoot??process.cwd())),d=ui((v)=>{let S=to(v);u(S);let E=r?.repoRoot??process.cwd();if(Ex(E,S)){n({mcp_port:null},`MCP port ${S} (default)`);return}n({mcp_port:S},`MCP port ${S}`)},[r,n]),f=ui(()=>{if(a==="")return c;let v=Tx(a,c);return l(""),d(v),v},[c,a,d]),p=ui(async(v)=>{if(!t||o?.mcp?.running!==!0)return;await t.mcpStop(),await t.mcpStart({port:v}),await i()},[t,i,o?.mcp?.running]),m=ui(async(v)=>{if(!t){s("Supervisor is not running");return}let S=o?.mcp?.disabled_tools??[],E=no(v.name,S),_=E?[...S,v.name]:S.filter((y)=>y!==v.name);try{let y=await t.mcpSetTools(_);n({mcp_disabled_tools:y},`${v.label} ${E?"disabled":"enabled"}`),await i()}catch(y){s(I(y))}},[t,n,i,o]),h=ui(async()=>{if(!t){s("Supervisor is not running");return}try{if(o?.mcp?.running)await t.mcpStop(),n({mcp_enabled:!1},"MCP off"),s("MCP stopped");else await t.mcpStart({port:c}),n({mcp_enabled:!0},"MCP on"),s("MCP started");await i()}catch(v){s(I(v))}},[t,c,n,i,o?.mcp?.running]),g=ui((v)=>{Ru(v.text).then(()=>{s(`Copied ${v.title} snippet`)}).catch((S)=>{s(I(S))})},[]),w=ui((v)=>{let S=bh(v);if(S===void 0)return!1;let E=o?.mcp?.address??cs(o?.mcp?.port??c),_=Ia(E,o?.mcp?.token??"")[S];if(!_)return!1;return g(_),!0},[g,c,o?.mcp?.address,o?.mcp?.port,o?.mcp?.token]);return{mcpPortDraft:a,setMcpPortDraft:l,mcpPort:c,persistMcpPort:d,applyMcpPortDraft:f,restartMcpOnPort:p,toggleMcpTool:m,toggleMcp:h,copyMcpSnippet:g,copyFocusedMcpSnippet:w}}var VC=A(()=>{ne();Mu();Ji();eh();Oa()});import{RGBA as CF}from"@opentui/core";import{useCallback as Dn,useEffect as TF,useMemo as YC,useRef as Bu,useState as Wu}from"react";function JC({tui:e,controller:t,resolveTuiOverridePath:r,terminalBackground:n,userTuiConfigPath:o,snap:i,setStatus:s,saveTuiPreferences:a,setPaletteIndex:l,setOverlay:c,setConfirmKind:u,setScreen:d,setSelected:f,screen:p}){let[m,h]=Wu(e.theme||t?.cfg.ui.theme||"devctl"),g=Bu(m),[w,v]=Wu(e.mouse),S=Bu(e.mouse),[E,_]=Wu(e.leader_timeout),y=Bu(e.leader_timeout),[b,k]=Wu(()=>wa(e.font_size)),x=Bu(b),L=b0(r()),F=YC(()=>{let z=m0(m);if(Kc(m)!=="terminal"||!bm(n))return z;let ue=n??z.background;return{...z,background:ue,panel:ue,element:ue,inverse:ue}},[n,m]),B=Kc(m)==="terminal"&&bm(n)?CF.defaultBackground(n??void 0):F.background,K=YC(()=>S0({themeName:m,fontSize:b,mouse:w,leaderMs:E,locked:L,configPath:L?e.path||Cm(r(),o()):Cm(r(),o()),mcpRunning:i?.mcp?.running===!0}),[b,E,w,L,i?.mcp?.running,m,e.path]),V=Dn((z,ue)=>{if(L){s(`${ue} session only`);return}let re=a(z);s(`${ue} saved ${re}`)},[L]),X=Dn((z)=>{h(z),g.current=z,V({theme:z},`theme ${z}`)},[V]),te=Dn(()=>{let z=!w;v(z),S.current=z,V({mouse:z},`mouse ${z?"on":"off"} restart TUI to apply clicks`)},[w,V]),R=Dn((z)=>{_(z),y.current=z,V({leader_timeout:z},`leader ${z}ms`)},[V]),U=Dn((z)=>{let ue=wa(z);k(ue),x.current=ue,V({font_size:ue},`display ${Xc(ue)}`)},[V]),O=Dn(()=>{let z=Qc();h(z.theme),g.current=z.theme,v(z.mouse),S.current=z.mouse,_(z.leader_timeout),y.current=z.leader_timeout,k(z.font_size),x.current=z.font_size,V(z,"restored default preferences")},[V]),ae=Dn((z)=>{if(z.id==="theme"){l(Math.max(0,_t.indexOf(m))),c("themes");return}if(z.id==="mouse"){te();return}if(z.id==="leader"){R(E);return}if(z.id==="font"){U(b);return}if(z.id==="reset"){u("reset-prefs"),c("confirm");return}if(z.id==="mcp"){d("mcp"),f(0);return}s(z.detail)},[U,R,b,E,m,te]),Ae=Dn((z,ue)=>{let re=oo(K,ue);if(!re)return;if(re.id==="theme"){X(w0(m,z));return}if(re.id==="leader"){R(x0(E,z));return}if(re.id==="font"){U(xa(b,z));return}if(re.id==="mouse")te()},[U,R,b,E,X,K,m,te]),se=Dn(()=>{h(g.current)},[]);return TF(()=>{if(p==="settings")return;h(g.current),k(x.current),_(y.current),v(S.current)},[p]),{themeName:m,setThemeName:h,leaderMs:E,fontSize:b,prefsLocked:L,palette:F,rootBackground:B,settingRows:K,persistPrefs:V,persistTheme:X,toggleMouse:te,applyFont:U,applyReset:O,activateSetting:ae,cycleSetting:Ae,revertThemePreview:se}}var XC=A(()=>{Mr();rt()});import{jsxDEV as Fa}from"@opentui/react/jsx-dev-runtime";function QC(e){let{palette:t,termW:r,termH:n,step:o,answers:i,repo:s,draft:a,authStatus:l,onDraft:c,onSubmit:u}=e,d=Rt[o]??Rt[0],f=Rt.length,p=EF(d.id,i,s);return Fa(ot,{palette:t,title:`setup ${o+1}/${f} ${d.title}`,bottomTitle:"enter next \xB7 esc cancel",termW:r,termH:n,preferW:64,preferH:12,borderColor:t.primary,gap:1,children:[Fa("text",{fg:t.muted,wrapMode:"word",children:p},void 0,!1,void 0,this),d.id==="auth"||d.id==="write"||d.id==="repo"?Fa("text",{fg:t.text,wrapMode:"word",children:d.id==="auth"?l:d.id==="repo"?s:"Write .devctl/config.yaml and attach the daemon."},void 0,!1,void 0,this):Fa("input",{focused:!0,value:a,placeholder:d.prompt,onInput:c,onSubmit:u,backgroundColor:t.element,focusedBackgroundColor:t.element,textColor:t.text,cursorColor:t.primary},void 0,!1,void 0,this),Fa(mt,{palette:t,hints:[{key:"enter",label:d.id==="write"?"write and attach":"next"},{key:"esc",label:"cancel"}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Ih(e,t,r){if(e==="name")return t.name;if(e==="project")return t.project;if(e==="sa")return t.sa;if(e==="audience")return t.audience;if(e==="port")return String(t.proxyPort);if(e==="profile")return t.profile;if(e==="repo")return r;return""}function ZC(e,t,r,n){let o={...t};if(e==="name")o.name=r.trim()||Yn(n).name;else if(e==="project")o.project=r.trim();else if(e==="sa")o.sa=r.trim();else if(e==="audience")o.audience=r.trim();else if(e==="port")o.proxyPort=Ul(r,t.proxyPort);else if(e==="profile")o.profile=r.trim();return o}function EF(e,t,r){if(e==="repo")return`Using ${r}. The TUI always writes under this checkout.`;if(e==="auth")return"ADC login needs a real TTY. Enter continues; if ADC is missing, login runs gcloud on the terminal.";if(e==="write")return`Project ${t.name||"(unnamed)"}. Enter writes the starter file and attaches the daemon.`;return Rt.find((n)=>n.id===e)?.prompt??""}var Dh=A(()=>{jl();Re()});import{useCallback as Oh,useState as zu}from"react";function eT({workspace:e,renderer:t,setOverlay:r,setStatus:n,setScreen:o,onAttached:i,setController:s,setCfg:a,setBootError:l}){let c=process.cwd(),[u,d]=zu(0),[f,p]=zu(()=>Yn(c)),[m,h]=zu(""),[g,w]=zu("Checking Application Default Credentials\u2026"),v=Oh(()=>{let _=Yn(c);d(0),p(_),h(Ih("repo",_,c)),r("setup-wizard"),e.detectGoogle("").then((y)=>{p((b)=>({...b,project:y.projectID||b.project})),w(y.adcAvailable?`ADC available${y.userEmail?` (${y.userEmail})`:""}. Enter continues.`:"ADC is not available. Enter runs gcloud ADC login on this TTY, then continues.")})},[c,r,e]),S=Oh(async(_)=>{try{Wl(c,_);let y=await e.openTui(c,"");i?.(y),s(y),a(y.cfg),l(void 0),r("none"),o("dashboard"),n("Wrote .devctl/config.yaml and attached the daemon")}catch(y){n(I(y))}},[i,c,l,a,s,r,o,n,e]),E=Oh(async()=>{let _=Rt[u];if(!_)return;let y=ZC(_.id,f,m,c);if(_.id==="auth"){if(!(await e.detectGoogle(y.project)).adcAvailable)try{await Uu(t,()=>e.loginGoogle())}catch(L){n(I(L))}}if(p(y),_.id==="write"){await S(y);return}let b=Math.min(u+1,Rt.length-1),k=Rt[b];d(b),h(k?Ih(k.id,y,c):"")},[f,m,S,t,c,u,e,n]);return{step:u,answers:f,draft:m,authStatus:g,repo:c,setDraft:h,startWizard:v,advanceWizard:E}}var tT=A(()=>{jl();zl();ne();Dh()});import{useCallback as RF,useEffect as rT,useState as Mh}from"react";function nT({controller:e,cfg:t,envService:r}){let[n,o]=Mh(),[i,s]=Mh(!1),[a,l]=Mh(""),c=n?.name===r,u=c?n?.env:void 0,d=r===""?"config":i&&!c?"loading":c?"resolved":a!==""?"error":"config",f=c||r===""?"":a;rT(()=>{o(void 0),l("")},[t]),rT(()=>{if(!e||r===""||!t?.services[r])return;if(n?.name===r)return;let m=!1;return s(!0),l(""),e.execService(r,[],!0).then((h)=>{if(m)return;o({name:r,env:h.environment??{}}),l("")}).catch((h)=>{if(m)return;l(I(h))}).finally(()=>{s(!1)}),()=>{m=!0}},[t,e,r,n?.name]);let p=RF(async(m)=>{if(!e)return;try{let h=await e.execService(m,[],!0);o({name:m,env:h.environment??{}}),l("")}catch(h){throw l(I(h)),h}},[e]);return{inspectorEnv:u,inspectorEnvStatus:d,inspectorEnvError:f,resolveEnvironment:p}}var oT=A(()=>{ne()});import{jsxDEV as fo}from"@opentui/react/jsx-dev-runtime";function iT(e){let{palette:t,path:r,initialValue:n,error:o,termW:i,termH:s,textareaRef:a}=e;return fo(ot,{palette:t,title:"config buffer",bottomTitle:`${jt("s")} save \xB7 esc discard \xB7 e still opens $EDITOR`,termW:i,termH:s,preferW:88,preferH:28,gap:1,children:[fo("box",{height:1,overflow:"hidden",children:fo("text",{fg:t.muted,wrapMode:"none",children:r},void 0,!1,void 0,this)},void 0,!1,void 0,this),fo("textarea",{ref:a,focused:!0,initialValue:n,backgroundColor:t.panel,focusedBackgroundColor:t.panel,textColor:t.text,focusedTextColor:t.text,cursorColor:t.primary},void 0,!1,void 0,this),o!==""?fo("box",{height:2,overflow:"hidden",children:fo("text",{fg:t.error,wrapMode:"word",children:o},void 0,!1,void 0,this)},void 0,!1,void 0,this):fo("box",{height:1,overflow:"hidden",children:fo("text",{fg:t.muted,children:"validate, then write. invalid YAML is not saved."},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var sT=A(()=>{Re();Vr()});import{jsxDEV as Nh}from"@opentui/react/jsx-dev-runtime";function aT(e){let{palette:t,title:r,body:n,kind:o,termW:i,termH:s}=e,a=ck(o),l=a.map((c)=>`${c.key} ${c.label}`).join(" \xB7 ");return Nh(ot,{palette:t,title:r,bottomTitle:l,termW:i,termH:s,preferW:52,preferH:8,borderColor:t.warning,gap:1,children:[Nh("text",{fg:t.text,wrapMode:"word",children:n},void 0,!1,void 0,this),Nh(mt,{palette:t,hints:a},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var lT=A(()=>{wr();Re()});import{jsxDEV as cT}from"@opentui/react/jsx-dev-runtime";function uT(e){let{palette:t,termW:r,termH:n}=e,o=Km();return cT(ot,{palette:t,title:"leader",termW:r,termH:n,preferW:68,preferH:5,anchor:"bottom",children:cT(mt,{palette:t,hints:o},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var dT=A(()=>{si();Re()});import{jsxDEV as st,Fragment as Fh}from"@opentui/react/jsx-dev-runtime";function pT(e){let{palette:t,event:r,termW:n,termH:o,scrollRef:i,onViewTrace:s}=e;if(!r)return null;let a=r.traceId,l=typeof r.body==="object"&&r.body!==null?$0(r):void 0,c=r.raw&&r.raw!==Kt(r)?F0(r.raw):void 0,u=Object.entries(r.attributes),d=Kt(r).length>120||Kt(r).includes(`
|
|
2494
|
-
`)||l!==void 0||u.length>0,f=r.resource["process.pid"];return st(ot,{palette:t,title:"log details",bottomTitle:a?"enter view trace \xB7 j/k scroll \xB7 esc close":"j/k scroll \xB7 esc close",termW:n,termH:o,preferW:d?84:72,preferH:d?24:16,gap:1,children:st("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:st("box",{flexDirection:"column",overflow:"hidden",children:[st("text",{fg:t.text,wrapMode:"word",children:du(Kt(r))},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`time ${r.timestamp}`},void 0,!1,void 0,this),st("text",{fg:Ye(r.service,t),children:`service ${r.service}`},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`source ${r.source}${r.stream?` / ${r.stream}`:""}`},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`level ${Zi(r.severityText)} (${r.severityNumber})`},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`pid ${typeof f==="number"&&f>0?f:"\u2014"}`},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`trace ${a||"\u2014"}`},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`span ${r.spanId||"\u2014"}`},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`identity ${r.identity||"\u2014"}`},void 0,!1,void 0,this),r.scope?st("text",{fg:t.muted,children:`scope ${r.scope.name}${r.scope.version?` ${r.scope.version}`:""}`},void 0,!1,void 0,this):null,u.length===0?null:st(Fh,{children:[st("text",{fg:t.muted,children:"attributes"},void 0,!1,void 0,this),u.map(([p,m])=>st("text",{fg:t.text,wrapMode:"word",children:`${p} ${gr(m)}`},p,!1,void 0,this))]},void 0,!0,void 0,this),l===void 0?null:st(Fh,{children:[st("text",{fg:t.muted,children:"body"},void 0,!1,void 0,this),st("text",{fg:t.text,wrapMode:"word",children:l},void 0,!1,void 0,this)]},void 0,!0,void 0,this),c===void 0||c===l?null:st(Fh,{children:[st("text",{fg:t.muted,children:"raw"},void 0,!1,void 0,this),st("text",{fg:t.text,wrapMode:"word",children:c},void 0,!1,void 0,this)]},void 0,!0,void 0,this),a&&s?st("text",{fg:t.primary,onMouseDown:()=>s(a),children:"view trace \u21B5"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var fT=A(()=>{sn();br();Re();rt()});import{jsxDEV as G}from"@opentui/react/jsx-dev-runtime";function $h(e,t){switch(e){case"completed":return{icon:"\u2713",label:"Completed",tone:"success",color:t.success};case"failed":return{icon:"\u2717",label:"Failed",tone:"error",color:t.error};case"unhealthy":return{icon:"\u26A0",label:"Unhealthy",tone:"warning",color:t.warning};case"active":return{icon:"\u25CF",label:"In progress",tone:"primary",color:t.primary};default:return{icon:"\u25CB",label:"Queued",tone:"muted",color:t.muted}}}function _F(e,t,r,n){if(t!=="")return{icon:"\u2717",label:"Failed",tone:"error",color:n.error};if(!e)return{icon:"\u2713",label:"Finished",tone:"success",color:n.success};if(r==="unhealthy")return{icon:"\u26A0",label:"Waiting on health",tone:"warning",color:n.warning};return{icon:"\u25CF",label:"Running",tone:"primary",color:n.primary}}function mT(e){return G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:G("text",{wrapMode:"none",children:[G("span",{fg:e.palette.primary,children:e.label.toUpperCase()},void 0,!1,void 0,this),e.detail?G("span",{fg:e.palette.muted,children:` ${e.detail}`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function hT(e){let{palette:t,plan:r,snap:n,busy:o,failed:i,kind:s,termW:a=80,termH:l=24,scrollRef:c,initiallyRunning:u=[],onDismiss:d}=e,f=new Set(u),p=r.waves.map((X,te)=>({wave:X.filter((R)=>!f.has(R)),waveIdx:te})).filter(({wave:X})=>X.length>0),m=rC(r,n,s),h=r.waves[m.currentWaveIndex]??[],g=Ma(h,n,s),w=$h(g,t),v=_F(o,i,g,t),S=oC(s,o,i,r.profile),E=iC(o,i),_=i?t.inverse:t.text,y=i?t.error:t.element,b=Math.min(92,Math.max(40,a-8)),k=b>=82?22:b>=66?17:13,x=12,L=9,F=b>=56,B=b>=72,K=b<72||r.waves.length>3,V=r.profile?`PROFILE ${r.profile}`:s.toUpperCase();return G(ot,{palette:t,title:S,bottomTitle:"enter close \xB7 esc hide (operation continues)",termW:a,termH:l,preferW:98,preferH:28,borderColor:v.color,gap:0,children:[G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:[G(Ue,{palette:t,label:`${v.icon} ${v.label.toUpperCase()}`,tone:v.tone},void 0,!1,void 0,this),G("box",{paddingLeft:1,flexGrow:1,overflow:"hidden",children:G("text",{fg:t.text,wrapMode:"none",children:V},void 0,!1,void 0,this)},void 0,!1,void 0,this),G(Ue,{palette:t,label:`${m.ready}/${m.total} READY`,tone:m.isComplete?"success":"info"},void 0,!1,void 0,this),G(Ue,{palette:t,label:`WAVE ${Math.min(m.currentWaveIndex+1,Math.max(1,m.totalWaves))}/${Math.max(1,m.totalWaves)}`,tone:w.tone},void 0,!1,void 0,this)]},void 0,!0,void 0,this),G("box",{height:2,flexDirection:"column",overflow:"hidden",flexShrink:0,paddingLeft:1,paddingRight:1,children:[G("box",{height:1,flexDirection:"row",overflow:"hidden",children:[G("text",{wrapMode:"none",children:[G("span",{fg:t.muted,children:"PROGRESS "},void 0,!1,void 0,this),G("span",{fg:v.color,children:`[${m.progressBar}]`},void 0,!1,void 0,this),G("span",{fg:t.text,children:` ${m.percent}%`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),G("box",{flexGrow:1},void 0,!1,void 0,this),G("text",{wrapMode:"none",children:G("span",{fg:w.color,children:`${w.icon} ${w.label}`},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),G("box",{height:1,overflow:"hidden",children:G("text",{fg:t.muted,wrapMode:"none",children:o?s==="stop"?"Dependents stop first; each wave waits for the previous wave.":"Each wave waits until its services are healthy before the next wave starts.":E.primary},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),G(mT,{palette:t,label:"Pipeline",detail:`${r.waves.length} execution wave${r.waves.length===1?"":"s"}`},void 0,!1,void 0,this),G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:r.waves.map((X,te)=>{let R=Ma(X,n,s),U=$h(R,t),O=K?`W${te+1} ${U.icon} ${X.length}`:`W${te+1} ${U.icon} ${U.label} \xB7 ${X.length}`;return G("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:[G(Ue,{palette:t,label:O,tone:U.tone},void 0,!1,void 0,this),te<r.waves.length-1?G("box",{width:3,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:" \u2500\u25BA"},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},`step-${te}`,!0,void 0,this)})},void 0,!1,void 0,this),(r.blockers??[]).length>0?G("box",{minHeight:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,paddingLeft:1,children:G("text",{fg:t.error,wrapMode:"word",children:`BLOCKED ${r.blockers?.map((X)=>`${X.name}: ${X.message}`).join(" \xB7 ")}`},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,u.length>0?G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,paddingLeft:1,children:G("text",{wrapMode:"none",children:[G("span",{fg:t.success,children:"\u2713 ALREADY READY"},void 0,!1,void 0,this),G("span",{fg:t.muted,children:` ${u.join(", ")}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this):null,G(mT,{palette:t,label:"Wave details",detail:"live process and health state"},void 0,!1,void 0,this),G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,paddingLeft:1,children:[G("box",{width:2,flexShrink:0},void 0,!1,void 0,this),G("box",{width:k,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:j("SERVICE",k)},void 0,!1,void 0,this)},void 0,!1,void 0,this),G("box",{width:12,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:j("STATE",12)},void 0,!1,void 0,this)},void 0,!1,void 0,this),F?G("box",{width:9,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:j("PORT",9)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,B?G("box",{flexGrow:1,overflow:"hidden",children:G("text",{fg:t.muted,children:"DETAIL"},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),G("scrollbox",{ref:c,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:G("box",{flexDirection:"column",overflow:"hidden",gap:1,children:p.map(({wave:X,waveIdx:te})=>{let R=Ma(X,n,s),U=$h(R,t),O=`${nC(s,te,R)} \xB7 ${X.length} service${X.length===1?"":"s"}`;return G("box",{border:!0,borderStyle:"rounded",borderColor:U.color,title:O,titleColor:U.color,flexDirection:"column",paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:X.map((ae)=>{let Ae=n?.services[ae],se=yr(Ae),z=tC(ae,r,n,s),ue=ae===i||se==="FAILED",re=se==="UNHEALTHY",pt=se==="HEALTHY"||s==="stop"&&se==="STOPPED",xt=ti(Ae),le=ue?"\u2717":pt?"\u2713":re?"\u26A0":se==="STARTING"||se==="RUNNING"||se==="STOPPING"||se==="RESTARTING"?"\u25CF":"\u25CB",Oe=ue?t.error:dt(t,se),Fe=ue?t.error:re?t.warning:pt?t.success:t.muted;return G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[G("box",{width:2,flexShrink:0,overflow:"hidden",children:G("text",{fg:Oe,children:le},void 0,!1,void 0,this)},void 0,!1,void 0,this),G("box",{width:k,flexShrink:0,overflow:"hidden",children:G("text",{fg:Ye(ae,t),wrapMode:"none",children:j(ae,k)},void 0,!1,void 0,this)},void 0,!1,void 0,this),G("box",{width:12,flexShrink:0,overflow:"hidden",children:G("text",{fg:dt(t,se),wrapMode:"none",children:j(se,12)},void 0,!1,void 0,this)},void 0,!1,void 0,this),F?G("box",{width:9,flexShrink:0,overflow:"hidden",children:G("text",{fg:xt?t.info:t.muted,wrapMode:"none",children:j(xt?`:${xt}`:"\u2014",9)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,B?G("box",{flexGrow:1,overflow:"hidden",children:G("text",{fg:Fe,wrapMode:"none",children:z},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},ae,!0,void 0,this)})},`wave-card-${te}`,!1,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this),G("box",{height:3,flexShrink:0,flexDirection:"column",backgroundColor:y,border:["top"],borderStyle:"single",borderColor:v.color,paddingLeft:1,paddingRight:1,overflow:"hidden",onMouseDown:d,children:[G("text",{fg:_,wrapMode:"none",children:E.primary},void 0,!1,void 0,this),G("text",{fg:i?t.inverse:t.muted,wrapMode:"none",children:E.secondary},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var gT=A(()=>{nt();Fu();Ut();Re();rt()});import{jsxDEV as Fr}from"@opentui/react/jsx-dev-runtime";function vT(e){let{palette:t,route:r,termW:n,termH:o,scrollRef:i}=e;if(!r)return null;return Fr(ot,{palette:t,title:r.name,bottomTitle:"j/k scroll \xB7 esc close",termW:n,termH:o,preferW:78,preferH:18,gap:1,children:Fr("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:Fr("box",{flexDirection:"column",overflow:"hidden",children:[Fr("text",{fg:t.muted,children:`auth ${r.authType||"none"}`},void 0,!1,void 0,this),Fr("text",{fg:t.muted,children:`identity ${r.identityType||"\u2014"}`},void 0,!1,void 0,this),Fr("text",{fg:t.text,wrapMode:"word",children:`account ${r.serviceAccount||"\u2014"}`},void 0,!1,void 0,this),Fr("text",{fg:t.text,wrapMode:"word",children:`audience ${r.audience||"\u2014"}`},void 0,!1,void 0,this),Fr("text",{fg:t.muted,wrapMode:"word",children:`client id ${r.clientId||"ADC default"}`},void 0,!1,void 0,this),Fr("text",{fg:t.muted,wrapMode:"word",children:`client secret ${r.clientSecret||"\u2014"}`},void 0,!1,void 0,this),Fr("text",{fg:t.muted,children:`match host ${r.matchHost||"*"}`},void 0,!1,void 0,this),Fr("text",{fg:t.muted,children:`match path ${r.matchPath||"*"}`},void 0,!1,void 0,this),Fr("text",{fg:t.text,wrapMode:"word",children:`upstream ${r.upstream}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var yT=A(()=>{Re()});import{jsxDEV as qu}from"@opentui/react/jsx-dev-runtime";function bT(e){let{palette:t,title:r,body:n,termW:o,termH:i,scrollRef:s}=e,a=n.length>400||n.split(`
|
|
2495
|
-
`).length>16;return qu(ot,{palette:t,title:r,bottomTitle:"j/k scroll \xB7 esc close",termW:o,termH:i,preferW:a?88:76,preferH:a?24:16,gap:1,children:qu("scrollbox",{ref:s,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:qu("box",{flexDirection:"column",overflow:"hidden",children:qu("text",{fg:n===""?t.muted:t.text,wrapMode:"word",children:n===""?"(empty)":n},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var wT=A(()=>{Re()});import{jsxDEV as er}from"@opentui/react/jsx-dev-runtime";function xT(e){let{palette:t,items:r,query:n,selected:o,onQuery:i,onSubmit:s,title:a="commands"}=e,l=ii(n)!=="",c=Lk(o,Hh,r.length),u=l?r.slice(c,c+Hh):Ik(r,o,Hh),d=l?[{group:"",items:u}]:zm(u),f=Math.max(u.length+(l?0:d.length),1),p=os(r,o),m=Ek(r);return er("box",{height:f+PF,flexShrink:0,border:!0,borderStyle:"rounded",borderColor:t.borderActive,titleColor:t.primary,backgroundColor:t.panel,title:a,flexDirection:"column",overflow:"hidden",children:[u.length===0?er("box",{height:1,paddingLeft:1,overflow:"hidden",children:er("text",{fg:t.muted,children:"no matching command"},void 0,!1,void 0,this)},void 0,!1,void 0,this):d.flatMap((h)=>[...h.group===""?[]:[er("box",{height:1,paddingLeft:1,overflow:"hidden",backgroundColor:t.panel,children:er("text",{fg:t.muted,wrapMode:"none",children:h.group},void 0,!1,void 0,this)},`g-${h.group}`,!1,void 0,this)],...h.items.map((w)=>{let v=bu(w)===(p?bu(p):"");return er("box",{height:1,flexDirection:"row",overflow:"hidden",paddingLeft:1,paddingRight:1,backgroundColor:v?t.highlight:t.panel,children:[er("box",{width:m,flexShrink:0,overflow:"hidden",children:er("text",{fg:v?t.primary:t.text,wrapMode:"none",children:j(`${v?"\u203A":" "} /${qm(w).slice(0,Wm)}`,m)},void 0,!1,void 0,this)},void 0,!1,void 0,this),er("box",{flexGrow:1,overflow:"hidden",children:er("text",{fg:v?t.accent:t.muted,wrapMode:"none",children:Tk(w)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},bu(w),!0,void 0,this)})]),er("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.highlight,paddingLeft:1,children:[er("box",{width:2,flexShrink:0,children:er("text",{fg:t.primary,children:"/"},void 0,!1,void 0,this)},void 0,!1,void 0,this),er("box",{flexGrow:1,overflow:"hidden",children:er("input",{focused:!0,value:n,placeholder:"start logs settings",onInput:i,onSubmit:()=>s(),backgroundColor:t.highlight,focusedBackgroundColor:t.highlight,textColor:t.text,cursorColor:t.primary},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var Hh=10,PF=3;var kT=A(()=>{si();nt()});import{jsxDEV as TT}from"@opentui/react/jsx-dev-runtime";function ET(e){let{palette:t,themeName:r,selected:n,termW:o,termH:i,onIndex:s,onPreview:a,onPick:l}=e,c=_t.map((d)=>({name:d===r?`${d} (active)`:d,description:d===r?`${ym[d]} \xB7 current`:ym[d],value:d})),u=ns(o,i,ST,CT,"center",!Ln(ye()));return TT(ot,{palette:t,title:"/themes",bottomTitle:"enter save \xB7 esc revert",termW:o,termH:i,preferW:ST,preferH:CT,children:TT("select",{height:Math.max(4,u.height-3),options:c,selectedIndex:n,showDescription:!0,showSelectionIndicator:!0,wrapSelection:!0,backgroundColor:t.panel,focusedBackgroundColor:t.panel,textColor:t.text,focusedTextColor:t.text,selectedBackgroundColor:t.highlight,selectedTextColor:t.primary,descriptionColor:t.muted,selectedDescriptionColor:t.accent,onChange:(d)=>{s(d);let f=_t[d];if(f)a(f)},onSelect:(d,f)=>{let p=f?.value;if(typeof p==="string"&&p!=="")l(p)}},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var ST=52,CT=22;var RT=A(()=>{Ht();wr();Re();Mr();rt()});import{useEffect as AF,useRef as LF}from"react";import{jsxDEV as W}from"@opentui/react/jsx-dev-runtime";function _T(e){let{palette:t,trace:r,termW:n,termH:o,onSelect:i,onOpenLogs:s,scrollRef:a}=e,l=Ln(ye()),c=_S(n,o),u=ns(n,o,c.w,c.h,"center",!l),d=l?0:1,f=Math.max(oh-8,u.width-2-d*2),p=Math.max(ih-4,u.height-2-d*2),m=r?Pu(r):[],h=r?pS(r):void 0,g=PS(f,p),w=hS(g.listWidth,fS(m),mS(m)),v=Au(e.selected??0,m.length),S=LF({index:-1,at:0});if(AF(()=>{let _=a&&"current"in a?a.current:null;if(!_||m.length===0)return;let y=requestAnimationFrame(()=>{_.scrollChildIntoView(`trace-span-${v}`)});return()=>cancelAnimationFrame(y)},[m.length,a,v]),!r||!h)return null;let E=(_)=>{let y=Date.now(),b=kS(S.current.index,S.current.at,_,y);if(S.current={index:_,at:y},i?.(_),b)s?.(_)};return W(ot,{palette:t,title:u.width>=48?`trace ${r.traceId}`:`trace ${KF(r.traceId,12)}`,bottomTitle:"j/k span \xB7 enter or double-click logs \xB7 esc close",termW:n,termH:o,preferW:c.w,preferH:c.h,gap:0,children:[W(IF,{palette:t,facts:h,width:f,showServices:g.showServices,showLegend:g.showLegend},void 0,!1,void 0,this),W("box",{flexGrow:1,height:g.listHeight,flexDirection:"column",overflow:"hidden",children:[W(OF,{palette:t,cols:w,durationMs:h.durationMs},void 0,!1,void 0,this),W("scrollbox",{ref:a,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:W("box",{flexDirection:"column",overflow:"hidden",children:m.length===0?W("text",{fg:t.muted,children:"no spans in this trace yet"},void 0,!1,void 0,this):m.map((_,y)=>W(MF,{id:`trace-span-${y}`,palette:t,row:_,cols:w,facts:h,active:y===v,onPick:()=>E(y)},`${_.span.spanId}-${_.span.seq}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function PT(e){let{palette:t,span:r,records:n=[],termW:o,termH:i,scrollRef:s}=e;if(!r)return null;return W(ot,{palette:t,title:VF(`${lh(r.kind)} ${r.name}`),bottomTitle:"j/k scroll \xB7 esc back to trace",termW:o,termH:i,preferW:84,preferH:28,gap:0,children:W(NF,{palette:t,span:r,records:n,scrollRef:s},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function IF(e){let{palette:t,facts:r,width:n,showServices:o,showLegend:i}=e,s=TS(CS(r),n),a=ES(r.services,n);return W("box",{flexShrink:0,flexDirection:"column",overflow:"hidden",children:[W("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:s.map((l)=>W(DF,{palette:t,chip:l},l.id,!1,void 0,this))},void 0,!1,void 0,this),o&&a!==""?W("text",{fg:t.muted,wrapMode:"none",children:a},void 0,!1,void 0,this):null,i?W("text",{fg:t.muted,wrapMode:"none",children:RS(n)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function DF(e){let{palette:t,chip:r}=e;return W(Ue,{palette:t,label:r.label,tone:r.tone},void 0,!1,void 0,this)}function OF(e){let{palette:t,cols:r,durationMs:n}=e,o=xS(r),i=gS(r);return W("box",{flexShrink:0,flexDirection:"column",overflow:"hidden",children:[W("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[W(tr,{width:r.tree,fg:t.muted,text:o.tree,raw:!0},void 0,!1,void 0,this),W(tr,{width:r.service,fg:t.muted,text:o.service,raw:!0},void 0,!1,void 0,this),W(tr,{width:r.name,fg:t.muted,text:o.name,raw:!0},void 0,!1,void 0,this),W(tr,{width:r.duration,fg:t.muted,text:o.duration,raw:!0},void 0,!1,void 0,this),W(tr,{width:r.bar,fg:t.muted,text:o.bar,raw:!0},void 0,!1,void 0,this)]},void 0,!0,void 0,this),W("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[W(tr,{width:i,fg:t.muted,text:""},void 0,!1,void 0,this),W(tr,{width:r.bar,fg:t.muted,text:wS(n,r.bar),raw:!0},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function MF(e){let{id:t,palette:r,row:n,cols:o,facts:i,active:s,onPick:a}=e,l=typeof n.span.resource["service.name"]==="string"?n.span.resource["service.name"]:"\u2014",c=ah(n.span),u=Math.max(1,i.endUnixNano-i.startUnixNano),d=yS(n.span,i.startUnixNano,u),f=bS(d.offset,d.width,o.bar),p=n.span.status.code==="error",m=p?r.error:GF(r,n.span.kind);return W("box",{id:t,height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:s?r.highlight:void 0,onMouseDown:a,children:[W(tr,{width:o.tree,fg:m,text:vS(n.depth,n.span.kind,o.tree,s),raw:!0},void 0,!1,void 0,this),W(tr,{width:o.service,fg:Ye(l,r),text:l},void 0,!1,void 0,this),W(tr,{width:o.name,fg:p?r.error:r.text,text:n.span.name},void 0,!1,void 0,this),W(tr,{width:o.duration,fg:r.muted,text:li(c)},void 0,!1,void 0,this),W(zF,{width:o.bar,trackFg:r.muted,fillFg:m,lead:f.lead,fill:f.fill,trail:f.trail},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function NF(e){let{palette:t,span:r,records:n,scrollRef:o}=e,i=typeof r.resource["service.name"]==="string"?r.resource["service.name"]:"\u2014",s=Object.entries(r.attributes),a=r.status.code==="error";return W("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:W("scrollbox",{ref:o,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:W("box",{flexDirection:"column",overflow:"hidden",children:[W(mo,{palette:t,label:"status",value:qF(r),tone:a?"error":"text"},void 0,!1,void 0,this),W(mo,{palette:t,label:"kind",value:lh(r.kind)},void 0,!1,void 0,this),W(mo,{palette:t,label:"service",value:i},void 0,!1,void 0,this),W(mo,{palette:t,label:"duration",value:li(ah(r))},void 0,!1,void 0,this),W(mo,{palette:t,label:"trace",value:r.traceId},void 0,!1,void 0,this),W(mo,{palette:t,label:"span",value:r.spanId},void 0,!1,void 0,this),W(mo,{palette:t,label:"parent",value:r.parentSpanId||"\u2014"},void 0,!1,void 0,this),r.scope?W(mo,{palette:t,label:"scope",value:`${r.scope.name}${r.scope.version?` ${r.scope.version}`:""}`},void 0,!1,void 0,this):null,s.length===0?null:W("text",{fg:t.muted,children:"attributes"},void 0,!1,void 0,this),s.map(([l,c])=>W("text",{fg:t.text,wrapMode:"word",children:`${l} ${gr(c)}`},l,!1,void 0,this)),r.events.length===0?null:W("text",{fg:t.muted,children:`events ${r.events.length}`},void 0,!1,void 0,this),r.events.map((l,c)=>W("box",{flexDirection:"column",overflow:"hidden",children:[W("text",{fg:t.info,wrapMode:"word",children:`+${li(SS(r,l.timeUnixNano))} ${l.name}`},void 0,!1,void 0,this),Object.entries(l.attributes).map(([u,d])=>W("text",{fg:t.muted,wrapMode:"word",children:` ${u} ${gr(d)}`},u,!1,void 0,this))]},`${l.name}-${c}`,!0,void 0,this)),W(BF,{palette:t,records:n,spanId:r.spanId},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function BF(e){let{palette:t,records:r,spanId:n}=e;if(r.length===0)return W("text",{fg:t.muted,children:"logs none"},void 0,!1,void 0,this);let o=WF(r);return W("box",{flexDirection:"column",overflow:"hidden",children:[W("text",{fg:t.muted,children:`logs ${r.length} \xB7 \u2192 this span`},void 0,!1,void 0,this),r.map((i)=>{let s=n!==void 0&&i.spanId===n,a=Kt(i);return W("box",{flexShrink:0,flexDirection:"row",alignItems:"flex-start",overflow:"hidden",children:[W(tr,{width:FF,fg:s?t.primary:t.muted,text:s?"\u2192":""},void 0,!1,void 0,this),W(tr,{width:$F,fg:t.muted,text:i.timestamp.slice(11,19)},void 0,!1,void 0,this),W(tr,{width:o,fg:s?t.primary:t.text,text:i.service},void 0,!1,void 0,this),W(tr,{width:HF,fg:s?t.primary:t.muted,text:Zi(i.severityText)},void 0,!1,void 0,this),W("box",{flexGrow:1,flexShrink:1,minWidth:0,overflow:"hidden",children:W("text",{fg:s?t.primary:t.text,wrapMode:"word",flexShrink:0,width:"100%",children:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},i.seq,!0,void 0,this)})]},void 0,!0,void 0,this)}function WF(e){return Math.min(jF,Math.max(UF,e.reduce((t,r)=>Math.max(t,r.service.length),0)))}function mo(e){let{palette:t,label:r,value:n,tone:o="text"}=e;return W("text",{fg:o==="error"?t.error:t.text,wrapMode:"word",children:`${j(r,10)}${n}`},void 0,!1,void 0,this)}function zF(e){let{width:t,trackFg:r,fillFg:n,lead:o,fill:i,trail:s}=e;return W("box",{width:t,flexShrink:0,overflow:"hidden",children:W("text",{wrapMode:"none",children:[W("span",{fg:r,children:o},void 0,!1,void 0,this),W("span",{fg:n,children:i},void 0,!1,void 0,this),W("span",{fg:r,children:s},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function tr(e){let{width:t,fg:r,text:n,raw:o}=e;return W("box",{width:t,flexShrink:0,overflow:"hidden",children:W("text",{fg:r,wrapMode:"none",children:o?n:j(n,t)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function qF(e){let t=dS(e.status.code);return e.status.message?`${t} ${e.status.message}`:t}function GF(e,t){if(t==="server")return e.info;if(t==="client")return e.primary;if(t==="producer"||t==="consumer")return e.accent;return e.muted}function KF(e,t){if(e.length<=t)return e;return`${e.slice(0,t)}\u2026`}function VF(e){return e.length<=42?e:`${e.slice(0,41)}\u2026`}var FF=2,$F=9,HF=8,UF=8,jF=14;var AT=A(()=>{sn();wr();nt();br();Lu();Re();Mr();rt();Ht()});function Gu(e,t,r){let n=e?.google?.project_id??"";if(n!=="")return{project:n,source:"configuration"};let o=t?.project||r?.projectID||"",i=t?.project_source||r?.projectSource||"";return{project:o,source:i}}import{jsxDEV as ht}from"@opentui/react/jsx-dev-runtime";function Ku(e){let{palette:t,title:r,tone:n="muted",children:o}=e,i=n==="success"?t.success:n==="warning"?t.warning:n==="error"?t.error:t.border;return ht("box",{border:!0,borderStyle:"rounded",borderColor:i,title:r,titleColor:i,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,marginBottom:1,overflow:"hidden",children:o},void 0,!1,void 0,this)}function LT(e){let{palette:t,cfg:r,google:n,identity:o}=e;if(!n&&!o)return ht(Eu,{palette:t,label:"Checking Application Default Credentials\u2026"},void 0,!1,void 0,this);let i=YF(r,o),s=o?.user||n?.userEmail||"",{project:a,source:l}=Gu(r,o,n),c=o?.adc??n?.adcAvailable===!0,u=o?.iap??(r?.proxy.routes??[]).some((h)=>h.auth.type.toLowerCase()==="iap"),d=i.filter((h)=>h.inactive!==!0),f=d.some((h)=>h.ok===!0),p=d.some((h)=>h.ok===!1),m=f?"AVAILABLE":p?"UNAVAILABLE":d.length>0?"NOT PROBED":i.length>0?"not required":"not configured";return ht(Pt,{palette:t,title:"identity",scroll:!0,children:[ht(Ku,{palette:t,title:"Google identity",tone:c?"success":"warning",children:[ht(ai,{palette:t,label:"user",value:s||"(unknown)"},void 0,!1,void 0,this),ht(ai,{palette:t,label:"project",value:a||"(unset)"},void 0,!1,void 0,this),ht(ai,{palette:t,label:"source",value:l||"\u2014"},void 0,!1,void 0,this),ht(ai,{palette:t,label:"ADC",value:c?"\u2713 available":"\u2717 missing",tone:c?"success":"error"},void 0,!1,void 0,this),ht(ai,{palette:t,label:"gcloud",value:n?.gcloudInstalled?"\u2713 installed":"\u2717 not installed",tone:n?.gcloudInstalled?"success":"error"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ht(Ku,{palette:t,title:`Service accounts (${i.length})`,tone:d.length===0?"muted":f?"success":"warning",children:[i.length===0?ht("text",{fg:t.muted,wrapMode:"word",children:"none configured \u2014 identities come from config, never hard-coded"},void 0,!1,void 0,this):i.map((h)=>ht("text",{fg:h.inactive?t.muted:h.ok===!0?t.success:h.ok===!1?t.error:t.text,wrapMode:"none",children:`${h.inactive?"\u2013":h.ok===!0?"\u2713":h.ok===!1?"\u2717":"\u25CB"} ${h.email}${h.inactive?" \u2014 inactive (route auth is none)":""}`},h.email,!1,void 0,this)),ht("box",{height:1,flexShrink:0},void 0,!1,void 0,this),ht(ai,{palette:t,label:"impersonation",value:m,tone:f?"success":d.length>0?"warning":"muted"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ht(Ku,{palette:t,title:"IAP",tone:u?"success":"muted",children:[ht("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:ht(Ue,{palette:t,label:u?"routes present":"no IAP routes",tone:u?"success":"idle"},void 0,!1,void 0,this)},void 0,!1,void 0,this),u?ht("text",{fg:t.muted,wrapMode:"word",children:"each route needs its own audience"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),!c?ht(Ku,{palette:t,title:"ADC unavailable",tone:"warning",children:[ht("text",{fg:t.text,wrapMode:"word",children:"Local services still start. Cloud identity, impersonation, and IAP need ADC."},void 0,!1,void 0,this),ht("text",{fg:t.muted,wrapMode:"word",children:"/auth login suspends this screen and runs gcloud ADC login, then restores the TUI"},void 0,!1,void 0,this)]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this)}function YF(e,t){let r=new Map((e?Jp(e):[]).map((i)=>[i.email,i.active])),n=t?.service_account_status??{};return[...new Set([...r.keys(),...Object.keys(n)])].sort((i,s)=>i.localeCompare(s)).map((i)=>{let s=n[i]??"unknown",a=r.get(i)===!1;return{email:i,inactive:a,ok:a||s==="unknown"?void 0:s==="available"}})}var IT=A(()=>{Gr();cr();Re()});import{jsxDEV as N}from"@opentui/react/jsx-dev-runtime";function NT(e){let{palette:t,cfg:r,width:n,selectedTask:o=0}=e,i=ye();if(!r)return N(it,{palette:t,title:"No configuration",body:"Create .devctl/config.yaml or run setup."},void 0,!1,void 0,this);let s=Math.max(ps+8,n-6-i.pad*2),a=s>=RC,l=a?Math.floor((s-OT)/2):s,c=bC(r),u=wC(r),d=xC(r),f=kC(r),p=SC(r);return N(Pt,{palette:t,title:`config ${r.project.name||"unnamed"}`,children:[N(wt,{palette:t,items:fC(r)},void 0,!1,void 0,this),N("box",{flexGrow:1,overflow:"hidden",children:N("scrollbox",{ref:e.scrollRef,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:N("box",{flexDirection:"column",overflow:"hidden",gap:MT,children:[N(Uh,{wide:a,left:N(hn,{palette:t,title:"project",children:N(ms,{palette:t,facts:mC(r,Xt),width:l},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:N(hn,{palette:t,title:"google",children:N(ms,{palette:t,facts:hC(r),width:l},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N(Uh,{wide:a,left:N(hn,{palette:t,title:"runtime",children:N(ms,{palette:t,facts:gC(r),width:l},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:N(hn,{palette:t,title:"logs",children:N(ms,{palette:t,facts:vC(r),width:l},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N(hn,{palette:t,title:`proxy ${r.proxy.enabled?"enabled":"disabled"}`,children:[N(ms,{palette:t,facts:yC(r),width:s},void 0,!1,void 0,this),N(XF,{palette:t,routes:u,width:s},void 0,!1,void 0,this)]},void 0,!0,void 0,this),N(hn,{palette:t,title:`services ${c.length}`,children:N(JF,{palette:t,rows:c,width:s},void 0,!1,void 0,this)},void 0,!1,void 0,this),N(hn,{palette:t,title:`tasks ${p.length}`,children:N(DT,{palette:t,rows:p,empty:"no tasks",width:s,selected:o},void 0,!1,void 0,this)},void 0,!1,void 0,this),N(Uh,{wide:a,left:N(hn,{palette:t,title:`profiles ${d.length}`,children:N(QF,{palette:t,rows:d,width:l},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:N(hn,{palette:t,title:`templates ${f.length}`,children:N(DT,{palette:t,rows:f,empty:"no templates",width:l},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N(hn,{palette:t,title:"extras",children:N(ms,{palette:t,facts:TC(r),width:s},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N(Zt,{palette:t,backgroundColor:t.element,edge:"top",children:N(mt,{palette:t,hints:[{key:"v",label:"validate/save buffer"},{key:"e",label:"open in $EDITOR"},{key:"/diff",label:"config sources"},{key:"/reload",label:"re-read .devctl after editing"},{key:"enter",label:"run task"},{key:"j/k",label:"scroll"}]},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Uh(e){let{wide:t,left:r,right:n}=e;if(!t)return N("box",{flexDirection:"column",overflow:"hidden",gap:MT,flexShrink:0,children:[r,n]},void 0,!0,void 0,this);return N("box",{flexDirection:"row",overflow:"hidden",gap:OT,flexShrink:0,children:[N("box",{flexGrow:1,flexBasis:0,overflow:"hidden",children:r},void 0,!1,void 0,this),N("box",{flexGrow:1,flexBasis:0,overflow:"hidden",children:n},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function hn(e){let{palette:t,title:r,children:n}=e;return N("box",{border:!0,borderStyle:"rounded",borderColor:t.border,title:r,titleColor:t.accent,paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",flexShrink:0,children:n},void 0,!1,void 0,this)}function ms(e){let{palette:t,facts:r,width:n}=e,o=Math.max(4,n-ps-4);return N("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((i)=>N("box",{height:1,flexDirection:"row",overflow:"hidden",children:[N("box",{width:ps,flexShrink:0,overflow:"hidden",children:N("text",{fg:t.muted,wrapMode:"none",children:j(i.label,ps)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N("box",{width:o,flexShrink:0,overflow:"hidden",children:N("text",{fg:t$(t,i.tone),wrapMode:"none",children:j(i.value,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},i.label,!0,void 0,this))},void 0,!1,void 0,this)}function JF(e){let{palette:t,rows:r,width:n}=e;if(r.length===0)return N(Vu,{palette:t,text:"no services"},void 0,!1,void 0,this);let o=EC(r),i=Math.max(8,n-o-6);return N("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((s)=>N("box",{height:1,flexDirection:"row",overflow:"hidden",children:[N("box",{width:o,flexShrink:0,overflow:"hidden",children:N("text",{fg:Ye(s.name,t),wrapMode:"none",children:j(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N("box",{width:i,flexShrink:0,overflow:"hidden",children:N("text",{fg:t.text,wrapMode:"none",children:ke(ZF(s),i)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},s.name,!0,void 0,this))},void 0,!1,void 0,this)}function XF(e){let{palette:t,routes:r,width:n}=e;if(r.length===0)return N(Vu,{palette:t,text:"no routes"},void 0,!1,void 0,this);let o=Math.min(ps+4,Math.max(8,...r.map((s)=>s.name.length))),i=Math.max(8,n-o-6);return N("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((s)=>N("box",{height:1,flexDirection:"row",overflow:"hidden",children:[N("box",{width:o,flexShrink:0,overflow:"hidden",children:N("text",{fg:t.primary,wrapMode:"none",children:j(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N("box",{width:i,flexShrink:0,overflow:"hidden",children:N("text",{fg:t.text,wrapMode:"none",children:ke(e$(s),i)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},`${s.name}-${s.match}`,!0,void 0,this))},void 0,!1,void 0,this)}function QF(e){let{palette:t,rows:r,width:n}=e;if(r.length===0)return N(Vu,{palette:t,text:"no profiles"},void 0,!1,void 0,this);let o=Math.min(12,Math.max(8,...r.map((s)=>s.name.length))),i=Math.max(8,n-o-6);return N("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((s)=>N("box",{height:1,flexDirection:"row",overflow:"hidden",children:[N("box",{width:o,flexShrink:0,overflow:"hidden",children:N("text",{fg:t.primary,wrapMode:"none",children:j(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N("box",{width:i,flexShrink:0,overflow:"hidden",children:N("text",{fg:t.text,wrapMode:"none",children:ke(s.env==="\u2014"?s.services:`${s.services} env ${s.env}`,i)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},s.name,!0,void 0,this))},void 0,!1,void 0,this)}function DT(e){let{palette:t,rows:r,empty:n,width:o,selected:i}=e;if(r.length===0)return N(Vu,{palette:t,text:n},void 0,!1,void 0,this);let s=Math.min(14,Math.max(8,...r.map((l)=>l.name.length))),a=Math.max(8,o-s-6);return N("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((l,c)=>{let u=i===c;return N("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:u?t.highlight:void 0,children:[N("box",{width:s,flexShrink:0,overflow:"hidden",children:N("text",{fg:u?t.primary:t.text,wrapMode:"none",children:j(l.name,s)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N("box",{width:a,flexShrink:0,overflow:"hidden",children:N("text",{fg:u?t.accent:t.muted,wrapMode:"none",children:ke(l.summary,a)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},l.name,!0,void 0,this)})},void 0,!1,void 0,this)}function Vu(e){return N("box",{height:1,overflow:"hidden",children:N("text",{fg:e.palette.muted,wrapMode:"none",children:e.text},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function ZF(e){let t=e.extends==="\u2014"?"":` ${e.extends}`;return` ${e.ports} ${e.identity} ${e.health} ${e.restart} \u2190 ${e.depends}${t}`}function e$(e){return` ${e.auth} ${e.identity} ${e.match} \u2192 ${e.upstream}`}function t$(e,t){if(t==="success")return e.success;if(t==="warning")return e.warning;if(t==="error")return e.error;if(t==="muted")return e.muted;return e.text}var OT=1,MT=1;var FT=A(()=>{cr();Ah();Ht();nt();Re();rt()});import{jsxDEV as Wt}from"@opentui/react/jsx-dev-runtime";function $T(e){let{palette:t,credentials:r}=e;if(!r)return Wt(Eu,{palette:t,label:"Reading credential store\u2026"},void 0,!1,void 0,this);let n=r.entries.filter((i)=>i.valid).length,o=r.entries.length-n;return Wt(Pt,{palette:t,title:"credentials",scroll:!0,children:[Wt("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[Wt(Ue,{palette:t,label:`backend: ${r.backend}`,tone:"info"},void 0,!1,void 0,this),r.entries.length>0?Wt(Ue,{palette:t,label:`${n} valid`,tone:"success"},void 0,!1,void 0,this):null,o>0?Wt(Ue,{palette:t,label:`${o} expired`,tone:"warning"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),Wt("text",{fg:t.muted,wrapMode:"word",children:"Tokens stay in the OS keychain or ~/.devctl/credentials (0600). They are never shown here."},void 0,!1,void 0,this),Wt("box",{height:1,flexShrink:0},void 0,!1,void 0,this),r.entries.length===0?Wt("text",{fg:t.muted,children:"no cached credentials"},void 0,!1,void 0,this):Wt("box",{flexDirection:"column",overflow:"hidden",gap:1,children:r.entries.map((i)=>Wt("box",{border:!0,borderStyle:"rounded",borderColor:i.valid?t.success:t.warning,title:i.identity,titleColor:i.valid?t.success:t.warning,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",children:[Wt("text",{wrapMode:"none",children:[Wt("span",{fg:i.valid?t.success:t.warning,children:i.valid?"\u2713 valid":"\u2717 expired"},void 0,!1,void 0,this),Wt("span",{fg:t.muted,children:` \xB7 expires ${i.expires_at}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Wt("text",{fg:t.muted,wrapMode:"none",children:`audience: ${i.audience||"(none)"}`},void 0,!1,void 0,this)]},`${i.identity}|${i.audience}`,!0,void 0,this))},void 0,!1,void 0,this),Wt(Tu,{palette:t,title:"Actions",body:"Use /refresh to mint again or auth refresh on the CLI. Invalidate clears the store without printing tokens.",hint:"/refresh /auth"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var HT=A(()=>{cr();Re()});import{jsxDEV as Yu}from"@opentui/react/jsx-dev-runtime";function hs(e){let t=e.newer>0?`g jump to latest \xB7 ${e.newer} new`:"g jump to latest",r=Math.min(e.width,t.length+4);return Yu("box",{position:"absolute",left:Math.max(0,Math.floor((e.width-r)/2)),bottom:e.bottom??2,width:r,height:3,border:!0,borderStyle:"rounded",borderColor:e.palette.warning,backgroundColor:e.palette.panel,alignItems:"center",justifyContent:"center",onMouseDown:e.onJump,children:Yu("text",{wrapMode:"none",children:[Yu("span",{fg:e.palette.primary,children:"g"},void 0,!1,void 0,this),Yu("span",{fg:e.palette.text,children:t.slice(1)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var UT=()=>{};import{jsxDEV as $a}from"@opentui/react/jsx-dev-runtime";function gs(e){let{palette:t,logs:r,names:n,service:o,errorOnly:i,width:s,onService:a,onToggleErrors:l,facets:c}=e,u=c?Y0(n,c):V0(n,r),d=s<80,f=u.map((g)=>{let w=g.name===""?"all":g.name;return{id:w,label:d?w:`${w} \xB7 ${g.count}`,color:Ye(g.name,t)}}),p=Math.max(0,u.findIndex((g)=>g.name===o)),m=i?"ERROR+":d?"lvls":"all levels",h=Math.max(ts(f[p]?.label??"all"),s-ts(m));return $a(Zt,{palette:t,backgroundColor:t.element,children:$a("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[$a("box",{flexGrow:1,overflow:"hidden",children:$a(Cu,{palette:t,items:f,active:p,width:h,emphasis:"fill",onPick:(g)=>{let w=u[g];if(w)a(w.name)}},void 0,!1,void 0,this)},void 0,!1,void 0,this),$a(Ue,{palette:t,label:m,tone:i?"error":"muted",onMouseDown:l},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var jT=A(()=>{br();so();Re();rt()});import{jsxDEV as r$}from"@opentui/react/jsx-dev-runtime";function Ha(e){let t=Math.min(e.total,e.start+e.count),r=Math.max(0,e.start),n=Math.max(0,e.total-t);return r$(wt,{palette:e.palette,items:[{text:`view ${e.start+1}\u2013${t} of ${e.total}`,tone:"primary"},{text:r>0?`\u2191 ${r} older`:"start of history",tone:r>0?"info":"idle"},{text:n>0?`\u2193 ${n} newer`:"at latest",tone:n>0?"warning":"success"}],hints:[{key:"pgup/pgdn",label:"move history window"},{key:"g",label:"latest"}]},void 0,!1,void 0,this)}var BT=A(()=>{Re()});import{useEffect as Ju,useRef as jh}from"react";import{jsxDEV as ze}from"@opentui/react/jsx-dev-runtime";function vs(e){let{palette:t,logs:r,limit:n,width:o=80,followTick:i=0,focused:s=!1,wrapMode:a="all",selected:l=-1,follow:c=!0,showTimestamps:u=!0,showMeta:d=!0,onPick:f,onLeaveLatest:p,viewStart:m=0,search:h="",regex:g=!1}=e,w=jh(null),v=jh(""),S=jh(p);Ju(()=>{S.current=p},[p]);let E=n===void 0?r:r.slice(-n),_=[...new Set(r.map((x)=>x.service))],y=B0(o,_),b=E[E.length-1],k=b===void 0?"empty":String(b.seq);return Ju(()=>{let x=w.current;if(!x)return;if(x.stickyScroll=c,c)x.stickyStart="bottom",x.scrollTo({x:x.scrollLeft,y:Math.max(0,x.scrollHeight)})},[c,i,k]),Ju(()=>{let x=`${m}:${l}:${a}`;if(v.current===x)return;if(v.current=x,c&&(l<0||l>=E.length-1))return;let L=w.current;if(!L||l<0)return;let F=`log-row-${l}`,B=requestAnimationFrame(()=>{L.stickyScroll=!1,L.scrollChildIntoView(F)});return()=>cancelAnimationFrame(B)},[c,l,E.length,m,a]),Ju(()=>{if(!c||!p)return;let x=!1,L=0,F=0,B=setInterval(()=>{let K=w.current;if(!K)return;let V=K.viewport.height;if(V<=0)return;let{scrollHeight:X,scrollTop:te}=K;if(te<F){K.stickyScroll=!1,F=te,L=X,S.current?.();return}if(F=te,te+V>=X-o$){x=!0,L=X;return}if(X>L){K.stickyScroll=!0,K.stickyStart="bottom",K.scrollTo({x:K.scrollLeft,y:Math.max(0,X)}),L=X;return}if(x)S.current?.()},n$);return()=>{clearInterval(B)}},[c,i,p]),ze("box",{flexGrow:1,height:"100%",flexDirection:"column",overflow:"hidden",children:[ze(s$,{palette:t,serviceWidth:y,showTimestamps:u,showMeta:d},void 0,!1,void 0,this),ze("scrollbox",{ref:w,focused:s,stickyScroll:c,stickyStart:"bottom",scrollX:!1,style:{rootOptions:{flexGrow:1,height:"100%",overflow:"hidden",backgroundColor:t.panel},viewportOptions:{backgroundColor:t.panel},contentOptions:{backgroundColor:t.panel},scrollbarOptions:{trackOptions:{foregroundColor:t.primary,backgroundColor:t.element}}},children:ze("box",{flexDirection:"column",overflow:"hidden",children:E.map((x,L)=>ze(a$,{id:`log-row-${L}`,palette:t,event:x,serviceWidth:y,expanded:U0(a,L===l),active:L===l,showTimestamps:u,showMeta:d,onPick:f?()=>f(L):void 0,search:h,regex:g},`${x.timestamp}-${x.service}-${L}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function s$(e){let{palette:t,serviceWidth:r,showTimestamps:n,showMeta:o}=e;return ze("box",{height:1,flexShrink:0,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[ze(WT,{palette:t,serviceWidth:r,showTimestamps:n,showMeta:o,time:"TIME",service:"SERVICE",level:"LEVEL",meta:"SRC",header:!0},void 0,!1,void 0,this),ze("box",{flexGrow:1,flexShrink:1,minWidth:0,overflow:"hidden",children:ze("text",{fg:t.muted,wrapMode:"none",children:"MESSAGE"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function a$(e){let{id:t,palette:r,event:n,serviceWidth:o,expanded:i,active:s,showTimestamps:a=!0,showMeta:l=!0,onPick:c,search:u="",regex:d=!1}=e,f=Kt(n),p=n.severityText,m=n.source?n.traceId?`${i$}${n.source}`:n.source:"";return ze("box",{id:t,flexShrink:0,flexDirection:"row",alignItems:"flex-start",overflow:"hidden",height:i?"auto":1,backgroundColor:s?r.highlight:void 0,onMouseDown:c,children:[ze(WT,{palette:r,serviceWidth:o,showTimestamps:a,showMeta:l,time:n.timestamp.slice(11,19),service:n.service,level:p,meta:m},void 0,!1,void 0,this),ze("box",{flexGrow:1,flexShrink:1,minWidth:0,overflow:"hidden",children:ze(l$,{palette:r,level:p,text:f,wrap:i,search:u,regex:d},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function WT(e){let{palette:t,serviceWidth:r,showTimestamps:n,showMeta:o,time:i,service:s,level:a,meta:l,header:c=!1}=e,u=c?t.muted:void 0;return ze("box",{flexShrink:0,flexDirection:"row",overflow:"hidden",children:[n?ze(Xu,{width:Om,fg:u??t.muted,text:i},void 0,!1,void 0,this):null,ze(Xu,{width:r,fg:u??Ye(s,t),text:s},void 0,!1,void 0,this),ze("box",{width:uu,flexShrink:0,overflow:"hidden",children:ze("text",{children:" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),ze(Xu,{width:Mm,fg:u??dt(t,a),text:c?a:Zi(a)},void 0,!1,void 0,this),o?ze(Xu,{width:N0,fg:u??t.muted,text:l},void 0,!1,void 0,this):null,ze("box",{width:uu,flexShrink:0,overflow:"hidden",children:ze("text",{children:" "},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Xu(e){let{width:t,fg:r,text:n}=e;return ze("box",{width:t,flexShrink:0,overflow:"hidden",children:ze("text",{fg:r,wrapMode:"none",children:j(n,t)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function l$(e){let{palette:t,level:r,text:n,wrap:o,search:i="",regex:s=!1}=e;return ze("text",{wrapMode:o?"word":"none",truncate:!o,flexShrink:0,width:"100%",children:j0(n,i,s).map((a,l)=>ze("span",{fg:g0(t,r,a.kind),children:a.text},`${a.kind}-${l}`,!1,void 0,this))},void 0,!1,void 0,this)}var n$=200,o$=2,i$="\u25CE";var zT=A(()=>{sn();nt();br();rt()});var Bh=A(()=>{UT();jT();BT();zT()});import{useRef as c$}from"react";import{jsxDEV as Ne}from"@opentui/react/jsx-dev-runtime";function Qu(e){let{palette:t,names:r,snap:n,selected:o,checked:i,width:s,onOpen:a,onSelectIndex:l,onToggle:c}=e,u=ye(),d=c$(!1),f=new Set(i),p=Im(s),m=Lm(s),h=Am(s),g=A0(s);return Ne("box",{flexDirection:"column",flexGrow:1,overflow:"hidden",children:[Ne("box",{height:1,flexDirection:"row",overflow:"hidden",children:[Ne(rr,{width:2,fg:t.muted,text:""},void 0,!1,void 0,this),Ne(rr,{width:4,fg:t.accent,text:"sel"},void 0,!1,void 0,this),Ne(rr,{width:2,fg:t.muted,text:""},void 0,!1,void 0,this),Ne(rr,{width:g,fg:t.muted,text:"name"},void 0,!1,void 0,this),Ne(rr,{width:Bt,fg:t.muted,text:""},void 0,!1,void 0,this),Ne(rr,{width:Yr,fg:t.muted,text:"state"},void 0,!1,void 0,this),h?Ne(rr,{width:dn,fg:t.muted,text:"health"},void 0,!1,void 0,this):null,m?Ne(rr,{width:eu,fg:t.muted,text:"port"},void 0,!1,void 0,this):null,p?Ne(rr,{width:In,fg:t.muted,text:"pid"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),r.map((w,v)=>{let S=n?.services[w],E=yr(S),_=S?.health??"UNKNOWN",y=f.has(w),b=v===o,k=y?"[x]":"[ ]",x=b?"\u203A":" ";return Ne("box",{height:u.rowH,flexDirection:"row",overflow:"hidden",backgroundColor:b?t.highlight:y?t.element:void 0,onMouseDown:()=>{if(d.current)return;if(b){a(w);return}l(v)},children:[Ne("box",{width:2,flexShrink:0,children:Ne("text",{fg:t.primary,children:x},void 0,!1,void 0,this)},void 0,!1,void 0,this),Ne("box",{width:4,flexShrink:0,onMouseDown:()=>{d.current=!0,c?.(w),setTimeout(()=>{d.current=!1},0)},children:Ne("text",{fg:u$(t,y,b),children:k},void 0,!1,void 0,this)},void 0,!1,void 0,this),Ne("box",{width:2,flexShrink:0,children:Ne("text",{fg:dt(t,E),children:Or(E)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Ne(rr,{width:g,fg:b?t.primary:Ye(w,t),text:w},void 0,!1,void 0,this),Ne(rr,{width:Bt,fg:t.muted,text:""},void 0,!1,void 0,this),Ne(rr,{width:Yr,fg:dt(t,E),text:E},void 0,!1,void 0,this),h?Ne(rr,{width:dn,fg:dt(t,_),text:_},void 0,!1,void 0,this):null,m?Ne(rr,{width:eu,fg:t.text,text:ti(S)},void 0,!1,void 0,this):null,p?Ne(rr,{width:In,fg:t.text,text:S?.pid?String(S.pid):""},void 0,!1,void 0,this):null]},w,!0,void 0,this)})]},void 0,!0,void 0,this)}function Zu(e){let{palette:t,checked:r}=e,n=r.length;if(n>0)return Ne(wt,{palette:t,items:[{text:`${n} selected`,tone:"primary"}],hints:[{key:"space",label:"unmark"},{key:"n",label:"start these"},{key:"x",label:"stop these"}]},void 0,!1,void 0,this);return null}function u$(e,t,r){if(t)return e.success;if(r)return e.primary;return e.muted}function rr(e){return Ne("box",{width:e.width,flexShrink:0,overflow:"hidden",children:Ne("text",{fg:e.fg,wrapMode:"none",children:j(e.text,e.width)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var Wh=A(()=>{Ht();nt();Ut();Re();rt()});import{jsxDEV as fe}from"@opentui/react/jsx-dev-runtime";function GT(e){let{palette:t,cfg:r,snap:n,logs:o,names:i,selected:s,selectedLog:a=-1,checked:l,width:c,followTick:u,logService:d,logSources:f,errorOnly:p,showSystemLogs:m,onOpen:h,onSelectIndex:g,onToggle:w,onFilterService:v,onToggleErrors:S,onShowErrors:E,wrapMode:_="all",view:y,follow:b=!0,onLeaveLatest:k,onPickLog:x,viewStart:L=0,viewTotal:F,newer:B=0,onJumpLatest:K,facets:V,leftover:X,search:te="",regex:R=!1}=e,U=ye();if(!r||i.length===0)return fe(it,{palette:t,title:"No services configured",body:"Add services to .devctl/config.yaml or finish setup.",hint:"open the setup screen with /setup"},void 0,!1,void 0,this);let O=c<rs,ae=ou(n),Ae=xu(n,i),se=i.filter((Se)=>n?.services[Se]?.state==="FAILED").length,z=K0(o),ue=ae?D0(X,n?.session_id):void 0,re=nu(c,i,O),pt=Math.max(24,O?c-4:c-re-4),xt=m?o:o.filter((Se)=>!es(Se.source)),le=ni(o,{service:d,errorOnly:p,systemLogs:m,search:te,regex:R}),Oe=y??le,Fe=F??le.length,Qe=Math.min(Fe,L+Oe.length),kt=Fe===0?"empty":`${L+1}\u2013${Qe} of ${Fe}`,at=d===""?"all":d,At=[...Ae.running>0?[{text:`${Ae.running}/${i.length}`,tone:"success"}]:[],...se>0?[{text:`${se} failed`,tone:"error"}]:[],...l.length>0?[{text:`${l.length} selected`,tone:"primary"}]:[],...z>0?[{text:`${z} errors`,tone:"error",onMouseDown:E}]:[]];return fe("box",{flexGrow:1,flexDirection:O?"column":"row",overflow:"hidden",children:[fe("box",{flexGrow:O?1:0,flexShrink:0,minWidth:O?void 0:re,width:O?void 0:re,border:!0,borderStyle:"rounded",borderColor:ae?t.border:t.borderActive,backgroundColor:t.panel,title:"services",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[At.length>0?fe(wt,{palette:t,items:At},void 0,!1,void 0,this):null,fe(Zu,{palette:t,checked:l},void 0,!1,void 0,this),fe("box",{flexGrow:1,paddingLeft:U.pad,paddingRight:U.pad,overflow:"hidden",children:fe(Qu,{palette:t,names:i,snap:n,selected:s,checked:l,width:ru(re,U.pad),onOpen:h,onSelectIndex:g,onToggle:w},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe(m$,{palette:t,names:i,snap:n,width:re,onOpen:h},void 0,!1,void 0,this),ue?fe(g$,{palette:t,leftover:ue,width:re},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),fe("box",{position:"relative",flexGrow:2,minWidth:O?void 0:32,minHeight:O?8:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,backgroundColor:t.panel,title:`logs \xB7 ${at} \xB7 ${kt}`,titleColor:t.primary,overflow:"hidden",flexDirection:"column",children:[fe(gs,{palette:t,logs:xt,names:f??i,service:d,errorOnly:p,width:pt,onService:v,onToggleErrors:S,facets:V},void 0,!1,void 0,this),Fe>Oe.length?fe(Ha,{palette:t,start:L,count:Oe.length,total:Fe},void 0,!1,void 0,this):null,le.length===0?fe(it,{palette:t,title:ae?"Waiting for logs":o.length===0?"No events yet":"No events in this filter",body:ae?"Start services to stream output here. Later starts keep earlier logs.":o.length===0?"New lines appear as services write output.":"Click All or another service chip, or turn off ERROR+.",hint:"\u2190 \u2192 cycle service e errors g latest"},void 0,!1,void 0,this):fe(vs,{palette:t,logs:Oe,width:pt,followTick:u,focused:!1,wrapMode:_,selected:a,follow:b,onLeaveLatest:k,onPick:x,viewStart:L,search:te,regex:R},u,!1,void 0,this),!b?fe(hs,{palette:t,width:pt,newer:B,bottom:0,onJump:K},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function p$(e){if(!e)return!1;return e.state===bt||e.health===He||e.state===Ir||e.restarts>0||e.last_error!==""}function qT(e){if(e.state===bt)return 0;if(e.health===He)return 1;if(e.state===Ir)return 2;return 3}function f$(e){if(e.last_error!=="")return e.last_error;if(e.restarts>0)return`restarted ${e.restarts}x, no error recorded`;return e.health===He?"failing health check":e.state.toLowerCase()}function m$(e){let{palette:t,names:r,snap:n,width:o,onOpen:i}=e,s=r.map((u)=>({name:u,rt:n?.services[u]})).filter((u)=>p$(u.rt)).sort((u,d)=>qT(u.rt)-qT(d.rt));if(s.length===0)return null;let a=s.slice(0,d$),l=s.length-a.length,c=Math.max(8,o-zh-4);return fe("box",{flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",children:[fe("box",{height:1,overflow:"hidden",children:fe("text",{fg:t.error,wrapMode:"none",children:`issues (${s.length})`},void 0,!1,void 0,this)},void 0,!1,void 0,this),a.map(({name:u,rt:d})=>{let f=yr(d);return fe("box",{height:1,flexDirection:"row",overflow:"hidden",onMouseDown:()=>i(u),children:[fe("box",{width:2,flexShrink:0,children:fe("text",{fg:dt(t,f),children:Or(f)},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{width:zh,flexShrink:0,overflow:"hidden",children:fe("text",{fg:Ye(u,t),wrapMode:"none",children:j(u,zh)},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{width:c,flexShrink:0,overflow:"hidden",children:fe("text",{fg:t.muted,wrapMode:"none",children:ke(f$(d),c)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},u,!0,void 0,this)}),l>0?fe("text",{fg:t.muted,wrapMode:"none",children:`+${l} more \u2014 open a service to see details`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function g$(e){let{palette:t,leftover:r,width:n}=e,o=r.processes.slice(0,h$),i=r.processes.length-o.length,s=Math.max(8,n-qh-4);return fe("box",{flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",children:[fe("box",{height:1,overflow:"hidden",children:fe("text",{fg:t.warning,wrapMode:"none",children:"last session"},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("text",{fg:t.muted,wrapMode:"none",children:ke(`${r.session_id} ${r.profile||"(none)"}`,Math.max(8,n-4))},void 0,!1,void 0,this),o.map((a)=>fe("box",{height:1,flexDirection:"row",overflow:"hidden",children:[fe("box",{width:qh,flexShrink:0,overflow:"hidden",children:fe("text",{fg:t.text,wrapMode:"none",children:j(a.name,qh)},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{width:s,flexShrink:0,overflow:"hidden",children:fe("text",{fg:t.muted,wrapMode:"none",children:ke(`pid ${a.pid} leftover`,s)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},`${a.name}-${a.pid}`,!0,void 0,this)),i>0?fe("text",{fg:t.muted,wrapMode:"none",children:`+${i} more leftover pids`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var d$=4,zh=14,h$=4,qh=14;var KT=A(()=>{$t();cr();Ht();wr();nt();br();Ut();Su();Re();rt();Bh();Wh()});import v$ from"cli-spinners";import{useEffect as y$,useState as b$}from"react";import{jsxDEV as ie}from"@opentui/react/jsx-dev-runtime";function VT(e){let{palette:t,report:r,loading:n,progress:o,error:i,selected:s,onPick:a,onReload:l}=e,c=ss(s,Kh);if(n)return ie(w$,{palette:t,progress:o},void 0,!1,void 0,this);if(i)return ie(eS,{palette:t,title:"Doctor failed",body:i},void 0,!1,void 0,this);if(!r)return ie(it,{palette:t,title:"Doctor",body:"Diagnostics have not run yet.",hint:"opening this screen runs doctor"},void 0,!1,void 0,this);let u=r.checks.filter((g)=>g.severity==="ok").length,d=r.checks.filter((g)=>g.severity==="warn").length,f=r.checks.filter((g)=>g.severity==="error").length,p=r.checks.length,m=Qi(p>0?u/p:0),h=f>0?t.error:d>0?t.warning:t.success;return ie(Pt,{palette:t,title:`doctor ${r.issues} issue(s)`,children:[ie("box",{height:4,flexDirection:"column",flexShrink:0,alignItems:"center",justifyContent:"center",overflow:"hidden",border:!0,borderStyle:"rounded",borderColor:t.primary,backgroundColor:t.element,onMouseDown:l,children:[ie("text",{wrapMode:"none",children:[ie("span",{fg:t.inverse,bg:t.primary,children:" r "},void 0,!1,void 0,this),ie("span",{fg:t.primary,children:" RUN DOCTOR AGAIN"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ie("text",{fg:t.muted,wrapMode:"none",children:"results stay cached until you refresh"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ie("box",{height:1,flexShrink:0},void 0,!1,void 0,this),ie("box",{height:1,flexShrink:0,overflow:"hidden",children:ie("text",{wrapMode:"none",children:[ie("span",{fg:h,children:`[${m}]`},void 0,!1,void 0,this),ie("span",{fg:t.success,children:` ${u} ok`},void 0,!1,void 0,this),d>0?ie("span",{fg:t.warning,children:` \xB7 ${d} warn`},void 0,!1,void 0,this):null,f>0?ie("span",{fg:t.error,children:` \xB7 ${f} error`},void 0,!1,void 0,this):null,d===0&&f===0?ie("span",{fg:t.muted,children:" \xB7 all clear"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this),ie("box",{height:1,flexShrink:0},void 0,!1,void 0,this),ie("scrollbox",{ref:c,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:ie("box",{flexDirection:"column",overflow:"hidden",gap:1,children:r.checks.map((g,w)=>ie(x$,{palette:t,check:g,index:w,active:w===s,onPick:a},`${g.name}-${w}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function w$({palette:e,progress:t}){let[r,n]=b$(0);return y$(()=>{let o=setInterval(()=>n((i)=>(i+1)%Gh.frames.length),Gh.interval);return()=>clearInterval(o)},[]),ie("box",{flexGrow:1,alignItems:"center",justifyContent:"center",overflow:"hidden",children:ie("box",{width:"80%",maxWidth:52,height:10,flexShrink:1,border:!0,borderStyle:"rounded",borderColor:e.borderActive,backgroundColor:e.panel,flexDirection:"column",alignItems:"center",justifyContent:"center",overflow:"hidden",children:[ie("text",{wrapMode:"none",children:[ie("span",{fg:e.primary,children:`${Gh.frames[r]} `},void 0,!1,void 0,this),ie("span",{fg:e.text,children:"devctl doctor"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ie("box",{height:1,flexShrink:0},void 0,!1,void 0,this),ie("text",{fg:e.text,wrapMode:"none",children:`Checking ${t.active}`},void 0,!1,void 0,this),ie("box",{height:1,flexShrink:0},void 0,!1,void 0,this),t.checks.slice(-4).map((o,i)=>ie("text",{wrapMode:"none",children:[ie("span",{fg:dt(e,o.severity==="error"?"ERROR":o.severity==="warn"?"WARN":"OK"),children:`${Or(o.severity==="error"?"ERROR":o.severity==="warn"?"WARN":"OK")} `},void 0,!1,void 0,this),ie("span",{fg:e.muted,children:o.name},void 0,!1,void 0,this)]},`${o.name}-${i}`,!0,void 0,this)),t.checks.length===0?ie("text",{fg:e.muted,children:"Waiting for the first result\u2026"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function x$(e){let{palette:t,check:r,index:n,active:o,onPick:i}=e,s=r.severity==="error"?"ERROR":r.severity==="warn"?"WARN":"OK";if(r.severity==="ok")return ie("box",{id:`${Kh}-${n}`,flexDirection:"row",flexShrink:0,paddingLeft:1,overflow:"hidden",backgroundColor:o?t.highlight:void 0,onMouseDown:()=>i(n),children:ie("text",{wrapMode:"none",children:[ie("span",{fg:t.primary,children:o?"\u203A ":" "},void 0,!1,void 0,this),ie("span",{fg:dt(t,s),children:Or(s)},void 0,!1,void 0,this),ie("span",{fg:o?t.primary:t.text,children:` ${r.name}`},void 0,!1,void 0,this),ie("span",{fg:t.muted,children:r.message?` \xB7 ${r.message}`:""},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this);let l=r.severity==="error"?t.error:t.warning;return ie("box",{id:`${Kh}-${n}`,border:!0,borderStyle:"rounded",borderColor:o?t.borderActive:l,title:r.name,titleColor:l,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",backgroundColor:o?t.highlight:void 0,onMouseDown:()=>i(n),children:[ie("text",{wrapMode:"word",children:[ie("span",{fg:dt(t,s),children:`${Or(s)} `},void 0,!1,void 0,this),ie("span",{fg:t.text,children:r.message},void 0,!1,void 0,this)]},void 0,!0,void 0,this),r.hint?ie("text",{fg:t.info,wrapMode:"word",children:`\u2192 ${r.hint}`},void 0,!1,void 0,this):null,o&&r.action?.kind==="free-port"?ie("text",{fg:t.primary,wrapMode:"none",children:`enter stop ${r.action.holder.command} (pid ${r.action.holder.pid})`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var Kh="doctor-row",Gh;var YT=A(()=>{cr();nt();Re();rt();Gh=v$.bouncingBall});import{jsxDEV as Je,Fragment as k$}from"@opentui/react/jsx-dev-runtime";function XT(e){let{palette:t,logs:r,names:n,logSources:o,service:i,errorOnly:s,showSystemLogs:a,search:l,searchFocused:c,followTick:u,width:d,onSearch:f,onService:p,onToggleErrors:m,onSelect:h,wrapMode:g="all",selected:w=-1,follow:v=!0,newer:S=0,viewStart:E=0,viewTotal:_,onLeaveLatest:y,onJumpLatest:b,view:k,fullscreen:x=!1,facets:L,split:F=!1,splitFocus:B=0,serviceB:K="",viewB:V,selectedB:X=-1,followB:te=!0,newerB:R=0,viewStartB:U=0,viewTotalB:O,onServiceB:ae,onSelectB:Ae,onLeaveLatestB:se,onFocusPane:z}=e,ue=ye(),re=Nm(d,ue.pad,x),pt=a?r:r.filter((Se)=>!es(Se.source)),xt=ni(r,{service:i,services:e.services,errorOnly:s,search:l,regex:e.regex,source:e.source,systemLogs:a}),le=k??xt,Oe=_??xt.length,Fe=Math.min(Oe,E+le.length),Qe=Oe===0?"empty":`${E+1}\u2013${Fe} of ${Oe}`,kt=e.services??[],at=kt.length>0?kt.join(","):i===""?"all services":i,At=[...v?[]:[{text:S>0?`${F?"left ":""}pinned \xB7 +${S} new`:`${F?"left ":""}pinned`,tone:"warning"}],...F&&!te?[{text:R>0?`right pinned \xB7 +${R} new`:"right pinned",tone:"warning"}]:[],...e.source?[{text:`src ${e.source}`,tone:"info"}]:[],...e.regex?[{text:"regex",tone:"accent"}]:[],...l===""?[]:[{text:`search ${l}`,tone:"accent"}],...F?[{text:B===0?"left pane":"right pane",tone:"accent"}]:[]];if(F){let Se=Math.max(20,Math.floor(d/2)),St=Math.max(20,d-Se),gt=V??[],Ct=O??gt.length;return Je("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[c?Je("box",{height:1,paddingLeft:1,backgroundColor:t.highlight,overflow:"hidden",children:Je("input",{focused:!0,value:l,placeholder:"search messages or service names",onInput:f,backgroundColor:t.highlight,focusedBackgroundColor:t.highlight,textColor:t.text,cursorColor:t.primary},void 0,!1,void 0,this)},void 0,!1,void 0,this):Je(wt,{palette:t,items:At},void 0,!1,void 0,this),Je("box",{flexGrow:1,flexDirection:"row",overflow:"hidden",children:[Je(JT,{palette:t,names:o??n,logs:r,service:i,errorOnly:s,showSystemLogs:a,search:l,regex:e.regex,source:e.source,width:Se,shown:le,shownTotal:Oe,selected:w,follow:v,newer:S,viewStart:E,wrapMode:g,showTimestamps:e.showTimestamps!==!1,showMeta:e.showMeta!==!1,followTick:u,facets:L,focused:B===0,onService:p,onToggleErrors:m,onSelect:h,onLeaveLatest:y,onFocus:()=>z?.(0)},void 0,!1,void 0,this),Je(JT,{palette:t,names:o??n,logs:r,service:K,errorOnly:s,showSystemLogs:a,search:l,regex:e.regex,source:e.source,width:St,shown:gt,shownTotal:Ct,selected:X,follow:te,newer:R,viewStart:U,wrapMode:g,showTimestamps:e.showTimestamps!==!1,showMeta:e.showMeta!==!1,followTick:u,facets:L,focused:B===1,onService:ae??p,onToggleErrors:m,onSelect:Ae,onLeaveLatest:se,onFocus:()=>z?.(1)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),!v||!te?Je(hs,{palette:t,width:d,newer:Math.max(S,R),onJump:b},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}return Je("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[x?null:Je(k$,{children:[At.length>0?Je(wt,{palette:t,items:At},void 0,!1,void 0,this):null,Je(gs,{palette:t,logs:pt,names:o??n,service:i,errorOnly:s,width:d,onService:p,onToggleErrors:m,facets:L},void 0,!1,void 0,this)]},void 0,!0,void 0,this),c?Je("box",{height:1,paddingLeft:1,backgroundColor:t.highlight,overflow:"hidden",children:Je("input",{focused:!0,value:l,placeholder:"search messages or service names",onInput:f,backgroundColor:t.highlight,focusedBackgroundColor:t.highlight,textColor:t.text,cursorColor:t.primary},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,k&&Oe>le.length?Je(Ha,{palette:t,start:E,count:le.length,total:Oe},void 0,!1,void 0,this):null,Je("box",{flexGrow:1,border:!x,borderStyle:"rounded",borderColor:t.border,title:x?void 0:`logs ${at} \xB7 ${Qe}`,titleColor:t.primary,padding:x?0:ue.pad,overflow:"hidden",children:le.length===0?Je(it,{palette:t,title:r.length===0?"No log events":"No events in this filter",body:r.length===0?"Start services to stream logs.":"Pick All, another service, or clear search / ERROR+.",hint:`\u2190 \u2192 cycle filters e errors i internal ${jt("l")} clear`},void 0,!1,void 0,this):Je(vs,{palette:t,logs:le,width:re,followTick:u,focused:!1,wrapMode:g,selected:w,follow:v,showTimestamps:e.showTimestamps!==!1,showMeta:e.showMeta!==!1,onPick:h,onLeaveLatest:y,viewStart:E,search:l,regex:e.regex===!0},u,!1,void 0,this)},void 0,!1,void 0,this),!v?Je(hs,{palette:t,width:d,newer:S,onJump:b},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function JT(e){let{palette:t,width:r,service:n,shown:o,shownTotal:i,viewStart:s,focused:a}=e,l=e.showSystemLogs?e.logs:e.logs.filter((d)=>!es(d.source)),c=n===""?"all services":n,u=i===0?"empty":`${s+1}\u2013${Math.min(i,s+o.length)} of ${i}`;return Je("box",{width:r,flexGrow:0,flexShrink:0,flexDirection:"column",overflow:"hidden",onMouseDown:e.onFocus,children:[Je(gs,{palette:t,logs:l,names:e.names,service:n,errorOnly:e.errorOnly,width:r,onService:(d)=>{e.onFocus(),e.onService(d)},onToggleErrors:()=>{e.onFocus(),e.onToggleErrors()},facets:e.facets},void 0,!1,void 0,this),Je("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:a?t.borderActive:t.border,title:`logs ${c} \xB7 ${u}`,titleColor:a?t.primary:t.muted,overflow:"hidden",children:o.length===0?Je(it,{palette:t,title:"No events in this pane",body:"Click the pane, then \u2190 \u2192 to pick a service.",hint:"\\\\ split | focus"},void 0,!1,void 0,this):Je(vs,{palette:t,logs:o,width:Nm(r,0,!1),followTick:e.followTick,focused:!1,wrapMode:e.wrapMode,selected:e.selected,follow:e.follow,showTimestamps:e.showTimestamps,showMeta:e.showMeta,onPick:(d)=>{e.onFocus(),e.onSelect?.(d)},onLeaveLatest:e.onLeaveLatest,viewStart:s,search:e.search,regex:e.regex===!0},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var QT=A(()=>{Bh();cr();Ht();br();Re();Vr()});import{jsxDEV as Xe}from"@opentui/react/jsx-dev-runtime";function eE(e){let{palette:t,cfg:r,snap:n,profile:o,selected:i,onPick:s}=e,a=ye(),l=ss(i,ZT),c=Object.keys(r?.profiles??{}).sort();if(c.length===0)return Xe(it,{palette:t,title:"No profiles",body:"Add profiles.<name>.services in config.yaml."},void 0,!1,void 0,this);return Xe(Pt,{palette:t,title:"profiles",children:[Xe("box",{height:1,flexShrink:0,overflow:"hidden",children:Xe("text",{fg:t.muted,wrapMode:"none",children:[`${c.length} profile${c.length===1?"":"s"} \xB7 current: `,Xe("span",{fg:t.success,children:o||"(none)"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Xe("box",{height:1,flexShrink:0},void 0,!1,void 0,this),Xe("scrollbox",{ref:l,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:Xe("box",{flexDirection:"column",overflow:"hidden",gap:a.gap||1,children:c.map((u,d)=>{let f=u===o,p=d===i,m=r?.profiles[u]?.services??[],h=Object.keys(r?.profiles[u]?.environment??{}).length,g=p?t.borderActive:f?t.success:t.border,w=p?t.primary:f?t.success:t.muted;return Xe("box",{id:`${ZT}-${d}`,border:!0,borderStyle:"rounded",borderColor:g,title:u,titleColor:w,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",backgroundColor:p?t.highlight:void 0,onMouseDown:()=>s(d),children:[Xe("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:Xe("text",{wrapMode:"none",children:[f?Xe("span",{fg:t.success,children:"\u25CF current profile"},void 0,!1,void 0,this):Xe("span",{fg:t.muted,children:"\u25CB not active"},void 0,!1,void 0,this),Xe("span",{fg:t.muted,children:` \xB7 ${m.length} service${m.length===1?"":"s"}`},void 0,!1,void 0,this),h>0?Xe("span",{fg:t.muted,children:` \xB7 ${h} env var${h===1?"":"s"}`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Xe("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:m.length===0?Xe("text",{fg:t.muted,wrapMode:"none",children:"(no services)"},void 0,!1,void 0,this):Xe("text",{wrapMode:"word",children:m.map((v,S)=>{let E=yr(n?.services[v]);return Xe("span",{children:[Xe("span",{fg:dt(t,E),children:Or(E)},void 0,!1,void 0,this),Xe("span",{fg:Ye(v,t),children:` ${v}`},void 0,!1,void 0,this),S<m.length-1?Xe("span",{fg:t.muted,children:" "},void 0,!1,void 0,this):null]},v,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},u,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this),Xe(Zt,{palette:t,backgroundColor:t.element,edge:"top",children:Xe(mt,{palette:t,hints:[{key:"space",label:"set current"},{key:"enter",label:"set and start"}]},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var ZT="profile-row";var tE=A(()=>{cr();Ht();Ut();Re();rt()});import{jsxDEV as J,Fragment as iE}from"@opentui/react/jsx-dev-runtime";function S$(e){let t=e.toLowerCase();if(t==="iap")return"info";if(t==="service"||t==="service_account")return"primary";return"idle"}function C$(e,t,r){if(r||t>=500)return e.error;if(t===0||t>=400)return e.warning;return e.success}function T$(e,t){if(t.startsWith("sa:"))return{label:"SA",color:e.primary};if(t!=="")return{label:"USR",color:e.info};return{label:"\u2014",color:e.muted}}function P$(e){let{palette:t,req:r,cols:n,onOpenTrace:o}=e,i=C$(t,r.status,r.error),s=r.status>0?String(r.status):"ERR",a=T$(t,r.identity),l=r.route||sE,c=r.error?`${r.path} \u2014 ${ke(r.error,_$)}`:r.path,u=r.traceId;return J("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,onMouseDown:u&&o?()=>o(u):void 0,children:[J("box",{width:ed,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j(r.timestamp.slice(11,19),ed)},void 0,!1,void 0,this)},void 0,!1,void 0,this),n.showMethod?J("box",{width:td,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.text,wrapMode:"none",children:j(r.method,td)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,J("box",{width:rd,flexShrink:0,overflow:"hidden",children:J("text",{fg:i,wrapMode:"none",children:j(s,rd)},void 0,!1,void 0,this)},void 0,!1,void 0,this),n.showDur?J("box",{width:nd,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,wrapMode:"none",children:j(`${r.durationMs}ms`,nd)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,J("box",{width:od,flexShrink:0,overflow:"hidden",children:J("text",{fg:a.color,wrapMode:"none",children:j(a.label,od)},void 0,!1,void 0,this)},void 0,!1,void 0,this),J("box",{width:n.routeCol,flexShrink:0,overflow:"hidden",children:J("text",{fg:r.route?t.info:t.muted,wrapMode:"none",children:j(l,n.routeCol)},void 0,!1,void 0,this)},void 0,!1,void 0,this),J("box",{flexGrow:1,overflow:"hidden",children:J("text",{fg:r.error?t.error:t.text,wrapMode:"none",children:c},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function A$(e){let{palette:t,cols:r}=e;return J("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:[J("box",{width:ed,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j("TIME",ed)},void 0,!1,void 0,this)},void 0,!1,void 0,this),r.showMethod?J("box",{width:td,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j("METHOD",td)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,J("box",{width:rd,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j("ST",rd)},void 0,!1,void 0,this)},void 0,!1,void 0,this),r.showDur?J("box",{width:nd,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j("DUR",nd)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,J("box",{width:od,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j("WHO",od)},void 0,!1,void 0,this)},void 0,!1,void 0,this),J("box",{width:r.routeCol,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j("ROUTE",r.routeCol)},void 0,!1,void 0,this)},void 0,!1,void 0,this),J("box",{flexGrow:1,overflow:"hidden",children:J("text",{fg:t.muted,children:"PATH"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function L$(e){let{palette:t,name:r,auth:n,identity:o,upstream:i,match:s,onMouseDown:a}=e;return J("box",{flexDirection:"column",flexShrink:0,overflow:"hidden",onMouseDown:a,children:[J("text",{fg:t.text,wrapMode:"none",children:r},void 0,!1,void 0,this),J("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[J(Ue,{palette:t,label:n||"no auth",tone:S$(n)},void 0,!1,void 0,this),o?J(Ue,{palette:t,label:o,tone:"idle"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),s?J("text",{fg:t.muted,wrapMode:"word",children:`match: ${s}`},void 0,!1,void 0,this):null,J("text",{fg:t.muted,wrapMode:"word",children:`\u2192 ${i}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function aE(e){let{palette:t,cfg:r,snap:n,width:o,onSelectRoute:i,onOpenTrace:s}=e,a=n?.proxy.routes??[],l=new Map((r?.proxy.routes??[]).map((y)=>[y.name,y])),c=new Map((r?.proxy.routes??[]).map((y)=>[y.name,y.match])),u=n?.proxy.recentRequests??[],d=n?.proxy.requestTotal??0,f=n?.proxy.requestErrors??0,p=o<rs,m=Math.max(rE,Math.min(I$,Math.floor(o*0.36))),h=p?o-nE:o-m-nE,g=Math.max(20,h-2),w=g>=oE,v=g>=D$,S=g>=oE?O$:M$,E=u.reduce((y,b)=>Math.min(S,Math.max(y,(b.route||sE).length+R$)),E$),_={showMethod:w,showDur:v,routeCol:E};return J(Pt,{palette:t,title:"proxy",children:[J(wt,{palette:t,items:[{text:n?.proxy.running?"RUNNING":"STOPPED",tone:n?.proxy.running?"success":"idle"},...n?.proxy.address?[{text:n.proxy.address,tone:"info"}]:[],{text:`${a.length} routes`,tone:a.length>0?"primary":"idle"},...d>0?[{text:`${d} requests`,tone:"idle"},...f>0?[{text:`${f} errors`,tone:"warning"}]:[]]:[]]},void 0,!1,void 0,this),J("box",{flexGrow:1,flexDirection:p?"column":"row",overflow:"hidden",children:[J("box",{flexGrow:p?1:0,flexBasis:p?0:void 0,flexShrink:0,minWidth:p?void 0:rE,width:p?void 0:m,minHeight:p?8:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,title:"routes",titleColor:t.primary,paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",children:a.length===0?J(it,{palette:t,title:"No proxy routes",body:"Add routes under proxy.routes or .devctl/proxy/routes.yaml."},void 0,!1,void 0,this):J(iE,{children:[i?J("text",{fg:t.muted,wrapMode:"word",children:"click a route for full details"},void 0,!1,void 0,this):null,J("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:J("box",{flexDirection:"column",overflow:"hidden",gap:1,children:a.map((y)=>{let b=c.get(y.name),k=b&&(b.host||b.path)?`${b.host||"*"}${b.path?b.path:""}`:void 0,x=l.get(y.name);return J(L$,{palette:t,name:y.name,auth:y.auth,identity:y.identity,upstream:y.upstream,match:k,onMouseDown:i?()=>i({name:y.name,authType:x?.auth.type||y.auth,identityType:x?.auth.identity.type??"",serviceAccount:x?.auth.identity.service_account||x?.auth.service_account||"",audience:x?.auth.audience??"",clientId:x?.auth.client_id??"",clientSecret:Xl(x?.auth.client_secret??"")??((x?.auth.client_secret??"").trim()?"inline":""),matchHost:x?.match.host??"",matchPath:x?.match.path??"",upstream:y.upstream}):void 0},y.name,!1,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),J("box",{flexGrow:1,flexBasis:0,minWidth:p?void 0:30,minHeight:p?10:void 0,border:!0,borderStyle:"rounded",borderColor:t.borderActive,title:"requests",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:u.length===0?J("box",{paddingLeft:1,paddingRight:1,children:J("text",{fg:t.muted,wrapMode:"word",children:n?.proxy.running?"No requests seen yet. Send one through the proxy to see it show up here \u2014 no need to restart or press r.":"Start the proxy, then send it a request to see live traffic here."},void 0,!1,void 0,this)},void 0,!1,void 0,this):J(iE,{children:[J(A$,{palette:t,cols:_},void 0,!1,void 0,this),J("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:J("box",{flexDirection:"column",overflow:"hidden",children:u.map((y)=>J(P$,{palette:t,req:y,cols:_,onOpenTrace:s},y.requestId,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),J(Zt,{palette:t,backgroundColor:t.element,edge:"top",children:J(mt,{palette:t,hints:[{key:"n",label:"start proxy"},{key:"x",label:"stop proxy"}]},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var ed=9,td=8,rd=4,nd=8,od=4,E$=8,R$=2,_$=64,sE="(none)",rE=26,I$=56,nE=2,oE=46,D$=54,O$=20,M$=12;var lE=A(()=>{cr();wr();nt();Re()});import{jsxDEV as pe}from"@opentui/react/jsx-dev-runtime";function dE(e){let{palette:t,name:r}=e;return pe("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:r,titleColor:Ye(r,t),flexDirection:"column",overflow:"hidden",children:pe(Vh,{...e,compact:!1},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Vh(e){let{palette:t,cfg:r,snap:n,name:o,reveal:i,width:s,compact:a=!0,envScrollRef:l}=e,c=ye(),u=r?.services[o];if(!u)return pe(it,{palette:t,title:"Unknown service",body:`No service named ${o}.`,hint:"j/k move"},void 0,!1,void 0,this);let d=n?.services[o],f=yr(d),p=d?.health??"UNKNOWN",m=ti(d)||Pa(u,d),h=I0(u,i,r?.secrets.extra_markers??[],r?.secrets.extra_patterns??[],e.resolvedEnv),g=e.envStatus==="error"?"error":e.envStatus==="resolved"?"success":e.envStatus==="loading"?"info":"muted",w=e.envStatus==="resolved"?"resolved":e.envStatus==="loading"?"resolving":e.envStatus==="error"?"config fallback":"config",v=s>=F$,S=[{label:"health",value:au(u)},{label:"workdir",value:u.working_dir||"."},{label:"restart",value:cu(u)},{label:"caps",value:u.capabilities.join(", ")||"\u2014"},{label:"runtime",value:u.container?`${u.container.runtime||"docker"} \xB7 ${u.container.image}`:"host"},...u.watch.enabled?[{label:"watch",value:u.watch.paths.join(" ")||"on"}]:[]],E=[{label:"identity",value:lu(u,d)},{label:"depends",value:u.dependencies.map(Fl).join(", ")||"\u2014"},{label:"ports",value:Pa(u,d)},{label:"tries",value:String(d?.restarts??0),tone:d?.restarts?"warning":"muted"}],_=Math.max(di+8,s-2),y=v?Math.floor(_/2):_;return pe("box",{padding:c.pad,flexGrow:1,flexDirection:"column",overflow:"hidden",children:[pe(wt,{palette:t,items:[{text:f,tone:uE(f)},{text:p,tone:uE(p)},{text:d?.pid?`pid ${d.pid}`:"pid \u2014",tone:d?.pid?"info":"idle"},{text:m==="\u2014"?"port \u2014":`port ${m}`,tone:m==="\u2014"?"idle":"info"}]},void 0,!1,void 0,this),u.description?pe("box",{height:1,overflow:"hidden",children:pe("text",{fg:t.muted,wrapMode:"none",children:ke(u.description,Math.max(8,s-4))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,d?.last_error?pe("box",{height:1,overflow:"hidden",children:pe("text",{fg:t.error,wrapMode:"none",children:ke(d.last_error,N$)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,pe(Yh,{palette:t,item:{label:"command",value:su(u)},valueWidth:Math.max(8,_-di)},void 0,!1,void 0,this),pe($$,{palette:t,left:S,right:E,wide:v,colWidth:y},void 0,!1,void 0,this),pe(H$,{palette:t,entries:h,reveal:i,width:s,focused:!a,scrollRef:l,source:w,sourceTone:g,error:e.envError,onSelect:e.onSelectEnv},void 0,!1,void 0,this),a?null:pe(mt,{palette:t,hints:[{key:"n",label:"start"},{key:"x",label:"stop"},{key:"R",label:"restart"},{key:"o",label:"config"},{key:"l",label:"logs"},{key:"/reveal",label:"secrets"},{key:"esc",label:"back"}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function $$(e){let{palette:t,left:r,right:n,wide:o,colWidth:i}=e,s=Math.max(4,i-di);if(!o)return pe("box",{width:i,flexShrink:0,flexDirection:"column",overflow:"hidden",children:[...r,...n].map((a)=>pe(Yh,{palette:t,item:a,valueWidth:s},a.label,!1,void 0,this))},void 0,!1,void 0,this);return pe("box",{height:r.length,flexShrink:0,flexDirection:"row",overflow:"hidden",children:[pe(cE,{palette:t,items:r,width:i},void 0,!1,void 0,this),pe(cE,{palette:t,items:n,width:i},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function cE(e){let t=Math.max(4,e.width-di);return pe("box",{width:e.width,flexShrink:0,flexDirection:"column",overflow:"hidden",children:e.items.map((r)=>pe(Yh,{palette:e.palette,item:r,valueWidth:t},r.label,!1,void 0,this))},void 0,!1,void 0,this)}function Yh(e){let{palette:t,item:r,valueWidth:n}=e,o=r.tone==="warning"?t.warning:r.tone==="muted"?t.muted:t.text;return pe("box",{height:1,width:di+n,flexDirection:"row",overflow:"hidden",children:[pe("box",{width:di,flexShrink:0,overflow:"hidden",children:pe("text",{fg:t.muted,wrapMode:"none",children:j(r.label,di)},void 0,!1,void 0,this)},void 0,!1,void 0,this),pe("box",{width:n,flexShrink:0,overflow:"hidden",children:pe("text",{fg:o,wrapMode:"none",children:j(r.value,n)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function H$(e){let{palette:t,entries:r,reveal:n,width:o,focused:i,scrollRef:s,source:a,sourceTone:l,error:c,onSelect:u}=e;return pe("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[pe(wt,{palette:t,items:[{text:`env ${r.length}`,tone:r.length>0?"info":"idle"},{text:a,tone:l},{text:n?"secrets shown":"redacted",tone:n?"warning":"muted"}],hints:i?[{key:"j/k",label:"scroll"}]:[{key:"/reveal",label:"secrets"}]},void 0,!1,void 0,this),c?pe("box",{height:1,overflow:"hidden",children:pe("text",{fg:t.warning,wrapMode:"none",children:ke(c,Math.max(8,o-4))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,r.length===0?pe("text",{fg:t.muted,children:"no service env overrides"},void 0,!1,void 0,this):pe("box",{flexGrow:1,height:"100%",overflow:"hidden",children:[u?pe("text",{fg:t.muted,wrapMode:"word",children:"click a variable for its full value"},void 0,!1,void 0,this):null,pe("scrollbox",{ref:s,focused:i,stickyScroll:!1,scrollX:!1,style:{rootOptions:{flexGrow:1,height:"100%",overflow:"hidden",backgroundColor:t.panel},viewportOptions:{backgroundColor:t.panel},contentOptions:{backgroundColor:t.panel},scrollbarOptions:{trackOptions:{foregroundColor:t.primary,backgroundColor:t.element}}},children:pe("box",{flexDirection:"column",overflow:"hidden",children:r.map((d)=>{let f=d.required?t.warning:d.fromConfig?t.accent:t.muted,p=d.value===""&&d.required?"(required)":d.value;return pe("box",{flexDirection:"row",overflow:"hidden",onMouseDown:u?()=>u(d):void 0,children:pe("text",{wrapMode:"word",children:[pe("span",{fg:f,children:d.required?`${d.key}*`:d.key},void 0,!1,void 0,this),pe("span",{fg:d.value===""?t.muted:t.text,children:` ${p}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},d.key,!1,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function uE(e){switch(e.toUpperCase()){case"HEALTHY":case"RUNNING":return"success";case"UNHEALTHY":case"WARNING":case"WARN":case"STARTING":case"RESTARTING":return"warning";case"FAILED":case"ERROR":return"error";default:return"muted"}}var N$=72,F$=56,di=9;var Jh=A(()=>{Ke();cr();Ht();nt();Ut();Re();rt()});import{jsxDEV as ho}from"@opentui/react/jsx-dev-runtime";function pE(e){let{palette:t,cfg:r,names:n,snap:o,selected:i,checked:s,width:a,reveal:l,onOpen:c,onSelectIndex:u,onToggle:d,resolvedEnv:f,envStatus:p,envError:m,onSelectEnv:h}=e;if(n.length===0)return ho(it,{palette:t,title:"No services",body:"This configuration does not define any services."},void 0,!1,void 0,this);let g=a<rs,w=n[i]??"",v=nu(a,n,g),S=4,E=g?Math.max(Xh,a-S):Math.max(Xh,a-v-S);return ho("box",{flexGrow:1,flexDirection:g?"column":"row",overflow:"hidden",children:[ho("box",{flexGrow:g?1:0,flexShrink:0,minWidth:g?void 0:Zc,width:g?void 0:v,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:"services",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[ho(Zu,{palette:t,checked:s},void 0,!1,void 0,this),ho("box",{flexGrow:1,overflow:"hidden",children:ho(Qu,{palette:t,names:n,snap:o,selected:i,checked:s,width:ru(v),onOpen:c,onSelectIndex:u,onToggle:d},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ho("box",{flexGrow:2,minWidth:g?void 0:Xh,minHeight:g?U$:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,backgroundColor:t.panel,title:w||"detail",titleColor:w?Ye(w,t):t.primary,overflow:"hidden",flexDirection:"column",children:ho(Vh,{palette:t,cfg:r,snap:o,name:w,reveal:l,width:E,resolvedEnv:f,envStatus:p,envError:m,onSelectEnv:h},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Xh=36,U$=12;var fE=A(()=>{cr();wr();Ut();rt();Jh();Wh()});import{jsxDEV as _e}from"@opentui/react/jsx-dev-runtime";function B$(e){switch(e){case"cycle":return"\u2194";case"toggle":return"\u23FB";case"page":return"\u25B8";case"action":return"!";default:return"\xB7"}}function gE(e){let{palette:t,items:r,selected:n,locked:o,width:i,onPick:s,onActivate:a}=e,l=ye(),c=Sm(r,n),u=oo(r,c);return _e("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:"settings",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[_e("box",{height:2,paddingLeft:l.pad,flexShrink:0,flexDirection:"column",overflow:"hidden",children:[_e("text",{fg:t.primary,wrapMode:"none",children:"Preferences"},void 0,!1,void 0,this),_e("text",{fg:t.muted,wrapMode:"none",children:o?"DEVCTL_TUI_CONFIG is set \u2014 changes stay in this session.":"Changes save to your user tui.json unless noted."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),_e("box",{flexGrow:1,paddingLeft:l.pad,paddingRight:l.pad,overflow:"hidden",flexShrink:1,children:_e(W$,{palette:t,items:r,active:c,scale:l,width:i,onPick:s,onActivate:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),_e(q$,{palette:t,item:u,scale:l},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function W$(e){let{palette:t,items:r,active:n,scale:o,width:i,onPick:s,onActivate:a}=e,l=ss(n,hE),c=Math.max(8,i-Qh-mE-10),u=0,d=C0(r);return _e("scrollbox",{ref:l,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:_e("box",{flexDirection:"column",overflow:"hidden",children:d.map((f,p)=>{let m=u;u+=f.items.length;let h=n>=m&&n<m+f.items.length;return _e("box",{flexDirection:"column",flexShrink:0,marginBottom:p<d.length-1?Math.max(1,o.gap):0,overflow:"hidden",children:[_e("box",{height:1,overflow:"hidden",children:_e("text",{fg:h?t.primary:t.muted,wrapMode:"none",children:f.group},void 0,!1,void 0,this)},void 0,!1,void 0,this),f.group==="MCP"?_e("box",{height:1,overflow:"hidden",children:_e("text",{fg:t.muted,wrapMode:"none",children:"dedicated page \u2014 also /mcp or /agent"},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,f.items.map((g,w)=>{let v=m+w;return _e(z$,{index:v,palette:t,item:g,active:v===n,rowH:o.rowH,valueWidth:c,onPick:()=>s(v),onActivate:()=>a(g)},g.id,!1,void 0,this)})]},f.group,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function z$(e){let{palette:t,index:r,item:n,active:o,rowH:i,valueWidth:s,onPick:a,onActivate:l}=e;return _e("box",{id:`${hE}-${r}`,height:i,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:o?t.highlight:void 0,onMouseDown:()=>{if(o){l();return}a()},children:[_e("box",{width:2,flexShrink:0,overflow:"hidden",children:_e("text",{fg:t.primary,children:o?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),_e("box",{width:mE,flexShrink:0,overflow:"hidden",children:_e("text",{fg:o?t.primary:t.muted,children:B$(n.kind)},void 0,!1,void 0,this)},void 0,!1,void 0,this),_e("box",{width:Qh,flexShrink:0,overflow:"hidden",children:_e("text",{fg:o?t.primary:t.text,wrapMode:"none",children:j(n.name,Qh)},void 0,!1,void 0,this)},void 0,!1,void 0,this),_e("box",{flexGrow:1,overflow:"hidden",children:_e("text",{fg:G$(t,n,o),wrapMode:"none",children:ke(n.value,s)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function q$(e){let{palette:t,item:r,scale:n}=e,o=r?.id==="font",i=r?.kind==="page"?`${r.name} \u2192 dedicated page`:r?.name??"";return _e("box",{height:j$,flexShrink:0,border:!0,borderStyle:"rounded",borderColor:t.border,title:"selected",titleColor:t.muted,backgroundColor:t.element,paddingLeft:n.pad,paddingRight:n.pad,flexDirection:"column",overflow:"hidden",children:[_e("box",{height:1,overflow:"hidden",children:_e("text",{fg:t.primary,wrapMode:"none",children:o?`${k0(n.steps)} ${n.label}`:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),_e("box",{height:1,overflow:"hidden",children:_e("text",{fg:t.text,wrapMode:"word",children:r?.detail??""},void 0,!1,void 0,this)},void 0,!1,void 0,this),_e("box",{height:1,overflow:"hidden",children:_e("text",{fg:t.muted,wrapMode:"none",children:r?r.kind==="info"?"read-only":r.hint:""},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function G$(e,t,r){if(t.id==="mouse")return t.value==="on"?e.success:e.text;if(t.kind==="page")return e.info;if(t.kind==="info")return e.text;return r?e.primary:e.text}var Qh=14,mE=2,j$=5,hE="settings-row";var vE=A(()=>{Ht();nt();Re();Mr()});import{jsxDEV as De}from"@opentui/react/jsx-dev-runtime";function yE(e){let{palette:t,cfg:r,google:n,bootError:o,bootErrorMissing:i=!1,step:s=0}=e,a=ye();if(o&&!r)return i?De(it,{palette:t,title:"No configuration found",body:"Would you like to run setup?",hint:"[Enter] 9-step setup [Esc] Exit"},void 0,!1,void 0,this):De(it,{palette:t,title:"Configuration error",body:o,hint:"Fix .devctl/config.yaml, then restart devctl [Esc] Exit"},void 0,!1,void 0,this);let l=e.issues,c=K$(r,n,l),u=c.filter((v)=>v.ok).length,d=c.length,f=d>0?Math.round(u/d*100):0,p=20,m=Math.round(f/100*p),h="\u2588".repeat(m)+"\u2591".repeat(Math.max(0,p-m)),g=f===100?t.success:f===0?t.muted:t.primary,w=c[s];return De(Pt,{palette:t,title:"setup",scroll:!0,children:[De("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:De("text",{fg:t.primary,children:"Developer onboarding"},void 0,!1,void 0,this)},void 0,!1,void 0,this),De("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:De("text",{wrapMode:"none",children:[De("span",{fg:g,children:`[${h}]`},void 0,!1,void 0,this),De("span",{fg:t.text,children:` ${u}/${d} ready`},void 0,!1,void 0,this),De("span",{fg:t.muted,children:` (${f}%)`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),De("box",{height:1,flexShrink:0},void 0,!1,void 0,this),c.map((v,S)=>{let E=S===s;return De("box",{height:a.rowH,flexDirection:"row",overflow:"hidden",backgroundColor:E?t.highlight:void 0,paddingLeft:1,children:[De("box",{width:2,flexShrink:0,children:De("text",{fg:dt(t,v.ok?"OK":"WARN"),children:Or(v.ok?"OK":"WARN")},void 0,!1,void 0,this)},void 0,!1,void 0,this),De("box",{width:3,flexShrink:0,children:De("text",{fg:E?t.primary:t.muted,children:String(S+1).padStart(2," ")},void 0,!1,void 0,this)},void 0,!1,void 0,this),De("box",{width:20,flexShrink:0,overflow:"hidden",children:De("text",{fg:E?t.primary:t.text,children:j(v.name,20)},void 0,!1,void 0,this)},void 0,!1,void 0,this),De("box",{flexGrow:1,overflow:"hidden",children:De("text",{fg:E?t.text:t.muted,wrapMode:"none",children:v.detail},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},v.name,!0,void 0,this)}),De("box",{height:1,flexShrink:0},void 0,!1,void 0,this),w?De("box",{border:!0,borderStyle:"rounded",borderColor:w.ok?t.success:t.warning,title:w.name,titleColor:w.ok?t.success:t.warning,flexDirection:"column",paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:De("text",{fg:w.ok?t.text:t.warning,wrapMode:"word",children:w.detail},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,De("box",{height:1,flexShrink:0},void 0,!1,void 0,this),De("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:De(Ue,{palette:t,label:"never hard-coded",tone:"idle"},void 0,!1,void 0,this)},void 0,!1,void 0,this),De("text",{fg:t.muted,wrapMode:"word",children:"Service accounts and IAP audiences stay in configuration. Run `devctl setup` for the interactive CLI wizard."},void 0,!1,void 0,this),De(mt,{palette:t,hints:[{key:"j/k",label:"steps"},{key:"enter",label:r?"start":"begin setup"},{key:"esc",label:"exit"},{key:"o",label:"profiles"}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function K$(e,t,r=[]){let n=Object.values(e?.services??{}).flatMap((s)=>s.ports.filter((a)=>!a.auto)),o=(e?.proxy.routes??[]).some((s)=>s.auth.type.toLowerCase()==="iap"),i=Gu(e,void 0,t).project;return[{name:On[0],ok:Boolean(e?.repoRoot),detail:e?.repoRoot||"unknown"},{name:On[1],ok:Boolean(e?.project.name),detail:e?.project.name||"set project.name"},{name:On[2],ok:Boolean(i),detail:i||"optional for local-only"},{name:On[3],ok:t?.adcAvailable===!0,detail:t?.adcAvailable?"ADC available":"needed only for cloud identity / IAP"},{name:On[4],ok:!0,detail:"read from configuration; never hard-coded"},{name:On[5],ok:!o||(e?.proxy.routes??[]).every((s)=>s.auth.type.toLowerCase()!=="iap"||s.auth.audience!==""),detail:o?"IAP routes present":"no IAP routes"},{name:On[6],ok:n.length===0||Boolean(e),detail:`${n.length} fixed ports from configuration`},{name:On[7],ok:Object.keys(e?.profiles??{}).length>0,detail:`${Object.keys(e?.profiles??{}).length} profile(s)`},{name:On[8],ok:r.length===0,detail:r.length===0?"configuration is valid":r[0]??"invalid"}]}var On;var bE=A(()=>{cr();Ht();nt();Re();rt();On=["Repository","Environment","Google project","Authentication","Service accounts","IAP","Ports","Profiles","Validation"]});import{useEffect as V$,useState as Y$}from"react";import{jsxDEV as oe}from"@opentui/react/jsx-dev-runtime";function ys(e){let{palette:t,title:r,tone:n="muted",children:o}=e,i=n==="success"?t.success:n==="warning"?t.warning:n==="error"?t.error:t.border;return oe("box",{border:!0,borderStyle:"rounded",borderColor:i,title:r,titleColor:i,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,marginBottom:1,overflow:"hidden",children:o},void 0,!1,void 0,this)}function Zh(e,t){if(t.color)return t.color;switch(t.tone){case"success":return e.success;case"warning":return e.warning;case"error":return e.error;case"primary":return e.primary;case"muted":return e.muted;default:return e.text}}function ja(e){let{palette:t,cells:r,header:n,gap:o=0,stripe:i}=e;return oe("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:i?t.element:void 0,children:r.map((s,a)=>oe("box",{flexDirection:"row",flexShrink:0,overflow:"hidden",children:[a>0&&o>0?oe("box",{width:o,flexShrink:0},void 0,!1,void 0,this):null,oe("box",{width:s.width,flexShrink:0,overflow:"hidden",children:oe("text",{fg:n?t.primary:Zh(t,s),wrapMode:"none",children:j(s.text,s.width)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},`${s.text}-${a}`,!0,void 0,this))},void 0,!1,void 0,this)}function wE(e){let{palette:t,width:r}=e;return oe("box",{height:1,flexShrink:0,overflow:"hidden",children:oe("text",{fg:t.border,wrapMode:"none",children:j("\u2500".repeat(Math.max(1,r)),r)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Ua(e){let{palette:t,facts:r,width:n}=e,o=Qm(r,n),i=[{text:"what",width:o.what},{text:"reading",width:o.reading}];if(o.meter>0)i.push({text:"used",width:o.meter});return i.push({text:"meaning",width:o.meaning}),oe("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[oe(ja,{palette:t,header:!0,gap:is,cells:i},void 0,!1,void 0,this),oe(wE,{palette:t,width:n},void 0,!1,void 0,this),r.map((s,a)=>{let l=s.meaning===""?[""]:H0(s.meaning,Math.max(1,o.meaning)),c=s.meter?Uk(s.meter):o.meter>0?"":void 0,u=[{text:s.what,width:o.what,tone:"text"},{text:s.reading,width:o.reading,tone:s.tone??"text"}];if(o.meter>0)u.push({text:c??"",width:o.meter,tone:s.meter?s.tone??"text":"muted"});return u.push({text:l[0]??"",width:o.meaning,tone:"muted"}),oe("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[oe(ja,{palette:t,gap:is,stripe:a%2===1,cells:u},void 0,!1,void 0,this),l.slice(1).map((d,f)=>{let p=[{text:"",width:o.what},{text:"",width:o.reading}];if(o.meter>0)p.push({text:"",width:o.meter});return p.push({text:d,width:o.meaning,tone:"muted"}),oe(ja,{palette:t,gap:is,stripe:a%2===1,cells:p},`${s.what}-more-${f}`,!1,void 0,this)})]},`${s.what}-${s.reading}-${a}`,!0,void 0,this)})]},void 0,!0,void 0,this)}function xE(e){let{palette:t,cfg:r,snap:n,width:o,onRefresh:i}=e,s=ye(),[,a]=Y$(0);if(V$(()=>{let O=setInterval(()=>{a((ae)=>{let Ae=ae+1;if(i&&Ae%X$===0)i();return Ae})},J$);return()=>clearInterval(O)},[i]),!r)return oe(it,{palette:t,title:"No configuration loaded",body:"Add services to .devctl/config.yaml or finish setup."},void 0,!1,void 0,this);let l=Object.keys(r.services).sort(),c=l.some((O)=>jk(r.services[O])),u=Dk(l,n),d=Vk(u,c),f=c&&u.live>0?u.healthy/u.live:u.total>0?u.live/u.total:0,p=Qi(f,Q$),m=u.failed>0?"error":c&&u.live>0&&u.healthy<u.live?"warning":"success",h=Fk(o,s.pad),g=n?.session_id?kd(n.session_id):void 0,w=g?Ca(Date.now()-g.getTime()):"just started",v=n?.logs.total??0,S=n?.logs.errors??0,E=n?.logs.seen??v,_=n?.logs.seenErrors??S,y=Nk(n?.logs.counts??{}),b=n?.proxy.routes??[],k=n?.credentials,x=(k?.entries??[]).filter((O)=>O.valid).length,L=n?.system,F=L?L.memAvailableKB??L.memFreeKB:0,B=L?Wk(L.loadAvg1,L.cpuCount):void 0,K=L?zk(F,L.memTotalKB):void 0,V=[];if(L&&B&&K){V.push(B,K,{what:"Computer",reading:Bk(L.platform),meaning:`on for ${Ca(L.hostUptimeSec*Z$)}`,tone:"text"});let O=n?.stats_series;if(O&&O.cpu.length>1)V.push({what:"Load trend",reading:Xm(O.cpu),meaning:`${Math.round(O.interval_ms/1000)}s samples`,tone:"text"});if(O&&O.mem.length>1)V.push({what:"RAM trend",reading:Xm(O.mem),meaning:"used memory over the same window",tone:"text"})}let X=u.failed>0||B?.tone==="error"||K?.tone==="error"?"error":m==="warning"||B?.tone==="warning"||K?.tone==="warning"?"warning":"success",te=[{what:"This session",reading:w,meaning:"how long this run has been going",tone:"text"},{what:"Profile",reading:n?.profile||"none",meaning:"which group of services is selected",tone:n?.profile?"text":"muted"},{what:"This window",reading:n?.detached?"closed":"watching",meaning:n?.detached?"services keep running without this screen":"you are watching the services from here",tone:n?.detached?"warning":"text"},{what:"Project folder",reading:"",meaning:r.repoRoot,tone:"muted"}],R=[{what:"Lines kept",reading:String(v),meaning:"log lines still in memory",tone:"text"},...E>v?[{what:"Lines seen",reading:String(E),meaning:"ingested this session, including rotated-out lines",tone:"text"}]:[],{what:"Error lines",reading:String(_),meaning:_>0?"open Logs and press e to see only errors":"no ERROR or FATAL lines",tone:_>0?"error":"muted"},...y.map(([O,ae])=>({what:O,reading:String(ae),meaning:"lines from this service",tone:"text"}))],U=[{what:"Web proxy",reading:n?.proxy.running?"on":"off",meaning:n?.proxy.running?`${b.length} apps${n.proxy.address?` at ${n.proxy.address}`:""}`:"not forwarding local URLs",tone:n?.proxy.running?"success":"muted"},{what:"Agent tools",reading:n?.mcp?.running?"on":"off",meaning:n?.mcp?.address?`Cursor talks to devctl at ${n.mcp.address}`:"turn on from Settings \u2192 MCP",tone:n?.mcp?.running?"success":"muted"},{what:"Google account",reading:n?.identity.user?"signed in":"not signed in",meaning:[n?.identity.user,n?.identity.project].filter(Boolean).join(" \xB7 ")||"no Google user for this session",tone:n?.identity.user?"success":"muted"},{what:"Saved tokens",reading:k?`${x} of ${k.entries.length} good`:"none",meaning:k?Kk(k.backend):"nothing stored yet",tone:k&&x<k.entries.length?"warning":k?"success":"muted"}];return oe(Pt,{palette:t,title:"stats",scroll:!0,children:[oe(ys,{palette:t,title:`Your services ${u.live} of ${u.total} started`,tone:X,children:[oe(Ua,{palette:t,facts:d,width:h},void 0,!1,void 0,this),oe("box",{height:1,flexShrink:0},void 0,!1,void 0,this),oe("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:oe("text",{wrapMode:"none",children:[oe("span",{fg:t.muted,children:j(c?"Ready":"Started",Qm(d,h).what)},void 0,!1,void 0,this),oe("span",{children:" ".repeat(is)},void 0,!1,void 0,this),oe("span",{fg:Zh(t,{text:"",width:1,tone:m}),children:`[${p}]`},void 0,!1,void 0,this),oe("span",{fg:Zh(t,{text:"",width:1,tone:m}),children:c?` ${u.healthy} of ${u.live||u.total} passing checks`:` ${u.live} of ${u.total} up`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),L?oe(ys,{palette:t,title:"This computer",tone:B?.tone==="error"||K?.tone==="error"?"error":B?.tone==="warning"||K?.tone==="warning"?"warning":"success",children:oe(Ua,{palette:t,facts:V,width:h},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,oe(ys,{palette:t,title:"This session",children:oe(Ua,{palette:t,facts:te,width:h},void 0,!1,void 0,this)},void 0,!1,void 0,this),oe(ys,{palette:t,title:"Each service",tone:u.failed>0?"error":c&&u.live>0&&u.healthy<u.live?"warning":"success",children:u.total===0?oe("text",{fg:t.muted,children:"No services in this project yet."},void 0,!1,void 0,this):oe("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[oe(eH,{palette:t,names:l,snap:n,width:h},void 0,!1,void 0,this),oe("box",{height:1,flexShrink:0},void 0,!1,void 0,this),oe("text",{fg:t.muted,wrapMode:"none",children:j("CPU is % of one core. RAM is what that process is holding now.",h)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),oe(ys,{palette:t,title:"Log lines",tone:S>0?"warning":"muted",children:oe(Ua,{palette:t,facts:R,width:h},void 0,!1,void 0,this)},void 0,!1,void 0,this),oe(ys,{palette:t,title:"Other parts",children:oe(Ua,{palette:t,facts:U,width:h},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function eH(e){let{palette:t,names:r,snap:n,width:o}=e,i=$k(o),s=[{text:"service",width:i.name},{text:"status",width:Yr}];if(i.health)s.push({text:"check",width:dn});if(i.cpu)s.push({text:"cpu",width:Ra});if(i.mem)s.push({text:"ram",width:_a});if(i.up)s.push({text:"up",width:Ea});if(i.rst)s.push({text:"restarts",width:ku});if(i.pid)s.push({text:"pid",width:In});return oe("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[oe(ja,{palette:t,header:!0,gap:Bt,cells:s},void 0,!1,void 0,this),oe(wE,{palette:t,width:o},void 0,!1,void 0,this),r.map((a,l)=>oe(oH,{palette:t,name:a,rt:n?.services[a],cols:i,stripe:l%2===1},a,!1,void 0,this))]},void 0,!0,void 0,this)}function nH(e){if(e===void 0)return"muted";if(e>rH)return"error";if(e>tH)return"warning";return"text"}function oH(e){let{palette:t,name:r,rt:n,cols:o,stripe:i}=e,s=qk(n),a=Gk(n),l=n?.restarts??0,c=[{text:r,width:o.name,color:Ye(r,t)},{text:s,width:Yr,color:dt(t,n?.state??"STOPPED")}];if(o.health)c.push({text:a,width:dn,color:dt(t,n?.health??"UNKNOWN")});if(o.cpu)c.push({text:n?.cpuPercent!==void 0?R0(n.cpuPercent):"\u2014",width:Ra,tone:nH(n?.cpuPercent)});if(o.mem)c.push({text:n?.memoryKB!==void 0?Ta(n.memoryKB):"\u2014",width:_a,tone:"text"});if(o.up)c.push({text:Mk(n),width:Ea,tone:"text"});if(o.rst)c.push({text:String(l),width:ku,tone:l>0?"warning":"muted"});if(o.pid)c.push({text:n?.pid?String(n.pid):"\u2014",width:In,tone:"muted"});return oe("box",{flexDirection:"column",flexShrink:0,overflow:"hidden",children:[oe(ja,{palette:t,gap:Bt,stripe:i,cells:c},void 0,!1,void 0,this),n?.last_error?oe("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:oe("text",{fg:t.error,wrapMode:"none",children:j(` ${n.last_error}`,Math.max(24,o.name+Bt+Yr+dn))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var J$=1000,X$=5,Q$=16,Z$=1000,tH=80,rH=100;var kE=A(()=>{cr();Ht();nt();br();Ut();Su();Re();rt()});import{useRenderer as iH,useTerminalDimensions as sH}from"@opentui/react";import{useCallback as gn,useEffect as aH,useMemo as eg,useRef as $r,useState as qe}from"react";import{jsxDEV as me,Fragment as lH}from"@opentui/react/jsx-dev-runtime";function SE({controller:e,tui:t,onQuit:r,onDown:n,onAttached:o,bootError:i,bootErrorMissing:s=!1,terminalBackground:a,workspace:l}){let{saveTuiPreferences:c,resolveTuiOverridePath:u,userTuiConfigPath:d,validateConfigText:f,freePort:p,readTextFile:m,writeTextFile:h,createStarterConfig:g,validate:w}=l,[v,S]=qe(e),[E,_]=qe(i),y=iH(),{width:b,height:k}=sH(),[x,L]=qe(v?"dashboard":"setup"),[F,B]=qe("none"),[K,V]=qe(""),[X,te]=qe("commands"),[R,U]=qe(0),[O,ae]=qe(0),[Ae,se]=qe(0),[z,ue]=qe([]),[re,pt]=qe(),[xt,le]=qe(E??""),[Oe,Fe]=qe({}),[Qe,kt]=qe(),[at,At]=qe(L0(v?.cfg)),[Se,St]=qe(""),[gt,Ct]=qe(!1),[xr,lt]=qe(),[Lt,Ze]=qe(),[Tt,ur]=qe(0),[dr,Zr]=qe(),[pr,nr]=qe(),kr=$r(null),Sr=$r(null),Cr=$r(null),zt=$r(null),de=$r(null),Z=$r(null),D=$r(null),we=$r(null),ft=$r(null),or=$r(""),[ct,Pe]=qe("quit"),vn=$r(void 0),P=$r(0),[H,ir]=qe(v?.cfg),go=v?.previousPersisted,[Hr,fr]=qe(void 0),yn=JC({tui:t,controller:v,resolveTuiOverridePath:u,terminalBackground:a,userTuiConfigPath:d,snap:re,setStatus:le,saveTuiPreferences:c,setPaletteIndex:U,setOverlay:B,setConfirmKind:Pe,setScreen:L,setSelected:se,screen:x}),{themeName:bn,setThemeName:vo,fontSize:sd,prefsLocked:ad,palette:ve,rootBackground:Mn,settingRows:yo,persistPrefs:Ba,persistTheme:bs,activateSetting:ld}=yn,ce=$C({controller:v,workspace:l,cfg:H,snap:re,screen:x,configReloadError:Hr,setSnap:pt,setStatus:le}),{google:vt,doctor:Et,doctorLoading:wn,doctorError:Wa,doctorProgress:ws,setDoctorTick:xs}=ce,ng=t.keybinds.copy??kn(),bo=eg(()=>Object.keys(H?.services??{}).sort(),[H]),Nn=gn(async()=>{if(!v)return;try{let Q=await v.status();if(pt(Q),Q.profile&&at==="")At(Q.profile);return Q}catch(Q){le(I(Q));return}},[v,at]),cd=zC({controller:v,tui:t,names:bo,screen:x,refresh:Nn,setStatus:le}),{logs:og,setLogs:QE,paused:ig,errorOnly:ud,setErrorOnly:dd,showSystemLogs:sg,logSearch:ag,setLogSearch:lg,logSearchFocused:ZE,setLogSearchFocused:eR,logFollow:cg,logSince:tR,logService:ug,setLogService:pd,logServiceB:rR,setLogServiceB:nR,splitLogs:fd,splitFocus:md,setSplitFocus:oR,logSliceB:dg,logWindowB:pg,logSelectedB:fg,logPinnedB:iR,pinLogViewB:sR,logServices:aR,logShowTimestamps:lR,logShowMeta:cR,logSource:uR,logRegex:mg,logWrap:hg,logPinned:gg,logSelected:vg,logsFullscreen:hd,dashboardLogCursor:dR,setDashboardLogCursor:pR,logFacets:yg,logSources:bg,filteredLogs:wg,filteredLogsB:fR,logWindow:za,logSlice:qa,pinLogView:gd,applyLogCursorA:mR,applyLogCursorB:hR,jumpToLatestLogs:xg}=cd,pi=eg(()=>{if(X==="tasks")return Gm(Object.keys(H?.tasks??{}),K,"tasks","run this task");if(X==="services")return Gm(Object.keys(H?.services??{}),K,"services","exec in this service");return Pk(K,{services:Object.keys(H?.services??{}),tasks:Object.keys(H?.tasks??{})})},[H,K,X]);aH(()=>{ae(0)},[K]);let vd=ek(x,{doctor:Et?.checks.length??0,settings:yo.length,profiles:Object.keys(H?.profiles??{}).length,services:bo.length,logs:fd&&md===1?dg.length:qa.length,mcp:WS(),config:Object.keys(H?.tasks??{}).length}),kg=x==="logs"?fd&&md===1?fg:vg:Ae,en=vd<=0?Math.max(0,kg):Math.max(0,Math.min(kg,vd-1)),gR=x==="detail"?Se:x==="services"?bo[en]??"":"",{inspectorEnv:Sg,inspectorEnvStatus:Cg,inspectorEnvError:Tg,resolveEnvironment:vR}=nT({controller:v,cfg:H,envService:gR}),yd=eg(()=>Lt?Pu(Lt.tree):[],[Lt]),yR=yd[Au(Tt,yd.length)]?.span,fi=gn(()=>{if(B("none"),V(""),te("commands"),eR(!1),vn.current)clearTimeout(vn.current)},[]),bd=gn((Q)=>{ue((ut)=>ut.includes(Q)?ut.filter((DR)=>DR!==Q):[...ut,Q])},[]),Eg=KC({tui:t,controller:v,cfg:H,persistPrefs:Ba,snap:re,refresh:Nn,setStatus:le}),{mcpPortDraft:bR,mcpPort:wR,toggleMcpTool:xR,toggleMcp:kR,copyMcpSnippet:SR}=Eg;OC({controller:v,cfg:H,paused:ig,logSince:tR,refresh:Nn,setLogs:QE,setCfg:ir,setConfigReloadError:fr,setStatus:le});let Ga=gn((Q)=>{St(Q),L("detail")},[]),wd=gn((Q)=>{if(Q===""||!v)return;v.getTrace(Q).then((ut)=>{ur(0),Ze(ut),B("trace")}).catch((ut)=>{le(I(ut))})},[v]),Rg=gn((Q)=>{if(Q!==void 0)ur(Q);B("span-details")},[]),_g=gn((Q)=>{let ut=Q.value!==""?Q.value:Q.required?"(required, not set)":"(empty)";nr({title:Q.key,body:ut}),B("scroll-text")},[]),xd=UC({controller:v,workspace:l,cfg:H,snap:re,refresh:Nn,setStatus:le,setOverlay:B}),{plan:Ka,planInitiallyRunning:CR,planBusy:TR,lifecycle:Pg}=xd,xn=eT({workspace:l,renderer:y,setOverlay:B,setStatus:le,setScreen:L,onAttached:o,setController:S,setCfg:ir,setBootError:_}),{configEditRef:ER,configEditText:RR,configEditError:_R,setConfigEditError:PR,openConfigBuffer:Ag,saveConfigBuffer:AR}=IC({cfg:H,readTextFile:m,setOverlay:B,setStatus:le,validateConfigText:f,writeTextFile:h,controller:v,setConfirmKind:Pe,refresh:Nn}),Lg=gn(async()=>{let Q=y.getSelection()?.getSelectedText()??"";if(Q.trim()===""){le("Nothing selected \u2014 drag to highlight text");return}try{await Ru(Q);let ut=Q.split(`
|
|
2496
|
-
`).length;le(ut===1?"Copied selection":`Copied ${ut} selected lines`)}catch(ut){le(I(ut))}},[y]),{runCommand:Va}=_C({setOverlay:B,setQuery:V,setSlashPicker:te,checked:z,setConfirmKind:Pe,setStatus:le,persistTheme:bs,setPaletteIndex:U,themeName:bn,setScreen:L,setSelected:se,screen:x,renderer:y,cfg:H,setScrollText:nr,reveal:gt,controller:v,refresh:Nn,profile:at,setReveal:Ct,resolveEnvironment:vR,openDetail:Ga,copySelection:Lg,lastExportPath:or,openConfigBuffer:Ag,onDown:n??((Q)=>r(Q)),workspace:l,logView:cd,diagnostics:ce,lifecycleActions:xd}),Ig=gn(()=>{let Q=os(pi,O);if(X==="tasks"){if(!Q){le(pi.length===0?"no tasks configured":"pick a task");return}te("commands");let ut=pn("run");if(ut)Va(ut,[Q.name]);return}if(X==="services"){if(!Q){le(pi.length===0?"no services configured":"pick a service");return}te("commands"),V(`exec ${Q.name} -- `);return}if(!Q){le(K.trim()===""?"pick a command from the list":`unknown command /${K}`),fi();return}Va(Q,_k(Q,K))},[fi,pi,K,Va,O,X]),Dg=gn((Q)=>{bs(Q),fi()},[fi,bs]);cC({tui:t,controller:v,cfg:H,snap:re,ui:{screen:x,overlay:F,onQuit:r,onDown:n??((Q)=>r(Q)),closeOverlay:fi,confirmKind:ct,confirmDetail:Oe,portTarget:Qe,profile:at,listCursor:en,names:bo,listCount:vd,openDetail:Ga,copySelection:Lg,height:k,paletteIndex:R,applyTheme:Dg,runCommand:Va,saveConfigBuffer:AR,filtered:pi,slashIndex:O,submitSlash:Ig,advanceWizard:()=>void xn.advanceWizard(),bootErrorMissing:s,bootError:E,createStarterConfig:g,startWizard:xn.startWizard,toggleChecked:bd,checked:z,detailName:Se,refresh:Nn,openConfigBuffer:Ag,setOverlay:B,setConfirmKind:Pe,setConfirmDetail:Fe,setPortTarget:kt,setLogDetail:lt,logDetail:xr,openTrace:wd,openSpanLogs:Rg,traceSpanCount:yd.length,setTraceSpanIndex:ur,setLogSearch:lg,setProfile:At,setStatus:le,setPaletteIndex:U,setSlashIndex:ae,setQuery:V,setSlashPicker:te,setScreen:L,setSelected:se,setChecked:ue,setConfigEditError:PR,freePort:p},logView:cd,lifecycleActions:xd,mcp:Eg,preferences:yn,diagnostics:ce,refs:{interruptArmedAt:P,leaderTimer:vn,logDetailsScrollRef:zt,traceScrollRef:de,traceDetailScrollRef:Z,scrollTextScrollRef:we,routeDetailsScrollRef:D,planScrollRef:ft,helpScrollRef:Sr,configScrollRef:kr,detailScrollRef:Cr}});let Og=lk(ct,at,Oe),LR=new Set(Ka?.waves.flat()??[]),IR=Ka===void 0||Pg==="stop"?"":Object.entries(re?.services??{}).find(([Q,ut])=>LR.has(Q)&&ut.state==="FAILED")?.[0]??"";return me(Tm.Provider,{value:ka(sd),children:me("box",{flexDirection:"column",width:b,height:k,backgroundColor:Mn,overflow:"hidden",children:[hd?null:me(lH,{children:[me(Xk,{palette:ve,cfg:H,snap:re,google:vt,profile:at,reveal:gt,width:b},void 0,!1,void 0,this),me(Qk,{palette:ve,screen:x,width:b,onSelect:L},void 0,!1,void 0,this),Hr?me("box",{height:1,paddingLeft:1,backgroundColor:ve.panel,overflow:"hidden",children:me("text",{fg:ve.error,wrapMode:"none",children:`\u26A0 configuration reload failed: ${Hr}`},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),me("box",{flexGrow:1,overflow:"hidden",children:[x==="dashboard"?me(GT,{palette:ve,cfg:H,snap:re,logs:og,names:bo,selected:en,checked:z,width:b,followTick:cg,logService:ug,errorOnly:ud,showSystemLogs:sg,onOpen:Ga,onSelectIndex:se,selectedLog:dR,onToggle:bd,logSources:bg,onFilterService:pd,onToggleErrors:()=>dd((Q)=>!Q),onShowErrors:()=>{pd(""),dd(!0)},wrapMode:hg,view:qa,follow:!gg,onLeaveLatest:gd,onPickLog:(Q)=>{let ut=qa[Q];if(!ut)return;pR(Q),lt(ut),gd()},viewStart:za.start,viewTotal:wg.length,newer:za.newer,onJumpLatest:xg,facets:yg,leftover:go,search:ag,regex:mg},void 0,!1,void 0,this):null,x==="services"?me(pE,{palette:ve,cfg:H,names:bo,snap:re,selected:en,checked:z,width:b,reveal:gt,onOpen:Ga,onSelectIndex:se,onToggle:bd,resolvedEnv:Sg,envStatus:Cg,envError:Tg,onSelectEnv:_g},void 0,!1,void 0,this):null,x==="detail"?me(dE,{palette:ve,cfg:H,snap:re,name:Se,reveal:gt,width:b,envScrollRef:Cr,resolvedEnv:Sg,envStatus:Cg,envError:Tg,onSelectEnv:_g},void 0,!1,void 0,this):null,x==="logs"?me(XT,{palette:ve,logs:og,names:bo,logSources:bg,service:ug,errorOnly:ud,showSystemLogs:sg,search:ag,searchFocused:ZE,followTick:cg,width:b,onSearch:lg,onService:pd,onToggleErrors:()=>dd((Q)=>!Q),source:uR,regex:mg,services:aR,showTimestamps:lR,showMeta:cR,view:qa,wrapMode:hg,selected:vg,follow:!gg,newer:za.newer,viewStart:za.start,viewTotal:wg.length,onSelect:mR,fullscreen:hd,onLeaveLatest:gd,onJumpLatest:xg,facets:yg,split:fd,splitFocus:md,serviceB:rR,viewB:dg,selectedB:fg,followB:!iR,newerB:pg.newer,viewStartB:pg.start,viewTotalB:fR.length,onServiceB:nR,onSelectB:hR,onLeaveLatestB:sR,onFocusPane:oR},void 0,!1,void 0,this):null,x==="auth"?me(LT,{palette:ve,cfg:H,google:vt,identity:re?.identity},void 0,!1,void 0,this):null,x==="credentials"?me($T,{palette:ve,credentials:re?.credentials},void 0,!1,void 0,this):null,x==="proxy"?me(aE,{palette:ve,cfg:H,snap:re,width:b,onSelectRoute:(Q)=>{Zr(Q),B("route-details")},onOpenTrace:wd},void 0,!1,void 0,this):null,x==="mcp"?me(zS,{palette:ve,snap:re,port:wR,portDraft:bR,selected:en,onPick:se,onToggle:()=>{kR()},onCopy:SR,onToggleTool:(Q)=>{xR(Q)}},void 0,!1,void 0,this):null,x==="doctor"?me(VT,{palette:ve,report:Et,loading:wn,progress:ws,error:Wa,selected:en,onPick:se,onReload:()=>{xs((Q)=>Q+1),le("Re-running doctor")}},void 0,!1,void 0,this):null,x==="stats"?me(xE,{palette:ve,cfg:H,snap:re,width:b,onRefresh:Nn},void 0,!1,void 0,this):null,x==="config"?me(NT,{palette:ve,cfg:H,width:b,selectedTask:en,scrollRef:kr},void 0,!1,void 0,this):null,x==="profiles"?me(eE,{palette:ve,cfg:H,snap:re,profile:at,selected:en,onPick:se},void 0,!1,void 0,this):null,x==="setup"?me(yE,{issues:H?w(H):["configuration not loaded"],palette:ve,cfg:H,google:vt,bootError:E,bootErrorMissing:s,step:en},void 0,!1,void 0,this):null,x==="settings"?me(gE,{palette:ve,items:yo,selected:en,locked:ad,width:b,onPick:se,onActivate:ld},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),F==="slash"?me(xT,{palette:ve,items:pi,query:K,selected:O,title:X==="tasks"?"tasks":X==="services"?"services":"commands",onQuery:V,onSubmit:Ig},void 0,!1,void 0,this):null,F==="themes"?me(ET,{palette:ve,themeName:bn,selected:R%_t.length,termW:b,termH:k,onIndex:U,onPreview:vo,onPick:Dg},void 0,!1,void 0,this):null,F==="help"?me(VS,{palette:ve,termW:b,termH:k,copyKey:ng,scrollRef:Sr},void 0,!1,void 0,this):null,F==="leader"?me(uT,{palette:ve,termW:b,termH:k},void 0,!1,void 0,this):null,F==="confirm"?me(aT,{palette:ve,title:Og.title,body:Og.body,kind:ct,termW:b,termH:k},void 0,!1,void 0,this):null,F==="setup-wizard"?me(QC,{palette:ve,termW:b,termH:k,step:xn.step,answers:xn.answers,repo:xn.repo,draft:xn.draft,authStatus:xn.authStatus,onDraft:xn.setDraft,onSubmit:()=>void xn.advanceWizard()},void 0,!1,void 0,this):null,F==="log-details"?me(pT,{palette:ve,event:xr,termW:b,termH:k,scrollRef:zt,onViewTrace:wd},void 0,!1,void 0,this):null,F==="trace"||F==="span-details"?me(_T,{palette:ve,trace:Lt?.tree,selected:Tt,onSelect:ur,onOpenLogs:Rg,termW:b,termH:k,scrollRef:de},void 0,!1,void 0,this):null,F==="span-details"?me(PT,{palette:ve,span:yR,records:Lt?.events,termW:b,termH:k,scrollRef:Z},void 0,!1,void 0,this):null,F==="route-details"?me(vT,{palette:ve,route:dr,termW:b,termH:k,scrollRef:D},void 0,!1,void 0,this):null,F==="scroll-text"&&pr?me(bT,{palette:ve,title:pr.title,body:pr.body,termW:b,termH:k,scrollRef:we},void 0,!1,void 0,this):null,F==="config-edit"&&H?me(iT,{palette:ve,path:H.configPath,initialValue:RR,error:_R,termW:b,termH:k,textareaRef:ER},void 0,!1,void 0,this):null,F==="plan"&&Ka?me(hT,{palette:ve,plan:Ka,snap:re,busy:TR,failed:IR,kind:Pg,termW:b,termH:k,scrollRef:ft,initiallyRunning:CR,onDismiss:fi},void 0,!1,void 0,this):null,hd?null:me(Zk,{palette:ve,screen:x,overlay:F,status:xt,paused:ig,errorOnly:ud,width:b,copyKey:ng},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var CE=A(()=>{ne();cr();eh();Ht();wr();si();so();Ut();Lu();uC();PC();DC();MC();HC();jC();qC();VC();XC();tT();oT();sT();lT();Rh();dT();fT();gT();yT();wT();Dh();kT();RT();AT();IT();FT();HT();KT();YT();QT();Oa();tE();lE();Jh();fE();vE();bE();kE();Mr();rt();Vr()});import{createCliRenderer as cH}from"@opentui/core";import{createRoot as uH}from"@opentui/react";import{jsxDEV as dH}from"@opentui/react/jsx-dev-runtime";async function TE(e,t){let r=e.loadTuiConfig(t.cfg.repoRoot,t.cfg.ui.keymap);await RE(e,t,r)}async function EE(e,t){let r,n,o=!1;try{r=await e.openTui("",t)}catch(s){n=I(s),o=Al(s,Po)}let i=e.loadTuiConfig(r?.cfg.repoRoot??process.cwd(),r?.cfg.ui.keymap);await RE(e,r,i,n,o)}async function RE(e,t,r=e.loadTuiConfig(t?.cfg.repoRoot??process.cwd(),t?.cfg.ui.keymap),n,o=!1){Ya();let i=Fg(),s=await cH({exitOnCtrlC:!1,useMouse:r.mouse,enableMouseMovement:r.mouse,useKittyKeyboard:{}}),a=uH(s),l=null;try{l=(await s.getPalette({timeout:120,size:16})).defaultBackground}catch{}await new Promise((c)=>{let u=(f)=>{let p=()=>{a.unmount(),i(),s.destroy(),c(),process.exit(0)};if(!t){p();return}t.close({detach:f,shutdownSupervisor:!0}).finally(p)},d=(f)=>{let p=()=>{a.unmount(),i(),s.destroy(),c(),process.exit(0)};if(!t){p();return}t.shutdown({stopServices:!f}).then(()=>t?.close({detach:!0})).finally(p)};a.render(dH(SE,{workspace:p0(e),controller:t,tui:r,onQuit:u,onDown:d,onAttached:(f)=>{t=f},bootError:n,bootErrorMissing:o,terminalBackground:l},void 0,!1,void 0,this))})}var tg=A(()=>{f0();ne();CE()});if(process.env.METADATA_SERVER_DETECTION===void 0)process.env.METADATA_SERVER_DETECTION="bios-only";if(process.env.GCE_METADATA_TIMEOUT===void 0)process.env.GCE_METADATA_TIMEOUT="0";import{existsSync as ol,readFileSync as tl}from"fs";import{dirname as c1,isAbsolute as Kg,join as nl,resolve as u1}from"path";Ja();Ja();import{spawnSync as UR}from"child_process";import{randomBytes as Td}from"crypto";import{copyFileSync as jR,existsSync as Fn,mkdirSync as BR,readdirSync as WR,readFileSync as Ed,renameSync as Rd,statSync as zR,unlinkSync as Sd,writeFileSync as qR}from"fs";import{homedir as $g}from"os";import{basename as GR,dirname as Cd,isAbsolute as KR,join as It,resolve as VR}from"path";var YR=448,JR=384;function ks(e,t){let r=e.startsWith("~/")?It($g(),e.slice(2)):e;return KR(r)?r:VR(t,r)}function Er(){let e=process.env.DEVCTL_HOME;if(e&&e!=="")return e;return It($g(),".devctl")}function tn(e){BR(e,{recursive:!0,mode:YR})}function mi(e){let t=It(Er(),"state",Tr(e)),r=It(Er(),"sessions",Tr(e));if(!Fn(t)&&Fn(r)){tn(Cd(t));try{Rd(r,t)}catch{tn(t);for(let n of["state.json","devctl.lock","devctl.sock"]){let o=It(r,n);if(Fn(o))jR(o,It(t,n))}}}return tn(t),t}function Xa(){let e=It(Er(),"logs");return tn(e),e}function Qa(){let e=It(Er(),"exports");return tn(e),e}function Ur(){let e=It(Er(),"credentials");return tn(e),e}function Za(e,t=process.platform){if(t==="win32")return`\\\\.\\pipe\\devctl-${Tr(e)}`;return It(mi(e),"devctl.sock")}function XR(e){return It(mi(e),"devctl.lock")}function Hg(e){return It(mi(e),"state.json")}function Ss(e){return It(mi(e),"bootstrap.log")}var QR=5,Ug="bootstrap-";function jg(e){let t=Ss(e);if(!Fn(t))return;let r=mi(e),n=It(r,`${Ug}${_d()}.log`);try{Rd(t,n)}catch{return}ZR(r)}function ZR(e){let t;try{t=WR(e).filter((n)=>n.startsWith(Ug)&&n.endsWith(".log"))}catch{return}let r=t.map((n)=>{let o=It(e,n);try{return{path:o,mtime:zR(o).mtimeMs}}catch{return}}).filter((n)=>n!==void 0).sort((n,o)=>o.mtime-n.mtime);for(let n=QR;n<r.length;n++)try{Sd(r[n].path)}catch{}}function jr(e,t){tn(Cd(e));let r=It(Cd(e),`.${GR(e)}.tmp-${process.pid}-${Td(4).toString("hex")}`);qR(r,t,{mode:JR}),Rd(r,e)}function _d(e=new Date){return`${e.toISOString().slice(0,19).replace(/:/g,"-")+"Z"}-${Td(3).toString("hex")}`}function $n(e){return Pd(Hg(e))}function Pd(e){if(!Fn(e))return;try{let t=JSON.parse(Ed(e,"utf8"));if(Array.isArray(t.processes)&&typeof t.repo_root==="string")return t;return}catch{return}}function Bg(e,t){jr(Hg(e),`${JSON.stringify(t,null,2)}
|
|
2497
|
-
`)}function
|
|
2498
|
-
`),t}function
|
|
2499
|
-
`,{mode:384}),
|
|
2500
|
-
`,a=
|
|
2498
|
+
Enter is preview only. /import compose ${ir} --write to save.`}),e("scroll-text")}catch(fr){i(I(fr))}return}case"diff":if(!p){i("no configuration loaded");return}m({title:"config sources",body:EC(p,h)}),e("scroll-text");return;case"daemon":{let P=p?.repoRoot;if(!P){i("no repository");return}let H=R(P);if(!U(H)){i("no daemon bootstrap log yet for this repository");return}m({title:"daemon bootstrap",body:O(H)}),e("scroll-text");return}case"reload":if(!g)return;g.reload().then((P)=>{if(i(P.restart_required.length===0?"Configuration reloaded":`Reload requires restart: ${P.restart_required.join(", ")}`),P.restart_required.length>0)o("reload"),e("confirm");w()});return;case"doctor":c("doctor");return;case"stats":c("stats");return;case"start":await Z(vn,v);return;case"stop":await D(vn);return;case"restart":{let P=bk(Pe),H=Om(P.services,n);await we(H,v,P.cascade);return}case"run":{let P=Pe[0]??"";if(!P){r("tasks"),t(""),e("slash"),i(Object.keys(p?.tasks??{}).length===0?"no tasks configured":"pick a task");return}if(!g){i("no daemon attached");return}try{let H=await g.runTask(P);Qe(`task:${P}`),c("logs"),i(`task ${P} exited ${H.code}`)}catch(H){throw Qe(`task:${P}`),c("logs"),H}return}case"exec":{let P=wk(Pe);if(!P.service){r("services"),t(""),e("slash"),i(Object.keys(p?.services??{}).length===0?"no services configured":"pick a service");return}if(!g){i("no daemon attached");return}if(P.printEnv){if(!p?.services[P.service]){i(`unknown service ${P.service}`);return}if(P.reveal)S(!0);i(`Resolving environment for ${P.service}\u2026`);try{await E(P.service),_(P.service),i(`Resolved environment for ${P.service}`)}catch(H){_(P.service),i(I(H))}return}if(P.command.length===0){i("usage: /exec <service> -- <command\u2026>");return}try{let H=await g.execService(P.service,P.command);Qe(`${P.service}:exec`),c("logs"),i(`${P.service}:exec exited ${H.code}`)}catch(H){throw Qe(`${P.service}:exec`),c("logs"),H}return}case"refresh":if(d==="auth"){await zt();return}await w(),i("Refreshed status and logs");return;case"pause":at((P)=>!P),c("logs");return;case"filter":Lt((P)=>!P),c("logs");return;case"system":Se(),c("logs");return;case"clear":St();return;case"reveal":{let P=!h;S(P),i(P?"Secrets visible this session":"Secrets hidden");return}case"wrap":{let P=pu(gt);Ct(P),i(`Log ${mu(P)}`);return}case"copy":await y();return;case"export":{let P=se(Pe[0]);if(g)await g.logs({export:P,services:xr,level:lt?"ERROR":It,search:Ze,regex:Tt,source:ur});else z(P,dr);b.current=P,i(`Exported ${P}`);return}case"exports":{let P=b.current||ue();re(P),i(`Opened ${ue()}`);return}case"regex":Zr((P)=>!P),i(Tt?"Substring search":"Regex search");return;case"since":pr(Pe[0]||new Date(Date.now()-3600000).toISOString()),i(`Logs since ${Pe[0]||"1h"}`);return;case"until":nr(Pe[0]||new Date().toISOString()),i(`Logs until ${Pe[0]||"now"}`);return;case"history":{let P=pt(),H=Pe[0]||P[0];if(!H){i("No persisted log sessions");return}kr(xt(H)),i(`Loaded session ${H}`);return}case"buffer":k();return;case"edit":{if(!p)return;let P=process.env.DEVCTL_EDITOR||process.env.EDITOR,H=P?[P,p.configPath]:process.platform==="darwin"?["open",p.configPath]:["xdg-open",p.configPath];Bun.spawn({cmd:H,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),i(`Opened ${p.configPath} in ${H[0]}. Run /reload after saving.`);return}default:i(`/${ct.name}`)}}catch(P){i(I(P))}finally{setTimeout(()=>{ft.current=!1},_F)}},[we,Z,D,n,p,St,g,y,lt,dr,It,Tt,Ze,xr,ur,gt,x,k,_,s,v,w,zt,f,h,d,Sr,r,l,Cr,Se])}}var _F=50;var LC=A(()=>{ne();Ah();Lh();br();Ut();rt()});import{useCallback as IC,useRef as PF,useState as DC}from"react";function OC({cfg:e,readTextFile:t,setOverlay:r,setStatus:n,validateConfigText:o,writeTextFile:i,controller:s,setConfirmKind:a,refresh:l}){let c=PF(null),[u,d]=DC(""),[f,p]=DC(""),m=IC(()=>{if(!e)return;try{d(t(e.configPath)),p(""),r("config-edit")}catch(g){n(I(g))}},[e]),h=IC(()=>{if(!e)return;let g=c.current?.plainText??u,w=o(e.repoRoot,e.configPath,g);if(w.length>0){p(w.join(`
|
|
2499
|
+
`)),n("Config buffer not saved");return}if(i(e.configPath,g),p(""),r("none"),!s){n(`Wrote ${e.configPath}`);return}s.reload().then((v)=>{if(n(v.restart_required.length===0?"Configuration saved and reloaded":`Saved; restart required: ${v.restart_required.join(", ")}`),v.restart_required.length>0)a("reload"),r("confirm");l()})},[e,u,s,l]);return{configEditRef:c,configEditText:u,configEditError:f,setConfigEditError:p,openConfigBuffer:m,saveConfigBuffer:h}}var MC=A(()=>{ne()});import{useEffect as AF}from"react";function NC({controller:e,cfg:t,paused:r,logSince:n,refresh:o,setLogs:i,setCfg:s,setConfigReloadError:a,setStatus:l}){return AF(()=>{if(!e)return;let c,u=!1,d=[],f=t&&t.logs.max_memory_events>0?t.logs.max_memory_events:50000,p=()=>{if(c=void 0,d.length>0){let h=d.splice(0,d.length);i((g)=>G0(g,h,n,f))}if(u)u=!1,o()},m=e.onEvent((h)=>{if(h.type===yi&&h.payload&&typeof h.payload==="object"&&"event"in h.payload){let g=h.payload.event;if(!r)d.push(g);if(!c)c=setTimeout(p,30);return}if(h.type===Ts){a(pk(h));return}if(h.type===cl)a(void 0),e.configSnapshot().then(s).catch((g)=>l(I(g)));if(u=!0,!c)c=setTimeout(p,30)});return()=>{if(m(),c)clearTimeout(c)}},[e,n,r,o]),{}}var FC=A(()=>{ne();wr();br()});import{useCallback as LF,useEffect as $C,useRef as HC,useState as fs}from"react";function UC({controller:e,workspace:t,cfg:r,snap:n,screen:o,configReloadError:i,setSnap:s,setStatus:a}){let{detectGoogle:l,runDoctor:c,loadPath:u}=t,[d,f]=fs(),[p,m]=fs(),[h,g]=fs(!1),[w,v]=fs(""),[S,E]=fs(0),[_,y]=fs({active:"Preparing diagnostics",checks:[]}),b=HC(void 0),k=HC(0),x=LF(async()=>{if(!e){a("Supervisor is not running");return}a("Probing configured identities\u2026");try{let L=await e.refreshAuth();s((V)=>V?{...V,identity:L}:V);let F=Object.values(L.service_account_status),B=F.filter((V)=>V==="available").length,K=F.filter((V)=>V==="unavailable").length;a(F.length===0?"Identity refreshed \u2014 no service accounts configured":`Identity refreshed \u2014 ${B} available${K>0?`, ${K} unavailable`:""}`)}catch(L){a(I(L))}},[e]);return $C(()=>{l(r?.google.project_id??"").then(f).catch((L)=>{a(I(L))})},[r?.google.project_id,n?.identity.project]),$C(()=>{if(o!=="doctor"||!r)return;let L=b.current,F=n?.session_id??"";if(L?.cfg===r&&L.tick===S&&L.sessionID===F&&L.reloadError===i)return;b.current={cfg:r,tick:S,sessionID:F,reloadError:i};let B=++k.current;g(!0),v(""),y({active:"Preparing diagnostics",checks:[]});let K;if(r.configPath!==""){K="";try{u(r.repoRoot,r.configPath)}catch(V){K=I(V)}}c(r,(V)=>{if(B===k.current)y(V)},{services:n?.services,proxyRunning:n?.proxy.running,repositoryConfigError:K}).then((V)=>{if(B!==k.current)return;m(V)}).catch((V)=>{if(B!==k.current)return;v(I(V))}).finally(()=>{if(B===k.current)g(!1)})},[o,r,S,n?.session_id,i]),{google:d,setGoogle:f,doctor:p,doctorLoading:h,doctorError:w,doctorProgress:_,setDoctorTick:E,refreshAuth:x}}var jC=A(()=>{ne()});import{useCallback as Ih,useState as ju}from"react";function BC({controller:e,workspace:t,cfg:r,snap:n,refresh:o,setStatus:i,setOverlay:s}){let{resolveStartRequest:a,startupPlan:l,shutdownPlan:c,shutdownPlanExact:u}=t,[d,f]=ju(),[p,m]=ju([]),[h,g]=ju(!1),[w,v]=ju("start"),S=Ih(async(y,b)=>{if(!e||!r){i("no configuration loaded");return}try{let k=y.length>0,x=a(r,{services:y,profile:k?void 0:b}),L=l(r,x.services,x.profile);v("start"),m(L.waves.flat().filter((K)=>ri(n?.services[K]))),f(L),s("plan"),g(!0);let F=x.services.filter((K)=>!ri(n?.services[K])),B=await e.start({services:F.length>0?F:x.services,profile:k?void 0:x.profile});await o(),g(!1),i(tC(B))}catch(k){g(!1),await o(),i(I(k))}},[r,e,o,n]),E=Ih(async(y)=>{if(!e||!r){i("no configuration loaded");return}let b=y.length>0?y:Object.entries(n?.services??{}).filter(([,k])=>k.state!=="STOPPED"&&k.state!=="UNKNOWN").map(([k])=>k);if(b.length===0){i("nothing to stop");return}try{let k=c(r,b);v("stop"),m([]),f(k),s("plan"),g(!0),await e.stop(y),await o(),g(!1),i(rC(k))}catch(k){g(!1),await o(),i(I(k))}},[r,e,o,n]),_=Ih(async(y,b,k=!1)=>{if(!e||!r){i("no configuration loaded");return}try{let x=eC(r,y,b),L=k?c(r,x.services):u(r,x.services);v("restart"),m([]),f(L),s("plan"),g(!0),await e.restart(x.services,k),await o(),g(!1);let F=Nu(L);i(F===""?"Restarted selected services":`Restarted ${F}`)}catch(x){g(!1),await o(),i(I(x))}},[r,e,o]);return{plan:d,planInitiallyRunning:p,planBusy:h,lifecycle:w,beginStart:S,beginStop:E,beginRestart:_}}var WC=A(()=>{ne();Fu();Ut()});import{useCallback as Xr,useEffect as mn,useMemo as po,useRef as Na,useState as Ee}from"react";function qC(e,t,r,n,o){let i=Hm(e,t.sliceLen,t.windowStart,t.windowNewer);if(i.startDelta!==0){r(Math.max(0,t.windowStart+i.startDelta)),n(!0),o(i.selected);return}let s=Math.max(t.sliceLen-1,0),a=t.sliceLen>0&&(i.selected<s||t.windowNewer>0);if(a&&!t.pinned)r(fu(t.filteredLen));n(a),o(i.selected)}function GC({controller:e,tui:t,names:r,screen:n,refresh:o,setStatus:i}){let[s,a]=Ee([]),[l,c]=Ee(!1),[u,d]=Ee(!1),[f,p]=Ee(!0),[m,h]=Ee(""),[g,w]=Ee(!1),[v,S]=Ee(0),[E,_]=Ee(""),[y,b]=Ee(""),[k,x]=Ee(""),[L,F]=Ee(""),[B,K]=Ee(!1),[V,X]=Ee(0),[te,R]=Ee(Jr-1),[U,O]=Ee(!1),[ae,Ae]=Ee(0),se=zC,[z,ue]=Ee(t.log_timestamps!==!1),[re,pt]=Ee(t.log_metadata!==!1),[xt,le]=Ee(()=>[...q0]),[Oe]=Ee(""),[Fe]=Ee(""),[Qe,kt]=Ee(!1),[at,Lt]=Ee("all"),[Se,St]=Ee(!1),[gt,Ct]=Ee(Jr-1),[xr,lt]=Ee(!1),[It,Ze]=Ee(-1),[Tt,ur]=Ee(),[dr,Zr]=Ee(""),[pr,nr]=Ee(!1),[kr,Sr]=Ee(!1),Cr=Na([]),[zt,de]=Ee(0),Z=po(()=>hu(r,s,xt),[r,s,xt]);mn(()=>{le((ce)=>{let vt=new Set(ce),Et=!1;for(let wn of s)if(wn.service!==""&&!r.includes(wn.service)&&!vt.has(wn.service))vt.add(wn.service),Et=!0;return Et?[...vt].sort():ce})},[s,r]);let D=po(()=>ni(s,{service:k,services:se,errorOnly:u,search:m,regex:Qe,source:Fe,since:E,until:y,systemLogs:f}),[u,Qe,m,k,se,E,Fe,y,s,f]),we=po(()=>$m(D,Se,zt),[D,Se,zt]),ft=we.items,or=po(()=>ni(s,{service:L,services:se,errorOnly:u,search:m,regex:Qe,source:Fe,since:E,until:y,systemLogs:f}),[u,Qe,m,L,se,E,Fe,y,s,f]),ct=po(()=>$m(or,U,ae),[or,U,ae]),Pe=ct.items,vn=Na(0);vn.current=D.length;let P=Na(0);P.current=or.length;let H=Na(!1);H.current=Se;let ir=Na(!1);ir.current=U,mn(()=>{Ze(-1),H.current=!1,St(!1),Ct(Math.max(0,Math.min(Jr,D.length)-1))},[u,m,k,f]),mn(()=>{ir.current=!1,O(!1),R(Math.max(0,Math.min(Jr,or.length)-1))},[u,m,L,f]),mn(()=>{if(n!=="logs")lt(!1)},[n]),mn(()=>{if(n!=="logs"||Se)return;Ct(Math.max(0,Math.min(Jr,D.length)-1))},[D.length,Se,n]),mn(()=>{if(n!=="logs"||U)return;R(Math.max(0,Math.min(Jr,or.length)-1))},[or.length,U,n]);let go=Xr(()=>{if(H.current)return;H.current=!0,de(fu(vn.current)),St(!0)},[]),Hr=Xr(()=>{if(ir.current)return;ir.current=!0,Ae(fu(P.current)),O(!0)},[]),fr=po(()=>({sliceLen:ft.length,windowStart:we.start,windowNewer:we.newer,filteredLen:D.length,pinned:Se}),[D.length,Se,ft.length,we.newer,we.start]),yn=po(()=>({sliceLen:Pe.length,windowStart:ct.start,windowNewer:ct.newer,filteredLen:or.length,pinned:U}),[or.length,U,Pe.length,ct.newer,ct.start]),bn=Xr((ce)=>qC(ce,fr,de,St,Ct),[fr]),vo=Xr((ce)=>qC(ce,yn,Ae,O,R),[yn]),sd=Xr((ce)=>{if(B&&V===1){vo(ce);return}bn(ce)},[bn,vo,V,B]),ad=Xr((ce)=>{let vt=ft.length,Et=Hm(ce,vt,we.start,we.newer);if(Et.startDelta!==0)de(Math.max(0,we.start+Et.startDelta)),St(!0);Ze(Et.selected)},[ft.length,we.newer,we.start]),ve=Xr(()=>{if(H.current=!1,ir.current=!1,St(!1),O(!1),Ze(-1),n==="logs")Ct(Math.max(0,Math.min(Jr,D.length)-1)),R(Math.max(0,Math.min(Jr,or.length)-1));S((vt)=>vt+1);let ce=Math.max(we.newer,ct.newer);i(ce>0?`Jumped to latest (+${ce} new)`:"Jumped to latest logs")},[D.length,or.length,we.newer,ct.newer,n]),Mn=po(()=>({services:B?zC:k!==""?[k]:se,level:u?"ERROR":Oe,search:m,regex:Qe,source:Fe,since:E,until:y}),[u,Oe,Qe,m,k,se,E,Fe,y,B]),yo=Xr(async()=>{if(!e)return;try{ur(await e.logsStats(Mn))}catch(ce){i(I(ce))}},[e,Mn]),Ba=Xr(async()=>{if(!e||l)return;try{let ce=await e.logsPage(Mn);a((vt)=>K0(vt,ce.events)),Zr(ce.prevCursor),nr(ce.hasPrev),await yo()}catch(ce){i(I(ce))}},[e,Mn,l,yo]),bs=Xr(()=>{H.current=!1,ir.current=!1,a([]),_(new Date().toISOString()),St(!1),O(!1),i("Cleared on-screen log buffer")},[]),ld=Xr(()=>{p((ce)=>!ce)},[]);return mn(()=>{o().then(()=>Ba())},[o,Ba]),mn(()=>{Cr.current=s},[s]),mn(()=>{let ce=Um(Se,we.start,pr),vt=B&&Um(U,ct.start,pr);if(!e||kr||!ce&&!vt)return;Sr(!0),e.logsPage({...Mn,cursor:dr,direction:"backward"}).then((Et)=>{if(Et.sessionChanged){i("Daemon session changed \u2014 older log history is no longer available"),nr(!1);return}let wn=Cr.current,Wa=V0(wn,Et.events);a(Wa);let ws=Wa.length-wn.length;if(ws>0){if(Se)de((xs)=>xs+ws);if(U)Ae((xs)=>xs+ws)}Zr(Et.prevCursor),nr(Et.hasPrev)}).catch((Et)=>i(I(Et))).finally(()=>Sr(!1))},[e,Mn,kr,pr,Se,U,dr,we.start,ct.start,B]),mn(()=>{if(!e||l||n!=="logs")return;let ce=setInterval(()=>{yo()},IF);return()=>clearInterval(ce)},[e,l,yo,n]),{logs:s,setLogs:a,paused:l,setPaused:c,errorOnly:u,setErrorOnly:d,showSystemLogs:f,logSearch:m,setLogSearch:h,logSearchFocused:g,setLogSearchFocused:w,logFollow:v,logSince:E,setLogSince:_,setLogUntil:b,logService:k,setLogService:x,logServiceB:L,setLogServiceB:F,splitLogs:B,splitFocus:V,setSplitFocus:X,toggleSplitLogs:()=>{if(B){X(0),K(!1);return}if(L===""){let ce=r.find((vt)=>vt!==k);if(ce!==void 0)F(ce)}K(!0)},cycleSplitFocus:()=>X((ce)=>ce===0?1:0),setActiveLogService:(ce)=>{let vt=(Et)=>typeof ce==="function"?ce(Et):ce;if(B&&V===1){F(vt);return}x(vt)},logSliceB:Pe,logWindowB:ct,logSelectedB:te,logPinnedB:U,logServices:se,logShowTimestamps:z,setLogShowTimestamps:ue,logShowMeta:re,setLogShowMeta:pt,logLevel:Oe,logSource:Fe,logRegex:Qe,setLogRegex:kt,logWrap:at,setLogWrap:Lt,logPinned:Se,logSelected:gt,logsFullscreen:xr,setLogsFullscreen:lt,dashboardLogCursor:It,setDashboardLogCursor:Ze,logFacets:Tt,logSources:Z,filteredLogs:D,filteredLogsB:or,logWindow:we,logSlice:ft,pinLogView:go,pinLogViewB:Hr,applyLogCursor:sd,applyLogCursorA:bn,applyLogCursorB:vo,applyDashboardLogCursor:ad,jumpToLatestLogs:ve,clearLogs:bs,toggleSystemLogs:ld}}var zC,IF=2000;var KC=A(()=>{ne();br();zC=[]});import{useCallback as ui,useState as VC}from"react";function YC({tui:e,controller:t,cfg:r,persistPrefs:n,snap:o,refresh:i,setStatus:s}){let[a,l]=VC(""),[c,u]=VC(()=>e.mcp_port??Xo(t?.cfg.repoRoot??process.cwd())),d=ui((v)=>{let S=to(v);u(S);let E=r?.repoRoot??process.cwd();if(Px(E,S)){n({mcp_port:null},`MCP port ${S} (default)`);return}n({mcp_port:S},`MCP port ${S}`)},[r,n]),f=ui(()=>{if(a==="")return c;let v=_x(a,c);return l(""),d(v),v},[c,a,d]),p=ui(async(v)=>{if(!t||o?.mcp?.running!==!0)return;await t.mcpStop(),await t.mcpStart({port:v}),await i()},[t,i,o?.mcp?.running]),m=ui(async(v)=>{if(!t){s("Supervisor is not running");return}let S=o?.mcp?.disabled_tools??[],E=no(v.name,S),_=E?[...S,v.name]:S.filter((y)=>y!==v.name);try{let y=await t.mcpSetTools(_);n({mcp_disabled_tools:y},`${v.label} ${E?"disabled":"enabled"}`),await i()}catch(y){s(I(y))}},[t,n,i,o]),h=ui(async()=>{if(!t){s("Supervisor is not running");return}try{if(o?.mcp?.running)await t.mcpStop(),n({mcp_enabled:!1},"MCP off"),s("MCP stopped");else await t.mcpStart({port:c}),n({mcp_enabled:!0},"MCP on"),s("MCP started");await i()}catch(v){s(I(v))}},[t,c,n,i,o?.mcp?.running]),g=ui((v)=>{Ru(v.text).then(()=>{s(`Copied ${v.title} snippet`)}).catch((S)=>{s(I(S))})},[]),w=ui((v)=>{let S=wh(v);if(S===void 0)return!1;let E=o?.mcp?.address??cs(o?.mcp?.port??c),_=Ia(E,o?.mcp?.token??"")[S];if(!_)return!1;return g(_),!0},[g,c,o?.mcp?.address,o?.mcp?.port,o?.mcp?.token]);return{mcpPortDraft:a,setMcpPortDraft:l,mcpPort:c,persistMcpPort:d,applyMcpPortDraft:f,restartMcpOnPort:p,toggleMcpTool:m,toggleMcp:h,copyMcpSnippet:g,copyFocusedMcpSnippet:w}}var JC=A(()=>{ne();Mu();Ji();th();Oa()});import{RGBA as DF}from"@opentui/core";import{useCallback as Dn,useEffect as OF,useMemo as XC,useRef as Bu,useState as Wu}from"react";function QC({tui:e,controller:t,resolveTuiOverridePath:r,terminalBackground:n,userTuiConfigPath:o,snap:i,setStatus:s,saveTuiPreferences:a,setPaletteIndex:l,setOverlay:c,setConfirmKind:u,setScreen:d,setSelected:f,screen:p}){let[m,h]=Wu(e.theme||t?.cfg.ui.theme||"devctl"),g=Bu(m),[w,v]=Wu(e.mouse),S=Bu(e.mouse),[E,_]=Wu(e.leader_timeout),y=Bu(e.leader_timeout),[b,k]=Wu(()=>wa(e.font_size)),x=Bu(b),L=x0(r()),F=XC(()=>{let z=g0(m);if(Kc(m)!=="terminal"||!wm(n))return z;let ue=n??z.background;return{...z,background:ue,panel:ue,element:ue,inverse:ue}},[n,m]),B=Kc(m)==="terminal"&&wm(n)?DF.defaultBackground(n??void 0):F.background,K=XC(()=>T0({themeName:m,fontSize:b,mouse:w,leaderMs:E,locked:L,configPath:L?e.path||Tm(r(),o()):Tm(r(),o()),mcpRunning:i?.mcp?.running===!0}),[b,E,w,L,i?.mcp?.running,m,e.path]),V=Dn((z,ue)=>{if(L){s(`${ue} session only`);return}let re=a(z);s(`${ue} saved ${re}`)},[L]),X=Dn((z)=>{h(z),g.current=z,V({theme:z},`theme ${z}`)},[V]),te=Dn(()=>{let z=!w;v(z),S.current=z,V({mouse:z},`mouse ${z?"on":"off"} restart TUI to apply clicks`)},[w,V]),R=Dn((z)=>{_(z),y.current=z,V({leader_timeout:z},`leader ${z}ms`)},[V]),U=Dn((z)=>{let ue=wa(z);k(ue),x.current=ue,V({font_size:ue},`display ${Xc(ue)}`)},[V]),O=Dn(()=>{let z=Qc();h(z.theme),g.current=z.theme,v(z.mouse),S.current=z.mouse,_(z.leader_timeout),y.current=z.leader_timeout,k(z.font_size),x.current=z.font_size,V(z,"restored default preferences")},[V]),ae=Dn((z)=>{if(z.id==="theme"){l(Math.max(0,Pt.indexOf(m))),c("themes");return}if(z.id==="mouse"){te();return}if(z.id==="leader"){R(E);return}if(z.id==="font"){U(b);return}if(z.id==="reset"){u("reset-prefs"),c("confirm");return}if(z.id==="mcp"){d("mcp"),f(0);return}s(z.detail)},[U,R,b,E,m,te]),Ae=Dn((z,ue)=>{let re=oo(K,ue);if(!re)return;if(re.id==="theme"){X(k0(m,z));return}if(re.id==="leader"){R(S0(E,z));return}if(re.id==="font"){U(xa(b,z));return}if(re.id==="mouse")te()},[U,R,b,E,X,K,m,te]),se=Dn(()=>{h(g.current)},[]);return OF(()=>{if(p==="settings")return;h(g.current),k(x.current),_(y.current),v(S.current)},[p]),{themeName:m,setThemeName:h,leaderMs:E,fontSize:b,prefsLocked:L,palette:F,rootBackground:B,settingRows:K,persistPrefs:V,persistTheme:X,toggleMouse:te,applyFont:U,applyReset:O,activateSetting:ae,cycleSetting:Ae,revertThemePreview:se}}var ZC=A(()=>{Mr();rt()});import{jsxDEV as Fa}from"@opentui/react/jsx-dev-runtime";function eT(e){let{palette:t,termW:r,termH:n,step:o,answers:i,repo:s,draft:a,authStatus:l,onDraft:c,onSubmit:u}=e,d=Rt[o]??Rt[0],f=Rt.length,p=MF(d.id,i,s);return Fa(ot,{palette:t,title:`setup ${o+1}/${f} ${d.title}`,bottomTitle:"enter next \xB7 esc cancel",termW:r,termH:n,preferW:64,preferH:12,borderColor:t.primary,gap:1,children:[Fa("text",{fg:t.muted,wrapMode:"word",children:p},void 0,!1,void 0,this),d.id==="auth"||d.id==="write"||d.id==="repo"?Fa("text",{fg:t.text,wrapMode:"word",children:d.id==="auth"?l:d.id==="repo"?s:"Write .devctl/config.yaml and attach the daemon."},void 0,!1,void 0,this):Fa("input",{focused:!0,value:a,placeholder:d.prompt,onInput:c,onSubmit:u,backgroundColor:t.element,focusedBackgroundColor:t.element,textColor:t.text,cursorColor:t.primary},void 0,!1,void 0,this),Fa(mt,{palette:t,hints:[{key:"enter",label:d.id==="write"?"write and attach":"next"},{key:"esc",label:"cancel"}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Dh(e,t,r){if(e==="name")return t.name;if(e==="project")return t.project;if(e==="sa")return t.sa;if(e==="audience")return t.audience;if(e==="port")return String(t.proxyPort);if(e==="profile")return t.profile;if(e==="repo")return r;return""}function tT(e,t,r,n){let o={...t};if(e==="name")o.name=r.trim()||Yn(n).name;else if(e==="project")o.project=r.trim();else if(e==="sa")o.sa=r.trim();else if(e==="audience")o.audience=r.trim();else if(e==="port")o.proxyPort=Ul(r,t.proxyPort);else if(e==="profile")o.profile=r.trim();return o}function MF(e,t,r){if(e==="repo")return`Using ${r}. The TUI always writes under this checkout.`;if(e==="auth")return"ADC login needs a real TTY. Enter continues; if ADC is missing, login runs gcloud on the terminal.";if(e==="write")return`Project ${t.name||"(unnamed)"}. Enter writes the starter file and attaches the daemon.`;return Rt.find((n)=>n.id===e)?.prompt??""}var Oh=A(()=>{jl();Re()});import{useCallback as Mh,useState as zu}from"react";function rT({workspace:e,renderer:t,setOverlay:r,setStatus:n,setScreen:o,onAttached:i,setController:s,setCfg:a,setBootError:l}){let c=process.cwd(),[u,d]=zu(0),[f,p]=zu(()=>Yn(c)),[m,h]=zu(""),[g,w]=zu("Checking Application Default Credentials\u2026"),v=Mh(()=>{let _=Yn(c);d(0),p(_),h(Dh("repo",_,c)),r("setup-wizard"),e.detectGoogle("").then((y)=>{p((b)=>({...b,project:y.projectID||b.project})),w(y.adcAvailable?`ADC available${y.userEmail?` (${y.userEmail})`:""}. Enter continues.`:"ADC is not available. Enter runs gcloud ADC login on this TTY, then continues.")})},[c,r,e]),S=Mh(async(_)=>{try{Wl(c,_);let y=await e.openTui(c,"");i?.(y),s(y),a(y.cfg),l(void 0),r("none"),o("dashboard"),n("Wrote .devctl/config.yaml and attached the daemon")}catch(y){n(I(y))}},[i,c,l,a,s,r,o,n,e]),E=Mh(async()=>{let _=Rt[u];if(!_)return;let y=tT(_.id,f,m,c);if(_.id==="auth"){if(!(await e.detectGoogle(y.project)).adcAvailable)try{await Uu(t,()=>e.loginGoogle())}catch(L){n(I(L))}}if(p(y),_.id==="write"){await S(y);return}let b=Math.min(u+1,Rt.length-1),k=Rt[b];d(b),h(k?Dh(k.id,y,c):"")},[f,m,S,t,c,u,e,n]);return{step:u,answers:f,draft:m,authStatus:g,repo:c,setDraft:h,startWizard:v,advanceWizard:E}}var nT=A(()=>{jl();zl();ne();Oh()});import{useCallback as NF,useEffect as oT,useState as Nh}from"react";function iT({controller:e,cfg:t,envService:r}){let[n,o]=Nh(),[i,s]=Nh(!1),[a,l]=Nh(""),c=n?.name===r,u=c?n?.env:void 0,d=r===""?"config":i&&!c?"loading":c?"resolved":a!==""?"error":"config",f=c||r===""?"":a;oT(()=>{o(void 0),l("")},[t]),oT(()=>{if(!e||r===""||!t?.services[r])return;if(n?.name===r)return;let m=!1;return s(!0),l(""),e.execService(r,[],!0).then((h)=>{if(m)return;o({name:r,env:h.environment??{}}),l("")}).catch((h)=>{if(m)return;l(I(h))}).finally(()=>{s(!1)}),()=>{m=!0}},[t,e,r,n?.name]);let p=NF(async(m)=>{if(!e)return;try{let h=await e.execService(m,[],!0);o({name:m,env:h.environment??{}}),l("")}catch(h){throw l(I(h)),h}},[e]);return{inspectorEnv:u,inspectorEnvStatus:d,inspectorEnvError:f,resolveEnvironment:p}}var sT=A(()=>{ne()});import{jsxDEV as fo}from"@opentui/react/jsx-dev-runtime";function aT(e){let{palette:t,path:r,initialValue:n,error:o,termW:i,termH:s,textareaRef:a}=e;return fo(ot,{palette:t,title:"config buffer",bottomTitle:`${jt("s")} save \xB7 esc discard \xB7 e still opens $EDITOR`,termW:i,termH:s,preferW:88,preferH:28,gap:1,children:[fo("box",{height:1,overflow:"hidden",children:fo("text",{fg:t.muted,wrapMode:"none",children:r},void 0,!1,void 0,this)},void 0,!1,void 0,this),fo("textarea",{ref:a,focused:!0,initialValue:n,backgroundColor:t.panel,focusedBackgroundColor:t.panel,textColor:t.text,focusedTextColor:t.text,cursorColor:t.primary},void 0,!1,void 0,this),o!==""?fo("box",{height:2,overflow:"hidden",children:fo("text",{fg:t.error,wrapMode:"word",children:o},void 0,!1,void 0,this)},void 0,!1,void 0,this):fo("box",{height:1,overflow:"hidden",children:fo("text",{fg:t.muted,children:"validate, then write. invalid YAML is not saved."},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var lT=A(()=>{Re();Vr()});import{jsxDEV as Fh}from"@opentui/react/jsx-dev-runtime";function cT(e){let{palette:t,title:r,body:n,kind:o,termW:i,termH:s}=e,a=dk(o),l=a.map((c)=>`${c.key} ${c.label}`).join(" \xB7 ");return Fh(ot,{palette:t,title:r,bottomTitle:l,termW:i,termH:s,preferW:52,preferH:8,borderColor:t.warning,gap:1,children:[Fh("text",{fg:t.text,wrapMode:"word",children:n},void 0,!1,void 0,this),Fh(mt,{palette:t,hints:a},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var uT=A(()=>{wr();Re()});import{jsxDEV as dT}from"@opentui/react/jsx-dev-runtime";function pT(e){let{palette:t,termW:r,termH:n}=e,o=Vm();return dT(ot,{palette:t,title:"leader",termW:r,termH:n,preferW:68,preferH:5,anchor:"bottom",children:dT(mt,{palette:t,hints:o},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var fT=A(()=>{si();Re()});import{jsxDEV as st,Fragment as $h}from"@opentui/react/jsx-dev-runtime";function mT(e){let{palette:t,event:r,termW:n,termH:o,scrollRef:i,onViewTrace:s}=e;if(!r)return null;let a=r.traceId,l=typeof r.body==="object"&&r.body!==null?U0(r):void 0,c=r.raw&&r.raw!==Kt(r)?H0(r.raw):void 0,u=Object.entries(r.attributes),d=Kt(r).length>120||Kt(r).includes(`
|
|
2500
|
+
`)||l!==void 0||u.length>0,f=r.resource["process.pid"];return st(ot,{palette:t,title:"log details",bottomTitle:a?"enter view trace \xB7 j/k scroll \xB7 esc close":"j/k scroll \xB7 esc close",termW:n,termH:o,preferW:d?84:72,preferH:d?24:16,gap:1,children:st("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:st("box",{flexDirection:"column",overflow:"hidden",children:[st("text",{fg:t.text,wrapMode:"word",children:du(Kt(r))},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`time ${r.timestamp}`},void 0,!1,void 0,this),st("text",{fg:Ye(r.service,t),children:`service ${r.service}`},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`source ${r.source}${r.stream?` / ${r.stream}`:""}`},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`level ${Zi(r.severityText)} (${r.severityNumber})`},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`pid ${typeof f==="number"&&f>0?f:"\u2014"}`},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`trace ${a||"\u2014"}`},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`span ${r.spanId||"\u2014"}`},void 0,!1,void 0,this),st("text",{fg:t.muted,children:`identity ${r.identity||"\u2014"}`},void 0,!1,void 0,this),r.scope?st("text",{fg:t.muted,children:`scope ${r.scope.name}${r.scope.version?` ${r.scope.version}`:""}`},void 0,!1,void 0,this):null,u.length===0?null:st($h,{children:[st("text",{fg:t.muted,children:"attributes"},void 0,!1,void 0,this),u.map(([p,m])=>st("text",{fg:t.text,wrapMode:"word",children:`${p} ${gr(m)}`},p,!1,void 0,this))]},void 0,!0,void 0,this),l===void 0?null:st($h,{children:[st("text",{fg:t.muted,children:"body"},void 0,!1,void 0,this),st("text",{fg:t.text,wrapMode:"word",children:l},void 0,!1,void 0,this)]},void 0,!0,void 0,this),c===void 0||c===l?null:st($h,{children:[st("text",{fg:t.muted,children:"raw"},void 0,!1,void 0,this),st("text",{fg:t.text,wrapMode:"word",children:c},void 0,!1,void 0,this)]},void 0,!0,void 0,this),a&&s?st("text",{fg:t.primary,onMouseDown:()=>s(a),children:"view trace \u21B5"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var hT=A(()=>{sn();br();Re();rt()});import{jsxDEV as G}from"@opentui/react/jsx-dev-runtime";function Hh(e,t){switch(e){case"completed":return{icon:"\u2713",label:"Completed",tone:"success",color:t.success};case"failed":return{icon:"\u2717",label:"Failed",tone:"error",color:t.error};case"unhealthy":return{icon:"\u26A0",label:"Unhealthy",tone:"warning",color:t.warning};case"active":return{icon:"\u25CF",label:"In progress",tone:"primary",color:t.primary};default:return{icon:"\u25CB",label:"Queued",tone:"muted",color:t.muted}}}function FF(e,t,r,n){if(t!=="")return{icon:"\u2717",label:"Failed",tone:"error",color:n.error};if(!e)return{icon:"\u2713",label:"Finished",tone:"success",color:n.success};if(r==="unhealthy")return{icon:"\u26A0",label:"Waiting on health",tone:"warning",color:n.warning};return{icon:"\u25CF",label:"Running",tone:"primary",color:n.primary}}function gT(e){return G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:G("text",{wrapMode:"none",children:[G("span",{fg:e.palette.primary,children:e.label.toUpperCase()},void 0,!1,void 0,this),e.detail?G("span",{fg:e.palette.muted,children:` ${e.detail}`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function vT(e){let{palette:t,plan:r,snap:n,busy:o,failed:i,kind:s,termW:a=80,termH:l=24,scrollRef:c,initiallyRunning:u=[],onDismiss:d}=e,f=new Set(u),p=r.waves.map((X,te)=>({wave:X.filter((R)=>!f.has(R)),waveIdx:te})).filter(({wave:X})=>X.length>0),m=oC(r,n,s),h=r.waves[m.currentWaveIndex]??[],g=Ma(h,n,s),w=Hh(g,t),v=FF(o,i,g,t),S=sC(s,o,i,r.profile),E=aC(o,i),_=i?t.inverse:t.text,y=i?t.error:t.element,b=Math.min(92,Math.max(40,a-8)),k=b>=82?22:b>=66?17:13,x=12,L=9,F=b>=56,B=b>=72,K=b<72||r.waves.length>3,V=r.profile?`PROFILE ${r.profile}`:s.toUpperCase();return G(ot,{palette:t,title:S,bottomTitle:"enter close \xB7 esc hide (operation continues)",termW:a,termH:l,preferW:98,preferH:28,borderColor:v.color,gap:0,children:[G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:[G(Ue,{palette:t,label:`${v.icon} ${v.label.toUpperCase()}`,tone:v.tone},void 0,!1,void 0,this),G("box",{paddingLeft:1,flexGrow:1,overflow:"hidden",children:G("text",{fg:t.text,wrapMode:"none",children:V},void 0,!1,void 0,this)},void 0,!1,void 0,this),G(Ue,{palette:t,label:`${m.ready}/${m.total} READY`,tone:m.isComplete?"success":"info"},void 0,!1,void 0,this),G(Ue,{palette:t,label:`WAVE ${Math.min(m.currentWaveIndex+1,Math.max(1,m.totalWaves))}/${Math.max(1,m.totalWaves)}`,tone:w.tone},void 0,!1,void 0,this)]},void 0,!0,void 0,this),G("box",{height:2,flexDirection:"column",overflow:"hidden",flexShrink:0,paddingLeft:1,paddingRight:1,children:[G("box",{height:1,flexDirection:"row",overflow:"hidden",children:[G("text",{wrapMode:"none",children:[G("span",{fg:t.muted,children:"PROGRESS "},void 0,!1,void 0,this),G("span",{fg:v.color,children:`[${m.progressBar}]`},void 0,!1,void 0,this),G("span",{fg:t.text,children:` ${m.percent}%`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),G("box",{flexGrow:1},void 0,!1,void 0,this),G("text",{wrapMode:"none",children:G("span",{fg:w.color,children:`${w.icon} ${w.label}`},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),G("box",{height:1,overflow:"hidden",children:G("text",{fg:t.muted,wrapMode:"none",children:o?s==="stop"?"Dependents stop first; each wave waits for the previous wave.":"Each wave waits until its services are healthy before the next wave starts.":E.primary},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),G(gT,{palette:t,label:"Pipeline",detail:`${r.waves.length} execution wave${r.waves.length===1?"":"s"}`},void 0,!1,void 0,this),G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:r.waves.map((X,te)=>{let R=Ma(X,n,s),U=Hh(R,t),O=K?`W${te+1} ${U.icon} ${X.length}`:`W${te+1} ${U.icon} ${U.label} \xB7 ${X.length}`;return G("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:[G(Ue,{palette:t,label:O,tone:U.tone},void 0,!1,void 0,this),te<r.waves.length-1?G("box",{width:3,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:" \u2500\u25BA"},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},`step-${te}`,!0,void 0,this)})},void 0,!1,void 0,this),(r.blockers??[]).length>0?G("box",{minHeight:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,paddingLeft:1,children:G("text",{fg:t.error,wrapMode:"word",children:`BLOCKED ${r.blockers?.map((X)=>`${X.name}: ${X.message}`).join(" \xB7 ")}`},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,u.length>0?G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,paddingLeft:1,children:G("text",{wrapMode:"none",children:[G("span",{fg:t.success,children:"\u2713 ALREADY READY"},void 0,!1,void 0,this),G("span",{fg:t.muted,children:` ${u.join(", ")}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this):null,G(gT,{palette:t,label:"Wave details",detail:"live process and health state"},void 0,!1,void 0,this),G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,paddingLeft:1,children:[G("box",{width:2,flexShrink:0},void 0,!1,void 0,this),G("box",{width:k,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:j("SERVICE",k)},void 0,!1,void 0,this)},void 0,!1,void 0,this),G("box",{width:12,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:j("STATE",12)},void 0,!1,void 0,this)},void 0,!1,void 0,this),F?G("box",{width:9,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:j("PORT",9)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,B?G("box",{flexGrow:1,overflow:"hidden",children:G("text",{fg:t.muted,children:"DETAIL"},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),G("scrollbox",{ref:c,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:G("box",{flexDirection:"column",overflow:"hidden",gap:1,children:p.map(({wave:X,waveIdx:te})=>{let R=Ma(X,n,s),U=Hh(R,t),O=`${iC(s,te,R)} \xB7 ${X.length} service${X.length===1?"":"s"}`;return G("box",{border:!0,borderStyle:"rounded",borderColor:U.color,title:O,titleColor:U.color,flexDirection:"column",paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:X.map((ae)=>{let Ae=n?.services[ae],se=yr(Ae),z=nC(ae,r,n,s),ue=ae===i||se==="FAILED",re=se==="UNHEALTHY",pt=se==="HEALTHY"||s==="stop"&&se==="STOPPED",xt=ti(Ae),le=ue?"\u2717":pt?"\u2713":re?"\u26A0":se==="STARTING"||se==="RUNNING"||se==="STOPPING"||se==="RESTARTING"?"\u25CF":"\u25CB",Oe=ue?t.error:dt(t,se),Fe=ue?t.error:re?t.warning:pt?t.success:t.muted;return G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[G("box",{width:2,flexShrink:0,overflow:"hidden",children:G("text",{fg:Oe,children:le},void 0,!1,void 0,this)},void 0,!1,void 0,this),G("box",{width:k,flexShrink:0,overflow:"hidden",children:G("text",{fg:Ye(ae,t),wrapMode:"none",children:j(ae,k)},void 0,!1,void 0,this)},void 0,!1,void 0,this),G("box",{width:12,flexShrink:0,overflow:"hidden",children:G("text",{fg:dt(t,se),wrapMode:"none",children:j(se,12)},void 0,!1,void 0,this)},void 0,!1,void 0,this),F?G("box",{width:9,flexShrink:0,overflow:"hidden",children:G("text",{fg:xt?t.info:t.muted,wrapMode:"none",children:j(xt?`:${xt}`:"\u2014",9)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,B?G("box",{flexGrow:1,overflow:"hidden",children:G("text",{fg:Fe,wrapMode:"none",children:z},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},ae,!0,void 0,this)})},`wave-card-${te}`,!1,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this),G("box",{height:3,flexShrink:0,flexDirection:"column",backgroundColor:y,border:["top"],borderStyle:"single",borderColor:v.color,paddingLeft:1,paddingRight:1,overflow:"hidden",onMouseDown:d,children:[G("text",{fg:_,wrapMode:"none",children:E.primary},void 0,!1,void 0,this),G("text",{fg:i?t.inverse:t.muted,wrapMode:"none",children:E.secondary},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var yT=A(()=>{nt();Fu();Ut();Re();rt()});import{jsxDEV as Fr}from"@opentui/react/jsx-dev-runtime";function bT(e){let{palette:t,route:r,termW:n,termH:o,scrollRef:i}=e;if(!r)return null;return Fr(ot,{palette:t,title:r.name,bottomTitle:"j/k scroll \xB7 esc close",termW:n,termH:o,preferW:78,preferH:18,gap:1,children:Fr("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:Fr("box",{flexDirection:"column",overflow:"hidden",children:[Fr("text",{fg:t.muted,children:`auth ${r.authType||"none"}`},void 0,!1,void 0,this),Fr("text",{fg:t.muted,children:`identity ${r.identityType||"\u2014"}`},void 0,!1,void 0,this),Fr("text",{fg:t.text,wrapMode:"word",children:`account ${r.serviceAccount||"\u2014"}`},void 0,!1,void 0,this),Fr("text",{fg:t.text,wrapMode:"word",children:`audience ${r.audience||"\u2014"}`},void 0,!1,void 0,this),Fr("text",{fg:t.muted,wrapMode:"word",children:`client id ${r.clientId||"ADC default"}`},void 0,!1,void 0,this),Fr("text",{fg:t.muted,wrapMode:"word",children:`client secret ${r.clientSecret||"\u2014"}`},void 0,!1,void 0,this),Fr("text",{fg:t.muted,children:`match host ${r.matchHost||"*"}`},void 0,!1,void 0,this),Fr("text",{fg:t.muted,children:`match path ${r.matchPath||"*"}`},void 0,!1,void 0,this),Fr("text",{fg:t.text,wrapMode:"word",children:`upstream ${r.upstream}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var wT=A(()=>{Re()});import{jsxDEV as qu}from"@opentui/react/jsx-dev-runtime";function xT(e){let{palette:t,title:r,body:n,termW:o,termH:i,scrollRef:s}=e,a=n.length>400||n.split(`
|
|
2501
|
+
`).length>16;return qu(ot,{palette:t,title:r,bottomTitle:"j/k scroll \xB7 esc close",termW:o,termH:i,preferW:a?88:76,preferH:a?24:16,gap:1,children:qu("scrollbox",{ref:s,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:qu("box",{flexDirection:"column",overflow:"hidden",children:qu("text",{fg:n===""?t.muted:t.text,wrapMode:"word",children:n===""?"(empty)":n},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var kT=A(()=>{Re()});import{jsxDEV as er}from"@opentui/react/jsx-dev-runtime";function ST(e){let{palette:t,items:r,query:n,selected:o,onQuery:i,onSubmit:s,title:a="commands"}=e,l=ii(n)!=="",c=Dk(o,Uh,r.length),u=l?r.slice(c,c+Uh):Ok(r,o,Uh),d=l?[{group:"",items:u}]:qm(u),f=Math.max(u.length+(l?0:d.length),1),p=os(r,o),m=_k(r);return er("box",{height:f+$F,flexShrink:0,border:!0,borderStyle:"rounded",borderColor:t.borderActive,titleColor:t.primary,backgroundColor:t.panel,title:a,flexDirection:"column",overflow:"hidden",children:[u.length===0?er("box",{height:1,paddingLeft:1,overflow:"hidden",children:er("text",{fg:t.muted,children:"no matching command"},void 0,!1,void 0,this)},void 0,!1,void 0,this):d.flatMap((h)=>[...h.group===""?[]:[er("box",{height:1,paddingLeft:1,overflow:"hidden",backgroundColor:t.panel,children:er("text",{fg:t.muted,wrapMode:"none",children:h.group},void 0,!1,void 0,this)},`g-${h.group}`,!1,void 0,this)],...h.items.map((w)=>{let v=bu(w)===(p?bu(p):"");return er("box",{height:1,flexDirection:"row",overflow:"hidden",paddingLeft:1,paddingRight:1,backgroundColor:v?t.highlight:t.panel,children:[er("box",{width:m,flexShrink:0,overflow:"hidden",children:er("text",{fg:v?t.primary:t.text,wrapMode:"none",children:j(`${v?"\u203A":" "} /${Gm(w).slice(0,zm)}`,m)},void 0,!1,void 0,this)},void 0,!1,void 0,this),er("box",{flexGrow:1,overflow:"hidden",children:er("text",{fg:v?t.accent:t.muted,wrapMode:"none",children:Rk(w)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},bu(w),!0,void 0,this)})]),er("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.highlight,paddingLeft:1,children:[er("box",{width:2,flexShrink:0,children:er("text",{fg:t.primary,children:"/"},void 0,!1,void 0,this)},void 0,!1,void 0,this),er("box",{flexGrow:1,overflow:"hidden",children:er("input",{focused:!0,value:n,placeholder:"start logs settings",onInput:i,onSubmit:()=>s(),backgroundColor:t.highlight,focusedBackgroundColor:t.highlight,textColor:t.text,cursorColor:t.primary},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var Uh=10,$F=3;var CT=A(()=>{si();nt()});import{jsxDEV as RT}from"@opentui/react/jsx-dev-runtime";function _T(e){let{palette:t,themeName:r,selected:n,termW:o,termH:i,onIndex:s,onPreview:a,onPick:l}=e,c=Pt.map((d)=>({name:d===r?`${d} (active)`:d,description:d===r?`${bm[d]} \xB7 current`:bm[d],value:d})),u=ns(o,i,TT,ET,"center",!Ln(ye()));return RT(ot,{palette:t,title:"/themes",bottomTitle:"enter save \xB7 esc revert",termW:o,termH:i,preferW:TT,preferH:ET,children:RT("select",{height:Math.max(4,u.height-3),options:c,selectedIndex:n,showDescription:!0,showSelectionIndicator:!0,wrapSelection:!0,backgroundColor:t.panel,focusedBackgroundColor:t.panel,textColor:t.text,focusedTextColor:t.text,selectedBackgroundColor:t.highlight,selectedTextColor:t.primary,descriptionColor:t.muted,selectedDescriptionColor:t.accent,onChange:(d)=>{s(d);let f=Pt[d];if(f)a(f)},onSelect:(d,f)=>{let p=f?.value;if(typeof p==="string"&&p!=="")l(p)}},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var TT=52,ET=22;var PT=A(()=>{Ht();wr();Re();Mr();rt()});import{useEffect as HF,useRef as UF}from"react";import{jsxDEV as W}from"@opentui/react/jsx-dev-runtime";function AT(e){let{palette:t,trace:r,termW:n,termH:o,onSelect:i,onOpenLogs:s,scrollRef:a}=e,l=Ln(ye()),c=AS(n,o),u=ns(n,o,c.w,c.h,"center",!l),d=l?0:1,f=Math.max(ih-8,u.width-2-d*2),p=Math.max(sh-4,u.height-2-d*2),m=r?Pu(r):[],h=r?mS(r):void 0,g=LS(f,p),w=vS(g.listWidth,hS(m),gS(m)),v=Au(e.selected??0,m.length),S=UF({index:-1,at:0});if(HF(()=>{let _=a&&"current"in a?a.current:null;if(!_||m.length===0)return;let y=requestAnimationFrame(()=>{_.scrollChildIntoView(`trace-span-${v}`)});return()=>cancelAnimationFrame(y)},[m.length,a,v]),!r||!h)return null;let E=(_)=>{let y=Date.now(),b=CS(S.current.index,S.current.at,_,y);if(S.current={index:_,at:y},i?.(_),b)s?.(_)};return W(ot,{palette:t,title:u.width>=48?`trace ${r.traceId}`:`trace ${r$(r.traceId,12)}`,bottomTitle:"j/k span \xB7 enter or double-click logs \xB7 esc close",termW:n,termH:o,preferW:c.w,preferH:c.h,gap:0,children:[W(jF,{palette:t,facts:h,width:f,showServices:g.showServices,showLegend:g.showLegend},void 0,!1,void 0,this),W("box",{flexGrow:1,height:g.listHeight,flexDirection:"column",overflow:"hidden",children:[W(WF,{palette:t,cols:w,durationMs:h.durationMs},void 0,!1,void 0,this),W("scrollbox",{ref:a,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:W("box",{flexDirection:"column",overflow:"hidden",children:m.length===0?W("text",{fg:t.muted,children:"no spans in this trace yet"},void 0,!1,void 0,this):m.map((_,y)=>W(zF,{id:`trace-span-${y}`,palette:t,row:_,cols:w,facts:h,active:y===v,onPick:()=>E(y)},`${_.span.spanId}-${_.span.seq}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function LT(e){let{palette:t,span:r,records:n=[],termW:o,termH:i,scrollRef:s}=e;if(!r)return null;return W(ot,{palette:t,title:n$(`${ch(r.kind)} ${r.name}`),bottomTitle:"j/k scroll \xB7 esc back to trace",termW:o,termH:i,preferW:84,preferH:28,gap:0,children:W(qF,{palette:t,span:r,records:n,scrollRef:s},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function jF(e){let{palette:t,facts:r,width:n,showServices:o,showLegend:i}=e,s=RS(ES(r),n),a=_S(r.services,n);return W("box",{flexShrink:0,flexDirection:"column",overflow:"hidden",children:[W("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:s.map((l)=>W(BF,{palette:t,chip:l},l.id,!1,void 0,this))},void 0,!1,void 0,this),o&&a!==""?W("text",{fg:t.muted,wrapMode:"none",children:a},void 0,!1,void 0,this):null,i?W("text",{fg:t.muted,wrapMode:"none",children:PS(n)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function BF(e){let{palette:t,chip:r}=e;return W(Ue,{palette:t,label:r.label,tone:r.tone},void 0,!1,void 0,this)}function WF(e){let{palette:t,cols:r,durationMs:n}=e,o=SS(r),i=yS(r);return W("box",{flexShrink:0,flexDirection:"column",overflow:"hidden",children:[W("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[W(tr,{width:r.tree,fg:t.muted,text:o.tree,raw:!0},void 0,!1,void 0,this),W(tr,{width:r.service,fg:t.muted,text:o.service,raw:!0},void 0,!1,void 0,this),W(tr,{width:r.name,fg:t.muted,text:o.name,raw:!0},void 0,!1,void 0,this),W(tr,{width:r.duration,fg:t.muted,text:o.duration,raw:!0},void 0,!1,void 0,this),W(tr,{width:r.bar,fg:t.muted,text:o.bar,raw:!0},void 0,!1,void 0,this)]},void 0,!0,void 0,this),W("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[W(tr,{width:i,fg:t.muted,text:""},void 0,!1,void 0,this),W(tr,{width:r.bar,fg:t.muted,text:kS(n,r.bar),raw:!0},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function zF(e){let{id:t,palette:r,row:n,cols:o,facts:i,active:s,onPick:a}=e,l=typeof n.span.resource["service.name"]==="string"?n.span.resource["service.name"]:"\u2014",c=lh(n.span),u=Math.max(1,i.endUnixNano-i.startUnixNano),d=wS(n.span,i.startUnixNano,u),f=xS(d.offset,d.width,o.bar),p=n.span.status.code==="error",m=p?r.error:t$(r,n.span.kind);return W("box",{id:t,height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:s?r.highlight:void 0,onMouseDown:a,children:[W(tr,{width:o.tree,fg:m,text:bS(n.depth,n.span.kind,o.tree,s),raw:!0},void 0,!1,void 0,this),W(tr,{width:o.service,fg:Ye(l,r),text:l},void 0,!1,void 0,this),W(tr,{width:o.name,fg:p?r.error:r.text,text:n.span.name},void 0,!1,void 0,this),W(tr,{width:o.duration,fg:r.muted,text:li(c)},void 0,!1,void 0,this),W(ZF,{width:o.bar,trackFg:r.muted,fillFg:m,lead:f.lead,fill:f.fill,trail:f.trail},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function qF(e){let{palette:t,span:r,records:n,scrollRef:o}=e,i=typeof r.resource["service.name"]==="string"?r.resource["service.name"]:"\u2014",s=Object.entries(r.attributes),a=r.status.code==="error";return W("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:W("scrollbox",{ref:o,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:W("box",{flexDirection:"column",overflow:"hidden",children:[W(mo,{palette:t,label:"status",value:e$(r),tone:a?"error":"text"},void 0,!1,void 0,this),W(mo,{palette:t,label:"kind",value:ch(r.kind)},void 0,!1,void 0,this),W(mo,{palette:t,label:"service",value:i},void 0,!1,void 0,this),W(mo,{palette:t,label:"duration",value:li(lh(r))},void 0,!1,void 0,this),W(mo,{palette:t,label:"trace",value:r.traceId},void 0,!1,void 0,this),W(mo,{palette:t,label:"span",value:r.spanId},void 0,!1,void 0,this),W(mo,{palette:t,label:"parent",value:r.parentSpanId||"\u2014"},void 0,!1,void 0,this),r.scope?W(mo,{palette:t,label:"scope",value:`${r.scope.name}${r.scope.version?` ${r.scope.version}`:""}`},void 0,!1,void 0,this):null,s.length===0?null:W("text",{fg:t.muted,children:"attributes"},void 0,!1,void 0,this),s.map(([l,c])=>W("text",{fg:t.text,wrapMode:"word",children:`${l} ${gr(c)}`},l,!1,void 0,this)),r.events.length===0?null:W("text",{fg:t.muted,children:`events ${r.events.length}`},void 0,!1,void 0,this),r.events.map((l,c)=>W("box",{flexDirection:"column",overflow:"hidden",children:[W("text",{fg:t.info,wrapMode:"word",children:`+${li(TS(r,l.timeUnixNano))} ${l.name}`},void 0,!1,void 0,this),Object.entries(l.attributes).map(([u,d])=>W("text",{fg:t.muted,wrapMode:"word",children:` ${u} ${gr(d)}`},u,!1,void 0,this))]},`${l.name}-${c}`,!0,void 0,this)),W(XF,{palette:t,records:n,spanId:r.spanId},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function XF(e){let{palette:t,records:r,spanId:n}=e;if(r.length===0)return W("text",{fg:t.muted,children:"logs none"},void 0,!1,void 0,this);let o=QF(r);return W("box",{flexDirection:"column",overflow:"hidden",children:[W("text",{fg:t.muted,children:`logs ${r.length} \xB7 \u2192 this span`},void 0,!1,void 0,this),r.map((i)=>{let s=n!==void 0&&i.spanId===n,a=Kt(i);return W("box",{flexShrink:0,flexDirection:"row",alignItems:"flex-start",overflow:"hidden",children:[W(tr,{width:GF,fg:s?t.primary:t.muted,text:s?"\u2192":""},void 0,!1,void 0,this),W(tr,{width:KF,fg:t.muted,text:i.timestamp.slice(11,19)},void 0,!1,void 0,this),W(tr,{width:o,fg:s?t.primary:t.text,text:i.service},void 0,!1,void 0,this),W(tr,{width:VF,fg:s?t.primary:t.muted,text:Zi(i.severityText)},void 0,!1,void 0,this),W("box",{flexGrow:1,flexShrink:1,minWidth:0,overflow:"hidden",children:W("text",{fg:s?t.primary:t.text,wrapMode:"word",flexShrink:0,width:"100%",children:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},i.seq,!0,void 0,this)})]},void 0,!0,void 0,this)}function QF(e){return Math.min(JF,Math.max(YF,e.reduce((t,r)=>Math.max(t,r.service.length),0)))}function mo(e){let{palette:t,label:r,value:n,tone:o="text"}=e;return W("text",{fg:o==="error"?t.error:t.text,wrapMode:"word",children:`${j(r,10)}${n}`},void 0,!1,void 0,this)}function ZF(e){let{width:t,trackFg:r,fillFg:n,lead:o,fill:i,trail:s}=e;return W("box",{width:t,flexShrink:0,overflow:"hidden",children:W("text",{wrapMode:"none",children:[W("span",{fg:r,children:o},void 0,!1,void 0,this),W("span",{fg:n,children:i},void 0,!1,void 0,this),W("span",{fg:r,children:s},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function tr(e){let{width:t,fg:r,text:n,raw:o}=e;return W("box",{width:t,flexShrink:0,overflow:"hidden",children:W("text",{fg:r,wrapMode:"none",children:o?n:j(n,t)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function e$(e){let t=fS(e.status.code);return e.status.message?`${t} ${e.status.message}`:t}function t$(e,t){if(t==="server")return e.info;if(t==="client")return e.primary;if(t==="producer"||t==="consumer")return e.accent;return e.muted}function r$(e,t){if(e.length<=t)return e;return`${e.slice(0,t)}\u2026`}function n$(e){return e.length<=42?e:`${e.slice(0,41)}\u2026`}var GF=2,KF=9,VF=8,YF=8,JF=14;var IT=A(()=>{sn();wr();nt();br();Lu();Re();Mr();rt();Ht()});function Gu(e,t,r){let n=e?.google?.project_id??"";if(n!=="")return{project:n,source:"configuration"};let o=t?.project||r?.projectID||"",i=t?.project_source||r?.projectSource||"";return{project:o,source:i}}import{jsxDEV as ht}from"@opentui/react/jsx-dev-runtime";function Ku(e){let{palette:t,title:r,tone:n="muted",children:o}=e,i=n==="success"?t.success:n==="warning"?t.warning:n==="error"?t.error:t.border;return ht("box",{border:!0,borderStyle:"rounded",borderColor:i,title:r,titleColor:i,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,marginBottom:1,overflow:"hidden",children:o},void 0,!1,void 0,this)}function DT(e){let{palette:t,cfg:r,google:n,identity:o}=e;if(!n&&!o)return ht(Eu,{palette:t,label:"Checking Application Default Credentials\u2026"},void 0,!1,void 0,this);let i=o$(r,o),s=o?.user||n?.userEmail||"",{project:a,source:l}=Gu(r,o,n),c=o?.adc??n?.adcAvailable===!0,u=o?.iap??(r?.proxy.routes??[]).some((h)=>h.auth.type.toLowerCase()==="iap"),d=i.filter((h)=>h.inactive!==!0),f=d.some((h)=>h.ok===!0),p=d.some((h)=>h.ok===!1),m=f?"AVAILABLE":p?"UNAVAILABLE":d.length>0?"NOT PROBED":i.length>0?"not required":"not configured";return ht(At,{palette:t,title:"identity",scroll:!0,children:[ht(Ku,{palette:t,title:"Google identity",tone:c?"success":"warning",children:[ht(ai,{palette:t,label:"user",value:s||"(unknown)"},void 0,!1,void 0,this),ht(ai,{palette:t,label:"project",value:a||"(unset)"},void 0,!1,void 0,this),ht(ai,{palette:t,label:"source",value:l||"\u2014"},void 0,!1,void 0,this),ht(ai,{palette:t,label:"ADC",value:c?"\u2713 available":"\u2717 missing",tone:c?"success":"error"},void 0,!1,void 0,this),ht(ai,{palette:t,label:"gcloud",value:n?.gcloudInstalled?"\u2713 installed":"\u2717 not installed",tone:n?.gcloudInstalled?"success":"error"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ht(Ku,{palette:t,title:`Service accounts (${i.length})`,tone:d.length===0?"muted":f?"success":"warning",children:[i.length===0?ht("text",{fg:t.muted,wrapMode:"word",children:"none configured \u2014 identities come from config, never hard-coded"},void 0,!1,void 0,this):i.map((h)=>ht("text",{fg:h.inactive?t.muted:h.ok===!0?t.success:h.ok===!1?t.error:t.text,wrapMode:"none",children:`${h.inactive?"\u2013":h.ok===!0?"\u2713":h.ok===!1?"\u2717":"\u25CB"} ${h.email}${h.inactive?" \u2014 inactive (route auth is none)":""}`},h.email,!1,void 0,this)),ht("box",{height:1,flexShrink:0},void 0,!1,void 0,this),ht(ai,{palette:t,label:"impersonation",value:m,tone:f?"success":d.length>0?"warning":"muted"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ht(Ku,{palette:t,title:"IAP",tone:u?"success":"muted",children:[ht("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:ht(Ue,{palette:t,label:u?"routes present":"no IAP routes",tone:u?"success":"idle"},void 0,!1,void 0,this)},void 0,!1,void 0,this),u?ht("text",{fg:t.muted,wrapMode:"word",children:"each route needs its own audience"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),!c?ht(Ku,{palette:t,title:"ADC unavailable",tone:"warning",children:[ht("text",{fg:t.text,wrapMode:"word",children:"Local services still start. Cloud identity, impersonation, and IAP need ADC."},void 0,!1,void 0,this),ht("text",{fg:t.muted,wrapMode:"word",children:"/auth login suspends this screen and runs gcloud ADC login, then restores the TUI"},void 0,!1,void 0,this)]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this)}function o$(e,t){let r=new Map((e?Xp(e):[]).map((i)=>[i.email,i.active])),n=t?.service_account_status??{};return[...new Set([...r.keys(),...Object.keys(n)])].sort((i,s)=>i.localeCompare(s)).map((i)=>{let s=n[i]??"unknown",a=r.get(i)===!1;return{email:i,inactive:a,ok:a||s==="unknown"?void 0:s==="available"}})}var OT=A(()=>{Gr();cr();Re()});import{jsxDEV as N}from"@opentui/react/jsx-dev-runtime";function $T(e){let{palette:t,cfg:r,width:n,selectedTask:o=0}=e,i=ye();if(!r)return N(it,{palette:t,title:"No configuration",body:"Create .devctl/config.yaml or run setup."},void 0,!1,void 0,this);let s=Math.max(ps+8,n-6-i.pad*2),a=s>=PC,l=a?Math.floor((s-NT)/2):s,c=xC(r),u=kC(r),d=SC(r),f=CC(r),p=TC(r);return N(At,{palette:t,title:`config ${r.project.name||"unnamed"}`,children:[N(wt,{palette:t,items:hC(r)},void 0,!1,void 0,this),N("box",{flexGrow:1,overflow:"hidden",children:N("scrollbox",{ref:e.scrollRef,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:N("box",{flexDirection:"column",overflow:"hidden",gap:FT,children:[N(jh,{wide:a,left:N(hn,{palette:t,title:"project",children:N(ms,{palette:t,facts:gC(r,Xt),width:l},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:N(hn,{palette:t,title:"google",children:N(ms,{palette:t,facts:vC(r),width:l},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N(jh,{wide:a,left:N(hn,{palette:t,title:"runtime",children:N(ms,{palette:t,facts:yC(r),width:l},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:N(hn,{palette:t,title:"logs",children:N(ms,{palette:t,facts:bC(r),width:l},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N(hn,{palette:t,title:`proxy ${r.proxy.enabled?"enabled":"disabled"}`,children:[N(ms,{palette:t,facts:wC(r),width:s},void 0,!1,void 0,this),N(s$,{palette:t,routes:u,width:s},void 0,!1,void 0,this)]},void 0,!0,void 0,this),N(hn,{palette:t,title:`services ${c.length}`,children:N(i$,{palette:t,rows:c,width:s},void 0,!1,void 0,this)},void 0,!1,void 0,this),N(hn,{palette:t,title:`tasks ${p.length}`,children:N(MT,{palette:t,rows:p,empty:"no tasks",width:s,selected:o},void 0,!1,void 0,this)},void 0,!1,void 0,this),N(jh,{wide:a,left:N(hn,{palette:t,title:`profiles ${d.length}`,children:N(a$,{palette:t,rows:d,width:l},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:N(hn,{palette:t,title:`templates ${f.length}`,children:N(MT,{palette:t,rows:f,empty:"no templates",width:l},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N(hn,{palette:t,title:"extras",children:N(ms,{palette:t,facts:RC(r),width:s},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N(Zt,{palette:t,backgroundColor:t.element,edge:"top",children:N(mt,{palette:t,hints:[{key:"v",label:"validate/save buffer"},{key:"e",label:"open in $EDITOR"},{key:"/diff",label:"config sources"},{key:"/reload",label:"re-read .devctl after editing"},{key:"enter",label:"run task"},{key:"j/k",label:"scroll"}]},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function jh(e){let{wide:t,left:r,right:n}=e;if(!t)return N("box",{flexDirection:"column",overflow:"hidden",gap:FT,flexShrink:0,children:[r,n]},void 0,!0,void 0,this);return N("box",{flexDirection:"row",overflow:"hidden",gap:NT,flexShrink:0,children:[N("box",{flexGrow:1,flexBasis:0,overflow:"hidden",children:r},void 0,!1,void 0,this),N("box",{flexGrow:1,flexBasis:0,overflow:"hidden",children:n},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function hn(e){let{palette:t,title:r,children:n}=e;return N("box",{border:!0,borderStyle:"rounded",borderColor:t.border,title:r,titleColor:t.accent,paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",flexShrink:0,children:n},void 0,!1,void 0,this)}function ms(e){let{palette:t,facts:r,width:n}=e,o=Math.max(4,n-ps-4);return N("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((i)=>N("box",{height:1,flexDirection:"row",overflow:"hidden",children:[N("box",{width:ps,flexShrink:0,overflow:"hidden",children:N("text",{fg:t.muted,wrapMode:"none",children:j(i.label,ps)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N("box",{width:o,flexShrink:0,overflow:"hidden",children:N("text",{fg:u$(t,i.tone),wrapMode:"none",children:j(i.value,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},i.label,!0,void 0,this))},void 0,!1,void 0,this)}function i$(e){let{palette:t,rows:r,width:n}=e;if(r.length===0)return N(Vu,{palette:t,text:"no services"},void 0,!1,void 0,this);let o=_C(r),i=Math.max(8,n-o-6);return N("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((s)=>N("box",{height:1,flexDirection:"row",overflow:"hidden",children:[N("box",{width:o,flexShrink:0,overflow:"hidden",children:N("text",{fg:Ye(s.name,t),wrapMode:"none",children:j(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N("box",{width:i,flexShrink:0,overflow:"hidden",children:N("text",{fg:t.text,wrapMode:"none",children:ke(l$(s),i)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},s.name,!0,void 0,this))},void 0,!1,void 0,this)}function s$(e){let{palette:t,routes:r,width:n}=e;if(r.length===0)return N(Vu,{palette:t,text:"no routes"},void 0,!1,void 0,this);let o=Math.min(ps+4,Math.max(8,...r.map((s)=>s.name.length))),i=Math.max(8,n-o-6);return N("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((s)=>N("box",{height:1,flexDirection:"row",overflow:"hidden",children:[N("box",{width:o,flexShrink:0,overflow:"hidden",children:N("text",{fg:t.primary,wrapMode:"none",children:j(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N("box",{width:i,flexShrink:0,overflow:"hidden",children:N("text",{fg:t.text,wrapMode:"none",children:ke(c$(s),i)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},`${s.name}-${s.match}`,!0,void 0,this))},void 0,!1,void 0,this)}function a$(e){let{palette:t,rows:r,width:n}=e;if(r.length===0)return N(Vu,{palette:t,text:"no profiles"},void 0,!1,void 0,this);let o=Math.min(12,Math.max(8,...r.map((s)=>s.name.length))),i=Math.max(8,n-o-6);return N("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((s)=>N("box",{height:1,flexDirection:"row",overflow:"hidden",children:[N("box",{width:o,flexShrink:0,overflow:"hidden",children:N("text",{fg:t.primary,wrapMode:"none",children:j(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N("box",{width:i,flexShrink:0,overflow:"hidden",children:N("text",{fg:t.text,wrapMode:"none",children:ke(s.env==="\u2014"?s.services:`${s.services} env ${s.env}`,i)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},s.name,!0,void 0,this))},void 0,!1,void 0,this)}function MT(e){let{palette:t,rows:r,empty:n,width:o,selected:i}=e;if(r.length===0)return N(Vu,{palette:t,text:n},void 0,!1,void 0,this);let s=Math.min(14,Math.max(8,...r.map((l)=>l.name.length))),a=Math.max(8,o-s-6);return N("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((l,c)=>{let u=i===c;return N("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:u?t.highlight:void 0,children:[N("box",{width:s,flexShrink:0,overflow:"hidden",children:N("text",{fg:u?t.primary:t.text,wrapMode:"none",children:j(l.name,s)},void 0,!1,void 0,this)},void 0,!1,void 0,this),N("box",{width:a,flexShrink:0,overflow:"hidden",children:N("text",{fg:u?t.accent:t.muted,wrapMode:"none",children:ke(l.summary,a)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},l.name,!0,void 0,this)})},void 0,!1,void 0,this)}function Vu(e){return N("box",{height:1,overflow:"hidden",children:N("text",{fg:e.palette.muted,wrapMode:"none",children:e.text},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function l$(e){let t=e.extends==="\u2014"?"":` ${e.extends}`;return` ${e.ports} ${e.identity} ${e.health} ${e.restart} \u2190 ${e.depends}${t}`}function c$(e){return` ${e.auth} ${e.identity} ${e.match} \u2192 ${e.upstream}`}function u$(e,t){if(t==="success")return e.success;if(t==="warning")return e.warning;if(t==="error")return e.error;if(t==="muted")return e.muted;return e.text}var NT=1,FT=1;var HT=A(()=>{cr();Lh();Ht();nt();Re();rt()});import{jsxDEV as Wt}from"@opentui/react/jsx-dev-runtime";function UT(e){let{palette:t,credentials:r}=e;if(!r)return Wt(Eu,{palette:t,label:"Reading credential store\u2026"},void 0,!1,void 0,this);let n=r.entries.filter((i)=>i.valid).length,o=r.entries.length-n;return Wt(At,{palette:t,title:"credentials",scroll:!0,children:[Wt("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[Wt(Ue,{palette:t,label:`backend: ${r.backend}`,tone:"info"},void 0,!1,void 0,this),r.entries.length>0?Wt(Ue,{palette:t,label:`${n} valid`,tone:"success"},void 0,!1,void 0,this):null,o>0?Wt(Ue,{palette:t,label:`${o} expired`,tone:"warning"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),Wt("text",{fg:t.muted,wrapMode:"word",children:"Tokens stay in the OS keychain or ~/.devctl/credentials (0600). They are never shown here."},void 0,!1,void 0,this),Wt("box",{height:1,flexShrink:0},void 0,!1,void 0,this),r.entries.length===0?Wt("text",{fg:t.muted,children:"no cached credentials"},void 0,!1,void 0,this):Wt("box",{flexDirection:"column",overflow:"hidden",gap:1,children:r.entries.map((i)=>Wt("box",{border:!0,borderStyle:"rounded",borderColor:i.valid?t.success:t.warning,title:i.identity,titleColor:i.valid?t.success:t.warning,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",children:[Wt("text",{wrapMode:"none",children:[Wt("span",{fg:i.valid?t.success:t.warning,children:i.valid?"\u2713 valid":"\u2717 expired"},void 0,!1,void 0,this),Wt("span",{fg:t.muted,children:` \xB7 expires ${i.expires_at}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Wt("text",{fg:t.muted,wrapMode:"none",children:`audience: ${i.audience||"(none)"}`},void 0,!1,void 0,this)]},`${i.identity}|${i.audience}`,!0,void 0,this))},void 0,!1,void 0,this),Wt(Tu,{palette:t,title:"Actions",body:"Use /refresh to mint again or auth refresh on the CLI. Invalidate clears the store without printing tokens.",hint:"/refresh /auth"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var jT=A(()=>{cr();Re()});import{jsxDEV as Yu}from"@opentui/react/jsx-dev-runtime";function hs(e){let t=e.newer>0?`g jump to latest \xB7 ${e.newer} new`:"g jump to latest",r=Math.min(e.width,t.length+4);return Yu("box",{position:"absolute",left:Math.max(0,Math.floor((e.width-r)/2)),bottom:e.bottom??2,width:r,height:3,border:!0,borderStyle:"rounded",borderColor:e.palette.warning,backgroundColor:e.palette.panel,alignItems:"center",justifyContent:"center",onMouseDown:e.onJump,children:Yu("text",{wrapMode:"none",children:[Yu("span",{fg:e.palette.primary,children:"g"},void 0,!1,void 0,this),Yu("span",{fg:e.palette.text,children:t.slice(1)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var BT=()=>{};import{jsxDEV as $a}from"@opentui/react/jsx-dev-runtime";function gs(e){let{palette:t,logs:r,names:n,service:o,errorOnly:i,width:s,onService:a,onToggleErrors:l,facets:c}=e,u=c?X0(n,c):J0(n,r),d=s<80,f=u.map((g)=>{let w=g.name===""?"all":g.name;return{id:w,label:d?w:`${w} \xB7 ${g.count}`,color:Ye(g.name,t)}}),p=Math.max(0,u.findIndex((g)=>g.name===o)),m=i?"ERROR+":d?"lvls":"all levels",h=Math.max(ts(f[p]?.label??"all"),s-ts(m));return $a(Zt,{palette:t,backgroundColor:t.element,children:$a("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[$a("box",{flexGrow:1,overflow:"hidden",children:$a(Cu,{palette:t,items:f,active:p,width:h,emphasis:"fill",onPick:(g)=>{let w=u[g];if(w)a(w.name)}},void 0,!1,void 0,this)},void 0,!1,void 0,this),$a(Ue,{palette:t,label:m,tone:i?"error":"muted",onMouseDown:l},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var WT=A(()=>{br();so();Re();rt()});import{jsxDEV as d$}from"@opentui/react/jsx-dev-runtime";function Ha(e){let t=Math.min(e.total,e.start+e.count),r=Math.max(0,e.start),n=Math.max(0,e.total-t);return d$(wt,{palette:e.palette,items:[{text:`view ${e.start+1}\u2013${t} of ${e.total}`,tone:"primary"},{text:r>0?`\u2191 ${r} older`:"start of history",tone:r>0?"info":"idle"},{text:n>0?`\u2193 ${n} newer`:"at latest",tone:n>0?"warning":"success"}],hints:[{key:"pgup/pgdn",label:"move history window"},{key:"g",label:"latest"}]},void 0,!1,void 0,this)}var zT=A(()=>{Re()});import{useEffect as Ju,useRef as Bh}from"react";import{jsxDEV as ze}from"@opentui/react/jsx-dev-runtime";function vs(e){let{palette:t,logs:r,limit:n,width:o=80,followTick:i=0,focused:s=!1,wrapMode:a="all",selected:l=-1,follow:c=!0,showTimestamps:u=!0,showMeta:d=!0,onPick:f,onLeaveLatest:p,viewStart:m=0,search:h="",regex:g=!1}=e,w=Bh(null),v=Bh(""),S=Bh(p);Ju(()=>{S.current=p},[p]);let E=n===void 0?r:r.slice(-n),_=[...new Set(r.map((x)=>x.service))],y=z0(o,_),b=E[E.length-1],k=b===void 0?"empty":String(b.seq);return Ju(()=>{let x=w.current;if(!x)return;if(x.stickyScroll=c,c)x.stickyStart="bottom",x.scrollTo({x:x.scrollLeft,y:Math.max(0,x.scrollHeight)})},[c,i,k]),Ju(()=>{let x=`${m}:${l}:${a}`;if(v.current===x)return;if(v.current=x,c&&(l<0||l>=E.length-1))return;let L=w.current;if(!L||l<0)return;let F=`log-row-${l}`,B=requestAnimationFrame(()=>{L.stickyScroll=!1,L.scrollChildIntoView(F)});return()=>cancelAnimationFrame(B)},[c,l,E.length,m,a]),Ju(()=>{if(!c||!p)return;let x=!1,L=0,F=0,B=setInterval(()=>{let K=w.current;if(!K)return;let V=K.viewport.height;if(V<=0)return;let{scrollHeight:X,scrollTop:te}=K;if(te<F){K.stickyScroll=!1,F=te,L=X,S.current?.();return}if(F=te,te+V>=X-f$){x=!0,L=X;return}if(X>L){K.stickyScroll=!0,K.stickyStart="bottom",K.scrollTo({x:K.scrollLeft,y:Math.max(0,X)}),L=X;return}if(x)S.current?.()},p$);return()=>{clearInterval(B)}},[c,i,p]),ze("box",{flexGrow:1,height:"100%",flexDirection:"column",overflow:"hidden",children:[ze(h$,{palette:t,serviceWidth:y,showTimestamps:u,showMeta:d},void 0,!1,void 0,this),ze("scrollbox",{ref:w,focused:s,stickyScroll:c,stickyStart:"bottom",scrollX:!1,style:{rootOptions:{flexGrow:1,height:"100%",overflow:"hidden",backgroundColor:t.panel},viewportOptions:{backgroundColor:t.panel},contentOptions:{backgroundColor:t.panel},scrollbarOptions:{trackOptions:{foregroundColor:t.primary,backgroundColor:t.element}}},children:ze("box",{flexDirection:"column",overflow:"hidden",children:E.map((x,L)=>ze(g$,{id:`log-row-${L}`,palette:t,event:x,serviceWidth:y,expanded:B0(a,L===l),active:L===l,showTimestamps:u,showMeta:d,onPick:f?()=>f(L):void 0,search:h,regex:g},`${x.timestamp}-${x.service}-${L}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function h$(e){let{palette:t,serviceWidth:r,showTimestamps:n,showMeta:o}=e;return ze("box",{height:1,flexShrink:0,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[ze(qT,{palette:t,serviceWidth:r,showTimestamps:n,showMeta:o,time:"TIME",service:"SERVICE",level:"LEVEL",meta:"SRC",header:!0},void 0,!1,void 0,this),ze("box",{flexGrow:1,flexShrink:1,minWidth:0,overflow:"hidden",children:ze("text",{fg:t.muted,wrapMode:"none",children:"MESSAGE"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function g$(e){let{id:t,palette:r,event:n,serviceWidth:o,expanded:i,active:s,showTimestamps:a=!0,showMeta:l=!0,onPick:c,search:u="",regex:d=!1}=e,f=Kt(n),p=n.severityText,m=n.source?n.traceId?`${m$}${n.source}`:n.source:"";return ze("box",{id:t,flexShrink:0,flexDirection:"row",alignItems:"flex-start",overflow:"hidden",height:i?"auto":1,backgroundColor:s?r.highlight:void 0,onMouseDown:c,children:[ze(qT,{palette:r,serviceWidth:o,showTimestamps:a,showMeta:l,time:n.timestamp.slice(11,19),service:n.service,level:p,meta:m},void 0,!1,void 0,this),ze("box",{flexGrow:1,flexShrink:1,minWidth:0,overflow:"hidden",children:ze(v$,{palette:r,level:p,text:f,wrap:i,search:u,regex:d},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function qT(e){let{palette:t,serviceWidth:r,showTimestamps:n,showMeta:o,time:i,service:s,level:a,meta:l,header:c=!1}=e,u=c?t.muted:void 0;return ze("box",{flexShrink:0,flexDirection:"row",overflow:"hidden",children:[n?ze(Xu,{width:Mm,fg:u??t.muted,text:i},void 0,!1,void 0,this):null,ze(Xu,{width:r,fg:u??Ye(s,t),text:s},void 0,!1,void 0,this),ze("box",{width:uu,flexShrink:0,overflow:"hidden",children:ze("text",{children:" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),ze(Xu,{width:Nm,fg:u??dt(t,a),text:c?a:Zi(a)},void 0,!1,void 0,this),o?ze(Xu,{width:$0,fg:u??t.muted,text:l},void 0,!1,void 0,this):null,ze("box",{width:uu,flexShrink:0,overflow:"hidden",children:ze("text",{children:" "},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Xu(e){let{width:t,fg:r,text:n}=e;return ze("box",{width:t,flexShrink:0,overflow:"hidden",children:ze("text",{fg:r,wrapMode:"none",children:j(n,t)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function v$(e){let{palette:t,level:r,text:n,wrap:o,search:i="",regex:s=!1}=e;return ze("text",{wrapMode:o?"word":"none",truncate:!o,flexShrink:0,width:"100%",children:W0(n,i,s).map((a,l)=>ze("span",{fg:y0(t,r,a.kind),children:a.text},`${a.kind}-${l}`,!1,void 0,this))},void 0,!1,void 0,this)}var p$=200,f$=2,m$="\u25CE";var GT=A(()=>{sn();nt();br();rt()});var Wh=A(()=>{BT();WT();zT();GT()});import{useRef as y$}from"react";import{jsxDEV as Ne}from"@opentui/react/jsx-dev-runtime";function Qu(e){let{palette:t,names:r,snap:n,selected:o,checked:i,width:s,onOpen:a,onSelectIndex:l,onToggle:c}=e,u=ye(),d=y$(!1),f=new Set(i),p=Dm(s),m=Im(s),h=Lm(s),g=I0(s);return Ne("box",{flexDirection:"column",flexGrow:1,overflow:"hidden",children:[Ne("box",{height:1,flexDirection:"row",overflow:"hidden",children:[Ne(rr,{width:2,fg:t.muted,text:""},void 0,!1,void 0,this),Ne(rr,{width:4,fg:t.accent,text:"sel"},void 0,!1,void 0,this),Ne(rr,{width:2,fg:t.muted,text:""},void 0,!1,void 0,this),Ne(rr,{width:g,fg:t.muted,text:"name"},void 0,!1,void 0,this),Ne(rr,{width:Bt,fg:t.muted,text:""},void 0,!1,void 0,this),Ne(rr,{width:Yr,fg:t.muted,text:"state"},void 0,!1,void 0,this),h?Ne(rr,{width:dn,fg:t.muted,text:"health"},void 0,!1,void 0,this):null,m?Ne(rr,{width:eu,fg:t.muted,text:"port"},void 0,!1,void 0,this):null,p?Ne(rr,{width:In,fg:t.muted,text:"pid"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),r.map((w,v)=>{let S=n?.services[w],E=yr(S),_=S?.health??"UNKNOWN",y=f.has(w),b=v===o,k=y?"[x]":"[ ]",x=b?"\u203A":" ";return Ne("box",{height:u.rowH,flexDirection:"row",overflow:"hidden",backgroundColor:b?t.highlight:y?t.element:void 0,onMouseDown:()=>{if(d.current)return;if(b){a(w);return}l(v)},children:[Ne("box",{width:2,flexShrink:0,children:Ne("text",{fg:t.primary,children:x},void 0,!1,void 0,this)},void 0,!1,void 0,this),Ne("box",{width:4,flexShrink:0,onMouseDown:()=>{d.current=!0,c?.(w),setTimeout(()=>{d.current=!1},0)},children:Ne("text",{fg:b$(t,y,b),children:k},void 0,!1,void 0,this)},void 0,!1,void 0,this),Ne("box",{width:2,flexShrink:0,children:Ne("text",{fg:dt(t,E),children:Or(E)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Ne(rr,{width:g,fg:b?t.primary:Ye(w,t),text:w},void 0,!1,void 0,this),Ne(rr,{width:Bt,fg:t.muted,text:""},void 0,!1,void 0,this),Ne(rr,{width:Yr,fg:dt(t,E),text:E},void 0,!1,void 0,this),h?Ne(rr,{width:dn,fg:dt(t,_),text:_},void 0,!1,void 0,this):null,m?Ne(rr,{width:eu,fg:t.text,text:ti(S)},void 0,!1,void 0,this):null,p?Ne(rr,{width:In,fg:t.text,text:S?.pid?String(S.pid):""},void 0,!1,void 0,this):null]},w,!0,void 0,this)})]},void 0,!0,void 0,this)}function Zu(e){let{palette:t,checked:r}=e,n=r.length;if(n>0)return Ne(wt,{palette:t,items:[{text:`${n} selected`,tone:"primary"}],hints:[{key:"space",label:"unmark"},{key:"n",label:"start these"},{key:"x",label:"stop these"}]},void 0,!1,void 0,this);return null}function b$(e,t,r){if(t)return e.success;if(r)return e.primary;return e.muted}function rr(e){return Ne("box",{width:e.width,flexShrink:0,overflow:"hidden",children:Ne("text",{fg:e.fg,wrapMode:"none",children:j(e.text,e.width)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var zh=A(()=>{Ht();nt();Ut();Re();rt()});import{jsxDEV as fe}from"@opentui/react/jsx-dev-runtime";function VT(e){let{palette:t,cfg:r,snap:n,logs:o,names:i,selected:s,selectedLog:a=-1,checked:l,width:c,followTick:u,logService:d,logSources:f,errorOnly:p,showSystemLogs:m,onOpen:h,onSelectIndex:g,onToggle:w,onFilterService:v,onToggleErrors:S,onShowErrors:E,wrapMode:_="all",view:y,follow:b=!0,onLeaveLatest:k,onPickLog:x,viewStart:L=0,viewTotal:F,newer:B=0,onJumpLatest:K,facets:V,leftover:X,search:te="",regex:R=!1}=e,U=ye();if(!r||i.length===0)return fe(it,{palette:t,title:"No services configured",body:"Add services to .devctl/config.yaml or finish setup.",hint:"open the setup screen with /setup"},void 0,!1,void 0,this);let O=c<rs,ae=ou(n),Ae=xu(n,i),se=i.filter((Se)=>n?.services[Se]?.state==="FAILED").length,z=Y0(o),ue=ae?M0(X,n?.session_id):void 0,re=nu(c,i,O),pt=Math.max(24,O?c-4:c-re-4),xt=m?o:o.filter((Se)=>!es(Se.source)),le=ni(o,{service:d,errorOnly:p,systemLogs:m,search:te,regex:R}),Oe=y??le,Fe=F??le.length,Qe=Math.min(Fe,L+Oe.length),kt=Fe===0?"empty":`${L+1}\u2013${Qe} of ${Fe}`,at=d===""?"all":d,Lt=[...Ae.running>0?[{text:`${Ae.running}/${i.length}`,tone:"success"}]:[],...se>0?[{text:`${se} failed`,tone:"error"}]:[],...l.length>0?[{text:`${l.length} selected`,tone:"primary"}]:[],...z>0?[{text:`${z} errors`,tone:"error",onMouseDown:E}]:[]];return fe("box",{flexGrow:1,flexDirection:O?"column":"row",overflow:"hidden",children:[fe("box",{flexGrow:O?1:0,flexShrink:0,minWidth:O?void 0:re,width:O?void 0:re,border:!0,borderStyle:"rounded",borderColor:ae?t.border:t.borderActive,backgroundColor:t.panel,title:"services",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[Lt.length>0?fe(wt,{palette:t,items:Lt},void 0,!1,void 0,this):null,fe(Zu,{palette:t,checked:l},void 0,!1,void 0,this),fe("box",{flexGrow:1,paddingLeft:U.pad,paddingRight:U.pad,overflow:"hidden",children:fe(Qu,{palette:t,names:i,snap:n,selected:s,checked:l,width:ru(re,U.pad),onOpen:h,onSelectIndex:g,onToggle:w},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe(S$,{palette:t,names:i,snap:n,width:re,onOpen:h},void 0,!1,void 0,this),ue?fe(T$,{palette:t,leftover:ue,width:re},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),fe("box",{position:"relative",flexGrow:2,minWidth:O?void 0:32,minHeight:O?8:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,backgroundColor:t.panel,title:`logs \xB7 ${at} \xB7 ${kt}`,titleColor:t.primary,overflow:"hidden",flexDirection:"column",children:[fe(gs,{palette:t,logs:xt,names:f??i,service:d,errorOnly:p,width:pt,onService:v,onToggleErrors:S,facets:V},void 0,!1,void 0,this),Fe>Oe.length?fe(Ha,{palette:t,start:L,count:Oe.length,total:Fe},void 0,!1,void 0,this):null,le.length===0?fe(it,{palette:t,title:ae?"Waiting for logs":o.length===0?"No events yet":"No events in this filter",body:ae?"Start services to stream output here. Later starts keep earlier logs.":o.length===0?"New lines appear as services write output.":"Click All or another service chip, or turn off ERROR+.",hint:"\u2190 \u2192 cycle service e errors g latest"},void 0,!1,void 0,this):fe(vs,{palette:t,logs:Oe,width:pt,followTick:u,focused:!1,wrapMode:_,selected:a,follow:b,onLeaveLatest:k,onPick:x,viewStart:L,search:te,regex:R},u,!1,void 0,this),!b?fe(hs,{palette:t,width:pt,newer:B,bottom:0,onJump:K},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function x$(e){if(!e)return!1;return e.state===bt||e.health===He||e.state===Ir||e.restarts>0||e.last_error!==""}function KT(e){if(e.state===bt)return 0;if(e.health===He)return 1;if(e.state===Ir)return 2;return 3}function k$(e){if(e.last_error!=="")return e.last_error;if(e.restarts>0)return`restarted ${e.restarts}x, no error recorded`;return e.health===He?"failing health check":e.state.toLowerCase()}function S$(e){let{palette:t,names:r,snap:n,width:o,onOpen:i}=e,s=r.map((u)=>({name:u,rt:n?.services[u]})).filter((u)=>x$(u.rt)).sort((u,d)=>KT(u.rt)-KT(d.rt));if(s.length===0)return null;let a=s.slice(0,w$),l=s.length-a.length,c=Math.max(8,o-qh-4);return fe("box",{flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",children:[fe("box",{height:1,overflow:"hidden",children:fe("text",{fg:t.error,wrapMode:"none",children:`issues (${s.length})`},void 0,!1,void 0,this)},void 0,!1,void 0,this),a.map(({name:u,rt:d})=>{let f=yr(d);return fe("box",{height:1,flexDirection:"row",overflow:"hidden",onMouseDown:()=>i(u),children:[fe("box",{width:2,flexShrink:0,children:fe("text",{fg:dt(t,f),children:Or(f)},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{width:qh,flexShrink:0,overflow:"hidden",children:fe("text",{fg:Ye(u,t),wrapMode:"none",children:j(u,qh)},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{width:c,flexShrink:0,overflow:"hidden",children:fe("text",{fg:t.muted,wrapMode:"none",children:ke(k$(d),c)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},u,!0,void 0,this)}),l>0?fe("text",{fg:t.muted,wrapMode:"none",children:`+${l} more \u2014 open a service to see details`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function T$(e){let{palette:t,leftover:r,width:n}=e,o=r.processes.slice(0,C$),i=r.processes.length-o.length,s=Math.max(8,n-Gh-4);return fe("box",{flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",children:[fe("box",{height:1,overflow:"hidden",children:fe("text",{fg:t.warning,wrapMode:"none",children:"last session"},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("text",{fg:t.muted,wrapMode:"none",children:ke(`${r.session_id} ${r.profile||"(none)"}`,Math.max(8,n-4))},void 0,!1,void 0,this),o.map((a)=>fe("box",{height:1,flexDirection:"row",overflow:"hidden",children:[fe("box",{width:Gh,flexShrink:0,overflow:"hidden",children:fe("text",{fg:t.text,wrapMode:"none",children:j(a.name,Gh)},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{width:s,flexShrink:0,overflow:"hidden",children:fe("text",{fg:t.muted,wrapMode:"none",children:ke(`pid ${a.pid} leftover`,s)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},`${a.name}-${a.pid}`,!0,void 0,this)),i>0?fe("text",{fg:t.muted,wrapMode:"none",children:`+${i} more leftover pids`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var w$=4,qh=14,C$=4,Gh=14;var YT=A(()=>{$t();cr();Ht();wr();nt();br();Ut();Su();Re();rt();Wh();zh()});import E$ from"cli-spinners";import{useEffect as R$,useState as _$}from"react";import{jsxDEV as ie}from"@opentui/react/jsx-dev-runtime";function JT(e){let{palette:t,report:r,loading:n,progress:o,error:i,selected:s,onPick:a,onReload:l}=e,c=ss(s,Vh);if(n)return ie(P$,{palette:t,progress:o},void 0,!1,void 0,this);if(i)return ie(rS,{palette:t,title:"Doctor failed",body:i},void 0,!1,void 0,this);if(!r)return ie(it,{palette:t,title:"Doctor",body:"Diagnostics have not run yet.",hint:"opening this screen runs doctor"},void 0,!1,void 0,this);let u=r.checks.filter((g)=>g.severity==="ok").length,d=r.checks.filter((g)=>g.severity==="warn").length,f=r.checks.filter((g)=>g.severity==="error").length,p=r.checks.length,m=Qi(p>0?u/p:0),h=f>0?t.error:d>0?t.warning:t.success;return ie(At,{palette:t,title:`doctor ${r.issues} issue(s)`,children:[ie("box",{height:4,flexDirection:"column",flexShrink:0,alignItems:"center",justifyContent:"center",overflow:"hidden",border:!0,borderStyle:"rounded",borderColor:t.primary,backgroundColor:t.element,onMouseDown:l,children:[ie("text",{wrapMode:"none",children:[ie("span",{fg:t.inverse,bg:t.primary,children:" r "},void 0,!1,void 0,this),ie("span",{fg:t.primary,children:" RUN DOCTOR AGAIN"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ie("text",{fg:t.muted,wrapMode:"none",children:"results stay cached until you refresh"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ie("box",{height:1,flexShrink:0},void 0,!1,void 0,this),ie("box",{height:1,flexShrink:0,overflow:"hidden",children:ie("text",{wrapMode:"none",children:[ie("span",{fg:h,children:`[${m}]`},void 0,!1,void 0,this),ie("span",{fg:t.success,children:` ${u} ok`},void 0,!1,void 0,this),d>0?ie("span",{fg:t.warning,children:` \xB7 ${d} warn`},void 0,!1,void 0,this):null,f>0?ie("span",{fg:t.error,children:` \xB7 ${f} error`},void 0,!1,void 0,this):null,d===0&&f===0?ie("span",{fg:t.muted,children:" \xB7 all clear"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this),ie("box",{height:1,flexShrink:0},void 0,!1,void 0,this),ie("scrollbox",{ref:c,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:ie("box",{flexDirection:"column",overflow:"hidden",gap:1,children:r.checks.map((g,w)=>ie(A$,{palette:t,check:g,index:w,active:w===s,onPick:a},`${g.name}-${w}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function P$({palette:e,progress:t}){let[r,n]=_$(0);return R$(()=>{let o=setInterval(()=>n((i)=>(i+1)%Kh.frames.length),Kh.interval);return()=>clearInterval(o)},[]),ie("box",{flexGrow:1,alignItems:"center",justifyContent:"center",overflow:"hidden",children:ie("box",{width:"80%",maxWidth:52,height:10,flexShrink:1,border:!0,borderStyle:"rounded",borderColor:e.borderActive,backgroundColor:e.panel,flexDirection:"column",alignItems:"center",justifyContent:"center",overflow:"hidden",children:[ie("text",{wrapMode:"none",children:[ie("span",{fg:e.primary,children:`${Kh.frames[r]} `},void 0,!1,void 0,this),ie("span",{fg:e.text,children:"devctl doctor"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ie("box",{height:1,flexShrink:0},void 0,!1,void 0,this),ie("text",{fg:e.text,wrapMode:"none",children:`Checking ${t.active}`},void 0,!1,void 0,this),ie("box",{height:1,flexShrink:0},void 0,!1,void 0,this),t.checks.slice(-4).map((o,i)=>ie("text",{wrapMode:"none",children:[ie("span",{fg:dt(e,o.severity==="error"?"ERROR":o.severity==="warn"?"WARN":"OK"),children:`${Or(o.severity==="error"?"ERROR":o.severity==="warn"?"WARN":"OK")} `},void 0,!1,void 0,this),ie("span",{fg:e.muted,children:o.name},void 0,!1,void 0,this)]},`${o.name}-${i}`,!0,void 0,this)),t.checks.length===0?ie("text",{fg:e.muted,children:"Waiting for the first result\u2026"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function A$(e){let{palette:t,check:r,index:n,active:o,onPick:i}=e,s=r.severity==="error"?"ERROR":r.severity==="warn"?"WARN":"OK";if(r.severity==="ok")return ie("box",{id:`${Vh}-${n}`,flexDirection:"row",flexShrink:0,paddingLeft:1,overflow:"hidden",backgroundColor:o?t.highlight:void 0,onMouseDown:()=>i(n),children:ie("text",{wrapMode:"none",children:[ie("span",{fg:t.primary,children:o?"\u203A ":" "},void 0,!1,void 0,this),ie("span",{fg:dt(t,s),children:Or(s)},void 0,!1,void 0,this),ie("span",{fg:o?t.primary:t.text,children:` ${r.name}`},void 0,!1,void 0,this),ie("span",{fg:t.muted,children:r.message?` \xB7 ${r.message}`:""},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this);let l=r.severity==="error"?t.error:t.warning;return ie("box",{id:`${Vh}-${n}`,border:!0,borderStyle:"rounded",borderColor:o?t.borderActive:l,title:r.name,titleColor:l,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",backgroundColor:o?t.highlight:void 0,onMouseDown:()=>i(n),children:[ie("text",{wrapMode:"word",children:[ie("span",{fg:dt(t,s),children:`${Or(s)} `},void 0,!1,void 0,this),ie("span",{fg:t.text,children:r.message},void 0,!1,void 0,this)]},void 0,!0,void 0,this),r.hint?ie("text",{fg:t.info,wrapMode:"word",children:`\u2192 ${r.hint}`},void 0,!1,void 0,this):null,o&&r.action?.kind==="free-port"?ie("text",{fg:t.primary,wrapMode:"none",children:`enter stop ${r.action.holder.command} (pid ${r.action.holder.pid})`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var Vh="doctor-row",Kh;var XT=A(()=>{cr();nt();Re();rt();Kh=E$.bouncingBall});import{jsxDEV as Je,Fragment as L$}from"@opentui/react/jsx-dev-runtime";function ZT(e){let{palette:t,logs:r,names:n,logSources:o,service:i,errorOnly:s,showSystemLogs:a,search:l,searchFocused:c,followTick:u,width:d,onSearch:f,onService:p,onToggleErrors:m,onSelect:h,wrapMode:g="all",selected:w=-1,follow:v=!0,newer:S=0,viewStart:E=0,viewTotal:_,onLeaveLatest:y,onJumpLatest:b,view:k,fullscreen:x=!1,facets:L,split:F=!1,splitFocus:B=0,serviceB:K="",viewB:V,selectedB:X=-1,followB:te=!0,newerB:R=0,viewStartB:U=0,viewTotalB:O,onServiceB:ae,onSelectB:Ae,onLeaveLatestB:se,onFocusPane:z}=e,ue=ye(),re=Fm(d,ue.pad,x),pt=a?r:r.filter((Se)=>!es(Se.source)),xt=ni(r,{service:i,services:e.services,errorOnly:s,search:l,regex:e.regex,source:e.source,systemLogs:a}),le=k??xt,Oe=_??xt.length,Fe=Math.min(Oe,E+le.length),Qe=Oe===0?"empty":`${E+1}\u2013${Fe} of ${Oe}`,kt=e.services??[],at=kt.length>0?kt.join(","):i===""?"all services":i,Lt=[...v?[]:[{text:S>0?`${F?"left ":""}pinned \xB7 +${S} new`:`${F?"left ":""}pinned`,tone:"warning"}],...F&&!te?[{text:R>0?`right pinned \xB7 +${R} new`:"right pinned",tone:"warning"}]:[],...e.source?[{text:`src ${e.source}`,tone:"info"}]:[],...e.regex?[{text:"regex",tone:"accent"}]:[],...l===""?[]:[{text:`search ${l}`,tone:"accent"}],...F?[{text:B===0?"left pane":"right pane",tone:"accent"}]:[]];if(F){let Se=Math.max(20,Math.floor(d/2)),St=Math.max(20,d-Se),gt=V??[],Ct=O??gt.length;return Je("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[c?Je("box",{height:1,paddingLeft:1,backgroundColor:t.highlight,overflow:"hidden",children:Je("input",{focused:!0,value:l,placeholder:"search messages or service names",onInput:f,backgroundColor:t.highlight,focusedBackgroundColor:t.highlight,textColor:t.text,cursorColor:t.primary},void 0,!1,void 0,this)},void 0,!1,void 0,this):Je(wt,{palette:t,items:Lt},void 0,!1,void 0,this),Je("box",{flexGrow:1,flexDirection:"row",overflow:"hidden",children:[Je(QT,{palette:t,names:o??n,logs:r,service:i,errorOnly:s,showSystemLogs:a,search:l,regex:e.regex,source:e.source,width:Se,shown:le,shownTotal:Oe,selected:w,follow:v,newer:S,viewStart:E,wrapMode:g,showTimestamps:e.showTimestamps!==!1,showMeta:e.showMeta!==!1,followTick:u,facets:L,focused:B===0,onService:p,onToggleErrors:m,onSelect:h,onLeaveLatest:y,onFocus:()=>z?.(0)},void 0,!1,void 0,this),Je(QT,{palette:t,names:o??n,logs:r,service:K,errorOnly:s,showSystemLogs:a,search:l,regex:e.regex,source:e.source,width:St,shown:gt,shownTotal:Ct,selected:X,follow:te,newer:R,viewStart:U,wrapMode:g,showTimestamps:e.showTimestamps!==!1,showMeta:e.showMeta!==!1,followTick:u,facets:L,focused:B===1,onService:ae??p,onToggleErrors:m,onSelect:Ae,onLeaveLatest:se,onFocus:()=>z?.(1)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),!v||!te?Je(hs,{palette:t,width:d,newer:Math.max(S,R),onJump:b},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}return Je("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[x?null:Je(L$,{children:[Lt.length>0?Je(wt,{palette:t,items:Lt},void 0,!1,void 0,this):null,Je(gs,{palette:t,logs:pt,names:o??n,service:i,errorOnly:s,width:d,onService:p,onToggleErrors:m,facets:L},void 0,!1,void 0,this)]},void 0,!0,void 0,this),c?Je("box",{height:1,paddingLeft:1,backgroundColor:t.highlight,overflow:"hidden",children:Je("input",{focused:!0,value:l,placeholder:"search messages or service names",onInput:f,backgroundColor:t.highlight,focusedBackgroundColor:t.highlight,textColor:t.text,cursorColor:t.primary},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,k&&Oe>le.length?Je(Ha,{palette:t,start:E,count:le.length,total:Oe},void 0,!1,void 0,this):null,Je("box",{flexGrow:1,border:!x,borderStyle:"rounded",borderColor:t.border,title:x?void 0:`logs ${at} \xB7 ${Qe}`,titleColor:t.primary,padding:x?0:ue.pad,overflow:"hidden",children:le.length===0?Je(it,{palette:t,title:r.length===0?"No log events":"No events in this filter",body:r.length===0?"Start services to stream logs.":"Pick All, another service, or clear search / ERROR+.",hint:`\u2190 \u2192 cycle filters e errors i internal ${jt("l")} clear`},void 0,!1,void 0,this):Je(vs,{palette:t,logs:le,width:re,followTick:u,focused:!1,wrapMode:g,selected:w,follow:v,showTimestamps:e.showTimestamps!==!1,showMeta:e.showMeta!==!1,onPick:h,onLeaveLatest:y,viewStart:E,search:l,regex:e.regex===!0},u,!1,void 0,this)},void 0,!1,void 0,this),!v?Je(hs,{palette:t,width:d,newer:S,onJump:b},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function QT(e){let{palette:t,width:r,service:n,shown:o,shownTotal:i,viewStart:s,focused:a}=e,l=e.showSystemLogs?e.logs:e.logs.filter((d)=>!es(d.source)),c=n===""?"all services":n,u=i===0?"empty":`${s+1}\u2013${Math.min(i,s+o.length)} of ${i}`;return Je("box",{width:r,flexGrow:0,flexShrink:0,flexDirection:"column",overflow:"hidden",onMouseDown:e.onFocus,children:[Je(gs,{palette:t,logs:l,names:e.names,service:n,errorOnly:e.errorOnly,width:r,onService:(d)=>{e.onFocus(),e.onService(d)},onToggleErrors:()=>{e.onFocus(),e.onToggleErrors()},facets:e.facets},void 0,!1,void 0,this),Je("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:a?t.borderActive:t.border,title:`logs ${c} \xB7 ${u}`,titleColor:a?t.primary:t.muted,overflow:"hidden",children:o.length===0?Je(it,{palette:t,title:"No events in this pane",body:"Click the pane, then \u2190 \u2192 to pick a service.",hint:"\\\\ split | focus"},void 0,!1,void 0,this):Je(vs,{palette:t,logs:o,width:Fm(r,0,!1),followTick:e.followTick,focused:!1,wrapMode:e.wrapMode,selected:e.selected,follow:e.follow,showTimestamps:e.showTimestamps,showMeta:e.showMeta,onPick:(d)=>{e.onFocus(),e.onSelect?.(d)},onLeaveLatest:e.onLeaveLatest,viewStart:s,search:e.search,regex:e.regex===!0},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var eE=A(()=>{Wh();cr();Ht();br();Re();Vr()});import{jsxDEV as Xe}from"@opentui/react/jsx-dev-runtime";function rE(e){let{palette:t,cfg:r,snap:n,profile:o,selected:i,onPick:s}=e,a=ye(),l=ss(i,tE),c=Object.keys(r?.profiles??{}).sort();if(c.length===0)return Xe(it,{palette:t,title:"No profiles",body:"Add profiles.<name>.services in config.yaml."},void 0,!1,void 0,this);return Xe(At,{palette:t,title:"profiles",children:[Xe("box",{height:1,flexShrink:0,overflow:"hidden",children:Xe("text",{fg:t.muted,wrapMode:"none",children:[`${c.length} profile${c.length===1?"":"s"} \xB7 current: `,Xe("span",{fg:t.success,children:o||"(none)"},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Xe("box",{height:1,flexShrink:0},void 0,!1,void 0,this),Xe("scrollbox",{ref:l,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:Xe("box",{flexDirection:"column",overflow:"hidden",gap:a.gap||1,children:c.map((u,d)=>{let f=u===o,p=d===i,m=r?.profiles[u]?.services??[],h=Object.keys(r?.profiles[u]?.environment??{}).length,g=p?t.borderActive:f?t.success:t.border,w=p?t.primary:f?t.success:t.muted;return Xe("box",{id:`${tE}-${d}`,border:!0,borderStyle:"rounded",borderColor:g,title:u,titleColor:w,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",backgroundColor:p?t.highlight:void 0,onMouseDown:()=>s(d),children:[Xe("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:Xe("text",{wrapMode:"none",children:[f?Xe("span",{fg:t.success,children:"\u25CF current profile"},void 0,!1,void 0,this):Xe("span",{fg:t.muted,children:"\u25CB not active"},void 0,!1,void 0,this),Xe("span",{fg:t.muted,children:` \xB7 ${m.length} service${m.length===1?"":"s"}`},void 0,!1,void 0,this),h>0?Xe("span",{fg:t.muted,children:` \xB7 ${h} env var${h===1?"":"s"}`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Xe("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:m.length===0?Xe("text",{fg:t.muted,wrapMode:"none",children:"(no services)"},void 0,!1,void 0,this):Xe("text",{wrapMode:"word",children:m.map((v,S)=>{let E=yr(n?.services[v]);return Xe("span",{children:[Xe("span",{fg:dt(t,E),children:Or(E)},void 0,!1,void 0,this),Xe("span",{fg:Ye(v,t),children:` ${v}`},void 0,!1,void 0,this),S<m.length-1?Xe("span",{fg:t.muted,children:" "},void 0,!1,void 0,this):null]},v,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},u,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this),Xe(Zt,{palette:t,backgroundColor:t.element,edge:"top",children:Xe(mt,{palette:t,hints:[{key:"space",label:"set current"},{key:"enter",label:"set and start"}]},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var tE="profile-row";var nE=A(()=>{cr();Ht();Ut();Re();rt()});import{jsxDEV as J,Fragment as aE}from"@opentui/react/jsx-dev-runtime";function I$(e){let t=e.toLowerCase();if(t==="iap")return"info";if(t==="service"||t==="service_account")return"primary";return"idle"}function D$(e,t,r){if(r||t>=500)return e.error;if(t===0||t>=400)return e.warning;return e.success}function O$(e,t){if(t.startsWith("sa:"))return{label:"SA",color:e.primary};if(t!=="")return{label:"USR",color:e.info};return{label:"\u2014",color:e.muted}}function $$(e){let{palette:t,req:r,cols:n,onOpenTrace:o}=e,i=D$(t,r.status,r.error),s=r.status>0?String(r.status):"ERR",a=O$(t,r.identity),l=r.route||lE,c=r.error?`${r.path} \u2014 ${ke(r.error,F$)}`:r.path,u=r.traceId;return J("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,onMouseDown:u&&o?()=>o(u):void 0,children:[J("box",{width:ed,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j(r.timestamp.slice(11,19),ed)},void 0,!1,void 0,this)},void 0,!1,void 0,this),n.showMethod?J("box",{width:td,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.text,wrapMode:"none",children:j(r.method,td)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,J("box",{width:rd,flexShrink:0,overflow:"hidden",children:J("text",{fg:i,wrapMode:"none",children:j(s,rd)},void 0,!1,void 0,this)},void 0,!1,void 0,this),n.showDur?J("box",{width:nd,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,wrapMode:"none",children:j(`${r.durationMs}ms`,nd)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,J("box",{width:od,flexShrink:0,overflow:"hidden",children:J("text",{fg:a.color,wrapMode:"none",children:j(a.label,od)},void 0,!1,void 0,this)},void 0,!1,void 0,this),J("box",{width:n.routeCol,flexShrink:0,overflow:"hidden",children:J("text",{fg:r.route?t.info:t.muted,wrapMode:"none",children:j(l,n.routeCol)},void 0,!1,void 0,this)},void 0,!1,void 0,this),J("box",{flexGrow:1,overflow:"hidden",children:J("text",{fg:r.error?t.error:t.text,wrapMode:"none",children:c},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function H$(e){let{palette:t,cols:r}=e;return J("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:[J("box",{width:ed,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j("TIME",ed)},void 0,!1,void 0,this)},void 0,!1,void 0,this),r.showMethod?J("box",{width:td,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j("METHOD",td)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,J("box",{width:rd,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j("ST",rd)},void 0,!1,void 0,this)},void 0,!1,void 0,this),r.showDur?J("box",{width:nd,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j("DUR",nd)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,J("box",{width:od,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j("WHO",od)},void 0,!1,void 0,this)},void 0,!1,void 0,this),J("box",{width:r.routeCol,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.muted,children:j("ROUTE",r.routeCol)},void 0,!1,void 0,this)},void 0,!1,void 0,this),J("box",{flexGrow:1,overflow:"hidden",children:J("text",{fg:t.muted,children:"PATH"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function U$(e){let{palette:t,name:r,auth:n,identity:o,upstream:i,match:s,onMouseDown:a}=e;return J("box",{flexDirection:"column",flexShrink:0,overflow:"hidden",onMouseDown:a,children:[J("text",{fg:t.text,wrapMode:"none",children:r},void 0,!1,void 0,this),J("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[J(Ue,{palette:t,label:n||"no auth",tone:I$(n)},void 0,!1,void 0,this),o?J(Ue,{palette:t,label:o,tone:"idle"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),s?J("text",{fg:t.muted,wrapMode:"word",children:`match: ${s}`},void 0,!1,void 0,this):null,J("text",{fg:t.muted,wrapMode:"word",children:`\u2192 ${i}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function cE(e){let{palette:t,cfg:r,snap:n,width:o,onSelectRoute:i,onOpenTrace:s}=e,a=n?.proxy.routes??[],l=new Map((r?.proxy.routes??[]).map((y)=>[y.name,y])),c=new Map((r?.proxy.routes??[]).map((y)=>[y.name,y.match])),u=n?.proxy.recentRequests??[],d=n?.proxy.requestTotal??0,f=n?.proxy.requestErrors??0,p=o<rs,m=Math.max(oE,Math.min(j$,Math.floor(o*0.36))),h=p?o-iE:o-m-iE,g=Math.max(20,h-2),w=g>=sE,v=g>=B$,S=g>=sE?W$:z$,E=u.reduce((y,b)=>Math.min(S,Math.max(y,(b.route||lE).length+N$)),M$),_={showMethod:w,showDur:v,routeCol:E};return J(At,{palette:t,title:"proxy",children:[J(wt,{palette:t,items:[{text:n?.proxy.running?"RUNNING":"STOPPED",tone:n?.proxy.running?"success":"idle"},...n?.proxy.address?[{text:n.proxy.address,tone:"info"}]:[],{text:`${a.length} routes`,tone:a.length>0?"primary":"idle"},...d>0?[{text:`${d} requests`,tone:"idle"},...f>0?[{text:`${f} errors`,tone:"warning"}]:[]]:[]]},void 0,!1,void 0,this),J("box",{flexGrow:1,flexDirection:p?"column":"row",overflow:"hidden",children:[J("box",{flexGrow:p?1:0,flexBasis:p?0:void 0,flexShrink:0,minWidth:p?void 0:oE,width:p?void 0:m,minHeight:p?8:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,title:"routes",titleColor:t.primary,paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",children:a.length===0?J(it,{palette:t,title:"No proxy routes",body:"Add routes under proxy.routes or .devctl/proxy/routes.yaml."},void 0,!1,void 0,this):J(aE,{children:[i?J("text",{fg:t.muted,wrapMode:"word",children:"click a route for full details"},void 0,!1,void 0,this):null,J("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:J("box",{flexDirection:"column",overflow:"hidden",gap:1,children:a.map((y)=>{let b=c.get(y.name),k=b&&(b.host||b.path)?`${b.host||"*"}${b.path?b.path:""}`:void 0,x=l.get(y.name);return J(U$,{palette:t,name:y.name,auth:y.auth,identity:y.identity,upstream:y.upstream,match:k,onMouseDown:i?()=>i({name:y.name,authType:x?.auth.type||y.auth,identityType:x?.auth.identity.type??"",serviceAccount:x?.auth.identity.service_account||x?.auth.service_account||"",audience:x?.auth.audience??"",clientId:x?.auth.client_id??"",clientSecret:Xl(x?.auth.client_secret??"")??((x?.auth.client_secret??"").trim()?"inline":""),matchHost:x?.match.host??"",matchPath:x?.match.path??"",upstream:y.upstream}):void 0},y.name,!1,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),J("box",{flexGrow:1,flexBasis:0,minWidth:p?void 0:30,minHeight:p?10:void 0,border:!0,borderStyle:"rounded",borderColor:t.borderActive,title:"requests",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:u.length===0?J("box",{paddingLeft:1,paddingRight:1,children:J("text",{fg:t.muted,wrapMode:"word",children:n?.proxy.running?"No requests seen yet. Send one through the proxy to see it show up here \u2014 no need to restart or press r.":"Start the proxy, then send it a request to see live traffic here."},void 0,!1,void 0,this)},void 0,!1,void 0,this):J(aE,{children:[J(H$,{palette:t,cols:_},void 0,!1,void 0,this),J("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:J("box",{flexDirection:"column",overflow:"hidden",children:u.map((y)=>J($$,{palette:t,req:y,cols:_,onOpenTrace:s},y.requestId,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),J(Zt,{palette:t,backgroundColor:t.element,edge:"top",children:J(mt,{palette:t,hints:[{key:"n",label:"start proxy"},{key:"x",label:"stop proxy"}]},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var ed=9,td=8,rd=4,nd=8,od=4,M$=8,N$=2,F$=64,lE="(none)",oE=26,j$=56,iE=2,sE=46,B$=54,W$=20,z$=12;var uE=A(()=>{cr();wr();nt();Re()});import{jsxDEV as pe}from"@opentui/react/jsx-dev-runtime";function fE(e){let{palette:t,name:r}=e;return pe("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:r,titleColor:Ye(r,t),flexDirection:"column",overflow:"hidden",children:pe(Yh,{...e,compact:!1},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Yh(e){let{palette:t,cfg:r,snap:n,name:o,reveal:i,width:s,compact:a=!0,envScrollRef:l}=e,c=ye(),u=r?.services[o];if(!u)return pe(it,{palette:t,title:"Unknown service",body:`No service named ${o}.`,hint:"j/k move"},void 0,!1,void 0,this);let d=n?.services[o],f=yr(d),p=d?.health??"UNKNOWN",m=ti(d)||Pa(u,d),h=O0(u,i,r?.secrets.extra_markers??[],r?.secrets.extra_patterns??[],e.resolvedEnv),g=e.envStatus==="error"?"error":e.envStatus==="resolved"?"success":e.envStatus==="loading"?"info":"muted",w=e.envStatus==="resolved"?"resolved":e.envStatus==="loading"?"resolving":e.envStatus==="error"?"config fallback":"config",v=s>=G$,S=[{label:"health",value:au(u)},{label:"workdir",value:u.working_dir||"."},{label:"restart",value:cu(u)},{label:"caps",value:u.capabilities.join(", ")||"\u2014"},{label:"runtime",value:u.container?`${u.container.runtime||"docker"} \xB7 ${u.container.image}`:"host"},...u.watch.enabled?[{label:"watch",value:u.watch.paths.join(" ")||"on"}]:[]],E=[{label:"identity",value:lu(u,d)},{label:"depends",value:u.dependencies.map(Fl).join(", ")||"\u2014"},{label:"ports",value:Pa(u,d)},{label:"tries",value:String(d?.restarts??0),tone:d?.restarts?"warning":"muted"}],_=Math.max(di+8,s-2),y=v?Math.floor(_/2):_;return pe("box",{padding:c.pad,flexGrow:1,flexDirection:"column",overflow:"hidden",children:[pe(wt,{palette:t,items:[{text:f,tone:pE(f)},{text:p,tone:pE(p)},{text:d?.pid?`pid ${d.pid}`:"pid \u2014",tone:d?.pid?"info":"idle"},{text:m==="\u2014"?"port \u2014":`port ${m}`,tone:m==="\u2014"?"idle":"info"}]},void 0,!1,void 0,this),u.description?pe("box",{height:1,overflow:"hidden",children:pe("text",{fg:t.muted,wrapMode:"none",children:ke(u.description,Math.max(8,s-4))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,d?.last_error?pe("box",{height:1,overflow:"hidden",children:pe("text",{fg:t.error,wrapMode:"none",children:ke(d.last_error,q$)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,pe(Jh,{palette:t,item:{label:"command",value:su(u)},valueWidth:Math.max(8,_-di)},void 0,!1,void 0,this),pe(K$,{palette:t,left:S,right:E,wide:v,colWidth:y},void 0,!1,void 0,this),pe(V$,{palette:t,entries:h,reveal:i,width:s,focused:!a,scrollRef:l,source:w,sourceTone:g,error:e.envError,onSelect:e.onSelectEnv},void 0,!1,void 0,this),a?null:pe(mt,{palette:t,hints:[{key:"n",label:"start"},{key:"x",label:"stop"},{key:"R",label:"restart"},{key:"o",label:"config"},{key:"l",label:"logs"},{key:"/reveal",label:"secrets"},{key:"esc",label:"back"}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function K$(e){let{palette:t,left:r,right:n,wide:o,colWidth:i}=e,s=Math.max(4,i-di);if(!o)return pe("box",{width:i,flexShrink:0,flexDirection:"column",overflow:"hidden",children:[...r,...n].map((a)=>pe(Jh,{palette:t,item:a,valueWidth:s},a.label,!1,void 0,this))},void 0,!1,void 0,this);return pe("box",{height:r.length,flexShrink:0,flexDirection:"row",overflow:"hidden",children:[pe(dE,{palette:t,items:r,width:i},void 0,!1,void 0,this),pe(dE,{palette:t,items:n,width:i},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function dE(e){let t=Math.max(4,e.width-di);return pe("box",{width:e.width,flexShrink:0,flexDirection:"column",overflow:"hidden",children:e.items.map((r)=>pe(Jh,{palette:e.palette,item:r,valueWidth:t},r.label,!1,void 0,this))},void 0,!1,void 0,this)}function Jh(e){let{palette:t,item:r,valueWidth:n}=e,o=r.tone==="warning"?t.warning:r.tone==="muted"?t.muted:t.text;return pe("box",{height:1,width:di+n,flexDirection:"row",overflow:"hidden",children:[pe("box",{width:di,flexShrink:0,overflow:"hidden",children:pe("text",{fg:t.muted,wrapMode:"none",children:j(r.label,di)},void 0,!1,void 0,this)},void 0,!1,void 0,this),pe("box",{width:n,flexShrink:0,overflow:"hidden",children:pe("text",{fg:o,wrapMode:"none",children:j(r.value,n)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function V$(e){let{palette:t,entries:r,reveal:n,width:o,focused:i,scrollRef:s,source:a,sourceTone:l,error:c,onSelect:u}=e;return pe("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[pe(wt,{palette:t,items:[{text:`env ${r.length}`,tone:r.length>0?"info":"idle"},{text:a,tone:l},{text:n?"secrets shown":"redacted",tone:n?"warning":"muted"}],hints:i?[{key:"j/k",label:"scroll"}]:[{key:"/reveal",label:"secrets"}]},void 0,!1,void 0,this),c?pe("box",{height:1,overflow:"hidden",children:pe("text",{fg:t.warning,wrapMode:"none",children:ke(c,Math.max(8,o-4))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,r.length===0?pe("text",{fg:t.muted,children:"no service env overrides"},void 0,!1,void 0,this):pe("box",{flexGrow:1,height:"100%",overflow:"hidden",children:[u?pe("text",{fg:t.muted,wrapMode:"word",children:"click a variable for its full value"},void 0,!1,void 0,this):null,pe("scrollbox",{ref:s,focused:i,stickyScroll:!1,scrollX:!1,style:{rootOptions:{flexGrow:1,height:"100%",overflow:"hidden",backgroundColor:t.panel},viewportOptions:{backgroundColor:t.panel},contentOptions:{backgroundColor:t.panel},scrollbarOptions:{trackOptions:{foregroundColor:t.primary,backgroundColor:t.element}}},children:pe("box",{flexDirection:"column",overflow:"hidden",children:r.map((d)=>{let f=d.required?t.warning:d.fromConfig?t.accent:t.muted,p=d.value===""&&d.required?"(required)":d.value;return pe("box",{flexDirection:"row",overflow:"hidden",onMouseDown:u?()=>u(d):void 0,children:pe("text",{wrapMode:"word",children:[pe("span",{fg:f,children:d.required?`${d.key}*`:d.key},void 0,!1,void 0,this),pe("span",{fg:d.value===""?t.muted:t.text,children:` ${p}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},d.key,!1,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function pE(e){switch(e.toUpperCase()){case"HEALTHY":case"RUNNING":return"success";case"UNHEALTHY":case"WARNING":case"WARN":case"STARTING":case"RESTARTING":return"warning";case"FAILED":case"ERROR":return"error";default:return"muted"}}var q$=72,G$=56,di=9;var Xh=A(()=>{Ke();cr();Ht();nt();Ut();Re();rt()});import{jsxDEV as ho}from"@opentui/react/jsx-dev-runtime";function mE(e){let{palette:t,cfg:r,names:n,snap:o,selected:i,checked:s,width:a,reveal:l,onOpen:c,onSelectIndex:u,onToggle:d,resolvedEnv:f,envStatus:p,envError:m,onSelectEnv:h}=e;if(n.length===0)return ho(it,{palette:t,title:"No services",body:"This configuration does not define any services."},void 0,!1,void 0,this);let g=a<rs,w=n[i]??"",v=nu(a,n,g),S=4,E=g?Math.max(Qh,a-S):Math.max(Qh,a-v-S);return ho("box",{flexGrow:1,flexDirection:g?"column":"row",overflow:"hidden",children:[ho("box",{flexGrow:g?1:0,flexShrink:0,minWidth:g?void 0:Zc,width:g?void 0:v,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:"services",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[ho(Zu,{palette:t,checked:s},void 0,!1,void 0,this),ho("box",{flexGrow:1,overflow:"hidden",children:ho(Qu,{palette:t,names:n,snap:o,selected:i,checked:s,width:ru(v),onOpen:c,onSelectIndex:u,onToggle:d},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ho("box",{flexGrow:2,minWidth:g?void 0:Qh,minHeight:g?Y$:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,backgroundColor:t.panel,title:w||"detail",titleColor:w?Ye(w,t):t.primary,overflow:"hidden",flexDirection:"column",children:ho(Yh,{palette:t,cfg:r,snap:o,name:w,reveal:l,width:E,resolvedEnv:f,envStatus:p,envError:m,onSelectEnv:h},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Qh=36,Y$=12;var hE=A(()=>{cr();wr();Ut();rt();Xh();zh()});import{jsxDEV as _e}from"@opentui/react/jsx-dev-runtime";function X$(e){switch(e){case"cycle":return"\u2194";case"toggle":return"\u23FB";case"page":return"\u25B8";case"action":return"!";default:return"\xB7"}}function yE(e){let{palette:t,items:r,selected:n,locked:o,width:i,onPick:s,onActivate:a}=e,l=ye(),c=Cm(r,n),u=oo(r,c);return _e("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:"settings",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[_e("box",{height:2,paddingLeft:l.pad,flexShrink:0,flexDirection:"column",overflow:"hidden",children:[_e("text",{fg:t.primary,wrapMode:"none",children:"Preferences"},void 0,!1,void 0,this),_e("text",{fg:t.muted,wrapMode:"none",children:o?"DEVCTL_TUI_CONFIG is set \u2014 changes stay in this session.":"Changes save to your user tui.json unless noted."},void 0,!1,void 0,this)]},void 0,!0,void 0,this),_e("box",{flexGrow:1,paddingLeft:l.pad,paddingRight:l.pad,overflow:"hidden",flexShrink:1,children:_e(Q$,{palette:t,items:r,active:c,scale:l,width:i,onPick:s,onActivate:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),_e(eH,{palette:t,item:u,scale:l},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Q$(e){let{palette:t,items:r,active:n,scale:o,width:i,onPick:s,onActivate:a}=e,l=ss(n,vE),c=Math.max(8,i-Zh-gE-10),u=0,d=E0(r);return _e("scrollbox",{ref:l,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:_e("box",{flexDirection:"column",overflow:"hidden",children:d.map((f,p)=>{let m=u;u+=f.items.length;let h=n>=m&&n<m+f.items.length;return _e("box",{flexDirection:"column",flexShrink:0,marginBottom:p<d.length-1?Math.max(1,o.gap):0,overflow:"hidden",children:[_e("box",{height:1,overflow:"hidden",children:_e("text",{fg:h?t.primary:t.muted,wrapMode:"none",children:f.group},void 0,!1,void 0,this)},void 0,!1,void 0,this),f.group==="MCP"?_e("box",{height:1,overflow:"hidden",children:_e("text",{fg:t.muted,wrapMode:"none",children:"dedicated page \u2014 also /mcp or /agent"},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,f.items.map((g,w)=>{let v=m+w;return _e(Z$,{index:v,palette:t,item:g,active:v===n,rowH:o.rowH,valueWidth:c,onPick:()=>s(v),onActivate:()=>a(g)},g.id,!1,void 0,this)})]},f.group,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Z$(e){let{palette:t,index:r,item:n,active:o,rowH:i,valueWidth:s,onPick:a,onActivate:l}=e;return _e("box",{id:`${vE}-${r}`,height:i,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:o?t.highlight:void 0,onMouseDown:()=>{if(o){l();return}a()},children:[_e("box",{width:2,flexShrink:0,overflow:"hidden",children:_e("text",{fg:t.primary,children:o?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),_e("box",{width:gE,flexShrink:0,overflow:"hidden",children:_e("text",{fg:o?t.primary:t.muted,children:X$(n.kind)},void 0,!1,void 0,this)},void 0,!1,void 0,this),_e("box",{width:Zh,flexShrink:0,overflow:"hidden",children:_e("text",{fg:o?t.primary:t.text,wrapMode:"none",children:j(n.name,Zh)},void 0,!1,void 0,this)},void 0,!1,void 0,this),_e("box",{flexGrow:1,overflow:"hidden",children:_e("text",{fg:tH(t,n,o),wrapMode:"none",children:ke(n.value,s)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function eH(e){let{palette:t,item:r,scale:n}=e,o=r?.id==="font",i=r?.kind==="page"?`${r.name} \u2192 dedicated page`:r?.name??"";return _e("box",{height:J$,flexShrink:0,border:!0,borderStyle:"rounded",borderColor:t.border,title:"selected",titleColor:t.muted,backgroundColor:t.element,paddingLeft:n.pad,paddingRight:n.pad,flexDirection:"column",overflow:"hidden",children:[_e("box",{height:1,overflow:"hidden",children:_e("text",{fg:t.primary,wrapMode:"none",children:o?`${C0(n.steps)} ${n.label}`:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),_e("box",{height:1,overflow:"hidden",children:_e("text",{fg:t.text,wrapMode:"word",children:r?.detail??""},void 0,!1,void 0,this)},void 0,!1,void 0,this),_e("box",{height:1,overflow:"hidden",children:_e("text",{fg:t.muted,wrapMode:"none",children:r?r.kind==="info"?"read-only":r.hint:""},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function tH(e,t,r){if(t.id==="mouse")return t.value==="on"?e.success:e.text;if(t.kind==="page")return e.info;if(t.kind==="info")return e.text;return r?e.primary:e.text}var Zh=14,gE=2,J$=5,vE="settings-row";var bE=A(()=>{Ht();nt();Re();Mr()});import{jsxDEV as De}from"@opentui/react/jsx-dev-runtime";function wE(e){let{palette:t,cfg:r,google:n,bootError:o,bootErrorMissing:i=!1,step:s=0}=e,a=ye();if(o&&!r)return i?De(it,{palette:t,title:"No configuration found",body:"Would you like to run setup?",hint:"[Enter] 9-step setup [Esc] Exit"},void 0,!1,void 0,this):De(it,{palette:t,title:"Configuration error",body:o,hint:"Fix .devctl/config.yaml, then restart devctl [Esc] Exit"},void 0,!1,void 0,this);let l=e.issues,c=rH(r,n,l),u=c.filter((v)=>v.ok).length,d=c.length,f=d>0?Math.round(u/d*100):0,p=20,m=Math.round(f/100*p),h="\u2588".repeat(m)+"\u2591".repeat(Math.max(0,p-m)),g=f===100?t.success:f===0?t.muted:t.primary,w=c[s];return De(At,{palette:t,title:"setup",scroll:!0,children:[De("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:De("text",{fg:t.primary,children:"Developer onboarding"},void 0,!1,void 0,this)},void 0,!1,void 0,this),De("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:De("text",{wrapMode:"none",children:[De("span",{fg:g,children:`[${h}]`},void 0,!1,void 0,this),De("span",{fg:t.text,children:` ${u}/${d} ready`},void 0,!1,void 0,this),De("span",{fg:t.muted,children:` (${f}%)`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),De("box",{height:1,flexShrink:0},void 0,!1,void 0,this),c.map((v,S)=>{let E=S===s;return De("box",{height:a.rowH,flexDirection:"row",overflow:"hidden",backgroundColor:E?t.highlight:void 0,paddingLeft:1,children:[De("box",{width:2,flexShrink:0,children:De("text",{fg:dt(t,v.ok?"OK":"WARN"),children:Or(v.ok?"OK":"WARN")},void 0,!1,void 0,this)},void 0,!1,void 0,this),De("box",{width:3,flexShrink:0,children:De("text",{fg:E?t.primary:t.muted,children:String(S+1).padStart(2," ")},void 0,!1,void 0,this)},void 0,!1,void 0,this),De("box",{width:20,flexShrink:0,overflow:"hidden",children:De("text",{fg:E?t.primary:t.text,children:j(v.name,20)},void 0,!1,void 0,this)},void 0,!1,void 0,this),De("box",{flexGrow:1,overflow:"hidden",children:De("text",{fg:E?t.text:t.muted,wrapMode:"none",children:v.detail},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},v.name,!0,void 0,this)}),De("box",{height:1,flexShrink:0},void 0,!1,void 0,this),w?De("box",{border:!0,borderStyle:"rounded",borderColor:w.ok?t.success:t.warning,title:w.name,titleColor:w.ok?t.success:t.warning,flexDirection:"column",paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:De("text",{fg:w.ok?t.text:t.warning,wrapMode:"word",children:w.detail},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,De("box",{height:1,flexShrink:0},void 0,!1,void 0,this),De("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:De(Ue,{palette:t,label:"never hard-coded",tone:"idle"},void 0,!1,void 0,this)},void 0,!1,void 0,this),De("text",{fg:t.muted,wrapMode:"word",children:"Service accounts and IAP audiences stay in configuration. Run `devctl setup` for the interactive CLI wizard."},void 0,!1,void 0,this),De(mt,{palette:t,hints:[{key:"j/k",label:"steps"},{key:"enter",label:r?"start":"begin setup"},{key:"esc",label:"exit"},{key:"o",label:"profiles"}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function rH(e,t,r=[]){let n=Object.values(e?.services??{}).flatMap((s)=>s.ports.filter((a)=>!a.auto)),o=(e?.proxy.routes??[]).some((s)=>s.auth.type.toLowerCase()==="iap"),i=Gu(e,void 0,t).project;return[{name:On[0],ok:Boolean(e?.repoRoot),detail:e?.repoRoot||"unknown"},{name:On[1],ok:Boolean(e?.project.name),detail:e?.project.name||"set project.name"},{name:On[2],ok:Boolean(i),detail:i||"optional for local-only"},{name:On[3],ok:t?.adcAvailable===!0,detail:t?.adcAvailable?"ADC available":"needed only for cloud identity / IAP"},{name:On[4],ok:!0,detail:"read from configuration; never hard-coded"},{name:On[5],ok:!o||(e?.proxy.routes??[]).every((s)=>s.auth.type.toLowerCase()!=="iap"||s.auth.audience!==""),detail:o?"IAP routes present":"no IAP routes"},{name:On[6],ok:n.length===0||Boolean(e),detail:`${n.length} fixed ports from configuration`},{name:On[7],ok:Object.keys(e?.profiles??{}).length>0,detail:`${Object.keys(e?.profiles??{}).length} profile(s)`},{name:On[8],ok:r.length===0,detail:r.length===0?"configuration is valid":r[0]??"invalid"}]}var On;var xE=A(()=>{cr();Ht();nt();Re();rt();On=["Repository","Environment","Google project","Authentication","Service accounts","IAP","Ports","Profiles","Validation"]});import{useEffect as nH,useState as oH}from"react";import{jsxDEV as oe}from"@opentui/react/jsx-dev-runtime";function ys(e){let{palette:t,title:r,tone:n="muted",children:o}=e,i=n==="success"?t.success:n==="warning"?t.warning:n==="error"?t.error:t.border;return oe("box",{border:!0,borderStyle:"rounded",borderColor:i,title:r,titleColor:i,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,marginBottom:1,overflow:"hidden",children:o},void 0,!1,void 0,this)}function eg(e,t){if(t.color)return t.color;switch(t.tone){case"success":return e.success;case"warning":return e.warning;case"error":return e.error;case"primary":return e.primary;case"muted":return e.muted;default:return e.text}}function ja(e){let{palette:t,cells:r,header:n,gap:o=0,stripe:i}=e;return oe("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:i?t.element:void 0,children:r.map((s,a)=>oe("box",{flexDirection:"row",flexShrink:0,overflow:"hidden",children:[a>0&&o>0?oe("box",{width:o,flexShrink:0},void 0,!1,void 0,this):null,oe("box",{width:s.width,flexShrink:0,overflow:"hidden",children:oe("text",{fg:n?t.primary:eg(t,s),wrapMode:"none",children:j(s.text,s.width)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},`${s.text}-${a}`,!0,void 0,this))},void 0,!1,void 0,this)}function kE(e){let{palette:t,width:r}=e;return oe("box",{height:1,flexShrink:0,overflow:"hidden",children:oe("text",{fg:t.border,wrapMode:"none",children:j("\u2500".repeat(Math.max(1,r)),r)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Ua(e){let{palette:t,facts:r,width:n}=e,o=Zm(r,n),i=[{text:"what",width:o.what},{text:"reading",width:o.reading}];if(o.meter>0)i.push({text:"used",width:o.meter});return i.push({text:"meaning",width:o.meaning}),oe("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[oe(ja,{palette:t,header:!0,gap:is,cells:i},void 0,!1,void 0,this),oe(kE,{palette:t,width:n},void 0,!1,void 0,this),r.map((s,a)=>{let l=s.meaning===""?[""]:j0(s.meaning,Math.max(1,o.meaning)),c=s.meter?Bk(s.meter):o.meter>0?"":void 0,u=[{text:s.what,width:o.what,tone:"text"},{text:s.reading,width:o.reading,tone:s.tone??"text"}];if(o.meter>0)u.push({text:c??"",width:o.meter,tone:s.meter?s.tone??"text":"muted"});return u.push({text:l[0]??"",width:o.meaning,tone:"muted"}),oe("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[oe(ja,{palette:t,gap:is,stripe:a%2===1,cells:u},void 0,!1,void 0,this),l.slice(1).map((d,f)=>{let p=[{text:"",width:o.what},{text:"",width:o.reading}];if(o.meter>0)p.push({text:"",width:o.meter});return p.push({text:d,width:o.meaning,tone:"muted"}),oe(ja,{palette:t,gap:is,stripe:a%2===1,cells:p},`${s.what}-more-${f}`,!1,void 0,this)})]},`${s.what}-${s.reading}-${a}`,!0,void 0,this)})]},void 0,!0,void 0,this)}function SE(e){let{palette:t,cfg:r,snap:n,width:o,onRefresh:i}=e,s=ye(),[,a]=oH(0);if(nH(()=>{let O=setInterval(()=>{a((ae)=>{let Ae=ae+1;if(i&&Ae%sH===0)i();return Ae})},iH);return()=>clearInterval(O)},[i]),!r)return oe(it,{palette:t,title:"No configuration loaded",body:"Add services to .devctl/config.yaml or finish setup."},void 0,!1,void 0,this);let l=Object.keys(r.services).sort(),c=l.some((O)=>Wk(r.services[O])),u=Mk(l,n),d=Jk(u,c),f=c&&u.live>0?u.healthy/u.live:u.total>0?u.live/u.total:0,p=Qi(f,aH),m=u.failed>0?"error":c&&u.live>0&&u.healthy<u.live?"warning":"success",h=Hk(o,s.pad),g=n?.session_id?kd(n.session_id):void 0,w=g?Ca(Date.now()-g.getTime()):"just started",v=n?.logs.total??0,S=n?.logs.errors??0,E=n?.logs.seen??v,_=n?.logs.seenErrors??S,y=$k(n?.logs.counts??{}),b=n?.proxy.routes??[],k=n?.credentials,x=(k?.entries??[]).filter((O)=>O.valid).length,L=n?.system,F=L?L.memAvailableKB??L.memFreeKB:0,B=L?qk(L.loadAvg1,L.cpuCount):void 0,K=L?Gk(F,L.memTotalKB):void 0,V=[];if(L&&B&&K){V.push(B,K,{what:"Computer",reading:zk(L.platform),meaning:`on for ${Ca(L.hostUptimeSec*lH)}`,tone:"text"});let O=n?.stats_series;if(O&&O.cpu.length>1)V.push({what:"Load trend",reading:Qm(O.cpu),meaning:`${Math.round(O.interval_ms/1000)}s samples`,tone:"text"});if(O&&O.mem.length>1)V.push({what:"RAM trend",reading:Qm(O.mem),meaning:"used memory over the same window",tone:"text"})}let X=u.failed>0||B?.tone==="error"||K?.tone==="error"?"error":m==="warning"||B?.tone==="warning"||K?.tone==="warning"?"warning":"success",te=[{what:"This session",reading:w,meaning:"how long this run has been going",tone:"text"},{what:"Profile",reading:n?.profile||"none",meaning:"which group of services is selected",tone:n?.profile?"text":"muted"},{what:"This window",reading:n?.detached?"closed":"watching",meaning:n?.detached?"services keep running without this screen":"you are watching the services from here",tone:n?.detached?"warning":"text"},{what:"Project folder",reading:"",meaning:r.repoRoot,tone:"muted"}],R=[{what:"Lines kept",reading:String(v),meaning:"log lines still in memory",tone:"text"},...E>v?[{what:"Lines seen",reading:String(E),meaning:"ingested this session, including rotated-out lines",tone:"text"}]:[],{what:"Error lines",reading:String(_),meaning:_>0?"open Logs and press e to see only errors":"no ERROR or FATAL lines",tone:_>0?"error":"muted"},...y.map(([O,ae])=>({what:O,reading:String(ae),meaning:"lines from this service",tone:"text"}))],U=[{what:"Web proxy",reading:n?.proxy.running?"on":"off",meaning:n?.proxy.running?`${b.length} apps${n.proxy.address?` at ${n.proxy.address}`:""}`:"not forwarding local URLs",tone:n?.proxy.running?"success":"muted"},{what:"Agent tools",reading:n?.mcp?.running?"on":"off",meaning:n?.mcp?.address?`Cursor talks to devctl at ${n.mcp.address}`:"turn on from Settings \u2192 MCP",tone:n?.mcp?.running?"success":"muted"},{what:"Google account",reading:n?.identity.user?"signed in":"not signed in",meaning:[n?.identity.user,n?.identity.project].filter(Boolean).join(" \xB7 ")||"no Google user for this session",tone:n?.identity.user?"success":"muted"},{what:"Saved tokens",reading:k?`${x} of ${k.entries.length} good`:"none",meaning:k?Yk(k.backend):"nothing stored yet",tone:k&&x<k.entries.length?"warning":k?"success":"muted"}];return oe(At,{palette:t,title:"stats",scroll:!0,children:[oe(ys,{palette:t,title:`Your services ${u.live} of ${u.total} started`,tone:X,children:[oe(Ua,{palette:t,facts:d,width:h},void 0,!1,void 0,this),oe("box",{height:1,flexShrink:0},void 0,!1,void 0,this),oe("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:oe("text",{wrapMode:"none",children:[oe("span",{fg:t.muted,children:j(c?"Ready":"Started",Zm(d,h).what)},void 0,!1,void 0,this),oe("span",{children:" ".repeat(is)},void 0,!1,void 0,this),oe("span",{fg:eg(t,{text:"",width:1,tone:m}),children:`[${p}]`},void 0,!1,void 0,this),oe("span",{fg:eg(t,{text:"",width:1,tone:m}),children:c?` ${u.healthy} of ${u.live||u.total} passing checks`:` ${u.live} of ${u.total} up`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),L?oe(ys,{palette:t,title:"This computer",tone:B?.tone==="error"||K?.tone==="error"?"error":B?.tone==="warning"||K?.tone==="warning"?"warning":"success",children:oe(Ua,{palette:t,facts:V,width:h},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,oe(ys,{palette:t,title:"This session",children:oe(Ua,{palette:t,facts:te,width:h},void 0,!1,void 0,this)},void 0,!1,void 0,this),oe(ys,{palette:t,title:"Each service",tone:u.failed>0?"error":c&&u.live>0&&u.healthy<u.live?"warning":"success",children:u.total===0?oe("text",{fg:t.muted,children:"No services in this project yet."},void 0,!1,void 0,this):oe("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[oe(cH,{palette:t,names:l,snap:n,width:h},void 0,!1,void 0,this),oe("box",{height:1,flexShrink:0},void 0,!1,void 0,this),oe("text",{fg:t.muted,wrapMode:"none",children:j("CPU is % of one core. RAM is what that process is holding now.",h)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),oe(ys,{palette:t,title:"Log lines",tone:S>0?"warning":"muted",children:oe(Ua,{palette:t,facts:R,width:h},void 0,!1,void 0,this)},void 0,!1,void 0,this),oe(ys,{palette:t,title:"Other parts",children:oe(Ua,{palette:t,facts:U,width:h},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function cH(e){let{palette:t,names:r,snap:n,width:o}=e,i=Uk(o),s=[{text:"service",width:i.name},{text:"status",width:Yr}];if(i.health)s.push({text:"check",width:dn});if(i.cpu)s.push({text:"cpu",width:Ra});if(i.mem)s.push({text:"ram",width:_a});if(i.up)s.push({text:"up",width:Ea});if(i.rst)s.push({text:"restarts",width:ku});if(i.pid)s.push({text:"pid",width:In});return oe("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[oe(ja,{palette:t,header:!0,gap:Bt,cells:s},void 0,!1,void 0,this),oe(kE,{palette:t,width:o},void 0,!1,void 0,this),r.map((a,l)=>oe(fH,{palette:t,name:a,rt:n?.services[a],cols:i,stripe:l%2===1},a,!1,void 0,this))]},void 0,!0,void 0,this)}function pH(e){if(e===void 0)return"muted";if(e>dH)return"error";if(e>uH)return"warning";return"text"}function fH(e){let{palette:t,name:r,rt:n,cols:o,stripe:i}=e,s=Kk(n),a=Vk(n),l=n?.restarts??0,c=[{text:r,width:o.name,color:Ye(r,t)},{text:s,width:Yr,color:dt(t,n?.state??"STOPPED")}];if(o.health)c.push({text:a,width:dn,color:dt(t,n?.health??"UNKNOWN")});if(o.cpu)c.push({text:n?.cpuPercent!==void 0?P0(n.cpuPercent):"\u2014",width:Ra,tone:pH(n?.cpuPercent)});if(o.mem)c.push({text:n?.memoryKB!==void 0?Ta(n.memoryKB):"\u2014",width:_a,tone:"text"});if(o.up)c.push({text:Fk(n),width:Ea,tone:"text"});if(o.rst)c.push({text:String(l),width:ku,tone:l>0?"warning":"muted"});if(o.pid)c.push({text:n?.pid?String(n.pid):"\u2014",width:In,tone:"muted"});return oe("box",{flexDirection:"column",flexShrink:0,overflow:"hidden",children:[oe(ja,{palette:t,gap:Bt,stripe:i,cells:c},void 0,!1,void 0,this),n?.last_error?oe("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:oe("text",{fg:t.error,wrapMode:"none",children:j(` ${n.last_error}`,Math.max(24,o.name+Bt+Yr+dn))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var iH=1000,sH=5,aH=16,lH=1000,uH=80,dH=100;var CE=A(()=>{cr();Ht();nt();br();Ut();Su();Re();rt()});import{useRenderer as mH,useTerminalDimensions as hH}from"@opentui/react";import{useCallback as gn,useEffect as gH,useMemo as tg,useRef as $r,useState as qe}from"react";import{jsxDEV as me,Fragment as vH}from"@opentui/react/jsx-dev-runtime";function TE({controller:e,tui:t,onQuit:r,onDown:n,onAttached:o,bootError:i,bootErrorMissing:s=!1,terminalBackground:a,workspace:l}){let{saveTuiPreferences:c,resolveTuiOverridePath:u,userTuiConfigPath:d,validateConfigText:f,freePort:p,readTextFile:m,writeTextFile:h,createStarterConfig:g,validate:w}=l,[v,S]=qe(e),[E,_]=qe(i),y=mH(),{width:b,height:k}=hH(),[x,L]=qe(v?"dashboard":"setup"),[F,B]=qe("none"),[K,V]=qe(""),[X,te]=qe("commands"),[R,U]=qe(0),[O,ae]=qe(0),[Ae,se]=qe(0),[z,ue]=qe([]),[re,pt]=qe(),[xt,le]=qe(E??""),[Oe,Fe]=qe({}),[Qe,kt]=qe(),[at,Lt]=qe(D0(v?.cfg)),[Se,St]=qe(""),[gt,Ct]=qe(!1),[xr,lt]=qe(),[It,Ze]=qe(),[Tt,ur]=qe(0),[dr,Zr]=qe(),[pr,nr]=qe(),kr=$r(null),Sr=$r(null),Cr=$r(null),zt=$r(null),de=$r(null),Z=$r(null),D=$r(null),we=$r(null),ft=$r(null),or=$r(""),[ct,Pe]=qe("quit"),vn=$r(void 0),P=$r(0),[H,ir]=qe(v?.cfg),go=v?.previousPersisted,[Hr,fr]=qe(void 0),yn=QC({tui:t,controller:v,resolveTuiOverridePath:u,terminalBackground:a,userTuiConfigPath:d,snap:re,setStatus:le,saveTuiPreferences:c,setPaletteIndex:U,setOverlay:B,setConfirmKind:Pe,setScreen:L,setSelected:se,screen:x}),{themeName:bn,setThemeName:vo,fontSize:sd,prefsLocked:ad,palette:ve,rootBackground:Mn,settingRows:yo,persistPrefs:Ba,persistTheme:bs,activateSetting:ld}=yn,ce=UC({controller:v,workspace:l,cfg:H,snap:re,screen:x,configReloadError:Hr,setSnap:pt,setStatus:le}),{google:vt,doctor:Et,doctorLoading:wn,doctorError:Wa,doctorProgress:ws,setDoctorTick:xs}=ce,og=t.keybinds.copy??kn(),bo=tg(()=>Object.keys(H?.services??{}).sort(),[H]),Nn=gn(async()=>{if(!v)return;try{let Q=await v.status();if(pt(Q),Q.profile&&at==="")Lt(Q.profile);return Q}catch(Q){le(I(Q));return}},[v,at]),cd=GC({controller:v,tui:t,names:bo,screen:x,refresh:Nn,setStatus:le}),{logs:ig,setLogs:e1,paused:sg,errorOnly:ud,setErrorOnly:dd,showSystemLogs:ag,logSearch:lg,setLogSearch:cg,logSearchFocused:t1,setLogSearchFocused:r1,logFollow:ug,logSince:n1,logService:dg,setLogService:pd,logServiceB:o1,setLogServiceB:i1,splitLogs:fd,splitFocus:md,setSplitFocus:s1,logSliceB:pg,logWindowB:fg,logSelectedB:mg,logPinnedB:a1,pinLogViewB:l1,logServices:c1,logShowTimestamps:u1,logShowMeta:d1,logSource:p1,logRegex:hg,logWrap:gg,logPinned:vg,logSelected:yg,logsFullscreen:hd,dashboardLogCursor:f1,setDashboardLogCursor:m1,logFacets:bg,logSources:wg,filteredLogs:xg,filteredLogsB:h1,logWindow:za,logSlice:qa,pinLogView:gd,applyLogCursorA:g1,applyLogCursorB:v1,jumpToLatestLogs:kg}=cd,pi=tg(()=>{if(X==="tasks")return Km(Object.keys(H?.tasks??{}),K,"tasks","run this task");if(X==="services")return Km(Object.keys(H?.services??{}),K,"services","exec in this service");return Lk(K,{services:Object.keys(H?.services??{}),tasks:Object.keys(H?.tasks??{})})},[H,K,X]);gH(()=>{ae(0)},[K]);let vd=rk(x,{doctor:Et?.checks.length??0,settings:yo.length,profiles:Object.keys(H?.profiles??{}).length,services:bo.length,logs:fd&&md===1?pg.length:qa.length,mcp:qS(),config:Object.keys(H?.tasks??{}).length}),Sg=x==="logs"?fd&&md===1?mg:yg:Ae,en=vd<=0?Math.max(0,Sg):Math.max(0,Math.min(Sg,vd-1)),y1=x==="detail"?Se:x==="services"?bo[en]??"":"",{inspectorEnv:Cg,inspectorEnvStatus:Tg,inspectorEnvError:Eg,resolveEnvironment:b1}=iT({controller:v,cfg:H,envService:y1}),yd=tg(()=>It?Pu(It.tree):[],[It]),w1=yd[Au(Tt,yd.length)]?.span,fi=gn(()=>{if(B("none"),V(""),te("commands"),r1(!1),vn.current)clearTimeout(vn.current)},[]),bd=gn((Q)=>{ue((ut)=>ut.includes(Q)?ut.filter((M1)=>M1!==Q):[...ut,Q])},[]),Rg=YC({tui:t,controller:v,cfg:H,persistPrefs:Ba,snap:re,refresh:Nn,setStatus:le}),{mcpPortDraft:x1,mcpPort:k1,toggleMcpTool:S1,toggleMcp:C1,copyMcpSnippet:T1}=Rg;NC({controller:v,cfg:H,paused:sg,logSince:n1,refresh:Nn,setLogs:e1,setCfg:ir,setConfigReloadError:fr,setStatus:le});let Ga=gn((Q)=>{St(Q),L("detail")},[]),wd=gn((Q)=>{if(Q===""||!v)return;v.getTrace(Q).then((ut)=>{ur(0),Ze(ut),B("trace")}).catch((ut)=>{le(I(ut))})},[v]),_g=gn((Q)=>{if(Q!==void 0)ur(Q);B("span-details")},[]),Pg=gn((Q)=>{let ut=Q.value!==""?Q.value:Q.required?"(required, not set)":"(empty)";nr({title:Q.key,body:ut}),B("scroll-text")},[]),xd=BC({controller:v,workspace:l,cfg:H,snap:re,refresh:Nn,setStatus:le,setOverlay:B}),{plan:Ka,planInitiallyRunning:E1,planBusy:R1,lifecycle:Ag}=xd,xn=rT({workspace:l,renderer:y,setOverlay:B,setStatus:le,setScreen:L,onAttached:o,setController:S,setCfg:ir,setBootError:_}),{configEditRef:_1,configEditText:P1,configEditError:A1,setConfigEditError:L1,openConfigBuffer:Lg,saveConfigBuffer:I1}=OC({cfg:H,readTextFile:m,setOverlay:B,setStatus:le,validateConfigText:f,writeTextFile:h,controller:v,setConfirmKind:Pe,refresh:Nn}),Ig=gn(async()=>{let Q=y.getSelection()?.getSelectedText()??"";if(Q.trim()===""){le("Nothing selected \u2014 drag to highlight text");return}try{await Ru(Q);let ut=Q.split(`
|
|
2502
|
+
`).length;le(ut===1?"Copied selection":`Copied ${ut} selected lines`)}catch(ut){le(I(ut))}},[y]),{runCommand:Va}=AC({setOverlay:B,setQuery:V,setSlashPicker:te,checked:z,setConfirmKind:Pe,setStatus:le,persistTheme:bs,setPaletteIndex:U,themeName:bn,setScreen:L,setSelected:se,screen:x,renderer:y,cfg:H,setScrollText:nr,reveal:gt,controller:v,refresh:Nn,profile:at,setReveal:Ct,resolveEnvironment:b1,openDetail:Ga,copySelection:Ig,lastExportPath:or,openConfigBuffer:Lg,onDown:n??((Q)=>r(Q)),workspace:l,logView:cd,diagnostics:ce,lifecycleActions:xd}),Dg=gn(()=>{let Q=os(pi,O);if(X==="tasks"){if(!Q){le(pi.length===0?"no tasks configured":"pick a task");return}te("commands");let ut=pn("run");if(ut)Va(ut,[Q.name]);return}if(X==="services"){if(!Q){le(pi.length===0?"no services configured":"pick a service");return}te("commands"),V(`exec ${Q.name} -- `);return}if(!Q){le(K.trim()===""?"pick a command from the list":`unknown command /${K}`),fi();return}Va(Q,Ak(Q,K))},[fi,pi,K,Va,O,X]),Og=gn((Q)=>{bs(Q),fi()},[fi,bs]);dC({tui:t,controller:v,cfg:H,snap:re,ui:{screen:x,overlay:F,onQuit:r,onDown:n??((Q)=>r(Q)),closeOverlay:fi,confirmKind:ct,confirmDetail:Oe,portTarget:Qe,profile:at,listCursor:en,names:bo,listCount:vd,openDetail:Ga,copySelection:Ig,height:k,paletteIndex:R,applyTheme:Og,runCommand:Va,saveConfigBuffer:I1,filtered:pi,slashIndex:O,submitSlash:Dg,advanceWizard:()=>void xn.advanceWizard(),bootErrorMissing:s,bootError:E,createStarterConfig:g,startWizard:xn.startWizard,toggleChecked:bd,checked:z,detailName:Se,refresh:Nn,openConfigBuffer:Lg,setOverlay:B,setConfirmKind:Pe,setConfirmDetail:Fe,setPortTarget:kt,setLogDetail:lt,logDetail:xr,openTrace:wd,openSpanLogs:_g,traceSpanCount:yd.length,setTraceSpanIndex:ur,setLogSearch:cg,setProfile:Lt,setStatus:le,setPaletteIndex:U,setSlashIndex:ae,setQuery:V,setSlashPicker:te,setScreen:L,setSelected:se,setChecked:ue,setConfigEditError:L1,freePort:p},logView:cd,lifecycleActions:xd,mcp:Rg,preferences:yn,diagnostics:ce,refs:{interruptArmedAt:P,leaderTimer:vn,logDetailsScrollRef:zt,traceScrollRef:de,traceDetailScrollRef:Z,scrollTextScrollRef:we,routeDetailsScrollRef:D,planScrollRef:ft,helpScrollRef:Sr,configScrollRef:kr,detailScrollRef:Cr}});let Mg=uk(ct,at,Oe),D1=new Set(Ka?.waves.flat()??[]),O1=Ka===void 0||Ag==="stop"?"":Object.entries(re?.services??{}).find(([Q,ut])=>D1.has(Q)&&ut.state==="FAILED")?.[0]??"";return me(Em.Provider,{value:ka(sd),children:me("box",{flexDirection:"column",width:b,height:k,backgroundColor:Mn,overflow:"hidden",children:[hd?null:me(vH,{children:[me(Zk,{palette:ve,cfg:H,snap:re,google:vt,profile:at,reveal:gt,width:b},void 0,!1,void 0,this),me(eS,{palette:ve,screen:x,width:b,onSelect:L},void 0,!1,void 0,this),Hr?me("box",{height:1,paddingLeft:1,backgroundColor:ve.panel,overflow:"hidden",children:me("text",{fg:ve.error,wrapMode:"none",children:`\u26A0 configuration reload failed: ${Hr}`},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),me("box",{flexGrow:1,overflow:"hidden",children:[x==="dashboard"?me(VT,{palette:ve,cfg:H,snap:re,logs:ig,names:bo,selected:en,checked:z,width:b,followTick:ug,logService:dg,errorOnly:ud,showSystemLogs:ag,onOpen:Ga,onSelectIndex:se,selectedLog:f1,onToggle:bd,logSources:wg,onFilterService:pd,onToggleErrors:()=>dd((Q)=>!Q),onShowErrors:()=>{pd(""),dd(!0)},wrapMode:gg,view:qa,follow:!vg,onLeaveLatest:gd,onPickLog:(Q)=>{let ut=qa[Q];if(!ut)return;m1(Q),lt(ut),gd()},viewStart:za.start,viewTotal:xg.length,newer:za.newer,onJumpLatest:kg,facets:bg,leftover:go,search:lg,regex:hg},void 0,!1,void 0,this):null,x==="services"?me(mE,{palette:ve,cfg:H,names:bo,snap:re,selected:en,checked:z,width:b,reveal:gt,onOpen:Ga,onSelectIndex:se,onToggle:bd,resolvedEnv:Cg,envStatus:Tg,envError:Eg,onSelectEnv:Pg},void 0,!1,void 0,this):null,x==="detail"?me(fE,{palette:ve,cfg:H,snap:re,name:Se,reveal:gt,width:b,envScrollRef:Cr,resolvedEnv:Cg,envStatus:Tg,envError:Eg,onSelectEnv:Pg},void 0,!1,void 0,this):null,x==="logs"?me(ZT,{palette:ve,logs:ig,names:bo,logSources:wg,service:dg,errorOnly:ud,showSystemLogs:ag,search:lg,searchFocused:t1,followTick:ug,width:b,onSearch:cg,onService:pd,onToggleErrors:()=>dd((Q)=>!Q),source:p1,regex:hg,services:c1,showTimestamps:u1,showMeta:d1,view:qa,wrapMode:gg,selected:yg,follow:!vg,newer:za.newer,viewStart:za.start,viewTotal:xg.length,onSelect:g1,fullscreen:hd,onLeaveLatest:gd,onJumpLatest:kg,facets:bg,split:fd,splitFocus:md,serviceB:o1,viewB:pg,selectedB:mg,followB:!a1,newerB:fg.newer,viewStartB:fg.start,viewTotalB:h1.length,onServiceB:i1,onSelectB:v1,onLeaveLatestB:l1,onFocusPane:s1},void 0,!1,void 0,this):null,x==="auth"?me(DT,{palette:ve,cfg:H,google:vt,identity:re?.identity},void 0,!1,void 0,this):null,x==="credentials"?me(UT,{palette:ve,credentials:re?.credentials},void 0,!1,void 0,this):null,x==="proxy"?me(cE,{palette:ve,cfg:H,snap:re,width:b,onSelectRoute:(Q)=>{Zr(Q),B("route-details")},onOpenTrace:wd},void 0,!1,void 0,this):null,x==="mcp"?me(GS,{palette:ve,snap:re,port:k1,portDraft:x1,selected:en,onPick:se,onToggle:()=>{C1()},onCopy:T1,onToggleTool:(Q)=>{S1(Q)}},void 0,!1,void 0,this):null,x==="doctor"?me(JT,{palette:ve,report:Et,loading:wn,progress:ws,error:Wa,selected:en,onPick:se,onReload:()=>{xs((Q)=>Q+1),le("Re-running doctor")}},void 0,!1,void 0,this):null,x==="stats"?me(SE,{palette:ve,cfg:H,snap:re,width:b,onRefresh:Nn},void 0,!1,void 0,this):null,x==="config"?me($T,{palette:ve,cfg:H,width:b,selectedTask:en,scrollRef:kr},void 0,!1,void 0,this):null,x==="profiles"?me(rE,{palette:ve,cfg:H,snap:re,profile:at,selected:en,onPick:se},void 0,!1,void 0,this):null,x==="setup"?me(wE,{issues:H?w(H):["configuration not loaded"],palette:ve,cfg:H,google:vt,bootError:E,bootErrorMissing:s,step:en},void 0,!1,void 0,this):null,x==="settings"?me(yE,{palette:ve,items:yo,selected:en,locked:ad,width:b,onPick:se,onActivate:ld},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),F==="slash"?me(ST,{palette:ve,items:pi,query:K,selected:O,title:X==="tasks"?"tasks":X==="services"?"services":"commands",onQuery:V,onSubmit:Dg},void 0,!1,void 0,this):null,F==="themes"?me(_T,{palette:ve,themeName:bn,selected:R%Pt.length,termW:b,termH:k,onIndex:U,onPreview:vo,onPick:Og},void 0,!1,void 0,this):null,F==="help"?me(JS,{palette:ve,termW:b,termH:k,copyKey:og,scrollRef:Sr},void 0,!1,void 0,this):null,F==="leader"?me(pT,{palette:ve,termW:b,termH:k},void 0,!1,void 0,this):null,F==="confirm"?me(cT,{palette:ve,title:Mg.title,body:Mg.body,kind:ct,termW:b,termH:k},void 0,!1,void 0,this):null,F==="setup-wizard"?me(eT,{palette:ve,termW:b,termH:k,step:xn.step,answers:xn.answers,repo:xn.repo,draft:xn.draft,authStatus:xn.authStatus,onDraft:xn.setDraft,onSubmit:()=>void xn.advanceWizard()},void 0,!1,void 0,this):null,F==="log-details"?me(mT,{palette:ve,event:xr,termW:b,termH:k,scrollRef:zt,onViewTrace:wd},void 0,!1,void 0,this):null,F==="trace"||F==="span-details"?me(AT,{palette:ve,trace:It?.tree,selected:Tt,onSelect:ur,onOpenLogs:_g,termW:b,termH:k,scrollRef:de},void 0,!1,void 0,this):null,F==="span-details"?me(LT,{palette:ve,span:w1,records:It?.events,termW:b,termH:k,scrollRef:Z},void 0,!1,void 0,this):null,F==="route-details"?me(bT,{palette:ve,route:dr,termW:b,termH:k,scrollRef:D},void 0,!1,void 0,this):null,F==="scroll-text"&&pr?me(xT,{palette:ve,title:pr.title,body:pr.body,termW:b,termH:k,scrollRef:we},void 0,!1,void 0,this):null,F==="config-edit"&&H?me(aT,{palette:ve,path:H.configPath,initialValue:P1,error:A1,termW:b,termH:k,textareaRef:_1},void 0,!1,void 0,this):null,F==="plan"&&Ka?me(vT,{palette:ve,plan:Ka,snap:re,busy:R1,failed:O1,kind:Ag,termW:b,termH:k,scrollRef:ft,initiallyRunning:E1,onDismiss:fi},void 0,!1,void 0,this):null,hd?null:me(tS,{palette:ve,screen:x,overlay:F,status:xt,paused:sg,errorOnly:ud,width:b,copyKey:og},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var EE=A(()=>{ne();cr();th();Ht();wr();si();so();Ut();Lu();pC();LC();MC();FC();jC();WC();KC();JC();ZC();nT();sT();lT();uT();_h();fT();hT();yT();wT();kT();Oh();CT();PT();IT();OT();HT();jT();YT();XT();eE();Oa();nE();uE();Xh();hE();bE();xE();CE();Mr();rt();Vr()});import{createCliRenderer as yH}from"@opentui/core";import{createRoot as bH}from"@opentui/react";import{jsxDEV as wH}from"@opentui/react/jsx-dev-runtime";async function RE(e,t){let r=e.loadTuiConfig(t.cfg.repoRoot,t.cfg.ui.keymap);await PE(e,t,r)}async function _E(e,t){let r,n,o=!1;try{r=await e.openTui("",t)}catch(s){n=I(s),o=Al(s,Po)}let i=e.loadTuiConfig(r?.cfg.repoRoot??process.cwd(),r?.cfg.ui.keymap);await PE(e,r,i,n,o)}async function PE(e,t,r=e.loadTuiConfig(t?.cfg.repoRoot??process.cwd(),t?.cfg.ui.keymap),n,o=!1){Ya();let i=$g(),s=await yH({exitOnCtrlC:!1,useMouse:r.mouse,enableMouseMovement:r.mouse,useKittyKeyboard:{}}),a=bH(s),l=null;try{l=(await s.getPalette({timeout:120,size:16})).defaultBackground}catch{}await new Promise((c)=>{let u=(f)=>{let p=()=>{a.unmount(),i(),s.destroy(),c(),process.exit(0)};if(!t){p();return}t.close({detach:f,shutdownSupervisor:!0}).finally(p)},d=(f)=>{let p=()=>{a.unmount(),i(),s.destroy(),c(),process.exit(0)};if(!t){p();return}t.shutdown({stopServices:!f}).then(()=>t?.close({detach:!0})).finally(p)};a.render(wH(TE,{workspace:m0(e),controller:t,tui:r,onQuit:u,onDown:d,onAttached:(f)=>{t=f},bootError:n,bootErrorMissing:o,terminalBackground:l},void 0,!1,void 0,this))})}var rg=A(()=>{h0();ne();EE()});if(process.env.METADATA_SERVER_DETECTION===void 0)process.env.METADATA_SERVER_DETECTION="bios-only";if(process.env.GCE_METADATA_TIMEOUT===void 0)process.env.GCE_METADATA_TIMEOUT="0";import{existsSync as ol,readFileSync as tl}from"fs";import{dirname as dR,isAbsolute as Vg,join as nl,resolve as pR}from"path";Ja();Ja();import{spawnSync as B1}from"child_process";import{randomBytes as Td}from"crypto";import{copyFileSync as W1,existsSync as Fn,mkdirSync as z1,readdirSync as q1,readFileSync as Ed,renameSync as Rd,statSync as G1,unlinkSync as Sd,writeFileSync as K1}from"fs";import{homedir as Hg}from"os";import{basename as V1,dirname as Cd,isAbsolute as Y1,join as Dt,resolve as J1}from"path";var X1=448,Q1=384;function ks(e,t){let r=e.startsWith("~/")?Dt(Hg(),e.slice(2)):e;return Y1(r)?r:J1(t,r)}function Er(){let e=process.env.DEVCTL_HOME;if(e&&e!=="")return e;return Dt(Hg(),".devctl")}function tn(e){z1(e,{recursive:!0,mode:X1})}function mi(e){let t=Dt(Er(),"state",Tr(e)),r=Dt(Er(),"sessions",Tr(e));if(!Fn(t)&&Fn(r)){tn(Cd(t));try{Rd(r,t)}catch{tn(t);for(let n of["state.json","devctl.lock","devctl.sock"]){let o=Dt(r,n);if(Fn(o))W1(o,Dt(t,n))}}}return tn(t),t}function Xa(){let e=Dt(Er(),"logs");return tn(e),e}function Qa(){let e=Dt(Er(),"exports");return tn(e),e}function Ur(){let e=Dt(Er(),"credentials");return tn(e),e}function Za(e,t=process.platform){if(t==="win32")return`\\\\.\\pipe\\devctl-${Tr(e)}`;return Dt(mi(e),"devctl.sock")}function Z1(e){return Dt(mi(e),"devctl.lock")}function Ug(e){return Dt(mi(e),"state.json")}function Ss(e){return Dt(mi(e),"bootstrap.log")}var eR=5,jg="bootstrap-";function Bg(e){let t=Ss(e);if(!Fn(t))return;let r=mi(e),n=Dt(r,`${jg}${_d()}.log`);try{Rd(t,n)}catch{return}tR(r)}function tR(e){let t;try{t=q1(e).filter((n)=>n.startsWith(jg)&&n.endsWith(".log"))}catch{return}let r=t.map((n)=>{let o=Dt(e,n);try{return{path:o,mtime:G1(o).mtimeMs}}catch{return}}).filter((n)=>n!==void 0).sort((n,o)=>o.mtime-n.mtime);for(let n=eR;n<r.length;n++)try{Sd(r[n].path)}catch{}}function jr(e,t){tn(Cd(e));let r=Dt(Cd(e),`.${V1(e)}.tmp-${process.pid}-${Td(4).toString("hex")}`);K1(r,t,{mode:Q1}),Rd(r,e)}function _d(e=new Date){return`${e.toISOString().slice(0,19).replace(/:/g,"-")+"Z"}-${Td(3).toString("hex")}`}function $n(e){return Pd(Ug(e))}function Pd(e){if(!Fn(e))return;try{let t=JSON.parse(Ed(e,"utf8"));if(Array.isArray(t.processes)&&typeof t.repo_root==="string")return t;return}catch{return}}function Wg(e,t){jr(Ug(e),`${JSON.stringify(t,null,2)}
|
|
2503
|
+
`)}function zg(e,t){let r=Z1(e);if(Fn(r)){let n=rR(r);if(n&&mr(n.pid))throw Error(`supervisor already running (pid ${n.pid})`);try{Sd(r)}catch{}}return jr(r,JSON.stringify({pid:process.pid,socket:t})),{release:()=>{try{Sd(r)}catch{}}}}function rR(e){if(!Fn(e))return;try{let t=JSON.parse(Ed(e,"utf8"));if(typeof t.pid==="number"&&typeof t.socket==="string")return{pid:t.pid,socket:t.socket}}catch{return}return}function mr(e){if(e<=0)return!1;if(process.platform==="win32")return nR(e);try{return process.kill(e,0),!0}catch{return!1}}function Ad(e){try{let t=B1("cmd.exe",["/d","/c",`tasklist /FO CSV /NH /FI "PID eq ${e}"`],{encoding:"buffer",windowsHide:!0,timeout:5000});return oR(t.stdout)}catch{return""}}function nR(e){try{return process.kill(e,0),!0}catch{}let t=Ad(e).toLowerCase();if(t===""||t.includes("no tasks")||t.includes("no matching"))return!1;return t.includes(String(e))}function oR(e){if(!e)return"";if(typeof e==="string")return e;if(e.length>=2&&e[0]===255&&e[1]===254)return e.toString("utf16le");if(e.length>=4&&e[1]===0&&e[3]===0)return e.toString("utf16le");return e.toString("utf8")}function Ld(){return Td(24).toString("hex")}function iR(e){return Dt(mi(e),"mcp-token")}function qg(e){let t=iR(e);if(Fn(t)){let n=Ed(t,"utf8").trim();if(n!=="")return n}let r=Ld();return jr(t,r),r}el();el();var fR="OPENCODE_TUI_CONFIG";function il(){return nl(Er(),"tui.json")}function sl(e=""){for(let t of[Gg,fR]){let r=process.env[t];if(!r||r==="")continue;let n=Vg(r)?r:pR(e||process.cwd(),r);if(ol(n))return n}return}function mR(e,t){if(!t||Object.keys(t).length===0)return e;return{...e,keybinds:{...e.keybinds,...t}}}function vi(e,t){let r=mR(Kg(),t),n=sl(e);if(n)return Od(r,rl(tl(n,"utf8")),n);let o=hR(e),i=o?Od(r,rl(tl(o,"utf8")),o):r,s=il();if(!ol(s)||o===s)return i;return Od(i,rl(tl(s,"utf8")),s)}function Yg(e){let t=il(),r={};if(ol(t)){let o=rl(tl(t,"utf8"));if(xo(o))r=o}let n={...r};if(e.theme!==void 0)n.theme=e.theme;if(e.mouse!==void 0)n.mouse=e.mouse;if(e.leader_timeout!==void 0)n.leader_timeout=e.leader_timeout;if(e.font_size!==void 0)n.font_size=e.font_size;if(e.log_timestamps!==void 0)n.log_timestamps=e.log_timestamps;if(e.log_metadata!==void 0)n.log_metadata=e.log_metadata;if(e.mcp_enabled!==void 0)n.mcp_enabled=e.mcp_enabled;if(e.mcp_port===null)delete n.mcp_port;else if(e.mcp_port!==void 0)n.mcp_port=e.mcp_port;if(e.mcp_disabled_tools!==void 0)n.mcp_disabled_tools=e.mcp_disabled_tools;return jr(t,`${JSON.stringify(n,null,2)}
|
|
2504
|
+
`),t}function hR(e){let t=sl(e);if(t)return t;let r=[e||process.cwd(),nl(e||process.cwd(),".devctl"),Er()],n=["tui.json","tui.jsonc"];for(let o of r)for(let i of n){let s=nl(o,i);if(ol(s))return s}return}function Od(e,t,r){let n=xo(t)?t:{},o={...e.keybinds};if(xo(n.keybinds)){for(let[l,c]of Object.entries(n.keybinds))if(typeof c==="string")o[l]=c}let i={...e.cursor};if(xo(n.cursor)){if(vR(n.cursor.style))i.style=n.cursor.style;if(typeof n.cursor.blinking==="boolean")i.blinking=n.cursor.blinking}let s={...e.scroll_acceleration};if(xo(n.scroll_acceleration)&&typeof n.scroll_acceleration.enabled==="boolean")s.enabled=n.scroll_acceleration.enabled;let a={...e.attention,sounds:{...e.attention.sounds}};if(xo(n.attention)){if(typeof n.attention.enabled==="boolean")a.enabled=n.attention.enabled;if(typeof n.attention.notifications==="boolean")a.notifications=n.attention.notifications;if(typeof n.attention.sound==="boolean")a.sound=n.attention.sound;if(typeof n.attention.volume==="number")a.volume=n.attention.volume;if(typeof n.attention.sound_pack==="string")a.sound_pack=n.attention.sound_pack;if(xo(n.attention.sounds)){for(let[l,c]of Object.entries(n.attention.sounds))if(typeof c==="string")a.sounds[l]=gR(c,r)}}return{theme:typeof n.theme==="string"?n.theme:e.theme,leader_timeout:typeof n.leader_timeout==="number"?n.leader_timeout:e.leader_timeout,font_size:typeof n.font_size==="number"&&Number.isFinite(n.font_size)?Math.round(n.font_size):e.font_size,keybinds:o,scroll_speed:typeof n.scroll_speed==="number"?n.scroll_speed:e.scroll_speed,scroll_acceleration:s,diff_style:n.diff_style==="stacked"?"stacked":"auto",cursor:i,mouse:typeof n.mouse==="boolean"?n.mouse:e.mouse,attention:a,log_timestamps:typeof n.log_timestamps==="boolean"?n.log_timestamps:e.log_timestamps,log_metadata:typeof n.log_metadata==="boolean"?n.log_metadata:e.log_metadata,mcp_enabled:typeof n.mcp_enabled==="boolean"?n.mcp_enabled:e.mcp_enabled,mcp_port:typeof n.mcp_port==="number"&&Number.isInteger(n.mcp_port)?n.mcp_port:e.mcp_port,mcp_disabled_tools:Array.isArray(n.mcp_disabled_tools)?n.mcp_disabled_tools.filter((l)=>typeof l==="string"):e.mcp_disabled_tools,path:r}}function gR(e,t){if(e.startsWith("file://")||Vg(e))return e;return nl(dR(t),e)}function vR(e){return e==="block"||e==="underline"||e==="line"||e==="default"}function xo(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function rl(e){let t=e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/^\s*\/\/.*$/gm,"");return JSON.parse(t)}import{existsSync as pI,readFileSync as fI,writeFileSync as mI}from"fs";import{spawn as fp}from"child_process";import{createWriteStream as T_,existsSync as _o,mkdirSync as E_,readdirSync as Ms,readFileSync as gp,rmSync as R_,statSync as hp,writeFileSync as Gv}from"fs";import{dirname as Kv,join as Cn}from"path";sn();sn();var __=50000,vp="session-",Vv="FORMAT",Yv="jsonl";function qv(e){return Buffer.from(JSON.stringify(e),"utf8").toString("base64url")}function P_(e){try{let t=JSON.parse(Buffer.from(e,"base64url").toString("utf8"));if(typeof t==="object"&&t!==null&&typeof t.session==="string"&&typeof t.seq==="number")return t}catch{}return}function mp(e,t){let r={...e};return r[t]=void 0,r}class yp{events=[];eventStart=0;nextSeq=1;recorded=0;errorCount=0;max;bus;detector;persistDir;persist;sessionID;streams=new Map;lastWrite=new Map;parsers=[];constructor(e,t,r,n,o,i,s=0,a=0){this.max=e>0?e:__,this.bus=t,this.detector=r,this.sessionID=i;let l=o===""||o.startsWith("~/")?Xa():o;if(this.persist=n&&i!=="",this.persistDir=this.persist?Cn(l,`${vp}${i}`):"",this.persist)E_(this.persistDir,{recursive:!0,mode:448}),Gv(Cn(this.persistDir,Vv),`${Yv}
|
|
2505
|
+
`,{mode:384}),F_(l,s,a)}sessionDir(){return this.persistDir}setParsers(e){this.parsers=e}append(e){let t=e.body!==void 0||e.source==="otlp",r=Nv(e.message??(typeof e.body==="string"?e.body:"")),n=t?A_(e):this.parseLine(r),o=tp(e,n,this.nextSeq);this.nextSeq+=1;let i=this.detector?xl(this.detector,o):o;if(this.recorded+=1,Si(i.severityNumber))this.errorCount+=1;if(this.events.length<this.max)this.events.push(i);else this.events[this.eventStart]=i,this.eventStart=(this.eventStart+1)%this.max;if(this.bus?.publish(Ce(yi,i.service,{event:i,level:i.severityText})),this.persist){let s=`${JSON.stringify(i)}
|
|
2506
|
+
`,a=N_(i.service),l=this.streamFor(a);this.lastWrite.set(a,new Promise((c)=>{l.write(s,()=>c())}))}return i}async flush(){await Promise.all([...this.lastWrite.values()])}parseLine(e){let t=ap(e);for(let r of this.parsers)try{let n=r.parse(e);if(n)t={...t,...n}}catch{}return t}streamFor(e){let t=this.streams.get(e);if(t===void 0)t=T_(Cn(this.persistDir,`${e}.jsonl`),{flags:"a",mode:384}),t.on("error",()=>{}),this.streams.set(e,t);return t}async close(){await this.flush(),await Promise.all([...this.streams.values()].map((e)=>new Promise((t)=>{e.end(()=>t())}))),this.streams.clear(),this.lastWrite.clear()}query(e){let t=pp(e),r=[];return this.forEachEvent((n)=>{if(t(n))r.push(n)}),r}queryPage(e,t={}){let r=Wv(t.limit),n=t.cursor?P_(t.cursor):void 0,o=n!==void 0&&n.session!==this.sessionID,i=o?void 0:n,s=i?t.direction??"backward":"backward",a=pp(e),l=[];this.forEachEvent((m)=>{if(a(m))l.push(m)});let c;if(!i)c=l.slice(Math.max(0,l.length-r));else if(s==="forward")c=l.filter((m)=>m.seq>i.seq).slice(0,r);else{let m=l.filter((h)=>h.seq<i.seq);c=m.slice(Math.max(0,m.length-r))}let u=c[0]?.seq,d=c[c.length-1]?.seq,f=u!==void 0&&l.some((m)=>m.seq<u),p=d!==void 0&&l.some((m)=>m.seq>d);return{events:c,prevCursor:qv({session:this.sessionID,seq:u??i?.seq??0}),nextCursor:qv({session:this.sessionID,seq:d??i?.seq??this.nextSeq-1}),hasNext:p,hasPrev:f,sessionChanged:o}}queryFacets(e){let t=mp(e,"services"),r=mp(e,"level"),n=mp(e,"source"),o=dp(e),i=0,s={},a={},l={};return this.forEachEvent((c)=>{if(!o(c))return;if(_i(e,c))i+=1;if(_i(t,c))s[c.service]=(s[c.service]??0)+1;if(_i(r,c))a[c.severityText]=(a[c.severityText]??0)+1;if(_i(n,c))l[c.source]=(l[c.source]??0)+1}),{total:i,byService:s,byLevel:a,bySource:l}}snapshot(){let e={},t=0;return this.forEachEvent((r)=>{if(e[r.service]=(e[r.service]??0)+1,Si(r.severityNumber))t+=1}),{total:this.events.length,errors:t,counts:e,seen:this.recorded,seenErrors:this.errorCount}}forEachEvent(e){let t=this.events.length;for(let r=0;r<t;r+=1){let n=this.events[(this.eventStart+r)%t];if(n)e(n)}}exportTo(e,t){bp(e,this.query(t))}}function A_(e){return{body:e.body,attributes:e.attributes,severityNumber:e.severityNumber,severityText:e.severityText??e.level,traceId:e.traceId,spanId:e.spanId,traceFlags:e.traceFlags,timeUnixNano:e.timeUnixNano,observedTimeUnixNano:e.observedTimeUnixNano,scope:e.scope,resource:e.resource,raw:e.raw,message:e.message,request_id:e.request_id}}function Jv(e){return{append:(t)=>{e.append(t)},query:async(t)=>e.query(t),queryPage:async(t,r)=>e.queryPage(t,r),queryFacets:async(t)=>e.queryFacets(t),snapshot:()=>e.snapshot(),exportTo:async(t,r)=>{e.exportTo(t,r)},setParsers:(t)=>{e.setParsers(t)},setSecrets:(t,r)=>{},close:()=>e.close()}}function L_(e=new Date){let t=e.toISOString().replace(/[:.]/g,"-");return Cn(Qa(),`devctl-logs-${t}.jsonl`)}function Xv(e=""){if(e==="")return L_();return ks(e,process.cwd())}function bp(e,t){tn(Kv(e));let r=t.map((n)=>JSON.stringify(n));Gv(e,`${r.join(`
|
|
2501
2507
|
`)}
|
|
2502
|
-
`,{mode:384})}function
|
|
2503
|
-
`)){if(o.trim()==="")continue;let i=
|
|
2504
|
-
`)){if(i.trim()==="")continue;let s=i.split(" "),a=s.slice(3).join(" "),l=lp(a);t.push(tp({timestamp:s[0]??"",service:s[1]??n.replace(/\.log$/,""),source:"history",pid:0,level:s[2]??"INFO",message:a},l??{body:a,raw:a},0))}}let r=t.sort((n,o)=>n.timestamp.localeCompare(o.timestamp));return r.forEach((n,o)=>{n.seq=o+1}),r}function
|
|
2505
|
-
`).filter((n)=>n.trim()!==""&&!n.startsWith("COMMAND"));for(let n of r){let o=n.trim().split(/\s+/),i=o[0]??"",s=Number(o[1]);if(i!==""&&Number.isInteger(s)&&s>0)return{port:t,pid:s,command:i}}return}async function Lo(e){if(process.platform==="win32")return
|
|
2506
|
-
`)){if(!r.includes("LISTENING")&&!r.includes("LISTEN"))continue;if(!r.includes(`:${t}`)&&!r.includes(` ${t} `))continue;let n=r.trim().match(/(\d+)\s*$/),o=n?Number(n[1]):0;if(Number.isInteger(o)&&o>0)return{port:t,pid:o,command:"process"}}return}async function z_(e){let t=kp({cmd:["netstat","-ano"],stdout:"pipe",stderr:"ignore"}),r=t.stdout?await new Response(t.stdout).text():"";return await t.exited,W_(r,e)}var q_=400;async function Il(e){if(e.pid===process.pid)throw Ie(Ge,`port ${e.port} is held by this TUI`,"stop the proxy from the proxy screen, or quit the TUI");try{process.kill(e.pid,"SIGTERM")}catch(t){throw ge(Ge,`could not stop pid ${e.pid} on port ${e.port}`,t)}await G_(q_);try{process.kill(e.pid,0),process.kill(e.pid,"SIGKILL")}catch{return}}function G_(e){return new Promise((t)=>{setTimeout(t,e)})}zl();ne();import{readdirSync as cA,readFileSync as uA}from"fs";import{basename as Sb,dirname as dA,extname as pA,join as Ho,resolve as fA}from"path";import{parse as mA}from"yaml";Ke();function M(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Dp(e){return M(e)?new Set(Object.keys(e)):new Set}function q(e){if(typeof e==="string")return e;if(typeof e==="number"||typeof e==="boolean")return String(e);return""}function Te(e){if(typeof e==="number")return e;if(typeof e==="string"){let t=Number(e);return Number.isNaN(t)?0:t}return 0}function tt(e){return e===!0}function Ot(e){if(!Array.isArray(e))return[];return e.map((t)=>q(t))}function Op(e){if(!Array.isArray(e))return[];return e.map((t)=>M(t)?{service:q(t.service),condition:q(t.condition)||"service_started"}:q(t))}function an(e){if(!M(e))return{};let t={};for(let[r,n]of Object.entries(e))t[r]=q(n);return t}function qr(e){if(typeof e==="string")return{args:e.split(/\s+/).filter((t)=>t!==""),shell:!1};if(Array.isArray(e))return{args:e.map((t)=>q(t)),shell:!1};return Li()}function Mp(e){if(e===void 0||e===null)return[];if(typeof e==="string"||typeof e==="number")return[Ip(e,"http")];if(Array.isArray(e))return e.map((t,r)=>Ip(t,`port_${r}`));if(M(e))return Object.entries(e).map(([t,r])=>Ip(r,t));return[]}function Ip(e,t){if(typeof e==="string"&&e.toLowerCase()==="auto")return{name:t,value:0,auto:!0};return{name:t,value:Te(e),auto:!1}}function yy(e){if(!M(e))return Tp();let t={},r=[],n={};for(let[o,i]of Object.entries(e))if(o==="required")r=Ot(i);else if(o==="defaults")n=an(i);else t[o]=q(i);return{vars:t,required:r,defaults:n}}function oP(e){if(!M(e))return Rp();return{type:q(e.type),mode:q(e.mode),service_account:q(e.service_account),config:M(e.config)?{...e.config}:{}}}function iP(e){if(!M(e))return Ep();return{type:q(e.type),url:q(e.url),address:q(e.address),command:qr(e.command),interval_seconds:Te(e.interval_seconds),timeout_seconds:Te(e.timeout_seconds),start_period_seconds:Te(e.start_period_seconds),unhealthy_threshold:e.unhealthy_threshold===void 0?3:Te(e.unhealthy_threshold),healthy_reset_threshold:e.healthy_reset_threshold===void 0?10:Te(e.healthy_reset_threshold)}}function sP(e){if(!M(e))return{policy:"",max_retries:0,backoff_seconds:0};return{enabled:e.enabled===void 0?void 0:tt(e.enabled),policy:q(e.policy),max_retries:Te(e.max_retries),backoff_seconds:Te(e.backoff_seconds)}}function aP(e){if(!M(e))return{wait_for_healthy:!1,timeout_seconds:0};return{wait_for_healthy:tt(e.wait_for_healthy),timeout_seconds:Te(e.timeout_seconds)}}function Us(e){if(!M(e))return qn();let t=M(e.logs)?e.logs:{};return{extends:q(e.extends),description:q(e.description),command:qr(e.command),shell:tt(e.shell),working_dir:q(e.working_dir),dependencies:Op(e.dependencies),ports:Mp(e.ports),environment:yy(e.environment),health:iP(e.health),identity:oP(e.identity),logs:{stdout:tt(t.stdout),stderr:tt(t.stderr)},restart:sP(e.restart),startup:aP(e.startup),capabilities:Ot(e.capabilities),proxy:$p(e.proxy),expose:Fp(e.expose),container:Np(e.container),watch:lP(e.watch),hooks:cP(e.hooks)}}function lP(e){if(!M(e))return Sp();return{enabled:tt(e.enabled),paths:Ot(e.paths),debounce_ms:Nl(Te(e.debounce_ms)),ignore:e.ignore===void 0?[...Ns]:Ot(e.ignore)}}function cP(e){let t=M(e)?e:{};return{pre_start:qr(t.pre_start),post_start:qr(t.post_start)}}function by(e){let t=M(e)?e:{};return{command:qr(t.command),shell:tt(t.shell),working_dir:q(t.working_dir),dependencies:Ot(t.dependencies),environment:yy(t.environment)}}function Np(e){if(!M(e))return;let t={};if(M(e.ports))for(let[r,n]of Object.entries(e.ports))t[r]=Te(n);return{image:q(e.image),runtime:q(e.runtime),ports:t,env:an(e.env),volumes:Ot(e.volumes)}}function Fp(e){if(e===!0)return{enabled:!0,host:"",port:""};if(e===!1)return{enabled:!1,host:"",port:""};if(M(e))return{enabled:e.enabled!==void 0?tt(e.enabled):!0,host:q(e.host),port:q(e.port)};return Cp()}function $p(e){if(e===void 0||e===null)return[];if(Array.isArray(e))return e.map((t)=>Oo(t));if(M(e))return[Oo(e)];return[]}function ql(e){if(!M(e))return{services:[],environment:{}};return{services:Ot(e.services),environment:an(e.environment)}}function uP(e){if(typeof e==="string")return{type:e,service_account:""};if(!M(e))return{type:"",service_account:""};return{type:q(e.type),service_account:q(e.service_account)}}function dP(e){if(!M(e))return Fs();return{type:q(e.type),identity:uP(e.identity),audience:q(e.audience),service_account:q(e.service_account),client_id:q(e.client_id),client_secret:q(e.client_secret),credentials:q(e.credentials),headers:an(e.headers)}}function Oo(e){if(!M(e))return{name:"",match:{host:"",path:""},upstream:{url:""},auth:Fs()};let t=M(e.match)?e.match:{},r=M(e.upstream)?e.upstream:{};return{name:q(e.name),transport:q(e.transport),match:{host:q(t.host),path:q(t.path)},upstream:{url:q(r.url),service:q(r.service),port:q(r.port)},auth:dP(e.auth),response_headers:an(e.response_headers),listen:M(e.listen)?{host:q(e.listen.host),port:Te(e.listen.port)}:void 0}}ne();import{existsSync as pP,statSync as xy}from"fs";import{basename as wy,dirname as Gl,isAbsolute as fP,join as Kl,resolve as ky}from"path";function Mo(e,t){if(t!=="")return mP(t);let r=e===""?process.cwd():e;r=fP(r)?r:ky(r);for(;;){let n=Kl(r,Yt,_r);if(js(n))return{repoRoot:r,configPath:n};let o=Kl(r,"devctl.yaml");if(js(o))return{repoRoot:r,configPath:o};let i=Gl(r);if(i===r)break;r=i}throw Ie(Po,"no devctl configuration found","run `devctl setup` or create a .devctl/config.yaml in the repository root")}function mP(e){let t=ky(e),r;try{r=xy(t)}catch(o){throw ge(Po,"config path not found",o)}if(r.isDirectory()){if(wy(t)===Yt)return{repoRoot:Gl(t),configPath:Kl(t,_r)};return{repoRoot:t,configPath:Kl(t,_r)}}let n=Gl(t);if(wy(n)===Yt)n=Gl(n);return{repoRoot:n,configPath:t}}function js(e){return pP(e)&&!xy(e).isDirectory()}Ke();function Jl(){return{services:{},templates:{},provenance:{}}}function Rn(e,t,r,n,o=""){if(M(t)&&Object.keys(t).length>0){for(let[i,s]of Object.entries(t))Rn(e,s,r,n,o===""?i:`${o}.${i}`);return}if(o==="")return;(e[o]??=[]).push({source:r,layer:n})}var hP=["environment","restart","startup","health","logs","identity","container","watch","hooks"];function Vl(e,t,r){let n=Dp(r);if(M(r))for(let i of hP){let s=r[i];if(M(s))for(let a of Object.keys(s))n.add(`${i}.${a}`)}let o=e[t];e[t]=o?new Set([...o,...n]):n}function Sy(e,t,r=Jl(),n={source:"unknown",layer:"unknown"}){if(Rn(r.provenance,t,n.source,n.layer),t.version!==void 0)e.version=Te(t.version);if(M(t.project)&&t.project.name!==void 0)e.project.name=q(t.project.name);if(M(t.google)){if(t.google.project_id!==void 0)e.google.project_id=q(t.google.project_id);if(t.google.region!==void 0)e.google.region=q(t.google.region)}if(M(t.profiles))for(let[o,i]of Object.entries(t.profiles)){let s=e.profiles[o];e.profiles[o]=s?yP(s,i):ql(i)}if(M(t.templates))for(let[o,i]of Object.entries(t.templates)){let s=e.templates[o];e.templates[o]=s?Yl(s,i):Us(i),Vl(r.templates,o,i)}if(M(t.services))for(let[o,i]of Object.entries(t.services)){let s=e.services[o];e.services[o]=s?Yl(s,i):Us(i),Vl(r.services,o,i)}if(M(t.tasks))for(let[o,i]of Object.entries(t.tasks))e.tasks[o]=e.tasks[o]?bP(e.tasks[o],i):by(i);if(M(t.proxy))Hp(e.proxy,t.proxy);if(M(t.logs)){if(t.logs.max_memory_events!==void 0)e.logs.max_memory_events=Te(t.logs.max_memory_events);if(M(t.logs.persistence)){let o=t.logs.persistence;if(o.enabled!==void 0)e.logs.persistence.enabled=tt(o.enabled);if(o.directory!==void 0)e.logs.persistence.directory=q(o.directory);if(o.retention_days!==void 0)e.logs.persistence.retention_days=Te(o.retention_days);if(o.max_session_logs!==void 0)e.logs.persistence.max_session_logs=Te(o.max_session_logs)}}if(M(t.auth)&&t.auth.refresh_threshold_seconds!==void 0)e.auth.refresh_threshold_seconds=Te(t.auth.refresh_threshold_seconds);if(M(t.shutdown)){if(t.shutdown.stop_services_on_exit!==void 0)e.shutdown.stop_services_on_exit=tt(t.shutdown.stop_services_on_exit);if(t.shutdown.grace_seconds!==void 0)e.shutdown.grace_seconds=Te(t.shutdown.grace_seconds)}if(M(t.ui)){if(t.ui.theme!==void 0)e.ui.theme=q(t.ui.theme);if(t.ui.keymap!==void 0)e.ui.keymap=an(t.ui.keymap)}if(M(t.secrets)){if(t.secrets.extra_markers!==void 0)e.secrets.extra_markers=Ot(t.secrets.extra_markers);if(t.secrets.extra_patterns!==void 0)e.secrets.extra_patterns=Ot(t.secrets.extra_patterns)}if(M(t.doctor)&&Array.isArray(t.doctor.tools))e.doctor.tools=t.doctor.tools.filter(M).map((o)=>({name:q(o.name),command:q(o.command)}));if(Array.isArray(t.plugins))e.plugins=t.plugins.filter(M).map((o)=>({path:q(o.path)})).filter((o)=>o.path!=="");if(M(t.environment)){if(Array.isArray(t.environment.sources))e.environment.sources=Ot(t.environment.sources);if(M(t.environment.secrets))e.environment.secrets={...e.environment.secrets,...an(t.environment.secrets)}}if(M(t.telemetry))gP(e.telemetry,t.telemetry);if(M(t.web))vP(e.web,t.web)}function gP(e,t){if(!M(t.otlp))return;let r=t.otlp;if(r.enabled!==void 0)e.otlp.enabled=tt(r.enabled);if(M(r.listen)){if(r.listen.host!==void 0)e.otlp.listen.host=q(r.listen.host);if(r.listen.port!==void 0)e.otlp.listen.port=Te(r.listen.port)}}function vP(e,t){if(t.enabled!==void 0)e.enabled=tt(t.enabled);if(M(t.listen)){if(t.listen.host!==void 0)e.listen.host=q(t.listen.host);if(t.listen.port!==void 0)e.listen.port=Te(t.listen.port)}}function Hp(e,t){if(t.enabled!==void 0)e.enabled=tt(t.enabled);if(t.gateway!==void 0)e.gateway=tt(t.gateway);if(t.credentials!==void 0)e.credentials=q(t.credentials);if(M(t.listen)){if(t.listen.host!==void 0)e.listen.host=q(t.listen.host);if(t.listen.port!==void 0)e.listen.port=Te(t.listen.port)}if(M(t.token_endpoint)){let r=t.token_endpoint;if(r.enabled!==void 0)e.token_endpoint.enabled=tt(r.enabled);if(r.host!==void 0)e.token_endpoint.host=q(r.host);if(r.port!==void 0)e.token_endpoint.port=Te(r.port)}if(Array.isArray(t.routes))e.routes=t.routes.map((r)=>Oo(r))}function yP(e,t){if(!M(t))return e;return{services:t.services!==void 0?Ot(t.services):e.services,environment:t.environment!==void 0?{...e.environment,...an(t.environment)}:e.environment}}function bP(e,t){if(!M(t))return e;return{command:t.command!==void 0?qr(t.command):e.command,shell:t.shell!==void 0?tt(t.shell):e.shell,working_dir:t.working_dir!==void 0?q(t.working_dir):e.working_dir,dependencies:t.dependencies!==void 0?Ot(t.dependencies):e.dependencies,environment:Cy(e.environment,t.environment)}}function Yl(e,t){if(!M(t))return e;let r=Dp(t),n={...e,environment:Cy(e.environment,t.environment),health:kP(e.health,t.health),identity:SP(e.identity,t.identity),logs:CP(e.logs,t.logs),restart:TP(e.restart,t.restart),startup:EP(e.startup,t.startup),container:RP(e.container,t.container),watch:wP(e.watch,t.watch),hooks:xP(e.hooks,t.hooks)};if(r.has("extends"))n.extends=q(t.extends);if(r.has("description"))n.description=q(t.description);if(r.has("command"))n.command=qr(t.command);if(r.has("shell"))n.shell=tt(t.shell);if(r.has("working_dir"))n.working_dir=q(t.working_dir);if(r.has("dependencies"))n.dependencies=Op(t.dependencies);if(r.has("ports"))n.ports=Mp(t.ports);if(r.has("capabilities"))n.capabilities=Ot(t.capabilities);if(r.has("proxy"))n.proxy=$p(t.proxy);if(r.has("expose"))n.expose=Fp(t.expose);return n}function wP(e,t){if(!M(t))return e;return{enabled:t.enabled!==void 0?tt(t.enabled):e.enabled,paths:t.paths!==void 0?Ot(t.paths):e.paths,debounce_ms:t.debounce_ms!==void 0?Nl(Te(t.debounce_ms)):e.debounce_ms,ignore:t.ignore!==void 0?Ot(t.ignore):e.ignore}}function xP(e,t){if(!M(t))return e;return{pre_start:t.pre_start!==void 0?qr(t.pre_start):e.pre_start,post_start:t.post_start!==void 0?qr(t.post_start):e.post_start}}function Cy(e,t){if(!M(t))return e;let r={...e.vars},n={...e.defaults},o=e.required;for(let[i,s]of Object.entries(t))if(i==="required")o=Ot(s);else if(i==="defaults")Object.assign(n,an(s));else r[i]=q(s);return{vars:r,required:o,defaults:n}}function kP(e,t){if(!M(t))return e;return{type:t.type!==void 0?q(t.type):e.type,url:t.url!==void 0?q(t.url):e.url,address:t.address!==void 0?q(t.address):e.address,command:t.command!==void 0?qr(t.command):e.command,interval_seconds:t.interval_seconds!==void 0?Te(t.interval_seconds):e.interval_seconds,timeout_seconds:t.timeout_seconds!==void 0?Te(t.timeout_seconds):e.timeout_seconds,start_period_seconds:t.start_period_seconds!==void 0?Te(t.start_period_seconds):e.start_period_seconds,unhealthy_threshold:t.unhealthy_threshold!==void 0?Te(t.unhealthy_threshold):e.unhealthy_threshold,healthy_reset_threshold:t.healthy_reset_threshold!==void 0?Te(t.healthy_reset_threshold):e.healthy_reset_threshold}}function SP(e,t){if(!M(t))return e;return{type:t.type!==void 0?q(t.type):e.type,mode:t.mode!==void 0?q(t.mode):e.mode,service_account:t.service_account!==void 0?q(t.service_account):e.service_account,config:t.config!==void 0&&M(t.config)?{...e.config??{},...t.config}:e.config}}function CP(e,t){if(!M(t))return e;return{stdout:t.stdout!==void 0?tt(t.stdout):e.stdout,stderr:t.stderr!==void 0?tt(t.stderr):e.stderr}}function TP(e,t){if(!M(t))return e;return{enabled:t.enabled!==void 0?tt(t.enabled):e.enabled,policy:t.policy!==void 0?q(t.policy):e.policy,max_retries:t.max_retries!==void 0?Te(t.max_retries):e.max_retries,backoff_seconds:t.backoff_seconds!==void 0?Te(t.backoff_seconds):e.backoff_seconds}}function EP(e,t){if(!M(t))return e;return{wait_for_healthy:t.wait_for_healthy!==void 0?tt(t.wait_for_healthy):e.wait_for_healthy,timeout_seconds:t.timeout_seconds!==void 0?Te(t.timeout_seconds):e.timeout_seconds}}function RP(e,t){if(!M(t))return e;let r=Np(t);if(!r)return e;return{image:t.image!==void 0?r.image:e?.image??"",runtime:t.runtime!==void 0?r.runtime:e?.runtime??"",ports:t.ports!==void 0?{...e?.ports??{},...r.ports}:e?.ports??{},env:t.env!==void 0?{...e?.env??{},...r.env}:e?.env??{},volumes:t.volumes!==void 0?r.volumes:e?.volumes??[]}}function Ty(e,t){let r=Object.keys(e.services).sort();for(let n of r){let o=e.services[n]?.proxy??[];if(o.length===0)continue;o.forEach((i,s)=>{let l={name:o.length===1?n:`${n}-${s+1}`,match:i.match,upstream:i.upstream,auth:i.auth},c=e.proxy.routes.length;if(e.proxy.routes.push(l),t)Rn(t,l,`synthesized from services.${n}.proxy`,"synthesized",`proxy.routes.${c}`)})}_P(e,t)}function Ey(e){let t=e.repoRoot||process.cwd(),r=e.proxy.credentials.trim()===""?"":ks(e.proxy.credentials.trim(),t);e.proxy.credentials=r;for(let n of e.proxy.routes){if(n.auth.client_id.trim()==="")continue;let o=(n.auth.credentials??"").trim();n.auth.credentials=o===""?r:ks(o,t)}}function _P(e,t){if(!e.proxy.enabled)return;let r=new Set(e.proxy.routes.map((n)=>n.name));for(let n of Object.keys(e.services).sort()){let o=e.services[n];if(!o)continue;if(!(o.expose.enabled!==!1&&(o.expose.enabled===!0||e.proxy.gateway&&Do(o.ports,"http")!==void 0))||r.has(n))continue;let a={name:n,match:{host:o.expose.host||`${n}.local`,path:""},upstream:{url:"",service:n,port:o.expose.port||"http"},auth:Fs()},l=e.proxy.routes.length;if(e.proxy.routes.push(a),r.add(n),t){let c=o.expose.enabled===!0?`services.${n}.expose`:"proxy.gateway";Rn(t,a,`synthesized from ${c}`,"synthesized",`proxy.routes.${l}`)}}}function Ry(e,t=Jl()){if(Object.keys(e.templates).length===0)return;let r={};for(let[n,o]of Object.entries(e.services))r[n]=_y(e,o,t.services[n]??new Set,t,{});e.services=r}function _y(e,t,r,n,o){if(t.extends==="")return t;if(o[t.extends])throw Error(`template cycle involving "${t.extends}"`);let i=e.templates[t.extends]??qn();if(!e.templates[t.extends])throw Error(`service extends unknown template "${t.extends}"`);let s={...o,[t.extends]:!0},a=n.templates[t.extends]??new Set,l=_y(e,i,a,n,s),c=PP(l,t,r);return c.extends=t.extends,c}function PP(e,t,r){let n={...e};if(r.has("extends"))n.extends=t.extends;if(r.has("description"))n.description=t.description;if(r.has("command"))n.command=t.command;if(r.has("shell"))n.shell=t.shell;if(r.has("working_dir"))n.working_dir=t.working_dir;if(r.has("dependencies"))n.dependencies=t.dependencies;if(r.has("ports"))n.ports=t.ports;if(r.has("capabilities"))n.capabilities=t.capabilities;if(r.has("proxy"))n.proxy=t.proxy;if(r.has("container")){let o=t.container,i=e.container;n.container=o&&i?{image:r.has("container.image")?o.image:i.image,runtime:r.has("container.runtime")?o.runtime:i.runtime,ports:r.has("container.ports")?o.ports:i.ports,env:r.has("container.env")?o.env:i.env,volumes:r.has("container.volumes")?o.volumes:i.volumes}:o??i}if(r.has("watch"))n.watch=t.watch;return n.hooks={pre_start:r.has("hooks.pre_start")?t.hooks.pre_start:e.hooks.pre_start,post_start:r.has("hooks.post_start")?t.hooks.post_start:e.hooks.post_start},n.health={type:r.has("health.type")?t.health.type:e.health.type,url:r.has("health.url")?t.health.url:e.health.url,address:r.has("health.address")?t.health.address:e.health.address,command:r.has("health.command")?t.health.command:e.health.command,interval_seconds:r.has("health.interval_seconds")?t.health.interval_seconds:e.health.interval_seconds,timeout_seconds:r.has("health.timeout_seconds")?t.health.timeout_seconds:e.health.timeout_seconds,start_period_seconds:r.has("health.start_period_seconds")?t.health.start_period_seconds:e.health.start_period_seconds,unhealthy_threshold:r.has("health.unhealthy_threshold")?t.health.unhealthy_threshold:e.health.unhealthy_threshold,healthy_reset_threshold:r.has("health.healthy_reset_threshold")?t.health.healthy_reset_threshold:e.health.healthy_reset_threshold},n.identity={type:r.has("identity.type")?t.identity.type:e.identity.type,mode:r.has("identity.mode")?t.identity.mode:e.identity.mode,service_account:r.has("identity.service_account")?t.identity.service_account:e.identity.service_account,config:r.has("identity.config")?t.identity.config:e.identity.config},n.logs={stdout:r.has("logs.stdout")?t.logs.stdout:e.logs.stdout,stderr:r.has("logs.stderr")?t.logs.stderr:e.logs.stderr},n.restart={enabled:r.has("restart.enabled")?t.restart.enabled:e.restart.enabled,policy:r.has("restart.policy")?t.restart.policy:e.restart.policy,max_retries:r.has("restart.max_retries")?t.restart.max_retries:e.restart.max_retries,backoff_seconds:r.has("restart.backoff_seconds")?t.restart.backoff_seconds:e.restart.backoff_seconds},n.startup={wait_for_healthy:r.has("startup.wait_for_healthy")?t.startup.wait_for_healthy:e.startup.wait_for_healthy,timeout_seconds:r.has("startup.timeout_seconds")?t.startup.timeout_seconds:e.startup.timeout_seconds},n.environment={vars:{...e.environment.vars,...t.environment.vars},defaults:{...e.environment.defaults,...t.environment.defaults},required:r.has("environment.required")?t.environment.required:e.environment.required},n}ne();Ke();function Py(e){if(e.version===0)throw T(ee,"version is required");if(e.version===Ii)return e;throw T(ee,`unsupported config version ${e.version} (expected ${Ii}); no migration is available`)}var Ay=["version","project","google","profiles","templates","services","tasks","proxy","logs","auth","shutdown","ui","secrets","doctor","plugins","environment","telemetry","web"],Ly=["extends","description","command","shell","working_dir","dependencies","ports","environment","health","identity","logs","restart","startup","capabilities","proxy","expose","container","watch","hooks"],Iy=["type","url","address","command","interval_seconds","timeout_seconds","start_period_seconds","unhealthy_threshold","healthy_reset_threshold"],Dy=["service","condition"],Oy=["type","mode","service_account","config"],My=["enabled","policy","max_retries","backoff_seconds"],Ny=["wait_for_healthy","timeout_seconds"],Fy=["enabled","host","port"],$y=["enabled","gateway","credentials","listen","token_endpoint","routes"],Di=["host","port"],Up=["name","transport","listen","match","upstream","auth","response_headers"],jp=["host","path"],Bp=["url","service","port"],Wp=["type","identity","audience","service_account","client_id","client_secret","credentials","headers"],Hy=["max_memory_events","persistence"],Uy=["enabled","directory","retention_days","max_session_logs"],jy=["refresh_threshold_seconds"],By=["stop_services_on_exit","grace_seconds"],Wy=["theme","keymap"],zy=["name"],qy=["project_id","region"],Gy=["services","environment"],zp=["required","defaults"],Ky=["stdout","stderr"],Vy=["extra_markers","extra_patterns"],Yy=["tools"],Jy=["name","command"],Xy=["enabled","host","port"],Qy=["path"],Zy=["sources","secrets"],eb=["image","runtime","ports","env","volumes"],tb=["enabled","paths","debounce_ms","ignore"],rb=["pre_start","post_start"],nb=["command","shell","working_dir","dependencies","environment"],ob=["otlp"],ib=["enabled","listen"],sb=["enabled","listen"],ab=["google","google_api","iap","network","service_identity","local_http"],lb=["|","||","&&",";",">",">>","<","&"];var AP=2;function Jn(e,t){if(Array.isArray(e))return e.flatMap((o,i)=>Jn(o,cb(t,String(i))));if(!FP(e))return[];let r=IP(t),n=[];for(let o of Object.keys(e)){let i=cb(t,o);if(r.length>0&&!r.includes(o)&&!LP(t))n.push(i);n.push(...Jn(e[o],i))}return n}function LP(e){if(e==="services"||e==="profiles"||e==="templates"||e==="tasks")return!0;if(e.endsWith(".environment")||e.endsWith(".defaults")||e.endsWith(".keymap"))return!0;if(e.endsWith(".container.ports")||e.endsWith(".container.env"))return!0;if(e.endsWith(".auth.headers")||e.endsWith(".response_headers"))return!0;if(e.endsWith(".identity.config")||e.includes(".identity.config."))return!0;return e.includes(".environment.")&&!e.endsWith(".environment")}function IP(e){switch(e){case"":return Ay;case"project":return zy;case"google":return qy;case"proxy":return $y;case"proxy.listen":return Di;case"proxy.token_endpoint":return Xy;case"logs":return Hy;case"logs.persistence":return Uy;case"auth":return jy;case"shutdown":return By;case"ui":return Wy;case"secrets":return Vy;case"doctor":return Yy;case"environment":return Zy;case"telemetry":return ob;case"telemetry.otlp":return ib;case"telemetry.otlp.listen":return Di;case"web":return sb;case"web.listen":return Di;default:return DP(e)}}function DP(e){if(e==="services"||e==="profiles"||e==="templates"||e==="tasks")return[];if(e.startsWith("services.")||e.startsWith("templates.")){if(e.includes(".dependencies."))return Dy;return OP(e)}if(e.startsWith("profiles.")){if(e.split(".").length===2)return Gy}if(e.startsWith("tasks.")){let t=e.split(".");if(t.length===2)return nb;if(t[2]==="environment")return zp}if(e.includes("routes"))return NP(e);if(e.startsWith("doctor.tools")&&e.split(".").length>=3)return Jy;if(e==="plugins")return[];if(e.startsWith("plugins.")&&e.split(".").length===2)return Qy;return[]}function OP(e){let t=e.split(".");if(t.length===2)return Ly;if(t.length>=3)switch(t[2]){case"health":return Iy;case"identity":return Oy;case"restart":return My;case"startup":return Ny;case"logs":return Ky;case"environment":return zp;case"proxy":return MP(t);case"expose":return Fy;case"container":return eb;case"watch":return tb;case"hooks":return rb;default:return[]}return[]}function MP(e){let t=e.slice(3),r=t[0]!==void 0&&/^\d+$/.test(t[0])?1:0,n=t[r]??"";if(n==="match")return jp;if(n==="upstream")return Bp;if(n==="auth")return Wp;if(n==="listen")return Di;return Up}function NP(e){if(e==="proxy.routes")return[];if(e.endsWith(".match"))return jp;if(e.endsWith(".upstream"))return Bp;if(e.endsWith(".auth"))return Wp;if(e.endsWith(".listen"))return Di;if(e.includes("proxy.routes")&&e.split(".").length===AP+1)return Up;return[]}function cb(e,t){if(e==="")return t;return`${e}.${t}`}function FP(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Oi(e){return`unknown fields: ${e.join(", ")}`}Ke();function Mt(e){let t=e.trim().toLowerCase();if(t==="")return!0;if(t==="localhost"||t==="::1")return!0;if(ub(t))return!0;return $P(t)}function ub(e){let t=e.split(".");if(t.length!==4)return!1;let r=t.map((n)=>Number(n));if(r.some((n)=>!Number.isInteger(n)||n<0||n>255))return!1;return r[0]===127}function $P(e){if(!e.startsWith("::ffff:"))return!1;return ub(e.slice(7))}import{existsSync as jP}from"fs";import{isAbsolute as BP,resolve as WP}from"path";import{fileURLToPath as zP}from"url";Ke();function db(e,t){if(t){if(t.http!==void 0)return t.http;let n=Object.values(t)[0];if(n!==void 0)return n}let r=my(e.ports);if(r&&!r.auto)return r.value;return}function HP(e,t,r,n=""){let o=e,i="";for(;;){let s=o.indexOf("${");if(s<0)return i+o;i+=o.slice(0,s);let a=o.slice(s).indexOf("}");if(a<0)throw Error(`unclosed environment reference in "${e}"`);let l=o.slice(s+2,s+a);i+=UP(l,t,r,n),o=o.slice(s+a+1)}}function UP(e,t,r,n){let o=e.split(".");if(o[0]==="identity"){if(o.length===2&&o[1]==="user")return n;throw Error(`unsupported reference \${${e}}`)}if(o.length<3||o[0]!=="services")throw Error(`unsupported reference \${${e}}`);let i=o[1]??"",s=t.services[i];if(!s)throw Error(`reference \${${e}}: unknown service`);let a=r[i];if(o[2]==="host"||o[2]==="url"){let l=t.proxy.enabled?t.proxy.routes.find((u)=>u.upstream.service===i):void 0;if(o[2]==="host")return l?l.match.host||"127.0.0.1":"127.0.0.1";if(l)return`http://${l.match.host||"127.0.0.1"}:${t.proxy.listen.port}${l.match.path}`;let c=db(s,a);if(c===void 0)throw Error(`unresolvable reference \${${e}}`);return`http://127.0.0.1:${c}`}if(o[2]==="port"){let l=db(s,a);if(l!==void 0)return String(l)}if(o[2]==="ports"){let l=o[3];if(!l)throw Error(`reference \${${e}}: missing port name`);if(a&&a[l]!==void 0)return String(a[l]);let c=Do(s.ports,l);if(c&&!c.auto)return String(c.value);let u=Number.parseInt(l,10);if(!Number.isNaN(u)&&u>=0&&u<s.ports.length){let d=s.ports[u];if(d&&!d.auto)return String(d.value)}}throw Error(`unresolvable reference \${${e}}`)}function qp(e,t,r,n=""){let o={};for(let[i,s]of Object.entries(e))o[i]=HP(s,t,r,n);return o}function pb(e){let t=[],r=e;for(;;){let n=r.indexOf("${");if(n<0)return t;let o=r.slice(n).indexOf("}");if(o<0)return t;t.push(r.slice(n+2,n+o)),r=r.slice(n+o+1)}}function fb(e,t){let r=e.split(".");if(r.length<2)return!1;if(r[0]==="identity")return r.length===2&&r[1]==="user";if(r[0]!=="services"||r.length<3)return!1;let n=t.services[r[1]??""];if(!n)return!1;if(r[2]==="port"||r[2]==="ports"){if(r.length===3)return n.ports.length>0;if(r.length>=4){let o=r[3]??"";if(!Number.isNaN(Number.parseInt(o,10)))return!0;return Do(n.ports,o)!==void 0}}return!0}Ke();var No=65535,Fo=1,bb=["http","tcp","process","command"];function Kp(e){let t=[];for(let[r,n]of Object.entries(e.services)){let o=n.health.type;if(o!==""&&!bb.includes(o.toLowerCase()))t.push({service:r,type:o})}return t}var qP=0,vb=1,yb=2;function $o(e){let t=[];if(e.version===0)t.push("version is required");else if(e.version!==Ii)t.push(`unsupported config version ${e.version} (expected ${Ii}); no migration is available`);if(Object.keys(e.services).length===0)t.push("at least one service must be defined");t.push(...KP(e)),t.push(...GP(e)),t.push(...XP(e)),t.push(...QP(e)),t.push(...ZP(e)),t.push(...oA(e)),t.push(...iA(e));for(let[r,n]of e.plugins.entries())if(n.path==="")t.push(`plugins.${r}.path is required`);else try{let o=n.path.startsWith("file:")?zP(n.path):BP(n.path)?n.path:WP(e.repoRoot,n.path);if(!jP(o))t.push(`plugins.${r}.path does not exist: ${n.path}`)}catch{t.push(`plugins.${r}.path is invalid: ${n.path}`)}if(e.logs.max_memory_events<0)t.push("logs.max_memory_events must be >= 0");return t}function GP(e){let t=[];for(let[r,n]of Object.entries(e.tasks)){let o=`tasks.${r}`;if(Gn(n.command))t.push(`${o}.command is required`);t.push(...Ql(o,n.command,n.shell));for(let i of n.dependencies)if(!e.services[i])t.push(`${o}.dependencies: unknown service "${i}"`);t.push(...wb(`${o}.environment`,n.environment,e))}return t}function KP(e){let t=[],r={};for(let[n,o]of Object.entries(e.services)){let i=`services.${n}`;if(Gn(o.command)&&!o.container)t.push(`${i}.command is required`);t.push(...Ql(i,o.command,o.shell)),t.push(...Ql(`${i}.hooks.pre_start`,o.hooks.pre_start,o.shell)),t.push(...Ql(`${i}.hooks.post_start`,o.hooks.post_start,o.shell)),t.push(...aA(i,o.capabilities));for(let l of o.dependencies){let c=lr(l);if(!e.services[c])t.push(`${i}.dependencies: unknown service "${c}"`);if(c===n)t.push(`${i}.dependencies: service cannot depend on itself`);if(!["service_started","service_healthy"].includes(zn(l)))t.push(`${i}.dependencies: condition must be service_started or service_healthy`);if(zn(l)==="service_healthy"&&e.services[c]?.health.type==="")t.push(`${i}.dependencies: service_healthy requires ${c} to define a health check`)}if(o.extends!==""&&!e.templates[o.extends])t.push(`${i}.extends: unknown template "${o.extends}"`);for(let l of o.ports.filter((c)=>!c.auto))if(l.value<Fo||l.value>No)t.push(`${i}.ports.${l.name}: invalid port ${l.value}`);else if(r[l.value])t.push(`duplicate port ${l.value} used by ${r[l.value]} and ${n}`);else r[l.value]=n;let s=JP(`${i}.identity`,o.identity,e.plugins.length>0);if(s!=="")t.push(s);if(t.push(...VP(i,o,e.plugins.length>0)),o.health.start_period_seconds<0)t.push(`${i}.health.start_period_seconds must be >= 0`);if(o.health.unhealthy_threshold<1)t.push(`${i}.health.unhealthy_threshold must be >= 1`);if(o.health.healthy_reset_threshold<1)t.push(`${i}.health.healthy_reset_threshold must be >= 1`);let a=$l(o.restart);if(a!==Dl&&a!==Ol&&a!==Ml)t.push(`${i}.restart.policy must be never, on_failure, or always`);if(t.push(...wb(`${i}.environment`,o.environment,e)),o.container){if(o.container.image==="")t.push(`${i}.container.image is required`);if(o.container.runtime!==""&&o.container.runtime!=="docker"&&o.container.runtime!=="podman")t.push(`${i}.container.runtime must be docker or podman`);for(let[l,c]of Object.entries(o.container.ports)){if(!o.ports.some((u)=>u.name===l))t.push(`${i}.container.ports.${l}: no matching service port`);if(c<Fo||c>No)t.push(`${i}.container.ports.${l}: invalid container port ${c}`)}}}return t}function VP(e,t,r){let n=[];if(t.health.type==="")return n;let o=t.health.type.toLowerCase();if(!bb.includes(o)&&!r)n.push(`${e}.health.type must be http, tcp, process, or command`);if(o==="http"&&t.health.url==="")n.push(`${e}.health.url is required for http health checks`);if(o==="tcp"&&t.health.address===""&&t.ports.length===0)n.push(`${e}.health.address is required for tcp health checks without ports`);if(o==="command"&&Gn({args:t.health.command.args,shell:!1}))n.push(`${e}.health.command is required for command health checks`);return n}var YP=["","user","service","service_account"];function JP(e,t,r){let n=Hs(t).toLowerCase();if(n===""||n==="user")return"";if(n==="service"||n==="service_account"){if(t.service_account==="")return`${e}.service_account is required for service identity`;if(!t.service_account.includes("@"))return`${e}.service_account must be an email`;return""}if(r)return"";return`${e}.type must be user or service_account`}function Vp(e){let t=[];for(let[r,n]of Object.entries(e.services)){let o=Hs(n.identity).toLowerCase();if(!YP.includes(o))t.push({service:r,type:o})}return t}function XP(e){let t={},r=[],n=[],o=(i)=>{let s=t[i]??qP;if(s===yb)return;if(s===vb){r.push(`dependency cycle: ${[...n,i].join(" \u2192 ")}`);return}t[i]=vb,n.push(i);let a=e.services[i];if(a)for(let l of a.dependencies){let c=lr(l);if(e.services[c])o(c)}n.pop(),t[i]=yb};for(let i of Object.keys(e.services))o(i);return r}function wb(e,t,r){let n=[],o=(i,s)=>{for(let a of pb(s))if(!fb(a,r))n.push(`${e}.${i}: unresolvable reference \${${a}}`)};for(let[i,s]of Object.entries(t.vars))o(i,s);for(let[i,s]of Object.entries(t.defaults))o(i,s);return n}function QP(e){let t=[];for(let[r,n]of Object.entries(e.profiles))for(let o of n.services)if(!e.services[o])t.push(`profiles.${r} references unknown service "${o}"`);return t}function ZP(e){let t=[];if(e.proxy.listen.host!==""){if(!xb(e.proxy.listen.host))t.push("proxy.listen.host must be an IP address or localhost");else if(!Mt(e.proxy.listen.host))t.push("proxy.listen.host must be a loopback address")}if(e.proxy.enabled&&e.proxy.listen.port===0)t.push("proxy.listen.port is required when proxy.enabled is true");if(e.proxy.listen.port!==0&&(e.proxy.listen.port<Fo||e.proxy.listen.port>No))t.push("proxy.listen.port is invalid");let r={},n=new Set;return e.proxy.routes.forEach((o,i)=>{let s=`proxy.routes[${i}]`;if(o.name==="")t.push(`${s}.name is required`);else if(r[o.name])t.push(`${s}: duplicate route name ${o.name}`);r[o.name]=!0;let a=(o.transport??"").toLowerCase();if(a!==""&&a!=="http"&&a!=="grpc")t.push(`${s}.transport must be "http" or "grpc"`);if(t.push(...tA(o,s,e)),t.push(...rA(o,s)),Wn(o))t.push(...eA(o,s,n,e))}),t.push(...sA(e)),t}function eA(e,t,r,n){let o=[],i=e.listen;if(!i||i.port===0)o.push(`${t}.listen.port is required for a grpc route`);else{if(i.port<Fo||i.port>No)o.push(`${t}.listen.port is invalid`);if(r.has(i.port))o.push(`${t}.listen.port ${i.port} is already used by another grpc route`);if(r.add(i.port),i.port===n.proxy.listen.port)o.push(`${t}.listen.port must differ from proxy.listen.port`);if(n.proxy.token_endpoint.enabled&&i.port===n.proxy.token_endpoint.port)o.push(`${t}.listen.port must differ from proxy.token_endpoint.port`);if(i.host!==""&&(!xb(i.host)||!Mt(i.host)))o.push(`${t}.listen.host must be a loopback address`)}if(!(e.upstream.url??"").trim().toLowerCase().startsWith("https://"))o.push(`${t}.upstream.url must be an https:// address for a grpc route`);if(e.match.host!==""||e.match.path!=="")o.push(`${t}.match is not supported on a grpc route`);if(e.response_headers&&Object.keys(e.response_headers).length>0)o.push(`${t}.response_headers is not supported on a grpc route`);return o}function tA(e,t,r){let n=[],o=e.upstream.url!=="",i=e.upstream.service??"";if(i===""){if(!o)n.push(`${t}.upstream requires either url or service`);return n}let s=r.services[i];if(!s)return n.push(`${t}.upstream.service references unknown service ${i}`),n;let a=e.upstream.port||"http";if(Do(s.ports,a)===void 0)n.push(`${t}.upstream: service ${i} has no port named ${a}`);return n}function rA(e,t){let r=[];if(e.auth.type.toLowerCase()==="iap"){if(e.auth.audience.trim()==="")r.push(`${t}.auth.audience is required when auth.type is iap`);if(e.auth.identity.type.trim()==="")r.push(`${t}.auth.identity.type is required when auth.type is iap`)}r.push(...nA(e.auth,t));let n=e.auth.identity.type.toLowerCase();if(n==="service"||n==="service_account"||Tn({type:n,mode:"",service_account:""})){if((e.auth.identity.service_account||e.auth.service_account)==="")r.push(`${t}.auth.identity.service_account is required`)}return r}function nA(e,t){let r=(e.client_id??"").trim(),n=(e.client_secret??"").trim(),o=(e.credentials??"").trim();if(r===""&&n===""&&o==="")return[];if(e.type.toLowerCase()!=="iap")return[`${t}.auth.${r!==""?"client_id":n!==""?"client_secret":"credentials"} is only valid when auth.type is iap`];let i=[];if(r===""){if(n!=="")i.push(`${t}.auth.client_id is required when client_secret is set`);if(o!=="")i.push(`${t}.auth.credentials requires auth.client_id`);return i}if(n===""&&o==="")i.push(`${t}.auth.client_secret is required when client_id is set`);else if(n!==""&&Gp(n).length>0&&!gb(n))i.push(`${t}.auth.client_secret must be a literal or a single \${NAME} / \${env.NAME} reference`);let s=e.identity.type.toLowerCase();if(s==="service"||s==="service_account")i.push(`${t}.auth.client_id is only valid with identity.type user`);return i}function oA(e){let t=[],r=e.telemetry.otlp.listen.host||Dt;if(!Mt(r))t.push("telemetry.otlp.listen.host must be a loopback address");let n=e.telemetry.otlp.listen.port;if(n!==0&&(n<Fo||n>No))t.push("telemetry.otlp.listen.port is invalid");if(n!==0){if(e.proxy.listen.port===n)t.push("telemetry.otlp.listen.port must differ from proxy.listen.port");if(e.proxy.token_endpoint.enabled&&e.proxy.token_endpoint.port===n)t.push("telemetry.otlp.listen.port must differ from proxy.token_endpoint.port");e.proxy.routes.forEach((o,i)=>{if(Wn(o)&&o.listen&&o.listen.port===n)t.push(`telemetry.otlp.listen.port must differ from proxy.routes[${i}].listen.port`)})}return t}function iA(e){let t=[],r=e.web.listen.host||Dt;if(!Mt(r))t.push("web.listen.host must be a loopback address");let n=e.web.listen.port;if(n!==0&&(n<Fo||n>No))t.push("web.listen.port is invalid");if(n!==0){if(e.proxy.listen.port===n)t.push("web.listen.port must differ from proxy.listen.port");if(e.proxy.token_endpoint.enabled&&e.proxy.token_endpoint.port===n)t.push("web.listen.port must differ from proxy.token_endpoint.port");if(e.telemetry.otlp.listen.port===n)t.push("web.listen.port must differ from telemetry.otlp.listen.port");e.proxy.routes.forEach((o,i)=>{if(Wn(o)&&o.listen&&o.listen.port===n)t.push(`web.listen.port must differ from proxy.routes[${i}].listen.port`)})}return t}function sA(e){let t=[],r=e.proxy.token_endpoint;if(!r.enabled)return t;let n=r.host||Dt;if(!Mt(n))t.push("proxy.token_endpoint.host must be a loopback address");if(r.port!==0&&(r.port<Fo||r.port>No))t.push("proxy.token_endpoint.port is invalid");return t}function Ql(e,t,r){if(t.shell||r)return[];for(let n of t.args)if(lb.includes(n)||n.includes("|")||n.includes(";")||n.includes("&&"))return[`${e}.command contains shell metacharacters; set shell: true to run via a shell`];return[]}function aA(e,t){let r=[];for(let n of t)if(!ab.includes(n))r.push(`${e}.capabilities: unknown capability "${n}"`);return r}function xb(e){if(e==="localhost")return!0;return lA(e)}function lA(e){if(/^(\d{1,3}\.){3}\d{1,3}$/.test(e))return e.split(".").every((r)=>{let n=Number(r);return n>=0&&n<=255});return e.includes(":")}function Bs(e,t,r){try{return Ws(e,t,{candidateText:r}),[]}catch(n){if(n instanceof et){let o=`${n.kind}: `;return[n.message.startsWith(o)?n.message.slice(o.length):n.message]}return[n instanceof Error?n.message:String(n)]}}function _n(e,t){let{repoRoot:r,configPath:n}=Mo(e,t);return Ws(r,n)}function Uo(e,t){try{return _n(e,t)}catch(r){if(!Al(r,Po))throw r;let n=e===""?process.cwd():fA(e),o=Io();return o.repoRoot=n,o.configPath=Ho(n,Yt,_r),o}}function Ws(e,t,r){let n=Io(),o=Jl();Cb(t,n,o,r?.candidateText,"main"),n.repoRoot=e,n.configPath=t;let i=dA(t);if(Sb(i)===Yt)gA(i,n,o);n=hA(n,e,t,o),n=Py(n);try{Ry(n,o)}catch(a){throw ge(ee,"template merge failed",a)}Ty(n,o.provenance),Ey(n),n.provenance=o.provenance;let s=$o(n);if(s.length>0)throw T(ee,s.join(`
|
|
2507
|
-
`));return n}function
|
|
2508
|
-
`)}async delete(e){let t=
|
|
2509
|
-
`)}function
|
|
2510
|
-
`)}function
|
|
2511
|
-
`)}function nL(e){return{identity:e.identity,audience:e.audience,scopes:e.scopes,accessToken:e.accessToken,tokenType:e.tokenType,expiresAt:e.expiresAt.toISOString()}}function oL(e){return{accessToken:e.accessToken,tokenType:e.tokenType||"Bearer",expiresAt:new Date(e.expiresAt),audience:e.audience,identity:e.identity,scopes:e.scopes}}function Zn(){return[aL(),sL(),iL()]}function iL(){return{name:"user",accepts:(e,t)=>!e.startsWith("sa:")&&t==="",fetch:async(e,t,r)=>{if(e.startsWith("sa:"))throw T(zr,"user provider cannot mint service-account tokens");return fL(e,t,r)}}}function sL(){return{name:"service_account",accepts:(e,t)=>e.startsWith("sa:")&&t==="",fetch:async(e,t,r)=>{if(!e.startsWith("sa:"))throw T(zr,"service-account provider cannot mint user tokens");return lL(e,t,r)}}}function aL(){return{name:"iap",accepts:(e,t)=>t!=="",fetch:async(e,t,r,n)=>{if(t==="")throw T(zr,"IAP audience is required");if(e.startsWith("sa:"))return cL(e,t,r);return uL(e,t,r,n)}}}async function lL(e,t,r){let n=e.slice(3);try{Ni();let i=await new Ks({scopes:r.length>0?r:[ac]}).getClient(),s=new GA({sourceClient:i,targetPrincipal:n,targetScopes:r.length>0?r:[ac],lifetime:3600}),a=await s.getAccessToken(),l=typeof a==="string"?a:a?.token;if(!l)throw T(zr,"empty impersonated token");return{accessToken:l,tokenType:"Bearer",expiresAt:Vs(l,s),audience:t,identity:e,scopes:r}}catch(o){throw Fi(o)}}async function cL(e,t,r){let n=e.slice(3);try{Ni();let i=await new Ks({scopes:[ac]}).getClient(),s=`https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${encodeURIComponent(n)}:generateIdToken`,l=(await i.request({url:s,method:"POST",data:{audience:t,includeEmail:!0}})).data.token;if(!l)throw T(zr,"empty impersonated IAP id token");return{accessToken:l,tokenType:"Bearer",expiresAt:Vs(l),audience:t,identity:e,scopes:r}}catch(o){throw Fi(o)}}async function uL(e,t,r,n){try{if(Ni(),n)return await dL(e,t,r,n);let s=await(await new Ks({scopes:r.length>0?r:[Wb]}).getIdTokenClient(t)).idTokenProvider.fetchIdToken(t);return{accessToken:s,tokenType:"Bearer",expiresAt:Vs(s),audience:t,identity:e,scopes:r}}catch(o){if(o instanceof et)throw o;throw Fi(o)}}async function dL(e,t,r,n){let o=n.refreshToken;if(!o){if(o=(await new Ks({scopes:r.length>0?r:[Wb]}).getClient()).credentials.refresh_token??void 0,!o)throw Ie(Bn,"ADC has no refresh token for a custom IAP OAuth client","set auth.credentials (or proxy.credentials) to an authorized_user file whose refresh_token was issued by this client_id, or run `gcloud auth application-default login` with that client")}let i=await fetch(JA,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:pL(n,o,t)}),s=await i.text();if(!i.ok)throw Error(`IAP token exchange failed (${i.status}): ${s}`);let a;try{a=JSON.parse(s)}catch{throw T(zr,"IAP token endpoint returned a non-JSON response")}let l=a.id_token;if(!l)throw T(zr,"empty IAP id token");return{accessToken:l,tokenType:"Bearer",expiresAt:Vs(l),audience:t,identity:e,scopes:r}}function pL(e,t,r){return new URLSearchParams({grant_type:"refresh_token",client_id:e.clientId,client_secret:e.clientSecret,refresh_token:t,audience:r})}async function fL(e,t,r){try{Ni();let o=await new Ks({scopes:r.length>0?r:[ac]}).getClient(),i=await o.getAccessToken();if(!i.token)throw T(zr,"empty access token");return{accessToken:i.token,tokenType:"Bearer",expiresAt:mL(o,i.token),audience:t,identity:e,scopes:r}}catch(n){throw Fi(n)}}function Vs(e,t){if(t?.credentials?.expiry_date)return new Date(t.credentials.expiry_date);return hL(e)??new Date(Date.now()+KA)}function mL(e,t){return Vs(t,e)}function hL(e){let t=e.split(".");if(t.length<2||!t[1])return;try{let r=JSON.parse(Buffer.from(t[1],"base64url").toString("utf8"));if(typeof r.exp==="number")return new Date(r.exp*1000)}catch{return}return}function gL(e){if(e instanceof et)return e.kind!==ee&&e.kind!==Ao;let t=e instanceof Error?e.message.toLowerCase():String(e).toLowerCase();return t.includes("network")||t.includes("econnreset")||t.includes("etimedout")||t.includes("503")||t.includes("429")}ne();Gr();var Js=4000,vL=8000;function Hi(e){let t=e?.tokens,r=()=>(t??=new qo(60000,Zn(),void 0,oc("file")),t);return{detectGoogle:Wo,hasCommand:rf,portAvailable:Ai,hasLocalAdc:qs,adcQuotaProject:tf,mintToken:async(n,o,i)=>{await r().get(n,o,[],i)},probeServiceUsage:async(n,o)=>{let i=await Xs(r().get("user","",[]),Js),s=`https://serviceusage.googleapis.com/v1/projects/${n}/services/${o}`,a=await fetch(s,{headers:{Authorization:`Bearer ${i.accessToken}`},signal:AbortSignal.timeout(Js)});if(!a.ok)return!1;return(await a.json().catch(()=>{return}))?.state==="ENABLED"},containerRuntimeAvailable:async(n)=>{try{return await Bun.spawn({cmd:[n,"info"],stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited===0}catch{return!1}}}}var cc=Hi();function uc(e=Hi()){return{run:(t,r,n)=>yL(t,e,r,n)}}async function yL(e,t=cc,r,n){let o={checks:[],issues:0},i="Preparing diagnostics",s=()=>r?.({active:i,checks:[...o.checks]}),a=(p)=>{i=p,s()},l=(p)=>{if(o.checks.push(p),p.severity==="error")o.issues+=1;s()},c=[...new Set(Object.values(e.services).flatMap((p)=>p.container?[p.container.runtime||"docker"]:[]))];for(let p of c){a(`${p} container runtime`);let m=await t.hasCommand(p),h=m&&await(t.containerRuntimeAvailable??cc.containerRuntimeAvailable)(p);l(h?{name:`${p} container runtime`,severity:"ok",message:`${p} daemon reachable`}:{name:`${p} container runtime`,severity:"error",message:m?`${p} daemon is not reachable`:`${p} not found`,hint:`install and start ${p}`})}if(a("Google CLI installed"),await t.hasCommand("gcloud"))l({name:"Google CLI installed",severity:"ok",message:"gcloud found"});else l({name:"Google CLI installed",severity:zs(e)?"error":"warn",message:"gcloud not installed",hint:"install the Google Cloud CLI from https://cloud.google.com/sdk/docs/install"});a("Google environment");let u=await t.detectGoogle(e.google.project_id);if(u.adcAvailable)l({name:"Google authentication available",severity:"ok",message:"Application Default Credentials found"});else l({name:"Google authentication available",severity:zs(e)?"error":"warn",message:"ADC unavailable",hint:"run `gcloud auth application-default login`"});if(u.projectID!=="")l({name:"Project configured",severity:"ok",message:`${u.projectID} (source: ${u.projectSource})`});else l({name:"Project configured",severity:zs(e)?"error":"warn",message:"no Google project configured",hint:"set google.project_id in .devctl/config.yaml"});if(zs(e)||Object.values(e.services).some((p)=>p.capabilities.includes("google")||p.identity.type!=="")){a("Live Google access");let p=!0,m=(h)=>{if(p)l(h)};try{await Xs((async()=>{await wL(e,m,t,u.userEmail),await bL(e,m,t)})(),t.liveDeadlineMs??vL)}catch(h){m({name:"Live Google probes",severity:"warn",message:I(h),hint:"network or timeout \u2014 retry when online"})}finally{p=!1}}for(let p of e.doctor.tools){let m=p.command||p.name;if(a(`${p.name} installed`),await t.hasCommand(m))l({name:`${p.name} installed`,severity:"ok",message:`${m} found`});else l({name:`${p.name} installed`,severity:"error",message:`${m} not found`,hint:`install ${p.name} and ensure it is on PATH`})}if(a("Repository configuration"),n?.repositoryConfigError!==void 0)if(n.repositoryConfigError==="")l({name:"Repository configuration",severity:"ok",message:"valid"});else l({name:"Repository configuration",severity:"error",message:n.repositoryConfigError});else try{let p=$o(e);if(p.length>0)l({name:"Repository configuration",severity:"error",message:p.join("; ")});else l({name:"Repository configuration",severity:"ok",message:"valid"})}catch(p){l({name:"Repository configuration",severity:"error",message:I(p)})}let f={};for(let[p,m]of Object.entries(e.services))for(let h of m.ports){if(h.auto)continue;let g=`Port ${h.value}`;if(a(g),f[h.value])l({name:g,severity:"error",message:`configured on both ${f[h.value]} and ${p}`});else{f[h.value]=p;let w=n?.services?.[p],v=Boolean(m.container&&w&&["STARTING","RUNNING","HEALTHY","UNHEALTHY"].includes(w.state??""));if(Boolean(w&&(w.pid>0||v)&&Object.values(w.ports).includes(h.value)))l({name:g,severity:"ok",message:`in use by running service ${p}`});else if(await t.portAvailable(h.value))l({name:g,severity:"ok",message:"available"});else l(await qb(g,h.value,`services.${p}.ports`))}}if(e.proxy.listen.port>0){let p=`Port ${e.proxy.listen.port}`;if(a(p),n?.proxyRunning)l({name:p,severity:"ok",message:"in use by the running proxy"});else if(await t.portAvailable(e.proxy.listen.port))l({name:p,severity:"ok",message:"proxy listen port available"});else l(await qb(p,e.proxy.listen.port,"proxy.listen.port"))}return i="Diagnostics complete",s(),o}async function bL(e,t,r){let n=e.google.project_id,o=r.hasLocalAdc??qs;if(n===""||!o())return;let i=r.probeServiceUsage??cc.probeServiceUsage,s=[{name:"IAM Credentials API",service:"iamcredentials.googleapis.com"},{name:"Resource Manager API",service:"cloudresourcemanager.googleapis.com"},{name:"IAP API",service:"iap.googleapis.com"}];(await Promise.allSettled(s.map((l)=>Xs(i(n,l.service),Js)))).forEach((l,c)=>{let u=s[c];if(!u)return;if(l.status==="fulfilled"){t({name:u.name,severity:l.value?"ok":"warn",message:l.value?"enabled":"not enabled or unreachable",hint:l.value?void 0:`enable ${u.service} in the Google Cloud console \u2014 doctor never auto-enables APIs`});return}t({name:u.name,severity:"warn",message:I(l.reason),hint:`enable ${u.service} in the Google Cloud console \u2014 doctor never auto-enables APIs`})})}async function wL(e,t,r,n){let o=ln(e),i=e.proxy.routes.filter((d)=>d.auth.type.toLowerCase()==="iap"),s=i.filter((d)=>d.auth.audience.trim()!=="");for(let d of i)if(d.auth.audience.trim()==="")t({name:`IAP audience ${d.name}`,severity:"error",message:"missing audience",hint:"set auth.audience to the IAP OAuth client ID"});if(o.length===0&&s.length===0)return;if(!(r.hasLocalAdc??qs)())return;let l=r.mintToken??cc.mintToken,c=o.map(async(d)=>{try{await Xs(l(`sa:${d}`,""),Js),t({name:`Impersonate ${d}`,severity:"ok",message:"token minted"})}catch(f){let p=(r.adcQuotaProject??tf)(),m=n||"the ADC principal",h=p===""?"unknown":p,g=zb(`Impersonate ${d}`,f,`grant roles/iam.serviceAccountTokenCreator to ${m} on ${d}; ADC quota project: ${h}`);if(p!==""&&g.message.toLowerCase().includes("api is not enabled"))g.message=`IAM Credentials API is disabled in ADC quota project ${p}`,g.hint=`enable iamcredentials.googleapis.com in ${p}, or set the ADC quota project to ${e.google.project_id}`;else if(g.message.toLowerCase()==="google authentication failed")g.message=`access-token mint failed: ${m} \u2192 ${d}`,g.hint=`verify roles/iam.serviceAccountTokenCreator for ${m} on this service account; ADC quota project: ${h}`;t(g)}}),u=s.map(async(d)=>{let f=Pn(d.auth).kind===jo?`sa:${Pn(d.auth).serviceAccount}`:"user";try{let p=lc(d.auth);await Xs(l(f,d.auth.audience,p),Js),t({name:`IAP ${d.name}`,severity:"ok",message:"id token minted"})}catch(p){t(zb(`IAP ${d.name}`,p,"check IAP OAuth client ID and ADC"))}});await Promise.all([...c,...u])}function zb(e,t,r){let n=I(t),o=n.toLowerCase();if(o.includes("timeout")||o.includes("network")||o.includes("econnrefused")||o.includes("enotfound"))return{name:e,severity:"warn",message:n,hint:"network or timeout \u2014 retry when online"};if(t instanceof et&&t.hint!==""){let i=`${t.kind}: `,s=t.message.startsWith(i)?t.message.slice(i.length):t.message;return{name:e,severity:"error",message:s,hint:t.hint}}return{name:e,severity:"error",message:n,hint:r}}function Xs(e,t){return new Promise((r,n)=>{let o=setTimeout(()=>n(Error("timeout")),t);e.then((i)=>{clearTimeout(o),r(i)},(i)=>{clearTimeout(o),n(i)})})}async function qb(e,t,r){let n=await Lo(t);if(!n)return{name:e,severity:"error",message:"already in use",hint:`stop the process using port ${t} or change ${r}`};if(n.pid===process.pid)return{name:e,severity:"error",message:`in use by this TUI (${n.command} pid ${n.pid})`,hint:"stop the proxy from the proxy screen (x), then rerun doctor"};return{name:e,severity:"error",message:`in use by ${n.command} (pid ${n.pid})`,hint:"enter stop that process after a confirmation",action:{kind:"free-port",holder:n}}}function Gb(e){let t=[`${vr()} doctor`,""];for(let r of e.checks){let n=r.severity==="error"?"\u2717":r.severity==="warn"?"!":"\u2713";if(t.push(`${n} ${r.name}`),r.severity!=="ok"){if(t.push(` ${r.message}`),r.hint)t.push(` \u2192 ${r.hint}`)}}return t.push("",`${e.issues} issue(s) found.`),t.join(`
|
|
2508
|
+
`,{mode:384})}function Qv(e){let t=_o(e)&&hp(e).isDirectory()?e:Kv(e);if(tn(t),process.platform==="darwin"){let r=_o(e)&&hp(e).isFile()?["-R",e]:[t];fp("open",r,{detached:!0,stdio:"ignore"}).unref();return}if(process.platform==="win32"){fp("explorer",[t],{detached:!0,stdio:"ignore"}).unref();return}fp("xdg-open",[t],{detached:!0,stdio:"ignore"}).unref()}function Zv(e=Xa()){if(!_o(e))return[];return Ms(e).filter((t)=>t.startsWith(vp)).sort().reverse()}function I_(e){let t=Cn(e,Vv);if(_o(t))return gp(t,"utf8").trim()===Yv;if(!_o(e))return!1;return Ms(e).some((r)=>r.endsWith(".jsonl"))}function ey(e,t=Xa()){let r=Cn(t,e);if(!_o(r))return[];if(I_(r))return D_(r);return O_(r)}function D_(e){let t=[];for(let r of Ms(e)){if(!r.endsWith(".jsonl"))continue;let n=gp(Cn(e,r),"utf8");for(let o of n.split(`
|
|
2509
|
+
`)){if(o.trim()==="")continue;let i=M_(o);if(i)t.push(i)}}return t.sort((r,n)=>r.seq-n.seq||r.timestamp.localeCompare(n.timestamp))}function O_(e){let t=[];for(let n of Ms(e)){if(!n.endsWith(".log"))continue;let o=gp(Cn(e,n),"utf8");for(let i of o.split(`
|
|
2510
|
+
`)){if(i.trim()==="")continue;let s=i.split(" "),a=s.slice(3).join(" "),l=lp(a);t.push(tp({timestamp:s[0]??"",service:s[1]??n.replace(/\.log$/,""),source:"history",pid:0,level:s[2]??"INFO",message:a},l??{body:a,raw:a},0))}}let r=t.sort((n,o)=>n.timestamp.localeCompare(o.timestamp));return r.forEach((n,o)=>{n.seq=o+1}),r}function M_(e){try{let t=JSON.parse(e);if(!Le(t)||typeof t.service!=="string"||typeof t.seq!=="number")return;return t}catch{return}}function N_(e){let t=e.replace(/[^A-Za-z0-9._-]+/g,"_");return t===""?"service":t}function F_(e,t,r){if(!_o(e))return;let n=Ms(e).filter((i)=>i.startsWith(vp)).map((i)=>{let s=Cn(e,i),a=hp(s);return{path:s,mtime:a.mtimeMs}}).sort((i,s)=>s.mtime-i.mtime),o=t>0?Date.now()-t*86400000:0;n.forEach((i,s)=>{let a=o>0&&i.mtime<o,l=r>0&&s>=r;if(a||l)R_(i.path,{recursive:!0,force:!0})})}ne();var{spawn:kp}=globalThis.Bun;import{createServer as ay}from"net";var $_=65535,xp=1;async function ly(e,t,r={}){let n={};for(let[i,s]of Object.entries(r))for(let a of Object.values(s))n[a]=i;let o={};for(let[i,s]of Object.entries(e.services)){if(t.length>0&&!t.includes(i))continue;let a={};for(let l of s.ports){let c=r[i]?.[l.name],u=c&&c>=xp?c:l.value;if(c===void 0&&l.auto)u=await H_();if(u<xp||u>$_)throw new et(ee,`invalid port ${u} on service ${i}`,{service:i});if(n[u]&&n[u]!==i)throw new et(ee,`duplicate port ${u} used by ${n[u]} and ${i}`,{service:i});if(c!==u&&!l.auto&&!await Ai(u))throw await U_(i,l.name,u);n[u]=i,a[l.name]=u}o[i]=a}return o}function H_(){return new Promise((e,t)=>{let r=ay();r.listen(0,"127.0.0.1",()=>{let n=r.address();r.close(()=>{if(n&&typeof n==="object")e(n.port);else t(ge(ee,"unable to allocate dynamic port",Error("no address")))})}),r.on("error",(n)=>t(ge(ee,"unable to allocate dynamic port",n)))})}async function Ll(e){let t=e.ports.filter((n)=>!n.auto&&n.value>=xp);if(t.length===0)return;let r={};for(let n of t){if(await Ai(n.value))return;r[n.name]=n.value}return r}function Ai(e){return new Promise((t)=>{let r=ay();r.listen(e,"127.0.0.1",()=>{r.close(()=>t(!0))}),r.on("error",()=>t(!1))})}async function U_(e,t,r){let n=await Lo(r);return j_(e,t,r,n)}function j_(e,t,r,n){let o=t===""?`${e} port`:`${e} ports.${t}`;if(n&&n.pid===process.pid)return Ie(Ge,`${e} blocked: this TUI already holds port ${r}`,`Stop the proxy from the Proxy screen, or change ${o} in .devctl.`,e);if(n)return Ie(Ge,`${e} blocked: ${n.command} (pid ${n.pid}) is using port ${r}`,`Open Doctor and press enter to free port ${r}, or change ${o} in .devctl.`,e);return Ie(Ge,`${e} blocked: port ${r} is already in use`,`Something is listening on ${r}. Open Doctor to free it, or change ${o} in .devctl.`,e)}function B_(e,t){let r=e.split(`
|
|
2511
|
+
`).filter((n)=>n.trim()!==""&&!n.startsWith("COMMAND"));for(let n of r){let o=n.trim().split(/\s+/),i=o[0]??"",s=Number(o[1]);if(i!==""&&Number.isInteger(s)&&s>0)return{port:t,pid:s,command:i}}return}async function Lo(e){if(process.platform==="win32")return G_(e);let t=await W_(e);if(t)return t;return z_(e)}async function W_(e){try{let t=kp({cmd:["lsof","-nP",`-iTCP:${e}`,"-sTCP:LISTEN"],stdout:"pipe",stderr:"ignore"}),r=await new Response(t.stdout).text();return await t.exited,B_(r,e)}catch{return}}async function z_(e){let t;try{let o=kp({cmd:["fuser","-n","tcp",String(e)],stdout:"pipe",stderr:"pipe"});t=`${await new Response(o.stdout).text()} ${await new Response(o.stderr).text()}`,await o.exited}catch{return}let r=t.match(/(\d+)/),n=r?Number(r[1]):0;if(!Number.isInteger(n)||n<=0)return;return{port:e,pid:n,command:"process"}}function q_(e,t){for(let r of e.split(`
|
|
2512
|
+
`)){if(!r.includes("LISTENING")&&!r.includes("LISTEN"))continue;if(!r.includes(`:${t}`)&&!r.includes(` ${t} `))continue;let n=r.trim().match(/(\d+)\s*$/),o=n?Number(n[1]):0;if(Number.isInteger(o)&&o>0)return{port:t,pid:o,command:"process"}}return}async function G_(e){let t=kp({cmd:["netstat","-ano"],stdout:"pipe",stderr:"ignore"}),r=t.stdout?await new Response(t.stdout).text():"";return await t.exited,q_(r,e)}var K_=400;async function Il(e){if(e.pid===process.pid)throw Ie(Ge,`port ${e.port} is held by this TUI`,"stop the proxy from the proxy screen, or quit the TUI");try{process.kill(e.pid,"SIGTERM")}catch(t){throw ge(Ge,`could not stop pid ${e.pid} on port ${e.port}`,t)}await V_(K_);try{process.kill(e.pid,0),process.kill(e.pid,"SIGKILL")}catch{return}}function V_(e){return new Promise((t)=>{setTimeout(t,e)})}zl();ne();import{readdirSync as yA,readFileSync as bA}from"fs";import{basename as Eb,dirname as wA,extname as xA,join as Ho,resolve as kA}from"path";import{parse as SA}from"yaml";Ke();function M(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Dp(e){return M(e)?new Set(Object.keys(e)):new Set}function q(e){if(typeof e==="string")return e;if(typeof e==="number"||typeof e==="boolean")return String(e);return""}function Te(e){if(typeof e==="number")return e;if(typeof e==="string"){let t=Number(e);return Number.isNaN(t)?0:t}return 0}function tt(e){return e===!0}function Mt(e){if(!Array.isArray(e))return[];return e.map((t)=>q(t))}function Op(e){if(!Array.isArray(e))return[];return e.map((t)=>M(t)?{service:q(t.service),condition:q(t.condition)||"service_started"}:q(t))}function an(e){if(!M(e))return{};let t={};for(let[r,n]of Object.entries(e))t[r]=q(n);return t}function qr(e){if(typeof e==="string")return{args:e.split(/\s+/).filter((t)=>t!==""),shell:!1};if(Array.isArray(e))return{args:e.map((t)=>q(t)),shell:!1};return Li()}function Mp(e){if(e===void 0||e===null)return[];if(typeof e==="string"||typeof e==="number")return[Ip(e,"http")];if(Array.isArray(e))return e.map((t,r)=>Ip(t,`port_${r}`));if(M(e))return Object.entries(e).map(([t,r])=>Ip(r,t));return[]}function Ip(e,t){if(typeof e==="string"&&e.toLowerCase()==="auto")return{name:t,value:0,auto:!0};return{name:t,value:Te(e),auto:!1}}function by(e){if(!M(e))return Tp();let t={},r=[],n={};for(let[o,i]of Object.entries(e))if(o==="required")r=Mt(i);else if(o==="defaults")n=an(i);else t[o]=q(i);return{vars:t,required:r,defaults:n}}function sP(e){if(!M(e))return Rp();return{type:q(e.type),mode:q(e.mode),service_account:q(e.service_account),config:M(e.config)?{...e.config}:{}}}function aP(e){if(!M(e))return Ep();return{type:q(e.type),url:q(e.url),address:q(e.address),command:qr(e.command),interval_seconds:Te(e.interval_seconds),timeout_seconds:Te(e.timeout_seconds),start_period_seconds:Te(e.start_period_seconds),unhealthy_threshold:e.unhealthy_threshold===void 0?3:Te(e.unhealthy_threshold),healthy_reset_threshold:e.healthy_reset_threshold===void 0?10:Te(e.healthy_reset_threshold)}}function lP(e){if(!M(e))return{policy:"",max_retries:0,backoff_seconds:0};return{enabled:e.enabled===void 0?void 0:tt(e.enabled),policy:q(e.policy),max_retries:Te(e.max_retries),backoff_seconds:Te(e.backoff_seconds)}}function cP(e){if(!M(e))return{wait_for_healthy:!1,timeout_seconds:0};return{wait_for_healthy:tt(e.wait_for_healthy),timeout_seconds:Te(e.timeout_seconds)}}function Us(e){if(!M(e))return qn();let t=M(e.logs)?e.logs:{};return{extends:q(e.extends),description:q(e.description),command:qr(e.command),shell:tt(e.shell),working_dir:q(e.working_dir),dependencies:Op(e.dependencies),ports:Mp(e.ports),environment:by(e.environment),health:aP(e.health),identity:sP(e.identity),logs:{stdout:tt(t.stdout),stderr:tt(t.stderr)},restart:lP(e.restart),startup:cP(e.startup),capabilities:Mt(e.capabilities),proxy:$p(e.proxy),expose:Fp(e.expose),container:Np(e.container),watch:uP(e.watch),hooks:dP(e.hooks)}}function uP(e){if(!M(e))return Sp();return{enabled:tt(e.enabled),paths:Mt(e.paths),debounce_ms:Nl(Te(e.debounce_ms)),ignore:e.ignore===void 0?[...Ns]:Mt(e.ignore)}}function dP(e){let t=M(e)?e:{};return{pre_start:qr(t.pre_start),post_start:qr(t.post_start)}}function wy(e){let t=M(e)?e:{};return{command:qr(t.command),shell:tt(t.shell),working_dir:q(t.working_dir),dependencies:Mt(t.dependencies),environment:by(t.environment)}}function Np(e){if(!M(e))return;let t={};if(M(e.ports))for(let[r,n]of Object.entries(e.ports))t[r]=Te(n);return{image:q(e.image),runtime:q(e.runtime),ports:t,env:an(e.env),volumes:Mt(e.volumes)}}function Fp(e){if(e===!0)return{enabled:!0,host:"",port:""};if(e===!1)return{enabled:!1,host:"",port:""};if(M(e))return{enabled:e.enabled!==void 0?tt(e.enabled):!0,host:q(e.host),port:q(e.port)};return Cp()}function $p(e){if(e===void 0||e===null)return[];if(Array.isArray(e))return e.map((t)=>Oo(t));if(M(e))return[Oo(e)];return[]}function ql(e){if(!M(e))return{services:[],environment:{}};return{services:Mt(e.services),environment:an(e.environment)}}function pP(e){if(typeof e==="string")return{type:e,service_account:""};if(!M(e))return{type:"",service_account:""};return{type:q(e.type),service_account:q(e.service_account)}}function fP(e){if(!M(e))return Fs();return{type:q(e.type),identity:pP(e.identity),audience:q(e.audience),service_account:q(e.service_account),client_id:q(e.client_id),client_secret:q(e.client_secret),credentials:q(e.credentials),headers:an(e.headers)}}function Oo(e){if(!M(e))return{name:"",match:{host:"",path:""},upstream:{url:""},auth:Fs()};let t=M(e.match)?e.match:{},r=M(e.upstream)?e.upstream:{};return{name:q(e.name),transport:q(e.transport),match:{host:q(t.host),path:q(t.path)},upstream:{url:q(r.url),service:q(r.service),port:q(r.port)},auth:fP(e.auth),response_headers:an(e.response_headers),listen:M(e.listen)?{host:q(e.listen.host),port:Te(e.listen.port)}:void 0}}ne();import{existsSync as mP,statSync as ky}from"fs";import{basename as xy,dirname as Gl,isAbsolute as hP,join as Kl,resolve as Sy}from"path";function Mo(e,t){if(t!=="")return gP(t);let r=e===""?process.cwd():e;r=hP(r)?r:Sy(r);for(;;){let n=Kl(r,Yt,_r);if(js(n))return{repoRoot:r,configPath:n};let o=Kl(r,"devctl.yaml");if(js(o))return{repoRoot:r,configPath:o};let i=Gl(r);if(i===r)break;r=i}throw Ie(Po,"no devctl configuration found","run `devctl setup` or create a .devctl/config.yaml in the repository root")}function gP(e){let t=Sy(e),r;try{r=ky(t)}catch(o){throw ge(Po,"config path not found",o)}if(r.isDirectory()){if(xy(t)===Yt)return{repoRoot:Gl(t),configPath:Kl(t,_r)};return{repoRoot:t,configPath:Kl(t,_r)}}let n=Gl(t);if(xy(n)===Yt)n=Gl(n);return{repoRoot:n,configPath:t}}function js(e){return mP(e)&&!ky(e).isDirectory()}Ke();function Jl(){return{services:{},templates:{},provenance:{}}}function Rn(e,t,r,n,o=""){if(M(t)&&Object.keys(t).length>0){for(let[i,s]of Object.entries(t))Rn(e,s,r,n,o===""?i:`${o}.${i}`);return}if(o==="")return;(e[o]??=[]).push({source:r,layer:n})}var vP=["environment","restart","startup","health","logs","identity","container","watch","hooks"];function Vl(e,t,r){let n=Dp(r);if(M(r))for(let i of vP){let s=r[i];if(M(s))for(let a of Object.keys(s))n.add(`${i}.${a}`)}let o=e[t];e[t]=o?new Set([...o,...n]):n}function Cy(e,t,r=Jl(),n={source:"unknown",layer:"unknown"}){if(Rn(r.provenance,t,n.source,n.layer),t.version!==void 0)e.version=Te(t.version);if(M(t.project)&&t.project.name!==void 0)e.project.name=q(t.project.name);if(M(t.google)){if(t.google.project_id!==void 0)e.google.project_id=q(t.google.project_id);if(t.google.region!==void 0)e.google.region=q(t.google.region)}if(M(t.profiles))for(let[o,i]of Object.entries(t.profiles)){let s=e.profiles[o];e.profiles[o]=s?wP(s,i):ql(i)}if(M(t.templates))for(let[o,i]of Object.entries(t.templates)){let s=e.templates[o];e.templates[o]=s?Yl(s,i):Us(i),Vl(r.templates,o,i)}if(M(t.services))for(let[o,i]of Object.entries(t.services)){let s=e.services[o];e.services[o]=s?Yl(s,i):Us(i),Vl(r.services,o,i)}if(M(t.tasks))for(let[o,i]of Object.entries(t.tasks))e.tasks[o]=e.tasks[o]?xP(e.tasks[o],i):wy(i);if(M(t.proxy))Hp(e.proxy,t.proxy);if(M(t.logs)){if(t.logs.max_memory_events!==void 0)e.logs.max_memory_events=Te(t.logs.max_memory_events);if(M(t.logs.persistence)){let o=t.logs.persistence;if(o.enabled!==void 0)e.logs.persistence.enabled=tt(o.enabled);if(o.directory!==void 0)e.logs.persistence.directory=q(o.directory);if(o.retention_days!==void 0)e.logs.persistence.retention_days=Te(o.retention_days);if(o.max_session_logs!==void 0)e.logs.persistence.max_session_logs=Te(o.max_session_logs)}}if(M(t.auth)&&t.auth.refresh_threshold_seconds!==void 0)e.auth.refresh_threshold_seconds=Te(t.auth.refresh_threshold_seconds);if(M(t.shutdown)){if(t.shutdown.stop_services_on_exit!==void 0)e.shutdown.stop_services_on_exit=tt(t.shutdown.stop_services_on_exit);if(t.shutdown.grace_seconds!==void 0)e.shutdown.grace_seconds=Te(t.shutdown.grace_seconds)}if(M(t.ui)){if(t.ui.theme!==void 0)e.ui.theme=q(t.ui.theme);if(t.ui.keymap!==void 0)e.ui.keymap=an(t.ui.keymap)}if(M(t.secrets)){if(t.secrets.extra_markers!==void 0)e.secrets.extra_markers=Mt(t.secrets.extra_markers);if(t.secrets.extra_patterns!==void 0)e.secrets.extra_patterns=Mt(t.secrets.extra_patterns)}if(M(t.doctor)&&Array.isArray(t.doctor.tools))e.doctor.tools=t.doctor.tools.filter(M).map((o)=>({name:q(o.name),command:q(o.command)}));if(Array.isArray(t.plugins))e.plugins=t.plugins.filter(M).map((o)=>({path:q(o.path)})).filter((o)=>o.path!=="");if(M(t.environment)){if(Array.isArray(t.environment.sources))e.environment.sources=Mt(t.environment.sources);if(M(t.environment.secrets))e.environment.secrets={...e.environment.secrets,...an(t.environment.secrets)}}if(M(t.telemetry))yP(e.telemetry,t.telemetry);if(M(t.web))bP(e.web,t.web)}function yP(e,t){if(!M(t.otlp))return;let r=t.otlp;if(r.enabled!==void 0)e.otlp.enabled=tt(r.enabled);if(M(r.listen)){if(r.listen.host!==void 0)e.otlp.listen.host=q(r.listen.host);if(r.listen.port!==void 0)e.otlp.listen.port=Te(r.listen.port)}}function bP(e,t){if(t.enabled!==void 0)e.enabled=tt(t.enabled);if(M(t.listen)){if(t.listen.host!==void 0)e.listen.host=q(t.listen.host);if(t.listen.port!==void 0)e.listen.port=Te(t.listen.port)}}function Hp(e,t){if(t.enabled!==void 0)e.enabled=tt(t.enabled);if(t.gateway!==void 0)e.gateway=tt(t.gateway);if(t.credentials!==void 0)e.credentials=q(t.credentials);if(M(t.listen)){if(t.listen.host!==void 0)e.listen.host=q(t.listen.host);if(t.listen.port!==void 0)e.listen.port=Te(t.listen.port)}if(M(t.token_endpoint)){let r=t.token_endpoint;if(r.enabled!==void 0)e.token_endpoint.enabled=tt(r.enabled);if(r.host!==void 0)e.token_endpoint.host=q(r.host);if(r.port!==void 0)e.token_endpoint.port=Te(r.port)}if(Array.isArray(t.routes))e.routes=t.routes.map((r)=>Oo(r))}function wP(e,t){if(!M(t))return e;return{services:t.services!==void 0?Mt(t.services):e.services,environment:t.environment!==void 0?{...e.environment,...an(t.environment)}:e.environment}}function xP(e,t){if(!M(t))return e;return{command:t.command!==void 0?qr(t.command):e.command,shell:t.shell!==void 0?tt(t.shell):e.shell,working_dir:t.working_dir!==void 0?q(t.working_dir):e.working_dir,dependencies:t.dependencies!==void 0?Mt(t.dependencies):e.dependencies,environment:Ty(e.environment,t.environment)}}function Yl(e,t){if(!M(t))return e;let r=Dp(t),n={...e,environment:Ty(e.environment,t.environment),health:CP(e.health,t.health),identity:TP(e.identity,t.identity),logs:EP(e.logs,t.logs),restart:RP(e.restart,t.restart),startup:_P(e.startup,t.startup),container:PP(e.container,t.container),watch:kP(e.watch,t.watch),hooks:SP(e.hooks,t.hooks)};if(r.has("extends"))n.extends=q(t.extends);if(r.has("description"))n.description=q(t.description);if(r.has("command"))n.command=qr(t.command);if(r.has("shell"))n.shell=tt(t.shell);if(r.has("working_dir"))n.working_dir=q(t.working_dir);if(r.has("dependencies"))n.dependencies=Op(t.dependencies);if(r.has("ports"))n.ports=Mp(t.ports);if(r.has("capabilities"))n.capabilities=Mt(t.capabilities);if(r.has("proxy"))n.proxy=$p(t.proxy);if(r.has("expose"))n.expose=Fp(t.expose);return n}function kP(e,t){if(!M(t))return e;return{enabled:t.enabled!==void 0?tt(t.enabled):e.enabled,paths:t.paths!==void 0?Mt(t.paths):e.paths,debounce_ms:t.debounce_ms!==void 0?Nl(Te(t.debounce_ms)):e.debounce_ms,ignore:t.ignore!==void 0?Mt(t.ignore):e.ignore}}function SP(e,t){if(!M(t))return e;return{pre_start:t.pre_start!==void 0?qr(t.pre_start):e.pre_start,post_start:t.post_start!==void 0?qr(t.post_start):e.post_start}}function Ty(e,t){if(!M(t))return e;let r={...e.vars},n={...e.defaults},o=e.required;for(let[i,s]of Object.entries(t))if(i==="required")o=Mt(s);else if(i==="defaults")Object.assign(n,an(s));else r[i]=q(s);return{vars:r,required:o,defaults:n}}function CP(e,t){if(!M(t))return e;return{type:t.type!==void 0?q(t.type):e.type,url:t.url!==void 0?q(t.url):e.url,address:t.address!==void 0?q(t.address):e.address,command:t.command!==void 0?qr(t.command):e.command,interval_seconds:t.interval_seconds!==void 0?Te(t.interval_seconds):e.interval_seconds,timeout_seconds:t.timeout_seconds!==void 0?Te(t.timeout_seconds):e.timeout_seconds,start_period_seconds:t.start_period_seconds!==void 0?Te(t.start_period_seconds):e.start_period_seconds,unhealthy_threshold:t.unhealthy_threshold!==void 0?Te(t.unhealthy_threshold):e.unhealthy_threshold,healthy_reset_threshold:t.healthy_reset_threshold!==void 0?Te(t.healthy_reset_threshold):e.healthy_reset_threshold}}function TP(e,t){if(!M(t))return e;return{type:t.type!==void 0?q(t.type):e.type,mode:t.mode!==void 0?q(t.mode):e.mode,service_account:t.service_account!==void 0?q(t.service_account):e.service_account,config:t.config!==void 0&&M(t.config)?{...e.config??{},...t.config}:e.config}}function EP(e,t){if(!M(t))return e;return{stdout:t.stdout!==void 0?tt(t.stdout):e.stdout,stderr:t.stderr!==void 0?tt(t.stderr):e.stderr}}function RP(e,t){if(!M(t))return e;return{enabled:t.enabled!==void 0?tt(t.enabled):e.enabled,policy:t.policy!==void 0?q(t.policy):e.policy,max_retries:t.max_retries!==void 0?Te(t.max_retries):e.max_retries,backoff_seconds:t.backoff_seconds!==void 0?Te(t.backoff_seconds):e.backoff_seconds}}function _P(e,t){if(!M(t))return e;return{wait_for_healthy:t.wait_for_healthy!==void 0?tt(t.wait_for_healthy):e.wait_for_healthy,timeout_seconds:t.timeout_seconds!==void 0?Te(t.timeout_seconds):e.timeout_seconds}}function PP(e,t){if(!M(t))return e;let r=Np(t);if(!r)return e;return{image:t.image!==void 0?r.image:e?.image??"",runtime:t.runtime!==void 0?r.runtime:e?.runtime??"",ports:t.ports!==void 0?{...e?.ports??{},...r.ports}:e?.ports??{},env:t.env!==void 0?{...e?.env??{},...r.env}:e?.env??{},volumes:t.volumes!==void 0?r.volumes:e?.volumes??[]}}function Ey(e,t){let r=Object.keys(e.services).sort();for(let n of r){let o=e.services[n]?.proxy??[];if(o.length===0)continue;o.forEach((i,s)=>{let l={name:o.length===1?n:`${n}-${s+1}`,match:i.match,upstream:i.upstream,auth:i.auth},c=e.proxy.routes.length;if(e.proxy.routes.push(l),t)Rn(t,l,`synthesized from services.${n}.proxy`,"synthesized",`proxy.routes.${c}`)})}AP(e,t)}function Ry(e){let t=e.repoRoot||process.cwd(),r=e.proxy.credentials.trim()===""?"":ks(e.proxy.credentials.trim(),t);e.proxy.credentials=r;for(let n of e.proxy.routes){if(n.auth.client_id.trim()==="")continue;let o=(n.auth.credentials??"").trim();n.auth.credentials=o===""?r:ks(o,t)}}function AP(e,t){if(!e.proxy.enabled)return;let r=new Set(e.proxy.routes.map((n)=>n.name));for(let n of Object.keys(e.services).sort()){let o=e.services[n];if(!o)continue;if(!(o.expose.enabled!==!1&&(o.expose.enabled===!0||e.proxy.gateway&&Do(o.ports,"http")!==void 0))||r.has(n))continue;let a={name:n,match:{host:o.expose.host||`${n}.local`,path:""},upstream:{url:"",service:n,port:o.expose.port||"http"},auth:Fs()},l=e.proxy.routes.length;if(e.proxy.routes.push(a),r.add(n),t){let c=o.expose.enabled===!0?`services.${n}.expose`:"proxy.gateway";Rn(t,a,`synthesized from ${c}`,"synthesized",`proxy.routes.${l}`)}}}function _y(e,t=Jl()){if(Object.keys(e.templates).length===0)return;let r={};for(let[n,o]of Object.entries(e.services))r[n]=Py(e,o,t.services[n]??new Set,t,{});e.services=r}function Py(e,t,r,n,o){if(t.extends==="")return t;if(o[t.extends])throw Error(`template cycle involving "${t.extends}"`);let i=e.templates[t.extends]??qn();if(!e.templates[t.extends])throw Error(`service extends unknown template "${t.extends}"`);let s={...o,[t.extends]:!0},a=n.templates[t.extends]??new Set,l=Py(e,i,a,n,s),c=LP(l,t,r);return c.extends=t.extends,c}function LP(e,t,r){let n={...e};if(r.has("extends"))n.extends=t.extends;if(r.has("description"))n.description=t.description;if(r.has("command"))n.command=t.command;if(r.has("shell"))n.shell=t.shell;if(r.has("working_dir"))n.working_dir=t.working_dir;if(r.has("dependencies"))n.dependencies=t.dependencies;if(r.has("ports"))n.ports=t.ports;if(r.has("capabilities"))n.capabilities=t.capabilities;if(r.has("proxy"))n.proxy=t.proxy;if(r.has("container")){let o=t.container,i=e.container;n.container=o&&i?{image:r.has("container.image")?o.image:i.image,runtime:r.has("container.runtime")?o.runtime:i.runtime,ports:r.has("container.ports")?o.ports:i.ports,env:r.has("container.env")?o.env:i.env,volumes:r.has("container.volumes")?o.volumes:i.volumes}:o??i}if(r.has("watch"))n.watch=t.watch;return n.hooks={pre_start:r.has("hooks.pre_start")?t.hooks.pre_start:e.hooks.pre_start,post_start:r.has("hooks.post_start")?t.hooks.post_start:e.hooks.post_start},n.health={type:r.has("health.type")?t.health.type:e.health.type,url:r.has("health.url")?t.health.url:e.health.url,address:r.has("health.address")?t.health.address:e.health.address,command:r.has("health.command")?t.health.command:e.health.command,interval_seconds:r.has("health.interval_seconds")?t.health.interval_seconds:e.health.interval_seconds,timeout_seconds:r.has("health.timeout_seconds")?t.health.timeout_seconds:e.health.timeout_seconds,start_period_seconds:r.has("health.start_period_seconds")?t.health.start_period_seconds:e.health.start_period_seconds,unhealthy_threshold:r.has("health.unhealthy_threshold")?t.health.unhealthy_threshold:e.health.unhealthy_threshold,healthy_reset_threshold:r.has("health.healthy_reset_threshold")?t.health.healthy_reset_threshold:e.health.healthy_reset_threshold},n.identity={type:r.has("identity.type")?t.identity.type:e.identity.type,mode:r.has("identity.mode")?t.identity.mode:e.identity.mode,service_account:r.has("identity.service_account")?t.identity.service_account:e.identity.service_account,config:r.has("identity.config")?t.identity.config:e.identity.config},n.logs={stdout:r.has("logs.stdout")?t.logs.stdout:e.logs.stdout,stderr:r.has("logs.stderr")?t.logs.stderr:e.logs.stderr},n.restart={enabled:r.has("restart.enabled")?t.restart.enabled:e.restart.enabled,policy:r.has("restart.policy")?t.restart.policy:e.restart.policy,max_retries:r.has("restart.max_retries")?t.restart.max_retries:e.restart.max_retries,backoff_seconds:r.has("restart.backoff_seconds")?t.restart.backoff_seconds:e.restart.backoff_seconds},n.startup={wait_for_healthy:r.has("startup.wait_for_healthy")?t.startup.wait_for_healthy:e.startup.wait_for_healthy,timeout_seconds:r.has("startup.timeout_seconds")?t.startup.timeout_seconds:e.startup.timeout_seconds},n.environment={vars:{...e.environment.vars,...t.environment.vars},defaults:{...e.environment.defaults,...t.environment.defaults},required:r.has("environment.required")?t.environment.required:e.environment.required},n}ne();Ke();function Ay(e){if(e.version===0)throw T(ee,"version is required");if(e.version===Ii)return e;throw T(ee,`unsupported config version ${e.version} (expected ${Ii}); no migration is available`)}var Ly=["version","project","google","profiles","templates","services","tasks","proxy","logs","auth","shutdown","ui","secrets","doctor","plugins","environment","telemetry","web"],Iy=["extends","description","command","shell","working_dir","dependencies","ports","environment","health","identity","logs","restart","startup","capabilities","proxy","expose","container","watch","hooks"],Dy=["type","url","address","command","interval_seconds","timeout_seconds","start_period_seconds","unhealthy_threshold","healthy_reset_threshold"],Oy=["service","condition"],My=["type","mode","service_account","config"],Ny=["enabled","policy","max_retries","backoff_seconds"],Fy=["wait_for_healthy","timeout_seconds"],$y=["enabled","host","port"],Hy=["enabled","gateway","credentials","listen","token_endpoint","routes"],Di=["host","port"],Up=["name","transport","listen","match","upstream","auth","response_headers"],jp=["host","path"],Bp=["url","service","port"],Wp=["type","identity","audience","service_account","client_id","client_secret","credentials","headers"],Uy=["max_memory_events","persistence"],jy=["enabled","directory","retention_days","max_session_logs"],By=["refresh_threshold_seconds"],Wy=["stop_services_on_exit","grace_seconds"],zy=["theme","keymap"],qy=["name"],Gy=["project_id","region"],Ky=["services","environment"],zp=["required","defaults"],Vy=["stdout","stderr"],Yy=["extra_markers","extra_patterns"],Jy=["tools"],Xy=["name","command"],Qy=["enabled","host","port"],Zy=["path"],eb=["sources","secrets"],tb=["image","runtime","ports","env","volumes"],rb=["enabled","paths","debounce_ms","ignore"],nb=["pre_start","post_start"],ob=["command","shell","working_dir","dependencies","environment"],ib=["otlp"],sb=["enabled","listen"],ab=["enabled","listen"],lb=["google","google_api","iap","network","service_identity","local_http"],cb=["|","||","&&",";",">",">>","<","&"];var IP=2;function Jn(e,t){if(Array.isArray(e))return e.flatMap((o,i)=>Jn(o,ub(t,String(i))));if(!HP(e))return[];let r=OP(t),n=[];for(let o of Object.keys(e)){let i=ub(t,o);if(r.length>0&&!r.includes(o)&&!DP(t))n.push(i);n.push(...Jn(e[o],i))}return n}function DP(e){if(e==="services"||e==="profiles"||e==="templates"||e==="tasks")return!0;if(e.endsWith(".environment")||e.endsWith(".defaults")||e.endsWith(".keymap"))return!0;if(e.endsWith(".container.ports")||e.endsWith(".container.env"))return!0;if(e.endsWith(".auth.headers")||e.endsWith(".response_headers"))return!0;if(e.endsWith(".identity.config")||e.includes(".identity.config."))return!0;return e.includes(".environment.")&&!e.endsWith(".environment")}function OP(e){switch(e){case"":return Ly;case"project":return qy;case"google":return Gy;case"proxy":return Hy;case"proxy.listen":return Di;case"proxy.token_endpoint":return Qy;case"logs":return Uy;case"logs.persistence":return jy;case"auth":return By;case"shutdown":return Wy;case"ui":return zy;case"secrets":return Yy;case"doctor":return Jy;case"environment":return eb;case"telemetry":return ib;case"telemetry.otlp":return sb;case"telemetry.otlp.listen":return Di;case"web":return ab;case"web.listen":return Di;default:return MP(e)}}function MP(e){if(e==="services"||e==="profiles"||e==="templates"||e==="tasks")return[];if(e.startsWith("services.")||e.startsWith("templates.")){if(e.includes(".dependencies."))return Oy;return NP(e)}if(e.startsWith("profiles.")){if(e.split(".").length===2)return Ky}if(e.startsWith("tasks.")){let t=e.split(".");if(t.length===2)return ob;if(t[2]==="environment")return zp}if(e.includes("routes"))return $P(e);if(e.startsWith("doctor.tools")&&e.split(".").length>=3)return Xy;if(e==="plugins")return[];if(e.startsWith("plugins.")&&e.split(".").length===2)return Zy;return[]}function NP(e){let t=e.split(".");if(t.length===2)return Iy;if(t.length>=3)switch(t[2]){case"health":return Dy;case"identity":return My;case"restart":return Ny;case"startup":return Fy;case"logs":return Vy;case"environment":return zp;case"proxy":return FP(t);case"expose":return $y;case"container":return tb;case"watch":return rb;case"hooks":return nb;default:return[]}return[]}function FP(e){let t=e.slice(3),r=t[0]!==void 0&&/^\d+$/.test(t[0])?1:0,n=t[r]??"";if(n==="match")return jp;if(n==="upstream")return Bp;if(n==="auth")return Wp;if(n==="listen")return Di;return Up}function $P(e){if(e==="proxy.routes")return[];if(e.endsWith(".match"))return jp;if(e.endsWith(".upstream"))return Bp;if(e.endsWith(".auth"))return Wp;if(e.endsWith(".listen"))return Di;if(e.includes("proxy.routes")&&e.split(".").length===IP+1)return Up;return[]}function ub(e,t){if(e==="")return t;return`${e}.${t}`}function HP(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Oi(e){return`unknown fields: ${e.join(", ")}`}Ke();function _t(e){let t=e.trim().toLowerCase();if(t==="")return!0;if(t==="localhost"||t==="::1")return!0;if(fb(t))return!0;return qP(t)}function qp(e){let t=WP(e);if(t==="")return!1;if(_t(t))return!0;return GP(t)}function db(e){let t=e.trim().toLowerCase();if(t==="")return;if(t.startsWith("["))return UP(t);let r=jP(t);if(r!==void 0)return r;let n=t.lastIndexOf(":");if(n===-1)return t;return t.slice(0,n)}function pb(e,t){let r=e.trim(),n=r===""?"127.0.0.1":r;if(n.includes(":")&&!n.startsWith("["))return`[${n}]:${t}`;return`${n}:${t}`}function UP(e){let t=e.indexOf("]");if(t<2)return;let r=e.slice(t+1);if(r!==""&&!r.startsWith(":"))return;return e.slice(1,t)}function jP(e){if(KP(e)<2)return;return BP(e)??e}function BP(e){let t=/^::ffff:(\d+\.\d+\.\d+\.\d+):(\d+)$/.exec(e);if(t?.[1]!==void 0)return`::ffff:${t[1]}`;if(/^::1:\d+$/.test(e))return"::1";return}function WP(e){let t=e.trim().toLowerCase();if(t.startsWith("[")&&t.endsWith("]"))t=t.slice(1,-1);return t=zP(t),t.replace(/\.+$/,"")}function zP(e){let t=e.indexOf("%");if(t===-1)return e;return e.slice(0,t)}function fb(e){let t=e.split(".");if(t.length!==4)return!1;let r=t.map((n)=>Number(n));if(r.some((n)=>!Number.isInteger(n)||n<0||n>255))return!1;return r[0]===127}function qP(e){if(!e.startsWith("::ffff:"))return!1;return fb(e.slice(7))}function GP(e){let t=e.split(":");if(t.length!==8)return!1;return t.every((r,n)=>{if(!/^[0-9a-f]{1,4}$/.test(r))return!1;let o=Number.parseInt(r,16);return n===7?o===1:o===0})}function KP(e){return e.split(":").length-1}import{existsSync as JP}from"fs";import{isAbsolute as XP,resolve as QP}from"path";import{fileURLToPath as ZP}from"url";Ke();function mb(e,t){if(t){if(t.http!==void 0)return t.http;let n=Object.values(t)[0];if(n!==void 0)return n}let r=hy(e.ports);if(r&&!r.auto)return r.value;return}function VP(e,t,r,n=""){let o=e,i="";for(;;){let s=o.indexOf("${");if(s<0)return i+o;i+=o.slice(0,s);let a=o.slice(s).indexOf("}");if(a<0)throw Error(`unclosed environment reference in "${e}"`);let l=o.slice(s+2,s+a);i+=YP(l,t,r,n),o=o.slice(s+a+1)}}function YP(e,t,r,n){let o=e.split(".");if(o[0]==="identity"){if(o.length===2&&o[1]==="user")return n;throw Error(`unsupported reference \${${e}}`)}if(o.length<3||o[0]!=="services")throw Error(`unsupported reference \${${e}}`);let i=o[1]??"",s=t.services[i];if(!s)throw Error(`reference \${${e}}: unknown service`);let a=r[i];if(o[2]==="host"||o[2]==="url"){let l=t.proxy.enabled?t.proxy.routes.find((u)=>u.upstream.service===i):void 0;if(o[2]==="host")return l?l.match.host||"127.0.0.1":"127.0.0.1";if(l)return`http://${l.match.host||"127.0.0.1"}:${t.proxy.listen.port}${l.match.path}`;let c=mb(s,a);if(c===void 0)throw Error(`unresolvable reference \${${e}}`);return`http://127.0.0.1:${c}`}if(o[2]==="port"){let l=mb(s,a);if(l!==void 0)return String(l)}if(o[2]==="ports"){let l=o[3];if(!l)throw Error(`reference \${${e}}: missing port name`);if(a&&a[l]!==void 0)return String(a[l]);let c=Do(s.ports,l);if(c&&!c.auto)return String(c.value);let u=Number.parseInt(l,10);if(!Number.isNaN(u)&&u>=0&&u<s.ports.length){let d=s.ports[u];if(d&&!d.auto)return String(d.value)}}throw Error(`unresolvable reference \${${e}}`)}function Gp(e,t,r,n=""){let o={};for(let[i,s]of Object.entries(e))o[i]=VP(s,t,r,n);return o}function hb(e){let t=[],r=e;for(;;){let n=r.indexOf("${");if(n<0)return t;let o=r.slice(n).indexOf("}");if(o<0)return t;t.push(r.slice(n+2,n+o)),r=r.slice(n+o+1)}}function gb(e,t){let r=e.split(".");if(r.length<2)return!1;if(r[0]==="identity")return r.length===2&&r[1]==="user";if(r[0]!=="services"||r.length<3)return!1;let n=t.services[r[1]??""];if(!n)return!1;if(r[2]==="port"||r[2]==="ports"){if(r.length===3)return n.ports.length>0;if(r.length>=4){let o=r[3]??"";if(!Number.isNaN(Number.parseInt(o,10)))return!0;return Do(n.ports,o)!==void 0}}return!0}Ke();var No=65535,Fo=1,kb=["http","tcp","process","command"];function Vp(e){let t=[];for(let[r,n]of Object.entries(e.services)){let o=n.health.type;if(o!==""&&!kb.includes(o.toLowerCase()))t.push({service:r,type:o})}return t}var eA=0,wb=1,xb=2;function $o(e){let t=[];if(e.version===0)t.push("version is required");else if(e.version!==Ii)t.push(`unsupported config version ${e.version} (expected ${Ii}); no migration is available`);if(Object.keys(e.services).length===0)t.push("at least one service must be defined");t.push(...rA(e)),t.push(...tA(e)),t.push(...sA(e)),t.push(...aA(e)),t.push(...lA(e)),t.push(...fA(e)),t.push(...mA(e));for(let[r,n]of e.plugins.entries())if(n.path==="")t.push(`plugins.${r}.path is required`);else try{let o=n.path.startsWith("file:")?ZP(n.path):XP(n.path)?n.path:QP(e.repoRoot,n.path);if(!JP(o))t.push(`plugins.${r}.path does not exist: ${n.path}`)}catch{t.push(`plugins.${r}.path is invalid: ${n.path}`)}if(e.logs.max_memory_events<0)t.push("logs.max_memory_events must be >= 0");return t}function tA(e){let t=[];for(let[r,n]of Object.entries(e.tasks)){let o=`tasks.${r}`;if(Gn(n.command))t.push(`${o}.command is required`);t.push(...Ql(o,n.command,n.shell));for(let i of n.dependencies)if(!e.services[i])t.push(`${o}.dependencies: unknown service "${i}"`);t.push(...Sb(`${o}.environment`,n.environment,e))}return t}function rA(e){let t=[],r={};for(let[n,o]of Object.entries(e.services)){let i=`services.${n}`;if(Gn(o.command)&&!o.container)t.push(`${i}.command is required`);t.push(...Ql(i,o.command,o.shell)),t.push(...Ql(`${i}.hooks.pre_start`,o.hooks.pre_start,o.shell)),t.push(...Ql(`${i}.hooks.post_start`,o.hooks.post_start,o.shell)),t.push(...gA(i,o.capabilities));for(let l of o.dependencies){let c=lr(l);if(!e.services[c])t.push(`${i}.dependencies: unknown service "${c}"`);if(c===n)t.push(`${i}.dependencies: service cannot depend on itself`);if(!["service_started","service_healthy"].includes(zn(l)))t.push(`${i}.dependencies: condition must be service_started or service_healthy`);if(zn(l)==="service_healthy"&&e.services[c]?.health.type==="")t.push(`${i}.dependencies: service_healthy requires ${c} to define a health check`)}if(o.extends!==""&&!e.templates[o.extends])t.push(`${i}.extends: unknown template "${o.extends}"`);for(let l of o.ports.filter((c)=>!c.auto))if(l.value<Fo||l.value>No)t.push(`${i}.ports.${l.name}: invalid port ${l.value}`);else if(r[l.value])t.push(`duplicate port ${l.value} used by ${r[l.value]} and ${n}`);else r[l.value]=n;let s=iA(`${i}.identity`,o.identity,e.plugins.length>0);if(s!=="")t.push(s);if(t.push(...nA(i,o,e.plugins.length>0)),o.health.start_period_seconds<0)t.push(`${i}.health.start_period_seconds must be >= 0`);if(o.health.unhealthy_threshold<1)t.push(`${i}.health.unhealthy_threshold must be >= 1`);if(o.health.healthy_reset_threshold<1)t.push(`${i}.health.healthy_reset_threshold must be >= 1`);let a=$l(o.restart);if(a!==Dl&&a!==Ol&&a!==Ml)t.push(`${i}.restart.policy must be never, on_failure, or always`);if(t.push(...Sb(`${i}.environment`,o.environment,e)),o.container){if(o.container.image==="")t.push(`${i}.container.image is required`);if(o.container.runtime!==""&&o.container.runtime!=="docker"&&o.container.runtime!=="podman")t.push(`${i}.container.runtime must be docker or podman`);for(let[l,c]of Object.entries(o.container.ports)){if(!o.ports.some((u)=>u.name===l))t.push(`${i}.container.ports.${l}: no matching service port`);if(c<Fo||c>No)t.push(`${i}.container.ports.${l}: invalid container port ${c}`)}}}return t}function nA(e,t,r){let n=[];if(t.health.type==="")return n;let o=t.health.type.toLowerCase();if(!kb.includes(o)&&!r)n.push(`${e}.health.type must be http, tcp, process, or command`);if(o==="http"&&t.health.url==="")n.push(`${e}.health.url is required for http health checks`);if(o==="tcp"&&t.health.address===""&&t.ports.length===0)n.push(`${e}.health.address is required for tcp health checks without ports`);if(o==="command"&&Gn({args:t.health.command.args,shell:!1}))n.push(`${e}.health.command is required for command health checks`);return n}var oA=["","user","service","service_account"];function iA(e,t,r){let n=Hs(t).toLowerCase();if(n===""||n==="user")return"";if(n==="service"||n==="service_account"){if(t.service_account==="")return`${e}.service_account is required for service identity`;if(!t.service_account.includes("@"))return`${e}.service_account must be an email`;return""}if(r)return"";return`${e}.type must be user or service_account`}function Yp(e){let t=[];for(let[r,n]of Object.entries(e.services)){let o=Hs(n.identity).toLowerCase();if(!oA.includes(o))t.push({service:r,type:o})}return t}function sA(e){let t={},r=[],n=[],o=(i)=>{let s=t[i]??eA;if(s===xb)return;if(s===wb){r.push(`dependency cycle: ${[...n,i].join(" \u2192 ")}`);return}t[i]=wb,n.push(i);let a=e.services[i];if(a)for(let l of a.dependencies){let c=lr(l);if(e.services[c])o(c)}n.pop(),t[i]=xb};for(let i of Object.keys(e.services))o(i);return r}function Sb(e,t,r){let n=[],o=(i,s)=>{for(let a of hb(s))if(!gb(a,r))n.push(`${e}.${i}: unresolvable reference \${${a}}`)};for(let[i,s]of Object.entries(t.vars))o(i,s);for(let[i,s]of Object.entries(t.defaults))o(i,s);return n}function aA(e){let t=[];for(let[r,n]of Object.entries(e.profiles))for(let o of n.services)if(!e.services[o])t.push(`profiles.${r} references unknown service "${o}"`);return t}function lA(e){let t=[];if(e.proxy.listen.host!==""){if(!Cb(e.proxy.listen.host))t.push("proxy.listen.host must be an IP address or localhost");else if(!_t(e.proxy.listen.host))t.push("proxy.listen.host must be a loopback address")}if(e.proxy.enabled&&e.proxy.listen.port===0)t.push("proxy.listen.port is required when proxy.enabled is true");if(e.proxy.listen.port!==0&&(e.proxy.listen.port<Fo||e.proxy.listen.port>No))t.push("proxy.listen.port is invalid");let r={},n=new Set;return e.proxy.routes.forEach((o,i)=>{let s=`proxy.routes[${i}]`;if(o.name==="")t.push(`${s}.name is required`);else if(r[o.name])t.push(`${s}: duplicate route name ${o.name}`);r[o.name]=!0;let a=(o.transport??"").toLowerCase();if(a!==""&&a!=="http"&&a!=="grpc")t.push(`${s}.transport must be "http" or "grpc"`);if(t.push(...uA(o,s,e)),t.push(...dA(o,s)),Wn(o))t.push(...cA(o,s,n,e))}),t.push(...hA(e)),t}function cA(e,t,r,n){let o=[],i=e.listen;if(!i||i.port===0)o.push(`${t}.listen.port is required for a grpc route`);else{if(i.port<Fo||i.port>No)o.push(`${t}.listen.port is invalid`);if(r.has(i.port))o.push(`${t}.listen.port ${i.port} is already used by another grpc route`);if(r.add(i.port),i.port===n.proxy.listen.port)o.push(`${t}.listen.port must differ from proxy.listen.port`);if(n.proxy.token_endpoint.enabled&&i.port===n.proxy.token_endpoint.port)o.push(`${t}.listen.port must differ from proxy.token_endpoint.port`);if(i.host!==""&&(!Cb(i.host)||!_t(i.host)))o.push(`${t}.listen.host must be a loopback address`)}if(!(e.upstream.url??"").trim().toLowerCase().startsWith("https://"))o.push(`${t}.upstream.url must be an https:// address for a grpc route`);if(e.match.host!==""||e.match.path!=="")o.push(`${t}.match is not supported on a grpc route`);if(e.response_headers&&Object.keys(e.response_headers).length>0)o.push(`${t}.response_headers is not supported on a grpc route`);return o}function uA(e,t,r){let n=[],o=e.upstream.url!=="",i=e.upstream.service??"";if(i===""){if(!o)n.push(`${t}.upstream requires either url or service`);return n}let s=r.services[i];if(!s)return n.push(`${t}.upstream.service references unknown service ${i}`),n;let a=e.upstream.port||"http";if(Do(s.ports,a)===void 0)n.push(`${t}.upstream: service ${i} has no port named ${a}`);return n}function dA(e,t){let r=[];if(e.auth.type.toLowerCase()==="iap"){if(e.auth.audience.trim()==="")r.push(`${t}.auth.audience is required when auth.type is iap`);if(e.auth.identity.type.trim()==="")r.push(`${t}.auth.identity.type is required when auth.type is iap`)}r.push(...pA(e.auth,t));let n=e.auth.identity.type.toLowerCase();if(n==="service"||n==="service_account"||Tn({type:n,mode:"",service_account:""})){if((e.auth.identity.service_account||e.auth.service_account)==="")r.push(`${t}.auth.identity.service_account is required`)}return r}function pA(e,t){let r=(e.client_id??"").trim(),n=(e.client_secret??"").trim(),o=(e.credentials??"").trim();if(r===""&&n===""&&o==="")return[];if(e.type.toLowerCase()!=="iap")return[`${t}.auth.${r!==""?"client_id":n!==""?"client_secret":"credentials"} is only valid when auth.type is iap`];let i=[];if(r===""){if(n!=="")i.push(`${t}.auth.client_id is required when client_secret is set`);if(o!=="")i.push(`${t}.auth.credentials requires auth.client_id`);return i}if(n===""&&o==="")i.push(`${t}.auth.client_secret is required when client_id is set`);else if(n!==""&&Kp(n).length>0&&!bb(n))i.push(`${t}.auth.client_secret must be a literal or a single \${NAME} / \${env.NAME} reference`);let s=e.identity.type.toLowerCase();if(s==="service"||s==="service_account")i.push(`${t}.auth.client_id is only valid with identity.type user`);return i}function fA(e){let t=[],r=e.telemetry.otlp.listen.host||Ot;if(!_t(r))t.push("telemetry.otlp.listen.host must be a loopback address");let n=e.telemetry.otlp.listen.port;if(n!==0&&(n<Fo||n>No))t.push("telemetry.otlp.listen.port is invalid");if(n!==0){if(e.proxy.listen.port===n)t.push("telemetry.otlp.listen.port must differ from proxy.listen.port");if(e.proxy.token_endpoint.enabled&&e.proxy.token_endpoint.port===n)t.push("telemetry.otlp.listen.port must differ from proxy.token_endpoint.port");e.proxy.routes.forEach((o,i)=>{if(Wn(o)&&o.listen&&o.listen.port===n)t.push(`telemetry.otlp.listen.port must differ from proxy.routes[${i}].listen.port`)})}return t}function mA(e){let t=[],r=e.web.listen.host||Ot;if(!_t(r))t.push("web.listen.host must be a loopback address");let n=e.web.listen.port;if(n!==0&&(n<Fo||n>No))t.push("web.listen.port is invalid");if(n!==0){if(e.proxy.listen.port===n)t.push("web.listen.port must differ from proxy.listen.port");if(e.proxy.token_endpoint.enabled&&e.proxy.token_endpoint.port===n)t.push("web.listen.port must differ from proxy.token_endpoint.port");if(e.telemetry.otlp.listen.port===n)t.push("web.listen.port must differ from telemetry.otlp.listen.port");e.proxy.routes.forEach((o,i)=>{if(Wn(o)&&o.listen&&o.listen.port===n)t.push(`web.listen.port must differ from proxy.routes[${i}].listen.port`)})}return t}function hA(e){let t=[],r=e.proxy.token_endpoint;if(!r.enabled)return t;let n=r.host||Ot;if(!_t(n))t.push("proxy.token_endpoint.host must be a loopback address");if(r.port!==0&&(r.port<Fo||r.port>No))t.push("proxy.token_endpoint.port is invalid");return t}function Ql(e,t,r){if(t.shell||r)return[];for(let n of t.args)if(cb.includes(n)||n.includes("|")||n.includes(";")||n.includes("&&"))return[`${e}.command contains shell metacharacters; set shell: true to run via a shell`];return[]}function gA(e,t){let r=[];for(let n of t)if(!lb.includes(n))r.push(`${e}.capabilities: unknown capability "${n}"`);return r}function Cb(e){if(e==="localhost")return!0;return vA(e)}function vA(e){if(/^(\d{1,3}\.){3}\d{1,3}$/.test(e))return e.split(".").every((r)=>{let n=Number(r);return n>=0&&n<=255});return e.includes(":")}function Bs(e,t,r){try{return Ws(e,t,{candidateText:r}),[]}catch(n){if(n instanceof et){let o=`${n.kind}: `;return[n.message.startsWith(o)?n.message.slice(o.length):n.message]}return[n instanceof Error?n.message:String(n)]}}function _n(e,t){let{repoRoot:r,configPath:n}=Mo(e,t);return Ws(r,n)}function Uo(e,t){try{return _n(e,t)}catch(r){if(!Al(r,Po))throw r;let n=e===""?process.cwd():kA(e),o=Io();return o.repoRoot=n,o.configPath=Ho(n,Yt,_r),o}}function Ws(e,t,r){let n=Io(),o=Jl();Rb(t,n,o,r?.candidateText,"main"),n.repoRoot=e,n.configPath=t;let i=wA(t);if(Eb(i)===Yt)TA(i,n,o);n=CA(n,e,t,o),n=Ay(n);try{_y(n,o)}catch(a){throw ge(ee,"template merge failed",a)}Ey(n,o.provenance),Ry(n),n.provenance=o.provenance;let s=$o(n);if(s.length>0)throw T(ee,s.join(`
|
|
2513
|
+
`));return n}function CA(e,t,r,n){let o=Ho(Er(),"config.local.yaml"),i=Ho(t,Yt,"config.local.yaml");for(let s of[o,i]){if(s===r||!js(s))continue;Rb(s,e,n,void 0,s===o?"home_local":"repo_local")}return e}function Rb(e,t,r,n,o="main"){let i=n!==void 0?_b(n,e):Jp(e),s=Jn(i,"");if(s.length>0)throw T(ee,Oi(s));Cy(t,i,r,{source:e,layer:o})}function TA(e,t,r){Tb(Ho(e,"services"),(o,i,s)=>{let a=Jn(i,`services.${o}`);if(a.length>0)throw T(ee,Oi(a));let l=t.services[o];t.services[o]=l?Yl(l,i):Us(i),Vl(r.services,o,i),Rn(r.provenance,i,s,"modular_service",`services.${o}`)}),Tb(Ho(e,"profiles"),(o,i,s)=>{let a=Jn(i,`profiles.${o}`);if(a.length>0)throw T(ee,Oi(a));t.profiles[o]=ql(i),Rn(r.provenance,i,s,"modular_profile",`profiles.${o}`)});let n=Ho(e,"proxy","routes.yaml");if(js(n))EA(n,t,r)}function EA(e,t,r){let n=Jp(e);if(M(n.proxy))Rn(r.provenance,n.proxy,e,"modular_proxy","proxy");if(Array.isArray(n.routes))Rn(r.provenance,n.routes,e,"modular_proxy","proxy.routes");if(M(n.proxy)){let o=Jn({proxy:n.proxy},"");if(o.length>0)throw T(ee,Oi(o))}if(Array.isArray(n.routes))n.routes.forEach((o,i)=>{let s=Jn(o,`proxy.routes.${i}`);if(s.length>0)throw T(ee,Oi(s))});if(M(n.proxy)){let o={...n.proxy};if(delete o.routes,Hp(t.proxy,o),Array.isArray(n.proxy.routes))t.proxy.routes.push(...n.proxy.routes.map((i)=>Oo(i)))}if(Array.isArray(n.routes))t.proxy.routes.push(...n.routes.map((o)=>Oo(o)))}function Tb(e,t){let r;try{r=yA(e)}catch(n){if(RA(n))return;throw n}for(let n of r.sort()){let o=xA(n);if(o!==".yaml"&&o!==".yml")continue;let i=Ho(e,n),s=Jp(i);t(Eb(n,o),s,i)}}function Jp(e){let t;try{t=bA(e,"utf8")}catch(r){throw ge(ee,"unable to read config",r)}return _b(t,e)}function _b(e,t){let r;try{r=SA(e)}catch(n){throw ge(ee,`invalid YAML in ${t}`,n)}if(r===null||r===void 0)return{};if(!M(r))throw T(ee,`unable to decode config: ${t} is not a mapping`);return r}function RA(e){return typeof e==="object"&&e!==null&&"code"in e&&e.code==="ENOENT"}Ke();ne();Gr();import{existsSync as tc,readFileSync as PA}from"fs";import{homedir as Db}from"os";import{join as ef}from"path";var{spawn:tf}=globalThis.Bun;var AA="https://www.googleapis.com/auth/cloud-platform",Ob=1500,LA=2000;function Ni(){let e=globalThis;if(e.window&&typeof e.window.fetch!=="function")e.window.fetch=fetch}function rf(){let e=process.env.GOOGLE_APPLICATION_CREDENTIALS||ef(Db(),".config","gcloud","application_default_credentials.json");if(!tc(e))return"";try{let t=JSON.parse(PA(e,"utf8"));return typeof t.quota_project_id==="string"?t.quota_project_id:""}catch{return""}}async function Wo(e){let t={gcloudInstalled:await nf("gcloud"),adcAvailable:!1,userEmail:"",projectID:"",projectSource:""};if(e!=="")t.projectID=e,t.projectSource="configuration";else{let r=NA("GOOGLE_CLOUD_PROJECT","GCLOUD_PROJECT","GOOGLE_PROJECT");if(r!=="")t.projectID=r,t.projectSource="environment variable";else if(t.gcloudInstalled){let n=await Ib("core/project");if(n!=="")t.projectID=n,t.projectSource="gcloud configuration"}}if(qs())try{await Hb(IA(t),LA)}catch(r){t.adcAvailable=!1,t.error=Fi(r)}if(t.userEmail===""&&t.gcloudInstalled)t.userEmail=await Ib("core/account");return t}async function IA(e){Ni();let{GoogleAuth:t}=await import("google-auth-library"),r=new t({scopes:[AA]});await r.getClient(),e.adcAvailable=!0;let n=await r.getProjectId().catch(()=>"");if(e.projectID===""&&n)e.projectID=n,e.projectSource="application default credentials";let o=await DA(r);if(o!=="")e.userEmail=o}async function DA(e){try{let t=await e.getCredentials();if(t.client_email)return t.client_email}catch{}try{let t=await e.getClient(),r=typeof t.credentials?.id_token==="string"?t.credentials.id_token:"";if(r!==""){let n=OA(r);if(n!=="")return n}}catch{return""}return""}function OA(e){let t=e.split(".");if(t.length<2||!t[1])return"";try{let r=JSON.parse(Buffer.from(t[1],"base64url").toString("utf8"));return typeof r.email==="string"?r.email:""}catch{return""}}async function Mb(e){let t=await Wo(e);return Pr({kind:"user",email:t.userEmail,project:t.projectID,projectSource:t.projectSource,adcAvailable:t.adcAvailable})}async function Nb(){if(await tf({cmd:["gcloud","auth","application-default","login"],stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited!==0)throw Ie(Bn,"application-default login failed","run `gcloud auth application-default login`")}async function Fb(){if(await tf({cmd:["gcloud","auth","application-default","revoke","--quiet"],stdout:"ignore",stderr:"pipe"}).exited!==0)throw Ie(Bn,"failed to revoke application-default credentials","run `gcloud auth application-default revoke`")}function Fi(e){let t=MA(e).toLowerCase();if(Bo(t,["unauthorized_client"]))return Ie(Pl,"IAP OAuth client does not match the ADC refresh token","omit client_id to use ADC's default client, or login with an OAuth client that matches auth.client_id");if(Bo(t,["unauth","invalid_grant","token has been expired","expired"]))return Ie(Bn,"credential expired or invalid","run `devctl auth login` or `gcloud auth application-default login`");if(Bo(t,["api has not been used","has not been enabled","access not configured","service_disabled"]))return Ie(Ao,"required Google API is not enabled","enable the API in the target service account project; devctl will not enable APIs automatically");if(Bo(t,["permission","forbidden","iam"])){if(Bo(t,["serviceaccounttoken","iamcredentials","token creator","getaccesstoken"]))return Ie(_l,"cannot impersonate service account","ask an administrator to grant roles/iam.serviceAccountTokenCreator on the target service account");return Ie(Ao,"authorization failure","verify IAM permissions for the current user on this project")}if(t.includes("audience"))return Ie(Pl,"IAP audience is incorrect","set auth.audience on the proxy route to the IAP OAuth client ID");if(t.includes("iap"))return ge(Pl,"IAP authentication failure",e);if(t.includes("project"))return Ie(ee,"wrong or missing Google project","set google.project_id in .devctl/config.yaml");if(Bo(t,["timeout","network","connection refused","no such host"]))return ge($e,"network problem reaching Google Cloud",e);if(Bo(t,["adc","default credentials","could not find"]))return Ie(Bn,"application default credentials unavailable","run `gcloud auth application-default login`");return ge(Bn,"Google authentication failed",e)}function MA(e){let t=[],r=new Set,n=(o,i)=>{if(o===null||o===void 0||i>8||r.has(o))return;if(typeof o==="string"){t.push(o);return}if(typeof o!=="object")return;r.add(o);let s=o;for(let a of["message","reason","status","code","error_description","permission","service"])n(s[a],i+1);for(let a of["error","errors","details","response","data","cause","metadata"]){let l=s[a];if(Array.isArray(l))l.forEach((c)=>n(c,i+1));else n(l,i+1)}};return n(e,0),t.length>0?t.join(" "):String(e)}function Bo(e,t){return t.some((r)=>e.includes(r))}function NA(...e){for(let t of e){let r=process.env[t];if(r)return r}return""}async function nf(e){try{return(await $b(process.platform==="win32"?["where",e]:["which",e],Ob)).code===0}catch{return!1}}function qs(){let e=process.env.GOOGLE_APPLICATION_CREDENTIALS;if(e&&tc(e))return!0;if(tc(ef(Db(),".config","gcloud","application_default_credentials.json")))return!0;let t=process.env.APPDATA;return Boolean(t&&tc(ef(t,"gcloud","application_default_credentials.json")))}async function Ib(e){try{let t=await $b(["gcloud","config","get-value",e],Ob);if(t.code!==0)return"";let r=t.stdout.trim();if(r===""||r==="(unset)")return"";return r}catch{return""}}async function $b(e,t){let r=tf({cmd:e,stdout:"pipe",stderr:"ignore",env:{...process.env,CLOUDSDK_CORE_DISABLE_PROMPTS:"1",CLOUDSDK_CORE_DISABLE_USAGE_REPORTING:"true"}}),n=r.stdout?new Response(r.stdout).text():Promise.resolve("");try{let[o,i]=await Hb(Promise.all([n,r.exited]),t);return{code:i??1,stdout:o}}catch{return r.kill(),{code:1,stdout:""}}}function Hb(e,t){return new Promise((r,n)=>{let o=setTimeout(()=>n(Error("timeout")),t);e.then((i)=>{clearTimeout(o),r(i)},(i)=>{clearTimeout(o),n(i)})})}import{createHash as QA}from"crypto";import{readFileSync as ZA}from"fs";import{join as eL}from"path";import{GoogleAuth as Ks,Impersonated as tL}from"google-auth-library";var{spawn:lf}=globalThis.Bun;import{existsSync as nc,readdirSync as FA,readFileSync as Ub,unlinkSync as $A}from"fs";import{join as Gs}from"path";var cf="keychain-index.json",zo="devctl.credentials",sf=".cred.json";function af(e){return Gs(Ur(),`${ic(e)}${sf}`)}function oc(e){if(e==="file"||process.env.DEVCTL_HOME&&e!=="keychain")return new rc;if(e==="keychain"||process.platform==="darwin"||process.platform==="win32"||process.platform==="linux")return new jb(new rc);return new rc}class rc{backend="file";async get(e){let t=BA(e);if(!t||t.accessToken==="")return;return t}async set(e,t){jr(af(e),`${JSON.stringify({...jA(t),key:e})}
|
|
2514
|
+
`)}async delete(e){let t=af(e);if(nc(t))$A(t)}async list(){let e=Ur();if(!nc(e))return[];let t=[];for(let r of FA(e)){if(!r.endsWith(sf))continue;let n=r.slice(0,-sf.length),o=Bb(Gs(Ur(),r));if(!o)continue;t.push(Wb(o.key??n,o.record))}return t.sort((r,n)=>r.identity.localeCompare(n.identity))}}class jb{backend="keychain";fallback;constructor(e){this.fallback=e}async get(e){let t=await WA(e);if(t)return t;return this.fallback.get(e)}async set(e,t){if(!await zA(e,t))await this.fallback.set(e,t);HA(e)}async delete(e){await qA(e),await this.fallback.delete(e),UA(e)}async list(){let e=new Set(uf()),t=await this.fallback.list(),r=new Map;for(let n of t)r.set(n.key,n);for(let n of e){let o=await this.get(n);if(o)r.set(n,Wb(n,o))}return[...r.values()].sort((n,o)=>n.identity.localeCompare(o.identity))}}function HA(e){let t=uf();if(!t.includes(e))jr(Gs(Ur(),cf),`${JSON.stringify([...t,e])}
|
|
2515
|
+
`)}function UA(e){let t=uf(),r=t.filter((n)=>n!==e);if(r.length!==t.length)jr(Gs(Ur(),cf),`${JSON.stringify(r)}
|
|
2516
|
+
`)}function uf(){let e=Gs(Ur(),cf);if(!nc(e))return[];try{let t=JSON.parse(Ub(e,"utf8"));return Array.isArray(t)?t.filter((r)=>typeof r==="string"):[]}catch{return[]}}function jA(e){return{...e,accessToken:""}}function BA(e){return Bb(af(e))?.record}function Bb(e){if(!nc(e))return;try{let t=JSON.parse(Ub(e,"utf8"));if(typeof t.identity!=="string")return;return{key:typeof t.key==="string"&&t.key!==""?t.key:void 0,record:{identity:t.identity,audience:typeof t.audience==="string"?t.audience:"",scopes:Array.isArray(t.scopes)?t.scopes.filter((r)=>typeof r==="string"):[],accessToken:typeof t.accessToken==="string"?t.accessToken:"",tokenType:typeof t.tokenType==="string"?t.tokenType:"Bearer",expiresAt:typeof t.expiresAt==="string"?t.expiresAt:""}}}catch{return}}function Wb(e,t){let r=Date.parse(t.expiresAt);return{key:e,identity:t.identity,audience:t.audience,scopes:t.scopes,expires_at:t.expiresAt,valid:Number.isFinite(r)&&r-Date.now()>0}}function ic(e){return e.replace(/[^A-Za-z0-9._-]+/g,"_").slice(0,80)||"token"}async function WA(e){let t=await GA(e);if(!t)return;try{return JSON.parse(t)}catch{return}}async function zA(e,t){let r=JSON.stringify(t);if(process.platform==="darwin")return await $i(["security","delete-generic-password","-s",zo,"-a",e]),await $i(["security","add-generic-password","-s",zo,"-a",e,"-w",r,"-U"])===0;if(process.platform==="linux")return await KA(["secret-tool","store","--label",`devctl ${e}`,"service",zo,"account",e],r)===0;if(process.platform==="win32"){let o=`Add-Type -AssemblyName System.Security; $bytes = [Convert]::FromBase64String('${Buffer.from(r,"utf8").toString("base64")}'); $enc = [System.Security.Cryptography.ProtectedData]::Protect($bytes, $null, 'CurrentUser'); [IO.File]::WriteAllBytes($env:LOCALAPPDATA + '\\devctl-cred-${ic(e)}.bin', $enc)`;return await $i(["powershell","-NoProfile","-Command",o])===0}return!1}async function qA(e){if(process.platform==="darwin"){await $i(["security","delete-generic-password","-s",zo,"-a",e]);return}if(process.platform==="linux"){await $i(["secret-tool","clear","service",zo,"account",e]);return}if(process.platform==="win32")await $i(["powershell","-NoProfile","-Command",`Remove-Item -ErrorAction SilentlyContinue ($env:LOCALAPPDATA + '\\devctl-cred-${ic(e)}.bin')`])}async function GA(e){if(process.platform==="darwin"){let t=await of(["security","find-generic-password","-s",zo,"-a",e,"-w"]);return t.code===0&&t.stdout!==""?t.stdout:void 0}if(process.platform==="linux"){let t=await of(["secret-tool","lookup","service",zo,"account",e]);return t.code===0&&t.stdout!==""?t.stdout:void 0}if(process.platform==="win32"){let t=`$p = $env:LOCALAPPDATA + '\\devctl-cred-${ic(e)}.bin'; if (-not (Test-Path $p)) { exit 1 }; Add-Type -AssemblyName System.Security; $raw = [IO.File]::ReadAllBytes($p); $dec = [System.Security.Cryptography.ProtectedData]::Unprotect($raw, $null, 'CurrentUser'); [Text.Encoding]::UTF8.GetString($dec)`,r=await of(["powershell","-NoProfile","-Command",t]);return r.code===0&&r.stdout!==""?r.stdout:void 0}return}var df=3000;async function $i(e){try{return await lf({cmd:e,stdout:"ignore",stderr:"ignore",timeout:df}).exited}catch{return 1}}async function KA(e,t){try{return await lf({cmd:e,stdin:new TextEncoder().encode(t),stdout:"ignore",stderr:"ignore",timeout:df}).exited}catch{return 1}}async function of(e){try{let t=lf({cmd:e,stdout:"pipe",stderr:"ignore",timeout:df}),r=t.stdout?await new Response(t.stdout).text():"";return{code:await t.exited,stdout:r.trim()}}catch{return{code:1,stdout:""}}}ne();ne();var VA=3,YA=200;async function zb(e,t={}){let r=t.attempts??VA,n=t.backoffMs??YA,o=t.retry??JA,i=Error("retry exhausted");for(let s=0;s<r;s+=1)try{return await e()}catch(a){if(i=a,!o(a)||s===r-1)throw a;await XA(n*(s+1))}throw i}function JA(e){if(e instanceof et)return e.kind!==ee&&e.kind!==Ao;return!0}function XA(e){return new Promise((t)=>{setTimeout(t,e)})}var sc={now:()=>new Date,isoNow:()=>new Date().toISOString(),unixMs:()=>Date.now()};var pf=300000,rL=3000000,nL=3,oL=200,ac="https://www.googleapis.com/auth/cloud-platform",Gb="https://www.googleapis.com/auth/userinfo.email",iL="https://oauth2.googleapis.com/token";function qb(e,t,r,n){let o=n??"",i=`${e}|${t}|${r.join(",")}`;return o===""?i:`${i}|oauth:${o}`}function sL(e){let t;try{t=ZA(e,"utf8")}catch{throw T(ee,`IAP credentials file not found: ${e}`)}let r;try{r=JSON.parse(t)}catch{throw T(ee,`IAP credentials file is not valid JSON: ${e}`)}if(typeof r!=="object"||r===null)throw T(ee,`IAP credentials file is malformed: ${e}`);let n=r,o=typeof n.refresh_token==="string"?n.refresh_token:"";if(o==="")throw T(ee,`IAP credentials file has no refresh_token: ${e}`);let i=typeof n.client_id==="string"?n.client_id:"";if(i==="")throw T(ee,`IAP credentials file has no client_id: ${e}`);return{clientId:i,clientSecret:typeof n.client_secret==="string"?n.client_secret:"",refreshToken:o}}function aL(e,t=process.env){let r=(e.client_id??"").trim();if(r==="")return;let n=(e.client_secret??"").trim(),{value:o,missing:i}=yb(n,t),s=(e.credentials??"").trim();if(s!==""){let a=sL(s);if(a.clientId!==r)throw T(ee,`IAP credentials file ${s} is for client_id ${a.clientId}, not the route's ${r}`);let l=o!==""?o:a.clientSecret;if(l==="")throw T(ee,`IAP client_id ${r} requires a client_secret (in the route or ${s})`);return{clientId:r,clientSecret:l,refreshToken:a.refreshToken}}if(o===""){let a=i[0];throw T(ee,a?`IAP client_secret env ${a} is empty`:`IAP client_id ${r} requires client_secret`)}return{clientId:r,clientSecret:o}}function lc(e,t=process.env){let r=(e.client_id??"").trim();if(r==="")return;return{clientId:r,resolve:()=>{let n=aL(e,t);if(!n)throw T(ee,`IAP client_id ${r} requires client_secret`);return n}}}function lL(e,t=pf,r=Date.now()){if(e.accessToken==="")return!1;return e.expiresAt.getTime()-r>=t}function cL(e,t=pf,r=Date.now()){if(e.accessToken==="")return!0;let n=e.expiresAt.getTime()-r;return n>0&&n<t}class qo{cache=new Map;inflight=new Map;providers;thresholdMs;bus;store;clock;constructor(e,t,r,n,o=sc){this.thresholdMs=e>0?e:pf,this.providers=[...t],this.bus=r,this.store=n??oc(process.env.DEVCTL_CREDENTIAL_BACKEND==="file"?"file":void 0),this.clock=o}replaceProviders(e){this.providers.splice(0,this.providers.length,...e)}isValid(e){return lL(e,this.thresholdMs,this.clock.unixMs())}expiresSoon(e){return cL(e,this.thresholdMs,this.clock.unixMs())}invalidate(e){if(e===void 0||e===""){this.cache.clear(),this.clearStore();return}this.cache.delete(e),this.store.delete(e)}async listStatus(){return this.store.list()}storeBackend(){return this.store.backend}async get(e,t,r,n){let o=qb(e,t,r,n?.clientId),i=this.cache.get(o)??await this.loadStored(o);if(i&&this.isValid(i))return this.cache.set(o,i),i;return this.refresh(e,t,r,n)}async refresh(e,t,r,n){let o=qb(e,t,r,n?.clientId),i=this.inflight.get(o);if(i)return i;let s=this.refreshOnce(o,e,t,r,n);this.inflight.set(o,s);try{return await s}finally{this.inflight.delete(o)}}async refreshOnce(e,t,r,n,o){let i=o?.resolve(),s=this.providers.filter((l)=>!l.accepts||l.accepts(t,r,n,i));if(s.length===0)throw T(zr,`no token provider accepts identity ${t}`);let a=T(zr,"no token provider available");for(let l of s)try{let c=await zb(()=>l.fetch(t,r,n,i),{attempts:nL,backoffMs:oL,retry:TL});return this.cache.set(e,c),dL(e,c),await this.store.set(e,pL(c)),this.bus?.publish(Ce(bi,"",{identity:c.identity,audience:c.audience})),c}catch(c){a=c instanceof Error?c:Error(String(c))}throw this.bus?.publish(Ce(ko,"",{identity:t,audience:r,error:I(a)})),a}async loadStored(e){let t=await this.store.get(e);if(!t||t.accessToken==="")return;return fL(t)}async clearStore(){let e=await this.store.list();await Promise.all(e.map((t)=>this.store.delete(t.key)))}}function uL(e){let t=QA("sha256").update(e).digest("hex").slice(0,16);return eL(Ur(),`${t}.json`)}function dL(e,t){let r={identity:t.identity,audience:t.audience,expires_at:t.expiresAt.toISOString(),scopes:t.scopes};jr(uL(e),`${JSON.stringify(r)}
|
|
2517
|
+
`)}function pL(e){return{identity:e.identity,audience:e.audience,scopes:e.scopes,accessToken:e.accessToken,tokenType:e.tokenType,expiresAt:e.expiresAt.toISOString()}}function fL(e){return{accessToken:e.accessToken,tokenType:e.tokenType||"Bearer",expiresAt:new Date(e.expiresAt),audience:e.audience,identity:e.identity,scopes:e.scopes}}function Zn(){return[gL(),hL(),mL()]}function mL(){return{name:"user",accepts:(e,t)=>!e.startsWith("sa:")&&t==="",fetch:async(e,t,r)=>{if(e.startsWith("sa:"))throw T(zr,"user provider cannot mint service-account tokens");return kL(e,t,r)}}}function hL(){return{name:"service_account",accepts:(e,t)=>e.startsWith("sa:")&&t==="",fetch:async(e,t,r)=>{if(!e.startsWith("sa:"))throw T(zr,"service-account provider cannot mint user tokens");return vL(e,t,r)}}}function gL(){return{name:"iap",accepts:(e,t)=>t!=="",fetch:async(e,t,r,n)=>{if(t==="")throw T(zr,"IAP audience is required");if(e.startsWith("sa:"))return yL(e,t,r);return bL(e,t,r,n)}}}async function vL(e,t,r){let n=e.slice(3);try{Ni();let i=await new Ks({scopes:r.length>0?r:[ac]}).getClient(),s=new tL({sourceClient:i,targetPrincipal:n,targetScopes:r.length>0?r:[ac],lifetime:3600}),a=await s.getAccessToken(),l=typeof a==="string"?a:a?.token;if(!l)throw T(zr,"empty impersonated token");return{accessToken:l,tokenType:"Bearer",expiresAt:Vs(l,s),audience:t,identity:e,scopes:r}}catch(o){throw Fi(o)}}async function yL(e,t,r){let n=e.slice(3);try{Ni();let i=await new Ks({scopes:[ac]}).getClient(),s=`https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${encodeURIComponent(n)}:generateIdToken`,l=(await i.request({url:s,method:"POST",data:{audience:t,includeEmail:!0}})).data.token;if(!l)throw T(zr,"empty impersonated IAP id token");return{accessToken:l,tokenType:"Bearer",expiresAt:Vs(l),audience:t,identity:e,scopes:r}}catch(o){throw Fi(o)}}async function bL(e,t,r,n){try{if(Ni(),n)return await wL(e,t,r,n);let s=await(await new Ks({scopes:r.length>0?r:[Gb]}).getIdTokenClient(t)).idTokenProvider.fetchIdToken(t);return{accessToken:s,tokenType:"Bearer",expiresAt:Vs(s),audience:t,identity:e,scopes:r}}catch(o){if(o instanceof et)throw o;throw Fi(o)}}async function wL(e,t,r,n){let o=n.refreshToken;if(!o){if(o=(await new Ks({scopes:r.length>0?r:[Gb]}).getClient()).credentials.refresh_token??void 0,!o)throw Ie(Bn,"ADC has no refresh token for a custom IAP OAuth client","set auth.credentials (or proxy.credentials) to an authorized_user file whose refresh_token was issued by this client_id, or run `gcloud auth application-default login` with that client")}let i=await fetch(iL,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:xL(n,o,t)}),s=await i.text();if(!i.ok)throw Error(`IAP token exchange failed (${i.status}): ${s}`);let a;try{a=JSON.parse(s)}catch{throw T(zr,"IAP token endpoint returned a non-JSON response")}let l=a.id_token;if(!l)throw T(zr,"empty IAP id token");return{accessToken:l,tokenType:"Bearer",expiresAt:Vs(l),audience:t,identity:e,scopes:r}}function xL(e,t,r){return new URLSearchParams({grant_type:"refresh_token",client_id:e.clientId,client_secret:e.clientSecret,refresh_token:t,audience:r})}async function kL(e,t,r){try{Ni();let o=await new Ks({scopes:r.length>0?r:[ac]}).getClient(),i=await o.getAccessToken();if(!i.token)throw T(zr,"empty access token");return{accessToken:i.token,tokenType:"Bearer",expiresAt:SL(o,i.token),audience:t,identity:e,scopes:r}}catch(n){throw Fi(n)}}function Vs(e,t){if(t?.credentials?.expiry_date)return new Date(t.credentials.expiry_date);return CL(e)??new Date(Date.now()+rL)}function SL(e,t){return Vs(t,e)}function CL(e){let t=e.split(".");if(t.length<2||!t[1])return;try{let r=JSON.parse(Buffer.from(t[1],"base64url").toString("utf8"));if(typeof r.exp==="number")return new Date(r.exp*1000)}catch{return}return}function TL(e){if(e instanceof et)return e.kind!==ee&&e.kind!==Ao;let t=e instanceof Error?e.message.toLowerCase():String(e).toLowerCase();return t.includes("network")||t.includes("econnreset")||t.includes("etimedout")||t.includes("503")||t.includes("429")}ne();Gr();var Js=4000,EL=8000;function Hi(e){let t=e?.tokens,r=()=>(t??=new qo(60000,Zn(),void 0,oc("file")),t);return{detectGoogle:Wo,hasCommand:nf,portAvailable:Ai,hasLocalAdc:qs,adcQuotaProject:rf,mintToken:async(n,o,i)=>{await r().get(n,o,[],i)},probeServiceUsage:async(n,o)=>{let i=await Xs(r().get("user","",[]),Js),s=`https://serviceusage.googleapis.com/v1/projects/${n}/services/${o}`,a=await fetch(s,{headers:{Authorization:`Bearer ${i.accessToken}`},signal:AbortSignal.timeout(Js)});if(!a.ok)return!1;return(await a.json().catch(()=>{return}))?.state==="ENABLED"},containerRuntimeAvailable:async(n)=>{try{return await Bun.spawn({cmd:[n,"info"],stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited===0}catch{return!1}}}}var cc=Hi();function uc(e=Hi()){return{run:(t,r,n)=>RL(t,e,r,n)}}async function RL(e,t=cc,r,n){let o={checks:[],issues:0},i="Preparing diagnostics",s=()=>r?.({active:i,checks:[...o.checks]}),a=(p)=>{i=p,s()},l=(p)=>{if(o.checks.push(p),p.severity==="error")o.issues+=1;s()},c=[...new Set(Object.values(e.services).flatMap((p)=>p.container?[p.container.runtime||"docker"]:[]))];for(let p of c){a(`${p} container runtime`);let m=await t.hasCommand(p),h=m&&await(t.containerRuntimeAvailable??cc.containerRuntimeAvailable)(p);l(h?{name:`${p} container runtime`,severity:"ok",message:`${p} daemon reachable`}:{name:`${p} container runtime`,severity:"error",message:m?`${p} daemon is not reachable`:`${p} not found`,hint:`install and start ${p}`})}if(a("Google CLI installed"),await t.hasCommand("gcloud"))l({name:"Google CLI installed",severity:"ok",message:"gcloud found"});else l({name:"Google CLI installed",severity:zs(e)?"error":"warn",message:"gcloud not installed",hint:"install the Google Cloud CLI from https://cloud.google.com/sdk/docs/install"});a("Google environment");let u=await t.detectGoogle(e.google.project_id);if(u.adcAvailable)l({name:"Google authentication available",severity:"ok",message:"Application Default Credentials found"});else l({name:"Google authentication available",severity:zs(e)?"error":"warn",message:"ADC unavailable",hint:"run `gcloud auth application-default login`"});if(u.projectID!=="")l({name:"Project configured",severity:"ok",message:`${u.projectID} (source: ${u.projectSource})`});else l({name:"Project configured",severity:zs(e)?"error":"warn",message:"no Google project configured",hint:"set google.project_id in .devctl/config.yaml"});if(zs(e)||Object.values(e.services).some((p)=>p.capabilities.includes("google")||p.identity.type!=="")){a("Live Google access");let p=!0,m=(h)=>{if(p)l(h)};try{await Xs((async()=>{await PL(e,m,t,u.userEmail),await _L(e,m,t)})(),t.liveDeadlineMs??EL)}catch(h){m({name:"Live Google probes",severity:"warn",message:I(h),hint:"network or timeout \u2014 retry when online"})}finally{p=!1}}for(let p of e.doctor.tools){let m=p.command||p.name;if(a(`${p.name} installed`),await t.hasCommand(m))l({name:`${p.name} installed`,severity:"ok",message:`${m} found`});else l({name:`${p.name} installed`,severity:"error",message:`${m} not found`,hint:`install ${p.name} and ensure it is on PATH`})}if(a("Repository configuration"),n?.repositoryConfigError!==void 0)if(n.repositoryConfigError==="")l({name:"Repository configuration",severity:"ok",message:"valid"});else l({name:"Repository configuration",severity:"error",message:n.repositoryConfigError});else try{let p=$o(e);if(p.length>0)l({name:"Repository configuration",severity:"error",message:p.join("; ")});else l({name:"Repository configuration",severity:"ok",message:"valid"})}catch(p){l({name:"Repository configuration",severity:"error",message:I(p)})}let f={};for(let[p,m]of Object.entries(e.services))for(let h of m.ports){if(h.auto)continue;let g=`Port ${h.value}`;if(a(g),f[h.value])l({name:g,severity:"error",message:`configured on both ${f[h.value]} and ${p}`});else{f[h.value]=p;let w=n?.services?.[p],v=Boolean(m.container&&w&&["STARTING","RUNNING","HEALTHY","UNHEALTHY"].includes(w.state??""));if(Boolean(w&&(w.pid>0||v)&&Object.values(w.ports).includes(h.value)))l({name:g,severity:"ok",message:`in use by running service ${p}`});else if(await t.portAvailable(h.value))l({name:g,severity:"ok",message:"available"});else l(await Vb(g,h.value,`services.${p}.ports`))}}if(e.proxy.listen.port>0){let p=`Port ${e.proxy.listen.port}`;if(a(p),n?.proxyRunning)l({name:p,severity:"ok",message:"in use by the running proxy"});else if(await t.portAvailable(e.proxy.listen.port))l({name:p,severity:"ok",message:"proxy listen port available"});else l(await Vb(p,e.proxy.listen.port,"proxy.listen.port"))}return i="Diagnostics complete",s(),o}async function _L(e,t,r){let n=e.google.project_id,o=r.hasLocalAdc??qs;if(n===""||!o())return;let i=r.probeServiceUsage??cc.probeServiceUsage,s=[{name:"IAM Credentials API",service:"iamcredentials.googleapis.com"},{name:"Resource Manager API",service:"cloudresourcemanager.googleapis.com"},{name:"IAP API",service:"iap.googleapis.com"}];(await Promise.allSettled(s.map((l)=>Xs(i(n,l.service),Js)))).forEach((l,c)=>{let u=s[c];if(!u)return;if(l.status==="fulfilled"){t({name:u.name,severity:l.value?"ok":"warn",message:l.value?"enabled":"not enabled or unreachable",hint:l.value?void 0:`enable ${u.service} in the Google Cloud console \u2014 doctor never auto-enables APIs`});return}t({name:u.name,severity:"warn",message:I(l.reason),hint:`enable ${u.service} in the Google Cloud console \u2014 doctor never auto-enables APIs`})})}async function PL(e,t,r,n){let o=ln(e),i=e.proxy.routes.filter((d)=>d.auth.type.toLowerCase()==="iap"),s=i.filter((d)=>d.auth.audience.trim()!=="");for(let d of i)if(d.auth.audience.trim()==="")t({name:`IAP audience ${d.name}`,severity:"error",message:"missing audience",hint:"set auth.audience to the IAP OAuth client ID"});if(o.length===0&&s.length===0)return;if(!(r.hasLocalAdc??qs)())return;let l=r.mintToken??cc.mintToken,c=o.map(async(d)=>{try{await Xs(l(`sa:${d}`,""),Js),t({name:`Impersonate ${d}`,severity:"ok",message:"token minted"})}catch(f){let p=(r.adcQuotaProject??rf)(),m=n||"the ADC principal",h=p===""?"unknown":p,g=Kb(`Impersonate ${d}`,f,`grant roles/iam.serviceAccountTokenCreator to ${m} on ${d}; ADC quota project: ${h}`);if(p!==""&&g.message.toLowerCase().includes("api is not enabled"))g.message=`IAM Credentials API is disabled in ADC quota project ${p}`,g.hint=`enable iamcredentials.googleapis.com in ${p}, or set the ADC quota project to ${e.google.project_id}`;else if(g.message.toLowerCase()==="google authentication failed")g.message=`access-token mint failed: ${m} \u2192 ${d}`,g.hint=`verify roles/iam.serviceAccountTokenCreator for ${m} on this service account; ADC quota project: ${h}`;t(g)}}),u=s.map(async(d)=>{let f=Pn(d.auth).kind===jo?`sa:${Pn(d.auth).serviceAccount}`:"user";try{let p=lc(d.auth);await Xs(l(f,d.auth.audience,p),Js),t({name:`IAP ${d.name}`,severity:"ok",message:"id token minted"})}catch(p){t(Kb(`IAP ${d.name}`,p,"check IAP OAuth client ID and ADC"))}});await Promise.all([...c,...u])}function Kb(e,t,r){let n=I(t),o=n.toLowerCase();if(o.includes("timeout")||o.includes("network")||o.includes("econnrefused")||o.includes("enotfound"))return{name:e,severity:"warn",message:n,hint:"network or timeout \u2014 retry when online"};if(t instanceof et&&t.hint!==""){let i=`${t.kind}: `,s=t.message.startsWith(i)?t.message.slice(i.length):t.message;return{name:e,severity:"error",message:s,hint:t.hint}}return{name:e,severity:"error",message:n,hint:r}}function Xs(e,t){return new Promise((r,n)=>{let o=setTimeout(()=>n(Error("timeout")),t);e.then((i)=>{clearTimeout(o),r(i)},(i)=>{clearTimeout(o),n(i)})})}async function Vb(e,t,r){let n=await Lo(t);if(!n)return{name:e,severity:"error",message:"already in use",hint:`stop the process using port ${t} or change ${r}`};if(n.pid===process.pid)return{name:e,severity:"error",message:`in use by this TUI (${n.command} pid ${n.pid})`,hint:"stop the proxy from the proxy screen (x), then rerun doctor"};return{name:e,severity:"error",message:`in use by ${n.command} (pid ${n.pid})`,hint:"enter stop that process after a confirmation",action:{kind:"free-port",holder:n}}}function Yb(e){let t=[`${vr()} doctor`,""];for(let r of e.checks){let n=r.severity==="error"?"\u2717":r.severity==="warn"?"!":"\u2713";if(t.push(`${n} ${r.name}`),r.severity!=="ok"){if(t.push(` ${r.message}`),r.hint)t.push(` \u2192 ${r.hint}`)}}return t.push("",`${e.issues} issue(s) found.`),t.join(`
|
|
2512
2518
|
`)+`
|
|
2513
|
-
`}$t();class
|
|
2514
|
-
`);this.buf=r.pop()??"";for(let n of r){if(n.trim()==="")continue;this.onLine(n)}}),e.on("error",(t)=>this.rejectPending(t instanceof Error?t:Error(String(t)))),e.on("close",()=>this.rejectPending(Error("supervisor connection closed")))}onLine(e){let t;try{t=JSON.parse(e)}catch{return}if(t.event){for(let n of this.listeners)n(t.event);return}let r=t.id?this.pending.get(t.id):void 0;if(!r)return;if(this.pending.delete(t.id??""),clearTimeout(r.timer),t.error){r.reject(
|
|
2515
|
-
`)})}close(){this.rejectPending(Error("supervisor connection closed")),this.socket.destroy()}rejectPending(e){for(let t of this.pending.values())clearTimeout(t.timer),t.reject(e);this.pending.clear()}}function
|
|
2516
|
-
`)}async function
|
|
2517
|
-
`).find((i)=>i.startsWith("n"));if(r&&r.length>1)return r.slice(1).trim();let n=await oa(["pwdx",String(e)]),o=n.indexOf(":");if(o>=0)return n.slice(o+1).trim();return""}async function oa(e){try{let t=
|
|
2518
|
-
`)){let o=n.trim();if(o==="")continue;let[i,s,a]=o.split(/\s+/),l=Number(i),c=Number(s),u=Number(a);if(Number.isFinite(l)&&Number.isFinite(c)&&Number.isFinite(u))t.set(l,{pid:l,cpuPercent:c,memoryKB:u})}return t}function
|
|
2519
|
-
`);i=a.pop()??"";for(let l of a)r(t,l.replace(/\r$/,""))}if(i!=="")r(t,i)}var
|
|
2519
|
+
`}$t();class rw{start;constructor(e){this.start=e}execute(e){return this.start({...e,profile:e.profile?Ar(e.profile):void 0,services:e.services?.map((t)=>mf(t))})}}class nw{stop;constructor(e){this.stop=e}execute(e){return this.stop(e.map((t)=>mf(t)))}}class ow{restart;constructor(e){this.restart=e}execute(e,t){return this.restart(e.map((r)=>mf(r)),t)}}class iw{start;constructor(e){this.start=e}execute(e,t){return this.start.execute({profile:e,client_env:t})}}class sw{host;constructor(e){this.host=e}execute(){return this.host.startProxy()}}class aw{host;constructor(e){this.host=e}execute(){return this.host.stopProxy()}}class lw{host;constructor(e){this.host=e}execute(){return this.host.reload()}}class cw{host;constructor(e){this.host=e}execute(){return this.host.refreshIdentity({probeServiceAccounts:!0})}}class gc{runner;constructor(e){this.runner=e}execute(e,t,r){return this.runner.run(e,t,r)}}class vc{execute(e,t,r){return dc(e,t,r)}}class yc{execute(e,t){return pc(e,t)}}class uw{host;constructor(e){this.host=e}execute(){return this.host.snapshot()}}class bc{execute(e,t){return hc(e,t)}}function mf(e){return Jb(e)}function dw(e,t,r){let n=r??e,o=new rw((i)=>n.start(i));return{startService:o,stopService:new nw((i)=>n.stop(i)),restartService:new ow((i,s)=>n.restart(i,s)),startProfile:new iw(o),startProxy:new sw(e),stopProxy:new aw(e),reloadConfig:new lw(e),refreshIdentity:new cw(e),runDoctor:new gc(t),getServiceStatus:new uw(e),getStartupPlan:new vc,getShutdownPlan:new yc,resolveStart:new bc}}import{createConnection as zL}from"net";var{spawn:qL}=globalThis.Bun;import{readdirSync as IL}from"fs";import{join as pw,resolve as hf,sep as gf}from"path";function DL(e){let t=pw(Er(),"state"),r;try{r=IL(t)}catch{return}let n=fw(hf(e)),o;for(let i of r){let s=Pd(pw(t,i,"state.json"));if(!s)continue;let a=fw(hf(s.repo_root));if(!OL(a,n))continue;if(!o||a.length>o.length)o=a}return o}function wc(e,t,r=""){if(t!=="")return{repoRoot:hf(t),source:"explicit"};let n=e===""?process.cwd():e;try{let{repoRoot:i}=Mo(n,r);return{repoRoot:i,source:"config"}}catch{if(r!=="")return}let o=DL(n);return o?{repoRoot:o,source:"state-scan"}:void 0}function fw(e){let t=e.length>1&&e.endsWith(gf)?e.slice(0,-1):e;return process.platform==="win32"?t.toLowerCase():t}function OL(e,t){return t===e||t.startsWith(e.endsWith(gf)?e:`${e}${gf}`)}import{existsSync as hw,readFileSync as gw}from"fs";import{isAbsolute as ML,join as vf}from"path";import{parse as NL}from"dotenv";ne();var ea=["process","profile","dotenv","generated","keychain","secret_manager","defaults","vars","runtime"],FL=/^projects\/[^/]+\/secrets\/[^/]+(?:\/versions\/[^/]+)?$/,$L=["process","defaults","vars","runtime"];function HL(){return{name:"dotenv",load:(e)=>{let t=mw(e.repoRoot,e.profile);if(e.workDir!=="")Object.assign(t,mw(e.workDir,e.profile));return t}}}function UL(e){let t=e?.environment.sources??[];if(t.length===0)return[...ea];let r=new Set([...$L,...t]),n=new Set(ea),o=t.filter((s)=>!n.has(s)),i=[];for(let s of ea){if(s==="defaults")i.push(...o);if(r.has(s))i.push(s)}return i}async function ta(e,t){let r={},n=t.serviceCfg.working_dir;if(n!==""&&!ML(n))n=vf(e,n);let o={repoRoot:e,profile:t.profile,service:t.service,serviceCfg:t.serviceCfg,workDir:n,cfg:t.cfg},i=jL(t),s=t.userEmail??"",a={process:t.includeProcess===!1?{}:t.clientEnv??ji(),profile:Zs(t.profileEnv,t.cfg,i,s),dotenv:Zs(await HL().load(o),t.cfg,i,s),generated:{},keychain:t.sourceValues?.keychain??BL(o),secret_manager:t.sourceValues?.secret_manager??await WL(o,t.fetchSecret),defaults:Zs(t.serviceCfg.environment.defaults,t.cfg,i,s),vars:Zs(t.serviceCfg.environment.vars,t.cfg,i,s),runtime:t.runtime};for(let l of UL(t.cfg)){if(a[l]!==void 0){Object.assign(r,a[l]);continue}let c=t.pluginSources?.find((u)=>u.name===l);if(c)Object.assign(r,Zs(await c.load(o),t.cfg,i,s))}for(let l of t.serviceCfg.environment.required)if((r[l]??"").trim()==="")throw T(ee,`service ${t.service} missing required environment variable ${l}`);return r}function jL(e){let t={};if(e.cfg)for(let[r,n]of Object.entries(e.cfg.services)){let o={};for(let i of n.ports)if(!i.auto)o[i.name]=i.value;t[r]=o}if(e.assignedPorts)t[e.service]=e.assignedPorts;return t}function Zs(e,t,r,n=""){if(!t||Object.keys(e).length===0)return e;return Gp(e,t,r,n)}function BL(e){let t=e.cfg?.environment.sources??[];if(t.length>0&&!t.includes("keychain"))return{};let r={},n=new Set([...Object.keys(e.serviceCfg.environment.defaults),...Object.keys(e.serviceCfg.environment.vars),...e.serviceCfg.environment.required]);for(let o of n){let i=vf(Ur(),"env",o);if(!hw(i))continue;try{r[o]=gw(i,"utf8").replace(/\n$/,"")}catch(s){throw ge(ee,`unable to read keychain env ${o}`,s)}}return r}async function WL(e,t){if(!(e.cfg?.environment.sources??[]).includes("secret_manager"))return{};let n=e.cfg?.environment.secrets??{},o={};for(let[i,s]of Object.entries(n)){if(!FL.test(s))throw T(ee,`environment.secrets.${i} is not a Secret Manager resource`);if(!t)throw T(ee,"environment source secret_manager is not configured \u2014 set credentials or remove it from environment.sources");o[i]=await t(s)}return o}function mw(e,t){let r={},n=[".env",".env.development",".env.local"];if(t!=="")n.push(`.env.${t}`);for(let o of n){let i=vf(e,o);if(!hw(i))continue;try{let s=NL(gw(i));Object.assign(r,s)}catch(s){throw ge(ee,`unable to read ${i}`,s)}}return r}function ji(){let e={};for(let[t,r]of Object.entries(process.env))if(r!==void 0)e[t]=r;return e}function ra(e,t,r,n,o,i=""){let s={DEVCTL_SERVICE_NAME:e,DEVCTL_ENVIRONMENT:o,SERVICE_HOST:t};if(n!=="")s.DEVCTL_PROXY_URL=n;if(i!=="")s.DEVCTL_USER_EMAIL=i;if(r.http!==void 0)s.SERVICE_PORT=String(r.http);else{let a=Object.values(r)[0];if(a!==void 0)s.SERVICE_PORT=String(a)}for(let[a,l]of Object.entries(r))s[`${a.toUpperCase()}_PORT`]=String(l);return s}function Bi(e){return{...e}}ne();var GL=50,KL=8000,VL=15000,YL=200,JL=30000,vw=86400000,XL=new Set(["logs","logs_page","logs_stats"]);function QL(e){if(e.legacy)return"attached daemon predates the client/daemon compatibility handshake";return`attached daemon speaks RPC protocol ${e.daemonProtocol??"unknown"}; this client speaks ${Ys}`}function ZL(e){if(e.compatible&&e.daemonVersion!==void 0&&e.daemonVersion!==Xt)return`attached daemon is devctl ${e.daemonVersion}; this client is ${Xt} (run \`devctl down\` then start again to update it)`;return}function yf(e,t){if(!e.compat.compatible&&!XL.has(t))throw Ie($e,QL(e.compat),"run `devctl down` to stop it, then start again")}class yw{socket;buf="";pending=new Map;listeners=[];nextID=0;compat={compatible:!0,legacy:!1};session="";constructor(e){this.socket=e,e.on("data",(t)=>{this.buf+=t.toString("utf8");let r=this.buf.split(`
|
|
2520
|
+
`);this.buf=r.pop()??"";for(let n of r){if(n.trim()==="")continue;this.onLine(n)}}),e.on("error",(t)=>this.rejectPending(t instanceof Error?t:Error(String(t)))),e.on("close",()=>this.rejectPending(Error("supervisor connection closed")))}onLine(e){let t;try{t=JSON.parse(e)}catch{return}if(t.event){for(let n of this.listeners)n(t.event);return}let r=t.id?this.pending.get(t.id):void 0;if(!r)return;if(this.pending.delete(t.id??""),clearTimeout(r.timer),t.error){r.reject(sy({error:t.error,kind:t.kind,hint:t.hint,service:t.service}));return}r.resolve(t.result)}onEvent(e){return this.listeners.push(e),()=>{let t=this.listeners.indexOf(e);if(t>=0)this.listeners.splice(t,1)}}call(e,t,r=JL){this.nextID+=1;let n=String(this.nextID);return new Promise((o,i)=>{let s=setTimeout(()=>{this.pending.delete(n),i(Error(`${e} timed out after ${r}ms`))},r);this.pending.set(n,{resolve:o,reject:i,timer:s}),this.socket.write(JSON.stringify({id:n,method:e,params:t})+`
|
|
2521
|
+
`)})}close(){this.rejectPending(Error("supervisor connection closed")),this.socket.destroy()}rejectPending(e){for(let t of this.pending.values())clearTimeout(t.timer),t.reject(e);this.pending.clear()}}function bw(e,t){let r=Za(e),n=Date.now()+t;return new Promise((o,i)=>{let s=()=>{let a=zL(r);a.once("connect",()=>{let l=new yw(a);eI(l).finally(()=>o(l))}),a.once("error",(l)=>{if(a.destroy(),Date.now()>=n){i(Ie($e,"supervisor is not running","run `devctl start` or `devctl attach` after starting services"));return}setTimeout(s,GL)})};s()})}async function eI(e){let t;try{t=await e.call("ping",null,KL)}catch{return}let r=tI(t)?t:{};if(typeof r.session==="string")e.session=r.session;let n=typeof r.protocol==="number"?r.protocol:void 0,o=typeof r.version==="string"?r.version:void 0;if(n===void 0){e.compat={compatible:!1,legacy:!0,daemonVersion:o};return}e.compat={compatible:n===Ys,legacy:!1,daemonVersion:o,daemonProtocol:n}}function tI(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}async function Vo(e){try{return await bw(e,YL)}catch{return}}function rI(e,t,r,n){return r?[e,...n]:[e,t,...n]}async function ww(e,t){let r=await Vo(e);if(r)return r;Bg(e);let n=Ss(e),o=rI(process.execPath,process.argv[1]??"",Bun.isStandaloneExecutable===!0,["--config",t,"_supervisor","--repo",e]),i=qL({cmd:o,env:{...process.env},stdout:"ignore",stderr:Bun.file(n),stdin:"ignore",detached:!0});try{let s=await oI(e,VL,i.exited);return i.unref(),s}catch{throw await iI(i),Ie($e,"supervisor failed to start",`see ${n} for details`)}}var nI=1000;function oI(e,t,r){return new Promise((n,o)=>{let i=!1,s=(a)=>{if(i)return;i=!0,a()};r.then((a)=>{s(()=>o(Error(`supervisor exited (code ${a}) before accepting connections`)))}),bw(e,t).then((a)=>s(()=>n(a)),(a)=>s(()=>o(a)))})}async function iI(e){let t=e.pid;try{e.kill("SIGKILL")}catch{}if(t!==void 0&&t>0&&process.platform!=="win32")try{process.kill(-t,"SIGKILL")}catch{try{process.kill(t,"SIGKILL")}catch{}}await Promise.race([e.exited.then(()=>{return}),new Promise((r)=>{setTimeout(r,nI)})])}class xc{cfg;client;previousPersisted;constructor(e){this.cfg=e}async start(e){return await this.call("start",{...e,client_env:ji()})}async stop(e){await this.call("stop",{services:e})}async restart(e,t){await this.call("restart",{services:e,cascade:t===!0,client_env:ji()})}async runTask(e){return await this.call("run_task",{name:e,client_env:ji()},vw)}async execService(e,t,r=!1){return await this.call("exec",{service:e,command:t,print_env:r,client_env:ji()},vw)}async status(){return await this.call("status",null)}async refreshAuth(){return await this.call("auth_refresh",null)}async configSnapshot(){return await this.call("config_snapshot",null)}async logs(e){return(await this.call("logs",e)).events??[]}async logsPage(e){return await this.call("logs_page",e)}async logsStats(e){return await this.call("logs_stats",e)}async getTrace(e){return await this.call("get_trace",{trace_id:e})}async traceRequest(e){return await this.call("trace_request",{request_id:e})}async proxyStart(){await this.call("proxy_start",null)}async proxyStop(){await this.call("proxy_stop",null)}async mcpStart(e){await this.call("mcp_start",e??null)}async mcpStop(){await this.call("mcp_stop",null)}async webStart(){await this.call("web_start",null)}async webStop(){await this.call("web_stop",null)}async mcpSetTools(e){return(await this.call("mcp_set_tools",{disabled:[...e]})).disabled_tools??[]}async reload(){return await this.call("reload",null)}async invalidateAuth(){await this.call("auth_invalidate",null)}onEvent(e){if(this.client)return this.client.onEvent(e);return()=>{return}}async shutdown(e){if(!this.client)return;let t=Math.max(5000,this.cfg.shutdown.grace_seconds*1000+2000);await this.client.call("shutdown",{stop_services:e.stopServices},t)}async close(e){if(!this.client)return;try{if(e?.shutdownSupervisor===!0&&e.detach!==!0)await this.shutdown({stopServices:!0})}finally{this.client.close()}}async call(e,t,r){if(!this.client)throw ge($e,"supervisor is not running",Error("no client"));return yf(this.client,e),this.client.call(e,t,r)}}function na(e){let t=e&&ZL(e.compat);if(t)process.stderr.write(`warning: ${t}
|
|
2522
|
+
`)}async function xw(e,t,r=""){let n=wc(e,t,r);if(!n)throw Ie($e,"no devctl configuration found","run `devctl setup`, create a .devctl/config.yaml in the repository root, or pass --repo");let o=await Vo(n.repoRoot);return na(o),{repoRoot:n.repoRoot,client:o}}async function kw(e,t,r,n){let o=n?.allowMissingConfig===!0?Uo(e,t):_n(e,t),i=new xc(o);if(!r)return i.client=await Vo(o.repoRoot),na(i.client),i;return i.client=await ww(o.repoRoot,o.configPath),na(i.client),i}async function Sw(e){let t=new xc(Io());return t.client=e,na(t.client),t.cfg=await t.configSnapshot(),t}async function Cw(e,t){let r=wc(e,"",t),n=r?await Vo(r.repoRoot):void 0;if(!n)throw Ie($e,"supervisor is not running","run `devctl start` before `devctl attach`");return Sw(n)}async function Tw(e,t){let r=wc(e,"",t),n=r?await Vo(r.repoRoot):void 0;if(n)return Sw(n);let o=_n(e,t),i=new xc(o),s=$n(o.repoRoot);if(i.client=await ww(o.repoRoot,o.configPath),na(i.client),i.cfg=await i.configSnapshot(),s&&s.processes.length>0)i.previousPersisted=s;return i}import{realpathSync as aI}from"fs";var lI="https://api.github.com/repos/amr-m-abdelgawad/devctl/releases/latest";function cI(){let e=Bun.isStandaloneExecutable===!0,t=e?"":Iw(process.argv[1]??"");return Pw({scriptPath:t,execPath:Iw(process.execPath),standalone:e})}async function uI(e=fetch,t=cI()){try{let r=await e(lI,{headers:{Accept:"application/vnd.github+json"}});if(!r.ok)return Lw(t);let o=((await r.json()).tag_name??"").replace(/^v/,"");return{current:Xt,latest:o,newer:o!==""&&Aw(o,Xt)>0,hint:t.hint,kind:t.kind,command:t.command}}catch{return Lw(t)}}async function dI(e,t=Dw){return t(e)}async function Dw(e,t=!1){let r=Bun.spawn([...e],{stdout:t?"inherit":"pipe",stderr:t?"inherit":"pipe",stdin:"ignore"});if(t)return{code:await r.exited,stdout:"",stderr:""};let n=await new Response(r.stdout).text(),o=await new Response(r.stderr).text();return{code:await r.exited,stdout:n,stderr:o}}function Ow(e=fetch){return{check:()=>uI(e),apply:(t,r)=>r===!0?Dw(t,!0):dI(t)}}function Lw(e){return{current:Xt,latest:"",newer:!1,hint:e.hint,kind:e.kind,command:e.command}}function Iw(e){if(e==="")return"";try{return aI(e)}catch{return e}}function Mw(e){let t=e?.tokens??new qo(60000,Zn(),void 0),r=e?.doctorHost??Hi({tokens:t}),n=Ow(),o={loadTuiConfig:vi,saveTuiPreferences:Yg,resolveTuiOverridePath:sl,userTuiConfigPath:il,listSessions:Zv,loadSessionEvents:ey,loadPath:Ws,validateConfigText:Bs,discover:Mo,configDiff:Xn,openTui:Tw,findDaemon:xw,tryDial:Vo,assertMethodAllowed:yf,readPersistedState:$n,bootstrapLogPath:Ss,exportsDir:Qa,resolveExportPath:Xv,writeLogExport:bp,openInFileManager:Qv,freePort:Il,createStarterConfig:vy,runSetup:(i,s,a)=>yy(o,i,s,a),readTextFile:(i)=>fI(i,"utf8"),writeTextFile:(i,s)=>mI(i,s),fileExists:pI,load:_n,loadOrEmpty:Uo,validate:$o,detectGoogle:Wo,loginGoogle:Nb,logoutGoogle:Fb,refreshUserToken:async(i="user")=>t.refresh(i,"",[]),runDoctor:new gc(e?.doctorRunner??uc(r)),getStartupPlan:new vc,getShutdownPlan:new yc,resolveStart:new bc,formatDoctor:Yb,openController:kw,openAttach:Cw,checkUpdate:()=>n.check(),applyUpdate:(i,s)=>n.apply(i,s),formatUpdateStatus:_w};return o}import{existsSync as fM,unlinkSync as mM}from"fs";import{connect as hI}from"net";$t();var gI=2000,vI=200,yI=300;function Nw(e){return{lookup(t){let r=t.toLowerCase();return["","http","tcp","command","process"].includes(r)||e.some((o)=>o.name.toLowerCase()===r)?{check:(o,i)=>bI({...o,type:t},i.pid,i.ports,i.workDir,i.env,e)}:void 0}}}async function bI(e,t,r,n,o,i=[]){let s=e.timeout_seconds>0?e.timeout_seconds*1000:gI,a=e.type.toLowerCase(),l=i.find((c)=>c.name.toLowerCase()===a);if(l)try{let c=await l.check(e,{pid:t,ports:r,workDir:n,env:o});return{status:c.status,message:c.message}}catch(c){return{status:He,message:c instanceof Error?c.message:String(c)}}if(a==="http")return wI(e.url,s);if(a==="tcp")return kI(xI(e.address,r),s);if(a==="command")return SI(e.command.args,e.command.shell,n,o,s);if(a==="process"||a===""){if(t>0&&mr(t))return{status:Qt,message:"process running"};return{status:He,message:"process not running"}}return{status:He,message:`unknown health type ${e.type}`}}async function wI(e,t){let r=new AbortController,n=setTimeout(()=>r.abort(),t);try{let o=await fetch(e,{signal:r.signal});if(o.status>=vI&&o.status<yI)return{status:Qt,message:String(o.status)};return{status:He,message:String(o.status)}}catch(o){return{status:He,message:o instanceof Error?o.message:String(o)}}finally{clearTimeout(n)}}function xI(e,t){if(e!=="")return e;if(t.http!==void 0)return`127.0.0.1:${t.http}`;let r=Object.values(t)[0];return r!==void 0?`127.0.0.1:${r}`:""}function kI(e,t){return new Promise((r)=>{if(e===""){r({status:He,message:"no tcp address"});return}let n=e.lastIndexOf(":"),o=Number.parseInt(e.slice(n+1),10),i=e.slice(0,n).replace(/^\[|\]$/g,"");if(n<1||!Number.isFinite(o)){r({status:He,message:`invalid tcp address ${e}`});return}let s=hI({host:i,port:o},()=>{s.end(),r({status:Qt,message:"connected"})});s.setTimeout(t),s.on("error",(a)=>{r({status:He,message:a.message})}),s.on("timeout",()=>{s.destroy(),r({status:He,message:"timeout"})})})}async function SI(e,t,r,n,o){if(e.length===0)return{status:He,message:"empty health command"};let i=t?process.platform==="win32"?["cmd.exe","/c",e.join(" ")]:["/bin/sh","-c",e.join(" ")]:e,s;try{s=Bun.spawn({cmd:i,cwd:r===""?void 0:r,env:n,stdout:"ignore",stderr:"ignore"})}catch(c){return{status:He,message:c instanceof Error?c.message:String(c)}}let a=setTimeout(()=>s.kill("SIGKILL"),o),l=await s.exited;if(clearTimeout(a),l===0)return{status:Qt,message:"ok"};return{status:He,message:`exit ${l}`}}ne();var{spawn:Jw}=globalThis.Bun;var{spawn:CI}=globalThis.Bun;async function Fw(e,t){if(e<=0)return;try{process.kill(-e,t);return}catch{try{process.kill(e,t)}catch{return}}}async function $w(e){if(!mr(e))return;let t=await oa(["ps","-p",String(e),"-o","command="]),r=Date.now(),n=TI(await oa(["ps","-p",String(e),"-o","etime="])),o=await EI(e);return{pid:e,command:t.trim(),cwd:o,startTime:n===void 0?void 0:new Date(r-n).toISOString()}}function TI(e){let t=e.trim();if(t==="")return;let r=t.indexOf("-"),n=r>=0?t.slice(0,r):"0",i=(r>=0?t.slice(r+1):t).split(":");if(i.length!==2&&i.length!==3)return;let s=Number(n),a=i.length===3?Number(i[0]):0,l=Number(i.length===3?i[1]:i[0]),c=Number(i.at(-1));if(!Number.isInteger(s)||s<0||!Number.isInteger(a)||a<0||a>23||!Number.isInteger(l)||l<0||l>59||!Number.isInteger(c)||c<0||c>59)return;return(((s*24+a)*60+l)*60+c)*1000}async function EI(e){let r=(await oa(["lsof","-a","-p",String(e),"-d","cwd","-Fn"])).split(`
|
|
2523
|
+
`).find((i)=>i.startsWith("n"));if(r&&r.length>1)return r.slice(1).trim();let n=await oa(["pwdx",String(e)]),o=n.indexOf(":");if(o>=0)return n.slice(o+1).trim();return""}async function oa(e){try{let t=CI({cmd:e,stdout:"pipe",stderr:"ignore"}),r=t.stdout?await new Response(t.stdout).text():"";return await t.exited,r}catch{return""}}async function Hw(e){let t=new Map;if(e.length===0)return t;let r=await oa(["ps","-o","pid=,pcpu=,rss=","-p",e.join(",")]);for(let n of r.split(`
|
|
2524
|
+
`)){let o=n.trim();if(o==="")continue;let[i,s,a]=o.split(/\s+/),l=Number(i),c=Number(s),u=Number(a);if(Number.isFinite(l)&&Number.isFinite(c)&&Number.isFinite(u))t.set(l,{pid:l,cpuPercent:c,memoryKB:u})}return t}function Uw(e,t){if(e.length===0||t==="")return!1;let r=e.join(" ");if(t.includes(r))return!0;let o=(e[0]??"").split(/[/\\]/).pop()??"";if(o!==""&&t.includes(o))return!0;let i=e[e.length-1]??"";return i!==""&&t.includes(i)}var{spawn:jw}=globalThis.Bun;var RI=1024,_I=3000;async function Bw(e,t){if(e<=0)return;try{await jw({cmd:["taskkill","/PID",String(e),"/T","/F"],stdout:"ignore",stderr:"ignore"}).exited}catch{return}}async function Ww(e){let t=PI(Ad(e),e);if(t)return t;if(!mr(e))return;let r=await bf(["powershell","-NoProfile","-Command",`Get-CimInstance Win32_Process -Filter "ProcessId=${e}" | Select-Object CommandLine,ExecutablePath,CreationDate | ConvertTo-Json -Compress`]),n=LI(r);if(n&&n.command!=="")return{pid:e,command:n.command,cwd:n.cwd,startTime:n.startTime};let o=await bf(["powershell","-NoProfile","-Command",`Get-Process -Id ${e} -ErrorAction SilentlyContinue | Select-Object Path,StartTime | ConvertTo-Json -Compress`]),i=AI(o);if(!i&&!n)return;return{pid:e,command:n?.command||i?.command||"",cwd:n?.cwd||i?.cwd||"",startTime:n?.startTime||i?.startTime}}function PI(e,t){let r=String(t);for(let n of e.split(/\r?\n/)){if(!n.includes(r))continue;let i=n.split(",").map((s)=>s.replace(/^"|"$/g,"").trim())[0]??"";if(i===""||i.toLowerCase().includes("info:"))continue;return{pid:t,command:i,cwd:""}}return}function AI(e){let t=e.trim();if(t==="")return;try{let r=JSON.parse(t),n=(r.Path||"").trim();if(n==="")return;return{command:n,cwd:Cc(n),startTime:r.StartTime}}catch{let r=Sc(t,"Path");if(r==="")return;return{command:r,cwd:Cc(r)}}}function LI(e){let t=e.trim();if(t==="")return;try{let r=JSON.parse(t),n=(r.CommandLine||r.ExecutablePath||"").trim(),o=(r.ExecutablePath||"").trim(),i=Cc(o);return{command:n,cwd:i,startTime:r.CreationDate||void 0}}catch{return{command:Sc(t,"CommandLine")||Sc(t,"ExecutablePath"),cwd:Cc(Sc(t,"ExecutablePath"))}}}async function zw(e){let t=new Map;if(e.length===0)return t;let r=e.filter((o)=>o>0).join(",");if(r==="")return t;let n=await bf(["powershell","-NoProfile","-Command",`${r}.Split(',') | ForEach-Object { Get-Process -Id $_ -ErrorAction SilentlyContinue } | Select-Object Id,CPU,WorkingSet64 | ConvertTo-Json -Compress`]);return II(n)}function II(e){let t=new Map,r=e.trim();if(r==="")return t;try{let n=JSON.parse(r),o=Array.isArray(n)?n:[n];for(let i of o){if(!i||typeof i!=="object")continue;let s=i,a=Number(s.Id),l=Number(s.CPU??0),c=Number(s.WorkingSet64??0)/RI;if(Number.isFinite(a)&&a>0&&Number.isFinite(l)&&Number.isFinite(c))t.set(a,{pid:a,cpuPercent:l,memoryKB:c})}}catch{return t}return t}function Cc(e){if(e==="")return"";let t=e.replace(/\//g,"\\"),r=t.lastIndexOf("\\");return r>0?t.slice(0,r):""}function Sc(e,t){let r=`${t}=`,n=e.split(/\r?\n/).find((o)=>o.startsWith(r));return n?n.slice(r.length).trim():""}async function bf(e){let t,r=setTimeout(()=>{try{t?.kill()}catch{}},_I);try{t=jw({cmd:e,stdout:"pipe",stderr:"ignore"});let n=t.stdout?await new Response(t.stdout).text():"";return await t.exited,n}catch{return""}finally{clearTimeout(r)}}ne();var{spawn:wf}=globalThis.Bun;async function Gw(e){await MI(e.runtime,e.containerName);let t=DI(e),r=await Wi(e.runtime,t,e.env);if(r.code!==0||r.stdout.trim()==="")throw T(Ge,`failed to start ${e.containerName}: ${r.stderr.trim()||"container runtime returned no id"}`);let n=r.stdout.trim().split(/\s+/)[0]??"";return Yw(e.runtime,e.containerName,n,e.onLine,e.onExit)}function DI(e){let t=["run","--detach","--name",e.containerName,"--label","devctl.managed=true"];for(let[r,n]of Object.entries(e.ports)){let o=e.targetPorts[r]??n;t.push("--publish",`127.0.0.1:${n}:${o}`)}for(let r of Object.keys(e.env).sort())t.push("--env",r);for(let r of e.volumes)t.push("--volume",r);return t.push(e.image,...e.command),t}var OI=new Set(["PATH","HOME","HOSTNAME","PWD","OLDPWD","SHLVL","_","TMPDIR"]);function Kw(e){return Object.fromEntries(Object.entries(e).filter(([t])=>!OI.has(t)))}async function Vw(e,t,r,n){let o=await Wi(e,["inspect","--format","{{.Id}} {{.State.Running}}",t],process.env);if(o.code!==0)return;let[i,s]=o.stdout.trim().split(/\s+/);if(!i||s!=="true")return;return Yw(e,t,i,r,n)}function Yw(e,t,r,n,o){let i=!0,s=wf({cmd:[e,"logs","--follow",r],stdout:"pipe",stderr:"pipe",stdin:"ignore"});qw(s.stdout,"stdout",n),qw(s.stderr,"stderr",n);let a=wf({cmd:[e,"wait",r],stdout:"pipe",stderr:"pipe",stdin:"ignore"}),l=Promise.all([new Response(a.stdout).text(),a.exited]).then(async([c,u])=>{i=!1,s.kill();let d=Number.parseInt(c.trim(),10),f=Number.isFinite(d)?d:u??1,p=f===0?void 0:Error(`container exited with code ${f}`);return await Wi(e,["rm","--force",r],process.env),o?.(f,p),{code:f,err:p}});return{id:r,runtime:e,containerName:t,done:l,running:()=>i,stop:async(c)=>{let u=Math.max(1,Math.ceil(c/1000));await Wi(e,["stop","--time",String(u),r],process.env),await l}}}async function MI(e,t){let r=await Wi(e,["inspect","--format","{{.State.Running}}",t],process.env);if(r.code===0&&r.stdout.trim()==="false")await Wi(e,["rm","--force",t],process.env)}async function Wi(e,t,r){try{let n=wf({cmd:[e,...t],env:{...process.env,...r},stdout:"pipe",stderr:"pipe",stdin:"ignore"}),[o,i,s]=await Promise.all([new Response(n.stdout).text(),new Response(n.stderr).text(),n.exited]);return{code:s??1,stdout:o,stderr:i}}catch(n){throw ge(Ge,`unable to run ${e}`,n)}}async function qw(e,t,r){if(!e||typeof e==="number"||!r)return;let n=e.getReader(),o=new TextDecoder,i="";for(;;){let s=await n.read();if(s.done)break;i+=o.decode(s.value,{stream:!0});let a=i.split(`
|
|
2525
|
+
`);i=a.pop()??"";for(let l of a)r(t,l.replace(/\r$/,""))}if(i!=="")r(t,i)}var NI=1e4,FI=2000,$I=500;class xf{isRunning(e){let t=this.running.get(e);return t!==void 0&&ia(t)}running=new Map;async start(e){let t=this.running.get(e.name);if(t&&ia(t))return t;if(this.running.delete(e.name),e.args.length===0)throw T(Ge,"empty command");let r=e.shell?Zw(e.args):e.args,n;try{n=Jw({cmd:r,cwd:e.workDir===""?void 0:e.workDir,env:e.env,stdout:e.captureStdout===!1?"ignore":"pipe",stderr:e.captureStderr===!1?"ignore":"pipe",stdin:"ignore",detached:process.platform!=="win32"})}catch(i){throw ge(Ge,`failed to start ${e.name}`,i)}let o={name:e.name,pid:n.pid??0,startTime:new Date,workDir:e.workDir,args:[...e.args],proc:n,done:Promise.resolve({code:0})};return Tc(n.stdout,"stdout",e.onLine),Tc(n.stderr,"stderr",e.onLine),o.done=n.exited.then((i)=>{let s=typeof i==="number"?i:0,a=s===0?void 0:Error(`exited with code ${s}`);if(this.running.get(e.name)===o)this.running.delete(e.name);if(e.onExit)e.onExit(s,a);return{code:s,err:a}}),this.running.set(e.name,o),o}async runOnce(e){if(e.args.length===0)throw T(Ge,"empty command");let t;try{t=Jw({cmd:e.shell?Zw(e.args):e.args,cwd:e.workDir||void 0,env:e.env,stdout:"pipe",stderr:"pipe",stdin:"ignore"})}catch(a){throw ge(Ge,`failed to run ${e.name}`,a)}let r="",n="",o=(a,l)=>{if(a==="stdout")r+=`${l}
|
|
2520
2526
|
`;else n+=`${l}
|
|
2521
|
-
`;e.onLine?.(a,l)},i=[Tc(t.stdout,"stdout",o),Tc(t.stderr,"stderr",o)],s=await t.exited;return await Promise.all(i),{code:typeof s==="number"?s:0,stdout:r,stderr:n}}async startContainer(e){let t=this.running.get(e.name);if(t&&ia(t))return t;let r=await
|
|
2522
|
-
`);i=l.pop()??"";for(let c of l)r(t,c.replace(/\r$/,""))}}async function Qw(e,t){return Promise.race([e.then(()=>!0),new Promise((r)=>{setTimeout(()=>r(!1),t)})])}function II(e){return new Promise((t)=>{setTimeout(t,e)})}import{existsSync as DI,readFileSync as OI,writeFileSync as MI}from"fs";var tx={exists:(e)=>DI(e),readText:(e)=>OI(e,"utf8"),writeText:(e,t)=>MI(e,t)};Ke();var xf=3,NI=3,FI=10,kf={shouldRestart(e){if(!e.enabled||e.policy===Dl)return!1;if(e.retryCount>=e.maxRetries)return!1;if(e.policy===Ml)return!0;return e.policy===Ol&&e.exitCode!==0},fromService(e,t,r){return{policy:$l(e.restart),enabled:e.restart.enabled!==!1,exitCode:r,retryCount:t,maxRetries:e.restart.max_retries>0?e.restart.max_retries:xf}}},Sf={shouldRestartUnhealthy(e,t=NI){return e>=t},shouldResetRestartBudget(e,t=FI){return e>=t}},Ec={timeoutMs(e,t){let r=e.startup.timeout_seconds;return r>0?r*1000:t},waitForHealthy(e){return e.startup.wait_for_healthy}};$t();ne();var $I=2,HI=2000,UI=3,jI=10;class Cf{host;processes;clock;actions;generation=new Map;healthTimers=new Map;restarts=new Map;unhealthyStreak=new Map;healthyStreak=new Map;restartTimers=new Map;constructor(e,t,r,n){this.host=e;this.processes=t;this.clock=r;this.actions=n}forget(e){this.clearHealthWatch(e),this.clearRestartTimer(e),this.restarts.delete(e),this.bumpGeneration(e),this.unhealthyStreak.delete(e),this.healthyStreak.delete(e)}dispose(){this.clearAllRestartTimers();for(let e of this.generation.keys())this.bumpGeneration(e);for(let e of this.healthTimers.keys())this.clearHealthWatch(e)}onExit(e,t,r,n){if(!this.isCurrentGeneration(e,t))return;this.clearHealthWatch(e);let o=this.host().runtimes.get(e);if(o?.state===bt)return;if(o&&(o.state===Kr||o.state===Nt)){this.host().setState(e,Nt,Ft,0,""),this.host().bus.publish(Ce(al,e,{code:r}));return}let i=this.host().cfg.services[e],s=n?.message??`exited with code ${r}`,a=this.restarts.get(e)??0;if((i?kf.shouldRestart(kf.fromService(i,a,r)):!1)&&i){this.host().setState(e,Ir,Ft,0,s),this.bumpRestartCount(e,a+1),this.host().persistState(),this.armRestart(e,i,t,a,()=>{let c=this.host().serviceProfile.get(e)??this.host().profile,u=this.host().serviceProfileEnv.get(e)??this.host().profileEnv;this.actions.startOne(e,c,u,!1).catch((d)=>this.host().log(e,"ERROR",I(d)))});return}this.host().fail(e,T("process_start",s))}startHealth(e,t,r,n,o,i,s){let a=this.healthTimers.get(e);if(a)clearInterval(a);if(t.health.type===""){this.setHealth(e,Qt,"no health check");return}let l=t.health.interval_seconds>0?t.health.interval_seconds*1000:HI,c=Date.parse(this.host().runtimes.get(e)?.startTime??"")||this.clock.unixMs(),u=()=>{(t.container&&t.health.type.toLowerCase()==="process"?Promise.resolve(this.processes.isRunning(e)?{status:Qt,message:"container running"}:{status:He,message:"container not running"}):Promise.resolve().then(()=>this.host().healthCheckers.lookup(t.health.type)?.check(t.health,{pid:r,ports:n,workDir:o,env:i})??{status:He,message:`unknown health type ${t.health.type}`})).catch((f)=>({status:He,message:I(f)})).then((f)=>{if(!this.isCurrentGeneration(e,s))return;let p=this.host().runtimes.get(e);if(p&&rx(p.state))return;if(f.status===He&&this.clock.unixMs()-c<t.health.start_period_seconds*1000){this.host().logs.append({timestamp:this.clock.isoNow(),service:e,source:"health",level:"INFO",message:`health check still in start period: ${f.message}`,pid:r});return}this.setHealth(e,f.status,f.message),this.host().logs.append({timestamp:this.clock.isoNow(),service:e,source:"health",level:BI(f.status),message:`health ${f.status} ${f.message}`,pid:r}),this.maybeRestartUnhealthy(e,t,f.status,s)})};u(),this.healthTimers.set(e,setInterval(u,l))}bumpRestartCount(e,t){this.restarts.set(e,t);let r=this.host().runtimes.get(e);if(r)r.restarts=t}resetRestartCount(e){this.healthyStreak.set(e,0),this.bumpRestartCount(e,0)}bumpGeneration(e){let t=(this.generation.get(e)??0)+1;return this.generation.set(e,t),this.healthyStreak.set(e,0),t}isCurrentGeneration(e,t){return this.generation.get(e)===t}scheduleRestart(e,t,r){this.clearRestartTimer(e);let n=setTimeout(()=>{this.restartTimers.delete(e),r()},t);this.restartTimers.set(e,n)}armRestart(e,t,r,n,o){let i=t.restart.backoff_seconds>0?t.restart.backoff_seconds:$I;this.scheduleRestart(e,i*2**n*1000,()=>{if(this.isCurrentGeneration(e,r))o()})}clearRestartTimer(e){let t=this.restartTimers.get(e);if(t)clearTimeout(t),this.restartTimers.delete(e)}clearAllRestartTimers(){for(let e of this.restartTimers.values())clearTimeout(e);this.restartTimers.clear()}setHealth(e,t,r){let n=this.host().runtimes.get(e);if(!n||rx(n.state))return;if(n.health=t,n.state===Ve||n.state===Lr||n.state===cn)n.state=t===Qt?Lr:t===He?cn:n.state;this.host().bus.publish(Ce(Xg,e,{health:t,message:r}))}maybeRestartUnhealthy(e,t,r,n){if(r!==He){if(this.unhealthyStreak.set(e,0),r===Qt)this.maybeForgiveRestarts(e,t);return}this.healthyStreak.set(e,0);let o=t.restart.policy||(t.restart.enabled?"on_failure":"never");if(o!=="on_failure"&&o!=="always")return;if(this.restartTimers.has(e))return;let i=(this.unhealthyStreak.get(e)??0)+1;this.unhealthyStreak.set(e,i);let s=t.health.unhealthy_threshold>0?t.health.unhealthy_threshold:UI;if(!Sf.shouldRestartUnhealthy(i,s))return;this.unhealthyStreak.set(e,0);let a=this.restarts.get(e)??0,l=t.restart.max_retries>0?t.restart.max_retries:xf;if(a>=l){this.host().log(e,"WARN",`unhealthy after ${i} consecutive checks but the restart limit (${l}) has already been reached; not restarting`);return}this.bumpRestartCount(e,a+1),this.host().log(e,"WARN",`restarting after ${i} consecutive unhealthy checks (attempt ${a+1}/${l})`),this.armRestart(e,t,n,a,()=>{this.actions.restart([e],{auto:!0}).catch((c)=>this.host().log(e,"ERROR",I(c)))})}maybeForgiveRestarts(e,t){let r=(this.healthyStreak.get(e)??0)+1;this.healthyStreak.set(e,r);let n=t.health.healthy_reset_threshold>0?t.health.healthy_reset_threshold:jI;if(Sf.shouldResetRestartBudget(r,n)&&(this.restarts.get(e)??0)>0)this.host().log(e,"INFO",`restart count reset after ${r} consecutive healthy checks`),this.bumpRestartCount(e,0)}clearHealthWatch(e){let t=this.healthTimers.get(e);if(t)clearInterval(t),this.healthTimers.delete(e)}}function rx(e){return e===Ir||e===Kr||e===Nt||e===bt}function BI(e){return e===He?"WARN":e===Qt?"INFO":"DEBUG"}Ke();ne();Gr();ne();$t();var Tf=[Kr,bt,Ir,Ve,Nt],WI={[Yb]:[Nt,An,Ve,bt,Ir,Kr],[Nt]:[An,Ve,bt],[An]:[Ve,bt,Nt,Kr],[Ve]:Tf,[Lr]:Tf,[cn]:Tf,[Kr]:[Nt,bt],[bt]:[An,Nt,Ve],[Ir]:[An,Ve,bt,Nt]};function aa(e,t){if(e===t)return!0;return(WI[e]??[]).includes(t)}function nx(e,t){if(!aa(e,t))throw T(ee,`illegal service lifecycle transition ${e} \u2192 ${t}`);return t}$t();var zI=100,ox=30000;class Ef{processes;clock;session;health;constructor(e,t){this.processes=e;this.clock=t;this.health=new Cf(()=>this.host(),e,t,{startOne:(r,n,o,i)=>this.startOne(r,n,o,i),restart:(r,n)=>this.restart(r,n)})}bind(e){this.session=e}host(){if(!this.session)throw T(Ge,"service orchestrator is not bound");return this.session}planStart(e,t,r){return dc(e,t,r)}planStop(e,t,r=!1){return r?fc(e,t):pc(e,t)}applyLifecycle(e,t){return nx(e,t)}isLegalLifecycle(e,t){return aa(e,t)}async start(e){let t=this.host();if(e.detach===!0)t.detached=!0;let r=hc(t.cfg,{services:e.services,profile:e.profile?Ar(e.profile):void 0,activeProfile:Ar(t.profile)});if(r.profile)t.profile=r.profile,t.profileEnv=r.env;if(e.client_env)for(let a of r.services)t.clientEnv.set(a,e.client_env);if(e.auto!==!0)for(let a of r.services)this.health.resetRestartCount(a);let n=this.planStart(t.cfg,r.services,r.profile),o=await t.detectGoogle(t.cfg.google.project_id);n.blockers=Rb(t.cfg,n.waves.flat(),o.adcAvailable);let i=new Set(n.blockers.map((a)=>a.name));for(let a of n.blockers)await t.fail(a.name,T(Ge,a.message));if(t.cfg.proxy.enabled&&!t.proxySuppressed)await t.startProxy().catch((a)=>t.log("devctl","ERROR",I(a)));let s=[];for(let a of n.waves.flat()){if(i.has(a)||await t.claimIfAlreadyUp(a))continue;s.push(a)}for(let a of s)if(e.profile||!t.serviceProfile.has(a))t.serviceProfile.set(a,r.profile);if(s.length>0)await t.assignPendingPorts(s);for(let a of n.waves){let l=a.filter((c)=>s.includes(c));if(l.length>0){let c=await Promise.allSettled(l.map((d)=>this.startOne(d,r.profile,r.env,e.auto!==!0))),u=!1;for(let d of c)if(d.status==="rejected")u=!0,t.log("devctl","ERROR",I(d.reason));if(u)throw T(Ge,"one or more services failed to start")}try{await this.awaitWaveHealth(a,n.waves.flat())}catch(c){throw t.log("devctl","ERROR",I(c)),c}}return t.persistState(),n}async stop(e){let t=this.host(),r=e;if(r.length===0)r=[...t.runtimes.entries()].filter(([,s])=>s.state!==Nt).map(([s])=>s);if(r.length===0)return;let n=r.filter((s)=>!t.cfg.services[s]&&t.runtimes.has(s)),o=r.filter((s)=>!t.cfg.services[s]&&!t.runtimes.has(s));if(o.length>0)throw T(Pi,`unknown service "${o[0]}"`);let i=r.filter((s)=>t.cfg.services[s]!==void 0);if(i.length>0)await this.runStopPlan(this.planStop(t.cfg,i),{resetRestartCounts:!0});if(n.length>0){await this.runStopPlan({profile:t.profile,steps:[],waves:n.map((s)=>[s])},{resetRestartCounts:!0});for(let s of n)t.forgetService(s)}}async restart(e,t){let r=this.host(),n=t?.cascade===!0,o=n?Go(r.cfg,e):e,i=n?this.planStop(r.cfg,e):this.planStop(r.cfg,e,!0),s=t?.auto!==!0;await this.runStopPlan(i,{resetRestartCounts:s}),await this.start({services:o,client_env:t?.clientEnv,auto:t?.auto})}async runStopPlan(e,t){let r=this.host();for(let i of e.waves.flat())if(this.health.clearRestartTimer(i),this.health.bumpGeneration(i),t?.resetRestartCounts)this.health.resetRestartCount(i);let n=Vn(r.cfg.shutdown)*1000,o=[];for(let i of e.waves){let s=await Promise.allSettled(i.map(async(a)=>{r.setState(a,Kr,Ft,0,""),this.health.clearHealthWatch(a);try{await this.processes.stop(a,n)}catch(l){throw r.setState(a,bt,Ft,0,I(l)),r.bus.publish(Ce(ll,a,{error:I(l)})),l}try{await r.releasePorts(a)}catch(l){r.log(a,"WARN",I(l))}r.setState(a,Nt,Ft,0,""),r.bus.publish(Ce(al,a,{}))}));for(let a=0;a<s.length;a+=1){let l=s[a];if(l?.status==="rejected"){let c=i[a]??"";o.push(c),r.log(c||"devctl","ERROR",I(l.reason))}}}if(r.persistState(),o.length>0)throw T(Ge,`failed to stop: ${o.join(", ")}`)}serviceIsActive(e){if(this.processes.isRunning(e))return!0;let t=this.host().runtimes.get(e);if(!t)return!1;if(t.state===Ir||t.state===Kr||t.state===Nt||t.state===bt)return!1;if(t.health===Qt||t.state===Lr)return!0;return t.state===An||t.state===Ve}async startOne(e,t,r,n=!1){let o=this.host();if(this.serviceIsActive(e))return;let i=o.cfg.services[e];if(!i)throw T($e,`unknown service ${e}`);o.setState(e,An,Ft,0,"");let s=this.health.bumpGeneration(e),a=o.serviceProfile.get(e)??t,l=a!==""?Ko(o.cfg,a):{...r};o.serviceProfileEnv.set(e,l);let c={},u={},d="",f;try{await o.prepareServiceIdentity(e,i),c=o.ports.get(e)??{};let p=await o.resolveServiceExecution(e,i,a,l,o.clientEnv.get(e),!i.container);if(u=p.env,d=p.workDir,n)await this.runTransient(`${e}:pre_start`,i.hooks.pre_start,i.shell,d,u);if(!this.health.isCurrentGeneration(e,s))return;let m=(g,w)=>{o.logs.append({timestamp:this.clock.isoNow(),service:e,source:g,stream:g,level:"",message:w,pid:f.pid})},h=(g,w)=>this.health.onExit(e,s,g,w);f=i.container?await this.processes.startContainer({name:e,runtime:i.container.runtime==="podman"?"podman":"docker",containerName:`${o.containerPrefix}${e.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,image:i.container.image,command:[...i.command.args],env:{...u,...i.container.env},ports:c,targetPorts:i.container.ports,volumes:i.container.volumes,workDir:d,onLine:m,onExit:h}):await this.processes.start({name:e,args:[...i.command.args],shell:i.shell||i.command.shell,workDir:d,env:u,graceMs:Vn(o.cfg.shutdown)*1000,captureStdout:py(i),captureStderr:fy(i),onLine:m,onExit:h})}catch(p){if(this.health.isCurrentGeneration(e,s))await o.fail(e,p);throw p}if(!this.health.isCurrentGeneration(e,s)){if(this.processes.get(e)===f)await this.processes.stop(e,Vn(o.cfg.shutdown)*1000).catch(()=>{});return}if(o.processMeta.set(e,{command:[...i.command.args],cwd:d,startTime:f.startTime}),o.setState(e,Ve,Ft,f.pid,""),o.bus.publish(Ce(Yg,e,{pid:f.pid})),n)try{await this.runTransient(`${e}:post_start`,i.hooks.post_start,i.shell,d,u)}catch(p){throw await o.fail(e,p),p}if(!this.health.isCurrentGeneration(e,s))return;if(this.health.startHealth(e,i,f.pid,c,d,u,s),o.persistState(),o.clearRestartRequired([e]),Ec.waitForHealthy(i)){let p=Ec.timeoutMs(i,ox);try{await this.waitHealthy(e,p)}catch(m){throw await o.fail(e,m),m}}}async awaitWaveHealth(e,t){for(let r of e){let n=this.host().cfg.services[r],o=t.some((s)=>(this.host().cfg.services[s]?.dependencies??[]).some((a)=>lr(a)===r&&zn(a)==="service_healthy"));if(!n||n.health.type===""||!o)continue;let i=Ec.timeoutMs(n,ox);try{await this.waitHealthy(r,i)}catch(s){throw await this.host().fail(r,s),s}}}async waitHealthy(e,t){let r=this.clock.unixMs()+t;while(this.clock.unixMs()<r){let n=this.host().runtimes.get(e);if(n?.health===Qt)return;if(n?.state===bt)throw T(wp,`service ${e} failed while waiting for healthy`);await qI(zI)}throw T(wp,`service ${e} did not become healthy in time`)}async runTransient(e,t,r,n,o){if(Gn(t))return{code:0,stdout:"",stderr:""};this.host().log(e,"INFO",`running ${t.args.join(" ")}`);let i=await this.processes.runOnce({name:e,args:[...t.args],shell:r||t.shell,workDir:n,env:o,graceMs:Vn(this.host().cfg.shutdown)*1000,onLine:(s,a)=>this.host().logs.append({timestamp:this.clock.isoNow(),service:e,source:s,stream:s,level:"",message:a,pid:0})});if(i.code!==0)throw T(Ge,`${e} exited with code ${i.code}`);return i}}function qI(e){return new Promise((t)=>setTimeout(t,e))}ne();function la(e){return async(t)=>{let r=t.includes("/versions/")?t:`${t}/versions/latest`,n=await e(),o=await fetch(`https://secretmanager.googleapis.com/v1/${r}:access`,{headers:{Authorization:`Bearer ${n}`}});if(!o.ok)throw T(ee,`secret manager request failed for ${t}: HTTP ${o.status}`);let i=await o.json();if(!i.payload?.data)throw T(ee,`secret manager response for ${t} had no payload`);return Buffer.from(i.payload.data,"base64").toString("utf8")}}$t();ne();async function Rc(e,t,r,n){let o="";if(e.proxy?.isRunning())o=`http://${e.proxy.address()}`;else if(e.cfg.proxy.enabled)o=`http://${Kn(e.cfg.proxy.listen)}`;let i=ra(t,"127.0.0.1",n,o,e.cfg.project.name);if(i.DEVCTL_INTERNAL_TOKEN=e.internalTok,e.cfg.proxy.token_endpoint.enabled)i.DEVCTL_TOKEN_URL=e.boundTokenURL||`http://127.0.0.1:${e.tokenEP?.listenPort()||e.cfg.proxy.token_endpoint.port}/token`;try{let s=await ta(e.cfg.repoRoot,{service:t,profile:e.serviceProfile.get(t)??e.profile,serviceCfg:r,profileEnv:e.serviceProfileEnv.get(t)??e.profileEnv,assignedPorts:n,runtime:i,cfg:e.cfg,fetchSecret:la(async()=>(await e.tokens.get("user","",[])).accessToken),pluginSources:e.registry?.environmentSources});return Bi(s)}catch(s){return e.log(t,"WARN",`could not fully reconstruct environment for adopted service's health check (${I(s)}); using a baseline environment`),Bi(i)}}function ix(e,t,r,n,o,i){if(e.procs.get(t)&&e.processAliveFn(e.procs.get(t)?.pid??0))return;if(!e.processAliveFn(r)||r===process.pid)return;let s=e.orchestrator.health.bumpGeneration(t);try{e.procs.adopt({name:t,pid:r,args:n,workDir:o,startTime:i,onExit:(a,l)=>{e.orchestrator.health.onExit(t,s,a,l)}})}catch(a){let l=a instanceof Error?a.message:String(a);e.log(t,"WARN",`adopt pid ${r} failed (${l}); tracking leftover in snapshot only`)}return e.processMeta.set(t,{command:n,cwd:o,startTime:i}),e.persistState(),s}async function sx(e,t){let r=e.cfg.services[t];if(e.orchestrator.serviceIsActive(t)){if(r&&!e.ports.has(t)){let a=await Ll(r);if(a)e.ports.set(t,a)}return!0}if(!r)return!1;if(r.container){let a=e.orchestrator.health.bumpGeneration(t),l=r.container.runtime==="podman"?"podman":"docker",c=e.serviceWorkDir(r),u=await e.procs.adoptContainer({name:t,runtime:l,containerName:`devctl-${Tr(e.cfg.repoRoot)}-${t.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,workDir:c,onLine:(p,m)=>e.logs.append({timestamp:e.clock.isoNow(),service:t,source:p,stream:p,level:"",message:m,pid:0}),onExit:(p,m)=>e.orchestrator.health.onExit(t,a,p,m)});if(!u)return!1;let d=e.ports.get(t)??Object.fromEntries(r.ports.filter((p)=>!p.auto).map((p)=>[p.name,p.value]));e.ports.set(t,d),e.processMeta.set(t,{command:[...r.command.args],cwd:c,startTime:u.startTime}),_c(e,t,Pc(e,$n(e.cfg.repoRoot)?.processes.find((p)=>p.name===t))),e.setState(t,Ve,Ft,0,"");let f=await Rc(e,t,r,d);return e.orchestrator.health.startHealth(t,r,0,d,c,f,a),e.persistState(),e.log(t,"INFO",`claimed running ${l} container ${u.container?.id??""}`),!0}let n=await Ll(r);if(!n)return!1;let o=Object.values(n)[0],s=(o===void 0?void 0:await Lo(o))?.pid??0;if(s>0&&s!==process.pid){let a=$n(e.cfg.repoRoot)?.processes.find((u)=>u.name===t&&u.pid===s);if(!a)return e.log(t,"WARN",`port ${o} is held by pid ${s} with no persisted record for ${t}; not adopting`),!1;let l=await e.inspectProcessFn(s);if(l!==void 0&&l.command!==""&&sa({args:[...r.command.args],workDir:e.serviceWorkDir(r),startTime:new Date(a.startTime)},l)){e.ports.set(t,n);let u=ix(e,t,s,[...r.command.args],e.serviceWorkDir(r),new Date(a.startTime))??e.orchestrator.health.bumpGeneration(t);_c(e,t,Pc(e,a)),e.setState(t,Ve,Ft,s,""),e.log(t,"INFO",`already listening on ${Object.values(n).join(", ")}; not starting again`);let d=e.serviceWorkDir(r),f=await Rc(e,t,r,n);return e.orchestrator.health.startHealth(t,r,s,n,d,f,u),!0}e.log(t,"WARN",`port ${o} is in use by an unrelated process (pid ${s}); not adopting`)}return!1}async function ax(e){let t=$n(e.cfg.repoRoot);if(!t)return;GI(e,t.profile);let r=[];for(let[n,o]of Object.entries(e.cfg.services)){if(!o.container)continue;let i=t.processes.find((d)=>d.name===n),s=e.orchestrator.health.bumpGeneration(n),a=o.container.runtime==="podman"?"podman":"docker",l=await e.procs.adoptContainer({name:n,runtime:a,containerName:`devctl-${Tr(e.cfg.repoRoot)}-${n.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,workDir:e.serviceWorkDir(o),onLine:(d,f)=>e.logs.append({timestamp:e.clock.isoNow(),service:n,source:d,stream:d,level:"",message:f,pid:0}),onExit:(d,f)=>e.orchestrator.health.onExit(n,s,d,f)});if(!l)continue;let c=i?.ports??Object.fromEntries(o.ports.filter((d)=>!d.auto).map((d)=>[d.name,d.value]));e.ports.set(n,c),e.processMeta.set(n,{command:[...o.command.args],cwd:e.serviceWorkDir(o),startTime:i?.startTime?new Date(i.startTime):l.startTime}),_c(e,n,Pc(e,i)),e.setState(n,Ve,Ft,0,"");let u=await Rc(e,n,o,c);e.orchestrator.health.startHealth(n,o,0,c,e.serviceWorkDir(o),u,s),e.log(n,"INFO",`adopted ${a} container ${l.container?.id??""}`),r.push(n)}for(let n of t.processes){if(!e.cfg.services[n.name]||e.cfg.services[n.name]?.container||n.pid<=0||n.pid===process.pid||!e.processAliveFn(n.pid))continue;let o=await e.inspectProcessFn(n.pid);if(!(o!==void 0&&o.command!==""&&sa({args:n.command,workDir:n.cwd,startTime:n.startTime?new Date(n.startTime):void 0},o))){if(Object.values(n.ports).length>0&&await Ll({ports:Object.entries(n.ports).map(([c,u])=>({name:c,value:u,auto:!1}))})!==void 0)e.log(n.name,"WARN",`pid ${n.pid} does not match stored command; leftover listener not adopted`);else e.log(n.name,"WARN",`pid ${n.pid} is a different process; not adopting`);continue}let s=ix(e,n.name,n.pid,n.command,n.cwd,new Date(n.startTime||e.clock.unixMs()))??e.orchestrator.health.bumpGeneration(n.name);if(Object.keys(n.ports).length>0)e.ports.set(n.name,n.ports);_c(e,n.name,Pc(e,n)),e.setState(n.name,Ve,Ft,n.pid,"");let a=e.cfg.services[n.name];if(a){let l=n.cwd||e.serviceWorkDir(a),c=await Rc(e,n.name,a,n.ports);e.orchestrator.health.startHealth(n.name,a,n.pid,n.ports,l,c,s)}e.log(n.name,"INFO","adopted leftover process; stdout/stderr from before adopt are not captured"),r.push(n.name)}if(r.length>0)e.bus.publish(Ce(ev,"",{services:r,session_id:t.session_id})),e.log("devctl","INFO",`recovered session processes: ${r.join(", ")}`)}function GI(e,t){e.profile=t||e.profile,e.profileEnv=Ko(e.cfg,e.profile)}function _c(e,t,r){e.serviceProfile.set(t,r),e.serviceProfileEnv.set(t,Ko(e.cfg,r))}function Pc(e,t){return t?.profile??e.profile}import{statSync as cD,watch as uD}from"fs";import{isAbsolute as dD,join as pD,resolve as fD}from"path";function lx(e,t){return t}function Rf(e,t){let r={},n=new Set,o=new Set([...Object.keys(e.services),...Object.keys(t.services)]);for(let s of o){let a=e.services[s],l=t.services[s],c=[];if(!a||!l)c.push("presence"),n.add(s);else{if(a.command.args.join("\x00")!==l.command.args.join("\x00")||a.command.shell!==l.command.shell||a.shell!==l.shell)c.push("command"),n.add(s);if(a.working_dir!==l.working_dir)c.push("working_dir"),n.add(s);if(JSON.stringify(a.environment)!==JSON.stringify(l.environment))c.push("environment"),n.add(s);if(JSON.stringify(a.ports)!==JSON.stringify(l.ports))c.push("ports"),n.add(s);if(JSON.stringify(a.identity)!==JSON.stringify(l.identity))c.push("identity"),n.add(s);if(JSON.stringify(a.health)!==JSON.stringify(l.health))c.push("health"),n.add(s);if(JSON.stringify(a.restart)!==JSON.stringify(l.restart))c.push("restart"),n.add(s);if(JSON.stringify(a.startup)!==JSON.stringify(l.startup))c.push("startup"),n.add(s);if(JSON.stringify(a.logs)!==JSON.stringify(l.logs))c.push("logs"),n.add(s);if(JSON.stringify(a.container)!==JSON.stringify(l.container))c.push("container"),n.add(s);if(JSON.stringify(a.watch)!==JSON.stringify(l.watch))c.push("watch"),n.add(s)}if(c.length>0)r[s]=c}let i=[];if(JSON.stringify(e.logs)!==JSON.stringify(t.logs))i.push("logs");if(JSON.stringify(e.telemetry)!==JSON.stringify(t.telemetry))i.push("telemetry");if(JSON.stringify(e.web)!==JSON.stringify(t.web))i.push("web");if(JSON.stringify(e.auth)!==JSON.stringify(t.auth))i.push("auth");return{restart_required:[...n].sort(),changes:r,supervisor_restart_required:i}}$t();ne();import{pathToFileURL as oD}from"url";import{isAbsolute as iD,resolve as sD}from"path";import{createServer as dx,request as VI}from"http";import{request as YI}from"https";import{Readable as JI}from"stream";ne();Gr();var Yo="traceparent";function KI(e){let t=Date.parse(e.timestamp),r=Number.isNaN(t)?Date.now():t,n=Number.isFinite(e.durationMs)?Math.max(0,e.durationMs):0;return{startUnixNano:(r-n)*qt,endUnixNano:r*qt}}function ca(e){return dv(e)}function ua(e,t,r){e[r]=t.requestId,e[Yo]=gl(t)}function Ac(e,t){let{startUnixNano:r,endUnixNano:n}=KI(e),o=e.status>=500||Boolean(e.error);return{traceId:e.traceId??t?.traceId??(sr(e.requestId)?e.requestId.toLowerCase():Vd()),spanId:e.spanId??t?.spanId??hl(),parentSpanId:e.parentSpanId??t?.parentSpanId,name:`${e.method} ${e.route||e.path}`,kind:"server",startUnixNano:r,endUnixNano:n,status:{code:o?"error":"ok",message:e.error},attributes:{"http.request.method":e.method,"url.path":e.path,"http.route":e.route,"http.response.status_code":e.status,[Gt]:e.requestId,...e.identity?{"enduser.id":e.identity}:{}},events:[],links:[],resource:{"service.name":"proxy"}}}var eo="x-devctl-request-id",XI="x-devctl-internal-token",QI=100;class Lc{cap;items=[];recorded=0;errorCount=0;constructor(e=QI){this.cap=e}record(e){if(this.recorded+=1,e.status>=400||e.error)this.errorCount+=1;if(this.items.push(e),this.items.length>this.cap)this.items.splice(0,this.items.length-this.cap)}stats(){return{total:this.recorded,errors:this.errorCount,recent:[...this.items].reverse()}}}var _f=new Set(["connection","keep-alive","proxy-authenticate","proxy-authorization","te","trailers","transfer-encoding","upgrade"]),ZI=new Set(["gzip","deflate","br"]);class Pf{cfg;tokens;logs;spans;bus;detector;resolvePort;middleware;server;running=!1;addr="";upgradedSockets=new Set;requests=new Lc;constructor(e,t,r,n,o,i=[],s,a){this.cfg=e,this.tokens=t,this.logs=r,this.bus=n,this.detector=o,this.middleware=i,this.resolvePort=s,this.spans=a}upstreamBase(e){let t=e.upstream.service??"";if(t==="")return e.upstream.url;if(!this.resolvePort)throw T(ar,`route ${e.name} addresses service ${t} but this proxy has no port resolver configured`);let r=this.resolvePort(t,e.upstream.port??"");if(r===void 0)throw T(ar,`upstream service ${t} is not running`);return`http://127.0.0.1:${r}`}address(){return this.addr||Kn(this.cfg.listen)}setMiddleware(e){this.middleware=e}isRunning(){return this.running}stats(){return this.requests.stats()}recordRequest(e){if(this.requests.record(e),this.spans&&(e.traceId||e.requestId))this.spans.append(Ac(e))}applyResponseHeaders(e,t){for(let[r,n]of Object.entries(t.response_headers??{}))e.setHeader(r,n)}start(){let e=this.cfg.listen.host||"127.0.0.1";if(!Mt(e))return Promise.reject(T(ar,`refusing to bind proxy to ${e}`));if(this.cfg.listen.port===0)return Promise.reject(T(ar,"proxy.listen.port is required when the proxy is enabled"));let t=this.cfg.listen.port;return new Promise((r,n)=>{this.server=dx((o,i)=>{this.serve(o,i)}),this.server.on("upgrade",(o,i,s)=>{this.serveUpgrade(o,i,s)}),this.server.on("error",(o)=>n(ge(ar,`unable to listen on ${e}:${t}`,o))),this.server.listen(t,e,()=>{this.running=!0,this.addr=`${e}:${t}`,this.bus?.publish(Ce(Qg,"",{address:this.addr})),r()})})}stop(){let e=this.server;if(!e)return Promise.resolve();for(let t of this.upgradedSockets)t.destroy();return this.upgradedSockets.clear(),new Promise((t)=>{e.close(()=>{this.running=!1,this.bus?.publish(Ce(Zg,"",{})),t()})})}async serveUpgrade(e,t,r){let n=Date.now(),o=ca({traceparent:e.headers[Yo]?.toString(),requestId:e.headers[eo]?.toString()}),i=o.requestId,s=e.method??"GET",a=e.url??"/",l=this.detector?this.detector.redactText(a):a,c=ux(this.cfg.routes,e);if(!c){t.end(`HTTP/1.1 404 Not Found\r
|
|
2527
|
+
`;e.onLine?.(a,l)},i=[Tc(t.stdout,"stdout",o),Tc(t.stderr,"stderr",o)],s=await t.exited;return await Promise.all(i),{code:typeof s==="number"?s:0,stdout:r,stderr:n}}async startContainer(e){let t=this.running.get(e.name);if(t&&ia(t))return t;let r=await Gw({...e,env:Kw(e.env)}),n={name:e.name,pid:0,startTime:new Date,workDir:e.workDir,args:[...e.command],done:r.done,container:r};return r.done.finally(()=>{if(this.running.get(e.name)===n)this.running.delete(e.name)}),this.running.set(e.name,n),n}async adoptContainer(e){let t=this.running.get(e.name);if(t&&ia(t))return t;let r=await Vw(e.runtime,e.containerName,e.onLine,e.onExit);if(!r)return;let n={name:e.name,pid:0,startTime:new Date,workDir:e.workDir,args:[],done:r.done,container:r};return r.done.finally(()=>{if(this.running.get(e.name)===n)this.running.delete(e.name)}),this.running.set(e.name,n),n}adopt(e){let t=this.running.get(e.name);if(t&&ia(t))return t;if(!mr(e.pid))throw T(Ge,`cannot adopt ${e.name}: pid ${e.pid} is not running`);let r={name:e.name,pid:e.pid,startTime:e.startTime,workDir:e.workDir,args:[...e.args],done:Promise.resolve({code:0})};return r.done=UI(e.pid).then((n)=>{if(this.running.get(e.name)===r)this.running.delete(e.name);if(e.onExit)e.onExit(n,n===0?void 0:Error(`exited with code ${n}`));return{code:n}}),this.running.set(e.name,r),r}async stop(e,t){let r=this.running.get(e);if(!r)return;let n=t>0?t:NI;if(r.container){await r.container.stop(n),this.running.delete(e);return}if(await Xw(r.pid,"SIGTERM"),!await tx(r.done,n)){if(await Xw(r.pid,"SIGKILL"),!await tx(r.done,FI))throw T(Ge,`process ${e} did not exit after SIGKILL`)}this.running.delete(e)}get(e){return this.running.get(e)}all(){return[...this.running.values()]}}function ia(e){if(e.container)return e.container.running();if(e.proc)return e.proc.exitCode===null&&!e.proc.killed;return mr(e.pid)}async function Xw(e,t){if(process.platform==="win32"){await Bw(e,t);return}await Fw(e,t)}async function rx(e){if(process.platform==="win32")return Ww(e);return $w(e)}async function nx(e){if(process.platform==="win32")return zw(e);return Hw(e)}var HI=2000;function sa(e,t){if(e.workDir!==""&&t.cwd!==""&&ex(e.workDir)!==ex(t.cwd))return!1;if(!Uw(e.args,t.command))return!1;let r=Qw(e.startTime),n=Qw(t.startTime);if(r!==void 0&&n!==void 0)return Math.abs(r-n)<=HI;return!0}function Qw(e){if(e===void 0)return;if(e instanceof Date)return Number.isNaN(e.getTime())?void 0:e.getTime();let t=Date.parse(e);return Number.isNaN(t)?void 0:t}function Zw(e){if(process.platform==="win32")return["cmd.exe","/c",e.join(" ")];return["/bin/sh","-c",e.join(" ")]}function ex(e){return e.replace(/\\/g,"/").replace(/\/+$/,"")}async function UI(e){while(mr(e))await jI($I);return 0}async function Tc(e,t,r){if(!e||typeof e==="number"||!r)return;let n=e.getReader(),o=new TextDecoder,i="";for(;;){let{value:s,done:a}=await n.read();if(a){if(i!=="")r(t,i);return}i+=o.decode(s,{stream:!0});let l=i.split(`
|
|
2528
|
+
`);i=l.pop()??"";for(let c of l)r(t,c.replace(/\r$/,""))}}async function tx(e,t){return Promise.race([e.then(()=>!0),new Promise((r)=>{setTimeout(()=>r(!1),t)})])}function jI(e){return new Promise((t)=>{setTimeout(t,e)})}import{existsSync as BI,readFileSync as WI,writeFileSync as zI}from"fs";var ox={exists:(e)=>BI(e),readText:(e)=>WI(e,"utf8"),writeText:(e,t)=>zI(e,t)};Ke();var kf=3,qI=3,GI=10,Sf={shouldRestart(e){if(!e.enabled||e.policy===Dl)return!1;if(e.retryCount>=e.maxRetries)return!1;if(e.policy===Ml)return!0;return e.policy===Ol&&e.exitCode!==0},fromService(e,t,r){return{policy:$l(e.restart),enabled:e.restart.enabled!==!1,exitCode:r,retryCount:t,maxRetries:e.restart.max_retries>0?e.restart.max_retries:kf}}},Cf={shouldRestartUnhealthy(e,t=qI){return e>=t},shouldResetRestartBudget(e,t=GI){return e>=t}},Ec={timeoutMs(e,t){let r=e.startup.timeout_seconds;return r>0?r*1000:t},waitForHealthy(e){return e.startup.wait_for_healthy}};$t();ne();var KI=2,VI=2000,YI=3,JI=10;class Tf{host;processes;clock;actions;generation=new Map;healthTimers=new Map;restarts=new Map;unhealthyStreak=new Map;healthyStreak=new Map;restartTimers=new Map;constructor(e,t,r,n){this.host=e;this.processes=t;this.clock=r;this.actions=n}forget(e){this.clearHealthWatch(e),this.clearRestartTimer(e),this.restarts.delete(e),this.bumpGeneration(e),this.unhealthyStreak.delete(e),this.healthyStreak.delete(e)}dispose(){this.clearAllRestartTimers();for(let e of this.generation.keys())this.bumpGeneration(e);for(let e of this.healthTimers.keys())this.clearHealthWatch(e)}onExit(e,t,r,n){if(!this.isCurrentGeneration(e,t))return;this.clearHealthWatch(e);let o=this.host().runtimes.get(e);if(o?.state===bt)return;if(o&&(o.state===Kr||o.state===Nt)){this.host().setState(e,Nt,Ft,0,""),this.host().bus.publish(Ce(al,e,{code:r}));return}let i=this.host().cfg.services[e],s=n?.message??`exited with code ${r}`,a=this.restarts.get(e)??0;if((i?Sf.shouldRestart(Sf.fromService(i,a,r)):!1)&&i){this.host().setState(e,Ir,Ft,0,s),this.bumpRestartCount(e,a+1),this.host().persistState(),this.armRestart(e,i,t,a,()=>{let c=this.host().serviceProfile.get(e)??this.host().profile,u=this.host().serviceProfileEnv.get(e)??this.host().profileEnv;this.actions.startOne(e,c,u,!1).catch((d)=>this.host().log(e,"ERROR",I(d)))});return}this.host().fail(e,T("process_start",s))}startHealth(e,t,r,n,o,i,s){let a=this.healthTimers.get(e);if(a)clearInterval(a);if(t.health.type===""){this.setHealth(e,Qt,"no health check");return}let l=t.health.interval_seconds>0?t.health.interval_seconds*1000:VI,c=Date.parse(this.host().runtimes.get(e)?.startTime??"")||this.clock.unixMs(),u=()=>{(t.container&&t.health.type.toLowerCase()==="process"?Promise.resolve(this.processes.isRunning(e)?{status:Qt,message:"container running"}:{status:He,message:"container not running"}):Promise.resolve().then(()=>this.host().healthCheckers.lookup(t.health.type)?.check(t.health,{pid:r,ports:n,workDir:o,env:i})??{status:He,message:`unknown health type ${t.health.type}`})).catch((f)=>({status:He,message:I(f)})).then((f)=>{if(!this.isCurrentGeneration(e,s))return;let p=this.host().runtimes.get(e);if(p&&ix(p.state))return;if(f.status===He&&this.clock.unixMs()-c<t.health.start_period_seconds*1000){this.host().logs.append({timestamp:this.clock.isoNow(),service:e,source:"health",level:"INFO",message:`health check still in start period: ${f.message}`,pid:r});return}this.setHealth(e,f.status,f.message),this.host().logs.append({timestamp:this.clock.isoNow(),service:e,source:"health",level:XI(f.status),message:`health ${f.status} ${f.message}`,pid:r}),this.maybeRestartUnhealthy(e,t,f.status,s)})};u(),this.healthTimers.set(e,setInterval(u,l))}bumpRestartCount(e,t){this.restarts.set(e,t);let r=this.host().runtimes.get(e);if(r)r.restarts=t}resetRestartCount(e){this.healthyStreak.set(e,0),this.bumpRestartCount(e,0)}bumpGeneration(e){let t=(this.generation.get(e)??0)+1;return this.generation.set(e,t),this.healthyStreak.set(e,0),t}isCurrentGeneration(e,t){return this.generation.get(e)===t}scheduleRestart(e,t,r){this.clearRestartTimer(e);let n=setTimeout(()=>{this.restartTimers.delete(e),r()},t);this.restartTimers.set(e,n)}armRestart(e,t,r,n,o){let i=t.restart.backoff_seconds>0?t.restart.backoff_seconds:KI;this.scheduleRestart(e,i*2**n*1000,()=>{if(this.isCurrentGeneration(e,r))o()})}clearRestartTimer(e){let t=this.restartTimers.get(e);if(t)clearTimeout(t),this.restartTimers.delete(e)}clearAllRestartTimers(){for(let e of this.restartTimers.values())clearTimeout(e);this.restartTimers.clear()}setHealth(e,t,r){let n=this.host().runtimes.get(e);if(!n||ix(n.state))return;if(n.health=t,n.state===Ve||n.state===Lr||n.state===cn)n.state=t===Qt?Lr:t===He?cn:n.state;this.host().bus.publish(Ce(Qg,e,{health:t,message:r}))}maybeRestartUnhealthy(e,t,r,n){if(r!==He){if(this.unhealthyStreak.set(e,0),r===Qt)this.maybeForgiveRestarts(e,t);return}this.healthyStreak.set(e,0);let o=t.restart.policy||(t.restart.enabled?"on_failure":"never");if(o!=="on_failure"&&o!=="always")return;if(this.restartTimers.has(e))return;let i=(this.unhealthyStreak.get(e)??0)+1;this.unhealthyStreak.set(e,i);let s=t.health.unhealthy_threshold>0?t.health.unhealthy_threshold:YI;if(!Cf.shouldRestartUnhealthy(i,s))return;this.unhealthyStreak.set(e,0);let a=this.restarts.get(e)??0,l=t.restart.max_retries>0?t.restart.max_retries:kf;if(a>=l){this.host().log(e,"WARN",`unhealthy after ${i} consecutive checks but the restart limit (${l}) has already been reached; not restarting`);return}this.bumpRestartCount(e,a+1),this.host().log(e,"WARN",`restarting after ${i} consecutive unhealthy checks (attempt ${a+1}/${l})`),this.armRestart(e,t,n,a,()=>{this.actions.restart([e],{auto:!0}).catch((c)=>this.host().log(e,"ERROR",I(c)))})}maybeForgiveRestarts(e,t){let r=(this.healthyStreak.get(e)??0)+1;this.healthyStreak.set(e,r);let n=t.health.healthy_reset_threshold>0?t.health.healthy_reset_threshold:JI;if(Cf.shouldResetRestartBudget(r,n)&&(this.restarts.get(e)??0)>0)this.host().log(e,"INFO",`restart count reset after ${r} consecutive healthy checks`),this.bumpRestartCount(e,0)}clearHealthWatch(e){let t=this.healthTimers.get(e);if(t)clearInterval(t),this.healthTimers.delete(e)}}function ix(e){return e===Ir||e===Kr||e===Nt||e===bt}function XI(e){return e===He?"WARN":e===Qt?"INFO":"DEBUG"}Ke();ne();Gr();ne();$t();var Ef=[Kr,bt,Ir,Ve,Nt],QI={[Qb]:[Nt,An,Ve,bt,Ir,Kr],[Nt]:[An,Ve,bt],[An]:[Ve,bt,Nt,Kr],[Ve]:Ef,[Lr]:Ef,[cn]:Ef,[Kr]:[Nt,bt],[bt]:[An,Nt,Ve],[Ir]:[An,Ve,bt,Nt]};function aa(e,t){if(e===t)return!0;return(QI[e]??[]).includes(t)}function sx(e,t){if(!aa(e,t))throw T(ee,`illegal service lifecycle transition ${e} \u2192 ${t}`);return t}$t();var ZI=100,ax=30000;class Rf{processes;clock;session;health;constructor(e,t){this.processes=e;this.clock=t;this.health=new Tf(()=>this.host(),e,t,{startOne:(r,n,o,i)=>this.startOne(r,n,o,i),restart:(r,n)=>this.restart(r,n)})}bind(e){this.session=e}host(){if(!this.session)throw T(Ge,"service orchestrator is not bound");return this.session}planStart(e,t,r){return dc(e,t,r)}planStop(e,t,r=!1){return r?fc(e,t):pc(e,t)}applyLifecycle(e,t){return sx(e,t)}isLegalLifecycle(e,t){return aa(e,t)}async start(e){let t=this.host();if(e.detach===!0)t.detached=!0;let r=hc(t.cfg,{services:e.services,profile:e.profile?Ar(e.profile):void 0,activeProfile:Ar(t.profile)});if(r.profile)t.profile=r.profile,t.profileEnv=r.env;if(e.client_env)for(let a of r.services)t.clientEnv.set(a,e.client_env);if(e.auto!==!0)for(let a of r.services)this.health.resetRestartCount(a);let n=this.planStart(t.cfg,r.services,r.profile),o=await t.detectGoogle(t.cfg.google.project_id);n.blockers=Ab(t.cfg,n.waves.flat(),o.adcAvailable);let i=new Set(n.blockers.map((a)=>a.name));for(let a of n.blockers)await t.fail(a.name,T(Ge,a.message));if(t.cfg.proxy.enabled&&!t.proxySuppressed)await t.startProxy().catch((a)=>t.log("devctl","ERROR",I(a)));let s=[];for(let a of n.waves.flat()){if(i.has(a)||await t.claimIfAlreadyUp(a))continue;s.push(a)}for(let a of s)if(e.profile||!t.serviceProfile.has(a))t.serviceProfile.set(a,r.profile);if(s.length>0)await t.assignPendingPorts(s);for(let a of n.waves){let l=a.filter((c)=>s.includes(c));if(l.length>0){let c=await Promise.allSettled(l.map((d)=>this.startOne(d,r.profile,r.env,e.auto!==!0))),u=!1;for(let d of c)if(d.status==="rejected")u=!0,t.log("devctl","ERROR",I(d.reason));if(u)throw T(Ge,"one or more services failed to start")}try{await this.awaitWaveHealth(a,n.waves.flat())}catch(c){throw t.log("devctl","ERROR",I(c)),c}}return t.persistState(),n}async stop(e){let t=this.host(),r=e;if(r.length===0)r=[...t.runtimes.entries()].filter(([,s])=>s.state!==Nt).map(([s])=>s);if(r.length===0)return;let n=r.filter((s)=>!t.cfg.services[s]&&t.runtimes.has(s)),o=r.filter((s)=>!t.cfg.services[s]&&!t.runtimes.has(s));if(o.length>0)throw T(Pi,`unknown service "${o[0]}"`);let i=r.filter((s)=>t.cfg.services[s]!==void 0);if(i.length>0)await this.runStopPlan(this.planStop(t.cfg,i),{resetRestartCounts:!0});if(n.length>0){await this.runStopPlan({profile:t.profile,steps:[],waves:n.map((s)=>[s])},{resetRestartCounts:!0});for(let s of n)t.forgetService(s)}}async restart(e,t){let r=this.host(),n=t?.cascade===!0,o=n?Go(r.cfg,e):e,i=n?this.planStop(r.cfg,e):this.planStop(r.cfg,e,!0),s=t?.auto!==!0;await this.runStopPlan(i,{resetRestartCounts:s}),await this.start({services:o,client_env:t?.clientEnv,auto:t?.auto})}async runStopPlan(e,t){let r=this.host();for(let i of e.waves.flat())if(this.health.clearRestartTimer(i),this.health.bumpGeneration(i),t?.resetRestartCounts)this.health.resetRestartCount(i);let n=Vn(r.cfg.shutdown)*1000,o=[];for(let i of e.waves){let s=await Promise.allSettled(i.map(async(a)=>{r.setState(a,Kr,Ft,0,""),this.health.clearHealthWatch(a);try{await this.processes.stop(a,n)}catch(l){throw r.setState(a,bt,Ft,0,I(l)),r.bus.publish(Ce(ll,a,{error:I(l)})),l}try{await r.releasePorts(a)}catch(l){r.log(a,"WARN",I(l))}r.setState(a,Nt,Ft,0,""),r.bus.publish(Ce(al,a,{}))}));for(let a=0;a<s.length;a+=1){let l=s[a];if(l?.status==="rejected"){let c=i[a]??"";o.push(c),r.log(c||"devctl","ERROR",I(l.reason))}}}if(r.persistState(),o.length>0)throw T(Ge,`failed to stop: ${o.join(", ")}`)}serviceIsActive(e){if(this.processes.isRunning(e))return!0;let t=this.host().runtimes.get(e);if(!t)return!1;if(t.state===Ir||t.state===Kr||t.state===Nt||t.state===bt)return!1;if(t.health===Qt||t.state===Lr)return!0;return t.state===An||t.state===Ve}async startOne(e,t,r,n=!1){let o=this.host();if(this.serviceIsActive(e))return;let i=o.cfg.services[e];if(!i)throw T($e,`unknown service ${e}`);o.setState(e,An,Ft,0,"");let s=this.health.bumpGeneration(e),a=o.serviceProfile.get(e)??t,l=a!==""?Ko(o.cfg,a):{...r};o.serviceProfileEnv.set(e,l);let c={},u={},d="",f;try{await o.prepareServiceIdentity(e,i),c=o.ports.get(e)??{};let p=await o.resolveServiceExecution(e,i,a,l,o.clientEnv.get(e),!i.container);if(u=p.env,d=p.workDir,n)await this.runTransient(`${e}:pre_start`,i.hooks.pre_start,i.shell,d,u);if(!this.health.isCurrentGeneration(e,s))return;let m=(g,w)=>{o.logs.append({timestamp:this.clock.isoNow(),service:e,source:g,stream:g,level:"",message:w,pid:f.pid})},h=(g,w)=>this.health.onExit(e,s,g,w);f=i.container?await this.processes.startContainer({name:e,runtime:i.container.runtime==="podman"?"podman":"docker",containerName:`${o.containerPrefix}${e.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,image:i.container.image,command:[...i.command.args],env:{...u,...i.container.env},ports:c,targetPorts:i.container.ports,volumes:i.container.volumes,workDir:d,onLine:m,onExit:h}):await this.processes.start({name:e,args:[...i.command.args],shell:i.shell||i.command.shell,workDir:d,env:u,graceMs:Vn(o.cfg.shutdown)*1000,captureStdout:fy(i),captureStderr:my(i),onLine:m,onExit:h})}catch(p){if(this.health.isCurrentGeneration(e,s))await o.fail(e,p);throw p}if(!this.health.isCurrentGeneration(e,s)){if(this.processes.get(e)===f)await this.processes.stop(e,Vn(o.cfg.shutdown)*1000).catch(()=>{});return}if(o.processMeta.set(e,{command:[...i.command.args],cwd:d,startTime:f.startTime}),o.setState(e,Ve,Ft,f.pid,""),o.bus.publish(Ce(Jg,e,{pid:f.pid})),n)try{await this.runTransient(`${e}:post_start`,i.hooks.post_start,i.shell,d,u)}catch(p){throw await o.fail(e,p),p}if(!this.health.isCurrentGeneration(e,s))return;if(this.health.startHealth(e,i,f.pid,c,d,u,s),o.persistState(),o.clearRestartRequired([e]),Ec.waitForHealthy(i)){let p=Ec.timeoutMs(i,ax);try{await this.waitHealthy(e,p)}catch(m){throw await o.fail(e,m),m}}}async awaitWaveHealth(e,t){for(let r of e){let n=this.host().cfg.services[r],o=t.some((s)=>(this.host().cfg.services[s]?.dependencies??[]).some((a)=>lr(a)===r&&zn(a)==="service_healthy"));if(!n||n.health.type===""||!o)continue;let i=Ec.timeoutMs(n,ax);try{await this.waitHealthy(r,i)}catch(s){throw await this.host().fail(r,s),s}}}async waitHealthy(e,t){let r=this.clock.unixMs()+t;while(this.clock.unixMs()<r){let n=this.host().runtimes.get(e);if(n?.health===Qt)return;if(n?.state===bt)throw T(wp,`service ${e} failed while waiting for healthy`);await eD(ZI)}throw T(wp,`service ${e} did not become healthy in time`)}async runTransient(e,t,r,n,o){if(Gn(t))return{code:0,stdout:"",stderr:""};this.host().log(e,"INFO",`running ${t.args.join(" ")}`);let i=await this.processes.runOnce({name:e,args:[...t.args],shell:r||t.shell,workDir:n,env:o,graceMs:Vn(this.host().cfg.shutdown)*1000,onLine:(s,a)=>this.host().logs.append({timestamp:this.clock.isoNow(),service:e,source:s,stream:s,level:"",message:a,pid:0})});if(i.code!==0)throw T(Ge,`${e} exited with code ${i.code}`);return i}}function eD(e){return new Promise((t)=>setTimeout(t,e))}ne();function la(e){return async(t)=>{let r=t.includes("/versions/")?t:`${t}/versions/latest`,n=await e(),o=await fetch(`https://secretmanager.googleapis.com/v1/${r}:access`,{headers:{Authorization:`Bearer ${n}`}});if(!o.ok)throw T(ee,`secret manager request failed for ${t}: HTTP ${o.status}`);let i=await o.json();if(!i.payload?.data)throw T(ee,`secret manager response for ${t} had no payload`);return Buffer.from(i.payload.data,"base64").toString("utf8")}}$t();ne();async function Rc(e,t,r,n){let o="";if(e.proxy?.isRunning())o=`http://${e.proxy.address()}`;else if(e.cfg.proxy.enabled)o=`http://${Kn(e.cfg.proxy.listen)}`;let i=ra(t,"127.0.0.1",n,o,e.cfg.project.name);if(i.DEVCTL_INTERNAL_TOKEN=e.internalTok,e.cfg.proxy.token_endpoint.enabled)i.DEVCTL_TOKEN_URL=e.boundTokenURL||`http://127.0.0.1:${e.tokenEP?.listenPort()||e.cfg.proxy.token_endpoint.port}/token`;try{let s=await ta(e.cfg.repoRoot,{service:t,profile:e.serviceProfile.get(t)??e.profile,serviceCfg:r,profileEnv:e.serviceProfileEnv.get(t)??e.profileEnv,assignedPorts:n,runtime:i,cfg:e.cfg,fetchSecret:la(async()=>(await e.tokens.get("user","",[])).accessToken),pluginSources:e.registry?.environmentSources});return Bi(s)}catch(s){return e.log(t,"WARN",`could not fully reconstruct environment for adopted service's health check (${I(s)}); using a baseline environment`),Bi(i)}}function lx(e,t,r,n,o,i){if(e.procs.get(t)&&e.processAliveFn(e.procs.get(t)?.pid??0))return;if(!e.processAliveFn(r)||r===process.pid)return;let s=e.orchestrator.health.bumpGeneration(t);try{e.procs.adopt({name:t,pid:r,args:n,workDir:o,startTime:i,onExit:(a,l)=>{e.orchestrator.health.onExit(t,s,a,l)}})}catch(a){let l=a instanceof Error?a.message:String(a);e.log(t,"WARN",`adopt pid ${r} failed (${l}); tracking leftover in snapshot only`)}return e.processMeta.set(t,{command:n,cwd:o,startTime:i}),e.persistState(),s}async function cx(e,t){let r=e.cfg.services[t];if(e.orchestrator.serviceIsActive(t)){if(r&&!e.ports.has(t)){let a=await Ll(r);if(a)e.ports.set(t,a)}return!0}if(!r)return!1;if(r.container){let a=e.orchestrator.health.bumpGeneration(t),l=r.container.runtime==="podman"?"podman":"docker",c=e.serviceWorkDir(r),u=await e.procs.adoptContainer({name:t,runtime:l,containerName:`devctl-${Tr(e.cfg.repoRoot)}-${t.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,workDir:c,onLine:(p,m)=>e.logs.append({timestamp:e.clock.isoNow(),service:t,source:p,stream:p,level:"",message:m,pid:0}),onExit:(p,m)=>e.orchestrator.health.onExit(t,a,p,m)});if(!u)return!1;let d=e.ports.get(t)??Object.fromEntries(r.ports.filter((p)=>!p.auto).map((p)=>[p.name,p.value]));e.ports.set(t,d),e.processMeta.set(t,{command:[...r.command.args],cwd:c,startTime:u.startTime}),_c(e,t,Pc(e,$n(e.cfg.repoRoot)?.processes.find((p)=>p.name===t))),e.setState(t,Ve,Ft,0,"");let f=await Rc(e,t,r,d);return e.orchestrator.health.startHealth(t,r,0,d,c,f,a),e.persistState(),e.log(t,"INFO",`claimed running ${l} container ${u.container?.id??""}`),!0}let n=await Ll(r);if(!n)return!1;let o=Object.values(n)[0],s=(o===void 0?void 0:await Lo(o))?.pid??0;if(s>0&&s!==process.pid){let a=$n(e.cfg.repoRoot)?.processes.find((u)=>u.name===t&&u.pid===s);if(!a)return e.log(t,"WARN",`port ${o} is held by pid ${s} with no persisted record for ${t}; not adopting`),!1;let l=await e.inspectProcessFn(s);if(l!==void 0&&l.command!==""&&sa({args:[...r.command.args],workDir:e.serviceWorkDir(r),startTime:new Date(a.startTime)},l)){e.ports.set(t,n);let u=lx(e,t,s,[...r.command.args],e.serviceWorkDir(r),new Date(a.startTime))??e.orchestrator.health.bumpGeneration(t);_c(e,t,Pc(e,a)),e.setState(t,Ve,Ft,s,""),e.log(t,"INFO",`already listening on ${Object.values(n).join(", ")}; not starting again`);let d=e.serviceWorkDir(r),f=await Rc(e,t,r,n);return e.orchestrator.health.startHealth(t,r,s,n,d,f,u),!0}e.log(t,"WARN",`port ${o} is in use by an unrelated process (pid ${s}); not adopting`)}return!1}async function ux(e){let t=$n(e.cfg.repoRoot);if(!t)return;tD(e,t.profile);let r=[];for(let[n,o]of Object.entries(e.cfg.services)){if(!o.container)continue;let i=t.processes.find((d)=>d.name===n),s=e.orchestrator.health.bumpGeneration(n),a=o.container.runtime==="podman"?"podman":"docker",l=await e.procs.adoptContainer({name:n,runtime:a,containerName:`devctl-${Tr(e.cfg.repoRoot)}-${n.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,workDir:e.serviceWorkDir(o),onLine:(d,f)=>e.logs.append({timestamp:e.clock.isoNow(),service:n,source:d,stream:d,level:"",message:f,pid:0}),onExit:(d,f)=>e.orchestrator.health.onExit(n,s,d,f)});if(!l)continue;let c=i?.ports??Object.fromEntries(o.ports.filter((d)=>!d.auto).map((d)=>[d.name,d.value]));e.ports.set(n,c),e.processMeta.set(n,{command:[...o.command.args],cwd:e.serviceWorkDir(o),startTime:i?.startTime?new Date(i.startTime):l.startTime}),_c(e,n,Pc(e,i)),e.setState(n,Ve,Ft,0,"");let u=await Rc(e,n,o,c);e.orchestrator.health.startHealth(n,o,0,c,e.serviceWorkDir(o),u,s),e.log(n,"INFO",`adopted ${a} container ${l.container?.id??""}`),r.push(n)}for(let n of t.processes){if(!e.cfg.services[n.name]||e.cfg.services[n.name]?.container||n.pid<=0||n.pid===process.pid||!e.processAliveFn(n.pid))continue;let o=await e.inspectProcessFn(n.pid);if(!(o!==void 0&&o.command!==""&&sa({args:n.command,workDir:n.cwd,startTime:n.startTime?new Date(n.startTime):void 0},o))){if(Object.values(n.ports).length>0&&await Ll({ports:Object.entries(n.ports).map(([c,u])=>({name:c,value:u,auto:!1}))})!==void 0)e.log(n.name,"WARN",`pid ${n.pid} does not match stored command; leftover listener not adopted`);else e.log(n.name,"WARN",`pid ${n.pid} is a different process; not adopting`);continue}let s=lx(e,n.name,n.pid,n.command,n.cwd,new Date(n.startTime||e.clock.unixMs()))??e.orchestrator.health.bumpGeneration(n.name);if(Object.keys(n.ports).length>0)e.ports.set(n.name,n.ports);_c(e,n.name,Pc(e,n)),e.setState(n.name,Ve,Ft,n.pid,"");let a=e.cfg.services[n.name];if(a){let l=n.cwd||e.serviceWorkDir(a),c=await Rc(e,n.name,a,n.ports);e.orchestrator.health.startHealth(n.name,a,n.pid,n.ports,l,c,s)}e.log(n.name,"INFO","adopted leftover process; stdout/stderr from before adopt are not captured"),r.push(n.name)}if(r.length>0)e.bus.publish(Ce(tv,"",{services:r,session_id:t.session_id})),e.log("devctl","INFO",`recovered session processes: ${r.join(", ")}`)}function tD(e,t){e.profile=t||e.profile,e.profileEnv=Ko(e.cfg,e.profile)}function _c(e,t,r){e.serviceProfile.set(t,r),e.serviceProfileEnv.set(t,Ko(e.cfg,r))}function Pc(e,t){return t?.profile??e.profile}import{statSync as yD,watch as bD}from"fs";import{isAbsolute as wD,join as xD,resolve as kD}from"path";function dx(e,t){return t}function _f(e,t){let r={},n=new Set,o=new Set([...Object.keys(e.services),...Object.keys(t.services)]);for(let s of o){let a=e.services[s],l=t.services[s],c=[];if(!a||!l)c.push("presence"),n.add(s);else{if(a.command.args.join("\x00")!==l.command.args.join("\x00")||a.command.shell!==l.command.shell||a.shell!==l.shell)c.push("command"),n.add(s);if(a.working_dir!==l.working_dir)c.push("working_dir"),n.add(s);if(JSON.stringify(a.environment)!==JSON.stringify(l.environment))c.push("environment"),n.add(s);if(JSON.stringify(a.ports)!==JSON.stringify(l.ports))c.push("ports"),n.add(s);if(JSON.stringify(a.identity)!==JSON.stringify(l.identity))c.push("identity"),n.add(s);if(JSON.stringify(a.health)!==JSON.stringify(l.health))c.push("health"),n.add(s);if(JSON.stringify(a.restart)!==JSON.stringify(l.restart))c.push("restart"),n.add(s);if(JSON.stringify(a.startup)!==JSON.stringify(l.startup))c.push("startup"),n.add(s);if(JSON.stringify(a.logs)!==JSON.stringify(l.logs))c.push("logs"),n.add(s);if(JSON.stringify(a.container)!==JSON.stringify(l.container))c.push("container"),n.add(s);if(JSON.stringify(a.watch)!==JSON.stringify(l.watch))c.push("watch"),n.add(s)}if(c.length>0)r[s]=c}let i=[];if(JSON.stringify(e.logs)!==JSON.stringify(t.logs))i.push("logs");if(JSON.stringify(e.telemetry)!==JSON.stringify(t.telemetry))i.push("telemetry");if(JSON.stringify(e.web)!==JSON.stringify(t.web))i.push("web");if(JSON.stringify(e.auth)!==JSON.stringify(t.auth))i.push("auth");return{restart_required:[...n].sort(),changes:r,supervisor_restart_required:i}}$t();ne();import{pathToFileURL as fD}from"url";import{isAbsolute as mD,resolve as hD}from"path";import{createServer as mx,request as nD}from"http";import{request as oD}from"https";import{Readable as iD}from"stream";ne();Gr();var Yo="traceparent";function rD(e){let t=Date.parse(e.timestamp),r=Number.isNaN(t)?Date.now():t,n=Number.isFinite(e.durationMs)?Math.max(0,e.durationMs):0;return{startUnixNano:(r-n)*qt,endUnixNano:r*qt}}function ca(e){return pv(e)}function ua(e,t,r){e[r]=t.requestId,e[Yo]=gl(t)}function Ac(e,t){let{startUnixNano:r,endUnixNano:n}=rD(e),o=e.status>=500||Boolean(e.error);return{traceId:e.traceId??t?.traceId??(sr(e.requestId)?e.requestId.toLowerCase():Vd()),spanId:e.spanId??t?.spanId??hl(),parentSpanId:e.parentSpanId??t?.parentSpanId,name:`${e.method} ${e.route||e.path}`,kind:"server",startUnixNano:r,endUnixNano:n,status:{code:o?"error":"ok",message:e.error},attributes:{"http.request.method":e.method,"url.path":e.path,"http.route":e.route,"http.response.status_code":e.status,[Gt]:e.requestId,...e.identity?{"enduser.id":e.identity}:{}},events:[],links:[],resource:{"service.name":"proxy"}}}var eo="x-devctl-request-id",sD="x-devctl-internal-token",aD=100;class Lc{cap;items=[];recorded=0;errorCount=0;constructor(e=aD){this.cap=e}record(e){if(this.recorded+=1,e.status>=400||e.error)this.errorCount+=1;if(this.items.push(e),this.items.length>this.cap)this.items.splice(0,this.items.length-this.cap)}stats(){return{total:this.recorded,errors:this.errorCount,recent:[...this.items].reverse()}}}var Pf=new Set(["connection","keep-alive","proxy-authenticate","proxy-authorization","te","trailers","transfer-encoding","upgrade"]),lD=new Set(["gzip","deflate","br"]);class Af{cfg;tokens;logs;spans;bus;detector;resolvePort;middleware;server;running=!1;addr="";upgradedSockets=new Set;requests=new Lc;constructor(e,t,r,n,o,i=[],s,a){this.cfg=e,this.tokens=t,this.logs=r,this.bus=n,this.detector=o,this.middleware=i,this.resolvePort=s,this.spans=a}upstreamBase(e){let t=e.upstream.service??"";if(t==="")return e.upstream.url;if(!this.resolvePort)throw T(ar,`route ${e.name} addresses service ${t} but this proxy has no port resolver configured`);let r=this.resolvePort(t,e.upstream.port??"");if(r===void 0)throw T(ar,`upstream service ${t} is not running`);return`http://127.0.0.1:${r}`}address(){return this.addr||Kn(this.cfg.listen)}setMiddleware(e){this.middleware=e}isRunning(){return this.running}stats(){return this.requests.stats()}recordRequest(e){if(this.requests.record(e),this.spans&&(e.traceId||e.requestId))this.spans.append(Ac(e))}applyResponseHeaders(e,t){for(let[r,n]of Object.entries(t.response_headers??{}))e.setHeader(r,n)}start(){let e=this.cfg.listen.host||"127.0.0.1";if(!_t(e))return Promise.reject(T(ar,`refusing to bind proxy to ${e}`));if(this.cfg.listen.port===0)return Promise.reject(T(ar,"proxy.listen.port is required when the proxy is enabled"));let t=this.cfg.listen.port;return new Promise((r,n)=>{this.server=mx((o,i)=>{this.serve(o,i)}),this.server.on("upgrade",(o,i,s)=>{this.serveUpgrade(o,i,s)}),this.server.on("error",(o)=>n(ge(ar,`unable to listen on ${e}:${t}`,o))),this.server.listen(t,e,()=>{this.running=!0,this.addr=`${e}:${t}`,this.bus?.publish(Ce(Zg,"",{address:this.addr})),r()})})}stop(){let e=this.server;if(!e)return Promise.resolve();for(let t of this.upgradedSockets)t.destroy();return this.upgradedSockets.clear(),new Promise((t)=>{e.close(()=>{this.running=!1,this.bus?.publish(Ce(ev,"",{})),t()})})}async serveUpgrade(e,t,r){let n=Date.now(),o=ca({traceparent:e.headers[Yo]?.toString(),requestId:e.headers[eo]?.toString()}),i=o.requestId,s=e.method??"GET",a=e.url??"/",l=this.detector?this.detector.redactText(a):a,c=fx(this.cfg.routes,e);if(!c){t.end(`HTTP/1.1 404 Not Found\r
|
|
2523
2529
|
Connection: close\r
|
|
2524
2530
|
Content-Length: 0\r
|
|
2525
2531
|
\r
|
|
2526
|
-
`),this.recordRequest({timestamp:new Date().toISOString(),requestId:i,method:s,path:l,route:"",identity:"",status:404,durationMs:Date.now()-n,traceId:o.traceId,spanId:o.spanId,parentSpanId:o.parentSpanId});return}let u=Pn(c.auth),d=Qn(u),f,p=!1,m=(g,w)=>{if(p)return;p=!0;let v=Date.now()-n;this.recordRequest({timestamp:new Date().toISOString(),requestId:i,method:s,path:l,route:c.name,identity:d,status:g,durationMs:v,error:w,traceId:o.traceId,spanId:o.spanId,parentSpanId:o.parentSpanId}),this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:g>=400||w?"ERROR":"INFO",message:`${s} ${a} route=${c.name} identity=${d} status=${g} duration=${v}ms upgrade=true${w?` error=${w}`:""}`,pid:0,request_id:i,identity:d}),this.bus?.publish(Ce(Cs,c.name,{status:g,request_id:i,duration:v,identity:d}))},h=()=>{t.destroy(),f?.destroy()};try{let g={};for(let[y,b]of Object.entries(e.headers)){let k=y.toLowerCase();if(
|
|
2532
|
+
`),this.recordRequest({timestamp:new Date().toISOString(),requestId:i,method:s,path:l,route:"",identity:"",status:404,durationMs:Date.now()-n,traceId:o.traceId,spanId:o.spanId,parentSpanId:o.parentSpanId});return}let u=Pn(c.auth),d=Qn(u),f,p=!1,m=(g,w)=>{if(p)return;p=!0;let v=Date.now()-n;this.recordRequest({timestamp:new Date().toISOString(),requestId:i,method:s,path:l,route:c.name,identity:d,status:g,durationMs:v,error:w,traceId:o.traceId,spanId:o.spanId,parentSpanId:o.parentSpanId}),this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:g>=400||w?"ERROR":"INFO",message:`${s} ${a} route=${c.name} identity=${d} status=${g} duration=${v}ms upgrade=true${w?` error=${w}`:""}`,pid:0,request_id:i,identity:d}),this.bus?.publish(Ce(Cs,c.name,{status:g,request_id:i,duration:v,identity:d}))},h=()=>{t.destroy(),f?.destroy()};try{let g={};for(let[y,b]of Object.entries(e.headers)){let k=y.toLowerCase();if(Pf.has(k)&&k!=="connection"&&k!=="upgrade")continue;if(typeof b==="string")g[y]=b;else if(Array.isArray(b))g[y]=b.join(",")}let w=e.socket.remoteAddress??"",v=g.host??"",S=g["x-forwarded-for"];if(g["x-forwarded-for"]=S?`${S}, ${w}`:w,g["x-forwarded-host"]=v,g["x-forwarded-proto"]="http",delete g.host,ua(g,o,eo),this.middleware.length===0)await qi(c,g,this.tokens);for(let y of this.middleware)await y.apply({route:c,headers:g,tokens:this.tokens,req:e,method:s,path:a,upgrade:!0});let E=px(this.upstreamBase(c),a),_=uD(E)(E,{method:s,headers:g});_.on("upgrade",(y,b,k)=>{f=b,this.upgradedSockets.add(t),this.upgradedSockets.add(b);let x=()=>{this.upgradedSockets.delete(t),this.upgradedSockets.delete(b)};t.once("close",()=>{x(),b.destroy()}),b.once("close",()=>{x(),t.destroy()}),t.once("error",h),b.once("error",h);let L=`HTTP/${y.httpVersion} ${y.statusCode??101} ${y.statusMessage??"Switching Protocols"}\r
|
|
2527
2533
|
`,F=y.rawHeaders.map((B,K)=>`${K%2===0?B+":":" "+B+`\r
|
|
2528
2534
|
`}`).join("");if(t.write(`${L}${F}\r
|
|
2529
2535
|
`),r.length>0)b.write(r);if(k.length>0)t.write(k);t.pipe(b).pipe(t),m(y.statusCode??101)}),_.on("response",(y)=>{y.resume();let b=y.statusCode??502;t.end(`HTTP/1.1 ${b} ${y.statusMessage??"Bad Gateway"}\r
|
|
@@ -2538,11 +2544,11 @@ Content-Length: 0\r
|
|
|
2538
2544
|
Connection: close\r
|
|
2539
2545
|
Content-Length: 0\r
|
|
2540
2546
|
\r
|
|
2541
|
-
`)}}async serve(e,t){let r=Date.now(),n=ca({traceparent:e.headers[Yo]?.toString(),requestId:e.headers[eo]?.toString()}),o=n.requestId;t.setHeader(eo,o),t.setHeader(Yo,gl(n));let i=e.method??"GET",s=e.url??"/",a=this.detector?this.detector.redactText(s):s,l=ux(this.cfg.routes,e);if(!l){zi(t,404,"no matching proxy route"),this.recordRequest({timestamp:new Date().toISOString(),requestId:o,method:i,path:a,route:"",identity:"",status:404,durationMs:Date.now()-r,traceId:n.traceId,spanId:n.spanId,parentSpanId:n.parentSpanId});return}if(i==="OPTIONS"&&e.headers["access-control-request-method"]!==void 0&&Object.keys(l.response_headers??{}).length>0){this.applyResponseHeaders(t,l),t.statusCode=204,t.setHeader("content-length","0"),t.end(),this.recordRequest({timestamp:new Date().toISOString(),requestId:o,method:i,path:a,route:l.name,identity:"",status:204,durationMs:Date.now()-r,traceId:n.traceId,spanId:n.spanId,parentSpanId:n.parentSpanId});return}let c=Pn(l.auth),u=Qn(c),d=0,f;try{let p={};for(let[b,k]of Object.entries(e.headers)){if(_f.has(b.toLowerCase()))continue;if(typeof k==="string")p[b]=k;else if(Array.isArray(k))p[b]=k.join(",")}let m=e.socket.remoteAddress??"",h=p.host??"",g=p["x-forwarded-for"];if(p["x-forwarded-for"]=g?`${g}, ${m}`:m,p["x-forwarded-host"]=h,p["x-forwarded-proto"]="http",delete p.host,p["accept-encoding"]="gzip, deflate, br",ua(p,n,eo),this.middleware.length===0)await qi(l,p,this.tokens);for(let b of this.middleware)await b.apply({route:l,headers:p,tokens:this.tokens});let w=cx(this.upstreamBase(l),s),v=i!=="GET"&&i!=="HEAD"?e:void 0,S=await fetch(w,{method:i,headers:p,body:v,redirect:"manual",duplex:v?"half":void 0});t.statusCode=S.status,d=S.status;let E=(S.headers.get("content-encoding")??"").split(",").map((b)=>b.trim().toLowerCase()).filter((b)=>b!==""),_=E.length>0&&E.every((b)=>ZI.has(b));S.headers.forEach((b,k)=>{let x=k.toLowerCase();if(_f.has(x))return;if(_&&(x==="content-encoding"||x==="content-length"))return;t.setHeader(k,this.detector?this.detector.redactText(b):b)}),this.applyResponseHeaders(t,l),await eD(S,t);let y=Date.now()-r;this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:S.status>=400?"WARN":"INFO",message:`${i} ${s} route=${l.name} identity=${u} status=${S.status} duration=${y}ms`,pid:0,request_id:o,identity:u}),this.bus?.publish(Ce(Cs,l.name,{status:S.status,request_id:o,duration:y,identity:u}))}catch(p){let m=p instanceof Error?p.message:"proxy error";f=m,d=502,this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:"ERROR",message:`${i} ${s} route=${l.name} identity=${u} error=${m}`,pid:0,request_id:o,identity:u}),this.applyResponseHeaders(t,l),zi(t,502,"proxy error")}finally{this.recordRequest({timestamp:new Date().toISOString(),requestId:o,method:i,path:a,route:l.name,identity:u,status:d,durationMs:Date.now()-r,error:f,traceId:n.traceId,spanId:n.spanId,parentSpanId:n.parentSpanId})}}}async function qi(e,t,r){let n=e.auth.type.toLowerCase();if(n===""||n==="none")return;if(!r)throw T(ar,"token manager unavailable");let o=Pn(e.auth),i=await r.get(Qn(o),e.auth.audience,[],lc(e.auth));t.authorization=`Bearer ${i.accessToken}`;for(let[s,a]of Object.entries(e.auth.headers??{}))t[s]=a.includes("${token}")?a.replaceAll("${token}",i.accessToken):a}async function eD(e,t){if(!e.body){t.end();return}let r=JI.fromWeb(e.body);await new Promise((n,o)=>{r.on("error",o),t.on("error",o),t.on("finish",n),r.pipe(t)})}function tD(e){return e.protocol==="https:"?YI:VI}function cx(e,t){let r=new URL(e),n=new URL(t||"/",r),o=new URL(r.href);if(o.pathname=rD(n.pathname),o.search=n.search,o.hash="",o.origin!==r.origin)throw T(ar,"refusing to proxy to a different origin");return o}function rD(e){return(e.startsWith("/")?e:`/${e}`).replace(/^\/+/,"/")}function zi(e,t,r){e.statusCode=t,e.setHeader("content-type","text/plain; charset=utf-8"),e.setHeader("x-content-type-options","nosniff"),e.end(r)}function ux(e,t){let r=(t.headers.host??"").split(":")[0]??"",n=t.url??"/";return e.find((o)=>{if(Wn(o))return!1;let i=o.match.host===""||o.match.host===r,s=o.match.path===""||n.startsWith(o.match.path);return i&&s})}class Af{host;port;secret;tokens;server;constructor(e,t,r,n){this.host=e;this.port=t;this.secret=r;this.tokens=n}listenPort(){let e=this.server?.address();if(typeof e==="object"&&e)return e.port;return this.port}start(){let e=this.host||"127.0.0.1";if(!Mt(e))return Promise.reject(T(ar,`refusing to bind token endpoint to ${e}`));return new Promise((t,r)=>{this.server=dx((n,o)=>{this.serve(n,o)}),this.server.on("error",(n)=>r(ge(ar,"token endpoint listen failed",n))),this.server.listen(this.port,e,()=>t())})}stop(){let e=this.server;if(!e)return Promise.resolve();return new Promise((t)=>e.close(()=>t()))}async serve(e,t){if(!nD(e.socket.remoteAddress)){zi(t,403,"forbidden");return}if((e.headers[XI]??"")!==this.secret){zi(t,401,"unauthorized");return}if(e.url?.startsWith("/token")!==!0){zi(t,404,"not found");return}let r=new URL(e.url,"http://127.0.0.1"),n=r.searchParams.get("identity")??"user",o=r.searchParams.get("audience")??"";try{let i=await this.tokens.get(n,o,[]);t.setHeader("content-type","application/json"),t.end(JSON.stringify({access_token:i.accessToken,token_type:i.tokenType,expires_at:i.expiresAt.toISOString(),identity:i.identity}))}catch{zi(t,500,"token error")}}}function nD(e){if(!e)return!0;return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}Gr();var px=1;class fx{tokenProviders=[];identityProviders=[];pluginIdentityProviders=[];environmentSources=[];healthChecks=[];logParsers=[];proxyMiddleware=[];loadErrors=[];pluginPaths=[];registerBuiltins(){this.tokenProviders.push(...Zn()),this.identityProviders.push(Xp(),Qp()),this.logParsers.push(Ov()),this.proxyMiddleware.push(lD())}register(e){aD(e),Jo(this.tokenProviders,e.tokenProviders),Jo(this.identityProviders,e.identityProviders),Jo(this.pluginIdentityProviders,e.identityProviders),Jo(this.environmentSources,e.environmentSources),Jo(this.healthChecks,e.healthChecks),Jo(this.logParsers,e.logParsers),Jo(this.proxyMiddleware,e.proxyMiddleware)}}async function Ic(e,t=process.cwd()){let r=new fx;r.registerBuiltins();for(let n of e){if(n.trim()==="")continue;try{let o=n.startsWith("file:")?n:iD(n)?n:sD(t,n),s=await import(o.startsWith("file:")?o:oD(o).href);if(s.sdkVersion!==px)throw Error(`plugin SDK version ${String(s.sdkVersion??"missing")} is incompatible; expected ${px}`);r.register(s),r.pluginPaths.push(o)}catch(o){r.loadErrors.push({path:n,message:o instanceof Error?o.message:String(o)})}}return r}function aD(e){if(!e||typeof e!=="object")throw Error("plugin module must export an object");Gi("tokenProviders",e.tokenProviders,["fetch"]),Gi("identityProviders",e.identityProviders,["accepts","resolve"]),Gi("environmentSources",e.environmentSources,["load"]),Gi("healthChecks",e.healthChecks,["check"]),Gi("logParsers",e.logParsers,["parse"]),Gi("proxyMiddleware",e.proxyMiddleware,["apply"])}function Gi(e,t,r){if(t===void 0)return;if(!Array.isArray(t))throw Error(`${e} must be an array`);for(let[n,o]of t.entries()){if(!o||typeof o!=="object"||typeof o.name!=="string"||o.name==="")throw Error(`${e}[${n}] must have a name`);for(let i of r)if(typeof o[i]!=="function")throw Error(`${e}[${n}].${i} must be a function`)}}function lD(){return{name:"identity_inject",apply:async(e)=>{await qi(e.route,e.headers,e.tokens)}}}function Jo(e,t){if(!t)return;e.push(...t)}var mD=200;function Lf(e){if(!e.registry)return;if(e.registry.tokenProviders.length>0)e.tokens.replaceProviders(e.registry.tokenProviders);e.logs.setParsers(e.registry.logParsers,e.registry.pluginPaths),e.proxy?.setMiddleware?.(e.registry.proxyMiddleware)}function If(e,t){let r=new Map;for(let n of e){let o=gD(n,t);try{r.set(o,cD(o).mtimeMs)}catch{}}return r}async function hD(e,t,r){let n=t.plugins.map((a)=>a.path),o=JSON.stringify(r)!==JSON.stringify(n),i=If(n,t.repoRoot),s=[];for(let[a,l]of i){let c=e.pluginMtimes.get(a);if(c!==void 0&&c!==l){s.push("plugins");break}}if(o){let a=await Ic(n,t.repoRoot);e.registry=a;for(let l of a.loadErrors)e.log("devctl","ERROR",`plugin ${l.path} skipped: ${l.message}`);Lf(e),e.log("devctl","INFO","plugin path list reloaded")}return e.pluginMtimes=i,s}function gD(e,t){if(e.startsWith("file:"))return e;return dD(e)?e:fD(t,e)}function Df(e,t){let r=Kp(t);if(r.length===0)return;let n=new Set((e?.healthChecks??[]).map((i)=>i.name.toLowerCase())),o=r.filter((i)=>!n.has(i.type.toLowerCase()));if(o.length>0)throw T(ee,`unknown health check type(s): ${o.map((i)=>`${i.service}.health.type=${i.type}`).join(", ")}`)}function Of(e,t){let r=Vp(t);if(r.length===0)return;let n=e?.pluginIdentityProviders??[],o=r.filter(({service:i})=>{let s=t.services[i];return!s||!n.some((a)=>a.accepts(s.identity))});if(o.length>0)throw T(ee,`unknown identity type(s): ${o.map((i)=>`${i.service}.identity.type=${i.type}`).join(", ")}`)}function Mf(e,t){let r=new Set(ea),n=new Set((e?.environmentSources??[]).map((i)=>i.name)),o=t.environment.sources.filter((i)=>!r.has(i)&&!n.has(i));if(o.length>0)throw T(ee,`unknown environment source(s): ${o.join(", ")}`)}function vD(e,t,r){for(let n of Object.keys(r))if(!t[n]&&!e.runtimes.has(n))e.runtimes.set(n,Qs(n));for(let n of Object.keys(t)){if(r[n])continue;if(e.orchestrator.serviceIsActive(n)){let o=e.runtimes.get(n);if(o)o.orphaned=!0;e.log(n,"WARN","removed from configuration while still running; now orphaned \u2014 stop it explicitly to clean it up");continue}e.forgetService(n)}}function Nf(e){let t=pD(e.cfg.repoRoot,".devctl");if(!e.fs.exists(t))return;try{e.configWatcher=uD(t,{recursive:!0},()=>{if(e.watchTimer)clearTimeout(e.watchTimer);e.watchTimer=setTimeout(()=>{e.reload().catch((r)=>e.log("devctl","WARN",I(r)))},mD)})}catch{e.log("devctl","WARN","unable to watch .devctl for configuration changes")}}async function mx(e){let t;try{t=_n(e.cfg.repoRoot,e.cfg.configPath)}catch(c){throw e.bus.publish(Ce(Ts,"",{error:I(c)})),e.log("devctl","ERROR",`configuration reload failed: ${I(c)}`),c}try{Df(e.registry,t),Of(e.registry,t),Mf(e.registry,t)}catch(c){throw e.bus.publish(Ce(Ts,"",{error:I(c)})),e.log("devctl","ERROR",`configuration reload failed: ${I(c)}`),c}if(e.setupMode){if(e.setupMode=!1,e.log("devctl","INFO",`configuration created at ${e.cfg.configPath}; leaving setup mode`),!e.configWatcher)Nf(e)}let r=Rf(e.cfg,t),n=JSON.stringify(e.cfg.proxy)!==JSON.stringify(t.proxy),o=JSON.stringify(e.cfg.secrets)!==JSON.stringify(t.secrets),i=e.cfg.plugins.map((c)=>c.path),s=e.cfg.services;e.cfg=lx(e.cfg,t),vD(e,s,t.services);let a=yD(e.restartRequired,r.restart_required,Object.keys(t.services));e.restartRequired=a,r.restart_required=a;let l=await hD(e,t,i);if(l.length>0)r.supervisor_restart_required=[...r.supervisor_restart_required??[],...l];if(e.syncServiceWatchers(),o)e.detector.update(t.secrets.extra_markers,t.secrets.extra_patterns),e.logs.setSecrets(t.secrets.extra_markers,t.secrets.extra_patterns);if(n){let c=e.proxy?.isRunning()??!1;if(await e.stopProxy(),c&&e.cfg.proxy.enabled)await e.startProxy();e.log("devctl","INFO","proxy configuration changed; proxy restarted")}if(e.bus.publish(Ce(cl,"",{restart_required:r.restart_required,changes:r.changes,supervisor_restart_required:r.supervisor_restart_required})),e.log("devctl","INFO",r.restart_required.length===0?"configuration reloaded":`configuration reloaded; restart required: ${r.restart_required.join(", ")}`),r.supervisor_restart_required)e.log("devctl","WARN",mc(r.supervisor_restart_required));return e.persistState(),e.refreshIdentity(),r}function yD(e,t,r){let n=new Set(r),o=new Set(e.filter((i)=>n.has(i)));for(let i of t)if(n.has(i))o.add(i);return[...o].sort()}import{watch as wD}from"fs";import{join as gx,relative as xD}from"path";Ke();function hx(e,t){if(!e?.enabled)return!1;let r=t.replaceAll("\\","/").replace(/^\.\//,"");if(r===""||r.includes(".."))return!1;if((e.ignore.length>0?e.ignore:Ns).some((o)=>bD(o,r)))return!1;if(e.paths.length===0)return!1;return e.paths.some((o)=>{let i=o.replaceAll("\\","/").replace(/\/$/,"");return r===i||r.startsWith(`${i}/`)})}function bD(e,t){let r=e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replaceAll("**/","<<<DS>>>").replaceAll("**","<<<DS>>>").replaceAll("*","[^/]*").replaceAll("<<<DS>>>",".*");return new RegExp(`^${r}$`).test(t)}class Ff{host;entries=new Map;constructor(e){this.host=e}sync(e){let t=new Set;for(let[r,n]of Object.entries(e)){if(!n.watch.enabled||n.watch.paths.length===0){this.stop(r);continue}t.add(r);let o=JSON.stringify(n.watch);if(this.entries.get(r)?.signature===o)continue;this.stop(r),this.start(r,n.watch)}for(let r of[...this.entries.keys()])if(!t.has(r))this.stop(r)}watched(){return[...this.entries.keys()].sort()}close(){for(let e of[...this.entries.keys()])this.stop(e)}start(e,t){let r=[],n=this.host.repoRoot();for(let o of t.paths){let i=o.replaceAll("\\","/").replace(/\/$/,"");if(i===""||i==="."){this.host.log(e,"WARN","service.watch skipped a whole-repo path; list concrete directories");continue}let s=gx(n,i);try{let a=wD(s,{recursive:!0},(l,c)=>{let u=c?gx(s,c.toString()):s,d=xD(n,u).replaceAll("\\","/");if(!hx(t,d))return;this.schedule(e,t.debounce_ms)});r.push(a)}catch{this.host.log(e,"WARN",`unable to watch ${i}`)}}if(r.length===0)return;this.entries.set(e,{signature:JSON.stringify(t),watch:t,handles:r}),this.host.log(e,"INFO",`watching ${t.paths.join(", ")}`)}schedule(e,t){let r=this.entries.get(e);if(!r)return;if(r.timer)clearTimeout(r.timer);r.timer=setTimeout(()=>{if(r.timer=void 0,!this.host.isActive(e))return;this.host.log(e,"INFO","watch: restarting after file change"),this.host.restart(e).catch((n)=>{this.host.log(e,"WARN",n instanceof Error?n.message:String(n))})},t)}stop(e){let t=this.entries.get(e);if(!t)return;if(t.timer)clearTimeout(t.timer);for(let r of t.handles)r.close();this.entries.delete(e)}}import{isAbsolute as $f,join as Hf}from"path";function vx(e,t,r){if(r.trim()==="")return;if((e.OTEL_EXPORTER_OTLP_ENDPOINT??"").trim()==="")e.OTEL_EXPORTER_OTLP_ENDPOINT=r;if((e.OTEL_EXPORTER_OTLP_PROTOCOL??"").trim()==="")e.OTEL_EXPORTER_OTLP_PROTOCOL="http/json";if((e.OTEL_SERVICE_NAME??"").trim()==="")e.OTEL_SERVICE_NAME=t}class Uf{clientEnv=new Map;serviceProfile=new Map;serviceProfileEnv=new Map;profile="";profileEnv={};deps;constructor(e){this.deps=e}forget(e){this.clientEnv.delete(e),this.serviceProfile.delete(e),this.serviceProfileEnv.delete(e)}serviceWorkDir(e){if(e.working_dir!==""&&!$f(e.working_dir))return Hf(this.deps.cfg().repoRoot,e.working_dir);return e.working_dir}async resolveServiceExecution(e,t,r,n,o,i=!0){let s=this.deps.cfg(),a=this.deps.ports().get(e)??Object.fromEntries(t.ports.filter((h)=>!h.auto).map((h)=>[h.name,h.value])),l=this.deps.proxy(),c=l?.isRunning()?`http://${l.address()}`:s.proxy.enabled?`http://${Kn(s.proxy.listen)}`:"",u=this.deps.userEmail(),d=ra(e,"127.0.0.1",a,c,s.project.name,u);if(!t.container){if(d.DEVCTL_INTERNAL_TOKEN=this.deps.internalTok(),s.proxy.token_endpoint.enabled)d.DEVCTL_TOKEN_URL=this.deps.boundTokenURL()||`http://127.0.0.1:${this.deps.tokenEndpoint()?.listenPort()||s.proxy.token_endpoint.port}/token`}let f=await ta(s.repoRoot,{service:e,profile:r,serviceCfg:t,profileEnv:n,assignedPorts:a,runtime:d,userEmail:u,cfg:s,fetchSecret:la(async()=>(await this.deps.tokens.get("user","",[])).accessToken),pluginSources:this.deps.environmentSources(),clientEnv:o,includeProcess:i}),p=t.working_dir&&!$f(t.working_dir)?Hf(s.repoRoot,t.working_dir):t.working_dir,m=Bi(f);if(!t.container)vx(m,e,this.deps.otlpEndpoint());return{env:m,workDir:p}}async resolveTaskEnvironment(e,t,r){let n=this.deps.cfg(),o=this.deps.userEmail(),i=await ta(n.repoRoot,{service:`task:${e}`,profile:this.profile,serviceCfg:t,profileEnv:this.profileEnv,assignedPorts:{},runtime:ra(`task:${e}`,"127.0.0.1",{},"",n.project.name,o),userEmail:o,cfg:n,clientEnv:r,fetchSecret:la(async()=>(await this.deps.tokens.get("user","",[])).accessToken),pluginSources:this.deps.environmentSources()}),s=t.working_dir&&!$f(t.working_dir)?Hf(n.repoRoot,t.working_dir):t.working_dir;return{env:Bi(i),workDir:s}}}Gr();ne();Gr();$t();import{cpus as LD,loadavg as ID,platform as DD,uptime as OD}from"os";import{readFileSync as kD}from"fs";import{freemem as SD,totalmem as CD}from"os";import{spawnSync as TD}from"child_process";var jf=1024,ED=2000,RD=/page size of (\d+) bytes/i,Ki;function _D(e){let t=e.match(/^MemAvailable:\s+(\d+)/m);if(!t)return;let r=Number(t[1]);return Number.isFinite(r)&&r>=0?r:void 0}function PD(e){let t=e.match(RD),r=t?Number(t[1]):0;if(!Number.isFinite(r)||r<=0)return;let n=Dc(e,"free")+Dc(e,"inactive")+Dc(e,"speculative")+Dc(e,"purgeable");return Math.round(n*r/jf)}function Dc(e,t){let r=e.match(new RegExp(`Pages ${t}:\\s+(\\d+)`,"i")),n=r?Number(r[1]):0;return Number.isFinite(n)&&n>0?n:0}function AD(){if(process.platform==="linux")try{return _D(kD("/proc/meminfo","utf8"))}catch{return}if(process.platform==="darwin"){let e=Date.now();if(Ki&&e-Ki.at<ED)return Ki.leftoverKB;let t=TD("vm_stat",{encoding:"utf8"});if(t.status!==0||!t.stdout)return Ki?.leftoverKB;let r=PD(t.stdout);if(r===void 0)return Ki?.leftoverKB;return Ki={at:e,leftoverKB:r},r}return}function yx(){let e=Math.max(0,Math.round(CD()/jf)),t=Math.max(0,Math.round(SD()/jf)),r=Math.max(0,Math.min(e,AD()??t));return{totalKB:e,unusedKB:t,leftoverKB:r}}function bx(e){return{user:"",project:e?.google.project_id??"",project_source:e?.google.project_id?"configuration":"",adc:!1,service_accounts:{},service_account_status:Object.fromEntries(e?ln(e).map((t)=>[t,"unknown"]):[]),iap:e?.proxy.routes.some((t)=>t.auth.type.toLowerCase()==="iap")??!1}}function Bf(){let e=ID(),t=yx();return{platform:DD(),cpuCount:LD().length,loadAvg1:e[0]??0,loadAvg5:e[1]??0,loadAvg15:e[2]??0,memTotalKB:t.totalKB,memFreeKB:t.unusedKB,memAvailableKB:t.leftoverKB,hostUptimeSec:OD()}}function Wf(e,t){let r={},n={};for(let o of ln(e)){let i=t.get(o)??"unknown";if(n[o]=i,i!=="unknown")r[o]=i==="available"}return{service_accounts:r,service_account_status:n}}function wx(e){let t={};for(let[o,i]of e.runtimes)t[o]={...i,ports:e.ports.get(o)??i.ports,profile:e.serviceProfile.get(o)??i.profile,env_source:e.clientEnv.has(o)?"client":"daemon"};let r=e.proxy?.stats(),n={requestTotal:r?.total??0,requestErrors:r?.errors??0,recentRequests:(r?.recent??[]).map((o)=>({...o,traceDurationMs:o.traceId&&e.traceDurationMs?e.traceDurationMs(o.traceId):void 0}))};return{session_id:e.sessionID,repo_root:e.cfg.repoRoot,profile:e.profile,services:t,proxy:{running:e.proxy?.isRunning()??!1,address:e.proxy?.address(),routes:e.cfg.proxy.routes.map((o)=>{let i=o.match.host||"*",s=o.match.path,a=s===""?i:`${i}${s.startsWith("/")?s:`/${s}`}`;return{name:o.name,identity:o.auth.identity.service_account||o.auth.identity.type||o.auth.type,upstream:o.upstream.url,auth:o.auth.type,match:a,client_id:o.auth.client_id.trim()||void 0}}),...n},mcp:{running:e.mcp?.isRunning()??!1,address:e.mcp?.isRunning()?`http://${e.mcp.address()}/mcp`:void 0,port:e.mcp?.isRunning()?e.mcp.listenPort():void 0,token:e.mcpToken,disabled_tools:[...e.mcpDisabledTools]},web:{running:e.web?.isRunning()??!1,address:e.web?.isRunning()?`http://${e.web.address()}/`:void 0,port:e.web?.isRunning()?e.web.listenPort():void 0},identity:{...e.identityCache,...Wf(e.cfg,e.serviceAccountStatus)},credentials:{backend:e.tokens.storeBackend(),entries:[...e.credentialEntries]},detached:e.detached,setup_mode:e.setupMode?!0:void 0,logs:e.logs.snapshot(),restart_required:[...e.restartRequired],system:Bf(),stats_series:e.statsSeries}}function xx(e){let t=[`PROFILE: ${e.profile||"(none)"}`,"","SERVICE\tSTATUS\tHEALTH\tPID"];for(let[r,n]of Object.entries(e.services))t.push(`${r} ${Ui(n)} ${n.health} ${n.pid}`);return t.push("",`PROXY ${e.proxy.running?"RUNNING":"STOPPED"} ${e.proxy.address??""}`),t.push(`MCP ${e.mcp?.running?"RUNNING":"STOPPED"} ${e.mcp?.address??""}`),t.push(`WEB ${e.web?.running?"RUNNING":"STOPPED"} ${e.web?.address??""}`),t.join(`
|
|
2547
|
+
`)}}async serve(e,t){let r=Date.now(),n=ca({traceparent:e.headers[Yo]?.toString(),requestId:e.headers[eo]?.toString()}),o=n.requestId;t.setHeader(eo,o),t.setHeader(Yo,gl(n));let i=e.method??"GET",s=e.url??"/",a=this.detector?this.detector.redactText(s):s,l=fx(this.cfg.routes,e);if(!l){zi(t,404,"no matching proxy route"),this.recordRequest({timestamp:new Date().toISOString(),requestId:o,method:i,path:a,route:"",identity:"",status:404,durationMs:Date.now()-r,traceId:n.traceId,spanId:n.spanId,parentSpanId:n.parentSpanId});return}if(i==="OPTIONS"&&e.headers["access-control-request-method"]!==void 0&&Object.keys(l.response_headers??{}).length>0){this.applyResponseHeaders(t,l),t.statusCode=204,t.setHeader("content-length","0"),t.end(),this.recordRequest({timestamp:new Date().toISOString(),requestId:o,method:i,path:a,route:l.name,identity:"",status:204,durationMs:Date.now()-r,traceId:n.traceId,spanId:n.spanId,parentSpanId:n.parentSpanId});return}let c=Pn(l.auth),u=Qn(c),d=0,f;try{let p={};for(let[b,k]of Object.entries(e.headers)){if(Pf.has(b.toLowerCase()))continue;if(typeof k==="string")p[b]=k;else if(Array.isArray(k))p[b]=k.join(",")}let m=e.socket.remoteAddress??"",h=p.host??"",g=p["x-forwarded-for"];if(p["x-forwarded-for"]=g?`${g}, ${m}`:m,p["x-forwarded-host"]=h,p["x-forwarded-proto"]="http",delete p.host,p["accept-encoding"]="gzip, deflate, br",ua(p,n,eo),this.middleware.length===0)await qi(l,p,this.tokens);for(let b of this.middleware)await b.apply({route:l,headers:p,tokens:this.tokens});let w=px(this.upstreamBase(l),s),v=i!=="GET"&&i!=="HEAD"?e:void 0,S=await fetch(w,{method:i,headers:p,body:v,redirect:"manual",duplex:v?"half":void 0});t.statusCode=S.status,d=S.status;let E=(S.headers.get("content-encoding")??"").split(",").map((b)=>b.trim().toLowerCase()).filter((b)=>b!==""),_=E.length>0&&E.every((b)=>lD.has(b));S.headers.forEach((b,k)=>{let x=k.toLowerCase();if(Pf.has(x))return;if(_&&(x==="content-encoding"||x==="content-length"))return;t.setHeader(k,this.detector?this.detector.redactText(b):b)}),this.applyResponseHeaders(t,l),await cD(S,t);let y=Date.now()-r;this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:S.status>=400?"WARN":"INFO",message:`${i} ${s} route=${l.name} identity=${u} status=${S.status} duration=${y}ms`,pid:0,request_id:o,identity:u}),this.bus?.publish(Ce(Cs,l.name,{status:S.status,request_id:o,duration:y,identity:u}))}catch(p){let m=p instanceof Error?p.message:"proxy error";f=m,d=502,this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:"ERROR",message:`${i} ${s} route=${l.name} identity=${u} error=${m}`,pid:0,request_id:o,identity:u}),this.applyResponseHeaders(t,l),zi(t,502,"proxy error")}finally{this.recordRequest({timestamp:new Date().toISOString(),requestId:o,method:i,path:a,route:l.name,identity:u,status:d,durationMs:Date.now()-r,error:f,traceId:n.traceId,spanId:n.spanId,parentSpanId:n.parentSpanId})}}}async function qi(e,t,r){let n=e.auth.type.toLowerCase();if(n===""||n==="none")return;if(!r)throw T(ar,"token manager unavailable");let o=Pn(e.auth),i=await r.get(Qn(o),e.auth.audience,[],lc(e.auth));t.authorization=`Bearer ${i.accessToken}`;for(let[s,a]of Object.entries(e.auth.headers??{}))t[s]=a.includes("${token}")?a.replaceAll("${token}",i.accessToken):a}async function cD(e,t){if(!e.body){t.end();return}let r=iD.fromWeb(e.body);await new Promise((n,o)=>{r.on("error",o),t.on("error",o),t.on("finish",n),r.pipe(t)})}function uD(e){return e.protocol==="https:"?oD:nD}function px(e,t){let r=new URL(e),n=new URL(t||"/",r),o=new URL(r.href);if(o.pathname=dD(n.pathname),o.search=n.search,o.hash="",o.origin!==r.origin)throw T(ar,"refusing to proxy to a different origin");return o}function dD(e){return(e.startsWith("/")?e:`/${e}`).replace(/^\/+/,"/")}function zi(e,t,r){e.statusCode=t,e.setHeader("content-type","text/plain; charset=utf-8"),e.setHeader("x-content-type-options","nosniff"),e.end(r)}function fx(e,t){let r=(t.headers.host??"").split(":")[0]??"",n=t.url??"/";return e.find((o)=>{if(Wn(o))return!1;let i=o.match.host===""||o.match.host===r,s=o.match.path===""||n.startsWith(o.match.path);return i&&s})}class Lf{host;port;secret;tokens;server;constructor(e,t,r,n){this.host=e;this.port=t;this.secret=r;this.tokens=n}listenPort(){let e=this.server?.address();if(typeof e==="object"&&e)return e.port;return this.port}start(){let e=this.host||"127.0.0.1";if(!_t(e))return Promise.reject(T(ar,`refusing to bind token endpoint to ${e}`));return new Promise((t,r)=>{this.server=mx((n,o)=>{this.serve(n,o)}),this.server.on("error",(n)=>r(ge(ar,"token endpoint listen failed",n))),this.server.listen(this.port,e,()=>t())})}stop(){let e=this.server;if(!e)return Promise.resolve();return new Promise((t)=>e.close(()=>t()))}async serve(e,t){if(!pD(e.socket.remoteAddress)){zi(t,403,"forbidden");return}if((e.headers[sD]??"")!==this.secret){zi(t,401,"unauthorized");return}if(e.url?.startsWith("/token")!==!0){zi(t,404,"not found");return}let r=new URL(e.url,"http://127.0.0.1"),n=r.searchParams.get("identity")??"user",o=r.searchParams.get("audience")??"";try{let i=await this.tokens.get(n,o,[]);t.setHeader("content-type","application/json"),t.end(JSON.stringify({access_token:i.accessToken,token_type:i.tokenType,expires_at:i.expiresAt.toISOString(),identity:i.identity}))}catch{zi(t,500,"token error")}}}function pD(e){if(!e)return!0;return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}Gr();var hx=1;class gx{tokenProviders=[];identityProviders=[];pluginIdentityProviders=[];environmentSources=[];healthChecks=[];logParsers=[];proxyMiddleware=[];loadErrors=[];pluginPaths=[];registerBuiltins(){this.tokenProviders.push(...Zn()),this.identityProviders.push(Qp(),Zp()),this.logParsers.push(Mv()),this.proxyMiddleware.push(vD())}register(e){gD(e),Jo(this.tokenProviders,e.tokenProviders),Jo(this.identityProviders,e.identityProviders),Jo(this.pluginIdentityProviders,e.identityProviders),Jo(this.environmentSources,e.environmentSources),Jo(this.healthChecks,e.healthChecks),Jo(this.logParsers,e.logParsers),Jo(this.proxyMiddleware,e.proxyMiddleware)}}async function Ic(e,t=process.cwd()){let r=new gx;r.registerBuiltins();for(let n of e){if(n.trim()==="")continue;try{let o=n.startsWith("file:")?n:mD(n)?n:hD(t,n),s=await import(o.startsWith("file:")?o:fD(o).href);if(s.sdkVersion!==hx)throw Error(`plugin SDK version ${String(s.sdkVersion??"missing")} is incompatible; expected ${hx}`);r.register(s),r.pluginPaths.push(o)}catch(o){r.loadErrors.push({path:n,message:o instanceof Error?o.message:String(o)})}}return r}function gD(e){if(!e||typeof e!=="object")throw Error("plugin module must export an object");Gi("tokenProviders",e.tokenProviders,["fetch"]),Gi("identityProviders",e.identityProviders,["accepts","resolve"]),Gi("environmentSources",e.environmentSources,["load"]),Gi("healthChecks",e.healthChecks,["check"]),Gi("logParsers",e.logParsers,["parse"]),Gi("proxyMiddleware",e.proxyMiddleware,["apply"])}function Gi(e,t,r){if(t===void 0)return;if(!Array.isArray(t))throw Error(`${e} must be an array`);for(let[n,o]of t.entries()){if(!o||typeof o!=="object"||typeof o.name!=="string"||o.name==="")throw Error(`${e}[${n}] must have a name`);for(let i of r)if(typeof o[i]!=="function")throw Error(`${e}[${n}].${i} must be a function`)}}function vD(){return{name:"identity_inject",apply:async(e)=>{await qi(e.route,e.headers,e.tokens)}}}function Jo(e,t){if(!t)return;e.push(...t)}var SD=200;function If(e){if(!e.registry)return;if(e.registry.tokenProviders.length>0)e.tokens.replaceProviders(e.registry.tokenProviders);e.logs.setParsers(e.registry.logParsers,e.registry.pluginPaths),e.proxy?.setMiddleware?.(e.registry.proxyMiddleware)}function Df(e,t){let r=new Map;for(let n of e){let o=TD(n,t);try{r.set(o,yD(o).mtimeMs)}catch{}}return r}async function CD(e,t,r){let n=t.plugins.map((a)=>a.path),o=JSON.stringify(r)!==JSON.stringify(n),i=Df(n,t.repoRoot),s=[];for(let[a,l]of i){let c=e.pluginMtimes.get(a);if(c!==void 0&&c!==l){s.push("plugins");break}}if(o){let a=await Ic(n,t.repoRoot);e.registry=a;for(let l of a.loadErrors)e.log("devctl","ERROR",`plugin ${l.path} skipped: ${l.message}`);If(e),e.log("devctl","INFO","plugin path list reloaded")}return e.pluginMtimes=i,s}function TD(e,t){if(e.startsWith("file:"))return e;return wD(e)?e:kD(t,e)}function Of(e,t){let r=Vp(t);if(r.length===0)return;let n=new Set((e?.healthChecks??[]).map((i)=>i.name.toLowerCase())),o=r.filter((i)=>!n.has(i.type.toLowerCase()));if(o.length>0)throw T(ee,`unknown health check type(s): ${o.map((i)=>`${i.service}.health.type=${i.type}`).join(", ")}`)}function Mf(e,t){let r=Yp(t);if(r.length===0)return;let n=e?.pluginIdentityProviders??[],o=r.filter(({service:i})=>{let s=t.services[i];return!s||!n.some((a)=>a.accepts(s.identity))});if(o.length>0)throw T(ee,`unknown identity type(s): ${o.map((i)=>`${i.service}.identity.type=${i.type}`).join(", ")}`)}function Nf(e,t){let r=new Set(ea),n=new Set((e?.environmentSources??[]).map((i)=>i.name)),o=t.environment.sources.filter((i)=>!r.has(i)&&!n.has(i));if(o.length>0)throw T(ee,`unknown environment source(s): ${o.join(", ")}`)}function ED(e,t,r){for(let n of Object.keys(r))if(!t[n]&&!e.runtimes.has(n))e.runtimes.set(n,Qs(n));for(let n of Object.keys(t)){if(r[n])continue;if(e.orchestrator.serviceIsActive(n)){let o=e.runtimes.get(n);if(o)o.orphaned=!0;e.log(n,"WARN","removed from configuration while still running; now orphaned \u2014 stop it explicitly to clean it up");continue}e.forgetService(n)}}function Ff(e){let t=xD(e.cfg.repoRoot,".devctl");if(!e.fs.exists(t))return;try{e.configWatcher=bD(t,{recursive:!0},()=>{if(e.watchTimer)clearTimeout(e.watchTimer);e.watchTimer=setTimeout(()=>{e.reload().catch((r)=>e.log("devctl","WARN",I(r)))},SD)})}catch{e.log("devctl","WARN","unable to watch .devctl for configuration changes")}}async function vx(e){let t;try{t=_n(e.cfg.repoRoot,e.cfg.configPath)}catch(c){throw e.bus.publish(Ce(Ts,"",{error:I(c)})),e.log("devctl","ERROR",`configuration reload failed: ${I(c)}`),c}try{Of(e.registry,t),Mf(e.registry,t),Nf(e.registry,t)}catch(c){throw e.bus.publish(Ce(Ts,"",{error:I(c)})),e.log("devctl","ERROR",`configuration reload failed: ${I(c)}`),c}if(e.setupMode){if(e.setupMode=!1,e.log("devctl","INFO",`configuration created at ${e.cfg.configPath}; leaving setup mode`),!e.configWatcher)Ff(e)}let r=_f(e.cfg,t),n=JSON.stringify(e.cfg.proxy)!==JSON.stringify(t.proxy),o=JSON.stringify(e.cfg.secrets)!==JSON.stringify(t.secrets),i=e.cfg.plugins.map((c)=>c.path),s=e.cfg.services;e.cfg=dx(e.cfg,t),ED(e,s,t.services);let a=RD(e.restartRequired,r.restart_required,Object.keys(t.services));e.restartRequired=a,r.restart_required=a;let l=await CD(e,t,i);if(l.length>0)r.supervisor_restart_required=[...r.supervisor_restart_required??[],...l];if(e.syncServiceWatchers(),o)e.detector.update(t.secrets.extra_markers,t.secrets.extra_patterns),e.logs.setSecrets(t.secrets.extra_markers,t.secrets.extra_patterns);if(n){let c=e.proxy?.isRunning()??!1;if(await e.stopProxy(),c&&e.cfg.proxy.enabled)await e.startProxy();e.log("devctl","INFO","proxy configuration changed; proxy restarted")}if(e.bus.publish(Ce(cl,"",{restart_required:r.restart_required,changes:r.changes,supervisor_restart_required:r.supervisor_restart_required})),e.log("devctl","INFO",r.restart_required.length===0?"configuration reloaded":`configuration reloaded; restart required: ${r.restart_required.join(", ")}`),r.supervisor_restart_required)e.log("devctl","WARN",mc(r.supervisor_restart_required));return e.persistState(),e.refreshIdentity(),r}function RD(e,t,r){let n=new Set(r),o=new Set(e.filter((i)=>n.has(i)));for(let i of t)if(n.has(i))o.add(i);return[...o].sort()}import{watch as PD}from"fs";import{join as bx,relative as AD}from"path";Ke();function yx(e,t){if(!e?.enabled)return!1;let r=t.replaceAll("\\","/").replace(/^\.\//,"");if(r===""||r.includes(".."))return!1;if((e.ignore.length>0?e.ignore:Ns).some((o)=>_D(o,r)))return!1;if(e.paths.length===0)return!1;return e.paths.some((o)=>{let i=o.replaceAll("\\","/").replace(/\/$/,"");return r===i||r.startsWith(`${i}/`)})}function _D(e,t){let r=e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replaceAll("**/","<<<DS>>>").replaceAll("**","<<<DS>>>").replaceAll("*","[^/]*").replaceAll("<<<DS>>>",".*");return new RegExp(`^${r}$`).test(t)}class $f{host;entries=new Map;constructor(e){this.host=e}sync(e){let t=new Set;for(let[r,n]of Object.entries(e)){if(!n.watch.enabled||n.watch.paths.length===0){this.stop(r);continue}t.add(r);let o=JSON.stringify(n.watch);if(this.entries.get(r)?.signature===o)continue;this.stop(r),this.start(r,n.watch)}for(let r of[...this.entries.keys()])if(!t.has(r))this.stop(r)}watched(){return[...this.entries.keys()].sort()}close(){for(let e of[...this.entries.keys()])this.stop(e)}start(e,t){let r=[],n=this.host.repoRoot();for(let o of t.paths){let i=o.replaceAll("\\","/").replace(/\/$/,"");if(i===""||i==="."){this.host.log(e,"WARN","service.watch skipped a whole-repo path; list concrete directories");continue}let s=bx(n,i);try{let a=PD(s,{recursive:!0},(l,c)=>{let u=c?bx(s,c.toString()):s,d=AD(n,u).replaceAll("\\","/");if(!yx(t,d))return;this.schedule(e,t.debounce_ms)});r.push(a)}catch{this.host.log(e,"WARN",`unable to watch ${i}`)}}if(r.length===0)return;this.entries.set(e,{signature:JSON.stringify(t),watch:t,handles:r}),this.host.log(e,"INFO",`watching ${t.paths.join(", ")}`)}schedule(e,t){let r=this.entries.get(e);if(!r)return;if(r.timer)clearTimeout(r.timer);r.timer=setTimeout(()=>{if(r.timer=void 0,!this.host.isActive(e))return;this.host.log(e,"INFO","watch: restarting after file change"),this.host.restart(e).catch((n)=>{this.host.log(e,"WARN",n instanceof Error?n.message:String(n))})},t)}stop(e){let t=this.entries.get(e);if(!t)return;if(t.timer)clearTimeout(t.timer);for(let r of t.handles)r.close();this.entries.delete(e)}}import{isAbsolute as Hf,join as Uf}from"path";function wx(e,t,r){if(r.trim()==="")return;if((e.OTEL_EXPORTER_OTLP_ENDPOINT??"").trim()==="")e.OTEL_EXPORTER_OTLP_ENDPOINT=r;if((e.OTEL_EXPORTER_OTLP_PROTOCOL??"").trim()==="")e.OTEL_EXPORTER_OTLP_PROTOCOL="http/json";if((e.OTEL_SERVICE_NAME??"").trim()==="")e.OTEL_SERVICE_NAME=t}class jf{clientEnv=new Map;serviceProfile=new Map;serviceProfileEnv=new Map;profile="";profileEnv={};deps;constructor(e){this.deps=e}forget(e){this.clientEnv.delete(e),this.serviceProfile.delete(e),this.serviceProfileEnv.delete(e)}serviceWorkDir(e){if(e.working_dir!==""&&!Hf(e.working_dir))return Uf(this.deps.cfg().repoRoot,e.working_dir);return e.working_dir}async resolveServiceExecution(e,t,r,n,o,i=!0){let s=this.deps.cfg(),a=this.deps.ports().get(e)??Object.fromEntries(t.ports.filter((h)=>!h.auto).map((h)=>[h.name,h.value])),l=this.deps.proxy(),c=l?.isRunning()?`http://${l.address()}`:s.proxy.enabled?`http://${Kn(s.proxy.listen)}`:"",u=this.deps.userEmail(),d=ra(e,"127.0.0.1",a,c,s.project.name,u);if(!t.container){if(d.DEVCTL_INTERNAL_TOKEN=this.deps.internalTok(),s.proxy.token_endpoint.enabled)d.DEVCTL_TOKEN_URL=this.deps.boundTokenURL()||`http://127.0.0.1:${this.deps.tokenEndpoint()?.listenPort()||s.proxy.token_endpoint.port}/token`}let f=await ta(s.repoRoot,{service:e,profile:r,serviceCfg:t,profileEnv:n,assignedPorts:a,runtime:d,userEmail:u,cfg:s,fetchSecret:la(async()=>(await this.deps.tokens.get("user","",[])).accessToken),pluginSources:this.deps.environmentSources(),clientEnv:o,includeProcess:i}),p=t.working_dir&&!Hf(t.working_dir)?Uf(s.repoRoot,t.working_dir):t.working_dir,m=Bi(f);if(!t.container)wx(m,e,this.deps.otlpEndpoint());return{env:m,workDir:p}}async resolveTaskEnvironment(e,t,r){let n=this.deps.cfg(),o=this.deps.userEmail(),i=await ta(n.repoRoot,{service:`task:${e}`,profile:this.profile,serviceCfg:t,profileEnv:this.profileEnv,assignedPorts:{},runtime:ra(`task:${e}`,"127.0.0.1",{},"",n.project.name,o),userEmail:o,cfg:n,clientEnv:r,fetchSecret:la(async()=>(await this.deps.tokens.get("user","",[])).accessToken),pluginSources:this.deps.environmentSources()}),s=t.working_dir&&!Hf(t.working_dir)?Uf(n.repoRoot,t.working_dir):t.working_dir;return{env:Bi(i),workDir:s}}}Gr();ne();Gr();$t();import{cpus as UD,loadavg as jD,platform as BD,uptime as WD}from"os";import{readFileSync as LD}from"fs";import{freemem as ID,totalmem as DD}from"os";import{spawnSync as OD}from"child_process";var Bf=1024,MD=2000,ND=/page size of (\d+) bytes/i,Ki;function FD(e){let t=e.match(/^MemAvailable:\s+(\d+)/m);if(!t)return;let r=Number(t[1]);return Number.isFinite(r)&&r>=0?r:void 0}function $D(e){let t=e.match(ND),r=t?Number(t[1]):0;if(!Number.isFinite(r)||r<=0)return;let n=Dc(e,"free")+Dc(e,"inactive")+Dc(e,"speculative")+Dc(e,"purgeable");return Math.round(n*r/Bf)}function Dc(e,t){let r=e.match(new RegExp(`Pages ${t}:\\s+(\\d+)`,"i")),n=r?Number(r[1]):0;return Number.isFinite(n)&&n>0?n:0}function HD(){if(process.platform==="linux")try{return FD(LD("/proc/meminfo","utf8"))}catch{return}if(process.platform==="darwin"){let e=Date.now();if(Ki&&e-Ki.at<MD)return Ki.leftoverKB;let t=OD("vm_stat",{encoding:"utf8"});if(t.status!==0||!t.stdout)return Ki?.leftoverKB;let r=$D(t.stdout);if(r===void 0)return Ki?.leftoverKB;return Ki={at:e,leftoverKB:r},r}return}function xx(){let e=Math.max(0,Math.round(DD()/Bf)),t=Math.max(0,Math.round(ID()/Bf)),r=Math.max(0,Math.min(e,HD()??t));return{totalKB:e,unusedKB:t,leftoverKB:r}}function kx(e){return{user:"",project:e?.google.project_id??"",project_source:e?.google.project_id?"configuration":"",adc:!1,service_accounts:{},service_account_status:Object.fromEntries(e?ln(e).map((t)=>[t,"unknown"]):[]),iap:e?.proxy.routes.some((t)=>t.auth.type.toLowerCase()==="iap")??!1}}function Wf(){let e=jD(),t=xx();return{platform:BD(),cpuCount:UD().length,loadAvg1:e[0]??0,loadAvg5:e[1]??0,loadAvg15:e[2]??0,memTotalKB:t.totalKB,memFreeKB:t.unusedKB,memAvailableKB:t.leftoverKB,hostUptimeSec:WD()}}function zf(e,t){let r={},n={};for(let o of ln(e)){let i=t.get(o)??"unknown";if(n[o]=i,i!=="unknown")r[o]=i==="available"}return{service_accounts:r,service_account_status:n}}function Sx(e){let t={};for(let[o,i]of e.runtimes)t[o]={...i,ports:e.ports.get(o)??i.ports,profile:e.serviceProfile.get(o)??i.profile,env_source:e.clientEnv.has(o)?"client":"daemon"};let r=e.proxy?.stats(),n={requestTotal:r?.total??0,requestErrors:r?.errors??0,recentRequests:(r?.recent??[]).map((o)=>({...o,traceDurationMs:o.traceId&&e.traceDurationMs?e.traceDurationMs(o.traceId):void 0}))};return{session_id:e.sessionID,repo_root:e.cfg.repoRoot,profile:e.profile,services:t,proxy:{running:e.proxy?.isRunning()??!1,address:e.proxy?.address(),routes:e.cfg.proxy.routes.map((o)=>{let i=o.match.host||"*",s=o.match.path,a=s===""?i:`${i}${s.startsWith("/")?s:`/${s}`}`;return{name:o.name,identity:o.auth.identity.service_account||o.auth.identity.type||o.auth.type,upstream:o.upstream.url,auth:o.auth.type,match:a,client_id:o.auth.client_id.trim()||void 0}}),...n},mcp:{running:e.mcp?.isRunning()??!1,address:e.mcp?.isRunning()?`http://${e.mcp.address()}/mcp`:void 0,port:e.mcp?.isRunning()?e.mcp.listenPort():void 0,token:e.mcpToken,disabled_tools:[...e.mcpDisabledTools]},web:{running:e.web?.isRunning()??!1,address:e.web?.isRunning()?`http://${e.web.address()}/`:void 0,port:e.web?.isRunning()?e.web.listenPort():void 0},identity:{...e.identityCache,...zf(e.cfg,e.serviceAccountStatus)},credentials:{backend:e.tokens.storeBackend(),entries:[...e.credentialEntries]},detached:e.detached,setup_mode:e.setupMode?!0:void 0,logs:e.logs.snapshot(),restart_required:[...e.restartRequired],system:Wf(),stats_series:e.statsSeries}}function Cx(e){let t=[`PROFILE: ${e.profile||"(none)"}`,"","SERVICE\tSTATUS\tHEALTH\tPID"];for(let[r,n]of Object.entries(e.services))t.push(`${r} ${Ui(n)} ${n.health} ${n.pid}`);return t.push("",`PROXY ${e.proxy.running?"RUNNING":"STOPPED"} ${e.proxy.address??""}`),t.push(`MCP ${e.mcp?.running?"RUNNING":"STOPPED"} ${e.mcp?.address??""}`),t.push(`WEB ${e.web?.running?"RUNNING":"STOPPED"} ${e.web?.address??""}`),t.join(`
|
|
2542
2548
|
`)+`
|
|
2543
|
-
`}var MD=4000;class zf{cache;accounts=new Map;entries=[];deps;constructor(e){this.deps=e,this.cache=bx(e.cfg()),this.deps.bus.subscribe((t)=>{let r=t.payload??{},n=t.type===bi?`token refreshed identity=${String(r.identity??"")}`:t.type===ko?`token refresh failed identity=${String(r.identity??"")} audience=${String(r.audience??"")}: ${String(r.error??"")}`:`authentication changed user=${String(r.user??"")}`;if(this.deps.logs.append({timestamp:this.deps.clock.isoNow(),service:"auth",source:"auth",level:t.type===ko?"WARN":"INFO",message:n,pid:0}),t.type===bi||t.type===ko)this.syncCredentialEntries()},[bi,ko,Md])}get identityCache(){return this.cache}get serviceAccountStatus(){return this.accounts}get credentialEntries(){return this.entries}async prepareServiceIdentity(e,t){let r=ec(t.identity);if(r.kind!=="none")try{if(r=await _b(t.identity,()=>Ib(this.deps.cfg().google.project_id),this.deps.identityProviders()),r.kind==="service_account")await this.deps.tokens.get(Qn(r),"",[]),this.accounts.set(r.serviceAccount,"available")}catch(n){if(r.kind==="service_account")this.accounts.set(r.serviceAccount,"unavailable");if(FD(t)||r.kind==="service_account"||r.kind!=="user"&&r.kind!=="none")throw await this.deps.fail(e,n),n;this.deps.log(e,"WARN","cloud identity unavailable; starting service locally")}}async syncCredentialEntries(){this.entries=(await this.deps.tokens.listStatus()).map((e)=>({identity:e.identity,audience:e.audience,expires_at:e.expires_at,valid:e.valid}))}async refreshIdentity(e){try{let t=this.deps.cfg(),r=await this.deps.detectGoogle(t.google.project_id);if(e?.probeServiceAccounts)for(let i of ln(t))await this.probeServiceAccount(i);let{service_accounts:n,service_account_status:o}=Wf(t,this.accounts);this.cache={user:r.userEmail,project:r.projectID||t.google.project_id,project_source:r.projectSource||(t.google.project_id?"configuration":""),adc:r.adcAvailable,service_accounts:n,service_account_status:o,iap:t.proxy.routes.some((i)=>i.auth.type.toLowerCase()==="iap")},await this.syncCredentialEntries(),this.deps.bus.publish(Ce(Md,"",{user:this.cache.user,adc:this.cache.adc})),this.deps.log("auth","INFO",`authentication changed user=${this.cache.user||"(unknown)"} adc=${this.cache.adc}`),this.deps.persistState()}catch(t){this.deps.log("devctl","WARN",`identity refresh failed: ${I(t)}`)}}async probeServiceAccount(e){let t;try{await ND(this.deps.tokens.refresh(`sa:${e}`,"",[]),MD),t="available"}catch{t="unavailable"}return this.accounts.set(e,t),t}}function ND(e,t){return new Promise((r,n)=>{let o=setTimeout(()=>n(Error("identity probe timed out")),t);e.then((i)=>{clearTimeout(o),r(i)},(i)=>{clearTimeout(o),n(i)})})}function FD(e){return e.capabilities.some((t)=>["google_api","iap","service_identity"].includes(t))}ne();ne();Gf();var BD=600,WD=65535;async function Rx(e,t){let r=Number.isInteger(t)&&(t??0)>0?t:Xo(e);for(let n=0;n<BD;n+=1){let o=r+n;if(o>WD)break;if(await Ai(o))return o}throw T(ee,`no free MCP port starting at ${r}`)}class Kf{listener;disabled=[];token;deps;constructor(e){this.deps=e,this.token=zg(e.repoRoot())}get instance(){return this.listener}get disabledTools(){return this.disabled}async bootFromPreferences(){let e=vi(this.deps.repoRoot());if(this.setDisabledTools(e.mcp_disabled_tools??[]),e.mcp_enabled)await this.start(e.mcp_port).catch((t)=>this.deps.log("devctl","ERROR",I(t)))}async start(e){if(this.listener?.isRunning())return;let t=await Rx(this.deps.repoRoot(),e);this.listener=this.deps.createListener({port:t,token:this.token,hostApi:this.deps.hostApi(),onEvent:(r,n)=>this.deps.log("mcp",r,`mcp ${n}`),disabledTools:()=>this.disabled}),await this.listener.start(),this.deps.persistState()}setDisabledTools(e){let t=e.filter((n)=>this.deps.isKnownTool(n)),r=this.disabled.join(",");if(this.disabled=[...new Set(t)].sort(),this.disabled.join(",")===r)return;this.deps.log("devctl","INFO",this.disabled.length===0?"all MCP tools enabled":`MCP tools disabled: ${this.disabled.join(", ")}`)}async stop(){await this.listener?.stop(),this.listener=void 0,this.deps.persistState()}}Ke();class Vf{listener;deps;constructor(e){this.deps=e}get instance(){return this.listener}address(){return this.listener?.isRunning()?this.listener.address():""}endpoint(){let e=this.address();return e===""?"":`http://${e}/`}async start(){if(!this.deps.cfg().web.enabled)return;await this.bind()}async startExplicit(){await this.bind()}async stop(){await this.listener?.stop(),this.listener=void 0}async bind(){if(this.listener?.isRunning())return;let e=this.deps.cfg().web.listen;this.listener=this.deps.createListener({host:e.host||Dt,port:e.port,hostApi:this.deps.hostApi(),onEvent:(t,r)=>this.deps.log("web",t,`web ${r}`)}),await this.listener.start(),this.deps.log("devctl","INFO",`web UI listening on ${this.endpoint()}`)}}Ke();import*as Qo from"http2";ne();Gr();var Yf="14",zD="16",qD="1",_x=new Set(["host","connection","keep-alive","transfer-encoding","upgrade","proxy-connection","authorization"]);class Jf{route;tokens;logs;bus;detector;spans;server;client;running=!1;addr="";requests=new Lc;constructor(e,t,r,n,o,i){this.route=e;this.tokens=t;this.logs=r;this.bus=n;this.detector=o;this.spans=i}address(){return this.addr}isRunning(){return this.running}stats(){return this.requests.stats()}start(){let e=this.route.listen?.host||"127.0.0.1",t=this.route.listen?.port??0;if(!Mt(e))return Promise.reject(T(ar,`refusing to bind grpc route ${this.route.name} to ${e}`));if(t===0)return Promise.reject(T(ar,`grpc route ${this.route.name} requires listen.port`));return new Promise((r,n)=>{let o=Qo.createServer();o.on("stream",(i,s)=>void this.serve(i,s)),o.on("sessionError",()=>{}),o.on("error",(i)=>{if(this.running){this.log("ERROR",`grpc route ${this.route.name} listener error: ${i.message}`);return}n(ge(ar,`grpc route ${this.route.name} unable to listen on ${e}:${t}`,i))}),o.listen(t,e,()=>{this.server=o,this.running=!0,this.addr=`${e}:${t}`,this.log("INFO",`grpc route ${this.route.name} listening on ${this.addr} \u2192 ${this.route.upstream.url}`),r()})})}stop(){let e=this.server;if(this.client?.close(),this.client=void 0,!e)return Promise.resolve();return new Promise((t)=>{e.close(()=>{this.running=!1,t()})})}upstream(){if(this.client&&!this.client.closed&&!this.client.destroyed)return this.client;let e=Qo.connect(this.route.upstream.url);return e.on("error",()=>{if(this.client===e)this.client=void 0}),e.on("goaway",()=>{if(this.client===e)this.client=void 0}),e.on("close",()=>{if(this.client===e)this.client=void 0}),this.client=e,e}async serve(e,t){let r=Date.now(),n=ca({traceparent:Px(t,Yo),requestId:Px(t,eo)}),o=n.requestId,i=String(t[":path"]??"/"),s=Pn(this.route.auth),a=Qn(s),l=!1,c=(h,g,w)=>{if(l)return;l=!0;let v=Date.now()-r,S=this.detector?this.detector.redactText(i):i,E=w??(g!=="0"?`grpc-status ${g}`:void 0),_={timestamp:new Date().toISOString(),requestId:o,method:"POST",path:S,route:this.route.name,identity:a,status:h,durationMs:v,error:E,traceId:n.traceId,spanId:n.spanId,parentSpanId:n.parentSpanId};this.requests.record(_),this.spans?.append(Ac(_)),this.log(E?"WARN":"INFO",`grpc ${i} route=${this.route.name} identity=${a} grpc-status=${g} duration=${v}ms${E?` error=${E}`:""}`,o,a),this.bus?.publish(Ce(Cs,this.route.name,{status:h,request_id:o,duration:v,identity:a}))},u=(h,g)=>{try{e.respond({":status":200,"content-type":"application/grpc","grpc-status":h,"grpc-message":g},{endStream:!0})}catch{e.close(Qo.constants.NGHTTP2_INTERNAL_ERROR)}c(200,h,g)},d;try{d=this.buildUpstreamHeaders(t),ua(d,n,eo),await qi(this.route,d,this.tokens)}catch(h){u(zD,h instanceof Error?h.message:"token injection failed");return}let f;try{f=this.upstream().request(d)}catch(h){u(Yf,h instanceof Error?h.message:"upstream unavailable");return}let p=!1,m={};f.on("response",(h)=>{if(p)return;if(p=!0,h["grpc-status"]!==void 0){e.respond(this.frontResponseHeaders(h),{endStream:!0}),c(Number(h[":status"]??200),String(h["grpc-status"]));return}e.respond(this.frontResponseHeaders(h),{waitForTrailers:!0}),e.on("wantTrailers",()=>{try{e.sendTrailers(this.sanitizeTrailers(m))}catch{}c(Number(h[":status"]??200),String(m["grpc-status"]??"0"))}),f.pipe(e,{end:!1}),f.on("end",()=>{try{e.end()}catch{}})}),f.on("trailers",(h)=>{m=h}),f.on("error",(h)=>{if(!p)u(Yf,h.message);else c(502,Yf,h.message),e.close(Qo.constants.NGHTTP2_INTERNAL_ERROR)}),e.on("error",()=>f.destroy()),e.on("close",()=>{if(!l)c(499,qD,"client closed before completion"),f.destroy()}),e.pipe(f)}buildUpstreamHeaders(e){let t={};for(let[n,o]of Object.entries(e)){if(n.startsWith(":")||_x.has(n.toLowerCase())||o===void 0)continue;t[n]=Array.isArray(o)?o.join(", "):String(o)}let r=new URL(this.route.upstream.url);return t[":method"]=String(e[":method"]??"POST"),t[":path"]=String(e[":path"]??"/"),t[":scheme"]=r.protocol==="https:"?"https":"http",t[":authority"]=r.host,t}frontResponseHeaders(e){let t={":status":e[":status"]??200};for(let[r,n]of Object.entries(e)){if(r.startsWith(":")||_x.has(r.toLowerCase())||n===void 0)continue;t[r]=n}return t}sanitizeTrailers(e){let t={};for(let[r,n]of Object.entries(e)){if(r.startsWith(":")||n===void 0)continue;t[r]=n}if(t["grpc-status"]===void 0)t["grpc-status"]="0";return t}log(e,t,r="",n=""){this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:e,message:t,pid:0,request_id:r,identity:n})}}function Px(e,t){let r=e[t];if(typeof r==="string"&&r!=="")return r;if(Array.isArray(r)&&typeof r[0]==="string"&&r[0]!=="")return r[0];return}class Xf{server;tokenEP;grpc=[];boundURL="";suppressed=!1;deps;constructor(e){this.deps=e}get instance(){return this.server}get tokenEndpoint(){return this.tokenEP}get boundTokenURL(){return this.boundURL}get isSuppressed(){return this.suppressed}setSuppressed(e){this.suppressed=e}async start(){if(this.server?.isRunning())return;this.server=new Pf(this.deps.cfg().proxy,this.deps.tokens,this.deps.logs,this.deps.bus,this.deps.detector,this.deps.middleware(),(t,r)=>this.deps.ports().get(t)?.[r||"http"],this.deps.spans),await this.server.start();let e=this.deps.cfg();if(e.proxy.token_endpoint.enabled)this.tokenEP=new Af(e.proxy.token_endpoint.host||"127.0.0.1",e.proxy.token_endpoint.port,this.deps.internalTok(),this.deps.tokens),await this.tokenEP.start(),this.boundURL=`http://127.0.0.1:${this.tokenEP.listenPort()}/token`;for(let t of e.proxy.routes.filter(Wn)){let r=new Jf(t,this.deps.tokens,this.deps.logs,this.deps.bus,this.deps.detector,this.deps.spans);await r.start(),this.grpc.push(r)}this.deps.persistState()}async stop(){await this.server?.stop(),await this.tokenEP?.stop(),await Promise.all(this.grpc.map((e)=>e.stop())),this.grpc=[],this.deps.persistState()}}$t();var GD=3000,Ax=5000,Lx=60;class Qf{timer;cpu=[];mem=[];lastAt=0;deps;constructor(e){this.deps=e}start(){if(this.timer)return;this.timer=setInterval(()=>void this.poll(),GD)}stop(){if(this.timer)clearInterval(this.timer),this.timer=void 0}series(){return{interval_ms:Ax,cpu:[...this.cpu],mem:[...this.mem]}}async poll(){this.recordStatsSample();let e=[];for(let r of this.deps.runtimes().values())if(r.pid>0&&(r.state===Ve||r.state===Lr||r.state===cn))e.push(r.pid);if(e.length===0)return;let t=await ex(e);for(let r of this.deps.runtimes().values()){let n=r.pid>0?t.get(r.pid):void 0;if(n)r.cpuPercent=n.cpuPercent,r.memoryKB=n.memoryKB}}recordStatsSample(){let e=this.deps.clock.unixMs();if(e-this.lastAt<Ax)return;this.lastAt=e;let t=Bf(),r=t.cpuCount>0?t.loadAvg1/t.cpuCount:0,n=t.memTotalKB>0?1-t.memAvailableKB/t.memTotalKB:0;if(this.cpu.push(r),this.mem.push(n),this.cpu.length>Lx)this.cpu.shift();if(this.mem.length>Lx)this.mem.shift()}}function Mc(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Nc(e){return{services:Vi(e.services),level:typeof e.level==="string"?e.level:"",search:typeof e.search==="string"?e.search:"",regex:e.regex===!0,source:typeof e.source==="string"?e.source:"",since:typeof e.since==="string"?e.since:"",until:typeof e.until==="string"?e.until:"",traceId:Oc(e.traceId)??Oc(e.trace_id),requestId:Oc(e.requestId)??Oc(e.request_id),attribute:KD(e.attribute)}}function Oc(e){return typeof e==="string"&&e!==""?e:void 0}function KD(e){if(!Mc(e)||typeof e.key!=="string"||typeof e.value!=="string")return;return{key:e.key,value:e.value}}function Vi(e){if(!Array.isArray(e))return[];return e.filter((t)=>typeof t==="string")}function da(e){if(!Mc(e))return;let t={};for(let[r,n]of Object.entries(e))if(typeof n==="string")t[r]=n;return t}ne();import{createServer as VD}from"net";var YD=2000;class Zf{server;deps;constructor(e){this.deps=e}get nativeServer(){return this.server}removeStaleSocket(e){if(process.platform==="win32")return;if(this.deps.socketExists(e))try{this.deps.unlinkSocket(e)}catch{this.deps.log("devctl","WARN","unable to remove stale socket")}}listen(e){return new Promise((t,r)=>{this.server=VD((n)=>{this.handleConn(n)}),this.server.on("error",r),this.server.listen(e,()=>t())})}close(){this.server?.close(),this.server=void 0}handleConn(e){let t="",r=[],n=!1,o=()=>{while(r.length>0){let a=r[0],l=e.write(`${JSON.stringify(a)}
|
|
2544
|
-
`);if(r.shift(),!l){n=!0,e.once("drain",()=>{n=!1,o()});return}}},i=(a)=>{if(a.id===void 0&&a.event!==void 0&&r.length>=
|
|
2545
|
-
`);t=l.pop()??"";for(let c of l){if(c.trim()==="")continue;this.dispatchLine(c,i)}}),e.on("close",()=>s())}async dispatchLine(e,t){let r;try{r=JSON.parse(e)}catch{t({error:"invalid json"});return}try{let n=await this.deps.dispatch(r.method??"",r.params);t({id:r.id,result:n})}catch(n){let o=oy(n);t({id:r.id,error:o.error,kind:o.kind,hint:o.hint,service:o.service})}}}ne();Gr();$t();ep();var Ix=1e4;class em{items=[];start=0;nextSeq=1;max;detector;byTrace=new Map;requestToTrace=new Map;constructor(e=Ix,t){this.max=e>0?e:Ix,this.detector=t}append(e){let t={...e,seq:this.nextSeq};this.nextSeq+=1;let r=this.detector?kl(this.detector,t):t;if(this.items.length<this.max)this.items.push(r);else{let n=this.items[this.start];if(n)this.dropFromIndex(n);this.items[this.start]=r,this.start=(this.start+1)%this.max}return this.index(r),r}getTrace(e){let t=[...this.byTrace.get(e)??[]].sort((o,i)=>o.startUnixNano-i.startUnixNano),r=new Set(t.map((o)=>o.spanId)),n=t.filter((o)=>!o.parentSpanId||!r.has(o.parentSpanId));return{traceId:e,spans:t,roots:n}}envelopeMs(e){let t=this.byTrace.get(e);if(!t||t.length===0)return;let{POSITIVE_INFINITY:r,NEGATIVE_INFINITY:n}=Number;for(let o of t){let i=Math.min(o.startUnixNano,o.endUnixNano||o.startUnixNano),s=Math.max(o.startUnixNano,o.endUnixNano||o.startUnixNano);if(i<r)r=i;if(s>n)n=s}return Math.max(0,(n-r)/qt)}findTraceIdByRequestId(e){return this.requestToTrace.get(e)}recent(e=100){let t=[];return this.forEach((r)=>{t.push(r)}),t.slice(Math.max(0,t.length-e)).reverse()}close(){this.items.length=0,this.byTrace.clear(),this.requestToTrace.clear()}index(e){let t=this.byTrace.get(e.traceId)??[];t.push(e),this.byTrace.set(e.traceId,t);let r=e.attributes[Gt];if(typeof r==="string"&&r!=="")this.requestToTrace.set(r,e.traceId)}dropFromIndex(e){let t=this.byTrace.get(e.traceId);if(!t)return;let r=t.filter((n)=>n.seq!==e.seq);if(r.length===0){this.byTrace.delete(e.traceId);let n=e.attributes[Gt];if(typeof n==="string"&&this.requestToTrace.get(n)===e.traceId)this.requestToTrace.delete(n)}else this.byTrace.set(e.traceId,r)}forEach(e){let t=this.items.length;for(let r=0;r<t;r+=1){let n=this.items[(this.start+r)%t];if(n)e(n)}}}Ke();import{createServer as rO}from"http";vl();Ci();function Dx(e){if(typeof e==="string"){let t=e.replace(/^span_kind_/i,"").toLowerCase();if(t==="server")return"server";if(t==="client")return"client";if(t==="producer")return"producer";if(t==="consumer")return"consumer";return"internal"}if(e===2)return"server";if(e===3)return"client";if(e===4)return"producer";if(e===5)return"consumer";if(e===1)return"internal";return"internal"}function Ox(e){if(typeof e!=="object"||e===null)return{code:"unset"};let t=e,r=typeof t.message==="string"&&t.message!==""?t.message:void 0;if(t.code===2||t.code==="STATUS_CODE_ERROR"||t.code==="error")return{code:"error",message:r};if(t.code===1||t.code==="STATUS_CODE_OK"||t.code==="ok")return{code:"ok",message:r};return{code:"unset",message:r}}function Mx(e,t){if(!Le(e)||!Array.isArray(e.resourceLogs))return[];return e.resourceLogs.flatMap((r)=>JD(r,t))}function Nx(e,t){if(!Le(e)||!Array.isArray(e.resourceSpans))return[];return e.resourceSpans.flatMap((r)=>QD(r,t))}function JD(e,t){if(!Le(e)||!Array.isArray(e.scopeLogs))return[];let r=Xd(e.resource,t),n=r["service.name"];return e.scopeLogs.flatMap((o)=>XD(o,r,n))}function XD(e,t,r){if(!Le(e)||!Array.isArray(e.logRecords))return[];let n=Qd(e.scope),o=typeof t?.["process.pid"]==="number"?t["process.pid"]:0;return e.logRecords.flatMap((i)=>{if(!Le(i)||t===void 0)return[];let s=av(i.severityNumber);return[{service:r,source:"otlp",pid:o,body:i.body===void 0?"":Ti(i.body),attributes:jn(i.attributes),severityNumber:s,severityText:typeof i.severityText==="string"&&i.severityText!==""?i.severityText:ki(s),traceId:tm(i.traceId),spanId:Fc(i.spanId),traceFlags:typeof i.flags==="number"?i.flags:void 0,timeUnixNano:nn(i.timeUnixNano),observedTimeUnixNano:nn(i.observedTimeUnixNano),resource:t,scope:n}]})}function QD(e,t){if(!Le(e)||!Array.isArray(e.scopeSpans))return[];let r=Xd(e.resource,t);return e.scopeSpans.flatMap((n)=>ZD(n,r))}function ZD(e,t){if(!Le(e)||!Array.isArray(e.spans))return[];let r=Qd(e.scope);return e.spans.flatMap((n)=>{if(!Le(n))return[];let o=tm(n.traceId),i=Fc(n.spanId);if(!o||!i)return[];return[{traceId:o,spanId:i,parentSpanId:Fc(n.parentSpanId),name:typeof n.name==="string"&&n.name!==""?n.name:"span",kind:Dx(n.kind),startUnixNano:nn(n.startTimeUnixNano)??0,endUnixNano:nn(n.endTimeUnixNano)??0,status:Ox(n.status),attributes:jn(n.attributes),events:eO(n.events),links:tO(n.links),resource:t,scope:r}]})}function eO(e){if(!Array.isArray(e))return[];return e.flatMap((t)=>{if(!Le(t)||typeof t.name!=="string")return[];return[{timeUnixNano:nn(t.timeUnixNano)??0,name:t.name,attributes:jn(t.attributes)}]})}function tO(e){if(!Array.isArray(e))return[];return e.flatMap((t)=>{if(!Le(t))return[];let r=tm(t.traceId),n=Fc(t.spanId);if(!r||!n)return[];return[{traceId:r,spanId:n}]})}function tm(e){if(typeof e!=="string")return;return sr(e)?e.toLowerCase():void 0}function Fc(e){if(typeof e!=="string")return;return Sn(e)?e.toLowerCase():void 0}ne();Ke();var nO="application/json",oO=4194304;class rm{server;running=!1;addr="";opts;constructor(e){this.opts=e}isRunning(){return this.running}address(){return this.addr}listenPort(){let e=this.server?.address();if(e&&typeof e==="object")return e.port;return this.opts.port}endpoint(){return`http://${this.opts.host||Dt}:${this.listenPort()}`}start(){let e=this.opts.host||Dt;if(!Mt(e))return Promise.reject(T($e,"OTLP receiver must bind to a loopback address"));return new Promise((t,r)=>{this.server=rO((n,o)=>{this.handle(n,o)}),this.server.on("error",(n)=>r(ge($e,`unable to listen on ${e}:${this.opts.port}`,n))),this.server.listen(this.opts.port,e,()=>{let n=this.server?.address(),o=n&&typeof n==="object"?n.port:this.opts.port;this.addr=`${e}:${o}`,this.running=!0,t()})})}stop(){let e=this.server;if(this.running=!1,this.server=void 0,!e)return Promise.resolve();return new Promise((t)=>{e.close(()=>t())})}async handle(e,t){let n=(e.url??"/").split("?")[0]??"/";if(e.method!=="POST"){pa(t,405,{error:"method not allowed"});return}let o;try{o=JSON.parse(await iO(e))}catch{pa(t,400,{error:"invalid json"});return}let i=this.opts.fallbackService??"otlp";if(n==="/v1/logs"){for(let s of Mx(o,i))this.opts.logs.append(s);pa(t,200,{partialSuccess:{}});return}if(n==="/v1/traces"){for(let s of Nx(o,i))this.opts.spans.append(s);pa(t,200,{partialSuccess:{}});return}pa(t,404,{error:"not found"})}}function pa(e,t,r){let n=JSON.stringify(r);e.writeHead(t,{"content-type":nO,"content-length":Buffer.byteLength(n)}),e.end(n)}function iO(e){return new Promise((t,r)=>{let n=[],o=0;e.on("data",(i)=>{if(o+=i.length,o>oO){e.destroy(),r(Error("payload too large"));return}n.push(i)}),e.on("end",()=>t(Buffer.concat(n).toString("utf8"))),e.on("error",r)})}class nm{server;deps;constructor(e){this.deps=e}endpoint(){if(!this.server?.isRunning())return"";return this.server.endpoint()}async start(){let e=this.deps.cfg().telemetry.otlp;if(!e.enabled)return;if(this.server?.isRunning())return;this.server=new rm({host:e.listen.host||Dt,port:e.listen.port,logs:this.deps.logs,spans:this.deps.spans}),await this.server.start(),this.deps.log("devctl","INFO",`OTLP/HTTP+JSON listening on ${this.server.address()}`)}async stop(){await this.server?.stop(),this.server=void 0}}class om{cfg;sessionID;internalTok;bus;logs;spans;procs;tokens;detector;env;proxy;telemetry;mcp;web;resources;runtimes=new Map;ports=new Map;lock;shuttingDown=!1;detached=!1;identity;rpc;detectGoogleFn;inspectProcessFn;processAliveFn;acquireLockFn;socketExistsFn;unlinkSocketFn;registry;restartRequired=[];processMeta=new Map;configWatcher;watchTimer;setupMode;serviceWatchers;pluginMtimes=new Map;orchestrator;commands;clock;fs;healthCheckers;constructor(e,t){this.healthCheckers=t.healthCheckers,this.cfg=e,this.sessionID=t.sessionID,this.internalTok=Ld(),this.clock=t.clock,this.fs=t.fs,this.bus=t.bus,this.detectGoogleFn=t.detectGoogle,this.inspectProcessFn=t.inspectProcess,this.processAliveFn=t.processAlive,this.acquireLockFn=t.acquireLock,this.socketExistsFn=t.socketExists,this.unlinkSocketFn=t.unlinkSocket,this.detector=t.detector,this.logs=t.logs,this.spans=new em(void 0,this.detector),this.procs=t.procs,this.orchestrator=t.orchestrator,this.tokens=t.tokens,this.telemetry=new nm({cfg:()=>this.cfg,logs:this.logs,spans:this.spans,log:(r,n,o)=>this.log(r,n,o)}),this.proxy=new Xf({cfg:()=>this.cfg,ports:()=>this.ports,tokens:this.tokens,logs:this.logs,spans:this.spans,bus:this.bus,detector:this.detector,internalTok:()=>this.internalTok,middleware:()=>this.registry?.proxyMiddleware??[],persistState:()=>this.persistState()}),this.env=new Uf({cfg:()=>this.cfg,ports:()=>this.ports,userEmail:()=>this.identity.identityCache.user,proxy:()=>this.proxy.instance,tokenEndpoint:()=>this.proxy.tokenEndpoint,boundTokenURL:()=>this.proxy.boundTokenURL,internalTok:()=>this.internalTok,tokens:this.tokens,environmentSources:()=>this.registry?.environmentSources,otlpEndpoint:()=>this.telemetry.endpoint()}),this.mcp=new Kf({repoRoot:()=>this.cfg.repoRoot,createListener:t.createMcpListener,hostApi:()=>this.asMcpHost(),isKnownTool:t.isKnownTool,log:(r,n,o)=>this.log(r,n,o),persistState:()=>this.persistState()}),this.web=new Vf({cfg:()=>this.cfg,createListener:t.createWebListener,hostApi:()=>this.asMcpHost(),log:(r,n,o)=>this.log(r,n,o)}),this.resources=new Qf({clock:this.clock,runtimes:()=>this.runtimes}),this.identity=new zf({cfg:()=>this.cfg,tokens:this.tokens,detectGoogle:(r)=>this.detectGoogleFn(r),clock:this.clock,bus:this.bus,logs:this.logs,persistState:()=>this.persistState(),fail:(r,n)=>this.fail(r,n),log:(r,n,o)=>this.log(r,n,o),identityProviders:()=>this.registry?.identityProviders}),this.rpc=new Zf({dispatch:(r,n)=>this.dispatch(r,n),subscribe:(r,n)=>this.bus.subscribe(r,n),log:(r,n,o)=>this.log(r,n,o),socketExists:(r)=>this.socketExistsFn(r),unlinkSocket:(r)=>this.unlinkSocketFn(r)}),this.setupMode=!this.fs.exists(e.configPath);for(let r of Object.keys(e.services))this.runtimes.set(r,Qs(r));this.orchestrator.bind(this.lifecycleSession()),this.commands=t.createCommands(this),this.serviceWatchers=new Ff({repoRoot:()=>this.cfg.repoRoot,log:(r,n,o)=>this.log(r,n,o),isActive:(r)=>this.orchestrator.serviceIsActive(r),restart:(r)=>this.restart([r],{auto:!0})})}get profile(){return this.env.profile}set profile(e){this.env.profile=e}get profileEnv(){return this.env.profileEnv}set profileEnv(e){this.env.profileEnv=e}get clientEnv(){return this.env.clientEnv}get serviceProfile(){return this.env.serviceProfile}get serviceProfileEnv(){return this.env.serviceProfileEnv}snapshotHost(){let e=this;return{get sessionID(){return e.sessionID},get cfg(){return e.cfg},get profile(){return e.profile},get runtimes(){return e.runtimes},get ports(){return e.ports},get serviceProfile(){return e.serviceProfile},get clientEnv(){return e.clientEnv},get proxy(){return e.proxy.instance},get mcp(){return e.mcp.instance},get web(){return e.web.instance},get mcpToken(){return e.mcp.token},get mcpDisabledTools(){return e.mcp.disabledTools},get identityCache(){return e.identity.identityCache},get serviceAccountStatus(){return e.identity.serviceAccountStatus},get credentialEntries(){return e.identity.credentialEntries},get detached(){return e.detached},get setupMode(){return e.setupMode},get restartRequired(){return e.restartRequired},get statsSeries(){return e.resources.series()},logs:{snapshot:()=>e.logs.snapshot()},tokens:{storeBackend:()=>e.tokens.storeBackend()},traceDurationMs:(t)=>e.spans.envelopeMs(t)}}reloadHost(){let e=this;return{get cfg(){return e.cfg},set cfg(t){e.cfg=t},get setupMode(){return e.setupMode},set setupMode(t){e.setupMode=t},get configWatcher(){return e.configWatcher},set configWatcher(t){e.configWatcher=t},get watchTimer(){return e.watchTimer},set watchTimer(t){e.watchTimer=t},get restartRequired(){return e.restartRequired},set restartRequired(t){e.restartRequired=t},get fs(){return e.fs},get registry(){return e.registry},set registry(t){e.registry=t},get pluginMtimes(){return e.pluginMtimes},set pluginMtimes(t){e.pluginMtimes=t},get detector(){return e.detector},get bus(){return e.bus},get orchestrator(){return e.orchestrator},get runtimes(){return e.runtimes},get tokens(){return e.tokens},get logs(){return e.logs},get proxy(){return e.proxy.instance},persistState:()=>e.persistState(),log:(t,r,n)=>e.log(t,r,n),refreshIdentity:()=>e.refreshIdentity(),startProxy:()=>e.startProxy(),stopProxy:()=>e.stopProxy(),reload:()=>e.reload(),forgetService:(t)=>e.forgetService(t),syncServiceWatchers:()=>e.serviceWatchers.sync(e.cfg.services)}}recoverHost(){let e=this;return{get cfg(){return e.cfg},set cfg(t){e.cfg=t},get profile(){return e.profile},set profile(t){e.profile=t},get profileEnv(){return e.profileEnv},set profileEnv(t){e.profileEnv=t},get runtimes(){return e.runtimes},get ports(){return e.ports},get processMeta(){return e.processMeta},get serviceProfile(){return e.serviceProfile},get serviceProfileEnv(){return e.serviceProfileEnv},get orchestrator(){return e.orchestrator},get procs(){return e.procs},logs:{append:(t)=>e.logs.append(t)},get clock(){return e.clock},get tokens(){return e.tokens},get registry(){return e.registry},get proxy(){return e.proxy.instance},get tokenEP(){return e.proxy.tokenEndpoint},get boundTokenURL(){return e.proxy.boundTokenURL},get internalTok(){return e.internalTok},get bus(){return e.bus},inspectProcessFn:(t)=>e.inspectProcessFn(t),processAliveFn:(t)=>e.processAliveFn(t),serviceWorkDir:(t)=>e.serviceWorkDir(t),persistState:()=>e.persistState(),setState:(t,r,n,o,i)=>e.setState(t,r,n,o,i),log:(t,r,n)=>e.log(t,r,n)}}async run(){let e=Za(this.cfg.repoRoot);this.lock=this.acquireLockFn(this.cfg.repoRoot,e),this.rpc.removeStaleSocket(e),this.registry=await Ic(this.cfg.plugins.map((t)=>t.path),this.cfg.repoRoot),this.pluginMtimes=If(this.cfg.plugins.map((t)=>t.path),this.cfg.repoRoot);for(let t of this.registry.loadErrors)this.log("devctl","ERROR",`plugin ${t.path} skipped: ${t.message}`);Lf(this.reloadHost()),Df(this.registry,this.cfg),Of(this.registry,this.cfg),Mf(this.registry,this.cfg),await this.recoverSession(),this.serviceWatchers.sync(this.cfg.services),Nf(this.reloadHost()),this.persistState(),this.log("devctl","INFO",`supervisor started session=${this.sessionID}`),this.refreshIdentity(),this.resources.start(),await this.telemetry.start(),await this.web.start(),await this.mcp.bootFromPreferences(),this.rpc.removeStaleSocket(e),await this.rpc.listen(e)}async dispatch(e,t){let r=Mc(t)?t:{};switch(e){case"ping":return{session:this.sessionID,version:Xt,protocol:Ys};case"start":return this.commands.startService.execute({services:Vi(r.services),profile:typeof r.profile==="string"&&r.profile!==""?r.profile:void 0,detach:r.detach===!0,client_env:da(r.client_env)});case"stop":return await this.commands.stopService.execute(Vi(r.services)),null;case"restart":return await this.commands.restartService.execute(Vi(r.services),{cascade:r.cascade===!0,clientEnv:da(r.client_env)}),null;case"run_task":return this.runTask(typeof r.name==="string"?r.name:"",da(r.client_env)??{});case"exec":return this.execService(typeof r.service==="string"?r.service:"",Vi(r.command),da(r.client_env)??{},r.print_env===!0);case"auth_refresh":return await this.commands.refreshIdentity.execute(),this.snapshot().identity;case"status":return this.snapshot();case"logs":return await this.queryLogs({...Nc(r),export:typeof r.export==="string"?r.export:""});case"logs_page":return await this.queryLogsPage({...Nc(r),cursor:typeof r.cursor==="string"?r.cursor:void 0,direction:r.direction==="forward"?"forward":"backward",limit:typeof r.limit==="number"?r.limit:void 0});case"logs_stats":return await this.queryLogsFacets(Nc(r));case"get_trace":return await this.queryTrace(typeof r.trace_id==="string"?r.trace_id:typeof r.traceId==="string"?r.traceId:"");case"trace_request":return await this.queryTraceByRequest(typeof r.request_id==="string"?r.request_id:typeof r.requestId==="string"?r.requestId:"");case"proxy_start":return this.proxy.setSuppressed(!1),await this.commands.startProxy.execute(),null;case"proxy_stop":return this.proxy.setSuppressed(!0),await this.commands.stopProxy.execute(),null;case"mcp_start":{let o=typeof r.port==="number"?r.port:void 0;return await this.startMcp(o??vi(this.cfg.repoRoot).mcp_port),null}case"mcp_stop":return await this.stopMcp(),null;case"web_start":return await this.web.startExplicit(),null;case"web_stop":return await this.web.stop(),null;case"mcp_set_tools":{let o=Array.isArray(r.disabled)?r.disabled.filter((i)=>typeof i==="string"):[];return this.setMcpDisabledTools(o),{disabled_tools:[...this.mcp.disabledTools]}}case"reload":return this.commands.reloadConfig.execute();case"config_snapshot":return this.cfg;case"auth_invalidate":return this.tokens.invalidate(),null;case"shutdown":let n=typeof r.stop_services==="boolean"?r.stop_services:Hl(this.cfg.shutdown);return setTimeout(()=>{this.shutdown(n)},50),null;default:throw T($e,`unknown method ${e}`)}}isDetached(){return this.detached}async start(e){return this.orchestrator.start(e)}lifecycleSession(){let e=this;return{get cfg(){return e.cfg},get profile(){return e.profile},set profile(t){e.profile=t},get profileEnv(){return e.profileEnv},set profileEnv(t){e.profileEnv=t},get detached(){return e.detached},set detached(t){e.detached=t},get proxySuppressed(){return e.proxy.isSuppressed},get runtimes(){return e.runtimes},get ports(){return e.ports},get clientEnv(){return e.clientEnv},get serviceProfile(){return e.serviceProfile},get serviceProfileEnv(){return e.serviceProfileEnv},healthCheckers:{lookup:(t)=>{let r=e.registry?.healthChecks.find((n)=>n.name.toLowerCase()===t.toLowerCase());return r?{check:async(n,o)=>{let i=await r.check(n,o);return{...i,status:i.status}}}:e.healthCheckers.lookup(t)}},logs:{append:(t)=>e.logs.append(t)},bus:e.bus,processMeta:e.processMeta,get containerPrefix(){return`devctl-${Tr(e.cfg.repoRoot)}-`},prepareServiceIdentity:(t,r)=>e.identity.prepareServiceIdentity(t,r),resolveServiceExecution:(t,r,n,o,i,s)=>e.env.resolveServiceExecution(t,r,n,o,i,s),detectGoogle:(t)=>e.detectGoogleFn(t),startProxy:()=>e.startProxy(),fail:(t,r)=>e.fail(t,r),claimIfAlreadyUp:(t)=>e.claimIfAlreadyUp(t),assignPendingPorts:(t)=>e.assignPendingPorts(t),setState:(t,r,n,o,i)=>e.setState(t,r,n,o,i),persistState:()=>e.persistState(),log:(t,r,n)=>e.log(t,r,n),releasePorts:(t)=>e.releasePorts(t),forgetService:(t)=>e.forgetService(t),clearRestartRequired:(t)=>e.dropRestartRequired(t)}}async assignPendingPorts(e){try{let t=await ay(this.cfg,e,Object.fromEntries(this.ports));for(let[r,n]of Object.entries(t)){this.ports.set(r,n);let o=Object.entries(n).map(([i,s])=>`${i}=${s}`).join(", ");this.log(r,"INFO",`assigned ports: ${o||"none"}`)}}catch(t){if(t instanceof et&&t.service!=="")await this.fail(t.service,t);else this.log("devctl","ERROR",I(t));throw t}}async runTask(e,t){let r=this.cfg.tasks[e];if(!r)throw T($e,`unknown task ${e}`);if(r.dependencies.length>0)await this.start({services:r.dependencies,client_env:t});let n={...qn(),command:r.command,shell:r.shell,working_dir:r.working_dir,dependencies:r.dependencies,environment:r.environment},{env:o,workDir:i}=await this.env.resolveTaskEnvironment(e,n,t),s=await this.runTransient(`task:${e}`,r.command,r.shell,i,o);return{task:e,...s}}async execService(e,t,r,n=!1){let o=this.cfg.services[e];if(!o)throw T(Pi,`unknown service ${e}`);let i=this.env.serviceProfile.get(e)??this.env.profile,s=i!==""?Ko(this.cfg,i):this.env.profileEnv,{env:a,workDir:l}=await this.env.resolveServiceExecution(e,o,i,s,r,!o.container);if(n)return{service:e,code:0,stdout:"",stderr:"",environment:a};if(t.length===0)throw T($e,"exec command is required");let c=await this.runTransient(`${e}:exec`,{args:t,shell:!1},!1,l,a);return{service:e,...c}}async runTransient(e,t,r,n,o){if(Gn(t))return{code:0,stdout:"",stderr:""};this.log(e,"INFO",`running ${t.args.join(" ")}`);let i=await this.procs.runOnce({name:e,args:[...t.args],shell:r||t.shell,workDir:n,env:o,graceMs:Vn(this.cfg.shutdown)*1000,onLine:(s,a)=>this.logs.append({timestamp:this.clock.isoNow(),service:e,source:s,stream:s,level:"",message:a,pid:0})});if(i.code!==0)throw T(Ge,`${e} exited with code ${i.code}`);return i}serviceWorkDir(e){return this.env.serviceWorkDir(e)}async claimIfAlreadyUp(e){return sx(this.recoverHost(),e)}async recoverSession(){return ax(this.recoverHost())}async stop(e){return this.orchestrator.stop(e)}forgetService(e){this.orchestrator.health.forget(e),this.runtimes.delete(e),this.ports.delete(e),this.processMeta.delete(e),this.env.forget(e)}async restart(e,t){let r=t?.cascade===!0?Go(this.cfg,e):e;await this.orchestrator.restart(e,t),this.dropRestartRequired(r)}dropRestartRequired(e){if(e.length===0)return;let t=new Set(e);this.restartRequired=this.restartRequired.filter((r)=>!t.has(r))}async startProxy(){return this.proxy.start()}async stopProxy(){return this.proxy.stop()}async startMcp(e){return this.mcp.start(e)}setMcpDisabledTools(e){this.mcp.setDisabledTools(e)}async stopMcp(){return this.mcp.stop()}asMcpHost(){return{status:()=>this.commands.getServiceStatus.execute(),logsPage:(e)=>this.queryLogsPage(e),config:()=>this.cfg,validateConfigText:(e)=>Bs(this.cfg.repoRoot,this.cfg.configPath,e),start:(e)=>this.commands.startService.execute(e),stop:(e)=>this.commands.stopService.execute(e),restart:(e,t)=>this.commands.restartService.execute(e,{cascade:t}),reload:()=>this.commands.reloadConfig.execute(),doctor:async()=>{for(let e of ln(this.cfg))await this.identity.probeServiceAccount(e);return this.commands.runDoctor.execute(this.cfg)},exec:(e,t,r)=>this.execService(e,t,void 0,r),runTask:(e)=>this.runTask(e,{}),startProxy:()=>this.startProxy(),stopProxy:()=>this.stopProxy(),getTrace:(e)=>this.queryTrace(e),traceRequest:(e)=>this.queryTraceByRequest(e)}}async reload(){return mx(this.reloadHost())}async shutdown(e){if(this.shuttingDown)return;if(this.shuttingDown=!0,this.persistState(),e)await this.stop([]);if(this.orchestrator.health.dispose(),await this.stopProxy(),await this.telemetry.stop(),this.spans.close(),await this.stopMcp(),await this.web.stop(),this.configWatcher?.close(),this.serviceWatchers.close(),this.watchTimer)clearTimeout(this.watchTimer);this.resources.stop(),this.rpc.close(),this.lock?.release(),await this.logs.close()}snapshot(){return wx(this.snapshotHost())}async refreshIdentity(e){return this.identity.refreshIdentity(e)}async queryLogs(e){let t=this.logFilter(e),r=await this.logs.query(t);if(e.export)await this.logs.exportTo(e.export,t);return{events:r}}async queryLogsPage(e){return this.logs.queryPage(this.logFilter(e),{cursor:e.cursor,direction:e.direction,limit:e.limit})}async queryLogsFacets(e){return this.logs.queryFacets(this.logFilter(e))}async queryTrace(e){let t=this.spans.getTrace(e),r=e===""?[]:await this.logs.query({traceId:e});return{traceId:e,tree:t,events:r}}async queryTraceByRequest(e){let r=this.spans.findTraceIdByRequestId(e)??(sr(e)?e.toLowerCase():"");return{...await this.queryTrace(r),requestId:e}}logFilter(e){return{services:e.services,level:e.level,search:e.search,regex:e.regex,source:e.source,since:e.since,until:e.until,traceId:e.traceId,requestId:e.requestId,attribute:e.attribute}}subscribe(e){return this.bus.subscribe(e)}formatStatus(){return xx(this.snapshot())}setState(e,t,r,n,o){let i=this.runtimes.get(e)??Qs(e);if(!aa(i.state,t))this.log(e,"WARN",`unusual lifecycle ${i.state} \u2192 ${t}`);i.state=t,i.health=r,i.pid=n,i.last_error=o;let s=t===Ve||t===Lr||t===cn;if(i.startTime=s?this.processMeta.get(e)?.startTime.toISOString():void 0,!s)i.cpuPercent=void 0,i.memoryKB=void 0;this.runtimes.set(e,i),this.bus.publish(Ce(Jg,e,{state:t,health:r,pid:n}))}async releasePorts(e){let t=this.ports.get(e);if(!t)return;let r=this.cfg.services[e];if(r?.container){this.ports.delete(e);return}let n=this.processMeta.get(e);for(let o of Object.values(t)){let i=await Lo(o);if(!i||i.pid===process.pid)continue;if(r){let s=await this.inspectProcessFn(i.pid);if(!(s!==void 0&&s.command!==""&&sa({args:n?.command??[...r.command.args],workDir:n?.cwd??this.serviceWorkDir(r),startTime:n?.startTime},s))){this.log(e,"WARN",`port ${o} is held by pid ${i.pid}, which does not match ${e}; leaving it running`);continue}}try{await Il(i),this.log(e,"INFO",`released port ${o} (pid ${i.pid})`)}catch(s){this.log(e,"WARN",I(s))}}this.ports.delete(e)}async fail(e,t){this.orchestrator.health.clearHealthWatch(e),this.orchestrator.health.clearRestartTimer(e),this.orchestrator.health.bumpGeneration(e),this.setState(e,bt,Ft,0,I(t));try{await this.procs.stop(e,Vn(this.cfg.shutdown)*1000)}catch(r){this.log(e,"WARN",I(r))}this.bus.publish(Ce(ll,e,{error:I(t)})),this.log(e,"ERROR",I(t)),this.persistState()}log(e,t,r){this.logs.append({timestamp:this.clock.isoNow(),service:e,source:"devctl",level:t,message:r,pid:0})}persistState(){let e=[];for(let t of this.procs.all()){let r=this.processMeta.get(t.name);e.push({name:t.name,pid:t.pid,command:r?.command??t.args,cwd:r?.cwd??t.workDir,startTime:(r?.startTime??t.startTime).toISOString(),ports:this.ports.get(t.name)??{},profile:this.serviceProfile.get(t.name)??this.profile})}Bg(this.cfg.repoRoot,{session_id:this.sessionID,repo_root:this.cfg.repoRoot,profile:this.profile,processes:e})}}var $x=500,sO=1e4,aO=2000,lO=new URL("./log-worker.ts",import.meta.url);class Hx{worker;bus;pending=new Map;nextId=1;stats={total:0,errors:0,counts:{},seen:0,seenErrors:0};dead=!1;readySettled=!1;ready;resolveReady=()=>{return};rejectReady=()=>{return};constructor(e,t,r={}){this.bus=t,this.ready=new Promise((n,o)=>{this.resolveReady=n,this.rejectReady=o}),this.worker=new Worker(r.script??lO,{name:"devctl-logs"}),this.worker.addEventListener("message",(n)=>{this.onMessage(n.data)}),this.worker.addEventListener("error",(n)=>{this.markDead(Error(n.message||"log worker failed"))}),this.post({type:"init",config:e})}waitUntilReady(e=$x){if(this.dead)return Promise.reject(Error("log worker is not running"));if(this.readySettled)return Promise.resolve();return new Promise((t,r)=>{let n=setTimeout(()=>{this.markDead(Error("log worker init timed out"))},e);this.ready.then(()=>{clearTimeout(n),t()},(o)=>{clearTimeout(n),r(o)})})}append(e){if(this.dead)return;try{this.post({type:"append",event:e})}catch{}}async query(e){let t=await this.rpc({type:"query",filter:e});if(!Array.isArray(t))throw Error("log worker query returned a non-array");return t}async queryPage(e,t){let r=await this.rpc({type:"queryPage",filter:e,page:t});if(!cO(r))throw Error("log worker queryPage returned an unexpected payload");return r}async queryFacets(e){let t=await this.rpc({type:"queryFacets",filter:e});if(!uO(t))throw Error("log worker queryFacets returned an unexpected payload");return t}snapshot(){return this.stats}async exportTo(e,t){await this.rpc({type:"exportTo",path:e,filter:t})}setParsers(e,t){if(this.dead)return;this.post({type:"setPluginPaths",paths:[...t??[]]})}setSecrets(e,t){if(this.dead)return;this.post({type:"setSecrets",extraMarkers:e,extraPatterns:t})}async close(){if(this.dead)return;try{await this.rpc({type:"close"},aO)}catch{}finally{this.markDead(Error("log worker closed"))}}rpc(e,t=sO){this.assertAlive();let r=this.nextId;this.nextId+=1;let n={...e,id:r};return new Promise((o,i)=>{let s=setTimeout(()=>{this.markDead(Error(`log worker timed out (${e.type})`))},t);this.pending.set(r,{resolve:o,reject:i,timer:s});try{this.post(n)}catch(a){clearTimeout(s),this.pending.delete(r),i(a instanceof Error?a:Error(String(a)))}})}post(e){this.assertAlive(),this.worker.postMessage(e)}onMessage(e){if(e.type==="ready"){this.settleReady();return}if(e.type==="appended"){this.stats=e.stats,this.bus?.publish(Ce(yi,e.event.service,{event:e.event,level:e.event.severityText}));return}let t=this.pending.get(e.id);if(!t)return;if(this.pending.delete(e.id),clearTimeout(t.timer),e.type==="error"){t.reject(Error(e.error));return}t.resolve(e.result)}settleReady(){if(this.readySettled||this.dead)return;this.readySettled=!0,this.resolveReady()}assertAlive(){if(this.dead)throw Error("log worker is not running")}markDead(e){if(this.dead)return;if(this.dead=!0,!this.readySettled)this.readySettled=!0,this.rejectReady(e);this.rejectAll(e);try{this.worker.terminate()}catch{}}rejectAll(e){for(let t of this.pending.values())clearTimeout(t.timer),t.reject(e);this.pending.clear()}}function cO(e){if(e===null||Array.isArray(e)||!("events"in e))return!1;return Array.isArray(e.events)}function uO(e){return e!==null&&!Array.isArray(e)&&"byService"in e}function Fx(e,t,r){return Yv(new yp(e.max,t,r,e.persist,e.directory,e.sessionID,e.retentionDays,e.maxSessionLogs))}async function Ux(e,t,r,n={}){if(n.standalone??Bun.isStandaloneExecutable===!0)return{logs:Fx(e,t,r),usingWorker:!1};try{let i=new Hx(e,t,{script:n.script});return await i.waitUntilReady(n.initTimeoutMs??$x),{logs:i,usingWorker:!0}}catch{return{logs:Fx(e,t,r),usingWorker:!1}}}To();import{createServer as DO}from"http";ne();Ji();var OO="2025-03-26",i0="2.0",t0=-32700,r0=-32600,MO=-32601,n0=-32602,NO=-32603;function FO(e){return e!==""&&Mt(e)}class pm{server;running=!1;addr="";boundPort=0;opts;constructor(e){this.opts=e}disabled(){return this.opts.disabledTools?.()??[]}address(){return this.addr}listenPort(){return this.boundPort}isRunning(){return this.running}emit(e,t){this.opts.onEvent?.(e,t)}start(){if(!FO(this.opts.host))return Promise.reject(T($e,`refusing to bind MCP to ${this.opts.host}`));return new Promise((e,t)=>{this.server=DO((r,n)=>{this.serve(r,n)}),this.server.on("error",(r)=>t(ge($e,`unable to listen on ${this.opts.host}:${this.opts.port}`,r))),this.server.listen(this.opts.port,this.opts.host,()=>{let r=this.server?.address();this.boundPort=typeof r==="object"&&r?r.port:this.opts.port,this.addr=`${this.opts.host}:${this.boundPort}`,this.running=!0,this.emit("INFO",`listening on ${this.addr}`),e()})})}stop(){let e=this.server,t=this.running;if(!e)return this.running=!1,Promise.resolve();return new Promise((r)=>{e.close(()=>{if(this.running=!1,this.addr="",this.boundPort=0,this.server=void 0,t)this.emit("INFO","stopped");r()})})}async serve(e,t){if(e.method==="OPTIONS"){t.writeHead(204,va()),t.end();return}if(!this.authorized(e)){this.emit("WARN",`rejected unauthorized request from ${o0(e)}`),Xi(t,401,{error:"unauthorized"});return}if(HO(e)!=="/mcp"){Xi(t,404,{error:"not found"});return}if(e.method==="GET"||e.method==="DELETE"){t.writeHead(405,{Allow:"POST, OPTIONS",...va()}),t.end();return}if(e.method!=="POST"){t.writeHead(405,{Allow:"POST, OPTIONS",...va()}),t.end();return}let n;try{n=await UO(e)}catch(a){Xi(t,400,ha(null,t0,a instanceof Error?a.message:"invalid body"));return}let o;try{o=JSON.parse(n)}catch{Xi(t,400,ha(null,t0,"parse error"));return}let i=o0(e);if(Array.isArray(o)){let a=[];for(let l of o){let c=await this.dispatch(l,i);if(c!==void 0)a.push(c)}Xi(t,200,a);return}let s=await this.dispatch(o,i);if(s===void 0){t.writeHead(202,va()),t.end();return}Xi(t,200,s)}authorized(e){if(this.opts.token==="")return!0;return(e.headers.authorization??"")===`Bearer ${this.opts.token}`}async dispatch(e,t){if(!zc(e))return ha(null,r0,"invalid request");let r=e,n=r.id??null,o=r.id===void 0;if(r.method===void 0||r.method==="")return o?void 0:ha(n,r0,"missing method");try{let i=await this.handleMethod(r.method,zc(r.params)?r.params:{},t);if(o)return;return{jsonrpc:i0,id:n,result:i}}catch(i){if(o)return;let s=i instanceof ga?i.code:NO,a=i instanceof Error?i.message:"internal error";return this.emit("WARN",`rpc error method=${r.method} addr=${t}: ${a}`),ha(n,s,a)}}async handleMethod(e,t,r){switch(e){case"initialize":{let n=$O(t);return this.emit("INFO",`client connected addr=${r}${n?` (${n})`:""}`),{protocolVersion:OO,capabilities:{tools:{},resources:{}},serverInfo:{name:"devctl",version:Xt}}}case"notifications/initialized":case"ping":return{};case"tools/list":return{tools:Jx(this.disabled()).map((n)=>({name:n.name,description:n.description,inputSchema:n.inputSchema}))};case"tools/call":return this.callTool(t);case"resources/list":return{resources:sm.map((n)=>({uri:n,name:n.replace("devctl://",""),mimeType:"application/json"}))};case"resources/read":return this.readResource(t);default:throw new ga(MO,`method not found: ${e}`)}}async callTool(e){let t=typeof e.name==="string"?e.name:"";if(t==="")throw new ga(n0,"tool name is required");if(Hc(t)&&!no(t,this.disabled())){let o=`tool ${t} is disabled in devctl's MCP settings`;return this.emit("WARN",`tool call rejected name=${t}: disabled`),{content:[{type:"text",text:o}],isError:!0}}let r=zc(e.arguments)?e.arguments:{},n=Date.now();try{let o=await Wc(this.opts.hostApi,t,r);return this.emit("INFO",`tool call name=${t} duration=${Date.now()-n}ms`),{content:[{type:"text",text:JSON.stringify(o,null,2)}]}}catch(o){let i=o instanceof Error?o.message:"tool failed";return this.emit("WARN",`tool call failed name=${t} duration=${Date.now()-n}ms: ${i}`),{content:[{type:"text",text:i}],isError:!0}}}async readResource(e){let t=typeof e.uri==="string"?e.uri:"";if(!Zx(t))throw new ga(n0,`unknown resource ${t}`);let r=await e0(this.opts.hostApi,t);return this.emit("INFO",`resource read uri=${t}`),{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(r,null,2)}]}}}function $O(e){let t=e.clientInfo;if(!zc(t))return"";let r=typeof t.name==="string"?t.name:"",n=typeof t.version==="string"?t.version:"";if(r==="")return"";return n===""?r:`${r} ${n}`}function o0(e){return e.socket.remoteAddress??"unknown"}class ga extends Error{code;constructor(e,t){super(t);this.code=e}}function va(){return{"Access-Control-Allow-Origin":"*","Access-Control-Allow-Headers":"Authorization, Content-Type, Accept, MCP-Protocol-Version, Mcp-Session-Id","Access-Control-Allow-Methods":"POST, OPTIONS"}}function Xi(e,t,r){let n=JSON.stringify(r);e.writeHead(t,{"Content-Type":"application/json","Content-Length":Buffer.byteLength(n),...va()}),e.end(n)}function ha(e,t,r){return{jsonrpc:i0,id:e,error:{code:t,message:r}}}function HO(e){let t=e.url??"/",r=t.indexOf("?");return r>=0?t.slice(0,r):t}function UO(e){return new Promise((t,r)=>{let n=[];e.on("data",(o)=>{n.push(o)}),e.on("end",()=>{t(Buffer.concat(n).toString("utf8"))}),e.on("error",r)})}function zc(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}import{readFileSync as jO}from"fs";import{createServer as BO}from"http";import{join as WO}from"path";ne();Ke();Ji();var qc=`<!doctype html>
|
|
2549
|
+
`}var zD=4000;class qf{cache;accounts=new Map;entries=[];deps;constructor(e){this.deps=e,this.cache=kx(e.cfg()),this.deps.bus.subscribe((t)=>{let r=t.payload??{},n=t.type===bi?`token refreshed identity=${String(r.identity??"")}`:t.type===ko?`token refresh failed identity=${String(r.identity??"")} audience=${String(r.audience??"")}: ${String(r.error??"")}`:`authentication changed user=${String(r.user??"")}`;if(this.deps.logs.append({timestamp:this.deps.clock.isoNow(),service:"auth",source:"auth",level:t.type===ko?"WARN":"INFO",message:n,pid:0}),t.type===bi||t.type===ko)this.syncCredentialEntries()},[bi,ko,Md])}get identityCache(){return this.cache}get serviceAccountStatus(){return this.accounts}get credentialEntries(){return this.entries}async prepareServiceIdentity(e,t){let r=ec(t.identity);if(r.kind!=="none")try{if(r=await Lb(t.identity,()=>Mb(this.deps.cfg().google.project_id),this.deps.identityProviders()),r.kind==="service_account")await this.deps.tokens.get(Qn(r),"",[]),this.accounts.set(r.serviceAccount,"available")}catch(n){if(r.kind==="service_account")this.accounts.set(r.serviceAccount,"unavailable");if(GD(t)||r.kind==="service_account"||r.kind!=="user"&&r.kind!=="none")throw await this.deps.fail(e,n),n;this.deps.log(e,"WARN","cloud identity unavailable; starting service locally")}}async syncCredentialEntries(){this.entries=(await this.deps.tokens.listStatus()).map((e)=>({identity:e.identity,audience:e.audience,expires_at:e.expires_at,valid:e.valid}))}async refreshIdentity(e){try{let t=this.deps.cfg(),r=await this.deps.detectGoogle(t.google.project_id);if(e?.probeServiceAccounts)for(let i of ln(t))await this.probeServiceAccount(i);let{service_accounts:n,service_account_status:o}=zf(t,this.accounts);this.cache={user:r.userEmail,project:r.projectID||t.google.project_id,project_source:r.projectSource||(t.google.project_id?"configuration":""),adc:r.adcAvailable,service_accounts:n,service_account_status:o,iap:t.proxy.routes.some((i)=>i.auth.type.toLowerCase()==="iap")},await this.syncCredentialEntries(),this.deps.bus.publish(Ce(Md,"",{user:this.cache.user,adc:this.cache.adc})),this.deps.log("auth","INFO",`authentication changed user=${this.cache.user||"(unknown)"} adc=${this.cache.adc}`),this.deps.persistState()}catch(t){this.deps.log("devctl","WARN",`identity refresh failed: ${I(t)}`)}}async probeServiceAccount(e){let t;try{await qD(this.deps.tokens.refresh(`sa:${e}`,"",[]),zD),t="available"}catch{t="unavailable"}return this.accounts.set(e,t),t}}function qD(e,t){return new Promise((r,n)=>{let o=setTimeout(()=>n(Error("identity probe timed out")),t);e.then((i)=>{clearTimeout(o),r(i)},(i)=>{clearTimeout(o),n(i)})})}function GD(e){return e.capabilities.some((t)=>["google_api","iap","service_identity"].includes(t))}ne();ne();Kf();var XD=600,QD=65535;async function Ax(e,t){let r=Number.isInteger(t)&&(t??0)>0?t:Xo(e);for(let n=0;n<XD;n+=1){let o=r+n;if(o>QD)break;if(await Ai(o))return o}throw T(ee,`no free MCP port starting at ${r}`)}class Vf{listener;disabled=[];token;deps;constructor(e){this.deps=e,this.token=qg(e.repoRoot())}get instance(){return this.listener}get disabledTools(){return this.disabled}async bootFromPreferences(){let e=vi(this.deps.repoRoot());if(this.setDisabledTools(e.mcp_disabled_tools??[]),e.mcp_enabled)await this.start(e.mcp_port).catch((t)=>this.deps.log("devctl","ERROR",I(t)))}async start(e){if(this.listener?.isRunning())return;let t=await Ax(this.deps.repoRoot(),e);this.listener=this.deps.createListener({port:t,token:this.token,hostApi:this.deps.hostApi(),onEvent:(r,n)=>this.deps.log("mcp",r,`mcp ${n}`),disabledTools:()=>this.disabled}),await this.listener.start(),this.deps.persistState()}setDisabledTools(e){let t=e.filter((n)=>this.deps.isKnownTool(n)),r=this.disabled.join(",");if(this.disabled=[...new Set(t)].sort(),this.disabled.join(",")===r)return;this.deps.log("devctl","INFO",this.disabled.length===0?"all MCP tools enabled":`MCP tools disabled: ${this.disabled.join(", ")}`)}async stop(){await this.listener?.stop(),this.listener=void 0,this.deps.persistState()}}Ke();class Yf{listener;deps;constructor(e){this.deps=e}get instance(){return this.listener}address(){return this.listener?.isRunning()?this.listener.address():""}endpoint(){let e=this.address();return e===""?"":`http://${e}/`}async start(){if(!this.deps.cfg().web.enabled)return;await this.bind()}async startExplicit(){await this.bind()}async stop(){await this.listener?.stop(),this.listener=void 0}async bind(){if(this.listener?.isRunning())return;let e=this.deps.cfg().web.listen;this.listener=this.deps.createListener({host:e.host||Ot,port:e.port,hostApi:this.deps.hostApi(),onEvent:(t,r)=>this.deps.log("web",t,`web ${r}`)}),await this.listener.start(),this.deps.log("devctl","INFO",`web UI listening on ${this.endpoint()}`)}}Ke();import*as Qo from"http2";ne();Gr();var Jf="14",ZD="16",eO="1",Lx=new Set(["host","connection","keep-alive","transfer-encoding","upgrade","proxy-connection","authorization"]);class Xf{route;tokens;logs;bus;detector;spans;server;client;running=!1;addr="";requests=new Lc;constructor(e,t,r,n,o,i){this.route=e;this.tokens=t;this.logs=r;this.bus=n;this.detector=o;this.spans=i}address(){return this.addr}isRunning(){return this.running}stats(){return this.requests.stats()}start(){let e=this.route.listen?.host||"127.0.0.1",t=this.route.listen?.port??0;if(!_t(e))return Promise.reject(T(ar,`refusing to bind grpc route ${this.route.name} to ${e}`));if(t===0)return Promise.reject(T(ar,`grpc route ${this.route.name} requires listen.port`));return new Promise((r,n)=>{let o=Qo.createServer();o.on("stream",(i,s)=>void this.serve(i,s)),o.on("sessionError",()=>{}),o.on("error",(i)=>{if(this.running){this.log("ERROR",`grpc route ${this.route.name} listener error: ${i.message}`);return}n(ge(ar,`grpc route ${this.route.name} unable to listen on ${e}:${t}`,i))}),o.listen(t,e,()=>{this.server=o,this.running=!0,this.addr=`${e}:${t}`,this.log("INFO",`grpc route ${this.route.name} listening on ${this.addr} \u2192 ${this.route.upstream.url}`),r()})})}stop(){let e=this.server;if(this.client?.close(),this.client=void 0,!e)return Promise.resolve();return new Promise((t)=>{e.close(()=>{this.running=!1,t()})})}upstream(){if(this.client&&!this.client.closed&&!this.client.destroyed)return this.client;let e=Qo.connect(this.route.upstream.url);return e.on("error",()=>{if(this.client===e)this.client=void 0}),e.on("goaway",()=>{if(this.client===e)this.client=void 0}),e.on("close",()=>{if(this.client===e)this.client=void 0}),this.client=e,e}async serve(e,t){let r=Date.now(),n=ca({traceparent:Ix(t,Yo),requestId:Ix(t,eo)}),o=n.requestId,i=String(t[":path"]??"/"),s=Pn(this.route.auth),a=Qn(s),l=!1,c=(h,g,w)=>{if(l)return;l=!0;let v=Date.now()-r,S=this.detector?this.detector.redactText(i):i,E=w??(g!=="0"?`grpc-status ${g}`:void 0),_={timestamp:new Date().toISOString(),requestId:o,method:"POST",path:S,route:this.route.name,identity:a,status:h,durationMs:v,error:E,traceId:n.traceId,spanId:n.spanId,parentSpanId:n.parentSpanId};this.requests.record(_),this.spans?.append(Ac(_)),this.log(E?"WARN":"INFO",`grpc ${i} route=${this.route.name} identity=${a} grpc-status=${g} duration=${v}ms${E?` error=${E}`:""}`,o,a),this.bus?.publish(Ce(Cs,this.route.name,{status:h,request_id:o,duration:v,identity:a}))},u=(h,g)=>{try{e.respond({":status":200,"content-type":"application/grpc","grpc-status":h,"grpc-message":g},{endStream:!0})}catch{e.close(Qo.constants.NGHTTP2_INTERNAL_ERROR)}c(200,h,g)},d;try{d=this.buildUpstreamHeaders(t),ua(d,n,eo),await qi(this.route,d,this.tokens)}catch(h){u(ZD,h instanceof Error?h.message:"token injection failed");return}let f;try{f=this.upstream().request(d)}catch(h){u(Jf,h instanceof Error?h.message:"upstream unavailable");return}let p=!1,m={};f.on("response",(h)=>{if(p)return;if(p=!0,h["grpc-status"]!==void 0){e.respond(this.frontResponseHeaders(h),{endStream:!0}),c(Number(h[":status"]??200),String(h["grpc-status"]));return}e.respond(this.frontResponseHeaders(h),{waitForTrailers:!0}),e.on("wantTrailers",()=>{try{e.sendTrailers(this.sanitizeTrailers(m))}catch{}c(Number(h[":status"]??200),String(m["grpc-status"]??"0"))}),f.pipe(e,{end:!1}),f.on("end",()=>{try{e.end()}catch{}})}),f.on("trailers",(h)=>{m=h}),f.on("error",(h)=>{if(!p)u(Jf,h.message);else c(502,Jf,h.message),e.close(Qo.constants.NGHTTP2_INTERNAL_ERROR)}),e.on("error",()=>f.destroy()),e.on("close",()=>{if(!l)c(499,eO,"client closed before completion"),f.destroy()}),e.pipe(f)}buildUpstreamHeaders(e){let t={};for(let[n,o]of Object.entries(e)){if(n.startsWith(":")||Lx.has(n.toLowerCase())||o===void 0)continue;t[n]=Array.isArray(o)?o.join(", "):String(o)}let r=new URL(this.route.upstream.url);return t[":method"]=String(e[":method"]??"POST"),t[":path"]=String(e[":path"]??"/"),t[":scheme"]=r.protocol==="https:"?"https":"http",t[":authority"]=r.host,t}frontResponseHeaders(e){let t={":status":e[":status"]??200};for(let[r,n]of Object.entries(e)){if(r.startsWith(":")||Lx.has(r.toLowerCase())||n===void 0)continue;t[r]=n}return t}sanitizeTrailers(e){let t={};for(let[r,n]of Object.entries(e)){if(r.startsWith(":")||n===void 0)continue;t[r]=n}if(t["grpc-status"]===void 0)t["grpc-status"]="0";return t}log(e,t,r="",n=""){this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:e,message:t,pid:0,request_id:r,identity:n})}}function Ix(e,t){let r=e[t];if(typeof r==="string"&&r!=="")return r;if(Array.isArray(r)&&typeof r[0]==="string"&&r[0]!=="")return r[0];return}class Qf{server;tokenEP;grpc=[];boundURL="";suppressed=!1;deps;constructor(e){this.deps=e}get instance(){return this.server}get tokenEndpoint(){return this.tokenEP}get boundTokenURL(){return this.boundURL}get isSuppressed(){return this.suppressed}setSuppressed(e){this.suppressed=e}async start(){if(this.server?.isRunning())return;this.server=new Af(this.deps.cfg().proxy,this.deps.tokens,this.deps.logs,this.deps.bus,this.deps.detector,this.deps.middleware(),(t,r)=>this.deps.ports().get(t)?.[r||"http"],this.deps.spans),await this.server.start();let e=this.deps.cfg();if(e.proxy.token_endpoint.enabled)this.tokenEP=new Lf(e.proxy.token_endpoint.host||"127.0.0.1",e.proxy.token_endpoint.port,this.deps.internalTok(),this.deps.tokens),await this.tokenEP.start(),this.boundURL=`http://127.0.0.1:${this.tokenEP.listenPort()}/token`;for(let t of e.proxy.routes.filter(Wn)){let r=new Xf(t,this.deps.tokens,this.deps.logs,this.deps.bus,this.deps.detector,this.deps.spans);await r.start(),this.grpc.push(r)}this.deps.persistState()}async stop(){await this.server?.stop(),await this.tokenEP?.stop(),await Promise.all(this.grpc.map((e)=>e.stop())),this.grpc=[],this.deps.persistState()}}$t();var tO=3000,Dx=5000,Ox=60;class Zf{timer;cpu=[];mem=[];lastAt=0;deps;constructor(e){this.deps=e}start(){if(this.timer)return;this.timer=setInterval(()=>void this.poll(),tO)}stop(){if(this.timer)clearInterval(this.timer),this.timer=void 0}series(){return{interval_ms:Dx,cpu:[...this.cpu],mem:[...this.mem]}}async poll(){this.recordStatsSample();let e=[];for(let r of this.deps.runtimes().values())if(r.pid>0&&(r.state===Ve||r.state===Lr||r.state===cn))e.push(r.pid);if(e.length===0)return;let t=await nx(e);for(let r of this.deps.runtimes().values()){let n=r.pid>0?t.get(r.pid):void 0;if(n)r.cpuPercent=n.cpuPercent,r.memoryKB=n.memoryKB}}recordStatsSample(){let e=this.deps.clock.unixMs();if(e-this.lastAt<Dx)return;this.lastAt=e;let t=Wf(),r=t.cpuCount>0?t.loadAvg1/t.cpuCount:0,n=t.memTotalKB>0?1-t.memAvailableKB/t.memTotalKB:0;if(this.cpu.push(r),this.mem.push(n),this.cpu.length>Ox)this.cpu.shift();if(this.mem.length>Ox)this.mem.shift()}}function Mc(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Nc(e){return{services:Vi(e.services),level:typeof e.level==="string"?e.level:"",search:typeof e.search==="string"?e.search:"",regex:e.regex===!0,source:typeof e.source==="string"?e.source:"",since:typeof e.since==="string"?e.since:"",until:typeof e.until==="string"?e.until:"",traceId:Oc(e.traceId)??Oc(e.trace_id),requestId:Oc(e.requestId)??Oc(e.request_id),attribute:rO(e.attribute)}}function Oc(e){return typeof e==="string"&&e!==""?e:void 0}function rO(e){if(!Mc(e)||typeof e.key!=="string"||typeof e.value!=="string")return;return{key:e.key,value:e.value}}function Vi(e){if(!Array.isArray(e))return[];return e.filter((t)=>typeof t==="string")}function da(e){if(!Mc(e))return;let t={};for(let[r,n]of Object.entries(e))if(typeof n==="string")t[r]=n;return t}ne();import{createServer as nO}from"net";var oO=2000;class em{server;deps;constructor(e){this.deps=e}get nativeServer(){return this.server}removeStaleSocket(e){if(process.platform==="win32")return;if(this.deps.socketExists(e))try{this.deps.unlinkSocket(e)}catch{this.deps.log("devctl","WARN","unable to remove stale socket")}}listen(e){return new Promise((t,r)=>{this.server=nO((n)=>{this.handleConn(n)}),this.server.on("error",r),this.server.listen(e,()=>t())})}close(){this.server?.close(),this.server=void 0}handleConn(e){let t="",r=[],n=!1,o=()=>{while(r.length>0){let a=r[0],l=e.write(`${JSON.stringify(a)}
|
|
2550
|
+
`);if(r.shift(),!l){n=!0,e.once("drain",()=>{n=!1,o()});return}}},i=(a)=>{if(a.id===void 0&&a.event!==void 0&&r.length>=oO){let c=r.findIndex((u)=>u.id===void 0&&u.event!==void 0);if(c>=0)r.splice(c,1)}if(r.push(a),!n)o()},s=this.deps.subscribe((a)=>i({event:a}));e.on("error",(a)=>{this.deps.log("devctl","WARN",`client connection error: ${I(a)}`)}),e.on("data",(a)=>{t+=a.toString("utf8");let l=t.split(`
|
|
2551
|
+
`);t=l.pop()??"";for(let c of l){if(c.trim()==="")continue;this.dispatchLine(c,i)}}),e.on("close",()=>s())}async dispatchLine(e,t){let r;try{r=JSON.parse(e)}catch{t({error:"invalid json"});return}try{let n=await this.deps.dispatch(r.method??"",r.params);t({id:r.id,result:n})}catch(n){let o=iy(n);t({id:r.id,error:o.error,kind:o.kind,hint:o.hint,service:o.service})}}}ne();Gr();$t();ep();var Mx=1e4;class tm{items=[];start=0;nextSeq=1;max;detector;byTrace=new Map;requestToTrace=new Map;constructor(e=Mx,t){this.max=e>0?e:Mx,this.detector=t}append(e){let t={...e,seq:this.nextSeq};this.nextSeq+=1;let r=this.detector?kl(this.detector,t):t;if(this.items.length<this.max)this.items.push(r);else{let n=this.items[this.start];if(n)this.dropFromIndex(n);this.items[this.start]=r,this.start=(this.start+1)%this.max}return this.index(r),r}getTrace(e){let t=[...this.byTrace.get(e)??[]].sort((o,i)=>o.startUnixNano-i.startUnixNano),r=new Set(t.map((o)=>o.spanId)),n=t.filter((o)=>!o.parentSpanId||!r.has(o.parentSpanId));return{traceId:e,spans:t,roots:n}}envelopeMs(e){let t=this.byTrace.get(e);if(!t||t.length===0)return;let{POSITIVE_INFINITY:r,NEGATIVE_INFINITY:n}=Number;for(let o of t){let i=Math.min(o.startUnixNano,o.endUnixNano||o.startUnixNano),s=Math.max(o.startUnixNano,o.endUnixNano||o.startUnixNano);if(i<r)r=i;if(s>n)n=s}return Math.max(0,(n-r)/qt)}findTraceIdByRequestId(e){return this.requestToTrace.get(e)}recent(e=100){let t=[];return this.forEach((r)=>{t.push(r)}),t.slice(Math.max(0,t.length-e)).reverse()}close(){this.items.length=0,this.byTrace.clear(),this.requestToTrace.clear()}index(e){let t=this.byTrace.get(e.traceId)??[];t.push(e),this.byTrace.set(e.traceId,t);let r=e.attributes[Gt];if(typeof r==="string"&&r!=="")this.requestToTrace.set(r,e.traceId)}dropFromIndex(e){let t=this.byTrace.get(e.traceId);if(!t)return;let r=t.filter((n)=>n.seq!==e.seq);if(r.length===0){this.byTrace.delete(e.traceId);let n=e.attributes[Gt];if(typeof n==="string"&&this.requestToTrace.get(n)===e.traceId)this.requestToTrace.delete(n)}else this.byTrace.set(e.traceId,r)}forEach(e){let t=this.items.length;for(let r=0;r<t;r+=1){let n=this.items[(this.start+r)%t];if(n)e(n)}}}Ke();import{createServer as dO}from"http";vl();Ci();function Nx(e){if(typeof e==="string"){let t=e.replace(/^span_kind_/i,"").toLowerCase();if(t==="server")return"server";if(t==="client")return"client";if(t==="producer")return"producer";if(t==="consumer")return"consumer";return"internal"}if(e===2)return"server";if(e===3)return"client";if(e===4)return"producer";if(e===5)return"consumer";if(e===1)return"internal";return"internal"}function Fx(e){if(typeof e!=="object"||e===null)return{code:"unset"};let t=e,r=typeof t.message==="string"&&t.message!==""?t.message:void 0;if(t.code===2||t.code==="STATUS_CODE_ERROR"||t.code==="error")return{code:"error",message:r};if(t.code===1||t.code==="STATUS_CODE_OK"||t.code==="ok")return{code:"ok",message:r};return{code:"unset",message:r}}function $x(e,t){if(!Le(e)||!Array.isArray(e.resourceLogs))return[];return e.resourceLogs.flatMap((r)=>iO(r,t))}function Hx(e,t){if(!Le(e)||!Array.isArray(e.resourceSpans))return[];return e.resourceSpans.flatMap((r)=>aO(r,t))}function iO(e,t){if(!Le(e)||!Array.isArray(e.scopeLogs))return[];let r=Xd(e.resource,t),n=r["service.name"];return e.scopeLogs.flatMap((o)=>sO(o,r,n))}function sO(e,t,r){if(!Le(e)||!Array.isArray(e.logRecords))return[];let n=Qd(e.scope),o=typeof t?.["process.pid"]==="number"?t["process.pid"]:0;return e.logRecords.flatMap((i)=>{if(!Le(i)||t===void 0)return[];let s=lv(i.severityNumber);return[{service:r,source:"otlp",pid:o,body:i.body===void 0?"":Ti(i.body),attributes:jn(i.attributes),severityNumber:s,severityText:typeof i.severityText==="string"&&i.severityText!==""?i.severityText:ki(s),traceId:rm(i.traceId),spanId:Fc(i.spanId),traceFlags:typeof i.flags==="number"?i.flags:void 0,timeUnixNano:nn(i.timeUnixNano),observedTimeUnixNano:nn(i.observedTimeUnixNano),resource:t,scope:n}]})}function aO(e,t){if(!Le(e)||!Array.isArray(e.scopeSpans))return[];let r=Xd(e.resource,t);return e.scopeSpans.flatMap((n)=>lO(n,r))}function lO(e,t){if(!Le(e)||!Array.isArray(e.spans))return[];let r=Qd(e.scope);return e.spans.flatMap((n)=>{if(!Le(n))return[];let o=rm(n.traceId),i=Fc(n.spanId);if(!o||!i)return[];return[{traceId:o,spanId:i,parentSpanId:Fc(n.parentSpanId),name:typeof n.name==="string"&&n.name!==""?n.name:"span",kind:Nx(n.kind),startUnixNano:nn(n.startTimeUnixNano)??0,endUnixNano:nn(n.endTimeUnixNano)??0,status:Fx(n.status),attributes:jn(n.attributes),events:cO(n.events),links:uO(n.links),resource:t,scope:r}]})}function cO(e){if(!Array.isArray(e))return[];return e.flatMap((t)=>{if(!Le(t)||typeof t.name!=="string")return[];return[{timeUnixNano:nn(t.timeUnixNano)??0,name:t.name,attributes:jn(t.attributes)}]})}function uO(e){if(!Array.isArray(e))return[];return e.flatMap((t)=>{if(!Le(t))return[];let r=rm(t.traceId),n=Fc(t.spanId);if(!r||!n)return[];return[{traceId:r,spanId:n}]})}function rm(e){if(typeof e!=="string")return;return sr(e)?e.toLowerCase():void 0}function Fc(e){if(typeof e!=="string")return;return Sn(e)?e.toLowerCase():void 0}ne();Ke();var pO="application/json",fO=4194304;class nm{server;running=!1;addr="";opts;constructor(e){this.opts=e}isRunning(){return this.running}address(){return this.addr}listenPort(){let e=this.server?.address();if(e&&typeof e==="object")return e.port;return this.opts.port}endpoint(){return`http://${this.opts.host||Ot}:${this.listenPort()}`}start(){let e=this.opts.host||Ot;if(!_t(e))return Promise.reject(T($e,"OTLP receiver must bind to a loopback address"));return new Promise((t,r)=>{this.server=dO((n,o)=>{this.handle(n,o)}),this.server.on("error",(n)=>r(ge($e,`unable to listen on ${e}:${this.opts.port}`,n))),this.server.listen(this.opts.port,e,()=>{let n=this.server?.address(),o=n&&typeof n==="object"?n.port:this.opts.port;this.addr=`${e}:${o}`,this.running=!0,t()})})}stop(){let e=this.server;if(this.running=!1,this.server=void 0,!e)return Promise.resolve();return new Promise((t)=>{e.close(()=>t())})}async handle(e,t){let n=(e.url??"/").split("?")[0]??"/";if(e.method!=="POST"){pa(t,405,{error:"method not allowed"});return}let o;try{o=JSON.parse(await mO(e))}catch{pa(t,400,{error:"invalid json"});return}let i=this.opts.fallbackService??"otlp";if(n==="/v1/logs"){for(let s of $x(o,i))this.opts.logs.append(s);pa(t,200,{partialSuccess:{}});return}if(n==="/v1/traces"){for(let s of Hx(o,i))this.opts.spans.append(s);pa(t,200,{partialSuccess:{}});return}pa(t,404,{error:"not found"})}}function pa(e,t,r){let n=JSON.stringify(r);e.writeHead(t,{"content-type":pO,"content-length":Buffer.byteLength(n)}),e.end(n)}function mO(e){return new Promise((t,r)=>{let n=[],o=0;e.on("data",(i)=>{if(o+=i.length,o>fO){e.destroy(),r(Error("payload too large"));return}n.push(i)}),e.on("end",()=>t(Buffer.concat(n).toString("utf8"))),e.on("error",r)})}class om{server;deps;constructor(e){this.deps=e}endpoint(){if(!this.server?.isRunning())return"";return this.server.endpoint()}async start(){let e=this.deps.cfg().telemetry.otlp;if(!e.enabled)return;if(this.server?.isRunning())return;this.server=new nm({host:e.listen.host||Ot,port:e.listen.port,logs:this.deps.logs,spans:this.deps.spans}),await this.server.start(),this.deps.log("devctl","INFO",`OTLP/HTTP+JSON listening on ${this.server.address()}`)}async stop(){await this.server?.stop(),this.server=void 0}}class im{cfg;sessionID;internalTok;bus;logs;spans;procs;tokens;detector;env;proxy;telemetry;mcp;web;resources;runtimes=new Map;ports=new Map;lock;shuttingDown=!1;detached=!1;identity;rpc;detectGoogleFn;inspectProcessFn;processAliveFn;acquireLockFn;socketExistsFn;unlinkSocketFn;registry;restartRequired=[];processMeta=new Map;configWatcher;watchTimer;setupMode;serviceWatchers;pluginMtimes=new Map;orchestrator;commands;clock;fs;healthCheckers;constructor(e,t){this.healthCheckers=t.healthCheckers,this.cfg=e,this.sessionID=t.sessionID,this.internalTok=Ld(),this.clock=t.clock,this.fs=t.fs,this.bus=t.bus,this.detectGoogleFn=t.detectGoogle,this.inspectProcessFn=t.inspectProcess,this.processAliveFn=t.processAlive,this.acquireLockFn=t.acquireLock,this.socketExistsFn=t.socketExists,this.unlinkSocketFn=t.unlinkSocket,this.detector=t.detector,this.logs=t.logs,this.spans=new tm(void 0,this.detector),this.procs=t.procs,this.orchestrator=t.orchestrator,this.tokens=t.tokens,this.telemetry=new om({cfg:()=>this.cfg,logs:this.logs,spans:this.spans,log:(r,n,o)=>this.log(r,n,o)}),this.proxy=new Qf({cfg:()=>this.cfg,ports:()=>this.ports,tokens:this.tokens,logs:this.logs,spans:this.spans,bus:this.bus,detector:this.detector,internalTok:()=>this.internalTok,middleware:()=>this.registry?.proxyMiddleware??[],persistState:()=>this.persistState()}),this.env=new jf({cfg:()=>this.cfg,ports:()=>this.ports,userEmail:()=>this.identity.identityCache.user,proxy:()=>this.proxy.instance,tokenEndpoint:()=>this.proxy.tokenEndpoint,boundTokenURL:()=>this.proxy.boundTokenURL,internalTok:()=>this.internalTok,tokens:this.tokens,environmentSources:()=>this.registry?.environmentSources,otlpEndpoint:()=>this.telemetry.endpoint()}),this.mcp=new Vf({repoRoot:()=>this.cfg.repoRoot,createListener:t.createMcpListener,hostApi:()=>this.asMcpHost(),isKnownTool:t.isKnownTool,log:(r,n,o)=>this.log(r,n,o),persistState:()=>this.persistState()}),this.web=new Yf({cfg:()=>this.cfg,createListener:t.createWebListener,hostApi:()=>this.asMcpHost(),log:(r,n,o)=>this.log(r,n,o)}),this.resources=new Zf({clock:this.clock,runtimes:()=>this.runtimes}),this.identity=new qf({cfg:()=>this.cfg,tokens:this.tokens,detectGoogle:(r)=>this.detectGoogleFn(r),clock:this.clock,bus:this.bus,logs:this.logs,persistState:()=>this.persistState(),fail:(r,n)=>this.fail(r,n),log:(r,n,o)=>this.log(r,n,o),identityProviders:()=>this.registry?.identityProviders}),this.rpc=new em({dispatch:(r,n)=>this.dispatch(r,n),subscribe:(r,n)=>this.bus.subscribe(r,n),log:(r,n,o)=>this.log(r,n,o),socketExists:(r)=>this.socketExistsFn(r),unlinkSocket:(r)=>this.unlinkSocketFn(r)}),this.setupMode=!this.fs.exists(e.configPath);for(let r of Object.keys(e.services))this.runtimes.set(r,Qs(r));this.orchestrator.bind(this.lifecycleSession()),this.commands=t.createCommands(this),this.serviceWatchers=new $f({repoRoot:()=>this.cfg.repoRoot,log:(r,n,o)=>this.log(r,n,o),isActive:(r)=>this.orchestrator.serviceIsActive(r),restart:(r)=>this.restart([r],{auto:!0})})}get profile(){return this.env.profile}set profile(e){this.env.profile=e}get profileEnv(){return this.env.profileEnv}set profileEnv(e){this.env.profileEnv=e}get clientEnv(){return this.env.clientEnv}get serviceProfile(){return this.env.serviceProfile}get serviceProfileEnv(){return this.env.serviceProfileEnv}snapshotHost(){let e=this;return{get sessionID(){return e.sessionID},get cfg(){return e.cfg},get profile(){return e.profile},get runtimes(){return e.runtimes},get ports(){return e.ports},get serviceProfile(){return e.serviceProfile},get clientEnv(){return e.clientEnv},get proxy(){return e.proxy.instance},get mcp(){return e.mcp.instance},get web(){return e.web.instance},get mcpToken(){return e.mcp.token},get mcpDisabledTools(){return e.mcp.disabledTools},get identityCache(){return e.identity.identityCache},get serviceAccountStatus(){return e.identity.serviceAccountStatus},get credentialEntries(){return e.identity.credentialEntries},get detached(){return e.detached},get setupMode(){return e.setupMode},get restartRequired(){return e.restartRequired},get statsSeries(){return e.resources.series()},logs:{snapshot:()=>e.logs.snapshot()},tokens:{storeBackend:()=>e.tokens.storeBackend()},traceDurationMs:(t)=>e.spans.envelopeMs(t)}}reloadHost(){let e=this;return{get cfg(){return e.cfg},set cfg(t){e.cfg=t},get setupMode(){return e.setupMode},set setupMode(t){e.setupMode=t},get configWatcher(){return e.configWatcher},set configWatcher(t){e.configWatcher=t},get watchTimer(){return e.watchTimer},set watchTimer(t){e.watchTimer=t},get restartRequired(){return e.restartRequired},set restartRequired(t){e.restartRequired=t},get fs(){return e.fs},get registry(){return e.registry},set registry(t){e.registry=t},get pluginMtimes(){return e.pluginMtimes},set pluginMtimes(t){e.pluginMtimes=t},get detector(){return e.detector},get bus(){return e.bus},get orchestrator(){return e.orchestrator},get runtimes(){return e.runtimes},get tokens(){return e.tokens},get logs(){return e.logs},get proxy(){return e.proxy.instance},persistState:()=>e.persistState(),log:(t,r,n)=>e.log(t,r,n),refreshIdentity:()=>e.refreshIdentity(),startProxy:()=>e.startProxy(),stopProxy:()=>e.stopProxy(),reload:()=>e.reload(),forgetService:(t)=>e.forgetService(t),syncServiceWatchers:()=>e.serviceWatchers.sync(e.cfg.services)}}recoverHost(){let e=this;return{get cfg(){return e.cfg},set cfg(t){e.cfg=t},get profile(){return e.profile},set profile(t){e.profile=t},get profileEnv(){return e.profileEnv},set profileEnv(t){e.profileEnv=t},get runtimes(){return e.runtimes},get ports(){return e.ports},get processMeta(){return e.processMeta},get serviceProfile(){return e.serviceProfile},get serviceProfileEnv(){return e.serviceProfileEnv},get orchestrator(){return e.orchestrator},get procs(){return e.procs},logs:{append:(t)=>e.logs.append(t)},get clock(){return e.clock},get tokens(){return e.tokens},get registry(){return e.registry},get proxy(){return e.proxy.instance},get tokenEP(){return e.proxy.tokenEndpoint},get boundTokenURL(){return e.proxy.boundTokenURL},get internalTok(){return e.internalTok},get bus(){return e.bus},inspectProcessFn:(t)=>e.inspectProcessFn(t),processAliveFn:(t)=>e.processAliveFn(t),serviceWorkDir:(t)=>e.serviceWorkDir(t),persistState:()=>e.persistState(),setState:(t,r,n,o,i)=>e.setState(t,r,n,o,i),log:(t,r,n)=>e.log(t,r,n)}}async run(){let e=Za(this.cfg.repoRoot);this.lock=this.acquireLockFn(this.cfg.repoRoot,e),this.rpc.removeStaleSocket(e),this.registry=await Ic(this.cfg.plugins.map((t)=>t.path),this.cfg.repoRoot),this.pluginMtimes=Df(this.cfg.plugins.map((t)=>t.path),this.cfg.repoRoot);for(let t of this.registry.loadErrors)this.log("devctl","ERROR",`plugin ${t.path} skipped: ${t.message}`);If(this.reloadHost()),Of(this.registry,this.cfg),Mf(this.registry,this.cfg),Nf(this.registry,this.cfg),await this.recoverSession(),this.serviceWatchers.sync(this.cfg.services),Ff(this.reloadHost()),this.persistState(),this.log("devctl","INFO",`supervisor started session=${this.sessionID}`),this.refreshIdentity(),this.resources.start(),await this.telemetry.start(),await this.web.start(),await this.mcp.bootFromPreferences(),this.rpc.removeStaleSocket(e),await this.rpc.listen(e)}async dispatch(e,t){let r=Mc(t)?t:{};switch(e){case"ping":return{session:this.sessionID,version:Xt,protocol:Ys};case"start":return this.commands.startService.execute({services:Vi(r.services),profile:typeof r.profile==="string"&&r.profile!==""?r.profile:void 0,detach:r.detach===!0,client_env:da(r.client_env)});case"stop":return await this.commands.stopService.execute(Vi(r.services)),null;case"restart":return await this.commands.restartService.execute(Vi(r.services),{cascade:r.cascade===!0,clientEnv:da(r.client_env)}),null;case"run_task":return this.runTask(typeof r.name==="string"?r.name:"",da(r.client_env)??{});case"exec":return this.execService(typeof r.service==="string"?r.service:"",Vi(r.command),da(r.client_env)??{},r.print_env===!0);case"auth_refresh":return await this.commands.refreshIdentity.execute(),this.snapshot().identity;case"status":return this.snapshot();case"logs":return await this.queryLogs({...Nc(r),export:typeof r.export==="string"?r.export:""});case"logs_page":return await this.queryLogsPage({...Nc(r),cursor:typeof r.cursor==="string"?r.cursor:void 0,direction:r.direction==="forward"?"forward":"backward",limit:typeof r.limit==="number"?r.limit:void 0});case"logs_stats":return await this.queryLogsFacets(Nc(r));case"get_trace":return await this.queryTrace(typeof r.trace_id==="string"?r.trace_id:typeof r.traceId==="string"?r.traceId:"");case"trace_request":return await this.queryTraceByRequest(typeof r.request_id==="string"?r.request_id:typeof r.requestId==="string"?r.requestId:"");case"proxy_start":return this.proxy.setSuppressed(!1),await this.commands.startProxy.execute(),null;case"proxy_stop":return this.proxy.setSuppressed(!0),await this.commands.stopProxy.execute(),null;case"mcp_start":{let o=typeof r.port==="number"?r.port:void 0;return await this.startMcp(o??vi(this.cfg.repoRoot).mcp_port),null}case"mcp_stop":return await this.stopMcp(),null;case"web_start":return await this.web.startExplicit(),null;case"web_stop":return await this.web.stop(),null;case"mcp_set_tools":{let o=Array.isArray(r.disabled)?r.disabled.filter((i)=>typeof i==="string"):[];return this.setMcpDisabledTools(o),{disabled_tools:[...this.mcp.disabledTools]}}case"reload":return this.commands.reloadConfig.execute();case"config_snapshot":return this.cfg;case"auth_invalidate":return this.tokens.invalidate(),null;case"shutdown":let n=typeof r.stop_services==="boolean"?r.stop_services:Hl(this.cfg.shutdown);return setTimeout(()=>{this.shutdown(n)},50),null;default:throw T($e,`unknown method ${e}`)}}isDetached(){return this.detached}async start(e){return this.orchestrator.start(e)}lifecycleSession(){let e=this;return{get cfg(){return e.cfg},get profile(){return e.profile},set profile(t){e.profile=t},get profileEnv(){return e.profileEnv},set profileEnv(t){e.profileEnv=t},get detached(){return e.detached},set detached(t){e.detached=t},get proxySuppressed(){return e.proxy.isSuppressed},get runtimes(){return e.runtimes},get ports(){return e.ports},get clientEnv(){return e.clientEnv},get serviceProfile(){return e.serviceProfile},get serviceProfileEnv(){return e.serviceProfileEnv},healthCheckers:{lookup:(t)=>{let r=e.registry?.healthChecks.find((n)=>n.name.toLowerCase()===t.toLowerCase());return r?{check:async(n,o)=>{let i=await r.check(n,o);return{...i,status:i.status}}}:e.healthCheckers.lookup(t)}},logs:{append:(t)=>e.logs.append(t)},bus:e.bus,processMeta:e.processMeta,get containerPrefix(){return`devctl-${Tr(e.cfg.repoRoot)}-`},prepareServiceIdentity:(t,r)=>e.identity.prepareServiceIdentity(t,r),resolveServiceExecution:(t,r,n,o,i,s)=>e.env.resolveServiceExecution(t,r,n,o,i,s),detectGoogle:(t)=>e.detectGoogleFn(t),startProxy:()=>e.startProxy(),fail:(t,r)=>e.fail(t,r),claimIfAlreadyUp:(t)=>e.claimIfAlreadyUp(t),assignPendingPorts:(t)=>e.assignPendingPorts(t),setState:(t,r,n,o,i)=>e.setState(t,r,n,o,i),persistState:()=>e.persistState(),log:(t,r,n)=>e.log(t,r,n),releasePorts:(t)=>e.releasePorts(t),forgetService:(t)=>e.forgetService(t),clearRestartRequired:(t)=>e.dropRestartRequired(t)}}async assignPendingPorts(e){try{let t=await ly(this.cfg,e,Object.fromEntries(this.ports));for(let[r,n]of Object.entries(t)){this.ports.set(r,n);let o=Object.entries(n).map(([i,s])=>`${i}=${s}`).join(", ");this.log(r,"INFO",`assigned ports: ${o||"none"}`)}}catch(t){if(t instanceof et&&t.service!=="")await this.fail(t.service,t);else this.log("devctl","ERROR",I(t));throw t}}async runTask(e,t){let r=this.cfg.tasks[e];if(!r)throw T($e,`unknown task ${e}`);if(r.dependencies.length>0)await this.start({services:r.dependencies,client_env:t});let n={...qn(),command:r.command,shell:r.shell,working_dir:r.working_dir,dependencies:r.dependencies,environment:r.environment},{env:o,workDir:i}=await this.env.resolveTaskEnvironment(e,n,t),s=await this.runTransient(`task:${e}`,r.command,r.shell,i,o);return{task:e,...s}}async execService(e,t,r,n=!1){let o=this.cfg.services[e];if(!o)throw T(Pi,`unknown service ${e}`);let i=this.env.serviceProfile.get(e)??this.env.profile,s=i!==""?Ko(this.cfg,i):this.env.profileEnv,{env:a,workDir:l}=await this.env.resolveServiceExecution(e,o,i,s,r,!o.container);if(n)return{service:e,code:0,stdout:"",stderr:"",environment:a};if(t.length===0)throw T($e,"exec command is required");let c=await this.runTransient(`${e}:exec`,{args:t,shell:!1},!1,l,a);return{service:e,...c}}async runTransient(e,t,r,n,o){if(Gn(t))return{code:0,stdout:"",stderr:""};this.log(e,"INFO",`running ${t.args.join(" ")}`);let i=await this.procs.runOnce({name:e,args:[...t.args],shell:r||t.shell,workDir:n,env:o,graceMs:Vn(this.cfg.shutdown)*1000,onLine:(s,a)=>this.logs.append({timestamp:this.clock.isoNow(),service:e,source:s,stream:s,level:"",message:a,pid:0})});if(i.code!==0)throw T(Ge,`${e} exited with code ${i.code}`);return i}serviceWorkDir(e){return this.env.serviceWorkDir(e)}async claimIfAlreadyUp(e){return cx(this.recoverHost(),e)}async recoverSession(){return ux(this.recoverHost())}async stop(e){return this.orchestrator.stop(e)}forgetService(e){this.orchestrator.health.forget(e),this.runtimes.delete(e),this.ports.delete(e),this.processMeta.delete(e),this.env.forget(e)}async restart(e,t){let r=t?.cascade===!0?Go(this.cfg,e):e;await this.orchestrator.restart(e,t),this.dropRestartRequired(r)}dropRestartRequired(e){if(e.length===0)return;let t=new Set(e);this.restartRequired=this.restartRequired.filter((r)=>!t.has(r))}async startProxy(){return this.proxy.start()}async stopProxy(){return this.proxy.stop()}async startMcp(e){return this.mcp.start(e)}setMcpDisabledTools(e){this.mcp.setDisabledTools(e)}async stopMcp(){return this.mcp.stop()}asMcpHost(){return{status:()=>this.commands.getServiceStatus.execute(),logsPage:(e)=>this.queryLogsPage(e),config:()=>this.cfg,validateConfigText:(e)=>Bs(this.cfg.repoRoot,this.cfg.configPath,e),start:(e)=>this.commands.startService.execute(e),stop:(e)=>this.commands.stopService.execute(e),restart:(e,t)=>this.commands.restartService.execute(e,{cascade:t}),reload:()=>this.commands.reloadConfig.execute(),doctor:async()=>{for(let e of ln(this.cfg))await this.identity.probeServiceAccount(e);return this.commands.runDoctor.execute(this.cfg)},exec:(e,t,r)=>this.execService(e,t,void 0,r),runTask:(e)=>this.runTask(e,{}),startProxy:()=>this.startProxy(),stopProxy:()=>this.stopProxy(),getTrace:(e)=>this.queryTrace(e),traceRequest:(e)=>this.queryTraceByRequest(e)}}async reload(){return vx(this.reloadHost())}async shutdown(e){if(this.shuttingDown)return;if(this.shuttingDown=!0,this.persistState(),e)await this.stop([]);if(this.orchestrator.health.dispose(),await this.stopProxy(),await this.telemetry.stop(),this.spans.close(),await this.stopMcp(),await this.web.stop(),this.configWatcher?.close(),this.serviceWatchers.close(),this.watchTimer)clearTimeout(this.watchTimer);this.resources.stop(),this.rpc.close(),this.lock?.release(),await this.logs.close()}snapshot(){return Sx(this.snapshotHost())}async refreshIdentity(e){return this.identity.refreshIdentity(e)}async queryLogs(e){let t=this.logFilter(e),r=await this.logs.query(t);if(e.export)await this.logs.exportTo(e.export,t);return{events:r}}async queryLogsPage(e){return this.logs.queryPage(this.logFilter(e),{cursor:e.cursor,direction:e.direction,limit:e.limit})}async queryLogsFacets(e){return this.logs.queryFacets(this.logFilter(e))}async queryTrace(e){let t=this.spans.getTrace(e),r=e===""?[]:await this.logs.query({traceId:e});return{traceId:e,tree:t,events:r}}async queryTraceByRequest(e){let r=this.spans.findTraceIdByRequestId(e)??(sr(e)?e.toLowerCase():"");return{...await this.queryTrace(r),requestId:e}}logFilter(e){return{services:e.services,level:e.level,search:e.search,regex:e.regex,source:e.source,since:e.since,until:e.until,traceId:e.traceId,requestId:e.requestId,attribute:e.attribute}}subscribe(e){return this.bus.subscribe(e)}formatStatus(){return Cx(this.snapshot())}setState(e,t,r,n,o){let i=this.runtimes.get(e)??Qs(e);if(!aa(i.state,t))this.log(e,"WARN",`unusual lifecycle ${i.state} \u2192 ${t}`);i.state=t,i.health=r,i.pid=n,i.last_error=o;let s=t===Ve||t===Lr||t===cn;if(i.startTime=s?this.processMeta.get(e)?.startTime.toISOString():void 0,!s)i.cpuPercent=void 0,i.memoryKB=void 0;this.runtimes.set(e,i),this.bus.publish(Ce(Xg,e,{state:t,health:r,pid:n}))}async releasePorts(e){let t=this.ports.get(e);if(!t)return;let r=this.cfg.services[e];if(r?.container){this.ports.delete(e);return}let n=this.processMeta.get(e);for(let o of Object.values(t)){let i=await Lo(o);if(!i||i.pid===process.pid)continue;if(r){let s=await this.inspectProcessFn(i.pid);if(!(s!==void 0&&s.command!==""&&sa({args:n?.command??[...r.command.args],workDir:n?.cwd??this.serviceWorkDir(r),startTime:n?.startTime},s))){this.log(e,"WARN",`port ${o} is held by pid ${i.pid}, which does not match ${e}; leaving it running`);continue}}try{await Il(i),this.log(e,"INFO",`released port ${o} (pid ${i.pid})`)}catch(s){this.log(e,"WARN",I(s))}}this.ports.delete(e)}async fail(e,t){this.orchestrator.health.clearHealthWatch(e),this.orchestrator.health.clearRestartTimer(e),this.orchestrator.health.bumpGeneration(e),this.setState(e,bt,Ft,0,I(t));try{await this.procs.stop(e,Vn(this.cfg.shutdown)*1000)}catch(r){this.log(e,"WARN",I(r))}this.bus.publish(Ce(ll,e,{error:I(t)})),this.log(e,"ERROR",I(t)),this.persistState()}log(e,t,r){this.logs.append({timestamp:this.clock.isoNow(),service:e,source:"devctl",level:t,message:r,pid:0})}persistState(){let e=[];for(let t of this.procs.all()){let r=this.processMeta.get(t.name);e.push({name:t.name,pid:t.pid,command:r?.command??t.args,cwd:r?.cwd??t.workDir,startTime:(r?.startTime??t.startTime).toISOString(),ports:this.ports.get(t.name)??{},profile:this.serviceProfile.get(t.name)??this.profile})}Wg(this.cfg.repoRoot,{session_id:this.sessionID,repo_root:this.cfg.repoRoot,profile:this.profile,processes:e})}}var jx=500,hO=1e4,gO=2000,vO=new URL("./log-worker.ts",import.meta.url);class Bx{worker;bus;pending=new Map;nextId=1;stats={total:0,errors:0,counts:{},seen:0,seenErrors:0};dead=!1;readySettled=!1;ready;resolveReady=()=>{return};rejectReady=()=>{return};constructor(e,t,r={}){this.bus=t,this.ready=new Promise((n,o)=>{this.resolveReady=n,this.rejectReady=o}),this.worker=new Worker(r.script??vO,{name:"devctl-logs"}),this.worker.addEventListener("message",(n)=>{this.onMessage(n.data)}),this.worker.addEventListener("error",(n)=>{this.markDead(Error(n.message||"log worker failed"))}),this.post({type:"init",config:e})}waitUntilReady(e=jx){if(this.dead)return Promise.reject(Error("log worker is not running"));if(this.readySettled)return Promise.resolve();return new Promise((t,r)=>{let n=setTimeout(()=>{this.markDead(Error("log worker init timed out"))},e);this.ready.then(()=>{clearTimeout(n),t()},(o)=>{clearTimeout(n),r(o)})})}append(e){if(this.dead)return;try{this.post({type:"append",event:e})}catch{}}async query(e){let t=await this.rpc({type:"query",filter:e});if(!Array.isArray(t))throw Error("log worker query returned a non-array");return t}async queryPage(e,t){let r=await this.rpc({type:"queryPage",filter:e,page:t});if(!yO(r))throw Error("log worker queryPage returned an unexpected payload");return r}async queryFacets(e){let t=await this.rpc({type:"queryFacets",filter:e});if(!bO(t))throw Error("log worker queryFacets returned an unexpected payload");return t}snapshot(){return this.stats}async exportTo(e,t){await this.rpc({type:"exportTo",path:e,filter:t})}setParsers(e,t){if(this.dead)return;this.post({type:"setPluginPaths",paths:[...t??[]]})}setSecrets(e,t){if(this.dead)return;this.post({type:"setSecrets",extraMarkers:e,extraPatterns:t})}async close(){if(this.dead)return;try{await this.rpc({type:"close"},gO)}catch{}finally{this.markDead(Error("log worker closed"))}}rpc(e,t=hO){this.assertAlive();let r=this.nextId;this.nextId+=1;let n={...e,id:r};return new Promise((o,i)=>{let s=setTimeout(()=>{this.markDead(Error(`log worker timed out (${e.type})`))},t);this.pending.set(r,{resolve:o,reject:i,timer:s});try{this.post(n)}catch(a){clearTimeout(s),this.pending.delete(r),i(a instanceof Error?a:Error(String(a)))}})}post(e){this.assertAlive(),this.worker.postMessage(e)}onMessage(e){if(e.type==="ready"){this.settleReady();return}if(e.type==="appended"){this.stats=e.stats,this.bus?.publish(Ce(yi,e.event.service,{event:e.event,level:e.event.severityText}));return}let t=this.pending.get(e.id);if(!t)return;if(this.pending.delete(e.id),clearTimeout(t.timer),e.type==="error"){t.reject(Error(e.error));return}t.resolve(e.result)}settleReady(){if(this.readySettled||this.dead)return;this.readySettled=!0,this.resolveReady()}assertAlive(){if(this.dead)throw Error("log worker is not running")}markDead(e){if(this.dead)return;if(this.dead=!0,!this.readySettled)this.readySettled=!0,this.rejectReady(e);this.rejectAll(e);try{this.worker.terminate()}catch{}}rejectAll(e){for(let t of this.pending.values())clearTimeout(t.timer),t.reject(e);this.pending.clear()}}function yO(e){if(e===null||Array.isArray(e)||!("events"in e))return!1;return Array.isArray(e.events)}function bO(e){return e!==null&&!Array.isArray(e)&&"byService"in e}function Ux(e,t,r){return Jv(new yp(e.max,t,r,e.persist,e.directory,e.sessionID,e.retentionDays,e.maxSessionLogs))}async function Wx(e,t,r,n={}){if(n.standalone??Bun.isStandaloneExecutable===!0)return{logs:Ux(e,t,r),usingWorker:!1};try{let i=new Bx(e,t,{script:n.script});return await i.waitUntilReady(n.initTimeoutMs??jx),{logs:i,usingWorker:!0}}catch{return{logs:Ux(e,t,r),usingWorker:!1}}}To();import{createServer as BO}from"http";ne();Ji();var WO="2025-03-26",l0="2.0",o0=-32700,i0=-32600,zO=-32601,s0=-32602,qO=-32603;function GO(e){return e!==""&&_t(e)}class fm{server;running=!1;addr="";boundPort=0;opts;constructor(e){this.opts=e}disabled(){return this.opts.disabledTools?.()??[]}address(){return this.addr}listenPort(){return this.boundPort}isRunning(){return this.running}emit(e,t){this.opts.onEvent?.(e,t)}start(){if(!GO(this.opts.host))return Promise.reject(T($e,`refusing to bind MCP to ${this.opts.host}`));return new Promise((e,t)=>{this.server=BO((r,n)=>{this.serve(r,n)}),this.server.on("error",(r)=>t(ge($e,`unable to listen on ${this.opts.host}:${this.opts.port}`,r))),this.server.listen(this.opts.port,this.opts.host,()=>{let r=this.server?.address();this.boundPort=typeof r==="object"&&r?r.port:this.opts.port,this.addr=`${this.opts.host}:${this.boundPort}`,this.running=!0,this.emit("INFO",`listening on ${this.addr}`),e()})})}stop(){let e=this.server,t=this.running;if(!e)return this.running=!1,Promise.resolve();return new Promise((r)=>{e.close(()=>{if(this.running=!1,this.addr="",this.boundPort=0,this.server=void 0,t)this.emit("INFO","stopped");r()})})}async serve(e,t){if(e.method==="OPTIONS"){t.writeHead(204,va()),t.end();return}if(!this.authorized(e)){this.emit("WARN",`rejected unauthorized request from ${a0(e)}`),Xi(t,401,{error:"unauthorized"});return}if(VO(e)!=="/mcp"){Xi(t,404,{error:"not found"});return}if(e.method==="GET"||e.method==="DELETE"){t.writeHead(405,{Allow:"POST, OPTIONS",...va()}),t.end();return}if(e.method!=="POST"){t.writeHead(405,{Allow:"POST, OPTIONS",...va()}),t.end();return}let n;try{n=await YO(e)}catch(a){Xi(t,400,ha(null,o0,a instanceof Error?a.message:"invalid body"));return}let o;try{o=JSON.parse(n)}catch{Xi(t,400,ha(null,o0,"parse error"));return}let i=a0(e);if(Array.isArray(o)){let a=[];for(let l of o){let c=await this.dispatch(l,i);if(c!==void 0)a.push(c)}Xi(t,200,a);return}let s=await this.dispatch(o,i);if(s===void 0){t.writeHead(202,va()),t.end();return}Xi(t,200,s)}authorized(e){if(this.opts.token==="")return!0;return(e.headers.authorization??"")===`Bearer ${this.opts.token}`}async dispatch(e,t){if(!zc(e))return ha(null,i0,"invalid request");let r=e,n=r.id??null,o=r.id===void 0;if(r.method===void 0||r.method==="")return o?void 0:ha(n,i0,"missing method");try{let i=await this.handleMethod(r.method,zc(r.params)?r.params:{},t);if(o)return;return{jsonrpc:l0,id:n,result:i}}catch(i){if(o)return;let s=i instanceof ga?i.code:qO,a=i instanceof Error?i.message:"internal error";return this.emit("WARN",`rpc error method=${r.method} addr=${t}: ${a}`),ha(n,s,a)}}async handleMethod(e,t,r){switch(e){case"initialize":{let n=KO(t);return this.emit("INFO",`client connected addr=${r}${n?` (${n})`:""}`),{protocolVersion:WO,capabilities:{tools:{},resources:{}},serverInfo:{name:"devctl",version:Xt}}}case"notifications/initialized":case"ping":return{};case"tools/list":return{tools:Zx(this.disabled()).map((n)=>({name:n.name,description:n.description,inputSchema:n.inputSchema}))};case"tools/call":return this.callTool(t);case"resources/list":return{resources:am.map((n)=>({uri:n,name:n.replace("devctl://",""),mimeType:"application/json"}))};case"resources/read":return this.readResource(t);default:throw new ga(zO,`method not found: ${e}`)}}async callTool(e){let t=typeof e.name==="string"?e.name:"";if(t==="")throw new ga(s0,"tool name is required");if(Hc(t)&&!no(t,this.disabled())){let o=`tool ${t} is disabled in devctl's MCP settings`;return this.emit("WARN",`tool call rejected name=${t}: disabled`),{content:[{type:"text",text:o}],isError:!0}}let r=zc(e.arguments)?e.arguments:{},n=Date.now();try{let o=await Wc(this.opts.hostApi,t,r);return this.emit("INFO",`tool call name=${t} duration=${Date.now()-n}ms`),{content:[{type:"text",text:JSON.stringify(o,null,2)}]}}catch(o){let i=o instanceof Error?o.message:"tool failed";return this.emit("WARN",`tool call failed name=${t} duration=${Date.now()-n}ms: ${i}`),{content:[{type:"text",text:i}],isError:!0}}}async readResource(e){let t=typeof e.uri==="string"?e.uri:"";if(!r0(t))throw new ga(s0,`unknown resource ${t}`);let r=await n0(this.opts.hostApi,t);return this.emit("INFO",`resource read uri=${t}`),{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(r,null,2)}]}}}function KO(e){let t=e.clientInfo;if(!zc(t))return"";let r=typeof t.name==="string"?t.name:"",n=typeof t.version==="string"?t.version:"";if(r==="")return"";return n===""?r:`${r} ${n}`}function a0(e){return e.socket.remoteAddress??"unknown"}class ga extends Error{code;constructor(e,t){super(t);this.code=e}}function va(){return{"Access-Control-Allow-Origin":"*","Access-Control-Allow-Headers":"Authorization, Content-Type, Accept, MCP-Protocol-Version, Mcp-Session-Id","Access-Control-Allow-Methods":"POST, OPTIONS"}}function Xi(e,t,r){let n=JSON.stringify(r);e.writeHead(t,{"Content-Type":"application/json","Content-Length":Buffer.byteLength(n),...va()}),e.end(n)}function ha(e,t,r){return{jsonrpc:l0,id:e,error:{code:t,message:r}}}function VO(e){let t=e.url??"/",r=t.indexOf("?");return r>=0?t.slice(0,r):t}function YO(e){return new Promise((t,r)=>{let n=[];e.on("data",(o)=>{n.push(o)}),e.on("end",()=>{t(Buffer.concat(n).toString("utf8"))}),e.on("error",r)})}function zc(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}import{readFileSync as JO}from"fs";import{createServer as XO}from"http";import{join as QO}from"path";ne();Ke();Ji();var qc=`<!doctype html>
|
|
2546
2552
|
<html lang="en">
|
|
2547
2553
|
<head>
|
|
2548
2554
|
<meta charset="utf-8" />
|
|
@@ -2568,7 +2574,7 @@ Error generating stack: \`+l.message+\`
|
|
|
2568
2574
|
|
|
2569
2575
|
</body>
|
|
2570
2576
|
</html>
|
|
2571
|
-
`;var
|
|
2577
|
+
`;var p0="application/json",ZO="text/html; charset=utf-8",hm={"X-Content-Type-Options":"nosniff"},eM=/export const WEB_INDEX_HTML = ("(?:\\.|[^"\\])*")/,tM="GET",c0="GET, POST",rM="POST",nM=65536;class gm{server;running=!1;addr="";boundPort=0;opts;constructor(e){this.opts=e}address(){return this.addr}listenPort(){return this.boundPort}isRunning(){return this.running}start(){let e=this.opts.host||Ot;if(!_t(e))return Promise.reject(T($e,`refusing to bind web UI to ${e}`));return new Promise((t,r)=>{this.server=XO((n,o)=>{this.serve(n,o)}),this.server.on("error",(n)=>r(ge($e,`unable to listen on ${e}:${this.opts.port}`,n))),this.server.listen(this.opts.port,e,()=>{let n=this.server?.address();this.boundPort=typeof n==="object"&&n?n.port:this.opts.port,this.addr=pb(e,this.boundPort),this.running=!0,this.opts.onEvent?.("INFO",`listening on ${this.addr}`),t()})})}stop(){let e=this.server,t=this.running;if(!e)return this.running=!1,Promise.resolve();return new Promise((r)=>{e.close(()=>{if(this.running=!1,this.addr="",this.boundPort=0,this.server=void 0,t)this.opts.onEvent?.("INFO","stopped");r()})})}async serve(e,t){if(!oM(e.headers.host)){Dr(t,403,{error:"forbidden"});return}let r=e.method??"GET";if(r!=="GET"&&r!=="POST"){mm(t,c0);return}let n=new URL(e.url??"/",`http://127.0.0.1:${this.boundPort}`),o=n.pathname;try{if(r==="POST"){await this.routePost(o,e,t);return}await this.routeGet(o,n.searchParams,t)}catch(i){let s=i instanceof Error?i.message:"internal error",a=i instanceof un?i.status:400;this.opts.onEvent?.("WARN",`web ${o}: ${s}`),Dr(t,a,{error:s})}}async routeGet(e,t,r){let n=this.opts.hostApi;if(e==="/"){uM(r,dM());return}if(e==="/api/control"){mm(r,rM);return}if(e==="/api/status"){Dr(r,200,jc(n.status()));return}if(e==="/api/services"){Dr(r,200,Uc(n.status()));return}if(e==="/api/requests"){Dr(r,200,dm(n.status()));return}if(e==="/api/config"){Dr(r,200,Bc(n.config()));return}if(e==="/api/profiles"){Dr(r,200,pm(n.config()));return}if(e==="/api/logs"){Dr(r,200,await fa(n,aM(t)));return}let o=d0(e,"/api/trace/");if(o!==void 0){Dr(r,200,await cm(n,{trace_id:decodeURIComponent(o)}));return}let i=d0(e,"/api/request/");if(i!==void 0){Dr(r,200,await um(n,{request_id:decodeURIComponent(i)}));return}Dr(r,404,{error:"not found"})}async routePost(e,t,r){if(e!=="/api/control"){mm(r,e==="/"||e.startsWith("/api/")?tM:c0);return}iM(t),sM(t.headers["content-type"]);let n=await cM(t),o=typeof n.tool==="string"?n.tool:"";if(!Qx(o))throw new un(400,"unknown or non-mutating tool");let i=await Wc(this.opts.hostApi,o,lM(n.args));Dr(r,200,i??{ok:!0})}}function Gc(e){return((Array.isArray(e)?e[0]:e)??"").split(",")[0]?.trim()??""}function oM(e){let t=db(Gc(e));return t!==void 0&&qp(t)}function u0(e){try{let t=new URL(e);return(t.protocol==="http:"||t.protocol==="https:")&&qp(t.hostname)}catch{return!1}}function iM(e){let t=Gc(e.headers.origin);if(t!==""){if(!u0(t))throw new un(403,"cross-origin request rejected");return}let r=Gc(e.headers.referer);if(r!==""&&u0(r))return;throw new un(403,"cross-origin request rejected")}function sM(e){if((Gc(e).split(";")[0]?.trim().toLowerCase()??"")!==p0)throw new un(415,"JSON content type required")}function d0(e,t){if(!e.startsWith(t))return;let r=e.slice(t.length);if(r===""||r.includes("/"))return;return r}function aM(e){let t={};for(let[r,n]of e.entries())t[r]=n;return t}class un extends Error{status;constructor(e,t){super(t);this.status=e}}function lM(e){if(e===void 0||e===null)return{};if(typeof e!=="object"||Array.isArray(e))throw new un(400,"args must be an object");return e}function cM(e){return new Promise((t,r)=>{let n=[],o=0,i=!1,s=(a)=>{if(i)return;i=!0,r(a)};e.on("data",(a)=>{if(i)return;if(o+=a.length,o>nM){s(new un(413,"payload too large"));return}n.push(a)}),e.on("end",()=>{if(i)return;if(i=!0,n.length===0){t({});return}try{let a=JSON.parse(Buffer.concat(n).toString("utf8"));if(a===null||typeof a!=="object"||Array.isArray(a)){r(new un(400,"JSON object required"));return}t(a)}catch{r(new un(400,"invalid JSON"))}}),e.on("error",(a)=>s(a instanceof Error?a:Error(String(a))))})}function mm(e,t){e.writeHead(405,{Allow:t,...hm}),e.end()}function Dr(e,t,r){let n=JSON.stringify(r);e.writeHead(t,{"Content-Type":p0,"Content-Length":Buffer.byteLength(n),...hm}),e.end(n)}function uM(e,t){e.writeHead(200,{"Content-Type":ZO,"Content-Length":Buffer.byteLength(t),"Cache-Control":"no-store",...hm}),e.end(t)}function dM(){let e="";try{e=JO(QO(import.meta.dir,"assets.generated.ts"),"utf8")}catch(r){if(pM(r))return qc;throw r}let t=eM.exec(e);if(!t?.[1])return qc;try{return JSON.parse(t[1])}catch(r){if(r instanceof SyntaxError)return qc;throw r}}function pM(e){return typeof e==="object"&&e!==null&&"code"in e&&e.code==="ENOENT"}Ji();var hM=(e)=>new fm({host:"127.0.0.1",...e}),gM=(e)=>new gm({host:"127.0.0.1",...e});async function vM(e,t={}){let r=t.clock??sc,n=t.fs??ox,o=t.processes??new xf,i=t.bus??new Nd(2048),s=t.tokens??new qo(e.auth.refresh_threshold_seconds*1000,Zn(),i,void 0,r),a=new Rf(o,r),l=_d(),c=new Rr(e.secrets.extra_markers,e.secrets.extra_patterns),u=Bun.isStandaloneExecutable===!0,{logs:d,usingWorker:f}=await Wx({max:e.logs.max_memory_events,persist:e.logs.persistence.enabled,directory:e.logs.persistence.directory,sessionID:l,retentionDays:e.logs.persistence.retention_days,maxSessionLogs:e.logs.persistence.max_session_logs,extraMarkers:e.secrets.extra_markers,extraPatterns:e.secrets.extra_patterns},i,c,{standalone:u});if(!f&&!u)d.append({timestamp:r.isoNow(),service:"devctl",source:"devctl",level:"WARN",message:"log worker failed to start; using in-process log store",pid:0});return{supervisor:new im(e,{healthCheckers:t.healthCheckers??Nw([]),detectGoogle:t.detectGoogle??Wo,tokens:s,inspectProcess:rx,processAlive:mr,acquireLock:zg,socketExists:fM,unlinkSocket:mM,procs:o,orchestrator:a,clock:r,fs:n,bus:i,logs:d,detector:c,sessionID:l,createMcpListener:t.createMcpListener??hM,createWebListener:t.createWebListener??gM,isKnownTool:Hc,createCommands:(m)=>dw(m,uc(Hi({tokens:s})),a)}),orchestrator:a,clock:r,fs:n}}async function f0(e,t){let r=Uo(e,t),{supervisor:n}=await vM(r),o=!1,i=()=>{if(o)return;o=!0,n.shutdown(Hl(r.shutdown)).finally(()=>process.exit(0))};process.on("SIGINT",i),process.on("SIGTERM",i),await n.run()}Ke();ne();rg();import{Command as AH}from"commander";var AE=["zsh","bash","fish"];function LE(e){if(e==="zsh")return`#compdef devctl
|
|
2572
2578
|
_devctl() {
|
|
2573
2579
|
local -a opts
|
|
2574
2580
|
local line="\${words[*]}"
|
|
@@ -2588,7 +2594,7 @@ complete -F _devctl devctl
|
|
|
2588
2594
|
devctl __complete (commandline -cp)
|
|
2589
2595
|
end
|
|
2590
2596
|
complete -c devctl -f -a "(__devctl_complete)"
|
|
2591
|
-
`;throw Error(`unsupported shell "${e}"; use ${
|
|
2597
|
+
`;throw Error(`unsupported shell "${e}"; use ${AE.join(", ")}`)}function ng(e,t){let r=e.trim().split(/\s+/).filter((c)=>c!==""),n=e.endsWith(" ")?"":r[r.length-1]??"",o=e.endsWith(" ")?r:r.slice(0,-1),i=o[1]??"",s=Object.keys(t.services).sort(),a=Object.keys(t.profiles).sort(),l=["start","run","exec","down","daemon","stop","restart","status","logs","doctor","setup","auth","proxy","mcp","web","config","reload","attach","completion","update","version"];if(i===""||o.length<2)return Qr(l,n);if(i==="start"||i==="stop"||i==="restart"||i==="logs"){if(n==="--profile"||o[o.length-1]==="--profile")return Qr(a,n==="--profile"?"":n);return Qr([...s,"--profile","--detach","--json","--since","--until"],n)}if(i==="completion")return Qr([...AE].sort(),n);if(i==="run")return Qr([...Object.keys(t.tasks).sort(),"--json"],n);if(i==="exec")return Qr([...s,"--print-env","--reveal","--json"],n);if(i==="auth")return Qr(["status","login","logout","refresh"],n);if(i==="config")return Qr(["validate","show","diff"],n);if(i==="proxy")return Qr(["status","start","stop"],n);if(i==="web")return Qr(["status","start","stop"],n);return Qr(l,n)}function Qr(e,t){if(t==="")return e;return e.filter((r)=>r.startsWith(t))}function he(e){return e.optsWithGlobals().config??""}function C(e){try{process.stdout.write(e)}catch(t){if(t.code==="EPIPE")process.exit(0);throw t}}function IE(e,t){let r=e.command("auth").description("Google authentication");r.command("status").option("--json","machine-readable output").action(async(n)=>{let o="";try{o=t.load("",he(e)).google.project_id}catch{o=""}let i=await t.detectGoogle(o);if(n.json){C(JSON.stringify(i,null,2)+`
|
|
2592
2598
|
`);return}if(C(`User: ${i.userEmail||"(unknown)"}
|
|
2593
2599
|
`),C(`Project: ${i.projectID||"(unset)"}
|
|
2594
2600
|
`),i.projectID!=="")C(`Source: ${i.projectSource}
|
|
@@ -2597,10 +2603,10 @@ complete -c devctl -f -a "(__devctl_complete)"
|
|
|
2597
2603
|
`)}),r.command("login").action(async()=>{await t.loginGoogle()}),r.command("logout").action(async()=>{await t.logoutGoogle()}),r.command("refresh").option("--json","machine-readable output").action(async(n)=>{let o=await t.openController("",he(e),!1);try{let i=await t.refreshUserToken("user"),s=o.client?await o.refreshAuth():void 0;if(n.json){C(JSON.stringify({identity:i.identity,expires_at:i.expiresAt.toISOString(),service_account_status:s?.service_account_status??{}},null,2)+`
|
|
2598
2604
|
`);return}if(C(`refreshed credentials expire ${i.expiresAt.toISOString()}
|
|
2599
2605
|
`),s)for(let[a,l]of Object.entries(s.service_account_status).sort(([c],[u])=>c.localeCompare(u)))C(`service account ${a}: ${l}
|
|
2600
|
-
`)}finally{await o.close()}})}ne();$t();
|
|
2606
|
+
`)}finally{await o.close()}})}ne();$t();Ah();import{mkdirSync as xH}from"fs";import{basename as kH,dirname as SH}from"path";import{stringify as CH}from"yaml";zl();function DE(e,t){e.command("reload").description("reload configuration").action(async()=>{let r=await t.openController("",he(e),!0);try{let n=await r.reload();if(n.restart_required.length===0)C(`configuration reloaded
|
|
2601
2607
|
`);else C(`configuration reloaded; restart required: ${n.restart_required.join(", ")}
|
|
2602
2608
|
`);if(n.supervisor_restart_required&&n.supervisor_restart_required.length>0)C(`note: ${mc(n.supervisor_restart_required)}
|
|
2603
|
-
`)}finally{await r.close()}})}function
|
|
2609
|
+
`)}finally{await r.close()}})}function OE(e,t){let r=e.command("config");r.command("validate").option("--json").action((n)=>{try{let o=t.load("",he(e)),i=t.validate(o);if(n.json){C(JSON.stringify({valid:i.length===0,issues:i},null,2)+`
|
|
2604
2610
|
`);return}if(i.length>0)throw Error(i.join(`
|
|
2605
2611
|
`));C(`configuration is valid
|
|
2606
2612
|
`)}catch(o){if(n.json){C(JSON.stringify({valid:!1,error:I(o)},null,2)+`
|
|
@@ -2609,20 +2615,20 @@ complete -c devctl -f -a "(__devctl_complete)"
|
|
|
2609
2615
|
`),C(` winner: ${s.layer} (${s.source})
|
|
2610
2616
|
`);for(let a of s.shadowed)C(` shadowed: ${a.layer} (${a.source})
|
|
2611
2617
|
`)}}),r.command("show").option("--json").action((n)=>{let o=t.load("",he(e));if(n.json){C(JSON.stringify(o,null,2)+`
|
|
2612
|
-
`);return}C(
|
|
2618
|
+
`);return}C(CH(o))}),r.command("import").command("compose").argument("<file>","docker-compose.yml or compose.yaml").option("--write","write mapped fields under .devctl/config.yaml").action((n,o)=>{let i=t.readTextFile(n),{repo:s,cfgPath:a}=Lp("",he(e)),l=$u(i,kH(s)),c=t.validateConfigText(s,a,l.yaml);if(C(Hu(l)),c.length>0){if(C(`validation:
|
|
2613
2619
|
${c.map((u)=>` ${u}`).join(`
|
|
2614
2620
|
`)}
|
|
2615
2621
|
`),o.write===!0)throw Error("refusing to write an invalid mapping");return}if(o.write!==!0){C(`dry-run; pass --write to save under .devctl/config.yaml
|
|
2616
|
-
`);return}if(t.fileExists(a))throw Error(`configuration already exists at ${a}; not overwriting`);
|
|
2617
|
-
`)})}To();$t();import{setTimeout as
|
|
2622
|
+
`);return}if(t.fileExists(a))throw Error(`configuration already exists at ${a}; not overwriting`);xH(SH(a),{recursive:!0}),t.writeTextFile(a,l.yaml),C(`wrote ${a}
|
|
2623
|
+
`)})}To();$t();import{setTimeout as TH}from"timers/promises";function NE(e,t){e.command("exec").argument("<service>","service whose execution context to use").argument("[command...]","command and arguments").option("--print-env","print the resolved environment instead of running a command").option("--reveal","show secret values with --print-env").option("--json","machine-readable output").action(async(r,n,o)=>{if(!o.printEnv&&n.length===0)throw Error("exec command is required (or use --print-env)");let i=await t.openController("",he(e),!0);try{let s=await i.execService(r,n,o.printEnv===!0);if(s.environment){let a=o.reveal?s.environment:new Rr(i.cfg.secrets.extra_markers,i.cfg.secrets.extra_patterns).redactMap(s.environment);if(o.json)C(JSON.stringify({...s,environment:a},null,2)+`
|
|
2618
2624
|
`);else for(let l of Object.keys(a).sort())C(`${l}=${a[l]}
|
|
2619
2625
|
`)}else if(o.json)C(JSON.stringify(s,null,2)+`
|
|
2620
|
-
`);else{if(s.stdout)C(s.stdout);if(s.stderr)process.stderr.write(s.stderr)}}finally{await i.close()}})}function
|
|
2621
|
-
`);else{if(i.stdout)C(i.stdout);if(i.stderr)process.stderr.write(i.stderr)}}finally{await o.close()}})}function
|
|
2622
|
-
`);return}if(C(
|
|
2623
|
-
`)}finally{await o.close()}})}function
|
|
2624
|
-
`)}finally{await o.close()}})}function
|
|
2625
|
-
`)}finally{await o.close()}})}async function
|
|
2626
|
+
`);else{if(s.stdout)C(s.stdout);if(s.stderr)process.stderr.write(s.stderr)}}finally{await i.close()}})}function FE(e,t){e.command("run").argument("<task>","task to run").option("--json","machine-readable output").action(async(r,n)=>{let o=await t.openController("",he(e),!0);try{let i=await o.runTask(r);if(n.json)C(JSON.stringify(i,null,2)+`
|
|
2627
|
+
`);else{if(i.stdout)C(i.stdout);if(i.stderr)process.stderr.write(i.stderr)}}finally{await o.close()}})}function $E(e,t){e.command("start").argument("[services...]","services to start").option("--profile <name>","profile to start").option("--detach","deprecated, no longer changes behavior: the daemon already outlives this command; use `devctl down` to stop it").option("--json","machine-readable output").action(async(r,n)=>{if(n.detach)process.stderr.write("warning: --detach is deprecated and no longer changes behavior \u2014 the daemon already keeps running after `start` exits; use `devctl down` to stop it\n");let o=await t.openController("",he(e),!0);try{let i=await o.start({services:r,profile:n.profile,detach:n.detach===!0});if(n.json){C(JSON.stringify(i,null,2)+`
|
|
2628
|
+
`);return}if(C(tw(i)),n.detach)C(`detached; services continue running
|
|
2629
|
+
`)}finally{await o.close()}})}function HE(e,t){e.command("stop").argument("[services...]","services to stop").option("--json","machine-readable output").action(async(r,n)=>{let o=await t.openController("",he(e),!0);try{if(await o.stop(r),n.json)C(JSON.stringify({stopped:r},null,2)+`
|
|
2630
|
+
`)}finally{await o.close()}})}function UE(e,t){e.command("restart").argument("[services...]").option("--cascade","also restart transitive dependents (default: only the named services)").option("--json","machine-readable output").action(async(r,n)=>{let o=await t.openController("",he(e),!0);try{if(await o.restart(r,n.cascade===!0),n.json)C(JSON.stringify({restarted:r,cascade:n.cascade===!0},null,2)+`
|
|
2631
|
+
`)}finally{await o.close()}})}async function ME(e,t,r){let{repoRoot:n,client:o}=await e.findDaemon("",r.repo??"",he(t));try{if(!o){let s=e.readPersistedState(n);if(r.json){C(JSON.stringify({running:!1,persisted:s},null,2)+`
|
|
2626
2632
|
`);return}if(C(`supervisor is not running
|
|
2627
2633
|
`),s&&s.processes.length>0){C(`last session ${s.session_id} profile ${s.profile||"(none)"}
|
|
2628
2634
|
`);for(let a of s.processes)C(`${a.name} stopped UNKNOWN ${a.pid}
|
|
@@ -2637,49 +2643,49 @@ PROXY ${i.proxy.running?"RUNNING":"STOPPED"} ${i.proxy.address??""}
|
|
|
2637
2643
|
`),C(`WEB ${i.web?.running?"RUNNING":"STOPPED"} ${i.web?.address??""}
|
|
2638
2644
|
`),C(`IDENTITY ${i.identity.user||"(unknown)"}
|
|
2639
2645
|
`),C(`CLOUD ${i.identity.project||"(unset)"}
|
|
2640
|
-
`)}finally{o?.close()}}var
|
|
2641
|
-
`),await
|
|
2642
|
-
`);try{await
|
|
2643
|
-
`);return}let i=await
|
|
2646
|
+
`)}finally{o?.close()}}var EH=2000;function jE(e,t){e.command("status").option("--repo <path>","target a repository directly, even without a loadable configuration").option("--json","machine-readable output").option("--watch","keep refreshing until interrupted").action(async(r)=>{if(!r.watch){await ME(t,e,r);return}let n=new AbortController,o=()=>n.abort();process.on("SIGINT",o),process.on("SIGTERM",o);try{while(!n.signal.aborted){C(`--- ${new Date().toISOString()} ---
|
|
2647
|
+
`),await ME(t,e,r),C(`
|
|
2648
|
+
`);try{await TH(EH,void 0,{signal:n.signal})}catch{break}}}finally{process.off("SIGINT",o),process.off("SIGTERM",o)}})}function BE(e,t){e.command("down").description("stop the daemon (and, by default, its services)").option("--repo <path>","target a repository directly, even without a loadable configuration").option("--keep-services","stop only the daemon; its services keep running, detached").action(async(r)=>{let{repoRoot:n,client:o}=await t.findDaemon("",r.repo??"",he(e));if(!o){C(`no supervisor is running for ${n}
|
|
2649
|
+
`);return}let i=await _H(o);try{let s=r.keepServices!==!0;await o.call("shutdown",{stop_services:s},i)}finally{o.close()}await RH(t,n,i),C(r.keepServices!==!0?`stopped services and the supervisor for ${n}
|
|
2644
2650
|
`:`stopped the supervisor for ${n}; its services keep running
|
|
2645
|
-
`)})}async function
|
|
2646
|
-
`}function
|
|
2647
|
-
`)}function
|
|
2651
|
+
`)})}async function RH(e,t,r){let n=Date.now()+r;while(Date.now()<n){let o=await e.tryDial(t);if(!o)return;o.close()}}async function _H(e){try{let r=await e.call("config_snapshot",null),n=typeof r.shutdown?.grace_seconds==="number"?r.shutdown.grace_seconds:0;return Math.max(5000,n*1000+2000)}catch{return 30000}}function WE(e,t){e.command("attach").action(async()=>{let r=await t.openAttach("",he(e));await Promise.resolve().then(() => rg());await RE(t,r)})}sn();import{setTimeout as qE}from"timers/promises";function id(e){return`${e.timestamp.slice(11,19)} ${e.service.padEnd(10)} ${e.severityText.padEnd(6)} ${Kt(e)}
|
|
2652
|
+
`}function zE(e){for(let t of e)C(`${JSON.stringify(t)}
|
|
2653
|
+
`)}function PH(e){if(!e)return;let t=e.indexOf("=");if(t<=0)return;return{key:e.slice(0,t),value:e.slice(t+1)}}async function GE(e,t,r,n=1000){let o=await e(void 0);o.events.forEach(t);let i=o.nextCursor;while(!r.aborted){try{await qE(n,void 0,{signal:r})}catch{return}o=await e(i),o.events.forEach(t),i=o.nextCursor}}function KE(e,t){let r=e.command("logs").argument("[services...]").enablePositionalOptions();r.option("--level <level>","minimum level").option("--search <text>","substring or regex search").option("--regex","treat search as regular expression").option("--source <source>","filter by source").option("--since <timestamp>","only events at or after this ISO timestamp").option("--until <timestamp>","only events at or before this ISO timestamp").option("--trace <id>","print a trace's spans and correlated logs").option("--request-id <id>","filter by request id").option("--attribute <key=value>","filter by a single attribute").option("--output <path>","export path").option("--json","JSONL LogRecord output").option("-f, --follow","keep printing new matching events until interrupted").option("--all","print the full matching history instead of the latest page").action(async(n,o)=>{let i=await t.openController("",he(e),!0);try{if(o.trace){let u=await i.getTrace(o.trace);if(o.json){C(`${JSON.stringify(u)}
|
|
2648
2654
|
`);return}for(let d of u.tree.spans)C(`${d.name} ${d.kind} ${d.status.code} ${d.spanId}
|
|
2649
|
-
`);for(let d of u.events)C(id(d));return}let s=
|
|
2655
|
+
`);for(let d of u.events)C(id(d));return}let s=PH(o.attribute),a={services:n,level:o.level,search:o.search,regex:o.regex,source:o.source,since:o.since,until:o.until,requestId:o.requestId,traceId:o.trace,attribute:s},l=o.output?t.resolveExportPath(o.output):void 0;if(o.follow&&!l){let u=new AbortController,d=()=>u.abort();process.on("SIGINT",d),process.on("SIGTERM",d);try{await GE((f)=>i.logsPage({...a,cursor:f,direction:"forward"}),(f)=>C(o.json?JSON.stringify(f)+`
|
|
2650
2656
|
`:id(f)),u.signal)}finally{process.off("SIGINT",d),process.off("SIGTERM",d)}return}if(l||o.all===!0){let u=await i.logs({...a,export:l});if(l){C(`exported ${l}
|
|
2651
|
-
`);return}if(o.json){
|
|
2657
|
+
`);return}if(o.json){zE(u);return}for(let d of u)C(id(d));return}let c=await i.logsPage({...a,direction:"backward"});if(o.json){zE(c.events);return}for(let u of c.events)C(id(u));if(c.hasPrev)C(`\u2026 older matching events omitted; pass --all for the full history
|
|
2652
2658
|
`)}finally{await i.close()}}),r.command("export").argument("[services...]").requiredOption("--output <path>","export path").option("--level <level>","minimum level").option("--search <text>","substring or regex search").option("--regex","treat search as regular expression").option("--source <source>","filter by source").action(async(n,o)=>{let i=await t.openController("",he(e),!0);try{let s=t.resolveExportPath(o.output);await i.logs({services:n,level:o.level,search:o.search,regex:o.regex,source:o.source,export:s}),C(`exported ${s}
|
|
2653
|
-
`)}finally{await i.close()}})}function
|
|
2654
|
-
`);else s();if(!r.follow)return;let a=new AbortController,l=()=>a.abort();process.on("SIGINT",l),process.on("SIGTERM",l);try{while(!a.signal.aborted){try{await
|
|
2659
|
+
`)}finally{await i.close()}})}function VE(e,t){e.command("daemon").command("logs").option("-f, --follow","keep printing new lines until interrupted").action(async(r)=>{let{repoRoot:n}=t.discover("",he(e)),o=t.bootstrapLogPath(n),i=0,s=()=>{if(!t.fileExists(o))return;let c=t.readTextFile(o);if(c.length>i)C(c.slice(i)),i=c.length};if(!t.fileExists(o))C(`no daemon bootstrap log yet for this repository
|
|
2660
|
+
`);else s();if(!r.follow)return;let a=new AbortController,l=()=>a.abort();process.on("SIGINT",l),process.on("SIGTERM",l);try{while(!a.signal.aborted){try{await qE(500,void 0,{signal:a.signal})}catch{break}s()}}finally{process.off("SIGINT",l),process.off("SIGTERM",l)}})}Mu();function YE(e,t){let r=e.command("proxy");r.command("status").option("--json").action(async(n)=>{let o=await t.openController("",he(e),!1);try{if(!o.client){C(`PROXY STOPPED
|
|
2655
2661
|
`);return}let i=await o.status();if(n.json){C(JSON.stringify(i.proxy,null,2)+`
|
|
2656
2662
|
`);return}C(`PROXY ${i.proxy.running?"RUNNING":"STOPPED"} ${i.proxy.address??""}
|
|
2657
2663
|
`);for(let s of i.proxy.routes??[]){let a=s.match?` match=${s.match}`:"",l=s.client_id?` client_id=${s.client_id}`:"";C(` ${s.name.padEnd(16)} identity=${s.identity}${a}${l} ${s.upstream}
|
|
2658
|
-
`)}}finally{await o.close()}}),r.command("start").action(async()=>{let n=await t.openController("",he(e),!0);try{await n.proxyStart()}finally{await n.close()}}),r.command("stop").action(async()=>{let n=await t.openController("",he(e),!0);try{await n.proxyStop()}finally{await n.close()}})}function
|
|
2664
|
+
`)}}finally{await o.close()}}),r.command("start").action(async()=>{let n=await t.openController("",he(e),!0);try{await n.proxyStart()}finally{await n.close()}}),r.command("stop").action(async()=>{let n=await t.openController("",he(e),!0);try{await n.proxyStop()}finally{await n.close()}})}function JE(e,t){e.command("mcp").description("Local MCP server for coding agents").option("--on","start the MCP listener").option("--off","stop the MCP listener").option("--port <port>","listen port").option("--json","machine-readable output").action(async(r)=>{let n=r.port===void 0?void 0:Number(r.port);if(r.port!==void 0&&(!Number.isInteger(n)||(n??0)<=0))throw Error(`invalid --port ${r.port}`);let o=await t.openController("",he(e),r.on===!0,{allowMissingConfig:!0});try{if(r.off===!0&&o.client)await o.mcpStop();else if(r.on===!0)await o.mcpStart({port:n});let i=o.client?await o.status():void 0,s=t.loadTuiConfig(o.cfg.repoRoot,o.cfg.ui.keymap),a=i?.mcp?.port??n??s.mcp_port??Xo(o.cfg.repoRoot),l=i?.mcp?.address??cs(a),c=i?.mcp?.token??"";if(r.json){C(JSON.stringify({running:i?.mcp?.running===!0,setup_mode:i?.setup_mode===!0,url:l,port:a,snippets:{claude:JSON.parse(ph(l,c)),cursor:JSON.parse(fh(l,c)),kilo:JSON.parse(mh(l,c)),codex:hh(l,c)}},null,2)+`
|
|
2659
2665
|
`);return}if(C(`MCP ${i?.mcp?.running?"RUNNING":"STOPPED"} ${l}
|
|
2660
2666
|
|
|
2661
2667
|
`),i?.setup_mode===!0)C(`This repository has no .devctl yet, so the daemon is in setup mode.
|
|
2662
2668
|
`),C(`Connect an agent with the config below and ask it to set devctl up for this repository.
|
|
2663
2669
|
`),C(`It can call get_setup_guide, search_docs, and validate_config; nothing will run until a configuration exists.
|
|
2664
2670
|
|
|
2665
|
-
`);C(
|
|
2671
|
+
`);C(jS(l,c))}finally{await o.close()}})}function XE(e,t){let r=e.command("web").description("Local loopback telemetry and control web UI");r.command("status").option("--json").action(async(n)=>{let o=await t.openController("",he(e),!1);try{if(!o.client){if(n.json){C(`${JSON.stringify({running:!1},null,2)}
|
|
2666
2672
|
`);return}C(`WEB STOPPED
|
|
2667
2673
|
`);return}let i=await o.status();if(n.json){C(JSON.stringify(i.web??{running:!1},null,2)+`
|
|
2668
2674
|
`);return}C(`WEB ${i.web?.running?"RUNNING":"STOPPED"} ${i.web?.address??""}
|
|
2669
2675
|
`)}finally{await o.close()}}),r.command("start").action(async()=>{let n=await t.openController("",he(e),!0);try{await n.webStart();let o=await n.status();C(`${o.web?.address??""}
|
|
2670
|
-
`)}finally{await n.close()}}),r.command("stop").action(async()=>{let n=await t.openController("",he(e),!0);try{await n.webStop()}finally{await n.close()}})}ne();function
|
|
2676
|
+
`)}finally{await n.close()}}),r.command("stop").action(async()=>{let n=await t.openController("",he(e),!0);try{await n.webStop()}finally{await n.close()}})}ne();function QE(e,t){e.command("update").description("check GitHub Releases and install when the install method is known").option("--json","machine-readable output").option("--check","report only; do not install").action(async(r)=>{let n=await t.checkUpdate();if(r.json){C(JSON.stringify(n,null,2)+`
|
|
2671
2677
|
`);return}if(C(`current ${n.current}
|
|
2672
2678
|
`),C(`latest ${n.latest||"(unavailable)"}
|
|
2673
2679
|
`),C(`channel ${n.kind}
|
|
2674
2680
|
`),!n.newer){if(n.latest!=="")C(`up to date
|
|
2675
2681
|
`);return}if(C(`install ${n.hint}
|
|
2676
2682
|
`),r.check||!n.command)return;if(C(`installing via ${n.kind}\u2026
|
|
2677
|
-
`),(await t.applyUpdate(n.command,!0)).code!==0){process.exitCode=
|
|
2678
|
-
`)})}function
|
|
2679
|
-
`)}),r.action(async()=>{let n=r.opts();await
|
|
2680
|
-
`);else C(t.formatDoctor(o));if(o.issues>0)process.exitCode=2})}function
|
|
2683
|
+
`),(await t.applyUpdate(n.command,!0)).code!==0){process.exitCode=ry;return}C(`updated to ${n.latest}; ${kc}
|
|
2684
|
+
`)})}function LH(e,t){let r=new AH;return r.name("devctl").description("Local development orchestrator").version(vr(),"-V, --version","print version").option("--config <path>","path to config file or .devctl directory").enablePositionalOptions(),r.command("version").description("print version").action(()=>{C(`${vr()}
|
|
2685
|
+
`)}),r.action(async()=>{let n=r.opts();await _E(e,n.config??"")}),$E(r,e),HE(r,e),UE(r,e),FE(r,e),NE(r,e),jE(r,e),BE(r,e),KE(r,e),VE(r,e),IH(r,e),DH(r,e),IE(r,e),YE(r,e),JE(r,e),XE(r,e),OE(r,e),DE(r,e),WE(r,e),OH(r,e),QE(r,e),MH(r,t),r}function IH(e,t){e.command("doctor").option("--json","machine-readable output").action(async(r)=>{let n=t.load("",he(e)),o=await t.runDoctor.execute(n);if(r.json)C(JSON.stringify(o,null,2)+`
|
|
2686
|
+
`);else C(t.formatDoctor(o));if(o.issues>0)process.exitCode=2})}function DH(e,t){e.command("setup").option("--force","overwrite an existing configuration").action(async(r)=>{await t.runSetup("",he(e),r.force===!0)})}function OH(e,t){e.command("completion").argument("[shell]","zsh, bash, or fish").description("print a shell completion script").action((r)=>{C(LE(r||"zsh"))}),e.command("__complete",{hidden:!0}).argument("[line...]").description("internal completion helper").action((r)=>{let n=r.join(" "),o=n===""?"devctl ":n;try{let i=t.load("",he(e));C(ng(o,i).join(`
|
|
2681
2687
|
`)+`
|
|
2682
|
-
`)}catch{C(
|
|
2688
|
+
`)}catch{C(ng(o,Io()).join(`
|
|
2683
2689
|
`)+`
|
|
2684
|
-
`)}})}function
|
|
2685
|
-
`),process.exit(
|
|
2690
|
+
`)}})}function MH(e,t){e.command("_supervisor").option("--repo <path>","repository root").action(async(r)=>{await t(r.repo??"",he(e))})}async function ZE(e,t){process.stdout.on("error",(r)=>{if(r.code==="EPIPE")process.exit(0)});try{await LH(e,t).parseAsync(process.argv)}catch(r){process.stderr.write(I(r)+`
|
|
2691
|
+
`),process.exit(oy(r))}}Ya();await ZE(Mw(),f0);
|