@lensmcp/cluster 1.23.10 → 1.23.12

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.
Files changed (87) hide show
  1. package/basic-ssl.js +1 -1
  2. package/build-scope-patterns.js +1 -1
  3. package/create-webpack-dev.js +1 -1
  4. package/create-webpack-prod.js +1 -1
  5. package/error-stack-release.js +1 -1
  6. package/executors/build/build.impl.js +1 -1
  7. package/executors/gateway/body-stall.js +1 -1
  8. package/executors/gateway/canonical-path.js +1 -1
  9. package/executors/gateway/client-ip.js +1 -1
  10. package/executors/gateway/gateway-errors.js +1 -1
  11. package/executors/gateway/gateway.impl.js +1 -1
  12. package/executors/gateway/gateway.lib.js +1 -1
  13. package/executors/gateway/health-check.js +1 -1
  14. package/executors/gateway/jwks-verify.js +1 -1
  15. package/executors/gateway/jwt-claims.js +1 -1
  16. package/executors/gateway/main.prod-gateway.js +2 -2
  17. package/executors/gateway/main.rollout.js +4 -4
  18. package/executors/gateway/manifest.js +1 -1
  19. package/executors/gateway/metrics.js +1 -1
  20. package/executors/gateway/otel-tracing.js +1 -1
  21. package/executors/gateway/prod-config.js +1 -1
  22. package/executors/gateway/prod-gateway.lib.js +1 -1
  23. package/executors/gateway/prod-runtime/access-log.js +1 -1
  24. package/executors/gateway/prod-runtime/app.js +1 -1
  25. package/executors/gateway/prod-runtime/auth.js +1 -1
  26. package/executors/gateway/prod-runtime/body-stall.js +1 -1
  27. package/executors/gateway/prod-runtime/cors.js +1 -1
  28. package/executors/gateway/prod-runtime/edge.js +1 -1
  29. package/executors/gateway/prod-runtime/handler.js +1 -1
  30. package/executors/gateway/prod-runtime/hooks.js +1 -1
  31. package/executors/gateway/prod-runtime/observability.js +1 -1
  32. package/executors/gateway/prod-runtime/rollout.js +1 -1
  33. package/executors/gateway/prod-runtime/routing.js +1 -1
  34. package/executors/gateway/prod-runtime/server.js +1 -1
  35. package/executors/gateway/prod-runtime/trust.js +1 -1
  36. package/executors/gateway/prod-runtime/upgrade.js +7 -7
  37. package/executors/gateway/prod-runtime/upstream.js +1 -1
  38. package/executors/gateway/providers-prod.js +1 -1
  39. package/executors/gateway/rate-limit.js +2 -2
  40. package/executors/gateway/registry-source.js +1 -1
  41. package/executors/gateway/rollout-ops.js +2 -2
  42. package/executors/gateway/runtime/auth.js +1 -1
  43. package/executors/gateway/runtime/chooser.js +9 -9
  44. package/executors/gateway/runtime/control.d.ts +15 -5
  45. package/executors/gateway/runtime/control.js +2 -2
  46. package/executors/gateway/runtime/dev-auth.js +1 -1
  47. package/executors/gateway/runtime/discovery.js +1 -1
  48. package/executors/gateway/runtime/edge.js +1 -1
  49. package/executors/gateway/runtime/handler.js +1 -1
  50. package/executors/gateway/runtime/hmr-reload.js +1 -1
  51. package/executors/gateway/runtime/hooks.js +1 -1
  52. package/executors/gateway/runtime/lens-children.js +1 -1
  53. package/executors/gateway/runtime/lifecycle.js +3 -3
  54. package/executors/gateway/runtime/observability.js +2 -2
  55. package/executors/gateway/runtime/pod-env.js +2 -2
  56. package/executors/gateway/runtime/pod-output.js +1 -1
  57. package/executors/gateway/runtime/pod-probe.js +1 -1
  58. package/executors/gateway/runtime/proxy.js +1 -1
  59. package/executors/gateway/runtime/route-registry.js +1 -1
  60. package/executors/gateway/runtime/scope.js +1 -1
  61. package/executors/gateway/runtime/server.js +2 -2
  62. package/executors/gateway/runtime/service-keys.js +1 -1
  63. package/executors/gateway/runtime/types.js +1 -1
  64. package/executors/gateway/runtime/upgrade.js +1 -1
  65. package/executors/gateway/runtime/workspace-log.js +1 -1
  66. package/executors/gateway/runtime/workspace-registry.js +1 -1
  67. package/executors/gateway/ssrf-guard.js +1 -1
  68. package/executors/serve/serve.impl.js +1 -1
  69. package/executors/trust/hostname.js +1 -1
  70. package/executors/trust/trust.impl.js +3 -3
  71. package/exit-reason.js +2 -2
  72. package/fork-ts-check-reporter.js +1 -1
  73. package/gateway.js +1 -1
  74. package/hot-swap-registries.js +1 -1
  75. package/index.js +1 -1
  76. package/main.devserver.js +8 -8
  77. package/package.json +4 -4
  78. package/process-name.js +1 -1
  79. package/redis-disconnect-fix.js +1 -1
  80. package/schema-first-instance.js +1 -1
  81. package/stdio-guard.js +1 -1
  82. package/swap-recycle.js +1 -1
  83. package/tsgo-check-plugin.d.ts +47 -2
  84. package/tsgo-check-plugin.js +5 -5
  85. package/typecheck-bus.js +3 -3
  86. package/typecheck-queue.d.ts +36 -0
  87. package/typecheck-queue.js +1 -0
package/main.devserver.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var De=Object.defineProperty;var f=(n,h)=>De(n,"name",{value:h,configurable:!0});var Oe=Object.defineProperty,u=f((n,h)=>Oe(n,"name",{value:h,configurable:!0}),"u"),Ce=Object.defineProperty,i=u((n,h)=>Ce(n,"name",{value:h,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.DEBUG_FIXED_PORTS_ENV=void 0,exports.isOwnerOnlyTransport=isOwnerOnlyTransport,exports.usesFixedInspectorPorts=usesFixedInspectorPorts,exports.inspectorPortFor=inspectorPortFor,exports.redactInspectorUrls=redactInspectorUrls,exports.inspectorPortOf=inspectorPortOf;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),node_child_process_1=require("node:child_process"),http=tslib_1.__importStar(require("node:http")),readline=tslib_1.__importStar(require("node:readline")),inspector=tslib_1.__importStar(require("node:inspector")),util=tslib_1.__importStar(require("node:util")),v8=tslib_1.__importStar(require("node:v8")),vm=tslib_1.__importStar(require("node:vm")),exit_reason_1=require("./exit-reason"),hot_swap_registries_1=require("./hot-swap-registries"),process_name_1=require("./process-name"),schema_first_instance_1=require("./schema-first-instance"),redis_disconnect_fix_1=require("./redis-disconnect-fix"),error_stack_release_1=require("./error-stack-release"),swap_recycle_1=require("./swap-recycle"),stdio_guard_1=require("./stdio-guard"),httpProxy=require("http-proxy"),{prettyFactory}=require("pino-pretty"),BUNDLE_PATH=process.env.BUNDLE_PATH?.trim()||"./main.js",SERVICE_NAME=process.env.SERVICE_NAME||"",SERVICE_PREFIX=process.env.SERVE_PREFIX?`/${process.env.SERVE_PREFIX}`:"",GATEWAY_MIDDLEWARE_PATH=process.env.GATEWAY_MIDDLEWARE||"",GATEWAY_CONFIG=(()=>{const n=process.env.GATEWAY_CONFIG;if(!n)return{};try{return JSON.parse(n)}catch{return{}}})();let gatewayMiddleware=null;if(GATEWAY_MIDDLEWARE_PATH)try{const n=require(GATEWAY_MIDDLEWARE_PATH);gatewayMiddleware=typeof n=="function"?n:typeof n.default=="function"?n.default:null,gatewayMiddleware||console.warn(`[gateway] ${GATEWAY_MIDDLEWARE_PATH} does not export a function, gateway disabled`)}catch(n){console.error(`[gateway] Failed to load middleware from ${GATEWAY_MIDDLEWARE_PATH}:`,n)}function applyGatewayMiddleware(n){if(gatewayMiddleware)try{gatewayMiddleware(n,GATEWAY_CONFIG)}catch(h){console.error("[gateway] Middleware error:",h)}}f(applyGatewayMiddleware,"applyGatewayMiddleware"),u(applyGatewayMiddleware,"applyGatewayMiddleware"),i(applyGatewayMiddleware,"applyGatewayMiddleware");const GATEWAY_ROUTES=(()=>{try{return JSON.parse(process.env.GATEWAY_ROUTES||"[]")}catch{return[]}})(),GATEWAY_HTTPS=process.env.GATEWAY_HTTPS==="1";function hostMatches(n,h){if(n.startsWith("*.")){const y=n.slice(1);return h.endsWith(y)||h===n.slice(2)}return h===n}f(hostMatches,"hostMatches"),u(hostMatches,"hostMatches"),i(hostMatches,"hostMatches");function matchGatewayRoute(n){if(GATEWAY_ROUTES.length===0)return;const h=(n.headers.host||"").split(":")[0],y=n.url||"/";for(const m of GATEWAY_ROUTES)if(!(m.host&&!hostMatches(m.host,h))&&!(m.prefix&&!y.startsWith(m.prefix)))return m}f(matchGatewayRoute,"matchGatewayRoute"),u(matchGatewayRoute,"matchGatewayRoute"),i(matchGatewayRoute,"matchGatewayRoute");const WORKER_NAMES=(()=>{try{return JSON.parse(process.env.WORKERS||"[]")}catch{return[]}})(),LENSMCP_WS_KEY=process.env.LENSMCP_WS_KEY||"",SOCK_DIR=LENSMCP_WS_KEY?path.join(os.tmpdir(),LENSMCP_WS_KEY,`${SERVICE_NAME||"lensmcp-cluster"}-devserver`):path.join(os.tmpdir(),`${SERVICE_NAME||"lensmcp-cluster"}-devserver`),POD_GENERATION=(()=>{const n=Number(process.env.LENSMCP_POD_GENERATION);return Number.isFinite(n)&&n>1?Math.floor(n):1})();function childSockPath(n){return path.join(SOCK_DIR,POD_GENERATION>1?`child-${n}-g${POD_GENERATION}.sock`:`child-${n}.sock`)}f(childSockPath,"childSockPath"),u(childSockPath,"childSockPath"),i(childSockPath,"childSockPath");function sockOwnerPath(n){return`${n}.owner`}f(sockOwnerPath,"sockOwnerPath"),u(sockOwnerPath,"sockOwnerPath"),i(sockOwnerPath,"sockOwnerPath");function sockRetiringPath(n){return`${n}.retiring`}f(sockRetiringPath,"sockRetiringPath"),u(sockRetiringPath,"sockRetiringPath"),i(sockRetiringPath,"sockRetiringPath");function isOwnerOnlyTransport(n){try{return typeof n.socket?.server?.address?.()=="string"}catch{return!1}}f(isOwnerOnlyTransport,"isOwnerOnlyTransport"),u(isOwnerOnlyTransport,"isOwnerOnlyTransport"),i(isOwnerOnlyTransport,"isOwnerOnlyTransport"),exports.DEBUG_FIXED_PORTS_ENV="LENSMCP_DEBUG_FIXED_PORTS";function usesFixedInspectorPorts(n=process.env){const h=(n[exports.DEBUG_FIXED_PORTS_ENV]??"").trim().toLowerCase();return h==="1"||h==="true"||h==="yes"||h==="on"}f(usesFixedInspectorPorts,"usesFixedInspectorPorts"),u(usesFixedInspectorPorts,"usesFixedInspectorPorts"),i(usesFixedInspectorPorts,"usesFixedInspectorPorts");function inspectorPortFor(n,h,y=process.env){if(!usesFixedInspectorPorts(y))return 0;const m=Math.trunc(n)+Math.trunc(h);return Number.isInteger(m)&&m>1024&&m<=65535?m:0}f(inspectorPortFor,"inspectorPortFor"),u(inspectorPortFor,"inspectorPortFor"),i(inspectorPortFor,"inspectorPortFor");const INSPECTOR_TOKEN_RE=/((?:wss?:\/\/[^\s/]+\/|ws=[^\s/]+\/))([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/gi;function redactInspectorUrls(n){return n.replace(INSPECTOR_TOKEN_RE,"$1<inspector-token-redacted>")}f(redactInspectorUrls,"redactInspectorUrls"),u(redactInspectorUrls,"redactInspectorUrls"),i(redactInspectorUrls,"redactInspectorUrls");function inspectorPortOf(n){const h=/^wss?:\/\/[^/]*?:(\d+)\//.exec(n??""),y=h?Number(h[1]):NaN;return Number.isInteger(y)&&y>0?y:null}f(inspectorPortOf,"inspectorPortOf"),u(inspectorPortOf,"inspectorPortOf"),i(inspectorPortOf,"inspectorPortOf");function ensureOwnerOnlyDir(n){try{fs.mkdirSync(n,{recursive:!0,mode:448})}catch{}try{const h=fs.lstatSync(n);h.isDirectory()&&(h.mode&63)!==0&&fs.chmodSync(n,448)}catch{}}f(ensureOwnerOnlyDir,"ensureOwnerOnlyDir"),u(ensureOwnerOnlyDir,"ensureOwnerOnlyDir"),i(ensureOwnerOnlyDir,"ensureOwnerOnlyDir");function claimSock(n,h=process.pid){ensureOwnerOnlyDir(path.dirname(n));try{const y=sockOwnerPath(n);try{fs.unlinkSync(y)}catch{}fs.writeFileSync(y,String(h),{flag:"wx",mode:384})}catch{}try{fs.unlinkSync(n)}catch{}try{fs.unlinkSync(sockRetiringPath(n))}catch{}}f(claimSock,"claimSock"),u(claimSock,"claimSock"),i(claimSock,"claimSock");function cleanupSock(n,h=process.pid){if(n){try{const y=fs.readFileSync(sockOwnerPath(n),"utf8").trim();if(y&&y!==String(h))return}catch{}try{fs.unlinkSync(n)}catch{}try{fs.unlinkSync(sockOwnerPath(n))}catch{}try{fs.unlinkSync(sockRetiringPath(n))}catch{}}}f(cleanupSock,"cleanupSock"),u(cleanupSock,"cleanupSock"),i(cleanupSock,"cleanupSock");function serviceKeyFingerprint(){const n=process.env.LENSMCP_SERVICE_KEY;if(!n)return;const{createHash:h}=require("node:crypto");return h("sha256").update(n).digest("hex").slice(0,8)}f(serviceKeyFingerprint,"serviceKeyFingerprint"),u(serviceKeyFingerprint,"serviceKeyFingerprint"),i(serviceKeyFingerprint,"serviceKeyFingerprint");async function importFresh(spec){process.env.DEVSERVER_MODE="1";const requested=path.isAbsolute(spec)?spec:path.join(__dirname,spec);let resolved=requested;try{resolved=fs.realpathSync(requested)}catch{}return eval(`(() => {
1
+ "use strict";var Oe=Object.defineProperty;var u=(n,h)=>Oe(n,"name",{value:h,configurable:!0});var Ce=Object.defineProperty,i=u((n,h)=>Ce(n,"name",{value:h,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.DEBUG_FIXED_PORTS_ENV=void 0,exports.isOwnerOnlyTransport=isOwnerOnlyTransport,exports.usesFixedInspectorPorts=usesFixedInspectorPorts,exports.inspectorPortFor=inspectorPortFor,exports.redactInspectorUrls=redactInspectorUrls,exports.inspectorPortOf=inspectorPortOf;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),node_child_process_1=require("node:child_process"),http=tslib_1.__importStar(require("node:http")),readline=tslib_1.__importStar(require("node:readline")),inspector=tslib_1.__importStar(require("node:inspector")),util=tslib_1.__importStar(require("node:util")),v8=tslib_1.__importStar(require("node:v8")),vm=tslib_1.__importStar(require("node:vm")),exit_reason_1=require("./exit-reason"),hot_swap_registries_1=require("./hot-swap-registries"),process_name_1=require("./process-name"),schema_first_instance_1=require("./schema-first-instance"),redis_disconnect_fix_1=require("./redis-disconnect-fix"),error_stack_release_1=require("./error-stack-release"),swap_recycle_1=require("./swap-recycle"),stdio_guard_1=require("./stdio-guard"),httpProxy=require("http-proxy"),{prettyFactory}=require("pino-pretty"),BUNDLE_PATH=process.env.BUNDLE_PATH?.trim()||"./main.js",SERVICE_NAME=process.env.SERVICE_NAME||"",SERVICE_PREFIX=process.env.SERVE_PREFIX?`/${process.env.SERVE_PREFIX}`:"",GATEWAY_MIDDLEWARE_PATH=process.env.GATEWAY_MIDDLEWARE||"",GATEWAY_CONFIG=(()=>{const n=process.env.GATEWAY_CONFIG;if(!n)return{};try{return JSON.parse(n)}catch{return{}}})();let gatewayMiddleware=null;if(GATEWAY_MIDDLEWARE_PATH)try{const n=require(GATEWAY_MIDDLEWARE_PATH);gatewayMiddleware=typeof n=="function"?n:typeof n.default=="function"?n.default:null,gatewayMiddleware||console.warn(`[gateway] ${GATEWAY_MIDDLEWARE_PATH} does not export a function, gateway disabled`)}catch(n){console.error(`[gateway] Failed to load middleware from ${GATEWAY_MIDDLEWARE_PATH}:`,n)}function applyGatewayMiddleware(n){if(gatewayMiddleware)try{gatewayMiddleware(n,GATEWAY_CONFIG)}catch(h){console.error("[gateway] Middleware error:",h)}}u(applyGatewayMiddleware,"applyGatewayMiddleware"),i(applyGatewayMiddleware,"applyGatewayMiddleware");const GATEWAY_ROUTES=(()=>{try{return JSON.parse(process.env.GATEWAY_ROUTES||"[]")}catch{return[]}})(),GATEWAY_HTTPS=process.env.GATEWAY_HTTPS==="1";function hostMatches(n,h){if(n.startsWith("*.")){const g=n.slice(1);return h.endsWith(g)||h===n.slice(2)}return h===n}u(hostMatches,"hostMatches"),i(hostMatches,"hostMatches");function matchGatewayRoute(n){if(GATEWAY_ROUTES.length===0)return;const h=(n.headers.host||"").split(":")[0],g=n.url||"/";for(const _ of GATEWAY_ROUTES)if(!(_.host&&!hostMatches(_.host,h))&&!(_.prefix&&!g.startsWith(_.prefix)))return _}u(matchGatewayRoute,"matchGatewayRoute"),i(matchGatewayRoute,"matchGatewayRoute");const WORKER_NAMES=(()=>{try{return JSON.parse(process.env.WORKERS||"[]")}catch{return[]}})(),LENSMCP_WS_KEY=process.env.LENSMCP_WS_KEY||"",SOCK_DIR=LENSMCP_WS_KEY?path.join(os.tmpdir(),LENSMCP_WS_KEY,`${SERVICE_NAME||"lensmcp-cluster"}-devserver`):path.join(os.tmpdir(),`${SERVICE_NAME||"lensmcp-cluster"}-devserver`),POD_GENERATION=(()=>{const n=Number(process.env.LENSMCP_POD_GENERATION);return Number.isFinite(n)&&n>1?Math.floor(n):1})();function childSockPath(n){return path.join(SOCK_DIR,POD_GENERATION>1?`child-${n}-g${POD_GENERATION}.sock`:`child-${n}.sock`)}u(childSockPath,"childSockPath"),i(childSockPath,"childSockPath");function sockOwnerPath(n){return`${n}.owner`}u(sockOwnerPath,"sockOwnerPath"),i(sockOwnerPath,"sockOwnerPath");function sockRetiringPath(n){return`${n}.retiring`}u(sockRetiringPath,"sockRetiringPath"),i(sockRetiringPath,"sockRetiringPath");function isOwnerOnlyTransport(n){try{return typeof n.socket?.server?.address?.()=="string"}catch{return!1}}u(isOwnerOnlyTransport,"isOwnerOnlyTransport"),i(isOwnerOnlyTransport,"isOwnerOnlyTransport"),exports.DEBUG_FIXED_PORTS_ENV="LENSMCP_DEBUG_FIXED_PORTS";function usesFixedInspectorPorts(n=process.env){const h=(n[exports.DEBUG_FIXED_PORTS_ENV]??"").trim().toLowerCase();return h==="1"||h==="true"||h==="yes"||h==="on"}u(usesFixedInspectorPorts,"usesFixedInspectorPorts"),i(usesFixedInspectorPorts,"usesFixedInspectorPorts");function inspectorPortFor(n,h,g=process.env){if(!usesFixedInspectorPorts(g))return 0;const _=Math.trunc(n)+Math.trunc(h);return Number.isInteger(_)&&_>1024&&_<=65535?_:0}u(inspectorPortFor,"inspectorPortFor"),i(inspectorPortFor,"inspectorPortFor");const INSPECTOR_TOKEN_RE=/((?:wss?:\/\/[^\s/]+\/|ws=[^\s/]+\/))([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/gi;function redactInspectorUrls(n){return n.replace(INSPECTOR_TOKEN_RE,"$1<inspector-token-redacted>")}u(redactInspectorUrls,"redactInspectorUrls"),i(redactInspectorUrls,"redactInspectorUrls");function inspectorPortOf(n){const h=/^wss?:\/\/[^/]*?:(\d+)\//.exec(n??""),g=h?Number(h[1]):NaN;return Number.isInteger(g)&&g>0?g:null}u(inspectorPortOf,"inspectorPortOf"),i(inspectorPortOf,"inspectorPortOf");function ensureOwnerOnlyDir(n){try{fs.mkdirSync(n,{recursive:!0,mode:448})}catch{}try{const h=fs.lstatSync(n);h.isDirectory()&&(h.mode&63)!==0&&fs.chmodSync(n,448)}catch{}}u(ensureOwnerOnlyDir,"ensureOwnerOnlyDir"),i(ensureOwnerOnlyDir,"ensureOwnerOnlyDir");function claimSock(n,h=process.pid){ensureOwnerOnlyDir(path.dirname(n));try{const g=sockOwnerPath(n);try{fs.unlinkSync(g)}catch{}fs.writeFileSync(g,String(h),{flag:"wx",mode:384})}catch{}try{fs.unlinkSync(n)}catch{}try{fs.unlinkSync(sockRetiringPath(n))}catch{}}u(claimSock,"claimSock"),i(claimSock,"claimSock");function cleanupSock(n,h=process.pid){if(n){try{const g=fs.readFileSync(sockOwnerPath(n),"utf8").trim();if(g&&g!==String(h))return}catch{}try{fs.unlinkSync(n)}catch{}try{fs.unlinkSync(sockOwnerPath(n))}catch{}try{fs.unlinkSync(sockRetiringPath(n))}catch{}}}u(cleanupSock,"cleanupSock"),i(cleanupSock,"cleanupSock");function serviceKeyFingerprint(){const n=process.env.LENSMCP_SERVICE_KEY;if(!n)return;const{createHash:h}=require("node:crypto");return h("sha256").update(n).digest("hex").slice(0,8)}u(serviceKeyFingerprint,"serviceKeyFingerprint"),i(serviceKeyFingerprint,"serviceKeyFingerprint");async function importFresh(spec){process.env.DEVSERVER_MODE="1";const requested=path.isAbsolute(spec)?spec:path.join(__dirname,spec);let resolved=requested;try{resolved=fs.realpathSync(requested)}catch{}return eval(`(() => {
2
2
  const key = ${JSON.stringify(resolved)};
3
3
  const previous = require.cache[key];
4
4
  delete require.cache[key]; // delete from CJS cache
@@ -9,13 +9,13 @@
9
9
  const at = owner && Array.isArray(owner.children) ? owner.children.indexOf(previous) : -1;
10
10
  if (at >= 0) owner.children.splice(at, 1);
11
11
  }
12
- })()`),eval(`require(${JSON.stringify(resolved)})`)}f(importFresh,"importFresh"),u(importFresh,"importFresh"),i(importFresh,"importFresh");function debounce(n,h){let y=null;return(...m)=>{y&&clearTimeout(y),y=setTimeout(()=>n(...m),h)}}if(f(debounce,"debounce"),u(debounce,"debounce"),i(debounce,"debounce"),process.env.APP_RUNNER==="1"){(0,stdio_guard_1.guardBrokenStdio)();const n=i(y=>{if(!inspector.url())try{inspector.open(y,"127.0.0.1",!1)}catch(Y){console.warn(`[child] inspector.open(${y}) failed (port taken by another devserver?) \u2014 falling back to a random port:`,Y.message);try{inspector.open(0,"127.0.0.1",!1)}catch{}}const m=inspector.url();m&&process.send&&process.send({type:"inspector-url",url:m})},"openInspector"),h=process.env.CHILD_DEBUG_PORT;if(h!==void 0&&h!==""){const y=Number(h);Number.isInteger(y)&&(y===0||y>1024)&&n(y)}try{require("@lensmcp/node-instrumentation/register")}catch{}(async()=>{let y=null,m=!1,Y,V=!1;const R=(0,hot_swap_registries_1.registryPruningEnabled)(),ee=i((t,s)=>{const g=(0,hot_swap_registries_1.describePrune)(t,s);g&&console.log(g)},"logPrune");let $={app:null,handler:i((t,s)=>{s.statusCode=503,s.end("starting")},"handler"),inflight:0};const te=(()=>{const t=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return Number.isFinite(t)&&t>=0?t:15*6e4})(),X=i(t=>{const s=globalThis.__lensmcpActiveWork;if(typeof s!="function")return{count:0};try{const g=s(t);return{count:Number(g?.count??0),...g?.oldestStartedAt?{oldestStartedAt:g.oldestStartedAt}:{}}}catch{return{count:0}}},"activeWork"),re=(()=>{const t=Number(process.env.LENSMCP_SWAP_MAX_DRAINING);return Number.isFinite(t)&&t>=1?Math.floor(t):1})(),C=new Set,k=(0,swap_recycle_1.swapRecyclePolicy)();let ne,ue=0;const we=(()=>{const t=Number(process.env.LENSMCP_POD_RETIRE_NOTICE_MS);return Number.isFinite(t)&&t>=0?t:3500})();let J=!1,z=!1,d;const E=i(()=>{if(d===void 0)try{v8.setFlagsFromString("--expose-gc");const t=vm.runInNewContext("gc");d=typeof t=="function"?t:null}catch{d=null}try{d?.()}catch{}return process.memoryUsage().heapUsed},"liveHeap"),_=(()=>{if(!(0,error_stack_release_1.errorFrameReleaseEnabled)())return null;try{const t=path.dirname(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH))+path.sep,s=`${path.sep}node_modules${path.sep}`,g=new Set(Object.keys(require.cache));return(0,error_stack_release_1.createErrorFrameReleaser)(require.cache,{skip:i(w=>g.has(w)||w.startsWith(t)&&!w.slice(t.length).includes(s)&&!w.slice(t.length).startsWith(`node_modules${path.sep}`),"skip")})}catch{return null}})();let x=!1;function G(){if(!(!_||x))try{const t=_();t.errors>0&&console.log(`[child] read the stack of ${t.errors} Error object(s) that libraries created while loading and keep for good \u2014 unread, each held the functions that were on its stack, this bundle's included`)}catch(t){console.error("[child] could not release library error frames:",t),x=!0}}f(G,"W"),u(G,"z"),i(G,"releaseLibraryErrorFrames");const F=new Map;let v=Date.now();const T=i(()=>k.settleMs<=0||!m&&!V&&F.size===0&&Date.now()-v>=k.settleMs,"settled");let A;function I(t){if(!(!k.enabled||J||z)){if(k.settleMs<=0){H(t);return}A&&clearTimeout(A),A=setTimeout(()=>{A=void 0,T()?H(t):I(t)},k.settleMs),A.unref?.()}}f(I,"A"),u(I,"N"),i(I,"recycleCheckWhenSettled");const se=i(()=>{if(k.stuckCloseMs<=0)return 0;const t=Date.now();let s=0;for(const g of F.values())t-g>=k.stuckCloseMs&&(s+=1);return s},"stuckCloses");function H(t){if(!k.enabled||J||z||!process.send)return;const s=v8.getHeapStatistics().heap_size_limit,g=i(S=>({swaps:ue,usedBytes:S,limitBytes:s,stuckCloses:se(),settled:T(),...ne===void 0?{}:{baselineBytes:ne}}),"state");if(!(0,swap_recycle_1.recycleReason)(k,g(process.memoryUsage().heapUsed)))return;const w=(0,swap_recycle_1.recycleReason)(k,g(E()));w&&(J=!0,console.log(`[child] asking for a fresh pod ${t} \u2014 ${w}. This pod keeps serving until its successor is ready. Size the bound with LENSMCP_SWAP_RECYCLE_HEAP_FACTOR / _HEAP_RATIO / _MIN_MB, or turn it off with LENSMCP_SWAP_RECYCLE=0.`),process.send({type:"recycle-request",reason:w}))}f(H,"F"),u(H,"K"),i(H,"considerRecycle");async function q(t,s){if(t.closed||(t.closed=!0,C.delete(t),s&&console.error(`[child] ${s}`),!t.app))return;F.set(t,Date.now());const g=k.enabled&&k.stuckCloseMs>0?setTimeout(()=>{F.has(t)&&(console.error(`[child] a previous app has been closing for ${Math.round(k.stuckCloseMs/1e3)}s and its close() has not returned \u2014 one of its shutdown hooks is waiting on something that does not end (a queue worker, a connection, a stream). It stays in memory until this pod is replaced.`),H("with a previous app stuck in close()"))},k.stuckCloseMs):void 0;g?.unref?.();try{await t.app.close()}catch(w){console.error("[child] error closing a previous app:",w)}finally{F.delete(t),v=Date.now(),g&&clearTimeout(g),t.app=null,t.handler=(w,S)=>{S.statusCode=503,S.end("closed")}}if(t.superseded){try{ee((0,hot_swap_registries_1.pruneRegistries)(t.superseded,"serve"),"after closing the previous app")}catch(w){console.error("[child] could not release the previous app's class registrations:",w)}t.superseded=void 0}I("after closing the previous app")}f(q,"J"),u(q,"Q"),i(q,"closeGeneration");async function ie(t){for(;C.size>=re;){const S=C.values().next().value;if(!S)break;await q(S,`closing a still-draining generation early \u2014 ${C.size} were pending and the cap is ${re} (each holds a whole app: DI container, DB pool, queue workers). Raise LENSMCP_SWAP_MAX_DRAINING if this pod legitimately needs more.`)}C.add(t);const s=Date.now(),g=i(()=>({inflight:t.inflight,work:X(t.workGen).count}),"busy");for(;te>0&&Date.now()-s<te;){if(t.closed)return;const S=g();if(S.inflight===0&&S.work===0)break;await new Promise(M=>{setTimeout(M,250).unref?.()})}if(t.closed)return;const w=g();w.inflight>0||w.work>0?console.error(`[child] swap drain expired after ${Date.now()-s}ms \u2014 closing the previous app with ${w.inflight} in-flight request(s) and ${w.work} background job(s) still running. A queue job killed here keeps its lock until the TTL lapses. Raise LENSMCP_SWAP_DRAIN_MS (currently ${te}ms) if this is legitimate work.`):Date.now()-s>250&&console.log(`[child] previous app drained in ${Date.now()-s}ms \u2014 closing it`),await q(t)}f(ie,"de"),u(ie,"he"),i(ie,"drainThenClose");async function D(){if(m)return V=!0,console.log("[child] Reload deferred \u2014 will re-swap after current swap completes"),y;m=!0,v=Date.now(),process.removeAllListeners("uncaughtException"),process.removeAllListeners("unhandledRejection"),process.on("uncaughtException",(P,U)=>{console.error(`[child] uncaughtException (${U}):`,P)}),process.on("unhandledRejection",P=>{const U=P instanceof Error?P.stack||P.message:String(P);U.includes("FronteggContextScope")||U.includes("populateLoggerMetadata")||console.error("[child] unhandledRejection:",P)});let t;if(R)try{t=(0,hot_swap_registries_1.captureRegistries)()}catch{t=void 0}try{try{await importFresh(BUNDLE_PATH)}catch(P){if(!(P instanceof SyntaxError))throw P;console.warn(`[child] bundle was unreadable mid-write (${P.message}) \u2014 retrying the swap once`),await new Promise(U=>setTimeout(U,400)),await importFresh(BUNDLE_PATH)}}catch(P){throw m=!1,v=Date.now(),P}if(typeof global.createChildApp!="function")throw m=!1,v=Date.now(),new Error(`Bundle '${BUNDLE_PATH}' does not export createChildApp() and the zero-touch bridge is not active. Either install @lensmcp/node-instrumentation (a plain NestFactory.create + app.listen main.ts then just works) or set global.createChildApp in main.ts when DEVSERVER_MODE === '1'.`);let s;if(t)try{s=(0,hot_swap_registries_1.supersededSince)(t),ee((0,hot_swap_registries_1.pruneRegistries)(s,"build"),"at the swap")}catch(P){console.error("[child] could not release superseded class registrations:",P)}const g=global.__lensmcpBeginWorkGeneration,w=typeof g=="function"?g():void 0;let S;try{S=await global.createChildApp()}catch(P){throw m=!1,v=Date.now(),P}const M=$;return s?.size&&(M.app?M.superseded=s:ee((0,hot_swap_registries_1.pruneRegistries)(s,"serve"),"at the swap")),y=S,$={app:S,handler:S.handler,inflight:0,...w===void 0?{}:{workGen:w}},console.log("[child] Swapped to fresh app (previous draining in background)"),G(),M.app&&(ue+=1,ie(M).catch(P=>console.error("[child] background close error:",P)),setTimeout(()=>H("30s after a hot swap"),3e4).unref?.()),m=!1,v=Date.now(),V?(V=!1,D()):S}f(D,"M"),u(D,"V"),i(D,"swapNow");const oe=debounce(async()=>{try{console.log("[child] /webpack/reload"),await D()}catch(t){console.error("[child] reload failed:",t)}},250),L=http.createServer((t,s)=>{if(t.method==="POST"&&t.url==="/webpack/reload"){s.writeHead(200,{"content-type":"application/json"}),s.end(JSON.stringify({ok:!0})),oe();return}if(t.method==="GET"&&t.url==="/__lensmcp/alive"){const w=t.headers["x-internal-token"],S=process.env.LENSMCP_SERVICE_KEY;if(S&&w!==S){s.writeHead(404,{"content-type":"text/plain"}),s.end("not found");return}const M=X();s.writeHead(200,{"content-type":"application/json","cache-control":"no-store"}),s.end(JSON.stringify({ok:!0,pid:process.pid,swapping:m,inflight:$.inflight,oldestInflightAt:$.oldestAt,activeWork:M.count,oldestWorkAt:M.oldestStartedAt,keyFingerprint:serviceKeyFingerprint(),...Y?{watcher:Y}:{},...Number.isFinite(Number(process.env.LENSMCP_POD_GENERATION))&&process.env.LENSMCP_POD_GENERATION?{podGeneration:Number(process.env.LENSMCP_POD_GENERATION)}:{}}));return}const g=$;g.inflight+=1,g.oldestAt===void 0&&(g.oldestAt=Date.now()),s.on("close",()=>{g.inflight-=1,g.inflight===0&&(g.oldestAt=void 0)}),g.handler(t,s)});L.keepAliveTimeout=0;const O=process.env.CHILD_SOCK_PATH;process.on("disconnect",()=>{cleanupSock(O),process.exit(0)});try{const t=path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH);if((0,schema_first_instance_1.schemaPrewarmEnabled)())try{const s=(0,schema_first_instance_1.prewarmZodFor)(t);s?.created&&console.log(`[child] zod${s.version?` ${s.version}`:""}: built ${s.created} throwaway schemas first, so none of the bundle's own is the first of its class`)}catch{}if((0,redis_disconnect_fix_1.redisDisconnectFixEnabled)())try{const s=(0,redis_disconnect_fix_1.finishStrandedDisconnectsFor)(t);s?.patched&&console.log(`[child] ioredis${s.versions.length?` ${s.versions.join(", ")}`:""}: a disconnect() between reconnect attempts now ends the client \u2014 it used to leave a queue worker's close() waiting for good`)}catch{}await D(),k.enabled&&k.heapFactor>0&&(ne=E()),console.log(`[child] Using bundle: ${t}`),claimSock(O),L.listen(O,()=>{console.log(`[child] Listening on ${O}`),process.send&&process.send({type:"ready",socketPath:O})})}catch(t){console.error("[child] Startup error:",t),process.send&&process.send({type:"boot-error",error:String(t?.stack||t)}),process.exitCode=1;return}process.on("message",async t=>{if(!(!t||typeof t!="object")){if(t.type==="debug-open"){const s=Number(t.port);n(Number.isInteger(s)&&s>1024?s:0);return}if(t.type==="watcher"){const s=t.testimony;s&&typeof s=="object"&&(Y=s);return}if(t.type==="recycle-declined"){J=!1;return}if(t.type==="retire"){W();return}if(t.type==="reload"){if(z)return;try{await D(),process.send&&process.send({type:"reloaded",socketPath:O})}catch(s){console.error("[child] reload error:",s),process.send&&process.send({type:"reload-error",error:String(s?.stack||s)})}}}});async function W(){if(z)return;z=!0,console.log("[child] retiring \u2014 a fresh pod has taken over; finishing in-flight work, then exiting");try{fs.writeFileSync(sockRetiringPath(O),String(process.pid),{flag:"w",mode:384})}catch{}await new Promise(s=>{setTimeout(s,we).unref?.()}),cleanupSock(O),L.close();const t=Date.now();for(;Date.now()-t<te&&(L.closeIdleConnections?.(),!($.inflight===0&&X().count===0));)await new Promise(s=>{setTimeout(s,250).unref?.()});setTimeout(()=>process.exit(0),3e4).unref?.();try{await y?.close()}catch(s){console.error("[child] close error while retiring:",s)}process.exit(0)}f(W,"U"),u(W,"ee"),i(W,"retire"),process.on("beforeExit",()=>{try{inspector?.close?.()}catch{}});const B=i(async t=>{console.log(`[child ${t}] shutting down\u2026`);const s=y?.close().catch(w=>console.error("[child] close error:",w)),g=new Promise(w=>L.close(()=>w()));cleanupSock(O),setTimeout(()=>process.exit(0),700).unref(),await Promise.all([s,g]),process.exit(0)},"shutdown");["SIGINT","SIGTERM","SIGHUP","SIGQUIT","SIGUSR2"].forEach(t=>{process.on(t,()=>{inspector?.close?.(),B(t)})})})()}else{let n=u(function(d){C.push(d),C.length>re&&C.splice(0,C.length-re),te?.write(d.replace(X,""));for(const E of k)try{const _=E.plain?d.replace(X,""):d;E.res.write(E.redact?redactInspectorUrls(_):_)}catch{k.delete(E)}},"P");i(n,"emitLogLine");const h=["\x1B[36m","\x1B[33m","\x1B[35m","\x1B[32m","\x1B[34m","\x1B[31m"],y="\x1B[0m",m=Math.max(1,Number(process.env.CHILD_COUNT||1)),Y=LENSMCP_WS_KEY||path.basename(process.cwd()),V=i(d=>(0,process_name_1.namedExecPath)((0,process_name_1.processName)(Y,SERVICE_NAME||"service",d)),"execPathFor");let R=(()=>{const d=Number(process.env.LENSMCP_DEBUG_PORT||"");return Number.isInteger(d)&&d>1024?d:0})();const ee=20;R&&(console.warn("[parent] DEBUGGER ENABLED \u2014 pods and workers open a Node inspector. Node's inspector has NO authentication: the ws:// URL's UUID is the whole credential, and any account on this host that obtains it can run code as you. Do not enable this on a shared machine. (issues/codex-security/06)"),console.warn(usesFixedInspectorPorts()?`[parent] ${exports.DEBUG_FIXED_PORTS_ENV} is set \u2014 inspectors bind PREDICTABLE ports (${R}+slot, workers ${R}+${ee}+i). Any account on this host can connect to 127.0.0.1:${R} and read the session UUID from /json/list. Unset it to use ephemeral ports.`:`[parent] Inspectors bind an EPHEMERAL loopback port; attach via the printed "Debugger listening" URL, or \`lensmcp debug <service>\` (control socket). Set ${exports.DEBUG_FIXED_PORTS_ENV}=1 for fixed ports if your IDE needs a pre-configured attach port \u2014 any account on this host can then reach them.`));const $=process.env.LENSMCP_LOG_FILE||"",te=$?(()=>{try{fs.mkdirSync(path.dirname($),{recursive:!0});const d=fs.createWriteStream($,{flags:"a",mode:384});try{fs.chmodSync($,384)}catch{}return d}catch(d){return console.warn(`[parent] cannot open log file ${$}:`,d.message),null}})():null,X=/\x1b\[[0-9;]*m/g,re=2e3,C=[],k=new Set;for(const d of["log","info","warn","error"]){const E=console[d].bind(console);console[d]=(..._)=>{E(..._),n(_.map(x=>typeof x=="string"?x:util.inspect(x)).join(" ")+`
13
- `)}}const ne=i(d=>h[(d-1)%h.length],"colorFor"),ue=i(d=>{if(m===1)return"";const E=`[child#${d}] `;return`${ne(d)}${E}${y}`},"tagFor"),we=i(d=>d.startsWith("{")&&d.endsWith("}"),"isJsonLog"),J=i((d,E,_)=>{const x=prettyFactory({sync:!0,colorize:!0,crlf:!0,messageKey:"message",errorLikeObjectKeys:["err","error"],errorProps:"type,message,stack",ignore:["logContext","context","hostname","req","res","err.driverError","module","cloudEnvironment","frontegg-application-id","frontegg-tenant-id","frontegg-trace-id","frontegg-vendor-id","host","service","version","err","error"].join(","),messageFormat:"{if module}[{module}] {end}{if context}[{context}] {end}{if logContext}[{logContext}] {end}{message}",customPrettifiers:{stack:i(v=>`
14
- `+String(v),"stack")}}),G=i((v,T)=>{const A=v==="stdout"?process.stdout:process.stderr;try{_?.(T)}catch{}const I=we(T)?x(T):`${T}
15
- `;A.write(`${E}${I}`),n(`${E}${I}`)},"write"),F=i((v,T)=>{if(!v)return;const A=readline.createInterface({input:v});A.on("line",I=>G(T,I)),A.on("close",()=>{})},"attach");F(d.stdout,"stdout"),F(d.stderr,"stderr")},"wireProcLogging"),z=i(d=>J(d.proc,ue(d.id),E=>d.tail.push(E)),"wireChildLogging");(async()=>{ensureOwnerOnlyDir(SOCK_DIR);const d=httpProxy.createProxyServer({});let E=Number(process.env.PORT)||0;E||(E=9090);const _=[],x=new Set;function G(){let e=0;for(;x.has(e);)e++;return x.add(e),e}f(G,"W"),u(G,"z"),i(G,"allocDebugSlot");let F=1,v=0,T=!1,A=m,I=[],se=0;const H=(()=>{const e=Number(process.env.LENSMCP_POD_BOOT_GRACE_MS);return Number.isFinite(e)&&e>=0?e:12e4})(),q=i(e=>e.proc.exitCode!==null||e.proc.signalCode!==null,"childExited"),ie=i(e=>e.booting&&!q(e)&&Date.now()-e.spawnedAt<H,"stillBooting");function D(){return _.filter(e=>e.healthy&&typeof e.socketPath=="string")}f(D,"M"),u(D,"V"),i(D,"healthyChildren");let oe;function L(e){if(!e||typeof e!="object")return;const r=e;if(r.schemaVersion===1){oe=r;for(const p of _)try{p.proc.send?.({type:"watcher",testimony:r})}catch{}}}f(L,"G"),u(L,"U"),i(L,"recordWatcherTestimony");function O(e,r=256*1024){return new Promise(p=>{let a="",c=!1;e.on("data",o=>{c||(a+=o,a.length>r&&(c=!0))}),e.on("end",()=>{if(c||!a)return p(void 0);try{p(JSON.parse(a))}catch{p(void 0)}}),e.on("error",()=>p(void 0))})}f(O,"I"),u(O,"v"),i(O,"readJsonBody");function W(){const e=D();if(e.length===0)return null;const r=v%e.length;return v=(v+1)%e.length,e[r]}f(W,"U"),u(W,"ee"),i(W,"pickChild");async function B(){const e=F++,r=childSockPath(e);cleanupSock(r);const p=["--enable-source-maps"];__filename.endsWith(".ts")&&p.unshift("--require","@swc-node/register");const a=R?G():-1,c=(0,node_child_process_1.fork)(__filename,{env:{...process.env,APP_RUNNER:"1",CHILD_SOCK_PATH:r,...a>=0&&{CHILD_DEBUG_PORT:String(inspectorPortFor(R,a))}},stdio:["inherit","pipe","pipe","ipc"],execArgv:p,execPath:V("pod")}),o={id:e,proc:c,healthy:!1,lastError:null,debugSlot:a,tail:new exit_reason_1.TailBuffer,booting:!0,spawnedAt:Date.now(),bootReloadSeq:se};return c.on("message",b=>{if(!b||typeof b!="object")return;const l=b;if(l.type==="ready"){if(o.socketPath=String(l.socketPath),o.healthy=!0,o.booting=!1,console.log(`[parent] Child#${o.id} ready on socket ${o.socketPath}`),oe)try{c.send?.({type:"watcher",testimony:oe})}catch{}if(se!==o.bootReloadSeq)try{c.send?.({type:"reload"})}catch{}}else l.type==="recycle-request"?U(o,String(l.reason||"it has outgrown its bound")):l.type==="inspector-url"?(o.inspectorUrl=String(l.url),console.log(`[parent] Child#${o.id} Debugger listening on ${l.url}`)):l.type==="reloaded"?(o.socketPath=String(l.socketPath),o.healthy=!0,console.log(`[parent] Child#${o.id} hot-swapped on socket ${o.socketPath}`)):l.type==="reload-error"?(o.lastError=String(l.error||"unknown reload error"),console.error(`[parent] Child#${o.id} reload error: ${o.lastError}`),o.healthy=!1):l.type==="boot-error"&&(o.lastError=String(l.error||"unknown boot error"),console.error(`[parent] Child#${o.id} boot error: ${o.lastError}`),o.healthy=!1,o.booting=!1)}),c.on("exit",(b,l)=>{o.booting=!1,o.debugSlot>=0&&(x.delete(o.debugSlot),o.debugSlot=-1);const N=l==="SIGINT"||l==="SIGTERM"||b===0;if(N?console.log(`[parent] Child#${o.id} exited cleanly (code=${b}, signal=${l??"none"})`):(console.error((0,exit_reason_1.crashReport)(`[parent] Child#${o.id} crashed (code=${b}, signal=${l??"none"}, pid=${o.proc.pid}, ${o.healthy?"was serving":"was not ready"})`,b,l,o.tail.snapshot())),o.lastError||(o.lastError=`Child exited abnormally (code=${b}, signal=${l??"none"})`)),o.healthy=!1,cleanupSock(o.socketPath,o.proc.pid),o.socketPath=void 0,!N&&!T){const K=_.indexOf(o);K>=0&&_.splice(K,1);const de=Date.now();if(I=I.filter(Z=>de-Z<3e4),I.length>=5){console.error(`[parent] crash-loop detected (${I.length} respawns/30s) \u2014 pausing auto-respawn; POST /webpack/reload to retry`);return}I.push(de),setTimeout(()=>{const Z=_.filter(xe=>xe.proc.killed===!1).length;!T&&Z<A&&(console.log(`[parent] respawning a crashed pod (${Z}/${A} live)`),B().catch(()=>{}))},1500).unref?.()}}),_.push(o),z(o),o}f(B,"X"),u(B,"te"),i(B,"spawnChild");async function t(e){A=Math.max(A,e);const r=_.filter(a=>a.proc.killed===!1),p=e-r.length;for(let a=0;a<p;a++)await B()}f(t,"t"),u(t,"r"),i(t,"ensurePoolSize");async function s(){const e=_.filter(r=>(!r.healthy||typeof r.socketPath!="string")&&!ie(r));await Promise.all(e.map(async r=>{try{r.proc.kill("SIGTERM")}catch{}cleanupSock(r.socketPath,r.proc.pid),r.socketPath=void 0;const p=_.indexOf(r);p>=0&&_.splice(p,1),await B()}))}f(s,"s"),u(s,"c"),i(s,"respawnUnhealthy");const g=new Set;let w=!1,S=0;const M=3e4,P=(()=>{const e=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return(Number.isFinite(e)&&e>=0?e:15*6e4)+6e4})();async function U(e,r){const p=i(c=>{console.log(`[parent] Child#${e.id} asked for a fresh pod (${r}) \u2014 not now: ${c}`);try{e.proc.send?.({type:"recycle-declined"})}catch{}},"decline");if(T||!_.includes(e))return;if(w)return p("another pod is already being replaced");const a=Date.now()-S;if(a<M)return p(`a pod was replaced ${Math.round(a/1e3)}s ago`);w=!0,console.log(`[parent] Child#${e.id} asked for a fresh pod \u2014 ${r}. Starting one; Child#${e.id} keeps serving until it is ready.`);try{const c=await B(),o=Date.now()+H;for(;!c.healthy&&!c.lastError&&!q(c)&&Date.now()<o;)await new Promise(N=>{setTimeout(N,100).unref?.()});if(T)return;if(!c.healthy){const N=_.indexOf(c);N>=0&&_.splice(N,1);try{c.proc.kill("SIGTERM")}catch{}return p(`its successor Child#${c.id} did not come up (${c.lastError??"no answer in time"})`)}const b=_.indexOf(e);b>=0&&_.splice(b,1),e.healthy=!1,g.add(e);const l=setTimeout(()=>{if(!q(e)){console.error(`[parent] Child#${e.id} was still running ${P}ms after it was retired \u2014 killing it`);try{e.proc.kill("SIGKILL")}catch{}}},P);l.unref?.(),e.proc.once("exit",()=>{clearTimeout(l),g.delete(e)});try{e.proc.send?.({type:"retire"})}catch{try{e.proc.kill("SIGTERM")}catch{}}S=Date.now(),console.log(`[parent] Child#${c.id} took over from Child#${e.id} (pid ${e.proc.pid} \u2192 ${c.proc.pid})`)}catch(c){p(`could not start a successor: ${c?.message??String(c)}`)}finally{w=!1}}f(U,"L"),u(U,"x"),i(U,"recyclePod");const j=[];function he(e){const r=path.dirname(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.resolve(BUNDLE_PATH)),p=path.join(r,`${e}.js`);if(!fs.existsSync(p))return console.error(`[parent] Worker "${e}" bundle not found: ${p}`),null;const a=["--enable-source-maps"];__filename.endsWith(".ts")&&a.unshift("--require","@swc-node/register");try{a.push("--require",require.resolve("@lensmcp/node-instrumentation/register"))}catch{}const c=inspectorPortFor(R||9229,ee+Math.max(0,WORKER_NAMES.indexOf(e)));a.push(R?`--inspect=127.0.0.1:${c}`:`--inspect-port=127.0.0.1:${c}`);const o=(0,node_child_process_1.fork)(p,{env:process.env,stdio:["inherit","pipe","pipe","ipc"],execArgv:a,execPath:V(`w-${e}`)}),b={name:e,proc:o,debugPort:c};return j.push(b),J(o,`\x1B[35m[worker:${e}] \x1B[0m`,l=>{const N=/Debugger listening on (wss?:\/\/\S+)/.exec(l);N&&(b.inspectorUrl=N[1])}),o.on("exit",(l,N)=>{N==="SIGINT"||N==="SIGTERM"||l===0||console.error(`[parent] Worker "${e}" crashed (code=${l}, signal=${N??"none"})`);const K=j.indexOf(b);K>=0&&j.splice(K,1)}),console.log(`[parent] Worker "${e}" started (pid=${o.pid})`),b}f(he,"ye"),u(he,"we"),i(he,"spawnWorkerProcess");const ke=(()=>{const e=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return Number.isFinite(e)&&e>=0?e:15*6e4})(),be=(()=>{const e=Number(process.env.LENSMCP_SWAP_MAX_DRAINING);return Number.isFinite(e)&&e>=1?Math.floor(e):1})(),ce=new Set,ve=i(e=>e.proc.exitCode!==null||e.proc.signalCode!==null,"workerExited");function ae(e,r){if(ce.delete(e),!ve(e)){console.error(`[parent] Worker "${e.name}" (pid=${e.proc.pid}) ${r} \u2014 killing it. A worker that returns from its SIGTERM handler but leaves a handle open (a Redis client handed to BullMQ is not closed by worker.close()) never exits on its own: close what it opened, or call process.exit().`);try{e.proc.kill("SIGKILL")}catch{}}}f(ae,"pe"),u(ae,"fe"),i(ae,"killDrainingWorker");function _e(e){try{e.proc.kill("SIGTERM")}catch{}if(ve(e))return;const r=[...ce].filter(a=>a.name===e.name);for(;r.length>=be;)ae(r.shift(),`was still running when a later reload replaced its successor (cap ${be})`);ce.add(e);const p=setTimeout(()=>ae(e,`was still running ${ke}ms after SIGTERM`),ke);p.unref?.(),e.proc.once("exit",()=>{clearTimeout(p),ce.delete(e)})}f(_e,"ke"),u(_e,"Ae"),i(_e,"retireWorker");function me(){for(const e of[...j])_e(e);j.length=0;for(const e of WORKER_NAMES)he(e)}f(me,"be"),u(me,"Te"),i(me,"restartWorkers");const Ie=debounce(async()=>{se+=1;const e=D();if(e.length>0){console.log(`[parent] Forwarding reload to ${e.length} child(ren)`);for(const r of e)r.proc.send?.({type:"reload"})}await s(),WORKER_NAMES.length>0&&me()},200),le=i(async(e,r)=>{if(e.method==="POST"&&e.url==="/webpack/reload"){r.writeHead(200,{"content-type":"application/json"}),r.end(JSON.stringify({ok:!0})),O(e).then(c=>L(c?.watcher)),Ie();return}if(e.method==="POST"&&e.url==="/webpack/watching"){const c=await O(e);L(c),r.writeHead(200,{"content-type":"application/json"}),r.end(JSON.stringify({ok:!0,relayed:oe!==void 0}));return}if(e.method==="POST"&&e.url==="/webpack/scale"){let c="";e.on("data",o=>{c+=o}),e.on("end",async()=>{let o=0;try{o=Number(JSON.parse(c||"{}").pods)||0}catch{}o=Math.max(1,Math.min(o,16)),await t(o),r.writeHead(200,{"content-type":"application/json"}),r.end(JSON.stringify({ok:!0,pods:o}))});return}if(e.method==="GET"&&e.url?.startsWith("/webpack/logs")){const c=new URL(e.url,"http://localhost").searchParams,o=Math.min(Math.max(Number(c.get("tail")??"100")||0,0),re),b=c.get("follow")!=="0",l=c.get("plain")==="1",N=!isOwnerOnlyTransport(e);r.writeHead(200,{"content-type":"text/plain; charset=utf-8","cache-control":"no-cache"});const K=o===0?"":C.slice(-o).join(""),de=l?K.replace(X,""):K;if(r.write(N?redactInspectorUrls(de):de),!b){r.end();return}const Z={res:r,plain:l,redact:N};k.add(Z),e.on("close",()=>k.delete(Z));return}if(e.method==="POST"&&e.url?.startsWith("/webpack/debug")){if(!isOwnerOnlyTransport(e)){r.writeHead(404,{"content-type":"application/json"}),r.end(JSON.stringify({error:"not found"}));return}const c=Number(new URL(e.url,"http://localhost").searchParams.get("port")||"");Number.isInteger(c)&&c>1024&&(R=c),R||(R=9229);const o=_.filter(l=>l.proc.exitCode===null&&l.proc.signalCode===null);for(const l of o){l.debugSlot<0&&(l.debugSlot=G());try{l.proc.send?.({type:"debug-open",port:inspectorPortFor(R,l.debugSlot)})}catch{}}for(const l of j)try{l.proc.kill("SIGUSR1")}catch{}const b=Date.now()+2e3;for(;Date.now()<b&&o.some(l=>!l.inspectorUrl);)await new Promise(l=>setTimeout(l,50));r.writeHead(200,{"content-type":"application/json"}),r.end(JSON.stringify({ok:!0,basePort:R,fixedPorts:usesFixedInspectorPorts(),pods:o.map(l=>({id:l.id,inspectorUrl:l.inspectorUrl??null})),workers:j.map(l=>({name:l.name,port:l.debugPort||inspectorPortOf(l.inspectorUrl),inspectorUrl:l.inspectorUrl??null}))},null,2)+`
16
- `);return}const p=matchGatewayRoute(e);if(p?.prependPrefix&&!e.url?.startsWith(p.prependPrefix)&&(e.url=p.prependPrefix+(e.url??"/")),p?.target){applyGatewayMiddleware(e),d.web(e,r,{target:p.target,autoRewrite:typeof p.target=="string",changeOrigin:!0},c=>{console.error(`[parent] proxy error to ${p.target}:`,c),r.statusCode=502,r.setHeader("content-type","text/plain; charset=utf-8"),r.end(`Upstream error from ${p.target}.`)});return}if(SERVICE_PREFIX){if(!e.url?.startsWith(SERVICE_PREFIX)){r.writeHead(404,{"content-type":"text/plain; charset=utf-8"}),r.end(`Not found. This service is mounted at ${SERVICE_PREFIX}/`);return}e.url=e.url.slice(SERVICE_PREFIX.length)||"/"}applyGatewayMiddleware(e);const a=W();if(!a){r.statusCode=503,r.setHeader("content-type","text/plain; charset=utf-8");const c=_.map(o=>`#${o.id}: ${o.lastError??"no error recorded"}`).join(`
12
+ })()`),eval(`require(${JSON.stringify(resolved)})`)}u(importFresh,"importFresh"),i(importFresh,"importFresh");function debounce(n,h){let g=null;return(..._)=>{g&&clearTimeout(g),g=setTimeout(()=>n(..._),h)}}if(u(debounce,"debounce"),i(debounce,"debounce"),process.env.APP_RUNNER==="1"){(0,stdio_guard_1.guardBrokenStdio)();const n=i(g=>{if(!inspector.url())try{inspector.open(g,"127.0.0.1",!1)}catch(B){console.warn(`[child] inspector.open(${g}) failed (port taken by another devserver?) \u2014 falling back to a random port:`,B.message);try{inspector.open(0,"127.0.0.1",!1)}catch{}}const _=inspector.url();_&&process.send&&process.send({type:"inspector-url",url:_})},"openInspector"),h=process.env.CHILD_DEBUG_PORT;if(h!==void 0&&h!==""){const g=Number(h);Number.isInteger(g)&&(g===0||g>1024)&&n(g)}try{require("@lensmcp/node-instrumentation/register")}catch{}(async()=>{let g=null,_=!1,B,j=!1;const v=(0,hot_swap_registries_1.registryPruningEnabled)(),Z=i((t,s)=>{const f=(0,hot_swap_registries_1.describePrune)(t,s);f&&console.log(f)},"logPrune");let $={app:null,handler:i((t,s)=>{s.statusCode=503,s.end("starting")},"handler"),inflight:0};const ee=(()=>{const t=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return Number.isFinite(t)&&t>=0?t:15*6e4})(),Y=i(t=>{const s=globalThis.__lensmcpActiveWork;if(typeof s!="function")return{count:0};try{const f=s(t);return{count:Number(f?.count??0),...f?.oldestStartedAt?{oldestStartedAt:f.oldestStartedAt}:{}}}catch{return{count:0}}},"activeWork"),te=(()=>{const t=Number(process.env.LENSMCP_SWAP_MAX_DRAINING);return Number.isFinite(t)&&t>=1?Math.floor(t):1})(),x=new Set,P=(0,swap_recycle_1.swapRecyclePolicy)();let oe,le=0;const ge=(()=>{const t=Number(process.env.LENSMCP_POD_RETIRE_NOTICE_MS);return Number.isFinite(t)&&t>=0?t:3500})();let K=!1,V=!1,p;const E=i(()=>{if(p===void 0)try{v8.setFlagsFromString("--expose-gc");const t=vm.runInNewContext("gc");p=typeof t=="function"?t:null}catch{p=null}try{p?.()}catch{}return process.memoryUsage().heapUsed},"liveHeap"),w=(()=>{if(!(0,error_stack_release_1.errorFrameReleaseEnabled)())return null;try{const t=path.dirname(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH))+path.sep,s=`${path.sep}node_modules${path.sep}`,f=new Set(Object.keys(require.cache));return(0,error_stack_release_1.createErrorFrameReleaser)(require.cache,{skip:i(y=>f.has(y)||y.startsWith(t)&&!y.slice(t.length).includes(s)&&!y.slice(t.length).startsWith(`node_modules${path.sep}`),"skip")})}catch{return null}})();let O=!1;function W(){if(!(!w||O))try{const t=w();t.errors>0&&console.log(`[child] read the stack of ${t.errors} Error object(s) that libraries created while loading and keep for good \u2014 unread, each held the functions that were on its stack, this bundle's included`)}catch(t){console.error("[child] could not release library error frames:",t),O=!0}}u(W,"z"),i(W,"releaseLibraryErrorFrames");const D=new Map;let b=Date.now();const T=i(()=>P.settleMs<=0||!_&&!j&&D.size===0&&Date.now()-b>=P.settleMs,"settled");let R;function A(t){if(!(!P.enabled||K||V)){if(P.settleMs<=0){F(t);return}R&&clearTimeout(R),R=setTimeout(()=>{R=void 0,T()?F(t):A(t)},P.settleMs),R.unref?.()}}u(A,"N"),i(A,"recycleCheckWhenSettled");const ne=i(()=>{if(P.stuckCloseMs<=0)return 0;const t=Date.now();let s=0;for(const f of D.values())t-f>=P.stuckCloseMs&&(s+=1);return s},"stuckCloses");function F(t){if(!P.enabled||K||V||!process.send)return;const s=v8.getHeapStatistics().heap_size_limit,f=i(m=>({swaps:le,usedBytes:m,limitBytes:s,stuckCloses:ne(),settled:T(),...oe===void 0?{}:{baselineBytes:oe}}),"state");if(!(0,swap_recycle_1.recycleReason)(P,f(process.memoryUsage().heapUsed)))return;const y=(0,swap_recycle_1.recycleReason)(P,f(E()));y&&(K=!0,console.log(`[child] asking for a fresh pod ${t} \u2014 ${y}. This pod keeps serving until its successor is ready. Size the bound with LENSMCP_SWAP_RECYCLE_HEAP_FACTOR / _HEAP_RATIO / _MIN_MB, or turn it off with LENSMCP_SWAP_RECYCLE=0.`),process.send({type:"recycle-request",reason:y}))}u(F,"K"),i(F,"considerRecycle");async function J(t,s){if(t.closed||(t.closed=!0,x.delete(t),s&&console.error(`[child] ${s}`),!t.app))return;D.set(t,Date.now());const f=P.enabled&&P.stuckCloseMs>0?setTimeout(()=>{D.has(t)&&(console.error(`[child] a previous app has been closing for ${Math.round(P.stuckCloseMs/1e3)}s and its close() has not returned \u2014 one of its shutdown hooks is waiting on something that does not end (a queue worker, a connection, a stream). It stays in memory until this pod is replaced.`),F("with a previous app stuck in close()"))},P.stuckCloseMs):void 0;f?.unref?.();try{await t.app.close()}catch(y){console.error("[child] error closing a previous app:",y)}finally{D.delete(t),b=Date.now(),f&&clearTimeout(f),t.app=null,t.handler=(y,m)=>{m.statusCode=503,m.end("closed")}}if(t.superseded){try{Z((0,hot_swap_registries_1.pruneRegistries)(t.superseded,"serve"),"after closing the previous app")}catch(y){console.error("[child] could not release the previous app's class registrations:",y)}t.superseded=void 0}A("after closing the previous app")}u(J,"Q"),i(J,"closeGeneration");async function de(t){for(;x.size>=te;){const m=x.values().next().value;if(!m)break;await J(m,`closing a still-draining generation early \u2014 ${x.size} were pending and the cap is ${te} (each holds a whole app: DI container, DB pool, queue workers). Raise LENSMCP_SWAP_MAX_DRAINING if this pod legitimately needs more.`)}x.add(t);const s=Date.now(),f=i(()=>({inflight:t.inflight,work:Y(t.workGen).count}),"busy");for(;ee>0&&Date.now()-s<ee;){if(t.closed)return;const m=f();if(m.inflight===0&&m.work===0)break;await new Promise(C=>{setTimeout(C,250).unref?.()})}if(t.closed)return;const y=f();y.inflight>0||y.work>0?console.error(`[child] swap drain expired after ${Date.now()-s}ms \u2014 closing the previous app with ${y.inflight} in-flight request(s) and ${y.work} background job(s) still running. A queue job killed here keeps its lock until the TTL lapses. Raise LENSMCP_SWAP_DRAIN_MS (currently ${ee}ms) if this is legitimate work.`):Date.now()-s>250&&console.log(`[child] previous app drained in ${Date.now()-s}ms \u2014 closing it`),await J(t)}u(de,"he"),i(de,"drainThenClose");async function M(){if(_)return j=!0,console.log("[child] Reload deferred \u2014 will re-swap after current swap completes"),g;_=!0,b=Date.now(),process.removeAllListeners("uncaughtException"),process.removeAllListeners("unhandledRejection"),process.on("uncaughtException",(S,L)=>{console.error(`[child] uncaughtException (${L}):`,S)}),process.on("unhandledRejection",S=>{const L=S instanceof Error?S.stack||S.message:String(S);L.includes("FronteggContextScope")||L.includes("populateLoggerMetadata")||console.error("[child] unhandledRejection:",S)});let t;if(v)try{t=(0,hot_swap_registries_1.captureRegistries)()}catch{t=void 0}try{try{await importFresh(BUNDLE_PATH)}catch(S){if(!(S instanceof SyntaxError))throw S;console.warn(`[child] bundle was unreadable mid-write (${S.message}) \u2014 retrying the swap once`),await new Promise(L=>setTimeout(L,400)),await importFresh(BUNDLE_PATH)}}catch(S){throw _=!1,b=Date.now(),S}if(typeof global.createChildApp!="function")throw _=!1,b=Date.now(),new Error(`Bundle '${BUNDLE_PATH}' does not export createChildApp() and the zero-touch bridge is not active. Either install @lensmcp/node-instrumentation (a plain NestFactory.create + app.listen main.ts then just works) or set global.createChildApp in main.ts when DEVSERVER_MODE === '1'.`);let s;if(t)try{s=(0,hot_swap_registries_1.supersededSince)(t),Z((0,hot_swap_registries_1.pruneRegistries)(s,"build"),"at the swap")}catch(S){console.error("[child] could not release superseded class registrations:",S)}const f=global.__lensmcpBeginWorkGeneration,y=typeof f=="function"?f():void 0;let m;try{m=await global.createChildApp()}catch(S){throw _=!1,b=Date.now(),S}const C=$;return s?.size&&(C.app?C.superseded=s:Z((0,hot_swap_registries_1.pruneRegistries)(s,"serve"),"at the swap")),g=m,$={app:m,handler:m.handler,inflight:0,...y===void 0?{}:{workGen:y}},console.log("[child] Swapped to fresh app (previous draining in background)"),W(),C.app&&(le+=1,de(C).catch(S=>console.error("[child] background close error:",S)),setTimeout(()=>F("30s after a hot swap"),3e4).unref?.()),_=!1,b=Date.now(),j?(j=!1,M()):m}u(M,"V"),i(M,"swapNow");const re=debounce(async()=>{try{console.log("[child] /webpack/reload"),await M()}catch(t){console.error("[child] reload failed:",t)}},250),G=http.createServer((t,s)=>{if(t.method==="POST"&&t.url==="/webpack/reload"){s.writeHead(200,{"content-type":"application/json"}),s.end(JSON.stringify({ok:!0})),re();return}if(t.method==="GET"&&t.url==="/__lensmcp/alive"){const y=t.headers["x-internal-token"],m=process.env.LENSMCP_SERVICE_KEY;if(m&&y!==m){s.writeHead(404,{"content-type":"text/plain"}),s.end("not found");return}const C=Y();s.writeHead(200,{"content-type":"application/json","cache-control":"no-store"}),s.end(JSON.stringify({ok:!0,pid:process.pid,swapping:_,inflight:$.inflight,oldestInflightAt:$.oldestAt,activeWork:C.count,oldestWorkAt:C.oldestStartedAt,keyFingerprint:serviceKeyFingerprint(),...B?{watcher:B}:{},...Number.isFinite(Number(process.env.LENSMCP_POD_GENERATION))&&process.env.LENSMCP_POD_GENERATION?{podGeneration:Number(process.env.LENSMCP_POD_GENERATION)}:{}}));return}const f=$;f.inflight+=1,f.oldestAt===void 0&&(f.oldestAt=Date.now()),s.on("close",()=>{f.inflight-=1,f.inflight===0&&(f.oldestAt=void 0)}),f.handler(t,s)});G.keepAliveTimeout=0;const I=process.env.CHILD_SOCK_PATH;process.on("disconnect",()=>{cleanupSock(I),process.exit(0)});try{const t=path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.join(__dirname,BUNDLE_PATH);if((0,schema_first_instance_1.schemaPrewarmEnabled)())try{const s=(0,schema_first_instance_1.prewarmZodFor)(t);s?.created&&console.log(`[child] zod${s.version?` ${s.version}`:""}: built ${s.created} throwaway schemas first, so none of the bundle's own is the first of its class`)}catch{}if((0,redis_disconnect_fix_1.redisDisconnectFixEnabled)())try{const s=(0,redis_disconnect_fix_1.finishStrandedDisconnectsFor)(t);s?.patched&&console.log(`[child] ioredis${s.versions.length?` ${s.versions.join(", ")}`:""}: a disconnect() between reconnect attempts now ends the client \u2014 it used to leave a queue worker's close() waiting for good`)}catch{}await M(),P.enabled&&P.heapFactor>0&&(oe=E()),console.log(`[child] Using bundle: ${t}`),claimSock(I),G.listen(I,()=>{console.log(`[child] Listening on ${I}`),process.send&&process.send({type:"ready",socketPath:I})})}catch(t){console.error("[child] Startup error:",t),process.send&&process.send({type:"boot-error",error:String(t?.stack||t)}),process.exitCode=1;return}process.on("message",async t=>{if(!(!t||typeof t!="object")){if(t.type==="debug-open"){const s=Number(t.port);n(Number.isInteger(s)&&s>1024?s:0);return}if(t.type==="watcher"){const s=t.testimony;s&&typeof s=="object"&&(B=s);return}if(t.type==="recycle-declined"){K=!1;return}if(t.type==="retire"){U();return}if(t.type==="reload"){if(V)return;try{await M(),process.send&&process.send({type:"reloaded",socketPath:I})}catch(s){console.error("[child] reload error:",s),process.send&&process.send({type:"reload-error",error:String(s?.stack||s)})}}}});async function U(){if(V)return;V=!0,console.log("[child] retiring \u2014 a fresh pod has taken over; finishing in-flight work, then exiting");try{fs.writeFileSync(sockRetiringPath(I),String(process.pid),{flag:"w",mode:384})}catch{}await new Promise(s=>{setTimeout(s,ge).unref?.()}),cleanupSock(I),G.close();const t=Date.now();for(;Date.now()-t<ee&&(G.closeIdleConnections?.(),!($.inflight===0&&Y().count===0));)await new Promise(s=>{setTimeout(s,250).unref?.()});setTimeout(()=>process.exit(0),3e4).unref?.();try{await g?.close()}catch(s){console.error("[child] close error while retiring:",s)}process.exit(0)}u(U,"ee"),i(U,"retire"),process.on("beforeExit",()=>{try{inspector?.close?.()}catch{}});const X=i(async t=>{console.log(`[child ${t}] shutting down\u2026`);const s=g?.close().catch(y=>console.error("[child] close error:",y)),f=new Promise(y=>G.close(()=>y()));cleanupSock(I),setTimeout(()=>process.exit(0),700).unref(),await Promise.all([s,f]),process.exit(0)},"shutdown");["SIGINT","SIGTERM","SIGHUP","SIGQUIT","SIGUSR2"].forEach(t=>{process.on(t,()=>{inspector?.close?.(),X(t)})})})()}else{let n=u(function(p){x.push(p),x.length>te&&x.splice(0,x.length-te),ee?.write(p.replace(Y,""));for(const E of P)try{const w=E.plain?p.replace(Y,""):p;E.res.write(E.redact?redactInspectorUrls(w):w)}catch{P.delete(E)}},"P");i(n,"emitLogLine");const h=["\x1B[36m","\x1B[33m","\x1B[35m","\x1B[32m","\x1B[34m","\x1B[31m"],g="\x1B[0m",_=Math.max(1,Number(process.env.CHILD_COUNT||1)),B=LENSMCP_WS_KEY||path.basename(process.cwd()),j=i(p=>(0,process_name_1.namedExecPath)((0,process_name_1.processName)(B,SERVICE_NAME||"service",p)),"execPathFor");let v=(()=>{const p=Number(process.env.LENSMCP_DEBUG_PORT||"");return Number.isInteger(p)&&p>1024?p:0})();const Z=20;v&&(console.warn("[parent] DEBUGGER ENABLED \u2014 pods and workers open a Node inspector. Node's inspector has NO authentication: the ws:// URL's UUID is the whole credential, and any account on this host that obtains it can run code as you. Do not enable this on a shared machine. (issues/codex-security/06)"),console.warn(usesFixedInspectorPorts()?`[parent] ${exports.DEBUG_FIXED_PORTS_ENV} is set \u2014 inspectors bind PREDICTABLE ports (${v}+slot, workers ${v}+${Z}+i). Any account on this host can connect to 127.0.0.1:${v} and read the session UUID from /json/list. Unset it to use ephemeral ports.`:`[parent] Inspectors bind an EPHEMERAL loopback port; attach via the printed "Debugger listening" URL, or \`lensmcp debug <service>\` (control socket). Set ${exports.DEBUG_FIXED_PORTS_ENV}=1 for fixed ports if your IDE needs a pre-configured attach port \u2014 any account on this host can then reach them.`));const $=process.env.LENSMCP_LOG_FILE||"",ee=$?(()=>{try{fs.mkdirSync(path.dirname($),{recursive:!0});const p=fs.createWriteStream($,{flags:"a",mode:384});try{fs.chmodSync($,384)}catch{}return p}catch(p){return console.warn(`[parent] cannot open log file ${$}:`,p.message),null}})():null,Y=/\x1b\[[0-9;]*m/g,te=2e3,x=[],P=new Set;for(const p of["log","info","warn","error"]){const E=console[p].bind(console);console[p]=(...w)=>{E(...w),n(w.map(O=>typeof O=="string"?O:util.inspect(O)).join(" ")+`
13
+ `)}}const oe=i(p=>h[(p-1)%h.length],"colorFor"),le=i(p=>{if(_===1)return"";const E=`[child#${p}] `;return`${oe(p)}${E}${g}`},"tagFor"),ge=i(p=>p.startsWith("{")&&p.endsWith("}"),"isJsonLog"),K=i((p,E,w)=>{const O=prettyFactory({sync:!0,colorize:!0,crlf:!0,messageKey:"message",errorLikeObjectKeys:["err","error"],errorProps:"type,message,stack",ignore:["logContext","context","hostname","req","res","err.driverError","module","cloudEnvironment","frontegg-application-id","frontegg-tenant-id","frontegg-trace-id","frontegg-vendor-id","host","service","version","err","error"].join(","),messageFormat:"{if module}[{module}] {end}{if context}[{context}] {end}{if logContext}[{logContext}] {end}{message}",customPrettifiers:{stack:i(b=>`
14
+ `+String(b),"stack")}}),W=i((b,T)=>{const R=b==="stdout"?process.stdout:process.stderr;try{w?.(T)}catch{}const A=ge(T)?O(T):`${T}
15
+ `;R.write(`${E}${A}`),n(`${E}${A}`)},"write"),D=i((b,T)=>{if(!b)return;const R=readline.createInterface({input:b});R.on("line",A=>W(T,A)),R.on("close",()=>{})},"attach");D(p.stdout,"stdout"),D(p.stderr,"stderr")},"wireProcLogging"),V=i(p=>K(p.proc,le(p.id),E=>p.tail.push(E)),"wireChildLogging");(async()=>{ensureOwnerOnlyDir(SOCK_DIR);const p=httpProxy.createProxyServer({});let E=Number(process.env.PORT)||0;E||(E=9090);const w=[],O=new Set;function W(){let e=0;for(;O.has(e);)e++;return O.add(e),e}u(W,"z"),i(W,"allocDebugSlot");let D=1,b=0,T=!1,R=_,A=[],ne=0;const F=(()=>{const e=Number(process.env.LENSMCP_POD_BOOT_GRACE_MS);return Number.isFinite(e)&&e>=0?e:12e4})(),J=i(e=>e.proc.exitCode!==null||e.proc.signalCode!==null,"childExited"),de=i(e=>e.booting&&!J(e)&&Date.now()-e.spawnedAt<F,"stillBooting");function M(){return w.filter(e=>e.healthy&&typeof e.socketPath=="string")}u(M,"V"),i(M,"healthyChildren");let re;function G(e){if(!e||typeof e!="object")return;const r=e;if(r.schemaVersion===1){re=r;for(const d of w)try{d.proc.send?.({type:"watcher",testimony:r})}catch{}}}u(G,"U"),i(G,"recordWatcherTestimony");function I(e,r=256*1024){return new Promise(d=>{let a="",c=!1;e.on("data",o=>{c||(a+=o,a.length>r&&(c=!0))}),e.on("end",()=>{if(c||!a)return d(void 0);try{d(JSON.parse(a))}catch{d(void 0)}}),e.on("error",()=>d(void 0))})}u(I,"v"),i(I,"readJsonBody");function U(){const e=M();if(e.length===0)return null;const r=b%e.length;return b=(b+1)%e.length,e[r]}u(U,"ee"),i(U,"pickChild");async function X(){const e=D++,r=childSockPath(e);cleanupSock(r);const d=["--enable-source-maps"];__filename.endsWith(".ts")&&d.unshift("--require","@swc-node/register");const a=v?W():-1,c=(0,node_child_process_1.fork)(__filename,{env:{...process.env,APP_RUNNER:"1",CHILD_SOCK_PATH:r,...a>=0&&{CHILD_DEBUG_PORT:String(inspectorPortFor(v,a))}},stdio:["inherit","pipe","pipe","ipc"],execArgv:d,execPath:j("pod")}),o={id:e,proc:c,healthy:!1,lastError:null,debugSlot:a,tail:new exit_reason_1.TailBuffer,booting:!0,spawnedAt:Date.now(),bootReloadSeq:ne};return c.on("message",k=>{if(!k||typeof k!="object")return;const l=k;if(l.type==="ready"){if(o.socketPath=String(l.socketPath),o.healthy=!0,o.booting=!1,console.log(`[parent] Child#${o.id} ready on socket ${o.socketPath}`),re)try{c.send?.({type:"watcher",testimony:re})}catch{}if(ne!==o.bootReloadSeq)try{c.send?.({type:"reload"})}catch{}}else l.type==="recycle-request"?L(o,String(l.reason||"it has outgrown its bound")):l.type==="inspector-url"?(o.inspectorUrl=String(l.url),console.log(`[parent] Child#${o.id} Debugger listening on ${l.url}`)):l.type==="reloaded"?(o.socketPath=String(l.socketPath),o.healthy=!0,console.log(`[parent] Child#${o.id} hot-swapped on socket ${o.socketPath}`)):l.type==="reload-error"?(o.lastError=String(l.error||"unknown reload error"),console.error(`[parent] Child#${o.id} reload error: ${o.lastError}`),o.healthy=!1):l.type==="boot-error"&&(o.lastError=String(l.error||"unknown boot error"),console.error(`[parent] Child#${o.id} boot error: ${o.lastError}`),o.healthy=!1,o.booting=!1)}),c.on("exit",(k,l)=>{o.booting=!1,o.debugSlot>=0&&(O.delete(o.debugSlot),o.debugSlot=-1);const N=l==="SIGINT"||l==="SIGTERM"||k===0;if(N?console.log(`[parent] Child#${o.id} exited cleanly (code=${k}, signal=${l??"none"})`):(console.error((0,exit_reason_1.crashReport)(`[parent] Child#${o.id} crashed (code=${k}, signal=${l??"none"}, pid=${o.proc.pid}, ${o.healthy?"was serving":"was not ready"})`,k,l,o.tail.snapshot())),o.lastError||(o.lastError=`Child exited abnormally (code=${k}, signal=${l??"none"})`)),o.healthy=!1,cleanupSock(o.socketPath,o.proc.pid),o.socketPath=void 0,!N&&!T){const q=w.indexOf(o);q>=0&&w.splice(q,1);const ae=Date.now();if(A=A.filter(Q=>ae-Q<3e4),A.length>=5){console.error(`[parent] crash-loop detected (${A.length} respawns/30s) \u2014 pausing auto-respawn; POST /webpack/reload to retry`);return}A.push(ae),setTimeout(()=>{const Q=w.filter($e=>$e.proc.killed===!1).length;!T&&Q<R&&(console.log(`[parent] respawning a crashed pod (${Q}/${R} live)`),X().catch(()=>{}))},1500).unref?.()}}),w.push(o),V(o),o}u(X,"te"),i(X,"spawnChild");async function t(e){R=Math.max(R,e);const r=w.filter(a=>a.proc.killed===!1),d=e-r.length;for(let a=0;a<d;a++)await X()}u(t,"r"),i(t,"ensurePoolSize");async function s(){const e=w.filter(r=>(!r.healthy||typeof r.socketPath!="string")&&!de(r));await Promise.all(e.map(async r=>{try{r.proc.kill("SIGTERM")}catch{}cleanupSock(r.socketPath,r.proc.pid),r.socketPath=void 0;const d=w.indexOf(r);d>=0&&w.splice(d,1),await X()}))}u(s,"c"),i(s,"respawnUnhealthy");const f=new Set;let y=!1,m=0;const C=3e4,S=(()=>{const e=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return(Number.isFinite(e)&&e>=0?e:15*6e4)+6e4})();async function L(e,r){const d=i(c=>{console.log(`[parent] Child#${e.id} asked for a fresh pod (${r}) \u2014 not now: ${c}`);try{e.proc.send?.({type:"recycle-declined"})}catch{}},"decline");if(T||!w.includes(e))return;if(y)return d("another pod is already being replaced");const a=Date.now()-m;if(a<C)return d(`a pod was replaced ${Math.round(a/1e3)}s ago`);y=!0,console.log(`[parent] Child#${e.id} asked for a fresh pod \u2014 ${r}. Starting one; Child#${e.id} keeps serving until it is ready.`);try{const c=await X(),o=Date.now()+F;for(;!c.healthy&&!c.lastError&&!J(c)&&Date.now()<o;)await new Promise(N=>{setTimeout(N,100).unref?.()});if(T)return;if(!c.healthy){const N=w.indexOf(c);N>=0&&w.splice(N,1);try{c.proc.kill("SIGTERM")}catch{}return d(`its successor Child#${c.id} did not come up (${c.lastError??"no answer in time"})`)}const k=w.indexOf(e);k>=0&&w.splice(k,1),e.healthy=!1,f.add(e);const l=setTimeout(()=>{if(!J(e)){console.error(`[parent] Child#${e.id} was still running ${S}ms after it was retired \u2014 killing it`);try{e.proc.kill("SIGKILL")}catch{}}},S);l.unref?.(),e.proc.once("exit",()=>{clearTimeout(l),f.delete(e)});try{e.proc.send?.({type:"retire"})}catch{try{e.proc.kill("SIGTERM")}catch{}}m=Date.now(),console.log(`[parent] Child#${c.id} took over from Child#${e.id} (pid ${e.proc.pid} \u2192 ${c.proc.pid})`)}catch(c){d(`could not start a successor: ${c?.message??String(c)}`)}finally{y=!1}}u(L,"x"),i(L,"recyclePod");const H=[];function ye(e){const r=path.dirname(path.isAbsolute(BUNDLE_PATH)?BUNDLE_PATH:path.resolve(BUNDLE_PATH)),d=path.join(r,`${e}.js`);if(!fs.existsSync(d))return console.error(`[parent] Worker "${e}" bundle not found: ${d}`),null;const a=["--enable-source-maps"];__filename.endsWith(".ts")&&a.unshift("--require","@swc-node/register");try{a.push("--require",require.resolve("@lensmcp/node-instrumentation/register"))}catch{}const c=inspectorPortFor(v||9229,Z+Math.max(0,WORKER_NAMES.indexOf(e)));a.push(v?`--inspect=127.0.0.1:${c}`:`--inspect-port=127.0.0.1:${c}`);const o=(0,node_child_process_1.fork)(d,{env:process.env,stdio:["inherit","pipe","pipe","ipc"],execArgv:a,execPath:j(`w-${e}`)}),k={name:e,proc:o,debugPort:c};return H.push(k),K(o,`\x1B[35m[worker:${e}] \x1B[0m`,l=>{const N=/Debugger listening on (wss?:\/\/\S+)/.exec(l);N&&(k.inspectorUrl=N[1])}),o.on("exit",(l,N)=>{N==="SIGINT"||N==="SIGTERM"||l===0||console.error(`[parent] Worker "${e}" crashed (code=${l}, signal=${N??"none"})`);const q=H.indexOf(k);q>=0&&H.splice(q,1)}),console.log(`[parent] Worker "${e}" started (pid=${o.pid})`),k}u(ye,"we"),i(ye,"spawnWorkerProcess");const me=(()=>{const e=Number(process.env.LENSMCP_SWAP_DRAIN_MS);return Number.isFinite(e)&&e>=0?e:15*6e4})(),Se=(()=>{const e=Number(process.env.LENSMCP_SWAP_MAX_DRAINING);return Number.isFinite(e)&&e>=1?Math.floor(e):1})(),se=new Set,Pe=i(e=>e.proc.exitCode!==null||e.proc.signalCode!==null,"workerExited");function pe(e,r){if(se.delete(e),!Pe(e)){console.error(`[parent] Worker "${e.name}" (pid=${e.proc.pid}) ${r} \u2014 killing it. A worker that returns from its SIGTERM handler but leaves a handle open (a Redis client handed to BullMQ is not closed by worker.close()) never exits on its own: close what it opened, or call process.exit().`);try{e.proc.kill("SIGKILL")}catch{}}}u(pe,"fe"),i(pe,"killDrainingWorker");function ke(e){try{e.proc.kill("SIGTERM")}catch{}if(Pe(e))return;const r=[...se].filter(a=>a.name===e.name);for(;r.length>=Se;)pe(r.shift(),`was still running when a later reload replaced its successor (cap ${Se})`);se.add(e);const d=setTimeout(()=>pe(e,`was still running ${me}ms after SIGTERM`),me);d.unref?.(),e.proc.once("exit",()=>{clearTimeout(d),se.delete(e)})}u(ke,"Ae"),i(ke,"retireWorker");function be(){for(const e of[...H])ke(e);H.length=0;for(const e of WORKER_NAMES)ye(e)}u(be,"Te"),i(be,"restartWorkers");const Ae=debounce(async()=>{ne+=1;const e=M();if(e.length>0){console.log(`[parent] Forwarding reload to ${e.length} child(ren)`);for(const r of e)r.proc.send?.({type:"reload"})}await s(),WORKER_NAMES.length>0&&be()},200),ie=i(async(e,r)=>{if(e.method==="POST"&&e.url==="/webpack/reload"){r.writeHead(200,{"content-type":"application/json"}),r.end(JSON.stringify({ok:!0})),I(e).then(c=>G(c?.watcher)),Ae();return}if(e.method==="POST"&&e.url==="/webpack/watching"){const c=await I(e);G(c),r.writeHead(200,{"content-type":"application/json"}),r.end(JSON.stringify({ok:!0,relayed:re!==void 0}));return}if(e.method==="POST"&&e.url==="/webpack/scale"){let c="";e.on("data",o=>{c+=o}),e.on("end",async()=>{let o=0;try{o=Number(JSON.parse(c||"{}").pods)||0}catch{}o=Math.max(1,Math.min(o,16)),await t(o),r.writeHead(200,{"content-type":"application/json"}),r.end(JSON.stringify({ok:!0,pods:o}))});return}if(e.method==="GET"&&e.url?.startsWith("/webpack/logs")){const c=new URL(e.url,"http://localhost").searchParams,o=Math.min(Math.max(Number(c.get("tail")??"100")||0,0),te),k=c.get("follow")!=="0",l=c.get("plain")==="1",N=!isOwnerOnlyTransport(e);r.writeHead(200,{"content-type":"text/plain; charset=utf-8","cache-control":"no-cache"});const q=o===0?"":x.slice(-o).join(""),ae=l?q.replace(Y,""):q;if(r.write(N?redactInspectorUrls(ae):ae),!k){r.end();return}const Q={res:r,plain:l,redact:N};P.add(Q),e.on("close",()=>P.delete(Q));return}if(e.method==="POST"&&e.url?.startsWith("/webpack/debug")){if(!isOwnerOnlyTransport(e)){r.writeHead(404,{"content-type":"application/json"}),r.end(JSON.stringify({error:"not found"}));return}const c=Number(new URL(e.url,"http://localhost").searchParams.get("port")||"");Number.isInteger(c)&&c>1024&&(v=c),v||(v=9229);const o=w.filter(l=>l.proc.exitCode===null&&l.proc.signalCode===null);for(const l of o){l.debugSlot<0&&(l.debugSlot=W());try{l.proc.send?.({type:"debug-open",port:inspectorPortFor(v,l.debugSlot)})}catch{}}for(const l of H)try{l.proc.kill("SIGUSR1")}catch{}const k=Date.now()+2e3;for(;Date.now()<k&&o.some(l=>!l.inspectorUrl);)await new Promise(l=>setTimeout(l,50));r.writeHead(200,{"content-type":"application/json"}),r.end(JSON.stringify({ok:!0,basePort:v,fixedPorts:usesFixedInspectorPorts(),pods:o.map(l=>({id:l.id,inspectorUrl:l.inspectorUrl??null})),workers:H.map(l=>({name:l.name,port:l.debugPort||inspectorPortOf(l.inspectorUrl),inspectorUrl:l.inspectorUrl??null}))},null,2)+`
16
+ `);return}const d=matchGatewayRoute(e);if(d?.prependPrefix&&!e.url?.startsWith(d.prependPrefix)&&(e.url=d.prependPrefix+(e.url??"/")),d?.target){applyGatewayMiddleware(e),p.web(e,r,{target:d.target,autoRewrite:typeof d.target=="string",changeOrigin:!0},c=>{console.error(`[parent] proxy error to ${d.target}:`,c),r.statusCode=502,r.setHeader("content-type","text/plain; charset=utf-8"),r.end(`Upstream error from ${d.target}.`)});return}if(SERVICE_PREFIX){if(!e.url?.startsWith(SERVICE_PREFIX)){r.writeHead(404,{"content-type":"text/plain; charset=utf-8"}),r.end(`Not found. This service is mounted at ${SERVICE_PREFIX}/`);return}e.url=e.url.slice(SERVICE_PREFIX.length)||"/"}applyGatewayMiddleware(e);const a=U();if(!a){r.statusCode=503,r.setHeader("content-type","text/plain; charset=utf-8");const c=w.map(o=>`#${o.id}: ${o.lastError??"no error recorded"}`).join(`
17
17
  `);r.end(`No healthy children available. POST /webpack/reload to recover.
18
18
 
19
19
  Last errors:
20
- ${c}`);return}d.web(e,r,{target:{socketPath:a.socketPath},headers:{"x-proxy-child-id":String(a.id)}},c=>{console.error(`[parent] proxy error to Child#${a.id}:`,c),a.healthy=!1,a.lastError=String(c?.stack||c),r.statusCode=502,r.setHeader("content-type","text/plain; charset=utf-8"),r.end(`Upstream error from Child#${a.id}. Try /webpack/reload.
21
- ${a.lastError}`)})},"requestHandler");let Q,pe,Ee;const fe=[];if(GATEWAY_HTTPS){const e=require("./basic-ssl"),r=GATEWAY_ROUTES.map(a=>a.host).filter(a=>!!a),p=path.join(process.cwd(),"node_modules",".cache","davnx-webpack");pe=e.getCertificateSync(p,SERVICE_NAME||"lensmcp.dev",r),Ee=e.caCertPath(),Q=require("node:https").createServer({key:pe,cert:pe},le)}else Q=http.createServer(le);const Ne=i((e,r,p)=>{const a=matchGatewayRoute(e);if(a?.prependPrefix&&!e.url?.startsWith(a.prependPrefix)&&(e.url=a.prependPrefix+(e.url??"/")),a?.target){d.ws(e,r,p,{target:a.target,changeOrigin:!0},()=>r.destroy());return}const c=W();if(!c){r.destroy();return}d.ws(e,r,p,{target:{socketPath:c.socketPath}},()=>r.destroy())},"upgradeHandler");Q.on("upgrade",Ne);const Te=2e3;let Re=!1;Q.on("error",e=>{if(e.code==="EADDRINUSE"){Re||(Re=!0,console.warn(`[parent] public port ${E} already in use \u2014 continuing on the unix-socket pool only (gateway routing is unaffected) and retrying the bind every ${Te/1e3}s. Give this service a distinct cluster.port if this is not a rolling handoff.`)),setTimeout(()=>{!T&&!Q.listening&&Q.listen(E)},Te).unref?.();return}console.error("[parent] public server error:",e)}),await t(m);for(const e of WORKER_NAMES)he(e);Q.listen(E,()=>{const e=GATEWAY_HTTPS?"https":"http";console.log(`[parent] Listening on ${e}://localhost:${E}`),SERVICE_PREFIX&&console.log(`[parent] Service prefix: "${SERVICE_PREFIX}" (enforced \u2014 requests without it will get 404)`),gatewayMiddleware&&console.log(`[parent] Gateway middleware: ACTIVE (${GATEWAY_MIDDLEWARE_PATH})`),GATEWAY_ROUTES.length>0&&console.log(`[parent] Gateway routes: ${GATEWAY_ROUTES.map(r=>`${r.host??"*"}${r.prefix??"/"}\u2192${r.target??"children"}`).join(" ")}`),Ee&&(console.log("[parent] HTTPS dev CA (trust ONCE, then rotations/new hostnames stay green):"),console.log(`[parent] sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${Ee}`)),console.log(`POST ${e}://localhost:${E}/webpack/reload to trigger rolling swap/respawn`)});const ge=Number(process.env.INTERNAL_PORT||0);if(ge>0){const e=i((p,a)=>{const c=W();if(!c){a.statusCode=503,a.setHeader("content-type","text/plain; charset=utf-8"),a.end("No healthy children available.");return}d.web(p,a,{target:{socketPath:c.socketPath}},o=>{c.healthy=!1,c.lastError=String(o?.stack||o),a.statusCode=502,a.end(`Upstream error from Child#${c.id}.`)})},"internalHandler"),r=http.createServer(e);r.on("upgrade",(p,a,c)=>{const o=W();if(!o){a.destroy();return}d.ws(p,a,c,{target:{socketPath:o.socketPath}},()=>a.destroy())}),r.on("error",p=>{console.warn(`[parent] internal port ${ge} unavailable (${p.code}).`)}),r.listen(ge,()=>{console.log(`[parent] Internal (service-to-service, no gateway middleware) on http://localhost:${ge}`)}),fe.push(r)}const $e=(()=>{try{return JSON.parse(process.env.GATEWAY_EXTRA_PORTS||"[]")}catch{return[]}})();for(const e of $e){if(!Number.isInteger(e)||e===Number(E))continue;const r=GATEWAY_HTTPS?require("node:https").createServer({key:pe,cert:pe},le):http.createServer(le);r.on("upgrade",Ne),r.on("error",p=>{console.warn(`[parent] extra port ${e} unavailable (${p.code}) \u2014 main port still up.`)}),r.listen(e,()=>{console.log(`[parent] Also listening on ${GATEWAY_HTTPS?"https":"http"}://localhost:${e}`)}),fe.push(r)}const Se=path.join(SOCK_DIR,"parent.sock");claimSock(Se);const Pe=http.createServer(le);Pe.on("error",e=>{console.warn(`[parent] control socket unavailable (${e.code}) \u2014 lensmcp logs/debug attach disabled.`)}),Pe.listen(Se),fe.push(Pe);const Ae=i(async e=>{T=!0,console.log(`[${e}] [parent] shutting down\u2026`),cleanupSock(Se);for(const r of fe)try{r.close()}catch{}for(const r of j)try{r.proc.kill("SIGTERM")}catch{}for(const r of[...ce])ae(r,"was still draining when its devserver shut down");for(const r of g)try{r.proc.kill("SIGTERM")}catch{}for(const r of _){try{r.proc.kill("SIGTERM")}catch{}r.socketPath&&cleanupSock(r.socketPath,r.proc.pid)}try{fs.rmdirSync(SOCK_DIR)}catch{}setTimeout(()=>process.exit(0),700).unref()},"shutdown");["SIGINT","SIGTERM","SIGHUP","SIGQUIT","SIGUSR2"].forEach(e=>process.on(e,()=>{Ae(e)}));const ye=Number(process.env.LENSMCP_GATEWAY_PID??0);if(Number.isInteger(ye)&&ye>0){const e=setInterval(()=>{try{process.kill(ye,0)}catch(r){if(r.code==="EPERM")return;clearInterval(e),console.error(`[parent] gateway (pid ${ye}) is gone \u2014 shutting the pod down to avoid an orphan tree.`),Ae("gateway-gone")}},5e3);e.unref()}})()}
20
+ ${c}`);return}p.web(e,r,{target:{socketPath:a.socketPath},headers:{"x-proxy-child-id":String(a.id)}},c=>{console.error(`[parent] proxy error to Child#${a.id}:`,c),a.healthy=!1,a.lastError=String(c?.stack||c),r.statusCode=502,r.setHeader("content-type","text/plain; charset=utf-8"),r.end(`Upstream error from Child#${a.id}. Try /webpack/reload.
21
+ ${a.lastError}`)})},"requestHandler");let z,ce,we;const ue=[];if(GATEWAY_HTTPS){const e=require("./basic-ssl"),r=GATEWAY_ROUTES.map(a=>a.host).filter(a=>!!a),d=path.join(process.cwd(),"node_modules",".cache","davnx-webpack");ce=e.getCertificateSync(d,SERVICE_NAME||"lensmcp.dev",r),we=e.caCertPath(),z=require("node:https").createServer({key:ce,cert:ce},ie)}else z=http.createServer(ie);const Ne=i((e,r,d)=>{const a=matchGatewayRoute(e);if(a?.prependPrefix&&!e.url?.startsWith(a.prependPrefix)&&(e.url=a.prependPrefix+(e.url??"/")),a?.target){p.ws(e,r,d,{target:a.target,changeOrigin:!0},()=>r.destroy());return}const c=U();if(!c){r.destroy();return}p.ws(e,r,d,{target:{socketPath:c.socketPath}},()=>r.destroy())},"upgradeHandler");z.on("upgrade",Ne);const Te=2e3;let ve=!1;z.on("error",e=>{if(e.code==="EADDRINUSE"){ve||(ve=!0,console.warn(`[parent] public port ${E} already in use \u2014 continuing on the unix-socket pool only (gateway routing is unaffected) and retrying the bind every ${Te/1e3}s. Give this service a distinct cluster.port if this is not a rolling handoff.`)),setTimeout(()=>{!T&&!z.listening&&z.listen(E)},Te).unref?.();return}console.error("[parent] public server error:",e)}),await t(_);for(const e of WORKER_NAMES)ye(e);z.listen(E,()=>{const e=GATEWAY_HTTPS?"https":"http";console.log(`[parent] Listening on ${e}://localhost:${E}`),SERVICE_PREFIX&&console.log(`[parent] Service prefix: "${SERVICE_PREFIX}" (enforced \u2014 requests without it will get 404)`),gatewayMiddleware&&console.log(`[parent] Gateway middleware: ACTIVE (${GATEWAY_MIDDLEWARE_PATH})`),GATEWAY_ROUTES.length>0&&console.log(`[parent] Gateway routes: ${GATEWAY_ROUTES.map(r=>`${r.host??"*"}${r.prefix??"/"}\u2192${r.target??"children"}`).join(" ")}`),we&&(console.log("[parent] HTTPS dev CA (trust ONCE, then rotations/new hostnames stay green):"),console.log(`[parent] sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${we}`)),console.log(`POST ${e}://localhost:${E}/webpack/reload to trigger rolling swap/respawn`)});const he=Number(process.env.INTERNAL_PORT||0);if(he>0){const e=i((d,a)=>{const c=U();if(!c){a.statusCode=503,a.setHeader("content-type","text/plain; charset=utf-8"),a.end("No healthy children available.");return}p.web(d,a,{target:{socketPath:c.socketPath}},o=>{c.healthy=!1,c.lastError=String(o?.stack||o),a.statusCode=502,a.end(`Upstream error from Child#${c.id}.`)})},"internalHandler"),r=http.createServer(e);r.on("upgrade",(d,a,c)=>{const o=U();if(!o){a.destroy();return}p.ws(d,a,c,{target:{socketPath:o.socketPath}},()=>a.destroy())}),r.on("error",d=>{console.warn(`[parent] internal port ${he} unavailable (${d.code}).`)}),r.listen(he,()=>{console.log(`[parent] Internal (service-to-service, no gateway middleware) on http://localhost:${he}`)}),ue.push(r)}const Ie=(()=>{try{return JSON.parse(process.env.GATEWAY_EXTRA_PORTS||"[]")}catch{return[]}})();for(const e of Ie){if(!Number.isInteger(e)||e===Number(E))continue;const r=GATEWAY_HTTPS?require("node:https").createServer({key:ce,cert:ce},ie):http.createServer(ie);r.on("upgrade",Ne),r.on("error",d=>{console.warn(`[parent] extra port ${e} unavailable (${d.code}) \u2014 main port still up.`)}),r.listen(e,()=>{console.log(`[parent] Also listening on ${GATEWAY_HTTPS?"https":"http"}://localhost:${e}`)}),ue.push(r)}const _e=path.join(SOCK_DIR,"parent.sock");claimSock(_e);const Ee=http.createServer(ie);Ee.on("error",e=>{console.warn(`[parent] control socket unavailable (${e.code}) \u2014 lensmcp logs/debug attach disabled.`)}),Ee.listen(_e),ue.push(Ee);const Re=i(async e=>{T=!0,console.log(`[${e}] [parent] shutting down\u2026`),cleanupSock(_e);for(const r of ue)try{r.close()}catch{}for(const r of H)try{r.proc.kill("SIGTERM")}catch{}for(const r of[...se])pe(r,"was still draining when its devserver shut down");for(const r of f)try{r.proc.kill("SIGTERM")}catch{}for(const r of w){try{r.proc.kill("SIGTERM")}catch{}r.socketPath&&cleanupSock(r.socketPath,r.proc.pid)}try{fs.rmdirSync(SOCK_DIR)}catch{}setTimeout(()=>process.exit(0),700).unref()},"shutdown");["SIGINT","SIGTERM","SIGHUP","SIGQUIT","SIGUSR2"].forEach(e=>process.on(e,()=>{Re(e)}));const fe=Number(process.env.LENSMCP_GATEWAY_PID??0);if(Number.isInteger(fe)&&fe>0){const e=setInterval(()=>{try{process.kill(fe,0)}catch(r){if(r.code==="EPERM")return;clearInterval(e),console.error(`[parent] gateway (pid ${fe}) is gone \u2014 shutting the pod down to avoid an orphan tree.`),Re("gateway-gone")}},5e3);e.unref()}})()}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lensmcp/cluster",
3
- "version": "1.23.10",
3
+ "version": "1.23.12",
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.23.10",
61
- "@lensmcp/node-instrumentation": "1.23.10",
62
- "@lensmcp/nx-plugin": "1.23.10",
60
+ "@lensmcp/core": "1.23.12",
61
+ "@lensmcp/node-instrumentation": "1.23.12",
62
+ "@lensmcp/nx-plugin": "1.23.12",
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/process-name.js CHANGED
@@ -1 +1 @@
1
- "use strict";var h=Object.defineProperty;var o=(t,e)=>h(t,"name",{value:e,configurable:!0});var E=Object.defineProperty,s=o((t,e)=>E(t,"name",{value:e,configurable:!0}),"s"),m=Object.defineProperty,r=s((t,e)=>m(t,"name",{value:e,configurable:!0}),"r");Object.defineProperty(exports,"__esModule",{value:!0}),exports.PROCESS_NAME_MAX=void 0,exports.processName=processName,exports.defaultLinkDirs=defaultLinkDirs,exports.processNamesEnabled=processNamesEnabled,exports.namedExecPath=namedExecPath;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"));exports.PROCESS_NAME_MAX=31;const sanitize=r(t=>(t??"").replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,""),"sanitize");function processName(...t){const e=t.map(sanitize).filter(Boolean),n=e.pop();if(n===void 0)return"";if(e.length===0)return n.slice(0,exports.PROCESS_NAME_MAX);const i=n.slice(0,exports.PROCESS_NAME_MAX-2),p=e.join("-").slice(0,exports.PROCESS_NAME_MAX-i.length-1).replace(/-+$/,"");return p?`${p}-${i}`:i}o(processName,"processName"),s(processName,"processName"),r(processName,"processName");function defaultLinkDirs(t=process.env){const e=t.LENSMCP_HOME||os.homedir();return[path.join(os.tmpdir(),"lensmcp-process-names"),path.join(e,".lensmcp","process-names")]}o(defaultLinkDirs,"defaultLinkDirs"),s(defaultLinkDirs,"defaultLinkDirs"),r(defaultLinkDirs,"defaultLinkDirs");function processNamesEnabled(t=process.env){const e=(t.LENSMCP_PROCESS_NAMES??"").trim().toLowerCase();return!(e==="0"||e==="false"||e==="no"||e==="off")}o(processNamesEnabled,"processNamesEnabled"),s(processNamesEnabled,"processNamesEnabled"),r(processNamesEnabled,"processNamesEnabled");function privateDir(t){try{fs.mkdirSync(t,{recursive:!0,mode:448});const e=fs.lstatSync(t);return!e.isDirectory()||typeof process.getuid=="function"&&e.uid!==process.getuid()?!1:((e.mode&63)!==0&&fs.chmodSync(t,448),!0)}catch{return!1}}o(privateDir,"privateDir"),s(privateDir,"privateDir"),r(privateDir,"privateDir");function isSameFile(t,e){try{const n=fs.lstatSync(t);return n.isFile()&&n.dev===e.dev&&n.ino===e.ino}catch{return!1}}o(isSameFile,"isSameFile"),s(isSameFile,"isSameFile"),r(isSameFile,"isSameFile");const resolved=new Map;function namedExecPath(t,e={}){const n=e.execPath??process.execPath,i=e.env??process.env,p=e.platform??process.platform,u=processName(t);if(!u||p==="win32"||!processNamesEnabled(i))return n;const d=e.dirs??defaultLinkDirs(i),f=`${n}|${u}|${d.join("|")}`,S=resolved.get(f);if(S)return S;let l,a;try{l=fs.realpathSync(n),a=fs.statSync(l)}catch{return n}for(const _ of d){if(!privateDir(_))continue;const v=path.join(_,`${a.dev}-${a.ino}`);if(!privateDir(v))continue;const c=path.join(v,u);if(!isSameFile(c,a)){try{fs.unlinkSync(c)}catch{}try{fs.linkSync(l,c)}catch{}}if(isSameFile(c,a))return resolved.set(f,c),c}return n}o(namedExecPath,"namedExecPath"),s(namedExecPath,"namedExecPath"),r(namedExecPath,"namedExecPath");
1
+ "use strict";var E=Object.defineProperty;var s=(t,e)=>E(t,"name",{value:e,configurable:!0});var m=Object.defineProperty,r=s((t,e)=>m(t,"name",{value:e,configurable:!0}),"r");Object.defineProperty(exports,"__esModule",{value:!0}),exports.PROCESS_NAME_MAX=void 0,exports.processName=processName,exports.defaultLinkDirs=defaultLinkDirs,exports.processNamesEnabled=processNamesEnabled,exports.namedExecPath=namedExecPath;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"));exports.PROCESS_NAME_MAX=31;const sanitize=r(t=>(t??"").replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,""),"sanitize");function processName(...t){const e=t.map(sanitize).filter(Boolean),n=e.pop();if(n===void 0)return"";if(e.length===0)return n.slice(0,exports.PROCESS_NAME_MAX);const o=n.slice(0,exports.PROCESS_NAME_MAX-2),a=e.join("-").slice(0,exports.PROCESS_NAME_MAX-o.length-1).replace(/-+$/,"");return a?`${a}-${o}`:o}s(processName,"processName"),r(processName,"processName");function defaultLinkDirs(t=process.env){const e=t.LENSMCP_HOME||os.homedir();return[path.join(os.tmpdir(),"lensmcp-process-names"),path.join(e,".lensmcp","process-names")]}s(defaultLinkDirs,"defaultLinkDirs"),r(defaultLinkDirs,"defaultLinkDirs");function processNamesEnabled(t=process.env){const e=(t.LENSMCP_PROCESS_NAMES??"").trim().toLowerCase();return!(e==="0"||e==="false"||e==="no"||e==="off")}s(processNamesEnabled,"processNamesEnabled"),r(processNamesEnabled,"processNamesEnabled");function privateDir(t){try{fs.mkdirSync(t,{recursive:!0,mode:448});const e=fs.lstatSync(t);return!e.isDirectory()||typeof process.getuid=="function"&&e.uid!==process.getuid()?!1:((e.mode&63)!==0&&fs.chmodSync(t,448),!0)}catch{return!1}}s(privateDir,"privateDir"),r(privateDir,"privateDir");function isSameFile(t,e){try{const n=fs.lstatSync(t);return n.isFile()&&n.dev===e.dev&&n.ino===e.ino}catch{return!1}}s(isSameFile,"isSameFile"),r(isSameFile,"isSameFile");const resolved=new Map;function namedExecPath(t,e={}){const n=e.execPath??process.execPath,o=e.env??process.env,a=e.platform??process.platform,p=processName(t);if(!p||a==="win32"||!processNamesEnabled(o))return n;const l=e.dirs??defaultLinkDirs(o),f=`${n}|${p}|${l.join("|")}`,d=resolved.get(f);if(d)return d;let u,c;try{u=fs.realpathSync(n),c=fs.statSync(u)}catch{return n}for(const S of l){if(!privateDir(S))continue;const _=path.join(S,`${c.dev}-${c.ino}`);if(!privateDir(_))continue;const i=path.join(_,p);if(!isSameFile(i,c)){try{fs.unlinkSync(i)}catch{}try{fs.linkSync(u,i)}catch{}}if(isSameFile(i,c))return resolved.set(f,i),i}return n}s(namedExecPath,"namedExecPath"),r(namedExecPath,"namedExecPath");
@@ -1 +1 @@
1
- "use strict";var S=Object.defineProperty;var a=(n,e)=>S(n,"name",{value:e,configurable:!0});var h=Object.defineProperty,r=a((n,e)=>h(n,"name",{value:e,configurable:!0}),"r"),d=Object.defineProperty,f=r((n,e)=>d(n,"name",{value:e,configurable:!0}),"f");Object.defineProperty(exports,"__esModule",{value:!0}),exports.redisDisconnectFixEnabled=redisDisconnectFixEnabled,exports.finishStrandedDisconnect=finishStrandedDisconnect,exports.finishStrandedDisconnectsFor=finishStrandedDisconnectsFor;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path"));function redisDisconnectFixEnabled(n=process.env){const e=(n.LENSMCP_SWAP_FIX_IOREDIS_DISCONNECT??"").trim().toLowerCase();return!(e==="0"||e==="false"||e==="no"||e==="off")}a(redisDisconnectFixEnabled,"redisDisconnectFixEnabled"),r(redisDisconnectFixEnabled,"redisDisconnectFixEnabled"),f(redisDisconnectFixEnabled,"redisDisconnectFixEnabled");const failAll=f((n,e)=>{if(!(!n||typeof n.shift!="function"))for(let t=n.shift();t;t=n.shift())try{t.command?.reject?.(e)}catch{}},"failAll");function finishStrandedDisconnect(n){const e=n,t=(typeof e?.Redis=="function"?e.Redis:typeof e?.default=="function"?e.default:e)?.prototype,i=t?.disconnect;if(typeof i!="function"||i.__lensmcpEnds||typeof t.setStatus!="function")return!1;const o=f(function(c=!1){const u=!c&&this.status==="reconnecting",l=i.call(this,c);if(u&&this.status==="reconnecting")try{const s=new Error("Connection is closed.");this.setStatus("end"),typeof this.flushQueue=="function"&&this.flushQueue(s),failAll(this.prevCommandQueue,s),this.prevCommandQueue=null}catch{}return l},"wrapped");return o.__lensmcpEnds=!0,t.disconnect=o,!0}a(finishStrandedDisconnect,"finishStrandedDisconnect"),r(finishStrandedDisconnect,"finishStrandedDisconnect"),f(finishStrandedDisconnect,"finishStrandedDisconnect");function finishStrandedDisconnectsFor(n,e=require){const t=[path.dirname(n)],i=[t];try{i.push([path.dirname(e.resolve("bullmq/package.json",{paths:t}))])}catch{}const o=new Set,c=[];let u=0;for(const l of i){let s;try{s=e.resolve("ioredis",{paths:l})}catch{continue}if(!o.has(s)&&(o.add(s),!!finishStrandedDisconnect(e(s)))){u+=1;try{const p=e(e.resolve("ioredis/package.json",{paths:l})).version;p&&!c.includes(p)&&c.push(p)}catch{}}}return o.size===0?void 0:{patched:u,versions:c}}a(finishStrandedDisconnectsFor,"finishStrandedDisconnectsFor"),r(finishStrandedDisconnectsFor,"finishStrandedDisconnectsFor"),f(finishStrandedDisconnectsFor,"finishStrandedDisconnectsFor");
1
+ "use strict";var h=Object.defineProperty;var r=(t,e)=>h(t,"name",{value:e,configurable:!0});var d=Object.defineProperty,f=r((t,e)=>d(t,"name",{value:e,configurable:!0}),"f");Object.defineProperty(exports,"__esModule",{value:!0}),exports.redisDisconnectFixEnabled=redisDisconnectFixEnabled,exports.finishStrandedDisconnect=finishStrandedDisconnect,exports.finishStrandedDisconnectsFor=finishStrandedDisconnectsFor;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path"));function redisDisconnectFixEnabled(t=process.env){const e=(t.LENSMCP_SWAP_FIX_IOREDIS_DISCONNECT??"").trim().toLowerCase();return!(e==="0"||e==="false"||e==="no"||e==="off")}r(redisDisconnectFixEnabled,"redisDisconnectFixEnabled"),f(redisDisconnectFixEnabled,"redisDisconnectFixEnabled");const failAll=f((t,e)=>{if(!(!t||typeof t.shift!="function"))for(let n=t.shift();n;n=t.shift())try{n.command?.reject?.(e)}catch{}},"failAll");function finishStrandedDisconnect(t){const e=t,n=(typeof e?.Redis=="function"?e.Redis:typeof e?.default=="function"?e.default:e)?.prototype,i=n?.disconnect;if(typeof i!="function"||i.__lensmcpEnds||typeof n.setStatus!="function")return!1;const o=f(function(c=!1){const a=!c&&this.status==="reconnecting",u=i.call(this,c);if(a&&this.status==="reconnecting")try{const s=new Error("Connection is closed.");this.setStatus("end"),typeof this.flushQueue=="function"&&this.flushQueue(s),failAll(this.prevCommandQueue,s),this.prevCommandQueue=null}catch{}return u},"wrapped");return o.__lensmcpEnds=!0,n.disconnect=o,!0}r(finishStrandedDisconnect,"finishStrandedDisconnect"),f(finishStrandedDisconnect,"finishStrandedDisconnect");function finishStrandedDisconnectsFor(t,e=require){const n=[path.dirname(t)],i=[n];try{i.push([path.dirname(e.resolve("bullmq/package.json",{paths:n}))])}catch{}const o=new Set,c=[];let a=0;for(const u of i){let s;try{s=e.resolve("ioredis",{paths:u})}catch{continue}if(!o.has(s)&&(o.add(s),!!finishStrandedDisconnect(e(s)))){a+=1;try{const l=e(e.resolve("ioredis/package.json",{paths:u})).version;l&&!c.includes(l)&&c.push(l)}catch{}}}return o.size===0?void 0:{patched:a,versions:c}}r(finishStrandedDisconnectsFor,"finishStrandedDisconnectsFor"),f(finishStrandedDisconnectsFor,"finishStrandedDisconnectsFor");
@@ -1 +1 @@
1
- "use strict";var d=Object.defineProperty;var i=(n,e)=>d(n,"name",{value:e,configurable:!0});var c=Object.defineProperty,r=i((n,e)=>c(n,"name",{value:e,configurable:!0}),"r"),u=Object.defineProperty,t=r((n,e)=>u(n,"name",{value:e,configurable:!0}),"t");Object.defineProperty(exports,"__esModule",{value:!0}),exports.schemaPrewarmEnabled=schemaPrewarmEnabled,exports.prewarmZod=prewarmZod,exports.prewarmZodFor=prewarmZodFor;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path"));function schemaPrewarmEnabled(n=process.env){const e=(n.LENSMCP_SWAP_PREWARM_ZOD??"").trim().toLowerCase();return!(e==="0"||e==="false"||e==="no"||e==="off")}i(schemaPrewarmEnabled,"schemaPrewarmEnabled"),r(schemaPrewarmEnabled,"schemaPrewarmEnabled"),t(schemaPrewarmEnabled,"schemaPrewarmEnabled");const identity=t(n=>n,"identity"),BUILDERS=[n=>n.string(),n=>n.number(),n=>n.bigint(),n=>n.boolean(),n=>n.date(),n=>n.symbol(),n=>n.undefined(),n=>n.null(),n=>n.any(),n=>n.unknown(),n=>n.never(),n=>n.void(),n=>n.nan(),n=>n.int(),n=>n.float32(),n=>n.float64(),n=>n.int32(),n=>n.uint32(),n=>n.int64(),n=>n.uint64(),n=>n.email(),n=>n.guid(),n=>n.uuid(),n=>n.url(),n=>n.emoji(),n=>n.nanoid(),n=>n.cuid(),n=>n.cuid2(),n=>n.ulid(),n=>n.xid(),n=>n.ksuid(),n=>n.ipv4(),n=>n.ipv6(),n=>n.mac(),n=>n.cidrv4(),n=>n.cidrv6(),n=>n.base64(),n=>n.base64url(),n=>n.e164(),n=>n.jwt(),n=>n.hostname(),n=>n.hex(),n=>n.httpUrl(),n=>n.stringFormat("lensmcp",identity),n=>n.iso.datetime(),n=>n.iso.date(),n=>n.iso.time(),n=>n.iso.duration(),n=>n.array(n.unknown()),n=>n.object({}),n=>n.strictObject({}),n=>n.looseObject({}),n=>n.union([n.unknown(),n.unknown()]),n=>n.xor([n.string(),n.number()]),n=>n.discriminatedUnion("kind",[n.object({kind:n.literal("a")}),n.object({kind:n.literal("b")})]),n=>n.intersection(n.unknown(),n.unknown()),n=>n.tuple([n.unknown()]),n=>n.record(n.string(),n.unknown()),n=>n.partialRecord(n.string(),n.unknown()),n=>n.map(n.unknown(),n.unknown()),n=>n.set(n.unknown()),n=>n.enum(["a"]),n=>n.nativeEnum({A:"a"}),n=>n.literal("a"),n=>n.file(),n=>n.templateLiteral(["a"]),n=>n.transform(identity),n=>n.unknown().transform(identity),n=>n.unknown().pipe(n.unknown()),n=>n.unknown().optional(),n=>n.exactOptional(n.unknown()),n=>n.unknown().nullable(),n=>n.unknown().nullish(),n=>n.unknown().default(0),n=>n.unknown().prefault(0),n=>n.unknown().nonoptional(),n=>n.success(n.unknown()),n=>n.unknown().catch(0),n=>n.unknown().readonly(),n=>n.lazy(()=>n.unknown()),n=>n.promise(n.unknown()),n=>n.custom(()=>!0),n=>n.unknown().refine(()=>!0),n=>n.unknown().superRefine(()=>{}),n=>n.instanceof(Object),n=>n.function(),n=>n.json(),n=>n.stringbool(),n=>n.preprocess(identity,n.unknown()),n=>n.codec(n.unknown(),n.unknown(),{decode:identity,encode:identity}),n=>n.coerce.string(),n=>n.coerce.number(),n=>n.coerce.boolean(),n=>n.coerce.bigint(),n=>n.coerce.date()];function prewarmZod(n){const e=n?.z??n;if(!e||typeof e.object!="function")return 0;let o=0;for(const a of BUILDERS)try{a(e)!==void 0&&(o+=1)}catch{}return o}i(prewarmZod,"prewarmZod"),r(prewarmZod,"prewarmZod"),t(prewarmZod,"prewarmZod");function prewarmZodFor(n,e=require){let o;try{o=e.resolve("zod",{paths:[path.dirname(n)]})}catch{return}const a=prewarmZod(e(o));let s;try{s=e(e.resolve("zod/package.json",{paths:[path.dirname(n)]})).version}catch{}return{created:a,...s?{version:s}:{}}}i(prewarmZodFor,"prewarmZodFor"),r(prewarmZodFor,"prewarmZodFor"),t(prewarmZodFor,"prewarmZodFor");
1
+ "use strict";var c=Object.defineProperty;var r=(n,e)=>c(n,"name",{value:e,configurable:!0});var u=Object.defineProperty,t=r((n,e)=>u(n,"name",{value:e,configurable:!0}),"t");Object.defineProperty(exports,"__esModule",{value:!0}),exports.schemaPrewarmEnabled=schemaPrewarmEnabled,exports.prewarmZod=prewarmZod,exports.prewarmZodFor=prewarmZodFor;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path"));function schemaPrewarmEnabled(n=process.env){const e=(n.LENSMCP_SWAP_PREWARM_ZOD??"").trim().toLowerCase();return!(e==="0"||e==="false"||e==="no"||e==="off")}r(schemaPrewarmEnabled,"schemaPrewarmEnabled"),t(schemaPrewarmEnabled,"schemaPrewarmEnabled");const identity=t(n=>n,"identity"),BUILDERS=[n=>n.string(),n=>n.number(),n=>n.bigint(),n=>n.boolean(),n=>n.date(),n=>n.symbol(),n=>n.undefined(),n=>n.null(),n=>n.any(),n=>n.unknown(),n=>n.never(),n=>n.void(),n=>n.nan(),n=>n.int(),n=>n.float32(),n=>n.float64(),n=>n.int32(),n=>n.uint32(),n=>n.int64(),n=>n.uint64(),n=>n.email(),n=>n.guid(),n=>n.uuid(),n=>n.url(),n=>n.emoji(),n=>n.nanoid(),n=>n.cuid(),n=>n.cuid2(),n=>n.ulid(),n=>n.xid(),n=>n.ksuid(),n=>n.ipv4(),n=>n.ipv6(),n=>n.mac(),n=>n.cidrv4(),n=>n.cidrv6(),n=>n.base64(),n=>n.base64url(),n=>n.e164(),n=>n.jwt(),n=>n.hostname(),n=>n.hex(),n=>n.httpUrl(),n=>n.stringFormat("lensmcp",identity),n=>n.iso.datetime(),n=>n.iso.date(),n=>n.iso.time(),n=>n.iso.duration(),n=>n.array(n.unknown()),n=>n.object({}),n=>n.strictObject({}),n=>n.looseObject({}),n=>n.union([n.unknown(),n.unknown()]),n=>n.xor([n.string(),n.number()]),n=>n.discriminatedUnion("kind",[n.object({kind:n.literal("a")}),n.object({kind:n.literal("b")})]),n=>n.intersection(n.unknown(),n.unknown()),n=>n.tuple([n.unknown()]),n=>n.record(n.string(),n.unknown()),n=>n.partialRecord(n.string(),n.unknown()),n=>n.map(n.unknown(),n.unknown()),n=>n.set(n.unknown()),n=>n.enum(["a"]),n=>n.nativeEnum({A:"a"}),n=>n.literal("a"),n=>n.file(),n=>n.templateLiteral(["a"]),n=>n.transform(identity),n=>n.unknown().transform(identity),n=>n.unknown().pipe(n.unknown()),n=>n.unknown().optional(),n=>n.exactOptional(n.unknown()),n=>n.unknown().nullable(),n=>n.unknown().nullish(),n=>n.unknown().default(0),n=>n.unknown().prefault(0),n=>n.unknown().nonoptional(),n=>n.success(n.unknown()),n=>n.unknown().catch(0),n=>n.unknown().readonly(),n=>n.lazy(()=>n.unknown()),n=>n.promise(n.unknown()),n=>n.custom(()=>!0),n=>n.unknown().refine(()=>!0),n=>n.unknown().superRefine(()=>{}),n=>n.instanceof(Object),n=>n.function(),n=>n.json(),n=>n.stringbool(),n=>n.preprocess(identity,n.unknown()),n=>n.codec(n.unknown(),n.unknown(),{decode:identity,encode:identity}),n=>n.coerce.string(),n=>n.coerce.number(),n=>n.coerce.boolean(),n=>n.coerce.bigint(),n=>n.coerce.date()];function prewarmZod(n){const e=n?.z??n;if(!e||typeof e.object!="function")return 0;let o=0;for(const i of BUILDERS)try{i(e)!==void 0&&(o+=1)}catch{}return o}r(prewarmZod,"prewarmZod"),t(prewarmZod,"prewarmZod");function prewarmZodFor(n,e=require){let o;try{o=e.resolve("zod",{paths:[path.dirname(n)]})}catch{return}const i=prewarmZod(e(o));let a;try{a=e(e.resolve("zod/package.json",{paths:[path.dirname(n)]})).version}catch{}return{created:i,...a?{version:a}:{}}}r(prewarmZodFor,"prewarmZodFor"),t(prewarmZodFor,"prewarmZodFor");
package/stdio-guard.js CHANGED
@@ -1 +1 @@
1
- "use strict";var u=Object.defineProperty;var t=(o,e)=>u(o,"name",{value:e,configurable:!0});var c=Object.defineProperty,r=t((o,e)=>c(o,"name",{value:e,configurable:!0}),"r"),d=Object.defineProperty,s=r((o,e)=>d(o,"name",{value:e,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.guardBrokenStdio=guardBrokenStdio;function guardBrokenStdio(o=[process.stdout,process.stderr]){for(const e of o){const n=e;n.__lensmcpStdioGuard||(n.__lensmcpStdioGuard=!0,e.on("error",a=>{if(a?.code!=="EPIPE")throw a}))}}t(guardBrokenStdio,"guardBrokenStdio"),r(guardBrokenStdio,"guardBrokenStdio"),s(guardBrokenStdio,"guardBrokenStdio");
1
+ "use strict";var c=Object.defineProperty;var r=(o,e)=>c(o,"name",{value:e,configurable:!0});var d=Object.defineProperty,s=r((o,e)=>d(o,"name",{value:e,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0}),exports.guardBrokenStdio=guardBrokenStdio;function guardBrokenStdio(o=[process.stdout,process.stderr]){for(const e of o){const t=e;t.__lensmcpStdioGuard||(t.__lensmcpStdioGuard=!0,e.on("error",n=>{if(n?.code!=="EPIPE")throw n}))}}r(guardBrokenStdio,"guardBrokenStdio"),s(guardBrokenStdio,"guardBrokenStdio");
package/swap-recycle.js CHANGED
@@ -1 +1 @@
1
- "use strict";var c=Object.defineProperty;var n=(e,s)=>c(e,"name",{value:s,configurable:!0});var r=Object.defineProperty,i=n((e,s)=>r(e,"name",{value:s,configurable:!0}),"i"),o=Object.defineProperty,t=i((e,s)=>o(e,"name",{value:s,configurable:!0}),"t");Object.defineProperty(exports,"__esModule",{value:!0}),exports.swapRecyclePolicy=swapRecyclePolicy,exports.recycleReason=recycleReason;const MB=1024*1024,numberFrom=t((e,s,a)=>{if(e===void 0||e.trim()==="")return s;const l=Number(e);return Number.isFinite(l)&&l>=a?l:s},"numberFrom");function swapRecyclePolicy(e=process.env){return{enabled:!["0","false","no","off"].includes((e.LENSMCP_SWAP_RECYCLE??"").trim().toLowerCase()),heapFactor:numberFrom(e.LENSMCP_SWAP_RECYCLE_HEAP_FACTOR,3,0),minHeapBytes:numberFrom(e.LENSMCP_SWAP_RECYCLE_MIN_MB,512,0)*MB,heapRatio:Math.min(1,numberFrom(e.LENSMCP_SWAP_RECYCLE_HEAP_RATIO,.7,0)),maxSwaps:Math.floor(numberFrom(e.LENSMCP_SWAP_RECYCLE_AFTER,0,0)),stuckCloseMs:Math.floor(numberFrom(e.LENSMCP_SWAP_RECYCLE_STUCK_CLOSE_MS,6e4,0)),settleMs:Math.floor(numberFrom(e.LENSMCP_SWAP_RECYCLE_SETTLE_MS,5e3,0))}}n(swapRecyclePolicy,"swapRecyclePolicy"),i(swapRecyclePolicy,"swapRecyclePolicy"),t(swapRecyclePolicy,"swapRecyclePolicy");const mb=t(e=>(e/MB).toFixed(0),"mb");function recycleReason(e,s){if(!(!e.enabled||s.swaps<1)){if(e.maxSwaps>0&&s.swaps>=e.maxSwaps)return`${s.swaps} hot swaps in this process (LENSMCP_SWAP_RECYCLE_AFTER=${e.maxSwaps})`;if(e.stuckCloseMs>0&&(s.stuckCloses??0)>0){const a=s.stuckCloses;return`${a} previous app${a===1?" has":"s have"} not finished closing after ${Math.round(e.stuckCloseMs/1e3)}s \u2014 a shutdown hook that never returns keeps the whole app, its connections included, in memory`}if(e.heapRatio>0&&s.limitBytes>0&&s.usedBytes>=e.heapRatio*s.limitBytes){const a=Math.round(s.usedBytes/s.limitBytes*100);return`its heap is ${mb(s.usedBytes)} MB after a full GC, ${a}% of V8's ${mb(s.limitBytes)} MB limit`}if(e.heapFactor>0&&s.settled!==!1&&s.baselineBytes!==void 0&&s.baselineBytes>0&&s.usedBytes>=e.minHeapBytes&&s.usedBytes>=e.heapFactor*s.baselineBytes){const a=(s.usedBytes/s.baselineBytes).toFixed(1);return`its heap is ${mb(s.usedBytes)} MB after a full GC, ${a}\xD7 the ${mb(s.baselineBytes)} MB it booted with \u2014 earlier generations of the bundle are still in memory`}}}n(recycleReason,"recycleReason"),i(recycleReason,"recycleReason"),t(recycleReason,"recycleReason");
1
+ "use strict";var r=Object.defineProperty;var i=(e,s)=>r(e,"name",{value:s,configurable:!0});var o=Object.defineProperty,t=i((e,s)=>o(e,"name",{value:s,configurable:!0}),"t");Object.defineProperty(exports,"__esModule",{value:!0}),exports.swapRecyclePolicy=swapRecyclePolicy,exports.recycleReason=recycleReason;const MB=1024*1024,numberFrom=t((e,s,a)=>{if(e===void 0||e.trim()==="")return s;const n=Number(e);return Number.isFinite(n)&&n>=a?n:s},"numberFrom");function swapRecyclePolicy(e=process.env){return{enabled:!["0","false","no","off"].includes((e.LENSMCP_SWAP_RECYCLE??"").trim().toLowerCase()),heapFactor:numberFrom(e.LENSMCP_SWAP_RECYCLE_HEAP_FACTOR,3,0),minHeapBytes:numberFrom(e.LENSMCP_SWAP_RECYCLE_MIN_MB,512,0)*MB,heapRatio:Math.min(1,numberFrom(e.LENSMCP_SWAP_RECYCLE_HEAP_RATIO,.7,0)),maxSwaps:Math.floor(numberFrom(e.LENSMCP_SWAP_RECYCLE_AFTER,0,0)),stuckCloseMs:Math.floor(numberFrom(e.LENSMCP_SWAP_RECYCLE_STUCK_CLOSE_MS,6e4,0)),settleMs:Math.floor(numberFrom(e.LENSMCP_SWAP_RECYCLE_SETTLE_MS,5e3,0))}}i(swapRecyclePolicy,"swapRecyclePolicy"),t(swapRecyclePolicy,"swapRecyclePolicy");const mb=t(e=>(e/MB).toFixed(0),"mb");function recycleReason(e,s){if(!(!e.enabled||s.swaps<1)){if(e.maxSwaps>0&&s.swaps>=e.maxSwaps)return`${s.swaps} hot swaps in this process (LENSMCP_SWAP_RECYCLE_AFTER=${e.maxSwaps})`;if(e.stuckCloseMs>0&&(s.stuckCloses??0)>0){const a=s.stuckCloses;return`${a} previous app${a===1?" has":"s have"} not finished closing after ${Math.round(e.stuckCloseMs/1e3)}s \u2014 a shutdown hook that never returns keeps the whole app, its connections included, in memory`}if(e.heapRatio>0&&s.limitBytes>0&&s.usedBytes>=e.heapRatio*s.limitBytes){const a=Math.round(s.usedBytes/s.limitBytes*100);return`its heap is ${mb(s.usedBytes)} MB after a full GC, ${a}% of V8's ${mb(s.limitBytes)} MB limit`}if(e.heapFactor>0&&s.settled!==!1&&s.baselineBytes!==void 0&&s.baselineBytes>0&&s.usedBytes>=e.minHeapBytes&&s.usedBytes>=e.heapFactor*s.baselineBytes){const a=(s.usedBytes/s.baselineBytes).toFixed(1);return`its heap is ${mb(s.usedBytes)} MB after a full GC, ${a}\xD7 the ${mb(s.baselineBytes)} MB it booted with \u2014 earlier generations of the bundle are still in memory`}}}i(recycleReason,"recycleReason"),t(recycleReason,"recycleReason");
@@ -5,7 +5,20 @@
5
5
  * 2-worker pair (~80MB+) per service, ~1GB across a 13-service cluster, alive even when nobody
6
6
  * saves. tsgo (@typescript/native-preview, the native TS compiler) full-checks one of these
7
7
  * services cold in ~1-3s, so instead of holding a program we re-check COLD after each successful
8
- * rebuild (debounced, killing any in-flight check): idle cost is exactly zero.
8
+ * rebuild (debounced): idle cost is exactly zero.
9
+ *
10
+ * ONE AT A TIME (issues/foodguard/34). "Zero resident" is not "small": a cold check of a real service
11
+ * peaks at 1.4-3.4GB. Every service's plugin used to start its own the moment its build finished, so
12
+ * one edit to a shared file started one per service at the same instant; and a newer build was meant
13
+ * to REPLACE the running check with SIGTERM, which this checker ignores — it runs to the end and
14
+ * exits 0 — so each further build ADDED a process. Fifteen at once on a 32GB machine turned a 2s
15
+ * check into two minutes, then fourteen. So now:
16
+ * - a check waits its turn in a MACHINE-WIDE line (`typecheck-queue.ts`), one slot by default;
17
+ * - a service has at most one check running and one asked for: a build that lands while a check
18
+ * runs is remembered, and one more check follows — a running check is never killed to be replaced;
19
+ * - stopping one for real is SIGKILL, and that happens only on shutdown or on a timeout, which is
20
+ * reported as the checker failing, never as a verdict;
21
+ * - one checker is held to a few cores (`GOMAXPROCS`).
9
22
  *
10
23
  * The output CONTRACT is the point: `--pretty false` prints classic `file.ts(1,2): error TS1234:`
11
24
  * lines to the executor's console, which the gateway sniffs (`error TS\d+`) into the lens
@@ -35,6 +48,7 @@
35
48
  * reports itself onto the lens bus instead of only warning into a log nobody reads.
36
49
  */
37
50
  import { spawn } from 'node:child_process';
51
+ import { type TypecheckQueue } from './typecheck-queue';
38
52
  export interface TsgoCheckPluginOptions {
39
53
  appName: string;
40
54
  /** Absolute path to the app tsconfig the check covers. */
@@ -53,7 +67,15 @@ export interface TsgoCheckPluginOptions {
53
67
  eventFile?: string;
54
68
  /** Set false to skip publishing to the lens bus (console output is unchanged). */
55
69
  publishEvents?: boolean;
70
+ /** The line a check waits in before it starts. Defaults to the machine-wide one. Injectable for tests. */
71
+ queue?: TypecheckQueue;
72
+ /** A check still running after this long is killed and reported as a tool failure. Default 120s. */
73
+ timeoutMs?: number;
74
+ /** Cores one checker may use (`GOMAXPROCS`). Default {@link checkerMaxProcs}. */
75
+ maxProcs?: number;
56
76
  }
77
+ /** `LENSMCP_TYPECHECK_GOMAXPROCS`, else {@link DEFAULT_MAX_PROCS}. An explicit `GOMAXPROCS` in the env wins over both. */
78
+ export declare function checkerMaxProcs(env?: NodeJS.ProcessEnv): number;
57
79
  /** The npm package that ships the tsgo compiler — a real `dependency` of `@lensmcp/cluster`. */
58
80
  export declare const TSGO_PACKAGE = "@typescript/native-preview";
59
81
  /** Seams for {@link resolveTsgoBin}, so every branch of the precedence is testable without an install. */
@@ -133,19 +155,42 @@ export declare function writeShimTsconfig(appName: string, tsConfig: string, wor
133
155
  export declare class TsgoCheckPlugin {
134
156
  private readonly opts;
135
157
  private readonly spawnImpl;
158
+ private readonly queue;
136
159
  private timer;
160
+ /** idle → waiting (in line) → running → idle. */
161
+ private phase;
162
+ /** A build finished while a check was running: one more check follows it. */
163
+ private dirty;
164
+ private ticket;
137
165
  private inflight;
166
+ private askedAt;
138
167
  private shimPath;
139
168
  private disabled;
169
+ private disposed;
140
170
  constructor(opts: TsgoCheckPluginOptions);
141
171
  apply(compiler: any): void;
142
- /** Debounced: rapid successive rebuilds collapse into one check; an in-flight check is superseded. */
172
+ /** Debounced: rapid successive rebuilds collapse into one request for a check. */
143
173
  schedule(): void;
174
+ /**
175
+ * A build asks for a check. At most one runs and one is asked for:
176
+ * - already in line → nothing to add, the check reads the files when its turn comes;
177
+ * - running → remembered, and ONE more check follows this one. The running check is left alone:
178
+ * it cannot be stopped politely, and alone it is done in seconds.
179
+ */
180
+ private request;
181
+ /** Asked through a method on purpose: `run()` may have moved the phase inside the call above. */
182
+ private isIdle;
144
183
  /**
145
184
  * Publish one completed check onto the lens bus so `typecheck://*` reflects
146
185
  * it. Strictly passive + fully swallowed: the console output above is the
147
186
  * contract webpack/the gateway rely on, this is pure observation on top.
148
187
  */
149
188
  private publish;
189
+ /** This service's turn in the line. */
150
190
  private run;
191
+ /** The check is over: give the slot back, and check once more if a build landed meanwhile. */
192
+ private finish;
193
+ private leave;
194
+ /** The dev server is going away: leave the line, and stop the checker for real (it ignores SIGTERM). */
195
+ dispose(): void;
151
196
  }
@@ -1,5 +1,5 @@
1
- "use strict";var v=Object.defineProperty;var u=(e,t)=>v(e,"name",{value:t,configurable:!0});var m=Object.defineProperty,a=u((e,t)=>m(e,"name",{value:t,configurable:!0}),"a"),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"]}u(shimNames,"shimNames"),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}}u(isExecutableFile,"isExecutableFile"),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}u(resolveTsgoPackageDir,"resolveTsgoPackageDir"),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}}u(packageDeclaredBin,"packageDeclaredBin"),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}u(ownBinCandidates,"ownBinCandidates"),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}u(resolveTsgoBin,"resolveTsgoBin"),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{}}u(reportTsgoUnavailable,"reportTsgoUnavailable"),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}}u(parseJsonc,"parseJsonc"),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}u(resolveExtends,"resolveExtends"),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(f=>typeof f=="string"):typeof s.extends=="string"?[s.extends]:[],l=c(()=>{for(const f of[...r].reverse()){const g=resolveExtends(f,n);if(!g)continue;const b=effectivePaths(g,t);if(b)return b}return null},"inherited"),h=o.paths,p=typeof o.baseUrl=="string"?path.resolve(n,o.baseUrl):void 0;if(!h){const f=l();return f?{paths:f.paths,anchorDir:p??f.anchorDir}:null}return{paths:h,anchorDir:p??l()?.anchorDir??n}}u(effectivePaths,"effectivePaths"),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,h])=>[l,(Array.isArray(h)?h:[]).map(p=>path.isAbsolute(p)?p:path.resolve(o.anchorDir,p))])):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}u(writeShimTsconfig,"writeShimTsconfig"),a(writeShimTsconfig,"writeShimTsconfig"),c(writeShimTsconfig,"writeShimTsconfig");class TsgoCheckPlugin{static{u(this,"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,h=(l/1e3).toFixed(1);if(o===0){console.log(`[tsgo] ${this.opts.appName}: types clean (${h}s)`),this.publish({output:"",durationMs:l});return}n.trim()&&process.stdout.write(n.endsWith(`
3
- `)?n:`${n}
4
- `);const p=(n.match(/error TS\d+/g)??[]).length;console.log(`[tsgo] ${this.opts.appName}: ${p} type error${p===1?"":"s"} (${h}s)`),this.publish({output:n,durationMs:l,...p===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)??""}u(firstLine,"firstLine"),a(firstLine,"firstLine"),c(firstLine,"firstLine");
1
+ "use strict";var y=Object.defineProperty;var h=(e,t)=>y(e,"name",{value:t,configurable:!0});var S=Object.defineProperty,a=h((e,t)=>S(e,"name",{value:t,configurable:!0}),"a");Object.defineProperty(exports,"__esModule",{value:!0}),exports.TsgoCheckPlugin=exports.TSGO_MISSING_CAUSE=exports.TSGO_PACKAGE=void 0,exports.checkerMaxProcs=checkerMaxProcs,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"),typecheck_queue_1=require("./typecheck-queue"),DEFAULT_TIMEOUT_MS=12e4,DEFAULT_MAX_PROCS=4;function checkerMaxProcs(e=process.env){const t=Number(e.LENSMCP_TYPECHECK_GOMAXPROCS);return Number.isInteger(t)&&t>=1?t:DEFAULT_MAX_PROCS}h(checkerMaxProcs,"checkerMaxProcs"),a(checkerMaxProcs,"checkerMaxProcs");const livePlugins=new Set;let exitHooked=!1;function stopWithTheProcess(e){livePlugins.add(e),!exitHooked&&(exitHooked=!0,process.once("exit",()=>{for(const t of livePlugins)t.dispose()}))}h(stopWithTheProcess,"stopWithTheProcess"),a(stopWithTheProcess,"stopWithTheProcess"),exports.TSGO_PACKAGE="@typescript/native-preview";function shimNames(e){return e==="win32"?["tsgo.cmd","tsgo.exe"]:["tsgo"]}h(shimNames,"shimNames"),a(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}}h(isExecutableFile,"isExecutableFile"),a(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 o=path.join(e,"package.json");if(fs.existsSync(o))try{const{name:s}=JSON.parse(fs.readFileSync(o,"utf8"));if(s===exports.TSGO_PACKAGE)return e}catch{}const r=path.dirname(e);if(r===e)break;e=r}}catch{}return null}h(resolveTsgoPackageDir,"resolveTsgoPackageDir"),a(resolveTsgoPackageDir,"resolveTsgoPackageDir");function packageDeclaredBin(e){try{const{bin:t}=JSON.parse(fs.readFileSync(path.join(e,"package.json"),"utf8")),o=typeof t=="string"?t:t?.tsgo;return o?path.join(e,o):null}catch{return null}}h(packageDeclaredBin,"packageDeclaredBin"),a(packageDeclaredBin,"packageDeclaredBin");function ownBinCandidates(e,t){const o=path.resolve(e,"..","..",".bin"),r=shimNames(t).map(i=>path.join(o,i)),s=t==="win32"?null:packageDeclaredBin(e);return s?[s,...r]:r}h(ownBinCandidates,"ownBinCandidates"),a(ownBinCandidates,"ownBinCandidates");function resolveTsgoBin(e,t,o={}){const r=o.platform??process.platform,s=o.isExecutable??(n=>isExecutableFile(n,r));if(t)return s(t)?t:null;for(const n of shimNames(r)){const l=path.join(e,"node_modules",".bin",n);if(s(l))return l}const i=(o.ownPackageDir??resolveTsgoPackageDir)();return i?ownBinCandidates(i,r).find(s)??null:null}h(resolveTsgoBin,"resolveTsgoBin"),a(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{}}h(reportTsgoUnavailable,"reportTsgoUnavailable"),a(reportTsgoUnavailable,"reportTsgoUnavailable");function parseJsonc(e){let t="",o=!1,r=!1,s=!1;for(let i=0;i<e.length;i++){const n=e[i],l=e[i+1];if(r){n===`
2
+ `&&(r=!1,t+=n);continue}if(s){n==="*"&&l==="/"&&(s=!1,i++);continue}if(o){t+=n,n==="\\"?(t+=l??"",i++):n==='"'&&(o=!1);continue}if(n==='"'){o=!0,t+=n;continue}if(n==="/"&&l==="/"){r=!0,i++;continue}if(n==="/"&&l==="*"){s=!0,i++;continue}t+=n}try{return JSON.parse(t.replace(/,(\s*[}\]])/g,"$1"))}catch{return null}}h(parseJsonc,"parseJsonc"),a(parseJsonc,"parseJsonc");function resolveExtends(e,t){if(!e.startsWith(".")&&!path.isAbsolute(e))return null;const o=path.isAbsolute(e)?e:path.resolve(t,e);for(const r of[o,`${o}.json`,path.join(o,"tsconfig.json")])try{if(fs.statSync(r).isFile())return r}catch{}return null}h(resolveExtends,"resolveExtends"),a(resolveExtends,"resolveExtends");function effectivePaths(e,t=new Set){if(t.has(e))return null;t.add(e);let o;try{o=fs.readFileSync(e,"utf8")}catch{return null}const r=parseJsonc(o);if(!r)return null;const s=path.dirname(e),i=r.compilerOptions??{},n=Array.isArray(r.extends)?r.extends.filter(p=>typeof p=="string"):typeof r.extends=="string"?[r.extends]:[],l=a(()=>{for(const p of[...n].reverse()){const d=resolveExtends(p,s);if(!d)continue;const f=effectivePaths(d,t);if(f)return f}return null},"inherited"),u=i.paths,c=typeof i.baseUrl=="string"?path.resolve(s,i.baseUrl):void 0;if(!u){const p=l();return p?{paths:p.paths,anchorDir:c??p.anchorDir}:null}return{paths:u,anchorDir:c??l()?.anchorDir??s}}h(effectivePaths,"effectivePaths"),a(effectivePaths,"effectivePaths");function writeShimTsconfig(e,t,o){const r=path.join(o,"tmp","lensmcp-tsgo");fs.mkdirSync(r,{recursive:!0});const s=path.join(r,`${e}.tsconfig.json`),i=effectivePaths(t),n=i?Object.fromEntries(Object.entries(i.paths).map(([l,u])=>[l,(Array.isArray(u)?u:[]).map(c=>path.isAbsolute(c)?c:path.resolve(i.anchorDir,c))])):void 0;return fs.writeFileSync(s,JSON.stringify({extends:t,compilerOptions:{module:"preserve",moduleResolution:"bundler",isolatedModules:!1,baseUrl:null,...n&&Object.keys(n).length?{paths:n}:{}}},null,2)),s}h(writeShimTsconfig,"writeShimTsconfig"),a(writeShimTsconfig,"writeShimTsconfig");class TsgoCheckPlugin{static{h(this,"TsgoCheckPlugin")}static{a(this,"TsgoCheckPlugin")}constructor(t){this.timer=null,this.phase="idle",this.dirty=!1,this.ticket=null,this.inflight=null,this.askedAt=0,this.shimPath=null,this.disabled=!1,this.disposed=!1,this.opts=t,this.spawnImpl=t.spawnImpl??node_child_process_1.spawn,this.queue=t.queue??(0,typecheck_queue_1.machineTypecheckQueue)()}apply(t){t.hooks.done.tap("TsgoCheckPlugin",o=>{o.hasErrors()||this.schedule()}),t.hooks.shutdown?.tap?.("TsgoCheckPlugin",()=>this.dispose()),stopWithTheProcess(this)}schedule(){this.disabled||this.disposed||(this.timer&&clearTimeout(this.timer),this.timer=setTimeout(()=>this.request(),this.opts.debounceMs??500),this.timer.unref?.())}request(){if(this.disabled||this.disposed)return;if(this.phase==="running"){this.dirty=!0;return}if(this.phase==="waiting")return;this.phase="waiting",this.askedAt=Date.now();const t=this.queue(this.opts.appName,()=>this.run());this.isIdle()?t.release():this.ticket=t}isIdle(){return this.phase==="idle"}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(){if(this.disposed)return this.leave();let t;try{t=resolveTsgoBin(this.opts.workspaceRoot,this.opts.binPath),t&&!this.shimPath&&(this.shimPath=writeShimTsconfig(this.opts.appName,this.opts.tsConfig,this.opts.workspaceRoot))}catch(c){return console.warn(`[tsgo] ${this.opts.appName}: could not prepare the check \u2014 ${c.message}`),this.publish({output:"",durationMs:0,toolError:`could not prepare the check: ${c.message}`}),this.leave()}if(!t){this.disabled=!0;const c=`${exports.TSGO_MISSING_CAUSE}. Type checking is disabled for the rest of this session`;return console.warn(`[tsgo] ${this.opts.appName}: ${c}.`),this.publish({output:"",durationMs:0,toolError:c}),this.leave()}this.phase="running",this.dirty=!1;const o=Date.now(),r=o-this.askedAt,s=this.spawnImpl(t,["--noEmit","--pretty","false","-p",this.shimPath],{cwd:this.opts.workspaceRoot,stdio:["ignore","pipe","pipe"],env:{...process.env,GOMAXPROCS:process.env.GOMAXPROCS??String(this.opts.maxProcs??checkerMaxProcs())}});this.inflight=s;let i="",n=!1;const l=this.opts.timeoutMs??DEFAULT_TIMEOUT_MS,u=setTimeout(()=>{n=!0,s.kill("SIGKILL")},l);u.unref?.(),s.stdout?.on("data",c=>{i+=c.toString()}),s.stderr?.on("data",c=>{i+=c.toString()}),s.on("error",()=>{clearTimeout(u),this.inflight===s&&(console.warn(`[tsgo] ${this.opts.appName}: failed to spawn ${t}`),this.publish({output:"",durationMs:Date.now()-o,toolError:`failed to spawn ${t}`}),this.finish(s))}),s.on("close",(c,p)=>{if(clearTimeout(u),this.inflight!==s)return;const d=Date.now()-o,f=(d/1e3).toFixed(1),m=r>=1e3?`${f}s, waited ${(r/1e3).toFixed(1)}s`:`${f}s`;if(this.disposed)return this.finish(s);if(n){const k=`the check was killed after ${Math.round(l/1e3)}s without finishing`;return console.warn(`[tsgo] ${this.opts.appName}: ${k} \u2014 no verdict.`),this.publish({output:"",durationMs:d,toolError:k}),this.finish(s)}if(p)return this.finish(s);if(c===0)return console.log(`[tsgo] ${this.opts.appName}: types clean (${m})`),this.publish({output:"",durationMs:d}),this.finish(s);i.trim()&&process.stdout.write(i.endsWith(`
3
+ `)?i:`${i}
4
+ `);const g=(i.match(/error TS\d+/g)??[]).length;console.log(`[tsgo] ${this.opts.appName}: ${g} type error${g===1?"":"s"} (${m})`),this.publish({output:i,durationMs:d,...g===0?{toolError:`tsgo exited ${c} with no diagnostics: ${firstLine(i)}`}:{}}),this.finish(s)})}finish(t){this.inflight===t&&(this.inflight=null),this.leave(),this.dirty&&!this.disposed&&(this.dirty=!1,this.request())}leave(){this.phase="idle",this.ticket?.release(),this.ticket=null}dispose(){this.disposed||(this.disposed=!0,livePlugins.delete(this),this.timer&&clearTimeout(this.timer),this.inflight?.kill("SIGKILL"),this.ticket?.release(),this.ticket=null)}}exports.TsgoCheckPlugin=TsgoCheckPlugin;function firstLine(e){return e.trim().split(`
5
+ `)[0]?.slice(0,300)??""}h(firstLine,"firstLine"),a(firstLine,"firstLine");
package/typecheck-bus.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var y=Object.defineProperty;var c=(t,e)=>y(t,"name",{value:e,configurable:!0});var d=Object.defineProperty,s=c((t,e)=>d(t,"name",{value:e,configurable:!0}),"s"),f=Object.defineProperty,i=s((t,e)=>f(t,"name",{value:e,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(t){return t.replace(ANSI_CSI,"")}c(stripAnsi,"stripAnsi"),s(stripAnsi,"stripAnsi"),i(stripAnsi,"stripAnsi");function parseTscDiagnosticLine(t){const e=stripAnsi(t).trim();if(!e)return null;const n=DIAG_LINE_REGEX.exec(e);if(!n)return null;const[,o,l,a,p,g,u]=n;return!o||!l||!a||!p||!g||!u?null:{file:o,line:Number(l),column:Number(a),severity:p==="warning"?"warning":"error",code:g,message:u}}c(parseTscDiagnosticLine,"parseTscDiagnosticLine"),s(parseTscDiagnosticLine,"parseTscDiagnosticLine"),i(parseTscDiagnosticLine,"parseTscDiagnosticLine");function parseTscOutput(t){const e=[];for(const n of t.split(`
2
- `)){const o=parseTscDiagnosticLine(n);o&&e.push(o)}return e}c(parseTscOutput,"parseTscOutput"),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)}`}c(makeId,"makeId"),s(makeId,"makeId"),i(makeId,"makeId");function buildTypecheckRunEvents(t){const e=(t.now??Date.now)(),n=t.idImpl??makeId,o="pending",l={sessionId:o,source:"typescript",category:"typecheck",context:{sessionId:o,projectName:t.project}},a={project:t.project,tool:t.tool,...t.tsConfig?{tsConfig:t.tsConfig}:{}},p=t.diagnostics.filter(r=>r.severity==="error"),g=t.diagnostics.slice(0,exports.MAX_DIAGNOSTICS_PER_RUN),u=[];if(!t.toolError){u.push({...l,id:n(),timestamp:e,severity:"info",title:`tsc clear: ${t.project}`,message:`typecheck run starting for ${t.project}`,fingerprint:`tsc:${t.project}:run-start`,raw:{...a,kind:"typecheck-run",phase:"start"}});for(const r of g)u.push({...l,id:n(),timestamp:e,severity:r.severity,title:`${r.code}: ${r.message}`,message:r.message,location:{file:r.file,line:r.line,column:r.column},fingerprint:`tsc:${t.project}:${r.file}:${r.line}:${r.column}:${r.code}`,raw:{...a,kind:"typecheck-diagnostic",code:r.code}})}const h=t.toolError?"error":p.length>0?"failing":"clean";return u.push({...l,id:n(),timestamp:e,severity:"info",title:`typecheck run: ${t.project} \u2014 ${t.toolError?"tool error":`${p.length} error${p.length===1?"":"s"}`} (${t.durationMs}ms)`,...t.toolError?{message:t.toolError}:{},fingerprint:`tsc:${t.project}:run-end`,raw:{...a,kind:"typecheck-run",phase:"end",status:h,durationMs:t.durationMs,errorCount:p.length,warningCount:t.diagnostics.length-p.length,...t.diagnostics.length>g.length?{truncatedDiagnostics:t.diagnostics.length-g.length}:{},...t.toolError?{error:t.toolError}:{}}}),u}c(buildTypecheckRunEvents,"buildTypecheckRunEvents"),s(buildTypecheckRunEvents,"buildTypecheckRunEvents"),i(buildTypecheckRunEvents,"buildTypecheckRunEvents");function resolveEventFile(t){return process.env.LENSMCP_EVENT_FILE||path.join(t,".lensmcp","events.jsonl")}c(resolveEventFile,"resolveEventFile"),s(resolveEventFile,"resolveEventFile"),i(resolveEventFile,"resolveEventFile");let ensuredDir=null;function ensureDir(t){const e=path.dirname(t);ensuredDir!==e&&(fs.mkdirSync(e,{recursive:!0}),ensuredDir=e)}c(ensureDir,"ensureDir"),s(ensureDir,"ensureDir"),i(ensureDir,"ensureDir");function appendTypecheckEvents(t,e){if(e.length===0)return;const n=e.map(o=>JSON.stringify(o)).join(`
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(t),busHygiene?.maybeRotateEventFile(t,n.length),fs.appendFileSync(t,n)}catch(o){if(o?.code==="ENOENT"){try{ensuredDir=null,ensureDir(t),fs.appendFileSync(t,n)}catch{}return}}}c(appendTypecheckEvents,"appendTypecheckEvents"),s(appendTypecheckEvents,"appendTypecheckEvents"),i(appendTypecheckEvents,"appendTypecheckEvents");function publishTypecheckDiagnostics(t){const e=buildTypecheckRunEvents({project:t.project,tool:t.tool,...t.tsConfig?{tsConfig:t.tsConfig}:{},diagnostics:t.diagnostics,durationMs:t.durationMs});return appendTypecheckEvents(t.eventFile??resolveEventFile(t.workspaceRoot),e),e}c(publishTypecheckDiagnostics,"publishTypecheckDiagnostics"),s(publishTypecheckDiagnostics,"publishTypecheckDiagnostics"),i(publishTypecheckDiagnostics,"publishTypecheckDiagnostics");function publishTypecheckRun(t){const e=buildTypecheckRunEvents({project:t.project,tool:t.tool,...t.tsConfig?{tsConfig:t.tsConfig}:{},diagnostics:t.toolError?[]:parseTscOutput(t.output),durationMs:t.durationMs,...t.toolError?{toolError:t.toolError}:{}});return appendTypecheckEvents(t.eventFile??resolveEventFile(t.workspaceRoot),e),e}c(publishTypecheckRun,"publishTypecheckRun"),s(publishTypecheckRun,"publishTypecheckRun"),i(publishTypecheckRun,"publishTypecheckRun");
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");
@@ -0,0 +1,36 @@
1
+ export interface QueueTicket {
2
+ /** Give the slot back, or leave the line. Idempotent. */
3
+ release(): void;
4
+ }
5
+ /** Join the line; `onTurn` is called once, when this caller may run. */
6
+ export type TypecheckQueue = (label: string, onTurn: () => void) => QueueTicket;
7
+ export interface MachineQueueOptions {
8
+ dir?: string;
9
+ slots?: number;
10
+ /** How often a waiter looks again. */
11
+ pollMs?: number;
12
+ /**
13
+ * How long a new ticket waits before its first look. A ticket created in the same clock tick as
14
+ * ours may not be listed yet; after this pause it is, so two newcomers can never both see
15
+ * themselves first.
16
+ */
17
+ settleMs?: number;
18
+ /** A ticket older than this is treated as abandoned whatever its pid says (a reused pid looks alive). */
19
+ maxAgeMs?: number;
20
+ pid?: number;
21
+ isAlive?: (pid: number) => boolean;
22
+ now?: () => number;
23
+ }
24
+ /** `~/.lensmcp/typecheck-queue` — machine-wide on purpose; `LENSMCP_HOME` moves it (tests, sandboxes). */
25
+ export declare function typecheckQueueDir(env?: NodeJS.ProcessEnv): string;
26
+ /** `LENSMCP_TYPECHECK_CONCURRENCY`, default ONE. Anything unreadable is one, never unlimited. */
27
+ export declare function typecheckSlots(env?: NodeJS.ProcessEnv): number;
28
+ /**
29
+ * The line, oldest first. A ticket whose owner is dead — or that has sat past `maxAgeMs` — is
30
+ * deleted on the way, so a crashed service never holds a slot.
31
+ */
32
+ export declare function liveTickets(dir: string, options?: Pick<MachineQueueOptions, 'isAlive' | 'now' | 'maxAgeMs'>): string[];
33
+ /** The real queue. Every option has a production default; they are parameters for the spec. */
34
+ export declare function machineTypecheckQueue(options?: MachineQueueOptions): TypecheckQueue;
35
+ /** No queue: run at once. For specs of the plugin's own logic, and for nothing else. */
36
+ export declare const immediateQueue: TypecheckQueue;
@@ -0,0 +1 @@
1
+ "use strict";var T=Object.defineProperty;var c=(e,t)=>T(e,"name",{value:t,configurable:!0});var E=Object.defineProperty,r=c((e,t)=>E(e,"name",{value:t,configurable:!0}),"r");Object.defineProperty(exports,"__esModule",{value:!0}),exports.immediateQueue=void 0,exports.typecheckQueueDir=typecheckQueueDir,exports.typecheckSlots=typecheckSlots,exports.liveTickets=liveTickets,exports.machineTypecheckQueue=machineTypecheckQueue;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")),TICKET_SUFFIX=".ticket",DEFAULT_POLL_MS=250,DEFAULT_SETTLE_MS=120,DEFAULT_MAX_AGE_MS=15*6e4,MAX_SLOTS=8;function typecheckQueueDir(e=process.env){return path.join(e.LENSMCP_HOME||os.homedir(),".lensmcp","typecheck-queue")}c(typecheckQueueDir,"typecheckQueueDir"),r(typecheckQueueDir,"typecheckQueueDir");function typecheckSlots(e=process.env){const t=Number(e.LENSMCP_TYPECHECK_CONCURRENCY);return Number.isInteger(t)&&t>=1?Math.min(t,MAX_SLOTS):1}c(typecheckSlots,"typecheckSlots"),r(typecheckSlots,"typecheckSlots");function pidAlive(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}c(pidAlive,"pidAlive"),r(pidAlive,"pidAlive");const ticketPid=r(e=>{const t=Number(e.split("-")[0]);return Number.isInteger(t)&&t>0?t:void 0},"ticketPid");function liveTickets(e,t={}){const h=t.isAlive??pidAlive,S=(t.now??Date.now)(),m=t.maxAgeMs??DEFAULT_MAX_AGE_MS;let s;try{s=fs.readdirSync(e).filter(i=>i.endsWith(TICKET_SUFFIX))}catch{return[]}const u=[];for(const i of s){const n=path.join(e,i);let o;try{o=fs.statSync(n,{bigint:!0})}catch{continue}const a=ticketPid(i);if(a===void 0||!h(a)||S-Number(o.mtimeMs)>m){try{fs.unlinkSync(n)}catch{}continue}u.push({name:i,at:o.mtimeNs})}return u.sort((i,n)=>i.at<n.at?-1:i.at>n.at?1:i.name<n.name?-1:i.name>n.name?1:0),u.map(i=>i.name)}c(liveTickets,"liveTickets"),r(liveTickets,"liveTickets");let ticketSeq=0;function machineTypecheckQueue(e={}){const t=e.dir??typecheckQueueDir(),h=Math.max(1,e.slots??typecheckSlots()),S=e.pollMs??DEFAULT_POLL_MS,m=e.settleMs??DEFAULT_SETTLE_MS,s=e.pid??process.pid,u=r(()=>liveTickets(t,e),"scan");return(i,n)=>{const o=`${s}-${(ticketSeq++).toString(36)}-${Math.random().toString(36).slice(2,8)}${TICKET_SUFFIX}`,a=path.join(t,o);let l=!1,y=!1,p;const f=r(()=>{l||y||(y=!0,n())},"turn"),_=r(()=>{try{return fs.mkdirSync(t,{recursive:!0}),fs.writeFileSync(a,JSON.stringify({pid:s,label:i,at:(e.now??Date.now)()})),!0}catch{return!1}},"write"),k=r(d=>{p=setTimeout(M,d),p.unref?.()},"later");function M(){if(l||y)return;const d=u().indexOf(o);if(d===-1)return _()?k(m):f();if(d<h)return f();k(S)}return c(M,"k"),r(M,"look"),_()?(k(m),{release(){if(!l){l=!0,p&&clearTimeout(p);try{fs.unlinkSync(a)}catch{}}}}):(f(),{release(){l=!0}})}}c(machineTypecheckQueue,"machineTypecheckQueue"),r(machineTypecheckQueue,"machineTypecheckQueue");const immediateQueue=r((e,t)=>(t(),{release(){}}),"immediateQueue");exports.immediateQueue=immediateQueue;