@lensmcp/cluster 1.24.0 → 1.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ /** The parent `Module._load` should see: the stand-in when `parent` is an evaluation of a registered bundle. */
2
+ export declare function loadParentFor(parent: unknown): unknown;
3
+ /**
4
+ * Route every `require` made by an evaluation of the bundle at `file` through its stand-in parent. Call it before
5
+ * the bundle is evaluated; idempotent. Pass every spelling the bundle may be loaded under (the requested path and
6
+ * its realpath): a `Module`'s `filename` is the resolved one.
7
+ */
8
+ export declare function routeBundleRequires(...files: string[]): void;
@@ -0,0 +1 @@
1
+ "use strict";var l=Object.defineProperty;var o=(e,t)=>l(e,"name",{value:t,configurable:!0});var d=Object.defineProperty,n=o((e,t)=>d(e,"name",{value:t,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.loadParentFor=loadParentFor,exports.routeBundleRequires=routeBundleRequires;const tslib_1=require("tslib"),nodeModule=tslib_1.__importStar(require("node:module")),path=tslib_1.__importStar(require("node:path")),ModuleCtor=nodeModule.Module,standIns=new Map,isStandIn=new WeakSet;let wrapped=!1;function standInFor(e){const t=standIns.get(e);if(t)return t;const r=new ModuleCtor(e,null);return r.filename=e,r.paths=ModuleCtor._nodeModulePaths(path.dirname(e)),r.loaded=!0,standIns.set(e,r),isStandIn.add(r),r}o(standInFor,"standInFor"),n(standInFor,"standInFor");function loadParentFor(e){if(!e||typeof e!="object"||isStandIn.has(e))return e;const t=e.filename;return typeof t=="string"?standIns.get(t)??e:e}o(loadParentFor,"loadParentFor"),n(loadParentFor,"loadParentFor");function routeBundleRequires(...e){for(const r of e)standInFor(r);if(wrapped)return;wrapped=!0;const t=ModuleCtor._load;ModuleCtor._load=n(function(r,a,...u){return t.call(this,r,loadParentFor(a),...u)},"lensmcpBundleParent")}o(routeBundleRequires,"routeBundleRequires"),n(routeBundleRequires,"routeBundleRequires");
@@ -280,6 +280,8 @@ export interface ServiceLayer {
280
280
  startSweeper(): NodeJS.Timeout;
281
281
  /** Rolling recycle: standby generation first, retire the old once the new answers (issues/closed/dev-gateway-09). */
282
282
  rollPod(svc: ServiceCtl, reason: string): Promise<boolean>;
283
+ /** Self-heal a WEDGED service (live parent, 0 live pods): recycle it, within the crash-loop budget. */
284
+ recycleWedged(svc: ServiceCtl): void;
283
285
  /** Stop the build host of the workspace at `root` — one that unregistered — or, with no root, every build host
284
286
  * (shared-build.ts): after the service trees, at gateway stop. */
285
287
  stopBuildHost(root?: string): Promise<void>;
@@ -1,3 +1,3 @@
1
- "use strict";var Te=Object.defineProperty;var f=(t,n)=>Te(t,"name",{value:n,configurable:!0});var Re=Object.defineProperty,i=f((t,n)=>Re(t,"name",{value:n,configurable:!0}),"i");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.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"),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"),inspector_secret_1=require("../../../inspector-secret"),pod_output_1=require("./pod-output"),serve_launch_1=require("./serve-launch"),shared_build_1=require("./shared-build"),protocol_1=require("../../../shared-build/protocol"),types_1=require("./types"),exit_reason_1=require("../../../exit-reason"),process_name_1=require("../../../process-name");function eastWestEnv(t,n){const c={},a=t.serviceKeys[(0,service_keys_1.serviceKeyId)(n.wsKey,n.project)];if(a&&(c.LENSMCP_SERVICE_KEY=a),t.https){const h=require("../../../basic-ssl").caCertPath();fs.existsSync(h)&&(c.NODE_EXTRA_CA_CERTS=h)}return c}f(eastWestEnv,"eastWestEnv"),i(eastWestEnv,"eastWestEnv");const sleep=i(t=>new Promise(n=>setTimeout(n,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 n=2166136261;for(let c=0;c<t.length;c+=1)n^=t.charCodeAt(c),n=Math.imul(n,16777619);return n>>>0}f(fnv1a,"fnv1a"),i(fnv1a,"fnv1a");const execFileP=(0,node_util_1.promisify)(node_child_process_1.execFile);async function gitIgnoredPaths(t){try{const{stdout:n}=await execFileP("git",["ls-files","--others","--directory","--ignored","--exclude-standard","-z"],{cwd:t,maxBuffer:33554432,timeout:1e4,windowsHide:!0});return new Set(n.split("\0").filter(Boolean))}catch{return new Set}}f(gitIgnoredPaths,"gitIgnoredPaths"),i(gitIgnoredPaths,"gitIgnoredPaths");function scaleTarget(t,n=fs.existsSync){if(t.decl.adminUrl)return{url:t.decl.adminUrl};const c=path.join(t.pool.dir,"parent.sock");return n(c)?{socketPath:c}:t.decl.port?{url:`http://localhost:${t.decl.port}`}:void 0}f(scaleTarget,"scaleTarget"),i(scaleTarget,"scaleTarget");function isLoopbackHostname(t){const n=t.toLowerCase().replace(/^\[(.*)\]$/,"$1").replace(/\.$/,"");return n==="localhost"||n.endsWith(".localhost")?!0:net.isIPv4(n)?n.split(".")[0]==="127":net.isIPv6(n)&&new URL(`http://[${n}]/`).hostname==="[::1]"}f(isLoopbackHostname,"isLoopbackHostname"),i(isLoopbackHostname,"isLoopbackHostname");function postScale(t,n,c){let a;if("socketPath"in t)a=http.request({socketPath:t.socketPath,path:"/webpack/scale",method:"POST",headers:{"content-type":"application/json"}},h=>h.resume());else{const h=t.url.startsWith("https"),A=h?require("node:https"):http,g={method:"POST"};h&&isLoopbackHostname(new URL(t.url).hostname)&&(g.rejectUnauthorized=!1),c&&(g.lookup=c),a=A.request(`${t.url}/webpack/scale`,g,S=>S.resume())}return a.on("error",()=>{}),a.end(JSON.stringify({pods:n})),a}f(postScale,"postScale"),i(postScale,"postScale");function isOwnRunnerCommand(t,n){return(0,serve_launch_1.isServeRunnerCommand)(t)?(0,serve_launch_1.isServeRunnerCommandOf)(t,n):t.includes("/node_modules/nx/")?t.includes(`${n.replace(/\/+$/,"")}/node_modules/nx/`):!0}f(isOwnRunnerCommand,"isOwnRunnerCommand"),i(isOwnRunnerCommand,"isOwnRunnerCommand");function isRunnerOf(t,n,c){const a=n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return!new RegExp(`(^|\\s)run ${a}(:|\\s|$)`).test(t)||!(0,serve_launch_1.isServeRunnerCommand)(t)&&!/\bnx(\.js)?\b/.test(t)?!1:isOwnRunnerCommand(t,c)}f(isRunnerOf,"isRunnerOf"),i(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 n=t.split("/"),c=n[n.length-1]??"";if(TEST_FILE_RE.test(c))return!0;for(let a=0;a<n.length-1;a+=1)if(TEST_DIR_SEGMENTS.has(n[a]))return!0;return!1}f(isTestSourcePath,"isTestSourcePath"),i(isTestSourcePath,"isTestSourcePath");function sourceScanPass(t,n,c){const a=c?.ignoreTests??!0;let h;const A=new Map,g=`tree:${path.resolve(t)}`,S=i(u=>path.relative(t,u).split(path.sep).join("/"),"rel"),$=i(async(u,w)=>{const j=await(h??=gitIgnoredPaths(t)),P=[],I=new Set;let x=!1;const N=i(async(H,te)=>{if(P.length>=SCAN_FILE_CAP){x=!0;return}let oe;try{oe=await fs.promises.readdir(H,{withFileTypes:!0})}catch{return}te&&I.add(S(H));for(const z of oe){if(P.length>=SCAN_FILE_CAP){x=!0;return}const D=z.name,J=path.join(H,D);if(z.isDirectory()){if(!te||D.startsWith(".")||SRC_EXCLUDE.has(D)||n?.has(D)||D.endsWith("-devserver")||j.has(`${S(J)}/`))continue;await N(J,!0)}else if(z.isFile()){const re=D.lastIndexOf(".");if(re<=0||!SRC_EXT.has(D.slice(re)))continue;const b=S(J);if(j.has(b)||a&&isTestSourcePath(b))continue;P.push(b)}}},"walk");return await N(u,w),{paths:P,entered:I,truncated:x}},"walkDir"),O=i((u,w)=>{let j=A.get(u);return j||(j=w(),A.set(u,j)),j},"memo"),Y=i(async()=>{const u=A.get(g);if(!u)return;const w=await u;return w.truncated?void 0:w},"wideWalk"),q=new Set,V=i(()=>O(`files:${path.resolve(t)}`,async()=>{const u=await Y();return u?{paths:u.paths.filter(w=>!w.includes("/")),entered:q,truncated:!1}:$(t,!1)}),"rootFiles"),ne=i(u=>O(`tree:${path.resolve(u)}`,async()=>{const w=await Y(),j=S(u);if(w?.entered.has(j)){const P=`${j}/`;return{paths:j===""?w.paths:w.paths.filter(I=>I.startsWith(P)),entered:q,truncated:!1}}return $(u,!0)}),"subtree"),v=i(u=>{const w=new Set;let j=0,P=u.some(x=>x.truncated);const I=i(x=>w.has(x)?!0:w.size>=SCAN_FILE_CAP?(P=!0,!1):(w.add(x),j^=fnv1a(x),!0),"add");for(const x of u)if(!x.paths.every(I))break;return{signature:`${w.size}:${(j>>>0).toString(36)}`,paths:w,truncated:P}},"compose");return{async snapshot(u){if(!u||u.length===0)return v([await O(g,()=>$(t,!0))]);const w=[await V()];for(const j of u)w.push(await ne(j));return v(w)}}}f(sourceScanPass,"sourceScanPass"),i(sourceScanPass,"sourceScanPass");async function sourceSetSnapshot(t,n,c,a){return sourceScanPass(t,c,a).snapshot(n)}f(sourceSetSnapshot,"sourceSetSnapshot"),i(sourceSetSnapshot,"sourceSetSnapshot");async function sourceSetSignature(t,n,c,a){return(await sourceSetSnapshot(t,n,c,a)).signature}f(sourceSetSignature,"sourceSetSignature"),i(sourceSetSignature,"sourceSetSignature");const SOURCE_DIFF_PATH_CAP=128;function diffSourceSets(t,n,c,a){if(t.paths.size===n.paths.size){let S=!0;for(const $ of t.paths)if(!n.paths.has($)){S=!1;break}if(S)return null}const h=[],A=[];let g=t.truncated||n.truncated;for(const S of n.paths)t.paths.has(S)||(h.length+A.length<SOURCE_DIFF_PATH_CAP?h.push(S):g=!0);for(const S of t.paths)n.paths.has(S)||(h.length+A.length<SOURCE_DIFF_PATH_CAP?A.push(S):g=!0);return{changedAt:c,added:h,removed:A,truncated:g,...a!==void 0?{windowMs:a}:{}}}f(diffSourceSets,"diffSourceSets"),i(diffSourceSets,"diffSourceSets");function sourceChangeWindowMs(t,n,c,a){const h=n&&n>0?t-n:c;return Math.max(h,c)+a}f(sourceChangeWindowMs,"sourceChangeWindowMs"),i(sourceChangeWindowMs,"sourceChangeWindowMs");function sourceScopeDirs(t,n,c,a,h){const A=i($=>{const O=path.relative(t,$).split(path.sep).filter(Boolean);return O.length===0||O[0].startsWith("..")?"":O[0]},"bucketOf")(n);if(!A)return[];const g=new Set(c.filter(Boolean)),S=new Set([A]);for(const $ of a)$.startsWith(".")||SRC_EXCLUDE.has($)||h?.has($)||$.endsWith("-devserver")||g.has($)||S.add($);return[...S].sort().map($=>path.join(t,$))}f(sourceScopeDirs,"sourceScopeDirs"),i(sourceScopeDirs,"sourceScopeDirs");function podRecycleReason(t,n,c,a){return!t.proc||t.state!=="up"||t.spawnAt==null||t.inflight>0||(t.activeWork??0)>0||n-t.lastUsed<a.settleMs||t.lastStaleRecycleAt!=null&&n-t.lastStaleRecycleAt<a.cooldownMs?null:c>0&&c-t.spawnAt>a.graceMs?"stale-source-set":a.maxAgeMs>0&&n-t.spawnAt>a.maxAgeMs?"max-age":null}f(podRecycleReason,"podRecycleReason"),i(podRecycleReason,"podRecycleReason");function lensFrontendStale(t,n,c,a,h){return!(a-n<h.cooldownMs||c<=0||c-t<=h.graceMs||a-c<h.settleMs)}f(lensFrontendStale,"lensFrontendStale"),i(lensFrontendStale,"lensFrontendStale");function lensWatcherVerdict(t,n,c,a=[]){if(!t)return"unknown";if("schemaVersion"in t&&t.schemaVersion>=2&&a.length>0){const h=n-c,A=new Set(t.recentEvents.filter(g=>g.at>=h).map(g=>path.resolve(g.path)));return a.every(g=>A.has(path.resolve(g)))?"heard":"missed"}return t.lastFsSetEventAt>=n-c?"heard":"missed"}f(lensWatcherVerdict,"lensWatcherVerdict"),i(lensWatcherVerdict,"lensWatcherVerdict");function podWatcherVerdict(t,n,c){if(!t)return"unknown";if(t.degraded)return"degraded";const a=n-c;return t.lastWatchRunAt>=a||t.lastBuildAt>=a?"heard":"silent"}f(podWatcherVerdict,"podWatcherVerdict"),i(podWatcherVerdict,"podWatcherVerdict");function lensChildWedged(t,n,c,a){const h=t.hasListened?a.graceMs:Math.max(a.graceMs,a.neverListenedGraceMs);return c-t.spawnedAt<h||c-n<a.cooldownMs||t.probeFails<Math.max(2,a.failureThreshold)?null:"wedged-no-listener"}f(lensChildWedged,"lensChildWedged"),i(lensChildWedged,"lensChildWedged");function isPortConflictExit(t,n){return t.signal||t.code===null||t.code===0||t.ranMs>n.fastFailMs?!1:t.portHeld}f(isPortConflictExit,"isPortConflictExit"),i(isPortConflictExit,"isPortConflictExit");function createServiceLayer(t,n,c={}){const a=c.spawnProcess??node_child_process_1.spawn,h=c.probeAlive??pod_probe_1.probePodAlive,A=c.killTree??((e,o="SIGTERM")=>{try{process.kill(-e.pid,o)}catch{try{e.kill(o)}catch{}}}),g=c.sharedBuild??(0,shared_build_1.createSharedBuildRelay)(t),S=i((e,o="SIGTERM")=>{g.detach(e),A(e,o)},"killTree"),$=c.rollReadyMs??types_1.POD_ROLL_READY_MS,O=c.rollPollMs??750,Y=c.maxConcurrentRolls??types_1.POD_MAX_CONCURRENT_ROLLS,q=Y>0?Y:Number.POSITIVE_INFINITY,{emit:V}=n,ne=i(e=>e.wsKey===t.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl"),"serviceBus"),v=i((e,o,s,r,l)=>V(o,s,r,{wsKey:e.wsKey,...l},void 0,ne(e)),"emitSvc"),u=i(e=>(e.scannedAt=0,(0,discovery_1.pickSock)(e,t.scanTtlMs)?e.socks.length:0),"scanNow"),w=i((e,o)=>{let s;try{s=(0,node_child_process_1.execFileSync)("ps",["ax","-ww","-o","pid=,pgid=,command="],{encoding:"utf8",timeout:5e3})}catch{return 0}const r=e.proc?.pid;let l=0;for(const d of s.split(`
2
- `)){const p=d.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);if(!p)continue;const _=Number(p[1]),C=Number(p[2]);if(isRunnerOf(p[3],o,e.root)&&!(_===process.pid||_===r)&&!(r!==void 0&&C===r)){try{process.kill(-C,"SIGKILL")}catch{try{process.kill(_,"SIGKILL")}catch{}}l+=1}}return l>0&&(console.log(`[gateway] ${o}: reaped ${l} stale runner tree(s) \u2014 a foreign generation of this service (holding nx's task lock, or its pool)`),v(e,"warning",`stale-runner reap: ${e.project} (${l} foreign tree(s))`,`cluster-service:${e.project}`,{kind:"stale-runner-reap",project:e.project,reaped:l})),l},"reapForeignRunners"),j=i((e,o)=>({...(0,pod_env_1.podBaseEnv)(process.env,t.root,e.root),NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false",...e.wsKey?{LENSMCP_WS_KEY:e.wsKey}:{},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(o),...eastWestEnv(t,e)}),"serviceEnv"),P=i((e,o,s,r)=>{const l=j(e,o),d=e.wsKey||path.basename(e.root),p=(0,serve_launch_1.planServeLaunch)({stores:t.graphStores,root:e.root,project:e.project,target:e.decl.serveTarget??"serve-hmr",childCount:r,baseEnv:l});if(p.kind==="runner"){const m=g.offeredTo(e),R=a((0,process_name_1.namedExecPath)((0,process_name_1.processName)(d,e.project,serve_launch_1.SERVE_RUNNER_ROLE)),[...p.script.execArgv,p.script.path,...(0,serve_launch_1.serveRunnerArgs)(s,r,e.root)],{cwd:e.root,detached:!0,env:m?{...p.env,[protocol_1.SHARED_BUILD_ENV]:"1"}:p.env,stdio:["ignore","pipe","pipe","ipc"]});return m&&g.attach(e,o,R),R.send?.(p.message,k=>{k&&console.error(`[gateway] ${s}: could not hand the task to its runner (${k.message})`)}),{proc:R,launcher:"runner"}}console.log(`[gateway] ${s}: starting through nx run \u2014 ${p.reason}`);const _=path.join(e.root,"node_modules","nx","dist","bin","nx.js"),C=(0,process_name_1.namedExecPath)((0,process_name_1.processName)(d,e.project,"nx")),[W,E]=fs.existsSync(_)?[C,[_,"run",s,`--childCount=${r}`]]:["yarn",["nx","run",s,`--childCount=${r}`]];return{proc:a(W,E,{cwd:e.root,detached:!0,env:l,stdio:["ignore","pipe","pipe"]}),launcher:"nx"}},"startServiceTree"),I=new WeakMap,x=i((e,o,s)=>{const r=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,l=Math.max(1,e.decl.minPods??1),{proc:d,launcher:p}=P(e,o,r,l);I.set(d,p),s==="active"&&(e.launcher=p),s==="active"&&(e.lastErrors=[],e.buildFailed=!1,e.faults=new pod_output_1.PodFaults);const _=i(E=>{const m=E.toString();for(const R of m.split(`
3
- `)){const k=(0,pod_output_1.classifyPodLine)(R),{clean:L,broken:U,healthy:y}=k,F=L;if(U){e.lastErrors.push(L),e.lastErrors.length>12&&e.lastErrors.shift(),e.buildFailed=!0;const M=Date.now();(L!==e.lastErrorEmitSig||M-(e.lastErrorEmitAt??0)>=types_1.SERVICE_ERROR_THROTTLE_MS)&&(e.lastErrorEmitSig=L,e.lastErrorEmitAt=M,v(e,"error",`service error: ${e.project}`,`cluster-service:${e.project}`,{kind:"service-error",project:e.project,line:L,fault:k.fault}))}y&&(e.buildFailed=!1);const T=(e.faults??=new pod_output_1.PodFaults).observe(k);if(T){e.lastErrorEmitSig=void 0;const M=T.open.length===0;v(e,"info",`${M?"service recovered":`${T.closed.join(" + ")} recovered`}: ${e.project}`,`cluster-service:${e.project}`,{kind:M?"service-recovered":"service-fault-closed",project:e.project,line:L,closed:T.closed,open:T.open})}!e.lockBlockedAt&&/Waiting for .+ in another nx process/.test(F)&&(e.lockBlockedAt=Date.now(),console.log(`[gateway] ${r}: spawn blocked by a stale nx runner \u2014 breaking the lock + respawning`),v(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||(b(e,"parked on a foreign nx task lock \u2014 recycling",{announce:!1}),w(e,r),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&N(e)},1500).unref?.())},250).unref?.())}},"sniff"),C=e.wsKey&&e.wsKey!==t.wsKey&&e.root?(0,workspace_log_1.workspaceLogWriter)(e.root):void 0,W=i(E=>m=>{if(t.stopped())return;const R=(0,inspector_secret_1.redactInspectorUrls)(m.toString());_(R);const k=`[${e.project}] ${R}`;E.write(k),C?.(k)},"relay");return d.stdout?.on("data",W(process.stdout)),d.stderr?.on("data",W(process.stderr)),d.on("exit",(E,m)=>{if(e.proc!==d||(e.proc=void 0,e.state="down",t.stopped()))return;const R=(0,exit_reason_1.describeExit)(E,m);if(console.log(`[gateway] ${r} exited (${E??"no code"}${m?`, ${m}`:""}${e.inflight?`, ${e.inflight} request(s) in flight`:""})${R?` \u2014 ${R}`:""}`),v(e,E===0?"info":"warning",`service down: ${e.project} (exit ${E})`,`cluster-service:${e.project}`,{kind:"service-down",project:e.project,code:E,...m?{signal:m}:{}}),E===0||e.buildFailed)return;const k=Date.now();if(e.restarts=(e.restarts??[]).filter(U=>k-U<types_1.SERVICE_RESTART_WINDOW_MS),e.restarts.length>=types_1.SERVICE_MAX_RESTARTS){v(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(k);const L=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})`),v(e,"info",`self-heal: respawning ${e.project}`,`cluster-service:${e.project}`,{kind:"service-respawn",project:e.project,attempt:e.restarts.length}),N(e))},L)}),d},"launchServiceProcess"),N=i(e=>{if(t.stopped())return;const o=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,s=Math.max(1,e.decl.minPods??1);c.reapForeign!==!1&&w(e,o),e.lockBlockedAt=void 0,console.log(`[gateway] starting ${o} (pods=${s})\u2026`),v(e,"info",`service starting: ${e.project} (${s} pod${s>1?"s":""})`,`cluster-service:${e.project}`,{kind:"service-starting",project:e.project,pods:s}),e.state="starting",e.spawnAt=Date.now(),e.generation=(e.generation??0)+1,e.proc=x(e,e.generation,"active")},"spawnService"),H=i(async e=>{const o=e.pool.socks[0];if(!o)return;const s=await(0,pod_probe_1.probePodAlive)(o,void 0,t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)]);s&&(e.activeWork=s.activeWork,s.watcher&&(e.watcher=s.watcher))},"refreshActiveWork"),te=i(e=>{try{const o=Number(fs.readFileSync(`${e}.owner`,"utf8").trim());return Number.isInteger(o)&&o>1?o:void 0}catch{return}},"readOwnerSidecar"),oe=i(async e=>{const o=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)];if(!o)return[];const s=(0,node_crypto_1.createHash)("sha256").update(o).digest("hex").slice(0,8),r=[];for(const l of e.pool.socks){const d=await(0,pod_probe_1.probePodAlive)(l,void 0,o);d&&(!d.keyFingerprint||d.keyFingerprint!==s)&&r.push({sock:l,pid:d.pid})}return r},"staleAdoptedSocks"),z=i((e,o)=>{const s=o.map(r=>r.sock);for(const{sock:r,pid:l}of o){const d=chooseStalePodKillTarget(l,te(r),process.pid);if(d!==void 0)try{process.kill(d,"SIGTERM")}catch{}try{fs.unlinkSync(r)}catch{}try{fs.unlinkSync(`${r}.owner`)}catch{}}e.pool.socks=e.pool.socks.filter(r=>!s.includes(r)),e.pool.idx=-1,e.pool.scannedAt=0},"evictStaleAdopted"),D=i((e,o)=>{if(e.state==="up")return!1;e.state="up";const s=e.pool.socks.length;return v(e,"info",`service up: ${e.project} (${s} pods, ${o})`,`cluster-service:${e.project}`,{kind:"service-up",project:e.project,pods:s,adopted:o==="adopted"}),!0},"markUp"),J=i(async e=>{if(u(e.pool)>0){const r=await oe(e);if(r.length>0&&(console.error(`[gateway] ${e.project}: ${r.length} adopted pod(s) hold a foreign east-west key \u2014 evicting instead of adopting.`),v(e,"warning",`stale adoption: ${e.project} (foreign east-west key)`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:"stale-adoption",pods:r.length}),e.proc&&b(e,"stale adoption (foreign east-west key)"),z(e,r)),e.pool.socks.length>0)return D(e,"adopted"),!0}if(t.stopped())return!1;e.state!=="starting"&&!e.proc&&N(e);const o=Date.now()+t.startupTimeoutMs,s=Date.now()+12e3;for(;!t.stopped()&&Date.now()<o;){if(await sleep(Math.min(700,t.startupTimeoutMs/4)),e.buildFailed&&Date.now()>s)return!1;if(u(e.pool)>0){e.state="up",e.buildFailed=!1;const r=e.spawnAt?Date.now()-e.spawnAt:void 0;return console.log(`[gateway] ${e.project} up (${e.pool.socks.length} pods${r?`, cold start ${r}ms`:""})`),v(e,"info",`cold start: ${e.project} (${e.pool.socks.length} pods, ${r??"?"}ms)`,`cluster-service:${e.project}`,{kind:"cold-start",project:e.project,pods:e.pool.socks.length,durationMs:r}),!0}if(e.state==="down")return!1}return!1},"ensureUp"),re=i(e=>{const o=e.decl.maxPods??e.decl.minPods??1,s=e.pool.socks.length,r=scaleTarget(e);!r||s===0||s>=o||e.inflight<=s||Date.now()-e.lastScaleAt<5e3||(e.lastScaleAt=Date.now(),postScale(r,s+1,c.scaleLookup),console.log(`[gateway] autoscale ${e.project}: ${s} \u2192 ${s+1} pods (inflight ${e.inflight})`),v(e,"info",`autoscale: ${e.project} ${s} \u2192 ${s+1} pods`,`cluster-service:${e.project}`,{kind:"autoscale",project:e.project,from:s,to:s+1,inflight:e.inflight}))},"scaleUp"),b=i((e,o,s)=>{if(!e.proc)return;console.log(`[gateway] ${e.project} ${o} \u2014 scaling to zero.`),s?.announce!==!1&&v(e,"info",`idle kill: ${e.project} (${o})`,`cluster-service:${e.project}`,{kind:"idle-kill",project:e.project,why:o});const r=e.proc;try{r.stdout?.removeAllListeners("data"),r.stderr?.removeAllListeners("data"),r.removeAllListeners("exit")}catch{}S(r,"SIGTERM"),e.proc=void 0,e.state="down",setTimeout(()=>{ce(e),e.pool.socks=[],e.pool.scannedAt=0},1200).unref?.()},"killSpawned"),ce=i(e=>{try{for(const o of fs.readdirSync(e.pool.dir)){if(!o.endsWith(".sock"))continue;const s=path.join(e.pool.dir,o);try{const r=Number(fs.readFileSync(`${s}.owner`,"utf8").trim());if(Number.isFinite(r)&&r>0)try{process.kill(r,0);continue}catch{}}catch{}try{fs.unlinkSync(s)}catch{}try{fs.unlinkSync(`${s}.owner`)}catch{}}}catch{}},"sweepDeadOwnerSocks");let G=0;const ae=[],ge=i(()=>G<q?(G+=1,Promise.resolve()):new Promise(e=>{ae.push(()=>{G+=1,e()})}),"acquireRollSlot"),we=i(()=>{G-=1,ae.shift()?.()},"releaseRollSlot"),ue=i((e,o)=>{if(e.rolling)return e.rolling;const s=e.proc;if(!s||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);G>=q&&console.log(`[gateway] pod handoff queued: ${e.project} reason=${o} \u2014 ${G} roll(s) in flight, ${ae.length} ahead (LENSMCP_POD_MAX_CONCURRENT_ROLLS=${q}).`);const r=(async()=>{await ge();try{return await Se(e,s,o)}finally{we()}})().finally(()=>{e.rolling=void 0});return e.rolling=r,r},"rollPod"),Se=i(async(e,o,s)=>{const r=e.proc;if(r!==o||t.stopped())return!1;const l=e.generation??0,d=l+1,p=Date.now();e.lastStaleRecycleAt=p,console.log(`[gateway] pod handoff start: ${e.project} g${l}\u2192g${d} reason=${s} \u2014 standby spawning, old generation keeps serving.`),v(e,"info",`pod handoff starting: ${e.project} (${s})`,`cluster-service:${e.project}`,{kind:"pod-handoff-start",project:e.project,reason:s,generation:d,fromGeneration:l});const _=x(e,d,"standby"),C=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],W=p+$;let E;for(;!t.stopped()&&Date.now()<W&&!(_.exitCode!==null||_.signalCode!==null);){u(e.pool);for(const m of e.pool.socks)if((await h(m,void 0,C))?.podGeneration===d){E=m;break}if(E)break;await sleep(O)}if(!E||t.stopped()){const m=t.stopped()?"gateway stopping":_.exitCode!==null||_.signalCode!==null?`standby exited (${_.exitCode??_.signalCode})`:`standby not ready within ${Math.round($/1e3)}s`;try{_.stdout?.removeAllListeners("data"),_.stderr?.removeAllListeners("data")}catch{}return S(_,"SIGTERM"),console.error(`[gateway] pod handoff failed: ${e.project} g${d}: ${m} \u2014 old generation g${l} kept serving.`),v(e,"warning",`pod handoff failed: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-failed",project:e.project,reason:s,generation:d,error:m,durationMs:Date.now()-p}),setTimeout(()=>ce(e),1200).unref?.(),!1}if(e.proc!==r)return S(_,"SIGTERM"),!1;e.proc=_,e.launcher=I.get(_),e.generation=d,e.spawnAt=p,e.state="up",e.watcher=void 0,e.staleVerifiedAt=void 0,e.staleKeptAt=void 0,e.buildFailed=!1,e.lastErrors=[];try{r.stdout?.removeAllListeners("data"),r.stderr?.removeAllListeners("data"),r.removeAllListeners("exit")}catch{}return S(r,"SIGTERM"),setTimeout(()=>{ce(e),e.pool.scannedAt=0},1200).unref?.(),console.log(`[gateway] pod handoff ready: ${e.project} g${d} answered on ${path.basename(E)} in ${Date.now()-p}ms; retiring g${l}.`),v(e,"info",`pod handoff complete: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-complete",project:e.project,reason:s,generation:d,fromGeneration:l,durationMs:Date.now()-p}),!0},"runRoll"),ve=i(e=>{const o=Date.now();if(e.restarts=(e.restarts??[]).filter(s=>o-s<types_1.SERVICE_RESTART_WINDOW_MS),e.restarts.length>=types_1.SERVICE_MAX_RESTARTS){v(e,"error",`service crash-looping: ${e.project} \u2014 wedged ${types_1.SERVICE_MAX_RESTARTS}+\xD7/min, not auto-recycling (the next request retries)`,`cluster-service:${e.project}`,{kind:"service-crash-loop",project:e.project}),b(e,"wedged (crash-loop cap) \u2014 leaving down for the next request",{announce:!1});return}e.restarts.push(o),console.log(`[gateway] self-heal: recycling WEDGED ${e.project} (live parent, 0 live pods; ${e.restarts.length}/${types_1.SERVICE_MAX_RESTARTS}; ${e.inflight??0} request(s) in flight \u2014 jobs held by the dead pod keep their locks until they expire)`),v(e,"warning",`self-heal: recycling wedged ${e.project} (0 live pods)`,`cluster-service:${e.project}`,{kind:"service-recycle",project:e.project,attempt:e.restarts.length}),b(e,"wedged: 0 live pods \u2014 recycling",{announce:!1}),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&N(e)},1500).unref?.()},"recycleWedged"),_e={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 ie;const Q=new Map,he=new Map;let le=!1,de=0,se=0;const ye=i(()=>{const e=t.projectRoots??{},o=new Set(t.services.map(r=>r.project));for(const r of t.routes)r.lens&&o.add(r.lens.project);const s=new Set;for(const r of o){const l=e[r];if(!l)continue;const d=path.relative(t.root,l).split(path.sep).filter(Boolean)[0];d&&!d.startsWith("..")&&s.add(d)}return[...s]},"managedBuckets"),me=i((e,o,s,r)=>{const l=t.projectSourceRoots?.[e];if(l?.length)return l;const d=t.projectRoots?.[e];if(!d)return;const p=sourceScopeDirs(t.root,d,s,o,r);return p.length>0?p:void 0},"scopeFor"),$e=i(()=>{if(le||Date.now()-de<types_1.POD_STALE_SCAN_MS)return;le=!0,de=Date.now();const e=de;(async()=>{const o=(0,scope_1.readSourceSetOptions)(t.root),s=o.exclude,r={ignoreTests:o.ignoreTests},l=sourceScanPass(t.root,s,r),d=await l.snapshot(),p=Date.now(),_=sourceChangeWindowMs(p,se,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS),C=ie?diffSourceSets(ie,d,p,_):null;if(C&&(t.sourceSetChangedAt=p,t.sourceSetChange=C,V("info","source file set changed \u2014 stale pods recycle when idle","cluster-gateway",{kind:"source-set-changed",added:C.added,removed:C.removed,truncated:C.truncated})),ie=d,!t.projectRoots){se=e;return}let W;try{W=(await fs.promises.readdir(t.root,{withFileTypes:!0})).filter(y=>y.isDirectory()).map(y=>y.name)}catch{return}const E=ye(),m=new Set(t.services.map(y=>y.project));for(const y of t.routes)y.lens&&m.add(y.lens.project);const R=new Map;for(const y of m){const F=me(y,W,E,s);if(!F)continue;const T=F.join("|"),M=R.get(T)??{dirs:F,projects:[]};M.projects.push(y),R.set(T,M)}const k=Date.now(),L=sourceChangeWindowMs(k,se,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS);se=e;const U=i((y,F,T)=>{t.sourceSetChangedFor??=new Map,t.sourceSetChangesFor??=new Map;for(const M of y)t.sourceSetChangedFor.set(M,F),t.sourceSetChangesFor.set(M,T)},"stampScoped");for(const[y,{dirs:F,projects:T}]of R){const M=await l.snapshot(F),fe=Q.get(y);Q.set(y,M);const pe=new Map;for(const B of T){const K=he.get(B);if(K===void 0||K===y)continue;const X=pe.get(K)??[];X.push(B),pe.set(K,X)}for(const B of T)he.set(B,y);for(const[B,K]of pe){const X=Q.get(B),ee=X?diffSourceSets(X,M,k,L):C;ee&&(U(K,X?k:p,ee),V("info",`source file set changed \u2014 ${K.join(", ")}'s watch scope was re-keyed`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,rescoped:!0,projects:K,added:ee.added,removed:ee.removed,truncated:ee.truncated}))}if(!fe)continue;const Z=diffSourceSets(fe,M,k,L);Z&&(U(T,k,Z),V("info",`source file set changed in ${T.join(", ")}'s scope`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,projects:T,added:Z.added,removed:Z.removed,truncated:Z.truncated}))}for(const y of[...Q.keys()])R.has(y)||Q.delete(y)})().catch(()=>{}).finally(()=>{le=!1})},"maybeScanSourceSet"),Ee=i((e,o)=>{const s=(t.sourceSetChangesFor?.get(e.project)??t.sourceSetChange)?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,r=podWatcherVerdict(e.watcher,o,s),l=i(d=>(e.staleKeptAt!==o&&(e.staleKeptAt=o,console.log(`[gateway] stale source set: pod ${e.project} ${d} \u2014 no recycle.`)),!1),"keep");return r==="heard"?(e.staleVerifiedAt=o,v(e,"info",`stale check: ${e.project} watcher confirmed \u2014 no recycle`,`cluster-service:${e.project}`,{kind:"pod-stale-verified",project:e.project,watcher:r}),l(`watcher CONFIRMED alive across the change (last build ${new Date(e.watcher?.lastBuildAt??0).toISOString()})`)):r==="degraded"?(console.log(`[gateway] stale source set: pod ${e.project} watcher DEGRADED (${e.watcher?.degraded}) \u2014 recycling.`),!0):r==="silent"?types_1.POD_WATCHER_SILENT==="keep"?l("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)"):!0:types_1.POD_WATCHER_UNVERIFIED==="keep"?l("unverifiable (no watcher testimony \u2014 older devserver bundle?) \u2014 keeping it (LENSMCP_POD_WATCHER_UNVERIFIED=keep)"):!0},"podStaleRecycleAllowed"),je=i((e,o)=>{if(e.lastStaleRecycleAt=Date.now(),types_1.POD_RECYCLE_MODE==="rolling"&&e.proc&&e.launcher!=="nx"){ue(e,o);return}console.log(`[gateway] zombie recycle: ${e.project} (${o}) \u2014 stale fs view; fresh pod incoming`),v(e,"warning",`zombie recycle: ${e.project} (${o})`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:o});const s=!!e.decl.eager;b(e,`${o} \u2014 recycling stale pod`,{announce:!1}),s&&setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&N(e)},1500).unref?.()},"recyclePod"),ke=i(()=>{const e=setInterval(()=>{Ae().catch(o=>console.error("[gateway] sweep error:",o))},t.sweepMs);return e.unref(),e},"startSweeper"),Ae=i(async()=>{{if(t.stopped())return;for(const e of t.graphStores?.all()??[])e.refreshIfStale();types_1.POD_RECYCLE_ENABLED&&$e();for(const e of t.services){if(t.stopped()||!e.proc){e.wedgedSince=void 0;continue}const o=e.decl.idleKillSec;if(o&&e.inflight===0&&Date.now()-e.lastUsed>o*1e3){b(e,`idle ${o}s`),e.wedgedSince=void 0;continue}const s=e.state==="starting"&&e.spawnAt!==void 0&&Date.now()-e.spawnAt<t.startupTimeoutMs,r=u(e.pool)>0;if(r||s){if(e.wedgedSince=void 0,r&&D(e,"observed"),r&&!s&&types_1.POD_RECYCLE_ENABLED){const l=t.sourceSetChangedFor?.get(e.project)??t.sourceSetChangedAt??0;await H(e);const d=(e.staleVerifiedAt??0)>=l&&l>0,p=podRecycleReason(e,Date.now(),d?0:l,_e);if(p==="stale-source-set"&&!Ee(e,l))continue;p&&je(e,p)}continue}e.wedgedSince??=Date.now(),Date.now()-e.wedgedSince>types_1.WEDGE_RECYCLE_GRACE_MS&&(e.wedgedSince=void 0,ve(e))}}},"sweepOnce");return{scanNow:u,spawnService:N,ensureUp:J,scaleUp:re,killSpawned:b,markUp:D,startSweeper:ke,rollPod:ue,stopBuildHost:i(e=>e===void 0?g.stop():g.release(e),"stopBuildHost")}}f(createServiceLayer,"createServiceLayer"),i(createServiceLayer,"createServiceLayer");function chooseStalePodKillTarget(t,n,c){if(!(t===void 0||!Number.isInteger(t)||t<=1)&&!(n!==void 0&&n!==t)&&t!==c)return t}f(chooseStalePodKillTarget,"chooseStalePodKillTarget"),i(chooseStalePodKillTarget,"chooseStalePodKillTarget");
1
+ "use strict";var Te=Object.defineProperty;var f=(t,n)=>Te(t,"name",{value:n,configurable:!0});var Ce=Object.defineProperty,i=f((t,n)=>Ce(t,"name",{value:n,configurable:!0}),"i");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.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"),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"),inspector_secret_1=require("../../../inspector-secret"),pod_output_1=require("./pod-output"),serve_launch_1=require("./serve-launch"),shared_build_1=require("./shared-build"),protocol_1=require("../../../shared-build/protocol"),types_1=require("./types"),exit_reason_1=require("../../../exit-reason"),process_name_1=require("../../../process-name");function eastWestEnv(t,n){const c={},a=t.serviceKeys[(0,service_keys_1.serviceKeyId)(n.wsKey,n.project)];if(a&&(c.LENSMCP_SERVICE_KEY=a),t.https){const h=require("../../../basic-ssl").caCertPath();fs.existsSync(h)&&(c.NODE_EXTRA_CA_CERTS=h)}return c}f(eastWestEnv,"eastWestEnv"),i(eastWestEnv,"eastWestEnv");const sleep=i(t=>new Promise(n=>setTimeout(n,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 n=2166136261;for(let c=0;c<t.length;c+=1)n^=t.charCodeAt(c),n=Math.imul(n,16777619);return n>>>0}f(fnv1a,"fnv1a"),i(fnv1a,"fnv1a");const execFileP=(0,node_util_1.promisify)(node_child_process_1.execFile);async function gitIgnoredPaths(t){try{const{stdout:n}=await execFileP("git",["ls-files","--others","--directory","--ignored","--exclude-standard","-z"],{cwd:t,maxBuffer:33554432,timeout:1e4,windowsHide:!0});return new Set(n.split("\0").filter(Boolean))}catch{return new Set}}f(gitIgnoredPaths,"gitIgnoredPaths"),i(gitIgnoredPaths,"gitIgnoredPaths");function scaleTarget(t,n=fs.existsSync){if(t.decl.adminUrl)return{url:t.decl.adminUrl};const c=path.join(t.pool.dir,"parent.sock");return n(c)?{socketPath:c}:t.decl.port?{url:`http://localhost:${t.decl.port}`}:void 0}f(scaleTarget,"scaleTarget"),i(scaleTarget,"scaleTarget");function isLoopbackHostname(t){const n=t.toLowerCase().replace(/^\[(.*)\]$/,"$1").replace(/\.$/,"");return n==="localhost"||n.endsWith(".localhost")?!0:net.isIPv4(n)?n.split(".")[0]==="127":net.isIPv6(n)&&new URL(`http://[${n}]/`).hostname==="[::1]"}f(isLoopbackHostname,"isLoopbackHostname"),i(isLoopbackHostname,"isLoopbackHostname");function postScale(t,n,c){let a;if("socketPath"in t)a=http.request({socketPath:t.socketPath,path:"/webpack/scale",method:"POST",headers:{"content-type":"application/json"}},h=>h.resume());else{const h=t.url.startsWith("https"),A=h?require("node:https"):http,g={method:"POST"};h&&isLoopbackHostname(new URL(t.url).hostname)&&(g.rejectUnauthorized=!1),c&&(g.lookup=c),a=A.request(`${t.url}/webpack/scale`,g,S=>S.resume())}return a.on("error",()=>{}),a.end(JSON.stringify({pods:n})),a}f(postScale,"postScale"),i(postScale,"postScale");function isOwnRunnerCommand(t,n){return(0,serve_launch_1.isServeRunnerCommand)(t)?(0,serve_launch_1.isServeRunnerCommandOf)(t,n):t.includes("/node_modules/nx/")?t.includes(`${n.replace(/\/+$/,"")}/node_modules/nx/`):!0}f(isOwnRunnerCommand,"isOwnRunnerCommand"),i(isOwnRunnerCommand,"isOwnRunnerCommand");function isRunnerOf(t,n,c){const a=n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return!new RegExp(`(^|\\s)run ${a}(:|\\s|$)`).test(t)||!(0,serve_launch_1.isServeRunnerCommand)(t)&&!/\bnx(\.js)?\b/.test(t)?!1:isOwnRunnerCommand(t,c)}f(isRunnerOf,"isRunnerOf"),i(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 n=t.split("/"),c=n[n.length-1]??"";if(TEST_FILE_RE.test(c))return!0;for(let a=0;a<n.length-1;a+=1)if(TEST_DIR_SEGMENTS.has(n[a]))return!0;return!1}f(isTestSourcePath,"isTestSourcePath"),i(isTestSourcePath,"isTestSourcePath");function sourceScanPass(t,n,c){const a=c?.ignoreTests??!0;let h;const A=new Map,g=`tree:${path.resolve(t)}`,S=i(u=>path.relative(t,u).split(path.sep).join("/"),"rel"),j=i(async(u,w)=>{const R=await(h??=gitIgnoredPaths(t)),D=[],I=new Set;let x=!1;const N=i(async(H,te)=>{if(D.length>=SCAN_FILE_CAP){x=!0;return}let oe;try{oe=await fs.promises.readdir(H,{withFileTypes:!0})}catch{return}te&&I.add(S(H));for(const z of oe){if(D.length>=SCAN_FILE_CAP){x=!0;return}const b=z.name,J=path.join(H,b);if(z.isDirectory()){if(!te||b.startsWith(".")||SRC_EXCLUDE.has(b)||n?.has(b)||b.endsWith("-devserver")||R.has(`${S(J)}/`))continue;await N(J,!0)}else if(z.isFile()){const re=b.lastIndexOf(".");if(re<=0||!SRC_EXT.has(b.slice(re)))continue;const L=S(J);if(R.has(L)||a&&isTestSourcePath(L))continue;D.push(L)}}},"walk");return await N(u,w),{paths:D,entered:I,truncated:x}},"walkDir"),O=i((u,w)=>{let R=A.get(u);return R||(R=w(),A.set(u,R)),R},"memo"),Y=i(async()=>{const u=A.get(g);if(!u)return;const w=await u;return w.truncated?void 0:w},"wideWalk"),q=new Set,V=i(()=>O(`files:${path.resolve(t)}`,async()=>{const u=await Y();return u?{paths:u.paths.filter(w=>!w.includes("/")),entered:q,truncated:!1}:j(t,!1)}),"rootFiles"),ne=i(u=>O(`tree:${path.resolve(u)}`,async()=>{const w=await Y(),R=S(u);if(w?.entered.has(R)){const D=`${R}/`;return{paths:R===""?w.paths:w.paths.filter(I=>I.startsWith(D)),entered:q,truncated:!1}}return j(u,!0)}),"subtree"),v=i(u=>{const w=new Set;let R=0,D=u.some(x=>x.truncated);const I=i(x=>w.has(x)?!0:w.size>=SCAN_FILE_CAP?(D=!0,!1):(w.add(x),R^=fnv1a(x),!0),"add");for(const x of u)if(!x.paths.every(I))break;return{signature:`${w.size}:${(R>>>0).toString(36)}`,paths:w,truncated:D}},"compose");return{async snapshot(u){if(!u||u.length===0)return v([await O(g,()=>j(t,!0))]);const w=[await V()];for(const R of u)w.push(await ne(R));return v(w)}}}f(sourceScanPass,"sourceScanPass"),i(sourceScanPass,"sourceScanPass");async function sourceSetSnapshot(t,n,c,a){return sourceScanPass(t,c,a).snapshot(n)}f(sourceSetSnapshot,"sourceSetSnapshot"),i(sourceSetSnapshot,"sourceSetSnapshot");async function sourceSetSignature(t,n,c,a){return(await sourceSetSnapshot(t,n,c,a)).signature}f(sourceSetSignature,"sourceSetSignature"),i(sourceSetSignature,"sourceSetSignature");const SOURCE_DIFF_PATH_CAP=128;function diffSourceSets(t,n,c,a){if(t.paths.size===n.paths.size){let S=!0;for(const j of t.paths)if(!n.paths.has(j)){S=!1;break}if(S)return null}const h=[],A=[];let g=t.truncated||n.truncated;for(const S of n.paths)t.paths.has(S)||(h.length+A.length<SOURCE_DIFF_PATH_CAP?h.push(S):g=!0);for(const S of t.paths)n.paths.has(S)||(h.length+A.length<SOURCE_DIFF_PATH_CAP?A.push(S):g=!0);return{changedAt:c,added:h,removed:A,truncated:g,...a!==void 0?{windowMs:a}:{}}}f(diffSourceSets,"diffSourceSets"),i(diffSourceSets,"diffSourceSets");function sourceChangeWindowMs(t,n,c,a){const h=n&&n>0?t-n:c;return Math.max(h,c)+a}f(sourceChangeWindowMs,"sourceChangeWindowMs"),i(sourceChangeWindowMs,"sourceChangeWindowMs");function sourceScopeDirs(t,n,c,a,h){const A=i(j=>{const O=path.relative(t,j).split(path.sep).filter(Boolean);return O.length===0||O[0].startsWith("..")?"":O[0]},"bucketOf")(n);if(!A)return[];const g=new Set(c.filter(Boolean)),S=new Set([A]);for(const j of a)j.startsWith(".")||SRC_EXCLUDE.has(j)||h?.has(j)||j.endsWith("-devserver")||g.has(j)||S.add(j);return[...S].sort().map(j=>path.join(t,j))}f(sourceScopeDirs,"sourceScopeDirs"),i(sourceScopeDirs,"sourceScopeDirs");function podRecycleReason(t,n,c,a){return!t.proc||t.state!=="up"||t.spawnAt==null||t.inflight>0||(t.activeWork??0)>0||n-t.lastUsed<a.settleMs||t.lastStaleRecycleAt!=null&&n-t.lastStaleRecycleAt<a.cooldownMs?null:c>0&&c-t.spawnAt>a.graceMs?"stale-source-set":a.maxAgeMs>0&&n-t.spawnAt>a.maxAgeMs?"max-age":null}f(podRecycleReason,"podRecycleReason"),i(podRecycleReason,"podRecycleReason");function lensFrontendStale(t,n,c,a,h){return!(a-n<h.cooldownMs||c<=0||c-t<=h.graceMs||a-c<h.settleMs)}f(lensFrontendStale,"lensFrontendStale"),i(lensFrontendStale,"lensFrontendStale");function lensWatcherVerdict(t,n,c,a=[]){if(!t)return"unknown";if("schemaVersion"in t&&t.schemaVersion>=2&&a.length>0){const h=n-c,A=new Set(t.recentEvents.filter(g=>g.at>=h).map(g=>path.resolve(g.path)));return a.every(g=>A.has(path.resolve(g)))?"heard":"missed"}return t.lastFsSetEventAt>=n-c?"heard":"missed"}f(lensWatcherVerdict,"lensWatcherVerdict"),i(lensWatcherVerdict,"lensWatcherVerdict");function podWatcherVerdict(t,n,c){if(!t)return"unknown";if(t.degraded)return"degraded";const a=n-c;return t.lastWatchRunAt>=a||t.lastBuildAt>=a?"heard":"silent"}f(podWatcherVerdict,"podWatcherVerdict"),i(podWatcherVerdict,"podWatcherVerdict");function lensChildWedged(t,n,c,a){const h=t.hasListened?a.graceMs:Math.max(a.graceMs,a.neverListenedGraceMs);return c-t.spawnedAt<h||c-n<a.cooldownMs||t.probeFails<Math.max(2,a.failureThreshold)?null:"wedged-no-listener"}f(lensChildWedged,"lensChildWedged"),i(lensChildWedged,"lensChildWedged");function isPortConflictExit(t,n){return t.signal||t.code===null||t.code===0||t.ranMs>n.fastFailMs?!1:t.portHeld}f(isPortConflictExit,"isPortConflictExit"),i(isPortConflictExit,"isPortConflictExit");function createServiceLayer(t,n,c={}){const a=c.spawnProcess??node_child_process_1.spawn,h=c.probeAlive??pod_probe_1.probePodAlive,A=c.killTree??((e,r="SIGTERM")=>{try{process.kill(-e.pid,r)}catch{try{e.kill(r)}catch{}}}),g=c.sharedBuild??(0,shared_build_1.createSharedBuildRelay)(t),S=i((e,r="SIGTERM")=>{g.detach(e),A(e,r)},"killTree"),j=c.rollReadyMs??types_1.POD_ROLL_READY_MS,O=c.rollPollMs??750,Y=c.maxConcurrentRolls??types_1.POD_MAX_CONCURRENT_ROLLS,q=Y>0?Y:Number.POSITIVE_INFINITY,{emit:V}=n,ne=i(e=>e.wsKey===t.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl"),"serviceBus"),v=i((e,r,s,o,l)=>V(r,s,o,{wsKey:e.wsKey,...l},void 0,ne(e)),"emitSvc"),u=i(e=>(e.scannedAt=0,(0,discovery_1.pickSock)(e,t.scanTtlMs)?e.socks.length:0),"scanNow"),w=i((e,r)=>{let s;try{s=(0,node_child_process_1.execFileSync)("ps",["ax","-ww","-o","pid=,pgid=,command="],{encoding:"utf8",timeout:5e3})}catch{return 0}const o=e.proc?.pid;let l=0;for(const d of s.split(`
2
+ `)){const p=d.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);if(!p)continue;const y=Number(p[1]),C=Number(p[2]);if(isRunnerOf(p[3],r,e.root)&&!(y===process.pid||y===o)&&!(o!==void 0&&C===o)){try{process.kill(-C,"SIGKILL")}catch{try{process.kill(y,"SIGKILL")}catch{}}l+=1}}return l>0&&(console.log(`[gateway] ${r}: reaped ${l} stale runner tree(s) \u2014 a foreign generation of this service (holding nx's task lock, or its pool)`),v(e,"warning",`stale-runner reap: ${e.project} (${l} foreign tree(s))`,`cluster-service:${e.project}`,{kind:"stale-runner-reap",project:e.project,reaped:l})),l},"reapForeignRunners"),R=i((e,r)=>({...(0,pod_env_1.podBaseEnv)(process.env,t.root,e.root),NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false",...e.wsKey?{LENSMCP_WS_KEY:e.wsKey}:{},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"),D=i((e,r,s,o)=>{const l=R(e,r),d=e.wsKey||path.basename(e.root),p=(0,serve_launch_1.planServeLaunch)({stores:t.graphStores,root:e.root,project:e.project,target:e.decl.serveTarget??"serve-hmr",childCount:o,baseEnv:l});if(p.kind==="runner"){const m=g.offeredTo(e),E=a((0,process_name_1.namedExecPath)((0,process_name_1.processName)(d,e.project,serve_launch_1.SERVE_RUNNER_ROLE)),[...p.script.execArgv,p.script.path,...(0,serve_launch_1.serveRunnerArgs)(s,o,e.root)],{cwd:e.root,detached:!0,env:m?{...p.env,[protocol_1.SHARED_BUILD_ENV]:"1"}:p.env,stdio:["ignore","pipe","pipe","ipc"]});return m&&g.attach(e,r,E),E.send?.(p.message,$=>{$&&console.error(`[gateway] ${s}: could not hand the task to its runner (${$.message})`)}),{proc:E,launcher:"runner"}}console.log(`[gateway] ${s}: starting through nx run \u2014 ${p.reason}`);const y=path.join(e.root,"node_modules","nx","dist","bin","nx.js"),C=(0,process_name_1.namedExecPath)((0,process_name_1.processName)(d,e.project,"nx")),[W,k]=fs.existsSync(y)?[C,[y,"run",s,`--childCount=${o}`]]:["yarn",["nx","run",s,`--childCount=${o}`]];return{proc:a(W,k,{cwd:e.root,detached:!0,env:l,stdio:["ignore","pipe","pipe"]}),launcher:"nx"}},"startServiceTree"),I=new WeakMap,x=i((e,r,s)=>{const o=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,l=Math.max(1,e.decl.minPods??1),{proc:d,launcher:p}=D(e,r,o,l);I.set(d,p),s==="active"&&(e.launcher=p),s==="active"&&(e.lastErrors=[],e.buildFailed=!1,e.faults=new pod_output_1.PodFaults);const y=i(k=>{const m=k.toString();for(const E of m.split(`
3
+ `)){const $=(0,pod_output_1.classifyPodLine)(E),{clean:P,broken:U,healthy:_}=$,F=P;if(U){e.lastErrors.push(P),e.lastErrors.length>12&&e.lastErrors.shift(),e.buildFailed=!0;const M=Date.now();(P!==e.lastErrorEmitSig||M-(e.lastErrorEmitAt??0)>=types_1.SERVICE_ERROR_THROTTLE_MS)&&(e.lastErrorEmitSig=P,e.lastErrorEmitAt=M,v(e,"error",`service error: ${e.project}`,`cluster-service:${e.project}`,{kind:"service-error",project:e.project,line:P,fault:$.fault}))}_&&(e.buildFailed=!1);const T=(e.faults??=new pod_output_1.PodFaults).observe($);if(T){e.lastErrorEmitSig=void 0;const M=T.open.length===0;v(e,"info",`${M?"service recovered":`${T.closed.join(" + ")} recovered`}: ${e.project}`,`cluster-service:${e.project}`,{kind:M?"service-recovered":"service-fault-closed",project:e.project,line:P,closed:T.closed,open:T.open})}!e.lockBlockedAt&&/Waiting for .+ in another nx process/.test(F)&&(e.lockBlockedAt=Date.now(),console.log(`[gateway] ${o}: spawn blocked by a stale nx runner \u2014 breaking the lock + respawning`),v(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||(L(e,"parked on a foreign nx task lock \u2014 recycling",{announce:!1}),w(e,o),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&N(e)},1500).unref?.())},250).unref?.())}},"sniff"),C=e.wsKey&&e.wsKey!==t.wsKey&&e.root?(0,workspace_log_1.workspaceLogWriter)(e.root):void 0,W=i(k=>m=>{if(t.stopped())return;const E=(0,inspector_secret_1.redactInspectorUrls)(m.toString());y(E);const $=`[${e.project}] ${E}`;k.write($),C?.($)},"relay");return d.stdout?.on("data",W(process.stdout)),d.stderr?.on("data",W(process.stderr)),d.on("exit",(k,m)=>{if(e.proc!==d||(e.proc=void 0,e.state="down",t.stopped()))return;const E=(0,exit_reason_1.describeExit)(k,m);if(console.log(`[gateway] ${o} exited (${k??"no code"}${m?`, ${m}`:""}${e.inflight?`, ${e.inflight} request(s) in flight`:""})${E?` \u2014 ${E}`:""}`),v(e,k===0?"info":"warning",`service down: ${e.project} (exit ${k})`,`cluster-service:${e.project}`,{kind:"service-down",project:e.project,code:k,...m?{signal:m}:{}}),k===0||e.buildFailed)return;const $=Date.now();if(e.restarts=(e.restarts??[]).filter(U=>$-U<types_1.SERVICE_RESTART_WINDOW_MS),e.restarts.length>=types_1.SERVICE_MAX_RESTARTS){v(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($);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})`),v(e,"info",`self-heal: respawning ${e.project}`,`cluster-service:${e.project}`,{kind:"service-respawn",project:e.project,attempt:e.restarts.length}),N(e))},P)}),d},"launchServiceProcess"),N=i(e=>{if(t.stopped())return;const r=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,s=Math.max(1,e.decl.minPods??1);c.reapForeign!==!1&&w(e,r),e.lockBlockedAt=void 0,console.log(`[gateway] starting ${r} (pods=${s})\u2026`),v(e,"info",`service starting: ${e.project} (${s} pod${s>1?"s":""})`,`cluster-service:${e.project}`,{kind:"service-starting",project:e.project,pods:s}),e.state="starting",e.spawnAt=Date.now(),e.generation=(e.generation??0)+1,e.proc=x(e,e.generation,"active")},"spawnService"),H=i(async e=>{const r=e.pool.socks[0];if(!r)return;const s=await(0,pod_probe_1.probePodAlive)(r,void 0,t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)]);s&&(e.activeWork=s.activeWork,s.watcher&&(e.watcher=s.watcher))},"refreshActiveWork"),te=i(e=>{try{const r=Number(fs.readFileSync(`${e}.owner`,"utf8").trim());return Number.isInteger(r)&&r>1?r:void 0}catch{return}},"readOwnerSidecar"),oe=i(async e=>{const r=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)];if(!r)return[];const s=(0,node_crypto_1.createHash)("sha256").update(r).digest("hex").slice(0,8),o=[];for(const l of e.pool.socks){const d=await(0,pod_probe_1.probePodAlive)(l,void 0,r);d&&(!d.keyFingerprint||d.keyFingerprint!==s)&&o.push({sock:l,pid:d.pid})}return o},"staleAdoptedSocks"),z=i((e,r)=>{const s=r.map(o=>o.sock);for(const{sock:o,pid:l}of r){const d=chooseStalePodKillTarget(l,te(o),process.pid);if(d!==void 0)try{process.kill(d,"SIGTERM")}catch{}try{fs.unlinkSync(o)}catch{}try{fs.unlinkSync(`${o}.owner`)}catch{}}e.pool.socks=e.pool.socks.filter(o=>!s.includes(o)),e.pool.idx=-1,e.pool.scannedAt=0},"evictStaleAdopted"),b=i((e,r)=>{if(e.state==="up")return!1;e.state="up",e.wedgeRecycles=0;const s=e.pool.socks.length;return v(e,"info",`service up: ${e.project} (${s} pods, ${r})`,`cluster-service:${e.project}`,{kind:"service-up",project:e.project,pods:s,adopted:r==="adopted"}),!0},"markUp"),J=i(async e=>{if(u(e.pool)>0){const o=await oe(e);if(o.length>0&&(console.error(`[gateway] ${e.project}: ${o.length} adopted pod(s) hold a foreign east-west key \u2014 evicting instead of adopting.`),v(e,"warning",`stale adoption: ${e.project} (foreign east-west key)`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:"stale-adoption",pods:o.length}),e.proc&&L(e,"stale adoption (foreign east-west key)"),z(e,o)),e.pool.socks.length>0)return b(e,"adopted"),!0}if(t.stopped())return!1;e.state!=="starting"&&!e.proc&&N(e);const r=Date.now()+t.startupTimeoutMs,s=Date.now()+12e3;for(;!t.stopped()&&Date.now()<r;){if(await sleep(Math.min(700,t.startupTimeoutMs/4)),e.buildFailed&&Date.now()>s)return!1;if(u(e.pool)>0){e.state="up",e.buildFailed=!1;const o=e.spawnAt?Date.now()-e.spawnAt:void 0;return console.log(`[gateway] ${e.project} up (${e.pool.socks.length} pods${o?`, cold start ${o}ms`:""})`),v(e,"info",`cold start: ${e.project} (${e.pool.socks.length} pods, ${o??"?"}ms)`,`cluster-service:${e.project}`,{kind:"cold-start",project:e.project,pods:e.pool.socks.length,durationMs:o}),!0}if(e.state==="down")return!1}return!1},"ensureUp"),re=i(e=>{const r=e.decl.maxPods??e.decl.minPods??1,s=e.pool.socks.length,o=scaleTarget(e);!o||s===0||s>=r||e.inflight<=s||Date.now()-e.lastScaleAt<5e3||(e.lastScaleAt=Date.now(),postScale(o,s+1,c.scaleLookup),console.log(`[gateway] autoscale ${e.project}: ${s} \u2192 ${s+1} pods (inflight ${e.inflight})`),v(e,"info",`autoscale: ${e.project} ${s} \u2192 ${s+1} pods`,`cluster-service:${e.project}`,{kind:"autoscale",project:e.project,from:s,to:s+1,inflight:e.inflight}))},"scaleUp"),L=i((e,r,s)=>{if(!e.proc)return;console.log(`[gateway] ${e.project} ${r} \u2014 scaling to zero.`),s?.announce!==!1&&v(e,"info",`idle kill: ${e.project} (${r})`,`cluster-service:${e.project}`,{kind:"idle-kill",project:e.project,why:r});const o=e.proc;try{o.stdout?.removeAllListeners("data"),o.stderr?.removeAllListeners("data"),o.removeAllListeners("exit")}catch{}S(o,"SIGTERM"),e.proc=void 0,e.state="down",setTimeout(()=>{ce(e),e.pool.socks=[],e.pool.scannedAt=0},1200).unref?.()},"killSpawned"),ce=i(e=>{try{for(const r of fs.readdirSync(e.pool.dir)){if(!r.endsWith(".sock"))continue;const s=path.join(e.pool.dir,r);try{const o=Number(fs.readFileSync(`${s}.owner`,"utf8").trim());if(Number.isFinite(o)&&o>0)try{process.kill(o,0);continue}catch{}}catch{}try{fs.unlinkSync(s)}catch{}try{fs.unlinkSync(`${s}.owner`)}catch{}}}catch{}},"sweepDeadOwnerSocks");let G=0;const ae=[],we=i(()=>G<q?(G+=1,Promise.resolve()):new Promise(e=>{ae.push(()=>{G+=1,e()})}),"acquireRollSlot"),Se=i(()=>{G-=1,ae.shift()?.()},"releaseRollSlot"),ve=i(async(e,r,s)=>{u(e.pool);for(const o of e.pool.socks){const l=await h(o,void 0,s);if(l&&r(l.podGeneration))return!0}return!1},"anyPodAnswers"),ue=i((e,r)=>{if(e.rolling)return e.rolling;const s=e.proc;if(!s||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);G>=q&&console.log(`[gateway] pod handoff queued: ${e.project} reason=${r} \u2014 ${G} roll(s) in flight, ${ae.length} ahead (LENSMCP_POD_MAX_CONCURRENT_ROLLS=${q}).`);const o=(async()=>{await we();try{return await ye(e,s,r)}finally{Se()}})().finally(()=>{e.rolling=void 0});return e.rolling=o,o},"rollPod"),ye=i(async(e,r,s)=>{const o=e.proc;if(o!==r||t.stopped())return!1;const l=e.generation??0,d=l+1,p=Date.now();e.lastStaleRecycleAt=p,console.log(`[gateway] pod handoff start: ${e.project} g${l}\u2192g${d} reason=${s} \u2014 standby spawning, old generation keeps serving.`),v(e,"info",`pod handoff starting: ${e.project} (${s})`,`cluster-service:${e.project}`,{kind:"pod-handoff-start",project:e.project,reason:s,generation:d,fromGeneration:l});const y=x(e,d,"standby"),C=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],W=p+j;let k;for(;!t.stopped()&&Date.now()<W&&!(y.exitCode!==null||y.signalCode!==null);){u(e.pool);for(const m of e.pool.socks)if((await h(m,void 0,C))?.podGeneration===d){k=m;break}if(k)break;await sleep(O)}if(!k||t.stopped()){const m=t.stopped()?"gateway stopping":y.exitCode!==null||y.signalCode!==null?`standby exited (${y.exitCode??y.signalCode})`:`standby not ready within ${Math.round(j/1e3)}s`;try{y.stdout?.removeAllListeners("data"),y.stderr?.removeAllListeners("data")}catch{}S(y,"SIGTERM");const E=!t.stopped()&&e.proc===o&&o.exitCode===null&&o.signalCode===null&&await ve(e,P=>P!==d,C),$=E?`old generation g${l} kept serving`:`and the old generation g${l} is NOT serving (${e.proc!==o||o.exitCode!==null||o.signalCode!==null?"its tree is gone":"none of its pods answers"}) \u2014 the service is down until it recovers`;return console.error(`[gateway] pod handoff failed: ${e.project} g${d}: ${m} \u2014 ${$}.`),v(e,E?"warning":"error",`pod handoff failed: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-failed",project:e.project,reason:s,generation:d,error:m,durationMs:Date.now()-p,oldServing:E}),setTimeout(()=>ce(e),1200).unref?.(),!1}if(e.proc!==o)return S(y,"SIGTERM"),!1;e.proc=y,e.launcher=I.get(y),e.generation=d,e.spawnAt=p,e.state="up",e.watcher=void 0,e.staleVerifiedAt=void 0,e.staleKeptAt=void 0,e.buildFailed=!1,e.lastErrors=[];try{o.stdout?.removeAllListeners("data"),o.stderr?.removeAllListeners("data"),o.removeAllListeners("exit")}catch{}return S(o,"SIGTERM"),setTimeout(()=>{ce(e),e.pool.scannedAt=0},1200).unref?.(),console.log(`[gateway] pod handoff ready: ${e.project} g${d} answered on ${path.basename(k)} in ${Date.now()-p}ms; retiring g${l}.`),v(e,"info",`pod handoff complete: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-complete",project:e.project,reason:s,generation:d,fromGeneration:l,durationMs:Date.now()-p}),!0},"runRoll"),he=i(e=>{const r=Date.now();e.restarts=(e.restarts??[]).filter(o=>r-o<types_1.SERVICE_RESTART_WINDOW_MS);const s=(e.wedgeRecycles??0)+1;if(e.restarts.length>=types_1.SERVICE_MAX_RESTARTS||s>types_1.SERVICE_MAX_RESTARTS){const o=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`;v(e,"error",`service crash-looping: ${e.project} \u2014 ${o}, not auto-recycling (the next request retries)`,`cluster-service:${e.project}`,{kind:"service-crash-loop",project:e.project,recycles:s-1}),L(e,"wedged (crash-loop cap) \u2014 leaving down for the next request",{announce:!1});return}e.wedgeRecycles=s,e.restarts.push(r),console.log(`[gateway] self-heal: recycling WEDGED ${e.project} (live parent, 0 live pods; attempt ${s}/${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)`),v(e,"warning",`self-heal: recycling wedged ${e.project} (0 live pods)`,`cluster-service:${e.project}`,{kind:"service-recycle",project:e.project,attempt:s,inWindow:e.restarts.length}),L(e,"wedged: 0 live pods \u2014 recycling",{announce:!1}),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&N(e)},1500).unref?.()},"recycleWedged"),_e={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 ie;const Q=new Map,fe=new Map;let le=!1,de=0,se=0;const me=i(()=>{const e=t.projectRoots??{},r=new Set(t.services.map(o=>o.project));for(const o of t.routes)o.lens&&r.add(o.lens.project);const s=new Set;for(const o of r){const l=e[o];if(!l)continue;const d=path.relative(t.root,l).split(path.sep).filter(Boolean)[0];d&&!d.startsWith("..")&&s.add(d)}return[...s]},"managedBuckets"),Ee=i((e,r,s,o)=>{const l=t.projectSourceRoots?.[e];if(l?.length)return l;const d=t.projectRoots?.[e];if(!d)return;const p=sourceScopeDirs(t.root,d,s,r,o);return p.length>0?p:void 0},"scopeFor"),$e=i(()=>{if(le||Date.now()-de<types_1.POD_STALE_SCAN_MS)return;le=!0,de=Date.now();const e=de;(async()=>{const r=(0,scope_1.readSourceSetOptions)(t.root),s=r.exclude,o={ignoreTests:r.ignoreTests},l=sourceScanPass(t.root,s,o),d=await l.snapshot(),p=Date.now(),y=sourceChangeWindowMs(p,se,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS),C=ie?diffSourceSets(ie,d,p,y):null;if(C&&(t.sourceSetChangedAt=p,t.sourceSetChange=C,V("info","source file set changed \u2014 stale pods recycle when idle","cluster-gateway",{kind:"source-set-changed",added:C.added,removed:C.removed,truncated:C.truncated})),ie=d,!t.projectRoots){se=e;return}let W;try{W=(await fs.promises.readdir(t.root,{withFileTypes:!0})).filter(_=>_.isDirectory()).map(_=>_.name)}catch{return}const k=me(),m=new Set(t.services.map(_=>_.project));for(const _ of t.routes)_.lens&&m.add(_.lens.project);const E=new Map;for(const _ of m){const F=Ee(_,W,k,s);if(!F)continue;const T=F.join("|"),M=E.get(T)??{dirs:F,projects:[]};M.projects.push(_),E.set(T,M)}const $=Date.now(),P=sourceChangeWindowMs($,se,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS);se=e;const U=i((_,F,T)=>{t.sourceSetChangedFor??=new Map,t.sourceSetChangesFor??=new Map;for(const M of _)t.sourceSetChangedFor.set(M,F),t.sourceSetChangesFor.set(M,T)},"stampScoped");for(const[_,{dirs:F,projects:T}]of E){const M=await l.snapshot(F),ge=Q.get(_);Q.set(_,M);const pe=new Map;for(const B of T){const K=fe.get(B);if(K===void 0||K===_)continue;const X=pe.get(K)??[];X.push(B),pe.set(K,X)}for(const B of T)fe.set(B,_);for(const[B,K]of pe){const X=Q.get(B),ee=X?diffSourceSets(X,M,$,P):C;ee&&(U(K,X?$:p,ee),V("info",`source file set changed \u2014 ${K.join(", ")}'s watch scope was re-keyed`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,rescoped:!0,projects:K,added:ee.added,removed:ee.removed,truncated:ee.truncated}))}if(!ge)continue;const Z=diffSourceSets(ge,M,$,P);Z&&(U(T,$,Z),V("info",`source file set changed in ${T.join(", ")}'s scope`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,projects:T,added:Z.added,removed:Z.removed,truncated:Z.truncated}))}for(const _ of[...Q.keys()])E.has(_)||Q.delete(_)})().catch(()=>{}).finally(()=>{le=!1})},"maybeScanSourceSet"),je=i((e,r)=>{const s=(t.sourceSetChangesFor?.get(e.project)??t.sourceSetChange)?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,o=podWatcherVerdict(e.watcher,r,s),l=i(d=>(e.staleKeptAt!==r&&(e.staleKeptAt=r,console.log(`[gateway] stale source set: pod ${e.project} ${d} \u2014 no recycle.`)),!1),"keep");return o==="heard"?(e.staleVerifiedAt=r,v(e,"info",`stale check: ${e.project} watcher confirmed \u2014 no recycle`,`cluster-service:${e.project}`,{kind:"pod-stale-verified",project:e.project,watcher:o}),l(`watcher CONFIRMED alive across the change (last build ${new Date(e.watcher?.lastBuildAt??0).toISOString()})`)):o==="degraded"?(console.log(`[gateway] stale source set: pod ${e.project} watcher DEGRADED (${e.watcher?.degraded}) \u2014 recycling.`),!0):o==="silent"?types_1.POD_WATCHER_SILENT==="keep"?l("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)"):!0:types_1.POD_WATCHER_UNVERIFIED==="keep"?l("unverifiable (no watcher testimony \u2014 older devserver bundle?) \u2014 keeping it (LENSMCP_POD_WATCHER_UNVERIFIED=keep)"):!0},"podStaleRecycleAllowed"),ke=i((e,r)=>{if(e.lastStaleRecycleAt=Date.now(),types_1.POD_RECYCLE_MODE==="rolling"&&e.proc&&e.launcher!=="nx"){ue(e,r);return}console.log(`[gateway] zombie recycle: ${e.project} (${r}) \u2014 stale fs view; fresh pod incoming`),v(e,"warning",`zombie recycle: ${e.project} (${r})`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:r});const s=!!e.decl.eager;L(e,`${r} \u2014 recycling stale pod`,{announce:!1}),s&&setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&N(e)},1500).unref?.()},"recyclePod"),Re=i(()=>{const e=setInterval(()=>{Ae().catch(r=>console.error("[gateway] sweep error:",r))},t.sweepMs);return e.unref(),e},"startSweeper"),Ae=i(async()=>{{if(t.stopped())return;for(const e of t.graphStores?.all()??[])e.refreshIfStale();types_1.POD_RECYCLE_ENABLED&&$e();for(const e of t.services){if(t.stopped()||!e.proc){e.wedgedSince=void 0;continue}const r=e.decl.idleKillSec;if(r&&e.inflight===0&&Date.now()-e.lastUsed>r*1e3){L(e,`idle ${r}s`),e.wedgedSince=void 0;continue}const s=e.state==="starting"&&e.spawnAt!==void 0&&Date.now()-e.spawnAt<t.startupTimeoutMs,o=u(e.pool)>0;if(o||s){if(e.wedgedSince=void 0,o&&b(e,"observed"),o&&!s&&types_1.POD_RECYCLE_ENABLED){const l=t.sourceSetChangedFor?.get(e.project)??t.sourceSetChangedAt??0;await H(e);const d=(e.staleVerifiedAt??0)>=l&&l>0,p=podRecycleReason(e,Date.now(),d?0:l,_e);if(p==="stale-source-set"&&!je(e,l))continue;p&&ke(e,p)}continue}e.wedgedSince??=Date.now(),Date.now()-e.wedgedSince>types_1.WEDGE_RECYCLE_GRACE_MS&&(e.wedgedSince=void 0,he(e))}}},"sweepOnce");return{scanNow:u,spawnService:N,ensureUp:J,scaleUp:re,killSpawned:L,markUp:b,startSweeper:Re,rollPod:ue,recycleWedged:he,stopBuildHost:i(e=>e===void 0?g.stop():g.release(e),"stopBuildHost")}}f(createServiceLayer,"createServiceLayer"),i(createServiceLayer,"createServiceLayer");function chooseStalePodKillTarget(t,n,c){if(!(t===void 0||!Number.isInteger(t)||t<=1)&&!(n!==void 0&&n!==t)&&t!==c)return t}f(chooseStalePodKillTarget,"chooseStalePodKillTarget"),i(chooseStalePodKillTarget,"chooseStalePodKillTarget");
@@ -252,6 +252,10 @@ export interface ServiceCtl {
252
252
  * failure recovers without a manual restart; too many in the window ⇒ stop hot-looping (the next request
253
253
  * still spawns it via scale-from-zero). Shared by the exit-self-heal AND the sweeper's wedge-recycle. */
254
254
  restarts?: number[];
255
+ /** Self-heal: wedge recycles in a row with no pod coming up in between — `markUp` ends the streak. The window above
256
+ * cannot see a wedge that returns slower than it: FoodGuard's engine was recycled every ~2.5 min with zero live
257
+ * pods, each one "attempt 1", for as long as anyone watched (issues/closed/foodguard-45). */
258
+ wedgeRecycles?: number;
255
259
  /** Self-heal: when the sweeper FIRST observed this service wedged (live `proc`, 0 live pods, not
256
260
  * cold-starting). Cleared once a pod appears; once it exceeds {@link WEDGE_RECYCLE_GRACE_MS} the sweeper
257
261
  * recycles the wedged tree. */
package/heap-snapshot.js CHANGED
@@ -1 +1 @@
1
- "use strict";var _=Object.defineProperty;var p=(e,t)=>_(e,"name",{value:t,configurable:!0});var h=Object.defineProperty,i=p((e,t)=>h(e,"name",{value:t,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.heapSnapshotPolicy=heapSnapshotPolicy,exports.availableSystemMemory=availableSystemMemory,exports.heapSnapshotRefusal=heapSnapshotRefusal,exports.heapSnapshotDir=heapSnapshotDir,exports.heapSnapshotFileName=heapSnapshotFileName,exports.ensureHeapDir=ensureHeapDir,exports.pruneHeapSnapshots=pruneHeapSnapshots,exports.writeHeapSnapshot=writeHeapSnapshot;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),fs=tslib_1.__importStar(require("node:fs")),inspector=tslib_1.__importStar(require("node:inspector")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),MB=1024*1024,numberFrom=i((e,t,o)=>{if(e===void 0||e.trim()==="")return t;const a=Number(e);return Number.isFinite(a)&&a>=o?a:t},"numberFrom");function heapSnapshotPolicy(e=process.env){return{maxHeapBytes:numberFrom(e.LENSMCP_HEAP_SNAPSHOT_MAX_MB,1024,1)*MB,minFreeBytes:numberFrom(e.LENSMCP_HEAP_SNAPSHOT_MIN_FREE_MB,1024,0)*MB,freeFactor:numberFrom(e.LENSMCP_HEAP_SNAPSHOT_FREE_FACTOR,3,0),keep:Math.max(1,Math.floor(numberFrom(e.LENSMCP_HEAP_SNAPSHOT_KEEP,3,1))),maxAgeMs:numberFrom(e.LENSMCP_HEAP_SNAPSHOT_MAX_AGE_H,24,0)*36e5}}p(heapSnapshotPolicy,"heapSnapshotPolicy"),i(heapSnapshotPolicy,"heapSnapshotPolicy");function availableSystemMemory(e=process.platform){try{if(e==="darwin"){const t=(0,node_child_process_1.spawnSync)("vm_stat",[],{encoding:"utf8",timeout:2e3}).stdout??"",o=Number(/page size of (\d+) bytes/.exec(t)?.[1]??4096),a=i(r=>Number(new RegExp(`Pages ${r}:\\s+(\\d+)`).exec(t)?.[1]??0),"pages"),n=a("free")+a("inactive")+a("speculative")+a("purgeable");if(n>0)return{bytes:n*o,source:"vm_stat free+inactive+speculative+purgeable"}}else if(e==="linux"){const t=/MemAvailable:\s+(\d+) kB/.exec(fs.readFileSync("/proc/meminfo","utf8"));if(t)return{bytes:Number(t[1])*1024,source:"/proc/meminfo MemAvailable"}}return{bytes:os.freemem(),source:"os.freemem()"}}catch{return}}p(availableSystemMemory,"availableSystemMemory"),i(availableSystemMemory,"availableSystemMemory");function heapSnapshotRefusal(e,t){if(t.live>e.maxHeapBytes)return`the pod's live heap is ${Math.round(t.live/MB)} MB, over the ${Math.round(e.maxHeapBytes/MB)} MB bound (LENSMCP_HEAP_SNAPSHOT_MAX_MB) \u2014 a snapshot this size needs several times that in memory while it is written`;if(t.available){const o=Math.max(e.minFreeBytes,e.freeFactor*t.live);if(t.available.bytes<o)return`only ${Math.round(t.available.bytes/MB)} MB of memory is available (${t.available.source}) and a snapshot of a ${Math.round(t.live/MB)} MB heap needs about ${Math.round(o/MB)} MB \u2014 free some memory first, or lower the floor with LENSMCP_HEAP_SNAPSHOT_MIN_FREE_MB / LENSMCP_HEAP_SNAPSHOT_FREE_FACTOR`}}p(heapSnapshotRefusal,"heapSnapshotRefusal"),i(heapSnapshotRefusal,"heapSnapshotRefusal");function heapSnapshotDir(e=process.env,t=process.cwd()){return e.LENSMCP_HEAP_DIR?path.resolve(e.LENSMCP_HEAP_DIR):e.LENSMCP_EVENT_FILE?path.join(path.dirname(path.resolve(e.LENSMCP_EVENT_FILE)),"heap"):path.join(t,".lensmcp","heap")}p(heapSnapshotDir,"heapSnapshotDir"),i(heapSnapshotDir,"heapSnapshotDir");function heapSnapshotFileName(e,t,o,a,n){const r=(e||"service").replace(/[^A-Za-z0-9_.-]/g,"_"),s=new Date(n).toISOString().replace(/[:.]/g,"-");return`${r}-pod${t}-pid${o}-g${a}-${s}.heapsnapshot`}p(heapSnapshotFileName,"heapSnapshotFileName"),i(heapSnapshotFileName,"heapSnapshotFileName");function ensureHeapDir(e){fs.mkdirSync(e,{recursive:!0,mode:448});const t=fs.lstatSync(e);if(!t.isDirectory())throw new Error(`${e} is not a directory`);(t.mode&63)!==0&&fs.chmodSync(e,448)}p(ensureHeapDir,"ensureHeapDir"),i(ensureHeapDir,"ensureHeapDir");function pruneHeapSnapshots(e,t,o=Date.now()){const a=[];let n;try{n=fs.readdirSync(e).filter(r=>r.endsWith(".heapsnapshot")).map(r=>{const s=path.join(e,r),u=fs.lstatSync(s);return u.isFile()?{file:s,mtime:u.mtimeMs}:void 0}).filter(r=>r!==void 0).sort((r,s)=>s.mtime-r.mtime)}catch{return a}return n.forEach((r,s)=>{if(s>=t.keep-1||o-r.mtime>t.maxAgeMs)try{fs.unlinkSync(r.file),a.push(r.file)}catch{}}),a}p(pruneHeapSnapshots,"pruneHeapSnapshots"),i(pruneHeapSnapshots,"pruneHeapSnapshots");function writeHeapSnapshot(e){const t=Date.now(),o=fs.constants.O_WRONLY|fs.constants.O_CREAT|fs.constants.O_EXCL|(fs.constants.O_NOFOLLOW??0),a=fs.openSync(e,o,384),n=new inspector.Session;let r=0,s;return new Promise((u,S)=>{const m=i(c=>{n.removeAllListeners("HeapProfiler.addHeapSnapshotChunk");try{n.disconnect()}catch{}try{fs.closeSync(a)}catch{}const l=c??s;if(l){try{fs.unlinkSync(e)}catch{}S(l);return}u({bytes:r,ms:Date.now()-t})},"finish");try{n.connect(),n.on("HeapProfiler.addHeapSnapshotChunk",c=>{if(!s)try{r+=fs.writeSync(a,c.params.chunk)}catch(l){s=l}}),n.post("HeapProfiler.takeHeapSnapshot",{reportProgress:!1},c=>m(c))}catch(c){m(c)}})}p(writeHeapSnapshot,"writeHeapSnapshot"),i(writeHeapSnapshot,"writeHeapSnapshot");
1
+ "use strict";var _=Object.defineProperty;var p=(e,t)=>_(e,"name",{value:t,configurable:!0});var m=Object.defineProperty,i=p((e,t)=>m(e,"name",{value:t,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.heapSnapshotPolicy=heapSnapshotPolicy,exports.availableSystemMemory=availableSystemMemory,exports.heapSnapshotRefusal=heapSnapshotRefusal,exports.heapSnapshotDir=heapSnapshotDir,exports.heapSnapshotFileName=heapSnapshotFileName,exports.ensureHeapDir=ensureHeapDir,exports.pruneHeapSnapshots=pruneHeapSnapshots,exports.writeHeapSnapshot=writeHeapSnapshot;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),fs=tslib_1.__importStar(require("node:fs")),inspector=tslib_1.__importStar(require("node:inspector")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),MB=1024*1024,numberFrom=i((e,t,s)=>{if(e===void 0||e.trim()==="")return t;const a=Number(e);return Number.isFinite(a)&&a>=s?a:t},"numberFrom");function heapSnapshotPolicy(e=process.env){return{maxHeapBytes:numberFrom(e.LENSMCP_HEAP_SNAPSHOT_MAX_MB,1024,1)*MB,minFreeBytes:numberFrom(e.LENSMCP_HEAP_SNAPSHOT_MIN_FREE_MB,1024,0)*MB,freeFactor:numberFrom(e.LENSMCP_HEAP_SNAPSHOT_FREE_FACTOR,3,0),keep:Math.max(1,Math.floor(numberFrom(e.LENSMCP_HEAP_SNAPSHOT_KEEP,3,1))),maxAgeMs:numberFrom(e.LENSMCP_HEAP_SNAPSHOT_MAX_AGE_H,24,0)*36e5}}p(heapSnapshotPolicy,"heapSnapshotPolicy"),i(heapSnapshotPolicy,"heapSnapshotPolicy");function availableSystemMemory(e=process.platform){try{if(e==="darwin"){const t=(0,node_child_process_1.spawnSync)("vm_stat",[],{encoding:"utf8",timeout:2e3}).stdout??"",s=Number(/page size of (\d+) bytes/.exec(t)?.[1]??4096),a=i(r=>Number(new RegExp(`Pages ${r}:\\s+(\\d+)`).exec(t)?.[1]??0),"pages"),o=a("free")+a("inactive")+a("speculative")+a("purgeable");if(o>0)return{bytes:o*s,source:"vm_stat free+inactive+speculative+purgeable"}}else if(e==="linux"){const t=/MemAvailable:\s+(\d+) kB/.exec(fs.readFileSync("/proc/meminfo","utf8"));if(t)return{bytes:Number(t[1])*1024,source:"/proc/meminfo MemAvailable"}}return{bytes:os.freemem(),source:"os.freemem()"}}catch{return}}p(availableSystemMemory,"availableSystemMemory"),i(availableSystemMemory,"availableSystemMemory");function heapSnapshotRefusal(e,t){if(t.live>e.maxHeapBytes){const s=Math.ceil(t.live/MB/256)*256;return`the pod's live heap is ${Math.round(t.live/MB)} MB, over the ${Math.round(e.maxHeapBytes/MB)} MB bound \u2014 a snapshot this size needs several times that in memory while it is written. Raise the bound for this one snapshot with \`--max-mb ${s}\` (the free-memory check still applies); the default is LENSMCP_HEAP_SNAPSHOT_MAX_MB, read when the pod starts`}if(t.available){const s=Math.max(e.minFreeBytes,e.freeFactor*t.live);if(t.available.bytes<s)return`only ${Math.round(t.available.bytes/MB)} MB of memory is available (${t.available.source}) and a snapshot of a ${Math.round(t.live/MB)} MB heap needs about ${Math.round(s/MB)} MB \u2014 free some memory first, or lower the floor with LENSMCP_HEAP_SNAPSHOT_MIN_FREE_MB / LENSMCP_HEAP_SNAPSHOT_FREE_FACTOR`}}p(heapSnapshotRefusal,"heapSnapshotRefusal"),i(heapSnapshotRefusal,"heapSnapshotRefusal");function heapSnapshotDir(e=process.env,t=process.cwd()){return e.LENSMCP_HEAP_DIR?path.resolve(e.LENSMCP_HEAP_DIR):e.LENSMCP_EVENT_FILE?path.join(path.dirname(path.resolve(e.LENSMCP_EVENT_FILE)),"heap"):path.join(t,".lensmcp","heap")}p(heapSnapshotDir,"heapSnapshotDir"),i(heapSnapshotDir,"heapSnapshotDir");function heapSnapshotFileName(e,t,s,a,o){const r=(e||"service").replace(/[^A-Za-z0-9_.-]/g,"_"),n=new Date(o).toISOString().replace(/[:.]/g,"-");return`${r}-pod${t}-pid${s}-g${a}-${n}.heapsnapshot`}p(heapSnapshotFileName,"heapSnapshotFileName"),i(heapSnapshotFileName,"heapSnapshotFileName");function ensureHeapDir(e){fs.mkdirSync(e,{recursive:!0,mode:448});const t=fs.lstatSync(e);if(!t.isDirectory())throw new Error(`${e} is not a directory`);(t.mode&63)!==0&&fs.chmodSync(e,448)}p(ensureHeapDir,"ensureHeapDir"),i(ensureHeapDir,"ensureHeapDir");function pruneHeapSnapshots(e,t,s=Date.now()){const a=[];let o;try{o=fs.readdirSync(e).filter(r=>r.endsWith(".heapsnapshot")).map(r=>{const n=path.join(e,r),h=fs.lstatSync(n);return h.isFile()?{file:n,mtime:h.mtimeMs}:void 0}).filter(r=>r!==void 0).sort((r,n)=>n.mtime-r.mtime)}catch{return a}return o.forEach((r,n)=>{if(n>=t.keep-1||s-r.mtime>t.maxAgeMs)try{fs.unlinkSync(r.file),a.push(r.file)}catch{}}),a}p(pruneHeapSnapshots,"pruneHeapSnapshots"),i(pruneHeapSnapshots,"pruneHeapSnapshots");function writeHeapSnapshot(e){const t=Date.now(),s=fs.constants.O_WRONLY|fs.constants.O_CREAT|fs.constants.O_EXCL|(fs.constants.O_NOFOLLOW??0),a=fs.openSync(e,s,384),o=new inspector.Session;let r=0,n;return new Promise((h,S)=>{const u=i(c=>{o.removeAllListeners("HeapProfiler.addHeapSnapshotChunk");try{o.disconnect()}catch{}try{fs.closeSync(a)}catch{}const l=c??n;if(l){try{fs.unlinkSync(e)}catch{}S(l);return}h({bytes:r,ms:Date.now()-t})},"finish");try{o.connect(),o.on("HeapProfiler.addHeapSnapshotChunk",c=>{if(!n)try{r+=fs.writeSync(a,c.params.chunk)}catch(l){n=l}}),o.post("HeapProfiler.takeHeapSnapshot",{reportProgress:!1},c=>u(c))}catch(c){u(c)}})}p(writeHeapSnapshot,"writeHeapSnapshot"),i(writeHeapSnapshot,"writeHeapSnapshot");
package/main.devserver.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var je=Object.defineProperty;var h=(s,u)=>je(s,"name",{value:u,configurable:!0});var Be=Object.defineProperty,n=h((s,u)=>Be(s,"name",{value:u,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.redactInspectorUrls=exports.DEBUG_FIXED_PORTS_ENV=void 0,exports.isOwnerOnlyTransport=isOwnerOnlyTransport,exports.tell=tell,exports.gatewayManaged=gatewayManaged,exports.mayDriveThePool=mayDriveThePool,exports.usesFixedInspectorPorts=usesFixedInspectorPorts,exports.inspectorPortFor=inspectorPortFor,exports.inspectorPortOf=inspectorPortOf;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),node_child_process_1=require("node:child_process"),http=tslib_1.__importStar(require("node:http")),readline=tslib_1.__importStar(require("node:readline")),inspector=tslib_1.__importStar(require("node:inspector")),util=tslib_1.__importStar(require("node:util")),v8=tslib_1.__importStar(require("node:v8")),exit_reason_1=require("./exit-reason"),hot_swap_registries_1=require("./hot-swap-registries"),process_name_1=require("./process-name"),inspector_secret_1=require("./inspector-secret");Object.defineProperty(exports,"redactInspectorUrls",{enumerable:!0,get:n(function(){return inspector_secret_1.redactInspectorUrls},"get")});const schema_first_instance_1=require("./schema-first-instance"),redis_disconnect_fix_1=require("./redis-disconnect-fix"),error_stack_release_1=require("./error-stack-release"),swap_recycle_1=require("./swap-recycle"),stdio_guard_1=require("./stdio-guard"),dev_devtool_1=require("./dev-devtool"),pod_memory_1=require("./pod-memory"),pod_memory_events_1=require("./pod-memory-events"),heap_snapshot_1=require("./heap-snapshot"),httpProxy=require("http-proxy"),{prettyFactory}=require("pino-pretty"),BUNDLE_PATH=process.env.BUNDLE_PATH?.trim()||"./main.js",SERVICE_NAME=process.env.SERVICE_NAME||"",SERVICE_PREFIX=process.env.SERVE_PREFIX?`/${process.env.SERVE_PREFIX}`:"",GATEWAY_MIDDLEWARE_PATH=process.env.GATEWAY_MIDDLEWARE||"",GATEWAY_CONFIG=(()=>{const s=process.env.GATEWAY_CONFIG;if(!s)return{};try{return JSON.parse(s)}catch{return{}}})();let gatewayMiddleware=null;if(GATEWAY_MIDDLEWARE_PATH)try{const s=require(GATEWAY_MIDDLEWARE_PATH);gatewayMiddleware=typeof s=="function"?s:typeof s.default=="function"?s.default:null,gatewayMiddleware||console.warn(`[gateway] ${GATEWAY_MIDDLEWARE_PATH} does not export a function, gateway disabled`)}catch(s){console.error(`[gateway] Failed to load middleware from ${GATEWAY_MIDDLEWARE_PATH}:`,s)}function applyGatewayMiddleware(s){if(gatewayMiddleware)try{gatewayMiddleware(s,GATEWAY_CONFIG)}catch(u){console.error("[gateway] Middleware error:",u)}}h(applyGatewayMiddleware,"applyGatewayMiddleware"),n(applyGatewayMiddleware,"applyGatewayMiddleware");const GATEWAY_ROUTES=(()=>{try{return JSON.parse(process.env.GATEWAY_ROUTES||"[]")}catch{return[]}})(),GATEWAY_HTTPS=process.env.GATEWAY_HTTPS==="1";function hostMatches(s,u){if(s.startsWith("*.")){const f=s.slice(1);return u.endsWith(f)||u===s.slice(2)}return u===s}h(hostMatches,"hostMatches"),n(hostMatches,"hostMatches");function matchGatewayRoute(s){if(GATEWAY_ROUTES.length===0)return;const u=(s.headers.host||"").split(":")[0],f=s.url||"/";for(const w of GATEWAY_ROUTES)if(!(w.host&&!hostMatches(w.host,u))&&!(w.prefix&&!f.startsWith(w.prefix)))return w}h(matchGatewayRoute,"matchGatewayRoute"),n(matchGatewayRoute,"matchGatewayRoute");const WORKER_NAMES=(()=>{try{return JSON.parse(process.env.WORKERS||"[]")}catch{return[]}})(),LENSMCP_WS_KEY=process.env.LENSMCP_WS_KEY||"",SOCK_DIR=LENSMCP_WS_KEY?path.join(os.tmpdir(),LENSMCP_WS_KEY,`${SERVICE_NAME||"lensmcp-cluster"}-devserver`):path.join(os.tmpdir(),`${SERVICE_NAME||"lensmcp-cluster"}-devserver`),POD_GENERATION=(()=>{const s=Number(process.env.LENSMCP_POD_GENERATION);return Number.isFinite(s)&&s>1?Math.floor(s):1})();function childSockPath(s){return path.join(SOCK_DIR,POD_GENERATION>1?`child-${s}-g${POD_GENERATION}.sock`:`child-${s}.sock`)}h(childSockPath,"childSockPath"),n(childSockPath,"childSockPath");function sockOwnerPath(s){return`${s}.owner`}h(sockOwnerPath,"sockOwnerPath"),n(sockOwnerPath,"sockOwnerPath");function sockRetiringPath(s){return`${s}.retiring`}h(sockRetiringPath,"sockRetiringPath"),n(sockRetiringPath,"sockRetiringPath");function isOwnerOnlyTransport(s){try{return typeof s.socket?.server?.address?.()=="string"}catch{return!1}}h(isOwnerOnlyTransport,"isOwnerOnlyTransport"),n(isOwnerOnlyTransport,"isOwnerOnlyTransport");function tell(s,u){if(!s.connected||typeof s.send!="function")return!1;try{return s.send(u,()=>{})}catch{return!1}}h(tell,"tell"),n(tell,"tell");function gatewayManaged(s=process.env){return Number(s.LENSMCP_GATEWAY_PID??0)>0}h(gatewayManaged,"gatewayManaged"),n(gatewayManaged,"gatewayManaged");function mayDriveThePool(s,u=gatewayManaged()){return!u||isOwnerOnlyTransport(s)}h(mayDriveThePool,"mayDriveThePool"),n(mayDriveThePool,"mayDriveThePool");function refusePoolCommand(s,u){console.warn(`[devserver] refused ${s.method} ${s.url} on the public port \u2014 under a gateway the pool is driven on the control socket only.`),u.writeHead(404,{"content-type":"application/json"}),u.end(JSON.stringify({error:"not found"}))}h(refusePoolCommand,"refusePoolCommand"),n(refusePoolCommand,"refusePoolCommand"),exports.DEBUG_FIXED_PORTS_ENV="LENSMCP_DEBUG_FIXED_PORTS";function usesFixedInspectorPorts(s=process.env){const u=(s[exports.DEBUG_FIXED_PORTS_ENV]??"").trim().toLowerCase();return u==="1"||u==="true"||u==="yes"||u==="on"}h(usesFixedInspectorPorts,"usesFixedInspectorPorts"),n(usesFixedInspectorPorts,"usesFixedInspectorPorts");function inspectorPortFor(s,u,f=process.env){if(!usesFixedInspectorPorts(f))return 0;const w=Math.trunc(s)+Math.trunc(u);return Number.isInteger(w)&&w>1024&&w<=65535?w:0}h(inspectorPortFor,"inspectorPortFor"),n(inspectorPortFor,"inspectorPortFor");function inspectorPortOf(s){const u=/^wss?:\/\/[^/]*?:(\d+)\//.exec(s??""),f=u?Number(u[1]):NaN;return Number.isInteger(f)&&f>0?f:null}h(inspectorPortOf,"inspectorPortOf"),n(inspectorPortOf,"inspectorPortOf");function ensureOwnerOnlyDir(s){try{fs.mkdirSync(s,{recursive:!0,mode:448})}catch{}try{const u=fs.lstatSync(s);u.isDirectory()&&(u.mode&63)!==0&&fs.chmodSync(s,448)}catch{}}h(ensureOwnerOnlyDir,"ensureOwnerOnlyDir"),n(ensureOwnerOnlyDir,"ensureOwnerOnlyDir");function claimSock(s,u=process.pid){ensureOwnerOnlyDir(path.dirname(s));try{const f=sockOwnerPath(s);try{fs.unlinkSync(f)}catch{}fs.writeFileSync(f,String(u),{flag:"wx",mode:384})}catch{}try{fs.unlinkSync(s)}catch{}try{fs.unlinkSync(sockRetiringPath(s))}catch{}}h(claimSock,"claimSock"),n(claimSock,"claimSock");function sockOwnedByAnother(s,u=process.pid){try{const f=fs.readFileSync(sockOwnerPath(s),"utf8").trim();return!!f&&f!==String(u)}catch{return!1}}h(sockOwnedByAnother,"sockOwnedByAnother"),n(sockOwnedByAnother,"sockOwnedByAnother");function cleanupSock(s,u=process.pid){if(s){try{const f=fs.readFileSync(sockOwnerPath(s),"utf8").trim();if(f&&f!==String(u))return}catch{}try{fs.unlinkSync(s)}catch{}try{fs.unlinkSync(sockOwnerPath(s))}catch{}try{fs.unlinkSync(sockRetiringPath(s))}catch{}}}h(cleanupSock,"cleanupSock"),n(cleanupSock,"cleanupSock");function serviceKeyFingerprint(){const s=process.env.LENSMCP_SERVICE_KEY;if(!s)return;const{createHash:u}=require("node:crypto");return u("sha256").update(s).digest("hex").slice(0,8)}h(serviceKeyFingerprint,"serviceKeyFingerprint"),n(serviceKeyFingerprint,"serviceKeyFingerprint");function rootModuleOf(s){let u;for(const f of s.getModules?.()?.values()??[])typeof f?.metatype!="function"||typeof f.distance!="number"||!Number.isFinite(f.distance)||(!u||f.distance<u.distance)&&(u=f);return u?.metatype}h(rootModuleOf,"rootModuleOf"),n(rootModuleOf,"rootModuleOf");let lastImportedModule;function takeImportedModule(){const s=lastImportedModule;return lastImportedModule=void 0,s}h(takeImportedModule,"takeImportedModule"),n(takeImportedModule,"takeImportedModule");async function importFresh(spec){process.env.DEVSERVER_MODE="1";const requested=path.isAbsolute(spec)?spec:path.join(__dirname,spec);let resolved=requested;try{resolved=fs.realpathSync(requested)}catch{}eval(`(() => {
1
+ "use strict";var Ke=Object.defineProperty;var h=(s,u)=>Ke(s,"name",{value:u,configurable:!0});var Ve=Object.defineProperty,n=h((s,u)=>Ve(s,"name",{value:u,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.redactInspectorUrls=exports.DEBUG_FIXED_PORTS_ENV=void 0,exports.isOwnerOnlyTransport=isOwnerOnlyTransport,exports.tell=tell,exports.gatewayManaged=gatewayManaged,exports.mayDriveThePool=mayDriveThePool,exports.usesFixedInspectorPorts=usesFixedInspectorPorts,exports.inspectorPortFor=inspectorPortFor,exports.inspectorPortOf=inspectorPortOf;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),node_child_process_1=require("node:child_process"),http=tslib_1.__importStar(require("node:http")),readline=tslib_1.__importStar(require("node:readline")),inspector=tslib_1.__importStar(require("node:inspector")),util=tslib_1.__importStar(require("node:util")),v8=tslib_1.__importStar(require("node:v8")),exit_reason_1=require("./exit-reason"),hot_swap_registries_1=require("./hot-swap-registries"),process_name_1=require("./process-name"),inspector_secret_1=require("./inspector-secret");Object.defineProperty(exports,"redactInspectorUrls",{enumerable:!0,get:n(function(){return inspector_secret_1.redactInspectorUrls},"get")});const schema_first_instance_1=require("./schema-first-instance"),redis_disconnect_fix_1=require("./redis-disconnect-fix"),error_stack_release_1=require("./error-stack-release"),swap_recycle_1=require("./swap-recycle"),stdio_guard_1=require("./stdio-guard"),bundle_parent_1=require("./bundle-parent"),dev_devtool_1=require("./dev-devtool"),pod_memory_1=require("./pod-memory"),pod_memory_events_1=require("./pod-memory-events"),heap_snapshot_1=require("./heap-snapshot"),httpProxy=require("http-proxy"),{prettyFactory}=require("pino-pretty"),BUNDLE_PATH=process.env.BUNDLE_PATH?.trim()||"./main.js",SERVICE_NAME=process.env.SERVICE_NAME||"",SERVICE_PREFIX=process.env.SERVE_PREFIX?`/${process.env.SERVE_PREFIX}`:"",GATEWAY_MIDDLEWARE_PATH=process.env.GATEWAY_MIDDLEWARE||"",GATEWAY_CONFIG=(()=>{const s=process.env.GATEWAY_CONFIG;if(!s)return{};try{return JSON.parse(s)}catch{return{}}})();let gatewayMiddleware=null;if(GATEWAY_MIDDLEWARE_PATH)try{const s=require(GATEWAY_MIDDLEWARE_PATH);gatewayMiddleware=typeof s=="function"?s:typeof s.default=="function"?s.default:null,gatewayMiddleware||console.warn(`[gateway] ${GATEWAY_MIDDLEWARE_PATH} does not export a function, gateway disabled`)}catch(s){console.error(`[gateway] Failed to load middleware from ${GATEWAY_MIDDLEWARE_PATH}:`,s)}function applyGatewayMiddleware(s){if(gatewayMiddleware)try{gatewayMiddleware(s,GATEWAY_CONFIG)}catch(u){console.error("[gateway] Middleware error:",u)}}h(applyGatewayMiddleware,"applyGatewayMiddleware"),n(applyGatewayMiddleware,"applyGatewayMiddleware");const GATEWAY_ROUTES=(()=>{try{return JSON.parse(process.env.GATEWAY_ROUTES||"[]")}catch{return[]}})(),GATEWAY_HTTPS=process.env.GATEWAY_HTTPS==="1";function hostMatches(s,u){if(s.startsWith("*.")){const f=s.slice(1);return u.endsWith(f)||u===s.slice(2)}return u===s}h(hostMatches,"hostMatches"),n(hostMatches,"hostMatches");function matchGatewayRoute(s){if(GATEWAY_ROUTES.length===0)return;const u=(s.headers.host||"").split(":")[0],f=s.url||"/";for(const S of GATEWAY_ROUTES)if(!(S.host&&!hostMatches(S.host,u))&&!(S.prefix&&!f.startsWith(S.prefix)))return S}h(matchGatewayRoute,"matchGatewayRoute"),n(matchGatewayRoute,"matchGatewayRoute");const WORKER_NAMES=(()=>{try{return JSON.parse(process.env.WORKERS||"[]")}catch{return[]}})(),LENSMCP_WS_KEY=process.env.LENSMCP_WS_KEY||"",SOCK_DIR=LENSMCP_WS_KEY?path.join(os.tmpdir(),LENSMCP_WS_KEY,`${SERVICE_NAME||"lensmcp-cluster"}-devserver`):path.join(os.tmpdir(),`${SERVICE_NAME||"lensmcp-cluster"}-devserver`),POD_GENERATION=(()=>{const s=Number(process.env.LENSMCP_POD_GENERATION);return Number.isFinite(s)&&s>1?Math.floor(s):1})();function childSockPath(s){return path.join(SOCK_DIR,POD_GENERATION>1?`child-${s}-g${POD_GENERATION}.sock`:`child-${s}.sock`)}h(childSockPath,"childSockPath"),n(childSockPath,"childSockPath");function sockOwnerPath(s){return`${s}.owner`}h(sockOwnerPath,"sockOwnerPath"),n(sockOwnerPath,"sockOwnerPath");function sockRetiringPath(s){return`${s}.retiring`}h(sockRetiringPath,"sockRetiringPath"),n(sockRetiringPath,"sockRetiringPath");function isOwnerOnlyTransport(s){try{return typeof s.socket?.server?.address?.()=="string"}catch{return!1}}h(isOwnerOnlyTransport,"isOwnerOnlyTransport"),n(isOwnerOnlyTransport,"isOwnerOnlyTransport");function tell(s,u){if(!s.connected||typeof s.send!="function")return!1;try{return s.send(u,()=>{})}catch{return!1}}h(tell,"tell"),n(tell,"tell");function gatewayManaged(s=process.env){return Number(s.LENSMCP_GATEWAY_PID??0)>0}h(gatewayManaged,"gatewayManaged"),n(gatewayManaged,"gatewayManaged");function mayDriveThePool(s,u=gatewayManaged()){return!u||isOwnerOnlyTransport(s)}h(mayDriveThePool,"mayDriveThePool"),n(mayDriveThePool,"mayDriveThePool");function refusePoolCommand(s,u){console.warn(`[devserver] refused ${s.method} ${s.url} on the public port \u2014 under a gateway the pool is driven on the control socket only.`),u.writeHead(404,{"content-type":"application/json"}),u.end(JSON.stringify({error:"not found"}))}h(refusePoolCommand,"refusePoolCommand"),n(refusePoolCommand,"refusePoolCommand"),exports.DEBUG_FIXED_PORTS_ENV="LENSMCP_DEBUG_FIXED_PORTS";function usesFixedInspectorPorts(s=process.env){const u=(s[exports.DEBUG_FIXED_PORTS_ENV]??"").trim().toLowerCase();return u==="1"||u==="true"||u==="yes"||u==="on"}h(usesFixedInspectorPorts,"usesFixedInspectorPorts"),n(usesFixedInspectorPorts,"usesFixedInspectorPorts");function inspectorPortFor(s,u,f=process.env){if(!usesFixedInspectorPorts(f))return 0;const S=Math.trunc(s)+Math.trunc(u);return Number.isInteger(S)&&S>1024&&S<=65535?S:0}h(inspectorPortFor,"inspectorPortFor"),n(inspectorPortFor,"inspectorPortFor");function inspectorPortOf(s){const u=/^wss?:\/\/[^/]*?:(\d+)\//.exec(s??""),f=u?Number(u[1]):NaN;return Number.isInteger(f)&&f>0?f:null}h(inspectorPortOf,"inspectorPortOf"),n(inspectorPortOf,"inspectorPortOf");function ensureOwnerOnlyDir(s){try{fs.mkdirSync(s,{recursive:!0,mode:448})}catch{}try{const u=fs.lstatSync(s);u.isDirectory()&&(u.mode&63)!==0&&fs.chmodSync(s,448)}catch{}}h(ensureOwnerOnlyDir,"ensureOwnerOnlyDir"),n(ensureOwnerOnlyDir,"ensureOwnerOnlyDir");function claimSock(s,u=process.pid){ensureOwnerOnlyDir(path.dirname(s));try{const f=sockOwnerPath(s);try{fs.unlinkSync(f)}catch{}fs.writeFileSync(f,String(u),{flag:"wx",mode:384})}catch{}try{fs.unlinkSync(s)}catch{}try{fs.unlinkSync(sockRetiringPath(s))}catch{}}h(claimSock,"claimSock"),n(claimSock,"claimSock");function sockOwnedByAnother(s,u=process.pid){try{const f=fs.readFileSync(sockOwnerPath(s),"utf8").trim();return!!f&&f!==String(u)}catch{return!1}}h(sockOwnedByAnother,"sockOwnedByAnother"),n(sockOwnedByAnother,"sockOwnedByAnother");function cleanupSock(s,u=process.pid){if(s){try{const f=fs.readFileSync(sockOwnerPath(s),"utf8").trim();if(f&&f!==String(u))return}catch{}try{fs.unlinkSync(s)}catch{}try{fs.unlinkSync(sockOwnerPath(s))}catch{}try{fs.unlinkSync(sockRetiringPath(s))}catch{}}}h(cleanupSock,"cleanupSock"),n(cleanupSock,"cleanupSock");function serviceKeyFingerprint(){const s=process.env.LENSMCP_SERVICE_KEY;if(!s)return;const{createHash:u}=require("node:crypto");return u("sha256").update(s).digest("hex").slice(0,8)}h(serviceKeyFingerprint,"serviceKeyFingerprint"),n(serviceKeyFingerprint,"serviceKeyFingerprint");function rootModuleOf(s){let u;for(const f of s.getModules?.()?.values()??[])typeof f?.metatype!="function"||typeof f.distance!="number"||!Number.isFinite(f.distance)||(!u||f.distance<u.distance)&&(u=f);return u?.metatype}h(rootModuleOf,"rootModuleOf"),n(rootModuleOf,"rootModuleOf");let lastImportedModule;function takeImportedModule(){const s=lastImportedModule;return lastImportedModule=void 0,s}h(takeImportedModule,"takeImportedModule"),n(takeImportedModule,"takeImportedModule");async function importFresh(spec){process.env.DEVSERVER_MODE="1";const requested=path.isAbsolute(spec)?spec:path.join(__dirname,spec);let resolved=requested;try{resolved=fs.realpathSync(requested)}catch{}eval(`(() => {
2
2
  const key = ${JSON.stringify(resolved)};
3
3
  const previous = require.cache[key];
4
4
  delete require.cache[key]; // delete from CJS cache
@@ -9,15 +9,15 @@
9
9
  const at = owner && Array.isArray(owner.children) ? owner.children.indexOf(previous) : -1;
10
10
  if (at >= 0) owner.children.splice(at, 1);
11
11
  }
12
- })()`);const exports=eval(`require(${JSON.stringify(resolved)})`);try{const mod=eval("require.cache")[resolved];lastImportedModule=mod&&typeof mod=="object"?mod:void 0}catch{}return exports}h(importFresh,"importFresh"),n(importFresh,"importFresh");function debounce(s,u){let f=null;return(...w)=>{f&&clearTimeout(f),f=setTimeout(()=>s(...w),u)}}if(h(debounce,"debounce"),n(debounce,"debounce"),process.env.APP_RUNNER==="1"){(0,stdio_guard_1.guardBrokenStdio)();const s=n(f=>{if(!inspector.url())try{inspector.open(f,"127.0.0.1",!1)}catch(F){console.warn(`[child] inspector.open(${f}) failed (port taken by another devserver?) \u2014 falling back to a random port:`,F.message);try{inspector.open(0,"127.0.0.1",!1)}catch{}}const w=inspector.url();w&&tell(process,{type:"inspector-url",url:w})},"openInspector"),u=process.env.CHILD_DEBUG_PORT;if(u!==void 0&&u!==""){const f=Number(u);Number.isInteger(f)&&(f===0||f>1024)&&s(f)}try{require("@lensmcp/node-instrumentation/register")}catch{}(async()=>{let f=null,w=!1,F,Q=!1;const Re=(0,hot_swap_registries_1.registryPruningEnabled)(),oe=n((t,i)=>{const p=(0,hot_swap_registries_1.describePrune)(t,i);p&&console.log(p)},"logPrune");let j={app:null,handler:n((t,i)=>{i.statusCode=503,i.end("starting")},"handler"),inflight:0};const ne=(()=>{const t=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return Number.isFinite(t)&&t>=0?t:15*6e4})(),I=n(t=>{const i=globalThis.__lensmcpActiveWork;if(typeof i!="function")return{count:0};try{const p=i(t);return{count:Number(p?.count??0),...p?.oldestStartedAt?{oldestStartedAt:p.oldestStartedAt}:{}}}catch{return{count:0}}},"activeWork"),ue=n(t=>{const i=globalThis.__lensmcpStopWorkIntake;if(typeof i=="function")try{return i(t)}catch{return}},"stopWorkIntake"),se=n(t=>{const i=globalThis.__lensmcpWorkIntakeReport;if(!(t===void 0||typeof i!="function"))try{return i(t)??void 0}catch{return}},"workIntakeReport"),we=(()=>{const t=Number(process.env.LENSMCP_SWAP_MAX_DRAINING);return Number.isFinite(t)&&t>=1?Math.floor(t):1})(),Y=new Set,A=(0,swap_recycle_1.swapRecyclePolicy)();let H,K=0;const Ee=(()=>{const t=Number(process.env.LENSMCP_POD_RETIRE_NOTICE_MS);return Number.isFinite(t)&&t>=0?t:3500})();let ie=!1,Z=!1;const $e=(0,pod_memory_1.podMemoryPolicy)();let Se=0;const C=(0,pod_memory_1.createPodMemoryMonitor)({policy:$e,state:n(()=>({gen:j.gen??0,swaps:K,...H===void 0?{}:{baseline:H},busy:w||Q||N.size>0,lastBusyAt:O}),"state"),send:n(t=>{tell(process,t)},"send"),counter:(0,pod_memory_1.createLiveObjectCounter)(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH)),onRetained:n(()=>ce(),"onRetained")}),g=n(()=>((0,pod_memory_1.fullGc)()&&C.tracker.noteGc(),process.memoryUsage().heapUsed),"liveHeap"),P=(()=>{if(!(0,error_stack_release_1.errorFrameReleaseEnabled)())return null;try{const t=path.dirname(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH))+path.sep,i=`${path.sep}node_modules${path.sep}`,p=new Set(Object.keys(require.cache));return(0,error_stack_release_1.createErrorFrameReleaser)(require.cache,{skip:n(m=>p.has(m)||m.startsWith(t)&&!m.slice(t.length).includes(i)&&!m.slice(t.length).startsWith(`node_modules${path.sep}`),"skip")})}catch{return null}})();let E=!1;function B(){if(!(!P||E))try{const t=P();t.errors>0&&console.log(`[child] read the stack of ${t.errors} Error object(s) that libraries created while loading and keep for good \u2014 unread, each held the functions that were on its stack, this bundle's included`)}catch(t){console.error("[child] could not release library error frames:",t),E=!0}}h(B,"B"),n(B,"releaseLibraryErrorFrames");const N=new Map;let O=Date.now();const D=n(()=>A.settleMs<=0||!w&&!Q&&N.size===0&&Date.now()-O>=A.settleMs,"settled");let T;function $(t){if(!(!A.enabled||ie||Z)){if(A.settleMs<=0){V(t);return}T&&clearTimeout(T),T=setTimeout(()=>{T=void 0,D()?V(t):$(t)},A.settleMs),T.unref?.()}}h($,"D"),n($,"recycleCheckWhenSettled");const x=n(()=>{if(A.stuckCloseMs<=0)return 0;const t=Date.now();let i=0;for(const p of N.values())t-p>=A.stuckCloseMs&&(i+=1);return i},"stuckCloses");function V(t){if(!A.enabled||ie||Z||!process.send)return;const i=v8.getHeapStatistics().heap_size_limit,p=n(_=>{const S=C.oldestRetained();return{swaps:K,usedBytes:_,limitBytes:i,stuckCloses:x(),settled:D(),...H===void 0?{}:{baselineBytes:H},...S?{retained:{generation:S.gen,ageMs:Date.now()-S.closedAt,gcs:S.gcs}}:{}}},"state");if(!(0,swap_recycle_1.recycleReason)(A,p(process.memoryUsage().heapUsed)))return;const m=(0,swap_recycle_1.recycleReason)(A,p(g()));m&&(ie=!0,console.log(`[child] asking for a fresh pod ${t} \u2014 ${m}. This pod keeps serving until its successor is ready. Size the bound with LENSMCP_SWAP_RECYCLE_HEAP_FACTOR / _HEAP_RATIO / _MIN_MB / _RETAINED_MS, or turn it off with LENSMCP_SWAP_RECYCLE=0.`),tell(process,{type:"recycle-request",reason:m}))}h(V,"V"),n(V,"considerRecycle");let ae;function ce(){if(!A.enabled||A.retainedMs<=0||ie||Z)return;const t=C.oldestRetained();if(!t)return;const i=t.closedAt+A.retainedMs-Date.now();if(i<=0){V("with a closed generation still in memory");return}ae||(ae=setTimeout(()=>{ae=void 0,C.measure("retention-check").catch(()=>{})},i),ae.unref?.())}h(ce,"ce"),n(ce,"retainedRecycleCheck");function Pe(t,i){const p={};i&&(p.module=i),t&&(p.app=t);try{const m=t?.app;if(m&&typeof m=="object"&&(p.nestApp=m,m.container&&typeof m.container=="object")){p.container=m.container;const _=rootModuleOf(m.container);_&&(p.rootModule=_)}}catch{}return p}h(Pe,"Te"),n(Pe,"generationTargets");async function ee(t,i){if(t.closed||(t.closed=!0,Y.delete(t),i&&console.error(`[child] ${i}`),!t.app))return;N.set(t,Date.now());const p=A.enabled&&A.stuckCloseMs>0?setTimeout(()=>{N.has(t)&&(console.error(`[child] a previous app has been closing for ${Math.round(A.stuckCloseMs/1e3)}s and its close() has not returned \u2014 one of its shutdown hooks is waiting on something that does not end (a queue worker, a connection, a stream). It stays in memory until this pod is replaced.`),V("with a previous app stuck in close()"))},A.stuckCloseMs):void 0;p?.unref?.();const m=t.app;try{await t.app.close()}catch(_){console.error("[child] error closing a previous app:",_)}finally{N.delete(t),O=Date.now(),p&&clearTimeout(p),t.app=null,t.handler=(_,S)=>{S.statusCode=503,S.end("closed")},t.gen!==void 0&&C.closed(t.gen,K,Pe(m,t.module)),t.module=void 0}if(t.superseded){try{oe((0,hot_swap_registries_1.pruneRegistries)(t.superseded,"serve"),"after closing the previous app")}catch(_){console.error("[child] could not release the previous app's class registrations:",_)}t.superseded=void 0}$("after closing the previous app")}h(ee,"ae"),n(ee,"closeGeneration");async function le(t){for(;Y.size>=we;){const S=Y.values().next().value;if(!S)break;await ee(S,`closing a still-draining generation early \u2014 ${Y.size} were pending and the cap is ${we} (each holds a whole app: DI container, DB pool, queue workers). Raise LENSMCP_SWAP_MAX_DRAINING if this pod legitimately needs more.`)}Y.add(t);const i=Date.now(),p=n(()=>({inflight:t.inflight,work:I(t.workGen).count}),"busy");for(;ne>0&&Date.now()-i<ne;){if(t.closed)return;const S=p();if(S.inflight===0&&S.work===0)break;await new Promise(X=>{setTimeout(X,250).unref?.()})}if(t.closed)return;const m=p(),_=se(t.workGen);m.inflight>0||m.work>0?console.error(`[child] swap drain expired after ${Date.now()-i}ms \u2014 closing the previous app with ${m.inflight} in-flight request(s) and ${m.work} background job(s) still running. `+(_?`Previous app still processing ${_.running} queue job(s); ${_.takenAfterStop} were taken after the swap. `:"")+`A queue job killed here keeps its lock until the TTL lapses. Raise LENSMCP_SWAP_DRAIN_MS (currently ${ne}ms) if this is legitimate work.`):(Date.now()-i>250||_?.runningAtStop||_?.takenAfterStop)&&console.log(`[child] previous app drained in ${Date.now()-i}ms \u2014 closing it`+(_?` (it finished ${_.finishedAfterStop} queue job(s) after the swap; ${_.takenAfterStop} were taken after the swap)`:"")),await ee(t)}h(le,"le"),n(le,"drainThenClose");async function J(){if(w)return Q=!0,console.log("[child] Reload deferred \u2014 will re-swap after current swap completes"),f;w=!0,O=Date.now(),process.removeAllListeners("uncaughtException"),process.removeAllListeners("unhandledRejection"),process.on("uncaughtException",(k,z)=>{console.error(`[child] uncaughtException (${z}):`,k)}),process.on("unhandledRejection",k=>{const z=k instanceof Error?k.stack||k.message:String(k);z.includes("FronteggContextScope")||z.includes("populateLoggerMetadata")||console.error("[child] unhandledRejection:",k)});let t;if(Re)try{t=(0,hot_swap_registries_1.captureRegistries)()}catch{t=void 0}const i=global.__lensmcpBeginWorkGeneration,p=typeof i=="function"?i():void 0;try{try{await importFresh(BUNDLE_PATH)}catch(k){if(!(k instanceof SyntaxError))throw k;console.warn(`[child] bundle was unreadable mid-write (${k.message}) \u2014 retrying the swap once`),await new Promise(z=>setTimeout(z,400)),await importFresh(BUNDLE_PATH)}}catch(k){throw w=!1,O=Date.now(),k}if(typeof global.createChildApp!="function")throw w=!1,O=Date.now(),new Error(`Bundle '${BUNDLE_PATH}' does not export createChildApp() and the zero-touch bridge is not active. Either install @lensmcp/node-instrumentation (a plain NestFactory.create + app.listen main.ts then just works) or set global.createChildApp in main.ts when DEVSERVER_MODE === '1'.`);let m;if(t)try{m=(0,hot_swap_registries_1.supersededSince)(t),oe((0,hot_swap_registries_1.pruneRegistries)(m,"build"),"at the swap")}catch(k){console.error("[child] could not release superseded class registrations:",k)}let _;try{_=await global.createChildApp()}catch(k){throw w=!1,O=Date.now(),takeImportedModule(),k}const S=j;m?.size&&(S.app?S.superseded=m:oe((0,hot_swap_registries_1.pruneRegistries)(m,"serve"),"at the swap")),f=_;const X=takeImportedModule();j={app:_,handler:_.handler,inflight:0,gen:++Se,...X?{module:X}:{},...p===void 0?{}:{workGen:p}};const L=S.app&&p!==void 0?ue(p):void 0;return console.log("[child] Swapped to fresh app (previous draining in background)"+(L?.workers?`; its ${L.workers} queue worker(s) stopped taking new jobs, previous app still processing ${L.runningAtStop} job(s)`:"")),B(),S.app&&(K+=1,le(S).catch(k=>console.error("[child] background close error:",k)),setTimeout(()=>V("30s after a hot swap"),3e4).unref?.(),C.swapped(S.gen,()=>S.closed===!0&&!N.has(S))),w=!1,O=Date.now(),Q?(Q=!1,J()):_}h(J,"re"),n(J,"swapNow");const he=debounce(async()=>{try{console.log("[child] /webpack/reload"),await J()}catch(t){console.error("[child] reload failed:",t)}},250),q=http.createServer((t,i)=>{if(t.method==="POST"&&t.url==="/webpack/reload"){i.writeHead(200,{"content-type":"application/json"}),i.end(JSON.stringify({ok:!0})),he();return}if(t.method==="GET"&&t.url==="/__lensmcp/alive"){const m=t.headers["x-internal-token"],_=process.env.LENSMCP_SERVICE_KEY;if(_&&m!==_){i.writeHead(404,{"content-type":"text/plain"}),i.end("not found");return}const S=I();i.writeHead(200,{"content-type":"application/json","cache-control":"no-store"}),i.end(JSON.stringify({ok:!0,pid:process.pid,swapping:w,inflight:j.inflight,oldestInflightAt:j.oldestAt,activeWork:S.count,oldestWorkAt:S.oldestStartedAt,keyFingerprint:serviceKeyFingerprint(),...F?{watcher:F}:{},...Number.isFinite(Number(process.env.LENSMCP_POD_GENERATION))&&process.env.LENSMCP_POD_GENERATION?{podGeneration:Number(process.env.LENSMCP_POD_GENERATION)}:{}}));return}const p=j;p.inflight+=1,p.oldestAt===void 0&&(p.oldestAt=Date.now()),i.on("close",()=>{p.inflight-=1,p.inflight===0&&(p.oldestAt=void 0),C.activity()}),p.handler(t,i)});q.keepAliveTimeout=0;const G=process.env.CHILD_SOCK_PATH;process.on("disconnect",()=>{cleanupSock(G),process.exit(0)});try{const t=path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH);if((0,schema_first_instance_1.schemaPrewarmEnabled)())try{const i=(0,schema_first_instance_1.prewarmZodFor)(t);i?.created&&console.log(`[child] zod${i.version?` ${i.version}`:""}: built ${i.created} throwaway schemas first, so none of the bundle's own is the first of its class`)}catch{}if((0,redis_disconnect_fix_1.redisDisconnectFixEnabled)())try{const i=(0,redis_disconnect_fix_1.finishStrandedDisconnectsFor)(t);i?.patched&&console.log(`[child] ioredis${i.versions.length?` ${i.versions.join(", ")}`:""}: a disconnect() between reconnect attempts now ends the client \u2014 it used to leave a queue worker's close() waiting for good`)}catch{}await J(),H=(await C.booted()).live,console.log(`[child] Using bundle: ${t}`),claimSock(G),q.listen(G,()=>{console.log(`[child] Listening on ${G}`),tell(process,{type:"ready",socketPath:G})})}catch(t){console.error("[child] Startup error:",t),tell(process,{type:"boot-error",error:String(t?.stack||t)}),process.exitCode=1;return}process.on("message",async t=>{if(!(!t||typeof t!="object")){if(t.type==="debug-open"){const i=Number(t.port);s(Number.isInteger(i)&&i>1024?i:0);return}if(t.type==="watcher"){const i=t.testimony;i&&typeof i=="object"&&(F=i);return}if(t.type==="heap-snapshot"){ke(t);return}if(t.type==="recycle-declined"){ie=!1;return}if(t.type==="retire"){re();return}if(t.type==="reload"){if(Z)return;try{await J(),tell(process,{type:"reloaded",socketPath:G})}catch(i){console.error("[child] reload error:",i),tell(process,{type:"reload-error",error:String(i?.stack||i)})}}}});let te=!1;async function ke(t){const i=n(p=>{tell(process,{type:"heap-snapshot-result",id:t.id,...p})},"reply");if(te)return i({ok:!1,refused:"a snapshot of this pod is already being written"});te=!0;try{const p=g(),m=C.tracker.views().map(X=>X.gen),_=(0,heap_snapshot_1.heapSnapshotRefusal)((0,heap_snapshot_1.heapSnapshotPolicy)(),{live:p,...t.available?{available:t.available}:{}});if(_)return i({ok:!1,refused:_,live:p});console.log(`[child] writing a heap snapshot (${Math.round(p/1048576)} MB live) \u2014 the pod pauses while V8 serialises it`);const S=await(0,heap_snapshot_1.writeHeapSnapshot)(t.file);i({ok:!0,file:t.file,bytes:S.bytes,ms:S.ms,live:p,gen:j.gen??0,closedAlive:m})}catch(p){i({ok:!1,error:p?.message??String(p)})}finally{te=!1}}h(ke,"Ne"),n(ke,"takeHeapSnapshot");async function re(){if(Z)return;Z=!0,C.stop(),console.log("[child] retiring \u2014 a fresh pod has taken over; finishing in-flight work, then exiting");const t=ue(Number.POSITIVE_INFINITY);t?.workers&&console.log(`[child] its ${t.workers} queue worker(s) stopped taking new jobs, still processing ${t.runningAtStop} job(s)`);try{fs.writeFileSync(sockRetiringPath(G),String(process.pid),{flag:"w",mode:384})}catch{}await new Promise(p=>{setTimeout(p,Ee).unref?.()}),cleanupSock(G),q.close();const i=Date.now();for(;Date.now()-i<ne&&(q.closeIdleConnections?.(),!(j.inflight===0&&I().count===0));)await new Promise(p=>{setTimeout(p,250).unref?.()});setTimeout(()=>process.exit(0),3e4).unref?.();try{await f?.close()}catch(p){console.error("[child] close error while retiring:",p)}process.exit(0)}h(re,"de"),n(re,"retire"),process.on("beforeExit",()=>{try{inspector?.close?.()}catch{}});const fe=n(async t=>{console.log(`[child ${t}] shutting down\u2026`);const i=f?.close().catch(m=>console.error("[child] close error:",m)),p=new Promise(m=>q.close(()=>m()));cleanupSock(G),setTimeout(()=>process.exit(0),700).unref(),await Promise.all([i,p]),process.exit(0)},"shutdown");["SIGINT","SIGTERM","SIGHUP","SIGQUIT","SIGUSR2"].forEach(t=>{process.on(t,()=>{inspector?.close?.(),fe(t)})})})()}else{let s=h(function(g){H.push(g),H.length>A&&H.splice(0,H.length-A),we?.write((0,inspector_secret_1.redactInspectorUrls)(g.replace(Y,"")));for(const P of K)try{const E=P.plain?g.replace(Y,""):g;P.res.write(P.redact?(0,inspector_secret_1.redactInspectorUrls)(E):E)}catch{K.delete(P)}},"Z");n(s,"emitLogLine");const u=12,f=process.env.LENSMCP_PROJECT||SERVICE_NAME||"service",w=(0,pod_memory_events_1.createPodMemoryPublisher)(process.env.LENSMCP_EVENT_FILE),F=n(g=>({project:f,service:SERVICE_NAME||f,pod:g.id,pid:g.proc.pid??0,podGeneration:POD_GENERATION}),"podIdentity"),Q=["\x1B[36m","\x1B[33m","\x1B[35m","\x1B[32m","\x1B[34m","\x1B[31m"],Re="\x1B[0m",oe=Math.max(1,Number(process.env.CHILD_COUNT||1)),j=LENSMCP_WS_KEY||path.basename(process.cwd()),ne=n(g=>(0,process_name_1.namedExecPath)((0,process_name_1.processName)(j,SERVICE_NAME||"service",g)),"execPathFor");let I=(()=>{const g=Number(process.env.LENSMCP_DEBUG_PORT||"");return Number.isInteger(g)&&g>1024?g:0})();const ue=20;I&&(console.warn("[parent] DEBUGGER ENABLED \u2014 pods and workers open a Node inspector. Node's inspector has NO authentication: the ws:// URL's UUID is the whole credential, and any account on this host that obtains it can run code as you. Do not enable this on a shared machine. (issues/closed/codex-security-06)"),console.warn(usesFixedInspectorPorts()?`[parent] ${exports.DEBUG_FIXED_PORTS_ENV} is set \u2014 inspectors bind PREDICTABLE ports (${I}+slot, workers ${I}+${ue}+i). Any account on this host can connect to 127.0.0.1:${I} and read the session UUID from /json/list. Unset it to use ephemeral ports.`:`[parent] Inspectors bind an EPHEMERAL loopback port; attach via the printed "Debugger listening" URL, or \`lensmcp debug <service>\` (control socket). Set ${exports.DEBUG_FIXED_PORTS_ENV}=1 for fixed ports if your IDE needs a pre-configured attach port \u2014 any account on this host can then reach them.`));const se=process.env.LENSMCP_LOG_FILE||"",we=se?(()=>{try{fs.mkdirSync(path.dirname(se),{recursive:!0});const g=fs.createWriteStream(se,{flags:"a",mode:384});try{fs.chmodSync(se,384)}catch{}return g}catch(g){return console.warn(`[parent] cannot open log file ${se}:`,g.message),null}})():null,Y=/\x1b\[[0-9;]*m/g,A=2e3,H=[],K=new Set,Ee=gatewayManaged();for(const g of["log","info","warn","error"]){const P=console[g].bind(console),E=g==="log"||g==="info"?process.stdout:process.stderr;console[g]=(...B)=>{P(...B.map(N=>typeof N=="string"?(0,inspector_secret_1.forStream)(E,Ee,N):N)),s(B.map(N=>typeof N=="string"?N:util.inspect(N)).join(" ")+`
13
- `)}}const ie=n(g=>Q[(g-1)%Q.length],"colorFor"),Z=n(g=>{if(oe===1)return"";const P=`[child#${g}] `;return`${ie(g)}${P}${Re}`},"tagFor"),$e=n(g=>g.startsWith("{")&&g.endsWith("}"),"isJsonLog"),Se=n((g,P,E)=>{const B=prettyFactory({sync:!0,colorize:!0,crlf:!0,messageKey:"message",errorLikeObjectKeys:["err","error"],errorProps:"type,message,stack",ignore:["logContext","context","hostname","req","res","err.driverError","module","cloudEnvironment","frontegg-application-id","frontegg-tenant-id","frontegg-trace-id","frontegg-vendor-id","host","service","version","err","error"].join(","),messageFormat:"{if module}[{module}] {end}{if context}[{context}] {end}{if logContext}[{logContext}] {end}{message}",customPrettifiers:{stack:n(D=>`
14
- `+String(D),"stack")}}),N=n((D,T)=>{const $=D==="stdout"?process.stdout:process.stderr;try{E?.(T)}catch{}const x=$e(T)?B(T):`${T}
15
- `;$.write((0,inspector_secret_1.forStream)($,Ee,`${P}${x}`)),s(`${P}${x}`)},"write"),O=n((D,T)=>{if(!D)return;const $=readline.createInterface({input:D});$.on("line",x=>N(T,x)),$.on("close",()=>{})},"attach");O(g.stdout,"stdout"),O(g.stderr,"stderr")},"wireProcLogging"),C=n(g=>Se(g.proc,Z(g.id),P=>g.tail.push(P)),"wireChildLogging");(async()=>{ensureOwnerOnlyDir(SOCK_DIR);const g=httpProxy.createProxyServer({});let P=Number(process.env.PORT)||0;P||(P=9090);const E=[],B=new Set;function N(){let e=0;for(;B.has(e);)e++;return B.add(e),e}h(N,"R"),n(N,"allocDebugSlot");let O=1,D=0,T=!1,$=oe,x=[],V=0;const ae=(()=>{const e=Number(process.env.LENSMCP_POD_BOOT_GRACE_MS);return Number.isFinite(e)&&e>=0?e:12e4})(),ce=n(e=>e.proc.exitCode!==null||e.proc.signalCode!==null,"childExited"),Pe=n(e=>e.booting&&!ce(e)&&Date.now()-e.spawnedAt<ae,"stillBooting");function ee(){return E.filter(e=>e.healthy&&typeof e.socketPath=="string")}h(ee,"ae"),n(ee,"healthyChildren");let le;function J(e){if(!e||typeof e!="object")return;const o=e;if(o.schemaVersion===1){le=o;for(const c of E)tell(c.proc,{type:"watcher",testimony:o})}}h(J,"re"),n(J,"recordWatcherTestimony");function he(e,o=256*1024){return new Promise(c=>{let d="",a=!1;e.on("data",r=>{a||(d+=r,d.length>o&&(a=!0))}),e.on("end",()=>{if(a||!d)return c(void 0);try{c(JSON.parse(d))}catch{c(void 0)}}),e.on("error",()=>c(void 0))})}h(he,"we"),n(he,"readJsonBody");function q(){const e=ee();if(e.length===0)return null;const o=D%e.length;return D=(D+1)%e.length,e[o]}h(q,"j"),n(q,"pickChild");function G(e,o){const c=`Child#${e.id}`,d=SERVICE_NAME||f,a=Date.now();if(o.type==="pod-memory"){const r=o.report;if(!r||typeof r.live!="number")return;e.memory.latest=r,e.memory.history.push(r),e.memory.history.length>12&&e.memory.history.splice(0,e.memory.history.length-12),console.log(`[parent] ${(0,pod_memory_1.describePodMemory)(c,r)}`),w.publish((0,pod_memory_events_1.buildPodMemoryEvent)(F(e),r))}else if(o.type==="pod-memory-retained"){const r=o.retained;if(!r||typeof r.gen!="number")return;e.memory.retained.set(r.gen,{...r,at:a}),console.warn(`[parent] ${(0,pod_memory_1.describeRetained)(c,d,r)}`),w.publish((0,pod_memory_events_1.buildPodRetainedEvent)(F(e),r,a))}else{const r=o.released;if(!r||typeof r.gen!="number")return;e.memory.retained.delete(r.gen),console.log(`[parent] ${(0,pod_memory_1.describeReleased)(c,d,r)}`),w.publish((0,pod_memory_events_1.buildPodReleasedEvent)(F(e),r,a))}}h(G,"U"),n(G,"recordPodMemory");const te=new Map;let ke=0;async function re(){const e=O++,o=childSockPath(e);cleanupSock(o);const c=(0,dev_devtool_1.sourceMapExecArgv)();__filename.endsWith(".ts")&&c.unshift("--require","@swc-node/register"),c.push(...(0,inspector_secret_1.inspectorPublishExecArgv)(usesFixedInspectorPorts()));const d=I?N():-1,a=(0,node_child_process_1.fork)(__filename,{env:{...process.env,APP_RUNNER:"1",CHILD_SOCK_PATH:o,...d>=0&&{CHILD_DEBUG_PORT:String(inspectorPortFor(I,d))}},stdio:["inherit","pipe","pipe","ipc"],execArgv:c,execPath:ne("pod")}),r={id:e,proc:a,healthy:!1,lastError:null,debugSlot:d,tail:new exit_reason_1.TailBuffer,booting:!0,spawnedAt:Date.now(),bootReloadSeq:V,memory:{history:[],retained:new Map}};return a.on("error",y=>console.error(`[parent] Child#${e}: ${y.message}`)),a.on("message",y=>{if(!y||typeof y!="object")return;const l=y;l.type==="ready"?(r.socketPath=String(l.socketPath),r.healthy=!0,r.booting=!1,console.log(`[parent] Child#${r.id} ready on socket ${r.socketPath}`),le&&tell(a,{type:"watcher",testimony:le}),V!==r.bootReloadSeq&&tell(a,{type:"reload"})):l.type==="recycle-request"?X(r,String(l.reason||"it has outgrown its bound")):l.type==="inspector-url"?(r.inspectorUrl=String(l.url),console.log(`[parent] Child#${r.id} Debugger listening on ${l.url}`)):l.type==="reloaded"?(r.socketPath=String(l.socketPath),r.healthy=!0,console.log(`[parent] Child#${r.id} hot-swapped on socket ${r.socketPath}`)):l.type==="reload-error"?(r.lastError=String(l.error||"unknown reload error"),console.error(`[parent] Child#${r.id} reload error: ${r.lastError}`),r.healthy=!1):l.type==="boot-error"?(r.lastError=String(l.error||"unknown boot error"),console.error(`[parent] Child#${r.id} boot error: ${r.lastError}`),r.healthy=!1,r.booting=!1):l.type==="pod-memory"||l.type==="pod-memory-retained"||l.type==="pod-memory-released"?G(r,l):l.type==="heap-snapshot-result"&&te.get(Number(l.id))?.(l)}),a.on("exit",(y,l)=>{r.booting=!1;for(const R of r.memory.retained.values()){const W={gen:R.gen,closedAt:R.closedAt,ageMs:Date.now()-R.closedAt,reason:"pod-exited"};console.log(`[parent] ${(0,pod_memory_1.describeReleased)(`Child#${r.id}`,SERVICE_NAME||f,W)}`),w.publish((0,pod_memory_events_1.buildPodReleasedEvent)(F(r),W,Date.now()))}r.memory.retained.clear(),r.memory.latest&&w.publish((0,pod_memory_events_1.buildPodExitedEvent)(F(r),{code:y,signal:l},Date.now())),r.debugSlot>=0&&(B.delete(r.debugSlot),r.debugSlot=-1);const v=l==="SIGINT"||l==="SIGTERM"||y===0;if(v?console.log(`[parent] Child#${r.id} exited cleanly (code=${y}, signal=${l??"none"})`):(console.error((0,exit_reason_1.crashReport)(`[parent] Child#${r.id} crashed (code=${y}, signal=${l??"none"}, pid=${r.proc.pid}, ${r.healthy?"was serving":"was not ready"})`,y,l,r.tail.snapshot())),r.lastError||(r.lastError=`Child exited abnormally (code=${y}, signal=${l??"none"})`)),r.healthy=!1,cleanupSock(r.socketPath,r.proc.pid),r.socketPath=void 0,!v&&!T){const R=E.indexOf(r);R>=0&&E.splice(R,1);const W=Date.now();if(x=x.filter(U=>W-U<3e4),x.length>=5){console.error(`[parent] crash-loop detected (${x.length} respawns/30s) \u2014 pausing auto-respawn; POST /webpack/reload to retry`);return}x.push(W),setTimeout(()=>{const U=E.filter(de=>de.proc.killed===!1).length;!T&&U<$&&(console.log(`[parent] respawning a crashed pod (${U}/${$} live)`),re().catch(()=>{}))},1500).unref?.()}}),E.push(r),C(r),r}h(re,"de"),n(re,"spawnChild");async function fe(e){$=Math.max($,e);const o=E.filter(d=>d.proc.killed===!1),c=e-o.length;for(let d=0;d<c;d++)await re()}h(fe,"Ee"),n(fe,"ensurePoolSize");async function t(){const e=E.filter(o=>(!o.healthy||typeof o.socketPath!="string")&&!Pe(o));await Promise.all(e.map(async o=>{try{o.proc.kill("SIGTERM")}catch{}cleanupSock(o.socketPath,o.proc.pid),o.socketPath=void 0;const c=E.indexOf(o);c>=0&&E.splice(c,1),await re()}))}h(t,"t"),n(t,"respawnUnhealthy");const i=new Set;let p=!1,m=0;const _=3e4,S=(()=>{const e=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return(Number.isFinite(e)&&e>=0?e:15*6e4)+6e4})();async function X(e,o){const c=n(a=>{console.log(`[parent] Child#${e.id} asked for a fresh pod (${o}) \u2014 not now: ${a}`),tell(e.proc,{type:"recycle-declined"})},"decline");if(T||!E.includes(e))return;if(p)return c("another pod is already being replaced");const d=Date.now()-m;if(d<_)return c(`a pod was replaced ${Math.round(d/1e3)}s ago`);p=!0,console.log(`[parent] Child#${e.id} asked for a fresh pod \u2014 ${o}. Starting one; Child#${e.id} keeps serving until it is ready.`);try{const a=await re(),r=Date.now()+ae;for(;!a.healthy&&!a.lastError&&!ce(a)&&Date.now()<r;)await new Promise(v=>{setTimeout(v,100).unref?.()});if(T)return;if(!a.healthy){const v=E.indexOf(a);v>=0&&E.splice(v,1);try{a.proc.kill("SIGTERM")}catch{}return c(`its successor Child#${a.id} did not come up (${a.lastError??"no answer in time"})`)}const y=E.indexOf(e);y>=0&&E.splice(y,1),e.healthy=!1,i.add(e);const l=setTimeout(()=>{if(!ce(e)){console.error(`[parent] Child#${e.id} was still running ${S}ms after it was retired \u2014 killing it`);try{e.proc.kill("SIGKILL")}catch{}}},S);if(l.unref?.(),e.proc.once("exit",()=>{clearTimeout(l),i.delete(e)}),!tell(e.proc,{type:"retire"}))try{e.proc.kill("SIGTERM")}catch{}m=Date.now(),console.log(`[parent] Child#${a.id} took over from Child#${e.id} (pid ${e.proc.pid} \u2192 ${a.proc.pid})`)}catch(a){c(`could not start a successor: ${a?.message??String(a)}`)}finally{p=!1}}h(X,"q"),n(X,"recyclePod");const L=[];function k(e){const o=path.dirname(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.resolve(BUNDLE_PATH)),c=path.join(o,`${e}.js`);if(!fs.existsSync(c))return console.error(`[parent] Worker "${e}" bundle not found: ${c}`),null;const d=(0,dev_devtool_1.sourceMapExecArgv)();__filename.endsWith(".ts")&&d.unshift("--require","@swc-node/register");try{d.push("--require",require.resolve("@lensmcp/node-instrumentation/register"))}catch{}const a=inspectorPortFor(I||9229,ue+Math.max(0,WORKER_NAMES.indexOf(e)));d.push(I?`--inspect=127.0.0.1:${a}`:`--inspect-port=127.0.0.1:${a}`,...(0,inspector_secret_1.inspectorPublishExecArgv)(usesFixedInspectorPorts()));const r=(0,node_child_process_1.fork)(c,{env:process.env,stdio:["inherit","pipe","pipe","ipc"],execArgv:d,execPath:ne(`w-${e}`)}),y={name:e,proc:r,debugPort:a};return L.push(y),r.on("error",l=>console.error(`[parent] Worker "${e}": ${l.message}`)),Se(r,`\x1B[35m[worker:${e}] \x1B[0m`,l=>{const v=/Debugger listening on (wss?:\/\/\S+)/.exec(l);v&&(y.inspectorUrl=v[1])}),r.on("exit",(l,v)=>{v==="SIGINT"||v==="SIGTERM"||l===0||console.error(`[parent] Worker "${e}" crashed (code=${l}, signal=${v??"none"})`);const R=L.indexOf(y);R>=0&&L.splice(R,1)}),console.log(`[parent] Worker "${e}" started (pid=${r.pid})`),y}h(k,"A"),n(k,"spawnWorkerProcess");const z=(()=>{const e=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return Number.isFinite(e)&&e>=0?e:15*6e4})(),Oe=(()=>{const e=Number(process.env.LENSMCP_SWAP_MAX_DRAINING);return Number.isFinite(e)&&e>=1?Math.floor(e):1})(),ge=new Set,De=n(e=>e.proc.exitCode!==null||e.proc.signalCode!==null,"workerExited");function ve(e,o){if(ge.delete(e),!De(e)){console.error(`[parent] Worker "${e.name}" (pid=${e.proc.pid}) ${o} \u2014 killing it. A worker that returns from its SIGTERM handler but leaves a handle open (a Redis client handed to BullMQ is not closed by worker.close()) never exits on its own: close what it opened, or call process.exit().`);try{e.proc.kill("SIGKILL")}catch{}}}h(ve,"Ie"),n(ve,"killDrainingWorker");function Ce(e){try{e.proc.kill("SIGTERM")}catch{}if(De(e))return;const o=[...ge].filter(d=>d.name===e.name);for(;o.length>=Oe;)ve(o.shift(),`was still running when a later reload replaced its successor (cap ${Oe})`);ge.add(e);const c=setTimeout(()=>ve(e,`was still running ${z}ms after SIGTERM`),z);c.unref?.(),e.proc.once("exit",()=>{clearTimeout(c),ge.delete(e)})}h(Ce,"Ge"),n(Ce,"retireWorker");function xe(){for(const e of[...L])Ce(e);L.length=0;for(const e of WORKER_NAMES)k(e)}h(xe,"We"),n(xe,"restartWorkers");const Fe=debounce(async()=>{V+=1;const e=ee();if(e.length>0){console.log(`[parent] Forwarding reload to ${e.length} child(ren)`);for(const o of e)tell(o.proc,{type:"reload"})}await t(),WORKER_NAMES.length>0&&xe()},200),ye=n(async(e,o)=>{if(e.method==="POST"&&e.url==="/webpack/reload"){if(!mayDriveThePool(e))return refusePoolCommand(e,o);o.writeHead(200,{"content-type":"application/json"}),o.end(JSON.stringify({ok:!0})),he(e).then(a=>J(a?.watcher)),Fe();return}if(e.method==="POST"&&e.url==="/webpack/watching"){if(!mayDriveThePool(e))return refusePoolCommand(e,o);const a=await he(e);J(a),o.writeHead(200,{"content-type":"application/json"}),o.end(JSON.stringify({ok:!0,relayed:le!==void 0}));return}if(e.method==="POST"&&e.url==="/webpack/scale"){if(!mayDriveThePool(e))return refusePoolCommand(e,o);let a="";e.on("data",r=>{a+=r}),e.on("end",async()=>{let r=0;try{r=Number(JSON.parse(a||"{}").pods)||0}catch{}r=Math.max(1,Math.min(r,16)),await fe(r),o.writeHead(200,{"content-type":"application/json"}),o.end(JSON.stringify({ok:!0,pods:r}))});return}if(e.method==="GET"&&e.url?.startsWith("/webpack/logs")){const a=new URL(e.url,"http://localhost").searchParams,r=Math.min(Math.max(Number(a.get("tail")??"100")||0,0),A),y=a.get("follow")!=="0",l=a.get("plain")==="1",v=!isOwnerOnlyTransport(e);o.writeHead(200,{"content-type":"text/plain; charset=utf-8","cache-control":"no-cache"});const R=r===0?"":H.slice(-r).join(""),W=l?R.replace(Y,""):R;if(o.write(v?(0,inspector_secret_1.redactInspectorUrls)(W):W),!y){o.end();return}const U={res:o,plain:l,redact:v};K.add(U),e.on("close",()=>K.delete(U));return}if(e.method==="POST"&&e.url?.startsWith("/webpack/debug")){if(!isOwnerOnlyTransport(e)){o.writeHead(404,{"content-type":"application/json"}),o.end(JSON.stringify({error:"not found"}));return}const a=Number(new URL(e.url,"http://localhost").searchParams.get("port")||"");Number.isInteger(a)&&a>1024&&(I=a),I||(I=9229);const r=E.filter(l=>l.proc.exitCode===null&&l.proc.signalCode===null);for(const l of r)l.debugSlot<0&&(l.debugSlot=N()),tell(l.proc,{type:"debug-open",port:inspectorPortFor(I,l.debugSlot)});for(const l of L)try{l.proc.kill("SIGUSR1")}catch{}const y=Date.now()+2e3;for(;Date.now()<y&&r.some(l=>!l.inspectorUrl);)await new Promise(l=>setTimeout(l,50));o.writeHead(200,{"content-type":"application/json"}),o.end(JSON.stringify({ok:!0,basePort:I,fixedPorts:usesFixedInspectorPorts(),pods:r.map(l=>({id:l.id,inspectorUrl:l.inspectorUrl??null})),workers:L.map(l=>({name:l.name,port:l.debugPort||inspectorPortOf(l.inspectorUrl),inspectorUrl:l.inspectorUrl??null}))},null,2)+`
16
- `);return}if(e.method==="GET"&&e.url==="/webpack/memory"){if(!isOwnerOnlyTransport(e)){o.writeHead(404,{"content-type":"application/json"}),o.end(JSON.stringify({error:"not found"}));return}const a=path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.resolve(BUNDLE_PATH),r=[...E,...i].map(y=>({id:y.id,pid:y.proc.pid??0,podGeneration:POD_GENERATION,healthy:y.healthy,retiring:i.has(y),latest:y.memory.latest??null,history:y.memory.history,retained:[...y.memory.retained.values()]}));o.writeHead(200,{"content-type":"application/json","cache-control":"no-store"}),o.end(JSON.stringify({ok:!0,service:SERVICE_NAME,project:f,bundle:{path:a},pods:r},null,2)+`
17
- `);return}if(e.method==="POST"&&e.url?.startsWith("/webpack/heap")){if(!isOwnerOnlyTransport(e)){o.writeHead(404,{"content-type":"application/json"}),o.end(JSON.stringify({error:"not found"}));return}const a=n((M,_e)=>{o.writeHead(M,{"content-type":"application/json"}),o.end(JSON.stringify(_e,null,2)+`
18
- `)},"reply"),r=Number(new URL(e.url,"http://localhost").searchParams.get("pod")||""),y=Number.isInteger(r)&&r>0?E.find(M=>M.id===r):ee()[0];if(!y||ce(y)){a(404,{ok:!1,error:r?`no pod #${r} \u2014 running: ${E.map(M=>`#${M.id}`).join(", ")||"none"}`:"no pod is serving"});return}if(te.size>0){a(409,{ok:!1,refused:"a heap snapshot is already being written for this service"});return}const l=(0,heap_snapshot_1.heapSnapshotPolicy)(),v=(0,heap_snapshot_1.heapSnapshotDir)();let R;try{(0,heap_snapshot_1.ensureHeapDir)(v);const M=(0,heap_snapshot_1.pruneHeapSnapshots)(v,l);M.length&&console.log(`[parent] removed ${M.length} older heap snapshot(s) from ${v}`),R=path.join(v,(0,heap_snapshot_1.heapSnapshotFileName)(SERVICE_NAME||f,y.id,y.proc.pid??0,y.memory.latest?.gen??0,Date.now()))}catch(M){a(500,{ok:!1,error:`cannot prepare ${v}: ${M.message}`});return}const W=++ke,U=(0,heap_snapshot_1.availableSystemMemory)();let de;const b=await new Promise(M=>{const _e=setTimeout(()=>M(void 0),6e5);_e.unref?.(),te.set(W,qe=>{clearTimeout(_e),M(qe)}),de=n(()=>{clearTimeout(_e),M(void 0)},"onExit"),y.proc.once("exit",de),tell(y.proc,{type:"heap-snapshot",id:W,file:R,...U?{available:U}:{}})||de()}).finally(()=>{te.delete(W),de&&y.proc.off("exit",de)});if(!b){a(504,{ok:!1,pod:y.id,error:"the pod did not finish the snapshot (it exited, or took longer than 10 minutes)"});return}b.ok?console.log(`[parent] Child#${y.id} wrote a ${Math.round((b.bytes??0)/1048576)} MB heap snapshot in ${b.ms} ms \u2192 ${b.file}`):console.warn(`[parent] Child#${y.id} heap snapshot not taken: ${b.refused??b.error}`),a(b.ok?200:b.refused?409:500,{ok:b.ok,pod:y.id,pid:y.proc.pid??0,service:SERVICE_NAME,bundle:path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.resolve(BUNDLE_PATH),...U?{available:U}:{},...b.file?{file:b.file,bytes:b.bytes,ms:b.ms}:{},...b.live!==void 0?{live:b.live}:{},...b.gen!==void 0?{gen:b.gen,closedAlive:b.closedAlive??[]}:{},...b.refused?{refused:b.refused}:{},...b.error?{error:b.error}:{}});return}const c=matchGatewayRoute(e);if(c?.prependPrefix&&!e.url?.startsWith(c.prependPrefix)&&(e.url=c.prependPrefix+(e.url??"/")),c?.target){applyGatewayMiddleware(e),g.web(e,o,{target:c.target,autoRewrite:typeof c.target=="string",changeOrigin:!0},a=>{console.error(`[parent] proxy error to ${c.target}:`,a),o.statusCode=502,o.setHeader("content-type","text/plain; charset=utf-8"),o.end(`Upstream error from ${c.target}.`)});return}if(SERVICE_PREFIX){if(!e.url?.startsWith(SERVICE_PREFIX)){o.writeHead(404,{"content-type":"text/plain; charset=utf-8"}),o.end(`Not found. This service is mounted at ${SERVICE_PREFIX}/`);return}e.url=e.url.slice(SERVICE_PREFIX.length)||"/"}applyGatewayMiddleware(e);const d=q();if(!d){o.statusCode=503,o.setHeader("content-type","text/plain; charset=utf-8");const a=E.map(r=>`#${r.id}: ${r.lastError??"no error recorded"}`).join(`
12
+ })()`),(0,bundle_parent_1.routeBundleRequires)(requested,resolved);const exports=eval(`require(${JSON.stringify(resolved)})`);try{const mod=eval("require.cache")[resolved];lastImportedModule=mod&&typeof mod=="object"?mod:void 0}catch{}return exports}h(importFresh,"importFresh"),n(importFresh,"importFresh");function debounce(s,u){let f=null;return(...S)=>{f&&clearTimeout(f),f=setTimeout(()=>s(...S),u)}}if(h(debounce,"debounce"),n(debounce,"debounce"),process.env.APP_RUNNER==="1"){(0,stdio_guard_1.guardBrokenStdio)();const s=n(f=>{if(!inspector.url())try{inspector.open(f,"127.0.0.1",!1)}catch(G){console.warn(`[child] inspector.open(${f}) failed (port taken by another devserver?) \u2014 falling back to a random port:`,G.message);try{inspector.open(0,"127.0.0.1",!1)}catch{}}const S=inspector.url();S&&tell(process,{type:"inspector-url",url:S})},"openInspector"),u=process.env.CHILD_DEBUG_PORT;if(u!==void 0&&u!==""){const f=Number(u);Number.isInteger(f)&&(f===0||f>1024)&&s(f)}try{require("@lensmcp/node-instrumentation/register")}catch{}(async()=>{let f=null,S=!1,G,J=!1;const De=(0,hot_swap_registries_1.registryPruningEnabled)(),te=n((t,i)=>{const p=(0,hot_swap_registries_1.describePrune)(t,i);p&&console.log(p)},"logPrune");let F={app:null,handler:n((t,i)=>{i.statusCode=503,i.end("starting")},"handler"),inflight:0};const re=(()=>{const t=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return Number.isFinite(t)&&t>=0?t:15*6e4})(),R=n(t=>{const i=globalThis.__lensmcpActiveWork;if(typeof i!="function")return{count:0};try{const p=i(t);return{count:Number(p?.count??0),...p?.oldestStartedAt?{oldestStartedAt:p.oldestStartedAt}:{}}}catch{return{count:0}}},"activeWork"),ge=n(t=>{const i=globalThis.__lensmcpStopWorkIntake;if(typeof i=="function")try{return i(t)}catch{return}},"stopWorkIntake"),oe=n(t=>{const i=globalThis.__lensmcpWorkIntakeReport;if(!(t===void 0||typeof i!="function"))try{return i(t)??void 0}catch{return}},"workIntakeReport"),be=(()=>{const t=Number(process.env.LENSMCP_SWAP_MAX_DRAINING);return Number.isFinite(t)&&t>=1?Math.floor(t):1})(),q=new Set,A=(0,swap_recycle_1.swapRecyclePolicy)();let L,j=0;const Ae=(()=>{const t=Number(process.env.LENSMCP_POD_RETIRE_NOTICE_MS);return Number.isFinite(t)&&t>=0?t:3500})();let ne=!1,X=!1;const xe=(0,pod_memory_1.podMemoryPolicy)();let Ne=0;const me=new Set;let y=!1;const v=n(()=>{if(!y)return;let t=0;for(const i of me)i.deref()===void 0?me.delete(i):t+=1;return t},"liveContainers"),_=(0,pod_memory_1.createPodMemoryMonitor)({policy:xe,state:n(()=>({gen:F.gen??0,swaps:j,...L===void 0?{}:{baseline:L},busy:S||J||N.size>0,lastBusyAt:T}),"state"),send:n(t=>{tell(process,t)},"send"),containers:v,counter:(0,pod_memory_1.createLiveObjectCounter)(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH)),onRetained:n(()=>ie(),"onRetained")}),W=n(()=>((0,pod_memory_1.fullGc)()&&_.tracker.noteGc(),process.memoryUsage().heapUsed),"liveHeap"),$=(()=>{if(!(0,error_stack_release_1.errorFrameReleaseEnabled)())return null;try{const t=path.dirname(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH))+path.sep,i=`${path.sep}node_modules${path.sep}`,p=new Set(Object.keys(require.cache));return(0,error_stack_release_1.createErrorFrameReleaser)(require.cache,{skip:n(g=>p.has(g)||g.startsWith(t)&&!g.slice(t.length).includes(i)&&!g.slice(t.length).startsWith(`node_modules${path.sep}`),"skip")})}catch{return null}})();let se=!1;function x(){if(!(!$||se))try{const t=$();t.errors>0&&console.log(`[child] read the stack of ${t.errors} Error object(s) that libraries created while loading and keep for good \u2014 unread, each held the functions that were on its stack, this bundle's included`)}catch(t){console.error("[child] could not release library error frames:",t),se=!0}}h(x,"C"),n(x,"releaseLibraryErrorFrames");const N=new Map;let T=Date.now();const C=n(()=>A.settleMs<=0||!S&&!J&&N.size===0&&Date.now()-T>=A.settleMs,"settled");let V;function he(t){if(!(!A.enabled||ne||X)){if(A.settleMs<=0){z(t);return}V&&clearTimeout(V),V=setTimeout(()=>{V=void 0,C()?z(t):he(t)},A.settleMs),V.unref?.()}}h(he,"_e"),n(he,"recycleCheckWhenSettled");const fe=n(()=>{if(A.stuckCloseMs<=0)return 0;const t=Date.now();let i=0;for(const p of N.values())t-p>=A.stuckCloseMs&&(i+=1);return i},"stuckCloses");function z(t){if(!A.enabled||ne||X||!process.send)return;const i=v8.getHeapStatistics().heap_size_limit,p=n(m=>{const E=_.oldestRetained();return{swaps:j,usedBytes:m,limitBytes:i,stuckCloses:fe(),settled:C(),...L===void 0?{}:{baselineBytes:L},...E?{retained:{generation:E.gen,ageMs:Date.now()-E.closedAt,gcs:E.gcs}}:{}}},"state");if(!(0,swap_recycle_1.recycleReason)(A,p(process.memoryUsage().heapUsed)))return;const g=(0,swap_recycle_1.recycleReason)(A,p(W()));g&&(ne=!0,console.log(`[child] asking for a fresh pod ${t} \u2014 ${g}. This pod keeps serving until its successor is ready. Size the bound with LENSMCP_SWAP_RECYCLE_HEAP_FACTOR / _HEAP_RATIO / _MIN_MB / _RETAINED_MS, or turn it off with LENSMCP_SWAP_RECYCLE=0.`),tell(process,{type:"recycle-request",reason:g}))}h(z,"ee"),n(z,"considerRecycle");let Y;function ie(){if(!A.enabled||A.retainedMs<=0||ne||X)return;const t=_.oldestRetained();if(!t)return;const i=t.closedAt+A.retainedMs-Date.now();if(i<=0){z("with a closed generation still in memory");return}Y||(Y=setTimeout(()=>{Y=void 0,_.measure("retention-check").catch(()=>{})},i),Y.unref?.())}h(ie,"ae"),n(ie,"retainedRecycleCheck");function ae(t,i){const p={};i&&(p.module=i),t&&(p.app=t);try{const g=t?.app;if(g&&typeof g=="object"&&(p.nestApp=g,g.container&&typeof g.container=="object")){p.container=g.container;const m=rootModuleOf(g.container);m&&(p.rootModule=m)}}catch{}return p}h(ae,"ye"),n(ae,"generationTargets");async function ce(t,i){if(t.closed||(t.closed=!0,q.delete(t),i&&console.error(`[child] ${i}`),!t.app))return;N.set(t,Date.now());const p=A.enabled&&A.stuckCloseMs>0?setTimeout(()=>{N.has(t)&&(console.error(`[child] a previous app has been closing for ${Math.round(A.stuckCloseMs/1e3)}s and its close() has not returned \u2014 one of its shutdown hooks is waiting on something that does not end (a queue worker, a connection, a stream). It stays in memory until this pod is replaced.`),z("with a previous app stuck in close()"))},A.stuckCloseMs):void 0;p?.unref?.();const g=t.app;try{await t.app.close()}catch(m){console.error("[child] error closing a previous app:",m)}finally{N.delete(t),T=Date.now(),p&&clearTimeout(p),t.app=null,t.handler=(m,E)=>{E.statusCode=503,E.end("closed")},t.gen!==void 0&&_.closed(t.gen,j,ae(g,t.module)),t.module=void 0}if(t.superseded){try{te((0,hot_swap_registries_1.pruneRegistries)(t.superseded,"serve"),"after closing the previous app")}catch(m){console.error("[child] could not release the previous app's class registrations:",m)}t.superseded=void 0}he("after closing the previous app")}h(ce,"ge"),n(ce,"closeGeneration");async function Q(t){for(;q.size>=be;){const E=q.values().next().value;if(!E)break;await ce(E,`closing a still-draining generation early \u2014 ${q.size} were pending and the cap is ${be} (each holds a whole app: DI container, DB pool, queue workers). Raise LENSMCP_SWAP_MAX_DRAINING if this pod legitimately needs more.`)}q.add(t);const i=Date.now(),p=n(()=>({inflight:t.inflight,work:R(t.workGen).count}),"busy");for(;re>0&&Date.now()-i<re;){if(t.closed)return;const E=p();if(E.inflight===0&&E.work===0)break;await new Promise(H=>{setTimeout(H,250).unref?.()})}if(t.closed)return;const g=p(),m=oe(t.workGen);g.inflight>0||g.work>0?console.error(`[child] swap drain expired after ${Date.now()-i}ms \u2014 closing the previous app with ${g.inflight} in-flight request(s) and ${g.work} background job(s) still running. `+(m?`Previous app still processing ${m.running} queue job(s); ${m.takenAfterStop} were taken after the swap. `:"")+`A queue job killed here keeps its lock until the TTL lapses. Raise LENSMCP_SWAP_DRAIN_MS (currently ${re}ms) if this is legitimate work.`):(Date.now()-i>250||m?.runningAtStop||m?.takenAfterStop)&&console.log(`[child] previous app drained in ${Date.now()-i}ms \u2014 closing it`+(m?` (it finished ${m.finishedAfterStop} queue job(s) after the swap; ${m.takenAfterStop} were taken after the swap)`:"")),await ce(t)}h(Q,"ce"),n(Q,"drainThenClose");async function Z(){if(S)return J=!0,console.log("[child] Reload deferred \u2014 will re-swap after current swap completes"),f;S=!0,T=Date.now(),process.removeAllListeners("uncaughtException"),process.removeAllListeners("unhandledRejection"),process.on("uncaughtException",(b,U)=>{console.error(`[child] uncaughtException (${U}):`,b)}),process.on("unhandledRejection",b=>{const U=b instanceof Error?b.stack||b.message:String(b);U.includes("FronteggContextScope")||U.includes("populateLoggerMetadata")||console.error("[child] unhandledRejection:",b)});let t;if(De)try{t=(0,hot_swap_registries_1.captureRegistries)()}catch{t=void 0}const i=global.__lensmcpBeginWorkGeneration,p=typeof i=="function"?i():void 0;try{try{await importFresh(BUNDLE_PATH)}catch(b){if(!(b instanceof SyntaxError))throw b;console.warn(`[child] bundle was unreadable mid-write (${b.message}) \u2014 retrying the swap once`),await new Promise(U=>setTimeout(U,400)),await importFresh(BUNDLE_PATH)}}catch(b){throw S=!1,T=Date.now(),b}if(typeof global.createChildApp!="function")throw S=!1,T=Date.now(),new Error(`Bundle '${BUNDLE_PATH}' does not export createChildApp() and the zero-touch bridge is not active. Either install @lensmcp/node-instrumentation (a plain NestFactory.create + app.listen main.ts then just works) or set global.createChildApp in main.ts when DEVSERVER_MODE === '1'.`);let g;if(t)try{g=(0,hot_swap_registries_1.supersededSince)(t),te((0,hot_swap_registries_1.pruneRegistries)(g,"build"),"at the swap")}catch(b){console.error("[child] could not release superseded class registrations:",b)}let m;try{m=await global.createChildApp()}catch(b){throw S=!1,T=Date.now(),takeImportedModule(),b}const E=F;g?.size&&(E.app?E.superseded=g:te((0,hot_swap_registries_1.pruneRegistries)(g,"serve"),"at the swap")),f=m;const H=takeImportedModule();F={app:m,handler:m.handler,inflight:0,gen:++Ne,...H?{module:H}:{},...p===void 0?{}:{workGen:p}};const de=ae(m,void 0).container;de&&(me.add(new WeakRef(de)),y=!0);const K=E.app&&p!==void 0?ge(p):void 0;return console.log("[child] Swapped to fresh app (previous draining in background)"+(K?.workers?`; its ${K.workers} queue worker(s) stopped taking new jobs, previous app still processing ${K.runningAtStop} job(s)`:"")),x(),E.app&&(j+=1,Q(E).catch(b=>console.error("[child] background close error:",b)),setTimeout(()=>z("30s after a hot swap"),3e4).unref?.(),_.swapped(E.gen,()=>E.closed===!0&&!N.has(E))),S=!1,T=Date.now(),J?(J=!1,Z()):m}h(Z,"le"),n(Z,"swapNow");const ye=debounce(async()=>{try{console.log("[child] /webpack/reload"),await Z()}catch(t){console.error("[child] reload failed:",t)}},250),le=http.createServer((t,i)=>{if(t.method==="POST"&&t.url==="/webpack/reload"){i.writeHead(200,{"content-type":"application/json"}),i.end(JSON.stringify({ok:!0})),ye();return}if(t.method==="GET"&&t.url==="/__lensmcp/alive"){const g=t.headers["x-internal-token"],m=process.env.LENSMCP_SERVICE_KEY;if(m&&g!==m){i.writeHead(404,{"content-type":"text/plain"}),i.end("not found");return}const E=R();i.writeHead(200,{"content-type":"application/json","cache-control":"no-store"}),i.end(JSON.stringify({ok:!0,pid:process.pid,swapping:S,inflight:F.inflight,oldestInflightAt:F.oldestAt,activeWork:E.count,oldestWorkAt:E.oldestStartedAt,keyFingerprint:serviceKeyFingerprint(),...G?{watcher:G}:{},...Number.isFinite(Number(process.env.LENSMCP_POD_GENERATION))&&process.env.LENSMCP_POD_GENERATION?{podGeneration:Number(process.env.LENSMCP_POD_GENERATION)}:{}}));return}const p=F;p.inflight+=1,p.oldestAt===void 0&&(p.oldestAt=Date.now()),i.on("close",()=>{p.inflight-=1,p.inflight===0&&(p.oldestAt=void 0),_.activity()}),p.handler(t,i)});le.keepAliveTimeout=0;const I=process.env.CHILD_SOCK_PATH;process.on("disconnect",()=>{cleanupSock(I),process.exit(0)});try{const t=path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH);if((0,schema_first_instance_1.schemaPrewarmEnabled)())try{const i=(0,schema_first_instance_1.prewarmZodFor)(t);i?.created&&console.log(`[child] zod${i.version?` ${i.version}`:""}: built ${i.created} throwaway schemas first, so none of the bundle's own is the first of its class`)}catch{}if((0,redis_disconnect_fix_1.redisDisconnectFixEnabled)())try{const i=(0,redis_disconnect_fix_1.finishStrandedDisconnectsFor)(t);i?.patched&&console.log(`[child] ioredis${i.versions.length?` ${i.versions.join(", ")}`:""}: a disconnect() between reconnect attempts now ends the client \u2014 it used to leave a queue worker's close() waiting for good`)}catch{}await Z(),L=(await _.booted()).live,console.log(`[child] Using bundle: ${t}`),claimSock(I),le.listen(I,()=>{console.log(`[child] Listening on ${I}`),tell(process,{type:"ready",socketPath:I})})}catch(t){console.error("[child] Startup error:",t),tell(process,{type:"boot-error",error:String(t?.stack||t)}),process.exitCode=1;return}process.on("message",async t=>{if(!(!t||typeof t!="object")){if(t.type==="debug-open"){const i=Number(t.port);s(Number.isInteger(i)&&i>1024?i:0);return}if(t.type==="watcher"){const i=t.testimony;i&&typeof i=="object"&&(G=i);return}if(t.type==="heap-snapshot"){_e(t);return}if(t.type==="recycle-declined"){ne=!1;return}if(t.type==="retire"){ee();return}if(t.type==="reload"){if(X)return;try{await Z(),tell(process,{type:"reloaded",socketPath:I})}catch(i){console.error("[child] reload error:",i),tell(process,{type:"reload-error",error:String(i?.stack||i)})}}}});let pe=!1;async function _e(t){const i=n(p=>{tell(process,{type:"heap-snapshot-result",id:t.id,...p})},"reply");if(pe)return i({ok:!1,refused:"a snapshot of this pod is already being written"});pe=!0;try{const p=W(),g=_.tracker.views().map(de=>de.gen),m=(0,heap_snapshot_1.heapSnapshotPolicy)();t.maxHeapBytes&&(m.maxHeapBytes=t.maxHeapBytes);const E=(0,heap_snapshot_1.heapSnapshotRefusal)(m,{live:p,...t.available?{available:t.available}:{}});if(E)return i({ok:!1,refused:E,live:p});console.log(`[child] writing a heap snapshot (${Math.round(p/1048576)} MB live) \u2014 the pod pauses while V8 serialises it`);const H=await(0,heap_snapshot_1.writeHeapSnapshot)(t.file);i({ok:!0,file:t.file,bytes:H.bytes,ms:H.ms,live:p,gen:F.gen??0,closedAlive:g})}catch(p){i({ok:!1,error:p?.message??String(p)})}finally{pe=!1}}h(_e,"De"),n(_e,"takeHeapSnapshot");async function ee(){if(X)return;X=!0,_.stop(),console.log("[child] retiring \u2014 a fresh pod has taken over; finishing in-flight work, then exiting");const t=ge(Number.POSITIVE_INFINITY);t?.workers&&console.log(`[child] its ${t.workers} queue worker(s) stopped taking new jobs, still processing ${t.runningAtStop} job(s)`);try{fs.writeFileSync(sockRetiringPath(I),String(process.pid),{flag:"w",mode:384})}catch{}await new Promise(p=>{setTimeout(p,Ae).unref?.()}),cleanupSock(I),le.close();const i=Date.now();for(;Date.now()-i<re&&(le.closeIdleConnections?.(),!(F.inflight===0&&R().count===0));)await new Promise(p=>{setTimeout(p,250).unref?.()});setTimeout(()=>process.exit(0),3e4).unref?.();try{await f?.close()}catch(p){console.error("[child] close error while retiring:",p)}process.exit(0)}h(ee,"re"),n(ee,"retire"),process.on("beforeExit",()=>{try{inspector?.close?.()}catch{}});const we=n(async t=>{console.log(`[child ${t}] shutting down\u2026`);const i=f?.close().catch(g=>console.error("[child] close error:",g)),p=new Promise(g=>le.close(()=>g()));cleanupSock(I),setTimeout(()=>process.exit(0),700).unref(),await Promise.all([i,p]),process.exit(0)},"shutdown");["SIGINT","SIGTERM","SIGHUP","SIGQUIT","SIGUSR2"].forEach(t=>{process.on(t,()=>{inspector?.close?.(),we(t)})})})()}else{let s=h(function(y){L.push(y),L.length>A&&L.splice(0,L.length-A),be?.write((0,inspector_secret_1.redactInspectorUrls)(y.replace(q,"")));for(const v of j)try{const _=v.plain?y.replace(q,""):y;v.res.write(v.redact?(0,inspector_secret_1.redactInspectorUrls)(_):_)}catch{j.delete(v)}},"z");n(s,"emitLogLine");const u=12,f=process.env.LENSMCP_PROJECT||SERVICE_NAME||"service",S=(0,pod_memory_events_1.createPodMemoryPublisher)(process.env.LENSMCP_EVENT_FILE),G=n(y=>({project:f,service:SERVICE_NAME||f,pod:y.id,pid:y.proc.pid??0,podGeneration:POD_GENERATION}),"podIdentity"),J=["\x1B[36m","\x1B[33m","\x1B[35m","\x1B[32m","\x1B[34m","\x1B[31m"],De="\x1B[0m",te=Math.max(1,Number(process.env.CHILD_COUNT||1)),F=LENSMCP_WS_KEY||path.basename(process.cwd()),re=n(y=>(0,process_name_1.namedExecPath)((0,process_name_1.processName)(F,SERVICE_NAME||"service",y)),"execPathFor");let R=(()=>{const y=Number(process.env.LENSMCP_DEBUG_PORT||"");return Number.isInteger(y)&&y>1024?y:0})();const ge=20;R&&(console.warn("[parent] DEBUGGER ENABLED \u2014 pods and workers open a Node inspector. Node's inspector has NO authentication: the ws:// URL's UUID is the whole credential, and any account on this host that obtains it can run code as you. Do not enable this on a shared machine. (issues/closed/codex-security-06)"),console.warn(usesFixedInspectorPorts()?`[parent] ${exports.DEBUG_FIXED_PORTS_ENV} is set \u2014 inspectors bind PREDICTABLE ports (${R}+slot, workers ${R}+${ge}+i). Any account on this host can connect to 127.0.0.1:${R} and read the session UUID from /json/list. Unset it to use ephemeral ports.`:`[parent] Inspectors bind an EPHEMERAL loopback port; attach via the printed "Debugger listening" URL, or \`lensmcp debug <service>\` (control socket). Set ${exports.DEBUG_FIXED_PORTS_ENV}=1 for fixed ports if your IDE needs a pre-configured attach port \u2014 any account on this host can then reach them.`));const oe=process.env.LENSMCP_LOG_FILE||"",be=oe?(()=>{try{fs.mkdirSync(path.dirname(oe),{recursive:!0});const y=fs.createWriteStream(oe,{flags:"a",mode:384});try{fs.chmodSync(oe,384)}catch{}return y}catch(y){return console.warn(`[parent] cannot open log file ${oe}:`,y.message),null}})():null,q=/\x1b\[[0-9;]*m/g,A=2e3,L=[],j=new Set,Ae=gatewayManaged();for(const y of["log","info","warn","error"]){const v=console[y].bind(console),_=y==="log"||y==="info"?process.stdout:process.stderr;console[y]=(...W)=>{v(...W.map($=>typeof $=="string"?(0,inspector_secret_1.forStream)(_,Ae,$):$)),s(W.map($=>typeof $=="string"?$:util.inspect($)).join(" ")+`
13
+ `)}}const ne=n(y=>J[(y-1)%J.length],"colorFor"),X=n(y=>{if(te===1)return"";const v=`[child#${y}] `;return`${ne(y)}${v}${De}`},"tagFor"),xe=n(y=>y.startsWith("{")&&y.endsWith("}"),"isJsonLog"),Ne=n((y,v,_)=>{const W=prettyFactory({sync:!0,colorize:!0,crlf:!0,messageKey:"message",errorLikeObjectKeys:["err","error"],errorProps:"type,message,stack",ignore:["logContext","context","hostname","req","res","err.driverError","module","cloudEnvironment","frontegg-application-id","frontegg-tenant-id","frontegg-trace-id","frontegg-vendor-id","host","service","version","err","error"].join(","),messageFormat:"{if module}[{module}] {end}{if context}[{context}] {end}{if logContext}[{logContext}] {end}{message}",customPrettifiers:{stack:n(x=>`
14
+ `+String(x),"stack")}}),$=n((x,N)=>{const T=x==="stdout"?process.stdout:process.stderr;try{_?.(N)}catch{}const C=xe(N)?W(N):`${N}
15
+ `;T.write((0,inspector_secret_1.forStream)(T,Ae,`${v}${C}`)),s(`${v}${C}`)},"write"),se=n((x,N)=>{if(!x)return;const T=readline.createInterface({input:x});T.on("line",C=>$(N,C)),T.on("close",()=>{})},"attach");se(y.stdout,"stdout"),se(y.stderr,"stderr")},"wireProcLogging"),me=n(y=>Ne(y.proc,X(y.id),v=>y.tail.push(v)),"wireChildLogging");(async()=>{ensureOwnerOnlyDir(SOCK_DIR);const y=httpProxy.createProxyServer({});let v=Number(process.env.PORT)||0;v||(v=9090);const _=[],W=new Set;function $(){let e=0;for(;W.has(e);)e++;return W.add(e),e}h($,"I"),n($,"allocDebugSlot");let se=1,x=0,N=!1,T=te,C=[],V=0;const he=(()=>{const e=Number(process.env.LENSMCP_POD_BOOT_GRACE_MS);return Number.isFinite(e)&&e>=0?e:12e4})(),fe=n(e=>e.proc.exitCode!==null||e.proc.signalCode!==null,"childExited"),z=n(e=>e.booting&&!fe(e)&&Date.now()-e.spawnedAt<he,"stillBooting");function Y(){return _.filter(e=>e.healthy&&typeof e.socketPath=="string")}h(Y,"J"),n(Y,"healthyChildren");let ie;function ae(e){if(!e||typeof e!="object")return;const o=e;if(o.schemaVersion===1){ie=o;for(const l of _)tell(l.proc,{type:"watcher",testimony:o})}}h(ae,"ye"),n(ae,"recordWatcherTestimony");function ce(e,o=256*1024){return new Promise(l=>{let d="",a=!1;e.on("data",r=>{a||(d+=r,d.length>o&&(a=!0))}),e.on("end",()=>{if(a||!d)return l(void 0);try{l(JSON.parse(d))}catch{l(void 0)}}),e.on("error",()=>l(void 0))})}h(ce,"ge"),n(ce,"readJsonBody");function Q(){const e=Y();if(e.length===0)return null;const o=x%e.length;return x=(x+1)%e.length,e[o]}h(Q,"ce"),n(Q,"pickChild");function Z(e,o){const l=`Child#${e.id}`,d=SERVICE_NAME||f,a=Date.now();if(o.type==="pod-memory"){const r=o.report;if(!r||typeof r.live!="number")return;e.memory.latest=r,e.memory.history.push(r),e.memory.history.length>12&&e.memory.history.splice(0,e.memory.history.length-12),console.log(`[parent] ${(0,pod_memory_1.describePodMemory)(l,r)}`),S.publish((0,pod_memory_events_1.buildPodMemoryEvent)(G(e),r))}else if(o.type==="pod-memory-retained"){const r=o.retained;if(!r||typeof r.gen!="number")return;e.memory.retained.set(r.gen,{...r,at:a}),console.warn(`[parent] ${(0,pod_memory_1.describeRetained)(l,d,r)}`),S.publish((0,pod_memory_events_1.buildPodRetainedEvent)(G(e),r,a))}else{const r=o.released;if(!r||typeof r.gen!="number")return;e.memory.retained.delete(r.gen),console.log(`[parent] ${(0,pod_memory_1.describeReleased)(l,d,r)}`),S.publish((0,pod_memory_events_1.buildPodReleasedEvent)(G(e),r,a))}}h(Z,"le"),n(Z,"recordPodMemory");const ye=new Map;let le=0;async function I(){const e=se++,o=childSockPath(e);cleanupSock(o);const l=(0,dev_devtool_1.sourceMapExecArgv)();__filename.endsWith(".ts")&&l.unshift("--require","@swc-node/register"),l.push(...(0,inspector_secret_1.inspectorPublishExecArgv)(usesFixedInspectorPorts()));const d=R?$():-1,a=(0,node_child_process_1.fork)(__filename,{env:{...process.env,APP_RUNNER:"1",CHILD_SOCK_PATH:o,...d>=0&&{CHILD_DEBUG_PORT:String(inspectorPortFor(R,d))}},stdio:["inherit","pipe","pipe","ipc"],execArgv:l,execPath:re("pod")}),r={id:e,proc:a,healthy:!1,lastError:null,debugSlot:d,tail:new exit_reason_1.TailBuffer,booting:!0,spawnedAt:Date.now(),bootReloadSeq:V,memory:{history:[],retained:new Map}};return a.on("error",w=>console.error(`[parent] Child#${e}: ${w.message}`)),a.on("message",w=>{if(!w||typeof w!="object")return;const c=w;c.type==="ready"?(r.socketPath=String(c.socketPath),r.healthy=!0,r.booting=!1,console.log(`[parent] Child#${r.id} ready on socket ${r.socketPath}`),ie&&tell(a,{type:"watcher",testimony:ie}),V!==r.bootReloadSeq&&tell(a,{type:"reload"})):c.type==="recycle-request"?g(r,String(c.reason||"it has outgrown its bound")):c.type==="inspector-url"?(r.inspectorUrl=String(c.url),console.log(`[parent] Child#${r.id} Debugger listening on ${c.url}`)):c.type==="reloaded"?(r.socketPath=String(c.socketPath),r.healthy=!0,console.log(`[parent] Child#${r.id} hot-swapped on socket ${r.socketPath}`)):c.type==="reload-error"?(r.lastError=String(c.error||"unknown reload error"),console.error(`[parent] Child#${r.id} reload error: ${r.lastError}`),r.healthy=!1):c.type==="boot-error"?(r.lastError=String(c.error||"unknown boot error"),console.error(`[parent] Child#${r.id} boot error: ${r.lastError}`),r.healthy=!1,r.booting=!1):c.type==="pod-memory"||c.type==="pod-memory-retained"||c.type==="pod-memory-released"?Z(r,c):c.type==="heap-snapshot-result"&&ye.get(Number(c.id))?.(c)}),a.on("exit",(w,c)=>{r.booting=!1;for(const M of r.memory.retained.values()){const O={gen:M.gen,closedAt:M.closedAt,ageMs:Date.now()-M.closedAt,reason:"pod-exited"};console.log(`[parent] ${(0,pod_memory_1.describeReleased)(`Child#${r.id}`,SERVICE_NAME||f,O)}`),S.publish((0,pod_memory_events_1.buildPodReleasedEvent)(G(r),O,Date.now()))}r.memory.retained.clear(),r.memory.latest&&S.publish((0,pod_memory_events_1.buildPodExitedEvent)(G(r),{code:w,signal:c},Date.now())),r.debugSlot>=0&&(W.delete(r.debugSlot),r.debugSlot=-1);const P=c==="SIGINT"||c==="SIGTERM"||w===0;if(P?console.log(`[parent] Child#${r.id} exited cleanly (code=${w}, signal=${c??"none"})`):(console.error((0,exit_reason_1.crashReport)(`[parent] Child#${r.id} crashed (code=${w}, signal=${c??"none"}, pid=${r.proc.pid}, ${r.healthy?"was serving":"was not ready"})`,w,c,r.tail.snapshot())),r.lastError||(r.lastError=`Child exited abnormally (code=${w}, signal=${c??"none"})`)),r.healthy=!1,cleanupSock(r.socketPath,r.proc.pid),r.socketPath=void 0,!P&&!N){const M=_.indexOf(r);M>=0&&_.splice(M,1);const O=Date.now();if(C=C.filter(B=>O-B<3e4),C.length>=5){console.error(`[parent] crash-loop detected (${C.length} respawns/30s) \u2014 pausing auto-respawn; POST /webpack/reload to retry`);return}C.push(O),setTimeout(()=>{const B=_.filter(Pe=>Pe.proc.killed===!1).length;!N&&B<T&&(console.log(`[parent] respawning a crashed pod (${B}/${T} live)`),I().catch(()=>{}))},1500).unref?.()}}),_.push(r),me(r),r}h(I,"M"),n(I,"spawnChild");async function pe(e){T=Math.max(T,e);const o=_.filter(d=>d.proc.killed===!1),l=e-o.length;for(let d=0;d<l;d++)await I()}h(pe,"pe"),n(pe,"ensurePoolSize");async function _e(){const e=_.filter(o=>(!o.healthy||typeof o.socketPath!="string")&&!z(o));await Promise.all(e.map(async o=>{try{o.proc.kill("SIGTERM")}catch{}cleanupSock(o.socketPath,o.proc.pid),o.socketPath=void 0;const l=_.indexOf(o);l>=0&&_.splice(l,1),await I()}))}h(_e,"De"),n(_e,"respawnUnhealthy");const ee=new Set;let we=!1,t=0;const i=3e4,p=(()=>{const e=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return(Number.isFinite(e)&&e>=0?e:15*6e4)+6e4})();async function g(e,o){const l=n(a=>{console.log(`[parent] Child#${e.id} asked for a fresh pod (${o}) \u2014 not now: ${a}`),tell(e.proc,{type:"recycle-declined"})},"decline");if(N||!_.includes(e))return;if(we)return l("another pod is already being replaced");const d=Date.now()-t;if(d<i)return l(`a pod was replaced ${Math.round(d/1e3)}s ago`);we=!0,console.log(`[parent] Child#${e.id} asked for a fresh pod \u2014 ${o}. Starting one; Child#${e.id} keeps serving until it is ready.`);try{const a=await I(),r=Date.now()+he;for(;!a.healthy&&!a.lastError&&!fe(a)&&Date.now()<r;)await new Promise(P=>{setTimeout(P,100).unref?.()});if(N)return;if(!a.healthy){const P=_.indexOf(a);P>=0&&_.splice(P,1);try{a.proc.kill("SIGTERM")}catch{}return l(`its successor Child#${a.id} did not come up (${a.lastError??"no answer in time"})`)}const w=_.indexOf(e);w>=0&&_.splice(w,1),e.healthy=!1,ee.add(e);const c=setTimeout(()=>{if(!fe(e)){console.error(`[parent] Child#${e.id} was still running ${p}ms after it was retired \u2014 killing it`);try{e.proc.kill("SIGKILL")}catch{}}},p);if(c.unref?.(),e.proc.once("exit",()=>{clearTimeout(c),ee.delete(e)}),!tell(e.proc,{type:"retire"}))try{e.proc.kill("SIGTERM")}catch{}t=Date.now(),console.log(`[parent] Child#${a.id} took over from Child#${e.id} (pid ${e.proc.pid} \u2192 ${a.proc.pid})`)}catch(a){l(`could not start a successor: ${a?.message??String(a)}`)}finally{we=!1}}h(g,"_"),n(g,"recyclePod");const m=[];function E(e){const o=path.dirname(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.resolve(BUNDLE_PATH)),l=path.join(o,`${e}.js`);if(!fs.existsSync(l))return console.error(`[parent] Worker "${e}" bundle not found: ${l}`),null;const d=(0,dev_devtool_1.sourceMapExecArgv)();__filename.endsWith(".ts")&&d.unshift("--require","@swc-node/register");try{d.push("--require",require.resolve("@lensmcp/node-instrumentation/register"))}catch{}const a=inspectorPortFor(R||9229,ge+Math.max(0,WORKER_NAMES.indexOf(e)));d.push(R?`--inspect=127.0.0.1:${a}`:`--inspect-port=127.0.0.1:${a}`,...(0,inspector_secret_1.inspectorPublishExecArgv)(usesFixedInspectorPorts()));const r=(0,node_child_process_1.fork)(l,{env:process.env,stdio:["inherit","pipe","pipe","ipc"],execArgv:d,execPath:re(`w-${e}`)}),w={name:e,proc:r,debugPort:a};return m.push(w),r.on("error",c=>console.error(`[parent] Worker "${e}": ${c.message}`)),Ne(r,`\x1B[35m[worker:${e}] \x1B[0m`,c=>{const P=/Debugger listening on (wss?:\/\/\S+)/.exec(c);P&&(w.inspectorUrl=P[1])}),r.on("exit",(c,P)=>{P==="SIGINT"||P==="SIGTERM"||c===0||console.error(`[parent] Worker "${e}" crashed (code=${c}, signal=${P??"none"})`);const M=m.indexOf(w);M>=0&&m.splice(M,1)}),console.log(`[parent] Worker "${e}" started (pid=${r.pid})`),w}h(E,"E"),n(E,"spawnWorkerProcess");const H=(()=>{const e=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return Number.isFinite(e)&&e>=0?e:15*6e4})(),de=(()=>{const e=Number(process.env.LENSMCP_SWAP_MAX_DRAINING);return Number.isFinite(e)&&e>=1?Math.floor(e):1})(),K=new Set,b=n(e=>e.proc.exitCode!==null||e.proc.signalCode!==null,"workerExited");function U(e,o){if(K.delete(e),!b(e)){console.error(`[parent] Worker "${e.name}" (pid=${e.proc.pid}) ${o} \u2014 killing it. A worker that returns from its SIGTERM handler but leaves a handle open (a Redis client handed to BullMQ is not closed by worker.close()) never exits on its own: close what it opened, or call process.exit().`);try{e.proc.kill("SIGKILL")}catch{}}}h(U,"x"),n(U,"killDrainingWorker");function Ge(e){try{e.proc.kill("SIGTERM")}catch{}if(b(e))return;const o=[...K].filter(d=>d.name===e.name);for(;o.length>=de;)U(o.shift(),`was still running when a later reload replaced its successor (cap ${de})`);K.add(e);const l=setTimeout(()=>U(e,`was still running ${H}ms after SIGTERM`),H);l.unref?.(),e.proc.once("exit",()=>{clearTimeout(l),K.delete(e)})}h(Ge,"Ue"),n(Ge,"retireWorker");function Le(){for(const e of[...m])Ge(e);m.length=0;for(const e of WORKER_NAMES)E(e)}h(Le,"He"),n(Le,"restartWorkers");const Be=debounce(async()=>{V+=1;const e=Y();if(e.length>0){console.log(`[parent] Forwarding reload to ${e.length} child(ren)`);for(const o of e)tell(o.proc,{type:"reload"})}await _e(),WORKER_NAMES.length>0&&Le()},200),Ee=n(async(e,o)=>{if(e.method==="POST"&&e.url==="/webpack/reload"){if(!mayDriveThePool(e))return refusePoolCommand(e,o);o.writeHead(200,{"content-type":"application/json"}),o.end(JSON.stringify({ok:!0})),ce(e).then(a=>ae(a?.watcher)),Be();return}if(e.method==="POST"&&e.url==="/webpack/watching"){if(!mayDriveThePool(e))return refusePoolCommand(e,o);const a=await ce(e);ae(a),o.writeHead(200,{"content-type":"application/json"}),o.end(JSON.stringify({ok:!0,relayed:ie!==void 0}));return}if(e.method==="POST"&&e.url==="/webpack/scale"){if(!mayDriveThePool(e))return refusePoolCommand(e,o);let a="";e.on("data",r=>{a+=r}),e.on("end",async()=>{let r=0;try{r=Number(JSON.parse(a||"{}").pods)||0}catch{}r=Math.max(1,Math.min(r,16)),await pe(r),o.writeHead(200,{"content-type":"application/json"}),o.end(JSON.stringify({ok:!0,pods:r}))});return}if(e.method==="GET"&&e.url?.startsWith("/webpack/logs")){const a=new URL(e.url,"http://localhost").searchParams,r=Math.min(Math.max(Number(a.get("tail")??"100")||0,0),A),w=a.get("follow")!=="0",c=a.get("plain")==="1",P=!isOwnerOnlyTransport(e);o.writeHead(200,{"content-type":"text/plain; charset=utf-8","cache-control":"no-cache"});const M=r===0?"":L.slice(-r).join(""),O=c?M.replace(q,""):M;if(o.write(P?(0,inspector_secret_1.redactInspectorUrls)(O):O),!w){o.end();return}const B={res:o,plain:c,redact:P};j.add(B),e.on("close",()=>j.delete(B));return}if(e.method==="POST"&&e.url?.startsWith("/webpack/debug")){if(!isOwnerOnlyTransport(e)){o.writeHead(404,{"content-type":"application/json"}),o.end(JSON.stringify({error:"not found"}));return}const a=Number(new URL(e.url,"http://localhost").searchParams.get("port")||"");Number.isInteger(a)&&a>1024&&(R=a),R||(R=9229);const r=_.filter(c=>c.proc.exitCode===null&&c.proc.signalCode===null);for(const c of r)c.debugSlot<0&&(c.debugSlot=$()),tell(c.proc,{type:"debug-open",port:inspectorPortFor(R,c.debugSlot)});for(const c of m)try{c.proc.kill("SIGUSR1")}catch{}const w=Date.now()+2e3;for(;Date.now()<w&&r.some(c=>!c.inspectorUrl);)await new Promise(c=>setTimeout(c,50));o.writeHead(200,{"content-type":"application/json"}),o.end(JSON.stringify({ok:!0,basePort:R,fixedPorts:usesFixedInspectorPorts(),pods:r.map(c=>({id:c.id,inspectorUrl:c.inspectorUrl??null})),workers:m.map(c=>({name:c.name,port:c.debugPort||inspectorPortOf(c.inspectorUrl),inspectorUrl:c.inspectorUrl??null}))},null,2)+`
16
+ `);return}if(e.method==="GET"&&e.url==="/webpack/memory"){if(!isOwnerOnlyTransport(e)){o.writeHead(404,{"content-type":"application/json"}),o.end(JSON.stringify({error:"not found"}));return}const a=path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.resolve(BUNDLE_PATH),r=[..._,...ee].map(w=>({id:w.id,pid:w.proc.pid??0,podGeneration:POD_GENERATION,healthy:w.healthy,retiring:ee.has(w),latest:w.memory.latest??null,history:w.memory.history,retained:[...w.memory.retained.values()]}));o.writeHead(200,{"content-type":"application/json","cache-control":"no-store"}),o.end(JSON.stringify({ok:!0,service:SERVICE_NAME,project:f,bundle:{path:a},pods:r},null,2)+`
17
+ `);return}if(e.method==="POST"&&e.url?.startsWith("/webpack/heap")){if(!isOwnerOnlyTransport(e)){o.writeHead(404,{"content-type":"application/json"}),o.end(JSON.stringify({error:"not found"}));return}const a=n((D,ke)=>{o.writeHead(D,{"content-type":"application/json"}),o.end(JSON.stringify(ke,null,2)+`
18
+ `)},"reply"),r=new URL(e.url,"http://localhost").searchParams,w=Number(r.get("pod")||""),c=r.has("maxMb")?Number(r.get("maxMb")):void 0;if(c!==void 0&&!(Number.isFinite(c)&&c>0)){a(400,{ok:!1,error:"maxMb takes a positive number of MB"});return}const P=Number.isInteger(w)&&w>0?_.find(D=>D.id===w):Y()[0];if(!P||fe(P)){a(404,{ok:!1,error:w?`no pod #${w} \u2014 running: ${_.map(D=>`#${D.id}`).join(", ")||"none"}`:"no pod is serving"});return}if(ye.size>0){a(409,{ok:!1,refused:"a heap snapshot is already being written for this service"});return}const M=(0,heap_snapshot_1.heapSnapshotPolicy)(),O=(0,heap_snapshot_1.heapSnapshotDir)();let B;try{(0,heap_snapshot_1.ensureHeapDir)(O);const D=(0,heap_snapshot_1.pruneHeapSnapshots)(O,M);D.length&&console.log(`[parent] removed ${D.length} older heap snapshot(s) from ${O}`),B=path.join(O,(0,heap_snapshot_1.heapSnapshotFileName)(SERVICE_NAME||f,P.id,P.proc.pid??0,P.memory.latest?.gen??0,Date.now()))}catch(D){a(500,{ok:!1,error:`cannot prepare ${O}: ${D.message}`});return}const Pe=++le,Oe=(0,heap_snapshot_1.availableSystemMemory)();let ve;const k=await new Promise(D=>{const ke=setTimeout(()=>D(void 0),6e5);ke.unref?.(),ye.set(Pe,Ye=>{clearTimeout(ke),D(Ye)}),ve=n(()=>{clearTimeout(ke),D(void 0)},"onExit"),P.proc.once("exit",ve);const je={type:"heap-snapshot",id:Pe,file:B,...Oe?{available:Oe}:{},...c!==void 0?{maxHeapBytes:Math.floor(c*1048576)}:{}};tell(P.proc,je)||ve()}).finally(()=>{ye.delete(Pe),ve&&P.proc.off("exit",ve)});if(!k){a(504,{ok:!1,pod:P.id,error:"the pod did not finish the snapshot (it exited, or took longer than 10 minutes)"});return}k.ok?console.log(`[parent] Child#${P.id} wrote a ${Math.round((k.bytes??0)/1048576)} MB heap snapshot in ${k.ms} ms \u2192 ${k.file}`):console.warn(`[parent] Child#${P.id} heap snapshot not taken: ${k.refused??k.error}`),a(k.ok?200:k.refused?409:500,{ok:k.ok,pod:P.id,pid:P.proc.pid??0,service:SERVICE_NAME,bundle:path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.resolve(BUNDLE_PATH),...Oe?{available:Oe}:{},...k.file?{file:k.file,bytes:k.bytes,ms:k.ms}:{},...k.live!==void 0?{live:k.live}:{},...k.gen!==void 0?{gen:k.gen,closedAlive:k.closedAlive??[]}:{},...k.refused?{refused:k.refused}:{},...k.error?{error:k.error}:{}});return}const l=matchGatewayRoute(e);if(l?.prependPrefix&&!e.url?.startsWith(l.prependPrefix)&&(e.url=l.prependPrefix+(e.url??"/")),l?.target){applyGatewayMiddleware(e),y.web(e,o,{target:l.target,autoRewrite:typeof l.target=="string",changeOrigin:!0},a=>{console.error(`[parent] proxy error to ${l.target}:`,a),o.statusCode=502,o.setHeader("content-type","text/plain; charset=utf-8"),o.end(`Upstream error from ${l.target}.`)});return}if(SERVICE_PREFIX){if(!e.url?.startsWith(SERVICE_PREFIX)){o.writeHead(404,{"content-type":"text/plain; charset=utf-8"}),o.end(`Not found. This service is mounted at ${SERVICE_PREFIX}/`);return}e.url=e.url.slice(SERVICE_PREFIX.length)||"/"}applyGatewayMiddleware(e);const d=Q();if(!d){o.statusCode=503,o.setHeader("content-type","text/plain; charset=utf-8");const a=_.map(r=>`#${r.id}: ${r.lastError??"no error recorded"}`).join(`
19
19
  `);o.end(`No healthy children available. POST /webpack/reload to recover.
20
20
 
21
21
  Last errors:
22
- ${a}`);return}g.web(e,o,{target:{socketPath:d.socketPath},headers:{"x-proxy-child-id":String(d.id)}},a=>{console.error(`[parent] proxy error to Child#${d.id}:`,a),d.healthy=!1,d.lastError=String(a?.stack||a),o.statusCode=502,o.setHeader("content-type","text/plain; charset=utf-8"),o.end(`Upstream error from Child#${d.id}. Try /webpack/reload.
23
- ${d.lastError}`)})},"requestHandler");let pe,me,Me;const be=[];if(GATEWAY_HTTPS){const e=require("./basic-ssl"),o=GATEWAY_ROUTES.map(d=>d.host).filter(d=>!!d),c=path.join(process.cwd(),"node_modules",".cache","davnx-webpack");me=e.getCertificateSync(c,SERVICE_NAME||"lensmcp.dev",o),Me=e.caCertPath(),pe=require("node:https").createServer({key:me,cert:me},ye)}else pe=http.createServer(ye);const Ge=n((e,o,c)=>{const d=matchGatewayRoute(e);if(d?.prependPrefix&&!e.url?.startsWith(d.prependPrefix)&&(e.url=d.prependPrefix+(e.url??"/")),d?.target){g.ws(e,o,c,{target:d.target,changeOrigin:!0},()=>o.destroy());return}const a=q();if(!a){o.destroy();return}g.ws(e,o,c,{target:{socketPath:a.socketPath}},()=>o.destroy())},"upgradeHandler");pe.on("upgrade",Ge);const Le=2e3;let We=!1;pe.on("error",e=>{if(e.code==="EADDRINUSE"){We||(We=!0,console.warn(`[parent] public port ${P} already in use \u2014 continuing on the unix-socket pool only (gateway routing is unaffected) and retrying the bind every ${Le/1e3}s. Give this service a distinct cluster.port if this is not a rolling handoff.`)),setTimeout(()=>{!T&&!pe.listening&&pe.listen(P)},Le).unref?.();return}console.error("[parent] public server error:",e)}),await fe(oe);for(const e of WORKER_NAMES)k(e);pe.listen(P,()=>{const e=GATEWAY_HTTPS?"https":"http";console.log(`[parent] Listening on ${e}://localhost:${P}`),SERVICE_PREFIX&&console.log(`[parent] Service prefix: "${SERVICE_PREFIX}" (enforced \u2014 requests without it will get 404)`),gatewayMiddleware&&console.log(`[parent] Gateway middleware: ACTIVE (${GATEWAY_MIDDLEWARE_PATH})`),GATEWAY_ROUTES.length>0&&console.log(`[parent] Gateway routes: ${GATEWAY_ROUTES.map(o=>`${o.host??"*"}${o.prefix??"/"}\u2192${o.target??"children"}`).join(" ")}`),Me&&(console.log("[parent] HTTPS dev CA (trust ONCE, then rotations/new hostnames stay green):"),console.log(`[parent] sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${Me}`)),console.log(`POST ${e}://localhost:${P}/webpack/reload to trigger rolling swap/respawn`)});const Ae=Number(process.env.INTERNAL_PORT||0);if(Ae>0){const e=n((c,d)=>{const a=q();if(!a){d.statusCode=503,d.setHeader("content-type","text/plain; charset=utf-8"),d.end("No healthy children available.");return}g.web(c,d,{target:{socketPath:a.socketPath}},r=>{a.healthy=!1,a.lastError=String(r?.stack||r),d.statusCode=502,d.end(`Upstream error from Child#${a.id}.`)})},"internalHandler"),o=http.createServer(e);o.on("upgrade",(c,d,a)=>{const r=q();if(!r){d.destroy();return}g.ws(c,d,a,{target:{socketPath:r.socketPath}},()=>d.destroy())}),o.on("error",c=>{console.warn(`[parent] internal port ${Ae} unavailable (${c.code}).`)}),o.listen(Ae,()=>{console.log(`[parent] Internal (service-to-service, no gateway middleware) on http://localhost:${Ae}`)}),be.push(o)}const He=(()=>{try{return JSON.parse(process.env.GATEWAY_EXTRA_PORTS||"[]")}catch{return[]}})();for(const e of He){if(!Number.isInteger(e)||e===Number(P))continue;const o=GATEWAY_HTTPS?require("node:https").createServer({key:me,cert:me},ye):http.createServer(ye);o.on("upgrade",Ge),o.on("error",c=>{console.warn(`[parent] extra port ${e} unavailable (${c.code}) \u2014 main port still up.`)}),o.listen(e,()=>{console.log(`[parent] Also listening on ${GATEWAY_HTTPS?"https":"http"}://localhost:${e}`)}),be.push(o)}const Ne=path.join(SOCK_DIR,"parent.sock");claimSock(Ne);const Te=http.createServer(ye);Te.on("error",e=>{console.warn(`[parent] control socket unavailable (${e.code}) \u2014 lensmcp logs/debug attach disabled.`)}),Te.listen(Ne),be.push(Te);const Ue=n(async e=>{T=!0,console.log(`[${e}] [parent] shutting down\u2026`);const o=sockOwnedByAnother(Ne);cleanupSock(Ne);for(const c of be)if(!(c===Te&&o))try{c.close()}catch{}for(const c of L)try{c.proc.kill("SIGTERM")}catch{}for(const c of[...ge])ve(c,"was still draining when its devserver shut down");for(const c of i)try{c.proc.kill("SIGTERM")}catch{}for(const c of E){try{c.proc.kill("SIGTERM")}catch{}c.socketPath&&cleanupSock(c.socketPath,c.proc.pid)}try{fs.rmdirSync(SOCK_DIR)}catch{}setTimeout(()=>process.exit(0),700).unref()},"shutdown");["SIGINT","SIGTERM","SIGHUP","SIGQUIT","SIGUSR2"].forEach(e=>process.on(e,()=>{Ue(e)}));const Ie=Number(process.env.LENSMCP_GATEWAY_PID??0);if(Number.isInteger(Ie)&&Ie>0){const e=setInterval(()=>{try{process.kill(Ie,0)}catch(o){if(o.code==="EPERM")return;clearInterval(e),console.error(`[parent] gateway (pid ${Ie}) is gone \u2014 shutting the pod down to avoid an orphan tree.`),Ue("gateway-gone")}},5e3);e.unref()}})()}
22
+ ${a}`);return}y.web(e,o,{target:{socketPath:d.socketPath},headers:{"x-proxy-child-id":String(d.id)}},a=>{console.error(`[parent] proxy error to Child#${d.id}:`,a),d.healthy=!1,d.lastError=String(a?.stack||a),o.statusCode=502,o.setHeader("content-type","text/plain; charset=utf-8"),o.end(`Upstream error from Child#${d.id}. Try /webpack/reload.
23
+ ${d.lastError}`)})},"requestHandler");let ue,Se,Ce;const Te=[];if(GATEWAY_HTTPS){const e=require("./basic-ssl"),o=GATEWAY_ROUTES.map(d=>d.host).filter(d=>!!d),l=path.join(process.cwd(),"node_modules",".cache","davnx-webpack");Se=e.getCertificateSync(l,SERVICE_NAME||"lensmcp.dev",o),Ce=e.caCertPath(),ue=require("node:https").createServer({key:Se,cert:Se},Ee)}else ue=http.createServer(Ee);const We=n((e,o,l)=>{const d=matchGatewayRoute(e);if(d?.prependPrefix&&!e.url?.startsWith(d.prependPrefix)&&(e.url=d.prependPrefix+(e.url??"/")),d?.target){y.ws(e,o,l,{target:d.target,changeOrigin:!0},()=>o.destroy());return}const a=Q();if(!a){o.destroy();return}y.ws(e,o,l,{target:{socketPath:a.socketPath}},()=>o.destroy())},"upgradeHandler");ue.on("upgrade",We);const Ue=2e3;let Fe=!1;ue.on("error",e=>{if(e.code==="EADDRINUSE"){Fe||(Fe=!0,console.warn(`[parent] public port ${v} already in use \u2014 continuing on the unix-socket pool only (gateway routing is unaffected) and retrying the bind every ${Ue/1e3}s. Give this service a distinct cluster.port if this is not a rolling handoff.`)),setTimeout(()=>{!N&&!ue.listening&&ue.listen(v)},Ue).unref?.();return}console.error("[parent] public server error:",e)}),await pe(te);for(const e of WORKER_NAMES)E(e);ue.listen(v,()=>{const e=GATEWAY_HTTPS?"https":"http";console.log(`[parent] Listening on ${e}://localhost:${v}`),SERVICE_PREFIX&&console.log(`[parent] Service prefix: "${SERVICE_PREFIX}" (enforced \u2014 requests without it will get 404)`),gatewayMiddleware&&console.log(`[parent] Gateway middleware: ACTIVE (${GATEWAY_MIDDLEWARE_PATH})`),GATEWAY_ROUTES.length>0&&console.log(`[parent] Gateway routes: ${GATEWAY_ROUTES.map(o=>`${o.host??"*"}${o.prefix??"/"}\u2192${o.target??"children"}`).join(" ")}`),Ce&&(console.log("[parent] HTTPS dev CA (trust ONCE, then rotations/new hostnames stay green):"),console.log(`[parent] sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${Ce}`)),console.log(`POST ${e}://localhost:${v}/webpack/reload to trigger rolling swap/respawn`)});const Re=Number(process.env.INTERNAL_PORT||0);if(Re>0){const e=n((l,d)=>{const a=Q();if(!a){d.statusCode=503,d.setHeader("content-type","text/plain; charset=utf-8"),d.end("No healthy children available.");return}y.web(l,d,{target:{socketPath:a.socketPath}},r=>{a.healthy=!1,a.lastError=String(r?.stack||r),d.statusCode=502,d.end(`Upstream error from Child#${a.id}.`)})},"internalHandler"),o=http.createServer(e);o.on("upgrade",(l,d,a)=>{const r=Q();if(!r){d.destroy();return}y.ws(l,d,a,{target:{socketPath:r.socketPath}},()=>d.destroy())}),o.on("error",l=>{console.warn(`[parent] internal port ${Re} unavailable (${l.code}).`)}),o.listen(Re,()=>{console.log(`[parent] Internal (service-to-service, no gateway middleware) on http://localhost:${Re}`)}),Te.push(o)}const qe=(()=>{try{return JSON.parse(process.env.GATEWAY_EXTRA_PORTS||"[]")}catch{return[]}})();for(const e of qe){if(!Number.isInteger(e)||e===Number(v))continue;const o=GATEWAY_HTTPS?require("node:https").createServer({key:Se,cert:Se},Ee):http.createServer(Ee);o.on("upgrade",We),o.on("error",l=>{console.warn(`[parent] extra port ${e} unavailable (${l.code}) \u2014 main port still up.`)}),o.listen(e,()=>{console.log(`[parent] Also listening on ${GATEWAY_HTTPS?"https":"http"}://localhost:${e}`)}),Te.push(o)}const $e=path.join(SOCK_DIR,"parent.sock");claimSock($e);const Ie=http.createServer(Ee);Ie.on("error",e=>{console.warn(`[parent] control socket unavailable (${e.code}) \u2014 lensmcp logs/debug attach disabled.`)}),Ie.listen($e),Te.push(Ie);const He=n(async e=>{N=!0,console.log(`[${e}] [parent] shutting down\u2026`);const o=sockOwnedByAnother($e);cleanupSock($e);for(const l of Te)if(!(l===Ie&&o))try{l.close()}catch{}for(const l of m)try{l.proc.kill("SIGTERM")}catch{}for(const l of[...K])U(l,"was still draining when its devserver shut down");for(const l of ee)try{l.proc.kill("SIGTERM")}catch{}for(const l of _){try{l.proc.kill("SIGTERM")}catch{}l.socketPath&&cleanupSock(l.socketPath,l.proc.pid)}try{fs.rmdirSync(SOCK_DIR)}catch{}setTimeout(()=>process.exit(0),700).unref()},"shutdown");["SIGINT","SIGTERM","SIGHUP","SIGQUIT","SIGUSR2"].forEach(e=>process.on(e,()=>{He(e)}));const Me=Number(process.env.LENSMCP_GATEWAY_PID??0);if(Number.isInteger(Me)&&Me>0){const e=setInterval(()=>{try{process.kill(Me,0)}catch(o){if(o.code==="EPERM")return;clearInterval(e),console.error(`[parent] gateway (pid ${Me}) is gone \u2014 shutting the pod down to avoid an orphan tree.`),He("gateway-gone")}},5e3);e.unref()}})()}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lensmcp/cluster",
3
- "version": "1.24.0",
3
+ "version": "1.24.1",
4
4
  "description": "Run your Nx workspace as a local production cluster: pods on unix sockets with true HMR, one https gateway with per-project domains, scale-from-zero, autoscale, idle-kill, local-CA TLS — observed by the LensMCP lens.",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",
@@ -57,9 +57,9 @@
57
57
  }
58
58
  },
59
59
  "dependencies": {
60
- "@lensmcp/core": "1.24.0",
61
- "@lensmcp/node-instrumentation": "1.24.0",
62
- "@lensmcp/nx-plugin": "1.24.0",
60
+ "@lensmcp/core": "1.24.1",
61
+ "@lensmcp/node-instrumentation": "1.24.1",
62
+ "@lensmcp/nx-plugin": "1.24.1",
63
63
  "fastify": "^5.8.5",
64
64
  "@fastify/reply-from": "^12.6.2",
65
65
  "@typescript/native-preview": "^7.0.0-dev.20260707.2",
package/pod-memory.d.ts CHANGED
@@ -11,6 +11,8 @@ export interface PodMemoryPolicy {
11
11
  retainedAfterMs: number;
12
12
  /** How quiet the pod must be before a swap counts as settled. */
13
13
  settleMs: number;
14
+ /** A retained verdict counts the shared classes (one heap walk each) only when live heap is at most this. */
15
+ countMaxBytes: number;
14
16
  }
15
17
  /** Full GCs a closed generation must survive before it is called retained: one could have raced its last timer. */
16
18
  export declare const RETAINED_MIN_GCS = 2;
@@ -21,6 +23,8 @@ export declare const RETAINED_MIN_GCS = 2;
21
23
  * - `LENSMCP_POD_GC_IDLE_EVERY_MS` — default `300000`.
22
24
  * - `LENSMCP_POD_RETAINED_AFTER_MS` — default `300000` (5 min).
23
25
  * - `LENSMCP_POD_GC_SETTLE_MS` — default `2000`.
26
+ * - `LENSMCP_POD_COUNT_MAX_MB` — default `64`: the live heap up to which a retained verdict counts the shared
27
+ * classes. Each count walks the heap, ~7 ms per MB, with the pod paused; `0` never counts.
24
28
  */
25
29
  export declare function podMemoryPolicy(env?: NodeJS.ProcessEnv): PodMemoryPolicy;
26
30
  /** What made the pod collect. `swap+<delay>` names a scheduled run by its delay from the swap. */
@@ -222,6 +226,8 @@ export interface PodMemoryHost {
222
226
  policy: PodMemoryPolicy;
223
227
  state(): PodMemoryHostState;
224
228
  send(message: PodMemoryMessage): void;
229
+ /** Live Nest DI containers, without walking the heap (weak references the pod holds); read after a full GC. */
230
+ containers?: () => number | undefined;
225
231
  counter?: LiveObjectCounter;
226
232
  /** A generation was just reported retained — the recycle rule's cue. */
227
233
  onRetained?(oldest: ClosedGenerationView): void;
package/pod-memory.js CHANGED
@@ -1 +1 @@
1
- "use strict";var O=Object.defineProperty;var d=(s,e)=>O(s,"name",{value:e,configurable:!0});var L=Object.defineProperty,i=d((s,e)=>L(s,"name",{value:e,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GenerationTracker=exports.LensmcpClosedGeneration=exports.RETAINED_MIN_GCS=void 0,exports.podMemoryPolicy=podMemoryPolicy,exports.fullGc=fullGc,exports.countLiveInstances=countLiveInstances,exports.createLiveObjectCounter=createLiveObjectCounter,exports.delayLabel=delayLabel,exports.createPodMemoryMonitor=createPodMemoryMonitor,exports.ageLabel=ageLabel,exports.describePodMemory=describePodMemory,exports.describeRetained=describeRetained,exports.describeReleased=describeReleased;const tslib_1=require("tslib"),node_module_1=require("node:module"),v8=tslib_1.__importStar(require("node:v8")),vm=tslib_1.__importStar(require("node:vm"));exports.RETAINED_MIN_GCS=2;const numberFrom=i((s,e,t)=>{if(s===void 0||s.trim()==="")return e;const r=Number(s);return Number.isFinite(r)&&r>=t?r:e},"numberFrom");function podMemoryPolicy(s=process.env){const e=["0","false","no","off"].includes((s.LENSMCP_POD_GC??"").trim().toLowerCase()),t=(s.LENSMCP_POD_GC_SCHEDULE_MS??"").split(",").map(r=>Number(r.trim())).filter(r=>Number.isFinite(r)&&r>0).map(Math.floor).sort((r,a)=>r-a);return{enabled:!e,scheduleMs:t.length?t:[3e4,12e4,3e5],idleMs:Math.floor(numberFrom(s.LENSMCP_POD_GC_IDLE_MS,6e4,0)),idleEveryMs:Math.floor(numberFrom(s.LENSMCP_POD_GC_IDLE_EVERY_MS,3e5,0)),retainedAfterMs:Math.floor(numberFrom(s.LENSMCP_POD_RETAINED_AFTER_MS,3e5,0)),settleMs:Math.floor(numberFrom(s.LENSMCP_POD_GC_SETTLE_MS,2e3,0))}}d(podMemoryPolicy,"podMemoryPolicy"),i(podMemoryPolicy,"podMemoryPolicy");let collector;function fullGc(){if(collector===void 0)try{v8.setFlagsFromString("--expose-gc");const s=vm.runInNewContext("gc");collector=typeof s=="function"?s:null}catch{collector=null}if(!collector)return!1;try{return collector(),!0}catch{return!1}}d(fullGc,"fullGc"),i(fullGc,"fullGc");function countLiveInstances(s){const e=v8.queryObjects;if(typeof e!="function"||typeof s!="function")return;const t=process.emitWarning;process.emitWarning=i(function(r,...a){const l=typeof a[0]=="string"?a[0]:a[0]?.type,n=typeof r=="string"?r:r?.message;if(!(l==="ExperimentalWarning"&&/queryObjects/.test(n??"")))return t.call(process,r,...a)},"quiet");try{const r=e(s,{format:"count"});return typeof r=="number"&&Number.isFinite(r)?r:void 0}catch{return}finally{process.emitWarning=t}}d(countLiveInstances,"countLiveInstances"),i(countLiveInstances,"countLiveInstances");const LEAK_CLASSES=[{name:"NestContainer",pkg:"@nestjs/core",pick:i(s=>s.NestContainer,"pick")},{name:"ZodObject",pkg:"zod",pick:i(s=>s.ZodObject,"pick")},{name:"DataSource",pkg:"typeorm",pick:i(s=>s.DataSource,"pick")},{name:"Redis",pkg:"ioredis",pick:i(s=>typeof s=="function"?s:s.default??s.Redis,"pick")},{name:"Worker",pkg:"bullmq",pick:i(s=>s.Worker,"pick")}];function createLiveObjectCounter(s,e=require.cache){let t;try{t=(0,node_module_1.createRequire)(s)}catch{t=void 0}const r=new Map,a=i(l=>{if(!t)return;let n=r.get(l.pkg);if(n===void 0){try{n=t.resolve(l.pkg)}catch{n=null}r.set(l.pkg,n)}if(!n)return;const p=e[n]?.exports;if(!(!p||typeof p!="object"&&typeof p!="function"))try{return l.pick(p)}catch{return}},"classOf");return{containers:i(()=>countLiveInstances(a(LEAK_CLASSES[0])),"containers"),all:i(()=>{const l={};for(const n of LEAK_CLASSES){const p=countLiveInstances(a(n));p!==void 0&&(l[n.name]=p)}return Object.keys(l).length?l:void 0},"all")}}d(createLiveObjectCounter,"createLiveObjectCounter"),i(createLiveObjectCounter,"createLiveObjectCounter");class LensmcpClosedGeneration{static{d(this,"LensmcpClosedGeneration")}static{i(this,"LensmcpClosedGeneration")}constructor(e,t){this.gen=e,this.refs={},this.label=`lensmcp closed generation ${e}`;for(const[r,a]of Object.entries(t))a&&(typeof a=="object"||typeof a=="function")&&(this.refs[r]=new WeakRef(a))}}exports.LensmcpClosedGeneration=LensmcpClosedGeneration;class GenerationTracker{static{d(this,"GenerationTracker")}static{i(this,"GenerationTracker")}constructor(e={}){this.opts=e,this.closed=new Map,this.freed=new Map,this.now=e.now??Date.now,this.registry=new FinalizationRegistry(t=>this.collected(t))}close(e,t,r){if(this.closed.has(e)||this.freed.has(e))return;const a=new LensmcpClosedGeneration(e,r),l=new Set(Object.keys(a.refs));if(l.size===0){this.markFreed(e);return}this.closed.set(e,{marker:a,closedAt:this.now(),swapsAtClose:t,gcs:0,alive:l});for(const[n,p]of Object.entries(a.refs)){const m=p.deref();m?this.registry.register(m,{gen:e,name:n}):l.delete(n)}l.size===0&&this.drop(e)}noteGc(){for(const e of this.closed.values())e.gcs+=1}isAlive(e){if(this.closed.has(e))return!0;if(this.freed.has(e))return!1}views(){return[...this.closed.entries()].map(([e,t])=>this.view(e,t))}dueForReport(e,t=this.now()){return this.views().filter(r=>r.reportedAt===void 0&&r.gcs>=exports.RETAINED_MIN_GCS&&t-r.closedAt>=e)}retainedCount(e,t=this.now()){return this.views().filter(r=>r.gcs>=exports.RETAINED_MIN_GCS&&t-r.closedAt>=e).length}markReported(e,t=this.now()){const r=this.closed.get(e);r&&(r.reportedAt=t)}oldestRetained(e,t=this.now()){return this.views().filter(r=>r.gcs>=exports.RETAINED_MIN_GCS&&t-r.closedAt>=e).sort((r,a)=>r.closedAt-a.closedAt)[0]}markers(){return[...this.closed.values()].map(e=>e.marker)}forgetAll(){const e=this.views().filter(t=>t.reportedAt!==void 0);for(const t of[...this.closed.keys()])this.drop(t);return e}collected(e){const t=this.closed.get(e.gen);if(!t||(t.alive.delete(e.name),t.alive.size>0))return;const r=this.view(e.gen,t);this.drop(e.gen);try{this.opts.onFreed?.(r,r.reportedAt!==void 0)}catch{}}drop(e){this.closed.delete(e),this.markFreed(e)}markFreed(e){this.freed.set(e,this.now()),this.freed.size>64&&this.freed.delete(this.freed.keys().next().value)}view(e,t){return{gen:e,closedAt:t.closedAt,swapsAtClose:t.swapsAtClose,gcs:t.gcs,alive:[...t.alive],...t.reportedAt!==void 0?{reportedAt:t.reportedAt}:{}}}}exports.GenerationTracker=GenerationTracker;const MB=1024*1024;function delayLabel(s){return s%6e4===0?`${s/6e4}m`:s%1e3===0?`${s/1e3}s`:`${s}ms`}d(delayLabel,"delayLabel"),i(delayLabel,"delayLabel");const turn=i(()=>new Promise(s=>setImmediate(s)),"turn");function createPodMemoryMonitor(s){const e=s.now??Date.now,t=s.policy,r=new GenerationTracker({now:e,onFreed:i((o,u)=>{u&&s.send({type:"pod-memory-released",released:{gen:o.gen,closedAt:o.closedAt,ageMs:e()-o.closedAt,reason:"collected"}})},"onFreed")});let a=Promise.resolve(),l=!1,n,p,m,y=0,w=!1,_=0;const g=i((o,u)=>{const c=setTimeout(o,Math.max(0,u));return c.unref?.(),c},"unrefTimer");function E(){return!n||n.previousGen===void 0?null:n.previousClosed()?r.isAlive(n.previousGen)!==!1:!0}d(E,"S"),i(E,"previousAlive");async function G(o){const u=process.memoryUsage().heapUsed,c=process.hrtime.bigint();let f=s.counter?.containers();f===void 0&&fullGc();const x=Number(process.hrtime.bigint()-c)/1e6;r.noteGc(),await turn(),await turn();const h=process.memoryUsage(),v=v8.getHeapStatistics(),R=v8.getHeapSpaceStatistics().find(I=>I.space_name==="new_space"),$=s.state(),P=r.views(),N=e();return f!==void 0&&f<0&&(f=void 0),{trigger:o,at:N,gen:$.gen,swaps:$.swaps,live:h.heapUsed,used:u,reserved:h.heapTotal,rss:h.rss,external:h.external,youngGen:R?.space_size??0,limit:v.heap_size_limit,...$.baseline!==void 0?{baseline:$.baseline}:{},gcMs:Math.round(x),...n?.previousGen!==void 0?{previousGen:n.previousGen}:{},previousAlive:E(),closedAlive:P.length,retained:r.retainedCount(t.retainedAfterMs,N),...f!==void 0?{containers:f}:{},sourceMaps:process.sourceMapsEnabled===!0}}d(G,"k"),i(G,"collect");function S(o){for(const c of r.dueForReport(t.retainedAfterMs,o.at)){r.markReported(c.gen,o.at);const f=s.counter?.all();s.send({type:"pod-memory-retained",retained:{gen:c.gen,closedAt:c.closedAt,ageMs:o.at-c.closedAt,swapsSinceClose:Math.max(0,o.swaps-c.swapsAtClose),gcs:c.gcs,alive:c.alive,...f?{counts:f}:{},live:o.live}})}const u=r.oldestRetained(t.retainedAfterMs,o.at);if(u)try{s.onRetained?.(u)}catch{}n&&!n.done&&o.previousAlive===!1&&A(),C()}d(S,"G"),i(S,"afterCollect");function M(o){const u=a.then(async()=>{const c=await G(o);return w=!1,l||(s.send({type:"pod-memory",report:c}),S(c)),c});return a=u.catch(()=>{}),u}d(M,"v"),i(M,"measure");function b(o){if(!l){if(s.state().busy){g(()=>b(o),1e3);return}M(o).catch(()=>{})}}d(b,"b"),i(b,"measureWhenFree");function A(){if(n){n.done=!0;for(const o of n.timers)clearTimeout(o);n.timers=[]}}d(A,"A"),i(A,"finishSchedule");function C(){if(p&&clearTimeout(p),p=void 0,l||!t.enabled)return;const o=r.views().filter(f=>f.reportedAt===void 0);if(o.length===0)return;const u=e(),c=Math.min(...o.map(f=>Math.max(f.closedAt+t.retainedAfterMs,u+1e3)));p=g(()=>{p=void 0,b("retention-check")},c-u)}d(C,"C"),i(C,"armRetentionCheck");function k(){if(l||!t.enabled||t.idleMs<=0||m)return;const o=Math.max(t.idleMs-(e()-y),_+t.idleEveryMs-e(),250);m=g(()=>{if(m=void 0,!!w){if(e()-y<t.idleMs||e()-_<t.idleEveryMs||s.state().busy){k();return}_=e(),b("idle")}},o)}return d(k,"x"),i(k,"armIdle"),{tracker:r,booted:i(()=>M("boot"),"booted"),swapped(o,u){if(l||(A(),y=e(),w=!0,!t.enabled))return;const c={...o!==void 0?{previousGen:o}:{},previousClosed:u,timers:[],done:!1};n=c;const f=e(),x=t.scheduleMs[0]??Number.POSITIVE_INFINITY,h=i(()=>{if(c.done||n!==c)return;const v=s.state();if(!v.busy&&u()&&e()-v.lastBusyAt>=t.settleMs){M("swap-settled").catch(()=>{});return}e()-f+500<x&&c.timers.push(g(h,500))},"settledCheck");c.timers.push(g(h,Math.min(t.settleMs,500)));for(const v of t.scheduleMs)c.timers.push(g(()=>{c.done||n!==c||b(`swap+${delayLabel(v)}`)},v))},closed(o,u,c){r.close(o,u,c),C()},activity(){y=e(),w=!0,k()},measure:M,oldestRetained:i(()=>r.oldestRetained(t.retainedAfterMs),"oldestRetained"),stop(){l=!0,A(),p&&clearTimeout(p),m&&clearTimeout(m)}}}d(createPodMemoryMonitor,"createPodMemoryMonitor"),i(createPodMemoryMonitor,"createPodMemoryMonitor");const mbOf=i(s=>s===void 0?"?":`${Math.round(s/MB)} MB`,"mbOf");function ageLabel(s){return s<9e4?`${Math.max(0,Math.round(s/1e3))}s`:`${Math.round(s/6e4)} min`}d(ageLabel,"ageLabel"),i(ageLabel,"ageLabel");function describePodMemory(s,e){const t=e.trigger==="boot"?`${s} memory at boot: ${mbOf(e.live)} live after a full GC \u2014 the baseline later readings compare with`:`${s} memory (${e.trigger}): ${mbOf(e.live)} live after a full GC`+(e.used-e.live>=MB?` (${mbOf(e.used)} before it)`:"")+(e.baseline?`, ${(e.live/e.baseline).toFixed(1)}\xD7 its ${mbOf(e.baseline)} boot baseline`:""),r=[`${mbOf(e.reserved)} reserved`,`rss ${mbOf(e.rss)}`,`generation ${e.gen}, ${e.swaps} swap${e.swaps===1?"":"s"}`,`GC ${e.gcMs} ms`];return e.previousAlive===!1?r.push(`generation ${e.previousGen} freed`):e.previousAlive===!0&&r.push(`generation ${e.previousGen} still in memory`),e.containers!==void 0&&r.push(`${e.containers} Nest container${e.containers===1?"":"s"}`),e.retained>0&&r.push(`${e.retained} closed generation${e.retained===1?"":"s"} RETAINED`),`${t} \xB7 ${r.join(" \xB7 ")}`}d(describePodMemory,"describePodMemory"),i(describePodMemory,"describePodMemory");function describeRetained(s,e,t){const r=t.counts&&Object.keys(t.counts).length?` Live now: ${Object.entries(t.counts).map(([a,l])=>`${a} ${l}`).join(", ")}.`:"";return`${s} ${e}: generation ${t.gen} still in memory ${ageLabel(t.ageMs)} after its app was closed (${t.swapsSinceClose} swap${t.swapsSinceClose===1?"":"s"} since, ${t.gcs} full GCs; still alive: ${t.alive.join(", ")}) \u2014 something still points into it.${r} See what with \`lensmcp mem ${e} --snapshot --analyze\`.`}d(describeRetained,"describeRetained"),i(describeRetained,"describeRetained");function describeReleased(s,e,t){return t.reason==="pod-exited"?`${s} ${e}: generation ${t.gen} went with its pod`:`${s} ${e}: generation ${t.gen} was collected after all, ${ageLabel(t.ageMs)} after its app was closed`}d(describeReleased,"describeReleased"),i(describeReleased,"describeReleased");
1
+ "use strict";var O=Object.defineProperty;var d=(s,e)=>O(s,"name",{value:e,configurable:!0});var I=Object.defineProperty,i=d((s,e)=>I(s,"name",{value:e,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.GenerationTracker=exports.LensmcpClosedGeneration=exports.RETAINED_MIN_GCS=void 0,exports.podMemoryPolicy=podMemoryPolicy,exports.fullGc=fullGc,exports.countLiveInstances=countLiveInstances,exports.createLiveObjectCounter=createLiveObjectCounter,exports.delayLabel=delayLabel,exports.createPodMemoryMonitor=createPodMemoryMonitor,exports.ageLabel=ageLabel,exports.describePodMemory=describePodMemory,exports.describeRetained=describeRetained,exports.describeReleased=describeReleased;const tslib_1=require("tslib"),node_module_1=require("node:module"),v8=tslib_1.__importStar(require("node:v8")),vm=tslib_1.__importStar(require("node:vm"));exports.RETAINED_MIN_GCS=2;const numberFrom=i((s,e,t)=>{if(s===void 0||s.trim()==="")return e;const r=Number(s);return Number.isFinite(r)&&r>=t?r:e},"numberFrom");function podMemoryPolicy(s=process.env){const e=["0","false","no","off"].includes((s.LENSMCP_POD_GC??"").trim().toLowerCase()),t=(s.LENSMCP_POD_GC_SCHEDULE_MS??"").split(",").map(r=>Number(r.trim())).filter(r=>Number.isFinite(r)&&r>0).map(Math.floor).sort((r,a)=>r-a);return{enabled:!e,scheduleMs:t.length?t:[3e4,12e4,3e5],idleMs:Math.floor(numberFrom(s.LENSMCP_POD_GC_IDLE_MS,6e4,0)),idleEveryMs:Math.floor(numberFrom(s.LENSMCP_POD_GC_IDLE_EVERY_MS,3e5,0)),retainedAfterMs:Math.floor(numberFrom(s.LENSMCP_POD_RETAINED_AFTER_MS,3e5,0)),settleMs:Math.floor(numberFrom(s.LENSMCP_POD_GC_SETTLE_MS,2e3,0)),countMaxBytes:Math.floor(numberFrom(s.LENSMCP_POD_COUNT_MAX_MB,64,0)*1024*1024)}}d(podMemoryPolicy,"podMemoryPolicy"),i(podMemoryPolicy,"podMemoryPolicy");let collector;function fullGc(){if(collector===void 0)try{v8.setFlagsFromString("--expose-gc");const s=vm.runInNewContext("gc");collector=typeof s=="function"?s:null}catch{collector=null}if(!collector)return!1;try{return collector(),!0}catch{return!1}}d(fullGc,"fullGc"),i(fullGc,"fullGc");function countLiveInstances(s){const e=v8.queryObjects;if(typeof e!="function"||typeof s!="function")return;const t=process.emitWarning;process.emitWarning=i(function(r,...a){const l=typeof a[0]=="string"?a[0]:a[0]?.type,n=typeof r=="string"?r:r?.message;if(!(l==="ExperimentalWarning"&&/queryObjects/.test(n??"")))return t.call(process,r,...a)},"quiet");try{const r=e(s,{format:"count"});return typeof r=="number"&&Number.isFinite(r)?r:void 0}catch{return}finally{process.emitWarning=t}}d(countLiveInstances,"countLiveInstances"),i(countLiveInstances,"countLiveInstances");const LEAK_CLASSES=[{name:"NestContainer",pkg:"@nestjs/core",pick:i(s=>s.NestContainer,"pick")},{name:"ZodObject",pkg:"zod",pick:i(s=>s.ZodObject,"pick")},{name:"DataSource",pkg:"typeorm",pick:i(s=>s.DataSource,"pick")},{name:"Redis",pkg:"ioredis",pick:i(s=>typeof s=="function"?s:s.default??s.Redis,"pick")},{name:"Worker",pkg:"bullmq",pick:i(s=>s.Worker,"pick")}];function createLiveObjectCounter(s,e=require.cache){let t;try{t=(0,node_module_1.createRequire)(s)}catch{t=void 0}const r=new Map,a=i(l=>{if(!t)return;let n=r.get(l.pkg);if(n===void 0){try{n=t.resolve(l.pkg)}catch{n=null}r.set(l.pkg,n)}if(!n)return;const p=e[n]?.exports;if(!(!p||typeof p!="object"&&typeof p!="function"))try{return l.pick(p)}catch{return}},"classOf");return{containers:i(()=>countLiveInstances(a(LEAK_CLASSES[0])),"containers"),all:i(()=>{const l={};for(const n of LEAK_CLASSES){const p=countLiveInstances(a(n));p!==void 0&&(l[n.name]=p)}return Object.keys(l).length?l:void 0},"all")}}d(createLiveObjectCounter,"createLiveObjectCounter"),i(createLiveObjectCounter,"createLiveObjectCounter");class LensmcpClosedGeneration{static{d(this,"LensmcpClosedGeneration")}static{i(this,"LensmcpClosedGeneration")}constructor(e,t){this.gen=e,this.refs={},this.label=`lensmcp closed generation ${e}`;for(const[r,a]of Object.entries(t))a&&(typeof a=="object"||typeof a=="function")&&(this.refs[r]=new WeakRef(a))}}exports.LensmcpClosedGeneration=LensmcpClosedGeneration;class GenerationTracker{static{d(this,"GenerationTracker")}static{i(this,"GenerationTracker")}constructor(e={}){this.opts=e,this.closed=new Map,this.freed=new Map,this.now=e.now??Date.now,this.registry=new FinalizationRegistry(t=>this.collected(t))}close(e,t,r){if(this.closed.has(e)||this.freed.has(e))return;const a=new LensmcpClosedGeneration(e,r),l=new Set(Object.keys(a.refs));if(l.size===0){this.markFreed(e);return}this.closed.set(e,{marker:a,closedAt:this.now(),swapsAtClose:t,gcs:0,alive:l});for(const[n,p]of Object.entries(a.refs)){const m=p.deref();m?this.registry.register(m,{gen:e,name:n}):l.delete(n)}l.size===0&&this.drop(e)}noteGc(){for(const e of this.closed.values())e.gcs+=1}isAlive(e){if(this.closed.has(e))return!0;if(this.freed.has(e))return!1}views(){return[...this.closed.entries()].map(([e,t])=>this.view(e,t))}dueForReport(e,t=this.now()){return this.views().filter(r=>r.reportedAt===void 0&&r.gcs>=exports.RETAINED_MIN_GCS&&t-r.closedAt>=e)}retainedCount(e,t=this.now()){return this.views().filter(r=>r.gcs>=exports.RETAINED_MIN_GCS&&t-r.closedAt>=e).length}markReported(e,t=this.now()){const r=this.closed.get(e);r&&(r.reportedAt=t)}oldestRetained(e,t=this.now()){return this.views().filter(r=>r.gcs>=exports.RETAINED_MIN_GCS&&t-r.closedAt>=e).sort((r,a)=>r.closedAt-a.closedAt)[0]}markers(){return[...this.closed.values()].map(e=>e.marker)}forgetAll(){const e=this.views().filter(t=>t.reportedAt!==void 0);for(const t of[...this.closed.keys()])this.drop(t);return e}collected(e){const t=this.closed.get(e.gen);if(!t||(t.alive.delete(e.name),t.alive.size>0))return;const r=this.view(e.gen,t);this.drop(e.gen);try{this.opts.onFreed?.(r,r.reportedAt!==void 0)}catch{}}drop(e){this.closed.delete(e),this.markFreed(e)}markFreed(e){this.freed.set(e,this.now()),this.freed.size>64&&this.freed.delete(this.freed.keys().next().value)}view(e,t){return{gen:e,closedAt:t.closedAt,swapsAtClose:t.swapsAtClose,gcs:t.gcs,alive:[...t.alive],...t.reportedAt!==void 0?{reportedAt:t.reportedAt}:{}}}}exports.GenerationTracker=GenerationTracker;const MB=1024*1024;function delayLabel(s){return s%6e4===0?`${s/6e4}m`:s%1e3===0?`${s/1e3}s`:`${s}ms`}d(delayLabel,"delayLabel"),i(delayLabel,"delayLabel");const turn=i(()=>new Promise(s=>setImmediate(s)),"turn");function createPodMemoryMonitor(s){const e=s.now??Date.now,t=s.policy,r=new GenerationTracker({now:e,onFreed:i((o,u)=>{u&&s.send({type:"pod-memory-released",released:{gen:o.gen,closedAt:o.closedAt,ageMs:e()-o.closedAt,reason:"collected"}})},"onFreed")});let a=Promise.resolve(),l=!1,n,p,m,w=0,A=!1,C=0;const M=i((o,u)=>{const c=setTimeout(o,Math.max(0,u));return c.unref?.(),c},"unrefTimer");function E(){return!n||n.previousGen===void 0?null:n.previousClosed()?r.isAlive(n.previousGen)!==!1:!0}d(E,"S"),i(E,"previousAlive");async function S(o){const u=process.memoryUsage().heapUsed,c=process.hrtime.bigint();fullGc();const f=Number(process.hrtime.bigint()-c)/1e6;r.noteGc(),await turn(),await turn();let h=s.containers?.();const v=process.memoryUsage(),g=v8.getHeapStatistics(),R=v8.getHeapSpaceStatistics().find(P=>P.space_name==="new_space"),$=s.state(),L=r.views(),N=e();return h!==void 0&&h<0&&(h=void 0),{trigger:o,at:N,gen:$.gen,swaps:$.swaps,live:v.heapUsed,used:u,reserved:v.heapTotal,rss:v.rss,external:v.external,youngGen:R?.space_size??0,limit:g.heap_size_limit,...$.baseline!==void 0?{baseline:$.baseline}:{},gcMs:Math.round(f),...n?.previousGen!==void 0?{previousGen:n.previousGen}:{},previousAlive:E(),closedAlive:L.length,retained:r.retainedCount(t.retainedAfterMs,N),...h!==void 0?{containers:h}:{},sourceMaps:process.sourceMapsEnabled===!0}}d(S,"k"),i(S,"collect");function G(o){for(const c of r.dueForReport(t.retainedAfterMs,o.at)){r.markReported(c.gen,o.at);const f=o.live<=t.countMaxBytes?s.counter?.all():void 0;s.send({type:"pod-memory-retained",retained:{gen:c.gen,closedAt:c.closedAt,ageMs:o.at-c.closedAt,swapsSinceClose:Math.max(0,o.swaps-c.swapsAtClose),gcs:c.gcs,alive:c.alive,...f?{counts:f}:{},live:o.live}})}const u=r.oldestRetained(t.retainedAfterMs,o.at);if(u)try{s.onRetained?.(u)}catch{}n&&!n.done&&o.previousAlive===!1&&_(),k()}d(G,"G"),i(G,"afterCollect");function y(o){const u=a.then(async()=>{const c=await S(o);return A=!1,l||(s.send({type:"pod-memory",report:c}),G(c)),c});return a=u.catch(()=>{}),u}d(y,"_"),i(y,"measure");function b(o){if(!l){if(s.state().busy){M(()=>b(o),1e3);return}y(o).catch(()=>{})}}d(b,"b"),i(b,"measureWhenFree");function _(){if(n){n.done=!0;for(const o of n.timers)clearTimeout(o);n.timers=[]}}d(_,"$"),i(_,"finishSchedule");function k(){if(p&&clearTimeout(p),p=void 0,l||!t.enabled)return;const o=r.views().filter(f=>f.reportedAt===void 0);if(o.length===0)return;const u=e(),c=Math.min(...o.map(f=>Math.max(f.closedAt+t.retainedAfterMs,u+1e3)));p=M(()=>{p=void 0,b("retention-check")},c-u)}d(k,"C"),i(k,"armRetentionCheck");function x(){if(l||!t.enabled||t.idleMs<=0||m)return;const o=Math.max(t.idleMs-(e()-w),C+t.idleEveryMs-e(),250);m=M(()=>{if(m=void 0,!!A){if(e()-w<t.idleMs||e()-C<t.idleEveryMs||s.state().busy){x();return}C=e(),b("idle")}},o)}return d(x,"x"),i(x,"armIdle"),{tracker:r,booted:i(()=>y("boot"),"booted"),swapped(o,u){if(l||(_(),w=e(),A=!0,!t.enabled))return;const c={...o!==void 0?{previousGen:o}:{},previousClosed:u,timers:[],done:!1};n=c;const f=e(),h=t.scheduleMs[0]??Number.POSITIVE_INFINITY,v=i(()=>{if(c.done||n!==c)return;const g=s.state();if(!g.busy&&u()&&e()-g.lastBusyAt>=t.settleMs){y("swap-settled").catch(()=>{});return}e()-f+500<h&&c.timers.push(M(v,500))},"settledCheck");c.timers.push(M(v,Math.min(t.settleMs,500)));for(const g of t.scheduleMs)c.timers.push(M(()=>{c.done||n!==c||b(`swap+${delayLabel(g)}`)},g))},closed(o,u,c){r.close(o,u,c),k()},activity(){w=e(),A=!0,x()},measure:y,oldestRetained:i(()=>r.oldestRetained(t.retainedAfterMs),"oldestRetained"),stop(){l=!0,_(),p&&clearTimeout(p),m&&clearTimeout(m)}}}d(createPodMemoryMonitor,"createPodMemoryMonitor"),i(createPodMemoryMonitor,"createPodMemoryMonitor");const mbOf=i(s=>s===void 0?"?":`${Math.round(s/MB)} MB`,"mbOf");function ageLabel(s){return s<9e4?`${Math.max(0,Math.round(s/1e3))}s`:`${Math.round(s/6e4)} min`}d(ageLabel,"ageLabel"),i(ageLabel,"ageLabel");function describePodMemory(s,e){const t=e.trigger==="boot"?`${s} memory at boot: ${mbOf(e.live)} live after a full GC \u2014 the baseline later readings compare with`:`${s} memory (${e.trigger}): ${mbOf(e.live)} live after a full GC`+(e.used-e.live>=MB?` (${mbOf(e.used)} before it)`:"")+(e.baseline?`, ${(e.live/e.baseline).toFixed(1)}\xD7 its ${mbOf(e.baseline)} boot baseline`:""),r=[`${mbOf(e.reserved)} reserved`,`rss ${mbOf(e.rss)}`,`generation ${e.gen}, ${e.swaps} swap${e.swaps===1?"":"s"}`,`GC ${e.gcMs} ms`];return e.previousAlive===!1?r.push(`generation ${e.previousGen} freed`):e.previousAlive===!0&&r.push(`generation ${e.previousGen} still in memory`),e.containers!==void 0&&r.push(`${e.containers} Nest container${e.containers===1?"":"s"}`),e.retained>0&&r.push(`${e.retained} closed generation${e.retained===1?"":"s"} RETAINED`),`${t} \xB7 ${r.join(" \xB7 ")}`}d(describePodMemory,"describePodMemory"),i(describePodMemory,"describePodMemory");function describeRetained(s,e,t){const r=t.counts&&Object.keys(t.counts).length?` Live now: ${Object.entries(t.counts).map(([a,l])=>`${a} ${l}`).join(", ")}.`:"";return`${s} ${e}: generation ${t.gen} still in memory ${ageLabel(t.ageMs)} after its app was closed (${t.swapsSinceClose} swap${t.swapsSinceClose===1?"":"s"} since, ${t.gcs} full GCs; still alive: ${t.alive.join(", ")}) \u2014 something still points into it.${r} See what with \`lensmcp mem ${e} --snapshot --analyze\`.`}d(describeRetained,"describeRetained"),i(describeRetained,"describeRetained");function describeReleased(s,e,t){return t.reason==="pod-exited"?`${s} ${e}: generation ${t.gen} went with its pod`:`${s} ${e}: generation ${t.gen} was collected after all, ${ageLabel(t.ageMs)} after its app was closed`}d(describeReleased,"describeReleased"),i(describeReleased,"describeReleased");