@lensmcp/cluster 1.25.21 → 1.25.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/child-process-env.d.ts +7 -0
- package/child-process-env.js +1 -0
- package/executors/gateway/runtime/control.js +2 -2
- package/executors/gateway/runtime/lifecycle.js +3 -3
- package/executors/serve/serve.impl.js +1 -1
- package/main.devserver.js +2 -2
- package/package.json +4 -4
- package/worker-supervisor.js +1 -1
package/README.md
CHANGED
|
@@ -104,6 +104,8 @@ A declaration must route *somewhere*: either a pod `service` or a TCP `upstream`
|
|
|
104
104
|
|
|
105
105
|
> Pass `minPods` via the `--childCount` option — the Nx daemon drops spawner env, so don't pin `childCount` in `serve-hmr` options expecting `minPods` to flow through.
|
|
106
106
|
|
|
107
|
+
**Child-process colors** — before launching devservers, pods or workers, LensMCP removes `NO_COLOR` and `NODE_DISABLE_COLORS` when `FORCE_COLOR` is set. This preserves Node's existing precedence (including `FORCE_COLOR=0`) without repeating its conflicting-environment warning on every hot reload. A color opt-out without `FORCE_COLOR` is preserved; the Nx task environment is unchanged.
|
|
108
|
+
|
|
107
109
|
**`gateway`** — `ports` (default `[443]` so dev domains need no `:port`); `https` (default `true`, terminate TLS with the local CA); `middleware` (workspace-relative JS module `(req) => void` run on every request — the JWT/auth seam; throwing rejects with 401); `trafficFlushMs` (traffic-edge aggregation window before flushing to the LensMCP bus; default 5000).
|
|
108
110
|
|
|
109
111
|
**Hot swap and process names** — a pod hot-swaps by re-requiring its bundle in the same process. Global class registries in libraries loaded once from node_modules (`@nestjs/typeorm`'s entity storage, TypeORM's metadata args) have the classes the new bundle replaced removed, so the previous generation can be collected (`LENSMCP_SWAP_PRUNE_REGISTRIES=0` turns it off). Pods, devservers and nx runners run under a hard link named `<workspace>-<service>-pod|dev|nx`, so Activity Monitor and `top` show which service and workspace a process belongs to (`LENSMCP_PROCESS_NAMES=0` turns it off).
|
|
@@ -131,6 +133,7 @@ A second checkout of a workspace — a git worktree an agent works in — can be
|
|
|
131
133
|
- **Each workspace's routes run its own edge middleware** — the `middleware` of the `@lensmcp/cluster:gateway` target in its own tree, loaded from its own root when it registers; one that declares none runs none. The owner's routes run the owner's, as before. `LENSMCP_GUEST_MIDDLEWARE=owner` restores the old behaviour (the owner's middleware on every route). A middleware is called `(req, ctx)`: `ctx` is `{ wsKey, root, env }`, where `env` is a worktree instance's variables (empty otherwise) — a middleware runs inside the daemon, so its `process.env` is the owner's, and an instance's addresses (its `AUTH_API_RESOURCE`, …) reach it this way. A one-argument middleware ignores it.
|
|
132
134
|
- **A restarted daemon hosts its guests again.** Every registration is recorded in `~/.lensmcp/guests.json` (owner-only) and replayed on boot, one workspace at a time, through the same guards; an unregister forgets it, a folder that is gone is dropped. Only the daemon of the workspace it registered with replays it. `LENSMCP_GUEST_REPLAY=0` turns it off.
|
|
133
135
|
- **Cold starts queue daemon-wide** (`LENSMCP_MAX_COLD_STARTS`, default half the cores): a page that touches a dozen lazy services, or two dozen worktrees waking at once, no longer starts every `serve-hmr` tree and cold compile in the same second.
|
|
136
|
+
- **Explicit restarts get a fresh idle window.** Idle cleanup skips starting services and pending restarts; a successful restart starts its idle clock again. Retiring generations keep forwarding final pipe output until stdio closes, with a bounded fallback for inherited pipes.
|
|
134
137
|
- **Worktree instances show under their project** — nested under it on the `lensmcp.local/` chooser, and in a Worktrees panel on its Cluster page (running ones link to their own dashboard); an instance's own dashboard says whose worktree it is.
|
|
135
138
|
|
|
136
139
|
## How it fits
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keep Node's FORCE_COLOR precedence without passing contradictory color flags to children.
|
|
3
|
+
* Nx adds FORCE_COLOR to the task environment even when the launching shell has NO_COLOR.
|
|
4
|
+
* Normalize at the spawn boundary, after all overrides, so task/dotenv handling stays unchanged
|
|
5
|
+
* and each hot-swapped pod does not emit the same startup warning. Never mutate the parent.
|
|
6
|
+
*/
|
|
7
|
+
export declare function childProcessEnv(base: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var o=Object.defineProperty;var c=(t,e)=>o(t,"name",{value:e,configurable:!0});var r=Object.defineProperty,n=c((t,e)=>r(t,"name",{value:e,configurable:!0}),"n");Object.defineProperty(exports,"__esModule",{value:!0}),exports.childProcessEnv=childProcessEnv;function childProcessEnv(t){const e={...t};return e.FORCE_COLOR!==void 0&&(delete e.NO_COLOR,delete e.NODE_DISABLE_COLORS),e}c(childProcessEnv,"childProcessEnv"),n(childProcessEnv,"childProcessEnv");
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`)}catch{}let K;if(r.graphStores){const v={root:e.root,daemonRoot:r.root,otherRoots:r.registry.keys().filter(
|
|
1
|
+
"use strict";var T=Object.defineProperty;var g=(o,r)=>T(o,"name",{value:r,configurable:!0});var G=Object.defineProperty,u=g((o,r)=>G(o,"name",{value:r,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.clusterVersion=void 0,exports.instanceSummary=instanceSummary,exports.controlSocketPath=controlSocketPath,exports.versionAtLoad=versionAtLoad,exports.readClusterVersion=readClusterVersion,exports.ensureOwnerOnlyDir=ensureOwnerOnlyDir,exports.startControlServer=startControlServer;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),discovery_1=require("./discovery"),guest_graph_1=require("./guest-graph"),guest_replay_1=require("./guest-replay"),registration_guards_1=require("./registration-guards"),scope_1=require("./scope"),service_keys_1=require("./service-keys"),workspace_log_1=require("./workspace-log"),workspace_middleware_1=require("./workspace-middleware");function instanceSummary(o){const r=o?.instance;return r?{instance:r.name,baseKey:r.baseKey,apex:r.apex,baseApex:r.baseApex,...r.frozen?{frozen:!0}:{}}:{}}g(instanceSummary,"instanceSummary"),u(instanceSummary,"instanceSummary");function controlSocketPath(){const o=process.env.LENSMCP_HOME||os.homedir();return path.join(o,".lensmcp","control.sock")}g(controlSocketPath,"controlSocketPath"),u(controlSocketPath,"controlSocketPath");const CONTROL_BODY_BYTES=1e6;class BodyTooLarge extends Error{static{g(this,"BodyTooLarge")}static{u(this,"BodyTooLarge")}constructor(r){super(`body too large (over ${r} bytes)`),this.limit=r}}exports.clusterVersion=versionAtLoad(()=>readClusterVersion(__dirname));function versionAtLoad(o){const r=o();return()=>r}g(versionAtLoad,"versionAtLoad"),u(versionAtLoad,"versionAtLoad");function readClusterVersion(o){let r=o;for(let p=0;p<6;p++){const h=path.join(r,"package.json");if(fs.existsSync(h))try{const l=JSON.parse(fs.readFileSync(h,"utf8"));if(l.name==="@lensmcp/cluster"&&typeof l.version=="string")return l.version}catch{}const a=path.dirname(r);if(a===r)break;r=a}}g(readClusterVersion,"readClusterVersion"),u(readClusterVersion,"readClusterVersion");function readJsonBody(o,r=CONTROL_BODY_BYTES){return new Promise((p,h)=>{const a=[];let l=0,k=!1;o.on("data",m=>{if(!k){if(l+=m.length,l>r){k=!0,a.length=0,h(new BodyTooLarge(r));return}a.push(m)}}),o.on("end",()=>{if(k)return;const m=Buffer.concat(a).toString("utf8");try{p({value:m?JSON.parse(m):{},bytes:l})}catch(S){h(S)}}),o.on("error",h)})}g(readJsonBody,"readJsonBody"),u(readJsonBody,"readJsonBody");function graphShare(o,r){return r-Buffer.byteLength(JSON.stringify({...o,projectGraph:null}))}g(graphShare,"graphShare"),u(graphShare,"graphShare");function graphVerdict(o){return o?o.refused===void 0?{forwarded:!0,accepted:!0}:{forwarded:!0,accepted:!1,reason:o.refused}:{forwarded:!1,accepted:!1}}g(graphVerdict,"graphVerdict"),u(graphVerdict,"graphVerdict");function ensureOwnerOnlyDir(o){try{fs.mkdirSync(o,{recursive:!0,mode:448})}catch{}try{const r=fs.lstatSync(o);return r.isDirectory()?((r.mode&63)!==0&&fs.chmodSync(o,448),!0):!1}catch{return!1}}g(ensureOwnerOnlyDir,"ensureOwnerOnlyDir"),u(ensureOwnerOnlyDir,"ensureOwnerOnlyDir");function startControlServer(o){const{rt:r}=o,p=controlSocketPath(),h=path.dirname(p);ensureOwnerOnlyDir(h)||console.warn(`[gateway] control home ${h} is not a usable owner-only directory \u2014 refusing to expose the control plane there.`);try{fs.unlinkSync(p)}catch{}const a=u((e,n,c)=>{e.writeHead(n,{"content-type":"application/json"}),e.end(JSON.stringify(c))},"send"),l=u(async(e,n,c=!1)=>{if(!e.wsKey||!e.root)return{status:400,json:{error:"wsKey and root are required"}};const t=e.projects??{},s=(0,discovery_1.projectSourceRoots)(e.root,t,e.projectDependencies),i=(0,scope_1.readLensScope)(e.root),y=i.key===e.wsKey,d=y&&i.sockNs!==e.wsKey?i.sockNs:void 0,{routes:w,services:f,instance:j}=(0,discovery_1.discoverRoutes)(e.root,t,void 0,e.wsKey,s,d,y?i.instance:void 0),b=(0,workspace_middleware_1.findGatewayMiddleware)(e.root,t),$={wsKey:e.wsKey,...d?{sockNs:d}:{},root:e.root,routes:w,services:f,...j?{instance:j}:{},...b?{middleware:b}:{}},_=(0,registration_guards_1.refuseRegistration)(r.registry,$);if(_)return console.warn(`[gateway] refused to register '${e.wsKey}' from ${e.root}: ${_.error}`),{status:409,json:_};if(c)return j?{status:200,json:{wsKey:e.wsKey,root:e.root,...instanceSummary($),env:j.env}}:{status:400,json:{error:`'${e.wsKey}' has no resolvable instance configuration`}};try{const v=(0,service_keys_1.adoptServiceKeys)(r,e.root,f,e.wsKey);v.added.length>0&&console.log(`[gateway] adopted east-west keys for ${e.wsKey}: ${v.added.join(", ")}`),v.regenerated.length>0&&console.warn(`[gateway] ${e.root} carried another workspace's east-west keys (a copied key file) \u2014 new keys for ${e.wsKey}: ${v.regenerated.join(", ")}`)}catch(v){console.error(`[gateway] could not adopt east-west keys for ${e.wsKey}: ${v.message}`)}try{(0,workspace_log_1.workspaceLogWriter)(e.root)?.(`[gateway] ${new Date().toISOString()} this workspace ('${e.wsKey}') is served by the daemon at ${r.root} (pid ${process.pid}); its gateway-level log is ${path.join(r.root,".lensmcp","gateway.log")}. Pod output for this workspace follows here. Attach live with \`lensmcp logs <service>\`.
|
|
2
|
+
`)}catch{}let K;if(r.graphStores){const v={root:e.root,daemonRoot:r.root,otherRoots:r.registry.keys().filter(O=>O!==e.wsKey).flatMap(O=>r.registry.get(O)?.root??[])};K=e.projectGraph===void 0?void 0:(0,guest_graph_1.admitForwardedGraph)(e.projectGraph,{...v,bytes:graphShare(e,n)}),K?.refused!==void 0&&console.warn(`[gateway] refused the project graph '${e.wsKey}' forwarded from ${e.root}: ${K.refused} \u2014 its services start through \`nx run\` until the gateway computes it`),(0,registration_guards_1.sameRoot)(e.root,r.root)||r.graphStores.set((0,guest_graph_1.createGuestGraphStore)({wsKey:e.wsKey,root:e.root,...K?{admission:K}:{},context:v}))}return r.registry.register($),await o.onRegister?.($),r.rebuildRoutes(),r.root&&!(0,registration_guards_1.sameRoot)(e.root,r.root)&&(0,guest_replay_1.recordGuest)({wsKey:e.wsKey,root:e.root,projects:t,...e.projectDependencies?{projectDependencies:e.projectDependencies}:{},daemonRoot:r.root,registeredAt:new Date().toISOString()}),{status:200,json:{ok:!0,wsKey:e.wsKey,routes:w.length,services:f.length,workspaces:r.registry.keys(),...r.graphStores?{projectGraph:graphVerdict(K)}:{}}}},"register"),k=u((e,n)=>{const c=r.registry.get(e);if(!c)return{error:`no workspace '${e}' is registered`,workspaces:r.registry.keys()};const t=c.services.find(s=>s.project===n);return t?{svc:t}:{error:`'${e}' has no service '${n}'`,services:c.services.map(s=>s.project)}},"findService"),m=u(e=>({wsKey:e.wsKey,service:e.project,state:e.state,...e.generation!==void 0?{generation:e.generation}:{},...e.restart?{restart:e.restart}:{}}),"restartView"),S=http.createServer((e,n)=>{(async()=>{try{const c=(e.url??"").split("?")[0];if(e.method==="GET"&&c==="/list")return a(n,200,{workspaces:r.registry.keys().map(t=>{const s=r.registry.get(t);return{key:t,root:s?.root,routes:s?.routes.length??0,services:s?.services.length??0,...instanceSummary(s)}})});if(e.method==="GET"&&c==="/status"){const t=(0,exports.clusterVersion)();return a(n,200,{daemon:{pid:process.pid,wsKey:r.wsKey,...t?{version:t}:{}},workspaces:r.registry.keys().map(s=>{const i=r.registry.get(s);return{key:s,root:i?.root,routes:i?.routes.length??0,services:i?.services.length??0,isDaemon:s===r.wsKey,...instanceSummary(i)}}),services:r.registry.allServices().map(s=>({project:s.project,wsKey:s.wsKey,host:s.decl.host,state:s.state,...s.generation!==void 0?{generation:s.generation}:{},...s.restart?{restart:s.restart}:{}}))})}if(e.method==="GET"&&c==="/instance-env"){const t=new URL(e.url??"/","http://control").searchParams.get("wsKey")??"",s=r.registry.get(t);return s?s.instance?a(n,200,{wsKey:t,root:s.root,...instanceSummary(s),env:s.instance.env}):a(n,404,{error:`'${t}' is not an instance`}):a(n,404,{error:`no workspace '${t}' is registered`})}if(e.method==="POST"&&c==="/instance-env"){const{value:t,bytes:s}=await readJsonBody(e,CONTROL_BODY_BYTES+guest_graph_1.MAX_FORWARDED_GRAPH_BYTES),i=await l(t,s,!0);return a(n,i.status,i.json)}if(c==="/restart"&&(e.method==="POST"||e.method==="GET")){const t=e.method==="GET"?Object.fromEntries(new URL(e.url??"/","http://control").searchParams):(await readJsonBody(e)).value??{},s=typeof t.wsKey=="string"?t.wsKey:"",i=typeof t.service=="string"?t.service:"";if(!s||!i)return a(n,400,{error:"wsKey and service are required"});const y=k(s,i);if("error"in y)return a(n,404,y);const d=y.svc;if(e.method==="GET")return a(n,200,m(d));if(!o.restartService)return a(n,501,{error:"this gateway cannot restart a service"});const w=typeof t.reason=="string"&&t.reason.trim()?t.reason.trim().slice(0,200):"asked for",f=o.restartService(d,{hard:t.hard===!0,reason:w});return"refused"in f?a(n,409,{error:f.refused,...m(d)}):a(n,202,{ok:!0,already:f.already,...m(d)})}if(e.method==="GET"&&c==="/identities"||e.method==="POST"&&c==="/act"){const t=e.method==="GET"?Object.fromEntries(new URL(e.url??"/","http://control").searchParams):(await readJsonBody(e)).value??{},s=typeof t.wsKey=="string"?t.wsKey:"";if(!s)return a(n,400,{error:"wsKey is required"});if(!r.registry.get(s)&&s!==r.wsKey)return a(n,404,{error:`no workspace '${s}' is registered`,workspaces:r.registry.keys()});if(!o.act)return a(n,501,{error:"acting as a signed-in user is turned off on this gateway (LENSMCP_GW_ACT=0)"});if(e.method==="GET")return a(n,200,{wsKey:s,identities:o.act.list(s)});const i=u(f=>typeof t[f]=="string"&&t[f].trim()?t[f].trim().slice(0,256):void 0,"pick"),y=i("user"),d=i("tenant"),w=o.act.mint(s,{...y?{user:y}:{},...d?{tenant:d}:{}});return"error"in w?a(n,404,{wsKey:s,...w}):a(n,200,{wsKey:s,...w})}if(e.method==="POST"&&c==="/register"){const{value:t,bytes:s}=await readJsonBody(e,CONTROL_BODY_BYTES+guest_graph_1.MAX_FORWARDED_GRAPH_BYTES),i=await l(t,s);return a(n,i.status,i.json)}if(e.method==="POST"&&c==="/unregister"){const t=(await readJsonBody(e)).value;if(!t.wsKey)return a(n,400,{error:"wsKey is required"});const s=(0,registration_guards_1.refuseUnregistration)(r.registry,{wsKey:t.wsKey,...t.root?{root:t.root}:{}},r.wsKey);if(s)return console.warn(`[gateway] refused to unregister '${t.wsKey}'${t.root?` for ${t.root}`:""}: ${s.error}`),a(n,409,s);const i=r.registry.unregister(t.wsKey);if(i){for(const y of i.services){const d=(0,service_keys_1.serviceKeyId)(y.wsKey??t.wsKey,y.project),w=r.serviceKeys[d];w&&(delete r.serviceKeys[d],r.keyToProject.delete(w),r.keyToWorkspace?.delete(w))}for(const y of i.services)o.killService(y,"workspace unregistered");r.graphStores?.delete(i.root),(0,guest_replay_1.forgetGuest)(t.wsKey),o.onUnregister?.(i)}return r.rebuildRoutes(),a(n,200,{ok:!0,removed:!!i,workspaces:r.registry.keys()})}a(n,404,{error:"not found"})}catch(c){if(c instanceof BodyTooLarge)return e.resume(),a(n,413,{error:c.message});a(n,500,{error:c.message})}})()});return S.listen(p,()=>{try{fs.chmodSync(p,384)}catch(e){console.warn(`[gateway] could not restrict ${p} to 0600:`,e.message)}}),{socketPath:p,async replay(){const{replay:e,gone:n}=(0,guest_replay_1.guestsToReplay)(r.root,(0,guest_replay_1.readGuests)()),c={replayed:[],refused:[],gone:n.map(t=>t.wsKey)};for(const t of n)(0,guest_replay_1.forgetGuest)(t.wsKey),console.log(`[gateway] not re-hosting '${t.wsKey}': ${t.root} is no longer a workspace \u2014 forgotten`);for(const t of e)if(!r.registry.has(t.wsKey))try{const s=await l({wsKey:t.wsKey,root:t.root,projects:t.projects,...t.projectDependencies?{projectDependencies:t.projectDependencies}:{}},0);s.status===200?(c.replayed.push(t.wsKey),console.log(`[gateway] re-hosted '${t.wsKey}' (${t.root}) \u2014 registered before this daemon restarted`)):(c.refused.push(t.wsKey),console.warn(`[gateway] could not re-host '${t.wsKey}' (${t.root}): ${JSON.stringify(s.json)} \u2014 \`lensmcp gateway start\` there`))}catch(s){c.refused.push(t.wsKey),console.warn(`[gateway] could not re-host '${t.wsKey}' (${t.root}): ${s.message}`)}return c},close:u(()=>{S.close();try{fs.unlinkSync(p)}catch{}},"close")}}g(startControlServer,"startControlServer"),u(startControlServer,"startControlServer");
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var Ue=Object.defineProperty;var v=(t,a)=>Ue(t,"name",{value:a,configurable:!0});var Ve=Object.defineProperty,s=v((t,a)=>Ve(t,"name",{value:a,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.scaleTarget=scaleTarget,exports.isLoopbackHostname=isLoopbackHostname,exports.isOwnRunnerCommand=isOwnRunnerCommand,exports.isRunnerOf=isRunnerOf,exports.isTestSourcePath=isTestSourcePath,exports.sourceScanPass=sourceScanPass,exports.sourceSetSnapshot=sourceSetSnapshot,exports.sourceSetSignature=sourceSetSignature,exports.diffSourceSets=diffSourceSets,exports.sourceChangeWindowMs=sourceChangeWindowMs,exports.sourceScopeDirs=sourceScopeDirs,exports.podRecycleReason=podRecycleReason,exports.lensFrontendStale=lensFrontendStale,exports.lensWatcherVerdict=lensWatcherVerdict,exports.podWatcherVerdict=podWatcherVerdict,exports.lensChildWedged=lensChildWedged,exports.isPortConflictExit=isPortConflictExit,exports.podChangeClock=podChangeClock,exports.createServiceLayer=createServiceLayer,exports.chooseStalePodKillTarget=chooseStalePodKillTarget;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),node_crypto_1=require("node:crypto"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),net=tslib_1.__importStar(require("node:net")),path=tslib_1.__importStar(require("node:path")),node_util_1=require("node:util"),discovery_1=require("./discovery"),pod_sock_1=require("../../../pod-sock"),scope_1=require("./scope"),pod_env_1=require("./pod-env"),pod_probe_1=require("./pod-probe"),service_keys_1=require("./service-keys"),workspace_log_1=require("./workspace-log"),own_log_1=require("./own-log"),inspector_secret_1=require("../../../inspector-secret"),pod_output_1=require("./pod-output"),serve_launch_1=require("./serve-launch"),shared_build_1=require("./shared-build"),warm_start_1=require("./warm-start"),protocol_1=require("../../../shared-build/protocol"),types_1=require("./types"),exit_reason_1=require("../../../exit-reason"),handoff_retire_1=require("../../../handoff-retire"),process_name_1=require("../../../process-name");function eastWestEnv(t,a){const c={},d=t.serviceKeys[(0,service_keys_1.serviceKeyId)(a.wsKey,a.project)];if(d&&(c.LENSMCP_SERVICE_KEY=d),t.https){const g=require("../../../basic-ssl").caCertPath();fs.existsSync(g)&&(c.NODE_EXTRA_CA_CERTS=g)}return c}v(eastWestEnv,"eastWestEnv"),s(eastWestEnv,"eastWestEnv");const sleep=s(t=>new Promise(a=>setTimeout(a,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 a=2166136261;for(let c=0;c<t.length;c+=1)a^=t.charCodeAt(c),a=Math.imul(a,16777619);return a>>>0}v(fnv1a,"fnv1a"),s(fnv1a,"fnv1a");const execFileP=(0,node_util_1.promisify)(node_child_process_1.execFile);async function gitIgnoredPaths(t){try{const{stdout:a}=await execFileP("git",["ls-files","--others","--directory","--ignored","--exclude-standard","-z"],{cwd:t,maxBuffer:33554432,timeout:1e4,windowsHide:!0});return new Set(a.split("\0").filter(Boolean))}catch{return new Set}}v(gitIgnoredPaths,"gitIgnoredPaths"),s(gitIgnoredPaths,"gitIgnoredPaths");function scaleTarget(t,a=fs.existsSync){if(t.decl.adminUrl)return{url:t.decl.adminUrl};const c=path.join(t.pool.dir,"parent.sock");return a(c)?{socketPath:c}:t.decl.port?{url:`http://localhost:${t.decl.port}`}:void 0}v(scaleTarget,"scaleTarget"),s(scaleTarget,"scaleTarget");function isLoopbackHostname(t){const a=t.toLowerCase().replace(/^\[(.*)\]$/,"$1").replace(/\.$/,"");return a==="localhost"||a.endsWith(".localhost")?!0:net.isIPv4(a)?a.split(".")[0]==="127":net.isIPv6(a)&&new URL(`http://[${a}]/`).hostname==="[::1]"}v(isLoopbackHostname,"isLoopbackHostname"),s(isLoopbackHostname,"isLoopbackHostname");function postScale(t,a,c){let d;if("socketPath"in t)d=http.request({socketPath:t.socketPath,path:"/webpack/scale",method:"POST",headers:{"content-type":"application/json"}},g=>g.resume());else{const g=t.url.startsWith("https"),M=g?require("node:https"):http,m={method:"POST"};g&&isLoopbackHostname(new URL(t.url).hostname)&&(m.rejectUnauthorized=!1),c&&(m.lookup=c),d=M.request(`${t.url}/webpack/scale`,m,E=>E.resume())}return d.on("error",()=>{}),d.end(JSON.stringify({pods:a})),d}v(postScale,"postScale"),s(postScale,"postScale");function isOwnRunnerCommand(t,a){return(0,serve_launch_1.isServeRunnerCommand)(t)?(0,serve_launch_1.isServeRunnerCommandOf)(t,a):t.includes("/node_modules/nx/")?t.includes(`${a.replace(/\/+$/,"")}/node_modules/nx/`):!0}v(isOwnRunnerCommand,"isOwnRunnerCommand"),s(isOwnRunnerCommand,"isOwnRunnerCommand");function isRunnerOf(t,a,c){const d=a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return!new RegExp(`(^|\\s)run ${d}(:|\\s|$)`).test(t)||!(0,serve_launch_1.isServeRunnerCommand)(t)&&!/\bnx(\.js)?\b/.test(t)?!1:isOwnRunnerCommand(t,c)}v(isRunnerOf,"isRunnerOf"),s(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 a=t.split("/"),c=a[a.length-1]??"";if(TEST_FILE_RE.test(c))return!0;for(let d=0;d<a.length-1;d+=1)if(TEST_DIR_SEGMENTS.has(a[d]))return!0;return!1}v(isTestSourcePath,"isTestSourcePath"),s(isTestSourcePath,"isTestSourcePath");function sourceScanPass(t,a,c){const d=c?.ignoreTests??!0;let g;const M=new Map,m=`tree:${path.resolve(t)}`,E=s(w=>path.relative(t,w).split(path.sep).join("/"),"rel"),C=s(async(w,y)=>{const _=await(g??=gitIgnoredPaths(t)),D=[],O=new Set;let P=!1;const V=s(async(Q,S)=>{if(D.length>=SCAN_FILE_CAP){P=!0;return}let N;try{N=await fs.promises.readdir(Q,{withFileTypes:!0})}catch{return}S&&O.add(E(Q));for(const X of N){if(D.length>=SCAN_FILE_CAP){P=!0;return}const F=X.name,Z=path.join(Q,F);if(X.isDirectory()){if(!S||F.startsWith(".")||SRC_EXCLUDE.has(F)||a?.has(F)||F.endsWith("-devserver")||_.has(`${E(Z)}/`))continue;await V(Z,!0)}else if(X.isFile()){const ee=F.lastIndexOf(".");if(ee<=0||!SRC_EXT.has(F.slice(ee)))continue;const H=E(Z);if(_.has(H)||d&&isTestSourcePath(H))continue;D.push(H)}}},"walk");return await V(w,y),{paths:D,entered:O,truncated:P}},"walkDir"),I=s((w,y)=>{let _=M.get(w);return _||(_=y(),M.set(w,_)),_},"memo"),se=s(async()=>{const w=M.get(m);if(!w)return;const y=await w;return y.truncated?void 0:y},"wideWalk"),J=new Set,ne=s(()=>I(`files:${path.resolve(t)}`,async()=>{const w=await se();return w?{paths:w.paths.filter(y=>!y.includes("/")),entered:J,truncated:!1}:C(t,!1)}),"rootFiles"),ae=s(w=>I(`tree:${path.resolve(w)}`,async()=>{const y=await se(),_=E(w);if(y?.entered.has(_)){const D=`${_}/`;return{paths:_===""?y.paths:y.paths.filter(O=>O.startsWith(D)),entered:J,truncated:!1}}return C(w,!0)}),"subtree"),B=s(w=>{const y=new Set;let _=0,D=w.some(P=>P.truncated);const O=s(P=>y.has(P)?!0:y.size>=SCAN_FILE_CAP?(D=!0,!1):(y.add(P),_^=fnv1a(P),!0),"add");for(const P of w)if(!P.paths.every(O))break;return{signature:`${y.size}:${(_>>>0).toString(36)}`,paths:y,truncated:D}},"compose");return{async snapshot(w){if(!w||w.length===0)return B([await I(m,()=>C(t,!0))]);const y=[await ne()];for(const _ of w)y.push(await ae(_));return B(y)}}}v(sourceScanPass,"sourceScanPass"),s(sourceScanPass,"sourceScanPass");async function sourceSetSnapshot(t,a,c,d){return sourceScanPass(t,c,d).snapshot(a)}v(sourceSetSnapshot,"sourceSetSnapshot"),s(sourceSetSnapshot,"sourceSetSnapshot");async function sourceSetSignature(t,a,c,d){return(await sourceSetSnapshot(t,a,c,d)).signature}v(sourceSetSignature,"sourceSetSignature"),s(sourceSetSignature,"sourceSetSignature");const SOURCE_DIFF_PATH_CAP=128;function diffSourceSets(t,a,c,d){if(t.paths.size===a.paths.size){let E=!0;for(const C of t.paths)if(!a.paths.has(C)){E=!1;break}if(E)return null}const g=[],M=[];let m=t.truncated||a.truncated;for(const E of a.paths)t.paths.has(E)||(g.length+M.length<SOURCE_DIFF_PATH_CAP?g.push(E):m=!0);for(const E of t.paths)a.paths.has(E)||(g.length+M.length<SOURCE_DIFF_PATH_CAP?M.push(E):m=!0);return{changedAt:c,added:g,removed:M,truncated:m,...d!==void 0?{windowMs:d}:{}}}v(diffSourceSets,"diffSourceSets"),s(diffSourceSets,"diffSourceSets");function sourceChangeWindowMs(t,a,c,d){const g=a&&a>0?t-a:c;return Math.max(g,c)+d}v(sourceChangeWindowMs,"sourceChangeWindowMs"),s(sourceChangeWindowMs,"sourceChangeWindowMs");function sourceScopeDirs(t,a,c,d,g){const M=s(C=>{const I=path.relative(t,C).split(path.sep).filter(Boolean);return I.length===0||I[0].startsWith("..")?"":I[0]},"bucketOf")(a);if(!M)return[];const m=new Set(c.filter(Boolean)),E=new Set([M]);for(const C of d)C.startsWith(".")||SRC_EXCLUDE.has(C)||g?.has(C)||C.endsWith("-devserver")||m.has(C)||E.add(C);return[...E].sort().map(C=>path.join(t,C))}v(sourceScopeDirs,"sourceScopeDirs"),s(sourceScopeDirs,"sourceScopeDirs");function podRecycleReason(t,a,c,d){return!t.proc||t.state!=="up"||t.spawnAt==null||t.inflight>0||(t.activeWork??0)>0||a-t.lastUsed<d.settleMs||t.lastStaleRecycleAt!=null&&a-t.lastStaleRecycleAt<d.cooldownMs?null:c>0&&c-t.spawnAt>d.graceMs?"stale-source-set":d.maxAgeMs>0&&a-t.spawnAt>d.maxAgeMs?"max-age":null}v(podRecycleReason,"podRecycleReason"),s(podRecycleReason,"podRecycleReason");function lensFrontendStale(t,a,c,d,g){return!(d-a<g.cooldownMs||c<=0||c-t<=g.graceMs||d-c<g.settleMs)}v(lensFrontendStale,"lensFrontendStale"),s(lensFrontendStale,"lensFrontendStale");function lensWatcherVerdict(t,a,c,d=[]){if(!t)return"unknown";if("schemaVersion"in t&&t.schemaVersion>=2&&d.length>0){const g=a-c,M=new Set(t.recentEvents.filter(m=>m.at>=g).map(m=>path.resolve(m.path)));return d.every(m=>M.has(path.resolve(m)))?"heard":"missed"}return t.lastFsSetEventAt>=a-c?"heard":"missed"}v(lensWatcherVerdict,"lensWatcherVerdict"),s(lensWatcherVerdict,"lensWatcherVerdict");function podWatcherVerdict(t,a,c){if(!t)return"unknown";if(t.degraded)return"degraded";const d=a-c;return t.lastWatchRunAt>=d||t.lastBuildAt>=d?"heard":"silent"}v(podWatcherVerdict,"podWatcherVerdict"),s(podWatcherVerdict,"podWatcherVerdict");function lensChildWedged(t,a,c,d){const g=t.hasListened?d.graceMs:Math.max(d.graceMs,d.neverListenedGraceMs);return c-t.spawnedAt<g||c-a<d.cooldownMs||t.probeFails<Math.max(2,d.failureThreshold)?null:"wedged-no-listener"}v(lensChildWedged,"lensChildWedged"),s(lensChildWedged,"lensChildWedged");function isPortConflictExit(t,a){return t.signal||t.code===null||t.code===0||t.ranMs>a.fastFailMs?!1:t.portHeld}v(isPortConflictExit,"isPortConflictExit"),s(isPortConflictExit,"isPortConflictExit");function podChangeClock(t,a){const c=t.sourceSetChangedFor?.get(a);if(c!==void 0){const d=t.sourceSetChangesFor?.get(a);return{at:c,...d?{change:d}:{},scope:"project"}}return t.sourceSetScoped?.has(a)?{at:0,scope:"none"}:{at:t.sourceSetChangedAt??0,...t.sourceSetChange?{change:t.sourceSetChange}:{},scope:"workspace"}}v(podChangeClock,"podChangeClock"),s(podChangeClock,"podChangeClock");const changeEvidence=s(t=>{if(!t)return"no path evidence";const a=[...t.added.map(c=>`+${c}`),...t.removed.map(c=>`-${c}`)];return a.length?`${a.slice(0,3).join(", ")}${a.length>3?` (+${a.length-3} more)`:""}`:"no path evidence"},"changeEvidence");function createServiceLayer(t,a,c={}){const d=c.spawnProcess??node_child_process_1.spawn,g=c.probeAlive??pod_probe_1.probePodAlive,M=c.killTree??((e,r="SIGTERM")=>{try{process.kill(-e.pid,r)}catch{try{e.kill(r)}catch{}}}),m=c.sharedBuild??(0,shared_build_1.createSharedBuildRelay)(t),E=s((e,r="SIGTERM")=>{m.detach(e),M(e,r)},"killTree"),C=c.handoffDrainMs??(0,handoff_retire_1.handoffDrainBoundMs)(),I=c.treeAlive??(e=>{if(!e.pid)return!1;try{return process.kill(-e.pid,0),!0}catch(r){return r.code==="EPERM"}}),se=c.retirePollMs??1e3,J=c.rollReadyMs??types_1.POD_ROLL_READY_MS,ne=c.rollPollMs??750,ae=c.maxConcurrentRolls??types_1.POD_MAX_CONCURRENT_ROLLS,B=ae>0?ae:Number.POSITIVE_INFINITY,w=c.maxConcurrentColdStarts??types_1.MAX_COLD_STARTS,y=w>0?w:Number.POSITIVE_INFINITY;let _=0;const D=[],O=s(()=>_<y?(_+=1,Promise.resolve()):new Promise(e=>{D.push(()=>{_+=1,e()})}),"acquireColdSlot"),P=s(()=>{_-=1,D.shift()?.()},"releaseColdSlot"),{emit:V}=a,Q=s(e=>e.wsKey===t.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl"),"serviceBus"),S=s((e,r,n,o,i)=>V(r,n,o,{wsKey:e.wsKey,...i},void 0,Q(e)),"emitSvc"),N=s(e=>(e.scannedAt=0,(0,discovery_1.pickSock)(e,t.scanTtlMs)?e.socks.length:0),"scanNow"),X=s((e,r)=>{let n;try{n=(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 i=0;for(const l of n.split(`
|
|
2
|
-
`)){const p=l.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);if(!p)continue;const u=Number(p[1]),$=Number(p[2]);if(isRunnerOf(p[3],r,e.root)&&!(u===process.pid||u===o)&&!(o!==void 0&&$===o)){try{process.kill(-$,"SIGKILL")}catch{try{process.kill(u,"SIGKILL")}catch{}}i+=1}}return i>0&&(console.log(`[gateway] ${r}: reaped ${i} stale runner tree(s) \u2014 a foreign generation of this service (holding nx's task lock, or its pool)`),S(e,"warning",`stale-runner reap: ${e.project} (${i} foreign tree(s))`,`cluster-service:${e.project}`,{kind:"stale-runner-reap",project:e.project,reaped:i})),i},"reapForeignRunners"),F=s((e,r)=>({...(0,pod_env_1.podBaseEnv)(process.env,t.root,e.root),...e.instanceEnv?{...e.instanceEnv,LENSMCP_SOCKET_ONLY:"1"}:{},...e.frozen?{LENSMCP_FREEZE:"1",LENSMCP_TYPECHECK:"off"}:{},NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false",...e.wsKey?{LENSMCP_WS_KEY:e.wsKey}:{},...e.sockNs?{LENSMCP_SOCK_NS:e.sockNs}:{},LENSMCP_EVENT_FILE:e.wsKey===t.wsKey?t.eventFile:path.join(e.root,".lensmcp","events.jsonl"),LENSMCP_GATEWAY_PID:String(process.pid),LENSMCP_POD_GENERATION:String(r),...eastWestEnv(t,e)}),"serviceEnv"),Z=s((e,r,n,o)=>{const i=F(e,r),l=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:i});if(p.kind==="runner"){const h=
|
|
3
|
-
`)){const R=(0,pod_output_1.classifyPodLine)(j),{clean:T,broken:K,healthy:ye}=R,f=T;if(K){e.lastErrors.push(T),e.lastErrors.length>12&&e.lastErrors.shift(),e.buildFailed=!0;const x=Date.now();(T!==e.lastErrorEmitSig||x-(e.lastErrorEmitAt??0)>=types_1.SERVICE_ERROR_THROTTLE_MS)&&(e.lastErrorEmitSig=T,e.lastErrorEmitAt=x,S(e,"error",`service error: ${e.project}`,`cluster-service:${e.project}`,{kind:"service-error",project:e.project,line:T,fault:R.fault}))}ye&&(e.buildFailed=!1);const L=(e.faults??=new pod_output_1.PodFaults).observe(R);if(L){e.lastErrorEmitSig=void 0;const x=L.open.length===0;S(e,"info",`${x?"service recovered":`${L.closed.join(" + ")} recovered`}: ${e.project}`,`cluster-service:${e.project}`,{kind:x?"service-recovered":"service-fault-closed",project:e.project,line:T,closed:L.closed,open:L.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`),S(e,"warning",`nx task lock: ${e.project} blocked by a stale runner \u2014 auto-breaking`,`cluster-service:${e.project}`,{kind:"nx-lock-break",project:e.project}),setTimeout(()=>{t.stopped()||!e.lockBlockedAt||(q(e,"parked on a foreign nx task lock \u2014 recycling",{announce:!1}),X(e,o),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&U(e)},1500).unref?.())},250).unref?.())}},"sniff"),$=e.wsKey&&e.wsKey!==t.wsKey&&e.root?(0,workspace_log_1.workspaceLogWriter)(e.root):void 0,A=s(k=>{const h=(0,own_log_1.linePrefixer)(e.project);return j=>{if(t.stopped())return;const R=(0,inspector_secret_1.redactInspectorUrls)(j.toString());u(R);const T=h(R);k.write(T),$?.(T)}},"relay");return l.stdout?.on("data",A(process.stdout)),l.stderr?.on("data",A(process.stderr)),l.on("exit",(k,h)=>{if(e.proc!==l||(e.proc=void 0,e.state="down",t.stopped()))return;const j=(0,exit_reason_1.describeExit)(k,h);if(console.log(`[gateway] ${o} exited (${k??"no code"}${h?`, ${h}`:""}${e.inflight?`, ${e.inflight} request(s) in flight`:""})${j?` \u2014 ${j}`:""}`),S(e,k===0?"info":"warning",`service down: ${e.project} (exit ${k})`,`cluster-service:${e.project}`,{kind:"service-down",project:e.project,code:k,...h?{signal:h}:{}}),k===0||e.buildFailed)return;const R=Date.now();if(e.restarts=(e.restarts??[]).filter(K=>R-K<types_1.SERVICE_RESTART_WINDOW_MS),e.restarts.length>=types_1.SERVICE_MAX_RESTARTS){S(e,"error",`service crash-looping: ${e.project} \u2014 ${types_1.SERVICE_MAX_RESTARTS}+ restarts/min, not auto-respawning (the next request retries)`,`cluster-service:${e.project}`,{kind:"service-crash-loop",project:e.project});return}e.restarts.push(R);const T=Math.min(8e3,500*2**(e.restarts.length-1));setTimeout(()=>{t.stopped()||e.proc||e.state!=="down"||(console.log(`[gateway] self-heal: respawning ${e.project} (restart ${e.restarts.length}/${types_1.SERVICE_MAX_RESTARTS})`),S(e,"info",`self-heal: respawning ${e.project}`,`cluster-service:${e.project}`,{kind:"service-respawn",project:e.project,attempt:e.restarts.length}),U(e))},T)}),l},"launchServiceProcess"),U=s(e=>{if(t.stopped())return;const r=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,n=Math.max(1,e.decl.minPods??1);c.reapForeign!==!1&&X(e,r),e.lockBlockedAt=void 0,console.log(`[gateway] starting ${r} (pods=${n})\u2026`),S(e,"info",`service starting: ${e.project} (${n} pod${n>1?"s":""})`,`cluster-service:${e.project}`,{kind:"service-starting",project:e.project,pods:n}),e.state="starting",e.spawnAt=Date.now(),e.generation=(e.generation??0)+1,e.proc=H(e,e.generation,"active")},"spawnService"),ke=s(async e=>{const r=e.pool.socks[0];if(!r)return;const n=await(0,pod_probe_1.probePodAlive)(r,void 0,t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)]);n&&(e.activeWork=n.activeWork,n.watcher&&(e.watcher=n.watcher))},"refreshActiveWork"),je=s(e=>{try{const r=Number(fs.readFileSync(`${e}.owner`,"utf8").trim());return Number.isInteger(r)&&r>1?r:void 0}catch{return}},"readOwnerSidecar"),Re=s(async e=>{const r=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)];if(!r)return[];const n=(0,node_crypto_1.createHash)("sha256").update(r).digest("hex").slice(0,8),o=[];for(const i of e.pool.socks){const l=await(0,pod_probe_1.probePodAlive)(i,void 0,r);l&&(!l.keyFingerprint||l.keyFingerprint!==n)&&o.push({sock:i,pid:l.pid})}return o},"staleAdoptedSocks"),Ce=s((e,r)=>{const n=r.map(o=>o.sock);for(const{sock:o,pid:i}of r){const l=chooseStalePodKillTarget(i,je(o),process.pid);if(l!==void 0)try{process.kill(l,"SIGTERM")}catch{}try{fs.unlinkSync(o)}catch{}try{fs.unlinkSync(`${o}.owner`)}catch{}}e.pool.socks=e.pool.socks.filter(o=>!n.includes(o)),e.pool.idx=-1,e.pool.scannedAt=0},"evictStaleAdopted"),ce=s((e,r)=>{if(e.state==="up")return!1;e.state="up",e.wedgeRecycles=0;const n=e.pool.socks.length;return S(e,"info",`service up: ${e.project} (${n} pods, ${r})`,`cluster-service:${e.project}`,{kind:"service-up",project:e.project,pods:n,adopted:r==="adopted"}),!0},"markUp"),de=s(async e=>{if(N(e.pool)>0){const o=await Re(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.`),S(e,"warning",`stale adoption: ${e.project} (foreign east-west key)`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:"stale-adoption",pods:o.length}),e.proc&&q(e,"stale adoption (foreign east-west key)"),Ce(e,o)),e.pool.socks.length>0)return ce(e,"adopted"),!0}if(t.stopped())return!1;let r=!1;const n=s(()=>e.state!=="starting"&&!e.proc,"notStarted");if(n())if(e.coldWait)await e.coldWait;else{_>=y&&(console.log(`[gateway] cold start queued: ${e.project}${e.wsKey&&e.wsKey!==t.wsKey?` (${e.wsKey})`:""} \u2014 ${_} starting, ${D.length} ahead (LENSMCP_MAX_COLD_STARTS=${y}).`),S(e,"info",`cold start queued: ${e.project}`,`cluster-service:${e.project}`,{kind:"cold-start-queued",project:e.project,inFlight:_,ahead:D.length}));const o=O();if(e.coldWait=o,await o,e.coldWait=void 0,r=!0,t.stopped())return P(),!1;n()&&U(e)}try{return await Ae(e)}finally{r&&P()}},"ensureUp"),Ae=s(async e=>{const r=Date.now()+t.startupTimeoutMs,n=Date.now()+12e3;for(;!t.stopped()&&Date.now()<r;){if(await sleep(Math.min(700,t.startupTimeoutMs/4)),e.buildFailed&&Date.now()>n)return!1;if(N(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`:""})`),S(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},"waitForPods"),Te=s(e=>{const r=e.decl.maxPods??e.decl.minPods??1,n=e.pool.socks.length,o=scaleTarget(e);!o||n===0||n>=r||e.inflight<=n||Date.now()-e.lastScaleAt<5e3||(e.lastScaleAt=Date.now(),postScale(o,n+1,c.scaleLookup),console.log(`[gateway] autoscale ${e.project}: ${n} \u2192 ${n+1} pods (inflight ${e.inflight})`),S(e,"info",`autoscale: ${e.project} ${n} \u2192 ${n+1} pods`,`cluster-service:${e.project}`,{kind:"autoscale",project:e.project,from:n,to:n+1,inflight:e.inflight}))},"scaleUp"),q=s((e,r,n)=>{if(!e.proc)return;console.log(`[gateway] ${e.project} ${r} \u2014 scaling to zero.`),n?.announce!==!1&&S(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{}(0,discovery_1.stopRoutingTo)(e.pool),E(o,"SIGTERM"),e.proc=void 0,e.state="down",setTimeout(()=>{ie(e),e.pool.socks=[],e.pool.scannedAt=0},1200).unref?.()},"killSpawned"),ie=s(e=>{try{for(const r of fs.readdirSync(e.pool.dir)){if(!r.endsWith(".sock"))continue;const n=path.join(e.pool.dir,r);try{const o=Number(fs.readFileSync(`${n}.owner`,"utf8").trim());if(Number.isFinite(o)&&o>0)try{process.kill(o,0);continue}catch{}}catch{}try{fs.unlinkSync(n)}catch{}try{fs.unlinkSync(`${n}.owner`)}catch{}}}catch{}},"sweepDeadOwnerSocks");let Y=0;const pe=[],Me=s(()=>Y<B?(Y+=1,Promise.resolve()):new Promise(e=>{pe.push(()=>{Y+=1,e()})}),"acquireRollSlot"),xe=s(()=>{Y-=1,pe.shift()?.()},"releaseRollSlot"),_e=s(async(e,r,n)=>{N(e.pool);for(const o of e.pool.socks){const i=await g(o,void 0,n);if(i&&r(i.podGeneration))return!0}return!1},"anyPodAnswers"),ue=new Map,Pe=s((e,r,n)=>{const o=C>0&&(0,handoff_retire_1.requestHandoffRetire)(e.pool.dir,n);if(E(r,"SIGTERM"),!o)return;const i=e.wsKey&&e.wsKey!==t.wsKey&&e.root?(0,workspace_log_1.workspaceLogWriter)(e.root):void 0,l=s(R=>T=>{if(t.stopped())return;const K=(0,inspector_secret_1.redactInspectorUrls)(T.toString()).replace(/^(?=.)/gm,`[${e.project} g${n} retiring] `);R.write(K),i?.(K)},"say"),p=l(process.stdout),u=l(process.stderr);r.stdout?.on("data",p),r.stderr?.on("data",u);let $=!1;const A=s(()=>{$||($=!0,clearTimeout(k),clearInterval(j),r.stdout?.removeListener("data",p),r.stderr?.removeListener("data",u),ue.delete(r),(0,handoff_retire_1.clearHandoffRetire)(e.pool.dir,n),ie(e),e.pool.scannedAt=0)},"end"),k=setTimeout(()=>{console.error(`[gateway] pod handoff: ${e.project} g${n} was still running ${C}ms after it was retired \u2014 killing it.`),M(r,"SIGKILL"),A()},C);k.unref?.();const h=s(()=>{if(!$){if(t.stopped()){A();return}I(r)||(console.log(`[gateway] pod handoff: ${e.project} g${n} finished its in-flight work and exited.`),A())}},"look"),j=setInterval(h,se);j.unref?.(),r.once("exit",h),ue.set(r,()=>{M(r,"SIGTERM"),A()})},"retireReplacedTree"),De=s(()=>{for(const e of[...ue.values()])e()},"stopRetiringTrees"),he=s((e,r)=>{if(e.rolling)return e.rolling;const n=e.proc;if(!n||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);Y>=B&&console.log(`[gateway] pod handoff queued: ${e.project} reason=${r} \u2014 ${Y} roll(s) in flight, ${pe.length} ahead (LENSMCP_POD_MAX_CONCURRENT_ROLLS=${B}).`);const o=(async()=>{await Me();try{return await Le(e,n,r)}finally{xe()}})().finally(()=>{e.rolling=void 0});return e.rolling=o,o},"rollPod"),Le=s(async(e,r,n)=>{const o=e.proc;if(o!==r||t.stopped())return!1;const i=e.generation??0,l=i+1,p=Date.now();e.lastStaleRecycleAt=p,console.log(`[gateway] pod handoff start: ${e.project} g${i}\u2192g${l} reason=${n} \u2014 standby spawning, old generation keeps serving.`),S(e,"info",`pod handoff starting: ${e.project} (${n})`,`cluster-service:${e.project}`,{kind:"pod-handoff-start",project:e.project,reason:n,generation:l,fromGeneration:i});const u=H(e,l,"standby"),$=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],A=p+J;let k;for(;!t.stopped()&&Date.now()<A&&!(u.exitCode!==null||u.signalCode!==null);){N(e.pool);for(const h of e.pool.socks)if((await g(h,void 0,$))?.podGeneration===l){k=h;break}if(k)break;await sleep(ne)}if(!k||t.stopped()){const h=t.stopped()?"gateway stopping":u.exitCode!==null||u.signalCode!==null?`standby exited (${u.exitCode??u.signalCode})`:`standby not ready within ${Math.round(J/1e3)}s`;try{u.stdout?.removeAllListeners("data"),u.stderr?.removeAllListeners("data")}catch{}(0,discovery_1.stopRoutingTo)(e.pool,T=>(0,pod_sock_1.podSockGeneration)(T)===l),E(u,"SIGTERM");const j=!t.stopped()&&e.proc===o&&o.exitCode===null&&o.signalCode===null&&await _e(e,T=>T!==l,$),R=j?`old generation g${i} kept serving`:`and the old generation g${i} 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${l}: ${h} \u2014 ${R}.`),e.rollFailure=`${h} \u2014 ${R}`,S(e,j?"warning":"error",`pod handoff failed: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-failed",project:e.project,reason:n,generation:l,error:h,durationMs:Date.now()-p,oldServing:j}),setTimeout(()=>ie(e),1200).unref?.(),!1}if(e.proc!==o)return(0,discovery_1.stopRoutingTo)(e.pool,h=>(0,pod_sock_1.podSockGeneration)(h)===l),E(u,"SIGTERM"),!1;e.proc=u,e.launcher=ee.get(u),e.generation=l,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(0,discovery_1.stopRoutingTo)(e.pool,h=>(0,pod_sock_1.podSockGeneration)(h)!==l&&path.join(e.pool.dir,h)!==k),Pe(e,o,i),setTimeout(()=>{ie(e),e.pool.scannedAt=0},1200).unref?.(),console.log(`[gateway] pod handoff ready: ${e.project} g${l} answered on ${path.basename(k)} in ${Date.now()-p}ms; retiring g${i}.`),S(e,"info",`pod handoff complete: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-complete",project:e.project,reason:n,generation:l,fromGeneration:i,durationMs:Date.now()-p}),!0},"runRoll"),be=s((e,r)=>{if(t.stopped())return{refused:"the gateway is stopping"};if(e.restart&&!e.restart.done)return{restart:e.restart,already:!0};if(!e.proc&&e.state!=="down")return{refused:`${e.project} is served by pods this gateway adopted from an earlier one \u2014 it has no tree of its own to replace. \`lensmcp gateway restart\` starts every service under this gateway.`};const n=e.proc?r.hard||e.launcher==="nx"||e.state!=="up"?"hard":"rolling":"start",o={how:n,reason:r.reason,startedAt:Date.now(),...e.proc&&e.generation!==void 0?{fromGeneration:e.generation}:{}};return e.restart=o,console.log(`[gateway] restart asked: ${e.project}${e.wsKey!==t.wsKey?` (${e.wsKey})`:""} \u2014 ${n} (${r.reason}).`),S(e,"info",`restart asked: ${e.project} (${n})`,`cluster-service:${e.project}`,{kind:"service-restart",phase:"started",project:e.project,how:n,reason:r.reason,...o.fromGeneration!==void 0?{fromGeneration:o.fromGeneration}:{}}),s(async()=>{if(n==="start")return await de(e)?{ok:!0}:{ok:!1,error:ge(e)};if(n==="rolling")return e.rolling&&await e.rolling,e.proc?(e.rollFailure=void 0,await he(e,r.reason)?{ok:!0}:{ok:!1,error:e.rollFailure??"the new tree did not take over"}):await de(e)?{ok:!0}:{ok:!1,error:ge(e)};if(q(e,`restart asked (${r.reason})`,{announce:!1}),await sleep(1500),t.stopped())return{ok:!1,error:"the gateway is stopping"};let i=!1;e.proc||(await O(),i=!0,!e.proc&&e.state!=="starting"&&U(e));try{const l=e.proc,p=e.generation,u=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],$=Date.now()+t.startupTimeoutMs;for(;!t.stopped()&&Date.now()<$;){if(!l||e.proc!==l||l.exitCode!==null||l.signalCode!==null)return{ok:!1,error:ge(e)};if(await _e(e,A=>A===p,u))return ce(e,"observed"),e.buildFailed=!1,{ok:!0};await sleep(ne)}return{ok:!1,error:t.stopped()?"the gateway is stopping":`no pod of the new tree answered within ${Math.round(t.startupTimeoutMs/1e3)}s`}}finally{i&&P()}},"run")().catch(i=>({ok:!1,error:i.message})).then(i=>{o.done={ok:i.ok,at:Date.now(),...e.generation!==void 0?{generation:e.generation}:{},...i.error?{error:i.error}:{}};const l=Math.round((o.done.at-o.startedAt)/100)/10;i.ok?console.log(`[gateway] restarted: ${e.project} \u2014 g${o.done.generation??"?"} serving after ${l}s (${n}).`):console.error(`[gateway] restart failed: ${e.project} \u2014 ${i.error} (${n}, after ${l}s).`),S(e,i.ok?"info":"error",i.ok?`restarted: ${e.project}`:`restart failed: ${e.project}`,`cluster-service:${e.project}`,{kind:"service-restart",phase:i.ok?"done":"failed",project:e.project,how:n,reason:r.reason,...o.fromGeneration!==void 0?{fromGeneration:o.fromGeneration}:{},...o.done.generation!==void 0?{generation:o.done.generation}:{},durationMs:o.done.at-o.startedAt,...i.error?{error:i.error}:{}})}),{restart:o,already:!1}},"restartService"),ge=s(e=>e.buildFailed?`its build failed${e.lastErrors?.length?`: ${e.lastErrors[e.lastErrors.length-1]}`:""}`:e.proc&&(e.proc.exitCode!==null||e.proc.signalCode!==null)?`its tree exited (${e.proc.exitCode??e.proc.signalCode})`:!e.proc&&e.state==="down"?"its tree exited before a pod answered":`no pod answered within ${Math.round(t.startupTimeoutMs/1e3)}s`,"startFailure"),Ee=s(e=>{const r=Date.now();e.restarts=(e.restarts??[]).filter(o=>r-o<types_1.SERVICE_RESTART_WINDOW_MS);const n=(e.wedgeRecycles??0)+1;if(e.restarts.length>=types_1.SERVICE_MAX_RESTARTS||n>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`;S(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:n-1}),q(e,"wedged (crash-loop cap) \u2014 leaving down for the next request",{announce:!1});return}e.wedgeRecycles=n,e.restarts.push(r),console.log(`[gateway] self-heal: recycling WEDGED ${e.project} (live parent, 0 live pods; attempt ${n}/${types_1.SERVICE_MAX_RESTARTS} with no pod up since the first, ${e.restarts.length} in the last minute; ${e.inflight??0} request(s) in flight \u2014 jobs held by the dead pod keep their locks until they expire)`),S(e,"warning",`self-heal: recycling wedged ${e.project} (0 live pods)`,`cluster-service:${e.project}`,{kind:"service-recycle",project:e.project,attempt:n,inWindow:e.restarts.length}),q(e,"wedged: 0 live pods \u2014 recycling",{announce:!1}),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&U(e)},1500).unref?.()},"recycleWedged"),Ie={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 fe;const te=new Map,we=new Map;let Se=!1,ve=0,le=0;const Oe=s(()=>{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 n=new Set;for(const o of r){const i=e[o];if(!i)continue;const l=path.relative(t.root,i).split(path.sep).filter(Boolean)[0];l&&!l.startsWith("..")&&n.add(l)}return[...n]},"managedBuckets"),Ne=s((e,r,n,o)=>{const i=t.projectSourceRoots?.[e];if(i?.length)return i;const l=t.projectRoots?.[e];if(!l)return;const p=sourceScopeDirs(t.root,l,n,r,o);return p.length>0?p:void 0},"scopeFor"),Fe=s(()=>{if(Se||Date.now()-ve<types_1.POD_STALE_SCAN_MS)return;Se=!0,ve=Date.now();const e=ve;(async()=>{const r=(0,scope_1.readSourceSetOptions)(t.root),n=r.exclude,o={ignoreTests:r.ignoreTests},i=sourceScanPass(t.root,n,o),l=await i.snapshot(),p=Date.now(),u=sourceChangeWindowMs(p,le,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS),$=fe?diffSourceSets(fe,l,p,u):null;if($&&(t.sourceSetChangedAt=p,t.sourceSetChange=$,V("info","source file set changed \u2014 stale pods recycle when idle","cluster-gateway",{kind:"source-set-changed",added:$.added,removed:$.removed,truncated:$.truncated})),fe=l,!t.projectRoots){le=e;return}let A;try{A=(await fs.promises.readdir(t.root,{withFileTypes:!0})).filter(f=>f.isDirectory()).map(f=>f.name)}catch{return}const k=Oe(),h=new Set(t.services.map(f=>f.project));for(const f of t.routes)f.lens&&h.add(f.lens.project);const j=new Map;for(const f of h){const L=Ne(f,A,k,n);if(!L)continue;const x=L.join("|"),W=j.get(x)??{dirs:L,projects:[]};W.projects.push(f),j.set(x,W)}const R=Date.now(),T=sourceChangeWindowMs(R,le,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS);le=e;const K=s((f,L,x)=>{t.sourceSetChangedFor??=new Map,t.sourceSetChangesFor??=new Map;for(const W of f)t.sourceSetChangedFor.set(W,L),t.sourceSetChangesFor.set(W,x)},"stampScoped"),ye=new Set([...j.values()].flatMap(f=>f.projects));for(const f of[...t.sourceSetScoped??[]])ye.has(f)||t.sourceSetScoped.delete(f);for(const[f,{dirs:L,projects:x}]of j){const W=await i.snapshot(L),$e=te.get(f);if($e||x.some(b=>we.has(b))){t.sourceSetScoped??=new Set;for(const b of x)t.sourceSetScoped.add(b)}te.set(f,W);const me=new Map;for(const b of x){const G=we.get(b);if(G===void 0||G===f)continue;const z=me.get(G)??[];z.push(b),me.set(G,z)}for(const b of x)we.set(b,f);for(const[b,G]of me){const z=te.get(b),oe=z?diffSourceSets(z,W,R,T):$;oe&&(K(G,z?R:p,oe),V("info",`source file set changed \u2014 ${G.join(", ")}'s watch scope was re-keyed`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,rescoped:!0,projects:G,added:oe.added,removed:oe.removed,truncated:oe.truncated}))}if(!$e)continue;const re=diffSourceSets($e,W,R,T);re&&(K(x,R,re),V("info",`source file set changed in ${x.join(", ")}'s scope`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,projects:x,added:re.added,removed:re.removed,truncated:re.truncated}))}for(const f of[...te.keys()])j.has(f)||te.delete(f)})().catch(()=>{}).finally(()=>{Se=!1})},"maybeScanSourceSet"),Ke=s((e,r)=>{const n=podChangeClock(t,e.project),o=n.change,i=`${n.scope==="project"?"in its scope":"in the workspace (its scope is not known)"}: ${changeEvidence(o)}`,l=o?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,p=podWatcherVerdict(e.watcher,r,l),u=s(A=>(e.staleKeptAt!==r&&(e.staleKeptAt=r,console.log(`[gateway] stale source set: pod ${e.project} ${A} \u2014 no recycle.`)),!1),"keep");if(p==="heard")return e.staleVerifiedAt=r,S(e,"info",`stale check: ${e.project} watcher confirmed \u2014 no recycle`,`cluster-service:${e.project}`,{kind:"pod-stale-verified",project:e.project,watcher:p}),u(`watcher CONFIRMED alive across the change (last build ${new Date(e.watcher?.lastBuildAt??0).toISOString()})`);if(p==="degraded")return console.log(`[gateway] stale source set: pod ${e.project} watcher DEGRADED (${e.watcher?.degraded}) \u2014 recycling.`),!0;const $=s(A=>(e.staleKeptAt!==r&&(e.staleKeptAt=r,console.log(`[gateway] stale source set: pod ${e.project} ${A}; the change ${i} \u2014 recycling.`)),!0),"recycling");return p==="silent"?types_1.POD_WATCHER_SILENT==="keep"?u("watcher alive but quiet across the change \u2014 keeping it (LENSMCP_POD_WATCHER_SILENT=keep; a live watcher cannot miss an add it will need)"):$("watcher alive but quiet across the change"):types_1.POD_WATCHER_UNVERIFIED==="keep"?u("unverifiable (no watcher testimony \u2014 older devserver bundle?) \u2014 keeping it (LENSMCP_POD_WATCHER_UNVERIFIED=keep)"):$("watcher unverifiable (no testimony yet \u2014 a pod that never rebuilt, or an older devserver bundle)")},"podStaleRecycleAllowed"),We=s((e,r)=>{if(e.lastStaleRecycleAt=Date.now(),types_1.POD_RECYCLE_MODE==="rolling"&&e.proc&&e.launcher!=="nx"){he(e,r);return}console.log(`[gateway] zombie recycle: ${e.project} (${r}) \u2014 stale fs view; fresh pod incoming`),S(e,"warning",`zombie recycle: ${e.project} (${r})`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:r});const n=!!e.decl.eager;q(e,`${r} \u2014 recycling stale pod`,{announce:!1}),n&&setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&U(e)},1500).unref?.()},"recyclePod"),qe=s(()=>{const e=setInterval(()=>{Ge().catch(r=>console.error("[gateway] sweep error:",r))},t.sweepMs);return e.unref(),e},"startSweeper"),Ge=s(async()=>{{if(t.stopped())return;for(const e of t.graphStores?.all()??[])e.refreshIfStale();types_1.POD_RECYCLE_ENABLED&&Fe();for(const e of t.registry?t.registry.allServices():t.services){if(t.stopped()||!e.proc){e.wedgedSince=void 0;continue}const r=path.resolve(e.root)===path.resolve(t.root),n=(0,warm_start_1.instanceIdleSec)(e,!r&&!!t.registry?.get(e.wsKey)?.instance);if(n&&e.inflight===0&&Date.now()-e.lastUsed>n*1e3){q(e,`idle ${n}s`),e.wedgedSince=void 0;continue}const o=e.state==="starting"&&e.spawnAt!==void 0&&Date.now()-e.spawnAt<t.startupTimeoutMs,i=N(e.pool)>0;if(i||o){if(e.wedgedSince=void 0,i&&ce(e,"observed"),i&&!o&&types_1.POD_RECYCLE_ENABLED&&r){const l=podChangeClock(t,e.project).at;await ke(e);const p=(e.staleVerifiedAt??0)>=l&&l>0,u=podRecycleReason(e,Date.now(),p?0:l,Ie);if(u==="stale-source-set"&&!Ke(e,l))continue;u&&We(e,u)}continue}e.wedgedSince??=Date.now(),Date.now()-e.wedgedSince>types_1.WEDGE_RECYCLE_GRACE_MS&&(e.wedgedSince=void 0,Ee(e))}}},"sweepOnce");return{scanNow:N,spawnService:U,ensureUp:de,scaleUp:Te,killSpawned:q,markUp:ce,startSweeper:qe,rollPod:he,restartService:be,recycleWedged:Ee,stopRetiringTrees:De,stopBuildHost:s(e=>e===void 0?m.stop():m.release(e),"stopBuildHost")}}v(createServiceLayer,"createServiceLayer"),s(createServiceLayer,"createServiceLayer");function chooseStalePodKillTarget(t,a,c){if(!(t===void 0||!Number.isInteger(t)||t<=1)&&!(a!==void 0&&a!==t)&&t!==c)return t}v(chooseStalePodKillTarget,"chooseStalePodKillTarget"),s(chooseStalePodKillTarget,"chooseStalePodKillTarget");
|
|
1
|
+
"use strict";var Ue=Object.defineProperty;var v=(t,a)=>Ue(t,"name",{value:a,configurable:!0});var Ve=Object.defineProperty,s=v((t,a)=>Ve(t,"name",{value:a,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.scaleTarget=scaleTarget,exports.isLoopbackHostname=isLoopbackHostname,exports.isOwnRunnerCommand=isOwnRunnerCommand,exports.isRunnerOf=isRunnerOf,exports.isTestSourcePath=isTestSourcePath,exports.sourceScanPass=sourceScanPass,exports.sourceSetSnapshot=sourceSetSnapshot,exports.sourceSetSignature=sourceSetSignature,exports.diffSourceSets=diffSourceSets,exports.sourceChangeWindowMs=sourceChangeWindowMs,exports.sourceScopeDirs=sourceScopeDirs,exports.podRecycleReason=podRecycleReason,exports.lensFrontendStale=lensFrontendStale,exports.lensWatcherVerdict=lensWatcherVerdict,exports.podWatcherVerdict=podWatcherVerdict,exports.lensChildWedged=lensChildWedged,exports.isPortConflictExit=isPortConflictExit,exports.podChangeClock=podChangeClock,exports.createServiceLayer=createServiceLayer,exports.chooseStalePodKillTarget=chooseStalePodKillTarget;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),node_crypto_1=require("node:crypto"),fs=tslib_1.__importStar(require("node:fs")),http=tslib_1.__importStar(require("node:http")),net=tslib_1.__importStar(require("node:net")),path=tslib_1.__importStar(require("node:path")),node_util_1=require("node:util"),discovery_1=require("./discovery"),pod_sock_1=require("../../../pod-sock"),scope_1=require("./scope"),pod_env_1=require("./pod-env"),pod_probe_1=require("./pod-probe"),service_keys_1=require("./service-keys"),workspace_log_1=require("./workspace-log"),own_log_1=require("./own-log"),inspector_secret_1=require("../../../inspector-secret"),pod_output_1=require("./pod-output"),serve_launch_1=require("./serve-launch"),shared_build_1=require("./shared-build"),warm_start_1=require("./warm-start"),protocol_1=require("../../../shared-build/protocol"),types_1=require("./types"),exit_reason_1=require("../../../exit-reason"),handoff_retire_1=require("../../../handoff-retire"),process_name_1=require("../../../process-name");function eastWestEnv(t,a){const c={},d=t.serviceKeys[(0,service_keys_1.serviceKeyId)(a.wsKey,a.project)];if(d&&(c.LENSMCP_SERVICE_KEY=d),t.https){const f=require("../../../basic-ssl").caCertPath();fs.existsSync(f)&&(c.NODE_EXTRA_CA_CERTS=f)}return c}v(eastWestEnv,"eastWestEnv"),s(eastWestEnv,"eastWestEnv");const sleep=s(t=>new Promise(a=>setTimeout(a,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 a=2166136261;for(let c=0;c<t.length;c+=1)a^=t.charCodeAt(c),a=Math.imul(a,16777619);return a>>>0}v(fnv1a,"fnv1a"),s(fnv1a,"fnv1a");const execFileP=(0,node_util_1.promisify)(node_child_process_1.execFile);async function gitIgnoredPaths(t){try{const{stdout:a}=await execFileP("git",["ls-files","--others","--directory","--ignored","--exclude-standard","-z"],{cwd:t,maxBuffer:33554432,timeout:1e4,windowsHide:!0});return new Set(a.split("\0").filter(Boolean))}catch{return new Set}}v(gitIgnoredPaths,"gitIgnoredPaths"),s(gitIgnoredPaths,"gitIgnoredPaths");function scaleTarget(t,a=fs.existsSync){if(t.decl.adminUrl)return{url:t.decl.adminUrl};const c=path.join(t.pool.dir,"parent.sock");return a(c)?{socketPath:c}:t.decl.port?{url:`http://localhost:${t.decl.port}`}:void 0}v(scaleTarget,"scaleTarget"),s(scaleTarget,"scaleTarget");function isLoopbackHostname(t){const a=t.toLowerCase().replace(/^\[(.*)\]$/,"$1").replace(/\.$/,"");return a==="localhost"||a.endsWith(".localhost")?!0:net.isIPv4(a)?a.split(".")[0]==="127":net.isIPv6(a)&&new URL(`http://[${a}]/`).hostname==="[::1]"}v(isLoopbackHostname,"isLoopbackHostname"),s(isLoopbackHostname,"isLoopbackHostname");function postScale(t,a,c){let d;if("socketPath"in t)d=http.request({socketPath:t.socketPath,path:"/webpack/scale",method:"POST",headers:{"content-type":"application/json"}},f=>f.resume());else{const f=t.url.startsWith("https"),T=f?require("node:https"):http,E={method:"POST"};f&&isLoopbackHostname(new URL(t.url).hostname)&&(E.rejectUnauthorized=!1),c&&(E.lookup=c),d=T.request(`${t.url}/webpack/scale`,E,R=>R.resume())}return d.on("error",()=>{}),d.end(JSON.stringify({pods:a})),d}v(postScale,"postScale"),s(postScale,"postScale");function isOwnRunnerCommand(t,a){return(0,serve_launch_1.isServeRunnerCommand)(t)?(0,serve_launch_1.isServeRunnerCommandOf)(t,a):t.includes("/node_modules/nx/")?t.includes(`${a.replace(/\/+$/,"")}/node_modules/nx/`):!0}v(isOwnRunnerCommand,"isOwnRunnerCommand"),s(isOwnRunnerCommand,"isOwnRunnerCommand");function isRunnerOf(t,a,c){const d=a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return!new RegExp(`(^|\\s)run ${d}(:|\\s|$)`).test(t)||!(0,serve_launch_1.isServeRunnerCommand)(t)&&!/\bnx(\.js)?\b/.test(t)?!1:isOwnRunnerCommand(t,c)}v(isRunnerOf,"isRunnerOf"),s(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 a=t.split("/"),c=a[a.length-1]??"";if(TEST_FILE_RE.test(c))return!0;for(let d=0;d<a.length-1;d+=1)if(TEST_DIR_SEGMENTS.has(a[d]))return!0;return!1}v(isTestSourcePath,"isTestSourcePath"),s(isTestSourcePath,"isTestSourcePath");function sourceScanPass(t,a,c){const d=c?.ignoreTests??!0;let f;const T=new Map,E=`tree:${path.resolve(t)}`,R=s(w=>path.relative(t,w).split(path.sep).join("/"),"rel"),A=s(async(w,y)=>{const k=await(f??=gitIgnoredPaths(t)),L=[],O=new Set;let D=!1;const V=s(async(Q,S)=>{if(L.length>=SCAN_FILE_CAP){D=!0;return}let N;try{N=await fs.promises.readdir(Q,{withFileTypes:!0})}catch{return}S&&O.add(R(Q));for(const X of N){if(L.length>=SCAN_FILE_CAP){D=!0;return}const F=X.name,Z=path.join(Q,F);if(X.isDirectory()){if(!S||F.startsWith(".")||SRC_EXCLUDE.has(F)||a?.has(F)||F.endsWith("-devserver")||k.has(`${R(Z)}/`))continue;await V(Z,!0)}else if(X.isFile()){const ee=F.lastIndexOf(".");if(ee<=0||!SRC_EXT.has(F.slice(ee)))continue;const H=R(Z);if(k.has(H)||d&&isTestSourcePath(H))continue;L.push(H)}}},"walk");return await V(w,y),{paths:L,entered:O,truncated:D}},"walkDir"),I=s((w,y)=>{let k=T.get(w);return k||(k=y(),T.set(w,k)),k},"memo"),ne=s(async()=>{const w=T.get(E);if(!w)return;const y=await w;return y.truncated?void 0:y},"wideWalk"),J=new Set,ae=s(()=>I(`files:${path.resolve(t)}`,async()=>{const w=await ne();return w?{paths:w.paths.filter(y=>!y.includes("/")),entered:J,truncated:!1}:A(t,!1)}),"rootFiles"),ce=s(w=>I(`tree:${path.resolve(w)}`,async()=>{const y=await ne(),k=R(w);if(y?.entered.has(k)){const L=`${k}/`;return{paths:k===""?y.paths:y.paths.filter(O=>O.startsWith(L)),entered:J,truncated:!1}}return A(w,!0)}),"subtree"),B=s(w=>{const y=new Set;let k=0,L=w.some(D=>D.truncated);const O=s(D=>y.has(D)?!0:y.size>=SCAN_FILE_CAP?(L=!0,!1):(y.add(D),k^=fnv1a(D),!0),"add");for(const D of w)if(!D.paths.every(O))break;return{signature:`${y.size}:${(k>>>0).toString(36)}`,paths:y,truncated:L}},"compose");return{async snapshot(w){if(!w||w.length===0)return B([await I(E,()=>A(t,!0))]);const y=[await ae()];for(const k of w)y.push(await ce(k));return B(y)}}}v(sourceScanPass,"sourceScanPass"),s(sourceScanPass,"sourceScanPass");async function sourceSetSnapshot(t,a,c,d){return sourceScanPass(t,c,d).snapshot(a)}v(sourceSetSnapshot,"sourceSetSnapshot"),s(sourceSetSnapshot,"sourceSetSnapshot");async function sourceSetSignature(t,a,c,d){return(await sourceSetSnapshot(t,a,c,d)).signature}v(sourceSetSignature,"sourceSetSignature"),s(sourceSetSignature,"sourceSetSignature");const SOURCE_DIFF_PATH_CAP=128;function diffSourceSets(t,a,c,d){if(t.paths.size===a.paths.size){let R=!0;for(const A of t.paths)if(!a.paths.has(A)){R=!1;break}if(R)return null}const f=[],T=[];let E=t.truncated||a.truncated;for(const R of a.paths)t.paths.has(R)||(f.length+T.length<SOURCE_DIFF_PATH_CAP?f.push(R):E=!0);for(const R of t.paths)a.paths.has(R)||(f.length+T.length<SOURCE_DIFF_PATH_CAP?T.push(R):E=!0);return{changedAt:c,added:f,removed:T,truncated:E,...d!==void 0?{windowMs:d}:{}}}v(diffSourceSets,"diffSourceSets"),s(diffSourceSets,"diffSourceSets");function sourceChangeWindowMs(t,a,c,d){const f=a&&a>0?t-a:c;return Math.max(f,c)+d}v(sourceChangeWindowMs,"sourceChangeWindowMs"),s(sourceChangeWindowMs,"sourceChangeWindowMs");function sourceScopeDirs(t,a,c,d,f){const T=s(A=>{const I=path.relative(t,A).split(path.sep).filter(Boolean);return I.length===0||I[0].startsWith("..")?"":I[0]},"bucketOf")(a);if(!T)return[];const E=new Set(c.filter(Boolean)),R=new Set([T]);for(const A of d)A.startsWith(".")||SRC_EXCLUDE.has(A)||f?.has(A)||A.endsWith("-devserver")||E.has(A)||R.add(A);return[...R].sort().map(A=>path.join(t,A))}v(sourceScopeDirs,"sourceScopeDirs"),s(sourceScopeDirs,"sourceScopeDirs");function podRecycleReason(t,a,c,d){return!t.proc||t.state!=="up"||t.spawnAt==null||t.inflight>0||(t.activeWork??0)>0||a-t.lastUsed<d.settleMs||t.lastStaleRecycleAt!=null&&a-t.lastStaleRecycleAt<d.cooldownMs?null:c>0&&c-t.spawnAt>d.graceMs?"stale-source-set":d.maxAgeMs>0&&a-t.spawnAt>d.maxAgeMs?"max-age":null}v(podRecycleReason,"podRecycleReason"),s(podRecycleReason,"podRecycleReason");function lensFrontendStale(t,a,c,d,f){return!(d-a<f.cooldownMs||c<=0||c-t<=f.graceMs||d-c<f.settleMs)}v(lensFrontendStale,"lensFrontendStale"),s(lensFrontendStale,"lensFrontendStale");function lensWatcherVerdict(t,a,c,d=[]){if(!t)return"unknown";if("schemaVersion"in t&&t.schemaVersion>=2&&d.length>0){const f=a-c,T=new Set(t.recentEvents.filter(E=>E.at>=f).map(E=>path.resolve(E.path)));return d.every(E=>T.has(path.resolve(E)))?"heard":"missed"}return t.lastFsSetEventAt>=a-c?"heard":"missed"}v(lensWatcherVerdict,"lensWatcherVerdict"),s(lensWatcherVerdict,"lensWatcherVerdict");function podWatcherVerdict(t,a,c){if(!t)return"unknown";if(t.degraded)return"degraded";const d=a-c;return t.lastWatchRunAt>=d||t.lastBuildAt>=d?"heard":"silent"}v(podWatcherVerdict,"podWatcherVerdict"),s(podWatcherVerdict,"podWatcherVerdict");function lensChildWedged(t,a,c,d){const f=t.hasListened?d.graceMs:Math.max(d.graceMs,d.neverListenedGraceMs);return c-t.spawnedAt<f||c-a<d.cooldownMs||t.probeFails<Math.max(2,d.failureThreshold)?null:"wedged-no-listener"}v(lensChildWedged,"lensChildWedged"),s(lensChildWedged,"lensChildWedged");function isPortConflictExit(t,a){return t.signal||t.code===null||t.code===0||t.ranMs>a.fastFailMs?!1:t.portHeld}v(isPortConflictExit,"isPortConflictExit"),s(isPortConflictExit,"isPortConflictExit");function podChangeClock(t,a){const c=t.sourceSetChangedFor?.get(a);if(c!==void 0){const d=t.sourceSetChangesFor?.get(a);return{at:c,...d?{change:d}:{},scope:"project"}}return t.sourceSetScoped?.has(a)?{at:0,scope:"none"}:{at:t.sourceSetChangedAt??0,...t.sourceSetChange?{change:t.sourceSetChange}:{},scope:"workspace"}}v(podChangeClock,"podChangeClock"),s(podChangeClock,"podChangeClock");const changeEvidence=s(t=>{if(!t)return"no path evidence";const a=[...t.added.map(c=>`+${c}`),...t.removed.map(c=>`-${c}`)];return a.length?`${a.slice(0,3).join(", ")}${a.length>3?` (+${a.length-3} more)`:""}`:"no path evidence"},"changeEvidence");function createServiceLayer(t,a,c={}){const d=c.spawnProcess??node_child_process_1.spawn,f=c.probeAlive??pod_probe_1.probePodAlive,T=c.killTree??((e,r="SIGTERM")=>{try{process.kill(-e.pid,r)}catch{try{e.kill(r)}catch{}}}),E=c.sharedBuild??(0,shared_build_1.createSharedBuildRelay)(t),R=s((e,r="SIGTERM")=>{E.detach(e),T(e,r)},"killTree"),A=c.handoffDrainMs??(0,handoff_retire_1.handoffDrainBoundMs)(),I=c.treeAlive??(e=>{if(!e.pid)return!1;try{return process.kill(-e.pid,0),!0}catch(r){return r.code==="EPERM"}}),ne=c.retirePollMs??1e3,J=c.rollReadyMs??types_1.POD_ROLL_READY_MS,ae=c.rollPollMs??750,ce=c.maxConcurrentRolls??types_1.POD_MAX_CONCURRENT_ROLLS,B=ce>0?ce:Number.POSITIVE_INFINITY,w=c.maxConcurrentColdStarts??types_1.MAX_COLD_STARTS,y=w>0?w:Number.POSITIVE_INFINITY;let k=0;const L=[],O=s(()=>k<y?(k+=1,Promise.resolve()):new Promise(e=>{L.push(()=>{k+=1,e()})}),"acquireColdSlot"),D=s(()=>{k-=1,L.shift()?.()},"releaseColdSlot"),{emit:V}=a,Q=s(e=>e.wsKey===t.wsKey?void 0:path.join(e.root,".lensmcp","events.jsonl"),"serviceBus"),S=s((e,r,n,o,i)=>V(r,n,o,{wsKey:e.wsKey,...i},void 0,Q(e)),"emitSvc"),N=s(e=>(e.scannedAt=0,(0,discovery_1.pickSock)(e,t.scanTtlMs)?e.socks.length:0),"scanNow"),X=s((e,r)=>{let n;try{n=(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 i=0;for(const l of n.split(`
|
|
2
|
+
`)){const p=l.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);if(!p)continue;const u=Number(p[1]),$=Number(p[2]);if(isRunnerOf(p[3],r,e.root)&&!(u===process.pid||u===o)&&!(o!==void 0&&$===o)){try{process.kill(-$,"SIGKILL")}catch{try{process.kill(u,"SIGKILL")}catch{}}i+=1}}return i>0&&(console.log(`[gateway] ${r}: reaped ${i} stale runner tree(s) \u2014 a foreign generation of this service (holding nx's task lock, or its pool)`),S(e,"warning",`stale-runner reap: ${e.project} (${i} foreign tree(s))`,`cluster-service:${e.project}`,{kind:"stale-runner-reap",project:e.project,reaped:i})),i},"reapForeignRunners"),F=s((e,r)=>({...(0,pod_env_1.podBaseEnv)(process.env,t.root,e.root),...e.instanceEnv?{...e.instanceEnv,LENSMCP_SOCKET_ONLY:"1"}:{},...e.frozen?{LENSMCP_FREEZE:"1",LENSMCP_TYPECHECK:"off"}:{},NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false",...e.wsKey?{LENSMCP_WS_KEY:e.wsKey}:{},...e.sockNs?{LENSMCP_SOCK_NS:e.sockNs}:{},LENSMCP_EVENT_FILE:e.wsKey===t.wsKey?t.eventFile:path.join(e.root,".lensmcp","events.jsonl"),LENSMCP_GATEWAY_PID:String(process.pid),LENSMCP_POD_GENERATION:String(r),...eastWestEnv(t,e)}),"serviceEnv"),Z=s((e,r,n,o)=>{const i=F(e,r),l=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:i});if(p.kind==="runner"){const h=E.offeredTo(e),_=d((0,process_name_1.namedExecPath)((0,process_name_1.processName)(l,e.project,serve_launch_1.SERVE_RUNNER_ROLE)),[...p.script.execArgv,p.script.path,...(0,serve_launch_1.serveRunnerArgs)(n,o,e.root)],{cwd:e.root,detached:!0,env:h?{...p.env,[protocol_1.SHARED_BUILD_ENV]:"1"}:p.env,stdio:["ignore","pipe","pipe","ipc"]});return h&&E.attach(e,r,_),_.send?.(p.message,j=>{j&&console.error(`[gateway] ${n}: could not hand the task to its runner (${j.message})`)}),{proc:_,launcher:"runner"}}console.log(`[gateway] ${n}: starting through nx run \u2014 ${p.reason}`);const u=path.join(e.root,"node_modules","nx","dist","bin","nx.js"),$=(0,process_name_1.namedExecPath)((0,process_name_1.processName)(l,e.project,"nx")),[M,m]=fs.existsSync(u)?[$,[u,"run",n,`--childCount=${o}`]]:["yarn",["nx","run",n,`--childCount=${o}`]];return{proc:d(M,m,{cwd:e.root,detached:!0,env:i,stdio:["ignore","pipe","pipe"]}),launcher:"nx"}},"startServiceTree"),ee=new WeakMap,H=s((e,r,n)=>{const o=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,i=Math.max(1,e.decl.minPods??1),{proc:l,launcher:p}=Z(e,r,o,i);ee.set(l,p),n==="active"&&(e.launcher=p),n==="active"&&(e.lastErrors=[],e.buildFailed=!1,e.faults=new pod_output_1.PodFaults);const u=s(m=>{const h=m.toString();for(const _ of h.split(`
|
|
3
|
+
`)){const j=(0,pod_output_1.classifyPodLine)(_),{clean:C,broken:K,healthy:re}=j,g=C;if(K){e.lastErrors.push(C),e.lastErrors.length>12&&e.lastErrors.shift(),e.buildFailed=!0;const x=Date.now();(C!==e.lastErrorEmitSig||x-(e.lastErrorEmitAt??0)>=types_1.SERVICE_ERROR_THROTTLE_MS)&&(e.lastErrorEmitSig=C,e.lastErrorEmitAt=x,S(e,"error",`service error: ${e.project}`,`cluster-service:${e.project}`,{kind:"service-error",project:e.project,line:C,fault:j.fault}))}re&&(e.buildFailed=!1);const P=(e.faults??=new pod_output_1.PodFaults).observe(j);if(P){e.lastErrorEmitSig=void 0;const x=P.open.length===0;S(e,"info",`${x?"service recovered":`${P.closed.join(" + ")} recovered`}: ${e.project}`,`cluster-service:${e.project}`,{kind:x?"service-recovered":"service-fault-closed",project:e.project,line:C,closed:P.closed,open:P.open})}!e.lockBlockedAt&&/Waiting for .+ in another nx process/.test(g)&&(e.lockBlockedAt=Date.now(),console.log(`[gateway] ${o}: spawn blocked by a stale nx runner \u2014 breaking the lock + respawning`),S(e,"warning",`nx task lock: ${e.project} blocked by a stale runner \u2014 auto-breaking`,`cluster-service:${e.project}`,{kind:"nx-lock-break",project:e.project}),setTimeout(()=>{t.stopped()||!e.lockBlockedAt||(q(e,"parked on a foreign nx task lock \u2014 recycling",{announce:!1}),X(e,o),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&U(e)},1500).unref?.())},250).unref?.())}},"sniff"),$=e.wsKey&&e.wsKey!==t.wsKey&&e.root?(0,workspace_log_1.workspaceLogWriter)(e.root):void 0,M=s(m=>{const h=(0,own_log_1.linePrefixer)(e.project);return _=>{if(t.stopped())return;const j=(0,inspector_secret_1.redactInspectorUrls)(_.toString());u(j);const C=h(j);m.write(C),$?.(C)}},"relay");return l.stdout?.on("data",M(process.stdout)),l.stderr?.on("data",M(process.stderr)),l.on("exit",(m,h)=>{if(e.proc!==l||(e.proc=void 0,e.state="down",t.stopped()))return;const _=(0,exit_reason_1.describeExit)(m,h);if(console.log(`[gateway] ${o} exited (${m??"no code"}${h?`, ${h}`:""}${e.inflight?`, ${e.inflight} request(s) in flight`:""})${_?` \u2014 ${_}`:""}`),S(e,m===0?"info":"warning",`service down: ${e.project} (exit ${m})`,`cluster-service:${e.project}`,{kind:"service-down",project:e.project,code:m,...h?{signal:h}:{}}),m===0||e.buildFailed)return;const j=Date.now();if(e.restarts=(e.restarts??[]).filter(K=>j-K<types_1.SERVICE_RESTART_WINDOW_MS),e.restarts.length>=types_1.SERVICE_MAX_RESTARTS){S(e,"error",`service crash-looping: ${e.project} \u2014 ${types_1.SERVICE_MAX_RESTARTS}+ restarts/min, not auto-respawning (the next request retries)`,`cluster-service:${e.project}`,{kind:"service-crash-loop",project:e.project});return}e.restarts.push(j);const C=Math.min(8e3,500*2**(e.restarts.length-1));setTimeout(()=>{t.stopped()||e.proc||e.state!=="down"||(console.log(`[gateway] self-heal: respawning ${e.project} (restart ${e.restarts.length}/${types_1.SERVICE_MAX_RESTARTS})`),S(e,"info",`self-heal: respawning ${e.project}`,`cluster-service:${e.project}`,{kind:"service-respawn",project:e.project,attempt:e.restarts.length}),U(e))},C)}),l},"launchServiceProcess"),U=s(e=>{if(t.stopped())return;const r=`${e.project}:${e.decl.serveTarget??"serve-hmr"}`,n=Math.max(1,e.decl.minPods??1);c.reapForeign!==!1&&X(e,r),e.lockBlockedAt=void 0,console.log(`[gateway] starting ${r} (pods=${n})\u2026`),S(e,"info",`service starting: ${e.project} (${n} pod${n>1?"s":""})`,`cluster-service:${e.project}`,{kind:"service-starting",project:e.project,pods:n}),e.state="starting",e.spawnAt=Date.now(),e.generation=(e.generation??0)+1,e.proc=H(e,e.generation,"active")},"spawnService"),ke=s(async e=>{const r=e.pool.socks[0];if(!r)return;const n=await(0,pod_probe_1.probePodAlive)(r,void 0,t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)]);n&&(e.activeWork=n.activeWork,n.watcher&&(e.watcher=n.watcher))},"refreshActiveWork"),je=s(e=>{try{const r=Number(fs.readFileSync(`${e}.owner`,"utf8").trim());return Number.isInteger(r)&&r>1?r:void 0}catch{return}},"readOwnerSidecar"),Re=s(async e=>{const r=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)];if(!r)return[];const n=(0,node_crypto_1.createHash)("sha256").update(r).digest("hex").slice(0,8),o=[];for(const i of e.pool.socks){const l=await(0,pod_probe_1.probePodAlive)(i,void 0,r);l&&(!l.keyFingerprint||l.keyFingerprint!==n)&&o.push({sock:i,pid:l.pid})}return o},"staleAdoptedSocks"),Ce=s((e,r)=>{const n=r.map(o=>o.sock);for(const{sock:o,pid:i}of r){const l=chooseStalePodKillTarget(i,je(o),process.pid);if(l!==void 0)try{process.kill(l,"SIGTERM")}catch{}try{fs.unlinkSync(o)}catch{}try{fs.unlinkSync(`${o}.owner`)}catch{}}e.pool.socks=e.pool.socks.filter(o=>!n.includes(o)),e.pool.idx=-1,e.pool.scannedAt=0},"evictStaleAdopted"),ie=s((e,r)=>{if(e.state==="up")return!1;e.state="up",e.wedgeRecycles=0;const n=e.pool.socks.length;return S(e,"info",`service up: ${e.project} (${n} pods, ${r})`,`cluster-service:${e.project}`,{kind:"service-up",project:e.project,pods:n,adopted:r==="adopted"}),!0},"markUp"),pe=s(async e=>{if(N(e.pool)>0){const o=await Re(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.`),S(e,"warning",`stale adoption: ${e.project} (foreign east-west key)`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:"stale-adoption",pods:o.length}),e.proc&&q(e,"stale adoption (foreign east-west key)"),Ce(e,o)),e.pool.socks.length>0)return ie(e,"adopted"),!0}if(t.stopped())return!1;let r=!1;const n=s(()=>e.state!=="starting"&&!e.proc,"notStarted");if(n())if(e.coldWait)await e.coldWait;else{k>=y&&(console.log(`[gateway] cold start queued: ${e.project}${e.wsKey&&e.wsKey!==t.wsKey?` (${e.wsKey})`:""} \u2014 ${k} starting, ${L.length} ahead (LENSMCP_MAX_COLD_STARTS=${y}).`),S(e,"info",`cold start queued: ${e.project}`,`cluster-service:${e.project}`,{kind:"cold-start-queued",project:e.project,inFlight:k,ahead:L.length}));const o=O();if(e.coldWait=o,await o,e.coldWait=void 0,r=!0,t.stopped())return D(),!1;n()&&U(e)}try{return await Ae(e)}finally{r&&D()}},"ensureUp"),Ae=s(async e=>{const r=Date.now()+t.startupTimeoutMs,n=Date.now()+12e3;for(;!t.stopped()&&Date.now()<r;){if(await sleep(Math.min(700,t.startupTimeoutMs/4)),e.buildFailed&&Date.now()>n)return!1;if(N(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`:""})`),S(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},"waitForPods"),Te=s(e=>{const r=e.decl.maxPods??e.decl.minPods??1,n=e.pool.socks.length,o=scaleTarget(e);!o||n===0||n>=r||e.inflight<=n||Date.now()-e.lastScaleAt<5e3||(e.lastScaleAt=Date.now(),postScale(o,n+1,c.scaleLookup),console.log(`[gateway] autoscale ${e.project}: ${n} \u2192 ${n+1} pods (inflight ${e.inflight})`),S(e,"info",`autoscale: ${e.project} ${n} \u2192 ${n+1} pods`,`cluster-service:${e.project}`,{kind:"autoscale",project:e.project,from:n,to:n+1,inflight:e.inflight}))},"scaleUp"),q=s((e,r,n)=>{if(!e.proc)return;console.log(`[gateway] ${e.project} ${r} \u2014 scaling to zero.`),n?.announce!==!1&&S(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{}(0,discovery_1.stopRoutingTo)(e.pool),R(o,"SIGTERM"),e.proc=void 0,e.state="down",setTimeout(()=>{le(e),e.pool.socks=[],e.pool.scannedAt=0},1200).unref?.()},"killSpawned"),le=s(e=>{try{for(const r of fs.readdirSync(e.pool.dir)){if(!r.endsWith(".sock"))continue;const n=path.join(e.pool.dir,r);try{const o=Number(fs.readFileSync(`${n}.owner`,"utf8").trim());if(Number.isFinite(o)&&o>0)try{process.kill(o,0);continue}catch{}}catch{}try{fs.unlinkSync(n)}catch{}try{fs.unlinkSync(`${n}.owner`)}catch{}}}catch{}},"sweepDeadOwnerSocks");let Y=0;const ue=[],Me=s(()=>Y<B?(Y+=1,Promise.resolve()):new Promise(e=>{ue.push(()=>{Y+=1,e()})}),"acquireRollSlot"),xe=s(()=>{Y-=1,ue.shift()?.()},"releaseRollSlot"),_e=s(async(e,r,n)=>{N(e.pool);for(const o of e.pool.socks){const i=await f(o,void 0,n);if(i&&r(i.podGeneration))return!0}return!1},"anyPodAnswers"),he=new Map,Pe=s((e,r,n)=>{const o=A>0&&(0,handoff_retire_1.requestHandoffRetire)(e.pool.dir,n);if(R(r,"SIGTERM"),!o)return;const i=e.wsKey&&e.wsKey!==t.wsKey&&e.root?(0,workspace_log_1.workspaceLogWriter)(e.root):void 0,l=s(re=>g=>{if(t.stopped())return;const P=(0,inspector_secret_1.redactInspectorUrls)(g.toString()).replace(/^(?=.)/gm,`[${e.project} g${n} retiring] `);re.write(P),i?.(P)},"say"),p=l(process.stdout),u=l(process.stderr);r.stdout?.on("data",p),r.stderr?.on("data",u);let $,M=!1;const m=s(()=>{M=!0,clearTimeout($),r.stdout?.removeListener("data",p),r.stderr?.removeListener("data",u),r.removeListener("close",m)},"releaseLogs");r.once("close",m);let h=!1;const _=s(()=>{h||(h=!0,clearTimeout(j),clearInterval(K),t.stopped()?m():M||($=setTimeout(m,1e3),$.unref?.()),he.delete(r),(0,handoff_retire_1.clearHandoffRetire)(e.pool.dir,n),le(e),e.pool.scannedAt=0)},"end"),j=setTimeout(()=>{console.error(`[gateway] pod handoff: ${e.project} g${n} was still running ${A}ms after it was retired \u2014 killing it.`),T(r,"SIGKILL"),_()},A);j.unref?.();const C=s(()=>{if(!h){if(t.stopped()){_();return}I(r)||(console.log(`[gateway] pod handoff: ${e.project} g${n} finished its in-flight work and exited.`),_())}},"look"),K=setInterval(C,ne);K.unref?.(),r.once("exit",C),he.set(r,()=>{T(r,"SIGTERM"),_()})},"retireReplacedTree"),De=s(()=>{for(const e of[...he.values()])e()},"stopRetiringTrees"),ge=s((e,r)=>{if(e.rolling)return e.rolling;const n=e.proc;if(!n||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);Y>=B&&console.log(`[gateway] pod handoff queued: ${e.project} reason=${r} \u2014 ${Y} roll(s) in flight, ${ue.length} ahead (LENSMCP_POD_MAX_CONCURRENT_ROLLS=${B}).`);const o=(async()=>{await Me();try{return await Le(e,n,r)}finally{xe()}})().finally(()=>{e.rolling=void 0});return e.rolling=o,o},"rollPod"),Le=s(async(e,r,n)=>{const o=e.proc;if(o!==r||t.stopped())return!1;const i=e.generation??0,l=i+1,p=Date.now();e.lastStaleRecycleAt=p,console.log(`[gateway] pod handoff start: ${e.project} g${i}\u2192g${l} reason=${n} \u2014 standby spawning, old generation keeps serving.`),S(e,"info",`pod handoff starting: ${e.project} (${n})`,`cluster-service:${e.project}`,{kind:"pod-handoff-start",project:e.project,reason:n,generation:l,fromGeneration:i});const u=H(e,l,"standby"),$=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],M=p+J;let m;for(;!t.stopped()&&Date.now()<M&&!(u.exitCode!==null||u.signalCode!==null);){N(e.pool);for(const h of e.pool.socks)if((await f(h,void 0,$))?.podGeneration===l){m=h;break}if(m)break;await sleep(ae)}if(!m||t.stopped()){const h=t.stopped()?"gateway stopping":u.exitCode!==null||u.signalCode!==null?`standby exited (${u.exitCode??u.signalCode})`:`standby not ready within ${Math.round(J/1e3)}s`;try{u.stdout?.removeAllListeners("data"),u.stderr?.removeAllListeners("data")}catch{}(0,discovery_1.stopRoutingTo)(e.pool,C=>(0,pod_sock_1.podSockGeneration)(C)===l),R(u,"SIGTERM");const _=!t.stopped()&&e.proc===o&&o.exitCode===null&&o.signalCode===null&&await _e(e,C=>C!==l,$),j=_?`old generation g${i} kept serving`:`and the old generation g${i} 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${l}: ${h} \u2014 ${j}.`),e.rollFailure=`${h} \u2014 ${j}`,S(e,_?"warning":"error",`pod handoff failed: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-failed",project:e.project,reason:n,generation:l,error:h,durationMs:Date.now()-p,oldServing:_}),setTimeout(()=>le(e),1200).unref?.(),!1}if(e.proc!==o)return(0,discovery_1.stopRoutingTo)(e.pool,h=>(0,pod_sock_1.podSockGeneration)(h)===l),R(u,"SIGTERM"),!1;e.proc=u,e.launcher=ee.get(u),e.generation=l,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(0,discovery_1.stopRoutingTo)(e.pool,h=>(0,pod_sock_1.podSockGeneration)(h)!==l&&path.join(e.pool.dir,h)!==m),Pe(e,o,i),setTimeout(()=>{le(e),e.pool.scannedAt=0},1200).unref?.(),console.log(`[gateway] pod handoff ready: ${e.project} g${l} answered on ${path.basename(m)} in ${Date.now()-p}ms; retiring g${i}.`),S(e,"info",`pod handoff complete: ${e.project}`,`cluster-service:${e.project}`,{kind:"pod-handoff-complete",project:e.project,reason:n,generation:l,fromGeneration:i,durationMs:Date.now()-p}),!0},"runRoll"),be=s((e,r)=>{if(t.stopped())return{refused:"the gateway is stopping"};if(e.restart&&!e.restart.done)return{restart:e.restart,already:!0};if(!e.proc&&e.state!=="down")return{refused:`${e.project} is served by pods this gateway adopted from an earlier one \u2014 it has no tree of its own to replace. \`lensmcp gateway restart\` starts every service under this gateway.`};const n=e.proc?r.hard||e.launcher==="nx"||e.state!=="up"?"hard":"rolling":"start",o={how:n,reason:r.reason,startedAt:Date.now(),...e.proc&&e.generation!==void 0?{fromGeneration:e.generation}:{}};return e.restart=o,e.lastUsed=o.startedAt,console.log(`[gateway] restart asked: ${e.project}${e.wsKey!==t.wsKey?` (${e.wsKey})`:""} \u2014 ${n} (${r.reason}).`),S(e,"info",`restart asked: ${e.project} (${n})`,`cluster-service:${e.project}`,{kind:"service-restart",phase:"started",project:e.project,how:n,reason:r.reason,...o.fromGeneration!==void 0?{fromGeneration:o.fromGeneration}:{}}),s(async()=>{if(n==="start")return await pe(e)?{ok:!0}:{ok:!1,error:fe(e)};if(n==="rolling")return e.rolling&&await e.rolling,e.proc?(e.rollFailure=void 0,await ge(e,r.reason)?{ok:!0}:{ok:!1,error:e.rollFailure??"the new tree did not take over"}):await pe(e)?{ok:!0}:{ok:!1,error:fe(e)};if(q(e,`restart asked (${r.reason})`,{announce:!1}),await sleep(1500),t.stopped())return{ok:!1,error:"the gateway is stopping"};let i=!1;e.proc||(await O(),i=!0,!e.proc&&e.state!=="starting"&&U(e));try{const l=e.proc,p=e.generation,u=t.serviceKeys[(0,service_keys_1.serviceKeyId)(e.wsKey,e.project)],$=Date.now()+t.startupTimeoutMs;for(;!t.stopped()&&Date.now()<$;){if(!l||e.proc!==l||l.exitCode!==null||l.signalCode!==null)return{ok:!1,error:fe(e)};if(await _e(e,M=>M===p,u))return ie(e,"observed"),e.buildFailed=!1,{ok:!0};await sleep(ae)}return{ok:!1,error:t.stopped()?"the gateway is stopping":`no pod of the new tree answered within ${Math.round(t.startupTimeoutMs/1e3)}s`}}finally{i&&D()}},"run")().catch(i=>({ok:!1,error:i.message})).then(i=>{o.done={ok:i.ok,at:Date.now(),...e.generation!==void 0?{generation:e.generation}:{},...i.error?{error:i.error}:{}},i.ok&&(e.lastUsed=o.done.at);const l=Math.round((o.done.at-o.startedAt)/100)/10;i.ok?console.log(`[gateway] restarted: ${e.project} \u2014 g${o.done.generation??"?"} serving after ${l}s (${n}).`):console.error(`[gateway] restart failed: ${e.project} \u2014 ${i.error} (${n}, after ${l}s).`),S(e,i.ok?"info":"error",i.ok?`restarted: ${e.project}`:`restart failed: ${e.project}`,`cluster-service:${e.project}`,{kind:"service-restart",phase:i.ok?"done":"failed",project:e.project,how:n,reason:r.reason,...o.fromGeneration!==void 0?{fromGeneration:o.fromGeneration}:{},...o.done.generation!==void 0?{generation:o.done.generation}:{},durationMs:o.done.at-o.startedAt,...i.error?{error:i.error}:{}})}),{restart:o,already:!1}},"restartService"),fe=s(e=>e.buildFailed?`its build failed${e.lastErrors?.length?`: ${e.lastErrors[e.lastErrors.length-1]}`:""}`:e.proc&&(e.proc.exitCode!==null||e.proc.signalCode!==null)?`its tree exited (${e.proc.exitCode??e.proc.signalCode})`:!e.proc&&e.state==="down"?"its tree exited before a pod answered":`no pod answered within ${Math.round(t.startupTimeoutMs/1e3)}s`,"startFailure"),Ee=s(e=>{const r=Date.now();e.restarts=(e.restarts??[]).filter(o=>r-o<types_1.SERVICE_RESTART_WINDOW_MS);const n=(e.wedgeRecycles??0)+1;if(e.restarts.length>=types_1.SERVICE_MAX_RESTARTS||n>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`;S(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:n-1}),q(e,"wedged (crash-loop cap) \u2014 leaving down for the next request",{announce:!1});return}e.wedgeRecycles=n,e.restarts.push(r),console.log(`[gateway] self-heal: recycling WEDGED ${e.project} (live parent, 0 live pods; attempt ${n}/${types_1.SERVICE_MAX_RESTARTS} with no pod up since the first, ${e.restarts.length} in the last minute; ${e.inflight??0} request(s) in flight \u2014 jobs held by the dead pod keep their locks until they expire)`),S(e,"warning",`self-heal: recycling wedged ${e.project} (0 live pods)`,`cluster-service:${e.project}`,{kind:"service-recycle",project:e.project,attempt:n,inWindow:e.restarts.length}),q(e,"wedged: 0 live pods \u2014 recycling",{announce:!1}),setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&U(e)},1500).unref?.()},"recycleWedged"),Ie={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 we;const te=new Map,Se=new Map;let ve=!1,ye=0,de=0;const Oe=s(()=>{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 n=new Set;for(const o of r){const i=e[o];if(!i)continue;const l=path.relative(t.root,i).split(path.sep).filter(Boolean)[0];l&&!l.startsWith("..")&&n.add(l)}return[...n]},"managedBuckets"),Ne=s((e,r,n,o)=>{const i=t.projectSourceRoots?.[e];if(i?.length)return i;const l=t.projectRoots?.[e];if(!l)return;const p=sourceScopeDirs(t.root,l,n,r,o);return p.length>0?p:void 0},"scopeFor"),Fe=s(()=>{if(ve||Date.now()-ye<types_1.POD_STALE_SCAN_MS)return;ve=!0,ye=Date.now();const e=ye;(async()=>{const r=(0,scope_1.readSourceSetOptions)(t.root),n=r.exclude,o={ignoreTests:r.ignoreTests},i=sourceScanPass(t.root,n,o),l=await i.snapshot(),p=Date.now(),u=sourceChangeWindowMs(p,de,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS),$=we?diffSourceSets(we,l,p,u):null;if($&&(t.sourceSetChangedAt=p,t.sourceSetChange=$,V("info","source file set changed \u2014 stale pods recycle when idle","cluster-gateway",{kind:"source-set-changed",added:$.added,removed:$.removed,truncated:$.truncated})),we=l,!t.projectRoots){de=e;return}let M;try{M=(await fs.promises.readdir(t.root,{withFileTypes:!0})).filter(g=>g.isDirectory()).map(g=>g.name)}catch{return}const m=Oe(),h=new Set(t.services.map(g=>g.project));for(const g of t.routes)g.lens&&h.add(g.lens.project);const _=new Map;for(const g of h){const P=Ne(g,M,m,n);if(!P)continue;const x=P.join("|"),W=_.get(x)??{dirs:P,projects:[]};W.projects.push(g),_.set(x,W)}const j=Date.now(),C=sourceChangeWindowMs(j,de,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS);de=e;const K=s((g,P,x)=>{t.sourceSetChangedFor??=new Map,t.sourceSetChangesFor??=new Map;for(const W of g)t.sourceSetChangedFor.set(W,P),t.sourceSetChangesFor.set(W,x)},"stampScoped"),re=new Set([..._.values()].flatMap(g=>g.projects));for(const g of[...t.sourceSetScoped??[]])re.has(g)||t.sourceSetScoped.delete(g);for(const[g,{dirs:P,projects:x}]of _){const W=await i.snapshot(P),$e=te.get(g);if($e||x.some(b=>Se.has(b))){t.sourceSetScoped??=new Set;for(const b of x)t.sourceSetScoped.add(b)}te.set(g,W);const me=new Map;for(const b of x){const G=Se.get(b);if(G===void 0||G===g)continue;const z=me.get(G)??[];z.push(b),me.set(G,z)}for(const b of x)Se.set(b,g);for(const[b,G]of me){const z=te.get(b),se=z?diffSourceSets(z,W,j,C):$;se&&(K(G,z?j:p,se),V("info",`source file set changed \u2014 ${G.join(", ")}'s watch scope was re-keyed`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,rescoped:!0,projects:G,added:se.added,removed:se.removed,truncated:se.truncated}))}if(!$e)continue;const oe=diffSourceSets($e,W,j,C);oe&&(K(x,j,oe),V("info",`source file set changed in ${x.join(", ")}'s scope`,"cluster-gateway",{kind:"source-set-changed",scoped:!0,projects:x,added:oe.added,removed:oe.removed,truncated:oe.truncated}))}for(const g of[...te.keys()])_.has(g)||te.delete(g)})().catch(()=>{}).finally(()=>{ve=!1})},"maybeScanSourceSet"),Ke=s((e,r)=>{const n=podChangeClock(t,e.project),o=n.change,i=`${n.scope==="project"?"in its scope":"in the workspace (its scope is not known)"}: ${changeEvidence(o)}`,l=o?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,p=podWatcherVerdict(e.watcher,r,l),u=s(M=>(e.staleKeptAt!==r&&(e.staleKeptAt=r,console.log(`[gateway] stale source set: pod ${e.project} ${M} \u2014 no recycle.`)),!1),"keep");if(p==="heard")return e.staleVerifiedAt=r,S(e,"info",`stale check: ${e.project} watcher confirmed \u2014 no recycle`,`cluster-service:${e.project}`,{kind:"pod-stale-verified",project:e.project,watcher:p}),u(`watcher CONFIRMED alive across the change (last build ${new Date(e.watcher?.lastBuildAt??0).toISOString()})`);if(p==="degraded")return console.log(`[gateway] stale source set: pod ${e.project} watcher DEGRADED (${e.watcher?.degraded}) \u2014 recycling.`),!0;const $=s(M=>(e.staleKeptAt!==r&&(e.staleKeptAt=r,console.log(`[gateway] stale source set: pod ${e.project} ${M}; the change ${i} \u2014 recycling.`)),!0),"recycling");return p==="silent"?types_1.POD_WATCHER_SILENT==="keep"?u("watcher alive but quiet across the change \u2014 keeping it (LENSMCP_POD_WATCHER_SILENT=keep; a live watcher cannot miss an add it will need)"):$("watcher alive but quiet across the change"):types_1.POD_WATCHER_UNVERIFIED==="keep"?u("unverifiable (no watcher testimony \u2014 older devserver bundle?) \u2014 keeping it (LENSMCP_POD_WATCHER_UNVERIFIED=keep)"):$("watcher unverifiable (no testimony yet \u2014 a pod that never rebuilt, or an older devserver bundle)")},"podStaleRecycleAllowed"),We=s((e,r)=>{if(e.lastStaleRecycleAt=Date.now(),types_1.POD_RECYCLE_MODE==="rolling"&&e.proc&&e.launcher!=="nx"){ge(e,r);return}console.log(`[gateway] zombie recycle: ${e.project} (${r}) \u2014 stale fs view; fresh pod incoming`),S(e,"warning",`zombie recycle: ${e.project} (${r})`,`cluster-service:${e.project}`,{kind:"pod-recycle",project:e.project,reason:r});const n=!!e.decl.eager;q(e,`${r} \u2014 recycling stale pod`,{announce:!1}),n&&setTimeout(()=>{!t.stopped()&&!e.proc&&e.state==="down"&&U(e)},1500).unref?.()},"recyclePod"),qe=s(()=>{const e=setInterval(()=>{Ge().catch(r=>console.error("[gateway] sweep error:",r))},t.sweepMs);return e.unref(),e},"startSweeper"),Ge=s(async()=>{{if(t.stopped())return;for(const e of t.graphStores?.all()??[])e.refreshIfStale();types_1.POD_RECYCLE_ENABLED&&Fe();for(const e of t.registry?t.registry.allServices():t.services){if(t.stopped()||!e.proc){e.wedgedSince=void 0;continue}const r=path.resolve(e.root)===path.resolve(t.root),n=(0,warm_start_1.instanceIdleSec)(e,!r&&!!t.registry?.get(e.wsKey)?.instance);if(n&&e.state==="up"&&(!e.restart||e.restart.done)&&e.inflight===0&&Date.now()-e.lastUsed>n*1e3){q(e,`idle ${n}s`),e.wedgedSince=void 0;continue}const o=e.state==="starting"&&e.spawnAt!==void 0&&Date.now()-e.spawnAt<t.startupTimeoutMs,i=N(e.pool)>0;if(i||o){if(e.wedgedSince=void 0,i&&ie(e,"observed"),i&&!o&&types_1.POD_RECYCLE_ENABLED&&r){const l=podChangeClock(t,e.project).at;await ke(e);const p=(e.staleVerifiedAt??0)>=l&&l>0,u=podRecycleReason(e,Date.now(),p?0:l,Ie);if(u==="stale-source-set"&&!Ke(e,l))continue;u&&We(e,u)}continue}e.wedgedSince??=Date.now(),Date.now()-e.wedgedSince>types_1.WEDGE_RECYCLE_GRACE_MS&&(e.wedgedSince=void 0,Ee(e))}}},"sweepOnce");return{scanNow:N,spawnService:U,ensureUp:pe,scaleUp:Te,killSpawned:q,markUp:ie,startSweeper:qe,rollPod:ge,restartService:be,recycleWedged:Ee,stopRetiringTrees:De,stopBuildHost:s(e=>e===void 0?E.stop():E.release(e),"stopBuildHost")}}v(createServiceLayer,"createServiceLayer"),s(createServiceLayer,"createServiceLayer");function chooseStalePodKillTarget(t,a,c){if(!(t===void 0||!Number.isInteger(t)||t<=1)&&!(a!==void 0&&a!==t)&&t!==c)return t}v(chooseStalePodKillTarget,"chooseStalePodKillTarget"),s(chooseStalePodKillTarget,"chooseStalePodKillTarget");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var ie=Object.defineProperty;var c=(e,t)=>ie(e,"name",{value:t,configurable:!0});var se=Object.defineProperty,o=c((e,t)=>se(e,"name",{value:t,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0});const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),fs=tslib_1.__importStar(require("node:fs")),node_child_process_1=require("node:child_process"),yaml=tslib_1.__importStar(require("js-yaml")),dev_devtool_1=require("../../dev-devtool"),devserver_notifier_1=require("../../devserver-notifier"),process_name_1=require("../../process-name"),worker_supervisor_1=require("../../worker-supervisor"),attach_1=require("../../shared-build/attach");function definedEnv(e){const t={};for(const[_,i]of Object.entries(e))typeof i=="string"&&(t[_]=i);return t}c(definedEnv,"definedEnv"),o(definedEnv,"definedEnv");const frozen=o(()=>process.env.LENSMCP_FREEZE==="1","frozen");async function*serveExecutor(e,t){process.env.NODE_ENV="development";const _=t.projectsConfigurations.projects[t.projectName],i=t.root,g=path.join(i,_.root),U=e.outputPath?path.join(i,e.outputPath):path.join(i,"dist",_.root),B=e.configEnv||"development",R=path.join(i,"config",`config.${B}.yaml`),$=3050;let d=$,a=t.projectName,S={};fs.existsSync(R)?(S=yaml.load(fs.readFileSync(R,"utf8")),d=Number(S.port)||d,a=S.serviceName||a):console.warn(`[serve] ${t.projectName}: no config file at ${R} \u2014 public devserver port defaults to ${$}. If another service also lacks its config, both bind ${$} \u2192 EADDRINUSE. Add config/config.${B}.yaml with a distinct \`port:\` (matching this project's cluster.port).`),e.serviceName&&(a=e.serviceName);const T=e.servePrefix??"",h=e.debugPort??(Number(process.env.LENSMCP_DEBUG_PORT)||void 0),z=/^(1|true|yes|on)$/i.test((process.env.LENSMCP_DEBUG_FIXED_PORTS??"").trim()),p=e.logFile?path.resolve(i,e.logFile):process.env.LENSMCP_LOG_FILE||void 0;if(p){fs.mkdirSync(path.dirname(p),{recursive:!0}),fs.writeFileSync(p,"",{mode:384});try{fs.chmodSync(p,384)}catch{}}let k,D;e.gateway?.middleware&&(k=path.resolve(g,e.gateway.middleware),D=JSON.stringify(S));const K=e.entryFile||"./src/deployments/service/main.ts",Q=e.tsConfigFile||"./tsconfig.app.json",Z=path.resolve(g,K),q=path.resolve(g,Q),ee=(e.workers||[]).map(r=>({entryName:r.name,entryPath:path.resolve(g,r.entryPath)})),W={appName:t.projectName,appRoot:g,outputDir:U,main:Z,tsConfig:q,assets:e.assets||[],additionalEntryPoints:ee,port:d,serviceName:a,memoryLimit:e.memoryLimit||8192,buildLibsFromSource:e.buildLibsFromSource!==!1,workspaceRoot:i,orgScopes:e.orgScopes||[],bundlePackages:e.bundlePackages||[],nodeExternalsConfig:e.nodeExternalsConfig,webpackConfigPath:e.webpackConfigPath,httpsReload:e.gateway?.https===!0,...e.devtool!==void 0&&{devtool:e.devtool}};let l=null,O=!1,I=!1,m=!1;const V=path.join(__dirname,"../../main.devserver.js"),H=path.join(__dirname,"../../main.devserver.ts"),Y=!fs.existsSync(V)&&fs.existsSync(H),x=Y?H:V,oe=path.join(U,"main.js");function A(){l&&!l.killed&&(l.kill("SIGTERM"),l=null)}c(A,"H"),o(A,"cleanup");function N(){m=!0,A()}c(N,"O"),o(N,"stop");const re=["SIGINT","SIGTERM","SIGHUP","SIGQUIT"].map(r=>{const n=o(()=>N(),"handler");return process.on(r,n),{sig:r,handler:n}});process.on("exit",N);function E(){if(m)return;if(!fs.existsSync(x)){console.error(`[serve] devserver script not found at ${x}`);return}const r=["--enable-source-maps"];Y&&r.unshift("--require","@swc-node/register");const n=(0,node_child_process_1.fork)(x,{cwd:i,env:{...process.env,PORT:String(d),SERVICE_NAME:a,SERVE_PREFIX:T,LENSMCP_PROJECT:process.env.LENSMCP_PROJECT||t.projectName||a,LENSMCP_EVENT_FILE:process.env.LENSMCP_EVENT_FILE||path.join(i,".lensmcp","events.jsonl"),CHILD_COUNT:String(e.childCount||process.env.CHILD_COUNT||1),BUNDLE_PATH:oe,...k&&{GATEWAY_MIDDLEWARE:k},...D&&{GATEWAY_CONFIG:D},...e.gateway?.routes?.length&&{GATEWAY_ROUTES:JSON.stringify(e.gateway.routes)},...e.gateway?.https&&{GATEWAY_HTTPS:"1"},...e.gateway?.extraPorts?.length&&{GATEWAY_EXTRA_PORTS:JSON.stringify(e.gateway.extraPorts)},...e.internalPort&&{INTERNAL_PORT:String(e.internalPort)},...h&&{LENSMCP_DEBUG_PORT:String(h)},...p&&{LENSMCP_LOG_FILE:p},...e.workers?.length&&{WORKERS:(0,worker_supervisor_1.serializeWorkerSpecs)(e.workers)},[dev_devtool_1.DEV_SOURCE_MAPS_ENV]:I?"1":"0"},stdio:["inherit","inherit","inherit","ipc"],execArgv:r,execPath:(0,process_name_1.namedExecPath)((0,process_name_1.processName)(process.env.LENSMCP_WS_KEY||path.basename(i),a,"dev"))});l=n,n.on("exit",(u,f)=>{l===n&&(l=null),!(f||u===0||m)&&(console.error(`[serve] devserver exited unexpectedly (code=${u}, signal=${f}) \u2014 respawning in 1.5s`),setTimeout(()=>{!m&&!l&&O&&E()},1500).unref?.())}),console.log(`[serve] Devserver started on port ${d} (service: ${a}${T?`, prefix: /${T}`:""})`),h?(console.warn(`[serve] DEBUGGER ENABLED for ${a}. Node's inspector has NO authentication \u2014 the ws:// UUID is the whole credential, and any account on this host that obtains it runs code as you. Do not enable this on a shared machine.`),z?console.warn(`[serve] LENSMCP_DEBUG_FIXED_PORTS=1 \u2014 pod inspectors bind PREDICTABLE ports 127.0.0.1:${h}+slot (workers ${h}+20+i), reachable by any account on this host. Attach WebStorm (Attach to Node.js/Chrome) to ${h}. Unset it to bind ephemeral ports instead.`):console.log(`[serve] Debug: pod inspectors bind an EPHEMERAL 127.0.0.1 port. Get the ws:// URLs with \`lensmcp debug ${a}\` (the owner-only control socket); a devserver run in your own terminal also prints them there. Set LENSMCP_DEBUG_FIXED_PORTS=1 if your IDE needs a fixed attach port.`)):console.log(`[serve] Debug on demand: \`lensmcp debug ${a}\` opens pod inspectors without a restart`),p&&console.log(`[serve] Logs teed to ${p} \u2014 tail it in WebStorm via Run/Debug configuration \u2192 Logs tab`)}c(E,"_"),o(E,"startDevServer");function te(){if(!l||l.killed){console.log("[serve] Devserver not running, restarting..."),E();return}fetch(`http://localhost:${d}/webpack/reload`,{method:"POST",headers:{"content-type":"application/json"},body:"{}"}).then(()=>console.log("[serve] Notified devserver to reload")).catch(r=>{console.warn("[serve] Failed to notify devserver, restarting...",r.message),A(),E()})}c(te,"ne"),o(te,"_notifyDevServerReload");let w=null;const M=[];function v(r){if(w){const n=w;w=null,n(r)}else M.push(r)}c(v,"h"),o(v,"pushResult");function J(){return M.length>0?Promise.resolve(M.shift()):new Promise(r=>{w=r})}c(J,"ee"),o(J,"waitForNext");let y=o(()=>{},"closeBuild");function F(){return!O||!l?(O=!0,E(),!0):!1}c(F,"J"),o(F,"builtOk");function b(){if(m)return;const{createDevWebpackConfig:r}=require("../../create-webpack-dev"),n=require("webpack"),u=r(W),{watch:f,...P}=u,s=n(P);I=(0,dev_devtool_1.bundleCarriesSourceMaps)(s.options.devtool);const j=o((L,C)=>{if(L){console.error("[serve] Webpack error:",L),v({success:!1});return}const ne=C.hasErrors();if(console.info(C.toString({colors:!0,chunks:!1,assets:!0})),ne){v({success:!1});return}F(),v({success:!0,baseUrl:`http://localhost:${d}`})},"onBuild");if(frozen()){console.log(`[serve] ${t.projectName}: frozen \u2014 compiling once, no file watcher`),s.run((L,C)=>{j(L,C),s.close(()=>{})});return}const G=s.watch(u.watchOptions||{},j);y=o(()=>G.close(()=>{}),"closeBuild")}c(b,"A"),o(b,"compileOnItsOwn");function X(r){const n=r.accepted.projects.filter(s=>s!==t.projectName);console.log(`[serve] ${t.projectName}: compiled by the workspace's shared compilation ${r.accepted.group.slice(0,8)}${n.length?` with ${n.join(", ")}`:""} \u2014 no webpack in this process`);const u=new devserver_notifier_1.DevserverNotifier(d,e.gateway?.https===!0,(0,devserver_notifier_1.devserverControlSock)(a)),f=(0,attach_1.createAttachedTypecheck)({appName:t.projectName,tsConfig:q,workspaceRoot:i,memoryLimit:e.memoryLimit||8192});let P;y=o(()=>{r.close(),f.dispose()},"closeBuild"),r.listen(s=>{if(!m)switch(s.type){case"watch-run":u.watchRun(s.paths);return;case"watch-closed":u.degrade("watch closed");return;case"failed":console.error(`[serve] the shared compiler failed: ${s.message}`),u.degrade(`compiler failed: ${s.message}`),v({success:!1});return;case"refused":console.log(`[serve] ${t.projectName}: compiling on its own from now on \u2014 ${s.reason}`),y(),b();return;case"built":{if(console.info(s.text),I=s.sourceMaps,f.built(s),!s.ok){u.failed(),v({success:!1});return}const j=s.hash!==P;P=s.hash;const G=F();u.built(j&&!G),v({success:!0,baseUrl:`http://localhost:${d}`});return}default:return}})}if(c(X,"re"),o(X,"attachToSharedBuild"),(0,attach_1.sharedBuildOffered)()&&!frozen()){const r=await(0,attach_1.joinSharedBuild)({project:t.projectName,target:t.targetName??"serve-hmr",...t.configurationName?{configuration:t.configurationName}:{},options:W,targetOptions:{...e},env:definedEnv(process.env)});r.kind==="attached"?X(r.session):(console.log(`[serve] ${t.projectName}: compiling on its own \u2014 ${r.reason}`),b())}else b();try{for(;;)yield await J()}finally{N(),y(),re.forEach(({sig:r,handler:n})=>process.removeListener(r,n))}}c(serveExecutor,"serveExecutor"),o(serveExecutor,"serveExecutor"),exports.default=serveExecutor,module.exports=serveExecutor,module.exports.default=serveExecutor;
|
|
1
|
+
"use strict";var ie=Object.defineProperty;var c=(e,t)=>ie(e,"name",{value:t,configurable:!0});var se=Object.defineProperty,o=c((e,t)=>se(e,"name",{value:t,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0});const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),fs=tslib_1.__importStar(require("node:fs")),node_child_process_1=require("node:child_process"),yaml=tslib_1.__importStar(require("js-yaml")),child_process_env_1=require("../../child-process-env"),dev_devtool_1=require("../../dev-devtool"),devserver_notifier_1=require("../../devserver-notifier"),process_name_1=require("../../process-name"),worker_supervisor_1=require("../../worker-supervisor"),attach_1=require("../../shared-build/attach");function definedEnv(e){const t={};for(const[_,i]of Object.entries(e))typeof i=="string"&&(t[_]=i);return t}c(definedEnv,"definedEnv"),o(definedEnv,"definedEnv");const frozen=o(()=>process.env.LENSMCP_FREEZE==="1","frozen");async function*serveExecutor(e,t){process.env.NODE_ENV="development";const _=t.projectsConfigurations.projects[t.projectName],i=t.root,g=path.join(i,_.root),U=e.outputPath?path.join(i,e.outputPath):path.join(i,"dist",_.root),B=e.configEnv||"development",R=path.join(i,"config",`config.${B}.yaml`),$=3050;let d=$,a=t.projectName,S={};fs.existsSync(R)?(S=yaml.load(fs.readFileSync(R,"utf8")),d=Number(S.port)||d,a=S.serviceName||a):console.warn(`[serve] ${t.projectName}: no config file at ${R} \u2014 public devserver port defaults to ${$}. If another service also lacks its config, both bind ${$} \u2192 EADDRINUSE. Add config/config.${B}.yaml with a distinct \`port:\` (matching this project's cluster.port).`),e.serviceName&&(a=e.serviceName);const T=e.servePrefix??"",h=e.debugPort??(Number(process.env.LENSMCP_DEBUG_PORT)||void 0),z=/^(1|true|yes|on)$/i.test((process.env.LENSMCP_DEBUG_FIXED_PORTS??"").trim()),p=e.logFile?path.resolve(i,e.logFile):process.env.LENSMCP_LOG_FILE||void 0;if(p){fs.mkdirSync(path.dirname(p),{recursive:!0}),fs.writeFileSync(p,"",{mode:384});try{fs.chmodSync(p,384)}catch{}}let k,D;e.gateway?.middleware&&(k=path.resolve(g,e.gateway.middleware),D=JSON.stringify(S));const K=e.entryFile||"./src/deployments/service/main.ts",Q=e.tsConfigFile||"./tsconfig.app.json",Z=path.resolve(g,K),q=path.resolve(g,Q),ee=(e.workers||[]).map(r=>({entryName:r.name,entryPath:path.resolve(g,r.entryPath)})),W={appName:t.projectName,appRoot:g,outputDir:U,main:Z,tsConfig:q,assets:e.assets||[],additionalEntryPoints:ee,port:d,serviceName:a,memoryLimit:e.memoryLimit||8192,buildLibsFromSource:e.buildLibsFromSource!==!1,workspaceRoot:i,orgScopes:e.orgScopes||[],bundlePackages:e.bundlePackages||[],nodeExternalsConfig:e.nodeExternalsConfig,webpackConfigPath:e.webpackConfigPath,httpsReload:e.gateway?.https===!0,...e.devtool!==void 0&&{devtool:e.devtool}};let l=null,O=!1,I=!1,m=!1;const V=path.join(__dirname,"../../main.devserver.js"),H=path.join(__dirname,"../../main.devserver.ts"),Y=!fs.existsSync(V)&&fs.existsSync(H),x=Y?H:V,oe=path.join(U,"main.js");function A(){l&&!l.killed&&(l.kill("SIGTERM"),l=null)}c(A,"H"),o(A,"cleanup");function N(){m=!0,A()}c(N,"O"),o(N,"stop");const re=["SIGINT","SIGTERM","SIGHUP","SIGQUIT"].map(r=>{const n=o(()=>N(),"handler");return process.on(r,n),{sig:r,handler:n}});process.on("exit",N);function E(){if(m)return;if(!fs.existsSync(x)){console.error(`[serve] devserver script not found at ${x}`);return}const r=["--enable-source-maps"];Y&&r.unshift("--require","@swc-node/register");const n=(0,node_child_process_1.fork)(x,{cwd:i,env:(0,child_process_env_1.childProcessEnv)({...process.env,PORT:String(d),SERVICE_NAME:a,SERVE_PREFIX:T,LENSMCP_PROJECT:process.env.LENSMCP_PROJECT||t.projectName||a,LENSMCP_EVENT_FILE:process.env.LENSMCP_EVENT_FILE||path.join(i,".lensmcp","events.jsonl"),CHILD_COUNT:String(e.childCount||process.env.CHILD_COUNT||1),BUNDLE_PATH:oe,...k&&{GATEWAY_MIDDLEWARE:k},...D&&{GATEWAY_CONFIG:D},...e.gateway?.routes?.length&&{GATEWAY_ROUTES:JSON.stringify(e.gateway.routes)},...e.gateway?.https&&{GATEWAY_HTTPS:"1"},...e.gateway?.extraPorts?.length&&{GATEWAY_EXTRA_PORTS:JSON.stringify(e.gateway.extraPorts)},...e.internalPort&&{INTERNAL_PORT:String(e.internalPort)},...h&&{LENSMCP_DEBUG_PORT:String(h)},...p&&{LENSMCP_LOG_FILE:p},...e.workers?.length&&{WORKERS:(0,worker_supervisor_1.serializeWorkerSpecs)(e.workers)},[dev_devtool_1.DEV_SOURCE_MAPS_ENV]:I?"1":"0"}),stdio:["inherit","inherit","inherit","ipc"],execArgv:r,execPath:(0,process_name_1.namedExecPath)((0,process_name_1.processName)(process.env.LENSMCP_WS_KEY||path.basename(i),a,"dev"))});l=n,n.on("exit",(u,f)=>{l===n&&(l=null),!(f||u===0||m)&&(console.error(`[serve] devserver exited unexpectedly (code=${u}, signal=${f}) \u2014 respawning in 1.5s`),setTimeout(()=>{!m&&!l&&O&&E()},1500).unref?.())}),console.log(`[serve] Devserver started on port ${d} (service: ${a}${T?`, prefix: /${T}`:""})`),h?(console.warn(`[serve] DEBUGGER ENABLED for ${a}. Node's inspector has NO authentication \u2014 the ws:// UUID is the whole credential, and any account on this host that obtains it runs code as you. Do not enable this on a shared machine.`),z?console.warn(`[serve] LENSMCP_DEBUG_FIXED_PORTS=1 \u2014 pod inspectors bind PREDICTABLE ports 127.0.0.1:${h}+slot (workers ${h}+20+i), reachable by any account on this host. Attach WebStorm (Attach to Node.js/Chrome) to ${h}. Unset it to bind ephemeral ports instead.`):console.log(`[serve] Debug: pod inspectors bind an EPHEMERAL 127.0.0.1 port. Get the ws:// URLs with \`lensmcp debug ${a}\` (the owner-only control socket); a devserver run in your own terminal also prints them there. Set LENSMCP_DEBUG_FIXED_PORTS=1 if your IDE needs a fixed attach port.`)):console.log(`[serve] Debug on demand: \`lensmcp debug ${a}\` opens pod inspectors without a restart`),p&&console.log(`[serve] Logs teed to ${p} \u2014 tail it in WebStorm via Run/Debug configuration \u2192 Logs tab`)}c(E,"_"),o(E,"startDevServer");function te(){if(!l||l.killed){console.log("[serve] Devserver not running, restarting..."),E();return}fetch(`http://localhost:${d}/webpack/reload`,{method:"POST",headers:{"content-type":"application/json"},body:"{}"}).then(()=>console.log("[serve] Notified devserver to reload")).catch(r=>{console.warn("[serve] Failed to notify devserver, restarting...",r.message),A(),E()})}c(te,"ne"),o(te,"_notifyDevServerReload");let w=null;const M=[];function v(r){if(w){const n=w;w=null,n(r)}else M.push(r)}c(v,"h"),o(v,"pushResult");function J(){return M.length>0?Promise.resolve(M.shift()):new Promise(r=>{w=r})}c(J,"ee"),o(J,"waitForNext");let y=o(()=>{},"closeBuild");function F(){return!O||!l?(O=!0,E(),!0):!1}c(F,"J"),o(F,"builtOk");function b(){if(m)return;const{createDevWebpackConfig:r}=require("../../create-webpack-dev"),n=require("webpack"),u=r(W),{watch:f,...P}=u,s=n(P);I=(0,dev_devtool_1.bundleCarriesSourceMaps)(s.options.devtool);const j=o((L,C)=>{if(L){console.error("[serve] Webpack error:",L),v({success:!1});return}const ne=C.hasErrors();if(console.info(C.toString({colors:!0,chunks:!1,assets:!0})),ne){v({success:!1});return}F(),v({success:!0,baseUrl:`http://localhost:${d}`})},"onBuild");if(frozen()){console.log(`[serve] ${t.projectName}: frozen \u2014 compiling once, no file watcher`),s.run((L,C)=>{j(L,C),s.close(()=>{})});return}const G=s.watch(u.watchOptions||{},j);y=o(()=>G.close(()=>{}),"closeBuild")}c(b,"A"),o(b,"compileOnItsOwn");function X(r){const n=r.accepted.projects.filter(s=>s!==t.projectName);console.log(`[serve] ${t.projectName}: compiled by the workspace's shared compilation ${r.accepted.group.slice(0,8)}${n.length?` with ${n.join(", ")}`:""} \u2014 no webpack in this process`);const u=new devserver_notifier_1.DevserverNotifier(d,e.gateway?.https===!0,(0,devserver_notifier_1.devserverControlSock)(a)),f=(0,attach_1.createAttachedTypecheck)({appName:t.projectName,tsConfig:q,workspaceRoot:i,memoryLimit:e.memoryLimit||8192});let P;y=o(()=>{r.close(),f.dispose()},"closeBuild"),r.listen(s=>{if(!m)switch(s.type){case"watch-run":u.watchRun(s.paths);return;case"watch-closed":u.degrade("watch closed");return;case"failed":console.error(`[serve] the shared compiler failed: ${s.message}`),u.degrade(`compiler failed: ${s.message}`),v({success:!1});return;case"refused":console.log(`[serve] ${t.projectName}: compiling on its own from now on \u2014 ${s.reason}`),y(),b();return;case"built":{if(console.info(s.text),I=s.sourceMaps,f.built(s),!s.ok){u.failed(),v({success:!1});return}const j=s.hash!==P;P=s.hash;const G=F();u.built(j&&!G),v({success:!0,baseUrl:`http://localhost:${d}`});return}default:return}})}if(c(X,"re"),o(X,"attachToSharedBuild"),(0,attach_1.sharedBuildOffered)()&&!frozen()){const r=await(0,attach_1.joinSharedBuild)({project:t.projectName,target:t.targetName??"serve-hmr",...t.configurationName?{configuration:t.configurationName}:{},options:W,targetOptions:{...e},env:definedEnv(process.env)});r.kind==="attached"?X(r.session):(console.log(`[serve] ${t.projectName}: compiling on its own \u2014 ${r.reason}`),b())}else b();try{for(;;)yield await J()}finally{N(),y(),re.forEach(({sig:r,handler:n})=>process.removeListener(r,n))}}c(serveExecutor,"serveExecutor"),o(serveExecutor,"serveExecutor"),exports.default=serveExecutor,module.exports=serveExecutor,module.exports.default=serveExecutor;
|
package/main.devserver.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var yt=Object.defineProperty;var u=(l,_)=>yt(l,"name",{value:_,configurable:!0});var gt=Object.defineProperty,a=u((l,_)=>gt(l,"name",{value:_,configurable:!0}),"a");Object.defineProperty(exports,"__esModule",{value:!0}),exports.redactInspectorUrls=exports.inspectorPortOf=exports.DEBUG_FIXED_PORTS_ENV=exports.mayDriveThePool=exports.isOwnerOnlyTransport=exports.gatewayManaged=void 0,exports.tell=tell,exports.usesFixedInspectorPorts=usesFixedInspectorPorts,exports.inspectorPortFor=inspectorPortFor;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"),worker_supervisor_1=require("./worker-supervisor"),hot_swap_registries_1=require("./hot-swap-registries"),process_name_1=require("./process-name"),inspector_secret_1=require("./inspector-secret");Object.defineProperty(exports,"inspectorPortOf",{enumerable:!0,get:a(function(){return inspector_secret_1.inspectorPortOf},"get")}),Object.defineProperty(exports,"redactInspectorUrls",{enumerable:!0,get:a(function(){return inspector_secret_1.redactInspectorUrls},"get")});const devserver_transport_1=require("./devserver-transport");Object.defineProperty(exports,"gatewayManaged",{enumerable:!0,get:a(function(){return devserver_transport_1.gatewayManaged},"get")}),Object.defineProperty(exports,"isOwnerOnlyTransport",{enumerable:!0,get:a(function(){return devserver_transport_1.isOwnerOnlyTransport},"get")}),Object.defineProperty(exports,"mayDriveThePool",{enumerable:!0,get:a(function(){return devserver_transport_1.mayDriveThePool},"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"),swap_mode_1=require("./swap-mode"),handoff_retire_1=require("./handoff-retire"),gc_notice_1=require("./gc-notice"),pod_sock_1=require("./pod-sock"),notice_generation_1=require("./notice-generation"),service_build_events_1=require("./service-build-events"),stdio_guard_1=require("./stdio-guard"),bundle_parent_1=require("./bundle-parent"),checkout_cache_1=require("./checkout-cache"),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 l=process.env.GATEWAY_CONFIG;if(!l)return{};try{return JSON.parse(l)}catch{return{}}})();let gatewayMiddleware=null;if(GATEWAY_MIDDLEWARE_PATH)try{const l=require(GATEWAY_MIDDLEWARE_PATH);gatewayMiddleware=typeof l=="function"?l:typeof l.default=="function"?l.default:null,gatewayMiddleware||console.warn(`[gateway] ${GATEWAY_MIDDLEWARE_PATH} does not export a function, gateway disabled`)}catch(l){console.error(`[gateway] Failed to load middleware from ${GATEWAY_MIDDLEWARE_PATH}:`,l)}function applyGatewayMiddleware(l){if(gatewayMiddleware)try{gatewayMiddleware(l,GATEWAY_CONFIG)}catch(_){console.error("[gateway] Middleware error:",_)}}u(applyGatewayMiddleware,"applyGatewayMiddleware"),a(applyGatewayMiddleware,"applyGatewayMiddleware");const GATEWAY_ROUTES=(()=>{try{return JSON.parse(process.env.GATEWAY_ROUTES||"[]")}catch{return[]}})(),GATEWAY_HTTPS=process.env.GATEWAY_HTTPS==="1";function hostMatches(l,_){if(l.startsWith("*.")){const f=l.slice(1);return _.endsWith(f)||_===l.slice(2)}return _===l}u(hostMatches,"hostMatches"),a(hostMatches,"hostMatches");function matchGatewayRoute(l){if(GATEWAY_ROUTES.length===0)return;const _=(l.headers.host||"").split(":")[0],f=l.url||"/";for(const m of GATEWAY_ROUTES)if(!(m.host&&!hostMatches(m.host,_))&&!(m.prefix&&!f.startsWith(m.prefix)))return m}u(matchGatewayRoute,"matchGatewayRoute"),a(matchGatewayRoute,"matchGatewayRoute");const{specs:WORKER_SPECS,problems:WORKER_PROBLEMS}=(0,worker_supervisor_1.parseWorkerSpecs)(process.env.WORKERS),WORKER_NAMES=WORKER_SPECS.map(l=>l.name),LENSMCP_WS_KEY=process.env.LENSMCP_WS_KEY||"",SOCK_NS=process.env.LENSMCP_SOCK_NS||LENSMCP_WS_KEY,SOCK_DIR=SOCK_NS?path.join(os.tmpdir(),SOCK_NS,`${SERVICE_NAME||"lensmcp-cluster"}-devserver`):path.join(os.tmpdir(),`${SERVICE_NAME||"lensmcp-cluster"}-devserver`),SOCKET_ONLY=process.env.LENSMCP_SOCKET_ONLY==="1",POD_GENERATION=(()=>{const l=Number(process.env.LENSMCP_POD_GENERATION);return Number.isFinite(l)&&l>1?Math.floor(l):1})();function childSockPath(l){return path.join(SOCK_DIR,(0,pod_sock_1.podSockName)(l,POD_GENERATION))}u(childSockPath,"childSockPath"),a(childSockPath,"childSockPath");function sockOwnerPath(l){return`${l}.owner`}u(sockOwnerPath,"sockOwnerPath"),a(sockOwnerPath,"sockOwnerPath");function sockRetiringPath(l){return`${l}.retiring`}u(sockRetiringPath,"sockRetiringPath"),a(sockRetiringPath,"sockRetiringPath");function tell(l,_){if(!l.connected||typeof l.send!="function")return!1;try{return l.send(_,()=>{})}catch{return!1}}u(tell,"tell"),a(tell,"tell");function refusePoolCommand(l,_){console.warn(`[devserver] refused ${l.method} ${l.url} on the public port \u2014 under a gateway the pool is driven on the control socket only.`),_.writeHead(404,{"content-type":"application/json"}),_.end(JSON.stringify({error:"not found"}))}u(refusePoolCommand,"refusePoolCommand"),a(refusePoolCommand,"refusePoolCommand"),exports.DEBUG_FIXED_PORTS_ENV="LENSMCP_DEBUG_FIXED_PORTS";function usesFixedInspectorPorts(l=process.env){const _=(l[exports.DEBUG_FIXED_PORTS_ENV]??"").trim().toLowerCase();return _==="1"||_==="true"||_==="yes"||_==="on"}u(usesFixedInspectorPorts,"usesFixedInspectorPorts"),a(usesFixedInspectorPorts,"usesFixedInspectorPorts");function inspectorPortFor(l,_,f=process.env){if(!usesFixedInspectorPorts(f))return 0;const m=Math.trunc(l)+Math.trunc(_);return Number.isInteger(m)&&m>1024&&m<=65535?m:0}u(inspectorPortFor,"inspectorPortFor"),a(inspectorPortFor,"inspectorPortFor");function ensureOwnerOnlyDir(l){try{fs.mkdirSync(l,{recursive:!0,mode:448})}catch{}try{const _=fs.lstatSync(l);_.isDirectory()&&(_.mode&63)!==0&&fs.chmodSync(l,448)}catch{}}u(ensureOwnerOnlyDir,"ensureOwnerOnlyDir"),a(ensureOwnerOnlyDir,"ensureOwnerOnlyDir");function claimSock(l,_=process.pid){ensureOwnerOnlyDir(path.dirname(l));try{const f=sockOwnerPath(l);try{fs.unlinkSync(f)}catch{}fs.writeFileSync(f,String(_),{flag:"wx",mode:384})}catch{}try{fs.unlinkSync(l)}catch{}try{fs.unlinkSync(sockRetiringPath(l))}catch{}}u(claimSock,"claimSock"),a(claimSock,"claimSock");function sockOwnedByAnother(l,_=process.pid){try{const f=fs.readFileSync(sockOwnerPath(l),"utf8").trim();return!!f&&f!==String(_)}catch{return!1}}u(sockOwnedByAnother,"sockOwnedByAnother"),a(sockOwnedByAnother,"sockOwnedByAnother");function cleanupSock(l,_=process.pid){if(l){try{const f=fs.readFileSync(sockOwnerPath(l),"utf8").trim();if(f&&f!==String(_))return}catch{}try{fs.unlinkSync(l)}catch{}try{fs.unlinkSync(sockOwnerPath(l))}catch{}try{fs.unlinkSync(sockRetiringPath(l))}catch{}(0,gc_notice_1.clearGcNotice)(l)}}u(cleanupSock,"cleanupSock"),a(cleanupSock,"cleanupSock");function postRetiringNotice(l,_){if(!(!l||!_)){try{const f=fs.readFileSync(sockOwnerPath(l),"utf8").trim();if(f&&f!==String(_))return}catch{}try{fs.writeFileSync(sockRetiringPath(l),String(_),{flag:"w",mode:384})}catch{}}}u(postRetiringNotice,"postRetiringNotice"),a(postRetiringNotice,"postRetiringNotice");function serviceKeyFingerprint(){const l=process.env.LENSMCP_SERVICE_KEY;if(!l)return;const{createHash:_}=require("node:crypto");return _("sha256").update(l).digest("hex").slice(0,8)}u(serviceKeyFingerprint,"serviceKeyFingerprint"),a(serviceKeyFingerprint,"serviceKeyFingerprint");function rootModuleOf(l){let _;for(const f of l.getModules?.()?.values()??[])typeof f?.metatype!="function"||typeof f.distance!="number"||!Number.isFinite(f.distance)||(!_||f.distance<_.distance)&&(_=f);return _?.metatype}u(rootModuleOf,"rootModuleOf"),a(rootModuleOf,"rootModuleOf");let lastImportedModule;function takeImportedModule(){const l=lastImportedModule;return lastImportedModule=void 0,l}u(takeImportedModule,"takeImportedModule"),a(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 yt=Object.defineProperty;var u=(l,_)=>yt(l,"name",{value:_,configurable:!0});var gt=Object.defineProperty,a=u((l,_)=>gt(l,"name",{value:_,configurable:!0}),"a");Object.defineProperty(exports,"__esModule",{value:!0}),exports.redactInspectorUrls=exports.inspectorPortOf=exports.DEBUG_FIXED_PORTS_ENV=exports.mayDriveThePool=exports.isOwnerOnlyTransport=exports.gatewayManaged=void 0,exports.tell=tell,exports.usesFixedInspectorPorts=usesFixedInspectorPorts,exports.inspectorPortFor=inspectorPortFor;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")),child_process_env_1=require("./child-process-env"),exit_reason_1=require("./exit-reason"),worker_supervisor_1=require("./worker-supervisor"),hot_swap_registries_1=require("./hot-swap-registries"),process_name_1=require("./process-name"),inspector_secret_1=require("./inspector-secret");Object.defineProperty(exports,"inspectorPortOf",{enumerable:!0,get:a(function(){return inspector_secret_1.inspectorPortOf},"get")}),Object.defineProperty(exports,"redactInspectorUrls",{enumerable:!0,get:a(function(){return inspector_secret_1.redactInspectorUrls},"get")});const devserver_transport_1=require("./devserver-transport");Object.defineProperty(exports,"gatewayManaged",{enumerable:!0,get:a(function(){return devserver_transport_1.gatewayManaged},"get")}),Object.defineProperty(exports,"isOwnerOnlyTransport",{enumerable:!0,get:a(function(){return devserver_transport_1.isOwnerOnlyTransport},"get")}),Object.defineProperty(exports,"mayDriveThePool",{enumerable:!0,get:a(function(){return devserver_transport_1.mayDriveThePool},"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"),swap_mode_1=require("./swap-mode"),handoff_retire_1=require("./handoff-retire"),gc_notice_1=require("./gc-notice"),pod_sock_1=require("./pod-sock"),notice_generation_1=require("./notice-generation"),service_build_events_1=require("./service-build-events"),stdio_guard_1=require("./stdio-guard"),bundle_parent_1=require("./bundle-parent"),checkout_cache_1=require("./checkout-cache"),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 l=process.env.GATEWAY_CONFIG;if(!l)return{};try{return JSON.parse(l)}catch{return{}}})();let gatewayMiddleware=null;if(GATEWAY_MIDDLEWARE_PATH)try{const l=require(GATEWAY_MIDDLEWARE_PATH);gatewayMiddleware=typeof l=="function"?l:typeof l.default=="function"?l.default:null,gatewayMiddleware||console.warn(`[gateway] ${GATEWAY_MIDDLEWARE_PATH} does not export a function, gateway disabled`)}catch(l){console.error(`[gateway] Failed to load middleware from ${GATEWAY_MIDDLEWARE_PATH}:`,l)}function applyGatewayMiddleware(l){if(gatewayMiddleware)try{gatewayMiddleware(l,GATEWAY_CONFIG)}catch(_){console.error("[gateway] Middleware error:",_)}}u(applyGatewayMiddleware,"applyGatewayMiddleware"),a(applyGatewayMiddleware,"applyGatewayMiddleware");const GATEWAY_ROUTES=(()=>{try{return JSON.parse(process.env.GATEWAY_ROUTES||"[]")}catch{return[]}})(),GATEWAY_HTTPS=process.env.GATEWAY_HTTPS==="1";function hostMatches(l,_){if(l.startsWith("*.")){const f=l.slice(1);return _.endsWith(f)||_===l.slice(2)}return _===l}u(hostMatches,"hostMatches"),a(hostMatches,"hostMatches");function matchGatewayRoute(l){if(GATEWAY_ROUTES.length===0)return;const _=(l.headers.host||"").split(":")[0],f=l.url||"/";for(const m of GATEWAY_ROUTES)if(!(m.host&&!hostMatches(m.host,_))&&!(m.prefix&&!f.startsWith(m.prefix)))return m}u(matchGatewayRoute,"matchGatewayRoute"),a(matchGatewayRoute,"matchGatewayRoute");const{specs:WORKER_SPECS,problems:WORKER_PROBLEMS}=(0,worker_supervisor_1.parseWorkerSpecs)(process.env.WORKERS),WORKER_NAMES=WORKER_SPECS.map(l=>l.name),LENSMCP_WS_KEY=process.env.LENSMCP_WS_KEY||"",SOCK_NS=process.env.LENSMCP_SOCK_NS||LENSMCP_WS_KEY,SOCK_DIR=SOCK_NS?path.join(os.tmpdir(),SOCK_NS,`${SERVICE_NAME||"lensmcp-cluster"}-devserver`):path.join(os.tmpdir(),`${SERVICE_NAME||"lensmcp-cluster"}-devserver`),SOCKET_ONLY=process.env.LENSMCP_SOCKET_ONLY==="1",POD_GENERATION=(()=>{const l=Number(process.env.LENSMCP_POD_GENERATION);return Number.isFinite(l)&&l>1?Math.floor(l):1})();function childSockPath(l){return path.join(SOCK_DIR,(0,pod_sock_1.podSockName)(l,POD_GENERATION))}u(childSockPath,"childSockPath"),a(childSockPath,"childSockPath");function sockOwnerPath(l){return`${l}.owner`}u(sockOwnerPath,"sockOwnerPath"),a(sockOwnerPath,"sockOwnerPath");function sockRetiringPath(l){return`${l}.retiring`}u(sockRetiringPath,"sockRetiringPath"),a(sockRetiringPath,"sockRetiringPath");function tell(l,_){if(!l.connected||typeof l.send!="function")return!1;try{return l.send(_,()=>{})}catch{return!1}}u(tell,"tell"),a(tell,"tell");function refusePoolCommand(l,_){console.warn(`[devserver] refused ${l.method} ${l.url} on the public port \u2014 under a gateway the pool is driven on the control socket only.`),_.writeHead(404,{"content-type":"application/json"}),_.end(JSON.stringify({error:"not found"}))}u(refusePoolCommand,"refusePoolCommand"),a(refusePoolCommand,"refusePoolCommand"),exports.DEBUG_FIXED_PORTS_ENV="LENSMCP_DEBUG_FIXED_PORTS";function usesFixedInspectorPorts(l=process.env){const _=(l[exports.DEBUG_FIXED_PORTS_ENV]??"").trim().toLowerCase();return _==="1"||_==="true"||_==="yes"||_==="on"}u(usesFixedInspectorPorts,"usesFixedInspectorPorts"),a(usesFixedInspectorPorts,"usesFixedInspectorPorts");function inspectorPortFor(l,_,f=process.env){if(!usesFixedInspectorPorts(f))return 0;const m=Math.trunc(l)+Math.trunc(_);return Number.isInteger(m)&&m>1024&&m<=65535?m:0}u(inspectorPortFor,"inspectorPortFor"),a(inspectorPortFor,"inspectorPortFor");function ensureOwnerOnlyDir(l){try{fs.mkdirSync(l,{recursive:!0,mode:448})}catch{}try{const _=fs.lstatSync(l);_.isDirectory()&&(_.mode&63)!==0&&fs.chmodSync(l,448)}catch{}}u(ensureOwnerOnlyDir,"ensureOwnerOnlyDir"),a(ensureOwnerOnlyDir,"ensureOwnerOnlyDir");function claimSock(l,_=process.pid){ensureOwnerOnlyDir(path.dirname(l));try{const f=sockOwnerPath(l);try{fs.unlinkSync(f)}catch{}fs.writeFileSync(f,String(_),{flag:"wx",mode:384})}catch{}try{fs.unlinkSync(l)}catch{}try{fs.unlinkSync(sockRetiringPath(l))}catch{}}u(claimSock,"claimSock"),a(claimSock,"claimSock");function sockOwnedByAnother(l,_=process.pid){try{const f=fs.readFileSync(sockOwnerPath(l),"utf8").trim();return!!f&&f!==String(_)}catch{return!1}}u(sockOwnedByAnother,"sockOwnedByAnother"),a(sockOwnedByAnother,"sockOwnedByAnother");function cleanupSock(l,_=process.pid){if(l){try{const f=fs.readFileSync(sockOwnerPath(l),"utf8").trim();if(f&&f!==String(_))return}catch{}try{fs.unlinkSync(l)}catch{}try{fs.unlinkSync(sockOwnerPath(l))}catch{}try{fs.unlinkSync(sockRetiringPath(l))}catch{}(0,gc_notice_1.clearGcNotice)(l)}}u(cleanupSock,"cleanupSock"),a(cleanupSock,"cleanupSock");function postRetiringNotice(l,_){if(!(!l||!_)){try{const f=fs.readFileSync(sockOwnerPath(l),"utf8").trim();if(f&&f!==String(_))return}catch{}try{fs.writeFileSync(sockRetiringPath(l),String(_),{flag:"w",mode:384})}catch{}}}u(postRetiringNotice,"postRetiringNotice"),a(postRetiringNotice,"postRetiringNotice");function serviceKeyFingerprint(){const l=process.env.LENSMCP_SERVICE_KEY;if(!l)return;const{createHash:_}=require("node:crypto");return _("sha256").update(l).digest("hex").slice(0,8)}u(serviceKeyFingerprint,"serviceKeyFingerprint"),a(serviceKeyFingerprint,"serviceKeyFingerprint");function rootModuleOf(l){let _;for(const f of l.getModules?.()?.values()??[])typeof f?.metatype!="function"||typeof f.distance!="number"||!Number.isFinite(f.distance)||(!_||f.distance<_.distance)&&(_=f);return _?.metatype}u(rootModuleOf,"rootModuleOf"),a(rootModuleOf,"rootModuleOf");let lastImportedModule;function takeImportedModule(){const l=lastImportedModule;return lastImportedModule=void 0,l}u(takeImportedModule,"takeImportedModule"),a(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
|
|
@@ -12,7 +12,7 @@
|
|
|
12
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}u(importFresh,"importFresh"),a(importFresh,"importFresh");function debounce(l,_){let f=null;return(...m)=>{f&&clearTimeout(f),f=setTimeout(()=>l(...m),_)}}if(u(debounce,"debounce"),a(debounce,"debounce"),process.env.APP_RUNNER==="1"){(0,stdio_guard_1.guardBrokenStdio)();const l=a(f=>{if(!inspector.url())try{inspector.open(f,"127.0.0.1",!1)}catch(W){console.warn(`[child] inspector.open(${f}) failed (port taken by another devserver?) \u2014 falling back to a random port:`,W.message);try{inspector.open(0,"127.0.0.1",!1)}catch{}}const m=inspector.url();m&&tell(process,{type:"inspector-url",url:m})},"openInspector"),_=process.env.CHILD_DEBUG_PORT;if(_!==void 0&&_!==""){const f=Number(_);Number.isInteger(f)&&(f===0||f>1024)&&l(f)}try{require("@lensmcp/node-instrumentation/register")}catch{}(async()=>{let f=null,m=!1,W,re=!1;const Ve=(0,hot_swap_registries_1.registryPruningEnabled)(),he=a((r,c)=>{const p=(0,hot_swap_registries_1.describePrune)(r,c);p&&console.log(p)},"logPrune");let j={app:null,handler:a((r,c)=>{c.statusCode=503,c.end("starting")},"handler"),inflight:0};const fe=(()=>{const r=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return Number.isFinite(r)&&r>=0?r:15*6e4})(),M=a(r=>{const c=globalThis.__lensmcpActiveWork;if(typeof c!="function")return{count:0};try{const p=c(r);return{count:Number(p?.count??0),...p?.oldestStartedAt?{oldestStartedAt:p.oldestStartedAt}:{}}}catch{return{count:0}}},"activeWork"),$e=a(r=>{const c=globalThis.__lensmcpStopWorkIntake;if(typeof c=="function")try{return c(r)}catch{return}},"stopWorkIntake"),_e=a(r=>{const c=globalThis.__lensmcpWorkIntakeReport;if(!(r===void 0||typeof c!="function"))try{return c(r)??void 0}catch{return}},"workIntakeReport"),ke=(()=>{const r=Number(process.env.LENSMCP_SWAP_MAX_DRAINING);return Number.isFinite(r)&&r>=1?Math.floor(r):1})(),F=new Set,Z=(()=>{const r=Number(process.env.LENSMCP_SWAP_EARLY_CLOSE_GRACE_MS);return process.env.LENSMCP_SWAP_EARLY_CLOSE_GRACE_MS!==void 0&&process.env.LENSMCP_SWAP_EARLY_CLOSE_GRACE_MS!==""&&Number.isFinite(r)&&r>=0?r:3e4})(),V=a(r=>{if(!r.abandoned?.size)return 0;const c=Date.now();for(const[p,h]of r.abandoned)(p.writableEnded||c-h>=Z)&&r.abandoned.delete(p);return r.abandoned.size},"abandonedRunning"),oe=a(r=>{let c=0;for(const p of r.open??[])p.headersSent||(c+=1);return{unanswered:c+V(r),streams:Math.max(0,r.inflight-c),work:M(r.workGen).count}},"owedBy"),ne=a((r,c,p=`${c}s`)=>`${r} ${r===1?c:p}`,"plural");async function We(){if(Z<=0)return;const r=Date.now();let c=!1;for(;!(F.size<ke);){const p=F.values().next().value;if(!p||p.closed)break;const h=oe(p);if(h.unanswered===0&&h.work===0)break;const E=(p.drainingSince??r)+Z-Date.now();if(E<=0)break;c||(c=!0,console.log(`[child] swap held \u2014 the app replaced ${Math.round((Date.now()-(p.drainingSince??r))/100)/10}s ago is still `+[h.unanswered?`answering ${ne(h.unanswered,"request")}`:"",h.work?`running ${ne(h.work,"background job")}`:""].filter(Boolean).join(" and ")+`, and this pod keeps at most ${ke} replaced app(s) alive (LENSMCP_SWAP_MAX_DRAINING). The new build is applied when it is done \u2014 in ${Math.ceil(E/1e3)}s at the latest (LENSMCP_SWAP_EARLY_CLOSE_GRACE_MS).`)),await new Promise(S=>{setTimeout(S,Math.min(100,E)).unref?.()})}c&&console.log(`[child] swap resumed after ${Date.now()-r}ms`)}u(We,"He"),a(We,"holdForOwedWork");const O=(0,swap_recycle_1.swapRecyclePolicy)();let ge,se=0;const Je=(()=>{const r=Number(process.env.LENSMCP_POD_RETIRE_NOTICE_MS);return Number.isFinite(r)&&r>=0?r:3500})();let g=!1,b=!1;const v=(0,pod_memory_1.podMemoryPolicy)();let K=0;const x=new Set;let we=!1;const B=a(()=>{if(!we)return;let r=0;for(const c of x)c.deref()===void 0?x.delete(c):r+=1;return r},"liveContainers"),k=(0,pod_memory_1.createPodMemoryMonitor)({policy:v,state:a(()=>({gen:j.gen??0,swaps:se,...ge===void 0?{}:{baseline:ge},busy:m||re||J.size>0,lastBusyAt:D}),"state"),send:a(r=>{tell(process,r)},"send"),containers:B,counter:(0,pod_memory_1.createLiveObjectCounter)(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH)),onRetained:a(()=>Te(),"onRetained"),gc:a(()=>(0,gc_notice_1.withGcNotice)(I,pod_memory_1.fullGc),"gc")}),H=a(()=>((0,gc_notice_1.withGcNotice)(I,pod_memory_1.fullGc)&&k.tracker.noteGc(),process.memoryUsage().heapUsed),"liveHeap"),U=(()=>{if(!(0,error_stack_release_1.errorFrameReleaseEnabled)())return null;try{const r=path.dirname(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH))+path.sep,c=`${path.sep}node_modules${path.sep}`,p=new Set(Object.keys(require.cache));return(0,error_stack_release_1.createErrorFrameReleaser)(require.cache,{skip:a(h=>p.has(h)||h.startsWith(r)&&!h.slice(r.length).includes(c)&&!h.slice(r.length).startsWith(`node_modules${path.sep}`),"skip")})}catch{return null}})();let ie=!1;function Oe(){if(!(!U||ie))try{const r=U();r.errors>0&&console.log(`[child] read the stack of ${r.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(r){console.error("[child] could not release library error frames:",r),ie=!0}}u(Oe,"De"),a(Oe,"releaseLibraryErrorFrames");const J=new Map;let D=Date.now();const Fe=a(()=>O.settleMs<=0||!m&&!re&&J.size===0&&Date.now()-D>=O.settleMs,"settled");let Y;function ae(r){if(!(!O.enabled||g||b)){if(O.settleMs<=0){X(r);return}Y&&clearTimeout(Y),Y=setTimeout(()=>{Y=void 0,Fe()?X(r):ae(r)},O.settleMs),Y.unref?.()}}u(ae,"ue"),a(ae,"recycleCheckWhenSettled");const be=a(()=>{if(O.stuckCloseMs<=0)return 0;const r=Date.now();let c=0;for(const p of J.values())r-p>=O.stuckCloseMs&&(c+=1);return c},"stuckCloses");function X(r){if(!O.enabled||g||b||!process.send)return;const c=v8.getHeapStatistics().heap_size_limit,p=a(E=>{const S=k.oldestRetained();return{swaps:se,usedBytes:E,limitBytes:c,stuckCloses:be(),settled:Fe(),...ge===void 0?{}:{baselineBytes:ge},...S?{retained:{generation:S.gen,ageMs:Date.now()-S.closedAt,gcs:S.gcs}}:{}}},"state");if(!(0,swap_recycle_1.recycleReason)(O,p(process.memoryUsage().heapUsed)))return;const h=(0,swap_recycle_1.recycleReason)(O,p(H()));h&&(g=!0,console.log(`[child] asking for a fresh pod ${r} \u2014 ${h}. 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:h}))}u(X,"Q"),a(X,"considerRecycle");let me;function Te(){if(!O.enabled||O.retainedMs<=0||g||b)return;const r=k.oldestRetained();if(!r)return;const c=r.closedAt+O.retainedMs-Date.now();if(c<=0){X("with a closed generation still in memory");return}me||(me=setTimeout(()=>{me=void 0,k.measure("retention-check").catch(()=>{})},c),me.unref?.())}u(Te,"je"),a(Te,"retainedRecycleCheck");function ye(r,c){const p={};c&&(p.module=c),r&&(p.app=r);try{const h=r?.app;if(h&&typeof h=="object"&&(p.nestApp=h,h.container&&typeof h.container=="object")){p.container=h.container;const E=rootModuleOf(h.container);E&&(p.rootModule=E)}}catch{}return p}u(ye,"Ne"),a(ye,"generationTargets");async function ce(r,c){if(r.closed||(r.closed=!0,F.delete(r),c&&console.error(`[child] ${c}`),!r.app))return;J.set(r,Date.now());const p=O.enabled&&O.stuckCloseMs>0?setTimeout(()=>{J.has(r)&&(console.error(`[child] a previous app has been closing for ${Math.round(O.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.`),X("with a previous app stuck in close()"))},O.stuckCloseMs):void 0;p?.unref?.();const h=r.app;try{await r.app.close()}catch(E){console.error("[child] error closing a previous app:",E)}finally{J.delete(r),D=Date.now(),p&&clearTimeout(p),r.app=null,r.abandoned=void 0,r.handler=(E,S)=>{S.statusCode=503,S.end("closed")},r.gen!==void 0&&k.closed(r.gen,se,ye(h,r.module)),r.module=void 0}if(r.superseded){try{he((0,hot_swap_registries_1.pruneRegistries)(r.superseded,"serve"),"after closing the previous app")}catch(E){console.error("[child] could not release the previous app's class registrations:",E)}r.superseded=void 0}ae("after closing the previous app")}u(ce,"me"),a(ce,"closeGeneration");async function le(r){const c=Date.now();r.drainingSince=c;const p=a(()=>({inflight:r.inflight+V(r),work:M(r.workGen).count}),"busy"),h=p();if(h.inflight>0||h.work>0){for(;F.size>=ke;){const C=F.values().next().value;if(!C)break;const N=oe(C),z=Math.round((Date.now()-(C.drainingSince??c))/1e3);if(N.unanswered===0&&N.streams===0&&N.work===0){await ce(C);continue}await ce(C,`closing a still-draining generation early \u2014 ${F.size} were pending and the cap is ${ke} (each holds a whole app: DI container, DB pool, queue workers). `+(N.unanswered>0||N.work>0?`It was replaced ${z}s ago and had still not answered ${ne(N.unanswered,"request")}`+(N.work?` or finished ${ne(N.work,"background job")}`:"")+` \u2014 those fail now (a queue job keeps its lock until the TTL lapses). Raise LENSMCP_SWAP_EARLY_CLOSE_GRACE_MS (currently ${Z}ms) to wait longer for them. `:`It held only ${ne(N.streams,"open stream")}; their clients reconnect to the new app. `)+"Raise LENSMCP_SWAP_MAX_DRAINING if this pod legitimately needs more.")}F.add(r)}for(;fe>0&&Date.now()-c<fe;){if(r.closed)return;const C=p();if(C.inflight===0&&C.work===0)break;await new Promise(N=>{setTimeout(N,250).unref?.()})}if(r.closed)return;const E=p(),S=_e(r.workGen);E.inflight>0||E.work>0?console.error(`[child] swap drain expired after ${Date.now()-c}ms \u2014 closing the previous app with ${E.inflight} in-flight request(s) and ${E.work} background job(s) still running. `+(S?`Previous app still processing ${S.running} queue job(s); ${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 ${fe}ms) if this is legitimate work.`):(Date.now()-c>250||S?.runningAtStop||S?.takenAfterStop)&&console.log(`[child] previous app drained in ${Date.now()-c}ms \u2014 closing it`+(S?` (it finished ${S.finishedAfterStop} queue job(s) after the swap; ${S.takenAfterStop} were taken after the swap)`:"")),await ce(r)}u(le,"ye"),a(le,"drainThenClose");async function de(){if(m)return re=!0,console.log("[child] Reload deferred \u2014 will re-swap after current swap completes"),f;m=!0,D=Date.now(),await We(),process.removeAllListeners("uncaughtException"),process.removeAllListeners("unhandledRejection"),process.on("uncaughtException",(P,ee)=>{console.error(`[child] uncaughtException (${ee}):`,P)}),process.on("unhandledRejection",P=>{const ee=P instanceof Error?P.stack||P.message:String(P);ee.includes("FronteggContextScope")||ee.includes("populateLoggerMetadata")||console.error("[child] unhandledRejection:",P)});let r;if(Ve)try{r=(0,hot_swap_registries_1.captureRegistries)()}catch{r=void 0}const c=global.__lensmcpBeginWorkGeneration,p=typeof c=="function"?c():void 0;try{try{await importFresh(BUNDLE_PATH)}catch(P){if(!(P instanceof SyntaxError))throw P;console.warn(`[child] bundle was unreadable mid-write (${P.message}) \u2014 retrying the swap once`),await new Promise(ee=>setTimeout(ee,400)),await importFresh(BUNDLE_PATH)}}catch(P){throw m=!1,D=Date.now(),P}if(typeof global.createChildApp!="function")throw m=!1,D=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 h;if(r)try{h=(0,hot_swap_registries_1.supersededSince)(r),he((0,hot_swap_registries_1.pruneRegistries)(h,"build"),"at the swap")}catch(P){console.error("[child] could not release superseded class registrations:",P)}let E;try{E=await global.createChildApp()}catch(P){throw m=!1,D=Date.now(),takeImportedModule(),P}const S=j;h?.size&&(S.app?S.superseded=h:he((0,hot_swap_registries_1.pruneRegistries)(h,"serve"),"at the swap")),f=E;const C=takeImportedModule();j={app:E,handler:E.handler,inflight:0,gen:++K,...C?{module:C}:{},...p===void 0?{}:{workGen:p}};const N=ye(E,void 0).container;N&&(x.add(new WeakRef(N)),we=!0);const z=S.app&&p!==void 0?$e(p):void 0;return console.log("[child] Swapped to fresh app (previous draining in background)"+(z?.workers?`; its ${z.workers} queue worker(s) stopped taking new jobs, previous app still processing ${z.runningAtStop} job(s)`:"")),Oe(),S.app&&(se+=1,le(S).catch(P=>console.error("[child] background close error:",P)),setTimeout(()=>X("30s after a hot swap"),3e4).unref?.(),k.swapped(S.gen,()=>S.closed===!0&&!J.has(S))),m=!1,D=Date.now(),re?(re=!1,de()):E}u(de,"Ee"),a(de,"swapNow");const Pe=debounce(async()=>{try{console.log("[child] /webpack/reload"),await de()}catch(r){console.error("[child] reload failed:",r)}},250),Ee=http.createServer((r,c)=>{if(r.method==="POST"&&r.url==="/webpack/reload"){c.writeHead(200,{"content-type":"application/json"}),c.end(JSON.stringify({ok:!0})),Pe();return}if(r.method==="GET"&&r.url==="/__lensmcp/alive"){const h=r.headers["x-internal-token"],E=process.env.LENSMCP_SERVICE_KEY;if(E&&h!==E){c.writeHead(404,{"content-type":"text/plain"}),c.end("not found");return}const S=M();c.writeHead(200,{"content-type":"application/json","cache-control":"no-store"}),c.end(JSON.stringify({ok:!0,pid:process.pid,swapping:m,inflight:j.inflight,oldestInflightAt:j.oldestAt,activeWork:S.count,oldestWorkAt:S.oldestStartedAt,keyFingerprint:serviceKeyFingerprint(),...W?{watcher:W}:{},...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.open??=new Set).add(c),p.oldestAt===void 0&&(p.oldestAt=Date.now()),c.on("close",()=>{p.inflight-=1,p.open?.delete(c),Z>0&&!p.closed&&!c.headersSent&&!c.writableEnded&&((p.abandoned??=new Map).set(c,Date.now()),p.abandoned.size>256&&V(p)),p.inflight===0&&(p.oldestAt=void 0),k.activity()}),p.handler(r,c)});Ee.keepAliveTimeout=0;const I=process.env.CHILD_SOCK_PATH;process.on("disconnect",()=>{cleanupSock(I),process.exit(0)});try{const r=path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH);if((0,schema_first_instance_1.schemaPrewarmEnabled)())try{const c=(0,schema_first_instance_1.prewarmZodFor)(r);c?.created&&console.log(`[child] zod${c.version?` ${c.version}`:""}: built ${c.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 c=(0,redis_disconnect_fix_1.finishStrandedDisconnectsFor)(r);c?.patched&&console.log(`[child] ioredis${c.versions.length?` ${c.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 de(),ge=(await k.booted()).live,console.log(`[child] Using bundle: ${r}`),claimSock(I),Ee.listen(I,()=>{console.log(`[child] Listening on ${I}`),tell(process,{type:"ready",socketPath:I})})}catch(r){console.error("[child] Startup error:",r),tell(process,{type:"boot-error",error:String(r?.stack||r)}),process.exitCode=1;return}process.on("message",async r=>{if(!(!r||typeof r!="object")){if(r.type==="debug-open"){const c=Number(r.port);l(Number.isInteger(c)&&c>1024?c:0);return}if(r.type==="watcher"){const c=r.testimony;c&&typeof c=="object"&&(W=c);return}if(r.type==="heap-snapshot"){Me(r);return}if(r.type==="recycle-declined"){g=!1;return}if(r.type==="retire"){q();return}if(r.type==="reload"){if(b)return;try{const c=Date.now();await de(),tell(process,{type:"reloaded",socketPath:I,swap:{generation:K,swaps:se,swapMs:Date.now()-c,draining:F.size}})}catch(c){console.error("[child] reload error:",c),tell(process,{type:"reload-error",error:String(c?.stack||c)})}}}});let Se=!1;async function Me(r){const c=a(p=>{tell(process,{type:"heap-snapshot-result",id:r.id,...p})},"reply");if(Se)return c({ok:!1,refused:"a snapshot of this pod is already being written"});Se=!0;try{const p=H(),h=k.tracker.views().map(N=>N.gen),E=(0,heap_snapshot_1.heapSnapshotPolicy)();r.maxHeapBytes&&(E.maxHeapBytes=r.maxHeapBytes);const S=(0,heap_snapshot_1.heapSnapshotRefusal)(E,{live:p,...r.available?{available:r.available}:{}});if(S)return c({ok:!1,refused:S,live:p});console.log(`[child] writing a heap snapshot (${Math.round(p/1048576)} MB live) \u2014 the pod pauses while V8 serialises it`);const C=await(0,heap_snapshot_1.writeHeapSnapshot)(r.file);c({ok:!0,file:r.file,bytes:C.bytes,ms:C.ms,live:p,gen:j.gen??0,closedAlive:h})}catch(p){c({ok:!1,error:p?.message??String(p)})}finally{Se=!1}}u(Me,"Ye"),a(Me,"takeHeapSnapshot");async function q(r="a fresh pod has taken over"){if(b)return;b=!0,k.stop(),console.log(`[child] retiring \u2014 ${r}; ${path.basename(I,".sock")} (pid ${process.pid}) is finishing in-flight work, then exiting`);const c=$e(Number.POSITIVE_INFINITY);c?.workers&&console.log(`[child] its ${c.workers} queue worker(s) stopped taking new jobs, still processing ${c.runningAtStop} job(s)`);try{fs.writeFileSync(sockRetiringPath(I),String(process.pid),{flag:"w",mode:384})}catch{}await new Promise(h=>{setTimeout(h,Je).unref?.()}),cleanupSock(I),Ee.close();const p=Date.now();for(;Date.now()-p<fe;){Ee.closeIdleConnections?.();let h=0;for(const E of F)h+=oe(E).unanswered;if(j.inflight+V(j)===0&&h===0&&M().count===0)break;await new Promise(E=>{setTimeout(E,250).unref?.()})}setTimeout(()=>process.exit(0),3e4).unref?.();try{await f?.close()}catch(h){console.error("[child] close error while retiring:",h)}process.exit(0)}u(q,"B"),a(q,"retire"),process.on("beforeExit",()=>{try{inspector?.close?.()}catch{}});const pe=a(async r=>{console.log(`[child ${r}] shutting down\u2026`);const c=f?.close().catch(h=>console.error("[child] close error:",h)),p=new Promise(h=>Ee.close(()=>h()));cleanupSock(I),setTimeout(()=>process.exit(0),700).unref(),await Promise.all([c,p]),process.exit(0)},"shutdown");["SIGINT","SIGTERM","SIGHUP","SIGQUIT","SIGUSR2"].forEach(r=>{process.on(r,()=>{if(r==="SIGTERM"&&!b&&(0,handoff_retire_1.handoffRetireRequested)(SOCK_DIR,POD_GENERATION)){q("this generation was handed over to a newer one");return}inspector?.close?.(),pe(r)})})})()}else{let l=u(function(g){V.push(g),V.length>Z&&V.splice(0,V.length-Z),ke?.write((0,inspector_secret_1.redactInspectorUrls)(g.replace(F,"")));for(const b of oe)try{const v=b.plain?g.replace(F,""):g;b.res.write(b.redact?(0,inspector_secret_1.redactInspectorUrls)(v):v)}catch{oe.delete(b)}},"we");a(l,"emitLogLine");const _=12,f=process.env.LENSMCP_PROJECT||SERVICE_NAME||"service",m=(0,pod_memory_events_1.createPodMemoryPublisher)(process.env.LENSMCP_EVENT_FILE),W=a(g=>({project:f,service:SERVICE_NAME||f,pod:g.id,pid:g.proc.pid??0,podGeneration:POD_GENERATION}),"podIdentity"),re=["\x1B[36m","\x1B[33m","\x1B[35m","\x1B[32m","\x1B[34m","\x1B[31m"],Ve="\x1B[0m",he=Math.max(1,Number(process.env.CHILD_COUNT||1)),j=LENSMCP_WS_KEY||path.basename(process.cwd()),fe=a(g=>(0,process_name_1.namedExecPath)((0,process_name_1.processName)(j,SERVICE_NAME||"service",g)),"execPathFor");let M=(()=>{const g=Number(process.env.LENSMCP_DEBUG_PORT||"");return Number.isInteger(g)&&g>1024?g:0})();const $e=20;M&&(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 (${M}+slot, workers ${M}+${$e}+i). Any account on this host can connect to 127.0.0.1:${M} 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 _e=process.env.LENSMCP_LOG_FILE||"",ke=_e?(()=>{try{fs.mkdirSync(path.dirname(_e),{recursive:!0});const g=fs.createWriteStream(_e,{flags:"a",mode:384});try{fs.chmodSync(_e,384)}catch{}return g}catch(g){return console.warn(`[parent] cannot open log file ${_e}:`,g.message),null}})():null,F=/\x1b\[[0-9;]*m/g,Z=2e3,V=[],oe=new Set,ne=(0,devserver_transport_1.gatewayManaged)();for(const g of["log","info","warn","error"]){const b=console[g].bind(console),v=g==="log"||g==="info"?process.stdout:process.stderr;console[g]=(...K)=>{b(...K.map(x=>typeof x=="string"?(0,inspector_secret_1.forStream)(v,ne,x):x)),l(K.map(x=>typeof x=="string"?x:util.inspect(x)).join(" ")+`
|
|
13
13
|
`)}}const We=a(g=>re[(g-1)%re.length],"colorFor"),O=a(g=>{if(he===1)return"";const b=`[child#${g}] `;return`${We(g)}${b}${Ve}`},"tagFor"),ge=a(g=>g.startsWith("{")&&g.endsWith("}"),"isJsonLog"),se=a((g,b,v)=>{const K=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:a(B=>`
|
|
14
14
|
`+String(B),"stack")}}),x=a((B,k)=>{const H=B==="stdout"?process.stdout:process.stderr;try{v?.(k)}catch{}const U=ge(k)?K(k):`${k}
|
|
15
|
-
`;H.write((0,inspector_secret_1.forStream)(H,ne,`${b}${U}`)),l(`${b}${U}`)},"write"),we=a((B,k)=>{if(!B)return;const H=readline.createInterface({input:B});H.on("line",U=>x(k,U)),H.on("close",()=>{})},"attach");we(g.stdout,"stdout"),we(g.stderr,"stderr")},"wireProcLogging"),Je=a(g=>se(g.proc,O(g.id),b=>g.tail.push(b)),"wireChildLogging");(async()=>{ensureOwnerOnlyDir(SOCK_DIR);const g=httpProxy.createProxyServer({});let b=Number(process.env.PORT)||0;b||(b=9090);const v=[],K=new Set;function x(){let e=0;for(;K.has(e);)e++;return K.add(e),e}u(x,"D"),a(x,"allocDebugSlot");let we=1,B=0,k=!1,H=he,U=[],ie=0;const Oe=(0,swap_mode_1.swapMode)(),J=(()=>{const e=Number(process.env.LENSMCP_POD_BOOT_GRACE_MS);return Number.isFinite(e)&&e>=0?e:12e4})(),D=a(e=>e.proc.exitCode!==null||e.proc.signalCode!==null,"childExited"),Fe=a(e=>e.booting&&!D(e)&&Date.now()-e.spawnedAt<J,"stillBooting");function Y(){return v.filter(e=>e.healthy&&typeof e.socketPath=="string")}u(Y,"J"),a(Y,"healthyChildren");let ae,be=0,X;const me={project:f,service:SERVICE_NAME||f,podGeneration:POD_GENERATION};function Te(e){const t=(0,service_build_events_1.buildAccountOf)(e.building);t&&t.startedAt!==be&&(be=t.startedAt,m.publish((0,service_build_events_1.buildServiceBuildEvent)(me,"started",t,{root:process.cwd()})));const n=(0,service_build_events_1.buildAccountOf)(e.failed);n&&(be=0,m.publish((0,service_build_events_1.buildServiceBuildEvent)(me,"failed",n,{root:process.cwd()})))}u(Te,"je"),a(Te,"recordBuildProgress");function ye(e){if(!e||typeof e!="object")return;const t=e;if(t.schemaVersion===1){Te(t),"failed"in t&&delete t.failed,ae=t;for(const n of v)tell(n.proc,{type:"watcher",testimony:t})}}u(ye,"Ne"),a(ye,"recordWatcherTestimony");function ce(e,t=256*1024){return new Promise(n=>{let i="",s=!1;e.on("data",o=>{s||(i+=o,i.length>t&&(s=!0))}),e.on("end",()=>{if(s||!i)return n(void 0);try{n(JSON.parse(i))}catch{n(void 0)}}),e.on("error",()=>n(void 0))})}u(ce,"me"),a(ce,"readJsonBody");function le(){const e=Y();if(e.length===0)return null;const t=B%e.length;return B=(B+1)%e.length,e[t]}u(le,"ye"),a(le,"pickChild");function de(e,t){const n=`Child#${e.id}`,i=SERVICE_NAME||f,s=Date.now();if(t.type==="pod-memory"){const o=t.report;if(!o||typeof o.live!="number")return;e.memory.latest=o,e.memory.history.push(o),e.memory.history.length>12&&e.memory.history.splice(0,e.memory.history.length-12),console.log(`[parent] ${(0,pod_memory_1.describePodMemory)(n,o)}`),m.publish((0,pod_memory_events_1.buildPodMemoryEvent)(W(e),o))}else if(t.type==="pod-memory-retained"){const o=t.retained;if(!o||typeof o.gen!="number")return;e.memory.retained.set(o.gen,{...o,at:s}),console.warn(`[parent] ${(0,pod_memory_1.describeRetained)(n,i,o)}`),m.publish((0,pod_memory_events_1.buildPodRetainedEvent)(W(e),o,s))}else{const o=t.released;if(!o||typeof o.gen!="number")return;e.memory.retained.delete(o.gen),console.log(`[parent] ${(0,pod_memory_1.describeReleased)(n,i,o)}`),m.publish((0,pod_memory_events_1.buildPodReleasedEvent)(W(e),o,s))}}u(de,"Ee"),a(de,"recordPodMemory");const Pe=new Map;let Ee=0;async function I(){const e=we++,t=childSockPath(e);cleanupSock(t);const n=(0,dev_devtool_1.sourceMapExecArgv)();__filename.endsWith(".ts")&&n.unshift("--require","@swc-node/register"),n.push(...(0,inspector_secret_1.inspectorPublishExecArgv)(usesFixedInspectorPorts()));const i=M?x():-1,s=(0,node_child_process_1.fork)(__filename,{env:{...process.env,APP_RUNNER:"1",CHILD_SOCK_PATH:t,...i>=0&&{CHILD_DEBUG_PORT:String(inspectorPortFor(M,i))}},stdio:["inherit","pipe","pipe","ipc"],execArgv:n,execPath:fe("pod")}),o={id:e,proc:s,healthy:!1,lastError:null,debugSlot:i,tail:new exit_reason_1.TailBuffer,booting:!0,spawnedAt:Date.now(),bootReloadSeq:ie,memory:{history:[],retained:new Map}};return s.on("error",y=>console.error(`[parent] Child#${e}: ${y.message}`)),s.on("message",y=>{if(!y||typeof y!="object")return;const d=y;if(d.type==="ready")o.socketPath=String(d.socketPath),o.healthy=!0,o.booting=!1,console.log(`[parent] Child#${o.id} ready on socket ${o.socketPath}`),ae&&tell(s,{type:"watcher",testimony:ae}),ie!==o.bootReloadSeq&&(Oe==="process"?P():tell(s,{type:"reload"}));else if(d.type==="recycle-request")S(o,String(d.reason||"it has outgrown its bound"));else if(d.type==="inspector-url")o.inspectorUrl=String(d.url),console.log(`[parent] Child#${o.id} Debugger listening on ${d.url}`);else if(d.type==="reloaded"){if(q.has(o)){console.log(`[parent] Child#${o.id} finished a swap it began before it was retired \u2014 not serving it: a fresh pod has taken over`);return}o.socketPath=String(d.socketPath),o.healthy=!0,console.log(`[parent] Child#${o.id} hot-swapped on socket ${o.socketPath}`);const w=d.swap;w&&typeof w.generation=="number"&&typeof w.swaps=="number"&&m.publish((0,service_build_events_1.buildServiceSwapEvent)(W(o),{generation:w.generation,swaps:w.swaps,swapMs:typeof w.swapMs=="number"?w.swapMs:0,draining:typeof w.draining=="number"?w.draining:0},X,{root:process.cwd()}))}else d.type==="reload-error"?(o.lastError=String(d.error||"unknown reload error"),console.error(`[parent] Child#${o.id} reload error: ${o.lastError}`),o.healthy=!1):d.type==="boot-error"?(o.lastError=String(d.error||"unknown boot error"),console.error(`[parent] Child#${o.id} boot error: ${o.lastError}`),o.healthy=!1,o.booting=!1):d.type==="pod-memory"||d.type==="pod-memory-retained"||d.type==="pod-memory-released"?de(o,d):d.type==="heap-snapshot-result"&&Pe.get(Number(d.id))?.(d)}),s.on("exit",(y,d)=>{o.booting=!1;for(const A of o.memory.retained.values()){const T={gen:A.gen,closedAt:A.closedAt,ageMs:Date.now()-A.closedAt,reason:"pod-exited"};console.log(`[parent] ${(0,pod_memory_1.describeReleased)(`Child#${o.id}`,SERVICE_NAME||f,T)}`),m.publish((0,pod_memory_events_1.buildPodReleasedEvent)(W(o),T,Date.now()))}o.memory.retained.clear(),o.memory.latest&&m.publish((0,pod_memory_events_1.buildPodExitedEvent)(W(o),{code:y,signal:d},Date.now())),o.debugSlot>=0&&(K.delete(o.debugSlot),o.debugSlot=-1);const w=d==="SIGINT"||d==="SIGTERM"||y===0;if(w?console.log(`[parent] Child#${o.id} exited cleanly (code=${y}, signal=${d??"none"})`):(console.error((0,exit_reason_1.crashReport)(`[parent] Child#${o.id} crashed (code=${y}, signal=${d??"none"}, pid=${o.proc.pid}, ${o.healthy?"was serving":"was not ready"})`,y,d,o.tail.snapshot())),o.lastError||(o.lastError=`Child exited abnormally (code=${y}, signal=${d??"none"})`)),o.healthy=!1,cleanupSock(o.socketPath,o.proc.pid),o.socketPath=void 0,!w&&!k){const A=v.indexOf(o);A>=0&&v.splice(A,1);const T=Date.now();if(U=U.filter($=>T-$<3e4),U.length>=5){console.error(`[parent] crash-loop detected (${U.length} respawns/30s) \u2014 pausing auto-respawn; POST /webpack/reload to retry`);return}U.push(T),setTimeout(()=>{const $=v.filter(Q=>Q.proc.killed===!1).length;!k&&$<H&&(console.log(`[parent] respawning a crashed pod (${$}/${H} live)`),I().catch(()=>{}))},1500).unref?.()}}),v.push(o),Je(o),o}u(I,"C"),a(I,"spawnChild");async function Se(e){H=Math.max(H,e);const t=v.filter(i=>i.proc.killed===!1),n=e-t.length;for(let i=0;i<n;i++)await I()}u(Se,"be"),a(Se,"ensurePoolSize");async function Me(){const e=v.filter(t=>(!t.healthy||typeof t.socketPath!="string")&&!Fe(t));await Promise.all(e.map(async t=>{try{t.proc.kill("SIGTERM")}catch{}cleanupSock(t.socketPath,t.proc.pid),t.socketPath=void 0;const n=v.indexOf(t);n>=0&&v.splice(n,1),await I()}))}u(Me,"Ye"),a(Me,"respawnUnhealthy");const q=new Set;let pe=!1,r=0;const c=3e4,p=(()=>{const e=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return(Number.isFinite(e)&&e>=0?e:15*6e4)+6e4})();async function h(e,t={}){const n=Date.now(),i=await I(),s=Date.now()+J;for(;!i.healthy&&!i.lastError&&!D(i)&&Date.now()<s;){if(t.superseded?.()){const o=v.indexOf(i);o>=0&&v.splice(o,1);try{i.proc.kill("SIGTERM")}catch{}return{why:`a newer build landed while Child#${i.id} booted`,superseded:!0}}await new Promise(o=>{setTimeout(o,100).unref?.()})}if(k)return{why:"shutting down"};if(!i.healthy){const o=v.indexOf(i);o>=0&&v.splice(o,1);try{i.proc.kill("SIGTERM")}catch{}return{why:`its successor Child#${i.id} did not come up (${i.lastError??"no answer in time"})`}}return E(e),{fresh:i,readyMs:Date.now()-n}}u(h,"_"),a(h,"replacePod");function E(e){const t=v.indexOf(e);if(t>=0&&v.splice(t,1),e.healthy=!1,D(e))return;q.add(e),postRetiringNotice(e.socketPath,e.proc.pid);const n=setTimeout(()=>{if(!D(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(n.unref?.(),e.proc.once("exit",()=>{clearTimeout(n),q.delete(e)}),!tell(e.proc,{type:"retire"}))try{e.proc.kill("SIGTERM")}catch{}}u(E,"m"),a(E,"retirePod");async function S(e,t){const n=a(s=>{console.log(`[parent] Child#${e.id} asked for a fresh pod (${t}) \u2014 not now: ${s}`),tell(e.proc,{type:"recycle-declined"})},"decline");if(k||!v.includes(e))return;if(pe)return n("another pod is already being replaced");const i=Date.now()-r;if(i<c)return n(`a pod was replaced ${Math.round(i/1e3)}s ago`);pe=!0,console.log(`[parent] Child#${e.id} asked for a fresh pod \u2014 ${t}. Starting one; Child#${e.id} keeps serving until it is ready.`);try{const s=await h(e);if("why"in s){s.why!=="shutting down"&&n(s.why);return}r=Date.now(),console.log(`[parent] Child#${s.fresh.id} took over from Child#${e.id} (pid ${e.proc.pid} \u2192 ${s.fresh.proc.pid})`)}catch(s){n(`could not start a successor: ${s?.message??String(s)}`)}finally{pe=!1}}u(S,"y"),a(S,"recyclePod");let C,N=!1,z=0;function P(){if(C){N=!0;return}C=(async()=>{do{N=!1;const e=ie;for(;pe&&!k;)await new Promise(n=>{setTimeout(n,100).unref?.()});let t=!1;for(const n of Y().filter(i=>i.bootReloadSeq<e)){if(k)break;if(!(!v.includes(n)||!n.healthy)){pe=!0;try{ee(),console.log(`[parent] A new build \u2014 starting a fresh pod for it; Child#${n.id} keeps serving the previous build until it is ready.`);const i=await h(n,{superseded:a(()=>ie!==e&&(0,swap_mode_1.abandonSuperseded)(z),"superseded")});if("why"in i){if(i.superseded){z+=1,console.log(`[parent] ${i.why} \u2014 abandoned; one fresh pod for the newest build instead (${z} in a row). Child#${n.id} keeps serving.`),t=!0;break}i.why!=="shutting down"&&console.error(`[parent] Child#${n.id} keeps serving the previous build \u2014 ${i.why}`);continue}z=0,console.log(`[parent] Child#${i.fresh.id} took over from Child#${n.id} with the new build (pid ${n.proc.pid} \u2192 ${i.fresh.proc.pid}, ready in ${(i.readyMs/1e3).toFixed(1)}s while Child#${n.id} served)`),m.publish((0,service_build_events_1.buildServiceSwapEvent)(W(i.fresh),{generation:1,swaps:0,swapMs:i.readyMs,draining:q.size,handoff:{fromPid:n.proc.pid??0}},X,{root:process.cwd()}))}catch(i){console.error(`[parent] Child#${n.id} keeps serving the previous build \u2014 could not start a successor: ${i?.message??String(i)}`)}finally{pe=!1}}}t&&(N=!0)}while(N&&!k)})().finally(()=>{C=void 0})}u(P,"A"),a(P,"handoffForReload");function ee(){const e=(0,swap_mode_1.maxRetiring)(),t=[...q].filter(n=>!D(n));for(;t.length>=e;){const n=t.shift();console.error(`[parent] Child#${n.id} (pid ${n.proc.pid}) was still finishing its work when a newer build replaced its successor too \u2014 stopping it (LENSMCP_SWAP_MAX_RETIRING=${e})`);try{n.proc.kill("SIGTERM")}catch{}}}u(ee,"X"),a(ee,"capRetiring");const G=[],He=new Map,Ue=a(e=>{let t=He.get(e);return t||He.set(e,t={crashes:0,restarts:0}),t},"watchOf"),Xe=(0,worker_supervisor_1.workerBackoff)(),Ae=a((e,t)=>({project:f,service:SERVICE_NAME||f,worker:e,pid:t,podGeneration:POD_GENERATION}),"workerWho"),tt=[path.join(__dirname,"worker-guard.js"),path.join(__dirname,"worker-guard.ts")].find(e=>fs.existsSync(e));for(const e of WORKER_PROBLEMS)console.error(`[parent] ${e}`);function ze(e,t){const n=e.name,i=path.dirname(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.resolve(BUNDLE_PATH)),s=path.join(i,`${n}.js`),o=Ue(n);if(!fs.existsSync(s))return console.error(`[parent] Worker "${n}" bundle not found: ${s}`),o.missing=s,m.publish((0,worker_supervisor_1.buildWorkerExitedEvent)(Ae(n,0),{ranMs:0,reason:`its bundle was not built (${path.basename(s)} is not in ${i})`})),null;o.missing=void 0;const y=(0,dev_devtool_1.sourceMapExecArgv)();__filename.endsWith(".ts")&&y.unshift("--require","@swc-node/register"),tt&&y.push("--require",tt);try{y.push("--require",require.resolve("@lensmcp/node-instrumentation/register"))}catch{}const d=inspectorPortFor(M||9229,$e+Math.max(0,WORKER_NAMES.indexOf(n)));y.push(M?`--inspect=127.0.0.1:${d}`:`--inspect-port=127.0.0.1:${d}`,...(0,inspector_secret_1.inspectorPublishExecArgv)(usesFixedInspectorPorts()));const w=(0,node_child_process_1.fork)(s,{env:(0,worker_supervisor_1.workerEnv)(process.env,e),stdio:["inherit","pipe","pipe","ipc"],execArgv:y,execPath:fe(`w-${n}`)}),A={name:n,spec:e,proc:w,debugPort:d,startedAt:Date.now(),tail:new exit_reason_1.TailBuffer,stopping:!1};G.push(A),w.on("error",$=>console.error(`[parent] Worker "${n}": ${$.message}`)),se(w,`\x1B[35m[worker:${n}] \x1B[0m`,$=>{A.tail.push($);const Q=/Debugger listening on (wss?:\/\/\S+)/.exec($);Q&&(A.inspectorUrl=Q[1])});const T=setTimeout(()=>{if(!(Re(A)||A.stopping)){if(o.crashes>0){const $=Date.now()-A.startedAt;console.log(`[parent] Worker "${n}" (pid=${w.pid}) is up again \u2014 ${(0,worker_supervisor_1.spanOf)($)} without a crash, after ${o.crashes} in a row`),m.publish((0,worker_supervisor_1.buildWorkerUpEvent)(Ae(n,w.pid??0),{ranMs:$,afterCrashes:o.crashes}))}o.crashes=0}},Xe.stableMs);return T.unref?.(),w.on("exit",($,Q)=>{clearTimeout(T);const ve=G.indexOf(A);ve>=0&&G.splice(ve,1),rt(A,$,Q)}),console.log(`[parent] Worker "${n}" started (pid=${w.pid}, PORT=${(0,worker_supervisor_1.workerEnv)(process.env,e).PORT}${t==="respawn"?`, restart ${o.restarts}`:""})`),m.publish((0,worker_supervisor_1.buildWorkerStartedEvent)(Ae(n,w.pid??0),{why:t,port:e.port,restarts:o.restarts})),A}u(ze,"Ze"),a(ze,"spawnWorkerProcess");function rt(e,t,n){const{name:i}=e,s=e.proc.pid??0,o=Date.now()-e.startedAt,y=(0,worker_supervisor_1.workerExitVerdict)(t,n,e.stopping||k);if(y.kind==="stopped")return;const d=Ue(i);if(y.kind==="exited"){d.lastEnd={at:Date.now(),pid:s,code:t,signal:n,ranMs:o,verdict:"exited"},console.warn(`[parent] Worker "${i}" (pid=${s}) exited on its own (code 0) after ${(0,worker_supervisor_1.spanOf)(o)} \u2014 not started again until the next build: a worker that ends is taken to have finished its work`),m.publish((0,worker_supervisor_1.buildWorkerExitedEvent)(Ae(i,s),{ranMs:o}));return}d.crashes+=1,d.lastEnd={at:Date.now(),pid:s,code:t,signal:n,ranMs:o,verdict:"crashed"};const w=(0,worker_supervisor_1.respawnDelay)(d.crashes,Xe),A=d.crashes>=worker_supervisor_1.CRASH_LOOP_AFTER;console.error((0,exit_reason_1.crashReport)(`[parent] Worker "${i}" crashed (code=${t}, signal=${n??"none"}, pid=${s}, after ${(0,worker_supervisor_1.spanOf)(o)})${y.external?" \u2014 stopped by a signal from outside its devserver":""}; starting it again in ${(0,worker_supervisor_1.spanOf)(w)}${A?` \u2014 ${d.crashes} crashes in a row: it is crash-looping (the wait doubles, up to ${(0,worker_supervisor_1.spanOf)(Xe.maxMs)})`:""}`,t,n,e.tail.snapshot())),m.publish((0,worker_supervisor_1.buildWorkerCrashedEvent)(Ae(i,s),{code:t,signal:n,ranMs:o,crashes:d.crashes,restarts:d.restarts,nextInMs:w,external:y.external,lines:e.tail.snapshot()})),clearTimeout(d.pending),d.nextAt=Date.now()+w,d.pending=setTimeout(()=>{d.pending=void 0,d.nextAt=void 0,!(k||G.some(T=>T.name===i))&&(d.restarts+=1,qe(e.spec,"respawn"))},w),d.pending.unref?.()}u(rt,"ct"),a(rt,"workerEnded");function qe(e,t){const n=Ue(e.name);n.waiting=void 0;const i=e.port>0?[...te].find(o=>o.name===e.name&&!Re(o)):void 0;if(!i){ze(e,t);return}console.log(`[parent] Worker "${e.name}" starts once its predecessor (pid=${i.proc.pid}) has finished its work \u2014 it holds port ${e.port}`);const s=a(()=>{n.waiting===s&&(n.waiting=void 0),!k&&!G.some(o=>o.name===e.name)&&ze(e,t)},"go");n.waiting=s,i.proc.once("exit",s)}u(qe,"Ve"),a(qe,"startWorker");const ot=(()=>{const e=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return Number.isFinite(e)&&e>=0?e:15*6e4})(),nt=(()=>{const e=Number(process.env.LENSMCP_SWAP_MAX_DRAINING);return Number.isFinite(e)&&e>=1?Math.floor(e):1})(),te=new Set,Re=a(e=>e.proc.exitCode!==null||e.proc.signalCode!==null,"workerExited");function Be(e,t){if(te.delete(e),!Re(e)){console.error(`[parent] Worker "${e.name}" (pid=${e.proc.pid}) ${t} \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{}}}u(Be,"Je"),a(Be,"killDrainingWorker");function Qe(e){e.stopping=!0;try{e.proc.kill("SIGTERM")}catch{}if(Re(e))return;const t=[...te].filter(i=>i.name===e.name);for(;t.length>=nt;)Be(t.shift(),`was still running when a later reload replaced its successor (cap ${nt})`);te.add(e);const n=setTimeout(()=>Be(e,`was still running ${ot}ms after SIGTERM`),ot);n.unref?.(),e.proc.once("exit",()=>{clearTimeout(n),te.delete(e)})}u(Qe,"rt"),a(Qe,"retireWorker");function je(){for(const e of He.values())clearTimeout(e.pending),e.pending=void 0,e.nextAt=void 0,e.waiting=void 0}u(je,"Xe"),a(je,"cancelWorkerStarts");function st(){for(const e of[...G])Qe(e);G.length=0,je();for(const e of WORKER_SPECS)Ue(e.name).crashes=0,qe(e,"reload")}u(st,"lt"),a(st,"restartWorkers");function it(){const e=Date.now();return{workers:WORKER_SPECS.map(t=>{const n=G.find(o=>o.name===t.name),i=He.get(t.name),s=n?"running":i?.pending?(i.crashes??0)>=worker_supervisor_1.CRASH_LOOP_AFTER?"crash-looping":"restarting":i?.waiting?"waiting":i?.missing?"missing":i?.lastEnd?.verdict==="exited"?"exited":"stopped";return{name:t.name,state:s,port:t.port,env:Object.keys(t.env),...n?{pid:n.proc.pid,upMs:e-n.startedAt}:{},crashes:i?.crashes??0,restarts:i?.restarts??0,...i?.nextAt?{nextInMs:Math.max(0,i.nextAt-e)}:{},...i?.lastEnd?{lastEnd:i.lastEnd}:{},...i?.missing?{missing:i.missing}:{}}}),draining:[...te].filter(t=>!Re(t)).map(t=>({name:t.name,pid:t.proc.pid}))}}u(it,"dt"),a(it,"workersView");const ht=debounce(async()=>{ie+=1;const e=Y();if(e.length>0)if(Oe==="process")P();else{console.log(`[parent] Forwarding reload to ${e.length} child(ren)`);for(const t of e)tell(t.proc,{type:"reload"})}await Me(),WORKER_NAMES.length>0&&st()},200),at=a((e,t)=>{const n=(0,notice_generation_1.noticeGeneration)(e.headers);return n===void 0||n===POD_GENERATION?!1:(e.resume(),t.writeHead(409,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!1,generation:POD_GENERATION,sentFor:n})),e.url==="/webpack/reload"&&console.log(`[parent] a build of generation g${n} reached generation g${POD_GENERATION} \u2014 not reloaded: it is not this generation's build`),!0)},"refusedForAnotherGeneration"),Ie=a(async(e,t)=>{if(e.method==="POST"&&e.url==="/webpack/reload"){if(!(0,devserver_transport_1.mayDriveThePool)(e))return refusePoolCommand(e,t);if(at(e,t))return;t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0})),ce(e).then(s=>{const o=s;X=(0,service_build_events_1.buildAccountOf)(o?.build),be=0,ye(o?.watcher)}),ht();return}if(e.method==="POST"&&e.url==="/webpack/watching"){if(!(0,devserver_transport_1.mayDriveThePool)(e))return refusePoolCommand(e,t);if(at(e,t))return;const s=await ce(e);ye(s),t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0,relayed:ae!==void 0}));return}if(e.method==="POST"&&e.url==="/webpack/scale"){if(!(0,devserver_transport_1.mayDriveThePool)(e))return refusePoolCommand(e,t);let s="";e.on("data",o=>{s+=o}),e.on("end",async()=>{let o=0;try{o=Number(JSON.parse(s||"{}").pods)||0}catch{}o=Math.max(1,Math.min(o,16)),await Se(o),t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0,pods:o}))});return}if(e.method==="GET"&&e.url?.startsWith("/webpack/logs")){const s=new URL(e.url,"http://localhost").searchParams,o=Math.min(Math.max(Number(s.get("tail")??"100")||0,0),Z),y=s.get("follow")!=="0",d=s.get("plain")==="1",w=!(0,devserver_transport_1.isOwnerOnlyTransport)(e);t.writeHead(200,{"content-type":"text/plain; charset=utf-8","cache-control":"no-cache"});const A=o===0?"":V.slice(-o).join(""),T=d?A.replace(F,""):A;if(t.write(w?(0,inspector_secret_1.redactInspectorUrls)(T):T),!y){t.end();return}const $={res:t,plain:d,redact:w};oe.add($),e.on("close",()=>oe.delete($));return}if(e.method==="POST"&&e.url?.startsWith("/webpack/debug")){if(!(0,devserver_transport_1.isOwnerOnlyTransport)(e)){t.writeHead(404,{"content-type":"application/json"}),t.end(JSON.stringify({error:"not found"}));return}const s=Number(new URL(e.url,"http://localhost").searchParams.get("port")||"");Number.isInteger(s)&&s>1024&&(M=s),M||(M=9229);const o=v.filter(d=>d.proc.exitCode===null&&d.proc.signalCode===null);for(const d of o)d.debugSlot<0&&(d.debugSlot=x()),tell(d.proc,{type:"debug-open",port:inspectorPortFor(M,d.debugSlot)});for(const d of G)try{d.proc.kill("SIGUSR1")}catch{}const y=Date.now()+2e3;for(;Date.now()<y&&o.some(d=>!d.inspectorUrl);)await new Promise(d=>setTimeout(d,50));t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0,basePort:M,fixedPorts:usesFixedInspectorPorts(),pods:o.map(d=>({id:d.id,inspectorUrl:d.inspectorUrl??null})),workers:G.map(d=>({name:d.name,port:d.debugPort||(0,inspector_secret_1.inspectorPortOf)(d.inspectorUrl),inspectorUrl:d.inspectorUrl??null}))},null,2)+`
|
|
15
|
+
`;H.write((0,inspector_secret_1.forStream)(H,ne,`${b}${U}`)),l(`${b}${U}`)},"write"),we=a((B,k)=>{if(!B)return;const H=readline.createInterface({input:B});H.on("line",U=>x(k,U)),H.on("close",()=>{})},"attach");we(g.stdout,"stdout"),we(g.stderr,"stderr")},"wireProcLogging"),Je=a(g=>se(g.proc,O(g.id),b=>g.tail.push(b)),"wireChildLogging");(async()=>{ensureOwnerOnlyDir(SOCK_DIR);const g=httpProxy.createProxyServer({});let b=Number(process.env.PORT)||0;b||(b=9090);const v=[],K=new Set;function x(){let e=0;for(;K.has(e);)e++;return K.add(e),e}u(x,"D"),a(x,"allocDebugSlot");let we=1,B=0,k=!1,H=he,U=[],ie=0;const Oe=(0,swap_mode_1.swapMode)(),J=(()=>{const e=Number(process.env.LENSMCP_POD_BOOT_GRACE_MS);return Number.isFinite(e)&&e>=0?e:12e4})(),D=a(e=>e.proc.exitCode!==null||e.proc.signalCode!==null,"childExited"),Fe=a(e=>e.booting&&!D(e)&&Date.now()-e.spawnedAt<J,"stillBooting");function Y(){return v.filter(e=>e.healthy&&typeof e.socketPath=="string")}u(Y,"J"),a(Y,"healthyChildren");let ae,be=0,X;const me={project:f,service:SERVICE_NAME||f,podGeneration:POD_GENERATION};function Te(e){const t=(0,service_build_events_1.buildAccountOf)(e.building);t&&t.startedAt!==be&&(be=t.startedAt,m.publish((0,service_build_events_1.buildServiceBuildEvent)(me,"started",t,{root:process.cwd()})));const n=(0,service_build_events_1.buildAccountOf)(e.failed);n&&(be=0,m.publish((0,service_build_events_1.buildServiceBuildEvent)(me,"failed",n,{root:process.cwd()})))}u(Te,"je"),a(Te,"recordBuildProgress");function ye(e){if(!e||typeof e!="object")return;const t=e;if(t.schemaVersion===1){Te(t),"failed"in t&&delete t.failed,ae=t;for(const n of v)tell(n.proc,{type:"watcher",testimony:t})}}u(ye,"Ne"),a(ye,"recordWatcherTestimony");function ce(e,t=256*1024){return new Promise(n=>{let i="",s=!1;e.on("data",o=>{s||(i+=o,i.length>t&&(s=!0))}),e.on("end",()=>{if(s||!i)return n(void 0);try{n(JSON.parse(i))}catch{n(void 0)}}),e.on("error",()=>n(void 0))})}u(ce,"me"),a(ce,"readJsonBody");function le(){const e=Y();if(e.length===0)return null;const t=B%e.length;return B=(B+1)%e.length,e[t]}u(le,"ye"),a(le,"pickChild");function de(e,t){const n=`Child#${e.id}`,i=SERVICE_NAME||f,s=Date.now();if(t.type==="pod-memory"){const o=t.report;if(!o||typeof o.live!="number")return;e.memory.latest=o,e.memory.history.push(o),e.memory.history.length>12&&e.memory.history.splice(0,e.memory.history.length-12),console.log(`[parent] ${(0,pod_memory_1.describePodMemory)(n,o)}`),m.publish((0,pod_memory_events_1.buildPodMemoryEvent)(W(e),o))}else if(t.type==="pod-memory-retained"){const o=t.retained;if(!o||typeof o.gen!="number")return;e.memory.retained.set(o.gen,{...o,at:s}),console.warn(`[parent] ${(0,pod_memory_1.describeRetained)(n,i,o)}`),m.publish((0,pod_memory_events_1.buildPodRetainedEvent)(W(e),o,s))}else{const o=t.released;if(!o||typeof o.gen!="number")return;e.memory.retained.delete(o.gen),console.log(`[parent] ${(0,pod_memory_1.describeReleased)(n,i,o)}`),m.publish((0,pod_memory_events_1.buildPodReleasedEvent)(W(e),o,s))}}u(de,"Ee"),a(de,"recordPodMemory");const Pe=new Map;let Ee=0;async function I(){const e=we++,t=childSockPath(e);cleanupSock(t);const n=(0,dev_devtool_1.sourceMapExecArgv)();__filename.endsWith(".ts")&&n.unshift("--require","@swc-node/register"),n.push(...(0,inspector_secret_1.inspectorPublishExecArgv)(usesFixedInspectorPorts()));const i=M?x():-1,s=(0,node_child_process_1.fork)(__filename,{env:(0,child_process_env_1.childProcessEnv)({...process.env,APP_RUNNER:"1",CHILD_SOCK_PATH:t,...i>=0&&{CHILD_DEBUG_PORT:String(inspectorPortFor(M,i))}}),stdio:["inherit","pipe","pipe","ipc"],execArgv:n,execPath:fe("pod")}),o={id:e,proc:s,healthy:!1,lastError:null,debugSlot:i,tail:new exit_reason_1.TailBuffer,booting:!0,spawnedAt:Date.now(),bootReloadSeq:ie,memory:{history:[],retained:new Map}};return s.on("error",y=>console.error(`[parent] Child#${e}: ${y.message}`)),s.on("message",y=>{if(!y||typeof y!="object")return;const d=y;if(d.type==="ready")o.socketPath=String(d.socketPath),o.healthy=!0,o.booting=!1,console.log(`[parent] Child#${o.id} ready on socket ${o.socketPath}`),ae&&tell(s,{type:"watcher",testimony:ae}),ie!==o.bootReloadSeq&&(Oe==="process"?P():tell(s,{type:"reload"}));else if(d.type==="recycle-request")S(o,String(d.reason||"it has outgrown its bound"));else if(d.type==="inspector-url")o.inspectorUrl=String(d.url),console.log(`[parent] Child#${o.id} Debugger listening on ${d.url}`);else if(d.type==="reloaded"){if(q.has(o)){console.log(`[parent] Child#${o.id} finished a swap it began before it was retired \u2014 not serving it: a fresh pod has taken over`);return}o.socketPath=String(d.socketPath),o.healthy=!0,console.log(`[parent] Child#${o.id} hot-swapped on socket ${o.socketPath}`);const w=d.swap;w&&typeof w.generation=="number"&&typeof w.swaps=="number"&&m.publish((0,service_build_events_1.buildServiceSwapEvent)(W(o),{generation:w.generation,swaps:w.swaps,swapMs:typeof w.swapMs=="number"?w.swapMs:0,draining:typeof w.draining=="number"?w.draining:0},X,{root:process.cwd()}))}else d.type==="reload-error"?(o.lastError=String(d.error||"unknown reload error"),console.error(`[parent] Child#${o.id} reload error: ${o.lastError}`),o.healthy=!1):d.type==="boot-error"?(o.lastError=String(d.error||"unknown boot error"),console.error(`[parent] Child#${o.id} boot error: ${o.lastError}`),o.healthy=!1,o.booting=!1):d.type==="pod-memory"||d.type==="pod-memory-retained"||d.type==="pod-memory-released"?de(o,d):d.type==="heap-snapshot-result"&&Pe.get(Number(d.id))?.(d)}),s.on("exit",(y,d)=>{o.booting=!1;for(const A of o.memory.retained.values()){const T={gen:A.gen,closedAt:A.closedAt,ageMs:Date.now()-A.closedAt,reason:"pod-exited"};console.log(`[parent] ${(0,pod_memory_1.describeReleased)(`Child#${o.id}`,SERVICE_NAME||f,T)}`),m.publish((0,pod_memory_events_1.buildPodReleasedEvent)(W(o),T,Date.now()))}o.memory.retained.clear(),o.memory.latest&&m.publish((0,pod_memory_events_1.buildPodExitedEvent)(W(o),{code:y,signal:d},Date.now())),o.debugSlot>=0&&(K.delete(o.debugSlot),o.debugSlot=-1);const w=d==="SIGINT"||d==="SIGTERM"||y===0;if(w?console.log(`[parent] Child#${o.id} exited cleanly (code=${y}, signal=${d??"none"})`):(console.error((0,exit_reason_1.crashReport)(`[parent] Child#${o.id} crashed (code=${y}, signal=${d??"none"}, pid=${o.proc.pid}, ${o.healthy?"was serving":"was not ready"})`,y,d,o.tail.snapshot())),o.lastError||(o.lastError=`Child exited abnormally (code=${y}, signal=${d??"none"})`)),o.healthy=!1,cleanupSock(o.socketPath,o.proc.pid),o.socketPath=void 0,!w&&!k){const A=v.indexOf(o);A>=0&&v.splice(A,1);const T=Date.now();if(U=U.filter($=>T-$<3e4),U.length>=5){console.error(`[parent] crash-loop detected (${U.length} respawns/30s) \u2014 pausing auto-respawn; POST /webpack/reload to retry`);return}U.push(T),setTimeout(()=>{const $=v.filter(Q=>Q.proc.killed===!1).length;!k&&$<H&&(console.log(`[parent] respawning a crashed pod (${$}/${H} live)`),I().catch(()=>{}))},1500).unref?.()}}),v.push(o),Je(o),o}u(I,"C"),a(I,"spawnChild");async function Se(e){H=Math.max(H,e);const t=v.filter(i=>i.proc.killed===!1),n=e-t.length;for(let i=0;i<n;i++)await I()}u(Se,"be"),a(Se,"ensurePoolSize");async function Me(){const e=v.filter(t=>(!t.healthy||typeof t.socketPath!="string")&&!Fe(t));await Promise.all(e.map(async t=>{try{t.proc.kill("SIGTERM")}catch{}cleanupSock(t.socketPath,t.proc.pid),t.socketPath=void 0;const n=v.indexOf(t);n>=0&&v.splice(n,1),await I()}))}u(Me,"Ye"),a(Me,"respawnUnhealthy");const q=new Set;let pe=!1,r=0;const c=3e4,p=(()=>{const e=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return(Number.isFinite(e)&&e>=0?e:15*6e4)+6e4})();async function h(e,t={}){const n=Date.now(),i=await I(),s=Date.now()+J;for(;!i.healthy&&!i.lastError&&!D(i)&&Date.now()<s;){if(t.superseded?.()){const o=v.indexOf(i);o>=0&&v.splice(o,1);try{i.proc.kill("SIGTERM")}catch{}return{why:`a newer build landed while Child#${i.id} booted`,superseded:!0}}await new Promise(o=>{setTimeout(o,100).unref?.()})}if(k)return{why:"shutting down"};if(!i.healthy){const o=v.indexOf(i);o>=0&&v.splice(o,1);try{i.proc.kill("SIGTERM")}catch{}return{why:`its successor Child#${i.id} did not come up (${i.lastError??"no answer in time"})`}}return E(e),{fresh:i,readyMs:Date.now()-n}}u(h,"_"),a(h,"replacePod");function E(e){const t=v.indexOf(e);if(t>=0&&v.splice(t,1),e.healthy=!1,D(e))return;q.add(e),postRetiringNotice(e.socketPath,e.proc.pid);const n=setTimeout(()=>{if(!D(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(n.unref?.(),e.proc.once("exit",()=>{clearTimeout(n),q.delete(e)}),!tell(e.proc,{type:"retire"}))try{e.proc.kill("SIGTERM")}catch{}}u(E,"m"),a(E,"retirePod");async function S(e,t){const n=a(s=>{console.log(`[parent] Child#${e.id} asked for a fresh pod (${t}) \u2014 not now: ${s}`),tell(e.proc,{type:"recycle-declined"})},"decline");if(k||!v.includes(e))return;if(pe)return n("another pod is already being replaced");const i=Date.now()-r;if(i<c)return n(`a pod was replaced ${Math.round(i/1e3)}s ago`);pe=!0,console.log(`[parent] Child#${e.id} asked for a fresh pod \u2014 ${t}. Starting one; Child#${e.id} keeps serving until it is ready.`);try{const s=await h(e);if("why"in s){s.why!=="shutting down"&&n(s.why);return}r=Date.now(),console.log(`[parent] Child#${s.fresh.id} took over from Child#${e.id} (pid ${e.proc.pid} \u2192 ${s.fresh.proc.pid})`)}catch(s){n(`could not start a successor: ${s?.message??String(s)}`)}finally{pe=!1}}u(S,"y"),a(S,"recyclePod");let C,N=!1,z=0;function P(){if(C){N=!0;return}C=(async()=>{do{N=!1;const e=ie;for(;pe&&!k;)await new Promise(n=>{setTimeout(n,100).unref?.()});let t=!1;for(const n of Y().filter(i=>i.bootReloadSeq<e)){if(k)break;if(!(!v.includes(n)||!n.healthy)){pe=!0;try{ee(),console.log(`[parent] A new build \u2014 starting a fresh pod for it; Child#${n.id} keeps serving the previous build until it is ready.`);const i=await h(n,{superseded:a(()=>ie!==e&&(0,swap_mode_1.abandonSuperseded)(z),"superseded")});if("why"in i){if(i.superseded){z+=1,console.log(`[parent] ${i.why} \u2014 abandoned; one fresh pod for the newest build instead (${z} in a row). Child#${n.id} keeps serving.`),t=!0;break}i.why!=="shutting down"&&console.error(`[parent] Child#${n.id} keeps serving the previous build \u2014 ${i.why}`);continue}z=0,console.log(`[parent] Child#${i.fresh.id} took over from Child#${n.id} with the new build (pid ${n.proc.pid} \u2192 ${i.fresh.proc.pid}, ready in ${(i.readyMs/1e3).toFixed(1)}s while Child#${n.id} served)`),m.publish((0,service_build_events_1.buildServiceSwapEvent)(W(i.fresh),{generation:1,swaps:0,swapMs:i.readyMs,draining:q.size,handoff:{fromPid:n.proc.pid??0}},X,{root:process.cwd()}))}catch(i){console.error(`[parent] Child#${n.id} keeps serving the previous build \u2014 could not start a successor: ${i?.message??String(i)}`)}finally{pe=!1}}}t&&(N=!0)}while(N&&!k)})().finally(()=>{C=void 0})}u(P,"A"),a(P,"handoffForReload");function ee(){const e=(0,swap_mode_1.maxRetiring)(),t=[...q].filter(n=>!D(n));for(;t.length>=e;){const n=t.shift();console.error(`[parent] Child#${n.id} (pid ${n.proc.pid}) was still finishing its work when a newer build replaced its successor too \u2014 stopping it (LENSMCP_SWAP_MAX_RETIRING=${e})`);try{n.proc.kill("SIGTERM")}catch{}}}u(ee,"X"),a(ee,"capRetiring");const G=[],He=new Map,Ue=a(e=>{let t=He.get(e);return t||He.set(e,t={crashes:0,restarts:0}),t},"watchOf"),Xe=(0,worker_supervisor_1.workerBackoff)(),Ae=a((e,t)=>({project:f,service:SERVICE_NAME||f,worker:e,pid:t,podGeneration:POD_GENERATION}),"workerWho"),tt=[path.join(__dirname,"worker-guard.js"),path.join(__dirname,"worker-guard.ts")].find(e=>fs.existsSync(e));for(const e of WORKER_PROBLEMS)console.error(`[parent] ${e}`);function ze(e,t){const n=e.name,i=path.dirname(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.resolve(BUNDLE_PATH)),s=path.join(i,`${n}.js`),o=Ue(n);if(!fs.existsSync(s))return console.error(`[parent] Worker "${n}" bundle not found: ${s}`),o.missing=s,m.publish((0,worker_supervisor_1.buildWorkerExitedEvent)(Ae(n,0),{ranMs:0,reason:`its bundle was not built (${path.basename(s)} is not in ${i})`})),null;o.missing=void 0;const y=(0,dev_devtool_1.sourceMapExecArgv)();__filename.endsWith(".ts")&&y.unshift("--require","@swc-node/register"),tt&&y.push("--require",tt);try{y.push("--require",require.resolve("@lensmcp/node-instrumentation/register"))}catch{}const d=inspectorPortFor(M||9229,$e+Math.max(0,WORKER_NAMES.indexOf(n)));y.push(M?`--inspect=127.0.0.1:${d}`:`--inspect-port=127.0.0.1:${d}`,...(0,inspector_secret_1.inspectorPublishExecArgv)(usesFixedInspectorPorts()));const w=(0,node_child_process_1.fork)(s,{env:(0,worker_supervisor_1.workerEnv)(process.env,e),stdio:["inherit","pipe","pipe","ipc"],execArgv:y,execPath:fe(`w-${n}`)}),A={name:n,spec:e,proc:w,debugPort:d,startedAt:Date.now(),tail:new exit_reason_1.TailBuffer,stopping:!1};G.push(A),w.on("error",$=>console.error(`[parent] Worker "${n}": ${$.message}`)),se(w,`\x1B[35m[worker:${n}] \x1B[0m`,$=>{A.tail.push($);const Q=/Debugger listening on (wss?:\/\/\S+)/.exec($);Q&&(A.inspectorUrl=Q[1])});const T=setTimeout(()=>{if(!(Re(A)||A.stopping)){if(o.crashes>0){const $=Date.now()-A.startedAt;console.log(`[parent] Worker "${n}" (pid=${w.pid}) is up again \u2014 ${(0,worker_supervisor_1.spanOf)($)} without a crash, after ${o.crashes} in a row`),m.publish((0,worker_supervisor_1.buildWorkerUpEvent)(Ae(n,w.pid??0),{ranMs:$,afterCrashes:o.crashes}))}o.crashes=0}},Xe.stableMs);return T.unref?.(),w.on("exit",($,Q)=>{clearTimeout(T);const ve=G.indexOf(A);ve>=0&&G.splice(ve,1),rt(A,$,Q)}),console.log(`[parent] Worker "${n}" started (pid=${w.pid}, PORT=${(0,worker_supervisor_1.workerEnv)(process.env,e).PORT}${t==="respawn"?`, restart ${o.restarts}`:""})`),m.publish((0,worker_supervisor_1.buildWorkerStartedEvent)(Ae(n,w.pid??0),{why:t,port:e.port,restarts:o.restarts})),A}u(ze,"Ze"),a(ze,"spawnWorkerProcess");function rt(e,t,n){const{name:i}=e,s=e.proc.pid??0,o=Date.now()-e.startedAt,y=(0,worker_supervisor_1.workerExitVerdict)(t,n,e.stopping||k);if(y.kind==="stopped")return;const d=Ue(i);if(y.kind==="exited"){d.lastEnd={at:Date.now(),pid:s,code:t,signal:n,ranMs:o,verdict:"exited"},console.warn(`[parent] Worker "${i}" (pid=${s}) exited on its own (code 0) after ${(0,worker_supervisor_1.spanOf)(o)} \u2014 not started again until the next build: a worker that ends is taken to have finished its work`),m.publish((0,worker_supervisor_1.buildWorkerExitedEvent)(Ae(i,s),{ranMs:o}));return}d.crashes+=1,d.lastEnd={at:Date.now(),pid:s,code:t,signal:n,ranMs:o,verdict:"crashed"};const w=(0,worker_supervisor_1.respawnDelay)(d.crashes,Xe),A=d.crashes>=worker_supervisor_1.CRASH_LOOP_AFTER;console.error((0,exit_reason_1.crashReport)(`[parent] Worker "${i}" crashed (code=${t}, signal=${n??"none"}, pid=${s}, after ${(0,worker_supervisor_1.spanOf)(o)})${y.external?" \u2014 stopped by a signal from outside its devserver":""}; starting it again in ${(0,worker_supervisor_1.spanOf)(w)}${A?` \u2014 ${d.crashes} crashes in a row: it is crash-looping (the wait doubles, up to ${(0,worker_supervisor_1.spanOf)(Xe.maxMs)})`:""}`,t,n,e.tail.snapshot())),m.publish((0,worker_supervisor_1.buildWorkerCrashedEvent)(Ae(i,s),{code:t,signal:n,ranMs:o,crashes:d.crashes,restarts:d.restarts,nextInMs:w,external:y.external,lines:e.tail.snapshot()})),clearTimeout(d.pending),d.nextAt=Date.now()+w,d.pending=setTimeout(()=>{d.pending=void 0,d.nextAt=void 0,!(k||G.some(T=>T.name===i))&&(d.restarts+=1,qe(e.spec,"respawn"))},w),d.pending.unref?.()}u(rt,"ct"),a(rt,"workerEnded");function qe(e,t){const n=Ue(e.name);n.waiting=void 0;const i=e.port>0?[...te].find(o=>o.name===e.name&&!Re(o)):void 0;if(!i){ze(e,t);return}console.log(`[parent] Worker "${e.name}" starts once its predecessor (pid=${i.proc.pid}) has finished its work \u2014 it holds port ${e.port}`);const s=a(()=>{n.waiting===s&&(n.waiting=void 0),!k&&!G.some(o=>o.name===e.name)&&ze(e,t)},"go");n.waiting=s,i.proc.once("exit",s)}u(qe,"Ve"),a(qe,"startWorker");const ot=(()=>{const e=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return Number.isFinite(e)&&e>=0?e:15*6e4})(),nt=(()=>{const e=Number(process.env.LENSMCP_SWAP_MAX_DRAINING);return Number.isFinite(e)&&e>=1?Math.floor(e):1})(),te=new Set,Re=a(e=>e.proc.exitCode!==null||e.proc.signalCode!==null,"workerExited");function Be(e,t){if(te.delete(e),!Re(e)){console.error(`[parent] Worker "${e.name}" (pid=${e.proc.pid}) ${t} \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{}}}u(Be,"Je"),a(Be,"killDrainingWorker");function Qe(e){e.stopping=!0;try{e.proc.kill("SIGTERM")}catch{}if(Re(e))return;const t=[...te].filter(i=>i.name===e.name);for(;t.length>=nt;)Be(t.shift(),`was still running when a later reload replaced its successor (cap ${nt})`);te.add(e);const n=setTimeout(()=>Be(e,`was still running ${ot}ms after SIGTERM`),ot);n.unref?.(),e.proc.once("exit",()=>{clearTimeout(n),te.delete(e)})}u(Qe,"rt"),a(Qe,"retireWorker");function je(){for(const e of He.values())clearTimeout(e.pending),e.pending=void 0,e.nextAt=void 0,e.waiting=void 0}u(je,"Xe"),a(je,"cancelWorkerStarts");function st(){for(const e of[...G])Qe(e);G.length=0,je();for(const e of WORKER_SPECS)Ue(e.name).crashes=0,qe(e,"reload")}u(st,"lt"),a(st,"restartWorkers");function it(){const e=Date.now();return{workers:WORKER_SPECS.map(t=>{const n=G.find(o=>o.name===t.name),i=He.get(t.name),s=n?"running":i?.pending?(i.crashes??0)>=worker_supervisor_1.CRASH_LOOP_AFTER?"crash-looping":"restarting":i?.waiting?"waiting":i?.missing?"missing":i?.lastEnd?.verdict==="exited"?"exited":"stopped";return{name:t.name,state:s,port:t.port,env:Object.keys(t.env),...n?{pid:n.proc.pid,upMs:e-n.startedAt}:{},crashes:i?.crashes??0,restarts:i?.restarts??0,...i?.nextAt?{nextInMs:Math.max(0,i.nextAt-e)}:{},...i?.lastEnd?{lastEnd:i.lastEnd}:{},...i?.missing?{missing:i.missing}:{}}}),draining:[...te].filter(t=>!Re(t)).map(t=>({name:t.name,pid:t.proc.pid}))}}u(it,"dt"),a(it,"workersView");const ht=debounce(async()=>{ie+=1;const e=Y();if(e.length>0)if(Oe==="process")P();else{console.log(`[parent] Forwarding reload to ${e.length} child(ren)`);for(const t of e)tell(t.proc,{type:"reload"})}await Me(),WORKER_NAMES.length>0&&st()},200),at=a((e,t)=>{const n=(0,notice_generation_1.noticeGeneration)(e.headers);return n===void 0||n===POD_GENERATION?!1:(e.resume(),t.writeHead(409,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!1,generation:POD_GENERATION,sentFor:n})),e.url==="/webpack/reload"&&console.log(`[parent] a build of generation g${n} reached generation g${POD_GENERATION} \u2014 not reloaded: it is not this generation's build`),!0)},"refusedForAnotherGeneration"),Ie=a(async(e,t)=>{if(e.method==="POST"&&e.url==="/webpack/reload"){if(!(0,devserver_transport_1.mayDriveThePool)(e))return refusePoolCommand(e,t);if(at(e,t))return;t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0})),ce(e).then(s=>{const o=s;X=(0,service_build_events_1.buildAccountOf)(o?.build),be=0,ye(o?.watcher)}),ht();return}if(e.method==="POST"&&e.url==="/webpack/watching"){if(!(0,devserver_transport_1.mayDriveThePool)(e))return refusePoolCommand(e,t);if(at(e,t))return;const s=await ce(e);ye(s),t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0,relayed:ae!==void 0}));return}if(e.method==="POST"&&e.url==="/webpack/scale"){if(!(0,devserver_transport_1.mayDriveThePool)(e))return refusePoolCommand(e,t);let s="";e.on("data",o=>{s+=o}),e.on("end",async()=>{let o=0;try{o=Number(JSON.parse(s||"{}").pods)||0}catch{}o=Math.max(1,Math.min(o,16)),await Se(o),t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0,pods:o}))});return}if(e.method==="GET"&&e.url?.startsWith("/webpack/logs")){const s=new URL(e.url,"http://localhost").searchParams,o=Math.min(Math.max(Number(s.get("tail")??"100")||0,0),Z),y=s.get("follow")!=="0",d=s.get("plain")==="1",w=!(0,devserver_transport_1.isOwnerOnlyTransport)(e);t.writeHead(200,{"content-type":"text/plain; charset=utf-8","cache-control":"no-cache"});const A=o===0?"":V.slice(-o).join(""),T=d?A.replace(F,""):A;if(t.write(w?(0,inspector_secret_1.redactInspectorUrls)(T):T),!y){t.end();return}const $={res:t,plain:d,redact:w};oe.add($),e.on("close",()=>oe.delete($));return}if(e.method==="POST"&&e.url?.startsWith("/webpack/debug")){if(!(0,devserver_transport_1.isOwnerOnlyTransport)(e)){t.writeHead(404,{"content-type":"application/json"}),t.end(JSON.stringify({error:"not found"}));return}const s=Number(new URL(e.url,"http://localhost").searchParams.get("port")||"");Number.isInteger(s)&&s>1024&&(M=s),M||(M=9229);const o=v.filter(d=>d.proc.exitCode===null&&d.proc.signalCode===null);for(const d of o)d.debugSlot<0&&(d.debugSlot=x()),tell(d.proc,{type:"debug-open",port:inspectorPortFor(M,d.debugSlot)});for(const d of G)try{d.proc.kill("SIGUSR1")}catch{}const y=Date.now()+2e3;for(;Date.now()<y&&o.some(d=>!d.inspectorUrl);)await new Promise(d=>setTimeout(d,50));t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify({ok:!0,basePort:M,fixedPorts:usesFixedInspectorPorts(),pods:o.map(d=>({id:d.id,inspectorUrl:d.inspectorUrl??null})),workers:G.map(d=>({name:d.name,port:d.debugPort||(0,inspector_secret_1.inspectorPortOf)(d.inspectorUrl),inspectorUrl:d.inspectorUrl??null}))},null,2)+`
|
|
16
16
|
`);return}if(e.method==="GET"&&e.url==="/webpack/workers"){if(!(0,devserver_transport_1.isOwnerOnlyTransport)(e)){t.writeHead(404,{"content-type":"application/json"}),t.end(JSON.stringify({error:"not found"}));return}t.writeHead(200,{"content-type":"application/json"}),t.end(JSON.stringify(it(),null,2)+`
|
|
17
17
|
`);return}if(e.method==="GET"&&e.url==="/webpack/memory"){if(!(0,devserver_transport_1.isOwnerOnlyTransport)(e)){t.writeHead(404,{"content-type":"application/json"}),t.end(JSON.stringify({error:"not found"}));return}const s=path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.resolve(BUNDLE_PATH),o=[...v,...q].map(y=>({id:y.id,pid:y.proc.pid??0,podGeneration:POD_GENERATION,healthy:y.healthy,retiring:q.has(y),latest:y.memory.latest??null,history:y.memory.history,retained:[...y.memory.retained.values()]}));t.writeHead(200,{"content-type":"application/json","cache-control":"no-store"}),t.end(JSON.stringify({ok:!0,service:SERVICE_NAME,project:f,bundle:{path:s},pods:o},null,2)+`
|
|
18
18
|
`);return}if(e.method==="POST"&&e.url?.startsWith("/webpack/heap")){if(!(0,devserver_transport_1.isOwnerOnlyTransport)(e)){t.writeHead(404,{"content-type":"application/json"}),t.end(JSON.stringify({error:"not found"}));return}const s=a((L,Le)=>{t.writeHead(L,{"content-type":"application/json"}),t.end(JSON.stringify(Le,null,2)+`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lensmcp/cluster",
|
|
3
|
-
"version": "1.25.
|
|
3
|
+
"version": "1.25.23",
|
|
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",
|
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@lensmcp/core": "1.25.
|
|
62
|
-
"@lensmcp/node-instrumentation": "1.25.
|
|
63
|
-
"@lensmcp/nx-plugin": "1.25.
|
|
61
|
+
"@lensmcp/core": "1.25.23",
|
|
62
|
+
"@lensmcp/node-instrumentation": "1.25.23",
|
|
63
|
+
"@lensmcp/nx-plugin": "1.25.23",
|
|
64
64
|
"fastify": "^5.8.5",
|
|
65
65
|
"@fastify/reply-from": "^12.6.2",
|
|
66
66
|
"@typescript/native-preview": "^7.0.0-dev.20260707.2",
|
package/worker-supervisor.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var k=Object.defineProperty;var a=(r,e)=>k(r,"name",{value:e,configurable:!0});var f=Object.defineProperty,i=a((r,e)=>f(r,"name",{value:e,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.CRASH_LINES=exports.MIN_RESPAWN_MS=exports.CRASH_LOOP_AFTER=void 0,exports.serializeWorkerSpecs=serializeWorkerSpecs,exports.parseWorkerSpecs=parseWorkerSpecs,exports.workerEnv=workerEnv,exports.workerBackoff=workerBackoff,exports.respawnDelay=respawnDelay,exports.workerExitVerdict=workerExitVerdict,exports.spanOf=spanOf,exports.crashLines=crashLines,exports.buildWorkerStartedEvent=buildWorkerStartedEvent,exports.buildWorkerUpEvent=buildWorkerUpEvent,exports.buildWorkerCrashedEvent=buildWorkerCrashedEvent,exports.buildWorkerExitedEvent=buildWorkerExitedEvent,exports.buildWorkerStoppedEvent=buildWorkerStoppedEvent;const exit_reason_1=require("./exit-reason"),NAME_RE=/^[\w.-]+$/,ENV_KEY_RE=/^[A-Za-z_][A-Za-z0-9_]*$/;function serializeWorkerSpecs(r){return JSON.stringify(r.map(e=>({name:e.name,...e.env&&typeof e.env=="object"?{env:e.env}:{},...e.port!==void 0?{port:e.port}:{}})))}a(serializeWorkerSpecs,"serializeWorkerSpecs"),i(serializeWorkerSpecs,"serializeWorkerSpecs");function parseWorkerSpecs(r){const e=[];let t;try{t=JSON.parse(r||"[]")}catch{return{specs:[],problems:[`WORKERS is not JSON: ${String(r).slice(0,80)}`]}}if(!Array.isArray(t))return{specs:[],problems:["WORKERS is not a list"]};const n=[];for(const s of t){const o=typeof s=="string"?{name:s}:s,p=typeof o?.name=="string"?o.name:"";if(!NAME_RE.test(p)){e.push(`worker ${JSON.stringify(o?.name??s)} is not a plain file name \u2014 not started`);continue}if(n.some(d=>d.name===p)){e.push(`worker "${p}" is declared twice \u2014 started once`);continue}const c={};for(const[d,l]of Object.entries(o?.env&&typeof o.env=="object"?o.env:{})){if(!ENV_KEY_RE.test(d)){e.push(`worker "${p}": env ${JSON.stringify(d)} is not a variable name \u2014 left out`);continue}typeof l=="string"||typeof l=="number"||typeof l=="boolean"?c[d]=String(l):e.push(`worker "${p}": env ${d} is not a string, number or boolean \u2014 left out`)}let u=0;o?.port!==void 0&&(Number.isInteger(o.port)&&o.port>=0&&o.port<=65535?u=o.port:e.push(`worker "${p}": port ${JSON.stringify(o.port)} is not a port \u2014 it gets 0 (a free one)`)),n.push({name:p,env:c,port:u})}return{specs:n,problems:e}}a(parseWorkerSpecs,"parseWorkerSpecs"),i(parseWorkerSpecs,"parseWorkerSpecs");function workerEnv(r,e){const t={...r,PORT:String(e.port),...e.env,LENSMCP_WORKER:e.name};return delete t.WORKERS,t}a(workerEnv,"workerEnv"),i(workerEnv,"workerEnv"),exports.CRASH_LOOP_AFTER=3;function envMs(r,e,t){const n=Number(r[e]);return r[e]!==void 0&&r[e]!==""&&Number.isFinite(n)&&n>=0?Math.floor(n):t}a(envMs,"envMs"),i(envMs,"envMs"),exports.MIN_RESPAWN_MS=100;function workerBackoff(r=process.env){const e=Math.max(exports.MIN_RESPAWN_MS,envMs(r,"LENSMCP_WORKER_BACKOFF_MS",1e3));return{baseMs:e,maxMs:Math.max(e,envMs(r,"LENSMCP_WORKER_BACKOFF_MAX_MS",6e4)),stableMs:envMs(r,"LENSMCP_WORKER_STABLE_MS",3e4)}}a(workerBackoff,"workerBackoff"),i(workerBackoff,"workerBackoff");function respawnDelay(r,e){const t=Math.max(1,Math.floor(r));return Math.min(e.maxMs,e.baseMs*2**Math.min(t-1,30))}a(respawnDelay,"respawnDelay"),i(respawnDelay,"respawnDelay");function workerExitVerdict(r,e,t){return t?{kind:"stopped"}:r===0&&!e?{kind:"exited"}:{kind:"crashed",external:e==="SIGTERM"||e==="SIGINT"||e==="SIGHUP"}}a(workerExitVerdict,"workerExitVerdict"),i(workerExitVerdict,"workerExitVerdict");function spanOf(r){return r<1e4?`${Math.round(r/100)/10} s`:r<12e4?`${Math.round(r/1e3)} s`:`${Math.round(r/6e4)} min`}a(spanOf,"spanOf"),i(spanOf,"spanOf"),exports.CRASH_LINES=12;const STACK_FRAMES=3,ANSI_SGR=/\x1b\[[0-9;]*m/g;function crashLines(r,e=exports.CRASH_LINES){const t=[];let n=0,s=0;const o=i(()=>{s&&t.push(` \u2026 ${s} more frame${s===1?"":"s"}`),s=0},"fold");for(const p of r){const c=p.replace(ANSI_SGR,"");if(/^\s+at\s/.test(c)){if(n+=1,n>STACK_FRAMES){s+=1;continue}}else o(),n=0;t.push(c)}return o(),t.slice(-e)}a(crashLines,"crashLines"),i(crashLines,"crashLines");let idCounter=0;function makeId(){return idCounter=(idCounter+1)%65535,`${Date.now().toString(36)}${idCounter.toString(36)}${Math.random().toString(36).slice(2,8)}`}a(makeId,"makeId"),i(makeId,"makeId");function envelope(r,e,t,n,s,o,p,c){const u="pending";return{id:p(),sessionId:u,timestamp:o,source:"gateway",category:"cluster",severity:t,context:{sessionId:u,projectName:r.project},fingerprint:`cluster-${e}:${r.service}`,title:n,...c?{message:c}:{},raw:{kind:e,project:r.project,service:r.service,worker:r.worker,pid:r.pid,podGeneration:r.podGeneration,...s}}}a(envelope,"envelope"),i(envelope,"envelope");function buildWorkerStartedEvent(r,e,t=Date.now(),n=makeId){const s=e.why==="respawn"?`started again (restart ${e.restarts})`:e.why==="reload"?"started on the new build":"started";return envelope(r,"worker-started","info",`${r.service} worker ${r.worker} ${s} \u2014 pid ${r.pid}`,{why:e.why,port:e.port,restarts:e.restarts},t,n)}a(buildWorkerStartedEvent,"buildWorkerStartedEvent"),i(buildWorkerStartedEvent,"buildWorkerStartedEvent");function buildWorkerUpEvent(r,e,t=Date.now(),n=makeId){return envelope(r,"worker-up","info",`${r.service} worker ${r.worker} is up again \u2014 ${spanOf(e.ranMs)} without a crash, after ${e.afterCrashes} in a row`,{ranMs:e.ranMs,afterCrashes:e.afterCrashes},t,n)}a(buildWorkerUpEvent,"buildWorkerUpEvent"),i(buildWorkerUpEvent,"buildWorkerUpEvent");function buildWorkerCrashedEvent(r,e,t=Date.now(),n=makeId){const s=e.crashes>=exports.CRASH_LOOP_AFTER,o=e.signal?e.signal:`exit ${e.code}`,p=s?`${r.service} worker ${r.worker} is crash-looping \u2014 ${e.crashes} crashes in a row (${o}); next start in ${spanOf(e.nextInMs)}`:`${r.service} worker ${r.worker} crashed (${o}${e.external?", a signal from outside its devserver":""}) after ${spanOf(e.ranMs)} \u2014 starting it again in ${spanOf(e.nextInMs)}`,c=e.external?`stopped by ${e.signal} from outside its devserver (\`kill\`, Activity Monitor)`:(0,exit_reason_1.describeExit)(e.code,e.signal),u=crashLines(e.lines);return envelope(r,"worker-crashed","error",p,{exitCode:e.code,signal:e.signal,ranMs:e.ranMs,crashes:e.crashes,restarts:e.restarts,nextInMs:e.nextInMs,crashLooping:s,external:e.external,...c?{reading:c}:{},lines:u},t,n,u.length?u.join(`
|
|
1
|
+
"use strict";var k=Object.defineProperty;var a=(r,e)=>k(r,"name",{value:e,configurable:!0});var f=Object.defineProperty,i=a((r,e)=>f(r,"name",{value:e,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.CRASH_LINES=exports.MIN_RESPAWN_MS=exports.CRASH_LOOP_AFTER=void 0,exports.serializeWorkerSpecs=serializeWorkerSpecs,exports.parseWorkerSpecs=parseWorkerSpecs,exports.workerEnv=workerEnv,exports.workerBackoff=workerBackoff,exports.respawnDelay=respawnDelay,exports.workerExitVerdict=workerExitVerdict,exports.spanOf=spanOf,exports.crashLines=crashLines,exports.buildWorkerStartedEvent=buildWorkerStartedEvent,exports.buildWorkerUpEvent=buildWorkerUpEvent,exports.buildWorkerCrashedEvent=buildWorkerCrashedEvent,exports.buildWorkerExitedEvent=buildWorkerExitedEvent,exports.buildWorkerStoppedEvent=buildWorkerStoppedEvent;const exit_reason_1=require("./exit-reason"),child_process_env_1=require("./child-process-env"),NAME_RE=/^[\w.-]+$/,ENV_KEY_RE=/^[A-Za-z_][A-Za-z0-9_]*$/;function serializeWorkerSpecs(r){return JSON.stringify(r.map(e=>({name:e.name,...e.env&&typeof e.env=="object"?{env:e.env}:{},...e.port!==void 0?{port:e.port}:{}})))}a(serializeWorkerSpecs,"serializeWorkerSpecs"),i(serializeWorkerSpecs,"serializeWorkerSpecs");function parseWorkerSpecs(r){const e=[];let t;try{t=JSON.parse(r||"[]")}catch{return{specs:[],problems:[`WORKERS is not JSON: ${String(r).slice(0,80)}`]}}if(!Array.isArray(t))return{specs:[],problems:["WORKERS is not a list"]};const n=[];for(const s of t){const o=typeof s=="string"?{name:s}:s,p=typeof o?.name=="string"?o.name:"";if(!NAME_RE.test(p)){e.push(`worker ${JSON.stringify(o?.name??s)} is not a plain file name \u2014 not started`);continue}if(n.some(d=>d.name===p)){e.push(`worker "${p}" is declared twice \u2014 started once`);continue}const c={};for(const[d,l]of Object.entries(o?.env&&typeof o.env=="object"?o.env:{})){if(!ENV_KEY_RE.test(d)){e.push(`worker "${p}": env ${JSON.stringify(d)} is not a variable name \u2014 left out`);continue}typeof l=="string"||typeof l=="number"||typeof l=="boolean"?c[d]=String(l):e.push(`worker "${p}": env ${d} is not a string, number or boolean \u2014 left out`)}let u=0;o?.port!==void 0&&(Number.isInteger(o.port)&&o.port>=0&&o.port<=65535?u=o.port:e.push(`worker "${p}": port ${JSON.stringify(o.port)} is not a port \u2014 it gets 0 (a free one)`)),n.push({name:p,env:c,port:u})}return{specs:n,problems:e}}a(parseWorkerSpecs,"parseWorkerSpecs"),i(parseWorkerSpecs,"parseWorkerSpecs");function workerEnv(r,e){const t={...r,PORT:String(e.port),...e.env,LENSMCP_WORKER:e.name};return delete t.WORKERS,(0,child_process_env_1.childProcessEnv)(t)}a(workerEnv,"workerEnv"),i(workerEnv,"workerEnv"),exports.CRASH_LOOP_AFTER=3;function envMs(r,e,t){const n=Number(r[e]);return r[e]!==void 0&&r[e]!==""&&Number.isFinite(n)&&n>=0?Math.floor(n):t}a(envMs,"envMs"),i(envMs,"envMs"),exports.MIN_RESPAWN_MS=100;function workerBackoff(r=process.env){const e=Math.max(exports.MIN_RESPAWN_MS,envMs(r,"LENSMCP_WORKER_BACKOFF_MS",1e3));return{baseMs:e,maxMs:Math.max(e,envMs(r,"LENSMCP_WORKER_BACKOFF_MAX_MS",6e4)),stableMs:envMs(r,"LENSMCP_WORKER_STABLE_MS",3e4)}}a(workerBackoff,"workerBackoff"),i(workerBackoff,"workerBackoff");function respawnDelay(r,e){const t=Math.max(1,Math.floor(r));return Math.min(e.maxMs,e.baseMs*2**Math.min(t-1,30))}a(respawnDelay,"respawnDelay"),i(respawnDelay,"respawnDelay");function workerExitVerdict(r,e,t){return t?{kind:"stopped"}:r===0&&!e?{kind:"exited"}:{kind:"crashed",external:e==="SIGTERM"||e==="SIGINT"||e==="SIGHUP"}}a(workerExitVerdict,"workerExitVerdict"),i(workerExitVerdict,"workerExitVerdict");function spanOf(r){return r<1e4?`${Math.round(r/100)/10} s`:r<12e4?`${Math.round(r/1e3)} s`:`${Math.round(r/6e4)} min`}a(spanOf,"spanOf"),i(spanOf,"spanOf"),exports.CRASH_LINES=12;const STACK_FRAMES=3,ANSI_SGR=/\x1b\[[0-9;]*m/g;function crashLines(r,e=exports.CRASH_LINES){const t=[];let n=0,s=0;const o=i(()=>{s&&t.push(` \u2026 ${s} more frame${s===1?"":"s"}`),s=0},"fold");for(const p of r){const c=p.replace(ANSI_SGR,"");if(/^\s+at\s/.test(c)){if(n+=1,n>STACK_FRAMES){s+=1;continue}}else o(),n=0;t.push(c)}return o(),t.slice(-e)}a(crashLines,"crashLines"),i(crashLines,"crashLines");let idCounter=0;function makeId(){return idCounter=(idCounter+1)%65535,`${Date.now().toString(36)}${idCounter.toString(36)}${Math.random().toString(36).slice(2,8)}`}a(makeId,"makeId"),i(makeId,"makeId");function envelope(r,e,t,n,s,o,p,c){const u="pending";return{id:p(),sessionId:u,timestamp:o,source:"gateway",category:"cluster",severity:t,context:{sessionId:u,projectName:r.project},fingerprint:`cluster-${e}:${r.service}`,title:n,...c?{message:c}:{},raw:{kind:e,project:r.project,service:r.service,worker:r.worker,pid:r.pid,podGeneration:r.podGeneration,...s}}}a(envelope,"envelope"),i(envelope,"envelope");function buildWorkerStartedEvent(r,e,t=Date.now(),n=makeId){const s=e.why==="respawn"?`started again (restart ${e.restarts})`:e.why==="reload"?"started on the new build":"started";return envelope(r,"worker-started","info",`${r.service} worker ${r.worker} ${s} \u2014 pid ${r.pid}`,{why:e.why,port:e.port,restarts:e.restarts},t,n)}a(buildWorkerStartedEvent,"buildWorkerStartedEvent"),i(buildWorkerStartedEvent,"buildWorkerStartedEvent");function buildWorkerUpEvent(r,e,t=Date.now(),n=makeId){return envelope(r,"worker-up","info",`${r.service} worker ${r.worker} is up again \u2014 ${spanOf(e.ranMs)} without a crash, after ${e.afterCrashes} in a row`,{ranMs:e.ranMs,afterCrashes:e.afterCrashes},t,n)}a(buildWorkerUpEvent,"buildWorkerUpEvent"),i(buildWorkerUpEvent,"buildWorkerUpEvent");function buildWorkerCrashedEvent(r,e,t=Date.now(),n=makeId){const s=e.crashes>=exports.CRASH_LOOP_AFTER,o=e.signal?e.signal:`exit ${e.code}`,p=s?`${r.service} worker ${r.worker} is crash-looping \u2014 ${e.crashes} crashes in a row (${o}); next start in ${spanOf(e.nextInMs)}`:`${r.service} worker ${r.worker} crashed (${o}${e.external?", a signal from outside its devserver":""}) after ${spanOf(e.ranMs)} \u2014 starting it again in ${spanOf(e.nextInMs)}`,c=e.external?`stopped by ${e.signal} from outside its devserver (\`kill\`, Activity Monitor)`:(0,exit_reason_1.describeExit)(e.code,e.signal),u=crashLines(e.lines);return envelope(r,"worker-crashed","error",p,{exitCode:e.code,signal:e.signal,ranMs:e.ranMs,crashes:e.crashes,restarts:e.restarts,nextInMs:e.nextInMs,crashLooping:s,external:e.external,...c?{reading:c}:{},lines:u},t,n,u.length?u.join(`
|
|
2
2
|
`):void 0)}a(buildWorkerCrashedEvent,"buildWorkerCrashedEvent"),i(buildWorkerCrashedEvent,"buildWorkerCrashedEvent");function buildWorkerExitedEvent(r,e,t=Date.now(),n=makeId){const s=e.reason??`it ended on its own (code 0) after ${spanOf(e.ranMs)}`;return envelope(r,"worker-exited","warning",`${r.service} worker ${r.worker} is not running \u2014 ${s}; not started again until the next build`,{ranMs:e.ranMs,...e.reason?{reason:e.reason}:{}},t,n)}a(buildWorkerExitedEvent,"buildWorkerExitedEvent"),i(buildWorkerExitedEvent,"buildWorkerExitedEvent");function buildWorkerStoppedEvent(r,e,t=Date.now(),n=makeId){return envelope(r,"worker-stopped","info",`${r.service} worker ${r.worker} stopped \u2014 ${e.reason}`,{reason:e.reason},t,n)}a(buildWorkerStoppedEvent,"buildWorkerStoppedEvent"),i(buildWorkerStoppedEvent,"buildWorkerStoppedEvent");
|