@lensmcp/cluster 1.22.3 → 1.22.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/create-webpack-dev.js +1 -1
- package/executors/gateway/runtime/discovery.js +1 -1
- package/executors/gateway/runtime/lens-children.d.ts +12 -0
- package/executors/gateway/runtime/lens-children.js +1 -1
- package/executors/gateway/runtime/observability.js +2 -2
- package/executors/gateway/runtime/types.d.ts +6 -0
- package/fork-ts-check-reporter.d.ts +13 -0
- package/fork-ts-check-reporter.js +1 -0
- package/index.d.ts +2 -1
- package/index.js +1 -1
- package/package.json +4 -4
- package/tsgo-check-plugin.d.ts +9 -4
- package/tsgo-check-plugin.js +5 -4
- package/typecheck-bus.d.ts +17 -0
- package/typecheck-bus.js +3 -3
package/create-webpack-dev.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var W=Object.defineProperty;var d=(r,t)=>W(r,"name",{value:t,configurable:!0});var T=Object.defineProperty,u=d((r,t)=>T(r,"name",{value:t,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.DevServerReloadPlugin=void 0,exports.devserverControlSock=devserverControlSock,exports.createDevWebpackConfig=createDevWebpackConfig;const tslib_1=require("tslib"),app_plugin_1=require("@nx/webpack/app-plugin"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),webpack_node_externals_1=tslib_1.__importDefault(require("webpack-node-externals")),build_scope_patterns_1=require("./build-scope-patterns"),tsgo_check_plugin_1=require("./tsgo-check-plugin"),fork_ts_check_reporter_1=require("./fork-ts-check-reporter"),webpack=require("webpack");class DevServerReloadPlugin{static{d(this,"DevServerReloadPlugin")}static{u(this,"DevServerReloadPlugin")}static{this.RECENT_PATH_CAP=32}constructor(t,o=!1,i){this.testimony={schemaVersion:1,lastWatchRunAt:0,lastBuildAt:0,buildsSinceSpawn:0,degraded:!1,recentPaths:[]},this.secure=o,this.base=`${o?"https":"http"}://localhost:${t}`,this.controlSock=i}post(t,o){const i=JSON.stringify(o),s=u(()=>new Promise((a,c)=>{const p=(this.secure?require("node:https"):require("node:http")).request(`${this.base}${t}`,{method:"POST",headers:{"content-type":"application/json"},rejectUnauthorized:!1},l=>{l.resume(),l.on("end",a)});p.on("error",c),p.end(i)}),"viaTcp"),n=this.controlSock;return!n||!fs.existsSync(n)?s():new Promise((a,c)=>{const p=require("node:http").request({socketPath:n,path:t,method:"POST",headers:{"content-type":"application/json"}},l=>{l.resume(),l.on("end",a)});p.on("error",c),p.end(i)}).catch(s)}snapshot(){return{...this.testimony,recentPaths:[...this.testimony.recentPaths]}}stampWatchRun(t){if(this.testimony.lastWatchRunAt=Date.now(),t.length){const o=[...this.testimony.recentPaths,...t];this.testimony.recentPaths=o.slice(-DevServerReloadPlugin.RECENT_PATH_CAP)}}degrade(t){this.testimony.degraded=t}tellWatching(){this.post("/webpack/watching",this.testimony).catch(()=>{})}apply(t){const o="DevServerReloadPlugin";let i=!1;t.hooks.watchRun?.tap(o,s=>{const n=[...s?.modifiedFiles??[],...s?.removedFiles??[]].filter(a=>typeof a=="string");if(this.stampWatchRun(n),!i){const a=s?.watchFileSystem?.watcher;a&&typeof a.on=="function"&&(i=!0,a.on("error",c=>{this.degrade(`watcher error: ${c?.message??String(c)}`),this.tellWatching()}))}this.tellWatching()}),t.hooks.watchClose?.tap(o,()=>{this.degrade("watch closed"),this.tellWatching()}),t.hooks.failed?.tap(o,s=>{this.degrade(`compiler failed: ${s?.message??String(s)}`),this.tellWatching()}),t.hooks.done.tap(o,async s=>{try{if(s.hasErrors()){this.tellWatching();return}this.testimony.lastBuildAt=Date.now(),this.testimony.buildsSinceSpawn+=1,await this.post("/webpack/reload",{watcher:this.testimony}),console.log("[DevServerReloadPlugin] notified devserver to reload")}catch{console.log("[DevServerReloadPlugin] devserver not running yet")}})}}exports.DevServerReloadPlugin=DevServerReloadPlugin;function devserverControlSock(r,t=process.env){const o=t.LENSMCP_WS_KEY||"",i=o?path.join(os.tmpdir(),o,`${r}-devserver`):path.join(os.tmpdir(),`${r}-devserver`);return path.join(i,"parent.sock")}d(devserverControlSock,"devserverControlSock"),u(devserverControlSock,"devserverControlSock");function createDevWebpackConfig(r){const{appRoot:t,outputDir:o,main:i,tsConfig:s,workspaceRoot:n,assets:a=[],port:c,memoryLimit:p=8192,buildLibsFromSource:l=!0,orgScopes:w=[],bundlePackages:b=[],additionalEntryPoints:y=[],nodeExternalsConfig:m,webpackConfigPath:v}=r,{allowlistPatterns:C,scopePrefixes:E,scopePatterns:N}=(0,build_scope_patterns_1.buildScopePatterns)(w),P=process.env.LENSMCP_TYPECHECK,f=P==="tsgo"?(0,tsgo_check_plugin_1.resolveTsgoBin)(n,process.env.LENSMCP_TSGO_BIN):null;if(P==="tsgo"&&!f){const e=`${tsgo_check_plugin_1.TSGO_MISSING_CAUSE}. Fell back to fork-ts-checker, which reports to the console only \u2014 so typecheck:// has no producer for this project until it is fixed`;console.warn(`[serve] ${r.appName}: LENSMCP_TYPECHECK=tsgo but ${e}.`),(0,tsgo_check_plugin_1.reportTsgoUnavailable)({appName:r.appName,tsConfig:s,workspaceRoot:n,detail:e})}const _=!!f,S=b.map(e=>new RegExp(`^${e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}(/|$)`)),R=[/webpack\/hot\/poll\?100/,...C,...S,...m?.allowlist||[]],k={output:{path:o,...process.env.NODE_ENV!=="production"&&{devtoolModuleFilenameTemplate:"[absolute-resource-path]"},clean:!0},externals:[(0,webpack_node_externals_1.default)({allowlist:R,additionalModuleDirs:m?.additionalModuleDirs||[],...m?.importType&&{importType:m.importType}}),({request:e},g)=>{if(e&&path.isAbsolute(e)&&e.startsWith(n)&&!e.includes("node_modules")||e&&(e.startsWith(path.join(n,"apps"))||e.startsWith(path.join(n,"libs")))||e&&E.some(h=>e.startsWith(h))||e&&N.some(h=>h.test(e))||e&&S.some(h=>h.test(e)))return g();if(e&&!(e.startsWith("./")||e.startsWith(".."))){const h=e.startsWith("@")?e.split("/").slice(0,2).join("/"):e.split("/")[0];return fs.existsSync(path.join(n,"node_modules",h))?g(null,`commonjs ${e}`):g()}return g()}],mode:"development",devtool:"eval-cheap-module-source-map",plugins:[new webpack.HotModuleReplacementPlugin,new app_plugin_1.NxAppWebpackPlugin({target:"node22",compiler:"tsc",main:i,additionalEntryPoints:y,verbose:!0,sourceMap:"eval-cheap-module-source-map",mergeExternals:!0,externalDependencies:[],memoryLimit:p,tsConfig:s,assets:a,optimization:!1,progress:!1,outputHashing:"none",generatePackageJson:!1,watchDependencies:!0,typeCheckOptions:process.env.LENSMCP_TYPECHECK==="off"||_?!1:{async:!0},buildLibsFromSource:l}),new DevServerReloadPlugin(c,r.httpsReload===!0,devserverControlSock(r.serviceName)),..._?[new tsgo_check_plugin_1.TsgoCheckPlugin({appName:r.appName,tsConfig:s,workspaceRoot:n,...process.env.LENSMCP_TSGO_BIN?{binPath:process.env.LENSMCP_TSGO_BIN}:{}})]:process.env.LENSMCP_TYPECHECK==="off"?[]:[new fork_ts_check_reporter_1.ForkTsCheckReporterPlugin({appName:r.appName,tsConfig:s,workspaceRoot:n})]],snapshot:{managedPaths:[/^(.+?[\\/])?node_modules[\\/]/]},watch:!0,watchOptions:{ignored:["**/*.env.template","**/config.template.json","**/*.md","**/dist/**","**/migrations/**"]},cache:{type:"filesystem"}};if(v){const e=require(path.resolve(t,v));return(e.default||e)(k)}return k}d(createDevWebpackConfig,"createDevWebpackConfig"),u(createDevWebpackConfig,"createDevWebpackConfig");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var b=Object.defineProperty;var a=(e,r)=>b(e,"name",{value:r,configurable:!0});var S=Object.defineProperty,u=a((e,r)=>S(e,"name",{value:r,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.pickSock=pickSock,exports.lensPortFromUpstream=lensPortFromUpstream,exports.discoverRoutes=discoverRoutes,exports.projectSourceRoots=projectSourceRoots;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),manifest_1=require("../manifest"),scope_1=require("./scope");function pickSock(e,r=1500){const p=Date.now();if(p-e.scannedAt>r){try{e.socks=fs.readdirSync(e.dir).filter(s=>/^child-\d+(?:-g\d+)?\.sock$/.test(s)).map(s=>path.join(e.dir,s))}catch{e.socks=[]}e.scannedAt=p}if(e.socks.length!==0)return e.idx=(e.idx+1)%e.socks.length,e.socks[e.idx]}a(pickSock,"pickSock"),u(pickSock,"pickSock");function lensPortFromUpstream(e){if(!e)return;const r=/:(\d+)/.exec(e);return r?Number(r[1]):void 0}a(lensPortFromUpstream,"lensPortFromUpstream"),u(lensPortFromUpstream,"lensPortFromUpstream");function discoverRoutes(e,r,p=os.tmpdir(),s="",l={}){const d=u(i=>s?path.join(p,s,`${i}-devserver`):path.join(p,`${i}-devserver`),"sockDirFor"),c=[],h=[],o=[];let n;for(const[i,x]of Object.entries(r)){let t;try{const f=JSON.parse(fs.readFileSync(path.join(e,x.root,"project.json"),"utf8"));t=f.cluster??f.davnx}catch{continue}if(!t)continue;let v,
|
|
1
|
+
"use strict";var b=Object.defineProperty;var a=(e,r)=>b(e,"name",{value:r,configurable:!0});var S=Object.defineProperty,u=a((e,r)=>S(e,"name",{value:r,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.pickSock=pickSock,exports.lensPortFromUpstream=lensPortFromUpstream,exports.discoverRoutes=discoverRoutes,exports.projectSourceRoots=projectSourceRoots;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path")),manifest_1=require("../manifest"),scope_1=require("./scope");function pickSock(e,r=1500){const p=Date.now();if(p-e.scannedAt>r){try{e.socks=fs.readdirSync(e.dir).filter(s=>/^child-\d+(?:-g\d+)?\.sock$/.test(s)).map(s=>path.join(e.dir,s))}catch{e.socks=[]}e.scannedAt=p}if(e.socks.length!==0)return e.idx=(e.idx+1)%e.socks.length,e.socks[e.idx]}a(pickSock,"pickSock"),u(pickSock,"pickSock");function lensPortFromUpstream(e){if(!e)return;const r=/:(\d+)/.exec(e);return r?Number(r[1]):void 0}a(lensPortFromUpstream,"lensPortFromUpstream"),u(lensPortFromUpstream,"lensPortFromUpstream");function discoverRoutes(e,r,p=os.tmpdir(),s="",l={}){const d=u(i=>s?path.join(p,s,`${i}-devserver`):path.join(p,`${i}-devserver`),"sockDirFor"),c=[],h=[],o=[];let n;for(const[i,x]of Object.entries(r)){let t;try{const f=JSON.parse(fs.readFileSync(path.join(e,x.root,"project.json"),"utf8"));t=f.cluster??f.davnx}catch{continue}if(!t)continue;let v,k,m,y;if(t.service)t.lens&&console.warn(`[gateway] ${i}: cluster.lens is ignored for pod (service) decls \u2014 backends are instrumented by serve-hmr.`),v={dir:d(t.service),socks:[],idx:-1,scannedAt:0},k={project:i,decl:t,root:e,wsKey:s,pool:v,state:"down",lastUsed:Date.now(),inflight:0,lastScaleAt:0},h.push(k);else if(t.lens){const f=t.port??lensPortFromUpstream(t.upstream)??5173;m=`http://localhost:${f}`,y={project:i,...s?{workspaceKey:s}:{},workspaceRoot:e,projectRoot:path.join(e,x.root),port:f,...l[i]?.length?{sourceRoots:l[i]}:{}}}else if(m=t.upstream??(t.port?`http://localhost:${t.port}`:void 0),!m){console.warn(`[gateway] ${i}: no service/upstream/port \u2014 skipped.`);continue}const j={project:i,prependPrefix:t.prependPrefix,target:m,pool:v,svc:k,prefix:t.path,auth:t.auth,lens:y};t.host&&(c.push({...j,host:t.host}),o.push(t.host),v&&t.internalHost!==!1&&c.push({...j,host:typeof t.internalHost=="string"?t.internalHost:`internal.${t.host}`,internal:!0})),t.default&&(n={...j,prefix:void 0})}return n&&(n.apex=(0,scope_1.baseDomainOf)(o),c.push(n)),(0,manifest_1.sortBySpecificity)(c),{routes:c,services:h}}a(discoverRoutes,"discoverRoutes"),u(discoverRoutes,"discoverRoutes");function projectSourceRoots(e,r,p={}){const s={};for(const l of Object.keys(r)){const d=new Set,c=u(o=>{if(!d.has(o)){d.add(o);for(const n of p[o]??[])c(n)}},"visit");c(l);const h=[...d].map(o=>r[o]?.root).filter(o=>typeof o=="string").map(o=>path.resolve(e,o)).filter(o=>{const n=path.relative(e,o);return n===""||n!==".."&&!n.startsWith(`..${path.sep}`)&&!path.isAbsolute(n)});s[l]=[...new Set(h)]}return s}a(projectSourceRoots,"projectSourceRoots"),u(projectSourceRoots,"projectSourceRoots");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ChildProcess } from 'node:child_process';
|
|
1
2
|
import { type SpawnChild } from '@lensmcp/nx-plugin/lens-frontend';
|
|
2
3
|
import type { WorkspaceFragment } from './route-registry';
|
|
3
4
|
import type { GatewayRuntime, GatewayRuntimeOptions, LensWatcherHealth } from './types';
|
|
@@ -37,6 +38,17 @@ export declare function waitForPortFree(port: number, timeoutMs: number, deps?:
|
|
|
37
38
|
* this child owns — the port the liveness probe checks and the port its respawn must wait to be free.
|
|
38
39
|
* `undefined` for an unpinned child (nothing to probe, nothing to wait for). */
|
|
39
40
|
export declare function viteArgPort(args: readonly string[]): number | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Why a child process is gone, in the few words a log line can carry.
|
|
43
|
+
*
|
|
44
|
+
* A SIGNAL and an exit CODE are different diagnoses and the difference is the whole value: a signal
|
|
45
|
+
* means something OUTSIDE the process ended it (the OS reclaiming memory, a stray `pkill`, the recycle
|
|
46
|
+
* escalation), a non-zero code means the process decided to leave on its own terms (a heap abort at
|
|
47
|
+
* 134, a refused `--strictPort` bind at 1). Node sets exactly one of the two, so reading both and
|
|
48
|
+
* naming which one fired is the entire diagnosis. Pure, and reads `exitCode`/`signalCode` rather than
|
|
49
|
+
* taking them as arguments, because both are already settled by the time an 'exit' handler runs.
|
|
50
|
+
*/
|
|
51
|
+
export declare function describeChildExit(child: Pick<ChildProcess, 'exitCode' | 'signalCode'>): string;
|
|
40
52
|
export interface LensChildren {
|
|
41
53
|
spawnManagedChild: SpawnChild;
|
|
42
54
|
/** Boot the dashboard + MCP singletons and every `lens:true` app. Pushes the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var Re=Object.defineProperty;var P=(s,f)=>Re(s,"name",{value:f,configurable:!0});var Le=Object.defineProperty,d=P((s,f)=>Le(s,"name",{value:f,configurable:!0}),"d");Object.defineProperty(exports,"__esModule",{value:!0}),exports.probePortFree=probePortFree,exports.probePortListening=probePortListening,exports.probeWatcherHealth=probeWatcherHealth,exports.waitForPortFree=waitForPortFree,exports.viteArgPort=viteArgPort,exports.claimPort=claimPort,exports.createLensChildren=createLensChildren;const tslib_1=require("tslib"),net=tslib_1.__importStar(require("node:net")),path=tslib_1.__importStar(require("node:path")),node_child_process_1=require("node:child_process"),lens_frontend_1=require("@lensmcp/nx-plugin/lens-frontend"),hmr_reload_1=require("./hmr-reload"),pod_env_1=require("./pod-env"),scope_1=require("./scope"),workspace_registry_1=require("./workspace-registry"),lifecycle_1=require("./lifecycle"),types_1=require("./types"),observability_1=require("./observability"),HEAL_BASE_MS=1500,HEAL_MAX_MS=3e4,HEAL_HEALTHY_MS=2e4;function tryBind(s,f){return new Promise(u=>{const _=net.createServer();_.unref(),_.once("error",p=>{const E=p.code??"";u(E==="EADDRINUSE"||E==="EACCES"?"in-use":"unavailable")}),_.listen(f===void 0?{port:s}:{port:s,host:f},()=>_.close(()=>u("free")))})}P(tryBind,"tryBind"),d(tryBind,"tryBind");async function probePortFree(s){for(const f of[void 0,"0.0.0.0","127.0.0.1","::1"])if(await tryBind(s,f)==="in-use")return!1;return!0}P(probePortFree,"probePortFree"),d(probePortFree,"probePortFree");function probeConnect(s,f,u){return new Promise(_=>{let p=!1;const E=net.createConnection({host:s,port:f});E.unref();const C=setTimeout(()=>y(!1),u);C.unref?.();function y(k){p||(p=!0,clearTimeout(C),E.destroy(),_(k))}P(y,"y"),d(y,"finish"),E.once("connect",()=>y(!0)),E.once("error",()=>y(!1))})}P(probeConnect,"probeConnect"),d(probeConnect,"probeConnect");async function probePortListening(s,f=1e3){return await probeConnect("127.0.0.1",s,f)?!0:probeConnect("::1",s,f)}P(probePortListening,"probePortListening"),d(probePortListening,"probePortListening");async function probeWatcherHealth(s,f=1500){try{const u=new AbortController,_=setTimeout(()=>u.abort(),f);_.unref?.();try{const p=await fetch(`http://127.0.0.1:${s}/__lensmcp/watcher-health`,{signal:u.signal});if(!p.ok)return null;const E=await p.json();if(typeof E?.lastFsSetEventAt!="number")return null;const C=Array.isArray(E.recentEvents)?E.recentEvents.filter(y=>y&&typeof y.path=="string"&&typeof y.at=="number"&&typeof y.sequence=="number"&&["add","addDir","unlink","unlinkDir"].includes(y.kind)):[];return{schemaVersion:E.schemaVersion===2?2:1,ready:E.ready!==!1,sequence:typeof E.sequence=="number"?E.sequence:0,lastFsSetEventAt:E.lastFsSetEventAt,fsSetEvents:typeof E.fsSetEvents=="number"?E.fsSetEvents:0,recentEvents:C}}finally{clearTimeout(_)}}catch{return null}}P(probeWatcherHealth,"probeWatcherHealth"),d(probeWatcherHealth,"probeWatcherHealth");const sleepUnref=d(s=>new Promise(f=>{setTimeout(f,s).unref?.()}),"sleepUnref");async function waitForPortFree(s,f,u={}){const _=u.isPortFree??probePortFree,p=Math.max(1,u.intervalMs??types_1.PORT_FREE_POLL_MS),E=Date.now()+Math.max(0,f);for(;;){if(await _(s))return!0;const C=E-Date.now();if(C<=0)return!1;await sleepUnref(Math.min(p,C))}}P(waitForPortFree,"waitForPortFree"),d(waitForPortFree,"waitForPortFree");function viteArgPort(s){const f=d(u=>Number.isInteger(u)&&u>0&&u<65536?u:void 0,"valid");for(let u=0;u<s.length;u+=1){const _=s[u];if(_==="--port")return f(Number(s[u+1]));if(_.startsWith("--port="))return f(Number(_.slice(7)))}}P(viteArgPort,"viteArgPort"),d(viteArgPort,"viteArgPort");async function claimPort(s,f,u,_){let p=s;for(;f.has(p)||_?.has(p)||!await u(p);)p+=1;return f.add(p),p}P(claimPort,"claimPort"),d(claimPort,"claimPort");function createLensChildren(s,f,u,_){const{emit:p}=f,E=_?.isPortFree??probePortFree,C=_?.probeWatcherHealth??probeWatcherHealth,y=[],k=new Map,A=new Map,j=new Map,W=new Map,K=new Set;let O;const N=new Map,$=new Set,X=new Set,H=new Set,b=new Set,v=new Map,D=new WeakMap,x=new Set,J=d((e,r,n)=>{if(x.has(e))return;x.add(e);const t=setInterval(()=>{(async()=>{if(s.stopped()||$.has(e)){clearInterval(t),x.delete(e);return}await E(r)&&(clearInterval(t),x.delete(e),console.log(`[gateway] lens child ${e}: :${r} freed \u2014 respawning.`),n())})().catch(()=>{})},types_1.LENS_PARKED_PORT_REPROBE_MS);t.unref?.()},"parkUntilPortFree"),F=d(async(e,r,n)=>{const t=await claimPort(e,r,E,n?.reserved);return t!==e&&(n?.heldBy?console.log(`[gateway] handoff: :${e} is held by ${n.heldBy} \u2014 replacement on :${t}.`):console.warn(`[gateway] port ${e} is unavailable (another process holds it \u2014 an orphan from a crashed gateway?) \u2014 using ${t} instead.`)),t},"claimFreePort"),le=d((e,r,n)=>{const t=n?.LENSMCP_FRONTEND_KEY,o=Number(n?.LENSMCP_FRONTEND_GENERATION);if(!t||!Number.isFinite(o))return;const a=[...v.get(t)?.generations??[]].find(i=>i.generation===o);a&&(e.endsWith(":vite")?a.vite=r:e.endsWith(":browser-capture")&&(a.capture=r))},"attachRespawnedGenerationChild"),B=d(e=>{if(!(e.exitCode!==null||e.signalCode!==null)){X.add(e);try{e.kill("SIGTERM")}catch{}setTimeout(()=>{if(e.exitCode===null&&e.signalCode===null)try{e.kill("SIGKILL")}catch{}},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.()}},"retireChild"),ce=d((e,r)=>{const n=N.get(e);!n||n===r||n.exitCode!==null||n.signalCode!==null||(console.warn(`[gateway] lens child ${e}: a replacement took the label \u2014 retiring the previous child (pid ${n.pid??"?"}).`),B(n))},"retireLabelHolder"),T=d((e,r,n,t,o=!1,a,i,l)=>{const g=Date.now(),c=(0,node_child_process_1.spawn)(r,n,{cwd:i??s.root,env:{...(0,pod_env_1.podBaseEnv)(process.env,s.root,i??s.root),...t??{},LENSMCP_PARENT_PID:String(process.pid)},stdio:"inherit"});y.push(c),ce(e,c),N.set(e,c),le(e,c,t);const S=e==="vite"||e.endsWith(":vite"),M=typeof t?.LENSMCP_EVENT_FILE=="string"?t.LENSMCP_EVENT_FILE:void 0,L=M&&M!==s.eventFile?M:void 0,w=S?viteArgPort(n):l;S&&A.set(c,{key:t?.LENSMCP_FRONTEND_KEY??`${i??s.root}:${t?.LENSMCP_PROJECT??"app"}`,project:t?.LENSMCP_PROJECT??"app",workspaceRoot:i??s.root,spawnedAt:g,port:w,probeFails:0,listening:!1,generation:Number(t?.LENSMCP_FRONTEND_GENERATION??0),role:t?.LENSMCP_FRONTEND_ROLE==="replacement"?"replacement":"active",...L?{bus:L}:{}});const h=e==="lens-mcp"?"lens-mcp":e==="lens-dashboard"||e.startsWith("lens-dashboard:")?"lens-dashboard":void 0;return h&&w!==void 0&&(p("info",`lens child starting: ${h} (:${w})`,`cluster-lens-child:${h}`,{kind:"lens-child-starting",project:h,label:e,pid:c.pid,port:w},void 0,L),(async()=>{const m=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!s.stopped()&&Date.now()<m;){if(c.exitCode!==null||c.signalCode!==null||$.has(e))return;if(await probePortListening(w,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){p("info",`lens child up: ${h} (:${w})`,`cluster-lens-child:${h}`,{kind:"lens-child-up",project:h,label:e,pid:c.pid,port:w},void 0,L);return}await sleepUnref(150)}})().catch(()=>{})),c.on("exit",(m,z)=>{const ne=y.indexOf(c);ne>=0&&y.splice(ne,1),N.get(e)===c&&N.delete(e);const re=A.get(c);if(A.delete(c),X.delete(c))return;const ye=$.delete(e);if(s.stopped()||ye||(h&&p("warning",`lens child exited: ${h}`,`cluster-lens-child:${h}`,{kind:"lens-child-exit",project:h,label:e,pid:c.pid,code:m,signal:z},void 0,L),re&&ue(c,re)))return;const se=Date.now()-g,R=k.get(e)??{attempts:0,portConflicts:0};(async()=>{const ve=w!==void 0&&!await E(w),ae=(0,lifecycle_1.isPortConflictExit)({code:m,signal:z,ranMs:se,portHeld:ve},{fastFailMs:types_1.CHILD_START_FAIL_MS});if(ae&&R.portConflicts<types_1.MAX_PORT_CONFLICT_RETRIES)R.portConflicts+=1,k.set(e,R),console.warn(`[gateway] lens child ${e} lost the :${w} bind race (EADDRINUSE, code=${m}); waiting for the port, then retrying (port-retry ${R.portConflicts}/${types_1.MAX_PORT_CONFLICT_RETRIES}; crash budget untouched).`);else if(ae){R.portConflicts=0,k.set(e,R),console.warn(`[gateway] lens child ${e}: :${w} persistently held after ${types_1.MAX_PORT_CONFLICT_RETRIES} bind races \u2014 another server owns it (an external/shared daemon?). Parking; re-probing every ${Math.round(types_1.LENS_PARKED_PORT_REPROBE_MS/1e3)}s, will respawn if it frees.`),p("warning",`lens child parked: ${e} (:${w} held externally)`,`cluster-lens-child:${e}`,{kind:"lens-child-parked",label:e,port:w}),J(e,w,()=>T(e,r,n,t,o,a,i,l));return}else{R.portConflicts=0,se>=HEAL_HEALTHY_MS&&(R.attempts=0);const ie=Math.min(HEAL_MAX_MS,HEAL_BASE_MS*2**R.attempts);R.attempts+=1,k.set(e,R),console.warn(`[gateway] lens child ${e} exited (code=${m} sig=${z}); auto-healing in ${Math.round(ie/1e3)}s (attempt ${R.attempts}).`),await sleepUnref(ie)}s.stopped()||$.has(e)||(w!==void 0&&!await waitForPortFree(w,types_1.PORT_FREE_WAIT_MS,{isPortFree:E,intervalMs:types_1.PORT_FREE_POLL_MS})&&console.warn(`[gateway] lens child ${e}: :${w} still held after ${Math.round(types_1.PORT_FREE_WAIT_MS/1e3)}s \u2014 spawning anyway.`),!(s.stopped()||$.has(e))&&T(e,r,n,t,o,a,i,l))})().catch(()=>{})}),c},"spawnManagedChild"),Q=d(e=>{const r=`${e.wsKey}:${e.project}`,n=v.get(r);if(n)return n;const t={key:r,...e,sourceDirs:e.frontend.sourceRoots?.length?e.frontend.sourceRoots:[e.projectRoot],generation:0,state:"starting",generations:new Set,disposed:!1};v.set(r,t);for(const o of e.routes)o.lens&&(o.lens.workspaceKey??=e.wsKey,D.set(o.lens,t));return e.frontend.workspaceKey??=e.wsKey,D.set(e.frontend,t),t},"registerFrontend"),de=d(e=>{if(!types_1.LENS_WATCH_SCOPE_ENABLED)return{};const r=path.resolve(e.projectRoot),n=e.sourceDirs.map(t=>path.resolve(t)).filter(t=>t!==r);return n.length>0?{LENSMCP_WATCH_DIRS:n.join(path.delimiter)}:{}},"lensWatchScopeEnv"),Z=d((e,r,n)=>{const t=++e.generation,o=`${e.key}:g${t}:`,a=`${o}vite`,i=`${o}browser-capture`;$.delete(a),$.delete(i);const l=d((S,M,L,w,h,m)=>T(S,M,L,w,h,m,e.workspaceRoot),"spawnInRoot"),g=(0,lens_frontend_1.spawnLensFrontend)({projectRoot:e.projectRoot,workspaceRoot:e.workspaceRoot,project:e.project,eventFile:e.eventFile,port:r,chrome:!0,headless:!0,viteEnv:{LENSMCP_PROJECT:e.project,LENSMCP_FRONTEND_KEY:e.key,LENSMCP_FRONTEND_GENERATION:String(t),LENSMCP_FRONTEND_ROLE:n,...de(e),NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false"},labelPrefix:o,log:d(S=>console.log(S),"log")},l),c={ownerKey:e.key,generation:t,port:r,labelPrefix:o,vite:g?.vite??N.get(a),capture:N.get(i)};return e.generations.add(c),c},"spawnFrontendGeneration"),I=d((e,r)=>{if(!e)return;v.get(e.ownerKey)?.generations.delete(e);const n=[[`${e.labelPrefix}browser-capture`,e.capture],[`${e.labelPrefix}vite`,e.vite]];for(const[t,o]of n)$.add(t),o&&B(o);r&&b.delete(e.port)},"terminateGeneration"),pe=d(async e=>{const r=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!s.stopped()&&Date.now()<r;){const n=e.vite;if(!n||n.exitCode!==null||n.signalCode!==null)return!1;if(await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){const t=await C(e.port);if(!t||t.ready)return!0}await sleepUnref(150)}return!1},"waitForGenerationReady"),G=d(async e=>{const r=e?.vite;return!!(e&&r&&r.exitCode===null&&r.signalCode===null&&await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS)))},"generationIsServing"),Y=d(e=>!e.disposed&&!s.stopped()&&v.get(e.key)===e,"frontendIsCurrent"),q=d((e,r)=>{if(!Y(e))return Promise.resolve(!1);if(e.replacement)return e.replacement;const n=e.active;e.state=n?"replacing":"starting",e.reason=r,e.startedAt=Date.now();const t=(async()=>{let o,a;const i=Date.now();try{const l=new Set;for(const h of v.values())h!==e&&l.add(h.desiredPort);const g=n&&n.port===e.desiredPort?`g${n.generation}`:void 0,c=await F(e.desiredPort,b,{reserved:l,heldBy:g});if(a=c,!Y(e))return b.delete(c),!1;o=Z(e,c,"replacement"),e.candidate=o;const S=await G(n);console.log(`[gateway] lens handoff start: ${e.key} g${n?.generation??0}\u2192g${o.generation} :${n?.port??"down"}\u2192:${c} reason=${r}`),p("info",`lens handoff starting: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-start",wsKey:e.wsKey,project:e.project,reason:r,generation:o.generation,oldPort:n?.port,newPort:c,oldServing:S},void 0,e.eventFile===s.eventFile?void 0:e.eventFile);const M=await pe(o);if(!Y(e))return I(o,!0),e.candidate=void 0,!1;if(!M){I(o,!0),e.candidate=void 0;const h=await G(n);return e.state=h?"ready":"failed",h&&(e.reason=void 0,e.startedAt=void 0),console.error(`[gateway] lens handoff failed: ${e.key} g${o.generation} did not become ready within ${types_1.LENS_REPLACEMENT_READY_MS}ms; ${e.state==="ready"?"old generation kept serving":"no active generation"}.`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:r,generation:o.generation,port:c,durationMs:Date.now()-i,oldKept:h},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),!1}for(const h of e.routes)h.target=`http://localhost:${o.port}`,h.lens&&(h.lens.port=o.port);e.frontend.port=o.port,e.active=o,e.candidate=void 0,e.state="ready",e.reason=void 0,e.startedAt=void 0;const L=o.vite?A.get(o.vite):void 0;L&&(L.role="active",L.listening=!0);const w=(0,hmr_reload_1.broadcastFullReload)(s,e.key);if(console.log(`[gateway] lens handoff ready: ${e.key} g${o.generation} :${o.port} in ${Date.now()-i}ms; draining g${n?.generation??0}${w>0?`; reloading ${w} tab(s)`:""}.`),p("info",`lens handoff complete: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-complete",wsKey:e.wsKey,project:e.project,reason:r,generation:o.generation,oldPort:n?.port,newPort:o.port,durationMs:Date.now()-i,reloadedTabs:w},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),n){const h=`${n.labelPrefix}browser-capture`;$.add(h),n.capture&&B(n.capture),setTimeout(()=>I(n,!0),types_1.LENS_REPLACEMENT_DRAIN_MS).unref?.()}return!0}catch(l){I(o,!0),!o&&a!==void 0&&b.delete(a),e.candidate=void 0;const g=await G(n);e.state=g?"ready":"failed",g&&(e.reason=void 0,e.startedAt=void 0);const c=l.message;return console.error(`[gateway] lens handoff failed: ${e.key}: ${c}`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:r,generation:o?.generation??e.generation,port:o?.port??a,durationMs:Date.now()-i,oldKept:g,error:c},void 0,e.eventFile===s.eventFile?void 0:e.eventFile),!1}finally{e.replacement=void 0}})();return e.replacement=t,t},"rollFrontend"),ee=d((e,r)=>{e.active=Z(e,r,"active"),e.state="starting",e.startedAt=Date.now()},"spawnInitialFrontend"),ue=d((e,r)=>{const n=v.get(r.key);return!n||types_1.LENS_RESTART_MODE==="in-place"?!1:(n.candidate?.vite===e||n.active?.vite!==e||(n.state="starting",n.reason="child-exit",n.startedAt=Date.now(),console.warn(`[gateway] lens frontend exited: ${n.key} g${r.generation} :${r.port}; starting an alternate-port replacement.`),q(n,"child-exit")),!0)},"handleManagedViteExit");s.lensSupervisor=types_1.LENS_RESTART_MODE==="rolling"?{status(e){const r=D.get(e);return r?{state:r.state,generation:r.candidate?.generation??r.active?.generation??r.generation,reason:r.reason,startedAt:r.startedAt}:void 0},recover(e,r){const n=D.get(e);return n?q(n,r):Promise.resolve(!1)}}:void 0;let V=!1,te=0;const fe=d(()=>{V||Date.now()-te<types_1.POD_STALE_SCAN_MS||(V=!0,te=Date.now(),(async()=>{for(const e of[...v.values()]){if(s.stopped())return;const r=Date.now(),n=(0,scope_1.readSourceSetOptions)(e.workspaceRoot),t=await(0,lifecycle_1.sourceSetSnapshot)(e.workspaceRoot,e.sourceDirs,n.exclude,{ignoreTests:n.ignoreTests});if(v.get(e.key)!==e)continue;const o=e.sourceSnapshot,a=e.sourceScanStartedAt;if(e.sourceSnapshot=t,e.sourceScanStartedAt=r,!o)continue;const i=Date.now(),l=(0,lifecycle_1.diffSourceSets)(o,t,i,(0,lifecycle_1.sourceChangeWindowMs)(i,a,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS));l&&(e.sourceChange=l,p("info",`source file set changed for ${e.key}`,`cluster-lens-app:${e.project}`,{kind:"source-set-changed",scoped:!0,wsKey:e.wsKey,project:e.project,added:l.added,removed:l.removed,truncated:l.truncated},void 0,e.eventFile===s.eventFile?void 0:e.eventFile))}})().catch(()=>{}).finally(()=>{V=!1}))},"scanFrontendSourceSets");let U=!1;const Ee=d(async(e,r)=>{if(!U){U=!0;try{for(const[n,t]of[...A]){if(s.stopped())return;if(t.port===void 0||n.exitCode!==null||n.signalCode!==null)continue;if(await probePortListening(t.port,types_1.LENS_PROBE_TIMEOUT_MS)){if(t.probeFails=0,!t.listening){t.listening=!0;const l=v.get(t.key);l?.active?.vite===n&&(l.state="ready",l.reason=void 0),p("info",`lens app up: ${t.project} (vite :${t.port} listening)`,`cluster-lens-app:${t.project}`,{kind:"service-up",project:t.project,port:t.port},void 0,t.bus)}continue}const o=t.listening?e.graceMs:Math.max(e.graceMs,e.neverListenedGraceMs);if(Date.now()-t.spawnedAt<o){t.probeFails=0;continue}if(!r)continue;t.probeFails+=1;const a=(0,lifecycle_1.lensChildWedged)({spawnedAt:t.spawnedAt,probeFails:t.probeFails,hasListened:t.listening},j.get(t.key)??0,Date.now(),e);if(!a)continue;const i=t.listening?"its listener VANISHED (was up, now refusing)":`it NEVER bound within the ${Math.round(o/1e3)}s boot allowance`;j.set(t.key,Date.now()),t.probeFails=0,t.listening=!1,console.error(`[gateway] wedge recycle: lens app ${t.project} is ALIVE but NOT LISTENING on :${t.port} after ${Math.max(2,e.failureThreshold)} probes \u2014 ${i} \u2014 SIGKILL; a fresh vite is coming.`),p("warning",`wedge recycle: ${t.project} (${a})`,`cluster-lens-app:${t.project}`,{kind:"pod-recycle",project:t.project,reason:a,port:t.port},void 0,t.bus);try{n.kill("SIGKILL")}catch{}}}finally{U=!1}}},"probeLensChildren"),he=d(()=>{if(O||!types_1.POD_RECYCLE_ENABLED&&!types_1.LENS_PROBE_ENABLED)return;const e={graceMs:types_1.POD_STALE_GRACE_MS,settleMs:types_1.POD_RECYCLE_SETTLE_MS,cooldownMs:types_1.POD_STALE_RECYCLE_COOLDOWN_MS};O=setInterval(()=>{if(s.stopped()||A.size===0||(oe(),!types_1.POD_RECYCLE_ENABLED))return;fe();const r=Date.now();for(const[n,t]of A){const o=v.get(t.key),a=o?.sourceChange?.changedAt??0,i=j.get(t.key)??0;(0,lifecycle_1.lensFrontendStale)(t.spawnedAt,i,a,r,e)&&((W.get(t.key)??0)>=a||K.has(t.key)||(K.add(t.key),(async()=>{try{const l=o?.sourceChange,g=l&&!l.truncated?[...l.added,...l.removed].map(L=>path.resolve(t.workspaceRoot,L)):[],c=types_1.LENS_WATCHER_PROBE_ENABLED&&t.port!==void 0?(0,lifecycle_1.lensWatcherVerdict)(await C(t.port),a,l?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,g):"unknown";if(c==="heard"){W.set(t.key,a),console.log(`[gateway] stale source set: lens app ${t.project} watcher CONFIRMED the change \u2014 no recycle, HMR intact.`),p("info",`stale check: ${t.project} watcher confirmed \u2014 no recycle`,`cluster-lens-app:${t.project}`,{kind:"pod-stale-verified",project:t.project},void 0,t.bus);return}if(c==="unknown"&&types_1.LENS_WATCHER_UNVERIFIED==="keep"){console.log(`[gateway] stale source set: lens app ${t.project} unverifiable (no watcher testimony) \u2014 keeping it (LENSMCP_LENS_WATCHER_UNVERIFIED=keep).`);return}if(n.exitCode!==null||n.signalCode!==null)return;j.set(t.key,Date.now());const S=v.get(t.key);if(types_1.LENS_RESTART_MODE==="rolling"&&S){console.log(`[gateway] stale refresh: lens app ${t.key} (stale-source-set) \u2014 watcher ${c==="missed"?"missed the exact path change":"unverifiable"}; preparing a standby without dropping traffic.`),p("warning",`stale refresh: ${t.project} (stale-source-set)`,`cluster-lens-app:${t.project}`,{kind:"pod-refresh",wsKey:S.wsKey,project:t.project,reason:"stale-source-set",watcher:c,added:l?.added,removed:l?.removed},void 0,t.bus),await q(S,"stale-source-set");return}t.listening=!1,console.log(`[gateway] zombie recycle: lens app ${t.project} (stale-source-set) \u2014 watcher ${c==="missed"?"SILENT across the change":"unverifiable"}; restarting it`),p("warning",`zombie recycle: ${t.project} (stale-source-set)`,`cluster-lens-app:${t.project}`,{kind:"pod-recycle",project:t.project,reason:"stale-source-set",watcher:c},void 0,t.bus);const M=(0,hmr_reload_1.broadcastFullReload)(s,t.key);M>0&&console.log(`[gateway] \u2192 told ${M} open tab(s) to reload (stale optimize-dep generation)`);try{n.kill("SIGTERM")}catch{}setTimeout(()=>{if(n.exitCode===null&&n.signalCode===null){console.log(`[gateway] zombie recycle: lens app ${t.project} ignored SIGTERM for ${Math.round(types_1.LENS_RECYCLE_KILL_GRACE_MS/1e3)}s \u2014 escalating to SIGKILL.`);try{n.kill("SIGKILL")}catch{}}},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.()}finally{K.delete(t.key)}})()))}},Math.min(types_1.POD_STALE_SCAN_MS,15e3)),O.unref?.()},"startLensSweeper"),ge=d(async()=>{const e=[...new Map(s.routes.filter(t=>t.lens).map(t=>[t.project,t.lens])).values()],r=u.dashboard!==!1,n=u.mcp!==!1&&e.length>0;if(r){const t=(0,lens_frontend_1.findDashboardBundle)(s.root);if(!t)console.warn("[gateway] lens dashboard bundle not found \u2014 skipping. Install the self-contained CLI: `npm i -D lensmcp` (it ships `bundled/dashboard.js`), or `yarn nx build @lensmcp/lensmcp-mcp` in-repo.");else{const o=(0,scope_1.readLensScope)(s.root),a=await F(u.dashboardPort??o.dashboardPort,H),i=u.lensHost??"lensmcp.local",l=o.basePath;s.registry.appendRoutes(s.wsKey,[{host:i,prefix:l,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),s.rebuildRoutes(),(0,workspace_registry_1.registerWorkspace)({key:o.key,root:s.root,base:l,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString()}),console.log(`[gateway] starting lens dashboard \u2192 http://localhost:${a} (routed at https://${i}${l}/)`),p("info",`lens dashboard up: ${i}${l} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:i,port:a,base:l}),T("lens-dashboard",process.execPath,[t],{LENSMCP_EVENT_FILE:s.eventFile,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:l},!1,void 0,void 0,a)}}if(n){const t=(0,lens_frontend_1.findMcpBundle)(s.root);if(!t)console.warn("[gateway] MCP server bundle not found \u2014 skipping (lens apps will still publish to the bus; an external `lensmcp mcp` can read it). Install: `npm i -D lensmcp`.");else{const o=(0,scope_1.readLensScope)(s.root),a=Number(process.env.LENSMCP_PORT??o.mcpHttpPort),i=d(()=>{console.log(`[gateway] starting lens MCP server on 127.0.0.1:${a} (${t})`),T("lens-mcp",process.execPath,[t],{LENSMCP_EVENT_FILE:s.eventFile,LENSMCP_PROCESS_ROLE:"mcp",LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_PORT:String(a),LENSMCP_WORKSPACE_KEY:o.key,LENSMCP_WORKSPACE_ROOT:s.root},!1,void 0,void 0,a)},"spawnMcp");await E(a)?i():(console.warn(`[gateway] lens MCP port :${a} is already served \u2014 an external lensmcp server (a shared daemon?) owns this workspace's MCP; not spawning a second. Re-probing every ${Math.round(types_1.LENS_PARKED_PORT_REPROBE_MS/1e3)}s; will take over if it frees.`),p("info",`lens MCP served externally on :${a} \u2014 gateway parked its own`,"cluster-lens-child:lens-mcp",{kind:"lens-child-up",project:"lens-mcp",label:"lens-mcp",port:a,external:!0}),J("lens-mcp",a,i))}}for(const t of e){if(t.started)continue;t.started=!0;const o=t.port,a=(s.registry.get(s.wsKey)?.routes??s.routes).filter(g=>g.lens?.project===t.project),i=await F(t.port,b);for(const g of a)g.lens&&(g.lens.port=i),g.target=`http://localhost:${i}`;t.port=i;const l=Q({wsKey:s.wsKey,project:t.project,workspaceRoot:s.root,projectRoot:t.projectRoot,eventFile:s.eventFile,routes:a,frontend:t,desiredPort:o});try{ee(l,i),p("info",`lens app started: ${t.project} (vite :${t.port})`,`cluster-lens-app:${t.project}`,{kind:"lens-app-up",project:t.project,port:t.port})}catch(g){b.delete(i),l.state="failed",console.error(`[gateway] lens app ${t.project}: ${g.message}`)}}he()},"bootSingletonsAndApps"),we=d(async e=>{if(u.dashboard===!1)return;const r=(0,lens_frontend_1.findDashboardBundle)(s.root);if(!r)return;const n=(0,scope_1.readLensScope)(e.root),t=u.lensHost??"lensmcp.local",o=n.basePath,a=await F(n.dashboardPort,H),i=`lens-dashboard:${e.wsKey}`,l=path.join(e.root,".lensmcp","events.jsonl");return $.delete(i),s.registry.appendRoutes(e.wsKey,[{host:t,prefix:o,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),(0,workspace_registry_1.registerWorkspace)({key:e.wsKey,root:e.root,base:o,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString()}),console.log(`[gateway] hosting dashboard for workspace '${e.wsKey}' \u2192 http://localhost:${a} (routed at https://${t}${o}/)`),p("info",`lens dashboard up: ${t}${o} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:t,port:a,base:o}),T(i,process.execPath,[r],{LENSMCP_EVENT_FILE:l,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:o,LENSMCP_WS_KEY:e.wsKey},!1,void 0,e.root,a),()=>{$.add(i),H.delete(a),(0,workspace_registry_1.unregisterWorkspace)(e.wsKey);const g=N.get(i);g&&B(g),N.delete(i)}},"hostWorkspaceDashboard"),_e=d(async e=>{const r=new Map;for(const o of e.routes){if(!o.lens)continue;const a=r.get(o.lens.project)??[];a.push(o),r.set(o.lens.project,a)}if(r.size===0)return()=>{};const n=path.join(e.root,".lensmcp","events.jsonl"),t=[];for(const[o,a]of r){const i=a[0].lens;if(i.started)continue;const l=await F(i.port,b),g=i.port;for(const S of a)S.lens.started=!0,S.lens.port=l,S.target=`http://localhost:${l}`;const c=Q({wsKey:e.wsKey,project:o,workspaceRoot:e.root,projectRoot:i.projectRoot,eventFile:n,routes:a,frontend:i,desiredPort:g});t.push(c),console.log(`[gateway] hosting lens app '${o}' of '${e.wsKey}' \u2192 vite :${l}`);try{ee(c,l),p("info",`lens app started: ${e.wsKey}/${o} (vite :${l})`,`cluster-lens-app:${e.wsKey}:${o}`,{kind:"lens-app-up",project:o,port:l},void 0,n)}catch(S){b.delete(l),c.state="failed",console.error(`[gateway] lens app ${e.wsKey}/${o}: ${S.message}`)}}return()=>{for(const o of t){o.disposed=!0;for(const a of[...o.generations])I(a,!0);for(const a of o.routes)a.lens&&D.delete(a.lens);D.delete(o.frontend),j.delete(o.key),W.delete(o.key),K.delete(o.key),v.delete(o.key)}}},"hostWorkspaceApps"),Se=d(async(e=2500)=>{O&&(clearInterval(O),O=void 0);const r=[...y];for(const o of r)try{o.kill("SIGTERM")}catch{}const n=d(o=>o.exitCode===null&&o.signalCode===null,"alive"),t=Date.now()+e;for(;Date.now()<t&&r.some(n);)await new Promise(o=>setTimeout(o,100));for(const o of r)if(n(o))try{o.kill("SIGKILL")}catch{}},"reapAll"),oe=d(()=>Ee({graceMs:types_1.LENS_PROBE_GRACE_MS,failureThreshold:types_1.LENS_PROBE_FAILS,cooldownMs:types_1.LENS_PROBE_COOLDOWN_MS,neverListenedGraceMs:types_1.LENS_PROBE_BOOT_GRACE_MS},types_1.LENS_PROBE_ENABLED),"probeLensFrontends");return{spawnManagedChild:T,bootSingletonsAndApps:ge,hostWorkspaceDashboard:we,hostWorkspaceApps:_e,probeLensFrontends:oe,reapAll:Se}}P(createLensChildren,"createLensChildren"),d(createLensChildren,"createLensChildren");
|
|
1
|
+
"use strict";var Re=Object.defineProperty;var R=(r,E)=>Re(r,"name",{value:E,configurable:!0});var Le=Object.defineProperty,d=R((r,E)=>Le(r,"name",{value:E,configurable:!0}),"d");Object.defineProperty(exports,"__esModule",{value:!0}),exports.probePortFree=probePortFree,exports.probePortListening=probePortListening,exports.probeWatcherHealth=probeWatcherHealth,exports.waitForPortFree=waitForPortFree,exports.viteArgPort=viteArgPort,exports.describeChildExit=describeChildExit,exports.claimPort=claimPort,exports.createLensChildren=createLensChildren;const tslib_1=require("tslib"),net=tslib_1.__importStar(require("node:net")),path=tslib_1.__importStar(require("node:path")),node_child_process_1=require("node:child_process"),lens_frontend_1=require("@lensmcp/nx-plugin/lens-frontend"),hmr_reload_1=require("./hmr-reload"),pod_env_1=require("./pod-env"),scope_1=require("./scope"),workspace_registry_1=require("./workspace-registry"),lifecycle_1=require("./lifecycle"),types_1=require("./types"),observability_1=require("./observability"),HEAL_BASE_MS=1500,HEAL_MAX_MS=3e4,HEAL_HEALTHY_MS=2e4;function tryBind(r,E){return new Promise(u=>{const _=net.createServer();_.unref(),_.once("error",p=>{const f=p.code??"";u(f==="EADDRINUSE"||f==="EACCES"?"in-use":"unavailable")}),_.listen(E===void 0?{port:r}:{port:r,host:E},()=>_.close(()=>u("free")))})}R(tryBind,"tryBind"),d(tryBind,"tryBind");async function probePortFree(r){for(const E of[void 0,"0.0.0.0","127.0.0.1","::1"])if(await tryBind(r,E)==="in-use")return!1;return!0}R(probePortFree,"probePortFree"),d(probePortFree,"probePortFree");function probeConnect(r,E,u){return new Promise(_=>{let p=!1;const f=net.createConnection({host:r,port:E});f.unref();const C=setTimeout(()=>y(!1),u);C.unref?.();function y(O){p||(p=!0,clearTimeout(C),f.destroy(),_(O))}R(y,"y"),d(y,"finish"),f.once("connect",()=>y(!0)),f.once("error",()=>y(!1))})}R(probeConnect,"probeConnect"),d(probeConnect,"probeConnect");async function probePortListening(r,E=1e3){return await probeConnect("127.0.0.1",r,E)?!0:probeConnect("::1",r,E)}R(probePortListening,"probePortListening"),d(probePortListening,"probePortListening");async function probeWatcherHealth(r,E=1500){try{const u=new AbortController,_=setTimeout(()=>u.abort(),E);_.unref?.();try{const p=await fetch(`http://127.0.0.1:${r}/__lensmcp/watcher-health`,{signal:u.signal});if(!p.ok)return null;const f=await p.json();if(typeof f?.lastFsSetEventAt!="number")return null;const C=Array.isArray(f.recentEvents)?f.recentEvents.filter(y=>y&&typeof y.path=="string"&&typeof y.at=="number"&&typeof y.sequence=="number"&&["add","addDir","unlink","unlinkDir"].includes(y.kind)):[];return{schemaVersion:f.schemaVersion===2?2:1,ready:f.ready!==!1,sequence:typeof f.sequence=="number"?f.sequence:0,lastFsSetEventAt:f.lastFsSetEventAt,fsSetEvents:typeof f.fsSetEvents=="number"?f.fsSetEvents:0,recentEvents:C}}finally{clearTimeout(_)}}catch{return null}}R(probeWatcherHealth,"probeWatcherHealth"),d(probeWatcherHealth,"probeWatcherHealth");const sleepUnref=d(r=>new Promise(E=>{setTimeout(E,r).unref?.()}),"sleepUnref");async function waitForPortFree(r,E,u={}){const _=u.isPortFree??probePortFree,p=Math.max(1,u.intervalMs??types_1.PORT_FREE_POLL_MS),f=Date.now()+Math.max(0,E);for(;;){if(await _(r))return!0;const C=f-Date.now();if(C<=0)return!1;await sleepUnref(Math.min(p,C))}}R(waitForPortFree,"waitForPortFree"),d(waitForPortFree,"waitForPortFree");function viteArgPort(r){const E=d(u=>Number.isInteger(u)&&u>0&&u<65536?u:void 0,"valid");for(let u=0;u<r.length;u+=1){const _=r[u];if(_==="--port")return E(Number(r[u+1]));if(_.startsWith("--port="))return E(Number(_.slice(7)))}}R(viteArgPort,"viteArgPort"),d(viteArgPort,"viteArgPort");function describeChildExit(r){return r.signalCode?`killed by ${r.signalCode}`:r.exitCode===null?"exit status unknown":`exit code ${r.exitCode}`}R(describeChildExit,"describeChildExit"),d(describeChildExit,"describeChildExit");async function claimPort(r,E,u,_){let p=r;for(;E.has(p)||_?.has(p)||!await u(p);)p+=1;return E.add(p),p}R(claimPort,"claimPort"),d(claimPort,"claimPort");function createLensChildren(r,E,u,_){const{emit:p}=E,f=_?.isPortFree??probePortFree,C=_?.probeWatcherHealth??probeWatcherHealth,y=[],O=new Map,T=new Map,F=new Map,H=new Map,K=new Set;let D;const N=new Map,P=new Set,J=new Set,Y=new Set,m=new Set,L=new Map,j=new WeakMap,B=new Set,Q=d((e,s,n)=>{if(B.has(e))return;B.add(e);const t=setInterval(()=>{(async()=>{if(r.stopped()||P.has(e)){clearInterval(t),B.delete(e);return}await f(s)&&(clearInterval(t),B.delete(e),console.log(`[gateway] lens child ${e}: :${s} freed \u2014 respawning.`),n())})().catch(()=>{})},types_1.LENS_PARKED_PORT_REPROBE_MS);t.unref?.()},"parkUntilPortFree"),I=d(async(e,s,n)=>{const t=await claimPort(e,s,f,n?.reserved);return t!==e&&(n?.heldBy?console.log(`[gateway] handoff: :${e} is held by ${n.heldBy} \u2014 replacement on :${t}.`):console.warn(`[gateway] port ${e} is unavailable (another process holds it \u2014 an orphan from a crashed gateway?) \u2014 using ${t} instead.`)),t},"claimFreePort"),le=d((e,s,n)=>{const t=n?.LENSMCP_FRONTEND_KEY,o=Number(n?.LENSMCP_FRONTEND_GENERATION);if(!t||!Number.isFinite(o))return;const a=[...L.get(t)?.generations??[]].find(i=>i.generation===o);a&&(e.endsWith(":vite")?a.vite=s:e.endsWith(":browser-capture")&&(a.capture=s))},"attachRespawnedGenerationChild"),W=d(e=>{if(!(e.exitCode!==null||e.signalCode!==null)){J.add(e);try{e.kill("SIGTERM")}catch{}setTimeout(()=>{if(e.exitCode===null&&e.signalCode===null)try{e.kill("SIGKILL")}catch{}},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.()}},"retireChild"),ce=d((e,s)=>{const n=N.get(e);!n||n===s||n.exitCode!==null||n.signalCode!==null||(console.warn(`[gateway] lens child ${e}: a replacement took the label \u2014 retiring the previous child (pid ${n.pid??"?"}).`),W(n))},"retireLabelHolder"),k=d((e,s,n,t,o=!1,a,i,l)=>{const h=Date.now(),c=(0,node_child_process_1.spawn)(s,n,{cwd:i??r.root,env:{...(0,pod_env_1.podBaseEnv)(process.env,r.root,i??r.root),...t??{},LENSMCP_PARENT_PID:String(process.pid)},stdio:"inherit"});y.push(c),ce(e,c),N.set(e,c),le(e,c,t);const S=e==="vite"||e.endsWith(":vite"),M=typeof t?.LENSMCP_EVENT_FILE=="string"?t.LENSMCP_EVENT_FILE:void 0,v=M&&M!==r.eventFile?M:void 0,w=S?viteArgPort(n):l;S&&T.set(c,{key:t?.LENSMCP_FRONTEND_KEY??`${i??r.root}:${t?.LENSMCP_PROJECT??"app"}`,project:t?.LENSMCP_PROJECT??"app",workspaceRoot:i??r.root,spawnedAt:h,port:w,probeFails:0,listening:!1,generation:Number(t?.LENSMCP_FRONTEND_GENERATION??0),role:t?.LENSMCP_FRONTEND_ROLE==="replacement"?"replacement":"active",...v?{bus:v}:{}});const g=e==="lens-mcp"?"lens-mcp":e==="lens-dashboard"||e.startsWith("lens-dashboard:")?"lens-dashboard":void 0;return g&&w!==void 0&&(p("info",`lens child starting: ${g} (:${w})`,`cluster-lens-child:${g}`,{kind:"lens-child-starting",project:g,label:e,pid:c.pid,port:w},void 0,v),(async()=>{const b=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!r.stopped()&&Date.now()<b;){if(c.exitCode!==null||c.signalCode!==null||P.has(e))return;if(await probePortListening(w,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){p("info",`lens child up: ${g} (:${w})`,`cluster-lens-child:${g}`,{kind:"lens-child-up",project:g,label:e,pid:c.pid,port:w},void 0,v);return}await sleepUnref(150)}})().catch(()=>{})),c.on("exit",(b,G)=>{const re=y.indexOf(c);re>=0&&y.splice(re,1),N.get(e)===c&&N.delete(e);const A=T.get(c);if(T.delete(c),J.delete(c))return;const ye=P.delete(e);if(r.stopped()||ye||(g?p("warning",`lens child exited: ${g}`,`cluster-lens-child:${g}`,{kind:"lens-child-exit",project:g,label:e,pid:c.pid,code:b,signal:G},void 0,v):A&&p("warning",`lens frontend exited: ${A.project}`,`cluster-lens-child:${A.project}`,{kind:"lens-child-exit",project:A.project,label:e,pid:c.pid,code:b,signal:G,generation:A.generation,port:A.port,ranMs:Date.now()-h},void 0,v),A&&ue(c,A)))return;const se=Date.now()-h,$=O.get(e)??{attempts:0,portConflicts:0};(async()=>{const ve=w!==void 0&&!await f(w),ae=(0,lifecycle_1.isPortConflictExit)({code:b,signal:G,ranMs:se,portHeld:ve},{fastFailMs:types_1.CHILD_START_FAIL_MS});if(ae&&$.portConflicts<types_1.MAX_PORT_CONFLICT_RETRIES)$.portConflicts+=1,O.set(e,$),console.warn(`[gateway] lens child ${e} lost the :${w} bind race (EADDRINUSE, code=${b}); waiting for the port, then retrying (port-retry ${$.portConflicts}/${types_1.MAX_PORT_CONFLICT_RETRIES}; crash budget untouched).`);else if(ae){$.portConflicts=0,O.set(e,$),console.warn(`[gateway] lens child ${e}: :${w} persistently held after ${types_1.MAX_PORT_CONFLICT_RETRIES} bind races \u2014 another server owns it (an external/shared daemon?). Parking; re-probing every ${Math.round(types_1.LENS_PARKED_PORT_REPROBE_MS/1e3)}s, will respawn if it frees.`),p("warning",`lens child parked: ${e} (:${w} held externally)`,`cluster-lens-child:${e}`,{kind:"lens-child-parked",label:e,port:w}),Q(e,w,()=>k(e,s,n,t,o,a,i,l));return}else{$.portConflicts=0,se>=HEAL_HEALTHY_MS&&($.attempts=0);const ie=Math.min(HEAL_MAX_MS,HEAL_BASE_MS*2**$.attempts);$.attempts+=1,O.set(e,$),console.warn(`[gateway] lens child ${e} exited (code=${b} sig=${G}); auto-healing in ${Math.round(ie/1e3)}s (attempt ${$.attempts}).`),await sleepUnref(ie)}r.stopped()||P.has(e)||(w!==void 0&&!await waitForPortFree(w,types_1.PORT_FREE_WAIT_MS,{isPortFree:f,intervalMs:types_1.PORT_FREE_POLL_MS})&&console.warn(`[gateway] lens child ${e}: :${w} still held after ${Math.round(types_1.PORT_FREE_WAIT_MS/1e3)}s \u2014 spawning anyway.`),!(r.stopped()||P.has(e))&&k(e,s,n,t,o,a,i,l))})().catch(()=>{})}),c},"spawnManagedChild"),Z=d(e=>{const s=`${e.wsKey}:${e.project}`,n=L.get(s);if(n)return n;const t={key:s,...e,sourceDirs:e.frontend.sourceRoots?.length?e.frontend.sourceRoots:[e.projectRoot],generation:0,state:"starting",generations:new Set,disposed:!1};L.set(s,t);for(const o of e.routes)o.lens&&(o.lens.workspaceKey??=e.wsKey,j.set(o.lens,t));return e.frontend.workspaceKey??=e.wsKey,j.set(e.frontend,t),t},"registerFrontend"),de=d(e=>{if(!types_1.LENS_WATCH_SCOPE_ENABLED)return{};const s=path.resolve(e.projectRoot),n=e.sourceDirs.map(t=>path.resolve(t)).filter(t=>t!==s);return n.length>0?{LENSMCP_WATCH_DIRS:n.join(path.delimiter)}:{}},"lensWatchScopeEnv"),ee=d((e,s,n)=>{const t=++e.generation,o=`${e.key}:g${t}:`,a=`${o}vite`,i=`${o}browser-capture`;P.delete(a),P.delete(i);const l=d((S,M,v,w,g,b)=>k(S,M,v,w,g,b,e.workspaceRoot),"spawnInRoot"),h=(0,lens_frontend_1.spawnLensFrontend)({projectRoot:e.projectRoot,workspaceRoot:e.workspaceRoot,project:e.project,eventFile:e.eventFile,port:s,chrome:!0,headless:!0,viteEnv:{LENSMCP_PROJECT:e.project,LENSMCP_FRONTEND_KEY:e.key,LENSMCP_FRONTEND_GENERATION:String(t),LENSMCP_FRONTEND_ROLE:n,...de(e),NX_DAEMON:"false",NX_ISOLATE_PLUGINS:"false"},labelPrefix:o,log:d(S=>console.log(S),"log")},l),c={ownerKey:e.key,generation:t,port:s,labelPrefix:o,vite:h?.vite??N.get(a),capture:N.get(i)};return e.generations.add(c),c},"spawnFrontendGeneration"),x=d((e,s)=>{if(!e)return;L.get(e.ownerKey)?.generations.delete(e);const n=[[`${e.labelPrefix}browser-capture`,e.capture],[`${e.labelPrefix}vite`,e.vite]];for(const[t,o]of n)P.add(t),o&&W(o);s&&m.delete(e.port)},"terminateGeneration"),pe=d(async e=>{const s=Date.now()+types_1.LENS_REPLACEMENT_READY_MS;for(;!r.stopped()&&Date.now()<s;){const n=e.vite;if(!n||n.exitCode!==null||n.signalCode!==null)return!1;if(await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS))){const t=await C(e.port);if(!t||t.ready)return!0}await sleepUnref(150)}return!1},"waitForGenerationReady"),q=d(async e=>{const s=e?.vite;return!!(e&&s&&s.exitCode===null&&s.signalCode===null&&await probePortListening(e.port,Math.min(500,types_1.LENS_PROBE_TIMEOUT_MS)))},"generationIsServing"),V=d(e=>!e.disposed&&!r.stopped()&&L.get(e.key)===e,"frontendIsCurrent"),U=d((e,s)=>{if(!V(e))return Promise.resolve(!1);if(e.replacement)return e.replacement;const n=e.active;e.state=n?"replacing":"starting",e.reason=s,e.startedAt=Date.now();const t=(async()=>{let o,a;const i=Date.now();try{const l=new Set;for(const g of L.values())g!==e&&l.add(g.desiredPort);const h=n&&n.port===e.desiredPort?`g${n.generation}`:void 0,c=await I(e.desiredPort,m,{reserved:l,heldBy:h});if(a=c,!V(e))return m.delete(c),!1;o=ee(e,c,"replacement"),e.candidate=o;const S=await q(n);console.log(`[gateway] lens handoff start: ${e.key} g${n?.generation??0}\u2192g${o.generation} :${n?.port??"down"}\u2192:${c} reason=${s}`),p("info",`lens handoff starting: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-start",wsKey:e.wsKey,project:e.project,reason:s,generation:o.generation,oldPort:n?.port,newPort:c,oldServing:S},void 0,e.eventFile===r.eventFile?void 0:e.eventFile);const M=await pe(o);if(!V(e))return x(o,!0),e.candidate=void 0,!1;if(!M){x(o,!0),e.candidate=void 0;const g=await q(n);return e.state=g?"ready":"failed",g&&(e.reason=void 0,e.startedAt=void 0),console.error(`[gateway] lens handoff failed: ${e.key} g${o.generation} did not become ready within ${types_1.LENS_REPLACEMENT_READY_MS}ms; ${e.state==="ready"?"old generation kept serving":"no active generation"}.`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:s,generation:o.generation,port:c,durationMs:Date.now()-i,oldKept:g},void 0,e.eventFile===r.eventFile?void 0:e.eventFile),!1}for(const g of e.routes)g.target=`http://localhost:${o.port}`,g.lens&&(g.lens.port=o.port);e.frontend.port=o.port,e.active=o,e.candidate=void 0,e.state="ready",e.reason=void 0,e.startedAt=void 0;const v=o.vite?T.get(o.vite):void 0;v&&(v.role="active",v.listening=!0);const w=(0,hmr_reload_1.broadcastFullReload)(r,e.key);if(console.log(`[gateway] lens handoff ready: ${e.key} g${o.generation} :${o.port} in ${Date.now()-i}ms; draining g${n?.generation??0}${w>0?`; reloading ${w} tab(s)`:""}.`),p("info",`lens handoff complete: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-complete",wsKey:e.wsKey,project:e.project,reason:s,generation:o.generation,oldPort:n?.port,newPort:o.port,durationMs:Date.now()-i,reloadedTabs:w},void 0,e.eventFile===r.eventFile?void 0:e.eventFile),n){const g=`${n.labelPrefix}browser-capture`;P.add(g),n.capture&&W(n.capture),setTimeout(()=>x(n,!0),types_1.LENS_REPLACEMENT_DRAIN_MS).unref?.()}return!0}catch(l){x(o,!0),!o&&a!==void 0&&m.delete(a),e.candidate=void 0;const h=await q(n);e.state=h?"ready":"failed",h&&(e.reason=void 0,e.startedAt=void 0);const c=l.message;return console.error(`[gateway] lens handoff failed: ${e.key}: ${c}`),p("warning",`lens handoff failed: ${e.project}`,`cluster-lens-app:${e.project}`,{kind:"lens-handoff-failed",wsKey:e.wsKey,project:e.project,reason:s,generation:o?.generation??e.generation,port:o?.port??a,durationMs:Date.now()-i,oldKept:h,error:c},void 0,e.eventFile===r.eventFile?void 0:e.eventFile),!1}finally{e.replacement=void 0}})();return e.replacement=t,t},"rollFrontend"),te=d((e,s)=>{e.active=ee(e,s,"active"),e.state="starting",e.startedAt=Date.now()},"spawnInitialFrontend"),ue=d((e,s)=>{const n=L.get(s.key);return!n||types_1.LENS_RESTART_MODE==="in-place"?!1:(n.candidate?.vite===e||n.active?.vite!==e||(n.state="starting",n.reason="child-exit",n.startedAt=Date.now(),console.warn(`[gateway] lens frontend exited: ${n.key} g${s.generation} :${s.port} (${describeChildExit(e)}); starting an alternate-port replacement.`),U(n,"child-exit")),!0)},"handleManagedViteExit");r.lensSupervisor=types_1.LENS_RESTART_MODE==="rolling"?{status(e){const s=j.get(e);return s?{state:s.state,generation:s.candidate?.generation??s.active?.generation??s.generation,reason:s.reason,startedAt:s.startedAt}:void 0},recover(e,s){const n=j.get(e);return n?U(n,s):Promise.resolve(!1)}}:void 0;let z=!1,oe=0;const Ee=d(()=>{z||Date.now()-oe<types_1.POD_STALE_SCAN_MS||(z=!0,oe=Date.now(),(async()=>{for(const e of[...L.values()]){if(r.stopped())return;const s=Date.now(),n=(0,scope_1.readSourceSetOptions)(e.workspaceRoot),t=await(0,lifecycle_1.sourceSetSnapshot)(e.workspaceRoot,e.sourceDirs,n.exclude,{ignoreTests:n.ignoreTests});if(L.get(e.key)!==e)continue;const o=e.sourceSnapshot,a=e.sourceScanStartedAt;if(e.sourceSnapshot=t,e.sourceScanStartedAt=s,!o)continue;const i=Date.now(),l=(0,lifecycle_1.diffSourceSets)(o,t,i,(0,lifecycle_1.sourceChangeWindowMs)(i,a,types_1.POD_STALE_SCAN_MS,types_1.POD_RECYCLE_SETTLE_MS));l&&(e.sourceChange=l,p("info",`source file set changed for ${e.key}`,`cluster-lens-app:${e.project}`,{kind:"source-set-changed",scoped:!0,wsKey:e.wsKey,project:e.project,added:l.added,removed:l.removed,truncated:l.truncated},void 0,e.eventFile===r.eventFile?void 0:e.eventFile))}})().catch(()=>{}).finally(()=>{z=!1}))},"scanFrontendSourceSets");let X=!1;const fe=d(async(e,s)=>{if(!X){X=!0;try{for(const[n,t]of[...T]){if(r.stopped())return;if(t.port===void 0||n.exitCode!==null||n.signalCode!==null)continue;if(await probePortListening(t.port,types_1.LENS_PROBE_TIMEOUT_MS)){if(t.probeFails=0,!t.listening){t.listening=!0;const l=L.get(t.key);l?.active?.vite===n&&(l.state="ready",l.reason=void 0),p("info",`lens app up: ${t.project} (vite :${t.port} listening)`,`cluster-lens-app:${t.project}`,{kind:"service-up",project:t.project,port:t.port},void 0,t.bus)}continue}const o=t.listening?e.graceMs:Math.max(e.graceMs,e.neverListenedGraceMs);if(Date.now()-t.spawnedAt<o){t.probeFails=0;continue}if(!s)continue;t.probeFails+=1;const a=(0,lifecycle_1.lensChildWedged)({spawnedAt:t.spawnedAt,probeFails:t.probeFails,hasListened:t.listening},F.get(t.key)??0,Date.now(),e);if(!a)continue;const i=t.listening?"its listener VANISHED (was up, now refusing)":`it NEVER bound within the ${Math.round(o/1e3)}s boot allowance`;F.set(t.key,Date.now()),t.probeFails=0,t.listening=!1,console.error(`[gateway] wedge recycle: lens app ${t.project} is ALIVE but NOT LISTENING on :${t.port} after ${Math.max(2,e.failureThreshold)} probes \u2014 ${i} \u2014 SIGKILL; a fresh vite is coming.`),p("warning",`wedge recycle: ${t.project} (${a})`,`cluster-lens-app:${t.project}`,{kind:"pod-recycle",project:t.project,reason:a,port:t.port},void 0,t.bus);try{n.kill("SIGKILL")}catch{}}}finally{X=!1}}},"probeLensChildren"),he=d(()=>{if(D||!types_1.POD_RECYCLE_ENABLED&&!types_1.LENS_PROBE_ENABLED)return;const e={graceMs:types_1.POD_STALE_GRACE_MS,settleMs:types_1.POD_RECYCLE_SETTLE_MS,cooldownMs:types_1.POD_STALE_RECYCLE_COOLDOWN_MS};D=setInterval(()=>{if(r.stopped()||T.size===0||(ne(),!types_1.POD_RECYCLE_ENABLED))return;Ee();const s=Date.now();for(const[n,t]of T){const o=L.get(t.key),a=o?.sourceChange?.changedAt??0,i=F.get(t.key)??0;(0,lifecycle_1.lensFrontendStale)(t.spawnedAt,i,a,s,e)&&((H.get(t.key)??0)>=a||K.has(t.key)||(K.add(t.key),(async()=>{try{const l=o?.sourceChange,h=l&&!l.truncated?[...l.added,...l.removed].map(v=>path.resolve(t.workspaceRoot,v)):[],c=types_1.LENS_WATCHER_PROBE_ENABLED&&t.port!==void 0?(0,lifecycle_1.lensWatcherVerdict)(await C(t.port),a,l?.windowMs??types_1.POD_STALE_SCAN_MS+types_1.POD_RECYCLE_SETTLE_MS,h):"unknown";if(c==="heard"){H.set(t.key,a),console.log(`[gateway] stale source set: lens app ${t.project} watcher CONFIRMED the change \u2014 no recycle, HMR intact.`),p("info",`stale check: ${t.project} watcher confirmed \u2014 no recycle`,`cluster-lens-app:${t.project}`,{kind:"pod-stale-verified",project:t.project},void 0,t.bus);return}if(c==="unknown"&&types_1.LENS_WATCHER_UNVERIFIED==="keep"){console.log(`[gateway] stale source set: lens app ${t.project} unverifiable (no watcher testimony) \u2014 keeping it (LENSMCP_LENS_WATCHER_UNVERIFIED=keep).`);return}if(n.exitCode!==null||n.signalCode!==null)return;F.set(t.key,Date.now());const S=L.get(t.key);if(types_1.LENS_RESTART_MODE==="rolling"&&S){console.log(`[gateway] stale refresh: lens app ${t.key} (stale-source-set) \u2014 watcher ${c==="missed"?"missed the exact path change":"unverifiable"}; preparing a standby without dropping traffic.`),p("warning",`stale refresh: ${t.project} (stale-source-set)`,`cluster-lens-app:${t.project}`,{kind:"pod-refresh",wsKey:S.wsKey,project:t.project,reason:"stale-source-set",watcher:c,added:l?.added,removed:l?.removed},void 0,t.bus),await U(S,"stale-source-set");return}t.listening=!1,console.log(`[gateway] zombie recycle: lens app ${t.project} (stale-source-set) \u2014 watcher ${c==="missed"?"SILENT across the change":"unverifiable"}; restarting it`),p("warning",`zombie recycle: ${t.project} (stale-source-set)`,`cluster-lens-app:${t.project}`,{kind:"pod-recycle",project:t.project,reason:"stale-source-set",watcher:c},void 0,t.bus);const M=(0,hmr_reload_1.broadcastFullReload)(r,t.key);M>0&&console.log(`[gateway] \u2192 told ${M} open tab(s) to reload (stale optimize-dep generation)`);try{n.kill("SIGTERM")}catch{}setTimeout(()=>{if(n.exitCode===null&&n.signalCode===null){console.log(`[gateway] zombie recycle: lens app ${t.project} ignored SIGTERM for ${Math.round(types_1.LENS_RECYCLE_KILL_GRACE_MS/1e3)}s \u2014 escalating to SIGKILL.`);try{n.kill("SIGKILL")}catch{}}},types_1.LENS_RECYCLE_KILL_GRACE_MS).unref?.()}finally{K.delete(t.key)}})()))}},Math.min(types_1.POD_STALE_SCAN_MS,15e3)),D.unref?.()},"startLensSweeper"),ge=d(async()=>{const e=[...new Map(r.routes.filter(t=>t.lens).map(t=>[t.project,t.lens])).values()],s=u.dashboard!==!1,n=u.mcp!==!1&&e.length>0;if(s){const t=(0,lens_frontend_1.findDashboardBundle)(r.root);if(!t)console.warn("[gateway] lens dashboard bundle not found \u2014 skipping. Install the self-contained CLI: `npm i -D lensmcp` (it ships `bundled/dashboard.js`), or `yarn nx build @lensmcp/lensmcp-mcp` in-repo.");else{const o=(0,scope_1.readLensScope)(r.root),a=await I(u.dashboardPort??o.dashboardPort,Y),i=u.lensHost??"lensmcp.local",l=o.basePath;r.registry.appendRoutes(r.wsKey,[{host:i,prefix:l,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),r.rebuildRoutes(),(0,workspace_registry_1.registerWorkspace)({key:o.key,root:r.root,base:l,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString()}),console.log(`[gateway] starting lens dashboard \u2192 http://localhost:${a} (routed at https://${i}${l}/)`),p("info",`lens dashboard up: ${i}${l} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:i,port:a,base:l}),k("lens-dashboard",process.execPath,[t],{LENSMCP_EVENT_FILE:r.eventFile,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:l},!1,void 0,void 0,a)}}if(n){const t=(0,lens_frontend_1.findMcpBundle)(r.root);if(!t)console.warn("[gateway] MCP server bundle not found \u2014 skipping (lens apps will still publish to the bus; an external `lensmcp mcp` can read it). Install: `npm i -D lensmcp`.");else{const o=(0,scope_1.readLensScope)(r.root),a=Number(process.env.LENSMCP_PORT??o.mcpHttpPort),i=d(()=>{console.log(`[gateway] starting lens MCP server on 127.0.0.1:${a} (${t})`),k("lens-mcp",process.execPath,[t],{LENSMCP_EVENT_FILE:r.eventFile,LENSMCP_PROCESS_ROLE:"mcp",LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_PORT:String(a),LENSMCP_WORKSPACE_KEY:o.key,LENSMCP_WORKSPACE_ROOT:r.root},!1,void 0,void 0,a)},"spawnMcp");await f(a)?i():(console.warn(`[gateway] lens MCP port :${a} is already served \u2014 an external lensmcp server (a shared daemon?) owns this workspace's MCP; not spawning a second. Re-probing every ${Math.round(types_1.LENS_PARKED_PORT_REPROBE_MS/1e3)}s; will take over if it frees.`),p("info",`lens MCP served externally on :${a} \u2014 gateway parked its own`,"cluster-lens-child:lens-mcp",{kind:"lens-child-up",project:"lens-mcp",label:"lens-mcp",port:a,external:!0}),Q("lens-mcp",a,i))}}for(const t of e){if(t.started)continue;t.started=!0;const o=t.port,a=(r.registry.get(r.wsKey)?.routes??r.routes).filter(h=>h.lens?.project===t.project),i=await I(t.port,m);for(const h of a)h.lens&&(h.lens.port=i),h.target=`http://localhost:${i}`;t.port=i;const l=Z({wsKey:r.wsKey,project:t.project,workspaceRoot:r.root,projectRoot:t.projectRoot,eventFile:r.eventFile,routes:a,frontend:t,desiredPort:o});try{te(l,i),p("info",`lens app started: ${t.project} (vite :${t.port})`,`cluster-lens-app:${t.project}`,{kind:"lens-app-up",project:t.project,port:t.port})}catch(h){m.delete(i),l.state="failed",console.error(`[gateway] lens app ${t.project}: ${h.message}`)}}he()},"bootSingletonsAndApps"),we=d(async e=>{if(u.dashboard===!1)return;const s=(0,lens_frontend_1.findDashboardBundle)(r.root);if(!s)return;const n=(0,scope_1.readLensScope)(e.root),t=u.lensHost??"lensmcp.local",o=n.basePath,a=await I(n.dashboardPort,Y),i=`lens-dashboard:${e.wsKey}`,l=path.join(e.root,".lensmcp","events.jsonl");return P.delete(i),r.registry.appendRoutes(e.wsKey,[{host:t,prefix:o,project:observability_1.LENS_DASHBOARD_PROJECT,target:`http://localhost:${a}`}]),(0,workspace_registry_1.registerWorkspace)({key:e.wsKey,root:e.root,base:o,pid:process.pid,procStamp:(0,workspace_registry_1.processStamp)(process.pid),updatedAt:new Date().toISOString()}),console.log(`[gateway] hosting dashboard for workspace '${e.wsKey}' \u2192 http://localhost:${a} (routed at https://${t}${o}/)`),p("info",`lens dashboard up: ${t}${o} \u2192 :${a}`,"cluster-lens-dashboard",{kind:"lens-dashboard-up",host:t,port:a,base:o}),k(i,process.execPath,[s],{LENSMCP_EVENT_FILE:l,LENSMCP_PROCESS_ROLE:"dashboard",LENSMCP_DASHBOARD_PORT:String(a),LENSMCP_DASHBOARD_BASE:o,LENSMCP_WS_KEY:e.wsKey},!1,void 0,e.root,a),()=>{P.add(i),Y.delete(a),(0,workspace_registry_1.unregisterWorkspace)(e.wsKey);const h=N.get(i);h&&W(h),N.delete(i)}},"hostWorkspaceDashboard"),_e=d(async e=>{const s=new Map;for(const o of e.routes){if(!o.lens)continue;const a=s.get(o.lens.project)??[];a.push(o),s.set(o.lens.project,a)}if(s.size===0)return()=>{};const n=path.join(e.root,".lensmcp","events.jsonl"),t=[];for(const[o,a]of s){const i=a[0].lens;if(i.started)continue;const l=await I(i.port,m),h=i.port;for(const S of a)S.lens.started=!0,S.lens.port=l,S.target=`http://localhost:${l}`;const c=Z({wsKey:e.wsKey,project:o,workspaceRoot:e.root,projectRoot:i.projectRoot,eventFile:n,routes:a,frontend:i,desiredPort:h});t.push(c),console.log(`[gateway] hosting lens app '${o}' of '${e.wsKey}' \u2192 vite :${l}`);try{te(c,l),p("info",`lens app started: ${e.wsKey}/${o} (vite :${l})`,`cluster-lens-app:${e.wsKey}:${o}`,{kind:"lens-app-up",project:o,port:l},void 0,n)}catch(S){m.delete(l),c.state="failed",console.error(`[gateway] lens app ${e.wsKey}/${o}: ${S.message}`)}}return()=>{for(const o of t){o.disposed=!0;for(const a of[...o.generations])x(a,!0);for(const a of o.routes)a.lens&&j.delete(a.lens);j.delete(o.frontend),F.delete(o.key),H.delete(o.key),K.delete(o.key),L.delete(o.key)}}},"hostWorkspaceApps"),Se=d(async(e=2500)=>{D&&(clearInterval(D),D=void 0);const s=[...y];for(const o of s)try{o.kill("SIGTERM")}catch{}const n=d(o=>o.exitCode===null&&o.signalCode===null,"alive"),t=Date.now()+e;for(;Date.now()<t&&s.some(n);)await new Promise(o=>setTimeout(o,100));for(const o of s)if(n(o))try{o.kill("SIGKILL")}catch{}},"reapAll"),ne=d(()=>fe({graceMs:types_1.LENS_PROBE_GRACE_MS,failureThreshold:types_1.LENS_PROBE_FAILS,cooldownMs:types_1.LENS_PROBE_COOLDOWN_MS,neverListenedGraceMs:types_1.LENS_PROBE_BOOT_GRACE_MS},types_1.LENS_PROBE_ENABLED),"probeLensFrontends");return{spawnManagedChild:k,bootSingletonsAndApps:ge,hostWorkspaceDashboard:we,hostWorkspaceApps:_e,probeLensFrontends:ne,reapAll:Se}}R(createLensChildren,"createLensChildren"),d(createLensChildren,"createLensChildren");
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var D=Object.defineProperty;var
|
|
2
|
-
`;busHygiene?.maybeRotateEventFile(i,g.length),fs.appendFileSync(i,g)}catch{}},"emit"),m=o(e=>{const r=hdr(e.headers["x-lensmcp-flow-id"]);let
|
|
1
|
+
"use strict";var D=Object.defineProperty;var p=(t,c)=>D(t,"name",{value:c,configurable:!0});var b=Object.defineProperty,o=p((t,c)=>b(t,"name",{value:c,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.LENS_DASHBOARD_PROJECT=void 0,exports.createObservability=createObservability;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),redact_1=require("@lensmcp/core/redact"),busHygiene=(()=>{try{return require("@lensmcp/node-instrumentation")}catch{return}})();exports.LENS_DASHBOARD_PROJECT="(lens-dashboard)";function ownerOf(t){return t?.svc?{root:t.svc.root,wsKey:t.svc.wsKey}:t?.lens?{...t.lens.workspaceRoot?{root:t.lens.workspaceRoot}:{},...t.lens.workspaceKey?{wsKey:t.lens.workspaceKey}:{}}:{}}p(ownerOf,"ownerOf"),o(ownerOf,"ownerOf");function busFileFor(t,c){const{root:u}=ownerOf(t);if(!u)return;const l=path.join(u,".lensmcp","events.jsonl");return l===c?void 0:l}p(busFileFor,"busFileFor"),o(busFileFor,"busFileFor");const hdr=o(t=>typeof t=="string"&&t!==""?t:Array.isArray(t)?t[0]:void 0,"hdr");function createObservability(t,c){const u=o(()=>Date.now().toString(36)+Math.random().toString(36).slice(2,12),"eid"),l=busHygiene?.createEventFloodGuard({burst:30,perSec:5}),h=o((e,r,s,n,a,d)=>{const i=d??t;try{const w=l?l.admit(s):{ok:!0,suppressed:0};if(!w.ok)return;fs.mkdirSync(path.dirname(i),{recursive:!0});const y=n&&(0,redact_1.redactDeep)(n),g=JSON.stringify({id:u(),sessionId:"pending",timestamp:Date.now(),source:"gateway",category:"cluster",severity:e,context:(0,redact_1.redactDeep)({sessionId:"pending",...a}),fingerprint:s,title:(0,redact_1.safeTitle)(r),raw:w.suppressed>0?{...y,floodSuppressed:w.suppressed}:y})+`
|
|
2
|
+
`;busHygiene?.maybeRotateEventFile(i,g.length),fs.appendFileSync(i,g)}catch{}},"emit"),m=o(e=>{const r=hdr(e.headers["x-lensmcp-flow-id"]);let s=hdr(e.headers["x-request-id"]);if(!(!r&&!s&&!hdr(e.headers.traceparent)))return s||(s=u(),e.headers["x-request-id"]=s),{startedAt:Date.now(),method:(e.method??"GET").toUpperCase(),host:(e.headers.host||"").split(":")[0],url:e.url??"/",steps:[],...r?{flowId:r}:{},...s?{requestId:s}:{},...hdr(e.headers["x-lensmcp-origin-node-id"])?{originNodeId:hdr(e.headers["x-lensmcp-origin-node-id"])}:{}}},"beginTrace"),v=o((e,r,s)=>{e&&e.steps.push({step:r,atMs:Date.now()-e.startedAt,...s})},"traceStep"),S=o((e,r,s,n,a)=>{if(!e||e.done||(e.done=!0,r===exports.LENS_DASHBOARD_PROJECT&&s<500))return;const d=Date.now()-e.startedAt;h(s>=500?"error":"info",`gateway ${e.method} ${e.host}${e.url} \u2192 ${s} (${d}ms)`,`gateway-request:${r}`,{kind:"gateway-request",project:r,host:e.host,method:e.method,url:e.url,status:s,durationMs:d,startedAt:e.startedAt,steps:e.steps,...ownerOf(a).wsKey?{wsKey:ownerOf(a).wsKey}:{},...n},{...e.flowId?{flowId:e.flowId}:{},...e.requestId?{requestId:e.requestId}:{},...e.originNodeId?{originNodeId:e.originNodeId}:{}},busFileFor(a,t))},"finishTrace"),f=new Map;return{emit:h,eid:u,beginTrace:m,traceStep:v,finishTrace:S,recordEdge:o((e,r,s,n)=>{if(e.project===exports.LENS_DASHBOARD_PROJECT&&s<500&&s!==0)return;const a=e.host??"(default)",d=(n?n+"\u21D2":"")+a+"\u2192"+e.project,i=f.get(d)??{host:a,project:e.project,caller:n,count:0,totalMs:0,errors:0,...busFileFor(e,t)?{busFile:busFileFor(e,t)}:{},...ownerOf(e).wsKey?{wsKey:ownerOf(e).wsKey}:{}};i.count+=1,i.totalMs+=r,(s>=500||s===0)&&(i.errors+=1),f.set(d,i)},"recordEdge"),startEdgeFlusher:o(()=>{const e=setInterval(()=>{for(const r of f.values()){const s=Math.round(r.totalMs/r.count);h(r.errors?"warning":"info",`traffic ${r.host} \u2192 ${r.project}: ${r.count} req, ~${s}ms${r.errors?`, ${r.errors} errors`:""}`,`gateway-traffic:${r.host}->${r.project}`,{kind:"gateway-traffic",host:r.host,project:r.project,caller:r.caller,count:r.count,avgMs:s,errors:r.errors,...r.wsKey?{wsKey:r.wsKey}:{}},void 0,r.busFile)}f.clear()},c.trafficFlushMs);return e.unref(),e},"startEdgeFlusher")}}p(createObservability,"createObservability"),o(createObservability,"createObservability");
|
|
@@ -117,6 +117,12 @@ export interface LensFrontend {
|
|
|
117
117
|
project: string;
|
|
118
118
|
/** Owning workspace, used to isolate same-named frontends in the shared daemon. */
|
|
119
119
|
workspaceKey?: string;
|
|
120
|
+
/** Absolute WORKSPACE root of the owning workspace — the parent of `.lensmcp/events.jsonl`.
|
|
121
|
+
* A pod route carries this on its `ServiceCtl.root`; a lens route had only `projectRoot`
|
|
122
|
+
* (the app dir), so `ownerOf` could not resolve the owning bus and every gateway event for
|
|
123
|
+
* the browser-facing host (`app.<apex>`) was narrated into the DAEMON's bus instead of the
|
|
124
|
+
* guest workspace's — the browser's own request hop went missing from that workspace's flows. */
|
|
125
|
+
workspaceRoot?: string;
|
|
120
126
|
/** Absolute project root (holds vite.config.*). */
|
|
121
127
|
projectRoot: string;
|
|
122
128
|
/** The pinned Vite dev port (also the upstream target's port). */
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ForkTsCheckReporterOptions {
|
|
2
|
+
appName: string;
|
|
3
|
+
tsConfig: string;
|
|
4
|
+
workspaceRoot: string;
|
|
5
|
+
/** Override the lens bus file; defaults to `LENSMCP_EVENT_FILE` / `<root>/.lensmcp/events.jsonl`. */
|
|
6
|
+
eventFile?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class ForkTsCheckReporterPlugin {
|
|
9
|
+
private readonly opts;
|
|
10
|
+
private startedAt;
|
|
11
|
+
constructor(opts: ForkTsCheckReporterOptions);
|
|
12
|
+
apply(compiler: any): void;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var p=Object.defineProperty;var s=(e,t)=>p(e,"name",{value:t,configurable:!0});var a=Object.defineProperty,r=s((e,t)=>a(e,"name",{value:t,configurable:!0}),"r");Object.defineProperty(exports,"__esModule",{value:!0}),exports.ForkTsCheckReporterPlugin=void 0;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),typecheck_bus_1=require("./typecheck-bus");function loadForkTsChecker(e){const t=[];try{t.push(path.dirname(require.resolve("@nx/webpack/package.json",{paths:[e]})))}catch{}t.push(e,__dirname);for(const o of t)try{return require(require.resolve("fork-ts-checker-webpack-plugin",{paths:[o]}))}catch{}return null}s(loadForkTsChecker,"loadForkTsChecker"),r(loadForkTsChecker,"loadForkTsChecker");function toDiagnostic(e,t){return{file:e.file?path.relative(t,e.file)||e.file:"<unknown>",line:e.location?.start?.line??0,column:e.location?.start?.column??0,severity:e.severity==="warning"?"warning":"error",code:/^TS\d+$/.test(e.code)?e.code:`TS${e.code}`,message:e.message}}s(toDiagnostic,"toDiagnostic"),r(toDiagnostic,"toDiagnostic");class ForkTsCheckReporterPlugin{static{s(this,"ForkTsCheckReporterPlugin")}static{r(this,"ForkTsCheckReporterPlugin")}constructor(t){this.startedAt=0,this.opts=t}apply(t){const o=loadForkTsChecker(this.opts.workspaceRoot)?.getCompilerHooks;if(typeof o!="function")return;let c;try{c=o(t)}catch{return}c.start?.tapPromise("LensmcpForkTsCheckReporter",async i=>(this.startedAt=Date.now(),i)),c.issues?.tap("LensmcpForkTsCheckReporter",i=>{try{(0,typecheck_bus_1.publishTypecheckDiagnostics)({workspaceRoot:this.opts.workspaceRoot,project:this.opts.appName,tool:"fork-ts-checker",tsConfig:this.opts.tsConfig,diagnostics:(i??[]).map(n=>toDiagnostic(n,this.opts.workspaceRoot)),durationMs:this.startedAt?Date.now()-this.startedAt:0,...this.opts.eventFile?{eventFile:this.opts.eventFile}:{}})}catch{}return i})}}exports.ForkTsCheckReporterPlugin=ForkTsCheckReporterPlugin;
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { type NodeExternalsConfig, type ScopePatterns, buildScopePatterns } from './build-scope-patterns';
|
|
2
2
|
export { createDevWebpackConfig, type DevWebpackOptions } from './create-webpack-dev';
|
|
3
3
|
export { createProdWebpackConfig, type ProdWebpackOptions } from './create-webpack-prod';
|
|
4
|
-
export { appendTypecheckEvents, buildTypecheckRunEvents, parseTscDiagnosticLine, parseTscOutput, publishTypecheckRun, resolveEventFile, type TscDiagnostic, type TypecheckBusEvent, } from './typecheck-bus';
|
|
4
|
+
export { appendTypecheckEvents, buildTypecheckRunEvents, parseTscDiagnosticLine, parseTscOutput, publishTypecheckDiagnostics, publishTypecheckRun, resolveEventFile, type TscDiagnostic, type TypecheckBusEvent, } from './typecheck-bus';
|
|
5
|
+
export { ForkTsCheckReporterPlugin, type ForkTsCheckReporterOptions } from './fork-ts-check-reporter';
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var p=Object.defineProperty;var c=(t
|
|
1
|
+
"use strict";var p=Object.defineProperty;var c=(r,t)=>p(r,"name",{value:t,configurable:!0});var n=Object.defineProperty,e=c((r,t)=>n(r,"name",{value:t,configurable:!0}),"e");Object.defineProperty(exports,"__esModule",{value:!0}),exports.ForkTsCheckReporterPlugin=exports.resolveEventFile=exports.publishTypecheckRun=exports.publishTypecheckDiagnostics=exports.parseTscOutput=exports.parseTscDiagnosticLine=exports.buildTypecheckRunEvents=exports.appendTypecheckEvents=exports.createProdWebpackConfig=exports.createDevWebpackConfig=exports.buildScopePatterns=void 0;var build_scope_patterns_1=require("./build-scope-patterns");Object.defineProperty(exports,"buildScopePatterns",{enumerable:!0,get:e(function(){return build_scope_patterns_1.buildScopePatterns},"get")});var create_webpack_dev_1=require("./create-webpack-dev");Object.defineProperty(exports,"createDevWebpackConfig",{enumerable:!0,get:e(function(){return create_webpack_dev_1.createDevWebpackConfig},"get")});var create_webpack_prod_1=require("./create-webpack-prod");Object.defineProperty(exports,"createProdWebpackConfig",{enumerable:!0,get:e(function(){return create_webpack_prod_1.createProdWebpackConfig},"get")});var typecheck_bus_1=require("./typecheck-bus");Object.defineProperty(exports,"appendTypecheckEvents",{enumerable:!0,get:e(function(){return typecheck_bus_1.appendTypecheckEvents},"get")}),Object.defineProperty(exports,"buildTypecheckRunEvents",{enumerable:!0,get:e(function(){return typecheck_bus_1.buildTypecheckRunEvents},"get")}),Object.defineProperty(exports,"parseTscDiagnosticLine",{enumerable:!0,get:e(function(){return typecheck_bus_1.parseTscDiagnosticLine},"get")}),Object.defineProperty(exports,"parseTscOutput",{enumerable:!0,get:e(function(){return typecheck_bus_1.parseTscOutput},"get")}),Object.defineProperty(exports,"publishTypecheckDiagnostics",{enumerable:!0,get:e(function(){return typecheck_bus_1.publishTypecheckDiagnostics},"get")}),Object.defineProperty(exports,"publishTypecheckRun",{enumerable:!0,get:e(function(){return typecheck_bus_1.publishTypecheckRun},"get")}),Object.defineProperty(exports,"resolveEventFile",{enumerable:!0,get:e(function(){return typecheck_bus_1.resolveEventFile},"get")});var fork_ts_check_reporter_1=require("./fork-ts-check-reporter");Object.defineProperty(exports,"ForkTsCheckReporterPlugin",{enumerable:!0,get:e(function(){return fork_ts_check_reporter_1.ForkTsCheckReporterPlugin},"get")});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lensmcp/cluster",
|
|
3
|
-
"version": "1.22.
|
|
3
|
+
"version": "1.22.5",
|
|
4
4
|
"description": "Run your Nx workspace as a local production cluster: pods on unix sockets with true HMR, one https gateway with per-project domains, scale-from-zero, autoscale, idle-kill, local-CA TLS — observed by the LensMCP lens.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@lensmcp/core": "1.22.
|
|
61
|
-
"@lensmcp/node-instrumentation": "1.22.
|
|
62
|
-
"@lensmcp/nx-plugin": "1.22.
|
|
60
|
+
"@lensmcp/core": "1.22.5",
|
|
61
|
+
"@lensmcp/node-instrumentation": "1.22.5",
|
|
62
|
+
"@lensmcp/nx-plugin": "1.22.5",
|
|
63
63
|
"fastify": "^5.8.5",
|
|
64
64
|
"@fastify/reply-from": "^12.6.2",
|
|
65
65
|
"@typescript/native-preview": "^7.0.0-dev.20260707.2",
|
package/tsgo-check-plugin.d.ts
CHANGED
|
@@ -116,11 +116,16 @@ export declare function reportTsgoUnavailable(args: {
|
|
|
116
116
|
eventFile?: string;
|
|
117
117
|
}): void;
|
|
118
118
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
119
|
+
* The `paths` in effect for a config, and the directory they are anchored at.
|
|
120
|
+
*
|
|
121
|
+
* Walks the `extends` chain leaf-first; the nearest declaration wins (tsconfig REPLACES `paths`,
|
|
122
|
+
* it does not merge them). The anchor is the nearest `baseUrl`, resolved against the file that
|
|
123
|
+
* declared IT — or, with no baseUrl anywhere, the file that declared the paths.
|
|
123
124
|
*/
|
|
125
|
+
export declare function effectivePaths(tsConfig: string, seen?: Set<string>): {
|
|
126
|
+
paths: Record<string, string[]>;
|
|
127
|
+
anchorDir: string;
|
|
128
|
+
} | null;
|
|
124
129
|
export declare function writeShimTsconfig(appName: string, tsConfig: string, workspaceRoot: string): string;
|
|
125
130
|
export declare class TsgoCheckPlugin {
|
|
126
131
|
private readonly opts;
|
package/tsgo-check-plugin.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
|
|
3
|
-
`)
|
|
4
|
-
`)[
|
|
1
|
+
"use strict";var m=Object.defineProperty;var a=(e,t)=>m(e,"name",{value:t,configurable:!0});var d=Object.defineProperty,c=a((e,t)=>d(e,"name",{value:t,configurable:!0}),"c");Object.defineProperty(exports,"__esModule",{value:!0}),exports.TsgoCheckPlugin=exports.TSGO_MISSING_CAUSE=exports.TSGO_PACKAGE=void 0,exports.resolveTsgoPackageDir=resolveTsgoPackageDir,exports.resolveTsgoBin=resolveTsgoBin,exports.reportTsgoUnavailable=reportTsgoUnavailable,exports.effectivePaths=effectivePaths,exports.writeShimTsconfig=writeShimTsconfig;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),typecheck_bus_1=require("./typecheck-bus");exports.TSGO_PACKAGE="@typescript/native-preview";function shimNames(e){return e==="win32"?["tsgo.cmd","tsgo.exe"]:["tsgo"]}a(shimNames,"shimNames"),c(shimNames,"shimNames");function isExecutableFile(e,t){try{if(!fs.statSync(e).isFile())return!1}catch{return!1}if(t==="win32")return!0;try{return fs.accessSync(e,fs.constants.X_OK),!0}catch{return!1}}a(isExecutableFile,"isExecutableFile"),c(isExecutableFile,"isExecutableFile");function resolveTsgoPackageDir(){try{return path.dirname(require.resolve(`${exports.TSGO_PACKAGE}/package.json`))}catch{}try{let e=path.dirname(require.resolve(exports.TSGO_PACKAGE));for(let t=0;t<6;t++){const i=path.join(e,"package.json");if(fs.existsSync(i))try{const{name:n}=JSON.parse(fs.readFileSync(i,"utf8"));if(n===exports.TSGO_PACKAGE)return e}catch{}const s=path.dirname(e);if(s===e)break;e=s}}catch{}return null}a(resolveTsgoPackageDir,"resolveTsgoPackageDir"),c(resolveTsgoPackageDir,"resolveTsgoPackageDir");function packageDeclaredBin(e){try{const{bin:t}=JSON.parse(fs.readFileSync(path.join(e,"package.json"),"utf8")),i=typeof t=="string"?t:t?.tsgo;return i?path.join(e,i):null}catch{return null}}a(packageDeclaredBin,"packageDeclaredBin"),c(packageDeclaredBin,"packageDeclaredBin");function ownBinCandidates(e,t){const i=path.resolve(e,"..","..",".bin"),s=shimNames(t).map(o=>path.join(i,o)),n=t==="win32"?null:packageDeclaredBin(e);return n?[n,...s]:s}a(ownBinCandidates,"ownBinCandidates"),c(ownBinCandidates,"ownBinCandidates");function resolveTsgoBin(e,t,i={}){const s=i.platform??process.platform,n=i.isExecutable??(r=>isExecutableFile(r,s));if(t)return n(t)?t:null;for(const r of shimNames(s)){const l=path.join(e,"node_modules",".bin",r);if(n(l))return l}const o=(i.ownPackageDir??resolveTsgoPackageDir)();return o?ownBinCandidates(o,s).find(n)??null:null}a(resolveTsgoBin,"resolveTsgoBin"),c(resolveTsgoBin,"resolveTsgoBin"),exports.TSGO_MISSING_CAUSE=`tsgo binary not found \u2014 @lensmcp/cluster depends on ${exports.TSGO_PACKAGE}, so an absent binary means an incomplete install (reinstall node_modules), a platform with no ${exports.TSGO_PACKAGE} build, or a LENSMCP_TSGO_BIN override pointing at a missing or non-executable file`;function reportTsgoUnavailable(e){try{(0,typecheck_bus_1.publishTypecheckRun)({workspaceRoot:e.workspaceRoot,project:e.appName,tool:"tsgo",tsConfig:e.tsConfig,output:"",durationMs:0,toolError:e.detail,...e.eventFile?{eventFile:e.eventFile}:{}})}catch{}}a(reportTsgoUnavailable,"reportTsgoUnavailable"),c(reportTsgoUnavailable,"reportTsgoUnavailable");function parseJsonc(e){let t="",i=!1,s=!1,n=!1;for(let o=0;o<e.length;o++){const r=e[o],l=e[o+1];if(s){r===`
|
|
2
|
+
`&&(s=!1,t+=r);continue}if(n){r==="*"&&l==="/"&&(n=!1,o++);continue}if(i){t+=r,r==="\\"?(t+=l??"",o++):r==='"'&&(i=!1);continue}if(r==='"'){i=!0,t+=r;continue}if(r==="/"&&l==="/"){s=!0,o++;continue}if(r==="/"&&l==="*"){n=!0,o++;continue}t+=r}try{return JSON.parse(t.replace(/,(\s*[}\]])/g,"$1"))}catch{return null}}a(parseJsonc,"parseJsonc"),c(parseJsonc,"parseJsonc");function resolveExtends(e,t){if(!e.startsWith(".")&&!path.isAbsolute(e))return null;const i=path.isAbsolute(e)?e:path.resolve(t,e);for(const s of[i,`${i}.json`,path.join(i,"tsconfig.json")])try{if(fs.statSync(s).isFile())return s}catch{}return null}a(resolveExtends,"resolveExtends"),c(resolveExtends,"resolveExtends");function effectivePaths(e,t=new Set){if(t.has(e))return null;t.add(e);let i;try{i=fs.readFileSync(e,"utf8")}catch{return null}const s=parseJsonc(i);if(!s)return null;const n=path.dirname(e),o=s.compilerOptions??{},r=Array.isArray(s.extends)?s.extends.filter(h=>typeof h=="string"):typeof s.extends=="string"?[s.extends]:[],l=c(()=>{for(const h of[...r].reverse()){const f=resolveExtends(h,n);if(!f)continue;const g=effectivePaths(f,t);if(g)return g}return null},"inherited"),p=o.paths,u=typeof o.baseUrl=="string"?path.resolve(n,o.baseUrl):void 0;if(!p){const h=l();return h?{paths:h.paths,anchorDir:u??h.anchorDir}:null}return{paths:p,anchorDir:u??l()?.anchorDir??n}}a(effectivePaths,"effectivePaths"),c(effectivePaths,"effectivePaths");function writeShimTsconfig(e,t,i){const s=path.join(i,"tmp","lensmcp-tsgo");fs.mkdirSync(s,{recursive:!0});const n=path.join(s,`${e}.tsconfig.json`),o=effectivePaths(t),r=o?Object.fromEntries(Object.entries(o.paths).map(([l,p])=>[l,(Array.isArray(p)?p:[]).map(u=>path.isAbsolute(u)?u:path.resolve(o.anchorDir,u))])):void 0;return fs.writeFileSync(n,JSON.stringify({extends:t,compilerOptions:{module:"preserve",moduleResolution:"bundler",isolatedModules:!1,baseUrl:null,...r&&Object.keys(r).length?{paths:r}:{}}},null,2)),n}a(writeShimTsconfig,"writeShimTsconfig"),c(writeShimTsconfig,"writeShimTsconfig");class TsgoCheckPlugin{static{a(this,"TsgoCheckPlugin")}static{c(this,"TsgoCheckPlugin")}constructor(t){this.timer=null,this.inflight=null,this.shimPath=null,this.disabled=!1,this.opts=t,this.spawnImpl=t.spawnImpl??node_child_process_1.spawn}apply(t){t.hooks.done.tap("TsgoCheckPlugin",i=>{i.hasErrors()||this.schedule()})}schedule(){this.disabled||(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>this.run(),this.opts.debounceMs??500),this.timer.unref?.())}publish(t){if(this.opts.publishEvents!==!1)try{(0,typecheck_bus_1.publishTypecheckRun)({workspaceRoot:this.opts.workspaceRoot,project:this.opts.appName,tool:"tsgo",tsConfig:this.opts.tsConfig,output:t.output,durationMs:t.durationMs,...t.toolError?{toolError:t.toolError}:{},...this.opts.eventFile?{eventFile:this.opts.eventFile}:{}})}catch{}}run(){const t=resolveTsgoBin(this.opts.workspaceRoot,this.opts.binPath);if(!t){this.disabled=!0;const o=`${exports.TSGO_MISSING_CAUSE}. Type checking is disabled for the rest of this session`;console.warn(`[tsgo] ${this.opts.appName}: ${o}.`),this.publish({output:"",durationMs:0,toolError:o});return}this.inflight&&(this.inflight.kill("SIGTERM"),this.inflight=null),this.shimPath||(this.shimPath=writeShimTsconfig(this.opts.appName,this.opts.tsConfig,this.opts.workspaceRoot));const i=Date.now(),s=this.spawnImpl(t,["--noEmit","--pretty","false","-p",this.shimPath],{cwd:this.opts.workspaceRoot,stdio:["ignore","pipe","pipe"]});this.inflight=s;let n="";s.stdout?.on("data",o=>{n+=o.toString()}),s.stderr?.on("data",o=>{n+=o.toString()}),s.on("error",()=>{this.inflight===s&&(this.inflight=null),console.warn(`[tsgo] ${this.opts.appName}: failed to spawn ${t}`),this.publish({output:"",durationMs:Date.now()-i,toolError:`failed to spawn ${t}`})}),s.on("close",(o,r)=>{if(this.inflight===s&&(this.inflight=null),r)return;const l=Date.now()-i,p=(l/1e3).toFixed(1);if(o===0){console.log(`[tsgo] ${this.opts.appName}: types clean (${p}s)`),this.publish({output:"",durationMs:l});return}n.trim()&&process.stdout.write(n.endsWith(`
|
|
3
|
+
`)?n:`${n}
|
|
4
|
+
`);const u=(n.match(/error TS\d+/g)??[]).length;console.log(`[tsgo] ${this.opts.appName}: ${u} type error${u===1?"":"s"} (${p}s)`),this.publish({output:n,durationMs:l,...u===0?{toolError:`tsgo exited ${o} with no diagnostics: ${firstLine(n)}`}:{}})})}}exports.TsgoCheckPlugin=TsgoCheckPlugin;function firstLine(e){return e.trim().split(`
|
|
5
|
+
`)[0]?.slice(0,300)??""}a(firstLine,"firstLine"),c(firstLine,"firstLine");
|
package/typecheck-bus.d.ts
CHANGED
|
@@ -68,6 +68,23 @@ export declare function resolveEventFile(workspaceRoot: string): string;
|
|
|
68
68
|
*/
|
|
69
69
|
export declare function appendTypecheckEvents(eventFile: string, events: readonly TypecheckBusEvent[]): void;
|
|
70
70
|
/** Parse a raw tsgo/tsc run and publish it. Returns the events written (for tests). */
|
|
71
|
+
/**
|
|
72
|
+
* Publish a run from diagnostics that are ALREADY structured.
|
|
73
|
+
*
|
|
74
|
+
* `publishTypecheckRun` exists for a checker we spawn ourselves and read text from. A checker
|
|
75
|
+
* running INSIDE webpack hands us `{file, line, column, code, message}` objects directly, and
|
|
76
|
+
* formatting those back into `file(1,2): error TS123: msg` only to re-parse them would be a
|
|
77
|
+
* round trip through a regex that can only lose information.
|
|
78
|
+
*/
|
|
79
|
+
export declare function publishTypecheckDiagnostics(args: {
|
|
80
|
+
workspaceRoot: string;
|
|
81
|
+
project: string;
|
|
82
|
+
tool: string;
|
|
83
|
+
tsConfig?: string;
|
|
84
|
+
diagnostics: readonly TscDiagnostic[];
|
|
85
|
+
durationMs: number;
|
|
86
|
+
eventFile?: string;
|
|
87
|
+
}): TypecheckBusEvent[];
|
|
71
88
|
export declare function publishTypecheckRun(args: {
|
|
72
89
|
workspaceRoot: string;
|
|
73
90
|
project: string;
|
package/typecheck-bus.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`)){const
|
|
1
|
+
"use strict";var d=Object.defineProperty;var s=(e,r)=>d(e,"name",{value:r,configurable:!0});var f=Object.defineProperty,i=s((e,r)=>f(e,"name",{value:r,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.MAX_DIAGNOSTICS_PER_RUN=void 0,exports.stripAnsi=stripAnsi,exports.parseTscDiagnosticLine=parseTscDiagnosticLine,exports.parseTscOutput=parseTscOutput,exports.buildTypecheckRunEvents=buildTypecheckRunEvents,exports.resolveEventFile=resolveEventFile,exports.appendTypecheckEvents=appendTypecheckEvents,exports.publishTypecheckDiagnostics=publishTypecheckDiagnostics,exports.publishTypecheckRun=publishTypecheckRun;const tslib_1=require("tslib"),fs=tslib_1.__importStar(require("node:fs")),path=tslib_1.__importStar(require("node:path")),busHygiene=(()=>{try{return require("@lensmcp/node-instrumentation")}catch{return}})(),DIAG_LINE_REGEX=/^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+(TS\d+):\s+(.+)$/,ANSI_CSI=new RegExp("\x1B\\[[0-9;]*[A-Za-z]","g");function stripAnsi(e){return e.replace(ANSI_CSI,"")}s(stripAnsi,"stripAnsi"),i(stripAnsi,"stripAnsi");function parseTscDiagnosticLine(e){const r=stripAnsi(e).trim();if(!r)return null;const o=DIAG_LINE_REGEX.exec(r);if(!o)return null;const[,t,u,l,c,a,p]=o;return!t||!u||!l||!c||!a||!p?null:{file:t,line:Number(u),column:Number(l),severity:c==="warning"?"warning":"error",code:a,message:p}}s(parseTscDiagnosticLine,"parseTscDiagnosticLine"),i(parseTscDiagnosticLine,"parseTscDiagnosticLine");function parseTscOutput(e){const r=[];for(const o of e.split(`
|
|
2
|
+
`)){const t=parseTscDiagnosticLine(o);t&&r.push(t)}return r}s(parseTscOutput,"parseTscOutput"),i(parseTscOutput,"parseTscOutput"),exports.MAX_DIAGNOSTICS_PER_RUN=200;let idCounter=0;function makeId(){return idCounter=(idCounter+1)%65535,`${Date.now().toString(36)}${idCounter.toString(36)}${Math.random().toString(36).slice(2,8)}`}s(makeId,"makeId"),i(makeId,"makeId");function buildTypecheckRunEvents(e){const r=(e.now??Date.now)(),o=e.idImpl??makeId,t="pending",u={sessionId:t,source:"typescript",category:"typecheck",context:{sessionId:t,projectName:e.project}},l={project:e.project,tool:e.tool,...e.tsConfig?{tsConfig:e.tsConfig}:{}},c=e.diagnostics.filter(n=>n.severity==="error"),a=e.diagnostics.slice(0,exports.MAX_DIAGNOSTICS_PER_RUN),p=[];if(!e.toolError){p.push({...u,id:o(),timestamp:r,severity:"info",title:`tsc clear: ${e.project}`,message:`typecheck run starting for ${e.project}`,fingerprint:`tsc:${e.project}:run-start`,raw:{...l,kind:"typecheck-run",phase:"start"}});for(const n of a)p.push({...u,id:o(),timestamp:r,severity:n.severity,title:`${n.code}: ${n.message}`,message:n.message,location:{file:n.file,line:n.line,column:n.column},fingerprint:`tsc:${e.project}:${n.file}:${n.line}:${n.column}:${n.code}`,raw:{...l,kind:"typecheck-diagnostic",code:n.code}})}const g=e.toolError?"error":c.length>0?"failing":"clean";return p.push({...u,id:o(),timestamp:r,severity:"info",title:`typecheck run: ${e.project} \u2014 ${e.toolError?"tool error":`${c.length} error${c.length===1?"":"s"}`} (${e.durationMs}ms)`,...e.toolError?{message:e.toolError}:{},fingerprint:`tsc:${e.project}:run-end`,raw:{...l,kind:"typecheck-run",phase:"end",status:g,durationMs:e.durationMs,errorCount:c.length,warningCount:e.diagnostics.length-c.length,...e.diagnostics.length>a.length?{truncatedDiagnostics:e.diagnostics.length-a.length}:{},...e.toolError?{error:e.toolError}:{}}}),p}s(buildTypecheckRunEvents,"buildTypecheckRunEvents"),i(buildTypecheckRunEvents,"buildTypecheckRunEvents");function resolveEventFile(e){return process.env.LENSMCP_EVENT_FILE||path.join(e,".lensmcp","events.jsonl")}s(resolveEventFile,"resolveEventFile"),i(resolveEventFile,"resolveEventFile");let ensuredDir=null;function ensureDir(e){const r=path.dirname(e);ensuredDir!==r&&(fs.mkdirSync(r,{recursive:!0}),ensuredDir=r)}s(ensureDir,"ensureDir"),i(ensureDir,"ensureDir");function appendTypecheckEvents(e,r){if(r.length===0)return;const o=r.map(t=>JSON.stringify(t)).join(`
|
|
3
3
|
`)+`
|
|
4
|
-
`;try{ensureDir(
|
|
4
|
+
`;try{ensureDir(e),busHygiene?.maybeRotateEventFile(e,o.length),fs.appendFileSync(e,o)}catch(t){if(t?.code==="ENOENT"){try{ensuredDir=null,ensureDir(e),fs.appendFileSync(e,o)}catch{}return}}}s(appendTypecheckEvents,"appendTypecheckEvents"),i(appendTypecheckEvents,"appendTypecheckEvents");function publishTypecheckDiagnostics(e){const r=buildTypecheckRunEvents({project:e.project,tool:e.tool,...e.tsConfig?{tsConfig:e.tsConfig}:{},diagnostics:e.diagnostics,durationMs:e.durationMs});return appendTypecheckEvents(e.eventFile??resolveEventFile(e.workspaceRoot),r),r}s(publishTypecheckDiagnostics,"publishTypecheckDiagnostics"),i(publishTypecheckDiagnostics,"publishTypecheckDiagnostics");function publishTypecheckRun(e){const r=buildTypecheckRunEvents({project:e.project,tool:e.tool,...e.tsConfig?{tsConfig:e.tsConfig}:{},diagnostics:e.toolError?[]:parseTscOutput(e.output),durationMs:e.durationMs,...e.toolError?{toolError:e.toolError}:{}});return appendTypecheckEvents(e.eventFile??resolveEventFile(e.workspaceRoot),r),r}s(publishTypecheckRun,"publishTypecheckRun"),i(publishTypecheckRun,"publishTypecheckRun");
|