@amr-m-abdelgawad/devctl 0.2.3 → 0.2.5
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 +157 -140
- package/package.json +2 -1
package/dist/devctl.js
CHANGED
|
@@ -1,37 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
var rS=Object.defineProperty;var oS=(e)=>e;function iS(e,t){this[e]=oS.bind(null,t)}var Ms=(e,t)=>{for(var n in t)rS(e,n,{get:t[n],enumerable:!0,configurable:!0,set:iS.bind(t,n)})};var D=(e,t)=>()=>(e&&(t=e(e=0)),t);var sS=import.meta.require;var eo=D(()=>{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"});function Df(e,t=""){if(t===Af)return!0;return e.includes(Af)||e.startsWith(aS)}function $s(){if(Lf)return;Lf=!0;let e=process.emitWarning.bind(process);process.emitWarning=(t,...n)=>{let r=lS(n[0]),o=cS(t);if(Df(o,r))return;e(t,...n)}}function Of(){let e=process.stderr.write.bind(process.stderr);return process.stderr.write=(t,n,r)=>{let o=dS(t);if(Df(o)){let i=typeof n==="function"?n:typeof r==="function"?r:void 0;if(typeof i==="function")i();return!0}if(typeof n==="function")return e(t,n);return e(t,n,r)},()=>{process.stderr.write=e}}function cS(e){if(typeof e==="string")return e;if(e instanceof Error)return e.message;return String(e)}function lS(e){if(typeof e==="string")return e;if(e&&typeof e==="object"&&"type"in e&&typeof e.type==="string")return e.type;return""}function dS(e){if(typeof e==="string")return e;if(e instanceof Uint8Array)return new TextDecoder().decode(e);return""}var Af="MetadataLookupWarning",aS="received unexpected error =",Lf=!1;var Cl=D(()=>{eo()});function L(e,t){return new Me(e,t)}function fe(e,t,n){let r=n instanceof Error?n:Error(String(n));return new Me(e,t,{cause:r})}function ke(e,t,n,r=""){return new Me(e,t,{hint:n,service:r})}function Fs(e,t){return e instanceof Me&&e.kind===t}function If(e){if(e instanceof Me)return e.exitCode();return 1}function Ff(e){if(e instanceof Me)return{error:O(e),kind:e.kind,hint:e.hint,service:e.service};return{error:O(e)}}function Nf(e){if(typeof e==="string")return L("general",e);if(e.kind)return new Me(e.kind,e.error.replace(`${e.kind}: `,""),{hint:e.hint,service:e.service});return L("general",e.error)}function O(e){if(e instanceof Me){if(e.hint!=="")return`${Mf(e)} \u2014 ${e.hint}`;return Mf(e)}if(e instanceof Error)return e.message;return String(e)}function Mf(e){let t=`${e.kind}: `;if(e.message.startsWith(t)){let n=e.message.slice(t.length),r=e.causeError?`: ${e.causeError.message}`:"";if(r!==""&&n.endsWith(r))return n.slice(0,n.length-r.length);return n}return e.message}var Z="configuration",cr="configuration_missing",fi="service_not_found",$f="dependency",Ne="process_start",to="authentication",lr="authorization",hn="token",Is="impersonation",_l="iap",$n="proxy",El="health_check",Je="general",Me;var Re=D(()=>{Me=class Me extends Error{kind;hint;service;causeError;constructor(e,t,n){super(n?.cause?`${e}: ${t}: ${n.cause.message}`:`${e}: ${t}`);this.name="DevctlError",this.kind=e,this.hint=n?.hint??"",this.service=n?.service??"",this.causeError=n?.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}}}});import{spawnSync as uS}from"child_process";import{createHash as pS,randomBytes as Tl}from"crypto";import{copyFileSync as fS,existsSync as In,mkdirSync as gS,readdirSync as mS,readFileSync as Al,renameSync as Ll,statSync as hS,unlinkSync as Rl,writeFileSync as vS}from"fs";import{homedir as yS}from"os";import{basename as xS,dirname as Pl,join as dt,resolve as bS}from"path";function Nt(){let e=process.env.DEVCTL_HOME;if(e&&e!=="")return e;return dt(yS(),".devctl")}function Yt(e){gS(e,{recursive:!0,mode:wS})}function vn(e){let t=bS(e),n=process.platform==="win32"?t.toLowerCase():t;return pS("sha256").update(n).digest("hex").slice(0,kS)}function no(e){let t=dt(Nt(),"state",vn(e)),n=dt(Nt(),"sessions",vn(e));if(!In(t)&&In(n)){Yt(Pl(t));try{Ll(n,t)}catch{Yt(t);for(let r of["state.json","devctl.lock","devctl.sock"]){let o=dt(n,r);if(In(o))fS(o,dt(t,r))}}}return Yt(t),t}function Ns(){let e=dt(Nt(),"logs");return Yt(e),e}function dr(){let e=dt(Nt(),"exports");return Yt(e),e}function Gt(){let e=dt(Nt(),"credentials");return Yt(e),e}function Hs(e,t=process.platform){if(t==="win32")return`\\\\.\\pipe\\devctl-${vn(e)}`;return dt(no(e),"devctl.sock")}function CS(e){return dt(no(e),"devctl.lock")}function Hf(e){return dt(no(e),"state.json")}function ur(e){return dt(no(e),"bootstrap.log")}function Bf(e){let t=ur(e);if(!In(t))return;let n=no(e),r=dt(n,`${jf}${Dl()}.log`);try{Ll(t,r)}catch{return}ES(n)}function ES(e){let t;try{t=mS(e).filter((r)=>r.startsWith(jf)&&r.endsWith(".log"))}catch{return}let n=t.map((r)=>{let o=dt(e,r);try{return{path:o,mtime:hS(o).mtimeMs}}catch{return}}).filter((r)=>r!==void 0).sort((r,o)=>o.mtime-r.mtime);for(let r=_S;r<n.length;r++)try{Rl(n[r].path)}catch{}}function Ut(e,t){Yt(Pl(e));let n=dt(Pl(e),`.${xS(e)}.tmp-${process.pid}-${Tl(4).toString("hex")}`);vS(n,t,{mode:SS}),Ll(n,e)}function Dl(e=new Date){return`${e.toISOString().slice(0,19).replace(/:/g,"-")+"Z"}-${Tl(3).toString("hex")}`}function js(e){let t=e.indexOf("Z-"),n=t>=0?e.slice(0,t+1):e,r=n.indexOf("T");if(r<0||!n.endsWith("Z"))return;let o=n.slice(0,r),i=n.slice(r+1,-1).replace(/-/g,":"),s=new Date(`${o}T${i}Z`);return Number.isNaN(s.getTime())?void 0:s}function pr(e){return Ol(Hf(e))}function Ol(e){if(!In(e))return;try{let t=JSON.parse(Al(e,"utf8"));if(Array.isArray(t.processes)&&typeof t.repo_root==="string")return t;return}catch{return}}function Wf(e,t){Ut(Hf(e),`${JSON.stringify(t,null,2)}
|
|
4
|
-
`)}function Gf(e,t){let n=CS(e);if(In(n)){let r=RS(n);if(r&&Tt(r.pid))throw Error(`supervisor already running (pid ${r.pid})`);try{Rl(n)}catch{}}return Ut(n,JSON.stringify({pid:process.pid,socket:t})),{release:()=>{try{Rl(n)}catch{}}}}function RS(e){if(!In(e))return;try{let t=JSON.parse(Al(e,"utf8"));if(typeof t.pid==="number"&&typeof t.socket==="string")return{pid:t.pid,socket:t.socket}}catch{return}return}function Tt(e){if(e<=0)return!1;if(process.platform==="win32")return PS(e);try{return process.kill(e,0),!0}catch{return!1}}function Ml(e){try{let t=uS("cmd.exe",["/d","/c",`tasklist /FO CSV /NH /FI "PID eq ${e}"`],{encoding:"buffer",windowsHide:!0,timeout:5000});return TS(t.stdout)}catch{return""}}function PS(e){try{return process.kill(e,0),!0}catch{}let t=Ml(e).toLowerCase();if(t===""||t.includes("no tasks")||t.includes("no matching"))return!1;return t.includes(String(e))}function TS(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 $l(){return Tl(24).toString("hex")}function AS(e){return dt(no(e),"mcp-token")}function Uf(e){let t=AS(e);if(In(t)){let r=Al(t,"utf8").trim();if(r!=="")return r}let n=$l();return Ut(t,n),n}var wS=448,SS=384,kS=16,_S=5,jf="bootstrap-";var ze=()=>{};function ro(){return{args:[],shell:!1}}function Fl(){return{vars:{},required:[],defaults:{}}}function Nl(){return{type:"",url:"",address:"",command:ro(),interval_seconds:0,timeout_seconds:0,start_period_seconds:0,unhealthy_threshold:3,healthy_reset_threshold:10}}function wt(e){return typeof e==="string"?e:e.service}function Fn(e){return typeof e==="string"?"service_started":e.condition||"service_started"}function Ws(e){return Fn(e)==="service_healthy"?`${wt(e)} (healthy)`:wt(e)}function Hl(){return{type:"",mode:"",service_account:"",config:{}}}function Nn(){return{extends:"",description:"",command:ro(),shell:!1,working_dir:"",dependencies:[],ports:[],environment:Fl(),health:Nl(),identity:Hl(),logs:{stdout:!1,stderr:!1},restart:{policy:"",max_retries:0,backoff_seconds:0},startup:{wait_for_healthy:!1,timeout_seconds:0},capabilities:[],proxy:[],container:void 0,hooks:{pre_start:ro(),post_start:ro()}}}function fr(){return{version:1,project:{name:""},google:{project_id:"",region:""},profiles:{},templates:{},services:{},tasks:{},proxy:{enabled:!1,listen:{host:"127.0.0.1",port:0},token_endpoint:{enabled:!1,host:"",port:0},routes:[]},logs:{max_memory_events:50000,persistence:{enabled:!0,directory:"~/.devctl/logs",retention_days:14,max_session_logs:0}},auth:{refresh_threshold_seconds:300},shutdown:{grace_seconds:10},ui:{theme:"system",keymap:{}},secrets:{extra_markers:[],extra_patterns:[]},doctor:{tools:[]},plugins:[],environment:{sources:[],secrets:{}},provenance:{},repoRoot:"",configPath:""}}function io(e){return e.args.length===0||e.args.length===1&&(e.args[0]??"").trim()===""}function gi(e){if(e.type!=="")return e.type;return e.mode}function yn(e){let t=gi(e).toLowerCase();return t==="service"||t==="service_account"}function Jf(e){let t=gi(e).toLowerCase();return t==="user"||t===""}function zf(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 gr(e){let t=e.host===""?"127.0.0.1":e.host;if(e.port===0)return t;return`${t}:${e.port}`}function Gs(e){if(e.refresh_threshold_seconds<=0)return 300;return e.refresh_threshold_seconds}function Us(e){if(e.stop_services_on_exit===void 0)return!0;return e.stop_services_on_exit}function so(e){if(e.grace_seconds<=0)return 10;return e.grace_seconds}function Yf(e){if(!e.logs.stdout&&!e.logs.stderr)return!0;return e.logs.stdout}function Xf(e){if(!e.logs.stdout&&!e.logs.stderr)return!0;return e.logs.stderr}function jl(e,t){return e.find((n)=>n.name===t)}function Qf(e){return e[0]}var oo=1,Kf="never",qf="on_failure",Vf="always",Bs=8080,Il="127.0.0.1";function F(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Wl(e){return F(e)?new Set(Object.keys(e)):new Set}function K(e){if(typeof e==="string")return e;if(typeof e==="number"||typeof e==="boolean")return String(e);return""}function xe(e){if(typeof e==="number")return e;if(typeof e==="string"){let t=Number(e);return Number.isNaN(t)?0:t}return 0}function it(e){return e===!0}function Lt(e){if(!Array.isArray(e))return[];return e.map((t)=>K(t))}function Gl(e){if(!Array.isArray(e))return[];return e.map((t)=>F(t)?{service:K(t.service),condition:K(t.condition)||"service_started"}:K(t))}function Hn(e){if(!F(e))return{};let t={};for(let[n,r]of Object.entries(e))t[n]=K(r);return t}function Kt(e){if(typeof e==="string")return{args:e.split(/\s+/).filter((t)=>t!==""),shell:!1};if(Array.isArray(e))return{args:e.map((t)=>K(t)),shell:!1};return ro()}function Ul(e){if(e===void 0||e===null)return[];if(typeof e==="string"||typeof e==="number")return[Bl(e,"http")];if(Array.isArray(e))return e.map((t,n)=>Bl(t,`port_${n}`));if(F(e))return Object.entries(e).map(([t,n])=>Bl(n,t));return[]}function Bl(e,t){if(typeof e==="string"&&e.toLowerCase()==="auto")return{name:t,value:0,auto:!0};return{name:t,value:xe(e),auto:!1}}function Zf(e){if(!F(e))return Fl();let t={},n=[],r={};for(let[o,i]of Object.entries(e))if(o==="required")n=Lt(i);else if(o==="defaults")r=Hn(i);else t[o]=K(i);return{vars:t,required:n,defaults:r}}function LS(e){if(!F(e))return Hl();return{type:K(e.type),mode:K(e.mode),service_account:K(e.service_account),config:F(e.config)?{...e.config}:{}}}function DS(e){if(!F(e))return Nl();return{type:K(e.type),url:K(e.url),address:K(e.address),command:Kt(e.command),interval_seconds:xe(e.interval_seconds),timeout_seconds:xe(e.timeout_seconds),start_period_seconds:xe(e.start_period_seconds),unhealthy_threshold:e.unhealthy_threshold===void 0?3:xe(e.unhealthy_threshold),healthy_reset_threshold:e.healthy_reset_threshold===void 0?10:xe(e.healthy_reset_threshold)}}function OS(e){if(!F(e))return{policy:"",max_retries:0,backoff_seconds:0};return{enabled:e.enabled===void 0?void 0:it(e.enabled),policy:K(e.policy),max_retries:xe(e.max_retries),backoff_seconds:xe(e.backoff_seconds)}}function MS(e){if(!F(e))return{wait_for_healthy:!1,timeout_seconds:0};return{wait_for_healthy:it(e.wait_for_healthy),timeout_seconds:xe(e.timeout_seconds)}}function mi(e){if(!F(e))return Nn();let t=F(e.logs)?e.logs:{};return{extends:K(e.extends),description:K(e.description),command:Kt(e.command),shell:it(e.shell),working_dir:K(e.working_dir),dependencies:Gl(e.dependencies),ports:Ul(e.ports),environment:Zf(e.environment),health:DS(e.health),identity:LS(e.identity),logs:{stdout:it(t.stdout),stderr:it(t.stderr)},restart:OS(e.restart),startup:MS(e.startup),capabilities:Lt(e.capabilities),proxy:ql(e.proxy),container:Kl(e.container),hooks:$S(e.hooks)}}function $S(e){let t=F(e)?e:{};return{pre_start:Kt(t.pre_start),post_start:Kt(t.post_start)}}function eg(e){let t=F(e)?e:{};return{command:Kt(t.command),shell:it(t.shell),working_dir:K(t.working_dir),dependencies:Lt(t.dependencies),environment:Zf(t.environment)}}function Kl(e){if(!F(e))return;let t={};if(F(e.ports))for(let[n,r]of Object.entries(e.ports))t[n]=xe(r);return{image:K(e.image),runtime:K(e.runtime),ports:t,env:Hn(e.env),volumes:Lt(e.volumes)}}function ql(e){if(e===void 0||e===null)return[];if(Array.isArray(e))return e.map((t)=>mr(t));if(F(e))return[mr(e)];return[]}function Ks(e){if(!F(e))return{services:[],environment:{}};return{services:Lt(e.services),environment:Hn(e.environment)}}function IS(e){if(typeof e==="string")return{type:e,service_account:""};if(!F(e))return{type:"",service_account:""};return{type:K(e.type),service_account:K(e.service_account)}}function FS(e){if(!F(e))return{type:"",identity:{type:"",service_account:""},audience:"",service_account:""};return{type:K(e.type),identity:IS(e.identity),audience:K(e.audience),service_account:K(e.service_account)}}function mr(e){if(!F(e))return{name:"",match:{host:"",path:""},upstream:{url:""},auth:{type:"",identity:{type:"",service_account:""},audience:"",service_account:""}};let t=F(e.match)?e.match:{},n=F(e.upstream)?e.upstream:{};return{name:K(e.name),match:{host:K(t.host),path:K(t.path)},upstream:{url:K(n.url)},auth:FS(e.auth)}}var Vl=()=>{};import{existsSync as NS,statSync as ng}from"fs";import{basename as tg,dirname as qs,isAbsolute as HS,join as Vs,resolve as rg}from"path";function jn(e,t){if(t!=="")return jS(t);let n=e===""?process.cwd():e;n=HS(n)?n:rg(n);for(;;){let r=Vs(n,St,qt);if(hi(r))return{repoRoot:n,configPath:r};let o=Vs(n,"devctl.yaml");if(hi(o))return{repoRoot:n,configPath:o};let i=qs(n);if(i===n)break;n=i}throw ke(cr,"no devctl configuration found","run `devctl setup` or create a .devctl/config.yaml in the repository root")}function jS(e){let t=rg(e),n;try{n=ng(t)}catch(o){throw fe(cr,"config path not found",o)}if(n.isDirectory()){if(tg(t)===St)return{repoRoot:qs(t),configPath:Vs(t,qt)};return{repoRoot:t,configPath:Vs(t,qt)}}let r=qs(t);if(tg(r)===St)r=qs(r);return{repoRoot:r,configPath:t}}function hi(e){return NS(e)&&!ng(e).isDirectory()}var St=".devctl",qt="config.yaml";var vi=D(()=>{Re()});function Ys(){return{services:{},templates:{},provenance:{}}}function Bn(e,t,n,r,o=""){if(F(t)&&Object.keys(t).length>0){for(let[i,s]of Object.entries(t))Bn(e,s,n,r,o===""?i:`${o}.${i}`);return}if(o==="")return;(e[o]??=[]).push({source:n,layer:r})}function Js(e,t,n){let r=Wl(n);if(F(n))for(let i of BS){let s=n[i];if(F(s))for(let a of Object.keys(s))r.add(`${i}.${a}`)}let o=e[t];e[t]=o?new Set([...o,...r]):r}function og(e,t,n=Ys(),r={source:"unknown",layer:"unknown"}){if(Bn(n.provenance,t,r.source,r.layer),t.version!==void 0)e.version=xe(t.version);if(F(t.project)&&t.project.name!==void 0)e.project.name=K(t.project.name);if(F(t.google)){if(t.google.project_id!==void 0)e.google.project_id=K(t.google.project_id);if(t.google.region!==void 0)e.google.region=K(t.google.region)}if(F(t.profiles))for(let[o,i]of Object.entries(t.profiles)){let s=e.profiles[o];e.profiles[o]=s?GS(s,i):Ks(i)}if(F(t.templates))for(let[o,i]of Object.entries(t.templates)){let s=e.templates[o];e.templates[o]=s?zs(s,i):mi(i),Js(n.templates,o,i)}if(F(t.services))for(let[o,i]of Object.entries(t.services)){let s=e.services[o];e.services[o]=s?zs(s,i):mi(i),Js(n.services,o,i)}if(F(t.tasks))for(let[o,i]of Object.entries(t.tasks))e.tasks[o]=e.tasks[o]?US(e.tasks[o],i):eg(i);if(F(t.proxy))WS(e.proxy,t.proxy);if(F(t.logs)){if(t.logs.max_memory_events!==void 0)e.logs.max_memory_events=xe(t.logs.max_memory_events);if(F(t.logs.persistence)){let o=t.logs.persistence;if(o.enabled!==void 0)e.logs.persistence.enabled=it(o.enabled);if(o.directory!==void 0)e.logs.persistence.directory=K(o.directory);if(o.retention_days!==void 0)e.logs.persistence.retention_days=xe(o.retention_days);if(o.max_session_logs!==void 0)e.logs.persistence.max_session_logs=xe(o.max_session_logs)}}if(F(t.auth)&&t.auth.refresh_threshold_seconds!==void 0)e.auth.refresh_threshold_seconds=xe(t.auth.refresh_threshold_seconds);if(F(t.shutdown)){if(t.shutdown.stop_services_on_exit!==void 0)e.shutdown.stop_services_on_exit=it(t.shutdown.stop_services_on_exit);if(t.shutdown.grace_seconds!==void 0)e.shutdown.grace_seconds=xe(t.shutdown.grace_seconds)}if(F(t.ui)){if(t.ui.theme!==void 0)e.ui.theme=K(t.ui.theme);if(t.ui.keymap!==void 0)e.ui.keymap=Hn(t.ui.keymap)}if(F(t.secrets)){if(t.secrets.extra_markers!==void 0)e.secrets.extra_markers=Lt(t.secrets.extra_markers);if(t.secrets.extra_patterns!==void 0)e.secrets.extra_patterns=Lt(t.secrets.extra_patterns)}if(F(t.doctor)&&Array.isArray(t.doctor.tools))e.doctor.tools=t.doctor.tools.filter(F).map((o)=>({name:K(o.name),command:K(o.command)}));if(Array.isArray(t.plugins))e.plugins=t.plugins.filter(F).map((o)=>({path:K(o.path)})).filter((o)=>o.path!=="");if(F(t.environment)){if(Array.isArray(t.environment.sources))e.environment.sources=Lt(t.environment.sources);if(F(t.environment.secrets))e.environment.secrets={...e.environment.secrets,...Hn(t.environment.secrets)}}}function WS(e,t){if(t.enabled!==void 0)e.enabled=it(t.enabled);if(F(t.listen)){if(t.listen.host!==void 0)e.listen.host=K(t.listen.host);if(t.listen.port!==void 0)e.listen.port=xe(t.listen.port)}if(F(t.token_endpoint)){let n=t.token_endpoint;if(n.enabled!==void 0)e.token_endpoint.enabled=it(n.enabled);if(n.host!==void 0)e.token_endpoint.host=K(n.host);if(n.port!==void 0)e.token_endpoint.port=xe(n.port)}if(Array.isArray(t.routes))e.routes=t.routes.map((n)=>mr(n))}function GS(e,t){if(!F(t))return e;return{services:t.services!==void 0?Lt(t.services):e.services,environment:t.environment!==void 0?{...e.environment,...Hn(t.environment)}:e.environment}}function US(e,t){if(!F(t))return e;return{command:t.command!==void 0?Kt(t.command):e.command,shell:t.shell!==void 0?it(t.shell):e.shell,working_dir:t.working_dir!==void 0?K(t.working_dir):e.working_dir,dependencies:t.dependencies!==void 0?Lt(t.dependencies):e.dependencies,environment:ig(e.environment,t.environment)}}function zs(e,t){if(!F(t))return e;let n=Wl(t),r={...e,environment:ig(e.environment,t.environment),health:qS(e.health,t.health),identity:VS(e.identity,t.identity),logs:JS(e.logs,t.logs),restart:zS(e.restart,t.restart),startup:YS(e.startup,t.startup),container:XS(e.container,t.container),hooks:KS(e.hooks,t.hooks)};if(n.has("extends"))r.extends=K(t.extends);if(n.has("description"))r.description=K(t.description);if(n.has("command"))r.command=Kt(t.command);if(n.has("shell"))r.shell=it(t.shell);if(n.has("working_dir"))r.working_dir=K(t.working_dir);if(n.has("dependencies"))r.dependencies=Gl(t.dependencies);if(n.has("ports"))r.ports=Ul(t.ports);if(n.has("capabilities"))r.capabilities=Lt(t.capabilities);if(n.has("proxy"))r.proxy=ql(t.proxy);return r}function KS(e,t){if(!F(t))return e;return{pre_start:t.pre_start!==void 0?Kt(t.pre_start):e.pre_start,post_start:t.post_start!==void 0?Kt(t.post_start):e.post_start}}function ig(e,t){if(!F(t))return e;let n={...e.vars},r={...e.defaults},o=e.required;for(let[i,s]of Object.entries(t))if(i==="required")o=Lt(s);else if(i==="defaults")Object.assign(r,Hn(s));else n[i]=K(s);return{vars:n,required:o,defaults:r}}function qS(e,t){if(!F(t))return e;return{type:t.type!==void 0?K(t.type):e.type,url:t.url!==void 0?K(t.url):e.url,address:t.address!==void 0?K(t.address):e.address,command:t.command!==void 0?Kt(t.command):e.command,interval_seconds:t.interval_seconds!==void 0?xe(t.interval_seconds):e.interval_seconds,timeout_seconds:t.timeout_seconds!==void 0?xe(t.timeout_seconds):e.timeout_seconds,start_period_seconds:t.start_period_seconds!==void 0?xe(t.start_period_seconds):e.start_period_seconds,unhealthy_threshold:t.unhealthy_threshold!==void 0?xe(t.unhealthy_threshold):e.unhealthy_threshold,healthy_reset_threshold:t.healthy_reset_threshold!==void 0?xe(t.healthy_reset_threshold):e.healthy_reset_threshold}}function VS(e,t){if(!F(t))return e;return{type:t.type!==void 0?K(t.type):e.type,mode:t.mode!==void 0?K(t.mode):e.mode,service_account:t.service_account!==void 0?K(t.service_account):e.service_account,config:t.config!==void 0&&F(t.config)?{...e.config??{},...t.config}:e.config}}function JS(e,t){if(!F(t))return e;return{stdout:t.stdout!==void 0?it(t.stdout):e.stdout,stderr:t.stderr!==void 0?it(t.stderr):e.stderr}}function zS(e,t){if(!F(t))return e;return{enabled:t.enabled!==void 0?it(t.enabled):e.enabled,policy:t.policy!==void 0?K(t.policy):e.policy,max_retries:t.max_retries!==void 0?xe(t.max_retries):e.max_retries,backoff_seconds:t.backoff_seconds!==void 0?xe(t.backoff_seconds):e.backoff_seconds}}function YS(e,t){if(!F(t))return e;return{wait_for_healthy:t.wait_for_healthy!==void 0?it(t.wait_for_healthy):e.wait_for_healthy,timeout_seconds:t.timeout_seconds!==void 0?xe(t.timeout_seconds):e.timeout_seconds}}function XS(e,t){if(!F(t))return e;let n=Kl(t);if(!n)return e;return{image:t.image!==void 0?n.image:e?.image??"",runtime:t.runtime!==void 0?n.runtime:e?.runtime??"",ports:t.ports!==void 0?{...e?.ports??{},...n.ports}:e?.ports??{},env:t.env!==void 0?{...e?.env??{},...n.env}:e?.env??{},volumes:t.volumes!==void 0?n.volumes:e?.volumes??[]}}function sg(e,t){let n=Object.keys(e.services).sort();for(let r of n){let o=e.services[r]?.proxy??[];if(o.length===0)continue;o.forEach((i,s)=>{let c={name:o.length===1?r:`${r}-${s+1}`,match:i.match,upstream:i.upstream,auth:i.auth},l=e.proxy.routes.length;if(e.proxy.routes.push(c),t)Bn(t,c,`synthesized from services.${r}.proxy`,"synthesized",`proxy.routes.${l}`)})}}function ag(e,t=Ys()){if(Object.keys(e.templates).length===0)return;let n={};for(let[r,o]of Object.entries(e.services))n[r]=cg(e,o,t.services[r]??new Set,t,{});e.services=n}function cg(e,t,n,r,o){if(t.extends==="")return t;if(o[t.extends])throw Error(`template cycle involving "${t.extends}"`);let i=e.templates[t.extends]??Nn();if(!e.templates[t.extends])throw Error(`service extends unknown template "${t.extends}"`);let s={...o,[t.extends]:!0},a=r.templates[t.extends]??new Set,c=cg(e,i,a,r,s),l=QS(c,t,n);return l.extends=t.extends,l}function QS(e,t,n){let r={...e};if(n.has("extends"))r.extends=t.extends;if(n.has("description"))r.description=t.description;if(n.has("command"))r.command=t.command;if(n.has("shell"))r.shell=t.shell;if(n.has("working_dir"))r.working_dir=t.working_dir;if(n.has("dependencies"))r.dependencies=t.dependencies;if(n.has("ports"))r.ports=t.ports;if(n.has("capabilities"))r.capabilities=t.capabilities;if(n.has("proxy"))r.proxy=t.proxy;if(n.has("container")){let o=t.container,i=e.container;r.container=o&&i?{image:n.has("container.image")?o.image:i.image,runtime:n.has("container.runtime")?o.runtime:i.runtime,ports:n.has("container.ports")?o.ports:i.ports,env:n.has("container.env")?o.env:i.env,volumes:n.has("container.volumes")?o.volumes:i.volumes}:o??i}return r.hooks={pre_start:n.has("hooks.pre_start")?t.hooks.pre_start:e.hooks.pre_start,post_start:n.has("hooks.post_start")?t.hooks.post_start:e.hooks.post_start},r.health={type:n.has("health.type")?t.health.type:e.health.type,url:n.has("health.url")?t.health.url:e.health.url,address:n.has("health.address")?t.health.address:e.health.address,command:n.has("health.command")?t.health.command:e.health.command,interval_seconds:n.has("health.interval_seconds")?t.health.interval_seconds:e.health.interval_seconds,timeout_seconds:n.has("health.timeout_seconds")?t.health.timeout_seconds:e.health.timeout_seconds,start_period_seconds:n.has("health.start_period_seconds")?t.health.start_period_seconds:e.health.start_period_seconds,unhealthy_threshold:n.has("health.unhealthy_threshold")?t.health.unhealthy_threshold:e.health.unhealthy_threshold,healthy_reset_threshold:n.has("health.healthy_reset_threshold")?t.health.healthy_reset_threshold:e.health.healthy_reset_threshold},r.identity={type:n.has("identity.type")?t.identity.type:e.identity.type,mode:n.has("identity.mode")?t.identity.mode:e.identity.mode,service_account:n.has("identity.service_account")?t.identity.service_account:e.identity.service_account,config:n.has("identity.config")?t.identity.config:e.identity.config},r.logs={stdout:n.has("logs.stdout")?t.logs.stdout:e.logs.stdout,stderr:n.has("logs.stderr")?t.logs.stderr:e.logs.stderr},r.restart={enabled:n.has("restart.enabled")?t.restart.enabled:e.restart.enabled,policy:n.has("restart.policy")?t.restart.policy:e.restart.policy,max_retries:n.has("restart.max_retries")?t.restart.max_retries:e.restart.max_retries,backoff_seconds:n.has("restart.backoff_seconds")?t.restart.backoff_seconds:e.restart.backoff_seconds},r.startup={wait_for_healthy:n.has("startup.wait_for_healthy")?t.startup.wait_for_healthy:e.startup.wait_for_healthy,timeout_seconds:n.has("startup.timeout_seconds")?t.startup.timeout_seconds:e.startup.timeout_seconds},r.environment={vars:{...e.environment.vars,...t.environment.vars},defaults:{...e.environment.defaults,...t.environment.defaults},required:n.has("environment.required")?t.environment.required:e.environment.required},r}var BS;var lg=D(()=>{Vl();BS=["environment","restart","startup","health","logs","identity","container","hooks"]});function Jl(e){if(e.version===0)throw L(Z,"version is required");if(e.version===oo)return e;throw L(Z,`unsupported config version ${e.version} (expected ${oo}); no migration is available`)}var zl=D(()=>{Re()});var dg,ug,pg,fg,gg,mg,hg,vg,yg,Yl,Xl,Ql,Zl,xg,bg,wg,Sg,kg,Cg,_g,Eg,ed,Rg,Pg,Tg,Ag,Lg,Dg,Og,Mg,$g,Ig,Fg,Ng;var td=D(()=>{dg=["version","project","google","profiles","templates","services","tasks","proxy","logs","auth","shutdown","ui","secrets","doctor","plugins","environment"],ug=["extends","description","command","shell","working_dir","dependencies","ports","environment","health","identity","logs","restart","startup","capabilities","proxy","container","hooks"],pg=["type","url","address","command","interval_seconds","timeout_seconds","start_period_seconds","unhealthy_threshold","healthy_reset_threshold"],fg=["service","condition"],gg=["type","mode","service_account","config"],mg=["enabled","policy","max_retries","backoff_seconds"],hg=["wait_for_healthy","timeout_seconds"],vg=["enabled","listen","token_endpoint","routes"],yg=["host","port"],Yl=["name","match","upstream","auth"],Xl=["host","path"],Ql=["url"],Zl=["type","identity","audience","service_account"],xg=["max_memory_events","persistence"],bg=["enabled","directory","retention_days","max_session_logs"],wg=["refresh_threshold_seconds"],Sg=["stop_services_on_exit","grace_seconds"],kg=["theme","keymap"],Cg=["name"],_g=["project_id","region"],Eg=["services","environment"],ed=["required","defaults"],Rg=["stdout","stderr"],Pg=["extra_markers","extra_patterns"],Tg=["tools"],Ag=["name","command"],Lg=["enabled","host","port"],Dg=["path"],Og=["sources","secrets"],Mg=["image","runtime","ports","env","volumes"],$g=["pre_start","post_start"],Ig=["command","shell","working_dir","dependencies","environment"],Fg=["google","google_api","iap","network","service_identity","local_http"],Ng=["|","||","&&",";",">",">>","<","&"]});function Wn(e,t){if(Array.isArray(e))return e.flatMap((o,i)=>Wn(o,Hg(t,String(i))));if(!sk(e))return[];let n=tk(t),r=[];for(let o of Object.keys(e)){let i=Hg(t,o);if(n.length>0&&!n.includes(o)&&!ek(t))r.push(i);r.push(...Wn(e[o],i))}return r}function ek(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(".identity.config")||e.includes(".identity.config."))return!0;return e.includes(".environment.")&&!e.endsWith(".environment")}function tk(e){switch(e){case"":return dg;case"project":return Cg;case"google":return _g;case"proxy":return vg;case"proxy.listen":return yg;case"proxy.token_endpoint":return Lg;case"logs":return xg;case"logs.persistence":return bg;case"auth":return wg;case"shutdown":return Sg;case"ui":return kg;case"secrets":return Pg;case"doctor":return Tg;case"environment":return Og;default:return nk(e)}}function nk(e){if(e==="services"||e==="profiles"||e==="templates"||e==="tasks")return[];if(e.startsWith("services.")||e.startsWith("templates.")){if(e.includes(".dependencies."))return fg;return rk(e)}if(e.startsWith("profiles.")){if(e.split(".").length===2)return Eg}if(e.startsWith("tasks.")){let t=e.split(".");if(t.length===2)return Ig;if(t[2]==="environment")return ed}if(e.includes("routes"))return ik(e);if(e.startsWith("doctor.tools")&&e.split(".").length>=3)return Ag;if(e==="plugins")return[];if(e.startsWith("plugins.")&&e.split(".").length===2)return Dg;return[]}function rk(e){let t=e.split(".");if(t.length===2)return ug;if(t.length>=3)switch(t[2]){case"health":return pg;case"identity":return gg;case"restart":return mg;case"startup":return hg;case"logs":return Rg;case"environment":return ed;case"proxy":return ok(t);case"container":return Mg;case"hooks":return $g;default:return[]}return[]}function ok(e){let t=e.slice(3),n=t[0]!==void 0&&/^\d+$/.test(t[0])?1:0,r=t[n]??"";if(r==="match")return Xl;if(r==="upstream")return Ql;if(r==="auth")return Zl;return Yl}function ik(e){if(e==="proxy.routes")return[];if(e.endsWith(".match"))return Xl;if(e.endsWith(".upstream"))return Ql;if(e.endsWith(".auth"))return Zl;if(e.includes("proxy.routes")&&e.split(".").length===ZS+1)return Yl;return[]}function Hg(e,t){if(e==="")return t;return`${e}.${t}`}function sk(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function ao(e){return`unknown fields: ${e.join(", ")}`}var ZS=2;var jg=D(()=>{td()});function Bg(e,t,n){let r=e,o="";for(;;){let i=r.indexOf("${");if(i<0)return o+r;o+=r.slice(0,i);let s=r.slice(i).indexOf("}");if(s<0)throw Error(`unclosed environment reference in "${e}"`);let a=r.slice(i+2,i+s);o+=ak(a,t,n),r=r.slice(i+s+1)}}function ak(e,t,n){let r=e.split(".");if(r.length<3||r[0]!=="services")throw Error(`unsupported reference \${${e}}`);let o=r[1]??"",i=t.services[o];if(!i)throw Error(`reference \${${e}}: unknown service`);let s=n[o];if(r[2]==="port"){if(s){if(s.http!==void 0)return String(s.http);let c=Object.values(s)[0];if(c!==void 0)return String(c)}let a=Qf(i.ports);if(a&&!a.auto)return String(a.value)}if(r[2]==="ports"){let a=r[3];if(!a)throw Error(`reference \${${e}}: missing port name`);if(s&&s[a]!==void 0)return String(s[a]);let c=jl(i.ports,a);if(c&&!c.auto)return String(c.value);let l=Number.parseInt(a,10);if(!Number.isNaN(l)&&l>=0&&l<i.ports.length){let d=i.ports[l];if(d&&!d.auto)return String(d.value)}}throw Error(`unresolvable reference \${${e}}`)}function nd(e,t,n){let r={};for(let[o,i]of Object.entries(e))r[o]=Bg(i,t,n);return r}function Wg(e){let t=[],n=e;for(;;){let r=n.indexOf("${");if(r<0)return t;let o=n.slice(r).indexOf("}");if(o<0)return t;t.push(n.slice(r+2,r+o)),n=n.slice(r+o+1)}}function Gg(e,t){let n=e.split(".");if(n.length<2)return!1;if(n[0]!=="services"||n.length<3)return!1;let r=t.services[n[1]??""];if(!r)return!1;if(n[2]==="port"||n[2]==="ports"){if(n.length===3)return r.ports.length>0;if(n.length>=4){let o=n[3]??"";if(!Number.isNaN(Number.parseInt(o,10)))return!0;return jl(r.ports,o)!==void 0}}return!0}var rd=()=>{};import{existsSync as ck}from"fs";import{isAbsolute as lk,resolve as dk}from"path";import{fileURLToPath as uk}from"url";function od(e){let t=[];for(let[n,r]of Object.entries(e.services)){let o=r.health.type;if(o!==""&&!qg.includes(o.toLowerCase()))t.push({service:n,type:o})}return t}function Xt(e){let t=[];if(e.version===0)t.push("version is required");else if(e.version!==oo)t.push(`unsupported config version ${e.version} (expected ${oo}); no migration is available`);if(Object.keys(e.services).length===0)t.push("at least one service must be defined");t.push(...gk(e)),t.push(...fk(e)),t.push(...yk(e)),t.push(...xk(e)),t.push(...bk(e));for(let[n,r]of e.plugins.entries())if(r.path==="")t.push(`plugins.${n}.path is required`);else try{let o=r.path.startsWith("file:")?uk(r.path):lk(r.path)?r.path:dk(e.repoRoot,r.path);if(!ck(o))t.push(`plugins.${n}.path does not exist: ${r.path}`)}catch{t.push(`plugins.${n}.path is invalid: ${r.path}`)}if(e.logs.max_memory_events<0)t.push("logs.max_memory_events must be >= 0");return t}function fk(e){let t=[];for(let[n,r]of Object.entries(e.tasks)){let o=`tasks.${n}`;if(io(r.command))t.push(`${o}.command is required`);t.push(...Xs(o,r.command,r.shell));for(let i of r.dependencies)if(!e.services[i])t.push(`${o}.dependencies: unknown service "${i}"`);t.push(...Vg(`${o}.environment`,r.environment,e))}return t}function gk(e){let t=[],n={};for(let[r,o]of Object.entries(e.services)){let i=`services.${r}`;if(io(o.command)&&!o.container)t.push(`${i}.command is required`);t.push(...Xs(i,o.command,o.shell)),t.push(...Xs(`${i}.hooks.pre_start`,o.hooks.pre_start,o.shell)),t.push(...Xs(`${i}.hooks.post_start`,o.hooks.post_start,o.shell)),t.push(...Sk(i,o.capabilities));for(let c of o.dependencies){let l=wt(c);if(!e.services[l])t.push(`${i}.dependencies: unknown service "${l}"`);if(l===r)t.push(`${i}.dependencies: service cannot depend on itself`);if(!["service_started","service_healthy"].includes(Fn(c)))t.push(`${i}.dependencies: condition must be service_started or service_healthy`);if(Fn(c)==="service_healthy"&&e.services[l]?.health.type==="")t.push(`${i}.dependencies: service_healthy requires ${l} to define a health check`)}if(o.extends!==""&&!e.templates[o.extends])t.push(`${i}.extends: unknown template "${o.extends}"`);for(let c of o.ports.filter((l)=>!l.auto))if(c.value<Zs||c.value>Qs)t.push(`${i}.ports.${c.name}: invalid port ${c.value}`);else if(n[c.value])t.push(`duplicate port ${c.value} used by ${n[c.value]} and ${r}`);else n[c.value]=r;let s=vk(`${i}.identity`,o.identity,e.plugins.length>0);if(s!=="")t.push(s);if(t.push(...mk(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=zf(o.restart);if(a!==Kf&&a!==qf&&a!==Vf)t.push(`${i}.restart.policy must be never, on_failure, or always`);if(t.push(...Vg(`${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[c,l]of Object.entries(o.container.ports)){if(!o.ports.some((d)=>d.name===c))t.push(`${i}.container.ports.${c}: no matching service port`);if(l<Zs||l>Qs)t.push(`${i}.container.ports.${c}: invalid container port ${l}`)}}}return t}function mk(e,t,n){let r=[];if(t.health.type==="")return r;let o=t.health.type.toLowerCase();if(!qg.includes(o)&&!n)r.push(`${e}.health.type must be http, tcp, process, or command`);if(o==="http"&&t.health.url==="")r.push(`${e}.health.url is required for http health checks`);if(o==="tcp"&&t.health.address===""&&t.ports.length===0)r.push(`${e}.health.address is required for tcp health checks without ports`);if(o==="command"&&io({args:t.health.command.args,shell:!1}))r.push(`${e}.health.command is required for command health checks`);return r}function vk(e,t,n){let r=gi(t).toLowerCase();if(r===""||r==="user")return"";if(r==="service"||r==="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(n)return"";return`${e}.type must be user or service_account`}function id(e){let t=[];for(let[n,r]of Object.entries(e.services)){let o=gi(r.identity).toLowerCase();if(!hk.includes(o))t.push({service:n,type:o})}return t}function yk(e){let t={},n=[],r=[],o=(i)=>{let s=t[i]??pk;if(s===Kg)return;if(s===Ug){n.push(`dependency cycle: ${[...r,i].join(" \u2192 ")}`);return}t[i]=Ug,r.push(i);let a=e.services[i];if(a)for(let c of a.dependencies){let l=wt(c);if(e.services[l])o(l)}r.pop(),t[i]=Kg};for(let i of Object.keys(e.services))o(i);return n}function Vg(e,t,n){let r=[],o=(i,s)=>{for(let a of Wg(s))if(!Gg(a,n))r.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 r}function xk(e){let t=[];for(let[n,r]of Object.entries(e.profiles))for(let o of r.services)if(!e.services[o])t.push(`profiles.${n} references unknown service "${o}"`);return t}function bk(e){let t=[];if(e.proxy.listen.host!==""&&!kk(e.proxy.listen.host))t.push("proxy.listen.host must be an IP address or localhost");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<Zs||e.proxy.listen.port>Qs))t.push("proxy.listen.port is invalid");let n={};return e.proxy.routes.forEach((r,o)=>{let i=`proxy.routes[${o}]`;if(r.name==="")t.push(`${i}.name is required`);else if(n[r.name])t.push(`${i}: duplicate route name ${r.name}`);if(n[r.name]=!0,r.upstream.url==="")t.push(`${i}.upstream.url is required`);if(r.auth.type.toLowerCase()==="iap"){if(r.auth.audience.trim()==="")t.push(`${i}.auth.audience is required when auth.type is iap`);if(r.auth.identity.type.trim()==="")t.push(`${i}.auth.identity.type is required when auth.type is iap`)}let s=r.auth.identity.type.toLowerCase();if(s==="service"||s==="service_account"||yn({type:s,mode:"",service_account:""})){if((r.auth.identity.service_account||r.auth.service_account)==="")t.push(`${i}.auth.identity.service_account is required`)}}),t.push(...wk(e)),t}function wk(e){let t=[],n=e.proxy.token_endpoint;if(!n.enabled)return t;let r=n.host||Il;if(r==="0.0.0.0")t.push("proxy.token_endpoint.host must be a loopback address");else if(r!==""&&r!==Il&&r!=="localhost"&&!r.startsWith("127."))t.push("proxy.token_endpoint.host must be a loopback address");if(n.port!==0&&(n.port<Zs||n.port>Qs))t.push("proxy.token_endpoint.port is invalid");return t}function Xs(e,t,n){if(t.shell||n)return[];for(let r of t.args)if(Ng.includes(r)||r.includes("|")||r.includes(";")||r.includes("&&"))return[`${e}.command contains shell metacharacters; set shell: true to run via a shell`];return[]}function Sk(e,t){let n=[];for(let r of t)if(!Fg.includes(r))n.push(`${e}.capabilities: unknown capability "${r}"`);return n}function kk(e){if(e==="localhost")return!0;return Ck(e)}function Ck(e){if(/^(\d{1,3}\.){3}\d{1,3}$/.test(e))return e.split(".").every((n)=>{let r=Number(n);return r>=0&&r<=255});return e.includes(":")}var Qs=65535,Zs=1,qg,pk=0,Ug=1,Kg=2,hk;var ea=D(()=>{td();rd();qg=["http","tcp","process","command"];hk=["","user","service","service_account"]});import{readdirSync as _k,readFileSync as Ek}from"fs";import{basename as zg,dirname as Rk,extname as Pk,join as hr,resolve as Tk}from"path";import{parse as Ak}from"yaml";function co(e,t,n){try{return xi(e,t,{candidateText:n}),[]}catch(r){if(r instanceof Me){let o=`${r.kind}: `;return[r.message.startsWith(o)?r.message.slice(o.length):r.message]}return[r instanceof Error?r.message:String(r)]}}function ut(e,t){let{repoRoot:n,configPath:r}=jn(e,t);return xi(n,r)}function yi(e,t){try{return ut(e,t)}catch(n){if(!Fs(n,cr))throw n;let r=e===""?process.cwd():Tk(e),o=fr();return o.repoRoot=r,o.configPath=hr(r,St,qt),o}}function xi(e,t,n){let r=fr(),o=Ys();Yg(t,r,o,n?.candidateText,"main"),r.repoRoot=e,r.configPath=t;let i=Rk(t);if(zg(i)===St)Dk(i,r,o);r=Lk(r,e,t,o),r=Jl(r);try{ag(r,o)}catch(a){throw fe(Z,"template merge failed",a)}sg(r,o.provenance),r.provenance=o.provenance;let s=Xt(r);if(s.length>0)throw L(Z,s.join(`
|
|
5
|
-
`));return r}function Lk(e,t,n,r){let o=hr(Nt(),"config.local.yaml"),i=hr(t,St,"config.local.yaml");for(let s of[o,i]){if(s===n||!hi(s))continue;Yg(s,e,r,void 0,s===o?"home_local":"repo_local")}return e}function Yg(e,t,n,r,o="main"){let i=r!==void 0?Xg(r,e):sd(e),s=Wn(i,"");if(s.length>0)throw L(Z,ao(s));og(t,i,n,{source:e,layer:o})}function Dk(e,t,n){Jg(hr(e,"services"),(o,i,s)=>{let a=Wn(i,`services.${o}`);if(a.length>0)throw L(Z,ao(a));let c=t.services[o];t.services[o]=c?zs(c,i):mi(i),Js(n.services,o,i),Bn(n.provenance,i,s,"modular_service",`services.${o}`)}),Jg(hr(e,"profiles"),(o,i,s)=>{let a=Wn(i,`profiles.${o}`);if(a.length>0)throw L(Z,ao(a));t.profiles[o]=Ks(i),Bn(n.provenance,i,s,"modular_profile",`profiles.${o}`)});let r=hr(e,"proxy","routes.yaml");if(hi(r))Ok(r,t,n)}function Ok(e,t,n){let r=sd(e);if(F(r.proxy))Bn(n.provenance,r.proxy,e,"modular_proxy","proxy");if(Array.isArray(r.routes))Bn(n.provenance,r.routes,e,"modular_proxy","proxy.routes");if(F(r.proxy)){let o=Wn({proxy:r.proxy},"");if(o.length>0)throw L(Z,ao(o))}if(Array.isArray(r.routes))r.routes.forEach((o,i)=>{let s=Wn(o,`proxy.routes.${i}`);if(s.length>0)throw L(Z,ao(s))});if(F(r.proxy)){if(Array.isArray(r.proxy.routes))t.proxy.routes.push(...r.proxy.routes.map((o)=>mr(o)));if(F(r.proxy.listen)){if(typeof r.proxy.listen.host==="string"&&r.proxy.listen.host!=="")t.proxy.listen.host=r.proxy.listen.host;if(typeof r.proxy.listen.port==="number"&&r.proxy.listen.port!==0)t.proxy.listen.port=r.proxy.listen.port}}if(Array.isArray(r.routes))t.proxy.routes.push(...r.routes.map((o)=>mr(o)))}function Jg(e,t){let n;try{n=_k(e)}catch(r){if(Mk(r))return;throw r}for(let r of n.sort()){let o=Pk(r);if(o!==".yaml"&&o!==".yml")continue;let i=hr(e,r),s=sd(i);t(zg(r,o),s,i)}}function sd(e){let t;try{t=Ek(e,"utf8")}catch(n){throw fe(Z,"unable to read config",n)}return Xg(t,e)}function Xg(e,t){let n;try{n=Ak(e)}catch(r){throw fe(Z,`invalid YAML in ${t}`,r)}if(n===null||n===void 0)return{};if(!F(n))throw L(Z,`unable to decode config: ${t} is not a mapping`);return n}function Mk(e){return typeof e==="object"&&e!==null&&"code"in e&&e.code==="ENOENT"}var Qg=D(()=>{Re();ze();Vl();vi();lg();zl();jg();ea();vi();ea()});function vr(e){return Object.entries(e.provenance).sort(([t],[n])=>t.localeCompare(n)).flatMap(([t,n])=>{let r=n[n.length-1];if(!r)return[];return[{path:t,value:$k(e,t),...r,shadowed:n.slice(0,-1)}]})}function $k(e,t){let n=e;for(let r of t.split(".")){if(typeof n!=="object"||n===null)return;n=n[r]}return n}var st=D(()=>{Qg();vi();ea();zl();rd()});import{readdirSync as Ik}from"fs";import{join as Zg,resolve as ad,sep as cd}from"path";function Fk(e){let t=Zg(Nt(),"state"),n;try{n=Ik(t)}catch{return}let r=em(ad(e)),o;for(let i of n){let s=Ol(Zg(t,i,"state.json"));if(!s)continue;let a=em(ad(s.repo_root));if(!Nk(a,r))continue;if(!o||a.length>o.length)o=a}return o}function ta(e,t,n=""){if(t!=="")return{repoRoot:ad(t),source:"explicit"};let r=e===""?process.cwd():e;try{let{repoRoot:i}=jn(r,n);return{repoRoot:i,source:"config"}}catch{if(n!=="")return}let o=Fk(r);return o?{repoRoot:o,source:"state-scan"}:void 0}function em(e){let t=e.length>1&&e.endsWith(cd)?e.slice(0,-1):e;return process.platform==="win32"?t.toLowerCase():t}function Nk(e,t){return t===e||t.startsWith(e.endsWith(cd)?e:`${e}${cd}`)}var tm=D(()=>{vi();ze()});import{existsSync as rm,readFileSync as om}from"fs";import{isAbsolute as Hk,join as ld}from"path";import{parse as jk}from"dotenv";function Gk(){return{name:"dotenv",load:(e)=>{let t=nm(e.repoRoot,e.profile);if(e.workDir!=="")Object.assign(t,nm(e.workDir,e.profile));return t}}}function na(e){return async(t)=>{let n=t.includes("/versions/")?t:`${t}/versions/latest`,r=await e(),o=await fetch(`https://secretmanager.googleapis.com/v1/${n}:access`,{headers:{Authorization:`Bearer ${r}`}});if(!o.ok)throw L(Z,`secret manager request failed for ${t}: HTTP ${o.status}`);let i=await o.json();if(!i.payload?.data)throw L(Z,`secret manager response for ${t} had no payload`);return Buffer.from(i.payload.data,"base64").toString("utf8")}}function Uk(e){let t=e?.environment.sources??[];if(t.length===0)return[...wi];let n=new Set([...Wk,...t]),r=new Set(wi),o=t.filter((s)=>!r.has(s)),i=[];for(let s of wi){if(s==="defaults")i.push(...o);if(n.has(s))i.push(s)}return i}async function ra(e,t){let n={},r=t.serviceCfg.working_dir;if(r!==""&&!Hk(r))r=ld(e,r);let o={repoRoot:e,profile:t.profile,service:t.service,serviceCfg:t.serviceCfg,workDir:r,cfg:t.cfg},i=Kk(t),s={process:t.includeProcess===!1?{}:t.clientEnv??lo(),profile:bi(t.profileEnv,t.cfg,i),dotenv:bi(await Gk().load(o),t.cfg,i),generated:{},keychain:t.sourceValues?.keychain??qk(o),secret_manager:t.sourceValues?.secret_manager??await Vk(o,t.fetchSecret),defaults:bi(t.serviceCfg.environment.defaults,t.cfg,i),vars:bi(t.serviceCfg.environment.vars,t.cfg,i),runtime:t.runtime};for(let a of Uk(t.cfg)){if(s[a]!==void 0){Object.assign(n,s[a]);continue}let c=t.pluginSources?.find((l)=>l.name===a);if(c)Object.assign(n,bi(await c.load(o),t.cfg,i))}for(let a of t.serviceCfg.environment.required)if((n[a]??"").trim()==="")throw L(Z,`service ${t.service} missing required environment variable ${a}`);return n}function Kk(e){let t={};if(e.cfg)for(let[n,r]of Object.entries(e.cfg.services)){let o={};for(let i of r.ports)if(!i.auto)o[i.name]=i.value;t[n]=o}if(e.assignedPorts)t[e.service]=e.assignedPorts;return t}function bi(e,t,n){if(!t||Object.keys(e).length===0)return e;return nd(e,t,n)}function qk(e){let t=e.cfg?.environment.sources??[];if(t.length>0&&!t.includes("keychain"))return{};let n={},r=new Set([...Object.keys(e.serviceCfg.environment.defaults),...Object.keys(e.serviceCfg.environment.vars),...e.serviceCfg.environment.required]);for(let o of r){let i=ld(Gt(),"env",o);if(!rm(i))continue;try{n[o]=om(i,"utf8").replace(/\n$/,"")}catch(s){throw fe(Z,`unable to read keychain env ${o}`,s)}}return n}async function Vk(e,t){if(!(e.cfg?.environment.sources??[]).includes("secret_manager"))return{};let r=e.cfg?.environment.secrets??{},o={};for(let[i,s]of Object.entries(r)){if(!Bk.test(s))throw L(Z,`environment.secrets.${i} is not a Secret Manager resource`);if(!t)throw L(Z,"environment source secret_manager is not configured \u2014 set credentials or remove it from environment.sources");o[i]=await t(s)}return o}function nm(e,t){let n={},r=[".env",".env.development",".env.local"];if(t!=="")r.push(`.env.${t}`);for(let o of r){let i=ld(e,o);if(!rm(i))continue;try{let s=jk(om(i));Object.assign(n,s)}catch(s){throw fe(Z,`unable to read ${i}`,s)}}return n}function lo(){let e={};for(let[t,n]of Object.entries(process.env))if(n!==void 0)e[t]=n;return e}function oa(e,t,n,r,o){let i={DEVCTL_SERVICE_NAME:e,DEVCTL_ENVIRONMENT:o,SERVICE_HOST:t};if(r!=="")i.DEVCTL_PROXY_URL=r;if(n.http!==void 0)i.SERVICE_PORT=String(n.http);else{let s=Object.values(n)[0];if(s!==void 0)i.SERVICE_PORT=String(s)}for(let[s,a]of Object.entries(n))i[`${s.toUpperCase()}_PORT`]=String(a);return i}function Si(e){return{...e}}var wi,Bk,Wk;var dd=D(()=>{st();Re();ze();wi=["process","profile","dotenv","generated","keychain","secret_manager","defaults","vars","runtime"],Bk=/^projects\/[^/]+\/secrets\/[^/]+(?:\/versions\/[^/]+)?$/,Wk=["process","defaults","vars","runtime"]});function Dt(){return"devctl 0.2.3"}var pt="0.2.3",ki=1;import{createConnection as Jk}from"net";var{spawn:zk}=globalThis.Bun;function eC(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 ${ki}`}function tC(e){if(e.compatible&&e.daemonVersion!==void 0&&e.daemonVersion!==pt)return`attached daemon is devctl ${e.daemonVersion}; this client is ${pt} (run \`devctl down\` then start again to update it)`;return}function ud(e,t){if(!e.compat.compatible&&!Zk.has(t))throw ke(Je,eC(e.compat),"run `devctl down` to stop it, then start again")}class am{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 n=this.buf.split(`
|
|
6
|
-
`);this.buf=n.pop()??"";for(let r of n){if(r.trim()==="")continue;this.onLine(r)}}),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 r of this.listeners)r(t.event);return}let n=t.id?this.pending.get(t.id):void 0;if(!n)return;if(this.pending.delete(t.id??""),clearTimeout(n.timer),t.error){n.reject(Nf({error:t.error,kind:t.kind,hint:t.hint,service:t.service}));return}n.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,n=Qk){this.nextID+=1;let r=String(this.nextID);return new Promise((o,i)=>{let s=setTimeout(()=>{this.pending.delete(r),i(Error(`${e} timed out after ${n}ms`))},n);this.pending.set(r,{resolve:o,reject:i,timer:s}),this.socket.write(JSON.stringify({id:r,method:e,params:t})+`
|
|
7
|
-
`)})}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 cm(e,t){let n=Hs(e),r=Date.now()+t;return new Promise((o,i)=>{let s=()=>{let a=Jk(n);a.once("connect",()=>{let c=new am(a);nC(c).finally(()=>o(c))}),a.once("error",(c)=>{if(a.destroy(),Date.now()>=r){i(ke(Je,"supervisor is not running","run `devctl start` or `devctl attach` after starting services"));return}setTimeout(s,Yk)})};s()})}async function nC(e){let t;try{t=await e.call("ping",null,sm)}catch{return}let n=rC(t)?t:{};if(typeof n.session==="string")e.session=n.session;let r=typeof n.protocol==="number"?n.protocol:void 0,o=typeof n.version==="string"?n.version:void 0;if(r===void 0){e.compat={compatible:!1,legacy:!0,daemonVersion:o};return}e.compat={compatible:r===ki,legacy:!1,daemonVersion:o,daemonProtocol:r}}function rC(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}async function yr(e){try{return await cm(e,Xk)}catch{return}}function oC(e,t,n,r){return n?[e,...r]:[e,t,...r]}async function lm(e,t){let n=await yr(e);if(n)return n;Bf(e);let r=ur(e),o=oC(process.execPath,process.argv[1]??"",Bun.isStandaloneExecutable===!0,["--config",t,"_supervisor","--repo",e]);zk({cmd:o,env:process.env,stdout:"ignore",stderr:Bun.file(r),stdin:"ignore",detached:!0}).unref();try{return await cm(e,sm)}catch{throw ke(Je,"supervisor failed to start",`see ${r} for details`)}}class ia{cfg;client;previousPersisted;constructor(e){this.cfg=e}async start(e){return await this.call("start",{...e,client_env:lo()})}async stop(e){await this.call("stop",{services:e})}async restart(e,t){await this.call("restart",{services:e,cascade:t===!0,client_env:lo()})}async runTask(e){return await this.call("run_task",{name:e,client_env:lo()},im)}async execService(e,t,n=!1){return await this.call("exec",{service:e,command:t,print_env:n,client_env:lo()},im)}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 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 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 close(e){if(!this.client)return;try{if(e?.shutdownSupervisor===!0&&e.detach!==!0){let t=Math.max(5000,this.cfg.shutdown.grace_seconds*1000+2000);await this.client.call("shutdown",{stop_services:!0},t)}}finally{this.client.close()}}async call(e,t,n){if(!this.client)throw fe(Je,"supervisor is not running",Error("no client"));return ud(this.client,e),this.client.call(e,t,n)}}function Ci(e){let t=e&&tC(e.compat);if(t)process.stderr.write(`warning: ${t}
|
|
8
|
-
`)}async function pd(e,t,n=""){let r=ta(e,t,n);if(!r)throw ke(Je,"no devctl configuration found","run `devctl setup`, create a .devctl/config.yaml in the repository root, or pass --repo");let o=await yr(r.repoRoot);return Ci(o),{repoRoot:r.repoRoot,client:o}}async function kt(e,t,n,r){let o=r?.allowMissingConfig===!0?yi(e,t):ut(e,t),i=new ia(o);if(!n)return i.client=await yr(o.repoRoot),Ci(i.client),i;return i.client=await lm(o.repoRoot,o.configPath),Ci(i.client),i}async function dm(e){let t=new ia(fr());return t.client=e,Ci(t.client),t.cfg=await t.configSnapshot(),t}async function um(e,t){let n=ta(e,"",t),r=n?await yr(n.repoRoot):void 0;if(!r)throw ke(Je,"supervisor is not running","run `devctl start` before `devctl attach`");return dm(r)}async function pm(e,t){let n=ta(e,"",t),r=n?await yr(n.repoRoot):void 0;if(r)return dm(r);let o=ut(e,t),i=new ia(o),s=pr(o.repoRoot);if(i.client=await lm(o.repoRoot,o.configPath),Ci(i.client),i.cfg=await i.configSnapshot(),s&&s.processes.length>0)i.previousPersisted=s;return i}var Yk=50,sm=8000,Xk=200,Qk=30000,im=86400000,Zk;var fd=D(()=>{st();tm();dd();Re();ze();Zk=new Set(["logs","logs_page","logs_stats"])});function aa(e){if(yn(e))return Ht({kind:xr,serviceAccount:e.service_account});if(Jf(e)&&(e.type!==""||e.mode!==""))return Ht({kind:sa});let t=(e.type||e.mode).toLowerCase();if(t!=="")return Ht({kind:t,providerConfig:e.config??{}});return Ht({kind:uo})}function br(e){if(e.type.toLowerCase()==="none")return Ht({kind:uo});let t=e.identity.type.toLowerCase(),n=e.identity.service_account||e.service_account;if(t==="service"||t==="service_account"||e.type==="service_account")return Ht({kind:xr,serviceAccount:n});if(e.type.toLowerCase()==="iap"&&t==="")return Ht({kind:uo});if(e.type===""&&t==="")return Ht({kind:uo});return Ht({kind:sa})}function fm(e){return e.kind===sa||e.kind===xr}function po(e){if(e.tokenKey!=="")return e.tokenKey;if(e.kind===xr)return`sa:${e.serviceAccount}`;if(e.email!=="")return`user:${e.email}`;return"user"}function Ht(e={}){return{kind:uo,email:"",serviceAccount:"",project:"",projectSource:"",adcAvailable:!1,providerConfig:{},tokenKey:"",...e}}function gd(e){let t=new Map,n=(r,o)=>{if(r!=="")t.set(r,(t.get(r)??!1)||o)};for(let r of Object.values(e.services))if(yn(r.identity)&&r.identity.service_account!=="")n(r.identity.service_account,!0);for(let r of e.proxy.routes){let o=r.auth.type.toLowerCase(),i=r.auth.identity.type.toLowerCase(),s=r.auth.identity.service_account||r.auth.service_account;if(i==="service"||i==="service_account"||o==="service_account")n(s,o!=="none")}return[...t.entries()].map(([r,o])=>({email:r,active:o})).sort((r,o)=>r.email.localeCompare(o.email))}function Gn(e){return gd(e).filter((t)=>t.active).map((t)=>t.email)}function gm(e,t,n){let r=[];for(let o of t){let i=e.services[o];if(!i)continue;let s=aa(i.identity);if(yn(i.identity)&&i.identity.service_account===""){r.push({name:o,message:"service account identity is not configured"});continue}if((fm(s)||i.capabilities.some((c)=>c==="google_api"||c==="iap"||c==="service_identity"))&&!n)r.push({name:o,message:"ADC unavailable"})}return r}function _i(e){if(Gn(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(fm(aa(t.identity)))return!0;return t.capabilities.some((n)=>n==="google_api"||n==="iap"||n==="service_identity")})}function md(){return{name:"user",accepts:(e)=>!yn(e),resolve:async(e,t)=>{if(e.type===""&&e.mode==="")return Ht({kind:uo});return{...await t(),kind:sa}}}}function hd(){return{name:"service_account",accepts:(e)=>yn(e),resolve:async(e,t)=>{if(e.service_account==="")throw L(Is,"service account identity is not configured");return{...await t(),kind:xr,serviceAccount:e.service_account}}}}async function mm(e,t,n){if(n)for(let r=n.length-1;r>=0;r-=1){let o=n[r];if(o?.accepts(e))return o.resolve(e,t)}if(yn(e))return hd().resolve(e,t);return md().resolve(e,t)}var sa="user",xr="service_account",uo="none";var wr=D(()=>{st();Re()});import{existsSync as ca,readFileSync as iC}from"fs";import{homedir as vm}from"os";import{join as vd}from"path";var{spawn:yd}=globalThis.Bun;function go(){let e=globalThis;if(e.window&&typeof e.window.fetch!=="function")e.window.fetch=fetch}function xd(){let e=process.env.GOOGLE_APPLICATION_CREDENTIALS||vd(vm(),".config","gcloud","application_default_credentials.json");if(!ca(e))return"";try{let t=JSON.parse(iC(e,"utf8"));return typeof t.quota_project_id==="string"?t.quota_project_id:""}catch{return""}}async function Ot(e){let t={gcloudInstalled:await bd("gcloud"),adcAvailable:!1,userEmail:"",projectID:"",projectSource:""};if(e!=="")t.projectID=e,t.projectSource="configuration";else{let n=pC("GOOGLE_CLOUD_PROJECT","GCLOUD_PROJECT","GOOGLE_PROJECT");if(n!=="")t.projectID=n,t.projectSource="environment variable";else if(t.gcloudInstalled){let r=await hm("core/project");if(r!=="")t.projectID=r,t.projectSource="gcloud configuration"}}if(Ei())try{await wm(cC(t),aC)}catch(n){t.adcAvailable=!1,t.error=ho(n)}if(t.userEmail===""&&t.gcloudInstalled)t.userEmail=await hm("core/account");return t}async function cC(e){go();let{GoogleAuth:t}=await import("google-auth-library"),n=new t({scopes:[sC]});await n.getClient(),e.adcAvailable=!0;let r=await n.getProjectId().catch(()=>"");if(e.projectID===""&&r)e.projectID=r,e.projectSource="application default credentials";let o=await lC(n);if(o!=="")e.userEmail=o}async function lC(e){try{let t=await e.getCredentials();if(t.client_email)return t.client_email}catch{}try{let t=await e.getClient(),n=typeof t.credentials?.id_token==="string"?t.credentials.id_token:"";if(n!==""){let r=dC(n);if(r!=="")return r}}catch{return""}return""}function dC(e){let t=e.split(".");if(t.length<2||!t[1])return"";try{let n=JSON.parse(Buffer.from(t[1],"base64url").toString("utf8"));return typeof n.email==="string"?n.email:""}catch{return""}}async function xm(e){let t=await Ot(e);return Ht({kind:"user",email:t.userEmail,project:t.projectID,projectSource:t.projectSource,adcAvailable:t.adcAvailable})}async function mo(){if(await yd({cmd:["gcloud","auth","application-default","login"],stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited!==0)throw ke(to,"application-default login failed","run `gcloud auth application-default login`")}async function la(){if(await yd({cmd:["gcloud","auth","application-default","revoke","--quiet"],stdout:"ignore",stderr:"pipe"}).exited!==0)throw ke(to,"failed to revoke application-default credentials","run `gcloud auth application-default revoke`")}function ho(e){let t=uC(e).toLowerCase();if(fo(t,["unauth","invalid_grant","token has been expired","expired"]))return ke(to,"credential expired or invalid","run `devctl auth login` or `gcloud auth application-default login`");if(fo(t,["api has not been used","has not been enabled","access not configured","service_disabled"]))return ke(lr,"required Google API is not enabled","enable the API in the target service account project; devctl will not enable APIs automatically");if(fo(t,["permission","forbidden","iam"])){if(fo(t,["serviceaccounttoken","iamcredentials","token creator","getaccesstoken"]))return ke(Is,"cannot impersonate service account","ask an administrator to grant roles/iam.serviceAccountTokenCreator on the target service account");return ke(lr,"authorization failure","verify IAM permissions for the current user on this project")}if(t.includes("audience"))return ke(_l,"IAP audience is incorrect","set auth.audience on the proxy route to the IAP OAuth client ID");if(t.includes("iap"))return fe(_l,"IAP authentication failure",e);if(t.includes("project"))return ke(Z,"wrong or missing Google project","set google.project_id in .devctl/config.yaml");if(fo(t,["timeout","network","connection refused","no such host"]))return fe(Je,"network problem reaching Google Cloud",e);if(fo(t,["adc","default credentials","could not find"]))return ke(to,"application default credentials unavailable","run `gcloud auth application-default login`");return fe(to,"Google authentication failed",e)}function uC(e){let t=[],n=new Set,r=(o,i)=>{if(o===null||o===void 0||i>8||n.has(o))return;if(typeof o==="string"){t.push(o);return}if(typeof o!=="object")return;n.add(o);let s=o;for(let a of["message","reason","status","code","error_description","permission","service"])r(s[a],i+1);for(let a of["error","errors","details","response","data","cause","metadata"]){let c=s[a];if(Array.isArray(c))c.forEach((l)=>r(l,i+1));else r(c,i+1)}};return r(e,0),t.length>0?t.join(" "):String(e)}function fo(e,t){return t.some((n)=>e.includes(n))}function pC(...e){for(let t of e){let n=process.env[t];if(n)return n}return""}async function bd(e){try{return(await bm(process.platform==="win32"?["where",e]:["which",e],ym)).code===0}catch{return!1}}function Ei(){let e=process.env.GOOGLE_APPLICATION_CREDENTIALS;if(e&&ca(e))return!0;if(ca(vd(vm(),".config","gcloud","application_default_credentials.json")))return!0;let t=process.env.APPDATA;return Boolean(t&&ca(vd(t,"gcloud","application_default_credentials.json")))}async function hm(e){try{let t=await bm(["gcloud","config","get-value",e],ym);if(t.code!==0)return"";let n=t.stdout.trim();if(n===""||n==="(unset)")return"";return n}catch{return""}}async function bm(e,t){let n=yd({cmd:e,stdout:"pipe",stderr:"ignore",env:{...process.env,CLOUDSDK_CORE_DISABLE_PROMPTS:"1",CLOUDSDK_CORE_DISABLE_USAGE_REPORTING:"true"}}),r=n.stdout?new Response(n.stdout).text():Promise.resolve("");try{let[o,i]=await wm(Promise.all([r,n.exited]),t);return{code:i??1,stdout:o}}catch{return n.kill(),{code:1,stdout:""}}}function wm(e,t){return new Promise((n,r)=>{let o=setTimeout(()=>r(Error("timeout")),t);e.then((i)=>{clearTimeout(o),n(i)},(i)=>{clearTimeout(o),r(i)})})}var sC="https://www.googleapis.com/auth/cloud-platform",ym=1500,aC=2000;var Sr=D(()=>{eo();Re();wr()});var{spawn:Sd}=globalThis.Bun;import{createServer as Sm}from"net";async function km(e,t,n={}){let r={};for(let[i,s]of Object.entries(n))for(let a of Object.values(s))r[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 c of s.ports){let l=n[i]?.[c.name],d=l&&l>=wd?l:c.value;if(l===void 0&&c.auto)d=await gC();if(d<wd||d>fC)throw new Me(Z,`invalid port ${d} on service ${i}`,{service:i});if(r[d]&&r[d]!==i)throw new Me(Z,`duplicate port ${d} used by ${r[d]} and ${i}`,{service:i});if(l!==d&&!c.auto&&!await vo(d))throw await mC(i,c.name,d);r[d]=i,a[c.name]=d}o[i]=a}return o}function gC(){return new Promise((e,t)=>{let n=Sm();n.listen(0,"127.0.0.1",()=>{let r=n.address();n.close(()=>{if(r&&typeof r==="object")e(r.port);else t(fe(Z,"unable to allocate dynamic port",Error("no address")))})}),n.on("error",(r)=>t(fe(Z,"unable to allocate dynamic port",r)))})}async function da(e){let t=e.ports.filter((r)=>!r.auto&&r.value>=wd);if(t.length===0)return;let n={};for(let r of t){if(await vo(r.value))return;n[r.name]=r.value}return n}function vo(e){return new Promise((t)=>{let n=Sm();n.listen(e,"127.0.0.1",()=>{n.close(()=>t(!0))}),n.on("error",()=>t(!1))})}async function mC(e,t,n){let r=await yo(n);return hC(e,t,n,r)}function hC(e,t,n,r){let o=t===""?`${e} port`:`${e} ports.${t}`;if(r&&r.pid===process.pid)return ke(Ne,`${e} blocked: this TUI already holds port ${n}`,`Stop the proxy from the Proxy screen, or change ${o} in .devctl.`,e);if(r)return ke(Ne,`${e} blocked: ${r.command} (pid ${r.pid}) is using port ${n}`,`Open Doctor and press enter to free port ${n}, or change ${o} in .devctl.`,e);return ke(Ne,`${e} blocked: port ${n} is already in use`,`Something is listening on ${n}. Open Doctor to free it, or change ${o} in .devctl.`,e)}function vC(e,t){let n=e.split(`
|
|
9
|
-
`).filter((r)=>r.trim()!==""&&!r.startsWith("COMMAND"));for(let r of n){let o=r.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 yo(e){if(process.platform==="win32")return wC(e);let t=await yC(e);if(t)return t;return xC(e)}async function yC(e){try{let t=Sd({cmd:["lsof","-nP",`-iTCP:${e}`,"-sTCP:LISTEN"],stdout:"pipe",stderr:"ignore"}),n=await new Response(t.stdout).text();return await t.exited,vC(n,e)}catch{return}}async function xC(e){let t;try{let o=Sd({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 n=t.match(/(\d+)/),r=n?Number(n[1]):0;if(!Number.isInteger(r)||r<=0)return;return{port:e,pid:r,command:"process"}}function bC(e,t){for(let n of e.split(`
|
|
10
|
-
`)){if(!n.includes("LISTENING")&&!n.includes("LISTEN"))continue;if(!n.includes(`:${t}`)&&!n.includes(` ${t} `))continue;let r=n.trim().match(/(\d+)\s*$/),o=r?Number(r[1]):0;if(Number.isInteger(o)&&o>0)return{port:t,pid:o,command:"process"}}return}async function wC(e){let t=Sd({cmd:["netstat","-ano"],stdout:"pipe",stderr:"ignore"}),n=t.stdout?await new Response(t.stdout).text():"";return await t.exited,bC(n,e)}async function ua(e){if(e.pid===process.pid)throw ke(Ne,`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 fe(Ne,`could not stop pid ${e.pid} on port ${e.port}`,t)}await kC(SC);try{process.kill(e.pid,0),process.kill(e.pid,"SIGKILL")}catch{return}}function kC(e){return new Promise((t)=>{setTimeout(t,e)})}var fC=65535,wd=1,SC=400;var Ri=D(()=>{Re()});var{spawn:Ed}=globalThis.Bun;import{existsSync as fa,readdirSync as CC,readFileSync as Cm,unlinkSync as _C}from"fs";import{join as Pi}from"path";function _d(e){return Pi(Gt(),`${ma(e)}${Cd}`)}function ga(e){if(e==="file"||process.env.DEVCTL_HOME&&e!=="keychain")return new pa;if(e==="keychain"||process.platform==="darwin"||process.platform==="win32"||process.platform==="linux")return new _m(new pa);return new pa}class pa{backend="file";async get(e){let t=TC(e);if(!t||t.accessToken==="")return;return t}async set(e,t){Ut(_d(e),`${JSON.stringify({...PC(t),key:e})}
|
|
11
|
-
`)}async delete(e){let t=_d(e);if(fa(t))_C(t)}async list(){let e=Gt();if(!fa(e))return[];let t=[];for(let n of CC(e)){if(!n.endsWith(Cd))continue;let r=n.slice(0,-Cd.length),o=Em(Pi(Gt(),n));if(!o)continue;t.push(Rm(o.key??r,o.record))}return t.sort((n,r)=>n.identity.localeCompare(r.identity))}}class _m{backend="keychain";fallback;constructor(e){this.fallback=e}async get(e){let t=await AC(e);if(t)return t;return this.fallback.get(e)}async set(e,t){if(!await LC(e,t))await this.fallback.set(e,t);EC(e)}async delete(e){await DC(e),await this.fallback.delete(e),RC(e)}async list(){let e=new Set(Pd()),t=await this.fallback.list(),n=new Map;for(let r of t)n.set(r.key,r);for(let r of e){let o=await this.get(r);if(o)n.set(r,Rm(r,o))}return[...n.values()].sort((r,o)=>r.identity.localeCompare(o.identity))}}function EC(e){let t=Pd();if(!t.includes(e))Ut(Pi(Gt(),Rd),`${JSON.stringify([...t,e])}
|
|
12
|
-
`)}function RC(e){let t=Pd(),n=t.filter((r)=>r!==e);if(n.length!==t.length)Ut(Pi(Gt(),Rd),`${JSON.stringify(n)}
|
|
13
|
-
`)}function Pd(){let e=Pi(Gt(),Rd);if(!fa(e))return[];try{let t=JSON.parse(Cm(e,"utf8"));return Array.isArray(t)?t.filter((n)=>typeof n==="string"):[]}catch{return[]}}function PC(e){return{...e,accessToken:""}}function TC(e){return Em(_d(e))?.record}function Em(e){if(!fa(e))return;try{let t=JSON.parse(Cm(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((n)=>typeof n==="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 Rm(e,t){let n=Date.parse(t.expiresAt);return{key:e,identity:t.identity,audience:t.audience,scopes:t.scopes,expires_at:t.expiresAt,valid:Number.isFinite(n)&&n-Date.now()>0}}function ma(e){return e.replace(/[^A-Za-z0-9._-]+/g,"_").slice(0,80)||"token"}async function AC(e){let t=await OC(e);if(!t)return;try{return JSON.parse(t)}catch{return}}async function LC(e,t){let n=JSON.stringify(t);if(process.platform==="darwin")return await xo(["security","delete-generic-password","-s",kr,"-a",e]),await xo(["security","add-generic-password","-s",kr,"-a",e,"-w",n,"-U"])===0;if(process.platform==="linux")return await MC(["secret-tool","store","--label",`devctl ${e}`,"service",kr,"account",e],n)===0;if(process.platform==="win32"){let o=`Add-Type -AssemblyName System.Security; $bytes = [Convert]::FromBase64String('${Buffer.from(n,"utf8").toString("base64")}'); $enc = [System.Security.Cryptography.ProtectedData]::Protect($bytes, $null, 'CurrentUser'); [IO.File]::WriteAllBytes($env:LOCALAPPDATA + '\\devctl-cred-${ma(e)}.bin', $enc)`;return await xo(["powershell","-NoProfile","-Command",o])===0}return!1}async function DC(e){if(process.platform==="darwin"){await xo(["security","delete-generic-password","-s",kr,"-a",e]);return}if(process.platform==="linux"){await xo(["secret-tool","clear","service",kr,"account",e]);return}if(process.platform==="win32")await xo(["powershell","-NoProfile","-Command",`Remove-Item -ErrorAction SilentlyContinue ($env:LOCALAPPDATA + '\\devctl-cred-${ma(e)}.bin')`])}async function OC(e){if(process.platform==="darwin"){let t=await kd(["security","find-generic-password","-s",kr,"-a",e,"-w"]);return t.code===0&&t.stdout!==""?t.stdout:void 0}if(process.platform==="linux"){let t=await kd(["secret-tool","lookup","service",kr,"account",e]);return t.code===0&&t.stdout!==""?t.stdout:void 0}if(process.platform==="win32"){let t=`$p = $env:LOCALAPPDATA + '\\devctl-cred-${ma(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)`,n=await kd(["powershell","-NoProfile","-Command",t]);return n.code===0&&n.stdout!==""?n.stdout:void 0}return}async function xo(e){try{return await Ed({cmd:e,stdout:"ignore",stderr:"ignore",timeout:Td}).exited}catch{return 1}}async function MC(e,t){try{return await Ed({cmd:e,stdin:new TextEncoder().encode(t),stdout:"ignore",stderr:"ignore",timeout:Td}).exited}catch{return 1}}async function kd(e){try{let t=Ed({cmd:e,stdout:"pipe",stderr:"ignore",timeout:Td}),n=t.stdout?await new Response(t.stdout).text():"";return{code:await t.exited,stdout:n.trim()}}catch{return{code:1,stdout:""}}}var Rd="keychain-index.json",kr="devctl.credentials",Cd=".cred.json",Td=3000;var Ad=D(()=>{ze()});function Le(e,t,n){return{type:e,timestamp:new Date().toISOString(),service:t,payload:n}}class $d{subs=new Map;nextID=0;buffer=[];maxBuf;constructor(e){this.maxBuf=e>0?e:1024}subscribe(e,t=[]){this.nextID+=1;let n=this.nextID;return this.subs.set(n,{types:new Set(t),handler:e}),()=>{this.subs.delete(n)}}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 n of this.subs.values())if(n.types.size===0||n.types.has(t.type))n.handler(t)}recent(){return[...this.buffer]}}var Pm="ServiceStarted",Ld="ServiceStopped",Dd="ServiceFailed",Tm="ServiceStateChanged",Am="ServiceHealthChanged",ha="LogReceived",bo="TokenRefreshed",Cr="TokenRefreshFailed",Od="AuthenticationChanged",Lm="ProxyStarted",Dm="ProxyStopped",Md="ProxyRequest",va="ConfigurationChanged",Ti="ConfigurationReloadFailed",Om="SessionRecovered";async function Mm(e,t={}){let n=t.attempts??$C,r=t.backoffMs??IC,o=t.retry??FC,i=Error("retry exhausted");for(let s=0;s<n;s+=1)try{return await e()}catch(a){if(i=a,!o(a)||s===n-1)throw a;await NC(r*(s+1))}throw i}function FC(e){if(e instanceof Me)return e.kind!==Z&&e.kind!==lr;return!0}function NC(e){return new Promise((t)=>{setTimeout(t,e)})}var $C=3,IC=200;var $m=D(()=>{Re()});var Hm={};Ms(Hm,{TokenManager:()=>wo,expiresSoonToken:()=>Fm,googleTokenProviders:()=>_r,isValidToken:()=>Im,staticTokenProvider:()=>zC,tokenCacheKey:()=>Id,tokenMetaPath:()=>Nm});import{createHash as HC}from"crypto";import{join as jC}from"path";import{GoogleAuth as xa,Impersonated as BC}from"google-auth-library";function Id(e,t,n){return`${e}|${t}|${n.join(",")}`}function Im(e,t=Fd){if(e.accessToken==="")return!1;return e.expiresAt.getTime()-Date.now()>=t}function Fm(e,t=Fd){if(e.accessToken==="")return!0;let n=e.expiresAt.getTime()-Date.now();return n>0&&n<t}class wo{cache=new Map;inflight=new Map;providers;thresholdMs;bus;store;constructor(e,t,n,r){this.thresholdMs=e>0?e:Fd,this.providers=[...t],this.bus=n,this.store=r??ga(process.env.DEVCTL_CREDENTIAL_BACKEND==="file"?"file":void 0)}replaceProviders(e){this.providers.splice(0,this.providers.length,...e)}isValid(e){return Im(e,this.thresholdMs)}expiresSoon(e){return Fm(e,this.thresholdMs)}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,n){let r=Id(e,t,n),o=this.cache.get(r)??await this.loadStored(r);if(o&&this.isValid(o))return this.cache.set(r,o),o;return this.refresh(e,t,n)}async refresh(e,t,n){let r=Id(e,t,n),o=this.inflight.get(r);if(o)return o;let i=this.refreshOnce(r,e,t,n);this.inflight.set(r,i);try{return await i}finally{this.inflight.delete(r)}}async refreshOnce(e,t,n,r){let o=this.providers.filter((s)=>!s.accepts||s.accepts(t,n,r));if(o.length===0)throw L(hn,`no token provider accepts identity ${t}`);let i=L(hn,"no token provider available");for(let s of o)try{let a=await Mm(()=>s.fetch(t,n,r),{attempts:GC,backoffMs:UC,retry:i_});return this.cache.set(e,a),qC(e,a),await this.store.set(e,VC(a)),this.bus?.publish(Le(bo,"",{identity:a.identity,audience:a.audience})),a}catch(a){i=a instanceof Error?a:Error(String(a))}throw this.bus?.publish(Le(Cr,"",{identity:t,audience:n,error:O(i)})),i}async loadStored(e){let t=await this.store.get(e);if(!t||t.accessToken==="")return;return JC(t)}async clearStore(){let e=await this.store.list();await Promise.all(e.map((t)=>this.store.delete(t.key)))}}function Nm(e){let t=HC("sha256").update(e).digest("hex").slice(0,16);return jC(Gt(),`${t}.json`)}function qC(e,t){let n={identity:t.identity,audience:t.audience,expires_at:t.expiresAt.toISOString(),scopes:t.scopes};Ut(Nm(e),`${JSON.stringify(n)}
|
|
14
|
-
`)}function VC(e){return{identity:e.identity,audience:e.audience,scopes:e.scopes,accessToken:e.accessToken,tokenType:e.tokenType,expiresAt:e.expiresAt.toISOString()}}function JC(e){return{accessToken:e.accessToken,tokenType:e.tokenType||"Bearer",expiresAt:new Date(e.expiresAt),audience:e.audience,identity:e.identity,scopes:e.scopes}}function _r(){return[QC(),XC(),YC()]}function zC(e){return{name:"static",accepts:(t,n)=>(e.identity===""||t===e.identity)&&(e.audience===""||n===e.audience),fetch:async(t,n,r)=>({...e,identity:t,audience:n,scopes:r})}}function YC(){return{name:"user",accepts:(e,t)=>!e.startsWith("sa:")&&t==="",fetch:async(e,t,n)=>{if(e.startsWith("sa:"))throw L(hn,"user provider cannot mint service-account tokens");return n_(e,t,n)}}}function XC(){return{name:"service_account",accepts:(e,t)=>e.startsWith("sa:")&&t==="",fetch:async(e,t,n)=>{if(!e.startsWith("sa:"))throw L(hn,"service-account provider cannot mint user tokens");return ZC(e,t,n)}}}function QC(){return{name:"iap",accepts:(e,t)=>t!=="",fetch:async(e,t,n)=>{if(t==="")throw L(hn,"IAP audience is required");if(e.startsWith("sa:"))return e_(e,t,n);return t_(e,t,n)}}}async function ZC(e,t,n){let r=e.slice(3);try{go();let i=await new xa({scopes:n.length>0?n:[ya]}).getClient(),s=new BC({sourceClient:i,targetPrincipal:r,targetScopes:n.length>0?n:[ya],lifetime:3600}),a=await s.getAccessToken(),c=typeof a==="string"?a:a?.token;if(!c)throw L(hn,"empty impersonated token");return{accessToken:c,tokenType:"Bearer",expiresAt:ba(c,s),audience:t,identity:e,scopes:n}}catch(o){throw ho(o)}}async function e_(e,t,n){let r=e.slice(3);try{go();let i=await new xa({scopes:[ya]}).getClient(),s=`https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${encodeURIComponent(r)}:generateIdToken`,c=(await i.request({url:s,method:"POST",data:{audience:t,includeEmail:!0}})).data.token;if(!c)throw L(hn,"empty impersonated IAP id token");return{accessToken:c,tokenType:"Bearer",expiresAt:ba(c),audience:t,identity:e,scopes:n}}catch(o){throw ho(o)}}async function t_(e,t,n){try{go();let i=await(await new xa({scopes:n.length>0?n:[KC]}).getIdTokenClient(t)).idTokenProvider.fetchIdToken(t);return{accessToken:i,tokenType:"Bearer",expiresAt:ba(i),audience:t,identity:e,scopes:n}}catch(r){throw ho(r)}}async function n_(e,t,n){try{go();let o=await new xa({scopes:n.length>0?n:[ya]}).getClient(),i=await o.getAccessToken();if(!i.token)throw L(hn,"empty access token");return{accessToken:i.token,tokenType:"Bearer",expiresAt:r_(o,i.token),audience:t,identity:e,scopes:n}}catch(r){throw ho(r)}}function ba(e,t){if(t?.credentials?.expiry_date)return new Date(t.credentials.expiry_date);return o_(e)??new Date(Date.now()+WC)}function r_(e,t){return ba(t,e)}function o_(e){let t=e.split(".");if(t.length<2||!t[1])return;try{let n=JSON.parse(Buffer.from(t[1],"base64url").toString("utf8"));if(typeof n.exp==="number")return new Date(n.exp*1000)}catch{return}return}function i_(e){if(e instanceof Me)return e.kind!==Z&&e.kind!==lr;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")}var Fd=300000,WC=3000000,GC=3,UC=200,ya="https://www.googleapis.com/auth/cloud-platform",KC="https://www.googleapis.com/auth/userinfo.email";var Ai=D(()=>{eo();Ad();Re();Sr();$m();ze()});async function Un(e,t=jm,n,r){let o={checks:[],issues:0},i="Preparing diagnostics",s=()=>n?.({active:i,checks:[...o.checks]}),a=(m)=>{i=m,s()},c=(m)=>{if(o.checks.push(m),m.severity==="error")o.issues+=1;s()},l=[...new Set(Object.values(e.services).flatMap((m)=>m.container?[m.container.runtime||"docker"]:[]))];for(let m of l){a(`${m} container runtime`);let x=await t.hasCommand(m),v=x&&await(t.containerRuntimeAvailable??jm.containerRuntimeAvailable)(m);c(v?{name:`${m} container runtime`,severity:"ok",message:`${m} daemon reachable`}:{name:`${m} container runtime`,severity:"error",message:x?`${m} daemon is not reachable`:`${m} not found`,hint:`install and start ${m}`})}if(a("Google CLI installed"),await t.hasCommand("gcloud"))c({name:"Google CLI installed",severity:"ok",message:"gcloud found"});else c({name:"Google CLI installed",severity:_i(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 d=await t.detectGoogle(e.google.project_id);if(d.adcAvailable)c({name:"Google authentication available",severity:"ok",message:"Application Default Credentials found"});else c({name:"Google authentication available",severity:_i(e)?"error":"warn",message:"ADC unavailable",hint:"run `gcloud auth application-default login`"});if(d.projectID!=="")c({name:"Project configured",severity:"ok",message:`${d.projectID} (source: ${d.projectSource})`});else c({name:"Project configured",severity:_i(e)?"error":"warn",message:"no Google project configured",hint:"set google.project_id in .devctl/config.yaml"});if(_i(e)||Object.values(e.services).some((m)=>m.capabilities.includes("google")||m.identity.type!=="")){a("Live Google access");let m=!0,x=(v)=>{if(m)c(v)};try{await Di((async()=>{await c_(e,x,t,d.userEmail),await a_(e,x,t)})(),t.liveDeadlineMs??s_)}catch(v){x({name:"Live Google probes",severity:"warn",message:O(v),hint:"network or timeout \u2014 retry when online"})}finally{m=!1}}for(let m of e.doctor.tools){let x=m.command||m.name;if(a(`${m.name} installed`),await t.hasCommand(x))c({name:`${m.name} installed`,severity:"ok",message:`${x} found`});else c({name:`${m.name} installed`,severity:"error",message:`${x} not found`,hint:`install ${m.name} and ensure it is on PATH`})}if(a("Repository configuration"),r?.repositoryConfigError!==void 0)if(r.repositoryConfigError==="")c({name:"Repository configuration",severity:"ok",message:"valid"});else c({name:"Repository configuration",severity:"error",message:r.repositoryConfigError});else try{let m=Xt(e);if(m.length>0)c({name:"Repository configuration",severity:"error",message:m.join("; ")});else c({name:"Repository configuration",severity:"ok",message:"valid"})}catch(m){c({name:"Repository configuration",severity:"error",message:O(m)})}let g={};for(let[m,x]of Object.entries(e.services))for(let v of x.ports){if(v.auto)continue;let w=`Port ${v.value}`;if(a(w),g[v.value])c({name:w,severity:"error",message:`configured on both ${g[v.value]} and ${m}`});else{g[v.value]=m;let E=r?.services?.[m],k=Boolean(x.container&&E&&["STARTING","RUNNING","HEALTHY","UNHEALTHY"].includes(E.state??""));if(Boolean(E&&(E.pid>0||k)&&Object.values(E.ports).includes(v.value)))c({name:w,severity:"ok",message:`in use by running service ${m}`});else if(await t.portAvailable(v.value))c({name:w,severity:"ok",message:"available"});else c(await Wm(w,v.value,`services.${m}.ports`))}}if(e.proxy.listen.port>0){let m=`Port ${e.proxy.listen.port}`;if(a(m),r?.proxyRunning)c({name:m,severity:"ok",message:"in use by the running proxy"});else if(await t.portAvailable(e.proxy.listen.port))c({name:m,severity:"ok",message:"proxy listen port available"});else c(await Wm(m,e.proxy.listen.port,"proxy.listen.port"))}return i="Diagnostics complete",s(),o}async function a_(e,t,n){let r=e.google.project_id,o=n.hasLocalAdc??Ei;if(r===""||!o())return;let i=n.probeServiceUsage??Km,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((c)=>Di(i(r,c.service),Li)))).forEach((c,l)=>{let d=s[l];if(!d)return;if(c.status==="fulfilled"){t({name:d.name,severity:c.value?"ok":"warn",message:c.value?"enabled":"not enabled or unreachable",hint:c.value?void 0:`enable ${d.service} in the Google Cloud console \u2014 doctor never auto-enables APIs`});return}t({name:d.name,severity:"warn",message:O(c.reason),hint:`enable ${d.service} in the Google Cloud console \u2014 doctor never auto-enables APIs`})})}async function Gm(){if(!Nd)Nd=Promise.resolve().then(() => (Ai(),Hm)).then(({TokenManager:e,googleTokenProviders:t})=>new e(60000,t(),void 0,ga("file")));return Nd}async function Um(e,t){await(await Gm()).get(e,t,[])}async function Km(e,t){let n=await Gm(),r=await Di(n.get("user","",[]),Li),o=`https://serviceusage.googleapis.com/v1/projects/${e}/services/${t}`,i=await fetch(o,{headers:{Authorization:`Bearer ${r.accessToken}`},signal:AbortSignal.timeout(Li)});if(!i.ok)return!1;return(await i.json().catch(()=>{return}))?.state==="ENABLED"}async function c_(e,t,n,r){let o=Gn(e),i=e.proxy.routes.filter((f)=>f.auth.type.toLowerCase()==="iap"),s=i.filter((f)=>f.auth.audience.trim()!=="");for(let f of i)if(f.auth.audience.trim()==="")t({name:`IAP audience ${f.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(!(n.hasLocalAdc??Ei)())return;let c=n.mintToken??Um,l=o.map(async(f)=>{try{await Di(c(`sa:${f}`,""),Li),t({name:`Impersonate ${f}`,severity:"ok",message:"token minted"})}catch(g){let m=(n.adcQuotaProject??xd)(),x=r||"the ADC principal",v=m===""?"unknown":m,w=Bm(`Impersonate ${f}`,g,`grant roles/iam.serviceAccountTokenCreator to ${x} on ${f}; ADC quota project: ${v}`);if(m!==""&&w.message.toLowerCase().includes("api is not enabled"))w.message=`IAM Credentials API is disabled in ADC quota project ${m}`,w.hint=`enable iamcredentials.googleapis.com in ${m}, or set the ADC quota project to ${e.google.project_id}`;else if(w.message.toLowerCase()==="google authentication failed")w.message=`access-token mint failed: ${x} \u2192 ${f}`,w.hint=`verify roles/iam.serviceAccountTokenCreator for ${x} on this service account; ADC quota project: ${v}`;t(w)}}),d=s.map(async(f)=>{let g=br(f.auth).kind===xr?`sa:${br(f.auth).serviceAccount}`:"user";try{await Di(c(g,f.auth.audience),Li),t({name:`IAP ${f.name}`,severity:"ok",message:"id token minted"})}catch(m){t(Bm(`IAP ${f.name}`,m,"check IAP OAuth client ID and ADC"))}});await Promise.all([...l,...d])}function Bm(e,t,n){let r=O(t),o=r.toLowerCase();if(o.includes("timeout")||o.includes("network")||o.includes("econnrefused")||o.includes("enotfound"))return{name:e,severity:"warn",message:r,hint:"network or timeout \u2014 retry when online"};if(t instanceof Me&&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:r,hint:n}}function Di(e,t){return new Promise((n,r)=>{let o=setTimeout(()=>r(Error("timeout")),t);e.then((i)=>{clearTimeout(o),n(i)},(i)=>{clearTimeout(o),r(i)})})}async function Wm(e,t,n){let r=await yo(t);if(!r)return{name:e,severity:"error",message:"already in use",hint:`stop the process using port ${t} or change ${n}`};if(r.pid===process.pid)return{name:e,severity:"error",message:`in use by this TUI (${r.command} pid ${r.pid})`,hint:"stop the proxy from the proxy screen (x), then rerun doctor"};return{name:e,severity:"error",message:`in use by ${r.command} (pid ${r.pid})`,hint:"enter stop that process after a confirmation",action:{kind:"free-port",holder:r}}}function wa(e){let t=[`${Dt()} doctor`,""];for(let n of e.checks){let r=n.severity==="error"?"\u2717":n.severity==="warn"?"!":"\u2713";if(t.push(`${r} ${n.name}`),n.severity!=="ok"){if(t.push(` ${n.message}`),n.hint)t.push(` \u2192 ${n.hint}`)}}return t.push("",`${e.issues} issue(s) found.`),t.join(`
|
|
15
|
-
`)+`
|
|
16
|
-
`}var Li=4000,s_=8000,jm,Nd;var Oi=D(()=>{eo();st();Re();Sr();wr();Ri();Ad();jm={detectGoogle:Ot,hasCommand:bd,portAvailable:vo,hasLocalAdc:Ei,adcQuotaProject:xd,mintToken:Um,probeServiceUsage:Km,containerRuntimeAvailable:async(e)=>{try{return await Bun.spawn({cmd:[e,"info"],stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited===0}catch{return!1}}}});function Co(e){if(e.state===jt&&e.health===_t)return Er;if(e.state===jt&&e.health===Ce)return So;return e.state}function Sa(e){return{name:e,state:ko,health:Ct,pid:0,ports:{},restarts:0,last_error:"",identity:"",startTime:void 0,cpuPercent:void 0,memoryKB:void 0,profile:"",env_source:"daemon",orphaned:!1}}function Vm(e,t){let n={},r={};for(let a of Object.keys(t))n[a]=0;for(let a of Object.keys(t)){let c=e.services[a]?.dependencies??[];for(let l of c){let d=wt(l);if(!t[d])continue;r[d]=[...r[d]??[],a],n[a]=(n[a]??0)+1}}let o=[],i=Object.keys(t).length,s={};while(i>0){let a=Object.entries(n).filter(([c,l])=>l===0&&!s[c]).map(([c])=>c).sort();if(a.length===0)throw L($f,"dependency cycle detected while planning startup");o.push(a);for(let c of a){s[c]=!0,i-=1;for(let l of r[c]??[])n[l]=(n[l]??0)-1}}return o}function Bd(e,t){if(!e.services[t])throw L(fi,`unknown service "${t}"`)}function $i(e,t,n){let r={},o=(a)=>{if(r[a])return;Bd(e,a),r[a]=!0;for(let c of e.services[a]?.dependencies??[])o(wt(c))};for(let a of t)o(a);let i=Vm(e,r),s=[];return i.forEach((a,c)=>{for(let l of a)s.push({name:l,wave:c+1,dependencies:[...e.services[l]?.dependencies??[]]})}),{profile:n,steps:s,waves:i,blockers:[]}}function Wd(e,t){let n={};for(let[i,s]of Object.entries(e.services))for(let a of s.dependencies){let c=wt(a);n[c]=[...n[c]??[],i]}let r={},o=(i)=>{if(r[i])return;Bd(e,i),r[i]=!0;for(let s of n[i]??[])o(s)};for(let i of t)o(i);return Object.keys(r)}function Jm(e,t){let n=[...Vm(e,t)].reverse().map((o)=>[...o].sort()),r=[];return n.forEach((o,i)=>{for(let s of o)r.push({name:s,wave:i+1,dependencies:[...e.services[s]?.dependencies??[]]})}),{steps:r,waves:n,profile:"",blockers:[]}}function Ii(e,t){let n=Object.fromEntries(Wd(e,t).map((r)=>[r,!0]));return Jm(e,n)}function zm(e,t){let n={};for(let r of t)Bd(e,r),n[r]=!0;return Jm(e,n)}function Gd(e){let t="";if(e.profile!=="")t+=`Profile: ${e.profile}
|
|
17
|
-
|
|
18
|
-
`;t+=`Plan:
|
|
19
|
-
|
|
20
|
-
`;let n=1;for(let r of e.waves)for(let o of r)t+=`${n}. ${o}
|
|
21
|
-
`,n+=1;if((e.blockers??[]).length>0){t+=`
|
|
22
|
-
Blocked:
|
|
23
|
-
`;for(let r of e.blockers??[])t+=`- ${r.name}: ${r.message}
|
|
24
|
-
`}return t}function ka(e){return`${e.join(", ")} changed and only take effect after a full \`devctl down && devctl start\`, not a reload`}function l_(e,t,n){let r={};if(t!==""){let o=e.profiles[t];if(!o)throw L("configuration",`unknown profile "${t}"`);Object.assign(r,o.environment)}if(n.length>0)return{services:qm(e,n),env:r};if(t==="")return{services:Object.keys(e.services),env:r};return{services:qm(e,e.profiles[t]?.services??[]),env:r}}function d_(e){return Object.keys(e.profiles).sort()[0]??""}function Ca(e,t){let n=t.services??[],r=t.profile??"";if(n.length===0&&r===""){if(r=t.activeProfile||d_(e),r==="")throw L(Z,"no profile or services given; pass service names or add a profile")}let o=l_(e,r,n);return{services:o.services,env:o.env,profile:r}}function qm(e,t){let n={},r=[];for(let o of t){if(n[o])continue;if(!e.services[o])throw L("service_not_found",`unknown service "${o}"`);n[o]=!0,r.push(o)}return r}var Hd="STARTING",jt="RUNNING",Er="HEALTHY",So="UNHEALTHY",jd="STOPPING",ko="STOPPED",Kn="FAILED",Mi="RESTARTING",Ct="UNKNOWN",_t="HEALTHY",Ce="UNHEALTHY";var Rr=D(()=>{st();Re()});var Qm={};Ms(Qm,{createStarterConfig:()=>v_,resolveSetupTarget:()=>Ym,runSetup:()=>Vd});import{existsSync as qd,mkdirSync as Ud,statSync as u_,writeFileSync as p_}from"fs";import{createInterface as f_}from"readline/promises";import{stdin as g_,stdout as m_}from"process";import{basename as _a,dirname as Kd,join as xn,resolve as h_}from"path";function Ym(e,t){let n=e===""?process.cwd():e;if(t==="")return{repo:n,cfgPath:xn(n,St,qt)};let r=h_(t);if(!(qd(r)?u_(r).isDirectory():!/\.ya?ml$/i.test(r))){let i=Kd(r);return{repo:_a(i)===St?Kd(i):i,cfgPath:r}}if(_a(r)===St)return{repo:Kd(r),cfgPath:xn(r,qt)};return{repo:r,cfgPath:xn(r,St,qt)}}function v_(e,t=_a(e),n="",r="",o=!1){let i=xn(e,St,qt);if(!o&&qd(i))throw L(Z,`configuration already exists at ${i}; not overwriting`);return Xm(e,t,n,r),i}async function Vd(e,t="",n=!1){let{repo:r,cfgPath:o}=Ym(e,t);if(!n&&qd(o)){ht(`Found existing configuration at ${o}; nothing written.`),ht("Pass --force to overwrite it, or edit it directly.");return}let i=f_({input:g_,output:m_}),s=async(k,j)=>{let V=j!==""?` [${j}]`:"",C=(await i.question(`${k}${V}: `)).trim();return C===""?j:C},a=t===""?9:8,c=0,l=()=>(c+=1,c);if(ht(`devctl setup \u2014 ${a} steps`),ht(""),t==="")await s(`${l()}. Repository root`,r);let d=await s(`${l()}. Environment / project name`,_a(r)),f=await Ot(""),g=await s(`${l()}. Google Cloud project`,f.projectID);if(ht(`${l()}. Authentication`),!f.adcAvailable){if(ht(" ADC is not available. Run: gcloud auth application-default login"),(await s(" Run login now? (y/N)","n")).toLowerCase()==="y")try{await mo()}catch(j){ht(` login failed: ${j instanceof Error?j.message:String(j)}`)}}else if(ht(" \u2713 Application Default Credentials available"),f.userEmail!=="")ht(` user: ${f.userEmail}`);let m=await s(`${l()}. Service account email to record (optional, never hard-coded at runtime)`,""),x=await s(`${l()}. IAP audience to record on a sample route (optional)`,""),v=await s(`${l()}. Proxy listen port`,String(Bs)),w=Number(v)||Bs,E=await s(`${l()}. Default profile name (optional)`,"");i.close(),Xm(r,d,g,E,{sa:m,audience:x,proxyPort:w}),ht(""),ht(`Wrote starter configuration to ${o}`),ht(`${l()}. Validation`);try{let k=ut(r,""),j=await Un(k);ht(wa(j))}catch(k){ht(` configuration is not valid yet: ${k instanceof Error?k.message:String(k)}`),ht(" edit .devctl/config.yaml and run `devctl config validate`")}}function Xm(e,t,n,r,o={sa:"",audience:"",proxyPort:Bs}){let i=xn(e,".devctl");Ud(xn(i,"services"),{recursive:!0}),Ud(xn(i,"profiles"),{recursive:!0}),Ud(xn(i,"proxy"),{recursive:!0}),p_(xn(i,"config.yaml"),`# yaml-language-server: $schema=https://raw.githubusercontent.com/amr-m-abdelgawad/devctl/main/schema/devctl.config.schema.json
|
|
3
|
+
var EC=Object.defineProperty;var TC=(e)=>e;function AC(e,t){this[e]=TC.bind(null,t)}var LC=(e,t)=>{for(var r in t)EC(e,r,{get:t[r],enumerable:!0,configurable:!0,set:AC.bind(t,r)})};var D=(e,t)=>()=>(e&&(t=e(e=0)),t);var DC=import.meta.require;function um(e,t=""){if(t==="MetadataLookupWarning")return!0;return e.includes("MetadataLookupWarning")||e.startsWith("received unexpected error =")}function Gs(){if(dm)return;dm=!0;let e=process.emitWarning.bind(process);process.emitWarning=(t,...r)=>{let n=OC(r[0]),o=MC(t);if(um(o,n))return;e(t,...r)}}function pm(){let e=process.stderr.write.bind(process.stderr);return process.stderr.write=(t,r,n)=>{let o=IC(t);if(um(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 MC(e){if(typeof e==="string")return e;if(e instanceof Error)return e.message;return String(e)}function OC(e){if(typeof e==="string")return e;if(e&&typeof e==="object"&&"type"in e&&typeof e.type==="string")return e.type;return""}function IC(e){if(typeof e==="string")return e;if(e instanceof Uint8Array)return new TextDecoder().decode(e);return""}var dm=!1;import{createHash as $C}from"crypto";import{resolve as FC}from"path";function ar(e){let t=FC(e),r=process.platform==="win32"?t.toLowerCase():t;return $C("sha256").update(r).digest("hex").slice(0,NC)}var NC=16;var Us=()=>{};function Gl(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 ed(e=process.platform){return e==="darwin"}function rR(e=process.platform){return ed(e)?"cmd":"ctrl"}function _o(e,t=process.platform){return`${rR(t)}+${e}`}function nR(e=process.platform){return ed(e)?"command":"ctrl"}function Mt(e,t=process.platform){return`${nR(t)}+${e}`}function Ci(e){return e.replace(/\bcmd\b/gi,"command")}function Or(e,t=process.platform){let r=ed(t),n=Boolean(e.meta||e.super),o=Boolean(e.ctrl);return r?n&&!o:o&&!n}function Xr(e=process.platform){return _o("c",e)}function oR(e=process.platform){return{leader:_o("x",e),command_list:_o("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:Xr(e)}}function bm(){return{theme:"devctl",leader_timeout:2000,font_size:14,keybinds:{...iR},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 sR(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 pn(e,t){return sR(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 Zl=2000,Eo=14,xm="DEVCTL_TUI_CONFIG",iR;var Js=D(()=>{iR=oR()});function Se(e,t,r){return{type:e,timestamp:new Date().toISOString(),service:t,payload:r}}class od{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 km="ServiceStarted",ta="ServiceStopped",ra="ServiceFailed",Cm="ServiceStateChanged",Rm="ServiceHealthChanged",Ao="LogReceived",Lo="TokenRefreshed",jn="TokenRefreshFailed",rd="AuthenticationChanged",Pm="ProxyStarted",_m="ProxyStopped",nd="ProxyRequest",na="ConfigurationChanged",Ri="ConfigurationReloadFailed",Em="SessionRecovered";var Tm=5000,Am=500,id=16384,Lm=65536,oa="TRACE",ia="DEBUG",sa="INFO",Pi="WARN",Gn="ERROR",Do="FATAL",aa="UNKNOWN",sd;var _i=D(()=>{sd={["TRACE"]:0,["DEBUG"]:1,["INFO"]:2,["WARN"]:3,["ERROR"]:4,["FATAL"]:5,["UNKNOWN"]:2}});function Dm(){return{name:"default",parse:(e)=>{let t=dd(e);if(t)return t;return{level:ud(e),request_id:pd(e)||void 0}}}}function Ei(e,t){for(let r of t){let n=e[r];if(typeof n==="string"&&n.trim()!=="")return n}return}function Om(e){for(let t of mR){let r=e[t];if(typeof r==="number"){let n=kR[r];if(n)return n;continue}if(typeof r==="string"&&r.trim()!=="")return r.toUpperCase()}return}function Ti(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Zt(e){if(typeof e==="string"&&e.trim()!=="")return e;if(typeof e==="number"&&Number.isFinite(e))return String(e);return}function Mo(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 Ir(e,t){for(let r of t)if(e[r]!==void 0&&e[r]!==null)return e[r];return}function cd(e){return e.filter((t)=>t!==void 0&&t!=="").join(" ")}function CR(e){if(e>=hR)return Gn;if(e>=gR)return Pi;return}function RR(e){if(Ti(e))return e;return{}}function Im(e){let t=Zt(Ir(e,["http.method","method","request_method"])),r=Zt(Ir(e,["http.route","url.path","path","route","request_uri"])),n=Zt(Ir(e,["http.status_code","status","status_code"])),o=cd([t,r,n]);return o===""?void 0:o}function $m(e){if(!Ti(e))return Zt(e);if(typeof e.stringValue==="string")return e.stringValue.trim()===""?void 0:e.stringValue;return Zt(e.intValue??e.doubleValue??e.boolValue)}function PR(e){if(typeof e==="string"&&e.trim()!=="")return e;return $m(e)}function Fm(e){if(!Array.isArray(e)||e.length===0)return!1;return e.every((t)=>Ti(t)&&typeof t.key==="string"&&t.value!==void 0)}function _R(e){let t={};if(!Fm(e))return t;for(let r of e){let n=r.key;if(typeof n==="string"&&n!==""){let o=$m(r.value);if(o!==void 0)t[n]=o}}return t}function ER(e){let t=Om(e);if(t)return t;let r=Mo(e.severityNumber);if(r===void 0)return;if(r>=SR)return Do;if(r>=wR)return Gn;if(r>=bR)return Pi;if(r>=xR)return sa;if(r>=vR)return ia;if(r>=yR)return oa;return}function TR(e){if(e.timeUnixNano!==void 0||e.observedTimeUnixNano!==void 0)return!0;if(Ti(e.body)&&(e.body.stringValue!==void 0||e.body.intValue!==void 0||e.body.doubleValue!==void 0))return!0;return Fm(e.attributes)}function AR(e,t){if(!TR(e))return;let r=_R(e.attributes),n=PR(e.body)??Im(r)??"log",o=Ei(e,ad)??Zt(r.trace_id??r.traceId);return{message:n,level:ER(e),request_id:o,raw:t}}function LR(e,t){let r=Zt(e.metric_name);if(r===void 0)return;let n=Zt(e.metric_type),o=Mo(e.value);if(n===void 0&&o===void 0)return;let i=Zt(e.unit),s=o===void 0?void 0:i===void 0?String(o):`${o} ${i}`;return{message:cd([r,n,s,Im(RR(e.attributes))]),raw:t}}function DR(e){let t=e.trim().split(/\s+/);return{method:t[0],uri:t[1]}}function MR(e,t){if(Ei(e,Mm)!==void 0)return;let r=Zt(e.request),n=r===void 0?{}:DR(r),o=Zt(Ir(e,["request_method","method","http_method","verb"]))??n.method,i=Zt(Ir(e,["request_uri","uri","url","path","request_path"]))??n.uri,s=Mo(Ir(e,["status","status_code","statusCode","http_status"])),a=Zt(Ir(e,["remote_ip","remote_addr","client_ip"]));if(o===void 0||i===void 0)return;if(s===void 0&&a===void 0&&r===void 0)return;let c=Mo(Ir(e,["body_bytes_sent","bytes_sent","bytes"])),l=Mo(Ir(e,["request_time","duration"])),d=Mo(Ir(e,["request_time_ms","latency_ms","duration_ms"])),u=c===void 0?void 0:`${c}B`,f=d!==void 0?`${d}ms`:l===void 0?void 0:`${l}s`;return{message:cd([a,o,i,s===void 0?void 0:String(s),u,f]),level:s===void 0?void 0:CR(s),request_id:Ei(e,ad),raw:t}}function OR(e,t){let r=Ei(e,Mm),n=Om(e),o=Ei(e,ad);if(r===void 0&&n===void 0&&o===void 0)return;return{message:r??t,level:n,request_id:o,raw:t}}function ld(e){if(e.length<=id)return e;return e.slice(0,id)}function dd(e){let t=e.trim();if(!t.startsWith("{")||!t.endsWith("}"))return;if(t.length>Lm)return;let r;try{r=JSON.parse(t)}catch{return}if(!Ti(r))return;return AR(r,t)??LR(r,t)??MR(r,t)??OR(r,t)}function ud(e){return $R.find((r)=>r.re.test(e))?.level??aa}function pd(e){return IR.exec(e)?.[1]??""}var Mm,mR,ad,gR=400,hR=500,yR=1,vR=5,xR=9,bR=13,wR=17,SR=21,kR,IR,$R;var Nm=D(()=>{_i();Mm=["message","msg","text","log","event"],mR=["level","severity","severityText","levelname","loglevel","lvl"],ad=["request_id","requestId","trace_id","traceId","correlation_id","correlationId"],kR={10:oa,20:ia,30:sa,40:Pi,50:Gn,60:Do};IR=/(?:x-devctl-request-id|request[_-]?id)[=: ]+([A-Za-z0-9-]+)/i,$R=[{re:/\b(fatal|critical)\b/i,level:Do},{re:/\b(error|err)\b/i,level:Gn},{re:/\b(warn|warning)\b/i,level:Pi},{re:/\b(debug|dbg)\b/i,level:ia},{re:/\b(trace)\b/i,level:oa},{re:/\b(info|information)\b/i,level:sa}]});function Ai(e){let t=FR(e);if(t===void 0)return;return new RegExp(t)}function FR(e){if(e.length===0||e.length>200)return;let t={raw:e,i:0,out:[],quantifiers:0,depth:0,lastAtom:"none",groupQuant:[]};if(!Hm(t)||t.i!==e.length||t.depth!==0)return;return t.out.join("")}function Hm(e){while(e.i<e.raw.length){if(e.raw[e.i]===")")return!0;if(!NR(e))return!1}return!0}function NR(e){let t=e.raw[e.i]??"";if(t==="|")return ca(e,"|","none");if(t==="^")return ca(e,"^","none");if(t==="$")return ca(e,"$","none");if(t===".")return ca(e,".","atom");if(t==="(")return HR(e);if(t==="[")return WR(e);if(t==="*"||t==="+"||t==="?"||t==="{")return BR(e);if(t==="\\")return Bm(e);return e.out.push(RegExp.escape(t)),e.i+=1,e.lastAtom="atom",!0}function ca(e,t,r){return e.out.push(t),e.i+=1,e.lastAtom=r,!0}function HR(e){if(e.i+=1,e.depth+=1,e.depth>2)return!1;if(e.groupQuant.push(!1),e.out.push("(?:"),!Hm(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 BR(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 WR(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(!Bm(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 Bm(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 Oo(e,t){if(e.services&&e.services.length>0&&!e.services.includes(t.service))return!1;if(e.level&&(sd[t.level]??2)<(sd[e.level]??2))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;return!0}function fd(e){if(!e.search)return()=>!0;if(e.regex){let r=Ai(e.search);if(r)return(n)=>r.test(n.message)||n.raw!==void 0&&r.test(n.raw)}let t=e.search.toLowerCase();return(r)=>r.message.toLowerCase().includes(t)||r.raw!==void 0&&r.raw.toLowerCase().includes(t)}function md(e){let t=fd(e);return(r)=>Oo(e,r)&&t(r)}var Wm=D(()=>{_i()});function jm(e){if(!Number.isInteger(e)||(e??0)<=0)return Am;return Math.min(e,Tm)}var Gm=D(()=>{_i()});var la=D(()=>{_i();Nm();Wm();Gm()});function M(e,t){return new Qe(e,t)}function Re(e,t,r){let n=r instanceof Error?r:Error(String(r));return new Qe(e,t,{cause:n})}function Ne(e,t,r,n=""){return new Qe(e,t,{hint:r,service:n})}function ua(e,t){return e instanceof Qe&&e.kind===t}function eg(e){if(e instanceof Qe)return e.exitCode();return 1}function tg(e){if(e instanceof Qe)return{error:A(e),kind:e.kind,hint:e.hint,service:e.service};return{error:A(e)}}function rg(e){if(typeof e==="string")return M("general",e);if(e.kind)return new Qe(e.kind,e.error.replace(`${e.kind}: `,""),{hint:e.hint,service:e.service});return M("general",e.error)}function A(e){if(e instanceof Qe){if(e.hint!=="")return`${Xm(e)} \u2014 ${e.hint}`;return Xm(e)}if(e instanceof Error)return e.message;return String(e)}function Xm(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 Qm=1,ee="configuration",Kn="configuration_missing",Io="service_not_found",Zm="dependency",He="process_start",$o="authentication",qn="authorization",Qr="token",da="impersonation",Sd="iap",fn="proxy",kd="health_check",ct="general",Qe;var te=D(()=>{Qe=class Qe 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 ya(e){return e>0?e:300}function Pd(){return{enabled:!1,paths:[],debounce_ms:300,ignore:[...Di]}}function No(){return{args:[],shell:!1}}function _d(){return{vars:{},required:[],defaults:{}}}function Ed(){return{type:"",url:"",address:"",command:No(),interval_seconds:0,timeout_seconds:0,start_period_seconds:0,unhealthy_threshold:3,healthy_reset_threshold:10}}function Jt(e){return typeof e==="string"?e:e.service}function mn(e){return typeof e==="string"?"service_started":e.condition||"service_started"}function xa(e){return mn(e)==="service_healthy"?`${Jt(e)} (healthy)`:Jt(e)}function Td(){return{type:"",mode:"",service_account:"",config:{}}}function gn(){return{extends:"",description:"",command:No(),shell:!1,working_dir:"",dependencies:[],ports:[],environment:_d(),health:Ed(),identity:Td(),logs:{stdout:!1,stderr:!1},restart:{policy:"",max_retries:0,backoff_seconds:0},startup:{wait_for_healthy:!1,timeout_seconds:0},capabilities:[],proxy:[],container:void 0,watch:Pd(),hooks:{pre_start:No(),post_start:No()}}}function Jn(){return{version:1,project:{name:""},google:{project_id:"",region:""},profiles:{},templates:{},services:{},tasks:{},proxy:{enabled:!1,listen:{host:va,port:0},token_endpoint:{enabled:!1,host:"",port:0},routes:[]},logs:{max_memory_events:pP,persistence:{enabled:!0,directory:"~/.devctl/logs",retention_days:fP,max_session_logs:0}},auth:{refresh_threshold_seconds:sg},shutdown:{grace_seconds:ig},ui:{theme:"system",keymap:{}},secrets:{extra_markers:[],extra_patterns:[]},doctor:{tools:[]},plugins:[],environment:{sources:[],secrets:{}},provenance:{},repoRoot:"",configPath:""}}function hn(e){return e.args.length===0||e.args.length===1&&(e.args[0]??"").trim()===""}function Oi(e){if(e.type!=="")return e.type;return e.mode}function Zr(e){let t=Oi(e).toLowerCase();return t==="service"||t==="service_account"}function ag(e){let t=Oi(e).toLowerCase();return t==="user"||t===""}function ba(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 yn(e){let t=e.host===""?va:e.host;if(e.port===0)return t;return`${t}:${e.port}`}function cg(e){if(e.refresh_threshold_seconds<=0)return sg;return e.refresh_threshold_seconds}function wa(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 ig;return e.grace_seconds}function lg(e){if(!e.logs.stdout&&!e.logs.stderr)return!0;return e.logs.stdout}function dg(e){if(!e.logs.stdout&&!e.logs.stderr)return!0;return e.logs.stderr}function Ad(e,t){return e.find((r)=>r.name===t)}function ug(e){return e[0]}var Ho=1,ma="never",ga="on_failure",ha="always",Di,Mi=8080,ig=10,sg=300,pP=50000,fP=14,va="127.0.0.1";var mt=D(()=>{Di=["**/node_modules/**","**/.git/**"]});var Nt=".devctl",lr="config.yaml";import{basename as mP}from"path";function xn(e,t=""){return{name:mP(e),project:t,profile:"",sa:"",audience:"",proxyPort:Mi}}function Sa(e,t=Mi){let r=Number(e);return Number.isFinite(r)&&r>0?r:t}function pg(e){let t=e;return`# yaml-language-server: $schema=https://raw.githubusercontent.com/amr-m-abdelgawad/devctl/main/schema/devctl.config.schema.json
|
|
25
4
|
version: 1
|
|
26
5
|
|
|
27
6
|
project:
|
|
28
|
-
name: ${
|
|
7
|
+
name: ${e.name}
|
|
29
8
|
|
|
30
9
|
google:
|
|
31
|
-
project_id: ${
|
|
10
|
+
project_id: ${e.project}
|
|
32
11
|
|
|
33
|
-
profiles:${
|
|
34
|
-
${
|
|
12
|
+
profiles:${e.profile===""?" {}":`
|
|
13
|
+
${e.profile}:
|
|
35
14
|
services: []`}
|
|
36
15
|
|
|
37
16
|
services:
|
|
@@ -42,7 +21,7 @@ proxy:
|
|
|
42
21
|
enabled: true
|
|
43
22
|
listen:
|
|
44
23
|
host: 127.0.0.1
|
|
45
|
-
port: ${
|
|
24
|
+
port: ${t.proxyPort}${t.audience===""?"":`
|
|
46
25
|
routes:
|
|
47
26
|
- name: sample
|
|
48
27
|
match:
|
|
@@ -51,8 +30,8 @@ proxy:
|
|
|
51
30
|
url: http://127.0.0.1:8081
|
|
52
31
|
auth:
|
|
53
32
|
type: iap
|
|
54
|
-
audience: ${
|
|
55
|
-
identity: ${
|
|
33
|
+
audience: ${t.audience}
|
|
34
|
+
identity: ${t.sa===""?"user":`{ type: service_account, service_account: ${t.sa} }`}
|
|
56
35
|
`}
|
|
57
36
|
|
|
58
37
|
logs:
|
|
@@ -68,13 +47,17 @@ auth:
|
|
|
68
47
|
shutdown:
|
|
69
48
|
stop_services_on_exit: true
|
|
70
49
|
grace_seconds: 10
|
|
71
|
-
`)}function
|
|
72
|
-
`)}var
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
50
|
+
`}var wt;var ka=D(()=>{mt();wt=[{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 Md,mkdirSync as Ld,statSync as gP,writeFileSync as hP}from"fs";import{createInterface as yP}from"readline/promises";import{stdin as vP,stdout as xP}from"process";import{basename as Ca,dirname as Dd,join as en,resolve as bP}from"path";function Od(e,t){let r=e===""?process.cwd():e;if(t==="")return{repo:r,cfgPath:en(r,Nt,lr)};let n=bP(t);if(!(Md(n)?gP(n).isDirectory():!/\.ya?ml$/i.test(n))){let i=Dd(n);return{repo:Ca(i)===Nt?Dd(i):i,cfgPath:n}}if(Ca(n)===Nt)return{repo:Dd(n),cfgPath:en(n,lr)};return{repo:n,cfgPath:en(n,Nt,lr)}}function fg(e,t=Ca(e),r="",n="",o=!1){let i=en(e,Nt,lr);if(!o&&Md(i))throw M(ee,`configuration already exists at ${i}; not overwriting`);return Ra(e,{...xn(e,r),name:t,profile:n}),i}async function mg(e,t,r="",n=!1){let{repo:o,cfgPath:i}=Od(t,r);if(!n&&Md(i)){Ht(`Found existing configuration at ${i}; nothing written.`),Ht("Pass --force to overwrite it, or edit it directly.");return}let s=yP({input:vP,output:xP}),a=async(g,y)=>{let x=y!==""?` [${y}]`:"",h=(await s.question(`${g}${x}: `)).trim();return h===""?y:h},c=0,l=()=>(c+=1,c);if(Ht(`devctl setup \u2014 ${wt.length} steps`),Ht(""),r==="")await a(`${l()}. Repository root`,o);let d=xn(o,""),u=await a(`${l()}. ${wt[1]?.prompt}`,Ca(o));d.name=u;let f=await e.detectGoogle(""),p=await a(`${l()}. ${wt[2]?.prompt}`,f.projectID);if(d.project=p,Ht(`${l()}. ${wt[3]?.title}`),!f.adcAvailable){if(Ht(" 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(y){Ht(` login failed: ${y instanceof Error?y.message:String(y)}`)}}else if(Ht(" \u2713 Application Default Credentials available"),f.userEmail!=="")Ht(` user: ${f.userEmail}`);d.sa=await a(`${l()}. ${wt[4]?.prompt}`,""),d.audience=await a(`${l()}. ${wt[5]?.prompt}`,"");let m=await a(`${l()}. ${wt[6]?.prompt}`,String(Mi));d.proxyPort=Sa(m),d.profile=await a(`${l()}. ${wt[7]?.prompt}`,""),s.close(),Ra(o,d),Ht(""),Ht(`Wrote starter configuration to ${i}`),Ht(`${l()}. Validation`);try{let g=e.load(o,""),y=await e.runDoctor.execute(g);Ht(e.formatDoctor(y))}catch(g){Ht(` configuration is not valid yet: ${g instanceof Error?g.message:String(g)}`),Ht(" edit .devctl/config.yaml and run `devctl config validate`")}}function Ra(e,t){let r=en(e,".devctl");Ld(en(r,"services"),{recursive:!0}),Ld(en(r,"profiles"),{recursive:!0}),Ld(en(r,"proxy"),{recursive:!0}),hP(en(r,"config.yaml"),pg(t))}function Ht(e){process.stdout.write(`${e}
|
|
51
|
+
`)}var Pa=D(()=>{mt();ka();te()});function Cn(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:T_(e,t),...n,shadowed:r.slice(0,-1)}]})}function T_(e,t){let r=e;for(let n of t.split(".")){if(typeof r!=="object"||r===null)return;r=r[n]}return r}function Fa(e){if(Zr(e))return dr({kind:eo,serviceAccount:e.service_account});if(ag(e)&&(e.type!==""||e.mode!==""))return dr({kind:$a});let t=(e.type||e.mode).toLowerCase();if(t!=="")return dr({kind:t,providerConfig:e.config??{}});return dr({kind:Wo})}function to(e){if(e.type.toLowerCase()==="none")return dr({kind:Wo});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 dr({kind:eo,serviceAccount:r});if(e.type.toLowerCase()==="iap"&&t==="")return dr({kind:Wo});if(e.type===""&&t==="")return dr({kind:Wo});return dr({kind:$a})}function mh(e){return e.kind===$a||e.kind===eo}function jo(e){if(e.tokenKey!=="")return e.tokenKey;if(e.kind===eo)return`sa:${e.serviceAccount}`;if(e.email!=="")return`user:${e.email}`;return"user"}function dr(e={}){return{kind:Wo,email:"",serviceAccount:"",project:"",projectSource:"",adcAvailable:!1,providerConfig:{},tokenKey:"",...e}}function Yd(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(Zr(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 $r(e){return Yd(e).filter((t)=>t.active).map((t)=>t.email)}function gh(e,t,r){let n=[];for(let o of t){let i=e.services[o];if(!i)continue;let s=Fa(i.identity);if(Zr(i.identity)&&i.identity.service_account===""){n.push({name:o,message:"service account identity is not configured"});continue}if((mh(s)||i.capabilities.some((c)=>c==="google_api"||c==="iap"||c==="service_identity"))&&!r)n.push({name:o,message:"ADC unavailable"})}return n}function Hi(e){if($r(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(mh(Fa(t.identity)))return!0;return t.capabilities.some((r)=>r==="google_api"||r==="iap"||r==="service_identity")})}function Xd(){return{name:"user",accepts:(e)=>!Zr(e),resolve:async(e,t)=>{if(e.type===""&&e.mode==="")return dr({kind:Wo});return{...await t(),kind:$a}}}}function Qd(){return{name:"service_account",accepts:(e)=>Zr(e),resolve:async(e,t)=>{if(e.service_account==="")throw M(da,"service account identity is not configured");return{...await t(),kind:eo,serviceAccount:e.service_account}}}}async function hh(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(Zr(e))return Qd().resolve(e,t);return Xd().resolve(e,t)}var $a="user",eo="service_account",Wo="none";var Fr=D(()=>{mt();te()});function er(){return"devctl 0.2.5"}var Bt="0.2.5",ji=1;function Oh(e){return e}function ur(e){return e}function Jo(e){if(e.state===Be&&e.health===Wt)return pr;if(e.state===Be&&e.health===Me)return Nr;return e.state}function Ki(e){return{name:e,state:_t,health:Et,pid:0,ports:{},restarts:0,last_error:"",identity:"",startTime:void 0,cpuPercent:void 0,memoryKB:void 0,profile:"",env_source:"daemon",orphaned:!1}}function Fh(e,t){let r={},n={};for(let a of Object.keys(t))r[a]=0;for(let a of Object.keys(t)){let c=e.services[a]?.dependencies??[];for(let l of c){let d=Jt(l);if(!t[d])continue;n[d]=[...n[d]??[],a],r[a]=(r[a]??0)+1}}let o=[],i=Object.keys(t).length,s={};while(i>0){let a=Object.entries(r).filter(([c,l])=>l===0&&!s[c]).map(([c])=>c).sort();if(a.length===0)throw M(Zm,"dependency cycle detected while planning startup");o.push(a);for(let c of a){s[c]=!0,i-=1;for(let l of n[c]??[])r[l]=(r[l]??0)-1}}return o}function uu(e,t){if(!e.services[t])throw M(Io,`unknown service "${t}"`)}function za(e,t,r){let n={},o=(a)=>{if(n[a])return;uu(e,a),n[a]=!0;for(let c of e.services[a]?.dependencies??[])o(Jt(c))};for(let a of t)o(a);let i=Fh(e,n),s=[];return i.forEach((a,c)=>{for(let l of a)s.push({name:l,wave:c+1,dependencies:[...e.services[l]?.dependencies??[]]})}),{profile:r,steps:s,waves:i,blockers:[]}}function io(e,t){let r={};for(let[i,s]of Object.entries(e.services))for(let a of s.dependencies){let c=Jt(a);r[c]=[...r[c]??[],i]}let n={},o=(i)=>{if(n[i])return;uu(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 Nh(e,t){let r=[...Fh(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 Ya(e,t){let r=Object.fromEntries(io(e,t).map((n)=>[n,!0]));return Nh(e,r)}function Xa(e,t){let r={};for(let n of t)uu(e,n),r[n]=!0;return Nh(e,r)}function Hh(e){let t="";if(e.profile!=="")t+=`Profile: ${e.profile}
|
|
52
|
+
|
|
53
|
+
`;t+=`Plan:
|
|
54
|
+
|
|
55
|
+
`;let r=1;for(let n of e.waves)for(let o of n)t+=`${r}. ${o}
|
|
56
|
+
`,r+=1;if((e.blockers??[]).length>0){t+=`
|
|
57
|
+
Blocked:
|
|
58
|
+
`;for(let n of e.blockers??[])t+=`- ${n.name}: ${n.message}
|
|
59
|
+
`}return t}function Qa(e){return`${e.join(", ")} changed and only take effect after a full \`devctl down && devctl start\`, not a reload`}function PE(e,t,r){let n={};if(t!==""){let o=e.profiles[t];if(!o)throw M("configuration",`unknown profile "${t}"`);Object.assign(n,o.environment)}if(r.length>0)return{services:Ih(e,r),env:n};if(t==="")return{services:Object.keys(e.services),env:n};return{services:Ih(e,e.profiles[t]?.services??[]),env:n}}function _E(e){let t=Object.keys(e.profiles).sort();return ur(t[0]??"")}function so(e,t){if(t==="")return{};return{...e.profiles[ur(t)]?.environment??{}}}function Za(e,t){let r=t.services??[],n=t.profile??ur("");if(r.length===0&&n===""){if(n=t.activeProfile||_E(e),n==="")throw M(ee,"no profile or services given; pass service names or add a profile")}let o=PE(e,n,r);return{services:o.services,env:o.env,profile:n}}function Ih(e,t){let r={},n=[];for(let o of t){if(r[o])continue;if(!e.services[o])throw M("service_not_found",`unknown service "${o}"`);r[o]=!0,n.push(o)}return n}var $h="UNKNOWN",rn="STARTING",Be="RUNNING",pr="HEALTHY",Nr="UNHEALTHY",Rr="STOPPING",_t="STOPPED",lt="FAILED",fr="RESTARTING",Et="UNKNOWN",Wt="HEALTHY",Me="UNHEALTHY";var Tt=D(()=>{mt();te()});function py(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 fy(e){let t=dy(e.scriptPath),r=dy(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=r0();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 my(e,t){let r=uy(e),n=uy(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 r0(){return[process.platform==="win32"?"npm.cmd":"npm","install","--global","@amr-m-abdelgawad/devctl@latest"]}function dy(e){return e.replaceAll("\\","/")}function uy(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 sc="restart the daemon with `devctl down` then start again";function Pn(e){if(!Number.isInteger(e))return Gu;return Math.min(WT,Math.max(jT,e))}function uv(e,t){if(t.length!==1||t<"0"||t>"9")return e;if(e.length>=GT)return t;return`${e}${t}`}function pv(e){return e.slice(0,-1)}function fv(e,t){if(e==="")return Pn(t);let r=Number(e);if(!Number.isInteger(r))return Pn(t);return Pn(r)}function lo(e){let t=Number.parseInt(ar(e).slice(0,BT),16),r=Number.isFinite(t)?t%dv:0;return Gu+r}function mv(e,t){return t===lo(e)}var Gu=18700,dv=600,ZH,BT=8,WT=65535,jT=1024,GT=5;var Uu=D(()=>{Us();ZH=Gu+dv-1});class mr{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 eA(t)}}function eA(e){let t=e.toLowerCase(),r="authorization: bearer ",n=t.indexOf("authorization: bearer ");if(n>=0)return kv(e,n+22);let o=t.indexOf("bearer ");if(o<0)return e;return kv(e,o+7)}function kv(e,t){let r=t;while(r<e.length&&!tA(e[r]??""))r+=1;return e.slice(0,t)+"********"+e.slice(r)}function tA(e){return e===" "||e==="\t"||e===`
|
|
60
|
+
`||e==="\r"}var Sv;var ti=D(()=>{Sv=["PASSWORD","SECRET","TOKEN","PRIVATE_KEY","CLIENT_SECRET","API_KEY","CREDENTIAL","ACCESS_KEY","AUTH_KEY"]});var yc;var Cv=D(()=>{yc={procedure:`---
|
|
78
61
|
name: devctl-onboard
|
|
79
62
|
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.
|
|
80
63
|
---
|
|
@@ -382,7 +365,7 @@ the agent to set it up" a complete path. In that state \`get_status\` reports
|
|
|
382
365
|
arguments reports the missing configuration rather than a parse error. Draft,
|
|
383
366
|
validate the candidate text, write the files, then call \`reload_config\`: setup
|
|
384
367
|
mode clears on the reload that finds a valid configuration.
|
|
385
|
-
`,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`\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` `container` `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| `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| `proxy` | `enabled` `listen` `token_endpoint` `routes` |\n| `proxy.listen` | `host` `port` |\n| `proxy.token_endpoint` | `enabled` `host` `port` |\n| `route` | `name` `match` `upstream` `auth` |\n| `route.match` | `host` `path` |\n| `route.upstream` | `url` |\n| `route.auth` | `type` `identity` `audience` `service_account` |\n| `logs` | `max_memory_events` `persistence` |\n| `logs.persistence` | `enabled` `directory` `retention_days` `max_session_logs` |\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>}` and `${services.<name>.port}` are the\nsupported forms. Anything else \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 an IP or `localhost`. `0.0.0.0` is rejected.\n- `proxy.token_endpoint.host` must be loopback; `0.0.0.0` is rejected.\n- Every route needs a `name` and an `upstream.url`.\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- 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.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
|
|
368
|
+
`,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`\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` `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| `proxy` | `enabled` `listen` `token_endpoint` `routes` |\n| `proxy.listen` | `host` `port` |\n| `proxy.token_endpoint` | `enabled` `host` `port` |\n| `route` | `name` `match` `upstream` `auth` |\n| `route.match` | `host` `path` |\n| `route.upstream` | `url` |\n| `route.auth` | `type` `identity` `audience` `service_account` |\n| `logs` | `max_memory_events` `persistence` |\n| `logs.persistence` | `enabled` `directory` `retention_days` `max_session_logs` |\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>}` and `${services.<name>.port}` are the\nsupported forms. Anything else \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- Every route needs a `name` and an `upstream.url`.\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- 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.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
|
|
386
369
|
|
|
387
370
|
How to turn what a repository contains into the service list you draft from.
|
|
388
371
|
Read the signals in roughly this order \u2014 the earlier ones describe *how the
|
|
@@ -424,6 +407,8 @@ health check, and dependencies. Keep container-backed services out of the
|
|
|
424
407
|
default profile when doing so preserves a repository's existing no-Docker
|
|
425
408
|
onboarding path.
|
|
426
409
|
|
|
410
|
+
\`devctl config import compose <file>\` (dry-run) prints mapped YAML and a table of dropped fields (\`build\`, \`networks\`, \`deploy\`, \`replicas\`, per-service \`env_file\`, \`volumes\`, \u2026). \`--write\` saves mapped fields only under \`.devctl/config.yaml\` after the same decode/validate path as hand-authored configs. TUI: \`/import compose [path]\`. K8s import is not implemented.
|
|
411
|
+
|
|
427
412
|
### Procfile
|
|
428
413
|
|
|
429
414
|
Nearly a direct translation \u2014 one line, one service:
|
|
@@ -607,55 +592,77 @@ Rules for turning that into YAML:
|
|
|
607
592
|
a full one. Remember that a bare \`devctl start\` falls back to the first
|
|
608
593
|
configured profile, and the TUI's default is the first profile
|
|
609
594
|
alphabetically \u2014 so name them with that in mind.
|
|
610
|
-
`}});import{existsSync as j0,readFileSync as B0}from"fs";function qn(e,t){return!(t??[]).includes(e)}function Vh(e){return Ua.filter((t)=>qn(t.name,e))}function Ka(e){return Ua.some((t)=>t.name===e)}function qa(e){return new Vt(e.secrets.extra_markers,e.secrets.extra_patterns)}function Jh(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 G0(e,t){let n=e.config(),r=n.services[t];if(!r)throw Error(`unknown service ${t}`);let i=e.status().services[t],s=qa(n);return{name:t,state:i?.state,health:i?.health,pid:i?.pid,last_error:i?.last_error,command:r.command.args,cwd:r.working_dir,ports:i?.ports??Object.fromEntries(r.ports.map((a)=>[a.name,a.value])),environment:s.redactMap({...r.environment.defaults,...r.environment.vars}),container:r.container?{...r.container,env:s.redactMap(r.container.env)}:void 0}}function zh(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},logs:e.logs,mcp:e.mcp?{running:e.mcp.running,address:e.mcp.address,port:e.mcp.port}:{running:!1}}}async function Yh(e,t){let n=typeof t.service==="string"?t.service:"",r=typeof t.since==="string"?t.since:"",o=typeof t.cursor==="string"?t.cursor:void 0,i=await e.logsPage({services:n===""?[]:[n],level:typeof t.level==="string"?t.level:"",search:typeof t.search==="string"?t.search:"",source:typeof t.source==="string"?t.source:"",since:r,until:typeof t.until==="string"?t.until:"",cursor:o,direction:o?"forward":void 0,limit:W0}),s=qa(e.config());return{events:i.events.map((a)=>({timestamp:a.timestamp,service:a.service,source:a.source,level:a.level,message:s.redactText(a.message),pid:a.pid})),truncated:i.hasPrev,has_more:i.hasNext,next_since:i.events[i.events.length-1]?.timestamp??r,next_cursor:i.nextCursor,session_changed:i.sessionChanged}}function U0(e){return Object.entries(e.profiles).sort(([t],[n])=>t.localeCompare(n)).map(([t,n])=>({name:t,services:n.services}))}function Xh(e){let t=Object.entries(e.services).map(([n,r])=>({name:n,description:r.description,command:r.command.args,cwd:r.working_dir,ports:r.ports.map((o)=>({name:o.name,value:o.auto?0:o.value,auto:o.auto})),dependencies:r.dependencies,container:r.container?{image:r.container.image,runtime:r.container.runtime||"docker",ports:r.container.ports,volumes:r.container.volumes}:void 0}));return{project:e.project.name,config_path:e.configPath,repo_root:e.repoRoot,services:t,proxy:{enabled:e.proxy.enabled,listen:{host:e.proxy.listen.host,port:e.proxy.listen.port},routes:e.proxy.routes.map((n)=>({name:n.name,match:n.match,upstream:n.upstream.url,auth:n.auth.type}))}}}function K0(e){let t=qa(e);return{entries:vr(e).map((n)=>{let r=typeof n.value==="string"?n.value:JSON.stringify(n.value);return{...n,value:t.redactMap({[n.path]:r})[n.path]}})}}function Ga(e){if(!Array.isArray(e))return[];return e.filter((t)=>typeof t==="string")}async function Qh(e,t,n){switch(t){case"list_services":return Jh(e.status());case"get_service":if(typeof n.name!=="string"||n.name==="")throw Error("name is required");return G0(e,n.name);case"get_status":return zh(e.status());case"get_logs":return Yh(e,n);case"list_profiles":return U0(e.config());case"get_config":return Xh(e.config());case"get_config_sources":return K0(e.config());case"run_doctor":return e.doctor();case"start_services":return e.start({services:Ga(n.services),profile:typeof n.profile==="string"?n.profile:""});case"stop_services":return await e.stop(Ga(n.services)),{ok:!0};case"restart_services":return await e.restart(Ga(n.services),n.cascade===!0),{ok:!0};case"reload_config":return e.reload();case"exec_service":{if(typeof n.service!=="string"||n.service==="")throw Error("service is required");if(!e.exec)throw Error("exec is unavailable");let r=await e.exec(n.service,Ga(n.command),n.print_env===!0),o=qa(e.config());return{...r,stdout:o.redactText(r.stdout),stderr:o.redactText(r.stderr),environment:r.environment?o.redactMap(r.environment):void 0}}case"get_setup_guide":return q0(n);case"validate_config":return V0(e,n);default:throw Error(`unknown tool ${t}`)}}function q0(e){let t=typeof e.section==="string"?e.section:"procedure",n=t in Wa?t:"procedure";return{section:n,text:Wa[n],sections:Object.keys(Wa)}}function V0(e,t){let n=e.config();if(typeof t.text==="string"){let o=co(n.repoRoot,n.configPath,t.text);return{valid:o.length===0,issues:o,source:"candidate",config_path:n.configPath}}if(!j0(n.configPath))return{valid:!1,issues:[`no configuration at ${n.configPath}`],source:"disk",config_path:n.configPath,setup_mode:!0};let r=co(n.repoRoot,n.configPath,B0(n.configPath,"utf8"));return{valid:r.length===0,issues:r,source:"disk",config_path:n.configPath}}function Zh(e){return uu.includes(e)}async function ev(e,t){switch(t){case"devctl://status":return zh(e.status());case"devctl://services":return Jh(e.status());case"devctl://logs":return Yh(e,{});case"devctl://config":return Xh(e.config());case"devctl://doctor":return e.doctor();default:throw Error(`unknown resource ${t}`)}}var W0=200,uu,pu,Ua;var Gi=D(()=>{st();Ao();qh();uu=["devctl://status","devctl://services","devctl://logs","devctl://config","devctl://doctor"],pu=["inspect","logs","diagnostics","control","setup"],Ua=[{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 lines, 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"}},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. No secret env values.",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:"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:"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}}]});function Or(e){if(!Number.isInteger(e))return gu;return Math.min(av,Math.max(iE,e))}function cv(e,t){if(t.length!==1||t<"0"||t>"9")return e;if(e.length>=sE)return t;return`${e}${t}`}function lv(e){return e.slice(0,-1)}function dv(e,t){if(e==="")return Or(t);let n=Number(e);if(!Number.isInteger(n))return Or(t);return Or(n)}function Do(e){let t=Number.parseInt(vn(e).slice(0,rE),16),n=Number.isFinite(t)?t%sv:0;return gu+n}function uv(e,t){return t===Do(e)}async function pv(e,t){let n=Number.isInteger(t)&&(t??0)>0?t:Do(e);for(let r=0;r<oE;r+=1){let o=n+r;if(o>av)break;if(await vo(o))return o}throw L(Z,`no free MCP port starting at ${n}`)}var gu=18700,sv=600,AM,rE=8,oE=600,av=65535,iE=1024,sE=5;var Ja=D(()=>{Re();Ri();ze();AM=gu+sv-1});import{existsSync as Qa,readFileSync as za}from"fs";import{dirname as aE,isAbsolute as fv,join as Xa,resolve as cE}from"path";function bn(){return process.platform==="darwin"?"cmd+c":"ctrl+shift+c"}function gE(){return{theme:"devctl",leader_timeout:Za,font_size:$r,keybinds:{...fE},scroll_speed:lE,scroll_acceleration:{enabled:!1},diff_style:"auto",cursor:{style:"block",blinking:!0},mouse:!0,attention:{enabled:!1,notifications:!0,sound:!0,volume:dE,sound_pack:"default",sounds:{}},log_timestamps:!0,log_metadata:!0,mcp_enabled:!1}}function ec(){return Xa(Nt(),"tui.json")}function Vi(e=""){for(let t of[uE,pE]){let n=process.env[t];if(!n||n==="")continue;let r=fv(n)?n:cE(e||process.cwd(),n);if(Qa(r))return r}return}function mE(e,t){if(!t||Object.keys(t).length===0)return e;return{...e,keybinds:{...e.keybinds,...t}}}function Qt(e,t){let n=mE(gE(),t),r=Vi(e);if(r)return mu(n,Ya(za(r,"utf8")),r);let o=hE(e),i=o?mu(n,Ya(za(o,"utf8")),o):n,s=ec();if(!Qa(s)||o===s)return i;return mu(i,Ya(za(s,"utf8")),s)}function gv(e){let t=ec(),n={};if(Qa(t)){let o=Ya(za(t,"utf8"));if(Mr(o))n=o}let r={...n};if(e.theme!==void 0)r.theme=e.theme;if(e.mouse!==void 0)r.mouse=e.mouse;if(e.leader_timeout!==void 0)r.leader_timeout=e.leader_timeout;if(e.font_size!==void 0)r.font_size=e.font_size;if(e.log_timestamps!==void 0)r.log_timestamps=e.log_timestamps;if(e.log_metadata!==void 0)r.log_metadata=e.log_metadata;if(e.mcp_enabled!==void 0)r.mcp_enabled=e.mcp_enabled;if(e.mcp_port===null)delete r.mcp_port;else if(e.mcp_port!==void 0)r.mcp_port=e.mcp_port;if(e.mcp_disabled_tools!==void 0)r.mcp_disabled_tools=e.mcp_disabled_tools;return Ut(t,`${JSON.stringify(r,null,2)}
|
|
611
|
-
`),t}function hE(e){let t=Vi(e);if(t)return t;let n=[e||process.cwd(),Xa(e||process.cwd(),".devctl"),Nt()],r=["tui.json","tui.jsonc"];for(let o of n)for(let i of r){let s=Xa(o,i);if(Qa(s))return s}return}function mu(e,t,n){let r=Mr(t)?t:{},o={...e.keybinds};if(Mr(r.keybinds)){for(let[c,l]of Object.entries(r.keybinds))if(typeof l==="string")o[c]=l}let i={...e.cursor};if(Mr(r.cursor)){if(yE(r.cursor.style))i.style=r.cursor.style;if(typeof r.cursor.blinking==="boolean")i.blinking=r.cursor.blinking}let s={...e.scroll_acceleration};if(Mr(r.scroll_acceleration)&&typeof r.scroll_acceleration.enabled==="boolean")s.enabled=r.scroll_acceleration.enabled;let a={...e.attention,sounds:{...e.attention.sounds}};if(Mr(r.attention)){if(typeof r.attention.enabled==="boolean")a.enabled=r.attention.enabled;if(typeof r.attention.notifications==="boolean")a.notifications=r.attention.notifications;if(typeof r.attention.sound==="boolean")a.sound=r.attention.sound;if(typeof r.attention.volume==="number")a.volume=r.attention.volume;if(typeof r.attention.sound_pack==="string")a.sound_pack=r.attention.sound_pack;if(Mr(r.attention.sounds)){for(let[c,l]of Object.entries(r.attention.sounds))if(typeof l==="string")a.sounds[c]=vE(l,n)}}return{theme:typeof r.theme==="string"?r.theme:e.theme,leader_timeout:typeof r.leader_timeout==="number"?r.leader_timeout:e.leader_timeout,font_size:typeof r.font_size==="number"&&Number.isFinite(r.font_size)?Math.round(r.font_size):e.font_size,keybinds:o,scroll_speed:typeof r.scroll_speed==="number"?r.scroll_speed:e.scroll_speed,scroll_acceleration:s,diff_style:r.diff_style==="stacked"?"stacked":"auto",cursor:i,mouse:typeof r.mouse==="boolean"?r.mouse:e.mouse,attention:a,log_timestamps:typeof r.log_timestamps==="boolean"?r.log_timestamps:e.log_timestamps,log_metadata:typeof r.log_metadata==="boolean"?r.log_metadata:e.log_metadata,mcp_enabled:typeof r.mcp_enabled==="boolean"?r.mcp_enabled:e.mcp_enabled,mcp_port:typeof r.mcp_port==="number"&&Number.isInteger(r.mcp_port)?r.mcp_port:e.mcp_port,mcp_disabled_tools:Array.isArray(r.mcp_disabled_tools)?r.mcp_disabled_tools.filter((c)=>typeof c==="string"):e.mcp_disabled_tools,path:n}}function vE(e,t){if(e.startsWith("file://")||fv(e))return e;return Xa(aE(t),e)}function yE(e){return e==="block"||e==="underline"||e==="line"||e==="default"}function Mr(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Ya(e){let t=e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/^\s*\/\/.*$/gm,"");return JSON.parse(t)}function xE(e){if(e===""||e==="none")return[];return e.split(",").flatMap((t)=>{let n=t.trim();if(n===""||n==="none"||/\s/.test(n))return[];let r=n.toLowerCase().split("+"),o=r[r.length-1]??"";return[{name:o==="return"?"return":o,ctrl:r.includes("ctrl")||r.includes("control"),shift:r.includes("shift"),meta:r.includes("meta")||r.includes("cmd")||r.includes("super"),alt:r.includes("alt")||r.includes("option")}]})}function wn(e,t){return xE(t).some((r)=>(e.name??"").toLowerCase()===r.name&&Boolean(e.ctrl)===r.ctrl&&Boolean(e.shift)===r.shift&&Boolean(e.meta||e.super)===r.meta&&Boolean(e.option??e.alt)===r.alt)}var Za=2000,$r=14,lE=3,dE=0.4,uE="DEVCTL_TUI_CONFIG",pE="OPENCODE_TUI_CONFIG",fE;var Zt=D(()=>{ze();fE={leader:"ctrl+x",command_list:"ctrl+p",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:"ctrl+c",copy:bn()}});function Oo(e){return`http://127.0.0.1:${e}/mcp`}function xu(e){if(e==="")return{};return{Authorization:`Bearer ${e}`}}function bu(e,t){return JSON.stringify({mcpServers:{devctl:{type:"http",url:e,headers:xu(t)}}},null,2)}function wu(e,t){return JSON.stringify({mcpServers:{devctl:{url:e,headers:xu(t)}}},null,2)}function Su(e,t){return JSON.stringify({mcp:{devctl:{type:"remote",url:e,headers:xu(t),enabled:!0}}},null,2)}function ku(e,t){let n=t===""?"":`
|
|
612
|
-
http_headers = { Authorization = "Bearer ${t}" }`;return`[mcp_servers.devctl]
|
|
613
|
-
url = "${e}"${n}
|
|
614
|
-
`}function jE(e){return`codex mcp add --url ${e}`}function Ji(e,t){return[{kind:"claude",title:"Claude",path:".mcp.json",language:"json",text:bu(e,t),hint:"claude mcp add-json"},{kind:"cursor",title:"Cursor",path:".cursor/mcp.json",language:"json",text:wu(e,t)},{kind:"kilo",title:"Kilo Code",path:"kilo.jsonc",language:"json",text:Su(e,t)},{kind:"codex",title:"Codex",path:"~/.codex/config.toml",language:"toml",text:ku(e,t),hint:jE(e)}]}function xv(e,t){let n=[`URL ${e}`,""];for(let r of Ji(e,t))n.push(`# ${r.title} ${r.path}${r.hint?` (${r.hint})`:""}`),n.push(r.text.trimEnd()),n.push("");return n.join(`
|
|
615
|
-
`)}function Mo(){return[{name:"start",aliases:["up"],desc:"Start selected services or the current profile",leader:"n",group:"services"},{name:"stop",aliases:["down"],desc:"Stop selected services",leader:"x",group:"services"},{name:"restart",aliases:[],desc:"Restart selected services",leader:"R",group:"services"},{name:"run",aliases:["task"],desc:"Run a one-off task: /run <task>",leader:"",group:"services"},{name:"exec",aliases:[],desc:"Run a command in a service context: /exec <service> -- <command\u2026>",leader:"",group:"services"},{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; /auth login, logout, or refresh",leader:"a",group:"nav"},{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:"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:"Check GitHub Releases for a newer version",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"},{name:"until",aliases:[],desc:"Filter logs before an ISO timestamp",leader:"",group:"logs"},{name:"history",aliases:[],desc:"Load a persisted log session",leader:"",group:"logs"},{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:"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: selected, all lines, or clip",leader:"",group:"logs"},{name:"copy",aliases:[],desc:"Copy visible logs to the clipboard",leader:"",group:"logs"},{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:"exit",aliases:["quit","q"],desc:"Exit",leader:"q",group:"app"}]}function bv(e){let t=e.trim().toLowerCase().replace(/^\//,"");return Mo().filter((n)=>t===""||BE(n,t))}function BE(e,t){if(e.name.startsWith(t)||e.name.includes(t)||e.desc.toLowerCase().includes(t))return!0;return e.aliases.some((n)=>n.startsWith(t)||n===t)}function zi(e){let t=e.trim().toLowerCase().replace(/^\//,"").split(" ")[0]??"";return Mo().find((n)=>n.name===t||n.aliases.includes(t))}function wv(e){return e.trim().replace(/^\//,"").split(/\s+/).slice(1).filter((n)=>n!=="")}function Sv(e){return Mo().find((n)=>n.leader===e)?.name??""}function kv(e){let t=e.includes("--print-env"),n=e.includes("--reveal"),r=e.filter((o)=>o!=="--print-env"&&o!=="--reveal"&&o!=="--");return{service:r[0]??"",printEnv:t,reveal:n,command:r.slice(1)}}function _u(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)`}async function Yi(e=fetch){try{let t=await e(WE,{headers:{Accept:"application/vnd.github+json"}});if(!t.ok)return{current:pt,latest:"",newer:!1,hint:Cu};let r=((await t.json()).tag_name??"").replace(/^v/,"");return{current:pt,latest:r,newer:r!==""&&GE(r,pt)>0,hint:Cu}}catch{return{current:pt,latest:"",newer:!1,hint:Cu}}}function GE(e,t){let n=Cv(e),r=Cv(t);for(let o=0;o<3;o+=1){let i=(n[o]??0)-(r[o]??0);if(i!==0)return i>0?1:-1}return 0}function Cv(e){return e.replace(/^v/,"").split(".").slice(0,3).map((t)=>{let n=Number.parseInt(t.replace(/[^0-9].*$/,""),10);return Number.isFinite(n)?n:0})}var WE="https://api.github.com/repos/amr-m-abdelgawad/devctl/releases/latest",Cu="npm install --global @amr-m-abdelgawad/devctl@latest # alternatives: Homebrew or the unsigned GitHub Release binaries \u2014 see docs/installation.md";var Eu=()=>{};function Ov(e,t=!0){let n=e<uc?_v+1:_v,r=t?oR:0;return n+r+tR+r+nR+r+rR+r}function Vn(e){return e.length+iR}function Mv(e,t){if(t<aR)return ce(e,3);if(t<sR)return ce(e,4);return e}function $v(e,t,n){let r=e.length;if(r===0||n<=0)return{start:0,end:-1};let o=t>=0&&t<r?t:0,i=Ru(e,o,n);if(i.start===0&&i.end===r-1)return i;let s=o>0?rc:0,a=o<r-1?rc:0,c=s+a,l=Ru(e,o,Math.max(e[o]??0,n-c)),d=(s>0&&l.start===0?rc:0)+(a>0&&l.end===r-1?rc:0);if(d===0)return l;return Ru(e,o,Math.max(e[o]??0,n-c+d))}function Ru(e,t,n){let r=e.length,o=t,i=t,s=e[t]??0;if(s>=n)return{start:t,end:t};while(o>0||i<r-1){let a=o>0?e[o-1]??0:Number.POSITIVE_INFINITY,c=i<r-1?e[i+1]??0:Number.POSITIVE_INFINITY,l=o>0&&s+a<=n,d=i<r-1&&s+c<=n;if(!l&&!d)break;let f=t-(o-1),g=i+1-t;if(l&&(!d||f<=g))o-=1,s+=a;else if(d)i+=1,s+=c;else break}return{start:o,end:i}}function Iv(e){if(e==="detail")return Jn.findIndex((t)=>t.id==="services");return Jn.findIndex((t)=>t.id===e)}function ce(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 $u(e){return e>=qE}function Iu(e){return e>=VE}function Fu(e){return e>=JE}function fc(e,t=0){return Math.max(1,e-Dv-t*2)}function Fv(e){let t=Av+en+vt;if($u(e))t+=Sn;if(Iu(e))t+=ac;if(Fu(e))t+=zn;return Math.max(Mu,e-t)}function hc(e){return e===ji?"\u2014":e}function Bv(e,t,n){let r=n?Rv:cR+Rv+Math.max(0,t)*2;return Math.max(1,e-r)}function pR(e){if(e.startsWith('"')||e.startsWith("'"))return"string";if(/^\d+$/.test(e))return"number";return"keyword"}function Io(e){return e.replace(fR,"")}function Wv(e){try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e}}function vc(e,t){let n=Math.max(1,t),r=Io(e).replace(/\r\n/g,`
|
|
595
|
+
`}});import{existsSync as rA,readFileSync as nA}from"fs";function En(e,t){return!(t??[]).includes(e)}function Rv(e){return xc.filter((t)=>En(t.name,e))}function bc(e){return xc.some((t)=>t.name===e)}function is(e){return new mr(e.secrets.extra_markers,e.secrets.extra_patterns)}function Pv(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 iA(e,t){let r=e.config(),n=r.services[t];if(!n)throw Error(`unknown service ${t}`);let i=e.status().services[t],s=is(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 _v(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},logs:e.logs,mcp:e.mcp?{running:e.mcp.running,address:e.mcp.address,port:e.mcp.port}:{running:!1}}}async function Ev(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=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:"",cursor:o,direction:o?"forward":void 0,limit:oA}),s=is(e.config());return{events:i.events.map((a)=>({timestamp:a.timestamp,service:a.service,source:a.source,level:a.level,message:s.redactText(a.message),pid:a.pid})),truncated:i.hasPrev,has_more:i.hasNext,next_since:i.events[i.events.length-1]?.timestamp??n,next_cursor:i.nextCursor,session_changed:i.sessionChanged}}function sA(e){return Object.entries(e.profiles).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>({name:t,services:r.services}))}function Tv(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,proxy:{enabled:e.proxy.enabled,listen:{host:e.proxy.listen.host,port:e.proxy.listen.port},routes:e.proxy.routes.map((r)=>({name:r.name,match:r.match,upstream:r.upstream.url,auth:r.auth.type}))}}}function aA(e){let t=is(e);return{entries:Cn(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 vc(e){if(!Array.isArray(e))return[];return e.filter((t)=>typeof t==="string")}async function Av(e,t,r){switch(t){case"list_services":return Pv(e.status());case"get_service":if(typeof r.name!=="string"||r.name==="")throw Error("name is required");return iA(e,r.name);case"get_status":return _v(e.status());case"get_logs":return Ev(e,r);case"list_profiles":return sA(e.config());case"get_config":return Tv(e.config());case"get_config_sources":return aA(e.config());case"run_doctor":return e.doctor();case"start_services":return e.start({services:vc(r.services),profile:typeof r.profile==="string"&&r.profile!==""?r.profile:void 0});case"stop_services":return await e.stop(vc(r.services)),{ok:!0};case"restart_services":return await e.restart(vc(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=is(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,vc(r.command),r.print_env===!0),o=is(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 cA(r);case"validate_config":return lA(e,r);default:throw Error(`unknown tool ${t}`)}}function cA(e){let t=typeof e.section==="string"?e.section:"procedure",r=t in yc?t:"procedure";return{section:r,text:yc[r],sections:Object.keys(yc)}}function lA(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(!rA(r.configPath))return{valid:!1,issues:[`no configuration at ${r.configPath}`],source:"disk",config_path:r.configPath,setup_mode:!0};let n=e.validateConfigText(nA(r.configPath,"utf8"));return{valid:n.length===0,issues:n,source:"disk",config_path:r.configPath}}function Lv(e){return Xu.includes(e)}async function Dv(e,t){switch(t){case"devctl://status":return _v(e.status());case"devctl://services":return Pv(e.status());case"devctl://logs":return Ev(e,{});case"devctl://config":return Tv(e.config());case"devctl://doctor":return e.doctor();default:throw Error(`unknown resource ${t}`)}}var oA=200,Xu,Qu,xc;var ss=D(()=>{ti();Cv();Xu=["devctl://status","devctl://services","devctl://logs","devctl://config","devctl://doctor"],Qu=["inspect","logs","diagnostics","control","setup"],xc=[{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 lines, 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"}},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. No secret env values.",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:"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}}]});function Hv(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)=>Xa(t,r),resolveStartRequest:(t,r)=>e.resolveStart.execute(t,{...r,profile:r.profile?ur(r.profile):void 0,activeProfile:r.activeProfile===void 0?void 0:ur(r.activeProfile)})}}var Bv=D(()=>{Tt()});function Sc(e){let t=e.toLowerCase().trim(),r=SA[t];if(r)return r;return St.includes(t)?t:"devctl"}function kA(){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 Wv(e){let t=Sc(e);if(t==="system"){if(kA())return{...ep["solarized-light"],name:"system"};return ep.system}return ep[t]}function gr(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 uo(e,t){return us(e)>=ds?kc:t}function us(e){let t=e.startsWith("#")?e.slice(1):e,r=Number.parseInt(t,DA);if(Number.isNaN(r))return 0;let n=r>>MA&tp,o=r>>OA&tp,i=r&tp;return(n*EA+o*TA+i*AA)/LA}function IA(e){let t=PA;for(let r=0;r<e.length;r+=1)t^=e.charCodeAt(r),t=Math.imul(t,_A);return t>>>0}function Cc(e){return us(e.background)>=ds}function np(e){if(!e||!/^#[0-9a-f]{6}$/i.test(e))return!1;return us(e)<ds}function Rc(e,t){let r=$A[e];return Cc(t)?r.light:r.dark}function jv(e,t){return us(Rc(e,t))>=ds?FA:NA}function Ze(e,t){if(e===""||e==="all")return t.muted;let r=us(t.background)>=ds?RA:CA;return r[IA(e)%r.length]??t.info}function HA(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 Gv(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 HA(e,t)}function et(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 St,rp,ep,SA,CA,RA,PA=2166136261,_A=16777619,EA=299,TA=587,AA=114,LA=1000,ds=160,DA=16,tp=255,MA=16,OA=8,kc="#1A1A1A",$A,FA="#1A1A1A",NA="#F5F5F5";var tt=D(()=>{St=["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"],rp={devctl:"amber + cyan, product theme",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)"},ep={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:"#FFB020",accent:"#3DE0FF",error:"#FF5C7A",warning:"#FFD166",search:"#FFD166",success:"#3DFF9A",info:"#3DE0FF",text:"#F7FAFD",muted:"#B7C3D0",background:"#070B10",panel:"#121A22",element:"#1C2833",highlight:"#243444",inverse:"#0A1016",border:"#334556",borderActive:"#FFB020"},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"}},SA={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"};CA=["#7AA2F7","#9ECE6A","#E0AF68","#BB9AF7","#2AC3DE","#FF9E64","#F7768E","#73DACA","#C0CAF5","#FF79C6","#7DCFFF","#C3E88D"],RA=["#2E5AAC","#3D7A1F","#9A6B12","#6B3FA0","#0E7A86","#B85C1A","#B4234A","#1A7A6D","#4A5080","#9A3480","#1565C0","#4A7C19"];$A={claude:{dark:"#E08A6A",light:"#B54328"},cursor:{dark:"#B8D4FF",light:"#1E4EBF"},kilo:{dark:"#F0C94A",light:"#8A6400"},codex:{dark:"#4ADE80",light:"#0B7A4B"}}});var Pr=D(()=>{Js()});function qv(e){return e!==void 0}function Uv(e){let t=e/1000;if(Number.isInteger(t))return`${t}s`;return`${e}ms`}function sp(e,t,r){let n=e.indexOf(t),i=((n<0?0:n)+r+e.length)%e.length;return e[i]??e[0]}function Vv(e,t){let r=[...St],n=r.includes(e)?e:ip;return sp(r,n,t)}function Jv(e,t){let r=[...BA],n=r.reduce((o,i)=>Math.abs(i-e)<Math.abs(o-e)?i:o,r[0]);return sp(r,n,t)}function ps(e){let t=[...op];return t.reduce((r,n)=>Math.abs(n-e)<Math.abs(r-e)?n:r,t[0])}function fs(e,t){return sp([...op],ps(e),t)}function ms(e){let t=ps(e),r=Kv[t]??Kv[Eo];return{px:t,...r}}function po(e){return e.label==="compact"}function gs(e){return e.steps<=2}function zv(e){return op.map((r,n)=>n<e?"\u2588":"\u2591").join(" ")}function Pc(e){return ms(e).label}function Yv(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:Pc(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:Uv(e.leaderMs),hint:"\u2190 \u2192 save",detail:`How long ${Mt("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:Bt,hint:"read-only",detail:er()},{id:"reset",group:"About",kind:"action",name:"Reset",value:"defaults",hint:"enter confirm reset",detail:`Restore theme ${ip}, display ${Pc(Eo)}, mouse on, leader ${Uv(Zl)}. Enter asks first. ${t}`}]}function _c(){return{theme:ip,mouse:!0,leader_timeout:Zl,font_size:Eo}}function Xv(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 ap(e,t){if(e.length===0)return 0;return Math.min(Math.max(t,0),e.length-1)}function Tn(e,t){return e[ap(e,t)]}function cp(e,t){return e??t}var BA,op,ip="devctl",Kv;var _r=D(()=>{tt();Pr();BA=[1000,2000,3000],op=[12,14,16,18,20,22];Kv={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 WA,useContext as jA}from"react";function ve(){return jA(lp)}var lp;var Ot=D(()=>{_r();Pr();lp=WA(ms(Eo))});function _e(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 oe(e,t){if(t<=0)return"";if(e.length>=t)return _e(e,t);return e.padEnd(t)}function ni(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 hs(e){if(!Number.isFinite(e)||e<dp)return"< 1s";let t=Math.floor(e/Qv),r=Math.floor(e%Qv/pp),n=Math.floor(e%pp/up),o=Math.floor(e%up/dp);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 ys(e){if(!Number.isFinite(e)||e<0)return"\u2014";let t=e/GA;if(t>=Zv)return`${(t/Zv).toFixed(1)}G`;if(t>=1)return`${Math.round(t)}M`;return`${Math.round(e)}K`}function ex(e){if(!Number.isFinite(e)||e<0)return"\u2014";return`${e.toFixed(1)}%`}var dp=1000,up,pp,Qv,GA=1024,Zv=1024;var It=D(()=>{up=60*dp,pp=60*up,Qv=24*pp});function mp(e){return e>=qA}function gp(e){return e>=VA}function hp(e){return e>=JA}function Lc(e,t=0){return Math.max(1,e-rx-t*2)}function nx(e){let t=tx+Er+$t;if(mp(e))t+=Hr;if(gp(e))t+=Tc;if(hp(e))t+=nn;return Math.max(Ac,e-t)}function Dc(e,t,r){if(r)return e;let n=t.reduce((a,c)=>Math.max(a,c.length),0),o=Math.min(fp,Math.max(Ac,n+UA)),i=tx+Er+$t+o+rx+KA,s=Math.max(Ec,Math.floor(e*zA));return Math.min(s,Math.max(Ec,i))}function ox(e){if(!e)return"";return Object.keys(e.profiles).sort()[0]??""}function Mc(e){if(!e)return!0;let t=Object.values(e.services);if(t.length===0)return!0;return!t.some((r)=>mo(r))}function yp(e,t){if(e.length>0)return e;return[...t]}function Oc(e,t){if(e.length>0)return[...e];return t===""?[]:[t]}function Ic(e){return e.command.args.join(" ")||"\u2014"}function ws(e,t){let r=fo(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 $c(e){let t=e.health.type||"none",r=e.health.url||e.health.address;return r===""?t:`${t} ${r}`}function Fc(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 Nc(e){let t=e.restart.policy||"none";if(e.restart.max_retries>0)return`${t} \xD7${e.restart.max_retries}`;return t}function ix(e,t,r,n,o){let i={...e.environment.defaults,...e.environment.vars},a=YA(o??i,t,r,n);return[...new Set([...Object.keys(a),...e.environment.required])].map((l)=>({key:l,value:a[l]??"",required:e.environment.required.includes(l),fromConfig:Object.prototype.hasOwnProperty.call(i,l)})).sort((l,d)=>l.fromConfig===d.fromConfig?l.key.localeCompare(d.key):l.fromConfig?-1:1)}function sx(e,t){if(!e||e.processes.length===0)return;if(t!==void 0&&t!==""&&e.session_id===t)return;return e}function fo(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 tr(e){if(!e)return"STOPPED";return Jo(e)}function YA(e,t,r,n){if(t)return e;return new mr(r,n).redactMap(e)}function Ss(e){return XA.has(e)}function mo(e){if(!e)return!1;return Ss(e.state)}var tx=8,Er=12,Hr=10,Tc=8,nn=8,vs=9,xs=7,bs=8,Ac=12,fp=40,$t=2,UA=2,rx=2,KA=2,Ec=34,qA=48,VA=60,JA=72,zA=0.48,XA;var At=D(()=>{Tt();ti();XA=new Set(["RUNNING","STARTING","RESTARTING","HEALTHY","UNHEALTHY"])});function jc(e){return e===aa?"\u2014":e}function vp(e,t,r){let n=r?cx:QA+cx+Math.max(0,t)*2;return Math.max(1,e-n)}function rL(e){if(e.startsWith('"')||e.startsWith("'"))return"string";if(/^\d+$/.test(e))return"number";return"keyword"}function Gc(e){return e.replace(nL,"")}function px(e){try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e}}function Uc(e,t){let r=Math.max(1,t),n=Gc(e).replace(/\r\n/g,`
|
|
616
596
|
`).replace(/\r/g,`
|
|
617
597
|
`).split(`
|
|
618
|
-
`),o=[];for(let i of r)if(i.length<=n)o.push(i);else o.push(...gR(i,n));return o.length>0?o:[""]}function Gv(e,t,n){let r=e.length>0?[...e]:[""];if(n||r.length<=1)return{visible:r,mark:"",folded:!1,hidden:0};let o=r.length-1,i=` ${lR}${o}`,s=Math.max(1,t-i.length);return{visible:[ce(r[0]??"",s)],mark:i,folded:!0,hidden:o}}function Uv(e,t){return e==="all"||e==="focus"&&t}function Nu(e){if(e==="clip")return"focus";if(e==="focus")return"all";return"clip"}function Kv(e,t,n,r=Nr){if(e.length===0)return{start:0,items:[],newer:0};if(!t){let a=Math.max(0,e.length-r);return{start:a,items:e.slice(a),newer:0}}let o=e.length-1,i=Math.max(0,Math.min(n,o)),s=e.slice(i,i+r);return{start:i,items:s,newer:Math.max(0,e.length-i-s.length)}}function Hu(e,t=Nr){return Math.max(0,e-t)}function ju(e,t,n,r){let o=Math.max(t-1,0);if(e<0&&n>0)return{selected:0,startDelta:Math.max(-n,e)};if(e>o&&r>0)return{selected:o,startDelta:Math.min(r,e-o)};return{selected:Math.min(o,Math.max(0,e)),startDelta:0}}function Qi(e){if(e==="all")return"wrap all";if(e==="focus")return"wrap selected";return"clip"}function gR(e,t){let n=[],r=e;while(r.length>t){let o=r.slice(0,t),i=mR(o);if(i>0)n.push(r.slice(0,i).trimEnd()),r=r.slice(i).trimStart();else n.push(r.slice(0,t)),r=r.slice(t)}if(r.length>0)n.push(r);return n}function mR(e){let t=e.lastIndexOf(" "),n=e.lastIndexOf("\t"),r=e.lastIndexOf(","),o=Math.max(t,n,r);if(o<Math.floor(e.length*dR))return-1;return e[o]===","?o+1:o}function qv(e){let t=Io(e),n=[],r=new RegExp(uR.source,"gi"),o=0,i=r.exec(t);while(i){let s=i[0]??"";if(i.index>o)n.push({text:t.slice(o,i.index),kind:"text"});n.push({text:s,kind:pR(s)}),o=i.index+s.length,i=r.exec(t)}if(o<t.length)n.push({text:t.slice(o),kind:"text"});if(n.length===0)return[{text:t,kind:"text"}];return n}function Vv(e){let t=e.showTimestamps?gc:0,n=e.showMeta?pc:0;return Math.max(Nv,e.width-t-e.serviceWidth-mc-n-Hv-Xi*jv)}function Zi(e){return Math.max(QE,e-ZE*2)}function Jv(e){let t=e.width<YE,n=e.proxyOn?`\u25CF ${ce(e.proxyAddress,t?10:18)}`:t?"":"\u25CB off";return[{label:t?`${e.running}/${e.total}`:Wu(e.running,e.total),tone:e.running>0?"success":"idle"},{label:n,tone:e.proxyOn?"info":"idle",hide:t&&!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 zv(e,t){let n=t.reduce((s,a)=>Math.max(s,a.length),0),r=gc+mc+Hv+Nv+Xi*jv,o=Math.max(Ev,e-r),i=Math.max(Ev,n);return Math.min(Lv,o,i)}function yc(e,t,n){if(n)return e;let r=t.reduce((a,c)=>Math.max(a,c.length),0),o=Math.min(Lv,Math.max(Mu,r+UE)),i=Av+en+vt+o+Dv+KE,s=Math.max(ic,Math.floor(e*zE));return Math.min(s,Math.max(ic,i))}function ee(e,t){if(t<=0)return"";if(e.length>=t)return ce(e,t);return e.padEnd(t)}function Fo(e,t){let n=[],r=0;for(let o of e){let i=o.key.length+o.label.length+3;if(r+i>t)break;n.push(o),r+=i}return n}function Yv(e){return e<eR}function No(e,t,n,r,o="center",i=!0){let s=Math.min(n,Math.max(1,e-4)),a=Math.min(Ov(e,i),Math.max(0,t-1)),c=Math.min(r,Math.max(1,t-a)),l=Math.max(0,Math.min(Math.floor((e-s)/2),Math.max(0,e-s))),d=o==="bottom"?t-2-c:Math.floor((t-c)/2),f=Math.max(0,Math.min(d,t-c));return{left:l,top:f,width:s,height:c}}function Xv(e){if(e==="")return"idle";if(vR.test(e))return"error";if(e.includes("session only"))return"warning";if(hR.test(e))return"success";return"info"}function Qv(e,t,n){let r=n!==""&&e.profiles[n]?n:"";if(t.length>0)return{services:t,profile:r};if(r!=="")return{services:[...e.profiles[n]?.services??[]],profile:r};return{services:Object.keys(e.services),profile:""}}function Zv(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 XE;return 0}function ey(e){if(e==="0")return Jn[9]?.id;if(e.length===1&&e>="1"&&e<="9")return Jn[Number(e)-1]?.id;return}function xc(e){if(!e)return"";return Object.keys(e.profiles).sort()[0]??""}function bc(e){return yR.has(e)}function es(e){if(!e)return!1;return bc(e.state)}function wc(e,t){let n=t??Object.keys(e?.services??{});return{running:n.filter((o)=>es(e?.services[o])).length,total:n.length}}function ty(e,t){let n=0,r=0,o=0,i=0,s=0,a=0;for(let c of e){let l=t?.services[c];if(l?.health==="HEALTHY")o+=1;let d=l?.state??"STOPPED";if(d==="FAILED")i+=1;else if(d==="STOPPING")s+=1;else if(d==="STARTING"||d==="RESTARTING")r+=1;else if(bc(d))n+=1;else a+=1}return{total:e.length,live:n+r,running:n,starting:r,healthy:o,failed:i,stopping:s,stopped:a}}function ny(e,t){if(!Number.isFinite(e)||!Number.isFinite(t)||t<=0)return 0;return e/t}function CR(e,t,n){if(!Number.isFinite(e))return"success";if(e>n)return"error";if(e>t)return"warning";return"success"}function _R(e,t){return CR(ny(e,t),xR,bR)}function ER(e,t){let n=t>0?e/t:1;if(n<SR)return"error";if(n<wR)return"warning";return"success"}function Pu(e){if(!Number.isFinite(e)||e<0)return"\u2014";return e.toFixed(2)}function RR(e){if(!Number.isFinite(e)||e<0)return"\u2014";return`${Math.round(e*100)}%`}function ry(e,t=Date.now()){if(!e?.startTime)return"\u2014";let n=new Date(e.startTime).getTime();if(!Number.isFinite(n))return"\u2014";return jo(t-n)}function oy(e,t=kR){return Object.entries(e).sort((n,r)=>r[1]-n[1]||n[0].localeCompare(r[0])).slice(0,t)}function iy(e,t=1){return Math.max(24,e-MR-t*2-$R-IR-FR)}function sy(e){let t=e>=PR,n=e>=TR,r=e>=AR,o=e>=LR,i=e>=DR,s=e>=OR,a=en+vt;if(t)a+=Sn+vt;if(n)a+=lc+vt;if(r)a+=dc+vt;if(o)a+=cc+vt;if(i)a+=Sc+vt;if(s)a+=zn;return{name:Math.max(Mu,e-a),health:t,cpu:n,mem:r,up:o,rst:i,pid:s}}function ay(e){let t=Number.isFinite(e)&&e>0?e:0;return{ratio:Math.min(1,t),label:RR(t)}}function cy(e,t=jR){return`[${ts(e.ratio,t)}] ${e.label.padStart(4)}`}function Bu(e,t){let n=e.reduce((l,d)=>Math.max(l,d.what.length),4),r=e.reduce((l,d)=>Math.max(l,d.reading.length),7),o=e.some((l)=>l.meter)?BR:0,i=Ho*(o>0?3:2),s=Math.min(NR,Math.max(Tu,n)),a=Math.min(HR,Math.max(Au,r)),c=t-s-a-o-i;if(c<oc&&a>Au)a=Math.max(Au,a-(oc-c)),c=t-s-a-o-i;if(c<oc&&s>Tu)s=Math.max(Tu,s-(oc-c)),c=t-s-a-o-i;return{what:s,reading:a,meaning:Math.max(0,c),meter:o}}function ly(e){return WR.has((e?.health.type??"").toLowerCase())}function dy(e){if(e==="darwin")return"macOS";if(e==="win32")return"Windows";if(e==="linux")return"Linux";return e||"this computer"}function uy(e,t){let n=Math.max(1,t),r=_R(e,n),o=r==="error"?"overloaded":r==="warning"?"busy":"not busy",i=r==="error"?`${n} cores are queued up \u2014 last minute ${Pu(e)}`:r==="warning"?`${n} cores nearly full \u2014 last minute ${Pu(e)}`:`${n} cores. Last minute ${Pu(e)} (under ${n} is fine)`;return{what:"CPU work",reading:o,meaning:i,tone:r,meter:ay(ny(e,n))}}function py(e,t){let n=ER(e,t),r=`${sc(e)} of ${sc(t)}`,o=n==="error"?"Almost no RAM left for new work":n==="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:r,meaning:o,tone:n,meter:ay(i)}}function fy(e){let t=e?.state??"STOPPED";if(t==="FAILED")return"crashed";if(t==="STOPPING")return"stopping";if(t==="STARTING"||t==="RESTARTING")return"starting";if(bc(t))return"up";return"off"}function gy(e){if(!e||!bc(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 my(e){if(e==="keychain")return"password store";if(e==="file")return"local file";return e||"unknown store"}function hy(e,t){let n=[{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)n.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)n.push({what:"Still starting",reading:String(e.starting),meaning:"not ready for traffic yet",tone:"warning"});if(e.stopping>0)n.push({what:"Stopping",reading:String(e.stopping),meaning:"shutting down",tone:"warning"});return n.push({what:"Crashed",reading:String(e.failed),meaning:e.failed>0?"open the service for the error":"none",tone:e.failed>0?"error":"muted"}),n.push({what:"Not started",reading:String(e.stopped),meaning:e.stopped>0?"off until you start them":"all are up",tone:"muted"}),n}function ts(e,t=20){let n=Number.isFinite(e)?Math.min(1,Math.max(0,e)):0,r=Math.round(n*t);return"\u2588".repeat(r)+"\u2591".repeat(Math.max(0,t-r))}function jo(e){if(!Number.isFinite(e)||e<Lu)return"< 1s";let t=Math.floor(e/Pv),n=Math.floor(e%Pv/Ou),r=Math.floor(e%Ou/Du),o=Math.floor(e%Du/Lu);if(t>0)return`${t}d ${n}h`;if(n>0)return`${n}h ${r}m`;if(r>0)return`${r}m ${String(o).padStart(2,"0")}s`;return`${o}s`}function sc(e){if(!Number.isFinite(e)||e<0)return"\u2014";let t=e/GR;if(t>=Tv)return`${(t/Tv).toFixed(1)}G`;if(t>=1)return`${Math.round(t)}M`;return`${Math.round(e)}K`}function vy(e){if(!Number.isFinite(e)||e<0)return"\u2014";return`${e.toFixed(1)}%`}function Bo(e){if(!e)return!0;let t=Object.values(e.services);if(t.length===0)return!0;return!t.some((n)=>es(n))}function yy(e,t){if(e.length>0)return e;return[...t]}function kc(e,t){if(e.length>0)return[...e];return t===""?[]:[t]}function ns(e){return UR.has(e)}function by(e,t,n,r){let o=n===""?t:t.filter((a)=>a.timestamp>=n);if(o.length===0)return e;let i=Math.max(1,r);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 wy(e,t){let n=t.length>0?t[t.length-1].seq:-1,r=e.filter((o)=>o.seq>n);return[...t,...r]}function Sy(e,t){if(t.length===0)return e;let n=new Set(e.map((o)=>o.seq)),r=t.filter((o)=>!n.has(o.seq));return r.length===0?e:[...r,...e]}function ky(e,t,n){return e&&t<=0&&n}function Cy(e){return e.filter((t)=>t.level==="ERROR"||t.level==="FATAL").length}function KR(e){return`${e.timestamp} ${e.service} ${e.level} ${Io(e.message)}`}function _y(e){return[Io(e.message),`time ${e.timestamp}`,`service ${e.service}`,`source ${e.source}${e.stream?` / ${e.stream}`:""}`,`level ${e.level}`,`pid ${e.pid||"\u2014"}`,`request ${e.request_id||"\u2014"}`,`identity ${e.identity||"\u2014"}`].join(`
|
|
619
|
-
|
|
620
|
-
`)}function Wo(e,t){let n=t.services?.filter((l)=>l!=="")??[],r=t.service??"",o=(t.search??"").trim(),i=t.source??"",s=t.since??"",a=t.until??"",c;if(o!=="")if(t.regex===!0){let l=Da(o);if(l)c=(d)=>l.test(d);else c=(d)=>d.toLowerCase().includes(o.toLowerCase())}else{let l=o.toLowerCase();c=(d)=>d.toLowerCase().includes(l)}return e.filter((l)=>{if(n.length>0&&!n.includes(l.service))return!1;if(r!==""&&l.service!==r)return!1;if(i!==""&&l.source!==i)return!1;if(t.systemLogs===!1&&ns(l.source))return!1;if(s!==""&&l.timestamp<s)return!1;if(a!==""&&l.timestamp>a)return!1;if(t.errorOnly===!0&&l.level!=="ERROR"&&l.level!=="FATAL")return!1;if(!c)return!0;return c(l.message)||c(l.service)})}function qR(e,t){let n={};for(let i of e)n[i.service]=(n[i.service]??0)+1;let r=t.map((i)=>({name:i,count:n[i]??0})),o=Object.keys(n).filter((i)=>!t.includes(i)).sort().map((i)=>({name:i,count:n[i]??0}));return[...r,...o]}function Ry(e,t,n=[]){let r=rs(e,t,n);return[{name:"",count:t.length},...qR(t,r)]}function VR(e,t){let n=e.map((o)=>({name:o,count:t[o]??0})),r=Object.keys(t).filter((o)=>!e.includes(o)).sort().map((o)=>({name:o,count:t[o]??0}));return[...n,...r]}function Py(e,t,n=[]){let r=Object.keys(t.byService).map((i)=>({service:i})),o=rs(e,r,n);return[{name:"",count:t.total},...VR(o,t.byService)]}function Wu(e,t){if(e<=0)return"none started";return`${e}/${t} running`}function rs(e,t,n=[]){let r=[...e],o=(i)=>{if(i!==""&&!r.includes(i))r.push(i)};for(let i of n)o(i);for(let i of t)o(i.service);return r}function Ty(e,t,n){let r=["",...rs(e,t)];if(n<1||n>r.length)return;return r[n-1]}function Gu(e,t,n){let r=["",...e],o=r.indexOf(t),s=((o<0?0:o)+n+r.length)%r.length;return r[s]??""}function os(e){return e.waves.flat().join(" \u2192 ")}function Ay(e){let t=os(e);if(t==="")return"Started selected services";return`Started ${t}`}function Ly(e){let t=os(e);if(t==="")return"Stopped running services";return`Stopped ${t}`}function Dy(e,t,n,r="start"){let o=n?.services[e],i=Bt(o);if(o?.last_error&&r!=="stop")return o.last_error;if(r==="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((c)=>c.name===e)?.dependencies??[]).filter((c)=>{let l=Bt(n?.services[wt(c)]);return Fn(c)==="service_healthy"?l!=="HEALTHY":l==="STOPPED"||l==="FAILED"}).map(wt);if(a.length>0)return`waits for ${a.join(", ")}`;return"queued"}function is(e,t,n="start"){if(e.length===0)return"completed";let r=e.map((i)=>t?.services[i]);if(r.some((i)=>i?.state==="FAILED"))return"failed";if(n==="stop"){if(r.every((i)=>!i||i.state==="STOPPED"||i.state==="UNKNOWN"))return"completed";if(r.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(r.every(o))return"completed";if(r.some((i)=>i?.state==="UNHEALTHY"||i?.health==="UNHEALTHY"))return"unhealthy";if(r.some((i)=>i?.state==="STARTING"||i?.state==="RUNNING"||i?.state==="RESTARTING"))return"active";return"queued"}function Oy(e,t,n="start"){let o=e.waves.flat().length,i=0,s=0,a=0,c=0;for(let x=0;x<e.waves.length;x++){let v=e.waves[x]??[],w=is(v,t,n);if(w==="active"||w==="unhealthy"||w==="failed")c=x;else if(w==="completed"&&c===x&&x<e.waves.length-1)c=x+1;for(let E of v){let k=t?.services[E];if(n==="stop"?!k||k.state==="STOPPED"||k.state==="UNKNOWN":Boolean(k&&(k.state==="HEALTHY"||k.health==="HEALTHY"||k.state==="RUNNING"&&k.health!=="UNHEALTHY")))i++;else if(k?.state==="FAILED")s++;else if(k?.state==="STARTING"||k?.state==="RUNNING"||k?.state==="UNHEALTHY"||k?.health==="UNHEALTHY"||k?.state==="STOPPING"||k?.state==="RESTARTING")a++}}let l=o>0?Math.round(i/o*100):100,d=16,f=Math.round(l/100*d),g="\u2588".repeat(f)+"\u2591".repeat(Math.max(0,d-f)),m=i===o&&o>0;return{total:o,ready:i,active:a,failed:s,percent:l,progressBar:g,currentWaveIndex:c,totalWaves:e.waves.length,isComplete:m}}function My(e,t,n){let r=n==="completed"?"\u2713 Completed":n==="failed"?"\u2717 Failed":n==="unhealthy"?"\u26A0 Unhealthy":n==="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 ${r}`}function $y(e,t,n,r){let o=r?` \xB7 Profile ${r}`:"";if(n)return`${e==="stop"?"Shutdown":"Startup"} Failed (${n})`;if(t)return`${e==="stop"?"Stopping Services":e==="restart"?"Restarting Pipeline":"Starting Pipeline"}${o}`;return`${e==="stop"?"Shutdown Complete":"Startup Complete"}${o}`}function Iy(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."}}function Fy(e){let t=Fr.indexOf(e);if(t<0)return"dashboard";return Fr[(t+1)%Fr.length]??"dashboard"}function Ny(e){let t=Fr.indexOf(e);if(t<0)return"dashboard";return Fr[(t-1+Fr.length)%Fr.length]??"dashboard"}function Hy(e){return["services","nav","logs","ui","app"].flatMap((n)=>{let r=e.filter((o)=>o.group===n);if(r.length===0)return[];return[{group:n,items:r}]})}function jy(e){let t=e.trim().toLowerCase().replace(/^\//,""),n=Mo().filter((r)=>t===""||r.name.includes(t)||r.desc.toLowerCase().includes(t)||r.aliases.some((o)=>o.startsWith(t)));return Hy(n).flatMap((r)=>r.items)}function By(e){return Hy(e).flatMap((t)=>t.items.map((n)=>({name:`/${n.name}`,description:`${t.group} \xB7 ${n.desc}`,value:n.name})))}function Wy(e,t,n=bn()){if(t==="slash")return[{key:"\u2191\u2193",label:"suggest"},{key:"tab",label:"complete"},{key:"enter",label:"run"},{key:"esc",label:"cancel"}];if(t==="palette"||t==="themes")return[{key:"\u2191\u2193",label:"move"},{key:"enter",label:t==="themes"?"save":"select"},{key:"esc",label:t==="themes"?"revert":"close"}];if(t==="help")return[{key:"j/k",label:"scroll"},{key:"esc",label:"close"}];if(t==="log-details"||t==="scroll-text")return[{key:"j/k",label:"scroll"},{key:n,label:"copy"},{key:"esc",label:"close"}];if(t==="confirm")return[{key:"enter",label:"confirm"},{key:"esc",label:"stay"}];if(t==="plan")return[{key:"esc",label:"back to dashboard"},{key:"enter",label:"done"}];if(t==="leader")return Uu();if(t==="config-edit")return[{key:"ctrl+s",label:"save"},{key:"esc",label:"discard"}];return JR(e,n)}function Uu(){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 JR(e,t){let n=[{key:"/",label:"command"},{key:"ctrl+p",label:"palette"},{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:"ctrl+l",label:"clear logs"},{key:t,label:"copy logs"},{key:"j/k",label:"move"},...n];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"},...n];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"},...n];case"logs":return[{key:"\u2190\u2192",label:"filter"},{key:"1-9",label:"source"},{key:"e",label:"errors"},{key:"i",label:"internal logs"},{key:"ctrl+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:t,label:"copy"},{key:"p",label:"pause"},{key:"z",label:"full screen"},{key:"/exports",label:"open folder"},...n];case"profiles":return[{key:"space",label:"set current"},{key:"enter",label:"set and start"},{key:"j/k",label:"move"},...n];case"proxy":return[{key:"n",label:"start proxy"},{key:"x",label:"stop proxy"},...n];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"},...n];case"config":return[{key:"v",label:"buffer"},{key:"e",label:"editor"},{key:"/diff",label:"sources"},{key:"/reload",label:"reload"},{key:"j/k",label:"scroll"},...n];case"setup":return[{key:"j/k",label:"steps"},{key:"enter",label:"continue"},{key:"esc",label:"back or exit"},...n];case"doctor":return[{key:"r",label:"run doctor again"},{key:"j/k",label:"move"},{key:"enter",label:"fix port"},...n];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"},...n];case"settings":return[{key:"j/k",label:"move"},{key:"\u2190\u2192",label:"save"},{key:"enter",label:"apply or open page"},{key:"space",label:"toggle"},...n];default:return[{key:"tab",label:"screens"},...n]}}function Gy(e,t,n){if(n<=t||e<t)return 0;return Math.min(e-t+1,n-t)}function Hr(e,t){if(e.length===0)return;let n=Math.min(Math.max(t,0),e.length-1);return e[n]}function Cc(e){return e.command.args.join(" ")||"\u2014"}function ss(e,t){let n=jr(t);if(n!=="")return n;if(e.ports.length===0)return"\u2014";return e.ports.map((r)=>`${r.name}:${r.auto?"auto":r.value}`).join(" ")}function _c(e){let t=e.health.type||"none",n=e.health.url||e.health.address;return n===""?t:`${t} ${n}`}function Ec(e,t){if(t?.identity)return t.identity;let n=e.identity.type||"none",r=e.identity.service_account;return r===""?n:`${n} ${r}`}function Rc(e){let t=e.restart.policy||"none";if(e.restart.max_retries>0)return`${t} \xD7${e.restart.max_retries}`;return t}function Uy(e,t,n,r,o){let i={...e.environment.defaults,...e.environment.vars},a=zR(o??i,t,n,r);return[...new Set([...Object.keys(a),...e.environment.required])].map((l)=>({key:l,value:a[l]??"",required:e.environment.required.includes(l),fromConfig:Object.prototype.hasOwnProperty.call(i,l)})).sort((l,d)=>l.fromConfig===d.fromConfig?l.key.localeCompare(d.key):l.fromConfig?-1:1)}function Ky(e,t){if(!e||e.processes.length===0)return;if(t!==void 0&&t!==""&&e.session_id===t)return;return e}function jr(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 Bt(e){if(!e)return"STOPPED";return Co(e)}function qy(e,t,n){if(e==="quit")return{title:"Quit",body:"Stop managed services and leave the TUI? Press d to detach and leave them running."};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 r=n?.port??0,o=n?.process||"process",i=n?.pid??0;return{title:`Free port ${r}`,body:`Stop ${o} (pid ${i}) so port ${r} 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 zR(e,t,n,r){if(t)return e;return new Vt(n,r).redactMap(e)}function Vy(e,t){if(!e)return"";return(e.profiles[t]?.services??[]).join(", ")}function Go(e,t,n){let r=e?.google?.project_id??"";if(r!=="")return{project:r,source:"configuration"};let o=t?.project||n?.projectID||"",i=t?.project_source||n?.projectSource||"";return{project:o,source:i}}function Jy(e,t,n,r){let o=Math.max(8,r-2),i=`logs ${n}`,s=Vn(i),a=e||"(no user)",c=t||"";if(o<=s+6){let g=Math.max(2,o-s-2);return[{label:ce(a,g),tone:"idle"},{label:ce(i,s-2),tone:"muted"}]}let l=o-s;if(c&&l>=36){let g=ce(c,14),m=Vn(g),x=l-m-2,v=x>=a.length+9?`identity ${a}`:a;return[{label:ce(v,x),tone:"idle"},{label:g,tone:"muted"},{label:i,tone:"muted"}]}if(c&&l>=28&&c.length<=10){let g=ce(c,10),m=Vn(g),x=l-m-2;return[{label:ce(a,x),tone:"idle"},{label:g,tone:"muted"},{label:i,tone:"muted"}]}let d=l>=a.length+9?`identity ${a}`:a;return[{label:ce(d,l-2),tone:"idle"},{label:i,tone:"muted"}]}function zy(e){let t=e.payload?.error;return typeof t==="string"&&t!==""?t:"configuration reload failed"}var $o=100,Av=8,en=12,Sn=10,ac=8,zn=8,cc=9,lc=7,dc=8,Mu=12,Lv=40,vt=2,UE=2,Dv=2,KE=2,ic=34,qE=48,VE=60,JE=72,zE=0.48,uc=90,YE=60,XE=9,pc=8,QE=8,ZE=6,eR=20,_v=1,tR=1,nR=1,rR=1,oR=1,w$,iR=2,rc=2,sR=80,aR=56,gc=9,mc=7,Ev=10,Nv=16,Hv=2,Xi=1,Nr=200,cR=2,Rv=1,lR="\u25B8",jv=2,dR=0.4,uR,fR,hR,vR,Jn,Fr,yR,xR=0.85,bR=1.5,wR=0.2,SR=0.1,kR=5,PR=52,TR=64,AR=72,LR=82,DR=90,OR=100,MR=2,$R=2,IR=2,FR=1,Sc=8,Tu=8,NR=22,Au=6,HR=28,oc=12,Ho=2,jR=10,BR=18,WR,Lu=1000,Du,Ou,Pv,GR=1024,Tv=1024,UR,xy;var Pe=D(()=>{st();Ar();Ao();Rr();Zt();w$=Ov(uc-1);uR=/("[^"]*"|'[^']*'|\b(?:ERROR|FATAL|WARN(?:ING)?|FAIL(?:ED)?)\b|\b\d{3,5}\b)/gi;fR=/\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-Z\\-_]/g;hR=/^(started|stopped|restarted|refreshed|cleared|copied|exported|jumped|proxy started|proxy stopped|secrets|re-running|theme |mouse |leader |display |restored)/i,vR=/\b(fail|error|unknown|not found|no configuration|blocked|already in use|is using port)\b/i;Jn=[{id:"dashboard",label:"dashboard"},{id:"services",label:"services"},{id:"logs",label:"logs"},{id:"auth",label:"identity"},{id:"credentials",label:"credentials"},{id:"proxy",label:"proxy"},{id:"doctor",label:"doctor"},{id:"config",label:"config"},{id:"profiles",label:"profiles"},{id:"setup",label:"setup"},{id:"stats",label:"stats"},{id:"settings",label:"settings"}];Fr=Jn.map((e)=>e.id);yR=new Set(["RUNNING","STARTING","RESTARTING","HEALTHY","UNHEALTHY"]);WR=new Set(["http","tcp","command"]);Du=60*Lu,Ou=60*Du,Pv=24*Ou;UR=new Set(["auth","devctl","proxy"]),xy=["devctl","mcp","auth"]});function Yy(e){let t=Object.keys(e.services).length,n=Object.keys(e.profiles).length,r=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:`${n} profile${n===1?"":"s"}`,tone:n>0?"info":"idle"},{text:e.proxy.enabled?"proxy on":"proxy off",tone:e.proxy.enabled?"success":"idle"}];if(r>0)i.push({text:`${r} route${r===1?"":"s"}`,tone:"info"});if(o>0)i.push({text:`${o} task${o===1?"":"s"}`,tone:"info"});return i}function Xy(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 Qy(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 Zy(e){let t=YR(e);return[{label:"exit",value:t,tone:t==="ask on quit"?"warning":"text"},{label:"grace",value:`${e.shutdown.grace_seconds}s`},{label:"refresh",value:`${Gs(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 ex(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 tx(e){return[{label:"listen",value:gr(e.proxy.listen),tone:e.proxy.enabled?"text":"muted"},{label:"token",value:ZR(e),tone:e.proxy.token_endpoint.enabled?"text":"muted"}]}function nx(e){return Object.keys(e.services).sort().map((t)=>{let n=e.services[t]??Nn();return{name:t,extends:n.extends||"\u2014",command:Cc(n),ports:ss(n),identity:Ec(n),health:_c(n),depends:n.dependencies.map(Ws).join(", ")||"\u2014",restart:Rc(n)}})}function rx(e){return e.proxy.routes.map((t)=>({name:t.name||t.match.host||"(unnamed)",match:eP(t),upstream:t.upstream.url||"\u2014",auth:t.auth.type||"none",identity:tP(t)}))}function ox(e){return Object.keys(e.profiles).sort().map((t)=>{let n=e.profiles[t],r=Object.keys(n?.environment??{}).sort();return{name:t,services:n?.services.join(", ")||"\u2014",env:r.length>0?r.join(", "):"\u2014"}})}function ix(e){return Object.keys(e.templates).sort().map((t)=>({name:t,summary:nP(e.templates[t])}))}function sx(e){return Object.keys(e.tasks).sort().map((t)=>{let n=e.tasks[t],r=n?.command.args.join(" ")||"\u2014",o=n?.dependencies.join(", ");return{name:t,summary:o?`${r} depends ${o}`:r}})}function ax(e,t){let n=vr(e);if(n.length===0)return"No provenance recorded for this configuration.";let r=new Vt(e.secrets.extra_markers,e.secrets.extra_patterns);return n.map((o)=>{let i=typeof o.value==="string"?o.value:JSON.stringify(o.value),s=t?i:r.redactMap({[o.path]:i})[o.path],a=o.shadowed.length===0?"":`
|
|
598
|
+
`),o=[];for(let i of n)if(i.length<=r)o.push(i);else o.push(...oL(i,r));return o.length>0?o:[""]}function fx(e,t,r){let n=e.length>0?[...e]:[""];if(r||n.length<=1)return{visible:n,mark:"",folded:!1,hidden:0};let o=n.length-1,i=` ${ZA}${o}`,s=Math.max(1,t-i.length);return{visible:[_e(n[0]??"",s)],mark:i,folded:!0,hidden:o}}function mx(e,t){return e==="all"||e==="focus"&&t}function Kc(e){if(e==="clip")return"focus";if(e==="focus")return"all";return"clip"}function xp(e,t,r,n=Tr){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 qc(e,t=Tr){return Math.max(0,e-t)}function bp(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 Vc(e){if(e==="all")return"wrap all";if(e==="focus")return"wrap selected";return"clip"}function oL(e,t){let r=[],n=e;while(n.length>t){let o=n.slice(0,t),i=iL(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 iL(e){let t=e.lastIndexOf(" "),r=e.lastIndexOf("\t"),n=e.lastIndexOf(","),o=Math.max(t,r,n);if(o<Math.floor(e.length*eL))return-1;return e[o]===","?o+1:o}function sL(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function aL(e,t=!1){let r=e.trim();if(r==="")return;if(t){let n=Ai(r);if(n)return new RegExp(n.source,n.flags.includes("g")?n.flags:`${n.flags}g`)}return new RegExp(sL(r),"gi")}function cL(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 c=s,l=s+a.text.length,d=0;for(let u of n){let f=Math.max(u.start,c),p=Math.min(u.end,l);if(p<=f)continue;let m=f-c,g=p-c;if(m>d)i.push({text:a.text.slice(d,m),kind:a.kind});i.push({text:a.text.slice(m,g),kind:"search"}),d=g}if(d<a.text.length)i.push({text:a.text.slice(d),kind:a.kind});s=l}return i.filter((a)=>a.text!=="")}function gx(e,t="",r=!1){let n=Gc(e),o=[],i=new RegExp(tL.source,"gi"),s=0,a=i.exec(n);while(a){let d=a[0]??"";if(a.index>s)o.push({text:n.slice(s,a.index),kind:"text"});o.push({text:d,kind:rL(d)}),s=a.index+d.length,a=i.exec(n)}if(s<n.length)o.push({text:n.slice(s),kind:"text"});let c=o.length===0?[{text:n,kind:"text"}]:o,l=aL(t,r);return l?cL(c,l):c}function hx(e){let t=e.showTimestamps?Bc:0,r=e.showMeta?Hc:0;return Math.max(lx,e.width-t-e.serviceWidth-Wc-r-dx-ks*ux)}function yx(e,t){let r=t.reduce((s,a)=>Math.max(s,a.length),0),n=Bc+Wc+dx+lx+ks*ux,o=Math.max(ax,e-n),i=Math.max(ax,r);return Math.min(fp,o,i)}function oi(e){return lL.has(e)}function xx(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 bx(e,t){let r=t.length>0?t[t.length-1].seq:-1,n=e.filter((o)=>o.seq>r);return[...t,...n]}function wx(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 wp(e,t,r){return e&&t<=0&&r}function Sx(e){return e.filter((t)=>t.level==="ERROR"||t.level==="FATAL").length}function go(e,t){let r=t.services?.filter((l)=>l!=="")??[],n=t.service??"",o=(t.search??"").trim(),i=t.source??"",s=t.since??"",a=t.until??"",c;if(o!=="")if(t.regex===!0){let l=Ai(o);if(l)c=(d)=>l.test(d);else c=(d)=>d.toLowerCase().includes(o.toLowerCase())}else{let l=o.toLowerCase();c=(d)=>d.toLowerCase().includes(l)}return e.filter((l)=>{if(r.length>0&&!r.includes(l.service))return!1;if(n!==""&&l.service!==n)return!1;if(i!==""&&l.source!==i)return!1;if(t.systemLogs===!1&&oi(l.source))return!1;if(s!==""&&l.timestamp<s)return!1;if(a!==""&&l.timestamp>a)return!1;if(t.errorOnly===!0&&l.level!=="ERROR"&&l.level!=="FATAL")return!1;if(!c)return!0;return c(l.message)||c(l.service)})}function dL(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 kx(e,t,r=[]){let n=Jc(e,t,r);return[{name:"",count:t.length},...dL(t,n)]}function uL(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 Cx(e,t,r=[]){let n=Object.keys(t.byService).map((i)=>({service:i})),o=Jc(e,n,r);return[{name:"",count:t.total},...uL(o,t.byService)]}function Rx(e,t){if(e<=0)return"none started";return`${e}/${t} running`}function Jc(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 Sp(e,t,r){let n=["",...e],o=n.indexOf(t),s=((o<0?0:o)+r+n.length)%n.length;return n[s]??""}var Hc=8,Bc=9,Wc=7,ax=10,lx=16,dx=2,ks=1,Tr=200,QA=2,cx=1,ZA="\u25B8",ux=2,eL=0.4,tL,nL,lL,vx;var hr=D(()=>{la();It();At();tL=/("[^"]*"|'[^']*'|\b(?:ERROR|FATAL|WARN(?:ING)?|FAIL(?:ED)?)\b|\b\d{3,5}\b)/gi;nL=/\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-Z\\-_]/g;lL=new Set(["auth","devctl","proxy"]),vx=["devctl","mcp","auth"]});function ii(e){return e.length+fL}function Px(e,t){if(t<gL)return _e(e,3);if(t<mL)return _e(e,4);return e}function _x(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=kp(e,o,r);if(i.start===0&&i.end===n-1)return i;let s=o>0?zc:0,a=o<n-1?zc:0,c=s+a,l=kp(e,o,Math.max(e[o]??0,r-c)),d=(s>0&&l.start===0?zc:0)+(a>0&&l.end===n-1?zc:0);if(d===0)return l;return kp(e,o,Math.max(e[o]??0,r-c+d))}function kp(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,c=i<n-1?e[i+1]??0:Number.POSITIVE_INFINITY,l=o>0&&s+a<=r,d=i<n-1&&s+c<=r;if(!l&&!d)break;let u=t-(o-1),f=i+1-t;if(l&&(!d||u<=f))o-=1,s+=a;else if(d)i+=1,s+=c;else break}return{start:o,end:i}}function Ex(e){if(e==="detail")return ho.findIndex((t)=>t.id==="services");return ho.findIndex((t)=>t.id===e)}function Tx(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 pL;if(e==="config")return t.config??0;return 0}function Ax(e){if(e.length===1&&e>="1"&&e<="9")return ho[Number(e)-1]?.id;return}var pL=9,fL=2,zc=2,mL=80,gL=56,ho,An;var Ln=D(()=>{It();ho=[{id:"dashboard",label:"dashboard"},{id:"services",label:"services"},{id:"logs",label:"logs"},{id:"proxy",label:"proxy"}];An=ho.map((e)=>e.id)});function Mx(e,t=!0){let r=e<Yc?Lx+1:Lx,n=t?wL:0;return r+n+xL+n+bL+n}function ai(e){return Math.max(yL,e-vL*2)}function Ox(e){let t=e.width<hL,r=e.proxyOn?`\u25CF ${_e(e.proxyAddress,t?10:18)}`:"";return[{label:t?`${e.running}/${e.total}`:Rx(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 Dx(e){return e.key==="/"&&e.label==="command"}function SL(e){return e.key.length+e.label.length+3}function Ix(e,t){let r=e.filter(Dx),n=e.filter((s)=>!Dx(s)),o=[],i=0;for(let s of[...r,...n]){let a=SL(s);if(i+a>t)break;o.push(s),i+=a}return o}function Xc(e,t,r,n,o="center",i=!0){let s=Math.min(r,Math.max(1,e-4)),a=Math.min(Mx(e,i),Math.max(0,t-1)),c=Math.min(n,Math.max(1,t-a)),l=Math.max(0,Math.min(Math.floor((e-s)/2),Math.max(0,e-s))),d=o==="bottom"?t-2-c:Math.floor((t-c)/2),u=Math.max(0,Math.min(d,t-c));return{left:l,top:u,width:s,height:c}}function $x(e){if(e==="")return"idle";if(CL.test(e))return"error";if(e.includes("session only"))return"warning";if(kL.test(e))return"success";return"info"}function Fx(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 Nx(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 Hx(e){let t=e.payload?.error;return typeof t==="string"&&t!==""?t:"configuration reload failed"}var si=100,Yc=90,hL=60,yL=8,vL=6,Lx=1,xL=1,bL=1,wL=1,rj,kL,CL;var yr=D(()=>{It();hr();Ln();rj=Mx(Yc-1);kL=/^(started|stopped|restarted|refreshed|cleared|copied|exported|jumped|proxy started|proxy stopped|secrets|re-running|theme |mouse |leader |display |restored)/i,CL=/\b(fail|error|unknown|not found|no configuration|blocked|already in use|is using port)\b/i});function Qc(){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: selected, all lines, or clip",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 yo(e){let t=e.trim().toLowerCase().replace(/^\//,""),r=t.indexOf(" ");return r===-1?t:t.slice(0,r)}function Ux(e){let t=yo(e);if(t==="")return Qc();return Qc().map((r)=>({command:r,score:HL(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 HL(e,t){if(t==="")return 1;let r=e.name.toLowerCase(),n=e.aliases.map((o)=>o.toLowerCase());return WL(r,n,t)||jL(r,n,t)||GL(r,n,t)||UL(r,n,t)||BL(e.suggest,t)||KL(e.desc.toLowerCase(),t)}function BL(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 Wx;if(t.length<Gx)return 0;return r.some((n)=>n.includes(t)||n.replace(/^-+/,"").startsWith(t))?jx:0}function WL(e,t,r){if(e===r)return RL;return t.includes(r)?PL:0}function jL(e,t,r){if(e.startsWith(r))return _L;if(t.some((i)=>i.startsWith(r)))return EL;let n=e.split("-");return n.length>1&&n.some((i)=>i.startsWith(r))?TL:0}function GL(e,t,r){if(r.length<Gx)return 0;if(e.includes(r))return Wx;return t.some((n)=>n.includes(r))?jx:0}function UL(e,t,r){if(r.length<OL)return 0;let n=Bx(e,r);if(n>0)return AL+Math.min(n,NL);return t.some((o)=>Bx(o,r)>0)?LL:0}function Bx(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 KL(e,t){if(t.length<IL)return 0;if(e.split(/[^a-z0-9+]+/).filter((n)=>n.length>=$L).some((n)=>n.startsWith(t)))return DL;return t.length>=FL&&e.includes(t)?ML:0}function Br(e){let t=e.trim().toLowerCase().replace(/^\//,"").split(" ")[0]??"";return Qc().find((r)=>r.name===t||r.aliases.includes(t))}function Cp(e){return e.trim().replace(/^\//,"").split(/\s+/).slice(1).filter((r)=>r!=="")}function Kx(e){return Qc().find((r)=>r.leader===e)?.name??""}function qx(e){let t=e.includes("--cascade")||e.includes("-c");return{services:e.filter((n)=>n!=="--cascade"&&n!=="-c"),cascade:t}}function Vx(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 RL=100,PL=90,_L=80,EL=70,TL=60,Wx=50,jx=45,AL=30,LL=28,DL=20,ML=10,Gx=2,OL=3,IL=4,$L=4,FL=4,NL=9;function Xx(e){return e==="detail"?"services":e}function Qx(e){let t=An.indexOf(Xx(e));if(t<0)return"dashboard";return An[(t+1)%An.length]??"dashboard"}function Zx(e){let t=An.indexOf(Xx(e));if(t<0)return"dashboard";return An[(t-1+An.length)%An.length]??"dashboard"}function Pp(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 Zc(e){return e.hint?`${e.name} ${e.hint}`:e.name}function _p(e){return e.name}function eb(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 tb(e){let t=e.reduce((n,o)=>Math.max(n,_p(o).length),0),r=Math.min(Rp,Math.max(t,1));return qL+r+VL}function rb(e){return e.hint?`${e.name} ${e.hint} `:`${e.name} `}function nb(e,t){if(e.hint)return e.hint.split(/\s+/);return Br(t)?.name===e.name?Cp(t):[]}function Jx(e,t){if(t==="")return!0;let r=t.toLowerCase(),n=e.toLowerCase();return n.startsWith(r)||n.includes(r)}function JL(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 zx(e,t){return{...e,hint:t.token,desc:t.desc,usage:void 0,suggest:void 0}}function zL(e,t,r={}){let n=Cp(t).join(" "),o=t.trim().includes(" ")||t.endsWith(" "),i=yo(t),s=[];for(let a of e){if(s.push({...a,hint:void 0}),i==="")continue;let c=a.name===i||a.aliases.includes(i),l=c?n:i;for(let d of a.suggest??[])if(Jx(d.token,l))s.push(zx(a,d));if(!c||!o)continue;for(let d of JL(a,r))if(Jx(d.token,n))s.push(zx(a,d))}return s}function ob(e,t={}){let r=Ux(e),n=yo(e)===""?Pp(r).flatMap((o)=>o.items):r;return zL(n,e,t)}function Ep(e,t,r,n){let o=yo(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 ib(e,t,r=Xr()){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[Wr,{key:"\u2191\u2193",label:"move"},{key:"enter",label:"save"},{key:"esc",label:"revert"}];if(t==="help")return[Wr,{key:"j/k",label:"scroll"},{key:"esc",label:"close"}];if(t==="log-details"||t==="scroll-text")return[Wr,{key:"j/k",label:"scroll"},{key:Ci(r),label:"copy"},{key:"esc",label:"close"}];if(t==="confirm")return[{key:"enter",label:"confirm"},{key:"esc",label:"stay"}];if(t==="plan")return[Wr,{key:"esc",label:"back to dashboard"},{key:"enter",label:"done"}];if(t==="leader")return[Wr,...Tp()];if(t==="config-edit")return[{key:Mt("s"),label:"save"},{key:"esc",label:"discard"}];return YL(e,r)}function Tp(){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 YL(e,t){let r=[{key:Ci(t),label:"copy"},Wr,{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:Mt("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:Mt("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 sb(e,t,r){if(r<=t||e<t)return 0;return Math.min(e-t+1,r-t)}function Yx(e,t,r){let n=e.slice(t,r+1),o=new Set(n.map((i)=>i.group));return n.length+o.size}function ab(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&&Yx(e,o,i+1)<=r,a=o>0&&Yx(e,o-1,i)<=r;if(s)i+=1;else if(a)o-=1;else break}return e.slice(o,i+1)}function ci(e,t){if(e.length===0)return;let r=Math.min(Math.max(t,0),e.length-1);return e[r]}var Wr,qL=3,VL=2,Rp=22;var vo=D(()=>{Pr();Ln();Wr={key:"/",label:"command"}});function tl(e,t){let r=t??Object.keys(e?.services??{});return{running:r.filter((o)=>mo(e?.services[o])).length,total:r.length}}function cb(e,t){let r=0,n=0,o=0,i=0,s=0,a=0;for(let c of e){let l=t?.services[c];if(l?.health==="HEALTHY")o+=1;let d=l?.state??"STOPPED";if(d==="FAILED")i+=1;else if(d==="STOPPING")s+=1;else if(d==="STARTING"||d==="RESTARTING")n+=1;else if(Ss(d))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 lb(e,t){if(!Number.isFinite(e)||!Number.isFinite(t)||t<=0)return 0;return e/t}function rD(e,t,r){if(!Number.isFinite(e))return"success";if(e>r)return"error";if(e>t)return"warning";return"success"}function nD(e,t){return rD(lb(e,t),XL,QL)}function Mp(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 Cs[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(Cs.length-1,Math.round(i*(Cs.length-1)));return Cs[s]??Cs[0]}).join("")}function oD(e,t){let r=t>0?e/t:1;if(r<eD)return"error";if(r<ZL)return"warning";return"success"}function Ap(e){if(!Number.isFinite(e)||e<0)return"\u2014";return e.toFixed(2)}function iD(e){if(!Number.isFinite(e)||e<0)return"\u2014";return`${Math.round(e*100)}%`}function db(e,t=Date.now()){if(!e?.startTime)return"\u2014";let r=new Date(e.startTime).getTime();if(!Number.isFinite(r))return"\u2014";return hs(t-r)}function ub(e,t=tD){return Object.entries(e).sort((r,n)=>n[1]-r[1]||r[0].localeCompare(n[0])).slice(0,t)}function pb(e,t=1){return Math.max(24,e-pD-t*2-fD-mD-gD)}function fb(e){let t=e>=sD,r=e>=aD,n=e>=cD,o=e>=lD,i=e>=dD,s=e>=uD,a=Er+$t;if(t)a+=Hr+$t;if(r)a+=xs+$t;if(n)a+=bs+$t;if(o)a+=vs+$t;if(i)a+=rl+$t;if(s)a+=nn;return{name:Math.max(Ac,e-a),health:t,cpu:r,mem:n,up:o,rst:i,pid:s}}function mb(e){let t=Number.isFinite(e)&&e>0?e:0;return{ratio:Math.min(1,t),label:iD(t)}}function gb(e,t=vD){return`[${ni(e.ratio,t)}] ${e.label.padStart(4)}`}function Op(e,t){let r=e.reduce((l,d)=>Math.max(l,d.what.length),4),n=e.reduce((l,d)=>Math.max(l,d.reading.length),7),o=e.some((l)=>l.meter)?xD:0,i=li*(o>0?3:2),s=Math.min(hD,Math.max(Lp,r)),a=Math.min(yD,Math.max(Dp,n)),c=t-s-a-o-i;if(c<el&&a>Dp)a=Math.max(Dp,a-(el-c)),c=t-s-a-o-i;if(c<el&&s>Lp)s=Math.max(Lp,s-(el-c)),c=t-s-a-o-i;return{what:s,reading:a,meaning:Math.max(0,c),meter:o}}function hb(e){return bD.has((e?.health.type??"").toLowerCase())}function yb(e){if(e==="darwin")return"macOS";if(e==="win32")return"Windows";if(e==="linux")return"Linux";return e||"this computer"}function vb(e,t){let r=Math.max(1,t),n=nD(e,r),o=n==="error"?"overloaded":n==="warning"?"busy":"not busy",i=n==="error"?`${r} cores are queued up \u2014 last minute ${Ap(e)}`:n==="warning"?`${r} cores nearly full \u2014 last minute ${Ap(e)}`:`${r} cores. Last minute ${Ap(e)} (under ${r} is fine)`;return{what:"CPU work",reading:o,meaning:i,tone:n,meter:mb(lb(e,r))}}function xb(e,t){let r=oD(e,t),n=`${ys(e)} of ${ys(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:mb(i)}}function bb(e){let t=e?.state??"STOPPED";if(t==="FAILED")return"crashed";if(t==="STOPPING")return"stopping";if(t==="STARTING"||t==="RESTARTING")return"starting";if(Ss(t))return"up";return"off"}function wb(e){if(!e||!Ss(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 Sb(e){if(e==="keychain")return"password store";if(e==="file")return"local file";return e||"unknown store"}function kb(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 XL=0.85,QL=1.5,ZL=0.2,eD=0.1,tD=5,Cs="\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588",sD=52,aD=64,cD=72,lD=82,dD=90,uD=100,pD=2,fD=2,mD=2,gD=1,rl=8,Lp=8,hD=22,Dp=6,yD=28,el=12,li=2,vD=10,xD=18,bD;var nl=D(()=>{It();At();bD=new Set(["http","tcp","command"])});import{useEffect as wD,useRef as SD}from"react";import{jsxDEV as me,Fragment as CD}from"@opentui/react/jsx-dev-runtime";function kD(e,t){switch(t){case"primary":return{bg:e.primary,fg:uo(e.primary,e.inverse)};case"accent":return{bg:e.accent,fg:Cc(e)?kc:uo(e.accent,e.inverse)};case"success":return{bg:e.success,fg:uo(e.success,e.inverse)};case"warning":return{bg:e.warning,fg:Cc(e)?kc:uo(e.warning,e.inverse)};case"error":return{bg:e.error,fg:uo(e.error,e.inverse)};case"info":return{bg:e.info,fg:uo(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 Cb(e){let{palette:t,dir:r}=e;return me("box",{width:2,height:1,flexShrink:0,overflow:"hidden",children:me("text",{fg:t.muted,children:r==="left"?"\u2039":"\u203A"},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function jt(e){let{palette:t,children:r,backgroundColor:n,edge:o="bottom"}=e,i=ve(),s=e.ruled??!po(i),a=n??t.element,c=me("box",{flexShrink:0,flexDirection:"column",backgroundColor:a,overflow:"hidden",children:r},void 0,!1,void 0,this);if(!s)return c;return me("box",{flexShrink:0,flexDirection:"column",overflow:"hidden",border:[...o==="both"?["top","bottom"]:[o]],borderStyle:"single",borderColor:t.border,children:c},void 0,!1,void 0,this)}function ol(e){let{palette:t,items:r,active:n,width:o,onPick:i,emphasis:s="ghost"}=e,a=r.map((u)=>ii(u.label)),c=_x(a,n,Math.max(1,o)),l=c.start>0,d=c.end>=0&&c.end<r.length-1;return me("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[l?me(Cb,{palette:t,dir:"left"},void 0,!1,void 0,this):null,r.map((u,f)=>{if(f<c.start||f>c.end)return null;let p=f===n,m=s==="fill"&&p;return me(We,{palette:t,label:u.label,tone:m?"primary":"ghost",bg:m?void 0:p?t.highlight:t.element,fg:m?void 0:p?t.primary:u.color??t.muted,onMouseDown:()=>i(f)},u.id,!1,void 0,this)}),d?me(Cb,{palette:t,dir:"right"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function We(e){let{palette:t,label:r,tone:n="idle",fg:o,bg:i,onMouseDown:s}=e,a=kD(t,n);return me("box",{height:1,paddingLeft:1,paddingRight:1,backgroundColor:i??a.bg,overflow:"hidden",flexShrink:0,onMouseDown:s,children:me("text",{fg:o??a.fg,children:r},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function ot(e){let{palette:t,hints:r}=e;return me("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:r.map((n)=>me("box",{height:1,paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:me("text",{wrapMode:"none",children:[me("span",{fg:t.primary,children:n.key},void 0,!1,void 0,this),me("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 dt(e){let{palette:t,items:r,hints:n,ruled:o=!0}=e,i=me("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[r.map((s,a)=>me(We,{palette:t,label:s.text,tone:s.tone,onMouseDown:s.onMouseDown},`${s.text}-${a}`,!1,void 0,this)),n&&n.length>0?me(CD,{children:[me("box",{flexGrow:1,backgroundColor:t.element},void 0,!1,void 0,this),me(ot,{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 me(jt,{palette:t,backgroundColor:t.element,children:i},void 0,!1,void 0,this)}function ut(e){let{palette:t,title:r,termW:n,termH:o,preferW:i,preferH:s,anchor:a="center",borderColor:c,bottomTitle:l,gap:d,children:u}=e,f=po(ve()),p=Xc(n,o,i,s,a,!f);return me("box",{position:"absolute",left:p.left,top:p.top,width:p.width,height:p.height,border:!0,borderStyle:Ip,borderColor:c??t.borderActive,backgroundColor:t.panel,padding:f?0:1,title:r,titleColor:t.primary,bottomTitle:l,gap:f?0:d,flexDirection:"column",overflow:"hidden",children:u},void 0,!1,void 0,this)}function je(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 rt(e,t){if(!e)return;e.scrollBy({x:0,y:t})}function di(e,t){let r=SD(null);return wD(()=>{let n=r.current;if(!n||e<0)return;let o=requestAnimationFrame(()=>{n.scrollChildIntoView(`${t}-${e}`)});return()=>cancelAnimationFrame(o)},[t,e]),r}function kt(e){let t=ve(),r=gs(t),n=e.scroll?me("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:je(e.palette),children:me("box",{flexDirection:"column",overflow:"hidden",children:e.children},void 0,!1,void 0,this)},void 0,!1,void 0,this):e.children;return me("box",{flexGrow:1,border:!0,borderStyle:Ip,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 xo(e){let{palette:t,label:r,value:n,tone:o="text"}=e,i=ve(),s=o==="success"?t.success:o==="warning"?t.warning:o==="error"?t.error:o==="muted"?t.muted:t.text;return me("box",{height:i.rowH,flexDirection:"row",overflow:"hidden",children:[me("box",{width:14,flexShrink:0,overflow:"hidden",children:me("text",{fg:t.muted,children:r},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("box",{flexGrow:1,overflow:"hidden",children:me("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 il(e){let{palette:t,title:r,body:n,hint:o}=e;return me("box",{paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",border:!0,borderStyle:Ip,borderColor:t.borderActive,titleColor:t.primary,children:[me("text",{fg:t.primary,children:r},void 0,!1,void 0,this),me("text",{fg:t.text,wrapMode:"word",children:n},void 0,!1,void 0,this),o?me("text",{fg:t.muted,wrapMode:"word",children:o},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var Ip="rounded";var ke=D(()=>{Ot();yr();Ln();_r();tt()});import{jsxDEV as Oe,Fragment as PD}from"@opentui/react/jsx-dev-runtime";function Pb(e){let{palette:t,cfg:r,snap:n,google:o,profile:i,reveal:s,width:a}=e,c=tl(n,r?Object.keys(r.services):void 0),l=n?.proxy.running===!0,d=o?.adcAvailable===!0,u=a<Yc,f=_e(r?.project.name||"local",u?18:22),p=_e(i||n?.profile||"no profile",16),m=Ox({width:a,running:c.running,total:c.total,proxyOn:l,proxyAddress:n?.proxy.address??"",mcpOn:n?.mcp?.running===!0,adc:d,reveal:s}).filter((x)=>!x.hide&&x.label!=="").map((x)=>Oe(We,{palette:t,label:x.label,tone:x.tone},x.label,!1,void 0,this)),g=gs(ve()),y=Oe("box",{height:1,flexGrow:1,overflow:"hidden",backgroundColor:t.panel,paddingLeft:1,children:Oe("text",{wrapMode:"none",children:[Oe("span",{fg:t.primary,children:er()},void 0,!1,void 0,this),Oe("span",{fg:t.muted,children:` ${f}`},void 0,!1,void 0,this),Oe("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 Oe(jt,{palette:t,backgroundColor:t.panel,ruled:!g,children:Oe("box",{height:u?2:1,flexDirection:"column",backgroundColor:t.panel,overflow:"hidden",children:[Oe("box",{height:1,flexDirection:"row",overflow:"hidden",children:[y,u?null:m]},void 0,!0,void 0,this),u?Oe("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 _b(e){let{palette:t,screen:r,width:n,onSelect:o}=e,i=n>=Rb+RD,s=i?Math.max(1,n-Rb):n,a=ho.map((l)=>({id:l.id,label:Px(l.label,s)})),c=Ex(r);return Oe(jt,{palette:t,backgroundColor:t.element,children:Oe("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[Oe(ol,{palette:t,items:a,active:c,width:s,onPick:(l)=>{let d=ho[l];if(d)o(d.id)}},void 0,!1,void 0,this),i?Oe(PD,{children:[Oe("box",{flexGrow:1,backgroundColor:t.element},void 0,!1,void 0,this),Oe(ot,{palette:t,hints:[Wr]},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 Eb(e){let{palette:t,screen:r,overlay:n,status:o,paused:i,errorOnly:s,width:a,copyKey:c}=e,l=gs(ve()),d=Math.max(18,Math.floor(a*0.42)),u=Ix(ib(r,n,c),d),f=$x(o);return Oe(jt,{palette:t,backgroundColor:t.panel,edge:"top",ruled:!l,children:Oe("box",{height:1,backgroundColor:t.panel,overflow:"hidden",children:Oe(dt,{ruled:!1,palette:t,items:[{text:r,tone:"ghost"},{text:i?"PAUSED":"LIVE",tone:i?"warning":"success"},...s?[{text:"ERROR+",tone:"error"}]:[],...o===""?[]:[{text:_e(o,Math.max(16,a-d-28)),tone:f}]],hints:u},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Ve(e){return Oe("box",{flexGrow:1,padding:1,overflow:"hidden",children:Oe(il,{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 sl(e){return Oe("box",{flexGrow:1,padding:1,overflow:"hidden",children:Oe("text",{fg:e.palette.text,children:e.label},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Tb(e){return Oe("box",{flexGrow:1,padding:1,flexDirection:"column",overflow:"hidden",children:[Oe("text",{fg:e.palette.error,children:e.title},void 0,!1,void 0,this),Oe("text",{fg:e.palette.text,wrapMode:"word",children:e.body},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Rb,RD=8;var zt=D(()=>{Ot();yr();vo();It();Ln();nl();ke();_r();Rb=Wr.key.length+Wr.label.length+3});function _D(){if(process.platform==="darwin")return[["pbcopy"]];if(process.platform==="win32")return[["clip"]];return[["wl-copy"],["xclip","-selection","clipboard"],["xsel","--clipboard","--input"]]}function ED(){return _D().filter((e)=>{let t=e[0];return typeof t==="string"&&Bun.which(t)!==null})}function TD(e){return`\x1B]52;c;${Buffer.from(e,"utf8").toString("base64")}\x07`}function Ab(){if(process.platform==="linux")return"install wl-clipboard (Wayland) or xclip (X11)";return"no clipboard helper found"}async function al(e){let t=ED(),r;for(let n of t)try{await LD(n,e);return}catch(o){r=o instanceof Error?o:Error(String(o))}if(process.platform!=="win32")try{await AD(e);return}catch(n){r=n instanceof Error?n:Error(String(n))}throw Ne(ct,"clipboard unavailable",r?`${Ab()} (${r.message})`:Ab())}async function AD(e){let t=TD(e);try{await Bun.write("/dev/tty",t)}catch{if(!process.stderr.write(t))throw Error("terminal clipboard write failed")}}async function LD(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 $p=D(()=>{te()});function Fp(e){return e==="slash"||e==="config-edit"||e==="setup-wizard"}function Lb(e,t){return pn(e,t.keybinds.leader??_o("x"))}function Db(e,t){return pn(e,t.keybinds.command_list??_o("p"))}function on(e,t){return pn(e,t.keybinds.command??"/")||e.name==="/"}function Mb(e,t){return pn(e,t.keybinds.help??"?")||e.sequence==="?"}function Ob(e,t){return pn(e,t.keybinds.search??"f")}function Ib(e){return(e.name??"").toLowerCase()==="q"&&!e.ctrl&&!e.meta&&!e.super&&!e.alt&&!e.option}function $b(e){let t=e.name??"";return t==="R"||e.shift===!0&&t.toLowerCase()==="r"}function Fb(e){return Or(e)&&(e.name??"").toLowerCase()==="l"}function Nb(e,t){return pn(e,t.keybinds.copy??Xr())}function Hb(e,t,r=DD){return t>0&&e-t<=r}function Dn(e,t,r,n){return pn(e,t.keybinds[r]??n)}function Rs(e){let t=(e.name??"").toLowerCase();return t==="pagedown"||Or(e)&&t==="d"}function Ps(e){let t=(e.name??"").toLowerCase();return t==="pageup"||Or(e)&&t==="u"}var DD=2000;var cl=D(()=>{Pr()});function ui(e){return`http://127.0.0.1:${e}/mcp`}function Np(e){if(e==="")return{};return{Authorization:`Bearer ${e}`}}function Hp(e,t){return JSON.stringify({mcpServers:{devctl:{type:"http",url:e,headers:Np(t)}}},null,2)}function Bp(e,t){return JSON.stringify({mcpServers:{devctl:{url:e,headers:Np(t)}}},null,2)}function Wp(e,t){return JSON.stringify({mcp:{devctl:{type:"remote",url:e,headers:Np(t),enabled:!0}}},null,2)}function jp(e,t){let r=t===""?"":`
|
|
599
|
+
http_headers = { Authorization = "Bearer ${t}" }`;return`[mcp_servers.devctl]
|
|
600
|
+
url = "${e}"${r}
|
|
601
|
+
`}function MD(e){return`codex mcp add --url ${e}`}function _s(e,t){return[{kind:"claude",title:"Claude",path:".mcp.json",language:"json",text:Hp(e,t),hint:"claude mcp add-json"},{kind:"cursor",title:"Cursor",path:".cursor/mcp.json",language:"json",text:Bp(e,t)},{kind:"kilo",title:"Kilo Code",path:"kilo.jsonc",language:"json",text:Wp(e,t)},{kind:"codex",title:"Codex",path:"~/.codex/config.toml",language:"toml",text:jp(e,t),hint:MD(e)}]}function Bb(e,t){let r=[`URL ${e}`,""];for(let n of _s(e,t))r.push(`# ${n.title} ${n.path}${n.hint?` (${n.hint})`:""}`),r.push(n.text.trimEnd()),r.push("");return r.join(`
|
|
602
|
+
`)}import{jsxDEV as K}from"@opentui/react/jsx-dev-runtime";function qp(){return Qu.flatMap((e)=>xc.filter((t)=>t.category===e))}function dl(){return ll+qp().length}function Gb(){return dl()+jb}function Es(e){if(e<ll||e>=dl())return;return qp()[e-ll]}function Vp(e){let t=e-dl();return t>=0&&t<jb?t:void 0}function Ub(e){let{palette:t,snap:r,port:n,portDraft:o="",selected:i,onPick:s,onToggle:a,onCopy:c,onToggleTool:l}=e,d=ve(),u=r?.mcp?.running===!0,f=r?.mcp?.port??n,p=r?.mcp?.address??ui(f),m=r?.mcp?.token??"",g=_s(p,m),y=r?.mcp?.disabled_tools??[],x=qp(),h=x.filter((w)=>!En(w.name,y)).length,P=g[Vp(i)??-1],_=P??g[0];return K(kt,{palette:t,title:"mcp settings",children:[K(dt,{palette:t,items:[{text:u?"RUNNING":"STOPPED",tone:u?"success":"idle"},{text:`127.0.0.1:${f}`,tone:"info"}]},void 0,!1,void 0,this),K("box",{flexGrow:1,overflow:"hidden",children:K("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:je(t),children:K("box",{flexDirection:"column",overflow:"hidden",children:[K(Gp,{palette:t,text:"Server"},void 0,!1,void 0,this),K(Wb,{palette:t,active:i===Up,rowH:d.rowH,label:"Listen",value:u?"[ ON ]":"[ OFF ]",valueTone:u?"success":"muted",hint:u?"space or enter stop":"space or enter start",onPick:()=>s(Up),onActivate:a},void 0,!1,void 0,this),K(Wb,{palette:t,active:i===Kp,rowH:d.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(Kp)},void 0,!1,void 0,this),K("box",{height:1,overflow:"hidden",children:K("text",{fg:t.muted,wrapMode:"none",children:u?"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),K(Gp,{palette:t,text:"Tools",extra:h===0?"all enabled":`${h} disabled`},void 0,!1,void 0,this),K("box",{height:1,overflow:"hidden",children:K("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),Qu.map((w)=>{let v=x.filter((b)=>b.category===w);if(v.length===0)return null;return K("box",{flexDirection:"column",overflow:"hidden",children:[K("box",{height:1,marginTop:1,overflow:"hidden",children:K("text",{fg:t.muted,wrapMode:"none",children:OD[w]??w},void 0,!1,void 0,this)},void 0,!1,void 0,this),v.map((b)=>{let S=ll+x.indexOf(b);return K(ND,{palette:t,tool:b,enabled:En(b.name,y),active:i===S,rowH:d.rowH,onPick:()=>s(S),onToggle:()=>l(b)},b.name,!1,void 0,this)})]},w,!0,void 0,this)}),K(Gp,{palette:t,text:"Copy agent config",extra:"highlight a row, then enter or click Copy"},void 0,!1,void 0,this),g.map((w,v)=>{let b=dl()+v;return K(FD,{palette:t,snippet:w,active:i===b,rowH:d.rowH,onPick:()=>s(b),onCopy:()=>c(w)},w.kind,!1,void 0,this)}),K(HD,{palette:t,snippet:_,selected:Boolean(P),brand:_?Rc(_.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),K(jt,{palette:t,backgroundColor:t.element,edge:"top",children:K(ot,{palette:t,hints:$D(i,u)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function $D(e,t){if(e===Up)return[{key:"space",label:t?"stop server":"start server"},{key:"j/k",label:"move"}];if(e===Kp)return[{key:"\u2190\u2192",label:"change port"},{key:"0-9",label:"type port"},{key:"enter",label:"apply port"},{key:"j/k",label:"move"}];if(Es(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 Gp(e){let t=e.extra?` \xB7 ${e.extra}`:"";return K("box",{height:1,marginTop:1,overflow:"hidden",children:K("text",{wrapMode:"none",children:[K("span",{fg:e.palette.primary,children:e.text},void 0,!1,void 0,this),K("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 Wb(e){let{palette:t,active:r,rowH:n,label:o,value:i,valueTone:s,hint:a,onPick:c,onActivate:l}=e,d=s==="success"?t.success:s==="info"?t.info:t.muted;return K("box",{height:n,flexDirection:"row",overflow:"hidden",backgroundColor:r?t.highlight:t.panel,onMouseDown:()=>{if(r&&l){l();return}c()},children:[K("box",{width:2,flexShrink:0,overflow:"hidden",children:K("text",{fg:t.primary,children:r?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),K("box",{width:Jp,flexShrink:0,overflow:"hidden",children:K("text",{fg:r?t.primary:t.text,wrapMode:"none",children:o},void 0,!1,void 0,this)},void 0,!1,void 0,this),K("box",{width:ID,flexShrink:0,overflow:"hidden",children:K("text",{fg:d,wrapMode:"none",children:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),K("box",{flexGrow:1,overflow:"hidden",children:K("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 FD(e){let{palette:t,snippet:r,active:n,rowH:o,onPick:i,onCopy:s}=e,a=Rc(r.kind,t),c=jv(r.kind,t),l=r.language==="toml"?"Copy TOML":"Copy JSON";return K("box",{height:o,flexDirection:"row",overflow:"hidden",backgroundColor:n?t.highlight:t.panel,onMouseDown:i,children:[K("box",{width:2,flexShrink:0,overflow:"hidden",children:K("text",{fg:a,children:n?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),K("box",{width:Jp,flexShrink:0,overflow:"hidden",children:K("text",{fg:a,wrapMode:"none",children:r.title},void 0,!1,void 0,this)},void 0,!1,void 0,this),K("box",{flexGrow:1,overflow:"hidden",children:K("text",{fg:t.muted,wrapMode:"none",children:r.path},void 0,!1,void 0,this)},void 0,!1,void 0,this),K(We,{palette:t,label:l,bg:a,fg:c,onMouseDown:()=>{i(),s()}},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function ND(e){let{palette:t,tool:r,enabled:n,active:o,rowH:i,onPick:s,onToggle:a}=e;return K("box",{height:i,flexDirection:"row",overflow:"hidden",backgroundColor:o?t.highlight:t.panel,onMouseDown:()=>{if(o){a();return}s()},children:[K("box",{width:2,flexShrink:0,overflow:"hidden",children:K("text",{fg:t.primary,children:o?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),K("box",{width:5,flexShrink:0,overflow:"hidden",children:K("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),K("box",{width:Jp+4,flexShrink:0,overflow:"hidden",children:K("text",{fg:o?t.primary:n?t.text:t.muted,wrapMode:"none",children:r.label},void 0,!1,void 0,this)},void 0,!1,void 0,this),K("box",{width:7,flexShrink:0,overflow:"hidden",children:K("text",{fg:r.mutates?t.warning:t.muted,wrapMode:"none",children:r.mutates?"write":"read"},void 0,!1,void 0,this)},void 0,!1,void 0,this),K("box",{flexGrow:1,overflow:"hidden",children:K("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 HD(e){let{palette:t,snippet:r,selected:n,brand:o}=e;if(!r)return null;let i=r.hint?` \xB7 ${r.hint}`:"";return K("box",{marginTop:1,flexDirection:"column",overflow:"hidden",children:[K("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),K("text",{fg:t.text,children:r.text},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Up=0,Kp=1,ll=2,jb=4,OD,Jp=14,ID=14;var Ts=D(()=>{Ot();ke();tt();ss();OD={inspect:"Inspect",logs:"Logs",diagnostics:"Diagnostics",control:"Control",setup:"Setup"}});import{jsxDEV as Ie,Fragment as qb}from"@opentui/react/jsx-dev-runtime";function VD(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:"clip / wrap selected / wrap all"},{key:"j/k",label:"move and unfold"},{key:Ci(e),label:"copy selection"},{key:"/export",label:"write ~/.devctl/exports"},{key:"/exports",label:"open export folder"}]}function On(e){return e+jD}function Vb(e){let t=On(Yp.length),r=On(Xp.length),n=On(e.logCount),o=On(Qp.length),i=On(Zp.length),s=ef+e.pad*2;if(e.stacked)return s+t+r+n+o+i+zp+(KD-1)*e.gap;let a=Math.max(t,r),c=Math.max(o,i);return s+a+n+c+zp+(qD-1)*e.gap}function JD(e){return Vb(e)-ef-e.pad*2}function zD(e){return e-ef*2<WD}function Jb(e){let{palette:t,termW:r,termH:n,copyKey:o=Xr(),scrollRef:i}=e,s=po(ve()),a=zD(r),c=s?0:1,l=s?0:1,d=VD(o),u={stacked:a,logCount:d.length,pad:c,gap:l},f=Vb(u),p=JD(u);return Ie(ut,{palette:t,title:"help",bottomTitle:`${er()} \xB7 j/k scroll \xB7 esc close`,termW:r,termH:n,preferW:BD,preferH:f,gap:0,children:Ie("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:je(t),children:Ie("box",{height:p,flexDirection:"column",flexShrink:0,overflow:"hidden",gap:l,children:[a?Ie(qb,{children:[Ie(Mn,{palette:t,title:"navigation",bindings:Yp},void 0,!1,void 0,this),Ie(Mn,{palette:t,title:"services",bindings:Xp},void 0,!1,void 0,this),Ie(Mn,{palette:t,title:"logs",bindings:d},void 0,!1,void 0,this),Ie(Mn,{palette:t,title:"commands",bindings:Qp},void 0,!1,void 0,this),Ie(Mn,{palette:t,title:"display",bindings:Zp},void 0,!1,void 0,this)]},void 0,!0,void 0,this):Ie(qb,{children:[Ie(Kb,{palette:t,left:{title:"navigation",bindings:Yp},right:{title:"services",bindings:Xp}},void 0,!1,void 0,this),Ie(Mn,{palette:t,title:"logs",bindings:d},void 0,!1,void 0,this),Ie(Kb,{palette:t,left:{title:"commands",bindings:Qp},right:{title:"display",bindings:Zp}},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Ie("box",{height:zp,flexShrink:0,overflow:"hidden",paddingLeft:1,children:Ie("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 Kb(e){let{palette:t,left:r,right:n}=e,o=Math.max(On(r.bindings.length),On(n.bindings.length));return Ie("box",{height:o,flexDirection:"row",flexShrink:0,overflow:"hidden",gap:UD,children:[Ie(Mn,{palette:t,title:r.title,bindings:r.bindings,height:o,stretch:!0},void 0,!1,void 0,this),Ie(Mn,{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 Mn(e){let{palette:t,title:r,bindings:n,stretch:o=!1}=e,i=e.height??On(n.length),s=YD(n);return Ie("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)=>Ie("box",{height:1,flexShrink:0,overflow:"hidden",paddingLeft:1,paddingRight:1,children:Ie(XD,{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 YD(e){return e.reduce((r,n)=>Math.max(r,n.key.length),0)+GD}function XD(e){let{palette:t,binding:r,keyWidth:n}=e;return Ie("box",{height:1,flexDirection:"row",overflow:"hidden",children:[Ie("box",{width:n,flexShrink:0,overflow:"hidden",children:Ie("text",{fg:t.primary,wrapMode:"none",children:r.key},void 0,!1,void 0,this)},void 0,!1,void 0,this),Ie("box",{flexGrow:1,overflow:"hidden",children:Ie("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 BD=78,WD=56,jD=2,ef=2,zp=1,tf=8,GD=2,UD=2,KD=6,qD=4,Yp,Xp,Qp,Zp;var rf=D(()=>{Ot();ke();_r();Pr();Yp=[{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"}],Xp=[{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)"}];Qp=[{key:Mt("c"),label:"copy highlighted selection"},{key:"/",label:"command overlay"},{key:Mt("p"),label:"same overlay"},{key:Mt("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"}],Zp=[{key:Mt("="),label:"larger"},{key:Mt("-"),label:"smaller"},{key:"?",label:"this overlay"}]});function pi(e){e.setQuery(""),e.setSlashIndex(0),e.setSlashPicker("commands"),e.setOverlay("slash")}function zb(e,t){let{overlay:r,tui:n,height:o,closeOverlay:i,confirmKind:s,onQuit:a,confirmAction:c,planBusy:l,logDetailsScrollRef:d,scrollTextScrollRef:u,routeDetailsScrollRef:f,planScrollRef:p,helpScrollRef:m,revertThemePreview:g,setPaletteIndex:y,setThemeName:x,paletteIndex:h,applyTheme:P,leaderTimer:_,setOverlay:w,runCommand:v,setConfigEditError:b,saveConfigBuffer:S,setSlashIndex:k,filtered:L,setQuery:I,slashIndex:F,submitSlash:Q,advanceWizard:G}=e,C=(t.name??"").toLowerCase();if(r==="none")return!1;if(r==="setup-wizard"){if(C==="escape")return i(),!0;if(C==="return")return G?.(),!0;return Fp(r)}if(r==="confirm"){if(C==="escape")return i(),!0;if(s==="quit"&&C==="d")return a(!0),!0;if(s==="quit"&&C==="k")return e.onDown(!0),!0;if(s==="restart-cascade"&&C==="c")return c("cascade"),!0;if(C==="return")c();return!0}if(r==="log-details"||r==="scroll-text"){if(on(t,n))return pi(e),!0;if(C==="escape")return i(),!0;if(r==="log-details"&&C==="return"){let W=e.logDetail?.request_id?.trim()??"";if(W!=="")e.setLogSearch(W),e.setScreen("logs"),e.closeOverlay(),e.setStatus(`tracing ${W}`);return!0}let B=r==="log-details"?d.current:u.current;if(C==="down"||C==="j")return rt(B,n.scroll_speed),!0;if(C==="up"||C==="k")return rt(B,-n.scroll_speed),!0;if(Rs(t))return rt(B,ai(o)),!0;if(Ps(t))return rt(B,-ai(o)),!0;return!0}if(r==="route-details"){if(on(t,n))return pi(e),!0;if(C==="escape"||C==="return")return i(),!0;if(C==="down"||C==="j")return rt(f.current,n.scroll_speed),!0;if(C==="up"||C==="k")return rt(f.current,-n.scroll_speed),!0;return!0}if(r==="plan"){if(on(t,n))return pi(e),!0;if(C==="escape"||C==="return"&&!l)return i(),!0;if(C==="down"||C==="j")return rt(p.current,n.scroll_speed),!0;if(C==="up"||C==="k")return rt(p.current,-n.scroll_speed),!0;return!0}if(r==="help"){if(on(t,n))return pi(e),!0;if(C==="escape")return i(),!0;if(C==="down"||C==="j")return rt(m.current,1),!0;if(C==="up"||C==="k")return rt(m.current,-1),!0;if(C==="pagedown"||Rs(t))return rt(m.current,tf),!0;if(C==="pageup"||Ps(t))return rt(m.current,-tf),!0;return!0}if(r==="themes"){if(on(t,n))return g(),pi(e),!0;if(C==="escape")return g(),i(),!0;if(C==="down"||C==="j")return y((B)=>{let W=Math.min(B+1,St.length-1),V=St[W];if(V)x(V);return W}),!0;if(C==="up"||C==="k")return y((B)=>{let W=Math.max(0,B-1),V=St[W];if(V)x(V);return W}),!0;if(C==="return"){let B=St[h%St.length];if(B)P(B)}return!0}if(r==="leader"){if(on(t,n)){if(_.current)clearTimeout(_.current);return pi(e),!0}if(_.current)clearTimeout(_.current);w("none");let B=Kx(C),W=B?Br(B):void 0;if(W)v(W,[]);return!0}if(r==="config-edit"){if(C==="escape")return b(""),i(),!0;if(Or(t)&&C==="s")return S(),!0;return!0}if(Fp(r)){if(C==="escape")return i(),!0;if(r==="slash"&&C==="down")return k((B)=>Math.min(Math.max(L.length-1,0),B+1)),!0;if(r==="slash"&&C==="up")return k((B)=>Math.max(0,B-1)),!0;if(r==="slash"&&C==="tab"){if(t.shift)return k((W)=>Math.max(0,W-1)),!0;let B=ci(L,F);if(B)I(rb(B));return!0}if(r==="slash"&&C==="return")return Q(),!0;return!0}return!0}var Yb=D(()=>{yr();vo();cl();Pr();ke();rf();tt()});var ul=D(()=>{Uu()});function Xb(e,t){if(t.length===0)return[];let r=new Set(t);return io(e,t).filter((n)=>!r.has(n))}function Qb(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 pl(e){return e.waves.flat().join(" \u2192 ")}function Zb(e){let t=pl(e);if(t==="")return"Started selected services";return`Started ${t}`}function ew(e){let t=pl(e);if(t==="")return"Stopped running services";return`Stopped ${t}`}function tw(e,t,r,n="start"){let o=r?.services[e],i=tr(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((c)=>c.name===e)?.dependencies??[]).filter((c)=>{let l=tr(r?.services[Jt(c)]);return mn(c)==="service_healthy"?l!=="HEALTHY":l==="STOPPED"||l==="FAILED"}).map(Jt);if(a.length>0)return`waits for ${a.join(", ")}`;return"queued"}function As(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 rw(e,t,r="start"){let o=e.waves.flat().length,i=0,s=0,a=0,c=0;for(let m=0;m<e.waves.length;m++){let g=e.waves[m]??[],y=As(g,t,r);if(y==="active"||y==="unhealthy"||y==="failed")c=m;else if(y==="completed"&&c===m&&m<e.waves.length-1)c=m+1;for(let x of g){let h=t?.services[x];if(r==="stop"?!h||h.state==="STOPPED"||h.state==="UNKNOWN":Boolean(h&&(h.state==="HEALTHY"||h.health==="HEALTHY"||h.state==="RUNNING"&&h.health!=="UNHEALTHY")))i++;else if(h?.state==="FAILED")s++;else if(h?.state==="STARTING"||h?.state==="RUNNING"||h?.state==="UNHEALTHY"||h?.health==="UNHEALTHY"||h?.state==="STOPPING"||h?.state==="RESTARTING")a++}}let l=o>0?Math.round(i/o*100):100,d=16,u=Math.round(l/100*d),f="\u2588".repeat(u)+"\u2591".repeat(Math.max(0,d-u)),p=i===o&&o>0;return{total:o,ready:i,active:a,failed:s,percent:l,progressBar:f,currentWaveIndex:c,totalWaves:e.waves.length,isComplete:p}}function nw(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 ow(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 iw(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 fl=D(()=>{mt();Tt();At()});function sw(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)=>uv(n,r)),!0;return!1}function aw(e,t){let r=(t.name??"").toLowerCase(),{screen:n,overlay:o,tui:i,cfg:s,controller:a,profile:c,listCursor:l,names:d,listCount:u,height:f,checked:p,detailName:m,bootErrorMissing:g,bootError:y,logSearchFocused:x,logSources:h,logService:P,logShowTimestamps:_,logShowMeta:w,logWrap:v,showSystemLogs:b,logPinned:S,dashboardLogCursor:k,applyLogCursor:L,applyDashboardLogCursor:I,jumpToLatestLogs:F,toggleSystemLogs:Q,clearLogs:G,setLogService:C,setLogShowTimestamps:B,setLogShowMeta:W,setPaused:V,setErrorOnly:de,setLogWrap:Ee,beginStart:$e,beginStop:ne,beginRestart:H,applyMcpPortDraft:ae,toggleMcp:X,toggleMcpTool:nt,copyFocusedMcpSnippet:pt,persistMcpPort:ie,restartMcpOnPort:Ae,setMcpPortDraft:De,settingRows:Ke,persistPrefs:ht,cycleSetting:Ye,toggleMouse:Ct,setDoctorTick:he,refreshAuth:yt,configScrollRef:st,detailScrollRef:vt,handleEnter:rr,setScreen:Xe,setChecked:Xt,setStatus:qe,setSelected:ft,setProfile:vr,refresh:Kt,toggleChecked:xr,createStarterConfig:nr,startWizard:qt,setConfirmKind:or,setConfirmDetail:ir,setOverlay:sr,openConfigBuffer:Vt,runCommand:ce}=e,U=(n==="logs"||n==="dashboard")&&!x;if(U&&(r==="left"||r==="["||n==="logs"&&r==="h")){C(Sp(h,P,-1));return}if(U&&(r==="right"||r==="]"||n==="logs"&&r==="l")){C(Sp(h,P,1));return}if((n==="dashboard"||n==="setup")&&r==="o"){Xe("profiles");return}if((n==="dashboard"||n==="services")&&(r==="*"||t.shift&&r==="8")){Xt([...d]),qe(`Selected ${d.length} services`);return}if((n==="dashboard"||n==="services")&&(r==="-"||r==="_"||r==="minus")){Xt([]),qe("Selection cleared");return}if((n==="dashboard"||n==="services")&&r==="n"){$e(Oc(p,d[l]??""),c);return}if((n==="dashboard"||n==="services")&&r==="x"){ne(Oc(p,d[l]??""));return}if((n==="dashboard"||n==="services"||n==="detail")&&$b(t)){let T=Oc(p,d[l]??m);if(s&&Xb(s,T).length>0){or("restart-cascade"),ir({services:T}),sr("confirm");return}H(T,c);return}if((n==="dashboard"||n==="services")&&r==="r"){Kt(),qe("Refreshed");return}if(n==="auth"&&r==="r"){yt();return}if(n==="logs"&&r==="t"){let T=!_;B(T),ht({log_timestamps:T},T?"timestamps on":"timestamps off");return}if(n==="logs"&&r==="m"){let T=!w;W(T),ht({log_metadata:T},T?"metadata on":"metadata off");return}if(r==="down"||r==="j"){if(n==="mcp"&&l===1)ae();if(n==="config"){if(u>0)ft((T)=>Math.min(Math.max(u-1,0),T+1));rt(st.current,i.scroll_speed);return}if(n==="detail"){rt(vt.current,i.scroll_speed);return}if(n==="logs"){L(l+1);return}if(n==="dashboard"&&k>=0){I(k+1);return}ft((T)=>Math.min(Math.max(u-1,0),T+1));return}if(r==="up"||r==="k"){if(n==="mcp"&&l===1)ae();if(n==="config"){if(u>0)ft((T)=>Math.max(0,Math.min(T,Math.max(u-1,0))-1));rt(st.current,-i.scroll_speed);return}if(n==="detail"){rt(vt.current,-i.scroll_speed);return}if(n==="logs"){L(l-1);return}if(n==="dashboard"&&k>=0){I(k-1);return}ft((T)=>Math.max(0,Math.min(T,Math.max(u-1,0))-1));return}if(Rs(t)){let T=ai(f);if(n==="config"){rt(st.current,T);return}if(n==="detail"){rt(vt.current,T);return}if(n==="logs"){L(l+T);return}if(n==="dashboard"&&(S||k>=0)){I(Math.max(0,k)+T);return}ft((ye)=>Math.min(Math.max(u-1,0),ye+T));return}if(Ps(t)){let T=ai(f);if(n==="config"){rt(st.current,-T);return}if(n==="detail"){rt(vt.current,-T);return}if(n==="logs"){L(l-T);return}if(n==="dashboard"&&(S||k>=0)){I(Math.max(0,k)-T);return}ft((ye)=>Math.max(0,ye-T));return}if(n==="proxy"&&r==="n"){a?.proxyStart().then(async()=>{qe("Proxy started"),await Kt()});return}if(n==="proxy"&&r==="x"){a?.proxyStop().then(async()=>{qe("Proxy stopped"),await Kt()});return}if(n==="detail"&&m!==""){if(r==="n"){$e([m],c);return}if(r==="x"){ne([m]);return}if(r==="o"){Xe("config");return}if(r==="l"){C(m),Xe("logs");return}}if(n==="mcp"&&l===1&&(r==="left"||r==="h")){let T=Pn(ae()-1);ie(T),Ae(T);return}if(n==="mcp"&&l===1&&(r==="right"||r==="l")){let T=Pn(ae()+1);ie(T),Ae(T);return}if(n==="mcp"&&l===1&&(r==="backspace"||r==="delete")){De((T)=>pv(T));return}if(n==="settings"&&(r==="left"||r==="h")){Ye(-1,l);return}if(n==="settings"&&(r==="right"||r==="l")){Ye(1,l);return}if(r==="space"){if(n==="profiles"){let z=Object.keys(s?.profiles??{}).sort()[l];if(z)vr(z),qe(`Profile ${z}`);return}if(n==="mcp"){if(l===0){X();return}let ye=Es(l);if(ye){nt(ye);return}pt(l);return}if(n==="logs")return;if(n==="settings"){if(Tn(Ke,l)?.id==="mouse")Ct();return}let T=d[l];if(T)xr(T);return}if(r==="return"){if(n==="setup"&&!a){if(!g){qe(y||"Existing configuration is invalid \u2014 fix it and restart devctl.");return}qt();return}if(n==="setup"&&a){$e([],c);return}rr();return}if(Dn(t,i,"services","s")&&o==="none"&&n!=="logs"){Xe("services");return}if(Dn(t,i,"logs","l")&&o==="none"&&n!=="detail"&&n!=="logs"&&n!=="settings"){Xe("logs");return}if(Dn(t,i,"auth","a")&&o==="none"){Xe("auth");return}if(Dn(t,i,"proxy","p")&&o==="none"&&n!=="logs"){Xe("proxy");return}if(Dn(t,i,"doctor","d")&&o==="none"&&n!=="doctor"){Xe("doctor");return}if(Dn(t,i,"config","c")&&o==="none"){Xe("config");return}if(Dn(t,i,"setup","u")&&o==="none"){Xe("setup");return}if(n==="config"&&r==="e"){ce(Br("/edit")??{name:"edit",aliases:[],desc:"",leader:"",group:"ui"},[]);return}if(n==="config"&&r==="v"){Vt();return}if(n==="doctor"&&r==="r"){he((T)=>T+1),qe("Re-running doctor");return}if(n==="logs"&&r==="p"){V((T)=>!T);return}if((n==="logs"||n==="dashboard")&&r==="g"){F();return}if((n==="logs"||n==="dashboard")&&r==="w"){let T=Kc(v);Ee(T),qe(`Log ${Vc(T)}`);return}if((n==="logs"||n==="dashboard")&&r==="e"){de((T)=>!T);return}if((n==="logs"||n==="dashboard")&&r==="i"){Q(),qe(b?"Hiding internal auth/mcp/devctl/proxy logs":"Showing internal logs");return}if((n==="logs"||n==="dashboard")&&Fb(t))G()}var cw=D(()=>{ul();yr();hr();fl();At();cl();ke();Ts();_r()});import{useKeyboard as QD}from"@opentui/react";import{useCallback as nf}from"react";function lw({tui:e,controller:t,cfg:r,snap:n,ui:o,logView:i,lifecycleActions:s,mcp:a,preferences:c,diagnostics:l,refs:d}){let{screen:u,onQuit:f,closeOverlay:p,confirmKind:m,confirmDetail:g,portTarget:y,profile:x,listCursor:h,names:P,runCommand:_,copySelection:w,setOverlay:v,setConfirmKind:b,setConfirmDetail:S,setPortTarget:k,setLogDetail:L,setProfile:I,setStatus:F,setSlashIndex:Q,setQuery:G,setSlashPicker:C,setScreen:B,freePort:W,openDetail:V}=o,{logSlice:de,logSliceB:Ee,logSearchFocused:$e,logsFullscreen:ne,setLogSearchFocused:H,setLogsFullscreen:ae,splitLogs:X,splitFocus:nt,toggleSplitLogs:pt,cycleSplitFocus:ie,setActiveLogService:Ae,logService:De,logServiceB:Ke}=i,{beginStart:ht,beginRestart:Ye,planBusy:Ct}=s,{applyMcpPortDraft:he,toggleMcp:yt,toggleMcpTool:st,copyFocusedMcpSnippet:vt}=a,{settingRows:rr,activateSetting:Xe,applyFont:Xt,applyReset:qe,fontSize:ft,revertThemePreview:vr,setThemeName:Kt,leaderMs:xr}=c,{doctor:nr}=l,{interruptArmedAt:qt,leaderTimer:or}=d,ir=nf(()=>{if(r?.shutdown.stop_services_on_exit===void 0){b("quit"),v("confirm");return}f(r.shutdown.stop_services_on_exit===!1)},[r,f,b,v]),sr=nf((ce)=>{if(m==="quit"){f(!1);return}if(m==="reload"){p();let U=n?.restart_required??[];if(U.length>0)Ye(U,x);return}if(m==="restart-cascade"){let U=g?.services??[];p(),Ye(U,x,ce==="cascade");return}if(m==="reset-prefs"){p(),qe();return}if(m==="free-port"){let U=y;if(p(),!U)return;W(U).then(()=>{F(`Stopped ${U.command} (pid ${U.pid}) on port ${U.port}`),l.setDoctorTick((T)=>T+1)}).catch((T)=>{F(A(T))});return}p(),ht([],x)},[qe,Ye,ht,p,g,m,l,W,f,y,x,F,n]),Vt=nf(()=>{if(u==="logs"){let U=(X&&nt===1?Ee:de)[h];if(U)L(U),v("log-details");return}if(u==="profiles"){let T=Object.keys(r?.profiles??{}).sort()[h];if(T)I(T),b("start-profile"),v("confirm");return}if(u==="doctor"){let U=nr?.checks[h];if(U?.action?.kind==="free-port"){let T=U.action.holder;k(T),S({port:T.port,pid:T.pid,process:T.command}),b("free-port"),v("confirm")}return}if(u==="mcp"){if(h===0){yt();return}if(h===1){he();return}let U=Es(h);if(U){st(U);return}vt(h);return}if(u==="settings"){let U=Tn(rr,h);if(U)Xe(U);return}if(u==="config"){let U=Object.keys(r?.tasks??{}).sort()[h],T=Br("run");if(U&&T)_(T,[U]);return}if(u==="dashboard"&&Mc(n)){ht([],x);return}let ce=P[h];if(ce&&(u==="dashboard"||u==="services"))V(ce)},[Xe,he,ht,r,vt,nr,h,de,Ee,P,V,x,_,u,S,b,L,v,k,I,rr,n,nt,X,yt,st]);QD((ce)=>{let U=(ce.name??"").toLowerCase();if(Nb(ce,e)){w();return}if(Or(ce)&&(U==="="||U==="+"||U==="plus")){Xt(fs(ft,1));return}if(Or(ce)&&(U==="-"||U==="_"||U==="minus")){Xt(fs(ft,-1));return}if(Or(ce)&&U==="0"){Xt(_c().font_size);return}if(u==="logs"&&!$e&&(ce.sequence==="\\"||U==="\\")){pt(),F(X?"Single log pane":"Split log panes");return}if(u==="logs"&&!$e&&(ce.sequence==="|"||U==="|")){ie();return}if(zb({...o,tui:e,confirmAction:sr,planBusy:Ct,leaderTimer:or,logDetailsScrollRef:d.logDetailsScrollRef,scrollTextScrollRef:d.scrollTextScrollRef,routeDetailsScrollRef:d.routeDetailsScrollRef,planScrollRef:d.planScrollRef,helpScrollRef:d.helpScrollRef,revertThemePreview:vr,setThemeName:Kt},ce))return;if($e){if(U==="escape")H(!1);return}if(Lb(ce,e)){v("leader"),or.current=setTimeout(()=>v("none"),xr);return}if(Db(ce,e)||on(ce,e)){G(""),Q(0),C("commands"),v("slash");return}if(Mb(ce,e)){v("help");return}if(Ob(ce,e)||u==="logs"&&U==="f"&&!ce.ctrl&&!ce.meta){B("logs"),H(!0);return}if(U==="escape"||Ib(ce)){if(U==="escape"){if(ne){ae(!1);return}if(u==="detail"){B("services");return}if(u==="setup"&&t){B("dashboard");return}}let z=Date.now();if(Hb(z,qt.current)){qt.current=0,ir();return}qt.current=z,F(U==="q"?"q again to quit":"Esc again to quit");return}if(U==="z"&&(u==="logs"||u==="dashboard")&&!ce.ctrl&&!ce.meta){B("logs"),ae((z)=>u==="logs"?!z:!0);return}if(U==="tab"){B(ce.shift?Zx(u):Qx(u));return}let T={...o,tui:e,controller:t,cfg:r,snap:n,...i,...s,...a,...c,logService:X&&nt===1?Ke:De,setLogService:Ae,setDoctorTick:l.setDoctorTick,refreshAuth:l.refreshAuth,configScrollRef:d.configScrollRef,detailScrollRef:d.detailScrollRef,handleEnter:Vt};if(sw(T,ce))return;let ye=Ax(U);if(ye){B(ye);return}aw(T,ce)})}var dw=D(()=>{te();vo();Ln();At();cl();Ts();_r();Pr();Yb();cw()});import{parse as ZD,stringify as eM}from"yaml";function ml(e,t="imported"){let r=ZD(e);if(!r||typeof r!=="object"||Array.isArray(r))throw Error("compose file is not a mapping");let n=r,o=fi(n.services)?n.services:{},i=[];if(n.networks!==void 0)i.push({service:"(root)",field:"networks",reason:uw.networks??"not modeled"});let s={},a=[];for(let[l,d]of Object.entries(o)){if(!fi(d))continue;let u=tM(l,d,i);if(s[l]=u.body,!u.container)a.push(l)}return{yaml:eM({version:1,project:{name:t},services:s,profiles:{default:{services:a}}}),dropped:i,services:Object.keys(s),profileServices:a}}function gl(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(`
|
|
603
|
+
`)}
|
|
604
|
+
`}function tM(e,t,r){for(let f of Object.keys(t)){let p=uw[f];if(p)r.push({service:e,field:f,reason:p})}let n={},o=pw(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=rM(t.depends_on);if(s.length>0)n.dependencies=s;let a=nM(t.environment);if(Object.keys(a).length>0)n.environment={defaults:a};let c=oM(t.ports);if(c.host.length>0)n.ports=c.host;let l=sM(t.healthcheck);if(l)n.health=l;let d=typeof t.image==="string"?t.image:"",u=d!=="";if(u)n.container={image:d,...c.container&&Object.keys(c.container).length>0?{ports:c.container}:{},...Object.keys(a).length>0?{env:a}:{}};return{body:n,container:u}}function pw(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 rM(e){if(Array.isArray(e))return e.filter((t)=>typeof t==="string");if(fi(e))return Object.keys(e);return[]}function nM(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(fi(e))for(let[r,n]of Object.entries(e))t[r]=n===void 0||n===null?"":String(n);return t}function oM(e){let t=[],r={};if(!Array.isArray(e))return{host:t,container:r};let n=0;for(let o of e){let i=iM(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 iM(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(fi(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 sM(e){if(!fi(e)||e.disable===!0)return;let t=pw(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 fi(e){return Boolean(e)&&typeof e==="object"&&!Array.isArray(e)}var uw;var of=D(()=>{uw={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 fw(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 mw(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 gw(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 hw(e){let t=aM(e);return[{label:"exit",value:t,tone:t==="ask on quit"?"warning":"text"},{label:"grace",value:`${e.shutdown.grace_seconds}s`},{label:"refresh",value:`${cg(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 yw(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 vw(e){return[{label:"listen",value:yn(e.proxy.listen),tone:e.proxy.enabled?"text":"muted"},{label:"token",value:dM(e),tone:e.proxy.token_endpoint.enabled?"text":"muted"}]}function xw(e){return Object.keys(e.services).sort().map((t)=>{let r=e.services[t]??gn();return{name:t,extends:r.extends||"\u2014",command:Ic(r),ports:ws(r),identity:Fc(r),health:$c(r),depends:r.dependencies.map(xa).join(", ")||"\u2014",restart:Nc(r)}})}function bw(e){return e.proxy.routes.map((t)=>({name:t.name||t.match.host||"(unnamed)",match:uM(t),upstream:t.upstream.url||"\u2014",auth:t.auth.type||"none",identity:pM(t)}))}function ww(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 Sw(e){return Object.keys(e.templates).sort().map((t)=>({name:t,summary:fM(e.templates[t])}))}function kw(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 Cw(e,t){let r=Cn(e);if(r.length===0)return"No provenance recorded for this configuration.";let n=new mr(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?"":`
|
|
621
605
|
shadowed ${o.shadowed.map((c)=>`${c.layer} \xB7 ${c.source}`).join("; ")}`;return`${o.path}
|
|
622
606
|
${o.layer} \xB7 ${o.source}
|
|
623
607
|
${s??""}${a}`}).join(`
|
|
624
608
|
|
|
625
|
-
`)}function cx(e){let t=e.doctor.tools.map((i)=>i.name||i.command).filter((i)=>i!==""),n=e.plugins.map((i)=>i.path).filter((i)=>i!==""),r=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:n.join(", ")||"\u2014",tone:n.length>0?"text":"muted"},{label:"keymap",value:r.length>0?`${r.length} override${r.length===1?"":"s"}`:"defaults",tone:r.length>0?"text":"muted"},{label:"secrets",value:o.length>0?o.join(", "):"defaults",tone:o.length>0?"text":"muted"}]}function YR(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 lx(e){let t=e.reduce((n,r)=>Math.max(n,r.name.length),0);return Math.min(QR,Math.max(XR,t))}function ZR(e){let t=e.proxy.token_endpoint;if(!t.enabled)return"off";let n=t.host===""?"127.0.0.1":t.host;if(t.port===0)return n;return`${n}:${t.port}`}function eP(e){let t=e.match.host||"*",n=e.match.path;if(n==="")return t;return`${t}${n.startsWith("/")?n:`/${n}`}`}function tP(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 nP(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 XR=8,QR=20,dx=80,Uo=10;var Ku=D(()=>{st();Ao();Pe()});function Pc(e){let t=e.toLowerCase().trim(),n=rP[t];if(n)return n;return yt.includes(t)?t:"devctl"}function oP(){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"}),n=t.stdout.toString();if(t.exitCode===0&&n.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 ux(e){let t=Pc(e);if(t==="system"){if(oP())return{...qu["solarized-light"],name:"system"};return qu.system}return qu[t]}function Mt(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 Br(e,t){return cs(e)>=as?Tc:t}function cs(e){let t=e.startsWith("#")?e.slice(1):e,n=Number.parseInt(t,fP);if(Number.isNaN(n))return 0;let r=n>>gP&Vu,o=n>>mP&Vu,i=n&Vu;return(r*lP+o*dP+i*uP)/pP}function hP(e){let t=aP;for(let n=0;n<e.length;n+=1)t^=e.charCodeAt(n),t=Math.imul(t,cP);return t>>>0}function Ac(e){return cs(e.background)>=as}function zu(e){if(!e||!/^#[0-9a-f]{6}$/i.test(e))return!1;return cs(e)<as}function Lc(e,t){let n=vP[e];return Ac(t)?n.light:n.dark}function px(e,t){return cs(Lc(e,t))>=as?yP:xP}function He(e,t){if(e===""||e==="all")return t.muted;let n=cs(t.background)>=as?sP:iP;return n[hP(e)%n.length]??t.info}function bP(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 fx(e,t,n){if(n==="string")return e.accent;if(n==="number")return e.info;if(n==="keyword")return e.error;return bP(e,t)}function De(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 yt,Ju,qu,rP,iP,sP,aP=2166136261,cP=16777619,lP=299,dP=587,uP=114,pP=1000,as=160,fP=16,Vu=255,gP=16,mP=8,Tc="#1A1A1A",vP,yP="#1A1A1A",xP="#F5F5F5";var Ye=D(()=>{yt=["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"],Ju={devctl:"amber + cyan, product theme",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)"},qu={tokyonight:{name:"tokyonight",primary:"#82AAFF",accent:"#C792EA",error:"#FF5370",warning:"#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",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",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",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",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",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",success:"#50FA7B",info:"#8BE9FD",text:"#F8F8F2",muted:"#6272A4",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",success:"#98C379",info:"#56B6C2",text:"#ABB2BF",muted:"#5C6370",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",success:"#A6E22E",info:"#66D9EF",text:"#F8F8F2",muted:"#75715E",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",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",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",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",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",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",success:"#B4BE82",info:"#89B8C2",text:"#C6C8D1",muted:"#6B7089",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",success:"#C2D94C",info:"#95E6CB",text:"#B3B1AD",muted:"#626A73",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",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",success:"#ADDB67",info:"#7FDBCA",text:"#D6DEEB",muted:"#637777",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",success:"#55FF55",info:"#5555FF",text:"#C0C0C0",muted:"#808080",background:"#000000",panel:"#000000",element:"#000000",highlight:"#1A1A1A",inverse:"#000000",border:"#555555",borderActive:"#55FFFF"},voltage:{name:"voltage",primary:"#00E5FF",accent:"#FF3EA5",error:"#FF1744",warning:"#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",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",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",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",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",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",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:"#FFB020",accent:"#3DE0FF",error:"#FF5C7A",warning:"#FFD166",success:"#3DFF9A",info:"#3DE0FF",text:"#F7FAFD",muted:"#B7C3D0",background:"#070B10",panel:"#121A22",element:"#1C2833",highlight:"#243444",inverse:"#0A1016",border:"#334556",borderActive:"#FFB020"},ember:{name:"ember",primary:"#FF9F43",accent:"#2EE6FF",error:"#FF4D6D",warning:"#FFE566",success:"#3DFF9A",info:"#2EE6FF",text:"#F7F9FF",muted:"#B0B8CC",background:"#07090F",panel:"#12161F",element:"#1A2130",highlight:"#243044",inverse:"#0B0D12",border:"#334155",borderActive:"#FF9F43"}},rP={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"};iP=["#7AA2F7","#9ECE6A","#E0AF68","#BB9AF7","#2AC3DE","#FF9E64","#F7768E","#73DACA","#C0CAF5","#FF79C6","#7DCFFF","#C3E88D"],sP=["#2E5AAC","#3D7A1F","#9A6B12","#6B3FA0","#0E7A86","#B85C1A","#B4234A","#1A7A6D","#4A5080","#9A3480","#1565C0","#4A7C19"];vP={claude:{dark:"#E08A6A",light:"#B54328"},cursor:{dark:"#B8D4FF",light:"#1E4EBF"},kilo:{dark:"#F0C94A",light:"#8A6400"},codex:{dark:"#4ADE80",light:"#0B7A4B"}}});function hx(){return Vi()!==void 0}function gx(e){let t=e/1000;if(Number.isInteger(t))return`${t}s`;return`${e}ms`}function Qu(e,t,n){let r=e.indexOf(t),i=((r<0?0:r)+n+e.length)%e.length;return e[i]??e[0]}function vx(e,t){let n=[...yt],r=n.includes(e)?e:Xu;return Qu(n,r,t)}function yx(e,t){let n=[...wP],r=n.reduce((o,i)=>Math.abs(i-e)<Math.abs(o-e)?i:o,n[0]);return Qu(n,r,t)}function ls(e){let t=[...Yu];return t.reduce((n,r)=>Math.abs(r-e)<Math.abs(n-e)?r:n,t[0])}function Oc(e,t){return Qu([...Yu],ls(e),t)}function ds(e){let t=ls(e),n=mx[t]??mx[$r];return{px:t,...n}}function kn(e){return e.label==="compact"}function us(e){return e.steps<=2}function xx(e){return Yu.map((n,r)=>r<e?"\u2588":"\u2591").join(" ")}function Dc(e){return ds(e).label}function bx(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:Dc(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:gx(e.leaderMs),hint:"\u2190 \u2192 save",detail:`How long ctrl+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:pt,hint:"read-only",detail:Dt()},{id:"reset",group:"About",kind:"action",name:"Reset",value:"defaults",hint:"enter confirm reset",detail:`Restore theme ${Xu}, display ${Dc($r)}, mouse on, leader ${gx(Za)}. Enter asks first. ${t}`}]}function Zu(){return{theme:Xu,mouse:!0,leader_timeout:Za,font_size:$r}}function wx(e){return["Appearance","Input","MCP","About"].flatMap((n)=>{let r=e.filter((o)=>o.group===n);if(r.length===0)return[];return[{group:n,items:r}]})}function ep(e,t){if(e.length===0)return 0;return Math.min(Math.max(t,0),e.length-1)}function Ko(e,t){return e[ep(e,t)]}function tp(){return Vi()??ec()}var wP,Yu,Xu="devctl",mx;var Cn=D(()=>{Ye();Zt();wP=[1000,2000,3000],Yu=[12,14,16,18,20,22];mx={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 SP,useContext as kP}from"react";function se(){return kP(np)}var np;var at=D(()=>{Cn();Zt();np=SP(ds($r))});import{useEffect as CP,useRef as _P}from"react";import{jsxDEV as ae,Fragment as RP}from"@opentui/react/jsx-dev-runtime";function EP(e,t){switch(t){case"primary":return{bg:e.primary,fg:Br(e.primary,e.inverse)};case"accent":return{bg:e.accent,fg:Ac(e)?Tc:Br(e.accent,e.inverse)};case"success":return{bg:e.success,fg:Br(e.success,e.inverse)};case"warning":return{bg:e.warning,fg:Ac(e)?Tc:Br(e.warning,e.inverse)};case"error":return{bg:e.error,fg:Br(e.error,e.inverse)};case"info":return{bg:e.info,fg:Br(e.info,e.inverse)};case"muted":return{bg:e.element,fg:e.text};default:return{bg:e.element,fg:e.text}}}function Sx(e){let{palette:t,dir:n}=e;return ae("box",{width:2,height:1,flexShrink:0,overflow:"hidden",children:ae("text",{fg:t.muted,children:n==="left"?"\u2039":"\u203A"},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function je(e){let{palette:t,children:n,backgroundColor:r,edge:o="bottom"}=e,i=se(),s=e.ruled??!kn(i),a=r??t.element,c=ae("box",{flexShrink:0,flexDirection:"column",backgroundColor:a,overflow:"hidden",children:n},void 0,!1,void 0,this);if(!s)return c;return ae("box",{flexShrink:0,flexDirection:"column",overflow:"hidden",border:[...o==="both"?["top","bottom"]:[o]],borderStyle:"single",borderColor:t.border,children:c},void 0,!1,void 0,this)}function Mc(e){let{palette:t,items:n,active:r,width:o,onPick:i}=e,s=n.map((d)=>Vn(d.label)),a=$v(s,r,Math.max(1,o)),c=a.start>0,l=a.end>=0&&a.end<n.length-1;return ae("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[c?ae(Sx,{palette:t,dir:"left"},void 0,!1,void 0,this):null,n.map((d,f)=>{if(f<a.start||f>a.end)return null;let g=f===r;return ae(ge,{palette:t,label:d.label,tone:g?"primary":"muted",fg:g?void 0:d.color,onMouseDown:()=>i(f)},d.id,!1,void 0,this)}),l?ae(Sx,{palette:t,dir:"right"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function ge(e){let{palette:t,label:n,tone:r="idle",fg:o,bg:i,onMouseDown:s}=e,a=EP(t,r);return ae("box",{height:1,paddingLeft:1,paddingRight:1,backgroundColor:i??a.bg,overflow:"hidden",flexShrink:0,onMouseDown:s,children:ae("text",{fg:o??a.fg,children:n},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Oe(e){let{palette:t,hints:n}=e;return ae("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:n.map((r)=>ae("box",{height:1,paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:ae("text",{wrapMode:"none",children:[ae("span",{fg:t.primary,children:r.key},void 0,!1,void 0,this),ae("span",{fg:t.muted,children:` ${r.label}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},`${r.key}-${r.label}`,!1,void 0,this))},void 0,!1,void 0,this)}function Be(e){let{palette:t,items:n,hints:r,ruled:o=!0}=e,i=ae("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[n.map((s,a)=>ae(ge,{palette:t,label:s.text,tone:s.tone,onMouseDown:s.onMouseDown},`${s.text}-${a}`,!1,void 0,this)),r&&r.length>0?ae(RP,{children:[ae("box",{flexGrow:1,backgroundColor:t.element},void 0,!1,void 0,this),ae(Oe,{palette:t,hints:r},void 0,!1,void 0,this)]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this);if(!o)return i;return ae(je,{palette:t,backgroundColor:t.element,children:i},void 0,!1,void 0,this)}function qe(e){let{palette:t,title:n,termW:r,termH:o,preferW:i,preferH:s,anchor:a="center",borderColor:c,bottomTitle:l,gap:d,children:f}=e,g=kn(se()),m=No(r,o,i,s,a,!g);return ae("box",{position:"absolute",left:m.left,top:m.top,width:m.width,height:m.height,border:!0,borderStyle:rp,borderColor:c??t.borderActive,backgroundColor:t.panel,padding:g?0:1,title:n,titleColor:t.primary,bottomTitle:l,gap:g?0:d,flexDirection:"column",overflow:"hidden",children:f},void 0,!1,void 0,this)}function Te(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 We(e,t){if(!e)return;e.scrollBy({x:0,y:t})}function qo(e,t){let n=_P(null);return CP(()=>{let r=n.current;if(!r||e<0)return;let o=requestAnimationFrame(()=>{r.scrollChildIntoView(`${t}-${e}`)});return()=>cancelAnimationFrame(o)},[t,e]),n}function tt(e){let t=se(),n=us(t),r=e.scroll?ae("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Te(e.palette),children:ae("box",{flexDirection:"column",overflow:"hidden",children:e.children},void 0,!1,void 0,this)},void 0,!1,void 0,this):e.children;return ae("box",{flexGrow:1,border:!0,borderStyle:rp,borderColor:e.borderColor??e.palette.border,title:e.title,titleColor:e.palette.primary,paddingLeft:t.pad,paddingRight:t.pad,paddingTop:n?0:t.pad,paddingBottom:n?0:t.pad,backgroundColor:e.palette.panel,flexDirection:"column",overflow:"hidden",children:r},void 0,!1,void 0,this)}function Wr(e){let{palette:t,label:n,value:r,tone:o="text"}=e,i=se(),s=o==="success"?t.success:o==="warning"?t.warning:o==="error"?t.error:o==="muted"?t.muted:t.text;return ae("box",{height:i.rowH,flexDirection:"row",overflow:"hidden",children:[ae("box",{width:14,flexShrink:0,overflow:"hidden",children:ae("text",{fg:t.muted,children:n},void 0,!1,void 0,this)},void 0,!1,void 0,this),ae("box",{flexGrow:1,overflow:"hidden",children:ae("text",{fg:s,wrapMode:"none",children:r},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function $c(e){let{palette:t,title:n,body:r,hint:o}=e;return ae("box",{paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",border:!0,borderStyle:rp,borderColor:t.borderActive,titleColor:t.primary,children:[ae("text",{fg:t.primary,children:n},void 0,!1,void 0,this),ae("text",{fg:t.text,wrapMode:"word",children:r},void 0,!1,void 0,this),o?ae("text",{fg:t.muted,wrapMode:"word",children:o},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var rp="rounded";var be=D(()=>{at();Cn();Ye();Pe()});import{jsxDEV as de,Fragment as kx}from"@opentui/react/jsx-dev-runtime";function Cx(e){let{palette:t,cfg:n,snap:r,google:o,profile:i,reveal:s,width:a}=e,c=wc(r,n?Object.keys(n.services):void 0),l=r?.proxy.running===!0,d=o?.adcAvailable===!0,f=a<uc,g=ce(n?.project.name||"local",f?18:22),m=ce(i||r?.profile||"no profile",16),x=de(kx,{children:Jv({width:a,running:c.running,total:c.total,proxyOn:l,proxyAddress:r?.proxy.address??"",mcpOn:r?.mcp?.running===!0,adc:d,reveal:s}).filter((w)=>!w.hide&&w.label!=="").map((w)=>de(ge,{palette:t,label:w.label,tone:w.tone},w.label,!1,void 0,this))},void 0,!1,void 0,this),v=us(se());return de(je,{palette:t,backgroundColor:t.panel,ruled:!v,children:de("box",{height:f?2:1,flexDirection:"column",backgroundColor:t.panel,overflow:"hidden",children:[de("box",{height:1,flexDirection:"row",overflow:"hidden",children:[de(ge,{palette:t,label:Dt(),tone:"primary"},void 0,!1,void 0,this),de(ge,{palette:t,label:g,tone:"idle"},void 0,!1,void 0,this),de(ge,{palette:t,label:m,tone:"accent"},void 0,!1,void 0,this),f?null:de(kx,{children:[de("box",{flexGrow:1,backgroundColor:t.panel},void 0,!1,void 0,this),x]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),f?de("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.panel,children:x},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,screen:n,width:r,onSelect:o}=e,i=Jn.map((a)=>({id:a.id,label:Mv(a.label,r)})),s=Iv(n);return de(je,{palette:t,backgroundColor:t.element,children:de(Mc,{palette:t,items:i,active:s,width:r,onPick:(a)=>{let c=Jn[a];if(c)o(c.id)}},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Ex(e){let{palette:t,overlay:n,query:r,onQuery:o,onSubmit:i}=e;if(n==="slash"||n==="palette"){let c=n==="slash"?"/":"> ";return de(je,{palette:t,backgroundColor:t.highlight,edge:"top",children:de("box",{height:1,backgroundColor:t.highlight,paddingLeft:1,flexDirection:"row",overflow:"hidden",children:[de("box",{width:2,flexShrink:0,children:de("text",{fg:t.primary,children:c},void 0,!1,void 0,this)},void 0,!1,void 0,this),de("box",{flexGrow:1,overflow:"hidden",children:de("input",{focused:!0,value:r,placeholder:n==="slash"?"start auth":"filter commands",onInput:o,onSubmit:()=>i(r),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,!1,void 0,this)}let a=n==="leader"?[{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"}]:[{key:"/",label:"command"},{key:"ctrl+p",label:"palette"},{key:"ctrl+x",label:"leader"},{key:"?",label:"help"}];return de(je,{palette:t,backgroundColor:t.element,edge:"top",children:de("box",{height:1,backgroundColor:t.element,overflow:"hidden",children:de(Oe,{palette:t,hints:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Rx(e){let{palette:t,screen:n,overlay:r,status:o,paused:i,errorOnly:s,width:a,copyKey:c}=e,l=us(se()),d=Math.max(18,Math.floor(a*0.42)),f=Fo(Wy(n,r,c),d),g=Xv(o);return de(je,{palette:t,backgroundColor:t.panel,edge:"top",ruled:!l,children:de("box",{height:1,backgroundColor:t.panel,overflow:"hidden",children:de(Be,{ruled:!1,palette:t,items:[{text:n,tone:"primary"},{text:i?"PAUSED":"LIVE",tone:i?"warning":"success"},...s?[{text:"ERROR+",tone:"error"}]:[],...o===""?[]:[{text:ce(o,Math.max(16,a-d-28)),tone:g}]],hints:f},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function $e(e){return de("box",{flexGrow:1,padding:1,overflow:"hidden",children:de($c,{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 Ic(e){return de("box",{flexGrow:1,padding:1,overflow:"hidden",children:de("text",{fg:e.palette.text,children:e.label},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Px(e){return de("box",{flexGrow:1,padding:1,flexDirection:"column",overflow:"hidden",children:[de("text",{fg:e.palette.error,children:e.title},void 0,!1,void 0,this),de("text",{fg:e.palette.text,wrapMode:"word",children:e.body},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Et=D(()=>{at();Pe();be();Cn();Ye()});function PP(){if(process.platform==="darwin")return[["pbcopy"]];if(process.platform==="win32")return[["clip"]];return[["wl-copy"],["xclip","-selection","clipboard"],["xsel","--clipboard","--input"]]}function TP(){return PP().filter((e)=>{let t=e[0];return typeof t==="string"&&Bun.which(t)!==null})}function AP(e){return`\x1B]52;c;${Buffer.from(e,"utf8").toString("base64")}\x07`}function Tx(){if(process.platform==="linux")return"install wl-clipboard (Wayland) or xclip (X11)";return"no clipboard helper found"}async function op(e){let t=TP(),n;for(let r of t)try{await DP(r,e);return}catch(o){n=o instanceof Error?o:Error(String(o))}if(process.platform!=="win32")try{await LP(e);return}catch(r){n=r instanceof Error?r:Error(String(r))}throw ke(Je,"clipboard unavailable",n?`${Tx()} (${n.message})`:Tx())}async function LP(e){let t=AP(e);try{await Bun.write("/dev/tty",t)}catch{if(!process.stderr.write(t))throw Error("terminal clipboard write failed")}}async function DP(e,t){let n=Bun.spawn(e,{stdin:"pipe",stdout:"ignore",stderr:"ignore"});n.stdin.write(t),await n.stdin.end();let r=await n.exited;if(r!==0)throw Error(`${e[0]} exited ${r}`)}var Ax=D(()=>{Re()});function Lx(e){return e==="slash"||e==="palette"||e==="config-edit"}function Dx(e,t){return wn(e,t.keybinds.leader??"ctrl+x")}function Ox(e,t){return wn(e,t.keybinds.command_list??"ctrl+p")}function Mx(e,t){return wn(e,t.keybinds.command??"/")||e.name==="/"}function $x(e,t){return wn(e,t.keybinds.help??"?")||e.sequence==="?"}function Ix(e,t){return wn(e,t.keybinds.search??"f")}function Fx(e){let t=e.name??"";return t==="R"||e.shift===!0&&t.toLowerCase()==="r"}function Nx(e){return e.ctrl===!0&&(e.name??"").toLowerCase()==="l"}function Hx(e,t){if(t&&wn(e,t.keybinds.interrupt??"ctrl+c"))return!0;return e.ctrl===!0&&(e.name??"").toLowerCase()==="c"}function jx(e,t){return wn(e,t.keybinds.copy??bn())}function Bx(e,t,n=OP){return t>0&&e-t<=n}function Yn(e,t,n,r){return wn(e,t.keybinds[n]??r)}function Fc(e){let t=(e.name??"").toLowerCase();return t==="pagedown"||e.ctrl===!0&&t==="d"&&!e.meta}function Nc(e){let t=(e.name??"").toLowerCase();return t==="pageup"||e.ctrl===!0&&t==="u"&&!e.meta}var OP=2000;var Wx=D(()=>{Zt()});import{jsxDEV as Xn}from"@opentui/react/jsx-dev-runtime";function Gx(e){let{palette:t,path:n,initialValue:r,error:o,termW:i,termH:s,textareaRef:a}=e;return Xn(qe,{palette:t,title:"config buffer",bottomTitle:"ctrl+s save \xB7 esc discard \xB7 e still opens $EDITOR",termW:i,termH:s,preferW:88,preferH:28,gap:1,children:[Xn("box",{height:1,overflow:"hidden",children:Xn("text",{fg:t.muted,wrapMode:"none",children:n},void 0,!1,void 0,this)},void 0,!1,void 0,this),Xn("textarea",{ref:a,focused:!0,initialValue:r,backgroundColor:t.panel,focusedBackgroundColor:t.panel,textColor:t.text,focusedTextColor:t.text,cursorColor:t.primary},void 0,!1,void 0,this),o!==""?Xn("box",{height:2,overflow:"hidden",children:Xn("text",{fg:t.error,wrapMode:"word",children:o},void 0,!1,void 0,this)},void 0,!1,void 0,this):Xn("box",{height:1,overflow:"hidden",children:Xn("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 Ux=D(()=>{be()});import{jsxDEV as ip}from"@opentui/react/jsx-dev-runtime";function Kx(e){let{palette:t,title:n,body:r,termW:o,termH:i}=e;return ip(qe,{palette:t,title:n,bottomTitle:"enter confirm \xB7 esc stay",termW:o,termH:i,preferW:52,preferH:8,borderColor:t.warning,gap:1,children:[ip("text",{fg:t.text,wrapMode:"word",children:r},void 0,!1,void 0,this),ip(Oe,{palette:t,hints:[{key:"enter",label:"confirm"},{key:"esc",label:"stay"}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var qx=D(()=>{be()});import{jsxDEV as Rt,Fragment as MP}from"@opentui/react/jsx-dev-runtime";function Vx(e){let{palette:t,event:n,termW:r,termH:o,scrollRef:i}=e;if(!n)return null;let s=n.raw?Wv(n.raw):void 0,a=n.message.length>120||n.message.includes(`
|
|
626
|
-
`)||s!==void 0;return Rt(qe,{palette:t,title:"log details",bottomTitle:"j/k scroll \xB7 esc close",termW:r,termH:o,preferW:a?84:72,preferH:a?22:14,gap:1,children:Rt("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Te(t),children:Rt("box",{flexDirection:"column",overflow:"hidden",children:[Rt("text",{fg:t.text,wrapMode:"word",children:Io(n.message)},void 0,!1,void 0,this),Rt("text",{fg:t.muted,children:`time ${n.timestamp}`},void 0,!1,void 0,this),Rt("text",{fg:He(n.service,t),children:`service ${n.service}`},void 0,!1,void 0,this),Rt("text",{fg:t.muted,children:`source ${n.source}${n.stream?` / ${n.stream}`:""}`},void 0,!1,void 0,this),Rt("text",{fg:t.muted,children:`level ${hc(n.level)}`},void 0,!1,void 0,this),Rt("text",{fg:t.muted,children:`pid ${n.pid||"\u2014"}`},void 0,!1,void 0,this),Rt("text",{fg:t.muted,children:`request ${n.request_id||"\u2014"}`},void 0,!1,void 0,this),Rt("text",{fg:t.muted,children:`identity ${n.identity||"\u2014"}`},void 0,!1,void 0,this),s===void 0?null:Rt(MP,{children:[Rt("text",{fg:t.muted,children:"raw json"},void 0,!1,void 0,this),Rt("text",{fg:t.text,wrapMode:"word",children:s},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var Jx=D(()=>{be();Pe();Ye()});import{jsxDEV as we,Fragment as Yx}from"@opentui/react/jsx-dev-runtime";function WP(e){return[{key:"\u2190\u2192",label:"filter services"},{key:"1-9",label:"jump to source"},{key:"e",label:"ERROR+ only"},{key:"g",label:"jump to latest"},{key:"p",label:"pause stream"},{key:"z",label:"full-screen logs"},{key:"f",label:"search"},{key:"t",label:"timestamps"},{key:"m",label:"metadata"},{key:"w",label:"clip / wrap selected / wrap all"},{key:"j/k",label:"move and unfold"},{key:e,label:"copy visible logs"},{key:"/export",label:"write ~/.devctl/exports"},{key:"/exports",label:"open export folder"},{key:"ctrl+c \xD72",label:"quit"}]}function Zn(e){return e+FP}function Xx(e){let t=Zn(ap.length),n=Zn(cp.length),r=Zn(e.logCount),o=Zn(lp.length),i=Zn(dp.length),s=up+e.pad*2;if(e.stacked)return s+t+n+r+o+i+sp+(jP-1)*e.gap;let a=Math.max(t,n),c=Math.max(o,i);return s+a+r+c+sp+(BP-1)*e.gap}function GP(e){return Xx(e)-up-e.pad*2}function UP(e){return e-up*2<IP}function Qx(e){let{palette:t,termW:n,termH:r,copyKey:o=bn(),scrollRef:i}=e,s=kn(se()),a=UP(n),c=s?0:1,l=s?0:1,d=WP(o),f={stacked:a,logCount:d.length,pad:c,gap:l},g=Xx(f),m=GP(f);return we(qe,{palette:t,title:"help",bottomTitle:`${Dt()} \xB7 j/k scroll \xB7 esc close`,termW:n,termH:r,preferW:$P,preferH:g,gap:0,children:we("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Te(t),children:we("box",{height:m,flexDirection:"column",flexShrink:0,overflow:"hidden",gap:l,children:[a?we(Yx,{children:[we(Qn,{palette:t,title:"navigation",bindings:ap},void 0,!1,void 0,this),we(Qn,{palette:t,title:"services",bindings:cp},void 0,!1,void 0,this),we(Qn,{palette:t,title:"logs",bindings:d},void 0,!1,void 0,this),we(Qn,{palette:t,title:"commands",bindings:lp},void 0,!1,void 0,this),we(Qn,{palette:t,title:"display",bindings:dp},void 0,!1,void 0,this)]},void 0,!0,void 0,this):we(Yx,{children:[we(zx,{palette:t,left:{title:"navigation",bindings:ap},right:{title:"services",bindings:cp}},void 0,!1,void 0,this),we(Qn,{palette:t,title:"logs",bindings:d},void 0,!1,void 0,this),we(zx,{palette:t,left:{title:"commands",bindings:lp},right:{title:"display",bindings:dp}},void 0,!1,void 0,this)]},void 0,!0,void 0,this),we("box",{height:sp,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 zx(e){let{palette:t,left:n,right:r}=e,o=Math.max(Zn(n.bindings.length),Zn(r.bindings.length));return we("box",{height:o,flexDirection:"row",flexShrink:0,overflow:"hidden",gap:HP,children:[we(Qn,{palette:t,title:n.title,bindings:n.bindings,height:o,stretch:!0},void 0,!1,void 0,this),we(Qn,{palette:t,title:r.title,bindings:r.bindings,height:o,stretch:!0},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Qn(e){let{palette:t,title:n,bindings:r,stretch:o=!1}=e,i=e.height??Zn(r.length);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:n,titleColor:t.accent,children:r.map((s)=>we("box",{height:1,flexShrink:0,overflow:"hidden",paddingLeft:1,paddingRight:1,children:we(KP,{palette:t,binding:s},void 0,!1,void 0,this)},`${s.key}-${s.label}`,!1,void 0,this))},void 0,!1,void 0,this)}function KP(e){let{palette:t,binding:n}=e;return we("box",{height:1,flexDirection:"row",overflow:"hidden",children:[we("box",{width:NP,flexShrink:0,overflow:"hidden",children:we("text",{fg:t.primary,wrapMode:"none",children:n.key},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:n.label},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var $P=78,IP=56,FP=2,up=2,sp=1,pp=8,NP=16,HP=2,jP=6,BP=4,ap,cp,lp,dp;var Zx=D(()=>{at();be();Cn();Zt();ap=[{key:"tab",label:"next screen"},{key:"1-9,0",label:"jump to screen"},{key:"s/l/a/p/d/c/u",label:"letter jump (config, setup)"},{key:"j/k",label:"move selection"},{key:"esc",label:"back / close"}],cp=[{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"}];lp=[{key:"/",label:"slash command"},{key:"ctrl+p",label:"command palette"},{key:"ctrl+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"}],dp=[{key:"ctrl+=",label:"larger"},{key:"ctrl+-",label:"smaller"},{key:"?",label:"this overlay"}]});import{jsxDEV as eb}from"@opentui/react/jsx-dev-runtime";function tb(e){let{palette:t,termW:n,termH:r}=e,o=Uu();return eb(qe,{palette:t,title:"leader",termW:n,termH:r,preferW:68,preferH:5,anchor:"bottom",children:eb(Oe,{palette:t,hints:o},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var nb=D(()=>{Pe();be()});import{jsxDEV as rb}from"@opentui/react/jsx-dev-runtime";function ob(e){let{palette:t,items:n,selected:r,termW:o,termH:i,onIndex:s,onPick:a}=e,c=By(n),l=No(o,i,64,18,"center",!kn(se()));return rb(qe,{palette:t,title:"commands",bottomTitle:"enter select \xB7 esc close",termW:o,termH:i,preferW:64,preferH:18,children:rb("select",{height:Math.max(4,l.height-3),options:c,selectedIndex:r,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),onSelect:(d,f)=>{let g=f?.value;if(typeof g==="string"&&g!=="")a(g)}},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var ib=D(()=>{at();Pe();be();Cn()});import{jsxDEV as H}from"@opentui/react/jsx-dev-runtime";function fp(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 qP(e,t,n,r){if(t!=="")return{icon:"\u2717",label:"Failed",tone:"error",color:r.error};if(!e)return{icon:"\u2713",label:"Finished",tone:"success",color:r.success};if(n==="unhealthy")return{icon:"\u26A0",label:"Waiting on health",tone:"warning",color:r.warning};return{icon:"\u25CF",label:"Running",tone:"primary",color:r.primary}}function sb(e){return H("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:H("text",{wrapMode:"none",children:[H("span",{fg:e.palette.primary,children:e.label.toUpperCase()},void 0,!1,void 0,this),e.detail?H("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 ab(e){let{palette:t,plan:n,snap:r,busy:o,failed:i,kind:s,termW:a=80,termH:c=24,scrollRef:l,initiallyRunning:d=[],onDismiss:f}=e,g=new Set(d),m=n.waves.map((oe,Ue)=>({wave:oe.filter((Ee)=>!g.has(Ee)),waveIdx:Ue})).filter(({wave:oe})=>oe.length>0),x=Oy(n,r,s),v=n.waves[x.currentWaveIndex]??[],w=is(v,r,s),E=fp(w,t),k=qP(o,i,w,t),j=$y(s,o,i,n.profile),V=Iy(o,i),C=i?t.inverse:t.text,y=i?t.error:t.element,B=Math.min(92,Math.max(40,a-8)),h=B>=82?22:B>=66?17:13,q=12,I=9,z=B>=56,ue=B>=72,Ie=B<72||n.waves.length>3,ct=n.profile?`PROFILE ${n.profile}`:s.toUpperCase();return H(qe,{palette:t,title:j,bottomTitle:"enter close \xB7 esc hide (operation continues)",termW:a,termH:c,preferW:98,preferH:28,borderColor:k.color,gap:0,children:[H("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:[H(ge,{palette:t,label:`${k.icon} ${k.label.toUpperCase()}`,tone:k.tone},void 0,!1,void 0,this),H("box",{paddingLeft:1,flexGrow:1,overflow:"hidden",children:H("text",{fg:t.text,wrapMode:"none",children:ct},void 0,!1,void 0,this)},void 0,!1,void 0,this),H(ge,{palette:t,label:`${x.ready}/${x.total} READY`,tone:x.isComplete?"success":"info"},void 0,!1,void 0,this),H(ge,{palette:t,label:`WAVE ${Math.min(x.currentWaveIndex+1,Math.max(1,x.totalWaves))}/${Math.max(1,x.totalWaves)}`,tone:E.tone},void 0,!1,void 0,this)]},void 0,!0,void 0,this),H("box",{height:2,flexDirection:"column",overflow:"hidden",flexShrink:0,paddingLeft:1,paddingRight:1,children:[H("box",{height:1,flexDirection:"row",overflow:"hidden",children:[H("text",{wrapMode:"none",children:[H("span",{fg:t.muted,children:"PROGRESS "},void 0,!1,void 0,this),H("span",{fg:k.color,children:`[${x.progressBar}]`},void 0,!1,void 0,this),H("span",{fg:t.text,children:` ${x.percent}%`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),H("box",{flexGrow:1},void 0,!1,void 0,this),H("text",{wrapMode:"none",children:H("span",{fg:E.color,children:`${E.icon} ${E.label}`},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),H("box",{height:1,overflow:"hidden",children:H("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.":V.primary},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),H(sb,{palette:t,label:"Pipeline",detail:`${n.waves.length} execution wave${n.waves.length===1?"":"s"}`},void 0,!1,void 0,this),H("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:n.waves.map((oe,Ue)=>{let Ee=is(oe,r,s),Qe=fp(Ee,t),pe=Ie?`W${Ue+1} ${Qe.icon} ${oe.length}`:`W${Ue+1} ${Qe.icon} ${Qe.label} \xB7 ${oe.length}`;return H("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:[H(ge,{palette:t,label:pe,tone:Qe.tone},void 0,!1,void 0,this),Ue<n.waves.length-1?H("box",{width:3,flexShrink:0,overflow:"hidden",children:H("text",{fg:t.muted,children:" \u2500\u25BA"},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},`step-${Ue}`,!0,void 0,this)})},void 0,!1,void 0,this),(n.blockers??[]).length>0?H("box",{minHeight:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,paddingLeft:1,children:H("text",{fg:t.error,wrapMode:"word",children:`BLOCKED ${n.blockers?.map((oe)=>`${oe.name}: ${oe.message}`).join(" \xB7 ")}`},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,d.length>0?H("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,paddingLeft:1,children:H("text",{wrapMode:"none",children:[H("span",{fg:t.success,children:"\u2713 ALREADY READY"},void 0,!1,void 0,this),H("span",{fg:t.muted,children:` ${d.join(", ")}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this):null,H(sb,{palette:t,label:"Wave details",detail:"live process and health state"},void 0,!1,void 0,this),H("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,paddingLeft:1,children:[H("box",{width:2,flexShrink:0},void 0,!1,void 0,this),H("box",{width:h,flexShrink:0,overflow:"hidden",children:H("text",{fg:t.muted,children:ee("SERVICE",h)},void 0,!1,void 0,this)},void 0,!1,void 0,this),H("box",{width:12,flexShrink:0,overflow:"hidden",children:H("text",{fg:t.muted,children:ee("STATE",12)},void 0,!1,void 0,this)},void 0,!1,void 0,this),z?H("box",{width:9,flexShrink:0,overflow:"hidden",children:H("text",{fg:t.muted,children:ee("PORT",9)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,ue?H("box",{flexGrow:1,overflow:"hidden",children:H("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),H("scrollbox",{ref:l,focused:!1,stickyScroll:!1,scrollX:!1,style:Te(t),children:H("box",{flexDirection:"column",overflow:"hidden",gap:1,children:m.map(({wave:oe,waveIdx:Ue})=>{let Ee=is(oe,r,s),Qe=fp(Ee,t),pe=`${My(s,Ue,Ee)} \xB7 ${oe.length} service${oe.length===1?"":"s"}`;return H("box",{border:!0,borderStyle:"rounded",borderColor:Qe.color,title:pe,titleColor:Qe.color,flexDirection:"column",paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:oe.map((Se)=>{let It=r?.services[Se],N=Bt(It),Pt=Dy(Se,n,r,s),nt=Se===i||N==="FAILED",Ve=N==="UNHEALTHY",Wt=N==="HEALTHY"||s==="stop"&&N==="STOPPED",lt=jr(It),tr=nt?"\u2717":Wt?"\u2713":Ve?"\u26A0":N==="STARTING"||N==="RUNNING"||N==="STOPPING"||N==="RESTARTING"?"\u25CF":"\u25CB",mt=nt?t.error:De(t,N),on=nt?t.error:Ve?t.warning:Wt?t.success:t.muted;return H("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[H("box",{width:2,flexShrink:0,overflow:"hidden",children:H("text",{fg:mt,children:tr},void 0,!1,void 0,this)},void 0,!1,void 0,this),H("box",{width:h,flexShrink:0,overflow:"hidden",children:H("text",{fg:He(Se,t),wrapMode:"none",children:ee(Se,h)},void 0,!1,void 0,this)},void 0,!1,void 0,this),H("box",{width:12,flexShrink:0,overflow:"hidden",children:H("text",{fg:De(t,N),wrapMode:"none",children:ee(N,12)},void 0,!1,void 0,this)},void 0,!1,void 0,this),z?H("box",{width:9,flexShrink:0,overflow:"hidden",children:H("text",{fg:lt?t.info:t.muted,wrapMode:"none",children:ee(lt?`:${lt}`:"\u2014",9)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,ue?H("box",{flexGrow:1,overflow:"hidden",children:H("text",{fg:on,wrapMode:"none",children:Pt},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},Se,!0,void 0,this)})},`wave-card-${Ue}`,!1,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this),H("box",{height:3,flexShrink:0,flexDirection:"column",backgroundColor:y,border:["top"],borderStyle:"single",borderColor:k.color,paddingLeft:1,paddingRight:1,overflow:"hidden",onMouseDown:f,children:[H("text",{fg:C,wrapMode:"none",children:V.primary},void 0,!1,void 0,this),H("text",{fg:i?t.inverse:t.muted,wrapMode:"none",children:V.secondary},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var cb=D(()=>{Pe();be();Ye()});import{jsxDEV as tn}from"@opentui/react/jsx-dev-runtime";function lb(e){let{palette:t,route:n,termW:r,termH:o,scrollRef:i}=e;if(!n)return null;return tn(qe,{palette:t,title:n.name,bottomTitle:"j/k scroll \xB7 esc close",termW:r,termH:o,preferW:78,preferH:16,gap:1,children:tn("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Te(t),children:tn("box",{flexDirection:"column",overflow:"hidden",children:[tn("text",{fg:t.muted,children:`auth ${n.authType||"none"}`},void 0,!1,void 0,this),tn("text",{fg:t.muted,children:`identity ${n.identityType||"\u2014"}`},void 0,!1,void 0,this),tn("text",{fg:t.text,wrapMode:"word",children:`account ${n.serviceAccount||"\u2014"}`},void 0,!1,void 0,this),tn("text",{fg:t.text,wrapMode:"word",children:`audience ${n.audience||"\u2014"}`},void 0,!1,void 0,this),tn("text",{fg:t.muted,children:`match host ${n.matchHost||"*"}`},void 0,!1,void 0,this),tn("text",{fg:t.muted,children:`match path ${n.matchPath||"*"}`},void 0,!1,void 0,this),tn("text",{fg:t.text,wrapMode:"word",children:`upstream ${n.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 db=D(()=>{be()});import{jsxDEV as Hc}from"@opentui/react/jsx-dev-runtime";function ub(e){let{palette:t,title:n,body:r,termW:o,termH:i,scrollRef:s}=e,a=r.length>400||r.split(`
|
|
627
|
-
`).length>16;return Hc(qe,{palette:t,title:n,bottomTitle:"j/k scroll \xB7 esc close",termW:o,termH:i,preferW:a?88:76,preferH:a?24:16,gap:1,children:Hc("scrollbox",{ref:s,focused:!1,stickyScroll:!1,scrollX:!1,style:Te(t),children:Hc("box",{flexDirection:"column",overflow:"hidden",children:Hc("text",{fg:r===""?t.muted:t.text,wrapMode:"word",children:r===""?"(empty)":r},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 pb=D(()=>{be()});import{jsxDEV as $t}from"@opentui/react/jsx-dev-runtime";function gb(e){let{palette:t,items:n,query:r,selected:o,onQuery:i,onSubmit:s}=e,a=Gy(o,fb,n.length),c=n.slice(a,a+fb),l=Math.max(c.length,1),d=Hr(n,o);return $t("box",{height:l+3,flexShrink:0,border:!0,borderStyle:"rounded",borderColor:t.borderActive,titleColor:t.primary,backgroundColor:t.panel,title:"commands",flexDirection:"column",overflow:"hidden",children:[c.length===0?$t("box",{height:1,paddingLeft:1,overflow:"hidden",children:$t("text",{fg:t.muted,children:"no matching command"},void 0,!1,void 0,this)},void 0,!1,void 0,this):c.map((f)=>{let g=f.name===d?.name;return $t("box",{height:1,flexDirection:"row",overflow:"hidden",paddingLeft:1,paddingRight:1,backgroundColor:g?t.highlight:t.panel,children:[$t("box",{width:14,flexShrink:0,overflow:"hidden",children:$t("text",{fg:g?t.primary:t.text,wrapMode:"none",children:`${g?"\u203A":" "} /${f.name}`},void 0,!1,void 0,this)},void 0,!1,void 0,this),$t("box",{flexGrow:1,overflow:"hidden",children:$t("text",{fg:g?t.accent:t.muted,wrapMode:"none",children:f.desc},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},f.name,!0,void 0,this)}),$t("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.highlight,paddingLeft:1,children:[$t("box",{width:2,flexShrink:0,children:$t("text",{fg:t.primary,children:"/"},void 0,!1,void 0,this)},void 0,!1,void 0,this),$t("box",{flexGrow:1,overflow:"hidden",children:$t("input",{focused:!0,value:r,placeholder:"start auth",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 fb=8;var mb=D(()=>{Pe()});import{jsxDEV as yb}from"@opentui/react/jsx-dev-runtime";function xb(e){let{palette:t,themeName:n,selected:r,termW:o,termH:i,onIndex:s,onPreview:a,onPick:c}=e,l=yt.map((f)=>({name:f===n?`${f} (active)`:f,description:f===n?`${Ju[f]} \xB7 current`:Ju[f],value:f})),d=No(o,i,hb,vb,"center",!kn(se()));return yb(qe,{palette:t,title:"/themes",bottomTitle:"enter save \xB7 esc revert",termW:o,termH:i,preferW:hb,preferH:vb,children:yb("select",{height:Math.max(4,d.height-3),options:l,selectedIndex:r,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:(f)=>{s(f);let g=yt[f];if(g)a(g)},onSelect:(f,g)=>{let m=g?.value;if(typeof m==="string"&&m!=="")c(m)}},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var hb=52,vb=22;var bb=D(()=>{at();Pe();be();Cn();Ye()});import{jsxDEV as Ge}from"@opentui/react/jsx-dev-runtime";function jc(e){let{palette:t,title:n,tone:r="muted",children:o}=e,i=r==="success"?t.success:r==="warning"?t.warning:r==="error"?t.error:t.border;return Ge("box",{border:!0,borderStyle:"rounded",borderColor:i,title:n,titleColor:i,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,marginBottom:1,overflow:"hidden",children:o},void 0,!1,void 0,this)}function wb(e){let{palette:t,cfg:n,google:r,identity:o}=e;if(!r&&!o)return Ge(Ic,{palette:t,label:"Checking Application Default Credentials\u2026"},void 0,!1,void 0,this);let i=VP(n,o),s=o?.user||r?.userEmail||"",{project:a,source:c}=Go(n,o,r),l=o?.adc??r?.adcAvailable===!0,d=o?.iap??(n?.proxy.routes??[]).some((v)=>v.auth.type.toLowerCase()==="iap"),f=i.filter((v)=>v.inactive!==!0),g=f.some((v)=>v.ok===!0),m=f.some((v)=>v.ok===!1),x=g?"AVAILABLE":m?"UNAVAILABLE":f.length>0?"NOT PROBED":i.length>0?"not required":"not configured";return Ge(tt,{palette:t,title:"identity",scroll:!0,children:[Ge(jc,{palette:t,title:"Google identity",tone:l?"success":"warning",children:[Ge(Wr,{palette:t,label:"user",value:s||"(unknown)"},void 0,!1,void 0,this),Ge(Wr,{palette:t,label:"project",value:a||"(unset)"},void 0,!1,void 0,this),Ge(Wr,{palette:t,label:"source",value:c||"\u2014"},void 0,!1,void 0,this),Ge(Wr,{palette:t,label:"ADC",value:l?"\u2713 available":"\u2717 missing",tone:l?"success":"error"},void 0,!1,void 0,this),Ge(Wr,{palette:t,label:"gcloud",value:r?.gcloudInstalled?"\u2713 installed":"\u2717 not installed",tone:r?.gcloudInstalled?"success":"error"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Ge(jc,{palette:t,title:`Service accounts (${i.length})`,tone:f.length===0?"muted":g?"success":"warning",children:[i.length===0?Ge("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((v)=>Ge("text",{fg:v.inactive?t.muted:v.ok===!0?t.success:v.ok===!1?t.error:t.text,wrapMode:"none",children:`${v.inactive?"\u2013":v.ok===!0?"\u2713":v.ok===!1?"\u2717":"\u25CB"} ${v.email}${v.inactive?" \u2014 inactive (route auth is none)":""}`},v.email,!1,void 0,this)),Ge("box",{height:1,flexShrink:0},void 0,!1,void 0,this),Ge(Wr,{palette:t,label:"impersonation",value:x,tone:g?"success":f.length>0?"warning":"muted"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Ge(jc,{palette:t,title:"IAP",tone:d?"success":"muted",children:[Ge("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:Ge(ge,{palette:t,label:d?"routes present":"no IAP routes",tone:d?"success":"idle"},void 0,!1,void 0,this)},void 0,!1,void 0,this),d?Ge("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),!l?Ge(jc,{palette:t,title:"ADC unavailable",tone:"warning",children:[Ge("text",{fg:t.text,wrapMode:"word",children:"Local services still start. Cloud identity, impersonation, and IAP need ADC."},void 0,!1,void 0,this),Ge("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 VP(e,t){let n=new Map((e?gd(e):[]).map((i)=>[i.email,i.active])),r=t?.service_account_status??{};return[...new Set([...n.keys(),...Object.keys(r)])].sort((i,s)=>i.localeCompare(s)).map((i)=>{let s=r[i]??"unknown",a=n.get(i)===!1;return{email:i,inactive:a,ok:a||s==="unknown"?void 0:s==="available"}})}var Sb=D(()=>{Et();Pe();be();wr()});import{jsxDEV as ft}from"@opentui/react/jsx-dev-runtime";function kb(e){let{palette:t,credentials:n}=e;if(!n)return ft(Ic,{palette:t,label:"Reading credential store\u2026"},void 0,!1,void 0,this);let r=n.entries.filter((i)=>i.valid).length,o=n.entries.length-r;return ft(tt,{palette:t,title:"credentials",scroll:!0,children:[ft("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[ft(ge,{palette:t,label:`backend: ${n.backend}`,tone:"info"},void 0,!1,void 0,this),n.entries.length>0?ft(ge,{palette:t,label:`${r} valid`,tone:"success"},void 0,!1,void 0,this):null,o>0?ft(ge,{palette:t,label:`${o} expired`,tone:"warning"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),ft("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),ft("box",{height:1,flexShrink:0},void 0,!1,void 0,this),n.entries.length===0?ft("text",{fg:t.muted,children:"no cached credentials"},void 0,!1,void 0,this):ft("box",{flexDirection:"column",overflow:"hidden",gap:1,children:n.entries.map((i)=>ft("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:[ft("text",{wrapMode:"none",children:[ft("span",{fg:i.valid?t.success:t.warning,children:i.valid?"\u2713 valid":"\u2717 expired"},void 0,!1,void 0,this),ft("span",{fg:t.muted,children:` \xB7 expires ${i.expires_at}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ft("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),ft($c,{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 Cb=D(()=>{Et();be()});import{jsxDEV as A}from"@opentui/react/jsx-dev-runtime";function Pb(e){let{palette:t,cfg:n,width:r}=e,o=se();if(!n)return A($e,{palette:t,title:"No configuration",body:"Create .devctl/config.yaml or run setup."},void 0,!1,void 0,this);let i=Math.max(Uo+8,r-6-o.pad*2),s=i>=dx,a=s?Math.floor((i-Eb)/2):i,c=nx(n),l=rx(n),d=ox(n),f=ix(n),g=sx(n);return A(tt,{palette:t,title:`config ${n.project.name||"unnamed"}`,children:[A(Be,{palette:t,items:Yy(n)},void 0,!1,void 0,this),A("box",{flexGrow:1,overflow:"hidden",children:A("scrollbox",{ref:e.scrollRef,focused:!1,stickyScroll:!1,scrollX:!1,style:Te(t),children:A("box",{flexDirection:"column",overflow:"hidden",gap:Rb,children:[A(gp,{wide:s,left:A(nn,{palette:t,title:"project",children:A(Vo,{palette:t,facts:Xy(n,pt),width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:A(nn,{palette:t,title:"google",children:A(Vo,{palette:t,facts:Qy(n),width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),A(gp,{wide:s,left:A(nn,{palette:t,title:"runtime",children:A(Vo,{palette:t,facts:Zy(n),width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:A(nn,{palette:t,title:"logs",children:A(Vo,{palette:t,facts:ex(n),width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),A(nn,{palette:t,title:`proxy ${n.proxy.enabled?"enabled":"disabled"}`,children:[A(Vo,{palette:t,facts:tx(n),width:i},void 0,!1,void 0,this),A(zP,{palette:t,routes:l,width:i},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A(nn,{palette:t,title:`services ${c.length}`,children:A(JP,{palette:t,rows:c,width:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),A(nn,{palette:t,title:`tasks ${g.length}`,children:A(_b,{palette:t,rows:g,empty:"no tasks",width:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),A(gp,{wide:s,left:A(nn,{palette:t,title:`profiles ${d.length}`,children:A(YP,{palette:t,rows:d,width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:A(nn,{palette:t,title:`templates ${f.length}`,children:A(_b,{palette:t,rows:f,empty:"no templates",width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),A(nn,{palette:t,title:"extras",children:A(Vo,{palette:t,facts:cx(n),width:i},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),A(je,{palette:t,backgroundColor:t.element,edge:"top",children:A(Oe,{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:"j/k",label:"scroll"}]},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function gp(e){let{wide:t,left:n,right:r}=e;if(!t)return A("box",{flexDirection:"column",overflow:"hidden",gap:Rb,flexShrink:0,children:[n,r]},void 0,!0,void 0,this);return A("box",{flexDirection:"row",overflow:"hidden",gap:Eb,flexShrink:0,children:[A("box",{flexGrow:1,flexBasis:0,overflow:"hidden",children:n},void 0,!1,void 0,this),A("box",{flexGrow:1,flexBasis:0,overflow:"hidden",children:r},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function nn(e){let{palette:t,title:n,children:r}=e;return A("box",{border:!0,borderStyle:"rounded",borderColor:t.border,title:n,titleColor:t.accent,paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",flexShrink:0,children:r},void 0,!1,void 0,this)}function Vo(e){let{palette:t,facts:n,width:r}=e,o=Math.max(4,r-Uo-4);return A("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:n.map((i)=>A("box",{height:1,flexDirection:"row",overflow:"hidden",children:[A("box",{width:Uo,flexShrink:0,overflow:"hidden",children:A("text",{fg:t.muted,wrapMode:"none",children:ee(i.label,Uo)},void 0,!1,void 0,this)},void 0,!1,void 0,this),A("box",{width:o,flexShrink:0,overflow:"hidden",children:A("text",{fg:ZP(t,i.tone),wrapMode:"none",children:ee(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 JP(e){let{palette:t,rows:n,width:r}=e;if(n.length===0)return A(Bc,{palette:t,text:"no services"},void 0,!1,void 0,this);let o=lx(n),i=Math.max(8,r-o-6);return A("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:n.map((s)=>A("box",{height:1,flexDirection:"row",overflow:"hidden",children:[A("box",{width:o,flexShrink:0,overflow:"hidden",children:A("text",{fg:He(s.name,t),wrapMode:"none",children:ee(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),A("box",{width:i,flexShrink:0,overflow:"hidden",children:A("text",{fg:t.text,wrapMode:"none",children:ce(XP(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 zP(e){let{palette:t,routes:n,width:r}=e;if(n.length===0)return A(Bc,{palette:t,text:"no routes"},void 0,!1,void 0,this);let o=Math.min(Uo+4,Math.max(8,...n.map((s)=>s.name.length))),i=Math.max(8,r-o-6);return A("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:n.map((s)=>A("box",{height:1,flexDirection:"row",overflow:"hidden",children:[A("box",{width:o,flexShrink:0,overflow:"hidden",children:A("text",{fg:t.primary,wrapMode:"none",children:ee(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),A("box",{width:i,flexShrink:0,overflow:"hidden",children:A("text",{fg:t.text,wrapMode:"none",children:ce(QP(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 YP(e){let{palette:t,rows:n,width:r}=e;if(n.length===0)return A(Bc,{palette:t,text:"no profiles"},void 0,!1,void 0,this);let o=Math.min(12,Math.max(8,...n.map((s)=>s.name.length))),i=Math.max(8,r-o-6);return A("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:n.map((s)=>A("box",{height:1,flexDirection:"row",overflow:"hidden",children:[A("box",{width:o,flexShrink:0,overflow:"hidden",children:A("text",{fg:t.primary,wrapMode:"none",children:ee(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),A("box",{width:i,flexShrink:0,overflow:"hidden",children:A("text",{fg:t.text,wrapMode:"none",children:ce(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 _b(e){let{palette:t,rows:n,empty:r,width:o}=e;if(n.length===0)return A(Bc,{palette:t,text:r},void 0,!1,void 0,this);let i=Math.min(14,Math.max(8,...n.map((a)=>a.name.length))),s=Math.max(8,o-i-6);return A("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:n.map((a)=>A("box",{height:1,flexDirection:"row",overflow:"hidden",children:[A("box",{width:i,flexShrink:0,overflow:"hidden",children:A("text",{fg:t.text,wrapMode:"none",children:ee(a.name,i)},void 0,!1,void 0,this)},void 0,!1,void 0,this),A("box",{width:s,flexShrink:0,overflow:"hidden",children:A("text",{fg:t.muted,wrapMode:"none",children:ce(a.summary,s)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},a.name,!0,void 0,this))},void 0,!1,void 0,this)}function Bc(e){return A("box",{height:1,overflow:"hidden",children:A("text",{fg:e.palette.muted,wrapMode:"none",children:e.text},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function XP(e){let t=e.extends==="\u2014"?"":` ${e.extends}`;return` ${e.ports} ${e.identity} ${e.health} ${e.restart} \u2190 ${e.depends}${t}`}function QP(e){return` ${e.auth} ${e.identity} ${e.match} \u2192 ${e.upstream}`}function ZP(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 Eb=1,Rb=1;var Tb=D(()=>{Et();Ku();at();Pe();be();Ye()});import{useRef as eT}from"react";import{jsxDEV as me}from"@opentui/react/jsx-dev-runtime";function Wc(e){let{palette:t,names:n,snap:r,selected:o,checked:i,width:s,onOpen:a,onSelectIndex:c,onToggle:l}=e,d=se(),f=eT(!1),g=new Set(i),m=Fu(s),x=Iu(s),v=$u(s),w=Fv(s);return me("box",{flexDirection:"column",flexGrow:1,overflow:"hidden",children:[me("box",{height:1,flexDirection:"row",overflow:"hidden",children:[me(xt,{width:2,fg:t.muted,text:""},void 0,!1,void 0,this),me(xt,{width:4,fg:t.accent,text:"sel"},void 0,!1,void 0,this),me(xt,{width:2,fg:t.muted,text:""},void 0,!1,void 0,this),me(xt,{width:w,fg:t.muted,text:"name"},void 0,!1,void 0,this),me(xt,{width:vt,fg:t.muted,text:""},void 0,!1,void 0,this),me(xt,{width:en,fg:t.muted,text:"state"},void 0,!1,void 0,this),v?me(xt,{width:Sn,fg:t.muted,text:"health"},void 0,!1,void 0,this):null,x?me(xt,{width:ac,fg:t.muted,text:"port"},void 0,!1,void 0,this):null,m?me(xt,{width:zn,fg:t.muted,text:"pid"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),n.map((E,k)=>{let j=r?.services[E],V=Bt(j),C=j?.health??"UNKNOWN",y=g.has(E),B=k===o,h=y?"[x]":"[ ]",q=B?"\u203A":" ";return me("box",{height:d.rowH,flexDirection:"row",overflow:"hidden",backgroundColor:B?t.highlight:y?t.element:void 0,onMouseDown:()=>{if(f.current)return;if(B){a(E);return}c(k)},children:[me("box",{width:2,flexShrink:0,children:me("text",{fg:t.primary,children:q},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("box",{width:4,flexShrink:0,onMouseDown:()=>{f.current=!0,l?.(E),setTimeout(()=>{f.current=!1},0)},children:me("text",{fg:tT(t,y,B),children:h},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("box",{width:2,flexShrink:0,children:me("text",{fg:De(t,V),children:Mt(V)},void 0,!1,void 0,this)},void 0,!1,void 0,this),me(xt,{width:w,fg:B?t.primary:He(E,t),text:ee(E,w)},void 0,!1,void 0,this),me(xt,{width:vt,fg:t.muted,text:""},void 0,!1,void 0,this),me(xt,{width:en,fg:De(t,V),text:V},void 0,!1,void 0,this),v?me(xt,{width:Sn,fg:De(t,C),text:C},void 0,!1,void 0,this):null,x?me(xt,{width:ac,fg:t.text,text:jr(j)},void 0,!1,void 0,this):null,m?me(xt,{width:zn,fg:t.text,text:j?.pid?String(j.pid):""},void 0,!1,void 0,this):null]},E,!0,void 0,this)})]},void 0,!0,void 0,this)}function Gc(e){let{palette:t,checked:n,idle:r,profileName:o}=e,i=n.length;if(i>0)return me(Be,{palette:t,items:[{text:`${i} selected`,tone:"primary"}],hints:[{key:"space",label:"unmark"},{key:"*",label:"all"},{key:"-",label:"none"},{key:"n",label:"start these"},{key:"x",label:"stop these"}]},void 0,!1,void 0,this);if(r)return me(Be,{palette:t,items:[{text:"none started",tone:"idle"}],hints:[{key:"space",label:"select"},{key:"enter",label:o?`start ${o}`:"open"},{key:"n",label:"start"}]},void 0,!1,void 0,this);return me(Be,{palette:t,items:[{text:"running",tone:"success"}],hints:[{key:"space",label:"select"},{key:"n",label:"start"},{key:"x",label:"stop"}]},void 0,!1,void 0,this)}function tT(e,t,n){if(t)return e.success;if(n)return e.primary;return e.muted}function xt(e){return me("box",{width:e.width,flexShrink:0,overflow:"hidden",children:me("text",{fg:e.fg,wrapMode:"none",children:e.text},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var mp=D(()=>{Pe();at();be();Ye()});import{useEffect as hp,useRef as Ab}from"react";import{jsxDEV as Y,Fragment as aT}from"@opentui/react/jsx-dev-runtime";function Lb(e){let{palette:t,logs:n,names:r,logSources:o,service:i,paused:s,errorOnly:a,showSystemLogs:c,search:l,searchFocused:d,followTick:f,width:g,onSearch:m,onService:x,onToggleErrors:v,onToggleSystemLogs:w,onClearLogs:E,onSelect:k,wrapMode:j="focus",selected:V=-1,follow:C=!0,newer:y=0,viewStart:B=0,viewTotal:h,onLeaveLatest:q,onOpenExports:I,onJumpLatest:z,view:ue,fullscreen:Ie=!1,facets:ct}=e,oe=se(),Ue=Bv(g,oe.pad,Ie),Ee=c?n:n.filter((Ve)=>!ns(Ve.source)),Qe=Wo(n,{service:i,services:e.services,errorOnly:a,search:l,regex:e.regex,source:e.source,systemLogs:c}),pe=ue??Qe,Se=h??Qe.length,It=Math.min(Se,B+pe.length),N=Se===0?"empty":`${B+1}\u2013${It} of ${Se}`,Pt=e.services??[],nt=Pt.length>0?Pt.join(","):i===""?"all services":i;return Y("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[Ie?null:Y(aT,{children:[Y(Be,{palette:t,items:[{text:s?"PAUSED":"LIVE",tone:s?"warning":"success"},{text:`shown ${Se}`,tone:"info"},{text:ct?`total ${ct.total}`:`total ${n.length}`},...ue&&Se>ue.length?[{text:`${B+1}\u2013${B+ue.length} / ${Se}`,tone:"info"}]:[],{text:nt,tone:i===""?"idle":"primary"},{text:Qi(j),tone:j==="clip"?"idle":"accent"},...C?[]:[{text:y>0?`pinned \xB7 +${y} new`:"pinned",tone:"warning"}],{text:a?"ERROR+":"all levels",tone:a?"error":"idle",onMouseDown:v},{text:c?"system: on":"system: off",tone:c?"accent":"idle",onMouseDown:w},...e.source?[{text:`src ${e.source}`,tone:"info"}]:[],...e.regex?[{text:"regex",tone:"accent"}]:[],...l===""?[]:[{text:`search ${l}`,tone:"accent"}],{text:"clear",tone:"muted",onMouseDown:E},{text:"open folder",tone:"primary",onMouseDown:I}]},void 0,!1,void 0,this),Y(xp,{palette:t,logs:Ee,names:o??r,service:i,errorOnly:a,width:g,onService:x,onToggleErrors:v,facets:ct},void 0,!1,void 0,this)]},void 0,!0,void 0,this),d?Y("box",{height:1,paddingLeft:1,backgroundColor:t.highlight,overflow:"hidden",children:Y("input",{focused:!0,value:l,placeholder:"search messages or service names",onInput:m,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,ue&&Se>pe.length?Y(vp,{palette:t,start:B,count:pe.length,total:Se},void 0,!1,void 0,this):null,Y("box",{flexGrow:1,border:!Ie,borderStyle:"rounded",borderColor:t.border,title:Ie?void 0:`logs ${nt} \xB7 ${N}`,titleColor:t.primary,padding:Ie?0:oe.pad,overflow:"hidden",children:pe.length===0?Y($e,{palette:t,title:n.length===0?"No log events":"No events in this filter",body:n.length===0?"Start services to stream logs.":"Pick All, another service, or clear search / ERROR+.",hint:"\u2190 \u2192 cycle filters 1-9 pick a source e errors i internal ctrl+l clear"},void 0,!1,void 0,this):Y(bp,{palette:t,logs:pe,width:Ue,followTick:f,focused:!1,wrapMode:j,selected:V,follow:C,showTimestamps:e.showTimestamps!==!1,showMeta:e.showMeta!==!1,onPick:k,onLeaveLatest:q,viewStart:B},f,!1,void 0,this)},void 0,!1,void 0,this),Y(je,{palette:t,backgroundColor:t.element,edge:"top",children:Y(Oe,{palette:t,hints:Fo([{key:"\u2190\u2192",label:"filter"},{key:"1-9",label:"source"},{key:"e",label:"errors"},{key:"i",label:c?"internal off":"internal on"},{key:"ctrl+l",label:"clear"},{key:"f",label:"search"},{key:"j/k",label:"move"},{key:"enter",label:"details"},{key:"g",label:y>0?`latest +${y}`:"latest"},{key:"w",label:"wrap"},{key:"p",label:"pause"},{key:"z",label:Ie?"exit full":"full screen"},{key:"t",label:e.showTimestamps===!1?"time off":"time"},{key:"m",label:e.showMeta===!1?"meta off":"meta"},{key:"pgup/pgdn",label:"history"},{key:"/exports",label:"open folder"}],Math.max(20,g-2))},void 0,!1,void 0,this)},void 0,!1,void 0,this),!C?Y(yp,{palette:t,width:g,newer:y,onJump:z},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function vp(e){let t=Math.min(e.total,e.start+e.count),n=Math.max(0,e.start),r=Math.max(0,e.total-t);return Y(Be,{palette:e.palette,items:[{text:`view ${e.start+1}\u2013${t} of ${e.total}`,tone:"primary"},{text:n>0?`\u2191 ${n} older`:"start of history",tone:n>0?"info":"idle"},{text:r>0?`\u2193 ${r} newer`:"at latest",tone:r>0?"warning":"success"}],hints:[{key:"pgup/pgdn",label:"move history window"},{key:"g",label:"latest"}]},void 0,!1,void 0,this)}function yp(e){let t=e.newer>0?`g jump to latest \xB7 ${e.newer} new`:"g jump to latest",n=Math.min(e.width,t.length+4);return Y("box",{position:"absolute",left:Math.max(0,Math.floor((e.width-n)/2)),bottom:e.bottom??2,width:n,height:3,border:!0,borderStyle:"rounded",borderColor:e.palette.warning,backgroundColor:e.palette.panel,alignItems:"center",justifyContent:"center",onMouseDown:e.onJump,children:Y("text",{wrapMode:"none",children:[Y("span",{fg:e.palette.primary,children:"g"},void 0,!1,void 0,this),Y("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)}function xp(e){let{palette:t,logs:n,names:r,service:o,errorOnly:i,width:s,onService:a,onToggleErrors:c,facets:l}=e,d=l?Py(r,l):Ry(r,n),f=s<80,g=d.map((w,E)=>{let k=E+1,j=w.name===""?"all":w.name;return{id:j,label:f?`${k} ${j}`:`${k} ${j} \xB7 ${w.count}`,color:He(w.name,t)}}),m=Math.max(0,d.findIndex((w)=>w.name===o)),x=i?"ERROR+":f?"lvls":"all levels",v=Math.max(Vn(g[m]?.label??"1 all"),s-Vn(x));return Y(je,{palette:t,backgroundColor:t.element,children:Y("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[Y("box",{flexGrow:1,overflow:"hidden",children:Y(Mc,{palette:t,items:g,active:m,width:v,onPick:(w)=>{let E=d[w];if(E)a(E.name)}},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y(ge,{palette:t,label:x,tone:i?"error":"muted",onMouseDown:c},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function bp(e){let{palette:t,logs:n,limit:r,width:o=80,followTick:i=0,focused:s=!1,wrapMode:a="clip",selected:c=-1,follow:l=!0,showTimestamps:d=!0,showMeta:f=!0,onPick:g,onLeaveLatest:m,viewStart:x=0}=e,v=Ab(null),w=Ab(""),E=r===void 0?n:n.slice(-r),k=[...new Set(n.map((C)=>C.service))],j=zv(o,k),V=Vv({width:o,serviceWidth:j,showTimestamps:d,showMeta:f});return hp(()=>{let C=v.current;if(!C)return;if(C.stickyScroll=l,l)C.stickyStart="bottom",C.scrollTo({x:C.scrollLeft,y:Math.max(0,C.scrollHeight)})},[l,i]),hp(()=>{let C=`${x}:${c}:${a}`;if(w.current===C)return;if(w.current=C,l&&(c<0||c>=E.length-1))return;let y=v.current;if(!y||c<0)return;let B=`log-row-${c}`,h=requestAnimationFrame(()=>{y.stickyScroll=!1,y.scrollChildIntoView(B)});return()=>cancelAnimationFrame(h)},[l,c,E.length,x,a]),hp(()=>{if(!l||!m)return;let C=!1,y=setTimeout(()=>{C=!0},nT),B=setInterval(()=>{let h=v.current;if(!C||!h)return;let q=h.viewport.height;if(q>0&&h.scrollTop+q<h.scrollHeight-oT)m()},rT);return()=>{clearTimeout(y),clearInterval(B)}},[l,i,m]),Y("box",{flexGrow:1,height:"100%",overflow:"hidden",children:Y("scrollbox",{ref:v,focused:s,stickyScroll:l,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:Y("box",{flexDirection:"column",overflow:"hidden",children:E.map((C,y)=>Y(iT,{id:`log-row-${y}`,palette:t,event:C,serviceWidth:j,msgWidth:V,expanded:Uv(a,y===c),active:y===c,showTimestamps:d,showMeta:f,onPick:g?()=>g(y):void 0},`${C.timestamp}-${C.service}-${y}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function iT(e){let{id:t,palette:n,event:r,serviceWidth:o,msgWidth:i,expanded:s,active:a,showTimestamps:c=!0,showMeta:l=!0,onPick:d}=e,f=Gv(vc(r.message,i),i,s);return Y("box",{id:t,flexShrink:0,flexDirection:"column",overflow:"hidden",backgroundColor:a?n.highlight:void 0,onMouseDown:d,children:f.visible.map((g,m)=>Y("box",{height:1,flexDirection:"row",overflow:"hidden",children:[c?Y("box",{width:gc,flexShrink:0,overflow:"hidden",children:Y("text",{fg:n.muted,children:m===0?r.timestamp.slice(11,19):""},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,Y("box",{width:o,flexShrink:0,overflow:"hidden",children:Y("text",{fg:m===0?He(r.service,n):n.muted,wrapMode:"none",children:m===0?ee(r.service,o):""},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:Xi,flexShrink:0,overflow:"hidden",children:Y("text",{children:" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{width:mc,flexShrink:0,overflow:"hidden",children:Y("text",{fg:m===0?De(n,r.level):n.muted,children:m===0?hc(String(r.level)):""},void 0,!1,void 0,this)},void 0,!1,void 0,this),l?Y("box",{width:pc,flexShrink:0,overflow:"hidden",children:Y("text",{fg:n.muted,children:m===0&&r.source?ee(r.source,pc):""},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,Y("box",{width:Xi,flexShrink:0,overflow:"hidden",children:Y("text",{fg:n.muted,children:m===0?" ":"\u2502"},void 0,!1,void 0,this)},void 0,!1,void 0,this),Y("box",{flexGrow:1,overflow:"hidden",children:Y(sT,{palette:n,level:r.level,text:g,mark:m===0?f.mark:""},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},`${r.timestamp}-${m}`,!0,void 0,this))},void 0,!1,void 0,this)}function sT(e){let{palette:t,level:n,text:r,mark:o}=e;return Y("text",{wrapMode:"none",children:[qv(r).map((i,s)=>Y("span",{fg:fx(t,n,i.kind),children:i.text},`${i.kind}-${s}`,!1,void 0,this)),o===""?null:Y("span",{fg:t.muted,children:o},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var nT=400,rT=200,oT=2;var wp=D(()=>{Et();at();Pe();be();Ye()});import{jsxDEV as ne}from"@opentui/react/jsx-dev-runtime";function Ob(e){let{palette:t,cfg:n,snap:r,logs:o,names:i,selected:s,selectedLog:a=-1,checked:c,profile:l,google:d,width:f,paused:g,followTick:m,logService:x,logSources:v,errorOnly:w,showSystemLogs:E,onOpen:k,onSelectIndex:j,onToggle:V,onFilterService:C,onToggleErrors:y,onToggleSystemLogs:B,onClearLogs:h,onShowErrors:q,wrapMode:I="clip",view:z,follow:ue=!0,onLeaveLatest:Ie,onPickLog:ct,viewStart:oe=0,viewTotal:Ue,newer:Ee=0,onJumpLatest:Qe,facets:pe,leftover:Se}=e,It=se();if(!n||i.length===0)return ne($e,{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 N=f<$o,Pt=Bo(r),nt=wc(r,i),Ve=i.filter((zo)=>r?.services[zo]?.state==="FAILED").length,Wt=r?.session_id?js(r.session_id):void 0,lt=Wt?jo(Date.now()-Wt.getTime()):void 0,tr=Cy(o),mt=l||xc(n),on=Vy(n,mt),sn=Pt?Ky(Se,r?.session_id):void 0,an=yc(f,i,N),Ur=Math.max(24,N?f-4:f-an-4),_=E?o:o.filter((zo)=>!ns(zo.source)),cn=Wo(o,{service:x,errorOnly:w,systemLogs:E}),Rn=z??cn,Jt=Ue??cn.length,Xc=Math.min(Jt,oe+Rn.length),Qc=Jt===0?"empty":`${oe+1}\u2013${Xc} of ${Jt}`,gs=x===""?"all services":x;return ne("box",{flexGrow:1,flexDirection:N?"column":"row",overflow:"hidden",children:[ne("box",{flexGrow:N?1:0,flexShrink:0,minWidth:N?void 0:an,width:N?void 0:an,border:!0,borderStyle:"rounded",borderColor:Pt?t.border:t.borderActive,backgroundColor:t.panel,title:"services",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[ne(Be,{palette:t,items:[{text:Wu(nt.running,i.length),tone:nt.running>0?"success":"idle"},...Ve>0?[{text:`${Ve} failed`,tone:"error"}]:[],...c.length>0?[{text:`${c.length} selected`,tone:"primary"}]:[],...lt!==void 0?[{text:`up ${lt}`,tone:"idle"}]:[],...tr>0?[{text:`${tr} errors`,tone:"error",onMouseDown:q}]:[]]},void 0,!1,void 0,this),ne(Gc,{palette:t,checked:c,idle:Pt,profileName:mt,members:on},void 0,!1,void 0,this),ne("box",{flexGrow:1,paddingLeft:It.pad,paddingRight:It.pad,overflow:"hidden",children:ne(Wc,{palette:t,names:i,snap:r,selected:s,checked:c,width:fc(an,It.pad),onOpen:k,onSelectIndex:j,onToggle:V},void 0,!1,void 0,this)},void 0,!1,void 0,this),ne(uT,{palette:t,names:i,snap:r,width:an,onOpen:k},void 0,!1,void 0,this),sn?ne(fT,{palette:t,leftover:sn,width:an},void 0,!1,void 0,this):null,ne(gT,{palette:t,cfg:n,snap:r,google:d,width:an},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ne("box",{position:"relative",flexGrow:2,minWidth:N?void 0:32,minHeight:N?8:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,backgroundColor:t.panel,title:`logs \xB7 ${Qc}`,titleColor:t.primary,overflow:"hidden",flexDirection:"column",children:[ne(Be,{palette:t,items:[{text:g?"PAUSED":"LIVE",tone:g?"warning":"success"},{text:`shown ${cn.length}`,tone:"info"},{text:pe?`total ${pe.total}`:`total ${o.length}`},{text:gs,tone:x===""?"idle":"primary"},{text:w?"ERROR+":"all levels",tone:w?"error":"idle",onMouseDown:y},{text:E?"system: on":"system: off",tone:E?"accent":"idle",onMouseDown:B},{text:"clear",tone:"muted",onMouseDown:h}]},void 0,!1,void 0,this),ne(xp,{palette:t,logs:_,names:v??i,service:x,errorOnly:w,width:Ur,onService:C,onToggleErrors:y,facets:pe},void 0,!1,void 0,this),Jt>Rn.length?ne(vp,{palette:t,start:oe,count:Rn.length,total:Jt},void 0,!1,void 0,this):null,cn.length===0?ne($e,{palette:t,title:Pt?"Waiting for logs":o.length===0?"No events yet":"No events in this filter",body:Pt?"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:"[ ] cycle service g jump to latest"},void 0,!1,void 0,this):ne(bp,{palette:t,logs:Rn,width:Ur,followTick:m,focused:!1,wrapMode:I,selected:a,follow:ue,onLeaveLatest:Ie,onPick:ct,viewStart:oe},m,!1,void 0,this),ne(je,{palette:t,backgroundColor:t.element,edge:"top",children:ne(Oe,{palette:t,hints:Fo([{key:"e",label:"errors"},{key:"i",label:E?"internal off":"internal on"},{key:"ctrl+l",label:"clear"},{key:"g",label:"latest"},{key:"z",label:"full logs"},{key:"\u2190\u2192",label:"filter"}],Math.max(20,Ur-2))},void 0,!1,void 0,this)},void 0,!1,void 0,this),!ue?ne(yp,{palette:t,width:Ur,newer:Ee,bottom:1,onJump:Qe},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function lT(e){if(!e)return!1;return e.state===Kn||e.health===Ce||e.state===Mi||e.restarts>0||e.last_error!==""}function Db(e){if(e.state===Kn)return 0;if(e.health===Ce)return 1;if(e.state===Mi)return 2;return 3}function dT(e){if(e.last_error!=="")return e.last_error;if(e.restarts>0)return`restarted ${e.restarts}x, no error recorded`;return e.health===Ce?"failing health check":e.state.toLowerCase()}function uT(e){let{palette:t,names:n,snap:r,width:o,onOpen:i}=e,s=n.map((d)=>({name:d,rt:r?.services[d]})).filter((d)=>lT(d.rt)).sort((d,f)=>Db(d.rt)-Db(f.rt));if(s.length===0)return null;let a=s.slice(0,cT),c=s.length-a.length,l=Math.max(8,o-Sp-4);return ne("box",{border:!0,borderStyle:"rounded",borderColor:t.error,title:`issues (${s.length})`,titleColor:t.error,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",children:[a.map(({name:d,rt:f})=>{let g=Bt(f);return ne("box",{height:1,flexDirection:"row",overflow:"hidden",onMouseDown:()=>i(d),children:[ne("box",{width:2,flexShrink:0,children:ne("text",{fg:De(t,g),children:Mt(g)},void 0,!1,void 0,this)},void 0,!1,void 0,this),ne("box",{width:Sp,flexShrink:0,overflow:"hidden",children:ne("text",{fg:He(d,t),wrapMode:"none",children:ee(d,Sp)},void 0,!1,void 0,this)},void 0,!1,void 0,this),ne("box",{width:l,flexShrink:0,overflow:"hidden",children:ne("text",{fg:t.muted,wrapMode:"none",children:ce(dT(f),l)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},d,!0,void 0,this)}),c>0?ne("text",{fg:t.muted,wrapMode:"none",children:`+${c} more \u2014 open a service to see details`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function fT(e){let{palette:t,leftover:n,width:r}=e,o=n.processes.slice(0,pT),i=n.processes.length-o.length,s=Math.max(8,r-kp-4);return ne("box",{border:!0,borderStyle:"rounded",borderColor:t.warning,title:"last session",titleColor:t.warning,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",children:[ne("text",{fg:t.muted,wrapMode:"none",children:ce(`${n.session_id} ${n.profile||"(none)"}`,Math.max(8,r-4))},void 0,!1,void 0,this),o.map((a)=>ne("box",{height:1,flexDirection:"row",overflow:"hidden",children:[ne("box",{width:kp,flexShrink:0,overflow:"hidden",children:ne("text",{fg:t.text,wrapMode:"none",children:ee(a.name,kp)},void 0,!1,void 0,this)},void 0,!1,void 0,this),ne("box",{width:s,flexShrink:0,overflow:"hidden",children:ne("text",{fg:t.muted,wrapMode:"none",children:ce(`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?ne("text",{fg:t.muted,wrapMode:"none",children:`+${i} more leftover pids`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function gT(e){let{palette:t,cfg:n,snap:r,google:o,width:i}=e,s=o?.userEmail,a=Go(n,r?.identity,o).project,c=r?.logs.total??0,l=Jy(s,a,c,i);return ne(je,{palette:t,backgroundColor:t.element,edge:"top",children:ne("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:l.map((d,f)=>ne(ge,{palette:t,label:d.label,tone:d.tone},`${d.label}-${f}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var cT=4,Sp=14,pT=4,kp=14;var Mb=D(()=>{Pe();at();be();Et();Ye();Rr();ze();mp();wp()});import{useEffect as mT,useState as hT}from"react";import{jsxDEV as X}from"@opentui/react/jsx-dev-runtime";function Ib(e){let{palette:t,report:n,loading:r,progress:o,error:i,selected:s,onPick:a,onReload:c}=e,l=qo(s,Cp);if(r)return X(vT,{palette:t,progress:o},void 0,!1,void 0,this);if(i)return X(Px,{palette:t,title:"Doctor failed",body:i},void 0,!1,void 0,this);if(!n)return X($e,{palette:t,title:"Doctor",body:"Diagnostics have not run yet.",hint:"opening this screen runs doctor"},void 0,!1,void 0,this);let d=n.checks.filter((w)=>w.severity==="ok").length,f=n.checks.filter((w)=>w.severity==="warn").length,g=n.checks.filter((w)=>w.severity==="error").length,m=n.checks.length,x=ts(m>0?d/m:0),v=g>0?t.error:f>0?t.warning:t.success;return X(tt,{palette:t,title:`doctor ${n.issues} issue(s)`,children:[X("box",{height:4,flexDirection:"column",flexShrink:0,alignItems:"center",justifyContent:"center",overflow:"hidden",border:!0,borderStyle:"rounded",borderColor:t.primary,backgroundColor:t.element,onMouseDown:c,children:[X("text",{wrapMode:"none",children:[X("span",{fg:t.inverse,bg:t.primary,children:" r "},void 0,!1,void 0,this),X("span",{fg:t.primary,children:" RUN DOCTOR AGAIN"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),X("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),X("box",{height:1,flexShrink:0},void 0,!1,void 0,this),X("box",{height:1,flexShrink:0,overflow:"hidden",children:X("text",{wrapMode:"none",children:[X("span",{fg:v,children:`[${x}]`},void 0,!1,void 0,this),X("span",{fg:t.success,children:` ${d} ok`},void 0,!1,void 0,this),f>0?X("span",{fg:t.warning,children:` \xB7 ${f} warn`},void 0,!1,void 0,this):null,g>0?X("span",{fg:t.error,children:` \xB7 ${g} error`},void 0,!1,void 0,this):null,f===0&&g===0?X("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),X("box",{height:1,flexShrink:0},void 0,!1,void 0,this),X("scrollbox",{ref:l,focused:!1,stickyScroll:!1,scrollX:!1,style:Te(t),children:X("box",{flexDirection:"column",overflow:"hidden",gap:1,children:n.checks.map((w,E)=>X(yT,{palette:t,check:w,index:E,active:E===s,onPick:a},`${w.name}-${E}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function vT({palette:e,progress:t}){let[n,r]=hT(0);return mT(()=>{let o=setInterval(()=>r((i)=>(i+1)%$b.length),120);return()=>clearInterval(o)},[]),X("box",{flexGrow:1,alignItems:"center",justifyContent:"center",overflow:"hidden",children:X("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:[X("text",{wrapMode:"none",children:[X("span",{fg:e.primary,children:`${$b[n]} `},void 0,!1,void 0,this),X("span",{fg:e.text,children:"devctl doctor"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),X("box",{height:1,flexShrink:0},void 0,!1,void 0,this),X("text",{fg:e.text,wrapMode:"none",children:`Checking ${t.active}`},void 0,!1,void 0,this),X("box",{height:1,flexShrink:0},void 0,!1,void 0,this),t.checks.slice(-4).map((o,i)=>X("text",{wrapMode:"none",children:[X("span",{fg:De(e,o.severity==="error"?"ERROR":o.severity==="warn"?"WARN":"OK"),children:`${Mt(o.severity==="error"?"ERROR":o.severity==="warn"?"WARN":"OK")} `},void 0,!1,void 0,this),X("span",{fg:e.muted,children:o.name},void 0,!1,void 0,this)]},`${o.name}-${i}`,!0,void 0,this)),t.checks.length===0?X("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 yT(e){let{palette:t,check:n,index:r,active:o,onPick:i}=e,s=n.severity==="error"?"ERROR":n.severity==="warn"?"WARN":"OK";if(n.severity==="ok")return X("box",{id:`${Cp}-${r}`,flexDirection:"row",flexShrink:0,paddingLeft:1,overflow:"hidden",backgroundColor:o?t.highlight:void 0,onMouseDown:()=>i(r),children:X("text",{wrapMode:"none",children:[X("span",{fg:t.primary,children:o?"\u203A ":" "},void 0,!1,void 0,this),X("span",{fg:De(t,s),children:Mt(s)},void 0,!1,void 0,this),X("span",{fg:o?t.primary:t.text,children:` ${n.name}`},void 0,!1,void 0,this),X("span",{fg:t.muted,children:n.message?` \xB7 ${n.message}`:""},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this);let c=n.severity==="error"?t.error:t.warning;return X("box",{id:`${Cp}-${r}`,border:!0,borderStyle:"rounded",borderColor:o?t.borderActive:c,title:n.name,titleColor:c,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",backgroundColor:o?t.highlight:void 0,onMouseDown:()=>i(r),children:[X("text",{wrapMode:"word",children:[X("span",{fg:De(t,s),children:`${Mt(s)} `},void 0,!1,void 0,this),X("span",{fg:t.text,children:n.message},void 0,!1,void 0,this)]},void 0,!0,void 0,this),n.hint?X("text",{fg:t.info,wrapMode:"word",children:`\u2192 ${n.hint}`},void 0,!1,void 0,this):null,o&&n.action?.kind==="free-port"?X("text",{fg:t.primary,wrapMode:"none",children:`enter stop ${n.action.holder.command} (pid ${n.action.holder.pid})`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var Cp="doctor-row",$b;var Fb=D(()=>{Et();Pe();be();Ye();$b=["\u25D0","\u25D3","\u25D1","\u25D2"]});import{jsxDEV as Ae}from"@opentui/react/jsx-dev-runtime";function Hb(e){let{palette:t,cfg:n,snap:r,profile:o,selected:i,onPick:s}=e,a=se(),c=qo(i,Nb),l=Object.keys(n?.profiles??{}).sort();if(l.length===0)return Ae($e,{palette:t,title:"No profiles",body:"Add profiles.<name>.services in config.yaml."},void 0,!1,void 0,this);return Ae(tt,{palette:t,title:"profiles",children:[Ae("box",{height:1,flexShrink:0,overflow:"hidden",children:Ae("text",{fg:t.muted,wrapMode:"none",children:[`${l.length} profile${l.length===1?"":"s"} \xB7 current: `,Ae("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),Ae("box",{height:1,flexShrink:0},void 0,!1,void 0,this),Ae("scrollbox",{ref:c,focused:!1,stickyScroll:!1,scrollX:!1,style:Te(t),children:Ae("box",{flexDirection:"column",overflow:"hidden",gap:a.gap||1,children:l.map((d,f)=>{let g=d===o,m=f===i,x=n?.profiles[d]?.services??[],v=Object.keys(n?.profiles[d]?.environment??{}).length,w=m?t.borderActive:g?t.success:t.border,E=m?t.primary:g?t.success:t.muted;return Ae("box",{id:`${Nb}-${f}`,border:!0,borderStyle:"rounded",borderColor:w,title:d,titleColor:E,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",backgroundColor:m?t.highlight:void 0,onMouseDown:()=>s(f),children:[Ae("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:Ae("text",{wrapMode:"none",children:[g?Ae("span",{fg:t.success,children:"\u25CF current profile"},void 0,!1,void 0,this):Ae("span",{fg:t.muted,children:"\u25CB not active"},void 0,!1,void 0,this),Ae("span",{fg:t.muted,children:` \xB7 ${x.length} service${x.length===1?"":"s"}`},void 0,!1,void 0,this),v>0?Ae("span",{fg:t.muted,children:` \xB7 ${v} env var${v===1?"":"s"}`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Ae("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:x.length===0?Ae("text",{fg:t.muted,wrapMode:"none",children:"(no services)"},void 0,!1,void 0,this):Ae("text",{wrapMode:"word",children:x.map((k,j)=>{let V=Bt(r?.services[k]);return Ae("span",{children:[Ae("span",{fg:De(t,V),children:Mt(V)},void 0,!1,void 0,this),Ae("span",{fg:He(k,t),children:` ${k}`},void 0,!1,void 0,this),j<x.length-1?Ae("span",{fg:t.muted,children:" "},void 0,!1,void 0,this):null]},k,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},d,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this),Ae(je,{palette:t,backgroundColor:t.element,edge:"top",children:Ae(Oe,{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 Nb="profile-row";var jb=D(()=>{Et();at();Pe();be();Ye()});import{jsxDEV as G,Fragment as Ub}from"@opentui/react/jsx-dev-runtime";function xT(e){let t=e.toLowerCase();if(t==="iap")return"info";if(t==="service"||t==="service_account")return"primary";return"idle"}function bT(e,t,n){if(n||t>=500)return e.error;if(t===0||t>=400)return e.warning;return e.success}function wT(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 _T(e){let{palette:t,req:n,cols:r}=e,o=bT(t,n.status,n.error),i=n.status>0?String(n.status):"ERR",s=wT(t,n.identity),a=n.route||Kb,c=n.error?`${n.path} \u2014 ${ce(n.error,CT)}`:n.path;return G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[G("box",{width:_p,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:n.timestamp.slice(11,19)},void 0,!1,void 0,this)},void 0,!1,void 0,this),r.showMethod?G("box",{width:Uc,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.text,wrapMode:"none",children:ee(n.method,Uc)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,G("box",{width:Kc,flexShrink:0,overflow:"hidden",children:G("text",{fg:o,wrapMode:"none",children:ee(i,Kc)},void 0,!1,void 0,this)},void 0,!1,void 0,this),r.showDur?G("box",{width:qc,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,wrapMode:"none",children:ee(`${n.durationMs}ms`,qc)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,G("box",{width:Vc,flexShrink:0,overflow:"hidden",children:G("text",{fg:s.color,wrapMode:"none",children:ee(s.label,Vc)},void 0,!1,void 0,this)},void 0,!1,void 0,this),G("box",{width:r.routeCol,flexShrink:0,overflow:"hidden",children:G("text",{fg:n.route?t.info:t.muted,wrapMode:"none",children:ee(a,r.routeCol)},void 0,!1,void 0,this)},void 0,!1,void 0,this),G("box",{flexGrow:1,overflow:"hidden",children:G("text",{fg:n.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 ET(e){let{palette:t,cols:n}=e;return G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:[G("box",{width:_p,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:ee("TIME",_p)},void 0,!1,void 0,this)},void 0,!1,void 0,this),n.showMethod?G("box",{width:Uc,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:ee("METHOD",Uc)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,G("box",{width:Kc,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:ee("ST",Kc)},void 0,!1,void 0,this)},void 0,!1,void 0,this),n.showDur?G("box",{width:qc,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:ee("DUR",qc)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,G("box",{width:Vc,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:ee("WHO",Vc)},void 0,!1,void 0,this)},void 0,!1,void 0,this),G("box",{width:n.routeCol,flexShrink:0,overflow:"hidden",children:G("text",{fg:t.muted,children:ee("ROUTE",n.routeCol)},void 0,!1,void 0,this)},void 0,!1,void 0,this),G("box",{flexGrow:1,overflow:"hidden",children:G("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 RT(e){let{palette:t,name:n,auth:r,identity:o,upstream:i,match:s,onMouseDown:a}=e;return G("box",{flexDirection:"column",flexShrink:0,overflow:"hidden",onMouseDown:a,children:[G("text",{fg:t.text,wrapMode:"none",children:n},void 0,!1,void 0,this),G("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[G(ge,{palette:t,label:r||"no auth",tone:xT(r)},void 0,!1,void 0,this),o?G(ge,{palette:t,label:o,tone:"idle"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),s?G("text",{fg:t.muted,wrapMode:"word",children:`match: ${s}`},void 0,!1,void 0,this):null,G("text",{fg:t.muted,wrapMode:"word",children:`\u2192 ${i}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function qb(e){let{palette:t,cfg:n,snap:r,width:o,onSelectRoute:i}=e,s=r?.proxy.routes??[],a=new Map((n?.proxy.routes??[]).map((C)=>[C.name,C])),c=new Map((n?.proxy.routes??[]).map((C)=>[C.name,C.match])),l=r?.proxy.recentRequests??[],d=r?.proxy.requestTotal??0,f=r?.proxy.requestErrors??0,g=o<$o,m=Math.max(Bb,Math.min(PT,Math.floor(o*0.36))),x=g?o-Wb:o-m-Wb,v=Math.max(20,x-2),w=v>=Gb,E=v>=TT,k=v>=Gb?AT:LT,j=l.reduce((C,y)=>Math.min(k,Math.max(C,(y.route||Kb).length+kT)),ST),V={showMethod:w,showDur:E,routeCol:j};return G(tt,{palette:t,title:"proxy",children:[G(Be,{palette:t,items:[{text:r?.proxy.running?"RUNNING":"STOPPED",tone:r?.proxy.running?"success":"idle"},...r?.proxy.address?[{text:r.proxy.address,tone:"info"}]:[],{text:`${s.length} routes`,tone:s.length>0?"primary":"idle"},...d>0?[{text:`${d} requests`,tone:"idle"},...f>0?[{text:`${f} errors`,tone:"warning"}]:[]]:[]]},void 0,!1,void 0,this),G("box",{flexGrow:1,flexDirection:g?"column":"row",overflow:"hidden",children:[G("box",{flexGrow:g?1:0,flexBasis:g?0:void 0,flexShrink:0,minWidth:g?void 0:Bb,width:g?void 0:m,minHeight:g?8:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,title:"routes",titleColor:t.primary,paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",children:s.length===0?G($e,{palette:t,title:"No proxy routes",body:"Add routes under proxy.routes or .devctl/proxy/routes.yaml."},void 0,!1,void 0,this):G(Ub,{children:[i?G("text",{fg:t.muted,wrapMode:"word",children:"click a route for full details"},void 0,!1,void 0,this):null,G("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Te(t),children:G("box",{flexDirection:"column",overflow:"hidden",gap:1,children:s.map((C)=>{let y=c.get(C.name),B=y&&(y.host||y.path)?`${y.host||"*"}${y.path?y.path:""}`:void 0,h=a.get(C.name);return G(RT,{palette:t,name:C.name,auth:C.auth,identity:C.identity,upstream:C.upstream,match:B,onMouseDown:i?()=>i({name:C.name,authType:h?.auth.type||C.auth,identityType:h?.auth.identity.type??"",serviceAccount:h?.auth.identity.service_account||h?.auth.service_account||"",audience:h?.auth.audience??"",matchHost:h?.match.host??"",matchPath:h?.match.path??"",upstream:C.upstream}):void 0},C.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),G("box",{flexGrow:1,flexBasis:0,minWidth:g?void 0:30,minHeight:g?10:void 0,border:!0,borderStyle:"rounded",borderColor:t.borderActive,title:"requests",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:l.length===0?G("box",{paddingLeft:1,paddingRight:1,children:G("text",{fg:t.muted,wrapMode:"word",children:r?.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):G(Ub,{children:[G(ET,{palette:t,cols:V},void 0,!1,void 0,this),G("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Te(t),children:G("box",{flexDirection:"column",overflow:"hidden",children:l.map((C)=>G(_T,{palette:t,req:C,cols:V},C.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),G(je,{palette:t,backgroundColor:t.element,edge:"top",children:G(Oe,{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 _p=9,Uc=8,Kc=4,qc=8,Vc=4,ST=8,kT=2,CT=64,Kb="(none)",Bb=26,PT=56,Wb=2,Gb=46,TT=54,AT=20,LT=12;var Vb=D(()=>{Et();Pe();be()});import{jsxDEV as re}from"@opentui/react/jsx-dev-runtime";function Yb(e){let{palette:t,name:n}=e;return re("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:n,titleColor:He(n,t),flexDirection:"column",overflow:"hidden",children:re(Ep,{...e,compact:!1},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Ep(e){let{palette:t,cfg:n,snap:r,name:o,reveal:i,width:s,compact:a=!0,envScrollRef:c}=e,l=se(),d=n?.services[o];if(!d)return re($e,{palette:t,title:"Unknown service",body:`No service named ${o}.`,hint:"j/k move"},void 0,!1,void 0,this);let f=r?.services[o],g=Bt(f),m=f?.health??"UNKNOWN",x=jr(f)||ss(d,f),v=Uy(d,i,n?.secrets.extra_markers??[],n?.secrets.extra_patterns??[],e.resolvedEnv),w=e.envStatus==="error"?"error":e.envStatus==="resolved"?"success":e.envStatus==="loading"?"info":"muted",E=e.envStatus==="resolved"?"resolved":e.envStatus==="loading"?"resolving":e.envStatus==="error"?"config fallback":"config",k=s>=OT,j=[{label:"health",value:_c(d)},{label:"workdir",value:d.working_dir||"."},{label:"restart",value:Rc(d)},{label:"caps",value:d.capabilities.join(", ")||"\u2014"},{label:"runtime",value:d.container?`${d.container.runtime||"docker"} \xB7 ${d.container.image}`:"host"}],V=[{label:"identity",value:Ec(d,f)},{label:"depends",value:d.dependencies.map(Ws).join(", ")||"\u2014"},{label:"ports",value:ss(d,f)},{label:"tries",value:String(f?.restarts??0),tone:f?.restarts?"warning":"muted"}],C=Math.max(Gr+8,s-2),y=k?Math.floor(C/2):C;return re("box",{padding:l.pad,flexGrow:1,flexDirection:"column",overflow:"hidden",children:[re(Be,{palette:t,items:[{text:g,tone:zb(g)},{text:m,tone:zb(m)},{text:f?.pid?`pid ${f.pid}`:"pid \u2014",tone:f?.pid?"info":"idle"},{text:x==="\u2014"?"port \u2014":`port ${x}`,tone:x==="\u2014"?"idle":"info"}]},void 0,!1,void 0,this),d.description?re("box",{height:1,overflow:"hidden",children:re("text",{fg:t.muted,wrapMode:"none",children:ce(d.description,Math.max(8,s-4))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,f?.last_error?re("box",{height:1,overflow:"hidden",children:re("text",{fg:t.error,wrapMode:"none",children:ce(f.last_error,DT)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,re(Rp,{palette:t,item:{label:"command",value:Cc(d)},valueWidth:Math.max(8,C-Gr)},void 0,!1,void 0,this),re(MT,{palette:t,left:j,right:V,wide:k,colWidth:y},void 0,!1,void 0,this),re($T,{palette:t,entries:v,reveal:i,width:s,focused:!a,scrollRef:c,source:E,sourceTone:w,error:e.envError,onSelect:e.onSelectEnv},void 0,!1,void 0,this),a?null:re(Oe,{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 MT(e){let{palette:t,left:n,right:r,wide:o,colWidth:i}=e,s=Math.max(4,i-Gr);if(!o)return re("box",{width:i,flexShrink:0,flexDirection:"column",overflow:"hidden",children:[...n,...r].map((a)=>re(Rp,{palette:t,item:a,valueWidth:s},a.label,!1,void 0,this))},void 0,!1,void 0,this);return re("box",{height:n.length,flexShrink:0,flexDirection:"row",overflow:"hidden",children:[re(Jb,{palette:t,items:n,width:i},void 0,!1,void 0,this),re(Jb,{palette:t,items:r,width:i},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Jb(e){let t=Math.max(4,e.width-Gr);return re("box",{width:e.width,flexShrink:0,flexDirection:"column",overflow:"hidden",children:e.items.map((n)=>re(Rp,{palette:e.palette,item:n,valueWidth:t},n.label,!1,void 0,this))},void 0,!1,void 0,this)}function Rp(e){let{palette:t,item:n,valueWidth:r}=e,o=n.tone==="warning"?t.warning:n.tone==="muted"?t.muted:t.text;return re("box",{height:1,width:Gr+r,flexDirection:"row",overflow:"hidden",children:[re("box",{width:Gr,flexShrink:0,overflow:"hidden",children:re("text",{fg:t.muted,wrapMode:"none",children:ee(n.label,Gr)},void 0,!1,void 0,this)},void 0,!1,void 0,this),re("box",{width:r,flexShrink:0,overflow:"hidden",children:re("text",{fg:o,wrapMode:"none",children:ee(n.value,r)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function $T(e){let{palette:t,entries:n,reveal:r,width:o,focused:i,scrollRef:s,source:a,sourceTone:c,error:l,onSelect:d}=e;return re("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[re(Be,{palette:t,items:[{text:`env ${n.length}`,tone:n.length>0?"info":"idle"},{text:a,tone:c},{text:r?"secrets shown":"redacted",tone:r?"warning":"muted"}],hints:i?[{key:"j/k",label:"scroll"}]:[{key:"/reveal",label:"secrets"}]},void 0,!1,void 0,this),l?re("box",{height:1,overflow:"hidden",children:re("text",{fg:t.warning,wrapMode:"none",children:ce(l,Math.max(8,o-4))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,n.length===0?re("text",{fg:t.muted,children:"no service env overrides"},void 0,!1,void 0,this):re("box",{flexGrow:1,height:"100%",overflow:"hidden",children:[d?re("text",{fg:t.muted,wrapMode:"word",children:"click a variable for its full value"},void 0,!1,void 0,this):null,re("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:re("box",{flexDirection:"column",overflow:"hidden",children:n.map((f)=>{let g=f.required?t.warning:f.fromConfig?t.accent:t.muted,m=f.value===""&&f.required?"(required)":f.value;return re("box",{flexDirection:"row",overflow:"hidden",onMouseDown:d?()=>d(f):void 0,children:re("text",{wrapMode:"word",children:[re("span",{fg:g,children:f.required?`${f.key}*`:f.key},void 0,!1,void 0,this),re("span",{fg:f.value===""?t.muted:t.text,children:` ${m}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},f.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 zb(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 DT=72,OT=56,Gr=9;var Pp=D(()=>{Pe();Et();at();be();Ye();st()});import{jsxDEV as er}from"@opentui/react/jsx-dev-runtime";function Xb(e){let{palette:t,cfg:n,names:r,snap:o,selected:i,checked:s,width:a,reveal:c,onOpen:l,onSelectIndex:d,onToggle:f,resolvedEnv:g,envStatus:m,envError:x,onSelectEnv:v}=e;if(r.length===0)return er($e,{palette:t,title:"No services",body:"This configuration does not define any services."},void 0,!1,void 0,this);let w=a<$o,E=r[i]??"",k=yc(a,r,w),j=4,V=w?Math.max(Tp,a-j):Math.max(Tp,a-k-j);return er("box",{flexGrow:1,flexDirection:w?"column":"row",overflow:"hidden",children:[er("box",{flexGrow:w?1:0,flexShrink:0,minWidth:w?void 0:ic,width:w?void 0:k,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:"services",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[er(Gc,{palette:t,checked:s,idle:Bo(o),profileName:"",members:""},void 0,!1,void 0,this),er("box",{flexGrow:1,overflow:"hidden",children:er(Wc,{palette:t,names:r,snap:o,selected:i,checked:s,width:fc(k),onOpen:l,onSelectIndex:d,onToggle:f},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),er("box",{flexGrow:2,minWidth:w?void 0:Tp,minHeight:w?IT:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,backgroundColor:t.panel,title:E||"detail",titleColor:E?He(E,t):t.primary,overflow:"hidden",flexDirection:"column",children:er(Ep,{palette:t,cfg:n,snap:o,name:E,reveal:c,width:V,resolvedEnv:g,envStatus:m,envError:x,onSelectEnv:v},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Tp=36,IT=12;var Qb=D(()=>{Et();Pe();Ye();Pp();mp()});import{jsxDEV as he}from"@opentui/react/jsx-dev-runtime";function NT(e){switch(e){case"cycle":return"\u2194";case"toggle":return"\u23FB";case"page":return"\u25B8";case"action":return"!";default:return"\xB7"}}function nw(e){let{palette:t,items:n,selected:r,locked:o,width:i,onPick:s,onActivate:a}=e,c=se(),l=ep(n,r),d=Ko(n,l);return he("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:"settings",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[he("box",{height:2,paddingLeft:c.pad,flexShrink:0,flexDirection:"column",overflow:"hidden",children:[he("text",{fg:t.primary,wrapMode:"none",children:"Preferences"},void 0,!1,void 0,this),he("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),he("box",{flexGrow:1,paddingLeft:c.pad,paddingRight:c.pad,overflow:"hidden",flexShrink:1,children:he(HT,{palette:t,items:n,active:l,scale:c,width:i,onPick:s,onActivate:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),he(BT,{palette:t,item:d,scale:c},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function HT(e){let{palette:t,items:n,active:r,scale:o,width:i,onPick:s,onActivate:a}=e,c=qo(r,tw),l=Math.max(8,i-Zb-ew-10),d=0,f=wx(n);return he("scrollbox",{ref:c,focused:!1,stickyScroll:!1,scrollX:!1,style:Te(t),children:he("box",{flexDirection:"column",overflow:"hidden",children:f.map((g,m)=>{let x=d;d+=g.items.length;let v=r>=x&&r<x+g.items.length;return he("box",{border:!0,borderStyle:"rounded",borderColor:v?t.borderActive:t.border,title:`${g.group} (${g.items.length})`,titleColor:v?t.primary:t.muted,flexDirection:"column",flexShrink:0,marginBottom:m<f.length-1?Math.max(1,o.gap):0,paddingLeft:1,paddingRight:1,overflow:"hidden",children:[g.group==="MCP"?he("box",{height:1,overflow:"hidden",children:he("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,g.items.map((w,E)=>{let k=x+E;return he(jT,{index:k,palette:t,item:w,active:k===r,rowH:o.rowH,valueWidth:l,onPick:()=>s(k),onActivate:()=>a(w)},w.id,!1,void 0,this)})]},g.group,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function jT(e){let{palette:t,index:n,item:r,active:o,rowH:i,valueWidth:s,onPick:a,onActivate:c}=e;return he("box",{id:`${tw}-${n}`,height:i,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:o?t.highlight:void 0,onMouseDown:()=>{if(o){c();return}a()},children:[he("box",{width:2,flexShrink:0,overflow:"hidden",children:he("text",{fg:t.primary,children:o?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),he("box",{width:ew,flexShrink:0,overflow:"hidden",children:he("text",{fg:o?t.primary:t.muted,children:NT(r.kind)},void 0,!1,void 0,this)},void 0,!1,void 0,this),he("box",{width:Zb,flexShrink:0,overflow:"hidden",children:he("text",{fg:o?t.primary:t.text,wrapMode:"none",children:r.name},void 0,!1,void 0,this)},void 0,!1,void 0,this),he("box",{flexGrow:1,overflow:"hidden",children:he("text",{fg:WT(t,r,o),wrapMode:"none",children:ce(r.value,s)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function BT(e){let{palette:t,item:n,scale:r}=e,o=n?.id==="font",i=n?.kind==="page"?`${n.name} \u2192 dedicated page`:n?.name??"";return he("box",{height:FT,flexShrink:0,border:!0,borderStyle:"rounded",borderColor:t.border,title:"selected",titleColor:t.muted,backgroundColor:t.element,paddingLeft:r.pad,paddingRight:r.pad,flexDirection:"column",overflow:"hidden",children:[he("box",{height:1,overflow:"hidden",children:he("text",{fg:t.primary,wrapMode:"none",children:o?`${xx(r.steps)} ${r.label}`:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),he("box",{height:1,overflow:"hidden",children:he("text",{fg:t.text,wrapMode:"word",children:n?.detail??""},void 0,!1,void 0,this)},void 0,!1,void 0,this),he("box",{height:1,overflow:"hidden",children:he("text",{fg:t.muted,wrapMode:"none",children:n?n.kind==="info"?"read-only":n.hint:""},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function WT(e,t,n){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 n?e.primary:e.text}var Zb=14,ew=2,FT=5,tw="settings-row";var rw=D(()=>{at();Pe();be();Cn()});import{useEffect as GT,useState as UT}from"react";import{jsxDEV as J}from"@opentui/react/jsx-dev-runtime";function Jo(e){let{palette:t,title:n,tone:r="muted",children:o}=e,i=r==="success"?t.success:r==="warning"?t.warning:r==="error"?t.error:t.border;return J("box",{border:!0,borderStyle:"rounded",borderColor:i,title:n,titleColor:i,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,marginBottom:1,overflow:"hidden",children:o},void 0,!1,void 0,this)}function Ap(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 fs(e){let{palette:t,cells:n,header:r,gap:o=0,stripe:i}=e;return J("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:i?t.element:void 0,children:n.map((s,a)=>J("box",{flexDirection:"row",flexShrink:0,overflow:"hidden",children:[a>0&&o>0?J("box",{width:o,flexShrink:0},void 0,!1,void 0,this):null,J("box",{width:s.width,flexShrink:0,overflow:"hidden",children:J("text",{fg:r?t.primary:Ap(t,s),wrapMode:"none",children:ee(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 ow(e){let{palette:t,width:n}=e;return J("box",{height:1,flexShrink:0,overflow:"hidden",children:J("text",{fg:t.border,wrapMode:"none",children:ee("\u2500".repeat(Math.max(1,n)),n)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function ps(e){let{palette:t,facts:n,width:r}=e,o=Bu(n,r),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}),J("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[J(fs,{palette:t,header:!0,gap:Ho,cells:i},void 0,!1,void 0,this),J(ow,{palette:t,width:r},void 0,!1,void 0,this),n.map((s,a)=>{let c=s.meaning===""?[""]:vc(s.meaning,Math.max(1,o.meaning)),l=s.meter?cy(s.meter):o.meter>0?"":void 0,d=[{text:s.what,width:o.what,tone:"text"},{text:s.reading,width:o.reading,tone:s.tone??"text"}];if(o.meter>0)d.push({text:l??"",width:o.meter,tone:s.meter?s.tone??"text":"muted"});return d.push({text:c[0]??"",width:o.meaning,tone:"muted"}),J("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[J(fs,{palette:t,gap:Ho,stripe:a%2===1,cells:d},void 0,!1,void 0,this),c.slice(1).map((f,g)=>{let m=[{text:"",width:o.what},{text:"",width:o.reading}];if(o.meter>0)m.push({text:"",width:o.meter});return m.push({text:f,width:o.meaning,tone:"muted"}),J(fs,{palette:t,gap:Ho,stripe:a%2===1,cells:m},`${s.what}-more-${g}`,!1,void 0,this)})]},`${s.what}-${s.reading}-${a}`,!0,void 0,this)})]},void 0,!0,void 0,this)}function iw(e){let{palette:t,cfg:n,snap:r,width:o,onRefresh:i}=e,s=se(),[,a]=UT(0);if(GT(()=>{let Ee=setInterval(()=>{a((Qe)=>{let pe=Qe+1;if(i&&pe%qT===0)i();return pe})},KT);return()=>clearInterval(Ee)},[i]),!n)return J($e,{palette:t,title:"No configuration loaded",body:"Add services to .devctl/config.yaml or finish setup."},void 0,!1,void 0,this);let c=Object.keys(n.services).sort(),l=c.some((Ee)=>ly(n.services[Ee])),d=ty(c,r),f=hy(d,l),g=l&&d.live>0?d.healthy/d.live:d.total>0?d.live/d.total:0,m=ts(g,VT),x=d.failed>0?"error":l&&d.live>0&&d.healthy<d.live?"warning":"success",v=iy(o,s.pad),w=r?.session_id?js(r.session_id):void 0,E=w?jo(Date.now()-w.getTime()):"just started",k=r?.logs.total??0,j=r?.logs.errors??0,V=oy(r?.logs.counts??{}),C=r?.proxy.routes??[],y=r?.credentials,B=(y?.entries??[]).filter((Ee)=>Ee.valid).length,h=r?.system,q=h?h.memAvailableKB??h.memFreeKB:0,I=h?uy(h.loadAvg1,h.cpuCount):void 0,z=h?py(q,h.memTotalKB):void 0,ue=[];if(h&&I&&z)ue.push(I,z,{what:"Computer",reading:dy(h.platform),meaning:`on for ${jo(h.hostUptimeSec*JT)}`,tone:"text"});let Ie=d.failed>0||I?.tone==="error"||z?.tone==="error"?"error":x==="warning"||I?.tone==="warning"||z?.tone==="warning"?"warning":"success",ct=[{what:"This session",reading:E,meaning:"how long this run has been going",tone:"text"},{what:"Profile",reading:r?.profile||"none",meaning:"which group of services is selected",tone:r?.profile?"text":"muted"},{what:"This window",reading:r?.detached?"closed":"watching",meaning:r?.detached?"services keep running without this screen":"you are watching the services from here",tone:r?.detached?"warning":"text"},{what:"Project folder",reading:"",meaning:n.repoRoot,tone:"muted"}],oe=[{what:"Lines kept",reading:String(k),meaning:"log lines still in memory",tone:"text"},{what:"Error lines",reading:String(j),meaning:j>0?"open Logs and press e to see only errors":"no ERROR or FATAL lines",tone:j>0?"error":"muted"},...V.map(([Ee,Qe])=>({what:Ee,reading:String(Qe),meaning:"lines from this service",tone:"text"}))],Ue=[{what:"Web proxy",reading:r?.proxy.running?"on":"off",meaning:r?.proxy.running?`${C.length} apps${r.proxy.address?` at ${r.proxy.address}`:""}`:"not forwarding local URLs",tone:r?.proxy.running?"success":"muted"},{what:"Agent tools",reading:r?.mcp?.running?"on":"off",meaning:r?.mcp?.address?`Cursor talks to devctl at ${r.mcp.address}`:"turn on from Settings \u2192 MCP",tone:r?.mcp?.running?"success":"muted"},{what:"Google account",reading:r?.identity.user?"signed in":"not signed in",meaning:[r?.identity.user,r?.identity.project].filter(Boolean).join(" \xB7 ")||"no Google user for this session",tone:r?.identity.user?"success":"muted"},{what:"Saved tokens",reading:y?`${B} of ${y.entries.length} good`:"none",meaning:y?my(y.backend):"nothing stored yet",tone:y&&B<y.entries.length?"warning":y?"success":"muted"}];return J(tt,{palette:t,title:"stats",scroll:!0,children:[J(Jo,{palette:t,title:`Your services ${d.live} of ${d.total} started`,tone:Ie,children:[J(ps,{palette:t,facts:f,width:v},void 0,!1,void 0,this),J("box",{height:1,flexShrink:0},void 0,!1,void 0,this),J("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:J("text",{wrapMode:"none",children:[J("span",{fg:t.muted,children:ee(l?"Ready":"Started",Bu(f,v).what)},void 0,!1,void 0,this),J("span",{children:" ".repeat(Ho)},void 0,!1,void 0,this),J("span",{fg:Ap(t,{text:"",width:1,tone:x}),children:`[${m}]`},void 0,!1,void 0,this),J("span",{fg:Ap(t,{text:"",width:1,tone:x}),children:l?` ${d.healthy} of ${d.live||d.total} passing checks`:` ${d.live} of ${d.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),h?J(Jo,{palette:t,title:"This computer",tone:I?.tone==="error"||z?.tone==="error"?"error":I?.tone==="warning"||z?.tone==="warning"?"warning":"success",children:J(ps,{palette:t,facts:ue,width:v},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,J(Jo,{palette:t,title:"This session",children:J(ps,{palette:t,facts:ct,width:v},void 0,!1,void 0,this)},void 0,!1,void 0,this),J(Jo,{palette:t,title:"Each service",tone:d.failed>0?"error":l&&d.live>0&&d.healthy<d.live?"warning":"success",children:d.total===0?J("text",{fg:t.muted,children:"No services in this project yet."},void 0,!1,void 0,this):J("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[J(zT,{palette:t,names:c,snap:r,width:v},void 0,!1,void 0,this),J("box",{height:1,flexShrink:0},void 0,!1,void 0,this),J("text",{fg:t.muted,wrapMode:"none",children:ee("CPU is % of one core. RAM is what that process is holding now.",v)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),J(Jo,{palette:t,title:"Log lines",tone:j>0?"warning":"muted",children:J(ps,{palette:t,facts:oe,width:v},void 0,!1,void 0,this)},void 0,!1,void 0,this),J(Jo,{palette:t,title:"Other parts",children:J(ps,{palette:t,facts:Ue,width:v},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function zT(e){let{palette:t,names:n,snap:r,width:o}=e,i=sy(o),s=[{text:"service",width:i.name},{text:"status",width:en}];if(i.health)s.push({text:"check",width:Sn});if(i.cpu)s.push({text:"cpu",width:lc});if(i.mem)s.push({text:"ram",width:dc});if(i.up)s.push({text:"up",width:cc});if(i.rst)s.push({text:"restarts",width:Sc});if(i.pid)s.push({text:"pid",width:zn});return J("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[J(fs,{palette:t,header:!0,gap:vt,cells:s},void 0,!1,void 0,this),J(ow,{palette:t,width:o},void 0,!1,void 0,this),n.map((a,c)=>J(ZT,{palette:t,name:a,rt:r?.services[a],cols:i,stripe:c%2===1},a,!1,void 0,this))]},void 0,!0,void 0,this)}function QT(e){if(e===void 0)return"muted";if(e>XT)return"error";if(e>YT)return"warning";return"text"}function ZT(e){let{palette:t,name:n,rt:r,cols:o,stripe:i}=e,s=fy(r),a=gy(r),c=r?.restarts??0,l=[{text:n,width:o.name,color:He(n,t)},{text:s,width:en,color:De(t,r?.state??"STOPPED")}];if(o.health)l.push({text:a,width:Sn,color:De(t,r?.health??"UNKNOWN")});if(o.cpu)l.push({text:r?.cpuPercent!==void 0?vy(r.cpuPercent):"\u2014",width:lc,tone:QT(r?.cpuPercent)});if(o.mem)l.push({text:r?.memoryKB!==void 0?sc(r.memoryKB):"\u2014",width:dc,tone:"text"});if(o.up)l.push({text:ry(r),width:cc,tone:"text"});if(o.rst)l.push({text:String(c),width:Sc,tone:c>0?"warning":"muted"});if(o.pid)l.push({text:r?.pid?String(r.pid):"\u2014",width:zn,tone:"muted"});return J("box",{flexDirection:"column",flexShrink:0,overflow:"hidden",children:[J(fs,{palette:t,gap:vt,stripe:i,cells:l},void 0,!1,void 0,this),r?.last_error?J("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:J("text",{fg:t.error,wrapMode:"none",children:ee(` ${r.last_error}`,Math.max(24,o.name+vt+en+Sn))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var KT=1000,qT=5,VT=16,JT=1000,YT=80,XT=100;var sw=D(()=>{Et();Pe();at();be();Ye();ze()});import{jsxDEV as ye}from"@opentui/react/jsx-dev-runtime";function aw(e){let{palette:t,cfg:n,google:r,bootError:o,bootErrorMissing:i=!1,step:s=0}=e,a=se();if(o&&!n)return i?ye($e,{palette:t,title:"No configuration found",body:"Would you like to run setup?",hint:"[Enter] Setup [Esc] Exit"},void 0,!1,void 0,this):ye($e,{palette:t,title:"Configuration error",body:o,hint:"Fix .devctl/config.yaml, then restart devctl [Esc] Exit"},void 0,!1,void 0,this);let c=n?Xt(n):["configuration not loaded"],l=eA(n,r,c),d=l.filter((k)=>k.ok).length,f=l.length,g=f>0?Math.round(d/f*100):0,m=20,x=Math.round(g/100*m),v="\u2588".repeat(x)+"\u2591".repeat(Math.max(0,m-x)),w=g===100?t.success:g===0?t.muted:t.primary,E=l[s];return ye(tt,{palette:t,title:"setup",scroll:!0,children:[ye("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:ye("text",{fg:t.primary,children:"Developer onboarding"},void 0,!1,void 0,this)},void 0,!1,void 0,this),ye("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:ye("text",{wrapMode:"none",children:[ye("span",{fg:w,children:`[${v}]`},void 0,!1,void 0,this),ye("span",{fg:t.text,children:` ${d}/${f} ready`},void 0,!1,void 0,this),ye("span",{fg:t.muted,children:` (${g}%)`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),ye("box",{height:1,flexShrink:0},void 0,!1,void 0,this),l.map((k,j)=>{let V=j===s;return ye("box",{height:a.rowH,flexDirection:"row",overflow:"hidden",backgroundColor:V?t.highlight:void 0,paddingLeft:1,children:[ye("box",{width:2,flexShrink:0,children:ye("text",{fg:De(t,k.ok?"OK":"WARN"),children:Mt(k.ok?"OK":"WARN")},void 0,!1,void 0,this)},void 0,!1,void 0,this),ye("box",{width:3,flexShrink:0,children:ye("text",{fg:V?t.primary:t.muted,children:String(j+1).padStart(2," ")},void 0,!1,void 0,this)},void 0,!1,void 0,this),ye("box",{width:20,flexShrink:0,overflow:"hidden",children:ye("text",{fg:V?t.primary:t.text,children:k.name},void 0,!1,void 0,this)},void 0,!1,void 0,this),ye("box",{flexGrow:1,overflow:"hidden",children:ye("text",{fg:V?t.text:t.muted,wrapMode:"none",children:k.detail},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},k.name,!0,void 0,this)}),ye("box",{height:1,flexShrink:0},void 0,!1,void 0,this),E?ye("box",{border:!0,borderStyle:"rounded",borderColor:E.ok?t.success:t.warning,title:E.name,titleColor:E.ok?t.success:t.warning,flexDirection:"column",paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:ye("text",{fg:E.ok?t.text:t.warning,wrapMode:"word",children:E.detail},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,ye("box",{height:1,flexShrink:0},void 0,!1,void 0,this),ye("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:ye(ge,{palette:t,label:"never hard-coded",tone:"idle"},void 0,!1,void 0,this)},void 0,!1,void 0,this),ye("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),ye(Oe,{palette:t,hints:[{key:"j/k",label:"steps"},{key:"enter",label:n?"start":"begin setup"},{key:"esc",label:"exit"},{key:"o",label:"profiles"}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function eA(e,t,n=[]){let r=Object.values(e?.services??{}).flatMap((s)=>s.ports.filter((a)=>!a.auto)),o=(e?.proxy.routes??[]).some((s)=>s.auth.type.toLowerCase()==="iap"),i=Go(e,void 0,t).project;return[{name:_n[0],ok:Boolean(e?.repoRoot),detail:e?.repoRoot||"unknown"},{name:_n[1],ok:Boolean(e?.project.name),detail:e?.project.name||"set project.name"},{name:_n[2],ok:Boolean(i),detail:i||"optional for local-only"},{name:_n[3],ok:t?.adcAvailable===!0,detail:t?.adcAvailable?"ADC available":"needed only for cloud identity / IAP"},{name:_n[4],ok:!0,detail:"read from configuration; never hard-coded"},{name:_n[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:_n[6],ok:r.length===0||Boolean(e),detail:`${r.length} fixed ports from configuration`},{name:_n[7],ok:Object.keys(e?.profiles??{}).length>0,detail:`${Object.keys(e?.profiles??{}).length} profile(s)`},{name:_n[8],ok:n.length===0,detail:n.length===0?"configuration is valid":n[0]??"invalid"}]}var _n;var cw=D(()=>{st();Et();at();be();Pe();Ye();_n=["Repository","Environment","Google project","Authentication","Service accounts","IAP","Ports","Profiles","Validation"]});import{jsxDEV as U}from"@opentui/react/jsx-dev-runtime";function Mp(){return pu.flatMap((e)=>Ua.filter((t)=>t.category===e))}function zc(){return Jc+Mp().length}function uw(){return zc()+dw}function Yc(e){if(e<Jc||e>=zc())return;return Mp()[e-Jc]}function $p(e){let t=e-zc();return t>=0&&t<dw?t:void 0}function pw(e){let{palette:t,snap:n,port:r,portDraft:o="",selected:i,onPick:s,onToggle:a,onCopy:c,onToggleTool:l}=e,d=se(),f=n?.mcp?.running===!0,g=n?.mcp?.port??r,m=n?.mcp?.address??Oo(g),x=n?.mcp?.token??"",v=Ji(m,x),w=n?.mcp?.disabled_tools??[],E=Mp(),k=E.filter((C)=>!qn(C.name,w)).length,j=v[$p(i)??-1],V=j??v[0];return U(tt,{palette:t,title:"mcp settings",children:[U(Be,{palette:t,items:[{text:f?"RUNNING":"STOPPED",tone:f?"success":"idle"},{text:`127.0.0.1:${g}`,tone:"info"}]},void 0,!1,void 0,this),U("box",{flexGrow:1,overflow:"hidden",children:U("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Te(t),children:U("box",{flexDirection:"column",overflow:"hidden",children:[U(Lp,{palette:t,text:"Server"},void 0,!1,void 0,this),U(lw,{palette:t,active:i===Dp,rowH:d.rowH,label:"Listen",value:f?"[ ON ]":"[ OFF ]",valueTone:f?"success":"muted",hint:f?"space or enter stop":"space or enter start",onPick:()=>s(Dp),onActivate:a},void 0,!1,void 0,this),U(lw,{palette:t,active:i===Op,rowH:d.rowH,label:"Port",value:`\u2039 ${o===""?r:o} \u203A`,valueTone:"info",hint:o===""?"\u2190 \u2192 change type digits enter apply":"typing\u2026 enter apply \u232B erase",onPick:()=>s(Op)},void 0,!1,void 0,this),U("box",{height:1,overflow:"hidden",children:U("text",{fg:t.muted,wrapMode:"none",children:f?"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),U(Lp,{palette:t,text:"Tools",extra:k===0?"all enabled":`${k} disabled`},void 0,!1,void 0,this),U("box",{height:1,overflow:"hidden",children:U("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),pu.map((C)=>{let y=E.filter((B)=>B.category===C);if(y.length===0)return null;return U("box",{flexDirection:"column",overflow:"hidden",children:[U("box",{height:1,marginTop:1,overflow:"hidden",children:U("text",{fg:t.muted,wrapMode:"none",children:tA[C]??C},void 0,!1,void 0,this)},void 0,!1,void 0,this),y.map((B)=>{let h=Jc+E.indexOf(B);return U(iA,{palette:t,tool:B,enabled:qn(B.name,w),active:i===h,rowH:d.rowH,onPick:()=>s(h),onToggle:()=>l(B)},B.name,!1,void 0,this)})]},C,!0,void 0,this)}),U(Lp,{palette:t,text:"Copy agent config",extra:"highlight a row, then enter or click Copy"},void 0,!1,void 0,this),v.map((C,y)=>{let B=zc()+y;return U(oA,{palette:t,snippet:C,active:i===B,rowH:d.rowH,onPick:()=>s(B),onCopy:()=>c(C)},C.kind,!1,void 0,this)}),U(sA,{palette:t,snippet:V,selected:Boolean(j),brand:V?Lc(V.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),U(je,{palette:t,backgroundColor:t.element,edge:"top",children:U(Oe,{palette:t,hints:rA(i,f)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function rA(e,t){if(e===Dp)return[{key:"space",label:t?"stop server":"start server"},{key:"j/k",label:"move"}];if(e===Op)return[{key:"\u2190\u2192",label:"change port"},{key:"0-9",label:"type port"},{key:"enter",label:"apply port"},{key:"j/k",label:"move"}];if(Yc(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 Lp(e){let t=e.extra?` \xB7 ${e.extra}`:"";return U("box",{height:1,marginTop:1,overflow:"hidden",children:U("text",{wrapMode:"none",children:[U("span",{fg:e.palette.primary,children:e.text},void 0,!1,void 0,this),U("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 lw(e){let{palette:t,active:n,rowH:r,label:o,value:i,valueTone:s,hint:a,onPick:c,onActivate:l}=e,d=s==="success"?t.success:s==="info"?t.info:t.muted;return U("box",{height:r,flexDirection:"row",overflow:"hidden",backgroundColor:n?t.highlight:t.panel,onMouseDown:()=>{if(n&&l){l();return}c()},children:[U("box",{width:2,flexShrink:0,overflow:"hidden",children:U("text",{fg:t.primary,children:n?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),U("box",{width:Ip,flexShrink:0,overflow:"hidden",children:U("text",{fg:n?t.primary:t.text,wrapMode:"none",children:o},void 0,!1,void 0,this)},void 0,!1,void 0,this),U("box",{width:nA,flexShrink:0,overflow:"hidden",children:U("text",{fg:d,wrapMode:"none",children:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),U("box",{flexGrow:1,overflow:"hidden",children:U("text",{fg:n?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 oA(e){let{palette:t,snippet:n,active:r,rowH:o,onPick:i,onCopy:s}=e,a=Lc(n.kind,t),c=px(n.kind,t),l=n.language==="toml"?"Copy TOML":"Copy JSON";return U("box",{height:o,flexDirection:"row",overflow:"hidden",backgroundColor:r?t.highlight:t.panel,onMouseDown:i,children:[U("box",{width:2,flexShrink:0,overflow:"hidden",children:U("text",{fg:a,children:r?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),U("box",{width:Ip,flexShrink:0,overflow:"hidden",children:U("text",{fg:a,wrapMode:"none",children:n.title},void 0,!1,void 0,this)},void 0,!1,void 0,this),U("box",{flexGrow:1,overflow:"hidden",children:U("text",{fg:t.muted,wrapMode:"none",children:n.path},void 0,!1,void 0,this)},void 0,!1,void 0,this),U(ge,{palette:t,label:l,bg:a,fg:c,onMouseDown:()=>{i(),s()}},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function iA(e){let{palette:t,tool:n,enabled:r,active:o,rowH:i,onPick:s,onToggle:a}=e;return U("box",{height:i,flexDirection:"row",overflow:"hidden",backgroundColor:o?t.highlight:t.panel,onMouseDown:()=>{if(o){a();return}s()},children:[U("box",{width:2,flexShrink:0,overflow:"hidden",children:U("text",{fg:t.primary,children:o?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),U("box",{width:5,flexShrink:0,overflow:"hidden",children:U("text",{fg:r?t.success:t.muted,wrapMode:"none",children:r?" ON ":" OFF "},void 0,!1,void 0,this)},void 0,!1,void 0,this),U("box",{width:Ip+4,flexShrink:0,overflow:"hidden",children:U("text",{fg:o?t.primary:r?t.text:t.muted,wrapMode:"none",children:n.label},void 0,!1,void 0,this)},void 0,!1,void 0,this),U("box",{width:7,flexShrink:0,overflow:"hidden",children:U("text",{fg:n.mutates?t.warning:t.muted,wrapMode:"none",children:n.mutates?"write":"read"},void 0,!1,void 0,this)},void 0,!1,void 0,this),U("box",{flexGrow:1,overflow:"hidden",children:U("text",{fg:o?t.text:t.muted,wrapMode:"none",children:o?`space or enter ${r?"disable":"enable"} ${n.name}`:n.summary},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function sA(e){let{palette:t,snippet:n,selected:r,brand:o}=e;if(!n)return null;let i=n.hint?` \xB7 ${n.hint}`:"";return U("box",{marginTop:1,flexDirection:"column",overflow:"hidden",children:[U("text",{fg:o,wrapMode:"none",children:r?`${n.title} \xB7 paste into ${n.path}${i}`:`Preview ${n.title} \xB7 j/k to a copy row, then enter`},void 0,!1,void 0,this),U("text",{fg:t.text,children:n.text},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Dp=0,Op=1,Jc=2,dw=4,tA,Ip=14,nA=14;var fw=D(()=>{at();be();Ye();Gi();tA={inspect:"Inspect",logs:"Logs",diagnostics:"Diagnostics",control:"Control",setup:"Setup"}});async function gw(e,t){e.suspend();try{return await t()}finally{e.resume(),e.intermediateRender()}}import{existsSync as aA,readFileSync as mw,writeFileSync as cA}from"fs";import{useCallback as Q,useEffect as gt,useMemo as En,useRef as Xe,useState as M}from"react";import{RGBA as lA}from"@opentui/core";import{useKeyboard as dA,useRenderer as uA,useTerminalDimensions as pA}from"@opentui/react";import{jsxDEV as ie,Fragment as hA}from"@opentui/react/jsx-dev-runtime";function hw({controller:e,tui:t,onQuit:n,bootError:r,bootErrorMissing:o=!1,terminalBackground:i}){let s=uA(),{width:a,height:c}=pA(),[l,d]=M(t.theme||e?.cfg.ui.theme||"devctl"),f=Xe(l),[g,m]=M(t.mouse),x=Xe(t.mouse),[v,w]=M(t.leader_timeout),E=Xe(t.leader_timeout),[k,j]=M(()=>ls(t.font_size)),V=Xe(k),C=hx(),y=En(()=>{let p=ux(l);if(Pc(l)!=="terminal"||!zu(i))return p;let u=i??p.background;return{...p,background:u,panel:u,element:u,inverse:u}},[i,l]),B=Pc(l)==="terminal"&&zu(i)?lA.defaultBackground(i??void 0):y.background,[h,q]=M(e?"dashboard":"setup"),[I,z]=M("none"),[ue,Ie]=M(""),[ct,oe]=M(0),[Ue,Ee]=M(0),[Qe,pe]=M(0),[Se,It]=M([]),[N,Pt]=M(),nt=En(()=>bx({themeName:l,fontSize:k,mouse:g,leaderMs:v,locked:C,configPath:C?t.path||tp():tp(),mcpRunning:N?.mcp?.running===!0}),[k,v,g,C,N?.mcp?.running,l,t.path]),[Ve,Wt]=M([]),[lt,tr]=M(!1),[mt,on]=M(!1),[sn,an]=M(!0),[Ur,_]=M(r??""),[cn,Rn]=M(),[Jt,Xc]=M(),[Qc,gs]=M(!1),[zo,Wp]=M(""),[Zc,el]=M(0),[_w,Gp]=M({active:"Preparing diagnostics",checks:[]}),Up=Xe(void 0),Yo=Xe(0),[Ew,Rw]=M({}),[Kp,Pw]=M(),[Ze,tl]=M(xc(e?.cfg)),[nr,Tw]=M(""),[Kr,qp]=M(!1),[Pn,Aw]=M(""),[ms,nl]=M(!1),[Vp,Lw]=M(0),[qr,Jp]=M(""),[hs,Dw]=M(""),[zt,Ft]=M(""),rr=gA,[zp,Ow]=M(t.log_timestamps!==!1),[Yp,Mw]=M(t.log_metadata!==!1),[Xp,$w]=M(()=>[...xy]),[vs]=M(""),[or]=M(""),[Tn,Iw]=M(!1),[ys,Qp]=M(),[Fw,Nw]=M(),[Vr,rl]=M(),[xs,ol]=M(),[Hw,Zp]=M(!1),[ef,Jr]=M(""),[Xo,tf]=M("focus"),[bt,An]=M(!1),[jw,Qo]=M(Nr-1),[Zo,bs]=M(!1),[ln,ws]=M(-1),[nf,Bw]=M(),[rf,of]=M(""),[sf,il]=M(!1),[af,cf]=M(!1),lf=Xe([]),ei=Xe(null),ti=Xe(null),ni=Xe(null),df=Xe(null),sl=Xe(null),uf=Xe(null),al=Xe(null),pf=Xe(null),[cl,Ww]=M(""),[Gw,Ss]=M(""),ll=Xe(""),dl=Xe(!1),[ff,ri]=M(0),[ks,ul]=M(""),[Cs,pl]=M(),[Uw,fl]=M([]),[gf,dn]=M(!1),[mf,gl]=M("start"),[ir,Ln]=M("quit"),[Dn,Kw]=M(()=>t.mcp_port??Do(e?.cfg.repoRoot??process.cwd())),oi=Xe(void 0),ml=Xe(0),[T,qw]=M(e?.cfg),Vw=e?.previousPersisted,[ii,hf]=M(void 0),vf=t.keybinds.copy??bn(),rt=En(()=>Object.keys(T?.services??{}).sort(),[T]),si=En(()=>rs(rt,Ve,Xp),[rt,Ve,Xp]),ai=En(()=>bv(ue),[ue]),zr=En(()=>jy(ue),[ue]);gt(()=>{$w((p)=>{let u=new Set(p),R=!1;for(let b of Ve)if(b.service!==""&&!rt.includes(b.service)&&!u.has(b.service))u.add(b.service),R=!0;return R?[...u].sort():p})},[Ve,rt]),gt(()=>{Ee(0)},[ue]),gt(()=>{if(I==="palette")oe(0)},[I,ue]);let ot=En(()=>Wo(Ve,{service:zt,services:rr,errorOnly:mt,search:Pn,regex:Tn,source:or,since:qr,until:hs,systemLogs:sn}),[mt,Tn,Pn,zt,rr,qr,or,hs,Ve,sn]),Fe=En(()=>Kv(ot,bt,ff),[ot,bt,ff]),On=Fe.items,un=Zv(h,{doctor:Jt?.checks.length??0,settings:nt.length,profiles:Object.keys(T?.profiles??{}).length,services:rt.length,logs:On.length,mcp:uw()}),yf=h==="logs"?jw:Qe,te=un<=0?Math.max(0,yf):Math.max(0,Math.min(yf,un-1)),pn=h==="detail"?nr:h==="services"?rt[te]??"":"",_s=xs?.name===pn,xf=_s?xs?.env:void 0,bf=pn===""?"config":Hw&&!_s?"loading":_s?"resolved":ef!==""?"error":"config",wf=_s||pn===""?"":ef;gt(()=>{ws(-1),An(!1),Qo(Math.max(0,Math.min(Nr,ot.length)-1))},[mt,Pn,zt,sn]),gt(()=>{if(h!=="logs")bs(!1)},[h]),gt(()=>{if(h!=="logs"||bt)return;Qo(Math.max(0,Math.min(Nr,ot.length)-1))},[ot.length,bt,h]),gt(()=>{if(h==="settings")return;d(f.current),j(V.current),w(E.current),m(x.current)},[h]);let hl=Q(()=>{if(!bt)ri(Hu(ot.length)),An(!0)},[ot.length,bt]),ci=Q((p)=>{let u=ju(p,un,Fe.start,Fe.newer);if(u.startDelta!==0){ri(Math.max(0,Fe.start+u.startDelta)),An(!0),Qo(u.selected);return}let R=Math.max(un-1,0),b=un>0&&(u.selected<R||Fe.newer>0);if(b&&!bt)ri(Hu(ot.length)),An(!0);else if(!b)An(!1);Qo(u.selected)},[ot.length,un,bt,Fe.newer,Fe.start]),Es=Q((p)=>{let u=On.length,R=ju(p,u,Fe.start,Fe.newer);if(R.startDelta!==0)ri(Math.max(0,Fe.start+R.startDelta)),An(!0);ws(R.selected)},[On.length,Fe.newer,Fe.start]),vl=Q(()=>{if(An(!1),ws(-1),h==="logs")Qo(Math.max(0,Math.min(Nr,ot.length)-1));Lw((p)=>p+1),_(Fe.newer>0?`Jumped to latest (+${Fe.newer} new)`:"Jumped to latest logs")},[ot.length,Fe.newer,h]),et=Q(()=>{if(z("none"),Ie(""),nl(!1),oi.current)clearTimeout(oi.current)},[]),yl=Q((p)=>{It((u)=>u.includes(p)?u.filter((R)=>R!==p):[...u,p])},[]),Ke=Q((p,u)=>{if(C){_(`${u} session only`);return}let R=gv(p);_(`${u} saved ${R}`)},[C]),Yr=Q((p)=>{d(p),f.current=p,Ke({theme:p},`theme ${p}`)},[Ke]),li=Q(()=>{let p=!g;m(p),x.current=p,Ke({mouse:p},`mouse ${p?"on":"off"} restart TUI to apply clicks`)},[g,Ke]),Rs=Q((p)=>{w(p),E.current=p,Ke({leader_timeout:p},`leader ${p}ms`)},[Ke]),sr=Q((p)=>{let u=ls(p);j(u),V.current=u,Ke({font_size:u},`display ${Dc(u)}`)},[Ke]),Sf=Q(()=>{let p=Zu();d(p.theme),f.current=p.theme,m(p.mouse),x.current=p.mouse,w(p.leader_timeout),E.current=p.leader_timeout,j(p.font_size),V.current=p.font_size,Ke(p,"restored default preferences")},[Ke]),xl=Q((p)=>{if(p.id==="theme"){oe(Math.max(0,yt.indexOf(l))),z("themes");return}if(p.id==="mouse"){li();return}if(p.id==="leader"){Rs(v);return}if(p.id==="font"){sr(k);return}if(p.id==="reset"){Ln("reset-prefs"),z("confirm");return}if(p.id==="mcp"){q("mcp"),pe(0);return}_(p.detail)},[sr,Rs,k,v,l,li]),kf=Q((p)=>{let u=Ko(nt,te);if(!u)return;if(u.id==="theme"){Yr(vx(l,p));return}if(u.id==="leader"){Rs(yx(v,p));return}if(u.id==="font"){sr(Oc(k,p));return}if(u.id==="mouse")li()},[sr,Rs,k,v,te,Yr,nt,l,li]),Jw=Q(()=>{d(f.current)},[]),ve=Q(async()=>{if(!e)return;try{let p=await e.status();if(Pt(p),p.profile&&Ze==="")tl(p.profile);return p}catch(p){_(O(p));return}},[e,Ze]),Xr=Q(async()=>{if(!e){_("Supervisor is not running");return}_("Probing configured identities\u2026");try{let p=await e.refreshAuth();Pt((W)=>W?{...W,identity:p}:W);let u=Object.values(p.service_account_status),R=u.filter((W)=>W==="available").length,b=u.filter((W)=>W==="unavailable").length;_(u.length===0?"Identity refreshed \u2014 no service accounts configured":`Identity refreshed \u2014 ${R} available${b>0?`, ${b} unavailable`:""}`)}catch(p){_(O(p))}},[e]),Ps=Q((p)=>{let u=Or(p);Kw(u);let R=T?.repoRoot??process.cwd();if(uv(R,u)){Ke({mcp_port:null},`MCP port ${u} (default)`);return}Ke({mcp_port:u},`MCP port ${u}`)},[T,Ke]),Qr=Q(()=>{if(ks==="")return Dn;let p=dv(ks,Dn);return ul(""),Ps(p),p},[Dn,ks,Ps]),Cf=Q(async(p)=>{if(!e||N?.mcp?.running!==!0)return;await e.mcpStop(),await e.mcpStart({port:p}),await ve()},[e,ve,N?.mcp?.running]),bl=Q(async(p)=>{if(!e){_("Supervisor is not running");return}let u=N?.mcp?.disabled_tools??[],R=qn(p.name,u),b=R?[...u,p.name]:u.filter((W)=>W!==p.name);try{let W=await e.mcpSetTools(b);Ke({mcp_disabled_tools:W},`${p.label} ${R?"disabled":"enabled"}`),await ve()}catch(W){_(O(W))}},[e,Ke,ve,N]),Ts=Q(async()=>{if(!e){_("Supervisor is not running");return}try{if(N?.mcp?.running)await e.mcpStop(),Ke({mcp_enabled:!1},"MCP off"),_("MCP stopped");else await e.mcpStart({port:Dn}),Ke({mcp_enabled:!0},"MCP on"),_("MCP started");await ve()}catch(p){_(O(p))}},[e,Dn,Ke,ve,N?.mcp?.running]),wl=Q((p)=>{op(p.text).then(()=>{_(`Copied ${p.title} snippet`)}).catch((u)=>{_(O(u))})},[]),As=Q((p)=>{let u=$p(p);if(u===void 0)return!1;let R=N?.mcp?.address??Oo(N?.mcp?.port??Dn),b=Ji(R,N?.mcp?.token??"")[u];if(!b)return!1;return wl(b),!0},[wl,Dn,N?.mcp?.address,N?.mcp?.port,N?.mcp?.token]),Zr=En(()=>({services:zt!==""?[zt]:rr,level:mt?"ERROR":vs,search:Pn,regex:Tn,source:or,since:qr,until:hs}),[mt,vs,Tn,Pn,zt,rr,qr,or,hs]),Ls=Q(async()=>{if(!e)return;try{Bw(await e.logsStats(Zr))}catch(p){_(O(p))}},[e,Zr]),_f=Q(async()=>{if(!e||lt)return;try{let p=await e.logsPage(Zr);Wt((u)=>wy(u,p.events)),of(p.prevCursor),il(p.hasPrev),await Ls()}catch(p){_(O(p))}},[e,Zr,lt,Ls]),di=Q(()=>{Wt([]),Jp(new Date().toISOString()),An(!1),_("Cleared on-screen log buffer")},[]),ui=Q(()=>{an((p)=>!p)},[]);gt(()=>{ve().then(()=>_f())},[ve,_f]),gt(()=>{lf.current=Ve},[Ve]),gt(()=>{if(!e||af||!ky(bt,Fe.start,sf))return;cf(!0),e.logsPage({...Zr,cursor:rf,direction:"backward"}).then((p)=>{if(p.sessionChanged){_("Daemon session changed \u2014 older log history is no longer available"),il(!1);return}let u=lf.current,R=Sy(u,p.events);if(Wt(R),R.length>u.length)ri((b)=>b+(R.length-u.length));of(p.prevCursor),il(p.hasPrev)}).catch((p)=>_(O(p))).finally(()=>cf(!1))},[e,Zr,af,sf,bt,rf,Fe.start]),gt(()=>{if(!e||lt||h!=="logs")return;let p=setInterval(()=>{Ls()},mA);return()=>clearInterval(p)},[e,lt,Ls,h]),gt(()=>{if(!e)return;let p,u=!1,R=[],b=T&&T.logs.max_memory_events>0?T.logs.max_memory_events:50000,W=()=>{if(p=void 0,R.length>0){let S=R.splice(0,R.length);Wt((le)=>by(le,S,qr,b))}if(u)u=!1,ve()},Mn=e.onEvent((S)=>{if(S.type===ha&&S.payload&&typeof S.payload==="object"&&"event"in S.payload){let le=S.payload.event;if(!lt)R.push(le);if(!p)p=setTimeout(W,30);return}if(S.type===Ti){hf(zy(S));return}if(S.type===va)hf(void 0),e.configSnapshot().then(qw).catch((le)=>_(O(le)));if(u=!0,!p)p=setTimeout(W,30)});return()=>{if(Mn(),p)clearTimeout(p)}},[e,qr,lt,ve]),gt(()=>{Ot(T?.google.project_id??"").then(Rn).catch((p)=>{_(O(p))})},[T?.google.project_id,N?.identity.project]),gt(()=>{if(h!=="doctor"||!T)return;let p=Up.current,u=N?.session_id??"";if(p?.cfg===T&&p.tick===Zc&&p.sessionID===u&&p.reloadError===ii)return;Up.current={cfg:T,tick:Zc,sessionID:u,reloadError:ii};let R=++Yo.current;gs(!0),Wp(""),Gp({active:"Preparing diagnostics",checks:[]});let b;if(T.configPath!==""){b="";try{xi(T.repoRoot,T.configPath)}catch(W){b=O(W)}}Un(T,void 0,(W)=>{if(R===Yo.current)Gp(W)},{services:N?.services,proxyRunning:N?.proxy.running,repositoryConfigError:b}).then((W)=>{if(R!==Yo.current)return;Xc(W)}).catch((W)=>{if(R!==Yo.current)return;Wp(O(W))}).finally(()=>{if(R===Yo.current)gs(!1)})},[h,T,Zc,N?.session_id,ii]);let ar=Q((p)=>{Tw(p),q("detail")},[]),Ef=Q((p)=>{let u=p.value!==""?p.value:p.required?"(required, not set)":"(empty)";rl({title:p.key,body:u}),z("scroll-text")},[]);gt(()=>{ol(void 0),Jr("")},[T]),gt(()=>{if(!e||pn===""||!T?.services[pn])return;if(xs?.name===pn)return;let p=!1;return Zp(!0),Jr(""),e.execService(pn,[],!0).then((u)=>{if(p)return;ol({name:pn,env:u.environment??{}}),Jr("")}).catch((u)=>{if(p)return;Jr(O(u))}).finally(()=>{Zp(!1)}),()=>{p=!0}},[T,e,pn,xs?.name]);let fn=Q(async(p,u)=>{if(!e||!T){_("no configuration loaded");return}try{let R=Ca(T,{services:p,profile:u}),b=$i(T,R.services,R.profile);gl("start"),fl(b.waves.flat().filter((S)=>es(N?.services[S]))),pl(b),z("plan"),dn(!0);let W=R.services.filter((S)=>!es(N?.services[S])),Mn=await e.start({services:W.length>0?W:R.services,profile:R.profile});await ve(),dn(!1),_(Ay(Mn))}catch(R){dn(!1),await ve(),_(O(R))}},[T,e,ve,N]),Ds=Q(async(p)=>{if(!e||!T){_("no configuration loaded");return}let u=p.length>0?p:Object.entries(N?.services??{}).filter(([,R])=>R.state!=="STOPPED"&&R.state!=="UNKNOWN").map(([R])=>R);if(u.length===0){_("nothing to stop");return}try{let R=Ii(T,u);gl("stop"),fl([]),pl(R),z("plan"),dn(!0),await e.stop(p),await ve(),dn(!1),_(Ly(R))}catch(R){dn(!1),await ve(),_(O(R))}},[T,e,ve,N]),pi=Q(async(p,u)=>{if(!e||!T){_("no configuration loaded");return}try{let R=Qv(T,p,u),b=$i(T,R.services,R.profile);gl("restart"),fl([]),pl(b),z("plan"),dn(!0),await e.restart(p),await ve(),dn(!1),_(os(b)===""?"Restarted selected services":`Restarted ${os(b)}`)}catch(R){dn(!1),await ve(),_(O(R))}},[T,e,ve]),Os=Q(async(p="")=>{let u=I==="log-details"&&ys?_y(ys):I==="scroll-text"&&Vr?Vr.body:Ey(ot),R=p===""?"":` \xB7 ${p}`;if(u.trim()===""){_(`No logs to copy${R}`);return}try{await op(u);let b=u.split(`
|
|
628
|
-
`)
|
|
629
|
-
`)),_("Config buffer not saved");return}if(cA(T.configPath,p),Ss(""),z("none"),!e){_(`Wrote ${T.configPath}`);return}e.reload().then((R)=>{if(_(R.restart_required.length===0?"Configuration saved and reloaded":`Saved; restart required: ${R.restart_required.join(", ")}`),R.restart_required.length>0)Ln("reload"),z("confirm");ve()})},[T,cl,e,ve]),gn=Q(async(p,u)=>{if(dl.current)return;if(dl.current=!0,p.name!=="start"&&p.name!=="stop"&&p.name!=="restart")z("none");Ie("");let R=yy(u,Se);try{switch(p.name){case"exit":Ln("quit"),z("confirm");return;case"help":z("help");return;case"version":_(Dt()),Yi().then((b)=>_(_u(b))).catch((b)=>_(O(b)));return;case"update":_("checking for update\u2026"),Yi().then((b)=>_(_u(b))).catch((b)=>_(O(b)));return;case"themes":if(u[0]){Yr(u[0]);return}oe(Math.max(0,yt.indexOf(l))),Ie(""),z("themes");return;case"settings":q("settings"),pe(0);return;case"dashboard":case"services":q(p.name);return;case"logs":if(u[0])Ft(u[0]);q("logs");return;case"fullscreen":q("logs"),bs((b)=>h==="logs"?!b:!0);return;case"auth":{let b=(u[0]??"").toLowerCase();if(b==="refresh"){q("auth"),await Xr();return}if(b==="login"){q("auth"),_("starting gcloud ADC login\u2026");try{await gw(s,()=>mo()),Rn(await Ot(T?.google.project_id??"")),await Xr(),_("ADC login complete")}catch(W){_(O(W))}return}if(b==="logout"){q("auth"),_("revoking ADC\u2026");try{await la(),Rn(await Ot(T?.google.project_id??"")),await Xr(),_("ADC revoked")}catch(W){_(O(W))}return}q("auth");return}case"credentials":case"proxy":case"mcp":case"config":case"profiles":case"setup":q(p.name);return;case"diff":if(!T){_("no configuration loaded");return}rl({title:"config sources",body:ax(T,Kr)}),z("scroll-text");return;case"daemon":{let b=T?.repoRoot;if(!b){_("no repository");return}let W=ur(b);if(!aA(W)){_("no daemon bootstrap log yet for this repository");return}rl({title:"daemon bootstrap",body:mw(W,"utf8")}),z("scroll-text");return}case"reload":if(!e)return;e.reload().then((b)=>{if(_(b.restart_required.length===0?"Configuration reloaded":`Reload requires restart: ${b.restart_required.join(", ")}`),b.restart_required.length>0)Ln("reload"),z("confirm");ve()});return;case"doctor":q("doctor");return;case"stats":q("stats");return;case"start":await fn(R,Ze);return;case"stop":await Ds(R);return;case"restart":await pi(R,Ze);return;case"run":{let b=u[0]??"";if(!e||!b){_(b?"no daemon attached":"usage: /run <task>");return}try{let W=await e.runTask(b);Ft(`task:${b}`),q("logs"),_(`task ${b} exited ${W.code}`)}catch(W){throw Ft(`task:${b}`),q("logs"),W}return}case"exec":{let b=kv(u);if(!e||!b.service){_(b.service?"no daemon attached":"usage: /exec <service> -- <command\u2026>");return}if(b.printEnv){if(!T?.services[b.service]){_(`unknown service ${b.service}`);return}if(b.reveal)qp(!0);_(`Resolving environment for ${b.service}\u2026`);try{let W=await e.execService(b.service,[],!0);ol({name:b.service,env:W.environment??{}}),Jr(""),ar(b.service),_(`Resolved environment for ${b.service}`)}catch(W){Jr(O(W)),ar(b.service),_(O(W))}return}if(b.command.length===0){_("usage: /exec <service> -- <command\u2026>");return}try{let W=await e.execService(b.service,b.command);Ft(`${b.service}:exec`),q("logs"),_(`${b.service}:exec exited ${W.code}`)}catch(W){throw Ft(`${b.service}:exec`),q("logs"),W}return}case"refresh":if(h==="auth"){await Xr();return}await ve(),_("Refreshed status and logs");return;case"pause":tr((b)=>!b),q("logs");return;case"filter":on((b)=>!b),q("logs");return;case"system":ui(),q("logs");return;case"clear":di();return;case"reveal":{let b=!Kr;qp(b),_(b?"Secrets visible this session":"Secrets hidden");return}case"wrap":{let b=Nu(Xo);tf(b),_(`Log ${Qi(b)}`);return}case"copy":await Os();return;case"export":{let b=Eo(u[0]);if(e)await e.logs({export:b,services:rr,level:mt?"ERROR":vs,search:Pn,regex:Tn,source:or});else Ma(b,ot);ll.current=b,_(`Exported ${b}`);return}case"exports":{let b=ll.current||dr();$a(b),_(`Opened ${dr()}`);return}case"regex":Iw((b)=>!b),_(Tn?"Substring search":"Regex search");return;case"since":Jp(u[0]||new Date(Date.now()-3600000).toISOString()),_(`Logs since ${u[0]||"1h"}`);return;case"until":Dw(u[0]||new Date().toISOString()),_(`Logs until ${u[0]||"now"}`);return;case"history":{let{listSessions:b,loadSessionEvents:W}=await Promise.resolve().then(() => (Ar(),mh)),Mn=b(),S=u[0]||Mn[0];if(!S){_("No persisted log sessions");return}Wt(W(S)),_(`Loaded session ${S}`);return}case"buffer":Sl();return;case"edit":{if(!T)return;let b=process.env.DEVCTL_EDITOR||process.env.EDITOR,W=b?[b,T.configPath]:process.platform==="darwin"?["open",T.configPath]:["xdg-open",T.configPath];Bun.spawn({cmd:W,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),_(`Opened ${T.configPath} in ${W[0]}. Run /reload after saving.`);return}default:_(`/${p.name}`)}}catch(b){_(O(b))}finally{setTimeout(()=>{dl.current=!1},fA)}},[pi,fn,Ds,Se,T,di,e,Os,mt,ot,vs,Tn,Pn,rr,or,Xo,Sl,ar,Yr,Ze,ve,Xr,s,Kr,h,l,ui]),Yw=Q(()=>{let p=ll.current||dr();$a(p),_(`Opened ${dr()}`)},[]),kl=Q(()=>{let p=Hr(ai,Ue);if(!p){_(ue.trim()===""?"pick a command from the list":`unknown command /${ue}`),et();return}let R=zi(ue)?.name===p.name?wv(ue):[];gn(p,R)},[et,ai,ue,gn,Ue]),Rf=Q((p)=>{Yr(p),et()},[et,Yr]),Xw=Q((p)=>{let u=zi(p);if(u)gn(u,[])},[gn]),Pf=Q(()=>{if(I==="palette"){let p=Hr(zr,ct);if(p)gn(p,[]);return}kl()},[I,ct,zr,gn,kl]),Qw=Q(()=>{if(T?.shutdown.stop_services_on_exit===void 0){Ln("quit"),z("confirm");return}n(T.shutdown.stop_services_on_exit===!1)},[T,n]),Zw=Q(()=>{if(ir==="quit"){n(!1);return}if(ir==="reload"){et();let p=N?.restart_required??[];if(p.length>0)pi(p,Ze);return}if(ir==="reset-prefs"){et(),Sf();return}if(ir==="free-port"){let p=Kp;if(et(),!p)return;ua(p).then(()=>{_(`Stopped ${p.command} (pid ${p.pid}) on port ${p.port}`),el((u)=>u+1)}).catch((u)=>{_(O(u))});return}et(),fn([],Ze)},[Sf,pi,fn,et,ir,n,Kp,Ze,N]),eS=Q(()=>{if(h==="logs"){let u=On[te];if(u)Qp(u),z("log-details");return}if(h==="profiles"){let R=Object.keys(T?.profiles??{}).sort()[te];if(R)tl(R),Ln("start-profile"),z("confirm");return}if(h==="doctor"){let u=Jt?.checks[te];if(u?.action?.kind==="free-port"){let R=u.action.holder;Pw(R),Rw({port:R.port,pid:R.pid,process:R.command}),Ln("free-port"),z("confirm")}return}if(h==="mcp"){if(te===0){Ts();return}if(te===1){Qr();return}let u=Yc(te);if(u){bl(u);return}As(te);return}if(h==="settings"){let u=Ko(nt,te);if(u)xl(u);return}if(h==="dashboard"&&Bo(N)){fn([],Ze);return}let p=rt[te];if(p&&(h==="dashboard"||h==="services"))ar(p)},[xl,Qr,fn,T,As,Jt,te,On,rt,ar,Ze,h,nt,N,Ts]);dA((p)=>{let u=(p.name??"").toLowerCase(),R=jx(p,t),b=Hx(p,t);if(R&&!b){if(h==="mcp"&&As(te))return;Os();return}if(b){let S=Date.now();if(Bx(S,ml.current)){ml.current=0,Qw();return}ml.current=S;let le="Ctrl+C again to quit";if(R)Os(le);else _(`Press ${le}`);return}if(p.ctrl&&(u==="="||u==="+"||u==="plus")){sr(Oc(k,1));return}if(p.ctrl&&(u==="-"||u==="_"||u==="minus")){sr(Oc(k,-1));return}if(p.ctrl&&u==="0"){sr(Zu().font_size);return}if(I==="confirm"){if(u==="escape"){et();return}if(ir==="quit"&&u==="d"){n(!0);return}if(u==="return")Zw();return}if(I==="log-details"||I==="scroll-text"){if(u==="escape"){et();return}let S=I==="log-details"?df.current:uf.current;if(u==="down"||u==="j"){We(S,t.scroll_speed);return}if(u==="up"||u==="k"){We(S,-t.scroll_speed);return}if(Fc(p)){We(S,Zi(c));return}if(Nc(p)){We(S,-Zi(c));return}return}if(I==="route-details"){if(u==="escape"||u==="return"){et();return}if(u==="down"||u==="j"){We(sl.current,t.scroll_speed);return}if(u==="up"||u==="k"){We(sl.current,-t.scroll_speed);return}return}if(I==="plan"){if(u==="escape"||u==="return"&&!gf){et();return}if(u==="down"||u==="j"){We(al.current,t.scroll_speed);return}if(u==="up"||u==="k"){We(al.current,-t.scroll_speed);return}return}if(I==="help"){if(u==="escape"){et();return}if(u==="down"||u==="j"){We(ti.current,1);return}if(u==="up"||u==="k"){We(ti.current,-1);return}if(u==="pagedown"||Fc(p)){We(ti.current,pp);return}if(u==="pageup"||Nc(p)){We(ti.current,-pp);return}return}if(I==="themes"){if(u==="escape"){Jw(),et();return}if(u==="down"||u==="j"){oe((S)=>{let le=Math.min(S+1,yt.length-1),mn=yt[le];if(mn)d(mn);return le});return}if(u==="up"||u==="k"){oe((S)=>{let le=Math.max(0,S-1),mn=yt[le];if(mn)d(mn);return le});return}if(u==="return"){let S=yt[ct%yt.length];if(S)Rf(S)}return}if(I==="leader"){if(oi.current)clearTimeout(oi.current);z("none");let S=Sv(u),le=S?zi(S):void 0;if(le)gn(le,[]);return}if(I==="config-edit"){if(u==="escape"){Ss(""),et();return}if(p.ctrl&&u==="s"){zw();return}return}if(Lx(I)){if(u==="escape"){et();return}if(I==="slash"&&u==="down"){Ee((S)=>Math.min(Math.max(ai.length-1,0),S+1));return}if(I==="slash"&&u==="up"){Ee((S)=>Math.max(0,S-1));return}if(I==="slash"&&u==="tab"){if(p.shift){Ee((le)=>Math.max(0,le-1));return}let S=Hr(ai,Ue);if(S)Ie(`${S.name} `);return}if(I==="slash"&&u==="return"){kl();return}if(I==="palette"&&u==="down"){oe((S)=>Math.min(S+1,Math.max(zr.length-1,0)));return}if(I==="palette"&&u==="up"){oe((S)=>Math.max(0,S-1));return}if(I==="palette"&&u==="return"){let S=Hr(zr,ct);if(S)gn(S,[])}return}if(ms){if(u==="escape")nl(!1);return}if(Dx(p,t)){z("leader"),oi.current=setTimeout(()=>z("none"),v);return}if(Ox(p,t)){Ie(""),oe(0),z("palette");return}if(Mx(p,t)){Ie(""),Ee(0),z("slash");return}if($x(p,t)){z("help");return}if(Ix(p,t)||h==="logs"&&u==="f"&&!p.ctrl&&!p.meta){q("logs"),nl(!0);return}if(u==="escape"){if(Zo){bs(!1);return}if(h==="detail"){q("services");return}if(h==="setup")if(e)q("dashboard");else n(!0);return}if(u==="z"&&(h==="logs"||h==="dashboard")&&!p.ctrl&&!p.meta){q("logs"),bs((S)=>h==="logs"?!S:!0);return}let W=(h==="logs"||h==="dashboard")&&!ms;if(W&&(u==="left"||u==="["||h==="logs"&&u==="h")){Ft(Gu(si,zt,-1));return}if(W&&(u==="right"||u==="]"||h==="logs"&&u==="l")){Ft(Gu(si,zt,1));return}if(h==="logs"&&!ms&&u.length===1&&u>="1"&&u<="9"){let S=Ty(si,Ve,Number(u));if(S!==void 0)Ft(S);return}if(u==="tab"){q(p.shift?Ny(h):Fy(h));return}let Mn=ey(u);if(Mn){q(Mn);return}if((h==="dashboard"||h==="setup")&&u==="o"){q("profiles");return}if((h==="dashboard"||h==="services")&&(u==="*"||p.shift&&u==="8")){It([...rt]),_(`Selected ${rt.length} services`);return}if((h==="dashboard"||h==="services")&&(u==="-"||u==="_"||u==="minus")){It([]),_("Selection cleared");return}if((h==="dashboard"||h==="services")&&u==="n"){fn(kc(Se,rt[te]??""),Ze);return}if((h==="dashboard"||h==="services")&&u==="x"){Ds(kc(Se,rt[te]??""));return}if((h==="dashboard"||h==="services"||h==="detail")&&Fx(p)){pi(kc(Se,rt[te]??nr),Ze);return}if((h==="dashboard"||h==="services")&&u==="r"){ve(),_("Refreshed");return}if(h==="auth"&&u==="r"){Xr();return}if(h==="logs"&&u==="t"){let S=!zp;Ow(S),Ke({log_timestamps:S},S?"timestamps on":"timestamps off");return}if(h==="logs"&&u==="m"){let S=!Yp;Mw(S),Ke({log_metadata:S},S?"metadata on":"metadata off");return}if(u==="down"||u==="j"){if(h==="mcp"&&te===1)Qr();if(h==="config"){We(ei.current,t.scroll_speed);return}if(h==="detail"){We(ni.current,t.scroll_speed);return}if(h==="logs"){ci(te+1);return}if(h==="dashboard"&&ln>=0){Es(ln+1);return}pe((S)=>Math.min(Math.max(un-1,0),S+1));return}if(u==="up"||u==="k"){if(h==="mcp"&&te===1)Qr();if(h==="config"){We(ei.current,-t.scroll_speed);return}if(h==="detail"){We(ni.current,-t.scroll_speed);return}if(h==="logs"){ci(te-1);return}if(h==="dashboard"&&ln>=0){Es(ln-1);return}pe((S)=>Math.max(0,Math.min(S,Math.max(un-1,0))-1));return}if(Fc(p)){let S=Zi(c);if(h==="config"){We(ei.current,S);return}if(h==="detail"){We(ni.current,S);return}if(h==="logs"){ci(te+S);return}if(h==="dashboard"&&(bt||ln>=0)){Es(Math.max(0,ln)+S);return}pe((le)=>Math.min(Math.max(un-1,0),le+S));return}if(Nc(p)){let S=Zi(c);if(h==="config"){We(ei.current,-S);return}if(h==="detail"){We(ni.current,-S);return}if(h==="logs"){ci(te-S);return}if(h==="dashboard"&&(bt||ln>=0)){Es(Math.max(0,ln)-S);return}pe((le)=>Math.max(0,le-S));return}if(h==="proxy"&&u==="n"){e?.proxyStart().then(async()=>{_("Proxy started"),await ve()});return}if(h==="proxy"&&u==="x"){e?.proxyStop().then(async()=>{_("Proxy stopped"),await ve()});return}if(h==="detail"&&nr!==""){if(u==="n"){fn([nr],Ze);return}if(u==="x"){Ds([nr]);return}if(u==="o"){q("config");return}if(u==="l"){Ft(nr),q("logs");return}}if(h==="mcp"&&te===1&&(u==="left"||u==="h")){let S=Or(Qr()-1);Ps(S),Cf(S);return}if(h==="mcp"&&te===1&&(u==="right"||u==="l")){let S=Or(Qr()+1);Ps(S),Cf(S);return}if(h==="mcp"&&te===1&&(u==="backspace"||u==="delete")){ul((S)=>lv(S));return}if(h==="mcp"&&te===1&&u.length===1&&u>="0"&&u<="9"){ul((S)=>cv(S,u));return}if(h==="settings"&&(u==="left"||u==="h")){kf(-1);return}if(h==="settings"&&(u==="right"||u==="l")){kf(1);return}if(u==="space"){if(h==="profiles"){let mn=Object.keys(T?.profiles??{}).sort()[te];if(mn)tl(mn),_(`Profile ${mn}`);return}if(h==="mcp"){if(te===0){Ts();return}let le=Yc(te);if(le){bl(le);return}As(te);return}if(h==="logs")return;if(h==="settings"){if(Ko(nt,te)?.id==="mouse")li();return}let S=rt[te];if(S)yl(S);return}if(u==="return"){if(h==="setup"&&!e){if(!o){_(r||"Existing configuration is invalid \u2014 fix it and restart devctl.");return}Promise.resolve().then(() => (Jd(),Qm)).then(({createStarterConfig:S})=>{try{let le=S(process.cwd());_(`Wrote ${le}. Restart devctl or run the CLI wizard.`)}catch(le){_(O(le))}});return}if(h==="setup"&&e){fn([],Ze);return}eS();return}if(u==="q"){if(T?.shutdown.stop_services_on_exit===!1){n(!0);return}if(T?.shutdown.stop_services_on_exit===!0){n(!1);return}Ln("quit"),z("confirm");return}if(Yn(p,t,"services","s")&&I==="none"&&h!=="logs"){q("services");return}if(Yn(p,t,"logs","l")&&I==="none"&&h!=="detail"&&h!=="logs"&&h!=="settings"){q("logs");return}if(Yn(p,t,"auth","a")&&I==="none"){q("auth");return}if(Yn(p,t,"proxy","p")&&I==="none"&&h!=="logs"){q("proxy");return}if(Yn(p,t,"doctor","d")&&I==="none"&&h!=="doctor"){q("doctor");return}if(Yn(p,t,"config","c")&&I==="none"){q("config");return}if(Yn(p,t,"setup","u")&&I==="none"){q("setup");return}if(h==="config"&&u==="e"){gn(zi("/edit")??{name:"edit",aliases:[],desc:"",leader:"",group:"ui"},[]);return}if(h==="config"&&u==="v"){Sl();return}if(h==="doctor"&&u==="r"){el((S)=>S+1),_("Re-running doctor");return}if(h==="logs"&&u==="p"){tr((S)=>!S);return}if((h==="logs"||h==="dashboard")&&u==="g"){vl();return}if((h==="logs"||h==="dashboard")&&u==="w"){let S=Nu(Xo);tf(S),_(`Log ${Qi(S)}`);return}if((h==="logs"||h==="dashboard")&&u==="e"){on((S)=>!S);return}if((h==="logs"||h==="dashboard")&&u==="i"){ui(),_(sn?"Hiding internal auth/mcp/devctl/proxy logs":"Showing internal logs");return}if((h==="logs"||h==="dashboard")&&Nx(p))di()});let Tf=qy(ir,Ze,Ew),tS=new Set(Cs?.waves.flat()??[]),nS=Cs===void 0||mf==="stop"?"":Object.entries(N?.services??{}).find(([p,u])=>tS.has(p)&&u.state==="FAILED")?.[0]??"";return ie(np.Provider,{value:ds(k),children:ie("box",{flexDirection:"column",width:a,height:c,backgroundColor:B,overflow:"hidden",children:[Zo?null:ie(hA,{children:[ie(Cx,{palette:y,cfg:T,snap:N,google:cn,profile:Ze,reveal:Kr,width:a},void 0,!1,void 0,this),ie(_x,{palette:y,screen:h,width:a,onSelect:q},void 0,!1,void 0,this),ii?ie("box",{height:1,paddingLeft:1,backgroundColor:y.panel,overflow:"hidden",children:ie("text",{fg:y.error,wrapMode:"none",children:`\u26A0 configuration reload failed: ${ii}`},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),ie("box",{flexGrow:1,overflow:"hidden",children:[h==="dashboard"?ie(Ob,{palette:y,cfg:T,snap:N,logs:Ve,names:rt,selected:te,checked:Se,profile:Ze,google:cn,width:a,paused:lt,followTick:Vp,logService:zt,errorOnly:mt,showSystemLogs:sn,onOpen:ar,onSelectIndex:pe,selectedLog:ln,onToggle:yl,logSources:si,onFilterService:Ft,onToggleErrors:()=>on((p)=>!p),onToggleSystemLogs:ui,onClearLogs:di,onShowErrors:()=>{Ft(""),on(!0)},wrapMode:Xo,view:On,follow:!bt,onLeaveLatest:hl,onPickLog:(p)=>{let u=On[p];if(!u)return;ws(p),Qp(u),hl()},viewStart:Fe.start,viewTotal:ot.length,newer:Fe.newer,onJumpLatest:vl,facets:nf,leftover:Vw},void 0,!1,void 0,this):null,h==="services"?ie(Xb,{palette:y,cfg:T,names:rt,snap:N,selected:te,checked:Se,width:a,reveal:Kr,onOpen:ar,onSelectIndex:pe,onToggle:yl,resolvedEnv:xf,envStatus:bf,envError:wf,onSelectEnv:Ef},void 0,!1,void 0,this):null,h==="detail"?ie(Yb,{palette:y,cfg:T,snap:N,name:nr,reveal:Kr,width:a,envScrollRef:ni,resolvedEnv:xf,envStatus:bf,envError:wf,onSelectEnv:Ef},void 0,!1,void 0,this):null,h==="logs"?ie(Lb,{palette:y,logs:Ve,names:rt,logSources:si,service:zt,paused:lt,errorOnly:mt,showSystemLogs:sn,search:Pn,searchFocused:ms,followTick:Vp,width:a,onSearch:Aw,onService:Ft,onToggleErrors:()=>on((p)=>!p),onToggleSystemLogs:ui,onClearLogs:di,source:or,regex:Tn,services:rr,showTimestamps:zp,showMeta:Yp,view:On,wrapMode:Xo,selected:te,follow:!bt,newer:Fe.newer,viewStart:Fe.start,viewTotal:ot.length,onSelect:ci,fullscreen:Zo,onLeaveLatest:hl,onOpenExports:Yw,onJumpLatest:vl,facets:nf},void 0,!1,void 0,this):null,h==="auth"?ie(wb,{palette:y,cfg:T,google:cn,identity:N?.identity},void 0,!1,void 0,this):null,h==="credentials"?ie(kb,{palette:y,credentials:N?.credentials},void 0,!1,void 0,this):null,h==="proxy"?ie(qb,{palette:y,cfg:T,snap:N,width:a,onSelectRoute:(p)=>{Nw(p),z("route-details")}},void 0,!1,void 0,this):null,h==="mcp"?ie(pw,{palette:y,snap:N,port:Dn,portDraft:ks,selected:te,onPick:pe,onToggle:()=>{Ts()},onCopy:wl,onToggleTool:(p)=>{bl(p)}},void 0,!1,void 0,this):null,h==="doctor"?ie(Ib,{palette:y,report:Jt,loading:Qc,progress:_w,error:zo,selected:te,onPick:pe,onReload:()=>{el((p)=>p+1),_("Re-running doctor")}},void 0,!1,void 0,this):null,h==="stats"?ie(iw,{palette:y,cfg:T,snap:N,width:a,onRefresh:ve},void 0,!1,void 0,this):null,h==="config"?ie(Pb,{palette:y,cfg:T,width:a,scrollRef:ei},void 0,!1,void 0,this):null,h==="profiles"?ie(Hb,{palette:y,cfg:T,snap:N,profile:Ze,selected:te,onPick:pe},void 0,!1,void 0,this):null,h==="setup"?ie(aw,{palette:y,cfg:T,google:cn,bootError:r,bootErrorMissing:o,step:te},void 0,!1,void 0,this):null,h==="settings"?ie(nw,{palette:y,items:nt,selected:te,locked:C,width:a,onPick:pe,onActivate:xl},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),I==="slash"?ie(gb,{palette:y,items:ai,query:ue,selected:Ue,onQuery:Ie,onSubmit:Pf},void 0,!1,void 0,this):null,I==="palette"?ie(ob,{palette:y,items:zr,selected:Math.min(ct,Math.max(zr.length-1,0)),termW:a,termH:c,onIndex:oe,onPick:Xw},void 0,!1,void 0,this):null,I==="themes"?ie(xb,{palette:y,themeName:l,selected:ct%yt.length,termW:a,termH:c,onIndex:oe,onPreview:d,onPick:Rf},void 0,!1,void 0,this):null,I==="help"?ie(Qx,{palette:y,termW:a,termH:c,copyKey:vf,scrollRef:ti},void 0,!1,void 0,this):null,I==="leader"?ie(tb,{palette:y,termW:a,termH:c},void 0,!1,void 0,this):null,I==="confirm"?ie(Kx,{palette:y,title:Tf.title,body:Tf.body,termW:a,termH:c},void 0,!1,void 0,this):null,I==="log-details"?ie(Vx,{palette:y,event:ys,termW:a,termH:c,scrollRef:df},void 0,!1,void 0,this):null,I==="route-details"?ie(lb,{palette:y,route:Fw,termW:a,termH:c,scrollRef:sl},void 0,!1,void 0,this):null,I==="scroll-text"&&Vr?ie(ub,{palette:y,title:Vr.title,body:Vr.body,termW:a,termH:c,scrollRef:uf},void 0,!1,void 0,this):null,I==="config-edit"&&T?ie(Gx,{palette:y,path:T.configPath,initialValue:cl,error:Gw,termW:a,termH:c,textareaRef:pf},void 0,!1,void 0,this):null,I==="plan"&&Cs?ie(ab,{palette:y,plan:Cs,snap:N,busy:gf,failed:nS,kind:mf,termW:a,termH:c,scrollRef:al,initiallyRunning:Uw,onDismiss:et},void 0,!1,void 0,this):null,I==="slash"||I==="plan"||I==="config-edit"||Zo||Yv(c)&&I==="none"?null:ie(Ex,{palette:y,overlay:I,query:ue,onQuery:Ie,onSubmit:Pf},void 0,!1,void 0,this),Zo?null:ie(Rx,{palette:y,screen:h,overlay:I,status:Ur,paused:lt,errorOnly:mt,width:a,copyKey:vf},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var fA=50,gA,mA=2000;var vw=D(()=>{st();Oi();Ri();Sr();Re();Ar();ze();Rr();Ja();Eu();Ku();Et();Ax();Pe();Wx();be();Ux();qx();Jx();Zx();nb();ib();cb();db();pb();mb();bb();Sb();Cb();Tb();Mb();Fb();wp();jb();Vb();Pp();Qb();rw();sw();cw();fw();Gi();at();Cn();Ye();Zt();gA=[]});var yw={};Ms(yw,{renderApp:()=>Np,runTui:()=>Fp,runTuiWithController:()=>xA,tuiConfigFor:()=>bA});import{createCliRenderer as vA}from"@opentui/core";import{createRoot as yA}from"@opentui/react";import{jsxDEV as wA}from"@opentui/react/jsx-dev-runtime";async function xA(e){let t=Qt(e.cfg.repoRoot,e.cfg.ui.keymap);await Np(e,t)}async function Fp(e){let t,n,r=!1;try{t=await pm("",e)}catch(i){n=O(i),r=Fs(i,cr)}let o=Qt(t?.cfg.repoRoot??process.cwd(),t?.cfg.ui.keymap);await Np(t,o,n,r)}async function Np(e,t=Qt(e?.cfg.repoRoot??process.cwd(),e?.cfg.ui.keymap),n,r=!1){$s();let o=Of(),i=await vA({exitOnCtrlC:!1,useMouse:t.mouse,enableMouseMovement:t.mouse,useKittyKeyboard:{}}),s=yA(i),a=null;try{a=(await i.getPalette({timeout:120,size:16})).defaultBackground}catch{}await new Promise((c)=>{let l=(d)=>{let f=()=>{s.unmount(),o(),i.destroy(),c(),process.exit(0)};if(!e){f();return}e.close({detach:d,shutdownSupervisor:!0}).finally(f)};s.render(wA(hw,{controller:e,tui:t,onQuit:l,bootError:n,bootErrorMissing:r,terminalBackground:a},void 0,!1,void 0,this))})}function bA(e){return Qt(e.repoRoot,e.ui.keymap)}var Hp=D(()=>{fd();Re();vw();Cl();Zt()});eo();Cl();st();fd();ze();Oi();Re();Sr();st();Ai();Rr();Jd();import{Command as SA}from"commander";import{setTimeout as Bp}from"timers/promises";import{stringify as kA}from"yaml";import{existsSync as ww,readFileSync as CA}from"fs";st();dd();Re();Sr();import{createServer as bE}from"net";import{existsSync as hu,unlinkSync as wE,watch as SE}from"fs";import{cpus as kE,loadavg as CE,platform as _E,uptime as EE}from"os";import{isAbsolute as vu,join as tc}from"path";ze();Rr();import{connect as y_}from"net";var x_=2000,b_=2000,w_=200,S_=300;function Zm(e){if(e.interval_seconds<=0)return b_;return e.interval_seconds*1000}async function eh(e,t,n,r,o,i=[]){let s=e.timeout_seconds>0?e.timeout_seconds*1000:x_,a=e.type.toLowerCase(),c=i.find((l)=>l.name.toLowerCase()===a);if(c)try{let l=await c.check(e,{pid:t,ports:n,workDir:r,env:o});return{status:l.status,message:l.message}}catch(l){return{status:Ce,message:l instanceof Error?l.message:String(l)}}if(a==="http")return k_(e.url,s);if(a==="tcp")return __(C_(e.address,n),s);if(a==="command")return E_(e.command.args,e.command.shell,r,o,s);if(a==="process"||a===""){if(t>0&&Tt(t))return{status:_t,message:"process running"};return{status:Ce,message:"process not running"}}return{status:Ce,message:`unknown health type ${e.type}`}}async function k_(e,t){let n=new AbortController,r=setTimeout(()=>n.abort(),t);try{let o=await fetch(e,{signal:n.signal});if(o.status>=w_&&o.status<S_)return{status:_t,message:String(o.status)};return{status:Ce,message:String(o.status)}}catch(o){return{status:Ce,message:o instanceof Error?o.message:String(o)}}finally{clearTimeout(r)}}function C_(e,t){if(e!=="")return e;if(t.http!==void 0)return`127.0.0.1:${t.http}`;let n=Object.values(t)[0];return n!==void 0?`127.0.0.1:${n}`:""}function __(e,t){return new Promise((n)=>{if(e===""){n({status:Ce,message:"no tcp address"});return}let r=e.lastIndexOf(":"),o=Number.parseInt(e.slice(r+1),10),i=e.slice(0,r).replace(/^\[|\]$/g,"");if(r<1||!Number.isFinite(o)){n({status:Ce,message:`invalid tcp address ${e}`});return}let s=y_({host:i,port:o},()=>{s.end(),n({status:_t,message:"connected"})});s.setTimeout(t),s.on("error",(a)=>{n({status:Ce,message:a.message})}),s.on("timeout",()=>{s.destroy(),n({status:Ce,message:"timeout"})})})}async function E_(e,t,n,r,o){if(e.length===0)return{status:Ce,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:n===""?void 0:n,env:r,stdout:"ignore",stderr:"ignore"})}catch(l){return{status:Ce,message:l instanceof Error?l.message:String(l)}}let a=setTimeout(()=>s.kill("SIGKILL"),o),c=await s.exited;if(clearTimeout(a),c===0)return{status:_t,message:"ok"};return{status:Ce,message:`exit ${c}`}}function th(e){if(e===Ce)return"WARN";if(e===_t)return"INFO";return"DEBUG"}import{readFileSync as R_}from"fs";import{freemem as P_,totalmem as T_}from"os";import{spawnSync as A_}from"child_process";var zd=1024,L_=2000,D_=/page size of (\d+) bytes/i,_o;function O_(e){let t=e.match(/^MemAvailable:\s+(\d+)/m);if(!t)return;let n=Number(t[1]);return Number.isFinite(n)&&n>=0?n:void 0}function M_(e){let t=e.match(D_),n=t?Number(t[1]):0;if(!Number.isFinite(n)||n<=0)return;let r=Ea(e,"free")+Ea(e,"inactive")+Ea(e,"speculative")+Ea(e,"purgeable");return Math.round(r*n/zd)}function Ea(e,t){let n=e.match(new RegExp(`Pages ${t}:\\s+(\\d+)`,"i")),r=n?Number(n[1]):0;return Number.isFinite(r)&&r>0?r:0}function $_(){if(process.platform==="linux")try{return O_(R_("/proc/meminfo","utf8"))}catch{return}if(process.platform==="darwin"){let e=Date.now();if(_o&&e-_o.at<L_)return _o.leftoverKB;let t=A_("vm_stat",{encoding:"utf8"});if(t.status!==0||!t.stdout)return _o?.leftoverKB;let n=M_(t.stdout);if(n===void 0)return _o?.leftoverKB;return _o={at:e,leftoverKB:n},n}return}function nh(){let e=Math.max(0,Math.round(T_()/zd)),t=Math.max(0,Math.round(P_()/zd)),n=Math.max(0,Math.min(e,$_()??t));return{totalKB:e,unusedKB:t,leftoverKB:n}}wr();Ar();Ri();Ar();import{pathToFileURL as h0}from"url";import{isAbsolute as v0,resolve as y0}from"path";st();Re();wr();import{createServer as bh,request as l0}from"http";import{randomBytes as hh}from"crypto";import{Readable as d0}from"stream";var Bi="x-devctl-request-id",u0="x-devctl-internal-token",vh=100,iu=new Set(["connection","keep-alive","proxy-authenticate","proxy-authorization","te","trailers","transfer-encoding","upgrade"]),p0=new Set(["gzip","deflate","br"]);class su{cfg;tokens;logs;bus;detector;middleware;server;running=!1;addr="";upgradedSockets=new Set;recentRequests=[];constructor(e,t,n,r,o,i=[]){this.cfg=e,this.tokens=t,this.logs=n,this.bus=r,this.detector=o,this.middleware=i}address(){return this.addr||gr(this.cfg.listen)}isRunning(){return this.running}stats(){let e=this.recentRequests.reduce((t,n)=>t+(n.status>=400||n.error?1:0),0);return{total:this.recentRequests.length,errors:e,recent:[...this.recentRequests].reverse()}}recordRequest(e){if(this.recentRequests.push(e),this.recentRequests.length>vh)this.recentRequests.splice(0,this.recentRequests.length-vh)}start(){if(this.cfg.listen.host==="0.0.0.0")return Promise.reject(L($n,"refusing to bind proxy to 0.0.0.0 without explicit unsafe configuration"));let e=this.cfg.listen.host||"127.0.0.1";if(this.cfg.listen.port===0)return Promise.reject(L($n,"proxy.listen.port is required when the proxy is enabled"));let t=this.cfg.listen.port;return new Promise((n,r)=>{this.server=bh((o,i)=>{this.serve(o,i)}),this.server.on("upgrade",(o,i,s)=>{this.serveUpgrade(o,i,s)}),this.server.on("error",(o)=>r(fe($n,`unable to listen on ${e}:${t}`,o))),this.server.listen(t,e,()=>{this.running=!0,this.addr=`${e}:${t}`,this.bus?.publish(Le(Lm,"",{address:this.addr})),n()})})}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(Le(Dm,"",{})),t()})})}async serveUpgrade(e,t,n){let r=Date.now(),o=e.headers[Bi]?.toString()||hh(8).toString("hex"),i=e.method??"GET",s=e.url??"/",a=this.detector?this.detector.redactText(s):s,c=xh(this.cfg.routes,e);if(!c){t.end(`HTTP/1.1 404 Not Found\r
|
|
609
|
+
`)}function Rw(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 aM(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 Pw(e){let t=e.reduce((r,n)=>Math.max(r,n.name.length),0);return Math.min(lM,Math.max(cM,t))}function dM(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 uM(e){let t=e.match.host||"*",r=e.match.path;if(r==="")return t;return`${t}${r.startsWith("/")?r:`/${r}`}`}function pM(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 fM(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 cM=8,lM=20,_w=80,mi=10;var sf=D(()=>{mt();ti();At()});async function hl(e,t){e.suspend();try{return await t()}finally{e.resume(),e.intermediateRender()}}import{useCallback as mM,useRef as gM}from"react";function Ew({setOverlay:e,setQuery:t,setSlashPicker:r,checked:n,setConfirmKind:o,setStatus:i,persistTheme:s,setPaletteIndex:a,themeName:c,setScreen:l,setSelected:d,screen:u,renderer:f,cfg:p,setScrollText:m,reveal:g,controller:y,refresh:x,profile:h,setReveal:P,resolveEnvironment:_,openDetail:w,copySelection:v,lastExportPath:b,openConfigBuffer:S,onDown:k,workspace:L,logView:I,diagnostics:F,lifecycleActions:Q}){let{loginGoogle:G,detectGoogle:C,logoutGoogle:B,bootstrapLogPath:W,fileExists:V,readTextFile:de,writeTextFile:Ee,validateConfigText:$e,resolveExportPath:ne,writeLogExport:H,exportsDir:ae,openInFileManager:X,listSessions:nt,loadSessionEvents:pt,checkUpdate:ie,applyUpdate:Ae,formatUpdateStatus:De}=L,{setLogService:Ke,setLogsFullscreen:ht,setPaused:Ye,setErrorOnly:Ct,toggleSystemLogs:he,clearLogs:yt,logWrap:st,setLogWrap:vt,logServices:rr,errorOnly:Xe,logLevel:Xt,logSearch:qe,logRegex:ft,logSource:vr,filteredLogs:Kt,setLogRegex:xr,setLogSince:nr,setLogUntil:qt,setLogs:or,setLogSearch:ir,toggleSplitLogs:sr}=I,{refreshAuth:Vt,setGoogle:ce}=F,{beginStart:U,beginStop:T,beginRestart:ye}=Q,z=gM(!1);return{runCommand:mM(async(at,Ce)=>{if(z.current)return;if(z.current=!0,at.name!=="start"&&at.name!=="stop"&&at.name!=="restart")e("none");t("");let So=yp(Ce,n);try{switch(at.name){case"exit":o("quit"),e("confirm");return;case"down":{let R=Ce.includes("--keep-services")||Ce.includes("-k");k(R);return}case"help":e("help");return;case"version":i(er()),ie().then((R)=>i(De(R))).catch((R)=>i(A(R)));return;case"update":i("checking for update\u2026"),ie().then(async(R)=>{if(!R.newer||!R.command){i(De(R));return}i(`installing ${R.current} \u2192 ${R.latest} via ${R.kind}\u2026`);let ue=await Ae(R.command);if(ue.code!==0){i(`update failed (${ue.code}): ${(ue.stderr||ue.stdout).trim()||R.hint}`);return}i(`updated to ${R.latest}; ${sc}`)}).catch((R)=>i(A(R)));return;case"themes":if(Ce[0]){s(Ce[0]);return}a(Math.max(0,St.indexOf(c))),t(""),e("themes");return;case"settings":l("settings"),d(0);return;case"dashboard":case"services":l(at.name);return;case"logs":if(Ce[0])Ke(Ce[0]);l("logs");return;case"fullscreen":l("logs"),ht((R)=>u==="logs"?!R:!0);return;case"split":l("logs"),sr(),i("Split log panes");return;case"trace":{let R=Ce.join(" ").trim();if(R===""){i("usage: /trace <request-or-trace-id>");return}ir(R),l("logs"),i(`tracing ${R}`);return}case"auth":{let R=(Ce[0]??"").toLowerCase();if(R==="refresh"){l("auth"),await Vt();return}if(R==="login"){l("auth"),i("starting gcloud ADC login\u2026");try{await hl(f,()=>G()),ce(await C(p?.google.project_id??"")),await Vt(),i("ADC login complete")}catch(ue){i(A(ue))}return}if(R==="logout"){l("auth"),i("revoking ADC\u2026");try{await B(),ce(await C(p?.google.project_id??"")),await Vt(),i("ADC revoked")}catch(ue){i(A(ue))}return}l("auth");return}case"credentials":case"proxy":case"mcp":case"config":case"profiles":case"setup":l(at.name);return;case"import":{let R=Ce[0]??"",ue=Ce.includes("--write"),Vr=Ce.find((se)=>se!=="compose"&&se!=="--write")??"compose.yaml";if(R!=="compose"){i("usage: /import compose [path] [--write]");return}if(!V(Vr)){i(`compose file not found: ${Vr}`);return}let Jr=p?.repoRoot||process.cwd(),br=p?.configPath||`${Jr}/.devctl/config.yaml`;try{let se=ml(de(Vr),Jr.split("/").pop()??"imported"),Hn=$e(Jr,br,se.yaml),Bn=`${gl(se)}${Hn.length>0?`
|
|
610
|
+
validation:
|
|
611
|
+
${Hn.map((Lr)=>` ${Lr}`).join(`
|
|
612
|
+
`)}
|
|
613
|
+
`:""}`;if(ue){if(Hn.length>0){m({title:"compose import",body:Bn}),e("scroll-text"),i("import is invalid; not written");return}if(V(br)){i(`configuration already exists at ${br}; not overwriting`);return}Ee(br,se.yaml),i(`wrote ${br}; /reload to apply`);return}m({title:"compose import (dry-run)",body:`${Bn}
|
|
614
|
+
Enter is preview only. /import compose ${Vr} --write to save.`}),e("scroll-text")}catch(se){i(A(se))}return}case"diff":if(!p){i("no configuration loaded");return}m({title:"config sources",body:Cw(p,g)}),e("scroll-text");return;case"daemon":{let R=p?.repoRoot;if(!R){i("no repository");return}let ue=W(R);if(!V(ue)){i("no daemon bootstrap log yet for this repository");return}m({title:"daemon bootstrap",body:de(ue)}),e("scroll-text");return}case"reload":if(!y)return;y.reload().then((R)=>{if(i(R.restart_required.length===0?"Configuration reloaded":`Reload requires restart: ${R.restart_required.join(", ")}`),R.restart_required.length>0)o("reload"),e("confirm");x()});return;case"doctor":l("doctor");return;case"stats":l("stats");return;case"start":await U(So,h);return;case"stop":await T(So);return;case"restart":{let R=qx(Ce),ue=yp(R.services,n);await ye(ue,h,R.cascade);return}case"run":{let R=Ce[0]??"";if(!R){r("tasks"),t(""),e("slash"),i(Object.keys(p?.tasks??{}).length===0?"no tasks configured":"pick a task");return}if(!y){i("no daemon attached");return}try{let ue=await y.runTask(R);Ke(`task:${R}`),l("logs"),i(`task ${R} exited ${ue.code}`)}catch(ue){throw Ke(`task:${R}`),l("logs"),ue}return}case"exec":{let R=Vx(Ce);if(!R.service){r("services"),t(""),e("slash"),i(Object.keys(p?.services??{}).length===0?"no services configured":"pick a service");return}if(!y){i("no daemon attached");return}if(R.printEnv){if(!p?.services[R.service]){i(`unknown service ${R.service}`);return}if(R.reveal)P(!0);i(`Resolving environment for ${R.service}\u2026`);try{await _(R.service),w(R.service),i(`Resolved environment for ${R.service}`)}catch(ue){w(R.service),i(A(ue))}return}if(R.command.length===0){i("usage: /exec <service> -- <command\u2026>");return}try{let ue=await y.execService(R.service,R.command);Ke(`${R.service}:exec`),l("logs"),i(`${R.service}:exec exited ${ue.code}`)}catch(ue){throw Ke(`${R.service}:exec`),l("logs"),ue}return}case"refresh":if(u==="auth"){await Vt();return}await x(),i("Refreshed status and logs");return;case"pause":Ye((R)=>!R),l("logs");return;case"filter":Ct((R)=>!R),l("logs");return;case"system":he(),l("logs");return;case"clear":yt();return;case"reveal":{let R=!g;P(R),i(R?"Secrets visible this session":"Secrets hidden");return}case"wrap":{let R=Kc(st);vt(R),i(`Log ${Vc(R)}`);return}case"copy":await v();return;case"export":{let R=ne(Ce[0]);if(y)await y.logs({export:R,services:rr,level:Xe?"ERROR":Xt,search:qe,regex:ft,source:vr});else H(R,Kt);b.current=R,i(`Exported ${R}`);return}case"exports":{let R=b.current||ae();X(R),i(`Opened ${ae()}`);return}case"regex":xr((R)=>!R),i(ft?"Substring search":"Regex search");return;case"since":nr(Ce[0]||new Date(Date.now()-3600000).toISOString()),i(`Logs since ${Ce[0]||"1h"}`);return;case"until":qt(Ce[0]||new Date().toISOString()),i(`Logs until ${Ce[0]||"now"}`);return;case"history":{let R=nt(),ue=Ce[0]||R[0];if(!ue){i("No persisted log sessions");return}or(pt(ue)),i(`Loaded session ${ue}`);return}case"buffer":S();return;case"edit":{if(!p)return;let R=process.env.DEVCTL_EDITOR||process.env.EDITOR,ue=R?[R,p.configPath]:process.platform==="darwin"?["open",p.configPath]:["xdg-open",p.configPath];Bun.spawn({cmd:ue,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),i(`Opened ${p.configPath} in ${ue[0]}. Run /reload after saving.`);return}default:i(`/${at.name}`)}}catch(R){i(A(R))}finally{setTimeout(()=>{z.current=!1},hM)}},[ye,U,T,n,p,yt,y,v,Xe,Kt,Xt,ft,qe,rr,vr,st,k,S,w,s,h,x,Vt,f,g,u,ir,r,c,sr,he])}}var hM=50;var Tw=D(()=>{te();of();sf();hr();At();tt()});import{useCallback as Aw,useRef as yM,useState as Lw}from"react";function Dw({cfg:e,readTextFile:t,setOverlay:r,setStatus:n,validateConfigText:o,writeTextFile:i,controller:s,setConfirmKind:a,refresh:c}){let l=yM(null),[d,u]=Lw(""),[f,p]=Lw(""),m=Aw(()=>{if(!e)return;try{u(t(e.configPath)),p(""),r("config-edit")}catch(y){n(A(y))}},[e]),g=Aw(()=>{if(!e)return;let y=l.current?.plainText??d,x=o(e.repoRoot,e.configPath,y);if(x.length>0){p(x.join(`
|
|
615
|
+
`)),n("Config buffer not saved");return}if(i(e.configPath,y),p(""),r("none"),!s){n(`Wrote ${e.configPath}`);return}s.reload().then((h)=>{if(n(h.restart_required.length===0?"Configuration saved and reloaded":`Saved; restart required: ${h.restart_required.join(", ")}`),h.restart_required.length>0)a("reload"),r("confirm");c()})},[e,d,s,c]);return{configEditRef:l,configEditText:d,configEditError:f,setConfigEditError:p,openConfigBuffer:m,saveConfigBuffer:g}}var Mw=D(()=>{te()});import{useEffect as vM}from"react";function Ow({controller:e,cfg:t,paused:r,logSince:n,refresh:o,setLogs:i,setCfg:s,setConfigReloadError:a,setStatus:c}){return vM(()=>{if(!e)return;let l,d=!1,u=[],f=t&&t.logs.max_memory_events>0?t.logs.max_memory_events:50000,p=()=>{if(l=void 0,u.length>0){let g=u.splice(0,u.length);i((y)=>xx(y,g,n,f))}if(d)d=!1,o()},m=e.onEvent((g)=>{if(g.type===Ao&&g.payload&&typeof g.payload==="object"&&"event"in g.payload){let y=g.payload.event;if(!r)u.push(y);if(!l)l=setTimeout(p,30);return}if(g.type===Ri){a(Hx(g));return}if(g.type===na)a(void 0),e.configSnapshot().then(s).catch((y)=>c(A(y)));if(d=!0,!l)l=setTimeout(p,30)});return()=>{if(m(),l)clearTimeout(l)}},[e,n,r,o]),{}}var Iw=D(()=>{te();yr();hr()});import{useCallback as xM,useEffect as $w,useRef as Fw,useState as gi}from"react";function Nw({controller:e,workspace:t,cfg:r,snap:n,screen:o,configReloadError:i,setSnap:s,setStatus:a}){let{detectGoogle:c,runDoctor:l,loadPath:d}=t,[u,f]=gi(),[p,m]=gi(),[g,y]=gi(!1),[x,h]=gi(""),[P,_]=gi(0),[w,v]=gi({active:"Preparing diagnostics",checks:[]}),b=Fw(void 0),S=Fw(0),k=xM(async()=>{if(!e){a("Supervisor is not running");return}a("Probing configured identities\u2026");try{let L=await e.refreshAuth();s((G)=>G?{...G,identity:L}:G);let I=Object.values(L.service_account_status),F=I.filter((G)=>G==="available").length,Q=I.filter((G)=>G==="unavailable").length;a(I.length===0?"Identity refreshed \u2014 no service accounts configured":`Identity refreshed \u2014 ${F} available${Q>0?`, ${Q} unavailable`:""}`)}catch(L){a(A(L))}},[e]);return $w(()=>{c(r?.google.project_id??"").then(f).catch((L)=>{a(A(L))})},[r?.google.project_id,n?.identity.project]),$w(()=>{if(o!=="doctor"||!r)return;let L=b.current,I=n?.session_id??"";if(L?.cfg===r&&L.tick===P&&L.sessionID===I&&L.reloadError===i)return;b.current={cfg:r,tick:P,sessionID:I,reloadError:i};let F=++S.current;y(!0),h(""),v({active:"Preparing diagnostics",checks:[]});let Q;if(r.configPath!==""){Q="";try{d(r.repoRoot,r.configPath)}catch(G){Q=A(G)}}l(r,(G)=>{if(F===S.current)v(G)},{services:n?.services,proxyRunning:n?.proxy.running,repositoryConfigError:Q}).then((G)=>{if(F!==S.current)return;m(G)}).catch((G)=>{if(F!==S.current)return;h(A(G))}).finally(()=>{if(F===S.current)y(!1)})},[o,r,P,n?.session_id,i]),{google:u,setGoogle:f,doctor:p,doctorLoading:g,doctorError:x,doctorProgress:w,setDoctorTick:_,refreshAuth:k}}var Hw=D(()=>{te()});import{useCallback as af,useState as yl}from"react";function Bw({controller:e,workspace:t,cfg:r,snap:n,refresh:o,setStatus:i,setOverlay:s}){let{resolveStartRequest:a,startupPlan:c,shutdownPlan:l,shutdownPlanExact:d}=t,[u,f]=yl(),[p,m]=yl([]),[g,y]=yl(!1),[x,h]=yl("start"),P=af(async(v,b)=>{if(!e||!r){i("no configuration loaded");return}try{let S=v.length>0,k=a(r,{services:v,profile:S?void 0:b}),L=c(r,k.services,k.profile);h("start"),m(L.waves.flat().filter((Q)=>mo(n?.services[Q]))),f(L),s("plan"),y(!0);let I=k.services.filter((Q)=>!mo(n?.services[Q])),F=await e.start({services:I.length>0?I:k.services,profile:S?void 0:k.profile});await o(),y(!1),i(Zb(F))}catch(S){y(!1),await o(),i(A(S))}},[r,e,o,n]),_=af(async(v)=>{if(!e||!r){i("no configuration loaded");return}let b=v.length>0?v:Object.entries(n?.services??{}).filter(([,S])=>S.state!=="STOPPED"&&S.state!=="UNKNOWN").map(([S])=>S);if(b.length===0){i("nothing to stop");return}try{let S=l(r,b);h("stop"),m([]),f(S),s("plan"),y(!0),await e.stop(v),await o(),y(!1),i(ew(S))}catch(S){y(!1),await o(),i(A(S))}},[r,e,o,n]),w=af(async(v,b,S=!1)=>{if(!e||!r){i("no configuration loaded");return}try{let k=Qb(r,v,b),L=S?l(r,k.services):d(r,k.services);h("restart"),m([]),f(L),s("plan"),y(!0),await e.restart(k.services,S),await o(),y(!1);let I=pl(L);i(I===""?"Restarted selected services":`Restarted ${I}`)}catch(k){y(!1),await o(),i(A(k))}},[r,e,o]);return{plan:u,planInitiallyRunning:p,planBusy:g,lifecycle:x,beginStart:P,beginStop:_,beginRestart:w}}var Ww=D(()=>{te();fl();At()});import{useCallback as Ar,useEffect as jr,useMemo as In,useRef as bM,useState as xe}from"react";function Gw(e,t,r,n,o){let i=bp(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(qc(t.filteredLen));n(a),o(i.selected)}function Uw({controller:e,tui:t,names:r,screen:n,refresh:o,setStatus:i}){let[s,a]=xe([]),[c,l]=xe(!1),[d,u]=xe(!1),[f,p]=xe(!0),[m,g]=xe(""),[y,x]=xe(!1),[h,P]=xe(0),[_,w]=xe(""),[v,b]=xe(""),[S,k]=xe(""),[L,I]=xe(""),[F,Q]=xe(!1),[G,C]=xe(0),[B,W]=xe(Tr-1),[V,de]=xe(!1),[Ee,$e]=xe(0),ne=jw,[H,ae]=xe(t.log_timestamps!==!1),[X,nt]=xe(t.log_metadata!==!1),[pt,ie]=xe(()=>[...vx]),[Ae]=xe(""),[De]=xe(""),[Ke,ht]=xe(!1),[Ye,Ct]=xe("focus"),[he,yt]=xe(!1),[st,vt]=xe(Tr-1),[rr,Xe]=xe(!1),[Xt,qe]=xe(-1),[ft,vr]=xe(),[Kt,xr]=xe(""),[nr,qt]=xe(!1),[or,ir]=xe(!1),sr=bM([]),[Vt,ce]=xe(0),U=In(()=>Jc(r,s,pt),[r,s,pt]);jr(()=>{ie((le)=>{let xt=new Set(le),Rt=!1;for(let zr of s)if(zr.service!==""&&!r.includes(zr.service)&&!xt.has(zr.service))xt.add(zr.service),Rt=!0;return Rt?[...xt].sort():le})},[s,r]);let T=In(()=>go(s,{service:S,services:ne,errorOnly:d,search:m,regex:Ke,source:De,since:_,until:v,systemLogs:f}),[d,Ke,m,S,ne,_,De,v,s,f]),ye=In(()=>xp(T,he,Vt),[T,he,Vt]),z=ye.items,Lt=In(()=>go(s,{service:L,services:ne,errorOnly:d,search:m,regex:Ke,source:De,since:_,until:v,systemLogs:f}),[d,Ke,m,L,ne,_,De,v,s,f]),at=In(()=>xp(Lt,V,Ee),[Lt,V,Ee]),Ce=at.items;jr(()=>{qe(-1),yt(!1),vt(Math.max(0,Math.min(Tr,T.length)-1))},[d,m,S,f]),jr(()=>{de(!1),W(Math.max(0,Math.min(Tr,Lt.length)-1))},[d,m,L,f]),jr(()=>{if(n!=="logs")Xe(!1)},[n]),jr(()=>{if(n!=="logs"||he)return;vt(Math.max(0,Math.min(Tr,T.length)-1))},[T.length,he,n]),jr(()=>{if(n!=="logs"||V)return;W(Math.max(0,Math.min(Tr,Lt.length)-1))},[Lt.length,V,n]);let So=Ar(()=>{if(!he)ce(qc(T.length)),yt(!0)},[T.length,he]),R=Ar(()=>{if(!V)$e(qc(Lt.length)),de(!0)},[Lt.length,V]),ue=In(()=>({sliceLen:z.length,windowStart:ye.start,windowNewer:ye.newer,filteredLen:T.length,pinned:he}),[T.length,he,z.length,ye.newer,ye.start]),Vr=In(()=>({sliceLen:Ce.length,windowStart:at.start,windowNewer:at.newer,filteredLen:Lt.length,pinned:V}),[Lt.length,V,Ce.length,at.newer,at.start]),Jr=Ar((le)=>Gw(le,ue,ce,yt,vt),[ue]),br=Ar((le)=>Gw(le,Vr,$e,de,W),[Vr]),se=Ar((le)=>{if(F&&G===1){br(le);return}Jr(le)},[Jr,br,G,F]),Hn=Ar((le)=>{let xt=z.length,Rt=bp(le,xt,ye.start,ye.newer);if(Rt.startDelta!==0)ce(Math.max(0,ye.start+Rt.startDelta)),yt(!0);qe(Rt.selected)},[z.length,ye.newer,ye.start]),Bn=Ar(()=>{if(yt(!1),de(!1),qe(-1),n==="logs")vt(Math.max(0,Math.min(Tr,T.length)-1)),W(Math.max(0,Math.min(Tr,Lt.length)-1));P((xt)=>xt+1);let le=Math.max(ye.newer,at.newer);i(le>0?`Jumped to latest (+${le} new)`:"Jumped to latest logs")},[T.length,Lt.length,ye.newer,at.newer,n]),Lr=In(()=>({services:F?jw:S!==""?[S]:ne,level:d?"ERROR":Ae,search:m,regex:Ke,source:De,since:_,until:v}),[d,Ae,Ke,m,S,ne,_,De,v,F]),cn=Ar(async()=>{if(!e)return;try{vr(await e.logsStats(Lr))}catch(le){i(A(le))}},[e,Lr]),$s=Ar(async()=>{if(!e||c)return;try{let le=await e.logsPage(Lr);a((xt)=>bx(xt,le.events)),xr(le.prevCursor),qt(le.hasPrev),await cn()}catch(le){i(A(le))}},[e,Lr,c,cn]),wi=Ar(()=>{a([]),w(new Date().toISOString()),yt(!1),de(!1),i("Cleared on-screen log buffer")},[]),Si=Ar(()=>{p((le)=>!le)},[]);return jr(()=>{o().then(()=>$s())},[o,$s]),jr(()=>{sr.current=s},[s]),jr(()=>{let le=wp(he,ye.start,nr),xt=F&&wp(V,at.start,nr);if(!e||or||!le&&!xt)return;ir(!0),e.logsPage({...Lr,cursor:Kt,direction:"backward"}).then((Rt)=>{if(Rt.sessionChanged){i("Daemon session changed \u2014 older log history is no longer available"),qt(!1);return}let zr=sr.current,Fs=wx(zr,Rt.events);a(Fs);let ko=Fs.length-zr.length;if(ko>0){if(he)ce((wr)=>wr+ko);if(V)$e((wr)=>wr+ko)}xr(Rt.prevCursor),qt(Rt.hasPrev)}).catch((Rt)=>i(A(Rt))).finally(()=>ir(!1))},[e,Lr,or,nr,he,V,Kt,ye.start,at.start,F]),jr(()=>{if(!e||c||n!=="logs")return;let le=setInterval(()=>{cn()},wM);return()=>clearInterval(le)},[e,c,cn,n]),{logs:s,setLogs:a,paused:c,setPaused:l,errorOnly:d,setErrorOnly:u,showSystemLogs:f,logSearch:m,setLogSearch:g,logSearchFocused:y,setLogSearchFocused:x,logFollow:h,logSince:_,setLogSince:w,setLogUntil:b,logService:S,setLogService:k,logServiceB:L,setLogServiceB:I,splitLogs:F,splitFocus:G,setSplitFocus:C,toggleSplitLogs:()=>{if(F){C(0),Q(!1);return}if(L===""){let le=r.find((xt)=>xt!==S);if(le!==void 0)I(le)}Q(!0)},cycleSplitFocus:()=>C((le)=>le===0?1:0),setActiveLogService:(le)=>{let xt=(Rt)=>typeof le==="function"?le(Rt):le;if(F&&G===1){I(xt);return}k(xt)},logSliceB:Ce,logWindowB:at,logSelectedB:B,logPinnedB:V,logServices:ne,logShowTimestamps:H,setLogShowTimestamps:ae,logShowMeta:X,setLogShowMeta:nt,logLevel:Ae,logSource:De,logRegex:Ke,setLogRegex:ht,logWrap:Ye,setLogWrap:Ct,logPinned:he,logSelected:st,logsFullscreen:rr,setLogsFullscreen:Xe,dashboardLogCursor:Xt,setDashboardLogCursor:qe,logFacets:ft,logSources:U,filteredLogs:T,filteredLogsB:Lt,logWindow:ye,logSlice:z,pinLogView:So,pinLogViewB:R,applyLogCursor:se,applyLogCursorA:Jr,applyLogCursorB:br,applyDashboardLogCursor:Hn,jumpToLatestLogs:Bn,clearLogs:wi,toggleSystemLogs:Si}}var jw,wM=2000;var Kw=D(()=>{te();hr();jw=[]});import{useCallback as bo,useState as qw}from"react";function Vw({tui:e,controller:t,cfg:r,persistPrefs:n,snap:o,refresh:i,setStatus:s}){let[a,c]=qw(""),[l,d]=qw(()=>e.mcp_port??lo(t?.cfg.repoRoot??process.cwd())),u=bo((h)=>{let P=Pn(h);d(P);let _=r?.repoRoot??process.cwd();if(mv(_,P)){n({mcp_port:null},`MCP port ${P} (default)`);return}n({mcp_port:P},`MCP port ${P}`)},[r,n]),f=bo(()=>{if(a==="")return l;let h=fv(a,l);return c(""),u(h),h},[l,a,u]),p=bo(async(h)=>{if(!t||o?.mcp?.running!==!0)return;await t.mcpStop(),await t.mcpStart({port:h}),await i()},[t,i,o?.mcp?.running]),m=bo(async(h)=>{if(!t){s("Supervisor is not running");return}let P=o?.mcp?.disabled_tools??[],_=En(h.name,P),w=_?[...P,h.name]:P.filter((v)=>v!==h.name);try{let v=await t.mcpSetTools(w);n({mcp_disabled_tools:v},`${h.label} ${_?"disabled":"enabled"}`),await i()}catch(v){s(A(v))}},[t,n,i,o]),g=bo(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:l}),n({mcp_enabled:!0},"MCP on"),s("MCP started");await i()}catch(h){s(A(h))}},[t,l,n,i,o?.mcp?.running]),y=bo((h)=>{al(h.text).then(()=>{s(`Copied ${h.title} snippet`)}).catch((P)=>{s(A(P))})},[]),x=bo((h)=>{let P=Vp(h);if(P===void 0)return!1;let _=o?.mcp?.address??ui(o?.mcp?.port??l),w=_s(_,o?.mcp?.token??"")[P];if(!w)return!1;return y(w),!0},[y,l,o?.mcp?.address,o?.mcp?.port,o?.mcp?.token]);return{mcpPortDraft:a,setMcpPortDraft:c,mcpPort:l,persistMcpPort:u,applyMcpPortDraft:f,restartMcpOnPort:p,toggleMcpTool:m,toggleMcp:g,copyMcpSnippet:y,copyFocusedMcpSnippet:x}}var Jw=D(()=>{te();ul();ss();$p();Ts()});import{RGBA as SM}from"@opentui/core";import{useCallback as sn,useEffect as kM,useMemo as zw,useRef as vl,useState as xl}from"react";function Yw({tui:e,controller:t,resolveTuiOverridePath:r,terminalBackground:n,userTuiConfigPath:o,snap:i,setStatus:s,saveTuiPreferences:a,setPaletteIndex:c,setOverlay:l,setConfirmKind:d,setScreen:u,setSelected:f,screen:p}){let[m,g]=xl(e.theme||t?.cfg.ui.theme||"devctl"),y=vl(m),[x,h]=xl(e.mouse),P=vl(e.mouse),[_,w]=xl(e.leader_timeout),v=vl(e.leader_timeout),[b,S]=xl(()=>ps(e.font_size)),k=vl(b),L=qv(r()),I=zw(()=>{let H=Wv(m);if(Sc(m)!=="terminal"||!np(n))return H;let ae=n??H.background;return{...H,background:ae,panel:ae,element:ae,inverse:ae}},[n,m]),F=Sc(m)==="terminal"&&np(n)?SM.defaultBackground(n??void 0):I.background,Q=zw(()=>Yv({themeName:m,fontSize:b,mouse:x,leaderMs:_,locked:L,configPath:L?e.path||cp(r(),o()):cp(r(),o()),mcpRunning:i?.mcp?.running===!0}),[b,_,x,L,i?.mcp?.running,m,e.path]),G=sn((H,ae)=>{if(L){s(`${ae} session only`);return}let X=a(H);s(`${ae} saved ${X}`)},[L]),C=sn((H)=>{g(H),y.current=H,G({theme:H},`theme ${H}`)},[G]),B=sn(()=>{let H=!x;h(H),P.current=H,G({mouse:H},`mouse ${H?"on":"off"} restart TUI to apply clicks`)},[x,G]),W=sn((H)=>{w(H),v.current=H,G({leader_timeout:H},`leader ${H}ms`)},[G]),V=sn((H)=>{let ae=ps(H);S(ae),k.current=ae,G({font_size:ae},`display ${Pc(ae)}`)},[G]),de=sn(()=>{let H=_c();g(H.theme),y.current=H.theme,h(H.mouse),P.current=H.mouse,w(H.leader_timeout),v.current=H.leader_timeout,S(H.font_size),k.current=H.font_size,G(H,"restored default preferences")},[G]),Ee=sn((H)=>{if(H.id==="theme"){c(Math.max(0,St.indexOf(m))),l("themes");return}if(H.id==="mouse"){B();return}if(H.id==="leader"){W(_);return}if(H.id==="font"){V(b);return}if(H.id==="reset"){d("reset-prefs"),l("confirm");return}if(H.id==="mcp"){u("mcp"),f(0);return}s(H.detail)},[V,W,b,_,m,B]),$e=sn((H,ae)=>{let X=Tn(Q,ae);if(!X)return;if(X.id==="theme"){C(Vv(m,H));return}if(X.id==="leader"){W(Jv(_,H));return}if(X.id==="font"){V(fs(b,H));return}if(X.id==="mouse")B()},[V,W,b,_,C,Q,m,B]),ne=sn(()=>{g(y.current)},[]);return kM(()=>{if(p==="settings")return;g(y.current),S(k.current),w(v.current),h(P.current)},[p]),{themeName:m,setThemeName:g,leaderMs:_,fontSize:b,prefsLocked:L,palette:I,rootBackground:F,settingRows:Q,persistPrefs:G,persistTheme:C,toggleMouse:B,applyFont:V,applyReset:de,activateSetting:Ee,cycleSetting:$e,revertThemePreview:ne}}var Xw=D(()=>{_r();tt()});import{jsxDEV as Ls}from"@opentui/react/jsx-dev-runtime";function Qw(e){let{palette:t,termW:r,termH:n,step:o,answers:i,repo:s,draft:a,authStatus:c,onDraft:l,onSubmit:d}=e,u=wt[o]??wt[0],f=wt.length,p=CM(u.id,i,s);return Ls(ut,{palette:t,title:`setup ${o+1}/${f} ${u.title}`,bottomTitle:"enter next \xB7 esc cancel",termW:r,termH:n,preferW:64,preferH:12,borderColor:t.primary,gap:1,children:[Ls("text",{fg:t.muted,wrapMode:"word",children:p},void 0,!1,void 0,this),u.id==="auth"||u.id==="write"||u.id==="repo"?Ls("text",{fg:t.text,wrapMode:"word",children:u.id==="auth"?c:u.id==="repo"?s:"Write .devctl/config.yaml and attach the daemon."},void 0,!1,void 0,this):Ls("input",{focused:!0,value:a,placeholder:u.prompt,onInput:l,onSubmit:d,backgroundColor:t.element,focusedBackgroundColor:t.element,textColor:t.text,cursorColor:t.primary},void 0,!1,void 0,this),Ls(ot,{palette:t,hints:[{key:"enter",label:u.id==="write"?"write and attach":"next"},{key:"esc",label:"cancel"}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function cf(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 Zw(e,t,r,n){let o={...t};if(e==="name")o.name=r.trim()||xn(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=Sa(r,t.proxyPort);else if(e==="profile")o.profile=r.trim();return o}function CM(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 wt.find((n)=>n.id===e)?.prompt??""}var lf=D(()=>{ka();ke()});import{useCallback as df,useState as bl}from"react";function eS({workspace:e,renderer:t,setOverlay:r,setStatus:n,setScreen:o,onAttached:i,setController:s,setCfg:a,setBootError:c}){let l=process.cwd(),[d,u]=bl(0),[f,p]=bl(()=>xn(l)),[m,g]=bl(""),[y,x]=bl("Checking Application Default Credentials\u2026"),h=df(()=>{let w=xn(l);u(0),p(w),g(cf("repo",w,l)),r("setup-wizard"),e.detectGoogle("").then((v)=>{p((b)=>({...b,project:v.projectID||b.project})),x(v.adcAvailable?`ADC available${v.userEmail?` (${v.userEmail})`:""}. Enter continues.`:"ADC is not available. Enter runs gcloud ADC login on this TTY, then continues.")})},[l,r,e]),P=df(async(w)=>{try{Ra(l,w);let v=await e.openTui(l,"");i?.(v),s(v),a(v.cfg),c(void 0),r("none"),o("dashboard"),n("Wrote .devctl/config.yaml and attached the daemon")}catch(v){n(A(v))}},[i,l,c,a,s,r,o,n,e]),_=df(async()=>{let w=wt[d];if(!w)return;let v=Zw(w.id,f,m,l);if(w.id==="auth"){if(!(await e.detectGoogle(v.project)).adcAvailable)try{await hl(t,()=>e.loginGoogle())}catch(L){n(A(L))}}if(p(v),w.id==="write"){await P(v);return}let b=Math.min(d+1,wt.length-1),S=wt[b];u(b),g(S?cf(S.id,v,l):"")},[f,m,P,t,l,d,e,n]);return{step:d,answers:f,draft:m,authStatus:y,repo:l,setDraft:g,startWizard:h,advanceWizard:_}}var tS=D(()=>{ka();Pa();te();lf()});import{useCallback as RM,useEffect as rS,useState as uf}from"react";function nS({controller:e,cfg:t,envService:r}){let[n,o]=uf(),[i,s]=uf(!1),[a,c]=uf(""),l=n?.name===r,d=l?n?.env:void 0,u=r===""?"config":i&&!l?"loading":l?"resolved":a!==""?"error":"config",f=l||r===""?"":a;rS(()=>{o(void 0),c("")},[t]),rS(()=>{if(!e||r===""||!t?.services[r])return;if(n?.name===r)return;let m=!1;return s(!0),c(""),e.execService(r,[],!0).then((g)=>{if(m)return;o({name:r,env:g.environment??{}}),c("")}).catch((g)=>{if(m)return;c(A(g))}).finally(()=>{s(!1)}),()=>{m=!0}},[t,e,r,n?.name]);let p=RM(async(m)=>{if(!e)return;try{let g=await e.execService(m,[],!0);o({name:m,env:g.environment??{}}),c("")}catch(g){throw c(A(g)),g}},[e]);return{inspectorEnv:d,inspectorEnvStatus:u,inspectorEnvError:f,resolveEnvironment:p}}var oS=D(()=>{te()});import{jsxDEV as $n}from"@opentui/react/jsx-dev-runtime";function iS(e){let{palette:t,path:r,initialValue:n,error:o,termW:i,termH:s,textareaRef:a}=e;return $n(ut,{palette:t,title:"config buffer",bottomTitle:`${Mt("s")} save \xB7 esc discard \xB7 e still opens $EDITOR`,termW:i,termH:s,preferW:88,preferH:28,gap:1,children:[$n("box",{height:1,overflow:"hidden",children:$n("text",{fg:t.muted,wrapMode:"none",children:r},void 0,!1,void 0,this)},void 0,!1,void 0,this),$n("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!==""?$n("box",{height:2,overflow:"hidden",children:$n("text",{fg:t.error,wrapMode:"word",children:o},void 0,!1,void 0,this)},void 0,!1,void 0,this):$n("box",{height:1,overflow:"hidden",children:$n("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 sS=D(()=>{ke();Pr()});import{jsxDEV as pf}from"@opentui/react/jsx-dev-runtime";function aS(e){let{palette:t,title:r,body:n,kind:o,termW:i,termH:s}=e,a=Nx(o),c=a.map((l)=>`${l.key} ${l.label}`).join(" \xB7 ");return pf(ut,{palette:t,title:r,bottomTitle:c,termW:i,termH:s,preferW:52,preferH:8,borderColor:t.warning,gap:1,children:[pf("text",{fg:t.text,wrapMode:"word",children:n},void 0,!1,void 0,this),pf(ot,{palette:t,hints:a},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var cS=D(()=>{yr();ke()});import{jsxDEV as lS}from"@opentui/react/jsx-dev-runtime";function dS(e){let{palette:t,termW:r,termH:n}=e,o=Tp();return lS(ut,{palette:t,title:"leader",termW:r,termH:n,preferW:68,preferH:5,anchor:"bottom",children:lS(ot,{palette:t,hints:o},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var uS=D(()=>{vo();ke()});import{jsxDEV as Yt,Fragment as PM}from"@opentui/react/jsx-dev-runtime";function pS(e){let{palette:t,event:r,termW:n,termH:o,scrollRef:i}=e;if(!r)return null;let s=r.raw?px(r.raw):void 0,a=r.message.length>120||r.message.includes(`
|
|
616
|
+
`)||s!==void 0;return Yt(ut,{palette:t,title:"log details",bottomTitle:"j/k scroll \xB7 esc close",termW:n,termH:o,preferW:a?84:72,preferH:a?22:14,gap:1,children:Yt("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:je(t),children:Yt("box",{flexDirection:"column",overflow:"hidden",children:[Yt("text",{fg:t.text,wrapMode:"word",children:Gc(r.message)},void 0,!1,void 0,this),Yt("text",{fg:t.muted,children:`time ${r.timestamp}`},void 0,!1,void 0,this),Yt("text",{fg:Ze(r.service,t),children:`service ${r.service}`},void 0,!1,void 0,this),Yt("text",{fg:t.muted,children:`source ${r.source}${r.stream?` / ${r.stream}`:""}`},void 0,!1,void 0,this),Yt("text",{fg:t.muted,children:`level ${jc(r.level)}`},void 0,!1,void 0,this),Yt("text",{fg:t.muted,children:`pid ${r.pid||"\u2014"}`},void 0,!1,void 0,this),Yt("text",{fg:t.muted,children:`request ${r.request_id||"\u2014"}`},void 0,!1,void 0,this),Yt("text",{fg:t.muted,children:`identity ${r.identity||"\u2014"}`},void 0,!1,void 0,this),s===void 0?null:Yt(PM,{children:[Yt("text",{fg:t.muted,children:"raw json"},void 0,!1,void 0,this),Yt("text",{fg:t.text,wrapMode:"word",children:s},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var fS=D(()=>{hr();ke();tt()});import{jsxDEV as j}from"@opentui/react/jsx-dev-runtime";function ff(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 _M(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 mS(e){return j("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:j("text",{wrapMode:"none",children:[j("span",{fg:e.palette.primary,children:e.label.toUpperCase()},void 0,!1,void 0,this),e.detail?j("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 gS(e){let{palette:t,plan:r,snap:n,busy:o,failed:i,kind:s,termW:a=80,termH:c=24,scrollRef:l,initiallyRunning:d=[],onDismiss:u}=e,f=new Set(d),p=r.waves.map((C,B)=>({wave:C.filter((W)=>!f.has(W)),waveIdx:B})).filter(({wave:C})=>C.length>0),m=rw(r,n,s),g=r.waves[m.currentWaveIndex]??[],y=As(g,n,s),x=ff(y,t),h=_M(o,i,y,t),P=ow(s,o,i,r.profile),_=iw(o,i),w=i?t.inverse:t.text,v=i?t.error:t.element,b=Math.min(92,Math.max(40,a-8)),S=b>=82?22:b>=66?17:13,k=12,L=9,I=b>=56,F=b>=72,Q=b<72||r.waves.length>3,G=r.profile?`PROFILE ${r.profile}`:s.toUpperCase();return j(ut,{palette:t,title:P,bottomTitle:"enter close \xB7 esc hide (operation continues)",termW:a,termH:c,preferW:98,preferH:28,borderColor:h.color,gap:0,children:[j("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:[j(We,{palette:t,label:`${h.icon} ${h.label.toUpperCase()}`,tone:h.tone},void 0,!1,void 0,this),j("box",{paddingLeft:1,flexGrow:1,overflow:"hidden",children:j("text",{fg:t.text,wrapMode:"none",children:G},void 0,!1,void 0,this)},void 0,!1,void 0,this),j(We,{palette:t,label:`${m.ready}/${m.total} READY`,tone:m.isComplete?"success":"info"},void 0,!1,void 0,this),j(We,{palette:t,label:`WAVE ${Math.min(m.currentWaveIndex+1,Math.max(1,m.totalWaves))}/${Math.max(1,m.totalWaves)}`,tone:x.tone},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j("box",{height:2,flexDirection:"column",overflow:"hidden",flexShrink:0,paddingLeft:1,paddingRight:1,children:[j("box",{height:1,flexDirection:"row",overflow:"hidden",children:[j("text",{wrapMode:"none",children:[j("span",{fg:t.muted,children:"PROGRESS "},void 0,!1,void 0,this),j("span",{fg:h.color,children:`[${m.progressBar}]`},void 0,!1,void 0,this),j("span",{fg:t.text,children:` ${m.percent}%`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j("box",{flexGrow:1},void 0,!1,void 0,this),j("text",{wrapMode:"none",children:j("span",{fg:x.color,children:`${x.icon} ${x.label}`},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j("box",{height:1,overflow:"hidden",children:j("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.":_.primary},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j(mS,{palette:t,label:"Pipeline",detail:`${r.waves.length} execution wave${r.waves.length===1?"":"s"}`},void 0,!1,void 0,this),j("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:r.waves.map((C,B)=>{let W=As(C,n,s),V=ff(W,t),de=Q?`W${B+1} ${V.icon} ${C.length}`:`W${B+1} ${V.icon} ${V.label} \xB7 ${C.length}`;return j("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:[j(We,{palette:t,label:de,tone:V.tone},void 0,!1,void 0,this),B<r.waves.length-1?j("box",{width:3,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.muted,children:" \u2500\u25BA"},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},`step-${B}`,!0,void 0,this)})},void 0,!1,void 0,this),(r.blockers??[]).length>0?j("box",{minHeight:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,paddingLeft:1,children:j("text",{fg:t.error,wrapMode:"word",children:`BLOCKED ${r.blockers?.map((C)=>`${C.name}: ${C.message}`).join(" \xB7 ")}`},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,d.length>0?j("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,paddingLeft:1,children:j("text",{wrapMode:"none",children:[j("span",{fg:t.success,children:"\u2713 ALREADY READY"},void 0,!1,void 0,this),j("span",{fg:t.muted,children:` ${d.join(", ")}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this):null,j(mS,{palette:t,label:"Wave details",detail:"live process and health state"},void 0,!1,void 0,this),j("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,paddingLeft:1,children:[j("box",{width:2,flexShrink:0},void 0,!1,void 0,this),j("box",{width:S,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.muted,children:oe("SERVICE",S)},void 0,!1,void 0,this)},void 0,!1,void 0,this),j("box",{width:12,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.muted,children:oe("STATE",12)},void 0,!1,void 0,this)},void 0,!1,void 0,this),I?j("box",{width:9,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.muted,children:oe("PORT",9)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,F?j("box",{flexGrow:1,overflow:"hidden",children:j("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),j("scrollbox",{ref:l,focused:!1,stickyScroll:!1,scrollX:!1,style:je(t),children:j("box",{flexDirection:"column",overflow:"hidden",gap:1,children:p.map(({wave:C,waveIdx:B})=>{let W=As(C,n,s),V=ff(W,t),de=`${nw(s,B,W)} \xB7 ${C.length} service${C.length===1?"":"s"}`;return j("box",{border:!0,borderStyle:"rounded",borderColor:V.color,title:de,titleColor:V.color,flexDirection:"column",paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:C.map((Ee)=>{let $e=n?.services[Ee],ne=tr($e),H=tw(Ee,r,n,s),ae=Ee===i||ne==="FAILED",X=ne==="UNHEALTHY",nt=ne==="HEALTHY"||s==="stop"&&ne==="STOPPED",pt=fo($e),ie=ae?"\u2717":nt?"\u2713":X?"\u26A0":ne==="STARTING"||ne==="RUNNING"||ne==="STOPPING"||ne==="RESTARTING"?"\u25CF":"\u25CB",Ae=ae?t.error:et(t,ne),De=ae?t.error:X?t.warning:nt?t.success:t.muted;return j("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[j("box",{width:2,flexShrink:0,overflow:"hidden",children:j("text",{fg:Ae,children:ie},void 0,!1,void 0,this)},void 0,!1,void 0,this),j("box",{width:S,flexShrink:0,overflow:"hidden",children:j("text",{fg:Ze(Ee,t),wrapMode:"none",children:oe(Ee,S)},void 0,!1,void 0,this)},void 0,!1,void 0,this),j("box",{width:12,flexShrink:0,overflow:"hidden",children:j("text",{fg:et(t,ne),wrapMode:"none",children:oe(ne,12)},void 0,!1,void 0,this)},void 0,!1,void 0,this),I?j("box",{width:9,flexShrink:0,overflow:"hidden",children:j("text",{fg:pt?t.info:t.muted,wrapMode:"none",children:oe(pt?`:${pt}`:"\u2014",9)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,F?j("box",{flexGrow:1,overflow:"hidden",children:j("text",{fg:De,wrapMode:"none",children:H},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},Ee,!0,void 0,this)})},`wave-card-${B}`,!1,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this),j("box",{height:3,flexShrink:0,flexDirection:"column",backgroundColor:v,border:["top"],borderStyle:"single",borderColor:h.color,paddingLeft:1,paddingRight:1,overflow:"hidden",onMouseDown:u,children:[j("text",{fg:w,wrapMode:"none",children:_.primary},void 0,!1,void 0,this),j("text",{fg:i?t.inverse:t.muted,wrapMode:"none",children:_.secondary},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var hS=D(()=>{It();fl();At();ke();tt()});import{jsxDEV as Gr}from"@opentui/react/jsx-dev-runtime";function yS(e){let{palette:t,route:r,termW:n,termH:o,scrollRef:i}=e;if(!r)return null;return Gr(ut,{palette:t,title:r.name,bottomTitle:"j/k scroll \xB7 esc close",termW:n,termH:o,preferW:78,preferH:16,gap:1,children:Gr("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:je(t),children:Gr("box",{flexDirection:"column",overflow:"hidden",children:[Gr("text",{fg:t.muted,children:`auth ${r.authType||"none"}`},void 0,!1,void 0,this),Gr("text",{fg:t.muted,children:`identity ${r.identityType||"\u2014"}`},void 0,!1,void 0,this),Gr("text",{fg:t.text,wrapMode:"word",children:`account ${r.serviceAccount||"\u2014"}`},void 0,!1,void 0,this),Gr("text",{fg:t.text,wrapMode:"word",children:`audience ${r.audience||"\u2014"}`},void 0,!1,void 0,this),Gr("text",{fg:t.muted,children:`match host ${r.matchHost||"*"}`},void 0,!1,void 0,this),Gr("text",{fg:t.muted,children:`match path ${r.matchPath||"*"}`},void 0,!1,void 0,this),Gr("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 vS=D(()=>{ke()});import{jsxDEV as wl}from"@opentui/react/jsx-dev-runtime";function xS(e){let{palette:t,title:r,body:n,termW:o,termH:i,scrollRef:s}=e,a=n.length>400||n.split(`
|
|
617
|
+
`).length>16;return wl(ut,{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:wl("scrollbox",{ref:s,focused:!1,stickyScroll:!1,scrollX:!1,style:je(t),children:wl("box",{flexDirection:"column",overflow:"hidden",children:wl("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 bS=D(()=>{ke()});import{jsxDEV as Gt}from"@opentui/react/jsx-dev-runtime";function wS(e){let{palette:t,items:r,query:n,selected:o,onQuery:i,onSubmit:s,title:a="commands"}=e,c=yo(n)!=="",l=sb(o,mf,r.length),d=c?r.slice(l,l+mf):ab(r,o,mf),u=c?[{group:"",items:d}]:Pp(d),f=Math.max(d.length+(c?0:u.length),1),p=ci(r,o),m=tb(r);return Gt("box",{height:f+EM,flexShrink:0,border:!0,borderStyle:"rounded",borderColor:t.borderActive,titleColor:t.primary,backgroundColor:t.panel,title:a,flexDirection:"column",overflow:"hidden",children:[d.length===0?Gt("box",{height:1,paddingLeft:1,overflow:"hidden",children:Gt("text",{fg:t.muted,children:"no matching command"},void 0,!1,void 0,this)},void 0,!1,void 0,this):u.flatMap((g)=>[...g.group===""?[]:[Gt("box",{height:1,paddingLeft:1,overflow:"hidden",backgroundColor:t.panel,children:Gt("text",{fg:t.muted,wrapMode:"none",children:g.group},void 0,!1,void 0,this)},`g-${g.group}`,!1,void 0,this)],...g.items.map((x)=>{let h=Zc(x)===(p?Zc(p):"");return Gt("box",{height:1,flexDirection:"row",overflow:"hidden",paddingLeft:1,paddingRight:1,backgroundColor:h?t.highlight:t.panel,children:[Gt("box",{width:m,flexShrink:0,overflow:"hidden",children:Gt("text",{fg:h?t.primary:t.text,wrapMode:"none",children:`${h?"\u203A":" "} /${_p(x).slice(0,Rp)}`},void 0,!1,void 0,this)},void 0,!1,void 0,this),Gt("box",{flexGrow:1,overflow:"hidden",children:Gt("text",{fg:h?t.accent:t.muted,wrapMode:"none",children:eb(x)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},Zc(x),!0,void 0,this)})]),Gt("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.highlight,paddingLeft:1,children:[Gt("box",{width:2,flexShrink:0,children:Gt("text",{fg:t.primary,children:"/"},void 0,!1,void 0,this)},void 0,!1,void 0,this),Gt("box",{flexGrow:1,overflow:"hidden",children:Gt("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 mf=10,EM=3;var SS=D(()=>{vo()});import{jsxDEV as RS}from"@opentui/react/jsx-dev-runtime";function PS(e){let{palette:t,themeName:r,selected:n,termW:o,termH:i,onIndex:s,onPreview:a,onPick:c}=e,l=St.map((u)=>({name:u===r?`${u} (active)`:u,description:u===r?`${rp[u]} \xB7 current`:rp[u],value:u})),d=Xc(o,i,kS,CS,"center",!po(ve()));return RS(ut,{palette:t,title:"/themes",bottomTitle:"enter save \xB7 esc revert",termW:o,termH:i,preferW:kS,preferH:CS,children:RS("select",{height:Math.max(4,d.height-3),options:l,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:(u)=>{s(u);let f=St[u];if(f)a(f)},onSelect:(u,f)=>{let p=f?.value;if(typeof p==="string"&&p!=="")c(p)}},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var kS=52,CS=22;var _S=D(()=>{Ot();yr();ke();_r();tt()});function Sl(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 it}from"@opentui/react/jsx-dev-runtime";function kl(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 it("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 ES(e){let{palette:t,cfg:r,google:n,identity:o}=e;if(!n&&!o)return it(sl,{palette:t,label:"Checking Application Default Credentials\u2026"},void 0,!1,void 0,this);let i=TM(r,o),s=o?.user||n?.userEmail||"",{project:a,source:c}=Sl(r,o,n),l=o?.adc??n?.adcAvailable===!0,d=o?.iap??(r?.proxy.routes??[]).some((g)=>g.auth.type.toLowerCase()==="iap"),u=i.filter((g)=>g.inactive!==!0),f=u.some((g)=>g.ok===!0),p=u.some((g)=>g.ok===!1),m=f?"AVAILABLE":p?"UNAVAILABLE":u.length>0?"NOT PROBED":i.length>0?"not required":"not configured";return it(kt,{palette:t,title:"identity",scroll:!0,children:[it(kl,{palette:t,title:"Google identity",tone:l?"success":"warning",children:[it(xo,{palette:t,label:"user",value:s||"(unknown)"},void 0,!1,void 0,this),it(xo,{palette:t,label:"project",value:a||"(unset)"},void 0,!1,void 0,this),it(xo,{palette:t,label:"source",value:c||"\u2014"},void 0,!1,void 0,this),it(xo,{palette:t,label:"ADC",value:l?"\u2713 available":"\u2717 missing",tone:l?"success":"error"},void 0,!1,void 0,this),it(xo,{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),it(kl,{palette:t,title:`Service accounts (${i.length})`,tone:u.length===0?"muted":f?"success":"warning",children:[i.length===0?it("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((g)=>it("text",{fg:g.inactive?t.muted:g.ok===!0?t.success:g.ok===!1?t.error:t.text,wrapMode:"none",children:`${g.inactive?"\u2013":g.ok===!0?"\u2713":g.ok===!1?"\u2717":"\u25CB"} ${g.email}${g.inactive?" \u2014 inactive (route auth is none)":""}`},g.email,!1,void 0,this)),it("box",{height:1,flexShrink:0},void 0,!1,void 0,this),it(xo,{palette:t,label:"impersonation",value:m,tone:f?"success":u.length>0?"warning":"muted"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),it(kl,{palette:t,title:"IAP",tone:d?"success":"muted",children:[it("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:it(We,{palette:t,label:d?"routes present":"no IAP routes",tone:d?"success":"idle"},void 0,!1,void 0,this)},void 0,!1,void 0,this),d?it("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),!l?it(kl,{palette:t,title:"ADC unavailable",tone:"warning",children:[it("text",{fg:t.text,wrapMode:"word",children:"Local services still start. Cloud identity, impersonation, and IAP need ADC."},void 0,!1,void 0,this),it("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 TM(e,t){let r=new Map((e?Yd(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 TS=D(()=>{Fr();zt();ke()});import{jsxDEV as O}from"@opentui/react/jsx-dev-runtime";function MS(e){let{palette:t,cfg:r,width:n,selectedTask:o=0}=e,i=ve();if(!r)return O(Ve,{palette:t,title:"No configuration",body:"Create .devctl/config.yaml or run setup."},void 0,!1,void 0,this);let s=Math.max(mi+8,n-6-i.pad*2),a=s>=_w,c=a?Math.floor((s-LS)/2):s,l=xw(r),d=bw(r),u=ww(r),f=Sw(r),p=kw(r);return O(kt,{palette:t,title:`config ${r.project.name||"unnamed"}`,children:[O(dt,{palette:t,items:fw(r)},void 0,!1,void 0,this),O("box",{flexGrow:1,overflow:"hidden",children:O("scrollbox",{ref:e.scrollRef,focused:!1,stickyScroll:!1,scrollX:!1,style:je(t),children:O("box",{flexDirection:"column",overflow:"hidden",gap:DS,children:[O(gf,{wide:a,left:O(Ur,{palette:t,title:"project",children:O(hi,{palette:t,facts:mw(r,Bt),width:c},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:O(Ur,{palette:t,title:"google",children:O(hi,{palette:t,facts:gw(r),width:c},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),O(gf,{wide:a,left:O(Ur,{palette:t,title:"runtime",children:O(hi,{palette:t,facts:hw(r),width:c},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:O(Ur,{palette:t,title:"logs",children:O(hi,{palette:t,facts:yw(r),width:c},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),O(Ur,{palette:t,title:`proxy ${r.proxy.enabled?"enabled":"disabled"}`,children:[O(hi,{palette:t,facts:vw(r),width:s},void 0,!1,void 0,this),O(LM,{palette:t,routes:d,width:s},void 0,!1,void 0,this)]},void 0,!0,void 0,this),O(Ur,{palette:t,title:`services ${l.length}`,children:O(AM,{palette:t,rows:l,width:s},void 0,!1,void 0,this)},void 0,!1,void 0,this),O(Ur,{palette:t,title:`tasks ${p.length}`,children:O(AS,{palette:t,rows:p,empty:"no tasks",width:s,selected:o},void 0,!1,void 0,this)},void 0,!1,void 0,this),O(gf,{wide:a,left:O(Ur,{palette:t,title:`profiles ${u.length}`,children:O(DM,{palette:t,rows:u,width:c},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:O(Ur,{palette:t,title:`templates ${f.length}`,children:O(AS,{palette:t,rows:f,empty:"no templates",width:c},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),O(Ur,{palette:t,title:"extras",children:O(hi,{palette:t,facts:Rw(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),O(jt,{palette:t,backgroundColor:t.element,edge:"top",children:O(ot,{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 gf(e){let{wide:t,left:r,right:n}=e;if(!t)return O("box",{flexDirection:"column",overflow:"hidden",gap:DS,flexShrink:0,children:[r,n]},void 0,!0,void 0,this);return O("box",{flexDirection:"row",overflow:"hidden",gap:LS,flexShrink:0,children:[O("box",{flexGrow:1,flexBasis:0,overflow:"hidden",children:r},void 0,!1,void 0,this),O("box",{flexGrow:1,flexBasis:0,overflow:"hidden",children:n},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Ur(e){let{palette:t,title:r,children:n}=e;return O("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 hi(e){let{palette:t,facts:r,width:n}=e,o=Math.max(4,n-mi-4);return O("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((i)=>O("box",{height:1,flexDirection:"row",overflow:"hidden",children:[O("box",{width:mi,flexShrink:0,overflow:"hidden",children:O("text",{fg:t.muted,wrapMode:"none",children:oe(i.label,mi)},void 0,!1,void 0,this)},void 0,!1,void 0,this),O("box",{width:o,flexShrink:0,overflow:"hidden",children:O("text",{fg:IM(t,i.tone),wrapMode:"none",children:oe(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 AM(e){let{palette:t,rows:r,width:n}=e;if(r.length===0)return O(Cl,{palette:t,text:"no services"},void 0,!1,void 0,this);let o=Pw(r),i=Math.max(8,n-o-6);return O("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((s)=>O("box",{height:1,flexDirection:"row",overflow:"hidden",children:[O("box",{width:o,flexShrink:0,overflow:"hidden",children:O("text",{fg:Ze(s.name,t),wrapMode:"none",children:oe(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),O("box",{width:i,flexShrink:0,overflow:"hidden",children:O("text",{fg:t.text,wrapMode:"none",children:_e(MM(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 LM(e){let{palette:t,routes:r,width:n}=e;if(r.length===0)return O(Cl,{palette:t,text:"no routes"},void 0,!1,void 0,this);let o=Math.min(mi+4,Math.max(8,...r.map((s)=>s.name.length))),i=Math.max(8,n-o-6);return O("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((s)=>O("box",{height:1,flexDirection:"row",overflow:"hidden",children:[O("box",{width:o,flexShrink:0,overflow:"hidden",children:O("text",{fg:t.primary,wrapMode:"none",children:oe(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),O("box",{width:i,flexShrink:0,overflow:"hidden",children:O("text",{fg:t.text,wrapMode:"none",children:_e(OM(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 DM(e){let{palette:t,rows:r,width:n}=e;if(r.length===0)return O(Cl,{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 O("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((s)=>O("box",{height:1,flexDirection:"row",overflow:"hidden",children:[O("box",{width:o,flexShrink:0,overflow:"hidden",children:O("text",{fg:t.primary,wrapMode:"none",children:oe(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),O("box",{width:i,flexShrink:0,overflow:"hidden",children:O("text",{fg:t.text,wrapMode:"none",children:_e(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 AS(e){let{palette:t,rows:r,empty:n,width:o,selected:i}=e;if(r.length===0)return O(Cl,{palette:t,text:n},void 0,!1,void 0,this);let s=Math.min(14,Math.max(8,...r.map((c)=>c.name.length))),a=Math.max(8,o-s-6);return O("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((c,l)=>{let d=i===l;return O("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:d?t.highlight:void 0,children:[O("box",{width:s,flexShrink:0,overflow:"hidden",children:O("text",{fg:d?t.primary:t.text,wrapMode:"none",children:oe(c.name,s)},void 0,!1,void 0,this)},void 0,!1,void 0,this),O("box",{width:a,flexShrink:0,overflow:"hidden",children:O("text",{fg:d?t.accent:t.muted,wrapMode:"none",children:_e(c.summary,a)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},c.name,!0,void 0,this)})},void 0,!1,void 0,this)}function Cl(e){return O("box",{height:1,overflow:"hidden",children:O("text",{fg:e.palette.muted,wrapMode:"none",children:e.text},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function MM(e){let t=e.extends==="\u2014"?"":` ${e.extends}`;return` ${e.ports} ${e.identity} ${e.health} ${e.restart} \u2190 ${e.depends}${t}`}function OM(e){return` ${e.auth} ${e.identity} ${e.match} \u2192 ${e.upstream}`}function IM(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 LS=1,DS=1;var OS=D(()=>{zt();sf();Ot();It();ke();tt()});import{jsxDEV as Ft}from"@opentui/react/jsx-dev-runtime";function IS(e){let{palette:t,credentials:r}=e;if(!r)return Ft(sl,{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 Ft(kt,{palette:t,title:"credentials",scroll:!0,children:[Ft("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[Ft(We,{palette:t,label:`backend: ${r.backend}`,tone:"info"},void 0,!1,void 0,this),r.entries.length>0?Ft(We,{palette:t,label:`${n} valid`,tone:"success"},void 0,!1,void 0,this):null,o>0?Ft(We,{palette:t,label:`${o} expired`,tone:"warning"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),Ft("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),Ft("box",{height:1,flexShrink:0},void 0,!1,void 0,this),r.entries.length===0?Ft("text",{fg:t.muted,children:"no cached credentials"},void 0,!1,void 0,this):Ft("box",{flexDirection:"column",overflow:"hidden",gap:1,children:r.entries.map((i)=>Ft("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:[Ft("text",{wrapMode:"none",children:[Ft("span",{fg:i.valid?t.success:t.warning,children:i.valid?"\u2713 valid":"\u2717 expired"},void 0,!1,void 0,this),Ft("span",{fg:t.muted,children:` \xB7 expires ${i.expires_at}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Ft("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),Ft(il,{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 $S=D(()=>{zt();ke()});import{jsxDEV as Rl}from"@opentui/react/jsx-dev-runtime";function yi(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 Rl("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:Rl("text",{wrapMode:"none",children:[Rl("span",{fg:e.palette.primary,children:"g"},void 0,!1,void 0,this),Rl("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 FS=()=>{};import{jsxDEV as Ds}from"@opentui/react/jsx-dev-runtime";function vi(e){let{palette:t,logs:r,names:n,service:o,errorOnly:i,width:s,onService:a,onToggleErrors:c,facets:l}=e,d=l?Cx(n,l):kx(n,r),u=s<80,f=d.map((y)=>{let x=y.name===""?"all":y.name;return{id:x,label:u?x:`${x} \xB7 ${y.count}`,color:Ze(y.name,t)}}),p=Math.max(0,d.findIndex((y)=>y.name===o)),m=i?"ERROR+":u?"lvls":"all levels",g=Math.max(ii(f[p]?.label??"all"),s-ii(m));return Ds(jt,{palette:t,backgroundColor:t.element,children:Ds("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[Ds("box",{flexGrow:1,overflow:"hidden",children:Ds(ol,{palette:t,items:f,active:p,width:g,emphasis:"fill",onPick:(y)=>{let x=d[y];if(x)a(x.name)}},void 0,!1,void 0,this)},void 0,!1,void 0,this),Ds(We,{palette:t,label:m,tone:i?"error":"muted",onMouseDown:c},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var NS=D(()=>{hr();Ln();ke();tt()});import{jsxDEV as $M}from"@opentui/react/jsx-dev-runtime";function Ms(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 $M(dt,{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 HS=D(()=>{ke()});import{useEffect as hf,useRef as BS}from"react";import{jsxDEV as Je}from"@opentui/react/jsx-dev-runtime";function xi(e){let{palette:t,logs:r,limit:n,width:o=80,followTick:i=0,focused:s=!1,wrapMode:a="clip",selected:c=-1,follow:l=!0,showTimestamps:d=!0,showMeta:u=!0,onPick:f,onLeaveLatest:p,viewStart:m=0,search:g="",regex:y=!1}=e,x=BS(null),h=BS(""),P=n===void 0?r:r.slice(-n),_=[...new Set(r.map((k)=>k.service))],w=yx(o,_),v=hx({width:o,serviceWidth:w,showTimestamps:d,showMeta:u}),b=P[P.length-1],S=b===void 0?"empty":String(b.seq);return hf(()=>{let k=x.current;if(!k)return;if(k.stickyScroll=l,l)k.stickyStart="bottom",k.scrollTo({x:k.scrollLeft,y:Math.max(0,k.scrollHeight)})},[l,i,S]),hf(()=>{let k=`${m}:${c}:${a}`;if(h.current===k)return;if(h.current=k,l&&(c<0||c>=P.length-1))return;let L=x.current;if(!L||c<0)return;let I=`log-row-${c}`,F=requestAnimationFrame(()=>{L.stickyScroll=!1,L.scrollChildIntoView(I)});return()=>cancelAnimationFrame(F)},[l,c,P.length,m,a]),hf(()=>{if(!l||!p)return;let k=!1,L=0,I=setInterval(()=>{let F=x.current;if(!F)return;let Q=F.viewport.height;if(Q<=0)return;let G=F.scrollHeight;if(F.scrollTop+Q>=G-NM){k=!0,L=G;return}if(G>L){F.stickyScroll=!0,F.stickyStart="bottom",F.scrollTo({x:F.scrollLeft,y:Math.max(0,G)}),L=G;return}if(k)p()},FM);return()=>{clearInterval(I)}},[l,i,p]),Je("box",{flexGrow:1,height:"100%",overflow:"hidden",children:Je("scrollbox",{ref:x,focused:s,stickyScroll:l,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:Je("box",{flexDirection:"column",overflow:"hidden",children:P.map((k,L)=>Je(HM,{id:`log-row-${L}`,palette:t,event:k,serviceWidth:w,msgWidth:v,expanded:mx(a,L===c),active:L===c,showTimestamps:d,showMeta:u,onPick:f?()=>f(L):void 0,search:g,regex:y},`${k.timestamp}-${k.service}-${L}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function HM(e){let{id:t,palette:r,event:n,serviceWidth:o,msgWidth:i,expanded:s,active:a,showTimestamps:c=!0,showMeta:l=!0,onPick:d,search:u="",regex:f=!1}=e,p=fx(Uc(n.message,i),i,s);return Je("box",{id:t,flexShrink:0,flexDirection:"column",overflow:"hidden",backgroundColor:a?r.highlight:void 0,onMouseDown:d,children:p.visible.map((m,g)=>Je("box",{height:1,flexDirection:"row",overflow:"hidden",children:[c?Je("box",{width:Bc,flexShrink:0,overflow:"hidden",children:Je("text",{fg:r.muted,children:g===0?n.timestamp.slice(11,19):""},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,Je("box",{width:o,flexShrink:0,overflow:"hidden",children:Je("text",{fg:g===0?Ze(n.service,r):r.muted,wrapMode:"none",children:g===0?oe(n.service,o):""},void 0,!1,void 0,this)},void 0,!1,void 0,this),Je("box",{width:ks,flexShrink:0,overflow:"hidden",children:Je("text",{children:" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),Je("box",{width:Wc,flexShrink:0,overflow:"hidden",children:Je("text",{fg:g===0?et(r,n.level):r.muted,children:g===0?jc(String(n.level)):""},void 0,!1,void 0,this)},void 0,!1,void 0,this),l?Je("box",{width:Hc,flexShrink:0,overflow:"hidden",children:Je("text",{fg:r.muted,children:g===0&&n.source?oe(n.source,Hc):""},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,Je("box",{width:ks,flexShrink:0,overflow:"hidden",children:Je("text",{fg:r.muted,children:g===0?" ":"\u2502"},void 0,!1,void 0,this)},void 0,!1,void 0,this),Je("box",{flexGrow:1,overflow:"hidden",children:Je(BM,{palette:r,level:n.level,text:m,mark:g===0?p.mark:"",search:u,regex:f},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},`${n.timestamp}-${g}`,!0,void 0,this))},void 0,!1,void 0,this)}function BM(e){let{palette:t,level:r,text:n,mark:o,search:i="",regex:s=!1}=e;return Je("text",{wrapMode:"none",children:[gx(n,i,s).map((a,c)=>Je("span",{fg:Gv(t,r,a.kind),children:a.text},`${a.kind}-${c}`,!1,void 0,this)),o===""?null:Je("span",{fg:t.muted,children:o},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var FM=200,NM=2;var WS=D(()=>{It();hr();tt()});var yf=D(()=>{FS();NS();HS();WS()});import{useRef as WM}from"react";import{jsxDEV as Le}from"@opentui/react/jsx-dev-runtime";function Pl(e){let{palette:t,names:r,snap:n,selected:o,checked:i,width:s,onOpen:a,onSelectIndex:c,onToggle:l}=e,d=ve(),u=WM(!1),f=new Set(i),p=hp(s),m=gp(s),g=mp(s),y=nx(s);return Le("box",{flexDirection:"column",flexGrow:1,overflow:"hidden",children:[Le("box",{height:1,flexDirection:"row",overflow:"hidden",children:[Le(Ut,{width:2,fg:t.muted,text:""},void 0,!1,void 0,this),Le(Ut,{width:4,fg:t.accent,text:"sel"},void 0,!1,void 0,this),Le(Ut,{width:2,fg:t.muted,text:""},void 0,!1,void 0,this),Le(Ut,{width:y,fg:t.muted,text:"name"},void 0,!1,void 0,this),Le(Ut,{width:$t,fg:t.muted,text:""},void 0,!1,void 0,this),Le(Ut,{width:Er,fg:t.muted,text:"state"},void 0,!1,void 0,this),g?Le(Ut,{width:Hr,fg:t.muted,text:"health"},void 0,!1,void 0,this):null,m?Le(Ut,{width:Tc,fg:t.muted,text:"port"},void 0,!1,void 0,this):null,p?Le(Ut,{width:nn,fg:t.muted,text:"pid"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),r.map((x,h)=>{let P=n?.services[x],_=tr(P),w=P?.health??"UNKNOWN",v=f.has(x),b=h===o,S=v?"[x]":"[ ]",k=b?"\u203A":" ";return Le("box",{height:d.rowH,flexDirection:"row",overflow:"hidden",backgroundColor:b?t.highlight:v?t.element:void 0,onMouseDown:()=>{if(u.current)return;if(b){a(x);return}c(h)},children:[Le("box",{width:2,flexShrink:0,children:Le("text",{fg:t.primary,children:k},void 0,!1,void 0,this)},void 0,!1,void 0,this),Le("box",{width:4,flexShrink:0,onMouseDown:()=>{u.current=!0,l?.(x),setTimeout(()=>{u.current=!1},0)},children:Le("text",{fg:jM(t,v,b),children:S},void 0,!1,void 0,this)},void 0,!1,void 0,this),Le("box",{width:2,flexShrink:0,children:Le("text",{fg:et(t,_),children:gr(_)},void 0,!1,void 0,this)},void 0,!1,void 0,this),Le(Ut,{width:y,fg:b?t.primary:Ze(x,t),text:oe(x,y)},void 0,!1,void 0,this),Le(Ut,{width:$t,fg:t.muted,text:""},void 0,!1,void 0,this),Le(Ut,{width:Er,fg:et(t,_),text:_},void 0,!1,void 0,this),g?Le(Ut,{width:Hr,fg:et(t,w),text:w},void 0,!1,void 0,this):null,m?Le(Ut,{width:Tc,fg:t.text,text:fo(P)},void 0,!1,void 0,this):null,p?Le(Ut,{width:nn,fg:t.text,text:P?.pid?String(P.pid):""},void 0,!1,void 0,this):null]},x,!0,void 0,this)})]},void 0,!0,void 0,this)}function _l(e){let{palette:t,checked:r}=e,n=r.length;if(n>0)return Le(dt,{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 jM(e,t,r){if(t)return e.success;if(r)return e.primary;return e.muted}function Ut(e){return Le("box",{width:e.width,flexShrink:0,overflow:"hidden",children:Le("text",{fg:e.fg,wrapMode:"none",children:e.text},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var vf=D(()=>{Ot();It();At();ke();tt()});import{jsxDEV as fe}from"@opentui/react/jsx-dev-runtime";function GS(e){let{palette:t,cfg:r,snap:n,logs:o,names:i,selected:s,selectedLog:a=-1,checked:c,width:l,followTick:d,logService:u,logSources:f,errorOnly:p,showSystemLogs:m,onOpen:g,onSelectIndex:y,onToggle:x,onFilterService:h,onToggleErrors:P,onShowErrors:_,wrapMode:w="clip",view:v,follow:b=!0,onLeaveLatest:S,onPickLog:k,viewStart:L=0,viewTotal:I,newer:F=0,onJumpLatest:Q,facets:G,leftover:C,search:B="",regex:W=!1}=e,V=ve();if(!r||i.length===0)return fe(Ve,{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 de=l<si,Ee=Mc(n),$e=tl(n,i),ne=i.filter((he)=>n?.services[he]?.state==="FAILED").length,H=Sx(o),ae=Ee?sx(C,n?.session_id):void 0,X=Dc(l,i,de),nt=Math.max(24,de?l-4:l-X-4),pt=m?o:o.filter((he)=>!oi(he.source)),ie=go(o,{service:u,errorOnly:p,systemLogs:m,search:B,regex:W}),Ae=v??ie,De=I??ie.length,Ke=Math.min(De,L+Ae.length),ht=De===0?"empty":`${L+1}\u2013${Ke} of ${De}`,Ye=u===""?"all":u,Ct=[...$e.running>0?[{text:`${$e.running}/${i.length}`,tone:"success"}]:[],...ne>0?[{text:`${ne} failed`,tone:"error"}]:[],...c.length>0?[{text:`${c.length} selected`,tone:"primary"}]:[],...H>0?[{text:`${H} errors`,tone:"error",onMouseDown:_}]:[]];return fe("box",{flexGrow:1,flexDirection:de?"column":"row",overflow:"hidden",children:[fe("box",{flexGrow:de?1:0,flexShrink:0,minWidth:de?void 0:X,width:de?void 0:X,border:!0,borderStyle:"rounded",borderColor:Ee?t.border:t.borderActive,backgroundColor:t.panel,title:"services",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[Ct.length>0?fe(dt,{palette:t,items:Ct},void 0,!1,void 0,this):null,fe(_l,{palette:t,checked:c},void 0,!1,void 0,this),fe("box",{flexGrow:1,paddingLeft:V.pad,paddingRight:V.pad,overflow:"hidden",children:fe(Pl,{palette:t,names:i,snap:n,selected:s,checked:c,width:Lc(X,V.pad),onOpen:g,onSelectIndex:y,onToggle:x},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe(qM,{palette:t,names:i,snap:n,width:X,onOpen:g},void 0,!1,void 0,this),ae?fe(JM,{palette:t,leftover:ae,width:X},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),fe("box",{position:"relative",flexGrow:2,minWidth:de?void 0:32,minHeight:de?8:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,backgroundColor:t.panel,title:`logs \xB7 ${Ye} \xB7 ${ht}`,titleColor:t.primary,overflow:"hidden",flexDirection:"column",children:[fe(vi,{palette:t,logs:pt,names:f??i,service:u,errorOnly:p,width:nt,onService:h,onToggleErrors:P,facets:G},void 0,!1,void 0,this),De>Ae.length?fe(Ms,{palette:t,start:L,count:Ae.length,total:De},void 0,!1,void 0,this):null,ie.length===0?fe(Ve,{palette:t,title:Ee?"Waiting for logs":o.length===0?"No events yet":"No events in this filter",body:Ee?"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(xi,{palette:t,logs:Ae,width:nt,followTick:d,focused:!1,wrapMode:w,selected:a,follow:b,onLeaveLatest:S,onPick:k,viewStart:L,search:B,regex:W},d,!1,void 0,this),!b?fe(yi,{palette:t,width:nt,newer:F,bottom:0,onJump:Q},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function UM(e){if(!e)return!1;return e.state===lt||e.health===Me||e.state===fr||e.restarts>0||e.last_error!==""}function jS(e){if(e.state===lt)return 0;if(e.health===Me)return 1;if(e.state===fr)return 2;return 3}function KM(e){if(e.last_error!=="")return e.last_error;if(e.restarts>0)return`restarted ${e.restarts}x, no error recorded`;return e.health===Me?"failing health check":e.state.toLowerCase()}function qM(e){let{palette:t,names:r,snap:n,width:o,onOpen:i}=e,s=r.map((d)=>({name:d,rt:n?.services[d]})).filter((d)=>UM(d.rt)).sort((d,u)=>jS(d.rt)-jS(u.rt));if(s.length===0)return null;let a=s.slice(0,GM),c=s.length-a.length,l=Math.max(8,o-xf-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:d,rt:u})=>{let f=tr(u);return fe("box",{height:1,flexDirection:"row",overflow:"hidden",onMouseDown:()=>i(d),children:[fe("box",{width:2,flexShrink:0,children:fe("text",{fg:et(t,f),children:gr(f)},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{width:xf,flexShrink:0,overflow:"hidden",children:fe("text",{fg:Ze(d,t),wrapMode:"none",children:oe(d,xf)},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{width:l,flexShrink:0,overflow:"hidden",children:fe("text",{fg:t.muted,wrapMode:"none",children:_e(KM(u),l)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},d,!0,void 0,this)}),c>0?fe("text",{fg:t.muted,wrapMode:"none",children:`+${c} more \u2014 open a service to see details`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function JM(e){let{palette:t,leftover:r,width:n}=e,o=r.processes.slice(0,VM),i=r.processes.length-o.length,s=Math.max(8,n-bf-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:_e(`${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:bf,flexShrink:0,overflow:"hidden",children:fe("text",{fg:t.text,wrapMode:"none",children:oe(a.name,bf)},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:_e(`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 GM=4,xf=14,VM=4,bf=14;var US=D(()=>{Tt();zt();Ot();yr();It();hr();At();nl();ke();tt();yf();vf()});import zM from"cli-spinners";import{useEffect as YM,useState as XM}from"react";import{jsxDEV as re}from"@opentui/react/jsx-dev-runtime";function KS(e){let{palette:t,report:r,loading:n,progress:o,error:i,selected:s,onPick:a,onReload:c}=e,l=di(s,Sf);if(n)return re(QM,{palette:t,progress:o},void 0,!1,void 0,this);if(i)return re(Tb,{palette:t,title:"Doctor failed",body:i},void 0,!1,void 0,this);if(!r)return re(Ve,{palette:t,title:"Doctor",body:"Diagnostics have not run yet.",hint:"opening this screen runs doctor"},void 0,!1,void 0,this);let d=r.checks.filter((y)=>y.severity==="ok").length,u=r.checks.filter((y)=>y.severity==="warn").length,f=r.checks.filter((y)=>y.severity==="error").length,p=r.checks.length,m=ni(p>0?d/p:0),g=f>0?t.error:u>0?t.warning:t.success;return re(kt,{palette:t,title:`doctor ${r.issues} issue(s)`,children:[re("box",{height:4,flexDirection:"column",flexShrink:0,alignItems:"center",justifyContent:"center",overflow:"hidden",border:!0,borderStyle:"rounded",borderColor:t.primary,backgroundColor:t.element,onMouseDown:c,children:[re("text",{wrapMode:"none",children:[re("span",{fg:t.inverse,bg:t.primary,children:" r "},void 0,!1,void 0,this),re("span",{fg:t.primary,children:" RUN DOCTOR AGAIN"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),re("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),re("box",{height:1,flexShrink:0},void 0,!1,void 0,this),re("box",{height:1,flexShrink:0,overflow:"hidden",children:re("text",{wrapMode:"none",children:[re("span",{fg:g,children:`[${m}]`},void 0,!1,void 0,this),re("span",{fg:t.success,children:` ${d} ok`},void 0,!1,void 0,this),u>0?re("span",{fg:t.warning,children:` \xB7 ${u} warn`},void 0,!1,void 0,this):null,f>0?re("span",{fg:t.error,children:` \xB7 ${f} error`},void 0,!1,void 0,this):null,u===0&&f===0?re("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),re("box",{height:1,flexShrink:0},void 0,!1,void 0,this),re("scrollbox",{ref:l,focused:!1,stickyScroll:!1,scrollX:!1,style:je(t),children:re("box",{flexDirection:"column",overflow:"hidden",gap:1,children:r.checks.map((y,x)=>re(ZM,{palette:t,check:y,index:x,active:x===s,onPick:a},`${y.name}-${x}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function QM({palette:e,progress:t}){let[r,n]=XM(0);return YM(()=>{let o=setInterval(()=>n((i)=>(i+1)%wf.frames.length),wf.interval);return()=>clearInterval(o)},[]),re("box",{flexGrow:1,alignItems:"center",justifyContent:"center",overflow:"hidden",children:re("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:[re("text",{wrapMode:"none",children:[re("span",{fg:e.primary,children:`${wf.frames[r]} `},void 0,!1,void 0,this),re("span",{fg:e.text,children:"devctl doctor"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),re("box",{height:1,flexShrink:0},void 0,!1,void 0,this),re("text",{fg:e.text,wrapMode:"none",children:`Checking ${t.active}`},void 0,!1,void 0,this),re("box",{height:1,flexShrink:0},void 0,!1,void 0,this),t.checks.slice(-4).map((o,i)=>re("text",{wrapMode:"none",children:[re("span",{fg:et(e,o.severity==="error"?"ERROR":o.severity==="warn"?"WARN":"OK"),children:`${gr(o.severity==="error"?"ERROR":o.severity==="warn"?"WARN":"OK")} `},void 0,!1,void 0,this),re("span",{fg:e.muted,children:o.name},void 0,!1,void 0,this)]},`${o.name}-${i}`,!0,void 0,this)),t.checks.length===0?re("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 ZM(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 re("box",{id:`${Sf}-${n}`,flexDirection:"row",flexShrink:0,paddingLeft:1,overflow:"hidden",backgroundColor:o?t.highlight:void 0,onMouseDown:()=>i(n),children:re("text",{wrapMode:"none",children:[re("span",{fg:t.primary,children:o?"\u203A ":" "},void 0,!1,void 0,this),re("span",{fg:et(t,s),children:gr(s)},void 0,!1,void 0,this),re("span",{fg:o?t.primary:t.text,children:` ${r.name}`},void 0,!1,void 0,this),re("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 c=r.severity==="error"?t.error:t.warning;return re("box",{id:`${Sf}-${n}`,border:!0,borderStyle:"rounded",borderColor:o?t.borderActive:c,title:r.name,titleColor:c,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",backgroundColor:o?t.highlight:void 0,onMouseDown:()=>i(n),children:[re("text",{wrapMode:"word",children:[re("span",{fg:et(t,s),children:`${gr(s)} `},void 0,!1,void 0,this),re("span",{fg:t.text,children:r.message},void 0,!1,void 0,this)]},void 0,!0,void 0,this),r.hint?re("text",{fg:t.info,wrapMode:"word",children:`\u2192 ${r.hint}`},void 0,!1,void 0,this):null,o&&r.action?.kind==="free-port"?re("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 Sf="doctor-row",wf;var qS=D(()=>{zt();It();ke();tt();wf=zM.bouncingBall});import{jsxDEV as Ge,Fragment as eO}from"@opentui/react/jsx-dev-runtime";function JS(e){let{palette:t,logs:r,names:n,logSources:o,service:i,errorOnly:s,showSystemLogs:a,search:c,searchFocused:l,followTick:d,width:u,onSearch:f,onService:p,onToggleErrors:m,onSelect:g,wrapMode:y="focus",selected:x=-1,follow:h=!0,newer:P=0,viewStart:_=0,viewTotal:w,onLeaveLatest:v,onJumpLatest:b,view:S,fullscreen:k=!1,facets:L,split:I=!1,splitFocus:F=0,serviceB:Q="",viewB:G,selectedB:C=-1,followB:B=!0,newerB:W=0,viewStartB:V=0,viewTotalB:de,onServiceB:Ee,onSelectB:$e,onLeaveLatestB:ne,onFocusPane:H}=e,ae=ve(),X=vp(u,ae.pad,k),nt=a?r:r.filter((he)=>!oi(he.source)),pt=go(r,{service:i,services:e.services,errorOnly:s,search:c,regex:e.regex,source:e.source,systemLogs:a}),ie=S??pt,Ae=w??pt.length,De=Math.min(Ae,_+ie.length),Ke=Ae===0?"empty":`${_+1}\u2013${De} of ${Ae}`,ht=e.services??[],Ye=ht.length>0?ht.join(","):i===""?"all services":i,Ct=[...h?[]:[{text:P>0?`${I?"left ":""}pinned \xB7 +${P} new`:`${I?"left ":""}pinned`,tone:"warning"}],...I&&!B?[{text:W>0?`right pinned \xB7 +${W} new`:"right pinned",tone:"warning"}]:[],...e.source?[{text:`src ${e.source}`,tone:"info"}]:[],...e.regex?[{text:"regex",tone:"accent"}]:[],...c===""?[]:[{text:`search ${c}`,tone:"accent"}],...I?[{text:F===0?"left pane":"right pane",tone:"accent"}]:[]];if(I){let he=Math.max(20,Math.floor(u/2)),yt=Math.max(20,u-he),st=G??[],vt=de??st.length;return Ge("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[l?Ge("box",{height:1,paddingLeft:1,backgroundColor:t.highlight,overflow:"hidden",children:Ge("input",{focused:!0,value:c,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):Ge(dt,{palette:t,items:Ct},void 0,!1,void 0,this),Ge("box",{flexGrow:1,flexDirection:"row",overflow:"hidden",children:[Ge(VS,{palette:t,names:o??n,logs:r,service:i,errorOnly:s,showSystemLogs:a,search:c,regex:e.regex,source:e.source,width:he,shown:ie,shownTotal:Ae,selected:x,follow:h,newer:P,viewStart:_,wrapMode:y,showTimestamps:e.showTimestamps!==!1,showMeta:e.showMeta!==!1,followTick:d,facets:L,focused:F===0,onService:p,onToggleErrors:m,onSelect:g,onLeaveLatest:v,onFocus:()=>H?.(0)},void 0,!1,void 0,this),Ge(VS,{palette:t,names:o??n,logs:r,service:Q,errorOnly:s,showSystemLogs:a,search:c,regex:e.regex,source:e.source,width:yt,shown:st,shownTotal:vt,selected:C,follow:B,newer:W,viewStart:V,wrapMode:y,showTimestamps:e.showTimestamps!==!1,showMeta:e.showMeta!==!1,followTick:d,facets:L,focused:F===1,onService:Ee??p,onToggleErrors:m,onSelect:$e,onLeaveLatest:ne,onFocus:()=>H?.(1)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),!h||!B?Ge(yi,{palette:t,width:u,newer:Math.max(P,W),onJump:b},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}return Ge("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[k?null:Ge(eO,{children:[Ct.length>0?Ge(dt,{palette:t,items:Ct},void 0,!1,void 0,this):null,Ge(vi,{palette:t,logs:nt,names:o??n,service:i,errorOnly:s,width:u,onService:p,onToggleErrors:m,facets:L},void 0,!1,void 0,this)]},void 0,!0,void 0,this),l?Ge("box",{height:1,paddingLeft:1,backgroundColor:t.highlight,overflow:"hidden",children:Ge("input",{focused:!0,value:c,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,S&&Ae>ie.length?Ge(Ms,{palette:t,start:_,count:ie.length,total:Ae},void 0,!1,void 0,this):null,Ge("box",{flexGrow:1,border:!k,borderStyle:"rounded",borderColor:t.border,title:k?void 0:`logs ${Ye} \xB7 ${Ke}`,titleColor:t.primary,padding:k?0:ae.pad,overflow:"hidden",children:ie.length===0?Ge(Ve,{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 ${Mt("l")} clear`},void 0,!1,void 0,this):Ge(xi,{palette:t,logs:ie,width:X,followTick:d,focused:!1,wrapMode:y,selected:x,follow:h,showTimestamps:e.showTimestamps!==!1,showMeta:e.showMeta!==!1,onPick:g,onLeaveLatest:v,viewStart:_,search:c,regex:e.regex===!0},d,!1,void 0,this)},void 0,!1,void 0,this),!h?Ge(yi,{palette:t,width:u,newer:P,onJump:b},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function VS(e){let{palette:t,width:r,service:n,shown:o,shownTotal:i,viewStart:s,focused:a}=e,c=e.showSystemLogs?e.logs:e.logs.filter((u)=>!oi(u.source)),l=n===""?"all services":n,d=i===0?"empty":`${s+1}\u2013${Math.min(i,s+o.length)} of ${i}`;return Ge("box",{width:r,flexGrow:0,flexShrink:0,flexDirection:"column",overflow:"hidden",onMouseDown:e.onFocus,children:[Ge(vi,{palette:t,logs:c,names:e.names,service:n,errorOnly:e.errorOnly,width:r,onService:(u)=>{e.onFocus(),e.onService(u)},onToggleErrors:()=>{e.onFocus(),e.onToggleErrors()},facets:e.facets},void 0,!1,void 0,this),Ge("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:a?t.borderActive:t.border,title:`logs ${l} \xB7 ${d}`,titleColor:a?t.primary:t.muted,overflow:"hidden",children:o.length===0?Ge(Ve,{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):Ge(xi,{palette:t,logs:o,width:vp(r,0,!1),followTick:e.followTick,focused:!1,wrapMode:e.wrapMode,selected:e.selected,follow:e.follow,showTimestamps:e.showTimestamps,showMeta:e.showMeta,onPick:(u)=>{e.onFocus(),e.onSelect?.(u)},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 zS=D(()=>{yf();zt();Ot();hr();ke();Pr()});import{jsxDEV as Ue}from"@opentui/react/jsx-dev-runtime";function XS(e){let{palette:t,cfg:r,snap:n,profile:o,selected:i,onPick:s}=e,a=ve(),c=di(i,YS),l=Object.keys(r?.profiles??{}).sort();if(l.length===0)return Ue(Ve,{palette:t,title:"No profiles",body:"Add profiles.<name>.services in config.yaml."},void 0,!1,void 0,this);return Ue(kt,{palette:t,title:"profiles",children:[Ue("box",{height:1,flexShrink:0,overflow:"hidden",children:Ue("text",{fg:t.muted,wrapMode:"none",children:[`${l.length} profile${l.length===1?"":"s"} \xB7 current: `,Ue("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),Ue("box",{height:1,flexShrink:0},void 0,!1,void 0,this),Ue("scrollbox",{ref:c,focused:!1,stickyScroll:!1,scrollX:!1,style:je(t),children:Ue("box",{flexDirection:"column",overflow:"hidden",gap:a.gap||1,children:l.map((d,u)=>{let f=d===o,p=u===i,m=r?.profiles[d]?.services??[],g=Object.keys(r?.profiles[d]?.environment??{}).length,y=p?t.borderActive:f?t.success:t.border,x=p?t.primary:f?t.success:t.muted;return Ue("box",{id:`${YS}-${u}`,border:!0,borderStyle:"rounded",borderColor:y,title:d,titleColor:x,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",backgroundColor:p?t.highlight:void 0,onMouseDown:()=>s(u),children:[Ue("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:Ue("text",{wrapMode:"none",children:[f?Ue("span",{fg:t.success,children:"\u25CF current profile"},void 0,!1,void 0,this):Ue("span",{fg:t.muted,children:"\u25CB not active"},void 0,!1,void 0,this),Ue("span",{fg:t.muted,children:` \xB7 ${m.length} service${m.length===1?"":"s"}`},void 0,!1,void 0,this),g>0?Ue("span",{fg:t.muted,children:` \xB7 ${g} env var${g===1?"":"s"}`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Ue("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:m.length===0?Ue("text",{fg:t.muted,wrapMode:"none",children:"(no services)"},void 0,!1,void 0,this):Ue("text",{wrapMode:"word",children:m.map((h,P)=>{let _=tr(n?.services[h]);return Ue("span",{children:[Ue("span",{fg:et(t,_),children:gr(_)},void 0,!1,void 0,this),Ue("span",{fg:Ze(h,t),children:` ${h}`},void 0,!1,void 0,this),P<m.length-1?Ue("span",{fg:t.muted,children:" "},void 0,!1,void 0,this):null]},h,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},d,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this),Ue(jt,{palette:t,backgroundColor:t.element,edge:"top",children:Ue(ot,{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 YS="profile-row";var QS=D(()=>{zt();Ot();At();ke();tt()});import{jsxDEV as q,Fragment as rk}from"@opentui/react/jsx-dev-runtime";function tO(e){let t=e.toLowerCase();if(t==="iap")return"info";if(t==="service"||t==="service_account")return"primary";return"idle"}function rO(e,t,r){if(r||t>=500)return e.error;if(t===0||t>=400)return e.warning;return e.success}function nO(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 aO(e){let{palette:t,req:r,cols:n}=e,o=rO(t,r.status,r.error),i=r.status>0?String(r.status):"ERR",s=nO(t,r.identity),a=r.route||nk,c=r.error?`${r.path} \u2014 ${_e(r.error,sO)}`:r.path;return q("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[q("box",{width:kf,flexShrink:0,overflow:"hidden",children:q("text",{fg:t.muted,children:r.timestamp.slice(11,19)},void 0,!1,void 0,this)},void 0,!1,void 0,this),n.showMethod?q("box",{width:El,flexShrink:0,overflow:"hidden",children:q("text",{fg:t.text,wrapMode:"none",children:oe(r.method,El)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,q("box",{width:Tl,flexShrink:0,overflow:"hidden",children:q("text",{fg:o,wrapMode:"none",children:oe(i,Tl)},void 0,!1,void 0,this)},void 0,!1,void 0,this),n.showDur?q("box",{width:Al,flexShrink:0,overflow:"hidden",children:q("text",{fg:t.muted,wrapMode:"none",children:oe(`${r.durationMs}ms`,Al)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,q("box",{width:Ll,flexShrink:0,overflow:"hidden",children:q("text",{fg:s.color,wrapMode:"none",children:oe(s.label,Ll)},void 0,!1,void 0,this)},void 0,!1,void 0,this),q("box",{width:n.routeCol,flexShrink:0,overflow:"hidden",children:q("text",{fg:r.route?t.info:t.muted,wrapMode:"none",children:oe(a,n.routeCol)},void 0,!1,void 0,this)},void 0,!1,void 0,this),q("box",{flexGrow:1,overflow:"hidden",children:q("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 cO(e){let{palette:t,cols:r}=e;return q("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:[q("box",{width:kf,flexShrink:0,overflow:"hidden",children:q("text",{fg:t.muted,children:oe("TIME",kf)},void 0,!1,void 0,this)},void 0,!1,void 0,this),r.showMethod?q("box",{width:El,flexShrink:0,overflow:"hidden",children:q("text",{fg:t.muted,children:oe("METHOD",El)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,q("box",{width:Tl,flexShrink:0,overflow:"hidden",children:q("text",{fg:t.muted,children:oe("ST",Tl)},void 0,!1,void 0,this)},void 0,!1,void 0,this),r.showDur?q("box",{width:Al,flexShrink:0,overflow:"hidden",children:q("text",{fg:t.muted,children:oe("DUR",Al)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,q("box",{width:Ll,flexShrink:0,overflow:"hidden",children:q("text",{fg:t.muted,children:oe("WHO",Ll)},void 0,!1,void 0,this)},void 0,!1,void 0,this),q("box",{width:r.routeCol,flexShrink:0,overflow:"hidden",children:q("text",{fg:t.muted,children:oe("ROUTE",r.routeCol)},void 0,!1,void 0,this)},void 0,!1,void 0,this),q("box",{flexGrow:1,overflow:"hidden",children:q("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 lO(e){let{palette:t,name:r,auth:n,identity:o,upstream:i,match:s,onMouseDown:a}=e;return q("box",{flexDirection:"column",flexShrink:0,overflow:"hidden",onMouseDown:a,children:[q("text",{fg:t.text,wrapMode:"none",children:r},void 0,!1,void 0,this),q("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[q(We,{palette:t,label:n||"no auth",tone:tO(n)},void 0,!1,void 0,this),o?q(We,{palette:t,label:o,tone:"idle"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),s?q("text",{fg:t.muted,wrapMode:"word",children:`match: ${s}`},void 0,!1,void 0,this):null,q("text",{fg:t.muted,wrapMode:"word",children:`\u2192 ${i}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function ok(e){let{palette:t,cfg:r,snap:n,width:o,onSelectRoute:i}=e,s=n?.proxy.routes??[],a=new Map((r?.proxy.routes??[]).map((w)=>[w.name,w])),c=new Map((r?.proxy.routes??[]).map((w)=>[w.name,w.match])),l=n?.proxy.recentRequests??[],d=n?.proxy.requestTotal??0,u=n?.proxy.requestErrors??0,f=o<si,p=Math.max(ZS,Math.min(dO,Math.floor(o*0.36))),m=f?o-ek:o-p-ek,g=Math.max(20,m-2),y=g>=tk,x=g>=uO,h=g>=tk?pO:fO,P=l.reduce((w,v)=>Math.min(h,Math.max(w,(v.route||nk).length+iO)),oO),_={showMethod:y,showDur:x,routeCol:P};return q(kt,{palette:t,title:"proxy",children:[q(dt,{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:`${s.length} routes`,tone:s.length>0?"primary":"idle"},...d>0?[{text:`${d} requests`,tone:"idle"},...u>0?[{text:`${u} errors`,tone:"warning"}]:[]]:[]]},void 0,!1,void 0,this),q("box",{flexGrow:1,flexDirection:f?"column":"row",overflow:"hidden",children:[q("box",{flexGrow:f?1:0,flexBasis:f?0:void 0,flexShrink:0,minWidth:f?void 0:ZS,width:f?void 0:p,minHeight:f?8:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,title:"routes",titleColor:t.primary,paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",children:s.length===0?q(Ve,{palette:t,title:"No proxy routes",body:"Add routes under proxy.routes or .devctl/proxy/routes.yaml."},void 0,!1,void 0,this):q(rk,{children:[i?q("text",{fg:t.muted,wrapMode:"word",children:"click a route for full details"},void 0,!1,void 0,this):null,q("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:je(t),children:q("box",{flexDirection:"column",overflow:"hidden",gap:1,children:s.map((w)=>{let v=c.get(w.name),b=v&&(v.host||v.path)?`${v.host||"*"}${v.path?v.path:""}`:void 0,S=a.get(w.name);return q(lO,{palette:t,name:w.name,auth:w.auth,identity:w.identity,upstream:w.upstream,match:b,onMouseDown:i?()=>i({name:w.name,authType:S?.auth.type||w.auth,identityType:S?.auth.identity.type??"",serviceAccount:S?.auth.identity.service_account||S?.auth.service_account||"",audience:S?.auth.audience??"",matchHost:S?.match.host??"",matchPath:S?.match.path??"",upstream:w.upstream}):void 0},w.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),q("box",{flexGrow:1,flexBasis:0,minWidth:f?void 0:30,minHeight:f?10:void 0,border:!0,borderStyle:"rounded",borderColor:t.borderActive,title:"requests",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:l.length===0?q("box",{paddingLeft:1,paddingRight:1,children:q("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):q(rk,{children:[q(cO,{palette:t,cols:_},void 0,!1,void 0,this),q("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:je(t),children:q("box",{flexDirection:"column",overflow:"hidden",children:l.map((w)=>q(aO,{palette:t,req:w,cols:_},w.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),q(jt,{palette:t,backgroundColor:t.element,edge:"top",children:q(ot,{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 kf=9,El=8,Tl=4,Al=8,Ll=4,oO=8,iO=2,sO=64,nk="(none)",ZS=26,dO=56,ek=2,tk=46,uO=54,pO=20,fO=12;var ik=D(()=>{zt();yr();It();ke()});import{jsxDEV as pe}from"@opentui/react/jsx-dev-runtime";function ck(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:Ze(r,t),flexDirection:"column",overflow:"hidden",children:pe(Cf,{...e,compact:!1},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Cf(e){let{palette:t,cfg:r,snap:n,name:o,reveal:i,width:s,compact:a=!0,envScrollRef:c}=e,l=ve(),d=r?.services[o];if(!d)return pe(Ve,{palette:t,title:"Unknown service",body:`No service named ${o}.`,hint:"j/k move"},void 0,!1,void 0,this);let u=n?.services[o],f=tr(u),p=u?.health??"UNKNOWN",m=fo(u)||ws(d,u),g=ix(d,i,r?.secrets.extra_markers??[],r?.secrets.extra_patterns??[],e.resolvedEnv),y=e.envStatus==="error"?"error":e.envStatus==="resolved"?"success":e.envStatus==="loading"?"info":"muted",x=e.envStatus==="resolved"?"resolved":e.envStatus==="loading"?"resolving":e.envStatus==="error"?"config fallback":"config",h=s>=gO,P=[{label:"health",value:$c(d)},{label:"workdir",value:d.working_dir||"."},{label:"restart",value:Nc(d)},{label:"caps",value:d.capabilities.join(", ")||"\u2014"},{label:"runtime",value:d.container?`${d.container.runtime||"docker"} \xB7 ${d.container.image}`:"host"},...d.watch.enabled?[{label:"watch",value:d.watch.paths.join(" ")||"on"}]:[]],_=[{label:"identity",value:Fc(d,u)},{label:"depends",value:d.dependencies.map(xa).join(", ")||"\u2014"},{label:"ports",value:ws(d,u)},{label:"tries",value:String(u?.restarts??0),tone:u?.restarts?"warning":"muted"}],w=Math.max(wo+8,s-2),v=h?Math.floor(w/2):w;return pe("box",{padding:l.pad,flexGrow:1,flexDirection:"column",overflow:"hidden",children:[pe(dt,{palette:t,items:[{text:f,tone:ak(f)},{text:p,tone:ak(p)},{text:u?.pid?`pid ${u.pid}`:"pid \u2014",tone:u?.pid?"info":"idle"},{text:m==="\u2014"?"port \u2014":`port ${m}`,tone:m==="\u2014"?"idle":"info"}]},void 0,!1,void 0,this),d.description?pe("box",{height:1,overflow:"hidden",children:pe("text",{fg:t.muted,wrapMode:"none",children:_e(d.description,Math.max(8,s-4))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,u?.last_error?pe("box",{height:1,overflow:"hidden",children:pe("text",{fg:t.error,wrapMode:"none",children:_e(u.last_error,mO)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,pe(Rf,{palette:t,item:{label:"command",value:Ic(d)},valueWidth:Math.max(8,w-wo)},void 0,!1,void 0,this),pe(hO,{palette:t,left:P,right:_,wide:h,colWidth:v},void 0,!1,void 0,this),pe(yO,{palette:t,entries:g,reveal:i,width:s,focused:!a,scrollRef:c,source:x,sourceTone:y,error:e.envError,onSelect:e.onSelectEnv},void 0,!1,void 0,this),a?null:pe(ot,{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 hO(e){let{palette:t,left:r,right:n,wide:o,colWidth:i}=e,s=Math.max(4,i-wo);if(!o)return pe("box",{width:i,flexShrink:0,flexDirection:"column",overflow:"hidden",children:[...r,...n].map((a)=>pe(Rf,{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(sk,{palette:t,items:r,width:i},void 0,!1,void 0,this),pe(sk,{palette:t,items:n,width:i},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function sk(e){let t=Math.max(4,e.width-wo);return pe("box",{width:e.width,flexShrink:0,flexDirection:"column",overflow:"hidden",children:e.items.map((r)=>pe(Rf,{palette:e.palette,item:r,valueWidth:t},r.label,!1,void 0,this))},void 0,!1,void 0,this)}function Rf(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:wo+n,flexDirection:"row",overflow:"hidden",children:[pe("box",{width:wo,flexShrink:0,overflow:"hidden",children:pe("text",{fg:t.muted,wrapMode:"none",children:oe(r.label,wo)},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:oe(r.value,n)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function yO(e){let{palette:t,entries:r,reveal:n,width:o,focused:i,scrollRef:s,source:a,sourceTone:c,error:l,onSelect:d}=e;return pe("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[pe(dt,{palette:t,items:[{text:`env ${r.length}`,tone:r.length>0?"info":"idle"},{text:a,tone:c},{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),l?pe("box",{height:1,overflow:"hidden",children:pe("text",{fg:t.warning,wrapMode:"none",children:_e(l,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:[d?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((u)=>{let f=u.required?t.warning:u.fromConfig?t.accent:t.muted,p=u.value===""&&u.required?"(required)":u.value;return pe("box",{flexDirection:"row",overflow:"hidden",onMouseDown:d?()=>d(u):void 0,children:pe("text",{wrapMode:"word",children:[pe("span",{fg:f,children:u.required?`${u.key}*`:u.key},void 0,!1,void 0,this),pe("span",{fg:u.value===""?t.muted:t.text,children:` ${p}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},u.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 ak(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 mO=72,gO=56,wo=9;var Pf=D(()=>{mt();zt();Ot();It();At();ke();tt()});import{jsxDEV as Fn}from"@opentui/react/jsx-dev-runtime";function lk(e){let{palette:t,cfg:r,names:n,snap:o,selected:i,checked:s,width:a,reveal:c,onOpen:l,onSelectIndex:d,onToggle:u,resolvedEnv:f,envStatus:p,envError:m,onSelectEnv:g}=e;if(n.length===0)return Fn(Ve,{palette:t,title:"No services",body:"This configuration does not define any services."},void 0,!1,void 0,this);let y=a<si,x=n[i]??"",h=Dc(a,n,y),P=4,_=y?Math.max(_f,a-P):Math.max(_f,a-h-P);return Fn("box",{flexGrow:1,flexDirection:y?"column":"row",overflow:"hidden",children:[Fn("box",{flexGrow:y?1:0,flexShrink:0,minWidth:y?void 0:Ec,width:y?void 0:h,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:"services",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[Fn(_l,{palette:t,checked:s},void 0,!1,void 0,this),Fn("box",{flexGrow:1,overflow:"hidden",children:Fn(Pl,{palette:t,names:n,snap:o,selected:i,checked:s,width:Lc(h),onOpen:l,onSelectIndex:d,onToggle:u},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Fn("box",{flexGrow:2,minWidth:y?void 0:_f,minHeight:y?vO:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,backgroundColor:t.panel,title:x||"detail",titleColor:x?Ze(x,t):t.primary,overflow:"hidden",flexDirection:"column",children:Fn(Cf,{palette:t,cfg:r,snap:o,name:x,reveal:c,width:_,resolvedEnv:f,envStatus:p,envError:m,onSelectEnv:g},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var _f=36,vO=12;var dk=D(()=>{zt();yr();At();tt();Pf();vf()});import{jsxDEV as we}from"@opentui/react/jsx-dev-runtime";function bO(e){switch(e){case"cycle":return"\u2194";case"toggle":return"\u23FB";case"page":return"\u25B8";case"action":return"!";default:return"\xB7"}}function mk(e){let{palette:t,items:r,selected:n,locked:o,width:i,onPick:s,onActivate:a}=e,c=ve(),l=ap(r,n),d=Tn(r,l);return we("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:"settings",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[we("box",{height:2,paddingLeft:c.pad,flexShrink:0,flexDirection:"column",overflow:"hidden",children:[we("text",{fg:t.primary,wrapMode:"none",children:"Preferences"},void 0,!1,void 0,this),we("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),we("box",{flexGrow:1,paddingLeft:c.pad,paddingRight:c.pad,overflow:"hidden",flexShrink:1,children:we(wO,{palette:t,items:r,active:l,scale:c,width:i,onPick:s,onActivate:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),we(kO,{palette:t,item:d,scale:c},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function wO(e){let{palette:t,items:r,active:n,scale:o,width:i,onPick:s,onActivate:a}=e,c=di(n,fk),l=Math.max(8,i-uk-pk-10),d=0,u=Xv(r);return we("scrollbox",{ref:c,focused:!1,stickyScroll:!1,scrollX:!1,style:je(t),children:we("box",{flexDirection:"column",overflow:"hidden",children:u.map((f,p)=>{let m=d;d+=f.items.length;let g=n>=m&&n<m+f.items.length;return we("box",{flexDirection:"column",flexShrink:0,marginBottom:p<u.length-1?Math.max(1,o.gap):0,overflow:"hidden",children:[we("box",{height:1,overflow:"hidden",children:we("text",{fg:g?t.primary:t.muted,wrapMode:"none",children:f.group},void 0,!1,void 0,this)},void 0,!1,void 0,this),f.group==="MCP"?we("box",{height:1,overflow:"hidden",children:we("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((y,x)=>{let h=m+x;return we(SO,{index:h,palette:t,item:y,active:h===n,rowH:o.rowH,valueWidth:l,onPick:()=>s(h),onActivate:()=>a(y)},y.id,!1,void 0,this)})]},f.group,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function SO(e){let{palette:t,index:r,item:n,active:o,rowH:i,valueWidth:s,onPick:a,onActivate:c}=e;return we("box",{id:`${fk}-${r}`,height:i,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:o?t.highlight:void 0,onMouseDown:()=>{if(o){c();return}a()},children:[we("box",{width:2,flexShrink:0,overflow:"hidden",children:we("text",{fg:t.primary,children:o?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),we("box",{width:pk,flexShrink:0,overflow:"hidden",children:we("text",{fg:o?t.primary:t.muted,children:bO(n.kind)},void 0,!1,void 0,this)},void 0,!1,void 0,this),we("box",{width:uk,flexShrink:0,overflow:"hidden",children:we("text",{fg:o?t.primary:t.text,wrapMode:"none",children:n.name},void 0,!1,void 0,this)},void 0,!1,void 0,this),we("box",{flexGrow:1,overflow:"hidden",children:we("text",{fg:CO(t,n,o),wrapMode:"none",children:_e(n.value,s)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function kO(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 we("box",{height:xO,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:[we("box",{height:1,overflow:"hidden",children:we("text",{fg:t.primary,wrapMode:"none",children:o?`${zv(n.steps)} ${n.label}`:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),we("box",{height:1,overflow:"hidden",children:we("text",{fg:t.text,wrapMode:"word",children:r?.detail??""},void 0,!1,void 0,this)},void 0,!1,void 0,this),we("box",{height:1,overflow:"hidden",children:we("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 CO(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 uk=14,pk=2,xO=5,fk="settings-row";var gk=D(()=>{Ot();It();ke();_r()});import{jsxDEV as Te}from"@opentui/react/jsx-dev-runtime";function hk(e){let{palette:t,cfg:r,google:n,bootError:o,bootErrorMissing:i=!1,step:s=0}=e,a=ve();if(o&&!r)return i?Te(Ve,{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):Te(Ve,{palette:t,title:"Configuration error",body:o,hint:"Fix .devctl/config.yaml, then restart devctl [Esc] Exit"},void 0,!1,void 0,this);let c=e.issues,l=RO(r,n,c),d=l.filter((h)=>h.ok).length,u=l.length,f=u>0?Math.round(d/u*100):0,p=20,m=Math.round(f/100*p),g="\u2588".repeat(m)+"\u2591".repeat(Math.max(0,p-m)),y=f===100?t.success:f===0?t.muted:t.primary,x=l[s];return Te(kt,{palette:t,title:"setup",scroll:!0,children:[Te("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:Te("text",{fg:t.primary,children:"Developer onboarding"},void 0,!1,void 0,this)},void 0,!1,void 0,this),Te("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:Te("text",{wrapMode:"none",children:[Te("span",{fg:y,children:`[${g}]`},void 0,!1,void 0,this),Te("span",{fg:t.text,children:` ${d}/${u} ready`},void 0,!1,void 0,this),Te("span",{fg:t.muted,children:` (${f}%)`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Te("box",{height:1,flexShrink:0},void 0,!1,void 0,this),l.map((h,P)=>{let _=P===s;return Te("box",{height:a.rowH,flexDirection:"row",overflow:"hidden",backgroundColor:_?t.highlight:void 0,paddingLeft:1,children:[Te("box",{width:2,flexShrink:0,children:Te("text",{fg:et(t,h.ok?"OK":"WARN"),children:gr(h.ok?"OK":"WARN")},void 0,!1,void 0,this)},void 0,!1,void 0,this),Te("box",{width:3,flexShrink:0,children:Te("text",{fg:_?t.primary:t.muted,children:String(P+1).padStart(2," ")},void 0,!1,void 0,this)},void 0,!1,void 0,this),Te("box",{width:20,flexShrink:0,overflow:"hidden",children:Te("text",{fg:_?t.primary:t.text,children:h.name},void 0,!1,void 0,this)},void 0,!1,void 0,this),Te("box",{flexGrow:1,overflow:"hidden",children:Te("text",{fg:_?t.text:t.muted,wrapMode:"none",children:h.detail},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},h.name,!0,void 0,this)}),Te("box",{height:1,flexShrink:0},void 0,!1,void 0,this),x?Te("box",{border:!0,borderStyle:"rounded",borderColor:x.ok?t.success:t.warning,title:x.name,titleColor:x.ok?t.success:t.warning,flexDirection:"column",paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:Te("text",{fg:x.ok?t.text:t.warning,wrapMode:"word",children:x.detail},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,Te("box",{height:1,flexShrink:0},void 0,!1,void 0,this),Te("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:Te(We,{palette:t,label:"never hard-coded",tone:"idle"},void 0,!1,void 0,this)},void 0,!1,void 0,this),Te("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),Te(ot,{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 RO(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=Sl(e,void 0,t).project;return[{name:an[0],ok:Boolean(e?.repoRoot),detail:e?.repoRoot||"unknown"},{name:an[1],ok:Boolean(e?.project.name),detail:e?.project.name||"set project.name"},{name:an[2],ok:Boolean(i),detail:i||"optional for local-only"},{name:an[3],ok:t?.adcAvailable===!0,detail:t?.adcAvailable?"ADC available":"needed only for cloud identity / IAP"},{name:an[4],ok:!0,detail:"read from configuration; never hard-coded"},{name:an[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:an[6],ok:n.length===0||Boolean(e),detail:`${n.length} fixed ports from configuration`},{name:an[7],ok:Object.keys(e?.profiles??{}).length>0,detail:`${Object.keys(e?.profiles??{}).length} profile(s)`},{name:an[8],ok:r.length===0,detail:r.length===0?"configuration is valid":r[0]??"invalid"}]}var an;var yk=D(()=>{zt();Ot();ke();tt();an=["Repository","Environment","Google project","Authentication","Service accounts","IAP","Ports","Profiles","Validation"]});import{useEffect as PO,useState as _O}from"react";import{jsxDEV as Z}from"@opentui/react/jsx-dev-runtime";function bi(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 Z("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 Ef(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 Is(e){let{palette:t,cells:r,header:n,gap:o=0,stripe:i}=e;return Z("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:i?t.element:void 0,children:r.map((s,a)=>Z("box",{flexDirection:"row",flexShrink:0,overflow:"hidden",children:[a>0&&o>0?Z("box",{width:o,flexShrink:0},void 0,!1,void 0,this):null,Z("box",{width:s.width,flexShrink:0,overflow:"hidden",children:Z("text",{fg:n?t.primary:Ef(t,s),wrapMode:"none",children:oe(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 vk(e){let{palette:t,width:r}=e;return Z("box",{height:1,flexShrink:0,overflow:"hidden",children:Z("text",{fg:t.border,wrapMode:"none",children:oe("\u2500".repeat(Math.max(1,r)),r)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Os(e){let{palette:t,facts:r,width:n}=e,o=Op(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}),Z("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[Z(Is,{palette:t,header:!0,gap:li,cells:i},void 0,!1,void 0,this),Z(vk,{palette:t,width:n},void 0,!1,void 0,this),r.map((s,a)=>{let c=s.meaning===""?[""]:Uc(s.meaning,Math.max(1,o.meaning)),l=s.meter?gb(s.meter):o.meter>0?"":void 0,d=[{text:s.what,width:o.what,tone:"text"},{text:s.reading,width:o.reading,tone:s.tone??"text"}];if(o.meter>0)d.push({text:l??"",width:o.meter,tone:s.meter?s.tone??"text":"muted"});return d.push({text:c[0]??"",width:o.meaning,tone:"muted"}),Z("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[Z(Is,{palette:t,gap:li,stripe:a%2===1,cells:d},void 0,!1,void 0,this),c.slice(1).map((u,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:u,width:o.meaning,tone:"muted"}),Z(Is,{palette:t,gap:li,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 xk(e){let{palette:t,cfg:r,snap:n,width:o,onRefresh:i}=e,s=ve(),[,a]=_O(0);if(PO(()=>{let W=setInterval(()=>{a((V)=>{let de=V+1;if(i&&de%TO===0)i();return de})},EO);return()=>clearInterval(W)},[i]),!r)return Z(Ve,{palette:t,title:"No configuration loaded",body:"Add services to .devctl/config.yaml or finish setup."},void 0,!1,void 0,this);let c=Object.keys(r.services).sort(),l=c.some((W)=>hb(r.services[W])),d=cb(c,n),u=kb(d,l),f=l&&d.live>0?d.healthy/d.live:d.total>0?d.live/d.total:0,p=ni(f,AO),m=d.failed>0?"error":l&&d.live>0&&d.healthy<d.live?"warning":"success",g=pb(o,s.pad),y=n?.session_id?Gl(n.session_id):void 0,x=y?hs(Date.now()-y.getTime()):"just started",h=n?.logs.total??0,P=n?.logs.errors??0,_=ub(n?.logs.counts??{}),w=n?.proxy.routes??[],v=n?.credentials,b=(v?.entries??[]).filter((W)=>W.valid).length,S=n?.system,k=S?S.memAvailableKB??S.memFreeKB:0,L=S?vb(S.loadAvg1,S.cpuCount):void 0,I=S?xb(k,S.memTotalKB):void 0,F=[];if(S&&L&&I){F.push(L,I,{what:"Computer",reading:yb(S.platform),meaning:`on for ${hs(S.hostUptimeSec*LO)}`,tone:"text"});let W=n?.stats_series;if(W&&W.cpu.length>1)F.push({what:"Load trend",reading:Mp(W.cpu),meaning:`${Math.round(W.interval_ms/1000)}s samples`,tone:"text"});if(W&&W.mem.length>1)F.push({what:"RAM trend",reading:Mp(W.mem),meaning:"used memory over the same window",tone:"text"})}let Q=d.failed>0||L?.tone==="error"||I?.tone==="error"?"error":m==="warning"||L?.tone==="warning"||I?.tone==="warning"?"warning":"success",G=[{what:"This session",reading:x,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"}],C=[{what:"Lines kept",reading:String(h),meaning:"log lines still in memory",tone:"text"},{what:"Error lines",reading:String(P),meaning:P>0?"open Logs and press e to see only errors":"no ERROR or FATAL lines",tone:P>0?"error":"muted"},..._.map(([W,V])=>({what:W,reading:String(V),meaning:"lines from this service",tone:"text"}))],B=[{what:"Web proxy",reading:n?.proxy.running?"on":"off",meaning:n?.proxy.running?`${w.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:v?`${b} of ${v.entries.length} good`:"none",meaning:v?Sb(v.backend):"nothing stored yet",tone:v&&b<v.entries.length?"warning":v?"success":"muted"}];return Z(kt,{palette:t,title:"stats",scroll:!0,children:[Z(bi,{palette:t,title:`Your services ${d.live} of ${d.total} started`,tone:Q,children:[Z(Os,{palette:t,facts:u,width:g},void 0,!1,void 0,this),Z("box",{height:1,flexShrink:0},void 0,!1,void 0,this),Z("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:Z("text",{wrapMode:"none",children:[Z("span",{fg:t.muted,children:oe(l?"Ready":"Started",Op(u,g).what)},void 0,!1,void 0,this),Z("span",{children:" ".repeat(li)},void 0,!1,void 0,this),Z("span",{fg:Ef(t,{text:"",width:1,tone:m}),children:`[${p}]`},void 0,!1,void 0,this),Z("span",{fg:Ef(t,{text:"",width:1,tone:m}),children:l?` ${d.healthy} of ${d.live||d.total} passing checks`:` ${d.live} of ${d.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),S?Z(bi,{palette:t,title:"This computer",tone:L?.tone==="error"||I?.tone==="error"?"error":L?.tone==="warning"||I?.tone==="warning"?"warning":"success",children:Z(Os,{palette:t,facts:F,width:g},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,Z(bi,{palette:t,title:"This session",children:Z(Os,{palette:t,facts:G,width:g},void 0,!1,void 0,this)},void 0,!1,void 0,this),Z(bi,{palette:t,title:"Each service",tone:d.failed>0?"error":l&&d.live>0&&d.healthy<d.live?"warning":"success",children:d.total===0?Z("text",{fg:t.muted,children:"No services in this project yet."},void 0,!1,void 0,this):Z("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[Z(DO,{palette:t,names:c,snap:n,width:g},void 0,!1,void 0,this),Z("box",{height:1,flexShrink:0},void 0,!1,void 0,this),Z("text",{fg:t.muted,wrapMode:"none",children:oe("CPU is % of one core. RAM is what that process is holding now.",g)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Z(bi,{palette:t,title:"Log lines",tone:P>0?"warning":"muted",children:Z(Os,{palette:t,facts:C,width:g},void 0,!1,void 0,this)},void 0,!1,void 0,this),Z(bi,{palette:t,title:"Other parts",children:Z(Os,{palette:t,facts:B,width:g},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function DO(e){let{palette:t,names:r,snap:n,width:o}=e,i=fb(o),s=[{text:"service",width:i.name},{text:"status",width:Er}];if(i.health)s.push({text:"check",width:Hr});if(i.cpu)s.push({text:"cpu",width:xs});if(i.mem)s.push({text:"ram",width:bs});if(i.up)s.push({text:"up",width:vs});if(i.rst)s.push({text:"restarts",width:rl});if(i.pid)s.push({text:"pid",width:nn});return Z("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[Z(Is,{palette:t,header:!0,gap:$t,cells:s},void 0,!1,void 0,this),Z(vk,{palette:t,width:o},void 0,!1,void 0,this),r.map((a,c)=>Z($O,{palette:t,name:a,rt:n?.services[a],cols:i,stripe:c%2===1},a,!1,void 0,this))]},void 0,!0,void 0,this)}function IO(e){if(e===void 0)return"muted";if(e>OO)return"error";if(e>MO)return"warning";return"text"}function $O(e){let{palette:t,name:r,rt:n,cols:o,stripe:i}=e,s=bb(n),a=wb(n),c=n?.restarts??0,l=[{text:r,width:o.name,color:Ze(r,t)},{text:s,width:Er,color:et(t,n?.state??"STOPPED")}];if(o.health)l.push({text:a,width:Hr,color:et(t,n?.health??"UNKNOWN")});if(o.cpu)l.push({text:n?.cpuPercent!==void 0?ex(n.cpuPercent):"\u2014",width:xs,tone:IO(n?.cpuPercent)});if(o.mem)l.push({text:n?.memoryKB!==void 0?ys(n.memoryKB):"\u2014",width:bs,tone:"text"});if(o.up)l.push({text:db(n),width:vs,tone:"text"});if(o.rst)l.push({text:String(c),width:rl,tone:c>0?"warning":"muted"});if(o.pid)l.push({text:n?.pid?String(n.pid):"\u2014",width:nn,tone:"muted"});return Z("box",{flexDirection:"column",flexShrink:0,overflow:"hidden",children:[Z(Is,{palette:t,gap:$t,stripe:i,cells:l},void 0,!1,void 0,this),n?.last_error?Z("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:Z("text",{fg:t.error,wrapMode:"none",children:oe(` ${n.last_error}`,Math.max(24,o.name+$t+Er+Hr))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var EO=1000,TO=5,AO=16,LO=1000,MO=80,OO=100;var bk=D(()=>{zt();Ot();It();hr();At();nl();ke();tt()});import{useRenderer as FO,useTerminalDimensions as NO}from"@opentui/react";import{useCallback as Nn,useEffect as HO,useMemo as wk,useRef as Kr,useState as ze}from"react";import{jsxDEV as ge,Fragment as BO}from"@opentui/react/jsx-dev-runtime";function Sk({controller:e,tui:t,onQuit:r,onDown:n,onAttached:o,bootError:i,bootErrorMissing:s=!1,terminalBackground:a,workspace:c}){let{saveTuiPreferences:l,resolveTuiOverridePath:d,userTuiConfigPath:u,validateConfigText:f,freePort:p,readTextFile:m,writeTextFile:g,createStarterConfig:y,validate:x}=c,[h,P]=ze(e),[_,w]=ze(i),v=FO(),{width:b,height:S}=NO(),[k,L]=ze(h?"dashboard":"setup"),[I,F]=ze("none"),[Q,G]=ze(""),[C,B]=ze("commands"),[W,V]=ze(0),[de,Ee]=ze(0),[$e,ne]=ze(0),[H,ae]=ze([]),[X,nt]=ze(),[pt,ie]=ze(_??""),[Ae,De]=ze({}),[Ke,ht]=ze(),[Ye,Ct]=ze(ox(h?.cfg)),[he,yt]=ze(""),[st,vt]=ze(!1),[rr,Xe]=ze(),[Xt,qe]=ze(),[ft,vr]=ze(),Kt=Kr(null),xr=Kr(null),nr=Kr(null),qt=Kr(null),or=Kr(null),ir=Kr(null),sr=Kr(null),Vt=Kr(""),[ce,U]=ze("quit"),T=Kr(void 0),ye=Kr(0),[z,Lt]=ze(h?.cfg),at=h?.previousPersisted,[Ce,So]=ze(void 0),R=Yw({tui:t,controller:h,resolveTuiOverridePath:d,terminalBackground:a,userTuiConfigPath:u,snap:X,setStatus:ie,saveTuiPreferences:l,setPaletteIndex:V,setOverlay:F,setConfirmKind:U,setScreen:L,setSelected:ne,screen:k}),{themeName:ue,setThemeName:Vr,fontSize:Jr,prefsLocked:br,palette:se,rootBackground:Hn,settingRows:Bn,persistPrefs:Lr,persistTheme:cn,activateSetting:$s}=R,wi=Nw({controller:h,workspace:c,cfg:z,snap:X,screen:k,configReloadError:Ce,setSnap:nt,setStatus:ie}),{google:Si,doctor:le,doctorLoading:xt,doctorError:Rt,doctorProgress:zr,setDoctorTick:Fs}=wi,ko=t.keybinds.copy??Xr(),wr=wk(()=>Object.keys(z?.services??{}).sort(),[z]),ln=Nn(async()=>{if(!h)return;try{let Y=await h.status();if(nt(Y),Y.profile&&Ye==="")Ct(Y.profile);return Y}catch(Y){ie(A(Y));return}},[h,Ye]),Dl=Uw({controller:h,tui:t,names:wr,screen:k,refresh:ln,setStatus:ie}),{logs:Of,setLogs:Vk,paused:If,errorOnly:Ml,setErrorOnly:Ol,showSystemLogs:$f,logSearch:Ff,setLogSearch:Nf,logSearchFocused:Jk,setLogSearchFocused:zk,logFollow:Hf,logSince:Yk,logService:Bf,setLogService:Il,logServiceB:Xk,setLogServiceB:Qk,splitLogs:$l,splitFocus:Fl,setSplitFocus:Zk,logSliceB:Wf,logWindowB:jf,logSelectedB:Gf,logPinnedB:eC,pinLogViewB:tC,logServices:rC,logShowTimestamps:nC,logShowMeta:oC,logSource:iC,logRegex:Uf,logWrap:Kf,logPinned:qf,logSelected:Vf,logsFullscreen:Nl,dashboardLogCursor:sC,setDashboardLogCursor:aC,logFacets:Jf,logSources:zf,filteredLogs:Yf,filteredLogsB:cC,logWindow:Ns,logSlice:Hs,pinLogView:Hl,applyLogCursorA:lC,applyLogCursorB:dC,jumpToLatestLogs:Xf}=Dl,Co=wk(()=>{if(C==="tasks")return Ep(Object.keys(z?.tasks??{}),Q,"tasks","run this task");if(C==="services")return Ep(Object.keys(z?.services??{}),Q,"services","exec in this service");return ob(Q,{services:Object.keys(z?.services??{}),tasks:Object.keys(z?.tasks??{})})},[z,Q,C]);HO(()=>{Ee(0)},[Q]);let Bl=Tx(k,{doctor:le?.checks.length??0,settings:Bn.length,profiles:Object.keys(z?.profiles??{}).length,services:wr.length,logs:$l&&Fl===1?Wf.length:Hs.length,mcp:Gb(),config:Object.keys(z?.tasks??{}).length}),Qf=k==="logs"?$l&&Fl===1?Gf:Vf:$e,Dr=Bl<=0?Math.max(0,Qf):Math.max(0,Math.min(Qf,Bl-1)),uC=k==="detail"?he:k==="services"?wr[Dr]??"":"",{inspectorEnv:Zf,inspectorEnvStatus:em,inspectorEnvError:tm,resolveEnvironment:pC}=nS({controller:h,cfg:z,envService:uC}),Ro=Nn(()=>{if(F("none"),G(""),B("commands"),zk(!1),T.current)clearTimeout(T.current)},[]),Wl=Nn((Y)=>{ae((bt)=>bt.includes(Y)?bt.filter((_C)=>_C!==Y):[...bt,Y])},[]),rm=Vw({tui:t,controller:h,cfg:z,persistPrefs:Lr,snap:X,refresh:ln,setStatus:ie}),{mcpPortDraft:fC,mcpPort:mC,toggleMcpTool:gC,toggleMcp:hC,copyMcpSnippet:yC}=rm;Ow({controller:h,cfg:z,paused:If,logSince:Yk,refresh:ln,setLogs:Vk,setCfg:Lt,setConfigReloadError:So,setStatus:ie});let Bs=Nn((Y)=>{yt(Y),L("detail")},[]),nm=Nn((Y)=>{let bt=Y.value!==""?Y.value:Y.required?"(required, not set)":"(empty)";vr({title:Y.key,body:bt}),F("scroll-text")},[]),jl=Bw({controller:h,workspace:c,cfg:z,snap:X,refresh:ln,setStatus:ie,setOverlay:F}),{plan:Ws,planInitiallyRunning:vC,planBusy:xC,lifecycle:om}=jl,Yr=eS({workspace:c,renderer:v,setOverlay:F,setStatus:ie,setScreen:L,onAttached:o,setController:P,setCfg:Lt,setBootError:w}),{configEditRef:bC,configEditText:wC,configEditError:SC,setConfigEditError:kC,openConfigBuffer:im,saveConfigBuffer:CC}=Dw({cfg:z,readTextFile:m,setOverlay:F,setStatus:ie,validateConfigText:f,writeTextFile:g,controller:h,setConfirmKind:U,refresh:ln}),sm=Nn(async()=>{let Y=v.getSelection()?.getSelectedText()??"";if(Y.trim()===""){ie("Nothing selected \u2014 drag to highlight text");return}try{await al(Y);let bt=Y.split(`
|
|
618
|
+
`).length;ie(bt===1?"Copied selection":`Copied ${bt} selected lines`)}catch(bt){ie(A(bt))}},[v]),{runCommand:js}=Ew({setOverlay:F,setQuery:G,setSlashPicker:B,checked:H,setConfirmKind:U,setStatus:ie,persistTheme:cn,setPaletteIndex:V,themeName:ue,setScreen:L,setSelected:ne,screen:k,renderer:v,cfg:z,setScrollText:vr,reveal:st,controller:h,refresh:ln,profile:Ye,setReveal:vt,resolveEnvironment:pC,openDetail:Bs,copySelection:sm,lastExportPath:Vt,openConfigBuffer:im,onDown:n??((Y)=>r(Y)),workspace:c,logView:Dl,diagnostics:wi,lifecycleActions:jl}),am=Nn(()=>{let Y=ci(Co,de);if(C==="tasks"){if(!Y){ie(Co.length===0?"no tasks configured":"pick a task");return}B("commands");let bt=Br("run");if(bt)js(bt,[Y.name]);return}if(C==="services"){if(!Y){ie(Co.length===0?"no services configured":"pick a service");return}B("commands"),G(`exec ${Y.name} -- `);return}if(!Y){ie(Q.trim()===""?"pick a command from the list":`unknown command /${Q}`),Ro();return}js(Y,nb(Y,Q))},[Ro,Co,Q,js,de,C]),cm=Nn((Y)=>{cn(Y),Ro()},[Ro,cn]);lw({tui:t,controller:h,cfg:z,snap:X,ui:{screen:k,overlay:I,onQuit:r,onDown:n??((Y)=>r(Y)),closeOverlay:Ro,confirmKind:ce,confirmDetail:Ae,portTarget:Ke,profile:Ye,listCursor:Dr,names:wr,listCount:Bl,openDetail:Bs,copySelection:sm,height:S,paletteIndex:W,applyTheme:cm,runCommand:js,saveConfigBuffer:CC,filtered:Co,slashIndex:de,submitSlash:am,advanceWizard:()=>void Yr.advanceWizard(),bootErrorMissing:s,bootError:_,createStarterConfig:y,startWizard:Yr.startWizard,toggleChecked:Wl,checked:H,detailName:he,refresh:ln,openConfigBuffer:im,setOverlay:F,setConfirmKind:U,setConfirmDetail:De,setPortTarget:ht,setLogDetail:Xe,logDetail:rr,setLogSearch:Nf,setProfile:Ct,setStatus:ie,setPaletteIndex:V,setSlashIndex:Ee,setQuery:G,setSlashPicker:B,setScreen:L,setSelected:ne,setChecked:ae,setConfigEditError:kC,freePort:p},logView:Dl,lifecycleActions:jl,mcp:rm,preferences:R,diagnostics:wi,refs:{interruptArmedAt:ye,leaderTimer:T,logDetailsScrollRef:qt,scrollTextScrollRef:ir,routeDetailsScrollRef:or,planScrollRef:sr,helpScrollRef:xr,configScrollRef:Kt,detailScrollRef:nr}});let lm=Fx(ce,Ye,Ae),RC=new Set(Ws?.waves.flat()??[]),PC=Ws===void 0||om==="stop"?"":Object.entries(X?.services??{}).find(([Y,bt])=>RC.has(Y)&&bt.state==="FAILED")?.[0]??"";return ge(lp.Provider,{value:ms(Jr),children:ge("box",{flexDirection:"column",width:b,height:S,backgroundColor:Hn,overflow:"hidden",children:[Nl?null:ge(BO,{children:[ge(Pb,{palette:se,cfg:z,snap:X,google:Si,profile:Ye,reveal:st,width:b},void 0,!1,void 0,this),ge(_b,{palette:se,screen:k,width:b,onSelect:L},void 0,!1,void 0,this),Ce?ge("box",{height:1,paddingLeft:1,backgroundColor:se.panel,overflow:"hidden",children:ge("text",{fg:se.error,wrapMode:"none",children:`\u26A0 configuration reload failed: ${Ce}`},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),ge("box",{flexGrow:1,overflow:"hidden",children:[k==="dashboard"?ge(GS,{palette:se,cfg:z,snap:X,logs:Of,names:wr,selected:Dr,checked:H,width:b,followTick:Hf,logService:Bf,errorOnly:Ml,showSystemLogs:$f,onOpen:Bs,onSelectIndex:ne,selectedLog:sC,onToggle:Wl,logSources:zf,onFilterService:Il,onToggleErrors:()=>Ol((Y)=>!Y),onShowErrors:()=>{Il(""),Ol(!0)},wrapMode:Kf,view:Hs,follow:!qf,onLeaveLatest:Hl,onPickLog:(Y)=>{let bt=Hs[Y];if(!bt)return;aC(Y),Xe(bt),Hl()},viewStart:Ns.start,viewTotal:Yf.length,newer:Ns.newer,onJumpLatest:Xf,facets:Jf,leftover:at,search:Ff,regex:Uf},void 0,!1,void 0,this):null,k==="services"?ge(lk,{palette:se,cfg:z,names:wr,snap:X,selected:Dr,checked:H,width:b,reveal:st,onOpen:Bs,onSelectIndex:ne,onToggle:Wl,resolvedEnv:Zf,envStatus:em,envError:tm,onSelectEnv:nm},void 0,!1,void 0,this):null,k==="detail"?ge(ck,{palette:se,cfg:z,snap:X,name:he,reveal:st,width:b,envScrollRef:nr,resolvedEnv:Zf,envStatus:em,envError:tm,onSelectEnv:nm},void 0,!1,void 0,this):null,k==="logs"?ge(JS,{palette:se,logs:Of,names:wr,logSources:zf,service:Bf,errorOnly:Ml,showSystemLogs:$f,search:Ff,searchFocused:Jk,followTick:Hf,width:b,onSearch:Nf,onService:Il,onToggleErrors:()=>Ol((Y)=>!Y),source:iC,regex:Uf,services:rC,showTimestamps:nC,showMeta:oC,view:Hs,wrapMode:Kf,selected:Vf,follow:!qf,newer:Ns.newer,viewStart:Ns.start,viewTotal:Yf.length,onSelect:lC,fullscreen:Nl,onLeaveLatest:Hl,onJumpLatest:Xf,facets:Jf,split:$l,splitFocus:Fl,serviceB:Xk,viewB:Wf,selectedB:Gf,followB:!eC,newerB:jf.newer,viewStartB:jf.start,viewTotalB:cC.length,onServiceB:Qk,onSelectB:dC,onLeaveLatestB:tC,onFocusPane:Zk},void 0,!1,void 0,this):null,k==="auth"?ge(ES,{palette:se,cfg:z,google:Si,identity:X?.identity},void 0,!1,void 0,this):null,k==="credentials"?ge(IS,{palette:se,credentials:X?.credentials},void 0,!1,void 0,this):null,k==="proxy"?ge(ok,{palette:se,cfg:z,snap:X,width:b,onSelectRoute:(Y)=>{qe(Y),F("route-details")}},void 0,!1,void 0,this):null,k==="mcp"?ge(Ub,{palette:se,snap:X,port:mC,portDraft:fC,selected:Dr,onPick:ne,onToggle:()=>{hC()},onCopy:yC,onToggleTool:(Y)=>{gC(Y)}},void 0,!1,void 0,this):null,k==="doctor"?ge(KS,{palette:se,report:le,loading:xt,progress:zr,error:Rt,selected:Dr,onPick:ne,onReload:()=>{Fs((Y)=>Y+1),ie("Re-running doctor")}},void 0,!1,void 0,this):null,k==="stats"?ge(xk,{palette:se,cfg:z,snap:X,width:b,onRefresh:ln},void 0,!1,void 0,this):null,k==="config"?ge(MS,{palette:se,cfg:z,width:b,selectedTask:Dr,scrollRef:Kt},void 0,!1,void 0,this):null,k==="profiles"?ge(XS,{palette:se,cfg:z,snap:X,profile:Ye,selected:Dr,onPick:ne},void 0,!1,void 0,this):null,k==="setup"?ge(hk,{issues:z?x(z):["configuration not loaded"],palette:se,cfg:z,google:Si,bootError:_,bootErrorMissing:s,step:Dr},void 0,!1,void 0,this):null,k==="settings"?ge(mk,{palette:se,items:Bn,selected:Dr,locked:br,width:b,onPick:ne,onActivate:$s},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),I==="slash"?ge(wS,{palette:se,items:Co,query:Q,selected:de,title:C==="tasks"?"tasks":C==="services"?"services":"commands",onQuery:G,onSubmit:am},void 0,!1,void 0,this):null,I==="themes"?ge(PS,{palette:se,themeName:ue,selected:W%St.length,termW:b,termH:S,onIndex:V,onPreview:Vr,onPick:cm},void 0,!1,void 0,this):null,I==="help"?ge(Jb,{palette:se,termW:b,termH:S,copyKey:ko,scrollRef:xr},void 0,!1,void 0,this):null,I==="leader"?ge(dS,{palette:se,termW:b,termH:S},void 0,!1,void 0,this):null,I==="confirm"?ge(aS,{palette:se,title:lm.title,body:lm.body,kind:ce,termW:b,termH:S},void 0,!1,void 0,this):null,I==="setup-wizard"?ge(Qw,{palette:se,termW:b,termH:S,step:Yr.step,answers:Yr.answers,repo:Yr.repo,draft:Yr.draft,authStatus:Yr.authStatus,onDraft:Yr.setDraft,onSubmit:()=>void Yr.advanceWizard()},void 0,!1,void 0,this):null,I==="log-details"?ge(pS,{palette:se,event:rr,termW:b,termH:S,scrollRef:qt},void 0,!1,void 0,this):null,I==="route-details"?ge(yS,{palette:se,route:Xt,termW:b,termH:S,scrollRef:or},void 0,!1,void 0,this):null,I==="scroll-text"&&ft?ge(xS,{palette:se,title:ft.title,body:ft.body,termW:b,termH:S,scrollRef:ir},void 0,!1,void 0,this):null,I==="config-edit"&&z?ge(iS,{palette:se,path:z.configPath,initialValue:wC,error:SC,termW:b,termH:S,textareaRef:bC},void 0,!1,void 0,this):null,I==="plan"&&Ws?ge(gS,{palette:se,plan:Ws,snap:X,busy:xC,failed:PC,kind:om,termW:b,termH:S,scrollRef:sr,initiallyRunning:vC,onDismiss:Ro},void 0,!1,void 0,this):null,Nl?null:ge(Eb,{palette:se,screen:k,overlay:I,status:pt,paused:If,errorOnly:Ml,width:b,copyKey:ko},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var kk=D(()=>{te();zt();$p();Ot();yr();vo();Ln();At();dw();Tw();Mw();Iw();Hw();Ww();Kw();Jw();Xw();tS();oS();sS();cS();rf();uS();fS();hS();vS();bS();lf();SS();_S();TS();OS();$S();US();qS();zS();Ts();QS();ik();Pf();dk();gk();yk();bk();_r();tt();Pr()});var Ck={};LC(Ck,{renderApp:()=>Af,runTui:()=>Tf,runTuiWithController:()=>GO});import{createCliRenderer as WO}from"@opentui/core";import{createRoot as jO}from"@opentui/react";import{jsxDEV as UO}from"@opentui/react/jsx-dev-runtime";async function GO(e,t){let r=e.loadTuiConfig(t.cfg.repoRoot,t.cfg.ui.keymap);await Af(e,t,r)}async function Tf(e,t){let r,n,o=!1;try{r=await e.openTui("",t)}catch(s){n=A(s),o=ua(s,Kn)}let i=e.loadTuiConfig(r?.cfg.repoRoot??process.cwd(),r?.cfg.ui.keymap);await Af(e,r,i,n,o)}async function Af(e,t,r=e.loadTuiConfig(t?.cfg.repoRoot??process.cwd(),t?.cfg.ui.keymap),n,o=!1){Gs();let i=pm(),s=await WO({exitOnCtrlC:!1,useMouse:r.mouse,enableMouseMovement:r.mouse,useKittyKeyboard:{}}),a=jO(s),c=null;try{c=(await s.getPalette({timeout:120,size:16})).defaultBackground}catch{}await new Promise((l)=>{let d=(f)=>{let p=()=>{a.unmount(),i(),s.destroy(),l(),process.exit(0)};if(!t){p();return}t.close({detach:f,shutdownSupervisor:!0}).finally(p)},u=(f)=>{let p=()=>{a.unmount(),i(),s.destroy(),l(),process.exit(0)};if(!t){p();return}t.shutdown({stopServices:!f}).then(()=>t?.close({detach:!0})).finally(p)};a.render(UO(Sk,{workspace:Hv(e),controller:t,tui:r,onQuit:d,onDown:u,onAttached:(f)=>{t=f},bootError:n,bootErrorMissing:o,terminalBackground:c},void 0,!1,void 0,this))})}var Lf=D(()=>{Bv();te();kk()});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 Qs,readFileSync as zs}from"fs";import{dirname as aR,isAbsolute as wm,join as Xs,resolve as cR}from"path";Us();Us();import{spawnSync as HC}from"child_process";import{randomBytes as ql}from"crypto";import{copyFileSync as BC,existsSync as dn,mkdirSync as WC,readdirSync as jC,readFileSync as Vl,renameSync as Jl,statSync as GC,unlinkSync as Ul,writeFileSync as UC}from"fs";import{homedir as KC}from"os";import{basename as qC,dirname as Kl,join as Dt}from"path";var VC=448,JC=384;function cr(){let e=process.env.DEVCTL_HOME;if(e&&e!=="")return e;return Dt(KC(),".devctl")}function Mr(e){WC(e,{recursive:!0,mode:VC})}function Po(e){let t=Dt(cr(),"state",ar(e)),r=Dt(cr(),"sessions",ar(e));if(!dn(t)&&dn(r)){Mr(Kl(t));try{Jl(r,t)}catch{Mr(t);for(let n of["state.json","devctl.lock","devctl.sock"]){let o=Dt(r,n);if(dn(o))BC(o,Dt(t,n))}}}return Mr(t),t}function Ks(){let e=Dt(cr(),"logs");return Mr(e),e}function qs(){let e=Dt(cr(),"exports");return Mr(e),e}function Sr(){let e=Dt(cr(),"credentials");return Mr(e),e}function Vs(e,t=process.platform){if(t==="win32")return`\\\\.\\pipe\\devctl-${ar(e)}`;return Dt(Po(e),"devctl.sock")}function zC(e){return Dt(Po(e),"devctl.lock")}function fm(e){return Dt(Po(e),"state.json")}function ki(e){return Dt(Po(e),"bootstrap.log")}var YC=5,mm="bootstrap-";function gm(e){let t=ki(e);if(!dn(t))return;let r=Po(e),n=Dt(r,`${mm}${zl()}.log`);try{Jl(t,n)}catch{return}XC(r)}function XC(e){let t;try{t=jC(e).filter((n)=>n.startsWith(mm)&&n.endsWith(".log"))}catch{return}let r=t.map((n)=>{let o=Dt(e,n);try{return{path:o,mtime:GC(o).mtimeMs}}catch{return}}).filter((n)=>n!==void 0).sort((n,o)=>o.mtime-n.mtime);for(let n=YC;n<r.length;n++)try{Ul(r[n].path)}catch{}}function kr(e,t){Mr(Kl(e));let r=Dt(Kl(e),`.${qC(e)}.tmp-${process.pid}-${ql(4).toString("hex")}`);UC(r,t,{mode:JC}),Jl(r,e)}function zl(e=new Date){return`${e.toISOString().slice(0,19).replace(/:/g,"-")+"Z"}-${ql(3).toString("hex")}`}function un(e){return Yl(fm(e))}function Yl(e){if(!dn(e))return;try{let t=JSON.parse(Vl(e,"utf8"));if(Array.isArray(t.processes)&&typeof t.repo_root==="string")return t;return}catch{return}}function hm(e,t){kr(fm(e),`${JSON.stringify(t,null,2)}
|
|
619
|
+
`)}function ym(e,t){let r=zC(e);if(dn(r)){let n=QC(r);if(n&&Qt(n.pid))throw Error(`supervisor already running (pid ${n.pid})`);try{Ul(r)}catch{}}return kr(r,JSON.stringify({pid:process.pid,socket:t})),{release:()=>{try{Ul(r)}catch{}}}}function QC(e){if(!dn(e))return;try{let t=JSON.parse(Vl(e,"utf8"));if(typeof t.pid==="number"&&typeof t.socket==="string")return{pid:t.pid,socket:t.socket}}catch{return}return}function Qt(e){if(e<=0)return!1;if(process.platform==="win32")return ZC(e);try{return process.kill(e,0),!0}catch{return!1}}function Xl(e){try{let t=HC("cmd.exe",["/d","/c",`tasklist /FO CSV /NH /FI "PID eq ${e}"`],{encoding:"buffer",windowsHide:!0,timeout:5000});return eR(t.stdout)}catch{return""}}function ZC(e){try{return process.kill(e,0),!0}catch{}let t=Xl(e).toLowerCase();if(t===""||t.includes("no tasks")||t.includes("no matching"))return!1;return t.includes(String(e))}function eR(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 Ql(){return ql(24).toString("hex")}function tR(e){return Dt(Po(e),"mcp-token")}function vm(e){let t=tR(e);if(dn(t)){let n=Vl(t,"utf8").trim();if(n!=="")return n}let r=Ql();return kr(t,r),r}Js();Js();var lR="OPENCODE_TUI_CONFIG";function Zs(){return Xs(cr(),"tui.json")}function ea(e=""){for(let t of[xm,lR]){let r=process.env[t];if(!r||r==="")continue;let n=wm(r)?r:cR(e||process.cwd(),r);if(Qs(n))return n}return}function dR(e,t){if(!t||Object.keys(t).length===0)return e;return{...e,keybinds:{...e.keybinds,...t}}}function To(e,t){let r=dR(bm(),t),n=ea(e);if(n)return td(r,Ys(zs(n,"utf8")),n);let o=uR(e),i=o?td(r,Ys(zs(o,"utf8")),o):r,s=Zs();if(!Qs(s)||o===s)return i;return td(i,Ys(zs(s,"utf8")),s)}function Sm(e){let t=Zs(),r={};if(Qs(t)){let o=Ys(zs(t,"utf8"));if(Wn(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 kr(t,`${JSON.stringify(n,null,2)}
|
|
620
|
+
`),t}function uR(e){let t=ea(e);if(t)return t;let r=[e||process.cwd(),Xs(e||process.cwd(),".devctl"),cr()],n=["tui.json","tui.jsonc"];for(let o of r)for(let i of n){let s=Xs(o,i);if(Qs(s))return s}return}function td(e,t,r){let n=Wn(t)?t:{},o={...e.keybinds};if(Wn(n.keybinds)){for(let[c,l]of Object.entries(n.keybinds))if(typeof l==="string")o[c]=l}let i={...e.cursor};if(Wn(n.cursor)){if(fR(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(Wn(n.scroll_acceleration)&&typeof n.scroll_acceleration.enabled==="boolean")s.enabled=n.scroll_acceleration.enabled;let a={...e.attention,sounds:{...e.attention.sounds}};if(Wn(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(Wn(n.attention.sounds)){for(let[c,l]of Object.entries(n.attention.sounds))if(typeof l==="string")a.sounds[c]=pR(l,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((c)=>typeof c==="string"):e.mcp_disabled_tools,path:r}}function pR(e,t){if(e.startsWith("file://")||wm(e))return e;return Xs(aR(t),e)}function fR(e){return e==="block"||e==="underline"||e==="line"||e==="default"}function Wn(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Ys(e){let t=e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/^\s*\/\/.*$/gm,"");return JSON.parse(t)}import{existsSync as c0,readFileSync as l0,writeFileSync as d0}from"fs";import{spawn as gd}from"child_process";import{createWriteStream as jR,existsSync as Li,mkdirSync as GR,readdirSync as vd,readFileSync as UR,rmSync as KR,statSync as yd,writeFileSync as qR}from"fs";import{homedir as VR}from"os";import{dirname as Km,isAbsolute as JR,join as Un,resolve as zR}from"path";la();la();var YR=50000,xd="session-";function Um(e){return Buffer.from(JSON.stringify(e),"utf8").toString("base64url")}function XR(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 hd(e,t){let r={...e};return r[t]=void 0,r}class bd{events=[];eventStart=0;nextSeq=1;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:YR,this.bus=t,this.detector=r,this.sessionID=i;let c=o===""||o.startsWith("~/")?Ks():o;if(this.persist=n&&i!=="",this.persistDir=this.persist?Un(c,`${xd}${i}`):"",this.persist)GR(this.persistDir,{recursive:!0,mode:448}),eP(c,s,a)}sessionDir(){return this.persistDir}setParsers(e){this.parsers=e}append(e){let t=ld(e.message),r=this.parseLine(t),n=(c)=>this.detector?this.detector.redactText(c):c,o=r.raw!==void 0,i=n(t),s=r.message!==void 0?n(ld(r.message)):void 0,a={...e,timestamp:e.timestamp||new Date().toISOString(),level:e.level||r.level||ud(t),request_id:e.request_id||r.request_id||pd(t),message:o&&s!==void 0?s:i,raw:o?i:void 0,seq:this.nextSeq++};if(this.events.length<this.max)this.events.push(a);else this.events[this.eventStart]=a,this.eventStart=(this.eventStart+1)%this.max;if(this.bus?.publish(Se(Ao,a.service,{event:a,level:a.level})),this.persist){let c=`${a.timestamp} ${a.service} ${a.level} ${a.raw??a.message}
|
|
621
|
+
`,l=ZR(a.service),d=this.streamFor(l);this.lastWrite.set(l,new Promise((u)=>{d.write(c,()=>u())}))}return a}async flush(){await Promise.all([...this.lastWrite.values()])}parseLine(e){let t={};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=jR(Un(this.persistDir,`${e}.log`),{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=md(e),r=[];return this.forEachEvent((n)=>{if(t(n))r.push(n)}),r}queryPage(e,t={}){let r=jm(t.limit),n=t.cursor?XR(t.cursor):void 0,o=n!==void 0&&n.session!==this.sessionID,i=o?void 0:n,s=i?t.direction??"backward":"backward",a=md(e),c=[];this.forEachEvent((m)=>{if(a(m))c.push(m)});let l;if(!i)l=c.slice(Math.max(0,c.length-r));else if(s==="forward")l=c.filter((m)=>m.seq>i.seq).slice(0,r);else{let m=c.filter((g)=>g.seq<i.seq);l=m.slice(Math.max(0,m.length-r))}let d=l[0]?.seq,u=l[l.length-1]?.seq,f=d!==void 0&&c.some((m)=>m.seq<d),p=u!==void 0&&c.some((m)=>m.seq>u);return{events:l,prevCursor:Um({session:this.sessionID,seq:d??i?.seq??0}),nextCursor:Um({session:this.sessionID,seq:u??i?.seq??this.nextSeq-1}),hasNext:p,hasPrev:f,sessionChanged:o}}queryFacets(e){let t=hd(e,"services"),r=hd(e,"level"),n=hd(e,"source"),o=fd(e),i=0,s={},a={},c={};return this.forEachEvent((l)=>{if(!o(l))return;if(Oo(e,l))i+=1;if(Oo(t,l))s[l.service]=(s[l.service]??0)+1;if(Oo(r,l))a[l.level]=(a[l.level]??0)+1;if(Oo(n,l))c[l.source]=(c[l.source]??0)+1}),{total:i,byService:s,byLevel:a,bySource:c}}snapshot(){let e={},t=0;return this.forEachEvent((r)=>{if(e[r.service]=(e[r.service]??0)+1,r.level===Gn||r.level===Do)t+=1}),{total:this.events.length,errors:t,counts:e}}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){wd(e,this.query(t))}}function qm(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 QR(e=new Date){let t=e.toISOString().replace(/[:.]/g,"-");return Un(qs(),`devctl-logs-${t}.log`)}function Vm(e=""){if(e==="")return QR();let t=e.startsWith("~/")?Un(VR(),e.slice(2)):e;return JR(t)?t:zR(process.cwd(),t)}function wd(e,t){Mr(Km(e));let r=t.map((n)=>`${n.timestamp} ${n.service} ${n.level} ${n.raw??n.message}`);qR(e,`${r.join(`
|
|
622
|
+
`)}
|
|
623
|
+
`,{mode:384})}function Jm(e){let t=Li(e)&&yd(e).isDirectory()?e:Km(e);if(Mr(t),process.platform==="darwin"){let r=Li(e)&&yd(e).isFile()?["-R",e]:[t];gd("open",r,{detached:!0,stdio:"ignore"}).unref();return}if(process.platform==="win32"){gd("explorer",[t],{detached:!0,stdio:"ignore"}).unref();return}gd("xdg-open",[t],{detached:!0,stdio:"ignore"}).unref()}function zm(e=Ks()){if(!Li(e))return[];return vd(e).filter((t)=>t.startsWith(xd)).sort().reverse()}function Ym(e,t=Ks()){let r=Un(t,e);if(!Li(r))return[];let n=[];for(let i of vd(r)){if(!i.endsWith(".log"))continue;let s=UR(Un(r,i),"utf8");for(let a of s.split(`
|
|
624
|
+
`)){if(a.trim()==="")continue;let c=a.split(" "),l=c.slice(3).join(" "),d=dd(l);n.push({timestamp:c[0]??"",service:c[1]??i.replace(/\.log$/,""),source:"history",level:c[2]??"INFO",message:d?.message??l,raw:d?l:void 0,pid:0,seq:0})}}let o=n.sort((i,s)=>i.timestamp.localeCompare(s.timestamp));return o.forEach((i,s)=>{i.seq=s+1}),o}function ZR(e){let t=e.replace(/[^A-Za-z0-9._-]+/g,"_");return t===""?"service":t}function eP(e,t,r){if(!Li(e))return;let n=vd(e).filter((i)=>i.startsWith(xd)).map((i)=>{let s=Un(e,i),a=yd(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,c=r>0&&s>=r;if(a||c)KR(i.path,{recursive:!0,force:!0})})}te();var{spawn:Rd}=globalThis.Bun;import{createServer as ng}from"net";var tP=65535,Cd=1;async function og(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 c of s.ports){let l=r[i]?.[c.name],d=l&&l>=Cd?l:c.value;if(l===void 0&&c.auto)d=await rP();if(d<Cd||d>tP)throw new Qe(ee,`invalid port ${d} on service ${i}`,{service:i});if(n[d]&&n[d]!==i)throw new Qe(ee,`duplicate port ${d} used by ${n[d]} and ${i}`,{service:i});if(l!==d&&!c.auto&&!await Fo(d))throw await nP(i,c.name,d);n[d]=i,a[c.name]=d}o[i]=a}return o}function rP(){return new Promise((e,t)=>{let r=ng();r.listen(0,"127.0.0.1",()=>{let n=r.address();r.close(()=>{if(n&&typeof n==="object")e(n.port);else t(Re(ee,"unable to allocate dynamic port",Error("no address")))})}),r.on("error",(n)=>t(Re(ee,"unable to allocate dynamic port",n)))})}async function pa(e){let t=e.ports.filter((n)=>!n.auto&&n.value>=Cd);if(t.length===0)return;let r={};for(let n of t){if(await Fo(n.value))return;r[n.name]=n.value}return r}function Fo(e){return new Promise((t)=>{let r=ng();r.listen(e,"127.0.0.1",()=>{r.close(()=>t(!0))}),r.on("error",()=>t(!1))})}async function nP(e,t,r){let n=await Vn(r);return oP(e,t,r,n)}function oP(e,t,r,n){let o=t===""?`${e} port`:`${e} ports.${t}`;if(n&&n.pid===process.pid)return Ne(He,`${e} blocked: this TUI already holds port ${r}`,`Stop the proxy from the Proxy screen, or change ${o} in .devctl.`,e);if(n)return Ne(He,`${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 Ne(He,`${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 iP(e,t){let r=e.split(`
|
|
625
|
+
`).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 Vn(e){if(process.platform==="win32")return lP(e);let t=await sP(e);if(t)return t;return aP(e)}async function sP(e){try{let t=Rd({cmd:["lsof","-nP",`-iTCP:${e}`,"-sTCP:LISTEN"],stdout:"pipe",stderr:"ignore"}),r=await new Response(t.stdout).text();return await t.exited,iP(r,e)}catch{return}}async function aP(e){let t;try{let o=Rd({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 cP(e,t){for(let r of e.split(`
|
|
626
|
+
`)){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 lP(e){let t=Rd({cmd:["netstat","-ano"],stdout:"pipe",stderr:"ignore"}),r=t.stdout?await new Response(t.stdout).text():"";return await t.exited,cP(r,e)}var dP=400;async function fa(e){if(e.pid===process.pid)throw Ne(He,`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 Re(He,`could not stop pid ${e.pid} on port ${e.port}`,t)}await uP(dP);try{process.kill(e.pid,0),process.kill(e.pid,"SIGKILL")}catch{return}}function uP(e){return new Promise((t)=>{setTimeout(t,e)})}Pa();te();import{readdirSync as x_,readFileSync as b_}from"fs";import{basename as uh,dirname as w_,extname as S_,join as Qn,resolve as k_}from"path";import{parse as C_}from"yaml";mt();function N(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function $d(e){return N(e)?new Set(Object.keys(e)):new Set}function J(e){if(typeof e==="string")return e;if(typeof e==="number"||typeof e==="boolean")return String(e);return""}function Pe(e){if(typeof e==="number")return e;if(typeof e==="string"){let t=Number(e);return Number.isNaN(t)?0:t}return 0}function gt(e){return e===!0}function Pt(e){if(!Array.isArray(e))return[];return e.map((t)=>J(t))}function Fd(e){if(!Array.isArray(e))return[];return e.map((t)=>N(t)?{service:J(t.service),condition:J(t.condition)||"service_started"}:J(t))}function bn(e){if(!N(e))return{};let t={};for(let[r,n]of Object.entries(e))t[r]=J(n);return t}function Cr(e){if(typeof e==="string")return{args:e.split(/\s+/).filter((t)=>t!==""),shell:!1};if(Array.isArray(e))return{args:e.map((t)=>J(t)),shell:!1};return No()}function Nd(e){if(e===void 0||e===null)return[];if(typeof e==="string"||typeof e==="number")return[Id(e,"http")];if(Array.isArray(e))return e.map((t,r)=>Id(t,`port_${r}`));if(N(e))return Object.entries(e).map(([t,r])=>Id(r,t));return[]}function Id(e,t){if(typeof e==="string"&&e.toLowerCase()==="auto")return{name:t,value:0,auto:!0};return{name:t,value:Pe(e),auto:!1}}function gg(e){if(!N(e))return _d();let t={},r=[],n={};for(let[o,i]of Object.entries(e))if(o==="required")r=Pt(i);else if(o==="defaults")n=bn(i);else t[o]=J(i);return{vars:t,required:r,defaults:n}}function wP(e){if(!N(e))return Td();return{type:J(e.type),mode:J(e.mode),service_account:J(e.service_account),config:N(e.config)?{...e.config}:{}}}function SP(e){if(!N(e))return Ed();return{type:J(e.type),url:J(e.url),address:J(e.address),command:Cr(e.command),interval_seconds:Pe(e.interval_seconds),timeout_seconds:Pe(e.timeout_seconds),start_period_seconds:Pe(e.start_period_seconds),unhealthy_threshold:e.unhealthy_threshold===void 0?3:Pe(e.unhealthy_threshold),healthy_reset_threshold:e.healthy_reset_threshold===void 0?10:Pe(e.healthy_reset_threshold)}}function kP(e){if(!N(e))return{policy:"",max_retries:0,backoff_seconds:0};return{enabled:e.enabled===void 0?void 0:gt(e.enabled),policy:J(e.policy),max_retries:Pe(e.max_retries),backoff_seconds:Pe(e.backoff_seconds)}}function CP(e){if(!N(e))return{wait_for_healthy:!1,timeout_seconds:0};return{wait_for_healthy:gt(e.wait_for_healthy),timeout_seconds:Pe(e.timeout_seconds)}}function Ii(e){if(!N(e))return gn();let t=N(e.logs)?e.logs:{};return{extends:J(e.extends),description:J(e.description),command:Cr(e.command),shell:gt(e.shell),working_dir:J(e.working_dir),dependencies:Fd(e.dependencies),ports:Nd(e.ports),environment:gg(e.environment),health:SP(e.health),identity:wP(e.identity),logs:{stdout:gt(t.stdout),stderr:gt(t.stderr)},restart:kP(e.restart),startup:CP(e.startup),capabilities:Pt(e.capabilities),proxy:Bd(e.proxy),container:Hd(e.container),watch:RP(e.watch),hooks:PP(e.hooks)}}function RP(e){if(!N(e))return Pd();return{enabled:gt(e.enabled),paths:Pt(e.paths),debounce_ms:ya(Pe(e.debounce_ms)),ignore:e.ignore===void 0?[...Di]:Pt(e.ignore)}}function PP(e){let t=N(e)?e:{};return{pre_start:Cr(t.pre_start),post_start:Cr(t.post_start)}}function hg(e){let t=N(e)?e:{};return{command:Cr(t.command),shell:gt(t.shell),working_dir:J(t.working_dir),dependencies:Pt(t.dependencies),environment:gg(t.environment)}}function Hd(e){if(!N(e))return;let t={};if(N(e.ports))for(let[r,n]of Object.entries(e.ports))t[r]=Pe(n);return{image:J(e.image),runtime:J(e.runtime),ports:t,env:bn(e.env),volumes:Pt(e.volumes)}}function Bd(e){if(e===void 0||e===null)return[];if(Array.isArray(e))return e.map((t)=>zn(t));if(N(e))return[zn(e)];return[]}function _a(e){if(!N(e))return{services:[],environment:{}};return{services:Pt(e.services),environment:bn(e.environment)}}function _P(e){if(typeof e==="string")return{type:e,service_account:""};if(!N(e))return{type:"",service_account:""};return{type:J(e.type),service_account:J(e.service_account)}}function EP(e){if(!N(e))return{type:"",identity:{type:"",service_account:""},audience:"",service_account:""};return{type:J(e.type),identity:_P(e.identity),audience:J(e.audience),service_account:J(e.service_account)}}function zn(e){if(!N(e))return{name:"",match:{host:"",path:""},upstream:{url:""},auth:{type:"",identity:{type:"",service_account:""},audience:"",service_account:""}};let t=N(e.match)?e.match:{},r=N(e.upstream)?e.upstream:{};return{name:J(e.name),match:{host:J(t.host),path:J(t.path)},upstream:{url:J(r.url)},auth:EP(e.auth)}}te();import{existsSync as TP,statSync as vg}from"fs";import{basename as yg,dirname as Ea,isAbsolute as AP,join as Ta,resolve as xg}from"path";function Yn(e,t){if(t!=="")return LP(t);let r=e===""?process.cwd():e;r=AP(r)?r:xg(r);for(;;){let n=Ta(r,Nt,lr);if($i(n))return{repoRoot:r,configPath:n};let o=Ta(r,"devctl.yaml");if($i(o))return{repoRoot:r,configPath:o};let i=Ea(r);if(i===r)break;r=i}throw Ne(Kn,"no devctl configuration found","run `devctl setup` or create a .devctl/config.yaml in the repository root")}function LP(e){let t=xg(e),r;try{r=vg(t)}catch(o){throw Re(Kn,"config path not found",o)}if(r.isDirectory()){if(yg(t)===Nt)return{repoRoot:Ea(t),configPath:Ta(t,lr)};return{repoRoot:t,configPath:Ta(t,lr)}}let n=Ea(t);if(yg(n)===Nt)n=Ea(n);return{repoRoot:n,configPath:t}}function $i(e){return TP(e)&&!vg(e).isDirectory()}mt();function Da(){return{services:{},templates:{},provenance:{}}}function wn(e,t,r,n,o=""){if(N(t)&&Object.keys(t).length>0){for(let[i,s]of Object.entries(t))wn(e,s,r,n,o===""?i:`${o}.${i}`);return}if(o==="")return;(e[o]??=[]).push({source:r,layer:n})}var DP=["environment","restart","startup","health","logs","identity","container","watch","hooks"];function Aa(e,t,r){let n=$d(r);if(N(r))for(let i of DP){let s=r[i];if(N(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 bg(e,t,r=Da(),n={source:"unknown",layer:"unknown"}){if(wn(r.provenance,t,n.source,n.layer),t.version!==void 0)e.version=Pe(t.version);if(N(t.project)&&t.project.name!==void 0)e.project.name=J(t.project.name);if(N(t.google)){if(t.google.project_id!==void 0)e.google.project_id=J(t.google.project_id);if(t.google.region!==void 0)e.google.region=J(t.google.region)}if(N(t.profiles))for(let[o,i]of Object.entries(t.profiles)){let s=e.profiles[o];e.profiles[o]=s?OP(s,i):_a(i)}if(N(t.templates))for(let[o,i]of Object.entries(t.templates)){let s=e.templates[o];e.templates[o]=s?La(s,i):Ii(i),Aa(r.templates,o,i)}if(N(t.services))for(let[o,i]of Object.entries(t.services)){let s=e.services[o];e.services[o]=s?La(s,i):Ii(i),Aa(r.services,o,i)}if(N(t.tasks))for(let[o,i]of Object.entries(t.tasks))e.tasks[o]=e.tasks[o]?IP(e.tasks[o],i):hg(i);if(N(t.proxy))MP(e.proxy,t.proxy);if(N(t.logs)){if(t.logs.max_memory_events!==void 0)e.logs.max_memory_events=Pe(t.logs.max_memory_events);if(N(t.logs.persistence)){let o=t.logs.persistence;if(o.enabled!==void 0)e.logs.persistence.enabled=gt(o.enabled);if(o.directory!==void 0)e.logs.persistence.directory=J(o.directory);if(o.retention_days!==void 0)e.logs.persistence.retention_days=Pe(o.retention_days);if(o.max_session_logs!==void 0)e.logs.persistence.max_session_logs=Pe(o.max_session_logs)}}if(N(t.auth)&&t.auth.refresh_threshold_seconds!==void 0)e.auth.refresh_threshold_seconds=Pe(t.auth.refresh_threshold_seconds);if(N(t.shutdown)){if(t.shutdown.stop_services_on_exit!==void 0)e.shutdown.stop_services_on_exit=gt(t.shutdown.stop_services_on_exit);if(t.shutdown.grace_seconds!==void 0)e.shutdown.grace_seconds=Pe(t.shutdown.grace_seconds)}if(N(t.ui)){if(t.ui.theme!==void 0)e.ui.theme=J(t.ui.theme);if(t.ui.keymap!==void 0)e.ui.keymap=bn(t.ui.keymap)}if(N(t.secrets)){if(t.secrets.extra_markers!==void 0)e.secrets.extra_markers=Pt(t.secrets.extra_markers);if(t.secrets.extra_patterns!==void 0)e.secrets.extra_patterns=Pt(t.secrets.extra_patterns)}if(N(t.doctor)&&Array.isArray(t.doctor.tools))e.doctor.tools=t.doctor.tools.filter(N).map((o)=>({name:J(o.name),command:J(o.command)}));if(Array.isArray(t.plugins))e.plugins=t.plugins.filter(N).map((o)=>({path:J(o.path)})).filter((o)=>o.path!=="");if(N(t.environment)){if(Array.isArray(t.environment.sources))e.environment.sources=Pt(t.environment.sources);if(N(t.environment.secrets))e.environment.secrets={...e.environment.secrets,...bn(t.environment.secrets)}}}function MP(e,t){if(t.enabled!==void 0)e.enabled=gt(t.enabled);if(N(t.listen)){if(t.listen.host!==void 0)e.listen.host=J(t.listen.host);if(t.listen.port!==void 0)e.listen.port=Pe(t.listen.port)}if(N(t.token_endpoint)){let r=t.token_endpoint;if(r.enabled!==void 0)e.token_endpoint.enabled=gt(r.enabled);if(r.host!==void 0)e.token_endpoint.host=J(r.host);if(r.port!==void 0)e.token_endpoint.port=Pe(r.port)}if(Array.isArray(t.routes))e.routes=t.routes.map((r)=>zn(r))}function OP(e,t){if(!N(t))return e;return{services:t.services!==void 0?Pt(t.services):e.services,environment:t.environment!==void 0?{...e.environment,...bn(t.environment)}:e.environment}}function IP(e,t){if(!N(t))return e;return{command:t.command!==void 0?Cr(t.command):e.command,shell:t.shell!==void 0?gt(t.shell):e.shell,working_dir:t.working_dir!==void 0?J(t.working_dir):e.working_dir,dependencies:t.dependencies!==void 0?Pt(t.dependencies):e.dependencies,environment:wg(e.environment,t.environment)}}function La(e,t){if(!N(t))return e;let r=$d(t),n={...e,environment:wg(e.environment,t.environment),health:NP(e.health,t.health),identity:HP(e.identity,t.identity),logs:BP(e.logs,t.logs),restart:WP(e.restart,t.restart),startup:jP(e.startup,t.startup),container:GP(e.container,t.container),watch:$P(e.watch,t.watch),hooks:FP(e.hooks,t.hooks)};if(r.has("extends"))n.extends=J(t.extends);if(r.has("description"))n.description=J(t.description);if(r.has("command"))n.command=Cr(t.command);if(r.has("shell"))n.shell=gt(t.shell);if(r.has("working_dir"))n.working_dir=J(t.working_dir);if(r.has("dependencies"))n.dependencies=Fd(t.dependencies);if(r.has("ports"))n.ports=Nd(t.ports);if(r.has("capabilities"))n.capabilities=Pt(t.capabilities);if(r.has("proxy"))n.proxy=Bd(t.proxy);return n}function $P(e,t){if(!N(t))return e;return{enabled:t.enabled!==void 0?gt(t.enabled):e.enabled,paths:t.paths!==void 0?Pt(t.paths):e.paths,debounce_ms:t.debounce_ms!==void 0?ya(Pe(t.debounce_ms)):e.debounce_ms,ignore:t.ignore!==void 0?Pt(t.ignore):e.ignore}}function FP(e,t){if(!N(t))return e;return{pre_start:t.pre_start!==void 0?Cr(t.pre_start):e.pre_start,post_start:t.post_start!==void 0?Cr(t.post_start):e.post_start}}function wg(e,t){if(!N(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=Pt(s);else if(i==="defaults")Object.assign(n,bn(s));else r[i]=J(s);return{vars:r,required:o,defaults:n}}function NP(e,t){if(!N(t))return e;return{type:t.type!==void 0?J(t.type):e.type,url:t.url!==void 0?J(t.url):e.url,address:t.address!==void 0?J(t.address):e.address,command:t.command!==void 0?Cr(t.command):e.command,interval_seconds:t.interval_seconds!==void 0?Pe(t.interval_seconds):e.interval_seconds,timeout_seconds:t.timeout_seconds!==void 0?Pe(t.timeout_seconds):e.timeout_seconds,start_period_seconds:t.start_period_seconds!==void 0?Pe(t.start_period_seconds):e.start_period_seconds,unhealthy_threshold:t.unhealthy_threshold!==void 0?Pe(t.unhealthy_threshold):e.unhealthy_threshold,healthy_reset_threshold:t.healthy_reset_threshold!==void 0?Pe(t.healthy_reset_threshold):e.healthy_reset_threshold}}function HP(e,t){if(!N(t))return e;return{type:t.type!==void 0?J(t.type):e.type,mode:t.mode!==void 0?J(t.mode):e.mode,service_account:t.service_account!==void 0?J(t.service_account):e.service_account,config:t.config!==void 0&&N(t.config)?{...e.config??{},...t.config}:e.config}}function BP(e,t){if(!N(t))return e;return{stdout:t.stdout!==void 0?gt(t.stdout):e.stdout,stderr:t.stderr!==void 0?gt(t.stderr):e.stderr}}function WP(e,t){if(!N(t))return e;return{enabled:t.enabled!==void 0?gt(t.enabled):e.enabled,policy:t.policy!==void 0?J(t.policy):e.policy,max_retries:t.max_retries!==void 0?Pe(t.max_retries):e.max_retries,backoff_seconds:t.backoff_seconds!==void 0?Pe(t.backoff_seconds):e.backoff_seconds}}function jP(e,t){if(!N(t))return e;return{wait_for_healthy:t.wait_for_healthy!==void 0?gt(t.wait_for_healthy):e.wait_for_healthy,timeout_seconds:t.timeout_seconds!==void 0?Pe(t.timeout_seconds):e.timeout_seconds}}function GP(e,t){if(!N(t))return e;let r=Hd(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 Sg(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 c={name:o.length===1?n:`${n}-${s+1}`,match:i.match,upstream:i.upstream,auth:i.auth},l=e.proxy.routes.length;if(e.proxy.routes.push(c),t)wn(t,c,`synthesized from services.${n}.proxy`,"synthesized",`proxy.routes.${l}`)})}}function kg(e,t=Da()){if(Object.keys(e.templates).length===0)return;let r={};for(let[n,o]of Object.entries(e.services))r[n]=Cg(e,o,t.services[n]??new Set,t,{});e.services=r}function Cg(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]??gn();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,c=Cg(e,i,a,n,s),l=UP(c,t,r);return l.extends=t.extends,l}function UP(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}te();mt();function Rg(e){if(e.version===0)throw M(ee,"version is required");if(e.version===Ho)return e;throw M(ee,`unsupported config version ${e.version} (expected ${Ho}); no migration is available`)}var Pg=["version","project","google","profiles","templates","services","tasks","proxy","logs","auth","shutdown","ui","secrets","doctor","plugins","environment"],_g=["extends","description","command","shell","working_dir","dependencies","ports","environment","health","identity","logs","restart","startup","capabilities","proxy","container","watch","hooks"],Eg=["type","url","address","command","interval_seconds","timeout_seconds","start_period_seconds","unhealthy_threshold","healthy_reset_threshold"],Tg=["service","condition"],Ag=["type","mode","service_account","config"],Lg=["enabled","policy","max_retries","backoff_seconds"],Dg=["wait_for_healthy","timeout_seconds"],Mg=["enabled","listen","token_endpoint","routes"],Og=["host","port"],Wd=["name","match","upstream","auth"],jd=["host","path"],Gd=["url"],Ud=["type","identity","audience","service_account"],Ig=["max_memory_events","persistence"],$g=["enabled","directory","retention_days","max_session_logs"],Fg=["refresh_threshold_seconds"],Ng=["stop_services_on_exit","grace_seconds"],Hg=["theme","keymap"],Bg=["name"],Wg=["project_id","region"],jg=["services","environment"],Kd=["required","defaults"],Gg=["stdout","stderr"],Ug=["extra_markers","extra_patterns"],Kg=["tools"],qg=["name","command"],Vg=["enabled","host","port"],Jg=["path"],zg=["sources","secrets"],Yg=["image","runtime","ports","env","volumes"],Xg=["enabled","paths","debounce_ms","ignore"],Qg=["pre_start","post_start"],Zg=["command","shell","working_dir","dependencies","environment"],eh=["google","google_api","iap","network","service_identity","local_http"],th=["|","||","&&",";",">",">>","<","&"];var KP=2;function Sn(e,t){if(Array.isArray(e))return e.flatMap((o,i)=>Sn(o,rh(t,String(i))));if(!QP(e))return[];let r=VP(t),n=[];for(let o of Object.keys(e)){let i=rh(t,o);if(r.length>0&&!r.includes(o)&&!qP(t))n.push(i);n.push(...Sn(e[o],i))}return n}function qP(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(".identity.config")||e.includes(".identity.config."))return!0;return e.includes(".environment.")&&!e.endsWith(".environment")}function VP(e){switch(e){case"":return Pg;case"project":return Bg;case"google":return Wg;case"proxy":return Mg;case"proxy.listen":return Og;case"proxy.token_endpoint":return Vg;case"logs":return Ig;case"logs.persistence":return $g;case"auth":return Fg;case"shutdown":return Ng;case"ui":return Hg;case"secrets":return Ug;case"doctor":return Kg;case"environment":return zg;default:return JP(e)}}function JP(e){if(e==="services"||e==="profiles"||e==="templates"||e==="tasks")return[];if(e.startsWith("services.")||e.startsWith("templates.")){if(e.includes(".dependencies."))return Tg;return zP(e)}if(e.startsWith("profiles.")){if(e.split(".").length===2)return jg}if(e.startsWith("tasks.")){let t=e.split(".");if(t.length===2)return Zg;if(t[2]==="environment")return Kd}if(e.includes("routes"))return XP(e);if(e.startsWith("doctor.tools")&&e.split(".").length>=3)return qg;if(e==="plugins")return[];if(e.startsWith("plugins.")&&e.split(".").length===2)return Jg;return[]}function zP(e){let t=e.split(".");if(t.length===2)return _g;if(t.length>=3)switch(t[2]){case"health":return Eg;case"identity":return Ag;case"restart":return Lg;case"startup":return Dg;case"logs":return Gg;case"environment":return Kd;case"proxy":return YP(t);case"container":return Yg;case"watch":return Xg;case"hooks":return Qg;default:return[]}return[]}function YP(e){let t=e.slice(3),r=t[0]!==void 0&&/^\d+$/.test(t[0])?1:0,n=t[r]??"";if(n==="match")return jd;if(n==="upstream")return Gd;if(n==="auth")return Ud;return Wd}function XP(e){if(e==="proxy.routes")return[];if(e.endsWith(".match"))return jd;if(e.endsWith(".upstream"))return Gd;if(e.endsWith(".auth"))return Ud;if(e.includes("proxy.routes")&&e.split(".").length===KP+1)return Wd;return[]}function rh(e,t){if(e==="")return t;return`${e}.${t}`}function QP(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Bo(e){return`unknown fields: ${e.join(", ")}`}mt();function kn(e){let t=e.trim().toLowerCase();if(t==="")return!0;if(t==="localhost"||t==="::1")return!0;if(nh(t))return!0;return ZP(t)}function nh(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 ZP(e){if(!e.startsWith("::ffff:"))return!1;return nh(e.slice(7))}import{existsSync as r_}from"fs";import{isAbsolute as n_,resolve as o_}from"path";import{fileURLToPath as i_}from"url";mt();function e_(e,t,r){let n=e,o="";for(;;){let i=n.indexOf("${");if(i<0)return o+n;o+=n.slice(0,i);let s=n.slice(i).indexOf("}");if(s<0)throw Error(`unclosed environment reference in "${e}"`);let a=n.slice(i+2,i+s);o+=t_(a,t,r),n=n.slice(i+s+1)}}function t_(e,t,r){let n=e.split(".");if(n.length<3||n[0]!=="services")throw Error(`unsupported reference \${${e}}`);let o=n[1]??"",i=t.services[o];if(!i)throw Error(`reference \${${e}}: unknown service`);let s=r[o];if(n[2]==="port"){if(s){if(s.http!==void 0)return String(s.http);let c=Object.values(s)[0];if(c!==void 0)return String(c)}let a=ug(i.ports);if(a&&!a.auto)return String(a.value)}if(n[2]==="ports"){let a=n[3];if(!a)throw Error(`reference \${${e}}: missing port name`);if(s&&s[a]!==void 0)return String(s[a]);let c=Ad(i.ports,a);if(c&&!c.auto)return String(c.value);let l=Number.parseInt(a,10);if(!Number.isNaN(l)&&l>=0&&l<i.ports.length){let d=i.ports[l];if(d&&!d.auto)return String(d.value)}}throw Error(`unresolvable reference \${${e}}`)}function qd(e,t,r){let n={};for(let[o,i]of Object.entries(e))n[o]=e_(i,t,r);return n}function oh(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 ih(e,t){let r=e.split(".");if(r.length<2)return!1;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 Ad(n.ports,o)!==void 0}}return!0}mt();var Oa=65535,Ia=1,ch=["http","tcp","process","command"];function Vd(e){let t=[];for(let[r,n]of Object.entries(e.services)){let o=n.health.type;if(o!==""&&!ch.includes(o.toLowerCase()))t.push({service:r,type:o})}return t}var s_=0,sh=1,ah=2;function Xn(e){let t=[];if(e.version===0)t.push("version is required");else if(e.version!==Ho)t.push(`unsupported config version ${e.version} (expected ${Ho}); no migration is available`);if(Object.keys(e.services).length===0)t.push("at least one service must be defined");t.push(...c_(e)),t.push(...a_(e)),t.push(...p_(e)),t.push(...f_(e)),t.push(...m_(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:")?i_(n.path):n_(n.path)?n.path:o_(e.repoRoot,n.path);if(!r_(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 a_(e){let t=[];for(let[r,n]of Object.entries(e.tasks)){let o=`tasks.${r}`;if(hn(n.command))t.push(`${o}.command is required`);t.push(...Ma(o,n.command,n.shell));for(let i of n.dependencies)if(!e.services[i])t.push(`${o}.dependencies: unknown service "${i}"`);t.push(...lh(`${o}.environment`,n.environment,e))}return t}function c_(e){let t=[],r={};for(let[n,o]of Object.entries(e.services)){let i=`services.${n}`;if(hn(o.command)&&!o.container)t.push(`${i}.command is required`);t.push(...Ma(i,o.command,o.shell)),t.push(...Ma(`${i}.hooks.pre_start`,o.hooks.pre_start,o.shell)),t.push(...Ma(`${i}.hooks.post_start`,o.hooks.post_start,o.shell)),t.push(...h_(i,o.capabilities));for(let c of o.dependencies){let l=Jt(c);if(!e.services[l])t.push(`${i}.dependencies: unknown service "${l}"`);if(l===n)t.push(`${i}.dependencies: service cannot depend on itself`);if(!["service_started","service_healthy"].includes(mn(c)))t.push(`${i}.dependencies: condition must be service_started or service_healthy`);if(mn(c)==="service_healthy"&&e.services[l]?.health.type==="")t.push(`${i}.dependencies: service_healthy requires ${l} to define a health check`)}if(o.extends!==""&&!e.templates[o.extends])t.push(`${i}.extends: unknown template "${o.extends}"`);for(let c of o.ports.filter((l)=>!l.auto))if(c.value<Ia||c.value>Oa)t.push(`${i}.ports.${c.name}: invalid port ${c.value}`);else if(r[c.value])t.push(`duplicate port ${c.value} used by ${r[c.value]} and ${n}`);else r[c.value]=n;let s=u_(`${i}.identity`,o.identity,e.plugins.length>0);if(s!=="")t.push(s);if(t.push(...l_(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=ba(o.restart);if(a!==ma&&a!==ga&&a!==ha)t.push(`${i}.restart.policy must be never, on_failure, or always`);if(t.push(...lh(`${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[c,l]of Object.entries(o.container.ports)){if(!o.ports.some((d)=>d.name===c))t.push(`${i}.container.ports.${c}: no matching service port`);if(l<Ia||l>Oa)t.push(`${i}.container.ports.${c}: invalid container port ${l}`)}}}return t}function l_(e,t,r){let n=[];if(t.health.type==="")return n;let o=t.health.type.toLowerCase();if(!ch.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"&&hn({args:t.health.command.args,shell:!1}))n.push(`${e}.health.command is required for command health checks`);return n}var d_=["","user","service","service_account"];function u_(e,t,r){let n=Oi(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 Jd(e){let t=[];for(let[r,n]of Object.entries(e.services)){let o=Oi(n.identity).toLowerCase();if(!d_.includes(o))t.push({service:r,type:o})}return t}function p_(e){let t={},r=[],n=[],o=(i)=>{let s=t[i]??s_;if(s===ah)return;if(s===sh){r.push(`dependency cycle: ${[...n,i].join(" \u2192 ")}`);return}t[i]=sh,n.push(i);let a=e.services[i];if(a)for(let c of a.dependencies){let l=Jt(c);if(e.services[l])o(l)}n.pop(),t[i]=ah};for(let i of Object.keys(e.services))o(i);return r}function lh(e,t,r){let n=[],o=(i,s)=>{for(let a of oh(s))if(!ih(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 f_(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 m_(e){let t=[];if(e.proxy.listen.host!==""){if(!y_(e.proxy.listen.host))t.push("proxy.listen.host must be an IP address or localhost");else if(!kn(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<Ia||e.proxy.listen.port>Oa))t.push("proxy.listen.port is invalid");let r={};return e.proxy.routes.forEach((n,o)=>{let i=`proxy.routes[${o}]`;if(n.name==="")t.push(`${i}.name is required`);else if(r[n.name])t.push(`${i}: duplicate route name ${n.name}`);if(r[n.name]=!0,n.upstream.url==="")t.push(`${i}.upstream.url is required`);if(n.auth.type.toLowerCase()==="iap"){if(n.auth.audience.trim()==="")t.push(`${i}.auth.audience is required when auth.type is iap`);if(n.auth.identity.type.trim()==="")t.push(`${i}.auth.identity.type is required when auth.type is iap`)}let s=n.auth.identity.type.toLowerCase();if(s==="service"||s==="service_account"||Zr({type:s,mode:"",service_account:""})){if((n.auth.identity.service_account||n.auth.service_account)==="")t.push(`${i}.auth.identity.service_account is required`)}}),t.push(...g_(e)),t}function g_(e){let t=[],r=e.proxy.token_endpoint;if(!r.enabled)return t;let n=r.host||va;if(!kn(n))t.push("proxy.token_endpoint.host must be a loopback address");if(r.port!==0&&(r.port<Ia||r.port>Oa))t.push("proxy.token_endpoint.port is invalid");return t}function Ma(e,t,r){if(t.shell||r)return[];for(let n of t.args)if(th.includes(n)||n.includes("|")||n.includes(";")||n.includes("&&"))return[`${e}.command contains shell metacharacters; set shell: true to run via a shell`];return[]}function h_(e,t){let r=[];for(let n of t)if(!eh.includes(n))r.push(`${e}.capabilities: unknown capability "${n}"`);return r}function y_(e){if(e==="localhost")return!0;return v_(e)}function v_(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 Fi(e,t,r){try{return Ni(e,t,{candidateText:r}),[]}catch(n){if(n instanceof Qe){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 tn(e,t){let{repoRoot:r,configPath:n}=Yn(e,t);return Ni(r,n)}function Zn(e,t){try{return tn(e,t)}catch(r){if(!ua(r,Kn))throw r;let n=e===""?process.cwd():k_(e),o=Jn();return o.repoRoot=n,o.configPath=Qn(n,Nt,lr),o}}function Ni(e,t,r){let n=Jn(),o=Da();ph(t,n,o,r?.candidateText,"main"),n.repoRoot=e,n.configPath=t;let i=w_(t);if(uh(i)===Nt)P_(i,n,o);n=R_(n,e,t,o),n=Rg(n);try{kg(n,o)}catch(a){throw Re(ee,"template merge failed",a)}Sg(n,o.provenance),n.provenance=o.provenance;let s=Xn(n);if(s.length>0)throw M(ee,s.join(`
|
|
627
|
+
`));return n}function R_(e,t,r,n){let o=Qn(cr(),"config.local.yaml"),i=Qn(t,Nt,"config.local.yaml");for(let s of[o,i]){if(s===r||!$i(s))continue;ph(s,e,n,void 0,s===o?"home_local":"repo_local")}return e}function ph(e,t,r,n,o="main"){let i=n!==void 0?fh(n,e):zd(e),s=Sn(i,"");if(s.length>0)throw M(ee,Bo(s));bg(t,i,r,{source:e,layer:o})}function P_(e,t,r){dh(Qn(e,"services"),(o,i,s)=>{let a=Sn(i,`services.${o}`);if(a.length>0)throw M(ee,Bo(a));let c=t.services[o];t.services[o]=c?La(c,i):Ii(i),Aa(r.services,o,i),wn(r.provenance,i,s,"modular_service",`services.${o}`)}),dh(Qn(e,"profiles"),(o,i,s)=>{let a=Sn(i,`profiles.${o}`);if(a.length>0)throw M(ee,Bo(a));t.profiles[o]=_a(i),wn(r.provenance,i,s,"modular_profile",`profiles.${o}`)});let n=Qn(e,"proxy","routes.yaml");if($i(n))__(n,t,r)}function __(e,t,r){let n=zd(e);if(N(n.proxy))wn(r.provenance,n.proxy,e,"modular_proxy","proxy");if(Array.isArray(n.routes))wn(r.provenance,n.routes,e,"modular_proxy","proxy.routes");if(N(n.proxy)){let o=Sn({proxy:n.proxy},"");if(o.length>0)throw M(ee,Bo(o))}if(Array.isArray(n.routes))n.routes.forEach((o,i)=>{let s=Sn(o,`proxy.routes.${i}`);if(s.length>0)throw M(ee,Bo(s))});if(N(n.proxy)){if(Array.isArray(n.proxy.routes))t.proxy.routes.push(...n.proxy.routes.map((o)=>zn(o)));if(N(n.proxy.listen)){if(typeof n.proxy.listen.host==="string"&&n.proxy.listen.host!=="")t.proxy.listen.host=n.proxy.listen.host;if(typeof n.proxy.listen.port==="number"&&n.proxy.listen.port!==0)t.proxy.listen.port=n.proxy.listen.port}}if(Array.isArray(n.routes))t.proxy.routes.push(...n.routes.map((o)=>zn(o)))}function dh(e,t){let r;try{r=x_(e)}catch(n){if(E_(n))return;throw n}for(let n of r.sort()){let o=S_(n);if(o!==".yaml"&&o!==".yml")continue;let i=Qn(e,n),s=zd(i);t(uh(n,o),s,i)}}function zd(e){let t;try{t=b_(e,"utf8")}catch(r){throw Re(ee,"unable to read config",r)}return fh(t,e)}function fh(e,t){let r;try{r=C_(e)}catch(n){throw Re(ee,`invalid YAML in ${t}`,n)}if(r===null||r===void 0)return{};if(!N(r))throw M(ee,`unable to decode config: ${t} is not a mapping`);return r}function E_(e){return typeof e==="object"&&e!==null&&"code"in e&&e.code==="ENOENT"}mt();te();Fr();import{existsSync as Na,readFileSync as A_}from"fs";import{homedir as vh}from"os";import{join as Zd}from"path";var{spawn:eu}=globalThis.Bun;var L_="https://www.googleapis.com/auth/cloud-platform",xh=1500,D_=2000;function Uo(){let e=globalThis;if(e.window&&typeof e.window.fetch!=="function")e.window.fetch=fetch}function tu(){let e=process.env.GOOGLE_APPLICATION_CREDENTIALS||Zd(vh(),".config","gcloud","application_default_credentials.json");if(!Na(e))return"";try{let t=JSON.parse(A_(e,"utf8"));return typeof t.quota_project_id==="string"?t.quota_project_id:""}catch{return""}}async function ro(e){let t={gcloudInstalled:await ru("gcloud"),adcAvailable:!1,userEmail:"",projectID:"",projectSource:""};if(e!=="")t.projectID=e,t.projectSource="configuration";else{let r=F_("GOOGLE_CLOUD_PROJECT","GCLOUD_PROJECT","GOOGLE_PROJECT");if(r!=="")t.projectID=r,t.projectSource="environment variable";else if(t.gcloudInstalled){let n=await yh("core/project");if(n!=="")t.projectID=n,t.projectSource="gcloud configuration"}}if(Bi())try{await Ch(M_(t),D_)}catch(r){t.adcAvailable=!1,t.error=Ko(r)}if(t.userEmail===""&&t.gcloudInstalled)t.userEmail=await yh("core/account");return t}async function M_(e){Uo();let{GoogleAuth:t}=await import("google-auth-library"),r=new t({scopes:[L_]});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 O_(r);if(o!=="")e.userEmail=o}async function O_(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=I_(r);if(n!=="")return n}}catch{return""}return""}function I_(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 bh(e){let t=await ro(e);return dr({kind:"user",email:t.userEmail,project:t.projectID,projectSource:t.projectSource,adcAvailable:t.adcAvailable})}async function wh(){if(await eu({cmd:["gcloud","auth","application-default","login"],stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited!==0)throw Ne($o,"application-default login failed","run `gcloud auth application-default login`")}async function Sh(){if(await eu({cmd:["gcloud","auth","application-default","revoke","--quiet"],stdout:"ignore",stderr:"pipe"}).exited!==0)throw Ne($o,"failed to revoke application-default credentials","run `gcloud auth application-default revoke`")}function Ko(e){let t=$_(e).toLowerCase();if(Go(t,["unauth","invalid_grant","token has been expired","expired"]))return Ne($o,"credential expired or invalid","run `devctl auth login` or `gcloud auth application-default login`");if(Go(t,["api has not been used","has not been enabled","access not configured","service_disabled"]))return Ne(qn,"required Google API is not enabled","enable the API in the target service account project; devctl will not enable APIs automatically");if(Go(t,["permission","forbidden","iam"])){if(Go(t,["serviceaccounttoken","iamcredentials","token creator","getaccesstoken"]))return Ne(da,"cannot impersonate service account","ask an administrator to grant roles/iam.serviceAccountTokenCreator on the target service account");return Ne(qn,"authorization failure","verify IAM permissions for the current user on this project")}if(t.includes("audience"))return Ne(Sd,"IAP audience is incorrect","set auth.audience on the proxy route to the IAP OAuth client ID");if(t.includes("iap"))return Re(Sd,"IAP authentication failure",e);if(t.includes("project"))return Ne(ee,"wrong or missing Google project","set google.project_id in .devctl/config.yaml");if(Go(t,["timeout","network","connection refused","no such host"]))return Re(ct,"network problem reaching Google Cloud",e);if(Go(t,["adc","default credentials","could not find"]))return Ne($o,"application default credentials unavailable","run `gcloud auth application-default login`");return Re($o,"Google authentication failed",e)}function $_(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 c=s[a];if(Array.isArray(c))c.forEach((l)=>n(l,i+1));else n(c,i+1)}};return n(e,0),t.length>0?t.join(" "):String(e)}function Go(e,t){return t.some((r)=>e.includes(r))}function F_(...e){for(let t of e){let r=process.env[t];if(r)return r}return""}async function ru(e){try{return(await kh(process.platform==="win32"?["where",e]:["which",e],xh)).code===0}catch{return!1}}function Bi(){let e=process.env.GOOGLE_APPLICATION_CREDENTIALS;if(e&&Na(e))return!0;if(Na(Zd(vh(),".config","gcloud","application_default_credentials.json")))return!0;let t=process.env.APPDATA;return Boolean(t&&Na(Zd(t,"gcloud","application_default_credentials.json")))}async function yh(e){try{let t=await kh(["gcloud","config","get-value",e],xh);if(t.code!==0)return"";let r=t.stdout.trim();if(r===""||r==="(unset)")return"";return r}catch{return""}}async function kh(e,t){let r=eu({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 Ch(Promise.all([n,r.exited]),t);return{code:i??1,stdout:o}}catch{return r.kill(),{code:1,stdout:""}}}function Ch(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 Z_}from"crypto";import{join as eE}from"path";import{GoogleAuth as Ka,Impersonated as tE}from"google-auth-library";var{spawn:su}=globalThis.Bun;import{existsSync as Ba,readdirSync as N_,readFileSync as Rh,unlinkSync as H_}from"fs";import{join as Wi}from"path";var au="keychain-index.json",no="devctl.credentials",ou=".cred.json";function iu(e){return Wi(Sr(),`${ja(e)}${ou}`)}function Wa(e){if(e==="file"||process.env.DEVCTL_HOME&&e!=="keychain")return new Ha;if(e==="keychain"||process.platform==="darwin"||process.platform==="win32"||process.platform==="linux")return new Ph(new Ha);return new Ha}class Ha{backend="file";async get(e){let t=G_(e);if(!t||t.accessToken==="")return;return t}async set(e,t){kr(iu(e),`${JSON.stringify({...j_(t),key:e})}
|
|
628
|
+
`)}async delete(e){let t=iu(e);if(Ba(t))H_(t)}async list(){let e=Sr();if(!Ba(e))return[];let t=[];for(let r of N_(e)){if(!r.endsWith(ou))continue;let n=r.slice(0,-ou.length),o=_h(Wi(Sr(),r));if(!o)continue;t.push(Eh(o.key??n,o.record))}return t.sort((r,n)=>r.identity.localeCompare(n.identity))}}class Ph{backend="keychain";fallback;constructor(e){this.fallback=e}async get(e){let t=await U_(e);if(t)return t;return this.fallback.get(e)}async set(e,t){if(!await K_(e,t))await this.fallback.set(e,t);B_(e)}async delete(e){await q_(e),await this.fallback.delete(e),W_(e)}async list(){let e=new Set(cu()),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,Eh(n,o))}return[...r.values()].sort((n,o)=>n.identity.localeCompare(o.identity))}}function B_(e){let t=cu();if(!t.includes(e))kr(Wi(Sr(),au),`${JSON.stringify([...t,e])}
|
|
629
|
+
`)}function W_(e){let t=cu(),r=t.filter((n)=>n!==e);if(r.length!==t.length)kr(Wi(Sr(),au),`${JSON.stringify(r)}
|
|
630
|
+
`)}function cu(){let e=Wi(Sr(),au);if(!Ba(e))return[];try{let t=JSON.parse(Rh(e,"utf8"));return Array.isArray(t)?t.filter((r)=>typeof r==="string"):[]}catch{return[]}}function j_(e){return{...e,accessToken:""}}function G_(e){return _h(iu(e))?.record}function _h(e){if(!Ba(e))return;try{let t=JSON.parse(Rh(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 Eh(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 ja(e){return e.replace(/[^A-Za-z0-9._-]+/g,"_").slice(0,80)||"token"}async function U_(e){let t=await V_(e);if(!t)return;try{return JSON.parse(t)}catch{return}}async function K_(e,t){let r=JSON.stringify(t);if(process.platform==="darwin")return await qo(["security","delete-generic-password","-s",no,"-a",e]),await qo(["security","add-generic-password","-s",no,"-a",e,"-w",r,"-U"])===0;if(process.platform==="linux")return await J_(["secret-tool","store","--label",`devctl ${e}`,"service",no,"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-${ja(e)}.bin', $enc)`;return await qo(["powershell","-NoProfile","-Command",o])===0}return!1}async function q_(e){if(process.platform==="darwin"){await qo(["security","delete-generic-password","-s",no,"-a",e]);return}if(process.platform==="linux"){await qo(["secret-tool","clear","service",no,"account",e]);return}if(process.platform==="win32")await qo(["powershell","-NoProfile","-Command",`Remove-Item -ErrorAction SilentlyContinue ($env:LOCALAPPDATA + '\\devctl-cred-${ja(e)}.bin')`])}async function V_(e){if(process.platform==="darwin"){let t=await nu(["security","find-generic-password","-s",no,"-a",e,"-w"]);return t.code===0&&t.stdout!==""?t.stdout:void 0}if(process.platform==="linux"){let t=await nu(["secret-tool","lookup","service",no,"account",e]);return t.code===0&&t.stdout!==""?t.stdout:void 0}if(process.platform==="win32"){let t=`$p = $env:LOCALAPPDATA + '\\devctl-cred-${ja(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 nu(["powershell","-NoProfile","-Command",t]);return r.code===0&&r.stdout!==""?r.stdout:void 0}return}var lu=3000;async function qo(e){try{return await su({cmd:e,stdout:"ignore",stderr:"ignore",timeout:lu}).exited}catch{return 1}}async function J_(e,t){try{return await su({cmd:e,stdin:new TextEncoder().encode(t),stdout:"ignore",stderr:"ignore",timeout:lu}).exited}catch{return 1}}async function nu(e){try{let t=su({cmd:e,stdout:"pipe",stderr:"ignore",timeout:lu}),r=t.stdout?await new Response(t.stdout).text():"";return{code:await t.exited,stdout:r.trim()}}catch{return{code:1,stdout:""}}}te();te();var z_=3,Y_=200;async function Th(e,t={}){let r=t.attempts??z_,n=t.backoffMs??Y_,o=t.retry??X_,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 Q_(n*(s+1))}throw i}function X_(e){if(e instanceof Qe)return e.kind!==ee&&e.kind!==qn;return!0}function Q_(e){return new Promise((t)=>{setTimeout(t,e)})}var Ga={now:()=>new Date,isoNow:()=>new Date().toISOString(),unixMs:()=>Date.now()};var du=300000,rE=3000000,nE=3,oE=200,Ua="https://www.googleapis.com/auth/cloud-platform",iE="https://www.googleapis.com/auth/userinfo.email";function Ah(e,t,r){return`${e}|${t}|${r.join(",")}`}function sE(e,t=du,r=Date.now()){if(e.accessToken==="")return!1;return e.expiresAt.getTime()-r>=t}function aE(e,t=du,r=Date.now()){if(e.accessToken==="")return!0;let n=e.expiresAt.getTime()-r;return n>0&&n<t}class oo{cache=new Map;inflight=new Map;providers;thresholdMs;bus;store;clock;constructor(e,t,r,n,o=Ga){this.thresholdMs=e>0?e:du,this.providers=[...t],this.bus=r,this.store=n??Wa(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 sE(e,this.thresholdMs,this.clock.unixMs())}expiresSoon(e){return aE(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){let n=Ah(e,t,r),o=this.cache.get(n)??await this.loadStored(n);if(o&&this.isValid(o))return this.cache.set(n,o),o;return this.refresh(e,t,r)}async refresh(e,t,r){let n=Ah(e,t,r),o=this.inflight.get(n);if(o)return o;let i=this.refreshOnce(n,e,t,r);this.inflight.set(n,i);try{return await i}finally{this.inflight.delete(n)}}async refreshOnce(e,t,r,n){let o=this.providers.filter((s)=>!s.accepts||s.accepts(t,r,n));if(o.length===0)throw M(Qr,`no token provider accepts identity ${t}`);let i=M(Qr,"no token provider available");for(let s of o)try{let a=await Th(()=>s.fetch(t,r,n),{attempts:nE,backoffMs:oE,retry:wE});return this.cache.set(e,a),lE(e,a),await this.store.set(e,dE(a)),this.bus?.publish(Se(Lo,"",{identity:a.identity,audience:a.audience})),a}catch(a){i=a instanceof Error?a:Error(String(a))}throw this.bus?.publish(Se(jn,"",{identity:t,audience:r,error:A(i)})),i}async loadStored(e){let t=await this.store.get(e);if(!t||t.accessToken==="")return;return uE(t)}async clearStore(){let e=await this.store.list();await Promise.all(e.map((t)=>this.store.delete(t.key)))}}function cE(e){let t=Z_("sha256").update(e).digest("hex").slice(0,16);return eE(Sr(),`${t}.json`)}function lE(e,t){let r={identity:t.identity,audience:t.audience,expires_at:t.expiresAt.toISOString(),scopes:t.scopes};kr(cE(e),`${JSON.stringify(r)}
|
|
631
|
+
`)}function dE(e){return{identity:e.identity,audience:e.audience,scopes:e.scopes,accessToken:e.accessToken,tokenType:e.tokenType,expiresAt:e.expiresAt.toISOString()}}function uE(e){return{accessToken:e.accessToken,tokenType:e.tokenType||"Bearer",expiresAt:new Date(e.expiresAt),audience:e.audience,identity:e.identity,scopes:e.scopes}}function Rn(){return[mE(),fE(),pE()]}function pE(){return{name:"user",accepts:(e,t)=>!e.startsWith("sa:")&&t==="",fetch:async(e,t,r)=>{if(e.startsWith("sa:"))throw M(Qr,"user provider cannot mint service-account tokens");return vE(e,t,r)}}}function fE(){return{name:"service_account",accepts:(e,t)=>e.startsWith("sa:")&&t==="",fetch:async(e,t,r)=>{if(!e.startsWith("sa:"))throw M(Qr,"service-account provider cannot mint user tokens");return gE(e,t,r)}}}function mE(){return{name:"iap",accepts:(e,t)=>t!=="",fetch:async(e,t,r)=>{if(t==="")throw M(Qr,"IAP audience is required");if(e.startsWith("sa:"))return hE(e,t,r);return yE(e,t,r)}}}async function gE(e,t,r){let n=e.slice(3);try{Uo();let i=await new Ka({scopes:r.length>0?r:[Ua]}).getClient(),s=new tE({sourceClient:i,targetPrincipal:n,targetScopes:r.length>0?r:[Ua],lifetime:3600}),a=await s.getAccessToken(),c=typeof a==="string"?a:a?.token;if(!c)throw M(Qr,"empty impersonated token");return{accessToken:c,tokenType:"Bearer",expiresAt:qa(c,s),audience:t,identity:e,scopes:r}}catch(o){throw Ko(o)}}async function hE(e,t,r){let n=e.slice(3);try{Uo();let i=await new Ka({scopes:[Ua]}).getClient(),s=`https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${encodeURIComponent(n)}:generateIdToken`,c=(await i.request({url:s,method:"POST",data:{audience:t,includeEmail:!0}})).data.token;if(!c)throw M(Qr,"empty impersonated IAP id token");return{accessToken:c,tokenType:"Bearer",expiresAt:qa(c),audience:t,identity:e,scopes:r}}catch(o){throw Ko(o)}}async function yE(e,t,r){try{Uo();let i=await(await new Ka({scopes:r.length>0?r:[iE]}).getIdTokenClient(t)).idTokenProvider.fetchIdToken(t);return{accessToken:i,tokenType:"Bearer",expiresAt:qa(i),audience:t,identity:e,scopes:r}}catch(n){throw Ko(n)}}async function vE(e,t,r){try{Uo();let o=await new Ka({scopes:r.length>0?r:[Ua]}).getClient(),i=await o.getAccessToken();if(!i.token)throw M(Qr,"empty access token");return{accessToken:i.token,tokenType:"Bearer",expiresAt:xE(o,i.token),audience:t,identity:e,scopes:r}}catch(n){throw Ko(n)}}function qa(e,t){if(t?.credentials?.expiry_date)return new Date(t.credentials.expiry_date);return bE(e)??new Date(Date.now()+rE)}function xE(e,t){return qa(t,e)}function bE(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 wE(e){if(e instanceof Qe)return e.kind!==ee&&e.kind!==qn;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")}te();Fr();var Gi=4000,SE=8000;function Vo(e){let t=e?.tokens,r=()=>(t??=new oo(60000,Rn(),void 0,Wa("file")),t);return{detectGoogle:ro,hasCommand:ru,portAvailable:Fo,hasLocalAdc:Bi,adcQuotaProject:tu,mintToken:async(n,o)=>{await r().get(n,o,[])},probeServiceUsage:async(n,o)=>{let i=await Ui(r().get("user","",[]),Gi),s=`https://serviceusage.googleapis.com/v1/projects/${n}/services/${o}`,a=await fetch(s,{headers:{Authorization:`Bearer ${i.accessToken}`},signal:AbortSignal.timeout(Gi)});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 Va=Vo();function Ja(e=Vo()){return{run:(t,r,n)=>kE(t,e,r,n)}}async function kE(e,t=Va,r,n){let o={checks:[],issues:0},i="Preparing diagnostics",s=()=>r?.({active:i,checks:[...o.checks]}),a=(p)=>{i=p,s()},c=(p)=>{if(o.checks.push(p),p.severity==="error")o.issues+=1;s()},l=[...new Set(Object.values(e.services).flatMap((p)=>p.container?[p.container.runtime||"docker"]:[]))];for(let p of l){a(`${p} container runtime`);let m=await t.hasCommand(p),g=m&&await(t.containerRuntimeAvailable??Va.containerRuntimeAvailable)(p);c(g?{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"))c({name:"Google CLI installed",severity:"ok",message:"gcloud found"});else c({name:"Google CLI installed",severity:Hi(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 d=await t.detectGoogle(e.google.project_id);if(d.adcAvailable)c({name:"Google authentication available",severity:"ok",message:"Application Default Credentials found"});else c({name:"Google authentication available",severity:Hi(e)?"error":"warn",message:"ADC unavailable",hint:"run `gcloud auth application-default login`"});if(d.projectID!=="")c({name:"Project configured",severity:"ok",message:`${d.projectID} (source: ${d.projectSource})`});else c({name:"Project configured",severity:Hi(e)?"error":"warn",message:"no Google project configured",hint:"set google.project_id in .devctl/config.yaml"});if(Hi(e)||Object.values(e.services).some((p)=>p.capabilities.includes("google")||p.identity.type!=="")){a("Live Google access");let p=!0,m=(g)=>{if(p)c(g)};try{await Ui((async()=>{await RE(e,m,t,d.userEmail),await CE(e,m,t)})(),t.liveDeadlineMs??SE)}catch(g){m({name:"Live Google probes",severity:"warn",message:A(g),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))c({name:`${p.name} installed`,severity:"ok",message:`${m} found`});else c({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==="")c({name:"Repository configuration",severity:"ok",message:"valid"});else c({name:"Repository configuration",severity:"error",message:n.repositoryConfigError});else try{let p=Xn(e);if(p.length>0)c({name:"Repository configuration",severity:"error",message:p.join("; ")});else c({name:"Repository configuration",severity:"ok",message:"valid"})}catch(p){c({name:"Repository configuration",severity:"error",message:A(p)})}let f={};for(let[p,m]of Object.entries(e.services))for(let g of m.ports){if(g.auto)continue;let y=`Port ${g.value}`;if(a(y),f[g.value])c({name:y,severity:"error",message:`configured on both ${f[g.value]} and ${p}`});else{f[g.value]=p;let x=n?.services?.[p],h=Boolean(m.container&&x&&["STARTING","RUNNING","HEALTHY","UNHEALTHY"].includes(x.state??""));if(Boolean(x&&(x.pid>0||h)&&Object.values(x.ports).includes(g.value)))c({name:y,severity:"ok",message:`in use by running service ${p}`});else if(await t.portAvailable(g.value))c({name:y,severity:"ok",message:"available"});else c(await Dh(y,g.value,`services.${p}.ports`))}}if(e.proxy.listen.port>0){let p=`Port ${e.proxy.listen.port}`;if(a(p),n?.proxyRunning)c({name:p,severity:"ok",message:"in use by the running proxy"});else if(await t.portAvailable(e.proxy.listen.port))c({name:p,severity:"ok",message:"proxy listen port available"});else c(await Dh(p,e.proxy.listen.port,"proxy.listen.port"))}return i="Diagnostics complete",s(),o}async function CE(e,t,r){let n=e.google.project_id,o=r.hasLocalAdc??Bi;if(n===""||!o())return;let i=r.probeServiceUsage??Va.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((c)=>Ui(i(n,c.service),Gi)))).forEach((c,l)=>{let d=s[l];if(!d)return;if(c.status==="fulfilled"){t({name:d.name,severity:c.value?"ok":"warn",message:c.value?"enabled":"not enabled or unreachable",hint:c.value?void 0:`enable ${d.service} in the Google Cloud console \u2014 doctor never auto-enables APIs`});return}t({name:d.name,severity:"warn",message:A(c.reason),hint:`enable ${d.service} in the Google Cloud console \u2014 doctor never auto-enables APIs`})})}async function RE(e,t,r,n){let o=$r(e),i=e.proxy.routes.filter((u)=>u.auth.type.toLowerCase()==="iap"),s=i.filter((u)=>u.auth.audience.trim()!=="");for(let u of i)if(u.auth.audience.trim()==="")t({name:`IAP audience ${u.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??Bi)())return;let c=r.mintToken??Va.mintToken,l=o.map(async(u)=>{try{await Ui(c(`sa:${u}`,""),Gi),t({name:`Impersonate ${u}`,severity:"ok",message:"token minted"})}catch(f){let p=(r.adcQuotaProject??tu)(),m=n||"the ADC principal",g=p===""?"unknown":p,y=Lh(`Impersonate ${u}`,f,`grant roles/iam.serviceAccountTokenCreator to ${m} on ${u}; ADC quota project: ${g}`);if(p!==""&&y.message.toLowerCase().includes("api is not enabled"))y.message=`IAM Credentials API is disabled in ADC quota project ${p}`,y.hint=`enable iamcredentials.googleapis.com in ${p}, or set the ADC quota project to ${e.google.project_id}`;else if(y.message.toLowerCase()==="google authentication failed")y.message=`access-token mint failed: ${m} \u2192 ${u}`,y.hint=`verify roles/iam.serviceAccountTokenCreator for ${m} on this service account; ADC quota project: ${g}`;t(y)}}),d=s.map(async(u)=>{let f=to(u.auth).kind===eo?`sa:${to(u.auth).serviceAccount}`:"user";try{await Ui(c(f,u.auth.audience),Gi),t({name:`IAP ${u.name}`,severity:"ok",message:"id token minted"})}catch(p){t(Lh(`IAP ${u.name}`,p,"check IAP OAuth client ID and ADC"))}});await Promise.all([...l,...d])}function Lh(e,t,r){let n=A(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 Qe&&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 Ui(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 Dh(e,t,r){let n=await Vn(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 Mh(e){let t=[`${er()} 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(`
|
|
632
|
+
`)+`
|
|
633
|
+
`}Tt();class Bh{start;constructor(e){this.start=e}execute(e){return this.start({...e,profile:e.profile?ur(e.profile):void 0,services:e.services?.map((t)=>pu(t))})}}class Wh{stop;constructor(e){this.stop=e}execute(e){return this.stop(e.map((t)=>pu(t)))}}class jh{restart;constructor(e){this.restart=e}execute(e,t){return this.restart(e.map((r)=>pu(r)),t)}}class Gh{start;constructor(e){this.start=e}execute(e,t){return this.start.execute({profile:e,client_env:t})}}class Uh{host;constructor(e){this.host=e}execute(){return this.host.startProxy()}}class Kh{host;constructor(e){this.host=e}execute(){return this.host.stopProxy()}}class qh{host;constructor(e){this.host=e}execute(){return this.host.reload()}}class Vh{host;constructor(e){this.host=e}execute(){return this.host.refreshIdentity({probeServiceAccounts:!0})}}class ec{runner;constructor(e){this.runner=e}execute(e,t,r){return this.runner.run(e,t,r)}}class tc{execute(e,t,r){return za(e,t,r)}}class rc{execute(e,t){return Ya(e,t)}}class Jh{host;constructor(e){this.host=e}execute(){return this.host.snapshot()}}class nc{execute(e,t){return Za(e,t)}}function pu(e){return Oh(e)}function zh(e,t,r){let n=r??e,o=new Bh((i)=>n.start(i));return{startService:o,stopService:new Wh((i)=>n.stop(i)),restartService:new jh((i,s)=>n.restart(i,s)),startProfile:new Gh(o),startProxy:new Uh(e),stopProxy:new Kh(e),reloadConfig:new qh(e),refreshIdentity:new Vh(e),runDoctor:new ec(t),getServiceStatus:new Jh(e),getStartupPlan:new tc,getShutdownPlan:new rc,resolveStart:new nc}}import{createConnection as BE}from"net";var{spawn:WE}=globalThis.Bun;import{readdirSync as EE}from"fs";import{join as Yh,resolve as fu,sep as mu}from"path";function TE(e){let t=Yh(cr(),"state"),r;try{r=EE(t)}catch{return}let n=Xh(fu(e)),o;for(let i of r){let s=Yl(Yh(t,i,"state.json"));if(!s)continue;let a=Xh(fu(s.repo_root));if(!AE(a,n))continue;if(!o||a.length>o.length)o=a}return o}function oc(e,t,r=""){if(t!=="")return{repoRoot:fu(t),source:"explicit"};let n=e===""?process.cwd():e;try{let{repoRoot:i}=Yn(n,r);return{repoRoot:i,source:"config"}}catch{if(r!=="")return}let o=TE(n);return o?{repoRoot:o,source:"state-scan"}:void 0}function Xh(e){let t=e.length>1&&e.endsWith(mu)?e.slice(0,-1):e;return process.platform==="win32"?t.toLowerCase():t}function AE(e,t){return t===e||t.startsWith(e.endsWith(mu)?e:`${e}${mu}`)}import{existsSync as Zh,readFileSync as ey}from"fs";import{isAbsolute as LE,join as gu}from"path";import{parse as DE}from"dotenv";te();var Vi=["process","profile","dotenv","generated","keychain","secret_manager","defaults","vars","runtime"],ME=/^projects\/[^/]+\/secrets\/[^/]+(?:\/versions\/[^/]+)?$/,OE=["process","defaults","vars","runtime"];function IE(){return{name:"dotenv",load:(e)=>{let t=Qh(e.repoRoot,e.profile);if(e.workDir!=="")Object.assign(t,Qh(e.workDir,e.profile));return t}}}function $E(e){let t=e?.environment.sources??[];if(t.length===0)return[...Vi];let r=new Set([...OE,...t]),n=new Set(Vi),o=t.filter((s)=>!n.has(s)),i=[];for(let s of Vi){if(s==="defaults")i.push(...o);if(r.has(s))i.push(s)}return i}async function Ji(e,t){let r={},n=t.serviceCfg.working_dir;if(n!==""&&!LE(n))n=gu(e,n);let o={repoRoot:e,profile:t.profile,service:t.service,serviceCfg:t.serviceCfg,workDir:n,cfg:t.cfg},i=FE(t),s={process:t.includeProcess===!1?{}:t.clientEnv??zo(),profile:qi(t.profileEnv,t.cfg,i),dotenv:qi(await IE().load(o),t.cfg,i),generated:{},keychain:t.sourceValues?.keychain??NE(o),secret_manager:t.sourceValues?.secret_manager??await HE(o,t.fetchSecret),defaults:qi(t.serviceCfg.environment.defaults,t.cfg,i),vars:qi(t.serviceCfg.environment.vars,t.cfg,i),runtime:t.runtime};for(let a of $E(t.cfg)){if(s[a]!==void 0){Object.assign(r,s[a]);continue}let c=t.pluginSources?.find((l)=>l.name===a);if(c)Object.assign(r,qi(await c.load(o),t.cfg,i))}for(let a of t.serviceCfg.environment.required)if((r[a]??"").trim()==="")throw M(ee,`service ${t.service} missing required environment variable ${a}`);return r}function FE(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 qi(e,t,r){if(!t||Object.keys(e).length===0)return e;return qd(e,t,r)}function NE(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=gu(Sr(),"env",o);if(!Zh(i))continue;try{r[o]=ey(i,"utf8").replace(/\n$/,"")}catch(s){throw Re(ee,`unable to read keychain env ${o}`,s)}}return r}async function HE(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(!ME.test(s))throw M(ee,`environment.secrets.${i} is not a Secret Manager resource`);if(!t)throw M(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 Qh(e,t){let r={},n=[".env",".env.development",".env.local"];if(t!=="")n.push(`.env.${t}`);for(let o of n){let i=gu(e,o);if(!Zh(i))continue;try{let s=DE(ey(i));Object.assign(r,s)}catch(s){throw Re(ee,`unable to read ${i}`,s)}}return r}function zo(){let e={};for(let[t,r]of Object.entries(process.env))if(r!==void 0)e[t]=r;return e}function zi(e,t,r,n,o){let i={DEVCTL_SERVICE_NAME:e,DEVCTL_ENVIRONMENT:o,SERVICE_HOST:t};if(n!=="")i.DEVCTL_PROXY_URL=n;if(r.http!==void 0)i.SERVICE_PORT=String(r.http);else{let s=Object.values(r)[0];if(s!==void 0)i.SERVICE_PORT=String(s)}for(let[s,a]of Object.entries(r))i[`${s.toUpperCase()}_PORT`]=String(a);return i}function Yo(e){return{...e}}te();var jE=50,GE=8000,UE=15000,KE=200,qE=30000,ty=86400000,VE=new Set(["logs","logs_page","logs_stats"]);function JE(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 ${ji}`}function zE(e){if(e.compatible&&e.daemonVersion!==void 0&&e.daemonVersion!==Bt)return`attached daemon is devctl ${e.daemonVersion}; this client is ${Bt} (run \`devctl down\` then start again to update it)`;return}function hu(e,t){if(!e.compat.compatible&&!VE.has(t))throw Ne(ct,JE(e.compat),"run `devctl down` to stop it, then start again")}class ry{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(`
|
|
634
|
+
`);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(rg({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=qE){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})+`
|
|
635
|
+
`)})}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 ny(e,t){let r=Vs(e),n=Date.now()+t;return new Promise((o,i)=>{let s=()=>{let a=BE(r);a.once("connect",()=>{let c=new ry(a);YE(c).finally(()=>o(c))}),a.once("error",(c)=>{if(a.destroy(),Date.now()>=n){i(Ne(ct,"supervisor is not running","run `devctl start` or `devctl attach` after starting services"));return}setTimeout(s,jE)})};s()})}async function YE(e){let t;try{t=await e.call("ping",null,GE)}catch{return}let r=XE(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===ji,legacy:!1,daemonVersion:o,daemonProtocol:n}}function XE(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}async function ao(e){try{return await ny(e,KE)}catch{return}}function QE(e,t,r,n){return r?[e,...n]:[e,t,...n]}async function oy(e,t){let r=await ao(e);if(r)return r;gm(e);let n=ki(e),o=QE(process.execPath,process.argv[1]??"",Bun.isStandaloneExecutable===!0,["--config",t,"_supervisor","--repo",e]),i=WE({cmd:o,env:{...process.env},stdout:"ignore",stderr:Bun.file(n),stdin:"ignore",detached:!0});try{let s=await e0(e,UE,i.exited);return i.unref(),s}catch{throw await t0(i),Ne(ct,"supervisor failed to start",`see ${n} for details`)}}var ZE=1000;function e0(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`)))}),ny(e,t).then((a)=>s(()=>n(a)),(a)=>s(()=>o(a)))})}async function t0(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,ZE)})])}class ic{cfg;client;previousPersisted;constructor(e){this.cfg=e}async start(e){return await this.call("start",{...e,client_env:zo()})}async stop(e){await this.call("stop",{services:e})}async restart(e,t){await this.call("restart",{services:e,cascade:t===!0,client_env:zo()})}async runTask(e){return await this.call("run_task",{name:e,client_env:zo()},ty)}async execService(e,t,r=!1){return await this.call("exec",{service:e,command:t,print_env:r,client_env:zo()},ty)}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 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 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 Re(ct,"supervisor is not running",Error("no client"));return hu(this.client,e),this.client.call(e,t,r)}}function Yi(e){let t=e&&zE(e.compat);if(t)process.stderr.write(`warning: ${t}
|
|
636
|
+
`)}async function iy(e,t,r=""){let n=oc(e,t,r);if(!n)throw Ne(ct,"no devctl configuration found","run `devctl setup`, create a .devctl/config.yaml in the repository root, or pass --repo");let o=await ao(n.repoRoot);return Yi(o),{repoRoot:n.repoRoot,client:o}}async function sy(e,t,r,n){let o=n?.allowMissingConfig===!0?Zn(e,t):tn(e,t),i=new ic(o);if(!r)return i.client=await ao(o.repoRoot),Yi(i.client),i;return i.client=await oy(o.repoRoot,o.configPath),Yi(i.client),i}async function ay(e){let t=new ic(Jn());return t.client=e,Yi(t.client),t.cfg=await t.configSnapshot(),t}async function cy(e,t){let r=oc(e,"",t),n=r?await ao(r.repoRoot):void 0;if(!n)throw Ne(ct,"supervisor is not running","run `devctl start` before `devctl attach`");return ay(n)}async function ly(e,t){let r=oc(e,"",t),n=r?await ao(r.repoRoot):void 0;if(n)return ay(n);let o=tn(e,t),i=new ic(o),s=un(o.repoRoot);if(i.client=await oy(o.repoRoot,o.configPath),Yi(i.client),i.cfg=await i.configSnapshot(),s&&s.processes.length>0)i.previousPersisted=s;return i}import{realpathSync as n0}from"fs";var o0="https://api.github.com/repos/amr-m-abdelgawad/devctl/releases/latest";function i0(){let e=Bun.isStandaloneExecutable===!0,t=e?"":hy(process.argv[1]??"");return fy({scriptPath:t,execPath:hy(process.execPath),standalone:e})}async function s0(e=fetch,t=i0()){try{let r=await e(o0,{headers:{Accept:"application/vnd.github+json"}});if(!r.ok)return gy(t);let o=((await r.json()).tag_name??"").replace(/^v/,"");return{current:Bt,latest:o,newer:o!==""&&my(o,Bt)>0,hint:t.hint,kind:t.kind,command:t.command}}catch{return gy(t)}}async function a0(e,t=yy){return t(e)}async function yy(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 vy(e=fetch){return{check:()=>s0(e),apply:(t,r)=>r===!0?yy(t,!0):a0(t)}}function gy(e){return{current:Bt,latest:"",newer:!1,hint:e.hint,kind:e.kind,command:e.command}}function hy(e){if(e==="")return"";try{return n0(e)}catch{return e}}function xy(e){let t=e?.tokens??new oo(60000,Rn(),void 0),r=e?.doctorHost??Vo({tokens:t}),n=vy(),o={loadTuiConfig:To,saveTuiPreferences:Sm,resolveTuiOverridePath:ea,userTuiConfigPath:Zs,listSessions:zm,loadSessionEvents:Ym,loadPath:Ni,validateConfigText:Fi,discover:Yn,configDiff:Cn,openTui:ly,findDaemon:iy,tryDial:ao,assertMethodAllowed:hu,readPersistedState:un,bootstrapLogPath:ki,exportsDir:qs,resolveExportPath:Vm,writeLogExport:wd,openInFileManager:Jm,freePort:fa,createStarterConfig:fg,runSetup:(i,s,a)=>mg(o,i,s,a),readTextFile:(i)=>l0(i,"utf8"),writeTextFile:(i,s)=>d0(i,s),fileExists:c0,load:tn,loadOrEmpty:Zn,validate:Xn,detectGoogle:ro,loginGoogle:wh,logoutGoogle:Sh,refreshUserToken:async(i="user")=>t.refresh(i,"",[]),runDoctor:new ec(e?.doctorRunner??Ja(r)),getStartupPlan:new tc,getShutdownPlan:new rc,resolveStart:new nc,formatDoctor:Mh,openController:sy,openAttach:cy,checkUpdate:()=>n.check(),applyUpdate:(i,s)=>n.apply(i,s),formatUpdateStatus:py};return o}import{existsSync as vA,unlinkSync as xA}from"fs";import{connect as u0}from"net";Tt();var p0=2000,f0=200,m0=300;function by(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)=>g0({...o,type:t},i.pid,i.ports,i.workDir,i.env,e)}:void 0}}}async function g0(e,t,r,n,o,i=[]){let s=e.timeout_seconds>0?e.timeout_seconds*1000:p0,a=e.type.toLowerCase(),c=i.find((l)=>l.name.toLowerCase()===a);if(c)try{let l=await c.check(e,{pid:t,ports:r,workDir:n,env:o});return{status:l.status,message:l.message}}catch(l){return{status:Me,message:l instanceof Error?l.message:String(l)}}if(a==="http")return h0(e.url,s);if(a==="tcp")return v0(y0(e.address,r),s);if(a==="command")return x0(e.command.args,e.command.shell,n,o,s);if(a==="process"||a===""){if(t>0&&Qt(t))return{status:Wt,message:"process running"};return{status:Me,message:"process not running"}}return{status:Me,message:`unknown health type ${e.type}`}}async function h0(e,t){let r=new AbortController,n=setTimeout(()=>r.abort(),t);try{let o=await fetch(e,{signal:r.signal});if(o.status>=f0&&o.status<m0)return{status:Wt,message:String(o.status)};return{status:Me,message:String(o.status)}}catch(o){return{status:Me,message:o instanceof Error?o.message:String(o)}}finally{clearTimeout(n)}}function y0(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 v0(e,t){return new Promise((r)=>{if(e===""){r({status:Me,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:Me,message:`invalid tcp address ${e}`});return}let s=u0({host:i,port:o},()=>{s.end(),r({status:Wt,message:"connected"})});s.setTimeout(t),s.on("error",(a)=>{r({status:Me,message:a.message})}),s.on("timeout",()=>{s.destroy(),r({status:Me,message:"timeout"})})})}async function x0(e,t,r,n,o){if(e.length===0)return{status:Me,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(l){return{status:Me,message:l instanceof Error?l.message:String(l)}}let a=setTimeout(()=>s.kill("SIGKILL"),o),c=await s.exited;if(clearTimeout(a),c===0)return{status:Wt,message:"ok"};return{status:Me,message:`exit ${c}`}}te();var{spawn:Oy}=globalThis.Bun;var{spawn:b0}=globalThis.Bun;async function wy(e,t){if(e<=0)return;try{process.kill(-e,t);return}catch{try{process.kill(e,t)}catch{return}}}async function Sy(e){if(!Qt(e))return;let t=await Xi(["ps","-p",String(e),"-o","command="]),r=Date.now(),n=w0(await Xi(["ps","-p",String(e),"-o","etime="])),o=await S0(e);return{pid:e,command:t.trim(),cwd:o,startTime:n===void 0?void 0:new Date(r-n).toISOString()}}function w0(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,c=Number(i.length===3?i[1]:i[0]),l=Number(i.at(-1));if(!Number.isInteger(s)||s<0||!Number.isInteger(a)||a<0||a>23||!Number.isInteger(c)||c<0||c>59||!Number.isInteger(l)||l<0||l>59)return;return(((s*24+a)*60+c)*60+l)*1000}async function S0(e){let r=(await Xi(["lsof","-a","-p",String(e),"-d","cwd","-Fn"])).split(`
|
|
637
|
+
`).find((i)=>i.startsWith("n"));if(r&&r.length>1)return r.slice(1).trim();let n=await Xi(["pwdx",String(e)]),o=n.indexOf(":");if(o>=0)return n.slice(o+1).trim();return""}async function Xi(e){try{let t=b0({cmd:e,stdout:"pipe",stderr:"ignore"}),r=t.stdout?await new Response(t.stdout).text():"";return await t.exited,r}catch{return""}}async function ky(e){let t=new Map;if(e.length===0)return t;let r=await Xi(["ps","-o","pid=,pcpu=,rss=","-p",e.join(",")]);for(let n of r.split(`
|
|
638
|
+
`)){let o=n.trim();if(o==="")continue;let[i,s,a]=o.split(/\s+/),c=Number(i),l=Number(s),d=Number(a);if(Number.isFinite(c)&&Number.isFinite(l)&&Number.isFinite(d))t.set(c,{pid:c,cpuPercent:l,memoryKB:d})}return t}function Cy(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:Ry}=globalThis.Bun;var k0=1024;async function Py(e,t){if(e<=0)return;try{await Ry({cmd:["taskkill","/PID",String(e),"/T","/F"],stdout:"ignore",stderr:"ignore"}).exited}catch{return}}async function _y(e){let t=C0(Xl(e),e);if(t)return t;if(!Qt(e))return;let r=await yu(["powershell","-NoProfile","-Command",`Get-CimInstance Win32_Process -Filter "ProcessId=${e}" | Select-Object CommandLine,ExecutablePath,CreationDate | ConvertTo-Json -Compress`]),n=P0(r);if(n&&n.command!=="")return{pid:e,command:n.command,cwd:n.cwd,startTime:n.startTime};let o=await yu(["powershell","-NoProfile","-Command",`Get-Process -Id ${e} -ErrorAction SilentlyContinue | Select-Object Path,StartTime | ConvertTo-Json -Compress`]),i=R0(o);if(!i&&!n)return;return{pid:e,command:n?.command||i?.command||"",cwd:n?.cwd||i?.cwd||"",startTime:n?.startTime||i?.startTime}}function C0(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 R0(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=ac(t,"Path");if(r==="")return;return{command:r,cwd:cc(r)}}}function P0(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:ac(t,"CommandLine")||ac(t,"ExecutablePath"),cwd:cc(ac(t,"ExecutablePath"))}}}async function Ey(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 yu(["powershell","-NoProfile","-Command",`${r}.Split(',') | ForEach-Object { Get-Process -Id $_ -ErrorAction SilentlyContinue } | Select-Object Id,CPU,WorkingSet64 | ConvertTo-Json -Compress`]);return _0(n)}function _0(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),c=Number(s.CPU??0),l=Number(s.WorkingSet64??0)/k0;if(Number.isFinite(a)&&a>0&&Number.isFinite(c)&&Number.isFinite(l))t.set(a,{pid:a,cpuPercent:c,memoryKB:l})}}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 ac(e,t){let r=`${t}=`,n=e.split(/\r?\n/).find((o)=>o.startsWith(r));return n?n.slice(r.length).trim():""}async function yu(e){try{let t=Ry({cmd:e,stdout:"pipe",stderr:"ignore"}),r=t.stdout?await new Response(t.stdout).text():"";return await t.exited,r}catch{return""}}te();var{spawn:vu}=globalThis.Bun;async function Ay(e){await A0(e.runtime,e.containerName);let t=E0(e),r=await Xo(e.runtime,t,e.env);if(r.code!==0||r.stdout.trim()==="")throw M(He,`failed to start ${e.containerName}: ${r.stderr.trim()||"container runtime returned no id"}`);let n=r.stdout.trim().split(/\s+/)[0]??"";return My(e.runtime,e.containerName,n,e.onLine,e.onExit)}function E0(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 T0=new Set(["PATH","HOME","HOSTNAME","PWD","OLDPWD","SHLVL","_","TMPDIR"]);function Ly(e){return Object.fromEntries(Object.entries(e).filter(([t])=>!T0.has(t)))}async function Dy(e,t,r,n){let o=await Xo(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 My(e,t,i,r,n)}function My(e,t,r,n,o){let i=!0,s=vu({cmd:[e,"logs","--follow",r],stdout:"pipe",stderr:"pipe",stdin:"ignore"});Ty(s.stdout,"stdout",n),Ty(s.stderr,"stderr",n);let a=vu({cmd:[e,"wait",r],stdout:"pipe",stderr:"pipe",stdin:"ignore"}),c=Promise.all([new Response(a.stdout).text(),a.exited]).then(async([l,d])=>{i=!1,s.kill();let u=Number.parseInt(l.trim(),10),f=Number.isFinite(u)?u:d??1,p=f===0?void 0:Error(`container exited with code ${f}`);return await Xo(e,["rm","--force",r],process.env),o?.(f,p),{code:f,err:p}});return{id:r,runtime:e,containerName:t,done:c,running:()=>i,stop:async(l)=>{let d=Math.max(1,Math.ceil(l/1000));await Xo(e,["stop","--time",String(d),r],process.env),await c}}}async function A0(e,t){let r=await Xo(e,["inspect","--format","{{.State.Running}}",t],process.env);if(r.code===0&&r.stdout.trim()==="false")await Xo(e,["rm","--force",t],process.env)}async function Xo(e,t,r){try{let n=vu({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 Re(He,`unable to run ${e}`,n)}}async function Ty(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(`
|
|
639
|
+
`);i=a.pop()??"";for(let c of a)r(t,c.replace(/\r$/,""))}if(i!=="")r(t,i)}var L0=1e4,D0=2000,M0=500;class xu{isRunning(e){let t=this.running.get(e);return t!==void 0&&Qi(t)}running=new Map;async start(e){let t=this.running.get(e.name);if(t&&Qi(t))return t;if(this.running.delete(e.name),e.args.length===0)throw M(He,"empty command");let r=e.shell?Fy(e.args):e.args,n;try{n=Oy({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 Re(He,`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 lc(n.stdout,"stdout",e.onLine),lc(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 M(He,"empty command");let t;try{t=Oy({cmd:e.shell?Fy(e.args):e.args,cwd:e.workDir||void 0,env:e.env,stdout:"pipe",stderr:"pipe",stdin:"ignore"})}catch(a){throw Re(He,`failed to run ${e.name}`,a)}let r="",n="",o=(a,c)=>{if(a==="stdout")r+=`${c}
|
|
640
|
+
`;else n+=`${c}
|
|
641
|
+
`;e.onLine?.(a,c)},i=[lc(t.stdout,"stdout",o),lc(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&&Qi(t))return t;let r=await Ay({...e,env:Ly(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&&Qi(t))return t;let r=await Dy(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&&Qi(t))return t;if(!Qt(e.pid))throw M(He,`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=I0(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:L0;if(r.container){await r.container.stop(n),this.running.delete(e);return}if(await Iy(r.pid,"SIGTERM"),!await Hy(r.done,n)){if(await Iy(r.pid,"SIGKILL"),!await Hy(r.done,D0))throw M(He,`process ${e} did not exit after SIGKILL`)}this.running.delete(e)}get(e){return this.running.get(e)}all(){return[...this.running.values()]}}function Qi(e){if(e.container)return e.container.running();if(e.proc)return e.proc.exitCode===null&&!e.proc.killed;return Qt(e.pid)}async function Iy(e,t){if(process.platform==="win32"){await Py(e,t);return}await wy(e,t)}async function By(e){if(process.platform==="win32")return _y(e);return Sy(e)}async function Wy(e){if(process.platform==="win32")return Ey(e);return ky(e)}var O0=2000;function Zi(e,t){if(e.workDir!==""&&t.cwd!==""&&Ny(e.workDir)!==Ny(t.cwd))return!1;if(!Cy(e.args,t.command))return!1;let r=$y(e.startTime),n=$y(t.startTime);if(r!==void 0&&n!==void 0)return Math.abs(r-n)<=O0;return!0}function $y(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 Fy(e){if(process.platform==="win32")return["cmd.exe","/c",e.join(" ")];return["/bin/sh","-c",e.join(" ")]}function Ny(e){return e.replace(/\\/g,"/").replace(/\/+$/,"")}async function I0(e){while(Qt(e))await $0(M0);return 0}async function lc(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 c=i.split(`
|
|
642
|
+
`);i=c.pop()??"";for(let l of c)r(t,l.replace(/\r$/,""))}}async function Hy(e,t){return Promise.race([e.then(()=>!0),new Promise((r)=>{setTimeout(()=>r(!1),t)})])}function $0(e){return new Promise((t)=>{setTimeout(t,e)})}import{existsSync as F0,readFileSync as N0,writeFileSync as H0}from"fs";var jy={exists:(e)=>F0(e),readText:(e)=>N0(e,"utf8"),writeText:(e,t)=>H0(e,t)};mt();var bu=3,B0=3,W0=10,es={shouldRestart(e){if(!e.enabled||e.policy===ma)return!1;if(e.retryCount>=e.maxRetries)return!1;if(e.policy===ha)return!0;return e.policy===ga&&e.exitCode!==0},fromService(e,t,r){return{policy:ba(e.restart),enabled:e.restart.enabled!==!1,exitCode:r,retryCount:t,maxRetries:e.restart.max_retries>0?e.restart.max_retries:bu}}},wu={shouldRestartUnhealthy(e,t=B0){return e>=t},shouldResetRestartBudget(e,t=W0){return e>=t}},dc={timeoutMs(e,t){let r=e.startup.timeout_seconds;return r>0?r*1000:t},waitForHealthy(e){return e.startup.wait_for_healthy}};Tt();te();var j0=2,G0=2000,U0=3,K0=10;class Su{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===lt)return;if(o&&(o.state===Rr||o.state===_t)){this.host().setState(e,_t,Et,0,""),this.host().bus.publish(Se(ta,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?es.shouldRestart(es.fromService(i,a,r)):!1)&&i){this.host().setState(e,fr,Et,0,s),this.bumpRestartCount(e,a+1),this.host().persistState(),this.armRestart(e,i,t,a,()=>{let l=this.host().serviceProfile.get(e)??this.host().profile,d=this.host().serviceProfileEnv.get(e)??this.host().profileEnv;this.actions.startOne(e,l,d,!1).catch((u)=>this.host().log(e,"ERROR",A(u)))});return}this.host().fail(e,M("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,Wt,"no health check");return}let c=t.health.interval_seconds>0?t.health.interval_seconds*1000:G0,l=Date.parse(this.host().runtimes.get(e)?.startTime??"")||this.clock.unixMs(),d=()=>{(t.container&&t.health.type.toLowerCase()==="process"?Promise.resolve(this.processes.isRunning(e)?{status:Wt,message:"container running"}:{status:Me,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:Me,message:`unknown health type ${t.health.type}`})).catch((f)=>({status:Me,message:A(f)})).then((f)=>{if(!this.isCurrentGeneration(e,s))return;let p=this.host().runtimes.get(e);if(p&&Gy(p.state))return;if(f.status===Me&&this.clock.unixMs()-l<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:q0(f.status),message:`health ${f.status} ${f.message}`,pid:r}),this.maybeRestartUnhealthy(e,t,f.status,s)})};d(),this.healthTimers.set(e,setInterval(d,c))}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:j0;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||Gy(n.state))return;if(n.health=t,n.state===Be||n.state===pr||n.state===Nr)n.state=t===Wt?pr:t===Me?Nr:n.state;this.host().bus.publish(Se(Rm,e,{health:t,message:r}))}maybeRestartUnhealthy(e,t,r,n){if(r!==Me){if(this.unhealthyStreak.set(e,0),r===Wt)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:U0;if(!wu.shouldRestartUnhealthy(i,s))return;this.unhealthyStreak.set(e,0);let a=this.restarts.get(e)??0,c=t.restart.max_retries>0?t.restart.max_retries:bu;if(a>=c){this.host().log(e,"WARN",`unhealthy after ${i} consecutive checks but the restart limit (${c}) 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}/${c})`),this.armRestart(e,t,n,a,()=>{this.actions.restart([e],{auto:!0}).catch((l)=>this.host().log(e,"ERROR",A(l)))})}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:K0;if(wu.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 Gy(e){return e===fr||e===Rr||e===_t||e===lt}function q0(e){return e===Me?"WARN":e===Wt?"INFO":"DEBUG"}mt();te();Fr();te();Tt();var ku=[Rr,lt,fr,Be,_t],V0={[$h]:[_t,rn,Be,lt,fr,Rr],[_t]:[rn,Be,lt],[rn]:[Be,lt,_t,Rr],[Be]:ku,[pr]:ku,[Nr]:ku,[Rr]:[_t,lt],[lt]:[rn,_t,Be],[fr]:[rn,Be,lt,_t]};function ts(e,t){if(e===t)return!0;return(V0[e]??[]).includes(t)}function Uy(e,t){if(!ts(e,t))throw M(ee,`illegal service lifecycle transition ${e} \u2192 ${t}`);return t}Tt();var J0=100,Ky=30000;class Cu{processes;clock;session;health;constructor(e,t){this.processes=e;this.clock=t;this.health=new Su(()=>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 M(He,"service orchestrator is not bound");return this.session}planStart(e,t,r){return za(e,t,r)}planStop(e,t,r=!1){return r?Xa(e,t):Ya(e,t)}applyLifecycle(e,t){return Uy(e,t)}isLegalLifecycle(e,t){return ts(e,t)}async start(e){let t=this.host();if(e.detach===!0)t.detached=!0;let r=Za(t.cfg,{services:e.services,profile:e.profile?ur(e.profile):void 0,activeProfile:ur(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=gh(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,M(He,a.message));if(t.cfg.proxy.enabled&&!t.proxySuppressed)await t.startProxy().catch((a)=>t.log("devctl","ERROR",A(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 c=a.filter((l)=>s.includes(l));if(c.length>0){let l=await Promise.allSettled(c.map((u)=>this.startOne(u,r.profile,r.env,e.auto!==!0))),d=!1;for(let u of l)if(u.status==="rejected")d=!0,t.log("devctl","ERROR",A(u.reason));if(d)throw M(He,"one or more services failed to start")}try{await this.awaitWaveHealth(a,n.waves.flat())}catch(l){throw t.log("devctl","ERROR",A(l)),l}}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!==_t).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 M(Io,`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?io(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,Rr,Et,0,""),this.health.clearHealthWatch(a);try{await this.processes.stop(a,n)}catch(c){throw r.setState(a,lt,Et,0,A(c)),r.bus.publish(Se(ra,a,{error:A(c)})),c}try{await r.releasePorts(a)}catch(c){r.log(a,"WARN",A(c))}r.setState(a,_t,Et,0,""),r.bus.publish(Se(ta,a,{}))}));for(let a=0;a<s.length;a+=1){let c=s[a];if(c?.status==="rejected"){let l=i[a]??"";o.push(l),r.log(l||"devctl","ERROR",A(c.reason))}}}if(r.persistState(),o.length>0)throw M(He,`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===fr||t.state===Rr||t.state===_t||t.state===lt)return!1;if(t.health===Wt||t.state===pr)return!0;return t.state===rn||t.state===Be}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 M(ct,`unknown service ${e}`);o.setState(e,rn,Et,0,"");let s=this.health.bumpGeneration(e),a=o.serviceProfile.get(e)??t,c=a!==""?so(o.cfg,a):{...r};o.serviceProfileEnv.set(e,c);let l={},d={},u="",f;try{await o.prepareServiceIdentity(e,i),l=o.ports.get(e)??{};let p=await o.resolveServiceExecution(e,i,a,c,o.clientEnv.get(e),!i.container);if(d=p.env,u=p.workDir,n)await this.runTransient(`${e}:pre_start`,i.hooks.pre_start,i.shell,u,d);if(!this.health.isCurrentGeneration(e,s))return;let m=(y,x)=>{o.logs.append({timestamp:this.clock.isoNow(),service:e,source:y,stream:y,level:"",message:x,pid:f.pid})},g=(y,x)=>this.health.onExit(e,s,y,x);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:{...d,...i.container.env},ports:l,targetPorts:i.container.ports,volumes:i.container.volumes,workDir:u,onLine:m,onExit:g}):await this.processes.start({name:e,args:[...i.command.args],shell:i.shell||i.command.shell,workDir:u,env:d,graceMs:vn(o.cfg.shutdown)*1000,captureStdout:lg(i),captureStderr:dg(i),onLine:m,onExit:g})}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:u,startTime:f.startTime}),o.setState(e,Be,Et,f.pid,""),o.bus.publish(Se(km,e,{pid:f.pid})),n)try{await this.runTransient(`${e}:post_start`,i.hooks.post_start,i.shell,u,d)}catch(p){throw await o.fail(e,p),p}if(!this.health.isCurrentGeneration(e,s))return;if(this.health.startHealth(e,i,f.pid,l,u,d,s),o.persistState(),o.clearRestartRequired([e]),dc.waitForHealthy(i)){let p=dc.timeoutMs(i,Ky);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)=>Jt(a)===r&&mn(a)==="service_healthy"));if(!n||n.health.type===""||!o)continue;let i=dc.timeoutMs(n,Ky);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===Wt)return;if(n?.state===lt)throw M(kd,`service ${e} failed while waiting for healthy`);await z0(J0)}throw M(kd,`service ${e} did not become healthy in time`)}async runTransient(e,t,r,n,o){if(hn(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 M(He,`${e} exited with code ${i.code}`);return i}}function z0(e){return new Promise((t)=>setTimeout(t,e))}te();function rs(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 M(ee,`secret manager request failed for ${t}: HTTP ${o.status}`);let i=await o.json();if(!i.payload?.data)throw M(ee,`secret manager response for ${t} had no payload`);return Buffer.from(i.payload.data,"base64").toString("utf8")}}Tt();te();async function uc(e,t,r,n){let o="";if(e.proxy?.isRunning())o=`http://${e.proxy.address()}`;else if(e.cfg.proxy.enabled)o=`http://${yn(e.cfg.proxy.listen)}`;let i=zi(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 Ji(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:rs(async()=>(await e.tokens.get("user","",[])).accessToken),pluginSources:e.registry?.environmentSources});return Yo(s)}catch(s){return e.log(t,"WARN",`could not fully reconstruct environment for adopted service's health check (${A(s)}); using a baseline environment`),Yo(i)}}function qy(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,c)=>{e.orchestrator.health.onExit(t,s,a,c)}})}catch(a){let c=a instanceof Error?a.message:String(a);e.log(t,"WARN",`adopt pid ${r} failed (${c}); tracking leftover in snapshot only`)}return e.processMeta.set(t,{command:n,cwd:o,startTime:i}),e.persistState(),s}async function Vy(e,t){let r=e.cfg.services[t];if(e.orchestrator.serviceIsActive(t)){if(r&&!e.ports.has(t)){let a=await pa(r);if(a)e.ports.set(t,a)}return!0}if(!r)return!1;if(r.container){let a=e.orchestrator.health.bumpGeneration(t),c=r.container.runtime==="podman"?"podman":"docker",l=e.serviceWorkDir(r),d=await e.procs.adoptContainer({name:t,runtime:c,containerName:`devctl-${ar(e.cfg.repoRoot)}-${t.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,workDir:l,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(!d)return!1;let u=e.ports.get(t)??Object.fromEntries(r.ports.filter((p)=>!p.auto).map((p)=>[p.name,p.value]));e.ports.set(t,u),e.processMeta.set(t,{command:[...r.command.args],cwd:l,startTime:d.startTime}),pc(e,t,fc(e,un(e.cfg.repoRoot)?.processes.find((p)=>p.name===t))),e.setState(t,Be,Et,0,"");let f=await uc(e,t,r,u);return e.orchestrator.health.startHealth(t,r,0,u,l,f,a),e.persistState(),e.log(t,"INFO",`claimed running ${c} container ${d.container?.id??""}`),!0}let n=await pa(r);if(!n)return!1;let o=Object.values(n)[0],s=(o===void 0?void 0:await Vn(o))?.pid??0;if(s>0&&s!==process.pid){let a=un(e.cfg.repoRoot)?.processes.find((d)=>d.name===t&&d.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 c=await e.inspectProcessFn(s);if(c!==void 0&&c.command!==""&&Zi({args:[...r.command.args],workDir:e.serviceWorkDir(r),startTime:new Date(a.startTime)},c)){e.ports.set(t,n);let d=qy(e,t,s,[...r.command.args],e.serviceWorkDir(r),new Date(a.startTime))??e.orchestrator.health.bumpGeneration(t);pc(e,t,fc(e,a)),e.setState(t,Be,Et,s,""),e.log(t,"INFO",`already listening on ${Object.values(n).join(", ")}; not starting again`);let u=e.serviceWorkDir(r),f=await uc(e,t,r,n);return e.orchestrator.health.startHealth(t,r,s,n,u,f,d),!0}e.log(t,"WARN",`port ${o} is in use by an unrelated process (pid ${s}); not adopting`)}return!1}async function Jy(e){let t=un(e.cfg.repoRoot);if(!t)return;Y0(e,t.profile);let r=[];for(let[n,o]of Object.entries(e.cfg.services)){if(!o.container)continue;let i=t.processes.find((u)=>u.name===n),s=e.orchestrator.health.bumpGeneration(n),a=o.container.runtime==="podman"?"podman":"docker",c=await e.procs.adoptContainer({name:n,runtime:a,containerName:`devctl-${ar(e.cfg.repoRoot)}-${n.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,workDir:e.serviceWorkDir(o),onLine:(u,f)=>e.logs.append({timestamp:e.clock.isoNow(),service:n,source:u,stream:u,level:"",message:f,pid:0}),onExit:(u,f)=>e.orchestrator.health.onExit(n,s,u,f)});if(!c)continue;let l=i?.ports??Object.fromEntries(o.ports.filter((u)=>!u.auto).map((u)=>[u.name,u.value]));e.ports.set(n,l),e.processMeta.set(n,{command:[...o.command.args],cwd:e.serviceWorkDir(o),startTime:i?.startTime?new Date(i.startTime):c.startTime}),pc(e,n,fc(e,i)),e.setState(n,Be,Et,0,"");let d=await uc(e,n,o,l);e.orchestrator.health.startHealth(n,o,0,l,e.serviceWorkDir(o),d,s),e.log(n,"INFO",`adopted ${a} container ${c.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!==""&&Zi({args:n.command,workDir:n.cwd,startTime:n.startTime?new Date(n.startTime):void 0},o))){if(Object.values(n.ports).length>0&&await pa({ports:Object.entries(n.ports).map(([l,d])=>({name:l,value:d,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=qy(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);pc(e,n.name,fc(e,n)),e.setState(n.name,Be,Et,n.pid,"");let a=e.cfg.services[n.name];if(a){let c=n.cwd||e.serviceWorkDir(a),l=await uc(e,n.name,a,n.ports);e.orchestrator.health.startHealth(n.name,a,n.pid,n.ports,c,l,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(Se(Em,"",{services:r,session_id:t.session_id})),e.log("devctl","INFO",`recovered session processes: ${r.join(", ")}`)}function Y0(e,t){e.profile=t||e.profile,e.profileEnv=so(e.cfg,e.profile)}function pc(e,t,r){e.serviceProfile.set(t,r),e.serviceProfileEnv.set(t,so(e.cfg,r))}function fc(e,t){return t?.profile??e.profile}import{statSync as uT,watch as pT}from"fs";import{isAbsolute as fT,join as mT,resolve as gT}from"path";function zy(e,t){return t}function Ru(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],c=t.services[s],l=[];if(!a||!c)l.push("presence"),n.add(s);else{if(a.command.args.join("\x00")!==c.command.args.join("\x00")||a.command.shell!==c.command.shell||a.shell!==c.shell)l.push("command"),n.add(s);if(a.working_dir!==c.working_dir)l.push("working_dir"),n.add(s);if(JSON.stringify(a.environment)!==JSON.stringify(c.environment))l.push("environment"),n.add(s);if(JSON.stringify(a.ports)!==JSON.stringify(c.ports))l.push("ports"),n.add(s);if(JSON.stringify(a.identity)!==JSON.stringify(c.identity))l.push("identity"),n.add(s);if(JSON.stringify(a.health)!==JSON.stringify(c.health))l.push("health"),n.add(s);if(JSON.stringify(a.restart)!==JSON.stringify(c.restart))l.push("restart"),n.add(s);if(JSON.stringify(a.startup)!==JSON.stringify(c.startup))l.push("startup"),n.add(s);if(JSON.stringify(a.logs)!==JSON.stringify(c.logs))l.push("logs"),n.add(s);if(JSON.stringify(a.container)!==JSON.stringify(c.container))l.push("container"),n.add(s);if(JSON.stringify(a.watch)!==JSON.stringify(c.watch))l.push("watch"),n.add(s)}if(l.length>0)r[s]=l}let i=[];if(JSON.stringify(e.logs)!==JSON.stringify(t.logs))i.push("logs");if(JSON.stringify(e.auth)!==JSON.stringify(t.auth))i.push("auth");return{restart_required:[...n].sort(),changes:r,supervisor_restart_required:i}}Tt();te();import{pathToFileURL as sT}from"url";import{isAbsolute as aT,resolve as cT}from"path";import{createServer as ev,request as X0}from"http";import{request as Q0}from"https";import{randomBytes as Yy}from"crypto";import{Readable as Z0}from"stream";te();Fr();var ns="x-devctl-request-id",eT="x-devctl-internal-token",Xy=100,Pu=new Set(["connection","keep-alive","proxy-authenticate","proxy-authorization","te","trailers","transfer-encoding","upgrade"]),tT=new Set(["gzip","deflate","br"]);class _u{cfg;tokens;logs;bus;detector;middleware;server;running=!1;addr="";upgradedSockets=new Set;recentRequests=[];constructor(e,t,r,n,o,i=[]){this.cfg=e,this.tokens=t,this.logs=r,this.bus=n,this.detector=o,this.middleware=i}address(){return this.addr||yn(this.cfg.listen)}setMiddleware(e){this.middleware=e}isRunning(){return this.running}stats(){let e=this.recentRequests.reduce((t,r)=>t+(r.status>=400||r.error?1:0),0);return{total:this.recentRequests.length,errors:e,recent:[...this.recentRequests].reverse()}}recordRequest(e){if(this.recentRequests.push(e),this.recentRequests.length>Xy)this.recentRequests.splice(0,this.recentRequests.length-Xy)}start(){let e=this.cfg.listen.host||"127.0.0.1";if(!kn(e))return Promise.reject(M(fn,`refusing to bind proxy to ${e}`));if(this.cfg.listen.port===0)return Promise.reject(M(fn,"proxy.listen.port is required when the proxy is enabled"));let t=this.cfg.listen.port;return new Promise((r,n)=>{this.server=ev((o,i)=>{this.serve(o,i)}),this.server.on("upgrade",(o,i,s)=>{this.serveUpgrade(o,i,s)}),this.server.on("error",(o)=>n(Re(fn,`unable to listen on ${e}:${t}`,o))),this.server.listen(t,e,()=>{this.running=!0,this.addr=`${e}:${t}`,this.bus?.publish(Se(Pm,"",{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(Se(_m,"",{})),t()})})}async serveUpgrade(e,t,r){let n=Date.now(),o=e.headers[ns]?.toString()||Yy(8).toString("hex"),i=e.method??"GET",s=e.url??"/",a=this.detector?this.detector.redactText(s):s,c=Zy(this.cfg.routes,e);if(!c){t.end(`HTTP/1.1 404 Not Found\r
|
|
630
643
|
Connection: close\r
|
|
631
644
|
Content-Length: 0\r
|
|
632
645
|
\r
|
|
633
|
-
`),this.recordRequest({timestamp:new Date().toISOString(),requestId:o,method:i,path:a,route:"",identity:"",status:404,durationMs:Date.now()-
|
|
634
|
-
`,
|
|
635
|
-
`}`).join("");if(t.write(`${
|
|
636
|
-
`),
|
|
646
|
+
`),this.recordRequest({timestamp:new Date().toISOString(),requestId:o,method:i,path:a,route:"",identity:"",status:404,durationMs:Date.now()-n});return}let l=to(c.auth),d=jo(l),u,f=!1,p=(g,y)=>{if(f)return;f=!0;let x=Date.now()-n;this.recordRequest({timestamp:new Date().toISOString(),requestId:o,method:i,path:a,route:c.name,identity:d,status:g,durationMs:x,error:y}),this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:g>=400||y?"ERROR":"INFO",message:`${i} ${s} route=${c.name} identity=${d} status=${g} duration=${x}ms upgrade=true${y?` error=${y}`:""}`,pid:0,request_id:o,identity:d}),this.bus?.publish(Se(nd,c.name,{status:g,request_id:o,duration:x,identity:d}))},m=()=>{t.destroy(),u?.destroy()};try{let g={};for(let[w,v]of Object.entries(e.headers)){let b=w.toLowerCase();if(Pu.has(b)&&b!=="connection"&&b!=="upgrade")continue;if(typeof v==="string")g[w]=v;else if(Array.isArray(v))g[w]=v.join(",")}let y=e.socket.remoteAddress??"",x=g.host??"",h=g["x-forwarded-for"];if(g["x-forwarded-for"]=h?`${h}, ${y}`:y,g["x-forwarded-host"]=x,g["x-forwarded-proto"]="http",delete g.host,g[ns]=o,this.middleware.length===0)await mc(c,g,this.tokens);for(let w of this.middleware)await w.apply({route:c,headers:g,tokens:this.tokens,req:e,method:i,path:s,upgrade:!0});let P=Qy(c.upstream.url,s),_=nT(P)(P,{method:i,headers:g});_.on("upgrade",(w,v,b)=>{u=v,this.upgradedSockets.add(t),this.upgradedSockets.add(v);let S=()=>{this.upgradedSockets.delete(t),this.upgradedSockets.delete(v)};t.once("close",()=>{S(),v.destroy()}),v.once("close",()=>{S(),t.destroy()}),t.once("error",m),v.once("error",m);let k=`HTTP/${w.httpVersion} ${w.statusCode??101} ${w.statusMessage??"Switching Protocols"}\r
|
|
647
|
+
`,L=w.rawHeaders.map((I,F)=>`${F%2===0?I+":":" "+I+`\r
|
|
648
|
+
`}`).join("");if(t.write(`${k}${L}\r
|
|
649
|
+
`),r.length>0)v.write(r);if(b.length>0)t.write(b);t.pipe(v).pipe(t),p(w.statusCode??101)}),_.on("response",(w)=>{w.resume();let v=w.statusCode??502;t.end(`HTTP/1.1 ${v} ${w.statusMessage??"Bad Gateway"}\r
|
|
637
650
|
Connection: close\r
|
|
638
651
|
Content-Length: 0\r
|
|
639
652
|
\r
|
|
640
|
-
`),
|
|
653
|
+
`),p(v,"upstream refused protocol upgrade")}),_.on("error",(w)=>{p(502,w.message),t.end(`HTTP/1.1 502 Bad Gateway\r
|
|
641
654
|
Connection: close\r
|
|
642
655
|
Content-Length: 0\r
|
|
643
656
|
\r
|
|
644
|
-
`)}),t.once("error",()=>
|
|
657
|
+
`)}),t.once("error",()=>_.destroy()),_.end()}catch(g){let y=g instanceof Error?g.message:"proxy upgrade error";p(502,y),t.end(`HTTP/1.1 502 Bad Gateway\r
|
|
645
658
|
Connection: close\r
|
|
646
659
|
Content-Length: 0\r
|
|
647
660
|
\r
|
|
648
|
-
`)}}async serve(e,t){let n=Date.now(),r=e.headers[Bi]?.toString()||hh(8).toString("hex");t.setHeader(Bi,r);let o=e.method??"GET",i=e.url??"/",s=this.detector?this.detector.redactText(i):i,a=xh(this.cfg.routes,e);if(!a){Ro(t,404,"no matching proxy route"),this.recordRequest({timestamp:new Date().toISOString(),requestId:r,method:o,path:s,route:"",identity:"",status:404,durationMs:Date.now()-n});return}let c=br(a.auth),l=po(c),d=0,f;try{let g={};for(let[y,B]of Object.entries(e.headers)){if(iu.has(y.toLowerCase()))continue;if(typeof B==="string")g[y]=B;else if(Array.isArray(B))g[y]=B.join(",")}let m=e.socket.remoteAddress??"",x=g.host??"",v=g["x-forwarded-for"];if(g["x-forwarded-for"]=v?`${v}, ${m}`:m,g["x-forwarded-host"]=x,g["x-forwarded-proto"]="http",delete g.host,g["accept-encoding"]="gzip, deflate, br",g[Bi]=r,this.middleware.length===0)await Ia(a,g,this.tokens);for(let y of this.middleware)await y.apply({route:a,headers:g,tokens:this.tokens});let w=yh(a.upstream.url,i),E=o!=="GET"&&o!=="HEAD"?e:void 0,k=await fetch(w,{method:o,headers:g,body:E,redirect:"manual",duplex:E?"half":void 0});t.statusCode=k.status,d=k.status;let j=(k.headers.get("content-encoding")??"").split(",").map((y)=>y.trim().toLowerCase()).filter((y)=>y!==""),V=j.length>0&&j.every((y)=>p0.has(y));k.headers.forEach((y,B)=>{let h=B.toLowerCase();if(iu.has(h))return;if(V&&(h==="content-encoding"||h==="content-length"))return;t.setHeader(B,this.detector?this.detector.redactText(y):y)}),await f0(k,t);let C=Date.now()-n;this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:k.status>=400?"WARN":"INFO",message:`${o} ${i} route=${a.name} identity=${l} status=${k.status} duration=${C}ms`,pid:0,request_id:r,identity:l}),this.bus?.publish(Le(Md,a.name,{status:k.status,request_id:r,duration:C,identity:l}))}catch(g){let m=g instanceof Error?g.message:"proxy error";f=m,d=502,this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:"ERROR",message:`${o} ${i} route=${a.name} identity=${l} error=${m}`,pid:0,request_id:r,identity:l}),Ro(t,502,"proxy error")}finally{this.recordRequest({timestamp:new Date().toISOString(),requestId:r,method:o,path:s,route:a.name,identity:l,status:d,durationMs:Date.now()-n,error:f})}}}async function Ia(e,t,n){let r=e.auth.type.toLowerCase();if(r===""||r==="none")return;if(!n)throw L($n,"token manager unavailable");let o=br(e.auth),i=await n.get(po(o),e.auth.audience,[]);t.authorization=`Bearer ${i.accessToken}`}async function f0(e,t){if(!e.body){t.end();return}let n=d0.fromWeb(e.body);await new Promise((r,o)=>{n.on("error",o),t.on("error",o),t.on("finish",r),n.pipe(t)})}function yh(e,t){let n=new URL(e),r=new URL(t||"/",n),o=new URL(n.href);if(o.pathname=g0(r.pathname),o.search=r.search,o.hash="",o.origin!==n.origin)throw L($n,"refusing to proxy to a different origin");return o}function g0(e){return(e.startsWith("/")?e:`/${e}`).replace(/^\/+/,"/")}function Ro(e,t,n){e.statusCode=t,e.setHeader("content-type","text/plain; charset=utf-8"),e.setHeader("x-content-type-options","nosniff"),e.end(n)}function xh(e,t){let n=(t.headers.host??"").split(":")[0]??"",r=t.url??"/";return e.find((o)=>{let i=o.match.host===""||o.match.host===n,s=o.match.path===""||r.startsWith(o.match.path);return i&&s})}class au{host;port;secret;tokens;server;constructor(e,t,n,r){this.host=e;this.port=t;this.secret=n;this.tokens=r}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(e==="0.0.0.0")return Promise.reject(L($n,"refusing to bind token endpoint to 0.0.0.0"));return new Promise((t,n)=>{this.server=bh((r,o)=>{this.serve(r,o)}),this.server.on("error",(r)=>n(fe($n,"token endpoint listen failed",r))),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(!m0(e.socket.remoteAddress)){Ro(t,403,"forbidden");return}if((e.headers[u0]??"")!==this.secret){Ro(t,401,"unauthorized");return}if(e.url?.startsWith("/token")!==!0){Ro(t,404,"not found");return}let n=new URL(e.url,"http://127.0.0.1"),r=n.searchParams.get("identity")??"user",o=n.searchParams.get("audience")??"";try{let i=await this.tokens.get(r,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{Ro(t,500,"token error")}}}function m0(e){if(!e)return!0;return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}Ai();wr();var wh=1;class Sh{tokenProviders=[];identityProviders=[];pluginIdentityProviders=[];environmentSources=[];healthChecks=[];logParsers=[];proxyMiddleware=[];loadErrors=[];registerBuiltins(){this.tokenProviders.push(..._r()),this.identityProviders.push(md(),hd()),this.logParsers.push(eu()),this.proxyMiddleware.push(b0())}register(e){x0(e),Lr(this.tokenProviders,e.tokenProviders),Lr(this.identityProviders,e.identityProviders),Lr(this.pluginIdentityProviders,e.identityProviders),Lr(this.environmentSources,e.environmentSources),Lr(this.healthChecks,e.healthChecks),Lr(this.logParsers,e.logParsers),Lr(this.proxyMiddleware,e.proxyMiddleware)}}async function kh(e,t=process.cwd()){let n=new Sh;n.registerBuiltins();for(let r of e){if(r.trim()==="")continue;try{let o=r.startsWith("file:")?r:v0(r)?r:y0(t,r),s=await import(o.startsWith("file:")?o:h0(o).href);if(s.sdkVersion!==wh)throw Error(`plugin SDK version ${String(s.sdkVersion??"missing")} is incompatible; expected ${wh}`);n.register(s)}catch(o){n.loadErrors.push({path:r,message:o instanceof Error?o.message:String(o)})}}return n}function x0(e){if(!e||typeof e!=="object")throw Error("plugin module must export an object");Po("tokenProviders",e.tokenProviders,["fetch"]),Po("identityProviders",e.identityProviders,["accepts","resolve"]),Po("environmentSources",e.environmentSources,["load"]),Po("healthChecks",e.healthChecks,["check"]),Po("logParsers",e.logParsers,["parse"]),Po("proxyMiddleware",e.proxyMiddleware,["apply"])}function Po(e,t,n){if(t===void 0)return;if(!Array.isArray(t))throw Error(`${e} must be an array`);for(let[r,o]of t.entries()){if(!o||typeof o!=="object"||typeof o.name!=="string"||o.name==="")throw Error(`${e}[${r}] must have a name`);for(let i of n)if(typeof o[i]!=="function")throw Error(`${e}[${r}].${i} must be a function`)}}function b0(){return{name:"identity_inject",apply:async(e)=>{await Ia(e.route,e.headers,e.tokens)}}}function Lr(e,t){if(!t)return;e.push(...t)}Re();var{spawn:Fh}=globalThis.Bun;ze();var{spawn:w0}=globalThis.Bun;async function Ch(e,t){if(e<=0)return;try{process.kill(-e,t);return}catch{try{process.kill(e,t)}catch{return}}}async function _h(e){if(!Tt(e))return;let t=await Wi(["ps","-p",String(e),"-o","command="]),n=Date.now(),r=S0(await Wi(["ps","-p",String(e),"-o","etime="])),o=await k0(e);return{pid:e,command:t.trim(),cwd:o,startTime:r===void 0?void 0:new Date(n-r).toISOString()}}function S0(e){let t=e.trim();if(t==="")return;let n=t.indexOf("-"),r=n>=0?t.slice(0,n):"0",i=(n>=0?t.slice(n+1):t).split(":");if(i.length!==2&&i.length!==3)return;let s=Number(r),a=i.length===3?Number(i[0]):0,c=Number(i.length===3?i[1]:i[0]),l=Number(i.at(-1));if(!Number.isInteger(s)||s<0||!Number.isInteger(a)||a<0||a>23||!Number.isInteger(c)||c<0||c>59||!Number.isInteger(l)||l<0||l>59)return;return(((s*24+a)*60+c)*60+l)*1000}async function k0(e){let n=(await Wi(["lsof","-a","-p",String(e),"-d","cwd","-Fn"])).split(`
|
|
649
|
-
`).find((i)=>i.startsWith("n"));if(n&&n.length>1)return n.slice(1).trim();let r=await Wi(["pwdx",String(e)]),o=r.indexOf(":");if(o>=0)return r.slice(o+1).trim();return""}async function Wi(e){try{let t=w0({cmd:e,stdout:"pipe",stderr:"ignore"}),n=t.stdout?await new Response(t.stdout).text():"";return await t.exited,n}catch{return""}}async function Eh(e){let t=new Map;if(e.length===0)return t;let n=await Wi(["ps","-o","pid=,pcpu=,rss=","-p",e.join(",")]);for(let r of n.split(`
|
|
650
|
-
`)){let o=r.trim();if(o==="")continue;let[i,s,a]=o.split(/\s+/),c=Number(i),l=Number(s),d=Number(a);if(Number.isFinite(c)&&Number.isFinite(l)&&Number.isFinite(d))t.set(c,{pid:c,cpuPercent:l,memoryKB:d})}return t}function Rh(e,t){if(e.length===0||t==="")return!1;let n=e.join(" ");if(t.includes(n))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)}ze();var{spawn:Ph}=globalThis.Bun;var C0=1024;async function Th(e,t){if(e<=0)return;try{await Ph({cmd:["taskkill","/PID",String(e),"/T","/F"],stdout:"ignore",stderr:"ignore"}).exited}catch{return}}async function Ah(e){let t=_0(Ml(e),e);if(t)return t;if(!Tt(e))return;let n=await cu(["powershell","-NoProfile","-Command",`Get-CimInstance Win32_Process -Filter "ProcessId=${e}" | Select-Object CommandLine,ExecutablePath,CreationDate | ConvertTo-Json -Compress`]),r=R0(n);if(r&&r.command!=="")return{pid:e,command:r.command,cwd:r.cwd,startTime:r.startTime};let o=await cu(["powershell","-NoProfile","-Command",`Get-Process -Id ${e} -ErrorAction SilentlyContinue | Select-Object Path,StartTime | ConvertTo-Json -Compress`]),i=E0(o);if(!i&&!r)return;return{pid:e,command:r?.command||i?.command||"",cwd:r?.cwd||i?.cwd||"",startTime:r?.startTime||i?.startTime}}function _0(e,t){let n=String(t);for(let r of e.split(/\r?\n/)){if(!r.includes(n))continue;let i=r.split(",").map((s)=>s.replace(/^"|"$/g,"").trim())[0]??"";if(i===""||i.toLowerCase().includes("info:"))continue;return{pid:t,command:i,cwd:""}}return}function E0(e){let t=e.trim();if(t==="")return;try{let n=JSON.parse(t),r=(n.Path||"").trim();if(r==="")return;return{command:r,cwd:Na(r),startTime:n.StartTime}}catch{let n=Fa(t,"Path");if(n==="")return;return{command:n,cwd:Na(n)}}}function R0(e){let t=e.trim();if(t==="")return;try{let n=JSON.parse(t),r=(n.CommandLine||n.ExecutablePath||"").trim(),o=(n.ExecutablePath||"").trim(),i=Na(o);return{command:r,cwd:i,startTime:n.CreationDate||void 0}}catch{return{command:Fa(t,"CommandLine")||Fa(t,"ExecutablePath"),cwd:Na(Fa(t,"ExecutablePath"))}}}async function Lh(e){let t=new Map;if(e.length===0)return t;let n=e.filter((o)=>o>0).join(",");if(n==="")return t;let r=await cu(["powershell","-NoProfile","-Command",`${n}.Split(',') | ForEach-Object { Get-Process -Id $_ -ErrorAction SilentlyContinue } | Select-Object Id,CPU,WorkingSet64 | ConvertTo-Json -Compress`]);return P0(r)}function P0(e){let t=new Map,n=e.trim();if(n==="")return t;try{let r=JSON.parse(n),o=Array.isArray(r)?r:[r];for(let i of o){if(!i||typeof i!=="object")continue;let s=i,a=Number(s.Id),c=Number(s.CPU??0),l=Number(s.WorkingSet64??0)/C0;if(Number.isFinite(a)&&a>0&&Number.isFinite(c)&&Number.isFinite(l))t.set(a,{pid:a,cpuPercent:c,memoryKB:l})}}catch{return t}return t}function Na(e){if(e==="")return"";let t=e.replace(/\//g,"\\"),n=t.lastIndexOf("\\");return n>0?t.slice(0,n):""}function Fa(e,t){let n=`${t}=`,r=e.split(/\r?\n/).find((o)=>o.startsWith(n));return r?r.slice(n.length).trim():""}async function cu(e){try{let t=Ph({cmd:e,stdout:"pipe",stderr:"ignore"}),n=t.stdout?await new Response(t.stdout).text():"";return await t.exited,n}catch{return""}}ze();Re();var{spawn:lu}=globalThis.Bun;async function Oh(e){await L0(e.runtime,e.containerName);let t=T0(e),n=await To(e.runtime,t,e.env);if(n.code!==0||n.stdout.trim()==="")throw L(Ne,`failed to start ${e.containerName}: ${n.stderr.trim()||"container runtime returned no id"}`);let r=n.stdout.trim().split(/\s+/)[0]??"";return Ih(e.runtime,e.containerName,r,e.onLine,e.onExit)}function T0(e){let t=["run","--detach","--name",e.containerName,"--label","devctl.managed=true"];for(let[n,r]of Object.entries(e.ports)){let o=e.targetPorts[n]??r;t.push("--publish",`127.0.0.1:${r}:${o}`)}for(let n of Object.keys(e.env).sort())t.push("--env",n);for(let n of e.volumes)t.push("--volume",n);return t.push(e.image,...e.command),t}var A0=new Set(["PATH","HOME","HOSTNAME","PWD","OLDPWD","SHLVL","_","TMPDIR"]);function Mh(e){return Object.fromEntries(Object.entries(e).filter(([t])=>!A0.has(t)))}async function $h(e,t,n,r){let o=await To(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 Ih(e,t,i,n,r)}function Ih(e,t,n,r,o){let i=!0,s=lu({cmd:[e,"logs","--follow",n],stdout:"pipe",stderr:"pipe",stdin:"ignore"});Dh(s.stdout,"stdout",r),Dh(s.stderr,"stderr",r);let a=lu({cmd:[e,"wait",n],stdout:"pipe",stderr:"pipe",stdin:"ignore"}),c=Promise.all([new Response(a.stdout).text(),a.exited]).then(async([l,d])=>{i=!1,s.kill();let f=Number.parseInt(l.trim(),10),g=Number.isFinite(f)?f:d??1,m=g===0?void 0:Error(`container exited with code ${g}`);return await To(e,["rm","--force",n],process.env),o?.(g,m),{code:g,err:m}});return{id:n,runtime:e,containerName:t,done:c,running:()=>i,stop:async(l)=>{let d=Math.max(1,Math.ceil(l/1000));await To(e,["stop","--time",String(d),n],process.env),await c}}}async function L0(e,t){let n=await To(e,["inspect","--format","{{.State.Running}}",t],process.env);if(n.code===0&&n.stdout.trim()==="false")await To(e,["rm","--force",t],process.env)}async function To(e,t,n){try{let r=lu({cmd:[e,...t],env:{...process.env,...n},stdout:"pipe",stderr:"pipe",stdin:"ignore"}),[o,i,s]=await Promise.all([new Response(r.stdout).text(),new Response(r.stderr).text(),r.exited]);return{code:s??1,stdout:o,stderr:i}}catch(r){throw fe(Ne,`unable to run ${e}`,r)}}async function Dh(e,t,n){if(!e||typeof e==="number"||!n)return;let r=e.getReader(),o=new TextDecoder,i="";for(;;){let s=await r.read();if(s.done)break;i+=o.decode(s.value,{stream:!0});let a=i.split(`
|
|
651
|
-
`);i=a.pop()??"";for(let c of a)n(t,c.replace(/\r$/,""))}if(i!=="")n(t,i)}var D0=1e4,O0=2000,M0=500;class du{running=new Map;async start(e){let t=this.running.get(e.name);if(t&&Dr(t))return t;if(this.running.delete(e.name),e.args.length===0)throw L(Ne,"empty command");let n=e.shell?jh(e.args):e.args,r;try{r=Fh({cmd:n,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 fe(Ne,`failed to start ${e.name}`,i)}let o={name:e.name,pid:r.pid??0,startTime:new Date,workDir:e.workDir,args:[...e.args],proc:r,done:Promise.resolve({code:0})};return Ha(r.stdout,"stdout",e.onLine),Ha(r.stderr,"stderr",e.onLine),o.done=r.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 L(Ne,"empty command");let t;try{t=Fh({cmd:e.shell?jh(e.args):e.args,cwd:e.workDir||void 0,env:e.env,stdout:"pipe",stderr:"pipe",stdin:"ignore"})}catch(a){throw fe(Ne,`failed to run ${e.name}`,a)}let n="",r="",o=(a,c)=>{if(a==="stdout")n+=`${c}
|
|
652
|
-
`;else r+=`${c}
|
|
653
|
-
`;e.onLine?.(a,c)},i=[Ha(t.stdout,"stdout",o),Ha(t.stderr,"stderr",o)],s=await t.exited;return await Promise.all(i),{code:typeof s==="number"?s:0,stdout:n,stderr:r}}async startContainer(e){let t=this.running.get(e.name);if(t&&Dr(t))return t;let n=await Oh(e),r={name:e.name,pid:0,startTime:new Date,workDir:e.workDir,args:[...e.command],done:n.done,container:n};return n.done.finally(()=>{if(this.running.get(e.name)===r)this.running.delete(e.name)}),this.running.set(e.name,r),r}async adoptContainer(e){let t=this.running.get(e.name);if(t&&Dr(t))return t;let n=await $h(e.runtime,e.containerName,e.onLine,e.onExit);if(!n)return;let r={name:e.name,pid:0,startTime:new Date,workDir:e.workDir,args:[],done:n.done,container:n};return n.done.finally(()=>{if(this.running.get(e.name)===r)this.running.delete(e.name)}),this.running.set(e.name,r),r}adopt(e){let t=this.running.get(e.name);if(t&&Dr(t))return t;if(!Tt(e.pid))throw L(Ne,`cannot adopt ${e.name}: pid ${e.pid} is not running`);let n={name:e.name,pid:e.pid,startTime:e.startTime,workDir:e.workDir,args:[...e.args],done:Promise.resolve({code:0})};return n.done=I0(e.pid).then((r)=>{if(this.running.get(e.name)===n)this.running.delete(e.name);if(e.onExit)e.onExit(r,r===0?void 0:Error(`exited with code ${r}`));return{code:r}}),this.running.set(e.name,n),n}async stop(e,t){let n=this.running.get(e);if(!n)return;let r=t>0?t:D0;if(n.container){await n.container.stop(r),this.running.delete(e);return}if(await Nh(n.pid,"SIGTERM"),!await Wh(n.done,r)){if(await Nh(n.pid,"SIGKILL"),!await Wh(n.done,O0))throw L(Ne,`process ${e} did not exit after SIGKILL`)}this.running.delete(e)}get(e){return this.running.get(e)}all(){return[...this.running.values()]}}function Dr(e){if(e.container)return e.container.running();if(e.proc)return e.proc.exitCode===null&&!e.proc.killed;return Tt(e.pid)}async function Nh(e,t){if(process.platform==="win32"){await Th(e,t);return}await Ch(e,t)}async function ja(e){if(process.platform==="win32")return Ah(e);return _h(e)}async function Gh(e){if(process.platform==="win32")return Lh(e);return Eh(e)}var $0=2000;function Ba(e,t){if(e.workDir!==""&&t.cwd!==""&&Bh(e.workDir)!==Bh(t.cwd))return!1;if(!Rh(e.args,t.command))return!1;let n=Hh(e.startTime),r=Hh(t.startTime);if(n!==void 0&&r!==void 0)return Math.abs(n-r)<=$0;return!0}function Hh(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 jh(e){if(process.platform==="win32")return["cmd.exe","/c",e.join(" ")];return["/bin/sh","-c",e.join(" ")]}function Bh(e){return e.replace(/\\/g,"/").replace(/\/+$/,"")}async function I0(e){while(Tt(e))await F0(M0);return 0}async function Ha(e,t,n){if(!e||typeof e==="number"||!n)return;let r=e.getReader(),o=new TextDecoder,i="";for(;;){let{value:s,done:a}=await r.read();if(a){if(i!=="")n(t,i);return}i+=o.decode(s,{stream:!0});let c=i.split(`
|
|
654
|
-
`);i=c.pop()??"";for(let l of c)n(t,l.replace(/\r$/,""))}}async function Wh(e,t){return Promise.race([e.then(()=>!0),new Promise((n)=>{setTimeout(()=>n(!1),t)})])}function F0(e){return new Promise((t)=>{setTimeout(t,e)})}Re();Gi();import{createServer as J0}from"http";var z0="2025-03-26",iv="2.0",tv=-32700,nv=-32600,Y0=-32601,rv=-32602,X0=-32603,Q0=new Set(["127.0.0.1","localhost","::1"]);function Z0(e){return Q0.has(e)}class fu{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(!Z0(this.opts.host))return Promise.reject(L(Je,`refusing to bind MCP to ${this.opts.host}`));return new Promise((e,t)=>{this.server=J0((n,r)=>{this.serve(n,r)}),this.server.on("error",(n)=>t(fe(Je,`unable to listen on ${this.opts.host}:${this.opts.port}`,n))),this.server.listen(this.opts.port,this.opts.host,()=>{let n=this.server?.address();this.boundPort=typeof n==="object"&&n?n.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((n)=>{e.close(()=>{if(this.running=!1,this.addr="",this.boundPort=0,this.server=void 0,t)this.emit("INFO","stopped");n()})})}async serve(e,t){if(e.method==="OPTIONS"){t.writeHead(204,qi()),t.end();return}if(!this.authorized(e)){this.emit("WARN",`rejected unauthorized request from ${ov(e)}`),Lo(t,401,{error:"unauthorized"});return}if(tE(e)!=="/mcp"){Lo(t,404,{error:"not found"});return}if(e.method==="GET"||e.method==="DELETE"){t.writeHead(405,{Allow:"POST, OPTIONS",...qi()}),t.end();return}if(e.method!=="POST"){t.writeHead(405,{Allow:"POST, OPTIONS",...qi()}),t.end();return}let r;try{r=await nE(e)}catch(a){Lo(t,400,Ui(null,tv,a instanceof Error?a.message:"invalid body"));return}let o;try{o=JSON.parse(r)}catch{Lo(t,400,Ui(null,tv,"parse error"));return}let i=ov(e);if(Array.isArray(o)){let a=[];for(let c of o){let l=await this.dispatch(c,i);if(l!==void 0)a.push(l)}Lo(t,200,a);return}let s=await this.dispatch(o,i);if(s===void 0){t.writeHead(202,qi()),t.end();return}Lo(t,200,s)}authorized(e){if(this.opts.token==="")return!0;return(e.headers.authorization??"")===`Bearer ${this.opts.token}`}async dispatch(e,t){if(!Va(e))return Ui(null,nv,"invalid request");let n=e,r=n.id??null,o=n.id===void 0;if(n.method===void 0||n.method==="")return o?void 0:Ui(r,nv,"missing method");try{let i=await this.handleMethod(n.method,Va(n.params)?n.params:{},t);if(o)return;return{jsonrpc:iv,id:r,result:i}}catch(i){if(o)return;let s=i instanceof Ki?i.code:X0,a=i instanceof Error?i.message:"internal error";return this.emit("WARN",`rpc error method=${n.method} addr=${t}: ${a}`),Ui(r,s,a)}}async handleMethod(e,t,n){switch(e){case"initialize":{let r=eE(t);return this.emit("INFO",`client connected addr=${n}${r?` (${r})`:""}`),{protocolVersion:z0,capabilities:{tools:{},resources:{}},serverInfo:{name:"devctl",version:pt}}}case"notifications/initialized":case"ping":return{};case"tools/list":return{tools:Vh(this.disabled()).map((r)=>({name:r.name,description:r.description,inputSchema:r.inputSchema}))};case"tools/call":return this.callTool(t);case"resources/list":return{resources:uu.map((r)=>({uri:r,name:r.replace("devctl://",""),mimeType:"application/json"}))};case"resources/read":return this.readResource(t);default:throw new Ki(Y0,`method not found: ${e}`)}}async callTool(e){let t=typeof e.name==="string"?e.name:"";if(t==="")throw new Ki(rv,"tool name is required");if(Ka(t)&&!qn(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 n=Va(e.arguments)?e.arguments:{},r=Date.now();try{let o=await Qh(this.opts.hostApi,t,n);return this.emit("INFO",`tool call name=${t} duration=${Date.now()-r}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()-r}ms: ${i}`),{content:[{type:"text",text:i}],isError:!0}}}async readResource(e){let t=typeof e.uri==="string"?e.uri:"";if(!Zh(t))throw new Ki(rv,`unknown resource ${t}`);let n=await ev(this.opts.hostApi,t);return this.emit("INFO",`resource read uri=${t}`),{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}}function eE(e){let t=e.clientInfo;if(!Va(t))return"";let n=typeof t.name==="string"?t.name:"",r=typeof t.version==="string"?t.version:"";if(n==="")return"";return r===""?n:`${n} ${r}`}function ov(e){return e.socket.remoteAddress??"unknown"}class Ki extends Error{code;constructor(e,t){super(t);this.code=e}}function qi(){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 Lo(e,t,n){let r=JSON.stringify(n);e.writeHead(t,{"Content-Type":"application/json","Content-Length":Buffer.byteLength(r),...qi()}),e.end(r)}function Ui(e,t,n){return{jsonrpc:iv,id:e,error:{code:t,message:n}}}function tE(e){let t=e.url??"/",n=t.indexOf("?");return n>=0?t.slice(0,n):t}function nE(e){return new Promise((t,n)=>{let r=[];e.on("data",(o)=>{r.push(o)}),e.on("end",()=>{t(Buffer.concat(r).toString("utf8"))}),e.on("error",n)})}function Va(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}Gi();Ja();Zt();Oi();Ao();Rr();ze();Ai();var RE=4000,PE=100,mv=30000,hv=3,TE=2,AE=2000,LE=200,DE=3,OE=10,ME=3000;class yu{cfg;sessionID;internalTok;bus;logs;procs;tokens;detector;proxy;proxySuppressed=!1;mcp;mcpToken;tokenEP;profile="";clientEnv=new Map;serviceProfile=new Map;serviceProfileEnv=new Map;generation=new Map;runtimes=new Map;ports=new Map;healthTimers=new Map;restarts=new Map;lock;server;shuttingDown=!1;detached=!1;identityCache=vv();serviceAccountStatus=new Map;detectGoogleFn;inspectProcessFn;processAliveFn;acquireLockFn;socketExistsFn;unlinkSocketFn;registry;restartRequired=[];processMeta=new Map;credentialEntries=[];boundTokenURL="";configWatcher;watchTimer;unhealthyStreak=new Map;healthyStreak=new Map;restartTimers=new Map;setupMode;mcpDisabledTools=[];profileEnv={};resourceTimer;constructor(e,t){this.cfg=e,this.sessionID=Dl(),this.internalTok=$l(),this.mcpToken=Uf(e.repoRoot),this.bus=new $d(2048),this.detectGoogleFn=t?.detectGoogle??Ot,this.inspectProcessFn=t?.inspectProcess??ja,this.processAliveFn=t?.processAlive??Tt,this.acquireLockFn=t?.acquireLock??Gf,this.socketExistsFn=t?.socketExists??hu,this.unlinkSocketFn=t?.unlinkSocket??wE,this.detector=new Vt(e.secrets.extra_markers,e.secrets.extra_patterns),this.logs=new Oa(e.logs.max_memory_events,this.bus,this.detector,e.logs.persistence.enabled,e.logs.persistence.directory,this.sessionID,e.logs.persistence.retention_days,e.logs.persistence.max_session_logs),this.procs=t?.procs??new du,this.tokens=t?.tokens??new wo(e.auth.refresh_threshold_seconds*1000,_r(),this.bus),this.bus.subscribe((n)=>{let r=n.payload??{},o=n.type===bo?`token refreshed identity=${String(r.identity??"")}`:n.type===Cr?`token refresh failed identity=${String(r.identity??"")} audience=${String(r.audience??"")}: ${String(r.error??"")}`:`authentication changed user=${String(r.user??"")}`;if(this.logs.append({timestamp:new Date().toISOString(),service:"auth",source:"auth",level:n.type===Cr?"WARN":"INFO",message:o,pid:0}),n.type===bo||n.type===Cr)this.syncCredentialEntries()},[bo,Cr,Od]),this.setupMode=!hu(e.configPath),this.identityCache=vv(e);for(let n of Object.keys(e.services))this.runtimes.set(n,Sa(n))}async run(){let e=Hs(this.cfg.repoRoot);this.lock=this.acquireLockFn(this.cfg.repoRoot,e),this.removeStaleSocket(e),this.registry=await kh(this.cfg.plugins.map((n)=>n.path),this.cfg.repoRoot);for(let n of this.registry.loadErrors)this.log("devctl","ERROR",`plugin ${n.path} skipped: ${n.message}`);this.applyRegistry(),this.checkPluginHealthTypes(),this.checkPluginIdentityTypes(),this.checkPluginEnvironmentSources(),await this.recoverSession(),this.watchConfig(),this.persistState(),this.log("devctl","INFO",`supervisor started session=${this.sessionID}`),this.refreshIdentity(),this.resourceTimer=setInterval(()=>void this.pollResourceUsage(),ME);let t=Qt(this.cfg.repoRoot);if(this.setMcpDisabledTools(t.mcp_disabled_tools??[]),t.mcp_enabled)await this.startMcp(t.mcp_port).catch((n)=>this.log("devctl","ERROR",O(n)));this.removeStaleSocket(e),await new Promise((n,r)=>{this.server=bE((o)=>{this.handleConn(o)}),this.server.on("error",r),this.server.listen(e,()=>n())})}removeStaleSocket(e){if(process.platform==="win32")return;if(this.socketExistsFn(e))try{this.unlinkSocketFn(e)}catch{this.log("devctl","WARN","unable to remove stale socket")}}handleConn(e){let t="",n=2000,r=[],o=!1,i=()=>{while(r.length>0){let c=r[0],l=e.write(`${JSON.stringify(c)}
|
|
655
|
-
`);if(r.shift(),!l){o=!0,e.once("drain",()=>{o=!1,i()});return}}},s=(c)=>{if(c.id===void 0&&c.event!==void 0&&r.length>=n){let d=r.findIndex((f)=>f.id===void 0&&f.event!==void 0);if(d>=0)r.splice(d,1)}if(r.push(c),!o)i()},a=this.bus.subscribe((c)=>s({event:c}));e.on("error",(c)=>{this.log("devctl","WARN",`client connection error: ${O(c)}`)}),e.on("data",(c)=>{t+=c.toString("utf8");let l=t.split(`
|
|
656
|
-
`);t=l.pop()??"";for(let d of l){if(d.trim()==="")continue;this.dispatchLine(d,s)}}),e.on("close",()=>a())}async dispatchLine(e,t){let n;try{n=JSON.parse(e)}catch{t({error:"invalid json"});return}try{let r=await this.dispatch(n.method??"",n.params);t({id:n.id,result:r})}catch(r){let o=Ff(r);t({id:n.id,error:o.error,kind:o.kind,hint:o.hint,service:o.service})}}async dispatch(e,t){let n=yv(t)?t:{};switch(e){case"ping":return{session:this.sessionID,version:pt,protocol:ki};case"start":return this.start({services:Ir(n.services),profile:typeof n.profile==="string"?n.profile:"",detach:n.detach===!0,client_env:nc(n.client_env)});case"stop":return await this.stop(Ir(n.services)),null;case"restart":return await this.restart(Ir(n.services),{cascade:n.cascade===!0,clientEnv:nc(n.client_env)}),null;case"run_task":return this.runTask(typeof n.name==="string"?n.name:"",nc(n.client_env)??{});case"exec":return this.execService(typeof n.service==="string"?n.service:"",Ir(n.command),nc(n.client_env)??{},n.print_env===!0);case"auth_refresh":return await this.refreshIdentity({probeServiceAccounts:!0}),this.snapshot().identity;case"status":return this.snapshot();case"logs":return this.queryLogs({services:Ir(n.services),level:typeof n.level==="string"?n.level:"",search:typeof n.search==="string"?n.search:"",regex:n.regex===!0,source:typeof n.source==="string"?n.source:"",since:typeof n.since==="string"?n.since:"",until:typeof n.until==="string"?n.until:"",export:typeof n.export==="string"?n.export:""});case"logs_page":return this.queryLogsPage({services:Ir(n.services),level:typeof n.level==="string"?n.level:"",search:typeof n.search==="string"?n.search:"",regex:n.regex===!0,source:typeof n.source==="string"?n.source:"",since:typeof n.since==="string"?n.since:"",until:typeof n.until==="string"?n.until:"",cursor:typeof n.cursor==="string"?n.cursor:void 0,direction:n.direction==="forward"?"forward":"backward",limit:typeof n.limit==="number"?n.limit:void 0});case"logs_stats":return this.queryLogsFacets({services:Ir(n.services),level:typeof n.level==="string"?n.level:"",search:typeof n.search==="string"?n.search:"",regex:n.regex===!0,source:typeof n.source==="string"?n.source:"",since:typeof n.since==="string"?n.since:"",until:typeof n.until==="string"?n.until:""});case"proxy_start":return this.proxySuppressed=!1,await this.startProxy(),null;case"proxy_stop":return this.proxySuppressed=!0,await this.stopProxy(),null;case"mcp_start":{let o=typeof n.port==="number"?n.port:void 0;return await this.startMcp(o??Qt(this.cfg.repoRoot).mcp_port),null}case"mcp_stop":return await this.stopMcp(),null;case"mcp_set_tools":{let o=Array.isArray(n.disabled)?n.disabled.filter((i)=>typeof i==="string"):[];return this.setMcpDisabledTools(o),{disabled_tools:[...this.mcpDisabledTools]}}case"reload":return this.reload();case"config_snapshot":return this.cfg;case"auth_invalidate":return this.tokens.invalidate(),null;case"shutdown":let r=typeof n.stop_services==="boolean"?n.stop_services:Us(this.cfg.shutdown);return setTimeout(()=>{this.shutdown(r)},50),null;default:throw L(Je,`unknown method ${e}`)}}isDetached(){return this.detached}async start(e){if(e.detach===!0)this.detached=!0;let t=Ca(this.cfg,{services:e.services,profile:e.profile,activeProfile:this.profile});if(t.profile)this.profile=t.profile;if(this.profileEnv=t.env,e.client_env)for(let s of t.services)this.clientEnv.set(s,e.client_env);for(let s of t.services)this.serviceProfile.set(s,t.profile),this.serviceProfileEnv.set(s,t.env);if(e.auto!==!0)for(let s of t.services)this.resetRestartCount(s);let n=$i(this.cfg,t.services,t.profile),r=await this.detectGoogleFn(this.cfg.google.project_id);n.blockers=gm(this.cfg,n.waves.flat(),r.adcAvailable);let o=new Set(n.blockers.map((s)=>s.name));for(let s of n.blockers)await this.fail(s.name,L(Ne,s.message));if(this.cfg.proxy.enabled&&!this.proxySuppressed)await this.startProxy().catch((s)=>this.log("devctl","ERROR",O(s)));let i=[];for(let s of n.waves.flat()){if(o.has(s)||await this.claimIfAlreadyUp(s))continue;i.push(s)}if(i.length>0)try{let s=await km(this.cfg,i,Object.fromEntries(this.ports));for(let[a,c]of Object.entries(s)){this.ports.set(a,c);let l=Object.entries(c).map(([d,f])=>`${d}=${f}`).join(", ");this.log(a,"INFO",`assigned ports: ${l||"none"}`)}}catch(s){if(s instanceof Me&&s.service!=="")await this.fail(s.service,s);else this.log("devctl","ERROR",O(s));throw s}for(let s of n.waves){let a=s.filter((c)=>i.includes(c));if(a.length>0){let c=await Promise.allSettled(a.map((d)=>this.startOne(d,t.profile,t.env,e.auto!==!0))),l=!1;for(let d of c)if(d.status==="rejected")l=!0,this.log("devctl","ERROR",O(d.reason));if(l)throw L(Ne,"one or more services failed to start")}try{await this.awaitWaveHealth(s,n.waves.flat())}catch(c){throw this.log("devctl","ERROR",O(c)),c}}return this.persistState(),n}async runTask(e,t){let n=this.cfg.tasks[e];if(!n)throw L(Je,`unknown task ${e}`);if(n.dependencies.length>0)await this.start({services:n.dependencies,client_env:t});let r={...Nn(),command:n.command,shell:n.shell,working_dir:n.working_dir,dependencies:n.dependencies,environment:n.environment},o=await ra(this.cfg.repoRoot,{service:`task:${e}`,profile:this.profile,serviceCfg:r,profileEnv:this.profileEnv,assignedPorts:{},runtime:oa(`task:${e}`,"127.0.0.1",{},"",this.cfg.project.name),cfg:this.cfg,clientEnv:t,fetchSecret:na(async()=>(await this.tokens.get("user","",[])).accessToken),pluginSources:this.registry?.environmentSources}),i=n.working_dir&&!vu(n.working_dir)?tc(this.cfg.repoRoot,n.working_dir):n.working_dir,s=await this.runTransient(`task:${e}`,n.command,n.shell,i,Si(o));return{task:e,...s}}async execService(e,t,n,r=!1){let o=this.cfg.services[e];if(!o)throw L(fi,`unknown service ${e}`);let i=this.serviceProfile.get(e)??this.profile,s=this.serviceProfileEnv.get(e)??this.profileEnv,{env:a,workDir:c}=await this.resolveServiceExecution(e,o,i,s,n,!o.container);if(r)return{service:e,code:0,stdout:"",stderr:"",environment:a};if(t.length===0)throw L(Je,"exec command is required");let l=await this.runTransient(`${e}:exec`,{args:t,shell:!1},!1,c,a);return{service:e,...l}}async resolveServiceExecution(e,t,n,r,o,i=!0){let s=this.ports.get(e)??Object.fromEntries(t.ports.filter((f)=>!f.auto).map((f)=>[f.name,f.value])),a=this.proxy?.isRunning()?`http://${this.proxy.address()}`:this.cfg.proxy.enabled?`http://${gr(this.cfg.proxy.listen)}`:"",c=oa(e,"127.0.0.1",s,a,this.cfg.project.name);if(!t.container){if(c.DEVCTL_INTERNAL_TOKEN=this.internalTok,this.cfg.proxy.token_endpoint.enabled)c.DEVCTL_TOKEN_URL=this.boundTokenURL||`http://127.0.0.1:${this.tokenEP?.listenPort()||this.cfg.proxy.token_endpoint.port}/token`}let l=await ra(this.cfg.repoRoot,{service:e,profile:n,serviceCfg:t,profileEnv:r,assignedPorts:s,runtime:c,cfg:this.cfg,fetchSecret:na(async()=>(await this.tokens.get("user","",[])).accessToken),pluginSources:this.registry?.environmentSources,clientEnv:o,includeProcess:i}),d=t.working_dir&&!vu(t.working_dir)?tc(this.cfg.repoRoot,t.working_dir):t.working_dir;return{env:Si(l),workDir:d}}async runTransient(e,t,n,r,o){if(io(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:n||t.shell,workDir:r,env:o,graceMs:so(this.cfg.shutdown)*1000,onLine:(s,a)=>this.logs.append({timestamp:new Date().toISOString(),service:e,source:s,stream:s,level:"",message:a,pid:0})});if(i.code!==0)throw L(Ne,`${e} exited with code ${i.code}`);return i}serviceIsActive(e){let t=this.procs.get(e);if(t&&Dr(t))return!0;let n=this.runtimes.get(e);if(!n)return!1;if(n.health===_t||n.state===Er)return!0;return n.state===Hd||n.state===jt}serviceWorkDir(e){if(e.working_dir!==""&&!vu(e.working_dir))return tc(this.cfg.repoRoot,e.working_dir);return e.working_dir}async claimIfAlreadyUp(e){let t=this.cfg.services[e];if(this.serviceIsActive(e)){if(t&&!this.ports.has(e)){let s=await da(t);if(s)this.ports.set(e,s)}return!0}if(!t)return!1;if(t.container){let s=this.bumpGeneration(e),a=t.container.runtime==="podman"?"podman":"docker",c=this.serviceWorkDir(t),l=await this.procs.adoptContainer({name:e,runtime:a,containerName:`devctl-${vn(this.cfg.repoRoot)}-${e.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,workDir:c,onLine:(g,m)=>this.logs.append({timestamp:new Date().toISOString(),service:e,source:g,stream:g,level:"",message:m,pid:0}),onExit:(g,m)=>this.onExit(e,s,g,m)});if(!l)return!1;let d=this.ports.get(e)??Object.fromEntries(t.ports.filter((g)=>!g.auto).map((g)=>[g.name,g.value]));this.ports.set(e,d),this.processMeta.set(e,{command:[...t.command.args],cwd:c,startTime:l.startTime}),this.setState(e,jt,Ct,0,"");let f=await this.resolveAdoptedHealthEnv(e,t,d);return this.startHealth(e,t,0,d,c,f,s),this.persistState(),this.log(e,"INFO",`claimed running ${a} container ${l.container?.id??""}`),!0}let n=await da(t);if(!n)return!1;let r=Object.values(n)[0],i=(r===void 0?void 0:await yo(r))?.pid??0;if(i>0&&i!==process.pid){let s=pr(this.cfg.repoRoot)?.processes.find((l)=>l.name===e&&l.pid===i);if(!s)return this.log(e,"WARN",`port ${r} is held by pid ${i} with no persisted record for ${e}; not adopting`),!1;let a=await ja(i);if(a!==void 0&&a.command!==""&&Ba({args:[...t.command.args],workDir:this.serviceWorkDir(t),startTime:new Date(s.startTime)},a)){this.ports.set(e,n);let l=this.attachProcess(e,i,[...t.command.args],this.serviceWorkDir(t),new Date(s.startTime))??this.bumpGeneration(e);this.setState(e,jt,Ct,i,""),this.log(e,"INFO",`already listening on ${Object.values(n).join(", ")}; not starting again`);let d=this.serviceWorkDir(t),f=await this.resolveAdoptedHealthEnv(e,t,n);return this.startHealth(e,t,i,n,d,f,l),!0}this.log(e,"WARN",`port ${r} is in use by an unrelated process (pid ${i}); not adopting`)}return!1}async startOne(e,t,n,r=!1){if(this.serviceIsActive(e))return;let o=this.cfg.services[e];if(!o)throw L(Je,`unknown service ${e}`);this.setState(e,Hd,Ct,0,"");let i=this.bumpGeneration(e),s=aa(o.identity);if(s.kind!=="none")try{if(s=await mm(o.identity,()=>xm(this.cfg.google.project_id),this.registry?.identityProviders),s.kind==="service_account")await this.tokens.get(po(s),"",[]),this.serviceAccountStatus.set(s.serviceAccount,"available")}catch(m){if(s.kind==="service_account")this.serviceAccountStatus.set(s.serviceAccount,"unavailable");if(NE(o)||s.kind==="service_account"||s.kind!=="user"&&s.kind!=="none")throw await this.fail(e,m),m;this.log(e,"WARN","cloud identity unavailable; starting service locally")}let a=this.ports.get(e)??{},{env:c,workDir:l}=await this.resolveServiceExecution(e,o,t,n,this.clientEnv.get(e),!o.container);if(r)try{await this.runTransient(`${e}:pre_start`,o.hooks.pre_start,o.shell,l,c)}catch(m){throw await this.fail(e,m),m}if(!this.isCurrentGeneration(e,i))return;let d=(m,x)=>{this.logs.append({timestamp:new Date().toISOString(),service:e,source:m,stream:m,level:"",message:x,pid:g.pid})},f=(m,x)=>this.onExit(e,i,m,x),g=o.container?await this.procs.startContainer({name:e,runtime:o.container.runtime==="podman"?"podman":"docker",containerName:`devctl-${vn(this.cfg.repoRoot)}-${e.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,image:o.container.image,command:[...o.command.args],env:Mh({...c,...o.container.env}),ports:a,targetPorts:o.container.ports,volumes:o.container.volumes,workDir:l,onLine:d,onExit:f}):await this.procs.start({name:e,args:[...o.command.args],shell:o.shell||o.command.shell,workDir:l,env:c,graceMs:so(this.cfg.shutdown)*1000,captureStdout:Yf(o),captureStderr:Xf(o),onLine:d,onExit:f});if(!this.isCurrentGeneration(e,i)){if(this.procs.get(e)===g)await this.procs.stop(e,so(this.cfg.shutdown)*1000).catch(()=>{});return}if(this.processMeta.set(e,{command:[...o.command.args],cwd:l,startTime:g.startTime}),this.setState(e,jt,Ct,g.pid,""),this.bus.publish(Le(Pm,e,{pid:g.pid})),r)try{await this.runTransient(`${e}:post_start`,o.hooks.post_start,o.shell,l,c)}catch(m){throw await this.fail(e,m),m}if(this.startHealth(e,o,g.pid,a,l,c,i),this.persistState(),o.startup.wait_for_healthy){let m=o.startup.timeout_seconds>0?o.startup.timeout_seconds*1000:mv;try{await this.waitHealthy(e,m)}catch(x){throw await this.fail(e,x),x}}}async resolveAdoptedHealthEnv(e,t,n){let r="";if(this.proxy?.isRunning())r=`http://${this.proxy.address()}`;else if(this.cfg.proxy.enabled)r=`http://${gr(this.cfg.proxy.listen)}`;let o=oa(e,"127.0.0.1",n,r,this.cfg.project.name);if(o.DEVCTL_INTERNAL_TOKEN=this.internalTok,this.cfg.proxy.token_endpoint.enabled)o.DEVCTL_TOKEN_URL=this.boundTokenURL||`http://127.0.0.1:${this.tokenEP?.listenPort()||this.cfg.proxy.token_endpoint.port}/token`;try{let i=await ra(this.cfg.repoRoot,{service:e,profile:this.serviceProfile.get(e)??this.profile,serviceCfg:t,profileEnv:this.serviceProfileEnv.get(e)??this.profileEnv,assignedPorts:n,runtime:o,cfg:this.cfg,fetchSecret:na(async()=>(await this.tokens.get("user","",[])).accessToken),pluginSources:this.registry?.environmentSources});return Si(i)}catch(i){return this.log(e,"WARN",`could not fully reconstruct environment for adopted service's health check (${O(i)}); using a baseline environment`),Si(o)}}async awaitWaveHealth(e,t){for(let n of e){let r=this.cfg.services[n],o=t.some((s)=>(this.cfg.services[s]?.dependencies??[]).some((a)=>wt(a)===n&&Fn(a)==="service_healthy"));if(!r||r.health.type===""||!o)continue;let i=r.startup.timeout_seconds>0?r.startup.timeout_seconds*1000:mv;try{await this.waitHealthy(n,i)}catch(s){throw await this.fail(n,s),s}}}async waitHealthy(e,t){let n=Date.now()+t;while(Date.now()<n){let r=this.runtimes.get(e);if(r?.health===_t)return;if(r?.state===Kn)throw L(El,`service ${e} failed while waiting for healthy`);await HE(PE)}throw L(El,`service ${e} did not become healthy in time`)}onExit(e,t,n,r){if(!this.isCurrentGeneration(e,t))return;let o=this.runtimes.get(e);if(o?.state===Kn)return;if(o&&(o.state===jd||o.state===ko)){this.setState(e,ko,Ct,0,""),this.bus.publish(Le(Ld,e,{code:n}));return}let i=this.cfg.services[e],s=i?i.restart.policy||(i.restart.enabled?"on_failure":"never"):"never",a=r?.message??`exited with code ${n}`,c=s==="always"||s==="on_failure"&&n!==0,l=this.restarts.get(e)??0,d=i&&i.restart.max_retries>0?i.restart.max_retries:hv;if(c&&i&&l<d){this.setState(e,Mi,Ct,0,a),this.bumpRestartCount(e,l+1),this.persistState(),this.armRestart(e,i,t,l,()=>{let f=this.serviceProfile.get(e)??this.profile,g=this.serviceProfileEnv.get(e)??this.profileEnv;this.startOne(e,f,g,!1).catch((m)=>this.log(e,"ERROR",O(m)))});return}this.fail(e,L("process_start",a))}startHealth(e,t,n,r,o,i,s){let a=this.healthTimers.get(e);if(a)clearInterval(a);if(t.health.type===""){this.setHealth(e,_t,"no health check");return}let c=Zm(t.health)||AE,l=Date.parse(this.runtimes.get(e)?.startTime??"")||Date.now(),d=()=>{(t.container&&t.health.type.toLowerCase()==="process"?Promise.resolve(this.procs.get(e)&&Dr(this.procs.get(e))?{status:_t,message:"container running"}:{status:Ce,message:"container not running"}):eh(t.health,n,r,o,i,this.registry?.healthChecks)).catch((g)=>({status:Ce,message:O(g)})).then((g)=>{if(!this.isCurrentGeneration(e,s))return;if(g.status===Ce&&Date.now()-l<t.health.start_period_seconds*1000){this.logs.append({timestamp:new Date().toISOString(),service:e,source:"health",level:"INFO",message:`health check still in start period: ${g.message}`,pid:n});return}this.setHealth(e,g.status,g.message),this.logs.append({timestamp:new Date().toISOString(),service:e,source:"health",level:th(g.status),message:`health ${g.status} ${g.message}`,pid:n}),this.maybeRestartUnhealthy(e,t,g.status,s)})};d(),this.healthTimers.set(e,setInterval(d,c))}async stop(e){let t=e;if(t.length===0)t=[...this.runtimes.entries()].filter(([,i])=>i.state!==ko).map(([i])=>i);if(t.length===0)return;let n=t.filter((i)=>!this.cfg.services[i]&&this.runtimes.has(i)),r=t.filter((i)=>!this.cfg.services[i]&&!this.runtimes.has(i));if(r.length>0)throw L(fi,`unknown service "${r[0]}"`);let o=t.filter((i)=>this.cfg.services[i]!==void 0);if(o.length>0)await this.runStopPlan(Ii(this.cfg,o),{resetRestartCounts:!0});if(n.length>0){await this.runStopPlan({profile:this.profile,steps:[],waves:n.map((i)=>[i])},{resetRestartCounts:!0});for(let i of n)this.forgetService(i)}}forgetService(e){let t=this.healthTimers.get(e);if(t)clearInterval(t),this.healthTimers.delete(e);this.clearRestartTimer(e),this.runtimes.delete(e),this.ports.delete(e),this.processMeta.delete(e),this.clientEnv.delete(e),this.serviceProfile.delete(e),this.serviceProfileEnv.delete(e),this.restarts.delete(e),this.generation.delete(e),this.unhealthyStreak.delete(e),this.healthyStreak.delete(e)}reconcileServices(e,t){for(let n of Object.keys(t))if(!e[n]&&!this.runtimes.has(n))this.runtimes.set(n,Sa(n));for(let n of Object.keys(e)){if(t[n])continue;if(this.serviceIsActive(n)){let r=this.runtimes.get(n);if(r)r.orphaned=!0;this.log(n,"WARN","removed from configuration while still running; now orphaned \u2014 stop it explicitly to clean it up");continue}this.forgetService(n)}}async restart(e,t){let n=t?.cascade===!0,r=n?Wd(this.cfg,e):e,o=n?Ii(this.cfg,e):zm(this.cfg,e),i=t?.auto!==!0;await this.runStopPlan(o,{resetRestartCounts:i});let s=r.map((a)=>this.serviceProfile.get(a)).find((a)=>a!==void 0)??this.profile;await this.start({services:r,profile:s,client_env:t?.clientEnv,auto:t?.auto})}async runStopPlan(e,t){for(let o of e.waves.flat())if(this.clearRestartTimer(o),this.bumpGeneration(o),t?.resetRestartCounts)this.resetRestartCount(o);let n=so(this.cfg.shutdown)*1000,r=[];for(let o of e.waves){let i=await Promise.allSettled(o.map(async(s)=>{this.setState(s,jd,Ct,0,"");let a=this.healthTimers.get(s);if(a)clearInterval(a),this.healthTimers.delete(s);try{await this.procs.stop(s,n)}catch(c){throw this.setState(s,Kn,Ct,0,O(c)),this.bus.publish(Le(Dd,s,{error:O(c)})),c}try{await this.releasePorts(s)}catch(c){this.log(s,"WARN",O(c))}this.setState(s,ko,Ct,0,""),this.bus.publish(Le(Ld,s,{}))}));for(let s=0;s<i.length;s+=1){let a=i[s];if(a?.status==="rejected"){let c=o[s]??"";r.push(c),this.log(c||"devctl","ERROR",O(a.reason))}}}if(this.persistState(),r.length>0)throw L(Ne,`failed to stop: ${r.join(", ")}`)}async startProxy(){if(this.proxy?.isRunning())return;if(this.proxy=new su(this.cfg.proxy,this.tokens,this.logs,this.bus,this.detector,this.registry?.proxyMiddleware??[]),await this.proxy.start(),this.cfg.proxy.token_endpoint.enabled)this.tokenEP=new au(this.cfg.proxy.token_endpoint.host||"127.0.0.1",this.cfg.proxy.token_endpoint.port,this.internalTok,this.tokens),await this.tokenEP.start(),this.boundTokenURL=`http://127.0.0.1:${this.tokenEP.listenPort()}/token`;this.persistState()}async stopProxy(){await this.proxy?.stop(),await this.tokenEP?.stop(),this.persistState()}async startMcp(e){if(this.mcp?.isRunning())return;let t=await pv(this.cfg.repoRoot,e);this.mcp=new fu({host:"127.0.0.1",port:t,token:this.mcpToken,hostApi:this.asMcpHost(),onEvent:(n,r)=>this.log("mcp",n,`mcp ${r}`),disabledTools:()=>this.mcpDisabledTools}),await this.mcp.start(),this.persistState()}setMcpDisabledTools(e){let t=e.filter((r)=>Ka(r)),n=this.mcpDisabledTools.join(",");if(this.mcpDisabledTools=[...new Set(t)].sort(),this.mcpDisabledTools.join(",")===n)return;this.log("devctl","INFO",this.mcpDisabledTools.length===0?"all MCP tools enabled":`MCP tools disabled: ${this.mcpDisabledTools.join(", ")}`)}async stopMcp(){await this.mcp?.stop(),this.mcp=void 0,this.persistState()}asMcpHost(){return{status:()=>this.snapshot(),logsPage:(e)=>this.queryLogsPage(e),config:()=>this.cfg,start:(e)=>this.start(e),stop:(e)=>this.stop(e),restart:(e,t)=>this.restart(e,{cascade:t}),reload:()=>this.reload(),doctor:async()=>{for(let e of Gn(this.cfg))await this.probeServiceAccount(e);return Un(this.cfg)},exec:(e,t,n)=>this.execService(e,t,void 0,n)}}async reload(){let e;try{e=ut(this.cfg.repoRoot,this.cfg.configPath)}catch(i){throw this.bus.publish(Le(Ti,"",{error:O(i)})),this.log("devctl","ERROR",`configuration reload failed: ${O(i)}`),i}try{this.checkPluginHealthTypes(e),this.checkPluginIdentityTypes(e),this.checkPluginEnvironmentSources(e)}catch(i){throw this.bus.publish(Le(Ti,"",{error:O(i)})),this.log("devctl","ERROR",`configuration reload failed: ${O(i)}`),i}if(this.setupMode){if(this.setupMode=!1,this.log("devctl","INFO",`configuration created at ${this.cfg.configPath}; leaving setup mode`),!this.configWatcher)this.watchConfig()}let t=$E(this.cfg,e),n=JSON.stringify(this.cfg.proxy)!==JSON.stringify(e.proxy),r=JSON.stringify(this.cfg.secrets)!==JSON.stringify(e.secrets),o=this.cfg.services;if(Object.assign(this.cfg,e),this.reconcileServices(o,e.services),this.restartRequired=t.restart_required,r)this.detector.update(e.secrets.extra_markers,e.secrets.extra_patterns);if(n){let i=this.proxy?.isRunning()??!1;if(await this.stopProxy(),i&&this.cfg.proxy.enabled)await this.startProxy();this.log("devctl","INFO","proxy configuration changed; proxy restarted")}if(this.bus.publish(Le(va,"",{restart_required:t.restart_required,changes:t.changes,supervisor_restart_required:t.supervisor_restart_required})),this.log("devctl","INFO",t.restart_required.length===0?"configuration reloaded":`configuration reloaded; restart required: ${t.restart_required.join(", ")}`),t.supervisor_restart_required)this.log("devctl","WARN",ka(t.supervisor_restart_required));return this.persistState(),this.refreshIdentity(),t}async shutdown(e){if(this.shuttingDown)return;if(this.shuttingDown=!0,this.persistState(),e)await this.stop([]);if(this.clearAllRestartTimers(),await this.stopProxy(),await this.stopMcp(),this.configWatcher?.close(),this.watchTimer)clearTimeout(this.watchTimer);if(this.resourceTimer)clearInterval(this.resourceTimer);this.server?.close(),this.lock?.release(),await this.logs.close()}snapshot(){let e={};for(let[r,o]of this.runtimes)e[r]={...o,ports:this.ports.get(r)??o.ports,profile:this.serviceProfile.get(r)??o.profile,env_source:this.clientEnv.has(r)?"client":"daemon"};let t=this.proxy?.stats(),n={requestTotal:t?.total??0,requestErrors:t?.errors??0,recentRequests:t?.recent??[]};return{session_id:this.sessionID,repo_root:this.cfg.repoRoot,profile:this.profile,services:e,proxy:{running:this.proxy?.isRunning()??!1,address:this.proxy?.address(),routes:this.cfg.proxy.routes.map((r)=>{let o=r.match.host||"*",i=r.match.path,s=i===""?o:`${o}${i.startsWith("/")?i:`/${i}`}`;return{name:r.name,identity:r.auth.identity.service_account||r.auth.identity.type||r.auth.type,upstream:r.upstream.url,auth:r.auth.type,match:s}}),...n},mcp:{running:this.mcp?.isRunning()??!1,address:this.mcp?.isRunning()?`http://${this.mcp.address()}/mcp`:void 0,port:this.mcp?.isRunning()?this.mcp.listenPort():void 0,token:this.mcpToken,disabled_tools:[...this.mcpDisabledTools]},identity:{...this.identityCache,...this.serviceAccountSnapshot()},credentials:{backend:this.tokens.storeBackend(),entries:[...this.credentialEntries]},detached:this.detached,setup_mode:this.setupMode?!0:void 0,logs:this.logs.snapshot(),restart_required:[...this.restartRequired],system:IE()}}async syncCredentialEntries(){this.credentialEntries=(await this.tokens.listStatus()).map((e)=>({identity:e.identity,audience:e.audience,expires_at:e.expires_at,valid:e.valid}))}async refreshIdentity(e){try{let t=await this.detectGoogleFn(this.cfg.google.project_id);if(e?.probeServiceAccounts)for(let o of Gn(this.cfg))await this.probeServiceAccount(o);let{service_accounts:n,service_account_status:r}=this.serviceAccountSnapshot();this.identityCache={user:t.userEmail,project:t.projectID||this.cfg.google.project_id,project_source:t.projectSource||(this.cfg.google.project_id?"configuration":""),adc:t.adcAvailable,service_accounts:n,service_account_status:r,iap:this.cfg.proxy.routes.some((o)=>o.auth.type.toLowerCase()==="iap")},await this.syncCredentialEntries(),this.bus.publish(Le(Od,"",{user:this.identityCache.user,adc:this.identityCache.adc})),this.log("auth","INFO",`authentication changed user=${this.identityCache.user||"(unknown)"} adc=${this.identityCache.adc}`),this.persistState()}catch(t){this.log("devctl","WARN",`identity refresh failed: ${O(t)}`)}}serviceAccountSnapshot(){let e={},t={};for(let n of Gn(this.cfg)){let r=this.serviceAccountStatus.get(n)??"unknown";if(t[n]=r,r!=="unknown")e[n]=r==="available"}return{service_accounts:e,service_account_status:t}}async probeServiceAccount(e){let t;try{await FE(this.tokens.refresh(`sa:${e}`,"",[]),RE),t="available"}catch{t="unavailable"}return this.serviceAccountStatus.set(e,t),t}queryLogs(e){let t=this.logs.query({services:e.services,level:e.level,search:e.search,regex:e.regex,source:e.source,since:e.since,until:e.until});if(e.export)this.logs.exportTo(e.export,{services:e.services,level:e.level,search:e.search,regex:e.regex,source:e.source,since:e.since,until:e.until});return{events:t}}queryLogsPage(e){return this.logs.queryPage({services:e.services,level:e.level,search:e.search,regex:e.regex,source:e.source,since:e.since,until:e.until},{cursor:e.cursor,direction:e.direction,limit:e.limit})}queryLogsFacets(e){return this.logs.queryFacets({services:e.services,level:e.level,search:e.search,regex:e.regex,source:e.source,since:e.since,until:e.until})}subscribe(e){return this.bus.subscribe(e)}formatStatus(){let e=this.snapshot(),t=[`PROFILE: ${e.profile||"(none)"}`,"","SERVICE\tSTATUS\tHEALTH\tPID"];for(let[n,r]of Object.entries(e.services))t.push(`${n} ${Co(r)} ${r.health} ${r.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.join(`
|
|
661
|
+
`)}}async serve(e,t){let r=Date.now(),n=e.headers[ns]?.toString()||Yy(8).toString("hex");t.setHeader(ns,n);let o=e.method??"GET",i=e.url??"/",s=this.detector?this.detector.redactText(i):i,a=Zy(this.cfg.routes,e);if(!a){Qo(t,404,"no matching proxy route"),this.recordRequest({timestamp:new Date().toISOString(),requestId:n,method:o,path:s,route:"",identity:"",status:404,durationMs:Date.now()-r});return}let c=to(a.auth),l=jo(c),d=0,u;try{let f={};for(let[v,b]of Object.entries(e.headers)){if(Pu.has(v.toLowerCase()))continue;if(typeof b==="string")f[v]=b;else if(Array.isArray(b))f[v]=b.join(",")}let p=e.socket.remoteAddress??"",m=f.host??"",g=f["x-forwarded-for"];if(f["x-forwarded-for"]=g?`${g}, ${p}`:p,f["x-forwarded-host"]=m,f["x-forwarded-proto"]="http",delete f.host,f["accept-encoding"]="gzip, deflate, br",f[ns]=n,this.middleware.length===0)await mc(a,f,this.tokens);for(let v of this.middleware)await v.apply({route:a,headers:f,tokens:this.tokens});let y=Qy(a.upstream.url,i),x=o!=="GET"&&o!=="HEAD"?e:void 0,h=await fetch(y,{method:o,headers:f,body:x,redirect:"manual",duplex:x?"half":void 0});t.statusCode=h.status,d=h.status;let P=(h.headers.get("content-encoding")??"").split(",").map((v)=>v.trim().toLowerCase()).filter((v)=>v!==""),_=P.length>0&&P.every((v)=>tT.has(v));h.headers.forEach((v,b)=>{let S=b.toLowerCase();if(Pu.has(S))return;if(_&&(S==="content-encoding"||S==="content-length"))return;t.setHeader(b,this.detector?this.detector.redactText(v):v)}),await rT(h,t);let w=Date.now()-r;this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:h.status>=400?"WARN":"INFO",message:`${o} ${i} route=${a.name} identity=${l} status=${h.status} duration=${w}ms`,pid:0,request_id:n,identity:l}),this.bus?.publish(Se(nd,a.name,{status:h.status,request_id:n,duration:w,identity:l}))}catch(f){let p=f instanceof Error?f.message:"proxy error";u=p,d=502,this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:"ERROR",message:`${o} ${i} route=${a.name} identity=${l} error=${p}`,pid:0,request_id:n,identity:l}),Qo(t,502,"proxy error")}finally{this.recordRequest({timestamp:new Date().toISOString(),requestId:n,method:o,path:s,route:a.name,identity:l,status:d,durationMs:Date.now()-r,error:u})}}}async function mc(e,t,r){let n=e.auth.type.toLowerCase();if(n===""||n==="none")return;if(!r)throw M(fn,"token manager unavailable");let o=to(e.auth),i=await r.get(jo(o),e.auth.audience,[]);t.authorization=`Bearer ${i.accessToken}`}async function rT(e,t){if(!e.body){t.end();return}let r=Z0.fromWeb(e.body);await new Promise((n,o)=>{r.on("error",o),t.on("error",o),t.on("finish",n),r.pipe(t)})}function nT(e){return e.protocol==="https:"?Q0:X0}function Qy(e,t){let r=new URL(e),n=new URL(t||"/",r),o=new URL(r.href);if(o.pathname=oT(n.pathname),o.search=n.search,o.hash="",o.origin!==r.origin)throw M(fn,"refusing to proxy to a different origin");return o}function oT(e){return(e.startsWith("/")?e:`/${e}`).replace(/^\/+/,"/")}function Qo(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 Zy(e,t){let r=(t.headers.host??"").split(":")[0]??"",n=t.url??"/";return e.find((o)=>{let i=o.match.host===""||o.match.host===r,s=o.match.path===""||n.startsWith(o.match.path);return i&&s})}class Eu{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(!kn(e))return Promise.reject(M(fn,`refusing to bind token endpoint to ${e}`));return new Promise((t,r)=>{this.server=ev((n,o)=>{this.serve(n,o)}),this.server.on("error",(n)=>r(Re(fn,"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(!iT(e.socket.remoteAddress)){Qo(t,403,"forbidden");return}if((e.headers[eT]??"")!==this.secret){Qo(t,401,"unauthorized");return}if(e.url?.startsWith("/token")!==!0){Qo(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{Qo(t,500,"token error")}}}function iT(e){if(!e)return!0;return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}Fr();var tv=1;class rv{tokenProviders=[];identityProviders=[];pluginIdentityProviders=[];environmentSources=[];healthChecks=[];logParsers=[];proxyMiddleware=[];loadErrors=[];pluginPaths=[];registerBuiltins(){this.tokenProviders.push(...Rn()),this.identityProviders.push(Xd(),Qd()),this.logParsers.push(Dm()),this.proxyMiddleware.push(dT())}register(e){lT(e),co(this.tokenProviders,e.tokenProviders),co(this.identityProviders,e.identityProviders),co(this.pluginIdentityProviders,e.identityProviders),co(this.environmentSources,e.environmentSources),co(this.healthChecks,e.healthChecks),co(this.logParsers,e.logParsers),co(this.proxyMiddleware,e.proxyMiddleware)}}async function gc(e,t=process.cwd()){let r=new rv;r.registerBuiltins();for(let n of e){if(n.trim()==="")continue;try{let o=n.startsWith("file:")?n:aT(n)?n:cT(t,n),s=await import(o.startsWith("file:")?o:sT(o).href);if(s.sdkVersion!==tv)throw Error(`plugin SDK version ${String(s.sdkVersion??"missing")} is incompatible; expected ${tv}`);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 lT(e){if(!e||typeof e!=="object")throw Error("plugin module must export an object");Zo("tokenProviders",e.tokenProviders,["fetch"]),Zo("identityProviders",e.identityProviders,["accepts","resolve"]),Zo("environmentSources",e.environmentSources,["load"]),Zo("healthChecks",e.healthChecks,["check"]),Zo("logParsers",e.logParsers,["parse"]),Zo("proxyMiddleware",e.proxyMiddleware,["apply"])}function Zo(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 dT(){return{name:"identity_inject",apply:async(e)=>{await mc(e.route,e.headers,e.tokens)}}}function co(e,t){if(!t)return;e.push(...t)}var hT=200;function Tu(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 Au(e,t){let r=new Map;for(let n of e){let o=vT(n,t);try{r.set(o,uT(o).mtimeMs)}catch{}}return r}async function yT(e,t,r){let n=t.plugins.map((a)=>a.path),o=JSON.stringify(r)!==JSON.stringify(n),i=Au(n,t.repoRoot),s=[];for(let[a,c]of i){let l=e.pluginMtimes.get(a);if(l!==void 0&&l!==c){s.push("plugins");break}}if(o){let a=await gc(n,t.repoRoot);e.registry=a;for(let c of a.loadErrors)e.log("devctl","ERROR",`plugin ${c.path} skipped: ${c.message}`);Tu(e),e.log("devctl","INFO","plugin path list reloaded")}return e.pluginMtimes=i,s}function vT(e,t){if(e.startsWith("file:"))return e;return fT(e)?e:gT(t,e)}function Lu(e,t){let r=Vd(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 M(ee,`unknown health check type(s): ${o.map((i)=>`${i.service}.health.type=${i.type}`).join(", ")}`)}function Du(e,t){let r=Jd(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 M(ee,`unknown identity type(s): ${o.map((i)=>`${i.service}.identity.type=${i.type}`).join(", ")}`)}function Mu(e,t){let r=new Set(Vi),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 M(ee,`unknown environment source(s): ${o.join(", ")}`)}function xT(e,t,r){for(let n of Object.keys(r))if(!t[n]&&!e.runtimes.has(n))e.runtimes.set(n,Ki(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 Ou(e){let t=mT(e.cfg.repoRoot,".devctl");if(!e.fs.exists(t))return;try{e.configWatcher=pT(t,{recursive:!0},()=>{if(e.watchTimer)clearTimeout(e.watchTimer);e.watchTimer=setTimeout(()=>{e.reload().catch((r)=>e.log("devctl","WARN",A(r)))},hT)})}catch{e.log("devctl","WARN","unable to watch .devctl for configuration changes")}}async function nv(e){let t;try{t=tn(e.cfg.repoRoot,e.cfg.configPath)}catch(l){throw e.bus.publish(Se(Ri,"",{error:A(l)})),e.log("devctl","ERROR",`configuration reload failed: ${A(l)}`),l}try{Lu(e.registry,t),Du(e.registry,t),Mu(e.registry,t)}catch(l){throw e.bus.publish(Se(Ri,"",{error:A(l)})),e.log("devctl","ERROR",`configuration reload failed: ${A(l)}`),l}if(e.setupMode){if(e.setupMode=!1,e.log("devctl","INFO",`configuration created at ${e.cfg.configPath}; leaving setup mode`),!e.configWatcher)Ou(e)}let r=Ru(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((l)=>l.path),s=e.cfg.services;e.cfg=zy(e.cfg,t),xT(e,s,t.services);let a=bT(e.restartRequired,r.restart_required,Object.keys(t.services));e.restartRequired=a,r.restart_required=a;let c=await yT(e,t,i);if(c.length>0)r.supervisor_restart_required=[...r.supervisor_restart_required??[],...c];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 l=e.proxy?.isRunning()??!1;if(await e.stopProxy(),l&&e.cfg.proxy.enabled)await e.startProxy();e.log("devctl","INFO","proxy configuration changed; proxy restarted")}if(e.bus.publish(Se(na,"",{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",Qa(r.supervisor_restart_required));return e.persistState(),e.refreshIdentity(),r}function bT(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 ST}from"fs";import{join as iv,relative as kT}from"path";mt();function ov(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:Di).some((o)=>wT(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 wT(e,t){let r=e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replaceAll("**/","<<<DS>>>").replaceAll("**","<<<DS>>>").replaceAll("*","[^/]*").replaceAll("<<<DS>>>",".*");return new RegExp(`^${r}$`).test(t)}class Iu{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=iv(n,i);try{let a=ST(s,{recursive:!0},(c,l)=>{let d=l?iv(s,l.toString()):s,u=kT(n,d).replaceAll("\\","/");if(!ov(t,u))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 $u,join as Fu}from"path";class Nu{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!==""&&!$u(e.working_dir))return Fu(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((p)=>!p.auto).map((p)=>[p.name,p.value])),c=this.deps.proxy(),l=c?.isRunning()?`http://${c.address()}`:s.proxy.enabled?`http://${yn(s.proxy.listen)}`:"",d=zi(e,"127.0.0.1",a,l,s.project.name);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 u=await Ji(s.repoRoot,{service:e,profile:r,serviceCfg:t,profileEnv:n,assignedPorts:a,runtime:d,cfg:s,fetchSecret:rs(async()=>(await this.deps.tokens.get("user","",[])).accessToken),pluginSources:this.deps.environmentSources(),clientEnv:o,includeProcess:i}),f=t.working_dir&&!$u(t.working_dir)?Fu(s.repoRoot,t.working_dir):t.working_dir;return{env:Yo(u),workDir:f}}async resolveTaskEnvironment(e,t,r){let n=this.deps.cfg(),o=await Ji(n.repoRoot,{service:`task:${e}`,profile:this.profile,serviceCfg:t,profileEnv:this.profileEnv,assignedPorts:{},runtime:zi(`task:${e}`,"127.0.0.1",{},"",n.project.name),cfg:n,clientEnv:r,fetchSecret:rs(async()=>(await this.deps.tokens.get("user","",[])).accessToken),pluginSources:this.deps.environmentSources()}),i=t.working_dir&&!$u(t.working_dir)?Fu(n.repoRoot,t.working_dir):t.working_dir;return{env:Yo(o),workDir:i}}}Fr();te();Fr();Tt();import{cpus as MT,loadavg as OT,platform as IT,uptime as $T}from"os";import{readFileSync as CT}from"fs";import{freemem as RT,totalmem as PT}from"os";import{spawnSync as _T}from"child_process";var Hu=1024,ET=2000,TT=/page size of (\d+) bytes/i,ei;function AT(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 LT(e){let t=e.match(TT),r=t?Number(t[1]):0;if(!Number.isFinite(r)||r<=0)return;let n=hc(e,"free")+hc(e,"inactive")+hc(e,"speculative")+hc(e,"purgeable");return Math.round(n*r/Hu)}function hc(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 DT(){if(process.platform==="linux")try{return AT(CT("/proc/meminfo","utf8"))}catch{return}if(process.platform==="darwin"){let e=Date.now();if(ei&&e-ei.at<ET)return ei.leftoverKB;let t=_T("vm_stat",{encoding:"utf8"});if(t.status!==0||!t.stdout)return ei?.leftoverKB;let r=LT(t.stdout);if(r===void 0)return ei?.leftoverKB;return ei={at:e,leftoverKB:r},r}return}function sv(){let e=Math.max(0,Math.round(PT()/Hu)),t=Math.max(0,Math.round(RT()/Hu)),r=Math.max(0,Math.min(e,DT()??t));return{totalKB:e,unusedKB:t,leftoverKB:r}}function av(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?$r(e).map((t)=>[t,"unknown"]):[]),iap:e?.proxy.routes.some((t)=>t.auth.type.toLowerCase()==="iap")??!1}}function Bu(){let e=OT(),t=sv();return{platform:IT(),cpuCount:MT().length,loadAvg1:e[0]??0,loadAvg5:e[1]??0,loadAvg15:e[2]??0,memTotalKB:t.totalKB,memFreeKB:t.unusedKB,memAvailableKB:t.leftoverKB,hostUptimeSec:$T()}}function Wu(e,t){let r={},n={};for(let o of $r(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 cv(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??[]};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}}),...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]},identity:{...e.identityCache,...Wu(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:Bu(),stats_series:e.statsSeries}}function lv(e){let t=[`PROFILE: ${e.profile||"(none)"}`,"","SERVICE\tSTATUS\tHEALTH\tPID"];for(let[r,n]of Object.entries(e.services))t.push(`${r} ${Jo(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.join(`
|
|
657
662
|
`)+`
|
|
658
|
-
`}setState(e,t,n,r,o){let i=this.runtimes.get(e)??Sa(e);i.state=t,i.health=n,i.pid=r,i.last_error=o;let s=t===jt||t===Er||t===So;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(Le(Tm,e,{state:t,health:n,pid:r}))}bumpRestartCount(e,t){this.restarts.set(e,t);let n=this.runtimes.get(e);if(n)n.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,n){this.clearRestartTimer(e);let r=setTimeout(()=>{this.restartTimers.delete(e),n()},t);this.restartTimers.set(e,r)}armRestart(e,t,n,r,o){let i=t.restart.backoff_seconds>0?t.restart.backoff_seconds:TE;this.scheduleRestart(e,i*2**r*1000,()=>{if(this.isCurrentGeneration(e,n))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()}async pollResourceUsage(){let e=[];for(let n of this.runtimes.values())if(n.pid>0&&(n.state===jt||n.state===Er||n.state===So))e.push(n.pid);if(e.length===0)return;let t=await Gh(e);for(let n of this.runtimes.values()){let r=n.pid>0?t.get(n.pid):void 0;if(r)n.cpuPercent=r.cpuPercent,n.memoryKB=r.memoryKB}}setHealth(e,t,n){let r=this.runtimes.get(e);if(!r)return;if(r.health=t,r.state===jt||r.state===Er||r.state===So)r.state=t===_t?Er:t===Ce?So:r.state;this.bus.publish(Le(Am,e,{health:t,message:n}))}maybeRestartUnhealthy(e,t,n,r){if(n!==Ce){if(this.unhealthyStreak.set(e,0),n===_t)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:DE;if(i<s)return;this.unhealthyStreak.set(e,0);let a=this.restarts.get(e)??0,c=t.restart.max_retries>0?t.restart.max_retries:hv;if(a>=c){this.log(e,"WARN",`unhealthy after ${i} consecutive checks but the restart limit (${c}) has already been reached; not restarting`);return}this.bumpRestartCount(e,a+1),this.log(e,"WARN",`restarting after ${i} consecutive unhealthy checks (attempt ${a+1}/${c})`),this.armRestart(e,t,r,a,()=>{this.restart([e],{auto:!0}).catch((l)=>this.log(e,"ERROR",O(l)))})}maybeForgiveRestarts(e,t){let n=(this.healthyStreak.get(e)??0)+1;this.healthyStreak.set(e,n);let r=t.health.healthy_reset_threshold>0?t.health.healthy_reset_threshold:OE;if(n>=r&&(this.restarts.get(e)??0)>0)this.log(e,"INFO",`restart count reset after ${n} consecutive healthy checks`),this.bumpRestartCount(e,0)}applyRegistry(){if(!this.registry)return;if(this.registry.tokenProviders.length>0)this.tokens.replaceProviders(this.registry.tokenProviders);this.logs.setParsers(this.registry.logParsers)}checkPluginHealthTypes(e=this.cfg){let t=od(e);if(t.length===0)return;let n=new Set((this.registry?.healthChecks??[]).map((o)=>o.name.toLowerCase())),r=t.filter((o)=>!n.has(o.type.toLowerCase()));if(r.length>0)throw L(Z,`unknown health check type(s): ${r.map((o)=>`${o.service}.health.type=${o.type}`).join(", ")}`)}checkPluginIdentityTypes(e=this.cfg){let t=id(e);if(t.length===0)return;let n=this.registry?.pluginIdentityProviders??[],r=t.filter(({service:o})=>{let i=e.services[o];return!i||!n.some((s)=>s.accepts(i.identity))});if(r.length>0)throw L(Z,`unknown identity type(s): ${r.map((o)=>`${o.service}.identity.type=${o.type}`).join(", ")}`)}checkPluginEnvironmentSources(e=this.cfg){let t=new Set(wi),n=new Set((this.registry?.environmentSources??[]).map((o)=>o.name)),r=e.environment.sources.filter((o)=>!t.has(o)&&!n.has(o));if(r.length>0)throw L(Z,`unknown environment source(s): ${r.join(", ")}`)}watchConfig(){let e=tc(this.cfg.repoRoot,".devctl");if(!hu(e))return;try{this.configWatcher=SE(e,{recursive:!0},()=>{if(this.watchTimer)clearTimeout(this.watchTimer);this.watchTimer=setTimeout(()=>{this.reload().catch((t)=>this.log("devctl","WARN",O(t)))},LE)})}catch{this.log("devctl","WARN","unable to watch .devctl for configuration changes")}}async releasePorts(e){let t=this.ports.get(e);if(!t)return;let n=this.cfg.services[e];if(n?.container){this.ports.delete(e);return}let r=this.processMeta.get(e);for(let o of Object.values(t)){let i=await yo(o);if(!i||i.pid===process.pid)continue;if(n){let s=await ja(i.pid);if(!(s!==void 0&&s.command!==""&&Ba({args:r?.command??[...n.command.args],workDir:r?.cwd??this.serviceWorkDir(n),startTime:r?.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 ua(i),this.log(e,"INFO",`released port ${o} (pid ${i.pid})`)}catch(s){this.log(e,"WARN",O(s))}}this.ports.delete(e)}async fail(e,t){let n=this.healthTimers.get(e);if(n)clearInterval(n),this.healthTimers.delete(e);this.clearRestartTimer(e),this.bumpGeneration(e),this.setState(e,Kn,Ct,0,O(t));try{await this.procs.stop(e,so(this.cfg.shutdown)*1000)}catch(r){this.log(e,"WARN",O(r))}this.bus.publish(Le(Dd,e,{error:O(t)})),this.log(e,"ERROR",O(t)),this.persistState()}log(e,t,n){this.logs.append({timestamp:new Date().toISOString(),service:e,source:"devctl",level:t,message:n,pid:0})}persistState(){let e=[];for(let t of this.procs.all()){let n=this.processMeta.get(t.name);e.push({name:t.name,pid:t.pid,command:n?.command??t.args,cwd:n?.cwd??t.workDir,startTime:(n?.startTime??t.startTime).toISOString(),ports:this.ports.get(t.name)??{}})}Wf(this.cfg.repoRoot,{session_id:this.sessionID,repo_root:this.cfg.repoRoot,profile:this.profile,processes:e})}attachProcess(e,t,n,r,o){if(this.procs.get(e)&&this.processAliveFn(this.procs.get(e)?.pid??0))return;if(!this.processAliveFn(t)||t===process.pid)return;let i=this.bumpGeneration(e);try{this.procs.adopt({name:e,pid:t,args:n,workDir:r,startTime:o,onExit:(s,a)=>{this.onExit(e,i,s,a)}})}catch(s){let a=s instanceof Error?s.message:String(s);this.log(e,"WARN",`adopt pid ${t} failed (${a}); tracking leftover in snapshot only`)}return this.processMeta.set(e,{command:n,cwd:r,startTime:o}),this.persistState(),i}async recoverSession(){let e=pr(this.cfg.repoRoot);if(!e)return;let t=[];for(let[n,r]of Object.entries(this.cfg.services)){if(!r.container)continue;let o=e.processes.find((d)=>d.name===n),i=this.bumpGeneration(n),s=r.container.runtime==="podman"?"podman":"docker",a=await this.procs.adoptContainer({name:n,runtime:s,containerName:`devctl-${vn(this.cfg.repoRoot)}-${n.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,workDir:this.serviceWorkDir(r),onLine:(d,f)=>this.logs.append({timestamp:new Date().toISOString(),service:n,source:d,stream:d,level:"",message:f,pid:0}),onExit:(d,f)=>this.onExit(n,i,d,f)});if(!a)continue;let c=o?.ports??Object.fromEntries(r.ports.filter((d)=>!d.auto).map((d)=>[d.name,d.value]));this.ports.set(n,c),this.processMeta.set(n,{command:[...r.command.args],cwd:this.serviceWorkDir(r),startTime:o?.startTime?new Date(o.startTime):a.startTime}),this.setState(n,jt,Ct,0,"");let l=await this.resolveAdoptedHealthEnv(n,r,c);this.startHealth(n,r,0,c,this.serviceWorkDir(r),l,i),this.log(n,"INFO",`adopted ${s} container ${a.container?.id??""}`),t.push(n)}for(let n of e.processes){if(!this.cfg.services[n.name]||this.cfg.services[n.name]?.container||n.pid<=0||n.pid===process.pid||!this.processAliveFn(n.pid))continue;let r=await this.inspectProcessFn(n.pid);if(!(r!==void 0&&r.command!==""&&Ba({args:n.command,workDir:n.cwd,startTime:n.startTime?new Date(n.startTime):void 0},r))){if(Object.values(n.ports).length>0&&await da({ports:Object.entries(n.ports).map(([c,l])=>({name:c,value:l,auto:!1}))})!==void 0)this.log(n.name,"WARN",`pid ${n.pid} does not match stored command; leftover listener not adopted`);else this.log(n.name,"WARN",`pid ${n.pid} is a different process; not adopting`);continue}let i=this.attachProcess(n.name,n.pid,n.command,n.cwd,new Date(n.startTime||Date.now()))??this.bumpGeneration(n.name);if(Object.keys(n.ports).length>0)this.ports.set(n.name,n.ports);this.setState(n.name,jt,Ct,n.pid,"");let s=this.cfg.services[n.name];if(s){let a=n.cwd||this.serviceWorkDir(s),c=await this.resolveAdoptedHealthEnv(n.name,s,n.ports);this.startHealth(n.name,s,n.pid,n.ports,a,c,i)}this.log(n.name,"INFO","adopted leftover process; stdout/stderr from before adopt are not captured"),t.push(n.name)}if(t.length>0)this.profile=e.profile||this.profile,this.bus.publish(Le(Om,"",{services:t,session_id:e.session_id})),this.log("devctl","INFO",`recovered session processes: ${t.join(", ")}`)}}function $E(e,t){let n={},r=new Set,o=new Set([...Object.keys(e.services),...Object.keys(t.services)]);for(let s of o){let a=e.services[s],c=t.services[s],l=[];if(!a||!c)l.push("presence"),r.add(s);else{if(a.command.args.join("\x00")!==c.command.args.join("\x00")||a.command.shell!==c.command.shell||a.shell!==c.shell)l.push("command"),r.add(s);if(a.working_dir!==c.working_dir)l.push("working_dir"),r.add(s);if(JSON.stringify(a.environment)!==JSON.stringify(c.environment))l.push("environment"),r.add(s);if(JSON.stringify(a.ports)!==JSON.stringify(c.ports))l.push("ports"),r.add(s);if(JSON.stringify(a.identity)!==JSON.stringify(c.identity))l.push("identity"),r.add(s);if(JSON.stringify(a.health)!==JSON.stringify(c.health))l.push("health"),r.add(s);if(JSON.stringify(a.restart)!==JSON.stringify(c.restart))l.push("restart"),r.add(s);if(JSON.stringify(a.startup)!==JSON.stringify(c.startup))l.push("startup"),r.add(s);if(JSON.stringify(a.logs)!==JSON.stringify(c.logs))l.push("logs"),r.add(s);if(JSON.stringify(a.container)!==JSON.stringify(c.container))l.push("container"),r.add(s)}if(l.length>0)n[s]=l}let i=[];if(JSON.stringify(e.logs)!==JSON.stringify(t.logs))i.push("logs");if(JSON.stringify(e.auth)!==JSON.stringify(t.auth))i.push("auth");if(JSON.stringify(e.plugins)!==JSON.stringify(t.plugins))i.push("plugins");return{restart_required:[...r].sort(),changes:n,supervisor_restart_required:i.length>0?i:void 0}}function vv(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?Gn(e).map((t)=>[t,"unknown"]):[]),iap:e?.proxy.routes.some((t)=>t.auth.type.toLowerCase()==="iap")??!1}}function IE(){let e=CE(),t=nh();return{platform:_E(),cpuCount:kE().length,loadAvg1:e[0]??0,loadAvg5:e[1]??0,loadAvg15:e[2]??0,memTotalKB:t.totalKB,memFreeKB:t.unusedKB,memAvailableKB:t.leftoverKB,hostUptimeSec:EE()}}function FE(e,t){return new Promise((n,r)=>{let o=setTimeout(()=>r(Error("identity probe timed out")),t);e.then((i)=>{clearTimeout(o),n(i)},(i)=>{clearTimeout(o),r(i)})})}function NE(e){return e.capabilities.some((t)=>["google_api","iap","service_identity"].includes(t))}function yv(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Ir(e){if(!Array.isArray(e))return[];return e.filter((t)=>typeof t==="string")}function nc(e){if(!yv(e))return;let t={};for(let[n,r]of Object.entries(e))if(typeof r==="string")t[n]=r;return t}function HE(e){return new Promise((t)=>setTimeout(t,e))}Ar();Ja();Zt();Hp();var xw=["zsh","bash","fish"];function bw(e){if(e==="zsh")return`#compdef devctl
|
|
663
|
+
`}var FT=4000;class ju{cache;accounts=new Map;entries=[];deps;constructor(e){this.deps=e,this.cache=av(e.cfg()),this.deps.bus.subscribe((t)=>{let r=t.payload??{},n=t.type===Lo?`token refreshed identity=${String(r.identity??"")}`:t.type===jn?`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===jn?"WARN":"INFO",message:n,pid:0}),t.type===Lo||t.type===jn)this.syncCredentialEntries()},[Lo,jn,rd])}get identityCache(){return this.cache}get serviceAccountStatus(){return this.accounts}get credentialEntries(){return this.entries}async prepareServiceIdentity(e,t){let r=Fa(t.identity);if(r.kind!=="none")try{if(r=await hh(t.identity,()=>bh(this.deps.cfg().google.project_id),this.deps.identityProviders()),r.kind==="service_account")await this.deps.tokens.get(jo(r),"",[]),this.accounts.set(r.serviceAccount,"available")}catch(n){if(r.kind==="service_account")this.accounts.set(r.serviceAccount,"unavailable");if(HT(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 $r(t))await this.probeServiceAccount(i);let{service_accounts:n,service_account_status:o}=Wu(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(Se(rd,"",{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: ${A(t)}`)}}async probeServiceAccount(e){let t;try{await NT(this.deps.tokens.refresh(`sa:${e}`,"",[]),FT),t="available"}catch{t="unavailable"}return this.accounts.set(e,t),t}}function NT(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 HT(e){return e.capabilities.some((t)=>["google_api","iap","service_identity"].includes(t))}te();te();Uu();var UT=600,KT=65535;async function gv(e,t){let r=Number.isInteger(t)&&(t??0)>0?t:lo(e);for(let n=0;n<UT;n+=1){let o=r+n;if(o>KT)break;if(await Fo(o))return o}throw M(ee,`no free MCP port starting at ${r}`)}class Ku{listener;disabled=[];token;deps;constructor(e){this.deps=e,this.token=vm(e.repoRoot())}get instance(){return this.listener}get disabledTools(){return this.disabled}async bootFromPreferences(){let e=To(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",A(t)))}async start(e){if(this.listener?.isRunning())return;let t=await gv(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()}}class qu{server;tokenEP;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 _u(this.deps.cfg().proxy,this.deps.tokens,this.deps.logs,this.deps.bus,this.deps.detector,this.deps.middleware()),await this.server.start();let e=this.deps.cfg();if(e.proxy.token_endpoint.enabled)this.tokenEP=new Eu(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`;this.deps.persistState()}async stop(){await this.server?.stop(),await this.tokenEP?.stop(),this.deps.persistState()}}Tt();var qT=3000,hv=5000,yv=60;class Vu{timer;cpu=[];mem=[];lastAt=0;deps;constructor(e){this.deps=e}start(){if(this.timer)return;this.timer=setInterval(()=>void this.poll(),qT)}stop(){if(this.timer)clearInterval(this.timer),this.timer=void 0}series(){return{interval_ms:hv,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===Be||r.state===pr||r.state===Nr))e.push(r.pid);if(e.length===0)return;let t=await Wy(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<hv)return;this.lastAt=e;let t=Bu(),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>yv)this.cpu.shift();if(this.mem.length>yv)this.mem.shift()}}function Ju(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function _n(e){if(!Array.isArray(e))return[];return e.filter((t)=>typeof t==="string")}function os(e){if(!Ju(e))return;let t={};for(let[r,n]of Object.entries(e))if(typeof n==="string")t[r]=n;return t}te();import{createServer as VT}from"net";var JT=2000;class zu{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=VT((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],c=e.write(`${JSON.stringify(a)}
|
|
664
|
+
`);if(r.shift(),!c){n=!0,e.once("drain",()=>{n=!1,o()});return}}},i=(a)=>{if(a.id===void 0&&a.event!==void 0&&r.length>=JT){let l=r.findIndex((d)=>d.id===void 0&&d.event!==void 0);if(l>=0)r.splice(l,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: ${A(a)}`)}),e.on("data",(a)=>{t+=a.toString("utf8");let c=t.split(`
|
|
665
|
+
`);t=c.pop()??"";for(let l of c){if(l.trim()==="")continue;this.dispatchLine(l,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=tg(n);t({id:r.id,error:o.error,kind:o.kind,hint:o.hint,service:o.service})}}}te();Fr();Tt();class Yu{cfg;sessionID;internalTok;bus;logs;procs;tokens;detector;env;proxy;mcp;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=Ql(),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.procs=t.procs,this.orchestrator=t.orchestrator,this.tokens=t.tokens,this.proxy=new qu({cfg:()=>this.cfg,tokens:this.tokens,logs:this.logs,bus:this.bus,detector:this.detector,internalTok:()=>this.internalTok,middleware:()=>this.registry?.proxyMiddleware??[],persistState:()=>this.persistState()}),this.env=new Nu({cfg:()=>this.cfg,ports:()=>this.ports,proxy:()=>this.proxy.instance,tokenEndpoint:()=>this.proxy.tokenEndpoint,boundTokenURL:()=>this.proxy.boundTokenURL,internalTok:()=>this.internalTok,tokens:this.tokens,environmentSources:()=>this.registry?.environmentSources}),this.mcp=new Ku({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.resources=new Vu({clock:this.clock,runtimes:()=>this.runtimes}),this.identity=new ju({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 zu({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,Ki(r));this.orchestrator.bind(this.lifecycleSession()),this.commands=t.createCommands(this),this.serviceWatchers=new Iu({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 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()}}}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=Vs(this.cfg.repoRoot);this.lock=this.acquireLockFn(this.cfg.repoRoot,e),this.rpc.removeStaleSocket(e),this.registry=await gc(this.cfg.plugins.map((t)=>t.path),this.cfg.repoRoot),this.pluginMtimes=Au(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}`);Tu(this.reloadHost()),Lu(this.registry,this.cfg),Du(this.registry,this.cfg),Mu(this.registry,this.cfg),await this.recoverSession(),this.serviceWatchers.sync(this.cfg.services),Ou(this.reloadHost()),this.persistState(),this.log("devctl","INFO",`supervisor started session=${this.sessionID}`),this.refreshIdentity(),this.resources.start(),await this.mcp.bootFromPreferences(),this.rpc.removeStaleSocket(e),await this.rpc.listen(e)}async dispatch(e,t){let r=Ju(t)?t:{};switch(e){case"ping":return{session:this.sessionID,version:Bt,protocol:ji};case"start":return this.commands.startService.execute({services:_n(r.services),profile:typeof r.profile==="string"&&r.profile!==""?r.profile:void 0,detach:r.detach===!0,client_env:os(r.client_env)});case"stop":return await this.commands.stopService.execute(_n(r.services)),null;case"restart":return await this.commands.restartService.execute(_n(r.services),{cascade:r.cascade===!0,clientEnv:os(r.client_env)}),null;case"run_task":return this.runTask(typeof r.name==="string"?r.name:"",os(r.client_env)??{});case"exec":return this.execService(typeof r.service==="string"?r.service:"",_n(r.command),os(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({services:_n(r.services),level:typeof r.level==="string"?r.level:"",search:typeof r.search==="string"?r.search:"",regex:r.regex===!0,source:typeof r.source==="string"?r.source:"",since:typeof r.since==="string"?r.since:"",until:typeof r.until==="string"?r.until:"",export:typeof r.export==="string"?r.export:""});case"logs_page":return await this.queryLogsPage({services:_n(r.services),level:typeof r.level==="string"?r.level:"",search:typeof r.search==="string"?r.search:"",regex:r.regex===!0,source:typeof r.source==="string"?r.source:"",since:typeof r.since==="string"?r.since:"",until:typeof r.until==="string"?r.until:"",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({services:_n(r.services),level:typeof r.level==="string"?r.level:"",search:typeof r.search==="string"?r.search:"",regex:r.regex===!0,source:typeof r.source==="string"?r.source:"",since:typeof r.since==="string"?r.since:"",until:typeof r.until==="string"?r.until:""});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??To(this.cfg.repoRoot).mcp_port),null}case"mcp_stop":return await this.stopMcp(),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:wa(this.cfg.shutdown);return setTimeout(()=>{this.shutdown(n)},50),null;default:throw M(ct,`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-${ar(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 og(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 Qe&&t.service!=="")await this.fail(t.service,t);else this.log("devctl","ERROR",A(t));throw t}}async runTask(e,t){let r=this.cfg.tasks[e];if(!r)throw M(ct,`unknown task ${e}`);if(r.dependencies.length>0)await this.start({services:r.dependencies,client_env:t});let n={...gn(),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 M(Io,`unknown service ${e}`);let i=this.env.serviceProfile.get(e)??this.env.profile,s=i!==""?so(this.cfg,i):this.env.profileEnv,{env:a,workDir:c}=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 M(ct,"exec command is required");let l=await this.runTransient(`${e}:exec`,{args:t,shell:!1},!1,c,a);return{service:e,...l}}async runTransient(e,t,r,n,o){if(hn(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 M(He,`${e} exited with code ${i.code}`);return i}serviceWorkDir(e){return this.env.serviceWorkDir(e)}async claimIfAlreadyUp(e){return Vy(this.recoverHost(),e)}async recoverSession(){return Jy(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?io(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)=>Fi(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 $r(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()}}async reload(){return nv(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.stopMcp(),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 cv(this.snapshotHost())}async refreshIdentity(e){return this.identity.refreshIdentity(e)}async queryLogs(e){let t=await this.logs.query({services:e.services,level:e.level,search:e.search,regex:e.regex,source:e.source,since:e.since,until:e.until});if(e.export)await this.logs.exportTo(e.export,{services:e.services,level:e.level,search:e.search,regex:e.regex,source:e.source,since:e.since,until:e.until});return{events:t}}async queryLogsPage(e){return this.logs.queryPage({services:e.services,level:e.level,search:e.search,regex:e.regex,source:e.source,since:e.since,until:e.until},{cursor:e.cursor,direction:e.direction,limit:e.limit})}async queryLogsFacets(e){return this.logs.queryFacets({services:e.services,level:e.level,search:e.search,regex:e.regex,source:e.source,since:e.since,until:e.until})}subscribe(e){return this.bus.subscribe(e)}formatStatus(){return lv(this.snapshot())}setState(e,t,r,n,o){let i=this.runtimes.get(e)??Ki(e);if(!ts(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===Be||t===pr||t===Nr;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(Se(Cm,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 Vn(o);if(!i||i.pid===process.pid)continue;if(r){let s=await this.inspectProcessFn(i.pid);if(!(s!==void 0&&s.command!==""&&Zi({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 fa(i),this.log(e,"INFO",`released port ${o} (pid ${i.pid})`)}catch(s){this.log(e,"WARN",A(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,lt,Et,0,A(t));try{await this.procs.stop(e,vn(this.cfg.shutdown)*1000)}catch(r){this.log(e,"WARN",A(r))}this.bus.publish(Se(ra,e,{error:A(t)})),this.log(e,"ERROR",A(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})}hm(this.cfg.repoRoot,{session_id:this.sessionID,repo_root:this.cfg.repoRoot,profile:this.profile,processes:e})}}var xv=500,zT=1e4,YT=2000,XT=new URL("./log-worker.ts",import.meta.url);class bv{worker;bus;pending=new Map;nextId=1;stats={total:0,errors:0,counts:{}};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??XT,{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=xv){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(!QT(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(!ZT(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"},YT)}catch{}finally{this.markDead(Error("log worker closed"))}}rpc(e,t=zT){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(Se(Ao,e.event.service,{event:e.event,level:e.event.level}));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 QT(e){if(e===null||Array.isArray(e)||!("events"in e))return!1;return Array.isArray(e.events)}function ZT(e){return e!==null&&!Array.isArray(e)&&"byService"in e}function vv(e,t,r){return qm(new bd(e.max,t,r,e.persist,e.directory,e.sessionID,e.retentionDays,e.maxSessionLogs))}async function wv(e,t,r,n={}){if(n.standalone??Bun.isStandaloneExecutable===!0)return{logs:vv(e,t,r),usingWorker:!1};try{let i=new bv(e,t,{script:n.script});return await i.waitUntilReady(n.initTimeoutMs??xv),{logs:i,usingWorker:!0}}catch{return{logs:vv(e,t,r),usingWorker:!1}}}ti();import{createServer as dA}from"http";te();ss();var uA="2025-03-26",Fv="2.0",Mv=-32700,Ov=-32600,pA=-32601,Iv=-32602,fA=-32603;function mA(e){return e!==""&&kn(e)}class Zu{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(!mA(this.opts.host))return Promise.reject(M(ct,`refusing to bind MCP to ${this.opts.host}`));return new Promise((e,t)=>{this.server=dA((r,n)=>{this.serve(r,n)}),this.server.on("error",(r)=>t(Re(ct,`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,ls()),t.end();return}if(!this.authorized(e)){this.emit("WARN",`rejected unauthorized request from ${$v(e)}`),ri(t,401,{error:"unauthorized"});return}if(hA(e)!=="/mcp"){ri(t,404,{error:"not found"});return}if(e.method==="GET"||e.method==="DELETE"){t.writeHead(405,{Allow:"POST, OPTIONS",...ls()}),t.end();return}if(e.method!=="POST"){t.writeHead(405,{Allow:"POST, OPTIONS",...ls()}),t.end();return}let n;try{n=await yA(e)}catch(a){ri(t,400,as(null,Mv,a instanceof Error?a.message:"invalid body"));return}let o;try{o=JSON.parse(n)}catch{ri(t,400,as(null,Mv,"parse error"));return}let i=$v(e);if(Array.isArray(o)){let a=[];for(let c of o){let l=await this.dispatch(c,i);if(l!==void 0)a.push(l)}ri(t,200,a);return}let s=await this.dispatch(o,i);if(s===void 0){t.writeHead(202,ls()),t.end();return}ri(t,200,s)}authorized(e){if(this.opts.token==="")return!0;return(e.headers.authorization??"")===`Bearer ${this.opts.token}`}async dispatch(e,t){if(!wc(e))return as(null,Ov,"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:as(n,Ov,"missing method");try{let i=await this.handleMethod(r.method,wc(r.params)?r.params:{},t);if(o)return;return{jsonrpc:Fv,id:n,result:i}}catch(i){if(o)return;let s=i instanceof cs?i.code:fA,a=i instanceof Error?i.message:"internal error";return this.emit("WARN",`rpc error method=${r.method} addr=${t}: ${a}`),as(n,s,a)}}async handleMethod(e,t,r){switch(e){case"initialize":{let n=gA(t);return this.emit("INFO",`client connected addr=${r}${n?` (${n})`:""}`),{protocolVersion:uA,capabilities:{tools:{},resources:{}},serverInfo:{name:"devctl",version:Bt}}}case"notifications/initialized":case"ping":return{};case"tools/list":return{tools:Rv(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:Xu.map((n)=>({uri:n,name:n.replace("devctl://",""),mimeType:"application/json"}))};case"resources/read":return this.readResource(t);default:throw new cs(pA,`method not found: ${e}`)}}async callTool(e){let t=typeof e.name==="string"?e.name:"";if(t==="")throw new cs(Iv,"tool name is required");if(bc(t)&&!En(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=wc(e.arguments)?e.arguments:{},n=Date.now();try{let o=await Av(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(!Lv(t))throw new cs(Iv,`unknown resource ${t}`);let r=await Dv(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 gA(e){let t=e.clientInfo;if(!wc(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 $v(e){return e.socket.remoteAddress??"unknown"}class cs extends Error{code;constructor(e,t){super(t);this.code=e}}function ls(){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 ri(e,t,r){let n=JSON.stringify(r);e.writeHead(t,{"Content-Type":"application/json","Content-Length":Buffer.byteLength(n),...ls()}),e.end(n)}function as(e,t,r){return{jsonrpc:Fv,id:e,error:{code:t,message:r}}}function hA(e){let t=e.url??"/",r=t.indexOf("?");return r>=0?t.slice(0,r):t}function yA(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 wc(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}ss();var bA=(e)=>new Zu({host:"127.0.0.1",...e});async function wA(e,t={}){let r=t.clock??Ga,n=t.fs??jy,o=t.processes??new xu,i=t.bus??new od(2048),s=t.tokens??new oo(e.auth.refresh_threshold_seconds*1000,Rn(),i,void 0,r),a=new Cu(o,r),c=zl(),l=new mr(e.secrets.extra_markers,e.secrets.extra_patterns),d=Bun.isStandaloneExecutable===!0,{logs:u,usingWorker:f}=await wv({max:e.logs.max_memory_events,persist:e.logs.persistence.enabled,directory:e.logs.persistence.directory,sessionID:c,retentionDays:e.logs.persistence.retention_days,maxSessionLogs:e.logs.persistence.max_session_logs,extraMarkers:e.secrets.extra_markers,extraPatterns:e.secrets.extra_patterns},i,l,{standalone:d});if(!f&&!d)u.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 Yu(e,{healthCheckers:t.healthCheckers??by([]),detectGoogle:t.detectGoogle??ro,tokens:s,inspectProcess:By,processAlive:Qt,acquireLock:ym,socketExists:vA,unlinkSocket:xA,procs:o,orchestrator:a,clock:r,fs:n,bus:i,logs:u,detector:l,sessionID:c,createMcpListener:t.createMcpListener??bA,isKnownTool:bc,createCommands:(m)=>zh(m,Ja(Vo({tokens:s})),a)}),orchestrator:a,clock:r,fs:n}}async function Nv(e,t){let r=Zn(e,t),{supervisor:n}=await wA(r),o=!1,i=()=>{if(o)return;o=!0,n.shutdown(wa(r.shutdown)).finally(()=>process.exit(0))};process.on("SIGINT",i),process.on("SIGTERM",i),await n.run()}mt();te();Lf();import{Command as ZO}from"commander";var Rk=["zsh","bash","fish"];function Pk(e){if(e==="zsh")return`#compdef devctl
|
|
659
666
|
_devctl() {
|
|
660
667
|
local -a opts
|
|
661
668
|
local line="\${words[*]}"
|
|
@@ -675,81 +682,91 @@ complete -F _devctl devctl
|
|
|
675
682
|
devctl __complete (commandline -cp)
|
|
676
683
|
end
|
|
677
684
|
complete -c devctl -f -a "(__devctl_complete)"
|
|
678
|
-
`;throw Error(`unsupported shell "${e}"; use ${
|
|
679
|
-
`)
|
|
680
|
-
`)
|
|
681
|
-
`)
|
|
682
|
-
`);
|
|
683
|
-
`)
|
|
684
|
-
`)
|
|
685
|
-
`)}
|
|
686
|
-
`)
|
|
687
|
-
`)}finally{await
|
|
688
|
-
`);
|
|
689
|
-
`)
|
|
690
|
-
`);
|
|
691
|
-
`)
|
|
692
|
-
`);
|
|
685
|
+
`;throw Error(`unsupported shell "${e}"; use ${Rk.join(", ")}`)}function Df(e,t){let r=e.trim().split(/\s+/).filter((l)=>l!==""),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(),c=["start","run","exec","down","daemon","stop","restart","status","logs","doctor","setup","auth","proxy","mcp","config","reload","attach","completion","update","version"];if(i===""||o.length<2)return qr(c,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([...Rk].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);return qr(c,n)}function qr(e,t){if(t==="")return e;return e.filter((r)=>r.startsWith(t))}function be(e){return e.optsWithGlobals().config??""}function E(e){try{process.stdout.write(e)}catch(t){if(t.code==="EPIPE")process.exit(0);throw t}}function _k(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("",be(e)).google.project_id}catch{o=""}let i=await t.detectGoogle(o);if(n.json){E(JSON.stringify(i,null,2)+`
|
|
686
|
+
`);return}if(E(`User: ${i.userEmail||"(unknown)"}
|
|
687
|
+
`),E(`Project: ${i.projectID||"(unset)"}
|
|
688
|
+
`),i.projectID!=="")E(`Source: ${i.projectSource}
|
|
689
|
+
`);E(`ADC: ${i.adcAvailable}
|
|
690
|
+
`),E(`gcloud: ${i.gcloudInstalled}
|
|
691
|
+
`)}),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("",be(e),!1);try{let i=await t.refreshUserToken("user"),s=o.client?await o.refreshAuth():void 0;if(n.json){E(JSON.stringify({identity:i.identity,expires_at:i.expiresAt.toISOString(),service_account_status:s?.service_account_status??{}},null,2)+`
|
|
692
|
+
`);return}if(E(`refreshed credentials expire ${i.expiresAt.toISOString()}
|
|
693
|
+
`),s)for(let[a,c]of Object.entries(s.service_account_status).sort(([l],[d])=>l.localeCompare(d)))E(`service account ${a}: ${c}
|
|
694
|
+
`)}finally{await o.close()}})}te();Tt();of();import{mkdirSync as KO}from"fs";import{basename as qO,dirname as VO}from"path";import{stringify as JO}from"yaml";Pa();function Ek(e,t){e.command("reload").description("reload configuration").action(async()=>{let r=await t.openController("",be(e),!0);try{let n=await r.reload();if(n.restart_required.length===0)E(`configuration reloaded
|
|
695
|
+
`);else E(`configuration reloaded; restart required: ${n.restart_required.join(", ")}
|
|
696
|
+
`);if(n.supervisor_restart_required&&n.supervisor_restart_required.length>0)E(`note: ${Qa(n.supervisor_restart_required)}
|
|
697
|
+
`)}finally{await r.close()}})}function Tk(e,t){let r=e.command("config");r.command("validate").option("--json").action((n)=>{try{let o=t.load("",be(e)),i=t.validate(o);if(n.json){E(JSON.stringify({valid:i.length===0,issues:i},null,2)+`
|
|
698
|
+
`);return}if(i.length>0)throw Error(i.join(`
|
|
699
|
+
`));E(`configuration is valid
|
|
700
|
+
`)}catch(o){if(n.json){E(JSON.stringify({valid:!1,error:A(o)},null,2)+`
|
|
701
|
+
`);return}throw o}}),r.command("diff").description("show where effective configuration values came from").option("--json").action((n)=>{let o=t.load("",be(e)),i=t.configDiff(o);if(n.json){E(JSON.stringify({entries:i},null,2)+`
|
|
702
|
+
`);return}for(let s of i){E(`${s.path} = ${JSON.stringify(s.value)}
|
|
703
|
+
`),E(` winner: ${s.layer} (${s.source})
|
|
704
|
+
`);for(let a of s.shadowed)E(` shadowed: ${a.layer} (${a.source})
|
|
705
|
+
`)}}),r.command("show").option("--json").action((n)=>{let o=t.load("",be(e));if(n.json){E(JSON.stringify(o,null,2)+`
|
|
706
|
+
`);return}E(JO(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}=Od("",be(e)),c=ml(i,qO(s)),l=t.validateConfigText(s,a,c.yaml);if(E(gl(c)),l.length>0){if(E(`validation:
|
|
707
|
+
${l.map((d)=>` ${d}`).join(`
|
|
708
|
+
`)}
|
|
709
|
+
`),o.write===!0)throw Error("refusing to write an invalid mapping");return}if(o.write!==!0){E(`dry-run; pass --write to save under .devctl/config.yaml
|
|
710
|
+
`);return}if(t.fileExists(a))throw Error(`configuration already exists at ${a}; not overwriting`);KO(VO(a),{recursive:!0}),t.writeTextFile(a,c.yaml),E(`wrote ${a}
|
|
711
|
+
`)})}ti();Tt();import{setTimeout as zO}from"timers/promises";function Lk(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("",be(e),!0);try{let s=await i.execService(r,n,o.printEnv===!0);if(s.environment){let a=o.reveal?s.environment:new mr(i.cfg.secrets.extra_markers,i.cfg.secrets.extra_patterns).redactMap(s.environment);if(o.json)E(JSON.stringify({...s,environment:a},null,2)+`
|
|
712
|
+
`);else for(let c of Object.keys(a).sort())E(`${c}=${a[c]}
|
|
713
|
+
`)}else if(o.json)E(JSON.stringify(s,null,2)+`
|
|
714
|
+
`);else{if(s.stdout)E(s.stdout);if(s.stderr)process.stderr.write(s.stderr)}}finally{await i.close()}})}function Dk(e,t){e.command("run").argument("<task>","task to run").option("--json","machine-readable output").action(async(r,n)=>{let o=await t.openController("",be(e),!0);try{let i=await o.runTask(r);if(n.json)E(JSON.stringify(i,null,2)+`
|
|
715
|
+
`);else{if(i.stdout)E(i.stdout);if(i.stderr)process.stderr.write(i.stderr)}}finally{await o.close()}})}function Mk(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("",be(e),!0);try{let i=await o.start({services:r,profile:n.profile,detach:n.detach===!0});if(n.json){E(JSON.stringify(i,null,2)+`
|
|
716
|
+
`);return}if(E(Hh(i)),n.detach)E(`detached; services continue running
|
|
717
|
+
`)}finally{await o.close()}})}function Ok(e,t){e.command("stop").argument("[services...]","services to stop").option("--json","machine-readable output").action(async(r,n)=>{let o=await t.openController("",be(e),!0);try{if(await o.stop(r),n.json)E(JSON.stringify({stopped:r},null,2)+`
|
|
718
|
+
`)}finally{await o.close()}})}function Ik(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("",be(e),!0);try{if(await o.restart(r,n.cascade===!0),n.json)E(JSON.stringify({restarted:r,cascade:n.cascade===!0},null,2)+`
|
|
719
|
+
`)}finally{await o.close()}})}async function Ak(e,t,r){let{repoRoot:n,client:o}=await e.findDaemon("",r.repo??"",be(t));try{if(!o){let s=e.readPersistedState(n);if(r.json){E(JSON.stringify({running:!1,persisted:s},null,2)+`
|
|
720
|
+
`);return}if(E(`supervisor is not running
|
|
721
|
+
`),s&&s.processes.length>0){E(`last session ${s.session_id} profile ${s.profile||"(none)"}
|
|
722
|
+
`);for(let a of s.processes)E(`${a.name} stopped UNKNOWN ${a.pid}
|
|
723
|
+
`)}return}e.assertMethodAllowed(o,"status");let i=await o.call("status",null);if(r.json){E(JSON.stringify(i,null,2)+`
|
|
724
|
+
`);return}E(`PROFILE: ${i.profile||"(none)"}
|
|
693
725
|
|
|
694
726
|
SERVICE STATUS HEALTH PID
|
|
695
|
-
`);for(let[
|
|
696
|
-
`);
|
|
697
|
-
PROXY ${
|
|
698
|
-
`),
|
|
699
|
-
`),
|
|
700
|
-
`),
|
|
701
|
-
`)}finally{
|
|
702
|
-
`),await
|
|
703
|
-
`);try{await
|
|
704
|
-
`);return}let
|
|
727
|
+
`);for(let[s,a]of Object.entries(i.services))E(`${s} ${Jo(a)} ${a.health} ${a.pid}
|
|
728
|
+
`);E(`
|
|
729
|
+
PROXY ${i.proxy.running?"RUNNING":"STOPPED"} ${i.proxy.address??""}
|
|
730
|
+
`),E(`MCP ${i.mcp?.running?"RUNNING":"STOPPED"} ${i.mcp?.address??""}
|
|
731
|
+
`),E(`IDENTITY ${i.identity.user||"(unknown)"}
|
|
732
|
+
`),E(`CLOUD ${i.identity.project||"(unset)"}
|
|
733
|
+
`)}finally{o?.close()}}var YO=2000;function $k(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 Ak(t,e,r);return}let n=new AbortController,o=()=>n.abort();process.on("SIGINT",o),process.on("SIGTERM",o);try{while(!n.signal.aborted){E(`--- ${new Date().toISOString()} ---
|
|
734
|
+
`),await Ak(t,e,r),E(`
|
|
735
|
+
`);try{await zO(YO,void 0,{signal:n.signal})}catch{break}}}finally{process.off("SIGINT",o),process.off("SIGTERM",o)}})}function Fk(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??"",be(e));if(!o){E(`no supervisor is running for ${n}
|
|
736
|
+
`);return}let i=await QO(o);try{let s=r.keepServices!==!0;await o.call("shutdown",{stop_services:s},i)}finally{o.close()}await XO(t,n,i),E(r.keepServices!==!0?`stopped services and the supervisor for ${n}
|
|
705
737
|
`:`stopped the supervisor for ${n}; its services keep running
|
|
706
|
-
`)})}async function
|
|
707
|
-
`}async function
|
|
708
|
-
`:
|
|
709
|
-
`);return}if(
|
|
710
|
-
`);return}for(let
|
|
711
|
-
`)}
|
|
712
|
-
`)
|
|
713
|
-
`)
|
|
714
|
-
`);
|
|
715
|
-
`)
|
|
716
|
-
`)
|
|
717
|
-
`);
|
|
718
|
-
`),
|
|
719
|
-
`)}
|
|
720
|
-
|
|
721
|
-
`),
|
|
722
|
-
`)
|
|
723
|
-
`)
|
|
724
|
-
|
|
725
|
-
`)}finally{await
|
|
726
|
-
`);return}
|
|
727
|
-
`)
|
|
728
|
-
`)
|
|
729
|
-
`)
|
|
730
|
-
`);return}if(
|
|
731
|
-
|
|
732
|
-
`),
|
|
733
|
-
`),
|
|
734
|
-
`),
|
|
735
|
-
|
|
736
|
-
`);P(xv(a,c))}finally{await r.close()}})}function KA(e){let t=e.command("config");t.command("validate").option("--json").action((n)=>{try{let r=ut("",_e(e)),o=Xt(r);if(n.json){P(JSON.stringify({valid:o.length===0,issues:o},null,2)+`
|
|
737
|
-
`);return}if(o.length>0)throw Error(o.join(`
|
|
738
|
-
`));P(`configuration is valid
|
|
739
|
-
`)}catch(r){if(n.json){P(JSON.stringify({valid:!1,error:O(r)},null,2)+`
|
|
740
|
-
`);return}throw r}}),t.command("diff").description("show where effective configuration values came from").option("--json").action((n)=>{let r=ut("",_e(e)),o=vr(r);if(n.json){P(JSON.stringify({entries:o},null,2)+`
|
|
741
|
-
`);return}for(let i of o){P(`${i.path} = ${JSON.stringify(i.value)}
|
|
742
|
-
`),P(` winner: ${i.layer} (${i.source})
|
|
743
|
-
`);for(let s of i.shadowed)P(` shadowed: ${s.layer} (${s.source})
|
|
744
|
-
`)}}),t.command("show").option("--json").action((n)=>{let r=ut("",_e(e));if(n.json){P(JSON.stringify(r,null,2)+`
|
|
745
|
-
`);return}P(kA(r))})}function qA(e){e.command("completion").argument("[shell]","zsh, bash, or fish").description("print a shell completion script").action((t)=>{P(bw(t||"zsh"))}),e.command("__complete",{hidden:!0}).argument("[line...]").description("internal completion helper").action((t)=>{let n=t.join(" "),r=n===""?"devctl ":n;try{let o=ut("",_e(e));P(jp(r,o).join(`
|
|
738
|
+
`)})}async function XO(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 QO(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 Nk(e,t){e.command("attach").action(async()=>{let r=await t.openAttach("",be(e)),{runTuiWithController:n}=await Promise.resolve().then(() => (Lf(),Ck));await n(t,r)})}import{setTimeout as Hk}from"timers/promises";function Mf(e){return`${e.timestamp.slice(11,19)} ${e.service.padEnd(10)} ${String(e.level).padEnd(6)} ${e.message}
|
|
739
|
+
`}async function Bk(e,t,r,n=1000){let o=await e(void 0);o.events.forEach(t);let i=o.nextCursor;while(!r.aborted){try{await Hk(n,void 0,{signal:r})}catch{return}o=await e(i),o.events.forEach(t),i=o.nextCursor}}function Wk(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("--output <path>","export path").option("--json","machine-readable 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("",be(e),!0);try{let s=o.output?t.resolveExportPath(o.output):void 0;if(o.follow&&!s){let c=new AbortController,l=()=>c.abort();process.on("SIGINT",l),process.on("SIGTERM",l);try{await Bk((d)=>i.logsPage({services:n,level:o.level,search:o.search,regex:o.regex,source:o.source,since:o.since,until:o.until,cursor:d,direction:"forward"}),(d)=>E(o.json?JSON.stringify(d)+`
|
|
740
|
+
`:Mf(d)),c.signal)}finally{process.off("SIGINT",l),process.off("SIGTERM",l)}return}if(s||o.all===!0){let c=await i.logs({services:n,level:o.level,search:o.search,regex:o.regex,source:o.source,since:o.since,until:o.until,export:s});if(s){E(`exported ${s}
|
|
741
|
+
`);return}if(o.json){E(JSON.stringify(c,null,2)+`
|
|
742
|
+
`);return}for(let l of c)E(Mf(l));return}let a=await i.logsPage({services:n,level:o.level,search:o.search,regex:o.regex,source:o.source,since:o.since,until:o.until,direction:"backward"});if(o.json){E(JSON.stringify(a.events,null,2)+`
|
|
743
|
+
`);return}for(let c of a.events)E(Mf(c));if(a.hasPrev)E(`\u2026 older matching events omitted; pass --all for the full history
|
|
744
|
+
`)}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("",be(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}),E(`exported ${s}
|
|
745
|
+
`)}finally{await i.close()}})}function jk(e,t){e.command("daemon").command("logs").option("-f, --follow","keep printing new lines until interrupted").action(async(r)=>{let{repoRoot:n}=t.discover("",be(e)),o=t.bootstrapLogPath(n),i=0,s=()=>{if(!t.fileExists(o))return;let l=t.readTextFile(o);if(l.length>i)E(l.slice(i)),i=l.length};if(!t.fileExists(o))E(`no daemon bootstrap log yet for this repository
|
|
746
|
+
`);else s();if(!r.follow)return;let a=new AbortController,c=()=>a.abort();process.on("SIGINT",c),process.on("SIGTERM",c);try{while(!a.signal.aborted){try{await Hk(500,void 0,{signal:a.signal})}catch{break}s()}}finally{process.off("SIGINT",c),process.off("SIGTERM",c)}})}ul();function Gk(e,t){let r=e.command("proxy");r.command("status").option("--json").action(async(n)=>{let o=await t.openController("",be(e),!1);try{if(!o.client){E(`PROXY STOPPED
|
|
747
|
+
`);return}let i=await o.status();if(n.json){E(JSON.stringify(i.proxy,null,2)+`
|
|
748
|
+
`);return}E(`PROXY ${i.proxy.running?"RUNNING":"STOPPED"} ${i.proxy.address??""}
|
|
749
|
+
`);for(let s of i.proxy.routes??[]){let a=s.match?` match=${s.match}`:"";E(` ${s.name.padEnd(16)} identity=${s.identity}${a} ${s.upstream}
|
|
750
|
+
`)}}finally{await o.close()}}),r.command("start").action(async()=>{let n=await t.openController("",be(e),!0);try{await n.proxyStart()}finally{await n.close()}}),r.command("stop").action(async()=>{let n=await t.openController("",be(e),!0);try{await n.proxyStop()}finally{await n.close()}})}function Uk(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("",be(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??lo(o.cfg.repoRoot),c=i?.mcp?.address??ui(a),l=i?.mcp?.token??"";if(r.json){E(JSON.stringify({running:i?.mcp?.running===!0,setup_mode:i?.setup_mode===!0,url:c,port:a,snippets:{claude:JSON.parse(Hp(c,l)),cursor:JSON.parse(Bp(c,l)),kilo:JSON.parse(Wp(c,l)),codex:jp(c,l)}},null,2)+`
|
|
751
|
+
`);return}if(E(`MCP ${i?.mcp?.running?"RUNNING":"STOPPED"} ${c}
|
|
752
|
+
|
|
753
|
+
`),i?.setup_mode===!0)E(`This repository has no .devctl yet, so the daemon is in setup mode.
|
|
754
|
+
`),E(`Connect an agent with the config below and ask it to set devctl up for this repository.
|
|
755
|
+
`),E(`It can call get_setup_guide and validate_config; nothing will run until a configuration exists.
|
|
756
|
+
|
|
757
|
+
`);E(Bb(c,l))}finally{await o.close()}})}te();function Kk(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){E(JSON.stringify(n,null,2)+`
|
|
758
|
+
`);return}if(E(`current ${n.current}
|
|
759
|
+
`),E(`latest ${n.latest||"(unavailable)"}
|
|
760
|
+
`),E(`channel ${n.kind}
|
|
761
|
+
`),!n.newer){if(n.latest!=="")E(`up to date
|
|
762
|
+
`);return}if(E(`install ${n.hint}
|
|
763
|
+
`),r.check||!n.command)return;if(E(`installing via ${n.kind}\u2026
|
|
764
|
+
`),(await t.applyUpdate(n.command,!0)).code!==0){process.exitCode=Qm;return}E(`updated to ${n.latest}; ${sc}
|
|
765
|
+
`)})}function eI(e,t){let r=new ZO;return r.name("devctl").description("Local development orchestrator").version(er(),"-V, --version","print version").option("--config <path>","path to config file or .devctl directory").enablePositionalOptions(),r.command("version").description("print version").action(()=>{E(`${er()}
|
|
766
|
+
`)}),r.action(async()=>{let n=r.opts();await Tf(e,n.config??"")}),Mk(r,e),Ok(r,e),Ik(r,e),Dk(r,e),Lk(r,e),$k(r,e),Fk(r,e),Wk(r,e),jk(r,e),tI(r,e),rI(r,e),_k(r,e),Gk(r,e),Uk(r,e),Tk(r,e),Ek(r,e),Nk(r,e),nI(r,e),Kk(r,e),oI(r,t),r}function tI(e,t){e.command("doctor").option("--json","machine-readable output").action(async(r)=>{let n=t.load("",be(e)),o=await t.runDoctor.execute(n);if(r.json)E(JSON.stringify(o,null,2)+`
|
|
767
|
+
`);else E(t.formatDoctor(o));if(o.issues>0)process.exitCode=2})}function rI(e,t){e.command("setup").option("--force","overwrite an existing configuration").action(async(r)=>{await t.runSetup("",be(e),r.force===!0)})}function nI(e,t){e.command("completion").argument("[shell]","zsh, bash, or fish").description("print a shell completion script").action((r)=>{E(Pk(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("",be(e));E(Df(o,i).join(`
|
|
746
768
|
`)+`
|
|
747
|
-
`)}catch{
|
|
769
|
+
`)}catch{E(Df(o,Jn()).join(`
|
|
748
770
|
`)+`
|
|
749
|
-
`)}})}function
|
|
750
|
-
`)
|
|
751
|
-
`),P(`latest ${n.latest||"(unavailable)"}
|
|
752
|
-
`),n.newer)P(`install ${n.hint}
|
|
753
|
-
`);else if(n.latest!=="")P(`up to date
|
|
754
|
-
`)})}function JA(e){e.command("attach").action(async()=>{let t=await um("",_e(e)),{runTuiWithController:n}=await Promise.resolve().then(() => (Hp(),yw));await n(t)})}function zA(e){e.command("_supervisor").option("--repo <path>","repository root").action(async(t)=>{let n=yi(t.repo??"",_e(e)),r=new yu(n),o=!1,i=()=>{if(o)return;o=!0,r.shutdown(Us(n.shutdown)).finally(()=>process.exit(0))};process.on("SIGINT",i),process.on("SIGTERM",i),await r.run()})}async function Cw(){process.stdout.on("error",(e)=>{if(e.code==="EPIPE")process.exit(0)});try{await _A().parseAsync(process.argv)}catch(e){process.stderr.write(O(e)+`
|
|
755
|
-
`),process.exit(If(e))}}function P(e){try{process.stdout.write(e)}catch(t){if(t.code==="EPIPE")process.exit(0);throw t}}$s();await Cw();
|
|
771
|
+
`)}})}function oI(e,t){e.command("_supervisor").option("--repo <path>","repository root").action(async(r)=>{await t(r.repo??"",be(e))})}async function qk(e,t){process.stdout.on("error",(r)=>{if(r.code==="EPIPE")process.exit(0)});try{await eI(e,t).parseAsync(process.argv)}catch(r){process.stderr.write(A(r)+`
|
|
772
|
+
`),process.exit(eg(r))}}Gs();await qk(xy(),Nv);
|