@amr-m-abdelgawad/devctl 0.1.4 → 0.2.0
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 +150 -116
- package/package.json +1 -1
package/dist/devctl.js
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
var
|
|
4
|
-
`)}function Xp(e,t){let r=uw(e);if(Rr(r)){let n=gw(r);if(n&&Rt(n.pid))throw Error(`supervisor already running (pid ${n.pid})`);try{Wc(r)}catch{}}return $t(r,JSON.stringify({pid:process.pid,socket:t})),{release:()=>{try{Wc(r)}catch{}}}}function gw(e){if(!Rr(e))return;try{let t=JSON.parse(Kc(e,"utf8"));if(typeof t.pid==="number"&&typeof t.socket==="string")return{pid:t.pid,socket:t.socket}}catch{return}return}function Rt(e){if(e<=0)return!1;if(process.platform==="win32")return mw(e);try{return process.kill(e,0),!0}catch{return!1}}function Yc(e){try{let t=Qb("cmd.exe",["/d","/c",`tasklist /FO CSV /NH /FI "PID eq ${e}"`],{encoding:"buffer",windowsHide:!0,timeout:5000});return hw(t.stdout)}catch{return""}}function mw(e){try{return process.kill(e,0),!0}catch{}let t=Yc(e).toLowerCase();if(t===""||t.includes("no tasks")||t.includes("no matching"))return!1;return t.includes(String(e))}function hw(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 zc(){return Uc(24).toString("hex")}function yw(e){return st($n(e),"mcp-token")}function Qp(e){let t=yw(e);if(Rr(t)){let n=Kc(t,"utf8").trim();if(n!=="")return n}let r=zc();return $t(t,r),r}var cw=448,lw=384,dw=16,pw=5,Jp="bootstrap-";var Ye=()=>{};function ms(){return{args:[],shell:!1}}function Qc(){return{vars:{},required:[],defaults:{}}}function Zc(){return{type:"",url:"",address:"",command:ms(),interval_seconds:0,timeout_seconds:0}}function el(){return{type:"",mode:"",service_account:""}}function Nn(){return{extends:"",description:"",command:ms(),shell:!1,working_dir:"",dependencies:[],ports:[],environment:Qc(),health:Zc(),identity:el(),logs:{stdout:!1,stderr:!1},restart:{policy:"",max_retries:0,backoff_seconds:0},startup:{wait_for_healthy:!1,timeout_seconds:0},capabilities:[],proxy:[]}}function Jr(){return{version:1,project:{name:""},google:{project_id:"",region:""},profiles:{},templates:{},services:{},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:{}},repoRoot:"",configPath:""}}function tl(e){return e.args.length===0||e.args.length===1&&(e.args[0]??"").trim()===""}function Ko(e){if(e.type!=="")return e.type;return e.mode}function ar(e){let t=Ko(e).toLowerCase();return t==="service"||t==="service_account"}function rf(e){let t=Ko(e).toLowerCase();return t==="user"||t===""}function nf(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 Yr(e){let t=e.host===""?"127.0.0.1":e.host;if(e.port===0)return t;return`${t}:${e.port}`}function hs(e){if(e.refresh_threshold_seconds<=0)return 300;return e.refresh_threshold_seconds}function ys(e){if(e.stop_services_on_exit===void 0)return!0;return e.stop_services_on_exit}function vs(e){if(e.grace_seconds<=0)return 10;return e.grace_seconds}function of(e){if(!e.logs.stdout&&!e.logs.stderr)return!0;return e.logs.stdout}function sf(e){if(!e.logs.stdout&&!e.logs.stderr)return!0;return e.logs.stderr}function rl(e,t){return e.find((r)=>r.name===t)}function af(e){return e[0]}var Fn=1,Zp="never",ef="on_failure",tf="always",gs=8080,Xc="127.0.0.1";function G(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function ol(e){return G(e)?new Set(Object.keys(e)):new Set}function q(e){if(typeof e==="string")return e;if(typeof e==="number"||typeof e==="boolean")return String(e);return""}function Ve(e){if(typeof e==="number")return e;if(typeof e==="string"){let t=Number(e);return Number.isNaN(t)?0:t}return 0}function ft(e){return e===!0}function Dt(e){if(!Array.isArray(e))return[];return e.map((t)=>q(t))}function Xr(e){if(!G(e))return{};let t={};for(let[r,n]of Object.entries(e))t[r]=q(n);return t}function qo(e){if(typeof e==="string")return{args:e.split(/\s+/).filter((t)=>t!==""),shell:!1};if(Array.isArray(e))return{args:e.map((t)=>q(t)),shell:!1};return ms()}function il(e){if(e===void 0||e===null)return[];if(typeof e==="string"||typeof e==="number")return[nl(e,"http")];if(Array.isArray(e))return e.map((t,r)=>nl(t,`port_${r}`));if(G(e))return Object.entries(e).map(([t,r])=>nl(r,t));return[]}function nl(e,t){if(typeof e==="string"&&e.toLowerCase()==="auto")return{name:t,value:0,auto:!0};return{name:t,value:Ve(e),auto:!1}}function vw(e){if(!G(e))return Qc();let t={},r=[],n={};for(let[o,i]of Object.entries(e))if(o==="required")r=Dt(i);else if(o==="defaults")n=Xr(i);else t[o]=q(i);return{vars:t,required:r,defaults:n}}function xw(e){if(!G(e))return el();return{type:q(e.type),mode:q(e.mode),service_account:q(e.service_account)}}function bw(e){if(!G(e))return Zc();return{type:q(e.type),url:q(e.url),address:q(e.address),command:qo(e.command),interval_seconds:Ve(e.interval_seconds),timeout_seconds:Ve(e.timeout_seconds)}}function ww(e){if(!G(e))return{policy:"",max_retries:0,backoff_seconds:0};return{enabled:e.enabled===void 0?void 0:ft(e.enabled),policy:q(e.policy),max_retries:Ve(e.max_retries),backoff_seconds:Ve(e.backoff_seconds)}}function Sw(e){if(!G(e))return{wait_for_healthy:!1,timeout_seconds:0};return{wait_for_healthy:ft(e.wait_for_healthy),timeout_seconds:Ve(e.timeout_seconds)}}function Vo(e){if(!G(e))return Nn();let t=G(e.logs)?e.logs:{};return{extends:q(e.extends),description:q(e.description),command:qo(e.command),shell:ft(e.shell),working_dir:q(e.working_dir),dependencies:Dt(e.dependencies),ports:il(e.ports),environment:vw(e.environment),health:bw(e.health),identity:xw(e.identity),logs:{stdout:ft(t.stdout),stderr:ft(t.stderr)},restart:ww(e.restart),startup:Sw(e.startup),capabilities:Dt(e.capabilities),proxy:sl(e.proxy)}}function sl(e){if(e===void 0||e===null)return[];if(Array.isArray(e))return e.map((t)=>zr(t));if(G(e))return[zr(e)];return[]}function xs(e){if(!G(e))return{services:[],environment:{}};return{services:Dt(e.services),environment:Xr(e.environment)}}function kw(e){if(typeof e==="string")return{type:e,service_account:""};if(!G(e))return{type:"",service_account:""};return{type:q(e.type),service_account:q(e.service_account)}}function Cw(e){if(!G(e))return{type:"",identity:{type:"",service_account:""},audience:"",service_account:""};return{type:q(e.type),identity:kw(e.identity),audience:q(e.audience),service_account:q(e.service_account)}}function zr(e){if(!G(e))return{name:"",match:{host:"",path:""},upstream:{url:""},auth:{type:"",identity:{type:"",service_account:""},audience:"",service_account:""}};let t=G(e.match)?e.match:{},r=G(e.upstream)?e.upstream:{};return{name:q(e.name),match:{host:q(t.host),path:q(t.path)},upstream:{url:q(r.url)},auth:Cw(e.auth)}}var al=()=>{};import{existsSync as _w,statSync as lf}from"fs";import{basename as cf,dirname as bs,isAbsolute as Rw,join as ws,resolve as df}from"path";function Pr(e,t){if(t!=="")return Pw(t);let r=e===""?process.cwd():e;r=Rw(r)?r:df(r);for(;;){let n=ws(r,wt,Ft);if(Jo(n))return{repoRoot:r,configPath:n};let o=ws(r,"devctl.yaml");if(Jo(o))return{repoRoot:r,configPath:o};let i=bs(r);if(i===r)break;r=i}throw be(Kr,"no devctl configuration found","run `devctl setup` or create a .devctl/config.yaml in the repository root")}function Pw(e){let t=df(e),r;try{r=lf(t)}catch(o){throw ye(Kr,"config path not found",o)}if(r.isDirectory()){if(cf(t)===wt)return{repoRoot:bs(t),configPath:ws(t,Ft)};return{repoRoot:t,configPath:ws(t,Ft)}}let n=bs(t);if(cf(n)===wt)n=bs(n);return{repoRoot:n,configPath:t}}function Jo(e){return _w(e)&&!lf(e).isDirectory()}var wt=".devctl",Ft="config.yaml";var Yo=T(()=>{_e()});function Cs(){return{services:{},templates:{}}}function Ss(e,t,r){let n=ol(r);if(G(r))for(let i of Ew){let s=r[i];if(G(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 uf(e,t,r=Cs()){if(t.version!==void 0)e.version=Ve(t.version);if(G(t.project)&&t.project.name!==void 0)e.project.name=q(t.project.name);if(G(t.google)){if(t.google.project_id!==void 0)e.google.project_id=q(t.google.project_id);if(t.google.region!==void 0)e.google.region=q(t.google.region)}if(G(t.profiles))for(let[n,o]of Object.entries(t.profiles)){let i=e.profiles[n];e.profiles[n]=i?Aw(i,o):xs(o)}if(G(t.templates))for(let[n,o]of Object.entries(t.templates)){let i=e.templates[n];e.templates[n]=i?ks(i,o):Vo(o),Ss(r.templates,n,o)}if(G(t.services))for(let[n,o]of Object.entries(t.services)){let i=e.services[n];e.services[n]=i?ks(i,o):Vo(o),Ss(r.services,n,o)}if(G(t.proxy))Tw(e.proxy,t.proxy);if(G(t.logs)){if(t.logs.max_memory_events!==void 0)e.logs.max_memory_events=Ve(t.logs.max_memory_events);if(G(t.logs.persistence)){let n=t.logs.persistence;if(n.enabled!==void 0)e.logs.persistence.enabled=ft(n.enabled);if(n.directory!==void 0)e.logs.persistence.directory=q(n.directory);if(n.retention_days!==void 0)e.logs.persistence.retention_days=Ve(n.retention_days);if(n.max_session_logs!==void 0)e.logs.persistence.max_session_logs=Ve(n.max_session_logs)}}if(G(t.auth)&&t.auth.refresh_threshold_seconds!==void 0)e.auth.refresh_threshold_seconds=Ve(t.auth.refresh_threshold_seconds);if(G(t.shutdown)){if(t.shutdown.stop_services_on_exit!==void 0)e.shutdown.stop_services_on_exit=ft(t.shutdown.stop_services_on_exit);if(t.shutdown.grace_seconds!==void 0)e.shutdown.grace_seconds=Ve(t.shutdown.grace_seconds)}if(G(t.ui)){if(t.ui.theme!==void 0)e.ui.theme=q(t.ui.theme);if(t.ui.keymap!==void 0)e.ui.keymap=Xr(t.ui.keymap)}if(G(t.secrets)){if(t.secrets.extra_markers!==void 0)e.secrets.extra_markers=Dt(t.secrets.extra_markers);if(t.secrets.extra_patterns!==void 0)e.secrets.extra_patterns=Dt(t.secrets.extra_patterns)}if(G(t.doctor)&&Array.isArray(t.doctor.tools))e.doctor.tools=t.doctor.tools.filter(G).map((n)=>({name:q(n.name),command:q(n.command)}));if(Array.isArray(t.plugins))e.plugins=t.plugins.filter(G).map((n)=>({path:q(n.path)})).filter((n)=>n.path!=="");if(G(t.environment)){if(Array.isArray(t.environment.sources))e.environment.sources=Dt(t.environment.sources);if(G(t.environment.secrets))e.environment.secrets={...e.environment.secrets,...Xr(t.environment.secrets)}}}function Tw(e,t){if(t.enabled!==void 0)e.enabled=ft(t.enabled);if(G(t.listen)){if(t.listen.host!==void 0)e.listen.host=q(t.listen.host);if(t.listen.port!==void 0)e.listen.port=Ve(t.listen.port)}if(G(t.token_endpoint)){let r=t.token_endpoint;if(r.enabled!==void 0)e.token_endpoint.enabled=ft(r.enabled);if(r.host!==void 0)e.token_endpoint.host=q(r.host);if(r.port!==void 0)e.token_endpoint.port=Ve(r.port)}if(Array.isArray(t.routes))e.routes=t.routes.map((r)=>zr(r))}function Aw(e,t){if(!G(t))return e;return{services:t.services!==void 0?Dt(t.services):e.services,environment:t.environment!==void 0?{...e.environment,...Xr(t.environment)}:e.environment}}function ks(e,t){if(!G(t))return e;let r=ol(t),n={...e,environment:Lw(e.environment,t.environment),health:Dw(e.health,t.health),identity:Mw(e.identity,t.identity),logs:Ow(e.logs,t.logs),restart:Iw(e.restart,t.restart),startup:$w(e.startup,t.startup)};if(r.has("extends"))n.extends=q(t.extends);if(r.has("description"))n.description=q(t.description);if(r.has("command"))n.command=qo(t.command);if(r.has("shell"))n.shell=ft(t.shell);if(r.has("working_dir"))n.working_dir=q(t.working_dir);if(r.has("dependencies"))n.dependencies=Dt(t.dependencies);if(r.has("ports"))n.ports=il(t.ports);if(r.has("capabilities"))n.capabilities=Dt(t.capabilities);if(r.has("proxy"))n.proxy=sl(t.proxy);return n}function Lw(e,t){if(!G(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=Dt(s);else if(i==="defaults")Object.assign(n,Xr(s));else r[i]=q(s);return{vars:r,required:o,defaults:n}}function Dw(e,t){if(!G(t))return e;return{type:t.type!==void 0?q(t.type):e.type,url:t.url!==void 0?q(t.url):e.url,address:t.address!==void 0?q(t.address):e.address,command:t.command!==void 0?qo(t.command):e.command,interval_seconds:t.interval_seconds!==void 0?Ve(t.interval_seconds):e.interval_seconds,timeout_seconds:t.timeout_seconds!==void 0?Ve(t.timeout_seconds):e.timeout_seconds}}function Mw(e,t){if(!G(t))return e;return{type:t.type!==void 0?q(t.type):e.type,mode:t.mode!==void 0?q(t.mode):e.mode,service_account:t.service_account!==void 0?q(t.service_account):e.service_account}}function Ow(e,t){if(!G(t))return e;return{stdout:t.stdout!==void 0?ft(t.stdout):e.stdout,stderr:t.stderr!==void 0?ft(t.stderr):e.stderr}}function Iw(e,t){if(!G(t))return e;return{enabled:t.enabled!==void 0?ft(t.enabled):e.enabled,policy:t.policy!==void 0?q(t.policy):e.policy,max_retries:t.max_retries!==void 0?Ve(t.max_retries):e.max_retries,backoff_seconds:t.backoff_seconds!==void 0?Ve(t.backoff_seconds):e.backoff_seconds}}function $w(e,t){if(!G(t))return e;return{wait_for_healthy:t.wait_for_healthy!==void 0?ft(t.wait_for_healthy):e.wait_for_healthy,timeout_seconds:t.timeout_seconds!==void 0?Ve(t.timeout_seconds):e.timeout_seconds}}function pf(e){let t=Object.keys(e.services).sort();for(let r of t){let n=e.services[r]?.proxy??[];if(n.length===0)continue;n.forEach((o,i)=>{let s=n.length===1?r:`${r}-${i+1}`;e.proxy.routes.push({name:s,match:o.match,upstream:o.upstream,auth:o.auth})})}}function ff(e,t=Cs()){if(Object.keys(e.templates).length===0)return;let r={};for(let[n,o]of Object.entries(e.services))r[n]=gf(e,o,t.services[n]??new Set,t,{});e.services=r}function gf(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]??Nn();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=gf(e,i,a,n,s),l=Fw(c,t,r);return l.extends=t.extends,l}function Fw(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;return 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},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},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}var Ew;var mf=T(()=>{al();Ew=["environment","restart","startup","health","logs","identity"]});function cl(e){if(e.version===0)throw M(X,"version is required");if(e.version===Fn)return e;throw M(X,`unsupported config version ${e.version} (expected ${Fn}); no migration is available`)}var ll=T(()=>{_e()});var hf,yf,vf,xf,bf,wf,Sf,kf,dl,ul,pl,fl,Cf,_f,Rf,Pf,Ef,Tf,Af,Lf,Df,Mf,Of,If,$f,Ff,Nf,Hf,jf,Bf;var gl=T(()=>{hf=["version","project","google","profiles","templates","services","proxy","logs","auth","shutdown","ui","secrets","doctor","plugins","environment"],yf=["extends","description","command","shell","working_dir","dependencies","ports","environment","health","identity","logs","restart","startup","capabilities","proxy"],vf=["type","url","address","command","interval_seconds","timeout_seconds"],xf=["type","mode","service_account"],bf=["enabled","policy","max_retries","backoff_seconds"],wf=["wait_for_healthy","timeout_seconds"],Sf=["enabled","listen","token_endpoint","routes"],kf=["host","port"],dl=["name","match","upstream","auth"],ul=["host","path"],pl=["url"],fl=["type","identity","audience","service_account"],Cf=["max_memory_events","persistence"],_f=["enabled","directory","retention_days","max_session_logs"],Rf=["refresh_threshold_seconds"],Pf=["stop_services_on_exit","grace_seconds"],Ef=["theme","keymap"],Tf=["name"],Af=["project_id","region"],Lf=["services","environment"],Df=["required","defaults"],Mf=["stdout","stderr"],Of=["extra_markers","extra_patterns"],If=["tools"],$f=["name","command"],Ff=["enabled","host","port"],Nf=["path"],Hf=["sources","secrets"],jf=["google","google_api","iap","network","service_identity","local_http"],Bf=["|","||","&&",";",">",">>","<","&"]});function Qr(e,t){if(!qw(e))return[];let r=jw(t),n=[];for(let o of Object.keys(e)){let i=Kw(t,o);if(r.length>0&&!r.includes(o)&&!Hw(t))n.push(i);n.push(...Qr(e[o],i))}return n}function Hw(e){if(e==="services"||e==="profiles"||e==="templates")return!0;if(e.endsWith(".environment")||e.endsWith(".defaults")||e.endsWith(".keymap"))return!0;return e.includes(".environment.")&&!e.endsWith(".environment")}function jw(e){switch(e){case"":return hf;case"project":return Tf;case"google":return Af;case"proxy":return Sf;case"proxy.listen":return kf;case"proxy.token_endpoint":return Ff;case"logs":return Cf;case"logs.persistence":return _f;case"auth":return Rf;case"shutdown":return Pf;case"ui":return Ef;case"secrets":return Of;case"doctor":return If;case"environment":return Hf;default:return Bw(e)}}function Bw(e){if(e==="services"||e==="profiles"||e==="templates")return[];if(e.startsWith("services.")||e.startsWith("templates."))return Ww(e);if(e.startsWith("profiles.")){if(e.split(".").length===2)return Lf}if(e.includes("routes"))return Uw(e);if(e.startsWith("doctor.tools")&&e.split(".").length>=3)return $f;if(e==="plugins")return[];if(e.startsWith("plugins.")&&e.split(".").length===2)return Nf;return[]}function Ww(e){let t=e.split(".");if(t.length===2)return yf;if(t.length>=3)switch(t[2]){case"health":return vf;case"identity":return xf;case"restart":return bf;case"startup":return wf;case"logs":return Mf;case"environment":return Df;case"proxy":return Gw(t);default:return[]}return[]}function Gw(e){let t=e.slice(3),r=t[0]!==void 0&&/^\d+$/.test(t[0])?1:0,n=t[r]??"";if(n==="match")return ul;if(n==="upstream")return pl;if(n==="auth")return fl;return dl}function Uw(e){if(e==="proxy.routes")return[];if(e.endsWith(".match"))return ul;if(e.endsWith(".upstream"))return pl;if(e.endsWith(".auth"))return fl;if(e.includes("proxy.routes")&&e.split(".").length===Nw+1)return dl;return[]}function Kw(e,t){if(e==="")return t;return`${e}.${t}`}function qw(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Hn(e){return`unknown fields: ${e.join(", ")}`}var Nw=2;var Wf=T(()=>{gl()});function Gf(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+=Vw(a,t,r),n=n.slice(i+s+1)}}function Vw(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=af(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=rl(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 ml(e,t,r){let n={};for(let[o,i]of Object.entries(e))n[o]=Gf(i,t,r);return n}function Uf(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 Kf(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 rl(n.ports,o)!==void 0}}return!0}var hl=()=>{};function xl(e){let t=[];for(let[r,n]of Object.entries(e.services)){let o=n.health.type;if(o!==""&&!Jf.includes(o.toLowerCase()))t.push({service:r,type:o})}return t}function Ut(e){let t=[];if(e.version===0)t.push("version is required");else if(e.version!==Fn)t.push(`unsupported config version ${e.version} (expected ${Fn}); no migration is available`);if(Object.keys(e.services).length===0)t.push("at least one service must be defined");if(t.push(...Yw(e)),t.push(...Zw(e)),t.push(...tS(e)),t.push(...rS(e)),e.logs.max_memory_events<0)t.push("logs.max_memory_events must be >= 0");return t}function Yw(e){let t=[],r={};for(let[n,o]of Object.entries(e.services)){let i=`services.${n}`;if(tl(o.command))t.push(`${i}.command is required`);t.push(...oS(i,o.command,o.shell)),t.push(...iS(i,o.capabilities));for(let c of o.dependencies){if(!e.services[c])t.push(`${i}.dependencies: unknown service "${c}"`);if(c===n)t.push(`${i}.dependencies: service cannot depend on itself`)}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<vl||c.value>yl)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=Qw(`${i}.identity`,o.identity,e.plugins.length>0);if(s!=="")t.push(s);t.push(...zw(i,o,e.plugins.length>0));let a=nf(o.restart);if(a!==Zp&&a!==ef&&a!==tf)t.push(`${i}.restart.policy must be never, on_failure, or always`);t.push(...eS(`${i}.environment`,o.environment,e))}return t}function zw(e,t,r){let n=[];if(t.health.type==="")return n;let o=t.health.type.toLowerCase();if(!Jf.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"&&tl({args:t.health.command.args,shell:!1}))n.push(`${e}.health.command is required for command health checks`);return n}function Qw(e,t,r){let n=Ko(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 bl(e){let t=[];for(let[r,n]of Object.entries(e.services)){let o=Ko(n.identity).toLowerCase();if(!Xw.includes(o))t.push({service:r,type:o})}return t}function Zw(e){let t={},r=[],n=[],o=(i)=>{let s=t[i]??Jw;if(s===Vf)return;if(s===qf){r.push(`dependency cycle: ${[...n,i].join(" \u2192 ")}`);return}t[i]=qf,n.push(i);let a=e.services[i];if(a){for(let c of a.dependencies)if(e.services[c])o(c)}n.pop(),t[i]=Vf};for(let i of Object.keys(e.services))o(i);return r}function eS(e,t,r){let n=[],o=(i,s)=>{for(let a of Uf(s))if(!Kf(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 tS(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 rS(e){let t=[];if(e.proxy.listen.host!==""&&!sS(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<vl||e.proxy.listen.port>yl))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"||ar({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(...nS(e)),t}function nS(e){let t=[],r=e.proxy.token_endpoint;if(!r.enabled)return t;let n=r.host||Xc;if(n==="0.0.0.0")t.push("proxy.token_endpoint.host must be a loopback address");else if(n!==""&&n!==Xc&&n!=="localhost"&&!n.startsWith("127."))t.push("proxy.token_endpoint.host must be a loopback address");if(r.port!==0&&(r.port<vl||r.port>yl))t.push("proxy.token_endpoint.port is invalid");return t}function oS(e,t,r){if(t.shell||r)return[];for(let n of t.args)if(Bf.includes(n)||n.includes("|")||n.includes(";")||n.includes("&&"))return[`${e}.command contains shell metacharacters; set shell: true to run via a shell`];return[]}function iS(e,t){let r=[];for(let n of t)if(!jf.includes(n))r.push(`${e}.capabilities: unknown capability "${n}"`);return r}function sS(e){if(e==="localhost")return!0;return aS(e)}function aS(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(":")}var yl=65535,vl=1,Jf,Jw=0,qf=1,Vf=2,Xw;var _s=T(()=>{gl();hl();Jf=["http","tcp","process","command"];Xw=["","user","service","service_account"]});import{readdirSync as cS,readFileSync as lS}from"fs";import{basename as zf,dirname as dS,extname as uS,join as Zr,resolve as pS}from"path";import{parse as fS}from"yaml";function jn(e,t,r){try{return Xo(e,t,{candidateText:r}),[]}catch(n){if(n instanceof Te){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 gt(e,t){let{repoRoot:r,configPath:n}=Pr(e,t);return Xo(r,n)}function zo(e,t){try{return gt(e,t)}catch(r){if(!ds(r,Kr))throw r;let n=e===""?process.cwd():pS(e),o=Jr();return o.repoRoot=n,o.configPath=Zr(n,wt,Ft),o}}function Xo(e,t,r){let n=Jr(),o=Cs();Xf(t,n,o,r?.candidateText),n.repoRoot=e,n.configPath=t;let i=dS(t);if(zf(i)===wt)mS(i,n,o);n=gS(n,e,t,o),n=cl(n);try{ff(n,o)}catch(a){throw ye(X,"template merge failed",a)}pf(n);let s=Ut(n);if(s.length>0)throw M(X,s.join(`
|
|
5
|
-
`));return
|
|
6
|
-
`);this.buf=
|
|
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
|
|
8
|
-
`)}async function Ll(e,t,r=""){let n=Rs(e,t,r);if(!n)throw be(nt,"no devctl configuration found","run `devctl setup`, create a .devctl/config.yaml in the repository root, or pass --repo");let o=await en(n.repoRoot);return ti(o),{repoRoot:n.repoRoot,client:o}}async function Mt(e,t,r,n){let o=n?.allowMissingConfig===!0?zo(e,t):gt(e,t),i=new Es(o);if(!r)return i.client=await en(o.repoRoot),ti(i.client),i;return i.client=await lg(o.repoRoot,o.configPath),ti(i.client),i}async function dg(e){let t=new Es(Jr());return t.client=e,ti(t.client),t.cfg=await t.configSnapshot(),t}async function ug(e,t){let r=Rs(e,"",t),n=r?await en(r.repoRoot):void 0;if(!n)throw be(nt,"supervisor is not running","run `devctl start` before `devctl attach`");return dg(n)}async function pg(e,t){let r=Rs(e,"",t),n=r?await en(r.repoRoot):void 0;if(n)return dg(n);let o=gt(e,t),i=new Es(o);return i.client=await lg(o.repoRoot,o.configPath),ti(i.client),i.cfg=await i.configSnapshot(),i}var DS=50,sg=8000,MS=200,OS=30000,IS;var Dl=T(()=>{St();rg();Tl();_e();Ye();IS=new Set(["logs","logs_page","logs_stats"])});function As(e){if(ar(e))return Nt({kind:tn,serviceAccount:e.service_account});if(rf(e)&&(e.type!==""||e.mode!==""))return Nt({kind:Ts});return Nt({kind:Bn})}function Wn(e){if(e.type.toLowerCase()==="none")return Nt({kind:Bn});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 Nt({kind:tn,serviceAccount:r});if(e.type.toLowerCase()==="iap"&&t==="")return Nt({kind:Bn});if(e.type===""&&t==="")return Nt({kind:Bn});return Nt({kind:Ts})}function Ls(e){return e.kind===Ts||e.kind===tn}function ri(e){if(e.kind===tn)return`sa:${e.serviceAccount}`;if(e.email!=="")return`user:${e.email}`;return"user"}function Nt(e={}){return{kind:Bn,email:"",serviceAccount:"",project:"",projectSource:"",adcAvailable:!1,...e}}function Ml(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(ar(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 Er(e){return Ml(e).filter((t)=>t.active).map((t)=>t.email)}function fg(e,t,r){let n=[];for(let o of t){let i=e.services[o];if(!i)continue;let s=As(i.identity);if(ar(i.identity)&&i.identity.service_account===""){n.push({name:o,message:"service account identity is not configured"});continue}if((Ls(s)||i.capabilities.some((c)=>c==="google_api"||c==="iap"||c==="service_identity"))&&!r)n.push({name:o,message:"ADC unavailable"})}return n}function ni(e){if(Er(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(Ls(As(t.identity)))return!0;return t.capabilities.some((r)=>r==="google_api"||r==="iap"||r==="service_identity")})}function Ol(){return{name:"user",accepts:(e)=>!ar(e),resolve:async(e,t)=>{if(e.type===""&&e.mode==="")return Nt({kind:Bn});return{...await t(),kind:Ts}}}}function Il(){return{name:"service_account",accepts:(e)=>ar(e),resolve:async(e,t)=>{if(e.service_account==="")throw M(ls,"service account identity is not configured");return{...await t(),kind:tn,serviceAccount:e.service_account}}}}async function gg(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(ar(e))return Il().resolve(e,t);return Ol().resolve(e,t)}var Ts="user",tn="service_account",Bn="none";var rn=T(()=>{St();_e()});import{existsSync as Ds,readFileSync as BS}from"fs";import{homedir as hg}from"os";import{join as $l}from"path";var{spawn:Fl}=globalThis.Bun;function Un(){let e=globalThis;if(e.window&&typeof e.window.fetch!=="function")e.window.fetch=fetch}function Nl(){let e=process.env.GOOGLE_APPLICATION_CREDENTIALS||$l(hg(),".config","gcloud","application_default_credentials.json");if(!Ds(e))return"";try{let t=JSON.parse(BS(e,"utf8"));return typeof t.quota_project_id==="string"?t.quota_project_id:""}catch{return""}}async function Ht(e){let t={gcloudInstalled:await Hl("gcloud"),adcAvailable:!1,userEmail:"",projectID:"",projectSource:""};if(e!=="")t.projectID=e,t.projectSource="configuration";else{let r=JS("GOOGLE_CLOUD_PROJECT","GCLOUD_PROJECT","GOOGLE_PROJECT");if(r!=="")t.projectID=r,t.projectSource="environment variable";else if(t.gcloudInstalled){let n=await mg("core/project");if(n!=="")t.projectID=n,t.projectSource="gcloud configuration"}}if(oi())try{await wg(US(t),GS)}catch(r){t.adcAvailable=!1,t.error=Kn(r)}if(t.userEmail===""&&t.gcloudInstalled)t.userEmail=await mg("core/account");return t}async function US(e){Un();let{GoogleAuth:t}=await import("google-auth-library"),r=new t({scopes:[WS]});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 KS(r);if(o!=="")e.userEmail=o}async function KS(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=qS(r);if(n!=="")return n}}catch{return""}return""}function qS(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 vg(e){let t=await Ht(e);return Nt({kind:"user",email:t.userEmail,project:t.projectID,projectSource:t.projectSource,adcAvailable:t.adcAvailable})}async function Ms(){if(await Fl({cmd:["gcloud","auth","application-default","login"],stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited!==0)throw be(In,"application-default login failed","run `gcloud auth application-default login`")}async function xg(){if(await Fl({cmd:["gcloud","auth","application-default","revoke","--quiet"],stdout:"ignore",stderr:"pipe"}).exited!==0)throw be(In,"failed to revoke application-default credentials","run `gcloud auth application-default revoke`")}function Kn(e){let t=VS(e).toLowerCase();if(Gn(t,["unauth","invalid_grant","token has been expired","expired"]))return be(In,"credential expired or invalid","run `devctl auth login` or `gcloud auth application-default login`");if(Gn(t,["api has not been used","has not been enabled","access not configured","service_disabled"]))return be(qr,"required Google API is not enabled","enable the API in the target service account project; devctl will not enable APIs automatically");if(Gn(t,["permission","forbidden","iam"])){if(Gn(t,["serviceaccounttoken","iamcredentials","token creator","getaccesstoken"]))return be(ls,"cannot impersonate service account","ask an administrator to grant roles/iam.serviceAccountTokenCreator on the target service account");return be(qr,"authorization failure","verify IAM permissions for the current user on this project")}if(t.includes("audience"))return be(jc,"IAP audience is incorrect","set auth.audience on the proxy route to the IAP OAuth client ID");if(t.includes("iap"))return ye(jc,"IAP authentication failure",e);if(t.includes("project"))return be(X,"wrong or missing Google project","set google.project_id in .devctl/config.yaml");if(Gn(t,["timeout","network","connection refused","no such host"]))return ye(nt,"network problem reaching Google Cloud",e);if(Gn(t,["adc","default credentials","could not find"]))return be(In,"application default credentials unavailable","run `gcloud auth application-default login`");return ye(In,"Google authentication failed",e)}function VS(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 Gn(e,t){return t.some((r)=>e.includes(r))}function JS(...e){for(let t of e){let r=process.env[t];if(r)return r}return""}async function Hl(e){try{return(await bg(process.platform==="win32"?["where",e]:["which",e],yg)).code===0}catch{return!1}}function oi(){let e=process.env.GOOGLE_APPLICATION_CREDENTIALS;if(e&&Ds(e))return!0;if(Ds($l(hg(),".config","gcloud","application_default_credentials.json")))return!0;let t=process.env.APPDATA;return Boolean(t&&Ds($l(t,"gcloud","application_default_credentials.json")))}async function mg(e){try{let t=await bg(["gcloud","config","get-value",e],yg);if(t.code!==0)return"";let r=t.stdout.trim();if(r===""||r==="(unset)")return"";return r}catch{return""}}async function bg(e,t){let r=Fl({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 wg(Promise.all([n,r.exited]),t);return{code:i??1,stdout:o}}catch{return r.kill(),{code:1,stdout:""}}}function wg(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)})})}var WS="https://www.googleapis.com/auth/cloud-platform",yg=1500,GS=2000;var nn=T(()=>{On();_e();rn()});var{spawn:jl}=globalThis.Bun;import{createServer as Sg}from"net";async function kg(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>=Bl?l:c.value;if(l===void 0&&c.auto)d=await zS();if(d<Bl||d>YS)throw new Te(X,`invalid port ${d} on service ${i}`,{service:i});if(n[d]&&n[d]!==i)throw new Te(X,`duplicate port ${d} used by ${n[d]} and ${i}`,{service:i});if(l!==d&&!c.auto&&!await qn(d))throw await XS(i,c.name,d);n[d]=i,a[c.name]=d}o[i]=a}return o}function zS(){return new Promise((e,t)=>{let r=Sg();r.listen(0,"127.0.0.1",()=>{let n=r.address();r.close(()=>{if(n&&typeof n==="object")e(n.port);else t(ye(X,"unable to allocate dynamic port",Error("no address")))})}),r.on("error",(n)=>t(ye(X,"unable to allocate dynamic port",n)))})}async function Os(e){let t=e.ports.filter((n)=>!n.auto&&n.value>=Bl);if(t.length===0)return;let r={};for(let n of t){if(await qn(n.value))return;r[n.name]=n.value}return r}function qn(e){return new Promise((t)=>{let r=Sg();r.listen(e,"127.0.0.1",()=>{r.close(()=>t(!0))}),r.on("error",()=>t(!1))})}async function XS(e,t,r){let n=await Vn(r);return QS(e,t,r,n)}function QS(e,t,r,n){let o=t===""?`${e} port`:`${e} ports.${t}`;if(n&&n.pid===process.pid)return be(bt,`${e} blocked: this TUI already holds port ${r}`,`Stop the proxy from the Proxy screen, or change ${o} in .devctl.`,e);if(n)return be(bt,`${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 be(bt,`${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 ZS(e,t){let r=e.split(`
|
|
9
|
-
`).filter((
|
|
10
|
-
`)){if(!
|
|
11
|
-
`)}async delete(e){let t=
|
|
12
|
-
`)}function
|
|
13
|
-
`)}function
|
|
14
|
-
`)}function Pk(e){return{identity:e.identity,audience:e.audience,scopes:e.scopes,accessToken:e.accessToken,tokenType:e.tokenType,expiresAt:e.expiresAt.toISOString()}}function Ek(e){return{accessToken:e.accessToken,tokenType:e.tokenType||"Bearer",expiresAt:new Date(e.expiresAt),audience:e.audience,identity:e.identity,scopes:e.scopes}}function an(){return[Dk(),Lk(),Ak()]}function Tk(e){return{name:"static",accepts:(t,r)=>(e.identity===""||t===e.identity)&&(e.audience===""||r===e.audience),fetch:async(t,r,n)=>({...e,identity:t,audience:r,scopes:n})}}function Ak(){return{name:"user",accepts:(e,t)=>!e.startsWith("sa:")&&t==="",fetch:async(e,t,r)=>{if(e.startsWith("sa:"))throw M(ir,"user provider cannot mint service-account tokens");return $k(e,t,r)}}}function Lk(){return{name:"service_account",accepts:(e,t)=>e.startsWith("sa:")&&t==="",fetch:async(e,t,r)=>{if(!e.startsWith("sa:"))throw M(ir,"service-account provider cannot mint user tokens");return Mk(e,t,r)}}}function Dk(){return{name:"iap",accepts:(e,t)=>t!=="",fetch:async(e,t,r)=>{if(t==="")throw M(ir,"IAP audience is required");if(e.startsWith("sa:"))return Ok(e,t,r);return Ik(e,t,r)}}}async function Mk(e,t,r){let n=e.slice(3);try{Un();let i=await new Gs({scopes:r.length>0?r:[Ws]}).getClient(),s=new wk({sourceClient:i,targetPrincipal:n,targetScopes:r.length>0?r:[Ws],lifetime:3600}),a=await s.getAccessToken(),c=typeof a==="string"?a:a?.token;if(!c)throw M(ir,"empty impersonated token");return{accessToken:c,tokenType:"Bearer",expiresAt:Us(c,s),audience:t,identity:e,scopes:r}}catch(o){throw Kn(o)}}async function Ok(e,t,r){let n=e.slice(3);try{Un();let i=await new Gs({scopes:[Ws]}).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(ir,"empty impersonated IAP id token");return{accessToken:c,tokenType:"Bearer",expiresAt:Us(c),audience:t,identity:e,scopes:r}}catch(o){throw Kn(o)}}async function Ik(e,t,r){try{Un();let i=await(await new Gs({scopes:r.length>0?r:[_k]}).getIdTokenClient(t)).idTokenProvider.fetchIdToken(t);return{accessToken:i,tokenType:"Bearer",expiresAt:Us(i),audience:t,identity:e,scopes:r}}catch(n){throw Kn(n)}}async function $k(e,t,r){try{Un();let o=await new Gs({scopes:r.length>0?r:[Ws]}).getClient(),i=await o.getAccessToken();if(!i.token)throw M(ir,"empty access token");return{accessToken:i.token,tokenType:"Bearer",expiresAt:Fk(o,i.token),audience:t,identity:e,scopes:r}}catch(n){throw Kn(n)}}function Us(e,t){if(t?.credentials?.expiry_date)return new Date(t.credentials.expiry_date);return Nk(e)??new Date(Date.now()+Sk)}function Fk(e,t){return Us(t,e)}function Nk(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 Hk(e){if(e instanceof Te)return e.kind!==X&&e.kind!==qr;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 ed=300000,Sk=3000000,kk=3,Ck=200,Ws="https://www.googleapis.com/auth/cloud-platform",_k="https://www.googleapis.com/auth/userinfo.email";var ci=T(()=>{On();Yl();_e();nn();Fg();Ye()});async function Tr(e,t=Bk,r,n){let o={checks:[],issues:0},i="Preparing diagnostics",s=()=>r?.({active:i,checks:[...o.checks]}),a=(f)=>{i=f,s()},c=(f)=>{if(o.checks.push(f),f.severity==="error")o.issues+=1;s()};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:ni(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 l=await t.detectGoogle(e.google.project_id);if(l.adcAvailable)c({name:"Google authentication available",severity:"ok",message:"Application Default Credentials found"});else c({name:"Google authentication available",severity:ni(e)?"error":"warn",message:"ADC unavailable",hint:"run `gcloud auth application-default login`"});if(l.projectID!=="")c({name:"Project configured",severity:"ok",message:`${l.projectID} (source: ${l.projectSource})`});else c({name:"Project configured",severity:ni(e)?"error":"warn",message:"no Google project configured",hint:"set google.project_id in .devctl/config.yaml"});if(ni(e)||Object.values(e.services).some((f)=>f.capabilities.includes("google")||f.identity.type!=="")){a("Live Google access");let f=!0,h=(y)=>{if(f)c(y)};try{await di((async()=>{await Gk(e,h,t,l.userEmail),await Wk(e,h,t)})(),t.liveDeadlineMs??jk)}catch(y){h({name:"Live Google probes",severity:"warn",message:H(y),hint:"network or timeout \u2014 retry when online"})}finally{f=!1}}for(let f of e.doctor.tools){let h=f.command||f.name;if(a(`${f.name} installed`),await t.hasCommand(h))c({name:`${f.name} installed`,severity:"ok",message:`${h} found`});else c({name:`${f.name} installed`,severity:"error",message:`${h} not found`,hint:`install ${f.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 f=Ut(e);if(f.length>0)c({name:"Repository configuration",severity:"error",message:f.join("; ")});else c({name:"Repository configuration",severity:"ok",message:"valid"})}catch(f){c({name:"Repository configuration",severity:"error",message:H(f)})}let g={};for(let[f,h]of Object.entries(e.services))for(let y of h.ports){if(y.auto)continue;let b=`Port ${y.value}`;if(a(b),g[y.value])c({name:b,severity:"error",message:`configured on both ${g[y.value]} and ${f}`});else{g[y.value]=f;let w=n?.services?.[f];if(Boolean(w&&w.pid>0&&Object.values(w.ports).includes(y.value)))c({name:b,severity:"ok",message:`in use by running service ${f}`});else if(await t.portAvailable(y.value))c({name:b,severity:"ok",message:"available"});else c(await Gg(b,y.value,`services.${f}.ports`))}}if(e.proxy.listen.port>0){let f=`Port ${e.proxy.listen.port}`;if(a(f),n?.proxyRunning)c({name:f,severity:"ok",message:"in use by the running proxy"});else if(await t.portAvailable(e.proxy.listen.port))c({name:f,severity:"ok",message:"proxy listen port available"});else c(await Gg(f,e.proxy.listen.port,"proxy.listen.port"))}return i="Diagnostics complete",s(),o}async function Wk(e,t,r){let n=e.google.project_id,o=r.hasLocalAdc??oi;if(n===""||!o())return;let i=r.probeServiceUsage??qg,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(n,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:H(c.reason),hint:`enable ${d.service} in the Google Cloud console \u2014 doctor never auto-enables APIs`})})}async function Ug(){if(!td)td=Promise.resolve().then(() => (ci(),Bg)).then(({TokenManager:e,googleTokenProviders:t})=>new e(60000,t(),void 0,Ns("file")));return td}async function Kg(e,t){await(await Ug()).get(e,t,[])}async function qg(e,t){let r=await Ug(),n=await di(r.get("user","",[]),li),o=`https://serviceusage.googleapis.com/v1/projects/${e}/services/${t}`,i=await fetch(o,{headers:{Authorization:`Bearer ${n.accessToken}`},signal:AbortSignal.timeout(li)});if(!i.ok)return!1;return(await i.json().catch(()=>{return}))?.state==="ENABLED"}async function Gk(e,t,r,n){let o=Er(e),i=e.proxy.routes.filter((g)=>g.auth.type.toLowerCase()==="iap"),s=i.filter((g)=>g.auth.audience.trim()!=="");for(let g of i)if(g.auth.audience.trim()==="")t({name:`IAP audience ${g.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??oi)())return;let c=r.mintToken??Kg,l=o.map(async(g)=>{try{await di(c(`sa:${g}`,""),li),t({name:`Impersonate ${g}`,severity:"ok",message:"token minted"})}catch(f){let h=(r.adcQuotaProject??Nl)(),y=n||"the ADC principal",b=h===""?"unknown":h,w=Wg(`Impersonate ${g}`,f,`grant roles/iam.serviceAccountTokenCreator to ${y} on ${g}; ADC quota project: ${b}`);if(h!==""&&w.message.toLowerCase().includes("api is not enabled"))w.message=`IAM Credentials API is disabled in ADC quota project ${h}`,w.hint=`enable iamcredentials.googleapis.com in ${h}, 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: ${y} \u2192 ${g}`,w.hint=`verify roles/iam.serviceAccountTokenCreator for ${y} on this service account; ADC quota project: ${b}`;t(w)}}),d=s.map(async(g)=>{let f=Wn(g.auth).kind===tn?`sa:${Wn(g.auth).serviceAccount}`:"user";try{await di(c(f,g.auth.audience),li),t({name:`IAP ${g.name}`,severity:"ok",message:"id token minted"})}catch(h){t(Wg(`IAP ${g.name}`,h,"check IAP OAuth client ID and ADC"))}});await Promise.all([...l,...d])}function Wg(e,t,r){let n=H(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 Te&&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 di(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 Gg(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 Ks(e){let t=[`${Pt()} 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(`
|
|
3
|
+
var kw=Object.defineProperty;var Cw=(e)=>e;function _w(e,t){this[e]=Cw.bind(null,t)}var ws=(e,t)=>{for(var n in t)kw(e,n,{get:t[n],enumerable:!0,configurable:!0,set:_w.bind(t,n)})};var D=(e,t)=>()=>(e&&(t=e(e=0)),t);var Pw=import.meta.require;var Ur=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 rf(e,t=""){if(t===tf)return!0;return e.includes(tf)||e.startsWith(Rw)}function Ss(){if(nf)return;nf=!0;let e=process.emitWarning.bind(process);process.emitWarning=(t,...n)=>{let r=Tw(n[0]),o=Ew(t);if(rf(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=Aw(t);if(rf(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 Ew(e){if(typeof e==="string")return e;if(e instanceof Error)return e.message;return String(e)}function Tw(e){if(typeof e==="string")return e;if(e&&typeof e==="object"&&"type"in e&&typeof e.type==="string")return e.type;return""}function Aw(e){if(typeof e==="string")return e;if(e instanceof Uint8Array)return new TextDecoder().decode(e);return""}var tf="MetadataLookupWarning",Rw="received unexpected error =",nf=!1;var sl=D(()=>{Ur()});function T(e,t){return new De(e,t)}function pe(e,t,n){let r=n instanceof Error?n:Error(String(n));return new De(e,t,{cause:r})}function Se(e,t,n,r=""){return new De(e,t,{hint:n,service:r})}function Cs(e,t){return e instanceof De&&e.kind===t}function cf(e){if(e instanceof De)return e.exitCode();return 1}function lf(e){if(e instanceof De)return{error:j(e),kind:e.kind,hint:e.hint,service:e.service};return{error:j(e)}}function df(e){if(typeof e==="string")return T("general",e);if(e.kind)return new De(e.kind,e.error.replace(`${e.kind}: `,""),{hint:e.hint,service:e.service});return T("general",e.error)}function j(e){if(e instanceof De){if(e.hint!=="")return`${sf(e)} \u2014 ${e.hint}`;return sf(e)}if(e instanceof Error)return e.message;return String(e)}function sf(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 X="configuration",tr="configuration_missing",ei="service_not_found",af="dependency",Je="process_start",Kr="authentication",nr="authorization",dn="token",ks="impersonation",al="iap",Ln="proxy",cl="health_check",Ye="general",De;var Pe=D(()=>{De=class De 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 Lw}from"child_process";import{createHash as Dw,randomBytes as ul}from"crypto";import{copyFileSync as Ow,existsSync as Dn,mkdirSync as Mw,readdirSync as $w,readFileSync as pl,renameSync as fl,statSync as Iw,unlinkSync as ll,writeFileSync as Fw}from"fs";import{homedir as Nw}from"os";import{basename as Hw,dirname as dl,join as lt,resolve as jw}from"path";function $t(){let e=process.env.DEVCTL_HOME;if(e&&e!=="")return e;return lt(Nw(),".devctl")}function Vt(e){Mw(e,{recursive:!0,mode:Bw})}function un(e){let t=jw(e),n=process.platform==="win32"?t.toLowerCase():t;return Dw("sha256").update(n).digest("hex").slice(0,Gw)}function qr(e){let t=lt($t(),"state",un(e)),n=lt($t(),"sessions",un(e));if(!Dn(t)&&Dn(n)){Vt(dl(t));try{fl(n,t)}catch{Vt(t);for(let r of["state.json","devctl.lock","devctl.sock"]){let o=lt(n,r);if(Dn(o))Ow(o,lt(t,r))}}}return Vt(t),t}function _s(){let e=lt($t(),"logs");return Vt(e),e}function rr(){let e=lt($t(),"exports");return Vt(e),e}function Ht(){let e=lt($t(),"credentials");return Vt(e),e}function Ps(e,t=process.platform){if(t==="win32")return`\\\\.\\pipe\\devctl-${un(e)}`;return lt(qr(e),"devctl.sock")}function Uw(e){return lt(qr(e),"devctl.lock")}function uf(e){return lt(qr(e),"state.json")}function ti(e){return lt(qr(e),"bootstrap.log")}function ff(e){let t=ti(e);if(!Dn(t))return;let n=qr(e),r=lt(n,`${pf}${gl()}.log`);try{fl(t,r)}catch{return}qw(n)}function qw(e){let t;try{t=$w(e).filter((r)=>r.startsWith(pf)&&r.endsWith(".log"))}catch{return}let n=t.map((r)=>{let o=lt(e,r);try{return{path:o,mtime:Iw(o).mtimeMs}}catch{return}}).filter((r)=>r!==void 0).sort((r,o)=>o.mtime-r.mtime);for(let r=Kw;r<n.length;r++)try{ll(n[r].path)}catch{}}function jt(e,t){Vt(dl(e));let n=lt(dl(e),`.${Hw(e)}.tmp-${process.pid}-${ul(4).toString("hex")}`);Fw(n,t,{mode:Ww}),fl(n,e)}function gl(e=new Date){return`${e.toISOString().slice(0,19).replace(/:/g,"-")+"Z"}-${ul(3).toString("hex")}`}function Rs(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 ni(e){return ml(uf(e))}function ml(e){if(!Dn(e))return;try{let t=JSON.parse(pl(e,"utf8"));if(Array.isArray(t.processes)&&typeof t.repo_root==="string")return t;return}catch{return}}function gf(e,t){jt(uf(e),`${JSON.stringify(t,null,2)}
|
|
4
|
+
`)}function mf(e,t){let n=Uw(e);if(Dn(n)){let r=Vw(n);if(r&&Tt(r.pid))throw Error(`supervisor already running (pid ${r.pid})`);try{ll(n)}catch{}}return jt(n,JSON.stringify({pid:process.pid,socket:t})),{release:()=>{try{ll(n)}catch{}}}}function Vw(e){if(!Dn(e))return;try{let t=JSON.parse(pl(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 Jw(e);try{return process.kill(e,0),!0}catch{return!1}}function hl(e){try{let t=Lw("cmd.exe",["/d","/c",`tasklist /FO CSV /NH /FI "PID eq ${e}"`],{encoding:"buffer",windowsHide:!0,timeout:5000});return zw(t.stdout)}catch{return""}}function Jw(e){try{return process.kill(e,0),!0}catch{}let t=hl(e).toLowerCase();if(t===""||t.includes("no tasks")||t.includes("no matching"))return!1;return t.includes(String(e))}function zw(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 yl(){return ul(24).toString("hex")}function Yw(e){return lt(qr(e),"mcp-token")}function hf(e){let t=Yw(e);if(Dn(t)){let r=pl(t,"utf8").trim();if(r!=="")return r}let n=yl();return jt(t,n),n}var Bw=448,Ww=384,Gw=16,Kw=5,pf="bootstrap-";var Xe=()=>{};function Vr(){return{args:[],shell:!1}}function xl(){return{vars:{},required:[],defaults:{}}}function bl(){return{type:"",url:"",address:"",command:Vr(),interval_seconds:0,timeout_seconds:0,start_period_seconds:0,unhealthy_threshold:3,healthy_reset_threshold:10}}function St(e){return typeof e==="string"?e:e.service}function On(e){return typeof e==="string"?"service_started":e.condition||"service_started"}function Ts(e){return On(e)==="service_healthy"?`${St(e)} (healthy)`:St(e)}function wl(){return{type:"",mode:"",service_account:"",config:{}}}function Mn(){return{extends:"",description:"",command:Vr(),shell:!1,working_dir:"",dependencies:[],ports:[],environment:xl(),health:bl(),identity:wl(),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:Vr(),post_start:Vr()}}}function or(){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 zr(e){return e.args.length===0||e.args.length===1&&(e.args[0]??"").trim()===""}function ri(e){if(e.type!=="")return e.type;return e.mode}function pn(e){let t=ri(e).toLowerCase();return t==="service"||t==="service_account"}function bf(e){let t=ri(e).toLowerCase();return t==="user"||t===""}function wf(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 ir(e){let t=e.host===""?"127.0.0.1":e.host;if(e.port===0)return t;return`${t}:${e.port}`}function As(e){if(e.refresh_threshold_seconds<=0)return 300;return e.refresh_threshold_seconds}function Ls(e){if(e.stop_services_on_exit===void 0)return!0;return e.stop_services_on_exit}function oi(e){if(e.grace_seconds<=0)return 10;return e.grace_seconds}function Sf(e){if(!e.logs.stdout&&!e.logs.stderr)return!0;return e.logs.stdout}function kf(e){if(!e.logs.stdout&&!e.logs.stderr)return!0;return e.logs.stderr}function Sl(e,t){return e.find((n)=>n.name===t)}function Cf(e){return e[0]}var Jr=1,yf="never",vf="on_failure",xf="always",Es=8080,vl="127.0.0.1";function O(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Cl(e){return O(e)?new Set(Object.keys(e)):new Set}function U(e){if(typeof e==="string")return e;if(typeof e==="number"||typeof e==="boolean")return String(e);return""}function ve(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 At(e){if(!Array.isArray(e))return[];return e.map((t)=>U(t))}function _l(e){if(!Array.isArray(e))return[];return e.map((t)=>O(t)?{service:U(t.service),condition:U(t.condition)||"service_started"}:U(t))}function $n(e){if(!O(e))return{};let t={};for(let[n,r]of Object.entries(e))t[n]=U(r);return t}function Wt(e){if(typeof e==="string")return{args:e.split(/\s+/).filter((t)=>t!==""),shell:!1};if(Array.isArray(e))return{args:e.map((t)=>U(t)),shell:!1};return Vr()}function Pl(e){if(e===void 0||e===null)return[];if(typeof e==="string"||typeof e==="number")return[kl(e,"http")];if(Array.isArray(e))return e.map((t,n)=>kl(t,`port_${n}`));if(O(e))return Object.entries(e).map(([t,n])=>kl(n,t));return[]}function kl(e,t){if(typeof e==="string"&&e.toLowerCase()==="auto")return{name:t,value:0,auto:!0};return{name:t,value:ve(e),auto:!1}}function _f(e){if(!O(e))return xl();let t={},n=[],r={};for(let[o,i]of Object.entries(e))if(o==="required")n=At(i);else if(o==="defaults")r=$n(i);else t[o]=U(i);return{vars:t,required:n,defaults:r}}function Xw(e){if(!O(e))return wl();return{type:U(e.type),mode:U(e.mode),service_account:U(e.service_account),config:O(e.config)?{...e.config}:{}}}function Qw(e){if(!O(e))return bl();return{type:U(e.type),url:U(e.url),address:U(e.address),command:Wt(e.command),interval_seconds:ve(e.interval_seconds),timeout_seconds:ve(e.timeout_seconds),start_period_seconds:ve(e.start_period_seconds),unhealthy_threshold:e.unhealthy_threshold===void 0?3:ve(e.unhealthy_threshold),healthy_reset_threshold:e.healthy_reset_threshold===void 0?10:ve(e.healthy_reset_threshold)}}function Zw(e){if(!O(e))return{policy:"",max_retries:0,backoff_seconds:0};return{enabled:e.enabled===void 0?void 0:it(e.enabled),policy:U(e.policy),max_retries:ve(e.max_retries),backoff_seconds:ve(e.backoff_seconds)}}function eS(e){if(!O(e))return{wait_for_healthy:!1,timeout_seconds:0};return{wait_for_healthy:it(e.wait_for_healthy),timeout_seconds:ve(e.timeout_seconds)}}function ii(e){if(!O(e))return Mn();let t=O(e.logs)?e.logs:{};return{extends:U(e.extends),description:U(e.description),command:Wt(e.command),shell:it(e.shell),working_dir:U(e.working_dir),dependencies:_l(e.dependencies),ports:Pl(e.ports),environment:_f(e.environment),health:Qw(e.health),identity:Xw(e.identity),logs:{stdout:it(t.stdout),stderr:it(t.stderr)},restart:Zw(e.restart),startup:eS(e.startup),capabilities:At(e.capabilities),proxy:El(e.proxy),container:Rl(e.container),hooks:tS(e.hooks)}}function tS(e){let t=O(e)?e:{};return{pre_start:Wt(t.pre_start),post_start:Wt(t.post_start)}}function Pf(e){let t=O(e)?e:{};return{command:Wt(t.command),shell:it(t.shell),working_dir:U(t.working_dir),dependencies:At(t.dependencies),environment:_f(t.environment)}}function Rl(e){if(!O(e))return;let t={};if(O(e.ports))for(let[n,r]of Object.entries(e.ports))t[n]=ve(r);return{image:U(e.image),runtime:U(e.runtime),ports:t,env:$n(e.env),volumes:At(e.volumes)}}function El(e){if(e===void 0||e===null)return[];if(Array.isArray(e))return e.map((t)=>sr(t));if(O(e))return[sr(e)];return[]}function Ds(e){if(!O(e))return{services:[],environment:{}};return{services:At(e.services),environment:$n(e.environment)}}function nS(e){if(typeof e==="string")return{type:e,service_account:""};if(!O(e))return{type:"",service_account:""};return{type:U(e.type),service_account:U(e.service_account)}}function rS(e){if(!O(e))return{type:"",identity:{type:"",service_account:""},audience:"",service_account:""};return{type:U(e.type),identity:nS(e.identity),audience:U(e.audience),service_account:U(e.service_account)}}function sr(e){if(!O(e))return{name:"",match:{host:"",path:""},upstream:{url:""},auth:{type:"",identity:{type:"",service_account:""},audience:"",service_account:""}};let t=O(e.match)?e.match:{},n=O(e.upstream)?e.upstream:{};return{name:U(e.name),match:{host:U(t.host),path:U(t.path)},upstream:{url:U(n.url)},auth:rS(e.auth)}}var Tl=()=>{};import{existsSync as oS,statSync as Ef}from"fs";import{basename as Rf,dirname as Os,isAbsolute as iS,join as Ms,resolve as Tf}from"path";function In(e,t){if(t!=="")return sS(t);let n=e===""?process.cwd():e;n=iS(n)?n:Tf(n);for(;;){let r=Ms(n,kt,Gt);if(si(r))return{repoRoot:n,configPath:r};let o=Ms(n,"devctl.yaml");if(si(o))return{repoRoot:n,configPath:o};let i=Os(n);if(i===n)break;n=i}throw Se(tr,"no devctl configuration found","run `devctl setup` or create a .devctl/config.yaml in the repository root")}function sS(e){let t=Tf(e),n;try{n=Ef(t)}catch(o){throw pe(tr,"config path not found",o)}if(n.isDirectory()){if(Rf(t)===kt)return{repoRoot:Os(t),configPath:Ms(t,Gt)};return{repoRoot:t,configPath:Ms(t,Gt)}}let r=Os(t);if(Rf(r)===kt)r=Os(r);return{repoRoot:r,configPath:t}}function si(e){return oS(e)&&!Ef(e).isDirectory()}var kt=".devctl",Gt="config.yaml";var ai=D(()=>{Pe()});function Fs(){return{services:{},templates:{},provenance:{}}}function Fn(e,t,n,r,o=""){if(O(t)&&Object.keys(t).length>0){for(let[i,s]of Object.entries(t))Fn(e,s,n,r,o===""?i:`${o}.${i}`);return}if(o==="")return;(e[o]??=[]).push({source:n,layer:r})}function $s(e,t,n){let r=Cl(n);if(O(n))for(let i of aS){let s=n[i];if(O(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 Af(e,t,n=Fs(),r={source:"unknown",layer:"unknown"}){if(Fn(n.provenance,t,r.source,r.layer),t.version!==void 0)e.version=ve(t.version);if(O(t.project)&&t.project.name!==void 0)e.project.name=U(t.project.name);if(O(t.google)){if(t.google.project_id!==void 0)e.google.project_id=U(t.google.project_id);if(t.google.region!==void 0)e.google.region=U(t.google.region)}if(O(t.profiles))for(let[o,i]of Object.entries(t.profiles)){let s=e.profiles[o];e.profiles[o]=s?lS(s,i):Ds(i)}if(O(t.templates))for(let[o,i]of Object.entries(t.templates)){let s=e.templates[o];e.templates[o]=s?Is(s,i):ii(i),$s(n.templates,o,i)}if(O(t.services))for(let[o,i]of Object.entries(t.services)){let s=e.services[o];e.services[o]=s?Is(s,i):ii(i),$s(n.services,o,i)}if(O(t.tasks))for(let[o,i]of Object.entries(t.tasks))e.tasks[o]=e.tasks[o]?dS(e.tasks[o],i):Pf(i);if(O(t.proxy))cS(e.proxy,t.proxy);if(O(t.logs)){if(t.logs.max_memory_events!==void 0)e.logs.max_memory_events=ve(t.logs.max_memory_events);if(O(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=U(o.directory);if(o.retention_days!==void 0)e.logs.persistence.retention_days=ve(o.retention_days);if(o.max_session_logs!==void 0)e.logs.persistence.max_session_logs=ve(o.max_session_logs)}}if(O(t.auth)&&t.auth.refresh_threshold_seconds!==void 0)e.auth.refresh_threshold_seconds=ve(t.auth.refresh_threshold_seconds);if(O(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=ve(t.shutdown.grace_seconds)}if(O(t.ui)){if(t.ui.theme!==void 0)e.ui.theme=U(t.ui.theme);if(t.ui.keymap!==void 0)e.ui.keymap=$n(t.ui.keymap)}if(O(t.secrets)){if(t.secrets.extra_markers!==void 0)e.secrets.extra_markers=At(t.secrets.extra_markers);if(t.secrets.extra_patterns!==void 0)e.secrets.extra_patterns=At(t.secrets.extra_patterns)}if(O(t.doctor)&&Array.isArray(t.doctor.tools))e.doctor.tools=t.doctor.tools.filter(O).map((o)=>({name:U(o.name),command:U(o.command)}));if(Array.isArray(t.plugins))e.plugins=t.plugins.filter(O).map((o)=>({path:U(o.path)})).filter((o)=>o.path!=="");if(O(t.environment)){if(Array.isArray(t.environment.sources))e.environment.sources=At(t.environment.sources);if(O(t.environment.secrets))e.environment.secrets={...e.environment.secrets,...$n(t.environment.secrets)}}}function cS(e,t){if(t.enabled!==void 0)e.enabled=it(t.enabled);if(O(t.listen)){if(t.listen.host!==void 0)e.listen.host=U(t.listen.host);if(t.listen.port!==void 0)e.listen.port=ve(t.listen.port)}if(O(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=U(n.host);if(n.port!==void 0)e.token_endpoint.port=ve(n.port)}if(Array.isArray(t.routes))e.routes=t.routes.map((n)=>sr(n))}function lS(e,t){if(!O(t))return e;return{services:t.services!==void 0?At(t.services):e.services,environment:t.environment!==void 0?{...e.environment,...$n(t.environment)}:e.environment}}function dS(e,t){if(!O(t))return e;return{command:t.command!==void 0?Wt(t.command):e.command,shell:t.shell!==void 0?it(t.shell):e.shell,working_dir:t.working_dir!==void 0?U(t.working_dir):e.working_dir,dependencies:t.dependencies!==void 0?At(t.dependencies):e.dependencies,environment:Lf(e.environment,t.environment)}}function Is(e,t){if(!O(t))return e;let n=Cl(t),r={...e,environment:Lf(e.environment,t.environment),health:pS(e.health,t.health),identity:fS(e.identity,t.identity),logs:gS(e.logs,t.logs),restart:mS(e.restart,t.restart),startup:hS(e.startup,t.startup),container:yS(e.container,t.container),hooks:uS(e.hooks,t.hooks)};if(n.has("extends"))r.extends=U(t.extends);if(n.has("description"))r.description=U(t.description);if(n.has("command"))r.command=Wt(t.command);if(n.has("shell"))r.shell=it(t.shell);if(n.has("working_dir"))r.working_dir=U(t.working_dir);if(n.has("dependencies"))r.dependencies=_l(t.dependencies);if(n.has("ports"))r.ports=Pl(t.ports);if(n.has("capabilities"))r.capabilities=At(t.capabilities);if(n.has("proxy"))r.proxy=El(t.proxy);return r}function uS(e,t){if(!O(t))return e;return{pre_start:t.pre_start!==void 0?Wt(t.pre_start):e.pre_start,post_start:t.post_start!==void 0?Wt(t.post_start):e.post_start}}function Lf(e,t){if(!O(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=At(s);else if(i==="defaults")Object.assign(r,$n(s));else n[i]=U(s);return{vars:n,required:o,defaults:r}}function pS(e,t){if(!O(t))return e;return{type:t.type!==void 0?U(t.type):e.type,url:t.url!==void 0?U(t.url):e.url,address:t.address!==void 0?U(t.address):e.address,command:t.command!==void 0?Wt(t.command):e.command,interval_seconds:t.interval_seconds!==void 0?ve(t.interval_seconds):e.interval_seconds,timeout_seconds:t.timeout_seconds!==void 0?ve(t.timeout_seconds):e.timeout_seconds,start_period_seconds:t.start_period_seconds!==void 0?ve(t.start_period_seconds):e.start_period_seconds,unhealthy_threshold:t.unhealthy_threshold!==void 0?ve(t.unhealthy_threshold):e.unhealthy_threshold,healthy_reset_threshold:t.healthy_reset_threshold!==void 0?ve(t.healthy_reset_threshold):e.healthy_reset_threshold}}function fS(e,t){if(!O(t))return e;return{type:t.type!==void 0?U(t.type):e.type,mode:t.mode!==void 0?U(t.mode):e.mode,service_account:t.service_account!==void 0?U(t.service_account):e.service_account,config:t.config!==void 0&&O(t.config)?{...e.config??{},...t.config}:e.config}}function gS(e,t){if(!O(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 mS(e,t){if(!O(t))return e;return{enabled:t.enabled!==void 0?it(t.enabled):e.enabled,policy:t.policy!==void 0?U(t.policy):e.policy,max_retries:t.max_retries!==void 0?ve(t.max_retries):e.max_retries,backoff_seconds:t.backoff_seconds!==void 0?ve(t.backoff_seconds):e.backoff_seconds}}function hS(e,t){if(!O(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?ve(t.timeout_seconds):e.timeout_seconds}}function yS(e,t){if(!O(t))return e;let n=Rl(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 Df(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)Fn(t,c,`synthesized from services.${r}.proxy`,"synthesized",`proxy.routes.${l}`)})}}function Of(e,t=Fs()){if(Object.keys(e.templates).length===0)return;let n={};for(let[r,o]of Object.entries(e.services))n[r]=Mf(e,o,t.services[r]??new Set,t,{});e.services=n}function Mf(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]??Mn();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=Mf(e,i,a,r,s),l=vS(c,t,n);return l.extends=t.extends,l}function vS(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 aS;var $f=D(()=>{Tl();aS=["environment","restart","startup","health","logs","identity","container","hooks"]});function Al(e){if(e.version===0)throw T(X,"version is required");if(e.version===Jr)return e;throw T(X,`unsupported config version ${e.version} (expected ${Jr}); no migration is available`)}var Ll=D(()=>{Pe()});var If,Ff,Nf,Hf,jf,Bf,Wf,Gf,Uf,Dl,Ol,Ml,$l,Kf,qf,Vf,Jf,zf,Yf,Xf,Qf,Il,Zf,eg,tg,ng,rg,og,ig,sg,ag,cg,lg,dg;var Fl=D(()=>{If=["version","project","google","profiles","templates","services","tasks","proxy","logs","auth","shutdown","ui","secrets","doctor","plugins","environment"],Ff=["extends","description","command","shell","working_dir","dependencies","ports","environment","health","identity","logs","restart","startup","capabilities","proxy","container","hooks"],Nf=["type","url","address","command","interval_seconds","timeout_seconds","start_period_seconds","unhealthy_threshold","healthy_reset_threshold"],Hf=["service","condition"],jf=["type","mode","service_account","config"],Bf=["enabled","policy","max_retries","backoff_seconds"],Wf=["wait_for_healthy","timeout_seconds"],Gf=["enabled","listen","token_endpoint","routes"],Uf=["host","port"],Dl=["name","match","upstream","auth"],Ol=["host","path"],Ml=["url"],$l=["type","identity","audience","service_account"],Kf=["max_memory_events","persistence"],qf=["enabled","directory","retention_days","max_session_logs"],Vf=["refresh_threshold_seconds"],Jf=["stop_services_on_exit","grace_seconds"],zf=["theme","keymap"],Yf=["name"],Xf=["project_id","region"],Qf=["services","environment"],Il=["required","defaults"],Zf=["stdout","stderr"],eg=["extra_markers","extra_patterns"],tg=["tools"],ng=["name","command"],rg=["enabled","host","port"],og=["path"],ig=["sources","secrets"],sg=["image","runtime","ports","env","volumes"],ag=["pre_start","post_start"],cg=["command","shell","working_dir","dependencies","environment"],lg=["google","google_api","iap","network","service_identity","local_http"],dg=["|","||","&&",";",">",">>","<","&"]});function Nn(e,t){if(Array.isArray(e))return e.flatMap((o,i)=>Nn(o,ug(t,String(i))));if(!PS(e))return[];let n=wS(t),r=[];for(let o of Object.keys(e)){let i=ug(t,o);if(n.length>0&&!n.includes(o)&&!bS(t))r.push(i);r.push(...Nn(e[o],i))}return r}function bS(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 wS(e){switch(e){case"":return If;case"project":return Yf;case"google":return Xf;case"proxy":return Gf;case"proxy.listen":return Uf;case"proxy.token_endpoint":return rg;case"logs":return Kf;case"logs.persistence":return qf;case"auth":return Vf;case"shutdown":return Jf;case"ui":return zf;case"secrets":return eg;case"doctor":return tg;case"environment":return ig;default:return SS(e)}}function SS(e){if(e==="services"||e==="profiles"||e==="templates"||e==="tasks")return[];if(e.startsWith("services.")||e.startsWith("templates.")){if(e.includes(".dependencies."))return Hf;return kS(e)}if(e.startsWith("profiles.")){if(e.split(".").length===2)return Qf}if(e.startsWith("tasks.")){let t=e.split(".");if(t.length===2)return cg;if(t[2]==="environment")return Il}if(e.includes("routes"))return _S(e);if(e.startsWith("doctor.tools")&&e.split(".").length>=3)return ng;if(e==="plugins")return[];if(e.startsWith("plugins.")&&e.split(".").length===2)return og;return[]}function kS(e){let t=e.split(".");if(t.length===2)return Ff;if(t.length>=3)switch(t[2]){case"health":return Nf;case"identity":return jf;case"restart":return Bf;case"startup":return Wf;case"logs":return Zf;case"environment":return Il;case"proxy":return CS(t);case"container":return sg;case"hooks":return ag;default:return[]}return[]}function CS(e){let t=e.slice(3),n=t[0]!==void 0&&/^\d+$/.test(t[0])?1:0,r=t[n]??"";if(r==="match")return Ol;if(r==="upstream")return Ml;if(r==="auth")return $l;return Dl}function _S(e){if(e==="proxy.routes")return[];if(e.endsWith(".match"))return Ol;if(e.endsWith(".upstream"))return Ml;if(e.endsWith(".auth"))return $l;if(e.includes("proxy.routes")&&e.split(".").length===xS+1)return Dl;return[]}function ug(e,t){if(e==="")return t;return`${e}.${t}`}function PS(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Yr(e){return`unknown fields: ${e.join(", ")}`}var xS=2;var pg=D(()=>{Fl()});function fg(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+=RS(a,t,n),r=r.slice(i+s+1)}}function RS(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=Cf(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=Sl(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 Nl(e,t,n){let r={};for(let[o,i]of Object.entries(e))r[o]=fg(i,t,n);return r}function gg(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 mg(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 Sl(r.ports,o)!==void 0}}return!0}var Hl=()=>{};import{existsSync as ES}from"fs";import{isAbsolute as TS,resolve as AS}from"path";import{fileURLToPath as LS}from"url";function jl(e){let t=[];for(let[n,r]of Object.entries(e.services)){let o=r.health.type;if(o!==""&&!vg.includes(o.toLowerCase()))t.push({service:n,type:o})}return t}function Jt(e){let t=[];if(e.version===0)t.push("version is required");else if(e.version!==Jr)t.push(`unsupported config version ${e.version} (expected ${Jr}); no migration is available`);if(Object.keys(e.services).length===0)t.push("at least one service must be defined");t.push(...MS(e)),t.push(...OS(e)),t.push(...NS(e)),t.push(...HS(e)),t.push(...jS(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:")?LS(r.path):TS(r.path)?r.path:AS(e.repoRoot,r.path);if(!ES(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 OS(e){let t=[];for(let[n,r]of Object.entries(e.tasks)){let o=`tasks.${n}`;if(zr(r.command))t.push(`${o}.command is required`);t.push(...Ns(o,r.command,r.shell));for(let i of r.dependencies)if(!e.services[i])t.push(`${o}.dependencies: unknown service "${i}"`);t.push(...xg(`${o}.environment`,r.environment,e))}return t}function MS(e){let t=[],n={};for(let[r,o]of Object.entries(e.services)){let i=`services.${r}`;if(zr(o.command)&&!o.container)t.push(`${i}.command is required`);t.push(...Ns(i,o.command,o.shell)),t.push(...Ns(`${i}.hooks.pre_start`,o.hooks.pre_start,o.shell)),t.push(...Ns(`${i}.hooks.post_start`,o.hooks.post_start,o.shell)),t.push(...WS(i,o.capabilities));for(let c of o.dependencies){let l=St(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(On(c)))t.push(`${i}.dependencies: condition must be service_started or service_healthy`);if(On(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<js||c.value>Hs)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=FS(`${i}.identity`,o.identity,e.plugins.length>0);if(s!=="")t.push(s);if(t.push(...$S(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=wf(o.restart);if(a!==yf&&a!==vf&&a!==xf)t.push(`${i}.restart.policy must be never, on_failure, or always`);if(t.push(...xg(`${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<js||l>Hs)t.push(`${i}.container.ports.${c}: invalid container port ${l}`)}}}return t}function $S(e,t,n){let r=[];if(t.health.type==="")return r;let o=t.health.type.toLowerCase();if(!vg.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"&&zr({args:t.health.command.args,shell:!1}))r.push(`${e}.health.command is required for command health checks`);return r}function FS(e,t,n){let r=ri(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 Bl(e){let t=[];for(let[n,r]of Object.entries(e.services)){let o=ri(r.identity).toLowerCase();if(!IS.includes(o))t.push({service:n,type:o})}return t}function NS(e){let t={},n=[],r=[],o=(i)=>{let s=t[i]??DS;if(s===yg)return;if(s===hg){n.push(`dependency cycle: ${[...r,i].join(" \u2192 ")}`);return}t[i]=hg,r.push(i);let a=e.services[i];if(a)for(let c of a.dependencies){let l=St(c);if(e.services[l])o(l)}r.pop(),t[i]=yg};for(let i of Object.keys(e.services))o(i);return n}function xg(e,t,n){let r=[],o=(i,s)=>{for(let a of gg(s))if(!mg(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 HS(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 jS(e){let t=[];if(e.proxy.listen.host!==""&&!GS(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<js||e.proxy.listen.port>Hs))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"||pn({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(...BS(e)),t}function BS(e){let t=[],n=e.proxy.token_endpoint;if(!n.enabled)return t;let r=n.host||vl;if(r==="0.0.0.0")t.push("proxy.token_endpoint.host must be a loopback address");else if(r!==""&&r!==vl&&r!=="localhost"&&!r.startsWith("127."))t.push("proxy.token_endpoint.host must be a loopback address");if(n.port!==0&&(n.port<js||n.port>Hs))t.push("proxy.token_endpoint.port is invalid");return t}function Ns(e,t,n){if(t.shell||n)return[];for(let r of t.args)if(dg.includes(r)||r.includes("|")||r.includes(";")||r.includes("&&"))return[`${e}.command contains shell metacharacters; set shell: true to run via a shell`];return[]}function WS(e,t){let n=[];for(let r of t)if(!lg.includes(r))n.push(`${e}.capabilities: unknown capability "${r}"`);return n}function GS(e){if(e==="localhost")return!0;return US(e)}function US(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 Hs=65535,js=1,vg,DS=0,hg=1,yg=2,IS;var Bs=D(()=>{Fl();Hl();vg=["http","tcp","process","command"];IS=["","user","service","service_account"]});import{readdirSync as KS,readFileSync as qS}from"fs";import{basename as wg,dirname as VS,extname as JS,join as ar,resolve as zS}from"path";import{parse as YS}from"yaml";function Xr(e,t,n){try{return li(e,t,{candidateText:n}),[]}catch(r){if(r instanceof De){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 dt(e,t){let{repoRoot:n,configPath:r}=In(e,t);return li(n,r)}function ci(e,t){try{return dt(e,t)}catch(n){if(!Cs(n,tr))throw n;let r=e===""?process.cwd():zS(e),o=or();return o.repoRoot=r,o.configPath=ar(r,kt,Gt),o}}function li(e,t,n){let r=or(),o=Fs();Sg(t,r,o,n?.candidateText,"main"),r.repoRoot=e,r.configPath=t;let i=VS(t);if(wg(i)===kt)QS(i,r,o);r=XS(r,e,t,o),r=Al(r);try{Of(r,o)}catch(a){throw pe(X,"template merge failed",a)}Df(r,o.provenance),r.provenance=o.provenance;let s=Jt(r);if(s.length>0)throw T(X,s.join(`
|
|
5
|
+
`));return r}function XS(e,t,n,r){let o=ar($t(),"config.local.yaml"),i=ar(t,kt,"config.local.yaml");for(let s of[o,i]){if(s===n||!si(s))continue;Sg(s,e,r,void 0,s===o?"home_local":"repo_local")}return e}function Sg(e,t,n,r,o="main"){let i=r!==void 0?kg(r,e):Wl(e),s=Nn(i,"");if(s.length>0)throw T(X,Yr(s));Af(t,i,n,{source:e,layer:o})}function QS(e,t,n){bg(ar(e,"services"),(o,i,s)=>{let a=Nn(i,`services.${o}`);if(a.length>0)throw T(X,Yr(a));let c=t.services[o];t.services[o]=c?Is(c,i):ii(i),$s(n.services,o,i),Fn(n.provenance,i,s,"modular_service",`services.${o}`)}),bg(ar(e,"profiles"),(o,i,s)=>{let a=Nn(i,`profiles.${o}`);if(a.length>0)throw T(X,Yr(a));t.profiles[o]=Ds(i),Fn(n.provenance,i,s,"modular_profile",`profiles.${o}`)});let r=ar(e,"proxy","routes.yaml");if(si(r))ZS(r,t,n)}function ZS(e,t,n){let r=Wl(e);if(O(r.proxy))Fn(n.provenance,r.proxy,e,"modular_proxy","proxy");if(Array.isArray(r.routes))Fn(n.provenance,r.routes,e,"modular_proxy","proxy.routes");if(O(r.proxy)){let o=Nn({proxy:r.proxy},"");if(o.length>0)throw T(X,Yr(o))}if(Array.isArray(r.routes))r.routes.forEach((o,i)=>{let s=Nn(o,`proxy.routes.${i}`);if(s.length>0)throw T(X,Yr(s))});if(O(r.proxy)){if(Array.isArray(r.proxy.routes))t.proxy.routes.push(...r.proxy.routes.map((o)=>sr(o)));if(O(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)=>sr(o)))}function bg(e,t){let n;try{n=KS(e)}catch(r){if(ek(r))return;throw r}for(let r of n.sort()){let o=JS(r);if(o!==".yaml"&&o!==".yml")continue;let i=ar(e,r),s=Wl(i);t(wg(r,o),s,i)}}function Wl(e){let t;try{t=qS(e,"utf8")}catch(n){throw pe(X,"unable to read config",n)}return kg(t,e)}function kg(e,t){let n;try{n=YS(e)}catch(r){throw pe(X,`invalid YAML in ${t}`,r)}if(n===null||n===void 0)return{};if(!O(n))throw T(X,`unable to decode config: ${t} is not a mapping`);return n}function ek(e){return typeof e==="object"&&e!==null&&"code"in e&&e.code==="ENOENT"}var Cg=D(()=>{Pe();Xe();Tl();ai();$f();Ll();pg();Bs();ai();Bs()});function di(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:tk(e,t),...r,shadowed:n.slice(0,-1)}]})}function tk(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(()=>{Cg();ai();Bs();Ll();Hl()});import{readdirSync as nk}from"fs";import{join as _g,resolve as Gl,sep as Ul}from"path";function rk(e){let t=_g($t(),"state"),n;try{n=nk(t)}catch{return}let r=Pg(Gl(e)),o;for(let i of n){let s=ml(_g(t,i,"state.json"));if(!s)continue;let a=Pg(Gl(s.repo_root));if(!ok(a,r))continue;if(!o||a.length>o.length)o=a}return o}function Ws(e,t,n=""){if(t!=="")return{repoRoot:Gl(t),source:"explicit"};let r=e===""?process.cwd():e;try{let{repoRoot:i}=In(r,n);return{repoRoot:i,source:"config"}}catch{if(n!=="")return}let o=rk(r);return o?{repoRoot:o,source:"state-scan"}:void 0}function Pg(e){let t=e.length>1&&e.endsWith(Ul)?e.slice(0,-1):e;return process.platform==="win32"?t.toLowerCase():t}function ok(e,t){return t===e||t.startsWith(e.endsWith(Ul)?e:`${e}${Ul}`)}var Rg=D(()=>{ai();Xe()});import{existsSync as Tg,readFileSync as Ag}from"fs";import{isAbsolute as ik,join as Kl}from"path";import{parse as sk}from"dotenv";function lk(){return{name:"dotenv",load:(e)=>{let t=Eg(e.repoRoot,e.profile);if(e.workDir!=="")Object.assign(t,Eg(e.workDir,e.profile));return t}}}function Gs(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 T(X,`secret manager request failed for ${t}: HTTP ${o.status}`);let i=await o.json();if(!i.payload?.data)throw T(X,`secret manager response for ${t} had no payload`);return Buffer.from(i.payload.data,"base64").toString("utf8")}}function dk(e){let t=e?.environment.sources??[];if(t.length===0)return[...pi];let n=new Set([...ck,...t]),r=new Set(pi),o=t.filter((s)=>!r.has(s)),i=[];for(let s of pi){if(s==="defaults")i.push(...o);if(n.has(s))i.push(s)}return i}async function Us(e,t){let n={},r=t.serviceCfg.working_dir;if(r!==""&&!ik(r))r=Kl(e,r);let o={repoRoot:e,profile:t.profile,service:t.service,serviceCfg:t.serviceCfg,workDir:r,cfg:t.cfg},i=uk(t),s={process:t.includeProcess===!1?{}:t.clientEnv??Qr(),profile:ui(t.profileEnv,t.cfg,i),dotenv:ui(await lk().load(o),t.cfg,i),generated:{},keychain:t.sourceValues?.keychain??pk(o),secret_manager:t.sourceValues?.secret_manager??await fk(o,t.fetchSecret),defaults:ui(t.serviceCfg.environment.defaults,t.cfg,i),vars:ui(t.serviceCfg.environment.vars,t.cfg,i),runtime:t.runtime};for(let a of dk(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,ui(await c.load(o),t.cfg,i))}for(let a of t.serviceCfg.environment.required)if((n[a]??"").trim()==="")throw T(X,`service ${t.service} missing required environment variable ${a}`);return n}function uk(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 ui(e,t,n){if(!t||Object.keys(e).length===0)return e;return Nl(e,t,n)}function pk(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=Kl(Ht(),"env",o);if(!Tg(i))continue;try{n[o]=Ag(i,"utf8").replace(/\n$/,"")}catch(s){throw pe(X,`unable to read keychain env ${o}`,s)}}return n}async function fk(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(!ak.test(s))throw T(X,`environment.secrets.${i} is not a Secret Manager resource`);if(!t)throw T(X,"environment source secret_manager is not configured \u2014 set credentials or remove it from environment.sources");o[i]=await t(s)}return o}function Eg(e,t){let n={},r=[".env",".env.development",".env.local"];if(t!=="")r.push(`.env.${t}`);for(let o of r){let i=Kl(e,o);if(!Tg(i))continue;try{let s=sk(Ag(i));Object.assign(n,s)}catch(s){throw pe(X,`unable to read ${i}`,s)}}return n}function Qr(){let e={};for(let[t,n]of Object.entries(process.env))if(n!==void 0)e[t]=n;return e}function Ks(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 fi(e){return{...e}}var pi,ak,ck;var ql=D(()=>{st();Pe();Xe();pi=["process","profile","dotenv","generated","keychain","secret_manager","defaults","vars","runtime"],ak=/^projects\/[^/]+\/secrets\/[^/]+(?:\/versions\/[^/]+)?$/,ck=["process","defaults","vars","runtime"]});function Lt(){return"devctl 0.2.0"}var ut="0.2.0",gi=1;import{createConnection as gk}from"net";var{spawn:mk}=globalThis.Bun;function bk(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 ${gi}`}function wk(e){if(e.compatible&&e.daemonVersion!==void 0&&e.daemonVersion!==ut)return`attached daemon is devctl ${e.daemonVersion}; this client is ${ut} (run \`devctl down\` then start again to update it)`;return}function Vl(e,t){if(!e.compat.compatible&&!xk.has(t))throw Se(Ye,bk(e.compat),"run `devctl down` to stop it, then start again")}class Og{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(df({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=vk){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 Mg(e,t){let n=Ps(e),r=Date.now()+t;return new Promise((o,i)=>{let s=()=>{let a=gk(n);a.once("connect",()=>{let c=new Og(a);Sk(c).finally(()=>o(c))}),a.once("error",(c)=>{if(a.destroy(),Date.now()>=r){i(Se(Ye,"supervisor is not running","run `devctl start` or `devctl attach` after starting services"));return}setTimeout(s,hk)})};s()})}async function Sk(e){let t;try{t=await e.call("ping",null,Dg)}catch{return}let n=kk(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===gi,legacy:!1,daemonVersion:o,daemonProtocol:r}}function kk(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}async function cr(e){try{return await Mg(e,yk)}catch{return}}function Ck(e,t,n,r){return n?[e,...r]:[e,t,...r]}async function $g(e,t){let n=await cr(e);if(n)return n;ff(e);let r=ti(e),o=Ck(process.execPath,process.argv[1]??"",Bun.isStandaloneExecutable===!0,["--config",t,"_supervisor","--repo",e]);mk({cmd:o,env:process.env,stdout:"ignore",stderr:Bun.file(r),stdin:"ignore",detached:!0}).unref();try{return await Mg(e,Dg)}catch{throw Se(Ye,"supervisor failed to start",`see ${r} for details`)}}class qs{cfg;client;constructor(e){this.cfg=e}async start(e){return await this.call("start",{...e,client_env:Qr()})}async stop(e){await this.call("stop",{services:e})}async restart(e,t){await this.call("restart",{services:e,cascade:t===!0,client_env:Qr()})}async runTask(e){return await this.call("run_task",{name:e,client_env:Qr()},Lg)}async execService(e,t,n=!1){return await this.call("exec",{service:e,command:t,print_env:n,client_env:Qr()},Lg)}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 pe(Ye,"supervisor is not running",Error("no client"));return Vl(this.client,e),this.client.call(e,t,n)}}function mi(e){let t=e&&wk(e.compat);if(t)process.stderr.write(`warning: ${t}
|
|
8
|
+
`)}async function Jl(e,t,n=""){let r=Ws(e,t,n);if(!r)throw Se(Ye,"no devctl configuration found","run `devctl setup`, create a .devctl/config.yaml in the repository root, or pass --repo");let o=await cr(r.repoRoot);return mi(o),{repoRoot:r.repoRoot,client:o}}async function Ct(e,t,n,r){let o=r?.allowMissingConfig===!0?ci(e,t):dt(e,t),i=new qs(o);if(!n)return i.client=await cr(o.repoRoot),mi(i.client),i;return i.client=await $g(o.repoRoot,o.configPath),mi(i.client),i}async function Ig(e){let t=new qs(or());return t.client=e,mi(t.client),t.cfg=await t.configSnapshot(),t}async function Fg(e,t){let n=Ws(e,"",t),r=n?await cr(n.repoRoot):void 0;if(!r)throw Se(Ye,"supervisor is not running","run `devctl start` before `devctl attach`");return Ig(r)}async function Ng(e,t){let n=Ws(e,"",t),r=n?await cr(n.repoRoot):void 0;if(r)return Ig(r);let o=dt(e,t),i=new qs(o);return i.client=await $g(o.repoRoot,o.configPath),mi(i.client),i.cfg=await i.configSnapshot(),i}var hk=50,Dg=8000,yk=200,vk=30000,Lg=86400000,xk;var zl=D(()=>{st();Rg();ql();Pe();Xe();xk=new Set(["logs","logs_page","logs_stats"])});function Js(e){if(pn(e))return It({kind:lr,serviceAccount:e.service_account});if(bf(e)&&(e.type!==""||e.mode!==""))return It({kind:Vs});let t=(e.type||e.mode).toLowerCase();if(t!=="")return It({kind:t,providerConfig:e.config??{}});return It({kind:Zr})}function dr(e){if(e.type.toLowerCase()==="none")return It({kind:Zr});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 It({kind:lr,serviceAccount:n});if(e.type.toLowerCase()==="iap"&&t==="")return It({kind:Zr});if(e.type===""&&t==="")return It({kind:Zr});return It({kind:Vs})}function Hg(e){return e.kind===Vs||e.kind===lr}function eo(e){if(e.tokenKey!=="")return e.tokenKey;if(e.kind===lr)return`sa:${e.serviceAccount}`;if(e.email!=="")return`user:${e.email}`;return"user"}function It(e={}){return{kind:Zr,email:"",serviceAccount:"",project:"",projectSource:"",adcAvailable:!1,providerConfig:{},tokenKey:"",...e}}function Yl(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(pn(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 Hn(e){return Yl(e).filter((t)=>t.active).map((t)=>t.email)}function jg(e,t,n){let r=[];for(let o of t){let i=e.services[o];if(!i)continue;let s=Js(i.identity);if(pn(i.identity)&&i.identity.service_account===""){r.push({name:o,message:"service account identity is not configured"});continue}if((Hg(s)||i.capabilities.some((c)=>c==="google_api"||c==="iap"||c==="service_identity"))&&!n)r.push({name:o,message:"ADC unavailable"})}return r}function hi(e){if(Hn(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(Hg(Js(t.identity)))return!0;return t.capabilities.some((n)=>n==="google_api"||n==="iap"||n==="service_identity")})}function Xl(){return{name:"user",accepts:(e)=>!pn(e),resolve:async(e,t)=>{if(e.type===""&&e.mode==="")return It({kind:Zr});return{...await t(),kind:Vs}}}}function Ql(){return{name:"service_account",accepts:(e)=>pn(e),resolve:async(e,t)=>{if(e.service_account==="")throw T(ks,"service account identity is not configured");return{...await t(),kind:lr,serviceAccount:e.service_account}}}}async function Bg(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(pn(e))return Ql().resolve(e,t);return Xl().resolve(e,t)}var Vs="user",lr="service_account",Zr="none";var ur=D(()=>{st();Pe()});import{existsSync as zs,readFileSync as _k}from"fs";import{homedir as Gg}from"os";import{join as Zl}from"path";var{spawn:ed}=globalThis.Bun;function no(){let e=globalThis;if(e.window&&typeof e.window.fetch!=="function")e.window.fetch=fetch}function td(){let e=process.env.GOOGLE_APPLICATION_CREDENTIALS||Zl(Gg(),".config","gcloud","application_default_credentials.json");if(!zs(e))return"";try{let t=JSON.parse(_k(e,"utf8"));return typeof t.quota_project_id==="string"?t.quota_project_id:""}catch{return""}}async function Ut(e){let t={gcloudInstalled:await nd("gcloud"),adcAvailable:!1,userEmail:"",projectID:"",projectSource:""};if(e!=="")t.projectID=e,t.projectSource="configuration";else{let n=Dk("GOOGLE_CLOUD_PROJECT","GCLOUD_PROJECT","GOOGLE_PROJECT");if(n!=="")t.projectID=n,t.projectSource="environment variable";else if(t.gcloudInstalled){let r=await Wg("core/project");if(r!=="")t.projectID=r,t.projectSource="gcloud configuration"}}if(yi())try{await Jg(Ek(t),Rk)}catch(n){t.adcAvailable=!1,t.error=ro(n)}if(t.userEmail===""&&t.gcloudInstalled)t.userEmail=await Wg("core/account");return t}async function Ek(e){no();let{GoogleAuth:t}=await import("google-auth-library"),n=new t({scopes:[Pk]});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 Tk(n);if(o!=="")e.userEmail=o}async function Tk(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=Ak(n);if(r!=="")return r}}catch{return""}return""}function Ak(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 Kg(e){let t=await Ut(e);return It({kind:"user",email:t.userEmail,project:t.projectID,projectSource:t.projectSource,adcAvailable:t.adcAvailable})}async function Ys(){if(await ed({cmd:["gcloud","auth","application-default","login"],stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited!==0)throw Se(Kr,"application-default login failed","run `gcloud auth application-default login`")}async function qg(){if(await ed({cmd:["gcloud","auth","application-default","revoke","--quiet"],stdout:"ignore",stderr:"pipe"}).exited!==0)throw Se(Kr,"failed to revoke application-default credentials","run `gcloud auth application-default revoke`")}function ro(e){let t=Lk(e).toLowerCase();if(to(t,["unauth","invalid_grant","token has been expired","expired"]))return Se(Kr,"credential expired or invalid","run `devctl auth login` or `gcloud auth application-default login`");if(to(t,["api has not been used","has not been enabled","access not configured","service_disabled"]))return Se(nr,"required Google API is not enabled","enable the API in the target service account project; devctl will not enable APIs automatically");if(to(t,["permission","forbidden","iam"])){if(to(t,["serviceaccounttoken","iamcredentials","token creator","getaccesstoken"]))return Se(ks,"cannot impersonate service account","ask an administrator to grant roles/iam.serviceAccountTokenCreator on the target service account");return Se(nr,"authorization failure","verify IAM permissions for the current user on this project")}if(t.includes("audience"))return Se(al,"IAP audience is incorrect","set auth.audience on the proxy route to the IAP OAuth client ID");if(t.includes("iap"))return pe(al,"IAP authentication failure",e);if(t.includes("project"))return Se(X,"wrong or missing Google project","set google.project_id in .devctl/config.yaml");if(to(t,["timeout","network","connection refused","no such host"]))return pe(Ye,"network problem reaching Google Cloud",e);if(to(t,["adc","default credentials","could not find"]))return Se(Kr,"application default credentials unavailable","run `gcloud auth application-default login`");return pe(Kr,"Google authentication failed",e)}function Lk(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 to(e,t){return t.some((n)=>e.includes(n))}function Dk(...e){for(let t of e){let n=process.env[t];if(n)return n}return""}async function nd(e){try{return(await Vg(process.platform==="win32"?["where",e]:["which",e],Ug)).code===0}catch{return!1}}function yi(){let e=process.env.GOOGLE_APPLICATION_CREDENTIALS;if(e&&zs(e))return!0;if(zs(Zl(Gg(),".config","gcloud","application_default_credentials.json")))return!0;let t=process.env.APPDATA;return Boolean(t&&zs(Zl(t,"gcloud","application_default_credentials.json")))}async function Wg(e){try{let t=await Vg(["gcloud","config","get-value",e],Ug);if(t.code!==0)return"";let n=t.stdout.trim();if(n===""||n==="(unset)")return"";return n}catch{return""}}async function Vg(e,t){let n=ed({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 Jg(Promise.all([r,n.exited]),t);return{code:i??1,stdout:o}}catch{return n.kill(),{code:1,stdout:""}}}function Jg(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 Pk="https://www.googleapis.com/auth/cloud-platform",Ug=1500,Rk=2000;var pr=D(()=>{Ur();Pe();ur()});var{spawn:rd}=globalThis.Bun;import{createServer as zg}from"net";async function Yg(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>=od?l:c.value;if(l===void 0&&c.auto)d=await Mk();if(d<od||d>Ok)throw new De(X,`invalid port ${d} on service ${i}`,{service:i});if(r[d]&&r[d]!==i)throw new De(X,`duplicate port ${d} used by ${r[d]} and ${i}`,{service:i});if(l!==d&&!c.auto&&!await oo(d))throw await $k(i,c.name,d);r[d]=i,a[c.name]=d}o[i]=a}return o}function Mk(){return new Promise((e,t)=>{let n=zg();n.listen(0,"127.0.0.1",()=>{let r=n.address();n.close(()=>{if(r&&typeof r==="object")e(r.port);else t(pe(X,"unable to allocate dynamic port",Error("no address")))})}),n.on("error",(r)=>t(pe(X,"unable to allocate dynamic port",r)))})}async function Xs(e){let t=e.ports.filter((r)=>!r.auto&&r.value>=od);if(t.length===0)return;let n={};for(let r of t){if(await oo(r.value))return;n[r.name]=r.value}return n}function oo(e){return new Promise((t)=>{let n=zg();n.listen(e,"127.0.0.1",()=>{n.close(()=>t(!0))}),n.on("error",()=>t(!1))})}async function $k(e,t,n){let r=await io(n);return Ik(e,t,n,r)}function Ik(e,t,n,r){let o=t===""?`${e} port`:`${e} ports.${t}`;if(r&&r.pid===process.pid)return Se(Je,`${e} blocked: this TUI already holds port ${n}`,`Stop the proxy from the Proxy screen, or change ${o} in .devctl.`,e);if(r)return Se(Je,`${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 Se(Je,`${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 Fk(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 io(e){if(process.platform==="win32")return Hk(e);let t=rd({cmd:["lsof","-nP",`-iTCP:${e}`,"-sTCP:LISTEN"],stdout:"pipe",stderr:"ignore"}),n=await new Response(t.stdout).text();await t.exited;let r=Fk(n,e);if(r)return r;let o=rd({cmd:["fuser","-n","tcp",String(e)],stdout:"pipe",stderr:"pipe"}),i=`${await new Response(o.stdout).text()} ${await new Response(o.stderr).text()}`;await o.exited;let s=i.match(/(\d+)/),a=s?Number(s[1]):0;if(!Number.isInteger(a)||a<=0)return;return{port:e,pid:a,command:"process"}}function Nk(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 Hk(e){let t=rd({cmd:["netstat","-ano"],stdout:"pipe",stderr:"ignore"}),n=t.stdout?await new Response(t.stdout).text():"";return await t.exited,Nk(n,e)}async function Qs(e){if(e.pid===process.pid)throw Se(Je,`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 pe(Je,`could not stop pid ${e.pid} on port ${e.port}`,t)}await Bk(jk);try{process.kill(e.pid,0),process.kill(e.pid,"SIGKILL")}catch{return}}function Bk(e){return new Promise((t)=>{setTimeout(t,e)})}var Ok=65535,od=1,jk=400;var vi=D(()=>{Pe()});var{spawn:cd}=globalThis.Bun;import{existsSync as ea,readdirSync as Wk,readFileSync as Xg,unlinkSync as Gk}from"fs";import{join as xi}from"path";function ad(e){return xi(Ht(),`${na(e)}${sd}`)}function ta(e){if(e==="file"||process.env.DEVCTL_HOME&&e!=="keychain")return new Zs;if(e==="keychain"||process.platform==="darwin"||process.platform==="win32"||process.platform==="linux")return new Qg(new Zs);return new Zs}class Zs{backend="file";async get(e){let t=Vk(e);if(!t||t.accessToken==="")return;return t}async set(e,t){jt(ad(e),`${JSON.stringify({...qk(t),key:e})}
|
|
11
|
+
`)}async delete(e){let t=ad(e);if(ea(t))Gk(t)}async list(){let e=Ht();if(!ea(e))return[];let t=[];for(let n of Wk(e)){if(!n.endsWith(sd))continue;let r=n.slice(0,-sd.length),o=Zg(xi(Ht(),n));if(!o)continue;t.push(em(o.key??r,o.record))}return t.sort((n,r)=>n.identity.localeCompare(r.identity))}}class Qg{backend="keychain";fallback;constructor(e){this.fallback=e}async get(e){let t=await Jk(e);if(t)return t;return this.fallback.get(e)}async set(e,t){if(!await zk(e,t))await this.fallback.set(e,t);Uk(e)}async delete(e){await Yk(e),await this.fallback.delete(e),Kk(e)}async list(){let e=new Set(dd()),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,em(r,o))}return[...n.values()].sort((r,o)=>r.identity.localeCompare(o.identity))}}function Uk(e){let t=dd();if(!t.includes(e))jt(xi(Ht(),ld),`${JSON.stringify([...t,e])}
|
|
12
|
+
`)}function Kk(e){let t=dd(),n=t.filter((r)=>r!==e);if(n.length!==t.length)jt(xi(Ht(),ld),`${JSON.stringify(n)}
|
|
13
|
+
`)}function dd(){let e=xi(Ht(),ld);if(!ea(e))return[];try{let t=JSON.parse(Xg(e,"utf8"));return Array.isArray(t)?t.filter((n)=>typeof n==="string"):[]}catch{return[]}}function qk(e){return{...e,accessToken:""}}function Vk(e){return Zg(ad(e))?.record}function Zg(e){if(!ea(e))return;try{let t=JSON.parse(Xg(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 em(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 na(e){return e.replace(/[^A-Za-z0-9._-]+/g,"_").slice(0,80)||"token"}async function Jk(e){let t=await Xk(e);if(!t)return;try{return JSON.parse(t)}catch{return}}async function zk(e,t){let n=JSON.stringify(t);if(process.platform==="darwin")return await so(["security","delete-generic-password","-s",fr,"-a",e]),await so(["security","add-generic-password","-s",fr,"-a",e,"-w",n,"-U"])===0;if(process.platform==="linux")return await Qk(["secret-tool","store","--label",`devctl ${e}`,"service",fr,"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-${na(e)}.bin', $enc)`;return await so(["powershell","-NoProfile","-Command",o])===0}return!1}async function Yk(e){if(process.platform==="darwin"){await so(["security","delete-generic-password","-s",fr,"-a",e]);return}if(process.platform==="linux"){await so(["secret-tool","clear","service",fr,"account",e]);return}if(process.platform==="win32")await so(["powershell","-NoProfile","-Command",`Remove-Item -ErrorAction SilentlyContinue ($env:LOCALAPPDATA + '\\devctl-cred-${na(e)}.bin')`])}async function Xk(e){if(process.platform==="darwin"){let t=await id(["security","find-generic-password","-s",fr,"-a",e,"-w"]);return t.code===0&&t.stdout!==""?t.stdout:void 0}if(process.platform==="linux"){let t=await id(["secret-tool","lookup","service",fr,"account",e]);return t.code===0&&t.stdout!==""?t.stdout:void 0}if(process.platform==="win32"){let t=`$p = $env:LOCALAPPDATA + '\\devctl-cred-${na(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 id(["powershell","-NoProfile","-Command",t]);return n.code===0&&n.stdout!==""?n.stdout:void 0}return}async function so(e){try{return await cd({cmd:e,stdout:"ignore",stderr:"ignore",timeout:ud}).exited}catch{return 1}}async function Qk(e,t){try{return await cd({cmd:e,stdin:new TextEncoder().encode(t),stdout:"ignore",stderr:"ignore",timeout:ud}).exited}catch{return 1}}async function id(e){try{let t=cd({cmd:e,stdout:"pipe",stderr:"ignore",timeout:ud}),n=t.stdout?await new Response(t.stdout).text():"";return{code:await t.exited,stdout:n.trim()}}catch{return{code:1,stdout:""}}}var ld="keychain-index.json",fr="devctl.credentials",sd=".cred.json",ud=3000;var pd=D(()=>{Xe()});function Oe(e,t,n){return{type:e,timestamp:new Date().toISOString(),service:t,payload:n}}class hd{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 tm="ServiceStarted",fd="ServiceStopped",nm="ServiceFailed",rm="ServiceStateChanged",om="ServiceHealthChanged",ra="LogReceived",ao="TokenRefreshed",gr="TokenRefreshFailed",gd="AuthenticationChanged",im="ProxyStarted",sm="ProxyStopped",md="ProxyRequest",oa="ConfigurationChanged",bi="ConfigurationReloadFailed",am="SessionRecovered";async function cm(e,t={}){let n=t.attempts??Zk,r=t.backoffMs??eC,o=t.retry??tC,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 tC(e){if(e instanceof De)return e.kind!==X&&e.kind!==nr;return!0}function nC(e){return new Promise((t)=>{setTimeout(t,e)})}var Zk=3,eC=200;var lm=D(()=>{Pe()});var fm={};ws(fm,{TokenManager:()=>co,expiresSoonToken:()=>um,googleTokenProviders:()=>mr,isValidToken:()=>dm,staticTokenProvider:()=>fC,tokenCacheKey:()=>yd,tokenMetaPath:()=>pm});import{createHash as rC}from"crypto";import{join as oC}from"path";import{GoogleAuth as sa,Impersonated as iC}from"google-auth-library";function yd(e,t,n){return`${e}|${t}|${n.join(",")}`}function dm(e,t=vd){if(e.accessToken==="")return!1;return e.expiresAt.getTime()-Date.now()>=t}function um(e,t=vd){if(e.accessToken==="")return!0;let n=e.expiresAt.getTime()-Date.now();return n>0&&n<t}class co{cache=new Map;inflight=new Map;providers;thresholdMs;bus;store;constructor(e,t,n,r){this.thresholdMs=e>0?e:vd,this.providers=[...t],this.bus=n,this.store=r??ta(process.env.DEVCTL_CREDENTIAL_BACKEND==="file"?"file":void 0)}replaceProviders(e){this.providers.splice(0,this.providers.length,...e)}isValid(e){return dm(e,this.thresholdMs)}expiresSoon(e){return um(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=yd(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=yd(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 T(dn,`no token provider accepts identity ${t}`);let i=T(dn,"no token provider available");for(let s of o)try{let a=await cm(()=>s.fetch(t,n,r),{attempts:aC,backoffMs:cC,retry:kC});return this.cache.set(e,a),dC(e,a),await this.store.set(e,uC(a)),this.bus?.publish(Oe(ao,"",{identity:a.identity,audience:a.audience})),a}catch(a){i=a instanceof Error?a:Error(String(a))}throw this.bus?.publish(Oe(gr,"",{identity:t,audience:n,error:j(i)})),i}async loadStored(e){let t=await this.store.get(e);if(!t||t.accessToken==="")return;return pC(t)}async clearStore(){let e=await this.store.list();await Promise.all(e.map((t)=>this.store.delete(t.key)))}}function pm(e){let t=rC("sha256").update(e).digest("hex").slice(0,16);return oC(Ht(),`${t}.json`)}function dC(e,t){let n={identity:t.identity,audience:t.audience,expires_at:t.expiresAt.toISOString(),scopes:t.scopes};jt(pm(e),`${JSON.stringify(n)}
|
|
14
|
+
`)}function uC(e){return{identity:e.identity,audience:e.audience,scopes:e.scopes,accessToken:e.accessToken,tokenType:e.tokenType,expiresAt:e.expiresAt.toISOString()}}function pC(e){return{accessToken:e.accessToken,tokenType:e.tokenType||"Bearer",expiresAt:new Date(e.expiresAt),audience:e.audience,identity:e.identity,scopes:e.scopes}}function mr(){return[hC(),mC(),gC()]}function fC(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 gC(){return{name:"user",accepts:(e,t)=>!e.startsWith("sa:")&&t==="",fetch:async(e,t,n)=>{if(e.startsWith("sa:"))throw T(dn,"user provider cannot mint service-account tokens");return bC(e,t,n)}}}function mC(){return{name:"service_account",accepts:(e,t)=>e.startsWith("sa:")&&t==="",fetch:async(e,t,n)=>{if(!e.startsWith("sa:"))throw T(dn,"service-account provider cannot mint user tokens");return yC(e,t,n)}}}function hC(){return{name:"iap",accepts:(e,t)=>t!=="",fetch:async(e,t,n)=>{if(t==="")throw T(dn,"IAP audience is required");if(e.startsWith("sa:"))return vC(e,t,n);return xC(e,t,n)}}}async function yC(e,t,n){let r=e.slice(3);try{no();let i=await new sa({scopes:n.length>0?n:[ia]}).getClient(),s=new iC({sourceClient:i,targetPrincipal:r,targetScopes:n.length>0?n:[ia],lifetime:3600}),a=await s.getAccessToken(),c=typeof a==="string"?a:a?.token;if(!c)throw T(dn,"empty impersonated token");return{accessToken:c,tokenType:"Bearer",expiresAt:aa(c,s),audience:t,identity:e,scopes:n}}catch(o){throw ro(o)}}async function vC(e,t,n){let r=e.slice(3);try{no();let i=await new sa({scopes:[ia]}).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 T(dn,"empty impersonated IAP id token");return{accessToken:c,tokenType:"Bearer",expiresAt:aa(c),audience:t,identity:e,scopes:n}}catch(o){throw ro(o)}}async function xC(e,t,n){try{no();let i=await(await new sa({scopes:n.length>0?n:[lC]}).getIdTokenClient(t)).idTokenProvider.fetchIdToken(t);return{accessToken:i,tokenType:"Bearer",expiresAt:aa(i),audience:t,identity:e,scopes:n}}catch(r){throw ro(r)}}async function bC(e,t,n){try{no();let o=await new sa({scopes:n.length>0?n:[ia]}).getClient(),i=await o.getAccessToken();if(!i.token)throw T(dn,"empty access token");return{accessToken:i.token,tokenType:"Bearer",expiresAt:wC(o,i.token),audience:t,identity:e,scopes:n}}catch(r){throw ro(r)}}function aa(e,t){if(t?.credentials?.expiry_date)return new Date(t.credentials.expiry_date);return SC(e)??new Date(Date.now()+sC)}function wC(e,t){return aa(t,e)}function SC(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 kC(e){if(e instanceof De)return e.kind!==X&&e.kind!==nr;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 vd=300000,sC=3000000,aC=3,cC=200,ia="https://www.googleapis.com/auth/cloud-platform",lC="https://www.googleapis.com/auth/userinfo.email";var wi=D(()=>{Ur();pd();Pe();pr();lm();Xe()});async function jn(e,t=gm,n,r){let o={checks:[],issues:0},i="Preparing diagnostics",s=()=>n?.({active:i,checks:[...o.checks]}),a=(g)=>{i=g,s()},c=(g)=>{if(o.checks.push(g),g.severity==="error")o.issues+=1;s()},l=[...new Set(Object.values(e.services).flatMap((g)=>g.container?[g.container.runtime||"docker"]:[]))];for(let g of l){a(`${g} container runtime`);let x=await t.hasCommand(g),y=x&&await(t.containerRuntimeAvailable??gm.containerRuntimeAvailable)(g);c(y?{name:`${g} container runtime`,severity:"ok",message:`${g} daemon reachable`}:{name:`${g} container runtime`,severity:"error",message:x?`${g} daemon is not reachable`:`${g} not found`,hint:`install and start ${g}`})}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((g)=>g.capabilities.includes("google")||g.identity.type!=="")){a("Live Google access");let g=!0,x=(y)=>{if(g)c(y)};try{await ki((async()=>{await PC(e,x,t,d.userEmail),await _C(e,x,t)})(),t.liveDeadlineMs??CC)}catch(y){x({name:"Live Google probes",severity:"warn",message:j(y),hint:"network or timeout \u2014 retry when online"})}finally{g=!1}}for(let g of e.doctor.tools){let x=g.command||g.name;if(a(`${g.name} installed`),await t.hasCommand(x))c({name:`${g.name} installed`,severity:"ok",message:`${x} found`});else c({name:`${g.name} installed`,severity:"error",message:`${x} not found`,hint:`install ${g.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 g=Jt(e);if(g.length>0)c({name:"Repository configuration",severity:"error",message:g.join("; ")});else c({name:"Repository configuration",severity:"ok",message:"valid"})}catch(g){c({name:"Repository configuration",severity:"error",message:j(g)})}let m={};for(let[g,x]of Object.entries(e.services))for(let y of x.ports){if(y.auto)continue;let b=`Port ${y.value}`;if(a(b),m[y.value])c({name:b,severity:"error",message:`configured on both ${m[y.value]} and ${g}`});else{m[y.value]=g;let k=r?.services?.[g],S=Boolean(x.container&&k&&["STARTING","RUNNING","HEALTHY","UNHEALTHY"].includes(k.state??""));if(Boolean(k&&(k.pid>0||S)&&Object.values(k.ports).includes(y.value)))c({name:b,severity:"ok",message:`in use by running service ${g}`});else if(await t.portAvailable(y.value))c({name:b,severity:"ok",message:"available"});else c(await hm(b,y.value,`services.${g}.ports`))}}if(e.proxy.listen.port>0){let g=`Port ${e.proxy.listen.port}`;if(a(g),r?.proxyRunning)c({name:g,severity:"ok",message:"in use by the running proxy"});else if(await t.portAvailable(e.proxy.listen.port))c({name:g,severity:"ok",message:"proxy listen port available"});else c(await hm(g,e.proxy.listen.port,"proxy.listen.port"))}return i="Diagnostics complete",s(),o}async function _C(e,t,n){let r=e.google.project_id,o=n.hasLocalAdc??yi;if(r===""||!o())return;let i=n.probeServiceUsage??xm,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)=>ki(i(r,c.service),Si)))).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:j(c.reason),hint:`enable ${d.service} in the Google Cloud console \u2014 doctor never auto-enables APIs`})})}async function ym(){if(!xd)xd=Promise.resolve().then(() => (wi(),fm)).then(({TokenManager:e,googleTokenProviders:t})=>new e(60000,t(),void 0,ta("file")));return xd}async function vm(e,t){await(await ym()).get(e,t,[])}async function xm(e,t){let n=await ym(),r=await ki(n.get("user","",[]),Si),o=`https://serviceusage.googleapis.com/v1/projects/${e}/services/${t}`,i=await fetch(o,{headers:{Authorization:`Bearer ${r.accessToken}`},signal:AbortSignal.timeout(Si)});if(!i.ok)return!1;return(await i.json().catch(()=>{return}))?.state==="ENABLED"}async function PC(e,t,n,r){let o=Hn(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??yi)())return;let c=n.mintToken??vm,l=o.map(async(f)=>{try{await ki(c(`sa:${f}`,""),Si),t({name:`Impersonate ${f}`,severity:"ok",message:"token minted"})}catch(m){let g=(n.adcQuotaProject??td)(),x=r||"the ADC principal",y=g===""?"unknown":g,b=mm(`Impersonate ${f}`,m,`grant roles/iam.serviceAccountTokenCreator to ${x} on ${f}; ADC quota project: ${y}`);if(g!==""&&b.message.toLowerCase().includes("api is not enabled"))b.message=`IAM Credentials API is disabled in ADC quota project ${g}`,b.hint=`enable iamcredentials.googleapis.com in ${g}, or set the ADC quota project to ${e.google.project_id}`;else if(b.message.toLowerCase()==="google authentication failed")b.message=`access-token mint failed: ${x} \u2192 ${f}`,b.hint=`verify roles/iam.serviceAccountTokenCreator for ${x} on this service account; ADC quota project: ${y}`;t(b)}}),d=s.map(async(f)=>{let m=dr(f.auth).kind===lr?`sa:${dr(f.auth).serviceAccount}`:"user";try{await ki(c(m,f.auth.audience),Si),t({name:`IAP ${f.name}`,severity:"ok",message:"id token minted"})}catch(g){t(mm(`IAP ${f.name}`,g,"check IAP OAuth client ID and ADC"))}});await Promise.all([...l,...d])}function mm(e,t,n){let r=j(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 De&&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 ki(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 hm(e,t,n){let r=await io(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 ca(e){let t=[`${Lt()} 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
15
|
`)+`
|
|
16
|
-
`}var
|
|
16
|
+
`}var Si=4000,CC=8000,gm,xd;var Ci=D(()=>{Ur();st();Pe();pr();ur();vi();pd();gm={detectGoogle:Ut,hasCommand:nd,portAvailable:oo,hasLocalAdc:yi,adcQuotaProject:td,mintToken:vm,probeServiceUsage:xm,containerRuntimeAvailable:async(e)=>{try{return await Bun.spawn({cmd:[e,"info"],stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited===0}catch{return!1}}}});function po(e){if(e.state===Ft&&e.health===_t)return hr;if(e.state===Ft&&e.health===ke)return lo;return e.state}function la(e){return{name:e,state:uo,health:Dt,pid:0,ports:{},restarts:0,last_error:"",identity:"",startTime:void 0,cpuPercent:void 0,memoryKB:void 0,profile:"",env_source:"daemon",orphaned:!1}}function wm(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=St(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 T(af,"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 Sd(e,t){if(!e.services[t])throw T(ei,`unknown service "${t}"`)}function Pi(e,t,n){let r={},o=(a)=>{if(r[a])return;Sd(e,a),r[a]=!0;for(let c of e.services[a]?.dependencies??[])o(St(c))};for(let a of t)o(a);let i=wm(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 kd(e,t){let n={};for(let[i,s]of Object.entries(e.services))for(let a of s.dependencies){let c=St(a);n[c]=[...n[c]??[],i]}let r={},o=(i)=>{if(r[i])return;Sd(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 Sm(e,t){let n=[...wm(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 Ri(e,t){let n=Object.fromEntries(kd(e,t).map((r)=>[r,!0]));return Sm(e,n)}function km(e,t){let n={};for(let r of t)Sd(e,r),n[r]=!0;return Sm(e,n)}function Cd(e){let t="";if(e.profile!=="")t+=`Profile: ${e.profile}
|
|
17
17
|
|
|
18
18
|
`;t+=`Plan:
|
|
19
19
|
|
|
20
|
-
`;let
|
|
21
|
-
`,
|
|
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
22
|
Blocked:
|
|
23
|
-
`;for(let
|
|
24
|
-
`}return t}function
|
|
23
|
+
`;for(let r of e.blockers??[])t+=`- ${r.name}: ${r.message}
|
|
24
|
+
`}return t}function da(e){return`${e.join(", ")} changed and only take effect after a full \`devctl down && devctl start\`, not a reload`}function RC(e,t,n){let r={};if(t!==""){let o=e.profiles[t];if(!o)throw T("configuration",`unknown profile "${t}"`);Object.assign(r,o.environment)}if(n.length>0)return{services:bm(e,n),env:r};if(t==="")return{services:Object.keys(e.services),env:r};return{services:bm(e,e.profiles[t]?.services??[]),env:r}}function EC(e){return Object.keys(e.profiles).sort()[0]??""}function ua(e,t){let n=t.services??[],r=t.profile??"";if(n.length===0&&r===""){if(r=t.activeProfile||EC(e),r==="")throw T(X,"no profile or services given; pass service names or add a profile")}let o=RC(e,r,n);return{services:o.services,env:o.env,profile:r}}function bm(e,t){let n={},r=[];for(let o of t){if(n[o])continue;if(!e.services[o])throw T("service_not_found",`unknown service "${o}"`);n[o]=!0,r.push(o)}return r}var bd="STARTING",Ft="RUNNING",hr="HEALTHY",lo="UNHEALTHY",wd="STOPPING",uo="STOPPED",yr="FAILED",_i="RESTARTING",Dt="UNKNOWN",_t="HEALTHY",ke="UNHEALTHY";var vr=D(()=>{st();Pe()});var Pm={};ws(Pm,{createStarterConfig:()=>$C,resolveSetupTarget:()=>Cm,runSetup:()=>Ed});import{existsSync as Rd,mkdirSync as _d,statSync as TC,writeFileSync as AC}from"fs";import{createInterface as LC}from"readline/promises";import{stdin as DC,stdout as OC}from"process";import{basename as pa,dirname as Pd,join as fn,resolve as MC}from"path";function Cm(e,t){let n=e===""?process.cwd():e;if(t==="")return{repo:n,cfgPath:fn(n,kt,Gt)};let r=MC(t);if(!(Rd(r)?TC(r).isDirectory():!/\.ya?ml$/i.test(r))){let i=Pd(r);return{repo:pa(i)===kt?Pd(i):i,cfgPath:r}}if(pa(r)===kt)return{repo:Pd(r),cfgPath:fn(r,Gt)};return{repo:r,cfgPath:fn(r,kt,Gt)}}function $C(e,t=pa(e),n="",r="",o=!1){let i=fn(e,kt,Gt);if(!o&&Rd(i))throw T(X,`configuration already exists at ${i}; not overwriting`);return _m(e,t,n,r),i}async function Ed(e,t="",n=!1){let{repo:r,cfgPath:o}=Cm(e,t);if(!n&&Rd(o)){yt(`Found existing configuration at ${o}; nothing written.`),yt("Pass --force to overwrite it, or edit it directly.");return}let i=LC({input:DC,output:OC}),s=async(S,N)=>{let K=N!==""?` [${N}]`:"",v=(await i.question(`${S}${K}: `)).trim();return v===""?N:v},a=t===""?9:8,c=0,l=()=>(c+=1,c);if(yt(`devctl setup \u2014 ${a} steps`),yt(""),t==="")await s(`${l()}. Repository root`,r);let d=await s(`${l()}. Environment / project name`,pa(r)),f=await Ut(""),m=await s(`${l()}. Google Cloud project`,f.projectID);if(yt(`${l()}. Authentication`),!f.adcAvailable){if(yt(" ADC is not available. Run: gcloud auth application-default login"),(await s(" Run login now? (y/N)","n")).toLowerCase()==="y")try{await Ys()}catch(N){yt(` login failed: ${N instanceof Error?N.message:String(N)}`)}}else if(yt(" \u2713 Application Default Credentials available"),f.userEmail!=="")yt(` user: ${f.userEmail}`);let g=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)`,""),y=await s(`${l()}. Proxy listen port`,String(Es)),b=Number(y)||Es,k=await s(`${l()}. Default profile name (optional)`,"");i.close(),_m(r,d,m,k,{sa:g,audience:x,proxyPort:b}),yt(""),yt(`Wrote starter configuration to ${o}`),yt(`${l()}. Validation`);try{let S=dt(r,""),N=await jn(S);yt(ca(N))}catch(S){yt(` configuration is not valid yet: ${S instanceof Error?S.message:String(S)}`),yt(" edit .devctl/config.yaml and run `devctl config validate`")}}function _m(e,t,n,r,o={sa:"",audience:"",proxyPort:Es}){let i=fn(e,".devctl");_d(fn(i,"services"),{recursive:!0}),_d(fn(i,"profiles"),{recursive:!0}),_d(fn(i,"proxy"),{recursive:!0}),AC(fn(i,"config.yaml"),`# yaml-language-server: $schema=https://raw.githubusercontent.com/amr-m-abdelgawad/devctl/main/schema/devctl.config.schema.json
|
|
25
25
|
version: 1
|
|
26
26
|
|
|
27
27
|
project:
|
|
28
28
|
name: ${t}
|
|
29
29
|
|
|
30
30
|
google:
|
|
31
|
-
project_id: ${
|
|
31
|
+
project_id: ${n}
|
|
32
32
|
|
|
33
|
-
profiles:${
|
|
34
|
-
${
|
|
33
|
+
profiles:${r===""?" {}":`
|
|
34
|
+
${r}:
|
|
35
35
|
services: []`}
|
|
36
36
|
|
|
37
37
|
services:
|
|
@@ -68,13 +68,13 @@ auth:
|
|
|
68
68
|
shutdown:
|
|
69
69
|
stop_services_on_exit: true
|
|
70
70
|
grace_seconds: 10
|
|
71
|
-
`)}function
|
|
72
|
-
`)}var
|
|
73
|
-
`,o=
|
|
71
|
+
`)}function yt(e){process.stdout.write(`${e}
|
|
72
|
+
`)}var Td=D(()=>{st();Ci();Pe();pr()});var Wm={};ws(Wm,{DEFAULT_LOG_PAGE_SIZE:()=>Im,LevelDebug:()=>Id,LevelError:()=>ma,LevelFatal:()=>ha,LevelInfo:()=>Fd,LevelTrace:()=>$d,LevelUnknown:()=>Hd,LevelWarn:()=>Nd,LogManager:()=>va,MAX_LOG_PAGE_SIZE:()=>Fm,clampLogPageSize:()=>Nm,compileLogSearch:()=>ya,defaultExportPath:()=>Hm,defaultLogParser:()=>jd,listSessions:()=>b_,loadSessionEvents:()=>w_,matchLog:()=>xr,openInFileManager:()=>ba,parseLevel:()=>Bd,parseRequestID:()=>Wd,pruneSessions:()=>Bm,resolveExportPath:()=>go,safeServiceFile:()=>jm,writeLogExport:()=>xa});import{spawn as Ld}from"child_process";import{createWriteStream as e_,existsSync as Ei,mkdirSync as t_,readdirSync as Md,readFileSync as n_,rmSync as r_,statSync as Od,writeFileSync as o_}from"fs";import{homedir as i_}from"os";import{dirname as Om,isAbsolute as s_,join as br,resolve as a_}from"path";function jd(){return{name:"default",parse:(e)=>({level:Bd(e),request_id:Wd(e)||void 0})}}function Bd(e){return l_.find((n)=>n.re.test(e))?.level??Hd}function Wd(e){return c_.exec(e)?.[1]??""}function xr(e,t){if(e.services&&e.services.length>0&&!e.services.includes(t.service))return!1;if(e.level&&(Lm[t.level]??2)<(Lm[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;if(!e.search)return!0;if(e.regex){let n=ya(e.search);if(n)return n.test(t.message)}return t.message.toLowerCase().includes(e.search.toLowerCase())}function ya(e){let t=f_(e);if(t===void 0)return;return new RegExp(t)}function f_(e){if(e.length===0||e.length>d_)return;let t={raw:e,i:0,out:[],quantifiers:0,depth:0,lastAtom:"none",groupQuant:[]};if(!Mm(t)||t.i!==e.length||t.depth!==0)return;return t.out.join("")}function Mm(e){while(e.i<e.raw.length){if(e.raw[e.i]===")")return!0;if(!g_(e))return!1}return!0}function g_(e){let t=e.raw[e.i]??"";if(t==="|")return ga(e,"|","none");if(t==="^")return ga(e,"^","none");if(t==="$")return ga(e,"$","none");if(t===".")return ga(e,".","atom");if(t==="(")return m_(e);if(t==="[")return y_(e);if(t==="*"||t==="+"||t==="?"||t==="{")return h_(e);if(t==="\\")return $m(e);return e.out.push(RegExp.escape(t)),e.i+=1,e.lastAtom="atom",!0}function ga(e,t,n){return e.out.push(t),e.i+=1,e.lastAtom=n,!0}function m_(e){if(e.i+=1,e.depth+=1,e.depth>p_)return!1;if(e.groupQuant.push(!1),e.out.push("(?:"),!Mm(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 h_(e){let t=e.raw[e.i]??"";if(t==="{"||e.lastAtom==="none"||e.lastAtom==="quant"||e.lastAtom==="quantified-group")return!1;if(e.quantifiers>=u_)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 n=e.groupQuant.length-1;if(n>=0)e.groupQuant[n]=!0;if(e.raw[e.i]==="?")e.out.push("?"),e.i+=1;return e.lastAtom="quant",!0}function y_(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(!$m(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 $m(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 Dm(e){return Buffer.from(JSON.stringify(e),"utf8").toString("base64url")}function x_(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 Dd(e,t){let n={...e};return n[t]=void 0,n}function Nm(e){if(!Number.isInteger(e)||(e??0)<=0)return Im;return Math.min(e,Fm)}class va{events=[];eventStart=0;nextSeq=1;max;bus;detector;persistDir;persist;sessionID;streams=new Map;lastWrite=new Map;parsers=[];constructor(e,t,n,r,o,i,s=0,a=0){this.max=e>0?e:v_,this.bus=t,this.detector=n,this.sessionID=i;let c=o===""||o.startsWith("~/")?_s():o;if(this.persist=r&&i!=="",this.persistDir=this.persist?br(c,`${Gd}${i}`):"",this.persist)t_(this.persistDir,{recursive:!0,mode:448}),Bm(c,s,a)}sessionDir(){return this.persistDir}setParsers(e){this.parsers=e}append(e){let t=this.parseLine(e.message),n={...e,timestamp:e.timestamp||new Date().toISOString(),level:e.level||t.level||Bd(e.message),request_id:e.request_id||t.request_id||Wd(e.message),message:this.detector?this.detector.redactText(e.message):e.message,seq:this.nextSeq++};if(this.events.length<this.max)this.events.push(n);else this.events[this.eventStart]=n,this.eventStart=(this.eventStart+1)%this.max;if(this.bus?.publish(Oe(ra,n.service,{event:n,level:n.level})),this.persist){let r=`${n.timestamp} ${n.service} ${n.level} ${n.message}
|
|
73
|
+
`,o=jm(n.service),i=this.streamFor(o);this.lastWrite.set(o,new Promise((s)=>{i.write(r,()=>s())}))}}async flush(){await Promise.all([...this.lastWrite.values()])}parseLine(e){let t={};for(let n of this.parsers)try{let r=n.parse(e);if(r)t={...t,...r}}catch{}return t}streamFor(e){let t=this.streams.get(e);if(t===void 0)t=e_(br(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=[];return this.forEachEvent((n)=>{if(xr(e,n))t.push(n)}),t}queryPage(e,t={}){let n=Nm(t.limit),r=t.cursor?x_(t.cursor):void 0,o=r!==void 0&&r.session!==this.sessionID,i=o?void 0:r,s=i?t.direction??"backward":"backward",a=[];this.forEachEvent((g)=>{if(xr(e,g))a.push(g)});let c;if(!i)c=a.slice(Math.max(0,a.length-n));else if(s==="forward")c=a.filter((g)=>g.seq>i.seq).slice(0,n);else{let g=a.filter((x)=>x.seq<i.seq);c=g.slice(Math.max(0,g.length-n))}let l=c[0]?.seq,d=c[c.length-1]?.seq,f=l!==void 0&&a.some((g)=>g.seq<l),m=d!==void 0&&a.some((g)=>g.seq>d);return{events:c,prevCursor:Dm({session:this.sessionID,seq:l??i?.seq??0}),nextCursor:Dm({session:this.sessionID,seq:d??i?.seq??this.nextSeq-1}),hasNext:m,hasPrev:f,sessionChanged:o}}queryFacets(e){let t=Dd(e,"services"),n=Dd(e,"level"),r=Dd(e,"source"),o=0,i={},s={},a={};return this.forEachEvent((c)=>{if(xr(e,c))o+=1;if(xr(t,c))i[c.service]=(i[c.service]??0)+1;if(xr(n,c))s[c.level]=(s[c.level]??0)+1;if(xr(r,c))a[c.source]=(a[c.source]??0)+1}),{total:o,byService:i,byLevel:s,bySource:a}}snapshot(){let e={},t=0;return this.forEachEvent((n)=>{if(e[n.service]=(e[n.service]??0)+1,n.level===ma||n.level===ha)t+=1}),{total:this.events.length,errors:t,counts:e}}forEachEvent(e){let t=this.events.length;for(let n=0;n<t;n+=1){let r=this.events[(this.eventStart+n)%t];if(r)e(r)}}exportTo(e,t){xa(e,this.query(t))}}function Hm(e=new Date){let t=e.toISOString().replace(/[:.]/g,"-");return br(rr(),`devctl-logs-${t}.log`)}function go(e=""){if(e==="")return Hm();let t=e.startsWith("~/")?br(i_(),e.slice(2)):e;return s_(t)?t:a_(process.cwd(),t)}function xa(e,t){Vt(Om(e));let n=t.map((r)=>`${r.timestamp} ${r.service} ${r.level} ${r.message}`);o_(e,`${n.join(`
|
|
74
74
|
`)}
|
|
75
|
-
`,{mode:384})}function
|
|
76
|
-
`)){if(a.trim()==="")continue;let c=a.split(" ");
|
|
77
|
-
`||e==="\r"}var
|
|
75
|
+
`,{mode:384})}function ba(e){let t=Ei(e)&&Od(e).isDirectory()?e:Om(e);if(Vt(t),process.platform==="darwin"){let n=Ei(e)&&Od(e).isFile()?["-R",e]:[t];Ld("open",n,{detached:!0,stdio:"ignore"}).unref();return}if(process.platform==="win32"){Ld("explorer",[t],{detached:!0,stdio:"ignore"}).unref();return}Ld("xdg-open",[t],{detached:!0,stdio:"ignore"}).unref()}function b_(e=_s()){if(!Ei(e))return[];return Md(e).filter((t)=>t.startsWith(Gd)).sort().reverse()}function w_(e,t=_s()){let n=br(t,e);if(!Ei(n))return[];let r=[];for(let i of Md(n)){if(!i.endsWith(".log"))continue;let s=n_(br(n,i),"utf8");for(let a of s.split(`
|
|
76
|
+
`)){if(a.trim()==="")continue;let c=a.split(" ");r.push({timestamp:c[0]??"",service:c[1]??i.replace(/\.log$/,""),source:"history",level:c[2]??"INFO",message:c.slice(3).join(" "),pid:0,seq:0})}}let o=r.sort((i,s)=>i.timestamp.localeCompare(s.timestamp));return o.forEach((i,s)=>{i.seq=s+1}),o}function jm(e){let t=e.replace(/[^A-Za-z0-9._-]+/g,"_");return t===""?"service":t}function Bm(e,t,n){if(!Ei(e))return;let r=Md(e).filter((i)=>i.startsWith(Gd)).map((i)=>{let s=br(e,i),a=Od(s);return{path:s,mtime:a.mtimeMs}}).sort((i,s)=>s.mtime-i.mtime),o=t>0?Date.now()-t*86400000:0;r.forEach((i,s)=>{let a=o>0&&i.mtime<o,c=n>0&&s>=n;if(a||c)r_(i.path,{recursive:!0,force:!0})})}var $d="TRACE",Id="DEBUG",Fd="INFO",Nd="WARN",ma="ERROR",ha="FATAL",Hd="UNKNOWN",Lm,c_,l_,d_=200,u_=8,p_=2,v_=50000,Gd="session-",Im=500,Fm=5000;var wr=D(()=>{Xe();Lm={[$d]:0,[Id]:1,[Fd]:2,[Nd]:3,[ma]:4,[ha]:5,[Hd]:2};c_=/(?:x-devctl-request-id|request[_-]?id)[=: ]+([A-Za-z0-9-]+)/i,l_=[{re:/\b(fatal|critical)\b/i,level:ha},{re:/\b(error|err)\b/i,level:ma},{re:/\b(warn|warning)\b/i,level:Nd},{re:/\b(debug|dbg)\b/i,level:Id},{re:/\b(trace)\b/i,level:$d},{re:/\b(info|information)\b/i,level:Fd}]});class gn{nameMarkers;patterns;constructor(e,t){this.nameMarkers=[...yh,...e],this.patterns=t.flatMap((n)=>{try{return[new RegExp(n)]}catch{return[]}})}update(e,t){this.nameMarkers=[...yh,...e],this.patterns=t.flatMap((n)=>{try{return[new RegExp(n)]}catch{return[]}})}isSecretName(e){let t=e.toUpperCase();return this.nameMarkers.some((n)=>t.includes(n.toUpperCase()))}redactValue(e,t){if(t==="")return t;if(this.isSecretName(e))return"********";if(this.patterns.some((n)=>n.test(t)))return"********";return t}redactMap(e){let t={};for(let[n,r]of Object.entries(e))t[n]=this.redactValue(n,r);return t}redactText(e){if(e==="")return e;let t=e;for(let n of this.patterns)t=t.replace(n,"********");return X_(t)}}function X_(e){let t=e.toLowerCase(),n="authorization: bearer ",r=t.indexOf("authorization: bearer ");if(r>=0)return vh(e,r+22);let o=t.indexOf("bearer ");if(o<0)return e;return vh(e,o+7)}function vh(e,t){let n=t;while(n<e.length&&!Q_(e[n]??""))n+=1;return e.slice(0,t)+"********"+e.slice(n)}function Q_(e){return e===" "||e==="\t"||e===`
|
|
77
|
+
`||e==="\r"}var yh;var Li=D(()=>{yh=["PASSWORD","SECRET","TOKEN","PRIVATE_KEY","CLIENT_SECRET","API_KEY","CREDENTIAL","ACCESS_KEY","AUTH_KEY"]});var Ra;var xh=D(()=>{Ra={procedure:`---
|
|
78
78
|
name: devctl-onboard
|
|
79
79
|
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
80
|
---
|
|
@@ -180,7 +180,9 @@ Guidance that shapes a good first config:
|
|
|
180
180
|
- **Templates over repetition.** Two services sharing a language or runner
|
|
181
181
|
should \`extends\` a template that holds \`health\` cadence, \`logs\`, \`restart\`.
|
|
182
182
|
- **Dependencies are start-order, not networking.** Declare \`dependencies\` only
|
|
183
|
-
where one service genuinely cannot start usefully before another.
|
|
183
|
+
where one service genuinely cannot start usefully before another. Use the
|
|
184
|
+
object form with \`condition: service_healthy\` only when launch truly requires
|
|
185
|
+
a dependency's health check to pass; strings mean \`service_started\`.
|
|
184
186
|
- **Cross-service URLs use references**, not hard-coded ports:
|
|
185
187
|
\`API_URL: http://127.0.0.1:\${services.invoices-api.ports.http}\`. This keeps
|
|
186
188
|
working when a port changes or is \`auto\`.
|
|
@@ -380,7 +382,7 @@ the agent to set it up" a complete path. In that state \`get_status\` reports
|
|
|
380
382
|
arguments reports the missing configuration rather than a parse error. Draft,
|
|
381
383
|
validate the candidate text, write the files, then call \`reload_config\`: setup
|
|
382
384
|
mode clears on the reload that finds a valid configuration.
|
|
383
|
-
`,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`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`\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` |\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`, no `image`, no `build`, no `volumes`, no `replicas`,\nno `env_file` \u2014 those are compose/k8s spellings and will be rejected. Translate\nthem.\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 service needs a non-empty `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\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.\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
|
|
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
|
|
384
386
|
|
|
385
387
|
How to turn what a repository contains into the service list you draft from.
|
|
386
388
|
Read the signals in roughly this order \u2014 the earlier ones describe *how the
|
|
@@ -405,20 +407,22 @@ copy it:
|
|
|
405
407
|
| Compose | devctl |
|
|
406
408
|
|---|---|
|
|
407
409
|
| \`services.<name>\` | \`services.<name>\` (same key) |
|
|
408
|
-
| \`
|
|
410
|
+
| \`image\` | \`container.image\` |
|
|
411
|
+
| \`command\` / image entrypoint | \`command\` |
|
|
409
412
|
| \`ports: ["8000:8000"]\` | \`ports: { http: 8000 }\` (the **host** side) |
|
|
413
|
+
| container-side port | \`container.ports: { http: 8000 }\` |
|
|
410
414
|
| \`depends_on\` | \`dependencies\` |
|
|
411
415
|
| \`environment\` | \`environment\` vars / \`defaults\` |
|
|
412
416
|
| \`env_file\` | \`environment.sources: [dotenv]\` at the top level |
|
|
413
417
|
| \`healthcheck.test\` | \`health: { type: command, command: [...] }\`, or better, an \`http\` check if the container exposes one |
|
|
414
418
|
| \`working_dir\` / \`build.context\` | \`working_dir\` (relative to repo root) |
|
|
415
419
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
420
|
+
For a service with an image and no local host process, use devctl's native
|
|
421
|
+
\`container:\` service specification rather than spelling out \`docker run\` as a
|
|
422
|
+
command. Preserve the host/container port distinction, volumes, environment,
|
|
423
|
+
health check, and dependencies. Keep container-backed services out of the
|
|
424
|
+
default profile when doing so preserves a repository's existing no-Docker
|
|
425
|
+
onboarding path.
|
|
422
426
|
|
|
423
427
|
### Procfile
|
|
424
428
|
|
|
@@ -603,27 +607,49 @@ Rules for turning that into YAML:
|
|
|
603
607
|
a full one. Remember that a bare \`devctl start\` falls back to the first
|
|
604
608
|
configured profile, and the TUI's default is the first profile
|
|
605
609
|
alphabetically \u2014 so name them with that in mind.
|
|
606
|
-
`}});import{existsSync as g0,readFileSync as m0}from"fs";function Ar(e,t){return!(t??[]).includes(e)}function Nm(e){return ua.filter((t)=>Ar(t.name,e))}function pa(e){return ua.some((t)=>t.name===e)}function Hm(e){return new gn(e.secrets.extra_markers,e.secrets.extra_patterns)}function jm(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 y0(e,t){let r=e.config(),n=r.services[t];if(!n)throw Error(`unknown service ${t}`);let i=e.status().services[t],s=Hm(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})}}function Bm(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 Wm(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:h0}),s=Hm(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 v0(e){return Object.entries(e.profiles).sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>({name:t,services:r.services}))}function Gm(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}));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 Dd(e){if(!Array.isArray(e))return[];return e.filter((t)=>typeof t==="string")}async function Um(e,t,r){switch(t){case"list_services":return jm(e.status());case"get_service":if(typeof r.name!=="string"||r.name==="")throw Error("name is required");return y0(e,r.name);case"get_status":return Bm(e.status());case"get_logs":return Wm(e,r);case"list_profiles":return v0(e.config());case"get_config":return Gm(e.config());case"run_doctor":return e.doctor();case"start_services":return e.start({services:Dd(r.services),profile:typeof r.profile==="string"?r.profile:""});case"stop_services":return await e.stop(Dd(r.services)),{ok:!0};case"restart_services":return await e.restart(Dd(r.services),r.cascade===!0),{ok:!0};case"reload_config":return e.reload();case"get_setup_guide":return x0(r);case"validate_config":return b0(e,r);default:throw Error(`unknown tool ${t}`)}}function x0(e){let t=typeof e.section==="string"?e.section:"procedure",r=t in da?t:"procedure";return{section:r,text:da[r],sections:Object.keys(da)}}function b0(e,t){let r=e.config();if(typeof t.text==="string"){let o=jn(r.repoRoot,r.configPath,t.text);return{valid:o.length===0,issues:o,source:"candidate",config_path:r.configPath}}if(!g0(r.configPath))return{valid:!1,issues:[`no configuration at ${r.configPath}`],source:"disk",config_path:r.configPath,setup_mode:!0};let n=jn(r.repoRoot,r.configPath,m0(r.configPath,"utf8"));return{valid:n.length===0,issues:n,source:"disk",config_path:r.configPath}}function Km(e){return Md.includes(e)}async function qm(e,t){switch(t){case"devctl://status":return Bm(e.status());case"devctl://services":return jm(e.status());case"devctl://logs":return Wm(e,{});case"devctl://config":return Gm(e.config());case"devctl://doctor":return e.doctor();default:throw Error(`unknown resource ${t}`)}}var h0=200,Md,Od,ua;var yi=T(()=>{St();la();Fm();Md=["devctl://status","devctl://services","devctl://logs","devctl://config","devctl://doctor"],Od=["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:"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:"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 mn(e){if(!Number.isInteger(e))return $d;return Math.min(Zm,Math.max(D0,e))}function eh(e,t){if(t.length!==1||t<"0"||t>"9")return e;if(e.length>=M0)return t;return`${e}${t}`}function th(e){return e.slice(0,-1)}function rh(e,t){if(e==="")return mn(t);let r=Number(e);if(!Number.isInteger(r))return mn(t);return mn(r)}function io(e){let t=Number.parseInt(Wo(e).slice(0,A0),16),r=Number.isFinite(t)?t%Qm:0;return $d+r}function nh(e,t){return t===io(e)}async function oh(e,t){let r=Number.isInteger(t)&&(t??0)>0?t:io(e);for(let n=0;n<L0;n+=1){let o=r+n;if(o>Zm)break;if(await qn(o))return o}throw M(X,`no free MCP port starting at ${r}`)}var $d=18700,Qm=600,KD,A0=8,L0=600,Zm=65535,D0=1024,M0=5;var ga=T(()=>{_e();ii();Ye();KD=$d+Qm-1});import{existsSync as va,readFileSync as ma}from"fs";import{dirname as O0,isAbsolute as ih,join as ya,resolve as I0}from"path";function lr(){return process.platform==="darwin"?"cmd+c":"ctrl+shift+c"}function B0(){return{theme:"devctl",leader_timeout:xa,font_size:yn,keybinds:{...j0},scroll_speed:$0,scroll_acceleration:{enabled:!1},diff_style:"auto",cursor:{style:"block",blinking:!0},mouse:!0,attention:{enabled:!1,notifications:!0,sound:!0,volume:F0,sound_pack:"default",sounds:{}},log_timestamps:!0,log_metadata:!0,mcp_enabled:!1}}function ba(){return ya(Lt(),"tui.json")}function wi(e=""){for(let t of[N0,H0]){let r=process.env[t];if(!r||r==="")continue;let n=ih(r)?r:I0(e||process.cwd(),r);if(va(n))return n}return}function W0(e,t){if(!t||Object.keys(t).length===0)return e;return{...e,keybinds:{...e.keybinds,...t}}}function qt(e,t){let r=W0(B0(),t),n=wi(e);if(n)return Fd(r,ha(ma(n,"utf8")),n);let o=G0(e),i=o?Fd(r,ha(ma(o,"utf8")),o):r,s=ba();if(!va(s)||o===s)return i;return Fd(i,ha(ma(s,"utf8")),s)}function sh(e){let t=ba(),r={};if(va(t)){let o=ha(ma(t,"utf8"));if(hn(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 $t(t,`${JSON.stringify(n,null,2)}
|
|
607
|
-
`),t}function
|
|
610
|
+
`}});import{existsSync as Z_,readFileSync as e0}from"fs";function Bn(e,t){return!(t??[]).includes(e)}function bh(e){return Ta.filter((t)=>Bn(t.name,e))}function Aa(e){return Ta.some((t)=>t.name===e)}function La(e){return new gn(e.secrets.extra_markers,e.secrets.extra_patterns)}function wh(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 n0(e,t){let n=e.config(),r=n.services[t];if(!r)throw Error(`unknown service ${t}`);let i=e.status().services[t],s=La(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 Sh(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 kh(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:t0}),s=La(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 r0(e){return Object.entries(e.profiles).sort(([t],[n])=>t.localeCompare(n)).map(([t,n])=>({name:t,services:n.services}))}function Ch(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 o0(e){let t=La(e);return{entries:di(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 Ea(e){if(!Array.isArray(e))return[];return e.filter((t)=>typeof t==="string")}async function _h(e,t,n){switch(t){case"list_services":return wh(e.status());case"get_service":if(typeof n.name!=="string"||n.name==="")throw Error("name is required");return n0(e,n.name);case"get_status":return Sh(e.status());case"get_logs":return kh(e,n);case"list_profiles":return r0(e.config());case"get_config":return Ch(e.config());case"get_config_sources":return o0(e.config());case"run_doctor":return e.doctor();case"start_services":return e.start({services:Ea(n.services),profile:typeof n.profile==="string"?n.profile:""});case"stop_services":return await e.stop(Ea(n.services)),{ok:!0};case"restart_services":return await e.restart(Ea(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,Ea(n.command),n.print_env===!0),o=La(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 i0(n);case"validate_config":return s0(e,n);default:throw Error(`unknown tool ${t}`)}}function i0(e){let t=typeof e.section==="string"?e.section:"procedure",n=t in Ra?t:"procedure";return{section:n,text:Ra[n],sections:Object.keys(Ra)}}function s0(e,t){let n=e.config();if(typeof t.text==="string"){let o=Xr(n.repoRoot,n.configPath,t.text);return{valid:o.length===0,issues:o,source:"candidate",config_path:n.configPath}}if(!Z_(n.configPath))return{valid:!1,issues:[`no configuration at ${n.configPath}`],source:"disk",config_path:n.configPath,setup_mode:!0};let r=Xr(n.repoRoot,n.configPath,e0(n.configPath,"utf8"));return{valid:r.length===0,issues:r,source:"disk",config_path:n.configPath}}function Ph(e){return Yd.includes(e)}async function Rh(e,t){switch(t){case"devctl://status":return Sh(e.status());case"devctl://services":return wh(e.status());case"devctl://logs":return kh(e,{});case"devctl://config":return Ch(e.config());case"devctl://doctor":return e.doctor();default:throw Error(`unknown resource ${t}`)}}var t0=200,Yd,Xd,Ta;var Di=D(()=>{st();Li();xh();Yd=["devctl://status","devctl://services","devctl://logs","devctl://config","devctl://doctor"],Xd=["inspect","logs","diagnostics","control","setup"],Ta=[{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 Cr(e){if(!Number.isInteger(e))return Zd;return Math.min(Mh,Math.max(v0,e))}function $h(e,t){if(t.length!==1||t<"0"||t>"9")return e;if(e.length>=x0)return t;return`${e}${t}`}function Ih(e){return e.slice(0,-1)}function Fh(e,t){if(e==="")return Cr(t);let n=Number(e);if(!Number.isInteger(n))return Cr(t);return Cr(n)}function xo(e){let t=Number.parseInt(un(e).slice(0,h0),16),n=Number.isFinite(t)?t%Oh:0;return Zd+n}function Nh(e,t){return t===xo(e)}async function Hh(e,t){let n=Number.isInteger(t)&&(t??0)>0?t:xo(e);for(let r=0;r<y0;r+=1){let o=n+r;if(o>Mh)break;if(await oo(o))return o}throw T(X,`no free MCP port starting at ${n}`)}var Zd=18700,Oh=600,UO,h0=8,y0=600,Mh=65535,v0=1024,x0=5;var Oa=D(()=>{Pe();vi();Xe();UO=Zd+Oh-1});import{existsSync as Fa,readFileSync as Ma}from"fs";import{dirname as b0,isAbsolute as jh,join as Ia,resolve as w0}from"path";function mn(){return process.platform==="darwin"?"cmd+c":"ctrl+shift+c"}function R0(){return{theme:"devctl",leader_timeout:Na,font_size:Pr,keybinds:{...P0},scroll_speed:S0,scroll_acceleration:{enabled:!1},diff_style:"auto",cursor:{style:"block",blinking:!0},mouse:!0,attention:{enabled:!1,notifications:!0,sound:!0,volume:k0,sound_pack:"default",sounds:{}},log_timestamps:!0,log_metadata:!0,mcp_enabled:!1}}function Ha(){return Ia($t(),"tui.json")}function Ii(e=""){for(let t of[C0,_0]){let n=process.env[t];if(!n||n==="")continue;let r=jh(n)?n:w0(e||process.cwd(),n);if(Fa(r))return r}return}function E0(e,t){if(!t||Object.keys(t).length===0)return e;return{...e,keybinds:{...e.keybinds,...t}}}function zt(e,t){let n=E0(R0(),t),r=Ii(e);if(r)return eu(n,$a(Ma(r,"utf8")),r);let o=T0(e),i=o?eu(n,$a(Ma(o,"utf8")),o):n,s=Ha();if(!Fa(s)||o===s)return i;return eu(i,$a(Ma(s,"utf8")),s)}function Bh(e){let t=Ha(),n={};if(Fa(t)){let o=$a(Ma(t,"utf8"));if(_r(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 jt(t,`${JSON.stringify(r,null,2)}
|
|
611
|
+
`),t}function T0(e){let t=Ii(e);if(t)return t;let n=[e||process.cwd(),Ia(e||process.cwd(),".devctl"),$t()],r=["tui.json","tui.jsonc"];for(let o of n)for(let i of r){let s=Ia(o,i);if(Fa(s))return s}return}function eu(e,t,n){let r=_r(t)?t:{},o={...e.keybinds};if(_r(r.keybinds)){for(let[c,l]of Object.entries(r.keybinds))if(typeof l==="string")o[c]=l}let i={...e.cursor};if(_r(r.cursor)){if(L0(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(_r(r.scroll_acceleration)&&typeof r.scroll_acceleration.enabled==="boolean")s.enabled=r.scroll_acceleration.enabled;let a={...e.attention,sounds:{...e.attention.sounds}};if(_r(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(_r(r.attention.sounds)){for(let[c,l]of Object.entries(r.attention.sounds))if(typeof l==="string")a.sounds[c]=A0(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 A0(e,t){if(e.startsWith("file://")||jh(e))return e;return Ia(b0(t),e)}function L0(e){return e==="block"||e==="underline"||e==="line"||e==="default"}function _r(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function $a(e){let t=e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/^\s*\/\/.*$/gm,"");return JSON.parse(t)}function D0(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 hn(e,t){return D0(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 Na=2000,Pr=14,S0=3,k0=0.4,C0="DEVCTL_TUI_CONFIG",_0="OPENCODE_TUI_CONFIG",P0;var Yt=D(()=>{Xe();P0={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:mn()}});function bo(e){return`http://127.0.0.1:${e}/mcp`}function ou(e){if(e==="")return{};return{Authorization:`Bearer ${e}`}}function iu(e,t){return JSON.stringify({mcpServers:{devctl:{type:"http",url:e,headers:ou(t)}}},null,2)}function su(e,t){return JSON.stringify({mcpServers:{devctl:{url:e,headers:ou(t)}}},null,2)}function au(e,t){return JSON.stringify({mcp:{devctl:{type:"remote",url:e,headers:ou(t),enabled:!0}}},null,2)}function cu(e,t){let n=t===""?"":`
|
|
608
612
|
http_headers = { Authorization = "Bearer ${t}" }`;return`[mcp_servers.devctl]
|
|
609
|
-
url = "${e}"${
|
|
610
|
-
`}function
|
|
611
|
-
`)}function co(){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:"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; add refresh to probe accounts",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:"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 gh(e){let t=e.trim().toLowerCase().replace(/^\//,"");return co().filter((r)=>t===""||g_(r,t))}function g_(e,t){if(e.name.startsWith(t)||e.name.includes(t)||e.desc.toLowerCase().includes(t))return!0;return e.aliases.some((r)=>r.startsWith(t)||r===t)}function ki(e){let t=e.trim().toLowerCase().replace(/^\//,"").split(" ")[0]??"";return co().find((r)=>r.name===t||r.aliases.includes(t))}function mh(e){return e.trim().replace(/^\//,"").split(/\s+/).slice(1).filter((r)=>r!=="")}function hh(e){return co().find((r)=>r.leader===e)?.name??""}function wa(e){let t=e.toLowerCase().trim(),r=m_[t];if(r)return r;return ht.includes(t)?t:"devctl"}function h_(){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 yh(e){let t=wa(e);if(t==="system"){if(h_())return{...qd["solarized-light"],name:"system"};return qd.system}return qd[t]}function Tt(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 vn(e,t){return _i(e)>=Ci?Sa:t}function _i(e){let t=e.startsWith("#")?e.slice(1):e,r=Number.parseInt(t,__);if(Number.isNaN(r))return 0;let n=r>>R_&Vd,o=r>>P_&Vd,i=r&Vd;return(n*w_+o*S_+i*k_)/C_}function E_(e){let t=x_;for(let r=0;r<e.length;r+=1)t^=e.charCodeAt(r),t=Math.imul(t,b_);return t>>>0}function ka(e){return _i(e.background)>=Ci}function Yd(e){if(!e||!/^#[0-9a-f]{6}$/i.test(e))return!1;return _i(e)<Ci}function Ca(e,t){let r=T_[e];return ka(t)?r.light:r.dark}function vh(e,t){return _i(Ca(e,t))>=Ci?A_:L_}function He(e,t){if(e===""||e==="all")return t.muted;let r=_i(t.background)>=Ci?v_:y_;return r[E_(e)%r.length]??t.info}function D_(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 xh(e,t,r){if(r==="string")return e.accent;if(r==="number")return e.info;if(r==="keyword")return e.error;return D_(e,t)}function Re(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 ht,Jd,qd,m_,y_,v_,x_=2166136261,b_=16777619,w_=299,S_=587,k_=114,C_=1000,Ci=160,__=16,Vd=255,R_=16,P_=8,Sa="#1A1A1A",T_,A_="#1A1A1A",L_="#F5F5F5";var ze=T(()=>{ht=["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"],Jd={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)"},qd={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"}},m_={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"};y_=["#7AA2F7","#9ECE6A","#E0AF68","#BB9AF7","#2AC3DE","#FF9E64","#F7768E","#73DACA","#C0CAF5","#FF79C6","#7DCFFF","#C3E88D"],v_=["#2E5AAC","#3D7A1F","#9A6B12","#6B3FA0","#0E7A86","#B85C1A","#B4234A","#1A7A6D","#4A5080","#9A3480","#1565C0","#4A7C19"];T_={claude:{dark:"#E08A6A",light:"#B54328"},cursor:{dark:"#B8D4FF",light:"#1E4EBF"},kilo:{dark:"#F0C94A",light:"#8A6400"},codex:{dark:"#4ADE80",light:"#0B7A4B"}}});function Sh(){return wi()!==void 0}function bh(e){let t=e/1000;if(Number.isInteger(t))return`${t}s`;return`${e}ms`}function Qd(e,t,r){let n=e.indexOf(t),i=((n<0?0:n)+r+e.length)%e.length;return e[i]??e[0]}function kh(e,t){let r=[...ht],n=r.includes(e)?e:Xd;return Qd(r,n,t)}function Ch(e,t){let r=[...M_],n=r.reduce((o,i)=>Math.abs(i-e)<Math.abs(o-e)?i:o,r[0]);return Qd(r,n,t)}function Ri(e){let t=[...zd];return t.reduce((r,n)=>Math.abs(n-e)<Math.abs(r-e)?n:r,t[0])}function Ra(e,t){return Qd([...zd],Ri(e),t)}function Pi(e){let t=Ri(e),r=wh[t]??wh[yn];return{px:t,...r}}function ur(e){return e.label==="compact"}function Ei(e){return e.steps<=2}function _h(e){return zd.map((r,n)=>n<e?"\u2588":"\u2591").join(" ")}function _a(e){return Pi(e).label}function Rh(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:_a(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:bh(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:at,hint:"read-only",detail:Pt()},{id:"reset",group:"About",kind:"action",name:"Reset",value:"defaults",hint:"enter confirm reset",detail:`Restore theme ${Xd}, display ${_a(yn)}, mouse on, leader ${bh(xa)}. Enter asks first. ${t}`}]}function Zd(){return{theme:Xd,mouse:!0,leader_timeout:xa,font_size:yn}}function Ph(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 eu(e,t){if(e.length===0)return 0;return Math.min(Math.max(t,0),e.length-1)}function lo(e,t){return e[eu(e,t)]}function tu(){return wi()??ba()}var M_,zd,Xd="devctl",wh;var pr=T(()=>{ze();Vt();M_=[1000,2000,3000],zd=[12,14,16,18,20,22];wh={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 O_,useContext as I_}from"react";function re(){return I_(ru)}var ru;var ot=T(()=>{pr();Vt();ru=O_(Pi(yn))});function $h(e,t=!0){let r=e<Ia?Eh+1:Eh,n=t?z_:0;return r+n+V_+n+J_+n+Y_+n}function Lr(e){return e.length+X_}function Fh(e,t){if(t<Z_)return ce(e,3);if(t<Q_)return ce(e,4);return e}function Nh(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=nu(e,o,r);if(i.start===0&&i.end===n-1)return i;let s=o>0?Pa:0,a=o<n-1?Pa:0,c=s+a,l=nu(e,o,Math.max(e[o]??0,r-c)),d=(s>0&&l.start===0?Pa:0)+(a>0&&l.end===n-1?Pa:0);if(d===0)return l;return nu(e,o,Math.max(e[o]??0,r-c+d))}function nu(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 g=t-(o-1),f=i+1-t;if(l&&(!d||g<=f))o-=1,s+=a;else if(d)i+=1,s+=c;else break}return{start:o,end:i}}function Hh(e){if(e==="detail")return Dr.findIndex((t)=>t.id==="services");return Dr.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 uu(e){return e>=N_}function pu(e){return e>=H_}function fu(e){return e>=j_}function Fa(e,t=0){return Math.max(1,e-Ih-t*2)}function jh(e){let t=Mh+Jt+yt;if(uu(e))t+=fr;if(pu(e))t+=La;if(fu(e))t+=Mr;return Math.max(du,e-t)}function Uh(e,t,r){let n=r?Ah:eR+Ah+Math.max(0,t)*2;return Math.max(1,e-n)}function oR(e){if(e.startsWith('"')||e.startsWith("'"))return"string";if(/^\d+$/.test(e))return"number";return"keyword"}function ja(e,t){let r=Math.max(1,t),n=e.replace(/\r\n/g,`
|
|
613
|
+
url = "${e}"${n}
|
|
614
|
+
`}function Z0(e){return`codex mcp add --url ${e}`}function Fi(e,t){return[{kind:"claude",title:"Claude",path:".mcp.json",language:"json",text:iu(e,t),hint:"claude mcp add-json"},{kind:"cursor",title:"Cursor",path:".cursor/mcp.json",language:"json",text:su(e,t)},{kind:"kilo",title:"Kilo Code",path:"kilo.jsonc",language:"json",text:au(e,t)},{kind:"codex",title:"Codex",path:"~/.codex/config.toml",language:"toml",text:cu(e,t),hint:Z0(e)}]}function qh(e,t){let n=[`URL ${e}`,""];for(let r of Fi(e,t))n.push(`# ${r.title} ${r.path}${r.hint?` (${r.hint})`:""}`),n.push(r.text.trimEnd()),n.push("");return n.join(`
|
|
615
|
+
`)}function wo(){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:"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; add refresh to probe accounts",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:"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 Vh(e){let t=e.trim().toLowerCase().replace(/^\//,"");return wo().filter((n)=>t===""||eP(n,t))}function eP(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 Ni(e){let t=e.trim().toLowerCase().replace(/^\//,"").split(" ")[0]??"";return wo().find((n)=>n.name===t||n.aliases.includes(t))}function Jh(e){return e.trim().replace(/^\//,"").split(/\s+/).slice(1).filter((n)=>n!=="")}function zh(e){return wo().find((n)=>n.leader===e)?.name??""}function Wa(e){let t=e.toLowerCase().trim(),n=tP[t];if(n)return n;return vt.includes(t)?t:"devctl"}function nP(){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 Yh(e){let t=Wa(e);if(t==="system"){if(nP())return{...lu["solarized-light"],name:"system"};return lu.system}return lu[t]}function Ot(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 Er(e,t){return ji(e)>=Hi?Ga:t}function ji(e){let t=e.startsWith("#")?e.slice(1):e,n=Number.parseInt(t,uP);if(Number.isNaN(n))return 0;let r=n>>pP&du,o=n>>fP&du,i=n&du;return(r*aP+o*cP+i*lP)/dP}function gP(e){let t=iP;for(let n=0;n<e.length;n+=1)t^=e.charCodeAt(n),t=Math.imul(t,sP);return t>>>0}function Ua(e){return ji(e.background)>=Hi}function pu(e){if(!e||!/^#[0-9a-f]{6}$/i.test(e))return!1;return ji(e)<Hi}function Ka(e,t){let n=mP[e];return Ua(t)?n.light:n.dark}function Xh(e,t){return ji(Ka(e,t))>=Hi?hP:yP}function je(e,t){if(e===""||e==="all")return t.muted;let n=ji(t.background)>=Hi?oP:rP;return n[gP(e)%n.length]??t.info}function vP(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 Qh(e,t,n){if(n==="string")return e.accent;if(n==="number")return e.info;if(n==="keyword")return e.error;return vP(e,t)}function Te(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 vt,uu,lu,tP,rP,oP,iP=2166136261,sP=16777619,aP=299,cP=587,lP=114,dP=1000,Hi=160,uP=16,du=255,pP=16,fP=8,Ga="#1A1A1A",mP,hP="#1A1A1A",yP="#F5F5F5";var Qe=D(()=>{vt=["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"],uu={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)"},lu={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"}},tP={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"};rP=["#7AA2F7","#9ECE6A","#E0AF68","#BB9AF7","#2AC3DE","#FF9E64","#F7768E","#73DACA","#C0CAF5","#FF79C6","#7DCFFF","#C3E88D"],oP=["#2E5AAC","#3D7A1F","#9A6B12","#6B3FA0","#0E7A86","#B85C1A","#B4234A","#1A7A6D","#4A5080","#9A3480","#1565C0","#4A7C19"];mP={claude:{dark:"#E08A6A",light:"#B54328"},cursor:{dark:"#B8D4FF",light:"#1E4EBF"},kilo:{dark:"#F0C94A",light:"#8A6400"},codex:{dark:"#4ADE80",light:"#0B7A4B"}}});function ty(){return Ii()!==void 0}function Zh(e){let t=e/1000;if(Number.isInteger(t))return`${t}s`;return`${e}ms`}function mu(e,t,n){let r=e.indexOf(t),i=((r<0?0:r)+n+e.length)%e.length;return e[i]??e[0]}function ny(e,t){let n=[...vt],r=n.includes(e)?e:gu;return mu(n,r,t)}function ry(e,t){let n=[...xP],r=n.reduce((o,i)=>Math.abs(i-e)<Math.abs(o-e)?i:o,n[0]);return mu(n,r,t)}function Bi(e){let t=[...fu];return t.reduce((n,r)=>Math.abs(r-e)<Math.abs(n-e)?r:n,t[0])}function Va(e,t){return mu([...fu],Bi(e),t)}function Wi(e){let t=Bi(e),n=ey[t]??ey[Pr];return{px:t,...n}}function yn(e){return e.label==="compact"}function Gi(e){return e.steps<=2}function oy(e){return fu.map((n,r)=>r<e?"\u2588":"\u2591").join(" ")}function qa(e){return Wi(e).label}function iy(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:qa(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:Zh(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:ut,hint:"read-only",detail:Lt()},{id:"reset",group:"About",kind:"action",name:"Reset",value:"defaults",hint:"enter confirm reset",detail:`Restore theme ${gu}, display ${qa(Pr)}, mouse on, leader ${Zh(Na)}. Enter asks first. ${t}`}]}function hu(){return{theme:gu,mouse:!0,leader_timeout:Na,font_size:Pr}}function sy(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 yu(e,t){if(e.length===0)return 0;return Math.min(Math.max(t,0),e.length-1)}function So(e,t){return e[yu(e,t)]}function vu(){return Ii()??Ha()}var xP,fu,gu="devctl",ey;var vn=D(()=>{Qe();Yt();xP=[1000,2000,3000],fu=[12,14,16,18,20,22];ey={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 bP,useContext as wP}from"react";function ne(){return wP(xu)}var xu;var at=D(()=>{vn();Yt();xu=bP(Wi(Pr))});function my(e,t=!0){let n=e<nc?ay+1:ay,r=t?IP:0;return n+r+OP+r+MP+r+$P+r}function Wn(e){return e.length+FP}function hy(e,t){if(t<HP)return le(e,3);if(t<NP)return le(e,4);return e}function yy(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=bu(e,o,n);if(i.start===0&&i.end===r-1)return i;let s=o>0?Ja:0,a=o<r-1?Ja:0,c=s+a,l=bu(e,o,Math.max(e[o]??0,n-c)),d=(s>0&&l.start===0?Ja:0)+(a>0&&l.end===r-1?Ja:0);if(d===0)return l;return bu(e,o,Math.max(e[o]??0,n-c+d))}function bu(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),m=i+1-t;if(l&&(!d||f<=m))o-=1,s+=a;else if(d)i+=1,s+=c;else break}return{start:o,end:i}}function vy(e){if(e==="detail")return Gn.findIndex((t)=>t.id==="services");return Gn.findIndex((t)=>t.id===e)}function le(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 Eu(e){return e>=CP}function Tu(e){return e>=_P}function Au(e){return e>=PP}function oc(e,t=0){return Math.max(1,e-gy-t*2)}function xy(e){let t=py+Xt+xt;if(Eu(e))t+=xn;if(Tu(e))t+=Qa;if(Au(e))t+=Un;return Math.max(Ru,e-t)}function ky(e,t,n){let r=n?ly:jP+ly+Math.max(0,t)*2;return Math.max(1,e-r)}function UP(e){if(e.startsWith('"')||e.startsWith("'"))return"string";if(/^\d+$/.test(e))return"number";return"keyword"}function ac(e,t){let n=Math.max(1,t),r=e.replace(/\r\n/g,`
|
|
612
616
|
`).replace(/\r/g,`
|
|
613
617
|
`).split(`
|
|
614
|
-
`),o=[];for(let i of n)if(i.length<=r)o.push(i);else o.push(...iR(i,r));return o.length>0?o:[""]}function Kh(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=` ${tR}${o}`,s=Math.max(1,t-i.length);return{visible:[ce(n[0]??"",s)],mark:i,folded:!0,hidden:o}}function qh(e,t){return e==="all"||e==="focus"&&t}function gu(e){if(e==="clip")return"focus";if(e==="focus")return"all";return"clip"}function Vh(e,t,r,n=bn){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 mu(e,t=bn){return Math.max(0,e-t)}function hu(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 Ai(e){if(e==="all")return"wrap all";if(e==="focus")return"wrap selected";return"clip"}function iR(e,t){let r=[],n=e;while(n.length>t){let o=n.slice(0,t),i=sR(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 sR(e){let t=e.lastIndexOf(" "),r=e.lastIndexOf("\t"),n=e.lastIndexOf(","),o=Math.max(t,r,n);if(o<Math.floor(e.length*rR))return-1;return e[o]===","?o+1:o}function Jh(e){let t=[],r=new RegExp(nR.source,"gi"),n=0,o=r.exec(e);while(o){let i=o[0]??"";if(o.index>n)t.push({text:e.slice(n,o.index),kind:"text"});t.push({text:i,kind:oR(i)}),n=o.index+i.length,o=r.exec(e)}if(n<e.length)t.push({text:e.slice(n),kind:"text"});if(t.length===0)return[{text:e,kind:"text"}];return t}function Yh(e){let t=e.showTimestamps?Na:0,r=e.showMeta?$a:0;return Math.max(Bh,e.width-t-e.serviceWidth-Ha-r-Wh-Ti*Gh)}function Li(e){return Math.max(U_,e-K_*2)}function zh(e){let t=e.width<W_,r=e.proxyOn?`\u25CF ${ce(e.proxyAddress,t?10:18)}`:t?"":"\u25CB off";return[{label:t?`${e.running}/${e.total}`:vu(e.running,e.total),tone:e.running>0?"success":"idle"},{label:r,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 Xh(e,t){let r=t.reduce((s,a)=>Math.max(s,a.length),0),n=Na+Ha+Wh+Bh+Ti*Gh,o=Math.max(Th,e-n),i=Math.max(Th,r);return Math.min(Oh,o,i)}function Ba(e,t,r){if(r)return e;let n=t.reduce((a,c)=>Math.max(a,c.length),0),o=Math.min(Oh,Math.max(du,n+$_)),i=Mh+Jt+yt+o+Ih+F_,s=Math.max(Ta,Math.floor(e*B_));return Math.min(s,Math.max(Ta,i))}function Y(e,t){if(t<=0)return"";if(e.length>=t)return ce(e,t);return e.padEnd(t)}function po(e,t){let r=[],n=0;for(let o of e){let i=o.key.length+o.label.length+3;if(n+i>t)break;r.push(o),n+=i}return r}function Qh(e){return e<q_}function fo(e,t,r,n,o="center",i=!0){let s=Math.min(r,Math.max(1,e-4)),a=Math.min($h(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),g=Math.max(0,Math.min(d,t-c));return{left:l,top:g,width:s,height:c}}function Zh(e){if(e==="")return"idle";if(cR.test(e))return"error";if(e.includes("session only"))return"warning";if(aR.test(e))return"success";return"info"}function ey(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 ty(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 G_;return 0}function ry(e){if(e==="0")return Dr[9]?.id;if(e.length===1&&e>="1"&&e<="9")return Dr[Number(e)-1]?.id;return}function Wa(e){if(!e)return"";return Object.keys(e.profiles).sort()[0]??""}function Ga(e){return lR.has(e)}function Di(e){if(!e)return!1;return Ga(e.state)}function Ua(e,t){let r=t??Object.keys(e?.services??{});return{running:r.filter((o)=>Di(e?.services[o])).length,total:r.length}}function ny(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(Ga(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 oy(e,t){if(!Number.isFinite(e)||!Number.isFinite(t)||t<=0)return 0;return e/t}function mR(e,t,r){if(!Number.isFinite(e))return"success";if(e>r)return"error";if(e>t)return"warning";return"success"}function hR(e,t){return mR(oy(e,t),dR,uR)}function yR(e,t){let r=t>0?e/t:1;if(r<fR)return"error";if(r<pR)return"warning";return"success"}function ou(e){if(!Number.isFinite(e)||e<0)return"\u2014";return e.toFixed(2)}function vR(e){if(!Number.isFinite(e)||e<0)return"\u2014";return`${Math.round(e*100)}%`}function iy(e,t=Date.now()){if(!e?.startTime)return"\u2014";let r=new Date(e.startTime).getTime();if(!Number.isFinite(r))return"\u2014";return mo(t-r)}function sy(e,t=gR){return Object.entries(e).sort((r,n)=>n[1]-r[1]||r[0].localeCompare(n[0])).slice(0,t)}function ay(e,t=1){return Math.max(24,e-_R-t*2-RR-PR-ER)}function cy(e){let t=e>=xR,r=e>=bR,n=e>=wR,o=e>=SR,i=e>=kR,s=e>=CR,a=Jt+yt;if(t)a+=fr+yt;if(r)a+=Ma+yt;if(n)a+=Oa+yt;if(o)a+=Da+yt;if(i)a+=Ka+yt;if(s)a+=Mr;return{name:Math.max(du,e-a),health:t,cpu:r,mem:n,up:o,rst:i,pid:s}}function ly(e){let t=Number.isFinite(e)&&e>0?e:0;return{ratio:Math.min(1,t),label:vR(t)}}function dy(e,t=LR){return`[${Mi(e.ratio,t)}] ${e.label.padStart(4)}`}function yu(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)?DR:0,i=go*(o>0?3:2),s=Math.min(TR,Math.max(iu,r)),a=Math.min(AR,Math.max(su,n)),c=t-s-a-o-i;if(c<Ea&&a>su)a=Math.max(su,a-(Ea-c)),c=t-s-a-o-i;if(c<Ea&&s>iu)s=Math.max(iu,s-(Ea-c)),c=t-s-a-o-i;return{what:s,reading:a,meaning:Math.max(0,c),meter:o}}function uy(e){return MR.has((e?.health.type??"").toLowerCase())}function py(e){if(e==="darwin")return"macOS";if(e==="win32")return"Windows";if(e==="linux")return"Linux";return e||"this computer"}function fy(e,t){let r=Math.max(1,t),n=hR(e,r),o=n==="error"?"overloaded":n==="warning"?"busy":"not busy",i=n==="error"?`${r} cores are queued up \u2014 last minute ${ou(e)}`:n==="warning"?`${r} cores nearly full \u2014 last minute ${ou(e)}`:`${r} cores. Last minute ${ou(e)} (under ${r} is fine)`;return{what:"CPU work",reading:o,meaning:i,tone:n,meter:ly(oy(e,r))}}function gy(e,t){let r=yR(e,t),n=`${Aa(e)} of ${Aa(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:ly(i)}}function my(e){let t=e?.state??"STOPPED";if(t==="FAILED")return"crashed";if(t==="STOPPING")return"stopping";if(t==="STARTING"||t==="RESTARTING")return"starting";if(Ga(t))return"up";return"off"}function hy(e){if(!e||!Ga(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 yy(e){if(e==="keychain")return"password store";if(e==="file")return"local file";return e||"unknown store"}function vy(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}function Mi(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 mo(e){if(!Number.isFinite(e)||e<au)return"< 1s";let t=Math.floor(e/Lh),r=Math.floor(e%Lh/lu),n=Math.floor(e%lu/cu),o=Math.floor(e%cu/au);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 Aa(e){if(!Number.isFinite(e)||e<0)return"\u2014";let t=e/OR;if(t>=Dh)return`${(t/Dh).toFixed(1)}G`;if(t>=1)return`${Math.round(t)}M`;return`${Math.round(e)}K`}function xy(e){if(!Number.isFinite(e)||e<0)return"\u2014";return`${e.toFixed(1)}%`}function ho(e){if(!e)return!0;let t=Object.values(e.services);if(t.length===0)return!0;return!t.some((r)=>Di(r))}function by(e,t){if(e.length>0)return e;return[...t]}function qa(e,t){if(e.length>0)return[...e];return t===""?[]:[t]}function Oi(e){return IR.has(e)}function Sy(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 ky(e,t){let r=t.length>0?t[t.length-1].seq:-1,n=e.filter((o)=>o.seq>r);return[...t,...n]}function Cy(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 _y(e,t,r){return e&&t<=0&&r}function Ry(e){return e.filter((t)=>t.level==="ERROR"||t.level==="FATAL").length}function $R(e){return`${e.timestamp} ${e.service} ${e.level} ${e.message}`}function Py(e){return[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(`
|
|
615
|
-
`)}function
|
|
616
|
-
`)}function yo(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=ea(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 FR(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 Ty(e,t,r=[]){let n=Ii(e,t,r);return[{name:"",count:t.length},...FR(t,n)]}function NR(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 Ay(e,t,r=[]){let n=Object.keys(t.byService).map((i)=>({service:i})),o=Ii(e,n,r);return[{name:"",count:t.total},...NR(o,t.byService)]}function vu(e,t){if(e<=0)return"none started";return`${e}/${t} running`}function Ii(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 Ly(e,t,r){let n=["",...Ii(e,t)];if(r<1||r>n.length)return;return n[r-1]}function xu(e,t,r){let n=["",...e],o=n.indexOf(t),s=((o<0?0:o)+r+n.length)%n.length;return n[s]??""}function $i(e){return e.waves.flat().join(" \u2192 ")}function Dy(e){let t=$i(e);if(t==="")return"Started selected services";return`Started ${t}`}function My(e){let t=$i(e);if(t==="")return"Stopped running services";return`Stopped ${t}`}function Oy(e,t,r,n="start"){let o=r?.services[e],i=Ot(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)=>Ot(r?.services[c])!=="HEALTHY");if(a.length>0)return`waits for ${a.join(", ")}`;return"queued"}function Fi(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 Iy(e,t,r="start"){let o=e.waves.flat().length,i=0,s=0,a=0,c=0;for(let y=0;y<e.waves.length;y++){let b=e.waves[y]??[],w=Fi(b,t,r);if(w==="active"||w==="unhealthy"||w==="failed")c=y;else if(w==="completed"&&c===y&&y<e.waves.length-1)c=y+1;for(let R of b){let S=t?.services[R];if(r==="stop"?!S||S.state==="STOPPED"||S.state==="UNKNOWN":Boolean(S&&(S.state==="HEALTHY"||S.health==="HEALTHY"||S.state==="RUNNING"&&S.health!=="UNHEALTHY")))i++;else if(S?.state==="FAILED")s++;else if(S?.state==="STARTING"||S?.state==="RUNNING"||S?.state==="UNHEALTHY"||S?.health==="UNHEALTHY"||S?.state==="STOPPING"||S?.state==="RESTARTING")a++}}let l=o>0?Math.round(i/o*100):100,d=16,g=Math.round(l/100*d),f="\u2588".repeat(g)+"\u2591".repeat(Math.max(0,d-g)),h=i===o&&o>0;return{total:o,ready:i,active:a,failed:s,percent:l,progressBar:f,currentWaveIndex:c,totalWaves:e.waves.length,isComplete:h}}function $y(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 Fy(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 Ny(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 Hy(e){let t=xn.indexOf(e);if(t<0)return"dashboard";return xn[(t+1)%xn.length]??"dashboard"}function jy(e){let t=xn.indexOf(e);if(t<0)return"dashboard";return xn[(t-1+xn.length)%xn.length]??"dashboard"}function By(e){return["services","nav","logs","ui","app"].flatMap((r)=>{let n=e.filter((o)=>o.group===r);if(n.length===0)return[];return[{group:r,items:n}]})}function Wy(e){let t=e.trim().toLowerCase().replace(/^\//,""),r=co().filter((n)=>t===""||n.name.includes(t)||n.desc.toLowerCase().includes(t)||n.aliases.some((o)=>o.startsWith(t)));return By(r).flatMap((n)=>n.items)}function Gy(e){return By(e).flatMap((t)=>t.items.map((r)=>({name:`/${r.name}`,description:`${t.group} \xB7 ${r.desc}`,value:r.name})))}function Uy(e,t,r=lr()){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")return[{key:"j/k",label:"scroll"},{key:r,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 bu();if(t==="config-edit")return[{key:"ctrl+s",label:"save"},{key:"esc",label:"discard"}];return HR(e,r)}function bu(){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 HR(e,t){let r=[{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"},...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:"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"},...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:"v",label:"buffer"},{key:"e",label:"editor"},{key:"/reload",label:"reload"},{key:"j/k",label:"scroll"},...r];case"setup":return[{key:"j/k",label:"steps"},{key:"enter",label:"continue"},{key:"esc",label:"back or exit"},...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 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 Ky(e,t,r){if(r<=t||e<t)return 0;return Math.min(e-t+1,r-t)}function wn(e,t){if(e.length===0)return;let r=Math.min(Math.max(t,0),e.length-1);return e[r]}function Va(e){return e.command.args.join(" ")||"\u2014"}function Ni(e,t){let r=Sn(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 Ja(e){let t=e.health.type||"none",r=e.health.url||e.health.address;return r===""?t:`${t} ${r}`}function Ya(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 za(e){let t=e.restart.policy||"none";if(e.restart.max_retries>0)return`${t} \xD7${e.restart.max_retries}`;return t}function qy(e,t,r,n){let o={...e.environment.defaults,...e.environment.vars},i=KR(o,t,r,n);return[...new Set([...Object.keys(i),...e.environment.required])].sort().map((a)=>({key:a,value:i[a]??"",required:e.environment.required.includes(a)}))}function Vy(e){let t=Math.max(UR,e-GR);return Math.min(BR,Math.max(jR,Math.floor(t*WR)))}function Sn(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 Ot(e){if(!e)return"STOPPED";return Zn(e)}function Jy(e,t,r){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 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 KR(e,t,r,n){if(t)return e;return new gn(r,n).redactMap(e)}function Yy(e,t){if(!e)return"";return(e.profiles[t]?.services??[]).join(", ")}function vo(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}}function zy(e,t,r,n){let o=Math.max(8,n-2),i=`logs ${r}`,s=Lr(i),a=e||"(no user)",c=t||"";if(o<=s+6){let f=Math.max(2,o-s-2);return[{label:ce(a,f),tone:"idle"},{label:ce(i,s-2),tone:"muted"}]}let l=o-s;if(c&&l>=36){let f=ce(c,14),h=Lr(f),y=l-h-2,b=y>=a.length+9?`identity ${a}`:a;return[{label:ce(b,y),tone:"idle"},{label:f,tone:"muted"},{label:i,tone:"muted"}]}if(c&&l>=28&&c.length<=10){let f=ce(c,10),h=Lr(f),y=l-h-2;return[{label:ce(a,y),tone:"idle"},{label:f,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 Xy(e){let t=e.payload?.error;return typeof t==="string"&&t!==""?t:"configuration reload failed"}var uo=100,Mh=8,Jt=12,fr=10,La=8,Mr=8,Da=9,Ma=7,Oa=8,du=12,Oh=40,yt=2,$_=2,Ih=2,F_=2,Ta=34,N_=48,H_=60,j_=72,B_=0.48,Ia=90,W_=60,G_=9,$a=8,U_=8,K_=6,q_=20,Eh=1,V_=1,J_=1,Y_=1,z_=1,BM,X_=2,Pa=2,Q_=80,Z_=56,Na=9,Ha=7,Th=10,Bh=16,Wh=2,Ti=1,bn=200,eR=2,Ah=1,tR="\u25B8",Gh=2,rR=0.4,nR,aR,cR,Dr,xn,lR,dR=0.85,uR=1.5,pR=0.2,fR=0.1,gR=5,xR=52,bR=64,wR=72,SR=82,kR=90,CR=100,_R=2,RR=2,PR=2,ER=1,Ka=8,iu=8,TR=22,su=6,AR=28,Ea=12,go=2,LR=10,DR=18,MR,au=1000,cu,lu,Lh,OR=1024,Dh=1024,IR,wy,jR=10,BR=28,WR=0.42,GR=2,UR=20;var Pe=T(()=>{fn();la();dn();Vt();BM=$h(Ia-1);nR=/("[^"]*"|'[^']*'|\b(?:ERROR|FATAL|WARN(?:ING)?|FAIL(?:ED)?)\b|\b\d{3,5}\b)/gi;aR=/^(started|stopped|restarted|refreshed|cleared|copied|exported|jumped|proxy started|proxy stopped|secrets|re-running|theme |mouse |leader |display |restored)/i,cR=/\b(fail|error|unknown|not found|no configuration|blocked|already in use|is using port)\b/i;Dr=[{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"}];xn=Dr.map((e)=>e.id);lR=new Set(["RUNNING","STARTING","RESTARTING","HEALTHY","UNHEALTHY"]);MR=new Set(["http","tcp","command"]);cu=60*au,lu=60*cu,Lh=24*lu;IR=new Set(["auth","devctl","proxy"]),wy=["devctl","mcp","auth"]});import{useEffect as qR,useRef as VR}from"react";import{jsxDEV as ne,Fragment as YR}from"@opentui/react/jsx-dev-runtime";function JR(e,t){switch(t){case"primary":return{bg:e.primary,fg:vn(e.primary,e.inverse)};case"accent":return{bg:e.accent,fg:ka(e)?Sa:vn(e.accent,e.inverse)};case"success":return{bg:e.success,fg:vn(e.success,e.inverse)};case"warning":return{bg:e.warning,fg:ka(e)?Sa:vn(e.warning,e.inverse)};case"error":return{bg:e.error,fg:vn(e.error,e.inverse)};case"info":return{bg:e.info,fg:vn(e.info,e.inverse)};case"muted":return{bg:e.element,fg:e.text};default:return{bg:e.element,fg:e.text}}}function Qy(e){let{palette:t,dir:r}=e;return ne("box",{width:2,height:1,flexShrink:0,overflow:"hidden",children:ne("text",{fg:t.muted,children:r==="left"?"\u2039":"\u203A"},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function je(e){let{palette:t,children:r,backgroundColor:n,edge:o="bottom"}=e,i=re(),s=e.ruled??!ur(i),a=n??t.element,c=ne("box",{flexShrink:0,flexDirection:"column",backgroundColor:a,overflow:"hidden",children:r},void 0,!1,void 0,this);if(!s)return c;return ne("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 Xa(e){let{palette:t,items:r,active:n,width:o,onPick:i}=e,s=r.map((d)=>Lr(d.label)),a=Nh(s,n,Math.max(1,o)),c=a.start>0,l=a.end>=0&&a.end<r.length-1;return ne("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[c?ne(Qy,{palette:t,dir:"left"},void 0,!1,void 0,this):null,r.map((d,g)=>{if(g<a.start||g>a.end)return null;let f=g===n;return ne(ue,{palette:t,label:d.label,tone:f?"primary":"muted",fg:f?void 0:d.color,onMouseDown:()=>i(g)},d.id,!1,void 0,this)}),l?ne(Qy,{palette:t,dir:"right"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function ue(e){let{palette:t,label:r,tone:n="idle",fg:o,bg:i,onMouseDown:s}=e,a=JR(t,n);return ne("box",{height:1,paddingLeft:1,paddingRight:1,backgroundColor:i??a.bg,overflow:"hidden",flexShrink:0,onMouseDown:s,children:ne("text",{fg:o??a.fg,children:r},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Ee(e){let{palette:t,hints:r}=e;return ne("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:r.map((n)=>ne("box",{height:1,paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:ne("text",{wrapMode:"none",children:[ne("span",{fg:t.primary,children:n.key},void 0,!1,void 0,this),ne("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 Be(e){let{palette:t,items:r,hints:n,ruled:o=!0}=e,i=ne("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[r.map((s,a)=>ne(ue,{palette:t,label:s.text,tone:s.tone,onMouseDown:s.onMouseDown},`${s.text}-${a}`,!1,void 0,this)),n&&n.length>0?ne(YR,{children:[ne("box",{flexGrow:1,backgroundColor:t.element},void 0,!1,void 0,this),ne(Ee,{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 ne(je,{palette:t,backgroundColor:t.element,children:i},void 0,!1,void 0,this)}function Ze(e){let{palette:t,title:r,termW:n,termH:o,preferW:i,preferH:s,anchor:a="center",borderColor:c,bottomTitle:l,gap:d,children:g}=e,f=ur(re()),h=fo(n,o,i,s,a,!f);return ne("box",{position:"absolute",left:h.left,top:h.top,width:h.width,height:h.height,border:!0,borderStyle:wu,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:g},void 0,!1,void 0,this)}function Le(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 xo(e,t){let r=VR(null);return qR(()=>{let n=r.current;if(!n||e<0)return;let o=requestAnimationFrame(()=>{n.scrollChildIntoView(`${t}-${e}`)});return()=>cancelAnimationFrame(o)},[t,e]),r}function et(e){let t=re(),r=Ei(t),n=e.scroll?ne("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Le(e.palette),children:ne("box",{flexDirection:"column",overflow:"hidden",children:e.children},void 0,!1,void 0,this)},void 0,!1,void 0,this):e.children;return ne("box",{flexGrow:1,border:!0,borderStyle:wu,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 kn(e){let{palette:t,label:r,value:n,tone:o="text"}=e,i=re(),s=o==="success"?t.success:o==="warning"?t.warning:o==="error"?t.error:o==="muted"?t.muted:t.text;return ne("box",{height:i.rowH,flexDirection:"row",overflow:"hidden",children:[ne("box",{width:14,flexShrink:0,overflow:"hidden",children:ne("text",{fg:t.muted,children:r},void 0,!1,void 0,this)},void 0,!1,void 0,this),ne("box",{flexGrow:1,overflow:"hidden",children:ne("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 Qa(e){let{palette:t,title:r,body:n,hint:o}=e;return ne("box",{height:o?5:4,paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",border:!0,borderStyle:wu,borderColor:t.borderActive,titleColor:t.primary,children:[ne("text",{fg:t.primary,children:r},void 0,!1,void 0,this),ne("text",{fg:t.text,wrapMode:"word",children:n},void 0,!1,void 0,this),o?ne("text",{fg:t.muted,wrapMode:"word",children:o},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var wu="rounded";var ve=T(()=>{ot();pr();ze();Pe()});import{jsxDEV as se,Fragment as Zy}from"@opentui/react/jsx-dev-runtime";function ev(e){let{palette:t,cfg:r,snap:n,google:o,profile:i,reveal:s,width:a}=e,c=Ua(n,r?Object.keys(r.services):void 0),l=n?.proxy.running===!0,d=o?.adcAvailable===!0,g=a<Ia,f=ce(r?.project.name||"local",g?18:22),h=ce(i||n?.profile||"no profile",16),y=se(Zy,{children:zh({width:a,running:c.running,total:c.total,proxyOn:l,proxyAddress:n?.proxy.address??"",mcpOn:n?.mcp?.running===!0,adc:d,reveal:s}).filter((w)=>!w.hide&&w.label!=="").map((w)=>se(ue,{palette:t,label:w.label,tone:w.tone},w.label,!1,void 0,this))},void 0,!1,void 0,this),b=Ei(re());return se(je,{palette:t,backgroundColor:t.panel,ruled:!b,children:se("box",{height:g?2:1,flexDirection:"column",backgroundColor:t.panel,overflow:"hidden",children:[se("box",{height:1,flexDirection:"row",overflow:"hidden",children:[se(ue,{palette:t,label:Pt(),tone:"primary"},void 0,!1,void 0,this),se(ue,{palette:t,label:f,tone:"idle"},void 0,!1,void 0,this),se(ue,{palette:t,label:h,tone:"accent"},void 0,!1,void 0,this),g?null:se(Zy,{children:[se("box",{flexGrow:1,backgroundColor:t.panel},void 0,!1,void 0,this),y]},void 0,!0,void 0,this)]},void 0,!0,void 0,this),g?se("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.panel,children:y},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}function tv(e){let{palette:t,screen:r,width:n,onSelect:o}=e,i=Dr.map((a)=>({id:a.id,label:Fh(a.label,n)})),s=Hh(r);return se(je,{palette:t,backgroundColor:t.element,children:se(Xa,{palette:t,items:i,active:s,width:n,onPick:(a)=>{let c=Dr[a];if(c)o(c.id)}},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function rv(e){let{palette:t,overlay:r,query:n,onQuery:o,onSubmit:i}=e;if(r==="slash"||r==="palette"){let c=r==="slash"?"/":"> ";return se(je,{palette:t,backgroundColor:t.highlight,edge:"top",children:se("box",{height:1,backgroundColor:t.highlight,paddingLeft:1,flexDirection:"row",overflow:"hidden",children:[se("box",{width:2,flexShrink:0,children:se("text",{fg:t.primary,children:c},void 0,!1,void 0,this)},void 0,!1,void 0,this),se("box",{flexGrow:1,overflow:"hidden",children:se("input",{focused:!0,value:n,placeholder:r==="slash"?"start auth":"filter commands",onInput:o,onSubmit:()=>i(n),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=r==="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 se(je,{palette:t,backgroundColor:t.element,edge:"top",children:se("box",{height:1,backgroundColor:t.element,overflow:"hidden",children:se(Ee,{palette:t,hints:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function nv(e){let{palette:t,screen:r,overlay:n,status:o,paused:i,errorOnly:s,width:a,copyKey:c}=e,l=Ei(re()),d=Math.max(18,Math.floor(a*0.42)),g=po(Uy(r,n,c),d),f=Zh(o);return se(je,{palette:t,backgroundColor:t.panel,edge:"top",ruled:!l,children:se("box",{height:1,backgroundColor:t.panel,overflow:"hidden",children:se(Be,{ruled:!1,palette:t,items:[{text:r,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:f}]],hints:g},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function De(e){return se("box",{flexGrow:1,padding:1,overflow:"hidden",children:se(Qa,{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 Za(e){return se("box",{flexGrow:1,padding:1,overflow:"hidden",children:se("text",{fg:e.palette.text,children:e.label},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function ov(e){return se("box",{flexGrow:1,padding:1,flexDirection:"column",overflow:"hidden",children:[se("text",{fg:e.palette.error,children:e.title},void 0,!1,void 0,this),se("text",{fg:e.palette.text,wrapMode:"word",children:e.body},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var kt=T(()=>{ot();Pe();ve();pr();ze()});function zR(){if(process.platform==="darwin")return[["pbcopy"]];if(process.platform==="win32")return[["clip"]];return[["wl-copy"],["xclip","-selection","clipboard"],["xsel","--clipboard","--input"]]}function XR(){return zR().filter((e)=>{let t=e[0];return typeof t==="string"&&Bun.which(t)!==null})}function QR(e){return`\x1B]52;c;${Buffer.from(e,"utf8").toString("base64")}\x07`}function iv(){if(process.platform==="linux")return"install wl-clipboard (Wayland) or xclip (X11)";return"no clipboard helper found"}async function Su(e){let t=XR(),r;for(let n of t)try{await eP(n,e);return}catch(o){r=o instanceof Error?o:Error(String(o))}if(process.platform!=="win32")try{await ZR(e);return}catch(n){r=n instanceof Error?n:Error(String(n))}throw be(nt,"clipboard unavailable",r?`${iv()} (${r.message})`:iv())}async function ZR(e){let t=QR(e);try{await Bun.write("/dev/tty",t)}catch{if(!process.stderr.write(t))throw Error("terminal clipboard write failed")}}async function eP(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 sv=T(()=>{_e()});function av(e){return e==="slash"||e==="palette"||e==="config-edit"}function cv(e,t){return dr(e,t.keybinds.leader??"ctrl+x")}function lv(e,t){return dr(e,t.keybinds.command_list??"ctrl+p")}function dv(e,t){return dr(e,t.keybinds.command??"/")||e.name==="/"}function uv(e,t){return dr(e,t.keybinds.help??"?")||e.sequence==="?"}function pv(e,t){return dr(e,t.keybinds.search??"f")}function fv(e){let t=e.name??"";return t==="R"||e.shift===!0&&t.toLowerCase()==="r"}function gv(e){return e.ctrl===!0&&(e.name??"").toLowerCase()==="l"}function mv(e,t){if(t&&dr(e,t.keybinds.interrupt??"ctrl+c"))return!0;return e.ctrl===!0&&(e.name??"").toLowerCase()==="c"}function hv(e,t){return dr(e,t.keybinds.copy??lr())}function yv(e,t,r=tP){return t>0&&e-t<=r}function Or(e,t,r,n){return dr(e,t.keybinds[r]??n)}function ec(e){let t=(e.name??"").toLowerCase();return t==="pagedown"||e.ctrl===!0&&t==="d"&&!e.meta}function tc(e){let t=(e.name??"").toLowerCase();return t==="pageup"||e.ctrl===!0&&t==="u"&&!e.meta}var tP=2000;var vv=T(()=>{Vt()});import{jsxDEV as Ir}from"@opentui/react/jsx-dev-runtime";function xv(e){let{palette:t,path:r,initialValue:n,error:o,termW:i,termH:s,textareaRef:a}=e;return Ir(Ze,{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:[Ir("box",{height:1,overflow:"hidden",children:Ir("text",{fg:t.muted,wrapMode:"none",children:r},void 0,!1,void 0,this)},void 0,!1,void 0,this),Ir("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!==""?Ir("box",{height:2,overflow:"hidden",children:Ir("text",{fg:t.error,wrapMode:"word",children:o},void 0,!1,void 0,this)},void 0,!1,void 0,this):Ir("box",{height:1,overflow:"hidden",children:Ir("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 bv=T(()=>{ve()});import{jsxDEV as ku}from"@opentui/react/jsx-dev-runtime";function wv(e){let{palette:t,title:r,body:n,termW:o,termH:i}=e;return ku(Ze,{palette:t,title:r,bottomTitle:"enter confirm \xB7 esc stay",termW:o,termH:i,preferW:52,preferH:8,borderColor:t.warning,gap:1,children:[ku("text",{fg:t.text,wrapMode:"word",children:n},void 0,!1,void 0,this),ku(Ee,{palette:t,hints:[{key:"enter",label:"confirm"},{key:"esc",label:"stay"}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Sv=T(()=>{ve()});import{jsxDEV as Bt}from"@opentui/react/jsx-dev-runtime";function kv(e){let{palette:t,event:r,termW:n,termH:o,scrollRef:i}=e;if(!r)return null;let s=r.message.length>120||r.message.includes(`
|
|
617
|
-
`);return Bt(Ze,{palette:t,title:"log details",bottomTitle:"j/k scroll \xB7 esc close",termW:n,termH:o,preferW:s?84:72,preferH:s?22:14,gap:1,children:Bt("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Le(t),children:Bt("box",{flexDirection:"column",overflow:"hidden",children:[Bt("text",{fg:t.text,wrapMode:"word",children:r.message},void 0,!1,void 0,this),Bt("text",{fg:t.muted,children:`time ${r.timestamp}`},void 0,!1,void 0,this),Bt("text",{fg:He(r.service,t),children:`service ${r.service}`},void 0,!1,void 0,this),Bt("text",{fg:t.muted,children:`source ${r.source}${r.stream?` / ${r.stream}`:""}`},void 0,!1,void 0,this),Bt("text",{fg:t.muted,children:`level ${r.level}`},void 0,!1,void 0,this),Bt("text",{fg:t.muted,children:`pid ${r.pid||"\u2014"}`},void 0,!1,void 0,this),Bt("text",{fg:t.muted,children:`request ${r.request_id||"\u2014"}`},void 0,!1,void 0,this),Bt("text",{fg:t.muted,children:`identity ${r.identity||"\u2014"}`},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 Cv=T(()=>{ve();ze()});import{jsxDEV as xe,Fragment as Rv}from"@opentui/react/jsx-dev-runtime";function lP(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 Fr(e){return e+oP}function Pv(e){let t=Fr(_u.length),r=Fr(Ru.length),n=Fr(e.logCount),o=Fr(Pu.length),i=Fr(Eu.length),s=Tu+e.pad*2;if(e.stacked)return s+t+r+n+o+i+Cu+(aP-1)*e.gap;let a=Math.max(t,r),c=Math.max(o,i);return s+a+n+c+Cu+(cP-1)*e.gap}function dP(e){return Pv(e)-Tu-e.pad*2}function uP(e){return e-Tu*2<nP}function Ev(e){let{palette:t,termW:r,termH:n,copyKey:o=lr(),scrollRef:i}=e,s=ur(re()),a=uP(r),c=s?0:1,l=s?0:1,d=lP(o),g={stacked:a,logCount:d.length,pad:c,gap:l},f=Pv(g),h=dP(g);return xe(Ze,{palette:t,title:"help",bottomTitle:`${Pt()} \xB7 j/k scroll \xB7 esc close`,termW:r,termH:n,preferW:rP,preferH:f,gap:0,children:xe("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Le(t),children:xe("box",{height:h,flexDirection:"column",flexShrink:0,overflow:"hidden",gap:l,children:[a?xe(Rv,{children:[xe($r,{palette:t,title:"navigation",bindings:_u},void 0,!1,void 0,this),xe($r,{palette:t,title:"services",bindings:Ru},void 0,!1,void 0,this),xe($r,{palette:t,title:"logs",bindings:d},void 0,!1,void 0,this),xe($r,{palette:t,title:"commands",bindings:Pu},void 0,!1,void 0,this),xe($r,{palette:t,title:"display",bindings:Eu},void 0,!1,void 0,this)]},void 0,!0,void 0,this):xe(Rv,{children:[xe(_v,{palette:t,left:{title:"navigation",bindings:_u},right:{title:"services",bindings:Ru}},void 0,!1,void 0,this),xe($r,{palette:t,title:"logs",bindings:d},void 0,!1,void 0,this),xe(_v,{palette:t,left:{title:"commands",bindings:Pu},right:{title:"display",bindings:Eu}},void 0,!1,void 0,this)]},void 0,!0,void 0,this),xe("box",{height:Cu,flexShrink:0,overflow:"hidden",paddingLeft:1,children:xe("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 _v(e){let{palette:t,left:r,right:n}=e,o=Math.max(Fr(r.bindings.length),Fr(n.bindings.length));return xe("box",{height:o,flexDirection:"row",flexShrink:0,overflow:"hidden",gap:sP,children:[xe($r,{palette:t,title:r.title,bindings:r.bindings,height:o,stretch:!0},void 0,!1,void 0,this),xe($r,{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 $r(e){let{palette:t,title:r,bindings:n,stretch:o=!1}=e,i=e.height??Fr(n.length);return xe("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((s)=>xe("box",{height:1,flexShrink:0,overflow:"hidden",paddingLeft:1,paddingRight:1,children:xe(pP,{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 pP(e){let{palette:t,binding:r}=e;return xe("box",{height:1,flexDirection:"row",overflow:"hidden",children:[xe("box",{width:iP,flexShrink:0,overflow:"hidden",children:xe("text",{fg:t.primary,wrapMode:"none",children:r.key},void 0,!1,void 0,this)},void 0,!1,void 0,this),xe("box",{flexGrow:1,overflow:"hidden",children:xe("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 rP=78,nP=56,oP=2,Tu=2,Cu=1,Au=8,iP=16,sP=2,aP=6,cP=4,_u,Ru,Pu,Eu;var Tv=T(()=>{ot();ve();pr();Vt();_u=[{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"}],Ru=[{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"}];Pu=[{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:"/mcp",label:"agent MCP server"}],Eu=[{key:"ctrl+=",label:"larger"},{key:"ctrl+-",label:"smaller"},{key:"?",label:"this overlay"}]});import{jsxDEV as Av}from"@opentui/react/jsx-dev-runtime";function Lv(e){let{palette:t,termW:r,termH:n}=e,o=bu();return Av(Ze,{palette:t,title:"leader",termW:r,termH:n,preferW:68,preferH:5,anchor:"bottom",children:Av(Ee,{palette:t,hints:o},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var Dv=T(()=>{Pe();ve()});import{jsxDEV as Mv}from"@opentui/react/jsx-dev-runtime";function Ov(e){let{palette:t,items:r,selected:n,termW:o,termH:i,onIndex:s,onPick:a}=e,c=Gy(r),l=fo(o,i,64,18,"center",!ur(re()));return Mv(Ze,{palette:t,title:"commands",bottomTitle:"enter select \xB7 esc close",termW:o,termH:i,preferW:64,preferH:18,children:Mv("select",{height:Math.max(4,l.height-3),options:c,selectedIndex:n,showDescription:!0,showSelectionIndicator:!0,wrapSelection:!0,backgroundColor:t.panel,focusedBackgroundColor:t.panel,textColor:t.text,focusedTextColor:t.text,selectedBackgroundColor:t.highlight,selectedTextColor:t.primary,descriptionColor:t.muted,selectedDescriptionColor:t.accent,onChange:(d)=>s(d),onSelect:(d,g)=>{let f=g?.value;if(typeof f==="string"&&f!=="")a(f)}},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var Iv=T(()=>{ot();Pe();ve();pr()});import{jsxDEV as I}from"@opentui/react/jsx-dev-runtime";function Lu(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 fP(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 $v(e){return I("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:I("text",{wrapMode:"none",children:[I("span",{fg:e.palette.primary,children:e.label.toUpperCase()},void 0,!1,void 0,this),e.detail?I("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 Fv(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:g}=e,f=new Set(d),h=r.waves.map((ae,Oe)=>({wave:ae.filter((Ke)=>!f.has(Ke)),waveIdx:Oe})).filter(({wave:ae})=>ae.length>0),y=Iy(r,n,s),b=r.waves[y.currentWaveIndex]??[],w=Fi(b,n,s),R=Lu(w,t),S=fP(o,i,w,t),N=Fy(s,o,i,r.profile),J=Ny(o,i),v=i?t.inverse:t.text,A=i?t.error:t.element,m=Math.min(92,Math.max(40,a-8)),_=m>=82?22:m>=66?17:13,F=12,Z=9,he=m>=56,ke=m>=72,Je=m<72||r.waves.length>3,Ue=r.profile?`PROFILE ${r.profile}`:s.toUpperCase();return I(Ze,{palette:t,title:N,bottomTitle:"enter close \xB7 esc hide (operation continues)",termW:a,termH:c,preferW:98,preferH:28,borderColor:S.color,gap:0,children:[I("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:[I(ue,{palette:t,label:`${S.icon} ${S.label.toUpperCase()}`,tone:S.tone},void 0,!1,void 0,this),I("box",{paddingLeft:1,flexGrow:1,overflow:"hidden",children:I("text",{fg:t.text,wrapMode:"none",children:Ue},void 0,!1,void 0,this)},void 0,!1,void 0,this),I(ue,{palette:t,label:`${y.ready}/${y.total} READY`,tone:y.isComplete?"success":"info"},void 0,!1,void 0,this),I(ue,{palette:t,label:`WAVE ${Math.min(y.currentWaveIndex+1,Math.max(1,y.totalWaves))}/${Math.max(1,y.totalWaves)}`,tone:R.tone},void 0,!1,void 0,this)]},void 0,!0,void 0,this),I("box",{height:2,flexDirection:"column",overflow:"hidden",flexShrink:0,paddingLeft:1,paddingRight:1,children:[I("box",{height:1,flexDirection:"row",overflow:"hidden",children:[I("text",{wrapMode:"none",children:[I("span",{fg:t.muted,children:"PROGRESS "},void 0,!1,void 0,this),I("span",{fg:S.color,children:`[${y.progressBar}]`},void 0,!1,void 0,this),I("span",{fg:t.text,children:` ${y.percent}%`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),I("box",{flexGrow:1},void 0,!1,void 0,this),I("text",{wrapMode:"none",children:I("span",{fg:R.color,children:`${R.icon} ${R.label}`},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),I("box",{height:1,overflow:"hidden",children:I("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.":J.primary},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),I($v,{palette:t,label:"Pipeline",detail:`${r.waves.length} execution wave${r.waves.length===1?"":"s"}`},void 0,!1,void 0,this),I("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:r.waves.map((ae,Oe)=>{let Ke=Fi(ae,n,s),de=Lu(Ke,t),we=Je?`W${Oe+1} ${de.icon} ${ae.length}`:`W${Oe+1} ${de.icon} ${de.label} \xB7 ${ae.length}`;return I("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:[I(ue,{palette:t,label:we,tone:de.tone},void 0,!1,void 0,this),Oe<r.waves.length-1?I("box",{width:3,flexShrink:0,overflow:"hidden",children:I("text",{fg:t.muted,children:" \u2500\u25BA"},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},`step-${Oe}`,!0,void 0,this)})},void 0,!1,void 0,this),(r.blockers??[]).length>0?I("box",{minHeight:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,paddingLeft:1,children:I("text",{fg:t.error,wrapMode:"word",children:`BLOCKED ${r.blockers?.map((ae)=>`${ae.name}: ${ae.message}`).join(" \xB7 ")}`},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,d.length>0?I("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,paddingLeft:1,children:I("text",{wrapMode:"none",children:[I("span",{fg:t.success,children:"\u2713 ALREADY READY"},void 0,!1,void 0,this),I("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,I($v,{palette:t,label:"Wave details",detail:"live process and health state"},void 0,!1,void 0,this),I("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,paddingLeft:1,children:[I("box",{width:2,flexShrink:0},void 0,!1,void 0,this),I("box",{width:_,flexShrink:0,overflow:"hidden",children:I("text",{fg:t.muted,children:Y("SERVICE",_)},void 0,!1,void 0,this)},void 0,!1,void 0,this),I("box",{width:12,flexShrink:0,overflow:"hidden",children:I("text",{fg:t.muted,children:Y("STATE",12)},void 0,!1,void 0,this)},void 0,!1,void 0,this),he?I("box",{width:9,flexShrink:0,overflow:"hidden",children:I("text",{fg:t.muted,children:Y("PORT",9)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,ke?I("box",{flexGrow:1,overflow:"hidden",children:I("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),I("scrollbox",{ref:l,focused:!1,stickyScroll:!1,scrollX:!1,style:Le(t),children:I("box",{flexDirection:"column",overflow:"hidden",gap:1,children:h.map(({wave:ae,waveIdx:Oe})=>{let Ke=Fi(ae,n,s),de=Lu(Ke,t),we=`${$y(s,Oe,Ke)} \xB7 ${ae.length} service${ae.length===1?"":"s"}`;return I("box",{border:!0,borderStyle:"rounded",borderColor:de.color,title:we,titleColor:de.color,flexDirection:"column",paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:ae.map((Ce)=>{let W=n?.services[Ce],Ie=Ot(W),lt=Oy(Ce,r,n,s),$e=Ce===i||Ie==="FAILED",_t=Ie==="UNHEALTHY",dt=Ie==="HEALTHY"||s==="stop"&&Ie==="STOPPED",zt=Sn(W),ut=$e?"\u2717":dt?"\u2713":_t?"\u26A0":Ie==="STARTING"||Ie==="RUNNING"||Ie==="STOPPING"||Ie==="RESTARTING"?"\u25CF":"\u25CB",Xt=$e?t.error:Re(t,Ie),pt=$e?t.error:_t?t.warning:dt?t.success:t.muted;return I("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[I("box",{width:2,flexShrink:0,overflow:"hidden",children:I("text",{fg:Xt,children:ut},void 0,!1,void 0,this)},void 0,!1,void 0,this),I("box",{width:_,flexShrink:0,overflow:"hidden",children:I("text",{fg:He(Ce,t),wrapMode:"none",children:Y(Ce,_)},void 0,!1,void 0,this)},void 0,!1,void 0,this),I("box",{width:12,flexShrink:0,overflow:"hidden",children:I("text",{fg:Re(t,Ie),wrapMode:"none",children:Y(Ie,12)},void 0,!1,void 0,this)},void 0,!1,void 0,this),he?I("box",{width:9,flexShrink:0,overflow:"hidden",children:I("text",{fg:zt?t.info:t.muted,wrapMode:"none",children:Y(zt?`:${zt}`:"\u2014",9)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,ke?I("box",{flexGrow:1,overflow:"hidden",children:I("text",{fg:pt,wrapMode:"none",children:lt},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},Ce,!0,void 0,this)})},`wave-card-${Oe}`,!1,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this),I("box",{height:3,flexShrink:0,flexDirection:"column",backgroundColor:A,border:["top"],borderStyle:"single",borderColor:S.color,paddingLeft:1,paddingRight:1,overflow:"hidden",onMouseDown:g,children:[I("text",{fg:v,wrapMode:"none",children:J.primary},void 0,!1,void 0,this),I("text",{fg:i?t.inverse:t.muted,wrapMode:"none",children:J.secondary},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var Nv=T(()=>{Pe();ve();ze()});import{jsxDEV as Yt}from"@opentui/react/jsx-dev-runtime";function Hv(e){let{palette:t,route:r,termW:n,termH:o,scrollRef:i}=e;if(!r)return null;return Yt(Ze,{palette:t,title:r.name,bottomTitle:"j/k scroll \xB7 esc close",termW:n,termH:o,preferW:78,preferH:16,gap:1,children:Yt("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Le(t),children:Yt("box",{flexDirection:"column",overflow:"hidden",children:[Yt("text",{fg:t.muted,children:`auth ${r.authType||"none"}`},void 0,!1,void 0,this),Yt("text",{fg:t.muted,children:`identity ${r.identityType||"\u2014"}`},void 0,!1,void 0,this),Yt("text",{fg:t.text,wrapMode:"word",children:`account ${r.serviceAccount||"\u2014"}`},void 0,!1,void 0,this),Yt("text",{fg:t.text,wrapMode:"word",children:`audience ${r.audience||"\u2014"}`},void 0,!1,void 0,this),Yt("text",{fg:t.muted,children:`match host ${r.matchHost||"*"}`},void 0,!1,void 0,this),Yt("text",{fg:t.muted,children:`match path ${r.matchPath||"*"}`},void 0,!1,void 0,this),Yt("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 jv=T(()=>{ve()});import{jsxDEV as At}from"@opentui/react/jsx-dev-runtime";function Wv(e){let{palette:t,items:r,query:n,selected:o,onQuery:i,onSubmit:s}=e,a=Ky(o,Bv,r.length),c=r.slice(a,a+Bv),l=Math.max(c.length,1),d=wn(r,o);return At("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?At("box",{height:1,paddingLeft:1,overflow:"hidden",children:At("text",{fg:t.muted,children:"no matching command"},void 0,!1,void 0,this)},void 0,!1,void 0,this):c.map((g)=>{let f=g.name===d?.name;return At("box",{height:1,flexDirection:"row",overflow:"hidden",paddingLeft:1,paddingRight:1,backgroundColor:f?t.highlight:t.panel,children:[At("box",{width:14,flexShrink:0,overflow:"hidden",children:At("text",{fg:f?t.primary:t.text,wrapMode:"none",children:`${f?"\u203A":" "} /${g.name}`},void 0,!1,void 0,this)},void 0,!1,void 0,this),At("box",{flexGrow:1,overflow:"hidden",children:At("text",{fg:f?t.accent:t.muted,wrapMode:"none",children:g.desc},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},g.name,!0,void 0,this)}),At("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.highlight,paddingLeft:1,children:[At("box",{width:2,flexShrink:0,children:At("text",{fg:t.primary,children:"/"},void 0,!1,void 0,this)},void 0,!1,void 0,this),At("box",{flexGrow:1,overflow:"hidden",children:At("input",{focused:!0,value:n,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 Bv=8;var Gv=T(()=>{Pe()});import{jsxDEV as qv}from"@opentui/react/jsx-dev-runtime";function Vv(e){let{palette:t,themeName:r,selected:n,termW:o,termH:i,onIndex:s,onPreview:a,onPick:c}=e,l=ht.map((g)=>({name:g===r?`${g} (active)`:g,description:g===r?`${Jd[g]} \xB7 current`:Jd[g],value:g})),d=fo(o,i,Uv,Kv,"center",!ur(re()));return qv(Ze,{palette:t,title:"/themes",bottomTitle:"enter save \xB7 esc revert",termW:o,termH:i,preferW:Uv,preferH:Kv,children:qv("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:(g)=>{s(g);let f=ht[g];if(f)a(f)},onSelect:(g,f)=>{let h=f?.value;if(typeof h==="string"&&h!=="")c(h)}},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var Uv=52,Kv=22;var Jv=T(()=>{ot();Pe();ve();pr();ze()});import{jsxDEV as Ge}from"@opentui/react/jsx-dev-runtime";function rc(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 Ge("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 Yv(e){let{palette:t,cfg:r,google:n,identity:o}=e;if(!n&&!o)return Ge(Za,{palette:t,label:"Checking Application Default Credentials\u2026"},void 0,!1,void 0,this);let i=gP(r,o),s=o?.user||n?.userEmail||"",{project:a,source:c}=vo(r,o,n),l=o?.adc??n?.adcAvailable===!0,d=o?.iap??(r?.proxy.routes??[]).some((b)=>b.auth.type.toLowerCase()==="iap"),g=i.filter((b)=>b.inactive!==!0),f=g.some((b)=>b.ok===!0),h=g.some((b)=>b.ok===!1),y=f?"AVAILABLE":h?"UNAVAILABLE":g.length>0?"NOT PROBED":i.length>0?"not required":"not configured";return Ge(et,{palette:t,title:"identity",scroll:!0,children:[Ge(rc,{palette:t,title:"Google identity",tone:l?"success":"warning",children:[Ge(kn,{palette:t,label:"user",value:s||"(unknown)"},void 0,!1,void 0,this),Ge(kn,{palette:t,label:"project",value:a||"(unset)"},void 0,!1,void 0,this),Ge(kn,{palette:t,label:"source",value:c||"\u2014"},void 0,!1,void 0,this),Ge(kn,{palette:t,label:"ADC",value:l?"\u2713 available":"\u2717 missing",tone:l?"success":"error"},void 0,!1,void 0,this),Ge(kn,{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),Ge(rc,{palette:t,title:`Service accounts (${i.length})`,tone:g.length===0?"muted":f?"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((b)=>Ge("text",{fg:b.inactive?t.muted:b.ok===!0?t.success:b.ok===!1?t.error:t.text,wrapMode:"none",children:`${b.inactive?"\u2013":b.ok===!0?"\u2713":b.ok===!1?"\u2717":"\u25CB"} ${b.email}${b.inactive?" \u2014 inactive (route auth is none)":""}`},b.email,!1,void 0,this)),Ge("box",{height:1,flexShrink:0},void 0,!1,void 0,this),Ge(kn,{palette:t,label:"impersonation",value:y,tone:f?"success":g.length>0?"warning":"muted"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Ge(rc,{palette:t,title:"IAP",tone:d?"success":"muted",children:[Ge("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:Ge(ue,{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(rc,{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:"run `gcloud auth application-default login` or /auth"},void 0,!1,void 0,this)]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this)}function gP(e,t){let r=new Map((e?Ml(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 zv=T(()=>{kt();Pe();ve();rn()});import{jsxDEV as ct}from"@opentui/react/jsx-dev-runtime";function Xv(e){let{palette:t,credentials:r}=e;if(!r)return ct(Za,{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 ct(et,{palette:t,title:"credentials",scroll:!0,children:[ct("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[ct(ue,{palette:t,label:`backend: ${r.backend}`,tone:"info"},void 0,!1,void 0,this),r.entries.length>0?ct(ue,{palette:t,label:`${n} valid`,tone:"success"},void 0,!1,void 0,this):null,o>0?ct(ue,{palette:t,label:`${o} expired`,tone:"warning"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),ct("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),ct("box",{height:1,flexShrink:0},void 0,!1,void 0,this),r.entries.length===0?ct("text",{fg:t.muted,children:"no cached credentials"},void 0,!1,void 0,this):ct("box",{flexDirection:"column",overflow:"hidden",gap:1,children:r.entries.map((i)=>ct("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:[ct("text",{wrapMode:"none",children:[ct("span",{fg:i.valid?t.success:t.warning,children:i.valid?"\u2713 valid":"\u2717 expired"},void 0,!1,void 0,this),ct("span",{fg:t.muted,children:` \xB7 expires ${i.expires_at}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),ct("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),ct(Qa,{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 Qv=T(()=>{kt();ve()});function Zv(e){let t=Object.keys(e.services).length,r=Object.keys(e.profiles).length,n=e.proxy.routes.length,o=[{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)o.push({text:`${n} route${n===1?"":"s"}`,tone:"info"});return o}function ex(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 tx(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 rx(e){let t=mP(e);return[{label:"exit",value:t,tone:t==="ask on quit"?"warning":"text"},{label:"grace",value:`${e.shutdown.grace_seconds}s`},{label:"refresh",value:`${hs(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 nx(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 ox(e){return[{label:"listen",value:Yr(e.proxy.listen),tone:e.proxy.enabled?"text":"muted"},{label:"token",value:vP(e),tone:e.proxy.token_endpoint.enabled?"text":"muted"}]}function ix(e){return Object.keys(e.services).sort().map((t)=>{let r=e.services[t]??Nn();return{name:t,extends:r.extends||"\u2014",command:Va(r),ports:Ni(r),identity:Ya(r),health:Ja(r),depends:r.dependencies.join(", ")||"\u2014",restart:za(r)}})}function sx(e){return e.proxy.routes.map((t)=>({name:t.name||t.match.host||"(unnamed)",match:xP(t),upstream:t.upstream.url||"\u2014",auth:t.auth.type||"none",identity:bP(t)}))}function ax(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 cx(e){return Object.keys(e.templates).sort().map((t)=>({name:t,summary:wP(e.templates[t])}))}function lx(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 mP(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 dx(e){let t=e.reduce((r,n)=>Math.max(r,n.name.length),0);return Math.min(yP,Math.max(hP,t))}function vP(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 xP(e){let t=e.match.host||"*",r=e.match.path;if(r==="")return t;return`${t}${r.startsWith("/")?r:`/${r}`}`}function bP(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 wP(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 hP=8,yP=20,ux=80,bo=10;var px=T(()=>{St();Pe()});import{jsxDEV as P}from"@opentui/react/jsx-dev-runtime";function mx(e){let{palette:t,cfg:r,width:n}=e,o=re();if(!r)return P(De,{palette:t,title:"No configuration",body:"Create .devctl/config.yaml or run setup."},void 0,!1,void 0,this);let i=Math.max(bo+8,n-6-o.pad*2),s=i>=ux,a=s?Math.floor((i-fx)/2):i,c=ix(r),l=sx(r),d=ax(r),g=cx(r);return P(et,{palette:t,title:`config ${r.project.name||"unnamed"}`,children:[P(Be,{palette:t,items:Zv(r)},void 0,!1,void 0,this),P("box",{flexGrow:1,overflow:"hidden",children:P("scrollbox",{ref:e.scrollRef,focused:!1,stickyScroll:!1,scrollX:!1,style:Le(t),children:P("box",{flexDirection:"column",overflow:"hidden",gap:gx,children:[P(Du,{wide:s,left:P(gr,{palette:t,title:"project",children:P(wo,{palette:t,facts:ex(r,at),width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:P(gr,{palette:t,title:"google",children:P(wo,{palette:t,facts:tx(r),width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),P(Du,{wide:s,left:P(gr,{palette:t,title:"runtime",children:P(wo,{palette:t,facts:rx(r),width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:P(gr,{palette:t,title:"logs",children:P(wo,{palette:t,facts:nx(r),width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),P(gr,{palette:t,title:`proxy ${r.proxy.enabled?"enabled":"disabled"}`,children:[P(wo,{palette:t,facts:ox(r),width:i},void 0,!1,void 0,this),P(kP,{palette:t,routes:l,width:i},void 0,!1,void 0,this)]},void 0,!0,void 0,this),P(gr,{palette:t,title:`services ${c.length}`,children:P(SP,{palette:t,rows:c,width:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),P(Du,{wide:s,left:P(gr,{palette:t,title:`profiles ${d.length}`,children:P(CP,{palette:t,rows:d,width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:P(gr,{palette:t,title:`templates ${g.length}`,children:P(_P,{palette:t,rows:g,empty:"no templates",width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),P(gr,{palette:t,title:"extras",children:P(wo,{palette:t,facts:lx(r),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),P(je,{palette:t,backgroundColor:t.element,edge:"top",children:P(Ee,{palette:t,hints:[{key:"v",label:"validate/save buffer"},{key:"e",label:"open in $EDITOR"},{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 Du(e){let{wide:t,left:r,right:n}=e;if(!t)return P("box",{flexDirection:"column",overflow:"hidden",gap:gx,flexShrink:0,children:[r,n]},void 0,!0,void 0,this);return P("box",{flexDirection:"row",overflow:"hidden",gap:fx,flexShrink:0,children:[P("box",{flexGrow:1,flexBasis:0,overflow:"hidden",children:r},void 0,!1,void 0,this),P("box",{flexGrow:1,flexBasis:0,overflow:"hidden",children:n},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function gr(e){let{palette:t,title:r,children:n}=e;return P("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 wo(e){let{palette:t,facts:r,width:n}=e,o=Math.max(4,n-bo-4);return P("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((i)=>P("box",{height:1,flexDirection:"row",overflow:"hidden",children:[P("box",{width:bo,flexShrink:0,overflow:"hidden",children:P("text",{fg:t.muted,wrapMode:"none",children:Y(i.label,bo)},void 0,!1,void 0,this)},void 0,!1,void 0,this),P("box",{width:o,flexShrink:0,overflow:"hidden",children:P("text",{fg:EP(t,i.tone),wrapMode:"none",children:Y(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 SP(e){let{palette:t,rows:r,width:n}=e;if(r.length===0)return P(nc,{palette:t,text:"no services"},void 0,!1,void 0,this);let o=dx(r),i=Math.max(8,n-o-6);return P("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((s)=>P("box",{height:1,flexDirection:"row",overflow:"hidden",children:[P("box",{width:o,flexShrink:0,overflow:"hidden",children:P("text",{fg:He(s.name,t),wrapMode:"none",children:Y(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),P("box",{width:i,flexShrink:0,overflow:"hidden",children:P("text",{fg:t.text,wrapMode:"none",children:ce(RP(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 kP(e){let{palette:t,routes:r,width:n}=e;if(r.length===0)return P(nc,{palette:t,text:"no routes"},void 0,!1,void 0,this);let o=Math.min(bo+4,Math.max(8,...r.map((s)=>s.name.length))),i=Math.max(8,n-o-6);return P("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((s)=>P("box",{height:1,flexDirection:"row",overflow:"hidden",children:[P("box",{width:o,flexShrink:0,overflow:"hidden",children:P("text",{fg:t.primary,wrapMode:"none",children:Y(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),P("box",{width:i,flexShrink:0,overflow:"hidden",children:P("text",{fg:t.text,wrapMode:"none",children:ce(PP(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 CP(e){let{palette:t,rows:r,width:n}=e;if(r.length===0)return P(nc,{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 P("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((s)=>P("box",{height:1,flexDirection:"row",overflow:"hidden",children:[P("box",{width:o,flexShrink:0,overflow:"hidden",children:P("text",{fg:t.primary,wrapMode:"none",children:Y(s.name,o)},void 0,!1,void 0,this)},void 0,!1,void 0,this),P("box",{width:i,flexShrink:0,overflow:"hidden",children:P("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 _P(e){let{palette:t,rows:r,empty:n,width:o}=e;if(r.length===0)return P(nc,{palette:t,text:n},void 0,!1,void 0,this);let i=Math.min(14,Math.max(8,...r.map((a)=>a.name.length))),s=Math.max(8,o-i-6);return P("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:r.map((a)=>P("box",{height:1,flexDirection:"row",overflow:"hidden",children:[P("box",{width:i,flexShrink:0,overflow:"hidden",children:P("text",{fg:t.text,wrapMode:"none",children:Y(a.name,i)},void 0,!1,void 0,this)},void 0,!1,void 0,this),P("box",{width:s,flexShrink:0,overflow:"hidden",children:P("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 nc(e){return P("box",{height:1,overflow:"hidden",children:P("text",{fg:e.palette.muted,wrapMode:"none",children:e.text},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function RP(e){let t=e.extends==="\u2014"?"":` ${e.extends}`;return` ${e.ports} ${e.identity} ${e.health} ${e.restart} \u2190 ${e.depends}${t}`}function PP(e){return` ${e.auth} ${e.identity} ${e.match} \u2192 ${e.upstream}`}function EP(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 fx=1,gx=1;var hx=T(()=>{kt();px();ot();Pe();ve();ze()});import{useRef as TP}from"react";import{jsxDEV as pe}from"@opentui/react/jsx-dev-runtime";function oc(e){let{palette:t,names:r,snap:n,selected:o,checked:i,width:s,onOpen:a,onSelectIndex:c,onToggle:l}=e,d=re(),g=TP(!1),f=new Set(i),h=fu(s),y=pu(s),b=uu(s),w=jh(s);return pe("box",{flexDirection:"column",flexGrow:1,overflow:"hidden",children:[pe("box",{height:1,flexDirection:"row",overflow:"hidden",children:[pe(vt,{width:2,fg:t.muted,text:""},void 0,!1,void 0,this),pe(vt,{width:4,fg:t.accent,text:"sel"},void 0,!1,void 0,this),pe(vt,{width:2,fg:t.muted,text:""},void 0,!1,void 0,this),pe(vt,{width:w,fg:t.muted,text:"name"},void 0,!1,void 0,this),pe(vt,{width:yt,fg:t.muted,text:""},void 0,!1,void 0,this),pe(vt,{width:Jt,fg:t.muted,text:"state"},void 0,!1,void 0,this),b?pe(vt,{width:fr,fg:t.muted,text:"health"},void 0,!1,void 0,this):null,y?pe(vt,{width:La,fg:t.muted,text:"port"},void 0,!1,void 0,this):null,h?pe(vt,{width:Mr,fg:t.muted,text:"pid"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),r.map((R,S)=>{let N=n?.services[R],J=Ot(N),v=N?.health??"UNKNOWN",A=f.has(R),m=S===o,_=A?"[x]":"[ ]",F=m?"\u203A":" ";return pe("box",{height:d.rowH,flexDirection:"row",overflow:"hidden",backgroundColor:m?t.highlight:A?t.element:void 0,onMouseDown:()=>{if(g.current)return;if(m){a(R);return}c(S)},children:[pe("box",{width:2,flexShrink:0,children:pe("text",{fg:t.primary,children:F},void 0,!1,void 0,this)},void 0,!1,void 0,this),pe("box",{width:4,flexShrink:0,onMouseDown:()=>{g.current=!0,l?.(R),setTimeout(()=>{g.current=!1},0)},children:pe("text",{fg:AP(t,A,m),children:_},void 0,!1,void 0,this)},void 0,!1,void 0,this),pe("box",{width:2,flexShrink:0,children:pe("text",{fg:Re(t,J),children:Tt(J)},void 0,!1,void 0,this)},void 0,!1,void 0,this),pe(vt,{width:w,fg:m?t.primary:He(R,t),text:Y(R,w)},void 0,!1,void 0,this),pe(vt,{width:yt,fg:t.muted,text:""},void 0,!1,void 0,this),pe(vt,{width:Jt,fg:Re(t,J),text:J},void 0,!1,void 0,this),b?pe(vt,{width:fr,fg:Re(t,v),text:v},void 0,!1,void 0,this):null,y?pe(vt,{width:La,fg:t.text,text:Sn(N)},void 0,!1,void 0,this):null,h?pe(vt,{width:Mr,fg:t.text,text:N?.pid?String(N.pid):""},void 0,!1,void 0,this):null]},R,!0,void 0,this)})]},void 0,!0,void 0,this)}function ic(e){let{palette:t,checked:r,idle:n,profileName:o}=e,i=r.length;if(i>0)return pe(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(n)return pe(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 pe(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 AP(e,t,r){if(t)return e.success;if(r)return e.primary;return e.muted}function vt(e){return pe("box",{width:e.width,flexShrink:0,overflow:"hidden",children:pe("text",{fg:e.fg,wrapMode:"none",children:e.text},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var Mu=T(()=>{Pe();ot();ve();ze()});import{useEffect as Ou,useRef as yx}from"react";import{jsxDEV as K,Fragment as $P}from"@opentui/react/jsx-dev-runtime";function vx(e){let{palette:t,logs:r,names:n,logSources:o,service:i,paused:s,errorOnly:a,showSystemLogs:c,search:l,searchFocused:d,followTick:g,width:f,onSearch:h,onService:y,onToggleErrors:b,onToggleSystemLogs:w,onClearLogs:R,onSelect:S,wrapMode:N="focus",selected:J=-1,follow:v=!0,newer:A=0,viewStart:m=0,viewTotal:_,onLeaveLatest:F,onOpenExports:Z,onJumpLatest:he,view:ke,fullscreen:Je=!1,facets:Ue}=e,ae=re(),Oe=Uh(f,ae.pad,Je),Ke=c?r:r.filter((_t)=>!Oi(_t.source)),de=yo(r,{service:i,services:e.services,errorOnly:a,search:l,regex:e.regex,source:e.source,systemLogs:c}),we=ke??de,Ce=_??de.length,W=Math.min(Ce,m+we.length),Ie=Ce===0?"empty":`${m+1}\u2013${W} of ${Ce}`,lt=e.services??[],$e=lt.length>0?lt.join(","):i===""?"all services":i;return K("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[Je?null:K($P,{children:[K(Be,{palette:t,items:[{text:s?"PAUSED":"LIVE",tone:s?"warning":"success"},{text:`shown ${Ce}`,tone:"info"},{text:Ue?`total ${Ue.total}`:`total ${r.length}`},...ke&&Ce>ke.length?[{text:`${m+1}\u2013${m+ke.length} / ${Ce}`,tone:"info"}]:[],{text:$e,tone:i===""?"idle":"primary"},{text:Ai(N),tone:N==="clip"?"idle":"accent"},...v?[]:[{text:A>0?`pinned \xB7 +${A} new`:"pinned",tone:"warning"}],{text:a?"ERROR+":"all levels",tone:a?"error":"idle",onMouseDown:b},{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:R},{text:"open folder",tone:"primary",onMouseDown:Z}]},void 0,!1,void 0,this),K(Fu,{palette:t,logs:Ke,names:o??n,service:i,errorOnly:a,width:f,onService:y,onToggleErrors:b,facets:Ue},void 0,!1,void 0,this)]},void 0,!0,void 0,this),d?K("box",{height:1,paddingLeft:1,backgroundColor:t.highlight,overflow:"hidden",children:K("input",{focused:!0,value:l,placeholder:"search messages or service names",onInput:h,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,ke&&Ce>we.length?K(Iu,{palette:t,start:m,count:we.length,total:Ce},void 0,!1,void 0,this):null,K("box",{flexGrow:1,border:!Je,borderStyle:"rounded",borderColor:t.border,title:Je?void 0:`logs ${$e} \xB7 ${Ie}`,titleColor:t.primary,padding:Je?0:ae.pad,overflow:"hidden",children:we.length===0?K(De,{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 1-9 pick a source e errors i internal ctrl+l clear"},void 0,!1,void 0,this):K(Nu,{palette:t,logs:we,width:Oe,followTick:g,focused:!1,wrapMode:N,selected:J,follow:v,showTimestamps:e.showTimestamps!==!1,showMeta:e.showMeta!==!1,onPick:S,onLeaveLatest:F,viewStart:m},g,!1,void 0,this)},void 0,!1,void 0,this),K(je,{palette:t,backgroundColor:t.element,edge:"top",children:K(Ee,{palette:t,hints:po([{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:A>0?`latest +${A}`:"latest"},{key:"w",label:"wrap"},{key:"p",label:"pause"},{key:"z",label:Je?"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,f-2))},void 0,!1,void 0,this)},void 0,!1,void 0,this),!v?K($u,{palette:t,width:f,newer:A,onJump:he},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function Iu(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 K(Be,{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)}function $u(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 K("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:K("text",{wrapMode:"none",children:[K("span",{fg:e.palette.primary,children:"g"},void 0,!1,void 0,this),K("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 Fu(e){let{palette:t,logs:r,names:n,service:o,errorOnly:i,width:s,onService:a,onToggleErrors:c,facets:l}=e,d=l?Ay(n,l):Ty(n,r),g=s<80,f=d.map((w,R)=>{let S=R+1,N=w.name===""?"all":w.name;return{id:N,label:g?`${S} ${N}`:`${S} ${N} \xB7 ${w.count}`,color:He(w.name,t)}}),h=Math.max(0,d.findIndex((w)=>w.name===o)),y=i?"ERROR+":g?"lvls":"all levels",b=Math.max(Lr(f[h]?.label??"1 all"),s-Lr(y));return K(je,{palette:t,backgroundColor:t.element,children:K("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[K("box",{flexGrow:1,overflow:"hidden",children:K(Xa,{palette:t,items:f,active:h,width:b,onPick:(w)=>{let R=d[w];if(R)a(R.name)}},void 0,!1,void 0,this)},void 0,!1,void 0,this),K(ue,{palette:t,label:y,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 Nu(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:g=!0,onPick:f,onLeaveLatest:h,viewStart:y=0}=e,b=yx(null),w=yx(""),R=n===void 0?r:r.slice(-n),S=[...new Set(r.map((v)=>v.service))],N=Xh(o,S),J=Yh({width:o,serviceWidth:N,showTimestamps:d,showMeta:g});return Ou(()=>{let v=b.current;if(!v)return;if(v.stickyScroll=l,l)v.stickyStart="bottom",v.scrollTo({x:v.scrollLeft,y:Math.max(0,v.scrollHeight)})},[l,i]),Ou(()=>{let v=`${y}:${c}:${a}`;if(w.current===v)return;if(w.current=v,l&&(c<0||c>=R.length-1))return;let A=b.current;if(!A||c<0)return;let m=`log-row-${c}`,_=requestAnimationFrame(()=>{A.stickyScroll=!1,A.scrollChildIntoView(m)});return()=>cancelAnimationFrame(_)},[l,c,R.length,y,a]),Ou(()=>{if(!l||!h)return;let v=!1,A=setTimeout(()=>{v=!0},LP),m=setInterval(()=>{let _=b.current;if(!v||!_)return;let F=_.viewport.height;if(F>0&&_.scrollTop+F<_.scrollHeight-MP)h()},DP);return()=>{clearTimeout(A),clearInterval(m)}},[l,i,h]),K("box",{flexGrow:1,height:"100%",overflow:"hidden",children:K("scrollbox",{ref:b,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:K("box",{flexDirection:"column",overflow:"hidden",children:R.map((v,A)=>K(OP,{id:`log-row-${A}`,palette:t,event:v,serviceWidth:N,msgWidth:J,expanded:qh(a,A===c),active:A===c,showTimestamps:d,showMeta:g,onPick:f?()=>f(A):void 0},`${v.timestamp}-${v.service}-${A}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function OP(e){let{id:t,palette:r,event:n,serviceWidth:o,msgWidth:i,expanded:s,active:a,showTimestamps:c=!0,showMeta:l=!0,onPick:d}=e,g=Kh(ja(n.message,i),i,s);return K("box",{id:t,flexShrink:0,flexDirection:"column",overflow:"hidden",backgroundColor:a?r.highlight:void 0,onMouseDown:d,children:g.visible.map((f,h)=>K("box",{height:1,flexDirection:"row",overflow:"hidden",children:[c?K("box",{width:Na,flexShrink:0,overflow:"hidden",children:K("text",{fg:r.muted,children:h===0?n.timestamp.slice(11,19):""},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,K("box",{width:o,flexShrink:0,overflow:"hidden",children:K("text",{fg:h===0?He(n.service,r):r.muted,wrapMode:"none",children:h===0?Y(n.service,o):""},void 0,!1,void 0,this)},void 0,!1,void 0,this),K("box",{width:Ti,flexShrink:0,overflow:"hidden",children:K("text",{children:" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),K("box",{width:Ha,flexShrink:0,overflow:"hidden",children:K("text",{fg:h===0?Re(r,n.level):r.muted,children:h===0?String(n.level):""},void 0,!1,void 0,this)},void 0,!1,void 0,this),l?K("box",{width:$a,flexShrink:0,overflow:"hidden",children:K("text",{fg:r.muted,children:h===0&&n.source?Y(n.source,$a):""},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,K("box",{width:Ti,flexShrink:0,overflow:"hidden",children:K("text",{fg:r.muted,children:h===0?" ":"\u2502"},void 0,!1,void 0,this)},void 0,!1,void 0,this),K("box",{flexGrow:1,overflow:"hidden",children:K(IP,{palette:r,level:n.level,text:f,mark:h===0?g.mark:""},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},`${n.timestamp}-${h}`,!0,void 0,this))},void 0,!1,void 0,this)}function IP(e){let{palette:t,level:r,text:n,mark:o}=e;return K("text",{wrapMode:"none",children:[Jh(n).map((i,s)=>K("span",{fg:xh(t,r,i.kind),children:i.text},`${i.kind}-${s}`,!1,void 0,this)),o===""?null:K("span",{fg:t.muted,children:o},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var LP=400,DP=200,MP=2;var Hu=T(()=>{kt();ot();Pe();ve();ze()});import{jsxDEV as le}from"@opentui/react/jsx-dev-runtime";function bx(e){let{palette:t,cfg:r,snap:n,logs:o,names:i,selected:s,selectedLog:a=-1,checked:c,profile:l,google:d,width:g,paused:f,followTick:h,logService:y,logSources:b,errorOnly:w,showSystemLogs:R,onOpen:S,onSelectIndex:N,onToggle:J,onFilterService:v,onToggleErrors:A,onToggleSystemLogs:m,onClearLogs:_,onShowErrors:F,wrapMode:Z="clip",view:he,follow:ke=!0,onLeaveLatest:Je,onPickLog:Ue,viewStart:ae=0,viewTotal:Oe,newer:Ke=0,onJumpLatest:de,facets:we}=e,Ce=re();if(!r||i.length===0)return le(De,{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 W=g<uo,Ie=ho(n),lt=Ua(n,i),$e=i.filter((Pn)=>n?.services[Pn]?.state==="FAILED").length,_t=n?.session_id?fs(n.session_id):void 0,dt=_t?mo(Date.now()-_t.getTime()):void 0,zt=Ry(o),ut=l||Wa(r),Xt=Yy(r,ut),pt=Ba(g,i,W),_n=Math.max(24,W?g-4:g-pt-4),fc=R?o:o.filter((Pn)=>!Oi(Pn.source)),C=yo(o,{service:y,errorOnly:w,systemLogs:R}),Qt=he??C,jr=Oe??C.length,Rn=Math.min(jr,ae+Qt.length),gc=jr===0?"empty":`${ae+1}\u2013${Rn} of ${jr}`,mc=y===""?"all services":y;return le("box",{flexGrow:1,flexDirection:W?"column":"row",overflow:"hidden",children:[le("box",{flexGrow:W?1:0,flexShrink:0,minWidth:W?void 0:pt,width:W?void 0:pt,border:!0,borderStyle:"rounded",borderColor:Ie?t.border:t.borderActive,backgroundColor:t.panel,title:"services",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[le(Be,{palette:t,items:[{text:vu(lt.running,i.length),tone:lt.running>0?"success":"idle"},...$e>0?[{text:`${$e} failed`,tone:"error"}]:[],...c.length>0?[{text:`${c.length} selected`,tone:"primary"}]:[],...dt!==void 0?[{text:`up ${dt}`,tone:"idle"}]:[],...zt>0?[{text:`${zt} errors`,tone:"error",onMouseDown:F}]:[]]},void 0,!1,void 0,this),le(ic,{palette:t,checked:c,idle:Ie,profileName:ut,members:Xt},void 0,!1,void 0,this),le("box",{flexGrow:1,paddingLeft:Ce.pad,paddingRight:Ce.pad,overflow:"hidden",children:le(oc,{palette:t,names:i,snap:n,selected:s,checked:c,width:Fa(pt,Ce.pad),onOpen:S,onSelectIndex:N,onToggle:J},void 0,!1,void 0,this)},void 0,!1,void 0,this),le(jP,{palette:t,names:i,snap:n,width:pt,onOpen:S},void 0,!1,void 0,this),le(BP,{palette:t,cfg:r,snap:n,google:d,width:pt},void 0,!1,void 0,this)]},void 0,!0,void 0,this),le("box",{position:"relative",flexGrow:2,minWidth:W?void 0:32,minHeight:W?8:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,backgroundColor:t.panel,title:`logs \xB7 ${gc}`,titleColor:t.primary,overflow:"hidden",flexDirection:"column",children:[le(Be,{palette:t,items:[{text:f?"PAUSED":"LIVE",tone:f?"warning":"success"},{text:`shown ${C.length}`,tone:"info"},{text:we?`total ${we.total}`:`total ${o.length}`},{text:mc,tone:y===""?"idle":"primary"},{text:w?"ERROR+":"all levels",tone:w?"error":"idle",onMouseDown:A},{text:R?"system: on":"system: off",tone:R?"accent":"idle",onMouseDown:m},{text:"clear",tone:"muted",onMouseDown:_}]},void 0,!1,void 0,this),le(Fu,{palette:t,logs:fc,names:b??i,service:y,errorOnly:w,width:_n,onService:v,onToggleErrors:A,facets:we},void 0,!1,void 0,this),jr>Qt.length?le(Iu,{palette:t,start:ae,count:Qt.length,total:jr},void 0,!1,void 0,this):null,C.length===0?le(De,{palette:t,title:Ie?"Waiting for logs":o.length===0?"No events yet":"No events in this filter",body:Ie?"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):le(Nu,{palette:t,logs:Qt,width:_n,followTick:h,focused:!1,wrapMode:Z,selected:a,follow:ke,onLeaveLatest:Je,onPick:Ue,viewStart:ae},h,!1,void 0,this),le(je,{palette:t,backgroundColor:t.element,edge:"top",children:le(Ee,{palette:t,hints:po([{key:"e",label:"errors"},{key:"i",label:R?"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,_n-2))},void 0,!1,void 0,this)},void 0,!1,void 0,this),!ke?le($u,{palette:t,width:_n,newer:Ke,bottom:1,onJump:de},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function NP(e){if(!e)return!1;return e.state===ln||e.health===Ae||e.state===pi||e.restarts>0||e.last_error!==""}function xx(e){if(e.state===ln)return 0;if(e.health===Ae)return 1;if(e.state===pi)return 2;return 3}function HP(e){if(e.last_error!=="")return e.last_error;if(e.restarts>0)return`restarted ${e.restarts}x, no error recorded`;return e.health===Ae?"failing health check":e.state.toLowerCase()}function jP(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)=>NP(d.rt)).sort((d,g)=>xx(d.rt)-xx(g.rt));if(s.length===0)return null;let a=s.slice(0,FP),c=s.length-a.length,l=Math.max(8,o-ju-4);return le("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:g})=>{let f=Ot(g);return le("box",{height:1,flexDirection:"row",overflow:"hidden",onMouseDown:()=>i(d),children:[le("box",{width:2,flexShrink:0,children:le("text",{fg:Re(t,f),children:Tt(f)},void 0,!1,void 0,this)},void 0,!1,void 0,this),le("box",{width:ju,flexShrink:0,overflow:"hidden",children:le("text",{fg:He(d,t),wrapMode:"none",children:Y(d,ju)},void 0,!1,void 0,this)},void 0,!1,void 0,this),le("box",{width:l,flexShrink:0,overflow:"hidden",children:le("text",{fg:t.muted,wrapMode:"none",children:ce(HP(g),l)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},d,!0,void 0,this)}),c>0?le("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 BP(e){let{palette:t,cfg:r,snap:n,google:o,width:i}=e,s=o?.userEmail,a=vo(r,n?.identity,o).project,c=n?.logs.total??0,l=zy(s,a,c,i);return le(je,{palette:t,backgroundColor:t.element,edge:"top",children:le("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:l.map((d,g)=>le(ue,{palette:t,label:d.label,tone:d.tone},`${d.label}-${g}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var FP=4,ju=14;var wx=T(()=>{Pe();ot();ve();kt();ze();dn();Ye();Mu();Hu()});import{useEffect as WP,useState as GP}from"react";import{jsxDEV as V}from"@opentui/react/jsx-dev-runtime";function kx(e){let{palette:t,report:r,loading:n,progress:o,error:i,selected:s,onPick:a,onReload:c}=e,l=xo(s,Bu);if(n)return V(UP,{palette:t,progress:o},void 0,!1,void 0,this);if(i)return V(ov,{palette:t,title:"Doctor failed",body:i},void 0,!1,void 0,this);if(!r)return V(De,{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((w)=>w.severity==="ok").length,g=r.checks.filter((w)=>w.severity==="warn").length,f=r.checks.filter((w)=>w.severity==="error").length,h=r.checks.length,y=Mi(h>0?d/h:0),b=f>0?t.error:g>0?t.warning:t.success;return V(et,{palette:t,title:`doctor ${r.issues} issue(s)`,children:[V("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:[V("text",{wrapMode:"none",children:[V("span",{fg:t.inverse,bg:t.primary,children:" r "},void 0,!1,void 0,this),V("span",{fg:t.primary,children:" RUN DOCTOR AGAIN"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),V("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),V("box",{height:1,flexShrink:0},void 0,!1,void 0,this),V("box",{height:1,flexShrink:0,overflow:"hidden",children:V("text",{wrapMode:"none",children:[V("span",{fg:b,children:`[${y}]`},void 0,!1,void 0,this),V("span",{fg:t.success,children:` ${d} ok`},void 0,!1,void 0,this),g>0?V("span",{fg:t.warning,children:` \xB7 ${g} warn`},void 0,!1,void 0,this):null,f>0?V("span",{fg:t.error,children:` \xB7 ${f} error`},void 0,!1,void 0,this):null,g===0&&f===0?V("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),V("box",{height:1,flexShrink:0},void 0,!1,void 0,this),V("scrollbox",{ref:l,focused:!1,stickyScroll:!1,scrollX:!1,style:Le(t),children:V("box",{flexDirection:"column",overflow:"hidden",gap:1,children:r.checks.map((w,R)=>V(KP,{palette:t,check:w,index:R,active:R===s,onPick:a},`${w.name}-${R}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function UP({palette:e,progress:t}){let[r,n]=GP(0);return WP(()=>{let o=setInterval(()=>n((i)=>(i+1)%Sx.length),120);return()=>clearInterval(o)},[]),V("box",{flexGrow:1,alignItems:"center",justifyContent:"center",overflow:"hidden",children:V("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:[V("text",{wrapMode:"none",children:[V("span",{fg:e.primary,children:`${Sx[r]} `},void 0,!1,void 0,this),V("span",{fg:e.text,children:"devctl doctor"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),V("box",{height:1,flexShrink:0},void 0,!1,void 0,this),V("text",{fg:e.text,wrapMode:"none",children:`Checking ${t.active}`},void 0,!1,void 0,this),V("box",{height:1,flexShrink:0},void 0,!1,void 0,this),t.checks.slice(-4).map((o,i)=>V("text",{wrapMode:"none",children:[V("span",{fg:Re(e,o.severity==="error"?"ERROR":o.severity==="warn"?"WARN":"OK"),children:`${Tt(o.severity==="error"?"ERROR":o.severity==="warn"?"WARN":"OK")} `},void 0,!1,void 0,this),V("span",{fg:e.muted,children:o.name},void 0,!1,void 0,this)]},`${o.name}-${i}`,!0,void 0,this)),t.checks.length===0?V("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 KP(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 V("box",{id:`${Bu}-${n}`,flexDirection:"row",flexShrink:0,paddingLeft:1,overflow:"hidden",backgroundColor:o?t.highlight:void 0,onMouseDown:()=>i(n),children:V("text",{wrapMode:"none",children:[V("span",{fg:t.primary,children:o?"\u203A ":" "},void 0,!1,void 0,this),V("span",{fg:Re(t,s),children:Tt(s)},void 0,!1,void 0,this),V("span",{fg:o?t.primary:t.text,children:` ${r.name}`},void 0,!1,void 0,this),V("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 V("box",{id:`${Bu}-${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:[V("text",{wrapMode:"word",children:[V("span",{fg:Re(t,s),children:`${Tt(s)} `},void 0,!1,void 0,this),V("span",{fg:t.text,children:r.message},void 0,!1,void 0,this)]},void 0,!0,void 0,this),r.hint?V("text",{fg:t.info,wrapMode:"word",children:`\u2192 ${r.hint}`},void 0,!1,void 0,this):null,o&&r.action?.kind==="free-port"?V("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 Bu="doctor-row",Sx;var Cx=T(()=>{kt();Pe();ve();ze();Sx=["\u25D0","\u25D3","\u25D1","\u25D2"]});import{jsxDEV as Se}from"@opentui/react/jsx-dev-runtime";function Rx(e){let{palette:t,cfg:r,snap:n,profile:o,selected:i,onPick:s}=e,a=re(),c=xo(i,_x),l=Object.keys(r?.profiles??{}).sort();if(l.length===0)return Se(De,{palette:t,title:"No profiles",body:"Add profiles.<name>.services in config.yaml."},void 0,!1,void 0,this);return Se(et,{palette:t,title:"profiles",children:[Se("box",{height:1,flexShrink:0,overflow:"hidden",children:Se("text",{fg:t.muted,wrapMode:"none",children:[`${l.length} profile${l.length===1?"":"s"} \xB7 current: `,Se("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),Se("box",{height:1,flexShrink:0},void 0,!1,void 0,this),Se("scrollbox",{ref:c,focused:!1,stickyScroll:!1,scrollX:!1,style:Le(t),children:Se("box",{flexDirection:"column",overflow:"hidden",gap:a.gap||1,children:l.map((d,g)=>{let f=d===o,h=g===i,y=r?.profiles[d]?.services??[],b=Object.keys(r?.profiles[d]?.environment??{}).length,w=h?t.borderActive:f?t.success:t.border,R=h?t.primary:f?t.success:t.muted;return Se("box",{id:`${_x}-${g}`,border:!0,borderStyle:"rounded",borderColor:w,title:d,titleColor:R,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",backgroundColor:h?t.highlight:void 0,onMouseDown:()=>s(g),children:[Se("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:Se("text",{wrapMode:"none",children:[f?Se("span",{fg:t.success,children:"\u25CF current profile"},void 0,!1,void 0,this):Se("span",{fg:t.muted,children:"\u25CB not active"},void 0,!1,void 0,this),Se("span",{fg:t.muted,children:` \xB7 ${y.length} service${y.length===1?"":"s"}`},void 0,!1,void 0,this),b>0?Se("span",{fg:t.muted,children:` \xB7 ${b} env var${b===1?"":"s"}`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Se("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:y.length===0?Se("text",{fg:t.muted,wrapMode:"none",children:"(no services)"},void 0,!1,void 0,this):Se("text",{wrapMode:"none",children:y.map((S,N)=>{let J=Ot(n?.services[S]);return Se("span",{children:[Se("span",{fg:Re(t,J),children:Tt(J)},void 0,!1,void 0,this),Se("span",{fg:He(S,t),children:` ${S}`},void 0,!1,void 0,this),N<y.length-1?Se("span",{fg:t.muted,children:" "},void 0,!1,void 0,this):null]},S,!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),Se(je,{palette:t,backgroundColor:t.element,edge:"top",children:Se(Ee,{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 _x="profile-row";var Px=T(()=>{kt();ot();Pe();ve();ze()});import{jsxDEV as j,Fragment as Lx}from"@opentui/react/jsx-dev-runtime";function qP(e){let t=e.toLowerCase();if(t==="iap")return"info";if(t==="service"||t==="service_account")return"primary";return"idle"}function VP(e,t,r){if(r||t>=500)return e.error;if(t===0||t>=400)return e.warning;return e.success}function JP(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 QP(e){let{palette:t,req:r,cols:n}=e,o=VP(t,r.status,r.error),i=r.status>0?String(r.status):"ERR",s=JP(t,r.identity),a=r.route||Dx,c=r.error?`${r.path} \u2014 ${ce(r.error,XP)}`:r.path;return j("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[j("box",{width:Wu,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.muted,children:r.timestamp.slice(11,19)},void 0,!1,void 0,this)},void 0,!1,void 0,this),n.showMethod?j("box",{width:sc,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.text,wrapMode:"none",children:Y(r.method,sc)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,j("box",{width:ac,flexShrink:0,overflow:"hidden",children:j("text",{fg:o,wrapMode:"none",children:Y(i,ac)},void 0,!1,void 0,this)},void 0,!1,void 0,this),n.showDur?j("box",{width:cc,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.muted,wrapMode:"none",children:Y(`${r.durationMs}ms`,cc)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,j("box",{width:lc,flexShrink:0,overflow:"hidden",children:j("text",{fg:s.color,wrapMode:"none",children:Y(s.label,lc)},void 0,!1,void 0,this)},void 0,!1,void 0,this),j("box",{width:n.routeCol,flexShrink:0,overflow:"hidden",children:j("text",{fg:r.route?t.info:t.muted,wrapMode:"none",children:Y(a,n.routeCol)},void 0,!1,void 0,this)},void 0,!1,void 0,this),j("box",{flexGrow:1,overflow:"hidden",children:j("text",{fg:r.error?t.error:t.text,wrapMode:"none",children:c},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function ZP(e){let{palette:t,cols:r}=e;return j("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:[j("box",{width:Wu,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.muted,children:Y("TIME",Wu)},void 0,!1,void 0,this)},void 0,!1,void 0,this),r.showMethod?j("box",{width:sc,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.muted,children:Y("METHOD",sc)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,j("box",{width:ac,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.muted,children:Y("ST",ac)},void 0,!1,void 0,this)},void 0,!1,void 0,this),r.showDur?j("box",{width:cc,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.muted,children:Y("DUR",cc)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,j("box",{width:lc,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.muted,children:Y("WHO",lc)},void 0,!1,void 0,this)},void 0,!1,void 0,this),j("box",{width:r.routeCol,flexShrink:0,overflow:"hidden",children:j("text",{fg:t.muted,children:Y("ROUTE",r.routeCol)},void 0,!1,void 0,this)},void 0,!1,void 0,this),j("box",{flexGrow:1,overflow:"hidden",children:j("text",{fg:t.muted,children:"PATH"},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function eE(e){let{palette:t,name:r,auth:n,identity:o,upstream:i,match:s,onMouseDown:a}=e;return j("box",{flexDirection:"column",flexShrink:0,overflow:"hidden",onMouseDown:a,children:[j("text",{fg:t.text,wrapMode:"none",children:r},void 0,!1,void 0,this),j("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[j(ue,{palette:t,label:n||"no auth",tone:qP(n)},void 0,!1,void 0,this),o?j(ue,{palette:t,label:o,tone:"idle"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),s?j("text",{fg:t.muted,wrapMode:"none",children:`match: ${s}`},void 0,!1,void 0,this):null,j("text",{fg:t.muted,wrapMode:"none",children:`\u2192 ${i}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Mx(e){let{palette:t,cfg:r,snap:n,width:o,onSelectRoute:i}=e,s=n?.proxy.routes??[],a=new Map((r?.proxy.routes??[]).map((v)=>[v.name,v])),c=new Map((r?.proxy.routes??[]).map((v)=>[v.name,v.match])),l=n?.proxy.recentRequests??[],d=n?.proxy.requestTotal??0,g=n?.proxy.requestErrors??0,f=o<uo,h=Math.max(Ex,Math.min(tE,Math.floor(o*0.36))),y=f?o-Tx:o-h-Tx,b=Math.max(20,y-2),w=b>=Ax,R=b>=rE,S=b>=Ax?nE:oE,N=l.reduce((v,A)=>Math.min(S,Math.max(v,(A.route||Dx).length+zP)),YP),J={showMethod:w,showDur:R,routeCol:N};return j(et,{palette:t,title:"proxy",children:[j(Be,{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"},...g>0?[{text:`${g} errors`,tone:"warning"}]:[]]:[]]},void 0,!1,void 0,this),j("box",{flexGrow:1,flexDirection:f?"column":"row",overflow:"hidden",children:[j("box",{flexGrow:f?1:0,flexBasis:f?0:void 0,flexShrink:0,minWidth:f?void 0:Ex,width:f?void 0:h,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?j(De,{palette:t,title:"No proxy routes",body:"Add routes under proxy.routes or .devctl/proxy/routes.yaml."},void 0,!1,void 0,this):j(Lx,{children:[i?j("text",{fg:t.muted,wrapMode:"word",children:"click a route for full details"},void 0,!1,void 0,this):null,j("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Le(t),children:j("box",{flexDirection:"column",overflow:"hidden",gap:1,children:s.map((v)=>{let A=c.get(v.name),m=A&&(A.host||A.path)?`${A.host||"*"}${A.path?A.path:""}`:void 0,_=a.get(v.name);return j(eE,{palette:t,name:v.name,auth:v.auth,identity:v.identity,upstream:v.upstream,match:m,onMouseDown:i?()=>i({name:v.name,authType:_?.auth.type||v.auth,identityType:_?.auth.identity.type??"",serviceAccount:_?.auth.identity.service_account||_?.auth.service_account||"",audience:_?.auth.audience??"",matchHost:_?.match.host??"",matchPath:_?.match.path??"",upstream:v.upstream}):void 0},v.name,!1,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),j("box",{flexGrow:1,flexBasis:0,minWidth: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?j("box",{paddingLeft:1,paddingRight:1,children:j("text",{fg:t.muted,wrapMode:"word",children:n?.proxy.running?"No requests seen yet. Send one through the proxy to see it show up here \u2014 no need to restart or press r.":"Start the proxy, then send it a request to see live traffic here."},void 0,!1,void 0,this)},void 0,!1,void 0,this):j(Lx,{children:[j(ZP,{palette:t,cols:J},void 0,!1,void 0,this),j("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Le(t),children:j("box",{flexDirection:"column",overflow:"hidden",children:l.map((v)=>j(QP,{palette:t,req:v,cols:J},v.requestId,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),j(je,{palette:t,backgroundColor:t.element,edge:"top",children:j(Ee,{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 Wu=9,sc=8,ac=4,cc=8,lc=4,YP=8,zP=2,XP=64,Dx="(none)",Ex=26,tE=42,Tx=2,Ax=46,rE=54,nE=20,oE=12;var Ox=T(()=>{kt();Pe();ve()});import{jsxDEV as te}from"@opentui/react/jsx-dev-runtime";function Fx(e){let{palette:t,name:r}=e;return te("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:r,titleColor:He(r,t),flexDirection:"column",overflow:"hidden",children:te(Gu,{...e,compact:!1},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Gu(e){let{palette:t,cfg:r,snap:n,name:o,reveal:i,width:s,compact:a=!0,envScrollRef:c}=e,l=re(),d=r?.services[o];if(!d)return te(De,{palette:t,title:"Unknown service",body:`No service named ${o}.`,hint:"j/k move"},void 0,!1,void 0,this);let g=n?.services[o],f=Ot(g),h=g?.health??"UNKNOWN",y=Sn(g)||Ni(d,g),b=qy(d,i,r?.secrets.extra_markers??[],r?.secrets.extra_patterns??[]),w=s>=sE,R=[{label:"health",value:Ja(d)},{label:"workdir",value:d.working_dir||"."},{label:"restart",value:za(d)},{label:"caps",value:d.capabilities.join(", ")||"\u2014"}],S=[{label:"identity",value:Ya(d,g)},{label:"depends",value:d.dependencies.join(", ")||"\u2014"},{label:"ports",value:Ni(d,g)},{label:"tries",value:String(g?.restarts??0),tone:g?.restarts?"warning":"muted"}],N=Math.max(Cn+8,s-2),J=w?Math.floor(N/2):N;return te("box",{padding:l.pad,flexGrow:1,flexDirection:"column",overflow:"hidden",children:[te(Be,{palette:t,items:[{text:f,tone:$x(f)},{text:h,tone:$x(h)},{text:g?.pid?`pid ${g.pid}`:"pid \u2014",tone:g?.pid?"info":"idle"},{text:y==="\u2014"?"port \u2014":`port ${y}`,tone:y==="\u2014"?"idle":"info"}]},void 0,!1,void 0,this),d.description?te("box",{height:1,overflow:"hidden",children:te("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,g?.last_error?te("box",{height:1,overflow:"hidden",children:te("text",{fg:t.error,wrapMode:"none",children:ce(g.last_error,iE)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,te(Uu,{palette:t,item:{label:"command",value:Va(d)},valueWidth:Math.max(8,N-Cn)},void 0,!1,void 0,this),te(aE,{palette:t,left:R,right:S,wide:w,colWidth:J},void 0,!1,void 0,this),te(cE,{palette:t,entries:b,reveal:i,width:s,focused:!a,scrollRef:c},void 0,!1,void 0,this),a?null:te(Ee,{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 aE(e){let{palette:t,left:r,right:n,wide:o,colWidth:i}=e,s=Math.max(4,i-Cn);if(!o)return te("box",{width:i,flexShrink:0,flexDirection:"column",overflow:"hidden",children:[...r,...n].map((a)=>te(Uu,{palette:t,item:a,valueWidth:s},a.label,!1,void 0,this))},void 0,!1,void 0,this);return te("box",{height:r.length,flexShrink:0,flexDirection:"row",overflow:"hidden",children:[te(Ix,{palette:t,items:r,width:i},void 0,!1,void 0,this),te(Ix,{palette:t,items:n,width:i},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function Ix(e){let t=Math.max(4,e.width-Cn);return te("box",{width:e.width,flexShrink:0,flexDirection:"column",overflow:"hidden",children:e.items.map((r)=>te(Uu,{palette:e.palette,item:r,valueWidth:t},r.label,!1,void 0,this))},void 0,!1,void 0,this)}function Uu(e){let{palette:t,item:r,valueWidth:n}=e,o=r.tone==="warning"?t.warning:r.tone==="muted"?t.muted:t.text;return te("box",{height:1,width:Cn+n,flexDirection:"row",overflow:"hidden",children:[te("box",{width:Cn,flexShrink:0,overflow:"hidden",children:te("text",{fg:t.muted,wrapMode:"none",children:Y(r.label,Cn)},void 0,!1,void 0,this)},void 0,!1,void 0,this),te("box",{width:n,flexShrink:0,overflow:"hidden",children:te("text",{fg:o,wrapMode:"none",children:Y(r.value,n)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function cE(e){let{palette:t,entries:r,reveal:n,width:o,focused:i,scrollRef:s}=e,a=Vy(o),c=Math.max(8,o-a-4);return te("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[te(Be,{palette:t,items:[{text:`env ${r.length}`,tone:r.length>0?"info":"idle"},{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),r.length===0?te("text",{fg:t.muted,children:"no service env overrides"},void 0,!1,void 0,this):te("box",{flexGrow:1,height:"100%",overflow:"hidden",children:te("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:te("box",{flexDirection:"column",overflow:"hidden",children:r.map((l)=>te("box",{height:1,flexDirection:"row",overflow:"hidden",children:[te("box",{width:a,flexShrink:0,overflow:"hidden",children:te("text",{fg:l.required?t.warning:t.muted,wrapMode:"none",children:Y(l.required?`${l.key}*`:l.key,a)},void 0,!1,void 0,this)},void 0,!1,void 0,this),te("box",{width:c,flexShrink:0,overflow:"hidden",children:te("text",{fg:l.value===""?t.muted:t.text,wrapMode:"none",children:Y(l.value===""&&l.required?"(required)":l.value,c)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},l.key,!0,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function $x(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 iE=72,sE=56,Cn=9;var Ku=T(()=>{Pe();kt();ot();ve();ze()});import{jsxDEV as Nr}from"@opentui/react/jsx-dev-runtime";function Nx(e){let{palette:t,cfg:r,names:n,snap:o,selected:i,checked:s,width:a,reveal:c,onOpen:l,onSelectIndex:d,onToggle:g}=e;if(n.length===0)return Nr(De,{palette:t,title:"No services",body:"This configuration does not define any services."},void 0,!1,void 0,this);let f=a<uo,h=n[i]??"",y=Ba(a,n,f),b=4,w=f?Math.max(qu,a-b):Math.max(qu,a-y-b);return Nr("box",{flexGrow:1,flexDirection:f?"column":"row",overflow:"hidden",children:[Nr("box",{flexGrow:f?1:0,flexShrink:0,minWidth:f?void 0:Ta,width:f?void 0:y,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:"services",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[Nr(ic,{palette:t,checked:s,idle:ho(o),profileName:"",members:""},void 0,!1,void 0,this),Nr("box",{flexGrow:1,overflow:"hidden",children:Nr(oc,{palette:t,names:n,snap:o,selected:i,checked:s,width:Fa(y),onOpen:l,onSelectIndex:d,onToggle:g},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Nr("box",{flexGrow:2,minWidth:f?void 0:qu,minHeight:f?lE:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,backgroundColor:t.panel,title:h||"detail",titleColor:h?He(h,t):t.primary,overflow:"hidden",flexDirection:"column",children:Nr(Gu,{palette:t,cfg:r,snap:o,name:h,reveal:c,width:w},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var qu=36,lE=12;var Hx=T(()=>{kt();Pe();ze();Ku();Mu()});import{jsxDEV as fe}from"@opentui/react/jsx-dev-runtime";function uE(e){switch(e){case"cycle":return"\u2194";case"toggle":return"\u23FB";case"page":return"\u25B8";case"action":return"!";default:return"\xB7"}}function Gx(e){let{palette:t,items:r,selected:n,locked:o,width:i,onPick:s,onActivate:a}=e,c=re(),l=eu(r,n),d=lo(r,l);return fe("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:"settings",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[fe("box",{height:2,paddingLeft:c.pad,flexShrink:0,flexDirection:"column",overflow:"hidden",children:[fe("text",{fg:t.primary,wrapMode:"none",children:"Preferences"},void 0,!1,void 0,this),fe("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),fe("box",{flexGrow:1,paddingLeft:c.pad,paddingRight:c.pad,overflow:"hidden",flexShrink:1,children:fe(pE,{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),fe(gE,{palette:t,item:d,scale:c},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function pE(e){let{palette:t,items:r,active:n,scale:o,width:i,onPick:s,onActivate:a}=e,c=xo(n,Wx),l=Math.max(8,i-jx-Bx-10),d=0,g=Ph(r);return fe("scrollbox",{ref:c,focused:!1,stickyScroll:!1,scrollX:!1,style:Le(t),children:fe("box",{flexDirection:"column",overflow:"hidden",children:g.map((f,h)=>{let y=d;d+=f.items.length;let b=n>=y&&n<y+f.items.length;return fe("box",{border:!0,borderStyle:"rounded",borderColor:b?t.borderActive:t.border,title:`${f.group} (${f.items.length})`,titleColor:b?t.primary:t.muted,flexDirection:"column",flexShrink:0,marginBottom:h<g.length-1?Math.max(1,o.gap):0,paddingLeft:1,paddingRight:1,overflow:"hidden",children:[f.group==="MCP"?fe("box",{height:1,overflow:"hidden",children:fe("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((w,R)=>{let S=y+R;return fe(fE,{index:S,palette:t,item:w,active:S===n,rowH:o.rowH,valueWidth:l,onPick:()=>s(S),onActivate:()=>a(w)},w.id,!1,void 0,this)})]},f.group,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function fE(e){let{palette:t,index:r,item:n,active:o,rowH:i,valueWidth:s,onPick:a,onActivate:c}=e;return fe("box",{id:`${Wx}-${r}`,height:i,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:o?t.highlight:void 0,onMouseDown:()=>{if(o){c();return}a()},children:[fe("box",{width:2,flexShrink:0,overflow:"hidden",children:fe("text",{fg:t.primary,children:o?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{width:Bx,flexShrink:0,overflow:"hidden",children:fe("text",{fg:o?t.primary:t.muted,children:uE(n.kind)},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{width:jx,flexShrink:0,overflow:"hidden",children:fe("text",{fg:o?t.primary:t.text,wrapMode:"none",children:n.name},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{flexGrow:1,overflow:"hidden",children:fe("text",{fg:mE(t,n,o),wrapMode:"none",children:ce(n.value,s)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function gE(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 fe("box",{height:dE,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:[fe("box",{height:1,overflow:"hidden",children:fe("text",{fg:t.primary,wrapMode:"none",children:o?`${_h(n.steps)} ${n.label}`:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{height:1,overflow:"hidden",children:fe("text",{fg:t.text,wrapMode:"word",children:r?.detail??""},void 0,!1,void 0,this)},void 0,!1,void 0,this),fe("box",{height:1,overflow:"hidden",children:fe("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 mE(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 jx=14,Bx=2,dE=5,Wx="settings-row";var Ux=T(()=>{ot();Pe();ve();pr()});import{useEffect as hE,useState as yE}from"react";import{jsxDEV as U}from"@opentui/react/jsx-dev-runtime";function So(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 U("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 Vu(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 ji(e){let{palette:t,cells:r,header:n,gap:o=0,stripe:i}=e;return U("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:i?t.element:void 0,children:r.map((s,a)=>U("box",{flexDirection:"row",flexShrink:0,overflow:"hidden",children:[a>0&&o>0?U("box",{width:o,flexShrink:0},void 0,!1,void 0,this):null,U("box",{width:s.width,flexShrink:0,overflow:"hidden",children:U("text",{fg:n?t.primary:Vu(t,s),wrapMode:"none",children:Y(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 Kx(e){let{palette:t,width:r}=e;return U("box",{height:1,flexShrink:0,overflow:"hidden",children:U("text",{fg:t.border,wrapMode:"none",children:Y("\u2500".repeat(Math.max(1,r)),r)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Hi(e){let{palette:t,facts:r,width:n}=e,o=yu(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}),U("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[U(ji,{palette:t,header:!0,gap:go,cells:i},void 0,!1,void 0,this),U(Kx,{palette:t,width:n},void 0,!1,void 0,this),r.map((s,a)=>{let c=s.meaning===""?[""]:ja(s.meaning,Math.max(1,o.meaning)),l=s.meter?dy(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"}),U("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[U(ji,{palette:t,gap:go,stripe:a%2===1,cells:d},void 0,!1,void 0,this),c.slice(1).map((g,f)=>{let h=[{text:"",width:o.what},{text:"",width:o.reading}];if(o.meter>0)h.push({text:"",width:o.meter});return h.push({text:g,width:o.meaning,tone:"muted"}),U(ji,{palette:t,gap:go,stripe:a%2===1,cells:h},`${s.what}-more-${f}`,!1,void 0,this)})]},`${s.what}-${s.reading}-${a}`,!0,void 0,this)})]},void 0,!0,void 0,this)}function qx(e){let{palette:t,cfg:r,snap:n,width:o,onRefresh:i}=e,s=re(),[,a]=yE(0);if(hE(()=>{let Ke=setInterval(()=>{a((de)=>{let we=de+1;if(i&&we%xE===0)i();return we})},vE);return()=>clearInterval(Ke)},[i]),!r)return U(De,{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((Ke)=>uy(r.services[Ke])),d=ny(c,n),g=vy(d,l),f=l&&d.live>0?d.healthy/d.live:d.total>0?d.live/d.total:0,h=Mi(f,bE),y=d.failed>0?"error":l&&d.live>0&&d.healthy<d.live?"warning":"success",b=ay(o,s.pad),w=n?.session_id?fs(n.session_id):void 0,R=w?mo(Date.now()-w.getTime()):"just started",S=n?.logs.total??0,N=n?.logs.errors??0,J=sy(n?.logs.counts??{}),v=n?.proxy.routes??[],A=n?.credentials,m=(A?.entries??[]).filter((Ke)=>Ke.valid).length,_=n?.system,F=_?_.memAvailableKB??_.memFreeKB:0,Z=_?fy(_.loadAvg1,_.cpuCount):void 0,he=_?gy(F,_.memTotalKB):void 0,ke=[];if(_&&Z&&he)ke.push(Z,he,{what:"Computer",reading:py(_.platform),meaning:`on for ${mo(_.hostUptimeSec*wE)}`,tone:"text"});let Je=d.failed>0||Z?.tone==="error"||he?.tone==="error"?"error":y==="warning"||Z?.tone==="warning"||he?.tone==="warning"?"warning":"success",Ue=[{what:"This session",reading:R,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"}],ae=[{what:"Lines kept",reading:String(S),meaning:"log lines still in memory",tone:"text"},{what:"Error lines",reading:String(N),meaning:N>0?"open Logs and press e to see only errors":"no ERROR or FATAL lines",tone:N>0?"error":"muted"},...J.map(([Ke,de])=>({what:Ke,reading:String(de),meaning:"lines from this service",tone:"text"}))],Oe=[{what:"Web proxy",reading:n?.proxy.running?"on":"off",meaning:n?.proxy.running?`${v.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:A?`${m} of ${A.entries.length} good`:"none",meaning:A?yy(A.backend):"nothing stored yet",tone:A&&m<A.entries.length?"warning":A?"success":"muted"}];return U(et,{palette:t,title:"stats",scroll:!0,children:[U(So,{palette:t,title:`Your services ${d.live} of ${d.total} started`,tone:Je,children:[U(Hi,{palette:t,facts:g,width:b},void 0,!1,void 0,this),U("box",{height:1,flexShrink:0},void 0,!1,void 0,this),U("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:U("text",{wrapMode:"none",children:[U("span",{fg:t.muted,children:Y(l?"Ready":"Started",yu(g,b).what)},void 0,!1,void 0,this),U("span",{children:" ".repeat(go)},void 0,!1,void 0,this),U("span",{fg:Vu(t,{text:"",width:1,tone:y}),children:`[${h}]`},void 0,!1,void 0,this),U("span",{fg:Vu(t,{text:"",width:1,tone:y}),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),_?U(So,{palette:t,title:"This computer",tone:Z?.tone==="error"||he?.tone==="error"?"error":Z?.tone==="warning"||he?.tone==="warning"?"warning":"success",children:U(Hi,{palette:t,facts:ke,width:b},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,U(So,{palette:t,title:"This session",children:U(Hi,{palette:t,facts:Ue,width:b},void 0,!1,void 0,this)},void 0,!1,void 0,this),U(So,{palette:t,title:"Each service",tone:d.failed>0?"error":l&&d.live>0&&d.healthy<d.live?"warning":"success",children:d.total===0?U("text",{fg:t.muted,children:"No services in this project yet."},void 0,!1,void 0,this):U("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[U(SE,{palette:t,names:c,snap:n,width:b},void 0,!1,void 0,this),U("box",{height:1,flexShrink:0},void 0,!1,void 0,this),U("text",{fg:t.muted,wrapMode:"none",children:Y("CPU is % of one core. RAM is what that process is holding now.",b)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),U(So,{palette:t,title:"Log lines",tone:N>0?"warning":"muted",children:U(Hi,{palette:t,facts:ae,width:b},void 0,!1,void 0,this)},void 0,!1,void 0,this),U(So,{palette:t,title:"Other parts",children:U(Hi,{palette:t,facts:Oe,width:b},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function SE(e){let{palette:t,names:r,snap:n,width:o}=e,i=cy(o),s=[{text:"service",width:i.name},{text:"status",width:Jt}];if(i.health)s.push({text:"check",width:fr});if(i.cpu)s.push({text:"cpu",width:Ma});if(i.mem)s.push({text:"ram",width:Oa});if(i.up)s.push({text:"up",width:Da});if(i.rst)s.push({text:"restarts",width:Ka});if(i.pid)s.push({text:"pid",width:Mr});return U("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[U(ji,{palette:t,header:!0,gap:yt,cells:s},void 0,!1,void 0,this),U(Kx,{palette:t,width:o},void 0,!1,void 0,this),r.map((a,c)=>U(RE,{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 _E(e){if(e===void 0)return"muted";if(e>CE)return"error";if(e>kE)return"warning";return"text"}function RE(e){let{palette:t,name:r,rt:n,cols:o,stripe:i}=e,s=my(n),a=hy(n),c=n?.restarts??0,l=[{text:r,width:o.name,color:He(r,t)},{text:s,width:Jt,color:Re(t,n?.state??"STOPPED")}];if(o.health)l.push({text:a,width:fr,color:Re(t,n?.health??"UNKNOWN")});if(o.cpu)l.push({text:n?.cpuPercent!==void 0?xy(n.cpuPercent):"\u2014",width:Ma,tone:_E(n?.cpuPercent)});if(o.mem)l.push({text:n?.memoryKB!==void 0?Aa(n.memoryKB):"\u2014",width:Oa,tone:"text"});if(o.up)l.push({text:iy(n),width:Da,tone:"text"});if(o.rst)l.push({text:String(c),width:Ka,tone:c>0?"warning":"muted"});if(o.pid)l.push({text:n?.pid?String(n.pid):"\u2014",width:Mr,tone:"muted"});return U("box",{flexDirection:"column",flexShrink:0,overflow:"hidden",children:[U(ji,{palette:t,gap:yt,stripe:i,cells:l},void 0,!1,void 0,this),n?.last_error?U("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:U("text",{fg:t.error,wrapMode:"none",children:Y(` ${n.last_error}`,Math.max(24,o.name+yt+Jt+fr))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var vE=1000,xE=5,bE=16,wE=1000,kE=80,CE=100;var Vx=T(()=>{kt();Pe();ot();ve();ze();Ye()});import{jsxDEV as me}from"@opentui/react/jsx-dev-runtime";function Jx(e){let{palette:t,cfg:r,google:n,bootError:o,bootErrorMissing:i=!1,step:s=0}=e,a=re();if(o&&!r)return i?me(De,{palette:t,title:"No configuration found",body:"Would you like to run setup?",hint:"[Enter] Setup [Esc] Exit"},void 0,!1,void 0,this):me(De,{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=r?Ut(r):["configuration not loaded"],l=PE(r,n,c),d=l.filter((S)=>S.ok).length,g=l.length,f=g>0?Math.round(d/g*100):0,h=20,y=Math.round(f/100*h),b="\u2588".repeat(y)+"\u2591".repeat(Math.max(0,h-y)),w=f===100?t.success:f===0?t.muted:t.primary,R=l[s];return me(et,{palette:t,title:"setup",scroll:!0,children:[me("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:me("text",{fg:t.primary,children:"Developer onboarding"},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:me("text",{wrapMode:"none",children:[me("span",{fg:w,children:`[${b}]`},void 0,!1,void 0,this),me("span",{fg:t.text,children:` ${d}/${g} ready`},void 0,!1,void 0,this),me("span",{fg:t.muted,children:` (${f}%)`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),me("box",{height:1,flexShrink:0},void 0,!1,void 0,this),l.map((S,N)=>{let J=N===s;return me("box",{height:a.rowH,flexDirection:"row",overflow:"hidden",backgroundColor:J?t.highlight:void 0,paddingLeft:1,children:[me("box",{width:2,flexShrink:0,children:me("text",{fg:Re(t,S.ok?"OK":"WARN"),children:Tt(S.ok?"OK":"WARN")},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("box",{width:3,flexShrink:0,children:me("text",{fg:J?t.primary:t.muted,children:String(N+1).padStart(2," ")},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("box",{width:20,flexShrink:0,overflow:"hidden",children:me("text",{fg:J?t.primary:t.text,children:S.name},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("box",{flexGrow:1,overflow:"hidden",children:me("text",{fg:J?t.text:t.muted,wrapMode:"none",children:S.detail},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},S.name,!0,void 0,this)}),me("box",{height:1,flexShrink:0},void 0,!1,void 0,this),R?me("box",{border:!0,borderStyle:"rounded",borderColor:R.ok?t.success:t.warning,title:R.name,titleColor:R.ok?t.success:t.warning,flexDirection:"column",paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:me("text",{fg:R.ok?t.text:t.warning,wrapMode:"word",children:R.detail},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,me("box",{height:1,flexShrink:0},void 0,!1,void 0,this),me("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:me(ue,{palette:t,label:"never hard-coded",tone:"idle"},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("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),me(Ee,{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 PE(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=vo(e,void 0,t).project;return[{name:mr[0],ok:Boolean(e?.repoRoot),detail:e?.repoRoot||"unknown"},{name:mr[1],ok:Boolean(e?.project.name),detail:e?.project.name||"set project.name"},{name:mr[2],ok:Boolean(i),detail:i||"optional for local-only"},{name:mr[3],ok:t?.adcAvailable===!0,detail:t?.adcAvailable?"ADC available":"needed only for cloud identity / IAP"},{name:mr[4],ok:!0,detail:"read from configuration; never hard-coded"},{name:mr[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:mr[6],ok:n.length===0||Boolean(e),detail:`${n.length} fixed ports from configuration`},{name:mr[7],ok:Object.keys(e?.profiles??{}).length>0,detail:`${Object.keys(e?.profiles??{}).length} profile(s)`},{name:mr[8],ok:r.length===0,detail:r.length===0?"configuration is valid":r[0]??"invalid"}]}var mr;var Yx=T(()=>{St();kt();ot();ve();Pe();ze();mr=["Repository","Environment","Google project","Authentication","Service accounts","IAP","Ports","Profiles","Validation"]});import{jsxDEV as B}from"@opentui/react/jsx-dev-runtime";function Xu(){return Od.flatMap((e)=>ua.filter((t)=>t.category===e))}function uc(){return dc+Xu().length}function Qx(){return uc()+Xx}function pc(e){if(e<dc||e>=uc())return;return Xu()[e-dc]}function Qu(e){let t=e-uc();return t>=0&&t<Xx?t:void 0}function Zx(e){let{palette:t,snap:r,port:n,portDraft:o="",selected:i,onPick:s,onToggle:a,onCopy:c,onToggleTool:l}=e,d=re(),g=r?.mcp?.running===!0,f=r?.mcp?.port??n,h=r?.mcp?.address??ao(f),y=r?.mcp?.token??"",b=Si(h,y),w=r?.mcp?.disabled_tools??[],R=Xu(),S=R.filter((v)=>!Ar(v.name,w)).length,N=b[Qu(i)??-1],J=N??b[0];return B(et,{palette:t,title:"mcp settings",children:[B(Be,{palette:t,items:[{text:g?"RUNNING":"STOPPED",tone:g?"success":"idle"},{text:`127.0.0.1:${f}`,tone:"info"}]},void 0,!1,void 0,this),B("box",{flexGrow:1,overflow:"hidden",children:B("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Le(t),children:B("box",{flexDirection:"column",overflow:"hidden",children:[B(Ju,{palette:t,text:"Server"},void 0,!1,void 0,this),B(zx,{palette:t,active:i===Yu,rowH:d.rowH,label:"Listen",value:g?"[ ON ]":"[ OFF ]",valueTone:g?"success":"muted",hint:g?"space or enter stop":"space or enter start",onPick:()=>s(Yu),onActivate:a},void 0,!1,void 0,this),B(zx,{palette:t,active:i===zu,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(zu)},void 0,!1,void 0,this),B("box",{height:1,overflow:"hidden",children:B("text",{fg:t.muted,wrapMode:"none",children:g?"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),B(Ju,{palette:t,text:"Tools",extra:S===0?"all enabled":`${S} disabled`},void 0,!1,void 0,this),B("box",{height:1,overflow:"hidden",children:B("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),Od.map((v)=>{let A=R.filter((m)=>m.category===v);if(A.length===0)return null;return B("box",{flexDirection:"column",overflow:"hidden",children:[B("box",{height:1,marginTop:1,overflow:"hidden",children:B("text",{fg:t.muted,wrapMode:"none",children:EE[v]??v},void 0,!1,void 0,this)},void 0,!1,void 0,this),A.map((m)=>{let _=dc+R.indexOf(m);return B(DE,{palette:t,tool:m,enabled:Ar(m.name,w),active:i===_,rowH:d.rowH,onPick:()=>s(_),onToggle:()=>l(m)},m.name,!1,void 0,this)})]},v,!0,void 0,this)}),B(Ju,{palette:t,text:"Copy agent config",extra:"highlight a row, then enter or click Copy"},void 0,!1,void 0,this),b.map((v,A)=>{let m=uc()+A;return B(LE,{palette:t,snippet:v,active:i===m,rowH:d.rowH,onPick:()=>s(m),onCopy:()=>c(v)},v.kind,!1,void 0,this)}),B(ME,{palette:t,snippet:J,selected:Boolean(N),brand:J?Ca(J.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),B(je,{palette:t,backgroundColor:t.element,edge:"top",children:B(Ee,{palette:t,hints:AE(i,g)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function AE(e,t){if(e===Yu)return[{key:"space",label:t?"stop server":"start server"},{key:"j/k",label:"move"}];if(e===zu)return[{key:"\u2190\u2192",label:"change port"},{key:"0-9",label:"type port"},{key:"enter",label:"apply port"},{key:"j/k",label:"move"}];if(pc(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 Ju(e){let t=e.extra?` \xB7 ${e.extra}`:"";return B("box",{height:1,marginTop:1,overflow:"hidden",children:B("text",{wrapMode:"none",children:[B("span",{fg:e.palette.primary,children:e.text},void 0,!1,void 0,this),B("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 zx(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 B("box",{height:n,flexDirection:"row",overflow:"hidden",backgroundColor:r?t.highlight:t.panel,onMouseDown:()=>{if(r&&l){l();return}c()},children:[B("box",{width:2,flexShrink:0,overflow:"hidden",children:B("text",{fg:t.primary,children:r?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),B("box",{width:Zu,flexShrink:0,overflow:"hidden",children:B("text",{fg:r?t.primary:t.text,wrapMode:"none",children:o},void 0,!1,void 0,this)},void 0,!1,void 0,this),B("box",{width:TE,flexShrink:0,overflow:"hidden",children:B("text",{fg:d,wrapMode:"none",children:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),B("box",{flexGrow:1,overflow:"hidden",children:B("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 LE(e){let{palette:t,snippet:r,active:n,rowH:o,onPick:i,onCopy:s}=e,a=Ca(r.kind,t),c=vh(r.kind,t),l=r.language==="toml"?"Copy TOML":"Copy JSON";return B("box",{height:o,flexDirection:"row",overflow:"hidden",backgroundColor:n?t.highlight:t.panel,onMouseDown:i,children:[B("box",{width:2,flexShrink:0,overflow:"hidden",children:B("text",{fg:a,children:n?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),B("box",{width:Zu,flexShrink:0,overflow:"hidden",children:B("text",{fg:a,wrapMode:"none",children:r.title},void 0,!1,void 0,this)},void 0,!1,void 0,this),B("box",{flexGrow:1,overflow:"hidden",children:B("text",{fg:t.muted,wrapMode:"none",children:r.path},void 0,!1,void 0,this)},void 0,!1,void 0,this),B(ue,{palette:t,label:l,bg:a,fg:c,onMouseDown:()=>{i(),s()}},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function DE(e){let{palette:t,tool:r,enabled:n,active:o,rowH:i,onPick:s,onToggle:a}=e;return B("box",{height:i,flexDirection:"row",overflow:"hidden",backgroundColor:o?t.highlight:t.panel,onMouseDown:()=>{if(o){a();return}s()},children:[B("box",{width:2,flexShrink:0,overflow:"hidden",children:B("text",{fg:t.primary,children:o?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),B("box",{width:5,flexShrink:0,overflow:"hidden",children:B("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),B("box",{width:Zu+4,flexShrink:0,overflow:"hidden",children:B("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),B("box",{width:7,flexShrink:0,overflow:"hidden",children:B("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),B("box",{flexGrow:1,overflow:"hidden",children:B("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 ME(e){let{palette:t,snippet:r,selected:n,brand:o}=e;if(!r)return null;let i=r.hint?` \xB7 ${r.hint}`:"";return B("box",{marginTop:1,flexDirection:"column",overflow:"hidden",children:[B("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),B("text",{fg:t.text,children:r.text},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Yu=0,zu=1,dc=2,Xx=4,EE,Zu=14,TE=14;var eb=T(()=>{ot();ve();ze();yi();EE={inspect:"Inspect",logs:"Logs",diagnostics:"Diagnostics",control:"Control",setup:"Setup"}});import{readFileSync as OE,writeFileSync as IE}from"fs";import{useCallback as z,useEffect as Ct,useMemo as hr,useRef as tt,useState as O}from"react";import{RGBA as $E}from"@opentui/core";import{useKeyboard as FE,useTerminalDimensions as NE}from"@opentui/react";import{jsxDEV as oe,Fragment as WE}from"@opentui/react/jsx-dev-runtime";function tb({controller:e,tui:t,onQuit:r,bootError:n,bootErrorMissing:o=!1,terminalBackground:i}){let{width:s,height:a}=NE(),[c,l]=O(t.theme||e?.cfg.ui.theme||"devctl"),d=tt(c),[g,f]=O(t.mouse),h=tt(t.mouse),[y,b]=O(t.leader_timeout),w=tt(t.leader_timeout),[R,S]=O(()=>Ri(t.font_size)),N=tt(R),J=Sh(),v=hr(()=>{let p=yh(c);if(wa(c)!=="terminal"||!Yd(i))return p;let u=i??p.background;return{...p,background:u,panel:u,element:u,inverse:u}},[i,c]),A=wa(c)==="terminal"&&Yd(i)?$E.defaultBackground(i??void 0):v.background,[m,_]=O(e?"dashboard":"setup"),[F,Z]=O("none"),[he,ke]=O(""),[Je,Ue]=O(0),[ae,Oe]=O(0),[Ke,de]=O(0),[we,Ce]=O([]),[W,Ie]=O(),lt=hr(()=>Rh({themeName:c,fontSize:R,mouse:g,leaderMs:y,locked:J,configPath:J?t.path||tu():tu(),mcpRunning:W?.mcp?.running===!0}),[R,y,g,J,W?.mcp?.running,c,t.path]),[$e,_t]=O([]),[dt,zt]=O(!1),[ut,Xt]=O(!1),[pt,_n]=O(!0),[fc,C]=O(n??""),[Qt,jr]=O(),[Rn,gc]=O(),[mc,Pn]=O(!1),[pb,sp]=O(""),[hc,yc]=O(0),[fb,ap]=O({active:"Preparing diagnostics",checks:[]}),cp=tt(void 0),ko=tt(0),[gb,mb]=O({}),[lp,hb]=O(),[Xe,vc]=O(Wa(e?.cfg)),[En,yb]=O(""),[Co,vb]=O(!1),[yr,xb]=O(""),[Bi,xc]=O(!1),[dp,bb]=O(0),[Tn,up]=O(""),[Wi,wb]=O(""),[Wt,vr]=O(""),Br=jE,[pp,Sb]=O(t.log_timestamps!==!1),[fp,kb]=O(t.log_metadata!==!1),[gp,Cb]=O(()=>[...wy]),[Gi]=O(""),[Wr]=O(""),[xr,_b]=O(!1),[Ui,mp]=O(),[Rb,Pb]=O(),[_o,hp]=O("focus"),[xt,br]=O(!1),[Eb,Ro]=O(bn-1),[Po,Ki]=O(!1),[Zt,qi]=O(-1),[yp,Tb]=O(),[vp,xp]=O(""),[bp,bc]=O(!1),[wp,Sp]=O(!1),kp=tt([]),Eo=tt(null),To=tt(null),Ao=tt(null),Lo=tt(null),wc=tt(null),Sc=tt(null),Cp=tt(null),[kc,Ab]=O(""),[Lb,Vi]=O(""),Cc=tt(""),_c=tt(!1),[_p,Do]=O(0),[Ji,Rc]=O(""),[Yi,Pc]=O(),[Db,Ec]=O([]),[Rp,er]=O(!1),[Pp,Tc]=O("start"),[Gr,wr]=O("quit"),[Sr,Mb]=O(()=>t.mcp_port??io(e?.cfg.repoRoot??process.cwd())),Mo=tt(void 0),Ac=tt(0),[D,Ob]=O(e?.cfg),[Oo,Ep]=O(void 0),Tp=t.keybinds.copy??lr(),it=hr(()=>Object.keys(D?.services??{}).sort(),[D]),Io=hr(()=>Ii(it,$e,gp),[it,$e,gp]),$o=hr(()=>gh(he),[he]),An=hr(()=>Wy(he),[he]);Ct(()=>{Cb((p)=>{let u=new Set(p),k=!1;for(let E of $e)if(E.service!==""&&!it.includes(E.service)&&!u.has(E.service))u.add(E.service),k=!0;return k?[...u].sort():p})},[$e,it]),Ct(()=>{Oe(0)},[he]),Ct(()=>{if(F==="palette")Ue(0)},[F,he]);let rt=hr(()=>yo($e,{service:Wt,services:Br,errorOnly:ut,search:yr,regex:xr,source:Wr,since:Tn,until:Wi,systemLogs:pt}),[ut,xr,yr,Wt,Br,Tn,Wr,Wi,$e,pt]),Fe=hr(()=>Vh(rt,xt,_p),[rt,xt,_p]),kr=Fe.items,tr=ty(m,{doctor:Rn?.checks.length??0,settings:lt.length,profiles:Object.keys(D?.profiles??{}).length,services:it.length,logs:kr.length,mcp:Qx()}),Ap=m==="logs"?Eb:Ke,Q=tr<=0?Math.max(0,Ap):Math.max(0,Math.min(Ap,tr-1));Ct(()=>{qi(-1),br(!1),Ro(Math.max(0,Math.min(bn,rt.length)-1))},[ut,yr,Wt,pt]),Ct(()=>{if(m!=="logs")Ki(!1)},[m]),Ct(()=>{if(m!=="logs"||xt)return;Ro(Math.max(0,Math.min(bn,rt.length)-1))},[rt.length,xt,m]),Ct(()=>{if(m==="settings")return;l(d.current),S(N.current),b(w.current),f(h.current)},[m]);let Lc=z(()=>{if(!xt)Do(mu(rt.length)),br(!0)},[rt.length,xt]),Fo=z((p)=>{let u=hu(p,tr,Fe.start,Fe.newer);if(u.startDelta!==0){Do(Math.max(0,Fe.start+u.startDelta)),br(!0),Ro(u.selected);return}let k=Math.max(tr-1,0),E=tr>0&&(u.selected<k||Fe.newer>0);if(E&&!xt)Do(mu(rt.length)),br(!0);else if(!E)br(!1);Ro(u.selected)},[rt.length,tr,xt,Fe.newer,Fe.start]),zi=z((p)=>{let u=kr.length,k=hu(p,u,Fe.start,Fe.newer);if(k.startDelta!==0)Do(Math.max(0,Fe.start+k.startDelta)),br(!0);qi(k.selected)},[kr.length,Fe.newer,Fe.start]),Dc=z(()=>{if(br(!1),qi(-1),m==="logs")Ro(Math.max(0,Math.min(bn,rt.length)-1));bb((p)=>p+1),C(Fe.newer>0?`Jumped to latest (+${Fe.newer} new)`:"Jumped to latest logs")},[rt.length,Fe.newer,m]),Qe=z(()=>{if(Z("none"),ke(""),xc(!1),Mo.current)clearTimeout(Mo.current)},[]),Mc=z((p)=>{Ce((u)=>u.includes(p)?u.filter((k)=>k!==p):[...u,p])},[]),qe=z((p,u)=>{if(J){C(`${u} session only`);return}let k=sh(p);C(`${u} saved ${k}`)},[J]),Ln=z((p)=>{l(p),d.current=p,qe({theme:p},`theme ${p}`)},[qe]),No=z(()=>{let p=!g;f(p),h.current=p,qe({mouse:p},`mouse ${p?"on":"off"} restart TUI to apply clicks`)},[g,qe]),Xi=z((p)=>{b(p),w.current=p,qe({leader_timeout:p},`leader ${p}ms`)},[qe]),Ur=z((p)=>{let u=Ri(p);S(u),N.current=u,qe({font_size:u},`display ${_a(u)}`)},[qe]),Lp=z(()=>{let p=Zd();l(p.theme),d.current=p.theme,f(p.mouse),h.current=p.mouse,b(p.leader_timeout),w.current=p.leader_timeout,S(p.font_size),N.current=p.font_size,qe(p,"restored default preferences")},[qe]),Oc=z((p)=>{if(p.id==="theme"){Ue(Math.max(0,ht.indexOf(c))),Z("themes");return}if(p.id==="mouse"){No();return}if(p.id==="leader"){Xi(y);return}if(p.id==="font"){Ur(R);return}if(p.id==="reset"){wr("reset-prefs"),Z("confirm");return}if(p.id==="mcp"){_("mcp"),de(0);return}C(p.detail)},[Ur,Xi,R,y,c,No]),Dp=z((p)=>{let u=lo(lt,Q);if(!u)return;if(u.id==="theme"){Ln(kh(c,p));return}if(u.id==="leader"){Xi(Ch(y,p));return}if(u.id==="font"){Ur(Ra(R,p));return}if(u.id==="mouse")No()},[Ur,Xi,R,y,Q,Ln,lt,c,No]),Ib=z(()=>{l(d.current)},[]),ge=z(async()=>{if(!e)return;try{let p=await e.status();if(Ie(p),p.profile&&Xe==="")vc(p.profile);return p}catch(p){C(H(p));return}},[e,Xe]),Qi=z(async()=>{if(!e){C("Supervisor is not running");return}C("Probing configured identities\u2026");try{let p=await e.refreshAuth();Ie((ee)=>ee?{...ee,identity:p}:ee);let u=Object.values(p.service_account_status),k=u.filter((ee)=>ee==="available").length,E=u.filter((ee)=>ee==="unavailable").length;C(u.length===0?"Identity refreshed \u2014 no service accounts configured":`Identity refreshed \u2014 ${k} available${E>0?`, ${E} unavailable`:""}`)}catch(p){C(H(p))}},[e]),Zi=z((p)=>{let u=mn(p);Mb(u);let k=D?.repoRoot??process.cwd();if(nh(k,u)){qe({mcp_port:null},`MCP port ${u} (default)`);return}qe({mcp_port:u},`MCP port ${u}`)},[D,qe]),Dn=z(()=>{if(Ji==="")return Sr;let p=rh(Ji,Sr);return Rc(""),Zi(p),p},[Sr,Ji,Zi]),Mp=z(async(p)=>{if(!e||W?.mcp?.running!==!0)return;await e.mcpStop(),await e.mcpStart({port:p}),await ge()},[e,ge,W?.mcp?.running]),Ic=z(async(p)=>{if(!e){C("Supervisor is not running");return}let u=W?.mcp?.disabled_tools??[],k=Ar(p.name,u),E=k?[...u,p.name]:u.filter((ee)=>ee!==p.name);try{let ee=await e.mcpSetTools(E);qe({mcp_disabled_tools:ee},`${p.label} ${k?"disabled":"enabled"}`),await ge()}catch(ee){C(H(ee))}},[e,qe,ge,W]),es=z(async()=>{if(!e){C("Supervisor is not running");return}try{if(W?.mcp?.running)await e.mcpStop(),qe({mcp_enabled:!1},"MCP off"),C("MCP stopped");else await e.mcpStart({port:Sr}),qe({mcp_enabled:!0},"MCP on"),C("MCP started");await ge()}catch(p){C(H(p))}},[e,Sr,qe,ge,W?.mcp?.running]),$c=z((p)=>{Su(p.text).then(()=>{C(`Copied ${p.title} snippet`)}).catch((u)=>{C(H(u))})},[]),ts=z((p)=>{let u=Qu(p);if(u===void 0)return!1;let k=W?.mcp?.address??ao(W?.mcp?.port??Sr),E=Si(k,W?.mcp?.token??"")[u];if(!E)return!1;return $c(E),!0},[$c,Sr,W?.mcp?.address,W?.mcp?.port,W?.mcp?.token]),Mn=hr(()=>({services:Wt!==""?[Wt]:Br,level:ut?"ERROR":Gi,search:yr,regex:xr,source:Wr,since:Tn,until:Wi}),[ut,Gi,xr,yr,Wt,Br,Tn,Wr,Wi]),rs=z(async()=>{if(!e)return;try{Tb(await e.logsStats(Mn))}catch(p){C(H(p))}},[e,Mn]),Op=z(async()=>{if(!e||dt)return;try{let p=await e.logsPage(Mn);_t((u)=>ky(u,p.events)),xp(p.prevCursor),bc(p.hasPrev),await rs()}catch(p){C(H(p))}},[e,Mn,dt,rs]),Ho=z(()=>{_t([]),up(new Date().toISOString()),br(!1),C("Cleared on-screen log buffer")},[]),jo=z(()=>{_n((p)=>!p)},[]);Ct(()=>{ge().then(()=>Op())},[ge,Op]),Ct(()=>{kp.current=$e},[$e]),Ct(()=>{if(!e||wp||!_y(xt,Fe.start,bp))return;Sp(!0),e.logsPage({...Mn,cursor:vp,direction:"backward"}).then((p)=>{if(p.sessionChanged){C("Daemon session changed \u2014 older log history is no longer available"),bc(!1);return}let u=kp.current,k=Cy(u,p.events);if(_t(k),k.length>u.length)Do((E)=>E+(k.length-u.length));xp(p.prevCursor),bc(p.hasPrev)}).catch((p)=>C(H(p))).finally(()=>Sp(!1))},[e,Mn,wp,bp,xt,vp,Fe.start]),Ct(()=>{if(!e||dt||m!=="logs")return;let p=setInterval(()=>{rs()},BE);return()=>clearInterval(p)},[e,dt,rs,m]),Ct(()=>{if(!e)return;let p,u=!1,k=[],E=D&&D.logs.max_memory_events>0?D.logs.max_memory_events:50000,ee=()=>{if(p=void 0,k.length>0){let x=k.splice(0,k.length);_t((ie)=>Sy(ie,x,Tn,E))}if(u)u=!1,ge()},Cr=e.onEvent((x)=>{if(x.type===js&&x.payload&&typeof x.payload==="object"&&"event"in x.payload){let ie=x.payload.event;if(!dt)k.push(ie);if(!p)p=setTimeout(ee,30);return}if(x.type===ai){Ep(Xy(x));return}if(x.type===Bs)Ep(void 0),e.configSnapshot().then(Ob).catch((ie)=>C(H(ie)));if(u=!0,!p)p=setTimeout(ee,30)});return()=>{if(Cr(),p)clearTimeout(p)}},[e,Tn,dt,ge]),Ct(()=>{Ht(D?.google.project_id??"").then(jr).catch((p)=>{C(H(p))})},[D?.google.project_id,W?.identity.project]),Ct(()=>{if(m!=="doctor"||!D)return;let p=cp.current,u=W?.session_id??"";if(p?.cfg===D&&p.tick===hc&&p.sessionID===u&&p.reloadError===Oo)return;cp.current={cfg:D,tick:hc,sessionID:u,reloadError:Oo};let k=++ko.current;Pn(!0),sp(""),ap({active:"Preparing diagnostics",checks:[]});let E;if(D.configPath!==""){E="";try{Xo(D.repoRoot,D.configPath)}catch(ee){E=H(ee)}}Tr(D,void 0,(ee)=>{if(k===ko.current)ap(ee)},{services:W?.services,proxyRunning:W?.proxy.running,repositoryConfigError:E}).then((ee)=>{if(k!==ko.current)return;gc(ee)}).catch((ee)=>{if(k!==ko.current)return;sp(H(ee))}).finally(()=>{if(k===ko.current)Pn(!1)})},[m,D,hc,W?.session_id,Oo]);let ns=z((p)=>{yb(p),_("detail")},[]),rr=z(async(p,u)=>{if(!e||!D){C("no configuration loaded");return}try{let k=Js(D,{services:p,profile:u}),E=fi(D,k.services,k.profile);Tc("start"),Ec(E.waves.flat().filter((x)=>Di(W?.services[x]))),Pc(E),Z("plan"),er(!0);let ee=k.services.filter((x)=>!Di(W?.services[x])),Cr=await e.start({services:ee.length>0?ee:k.services,profile:k.profile});await ge(),er(!1),C(Dy(Cr))}catch(k){er(!1),await ge(),C(H(k))}},[D,e,ge,W]),os=z(async(p)=>{if(!e||!D){C("no configuration loaded");return}let u=p.length>0?p:Object.entries(W?.services??{}).filter(([,k])=>k.state!=="STOPPED"&&k.state!=="UNKNOWN").map(([k])=>k);if(u.length===0){C("nothing to stop");return}try{let k=gi(D,u);Tc("stop"),Ec([]),Pc(k),Z("plan"),er(!0),await e.stop(p),await ge(),er(!1),C(My(k))}catch(k){er(!1),await ge(),C(H(k))}},[D,e,ge,W]),Bo=z(async(p,u)=>{if(!e||!D){C("no configuration loaded");return}try{let k=ey(D,p,u),E=fi(D,k.services,k.profile);Tc("restart"),Ec([]),Pc(E),Z("plan"),er(!0),await e.restart(p),await ge(),er(!1),C($i(E)===""?"Restarted selected services":`Restarted ${$i(E)}`)}catch(k){er(!1),await ge(),C(H(k))}},[D,e,ge]),is=z(async(p="")=>{let u=F==="log-details"&&Ui?Py(Ui):Ey(rt),k=p===""?"":` \xB7 ${p}`;if(u.trim()===""){C(`No logs to copy${k}`);return}try{await Su(u);let E=u.split(`
|
|
618
|
-
`).length,ee=
|
|
619
|
-
`)),C("Config buffer not saved");return}if(IE(D.configPath,p),Vi(""),Z("none"),!e){C(`Wrote ${D.configPath}`);return}e.reload().then((k)=>{if(C(k.restart_required.length===0?"Configuration saved and reloaded":`Saved; restart required: ${k.restart_required.join(", ")}`),k.restart_required.length>0)wr("reload"),Z("confirm");ge()})},[D,kc,e,ge]),nr=z(async(p,u)=>{if(_c.current)return;if(_c.current=!0,p.name!=="start"&&p.name!=="stop"&&p.name!=="restart")Z("none");ke("");let k=by(u,we);try{switch(p.name){case"exit":wr("quit"),Z("confirm");return;case"help":Z("help");return;case"version":C(Pt());return;case"themes":if(u[0]){Ln(u[0]);return}Ue(Math.max(0,ht.indexOf(c))),ke(""),Z("themes");return;case"settings":_("settings"),de(0);return;case"dashboard":case"services":_(p.name);return;case"logs":if(u[0])vr(u[0]);_("logs");return;case"fullscreen":_("logs"),Ki((E)=>m==="logs"?!E:!0);return;case"auth":if(u[0]?.toLowerCase()==="refresh"){_("auth"),await Qi();return}_("auth");return;case"credentials":case"proxy":case"mcp":case"config":case"profiles":case"setup":_(p.name);return;case"reload":if(!e)return;e.reload().then((E)=>{if(C(E.restart_required.length===0?"Configuration reloaded":`Reload requires restart: ${E.restart_required.join(", ")}`),E.restart_required.length>0)wr("reload"),Z("confirm");ge()});return;case"doctor":_("doctor");return;case"stats":_("stats");return;case"start":await rr(k,Xe);return;case"stop":await os(k);return;case"restart":await Bo(k,Xe);return;case"refresh":if(m==="auth"){await Qi();return}await ge(),C("Refreshed status and logs");return;case"pause":zt((E)=>!E),_("logs");return;case"filter":Xt((E)=>!E),_("logs");return;case"system":jo(),_("logs");return;case"clear":Ho();return;case"reveal":{let E=!Co;vb(E),C(E?"Secrets visible this session":"Secrets hidden");return}case"wrap":{let E=gu(_o);hp(E),C(`Log ${Ai(E)}`);return}case"copy":await is();return;case"export":{let E=to(u[0]);if(e)await e.logs({export:E,services:Br,level:ut?"ERROR":Gi,search:yr,regex:xr,source:Wr});else ra(E,rt);Cc.current=E,C(`Exported ${E}`);return}case"exports":{let E=Cc.current||Vr();na(E),C(`Opened ${Vr()}`);return}case"regex":_b((E)=>!E),C(xr?"Substring search":"Regex search");return;case"since":up(u[0]||new Date(Date.now()-3600000).toISOString()),C(`Logs since ${u[0]||"1h"}`);return;case"until":wb(u[0]||new Date().toISOString()),C(`Logs until ${u[0]||"now"}`);return;case"history":{let{listSessions:E,loadSessionEvents:ee}=await Promise.resolve().then(() => (fn(),mm)),Cr=E(),x=u[0]||Cr[0];if(!x){C("No persisted log sessions");return}_t(ee(x)),C(`Loaded session ${x}`);return}case"buffer":Fc();return;case"edit":{if(!D)return;let E=process.env.DEVCTL_EDITOR||process.env.EDITOR,ee=E?[E,D.configPath]:process.platform==="darwin"?["open",D.configPath]:["xdg-open",D.configPath];Bun.spawn({cmd:ee,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),C(`Opened ${D.configPath} in ${ee[0]}. Run /reload after saving.`);return}default:C(`/${p.name}`)}}catch(E){C(H(E))}finally{setTimeout(()=>{_c.current=!1},HE)}},[Bo,rr,os,we,D,Ho,e,is,ut,rt,Gi,xr,yr,Br,Wr,_o,Fc,Ln,Xe,ge,Qi,Co,m,c,jo]),Fb=z(()=>{let p=Cc.current||Vr();na(p),C(`Opened ${Vr()}`)},[]),Nc=z(()=>{let p=wn($o,ae);if(!p){C(he.trim()===""?"pick a command from the list":`unknown command /${he}`),Qe();return}let k=ki(he)?.name===p.name?mh(he):[];nr(p,k)},[Qe,$o,he,nr,ae]),Ip=z((p)=>{Ln(p),Qe()},[Qe,Ln]),Nb=z((p)=>{let u=ki(p);if(u)nr(u,[])},[nr]),$p=z(()=>{if(F==="palette"){let p=wn(An,Je);if(p)nr(p,[]);return}Nc()},[F,Je,An,nr,Nc]),Hb=z(()=>{if(D?.shutdown.stop_services_on_exit===void 0){wr("quit"),Z("confirm");return}r(D.shutdown.stop_services_on_exit===!1)},[D,r]),jb=z(()=>{if(Gr==="quit"){r(!1);return}if(Gr==="reload"){Qe();let p=W?.restart_required??[];if(p.length>0)Bo(p,Xe);return}if(Gr==="reset-prefs"){Qe(),Lp();return}if(Gr==="free-port"){let p=lp;if(Qe(),!p)return;Is(p).then(()=>{C(`Stopped ${p.command} (pid ${p.pid}) on port ${p.port}`),yc((u)=>u+1)}).catch((u)=>{C(H(u))});return}Qe(),rr([],Xe)},[Lp,Bo,rr,Qe,Gr,r,lp,Xe,W]),Bb=z(()=>{if(m==="logs"){let u=kr[Q];if(u)mp(u),Z("log-details");return}if(m==="profiles"){let k=Object.keys(D?.profiles??{}).sort()[Q];if(k)vc(k),wr("start-profile"),Z("confirm");return}if(m==="doctor"){let u=Rn?.checks[Q];if(u?.action?.kind==="free-port"){let k=u.action.holder;hb(k),mb({port:k.port,pid:k.pid,process:k.command}),wr("free-port"),Z("confirm")}return}if(m==="mcp"){if(Q===0){es();return}if(Q===1){Dn();return}let u=pc(Q);if(u){Ic(u);return}ts(Q);return}if(m==="settings"){let u=lo(lt,Q);if(u)Oc(u);return}if(m==="dashboard"&&ho(W)){rr([],Xe);return}let p=it[Q];if(p&&(m==="dashboard"||m==="services"))ns(p)},[Oc,Dn,rr,D,ts,Rn,Q,kr,it,ns,Xe,m,lt,W,es]);FE((p)=>{let u=(p.name??"").toLowerCase(),k=hv(p,t),E=mv(p,t);if(k&&!E){if(m==="mcp"&&ts(Q))return;is();return}if(E){let x=Date.now();if(yv(x,Ac.current)){Ac.current=0,Hb();return}Ac.current=x;let ie="Ctrl+C again to quit";if(k)is(ie);else C(`Press ${ie}`);return}if(p.ctrl&&(u==="="||u==="+"||u==="plus")){Ur(Ra(R,1));return}if(p.ctrl&&(u==="-"||u==="_"||u==="minus")){Ur(Ra(R,-1));return}if(p.ctrl&&u==="0"){Ur(Zd().font_size);return}if(F==="confirm"){if(u==="escape"){Qe();return}if(Gr==="quit"&&u==="d"){r(!0);return}if(u==="return")jb();return}if(F==="log-details"){if(u==="escape"){Qe();return}if(u==="down"||u==="j"){We(Lo.current,t.scroll_speed);return}if(u==="up"||u==="k"){We(Lo.current,-t.scroll_speed);return}if(ec(p)){We(Lo.current,Li(a));return}if(tc(p)){We(Lo.current,-Li(a));return}return}if(F==="route-details"){if(u==="escape"||u==="return"){Qe();return}if(u==="down"||u==="j"){We(wc.current,t.scroll_speed);return}if(u==="up"||u==="k"){We(wc.current,-t.scroll_speed);return}return}if(F==="plan"){if(u==="escape"||u==="return"&&!Rp){Qe();return}if(u==="down"||u==="j"){We(Sc.current,t.scroll_speed);return}if(u==="up"||u==="k"){We(Sc.current,-t.scroll_speed);return}return}if(F==="help"){if(u==="escape"){Qe();return}if(u==="down"||u==="j"){We(To.current,1);return}if(u==="up"||u==="k"){We(To.current,-1);return}if(u==="pagedown"||ec(p)){We(To.current,Au);return}if(u==="pageup"||tc(p)){We(To.current,-Au);return}return}if(F==="themes"){if(u==="escape"){Ib(),Qe();return}if(u==="down"||u==="j"){Ue((x)=>{let ie=Math.min(x+1,ht.length-1),or=ht[ie];if(or)l(or);return ie});return}if(u==="up"||u==="k"){Ue((x)=>{let ie=Math.max(0,x-1),or=ht[ie];if(or)l(or);return ie});return}if(u==="return"){let x=ht[Je%ht.length];if(x)Ip(x)}return}if(F==="leader"){if(Mo.current)clearTimeout(Mo.current);Z("none");let x=hh(u),ie=x?ki(x):void 0;if(ie)nr(ie,[]);return}if(F==="config-edit"){if(u==="escape"){Vi(""),Qe();return}if(p.ctrl&&u==="s"){$b();return}return}if(av(F)){if(u==="escape"){Qe();return}if(F==="slash"&&u==="down"){Oe((x)=>Math.min(Math.max($o.length-1,0),x+1));return}if(F==="slash"&&u==="up"){Oe((x)=>Math.max(0,x-1));return}if(F==="slash"&&u==="tab"){if(p.shift){Oe((ie)=>Math.max(0,ie-1));return}let x=wn($o,ae);if(x)ke(`${x.name} `);return}if(F==="slash"&&u==="return"){Nc();return}if(F==="palette"&&u==="down"){Ue((x)=>Math.min(x+1,Math.max(An.length-1,0)));return}if(F==="palette"&&u==="up"){Ue((x)=>Math.max(0,x-1));return}if(F==="palette"&&u==="return"){let x=wn(An,Je);if(x)nr(x,[])}return}if(Bi){if(u==="escape")xc(!1);return}if(cv(p,t)){Z("leader"),Mo.current=setTimeout(()=>Z("none"),y);return}if(lv(p,t)){ke(""),Ue(0),Z("palette");return}if(dv(p,t)){ke(""),Oe(0),Z("slash");return}if(uv(p,t)){Z("help");return}if(pv(p,t)||m==="logs"&&u==="f"&&!p.ctrl&&!p.meta){_("logs"),xc(!0);return}if(u==="escape"){if(Po){Ki(!1);return}if(m==="detail"){_("services");return}if(m==="setup")if(e)_("dashboard");else r(!0);return}if(u==="z"&&(m==="logs"||m==="dashboard")&&!p.ctrl&&!p.meta){_("logs"),Ki((x)=>m==="logs"?!x:!0);return}let ee=(m==="logs"||m==="dashboard")&&!Bi;if(ee&&(u==="left"||u==="["||m==="logs"&&u==="h")){vr(xu(Io,Wt,-1));return}if(ee&&(u==="right"||u==="]"||m==="logs"&&u==="l")){vr(xu(Io,Wt,1));return}if(m==="logs"&&!Bi&&u.length===1&&u>="1"&&u<="9"){let x=Ly(Io,$e,Number(u));if(x!==void 0)vr(x);return}if(u==="tab"){_(p.shift?jy(m):Hy(m));return}let Cr=ry(u);if(Cr){_(Cr);return}if((m==="dashboard"||m==="setup")&&u==="o"){_("profiles");return}if((m==="dashboard"||m==="services")&&(u==="*"||p.shift&&u==="8")){Ce([...it]),C(`Selected ${it.length} services`);return}if((m==="dashboard"||m==="services")&&(u==="-"||u==="_"||u==="minus")){Ce([]),C("Selection cleared");return}if((m==="dashboard"||m==="services")&&u==="n"){rr(qa(we,it[Q]??""),Xe);return}if((m==="dashboard"||m==="services")&&u==="x"){os(qa(we,it[Q]??""));return}if((m==="dashboard"||m==="services"||m==="detail")&&fv(p)){Bo(qa(we,it[Q]??En),Xe);return}if((m==="dashboard"||m==="services")&&u==="r"){ge(),C("Refreshed");return}if(m==="auth"&&u==="r"){Qi();return}if(m==="logs"&&u==="t"){let x=!pp;Sb(x),qe({log_timestamps:x},x?"timestamps on":"timestamps off");return}if(m==="logs"&&u==="m"){let x=!fp;kb(x),qe({log_metadata:x},x?"metadata on":"metadata off");return}if(u==="down"||u==="j"){if(m==="mcp"&&Q===1)Dn();if(m==="config"){We(Eo.current,t.scroll_speed);return}if(m==="detail"){We(Ao.current,t.scroll_speed);return}if(m==="logs"){Fo(Q+1);return}if(m==="dashboard"&&Zt>=0){zi(Zt+1);return}de((x)=>Math.min(Math.max(tr-1,0),x+1));return}if(u==="up"||u==="k"){if(m==="mcp"&&Q===1)Dn();if(m==="config"){We(Eo.current,-t.scroll_speed);return}if(m==="detail"){We(Ao.current,-t.scroll_speed);return}if(m==="logs"){Fo(Q-1);return}if(m==="dashboard"&&Zt>=0){zi(Zt-1);return}de((x)=>Math.max(0,Math.min(x,Math.max(tr-1,0))-1));return}if(ec(p)){let x=Li(a);if(m==="config"){We(Eo.current,x);return}if(m==="detail"){We(Ao.current,x);return}if(m==="logs"){Fo(Q+x);return}if(m==="dashboard"&&(xt||Zt>=0)){zi(Math.max(0,Zt)+x);return}de((ie)=>Math.min(Math.max(tr-1,0),ie+x));return}if(tc(p)){let x=Li(a);if(m==="config"){We(Eo.current,-x);return}if(m==="detail"){We(Ao.current,-x);return}if(m==="logs"){Fo(Q-x);return}if(m==="dashboard"&&(xt||Zt>=0)){zi(Math.max(0,Zt)-x);return}de((ie)=>Math.max(0,ie-x));return}if(m==="proxy"&&u==="n"){e?.proxyStart().then(async()=>{C("Proxy started"),await ge()});return}if(m==="proxy"&&u==="x"){e?.proxyStop().then(async()=>{C("Proxy stopped"),await ge()});return}if(m==="detail"&&En!==""){if(u==="n"){rr([En],Xe);return}if(u==="x"){os([En]);return}if(u==="o"){_("config");return}if(u==="l"){vr(En),_("logs");return}}if(m==="mcp"&&Q===1&&(u==="left"||u==="h")){let x=mn(Dn()-1);Zi(x),Mp(x);return}if(m==="mcp"&&Q===1&&(u==="right"||u==="l")){let x=mn(Dn()+1);Zi(x),Mp(x);return}if(m==="mcp"&&Q===1&&(u==="backspace"||u==="delete")){Rc((x)=>th(x));return}if(m==="mcp"&&Q===1&&u.length===1&&u>="0"&&u<="9"){Rc((x)=>eh(x,u));return}if(m==="settings"&&(u==="left"||u==="h")){Dp(-1);return}if(m==="settings"&&(u==="right"||u==="l")){Dp(1);return}if(u==="space"){if(m==="profiles"){let or=Object.keys(D?.profiles??{}).sort()[Q];if(or)vc(or),C(`Profile ${or}`);return}if(m==="mcp"){if(Q===0){es();return}let ie=pc(Q);if(ie){Ic(ie);return}ts(Q);return}if(m==="logs")return;if(m==="settings"){if(lo(lt,Q)?.id==="mouse")No();return}let x=it[Q];if(x)Mc(x);return}if(u==="return"){if(m==="setup"&&!e){if(!o){C(n||"Existing configuration is invalid \u2014 fix it and restart devctl.");return}Promise.resolve().then(() => (ud(),Zg)).then(({createStarterConfig:x})=>{try{let ie=x(process.cwd());C(`Wrote ${ie}. Restart devctl or run the CLI wizard.`)}catch(ie){C(H(ie))}});return}if(m==="setup"&&e){rr([],Xe);return}Bb();return}if(u==="q"){if(D?.shutdown.stop_services_on_exit===!1){r(!0);return}if(D?.shutdown.stop_services_on_exit===!0){r(!1);return}wr("quit"),Z("confirm");return}if(Or(p,t,"services","s")&&F==="none"&&m!=="logs"){_("services");return}if(Or(p,t,"logs","l")&&F==="none"&&m!=="detail"&&m!=="logs"&&m!=="settings"){_("logs");return}if(Or(p,t,"auth","a")&&F==="none"){_("auth");return}if(Or(p,t,"proxy","p")&&F==="none"&&m!=="logs"){_("proxy");return}if(Or(p,t,"doctor","d")&&F==="none"&&m!=="doctor"){_("doctor");return}if(Or(p,t,"config","c")&&F==="none"){_("config");return}if(Or(p,t,"setup","u")&&F==="none"){_("setup");return}if(m==="config"&&u==="e"){nr(ki("/edit")??{name:"edit",aliases:[],desc:"",leader:"",group:"ui"},[]);return}if(m==="config"&&u==="v"){Fc();return}if(m==="doctor"&&u==="r"){yc((x)=>x+1),C("Re-running doctor");return}if(m==="logs"&&u==="p"){zt((x)=>!x);return}if((m==="logs"||m==="dashboard")&&u==="g"){Dc();return}if((m==="logs"||m==="dashboard")&&u==="w"){let x=gu(_o);hp(x),C(`Log ${Ai(x)}`);return}if((m==="logs"||m==="dashboard")&&u==="e"){Xt((x)=>!x);return}if((m==="logs"||m==="dashboard")&&u==="i"){jo(),C(pt?"Hiding internal auth/mcp/devctl/proxy logs":"Showing internal logs");return}if((m==="logs"||m==="dashboard")&&gv(p))Ho()});let Fp=Jy(Gr,Xe,gb),Wb=new Set(Yi?.waves.flat()??[]),Gb=Yi===void 0||Pp==="stop"?"":Object.entries(W?.services??{}).find(([p,u])=>Wb.has(p)&&u.state==="FAILED")?.[0]??"";return oe(ru.Provider,{value:Pi(R),children:oe("box",{flexDirection:"column",width:s,height:a,backgroundColor:A,overflow:"hidden",children:[Po?null:oe(WE,{children:[oe(ev,{palette:v,cfg:D,snap:W,google:Qt,profile:Xe,reveal:Co,width:s},void 0,!1,void 0,this),oe(tv,{palette:v,screen:m,width:s,onSelect:_},void 0,!1,void 0,this),Oo?oe("box",{height:1,paddingLeft:1,backgroundColor:v.panel,overflow:"hidden",children:oe("text",{fg:v.error,wrapMode:"none",children:`\u26A0 configuration reload failed: ${Oo}`},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),oe("box",{flexGrow:1,overflow:"hidden",children:[m==="dashboard"?oe(bx,{palette:v,cfg:D,snap:W,logs:$e,names:it,selected:Q,checked:we,profile:Xe,google:Qt,width:s,paused:dt,followTick:dp,logService:Wt,errorOnly:ut,showSystemLogs:pt,onOpen:ns,onSelectIndex:de,selectedLog:Zt,onToggle:Mc,logSources:Io,onFilterService:vr,onToggleErrors:()=>Xt((p)=>!p),onToggleSystemLogs:jo,onClearLogs:Ho,onShowErrors:()=>{vr(""),Xt(!0)},wrapMode:_o,view:kr,follow:!xt,onLeaveLatest:Lc,onPickLog:(p)=>{let u=kr[p];if(!u)return;qi(p),mp(u),Lc()},viewStart:Fe.start,viewTotal:rt.length,newer:Fe.newer,onJumpLatest:Dc,facets:yp},void 0,!1,void 0,this):null,m==="services"?oe(Nx,{palette:v,cfg:D,names:it,snap:W,selected:Q,checked:we,width:s,reveal:Co,onOpen:ns,onSelectIndex:de,onToggle:Mc},void 0,!1,void 0,this):null,m==="detail"?oe(Fx,{palette:v,cfg:D,snap:W,name:En,reveal:Co,width:s,envScrollRef:Ao},void 0,!1,void 0,this):null,m==="logs"?oe(vx,{palette:v,logs:$e,names:it,logSources:Io,service:Wt,paused:dt,errorOnly:ut,showSystemLogs:pt,search:yr,searchFocused:Bi,followTick:dp,width:s,onSearch:xb,onService:vr,onToggleErrors:()=>Xt((p)=>!p),onToggleSystemLogs:jo,onClearLogs:Ho,source:Wr,regex:xr,services:Br,showTimestamps:pp,showMeta:fp,view:kr,wrapMode:_o,selected:Q,follow:!xt,newer:Fe.newer,viewStart:Fe.start,viewTotal:rt.length,onSelect:Fo,fullscreen:Po,onLeaveLatest:Lc,onOpenExports:Fb,onJumpLatest:Dc,facets:yp},void 0,!1,void 0,this):null,m==="auth"?oe(Yv,{palette:v,cfg:D,google:Qt,identity:W?.identity},void 0,!1,void 0,this):null,m==="credentials"?oe(Xv,{palette:v,credentials:W?.credentials},void 0,!1,void 0,this):null,m==="proxy"?oe(Mx,{palette:v,cfg:D,snap:W,width:s,onSelectRoute:(p)=>{Pb(p),Z("route-details")}},void 0,!1,void 0,this):null,m==="mcp"?oe(Zx,{palette:v,snap:W,port:Sr,portDraft:Ji,selected:Q,onPick:de,onToggle:()=>{es()},onCopy:$c,onToggleTool:(p)=>{Ic(p)}},void 0,!1,void 0,this):null,m==="doctor"?oe(kx,{palette:v,report:Rn,loading:mc,progress:fb,error:pb,selected:Q,onPick:de,onReload:()=>{yc((p)=>p+1),C("Re-running doctor")}},void 0,!1,void 0,this):null,m==="stats"?oe(qx,{palette:v,cfg:D,snap:W,width:s,onRefresh:ge},void 0,!1,void 0,this):null,m==="config"?oe(mx,{palette:v,cfg:D,width:s,scrollRef:Eo},void 0,!1,void 0,this):null,m==="profiles"?oe(Rx,{palette:v,cfg:D,snap:W,profile:Xe,selected:Q,onPick:de},void 0,!1,void 0,this):null,m==="setup"?oe(Jx,{palette:v,cfg:D,google:Qt,bootError:n,bootErrorMissing:o,step:Q},void 0,!1,void 0,this):null,m==="settings"?oe(Gx,{palette:v,items:lt,selected:Q,locked:J,width:s,onPick:de,onActivate:Oc},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),F==="slash"?oe(Wv,{palette:v,items:$o,query:he,selected:ae,onQuery:ke,onSubmit:$p},void 0,!1,void 0,this):null,F==="palette"?oe(Ov,{palette:v,items:An,selected:Math.min(Je,Math.max(An.length-1,0)),termW:s,termH:a,onIndex:Ue,onPick:Nb},void 0,!1,void 0,this):null,F==="themes"?oe(Vv,{palette:v,themeName:c,selected:Je%ht.length,termW:s,termH:a,onIndex:Ue,onPreview:l,onPick:Ip},void 0,!1,void 0,this):null,F==="help"?oe(Ev,{palette:v,termW:s,termH:a,copyKey:Tp,scrollRef:To},void 0,!1,void 0,this):null,F==="leader"?oe(Lv,{palette:v,termW:s,termH:a},void 0,!1,void 0,this):null,F==="confirm"?oe(wv,{palette:v,title:Fp.title,body:Fp.body,termW:s,termH:a},void 0,!1,void 0,this):null,F==="log-details"?oe(kv,{palette:v,event:Ui,termW:s,termH:a,scrollRef:Lo},void 0,!1,void 0,this):null,F==="route-details"?oe(Hv,{palette:v,route:Rb,termW:s,termH:a,scrollRef:wc},void 0,!1,void 0,this):null,F==="config-edit"&&D?oe(xv,{palette:v,path:D.configPath,initialValue:kc,error:Lb,termW:s,termH:a,textareaRef:Cp},void 0,!1,void 0,this):null,F==="plan"&&Yi?oe(Fv,{palette:v,plan:Yi,snap:W,busy:Rp,failed:Gb,kind:Pp,termW:s,termH:a,scrollRef:Sc,initiallyRunning:Db,onDismiss:Qe},void 0,!1,void 0,this):null,F==="slash"||F==="plan"||F==="config-edit"||Po||Qh(a)&&F==="none"?null:oe(rv,{palette:v,overlay:F,query:he,onQuery:ke,onSubmit:$p},void 0,!1,void 0,this),Po?null:oe(nv,{palette:v,screen:m,overlay:F,status:fc,paused:dt,errorOnly:ut,width:s,copyKey:Tp},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var HE=50,jE,BE=2000;var rb=T(()=>{St();ui();ii();nn();_e();fn();Ye();dn();ga();kt();sv();Pe();vv();ve();bv();Sv();Cv();Tv();Dv();Iv();Nv();jv();Gv();Jv();zv();Qv();hx();wx();Cx();Hu();Px();Ox();Ku();Hx();Ux();Vx();Yx();eb();yi();ot();pr();ze();Vt();jE=[]});var nb={};ss(nb,{renderApp:()=>tp,runTui:()=>ep,runTuiWithController:()=>KE,tuiConfigFor:()=>qE});import{createCliRenderer as GE}from"@opentui/core";import{createRoot as UE}from"@opentui/react";import{jsxDEV as VE}from"@opentui/react/jsx-dev-runtime";async function KE(e){let t=qt(e.cfg.repoRoot,e.cfg.ui.keymap);await tp(e,t)}async function ep(e){let t,r,n=!1;try{t=await pg("",e)}catch(i){r=H(i),n=ds(i,Kr)}let o=qt(t?.cfg.repoRoot??process.cwd(),t?.cfg.ui.keymap);await tp(t,o,r,n)}async function tp(e,t=qt(e?.cfg.repoRoot??process.cwd(),e?.cfg.ui.keymap),r,n=!1){as();let o=Bp(),i=await GE({exitOnCtrlC:!1,useMouse:t.mouse,enableMouseMovement:t.mouse,useKittyKeyboard:{}}),s=UE(i),a=null;try{a=(await i.getPalette({timeout:120,size:16})).defaultBackground}catch{}await new Promise((c)=>{let l=(d)=>{let g=()=>{s.unmount(),o(),i.destroy(),c(),process.exit(0)};if(!e){g();return}e.close({detach:d,shutdownSupervisor:!0}).finally(g)};s.render(VE(tb,{controller:e,tui:t,onQuit:l,bootError:r,bootErrorMissing:n,terminalBackground:a},void 0,!1,void 0,this))})}function qE(e){return qt(e.repoRoot,e.ui.keymap)}var rp=T(()=>{Dl();_e();rb();Hc();Vt()});On();Hc();St();Dl();Ye();ui();_e();nn();St();ci();dn();ud();import{Command as zE}from"commander";import{setTimeout as ip}from"timers/promises";import{stringify as XE}from"yaml";import{existsSync as cb,readFileSync as QE}from"fs";St();Tl();_e();nn();import{createServer as V0}from"net";import{existsSync as Nd,unlinkSync as J0,watch as Y0}from"fs";import{cpus as z0,loadavg as X0,platform as Q0,uptime as Z0}from"os";import{isAbsolute as ah,join as Hd}from"path";Ye();dn();import{connect as Zk}from"net";var eC=2000,tC=2000,rC=200,nC=300;function em(e){if(e.interval_seconds<=0)return tC;return e.interval_seconds*1000}async function tm(e,t,r,n,o,i=[]){let s=e.timeout_seconds>0?e.timeout_seconds*1000:eC,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:Ae,message:l instanceof Error?l.message:String(l)}}if(a==="http")return oC(e.url,s);if(a==="tcp")return sC(iC(e.address,r),s);if(a==="command")return aC(e.command.args,e.command.shell,n,o,s);if(a==="process"||a===""){if(t>0&&Rt(t))return{status:Et,message:"process running"};return{status:Ae,message:"process not running"}}return{status:Ae,message:`unknown health type ${e.type}`}}async function oC(e,t){let r=new AbortController,n=setTimeout(()=>r.abort(),t);try{let o=await fetch(e,{signal:r.signal});if(o.status>=rC&&o.status<nC)return{status:Et,message:String(o.status)};return{status:Ae,message:String(o.status)}}catch(o){return{status:Ae,message:o instanceof Error?o.message:String(o)}}finally{clearTimeout(n)}}function iC(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 sC(e,t){return new Promise((r)=>{if(e===""){r({status:Ae,message:"no tcp address"});return}let n=Zk(e,()=>{n.end(),r({status:Et,message:"connected"})});n.setTimeout(t),n.on("error",(o)=>{r({status:Ae,message:o.message})}),n.on("timeout",()=>{n.destroy(),r({status:Ae,message:"timeout"})})})}async function aC(e,t,r,n,o){if(e.length===0)return{status:Ae,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:Ae,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:Et,message:"ok"};return{status:Ae,message:`exit ${c}`}}function rm(e){if(e===Ae)return"WARN";if(e===Et)return"INFO";return"DEBUG"}import{readFileSync as cC}from"fs";import{freemem as lC,totalmem as dC}from"os";import{spawnSync as uC}from"child_process";var pd=1024,pC=2000,fC=/page size of (\d+) bytes/i,eo;function gC(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 mC(e){let t=e.match(fC),r=t?Number(t[1]):0;if(!Number.isFinite(r)||r<=0)return;let n=zs(e,"free")+zs(e,"inactive")+zs(e,"speculative")+zs(e,"purgeable");return Math.round(n*r/pd)}function zs(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 hC(){if(process.platform==="linux")try{return gC(cC("/proc/meminfo","utf8"))}catch{return}if(process.platform==="darwin"){let e=Date.now();if(eo&&e-eo.at<pC)return eo.leftoverKB;let t=uC("vm_stat",{encoding:"utf8"});if(t.status!==0||!t.stdout)return eo?.leftoverKB;let r=mC(t.stdout);if(r===void 0)return eo?.leftoverKB;return eo={at:e,leftoverKB:r},r}return}function nm(){let e=Math.max(0,Math.round(dC()/pd)),t=Math.max(0,Math.round(lC()/pd)),r=Math.max(0,Math.min(e,hC()??t));return{totalKB:e,unusedKB:t,leftoverKB:r}}rn();fn();ii();fn();import{pathToFileURL as JC}from"url";St();_e();rn();import{createServer as vm}from"http";import{randomBytes as HC}from"crypto";import{Readable as jC}from"stream";var Rd="x-devctl-request-id",BC="x-devctl-internal-token",hm=100,ym=new Set(["connection","keep-alive","proxy-authenticate","proxy-authorization","te","trailers","transfer-encoding","upgrade"]),WC=new Set(["gzip","deflate","br"]);class Pd{cfg;tokens;logs;bus;detector;middleware;server;running=!1;addr="";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||Yr(this.cfg.listen)}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>hm)this.recentRequests.splice(0,this.recentRequests.length-hm)}start(){if(this.cfg.listen.host==="0.0.0.0")return Promise.reject(M(_r,"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(M(_r,"proxy.listen.port is required when the proxy is enabled"));let t=this.cfg.listen.port;return new Promise((r,n)=>{this.server=vm((o,i)=>{this.serve(o,i)}),this.server.on("error",(o)=>n(ye(_r,`unable to listen on ${e}:${t}`,o))),this.server.listen(t,e,()=>{this.running=!0,this.addr=`${e}:${t}`,this.bus?.publish(Ne(Dg,"",{address:this.addr})),r()})})}stop(){let e=this.server;if(!e)return Promise.resolve();return new Promise((t)=>{e.close(()=>{this.running=!1,this.bus?.publish(Ne(Mg,"",{})),t()})})}async serve(e,t){let r=Date.now(),n=e.headers[Rd]?.toString()||HC(8).toString("hex");t.setHeader(Rd,n);let o=e.method??"GET",i=e.url??"/",s=this.detector?this.detector.redactText(i):i,a=qC(this.cfg.routes,e);if(!a){ro(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=Wn(a.auth),l=ri(c),d=0,g;try{let f={};for(let[A,m]of Object.entries(e.headers)){if(ym.has(A.toLowerCase()))continue;if(typeof m==="string")f[A]=m;else if(Array.isArray(m))f[A]=m.join(",")}let h=e.socket.remoteAddress??"",y=f.host??"",b=f["x-forwarded-for"];if(f["x-forwarded-for"]=b?`${b}, ${h}`:h,f["x-forwarded-host"]=y,f["x-forwarded-proto"]="http",delete f.host,f["accept-encoding"]="gzip, deflate, br",f[Rd]=n,this.middleware.length===0)await Ed(a,f,this.tokens);for(let A of this.middleware)await A.apply({route:a,headers:f,tokens:this.tokens});let w=UC(a.upstream.url,i),R=o!=="GET"&&o!=="HEAD"?e:void 0,S=await fetch(w,{method:o,headers:f,body:R,redirect:"manual",duplex:R?"half":void 0});t.statusCode=S.status,d=S.status;let N=(S.headers.get("content-encoding")??"").split(",").map((A)=>A.trim().toLowerCase()).filter((A)=>A!==""),J=N.length>0&&N.every((A)=>WC.has(A));S.headers.forEach((A,m)=>{let _=m.toLowerCase();if(ym.has(_))return;if(J&&(_==="content-encoding"||_==="content-length"))return;t.setHeader(m,this.detector?this.detector.redactText(A):A)}),await GC(S,t);let v=Date.now()-r;this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:S.status>=400?"WARN":"INFO",message:`${o} ${i} route=${a.name} identity=${l} status=${S.status} duration=${v}ms`,pid:0,request_id:n,identity:l}),this.bus?.publish(Ne(Og,a.name,{status:S.status,request_id:n,duration:v,identity:l}))}catch(f){let h=f instanceof Error?f.message:"proxy error";g=h,d=502,this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:"ERROR",message:`${o} ${i} route=${a.name} identity=${l} error=${h}`,pid:0,request_id:n,identity:l}),ro(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:g})}}}async function Ed(e,t,r){let n=e.auth.type.toLowerCase();if(n===""||n==="none")return;if(!r)throw M(_r,"token manager unavailable");let o=Wn(e.auth),i=await r.get(ri(o),e.auth.audience,[]);t.authorization=`Bearer ${i.accessToken}`}async function GC(e,t){if(!e.body){t.end();return}let r=jC.fromWeb(e.body);await new Promise((n,o)=>{r.on("error",o),t.on("error",o),t.on("finish",n),r.pipe(t)})}function UC(e,t){let r=new URL(e),n=new URL(t||"/",r),o=new URL(r.href);if(o.pathname=KC(n.pathname),o.search=n.search,o.hash="",o.origin!==r.origin)throw M(_r,"refusing to proxy to a different origin");return o}function KC(e){return(e.startsWith("/")?e:`/${e}`).replace(/^\/+/,"/")}function ro(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 qC(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 Td{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(e==="0.0.0.0")return Promise.reject(M(_r,"refusing to bind token endpoint to 0.0.0.0"));return new Promise((t,r)=>{this.server=vm((n,o)=>{this.serve(n,o)}),this.server.on("error",(n)=>r(ye(_r,"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(!VC(e.socket.remoteAddress)){ro(t,403,"forbidden");return}if((e.headers[BC]??"")!==this.secret){ro(t,401,"unauthorized");return}if(e.url?.startsWith("/token")!==!0){ro(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{ro(t,500,"token error")}}}function VC(e){if(!e)return!0;return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}ci();rn();class xm{tokenProviders=[];identityProviders=[];environmentSources=[];healthChecks=[];logParsers=[];proxyMiddleware=[];registerBuiltins(){this.tokenProviders.push(...an()),this.identityProviders.push(Ol(),Il()),this.logParsers.push(Sd()),this.proxyMiddleware.push(YC())}register(e){no(this.tokenProviders,e.tokenProviders),no(this.identityProviders,e.identityProviders),no(this.environmentSources,e.environmentSources),no(this.healthChecks,e.healthChecks),no(this.logParsers,e.logParsers),no(this.proxyMiddleware,e.proxyMiddleware)}}async function bm(e){let t=new xm;t.registerBuiltins();for(let r of e){if(r.trim()==="")continue;let o=await import(r.startsWith("file:")?r:JC(r).href);t.register(o)}return t}function YC(){return{name:"identity_inject",apply:async(e)=>{await Ed(e.route,e.headers,e.tokens)}}}function no(e,t){if(!t)return;e.push(...t)}_e();var{spawn:o0}=globalThis.Bun;Ye();var{spawn:zC}=globalThis.Bun;async function wm(e,t){if(e<=0)return;try{process.kill(-e,t);return}catch{try{process.kill(e,t)}catch{return}}}async function Sm(e){if(!Rt(e))return;let t=await hi(["ps","-p",String(e),"-o","command="]),r=Date.now(),n=XC(await hi(["ps","-p",String(e),"-o","etime="])),o=await QC(e);return{pid:e,command:t.trim(),cwd:o,startTime:n===void 0?void 0:new Date(r-n).toISOString()}}function XC(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 QC(e){let r=(await hi(["lsof","-a","-p",String(e),"-d","cwd","-Fn"])).split(`
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
`)
|
|
624
|
-
`);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 r;try{r=JSON.parse(e)}catch{t({error:"invalid json"});return}try{let n=await this.dispatch(r.method??"",r.params);t({id:r.id,result:n})}catch(n){let o=Kp(n);t({id:r.id,error:o.error,kind:o.kind,hint:o.hint,service:o.service})}}async dispatch(e,t){let r=ph(t)?t:{};switch(e){case"ping":return{session:this.sessionID,version:at,protocol:ei};case"start":return this.start({services:so(r.services),profile:typeof r.profile==="string"?r.profile:"",detach:r.detach===!0,client_env:uh(r.client_env)});case"stop":return await this.stop(so(r.services)),null;case"restart":return await this.restart(so(r.services),{cascade:r.cascade===!0,clientEnv:uh(r.client_env)}),null;case"auth_refresh":return await this.refreshIdentity({probeServiceAccounts:!0}),this.snapshot().identity;case"status":return this.snapshot();case"logs":return this.queryLogs({services:so(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 this.queryLogsPage({services:so(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 this.queryLogsFacets({services:so(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.proxySuppressed=!1,await this.startProxy(),null;case"proxy_stop":return this.proxySuppressed=!0,await this.stopProxy(),null;case"mcp_start":{let o=typeof r.port==="number"?r.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(r.disabled)?r.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 n=typeof r.stop_services==="boolean"?r.stop_services:ys(this.cfg.shutdown);return setTimeout(()=>{this.shutdown(n)},50),null;default:throw M(nt,`unknown method ${e}`)}}isDetached(){return this.detached}async start(e){if(e.detach===!0)this.detached=!0;let t=Js(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 r=fi(this.cfg,t.services,t.profile),n=await this.detectGoogleFn(this.cfg.google.project_id);r.blockers=fg(this.cfg,r.waves.flat(),n.adcAvailable);let o=new Set(r.blockers.map((s)=>s.name));for(let s of r.blockers)await this.fail(s.name,M(bt,s.message));if(this.cfg.proxy.enabled&&!this.proxySuppressed)await this.startProxy().catch((s)=>this.log("devctl","ERROR",H(s)));let i=[];for(let s of r.waves.flat()){if(o.has(s)||await this.claimIfAlreadyUp(s))continue;i.push(s)}if(i.length>0)try{let s=await kg(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,g])=>`${d}=${g}`).join(", ");this.log(a,"INFO",`assigned ports: ${l||"none"}`)}}catch(s){if(s instanceof Te&&s.service!=="")await this.fail(s.service,s);else this.log("devctl","ERROR",H(s));throw s}for(let s of r.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))),l=!1;for(let d of c)if(d.status==="rejected")l=!0,this.log("devctl","ERROR",H(d.reason));if(l)throw M(bt,"one or more services failed to start")}try{await this.awaitWaveHealth(s)}catch(c){throw this.log("devctl","ERROR",H(c)),c}}return this.persistState(),r}serviceIsActive(e){let t=this.procs.get(e);if(t&&sa(t))return!0;let r=this.runtimes.get(e);if(!r)return!1;if(r.health===Et||r.state===cn)return!0;return r.state===rd||r.state===Kt}serviceWorkDir(e){if(e.working_dir!==""&&!ah(e.working_dir))return Hd(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 Os(t);if(s)this.ports.set(e,s)}return!0}if(!t)return!1;let r=await Os(t);if(!r)return!1;let n=Object.values(r)[0],i=(n===void 0?void 0:await Vn(n))?.pid??0;if(i>0&&i!==process.pid){let s=Uo(this.cfg.repoRoot)?.processes.find((l)=>l.name===e&&l.pid===i);if(!s)return this.log(e,"WARN",`port ${n} is held by pid ${i} with no persisted record for ${e}; not adopting`),!1;let a=await aa(i);if(a!==void 0&&a.command!==""&&ca({args:[...t.command.args],workDir:this.serviceWorkDir(t),startTime:new Date(s.startTime)},a)){this.ports.set(e,r);let l=this.attachProcess(e,i,[...t.command.args],this.serviceWorkDir(t),new Date(s.startTime))??this.bumpGeneration(e);this.setState(e,Kt,jt,i,""),this.log(e,"INFO",`already listening on ${Object.values(r).join(", ")}; not starting again`);let d=this.serviceWorkDir(t),g=await this.resolveAdoptedHealthEnv(e,t,r);return this.startHealth(e,t,i,r,d,g,l),!0}this.log(e,"WARN",`port ${n} is in use by an unrelated process (pid ${i}); not adopting`)}return!1}async startOne(e,t,r){if(this.serviceIsActive(e))return;let n=this.cfg.services[e];if(!n)throw M(nt,`unknown service ${e}`);this.setState(e,rd,jt,0,"");let o=this.bumpGeneration(e),i=As(n.identity);if(Ls(i))try{if(i=await gg(n.identity,()=>vg(this.cfg.google.project_id),this.registry?.identityProviders),i.kind==="service_account")await this.tokens.get(ri(i),"",[]),this.serviceAccountStatus.set(i.serviceAccount,"available")}catch(f){if(i.kind==="service_account")this.serviceAccountStatus.set(i.serviceAccount,"unavailable");if(u_(n)||i.kind==="service_account")throw await this.fail(e,f),f;this.log(e,"WARN","cloud identity unavailable; starting service locally")}let s=this.ports.get(e)??{},a="";if(this.proxy?.isRunning())a=`http://${this.proxy.address()}`;else if(this.cfg.proxy.enabled)a=`http://${Yr(this.cfg.proxy.listen)}`;let c=El(e,"127.0.0.1",s,a,this.cfg.project.name);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 Pl(this.cfg.repoRoot,{service:e,profile:t,serviceCfg:n,profileEnv:r,assignedPorts:s,runtime:c,cfg:this.cfg,fetchSecret:Rl(async()=>(await this.tokens.get("user","",[])).accessToken),pluginSources:this.registry?.environmentSources,clientEnv:this.clientEnv.get(e)}),d=n.working_dir;if(d!==""&&!ah(d))d=Hd(this.cfg.repoRoot,d);let g=await this.procs.start({name:e,args:[...n.command.args],shell:n.shell||n.command.shell,workDir:d,env:Zo(l),graceMs:vs(this.cfg.shutdown)*1000,captureStdout:of(n),captureStderr:sf(n),onLine:(f,h)=>{this.logs.append({timestamp:new Date().toISOString(),service:e,source:f,stream:f,level:"",message:h,pid:g.pid})},onExit:(f,h)=>{this.onExit(e,o,f,h)}});if(this.processMeta.set(e,{command:[...n.command.args],cwd:d,startTime:g.startTime}),this.setState(e,Kt,jt,g.pid,""),this.bus.publish(Ne(Eg,e,{pid:g.pid})),this.startHealth(e,n,g.pid,s,d,Zo(l),o),this.persistState(),n.startup.wait_for_healthy){let f=n.startup.timeout_seconds>0?n.startup.timeout_seconds*1000:ch;try{await this.waitHealthy(e,f)}catch(h){throw await this.fail(e,h),h}}}async resolveAdoptedHealthEnv(e,t,r){let n="";if(this.proxy?.isRunning())n=`http://${this.proxy.address()}`;else if(this.cfg.proxy.enabled)n=`http://${Yr(this.cfg.proxy.listen)}`;let o=El(e,"127.0.0.1",r,n,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 Pl(this.cfg.repoRoot,{service:e,profile:this.serviceProfile.get(e)??this.profile,serviceCfg:t,profileEnv:this.serviceProfileEnv.get(e)??this.profileEnv,assignedPorts:r,runtime:o,cfg:this.cfg,fetchSecret:Rl(async()=>(await this.tokens.get("user","",[])).accessToken),pluginSources:this.registry?.environmentSources});return Zo(i)}catch(i){return this.log(e,"WARN",`could not fully reconstruct environment for adopted service's health check (${H(i)}); using a baseline environment`),Zo(o)}}async awaitWaveHealth(e){for(let t of e){let r=this.cfg.services[t];if(!r||r.health.type==="")continue;let n=r.startup.timeout_seconds>0?r.startup.timeout_seconds*1000:ch;try{await this.waitHealthy(t,n)}catch(o){throw await this.fail(t,o),o}}}async waitHealthy(e,t){let r=Date.now()+t;while(Date.now()<r){let n=this.runtimes.get(e);if(n?.health===Et)return;if(n?.state===ln)throw M(Bc,`service ${e} failed while waiting for healthy`);await p_(t_)}throw M(Bc,`service ${e} did not become healthy in time`)}onExit(e,t,r,n){if(!this.isCurrentGeneration(e,t))return;let o=this.runtimes.get(e);if(o?.state===ln)return;if(o&&(o.state===nd||o.state===Qn)){this.setState(e,Qn,jt,0,""),this.bus.publish(Ne(zl,e,{code:r}));return}let i=this.cfg.services[e],s=i?i.restart.policy||(i.restart.enabled?"on_failure":"never"):"never",a=n?.message??`exited with code ${r}`,c=s==="always"||s==="on_failure"&&r!==0,l=this.restarts.get(e)??0,d=i&&i.restart.max_retries>0?i.restart.max_retries:lh;if(c&&i&&l<d){this.setState(e,pi,jt,0,a),this.bumpRestartCount(e,l+1),this.persistState(),this.armRestart(e,i,t,l,()=>{let g=this.serviceProfile.get(e)??this.profile,f=this.serviceProfileEnv.get(e)??this.profileEnv;this.startOne(e,g,f).catch((h)=>this.log(e,"ERROR",H(h)))});return}this.fail(e,M("process_start",a))}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,Et,"no health check");return}let c=em(t.health)||n_,l=()=>{tm(t.health,r,n,o,i,this.registry?.healthChecks).catch((d)=>({status:Ae,message:H(d)})).then((d)=>{if(!this.isCurrentGeneration(e,s))return;this.setHealth(e,d.status,d.message),this.logs.append({timestamp:new Date().toISOString(),service:e,source:"health",level:rm(d.status),message:`health ${d.status} ${d.message}`,pid:r}),this.maybeRestartUnhealthy(e,t,d.status,s)})};l(),this.healthTimers.set(e,setInterval(l,c))}async stop(e){let t=e;if(t.length===0)t=[...this.runtimes.entries()].filter(([,i])=>i.state!==Qn).map(([i])=>i);if(t.length===0)return;let r=t.filter((i)=>!this.cfg.services[i]&&this.runtimes.has(i)),n=t.filter((i)=>!this.cfg.services[i]&&!this.runtimes.has(i));if(n.length>0)throw M(cs,`unknown service "${n[0]}"`);let o=t.filter((i)=>this.cfg.services[i]!==void 0);if(o.length>0)await this.runStopPlan(gi(this.cfg,o),{resetRestartCounts:!0});if(r.length>0){await this.runStopPlan({profile:this.profile,steps:[],waves:r.map((i)=>[i])},{resetRestartCounts:!0});for(let i of r)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 r of Object.keys(t))if(!e[r]&&!this.runtimes.has(r))this.runtimes.set(r,qs(r));for(let r of Object.keys(e)){if(t[r])continue;if(this.serviceIsActive(r)){let n=this.runtimes.get(r);if(n)n.orphaned=!0;this.log(r,"WARN","removed from configuration while still running; now orphaned \u2014 stop it explicitly to clean it up");continue}this.forgetService(r)}}async restart(e,t){let r=t?.cascade===!0,n=r?id(this.cfg,e):e,o=r?gi(this.cfg,e):zg(this.cfg,e),i=t?.auto!==!0;await this.runStopPlan(o,{resetRestartCounts:i});let s=n.map((a)=>this.serviceProfile.get(a)).find((a)=>a!==void 0)??this.profile;await this.start({services:n,profile:s,client_env:t?.clientEnv,auto:t?.auto})}async runStopPlan(e,t){for(let n of e.waves.flat())if(this.clearRestartTimer(n),this.bumpGeneration(n),t?.resetRestartCounts)this.resetRestartCount(n);let r=vs(this.cfg.shutdown)*1000;for(let n of e.waves)await Promise.all(n.map(async(o)=>{this.setState(o,nd,jt,0,"");let i=this.healthTimers.get(o);if(i)clearInterval(i),this.healthTimers.delete(o);await this.procs.stop(o,r),await this.releasePorts(o),this.setState(o,Qn,jt,0,""),this.bus.publish(Ne(zl,o,{}))}));this.persistState()}async startProxy(){if(this.proxy?.isRunning())return;if(this.proxy=new Pd(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 Td(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 oh(this.cfg.repoRoot,e);this.mcp=new Id({host:"127.0.0.1",port:t,token:this.mcpToken,hostApi:this.asMcpHost(),onEvent:(r,n)=>this.log("mcp",r,`mcp ${n}`),disabledTools:()=>this.mcpDisabledTools}),await this.mcp.start(),this.persistState()}setMcpDisabledTools(e){let t=e.filter((n)=>pa(n)),r=this.mcpDisabledTools.join(",");if(this.mcpDisabledTools=[...new Set(t)].sort(),this.mcpDisabledTools.join(",")===r)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 Er(this.cfg))await this.probeServiceAccount(e);return Tr(this.cfg)}}}async reload(){let e;try{e=gt(this.cfg.repoRoot,this.cfg.configPath)}catch(i){throw this.bus.publish(Ne(ai,"",{error:H(i)})),this.log("devctl","ERROR",`configuration reload failed: ${H(i)}`),i}try{this.checkPluginHealthTypes(e),this.checkPluginIdentityTypes(e)}catch(i){throw this.bus.publish(Ne(ai,"",{error:H(i)})),this.log("devctl","ERROR",`configuration reload failed: ${H(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=c_(this.cfg,e),r=JSON.stringify(this.cfg.proxy)!==JSON.stringify(e.proxy),n=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,n)this.detector.update(e.secrets.extra_markers,e.secrets.extra_patterns);if(r){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(Ne(Bs,"",{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",Vs(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[n,o]of this.runtimes)e[n]={...o,ports:this.ports.get(n)??o.ports,profile:this.serviceProfile.get(n)??o.profile,env_source:this.clientEnv.has(n)?"client":"daemon"};let t=this.proxy?.stats(),r={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((n)=>({name:n.name,identity:n.auth.identity.service_account||n.auth.identity.type||n.auth.type,upstream:n.upstream.url,auth:n.auth.type})),...r},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:l_()}}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 Er(this.cfg))await this.probeServiceAccount(o);let{service_accounts:r,service_account_status:n}=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:r,service_account_status:n,iap:this.cfg.proxy.routes.some((o)=>o.auth.type.toLowerCase()==="iap")},await this.syncCredentialEntries(),this.bus.publish(Ne(Xl,"",{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: ${H(t)}`)}}serviceAccountSnapshot(){let e={},t={};for(let r of Er(this.cfg)){let n=this.serviceAccountStatus.get(r)??"unknown";if(t[r]=n,n!=="unknown")e[r]=n==="available"}return{service_accounts:e,service_account_status:t}}async probeServiceAccount(e){let t;try{await d_(this.tokens.refresh(`sa:${e}`,"",[]),e_),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[r,n]of Object.entries(e.services))t.push(`${r} ${Zn(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(`
|
|
618
|
+
`),o=[];for(let i of r)if(i.length<=n)o.push(i);else o.push(...KP(i,n));return o.length>0?o:[""]}function Cy(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=` ${BP}${o}`,s=Math.max(1,t-i.length);return{visible:[le(r[0]??"",s)],mark:i,folded:!0,hidden:o}}function _y(e,t){return e==="all"||e==="focus"&&t}function Lu(e){if(e==="clip")return"focus";if(e==="focus")return"all";return"clip"}function Py(e,t,n,r=Ar){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 Du(e,t=Ar){return Math.max(0,e-t)}function Ou(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 Ki(e){if(e==="all")return"wrap all";if(e==="focus")return"wrap selected";return"clip"}function KP(e,t){let n=[],r=e;while(r.length>t){let o=r.slice(0,t),i=qP(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 qP(e){let t=e.lastIndexOf(" "),n=e.lastIndexOf("\t"),r=e.lastIndexOf(","),o=Math.max(t,n,r);if(o<Math.floor(e.length*WP))return-1;return e[o]===","?o+1:o}function Ry(e){let t=[],n=new RegExp(GP.source,"gi"),r=0,o=n.exec(e);while(o){let i=o[0]??"";if(o.index>r)t.push({text:e.slice(r,o.index),kind:"text"});t.push({text:i,kind:UP(i)}),r=o.index+i.length,o=n.exec(e)}if(r<e.length)t.push({text:e.slice(r),kind:"text"});if(t.length===0)return[{text:e,kind:"text"}];return t}function Ey(e){let t=e.showTimestamps?ic:0,n=e.showMeta?rc:0;return Math.max(by,e.width-t-e.serviceWidth-sc-n-wy-Ui*Sy)}function qi(e){return Math.max(AP,e-LP*2)}function Ty(e){let t=e.width<EP,n=e.proxyOn?`\u25CF ${le(e.proxyAddress,t?10:18)}`:t?"":"\u25CB off";return[{label:t?`${e.running}/${e.total}`:$u(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 Ay(e,t){let n=t.reduce((s,a)=>Math.max(s,a.length),0),r=ic+sc+wy+by+Ui*Sy,o=Math.max(cy,e-r),i=Math.max(cy,n);return Math.min(fy,o,i)}function cc(e,t,n){if(n)return e;let r=t.reduce((a,c)=>Math.max(a,c.length),0),o=Math.min(fy,Math.max(Ru,r+SP)),i=py+Xt+xt+o+gy+kP,s=Math.max(Ya,Math.floor(e*RP));return Math.min(s,Math.max(Ya,i))}function z(e,t){if(t<=0)return"";if(e.length>=t)return le(e,t);return e.padEnd(t)}function Co(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 Ly(e){return e<DP}function _o(e,t,n,r,o="center",i=!0){let s=Math.min(n,Math.max(1,e-4)),a=Math.min(my(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 Dy(e){if(e==="")return"idle";if(JP.test(e))return"error";if(e.includes("session only"))return"warning";if(VP.test(e))return"success";return"info"}function Oy(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 My(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 TP;return 0}function $y(e){if(e==="0")return Gn[9]?.id;if(e.length===1&&e>="1"&&e<="9")return Gn[Number(e)-1]?.id;return}function lc(e){if(!e)return"";return Object.keys(e.profiles).sort()[0]??""}function dc(e){return zP.has(e)}function Vi(e){if(!e)return!1;return dc(e.state)}function uc(e,t){let n=t??Object.keys(e?.services??{});return{running:n.filter((o)=>Vi(e?.services[o])).length,total:n.length}}function Iy(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(dc(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 Fy(e,t){if(!Number.isFinite(e)||!Number.isFinite(t)||t<=0)return 0;return e/t}function tR(e,t,n){if(!Number.isFinite(e))return"success";if(e>n)return"error";if(e>t)return"warning";return"success"}function nR(e,t){return tR(Fy(e,t),YP,XP)}function rR(e,t){let n=t>0?e/t:1;if(n<ZP)return"error";if(n<QP)return"warning";return"success"}function wu(e){if(!Number.isFinite(e)||e<0)return"\u2014";return e.toFixed(2)}function oR(e){if(!Number.isFinite(e)||e<0)return"\u2014";return`${Math.round(e*100)}%`}function Ny(e,t=Date.now()){if(!e?.startTime)return"\u2014";let n=new Date(e.startTime).getTime();if(!Number.isFinite(n))return"\u2014";return Ro(t-n)}function Hy(e,t=eR){return Object.entries(e).sort((n,r)=>r[1]-n[1]||n[0].localeCompare(r[0])).slice(0,t)}function jy(e,t=1){return Math.max(24,e-uR-t*2-pR-fR-gR)}function By(e){let t=e>=iR,n=e>=sR,r=e>=aR,o=e>=cR,i=e>=lR,s=e>=dR,a=Xt+xt;if(t)a+=xn+xt;if(n)a+=ec+xt;if(r)a+=tc+xt;if(o)a+=Za+xt;if(i)a+=pc+xt;if(s)a+=Un;return{name:Math.max(Ru,e-a),health:t,cpu:n,mem:r,up:o,rst:i,pid:s}}function Wy(e){let t=Number.isFinite(e)&&e>0?e:0;return{ratio:Math.min(1,t),label:oR(t)}}function Gy(e,t=yR){return`[${Ji(e.ratio,t)}] ${e.label.padStart(4)}`}function Mu(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)?vR:0,i=Po*(o>0?3:2),s=Math.min(mR,Math.max(Su,n)),a=Math.min(hR,Math.max(ku,r)),c=t-s-a-o-i;if(c<za&&a>ku)a=Math.max(ku,a-(za-c)),c=t-s-a-o-i;if(c<za&&s>Su)s=Math.max(Su,s-(za-c)),c=t-s-a-o-i;return{what:s,reading:a,meaning:Math.max(0,c),meter:o}}function Uy(e){return xR.has((e?.health.type??"").toLowerCase())}function Ky(e){if(e==="darwin")return"macOS";if(e==="win32")return"Windows";if(e==="linux")return"Linux";return e||"this computer"}function qy(e,t){let n=Math.max(1,t),r=nR(e,n),o=r==="error"?"overloaded":r==="warning"?"busy":"not busy",i=r==="error"?`${n} cores are queued up \u2014 last minute ${wu(e)}`:r==="warning"?`${n} cores nearly full \u2014 last minute ${wu(e)}`:`${n} cores. Last minute ${wu(e)} (under ${n} is fine)`;return{what:"CPU work",reading:o,meaning:i,tone:r,meter:Wy(Fy(e,n))}}function Vy(e,t){let n=rR(e,t),r=`${Xa(e)} of ${Xa(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:Wy(i)}}function Jy(e){let t=e?.state??"STOPPED";if(t==="FAILED")return"crashed";if(t==="STOPPING")return"stopping";if(t==="STARTING"||t==="RESTARTING")return"starting";if(dc(t))return"up";return"off"}function zy(e){if(!e||!dc(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 Yy(e){if(e==="keychain")return"password store";if(e==="file")return"local file";return e||"unknown store"}function Xy(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 Ji(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 Ro(e){if(!Number.isFinite(e)||e<Cu)return"< 1s";let t=Math.floor(e/dy),n=Math.floor(e%dy/Pu),r=Math.floor(e%Pu/_u),o=Math.floor(e%_u/Cu);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 Xa(e){if(!Number.isFinite(e)||e<0)return"\u2014";let t=e/bR;if(t>=uy)return`${(t/uy).toFixed(1)}G`;if(t>=1)return`${Math.round(t)}M`;return`${Math.round(e)}K`}function Qy(e){if(!Number.isFinite(e)||e<0)return"\u2014";return`${e.toFixed(1)}%`}function Eo(e){if(!e)return!0;let t=Object.values(e.services);if(t.length===0)return!0;return!t.some((n)=>Vi(n))}function Zy(e,t){if(e.length>0)return e;return[...t]}function fc(e,t){if(e.length>0)return[...e];return t===""?[]:[t]}function zi(e){return wR.has(e)}function tv(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 nv(e,t){let n=t.length>0?t[t.length-1].seq:-1,r=e.filter((o)=>o.seq>n);return[...t,...r]}function rv(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 ov(e,t,n){return e&&t<=0&&n}function iv(e){return e.filter((t)=>t.level==="ERROR"||t.level==="FATAL").length}function SR(e){return`${e.timestamp} ${e.service} ${e.level} ${e.message}`}function sv(e){return[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
|
+
`)}function av(e){return e.map((t)=>SR(t)).join(`
|
|
620
|
+
`)}function To(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=ya(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&&zi(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 kR(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 cv(e,t,n=[]){let r=Yi(e,t,n);return[{name:"",count:t.length},...kR(t,r)]}function CR(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 lv(e,t,n=[]){let r=Object.keys(t.byService).map((i)=>({service:i})),o=Yi(e,r,n);return[{name:"",count:t.total},...CR(o,t.byService)]}function $u(e,t){if(e<=0)return"none started";return`${e}/${t} running`}function Yi(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 dv(e,t,n){let r=["",...Yi(e,t)];if(n<1||n>r.length)return;return r[n-1]}function Iu(e,t,n){let r=["",...e],o=r.indexOf(t),s=((o<0?0:o)+n+r.length)%r.length;return r[s]??""}function Xi(e){return e.waves.flat().join(" \u2192 ")}function uv(e){let t=Xi(e);if(t==="")return"Started selected services";return`Started ${t}`}function pv(e){let t=Xi(e);if(t==="")return"Stopped running services";return`Stopped ${t}`}function fv(e,t,n,r="start"){let o=n?.services[e],i=Nt(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=Nt(n?.services[St(c)]);return On(c)==="service_healthy"?l!=="HEALTHY":l==="STOPPED"||l==="FAILED"}).map(St);if(a.length>0)return`waits for ${a.join(", ")}`;return"queued"}function Qi(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 gv(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 y=e.waves[x]??[],b=Qi(y,t,n);if(b==="active"||b==="unhealthy"||b==="failed")c=x;else if(b==="completed"&&c===x&&x<e.waves.length-1)c=x+1;for(let k of y){let S=t?.services[k];if(n==="stop"?!S||S.state==="STOPPED"||S.state==="UNKNOWN":Boolean(S&&(S.state==="HEALTHY"||S.health==="HEALTHY"||S.state==="RUNNING"&&S.health!=="UNHEALTHY")))i++;else if(S?.state==="FAILED")s++;else if(S?.state==="STARTING"||S?.state==="RUNNING"||S?.state==="UNHEALTHY"||S?.health==="UNHEALTHY"||S?.state==="STOPPING"||S?.state==="RESTARTING")a++}}let l=o>0?Math.round(i/o*100):100,d=16,f=Math.round(l/100*d),m="\u2588".repeat(f)+"\u2591".repeat(Math.max(0,d-f)),g=i===o&&o>0;return{total:o,ready:i,active:a,failed:s,percent:l,progressBar:m,currentWaveIndex:c,totalWaves:e.waves.length,isComplete:g}}function mv(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 hv(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 yv(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 vv(e){let t=Tr.indexOf(e);if(t<0)return"dashboard";return Tr[(t+1)%Tr.length]??"dashboard"}function xv(e){let t=Tr.indexOf(e);if(t<0)return"dashboard";return Tr[(t-1+Tr.length)%Tr.length]??"dashboard"}function bv(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 wv(e){let t=e.trim().toLowerCase().replace(/^\//,""),n=wo().filter((r)=>t===""||r.name.includes(t)||r.desc.toLowerCase().includes(t)||r.aliases.some((o)=>o.startsWith(t)));return bv(n).flatMap((r)=>r.items)}function Sv(e){return bv(e).flatMap((t)=>t.items.map((n)=>({name:`/${n.name}`,description:`${t.group} \xB7 ${n.desc}`,value:n.name})))}function kv(e,t,n=mn()){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")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 Fu();if(t==="config-edit")return[{key:"ctrl+s",label:"save"},{key:"esc",label:"discard"}];return _R(e,n)}function Fu(){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 _R(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:"/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 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 Cv(e,t,n){if(n<=t||e<t)return 0;return Math.min(e-t+1,n-t)}function Lr(e,t){if(e.length===0)return;let n=Math.min(Math.max(t,0),e.length-1);return e[n]}function gc(e){return e.command.args.join(" ")||"\u2014"}function Zi(e,t){let n=Dr(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 mc(e){let t=e.health.type||"none",n=e.health.url||e.health.address;return n===""?t:`${t} ${n}`}function hc(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 yc(e){let t=e.restart.policy||"none";if(e.restart.max_retries>0)return`${t} \xD7${e.restart.max_retries}`;return t}function _v(e,t,n,r){let o={...e.environment.defaults,...e.environment.vars},i=LR(o,t,n,r);return[...new Set([...Object.keys(i),...e.environment.required])].sort().map((a)=>({key:a,value:i[a]??"",required:e.environment.required.includes(a)}))}function Pv(e){let t=Math.max(AR,e-TR);return Math.min(RR,Math.max(PR,Math.floor(t*ER)))}function Dr(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 Nt(e){if(!e)return"STOPPED";return po(e)}function Rv(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 LR(e,t,n,r){if(t)return e;return new gn(n,r).redactMap(e)}function Ev(e,t){if(!e)return"";return(e.profiles[t]?.services??[]).join(", ")}function Ao(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 Tv(e,t,n,r){let o=Math.max(8,r-2),i=`logs ${n}`,s=Wn(i),a=e||"(no user)",c=t||"";if(o<=s+6){let m=Math.max(2,o-s-2);return[{label:le(a,m),tone:"idle"},{label:le(i,s-2),tone:"muted"}]}let l=o-s;if(c&&l>=36){let m=le(c,14),g=Wn(m),x=l-g-2,y=x>=a.length+9?`identity ${a}`:a;return[{label:le(y,x),tone:"idle"},{label:m,tone:"muted"},{label:i,tone:"muted"}]}if(c&&l>=28&&c.length<=10){let m=le(c,10),g=Wn(m),x=l-g-2;return[{label:le(a,x),tone:"idle"},{label:m,tone:"muted"},{label:i,tone:"muted"}]}let d=l>=a.length+9?`identity ${a}`:a;return[{label:le(d,l-2),tone:"idle"},{label:i,tone:"muted"}]}function Av(e){let t=e.payload?.error;return typeof t==="string"&&t!==""?t:"configuration reload failed"}var ko=100,py=8,Xt=12,xn=10,Qa=8,Un=8,Za=9,ec=7,tc=8,Ru=12,fy=40,xt=2,SP=2,gy=2,kP=2,Ya=34,CP=48,_P=60,PP=72,RP=0.48,nc=90,EP=60,TP=9,rc=8,AP=8,LP=6,DP=20,ay=1,OP=1,MP=1,$P=1,IP=1,WM,FP=2,Ja=2,NP=80,HP=56,ic=9,sc=7,cy=10,by=16,wy=2,Ui=1,Ar=200,jP=2,ly=1,BP="\u25B8",Sy=2,WP=0.4,GP,VP,JP,Gn,Tr,zP,YP=0.85,XP=1.5,QP=0.2,ZP=0.1,eR=5,iR=52,sR=64,aR=72,cR=82,lR=90,dR=100,uR=2,pR=2,fR=2,gR=1,pc=8,Su=8,mR=22,ku=6,hR=28,za=12,Po=2,yR=10,vR=18,xR,Cu=1000,_u,Pu,dy,bR=1024,uy=1024,wR,ev,PR=10,RR=28,ER=0.42,TR=2,AR=20;var Ae=D(()=>{st();wr();Li();vr();Yt();WM=my(nc-1);GP=/("[^"]*"|'[^']*'|\b(?:ERROR|FATAL|WARN(?:ING)?|FAIL(?:ED)?)\b|\b\d{3,5}\b)/gi;VP=/^(started|stopped|restarted|refreshed|cleared|copied|exported|jumped|proxy started|proxy stopped|secrets|re-running|theme |mouse |leader |display |restored)/i,JP=/\b(fail|error|unknown|not found|no configuration|blocked|already in use|is using port)\b/i;Gn=[{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"}];Tr=Gn.map((e)=>e.id);zP=new Set(["RUNNING","STARTING","RESTARTING","HEALTHY","UNHEALTHY"]);xR=new Set(["http","tcp","command"]);_u=60*Cu,Pu=60*_u,dy=24*Pu;wR=new Set(["auth","devctl","proxy"]),ev=["devctl","mcp","auth"]});import{useEffect as DR,useRef as OR}from"react";import{jsxDEV as re,Fragment as $R}from"@opentui/react/jsx-dev-runtime";function MR(e,t){switch(t){case"primary":return{bg:e.primary,fg:Er(e.primary,e.inverse)};case"accent":return{bg:e.accent,fg:Ua(e)?Ga:Er(e.accent,e.inverse)};case"success":return{bg:e.success,fg:Er(e.success,e.inverse)};case"warning":return{bg:e.warning,fg:Ua(e)?Ga:Er(e.warning,e.inverse)};case"error":return{bg:e.error,fg:Er(e.error,e.inverse)};case"info":return{bg:e.info,fg:Er(e.info,e.inverse)};case"muted":return{bg:e.element,fg:e.text};default:return{bg:e.element,fg:e.text}}}function Lv(e){let{palette:t,dir:n}=e;return re("box",{width:2,height:1,flexShrink:0,overflow:"hidden",children:re("text",{fg:t.muted,children:n==="left"?"\u2039":"\u203A"},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Be(e){let{palette:t,children:n,backgroundColor:r,edge:o="bottom"}=e,i=ne(),s=e.ruled??!yn(i),a=r??t.element,c=re("box",{flexShrink:0,flexDirection:"column",backgroundColor:a,overflow:"hidden",children:n},void 0,!1,void 0,this);if(!s)return c;return re("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 vc(e){let{palette:t,items:n,active:r,width:o,onPick:i}=e,s=n.map((d)=>Wn(d.label)),a=yy(s,r,Math.max(1,o)),c=a.start>0,l=a.end>=0&&a.end<n.length-1;return re("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[c?re(Lv,{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 m=f===r;return re(fe,{palette:t,label:d.label,tone:m?"primary":"muted",fg:m?void 0:d.color,onMouseDown:()=>i(f)},d.id,!1,void 0,this)}),l?re(Lv,{palette:t,dir:"right"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function fe(e){let{palette:t,label:n,tone:r="idle",fg:o,bg:i,onMouseDown:s}=e,a=MR(t,r);return re("box",{height:1,paddingLeft:1,paddingRight:1,backgroundColor:i??a.bg,overflow:"hidden",flexShrink:0,onMouseDown:s,children:re("text",{fg:o??a.fg,children:n},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Le(e){let{palette:t,hints:n}=e;return re("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:n.map((r)=>re("box",{height:1,paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:re("text",{wrapMode:"none",children:[re("span",{fg:t.primary,children:r.key},void 0,!1,void 0,this),re("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 We(e){let{palette:t,items:n,hints:r,ruled:o=!0}=e,i=re("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[n.map((s,a)=>re(fe,{palette:t,label:s.text,tone:s.tone,onMouseDown:s.onMouseDown},`${s.text}-${a}`,!1,void 0,this)),r&&r.length>0?re($R,{children:[re("box",{flexGrow:1,backgroundColor:t.element},void 0,!1,void 0,this),re(Le,{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 re(Be,{palette:t,backgroundColor:t.element,children:i},void 0,!1,void 0,this)}function tt(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,m=yn(ne()),g=_o(r,o,i,s,a,!m);return re("box",{position:"absolute",left:g.left,top:g.top,width:g.width,height:g.height,border:!0,borderStyle:Nu,borderColor:c??t.borderActive,backgroundColor:t.panel,padding:m?0:1,title:n,titleColor:t.primary,bottomTitle:l,gap:m?0:d,flexDirection:"column",overflow:"hidden",children:f},void 0,!1,void 0,this)}function Me(e){return{rootOptions:{flexGrow:1,height:"100%",overflow:"hidden",backgroundColor:e.panel},viewportOptions:{backgroundColor:e.panel},contentOptions:{backgroundColor:e.panel},scrollbarOptions:{trackOptions:{foregroundColor:e.primary,backgroundColor:e.element}}}}function Ge(e,t){if(!e)return;e.scrollBy({x:0,y:t})}function Lo(e,t){let n=OR(null);return DR(()=>{let r=n.current;if(!r||e<0)return;let o=requestAnimationFrame(()=>{r.scrollChildIntoView(`${t}-${e}`)});return()=>cancelAnimationFrame(o)},[t,e]),n}function nt(e){let t=ne(),n=Gi(t),r=e.scroll?re("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Me(e.palette),children:re("box",{flexDirection:"column",overflow:"hidden",children:e.children},void 0,!1,void 0,this)},void 0,!1,void 0,this):e.children;return re("box",{flexGrow:1,border:!0,borderStyle:Nu,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 Or(e){let{palette:t,label:n,value:r,tone:o="text"}=e,i=ne(),s=o==="success"?t.success:o==="warning"?t.warning:o==="error"?t.error:o==="muted"?t.muted:t.text;return re("box",{height:i.rowH,flexDirection:"row",overflow:"hidden",children:[re("box",{width:14,flexShrink:0,overflow:"hidden",children:re("text",{fg:t.muted,children:n},void 0,!1,void 0,this)},void 0,!1,void 0,this),re("box",{flexGrow:1,overflow:"hidden",children:re("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 xc(e){let{palette:t,title:n,body:r,hint:o}=e;return re("box",{height:o?5:4,paddingLeft:1,paddingRight:1,flexDirection:"column",overflow:"hidden",border:!0,borderStyle:Nu,borderColor:t.borderActive,titleColor:t.primary,children:[re("text",{fg:t.primary,children:n},void 0,!1,void 0,this),re("text",{fg:t.text,wrapMode:"word",children:r},void 0,!1,void 0,this),o?re("text",{fg:t.muted,wrapMode:"word",children:o},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var Nu="rounded";var xe=D(()=>{at();vn();Qe();Ae()});import{jsxDEV as se,Fragment as Dv}from"@opentui/react/jsx-dev-runtime";function Ov(e){let{palette:t,cfg:n,snap:r,google:o,profile:i,reveal:s,width:a}=e,c=uc(r,n?Object.keys(n.services):void 0),l=r?.proxy.running===!0,d=o?.adcAvailable===!0,f=a<nc,m=le(n?.project.name||"local",f?18:22),g=le(i||r?.profile||"no profile",16),x=se(Dv,{children:Ty({width:a,running:c.running,total:c.total,proxyOn:l,proxyAddress:r?.proxy.address??"",mcpOn:r?.mcp?.running===!0,adc:d,reveal:s}).filter((b)=>!b.hide&&b.label!=="").map((b)=>se(fe,{palette:t,label:b.label,tone:b.tone},b.label,!1,void 0,this))},void 0,!1,void 0,this),y=Gi(ne());return se(Be,{palette:t,backgroundColor:t.panel,ruled:!y,children:se("box",{height:f?2:1,flexDirection:"column",backgroundColor:t.panel,overflow:"hidden",children:[se("box",{height:1,flexDirection:"row",overflow:"hidden",children:[se(fe,{palette:t,label:Lt(),tone:"primary"},void 0,!1,void 0,this),se(fe,{palette:t,label:m,tone:"idle"},void 0,!1,void 0,this),se(fe,{palette:t,label:g,tone:"accent"},void 0,!1,void 0,this),f?null:se(Dv,{children:[se("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?se("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 Mv(e){let{palette:t,screen:n,width:r,onSelect:o}=e,i=Gn.map((a)=>({id:a.id,label:hy(a.label,r)})),s=vy(n);return se(Be,{palette:t,backgroundColor:t.element,children:se(vc,{palette:t,items:i,active:s,width:r,onPick:(a)=>{let c=Gn[a];if(c)o(c.id)}},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function $v(e){let{palette:t,overlay:n,query:r,onQuery:o,onSubmit:i}=e;if(n==="slash"||n==="palette"){let c=n==="slash"?"/":"> ";return se(Be,{palette:t,backgroundColor:t.highlight,edge:"top",children:se("box",{height:1,backgroundColor:t.highlight,paddingLeft:1,flexDirection:"row",overflow:"hidden",children:[se("box",{width:2,flexShrink:0,children:se("text",{fg:t.primary,children:c},void 0,!1,void 0,this)},void 0,!1,void 0,this),se("box",{flexGrow:1,overflow:"hidden",children:se("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 se(Be,{palette:t,backgroundColor:t.element,edge:"top",children:se("box",{height:1,backgroundColor:t.element,overflow:"hidden",children:se(Le,{palette:t,hints:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Iv(e){let{palette:t,screen:n,overlay:r,status:o,paused:i,errorOnly:s,width:a,copyKey:c}=e,l=Gi(ne()),d=Math.max(18,Math.floor(a*0.42)),f=Co(kv(n,r,c),d),m=Dy(o);return se(Be,{palette:t,backgroundColor:t.panel,edge:"top",ruled:!l,children:se("box",{height:1,backgroundColor:t.panel,overflow:"hidden",children:se(We,{ruled:!1,palette:t,items:[{text:n,tone:"primary"},{text:i?"PAUSED":"LIVE",tone:i?"warning":"success"},...s?[{text:"ERROR+",tone:"error"}]:[],...o===""?[]:[{text:le(o,Math.max(16,a-d-28)),tone:m}]],hints:f},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function $e(e){return se("box",{flexGrow:1,padding:1,overflow:"hidden",children:se(xc,{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 bc(e){return se("box",{flexGrow:1,padding:1,overflow:"hidden",children:se("text",{fg:e.palette.text,children:e.label},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function Fv(e){return se("box",{flexGrow:1,padding:1,flexDirection:"column",overflow:"hidden",children:[se("text",{fg:e.palette.error,children:e.title},void 0,!1,void 0,this),se("text",{fg:e.palette.text,wrapMode:"word",children:e.body},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var Pt=D(()=>{at();Ae();xe();vn();Qe()});function IR(){if(process.platform==="darwin")return[["pbcopy"]];if(process.platform==="win32")return[["clip"]];return[["wl-copy"],["xclip","-selection","clipboard"],["xsel","--clipboard","--input"]]}function FR(){return IR().filter((e)=>{let t=e[0];return typeof t==="string"&&Bun.which(t)!==null})}function NR(e){return`\x1B]52;c;${Buffer.from(e,"utf8").toString("base64")}\x07`}function Nv(){if(process.platform==="linux")return"install wl-clipboard (Wayland) or xclip (X11)";return"no clipboard helper found"}async function Hu(e){let t=FR(),n;for(let r of t)try{await jR(r,e);return}catch(o){n=o instanceof Error?o:Error(String(o))}if(process.platform!=="win32")try{await HR(e);return}catch(r){n=r instanceof Error?r:Error(String(r))}throw Se(Ye,"clipboard unavailable",n?`${Nv()} (${n.message})`:Nv())}async function HR(e){let t=NR(e);try{await Bun.write("/dev/tty",t)}catch{if(!process.stderr.write(t))throw Error("terminal clipboard write failed")}}async function jR(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 Hv=D(()=>{Pe()});function jv(e){return e==="slash"||e==="palette"||e==="config-edit"}function Bv(e,t){return hn(e,t.keybinds.leader??"ctrl+x")}function Wv(e,t){return hn(e,t.keybinds.command_list??"ctrl+p")}function Gv(e,t){return hn(e,t.keybinds.command??"/")||e.name==="/"}function Uv(e,t){return hn(e,t.keybinds.help??"?")||e.sequence==="?"}function Kv(e,t){return hn(e,t.keybinds.search??"f")}function qv(e){let t=e.name??"";return t==="R"||e.shift===!0&&t.toLowerCase()==="r"}function Vv(e){return e.ctrl===!0&&(e.name??"").toLowerCase()==="l"}function Jv(e,t){if(t&&hn(e,t.keybinds.interrupt??"ctrl+c"))return!0;return e.ctrl===!0&&(e.name??"").toLowerCase()==="c"}function zv(e,t){return hn(e,t.keybinds.copy??mn())}function Yv(e,t,n=BR){return t>0&&e-t<=n}function Kn(e,t,n,r){return hn(e,t.keybinds[n]??r)}function wc(e){let t=(e.name??"").toLowerCase();return t==="pagedown"||e.ctrl===!0&&t==="d"&&!e.meta}function Sc(e){let t=(e.name??"").toLowerCase();return t==="pageup"||e.ctrl===!0&&t==="u"&&!e.meta}var BR=2000;var Xv=D(()=>{Yt()});import{jsxDEV as qn}from"@opentui/react/jsx-dev-runtime";function Qv(e){let{palette:t,path:n,initialValue:r,error:o,termW:i,termH:s,textareaRef:a}=e;return qn(tt,{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:[qn("box",{height:1,overflow:"hidden",children:qn("text",{fg:t.muted,wrapMode:"none",children:n},void 0,!1,void 0,this)},void 0,!1,void 0,this),qn("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!==""?qn("box",{height:2,overflow:"hidden",children:qn("text",{fg:t.error,wrapMode:"word",children:o},void 0,!1,void 0,this)},void 0,!1,void 0,this):qn("box",{height:1,overflow:"hidden",children:qn("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 Zv=D(()=>{xe()});import{jsxDEV as ju}from"@opentui/react/jsx-dev-runtime";function ex(e){let{palette:t,title:n,body:r,termW:o,termH:i}=e;return ju(tt,{palette:t,title:n,bottomTitle:"enter confirm \xB7 esc stay",termW:o,termH:i,preferW:52,preferH:8,borderColor:t.warning,gap:1,children:[ju("text",{fg:t.text,wrapMode:"word",children:r},void 0,!1,void 0,this),ju(Le,{palette:t,hints:[{key:"enter",label:"confirm"},{key:"esc",label:"stay"}]},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var tx=D(()=>{xe()});import{jsxDEV as Kt}from"@opentui/react/jsx-dev-runtime";function nx(e){let{palette:t,event:n,termW:r,termH:o,scrollRef:i}=e;if(!n)return null;let s=n.message.length>120||n.message.includes(`
|
|
621
|
+
`);return Kt(tt,{palette:t,title:"log details",bottomTitle:"j/k scroll \xB7 esc close",termW:r,termH:o,preferW:s?84:72,preferH:s?22:14,gap:1,children:Kt("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:Kt("box",{flexDirection:"column",overflow:"hidden",children:[Kt("text",{fg:t.text,wrapMode:"word",children:n.message},void 0,!1,void 0,this),Kt("text",{fg:t.muted,children:`time ${n.timestamp}`},void 0,!1,void 0,this),Kt("text",{fg:je(n.service,t),children:`service ${n.service}`},void 0,!1,void 0,this),Kt("text",{fg:t.muted,children:`source ${n.source}${n.stream?` / ${n.stream}`:""}`},void 0,!1,void 0,this),Kt("text",{fg:t.muted,children:`level ${n.level}`},void 0,!1,void 0,this),Kt("text",{fg:t.muted,children:`pid ${n.pid||"\u2014"}`},void 0,!1,void 0,this),Kt("text",{fg:t.muted,children:`request ${n.request_id||"\u2014"}`},void 0,!1,void 0,this),Kt("text",{fg:t.muted,children:`identity ${n.identity||"\u2014"}`},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 rx=D(()=>{xe();Qe()});import{jsxDEV as be,Fragment as ix}from"@opentui/react/jsx-dev-runtime";function zR(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 Jn(e){return e+UR}function sx(e){let t=Jn(Wu.length),n=Jn(Gu.length),r=Jn(e.logCount),o=Jn(Uu.length),i=Jn(Ku.length),s=qu+e.pad*2;if(e.stacked)return s+t+n+r+o+i+Bu+(VR-1)*e.gap;let a=Math.max(t,n),c=Math.max(o,i);return s+a+r+c+Bu+(JR-1)*e.gap}function YR(e){return sx(e)-qu-e.pad*2}function XR(e){return e-qu*2<GR}function ax(e){let{palette:t,termW:n,termH:r,copyKey:o=mn(),scrollRef:i}=e,s=yn(ne()),a=XR(n),c=s?0:1,l=s?0:1,d=zR(o),f={stacked:a,logCount:d.length,pad:c,gap:l},m=sx(f),g=YR(f);return be(tt,{palette:t,title:"help",bottomTitle:`${Lt()} \xB7 j/k scroll \xB7 esc close`,termW:n,termH:r,preferW:WR,preferH:m,gap:0,children:be("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:be("box",{height:g,flexDirection:"column",flexShrink:0,overflow:"hidden",gap:l,children:[a?be(ix,{children:[be(Vn,{palette:t,title:"navigation",bindings:Wu},void 0,!1,void 0,this),be(Vn,{palette:t,title:"services",bindings:Gu},void 0,!1,void 0,this),be(Vn,{palette:t,title:"logs",bindings:d},void 0,!1,void 0,this),be(Vn,{palette:t,title:"commands",bindings:Uu},void 0,!1,void 0,this),be(Vn,{palette:t,title:"display",bindings:Ku},void 0,!1,void 0,this)]},void 0,!0,void 0,this):be(ix,{children:[be(ox,{palette:t,left:{title:"navigation",bindings:Wu},right:{title:"services",bindings:Gu}},void 0,!1,void 0,this),be(Vn,{palette:t,title:"logs",bindings:d},void 0,!1,void 0,this),be(ox,{palette:t,left:{title:"commands",bindings:Uu},right:{title:"display",bindings:Ku}},void 0,!1,void 0,this)]},void 0,!0,void 0,this),be("box",{height:Bu,flexShrink:0,overflow:"hidden",paddingLeft:1,children:be("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 ox(e){let{palette:t,left:n,right:r}=e,o=Math.max(Jn(n.bindings.length),Jn(r.bindings.length));return be("box",{height:o,flexDirection:"row",flexShrink:0,overflow:"hidden",gap:qR,children:[be(Vn,{palette:t,title:n.title,bindings:n.bindings,height:o,stretch:!0},void 0,!1,void 0,this),be(Vn,{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 Vn(e){let{palette:t,title:n,bindings:r,stretch:o=!1}=e,i=e.height??Jn(r.length);return be("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)=>be("box",{height:1,flexShrink:0,overflow:"hidden",paddingLeft:1,paddingRight:1,children:be(QR,{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 QR(e){let{palette:t,binding:n}=e;return be("box",{height:1,flexDirection:"row",overflow:"hidden",children:[be("box",{width:KR,flexShrink:0,overflow:"hidden",children:be("text",{fg:t.primary,wrapMode:"none",children:n.key},void 0,!1,void 0,this)},void 0,!1,void 0,this),be("box",{flexGrow:1,overflow:"hidden",children:be("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 WR=78,GR=56,UR=2,qu=2,Bu=1,Vu=8,KR=16,qR=2,VR=6,JR=4,Wu,Gu,Uu,Ku;var cx=D(()=>{at();xe();vn();Yt();Wu=[{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"}],Gu=[{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"}];Uu=[{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:"/mcp",label:"agent MCP server"}],Ku=[{key:"ctrl+=",label:"larger"},{key:"ctrl+-",label:"smaller"},{key:"?",label:"this overlay"}]});import{jsxDEV as lx}from"@opentui/react/jsx-dev-runtime";function dx(e){let{palette:t,termW:n,termH:r}=e,o=Fu();return lx(tt,{palette:t,title:"leader",termW:n,termH:r,preferW:68,preferH:5,anchor:"bottom",children:lx(Le,{palette:t,hints:o},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var ux=D(()=>{Ae();xe()});import{jsxDEV as px}from"@opentui/react/jsx-dev-runtime";function fx(e){let{palette:t,items:n,selected:r,termW:o,termH:i,onIndex:s,onPick:a}=e,c=Sv(n),l=_o(o,i,64,18,"center",!yn(ne()));return px(tt,{palette:t,title:"commands",bottomTitle:"enter select \xB7 esc close",termW:o,termH:i,preferW:64,preferH:18,children:px("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 m=f?.value;if(typeof m==="string"&&m!=="")a(m)}},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var gx=D(()=>{at();Ae();xe();vn()});import{jsxDEV as F}from"@opentui/react/jsx-dev-runtime";function Ju(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 ZR(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 mx(e){return F("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:F("text",{wrapMode:"none",children:[F("span",{fg:e.palette.primary,children:e.label.toUpperCase()},void 0,!1,void 0,this),e.detail?F("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 hx(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,m=new Set(d),g=n.waves.map((ce,Ie)=>({wave:ce.filter((qe)=>!m.has(qe)),waveIdx:Ie})).filter(({wave:ce})=>ce.length>0),x=gv(n,r,s),y=n.waves[x.currentWaveIndex]??[],b=Qi(y,r,s),k=Ju(b,t),S=ZR(o,i,b,t),N=hv(s,o,i,n.profile),K=yv(o,i),v=i?t.inverse:t.text,C=i?t.error:t.element,h=Math.min(92,Math.max(40,a-8)),P=h>=82?22:h>=66?17:13,H=12,Q=9,ae=h>=56,we=h>=72,ze=h<72||n.waves.length>3,Ke=n.profile?`PROFILE ${n.profile}`:s.toUpperCase();return F(tt,{palette:t,title:N,bottomTitle:"enter close \xB7 esc hide (operation continues)",termW:a,termH:c,preferW:98,preferH:28,borderColor:S.color,gap:0,children:[F("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:[F(fe,{palette:t,label:`${S.icon} ${S.label.toUpperCase()}`,tone:S.tone},void 0,!1,void 0,this),F("box",{paddingLeft:1,flexGrow:1,overflow:"hidden",children:F("text",{fg:t.text,wrapMode:"none",children:Ke},void 0,!1,void 0,this)},void 0,!1,void 0,this),F(fe,{palette:t,label:`${x.ready}/${x.total} READY`,tone:x.isComplete?"success":"info"},void 0,!1,void 0,this),F(fe,{palette:t,label:`WAVE ${Math.min(x.currentWaveIndex+1,Math.max(1,x.totalWaves))}/${Math.max(1,x.totalWaves)}`,tone:k.tone},void 0,!1,void 0,this)]},void 0,!0,void 0,this),F("box",{height:2,flexDirection:"column",overflow:"hidden",flexShrink:0,paddingLeft:1,paddingRight:1,children:[F("box",{height:1,flexDirection:"row",overflow:"hidden",children:[F("text",{wrapMode:"none",children:[F("span",{fg:t.muted,children:"PROGRESS "},void 0,!1,void 0,this),F("span",{fg:S.color,children:`[${x.progressBar}]`},void 0,!1,void 0,this),F("span",{fg:t.text,children:` ${x.percent}%`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),F("box",{flexGrow:1},void 0,!1,void 0,this),F("text",{wrapMode:"none",children:F("span",{fg:k.color,children:`${k.icon} ${k.label}`},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),F("box",{height:1,overflow:"hidden",children:F("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.":K.primary},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),F(mx,{palette:t,label:"Pipeline",detail:`${n.waves.length} execution wave${n.waves.length===1?"":"s"}`},void 0,!1,void 0,this),F("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:n.waves.map((ce,Ie)=>{let qe=Qi(ce,r,s),ue=Ju(qe,t),_e=ze?`W${Ie+1} ${ue.icon} ${ce.length}`:`W${Ie+1} ${ue.icon} ${ue.label} \xB7 ${ce.length}`;return F("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:[F(fe,{palette:t,label:_e,tone:ue.tone},void 0,!1,void 0,this),Ie<n.waves.length-1?F("box",{width:3,flexShrink:0,overflow:"hidden",children:F("text",{fg:t.muted,children:" \u2500\u25BA"},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},`step-${Ie}`,!0,void 0,this)})},void 0,!1,void 0,this),(n.blockers??[]).length>0?F("box",{minHeight:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,paddingLeft:1,children:F("text",{fg:t.error,wrapMode:"word",children:`BLOCKED ${n.blockers?.map((ce)=>`${ce.name}: ${ce.message}`).join(" \xB7 ")}`},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,d.length>0?F("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,paddingLeft:1,children:F("text",{wrapMode:"none",children:[F("span",{fg:t.success,children:"\u2713 ALREADY READY"},void 0,!1,void 0,this),F("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,F(mx,{palette:t,label:"Wave details",detail:"live process and health state"},void 0,!1,void 0,this),F("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,paddingLeft:1,children:[F("box",{width:2,flexShrink:0},void 0,!1,void 0,this),F("box",{width:P,flexShrink:0,overflow:"hidden",children:F("text",{fg:t.muted,children:z("SERVICE",P)},void 0,!1,void 0,this)},void 0,!1,void 0,this),F("box",{width:12,flexShrink:0,overflow:"hidden",children:F("text",{fg:t.muted,children:z("STATE",12)},void 0,!1,void 0,this)},void 0,!1,void 0,this),ae?F("box",{width:9,flexShrink:0,overflow:"hidden",children:F("text",{fg:t.muted,children:z("PORT",9)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,we?F("box",{flexGrow:1,overflow:"hidden",children:F("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),F("scrollbox",{ref:l,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:F("box",{flexDirection:"column",overflow:"hidden",gap:1,children:g.map(({wave:ce,waveIdx:Ie})=>{let qe=Qi(ce,r,s),ue=Ju(qe,t),_e=`${mv(s,Ie,qe)} \xB7 ${ce.length} service${ce.length===1?"":"s"}`;return F("box",{border:!0,borderStyle:"rounded",borderColor:ue.color,title:_e,titleColor:ue.color,flexDirection:"column",paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:ce.map((Ee)=>{let G=r?.services[Ee],Fe=Nt(G),ft=fv(Ee,n,r,s),Ne=Ee===i||Fe==="FAILED",Et=Fe==="UNHEALTHY",gt=Fe==="HEALTHY"||s==="stop"&&Fe==="STOPPED",en=Dr(G),mt=Ne?"\u2717":gt?"\u2713":Et?"\u26A0":Fe==="STARTING"||Fe==="RUNNING"||Fe==="STOPPING"||Fe==="RESTARTING"?"\u25CF":"\u25CB",tn=Ne?t.error:Te(t,Fe),ht=Ne?t.error:Et?t.warning:gt?t.success:t.muted;return F("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[F("box",{width:2,flexShrink:0,overflow:"hidden",children:F("text",{fg:tn,children:mt},void 0,!1,void 0,this)},void 0,!1,void 0,this),F("box",{width:P,flexShrink:0,overflow:"hidden",children:F("text",{fg:je(Ee,t),wrapMode:"none",children:z(Ee,P)},void 0,!1,void 0,this)},void 0,!1,void 0,this),F("box",{width:12,flexShrink:0,overflow:"hidden",children:F("text",{fg:Te(t,Fe),wrapMode:"none",children:z(Fe,12)},void 0,!1,void 0,this)},void 0,!1,void 0,this),ae?F("box",{width:9,flexShrink:0,overflow:"hidden",children:F("text",{fg:en?t.info:t.muted,wrapMode:"none",children:z(en?`:${en}`:"\u2014",9)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,we?F("box",{flexGrow:1,overflow:"hidden",children:F("text",{fg:ht,wrapMode:"none",children:ft},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},Ee,!0,void 0,this)})},`wave-card-${Ie}`,!1,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this),F("box",{height:3,flexShrink:0,flexDirection:"column",backgroundColor:C,border:["top"],borderStyle:"single",borderColor:S.color,paddingLeft:1,paddingRight:1,overflow:"hidden",onMouseDown:f,children:[F("text",{fg:v,wrapMode:"none",children:K.primary},void 0,!1,void 0,this),F("text",{fg:i?t.inverse:t.muted,wrapMode:"none",children:K.secondary},void 0,!1,void 0,this)]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}var yx=D(()=>{Ae();xe();Qe()});import{jsxDEV as Qt}from"@opentui/react/jsx-dev-runtime";function vx(e){let{palette:t,route:n,termW:r,termH:o,scrollRef:i}=e;if(!n)return null;return Qt(tt,{palette:t,title:n.name,bottomTitle:"j/k scroll \xB7 esc close",termW:r,termH:o,preferW:78,preferH:16,gap:1,children:Qt("scrollbox",{ref:i,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:Qt("box",{flexDirection:"column",overflow:"hidden",children:[Qt("text",{fg:t.muted,children:`auth ${n.authType||"none"}`},void 0,!1,void 0,this),Qt("text",{fg:t.muted,children:`identity ${n.identityType||"\u2014"}`},void 0,!1,void 0,this),Qt("text",{fg:t.text,wrapMode:"word",children:`account ${n.serviceAccount||"\u2014"}`},void 0,!1,void 0,this),Qt("text",{fg:t.text,wrapMode:"word",children:`audience ${n.audience||"\u2014"}`},void 0,!1,void 0,this),Qt("text",{fg:t.muted,children:`match host ${n.matchHost||"*"}`},void 0,!1,void 0,this),Qt("text",{fg:t.muted,children:`match path ${n.matchPath||"*"}`},void 0,!1,void 0,this),Qt("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 xx=D(()=>{xe()});import{jsxDEV as Mt}from"@opentui/react/jsx-dev-runtime";function wx(e){let{palette:t,items:n,query:r,selected:o,onQuery:i,onSubmit:s}=e,a=Cv(o,bx,n.length),c=n.slice(a,a+bx),l=Math.max(c.length,1),d=Lr(n,o);return Mt("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?Mt("box",{height:1,paddingLeft:1,overflow:"hidden",children:Mt("text",{fg:t.muted,children:"no matching command"},void 0,!1,void 0,this)},void 0,!1,void 0,this):c.map((f)=>{let m=f.name===d?.name;return Mt("box",{height:1,flexDirection:"row",overflow:"hidden",paddingLeft:1,paddingRight:1,backgroundColor:m?t.highlight:t.panel,children:[Mt("box",{width:14,flexShrink:0,overflow:"hidden",children:Mt("text",{fg:m?t.primary:t.text,wrapMode:"none",children:`${m?"\u203A":" "} /${f.name}`},void 0,!1,void 0,this)},void 0,!1,void 0,this),Mt("box",{flexGrow:1,overflow:"hidden",children:Mt("text",{fg:m?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)}),Mt("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.highlight,paddingLeft:1,children:[Mt("box",{width:2,flexShrink:0,children:Mt("text",{fg:t.primary,children:"/"},void 0,!1,void 0,this)},void 0,!1,void 0,this),Mt("box",{flexGrow:1,overflow:"hidden",children:Mt("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 bx=8;var Sx=D(()=>{Ae()});import{jsxDEV as _x}from"@opentui/react/jsx-dev-runtime";function Px(e){let{palette:t,themeName:n,selected:r,termW:o,termH:i,onIndex:s,onPreview:a,onPick:c}=e,l=vt.map((f)=>({name:f===n?`${f} (active)`:f,description:f===n?`${uu[f]} \xB7 current`:uu[f],value:f})),d=_o(o,i,kx,Cx,"center",!yn(ne()));return _x(tt,{palette:t,title:"/themes",bottomTitle:"enter save \xB7 esc revert",termW:o,termH:i,preferW:kx,preferH:Cx,children:_x("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 m=vt[f];if(m)a(m)},onSelect:(f,m)=>{let g=m?.value;if(typeof g==="string"&&g!=="")c(g)}},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var kx=52,Cx=22;var Rx=D(()=>{at();Ae();xe();vn();Qe()});import{jsxDEV as Ue}from"@opentui/react/jsx-dev-runtime";function kc(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 Ue("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 Ex(e){let{palette:t,cfg:n,google:r,identity:o}=e;if(!r&&!o)return Ue(bc,{palette:t,label:"Checking Application Default Credentials\u2026"},void 0,!1,void 0,this);let i=eE(n,o),s=o?.user||r?.userEmail||"",{project:a,source:c}=Ao(n,o,r),l=o?.adc??r?.adcAvailable===!0,d=o?.iap??(n?.proxy.routes??[]).some((y)=>y.auth.type.toLowerCase()==="iap"),f=i.filter((y)=>y.inactive!==!0),m=f.some((y)=>y.ok===!0),g=f.some((y)=>y.ok===!1),x=m?"AVAILABLE":g?"UNAVAILABLE":f.length>0?"NOT PROBED":i.length>0?"not required":"not configured";return Ue(nt,{palette:t,title:"identity",scroll:!0,children:[Ue(kc,{palette:t,title:"Google identity",tone:l?"success":"warning",children:[Ue(Or,{palette:t,label:"user",value:s||"(unknown)"},void 0,!1,void 0,this),Ue(Or,{palette:t,label:"project",value:a||"(unset)"},void 0,!1,void 0,this),Ue(Or,{palette:t,label:"source",value:c||"\u2014"},void 0,!1,void 0,this),Ue(Or,{palette:t,label:"ADC",value:l?"\u2713 available":"\u2717 missing",tone:l?"success":"error"},void 0,!1,void 0,this),Ue(Or,{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),Ue(kc,{palette:t,title:`Service accounts (${i.length})`,tone:f.length===0?"muted":m?"success":"warning",children:[i.length===0?Ue("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((y)=>Ue("text",{fg:y.inactive?t.muted:y.ok===!0?t.success:y.ok===!1?t.error:t.text,wrapMode:"none",children:`${y.inactive?"\u2013":y.ok===!0?"\u2713":y.ok===!1?"\u2717":"\u25CB"} ${y.email}${y.inactive?" \u2014 inactive (route auth is none)":""}`},y.email,!1,void 0,this)),Ue("box",{height:1,flexShrink:0},void 0,!1,void 0,this),Ue(Or,{palette:t,label:"impersonation",value:x,tone:m?"success":f.length>0?"warning":"muted"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),Ue(kc,{palette:t,title:"IAP",tone:d?"success":"muted",children:[Ue("box",{flexDirection:"row",overflow:"hidden",flexShrink:0,children:Ue(fe,{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?Ue("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?Ue(kc,{palette:t,title:"ADC unavailable",tone:"warning",children:[Ue("text",{fg:t.text,wrapMode:"word",children:"Local services still start. Cloud identity, impersonation, and IAP need ADC."},void 0,!1,void 0,this),Ue("text",{fg:t.muted,wrapMode:"word",children:"run `gcloud auth application-default login` or /auth"},void 0,!1,void 0,this)]},void 0,!0,void 0,this):null]},void 0,!0,void 0,this)}function eE(e,t){let n=new Map((e?Yl(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 Tx=D(()=>{Pt();Ae();xe();ur()});import{jsxDEV as pt}from"@opentui/react/jsx-dev-runtime";function Ax(e){let{palette:t,credentials:n}=e;if(!n)return pt(bc,{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 pt(nt,{palette:t,title:"credentials",scroll:!0,children:[pt("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[pt(fe,{palette:t,label:`backend: ${n.backend}`,tone:"info"},void 0,!1,void 0,this),n.entries.length>0?pt(fe,{palette:t,label:`${r} valid`,tone:"success"},void 0,!1,void 0,this):null,o>0?pt(fe,{palette:t,label:`${o} expired`,tone:"warning"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),pt("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),pt("box",{height:1,flexShrink:0},void 0,!1,void 0,this),n.entries.length===0?pt("text",{fg:t.muted,children:"no cached credentials"},void 0,!1,void 0,this):pt("box",{flexDirection:"column",overflow:"hidden",gap:1,children:n.entries.map((i)=>pt("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:[pt("text",{wrapMode:"none",children:[pt("span",{fg:i.valid?t.success:t.warning,children:i.valid?"\u2713 valid":"\u2717 expired"},void 0,!1,void 0,this),pt("span",{fg:t.muted,children:` \xB7 expires ${i.expires_at}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this),pt("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),pt(xc,{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 Lx=D(()=>{Pt();xe()});function Dx(e){let t=Object.keys(e.services).length,n=Object.keys(e.profiles).length,r=e.proxy.routes.length,o=[{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)o.push({text:`${r} route${r===1?"":"s"}`,tone:"info"});return o}function Ox(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 Mx(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 $x(e){let t=tE(e);return[{label:"exit",value:t,tone:t==="ask on quit"?"warning":"text"},{label:"grace",value:`${e.shutdown.grace_seconds}s`},{label:"refresh",value:`${As(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 Ix(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 Fx(e){return[{label:"listen",value:ir(e.proxy.listen),tone:e.proxy.enabled?"text":"muted"},{label:"token",value:oE(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]??Mn();return{name:t,extends:n.extends||"\u2014",command:gc(n),ports:Zi(n),identity:hc(n),health:mc(n),depends:n.dependencies.map(Ts).join(", ")||"\u2014",restart:yc(n)}})}function Hx(e){return e.proxy.routes.map((t)=>({name:t.name||t.match.host||"(unnamed)",match:iE(t),upstream:t.upstream.url||"\u2014",auth:t.auth.type||"none",identity:sE(t)}))}function jx(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 Bx(e){return Object.keys(e.templates).sort().map((t)=>({name:t,summary:aE(e.templates[t])}))}function Wx(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 tE(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 Gx(e){let t=e.reduce((n,r)=>Math.max(n,r.name.length),0);return Math.min(rE,Math.max(nE,t))}function oE(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 iE(e){let t=e.match.host||"*",n=e.match.path;if(n==="")return t;return`${t}${n.startsWith("/")?n:`/${n}`}`}function sE(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 aE(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 nE=8,rE=20,Ux=80,Do=10;var Kx=D(()=>{st();Ae()});import{jsxDEV as A}from"@opentui/react/jsx-dev-runtime";function Jx(e){let{palette:t,cfg:n,width:r}=e,o=ne();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(Do+8,r-6-o.pad*2),s=i>=Ux,a=s?Math.floor((i-qx)/2):i,c=Nx(n),l=Hx(n),d=jx(n),f=Bx(n);return A(nt,{palette:t,title:`config ${n.project.name||"unnamed"}`,children:[A(We,{palette:t,items:Dx(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:Me(t),children:A("box",{flexDirection:"column",overflow:"hidden",gap:Vx,children:[A(zu,{wide:s,left:A(bn,{palette:t,title:"project",children:A(Oo,{palette:t,facts:Ox(n,ut),width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:A(bn,{palette:t,title:"google",children:A(Oo,{palette:t,facts:Mx(n),width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),A(zu,{wide:s,left:A(bn,{palette:t,title:"runtime",children:A(Oo,{palette:t,facts:$x(n),width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:A(bn,{palette:t,title:"logs",children:A(Oo,{palette:t,facts:Ix(n),width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this),A(bn,{palette:t,title:`proxy ${n.proxy.enabled?"enabled":"disabled"}`,children:[A(Oo,{palette:t,facts:Fx(n),width:i},void 0,!1,void 0,this),A(lE,{palette:t,routes:l,width:i},void 0,!1,void 0,this)]},void 0,!0,void 0,this),A(bn,{palette:t,title:`services ${c.length}`,children:A(cE,{palette:t,rows:c,width:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),A(zu,{wide:s,left:A(bn,{palette:t,title:`profiles ${d.length}`,children:A(dE,{palette:t,rows:d,width:a},void 0,!1,void 0,this)},void 0,!1,void 0,this),right:A(bn,{palette:t,title:`templates ${f.length}`,children:A(uE,{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(bn,{palette:t,title:"extras",children:A(Oo,{palette:t,facts:Wx(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(Be,{palette:t,backgroundColor:t.element,edge:"top",children:A(Le,{palette:t,hints:[{key:"v",label:"validate/save buffer"},{key:"e",label:"open in $EDITOR"},{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 zu(e){let{wide:t,left:n,right:r}=e;if(!t)return A("box",{flexDirection:"column",overflow:"hidden",gap:Vx,flexShrink:0,children:[n,r]},void 0,!0,void 0,this);return A("box",{flexDirection:"row",overflow:"hidden",gap:qx,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 bn(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 Oo(e){let{palette:t,facts:n,width:r}=e,o=Math.max(4,r-Do-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:Do,flexShrink:0,overflow:"hidden",children:A("text",{fg:t.muted,wrapMode:"none",children:z(i.label,Do)},void 0,!1,void 0,this)},void 0,!1,void 0,this),A("box",{width:o,flexShrink:0,overflow:"hidden",children:A("text",{fg:gE(t,i.tone),wrapMode:"none",children:z(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 cE(e){let{palette:t,rows:n,width:r}=e;if(n.length===0)return A(Cc,{palette:t,text:"no services"},void 0,!1,void 0,this);let o=Gx(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:je(s.name,t),wrapMode:"none",children:z(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:le(pE(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 lE(e){let{palette:t,routes:n,width:r}=e;if(n.length===0)return A(Cc,{palette:t,text:"no routes"},void 0,!1,void 0,this);let o=Math.min(Do+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:z(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:le(fE(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 dE(e){let{palette:t,rows:n,width:r}=e;if(n.length===0)return A(Cc,{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:z(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:le(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 uE(e){let{palette:t,rows:n,empty:r,width:o}=e;if(n.length===0)return A(Cc,{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:z(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:le(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 Cc(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 pE(e){let t=e.extends==="\u2014"?"":` ${e.extends}`;return` ${e.ports} ${e.identity} ${e.health} ${e.restart} \u2190 ${e.depends}${t}`}function fE(e){return` ${e.auth} ${e.identity} ${e.match} \u2192 ${e.upstream}`}function gE(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 qx=1,Vx=1;var zx=D(()=>{Pt();Kx();at();Ae();xe();Qe()});import{useRef as mE}from"react";import{jsxDEV as ge}from"@opentui/react/jsx-dev-runtime";function _c(e){let{palette:t,names:n,snap:r,selected:o,checked:i,width:s,onOpen:a,onSelectIndex:c,onToggle:l}=e,d=ne(),f=mE(!1),m=new Set(i),g=Au(s),x=Tu(s),y=Eu(s),b=xy(s);return ge("box",{flexDirection:"column",flexGrow:1,overflow:"hidden",children:[ge("box",{height:1,flexDirection:"row",overflow:"hidden",children:[ge(bt,{width:2,fg:t.muted,text:""},void 0,!1,void 0,this),ge(bt,{width:4,fg:t.accent,text:"sel"},void 0,!1,void 0,this),ge(bt,{width:2,fg:t.muted,text:""},void 0,!1,void 0,this),ge(bt,{width:b,fg:t.muted,text:"name"},void 0,!1,void 0,this),ge(bt,{width:xt,fg:t.muted,text:""},void 0,!1,void 0,this),ge(bt,{width:Xt,fg:t.muted,text:"state"},void 0,!1,void 0,this),y?ge(bt,{width:xn,fg:t.muted,text:"health"},void 0,!1,void 0,this):null,x?ge(bt,{width:Qa,fg:t.muted,text:"port"},void 0,!1,void 0,this):null,g?ge(bt,{width:Un,fg:t.muted,text:"pid"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),n.map((k,S)=>{let N=r?.services[k],K=Nt(N),v=N?.health??"UNKNOWN",C=m.has(k),h=S===o,P=C?"[x]":"[ ]",H=h?"\u203A":" ";return ge("box",{height:d.rowH,flexDirection:"row",overflow:"hidden",backgroundColor:h?t.highlight:C?t.element:void 0,onMouseDown:()=>{if(f.current)return;if(h){a(k);return}c(S)},children:[ge("box",{width:2,flexShrink:0,children:ge("text",{fg:t.primary,children:H},void 0,!1,void 0,this)},void 0,!1,void 0,this),ge("box",{width:4,flexShrink:0,onMouseDown:()=>{f.current=!0,l?.(k),setTimeout(()=>{f.current=!1},0)},children:ge("text",{fg:hE(t,C,h),children:P},void 0,!1,void 0,this)},void 0,!1,void 0,this),ge("box",{width:2,flexShrink:0,children:ge("text",{fg:Te(t,K),children:Ot(K)},void 0,!1,void 0,this)},void 0,!1,void 0,this),ge(bt,{width:b,fg:h?t.primary:je(k,t),text:z(k,b)},void 0,!1,void 0,this),ge(bt,{width:xt,fg:t.muted,text:""},void 0,!1,void 0,this),ge(bt,{width:Xt,fg:Te(t,K),text:K},void 0,!1,void 0,this),y?ge(bt,{width:xn,fg:Te(t,v),text:v},void 0,!1,void 0,this):null,x?ge(bt,{width:Qa,fg:t.text,text:Dr(N)},void 0,!1,void 0,this):null,g?ge(bt,{width:Un,fg:t.text,text:N?.pid?String(N.pid):""},void 0,!1,void 0,this):null]},k,!0,void 0,this)})]},void 0,!0,void 0,this)}function Pc(e){let{palette:t,checked:n,idle:r,profileName:o}=e,i=n.length;if(i>0)return ge(We,{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 ge(We,{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 ge(We,{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 hE(e,t,n){if(t)return e.success;if(n)return e.primary;return e.muted}function bt(e){return ge("box",{width:e.width,flexShrink:0,overflow:"hidden",children:ge("text",{fg:e.fg,wrapMode:"none",children:e.text},void 0,!1,void 0,this)},void 0,!1,void 0,this)}var Yu=D(()=>{Ae();at();xe();Qe()});import{useEffect as Xu,useRef as Yx}from"react";import{jsxDEV as V,Fragment as SE}from"@opentui/react/jsx-dev-runtime";function Xx(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:m,onSearch:g,onService:x,onToggleErrors:y,onToggleSystemLogs:b,onClearLogs:k,onSelect:S,wrapMode:N="focus",selected:K=-1,follow:v=!0,newer:C=0,viewStart:h=0,viewTotal:P,onLeaveLatest:H,onOpenExports:Q,onJumpLatest:ae,view:we,fullscreen:ze=!1,facets:Ke}=e,ce=ne(),Ie=ky(m,ce.pad,ze),qe=c?n:n.filter((Et)=>!zi(Et.source)),ue=To(n,{service:i,services:e.services,errorOnly:a,search:l,regex:e.regex,source:e.source,systemLogs:c}),_e=we??ue,Ee=P??ue.length,G=Math.min(Ee,h+_e.length),Fe=Ee===0?"empty":`${h+1}\u2013${G} of ${Ee}`,ft=e.services??[],Ne=ft.length>0?ft.join(","):i===""?"all services":i;return V("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[ze?null:V(SE,{children:[V(We,{palette:t,items:[{text:s?"PAUSED":"LIVE",tone:s?"warning":"success"},{text:`shown ${Ee}`,tone:"info"},{text:Ke?`total ${Ke.total}`:`total ${n.length}`},...we&&Ee>we.length?[{text:`${h+1}\u2013${h+we.length} / ${Ee}`,tone:"info"}]:[],{text:Ne,tone:i===""?"idle":"primary"},{text:Ki(N),tone:N==="clip"?"idle":"accent"},...v?[]:[{text:C>0?`pinned \xB7 +${C} new`:"pinned",tone:"warning"}],{text:a?"ERROR+":"all levels",tone:a?"error":"idle",onMouseDown:y},{text:c?"system: on":"system: off",tone:c?"accent":"idle",onMouseDown:b},...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:k},{text:"open folder",tone:"primary",onMouseDown:Q}]},void 0,!1,void 0,this),V(ep,{palette:t,logs:qe,names:o??r,service:i,errorOnly:a,width:m,onService:x,onToggleErrors:y,facets:Ke},void 0,!1,void 0,this)]},void 0,!0,void 0,this),d?V("box",{height:1,paddingLeft:1,backgroundColor:t.highlight,overflow:"hidden",children:V("input",{focused:!0,value:l,placeholder:"search messages or service names",onInput:g,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,we&&Ee>_e.length?V(Qu,{palette:t,start:h,count:_e.length,total:Ee},void 0,!1,void 0,this):null,V("box",{flexGrow:1,border:!ze,borderStyle:"rounded",borderColor:t.border,title:ze?void 0:`logs ${Ne} \xB7 ${Fe}`,titleColor:t.primary,padding:ze?0:ce.pad,overflow:"hidden",children:_e.length===0?V($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):V(tp,{palette:t,logs:_e,width:Ie,followTick:f,focused:!1,wrapMode:N,selected:K,follow:v,showTimestamps:e.showTimestamps!==!1,showMeta:e.showMeta!==!1,onPick:S,onLeaveLatest:H,viewStart:h},f,!1,void 0,this)},void 0,!1,void 0,this),V(Be,{palette:t,backgroundColor:t.element,edge:"top",children:V(Le,{palette:t,hints:Co([{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:C>0?`latest +${C}`:"latest"},{key:"w",label:"wrap"},{key:"p",label:"pause"},{key:"z",label:ze?"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,m-2))},void 0,!1,void 0,this)},void 0,!1,void 0,this),!v?V(Zu,{palette:t,width:m,newer:C,onJump:ae},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}function Qu(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 V(We,{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 Zu(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 V("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:V("text",{wrapMode:"none",children:[V("span",{fg:e.palette.primary,children:"g"},void 0,!1,void 0,this),V("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 ep(e){let{palette:t,logs:n,names:r,service:o,errorOnly:i,width:s,onService:a,onToggleErrors:c,facets:l}=e,d=l?lv(r,l):cv(r,n),f=s<80,m=d.map((b,k)=>{let S=k+1,N=b.name===""?"all":b.name;return{id:N,label:f?`${S} ${N}`:`${S} ${N} \xB7 ${b.count}`,color:je(b.name,t)}}),g=Math.max(0,d.findIndex((b)=>b.name===o)),x=i?"ERROR+":f?"lvls":"all levels",y=Math.max(Wn(m[g]?.label??"1 all"),s-Wn(x));return V(Be,{palette:t,backgroundColor:t.element,children:V("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:[V("box",{flexGrow:1,overflow:"hidden",children:V(vc,{palette:t,items:m,active:g,width:y,onPick:(b)=>{let k=d[b];if(k)a(k.name)}},void 0,!1,void 0,this)},void 0,!1,void 0,this),V(fe,{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 tp(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:m,onLeaveLatest:g,viewStart:x=0}=e,y=Yx(null),b=Yx(""),k=r===void 0?n:n.slice(-r),S=[...new Set(n.map((v)=>v.service))],N=Ay(o,S),K=Ey({width:o,serviceWidth:N,showTimestamps:d,showMeta:f});return Xu(()=>{let v=y.current;if(!v)return;if(v.stickyScroll=l,l)v.stickyStart="bottom",v.scrollTo({x:v.scrollLeft,y:Math.max(0,v.scrollHeight)})},[l,i]),Xu(()=>{let v=`${x}:${c}:${a}`;if(b.current===v)return;if(b.current=v,l&&(c<0||c>=k.length-1))return;let C=y.current;if(!C||c<0)return;let h=`log-row-${c}`,P=requestAnimationFrame(()=>{C.stickyScroll=!1,C.scrollChildIntoView(h)});return()=>cancelAnimationFrame(P)},[l,c,k.length,x,a]),Xu(()=>{if(!l||!g)return;let v=!1,C=setTimeout(()=>{v=!0},yE),h=setInterval(()=>{let P=y.current;if(!v||!P)return;let H=P.viewport.height;if(H>0&&P.scrollTop+H<P.scrollHeight-xE)g()},vE);return()=>{clearTimeout(C),clearInterval(h)}},[l,i,g]),V("box",{flexGrow:1,height:"100%",overflow:"hidden",children:V("scrollbox",{ref:y,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:V("box",{flexDirection:"column",overflow:"hidden",children:k.map((v,C)=>V(bE,{id:`log-row-${C}`,palette:t,event:v,serviceWidth:N,msgWidth:K,expanded:_y(a,C===c),active:C===c,showTimestamps:d,showMeta:f,onPick:m?()=>m(C):void 0},`${v.timestamp}-${v.service}-${C}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function bE(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=Cy(ac(r.message,i),i,s);return V("box",{id:t,flexShrink:0,flexDirection:"column",overflow:"hidden",backgroundColor:a?n.highlight:void 0,onMouseDown:d,children:f.visible.map((m,g)=>V("box",{height:1,flexDirection:"row",overflow:"hidden",children:[c?V("box",{width:ic,flexShrink:0,overflow:"hidden",children:V("text",{fg:n.muted,children:g===0?r.timestamp.slice(11,19):""},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,V("box",{width:o,flexShrink:0,overflow:"hidden",children:V("text",{fg:g===0?je(r.service,n):n.muted,wrapMode:"none",children:g===0?z(r.service,o):""},void 0,!1,void 0,this)},void 0,!1,void 0,this),V("box",{width:Ui,flexShrink:0,overflow:"hidden",children:V("text",{children:" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),V("box",{width:sc,flexShrink:0,overflow:"hidden",children:V("text",{fg:g===0?Te(n,r.level):n.muted,children:g===0?String(r.level):""},void 0,!1,void 0,this)},void 0,!1,void 0,this),l?V("box",{width:rc,flexShrink:0,overflow:"hidden",children:V("text",{fg:n.muted,children:g===0&&r.source?z(r.source,rc):""},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,V("box",{width:Ui,flexShrink:0,overflow:"hidden",children:V("text",{fg:n.muted,children:g===0?" ":"\u2502"},void 0,!1,void 0,this)},void 0,!1,void 0,this),V("box",{flexGrow:1,overflow:"hidden",children:V(wE,{palette:n,level:r.level,text:m,mark:g===0?f.mark:""},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},`${r.timestamp}-${g}`,!0,void 0,this))},void 0,!1,void 0,this)}function wE(e){let{palette:t,level:n,text:r,mark:o}=e;return V("text",{wrapMode:"none",children:[Ry(r).map((i,s)=>V("span",{fg:Qh(t,n,i.kind),children:i.text},`${i.kind}-${s}`,!1,void 0,this)),o===""?null:V("span",{fg:t.muted,children:o},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var yE=400,vE=200,xE=2;var np=D(()=>{Pt();at();Ae();xe();Qe()});import{jsxDEV as de}from"@opentui/react/jsx-dev-runtime";function Zx(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:m,followTick:g,logService:x,logSources:y,errorOnly:b,showSystemLogs:k,onOpen:S,onSelectIndex:N,onToggle:K,onFilterService:v,onToggleErrors:C,onToggleSystemLogs:h,onClearLogs:P,onShowErrors:H,wrapMode:Q="clip",view:ae,follow:we=!0,onLeaveLatest:ze,onPickLog:Ke,viewStart:ce=0,viewTotal:Ie,newer:qe=0,onJumpLatest:ue,facets:_e}=e,Ee=ne();if(!n||i.length===0)return de($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 G=f<ko,Fe=Eo(r),ft=uc(r,i),Ne=i.filter((Fr)=>r?.services[Fr]?.state==="FAILED").length,Et=r?.session_id?Rs(r.session_id):void 0,gt=Et?Ro(Date.now()-Et.getTime()):void 0,en=iv(o),mt=l||lc(n),tn=Ev(n,mt),ht=cc(f,i,G),$r=Math.max(24,G?f-4:f-ht-4),Mc=k?o:o.filter((Fr)=>!zi(Fr.source)),R=To(o,{service:x,errorOnly:b,systemLogs:k}),nn=ae??R,Yn=Ie??R.length,Ir=Math.min(Yn,ce+nn.length),$c=Yn===0?"empty":`${ce+1}\u2013${Ir} of ${Yn}`,Ic=x===""?"all services":x;return de("box",{flexGrow:1,flexDirection:G?"column":"row",overflow:"hidden",children:[de("box",{flexGrow:G?1:0,flexShrink:0,minWidth:G?void 0:ht,width:G?void 0:ht,border:!0,borderStyle:"rounded",borderColor:Fe?t.border:t.borderActive,backgroundColor:t.panel,title:"services",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[de(We,{palette:t,items:[{text:$u(ft.running,i.length),tone:ft.running>0?"success":"idle"},...Ne>0?[{text:`${Ne} failed`,tone:"error"}]:[],...c.length>0?[{text:`${c.length} selected`,tone:"primary"}]:[],...gt!==void 0?[{text:`up ${gt}`,tone:"idle"}]:[],...en>0?[{text:`${en} errors`,tone:"error",onMouseDown:H}]:[]]},void 0,!1,void 0,this),de(Pc,{palette:t,checked:c,idle:Fe,profileName:mt,members:tn},void 0,!1,void 0,this),de("box",{flexGrow:1,paddingLeft:Ee.pad,paddingRight:Ee.pad,overflow:"hidden",children:de(_c,{palette:t,names:i,snap:r,selected:s,checked:c,width:oc(ht,Ee.pad),onOpen:S,onSelectIndex:N,onToggle:K},void 0,!1,void 0,this)},void 0,!1,void 0,this),de(PE,{palette:t,names:i,snap:r,width:ht,onOpen:S},void 0,!1,void 0,this),de(RE,{palette:t,cfg:n,snap:r,google:d,width:ht},void 0,!1,void 0,this)]},void 0,!0,void 0,this),de("box",{position:"relative",flexGrow:2,minWidth:G?void 0:32,minHeight:G?8:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,backgroundColor:t.panel,title:`logs \xB7 ${$c}`,titleColor:t.primary,overflow:"hidden",flexDirection:"column",children:[de(We,{palette:t,items:[{text:m?"PAUSED":"LIVE",tone:m?"warning":"success"},{text:`shown ${R.length}`,tone:"info"},{text:_e?`total ${_e.total}`:`total ${o.length}`},{text:Ic,tone:x===""?"idle":"primary"},{text:b?"ERROR+":"all levels",tone:b?"error":"idle",onMouseDown:C},{text:k?"system: on":"system: off",tone:k?"accent":"idle",onMouseDown:h},{text:"clear",tone:"muted",onMouseDown:P}]},void 0,!1,void 0,this),de(ep,{palette:t,logs:Mc,names:y??i,service:x,errorOnly:b,width:$r,onService:v,onToggleErrors:C,facets:_e},void 0,!1,void 0,this),Yn>nn.length?de(Qu,{palette:t,start:ce,count:nn.length,total:Yn},void 0,!1,void 0,this):null,R.length===0?de($e,{palette:t,title:Fe?"Waiting for logs":o.length===0?"No events yet":"No events in this filter",body:Fe?"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):de(tp,{palette:t,logs:nn,width:$r,followTick:g,focused:!1,wrapMode:Q,selected:a,follow:we,onLeaveLatest:ze,onPick:Ke,viewStart:ce},g,!1,void 0,this),de(Be,{palette:t,backgroundColor:t.element,edge:"top",children:de(Le,{palette:t,hints:Co([{key:"e",label:"errors"},{key:"i",label:k?"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,$r-2))},void 0,!1,void 0,this)},void 0,!1,void 0,this),!we?de(Zu,{palette:t,width:$r,newer:qe,bottom:1,onJump:ue},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)]},void 0,!0,void 0,this)}function CE(e){if(!e)return!1;return e.state===yr||e.health===ke||e.state===_i||e.restarts>0||e.last_error!==""}function Qx(e){if(e.state===yr)return 0;if(e.health===ke)return 1;if(e.state===_i)return 2;return 3}function _E(e){if(e.last_error!=="")return e.last_error;if(e.restarts>0)return`restarted ${e.restarts}x, no error recorded`;return e.health===ke?"failing health check":e.state.toLowerCase()}function PE(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)=>CE(d.rt)).sort((d,f)=>Qx(d.rt)-Qx(f.rt));if(s.length===0)return null;let a=s.slice(0,kE),c=s.length-a.length,l=Math.max(8,o-rp-4);return de("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 m=Nt(f);return de("box",{height:1,flexDirection:"row",overflow:"hidden",onMouseDown:()=>i(d),children:[de("box",{width:2,flexShrink:0,children:de("text",{fg:Te(t,m),children:Ot(m)},void 0,!1,void 0,this)},void 0,!1,void 0,this),de("box",{width:rp,flexShrink:0,overflow:"hidden",children:de("text",{fg:je(d,t),wrapMode:"none",children:z(d,rp)},void 0,!1,void 0,this)},void 0,!1,void 0,this),de("box",{width:l,flexShrink:0,overflow:"hidden",children:de("text",{fg:t.muted,wrapMode:"none",children:le(_E(f),l)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},d,!0,void 0,this)}),c>0?de("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 RE(e){let{palette:t,cfg:n,snap:r,google:o,width:i}=e,s=o?.userEmail,a=Ao(n,r?.identity,o).project,c=r?.logs.total??0,l=Tv(s,a,c,i);return de(Be,{palette:t,backgroundColor:t.element,edge:"top",children:de("box",{height:1,flexDirection:"row",overflow:"hidden",backgroundColor:t.element,children:l.map((d,f)=>de(fe,{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 kE=4,rp=14;var eb=D(()=>{Ae();at();xe();Pt();Qe();vr();Xe();Yu();np()});import{useEffect as EE,useState as TE}from"react";import{jsxDEV as J}from"@opentui/react/jsx-dev-runtime";function nb(e){let{palette:t,report:n,loading:r,progress:o,error:i,selected:s,onPick:a,onReload:c}=e,l=Lo(s,op);if(r)return J(AE,{palette:t,progress:o},void 0,!1,void 0,this);if(i)return J(Fv,{palette:t,title:"Doctor failed",body:i},void 0,!1,void 0,this);if(!n)return J($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((b)=>b.severity==="ok").length,f=n.checks.filter((b)=>b.severity==="warn").length,m=n.checks.filter((b)=>b.severity==="error").length,g=n.checks.length,x=Ji(g>0?d/g:0),y=m>0?t.error:f>0?t.warning:t.success;return J(nt,{palette:t,title:`doctor ${n.issues} issue(s)`,children:[J("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:[J("text",{wrapMode:"none",children:[J("span",{fg:t.inverse,bg:t.primary,children:" r "},void 0,!1,void 0,this),J("span",{fg:t.primary,children:" RUN DOCTOR AGAIN"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),J("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),J("box",{height:1,flexShrink:0},void 0,!1,void 0,this),J("box",{height:1,flexShrink:0,overflow:"hidden",children:J("text",{wrapMode:"none",children:[J("span",{fg:y,children:`[${x}]`},void 0,!1,void 0,this),J("span",{fg:t.success,children:` ${d} ok`},void 0,!1,void 0,this),f>0?J("span",{fg:t.warning,children:` \xB7 ${f} warn`},void 0,!1,void 0,this):null,m>0?J("span",{fg:t.error,children:` \xB7 ${m} error`},void 0,!1,void 0,this):null,f===0&&m===0?J("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),J("box",{height:1,flexShrink:0},void 0,!1,void 0,this),J("scrollbox",{ref:l,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:J("box",{flexDirection:"column",overflow:"hidden",gap:1,children:n.checks.map((b,k)=>J(LE,{palette:t,check:b,index:k,active:k===s,onPick:a},`${b.name}-${k}`,!1,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function AE({palette:e,progress:t}){let[n,r]=TE(0);return EE(()=>{let o=setInterval(()=>r((i)=>(i+1)%tb.length),120);return()=>clearInterval(o)},[]),J("box",{flexGrow:1,alignItems:"center",justifyContent:"center",overflow:"hidden",children:J("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:[J("text",{wrapMode:"none",children:[J("span",{fg:e.primary,children:`${tb[n]} `},void 0,!1,void 0,this),J("span",{fg:e.text,children:"devctl doctor"},void 0,!1,void 0,this)]},void 0,!0,void 0,this),J("box",{height:1,flexShrink:0},void 0,!1,void 0,this),J("text",{fg:e.text,wrapMode:"none",children:`Checking ${t.active}`},void 0,!1,void 0,this),J("box",{height:1,flexShrink:0},void 0,!1,void 0,this),t.checks.slice(-4).map((o,i)=>J("text",{wrapMode:"none",children:[J("span",{fg:Te(e,o.severity==="error"?"ERROR":o.severity==="warn"?"WARN":"OK"),children:`${Ot(o.severity==="error"?"ERROR":o.severity==="warn"?"WARN":"OK")} `},void 0,!1,void 0,this),J("span",{fg:e.muted,children:o.name},void 0,!1,void 0,this)]},`${o.name}-${i}`,!0,void 0,this)),t.checks.length===0?J("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 LE(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 J("box",{id:`${op}-${r}`,flexDirection:"row",flexShrink:0,paddingLeft:1,overflow:"hidden",backgroundColor:o?t.highlight:void 0,onMouseDown:()=>i(r),children:J("text",{wrapMode:"none",children:[J("span",{fg:t.primary,children:o?"\u203A ":" "},void 0,!1,void 0,this),J("span",{fg:Te(t,s),children:Ot(s)},void 0,!1,void 0,this),J("span",{fg:o?t.primary:t.text,children:` ${n.name}`},void 0,!1,void 0,this),J("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 J("box",{id:`${op}-${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:[J("text",{wrapMode:"word",children:[J("span",{fg:Te(t,s),children:`${Ot(s)} `},void 0,!1,void 0,this),J("span",{fg:t.text,children:n.message},void 0,!1,void 0,this)]},void 0,!0,void 0,this),n.hint?J("text",{fg:t.info,wrapMode:"word",children:`\u2192 ${n.hint}`},void 0,!1,void 0,this):null,o&&n.action?.kind==="free-port"?J("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 op="doctor-row",tb;var rb=D(()=>{Pt();Ae();xe();Qe();tb=["\u25D0","\u25D3","\u25D1","\u25D2"]});import{jsxDEV as Re}from"@opentui/react/jsx-dev-runtime";function ib(e){let{palette:t,cfg:n,snap:r,profile:o,selected:i,onPick:s}=e,a=ne(),c=Lo(i,ob),l=Object.keys(n?.profiles??{}).sort();if(l.length===0)return Re($e,{palette:t,title:"No profiles",body:"Add profiles.<name>.services in config.yaml."},void 0,!1,void 0,this);return Re(nt,{palette:t,title:"profiles",children:[Re("box",{height:1,flexShrink:0,overflow:"hidden",children:Re("text",{fg:t.muted,wrapMode:"none",children:[`${l.length} profile${l.length===1?"":"s"} \xB7 current: `,Re("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),Re("box",{height:1,flexShrink:0},void 0,!1,void 0,this),Re("scrollbox",{ref:c,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:Re("box",{flexDirection:"column",overflow:"hidden",gap:a.gap||1,children:l.map((d,f)=>{let m=d===o,g=f===i,x=n?.profiles[d]?.services??[],y=Object.keys(n?.profiles[d]?.environment??{}).length,b=g?t.borderActive:m?t.success:t.border,k=g?t.primary:m?t.success:t.muted;return Re("box",{id:`${ob}-${f}`,border:!0,borderStyle:"rounded",borderColor:b,title:d,titleColor:k,flexDirection:"column",flexShrink:0,paddingLeft:1,paddingRight:1,overflow:"hidden",backgroundColor:g?t.highlight:void 0,onMouseDown:()=>s(f),children:[Re("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:Re("text",{wrapMode:"none",children:[m?Re("span",{fg:t.success,children:"\u25CF current profile"},void 0,!1,void 0,this):Re("span",{fg:t.muted,children:"\u25CB not active"},void 0,!1,void 0,this),Re("span",{fg:t.muted,children:` \xB7 ${x.length} service${x.length===1?"":"s"}`},void 0,!1,void 0,this),y>0?Re("span",{fg:t.muted,children:` \xB7 ${y} env var${y===1?"":"s"}`},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)},void 0,!1,void 0,this),Re("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:x.length===0?Re("text",{fg:t.muted,wrapMode:"none",children:"(no services)"},void 0,!1,void 0,this):Re("text",{wrapMode:"none",children:x.map((S,N)=>{let K=Nt(r?.services[S]);return Re("span",{children:[Re("span",{fg:Te(t,K),children:Ot(K)},void 0,!1,void 0,this),Re("span",{fg:je(S,t),children:` ${S}`},void 0,!1,void 0,this),N<x.length-1?Re("span",{fg:t.muted,children:" "},void 0,!1,void 0,this):null]},S,!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),Re(Be,{palette:t,backgroundColor:t.element,edge:"top",children:Re(Le,{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 ob="profile-row";var sb=D(()=>{Pt();at();Ae();xe();Qe()});import{jsxDEV as B,Fragment as db}from"@opentui/react/jsx-dev-runtime";function DE(e){let t=e.toLowerCase();if(t==="iap")return"info";if(t==="service"||t==="service_account")return"primary";return"idle"}function OE(e,t,n){if(n||t>=500)return e.error;if(t===0||t>=400)return e.warning;return e.success}function ME(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 NE(e){let{palette:t,req:n,cols:r}=e,o=OE(t,n.status,n.error),i=n.status>0?String(n.status):"ERR",s=ME(t,n.identity),a=n.route||ub,c=n.error?`${n.path} \u2014 ${le(n.error,FE)}`:n.path;return B("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[B("box",{width:ip,flexShrink:0,overflow:"hidden",children:B("text",{fg:t.muted,children:n.timestamp.slice(11,19)},void 0,!1,void 0,this)},void 0,!1,void 0,this),r.showMethod?B("box",{width:Rc,flexShrink:0,overflow:"hidden",children:B("text",{fg:t.text,wrapMode:"none",children:z(n.method,Rc)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,B("box",{width:Ec,flexShrink:0,overflow:"hidden",children:B("text",{fg:o,wrapMode:"none",children:z(i,Ec)},void 0,!1,void 0,this)},void 0,!1,void 0,this),r.showDur?B("box",{width:Tc,flexShrink:0,overflow:"hidden",children:B("text",{fg:t.muted,wrapMode:"none",children:z(`${n.durationMs}ms`,Tc)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,B("box",{width:Ac,flexShrink:0,overflow:"hidden",children:B("text",{fg:s.color,wrapMode:"none",children:z(s.label,Ac)},void 0,!1,void 0,this)},void 0,!1,void 0,this),B("box",{width:r.routeCol,flexShrink:0,overflow:"hidden",children:B("text",{fg:n.route?t.info:t.muted,wrapMode:"none",children:z(a,r.routeCol)},void 0,!1,void 0,this)},void 0,!1,void 0,this),B("box",{flexGrow:1,overflow:"hidden",children:B("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 HE(e){let{palette:t,cols:n}=e;return B("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:t.element,children:[B("box",{width:ip,flexShrink:0,overflow:"hidden",children:B("text",{fg:t.muted,children:z("TIME",ip)},void 0,!1,void 0,this)},void 0,!1,void 0,this),n.showMethod?B("box",{width:Rc,flexShrink:0,overflow:"hidden",children:B("text",{fg:t.muted,children:z("METHOD",Rc)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,B("box",{width:Ec,flexShrink:0,overflow:"hidden",children:B("text",{fg:t.muted,children:z("ST",Ec)},void 0,!1,void 0,this)},void 0,!1,void 0,this),n.showDur?B("box",{width:Tc,flexShrink:0,overflow:"hidden",children:B("text",{fg:t.muted,children:z("DUR",Tc)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,B("box",{width:Ac,flexShrink:0,overflow:"hidden",children:B("text",{fg:t.muted,children:z("WHO",Ac)},void 0,!1,void 0,this)},void 0,!1,void 0,this),B("box",{width:n.routeCol,flexShrink:0,overflow:"hidden",children:B("text",{fg:t.muted,children:z("ROUTE",n.routeCol)},void 0,!1,void 0,this)},void 0,!1,void 0,this),B("box",{flexGrow:1,overflow:"hidden",children:B("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 jE(e){let{palette:t,name:n,auth:r,identity:o,upstream:i,match:s,onMouseDown:a}=e;return B("box",{flexDirection:"column",flexShrink:0,overflow:"hidden",onMouseDown:a,children:[B("text",{fg:t.text,wrapMode:"none",children:n},void 0,!1,void 0,this),B("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:[B(fe,{palette:t,label:r||"no auth",tone:DE(r)},void 0,!1,void 0,this),o?B(fe,{palette:t,label:o,tone:"idle"},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),s?B("text",{fg:t.muted,wrapMode:"none",children:`match: ${s}`},void 0,!1,void 0,this):null,B("text",{fg:t.muted,wrapMode:"none",children:`\u2192 ${i}`},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function pb(e){let{palette:t,cfg:n,snap:r,width:o,onSelectRoute:i}=e,s=r?.proxy.routes??[],a=new Map((n?.proxy.routes??[]).map((v)=>[v.name,v])),c=new Map((n?.proxy.routes??[]).map((v)=>[v.name,v.match])),l=r?.proxy.recentRequests??[],d=r?.proxy.requestTotal??0,f=r?.proxy.requestErrors??0,m=o<ko,g=Math.max(ab,Math.min(BE,Math.floor(o*0.36))),x=m?o-cb:o-g-cb,y=Math.max(20,x-2),b=y>=lb,k=y>=WE,S=y>=lb?GE:UE,N=l.reduce((v,C)=>Math.min(S,Math.max(v,(C.route||ub).length+IE)),$E),K={showMethod:b,showDur:k,routeCol:N};return B(nt,{palette:t,title:"proxy",children:[B(We,{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),B("box",{flexGrow:1,flexDirection:m?"column":"row",overflow:"hidden",children:[B("box",{flexGrow:m?1:0,flexBasis:m?0:void 0,flexShrink:0,minWidth:m?void 0:ab,width:m?void 0:g,minHeight:m?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?B($e,{palette:t,title:"No proxy routes",body:"Add routes under proxy.routes or .devctl/proxy/routes.yaml."},void 0,!1,void 0,this):B(db,{children:[i?B("text",{fg:t.muted,wrapMode:"word",children:"click a route for full details"},void 0,!1,void 0,this):null,B("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:B("box",{flexDirection:"column",overflow:"hidden",gap:1,children:s.map((v)=>{let C=c.get(v.name),h=C&&(C.host||C.path)?`${C.host||"*"}${C.path?C.path:""}`:void 0,P=a.get(v.name);return B(jE,{palette:t,name:v.name,auth:v.auth,identity:v.identity,upstream:v.upstream,match:h,onMouseDown:i?()=>i({name:v.name,authType:P?.auth.type||v.auth,identityType:P?.auth.identity.type??"",serviceAccount:P?.auth.identity.service_account||P?.auth.service_account||"",audience:P?.auth.audience??"",matchHost:P?.match.host??"",matchPath:P?.match.path??"",upstream:v.upstream}):void 0},v.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),B("box",{flexGrow:1,flexBasis:0,minWidth:m?void 0:30,minHeight:m?10:void 0,border:!0,borderStyle:"rounded",borderColor:t.borderActive,title:"requests",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:l.length===0?B("box",{paddingLeft:1,paddingRight:1,children:B("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):B(db,{children:[B(HE,{palette:t,cols:K},void 0,!1,void 0,this),B("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:B("box",{flexDirection:"column",overflow:"hidden",children:l.map((v)=>B(NE,{palette:t,req:v,cols:K},v.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),B(Be,{palette:t,backgroundColor:t.element,edge:"top",children:B(Le,{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 ip=9,Rc=8,Ec=4,Tc=8,Ac=4,$E=8,IE=2,FE=64,ub="(none)",ab=26,BE=42,cb=2,lb=46,WE=54,GE=20,UE=12;var fb=D(()=>{Pt();Ae();xe()});import{jsxDEV as te}from"@opentui/react/jsx-dev-runtime";function hb(e){let{palette:t,name:n}=e;return te("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:n,titleColor:je(n,t),flexDirection:"column",overflow:"hidden",children:te(sp,{...e,compact:!1},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function sp(e){let{palette:t,cfg:n,snap:r,name:o,reveal:i,width:s,compact:a=!0,envScrollRef:c}=e,l=ne(),d=n?.services[o];if(!d)return te($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],m=Nt(f),g=f?.health??"UNKNOWN",x=Dr(f)||Zi(d,f),y=_v(d,i,n?.secrets.extra_markers??[],n?.secrets.extra_patterns??[]),b=s>=qE,k=[{label:"health",value:mc(d)},{label:"workdir",value:d.working_dir||"."},{label:"restart",value:yc(d)},{label:"caps",value:d.capabilities.join(", ")||"\u2014"},{label:"runtime",value:d.container?`${d.container.runtime||"docker"} \xB7 ${d.container.image}`:"host"}],S=[{label:"identity",value:hc(d,f)},{label:"depends",value:d.dependencies.map(Ts).join(", ")||"\u2014"},{label:"ports",value:Zi(d,f)},{label:"tries",value:String(f?.restarts??0),tone:f?.restarts?"warning":"muted"}],N=Math.max(Mr+8,s-2),K=b?Math.floor(N/2):N;return te("box",{padding:l.pad,flexGrow:1,flexDirection:"column",overflow:"hidden",children:[te(We,{palette:t,items:[{text:m,tone:mb(m)},{text:g,tone:mb(g)},{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?te("box",{height:1,overflow:"hidden",children:te("text",{fg:t.muted,wrapMode:"none",children:le(d.description,Math.max(8,s-4))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,f?.last_error?te("box",{height:1,overflow:"hidden",children:te("text",{fg:t.error,wrapMode:"none",children:le(f.last_error,KE)},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,te(ap,{palette:t,item:{label:"command",value:gc(d)},valueWidth:Math.max(8,N-Mr)},void 0,!1,void 0,this),te(VE,{palette:t,left:k,right:S,wide:b,colWidth:K},void 0,!1,void 0,this),te(JE,{palette:t,entries:y,reveal:i,width:s,focused:!a,scrollRef:c},void 0,!1,void 0,this),a?null:te(Le,{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 VE(e){let{palette:t,left:n,right:r,wide:o,colWidth:i}=e,s=Math.max(4,i-Mr);if(!o)return te("box",{width:i,flexShrink:0,flexDirection:"column",overflow:"hidden",children:[...n,...r].map((a)=>te(ap,{palette:t,item:a,valueWidth:s},a.label,!1,void 0,this))},void 0,!1,void 0,this);return te("box",{height:n.length,flexShrink:0,flexDirection:"row",overflow:"hidden",children:[te(gb,{palette:t,items:n,width:i},void 0,!1,void 0,this),te(gb,{palette:t,items:r,width:i},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function gb(e){let t=Math.max(4,e.width-Mr);return te("box",{width:e.width,flexShrink:0,flexDirection:"column",overflow:"hidden",children:e.items.map((n)=>te(ap,{palette:e.palette,item:n,valueWidth:t},n.label,!1,void 0,this))},void 0,!1,void 0,this)}function ap(e){let{palette:t,item:n,valueWidth:r}=e,o=n.tone==="warning"?t.warning:n.tone==="muted"?t.muted:t.text;return te("box",{height:1,width:Mr+r,flexDirection:"row",overflow:"hidden",children:[te("box",{width:Mr,flexShrink:0,overflow:"hidden",children:te("text",{fg:t.muted,wrapMode:"none",children:z(n.label,Mr)},void 0,!1,void 0,this)},void 0,!1,void 0,this),te("box",{width:r,flexShrink:0,overflow:"hidden",children:te("text",{fg:o,wrapMode:"none",children:z(n.value,r)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function JE(e){let{palette:t,entries:n,reveal:r,width:o,focused:i,scrollRef:s}=e,a=Pv(o),c=Math.max(8,o-a-4);return te("box",{flexGrow:1,flexDirection:"column",overflow:"hidden",children:[te(We,{palette:t,items:[{text:`env ${n.length}`,tone:n.length>0?"info":"idle"},{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),n.length===0?te("text",{fg:t.muted,children:"no service env overrides"},void 0,!1,void 0,this):te("box",{flexGrow:1,height:"100%",overflow:"hidden",children:te("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:te("box",{flexDirection:"column",overflow:"hidden",children:n.map((l)=>te("box",{height:1,flexDirection:"row",overflow:"hidden",children:[te("box",{width:a,flexShrink:0,overflow:"hidden",children:te("text",{fg:l.required?t.warning:t.muted,wrapMode:"none",children:z(l.required?`${l.key}*`:l.key,a)},void 0,!1,void 0,this)},void 0,!1,void 0,this),te("box",{width:c,flexShrink:0,overflow:"hidden",children:te("text",{fg:l.value===""?t.muted:t.text,wrapMode:"none",children:z(l.value===""&&l.required?"(required)":l.value,c)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},l.key,!0,void 0,this))},void 0,!1,void 0,this)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function mb(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 KE=72,qE=56,Mr=9;var cp=D(()=>{Ae();Pt();at();xe();Qe();st()});import{jsxDEV as zn}from"@opentui/react/jsx-dev-runtime";function yb(e){let{palette:t,cfg:n,names:r,snap:o,selected:i,checked:s,width:a,reveal:c,onOpen:l,onSelectIndex:d,onToggle:f}=e;if(r.length===0)return zn($e,{palette:t,title:"No services",body:"This configuration does not define any services."},void 0,!1,void 0,this);let m=a<ko,g=r[i]??"",x=cc(a,r,m),y=4,b=m?Math.max(lp,a-y):Math.max(lp,a-x-y);return zn("box",{flexGrow:1,flexDirection:m?"column":"row",overflow:"hidden",children:[zn("box",{flexGrow:m?1:0,flexShrink:0,minWidth:m?void 0:Ya,width:m?void 0:x,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:"services",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[zn(Pc,{palette:t,checked:s,idle:Eo(o),profileName:"",members:""},void 0,!1,void 0,this),zn("box",{flexGrow:1,overflow:"hidden",children:zn(_c,{palette:t,names:r,snap:o,selected:i,checked:s,width:oc(x),onOpen:l,onSelectIndex:d,onToggle:f},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this),zn("box",{flexGrow:2,minWidth:m?void 0:lp,minHeight:m?zE:void 0,border:!0,borderStyle:"rounded",borderColor:t.border,backgroundColor:t.panel,title:g||"detail",titleColor:g?je(g,t):t.primary,overflow:"hidden",flexDirection:"column",children:zn(sp,{palette:t,cfg:n,snap:o,name:g,reveal:c,width:b},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var lp=36,zE=12;var vb=D(()=>{Pt();Ae();Qe();cp();Yu()});import{jsxDEV as me}from"@opentui/react/jsx-dev-runtime";function XE(e){switch(e){case"cycle":return"\u2194";case"toggle":return"\u23FB";case"page":return"\u25B8";case"action":return"!";default:return"\xB7"}}function Sb(e){let{palette:t,items:n,selected:r,locked:o,width:i,onPick:s,onActivate:a}=e,c=ne(),l=yu(n,r),d=So(n,l);return me("box",{flexGrow:1,border:!0,borderStyle:"rounded",borderColor:t.borderActive,backgroundColor:t.panel,title:"settings",titleColor:t.primary,flexDirection:"column",overflow:"hidden",children:[me("box",{height:2,paddingLeft:c.pad,flexShrink:0,flexDirection:"column",overflow:"hidden",children:[me("text",{fg:t.primary,wrapMode:"none",children:"Preferences"},void 0,!1,void 0,this),me("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),me("box",{flexGrow:1,paddingLeft:c.pad,paddingRight:c.pad,overflow:"hidden",flexShrink:1,children:me(QE,{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),me(eT,{palette:t,item:d,scale:c},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function QE(e){let{palette:t,items:n,active:r,scale:o,width:i,onPick:s,onActivate:a}=e,c=Lo(r,wb),l=Math.max(8,i-xb-bb-10),d=0,f=sy(n);return me("scrollbox",{ref:c,focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:me("box",{flexDirection:"column",overflow:"hidden",children:f.map((m,g)=>{let x=d;d+=m.items.length;let y=r>=x&&r<x+m.items.length;return me("box",{border:!0,borderStyle:"rounded",borderColor:y?t.borderActive:t.border,title:`${m.group} (${m.items.length})`,titleColor:y?t.primary:t.muted,flexDirection:"column",flexShrink:0,marginBottom:g<f.length-1?Math.max(1,o.gap):0,paddingLeft:1,paddingRight:1,overflow:"hidden",children:[m.group==="MCP"?me("box",{height:1,overflow:"hidden",children:me("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,m.items.map((b,k)=>{let S=x+k;return me(ZE,{index:S,palette:t,item:b,active:S===r,rowH:o.rowH,valueWidth:l,onPick:()=>s(S),onActivate:()=>a(b)},b.id,!1,void 0,this)})]},m.group,!0,void 0,this)})},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function ZE(e){let{palette:t,index:n,item:r,active:o,rowH:i,valueWidth:s,onPick:a,onActivate:c}=e;return me("box",{id:`${wb}-${n}`,height:i,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:o?t.highlight:void 0,onMouseDown:()=>{if(o){c();return}a()},children:[me("box",{width:2,flexShrink:0,overflow:"hidden",children:me("text",{fg:t.primary,children:o?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("box",{width:bb,flexShrink:0,overflow:"hidden",children:me("text",{fg:o?t.primary:t.muted,children:XE(r.kind)},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("box",{width:xb,flexShrink:0,overflow:"hidden",children:me("text",{fg:o?t.primary:t.text,wrapMode:"none",children:r.name},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("box",{flexGrow:1,overflow:"hidden",children:me("text",{fg:tT(t,r,o),wrapMode:"none",children:le(r.value,s)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function eT(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 me("box",{height:YE,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:[me("box",{height:1,overflow:"hidden",children:me("text",{fg:t.primary,wrapMode:"none",children:o?`${oy(r.steps)} ${r.label}`:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("box",{height:1,overflow:"hidden",children:me("text",{fg:t.text,wrapMode:"word",children:n?.detail??""},void 0,!1,void 0,this)},void 0,!1,void 0,this),me("box",{height:1,overflow:"hidden",children:me("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 tT(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 xb=14,bb=2,YE=5,wb="settings-row";var kb=D(()=>{at();Ae();xe();vn()});import{useEffect as nT,useState as rT}from"react";import{jsxDEV as q}from"@opentui/react/jsx-dev-runtime";function Mo(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 q("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 dp(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 ts(e){let{palette:t,cells:n,header:r,gap:o=0,stripe:i}=e;return q("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,backgroundColor:i?t.element:void 0,children:n.map((s,a)=>q("box",{flexDirection:"row",flexShrink:0,overflow:"hidden",children:[a>0&&o>0?q("box",{width:o,flexShrink:0},void 0,!1,void 0,this):null,q("box",{width:s.width,flexShrink:0,overflow:"hidden",children:q("text",{fg:r?t.primary:dp(t,s),wrapMode:"none",children:z(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 Cb(e){let{palette:t,width:n}=e;return q("box",{height:1,flexShrink:0,overflow:"hidden",children:q("text",{fg:t.border,wrapMode:"none",children:z("\u2500".repeat(Math.max(1,n)),n)},void 0,!1,void 0,this)},void 0,!1,void 0,this)}function es(e){let{palette:t,facts:n,width:r}=e,o=Mu(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}),q("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[q(ts,{palette:t,header:!0,gap:Po,cells:i},void 0,!1,void 0,this),q(Cb,{palette:t,width:r},void 0,!1,void 0,this),n.map((s,a)=>{let c=s.meaning===""?[""]:ac(s.meaning,Math.max(1,o.meaning)),l=s.meter?Gy(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"}),q("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[q(ts,{palette:t,gap:Po,stripe:a%2===1,cells:d},void 0,!1,void 0,this),c.slice(1).map((f,m)=>{let g=[{text:"",width:o.what},{text:"",width:o.reading}];if(o.meter>0)g.push({text:"",width:o.meter});return g.push({text:f,width:o.meaning,tone:"muted"}),q(ts,{palette:t,gap:Po,stripe:a%2===1,cells:g},`${s.what}-more-${m}`,!1,void 0,this)})]},`${s.what}-${s.reading}-${a}`,!0,void 0,this)})]},void 0,!0,void 0,this)}function _b(e){let{palette:t,cfg:n,snap:r,width:o,onRefresh:i}=e,s=ne(),[,a]=rT(0);if(nT(()=>{let qe=setInterval(()=>{a((ue)=>{let _e=ue+1;if(i&&_e%iT===0)i();return _e})},oT);return()=>clearInterval(qe)},[i]),!n)return q($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((qe)=>Uy(n.services[qe])),d=Iy(c,r),f=Xy(d,l),m=l&&d.live>0?d.healthy/d.live:d.total>0?d.live/d.total:0,g=Ji(m,sT),x=d.failed>0?"error":l&&d.live>0&&d.healthy<d.live?"warning":"success",y=jy(o,s.pad),b=r?.session_id?Rs(r.session_id):void 0,k=b?Ro(Date.now()-b.getTime()):"just started",S=r?.logs.total??0,N=r?.logs.errors??0,K=Hy(r?.logs.counts??{}),v=r?.proxy.routes??[],C=r?.credentials,h=(C?.entries??[]).filter((qe)=>qe.valid).length,P=r?.system,H=P?P.memAvailableKB??P.memFreeKB:0,Q=P?qy(P.loadAvg1,P.cpuCount):void 0,ae=P?Vy(H,P.memTotalKB):void 0,we=[];if(P&&Q&&ae)we.push(Q,ae,{what:"Computer",reading:Ky(P.platform),meaning:`on for ${Ro(P.hostUptimeSec*aT)}`,tone:"text"});let ze=d.failed>0||Q?.tone==="error"||ae?.tone==="error"?"error":x==="warning"||Q?.tone==="warning"||ae?.tone==="warning"?"warning":"success",Ke=[{what:"This session",reading:k,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"}],ce=[{what:"Lines kept",reading:String(S),meaning:"log lines still in memory",tone:"text"},{what:"Error lines",reading:String(N),meaning:N>0?"open Logs and press e to see only errors":"no ERROR or FATAL lines",tone:N>0?"error":"muted"},...K.map(([qe,ue])=>({what:qe,reading:String(ue),meaning:"lines from this service",tone:"text"}))],Ie=[{what:"Web proxy",reading:r?.proxy.running?"on":"off",meaning:r?.proxy.running?`${v.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:C?`${h} of ${C.entries.length} good`:"none",meaning:C?Yy(C.backend):"nothing stored yet",tone:C&&h<C.entries.length?"warning":C?"success":"muted"}];return q(nt,{palette:t,title:"stats",scroll:!0,children:[q(Mo,{palette:t,title:`Your services ${d.live} of ${d.total} started`,tone:ze,children:[q(es,{palette:t,facts:f,width:y},void 0,!1,void 0,this),q("box",{height:1,flexShrink:0},void 0,!1,void 0,this),q("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:q("text",{wrapMode:"none",children:[q("span",{fg:t.muted,children:z(l?"Ready":"Started",Mu(f,y).what)},void 0,!1,void 0,this),q("span",{children:" ".repeat(Po)},void 0,!1,void 0,this),q("span",{fg:dp(t,{text:"",width:1,tone:x}),children:`[${g}]`},void 0,!1,void 0,this),q("span",{fg:dp(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),P?q(Mo,{palette:t,title:"This computer",tone:Q?.tone==="error"||ae?.tone==="error"?"error":Q?.tone==="warning"||ae?.tone==="warning"?"warning":"success",children:q(es,{palette:t,facts:we,width:y},void 0,!1,void 0,this)},void 0,!1,void 0,this):null,q(Mo,{palette:t,title:"This session",children:q(es,{palette:t,facts:Ke,width:y},void 0,!1,void 0,this)},void 0,!1,void 0,this),q(Mo,{palette:t,title:"Each service",tone:d.failed>0?"error":l&&d.live>0&&d.healthy<d.live?"warning":"success",children:d.total===0?q("text",{fg:t.muted,children:"No services in this project yet."},void 0,!1,void 0,this):q("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[q(cT,{palette:t,names:c,snap:r,width:y},void 0,!1,void 0,this),q("box",{height:1,flexShrink:0},void 0,!1,void 0,this),q("text",{fg:t.muted,wrapMode:"none",children:z("CPU is % of one core. RAM is what that process is holding now.",y)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this),q(Mo,{palette:t,title:"Log lines",tone:N>0?"warning":"muted",children:q(es,{palette:t,facts:ce,width:y},void 0,!1,void 0,this)},void 0,!1,void 0,this),q(Mo,{palette:t,title:"Other parts",children:q(es,{palette:t,facts:Ie,width:y},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function cT(e){let{palette:t,names:n,snap:r,width:o}=e,i=By(o),s=[{text:"service",width:i.name},{text:"status",width:Xt}];if(i.health)s.push({text:"check",width:xn});if(i.cpu)s.push({text:"cpu",width:ec});if(i.mem)s.push({text:"ram",width:tc});if(i.up)s.push({text:"up",width:Za});if(i.rst)s.push({text:"restarts",width:pc});if(i.pid)s.push({text:"pid",width:Un});return q("box",{flexDirection:"column",overflow:"hidden",flexShrink:0,children:[q(ts,{palette:t,header:!0,gap:xt,cells:s},void 0,!1,void 0,this),q(Cb,{palette:t,width:o},void 0,!1,void 0,this),n.map((a,c)=>q(pT,{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 uT(e){if(e===void 0)return"muted";if(e>dT)return"error";if(e>lT)return"warning";return"text"}function pT(e){let{palette:t,name:n,rt:r,cols:o,stripe:i}=e,s=Jy(r),a=zy(r),c=r?.restarts??0,l=[{text:n,width:o.name,color:je(n,t)},{text:s,width:Xt,color:Te(t,r?.state??"STOPPED")}];if(o.health)l.push({text:a,width:xn,color:Te(t,r?.health??"UNKNOWN")});if(o.cpu)l.push({text:r?.cpuPercent!==void 0?Qy(r.cpuPercent):"\u2014",width:ec,tone:uT(r?.cpuPercent)});if(o.mem)l.push({text:r?.memoryKB!==void 0?Xa(r.memoryKB):"\u2014",width:tc,tone:"text"});if(o.up)l.push({text:Ny(r),width:Za,tone:"text"});if(o.rst)l.push({text:String(c),width:pc,tone:c>0?"warning":"muted"});if(o.pid)l.push({text:r?.pid?String(r.pid):"\u2014",width:Un,tone:"muted"});return q("box",{flexDirection:"column",flexShrink:0,overflow:"hidden",children:[q(ts,{palette:t,gap:xt,stripe:i,cells:l},void 0,!1,void 0,this),r?.last_error?q("box",{height:1,flexDirection:"row",overflow:"hidden",flexShrink:0,children:q("text",{fg:t.error,wrapMode:"none",children:z(` ${r.last_error}`,Math.max(24,o.name+xt+Xt+xn))},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this)}var oT=1000,iT=5,sT=16,aT=1000,lT=80,dT=100;var Pb=D(()=>{Pt();Ae();at();xe();Qe();Xe()});import{jsxDEV as ye}from"@opentui/react/jsx-dev-runtime";function Rb(e){let{palette:t,cfg:n,google:r,bootError:o,bootErrorMissing:i=!1,step:s=0}=e,a=ne();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?Jt(n):["configuration not loaded"],l=fT(n,r,c),d=l.filter((S)=>S.ok).length,f=l.length,m=f>0?Math.round(d/f*100):0,g=20,x=Math.round(m/100*g),y="\u2588".repeat(x)+"\u2591".repeat(Math.max(0,g-x)),b=m===100?t.success:m===0?t.muted:t.primary,k=l[s];return ye(nt,{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:b,children:`[${y}]`},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:` (${m}%)`},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((S,N)=>{let K=N===s;return ye("box",{height:a.rowH,flexDirection:"row",overflow:"hidden",backgroundColor:K?t.highlight:void 0,paddingLeft:1,children:[ye("box",{width:2,flexShrink:0,children:ye("text",{fg:Te(t,S.ok?"OK":"WARN"),children:Ot(S.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:K?t.primary:t.muted,children:String(N+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:K?t.primary:t.text,children:S.name},void 0,!1,void 0,this)},void 0,!1,void 0,this),ye("box",{flexGrow:1,overflow:"hidden",children:ye("text",{fg:K?t.text:t.muted,wrapMode:"none",children:S.detail},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},S.name,!0,void 0,this)}),ye("box",{height:1,flexShrink:0},void 0,!1,void 0,this),k?ye("box",{border:!0,borderStyle:"rounded",borderColor:k.ok?t.success:t.warning,title:k.name,titleColor:k.ok?t.success:t.warning,flexDirection:"column",paddingLeft:1,paddingRight:1,flexShrink:0,overflow:"hidden",children:ye("text",{fg:k.ok?t.text:t.warning,wrapMode:"word",children:k.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(fe,{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(Le,{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 fT(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=Ao(e,void 0,t).project;return[{name:wn[0],ok:Boolean(e?.repoRoot),detail:e?.repoRoot||"unknown"},{name:wn[1],ok:Boolean(e?.project.name),detail:e?.project.name||"set project.name"},{name:wn[2],ok:Boolean(i),detail:i||"optional for local-only"},{name:wn[3],ok:t?.adcAvailable===!0,detail:t?.adcAvailable?"ADC available":"needed only for cloud identity / IAP"},{name:wn[4],ok:!0,detail:"read from configuration; never hard-coded"},{name:wn[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:wn[6],ok:r.length===0||Boolean(e),detail:`${r.length} fixed ports from configuration`},{name:wn[7],ok:Object.keys(e?.profiles??{}).length>0,detail:`${Object.keys(e?.profiles??{}).length} profile(s)`},{name:wn[8],ok:n.length===0,detail:n.length===0?"configuration is valid":n[0]??"invalid"}]}var wn;var Eb=D(()=>{st();Pt();at();xe();Ae();Qe();wn=["Repository","Environment","Google project","Authentication","Service accounts","IAP","Ports","Profiles","Validation"]});import{jsxDEV as W}from"@opentui/react/jsx-dev-runtime";function gp(){return Xd.flatMap((e)=>Ta.filter((t)=>t.category===e))}function Dc(){return Lc+gp().length}function Lb(){return Dc()+Ab}function Oc(e){if(e<Lc||e>=Dc())return;return gp()[e-Lc]}function mp(e){let t=e-Dc();return t>=0&&t<Ab?t:void 0}function Db(e){let{palette:t,snap:n,port:r,portDraft:o="",selected:i,onPick:s,onToggle:a,onCopy:c,onToggleTool:l}=e,d=ne(),f=n?.mcp?.running===!0,m=n?.mcp?.port??r,g=n?.mcp?.address??bo(m),x=n?.mcp?.token??"",y=Fi(g,x),b=n?.mcp?.disabled_tools??[],k=gp(),S=k.filter((v)=>!Bn(v.name,b)).length,N=y[mp(i)??-1],K=N??y[0];return W(nt,{palette:t,title:"mcp settings",children:[W(We,{palette:t,items:[{text:f?"RUNNING":"STOPPED",tone:f?"success":"idle"},{text:`127.0.0.1:${m}`,tone:"info"}]},void 0,!1,void 0,this),W("box",{flexGrow:1,overflow:"hidden",children:W("scrollbox",{focused:!1,stickyScroll:!1,scrollX:!1,style:Me(t),children:W("box",{flexDirection:"column",overflow:"hidden",children:[W(up,{palette:t,text:"Server"},void 0,!1,void 0,this),W(Tb,{palette:t,active:i===pp,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(pp),onActivate:a},void 0,!1,void 0,this),W(Tb,{palette:t,active:i===fp,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(fp)},void 0,!1,void 0,this),W("box",{height:1,overflow:"hidden",children:W("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),W(up,{palette:t,text:"Tools",extra:S===0?"all enabled":`${S} disabled`},void 0,!1,void 0,this),W("box",{height:1,overflow:"hidden",children:W("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),Xd.map((v)=>{let C=k.filter((h)=>h.category===v);if(C.length===0)return null;return W("box",{flexDirection:"column",overflow:"hidden",children:[W("box",{height:1,marginTop:1,overflow:"hidden",children:W("text",{fg:t.muted,wrapMode:"none",children:gT[v]??v},void 0,!1,void 0,this)},void 0,!1,void 0,this),C.map((h)=>{let P=Lc+k.indexOf(h);return W(vT,{palette:t,tool:h,enabled:Bn(h.name,b),active:i===P,rowH:d.rowH,onPick:()=>s(P),onToggle:()=>l(h)},h.name,!1,void 0,this)})]},v,!0,void 0,this)}),W(up,{palette:t,text:"Copy agent config",extra:"highlight a row, then enter or click Copy"},void 0,!1,void 0,this),y.map((v,C)=>{let h=Dc()+C;return W(yT,{palette:t,snippet:v,active:i===h,rowH:d.rowH,onPick:()=>s(h),onCopy:()=>c(v)},v.kind,!1,void 0,this)}),W(xT,{palette:t,snippet:K,selected:Boolean(N),brand:K?Ka(K.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),W(Be,{palette:t,backgroundColor:t.element,edge:"top",children:W(Le,{palette:t,hints:hT(i,f)},void 0,!1,void 0,this)},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function hT(e,t){if(e===pp)return[{key:"space",label:t?"stop server":"start server"},{key:"j/k",label:"move"}];if(e===fp)return[{key:"\u2190\u2192",label:"change port"},{key:"0-9",label:"type port"},{key:"enter",label:"apply port"},{key:"j/k",label:"move"}];if(Oc(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 up(e){let t=e.extra?` \xB7 ${e.extra}`:"";return W("box",{height:1,marginTop:1,overflow:"hidden",children:W("text",{wrapMode:"none",children:[W("span",{fg:e.palette.primary,children:e.text},void 0,!1,void 0,this),W("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 Tb(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 W("box",{height:r,flexDirection:"row",overflow:"hidden",backgroundColor:n?t.highlight:t.panel,onMouseDown:()=>{if(n&&l){l();return}c()},children:[W("box",{width:2,flexShrink:0,overflow:"hidden",children:W("text",{fg:t.primary,children:n?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),W("box",{width:hp,flexShrink:0,overflow:"hidden",children:W("text",{fg:n?t.primary:t.text,wrapMode:"none",children:o},void 0,!1,void 0,this)},void 0,!1,void 0,this),W("box",{width:mT,flexShrink:0,overflow:"hidden",children:W("text",{fg:d,wrapMode:"none",children:i},void 0,!1,void 0,this)},void 0,!1,void 0,this),W("box",{flexGrow:1,overflow:"hidden",children:W("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 yT(e){let{palette:t,snippet:n,active:r,rowH:o,onPick:i,onCopy:s}=e,a=Ka(n.kind,t),c=Xh(n.kind,t),l=n.language==="toml"?"Copy TOML":"Copy JSON";return W("box",{height:o,flexDirection:"row",overflow:"hidden",backgroundColor:r?t.highlight:t.panel,onMouseDown:i,children:[W("box",{width:2,flexShrink:0,overflow:"hidden",children:W("text",{fg:a,children:r?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),W("box",{width:hp,flexShrink:0,overflow:"hidden",children:W("text",{fg:a,wrapMode:"none",children:n.title},void 0,!1,void 0,this)},void 0,!1,void 0,this),W("box",{flexGrow:1,overflow:"hidden",children:W("text",{fg:t.muted,wrapMode:"none",children:n.path},void 0,!1,void 0,this)},void 0,!1,void 0,this),W(fe,{palette:t,label:l,bg:a,fg:c,onMouseDown:()=>{i(),s()}},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}function vT(e){let{palette:t,tool:n,enabled:r,active:o,rowH:i,onPick:s,onToggle:a}=e;return W("box",{height:i,flexDirection:"row",overflow:"hidden",backgroundColor:o?t.highlight:t.panel,onMouseDown:()=>{if(o){a();return}s()},children:[W("box",{width:2,flexShrink:0,overflow:"hidden",children:W("text",{fg:t.primary,children:o?"\u203A":" "},void 0,!1,void 0,this)},void 0,!1,void 0,this),W("box",{width:5,flexShrink:0,overflow:"hidden",children:W("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),W("box",{width:hp+4,flexShrink:0,overflow:"hidden",children:W("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),W("box",{width:7,flexShrink:0,overflow:"hidden",children:W("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),W("box",{flexGrow:1,overflow:"hidden",children:W("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 xT(e){let{palette:t,snippet:n,selected:r,brand:o}=e;if(!n)return null;let i=n.hint?` \xB7 ${n.hint}`:"";return W("box",{marginTop:1,flexDirection:"column",overflow:"hidden",children:[W("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),W("text",{fg:t.text,children:n.text},void 0,!1,void 0,this)]},void 0,!0,void 0,this)}var pp=0,fp=1,Lc=2,Ab=4,gT,hp=14,mT=14;var Ob=D(()=>{at();xe();Qe();Di();gT={inspect:"Inspect",logs:"Logs",diagnostics:"Diagnostics",control:"Control",setup:"Setup"}});import{readFileSync as bT,writeFileSync as wT}from"fs";import{useCallback as Y,useEffect as Rt,useMemo as Sn,useRef as rt,useState as I}from"react";import{RGBA as ST}from"@opentui/core";import{useKeyboard as kT,useTerminalDimensions as CT}from"@opentui/react";import{jsxDEV as oe,Fragment as ET}from"@opentui/react/jsx-dev-runtime";function Mb({controller:e,tui:t,onQuit:n,bootError:r,bootErrorMissing:o=!1,terminalBackground:i}){let{width:s,height:a}=CT(),[c,l]=I(t.theme||e?.cfg.ui.theme||"devctl"),d=rt(c),[f,m]=I(t.mouse),g=rt(t.mouse),[x,y]=I(t.leader_timeout),b=rt(t.leader_timeout),[k,S]=I(()=>Bi(t.font_size)),N=rt(k),K=ty(),v=Sn(()=>{let p=Yh(c);if(Wa(c)!=="terminal"||!pu(i))return p;let u=i??p.background;return{...p,background:u,panel:u,element:u,inverse:u}},[i,c]),C=Wa(c)==="terminal"&&pu(i)?ST.defaultBackground(i??void 0):v.background,[h,P]=I(e?"dashboard":"setup"),[H,Q]=I("none"),[ae,we]=I(""),[ze,Ke]=I(0),[ce,Ie]=I(0),[qe,ue]=I(0),[_e,Ee]=I([]),[G,Fe]=I(),ft=Sn(()=>iy({themeName:c,fontSize:k,mouse:f,leaderMs:x,locked:K,configPath:K?t.path||vu():vu(),mcpRunning:G?.mcp?.running===!0}),[k,x,f,K,G?.mcp?.running,c,t.path]),[Ne,Et]=I([]),[gt,en]=I(!1),[mt,tn]=I(!1),[ht,$r]=I(!0),[Mc,R]=I(r??""),[nn,Yn]=I(),[Ir,$c]=I(),[Ic,Fr]=I(!1),[Kb,kp]=I(""),[Fc,Nc]=I(0),[qb,Cp]=I({active:"Preparing diagnostics",checks:[]}),_p=rt(void 0),$o=rt(0),[Vb,Jb]=I({}),[Pp,zb]=I(),[Ze,Hc]=I(lc(e?.cfg)),[Nr,Yb]=I(""),[Io,Xb]=I(!1),[kn,Qb]=I(""),[ns,jc]=I(!1),[Rp,Zb]=I(0),[Hr,Ep]=I(""),[rs,ew]=I(""),[qt,Cn]=I(""),Xn=PT,[Tp,tw]=I(t.log_timestamps!==!1),[Ap,nw]=I(t.log_metadata!==!1),[Lp,rw]=I(()=>[...ev]),[os]=I(""),[Qn]=I(""),[_n,ow]=I(!1),[is,Dp]=I(),[iw,sw]=I(),[Fo,Op]=I("focus"),[wt,Pn]=I(!1),[aw,No]=I(Ar-1),[Ho,ss]=I(!1),[rn,as]=I(-1),[Mp,cw]=I(),[$p,Ip]=I(""),[Fp,Bc]=I(!1),[Np,Hp]=I(!1),jp=rt([]),jo=rt(null),Bo=rt(null),Wo=rt(null),Go=rt(null),Wc=rt(null),Gc=rt(null),Bp=rt(null),[Uc,lw]=I(""),[dw,cs]=I(""),Kc=rt(""),qc=rt(!1),[Wp,Uo]=I(0),[ls,Vc]=I(""),[ds,Jc]=I(),[uw,zc]=I([]),[Gp,on]=I(!1),[Up,Yc]=I("start"),[Zn,Rn]=I("quit"),[En,pw]=I(()=>t.mcp_port??xo(e?.cfg.repoRoot??process.cwd())),Ko=rt(void 0),Xc=rt(0),[M,fw]=I(e?.cfg),[qo,Kp]=I(void 0),qp=t.keybinds.copy??mn(),ct=Sn(()=>Object.keys(M?.services??{}).sort(),[M]),Vo=Sn(()=>Yi(ct,Ne,Lp),[ct,Ne,Lp]),Jo=Sn(()=>Vh(ae),[ae]),jr=Sn(()=>wv(ae),[ae]);Rt(()=>{rw((p)=>{let u=new Set(p),_=!1;for(let L of Ne)if(L.service!==""&&!ct.includes(L.service)&&!u.has(L.service))u.add(L.service),_=!0;return _?[...u].sort():p})},[Ne,ct]),Rt(()=>{Ie(0)},[ae]),Rt(()=>{if(H==="palette")Ke(0)},[H,ae]);let ot=Sn(()=>To(Ne,{service:qt,services:Xn,errorOnly:mt,search:kn,regex:_n,source:Qn,since:Hr,until:rs,systemLogs:ht}),[mt,_n,kn,qt,Xn,Hr,Qn,rs,Ne,ht]),He=Sn(()=>Py(ot,wt,Wp),[ot,wt,Wp]),Tn=He.items,sn=My(h,{doctor:Ir?.checks.length??0,settings:ft.length,profiles:Object.keys(M?.profiles??{}).length,services:ct.length,logs:Tn.length,mcp:Lb()}),Vp=h==="logs"?aw:qe,Z=sn<=0?Math.max(0,Vp):Math.max(0,Math.min(Vp,sn-1));Rt(()=>{as(-1),Pn(!1),No(Math.max(0,Math.min(Ar,ot.length)-1))},[mt,kn,qt,ht]),Rt(()=>{if(h!=="logs")ss(!1)},[h]),Rt(()=>{if(h!=="logs"||wt)return;No(Math.max(0,Math.min(Ar,ot.length)-1))},[ot.length,wt,h]),Rt(()=>{if(h==="settings")return;l(d.current),S(N.current),y(b.current),m(g.current)},[h]);let Qc=Y(()=>{if(!wt)Uo(Du(ot.length)),Pn(!0)},[ot.length,wt]),zo=Y((p)=>{let u=Ou(p,sn,He.start,He.newer);if(u.startDelta!==0){Uo(Math.max(0,He.start+u.startDelta)),Pn(!0),No(u.selected);return}let _=Math.max(sn-1,0),L=sn>0&&(u.selected<_||He.newer>0);if(L&&!wt)Uo(Du(ot.length)),Pn(!0);else if(!L)Pn(!1);No(u.selected)},[ot.length,sn,wt,He.newer,He.start]),us=Y((p)=>{let u=Tn.length,_=Ou(p,u,He.start,He.newer);if(_.startDelta!==0)Uo(Math.max(0,He.start+_.startDelta)),Pn(!0);as(_.selected)},[Tn.length,He.newer,He.start]),Zc=Y(()=>{if(Pn(!1),as(-1),h==="logs")No(Math.max(0,Math.min(Ar,ot.length)-1));Zb((p)=>p+1),R(He.newer>0?`Jumped to latest (+${He.newer} new)`:"Jumped to latest logs")},[ot.length,He.newer,h]),et=Y(()=>{if(Q("none"),we(""),jc(!1),Ko.current)clearTimeout(Ko.current)},[]),el=Y((p)=>{Ee((u)=>u.includes(p)?u.filter((_)=>_!==p):[...u,p])},[]),Ve=Y((p,u)=>{if(K){R(`${u} session only`);return}let _=Bh(p);R(`${u} saved ${_}`)},[K]),Br=Y((p)=>{l(p),d.current=p,Ve({theme:p},`theme ${p}`)},[Ve]),Yo=Y(()=>{let p=!f;m(p),g.current=p,Ve({mouse:p},`mouse ${p?"on":"off"} restart TUI to apply clicks`)},[f,Ve]),ps=Y((p)=>{y(p),b.current=p,Ve({leader_timeout:p},`leader ${p}ms`)},[Ve]),er=Y((p)=>{let u=Bi(p);S(u),N.current=u,Ve({font_size:u},`display ${qa(u)}`)},[Ve]),Jp=Y(()=>{let p=hu();l(p.theme),d.current=p.theme,m(p.mouse),g.current=p.mouse,y(p.leader_timeout),b.current=p.leader_timeout,S(p.font_size),N.current=p.font_size,Ve(p,"restored default preferences")},[Ve]),tl=Y((p)=>{if(p.id==="theme"){Ke(Math.max(0,vt.indexOf(c))),Q("themes");return}if(p.id==="mouse"){Yo();return}if(p.id==="leader"){ps(x);return}if(p.id==="font"){er(k);return}if(p.id==="reset"){Rn("reset-prefs"),Q("confirm");return}if(p.id==="mcp"){P("mcp"),ue(0);return}R(p.detail)},[er,ps,k,x,c,Yo]),zp=Y((p)=>{let u=So(ft,Z);if(!u)return;if(u.id==="theme"){Br(ny(c,p));return}if(u.id==="leader"){ps(ry(x,p));return}if(u.id==="font"){er(Va(k,p));return}if(u.id==="mouse")Yo()},[er,ps,k,x,Z,Br,ft,c,Yo]),gw=Y(()=>{l(d.current)},[]),he=Y(async()=>{if(!e)return;try{let p=await e.status();if(Fe(p),p.profile&&Ze==="")Hc(p.profile);return p}catch(p){R(j(p));return}},[e,Ze]),fs=Y(async()=>{if(!e){R("Supervisor is not running");return}R("Probing configured identities\u2026");try{let p=await e.refreshAuth();Fe((ee)=>ee?{...ee,identity:p}:ee);let u=Object.values(p.service_account_status),_=u.filter((ee)=>ee==="available").length,L=u.filter((ee)=>ee==="unavailable").length;R(u.length===0?"Identity refreshed \u2014 no service accounts configured":`Identity refreshed \u2014 ${_} available${L>0?`, ${L} unavailable`:""}`)}catch(p){R(j(p))}},[e]),gs=Y((p)=>{let u=Cr(p);pw(u);let _=M?.repoRoot??process.cwd();if(Nh(_,u)){Ve({mcp_port:null},`MCP port ${u} (default)`);return}Ve({mcp_port:u},`MCP port ${u}`)},[M,Ve]),Wr=Y(()=>{if(ls==="")return En;let p=Fh(ls,En);return Vc(""),gs(p),p},[En,ls,gs]),Yp=Y(async(p)=>{if(!e||G?.mcp?.running!==!0)return;await e.mcpStop(),await e.mcpStart({port:p}),await he()},[e,he,G?.mcp?.running]),nl=Y(async(p)=>{if(!e){R("Supervisor is not running");return}let u=G?.mcp?.disabled_tools??[],_=Bn(p.name,u),L=_?[...u,p.name]:u.filter((ee)=>ee!==p.name);try{let ee=await e.mcpSetTools(L);Ve({mcp_disabled_tools:ee},`${p.label} ${_?"disabled":"enabled"}`),await he()}catch(ee){R(j(ee))}},[e,Ve,he,G]),ms=Y(async()=>{if(!e){R("Supervisor is not running");return}try{if(G?.mcp?.running)await e.mcpStop(),Ve({mcp_enabled:!1},"MCP off"),R("MCP stopped");else await e.mcpStart({port:En}),Ve({mcp_enabled:!0},"MCP on"),R("MCP started");await he()}catch(p){R(j(p))}},[e,En,Ve,he,G?.mcp?.running]),rl=Y((p)=>{Hu(p.text).then(()=>{R(`Copied ${p.title} snippet`)}).catch((u)=>{R(j(u))})},[]),hs=Y((p)=>{let u=mp(p);if(u===void 0)return!1;let _=G?.mcp?.address??bo(G?.mcp?.port??En),L=Fi(_,G?.mcp?.token??"")[u];if(!L)return!1;return rl(L),!0},[rl,En,G?.mcp?.address,G?.mcp?.port,G?.mcp?.token]),Gr=Sn(()=>({services:qt!==""?[qt]:Xn,level:mt?"ERROR":os,search:kn,regex:_n,source:Qn,since:Hr,until:rs}),[mt,os,_n,kn,qt,Xn,Hr,Qn,rs]),ys=Y(async()=>{if(!e)return;try{cw(await e.logsStats(Gr))}catch(p){R(j(p))}},[e,Gr]),Xp=Y(async()=>{if(!e||gt)return;try{let p=await e.logsPage(Gr);Et((u)=>nv(u,p.events)),Ip(p.prevCursor),Bc(p.hasPrev),await ys()}catch(p){R(j(p))}},[e,Gr,gt,ys]),Xo=Y(()=>{Et([]),Ep(new Date().toISOString()),Pn(!1),R("Cleared on-screen log buffer")},[]),Qo=Y(()=>{$r((p)=>!p)},[]);Rt(()=>{he().then(()=>Xp())},[he,Xp]),Rt(()=>{jp.current=Ne},[Ne]),Rt(()=>{if(!e||Np||!ov(wt,He.start,Fp))return;Hp(!0),e.logsPage({...Gr,cursor:$p,direction:"backward"}).then((p)=>{if(p.sessionChanged){R("Daemon session changed \u2014 older log history is no longer available"),Bc(!1);return}let u=jp.current,_=rv(u,p.events);if(Et(_),_.length>u.length)Uo((L)=>L+(_.length-u.length));Ip(p.prevCursor),Bc(p.hasPrev)}).catch((p)=>R(j(p))).finally(()=>Hp(!1))},[e,Gr,Np,Fp,wt,$p,He.start]),Rt(()=>{if(!e||gt||h!=="logs")return;let p=setInterval(()=>{ys()},RT);return()=>clearInterval(p)},[e,gt,ys,h]),Rt(()=>{if(!e)return;let p,u=!1,_=[],L=M&&M.logs.max_memory_events>0?M.logs.max_memory_events:50000,ee=()=>{if(p=void 0,_.length>0){let w=_.splice(0,_.length);Et((ie)=>tv(ie,w,Hr,L))}if(u)u=!1,he()},An=e.onEvent((w)=>{if(w.type===ra&&w.payload&&typeof w.payload==="object"&&"event"in w.payload){let ie=w.payload.event;if(!gt)_.push(ie);if(!p)p=setTimeout(ee,30);return}if(w.type===bi){Kp(Av(w));return}if(w.type===oa)Kp(void 0),e.configSnapshot().then(fw).catch((ie)=>R(j(ie)));if(u=!0,!p)p=setTimeout(ee,30)});return()=>{if(An(),p)clearTimeout(p)}},[e,Hr,gt,he]),Rt(()=>{Ut(M?.google.project_id??"").then(Yn).catch((p)=>{R(j(p))})},[M?.google.project_id,G?.identity.project]),Rt(()=>{if(h!=="doctor"||!M)return;let p=_p.current,u=G?.session_id??"";if(p?.cfg===M&&p.tick===Fc&&p.sessionID===u&&p.reloadError===qo)return;_p.current={cfg:M,tick:Fc,sessionID:u,reloadError:qo};let _=++$o.current;Fr(!0),kp(""),Cp({active:"Preparing diagnostics",checks:[]});let L;if(M.configPath!==""){L="";try{li(M.repoRoot,M.configPath)}catch(ee){L=j(ee)}}jn(M,void 0,(ee)=>{if(_===$o.current)Cp(ee)},{services:G?.services,proxyRunning:G?.proxy.running,repositoryConfigError:L}).then((ee)=>{if(_!==$o.current)return;$c(ee)}).catch((ee)=>{if(_!==$o.current)return;kp(j(ee))}).finally(()=>{if(_===$o.current)Fr(!1)})},[h,M,Fc,G?.session_id,qo]);let vs=Y((p)=>{Yb(p),P("detail")},[]),an=Y(async(p,u)=>{if(!e||!M){R("no configuration loaded");return}try{let _=ua(M,{services:p,profile:u}),L=Pi(M,_.services,_.profile);Yc("start"),zc(L.waves.flat().filter((w)=>Vi(G?.services[w]))),Jc(L),Q("plan"),on(!0);let ee=_.services.filter((w)=>!Vi(G?.services[w])),An=await e.start({services:ee.length>0?ee:_.services,profile:_.profile});await he(),on(!1),R(uv(An))}catch(_){on(!1),await he(),R(j(_))}},[M,e,he,G]),xs=Y(async(p)=>{if(!e||!M){R("no configuration loaded");return}let u=p.length>0?p:Object.entries(G?.services??{}).filter(([,_])=>_.state!=="STOPPED"&&_.state!=="UNKNOWN").map(([_])=>_);if(u.length===0){R("nothing to stop");return}try{let _=Ri(M,u);Yc("stop"),zc([]),Jc(_),Q("plan"),on(!0),await e.stop(p),await he(),on(!1),R(pv(_))}catch(_){on(!1),await he(),R(j(_))}},[M,e,he,G]),Zo=Y(async(p,u)=>{if(!e||!M){R("no configuration loaded");return}try{let _=Oy(M,p,u),L=Pi(M,_.services,_.profile);Yc("restart"),zc([]),Jc(L),Q("plan"),on(!0),await e.restart(p),await he(),on(!1),R(Xi(L)===""?"Restarted selected services":`Restarted ${Xi(L)}`)}catch(_){on(!1),await he(),R(j(_))}},[M,e,he]),bs=Y(async(p="")=>{let u=H==="log-details"&&is?sv(is):av(ot),_=p===""?"":` \xB7 ${p}`;if(u.trim()===""){R(`No logs to copy${_}`);return}try{await Hu(u);let L=u.split(`
|
|
622
|
+
`).length,ee=H==="log-details"?"Copied log event":`Copied ${L} log lines`;R(`${ee}${_}`)}catch(L){R(j(L))}},[ot,is,H]),ol=Y(()=>{if(!M)return;try{lw(bT(M.configPath,"utf8")),cs(""),Q("config-edit")}catch(p){R(j(p))}},[M]),mw=Y(()=>{if(!M)return;let p=Bp.current?.plainText??Uc,u=Xr(M.repoRoot,M.configPath,p);if(u.length>0){cs(u.join(`
|
|
623
|
+
`)),R("Config buffer not saved");return}if(wT(M.configPath,p),cs(""),Q("none"),!e){R(`Wrote ${M.configPath}`);return}e.reload().then((_)=>{if(R(_.restart_required.length===0?"Configuration saved and reloaded":`Saved; restart required: ${_.restart_required.join(", ")}`),_.restart_required.length>0)Rn("reload"),Q("confirm");he()})},[M,Uc,e,he]),cn=Y(async(p,u)=>{if(qc.current)return;if(qc.current=!0,p.name!=="start"&&p.name!=="stop"&&p.name!=="restart")Q("none");we("");let _=Zy(u,_e);try{switch(p.name){case"exit":Rn("quit"),Q("confirm");return;case"help":Q("help");return;case"version":R(Lt());return;case"themes":if(u[0]){Br(u[0]);return}Ke(Math.max(0,vt.indexOf(c))),we(""),Q("themes");return;case"settings":P("settings"),ue(0);return;case"dashboard":case"services":P(p.name);return;case"logs":if(u[0])Cn(u[0]);P("logs");return;case"fullscreen":P("logs"),ss((L)=>h==="logs"?!L:!0);return;case"auth":if(u[0]?.toLowerCase()==="refresh"){P("auth"),await fs();return}P("auth");return;case"credentials":case"proxy":case"mcp":case"config":case"profiles":case"setup":P(p.name);return;case"reload":if(!e)return;e.reload().then((L)=>{if(R(L.restart_required.length===0?"Configuration reloaded":`Reload requires restart: ${L.restart_required.join(", ")}`),L.restart_required.length>0)Rn("reload"),Q("confirm");he()});return;case"doctor":P("doctor");return;case"stats":P("stats");return;case"start":await an(_,Ze);return;case"stop":await xs(_);return;case"restart":await Zo(_,Ze);return;case"refresh":if(h==="auth"){await fs();return}await he(),R("Refreshed status and logs");return;case"pause":en((L)=>!L),P("logs");return;case"filter":tn((L)=>!L),P("logs");return;case"system":Qo(),P("logs");return;case"clear":Xo();return;case"reveal":{let L=!Io;Xb(L),R(L?"Secrets visible this session":"Secrets hidden");return}case"wrap":{let L=Lu(Fo);Op(L),R(`Log ${Ki(L)}`);return}case"copy":await bs();return;case"export":{let L=go(u[0]);if(e)await e.logs({export:L,services:Xn,level:mt?"ERROR":os,search:kn,regex:_n,source:Qn});else xa(L,ot);Kc.current=L,R(`Exported ${L}`);return}case"exports":{let L=Kc.current||rr();ba(L),R(`Opened ${rr()}`);return}case"regex":ow((L)=>!L),R(_n?"Substring search":"Regex search");return;case"since":Ep(u[0]||new Date(Date.now()-3600000).toISOString()),R(`Logs since ${u[0]||"1h"}`);return;case"until":ew(u[0]||new Date().toISOString()),R(`Logs until ${u[0]||"now"}`);return;case"history":{let{listSessions:L,loadSessionEvents:ee}=await Promise.resolve().then(() => (wr(),Wm)),An=L(),w=u[0]||An[0];if(!w){R("No persisted log sessions");return}Et(ee(w)),R(`Loaded session ${w}`);return}case"buffer":ol();return;case"edit":{if(!M)return;let L=process.env.DEVCTL_EDITOR||process.env.EDITOR,ee=L?[L,M.configPath]:process.platform==="darwin"?["open",M.configPath]:["xdg-open",M.configPath];Bun.spawn({cmd:ee,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),R(`Opened ${M.configPath} in ${ee[0]}. Run /reload after saving.`);return}default:R(`/${p.name}`)}}catch(L){R(j(L))}finally{setTimeout(()=>{qc.current=!1},_T)}},[Zo,an,xs,_e,M,Xo,e,bs,mt,ot,os,_n,kn,Xn,Qn,Fo,ol,Br,Ze,he,fs,Io,h,c,Qo]),hw=Y(()=>{let p=Kc.current||rr();ba(p),R(`Opened ${rr()}`)},[]),il=Y(()=>{let p=Lr(Jo,ce);if(!p){R(ae.trim()===""?"pick a command from the list":`unknown command /${ae}`),et();return}let _=Ni(ae)?.name===p.name?Jh(ae):[];cn(p,_)},[et,Jo,ae,cn,ce]),Qp=Y((p)=>{Br(p),et()},[et,Br]),yw=Y((p)=>{let u=Ni(p);if(u)cn(u,[])},[cn]),Zp=Y(()=>{if(H==="palette"){let p=Lr(jr,ze);if(p)cn(p,[]);return}il()},[H,ze,jr,cn,il]),vw=Y(()=>{if(M?.shutdown.stop_services_on_exit===void 0){Rn("quit"),Q("confirm");return}n(M.shutdown.stop_services_on_exit===!1)},[M,n]),xw=Y(()=>{if(Zn==="quit"){n(!1);return}if(Zn==="reload"){et();let p=G?.restart_required??[];if(p.length>0)Zo(p,Ze);return}if(Zn==="reset-prefs"){et(),Jp();return}if(Zn==="free-port"){let p=Pp;if(et(),!p)return;Qs(p).then(()=>{R(`Stopped ${p.command} (pid ${p.pid}) on port ${p.port}`),Nc((u)=>u+1)}).catch((u)=>{R(j(u))});return}et(),an([],Ze)},[Jp,Zo,an,et,Zn,n,Pp,Ze,G]),bw=Y(()=>{if(h==="logs"){let u=Tn[Z];if(u)Dp(u),Q("log-details");return}if(h==="profiles"){let _=Object.keys(M?.profiles??{}).sort()[Z];if(_)Hc(_),Rn("start-profile"),Q("confirm");return}if(h==="doctor"){let u=Ir?.checks[Z];if(u?.action?.kind==="free-port"){let _=u.action.holder;zb(_),Jb({port:_.port,pid:_.pid,process:_.command}),Rn("free-port"),Q("confirm")}return}if(h==="mcp"){if(Z===0){ms();return}if(Z===1){Wr();return}let u=Oc(Z);if(u){nl(u);return}hs(Z);return}if(h==="settings"){let u=So(ft,Z);if(u)tl(u);return}if(h==="dashboard"&&Eo(G)){an([],Ze);return}let p=ct[Z];if(p&&(h==="dashboard"||h==="services"))vs(p)},[tl,Wr,an,M,hs,Ir,Z,Tn,ct,vs,Ze,h,ft,G,ms]);kT((p)=>{let u=(p.name??"").toLowerCase(),_=zv(p,t),L=Jv(p,t);if(_&&!L){if(h==="mcp"&&hs(Z))return;bs();return}if(L){let w=Date.now();if(Yv(w,Xc.current)){Xc.current=0,vw();return}Xc.current=w;let ie="Ctrl+C again to quit";if(_)bs(ie);else R(`Press ${ie}`);return}if(p.ctrl&&(u==="="||u==="+"||u==="plus")){er(Va(k,1));return}if(p.ctrl&&(u==="-"||u==="_"||u==="minus")){er(Va(k,-1));return}if(p.ctrl&&u==="0"){er(hu().font_size);return}if(H==="confirm"){if(u==="escape"){et();return}if(Zn==="quit"&&u==="d"){n(!0);return}if(u==="return")xw();return}if(H==="log-details"){if(u==="escape"){et();return}if(u==="down"||u==="j"){Ge(Go.current,t.scroll_speed);return}if(u==="up"||u==="k"){Ge(Go.current,-t.scroll_speed);return}if(wc(p)){Ge(Go.current,qi(a));return}if(Sc(p)){Ge(Go.current,-qi(a));return}return}if(H==="route-details"){if(u==="escape"||u==="return"){et();return}if(u==="down"||u==="j"){Ge(Wc.current,t.scroll_speed);return}if(u==="up"||u==="k"){Ge(Wc.current,-t.scroll_speed);return}return}if(H==="plan"){if(u==="escape"||u==="return"&&!Gp){et();return}if(u==="down"||u==="j"){Ge(Gc.current,t.scroll_speed);return}if(u==="up"||u==="k"){Ge(Gc.current,-t.scroll_speed);return}return}if(H==="help"){if(u==="escape"){et();return}if(u==="down"||u==="j"){Ge(Bo.current,1);return}if(u==="up"||u==="k"){Ge(Bo.current,-1);return}if(u==="pagedown"||wc(p)){Ge(Bo.current,Vu);return}if(u==="pageup"||Sc(p)){Ge(Bo.current,-Vu);return}return}if(H==="themes"){if(u==="escape"){gw(),et();return}if(u==="down"||u==="j"){Ke((w)=>{let ie=Math.min(w+1,vt.length-1),ln=vt[ie];if(ln)l(ln);return ie});return}if(u==="up"||u==="k"){Ke((w)=>{let ie=Math.max(0,w-1),ln=vt[ie];if(ln)l(ln);return ie});return}if(u==="return"){let w=vt[ze%vt.length];if(w)Qp(w)}return}if(H==="leader"){if(Ko.current)clearTimeout(Ko.current);Q("none");let w=zh(u),ie=w?Ni(w):void 0;if(ie)cn(ie,[]);return}if(H==="config-edit"){if(u==="escape"){cs(""),et();return}if(p.ctrl&&u==="s"){mw();return}return}if(jv(H)){if(u==="escape"){et();return}if(H==="slash"&&u==="down"){Ie((w)=>Math.min(Math.max(Jo.length-1,0),w+1));return}if(H==="slash"&&u==="up"){Ie((w)=>Math.max(0,w-1));return}if(H==="slash"&&u==="tab"){if(p.shift){Ie((ie)=>Math.max(0,ie-1));return}let w=Lr(Jo,ce);if(w)we(`${w.name} `);return}if(H==="slash"&&u==="return"){il();return}if(H==="palette"&&u==="down"){Ke((w)=>Math.min(w+1,Math.max(jr.length-1,0)));return}if(H==="palette"&&u==="up"){Ke((w)=>Math.max(0,w-1));return}if(H==="palette"&&u==="return"){let w=Lr(jr,ze);if(w)cn(w,[])}return}if(ns){if(u==="escape")jc(!1);return}if(Bv(p,t)){Q("leader"),Ko.current=setTimeout(()=>Q("none"),x);return}if(Wv(p,t)){we(""),Ke(0),Q("palette");return}if(Gv(p,t)){we(""),Ie(0),Q("slash");return}if(Uv(p,t)){Q("help");return}if(Kv(p,t)||h==="logs"&&u==="f"&&!p.ctrl&&!p.meta){P("logs"),jc(!0);return}if(u==="escape"){if(Ho){ss(!1);return}if(h==="detail"){P("services");return}if(h==="setup")if(e)P("dashboard");else n(!0);return}if(u==="z"&&(h==="logs"||h==="dashboard")&&!p.ctrl&&!p.meta){P("logs"),ss((w)=>h==="logs"?!w:!0);return}let ee=(h==="logs"||h==="dashboard")&&!ns;if(ee&&(u==="left"||u==="["||h==="logs"&&u==="h")){Cn(Iu(Vo,qt,-1));return}if(ee&&(u==="right"||u==="]"||h==="logs"&&u==="l")){Cn(Iu(Vo,qt,1));return}if(h==="logs"&&!ns&&u.length===1&&u>="1"&&u<="9"){let w=dv(Vo,Ne,Number(u));if(w!==void 0)Cn(w);return}if(u==="tab"){P(p.shift?xv(h):vv(h));return}let An=$y(u);if(An){P(An);return}if((h==="dashboard"||h==="setup")&&u==="o"){P("profiles");return}if((h==="dashboard"||h==="services")&&(u==="*"||p.shift&&u==="8")){Ee([...ct]),R(`Selected ${ct.length} services`);return}if((h==="dashboard"||h==="services")&&(u==="-"||u==="_"||u==="minus")){Ee([]),R("Selection cleared");return}if((h==="dashboard"||h==="services")&&u==="n"){an(fc(_e,ct[Z]??""),Ze);return}if((h==="dashboard"||h==="services")&&u==="x"){xs(fc(_e,ct[Z]??""));return}if((h==="dashboard"||h==="services"||h==="detail")&&qv(p)){Zo(fc(_e,ct[Z]??Nr),Ze);return}if((h==="dashboard"||h==="services")&&u==="r"){he(),R("Refreshed");return}if(h==="auth"&&u==="r"){fs();return}if(h==="logs"&&u==="t"){let w=!Tp;tw(w),Ve({log_timestamps:w},w?"timestamps on":"timestamps off");return}if(h==="logs"&&u==="m"){let w=!Ap;nw(w),Ve({log_metadata:w},w?"metadata on":"metadata off");return}if(u==="down"||u==="j"){if(h==="mcp"&&Z===1)Wr();if(h==="config"){Ge(jo.current,t.scroll_speed);return}if(h==="detail"){Ge(Wo.current,t.scroll_speed);return}if(h==="logs"){zo(Z+1);return}if(h==="dashboard"&&rn>=0){us(rn+1);return}ue((w)=>Math.min(Math.max(sn-1,0),w+1));return}if(u==="up"||u==="k"){if(h==="mcp"&&Z===1)Wr();if(h==="config"){Ge(jo.current,-t.scroll_speed);return}if(h==="detail"){Ge(Wo.current,-t.scroll_speed);return}if(h==="logs"){zo(Z-1);return}if(h==="dashboard"&&rn>=0){us(rn-1);return}ue((w)=>Math.max(0,Math.min(w,Math.max(sn-1,0))-1));return}if(wc(p)){let w=qi(a);if(h==="config"){Ge(jo.current,w);return}if(h==="detail"){Ge(Wo.current,w);return}if(h==="logs"){zo(Z+w);return}if(h==="dashboard"&&(wt||rn>=0)){us(Math.max(0,rn)+w);return}ue((ie)=>Math.min(Math.max(sn-1,0),ie+w));return}if(Sc(p)){let w=qi(a);if(h==="config"){Ge(jo.current,-w);return}if(h==="detail"){Ge(Wo.current,-w);return}if(h==="logs"){zo(Z-w);return}if(h==="dashboard"&&(wt||rn>=0)){us(Math.max(0,rn)-w);return}ue((ie)=>Math.max(0,ie-w));return}if(h==="proxy"&&u==="n"){e?.proxyStart().then(async()=>{R("Proxy started"),await he()});return}if(h==="proxy"&&u==="x"){e?.proxyStop().then(async()=>{R("Proxy stopped"),await he()});return}if(h==="detail"&&Nr!==""){if(u==="n"){an([Nr],Ze);return}if(u==="x"){xs([Nr]);return}if(u==="o"){P("config");return}if(u==="l"){Cn(Nr),P("logs");return}}if(h==="mcp"&&Z===1&&(u==="left"||u==="h")){let w=Cr(Wr()-1);gs(w),Yp(w);return}if(h==="mcp"&&Z===1&&(u==="right"||u==="l")){let w=Cr(Wr()+1);gs(w),Yp(w);return}if(h==="mcp"&&Z===1&&(u==="backspace"||u==="delete")){Vc((w)=>Ih(w));return}if(h==="mcp"&&Z===1&&u.length===1&&u>="0"&&u<="9"){Vc((w)=>$h(w,u));return}if(h==="settings"&&(u==="left"||u==="h")){zp(-1);return}if(h==="settings"&&(u==="right"||u==="l")){zp(1);return}if(u==="space"){if(h==="profiles"){let ln=Object.keys(M?.profiles??{}).sort()[Z];if(ln)Hc(ln),R(`Profile ${ln}`);return}if(h==="mcp"){if(Z===0){ms();return}let ie=Oc(Z);if(ie){nl(ie);return}hs(Z);return}if(h==="logs")return;if(h==="settings"){if(So(ft,Z)?.id==="mouse")Yo();return}let w=ct[Z];if(w)el(w);return}if(u==="return"){if(h==="setup"&&!e){if(!o){R(r||"Existing configuration is invalid \u2014 fix it and restart devctl.");return}Promise.resolve().then(() => (Td(),Pm)).then(({createStarterConfig:w})=>{try{let ie=w(process.cwd());R(`Wrote ${ie}. Restart devctl or run the CLI wizard.`)}catch(ie){R(j(ie))}});return}if(h==="setup"&&e){an([],Ze);return}bw();return}if(u==="q"){if(M?.shutdown.stop_services_on_exit===!1){n(!0);return}if(M?.shutdown.stop_services_on_exit===!0){n(!1);return}Rn("quit"),Q("confirm");return}if(Kn(p,t,"services","s")&&H==="none"&&h!=="logs"){P("services");return}if(Kn(p,t,"logs","l")&&H==="none"&&h!=="detail"&&h!=="logs"&&h!=="settings"){P("logs");return}if(Kn(p,t,"auth","a")&&H==="none"){P("auth");return}if(Kn(p,t,"proxy","p")&&H==="none"&&h!=="logs"){P("proxy");return}if(Kn(p,t,"doctor","d")&&H==="none"&&h!=="doctor"){P("doctor");return}if(Kn(p,t,"config","c")&&H==="none"){P("config");return}if(Kn(p,t,"setup","u")&&H==="none"){P("setup");return}if(h==="config"&&u==="e"){cn(Ni("/edit")??{name:"edit",aliases:[],desc:"",leader:"",group:"ui"},[]);return}if(h==="config"&&u==="v"){ol();return}if(h==="doctor"&&u==="r"){Nc((w)=>w+1),R("Re-running doctor");return}if(h==="logs"&&u==="p"){en((w)=>!w);return}if((h==="logs"||h==="dashboard")&&u==="g"){Zc();return}if((h==="logs"||h==="dashboard")&&u==="w"){let w=Lu(Fo);Op(w),R(`Log ${Ki(w)}`);return}if((h==="logs"||h==="dashboard")&&u==="e"){tn((w)=>!w);return}if((h==="logs"||h==="dashboard")&&u==="i"){Qo(),R(ht?"Hiding internal auth/mcp/devctl/proxy logs":"Showing internal logs");return}if((h==="logs"||h==="dashboard")&&Vv(p))Xo()});let ef=Rv(Zn,Ze,Vb),ww=new Set(ds?.waves.flat()??[]),Sw=ds===void 0||Up==="stop"?"":Object.entries(G?.services??{}).find(([p,u])=>ww.has(p)&&u.state==="FAILED")?.[0]??"";return oe(xu.Provider,{value:Wi(k),children:oe("box",{flexDirection:"column",width:s,height:a,backgroundColor:C,overflow:"hidden",children:[Ho?null:oe(ET,{children:[oe(Ov,{palette:v,cfg:M,snap:G,google:nn,profile:Ze,reveal:Io,width:s},void 0,!1,void 0,this),oe(Mv,{palette:v,screen:h,width:s,onSelect:P},void 0,!1,void 0,this),qo?oe("box",{height:1,paddingLeft:1,backgroundColor:v.panel,overflow:"hidden",children:oe("text",{fg:v.error,wrapMode:"none",children:`\u26A0 configuration reload failed: ${qo}`},void 0,!1,void 0,this)},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),oe("box",{flexGrow:1,overflow:"hidden",children:[h==="dashboard"?oe(Zx,{palette:v,cfg:M,snap:G,logs:Ne,names:ct,selected:Z,checked:_e,profile:Ze,google:nn,width:s,paused:gt,followTick:Rp,logService:qt,errorOnly:mt,showSystemLogs:ht,onOpen:vs,onSelectIndex:ue,selectedLog:rn,onToggle:el,logSources:Vo,onFilterService:Cn,onToggleErrors:()=>tn((p)=>!p),onToggleSystemLogs:Qo,onClearLogs:Xo,onShowErrors:()=>{Cn(""),tn(!0)},wrapMode:Fo,view:Tn,follow:!wt,onLeaveLatest:Qc,onPickLog:(p)=>{let u=Tn[p];if(!u)return;as(p),Dp(u),Qc()},viewStart:He.start,viewTotal:ot.length,newer:He.newer,onJumpLatest:Zc,facets:Mp},void 0,!1,void 0,this):null,h==="services"?oe(yb,{palette:v,cfg:M,names:ct,snap:G,selected:Z,checked:_e,width:s,reveal:Io,onOpen:vs,onSelectIndex:ue,onToggle:el},void 0,!1,void 0,this):null,h==="detail"?oe(hb,{palette:v,cfg:M,snap:G,name:Nr,reveal:Io,width:s,envScrollRef:Wo},void 0,!1,void 0,this):null,h==="logs"?oe(Xx,{palette:v,logs:Ne,names:ct,logSources:Vo,service:qt,paused:gt,errorOnly:mt,showSystemLogs:ht,search:kn,searchFocused:ns,followTick:Rp,width:s,onSearch:Qb,onService:Cn,onToggleErrors:()=>tn((p)=>!p),onToggleSystemLogs:Qo,onClearLogs:Xo,source:Qn,regex:_n,services:Xn,showTimestamps:Tp,showMeta:Ap,view:Tn,wrapMode:Fo,selected:Z,follow:!wt,newer:He.newer,viewStart:He.start,viewTotal:ot.length,onSelect:zo,fullscreen:Ho,onLeaveLatest:Qc,onOpenExports:hw,onJumpLatest:Zc,facets:Mp},void 0,!1,void 0,this):null,h==="auth"?oe(Ex,{palette:v,cfg:M,google:nn,identity:G?.identity},void 0,!1,void 0,this):null,h==="credentials"?oe(Ax,{palette:v,credentials:G?.credentials},void 0,!1,void 0,this):null,h==="proxy"?oe(pb,{palette:v,cfg:M,snap:G,width:s,onSelectRoute:(p)=>{sw(p),Q("route-details")}},void 0,!1,void 0,this):null,h==="mcp"?oe(Db,{palette:v,snap:G,port:En,portDraft:ls,selected:Z,onPick:ue,onToggle:()=>{ms()},onCopy:rl,onToggleTool:(p)=>{nl(p)}},void 0,!1,void 0,this):null,h==="doctor"?oe(nb,{palette:v,report:Ir,loading:Ic,progress:qb,error:Kb,selected:Z,onPick:ue,onReload:()=>{Nc((p)=>p+1),R("Re-running doctor")}},void 0,!1,void 0,this):null,h==="stats"?oe(_b,{palette:v,cfg:M,snap:G,width:s,onRefresh:he},void 0,!1,void 0,this):null,h==="config"?oe(Jx,{palette:v,cfg:M,width:s,scrollRef:jo},void 0,!1,void 0,this):null,h==="profiles"?oe(ib,{palette:v,cfg:M,snap:G,profile:Ze,selected:Z,onPick:ue},void 0,!1,void 0,this):null,h==="setup"?oe(Rb,{palette:v,cfg:M,google:nn,bootError:r,bootErrorMissing:o,step:Z},void 0,!1,void 0,this):null,h==="settings"?oe(Sb,{palette:v,items:ft,selected:Z,locked:K,width:s,onPick:ue,onActivate:tl},void 0,!1,void 0,this):null]},void 0,!0,void 0,this),H==="slash"?oe(wx,{palette:v,items:Jo,query:ae,selected:ce,onQuery:we,onSubmit:Zp},void 0,!1,void 0,this):null,H==="palette"?oe(fx,{palette:v,items:jr,selected:Math.min(ze,Math.max(jr.length-1,0)),termW:s,termH:a,onIndex:Ke,onPick:yw},void 0,!1,void 0,this):null,H==="themes"?oe(Px,{palette:v,themeName:c,selected:ze%vt.length,termW:s,termH:a,onIndex:Ke,onPreview:l,onPick:Qp},void 0,!1,void 0,this):null,H==="help"?oe(ax,{palette:v,termW:s,termH:a,copyKey:qp,scrollRef:Bo},void 0,!1,void 0,this):null,H==="leader"?oe(dx,{palette:v,termW:s,termH:a},void 0,!1,void 0,this):null,H==="confirm"?oe(ex,{palette:v,title:ef.title,body:ef.body,termW:s,termH:a},void 0,!1,void 0,this):null,H==="log-details"?oe(nx,{palette:v,event:is,termW:s,termH:a,scrollRef:Go},void 0,!1,void 0,this):null,H==="route-details"?oe(vx,{palette:v,route:iw,termW:s,termH:a,scrollRef:Wc},void 0,!1,void 0,this):null,H==="config-edit"&&M?oe(Qv,{palette:v,path:M.configPath,initialValue:Uc,error:dw,termW:s,termH:a,textareaRef:Bp},void 0,!1,void 0,this):null,H==="plan"&&ds?oe(hx,{palette:v,plan:ds,snap:G,busy:Gp,failed:Sw,kind:Up,termW:s,termH:a,scrollRef:Gc,initiallyRunning:uw,onDismiss:et},void 0,!1,void 0,this):null,H==="slash"||H==="plan"||H==="config-edit"||Ho||Ly(a)&&H==="none"?null:oe($v,{palette:v,overlay:H,query:ae,onQuery:we,onSubmit:Zp},void 0,!1,void 0,this),Ho?null:oe(Iv,{palette:v,screen:h,overlay:H,status:Mc,paused:gt,errorOnly:mt,width:s,copyKey:qp},void 0,!1,void 0,this)]},void 0,!0,void 0,this)},void 0,!1,void 0,this)}var _T=50,PT,RT=2000;var $b=D(()=>{st();Ci();vi();pr();Pe();wr();Xe();vr();Oa();Pt();Hv();Ae();Xv();xe();Zv();tx();rx();cx();ux();gx();yx();xx();Sx();Rx();Tx();Lx();zx();eb();rb();np();sb();fb();cp();vb();kb();Pb();Eb();Ob();Di();at();vn();Qe();Yt();PT=[]});var Ib={};ws(Ib,{renderApp:()=>vp,runTui:()=>yp,runTuiWithController:()=>LT,tuiConfigFor:()=>DT});import{createCliRenderer as TT}from"@opentui/core";import{createRoot as AT}from"@opentui/react";import{jsxDEV as OT}from"@opentui/react/jsx-dev-runtime";async function LT(e){let t=zt(e.cfg.repoRoot,e.cfg.ui.keymap);await vp(e,t)}async function yp(e){let t,n,r=!1;try{t=await Ng("",e)}catch(i){n=j(i),r=Cs(i,tr)}let o=zt(t?.cfg.repoRoot??process.cwd(),t?.cfg.ui.keymap);await vp(t,o,n,r)}async function vp(e,t=zt(e?.cfg.repoRoot??process.cwd(),e?.cfg.ui.keymap),n,r=!1){Ss();let o=of(),i=await TT({exitOnCtrlC:!1,useMouse:t.mouse,enableMouseMovement:t.mouse,useKittyKeyboard:{}}),s=AT(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(OT(Mb,{controller:e,tui:t,onQuit:l,bootError:n,bootErrorMissing:r,terminalBackground:a},void 0,!1,void 0,this))})}function DT(e){return zt(e.repoRoot,e.ui.keymap)}var xp=D(()=>{zl();Pe();$b();sl();Yt()});Ur();sl();st();zl();Xe();Ci();Pe();pr();st();wi();vr();Td();import{Command as IT}from"commander";import{setTimeout as Sp}from"timers/promises";import{stringify as FT}from"yaml";import{existsSync as Bb,readFileSync as NT}from"fs";st();ql();Pe();pr();import{createServer as O0}from"net";import{existsSync as tu,unlinkSync as M0,watch as $0}from"fs";import{cpus as I0,loadavg as F0,platform as N0,uptime as H0}from"os";import{isAbsolute as nu,join as ja}from"path";Xe();vr();import{connect as IC}from"net";var FC=2000,NC=2000,HC=200,jC=300;function Rm(e){if(e.interval_seconds<=0)return NC;return e.interval_seconds*1000}async function Em(e,t,n,r,o,i=[]){let s=e.timeout_seconds>0?e.timeout_seconds*1000:FC,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:ke,message:l instanceof Error?l.message:String(l)}}if(a==="http")return BC(e.url,s);if(a==="tcp")return GC(WC(e.address,n),s);if(a==="command")return UC(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:ke,message:"process not running"}}return{status:ke,message:`unknown health type ${e.type}`}}async function BC(e,t){let n=new AbortController,r=setTimeout(()=>n.abort(),t);try{let o=await fetch(e,{signal:n.signal});if(o.status>=HC&&o.status<jC)return{status:_t,message:String(o.status)};return{status:ke,message:String(o.status)}}catch(o){return{status:ke,message:o instanceof Error?o.message:String(o)}}finally{clearTimeout(r)}}function WC(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 GC(e,t){return new Promise((n)=>{if(e===""){n({status:ke,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:ke,message:`invalid tcp address ${e}`});return}let s=IC({host:i,port:o},()=>{s.end(),n({status:_t,message:"connected"})});s.setTimeout(t),s.on("error",(a)=>{n({status:ke,message:a.message})}),s.on("timeout",()=>{s.destroy(),n({status:ke,message:"timeout"})})})}async function UC(e,t,n,r,o){if(e.length===0)return{status:ke,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:ke,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:ke,message:`exit ${c}`}}function Tm(e){if(e===ke)return"WARN";if(e===_t)return"INFO";return"DEBUG"}import{readFileSync as KC}from"fs";import{freemem as qC,totalmem as VC}from"os";import{spawnSync as JC}from"child_process";var Ad=1024,zC=2000,YC=/page size of (\d+) bytes/i,fo;function XC(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 QC(e){let t=e.match(YC),n=t?Number(t[1]):0;if(!Number.isFinite(n)||n<=0)return;let r=fa(e,"free")+fa(e,"inactive")+fa(e,"speculative")+fa(e,"purgeable");return Math.round(r*n/Ad)}function fa(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 ZC(){if(process.platform==="linux")try{return XC(KC("/proc/meminfo","utf8"))}catch{return}if(process.platform==="darwin"){let e=Date.now();if(fo&&e-fo.at<zC)return fo.leftoverKB;let t=JC("vm_stat",{encoding:"utf8"});if(t.status!==0||!t.stdout)return fo?.leftoverKB;let n=QC(t.stdout);if(n===void 0)return fo?.leftoverKB;return fo={at:e,leftoverKB:n},n}return}function Am(){let e=Math.max(0,Math.round(VC()/Ad)),t=Math.max(0,Math.round(qC()/Ad)),n=Math.max(0,Math.min(e,ZC()??t));return{totalKB:e,unusedKB:t,leftoverKB:n}}ur();wr();vi();wr();import{pathToFileURL as T_}from"url";import{isAbsolute as A_,resolve as L_}from"path";st();Pe();ur();import{createServer as Vm,request as S_}from"http";import{randomBytes as Gm}from"crypto";import{Readable as k_}from"stream";var Ti="x-devctl-request-id",C_="x-devctl-internal-token",Um=100,Ud=new Set(["connection","keep-alive","proxy-authenticate","proxy-authorization","te","trailers","transfer-encoding","upgrade"]),__=new Set(["gzip","deflate","br"]);class Kd{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||ir(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>Um)this.recentRequests.splice(0,this.recentRequests.length-Um)}start(){if(this.cfg.listen.host==="0.0.0.0")return Promise.reject(T(Ln,"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(T(Ln,"proxy.listen.port is required when the proxy is enabled"));let t=this.cfg.listen.port;return new Promise((n,r)=>{this.server=Vm((o,i)=>{this.serve(o,i)}),this.server.on("upgrade",(o,i,s)=>{this.serveUpgrade(o,i,s)}),this.server.on("error",(o)=>r(pe(Ln,`unable to listen on ${e}:${t}`,o))),this.server.listen(t,e,()=>{this.running=!0,this.addr=`${e}:${t}`,this.bus?.publish(Oe(im,"",{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(Oe(sm,"",{})),t()})})}async serveUpgrade(e,t,n){let r=Date.now(),o=e.headers[Ti]?.toString()||Gm(8).toString("hex"),i=e.method??"GET",s=e.url??"/",a=this.detector?this.detector.redactText(s):s,c=qm(this.cfg.routes,e);if(!c){t.end(`HTTP/1.1 404 Not Found\r
|
|
624
|
+
Connection: close\r
|
|
625
|
+
Content-Length: 0\r
|
|
626
|
+
\r
|
|
627
|
+
`),this.recordRequest({timestamp:new Date().toISOString(),requestId:o,method:i,path:a,route:"",identity:"",status:404,durationMs:Date.now()-r});return}let l=dr(c.auth),d=eo(l),f,m=!1,g=(y,b)=>{if(m)return;m=!0;let k=Date.now()-r;this.recordRequest({timestamp:new Date().toISOString(),requestId:o,method:i,path:a,route:c.name,identity:d,status:y,durationMs:k,error:b}),this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:y>=400||b?"ERROR":"INFO",message:`${i} ${s} route=${c.name} identity=${d} status=${y} duration=${k}ms upgrade=true${b?` error=${b}`:""}`,pid:0,request_id:o,identity:d}),this.bus?.publish(Oe(md,c.name,{status:y,request_id:o,duration:k,identity:d}))},x=()=>{t.destroy(),f?.destroy()};try{let y={};for(let[v,C]of Object.entries(e.headers)){let h=v.toLowerCase();if(Ud.has(h)&&h!=="connection"&&h!=="upgrade")continue;if(typeof C==="string")y[v]=C;else if(Array.isArray(C))y[v]=C.join(",")}let b=e.socket.remoteAddress??"",k=y.host??"",S=y["x-forwarded-for"];if(y["x-forwarded-for"]=S?`${S}, ${b}`:b,y["x-forwarded-host"]=k,y["x-forwarded-proto"]="http",delete y.host,y[Ti]=o,this.middleware.length===0)await wa(c,y,this.tokens);for(let v of this.middleware)await v.apply({route:c,headers:y,tokens:this.tokens,req:e,method:i,path:s,upgrade:!0});let N=Km(c.upstream.url,s),K=S_(N,{method:i,headers:y});K.on("upgrade",(v,C,h)=>{f=C,this.upgradedSockets.add(t),this.upgradedSockets.add(C);let P=()=>{this.upgradedSockets.delete(t),this.upgradedSockets.delete(C)};t.once("close",()=>{P(),C.destroy()}),C.once("close",()=>{P(),t.destroy()}),t.once("error",x),C.once("error",x);let H=`HTTP/${v.httpVersion} ${v.statusCode??101} ${v.statusMessage??"Switching Protocols"}\r
|
|
628
|
+
`,Q=v.rawHeaders.map((ae,we)=>`${we%2===0?ae+":":" "+ae+`\r
|
|
629
|
+
`}`).join("");if(t.write(`${H}${Q}\r
|
|
630
|
+
`),n.length>0)C.write(n);if(h.length>0)t.write(h);t.pipe(C).pipe(t),g(v.statusCode??101)}),K.on("response",(v)=>{v.resume();let C=v.statusCode??502;t.end(`HTTP/1.1 ${C} ${v.statusMessage??"Bad Gateway"}\r
|
|
631
|
+
Connection: close\r
|
|
632
|
+
Content-Length: 0\r
|
|
633
|
+
\r
|
|
634
|
+
`),g(C,"upstream refused protocol upgrade")}),K.on("error",(v)=>{g(502,v.message),t.end(`HTTP/1.1 502 Bad Gateway\r
|
|
635
|
+
Connection: close\r
|
|
636
|
+
Content-Length: 0\r
|
|
637
|
+
\r
|
|
638
|
+
`)}),t.once("error",()=>K.destroy()),K.end()}catch(y){let b=y instanceof Error?y.message:"proxy upgrade error";g(502,b),t.end(`HTTP/1.1 502 Bad Gateway\r
|
|
639
|
+
Connection: close\r
|
|
640
|
+
Content-Length: 0\r
|
|
641
|
+
\r
|
|
642
|
+
`)}}async serve(e,t){let n=Date.now(),r=e.headers[Ti]?.toString()||Gm(8).toString("hex");t.setHeader(Ti,r);let o=e.method??"GET",i=e.url??"/",s=this.detector?this.detector.redactText(i):i,a=qm(this.cfg.routes,e);if(!a){mo(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=dr(a.auth),l=eo(c),d=0,f;try{let m={};for(let[C,h]of Object.entries(e.headers)){if(Ud.has(C.toLowerCase()))continue;if(typeof h==="string")m[C]=h;else if(Array.isArray(h))m[C]=h.join(",")}let g=e.socket.remoteAddress??"",x=m.host??"",y=m["x-forwarded-for"];if(m["x-forwarded-for"]=y?`${y}, ${g}`:g,m["x-forwarded-host"]=x,m["x-forwarded-proto"]="http",delete m.host,m["accept-encoding"]="gzip, deflate, br",m[Ti]=r,this.middleware.length===0)await wa(a,m,this.tokens);for(let C of this.middleware)await C.apply({route:a,headers:m,tokens:this.tokens});let b=Km(a.upstream.url,i),k=o!=="GET"&&o!=="HEAD"?e:void 0,S=await fetch(b,{method:o,headers:m,body:k,redirect:"manual",duplex:k?"half":void 0});t.statusCode=S.status,d=S.status;let N=(S.headers.get("content-encoding")??"").split(",").map((C)=>C.trim().toLowerCase()).filter((C)=>C!==""),K=N.length>0&&N.every((C)=>__.has(C));S.headers.forEach((C,h)=>{let P=h.toLowerCase();if(Ud.has(P))return;if(K&&(P==="content-encoding"||P==="content-length"))return;t.setHeader(h,this.detector?this.detector.redactText(C):C)}),await P_(S,t);let v=Date.now()-n;this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:S.status>=400?"WARN":"INFO",message:`${o} ${i} route=${a.name} identity=${l} status=${S.status} duration=${v}ms`,pid:0,request_id:r,identity:l}),this.bus?.publish(Oe(md,a.name,{status:S.status,request_id:r,duration:v,identity:l}))}catch(m){let g=m instanceof Error?m.message:"proxy error";f=g,d=502,this.logs?.append({timestamp:new Date().toISOString(),service:"proxy",source:"proxy",level:"ERROR",message:`${o} ${i} route=${a.name} identity=${l} error=${g}`,pid:0,request_id:r,identity:l}),mo(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 wa(e,t,n){let r=e.auth.type.toLowerCase();if(r===""||r==="none")return;if(!n)throw T(Ln,"token manager unavailable");let o=dr(e.auth),i=await n.get(eo(o),e.auth.audience,[]);t.authorization=`Bearer ${i.accessToken}`}async function P_(e,t){if(!e.body){t.end();return}let n=k_.fromWeb(e.body);await new Promise((r,o)=>{n.on("error",o),t.on("error",o),t.on("finish",r),n.pipe(t)})}function Km(e,t){let n=new URL(e),r=new URL(t||"/",n),o=new URL(n.href);if(o.pathname=R_(r.pathname),o.search=r.search,o.hash="",o.origin!==n.origin)throw T(Ln,"refusing to proxy to a different origin");return o}function R_(e){return(e.startsWith("/")?e:`/${e}`).replace(/^\/+/,"/")}function mo(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 qm(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 qd{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(T(Ln,"refusing to bind token endpoint to 0.0.0.0"));return new Promise((t,n)=>{this.server=Vm((r,o)=>{this.serve(r,o)}),this.server.on("error",(r)=>n(pe(Ln,"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(!E_(e.socket.remoteAddress)){mo(t,403,"forbidden");return}if((e.headers[C_]??"")!==this.secret){mo(t,401,"unauthorized");return}if(e.url?.startsWith("/token")!==!0){mo(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{mo(t,500,"token error")}}}function E_(e){if(!e)return!0;return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}wi();ur();var Jm=1;class zm{tokenProviders=[];identityProviders=[];pluginIdentityProviders=[];environmentSources=[];healthChecks=[];logParsers=[];proxyMiddleware=[];loadErrors=[];registerBuiltins(){this.tokenProviders.push(...mr()),this.identityProviders.push(Xl(),Ql()),this.logParsers.push(jd()),this.proxyMiddleware.push(O_())}register(e){D_(e),Sr(this.tokenProviders,e.tokenProviders),Sr(this.identityProviders,e.identityProviders),Sr(this.pluginIdentityProviders,e.identityProviders),Sr(this.environmentSources,e.environmentSources),Sr(this.healthChecks,e.healthChecks),Sr(this.logParsers,e.logParsers),Sr(this.proxyMiddleware,e.proxyMiddleware)}}async function Ym(e,t=process.cwd()){let n=new zm;n.registerBuiltins();for(let r of e){if(r.trim()==="")continue;try{let o=r.startsWith("file:")?r:A_(r)?r:L_(t,r),s=await import(o.startsWith("file:")?o:T_(o).href);if(s.sdkVersion!==Jm)throw Error(`plugin SDK version ${String(s.sdkVersion??"missing")} is incompatible; expected ${Jm}`);n.register(s)}catch(o){n.loadErrors.push({path:r,message:o instanceof Error?o.message:String(o)})}}return n}function D_(e){if(!e||typeof e!=="object")throw Error("plugin module must export an object");ho("tokenProviders",e.tokenProviders,["fetch"]),ho("identityProviders",e.identityProviders,["accepts","resolve"]),ho("environmentSources",e.environmentSources,["load"]),ho("healthChecks",e.healthChecks,["check"]),ho("logParsers",e.logParsers,["parse"]),ho("proxyMiddleware",e.proxyMiddleware,["apply"])}function ho(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 O_(){return{name:"identity_inject",apply:async(e)=>{await wa(e.route,e.headers,e.tokens)}}}function Sr(e,t){if(!t)return;e.push(...t)}Pe();var{spawn:dh}=globalThis.Bun;Xe();var{spawn:M_}=globalThis.Bun;async function Xm(e,t){if(e<=0)return;try{process.kill(-e,t);return}catch{try{process.kill(e,t)}catch{return}}}async function Qm(e){if(!Tt(e))return;let t=await Ai(["ps","-p",String(e),"-o","command="]),n=Date.now(),r=$_(await Ai(["ps","-p",String(e),"-o","etime="])),o=await I_(e);return{pid:e,command:t.trim(),cwd:o,startTime:r===void 0?void 0:new Date(n-r).toISOString()}}function $_(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 I_(e){let n=(await Ai(["lsof","-a","-p",String(e),"-d","cwd","-Fn"])).split(`
|
|
643
|
+
`).find((i)=>i.startsWith("n"));if(n&&n.length>1)return n.slice(1).trim();let r=await Ai(["pwdx",String(e)]),o=r.indexOf(":");if(o>=0)return r.slice(o+1).trim();return""}async function Ai(e){try{let t=M_({cmd:e,stdout:"pipe",stderr:"ignore"}),n=t.stdout?await new Response(t.stdout).text():"";return await t.exited,n}catch{return""}}async function Zm(e){let t=new Map;if(e.length===0)return t;let n=await Ai(["ps","-o","pid=,pcpu=,rss=","-p",e.join(",")]);for(let r of n.split(`
|
|
644
|
+
`)){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 eh(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)}Xe();var{spawn:th}=globalThis.Bun;var F_=1024;async function nh(e,t){if(e<=0)return;try{await th({cmd:["taskkill","/PID",String(e),"/T","/F"],stdout:"ignore",stderr:"ignore"}).exited}catch{return}}async function rh(e){let t=N_(hl(e),e);if(t)return t;if(!Tt(e))return;let n=await Vd(["powershell","-NoProfile","-Command",`Get-CimInstance Win32_Process -Filter "ProcessId=${e}" | Select-Object CommandLine,ExecutablePath,CreationDate | ConvertTo-Json -Compress`]),r=j_(n);if(r&&r.command!=="")return{pid:e,command:r.command,cwd:r.cwd,startTime:r.startTime};let o=await Vd(["powershell","-NoProfile","-Command",`Get-Process -Id ${e} -ErrorAction SilentlyContinue | Select-Object Path,StartTime | ConvertTo-Json -Compress`]),i=H_(o);if(!i&&!r)return;return{pid:e,command:r?.command||i?.command||"",cwd:r?.cwd||i?.cwd||"",startTime:r?.startTime||i?.startTime}}function N_(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 H_(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:ka(r),startTime:n.StartTime}}catch{let n=Sa(t,"Path");if(n==="")return;return{command:n,cwd:ka(n)}}}function j_(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=ka(o);return{command:r,cwd:i,startTime:n.CreationDate||void 0}}catch{return{command:Sa(t,"CommandLine")||Sa(t,"ExecutablePath"),cwd:ka(Sa(t,"ExecutablePath"))}}}async function oh(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 Vd(["powershell","-NoProfile","-Command",`${n}.Split(',') | ForEach-Object { Get-Process -Id $_ -ErrorAction SilentlyContinue } | Select-Object Id,CPU,WorkingSet64 | ConvertTo-Json -Compress`]);return B_(r)}function B_(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)/F_;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 ka(e){if(e==="")return"";let t=e.replace(/\//g,"\\"),n=t.lastIndexOf("\\");return n>0?t.slice(0,n):""}function Sa(e,t){let n=`${t}=`,r=e.split(/\r?\n/).find((o)=>o.startsWith(n));return r?r.slice(n.length).trim():""}async function Vd(e){try{let t=th({cmd:e,stdout:"pipe",stderr:"ignore"}),n=t.stdout?await new Response(t.stdout).text():"";return await t.exited,n}catch{return""}}Xe();Pe();var{spawn:Jd}=globalThis.Bun;async function sh(e){await U_(e.runtime,e.containerName);let t=W_(e),n=await yo(e.runtime,t,e.env);if(n.code!==0||n.stdout.trim()==="")throw T(Je,`failed to start ${e.containerName}: ${n.stderr.trim()||"container runtime returned no id"}`);let r=n.stdout.trim().split(/\s+/)[0]??"";return lh(e.runtime,e.containerName,r,e.onLine,e.onExit)}function W_(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 G_=new Set(["PATH","HOME","HOSTNAME","PWD","OLDPWD","SHLVL","_","TMPDIR"]);function ah(e){return Object.fromEntries(Object.entries(e).filter(([t])=>!G_.has(t)))}async function ch(e,t,n,r){let o=await yo(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 lh(e,t,i,n,r)}function lh(e,t,n,r,o){let i=!0,s=Jd({cmd:[e,"logs","--follow",n],stdout:"pipe",stderr:"pipe",stdin:"ignore"});ih(s.stdout,"stdout",r),ih(s.stderr,"stderr",r);let a=Jd({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),m=Number.isFinite(f)?f:d??1,g=m===0?void 0:Error(`container exited with code ${m}`);return await yo(e,["rm","--force",n],process.env),o?.(m,g),{code:m,err:g}});return{id:n,runtime:e,containerName:t,done:c,running:()=>i,stop:async(l)=>{let d=Math.max(1,Math.ceil(l/1000));await yo(e,["stop","--time",String(d),n],process.env),await c}}}async function U_(e,t){let n=await yo(e,["inspect","--format","{{.State.Running}}",t],process.env);if(n.code===0&&n.stdout.trim()==="false")await yo(e,["rm","--force",t],process.env)}async function yo(e,t,n){try{let r=Jd({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 pe(Je,`unable to run ${e}`,r)}}async function ih(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(`
|
|
645
|
+
`);i=a.pop()??"";for(let c of a)n(t,c.replace(/\r$/,""))}if(i!=="")n(t,i)}var K_=1e4,q_=2000,V_=500;class zd{running=new Map;async start(e){let t=this.running.get(e.name);if(t&&kr(t))return t;if(this.running.delete(e.name),e.args.length===0)throw T(Je,"empty command");let n=e.shell?fh(e.args):e.args,r;try{r=dh({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 pe(Je,`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 Ca(r.stdout,"stdout",e.onLine),Ca(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 T(Je,"empty command");let t;try{t=dh({cmd:e.shell?fh(e.args):e.args,cwd:e.workDir||void 0,env:e.env,stdout:"pipe",stderr:"pipe",stdin:"ignore"})}catch(a){throw pe(Je,`failed to run ${e.name}`,a)}let n="",r="",o=(a,c)=>{if(a==="stdout")n+=`${c}
|
|
646
|
+
`;else r+=`${c}
|
|
647
|
+
`;e.onLine?.(a,c)},i=[Ca(t.stdout,"stdout",o),Ca(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&&kr(t))return t;let n=await sh(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&&kr(t))return t;let n=await ch(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&&kr(t))return t;if(!Tt(e.pid))throw T(Je,`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=z_(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:K_;if(n.container){await n.container.stop(r),this.running.delete(e);return}if(await uh(n.pid,"SIGTERM"),!await mh(n.done,r)){if(await uh(n.pid,"SIGKILL"),!await mh(n.done,q_))throw T(Je,`process ${e} did not exit after SIGKILL`)}this.running.delete(e)}get(e){return this.running.get(e)}all(){return[...this.running.values()]}}function kr(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 uh(e,t){if(process.platform==="win32"){await nh(e,t);return}await Xm(e,t)}async function _a(e){if(process.platform==="win32")return rh(e);return Qm(e)}async function hh(e){if(process.platform==="win32")return oh(e);return Zm(e)}var J_=2000;function Pa(e,t){if(e.workDir!==""&&t.cwd!==""&&gh(e.workDir)!==gh(t.cwd))return!1;if(!eh(e.args,t.command))return!1;let n=ph(e.startTime),r=ph(t.startTime);if(n!==void 0&&r!==void 0)return Math.abs(n-r)<=J_;return!0}function ph(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 fh(e){if(process.platform==="win32")return["cmd.exe","/c",e.join(" ")];return["/bin/sh","-c",e.join(" ")]}function gh(e){return e.replace(/\\/g,"/").replace(/\/+$/,"")}async function z_(e){while(Tt(e))await Y_(V_);return 0}async function Ca(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(`
|
|
648
|
+
`);i=c.pop()??"";for(let l of c)n(t,l.replace(/\r$/,""))}}async function mh(e,t){return Promise.race([e.then(()=>!0),new Promise((n)=>{setTimeout(()=>n(!1),t)})])}function Y_(e){return new Promise((t)=>{setTimeout(t,e)})}Pe();Di();import{createServer as a0}from"http";var c0="2025-03-26",Dh="2.0",Eh=-32700,Th=-32600,l0=-32601,Ah=-32602,d0=-32603,u0=new Set(["127.0.0.1","localhost","::1"]);function p0(e){return u0.has(e)}class Qd{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(!p0(this.opts.host))return Promise.reject(T(Ye,`refusing to bind MCP to ${this.opts.host}`));return new Promise((e,t)=>{this.server=a0((n,r)=>{this.serve(n,r)}),this.server.on("error",(n)=>t(pe(Ye,`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,$i()),t.end();return}if(!this.authorized(e)){this.emit("WARN",`rejected unauthorized request from ${Lh(e)}`),vo(t,401,{error:"unauthorized"});return}if(g0(e)!=="/mcp"){vo(t,404,{error:"not found"});return}if(e.method==="GET"||e.method==="DELETE"){t.writeHead(405,{Allow:"POST, OPTIONS",...$i()}),t.end();return}if(e.method!=="POST"){t.writeHead(405,{Allow:"POST, OPTIONS",...$i()}),t.end();return}let r;try{r=await m0(e)}catch(a){vo(t,400,Oi(null,Eh,a instanceof Error?a.message:"invalid body"));return}let o;try{o=JSON.parse(r)}catch{vo(t,400,Oi(null,Eh,"parse error"));return}let i=Lh(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)}vo(t,200,a);return}let s=await this.dispatch(o,i);if(s===void 0){t.writeHead(202,$i()),t.end();return}vo(t,200,s)}authorized(e){if(this.opts.token==="")return!0;return(e.headers.authorization??"")===`Bearer ${this.opts.token}`}async dispatch(e,t){if(!Da(e))return Oi(null,Th,"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:Oi(r,Th,"missing method");try{let i=await this.handleMethod(n.method,Da(n.params)?n.params:{},t);if(o)return;return{jsonrpc:Dh,id:r,result:i}}catch(i){if(o)return;let s=i instanceof Mi?i.code:d0,a=i instanceof Error?i.message:"internal error";return this.emit("WARN",`rpc error method=${n.method} addr=${t}: ${a}`),Oi(r,s,a)}}async handleMethod(e,t,n){switch(e){case"initialize":{let r=f0(t);return this.emit("INFO",`client connected addr=${n}${r?` (${r})`:""}`),{protocolVersion:c0,capabilities:{tools:{},resources:{}},serverInfo:{name:"devctl",version:ut}}}case"notifications/initialized":case"ping":return{};case"tools/list":return{tools:bh(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:Yd.map((r)=>({uri:r,name:r.replace("devctl://",""),mimeType:"application/json"}))};case"resources/read":return this.readResource(t);default:throw new Mi(l0,`method not found: ${e}`)}}async callTool(e){let t=typeof e.name==="string"?e.name:"";if(t==="")throw new Mi(Ah,"tool name is required");if(Aa(t)&&!Bn(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=Da(e.arguments)?e.arguments:{},r=Date.now();try{let o=await _h(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(!Ph(t))throw new Mi(Ah,`unknown resource ${t}`);let n=await Rh(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 f0(e){let t=e.clientInfo;if(!Da(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 Lh(e){return e.socket.remoteAddress??"unknown"}class Mi extends Error{code;constructor(e,t){super(t);this.code=e}}function $i(){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 vo(e,t,n){let r=JSON.stringify(n);e.writeHead(t,{"Content-Type":"application/json","Content-Length":Buffer.byteLength(r),...$i()}),e.end(r)}function Oi(e,t,n){return{jsonrpc:Dh,id:e,error:{code:t,message:n}}}function g0(e){let t=e.url??"/",n=t.indexOf("?");return n>=0?t.slice(0,n):t}function m0(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 Da(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}Di();Oa();Yt();Ci();Li();vr();Xe();wi();var j0=4000,B0=100,Wh=30000,Gh=3,W0=2,G0=2000,U0=200,K0=3,q0=10,V0=3000;class ru{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=Uh();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=gl(),this.internalTok=yl(),this.mcpToken=hf(e.repoRoot),this.bus=new hd(2048),this.detectGoogleFn=t?.detectGoogle??Ut,this.inspectProcessFn=t?.inspectProcess??_a,this.processAliveFn=t?.processAlive??Tt,this.acquireLockFn=t?.acquireLock??mf,this.socketExistsFn=t?.socketExists??tu,this.unlinkSocketFn=t?.unlinkSocket??M0,this.detector=new gn(e.secrets.extra_markers,e.secrets.extra_patterns),this.logs=new va(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=new zd,this.tokens=t?.tokens??new co(e.auth.refresh_threshold_seconds*1000,mr(),this.bus),this.bus.subscribe((n)=>{let r=n.payload??{},o=n.type===ao?`token refreshed identity=${String(r.identity??"")}`:n.type===gr?`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===gr?"WARN":"INFO",message:o,pid:0}),n.type===ao||n.type===gr)this.syncCredentialEntries()},[ao,gr,gd]),this.setupMode=!tu(e.configPath),this.identityCache=Uh(e);for(let n of Object.keys(e.services))this.runtimes.set(n,la(n))}async run(){let e=Ps(this.cfg.repoRoot);this.lock=this.acquireLockFn(this.cfg.repoRoot,e),this.removeStaleSocket(e),this.registry=await Ym(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(),V0);let t=zt(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",j(n)));this.removeStaleSocket(e),await new Promise((n,r)=>{this.server=O0((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)}
|
|
649
|
+
`);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: ${j(c)}`)}),e.on("data",(c)=>{t+=c.toString("utf8");let l=t.split(`
|
|
650
|
+
`);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=lf(r);t({id:n.id,error:o.error,kind:o.kind,hint:o.hint,service:o.service})}}async dispatch(e,t){let n=Kh(t)?t:{};switch(e){case"ping":return{session:this.sessionID,version:ut,protocol:gi};case"start":return this.start({services:Rr(n.services),profile:typeof n.profile==="string"?n.profile:"",detach:n.detach===!0,client_env:Ba(n.client_env)});case"stop":return await this.stop(Rr(n.services)),null;case"restart":return await this.restart(Rr(n.services),{cascade:n.cascade===!0,clientEnv:Ba(n.client_env)}),null;case"run_task":return this.runTask(typeof n.name==="string"?n.name:"",Ba(n.client_env)??{});case"exec":return this.execService(typeof n.service==="string"?n.service:"",Rr(n.command),Ba(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:Rr(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:Rr(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:Rr(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??zt(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:Ls(this.cfg.shutdown);return setTimeout(()=>{this.shutdown(r)},50),null;default:throw T(Ye,`unknown method ${e}`)}}isDetached(){return this.detached}async start(e){if(e.detach===!0)this.detached=!0;let t=ua(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=Pi(this.cfg,t.services,t.profile),r=await this.detectGoogleFn(this.cfg.google.project_id);n.blockers=jg(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,T(Je,s.message));if(this.cfg.proxy.enabled&&!this.proxySuppressed)await this.startProxy().catch((s)=>this.log("devctl","ERROR",j(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 Yg(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 De&&s.service!=="")await this.fail(s.service,s);else this.log("devctl","ERROR",j(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",j(d.reason));if(l)throw T(Je,"one or more services failed to start")}try{await this.awaitWaveHealth(s,n.waves.flat())}catch(c){throw this.log("devctl","ERROR",j(c)),c}}return this.persistState(),n}async runTask(e,t){let n=this.cfg.tasks[e];if(!n)throw T(Ye,`unknown task ${e}`);if(n.dependencies.length>0)await this.start({services:n.dependencies,client_env:t});let r={...Mn(),command:n.command,shell:n.shell,working_dir:n.working_dir,dependencies:n.dependencies,environment:n.environment},o=await Us(this.cfg.repoRoot,{service:`task:${e}`,profile:this.profile,serviceCfg:r,profileEnv:this.profileEnv,assignedPorts:{},runtime:Ks(`task:${e}`,"127.0.0.1",{},"",this.cfg.project.name),cfg:this.cfg,clientEnv:t,fetchSecret:Gs(async()=>(await this.tokens.get("user","",[])).accessToken),pluginSources:this.registry?.environmentSources}),i=n.working_dir&&!nu(n.working_dir)?ja(this.cfg.repoRoot,n.working_dir):n.working_dir,s=await this.runTransient(`task:${e}`,n.command,n.shell,i,fi(o));return{task:e,...s}}async execService(e,t,n,r=!1){let o=this.cfg.services[e];if(!o)throw T(ei,`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 T(Ye,"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://${ir(this.cfg.proxy.listen)}`:"",c=Ks(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 Us(this.cfg.repoRoot,{service:e,profile:n,serviceCfg:t,profileEnv:r,assignedPorts:s,runtime:c,cfg:this.cfg,fetchSecret:Gs(async()=>(await this.tokens.get("user","",[])).accessToken),pluginSources:this.registry?.environmentSources,clientEnv:o,includeProcess:i}),d=t.working_dir&&!nu(t.working_dir)?ja(this.cfg.repoRoot,t.working_dir):t.working_dir;return{env:fi(l),workDir:d}}async runTransient(e,t,n,r,o){if(zr(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:oi(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 T(Je,`${e} exited with code ${i.code}`);return i}serviceIsActive(e){let t=this.procs.get(e);if(t&&kr(t))return!0;let n=this.runtimes.get(e);if(!n)return!1;if(n.health===_t||n.state===hr)return!0;return n.state===bd||n.state===Ft}serviceWorkDir(e){if(e.working_dir!==""&&!nu(e.working_dir))return ja(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 Xs(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-${un(this.cfg.repoRoot)}-${e.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,workDir:c,onLine:(m,g)=>this.logs.append({timestamp:new Date().toISOString(),service:e,source:m,stream:m,level:"",message:g,pid:0}),onExit:(m,g)=>this.onExit(e,s,m,g)});if(!l)return!1;let d=this.ports.get(e)??Object.fromEntries(t.ports.filter((m)=>!m.auto).map((m)=>[m.name,m.value]));this.ports.set(e,d),this.processMeta.set(e,{command:[...t.command.args],cwd:c,startTime:l.startTime}),this.setState(e,Ft,Dt,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 Xs(t);if(!n)return!1;let r=Object.values(n)[0],i=(r===void 0?void 0:await io(r))?.pid??0;if(i>0&&i!==process.pid){let s=ni(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 _a(i);if(a!==void 0&&a.command!==""&&Pa({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,Ft,Dt,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 T(Ye,`unknown service ${e}`);this.setState(e,bd,Dt,0,"");let i=this.bumpGeneration(e),s=Js(o.identity);if(s.kind!=="none")try{if(s=await Bg(o.identity,()=>Kg(this.cfg.google.project_id),this.registry?.identityProviders),s.kind==="service_account")await this.tokens.get(eo(s),"",[]),this.serviceAccountStatus.set(s.serviceAccount,"available")}catch(g){if(s.kind==="service_account")this.serviceAccountStatus.set(s.serviceAccount,"unavailable");if(X0(o)||s.kind==="service_account"||s.kind!=="user"&&s.kind!=="none")throw await this.fail(e,g),g;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(g){throw await this.fail(e,g),g}let d=(g,x)=>{this.logs.append({timestamp:new Date().toISOString(),service:e,source:g,stream:g,level:"",message:x,pid:m.pid})},f=(g,x)=>this.onExit(e,i,g,x),m=o.container?await this.procs.startContainer({name:e,runtime:o.container.runtime==="podman"?"podman":"docker",containerName:`devctl-${un(this.cfg.repoRoot)}-${e.replace(/[^a-zA-Z0-9_.-]/g,"-")}`,image:o.container.image,command:[...o.command.args],env:ah({...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:oi(this.cfg.shutdown)*1000,captureStdout:Sf(o),captureStderr:kf(o),onLine:d,onExit:f});if(this.processMeta.set(e,{command:[...o.command.args],cwd:l,startTime:m.startTime}),this.setState(e,Ft,Dt,m.pid,""),this.bus.publish(Oe(tm,e,{pid:m.pid})),r)try{await this.runTransient(`${e}:post_start`,o.hooks.post_start,o.shell,l,c)}catch(g){throw await this.fail(e,g),g}if(this.startHealth(e,o,m.pid,a,l,c,i),this.persistState(),o.startup.wait_for_healthy){let g=o.startup.timeout_seconds>0?o.startup.timeout_seconds*1000:Wh;try{await this.waitHealthy(e,g)}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://${ir(this.cfg.proxy.listen)}`;let o=Ks(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 Us(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:Gs(async()=>(await this.tokens.get("user","",[])).accessToken),pluginSources:this.registry?.environmentSources});return fi(i)}catch(i){return this.log(e,"WARN",`could not fully reconstruct environment for adopted service's health check (${j(i)}); using a baseline environment`),fi(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)=>St(a)===n&&On(a)==="service_healthy"));if(!r||r.health.type===""||!o)continue;let i=r.startup.timeout_seconds>0?r.startup.timeout_seconds*1000:Wh;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===yr)throw T(cl,`service ${e} failed while waiting for healthy`);await Q0(B0)}throw T(cl,`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===yr)return;if(o&&(o.state===wd||o.state===uo)){this.setState(e,uo,Dt,0,""),this.bus.publish(Oe(fd,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:Gh;if(c&&i&&l<d){this.setState(e,_i,Dt,0,a),this.bumpRestartCount(e,l+1),this.persistState(),this.armRestart(e,i,t,l,()=>{let f=this.serviceProfile.get(e)??this.profile,m=this.serviceProfileEnv.get(e)??this.profileEnv;this.startOne(e,f,m,!1).catch((g)=>this.log(e,"ERROR",j(g)))});return}this.fail(e,T("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=Rm(t.health)||G0,l=Date.parse(this.runtimes.get(e)?.startTime??"")||Date.now(),d=()=>{(t.container&&t.health.type.toLowerCase()==="process"?Promise.resolve(this.procs.get(e)&&kr(this.procs.get(e))?{status:_t,message:"container running"}:{status:ke,message:"container not running"}):Em(t.health,n,r,o,i,this.registry?.healthChecks)).catch((m)=>({status:ke,message:j(m)})).then((m)=>{if(!this.isCurrentGeneration(e,s))return;if(m.status===ke&&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: ${m.message}`,pid:n});return}this.setHealth(e,m.status,m.message),this.logs.append({timestamp:new Date().toISOString(),service:e,source:"health",level:Tm(m.status),message:`health ${m.status} ${m.message}`,pid:n}),this.maybeRestartUnhealthy(e,t,m.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!==uo).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 T(ei,`unknown service "${r[0]}"`);let o=t.filter((i)=>this.cfg.services[i]!==void 0);if(o.length>0)await this.runStopPlan(Ri(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,la(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?kd(this.cfg,e):e,o=n?Ri(this.cfg,e):km(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 r of e.waves.flat())if(this.clearRestartTimer(r),this.bumpGeneration(r),t?.resetRestartCounts)this.resetRestartCount(r);let n=oi(this.cfg.shutdown)*1000;for(let r of e.waves)await Promise.all(r.map(async(o)=>{this.setState(o,wd,Dt,0,"");let i=this.healthTimers.get(o);if(i)clearInterval(i),this.healthTimers.delete(o);await this.procs.stop(o,n),await this.releasePorts(o),this.setState(o,uo,Dt,0,""),this.bus.publish(Oe(fd,o,{}))}));this.persistState()}async startProxy(){if(this.proxy?.isRunning())return;if(this.proxy=new Kd(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 qd(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 Hh(this.cfg.repoRoot,e);this.mcp=new Qd({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)=>Aa(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 Hn(this.cfg))await this.probeServiceAccount(e);return jn(this.cfg)},exec:(e,t,n)=>this.execService(e,t,void 0,n)}}async reload(){let e;try{e=dt(this.cfg.repoRoot,this.cfg.configPath)}catch(i){throw this.bus.publish(Oe(bi,"",{error:j(i)})),this.log("devctl","ERROR",`configuration reload failed: ${j(i)}`),i}try{this.checkPluginHealthTypes(e),this.checkPluginIdentityTypes(e),this.checkPluginEnvironmentSources(e)}catch(i){throw this.bus.publish(Oe(bi,"",{error:j(i)})),this.log("devctl","ERROR",`configuration reload failed: ${j(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=J0(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(Oe(oa,"",{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",da(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)=>({name:r.name,identity:r.auth.identity.service_account||r.auth.identity.type||r.auth.type,upstream:r.upstream.url,auth:r.auth.type})),...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:z0()}}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 Hn(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(Oe(gd,"",{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: ${j(t)}`)}}serviceAccountSnapshot(){let e={},t={};for(let n of Hn(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 Y0(this.tokens.refresh(`sa:${e}`,"",[]),j0),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} ${po(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(`
|
|
625
651
|
`)+`
|
|
626
|
-
`}setState(e,t,r,n,o){let i=this.runtimes.get(e)??qs(e);i.state=t,i.health=r,i.pid=n,i.last_error=o;let s=t===Kt||t===cn||t===Xn;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(Ne(Ag,e,{state:t,health:r,pid:n}))}bumpRestartCount(e,t){this.restarts.set(e,t);let r=this.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:r_;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()}async pollResourceUsage(){let e=[];for(let r of this.runtimes.values())if(r.pid>0&&(r.state===Kt||r.state===cn||r.state===Xn))e.push(r.pid);if(e.length===0)return;let t=await Om(e);for(let r of this.runtimes.values()){let n=r.pid>0?t.get(r.pid):void 0;if(n)r.cpuPercent=n.cpuPercent,r.memoryKB=n.memoryKB}}setHealth(e,t,r){let n=this.runtimes.get(e);if(!n)return;if(n.health=t,n.state===Kt||n.state===cn||n.state===Xn)n.state=t===Et?cn:t===Ae?Xn:n.state;this.bus.publish(Ne(Lg,e,{health:t,message:r}))}maybeRestartUnhealthy(e,t,r,n){if(r!==Ae){if(this.unhealthyStreak.set(e,0),r===Et)this.maybeForgiveRestarts(e);return}this.healthyStreak.set(e,0);let o=t.restart.policy||(t.restart.enabled?"on_failure":"never");if(o!=="on_failure"&&o!=="always")return;let i=(this.unhealthyStreak.get(e)??0)+1;if(this.unhealthyStreak.set(e,i),i<i_)return;this.unhealthyStreak.set(e,0);let s=this.restarts.get(e)??0,a=t.restart.max_retries>0?t.restart.max_retries:lh;if(s>=a){this.log(e,"WARN",`unhealthy after ${i} consecutive checks but the restart limit (${a}) has already been reached; not restarting`);return}this.bumpRestartCount(e,s+1),this.log(e,"WARN",`restarting after ${i} consecutive unhealthy checks (attempt ${s+1}/${a})`),this.armRestart(e,t,n,s,()=>{this.restart([e],{auto:!0}).catch((c)=>this.log(e,"ERROR",H(c)))})}maybeForgiveRestarts(e){let t=(this.healthyStreak.get(e)??0)+1;if(this.healthyStreak.set(e,t),t>=s_&&(this.restarts.get(e)??0)>0)this.log(e,"INFO",`restart count reset after ${t} 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=xl(e);if(t.length===0)return;let r=new Set((this.registry?.healthChecks??[]).map((o)=>o.name.toLowerCase())),n=t.filter((o)=>!r.has(o.type.toLowerCase()));if(n.length>0)throw M(X,`unknown health check type(s): ${n.map((o)=>`${o.service}.health.type=${o.type}`).join(", ")}`)}checkPluginIdentityTypes(e=this.cfg){let t=bl(e);if(t.length===0)return;let r=(this.registry?.identityProviders??[]).filter((o)=>o.name!=="user"&&o.name!=="service_account"),n=t.filter(({service:o})=>{let i=e.services[o];return!i||!r.some((s)=>s.accepts(i.identity))});if(n.length>0)throw M(X,`unknown identity type(s): ${n.map((o)=>`${o.service}.identity.type=${o.type}`).join(", ")}`)}watchConfig(){let e=Hd(this.cfg.repoRoot,".devctl");if(!Nd(e))return;try{this.configWatcher=Y0(e,{recursive:!0},()=>{if(this.watchTimer)clearTimeout(this.watchTimer);this.watchTimer=setTimeout(()=>{this.reload().catch((t)=>this.log("devctl","WARN",H(t)))},o_)})}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 r=this.cfg.services[e],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 aa(i.pid);if(!(s!==void 0&&s.command!==""&&ca({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 Is(i),this.log(e,"INFO",`released port ${o} (pid ${i.pid})`)}catch(s){this.log(e,"WARN",H(s))}}this.ports.delete(e)}async fail(e,t){let r=this.healthTimers.get(e);if(r)clearInterval(r),this.healthTimers.delete(e);this.clearRestartTimer(e),this.bumpGeneration(e),this.setState(e,ln,jt,0,H(t));try{await this.procs.stop(e,vs(this.cfg.shutdown)*1000)}catch(n){this.log(e,"WARN",H(n))}this.bus.publish(Ne(Tg,e,{error:H(t)})),this.log(e,"ERROR",H(t)),this.persistState()}log(e,t,r){this.logs.append({timestamp:new Date().toISOString(),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)??{}})}zp(this.cfg.repoRoot,{session_id:this.sessionID,repo_root:this.cfg.repoRoot,profile:this.profile,processes:e})}attachProcess(e,t,r,n,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:r,workDir:n,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:r,cwd:n,startTime:o}),this.persistState(),i}async recoverSession(){let e=Uo(this.cfg.repoRoot);if(!e||e.processes.length===0)return;let t=[];for(let r of e.processes){if(!this.cfg.services[r.name]||r.pid<=0||r.pid===process.pid||!this.processAliveFn(r.pid))continue;let n=await this.inspectProcessFn(r.pid);if(!(n!==void 0&&n.command!==""&&ca({args:r.command,workDir:r.cwd,startTime:r.startTime?new Date(r.startTime):void 0},n))){if(Object.values(r.ports).length>0&&await Os({ports:Object.entries(r.ports).map(([c,l])=>({name:c,value:l,auto:!1}))})!==void 0)this.log(r.name,"WARN",`pid ${r.pid} does not match stored command; leftover listener not adopted`);else this.log(r.name,"WARN",`pid ${r.pid} is a different process; not adopting`);continue}let i=this.attachProcess(r.name,r.pid,r.command,r.cwd,new Date(r.startTime||Date.now()))??this.bumpGeneration(r.name);if(Object.keys(r.ports).length>0)this.ports.set(r.name,r.ports);this.setState(r.name,Kt,jt,r.pid,"");let s=this.cfg.services[r.name];if(s){let a=r.cwd||this.serviceWorkDir(s),c=await this.resolveAdoptedHealthEnv(r.name,s,r.ports);this.startHealth(r.name,s,r.pid,r.ports,a,c,i)}this.log(r.name,"INFO","adopted leftover process; stdout/stderr from before adopt are not captured"),t.push(r.name)}if(t.length>0)this.profile=e.profile||this.profile,this.bus.publish(Ne(Ig,"",{services:t,session_id:e.session_id})),this.log("devctl","INFO",`recovered session processes: ${t.join(", ")}`)}}function c_(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(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");if(JSON.stringify(e.plugins)!==JSON.stringify(t.plugins))i.push("plugins");return{restart_required:[...n].sort(),changes:r,supervisor_restart_required:i.length>0?i:void 0}}function dh(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?Er(e).map((t)=>[t,"unknown"]):[]),iap:e?.proxy.routes.some((t)=>t.auth.type.toLowerCase()==="iap")??!1}}function l_(){let e=X0(),t=nm();return{platform:Q0(),cpuCount:z0().length,loadAvg1:e[0]??0,loadAvg5:e[1]??0,loadAvg15:e[2]??0,memTotalKB:t.totalKB,memFreeKB:t.unusedKB,memAvailableKB:t.leftoverKB,hostUptimeSec:Z0()}}function d_(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 u_(e){return e.capabilities.some((t)=>["google_api","iap","service_identity"].includes(t))}function ph(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function so(e){if(!Array.isArray(e))return[];return e.filter((t)=>typeof t==="string")}function uh(e){if(!ph(e))return;let t={};for(let[r,n]of Object.entries(e))if(typeof n==="string")t[r]=n;return t}function p_(e){return new Promise((t)=>setTimeout(t,e))}fn();ga();Vt();rp();var ob=["zsh","bash","fish"];function ib(e){if(e==="zsh")return`#compdef devctl
|
|
652
|
+
`}setState(e,t,n,r,o){let i=this.runtimes.get(e)??la(e);i.state=t,i.health=n,i.pid=r,i.last_error=o;let s=t===Ft||t===hr||t===lo;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(Oe(rm,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:W0;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===Ft||n.state===hr||n.state===lo))e.push(n.pid);if(e.length===0)return;let t=await hh(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===Ft||r.state===hr||r.state===lo)r.state=t===_t?hr:t===ke?lo:r.state;this.bus.publish(Oe(om,e,{health:t,message:n}))}maybeRestartUnhealthy(e,t,n,r){if(n!==ke){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:K0;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:Gh;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",j(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:q0;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=jl(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 T(X,`unknown health check type(s): ${r.map((o)=>`${o.service}.health.type=${o.type}`).join(", ")}`)}checkPluginIdentityTypes(e=this.cfg){let t=Bl(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 T(X,`unknown identity type(s): ${r.map((o)=>`${o.service}.identity.type=${o.type}`).join(", ")}`)}checkPluginEnvironmentSources(e=this.cfg){let t=new Set(pi),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 T(X,`unknown environment source(s): ${r.join(", ")}`)}watchConfig(){let e=ja(this.cfg.repoRoot,".devctl");if(!tu(e))return;try{this.configWatcher=$0(e,{recursive:!0},()=>{if(this.watchTimer)clearTimeout(this.watchTimer);this.watchTimer=setTimeout(()=>{this.reload().catch((t)=>this.log("devctl","WARN",j(t)))},U0)})}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 io(o);if(!i||i.pid===process.pid)continue;if(n){let s=await _a(i.pid);if(!(s!==void 0&&s.command!==""&&Pa({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 Qs(i),this.log(e,"INFO",`released port ${o} (pid ${i.pid})`)}catch(s){this.log(e,"WARN",j(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,yr,Dt,0,j(t));try{await this.procs.stop(e,oi(this.cfg.shutdown)*1000)}catch(r){this.log(e,"WARN",j(r))}this.bus.publish(Oe(nm,e,{error:j(t)})),this.log(e,"ERROR",j(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)??{}})}gf(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=ni(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-${un(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,Ft,Dt,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!==""&&Pa({args:n.command,workDir:n.cwd,startTime:n.startTime?new Date(n.startTime):void 0},r))){if(Object.values(n.ports).length>0&&await Xs({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,Ft,Dt,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(Oe(am,"",{services:t,session_id:e.session_id})),this.log("devctl","INFO",`recovered session processes: ${t.join(", ")}`)}}function J0(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 Uh(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?Hn(e).map((t)=>[t,"unknown"]):[]),iap:e?.proxy.routes.some((t)=>t.auth.type.toLowerCase()==="iap")??!1}}function z0(){let e=F0(),t=Am();return{platform:N0(),cpuCount:I0().length,loadAvg1:e[0]??0,loadAvg5:e[1]??0,loadAvg15:e[2]??0,memTotalKB:t.totalKB,memFreeKB:t.unusedKB,memAvailableKB:t.leftoverKB,hostUptimeSec:H0()}}function Y0(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 X0(e){return e.capabilities.some((t)=>["google_api","iap","service_identity"].includes(t))}function Kh(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Rr(e){if(!Array.isArray(e))return[];return e.filter((t)=>typeof t==="string")}function Ba(e){if(!Kh(e))return;let t={};for(let[n,r]of Object.entries(e))if(typeof r==="string")t[n]=r;return t}function Q0(e){return new Promise((t)=>setTimeout(t,e))}wr();Oa();Yt();xp();var Fb=["zsh","bash","fish"];function Nb(e){if(e==="zsh")return`#compdef devctl
|
|
627
653
|
_devctl() {
|
|
628
654
|
local -a opts
|
|
629
655
|
local line="\${words[*]}"
|
|
@@ -643,73 +669,81 @@ complete -F _devctl devctl
|
|
|
643
669
|
devctl __complete (commandline -cp)
|
|
644
670
|
end
|
|
645
671
|
complete -c devctl -f -a "(__devctl_complete)"
|
|
646
|
-
`;throw Error(`unsupported shell "${e}"; use ${
|
|
647
|
-
`)}),e.action(async()=>{let t=e.opts();await
|
|
648
|
-
`);
|
|
649
|
-
`)}
|
|
650
|
-
`)}finally{await
|
|
651
|
-
`)}finally{await
|
|
652
|
-
`);return}if(
|
|
653
|
-
`)
|
|
654
|
-
`)
|
|
655
|
-
`)}
|
|
656
|
-
`);return}
|
|
672
|
+
`;throw Error(`unsupported shell "${e}"; use ${Fb.join(", ")}`)}function bp(e,t){let n=e.trim().split(/\s+/).filter((l)=>l!==""),r=e.endsWith(" ")?"":n[n.length-1]??"",o=e.endsWith(" ")?n:n.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 Zt(c,r);if(i==="start"||i==="stop"||i==="restart"||i==="logs"){if(r==="--profile"||o[o.length-1]==="--profile")return Zt(a,r==="--profile"?"":r);return Zt([...s,"--profile","--detach","--json","--since","--until"],r)}if(i==="completion")return Zt([...Fb].sort(),r);if(i==="run")return Zt([...Object.keys(t.tasks).sort(),"--json"],r);if(i==="exec")return Zt([...s,"--print-env","--reveal","--json"],r);if(i==="auth")return Zt(["status","login","logout","refresh"],r);if(i==="config")return Zt(["validate","show","diff"],r);if(i==="proxy")return Zt(["status","start","stop"],r);return Zt(c,r)}function Zt(e,t){if(t==="")return e;return e.filter((n)=>n.startsWith(t))}var MT="https://api.github.com/repos/amr-m-abdelgawad/devctl/releases/latest",wp="npm install --global @amr-m-abdelgawad/devctl@latest # alternatives: Homebrew or the unsigned GitHub Release binaries \u2014 see docs/installation.md";async function jb(e=fetch){try{let t=await e(MT,{headers:{Accept:"application/vnd.github+json"}});if(!t.ok)return{current:ut,latest:"",newer:!1,hint:wp};let r=((await t.json()).tag_name??"").replace(/^v/,"");return{current:ut,latest:r,newer:r!==""&&$T(r,ut)>0,hint:wp}}catch{return{current:ut,latest:"",newer:!1,hint:wp}}}function $T(e,t){let n=Hb(e),r=Hb(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 Hb(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})}Li();function HT(){let e=new IT;return e.name("devctl").description("Local development orchestrator").version(Lt(),"-V, --version","print version").option("--config <path>","path to config file or .devctl directory").enablePositionalOptions(),e.command("version").description("print version").action(()=>{E(`${Lt()}
|
|
673
|
+
`)}),e.action(async()=>{let t=e.opts();await yp(t.config??"")}),WT(e),GT(e),UT(e),BT(e),jT(e),qT(e),VT(e),XT(e),QT(e),ZT(e),eA(e),tA(e),rA(e),oA(e),iA(e),nA(e),cA(e),sA(e),aA(e),lA(e),e}function jT(e){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(t,n,r)=>{if(!r.printEnv&&n.length===0)throw Error("exec command is required (or use --print-env)");let o=await Ct("",Ce(e),!0);try{let i=await o.execService(t,n,r.printEnv===!0);if(i.environment){let s=r.reveal?i.environment:new gn(o.cfg.secrets.extra_markers,o.cfg.secrets.extra_patterns).redactMap(i.environment);if(r.json)E(JSON.stringify({...i,environment:s},null,2)+`
|
|
674
|
+
`);else for(let a of Object.keys(s).sort())E(`${a}=${s[a]}
|
|
675
|
+
`)}else if(r.json)E(JSON.stringify(i,null,2)+`
|
|
676
|
+
`);else{if(i.stdout)E(i.stdout);if(i.stderr)process.stderr.write(i.stderr)}}finally{await o.close()}})}function BT(e){e.command("run").argument("<task>","task to run").option("--json","machine-readable output").action(async(t,n)=>{let r=await Ct("",Ce(e),!0);try{let o=await r.runTask(t);if(n.json)E(JSON.stringify(o,null,2)+`
|
|
677
|
+
`);else{if(o.stdout)E(o.stdout);if(o.stderr)process.stderr.write(o.stderr)}}finally{await r.close()}})}function Ce(e){return e.optsWithGlobals().config??""}function WT(e){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(t,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 r=await Ct("",Ce(e),!0);try{let o=await r.start({services:t,profile:n.profile,detach:n.detach===!0});if(n.json){E(JSON.stringify(o,null,2)+`
|
|
678
|
+
`);return}if(E(Cd(o)),n.detach)E(`detached; services continue running
|
|
679
|
+
`)}finally{await r.close()}})}function GT(e){e.command("stop").argument("[services...]","services to stop").option("--json","machine-readable output").action(async(t,n)=>{let r=await Ct("",Ce(e),!0);try{if(await r.stop(t),n.json)E(JSON.stringify({stopped:t},null,2)+`
|
|
680
|
+
`)}finally{await r.close()}})}function UT(e){e.command("restart").argument("[services...]").option("--cascade","also restart transitive dependents (default: only the named services)").option("--json","machine-readable output").action(async(t,n)=>{let r=await Ct("",Ce(e),!0);try{if(await r.restart(t,n.cascade===!0),n.json)E(JSON.stringify({restarted:t,cascade:n.cascade===!0},null,2)+`
|
|
681
|
+
`)}finally{await r.close()}})}async function Wb(e,t){let{repoRoot:n,client:r}=await Jl("",t.repo??"",Ce(e));try{if(!r){let i=ni(n);if(t.json){E(JSON.stringify({running:!1,persisted:i},null,2)+`
|
|
682
|
+
`);return}if(E(`supervisor is not running
|
|
683
|
+
`),i&&i.processes.length>0){E(`last session ${i.session_id} profile ${i.profile||"(none)"}
|
|
684
|
+
`);for(let s of i.processes)E(`${s.name} stopped UNKNOWN ${s.pid}
|
|
685
|
+
`)}return}Vl(r,"status");let o=await r.call("status",null);if(t.json){E(JSON.stringify(o,null,2)+`
|
|
686
|
+
`);return}E(`PROFILE: ${o.profile||"(none)"}
|
|
657
687
|
|
|
658
688
|
SERVICE STATUS HEALTH PID
|
|
659
|
-
`);for(let[i,s]of Object.entries(o.services))
|
|
660
|
-
`);
|
|
689
|
+
`);for(let[i,s]of Object.entries(o.services))E(`${i} ${po(s)} ${s.health} ${s.pid}
|
|
690
|
+
`);E(`
|
|
661
691
|
PROXY ${o.proxy.running?"RUNNING":"STOPPED"} ${o.proxy.address??""}
|
|
662
|
-
`),
|
|
663
|
-
`),
|
|
664
|
-
`),
|
|
665
|
-
`)}finally{
|
|
666
|
-
`),await
|
|
667
|
-
`);try{await
|
|
668
|
-
`);return}let o=await
|
|
669
|
-
`:`stopped the supervisor for ${
|
|
670
|
-
`)})}async function
|
|
671
|
-
`}async function
|
|
672
|
-
`:
|
|
673
|
-
`);return}if(
|
|
674
|
-
`);return}for(let a of s)
|
|
675
|
-
`)}finally{await o.close()}})}function
|
|
676
|
-
`);else i();if(!t.follow)return;let s=new AbortController,a=()=>s.abort();process.on("SIGINT",a),process.on("SIGTERM",a);try{while(!s.signal.aborted){try{await
|
|
677
|
-
`);else
|
|
678
|
-
`);return}if(
|
|
679
|
-
`),
|
|
680
|
-
`),o.projectID!=="")
|
|
681
|
-
`);
|
|
682
|
-
`),
|
|
683
|
-
`)}),t.command("login").action(async()=>{await
|
|
684
|
-
`);return}if(
|
|
685
|
-
`),s)for(let[a,c]of Object.entries(s.service_account_status).sort(([l],[d])=>l.localeCompare(d)))
|
|
686
|
-
`)}finally{await
|
|
687
|
-
`);else
|
|
688
|
-
`);if(
|
|
689
|
-
`)}finally{await t.close()}})}function
|
|
690
|
-
`);return}let o=await
|
|
691
|
-
`);return}
|
|
692
|
-
`);for(let i of o.proxy.routes??[])
|
|
693
|
-
`)}finally{await
|
|
694
|
-
`);return}if(
|
|
695
|
-
|
|
696
|
-
`),o?.setup_mode===!0)
|
|
697
|
-
`),
|
|
698
|
-
`),
|
|
699
|
-
|
|
700
|
-
`);
|
|
692
|
+
`),E(`MCP ${o.mcp?.running?"RUNNING":"STOPPED"} ${o.mcp?.address??""}
|
|
693
|
+
`),E(`IDENTITY ${o.identity.user||"(unknown)"}
|
|
694
|
+
`),E(`CLOUD ${o.identity.project||"(unset)"}
|
|
695
|
+
`)}finally{r?.close()}}var KT=2000;function qT(e){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(t)=>{if(!t.watch){await Wb(e,t);return}let n=new AbortController,r=()=>n.abort();process.on("SIGINT",r),process.on("SIGTERM",r);try{while(!n.signal.aborted){E(`--- ${new Date().toISOString()} ---
|
|
696
|
+
`),await Wb(e,t),E(`
|
|
697
|
+
`);try{await Sp(KT,void 0,{signal:n.signal})}catch{break}}}finally{process.off("SIGINT",r),process.off("SIGTERM",r)}})}function VT(e){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(t)=>{let{repoRoot:n,client:r}=await Jl("",t.repo??"",Ce(e));if(!r){E(`no supervisor is running for ${n}
|
|
698
|
+
`);return}let o=await zT(r);try{let i=t.keepServices!==!0;await r.call("shutdown",{stop_services:i},o)}finally{r.close()}await JT(n,o),E(t.keepServices!==!0?`stopped services and the supervisor for ${n}
|
|
699
|
+
`:`stopped the supervisor for ${n}; its services keep running
|
|
700
|
+
`)})}async function JT(e,t){let n=Date.now()+t;while(Date.now()<n){let r=await cr(e);if(!r)return;r.close()}}async function zT(e){try{let n=await e.call("config_snapshot",null),r=typeof n.shutdown?.grace_seconds==="number"?n.shutdown.grace_seconds:0;return Math.max(5000,r*1000+2000)}catch{return 30000}}function Gb(e){return`${e.timestamp.slice(11,19)} ${e.service.padEnd(10)} ${String(e.level).padEnd(6)} ${e.message}
|
|
701
|
+
`}async function YT(e,t,n,r=1000){let o=await e(void 0);o.events.forEach(t);let i=o.nextCursor;while(!n.aborted){try{await Sp(r,void 0,{signal:n})}catch{return}o=await e(i),o.events.forEach(t),i=o.nextCursor}}function XT(e){let t=e.command("logs").argument("[services...]").enablePositionalOptions();t.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").action(async(n,r)=>{let o=await Ct("",Ce(e),!0);try{let i=r.output?go(r.output):void 0;if(r.follow&&!i){let a=new AbortController,c=()=>a.abort();process.on("SIGINT",c),process.on("SIGTERM",c);try{await YT((l)=>o.logsPage({services:n,level:r.level,search:r.search,regex:r.regex,source:r.source,since:r.since,until:r.until,cursor:l,direction:"forward"}),(l)=>E(r.json?JSON.stringify(l)+`
|
|
702
|
+
`:Gb(l)),a.signal)}finally{process.off("SIGINT",c),process.off("SIGTERM",c)}return}let s=await o.logs({services:n,level:r.level,search:r.search,regex:r.regex,source:r.source,since:r.since,until:r.until,export:i});if(i){E(`exported ${i}
|
|
703
|
+
`);return}if(r.json){E(JSON.stringify(s,null,2)+`
|
|
704
|
+
`);return}for(let a of s)E(Gb(a))}finally{await o.close()}}),t.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,r)=>{let o=await Ct("",Ce(e),!0);try{let i=go(r.output);await o.logs({services:n,level:r.level,search:r.search,regex:r.regex,source:r.source,export:i}),E(`exported ${i}
|
|
705
|
+
`)}finally{await o.close()}})}function QT(e){e.command("daemon").command("logs").option("-f, --follow","keep printing new lines until interrupted").action(async(t)=>{let{repoRoot:n}=In("",Ce(e)),r=ti(n),o=0,i=()=>{if(!Bb(r))return;let c=NT(r,"utf8");if(c.length>o)E(c.slice(o)),o=c.length};if(!Bb(r))E(`no daemon bootstrap log yet for this repository
|
|
706
|
+
`);else i();if(!t.follow)return;let s=new AbortController,a=()=>s.abort();process.on("SIGINT",a),process.on("SIGTERM",a);try{while(!s.signal.aborted){try{await Sp(500,void 0,{signal:s.signal})}catch{break}i()}}finally{process.off("SIGINT",a),process.off("SIGTERM",a)}})}function ZT(e){e.command("doctor").option("--json","machine-readable output").action(async(t)=>{let n=dt("",Ce(e)),r=await jn(n);if(t.json)E(JSON.stringify(r,null,2)+`
|
|
707
|
+
`);else E(ca(r));if(r.issues>0)process.exitCode=2})}function eA(e){e.command("setup").option("--force","overwrite an existing configuration").action(async(t)=>{await Ed("",Ce(e),t.force===!0)})}function tA(e){let t=e.command("auth").description("Google authentication");t.command("status").option("--json","machine-readable output").action(async(n)=>{let r="";try{r=dt("",Ce(e)).google.project_id}catch{r=""}let o=await Ut(r);if(n.json){E(JSON.stringify(o,null,2)+`
|
|
708
|
+
`);return}if(E(`User: ${o.userEmail||"(unknown)"}
|
|
709
|
+
`),E(`Project: ${o.projectID||"(unset)"}
|
|
710
|
+
`),o.projectID!=="")E(`Source: ${o.projectSource}
|
|
711
|
+
`);E(`ADC: ${o.adcAvailable}
|
|
712
|
+
`),E(`gcloud: ${o.gcloudInstalled}
|
|
713
|
+
`)}),t.command("login").action(async()=>{await Ys()}),t.command("logout").action(async()=>{await qg()}),t.command("refresh").option("--json","machine-readable output").action(async(n)=>{let r=await Ct("",Ce(e),!1);try{let i=await new co(As(r.cfg.auth)*1000,mr()).refresh("user","",[]),s=r.client?await r.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)+`
|
|
714
|
+
`);return}if(E(`refreshed credentials expire ${i.expiresAt.toISOString()}
|
|
715
|
+
`),s)for(let[a,c]of Object.entries(s.service_account_status).sort(([l],[d])=>l.localeCompare(d)))E(`service account ${a}: ${c}
|
|
716
|
+
`)}finally{await r.close()}})}function nA(e){e.command("reload").description("reload configuration").action(async()=>{let t=await Ct("",Ce(e),!0);try{let n=await t.reload();if(n.restart_required.length===0)E(`configuration reloaded
|
|
717
|
+
`);else E(`configuration reloaded; restart required: ${n.restart_required.join(", ")}
|
|
718
|
+
`);if(n.supervisor_restart_required&&n.supervisor_restart_required.length>0)E(`note: ${da(n.supervisor_restart_required)}
|
|
719
|
+
`)}finally{await t.close()}})}function rA(e){let t=e.command("proxy");t.command("status").option("--json").action(async(n)=>{let r=await Ct("",Ce(e),!1);try{if(!r.client){E(`PROXY STOPPED
|
|
720
|
+
`);return}let o=await r.status();if(n.json){E(JSON.stringify(o.proxy,null,2)+`
|
|
721
|
+
`);return}E(`PROXY ${o.proxy.running?"RUNNING":"STOPPED"} ${o.proxy.address??""}
|
|
722
|
+
`);for(let i of o.proxy.routes??[])E(` ${i.name.padEnd(16)} identity=${i.identity} ${i.upstream}
|
|
723
|
+
`)}finally{await r.close()}}),t.command("start").action(async()=>{let n=await Ct("",Ce(e),!0);try{await n.proxyStart()}finally{await n.close()}}),t.command("stop").action(async()=>{let n=await Ct("",Ce(e),!0);try{await n.proxyStop()}finally{await n.close()}})}function oA(e){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(t)=>{let n=t.port===void 0?void 0:Number(t.port);if(t.port!==void 0&&(!Number.isInteger(n)||(n??0)<=0))throw Error(`invalid --port ${t.port}`);let r=await Ct("",Ce(e),t.on===!0,{allowMissingConfig:!0});try{if(t.off===!0&&r.client)await r.mcpStop();else if(t.on===!0)await r.mcpStart({port:n});let o=r.client?await r.status():void 0,i=zt(r.cfg.repoRoot,r.cfg.ui.keymap),s=o?.mcp?.port??n??i.mcp_port??xo(r.cfg.repoRoot),a=o?.mcp?.address??bo(s),c=o?.mcp?.token??"";if(t.json){E(JSON.stringify({running:o?.mcp?.running===!0,setup_mode:o?.setup_mode===!0,url:a,port:s,snippets:{claude:JSON.parse(iu(a,c)),cursor:JSON.parse(su(a,c)),kilo:JSON.parse(au(a,c)),codex:cu(a,c)}},null,2)+`
|
|
724
|
+
`);return}if(E(`MCP ${o?.mcp?.running?"RUNNING":"STOPPED"} ${a}
|
|
725
|
+
|
|
726
|
+
`),o?.setup_mode===!0)E(`This repository has no .devctl yet, so the daemon is in setup mode.
|
|
727
|
+
`),E(`Connect an agent with the config below and ask it to set devctl up for this repository.
|
|
728
|
+
`),E(`It can call get_setup_guide and validate_config; nothing will run until a configuration exists.
|
|
729
|
+
|
|
730
|
+
`);E(qh(a,c))}finally{await r.close()}})}function iA(e){let t=e.command("config");t.command("validate").option("--json").action((n)=>{try{let r=dt("",Ce(e)),o=Jt(r);if(n.json){E(JSON.stringify({valid:o.length===0,issues:o},null,2)+`
|
|
701
731
|
`);return}if(o.length>0)throw Error(o.join(`
|
|
702
|
-
`));
|
|
703
|
-
`)}catch(
|
|
704
|
-
`);return}throw
|
|
705
|
-
`);return}
|
|
732
|
+
`));E(`configuration is valid
|
|
733
|
+
`)}catch(r){if(n.json){E(JSON.stringify({valid:!1,error:j(r)},null,2)+`
|
|
734
|
+
`);return}throw r}}),t.command("diff").description("show where effective configuration values came from").option("--json").action((n)=>{let r=dt("",Ce(e)),o=di(r);if(n.json){E(JSON.stringify({entries:o},null,2)+`
|
|
735
|
+
`);return}for(let i of o){E(`${i.path} = ${JSON.stringify(i.value)}
|
|
736
|
+
`),E(` winner: ${i.layer} (${i.source})
|
|
737
|
+
`);for(let s of i.shadowed)E(` shadowed: ${s.layer} (${s.source})
|
|
738
|
+
`)}}),t.command("show").option("--json").action((n)=>{let r=dt("",Ce(e));if(n.json){E(JSON.stringify(r,null,2)+`
|
|
739
|
+
`);return}E(FT(r))})}function sA(e){e.command("completion").argument("[shell]","zsh, bash, or fish").description("print a shell completion script").action((t)=>{E(Nb(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=dt("",Ce(e));E(bp(r,o).join(`
|
|
706
740
|
`)+`
|
|
707
|
-
`)}catch{
|
|
741
|
+
`)}catch{E(bp(r,or()).join(`
|
|
708
742
|
`)+`
|
|
709
|
-
`)}})}function
|
|
710
|
-
`);return}if(
|
|
711
|
-
`),
|
|
712
|
-
`),
|
|
713
|
-
`);else if(
|
|
714
|
-
`)})}function
|
|
715
|
-
`),process.exit(
|
|
743
|
+
`)}})}function aA(e){e.command("update").description("check GitHub Releases for a newer version").option("--json","machine-readable output").action(async(t)=>{let n=await jb();if(t.json){E(JSON.stringify(n,null,2)+`
|
|
744
|
+
`);return}if(E(`current ${n.current}
|
|
745
|
+
`),E(`latest ${n.latest||"(unavailable)"}
|
|
746
|
+
`),n.newer)E(`install ${n.hint}
|
|
747
|
+
`);else if(n.latest!=="")E(`up to date
|
|
748
|
+
`)})}function cA(e){e.command("attach").action(async()=>{let t=await Fg("",Ce(e)),{runTuiWithController:n}=await Promise.resolve().then(() => (xp(),Ib));await n(t)})}function lA(e){e.command("_supervisor").option("--repo <path>","repository root").action(async(t)=>{let n=ci(t.repo??"",Ce(e)),r=new ru(n),o=!1,i=()=>{if(o)return;o=!0,r.shutdown(Ls(n.shutdown)).finally(()=>process.exit(0))};process.on("SIGINT",i),process.on("SIGTERM",i),await r.run()})}async function Ub(){process.stdout.on("error",(e)=>{if(e.code==="EPIPE")process.exit(0)});try{await HT().parseAsync(process.argv)}catch(e){process.stderr.write(j(e)+`
|
|
749
|
+
`),process.exit(cf(e))}}function E(e){try{process.stdout.write(e)}catch(t){if(t.code==="EPIPE")process.exit(0);throw t}}Ss();await Ub();
|