@lensmcp/cluster 1.25.37 → 1.25.38
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/basic-ssl.js +1 -1
- package/build-host.js +1 -1
- package/build-scope-patterns.js +1 -1
- package/bundle-parent.js +1 -1
- package/checkout-cache.js +1 -1
- package/child-process-env.js +1 -1
- package/compile-retry.js +1 -1
- package/config-files.js +1 -1
- package/create-webpack-dev.js +1 -1
- package/create-webpack-prod.js +1 -1
- package/dev-devtool.js +1 -1
- package/devserver-host.js +1 -1
- package/devserver-notifier.js +1 -1
- package/devserver-transport.js +1 -1
- package/error-stack-release.js +1 -1
- package/executors/build/build.impl.js +1 -1
- package/executors/gateway/body-stall.js +1 -1
- package/executors/gateway/canonical-path.js +1 -1
- package/executors/gateway/client-ip.js +1 -1
- package/executors/gateway/gateway-errors.js +1 -1
- package/executors/gateway/gateway.impl.js +1 -1
- package/executors/gateway/gateway.lib.js +1 -1
- package/executors/gateway/health-check.js +1 -1
- package/executors/gateway/jwks-verify.js +1 -1
- package/executors/gateway/jwt-claims.js +1 -1
- package/executors/gateway/main.prod-gateway.js +2 -2
- package/executors/gateway/main.rollout.js +4 -4
- package/executors/gateway/manifest.js +1 -1
- package/executors/gateway/metrics.js +1 -1
- package/executors/gateway/otel-tracing.js +1 -1
- package/executors/gateway/prod-config.js +1 -1
- package/executors/gateway/prod-gateway.lib.js +1 -1
- package/executors/gateway/prod-runtime/access-log.js +1 -1
- package/executors/gateway/prod-runtime/app.js +1 -1
- package/executors/gateway/prod-runtime/auth.js +1 -1
- package/executors/gateway/prod-runtime/body-stall.js +1 -1
- package/executors/gateway/prod-runtime/cors.js +1 -1
- package/executors/gateway/prod-runtime/edge.js +1 -1
- package/executors/gateway/prod-runtime/handler.js +1 -1
- package/executors/gateway/prod-runtime/hooks.js +1 -1
- package/executors/gateway/prod-runtime/observability.js +1 -1
- package/executors/gateway/prod-runtime/rollout.js +1 -1
- package/executors/gateway/prod-runtime/routing.js +1 -1
- package/executors/gateway/prod-runtime/server.js +1 -1
- package/executors/gateway/prod-runtime/trust.js +1 -1
- package/executors/gateway/prod-runtime/upgrade.js +6 -6
- package/executors/gateway/prod-runtime/upstream.js +1 -1
- package/executors/gateway/providers-prod.js +1 -1
- package/executors/gateway/rate-limit.js +2 -2
- package/executors/gateway/registry-source.js +1 -1
- package/executors/gateway/rollout-ops.js +2 -2
- package/executors/gateway/runtime/act.js +1 -1
- package/executors/gateway/runtime/auth.js +1 -1
- package/executors/gateway/runtime/chooser.js +12 -12
- package/executors/gateway/runtime/control.js +2 -2
- package/executors/gateway/runtime/dev-auth.js +1 -1
- package/executors/gateway/runtime/discovery.js +1 -1
- package/executors/gateway/runtime/edge.js +1 -1
- package/executors/gateway/runtime/guest-graph.js +2 -2
- package/executors/gateway/runtime/guest-replay.js +2 -2
- package/executors/gateway/runtime/handler.js +1 -1
- package/executors/gateway/runtime/hmr-reload.js +1 -1
- package/executors/gateway/runtime/hooks.js +1 -1
- package/executors/gateway/runtime/hosted-dashboard.js +1 -1
- package/executors/gateway/runtime/instance.js +2 -2
- package/executors/gateway/runtime/lens-children.js +1 -1
- package/executors/gateway/runtime/lifecycle.js +3 -3
- package/executors/gateway/runtime/observability.js +3 -3
- package/executors/gateway/runtime/orphan-reaper.js +2 -2
- package/executors/gateway/runtime/own-log.js +6 -6
- package/executors/gateway/runtime/pod-env.js +2 -2
- package/executors/gateway/runtime/pod-output.js +1 -1
- package/executors/gateway/runtime/pod-probe.js +1 -1
- package/executors/gateway/runtime/process-names.js +1 -1
- package/executors/gateway/runtime/project-graph-store.js +1 -1
- package/executors/gateway/runtime/proxy.js +1 -1
- package/executors/gateway/runtime/registration-guards.js +1 -1
- package/executors/gateway/runtime/route-registry.js +1 -1
- package/executors/gateway/runtime/scope.js +1 -1
- package/executors/gateway/runtime/serve-launch.js +3 -3
- package/executors/gateway/runtime/server.js +2 -2
- package/executors/gateway/runtime/service-keys.js +1 -1
- package/executors/gateway/runtime/shared-build.js +3 -3
- package/executors/gateway/runtime/source-poller.js +1 -1
- package/executors/gateway/runtime/types.js +1 -1
- package/executors/gateway/runtime/upgrade.js +1 -1
- package/executors/gateway/runtime/warm-start.js +1 -1
- package/executors/gateway/runtime/workspace-log.js +1 -1
- package/executors/gateway/runtime/workspace-middleware.js +1 -1
- package/executors/gateway/runtime/workspace-registry.js +1 -1
- package/executors/gateway/ssrf-guard.js +1 -1
- package/executors/serve/serve.impl.js +1 -1
- package/executors/serve/stop-on-signal.js +1 -1
- package/executors/trust/hostname.js +1 -1
- package/executors/trust/trust.impl.js +3 -3
- package/exit-reason.js +2 -2
- package/fork-ts-check-reporter.js +1 -1
- package/gateway.js +1 -1
- package/gc-notice.js +1 -1
- package/graph-snapshot.js +1 -1
- package/handoff-retire.js +1 -1
- package/heap-snapshot.js +1 -1
- package/hot-swap-registries.js +1 -1
- package/index.js +1 -1
- package/inspector-secret.js +1 -1
- package/main.devserver.js +11 -11
- package/notice-generation.js +1 -1
- package/package.json +4 -4
- package/perf/heavy-barrel-import.js +1 -1
- package/perf/perf-config.js +1 -1
- package/perf/perf-rule-events.js +2 -2
- package/perf/perf-rules-analysis.js +1 -1
- package/perf/perf-rules-plugin.js +1 -1
- package/perf/source-scan.js +5 -5
- package/perf/workspace-libraries.js +2 -2
- package/pod-memory-events.js +2 -2
- package/pod-memory.js +1 -1
- package/pod-sock.js +1 -1
- package/process-name.js +1 -1
- package/redis-disconnect-fix.js +1 -1
- package/schema-first-instance.js +1 -1
- package/serve-runner.js +1 -1
- package/service-build-events.js +2 -2
- package/shared-build/attach.js +2 -2
- package/shared-build/host.js +3 -3
- package/shared-build/protocol.js +1 -1
- package/shared-build/shared-compilation.js +3 -3
- package/shared-build/signature.js +1 -1
- package/stdio-guard.js +1 -1
- package/swap-mode.js +1 -1
- package/swap-recycle.js +1 -1
- package/tsgo-check-plugin.js +4 -4
- package/typecheck-bus.js +3 -3
- package/typecheck-queue.js +1 -1
- package/worker-guard.js +1 -1
- package/worker-retire.js +1 -1
- package/worker-supervisor.js +2 -2
- package/workspace-paths.js +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var Te=Object.defineProperty;var R=(s,g)=>Te(s,"name",{value:g,configurable:!0});var me=Object.defineProperty,L=R((s,g)=>me(s,"name",{value:g,configurable:!0}),"L"),ve=Object.defineProperty,c=L((s,g)=>ve(s,"name",{value:g,configurable:!0}),"c");Object.defineProperty(exports,"__esModule",{value:!0}),exports.probePortFree=probePortFree,exports.probePortListening=probePortListening,exports.probeWatcherHealth=probeWatcherHealth,exports.waitForPortFree=waitForPortFree,exports.viteArgPort=viteArgPort,exports.describeChildExit=describeChildExit,exports.signalChild=signalChild,exports.claimPort=claimPort,exports.createLensChildren=createLensChildren;const tslib_1=require("tslib"),net=tslib_1.__importStar(require("node:net")),path=tslib_1.__importStar(require("node:path")),node_child_process_1=require("node:child_process"),lens_frontend_1=require("@lensmcp/nx-plugin/lens-frontend"),hmr_reload_1=require("./hmr-reload"),own_log_1=require("./own-log"),process_name_1=require("../../../process-name"),pod_env_1=require("./pod-env"),control_1=require("./control"),scope_1=require("./scope"),workspace_registry_1=require("./workspace-registry"),lifecycle_1=require("./lifecycle"),types_1=require("./types"),observability_1=require("./observability"),hosted_dashboard_1=require("./hosted-dashboard"),HEAL_BASE_MS=1500,HEAL_MAX_MS=3e4,HEAL_HEALTHY_MS=2e4,DASHBOARD_SWEEP_MS=15e3;function tryBind(s,g){return new Promise(h=>{const f=net.createServer();f.unref(),f.once("error",p=>{const w=p.code??"";h(w==="EADDRINUSE"||w==="EACCES"?"in-use":"unavailable")}),f.listen(g===void 0?{port:s}:{port:s,host:g},()=>f.close(()=>h("free")))})}R(tryBind,"tryBind"),L(tryBind,"tryBind"),c(tryBind,"tryBind");async function probePortFree(s){for(const g of[void 0,"0.0.0.0","127.0.0.1","::1"])if(await tryBind(s,g)==="in-use")return!1;return!0}R(probePortFree,"probePortFree"),L(probePortFree,"probePortFree"),c(probePortFree,"probePortFree");function probeConnect(s,g,h){return new Promise(f=>{let p=!1;const w=net.createConnection({host:s,port:g});w.unref();const m=setTimeout(()=>v(!1),h);m.unref?.();function v(Y){p||(p=!0,clearTimeout(m),w.destroy(),f(Y))}R(v,"R"),L(v,"M"),c(v,"finish"),w.once("connect",()=>v(!0)),w.once("error",()=>v(!1))})}R(probeConnect,"probeConnect"),L(probeConnect,"probeConnect"),c(probeConnect,"probeConnect");async function probePortListening(s,g=1e3){return await probeConnect("127.0.0.1",s,g)?!0:probeConnect("::1",s,g)}R(probePortListening,"probePortListening"),L(probePortListening,"probePortListening"),c(probePortListening,"probePortListening");async function probeWatcherHealth(s,g=1500){try{const h=new AbortController,f=setTimeout(()=>h.abort(),g);f.unref?.();try{const p=await fetch(`http://127.0.0.1:${s}/__lensmcp/watcher-health`,{signal:h.signal});if(!p.ok)return null;const w=await p.json();if(typeof w?.lastFsSetEventAt!="number")return null;const m=Array.isArray(w.recentEvents)?w.recentEvents.filter(v=>v&&typeof v.path=="string"&&typeof v.at=="number"&&typeof v.sequence=="number"&&["add","addDir","unlink","unlinkDir"].includes(v.kind)):[];return{schemaVersion:w.schemaVersion===2?2:1,ready:w.ready!==!1,sequence:typeof w.sequence=="number"?w.sequence:0,lastFsSetEventAt:w.lastFsSetEventAt,fsSetEvents:typeof w.fsSetEvents=="number"?w.fsSetEvents:0,recentEvents:m}}finally{clearTimeout(f)}}catch{return null}}R(probeWatcherHealth,"probeWatcherHealth"),L(probeWatcherHealth,"probeWatcherHealth"),c(probeWatcherHealth,"probeWatcherHealth");const sleepUnref=c(s=>new Promise(g=>{setTimeout(g,s).unref?.()}),"sleepUnref");async function waitForPortFree(s,g,h={}){const f=h.isPortFree??probePortFree,p=Math.max(1,h.intervalMs??types_1.PORT_FREE_POLL_MS),w=Date.now()+Math.max(0,g);for(;;){if(await f(s))return!0;const m=w-Date.now();if(m<=0)return!1;await sleepUnref(Math.min(p,m))}}R(waitForPortFree,"waitForPortFree"),L(waitForPortFree,"waitForPortFree"),c(waitForPortFree,"waitForPortFree");function viteArgPort(s){const g=c(h=>Number.isInteger(h)&&h>0&&h<65536?h:void 0,"valid");for(let h=0;h<s.length;h+=1){const f=s[h];if(f==="--port")return g(Number(s[h+1]));if(f.startsWith("--port="))return g(Number(f.slice(7)))}}R(viteArgPort,"viteArgPort"),L(viteArgPort,"viteArgPort"),c(viteArgPort,"viteArgPort");function describeChildExit(s){return s.signalCode?`killed by ${s.signalCode}`:s.exitCode===null?"exit status unknown":`exit code ${s.exitCode}`}R(describeChildExit,"describeChildExit"),L(describeChildExit,"describeChildExit"),c(describeChildExit,"describeChildExit");function signalChild(s,g){if(s.pid===void 0)return!1;try{return s.kill(g)}catch{return!1}}R(signalChild,"signalChild"),L(signalChild,"signalChild"),c(signalChild,"signalChild");async function claimPort(s,g,h,f){let p=s;for(;g.has(p)||f?.has(p)||!await h(p);)p+=1;return g.add(p),p}R(claimPort,"claimPort"),L(claimPort,"claimPort"),c(claimPort,"claimPort");function createLensChildren(s,g,h,f){const{emit:p}=g,w=f?.isPortFree??probePortFree,m=(h.ports?.length?h.ports:[443]).join(","),v=(0,control_1.clusterVersion)(),Y={LENSMCP_GATEWAY_PID:String(process.pid),...v?{LENSMCP_GATEWAY_VERSION:v}:{}},re=f?.probeWatcherHealth??probeWatcherHealth,j=[],q=new Map,T=new Map,W=new Map,X=new Map,U=new Set;let I;const A=new Map,M=new Set,J=new Set,Z=new Set,B=new Map;s.hostedDashboards=B;let K;const he=c(()=>{K||(K=setInterval(()=>{if(!s.stopped())for(const e of B.values())e.tick()},DASHBOARD_SWEEP_MS),K.unref?.())},"startDashboardSweeper"),O=new Set,b=new Map,x=new WeakMap,V=new Set,se=c((e,r,n)=>{if(V.has(e))return;V.add(e);const t=setInterval(()=>{(async()=>{if(s.stopped()||M.has(e)){clearInterval(t),V.delete(e);return}await w(r)&&(clearInterval(t),V.delete(e),console.log(`[gateway] lens child ${e}: :${r} freed \u2014 respawning.`),n())})().catch(()=>{})},types_1.LENS_PARKED_PORT_REPROBE_MS);t.unref?.()},"parkUntilPortFree"),H=c(async(e,r,n)=>{const t=await claimPort(e,r,w,n?.reserved);return t!==e&&(n?.heldBy?console.log(`[gateway] handoff: :${e} is held by ${n.heldBy} \u2014 replacement on :${t}.`):console.warn(`[gateway] port ${e} is unavailable (another process holds it \u2014 an orphan from a crashed gateway?) \u2014 using ${t} instead.`)),t},"claimFreePort"),_e=c((e,r,n)=>{const t=n?.LENSMCP_FRONTEND_KEY,o=Number(n?.LENSMCP_FRONTEND_GENERATION);if(!t||!Number.isFinite(o))return;const a=[...b.get(t)?.generations??[]].find(i=>i.generation===o);a&&(e.endsWith(":vite")?a.vite=r:e.endsWith(":browser-capture")&&(a.capture=r))},"attachRespawnedGenerationChild"),z=c(e=>{e.exitCode!==null||e.signalCode!==null||e.pid===void 0||(J.add(e),signalChild(e,"SIGTERM"),setTimeout(()=>{e.exitCode===null&&e.signalCode===null&&signalChild(e,"SIGKILL")},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.())},"retireChild"),we=c((e,r)=>{const n=A.get(e);!n||n===r||n.exitCode!==null||n.signalCode!==null||(console.warn(`[gateway] lens child ${e}: a replacement took the label \u2014 retiring the previous child (pid ${n.pid??"?"}).`),z(n))},"retireLabelHolder"),D=c((e,r,n,t,o=!1,a,i,l)=>{const E=Date.now(),_=(0,own_log_1.gatewayLogTakeover)()!==void 0,d=(0,node_child_process_1.spawn)(r,n,{cwd:i??s.root,env:{...(0,pod_env_1.podBaseEnv)(process.env,s.root,i??s.root),...t??{},LENSMCP_PARENT_PID:String(process.pid)},stdio:_?["inherit","pipe","pipe"]:"inherit"});_&&(d.stdout?.on("data",C=>process.stdout.write(C)),d.stderr?.on("data",C=>process.stderr.write(C))),j.push(d),we(e,d),A.set(e,d),_e(e,d,t);const $=e==="vite"||e.endsWith(":vite"),P=typeof t?.LENSMCP_EVENT_FILE=="string"?t.LENSMCP_EVENT_FILE:void 0,y=P&&P!==s.eventFile?P:void 0,u=$?viteArgPort(n):l;$&&T.set(d,{key:t?.LENSMCP_FRONTEND_KEY??`${i??s.root}:${t?.LENSMCP_PROJECT??"app"}`,project:t?.LENSMCP_PROJECT??"app",workspaceRoot:i??s.root,spawnedAt:E,port:u,probeFails:0,listening:!1,generation:Number(t?.LENSMCP_FRONTEND_GENERATION??0),role:t?.LENSMCP_FRONTEND_ROLE==="replacement"?"replacement":"active",...y?{bus:y}:{}});const S=e==="lens-mcp"?"lens-mcp":e==="lens-dashboard"||e.startsWith("lens-dashboard:")?"lens-dashboard":void 0;return S&&u!==void 0&&(p("info",`lens child starting: ${S} (:${u})`,`cluster-lens-child:${S}`,{kind:"lens-child-starting",project:S,label:e,pid:d.pid,port:u},void 0,y),(async()=>{const C=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!s.stopped()&&Date.now()<C;){if(d.exitCode!==null||d.signalCode!==null||M.has(e))return;if(await probePortListening(u,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){p("info",`lens child up: ${S} (:${u})`,`cluster-lens-child:${S}`,{kind:"lens-child-up",project:S,label:e,pid:d.pid,port:u},void 0,y);return}await sleepUnref(150)}})().catch(()=>{})),d.on("error",C=>{if(d.pid!==void 0){console.warn(`[gateway] lens child ${e}: ${C.message}`);return}const F=j.indexOf(d);F>=0&&j.splice(F,1),A.get(e)===d&&A.delete(e),T.delete(d),J.delete(d),console.error(`[gateway] lens child ${e} failed to spawn (${C.message}) \u2014 not started, not retried.`)}),d.on("exit",(C,F)=>{const pe=j.indexOf(d);pe>=0&&j.splice(pe,1),A.get(e)===d&&A.delete(e);const k=T.get(d);if(T.delete(d),J.delete(d))return;const Ne=M.delete(e);if(s.stopped()||Ne||(S?p("warning",`lens child exited: ${S}`,`cluster-lens-child:${S}`,{kind:"lens-child-exit",project:S,label:e,pid:d.pid,code:C,signal:F},void 0,y):k&&p("warning",`lens frontend exited: ${k.project}`,`cluster-lens-child:${k.project}`,{kind:"lens-child-exit",project:k.project,label:e,pid:d.pid,code:C,signal:F,generation:k.generation,port:k.port,ranMs:Date.now()-E},void 0,y),k&&ye(d,k)))return;const ue=Date.now()-E,N=q.get(e)??{attempts:0,portConflicts:0};(async()=>{const Ae=u!==void 0&&!await w(u),Ee=(0,lifecycle_1.isPortConflictExit)({code:C,signal:F,ranMs:ue,portHeld:Ae},{fastFailMs:types_1.CHILD_START_FAIL_MS});if(Ee&&N.portConflicts<types_1.MAX_PORT_CONFLICT_RETRIES)N.portConflicts+=1,q.set(e,N),console.warn(`[gateway] lens child ${e} lost the :${u} bind race (EADDRINUSE, code=${C}); waiting for the port, then retrying (port-retry ${N.portConflicts}/${types_1.MAX_PORT_CONFLICT_RETRIES}; crash budget untouched).`);else if(Ee){N.portConflicts=0,q.set(e,N),console.warn(`[gateway] lens child ${e}: :${u} persistently held after ${types_1.MAX_PORT_CONFLICT_RETRIES} bind races \u2014 another server owns it (an external/shared daemon?). Parking; re-probing every ${Math.round(types_1.LENS_PARKED_PORT_REPROBE_MS/1e3)}s, will respawn if it frees.`),p("warning",`lens child parked: ${e} (:${u} held externally)`,`cluster-lens-child:${e}`,{kind:"lens-child-parked",label:e,port:u}),se(e,u,()=>D(e,r,n,t,o,a,i,l));return}else{N.portConflicts=0,ue>=HEAL_HEALTHY_MS&&(N.attempts=0);const ge=Math.min(HEAL_MAX_MS,HEAL_BASE_MS*2**N.attempts);N.attempts+=1,q.set(e,N),console.warn(`[gateway] lens child ${e} exited (code=${C} sig=${F}); auto-healing in ${Math.round(ge/1e3)}s (attempt ${N.attempts}).`),await sleepUnref(ge)}s.stopped()||M.has(e)||(u!==void 0&&!await waitForPortFree(u,types_1.PORT_FREE_WAIT_MS,{isPortFree:w,intervalMs:types_1.PORT_FREE_POLL_MS})&&console.warn(`[gateway] lens child ${e}: :${u} still held after ${Math.round(types_1.PORT_FREE_WAIT_MS/1e3)}s \u2014 spawning anyway.`),!(s.stopped()||M.has(e))&&D(e,r,n,t,o,a,i,l))})().catch(()=>{})}),d},"spawnManagedChild"),ae=c(e=>{const r=`${e.wsKey}:${e.project}`,n=b.get(r);if(n)return n;const t={key:r,...e,sourceDirs:e.frontend.sourceRoots?.length?e.frontend.sourceRoots:[e.projectRoot],generation:0,state:"starting",generations:new Set,disposed:!1};b.set(r,t);for(const o of e.routes)o.lens&&(o.lens.workspaceKey??=e.wsKey,x.set(o.lens,t));return e.frontend.workspaceKey??=e.wsKey,x.set(e.frontend,t),t},"registerFrontend"),fe=c(e=>{if(!types_1.LENS_WATCH_SCOPE_ENABLED)return{};const r=path.resolve(e.projectRoot),n=e.sourceDirs.map(t=>path.resolve(t)).filter(t=>t!==r);return n.length>0?{LENSMCP_WATCH_DIRS:n.join(path.delimiter)}:{}},"lensWatchScopeEnv"),ie=c((e,r,n)=>{const t=++e.generation,o=`${e.key}:g${t}:`,a=`${o}vite`,i=`${o}browser-capture`;M.delete(a),M.delete(i);const l=c((d,$,P,y,u,S)=>D(d,$,P,y,u,S,e.workspaceRoot),"spawnInRoot"),E=(0,lens_frontend_1.spawnLensFrontend)({projectRoot:e.projectRoot,workspaceRoot:e.workspaceRoot,project:e.project,eventFile:e.eventFile,port:r,chrome:!0,headless:!0,viteEnv:{...e.frontend.env??{},...e.frontend.frozen?{LENSMCP_FREEZE:"1"}:{},LENSMCP_PROJECT:e.project,...e.replayWorkspace?{LENSMCP_REPLAY_WORKSPACE:e.replayWorkspace}:{},LENSMCP_FRONTEND_KEY:e.key,LENSMCP_FRONTEND_GENERATION:String(t),LENSMCP_FRONTEND_ROLE:n,...fe(e),NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false"},labelPrefix:o,log:c(d=>console.log(d),"log")},l),_={ownerKey:e.key,generation:t,port:r,labelPrefix:o,vite:E?.vite??A.get(a),capture:A.get(i)};return e.generations.add(_),_},"spawnFrontendGeneration"),G=c((e,r)=>{if(!e)return;b.get(e.ownerKey)?.generations.delete(e);const n=[[`${e.labelPrefix}browser-capture`,e.capture],[`${e.labelPrefix}vite`,e.vite]];for(const[t,o]of n)M.add(t),o&&z(o);r&&O.delete(e.port)},"terminateGeneration"),Se=c(async e=>{const r=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!s.stopped()&&Date.now()<r;){const n=e.vite;if(!n||n.exitCode!==null||n.signalCode!==null)return!1;if(await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){const t=await re(e.port);if(!t||t.ready)return!0}await sleepUnref(150)}return!1},"waitForGenerationReady"),Q=c(async e=>{const r=e?.vite;return!!(e&&r&&r.exitCode===null&&r.signalCode===null&&await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS)))},"generationIsServing"),ee=c(e=>!e.disposed&&!s.stopped()&&b.get(e.key)===e,"frontendIsCurrent"),te=c((e,r)=>{if(!ee(e))return Promise.resolve(!1);if(e.replacement)return e.replacement;const n=e.active;e.state=n?"replacing":"starting",e.reason=r,e.startedAt=Date.now();const t=(async()=>{let o,a;const i=Date.now();try{const l=new Set;for(const u of b.values())u!==e&&l.add(u.desiredPort);const E=n&&n.port===e.desiredPort?`g${n.generation}`:void 0,_=await H(e.desiredPort,O,{reserved:l,heldBy:E});if(a=_,!ee(e))return O.delete(_),!1;o=ie(e,_,"replacement"),e.candidate=o;const d=await Q(n);console.log(`[gateway] lens handoff start: ${e.key} g${n?.generation??0}\u2192g${o.generation} :${n?.port??"down"}\u2192:${_} reason=${r}`),p("info",`lens handoff starting: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-start",wsKey:e.wsKey,project:e.project,reason:r,generation:o.generation,oldPort:n?.port,newPort:_,oldServing:d},void 0,e.eventFile===s.eventFile?void 0:e.eventFile);const $=await Se(o);if(!ee(e))return G(o,!0),e.candidate=void 0,!1;if(!$){G(o,!0),e.candidate=void 0;const u=await Q(n);return e.state=u?"ready":"failed",u&&(e.reason=void 0,e.startedAt=void 0),console.error(`[gateway] lens handoff failed: ${e.key} g${o.generation} did not become ready within ${types_1.LENS_REPLACEMENT_READY_MS}ms; ${e.state==="ready"?"old generation kept serving":"no active generation"}.`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:r,generation:o.generation,port:_,durationMs:Date.now()-i,oldKept:u},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),!1}for(const u of e.routes)u.target=`http://localhost:${o.port}`,u.lens&&(u.lens.port=o.port);e.frontend.port=o.port,e.active=o,e.candidate=void 0,e.state="ready",e.reason=void 0,e.startedAt=void 0;const P=o.vite?T.get(o.vite):void 0;P&&(P.role="active",P.listening=!0);const y=(0,hmr_reload_1.broadcastFullReload)(s,e.key);if(console.log(`[gateway] lens handoff ready: ${e.key} g${o.generation} :${o.port} in ${Date.now()-i}ms; draining g${n?.generation??0}${y>0?`; reloading ${y} tab(s)`:""}.`),p("info",`lens handoff complete: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-complete",wsKey:e.wsKey,project:e.project,reason:r,generation:o.generation,oldPort:n?.port,newPort:o.port,durationMs:Date.now()-i,reloadedTabs:y},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),n){const u=`${n.labelPrefix}browser-capture`;M.add(u),n.capture&&z(n.capture),setTimeout(()=>G(n,!0),types_1.LENS_REPLACEMENT_DRAIN_MS).unref?.()}return!0}catch(l){G(o,!0),!o&&a!==void 0&&O.delete(a),e.candidate=void 0;const E=await Q(n);e.state=E?"ready":"failed",E&&(e.reason=void 0,e.startedAt=void 0);const _=l.message;return console.error(`[gateway] lens handoff failed: ${e.key}: ${_}`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:r,generation:o?.generation??e.generation,port:o?.port??a,durationMs:Date.now()-i,oldKept:E,error:_},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),!1}finally{e.replacement=void 0}})();return e.replacement=t,t},"rollFrontend"),le=c((e,r)=>{e.active=ie(e,r,"active"),e.state="starting",e.startedAt=Date.now()},"spawnInitialFrontend"),ye=c((e,r)=>{const n=b.get(r.key);return!n||types_1.LENS_RESTART_MODE==="in-place"?!1:(n.candidate?.vite===e||n.active?.vite!==e||(n.state="starting",n.reason="child-exit",n.startedAt=Date.now(),console.warn(`[gateway] lens frontend exited: ${n.key} g${r.generation} :${r.port} (${describeChildExit(e)}); starting an alternate-port replacement.`),te(n,"child-exit")),!0)},"handleManagedViteExit");s.lensSupervisor=types_1.LENS_RESTART_MODE==="rolling"?{status(e){const r=x.get(e);return r?{state:r.state,generation:r.candidate?.generation??r.active?.generation??r.generation,reason:r.reason,startedAt:r.startedAt}:void 0},recover(e,r){const n=x.get(e);return n?te(n,r):Promise.resolve(!1)}}:void 0;let oe=!1,ce=0;const Pe=c(()=>{oe||Date.now()-ce<types_1.POD_STALE_SCAN_MS||(oe=!0,ce=Date.now(),(async()=>{const e=new Map;for(const r of[...b.values()]){if(s.stopped())return;let n=e.get(r.workspaceRoot);if(!n){const _=(0,scope_1.readSourceSetOptions)(r.workspaceRoot);n={pass:(0,lifecycle_1.sourceScanPass)(r.workspaceRoot,_.exclude,{ignoreTests:_.ignoreTests}),startedAt:Date.now()},e.set(r.workspaceRoot,n)}const t=n.startedAt,o=await n.pass.snapshot(r.sourceDirs);if(b.get(r.key)!==r)continue;const a=r.sourceSnapshot,i=r.sourceScanStartedAt;if(r.sourceSnapshot=o,r.sourceScanStartedAt=t,!a)continue;const l=Date.now(),E=(0,lifecycle_1.diffSourceSets)(a,o,l,(0,lifecycle_1.sourceChangeWindowMs)(l,i,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS));E&&(r.sourceChange=E,p("info",`source file set changed for ${r.key}`,`cluster-lens-app:${r.project}`,{kind:"source-set-changed",scoped:!0,wsKey:r.wsKey,project:r.project,added:E.added,removed:E.removed,truncated:E.truncated},void 0,r.eventFile===s.eventFile?void 0:r.eventFile))}})().catch(()=>{}).finally(()=>{oe=!1}))},"scanFrontendSourceSets");let ne=!1;const Le=c(async(e,r)=>{if(!ne){ne=!0;try{for(const[n,t]of[...T]){if(s.stopped())return;if(t.port===void 0||n.exitCode!==null||n.signalCode!==null)continue;if(await probePortListening(t.port,types_1.LENS_PROBE_TIMEOUT_MS)){if(t.probeFails=0,!t.listening){t.listening=!0;const l=b.get(t.key);l?.active?.vite===n&&(l.state="ready",l.reason=void 0),p("info",`lens app up: ${t.project} (vite :${t.port} listening)`,`cluster-lens-app:${t.project}`,{kind:"service-up",project:t.project,port:t.port},void 0,t.bus)}continue}const o=t.listening?e.graceMs:Math.max(e.graceMs,e.neverListenedGraceMs);if(Date.now()-t.spawnedAt<o){t.probeFails=0;continue}if(!r)continue;t.probeFails+=1;const a=(0,lifecycle_1.lensChildWedged)({spawnedAt:t.spawnedAt,probeFails:t.probeFails,hasListened:t.listening},W.get(t.key)??0,Date.now(),e);if(!a)continue;const i=t.listening?"its listener VANISHED (was up, now refusing)":`it NEVER bound within the ${Math.round(o/1e3)}s boot allowance`;W.set(t.key,Date.now()),t.probeFails=0,t.listening=!1,console.error(`[gateway] wedge recycle: lens app ${t.project} is ALIVE but NOT LISTENING on :${t.port} after ${Math.max(2,e.failureThreshold)} probes \u2014 ${i} \u2014 SIGKILL; a fresh vite is coming.`),p("warning",`wedge recycle: ${t.project} (${a})`,`cluster-lens-app:${t.project}`,{kind:"pod-recycle",project:t.project,reason:a,port:t.port},void 0,t.bus),signalChild(n,"SIGKILL")}}finally{ne=!1}}},"probeLensChildren"),Ce=c(()=>{if(I||!types_1.POD_RECYCLE_ENABLED&&!types_1.LENS_PROBE_ENABLED)return;const e={graceMs:types_1.POD_STALE_GRACE_MS,settleMs:types_1.POD_RECYCLE_SETTLE_MS,cooldownMs:types_1.POD_STALE_RECYCLE_COOLDOWN_MS};I=setInterval(()=>{if(s.stopped()||T.size===0||(de(),!types_1.POD_RECYCLE_ENABLED))return;Pe();const r=Date.now();for(const[n,t]of T){const o=b.get(t.key);if(o?.frontend.frozen)continue;const a=o?.sourceChange?.changedAt??0,i=W.get(t.key)??0;(0,lifecycle_1.lensFrontendStale)(t.spawnedAt,i,a,r,e)&&((X.get(t.key)??0)>=a||U.has(t.key)||(U.add(t.key),(async()=>{try{const l=o?.sourceChange,E=l&&!l.truncated?[...l.added,...l.removed].map(P=>path.resolve(t.workspaceRoot,P)):[],_=types_1.LENS_WATCHER_PROBE_ENABLED&&t.port!==void 0?(0,lifecycle_1.lensWatcherVerdict)(await re(t.port),a,l?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,E):"unknown";if(_==="heard"){X.set(t.key,a),console.log(`[gateway] stale source set: lens app ${t.project} watcher CONFIRMED the change \u2014 no recycle, HMR intact.`),p("info",`stale check: ${t.project} watcher confirmed \u2014 no recycle`,`cluster-lens-app:${t.project}`,{kind:"pod-stale-verified",project:t.project},void 0,t.bus);return}if(_==="unknown"&&types_1.LENS_WATCHER_UNVERIFIED==="keep"){console.log(`[gateway] stale source set: lens app ${t.project} unverifiable (no watcher testimony) \u2014 keeping it (LENSMCP_LENS_WATCHER_UNVERIFIED=keep).`);return}if(n.exitCode!==null||n.signalCode!==null)return;W.set(t.key,Date.now());const d=b.get(t.key);if(types_1.LENS_RESTART_MODE==="rolling"&&d){console.log(`[gateway] stale refresh: lens app ${t.key} (stale-source-set) \u2014 watcher ${_==="missed"?"missed the exact path change":"unverifiable"}; preparing a standby without dropping traffic.`),p("warning",`stale refresh: ${t.project} (stale-source-set)`,`cluster-lens-app:${t.project}`,{kind:"pod-refresh",wsKey:d.wsKey,project:t.project,reason:"stale-source-set",watcher:_,added:l?.added,removed:l?.removed},void 0,t.bus),await te(d,"stale-source-set");return}t.listening=!1,console.log(`[gateway] zombie recycle: lens app ${t.project} (stale-source-set) \u2014 watcher ${_==="missed"?"SILENT across the change":"unverifiable"}; restarting it`),p("warning",`zombie recycle: ${t.project} (stale-source-set)`,`cluster-lens-app:${t.project}`,{kind:"pod-recycle",project:t.project,reason:"stale-source-set",watcher:_},void 0,t.bus);const $=(0,hmr_reload_1.broadcastFullReload)(s,t.key);$>0&&console.log(`[gateway] \u2192 told ${$} open tab(s) to reload (stale optimize-dep generation)`),signalChild(n,"SIGTERM"),setTimeout(()=>{n.exitCode===null&&n.signalCode===null&&(console.log(`[gateway] zombie recycle: lens app ${t.project} ignored SIGTERM for ${Math.round(types_1.LENS_RECYCLE_KILL_GRACE_MS/1e3)}s \u2014 escalating to SIGKILL.`),signalChild(n,"SIGKILL"))},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.()}finally{U.delete(t.key)}})()))}},Math.min(types_1.POD_STALE_SCAN_MS,15e3)),I.unref?.()},"startLensSweeper"),Re=c(async()=>{const e=[...new Map(s.routes.filter(t=>t.lens).map(t=>[t.project,t.lens])).values()],r=h.dashboard!==!1,n=h.mcp!==!1&&e.length>0;if(r){const t=(0,lens_frontend_1.findDashboardBundle)(s.root);if(!t)console.warn("[gateway] lens dashboard bundle not found \u2014 skipping. Install the self-contained CLI: `npm i -D lensmcp` (it ships `bundled/dashboard.js`), or `yarn nx build @lensmcp/lensmcp-mcp` in-repo.");else{const o=(0,scope_1.readLensScope)(s.root),a=await H(h.dashboardPort??o.dashboardPort,Z),i=h.lensHost??"lensmcp.local",l=o.basePath;s.registry.appendRoutes(s.wsKey,[{host:i,prefix:l,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),s.rebuildRoutes(),(0,workspace_registry_1.registerWorkspace)({key:o.key,root:s.root,base:l,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString()}),console.log(`[gateway] starting lens dashboard \u2192 http://localhost:${a} (routed at https://${i}${l}/)`),p("info",`lens dashboard up: ${i}${l} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:i,port:a,base:l}),D("lens-dashboard",(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",o.key,"dashboard")),[t],{LENSMCP_EVENT_FILE:s.eventFile,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:l,LENSMCP_REPLAY_WORKSPACE:o.key,LENSMCP_GATEWAY_PORTS:m,...Y},!1,void 0,void 0,a)}}if(n){const t=(0,lens_frontend_1.findMcpBundle)(s.root);if(!t)console.warn("[gateway] MCP server bundle not found \u2014 skipping (lens apps will still publish to the bus; an external `lensmcp mcp` can read it). Install: `npm i -D lensmcp`.");else{const o=(0,scope_1.readLensScope)(s.root),a=Number(process.env.LENSMCP_PORT??o.mcpHttpPort),i=c(()=>{console.log(`[gateway] starting lens MCP server on 127.0.0.1:${a} (${t})`),D("lens-mcp",(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",o.key,"mcp")),[t],{LENSMCP_EVENT_FILE:s.eventFile,LENSMCP_PROCESS_ROLE:"mcp",LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_PORT:String(a),LENSMCP_WORKSPACE_KEY:o.key,LENSMCP_REPLAY_WORKSPACE:o.key,LENSMCP_WORKSPACE_ROOT:s.root},!1,void 0,void 0,a)},"spawnMcp");await w(a)?i():(console.warn(`[gateway] lens MCP port :${a} is already served \u2014 an external lensmcp server (a shared daemon?) owns this workspace's MCP; not spawning a second. Re-probing every ${Math.round(types_1.LENS_PARKED_PORT_REPROBE_MS/1e3)}s; will take over if it frees.`),p("info",`lens MCP served externally on :${a} \u2014 gateway parked its own`,"cluster-lens-child:lens-mcp",{kind:"lens-child-up",project:"lens-mcp",label:"lens-mcp",port:a,external:!0}),se("lens-mcp",a,i))}}for(const t of e){if(t.started)continue;t.started=!0;const o=t.port,a=(s.registry.get(s.wsKey)?.routes??s.routes).filter(E=>E.lens?.project===t.project),i=await H(t.port,O);for(const E of a)E.lens&&(E.lens.port=i),E.target=`http://localhost:${i}`;t.port=i;const l=ae({wsKey:s.wsKey,replayWorkspace:s.wsKey,project:t.project,workspaceRoot:s.root,projectRoot:t.projectRoot,eventFile:s.eventFile,routes:a,frontend:t,desiredPort:o});try{le(l,i),p("info",`lens app started: ${t.project} (vite :${t.port})`,`cluster-lens-app:${t.project}`,{kind:"lens-app-up",project:t.project,port:t.port})}catch(E){O.delete(i),l.state="failed",console.error(`[gateway] lens app ${t.project}: ${E.message}`)}}Ce()},"bootSingletonsAndApps"),Me=c(async e=>{if(h.dashboard===!1)return;const r=(0,lens_frontend_1.findDashboardBundle)(s.root);if(!r)return;const n=(0,scope_1.readLensScope)(e.root),t=h.lensHost??"lensmcp.local",o=n.basePath,a=await H(n.dashboardPort,Z),i=`lens-dashboard:${e.wsKey}`,l=path.join(e.root,".lensmcp","events.jsonl");M.delete(i);const E=`http://localhost:${a}`;s.registry.appendRoutes(e.wsKey,[{host:t,prefix:o,project:observability_1.LENS_DASHBOARD_PROJECT,target:E}]),(0,workspace_registry_1.registerWorkspace)({key:e.wsKey,root:e.root,base:o,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString(),...e.instance?{instance:{name:e.instance.name,baseKey:e.instance.baseKey,apex:e.instance.apex}}:{}}),console.log(`[gateway] hosting dashboard for workspace '${e.wsKey}' \u2192 http://localhost:${a} (routed at https://${t}${o}/)`),p("info",`lens dashboard up: ${t}${o} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:t,port:a,base:o});const _=(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",e.wsKey,"dashboard")),d={LENSMCP_EVENT_FILE:l,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:o,LENSMCP_WS_KEY:e.wsKey,LENSMCP_HOSTED_GUEST:"1",LENSMCP_REPLAY_WORKSPACE:e.instance?.baseKey??e.wsKey,...e.sockNs?{LENSMCP_SOCK_NS:e.sockNs}:{},LENSMCP_GATEWAY_PORTS:m,...Y};let $=!1,P=!1;const y=c(()=>{const S=A.get(i);S&&z(S),A.delete(i)},"retireHolder"),u=(0,hosted_dashboard_1.createHostedDashboard)(e.wsKey,{idleMs:(0,hosted_dashboard_1.dashboardIdleMs)(),start:c(async()=>{M.delete(i),P&&await waitForPortFree(a,types_1.PORT_FREE_WAIT_MS,{isPortFree:w,intervalMs:types_1.PORT_FREE_POLL_MS}),!($||s.stopped())&&D(i,_,[r],d,!1,void 0,e.root,a)},"start"),stop:c(()=>{P=!0,M.add(i),y()},"stop"),listening:c(()=>probePortListening(a,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS)),"listening"),servicesUp:c(()=>(s.registry.get(e.wsKey)?.services??[]).some(S=>S.state!=="down"),"servicesUp")});return B.set(E,u),he(),u.tick(),()=>{$=!0,u.dispose(),B.get(E)===u&&B.delete(E),M.add(i),Z.delete(a),(0,workspace_registry_1.unregisterWorkspace)(e.wsKey),y()}},"hostWorkspaceDashboard"),be=c(async e=>{const r=new Map;for(const o of e.routes){if(!o.lens)continue;const a=r.get(o.lens.project)??[];a.push(o),r.set(o.lens.project,a)}if(r.size===0)return()=>{};const n=path.join(e.root,".lensmcp","events.jsonl"),t=[];for(const[o,a]of r){const i=a[0].lens;if(i.started)continue;const l=await H(i.port,O),E=i.port;for(const d of a)d.lens.started=!0,d.lens.port=l,d.target=`http://localhost:${l}`;const _=ae({wsKey:e.wsKey,replayWorkspace:e.instance?.baseKey??e.wsKey,project:o,workspaceRoot:e.root,projectRoot:i.projectRoot,eventFile:n,routes:a,frontend:i,desiredPort:E});t.push(_),console.log(`[gateway] hosting lens app '${o}' of '${e.wsKey}' \u2192 vite :${l}`);try{le(_,l),p("info",`lens app started: ${e.wsKey}/${o} (vite :${l})`,`cluster-lens-app:${e.wsKey}:${o}`,{kind:"lens-app-up",project:o,port:l},void 0,n)}catch(d){O.delete(l),_.state="failed",console.error(`[gateway] lens app ${e.wsKey}/${o}: ${d.message}`)}}return()=>{for(const o of t){o.disposed=!0;for(const a of[...o.generations])G(a,!0);for(const a of o.routes)a.lens&&x.delete(a.lens);x.delete(o.frontend),W.delete(o.key),X.delete(o.key),U.delete(o.key),b.delete(o.key)}}},"hostWorkspaceApps"),$e=c(async(e=2500)=>{I&&(clearInterval(I),I=void 0),K&&(clearInterval(K),K=void 0);const r=[...j];for(const o of r)signalChild(o,"SIGTERM");const n=c(o=>o.exitCode===null&&o.signalCode===null,"alive"),t=Date.now()+e;for(;Date.now()<t&&r.some(n);)await new Promise(o=>setTimeout(o,100));for(const o of r)n(o)&&signalChild(o,"SIGKILL")},"reapAll"),de=c(()=>Le({graceMs:types_1.LENS_PROBE_GRACE_MS,failureThreshold:types_1.LENS_PROBE_FAILS,cooldownMs:types_1.LENS_PROBE_COOLDOWN_MS,neverListenedGraceMs:types_1.LENS_PROBE_BOOT_GRACE_MS},types_1.LENS_PROBE_ENABLED),"probeLensFrontends");return{spawnManagedChild:D,bootSingletonsAndApps:Re,hostWorkspaceDashboard:Me,hostWorkspaceApps:be,probeLensFrontends:de,reapAll:$e}}R(createLensChildren,"createLensChildren"),L(createLensChildren,"createLensChildren"),c(createLensChildren,"createLensChildren");
|
|
1
|
+
"use strict";var me=Object.defineProperty;var L=(s,h)=>me(s,"name",{value:h,configurable:!0});var ve=Object.defineProperty,c=L((s,h)=>ve(s,"name",{value:h,configurable:!0}),"c");Object.defineProperty(exports,"__esModule",{value:!0}),exports.probePortFree=probePortFree,exports.probePortListening=probePortListening,exports.probeWatcherHealth=probeWatcherHealth,exports.waitForPortFree=waitForPortFree,exports.viteArgPort=viteArgPort,exports.describeChildExit=describeChildExit,exports.signalChild=signalChild,exports.claimPort=claimPort,exports.createLensChildren=createLensChildren;const tslib_1=require("tslib"),net=tslib_1.__importStar(require("node:net")),path=tslib_1.__importStar(require("node:path")),node_child_process_1=require("node:child_process"),lens_frontend_1=require("@lensmcp/nx-plugin/lens-frontend"),hmr_reload_1=require("./hmr-reload"),own_log_1=require("./own-log"),process_name_1=require("../../../process-name"),pod_env_1=require("./pod-env"),control_1=require("./control"),scope_1=require("./scope"),workspace_registry_1=require("./workspace-registry"),lifecycle_1=require("./lifecycle"),types_1=require("./types"),observability_1=require("./observability"),hosted_dashboard_1=require("./hosted-dashboard"),HEAL_BASE_MS=1500,HEAL_MAX_MS=3e4,HEAL_HEALTHY_MS=2e4,DASHBOARD_SWEEP_MS=15e3;function tryBind(s,h){return new Promise(f=>{const _=net.createServer();_.unref(),_.once("error",p=>{const w=p.code??"";f(w==="EADDRINUSE"||w==="EACCES"?"in-use":"unavailable")}),_.listen(h===void 0?{port:s}:{port:s,host:h},()=>_.close(()=>f("free")))})}L(tryBind,"tryBind"),c(tryBind,"tryBind");async function probePortFree(s){for(const h of[void 0,"0.0.0.0","127.0.0.1","::1"])if(await tryBind(s,h)==="in-use")return!1;return!0}L(probePortFree,"probePortFree"),c(probePortFree,"probePortFree");function probeConnect(s,h,f){return new Promise(_=>{let p=!1;const w=net.createConnection({host:s,port:h});w.unref();const b=setTimeout(()=>R(!1),f);b.unref?.();function R(H){p||(p=!0,clearTimeout(b),w.destroy(),_(H))}L(R,"M"),c(R,"finish"),w.once("connect",()=>R(!0)),w.once("error",()=>R(!1))})}L(probeConnect,"probeConnect"),c(probeConnect,"probeConnect");async function probePortListening(s,h=1e3){return await probeConnect("127.0.0.1",s,h)?!0:probeConnect("::1",s,h)}L(probePortListening,"probePortListening"),c(probePortListening,"probePortListening");async function probeWatcherHealth(s,h=1500){try{const f=new AbortController,_=setTimeout(()=>f.abort(),h);_.unref?.();try{const p=await fetch(`http://127.0.0.1:${s}/__lensmcp/watcher-health`,{signal:f.signal});if(!p.ok)return null;const w=await p.json();if(typeof w?.lastFsSetEventAt!="number")return null;const b=Array.isArray(w.recentEvents)?w.recentEvents.filter(R=>R&&typeof R.path=="string"&&typeof R.at=="number"&&typeof R.sequence=="number"&&["add","addDir","unlink","unlinkDir"].includes(R.kind)):[];return{schemaVersion:w.schemaVersion===2?2:1,ready:w.ready!==!1,sequence:typeof w.sequence=="number"?w.sequence:0,lastFsSetEventAt:w.lastFsSetEventAt,fsSetEvents:typeof w.fsSetEvents=="number"?w.fsSetEvents:0,recentEvents:b}}finally{clearTimeout(_)}}catch{return null}}L(probeWatcherHealth,"probeWatcherHealth"),c(probeWatcherHealth,"probeWatcherHealth");const sleepUnref=c(s=>new Promise(h=>{setTimeout(h,s).unref?.()}),"sleepUnref");async function waitForPortFree(s,h,f={}){const _=f.isPortFree??probePortFree,p=Math.max(1,f.intervalMs??types_1.PORT_FREE_POLL_MS),w=Date.now()+Math.max(0,h);for(;;){if(await _(s))return!0;const b=w-Date.now();if(b<=0)return!1;await sleepUnref(Math.min(p,b))}}L(waitForPortFree,"waitForPortFree"),c(waitForPortFree,"waitForPortFree");function viteArgPort(s){const h=c(f=>Number.isInteger(f)&&f>0&&f<65536?f:void 0,"valid");for(let f=0;f<s.length;f+=1){const _=s[f];if(_==="--port")return h(Number(s[f+1]));if(_.startsWith("--port="))return h(Number(_.slice(7)))}}L(viteArgPort,"viteArgPort"),c(viteArgPort,"viteArgPort");function describeChildExit(s){return s.signalCode?`killed by ${s.signalCode}`:s.exitCode===null?"exit status unknown":`exit code ${s.exitCode}`}L(describeChildExit,"describeChildExit"),c(describeChildExit,"describeChildExit");function signalChild(s,h){if(s.pid===void 0)return!1;try{return s.kill(h)}catch{return!1}}L(signalChild,"signalChild"),c(signalChild,"signalChild");async function claimPort(s,h,f,_){let p=s;for(;h.has(p)||_?.has(p)||!await f(p);)p+=1;return h.add(p),p}L(claimPort,"claimPort"),c(claimPort,"claimPort");function createLensChildren(s,h,f,_){const{emit:p}=h,w=_?.isPortFree??probePortFree,b=(f.ports?.length?f.ports:[443]).join(","),R=(0,control_1.clusterVersion)(),H={LENSMCP_GATEWAY_PID:String(process.pid),...R?{LENSMCP_GATEWAY_VERSION:R}:{}},ne=_?.probeWatcherHealth??probeWatcherHealth,j=[],Y=new Map,A=new Map,x=new Map,z=new Map,q=new Set;let F;const m=new Map,C=new Set,X=new Set,J=new Set,W=new Map;s.hostedDashboards=W;let I;const fe=c(()=>{I||(I=setInterval(()=>{if(!s.stopped())for(const e of W.values())e.tick()},DASHBOARD_SWEEP_MS),I.unref?.())},"startDashboardSweeper"),T=new Set,M=new Map,K=new WeakMap,U=new Set,re=c((e,r,n)=>{if(U.has(e))return;U.add(e);const t=setInterval(()=>{(async()=>{if(s.stopped()||C.has(e)){clearInterval(t),U.delete(e);return}await w(r)&&(clearInterval(t),U.delete(e),console.log(`[gateway] lens child ${e}: :${r} freed \u2014 respawning.`),n())})().catch(()=>{})},types_1.LENS_PARKED_PORT_REPROBE_MS);t.unref?.()},"parkUntilPortFree"),B=c(async(e,r,n)=>{const t=await claimPort(e,r,w,n?.reserved);return t!==e&&(n?.heldBy?console.log(`[gateway] handoff: :${e} is held by ${n.heldBy} \u2014 replacement on :${t}.`):console.warn(`[gateway] port ${e} is unavailable (another process holds it \u2014 an orphan from a crashed gateway?) \u2014 using ${t} instead.`)),t},"claimFreePort"),ge=c((e,r,n)=>{const t=n?.LENSMCP_FRONTEND_KEY,o=Number(n?.LENSMCP_FRONTEND_GENERATION);if(!t||!Number.isFinite(o))return;const a=[...M.get(t)?.generations??[]].find(i=>i.generation===o);a&&(e.endsWith(":vite")?a.vite=r:e.endsWith(":browser-capture")&&(a.capture=r))},"attachRespawnedGenerationChild"),V=c(e=>{e.exitCode!==null||e.signalCode!==null||e.pid===void 0||(X.add(e),signalChild(e,"SIGTERM"),setTimeout(()=>{e.exitCode===null&&e.signalCode===null&&signalChild(e,"SIGKILL")},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.())},"retireChild"),he=c((e,r)=>{const n=m.get(e);!n||n===r||n.exitCode!==null||n.signalCode!==null||(console.warn(`[gateway] lens child ${e}: a replacement took the label \u2014 retiring the previous child (pid ${n.pid??"?"}).`),V(n))},"retireLabelHolder"),k=c((e,r,n,t,o=!1,a,i,l)=>{const E=Date.now(),g=(0,own_log_1.gatewayLogTakeover)()!==void 0,d=(0,node_child_process_1.spawn)(r,n,{cwd:i??s.root,env:{...(0,pod_env_1.podBaseEnv)(process.env,s.root,i??s.root),...t??{},LENSMCP_PARENT_PID:String(process.pid)},stdio:g?["inherit","pipe","pipe"]:"inherit"});g&&(d.stdout?.on("data",P=>process.stdout.write(P)),d.stderr?.on("data",P=>process.stderr.write(P))),j.push(d),he(e,d),m.set(e,d),ge(e,d,t);const $=e==="vite"||e.endsWith(":vite"),v=typeof t?.LENSMCP_EVENT_FILE=="string"?t.LENSMCP_EVENT_FILE:void 0,y=v&&v!==s.eventFile?v:void 0,u=$?viteArgPort(n):l;$&&A.set(d,{key:t?.LENSMCP_FRONTEND_KEY??`${i??s.root}:${t?.LENSMCP_PROJECT??"app"}`,project:t?.LENSMCP_PROJECT??"app",workspaceRoot:i??s.root,spawnedAt:E,port:u,probeFails:0,listening:!1,generation:Number(t?.LENSMCP_FRONTEND_GENERATION??0),role:t?.LENSMCP_FRONTEND_ROLE==="replacement"?"replacement":"active",...y?{bus:y}:{}});const S=e==="lens-mcp"?"lens-mcp":e==="lens-dashboard"||e.startsWith("lens-dashboard:")?"lens-dashboard":void 0;return S&&u!==void 0&&(p("info",`lens child starting: ${S} (:${u})`,`cluster-lens-child:${S}`,{kind:"lens-child-starting",project:S,label:e,pid:d.pid,port:u},void 0,y),(async()=>{const P=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!s.stopped()&&Date.now()<P;){if(d.exitCode!==null||d.signalCode!==null||C.has(e))return;if(await probePortListening(u,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){p("info",`lens child up: ${S} (:${u})`,`cluster-lens-child:${S}`,{kind:"lens-child-up",project:S,label:e,pid:d.pid,port:u},void 0,y);return}await sleepUnref(150)}})().catch(()=>{})),d.on("error",P=>{if(d.pid!==void 0){console.warn(`[gateway] lens child ${e}: ${P.message}`);return}const D=j.indexOf(d);D>=0&&j.splice(D,1),m.get(e)===d&&m.delete(e),A.delete(d),X.delete(d),console.error(`[gateway] lens child ${e} failed to spawn (${P.message}) \u2014 not started, not retried.`)}),d.on("exit",(P,D)=>{const de=j.indexOf(d);de>=0&&j.splice(de,1),m.get(e)===d&&m.delete(e);const O=A.get(d);if(A.delete(d),X.delete(d))return;const Ne=C.delete(e);if(s.stopped()||Ne||(S?p("warning",`lens child exited: ${S}`,`cluster-lens-child:${S}`,{kind:"lens-child-exit",project:S,label:e,pid:d.pid,code:P,signal:D},void 0,y):O&&p("warning",`lens frontend exited: ${O.project}`,`cluster-lens-child:${O.project}`,{kind:"lens-child-exit",project:O.project,label:e,pid:d.pid,code:P,signal:D,generation:O.generation,port:O.port,ranMs:Date.now()-E},void 0,y),O&&Se(d,O)))return;const pe=Date.now()-E,N=Y.get(e)??{attempts:0,portConflicts:0};(async()=>{const be=u!==void 0&&!await w(u),ue=(0,lifecycle_1.isPortConflictExit)({code:P,signal:D,ranMs:pe,portHeld:be},{fastFailMs:types_1.CHILD_START_FAIL_MS});if(ue&&N.portConflicts<types_1.MAX_PORT_CONFLICT_RETRIES)N.portConflicts+=1,Y.set(e,N),console.warn(`[gateway] lens child ${e} lost the :${u} bind race (EADDRINUSE, code=${P}); waiting for the port, then retrying (port-retry ${N.portConflicts}/${types_1.MAX_PORT_CONFLICT_RETRIES}; crash budget untouched).`);else if(ue){N.portConflicts=0,Y.set(e,N),console.warn(`[gateway] lens child ${e}: :${u} persistently held after ${types_1.MAX_PORT_CONFLICT_RETRIES} bind races \u2014 another server owns it (an external/shared daemon?). Parking; re-probing every ${Math.round(types_1.LENS_PARKED_PORT_REPROBE_MS/1e3)}s, will respawn if it frees.`),p("warning",`lens child parked: ${e} (:${u} held externally)`,`cluster-lens-child:${e}`,{kind:"lens-child-parked",label:e,port:u}),re(e,u,()=>k(e,r,n,t,o,a,i,l));return}else{N.portConflicts=0,pe>=HEAL_HEALTHY_MS&&(N.attempts=0);const Ee=Math.min(HEAL_MAX_MS,HEAL_BASE_MS*2**N.attempts);N.attempts+=1,Y.set(e,N),console.warn(`[gateway] lens child ${e} exited (code=${P} sig=${D}); auto-healing in ${Math.round(Ee/1e3)}s (attempt ${N.attempts}).`),await sleepUnref(Ee)}s.stopped()||C.has(e)||(u!==void 0&&!await waitForPortFree(u,types_1.PORT_FREE_WAIT_MS,{isPortFree:w,intervalMs:types_1.PORT_FREE_POLL_MS})&&console.warn(`[gateway] lens child ${e}: :${u} still held after ${Math.round(types_1.PORT_FREE_WAIT_MS/1e3)}s \u2014 spawning anyway.`),!(s.stopped()||C.has(e))&&k(e,r,n,t,o,a,i,l))})().catch(()=>{})}),d},"spawnManagedChild"),se=c(e=>{const r=`${e.wsKey}:${e.project}`,n=M.get(r);if(n)return n;const t={key:r,...e,sourceDirs:e.frontend.sourceRoots?.length?e.frontend.sourceRoots:[e.projectRoot],generation:0,state:"starting",generations:new Set,disposed:!1};M.set(r,t);for(const o of e.routes)o.lens&&(o.lens.workspaceKey??=e.wsKey,K.set(o.lens,t));return e.frontend.workspaceKey??=e.wsKey,K.set(e.frontend,t),t},"registerFrontend"),we=c(e=>{if(!types_1.LENS_WATCH_SCOPE_ENABLED)return{};const r=path.resolve(e.projectRoot),n=e.sourceDirs.map(t=>path.resolve(t)).filter(t=>t!==r);return n.length>0?{LENSMCP_WATCH_DIRS:n.join(path.delimiter)}:{}},"lensWatchScopeEnv"),ae=c((e,r,n)=>{const t=++e.generation,o=`${e.key}:g${t}:`,a=`${o}vite`,i=`${o}browser-capture`;C.delete(a),C.delete(i);const l=c((d,$,v,y,u,S)=>k(d,$,v,y,u,S,e.workspaceRoot),"spawnInRoot"),E=(0,lens_frontend_1.spawnLensFrontend)({projectRoot:e.projectRoot,workspaceRoot:e.workspaceRoot,project:e.project,eventFile:e.eventFile,port:r,chrome:!0,headless:!0,viteEnv:{...e.frontend.env??{},...e.frontend.frozen?{LENSMCP_FREEZE:"1"}:{},LENSMCP_PROJECT:e.project,...e.replayWorkspace?{LENSMCP_REPLAY_WORKSPACE:e.replayWorkspace}:{},LENSMCP_FRONTEND_KEY:e.key,LENSMCP_FRONTEND_GENERATION:String(t),LENSMCP_FRONTEND_ROLE:n,...we(e),NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false"},labelPrefix:o,log:c(d=>console.log(d),"log")},l),g={ownerKey:e.key,generation:t,port:r,labelPrefix:o,vite:E?.vite??m.get(a),capture:m.get(i)};return e.generations.add(g),g},"spawnFrontendGeneration"),G=c((e,r)=>{if(!e)return;M.get(e.ownerKey)?.generations.delete(e);const n=[[`${e.labelPrefix}browser-capture`,e.capture],[`${e.labelPrefix}vite`,e.vite]];for(const[t,o]of n)C.add(t),o&&V(o);r&&T.delete(e.port)},"terminateGeneration"),_e=c(async e=>{const r=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!s.stopped()&&Date.now()<r;){const n=e.vite;if(!n||n.exitCode!==null||n.signalCode!==null)return!1;if(await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){const t=await ne(e.port);if(!t||t.ready)return!0}await sleepUnref(150)}return!1},"waitForGenerationReady"),Z=c(async e=>{const r=e?.vite;return!!(e&&r&&r.exitCode===null&&r.signalCode===null&&await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS)))},"generationIsServing"),Q=c(e=>!e.disposed&&!s.stopped()&&M.get(e.key)===e,"frontendIsCurrent"),ee=c((e,r)=>{if(!Q(e))return Promise.resolve(!1);if(e.replacement)return e.replacement;const n=e.active;e.state=n?"replacing":"starting",e.reason=r,e.startedAt=Date.now();const t=(async()=>{let o,a;const i=Date.now();try{const l=new Set;for(const u of M.values())u!==e&&l.add(u.desiredPort);const E=n&&n.port===e.desiredPort?`g${n.generation}`:void 0,g=await B(e.desiredPort,T,{reserved:l,heldBy:E});if(a=g,!Q(e))return T.delete(g),!1;o=ae(e,g,"replacement"),e.candidate=o;const d=await Z(n);console.log(`[gateway] lens handoff start: ${e.key} g${n?.generation??0}\u2192g${o.generation} :${n?.port??"down"}\u2192:${g} reason=${r}`),p("info",`lens handoff starting: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-start",wsKey:e.wsKey,project:e.project,reason:r,generation:o.generation,oldPort:n?.port,newPort:g,oldServing:d},void 0,e.eventFile===s.eventFile?void 0:e.eventFile);const $=await _e(o);if(!Q(e))return G(o,!0),e.candidate=void 0,!1;if(!$){G(o,!0),e.candidate=void 0;const u=await Z(n);return e.state=u?"ready":"failed",u&&(e.reason=void 0,e.startedAt=void 0),console.error(`[gateway] lens handoff failed: ${e.key} g${o.generation} did not become ready within ${types_1.LENS_REPLACEMENT_READY_MS}ms; ${e.state==="ready"?"old generation kept serving":"no active generation"}.`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:r,generation:o.generation,port:g,durationMs:Date.now()-i,oldKept:u},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),!1}for(const u of e.routes)u.target=`http://localhost:${o.port}`,u.lens&&(u.lens.port=o.port);e.frontend.port=o.port,e.active=o,e.candidate=void 0,e.state="ready",e.reason=void 0,e.startedAt=void 0;const v=o.vite?A.get(o.vite):void 0;v&&(v.role="active",v.listening=!0);const y=(0,hmr_reload_1.broadcastFullReload)(s,e.key);if(console.log(`[gateway] lens handoff ready: ${e.key} g${o.generation} :${o.port} in ${Date.now()-i}ms; draining g${n?.generation??0}${y>0?`; reloading ${y} tab(s)`:""}.`),p("info",`lens handoff complete: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-complete",wsKey:e.wsKey,project:e.project,reason:r,generation:o.generation,oldPort:n?.port,newPort:o.port,durationMs:Date.now()-i,reloadedTabs:y},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),n){const u=`${n.labelPrefix}browser-capture`;C.add(u),n.capture&&V(n.capture),setTimeout(()=>G(n,!0),types_1.LENS_REPLACEMENT_DRAIN_MS).unref?.()}return!0}catch(l){G(o,!0),!o&&a!==void 0&&T.delete(a),e.candidate=void 0;const E=await Z(n);e.state=E?"ready":"failed",E&&(e.reason=void 0,e.startedAt=void 0);const g=l.message;return console.error(`[gateway] lens handoff failed: ${e.key}: ${g}`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:r,generation:o?.generation??e.generation,port:o?.port??a,durationMs:Date.now()-i,oldKept:E,error:g},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),!1}finally{e.replacement=void 0}})();return e.replacement=t,t},"rollFrontend"),ie=c((e,r)=>{e.active=ae(e,r,"active"),e.state="starting",e.startedAt=Date.now()},"spawnInitialFrontend"),Se=c((e,r)=>{const n=M.get(r.key);return!n||types_1.LENS_RESTART_MODE==="in-place"?!1:(n.candidate?.vite===e||n.active?.vite!==e||(n.state="starting",n.reason="child-exit",n.startedAt=Date.now(),console.warn(`[gateway] lens frontend exited: ${n.key} g${r.generation} :${r.port} (${describeChildExit(e)}); starting an alternate-port replacement.`),ee(n,"child-exit")),!0)},"handleManagedViteExit");s.lensSupervisor=types_1.LENS_RESTART_MODE==="rolling"?{status(e){const r=K.get(e);return r?{state:r.state,generation:r.candidate?.generation??r.active?.generation??r.generation,reason:r.reason,startedAt:r.startedAt}:void 0},recover(e,r){const n=K.get(e);return n?ee(n,r):Promise.resolve(!1)}}:void 0;let te=!1,le=0;const ye=c(()=>{te||Date.now()-le<types_1.POD_STALE_SCAN_MS||(te=!0,le=Date.now(),(async()=>{const e=new Map;for(const r of[...M.values()]){if(s.stopped())return;let n=e.get(r.workspaceRoot);if(!n){const g=(0,scope_1.readSourceSetOptions)(r.workspaceRoot);n={pass:(0,lifecycle_1.sourceScanPass)(r.workspaceRoot,g.exclude,{ignoreTests:g.ignoreTests}),startedAt:Date.now()},e.set(r.workspaceRoot,n)}const t=n.startedAt,o=await n.pass.snapshot(r.sourceDirs);if(M.get(r.key)!==r)continue;const a=r.sourceSnapshot,i=r.sourceScanStartedAt;if(r.sourceSnapshot=o,r.sourceScanStartedAt=t,!a)continue;const l=Date.now(),E=(0,lifecycle_1.diffSourceSets)(a,o,l,(0,lifecycle_1.sourceChangeWindowMs)(l,i,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS));E&&(r.sourceChange=E,p("info",`source file set changed for ${r.key}`,`cluster-lens-app:${r.project}`,{kind:"source-set-changed",scoped:!0,wsKey:r.wsKey,project:r.project,added:E.added,removed:E.removed,truncated:E.truncated},void 0,r.eventFile===s.eventFile?void 0:r.eventFile))}})().catch(()=>{}).finally(()=>{te=!1}))},"scanFrontendSourceSets");let oe=!1;const Pe=c(async(e,r)=>{if(!oe){oe=!0;try{for(const[n,t]of[...A]){if(s.stopped())return;if(t.port===void 0||n.exitCode!==null||n.signalCode!==null)continue;if(await probePortListening(t.port,types_1.LENS_PROBE_TIMEOUT_MS)){if(t.probeFails=0,!t.listening){t.listening=!0;const l=M.get(t.key);l?.active?.vite===n&&(l.state="ready",l.reason=void 0),p("info",`lens app up: ${t.project} (vite :${t.port} listening)`,`cluster-lens-app:${t.project}`,{kind:"service-up",project:t.project,port:t.port},void 0,t.bus)}continue}const o=t.listening?e.graceMs:Math.max(e.graceMs,e.neverListenedGraceMs);if(Date.now()-t.spawnedAt<o){t.probeFails=0;continue}if(!r)continue;t.probeFails+=1;const a=(0,lifecycle_1.lensChildWedged)({spawnedAt:t.spawnedAt,probeFails:t.probeFails,hasListened:t.listening},x.get(t.key)??0,Date.now(),e);if(!a)continue;const i=t.listening?"its listener VANISHED (was up, now refusing)":`it NEVER bound within the ${Math.round(o/1e3)}s boot allowance`;x.set(t.key,Date.now()),t.probeFails=0,t.listening=!1,console.error(`[gateway] wedge recycle: lens app ${t.project} is ALIVE but NOT LISTENING on :${t.port} after ${Math.max(2,e.failureThreshold)} probes \u2014 ${i} \u2014 SIGKILL; a fresh vite is coming.`),p("warning",`wedge recycle: ${t.project} (${a})`,`cluster-lens-app:${t.project}`,{kind:"pod-recycle",project:t.project,reason:a,port:t.port},void 0,t.bus),signalChild(n,"SIGKILL")}}finally{oe=!1}}},"probeLensChildren"),Le=c(()=>{if(F||!types_1.POD_RECYCLE_ENABLED&&!types_1.LENS_PROBE_ENABLED)return;const e={graceMs:types_1.POD_STALE_GRACE_MS,settleMs:types_1.POD_RECYCLE_SETTLE_MS,cooldownMs:types_1.POD_STALE_RECYCLE_COOLDOWN_MS};F=setInterval(()=>{if(s.stopped()||A.size===0||(ce(),!types_1.POD_RECYCLE_ENABLED))return;ye();const r=Date.now();for(const[n,t]of A){const o=M.get(t.key);if(o?.frontend.frozen)continue;const a=o?.sourceChange?.changedAt??0,i=x.get(t.key)??0;(0,lifecycle_1.lensFrontendStale)(t.spawnedAt,i,a,r,e)&&((z.get(t.key)??0)>=a||q.has(t.key)||(q.add(t.key),(async()=>{try{const l=o?.sourceChange,E=l&&!l.truncated?[...l.added,...l.removed].map(v=>path.resolve(t.workspaceRoot,v)):[],g=types_1.LENS_WATCHER_PROBE_ENABLED&&t.port!==void 0?(0,lifecycle_1.lensWatcherVerdict)(await ne(t.port),a,l?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,E):"unknown";if(g==="heard"){z.set(t.key,a),console.log(`[gateway] stale source set: lens app ${t.project} watcher CONFIRMED the change \u2014 no recycle, HMR intact.`),p("info",`stale check: ${t.project} watcher confirmed \u2014 no recycle`,`cluster-lens-app:${t.project}`,{kind:"pod-stale-verified",project:t.project},void 0,t.bus);return}if(g==="unknown"&&types_1.LENS_WATCHER_UNVERIFIED==="keep"){console.log(`[gateway] stale source set: lens app ${t.project} unverifiable (no watcher testimony) \u2014 keeping it (LENSMCP_LENS_WATCHER_UNVERIFIED=keep).`);return}if(n.exitCode!==null||n.signalCode!==null)return;x.set(t.key,Date.now());const d=M.get(t.key);if(types_1.LENS_RESTART_MODE==="rolling"&&d){console.log(`[gateway] stale refresh: lens app ${t.key} (stale-source-set) \u2014 watcher ${g==="missed"?"missed the exact path change":"unverifiable"}; preparing a standby without dropping traffic.`),p("warning",`stale refresh: ${t.project} (stale-source-set)`,`cluster-lens-app:${t.project}`,{kind:"pod-refresh",wsKey:d.wsKey,project:t.project,reason:"stale-source-set",watcher:g,added:l?.added,removed:l?.removed},void 0,t.bus),await ee(d,"stale-source-set");return}t.listening=!1,console.log(`[gateway] zombie recycle: lens app ${t.project} (stale-source-set) \u2014 watcher ${g==="missed"?"SILENT across the change":"unverifiable"}; restarting it`),p("warning",`zombie recycle: ${t.project} (stale-source-set)`,`cluster-lens-app:${t.project}`,{kind:"pod-recycle",project:t.project,reason:"stale-source-set",watcher:g},void 0,t.bus);const $=(0,hmr_reload_1.broadcastFullReload)(s,t.key);$>0&&console.log(`[gateway] \u2192 told ${$} open tab(s) to reload (stale optimize-dep generation)`),signalChild(n,"SIGTERM"),setTimeout(()=>{n.exitCode===null&&n.signalCode===null&&(console.log(`[gateway] zombie recycle: lens app ${t.project} ignored SIGTERM for ${Math.round(types_1.LENS_RECYCLE_KILL_GRACE_MS/1e3)}s \u2014 escalating to SIGKILL.`),signalChild(n,"SIGKILL"))},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.()}finally{q.delete(t.key)}})()))}},Math.min(types_1.POD_STALE_SCAN_MS,15e3)),F.unref?.()},"startLensSweeper"),Re=c(async()=>{const e=[...new Map(s.routes.filter(t=>t.lens).map(t=>[t.project,t.lens])).values()],r=f.dashboard!==!1,n=f.mcp!==!1&&e.length>0;if(r){const t=(0,lens_frontend_1.findDashboardBundle)(s.root);if(!t)console.warn("[gateway] lens dashboard bundle not found \u2014 skipping. Install the self-contained CLI: `npm i -D lensmcp` (it ships `bundled/dashboard.js`), or `yarn nx build @lensmcp/lensmcp-mcp` in-repo.");else{const o=(0,scope_1.readLensScope)(s.root),a=await B(f.dashboardPort??o.dashboardPort,J),i=f.lensHost??"lensmcp.local",l=o.basePath;s.registry.appendRoutes(s.wsKey,[{host:i,prefix:l,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),s.rebuildRoutes(),(0,workspace_registry_1.registerWorkspace)({key:o.key,root:s.root,base:l,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString()}),console.log(`[gateway] starting lens dashboard \u2192 http://localhost:${a} (routed at https://${i}${l}/)`),p("info",`lens dashboard up: ${i}${l} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:i,port:a,base:l}),k("lens-dashboard",(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",o.key,"dashboard")),[t],{LENSMCP_EVENT_FILE:s.eventFile,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:l,LENSMCP_REPLAY_WORKSPACE:o.key,LENSMCP_GATEWAY_PORTS:b,...H},!1,void 0,void 0,a)}}if(n){const t=(0,lens_frontend_1.findMcpBundle)(s.root);if(!t)console.warn("[gateway] MCP server bundle not found \u2014 skipping (lens apps will still publish to the bus; an external `lensmcp mcp` can read it). Install: `npm i -D lensmcp`.");else{const o=(0,scope_1.readLensScope)(s.root),a=Number(process.env.LENSMCP_PORT??o.mcpHttpPort),i=c(()=>{console.log(`[gateway] starting lens MCP server on 127.0.0.1:${a} (${t})`),k("lens-mcp",(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",o.key,"mcp")),[t],{LENSMCP_EVENT_FILE:s.eventFile,LENSMCP_PROCESS_ROLE:"mcp",LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_PORT:String(a),LENSMCP_WORKSPACE_KEY:o.key,LENSMCP_REPLAY_WORKSPACE:o.key,LENSMCP_WORKSPACE_ROOT:s.root},!1,void 0,void 0,a)},"spawnMcp");await w(a)?i():(console.warn(`[gateway] lens MCP port :${a} is already served \u2014 an external lensmcp server (a shared daemon?) owns this workspace's MCP; not spawning a second. Re-probing every ${Math.round(types_1.LENS_PARKED_PORT_REPROBE_MS/1e3)}s; will take over if it frees.`),p("info",`lens MCP served externally on :${a} \u2014 gateway parked its own`,"cluster-lens-child:lens-mcp",{kind:"lens-child-up",project:"lens-mcp",label:"lens-mcp",port:a,external:!0}),re("lens-mcp",a,i))}}for(const t of e){if(t.started)continue;t.started=!0;const o=t.port,a=(s.registry.get(s.wsKey)?.routes??s.routes).filter(E=>E.lens?.project===t.project),i=await B(t.port,T);for(const E of a)E.lens&&(E.lens.port=i),E.target=`http://localhost:${i}`;t.port=i;const l=se({wsKey:s.wsKey,replayWorkspace:s.wsKey,project:t.project,workspaceRoot:s.root,projectRoot:t.projectRoot,eventFile:s.eventFile,routes:a,frontend:t,desiredPort:o});try{ie(l,i),p("info",`lens app started: ${t.project} (vite :${t.port})`,`cluster-lens-app:${t.project}`,{kind:"lens-app-up",project:t.project,port:t.port})}catch(E){T.delete(i),l.state="failed",console.error(`[gateway] lens app ${t.project}: ${E.message}`)}}Le()},"bootSingletonsAndApps"),Ce=c(async e=>{if(f.dashboard===!1)return;const r=(0,lens_frontend_1.findDashboardBundle)(s.root);if(!r)return;const n=(0,scope_1.readLensScope)(e.root),t=f.lensHost??"lensmcp.local",o=n.basePath,a=await B(n.dashboardPort,J),i=`lens-dashboard:${e.wsKey}`,l=path.join(e.root,".lensmcp","events.jsonl");C.delete(i);const E=`http://localhost:${a}`;s.registry.appendRoutes(e.wsKey,[{host:t,prefix:o,project:observability_1.LENS_DASHBOARD_PROJECT,target:E}]),(0,workspace_registry_1.registerWorkspace)({key:e.wsKey,root:e.root,base:o,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString(),...e.instance?{instance:{name:e.instance.name,baseKey:e.instance.baseKey,apex:e.instance.apex}}:{}}),console.log(`[gateway] hosting dashboard for workspace '${e.wsKey}' \u2192 http://localhost:${a} (routed at https://${t}${o}/)`),p("info",`lens dashboard up: ${t}${o} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:t,port:a,base:o});const g=(0,process_name_1.namedExecPath)((0,process_name_1.processName)("lensmcp",e.wsKey,"dashboard")),d={LENSMCP_EVENT_FILE:l,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:o,LENSMCP_WS_KEY:e.wsKey,LENSMCP_HOSTED_GUEST:"1",LENSMCP_REPLAY_WORKSPACE:e.instance?.baseKey??e.wsKey,...e.sockNs?{LENSMCP_SOCK_NS:e.sockNs}:{},LENSMCP_GATEWAY_PORTS:b,...H};let $=!1,v=!1;const y=c(()=>{const S=m.get(i);S&&V(S),m.delete(i)},"retireHolder"),u=(0,hosted_dashboard_1.createHostedDashboard)(e.wsKey,{idleMs:(0,hosted_dashboard_1.dashboardIdleMs)(),start:c(async()=>{C.delete(i),v&&await waitForPortFree(a,types_1.PORT_FREE_WAIT_MS,{isPortFree:w,intervalMs:types_1.PORT_FREE_POLL_MS}),!($||s.stopped())&&k(i,g,[r],d,!1,void 0,e.root,a)},"start"),stop:c(()=>{v=!0,C.add(i),y()},"stop"),listening:c(()=>probePortListening(a,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS)),"listening"),servicesUp:c(()=>(s.registry.get(e.wsKey)?.services??[]).some(S=>S.state!=="down"),"servicesUp")});return W.set(E,u),fe(),u.tick(),()=>{$=!0,u.dispose(),W.get(E)===u&&W.delete(E),C.add(i),J.delete(a),(0,workspace_registry_1.unregisterWorkspace)(e.wsKey),y()}},"hostWorkspaceDashboard"),Me=c(async e=>{const r=new Map;for(const o of e.routes){if(!o.lens)continue;const a=r.get(o.lens.project)??[];a.push(o),r.set(o.lens.project,a)}if(r.size===0)return()=>{};const n=path.join(e.root,".lensmcp","events.jsonl"),t=[];for(const[o,a]of r){const i=a[0].lens;if(i.started)continue;const l=await B(i.port,T),E=i.port;for(const d of a)d.lens.started=!0,d.lens.port=l,d.target=`http://localhost:${l}`;const g=se({wsKey:e.wsKey,replayWorkspace:e.instance?.baseKey??e.wsKey,project:o,workspaceRoot:e.root,projectRoot:i.projectRoot,eventFile:n,routes:a,frontend:i,desiredPort:E});t.push(g),console.log(`[gateway] hosting lens app '${o}' of '${e.wsKey}' \u2192 vite :${l}`);try{ie(g,l),p("info",`lens app started: ${e.wsKey}/${o} (vite :${l})`,`cluster-lens-app:${e.wsKey}:${o}`,{kind:"lens-app-up",project:o,port:l},void 0,n)}catch(d){T.delete(l),g.state="failed",console.error(`[gateway] lens app ${e.wsKey}/${o}: ${d.message}`)}}return()=>{for(const o of t){o.disposed=!0;for(const a of[...o.generations])G(a,!0);for(const a of o.routes)a.lens&&K.delete(a.lens);K.delete(o.frontend),x.delete(o.key),z.delete(o.key),q.delete(o.key),M.delete(o.key)}}},"hostWorkspaceApps"),$e=c(async(e=2500)=>{F&&(clearInterval(F),F=void 0),I&&(clearInterval(I),I=void 0);const r=[...j];for(const o of r)signalChild(o,"SIGTERM");const n=c(o=>o.exitCode===null&&o.signalCode===null,"alive"),t=Date.now()+e;for(;Date.now()<t&&r.some(n);)await new Promise(o=>setTimeout(o,100));for(const o of r)n(o)&&signalChild(o,"SIGKILL")},"reapAll"),ce=c(()=>Pe({graceMs:types_1.LENS_PROBE_GRACE_MS,failureThreshold:types_1.LENS_PROBE_FAILS,cooldownMs:types_1.LENS_PROBE_COOLDOWN_MS,neverListenedGraceMs:types_1.LENS_PROBE_BOOT_GRACE_MS},types_1.LENS_PROBE_ENABLED),"probeLensFrontends");return{spawnManagedChild:k,bootSingletonsAndApps:Re,hostWorkspaceDashboard:Ce,hostWorkspaceApps:Me,probeLensFrontends:ce,reapAll:$e}}L(createLensChildren,"createLensChildren"),c(createLensChildren,"createLensChildren");
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var dt=Object.defineProperty;var $=(t,c)=>dt(t,"name",{value:c,configurable:!0});var it=Object.defineProperty,m=$((t,c)=>it(t,"name",{value:c,configurable:!0}),"m"),at=Object.defineProperty,a=m((t,c)=>at(t,"name",{value:c,configurable:!0}),"a");Object.defineProperty(exports,"__esModule",{value:!0}),exports.scaleTarget=scaleTarget,exports.isLoopbackHostname=isLoopbackHostname,exports.isOwnRunnerCommand=isOwnRunnerCommand,exports.isRunnerOf=isRunnerOf,exports.isTestSourcePath=isTestSourcePath,exports.sourceScanPass=sourceScanPass,exports.sourceSetSnapshot=sourceSetSnapshot,exports.sourceSetSignature=sourceSetSignature,exports.diffSourceSets=diffSourceSets,exports.sourceChangeWindowMs=sourceChangeWindowMs,exports.sourceScopeDirs=sourceScopeDirs,exports.podRecycleReason=podRecycleReason,exports.lensFrontendStale=lensFrontendStale,exports.lensWatcherVerdict=lensWatcherVerdict,exports.podWatcherVerdict=podWatcherVerdict,exports.lensChildWedged=lensChildWedged,exports.isPortConflictExit=isPortConflictExit,exports.podChangeClock=podChangeClock,exports.createServiceLayer=createServiceLayer,exports.chooseStalePodKillTarget=chooseStalePodKillTarget;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),node_crypto_1=require("node:crypto"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),net=tslib_1.__importStar(require("node:net")),path=tslib_1.__importStar(require("node:path")),node_util_1=require("node:util"),discovery_1=require("./discovery"),pod_sock_1=require("../../../pod-sock"),scope_1=require("./scope"),pod_env_1=require("./pod-env"),pod_probe_1=require("./pod-probe"),service_keys_1=require("./service-keys"),workspace_log_1=require("./workspace-log"),own_log_1=require("./own-log"),inspector_secret_1=require("../../../inspector-secret"),pod_output_1=require("./pod-output"),serve_launch_1=require("./serve-launch"),shared_build_1=require("./shared-build"),warm_start_1=require("./warm-start"),protocol_1=require("../../../shared-build/protocol"),types_1=require("./types"),exit_reason_1=require("../../../exit-reason"),handoff_retire_1=require("../../../handoff-retire"),process_name_1=require("../../../process-name"),orphan_reaper_1=require("./orphan-reaper");function eastWestEnv(t,c){const l={},p=t.serviceKeys[(0,service_keys_1.serviceKeyId)(c.wsKey,c.project)];if(p&&(l.LENSMCP_SERVICE_KEY=p),t.https){const f=require("../../../basic-ssl").caCertPath();fs.existsSync(f)&&(l.NODE_EXTRA_CA_CERTS=f)}return l}$(eastWestEnv,"eastWestEnv"),m(eastWestEnv,"eastWestEnv"),a(eastWestEnv,"eastWestEnv");const sleep=a(t=>new Promise(c=>setTimeout(c,t)),"sleep"),SRC_EXCLUDE=new Set(["node_modules","dist","tmp","coverage","build","out","target"]),SRC_EXT=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".css",".scss",".sass",".less",".json",".html",".htm",".vue",".svelte",".mdx"]),SCAN_FILE_CAP=1e5;function fnv1a(t){let c=2166136261;for(let l=0;l<t.length;l+=1)c^=t.charCodeAt(l),c=Math.imul(c,16777619);return c>>>0}$(fnv1a,"fnv1a"),m(fnv1a,"fnv1a"),a(fnv1a,"fnv1a");const execFileP=(0,node_util_1.promisify)(node_child_process_1.execFile);async function gitIgnoredPaths(t){try{const{stdout:c}=await execFileP("git",["ls-files","--others","--directory","--ignored","--exclude-standard","-z"],{cwd:t,maxBuffer:33554432,timeout:1e4,windowsHide:!0});return new Set(c.split("\0").filter(Boolean))}catch{return new Set}}$(gitIgnoredPaths,"gitIgnoredPaths"),m(gitIgnoredPaths,"gitIgnoredPaths"),a(gitIgnoredPaths,"gitIgnoredPaths");function scaleTarget(t,c=fs.existsSync){if(t.decl.adminUrl)return{url:t.decl.adminUrl};const l=path.join(t.pool.dir,"parent.sock");return c(l)?{socketPath:l}:t.decl.port?{url:`http://localhost:${t.decl.port}`}:void 0}$(scaleTarget,"scaleTarget"),m(scaleTarget,"scaleTarget"),a(scaleTarget,"scaleTarget");function isLoopbackHostname(t){const c=t.toLowerCase().replace(/^\[(.*)\]$/,"$1").replace(/\.$/,"");return c==="localhost"||c.endsWith(".localhost")?!0:net.isIPv4(c)?c.split(".")[0]==="127":net.isIPv6(c)&&new URL(`http://[${c}]/`).hostname==="[::1]"}$(isLoopbackHostname,"isLoopbackHostname"),m(isLoopbackHostname,"isLoopbackHostname"),a(isLoopbackHostname,"isLoopbackHostname");function postScale(t,c,l){let p;if("socketPath"in t)p=http.request({socketPath:t.socketPath,path:"/webpack/scale",method:"POST",headers:{"content-type":"application/json"}},f=>f.resume());else{const f=t.url.startsWith("https"),M=f?require("node:https"):http,E={method:"POST"};f&&isLoopbackHostname(new URL(t.url).hostname)&&(E.rejectUnauthorized=!1),l&&(E.lookup=l),p=M.request(`${t.url}/webpack/scale`,E,C=>C.resume())}return p.on("error",()=>{}),p.end(JSON.stringify({pods:c})),p}$(postScale,"postScale"),m(postScale,"postScale"),a(postScale,"postScale");function isOwnRunnerCommand(t,c){return(0,serve_launch_1.isServeRunnerCommand)(t)?(0,serve_launch_1.isServeRunnerCommandOf)(t,c):t.includes("/node_modules/nx/")?t.includes(`${c.replace(/\/+$/,"")}/node_modules/nx/`):!0}$(isOwnRunnerCommand,"isOwnRunnerCommand"),m(isOwnRunnerCommand,"isOwnRunnerCommand"),a(isOwnRunnerCommand,"isOwnRunnerCommand");function isRunnerOf(t,c,l){const p=c.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return!new RegExp(`(^|\\s)run ${p}(:|\\s|$)`).test(t)||!(0,serve_launch_1.isServeRunnerCommand)(t)&&!/\bnx(\.js)?\b/.test(t)?!1:isOwnRunnerCommand(t,l)}$(isRunnerOf,"isRunnerOf"),m(isRunnerOf,"isRunnerOf"),a(isRunnerOf,"isRunnerOf");const TEST_FILE_RE=/\.(spec|test|e2e|e2e-spec|stories)\.[cm]?[jt]sx?$/,TEST_DIR_SEGMENTS=new Set(["__tests__","__mocks__","__snapshots__"]);function isTestSourcePath(t){const c=t.split("/"),l=c[c.length-1]??"";if(TEST_FILE_RE.test(l))return!0;for(let p=0;p<c.length-1;p+=1)if(TEST_DIR_SEGMENTS.has(c[p]))return!0;return!1}$(isTestSourcePath,"isTestSourcePath"),m(isTestSourcePath,"isTestSourcePath"),a(isTestSourcePath,"isTestSourcePath");function sourceScanPass(t,c,l){const p=l?.ignoreTests??!0;let f;const M=new Map,E=`tree:${path.resolve(t)}`,C=a(y=>path.relative(t,y).split(path.sep).join("/"),"rel"),T=a(async(y,_)=>{const k=await(f??=gitIgnoredPaths(t)),L=[],W=new Set;let D=!1;const X=a(async(oe,S)=>{if(L.length>=SCAN_FILE_CAP){D=!0;return}let N;try{N=await fs.promises.readdir(oe,{withFileTypes:!0})}catch{return}S&&W.add(C(oe));for(const J of N){if(L.length>=SCAN_FILE_CAP){D=!0;return}const G=J.name,re=path.join(oe,G);if(J.isDirectory()){if(!S||G.startsWith(".")||SRC_EXCLUDE.has(G)||c?.has(G)||G.endsWith("-devserver")||k.has(`${C(re)}/`))continue;await X(re,!0)}else if(J.isFile()){const se=G.lastIndexOf(".");if(se<=0||!SRC_EXT.has(G.slice(se)))continue;const Z=C(re);if(k.has(Z)||p&&isTestSourcePath(Z))continue;L.push(Z)}}},"walk");return await X(y,_),{paths:L,entered:W,truncated:D}},"walkDir"),I=a((y,_)=>{let k=M.get(y);return k||(k=_(),M.set(y,k)),k},"memo"),le=a(async()=>{const y=M.get(E);if(!y)return;const _=await y;return _.truncated?void 0:_},"wideWalk"),H=new Set,de=a(()=>I(`files:${path.resolve(t)}`,async()=>{const y=await le();return y?{paths:y.paths.filter(_=>!_.includes("/")),entered:H,truncated:!1}:T(t,!1)}),"rootFiles"),pe=a(y=>I(`tree:${path.resolve(y)}`,async()=>{const _=await le(),k=C(y);if(_?.entered.has(k)){const L=`${k}/`;return{paths:k===""?_.paths:_.paths.filter(W=>W.startsWith(L)),entered:H,truncated:!1}}return T(y,!0)}),"subtree"),z=a(y=>{const _=new Set;let k=0,L=y.some(D=>D.truncated);const W=a(D=>_.has(D)?!0:_.size>=SCAN_FILE_CAP?(L=!0,!1):(_.add(D),k^=fnv1a(D),!0),"add");for(const D of y)if(!D.paths.every(W))break;return{signature:`${_.size}:${(k>>>0).toString(36)}`,paths:_,truncated:L}},"compose");return{async snapshot(y){if(!y||y.length===0)return z([await I(E,()=>T(t,!0))]);const _=[await de()];for(const k of y)_.push(await pe(k));return z(_)}}}$(sourceScanPass,"sourceScanPass"),m(sourceScanPass,"sourceScanPass"),a(sourceScanPass,"sourceScanPass");async function sourceSetSnapshot(t,c,l,p){return sourceScanPass(t,l,p).snapshot(c)}$(sourceSetSnapshot,"sourceSetSnapshot"),m(sourceSetSnapshot,"sourceSetSnapshot"),a(sourceSetSnapshot,"sourceSetSnapshot");async function sourceSetSignature(t,c,l,p){return(await sourceSetSnapshot(t,c,l,p)).signature}$(sourceSetSignature,"sourceSetSignature"),m(sourceSetSignature,"sourceSetSignature"),a(sourceSetSignature,"sourceSetSignature");const SOURCE_DIFF_PATH_CAP=128;function diffSourceSets(t,c,l,p){if(t.paths.size===c.paths.size){let C=!0;for(const T of t.paths)if(!c.paths.has(T)){C=!1;break}if(C)return null}const f=[],M=[];let E=t.truncated||c.truncated;for(const C of c.paths)t.paths.has(C)||(f.length+M.length<SOURCE_DIFF_PATH_CAP?f.push(C):E=!0);for(const C of t.paths)c.paths.has(C)||(f.length+M.length<SOURCE_DIFF_PATH_CAP?M.push(C):E=!0);return{changedAt:l,added:f,removed:M,truncated:E,...p!==void 0?{windowMs:p}:{}}}$(diffSourceSets,"diffSourceSets"),m(diffSourceSets,"diffSourceSets"),a(diffSourceSets,"diffSourceSets");function sourceChangeWindowMs(t,c,l,p){const f=c&&c>0?t-c:l;return Math.max(f,l)+p}$(sourceChangeWindowMs,"sourceChangeWindowMs"),m(sourceChangeWindowMs,"sourceChangeWindowMs"),a(sourceChangeWindowMs,"sourceChangeWindowMs");function sourceScopeDirs(t,c,l,p,f){const M=a(T=>{const I=path.relative(t,T).split(path.sep).filter(Boolean);return I.length===0||I[0].startsWith("..")?"":I[0]},"bucketOf")(c);if(!M)return[];const E=new Set(l.filter(Boolean)),C=new Set([M]);for(const T of p)T.startsWith(".")||SRC_EXCLUDE.has(T)||f?.has(T)||T.endsWith("-devserver")||E.has(T)||C.add(T);return[...C].sort().map(T=>path.join(t,T))}$(sourceScopeDirs,"sourceScopeDirs"),m(sourceScopeDirs,"sourceScopeDirs"),a(sourceScopeDirs,"sourceScopeDirs");function podRecycleReason(t,c,l,p){return!t.proc||t.state!=="up"||t.spawnAt==null||t.inflight>0||(t.activeWork??0)>0||c-t.lastUsed<p.settleMs||t.lastStaleRecycleAt!=null&&c-t.lastStaleRecycleAt<p.cooldownMs?null:l>0&&l-t.spawnAt>p.graceMs?"stale-source-set":p.maxAgeMs>0&&c-t.spawnAt>p.maxAgeMs?"max-age":null}$(podRecycleReason,"podRecycleReason"),m(podRecycleReason,"podRecycleReason"),a(podRecycleReason,"podRecycleReason");function lensFrontendStale(t,c,l,p,f){return!(p-c<f.cooldownMs||l<=0||l-t<=f.graceMs||p-l<f.settleMs)}$(lensFrontendStale,"lensFrontendStale"),m(lensFrontendStale,"lensFrontendStale"),a(lensFrontendStale,"lensFrontendStale");function lensWatcherVerdict(t,c,l,p=[]){if(!t)return"unknown";if("schemaVersion"in t&&t.schemaVersion>=2&&p.length>0){const f=c-l,M=new Set(t.recentEvents.filter(E=>E.at>=f).map(E=>path.resolve(E.path)));return p.every(E=>M.has(path.resolve(E)))?"heard":"missed"}return t.lastFsSetEventAt>=c-l?"heard":"missed"}$(lensWatcherVerdict,"lensWatcherVerdict"),m(lensWatcherVerdict,"lensWatcherVerdict"),a(lensWatcherVerdict,"lensWatcherVerdict");function podWatcherVerdict(t,c,l){if(!t)return"unknown";if(t.degraded)return"degraded";const p=c-l;return t.lastWatchRunAt>=p||t.lastBuildAt>=p?"heard":"silent"}$(podWatcherVerdict,"podWatcherVerdict"),m(podWatcherVerdict,"podWatcherVerdict"),a(podWatcherVerdict,"podWatcherVerdict");function lensChildWedged(t,c,l,p){const f=t.hasListened?p.graceMs:Math.max(p.graceMs,p.neverListenedGraceMs);return l-t.spawnedAt<f||l-c<p.cooldownMs||t.probeFails<Math.max(2,p.failureThreshold)?null:"wedged-no-listener"}$(lensChildWedged,"lensChildWedged"),m(lensChildWedged,"lensChildWedged"),a(lensChildWedged,"lensChildWedged");function isPortConflictExit(t,c){return t.signal||t.code===null||t.code===0||t.ranMs>c.fastFailMs?!1:t.portHeld}$(isPortConflictExit,"isPortConflictExit"),m(isPortConflictExit,"isPortConflictExit"),a(isPortConflictExit,"isPortConflictExit");function podChangeClock(t,c){const l=t.sourceSetChangedFor?.get(c);if(l!==void 0){const p=t.sourceSetChangesFor?.get(c);return{at:l,...p?{change:p}:{},scope:"project"}}return t.sourceSetScoped?.has(c)?{at:0,scope:"none"}:{at:t.sourceSetChangedAt??0,...t.sourceSetChange?{change:t.sourceSetChange}:{},scope:"workspace"}}$(podChangeClock,"podChangeClock"),m(podChangeClock,"podChangeClock"),a(podChangeClock,"podChangeClock");const changeEvidence=a(t=>{if(!t)return"no path evidence";const c=[...t.added.map(l=>`+${l}`),...t.removed.map(l=>`-${l}`)];return c.length?`${c.slice(0,3).join(", ")}${c.length>3?` (+${c.length-3} more)`:""}`:"no path evidence"},"changeEvidence");function createServiceLayer(t,c,l={}){const p=l.spawnProcess??node_child_process_1.spawn,f=l.probeAlive??pod_probe_1.probePodAlive,M=l.killTree??((e,o="SIGTERM")=>{try{process.kill(-e.pid,o)}catch{try{e.kill(o)}catch{}}}),E=l.sharedBuild??(0,shared_build_1.createSharedBuildRelay)(t),C=a((e,o="SIGTERM")=>{E.detach(e),M(e,o)},"killTree"),T=l.handoffDrainMs??(0,handoff_retire_1.handoffDrainBoundMs)(),I=l.treeAlive??(e=>{if(!e.pid||!(e instanceof node_child_process_1.ChildProcess))return!1;try{return process.kill(-e.pid,0),!0}catch(o){return o.code==="EPERM"}}),le=l.retirePollMs??1e3,H=l.rollReadyMs??types_1.POD_ROLL_READY_MS,de=l.rollPollMs??750,pe=l.maxConcurrentRolls??types_1.POD_MAX_CONCURRENT_ROLLS,z=pe>0?pe:Number.POSITIVE_INFINITY,y=l.maxConcurrentColdStarts??types_1.MAX_COLD_STARTS,_=y>0?y:Number.POSITIVE_INFINITY;let k=0;const L=[],W=a(()=>k<_?(k+=1,Promise.resolve()):new Promise(e=>{L.push(()=>{k+=1,e()})}),"acquireColdSlot"),D=a(()=>{k-=1,L.shift()?.()},"releaseColdSlot"),{emit:X}=c,oe=a(e=>e.wsKey===t.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl"),"serviceBus"),S=a((e,o,r,s,i)=>X(o,r,s,{wsKey:e.wsKey,...i},void 0,oe(e)),"emitSvc"),N=a(e=>(e.scannedAt=0,(0,discovery_1.pickSock)(e,t.scanTtlMs)?e.socks.length:0),"scanNow"),J=a((e,o)=>{let r;try{r=(0,node_child_process_1.execFileSync)("ps",["ax","-ww","-o","pid=,pgid=,command="],{encoding:"utf8",timeout:5e3})}catch{return 0}const s=e.proc?.pid;let i=0;for(const n of r.split(`
|
|
2
|
-
`)){const d=n.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);if(!d)continue;const u=Number(d[1]),w=Number(d[2]);if(isRunnerOf(d[3],
|
|
3
|
-
`)){const A=(0,pod_output_1.classifyPodLine)(g),{clean:P,broken:q,healthy:ae}=A,h=P;if(q){e.lastErrors.push(P),e.lastErrors.length>12&&e.lastErrors.shift(),e.buildFailed=!0;const x=Date.now();(P!==e.lastErrorEmitSig||x-(e.lastErrorEmitAt??0)>=types_1.SERVICE_ERROR_THROTTLE_MS)&&(e.lastErrorEmitSig=P,e.lastErrorEmitAt=x,S(e,"error",`service error: ${e.project}`,`cluster-service:${e.project}`,{kind:"service-error",project:e.project,line:P,fault:A.fault}))}ae&&(e.buildFailed=!1);const b=(e.faults??=new pod_output_1.PodFaults).observe(A);if(b){e.lastErrorEmitSig=void 0;const x=b.open.length===0;S(e,"info",`${x?"service recovered":`${b.closed.join(" + ")} recovered`}: ${e.project}`,`cluster-service:${e.project}`,{kind:x?"service-recovered":"service-fault-closed",project:e.project,line:P,closed:b.closed,open:b.open})}!e.lockBlockedAt&&/Waiting for .+ in another nx process/.test(h)&&(e.lockBlockedAt=Date.now(),console.log(`[gateway] ${s}: spawn blocked by a stale nx runner \u2014 breaking the lock + respawning`),S(e,"warning",`nx task lock: ${e.project} blocked by a stale runner \u2014 auto-breaking`,`cluster-service:${e.project}`,{kind:"nx-lock-break",project:e.project}),setTimeout(()=>{t.stopped()||!e.lockBlockedAt||(U(e,"parked on a foreign nx task lock \u2014 recycling",{announce:!1}),J(e,s),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&Y(e)},1500).unref?.())},250).unref?.())}},"sniff"),w=e.wsKey&&e.wsKey!==t.wsKey&&e.root?(0,workspace_log_1.workspaceLogWriter)(e.root):void 0,j=a(R=>{const v=(0,own_log_1.linePrefixer)(e.project);return g=>{if(t.stopped())return;const A=(0,inspector_secret_1.redactInspectorUrls)(g.toString());u(A);const P=v(A);R.write(P),w?.(P)}},"relay");return n.stdout?.on("data",j(process.stdout)),n.stderr?.on("data",j(process.stderr)),n.on("exit",(R,v)=>{if(e.proc!==n||(e.proc=void 0,e.state="down",t.stopped()))return;const g=(0,exit_reason_1.describeExit)(R,v);if(console.log(`[gateway] ${s} exited (${R??"no code"}${v?`, ${v}`:""}${e.inflight?`, ${e.inflight} request(s) in flight`:""})${g?` \u2014 ${g}`:""}`),S(e,R===0?"info":"warning",`service down: ${e.project} (exit ${R})`,`cluster-service:${e.project}`,{kind:"service-down",project:e.project,code:R,...v?{signal:v}:{}}),R===0||e.buildFailed)return;const A=Date.now();if(e.restarts=(e.restarts??[]).filter(q=>A-q<types_1.SERVICE_RESTART_WINDOW_MS),e.restarts.length>=types_1.SERVICE_MAX_RESTARTS){S(e,"error",`service crash-looping: ${e.project} \u2014 ${types_1.SERVICE_MAX_RESTARTS}+ restarts/min, not auto-respawning (the next request retries)`,`cluster-service:${e.project}`,{kind:"service-crash-loop",project:e.project});return}e.restarts.push(A);const P=Math.min(8e3,500*2**(e.restarts.length-1));setTimeout(()=>{t.stopped()||e.proc||e.state!=="down"||(console.log(`[gateway] self-heal: respawning ${e.project} (restart ${e.restarts.length}/${types_1.SERVICE_MAX_RESTARTS})`),S(e,"info",`self-heal: respawning ${e.project}`,`cluster-service:${e.project}`,{kind:"service-respawn",project:e.project,attempt:e.restarts.length}),Y(e))},P)}),n},"launchServiceProcess"),Y=a(e=>{if(t.stopped()||e.manualStopped)return;const o=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,r=Math.max(1,e.decl.minPods??1);l.reapForeign!==!1&&J(e,o),e.lockBlockedAt=void 0,console.log(`[gateway] starting ${o} (pods=${r})\u2026`),S(e,"info",`service starting: ${e.project} (${r} pod${r>1?"s":""})`,`cluster-service:${e.project}`,{kind:"service-starting",project:e.project,pods:r}),e.state="starting",e.spawnAt=Date.now(),e.generation=(e.generation??0)+1,e.proc=Z(e,e.generation,"active")},"spawnService"),Le=a(async e=>{const o=e.pool.socks[0];if(!o)return;const r=await(0,pod_probe_1.probePodAlive)(o,void 0,t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)]);r&&(e.activeWork=r.activeWork,r.watcher&&(e.watcher=r.watcher))},"refreshActiveWork"),Ie=a(e=>{try{const o=Number(fs.readFileSync(`${e}.owner`,"utf8").trim());return Number.isInteger(o)&&o>1?o:void 0}catch{return}},"readOwnerSidecar"),Oe=a(async e=>{const o=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)];if(!o)return[];const r=(0,node_crypto_1.createHash)("sha256").update(o).digest("hex").slice(0,8),s=[];for(const i of e.pool.socks){const n=await(0,pod_probe_1.probePodAlive)(i,void 0,o);n&&(!n.keyFingerprint||n.keyFingerprint!==r)&&s.push({sock:i,pid:n.pid})}return s},"staleAdoptedSocks"),Ne=a((e,o)=>{const r=o.map(s=>s.sock);for(const{sock:s,pid:i}of o){const n=chooseStalePodKillTarget(i,Ie(s),process.pid);if(n!==void 0)try{process.kill(n,"SIGTERM")}catch{}try{fs.unlinkSync(s)}catch{}try{fs.unlinkSync(`${s}.owner`)}catch{}}e.pool.socks=e.pool.socks.filter(s=>!r.includes(s)),e.pool.idx=-1,e.pool.scannedAt=0},"evictStaleAdopted"),ue=a((e,o)=>{if(e.state==="up")return!1;e.state="up",e.wedgeRecycles=0;const r=e.pool.socks.length;return S(e,"info",`service up: ${e.project} (${r} pods, ${o})`,`cluster-service:${e.project}`,{kind:"service-up",project:e.project,pods:r,adopted:o==="adopted"}),!0},"markUp"),Se=a(async e=>{if(e.manualStopped)return!1;if(N(e.pool)>0){const s=await Oe(e);if(e.manualStopped)return!1;if(s.length>0&&(console.error(`[gateway] ${e.project}: ${s.length} adopted pod(s) hold a foreign east-west key \u2014 evicting instead of adopting.`),S(e,"warning",`stale adoption: ${e.project} (foreign east-west key)`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:"stale-adoption",pods:s.length}),e.proc&&U(e,"stale adoption (foreign east-west key)"),Ne(e,s)),e.pool.socks.length>0)return ue(e,"adopted"),!0}if(t.stopped())return!1;let o=!1;const r=a(()=>e.state!=="starting"&&!e.proc,"notStarted");if(r())if(e.coldWait)await e.coldWait;else{k>=_&&(console.log(`[gateway] cold start queued: ${e.project}${e.wsKey&&e.wsKey!==t.wsKey?` (${e.wsKey})`:""} \u2014 ${k} starting, ${L.length} ahead (LENSMCP_MAX_COLD_STARTS=${_}).`),S(e,"info",`cold start queued: ${e.project}`,`cluster-service:${e.project}`,{kind:"cold-start-queued",project:e.project,inFlight:k,ahead:L.length}));const s=W();if(e.coldWait=s,await s,e.coldWait=void 0,o=!0,t.stopped()||e.manualStopped)return D(),!1;r()&&Y(e)}try{return await Ke(e)}finally{o&&D()}},"ensureUp"),Ke=a(async e=>{const o=Date.now()+t.startupTimeoutMs,r=Date.now()+12e3;for(;!t.stopped()&&!e.manualStopped&&Date.now()<o;){if(await sleep(Math.min(700,t.startupTimeoutMs/4)),e.manualStopped||e.buildFailed&&Date.now()>r)return!1;if(N(e.pool)>0){e.state="up",e.buildFailed=!1;const s=e.spawnAt?Date.now()-e.spawnAt:void 0;return console.log(`[gateway] ${e.project} up (${e.pool.socks.length} pods${s?`, cold start ${s}ms`:""})`),S(e,"info",`cold start: ${e.project} (${e.pool.socks.length} pods, ${s??"?"}ms)`,`cluster-service:${e.project}`,{kind:"cold-start",project:e.project,pods:e.pool.socks.length,durationMs:s}),!0}if(e.state==="down")return!1}return!1},"waitForPods"),Fe=a(e=>{const o=e.decl.maxPods??e.decl.minPods??1,r=e.pool.socks.length,s=scaleTarget(e);!s||r===0||r>=o||e.inflight<=r||Date.now()-e.lastScaleAt<5e3||(e.lastScaleAt=Date.now(),postScale(s,r+1,l.scaleLookup),console.log(`[gateway] autoscale ${e.project}: ${r} \u2192 ${r+1} pods (inflight ${e.inflight})`),S(e,"info",`autoscale: ${e.project} ${r} \u2192 ${r+1} pods`,`cluster-service:${e.project}`,{kind:"autoscale",project:e.project,from:r,to:r+1,inflight:e.inflight}))},"scaleUp"),ge=l.killGraceMs??types_1.TREE_KILL_GRACE_MS,K=new Map,Te=a(e=>{const o=K.get(e);if(!o||(K.delete(e),clearTimeout(o.timer),!I(e)))return;const{svc:r,why:s}=o;console.log(`[gateway] ${r.project}: its tree (pid ${e.pid}) was still running ${Math.round(ge/1e3)}s after it was told to stop (${s}) \u2014 killing it (SIGKILL).`),S(r,"warning",`tree force-killed: ${r.project} (it ignored SIGTERM)`,`cluster-service:${r.project}`,{kind:"tree-force-killed",project:r.project,why:s,pid:e.pid,graceMs:ge}),M(e,"SIGKILL")},"settleDyingTree"),ve=a((e,o,r)=>{if(C(o,"SIGTERM"),ge<=0||K.has(o))return;const s=setTimeout(()=>Te(o),ge);s.unref?.(),K.set(o,{svc:e,why:r,timer:s})},"stopTree"),We=a(async(e=3e3)=>{const o=Date.now()+e;for(;K.size>0;){for(const[r,s]of[...K])I(r)||(clearTimeout(s.timer),K.delete(r));if(K.size===0||Date.now()>=o)break;await sleep(100)}for(const r of[...K.keys()])Te(r)},"finishDyingTrees"),U=a((e,o,r)=>{if(!e.proc)return;console.log(`[gateway] ${e.project} ${o} \u2014 scaling to zero.`),r?.announce!==!1&&S(e,"info",`idle kill: ${e.project} (${o})`,`cluster-service:${e.project}`,{kind:"idle-kill",project:e.project,why:o});const s=e.proc;try{s.stdout?.removeAllListeners("data"),s.stderr?.removeAllListeners("data"),s.removeAllListeners("exit")}catch{}(0,discovery_1.stopRoutingTo)(e.pool),ve(e,s,o),e.proc=void 0,e.state="down",setTimeout(()=>{he(e),e.pool.socks=[],e.pool.scannedAt=0},1200).unref?.()},"killSpawned"),he=a(e=>{try{for(const o of fs.readdirSync(e.pool.dir)){if(!o.endsWith(".sock"))continue;const r=path.join(e.pool.dir,o);try{const s=Number(fs.readFileSync(`${r}.owner`,"utf8").trim());if(Number.isFinite(s)&&s>0)try{process.kill(s,0);continue}catch{}}catch{}try{fs.unlinkSync(r)}catch{}try{fs.unlinkSync(`${r}.owner`)}catch{}}}catch{}},"sweepDeadOwnerSocks");let Q=0;const ye=[],Ge=a(()=>Q<z?(Q+=1,Promise.resolve()):new Promise(e=>{ye.push(()=>{Q+=1,e()})}),"acquireRollSlot"),qe=a(()=>{Q-=1,ye.shift()?.()},"releaseRollSlot"),$e=a(async(e,o,r)=>{N(e.pool);for(const s of e.pool.socks){const i=await f(s,void 0,r);if(i&&o(i.podGeneration))return!0}return!1},"anyPodAnswers"),fe=new Map,Ve=a((e,o,r)=>{const s=T>0&&(0,handoff_retire_1.requestHandoffRetire)(e.pool.dir,r);if(C(o,"SIGTERM"),!s)return;const i=e.wsKey&&e.wsKey!==t.wsKey&&e.root?(0,workspace_log_1.workspaceLogWriter)(e.root):void 0,n=a(ae=>h=>{if(t.stopped())return;const b=(0,inspector_secret_1.redactInspectorUrls)(h.toString()).replace(/^(?=.)/gm,`[${e.project} g${r} retiring] `);ae.write(b),i?.(b)},"say"),d=n(process.stdout),u=n(process.stderr);o.stdout?.on("data",d),o.stderr?.on("data",u);let w,j=!1;const R=a(()=>{j=!0,clearTimeout(w),o.stdout?.removeListener("data",d),o.stderr?.removeListener("data",u),o.removeListener("close",R)},"releaseLogs");o.once("close",R);let v=!1;const g=a(()=>{v||(v=!0,clearTimeout(A),clearInterval(q),t.stopped()?R():j||(w=setTimeout(R,1e3),w.unref?.()),fe.delete(o),(0,handoff_retire_1.clearHandoffRetire)(e.pool.dir,r),he(e),e.pool.scannedAt=0)},"end"),A=setTimeout(()=>{console.error(`[gateway] pod handoff: ${e.project} g${r} was still running ${T}ms after it was retired \u2014 killing it.`),M(o,"SIGKILL"),g()},T);A.unref?.();const P=a(()=>{if(!v){if(t.stopped()){g();return}I(o)||(console.log(`[gateway] pod handoff: ${e.project} g${r} finished its in-flight work and exited.`),g())}},"look"),q=setInterval(P,le);q.unref?.(),o.once("exit",P),fe.set(o,()=>{g(),ve(e,o,"the gateway is stopping")})},"retireReplacedTree"),Ue=l.standbyGraceMs??3e4,O=new Map,Be=a((e,o,r,s,i)=>{const n=i+H+Ue,d=setTimeout(()=>Pe(o),Math.max(0,n-Date.now()));d.unref?.(),O.set(o,{svc:e,generation:r,reason:s,beganAt:i,deadlineAt:n,timer:d})},"holdStandby"),He=a(e=>{const o=O.get(e);o&&(clearTimeout(o.timer),O.delete(e))},"releaseStandby"),ee=a((e,o)=>{const r=O.get(e);if(!r)return!1;clearTimeout(r.timer),O.delete(e);const{svc:s,generation:i}=r;try{e.stdout?.removeAllListeners("data"),e.stderr?.removeAllListeners("data")}catch{}return(0,discovery_1.stopRoutingTo)(s.pool,n=>(0,pod_sock_1.podSockGeneration)(n)===i),ve(s,e,`standby g${i}: ${o}`),setTimeout(()=>he(s),1200).unref?.(),!0},"endStandby"),Me=a((e,o)=>{const r=o.oldServing?`old generation g${o.fromGen} kept serving`:`and the old generation g${o.fromGen} is NOT serving (${o.oldGone?"its tree is gone":"none of its pods answers"}) \u2014 the service is down until it recovers`;console.error(`[gateway] pod handoff failed: ${e.project} g${o.generation}: ${o.why} \u2014 ${r}.`),e.rollFailure=`${o.why} \u2014 ${r}`,S(e,o.oldServing?"warning":"error",`pod handoff failed: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-failed",project:e.project,reason:o.reason,generation:o.generation,error:o.why,durationMs:Date.now()-o.beganAt,oldServing:o.oldServing})},"reportStandbyFailed"),Pe=a(e=>{const o=O.get(e);if(!o)return;const{svc:r,generation:s,reason:i,beganAt:n}=o,d=`the standby outlived its roll (${Math.round((Date.now()-n)/1e3)}s; a roll waits ${Math.round(H/1e3)}s for it)`;ee(e,d);const u=r.proc,w=t.serviceKeys[(0,service_keys_1.serviceKeyId)(r.wsKey,r.project)];(async()=>{const j=!u||u.exitCode!==null||u.signalCode!==null,R=j?!1:await Promise.race([$e(r,g=>g!==s,w).catch(()=>!1),sleep(2e3).then(()=>{})]),v=!t.stopped()&&!j&&(R??N(r.pool)>0);Me(r,{reason:i,generation:s,fromGen:r.generation??s-1,why:d,beganAt:n,oldServing:v,oldGone:j})})()},"outlivedRoll"),Xe=a(()=>{for(const[e,o]of[...O])Date.now()>=o.deadlineAt?Pe(e):!o.svc.rolling&&o.svc.proc!==e&&(console.error(`[gateway] pod handoff: ${o.svc.project} g${o.generation} is a standby whose roll is over \u2014 stopping it.`),ee(e,"its roll is over"))},"sweepStandbys"),Ye=a(()=>{for(const e of[...fe.values()])e();for(const e of[...O.keys()])ee(e,"the gateway is stopping")},"stopRetiringTrees"),me=a((e,o)=>{if(e.rolling)return e.rolling;const r=e.proc;if(!r||t.stopped())return Promise.resolve(!1);if(e.launcher==="nx")return console.log(`[gateway] pod handoff skipped: ${e.project} runs through nx run, which starts one instance of a target at a time \u2014 no standby can overlap it (reason=${o}).`),Promise.resolve(!1);Q>=z&&console.log(`[gateway] pod handoff queued: ${e.project} reason=${o} \u2014 ${Q} roll(s) in flight, ${ye.length} ahead (LENSMCP_POD_MAX_CONCURRENT_ROLLS=${z}).`);const s=(async()=>{await Ge();try{return await ze(e,r,o)}finally{qe()}})().finally(()=>{e.rolling=void 0});return e.rolling=s,s},"rollPod"),ze=a(async(e,o,r)=>{const s=e.proc;if(s!==o||t.stopped())return!1;const i=e.generation??0,n=i+1,d=Date.now();e.lastStaleRecycleAt=d,console.log(`[gateway] pod handoff start: ${e.project} g${i}\u2192g${n} reason=${r} \u2014 standby spawning, old generation keeps serving.`),S(e,"info",`pod handoff starting: ${e.project} (${r})`,`cluster-service:${e.project}`,{kind:"pod-handoff-start",project:e.project,reason:r,generation:n,fromGeneration:i});const u=Z(e,n,"standby"),w=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)];Be(e,u,n,r,d);let j=!1;try{const R=d+H;let v;for(;!t.stopped()&&Date.now()<R&&O.has(u)&&!(u.exitCode!==null||u.signalCode!==null);){N(e.pool);for(const g of e.pool.socks)if((await f(g,void 0,w))?.podGeneration===n){v=g;break}if(v)break;await sleep(de)}if(!O.has(u))return!1;if(!v||t.stopped()){const g=t.stopped()?"gateway stopping":u.exitCode!==null||u.signalCode!==null?`standby exited (${u.exitCode??u.signalCode})`:`standby not ready within ${Math.round(H/1e3)}s`;ee(u,g);const A=!t.stopped()&&e.proc===s&&s.exitCode===null&&s.signalCode===null&&await $e(e,P=>P!==n,w);return Me(e,{reason:r,generation:n,fromGen:i,why:g,beganAt:d,oldServing:A,oldGone:e.proc!==s||s.exitCode!==null||s.signalCode!==null}),!1}if(e.proc!==s)return ee(u,"the service was replaced underneath the roll"),!1;He(u),j=!0,e.proc=u,e.launcher=se.get(u),e.generation=n,e.spawnAt=d,e.state="up",e.watcher=void 0,e.staleVerifiedAt=void 0,e.staleKeptAt=void 0,e.buildFailed=!1,e.lastErrors=[];try{s.stdout?.removeAllListeners("data"),s.stderr?.removeAllListeners("data"),s.removeAllListeners("exit")}catch{}return(0,discovery_1.stopRoutingTo)(e.pool,g=>(0,pod_sock_1.podSockGeneration)(g)!==n&&path.join(e.pool.dir,g)!==v),Ve(e,s,i),setTimeout(()=>{he(e),e.pool.scannedAt=0},1200).unref?.(),console.log(`[gateway] pod handoff ready: ${e.project} g${n} answered on ${path.basename(v)} in ${Date.now()-d}ms; retiring g${i}.`),S(e,"info",`pod handoff complete: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-complete",project:e.project,reason:r,generation:n,fromGeneration:i,durationMs:Date.now()-d}),!0}finally{j||ee(u,"its roll ended without it")}},"runRoll"),Je=a((e,o)=>{if(t.stopped())return{refused:"the gateway is stopping"};if(e.manualStopped=!1,e.actionFailure=void 0,e.restart&&!e.restart.done)return{restart:e.restart,already:!0};if(!e.proc&&e.state!=="down")return{refused:`${e.project} is served by pods this gateway adopted from an earlier one \u2014 it has no tree of its own to replace. \`lensmcp gateway restart\` starts every service under this gateway.`};const r=e.proc?o.hard||e.launcher==="nx"||e.state!=="up"?"hard":"rolling":"start",s={how:r,reason:o.reason,startedAt:Date.now(),...e.proc&&e.generation!==void 0?{fromGeneration:e.generation}:{}};return e.restart=s,e.lastUsed=s.startedAt,console.log(`[gateway] restart asked: ${e.project}${e.wsKey!==t.wsKey?` (${e.wsKey})`:""} \u2014 ${r} (${o.reason}).`),S(e,"info",`restart asked: ${e.project} (${r})`,`cluster-service:${e.project}`,{kind:"service-restart",phase:"started",project:e.project,how:r,reason:o.reason,...s.fromGeneration!==void 0?{fromGeneration:s.fromGeneration}:{}}),a(async()=>{if(r==="start")return await Se(e)?{ok:!0}:{ok:!1,error:_e(e)};if(r==="rolling")return e.rolling&&await e.rolling,e.proc?(e.rollFailure=void 0,await me(e,o.reason)?{ok:!0}:{ok:!1,error:e.rollFailure??"the new tree did not take over"}):await Se(e)?{ok:!0}:{ok:!1,error:_e(e)};if(U(e,`restart asked (${o.reason})`,{announce:!1}),await sleep(1500),t.stopped())return{ok:!1,error:"the gateway is stopping"};let i=!1;e.proc||(await W(),i=!0,!e.proc&&e.state!=="starting"&&Y(e));try{const n=e.proc,d=e.generation,u=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],w=Date.now()+t.startupTimeoutMs;for(;!t.stopped()&&Date.now()<w;){if(!n||e.proc!==n||n.exitCode!==null||n.signalCode!==null)return{ok:!1,error:_e(e)};if(await $e(e,j=>j===d,u))return ue(e,"observed"),e.buildFailed=!1,{ok:!0};await sleep(de)}return{ok:!1,error:t.stopped()?"the gateway is stopping":`no pod of the new tree answered within ${Math.round(t.startupTimeoutMs/1e3)}s`}}finally{i&&D()}},"run")().catch(i=>({ok:!1,error:i.message})).then(i=>{s.done={ok:i.ok,at:Date.now(),...e.generation!==void 0?{generation:e.generation}:{},...i.error?{error:i.error}:{}},i.ok&&(e.lastUsed=s.done.at);const n=Math.round((s.done.at-s.startedAt)/100)/10;i.ok?console.log(`[gateway] restarted: ${e.project} \u2014 g${s.done.generation??"?"} serving after ${n}s (${r}).`):console.error(`[gateway] restart failed: ${e.project} \u2014 ${i.error} (${r}, after ${n}s).`),S(e,i.ok?"info":"error",i.ok?`restarted: ${e.project}`:`restart failed: ${e.project}`,`cluster-service:${e.project}`,{kind:"service-restart",phase:i.ok?"done":"failed",project:e.project,how:r,reason:o.reason,...s.fromGeneration!==void 0?{fromGeneration:s.fromGeneration}:{},...s.done.generation!==void 0?{generation:s.done.generation}:{},durationMs:s.done.at-s.startedAt,...i.error?{error:i.error}:{}})}),{restart:s,already:!1}},"restartService"),_e=a(e=>e.buildFailed?`its build failed${e.lastErrors?.length?`: ${e.lastErrors[e.lastErrors.length-1]}`:""}`:e.proc&&(e.proc.exitCode!==null||e.proc.signalCode!==null)?`its tree exited (${e.proc.exitCode??e.proc.signalCode})`:!e.proc&&e.state==="down"?"its tree exited before a pod answered":`no pod answered within ${Math.round(t.startupTimeoutMs/1e3)}s`,"startFailure"),xe=a(e=>{const o=Date.now();e.restarts=(e.restarts??[]).filter(s=>o-s<types_1.SERVICE_RESTART_WINDOW_MS);const r=(e.wedgeRecycles??0)+1;if(e.restarts.length>=types_1.SERVICE_MAX_RESTARTS||r>types_1.SERVICE_MAX_RESTARTS){const s=e.restarts.length>=types_1.SERVICE_MAX_RESTARTS?`wedged ${types_1.SERVICE_MAX_RESTARTS}+\xD7/min`:`recycled ${types_1.SERVICE_MAX_RESTARTS}\xD7 in a row and no pod came up`;S(e,"error",`service crash-looping: ${e.project} \u2014 ${s}, not auto-recycling (the next request retries)`,`cluster-service:${e.project}`,{kind:"service-crash-loop",project:e.project,recycles:r-1}),U(e,"wedged (crash-loop cap) \u2014 leaving down for the next request",{announce:!1});return}e.wedgeRecycles=r,e.restarts.push(o),console.log(`[gateway] self-heal: recycling WEDGED ${e.project} (live parent, 0 live pods; attempt ${r}/${types_1.SERVICE_MAX_RESTARTS} with no pod up since the first, ${e.restarts.length} in the last minute; ${e.inflight??0} request(s) in flight \u2014 jobs held by the dead pod keep their locks until they expire)`),S(e,"warning",`self-heal: recycling wedged ${e.project} (0 live pods)`,`cluster-service:${e.project}`,{kind:"service-recycle",project:e.project,attempt:r,inWindow:e.restarts.length}),U(e,"wedged: 0 live pods \u2014 recycling",{announce:!1}),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&Y(e)},1500).unref?.()},"recycleWedged"),Ze={maxAgeMs:types_1.POD_MAX_AGE_MS,graceMs:types_1.POD_STALE_GRACE_MS,settleMs:types_1.POD_RECYCLE_SETTLE_MS,cooldownMs:types_1.POD_STALE_RECYCLE_COOLDOWN_MS};let Ee;const ne=new Map,ke=new Map;let je=!1,Re=0,we=0;const Qe=a(()=>{const e=t.projectRoots??{},o=new Set(t.services.map(s=>s.project));for(const s of t.routes)s.lens&&o.add(s.lens.project);const r=new Set;for(const s of o){const i=e[s];if(!i)continue;const n=path.relative(t.root,i).split(path.sep).filter(Boolean)[0];n&&!n.startsWith("..")&&r.add(n)}return[...r]},"managedBuckets"),et=a((e,o,r,s)=>{const i=t.projectSourceRoots?.[e];if(i?.length)return i;const n=t.projectRoots?.[e];if(!n)return;const d=sourceScopeDirs(t.root,n,r,o,s);return d.length>0?d:void 0},"scopeFor"),tt=a(()=>{if(je||Date.now()-Re<types_1.POD_STALE_SCAN_MS)return;je=!0,Re=Date.now();const e=Re;(async()=>{const o=(0,scope_1.readSourceSetOptions)(t.root),r=o.exclude,s={ignoreTests:o.ignoreTests},i=sourceScanPass(t.root,r,s),n=await i.snapshot(),d=Date.now(),u=sourceChangeWindowMs(d,we,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS),w=Ee?diffSourceSets(Ee,n,d,u):null;if(w&&(t.sourceSetChangedAt=d,t.sourceSetChange=w,X("info","source file set changed \u2014 stale pods recycle when idle","cluster-gateway",{kind:"source-set-changed",added:w.added,removed:w.removed,truncated:w.truncated})),Ee=n,!t.projectRoots){we=e;return}let j;try{j=(await fs.promises.readdir(t.root,{withFileTypes:!0})).filter(h=>h.isDirectory()).map(h=>h.name)}catch{return}const R=Qe(),v=new Set(t.services.map(h=>h.project));for(const h of t.routes)h.lens&&v.add(h.lens.project);const g=new Map;for(const h of v){const b=et(h,j,R,r);if(!b)continue;const x=b.join("|"),V=g.get(x)??{dirs:b,projects:[]};V.projects.push(h),g.set(x,V)}const A=Date.now(),P=sourceChangeWindowMs(A,we,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS);we=e;const q=a((h,b,x)=>{t.sourceSetChangedFor??=new Map,t.sourceSetChangesFor??=new Map;for(const V of h)t.sourceSetChangedFor.set(V,b),t.sourceSetChangesFor.set(V,x)},"stampScoped"),ae=new Set([...g.values()].flatMap(h=>h.projects));for(const h of[...t.sourceSetScoped??[]])ae.has(h)||t.sourceSetScoped.delete(h);for(const[h,{dirs:b,projects:x}]of g){const V=await i.snapshot(b),Ae=ne.get(h);if(Ae||x.some(F=>ke.has(F))){t.sourceSetScoped??=new Set;for(const F of x)t.sourceSetScoped.add(F)}ne.set(h,V);const Ce=new Map;for(const F of x){const B=ke.get(F);if(B===void 0||B===h)continue;const te=Ce.get(B)??[];te.push(F),Ce.set(B,te)}for(const F of x)ke.set(F,h);for(const[F,B]of Ce){const te=ne.get(F),ie=te?diffSourceSets(te,V,A,P):w;ie&&(q(B,te?A:d,ie),X("info",`source file set changed \u2014 ${B.join(", ")}'s watch scope was re-keyed`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,rescoped:!0,projects:B,added:ie.added,removed:ie.removed,truncated:ie.truncated}))}if(!Ae)continue;const ce=diffSourceSets(Ae,V,A,P);ce&&(q(x,A,ce),X("info",`source file set changed in ${x.join(", ")}'s scope`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,projects:x,added:ce.added,removed:ce.removed,truncated:ce.truncated}))}for(const h of[...ne.keys()])g.has(h)||ne.delete(h)})().catch(()=>{}).finally(()=>{je=!1})},"maybeScanSourceSet"),ot=a((e,o)=>{const r=podChangeClock(t,e.project),s=r.change,i=`${r.scope==="project"?"in its scope":"in the workspace (its scope is not known)"}: ${changeEvidence(s)}`,n=s?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,d=podWatcherVerdict(e.watcher,o,n),u=a(j=>(e.staleKeptAt!==o&&(e.staleKeptAt=o,console.log(`[gateway] stale source set: pod ${e.project} ${j} \u2014 no recycle.`)),!1),"keep");if(d==="heard")return e.staleVerifiedAt=o,S(e,"info",`stale check: ${e.project} watcher confirmed \u2014 no recycle`,`cluster-service:${e.project}`,{kind:"pod-stale-verified",project:e.project,watcher:d}),u(`watcher CONFIRMED alive across the change (last build ${new Date(e.watcher?.lastBuildAt??0).toISOString()})`);if(d==="degraded")return console.log(`[gateway] stale source set: pod ${e.project} watcher DEGRADED (${e.watcher?.degraded}) \u2014 recycling.`),!0;const w=a(j=>(e.staleKeptAt!==o&&(e.staleKeptAt=o,console.log(`[gateway] stale source set: pod ${e.project} ${j}; the change ${i} \u2014 recycling.`)),!0),"recycling");return d==="silent"?types_1.POD_WATCHER_SILENT==="keep"?u("watcher alive but quiet across the change \u2014 keeping it (LENSMCP_POD_WATCHER_SILENT=keep; a live watcher cannot miss an add it will need)"):w("watcher alive but quiet across the change"):types_1.POD_WATCHER_UNVERIFIED==="keep"?u("unverifiable (no watcher testimony \u2014 older devserver bundle?) \u2014 keeping it (LENSMCP_POD_WATCHER_UNVERIFIED=keep)"):w("watcher unverifiable (no testimony yet \u2014 a pod that never rebuilt, or an older devserver bundle)")},"podStaleRecycleAllowed"),rt=a((e,o)=>{if(e.lastStaleRecycleAt=Date.now(),types_1.POD_RECYCLE_MODE==="rolling"&&e.proc&&e.launcher!=="nx"){me(e,o);return}console.log(`[gateway] zombie recycle: ${e.project} (${o}) \u2014 stale fs view; fresh pod incoming`),S(e,"warning",`zombie recycle: ${e.project} (${o})`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:o});const r=!!e.decl.eager;U(e,`${o} \u2014 recycling stale pod`,{announce:!1}),r&&setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&Y(e)},1500).unref?.()},"recyclePod"),st=a(()=>{const e=setInterval(()=>{lt().catch(o=>console.error("[gateway] sweep error:",o))},t.sweepMs);return e.unref(),e},"startSweeper"),nt=l.listProcesses??(()=>{try{return(0,orphan_reaper_1.parsePsRows)((0,node_child_process_1.execFileSync)("ps",orphan_reaper_1.PS_ROW_ARGS,{encoding:"utf8",timeout:5e3}))}catch{return[]}}),be=l.signalProcess??((e,o)=>{process.kill(e,o)});let De=0;const ct=a(()=>{if(typeof process.getuid!="function")return 0;const e=t.registry?t.registry.allServices():t.services;if(e.length===0)return 0;const o=e.map(n=>({label:n.wsKey||path.basename(n.root),project:n.project,root:n.root,svc:n})),r=new Set;for(const n of e)n.proc?.pid&&r.add(n.proc.pid);for(const n of[...fe.keys(),...K.keys(),...O.keys()])n.pid&&r.add(n.pid);const s=[...new Set((0,process_name_1.defaultLinkDirs)().flatMap(n=>{try{return[n,fs.realpathSync(n)]}catch{return[n]}}))];let i=0;for(const n of(0,orphan_reaper_1.findOrphanExecutors)(nt(),o,{linkDirs:s,uid:process.getuid(),selfPid:process.pid,ownGroups:r})){const{row:d}=n;try{be(n.group?-d.pgid:d.pid,"SIGKILL")}catch(w){if(w.code!=="ESRCH"||!n.group)continue;try{be(d.pid,"SIGKILL")}catch{continue}}i+=1;const u=n.owner.svc;console.log(`[gateway] reaped an orphaned executor of ${u.project} (${n.role}, pid ${d.pid}${n.group?`, group ${d.pgid}`:""}, parent gone) \u2014 a stopped tree it outlived: ${d.command.slice(0,160)}`),S(u,"warning",`orphan reap: ${u.project} (pid ${d.pid})`,`cluster-service:${u.project}`,{kind:"orphan-executor-reap",project:u.project,pid:d.pid,pgid:d.pgid,role:n.role,group:n.group})}return i},"reapOrphanExecutors"),lt=a(async()=>{{if(t.stopped())return;Xe(),l.reapForeign!==!1&&types_1.ORPHAN_REAP_EVERY_MS>0&&Date.now()-De>=types_1.ORPHAN_REAP_EVERY_MS&&(De=Date.now(),ct());for(const e of t.graphStores?.all()??[])e.refreshIfStale();types_1.POD_RECYCLE_ENABLED&&tt();for(const e of t.registry?t.registry.allServices():t.services){if(t.stopped()||!e.proc){e.wedgedSince=void 0;continue}const o=path.resolve(e.root)===path.resolve(t.root),r=(0,warm_start_1.instanceIdleSec)(e,!o&&!!t.registry?.get(e.wsKey)?.instance);if(r&&e.state==="up"&&(!e.restart||e.restart.done)&&e.inflight===0&&Date.now()-e.lastUsed>r*1e3){U(e,`idle ${r}s`),e.wedgedSince=void 0;continue}const s=e.state==="starting"&&e.spawnAt!==void 0&&Date.now()-e.spawnAt<t.startupTimeoutMs,i=N(e.pool)>0;if(i||s){if(e.wedgedSince=void 0,i&&ue(e,"observed"),i&&!s&&types_1.POD_RECYCLE_ENABLED&&o){const n=podChangeClock(t,e.project).at;await Le(e);const d=(e.staleVerifiedAt??0)>=n&&n>0,u=podRecycleReason(e,Date.now(),d?0:n,Ze);if(u==="stale-source-set"&&!ot(e,n))continue;u&&rt(e,u)}continue}e.wedgedSince??=Date.now(),Date.now()-e.wedgedSince>types_1.WEDGE_RECYCLE_GRACE_MS&&(e.wedgedSince=void 0,xe(e))}}},"sweepOnce");return{scanNow:N,spawnService:Y,ensureUp:Se,scaleUp:Fe,killSpawned:U,markUp:ue,startSweeper:st,rollPod:me,restartService:Je,recycleWedged:xe,stopRetiringTrees:Ye,finishDyingTrees:We,stopBuildHost:a(e=>e===void 0?E.stop():E.release(e),"stopBuildHost")}}$(createServiceLayer,"createServiceLayer"),m(createServiceLayer,"createServiceLayer"),a(createServiceLayer,"createServiceLayer");function chooseStalePodKillTarget(t,c,l){if(!(t===void 0||!Number.isInteger(t)||t<=1)&&!(c!==void 0&&c!==t)&&t!==l)return t}$(chooseStalePodKillTarget,"chooseStalePodKillTarget"),m(chooseStalePodKillTarget,"chooseStalePodKillTarget"),a(chooseStalePodKillTarget,"chooseStalePodKillTarget");
|
|
1
|
+
"use strict";var it=Object.defineProperty;var m=(t,c)=>it(t,"name",{value:c,configurable:!0});var at=Object.defineProperty,a=m((t,c)=>at(t,"name",{value:c,configurable:!0}),"a");Object.defineProperty(exports,"__esModule",{value:!0}),exports.scaleTarget=scaleTarget,exports.isLoopbackHostname=isLoopbackHostname,exports.isOwnRunnerCommand=isOwnRunnerCommand,exports.isRunnerOf=isRunnerOf,exports.isTestSourcePath=isTestSourcePath,exports.sourceScanPass=sourceScanPass,exports.sourceSetSnapshot=sourceSetSnapshot,exports.sourceSetSignature=sourceSetSignature,exports.diffSourceSets=diffSourceSets,exports.sourceChangeWindowMs=sourceChangeWindowMs,exports.sourceScopeDirs=sourceScopeDirs,exports.podRecycleReason=podRecycleReason,exports.lensFrontendStale=lensFrontendStale,exports.lensWatcherVerdict=lensWatcherVerdict,exports.podWatcherVerdict=podWatcherVerdict,exports.lensChildWedged=lensChildWedged,exports.isPortConflictExit=isPortConflictExit,exports.podChangeClock=podChangeClock,exports.createServiceLayer=createServiceLayer,exports.chooseStalePodKillTarget=chooseStalePodKillTarget;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),node_crypto_1=require("node:crypto"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),net=tslib_1.__importStar(require("node:net")),path=tslib_1.__importStar(require("node:path")),node_util_1=require("node:util"),discovery_1=require("./discovery"),pod_sock_1=require("../../../pod-sock"),scope_1=require("./scope"),pod_env_1=require("./pod-env"),pod_probe_1=require("./pod-probe"),service_keys_1=require("./service-keys"),workspace_log_1=require("./workspace-log"),own_log_1=require("./own-log"),inspector_secret_1=require("../../../inspector-secret"),pod_output_1=require("./pod-output"),serve_launch_1=require("./serve-launch"),shared_build_1=require("./shared-build"),warm_start_1=require("./warm-start"),protocol_1=require("../../../shared-build/protocol"),types_1=require("./types"),exit_reason_1=require("../../../exit-reason"),handoff_retire_1=require("../../../handoff-retire"),process_name_1=require("../../../process-name"),orphan_reaper_1=require("./orphan-reaper");function eastWestEnv(t,c){const l={},p=t.serviceKeys[(0,service_keys_1.serviceKeyId)(c.wsKey,c.project)];if(p&&(l.LENSMCP_SERVICE_KEY=p),t.https){const f=require("../../../basic-ssl").caCertPath();fs.existsSync(f)&&(l.NODE_EXTRA_CA_CERTS=f)}return l}m(eastWestEnv,"eastWestEnv"),a(eastWestEnv,"eastWestEnv");const sleep=a(t=>new Promise(c=>setTimeout(c,t)),"sleep"),SRC_EXCLUDE=new Set(["node_modules","dist","tmp","coverage","build","out","target"]),SRC_EXT=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".css",".scss",".sass",".less",".json",".html",".htm",".vue",".svelte",".mdx"]),SCAN_FILE_CAP=1e5;function fnv1a(t){let c=2166136261;for(let l=0;l<t.length;l+=1)c^=t.charCodeAt(l),c=Math.imul(c,16777619);return c>>>0}m(fnv1a,"fnv1a"),a(fnv1a,"fnv1a");const execFileP=(0,node_util_1.promisify)(node_child_process_1.execFile);async function gitIgnoredPaths(t){try{const{stdout:c}=await execFileP("git",["ls-files","--others","--directory","--ignored","--exclude-standard","-z"],{cwd:t,maxBuffer:33554432,timeout:1e4,windowsHide:!0});return new Set(c.split("\0").filter(Boolean))}catch{return new Set}}m(gitIgnoredPaths,"gitIgnoredPaths"),a(gitIgnoredPaths,"gitIgnoredPaths");function scaleTarget(t,c=fs.existsSync){if(t.decl.adminUrl)return{url:t.decl.adminUrl};const l=path.join(t.pool.dir,"parent.sock");return c(l)?{socketPath:l}:t.decl.port?{url:`http://localhost:${t.decl.port}`}:void 0}m(scaleTarget,"scaleTarget"),a(scaleTarget,"scaleTarget");function isLoopbackHostname(t){const c=t.toLowerCase().replace(/^\[(.*)\]$/,"$1").replace(/\.$/,"");return c==="localhost"||c.endsWith(".localhost")?!0:net.isIPv4(c)?c.split(".")[0]==="127":net.isIPv6(c)&&new URL(`http://[${c}]/`).hostname==="[::1]"}m(isLoopbackHostname,"isLoopbackHostname"),a(isLoopbackHostname,"isLoopbackHostname");function postScale(t,c,l){let p;if("socketPath"in t)p=http.request({socketPath:t.socketPath,path:"/webpack/scale",method:"POST",headers:{"content-type":"application/json"}},f=>f.resume());else{const f=t.url.startsWith("https"),T=f?require("node:https"):http,_={method:"POST"};f&&isLoopbackHostname(new URL(t.url).hostname)&&(_.rejectUnauthorized=!1),l&&(_.lookup=l),p=T.request(`${t.url}/webpack/scale`,_,A=>A.resume())}return p.on("error",()=>{}),p.end(JSON.stringify({pods:c})),p}m(postScale,"postScale"),a(postScale,"postScale");function isOwnRunnerCommand(t,c){return(0,serve_launch_1.isServeRunnerCommand)(t)?(0,serve_launch_1.isServeRunnerCommandOf)(t,c):t.includes("/node_modules/nx/")?t.includes(`${c.replace(/\/+$/,"")}/node_modules/nx/`):!0}m(isOwnRunnerCommand,"isOwnRunnerCommand"),a(isOwnRunnerCommand,"isOwnRunnerCommand");function isRunnerOf(t,c,l){const p=c.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return!new RegExp(`(^|\\s)run ${p}(:|\\s|$)`).test(t)||!(0,serve_launch_1.isServeRunnerCommand)(t)&&!/\bnx(\.js)?\b/.test(t)?!1:isOwnRunnerCommand(t,l)}m(isRunnerOf,"isRunnerOf"),a(isRunnerOf,"isRunnerOf");const TEST_FILE_RE=/\.(spec|test|e2e|e2e-spec|stories)\.[cm]?[jt]sx?$/,TEST_DIR_SEGMENTS=new Set(["__tests__","__mocks__","__snapshots__"]);function isTestSourcePath(t){const c=t.split("/"),l=c[c.length-1]??"";if(TEST_FILE_RE.test(l))return!0;for(let p=0;p<c.length-1;p+=1)if(TEST_DIR_SEGMENTS.has(c[p]))return!0;return!1}m(isTestSourcePath,"isTestSourcePath"),a(isTestSourcePath,"isTestSourcePath");function sourceScanPass(t,c,l){const p=l?.ignoreTests??!0;let f;const T=new Map,_=`tree:${path.resolve(t)}`,A=a(y=>path.relative(t,y).split(path.sep).join("/"),"rel"),C=a(async(y,$)=>{const E=await(f??=gitIgnoredPaths(t)),b=[],F=new Set;let D=!1;const H=a(async(te,S)=>{if(b.length>=SCAN_FILE_CAP){D=!0;return}let O;try{O=await fs.promises.readdir(te,{withFileTypes:!0})}catch{return}S&&F.add(A(te));for(const z of O){if(b.length>=SCAN_FILE_CAP){D=!0;return}const W=z.name,re=path.join(te,W);if(z.isDirectory()){if(!S||W.startsWith(".")||SRC_EXCLUDE.has(W)||c?.has(W)||W.endsWith("-devserver")||E.has(`${A(re)}/`))continue;await H(re,!0)}else if(z.isFile()){const oe=W.lastIndexOf(".");if(oe<=0||!SRC_EXT.has(W.slice(oe)))continue;const J=A(re);if(E.has(J)||p&&isTestSourcePath(J))continue;b.push(J)}}},"walk");return await H(y,$),{paths:b,entered:F,truncated:D}},"walkDir"),L=a((y,$)=>{let E=T.get(y);return E||(E=$(),T.set(y,E)),E},"memo"),ie=a(async()=>{const y=T.get(_);if(!y)return;const $=await y;return $.truncated?void 0:$},"wideWalk"),B=new Set,le=a(()=>L(`files:${path.resolve(t)}`,async()=>{const y=await ie();return y?{paths:y.paths.filter($=>!$.includes("/")),entered:B,truncated:!1}:C(t,!1)}),"rootFiles"),de=a(y=>L(`tree:${path.resolve(y)}`,async()=>{const $=await ie(),E=A(y);if($?.entered.has(E)){const b=`${E}/`;return{paths:E===""?$.paths:$.paths.filter(F=>F.startsWith(b)),entered:B,truncated:!1}}return C(y,!0)}),"subtree"),X=a(y=>{const $=new Set;let E=0,b=y.some(D=>D.truncated);const F=a(D=>$.has(D)?!0:$.size>=SCAN_FILE_CAP?(b=!0,!1):($.add(D),E^=fnv1a(D),!0),"add");for(const D of y)if(!D.paths.every(F))break;return{signature:`${$.size}:${(E>>>0).toString(36)}`,paths:$,truncated:b}},"compose");return{async snapshot(y){if(!y||y.length===0)return X([await L(_,()=>C(t,!0))]);const $=[await le()];for(const E of y)$.push(await de(E));return X($)}}}m(sourceScanPass,"sourceScanPass"),a(sourceScanPass,"sourceScanPass");async function sourceSetSnapshot(t,c,l,p){return sourceScanPass(t,l,p).snapshot(c)}m(sourceSetSnapshot,"sourceSetSnapshot"),a(sourceSetSnapshot,"sourceSetSnapshot");async function sourceSetSignature(t,c,l,p){return(await sourceSetSnapshot(t,c,l,p)).signature}m(sourceSetSignature,"sourceSetSignature"),a(sourceSetSignature,"sourceSetSignature");const SOURCE_DIFF_PATH_CAP=128;function diffSourceSets(t,c,l,p){if(t.paths.size===c.paths.size){let A=!0;for(const C of t.paths)if(!c.paths.has(C)){A=!1;break}if(A)return null}const f=[],T=[];let _=t.truncated||c.truncated;for(const A of c.paths)t.paths.has(A)||(f.length+T.length<SOURCE_DIFF_PATH_CAP?f.push(A):_=!0);for(const A of t.paths)c.paths.has(A)||(f.length+T.length<SOURCE_DIFF_PATH_CAP?T.push(A):_=!0);return{changedAt:l,added:f,removed:T,truncated:_,...p!==void 0?{windowMs:p}:{}}}m(diffSourceSets,"diffSourceSets"),a(diffSourceSets,"diffSourceSets");function sourceChangeWindowMs(t,c,l,p){const f=c&&c>0?t-c:l;return Math.max(f,l)+p}m(sourceChangeWindowMs,"sourceChangeWindowMs"),a(sourceChangeWindowMs,"sourceChangeWindowMs");function sourceScopeDirs(t,c,l,p,f){const T=a(C=>{const L=path.relative(t,C).split(path.sep).filter(Boolean);return L.length===0||L[0].startsWith("..")?"":L[0]},"bucketOf")(c);if(!T)return[];const _=new Set(l.filter(Boolean)),A=new Set([T]);for(const C of p)C.startsWith(".")||SRC_EXCLUDE.has(C)||f?.has(C)||C.endsWith("-devserver")||_.has(C)||A.add(C);return[...A].sort().map(C=>path.join(t,C))}m(sourceScopeDirs,"sourceScopeDirs"),a(sourceScopeDirs,"sourceScopeDirs");function podRecycleReason(t,c,l,p){return!t.proc||t.state!=="up"||t.spawnAt==null||t.inflight>0||(t.activeWork??0)>0||c-t.lastUsed<p.settleMs||t.lastStaleRecycleAt!=null&&c-t.lastStaleRecycleAt<p.cooldownMs?null:l>0&&l-t.spawnAt>p.graceMs?"stale-source-set":p.maxAgeMs>0&&c-t.spawnAt>p.maxAgeMs?"max-age":null}m(podRecycleReason,"podRecycleReason"),a(podRecycleReason,"podRecycleReason");function lensFrontendStale(t,c,l,p,f){return!(p-c<f.cooldownMs||l<=0||l-t<=f.graceMs||p-l<f.settleMs)}m(lensFrontendStale,"lensFrontendStale"),a(lensFrontendStale,"lensFrontendStale");function lensWatcherVerdict(t,c,l,p=[]){if(!t)return"unknown";if("schemaVersion"in t&&t.schemaVersion>=2&&p.length>0){const f=c-l,T=new Set(t.recentEvents.filter(_=>_.at>=f).map(_=>path.resolve(_.path)));return p.every(_=>T.has(path.resolve(_)))?"heard":"missed"}return t.lastFsSetEventAt>=c-l?"heard":"missed"}m(lensWatcherVerdict,"lensWatcherVerdict"),a(lensWatcherVerdict,"lensWatcherVerdict");function podWatcherVerdict(t,c,l){if(!t)return"unknown";if(t.degraded)return"degraded";const p=c-l;return t.lastWatchRunAt>=p||t.lastBuildAt>=p?"heard":"silent"}m(podWatcherVerdict,"podWatcherVerdict"),a(podWatcherVerdict,"podWatcherVerdict");function lensChildWedged(t,c,l,p){const f=t.hasListened?p.graceMs:Math.max(p.graceMs,p.neverListenedGraceMs);return l-t.spawnedAt<f||l-c<p.cooldownMs||t.probeFails<Math.max(2,p.failureThreshold)?null:"wedged-no-listener"}m(lensChildWedged,"lensChildWedged"),a(lensChildWedged,"lensChildWedged");function isPortConflictExit(t,c){return t.signal||t.code===null||t.code===0||t.ranMs>c.fastFailMs?!1:t.portHeld}m(isPortConflictExit,"isPortConflictExit"),a(isPortConflictExit,"isPortConflictExit");function podChangeClock(t,c){const l=t.sourceSetChangedFor?.get(c);if(l!==void 0){const p=t.sourceSetChangesFor?.get(c);return{at:l,...p?{change:p}:{},scope:"project"}}return t.sourceSetScoped?.has(c)?{at:0,scope:"none"}:{at:t.sourceSetChangedAt??0,...t.sourceSetChange?{change:t.sourceSetChange}:{},scope:"workspace"}}m(podChangeClock,"podChangeClock"),a(podChangeClock,"podChangeClock");const changeEvidence=a(t=>{if(!t)return"no path evidence";const c=[...t.added.map(l=>`+${l}`),...t.removed.map(l=>`-${l}`)];return c.length?`${c.slice(0,3).join(", ")}${c.length>3?` (+${c.length-3} more)`:""}`:"no path evidence"},"changeEvidence");function createServiceLayer(t,c,l={}){const p=l.spawnProcess??node_child_process_1.spawn,f=l.probeAlive??pod_probe_1.probePodAlive,T=l.killTree??((e,r="SIGTERM")=>{try{process.kill(-e.pid,r)}catch{try{e.kill(r)}catch{}}}),_=l.sharedBuild??(0,shared_build_1.createSharedBuildRelay)(t),A=a((e,r="SIGTERM")=>{_.detach(e),T(e,r)},"killTree"),C=l.handoffDrainMs??(0,handoff_retire_1.handoffDrainBoundMs)(),L=l.treeAlive??(e=>{if(!e.pid||!(e instanceof node_child_process_1.ChildProcess))return!1;try{return process.kill(-e.pid,0),!0}catch(r){return r.code==="EPERM"}}),ie=l.retirePollMs??1e3,B=l.rollReadyMs??types_1.POD_ROLL_READY_MS,le=l.rollPollMs??750,de=l.maxConcurrentRolls??types_1.POD_MAX_CONCURRENT_ROLLS,X=de>0?de:Number.POSITIVE_INFINITY,y=l.maxConcurrentColdStarts??types_1.MAX_COLD_STARTS,$=y>0?y:Number.POSITIVE_INFINITY;let E=0;const b=[],F=a(()=>E<$?(E+=1,Promise.resolve()):new Promise(e=>{b.push(()=>{E+=1,e()})}),"acquireColdSlot"),D=a(()=>{E-=1,b.shift()?.()},"releaseColdSlot"),{emit:H}=c,te=a(e=>e.wsKey===t.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl"),"serviceBus"),S=a((e,r,o,s,i)=>H(r,o,s,{wsKey:e.wsKey,...i},void 0,te(e)),"emitSvc"),O=a(e=>(e.scannedAt=0,(0,discovery_1.pickSock)(e,t.scanTtlMs)?e.socks.length:0),"scanNow"),z=a((e,r)=>{let o;try{o=(0,node_child_process_1.execFileSync)("ps",["ax","-ww","-o","pid=,pgid=,command="],{encoding:"utf8",timeout:5e3})}catch{return 0}const s=e.proc?.pid;let i=0;for(const n of o.split(`
|
|
2
|
+
`)){const d=n.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);if(!d)continue;const u=Number(d[1]),w=Number(d[2]);if(isRunnerOf(d[3],r,e.root)&&!(u===process.pid||u===s)&&!(s!==void 0&&w===s)){try{process.kill(-w,"SIGKILL")}catch{try{process.kill(u,"SIGKILL")}catch{}}i+=1}}return i>0&&(console.log(`[gateway] ${r}: reaped ${i} stale runner tree(s) \u2014 a foreign generation of this service (holding nx's task lock, or its pool)`),S(e,"warning",`stale-runner reap: ${e.project} (${i} foreign tree(s))`,`cluster-service:${e.project}`,{kind:"stale-runner-reap",project:e.project,reaped:i})),i},"reapForeignRunners"),W=a((e,r)=>({...(0,pod_env_1.podBaseEnv)(process.env,t.root,e.root),...e.instanceEnv?{...e.instanceEnv,LENSMCP_SOCKET_ONLY:"1"}:{},...e.frozen?{LENSMCP_FREEZE:"1",LENSMCP_TYPECHECK:"off"}:{},NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false",...e.wsKey?{LENSMCP_WS_KEY:e.wsKey}:{},...e.sockNs?{LENSMCP_SOCK_NS:e.sockNs}:{},LENSMCP_EVENT_FILE:e.wsKey===t.wsKey?t.eventFile:path.join(e.root,".lensmcp","events.jsonl"),LENSMCP_GATEWAY_PID:String(process.pid),LENSMCP_POD_GENERATION:String(r),...eastWestEnv(t,e)}),"serviceEnv"),re=a((e,r,o,s)=>{const i=W(e,r),n=e.wsKey||path.basename(e.root),d=(0,serve_launch_1.planServeLaunch)({stores:t.graphStores,root:e.root,project:e.project,target:e.decl.serveTarget??"serve-hmr",childCount:s,baseEnv:i});if(d.kind==="runner"){const v=_.offeredTo(e),g=p((0,process_name_1.namedExecPath)((0,process_name_1.processName)(n,e.project,serve_launch_1.SERVE_RUNNER_ROLE)),[...d.script.execArgv,d.script.path,...(0,serve_launch_1.serveRunnerArgs)(o,s,e.root)],{cwd:e.root,detached:!0,env:v?{...d.env,[protocol_1.SHARED_BUILD_ENV]:"1"}:d.env,stdio:["ignore","pipe","pipe","ipc"]});return v&&_.attach(e,r,g),g.send?.(d.message,R=>{R&&console.error(`[gateway] ${o}: could not hand the task to its runner (${R.message})`)}),{proc:g,launcher:"runner"}}console.log(`[gateway] ${o}: starting through nx run \u2014 ${d.reason}`);const u=path.join(e.root,"node_modules","nx","dist","bin","nx.js"),w=(0,process_name_1.namedExecPath)((0,process_name_1.processName)(n,e.project,"nx")),[k,j]=fs.existsSync(u)?[w,[u,"run",o,`--childCount=${s}`]]:["yarn",["nx","run",o,`--childCount=${s}`]];return{proc:p(k,j,{cwd:e.root,detached:!0,env:i,stdio:["ignore","pipe","pipe"]}),launcher:"nx"}},"startServiceTree"),oe=new WeakMap,J=a((e,r,o)=>{const s=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,i=Math.max(1,e.decl.minPods??1),{proc:n,launcher:d}=re(e,r,s,i);oe.set(n,d),o==="active"&&(e.launcher=d),o==="active"&&(e.lastErrors=[],e.buildFailed=!1,e.faults=new pod_output_1.PodFaults);const u=a(j=>{const v=j.toString();for(const g of v.split(`
|
|
3
|
+
`)){const R=(0,pod_output_1.classifyPodLine)(g),{clean:M,broken:G,healthy:ne}=R,h=M;if(G){e.lastErrors.push(M),e.lastErrors.length>12&&e.lastErrors.shift(),e.buildFailed=!0;const x=Date.now();(M!==e.lastErrorEmitSig||x-(e.lastErrorEmitAt??0)>=types_1.SERVICE_ERROR_THROTTLE_MS)&&(e.lastErrorEmitSig=M,e.lastErrorEmitAt=x,S(e,"error",`service error: ${e.project}`,`cluster-service:${e.project}`,{kind:"service-error",project:e.project,line:M,fault:R.fault}))}ne&&(e.buildFailed=!1);const P=(e.faults??=new pod_output_1.PodFaults).observe(R);if(P){e.lastErrorEmitSig=void 0;const x=P.open.length===0;S(e,"info",`${x?"service recovered":`${P.closed.join(" + ")} recovered`}: ${e.project}`,`cluster-service:${e.project}`,{kind:x?"service-recovered":"service-fault-closed",project:e.project,line:M,closed:P.closed,open:P.open})}!e.lockBlockedAt&&/Waiting for .+ in another nx process/.test(h)&&(e.lockBlockedAt=Date.now(),console.log(`[gateway] ${s}: spawn blocked by a stale nx runner \u2014 breaking the lock + respawning`),S(e,"warning",`nx task lock: ${e.project} blocked by a stale runner \u2014 auto-breaking`,`cluster-service:${e.project}`,{kind:"nx-lock-break",project:e.project}),setTimeout(()=>{t.stopped()||!e.lockBlockedAt||(V(e,"parked on a foreign nx task lock \u2014 recycling",{announce:!1}),z(e,s),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&Y(e)},1500).unref?.())},250).unref?.())}},"sniff"),w=e.wsKey&&e.wsKey!==t.wsKey&&e.root?(0,workspace_log_1.workspaceLogWriter)(e.root):void 0,k=a(j=>{const v=(0,own_log_1.linePrefixer)(e.project);return g=>{if(t.stopped())return;const R=(0,inspector_secret_1.redactInspectorUrls)(g.toString());u(R);const M=v(R);j.write(M),w?.(M)}},"relay");return n.stdout?.on("data",k(process.stdout)),n.stderr?.on("data",k(process.stderr)),n.on("exit",(j,v)=>{if(e.proc!==n||(e.proc=void 0,e.state="down",t.stopped()))return;const g=(0,exit_reason_1.describeExit)(j,v);if(console.log(`[gateway] ${s} exited (${j??"no code"}${v?`, ${v}`:""}${e.inflight?`, ${e.inflight} request(s) in flight`:""})${g?` \u2014 ${g}`:""}`),S(e,j===0?"info":"warning",`service down: ${e.project} (exit ${j})`,`cluster-service:${e.project}`,{kind:"service-down",project:e.project,code:j,...v?{signal:v}:{}}),j===0||e.buildFailed)return;const R=Date.now();if(e.restarts=(e.restarts??[]).filter(G=>R-G<types_1.SERVICE_RESTART_WINDOW_MS),e.restarts.length>=types_1.SERVICE_MAX_RESTARTS){S(e,"error",`service crash-looping: ${e.project} \u2014 ${types_1.SERVICE_MAX_RESTARTS}+ restarts/min, not auto-respawning (the next request retries)`,`cluster-service:${e.project}`,{kind:"service-crash-loop",project:e.project});return}e.restarts.push(R);const M=Math.min(8e3,500*2**(e.restarts.length-1));setTimeout(()=>{t.stopped()||e.proc||e.state!=="down"||(console.log(`[gateway] self-heal: respawning ${e.project} (restart ${e.restarts.length}/${types_1.SERVICE_MAX_RESTARTS})`),S(e,"info",`self-heal: respawning ${e.project}`,`cluster-service:${e.project}`,{kind:"service-respawn",project:e.project,attempt:e.restarts.length}),Y(e))},M)}),n},"launchServiceProcess"),Y=a(e=>{if(t.stopped()||e.manualStopped)return;const r=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,o=Math.max(1,e.decl.minPods??1);l.reapForeign!==!1&&z(e,r),e.lockBlockedAt=void 0,console.log(`[gateway] starting ${r} (pods=${o})\u2026`),S(e,"info",`service starting: ${e.project} (${o} pod${o>1?"s":""})`,`cluster-service:${e.project}`,{kind:"service-starting",project:e.project,pods:o}),e.state="starting",e.spawnAt=Date.now(),e.generation=(e.generation??0)+1,e.proc=J(e,e.generation,"active")},"spawnService"),be=a(async e=>{const r=e.pool.socks[0];if(!r)return;const o=await(0,pod_probe_1.probePodAlive)(r,void 0,t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)]);o&&(e.activeWork=o.activeWork,o.watcher&&(e.watcher=o.watcher))},"refreshActiveWork"),Le=a(e=>{try{const r=Number(fs.readFileSync(`${e}.owner`,"utf8").trim());return Number.isInteger(r)&&r>1?r:void 0}catch{return}},"readOwnerSidecar"),Ie=a(async e=>{const r=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)];if(!r)return[];const o=(0,node_crypto_1.createHash)("sha256").update(r).digest("hex").slice(0,8),s=[];for(const i of e.pool.socks){const n=await(0,pod_probe_1.probePodAlive)(i,void 0,r);n&&(!n.keyFingerprint||n.keyFingerprint!==o)&&s.push({sock:i,pid:n.pid})}return s},"staleAdoptedSocks"),Oe=a((e,r)=>{const o=r.map(s=>s.sock);for(const{sock:s,pid:i}of r){const n=chooseStalePodKillTarget(i,Le(s),process.pid);if(n!==void 0)try{process.kill(n,"SIGTERM")}catch{}try{fs.unlinkSync(s)}catch{}try{fs.unlinkSync(`${s}.owner`)}catch{}}e.pool.socks=e.pool.socks.filter(s=>!o.includes(s)),e.pool.idx=-1,e.pool.scannedAt=0},"evictStaleAdopted"),pe=a((e,r)=>{if(e.state==="up")return!1;e.state="up",e.wedgeRecycles=0;const o=e.pool.socks.length;return S(e,"info",`service up: ${e.project} (${o} pods, ${r})`,`cluster-service:${e.project}`,{kind:"service-up",project:e.project,pods:o,adopted:r==="adopted"}),!0},"markUp"),we=a(async e=>{if(e.manualStopped)return!1;if(O(e.pool)>0){const s=await Ie(e);if(e.manualStopped)return!1;if(s.length>0&&(console.error(`[gateway] ${e.project}: ${s.length} adopted pod(s) hold a foreign east-west key \u2014 evicting instead of adopting.`),S(e,"warning",`stale adoption: ${e.project} (foreign east-west key)`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:"stale-adoption",pods:s.length}),e.proc&&V(e,"stale adoption (foreign east-west key)"),Oe(e,s)),e.pool.socks.length>0)return pe(e,"adopted"),!0}if(t.stopped())return!1;let r=!1;const o=a(()=>e.state!=="starting"&&!e.proc,"notStarted");if(o())if(e.coldWait)await e.coldWait;else{E>=$&&(console.log(`[gateway] cold start queued: ${e.project}${e.wsKey&&e.wsKey!==t.wsKey?` (${e.wsKey})`:""} \u2014 ${E} starting, ${b.length} ahead (LENSMCP_MAX_COLD_STARTS=${$}).`),S(e,"info",`cold start queued: ${e.project}`,`cluster-service:${e.project}`,{kind:"cold-start-queued",project:e.project,inFlight:E,ahead:b.length}));const s=F();if(e.coldWait=s,await s,e.coldWait=void 0,r=!0,t.stopped()||e.manualStopped)return D(),!1;o()&&Y(e)}try{return await Ne(e)}finally{r&&D()}},"ensureUp"),Ne=a(async e=>{const r=Date.now()+t.startupTimeoutMs,o=Date.now()+12e3;for(;!t.stopped()&&!e.manualStopped&&Date.now()<r;){if(await sleep(Math.min(700,t.startupTimeoutMs/4)),e.manualStopped||e.buildFailed&&Date.now()>o)return!1;if(O(e.pool)>0){e.state="up",e.buildFailed=!1;const s=e.spawnAt?Date.now()-e.spawnAt:void 0;return console.log(`[gateway] ${e.project} up (${e.pool.socks.length} pods${s?`, cold start ${s}ms`:""})`),S(e,"info",`cold start: ${e.project} (${e.pool.socks.length} pods, ${s??"?"}ms)`,`cluster-service:${e.project}`,{kind:"cold-start",project:e.project,pods:e.pool.socks.length,durationMs:s}),!0}if(e.state==="down")return!1}return!1},"waitForPods"),Ke=a(e=>{const r=e.decl.maxPods??e.decl.minPods??1,o=e.pool.socks.length,s=scaleTarget(e);!s||o===0||o>=r||e.inflight<=o||Date.now()-e.lastScaleAt<5e3||(e.lastScaleAt=Date.now(),postScale(s,o+1,l.scaleLookup),console.log(`[gateway] autoscale ${e.project}: ${o} \u2192 ${o+1} pods (inflight ${e.inflight})`),S(e,"info",`autoscale: ${e.project} ${o} \u2192 ${o+1} pods`,`cluster-service:${e.project}`,{kind:"autoscale",project:e.project,from:o,to:o+1,inflight:e.inflight}))},"scaleUp"),ue=l.killGraceMs??types_1.TREE_KILL_GRACE_MS,N=new Map,Ce=a(e=>{const r=N.get(e);if(!r||(N.delete(e),clearTimeout(r.timer),!L(e)))return;const{svc:o,why:s}=r;console.log(`[gateway] ${o.project}: its tree (pid ${e.pid}) was still running ${Math.round(ue/1e3)}s after it was told to stop (${s}) \u2014 killing it (SIGKILL).`),S(o,"warning",`tree force-killed: ${o.project} (it ignored SIGTERM)`,`cluster-service:${o.project}`,{kind:"tree-force-killed",project:o.project,why:s,pid:e.pid,graceMs:ue}),T(e,"SIGKILL")},"settleDyingTree"),Se=a((e,r,o)=>{if(A(r,"SIGTERM"),ue<=0||N.has(r))return;const s=setTimeout(()=>Ce(r),ue);s.unref?.(),N.set(r,{svc:e,why:o,timer:s})},"stopTree"),Fe=a(async(e=3e3)=>{const r=Date.now()+e;for(;N.size>0;){for(const[o,s]of[...N])L(o)||(clearTimeout(s.timer),N.delete(o));if(N.size===0||Date.now()>=r)break;await sleep(100)}for(const o of[...N.keys()])Ce(o)},"finishDyingTrees"),V=a((e,r,o)=>{if(!e.proc)return;console.log(`[gateway] ${e.project} ${r} \u2014 scaling to zero.`),o?.announce!==!1&&S(e,"info",`idle kill: ${e.project} (${r})`,`cluster-service:${e.project}`,{kind:"idle-kill",project:e.project,why:r});const s=e.proc;try{s.stdout?.removeAllListeners("data"),s.stderr?.removeAllListeners("data"),s.removeAllListeners("exit")}catch{}(0,discovery_1.stopRoutingTo)(e.pool),Se(e,s,r),e.proc=void 0,e.state="down",setTimeout(()=>{ge(e),e.pool.socks=[],e.pool.scannedAt=0},1200).unref?.()},"killSpawned"),ge=a(e=>{try{for(const r of fs.readdirSync(e.pool.dir)){if(!r.endsWith(".sock"))continue;const o=path.join(e.pool.dir,r);try{const s=Number(fs.readFileSync(`${o}.owner`,"utf8").trim());if(Number.isFinite(s)&&s>0)try{process.kill(s,0);continue}catch{}}catch{}try{fs.unlinkSync(o)}catch{}try{fs.unlinkSync(`${o}.owner`)}catch{}}}catch{}},"sweepDeadOwnerSocks");let Q=0;const ve=[],We=a(()=>Q<X?(Q+=1,Promise.resolve()):new Promise(e=>{ve.push(()=>{Q+=1,e()})}),"acquireRollSlot"),Ge=a(()=>{Q-=1,ve.shift()?.()},"releaseRollSlot"),ye=a(async(e,r,o)=>{O(e.pool);for(const s of e.pool.socks){const i=await f(s,void 0,o);if(i&&r(i.podGeneration))return!0}return!1},"anyPodAnswers"),he=new Map,qe=a((e,r,o)=>{const s=C>0&&(0,handoff_retire_1.requestHandoffRetire)(e.pool.dir,o);if(A(r,"SIGTERM"),!s)return;const i=e.wsKey&&e.wsKey!==t.wsKey&&e.root?(0,workspace_log_1.workspaceLogWriter)(e.root):void 0,n=a(ne=>h=>{if(t.stopped())return;const P=(0,inspector_secret_1.redactInspectorUrls)(h.toString()).replace(/^(?=.)/gm,`[${e.project} g${o} retiring] `);ne.write(P),i?.(P)},"say"),d=n(process.stdout),u=n(process.stderr);r.stdout?.on("data",d),r.stderr?.on("data",u);let w,k=!1;const j=a(()=>{k=!0,clearTimeout(w),r.stdout?.removeListener("data",d),r.stderr?.removeListener("data",u),r.removeListener("close",j)},"releaseLogs");r.once("close",j);let v=!1;const g=a(()=>{v||(v=!0,clearTimeout(R),clearInterval(G),t.stopped()?j():k||(w=setTimeout(j,1e3),w.unref?.()),he.delete(r),(0,handoff_retire_1.clearHandoffRetire)(e.pool.dir,o),ge(e),e.pool.scannedAt=0)},"end"),R=setTimeout(()=>{console.error(`[gateway] pod handoff: ${e.project} g${o} was still running ${C}ms after it was retired \u2014 killing it.`),T(r,"SIGKILL"),g()},C);R.unref?.();const M=a(()=>{if(!v){if(t.stopped()){g();return}L(r)||(console.log(`[gateway] pod handoff: ${e.project} g${o} finished its in-flight work and exited.`),g())}},"look"),G=setInterval(M,ie);G.unref?.(),r.once("exit",M),he.set(r,()=>{g(),Se(e,r,"the gateway is stopping")})},"retireReplacedTree"),Ve=l.standbyGraceMs??3e4,I=new Map,Ue=a((e,r,o,s,i)=>{const n=i+B+Ve,d=setTimeout(()=>Me(r),Math.max(0,n-Date.now()));d.unref?.(),I.set(r,{svc:e,generation:o,reason:s,beganAt:i,deadlineAt:n,timer:d})},"holdStandby"),Be=a(e=>{const r=I.get(e);r&&(clearTimeout(r.timer),I.delete(e))},"releaseStandby"),Z=a((e,r)=>{const o=I.get(e);if(!o)return!1;clearTimeout(o.timer),I.delete(e);const{svc:s,generation:i}=o;try{e.stdout?.removeAllListeners("data"),e.stderr?.removeAllListeners("data")}catch{}return(0,discovery_1.stopRoutingTo)(s.pool,n=>(0,pod_sock_1.podSockGeneration)(n)===i),Se(s,e,`standby g${i}: ${r}`),setTimeout(()=>ge(s),1200).unref?.(),!0},"endStandby"),Te=a((e,r)=>{const o=r.oldServing?`old generation g${r.fromGen} kept serving`:`and the old generation g${r.fromGen} is NOT serving (${r.oldGone?"its tree is gone":"none of its pods answers"}) \u2014 the service is down until it recovers`;console.error(`[gateway] pod handoff failed: ${e.project} g${r.generation}: ${r.why} \u2014 ${o}.`),e.rollFailure=`${r.why} \u2014 ${o}`,S(e,r.oldServing?"warning":"error",`pod handoff failed: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-failed",project:e.project,reason:r.reason,generation:r.generation,error:r.why,durationMs:Date.now()-r.beganAt,oldServing:r.oldServing})},"reportStandbyFailed"),Me=a(e=>{const r=I.get(e);if(!r)return;const{svc:o,generation:s,reason:i,beganAt:n}=r,d=`the standby outlived its roll (${Math.round((Date.now()-n)/1e3)}s; a roll waits ${Math.round(B/1e3)}s for it)`;Z(e,d);const u=o.proc,w=t.serviceKeys[(0,service_keys_1.serviceKeyId)(o.wsKey,o.project)];(async()=>{const k=!u||u.exitCode!==null||u.signalCode!==null,j=k?!1:await Promise.race([ye(o,g=>g!==s,w).catch(()=>!1),sleep(2e3).then(()=>{})]),v=!t.stopped()&&!k&&(j??O(o.pool)>0);Te(o,{reason:i,generation:s,fromGen:o.generation??s-1,why:d,beganAt:n,oldServing:v,oldGone:k})})()},"outlivedRoll"),He=a(()=>{for(const[e,r]of[...I])Date.now()>=r.deadlineAt?Me(e):!r.svc.rolling&&r.svc.proc!==e&&(console.error(`[gateway] pod handoff: ${r.svc.project} g${r.generation} is a standby whose roll is over \u2014 stopping it.`),Z(e,"its roll is over"))},"sweepStandbys"),Ye=a(()=>{for(const e of[...he.values()])e();for(const e of[...I.keys()])Z(e,"the gateway is stopping")},"stopRetiringTrees"),me=a((e,r)=>{if(e.rolling)return e.rolling;const o=e.proc;if(!o||t.stopped())return Promise.resolve(!1);if(e.launcher==="nx")return console.log(`[gateway] pod handoff skipped: ${e.project} runs through nx run, which starts one instance of a target at a time \u2014 no standby can overlap it (reason=${r}).`),Promise.resolve(!1);Q>=X&&console.log(`[gateway] pod handoff queued: ${e.project} reason=${r} \u2014 ${Q} roll(s) in flight, ${ve.length} ahead (LENSMCP_POD_MAX_CONCURRENT_ROLLS=${X}).`);const s=(async()=>{await We();try{return await Xe(e,o,r)}finally{Ge()}})().finally(()=>{e.rolling=void 0});return e.rolling=s,s},"rollPod"),Xe=a(async(e,r,o)=>{const s=e.proc;if(s!==r||t.stopped())return!1;const i=e.generation??0,n=i+1,d=Date.now();e.lastStaleRecycleAt=d,console.log(`[gateway] pod handoff start: ${e.project} g${i}\u2192g${n} reason=${o} \u2014 standby spawning, old generation keeps serving.`),S(e,"info",`pod handoff starting: ${e.project} (${o})`,`cluster-service:${e.project}`,{kind:"pod-handoff-start",project:e.project,reason:o,generation:n,fromGeneration:i});const u=J(e,n,"standby"),w=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)];Ue(e,u,n,o,d);let k=!1;try{const j=d+B;let v;for(;!t.stopped()&&Date.now()<j&&I.has(u)&&!(u.exitCode!==null||u.signalCode!==null);){O(e.pool);for(const g of e.pool.socks)if((await f(g,void 0,w))?.podGeneration===n){v=g;break}if(v)break;await sleep(le)}if(!I.has(u))return!1;if(!v||t.stopped()){const g=t.stopped()?"gateway stopping":u.exitCode!==null||u.signalCode!==null?`standby exited (${u.exitCode??u.signalCode})`:`standby not ready within ${Math.round(B/1e3)}s`;Z(u,g);const R=!t.stopped()&&e.proc===s&&s.exitCode===null&&s.signalCode===null&&await ye(e,M=>M!==n,w);return Te(e,{reason:o,generation:n,fromGen:i,why:g,beganAt:d,oldServing:R,oldGone:e.proc!==s||s.exitCode!==null||s.signalCode!==null}),!1}if(e.proc!==s)return Z(u,"the service was replaced underneath the roll"),!1;Be(u),k=!0,e.proc=u,e.launcher=oe.get(u),e.generation=n,e.spawnAt=d,e.state="up",e.watcher=void 0,e.staleVerifiedAt=void 0,e.staleKeptAt=void 0,e.buildFailed=!1,e.lastErrors=[];try{s.stdout?.removeAllListeners("data"),s.stderr?.removeAllListeners("data"),s.removeAllListeners("exit")}catch{}return(0,discovery_1.stopRoutingTo)(e.pool,g=>(0,pod_sock_1.podSockGeneration)(g)!==n&&path.join(e.pool.dir,g)!==v),qe(e,s,i),setTimeout(()=>{ge(e),e.pool.scannedAt=0},1200).unref?.(),console.log(`[gateway] pod handoff ready: ${e.project} g${n} answered on ${path.basename(v)} in ${Date.now()-d}ms; retiring g${i}.`),S(e,"info",`pod handoff complete: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-complete",project:e.project,reason:o,generation:n,fromGeneration:i,durationMs:Date.now()-d}),!0}finally{k||Z(u,"its roll ended without it")}},"runRoll"),ze=a((e,r)=>{if(t.stopped())return{refused:"the gateway is stopping"};if(e.manualStopped=!1,e.actionFailure=void 0,e.restart&&!e.restart.done)return{restart:e.restart,already:!0};if(!e.proc&&e.state!=="down")return{refused:`${e.project} is served by pods this gateway adopted from an earlier one \u2014 it has no tree of its own to replace. \`lensmcp gateway restart\` starts every service under this gateway.`};const o=e.proc?r.hard||e.launcher==="nx"||e.state!=="up"?"hard":"rolling":"start",s={how:o,reason:r.reason,startedAt:Date.now(),...e.proc&&e.generation!==void 0?{fromGeneration:e.generation}:{}};return e.restart=s,e.lastUsed=s.startedAt,console.log(`[gateway] restart asked: ${e.project}${e.wsKey!==t.wsKey?` (${e.wsKey})`:""} \u2014 ${o} (${r.reason}).`),S(e,"info",`restart asked: ${e.project} (${o})`,`cluster-service:${e.project}`,{kind:"service-restart",phase:"started",project:e.project,how:o,reason:r.reason,...s.fromGeneration!==void 0?{fromGeneration:s.fromGeneration}:{}}),a(async()=>{if(o==="start")return await we(e)?{ok:!0}:{ok:!1,error:$e(e)};if(o==="rolling")return e.rolling&&await e.rolling,e.proc?(e.rollFailure=void 0,await me(e,r.reason)?{ok:!0}:{ok:!1,error:e.rollFailure??"the new tree did not take over"}):await we(e)?{ok:!0}:{ok:!1,error:$e(e)};if(V(e,`restart asked (${r.reason})`,{announce:!1}),await sleep(1500),t.stopped())return{ok:!1,error:"the gateway is stopping"};let i=!1;e.proc||(await F(),i=!0,!e.proc&&e.state!=="starting"&&Y(e));try{const n=e.proc,d=e.generation,u=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],w=Date.now()+t.startupTimeoutMs;for(;!t.stopped()&&Date.now()<w;){if(!n||e.proc!==n||n.exitCode!==null||n.signalCode!==null)return{ok:!1,error:$e(e)};if(await ye(e,k=>k===d,u))return pe(e,"observed"),e.buildFailed=!1,{ok:!0};await sleep(le)}return{ok:!1,error:t.stopped()?"the gateway is stopping":`no pod of the new tree answered within ${Math.round(t.startupTimeoutMs/1e3)}s`}}finally{i&&D()}},"run")().catch(i=>({ok:!1,error:i.message})).then(i=>{s.done={ok:i.ok,at:Date.now(),...e.generation!==void 0?{generation:e.generation}:{},...i.error?{error:i.error}:{}},i.ok&&(e.lastUsed=s.done.at);const n=Math.round((s.done.at-s.startedAt)/100)/10;i.ok?console.log(`[gateway] restarted: ${e.project} \u2014 g${s.done.generation??"?"} serving after ${n}s (${o}).`):console.error(`[gateway] restart failed: ${e.project} \u2014 ${i.error} (${o}, after ${n}s).`),S(e,i.ok?"info":"error",i.ok?`restarted: ${e.project}`:`restart failed: ${e.project}`,`cluster-service:${e.project}`,{kind:"service-restart",phase:i.ok?"done":"failed",project:e.project,how:o,reason:r.reason,...s.fromGeneration!==void 0?{fromGeneration:s.fromGeneration}:{},...s.done.generation!==void 0?{generation:s.done.generation}:{},durationMs:s.done.at-s.startedAt,...i.error?{error:i.error}:{}})}),{restart:s,already:!1}},"restartService"),$e=a(e=>e.buildFailed?`its build failed${e.lastErrors?.length?`: ${e.lastErrors[e.lastErrors.length-1]}`:""}`:e.proc&&(e.proc.exitCode!==null||e.proc.signalCode!==null)?`its tree exited (${e.proc.exitCode??e.proc.signalCode})`:!e.proc&&e.state==="down"?"its tree exited before a pod answered":`no pod answered within ${Math.round(t.startupTimeoutMs/1e3)}s`,"startFailure"),xe=a(e=>{const r=Date.now();e.restarts=(e.restarts??[]).filter(s=>r-s<types_1.SERVICE_RESTART_WINDOW_MS);const o=(e.wedgeRecycles??0)+1;if(e.restarts.length>=types_1.SERVICE_MAX_RESTARTS||o>types_1.SERVICE_MAX_RESTARTS){const s=e.restarts.length>=types_1.SERVICE_MAX_RESTARTS?`wedged ${types_1.SERVICE_MAX_RESTARTS}+\xD7/min`:`recycled ${types_1.SERVICE_MAX_RESTARTS}\xD7 in a row and no pod came up`;S(e,"error",`service crash-looping: ${e.project} \u2014 ${s}, not auto-recycling (the next request retries)`,`cluster-service:${e.project}`,{kind:"service-crash-loop",project:e.project,recycles:o-1}),V(e,"wedged (crash-loop cap) \u2014 leaving down for the next request",{announce:!1});return}e.wedgeRecycles=o,e.restarts.push(r),console.log(`[gateway] self-heal: recycling WEDGED ${e.project} (live parent, 0 live pods; attempt ${o}/${types_1.SERVICE_MAX_RESTARTS} with no pod up since the first, ${e.restarts.length} in the last minute; ${e.inflight??0} request(s) in flight \u2014 jobs held by the dead pod keep their locks until they expire)`),S(e,"warning",`self-heal: recycling wedged ${e.project} (0 live pods)`,`cluster-service:${e.project}`,{kind:"service-recycle",project:e.project,attempt:o,inWindow:e.restarts.length}),V(e,"wedged: 0 live pods \u2014 recycling",{announce:!1}),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&Y(e)},1500).unref?.()},"recycleWedged"),Je={maxAgeMs:types_1.POD_MAX_AGE_MS,graceMs:types_1.POD_STALE_GRACE_MS,settleMs:types_1.POD_RECYCLE_SETTLE_MS,cooldownMs:types_1.POD_STALE_RECYCLE_COOLDOWN_MS};let _e;const se=new Map,Ee=new Map;let ke=!1,je=0,fe=0;const Qe=a(()=>{const e=t.projectRoots??{},r=new Set(t.services.map(s=>s.project));for(const s of t.routes)s.lens&&r.add(s.lens.project);const o=new Set;for(const s of r){const i=e[s];if(!i)continue;const n=path.relative(t.root,i).split(path.sep).filter(Boolean)[0];n&&!n.startsWith("..")&&o.add(n)}return[...o]},"managedBuckets"),Ze=a((e,r,o,s)=>{const i=t.projectSourceRoots?.[e];if(i?.length)return i;const n=t.projectRoots?.[e];if(!n)return;const d=sourceScopeDirs(t.root,n,o,r,s);return d.length>0?d:void 0},"scopeFor"),et=a(()=>{if(ke||Date.now()-je<types_1.POD_STALE_SCAN_MS)return;ke=!0,je=Date.now();const e=je;(async()=>{const r=(0,scope_1.readSourceSetOptions)(t.root),o=r.exclude,s={ignoreTests:r.ignoreTests},i=sourceScanPass(t.root,o,s),n=await i.snapshot(),d=Date.now(),u=sourceChangeWindowMs(d,fe,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS),w=_e?diffSourceSets(_e,n,d,u):null;if(w&&(t.sourceSetChangedAt=d,t.sourceSetChange=w,H("info","source file set changed \u2014 stale pods recycle when idle","cluster-gateway",{kind:"source-set-changed",added:w.added,removed:w.removed,truncated:w.truncated})),_e=n,!t.projectRoots){fe=e;return}let k;try{k=(await fs.promises.readdir(t.root,{withFileTypes:!0})).filter(h=>h.isDirectory()).map(h=>h.name)}catch{return}const j=Qe(),v=new Set(t.services.map(h=>h.project));for(const h of t.routes)h.lens&&v.add(h.lens.project);const g=new Map;for(const h of v){const P=Ze(h,k,j,o);if(!P)continue;const x=P.join("|"),q=g.get(x)??{dirs:P,projects:[]};q.projects.push(h),g.set(x,q)}const R=Date.now(),M=sourceChangeWindowMs(R,fe,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS);fe=e;const G=a((h,P,x)=>{t.sourceSetChangedFor??=new Map,t.sourceSetChangesFor??=new Map;for(const q of h)t.sourceSetChangedFor.set(q,P),t.sourceSetChangesFor.set(q,x)},"stampScoped"),ne=new Set([...g.values()].flatMap(h=>h.projects));for(const h of[...t.sourceSetScoped??[]])ne.has(h)||t.sourceSetScoped.delete(h);for(const[h,{dirs:P,projects:x}]of g){const q=await i.snapshot(P),Re=se.get(h);if(Re||x.some(K=>Ee.has(K))){t.sourceSetScoped??=new Set;for(const K of x)t.sourceSetScoped.add(K)}se.set(h,q);const Ae=new Map;for(const K of x){const U=Ee.get(K);if(U===void 0||U===h)continue;const ee=Ae.get(U)??[];ee.push(K),Ae.set(U,ee)}for(const K of x)Ee.set(K,h);for(const[K,U]of Ae){const ee=se.get(K),ce=ee?diffSourceSets(ee,q,R,M):w;ce&&(G(U,ee?R:d,ce),H("info",`source file set changed \u2014 ${U.join(", ")}'s watch scope was re-keyed`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,rescoped:!0,projects:U,added:ce.added,removed:ce.removed,truncated:ce.truncated}))}if(!Re)continue;const ae=diffSourceSets(Re,q,R,M);ae&&(G(x,R,ae),H("info",`source file set changed in ${x.join(", ")}'s scope`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,projects:x,added:ae.added,removed:ae.removed,truncated:ae.truncated}))}for(const h of[...se.keys()])g.has(h)||se.delete(h)})().catch(()=>{}).finally(()=>{ke=!1})},"maybeScanSourceSet"),tt=a((e,r)=>{const o=podChangeClock(t,e.project),s=o.change,i=`${o.scope==="project"?"in its scope":"in the workspace (its scope is not known)"}: ${changeEvidence(s)}`,n=s?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,d=podWatcherVerdict(e.watcher,r,n),u=a(k=>(e.staleKeptAt!==r&&(e.staleKeptAt=r,console.log(`[gateway] stale source set: pod ${e.project} ${k} \u2014 no recycle.`)),!1),"keep");if(d==="heard")return e.staleVerifiedAt=r,S(e,"info",`stale check: ${e.project} watcher confirmed \u2014 no recycle`,`cluster-service:${e.project}`,{kind:"pod-stale-verified",project:e.project,watcher:d}),u(`watcher CONFIRMED alive across the change (last build ${new Date(e.watcher?.lastBuildAt??0).toISOString()})`);if(d==="degraded")return console.log(`[gateway] stale source set: pod ${e.project} watcher DEGRADED (${e.watcher?.degraded}) \u2014 recycling.`),!0;const w=a(k=>(e.staleKeptAt!==r&&(e.staleKeptAt=r,console.log(`[gateway] stale source set: pod ${e.project} ${k}; the change ${i} \u2014 recycling.`)),!0),"recycling");return d==="silent"?types_1.POD_WATCHER_SILENT==="keep"?u("watcher alive but quiet across the change \u2014 keeping it (LENSMCP_POD_WATCHER_SILENT=keep; a live watcher cannot miss an add it will need)"):w("watcher alive but quiet across the change"):types_1.POD_WATCHER_UNVERIFIED==="keep"?u("unverifiable (no watcher testimony \u2014 older devserver bundle?) \u2014 keeping it (LENSMCP_POD_WATCHER_UNVERIFIED=keep)"):w("watcher unverifiable (no testimony yet \u2014 a pod that never rebuilt, or an older devserver bundle)")},"podStaleRecycleAllowed"),rt=a((e,r)=>{if(e.lastStaleRecycleAt=Date.now(),types_1.POD_RECYCLE_MODE==="rolling"&&e.proc&&e.launcher!=="nx"){me(e,r);return}console.log(`[gateway] zombie recycle: ${e.project} (${r}) \u2014 stale fs view; fresh pod incoming`),S(e,"warning",`zombie recycle: ${e.project} (${r})`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:r});const o=!!e.decl.eager;V(e,`${r} \u2014 recycling stale pod`,{announce:!1}),o&&setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&Y(e)},1500).unref?.()},"recyclePod"),ot=a(()=>{const e=setInterval(()=>{ct().catch(r=>console.error("[gateway] sweep error:",r))},t.sweepMs);return e.unref(),e},"startSweeper"),st=l.listProcesses??(()=>{try{return(0,orphan_reaper_1.parsePsRows)((0,node_child_process_1.execFileSync)("ps",orphan_reaper_1.PS_ROW_ARGS,{encoding:"utf8",timeout:5e3}))}catch{return[]}}),Pe=l.signalProcess??((e,r)=>{process.kill(e,r)});let De=0;const nt=a(()=>{if(typeof process.getuid!="function")return 0;const e=t.registry?t.registry.allServices():t.services;if(e.length===0)return 0;const r=e.map(n=>({label:n.wsKey||path.basename(n.root),project:n.project,root:n.root,svc:n})),o=new Set;for(const n of e)n.proc?.pid&&o.add(n.proc.pid);for(const n of[...he.keys(),...N.keys(),...I.keys()])n.pid&&o.add(n.pid);const s=[...new Set((0,process_name_1.defaultLinkDirs)().flatMap(n=>{try{return[n,fs.realpathSync(n)]}catch{return[n]}}))];let i=0;for(const n of(0,orphan_reaper_1.findOrphanExecutors)(st(),r,{linkDirs:s,uid:process.getuid(),selfPid:process.pid,ownGroups:o})){const{row:d}=n;try{Pe(n.group?-d.pgid:d.pid,"SIGKILL")}catch(w){if(w.code!=="ESRCH"||!n.group)continue;try{Pe(d.pid,"SIGKILL")}catch{continue}}i+=1;const u=n.owner.svc;console.log(`[gateway] reaped an orphaned executor of ${u.project} (${n.role}, pid ${d.pid}${n.group?`, group ${d.pgid}`:""}, parent gone) \u2014 a stopped tree it outlived: ${d.command.slice(0,160)}`),S(u,"warning",`orphan reap: ${u.project} (pid ${d.pid})`,`cluster-service:${u.project}`,{kind:"orphan-executor-reap",project:u.project,pid:d.pid,pgid:d.pgid,role:n.role,group:n.group})}return i},"reapOrphanExecutors"),ct=a(async()=>{{if(t.stopped())return;He(),l.reapForeign!==!1&&types_1.ORPHAN_REAP_EVERY_MS>0&&Date.now()-De>=types_1.ORPHAN_REAP_EVERY_MS&&(De=Date.now(),nt());for(const e of t.graphStores?.all()??[])e.refreshIfStale();types_1.POD_RECYCLE_ENABLED&&et();for(const e of t.registry?t.registry.allServices():t.services){if(t.stopped()||!e.proc){e.wedgedSince=void 0;continue}const r=path.resolve(e.root)===path.resolve(t.root),o=(0,warm_start_1.instanceIdleSec)(e,!r&&!!t.registry?.get(e.wsKey)?.instance);if(o&&e.state==="up"&&(!e.restart||e.restart.done)&&e.inflight===0&&Date.now()-e.lastUsed>o*1e3){V(e,`idle ${o}s`),e.wedgedSince=void 0;continue}const s=e.state==="starting"&&e.spawnAt!==void 0&&Date.now()-e.spawnAt<t.startupTimeoutMs,i=O(e.pool)>0;if(i||s){if(e.wedgedSince=void 0,i&&pe(e,"observed"),i&&!s&&types_1.POD_RECYCLE_ENABLED&&r){const n=podChangeClock(t,e.project).at;await be(e);const d=(e.staleVerifiedAt??0)>=n&&n>0,u=podRecycleReason(e,Date.now(),d?0:n,Je);if(u==="stale-source-set"&&!tt(e,n))continue;u&&rt(e,u)}continue}e.wedgedSince??=Date.now(),Date.now()-e.wedgedSince>types_1.WEDGE_RECYCLE_GRACE_MS&&(e.wedgedSince=void 0,xe(e))}}},"sweepOnce");return{scanNow:O,spawnService:Y,ensureUp:we,scaleUp:Ke,killSpawned:V,markUp:pe,startSweeper:ot,rollPod:me,restartService:ze,recycleWedged:xe,stopRetiringTrees:Ye,finishDyingTrees:Fe,stopBuildHost:a(e=>e===void 0?_.stop():_.release(e),"stopBuildHost")}}m(createServiceLayer,"createServiceLayer"),a(createServiceLayer,"createServiceLayer");function chooseStalePodKillTarget(t,c,l){if(!(t===void 0||!Number.isInteger(t)||t<=1)&&!(c!==void 0&&c!==t)&&t!==l)return t}m(chooseStalePodKillTarget,"chooseStalePodKillTarget"),a(chooseStalePodKillTarget,"chooseStalePodKillTarget");
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`),
|
|
3
|
-
`;busHygiene?.maybeRotateEventFile(n,h.length),
|
|
1
|
+
"use strict";var q=Object.defineProperty;var f=(s,u)=>q(s,"name",{value:u,configurable:!0});var $=Object.defineProperty,d=f((s,u)=>$(s,"name",{value:u,configurable:!0}),"d");Object.defineProperty(exports,"__esModule",{value:!0}),exports.EDGE_DURATION_SAMPLES=exports.LENS_DASHBOARD_PROJECT=void 0,exports.createObservability=createObservability;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),headless_flow_1=require("@lensmcp/core/headless-flow"),http_exchange_1=require("@lensmcp/core/http-exchange"),redact_1=require("@lensmcp/core/redact"),busHygiene=(()=>{try{return require("@lensmcp/node-instrumentation")}catch{return}})();exports.LENS_DASHBOARD_PROJECT="(lens-dashboard)",exports.EDGE_DURATION_SAMPLES=64;function ownerOf(s){return s?.svc?{root:s.svc.root,wsKey:s.svc.wsKey}:s?.lens?{...s.lens.workspaceRoot?{root:s.lens.workspaceRoot}:{},...s.lens.workspaceKey?{wsKey:s.lens.workspaceKey}:{}}:{}}f(ownerOf,"ownerOf"),d(ownerOf,"ownerOf");function busFileFor(s,u){const{root:l}=ownerOf(s);if(!l)return;const w=path.join(l,".lensmcp","events.jsonl");return w===u?void 0:w}f(busFileFor,"busFileFor"),d(busFileFor,"busFileFor");const hdr=d(s=>typeof s=="string"&&s!==""?s:Array.isArray(s)?s[0]:void 0,"hdr"),lensRequestId=d(s=>hdr(s.headers[http_exchange_1.LENS_REQUEST_ID_HEADER])??hdr(s.headers["x-request-id"]),"lensRequestId");function createObservability(s,u){const l=d(()=>Date.now().toString(36)+Math.random().toString(36).slice(2,12),"eid"),w=busHygiene?.createEventFloodGuard({burst:30,perSec:5}),g=new Map,E=d((e,t)=>{try{const r=g.get(e);r&&(fs.appendFileSync(e,JSON.stringify({id:l(),sessionId:"pending",timestamp:Date.now(),source:"gateway",category:"cluster",severity:"warning",context:{sessionId:"pending"},fingerprint:"cluster-gateway:bus-dropped",title:`lens bus: ${r.count} event${r.count===1?"":"s"} could not be written since ${new Date(r.since).toISOString()} (${r.code}) \u2014 they are lost`,raw:{kind:"bus-events-dropped",project:"gateway",dropped:r.count,since:r.since,until:Date.now(),code:r.code}})+`
|
|
2
|
+
`),g.delete(e),console.warn(`[gateway] the lens bus ${e} takes events again \u2014 ${r.count} were lost (${r.code})`)),fs.appendFileSync(e,t)}catch(r){const a=g.get(e);if(a){a.count+=1;return}const o=r?.code??"EIO";g.set(e,{count:1,since:Date.now(),code:o}),console.warn(`[gateway] the lens bus ${e} cannot be written (${o}) \u2014 counting the events lost until it can`)}},"appendCounted"),y=d((e,t,r,a,o,i)=>{const n=i??s;try{const c=w?w.admit(r):{ok:!0,suppressed:0};if(!c.ok)return;fs.mkdirSync(path.dirname(n),{recursive:!0});const p=a&&(0,redact_1.redactDeep)(a),h=JSON.stringify({id:l(),sessionId:"pending",timestamp:Date.now(),source:"gateway",category:"cluster",severity:e,context:(0,redact_1.redactDeep)({sessionId:"pending",...o}),fingerprint:r,title:(0,redact_1.safeTitle)(t),raw:c.suppressed>0?{...p,floodSuppressed:c.suppressed}:p})+`
|
|
3
|
+
`;busHygiene?.maybeRotateEventFile(n,h.length),E(n,h)}catch{}},"emit"),S=d(e=>{const t=hdr(e.headers["x-lensmcp-flow-id"]);let r=lensRequestId(e);if(!(!t&&!r&&!hdr(e.headers.traceparent)))return r||(r=l(),e.headers["x-request-id"]=r),{startedAt:Date.now(),method:(e.method??"GET").toUpperCase(),host:(e.headers.host||"").split(":")[0],url:e.url??"/",steps:[],...t?{flowId:t}:{},...r?{requestId:r}:{},...hdr(e.headers["x-lensmcp-parent-request-id"])?{parentRequestId:hdr(e.headers["x-lensmcp-parent-request-id"])}:{},...hdr(e.headers["x-lensmcp-origin-node-id"])?{originNodeId:hdr(e.headers["x-lensmcp-origin-node-id"])}:{}}},"beginTrace"),_=d((e,t,r,a)=>{if(r?.flowId||!t.pool||t.internal||t.project===exports.LENS_DASHBOARD_PROJECT||!(0,headless_flow_1.headlessFlowsEnabled)())return r;const o=e.url??"/";if((0,headless_flow_1.isProbePath)(o))return r;const i=lensRequestId(e);if(!i)return r;const n=(0,headless_flow_1.headlessFlowId)(i);e.headers["x-lensmcp-flow-id"]=n;const c=(e.method??"GET").toUpperCase(),p=(e.headers.host||"").split(":")[0],h=`request:${c} ${o.split("?")[0]}`,m=r??{startedAt:a,method:c,host:p,url:o,steps:[{step:"received",atMs:0,host:p,method:c,url:o}],requestId:i};return m.flowId=n,m.originNodeId=h,y("info",`${c} ${o.split("?")[0]}`,`gateway-origin:${t.project}`,{kind:"flow-origin",originNodeId:h,project:t.project,host:p,method:c,url:o,...ownerOf(t).wsKey?{wsKey:ownerOf(t).wsKey}:{}},{flowId:n,requestId:i,originType:"request",originNodeId:h},busFileFor(t,s)),m},"startHeadlessFlow"),D=d((e,t,r)=>{e&&e.steps.push({step:t,atMs:Date.now()-e.startedAt,...r})},"traceStep"),b=d((e,t,r,a,o)=>{if(!e||e.done||(e.done=!0,t===exports.LENS_DASHBOARD_PROJECT&&r<500))return;const i=Date.now()-e.startedAt;y(r>=500?"error":"info",`gateway ${e.method} ${e.host}${e.url} \u2192 ${r} (${i}ms)`,`gateway-request:${t}`,{kind:"gateway-request",project:t,host:e.host,method:e.method,url:e.url,status:r,durationMs:i,startedAt:e.startedAt,steps:e.steps,...ownerOf(o).wsKey?{wsKey:ownerOf(o).wsKey}:{},...a},{...e.flowId?{flowId:e.flowId}:{},...e.requestId?{requestId:e.requestId}:{},...e.parentRequestId?{parentRequestId:e.parentRequestId}:{},...e.originNodeId?{originNodeId:e.originNodeId}:{}},busFileFor(o,s))},"finishTrace"),I=new Map;return{emit:y,eid:l,beginTrace:S,startHeadlessFlow:_,traceStep:D,finishTrace:b,recordEdge:d((e,t,r,a)=>{if(e.project===exports.LENS_DASHBOARD_PROJECT&&r<500&&r!==0)return;const o=e.host??"(default)",i=(a?a+"\u21D2":"")+o+"\u2192"+e.project,n=I.get(i)??{host:o,project:e.project,caller:a,count:0,totalMs:0,errors:0,durations:[],...busFileFor(e,s)?{busFile:busFileFor(e,s)}:{},...ownerOf(e).wsKey?{wsKey:ownerOf(e).wsKey}:{}};if(n.count+=1,n.totalMs+=t,n.durations.length<exports.EDGE_DURATION_SAMPLES)n.durations.push(Math.round(t));else{const c=Math.floor(Math.random()*n.count);c<exports.EDGE_DURATION_SAMPLES&&(n.durations[c]=Math.round(t))}(r>=500||r===0)&&(n.errors+=1),I.set(i,n)},"recordEdge"),startEdgeFlusher:d(()=>{const e=setInterval(()=>{for(const t of I.values()){const r=Math.round(t.totalMs/t.count);y(t.errors?"warning":"info",`traffic ${t.host} \u2192 ${t.project}: ${t.count} req, ~${r}ms${t.errors?`, ${t.errors} errors`:""}`,`gateway-traffic:${t.host}->${t.project}`,{kind:"gateway-traffic",host:t.host,project:t.project,caller:t.caller,count:t.count,avgMs:r,errors:t.errors,durationsMs:t.durations,...t.wsKey?{wsKey:t.wsKey}:{}},void 0,t.busFile)}I.clear()},u.trafficFlushMs);return e.unref(),e},"startEdgeFlusher")}}f(createObservability,"createObservability"),d(createObservability,"createObservability");
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`)){const
|
|
1
|
+
"use strict";var x=Object.defineProperty;var u=(r,o)=>x(r,"name",{value:o,configurable:!0});var m=Object.defineProperty,d=u((r,o)=>m(r,"name",{value:o,configurable:!0}),"d");Object.defineProperty(exports,"__esModule",{value:!0}),exports.ORPHAN_ROLES=exports.PS_ROW_ARGS=void 0,exports.parsePsRows=parsePsRows,exports.findOrphanExecutors=findOrphanExecutors;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),process_name_1=require("../../../process-name"),serve_launch_1=require("./serve-launch");exports.PS_ROW_ARGS=["ax","-ww","-o","pid=,ppid=,pgid=,uid=,command="];function parsePsRows(r){const o=[];for(const t of r.split(`
|
|
2
|
+
`)){const s=/^\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/.exec(t);s&&o.push({pid:Number(s[1]),ppid:Number(s[2]),pgid:Number(s[3]),uid:Number(s[4]),command:s[5]})}return o}u(parsePsRows,"parsePsRows"),d(parsePsRows,"parsePsRows"),exports.ORPHAN_ROLES=["nx",serve_launch_1.SERVE_RUNNER_ROLE];function namedExecutable(r,o){for(const t of o){const s=`${t.replace(/\/+$/,"")}/`;if(!r.startsWith(s))continue;const i=/^\d+-\d+\/([A-Za-z0-9._-]+)(?=\s|$)/.exec(r.slice(s.length));if(i)return{name:i[1],args:r.slice(s.length+i[0].length).trim().split(/\s+/).filter(Boolean)}}}u(namedExecutable,"namedExecutable"),d(namedExecutable,"namedExecutable");function rootForms(r){const o=new Set([path.resolve(r)]);try{o.add(fs.realpathSync(r))}catch{}return[...o]}u(rootForms,"rootForms"),d(rootForms,"rootForms");function isNxOf(r,o,t){const s=`${o}/node_modules/`,i=d(n=>n.startsWith(s)&&!n.slice(s.length).split("/").includes(".."),"under");if(r.some(n=>i(n)&&n.endsWith("/nx/dist/bin/run-executor.js")))return!0;const a=r.findIndex(n=>i(n)&&n.endsWith("/nx/dist/bin/nx.js"));return a>=0&&r[a+1]==="run"&&(r[a+2]??"").startsWith(`${t}:`)}u(isNxOf,"isNxOf"),d(isNxOf,"isNxOf");function findOrphanExecutors(r,o,t){const s=new Map;for(const e of o)for(const c of exports.ORPHAN_ROLES)for(const p of new Set([(0,process_name_1.processName)(e.label,e.project,c),(0,process_name_1.legacyProcessName)(e.label,e.project,c)])){if(!p)continue;const f=s.get(p)??[];f.push({owner:e,role:c}),s.set(p,f)}const i=new Set(r.map(e=>e.pid)),a=r.find(e=>e.pid===t.selfPid)?.pgid,n=[];for(const e of r){if(e.ppid!==1||e.uid!==t.uid||e.pid<=1||e.pgid<=1||e.pid===t.selfPid||t.ownGroups.has(e.pgid)||t.ownGroups.has(e.pid)||e.pgid===a)continue;const c=namedExecutable(e.command,t.linkDirs);if(!c)continue;const p=(s.get(c.name)??[]).find(({owner:f,role:h})=>rootForms(f.root).some(l=>h===serve_launch_1.SERVE_RUNNER_ROLE?(0,serve_launch_1.isServeRunnerCommandOf)(e.command,l):isNxOf(c.args,l,f.project)));p&&n.push({row:e,owner:p.owner,role:p.role,group:e.pid===e.pgid||!i.has(e.pgid)})}return n}u(findOrphanExecutors,"findOrphanExecutors"),d(findOrphanExecutors,"findOrphanExecutors");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`)}catch{}}:
|
|
3
|
-
`)}catch{}};return(
|
|
4
|
-
`}
|
|
5
|
-
`}${droppedNote(r,
|
|
6
|
-
`));return p}}
|
|
1
|
+
"use strict";var g=Object.defineProperty;var l=(t,e)=>g(t,"name",{value:e,configurable:!0});var S=Object.defineProperty,i=l((t,e)=>S(t,"name",{value:e,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GATEWAY_LOG_ENV=exports.OWN_LOG_GENERATIONS=exports.OWN_LOG_MAX_BYTES=void 0,exports.shiftGenerations=shiftGenerations,exports.rotateOwnLog=rotateOwnLog,exports.startOwnLogRotation=startOwnLogRotation,exports.droppedNote=droppedNote,exports.createLogWriter=createLogWriter,exports.gatewayLogTakeover=gatewayLogTakeover,exports.takeOverGatewayLog=takeOverGatewayLog,exports.linePrefixer=linePrefixer;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path"));exports.OWN_LOG_MAX_BYTES=50*1024*1024,exports.OWN_LOG_GENERATIONS=3;const CHECK_EVERY_MS=3e4;exports.GATEWAY_LOG_ENV="LENSMCP_GATEWAY_LOG";const readEnv=i(t=>process.env[t],"readEnv");function shiftGenerations(t,e){try{fs.unlinkSync(`${t}.${e}`)}catch{}for(let s=e-1;s>=1;s--)try{fs.renameSync(`${t}.${s}`,`${t}.${s+1}`)}catch{}}l(shiftGenerations,"shiftGenerations"),i(shiftGenerations,"shiftGenerations");const sameFile=i((t,e)=>!!t&&t.isFile()&&t.dev===e.dev&&t.ino===e.ino,"sameFile"),statOr=i(t=>{try{return t()}catch{return}},"statOr");function rotateOwnLog(t,e={}){const s=e.fd??1,r=e.maxBytes??exports.OWN_LOG_MAX_BYTES,p=e.keep??exports.OWN_LOG_GENERATIONS,d=statOr(()=>fs.statSync(t));if(!d||d.size<=r)return!1;const u=sameFile(statOr(()=>fs.fstatSync(s)),d),a=e.launchedLog??readEnv(exports.GATEWAY_LOG_ENV);if(!u&&!(a&&sameFile(statOr(()=>fs.statSync(a)),d)))return!1;try{shiftGenerations(t,p),fs.copyFileSync(t,`${t}.1`);try{fs.chmodSync(`${t}.1`,384)}catch{}u?fs.ftruncateSync(s,0):fs.truncateSync(t,0)}catch{return!1}const f=u?n=>{try{fs.writeSync(s,`${n}
|
|
2
|
+
`)}catch{}}:n=>{try{fs.appendFileSync(t,`${n}
|
|
3
|
+
`)}catch{}};return(e.note??f)(`[gateway] ${path.basename(t)} passed ${Math.round(r/1048576)} MB \u2014 rotated; the lines before are in ${path.basename(t)}.1 (\u2026${p} kept)`),!0}l(rotateOwnLog,"rotateOwnLog"),i(rotateOwnLog,"rotateOwnLog");function startOwnLogRotation(t,e={}){const s=path.join(t,".lensmcp","gateway.log"),r=setInterval(()=>{activeTakeover?.reopenIfMoved(),rotateOwnLog(s,e)},e.everyMs??CHECK_EVERY_MS);return r.unref?.(),()=>clearInterval(r)}l(startOwnLogRotation,"startOwnLogRotation"),i(startOwnLogRotation,"startOwnLogRotation");const sizeText=i(t=>t>=1048576?`${(t/1048576).toFixed(1)} MB`:t>=1024?`${Math.round(t/1024)} KB`:`${t} B`,"sizeText");function droppedNote(t,e="gateway.log"){const s=t.code==="ENOSPC"?"ENOSPC \u2014 the disk was full":t.code;return`[gateway] ${new Date(t.lastAt).toISOString()} ${e}: ${t.lines} line${t.lines===1?"":"s"} (${sizeText(t.bytes)}) could not be written between ${new Date(t.firstAt).toISOString()} and ${new Date(t.lastAt).toISOString()} (${s}) \u2014 they are lost
|
|
4
|
+
`}l(droppedNote,"droppedNote"),i(droppedNote,"droppedNote");function createLogWriter(t,e={}){const s=e.now??Date.now;let r,p=!0;const d=i(a=>{try{t(a);return}catch(f){return f??new Error("the write failed")}},"attempt"),u=i((a,f)=>{const n=s();let o=0;for(const y of a)y===10&&(o+=1);o=Math.max(1,o);const c=f?.code??"EIO";r=r?{lines:r.lines+o,bytes:r.bytes+a.length,firstAt:r.firstAt,lastAt:n,code:c}:{lines:o,bytes:a.length,firstAt:n,lastAt:n,code:c},p=!1},"count");return{write(a){const f=typeof a=="string"?Buffer.from(a):Buffer.from(a.buffer,a.byteOffset,a.byteLength);if(f.length===0)return!0;if(r){const o=Buffer.from(`${p?"":`
|
|
5
|
+
`}${droppedNote(r,e.file)}`),c=d(o);if(c)return u(f,c),!1;r=void 0,p=!0}const n=d(f);return n?(u(f,n),!1):(p=f[f.length-1]===10,!0)},dropped:i(()=>r?{...r}:void 0,"dropped")}}l(createLogWriter,"createLogWriter"),i(createLogWriter,"createLogWriter");let activeTakeover;function gatewayLogTakeover(){return activeTakeover}l(gatewayLogTakeover,"gatewayLogTakeover"),i(gatewayLogTakeover,"gatewayLogTakeover");function takeOverGatewayLog(t={}){const e=t.file??readEnv(exports.GATEWAY_LOG_ENV);if(!e||!path.isAbsolute(e))return;const s=i(()=>{try{const n=fs.openSync(e,"a",384);try{fs.fchmodSync(n,384)}catch{}return n}catch{return}},"open");let r=s();if(r===void 0)return;const p=t.writeFd??((n,o)=>fs.writeSync(n,o)),d=createLogWriter(i(n=>{if(r===void 0&&(r=s()),r===void 0)throw Object.assign(new Error(`${e} cannot be opened`),{code:"ENOENT"});let o=n;for(;o.length>0;){const c=p(r,o);if(!(c>0))throw Object.assign(new Error("nothing was written"),{code:"EIO"});o=o.subarray(c)}},"append"),{...t.now?{now:t.now}:{},file:path.basename(e)}),u=t.streams??[process.stdout,process.stderr],a=u.map(n=>n.write);for(const n of u)n.write=((o,c,y)=>{const O=typeof c=="function"?c:typeof y=="function"?y:void 0,w=typeof o=="string"?Buffer.from(o,typeof c=="string"&&Buffer.isEncoding(c)?c:"utf8"):o instanceof Uint8Array?o:Buffer.from(String(o));return d.write(w),O&&process.nextTick(O),!0});const f={file:e,reopenIfMoved(){const n=statOr(()=>fs.statSync(e)),o=r===void 0?void 0:statOr(()=>fs.fstatSync(r));if(n&&sameFile(o,n))return!1;const c=s();if(c===void 0)return!1;const y=r;if(r=c,y!==void 0)try{fs.closeSync(y)}catch{}return!0},dropped:i(()=>d.dropped(),"dropped"),restore(){if(u.forEach((n,o)=>{n.write=a[o]}),r!==void 0)try{fs.closeSync(r)}catch{}r=void 0,activeTakeover===f&&(activeTakeover=void 0)}};return t.streams||(activeTakeover=f),f}l(takeOverGatewayLog,"takeOverGatewayLog"),i(takeOverGatewayLog,"takeOverGatewayLog");function linePrefixer(t){let e=!0;const s=`[${t}] `;return r=>{let p="";for(const d of r.split(/(?<=\n)/))d&&(p+=(e?s:"")+d,e=d.endsWith(`
|
|
6
|
+
`));return p}}l(linePrefixer,"linePrefixer"),i(linePrefixer,"linePrefixer");
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`)){const r
|
|
1
|
+
"use strict";var p=Object.defineProperty;var a=(o,e)=>p(o,"name",{value:e,configurable:!0});var c=Object.defineProperty,s=a((o,e)=>c(o,"name",{value:e,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.FOREIGN_POD_ENV_DENYLIST=exports.WORKSPACE_DOTENV_FILES=void 0,exports.parseDotenvKeys=parseDotenvKeys,exports.workspaceDotenvKeys=workspaceDotenvKeys,exports.scrubEnv=scrubEnv,exports.podBaseEnv=podBaseEnv;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path"));exports.WORKSPACE_DOTENV_FILES=[".env",".env.local",".local.env"],exports.FOREIGN_POD_ENV_DENYLIST=["PG_URL","REDIS_URL","DATABASE_URL","POSTGRES_URL"];function parseDotenvKeys(o){const e=new Set;for(const r of o.split(`
|
|
2
|
+
`)){const t=r.trim();if(!t||t.startsWith("#"))continue;const n=t.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/);n&&e.add(n[1])}return e}a(parseDotenvKeys,"parseDotenvKeys"),s(parseDotenvKeys,"parseDotenvKeys");function workspaceDotenvKeys(o){const e=new Set;for(const r of exports.WORKSPACE_DOTENV_FILES){let t;try{t=fs.readFileSync(path.join(o,r),"utf8")}catch{continue}for(const n of parseDotenvKeys(t))e.add(n)}return e}a(workspaceDotenvKeys,"workspaceDotenvKeys"),s(workspaceDotenvKeys,"workspaceDotenvKeys");function scrubEnv(o,e){const r={};for(const[t,n]of Object.entries(o))e.has(t)||exports.FOREIGN_POD_ENV_DENYLIST.includes(t)||(r[t]=n);return r}a(scrubEnv,"scrubEnv"),s(scrubEnv,"scrubEnv");function podBaseEnv(o,e,r){return path.resolve(r)===path.resolve(e)?o:scrubEnv(o,workspaceDotenvKeys(e))}a(podBaseEnv,"podBaseEnv"),s(podBaseEnv,"podBaseEnv");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var i=Object.defineProperty;var l=(s,e)=>i(s,"name",{value:e,configurable:!0});var d=Object.defineProperty,r=l((s,e)=>d(s,"name",{value:e,configurable:!0}),"r");Object.defineProperty(exports,"__esModule",{value:!0}),exports.PodFaults=void 0,exports.classifyPodLine=classifyPodLine;const ANSI_SGR=/\x1b\[[0-9;]*m/g,OPENS=[["build",/ERROR in |Module not found/],["types",/error TS\d+|Found [1-9]\d* errors?/],["process",/Unhandled 'error' event|EADDRINUSE/]],CLOSES=[["build",/compiled successfully/],["types",/No typescript errors found|Found 0 errors|\[tsgo\] .+: types clean/],["process",/Child#\d+ (ready|hot-swapped)/]];function classifyPodLine(s){const e=s.replace(ANSI_SGR,"").trim(),t=OPENS.find(([,o])=>o.test(e))?.[0],n=t?[]:CLOSES.filter(([,o])=>o.test(e)).map(([o])=>o);return{clean:e,broken:t!==void 0,healthy:n.length>0,...t?{fault:t}:{},closes:n}}l(classifyPodLine,"classifyPodLine"),r(classifyPodLine,"classifyPodLine");class PodFaults{static{l(this,"PodFaults")}static{r(this,"PodFaults")}constructor(){this.open=new Set}observe(e){if(e.fault){this.open.add(e.fault);return}const t=e.closes.filter(n=>this.open.delete(n));return t.length?{closed:t,open:[...this.open]}:void 0}}exports.PodFaults=PodFaults;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var f=Object.defineProperty;var p=(t,e)=>f(t,"name",{value:e,configurable:!0});var l=Object.defineProperty,u=p((t,e)=>l(t,"name",{value:e,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.parsePodWatcherTestimony=parsePodWatcherTestimony,exports.probePodAlive=probePodAlive,exports.probePodAliveVerdict=probePodAliveVerdict,exports.podConnectionVerdict=podConnectionVerdict,exports.podSocketAccepts=podSocketAccepts;const tslib_1=require("tslib"),http=tslib_1.__importStar(require("node:http")),net=tslib_1.__importStar(require("node:net")),types_1=require("./types");function parsePodWatcherTestimony(t){if(!t||typeof t!="object")return;const e=t;if(e.schemaVersion!==1)return;const i=u(n=>typeof n=="number"&&Number.isFinite(n)?n:0,"num"),c=e.degraded;return{schemaVersion:1,lastWatchRunAt:i(e.lastWatchRunAt),lastBuildAt:i(e.lastBuildAt),buildsSinceSpawn:i(e.buildsSinceSpawn),degraded:typeof c=="string"&&c?c:c===!0?"degraded":!1,recentPaths:Array.isArray(e.recentPaths)?e.recentPaths.filter(n=>typeof n=="string").slice(-32):[]}}p(parsePodWatcherTestimony,"parsePodWatcherTestimony"),u(parsePodWatcherTestimony,"parsePodWatcherTestimony");async function probePodAlive(t,e=types_1.POD_ALIVE_PROBE_TIMEOUT_MS,i){return(await probePodAliveVerdict(t,e,i)).alive}p(probePodAlive,"probePodAlive"),u(probePodAlive,"probePodAlive");function probePodAliveVerdict(t,e=types_1.POD_ALIVE_PROBE_TIMEOUT_MS,i){return new Promise(c=>{let n=!1,s="no-route";const d=u(o=>{n||(n=!0,c(o?{alive:o}:{failure:s}))},"finish");let a;try{a=http.request({socketPath:t,path:types_1.POD_ALIVE_PATH,method:"GET",timeout:e,agent:!1,...i?{headers:{"x-internal-token":i}}:{}},o=>{if(o.statusCode!==200){o.resume(),d(void 0);return}let E="";o.setEncoding("utf8"),o.on("data",r=>{E+=r}),o.on("end",()=>{try{const r=JSON.parse(E);d(r.ok===!0?{inflight:Number(r.inflight??0),activeWork:Number(r.activeWork??0),swapping:r.swapping===!0,...typeof r.pid=="number"?{pid:r.pid}:{},...typeof r.keyFingerprint=="string"?{keyFingerprint:r.keyFingerprint}:{},...(()=>{const P=parsePodWatcherTestimony(r.watcher);return P?{watcher:P}:{}})(),...typeof r.podGeneration=="number"&&Number.isFinite(r.podGeneration)?{podGeneration:r.podGeneration}:{}}:void 0)}catch{d(void 0)}})})}catch{s="gone",d(void 0);return}a.on("timeout",()=>{s="silent",a.destroy(),d(void 0)}),a.on("error",o=>{s!=="silent"&&(s=o.code==="ECONNREFUSED"||o.code==="ENOENT"||o.code==="ECONNRESET"||o.code==="EPIPE"?"gone":"silent"),d(void 0)}),a.end()})}p(probePodAliveVerdict,"probePodAliveVerdict"),u(probePodAliveVerdict,"probePodAliveVerdict");async function podConnectionVerdict(t,e,i=types_1.POD_ALIVE_PROBE_TIMEOUT_MS){const c=e.code??"";return c==="ECONNREFUSED"||c==="ENOENT"?"gone":await podSocketAccepts(t,i)?"alive":"gone"}p(podConnectionVerdict,"podConnectionVerdict"),u(podConnectionVerdict,"podConnectionVerdict");function podSocketAccepts(t,e=types_1.POD_ALIVE_PROBE_TIMEOUT_MS){return new Promise(i=>{let c=!1,n;const s=u(a=>{c||(c=!0,clearTimeout(d),n?.destroy(),i(a))},"finish"),d=setTimeout(()=>s(!1),e);d.unref?.();try{n=net.connect({path:t}),n.once("connect",()=>s(!0)),n.once("error",()=>s(!1))}catch{s(!1)}})}p(podSocketAccepts,"podSocketAccepts"),u(podSocketAccepts,"podSocketAccepts");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var l=Object.defineProperty;var c=(o,e)=>l(o,"name",{value:e,configurable:!0});var t=Object.defineProperty,n=c((o,e)=>t(o,"name",{value:e,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.gatewayProcessNames=gatewayProcessNames;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),process_name_1=require("../../../process-name"),protocol_1=require("../../../shared-build/protocol"),serve_launch_1=require("./serve-launch");function gatewayProcessNames(o,e){const s=[];for(const r of o){const a=r.wsKey||path.basename(r.root),p=r.decl.service??r.project;e.runner&&s.push((0,process_name_1.processName)(a,r.project,serve_launch_1.SERVE_RUNNER_ROLE)),s.push((0,process_name_1.processName)(a,r.project,"nx"),(0,process_name_1.processName)(a,p,"dev"),(0,process_name_1.processName)(a,p,"pod"))}return e.sharedBuild&&s.push((0,process_name_1.processName)(e.label,protocol_1.BUILD_HOST_ROLE)),e.lens?.dashboard&&s.push((0,process_name_1.processName)("lensmcp",e.lens.key,"dashboard")),e.lens?.mcp&&s.push((0,process_name_1.processName)("lensmcp",e.lens.key,"mcp")),[...new Set(s.filter(Boolean))]}c(gatewayProcessNames,"gatewayProcessNames"),n(gatewayProcessNames,"gatewayProcessNames");
|