@lensmcp/cluster 1.25.38 → 1.25.40

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 (32) hide show
  1. package/config-files.d.ts +20 -0
  2. package/config-files.js +1 -1
  3. package/devserver-notifier.d.ts +1 -1
  4. package/executors/gateway/prod-runtime/handler.js +1 -1
  5. package/executors/gateway/prod-runtime/observability.d.ts +4 -2
  6. package/executors/gateway/prod-runtime/observability.js +1 -1
  7. package/executors/gateway/runtime/awake.d.ts +42 -0
  8. package/executors/gateway/runtime/awake.js +1 -0
  9. package/executors/gateway/runtime/control.d.ts +11 -1
  10. package/executors/gateway/runtime/control.js +2 -2
  11. package/executors/gateway/runtime/discovery.js +1 -1
  12. package/executors/gateway/runtime/instance.d.ts +19 -3
  13. package/executors/gateway/runtime/instance.js +3 -2
  14. package/executors/gateway/runtime/lifecycle.d.ts +4 -1
  15. package/executors/gateway/runtime/lifecycle.js +3 -3
  16. package/executors/gateway/runtime/observability.d.ts +8 -3
  17. package/executors/gateway/runtime/observability.js +3 -3
  18. package/executors/gateway/runtime/proxy.js +1 -1
  19. package/executors/gateway/runtime/server.js +2 -2
  20. package/executors/gateway/runtime/shared-build.d.ts +1 -1
  21. package/executors/gateway/runtime/types.d.ts +46 -2
  22. package/executors/gateway/runtime/warm-start.d.ts +18 -0
  23. package/executors/gateway/runtime/warm-start.js +1 -1
  24. package/executors/serve/serve.impl.d.ts +1 -1
  25. package/executors/serve/serve.impl.js +1 -1
  26. package/package.json +4 -4
  27. package/perf/heavy-barrel-import.d.ts +1 -1
  28. package/shared-build/attach.d.ts +9 -0
  29. package/shared-build/attach.js +3 -3
  30. package/shared-build/protocol.d.ts +1 -1
  31. package/tsgo-check-plugin.d.ts +15 -0
  32. package/tsgo-check-plugin.js +4 -4
@@ -270,6 +270,17 @@ export interface LensFrontendSupervisor {
270
270
  /** Ensure a replacement is running and resolve when its route is ready. */
271
271
  recover(frontend: LensFrontend, reason: string): Promise<boolean>;
272
272
  }
273
+ /**
274
+ * What a `POST /awake` did with one service (awake.ts): it was `up` already; it is `queued` behind the machine's one
275
+ * start at a time, or `starting`; it `started`; the memory floor `deferred` it; it `failed` to come up; or it was
276
+ * `skipped` (stopped by hand and not named, or a stop/start/restart of it under way). `reason` says why for the last three.
277
+ */
278
+ export interface ServiceWake {
279
+ /** When it was asked for (ms). */
280
+ at: number;
281
+ outcome: 'up' | 'queued' | 'starting' | 'started' | 'deferred' | 'failed' | 'skipped';
282
+ reason?: string;
283
+ }
273
284
  /**
274
285
  * A restart someone asked for — an agent's `service_restart`, `lensmcp restart <service>` — of ONE service of one
275
286
  * workspace or worktree. A fresh tree re-reads what the service reads when it starts: its config files, its env, its
@@ -284,6 +295,9 @@ export interface ServiceRestart {
284
295
  startedAt: number;
285
296
  /** The pod generation it replaces (none when it was down). */
286
297
  fromGeneration?: number;
298
+ /** A worktree instance's service only: the variables its new tree is started with, read again from the instance's
299
+ * files when the restart was asked ({@link ServiceRestartEnv}). Never a value. */
300
+ env?: ServiceRestartEnv;
287
301
  /** Set once it settled: a pod of `generation` answers (`ok`), or why not. */
288
302
  done?: {
289
303
  ok: boolean;
@@ -292,6 +306,19 @@ export interface ServiceRestart {
292
306
  error?: string;
293
307
  };
294
308
  }
309
+ /**
310
+ * What a restart of a worktree instance's service applied (issues/closed/foodguard-127). The gateway holds the instance's
311
+ * variables — its hosts, `instance.resources.env`, `instance.env` — and gives them to every tree it starts; a restart
312
+ * reads the files again, so an edit to them takes. These say which variables, never what they are.
313
+ */
314
+ export interface ServiceRestartEnv {
315
+ /** instance.ts `instanceEnvFingerprint` of the variables the new tree is started with. */
316
+ fingerprint: string;
317
+ /** The same over what the service had before. Equal to `fingerprint` when nothing changed. */
318
+ fromFingerprint: string;
319
+ /** The names of the variables added, removed or changed since then — sorted. */
320
+ changed: string[];
321
+ }
295
322
  export interface ServiceCtl {
296
323
  project: string;
297
324
  decl: ClusterProjectDecl;
@@ -306,8 +333,12 @@ export interface ServiceCtl {
306
333
  * `sockNs`): passed as `LENSMCP_SOCK_NS`, and the pool is `$TMPDIR/<sockNs>/<svc>-devserver`. */
307
334
  sockNs?: string;
308
335
  /** A worktree instance's variables (instance.ts `InstanceRouting.env`): its hosts and `instance.env`, injected
309
- * into this service's tree under the gateway's own variables. */
336
+ * into this service's tree under the gateway's own variables. Read at registration; a restart of this service
337
+ * (lifecycle.ts `restartService`) reads the files again and replaces this one's — no other service's. */
310
338
  instanceEnv?: Readonly<Record<string, string>>;
339
+ /** The built-ins those variables were layered over at discovery (instance.ts `instanceBuiltinEnv`: the instance's
340
+ * name, apexes and hosts) — what a restart reads the files over again. Set exactly when `instanceEnv` is. */
341
+ instanceBuiltins?: Readonly<Record<string, string>>;
311
342
  /** Set while this service waits for a cold-start slot ({@link MAX_COLD_STARTS}): later requests wait on it
312
343
  * rather than queueing a second start. */
313
344
  coldWait?: Promise<void>;
@@ -339,6 +370,19 @@ export interface ServiceCtl {
339
370
  rollFailure?: string;
340
371
  /** The latest restart someone ASKED for (control.ts `POST /restart`, lifecycle.ts `restartService`) — settled or not. */
341
372
  restart?: ServiceRestart;
373
+ /**
374
+ * Kept awake until then (ms): the idle sweep stops it no sooner, and its idle window counts from then rather than from
375
+ * a request long ago (control.ts `POST /awake`, awake.ts). A queue worker's work arrives with no request, and stops
376
+ * with its service (issues/closed/foodguard-123).
377
+ */
378
+ awakeUntil?: number;
379
+ /** When the idle sweep last stopped it, and why — what a preflight says of a required service it finds down. */
380
+ lastIdleStop?: {
381
+ at: number;
382
+ why: string;
383
+ };
384
+ /** The latest `POST /awake` of it, and how its start went ({@link ServiceWake}). */
385
+ wake?: ServiceWake;
342
386
  /** The pod GENERATION the current `proc` was spawned as (`LENSMCP_POD_GENERATION`, echoed in `/__lensmcp/alive`). */
343
387
  generation?: number;
344
388
  /** How the current `proc` was started: the gateway's serve runner, or `nx run` (serve-launch.ts). An `nx run`
@@ -855,7 +899,7 @@ export interface GatewayRuntime {
855
899
  * each current. Absent when the gateway was started without a graph — every service then starts through `nx run`. */
856
900
  readonly graphStores?: ProjectGraphStores;
857
901
  /** The gateway's `sharedCompiler` option — one webpack compilation for this workspace's services
858
- * (shared-build.ts, issues/open/pod-memory-05). `LENSMCP_SHARED_COMPILER` wins over it. */
902
+ * (shared-build.ts, issues/closed/pod-memory-05). `LENSMCP_SHARED_COMPILER` wins over it. */
859
903
  readonly sharedCompiler?: boolean;
860
904
  /** Managed lens frontend handoff state, installed by the child supervisor. */
861
905
  lensSupervisor?: LensFrontendSupervisor;
@@ -12,6 +12,16 @@ export declare function warmMinFreeBytes(env?: NodeJS.ProcessEnv): number;
12
12
  * `undefined` — never idle-stopped — for the daemon's own and other registered workspaces' services, as before.
13
13
  */
14
14
  export declare function instanceIdleSec(svc: Pick<ServiceCtl, 'decl'>, isInstance: boolean, env?: NodeJS.ProcessEnv): number | undefined;
15
+ /**
16
+ * The idle window the sweep gives `svc` (lifecycle.ts `sweepOnce`) — {@link instanceIdleSec}, an instance being a
17
+ * registered worktree's service, never the daemon's own. One rule for the sweep and for what `/status` says of it.
18
+ */
19
+ export declare function serviceIdleSec(rt: {
20
+ readonly root?: string;
21
+ readonly registry?: {
22
+ get(wsKey: string): WorkspaceFragment | undefined;
23
+ };
24
+ }, svc: Pick<ServiceCtl, 'decl' | 'root' | 'wsKey'>, env?: NodeJS.ProcessEnv): number | undefined;
15
25
  export interface MemoryProbe {
16
26
  platform?: NodeJS.Platform;
17
27
  /** `sysctl -n <name>`. */
@@ -39,6 +49,8 @@ export interface WarmOutcome {
39
49
  outcome: 'up' | 'failed' | 'deferred' | 'already';
40
50
  reason?: string;
41
51
  }
52
+ /** Why a start waits, when the memory the system can still give out is under the floor; nothing when it is not (or unread). */
53
+ export declare function belowFloor(free: number | undefined, minFreeBytes: number): string | undefined;
42
54
  /** Start `services`' always-warm ones, one at a time, while the floor holds. Never throws. */
43
55
  export declare function warmStart(services: readonly ServiceCtl[], deps: WarmStartDeps): Promise<WarmOutcome[]>;
44
56
  export interface WorktreeWarmerDeps {
@@ -61,4 +73,10 @@ export interface WorktreeWarmerDeps {
61
73
  export declare function createWorktreeWarmer(deps: WorktreeWarmerDeps): {
62
74
  onRegister(fragment: WorkspaceFragment): Promise<WarmOutcome[]> | undefined;
63
75
  onUnregister(wsKey: string): void;
76
+ /**
77
+ * Run `job` in the machine's one turn — after every warm start before it, and before any after it. A worktree's
78
+ * services woken for a milestone (control.ts `POST /awake`, awake.ts) start here too, so a wake and a registration
79
+ * never start two compilers at once (issues/closed/foodguard-123).
80
+ */
81
+ take<T>(job: () => Promise<T>): Promise<T>;
64
82
  };
@@ -1 +1 @@
1
- "use strict";var _=Object.defineProperty;var p=(e,r)=>_(e,"name",{value:r,configurable:!0});var f=Object.defineProperty,u=p((e,r)=>f(e,"name",{value:r,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.DEFAULT_WORKTREE_IDLE_SEC=exports.WORKTREE_IDLE_ENV=exports.DEFAULT_WARM_MIN_FREE_MB=exports.WARM_MIN_FREE_ENV=void 0,exports.warmMinFreeBytes=warmMinFreeBytes,exports.instanceIdleSec=instanceIdleSec,exports.availableMemory=availableMemory,exports.warmStart=warmStart,exports.createWorktreeWarmer=createWorktreeWarmer;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path"));exports.WARM_MIN_FREE_ENV="LENSMCP_WARM_MIN_FREE_MB",exports.DEFAULT_WARM_MIN_FREE_MB=4096,exports.WORKTREE_IDLE_ENV="LENSMCP_WORKTREE_IDLE_SEC",exports.DEFAULT_WORKTREE_IDLE_SEC=1800;function warmMinFreeBytes(e=process.env){const r=Number(e[exports.WARM_MIN_FREE_ENV]);return(Number.isFinite(r)&&r>=0?r:exports.DEFAULT_WARM_MIN_FREE_MB)*1024*1024}p(warmMinFreeBytes,"warmMinFreeBytes"),u(warmMinFreeBytes,"warmMinFreeBytes");function instanceIdleSec(e,r,i=process.env){if(e.decl.idleKillSec)return e.decl.idleKillSec;if(!r)return;const o=Number(i[exports.WORKTREE_IDLE_ENV]?.trim()||NaN);return!Number.isFinite(o)||o<0?exports.DEFAULT_WORKTREE_IDLE_SEC:o>0?o:void 0}p(instanceIdleSec,"instanceIdleSec"),u(instanceIdleSec,"instanceIdleSec");function availableMemory(e={}){const r=e.platform??process.platform;try{if(r==="darwin"){const i=e.sysctl??(t=>(0,node_child_process_1.execFileSync)("sysctl",["-n",t],{encoding:"utf8",timeout:2e3})),o=Number(i("kern.memorystatus_level").trim());return!Number.isFinite(o)||o<0||o>100?void 0:Math.round(o/100*(e.totalmem??os.totalmem)())}if(r==="linux"){const i=(e.readFile??(t=>fs.readFileSync(t,"utf8")))("/proc/meminfo"),o=/^MemAvailable:\s+(\d+)\s+kB/m.exec(i)?.[1];return o===void 0?void 0:Number(o)*1024}}catch{}}p(availableMemory,"availableMemory"),u(availableMemory,"availableMemory");const gb=u(e=>`${(e/1024**3).toFixed(1)} GB`,"gb");async function warmStart(e,r){const i=[],o=e.filter(t=>t.decl.eager&&!t.frozen);for(let t=0;t<o.length;t++){const c=o[t];if(!r.current(c))break;if(c.proc||c.state!=="down"){i.push({project:c.project,outcome:"already"});continue}const l=r.available();if(l!==void 0&&l<r.minFreeBytes){const a=`${gb(l)} of memory free, under the ${gb(r.minFreeBytes)} a warm start keeps (${exports.WARM_MIN_FREE_ENV})`,m=o.slice(t).filter(n=>!n.proc&&n.state==="down");r.log(`[gateway] warm start stopped for ${c.wsKey}: ${a} \u2014 ${m.map(n=>n.project).join(", ")} start on their first request.`);for(const n of m)r.emit(n,"info",`warm start deferred: ${n.project} \u2014 ${a}`,{kind:"service-warm-deferred",project:n.project,reason:a,availableBytes:l,minFreeBytes:r.minFreeBytes}),i.push({project:n.project,outcome:"deferred",reason:a});return i}const s=await r.ensureUp(c).catch(()=>!1);s&&(c.lastUsed=Date.now()),i.push({project:c.project,outcome:s?"up":"failed"})}return i}p(warmStart,"warmStart"),u(warmStart,"warmStart");function createWorktreeWarmer(e){const r=new Map,i=e.log??(t=>console.log(t));let o=(e.ready??Promise.resolve()).catch(()=>{});return{onRegister(t){if(!t.instance||t.instance.frozen)return;const c=Symbol(t.wsKey);r.set(t.wsKey,c);const l=o.then(()=>new Promise(s=>setTimeout(s,e.delayMs??1e3).unref?.())).then(()=>warmStart(t.services,{ensureUp:e.ensureUp,available:e.available??(()=>availableMemory()),minFreeBytes:warmMinFreeBytes(e.env),current:u(s=>!e.rt.stopped()&&r.get(s.wsKey)===c&&!!e.rt.registry.get(s.wsKey)?.services.includes(s),"current"),emit:u((s,a,m,n)=>e.obs.emit(a,m,`cluster-service:${s.project}`,{wsKey:s.wsKey,...n},void 0,path.join(s.root,".lensmcp","events.jsonl")),"emit"),log:i})).then(s=>{const a=u(m=>s.filter(n=>n.outcome===m).map(n=>n.project),"by");return s.length&&i(`[gateway] warm start of ${t.wsKey}: up ${a("up").join(", ")||"\u2014"}${a("failed").length?`; failed ${a("failed").join(", ")}`:""}${a("deferred").length?`; on first request ${a("deferred").join(", ")}`:""}`),s});return o=l.catch(()=>{}),l},onUnregister(t){r.delete(t)}}}p(createWorktreeWarmer,"createWorktreeWarmer"),u(createWorktreeWarmer,"createWorktreeWarmer");
1
+ "use strict";var m=Object.defineProperty;var u=(e,r)=>m(e,"name",{value:r,configurable:!0});var f=Object.defineProperty,a=u((e,r)=>f(e,"name",{value:r,configurable:!0}),"a");Object.defineProperty(exports,"__esModule",{value:!0}),exports.DEFAULT_WORKTREE_IDLE_SEC=exports.WORKTREE_IDLE_ENV=exports.DEFAULT_WARM_MIN_FREE_MB=exports.WARM_MIN_FREE_ENV=void 0,exports.warmMinFreeBytes=warmMinFreeBytes,exports.instanceIdleSec=instanceIdleSec,exports.serviceIdleSec=serviceIdleSec,exports.availableMemory=availableMemory,exports.belowFloor=belowFloor,exports.warmStart=warmStart,exports.createWorktreeWarmer=createWorktreeWarmer;const tslib_1=require("tslib"),node_child_process_1=require("node:child_process"),fs=tslib_1.__importStar(require("node:fs")),os=tslib_1.__importStar(require("node:os")),path=tslib_1.__importStar(require("node:path"));exports.WARM_MIN_FREE_ENV="LENSMCP_WARM_MIN_FREE_MB",exports.DEFAULT_WARM_MIN_FREE_MB=4096,exports.WORKTREE_IDLE_ENV="LENSMCP_WORKTREE_IDLE_SEC",exports.DEFAULT_WORKTREE_IDLE_SEC=1800;function warmMinFreeBytes(e=process.env){const r=Number(e[exports.WARM_MIN_FREE_ENV]);return(Number.isFinite(r)&&r>=0?r:exports.DEFAULT_WARM_MIN_FREE_MB)*1024*1024}u(warmMinFreeBytes,"warmMinFreeBytes"),a(warmMinFreeBytes,"warmMinFreeBytes");function instanceIdleSec(e,r,n=process.env){if(e.decl.idleKillSec)return e.decl.idleKillSec;if(!r)return;const o=Number(n[exports.WORKTREE_IDLE_ENV]?.trim()||NaN);return!Number.isFinite(o)||o<0?exports.DEFAULT_WORKTREE_IDLE_SEC:o>0?o:void 0}u(instanceIdleSec,"instanceIdleSec"),a(instanceIdleSec,"instanceIdleSec");function serviceIdleSec(e,r,n=process.env){const o=e.root!==void 0&&r.root!==void 0&&path.resolve(r.root)===path.resolve(e.root);return instanceIdleSec(r,!o&&!!e.registry?.get(r.wsKey)?.instance,n)}u(serviceIdleSec,"serviceIdleSec"),a(serviceIdleSec,"serviceIdleSec");function availableMemory(e={}){const r=e.platform??process.platform;try{if(r==="darwin"){const n=e.sysctl??(t=>(0,node_child_process_1.execFileSync)("sysctl",["-n",t],{encoding:"utf8",timeout:2e3})),o=Number(n("kern.memorystatus_level").trim());return!Number.isFinite(o)||o<0||o>100?void 0:Math.round(o/100*(e.totalmem??os.totalmem)())}if(r==="linux"){const n=(e.readFile??(t=>fs.readFileSync(t,"utf8")))("/proc/meminfo"),o=/^MemAvailable:\s+(\d+)\s+kB/m.exec(n)?.[1];return o===void 0?void 0:Number(o)*1024}}catch{}}u(availableMemory,"availableMemory"),a(availableMemory,"availableMemory");const gb=a(e=>`${(e/1024**3).toFixed(1)} GB`,"gb");function belowFloor(e,r){return e!==void 0&&e<r?`${gb(e)} of memory free, under the ${gb(r)} a warm start keeps (${exports.WARM_MIN_FREE_ENV})`:void 0}u(belowFloor,"belowFloor"),a(belowFloor,"belowFloor");async function warmStart(e,r){const n=[],o=e.filter(t=>t.decl.eager&&!t.frozen);for(let t=0;t<o.length;t++){const c=o[t];if(!r.current(c))break;if(c.proc||c.state!=="down"){n.push({project:c.project,outcome:"already"});continue}const d=r.available(),s=belowFloor(d,r.minFreeBytes);if(s){const p=o.slice(t).filter(i=>!i.proc&&i.state==="down");r.log(`[gateway] warm start stopped for ${c.wsKey}: ${s} \u2014 ${p.map(i=>i.project).join(", ")} start on their first request.`);for(const i of p)r.emit(i,"info",`warm start deferred: ${i.project} \u2014 ${s}`,{kind:"service-warm-deferred",project:i.project,reason:s,availableBytes:d,minFreeBytes:r.minFreeBytes}),n.push({project:i.project,outcome:"deferred",reason:s});return n}const l=await r.ensureUp(c).catch(()=>!1);l&&(c.lastUsed=Date.now()),n.push({project:c.project,outcome:l?"up":"failed"})}return n}u(warmStart,"warmStart"),a(warmStart,"warmStart");function createWorktreeWarmer(e){const r=new Map,n=e.log??(t=>console.log(t));let o=(e.ready??Promise.resolve()).catch(()=>{});return{onRegister(t){if(!t.instance||t.instance.frozen)return;const c=Symbol(t.wsKey);r.set(t.wsKey,c);const d=o.then(()=>new Promise(s=>setTimeout(s,e.delayMs??1e3).unref?.())).then(()=>warmStart(t.services,{ensureUp:e.ensureUp,available:e.available??(()=>availableMemory()),minFreeBytes:warmMinFreeBytes(e.env),current:a(s=>!e.rt.stopped()&&r.get(s.wsKey)===c&&!!e.rt.registry.get(s.wsKey)?.services.includes(s),"current"),emit:a((s,l,p,i)=>e.obs.emit(l,p,`cluster-service:${s.project}`,{wsKey:s.wsKey,...i},void 0,path.join(s.root,".lensmcp","events.jsonl")),"emit"),log:n})).then(s=>{const l=a(p=>s.filter(i=>i.outcome===p).map(i=>i.project),"by");return s.length&&n(`[gateway] warm start of ${t.wsKey}: up ${l("up").join(", ")||"\u2014"}${l("failed").length?`; failed ${l("failed").join(", ")}`:""}${l("deferred").length?`; on first request ${l("deferred").join(", ")}`:""}`),s});return o=d.catch(()=>{}),d},onUnregister(t){r.delete(t)},take(t){const c=o.then(t);return o=c.catch(()=>{}),c}}}u(createWorktreeWarmer,"createWorktreeWarmer"),a(createWorktreeWarmer,"createWorktreeWarmer");
@@ -19,7 +19,7 @@ interface ServeResult {
19
19
  *
20
20
  * Owns the full devserver lifecycle:
21
21
  * 1. Starts webpack in watch mode — or, under a gateway running the shared compiler, joins the workspace's ONE
22
- * compilation (shared-build/attach.ts, issues/open/pod-memory-05) and is told about each build of its bundle
22
+ * compilation (shared-build/attach.ts, issues/closed/pod-memory-05) and is told about each build of its bundle
23
23
  * 2. On first successful build, starts main.devserver.js with proper env vars — in this process under the gateway's
24
24
  * serve runner (devserver-host.ts), forked otherwise
25
25
  * 3. On subsequent builds, POSTs /webpack/reload to devserver — attached: only when ITS bundle changed
@@ -1 +1 @@
1
- "use strict";var me=Object.defineProperty;var i=(e,o)=>me(e,"name",{value:o,configurable:!0});var pe=Object.defineProperty,s=i((e,o)=>pe(e,"name",{value:o,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0});const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),fs=tslib_1.__importStar(require("node:fs")),node_child_process_1=require("node:child_process"),yaml=tslib_1.__importStar(require("js-yaml")),child_process_env_1=require("../../child-process-env"),dev_devtool_1=require("../../dev-devtool"),devserver_host_1=require("../../devserver-host"),devserver_notifier_1=require("../../devserver-notifier"),process_name_1=require("../../process-name"),worker_supervisor_1=require("../../worker-supervisor"),attach_1=require("../../shared-build/attach"),stop_on_signal_1=require("./stop-on-signal"),compile_retry_1=require("../../compile-retry"),config_files_1=require("../../config-files"),signature_1=require("../../shared-build/signature");function definedEnv(e){const o={};for(const[$,n]of Object.entries(e))typeof n=="string"&&(o[$]=n);return o}i(definedEnv,"definedEnv"),s(definedEnv,"definedEnv");const frozen=s(()=>process.env.LENSMCP_FREEZE==="1","frozen");async function*serveExecutor(e,o){process.env.NODE_ENV="development";const $=o.projectsConfigurations.projects[o.projectName],n=o.root,N=path.join(n,$.root),K=e.outputPath?path.join(n,e.outputPath):path.join(n,"dist",$.root),Z=e.configEnv||"development",D=path.join(n,"config",`config.${Z}.yaml`),T=3050;let d=T,a=o.projectName,j={};fs.existsSync(D)?(j=yaml.load(fs.readFileSync(D,"utf8")),d=Number(j.port)||d,a=j.serviceName||a):console.warn(`[serve] ${o.projectName}: no config file at ${D} \u2014 public devserver port defaults to ${T}. If another service also lacks its config, both bind ${T} \u2192 EADDRINUSE. Add config/config.${Z}.yaml with a distinct \`port:\` (matching this project's cluster.port).`),e.serviceName&&(a=e.serviceName);const x=e.servePrefix??"",y=e.debugPort??(Number(process.env.LENSMCP_DEBUG_PORT)||void 0),ne=/^(1|true|yes|on)$/i.test((process.env.LENSMCP_DEBUG_FIXED_PORTS??"").trim()),m=e.logFile?path.resolve(n,e.logFile):process.env.LENSMCP_LOG_FILE||void 0;if(m){fs.mkdirSync(path.dirname(m),{recursive:!0}),fs.writeFileSync(m,"",{mode:384});try{fs.chmodSync(m,384)}catch{}}let A,I;e.gateway?.middleware&&(A=path.resolve(N,e.gateway.middleware),I=JSON.stringify(j));const ie=e.entryFile||"./src/deployments/service/main.ts",ce=e.tsConfigFile||"./tsconfig.app.json",ae=path.resolve(N,ie),Q=path.resolve(N,ce),le=(e.workers||[]).map(r=>({entryName:r.name,entryPath:path.resolve(N,r.entryPath)})),E={appName:o.projectName,appRoot:N,outputDir:K,main:ae,tsConfig:Q,assets:e.assets||[],additionalEntryPoints:le,port:d,serviceName:a,memoryLimit:e.memoryLimit||8192,buildLibsFromSource:e.buildLibsFromSource!==!1,workspaceRoot:n,orgScopes:e.orgScopes||[],bundlePackages:e.bundlePackages||[],nodeExternalsConfig:e.nodeExternalsConfig,webpackConfigPath:e.webpackConfigPath,httpsReload:e.gateway?.https===!0,...e.devtool!==void 0&&{devtool:e.devtool}};let l=null,q=!1,F=!1,M=!1,p=!1;const ee=path.join(__dirname,"../../main.devserver.js"),oe=path.join(__dirname,"../../main.devserver.ts"),U=!fs.existsSync(ee)&&fs.existsSync(oe),C=U?oe:ee,ue=path.join(K,"main.js");function B(){l&&!l.killed&&(l.kill("SIGTERM"),l=null)}i(B,"K"),s(B,"cleanup");function O(){p=!0,B()}i(O,"U"),s(O,"stop");const de=(0,stop_on_signal_1.stopOnSignal)({stop:O,close:s(()=>b(),"close")});process.on("exit",O);function S(){if(p||q)return;if(!fs.existsSync(C)){console.error(`[serve] devserver script not found at ${C}`);return}const r=(0,child_process_env_1.childProcessEnv)({...process.env,PORT:String(d),SERVICE_NAME:a,SERVE_PREFIX:x,LENSMCP_PROJECT:process.env.LENSMCP_PROJECT||o.projectName||a,LENSMCP_EVENT_FILE:process.env.LENSMCP_EVENT_FILE||path.join(n,".lensmcp","events.jsonl"),CHILD_COUNT:String(e.childCount||process.env.CHILD_COUNT||1),BUNDLE_PATH:ue,...A&&{GATEWAY_MIDDLEWARE:A},...I&&{GATEWAY_CONFIG:I},...e.gateway?.routes?.length&&{GATEWAY_ROUTES:JSON.stringify(e.gateway.routes)},...e.gateway?.https&&{GATEWAY_HTTPS:"1"},...e.gateway?.extraPorts?.length&&{GATEWAY_EXTRA_PORTS:JSON.stringify(e.gateway.extraPorts)},...e.internalPort&&{INTERNAL_PORT:String(e.internalPort)},...y&&{LENSMCP_DEBUG_PORT:String(y)},...m&&{LENSMCP_LOG_FILE:m},...e.workers?.length&&{WORKERS:(0,worker_supervisor_1.serializeWorkerSpecs)(e.workers)},[dev_devtool_1.DEV_SOURCE_MAPS_ENV]:M?"1":"0"});if((0,devserver_host_1.devserverInProcessOffered)()&&(!U||require.extensions[".ts"])){q=!0;for(const[u,f]of Object.entries(r))f!==void 0&&(process.env[u]=f);(0,devserver_host_1.markDevserverInProcess)(),require(C),G("in this process");return}const v=["--enable-source-maps"];U&&v.unshift("--require","@swc-node/register");const c=(0,node_child_process_1.fork)(C,{cwd:n,env:r,stdio:["inherit","inherit","inherit","ipc"],execArgv:v,execPath:(0,process_name_1.namedExecPath)((0,process_name_1.processName)(process.env.LENSMCP_WS_KEY||path.basename(n),a,"dev"))});l=c,c.on("exit",(u,f)=>{l===c&&(l=null),!(f||u===0||p)&&(console.error(`[serve] devserver exited unexpectedly (code=${u}, signal=${f}) \u2014 respawning in 1.5s`),setTimeout(()=>{!p&&!l&&F&&S()},1500).unref?.())}),G()}i(S,"C"),s(S,"startDevServer");function G(r){console.log(`[serve] Devserver started on port ${d} (service: ${a}${x?`, prefix: /${x}`:""}${r?`, ${r}`:""})`),y?(console.warn(`[serve] DEBUGGER ENABLED for ${a}. Node's inspector has NO authentication \u2014 the ws:// UUID is the whole credential, and any account on this host that obtains it runs code as you. Do not enable this on a shared machine.`),ne?console.warn(`[serve] LENSMCP_DEBUG_FIXED_PORTS=1 \u2014 pod inspectors bind PREDICTABLE ports 127.0.0.1:${y}+slot (workers ${y}+20+i), reachable by any account on this host. Attach WebStorm (Attach to Node.js/Chrome) to ${y}. Unset it to bind ephemeral ports instead.`):console.log(`[serve] Debug: pod inspectors bind an EPHEMERAL 127.0.0.1 port. Get the ws:// URLs with \`lensmcp debug ${a}\` (the owner-only control socket); a devserver run in your own terminal also prints them there. Set LENSMCP_DEBUG_FIXED_PORTS=1 if your IDE needs a fixed attach port.`)):console.log(`[serve] Debug on demand: \`lensmcp debug ${a}\` opens pod inspectors without a restart`),m&&console.log(`[serve] Logs teed to ${m} \u2014 tail it in WebStorm via Run/Debug configuration \u2192 Logs tab`)}i(G,"Z"),s(G,"announceDevServer");function ve(){if(!l||l.killed){console.log("[serve] Devserver not running, restarting..."),S();return}fetch(`http://localhost:${d}/webpack/reload`,{method:"POST",headers:{"content-type":"application/json"},body:"{}"}).then(()=>console.log("[serve] Notified devserver to reload")).catch(r=>{console.warn("[serve] Failed to notify devserver, restarting...",r.message),B(),S()})}i(ve,"he"),s(ve,"_notifyDevServerReload");let k=null;const W=[];function _(r){if(k){const v=k;k=null,v(r)}else W.push(r)}i(_,"w"),s(_,"pushResult");function re(){return W.length>0?Promise.resolve(W.shift()):new Promise(r=>{k=r})}i(re,"le"),s(re,"waitForNext");let b=s(()=>{},"closeBuild");function V(){return!F||!l&&!q?(F=!0,S(),!0):!1}i(V,"Q"),s(V,"builtOk");function H(){try{return JSON.stringify((0,signature_1.transpileCompilerOptions)(E.tsConfig,n))}catch{return}}i(H,"ee"),s(H,"compileShape");function P(){if(p)return;const{createDevWebpackConfig:r}=require("../../create-webpack-dev"),v=require("webpack"),c=E.webpackConfigPath?path.resolve(E.appRoot,E.webpackConfigPath):void 0;if(c)try{delete require.cache[require.resolve(c)]}catch{}const u=r(E),{watch:f,...t}=u,J=(0,config_files_1.configFilesOf)(E),Y=H();let X;t.plugins=[...t.plugins??[],new config_files_1.ConfigFilesPlugin({files:s(()=>J,"files"),changed:s(w=>{if(!c||!w.includes(c)){const h=H();if(h===void 0||h===Y)return}X=w.map(h=>path.relative(n,h)).sort().join(", ")},"changed")})];const R=v(t);M=(0,dev_devtool_1.bundleCarriesSourceMaps)(R.options.devtool);let g;const L=(0,compile_retry_1.createFailureRetry)(()=>{p||!g||(console.log(`[serve] ${o.projectName}: compiling again after the failure`),g.invalidate())}),se=s((w,h)=>{if(X!==void 0&&g&&!p){console.log(`[serve] ${o.projectName}: ${X} changed what it compiles with \u2014 compiling again with a new compiler`),L.dispose();const z=g;g=void 0,setImmediate(()=>z.close(()=>P()));return}if(w){if(console.error("[serve] Webpack error:",w),g&&!p){const{delayMs:z,retry:he}=L.failed();console.log(`[serve] ${o.projectName}: compiling again in ${Math.round(z/1e3)} s (retry ${he}) \u2014 webpack does not after a failure like this`)}_({success:!1});return}L.succeeded();const fe=h.hasErrors();if(console.info(h.toString({colors:!0,chunks:!1,assets:!0})),fe){_({success:!1});return}V(),_({success:!0,baseUrl:`http://localhost:${d}`})},"onBuild");if(frozen()){console.log(`[serve] ${o.projectName}: frozen \u2014 compiling once, no file watcher`),R.run((w,h)=>{se(w,h),R.close(()=>{})});return}g=R.watch(u.watchOptions||{},se),b=s(()=>{L.dispose(),g?.close(()=>{})},"closeBuild")}i(P,"$"),s(P,"compileOnItsOwn");function te(r){const v=r.accepted.projects.filter(t=>t!==o.projectName);console.log(`[serve] ${o.projectName}: compiled by the workspace's shared compilation ${r.accepted.group.slice(0,8)}${v.length?` with ${v.join(", ")}`:""} \u2014 no webpack in this process`);const c=new devserver_notifier_1.DevserverNotifier(d,e.gateway?.https===!0,(0,devserver_notifier_1.devserverControlSock)(a)),u=(0,attach_1.createAttachedTypecheck)({appName:o.projectName,tsConfig:Q,workspaceRoot:n,memoryLimit:e.memoryLimit||8192});let f;b=s(()=>{r.close(),u.dispose()},"closeBuild"),r.listen(t=>{if(!p)switch(t.type){case"watch-run":c.watchRun(t.paths);return;case"watch-closed":c.degrade("watch closed");return;case"failed":console.error(`[serve] the shared compiler failed: ${t.message}`),c.failed(`the shared compiler failed: ${t.message}`),_({success:!1});return;case"refused":console.log(`[serve] ${o.projectName}: compiling on its own from now on \u2014 ${t.reason}`),b(),P();return;case"built":{if(console.info(t.text),M=t.sourceMaps,u.built(t),!t.ok){c.failed(),_({success:!1});return}const J=t.hash!==f;f=t.hash;const Y=V();c.built(J&&!Y),_({success:!0,baseUrl:`http://localhost:${d}`});return}default:return}})}if(i(te,"ue"),s(te,"attachToSharedBuild"),(0,attach_1.sharedBuildOffered)()&&!frozen()){const r=await(0,attach_1.joinSharedBuild)({project:o.projectName,target:o.targetName??"serve-hmr",...o.configurationName?{configuration:o.configurationName}:{},options:E,targetOptions:{...e},env:definedEnv(process.env)});r.kind==="attached"?te(r.session):(console.log(`[serve] ${o.projectName}: compiling on its own \u2014 ${r.reason}`),P())}else P();try{for(;;)yield await re()}finally{O(),b(),de()}}i(serveExecutor,"serveExecutor"),s(serveExecutor,"serveExecutor"),exports.default=serveExecutor,module.exports=serveExecutor,module.exports.default=serveExecutor;
1
+ "use strict";var _e=Object.defineProperty;var i=(e,o)=>_e(e,"name",{value:o,configurable:!0});var ve=Object.defineProperty,s=i((e,o)=>ve(e,"name",{value:o,configurable:!0}),"s");Object.defineProperty(exports,"__esModule",{value:!0});const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),fs=tslib_1.__importStar(require("node:fs")),node_child_process_1=require("node:child_process"),yaml=tslib_1.__importStar(require("js-yaml")),child_process_env_1=require("../../child-process-env"),dev_devtool_1=require("../../dev-devtool"),devserver_host_1=require("../../devserver-host"),devserver_notifier_1=require("../../devserver-notifier"),process_name_1=require("../../process-name"),worker_supervisor_1=require("../../worker-supervisor"),attach_1=require("../../shared-build/attach"),stop_on_signal_1=require("./stop-on-signal"),compile_retry_1=require("../../compile-retry"),config_files_1=require("../../config-files"),signature_1=require("../../shared-build/signature");function definedEnv(e){const o={};for(const[j,n]of Object.entries(e))typeof n=="string"&&(o[j]=n);return o}i(definedEnv,"definedEnv"),s(definedEnv,"definedEnv");const frozen=s(()=>process.env.LENSMCP_FREEZE==="1","frozen");async function*serveExecutor(e,o){process.env.NODE_ENV="development";const j=o.projectsConfigurations.projects[o.projectName],n=o.root,S=path.join(n,j.root),Q=e.outputPath?path.join(n,e.outputPath):path.join(n,"dist",j.root),ee=e.configEnv||"development",A=path.join(n,"config",`config.${ee}.yaml`),q=3050;let d=q,a=o.projectName,O={};fs.existsSync(A)?(O=yaml.load(fs.readFileSync(A,"utf8")),d=Number(O.port)||d,a=O.serviceName||a):console.warn(`[serve] ${o.projectName}: no config file at ${A} \u2014 public devserver port defaults to ${q}. If another service also lacks its config, both bind ${q} \u2192 EADDRINUSE. Add config/config.${ee}.yaml with a distinct \`port:\` (matching this project's cluster.port).`),e.serviceName&&(a=e.serviceName);const I=e.servePrefix??"",y=e.debugPort??(Number(process.env.LENSMCP_DEBUG_PORT)||void 0),ce=/^(1|true|yes|on)$/i.test((process.env.LENSMCP_DEBUG_FIXED_PORTS??"").trim()),g=e.logFile?path.resolve(n,e.logFile):process.env.LENSMCP_LOG_FILE||void 0;if(g){fs.mkdirSync(path.dirname(g),{recursive:!0}),fs.writeFileSync(g,"",{mode:384});try{fs.chmodSync(g,384)}catch{}}let M,F;e.gateway?.middleware&&(M=path.resolve(S,e.gateway.middleware),F=JSON.stringify(O));const ae=e.entryFile||"./src/deployments/service/main.ts",le=e.tsConfigFile||"./tsconfig.app.json",ue=path.resolve(S,ae),oe=path.resolve(S,le),pe=(e.workers||[]).map(r=>({entryName:r.name,entryPath:path.resolve(S,r.entryPath)})),m={appName:o.projectName,appRoot:S,outputDir:Q,main:ue,tsConfig:oe,assets:e.assets||[],additionalEntryPoints:pe,port:d,serviceName:a,memoryLimit:e.memoryLimit||8192,buildLibsFromSource:e.buildLibsFromSource!==!1,workspaceRoot:n,orgScopes:e.orgScopes||[],bundlePackages:e.bundlePackages||[],nodeExternalsConfig:e.nodeExternalsConfig,webpackConfigPath:e.webpackConfigPath,httpsReload:e.gateway?.https===!0,...e.devtool!==void 0&&{devtool:e.devtool}};let l=null,U=!1,G=!1,B=!1,h=!1;const re=path.join(__dirname,"../../main.devserver.js"),te=path.join(__dirname,"../../main.devserver.ts"),W=!fs.existsSync(re)&&fs.existsSync(te),L=W?te:re,de=path.join(Q,"main.js");function H(){l&&!l.killed&&(l.kill("SIGTERM"),l=null)}i(H,"Q"),s(H,"cleanup");function R(){h=!0,H()}i(R,"W"),s(R,"stop");const he=(0,stop_on_signal_1.stopOnSignal)({stop:R,close:s(()=>b(),"close")});process.on("exit",R);function P(){if(h||U)return;if(!fs.existsSync(L)){console.error(`[serve] devserver script not found at ${L}`);return}const r=(0,child_process_env_1.childProcessEnv)({...process.env,PORT:String(d),SERVICE_NAME:a,SERVE_PREFIX:I,LENSMCP_PROJECT:process.env.LENSMCP_PROJECT||o.projectName||a,LENSMCP_EVENT_FILE:process.env.LENSMCP_EVENT_FILE||path.join(n,".lensmcp","events.jsonl"),CHILD_COUNT:String(e.childCount||process.env.CHILD_COUNT||1),BUNDLE_PATH:de,...M&&{GATEWAY_MIDDLEWARE:M},...F&&{GATEWAY_CONFIG:F},...e.gateway?.routes?.length&&{GATEWAY_ROUTES:JSON.stringify(e.gateway.routes)},...e.gateway?.https&&{GATEWAY_HTTPS:"1"},...e.gateway?.extraPorts?.length&&{GATEWAY_EXTRA_PORTS:JSON.stringify(e.gateway.extraPorts)},...e.internalPort&&{INTERNAL_PORT:String(e.internalPort)},...y&&{LENSMCP_DEBUG_PORT:String(y)},...g&&{LENSMCP_LOG_FILE:g},...e.workers?.length&&{WORKERS:(0,worker_supervisor_1.serializeWorkerSpecs)(e.workers)},[dev_devtool_1.DEV_SOURCE_MAPS_ENV]:B?"1":"0"});if((0,devserver_host_1.devserverInProcessOffered)()&&(!W||require.extensions[".ts"])){U=!0;for(const[u,f]of Object.entries(r))f!==void 0&&(process.env[u]=f);(0,devserver_host_1.markDevserverInProcess)(),require(L),J("in this process");return}const v=["--enable-source-maps"];W&&v.unshift("--require","@swc-node/register");const c=(0,node_child_process_1.fork)(L,{cwd:n,env:r,stdio:["inherit","inherit","inherit","ipc"],execArgv:v,execPath:(0,process_name_1.namedExecPath)((0,process_name_1.processName)(process.env.LENSMCP_WS_KEY||path.basename(n),a,"dev"))});l=c,c.on("exit",(u,f)=>{l===c&&(l=null),!(f||u===0||h)&&(console.error(`[serve] devserver exited unexpectedly (code=${u}, signal=${f}) \u2014 respawning in 1.5s`),setTimeout(()=>{!h&&!l&&G&&P()},1500).unref?.())}),J()}i(P,"j"),s(P,"startDevServer");function J(r){console.log(`[serve] Devserver started on port ${d} (service: ${a}${I?`, prefix: /${I}`:""}${r?`, ${r}`:""})`),y?(console.warn(`[serve] DEBUGGER ENABLED for ${a}. Node's inspector has NO authentication \u2014 the ws:// UUID is the whole credential, and any account on this host that obtains it runs code as you. Do not enable this on a shared machine.`),ce?console.warn(`[serve] LENSMCP_DEBUG_FIXED_PORTS=1 \u2014 pod inspectors bind PREDICTABLE ports 127.0.0.1:${y}+slot (workers ${y}+20+i), reachable by any account on this host. Attach WebStorm (Attach to Node.js/Chrome) to ${y}. Unset it to bind ephemeral ports instead.`):console.log(`[serve] Debug: pod inspectors bind an EPHEMERAL 127.0.0.1 port. Get the ws:// URLs with \`lensmcp debug ${a}\` (the owner-only control socket); a devserver run in your own terminal also prints them there. Set LENSMCP_DEBUG_FIXED_PORTS=1 if your IDE needs a fixed attach port.`)):console.log(`[serve] Debug on demand: \`lensmcp debug ${a}\` opens pod inspectors without a restart`),g&&console.log(`[serve] Logs teed to ${g} \u2014 tail it in WebStorm via Run/Debug configuration \u2192 Logs tab`)}i(J,"ee"),s(J,"announceDevServer");function fe(){if(!l||l.killed){console.log("[serve] Devserver not running, restarting..."),P();return}fetch(`http://localhost:${d}/webpack/reload`,{method:"POST",headers:{"content-type":"application/json"},body:"{}"}).then(()=>console.log("[serve] Notified devserver to reload")).catch(r=>{console.warn("[serve] Failed to notify devserver, restarting...",r.message),H(),P()})}i(fe,"me"),s(fe,"_notifyDevServerReload");let D=null;const V=[];function _(r){if(D){const v=D;D=null,v(r)}else V.push(r)}i(_,"w"),s(_,"pushResult");function se(){return V.length>0?Promise.resolve(V.shift()):new Promise(r=>{D=r})}i(se,"de"),s(se,"waitForNext");let b=s(()=>{},"closeBuild");function Y(){return!G||!l&&!U?(G=!0,P(),!0):!1}i(Y,"re"),s(Y,"builtOk");function X(){try{return JSON.stringify((0,signature_1.transpileCompilerOptions)(m.tsConfig,n))}catch{return}}i(X,"te"),s(X,"compileShape");function C(){if(h)return;const{createDevWebpackConfig:r}=require("../../create-webpack-dev"),v=require("webpack"),c=m.webpackConfigPath?path.resolve(m.appRoot,m.webpackConfigPath):void 0;if(c)try{delete require.cache[require.resolve(c)]}catch{}const u=r(m),{watch:f,...t}=u,z=(0,config_files_1.configFilesOf)(m),K=X(),{TsgoCheckPlugin:ge}=require("../../tsgo-check-plugin"),me=process.env.LENSMCP_TYPECHECK!=="off"&&!(t.plugins??[]).some(p=>p instanceof ge);let $,Z=!1;t.plugins=[...t.plugins??[],new config_files_1.ConfigFilesPlugin({files:s(()=>z,"files"),changed:s(p=>{let w=!1;if(!c||!p.includes(c)){const N=X();if(N===void 0)return;if(N===K){if(!me||p.every(k=>k===m.tsConfig))return;w=!0}}Z=($===void 0||Z)&&w,$=p.map(N=>path.relative(n,N)).sort().join(", ")},"changed")})];const T=v(t);B=(0,dev_devtool_1.bundleCarriesSourceMaps)(T.options.devtool);let E;const x=(0,compile_retry_1.createFailureRetry)(()=>{h||!E||(console.log(`[serve] ${o.projectName}: compiling again after the failure`),E.invalidate())}),ie=s((p,w)=>{if($!==void 0&&E&&!h){console.log(Z?`[serve] ${o.projectName}: ${$} changed what it type-checks with \u2014 fork-ts-checker reads that only when it starts, so a new compiler checks it`:`[serve] ${o.projectName}: ${$} changed what it compiles with \u2014 compiling again with a new compiler`),x.dispose();const k=E;E=void 0,setImmediate(()=>k.close(()=>C()));return}if(p){if(console.error("[serve] Webpack error:",p),E&&!h){const{delayMs:k,retry:Ee}=x.failed();console.log(`[serve] ${o.projectName}: compiling again in ${Math.round(k/1e3)} s (retry ${Ee}) \u2014 webpack does not after a failure like this`)}_({success:!1});return}x.succeeded();const N=w.hasErrors();if(console.info(w.toString({colors:!0,chunks:!1,assets:!0})),N){_({success:!1});return}Y(),_({success:!0,baseUrl:`http://localhost:${d}`})},"onBuild");if(frozen()){console.log(`[serve] ${o.projectName}: frozen \u2014 compiling once, no file watcher`),T.run((p,w)=>{ie(p,w),T.close(()=>{})});return}E=T.watch(u.watchOptions||{},ie),b=s(()=>{x.dispose(),E?.close(()=>{})},"closeBuild")}i(C,"L"),s(C,"compileOnItsOwn");function ne(r){const v=r.accepted.projects.filter(t=>t!==o.projectName);console.log(`[serve] ${o.projectName}: compiled by the workspace's shared compilation ${r.accepted.group.slice(0,8)}${v.length?` with ${v.join(", ")}`:""} \u2014 no webpack in this process`);const c=new devserver_notifier_1.DevserverNotifier(d,e.gateway?.https===!0,(0,devserver_notifier_1.devserverControlSock)(a)),u=(0,attach_1.createAttachedTypecheck)({appName:o.projectName,tsConfig:oe,workspaceRoot:n,memoryLimit:e.memoryLimit||8192});let f;b=s(()=>{r.close(),u.dispose()},"closeBuild"),r.listen(t=>{if(!h)switch(t.type){case"watch-run":c.watchRun(t.paths);return;case"watch-closed":c.degrade("watch closed");return;case"failed":console.error(`[serve] the shared compiler failed: ${t.message}`),c.failed(`the shared compiler failed: ${t.message}`),_({success:!1});return;case"refused":console.log(`[serve] ${o.projectName}: compiling on its own from now on \u2014 ${t.reason}`),b(),C();return;case"built":{if(console.info(t.text),B=t.sourceMaps,u.built(t),!t.ok){c.failed(),_({success:!1});return}const z=t.hash!==f;f=t.hash;const K=Y();c.built(z&&!K),_({success:!0,baseUrl:`http://localhost:${d}`});return}default:return}})}if(i(ne,"fe"),s(ne,"attachToSharedBuild"),(0,attach_1.sharedBuildOffered)()&&!frozen()){const r=await(0,attach_1.joinSharedBuild)({project:o.projectName,target:o.targetName??"serve-hmr",...o.configurationName?{configuration:o.configurationName}:{},options:m,targetOptions:{...e},env:definedEnv(process.env)});r.kind==="attached"?ne(r.session):(console.log(`[serve] ${o.projectName}: compiling on its own \u2014 ${r.reason}`),C())}else C();try{for(;;)yield await se()}finally{R(),b(),he()}}i(serveExecutor,"serveExecutor"),s(serveExecutor,"serveExecutor"),exports.default=serveExecutor,module.exports=serveExecutor,module.exports.default=serveExecutor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lensmcp/cluster",
3
- "version": "1.25.38",
3
+ "version": "1.25.40",
4
4
  "description": "Run your Nx workspace as a local production cluster: pods on unix sockets with true HMR, one https gateway with per-project domains, scale-from-zero, autoscale, idle-kill, local-CA TLS — observed by the LensMCP lens.",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",
@@ -58,9 +58,9 @@
58
58
  }
59
59
  },
60
60
  "dependencies": {
61
- "@lensmcp/core": "1.25.38",
62
- "@lensmcp/node-instrumentation": "1.25.38",
63
- "@lensmcp/nx-plugin": "1.25.38",
61
+ "@lensmcp/core": "1.25.40",
62
+ "@lensmcp/node-instrumentation": "1.25.40",
63
+ "@lensmcp/nx-plugin": "1.25.40",
64
64
  "fastify": "^5.8.5",
65
65
  "@fastify/reply-from": "^12.6.2",
66
66
  "@typescript/native-preview": "^7.0.0-dev.20260707.2",
@@ -112,7 +112,7 @@ export interface BarrelAnalysis {
112
112
  }
113
113
  /** Measure every (project, library) pair reached through a root barrel. */
114
114
  export declare function analyzeBarrelImports(input: BarrelAnalysisInput): BarrelAnalysis;
115
- /** Executor memory per compiled module, MB — the fit to FoodGuard's seven watchers (issues/open/pod-memory-05). */
115
+ /** Executor memory per compiled module, MB — the fit to FoodGuard's seven watchers (issues/closed/pod-memory-05). */
116
116
  export declare const EXECUTOR_MB_PER_MODULE = 0.374;
117
117
  /** A finding's text, evidence and cost — the payload a finding event carries. */
118
118
  export interface HeavyBarrelFindingText {
@@ -40,6 +40,8 @@ export interface AttachedTypecheckOptions {
40
40
  workspaceRoot: string;
41
41
  memoryLimit: number;
42
42
  env?: NodeJS.ProcessEnv;
43
+ /** How often the tsconfig chain is read for a change. Default `CONFIG_POLL_MS` (config-files.ts). */
44
+ configPollMs?: number;
43
45
  }
44
46
  /**
45
47
  * The checker `LENSMCP_TYPECHECK` asks for, run in THIS process for THIS service — what its own compiler used to
@@ -52,5 +54,12 @@ export interface AttachedTypecheckOptions {
52
54
  * the watcher's changed files and adds its program's files to what it watches. Its program lists only the
53
55
  * tsconfig's own files, so the build host's file list for this bundle (`files`) is watched too — a library
54
56
  * save re-checks every service that compiles it, as before.
57
+ *
58
+ * Either one also follows the tsconfig and every file it extends (issues/closed/foodguard-115). The checker read them
59
+ * when it started, and the build host follows them only for what it compiles: a `paths` change moves the service to
60
+ * a new compiler, and a type-check-only edit compiles nothing again. On a change, tsgo checks again (its shim is
61
+ * derived from the chain for every check) and fork-ts-checker is made again: it reads its configuration again only
62
+ * when its own tsconfig changes, never a file that one extends. The webpack override is not watched: no checker
63
+ * reads it.
55
64
  */
56
65
  export declare function createAttachedTypecheck(opts: AttachedTypecheckOptions): AttachedTypecheck;
@@ -1,3 +1,3 @@
1
- "use strict";var T=Object.defineProperty;var f=(e,t)=>T(e,"name",{value:t,configurable:!0});var _=Object.defineProperty,o=f((e,t)=>_(e,"name",{value:t,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.JOIN_TIMEOUT_MS=void 0,exports.sharedBuildOffered=sharedBuildOffered,exports.joinSharedBuild=joinSharedBuild,exports.createAttachedTypecheck=createAttachedTypecheck;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),fork_ts_check_reporter_1=require("../fork-ts-check-reporter"),tsgo_check_plugin_1=require("../tsgo-check-plugin"),protocol_1=require("./protocol");exports.JOIN_TIMEOUT_MS=12e4;function sharedBuildOffered(e=process.env,t=process){return e[protocol_1.SHARED_BUILD_ENV]==="1"&&typeof t.send=="function"}f(sharedBuildOffered,"sharedBuildOffered"),o(sharedBuildOffered,"sharedBuildOffered");function joinSharedBuild(e,t={}){const i=t.proc??process,c=t.timeoutMs??exports.JOIN_TIMEOUT_MS;return new Promise(n=>{const p=[];let d,s=!1;const u=o(r=>{if(!(0,protocol_1.isRunnerInbound)(r))return;const a=r.event;if(!s)return a.type==="refused"?l({kind:"refused",reason:a.reason}):a.type!=="accepted"?void 0:l({kind:"attached",session:m(a)});d?d(a):p.push(a)},"onMessage"),h=o(()=>{i.removeListener("message",u)},"close"),m=o(r=>({accepted:r,listen(a){d=a;for(const w of p.splice(0))a(w)},close:h}),"makeSession"),l=o(r=>{s||(s=!0,clearTimeout(k),r.kind==="refused"&&h(),n(r))},"finish"),k=setTimeout(()=>l({kind:"refused",reason:`the build host did not answer within ${Math.round(c/1e3)} s`}),c);k.unref?.(),i.on("message",u);const g={channel:protocol_1.SHARED_BUILD_CHANNEL,type:"join",join:e};try{i.send?.(g,void 0,void 0,r=>{r&&l({kind:"refused",reason:`could not reach the gateway (${r.message})`})})}catch(r){l({kind:"refused",reason:`could not reach the gateway (${r.message})`})}})}f(joinSharedBuild,"joinSharedBuild"),o(joinSharedBuild,"joinSharedBuild");function createAttachedTypecheck(e){const t=e.env??process.env,i=t.LENSMCP_TYPECHECK;if(i==="off")return{built:o(()=>{},"built"),dispose:o(()=>{},"dispose")};if(i==="tsgo"){if((0,tsgo_check_plugin_1.resolveTsgoBin)(e.workspaceRoot,t.LENSMCP_TSGO_BIN)){const n=new tsgo_check_plugin_1.TsgoCheckPlugin({appName:e.appName,tsConfig:e.tsConfig,workspaceRoot:e.workspaceRoot,...t.LENSMCP_TSGO_BIN?{binPath:t.LENSMCP_TSGO_BIN}:{}}),p=[];return n.apply({hooks:{done:{tap:o((d,s)=>p.push(s),"tap")}}}),{built:o(d=>{for(const s of p)s({hasErrors:o(()=>!d.ok,"hasErrors")})},"built"),dispose:o(()=>n.dispose(),"dispose")}}const c=`${tsgo_check_plugin_1.TSGO_MISSING_CAUSE}. Fell back to fork-ts-checker, which reports to the console only \u2014 so typecheck:// has no producer for this project until it is fixed`;console.warn(`[serve] ${e.appName}: LENSMCP_TYPECHECK=tsgo but ${c}.`),(0,tsgo_check_plugin_1.reportTsgoUnavailable)({appName:e.appName,tsConfig:e.tsConfig,workspaceRoot:e.workspaceRoot,detail:c})}return forkTsCheckerOnItsOwn(e)}f(createAttachedTypecheck,"createAttachedTypecheck"),o(createAttachedTypecheck,"createAttachedTypecheck");function forkTsCheckerOnItsOwn(e){const t=(0,fork_ts_check_reporter_1.loadForkTsChecker)(e.workspaceRoot),i=t?.default??t;if(typeof i!="function")return console.warn(`[serve] ${e.appName}: fork-ts-checker-webpack-plugin is not installed \u2014 this service is not type-checked`),{built:o(()=>{},"built"),dispose:o(()=>{},"dispose")};let c=[],n,p=!1;const d=o(()=>{n=require("webpack")({mode:"development",context:e.workspaceRoot,entry:{},infrastructureLogging:{level:"info"},plugins:[{apply(s){s.hooks.afterCompile.tapPromise("LensmcpAttachedTypecheck",()=>new Promise(u=>setTimeout(u,0))),s.hooks.afterCompile.tap("LensmcpAttachedTypecheck",u=>{for(const h of c)u.fileDependencies.add(h)})}},new i({async:!0,typescript:{configFile:e.tsConfig,memoryLimit:e.memoryLimit}}),new fork_ts_check_reporter_1.ForkTsCheckReporterPlugin({appName:e.appName,tsConfig:e.tsConfig,workspaceRoot:e.workspaceRoot})]}).watch({ignored:["**/node_modules/**",`${path.join(e.workspaceRoot,"dist")}/**`]},()=>{})},"start");return{built(s){if(p)return;const u=s.files&&s.files.join(`
2
- `)!==c.join(`
3
- `);s.files&&(c=[...s.files]),n?u&&n.invalidate():d()},dispose(){p=!0;try{n?.close(()=>{})}catch{}n=void 0}}}f(forkTsCheckerOnItsOwn,"forkTsCheckerOnItsOwn"),o(forkTsCheckerOnItsOwn,"forkTsCheckerOnItsOwn");
1
+ "use strict";var y=Object.defineProperty;var k=(e,t)=>y(e,"name",{value:t,configurable:!0});var _=Object.defineProperty,o=k((e,t)=>_(e,"name",{value:t,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.JOIN_TIMEOUT_MS=void 0,exports.sharedBuildOffered=sharedBuildOffered,exports.joinSharedBuild=joinSharedBuild,exports.createAttachedTypecheck=createAttachedTypecheck;const tslib_1=require("tslib"),path=tslib_1.__importStar(require("node:path")),config_files_1=require("../config-files"),fork_ts_check_reporter_1=require("../fork-ts-check-reporter"),tsgo_check_plugin_1=require("../tsgo-check-plugin"),protocol_1=require("./protocol");exports.JOIN_TIMEOUT_MS=12e4;function sharedBuildOffered(e=process.env,t=process){return e[protocol_1.SHARED_BUILD_ENV]==="1"&&typeof t.send=="function"}k(sharedBuildOffered,"sharedBuildOffered"),o(sharedBuildOffered,"sharedBuildOffered");function joinSharedBuild(e,t={}){const c=t.proc??process,r=t.timeoutMs??exports.JOIN_TIMEOUT_MS;return new Promise(n=>{const p=[];let l,f=!1;const a=o(i=>{if(!(0,protocol_1.isRunnerInbound)(i))return;const d=i.event;if(!f)return d.type==="refused"?h({kind:"refused",reason:d.reason}):d.type!=="accepted"?void 0:h({kind:"attached",session:u(d)});l?l(d):p.push(d)},"onMessage"),s=o(()=>{c.removeListener("message",a)},"close"),u=o(i=>({accepted:i,listen(d){l=d;for(const w of p.splice(0))d(w)},close:s}),"makeSession"),h=o(i=>{f||(f=!0,clearTimeout(g),i.kind==="refused"&&s(),n(i))},"finish"),g=setTimeout(()=>h({kind:"refused",reason:`the build host did not answer within ${Math.round(r/1e3)} s`}),r);g.unref?.(),c.on("message",a);const m={channel:protocol_1.SHARED_BUILD_CHANNEL,type:"join",join:e};try{c.send?.(m,void 0,void 0,i=>{i&&h({kind:"refused",reason:`could not reach the gateway (${i.message})`})})}catch(i){h({kind:"refused",reason:`could not reach the gateway (${i.message})`})}})}k(joinSharedBuild,"joinSharedBuild"),o(joinSharedBuild,"joinSharedBuild");function createAttachedTypecheck(e){const t=e.env??process.env,c=t.LENSMCP_TYPECHECK;if(c==="off")return{built:o(()=>{},"built"),dispose:o(()=>{},"dispose")};if(c==="tsgo"){if((0,tsgo_check_plugin_1.resolveTsgoBin)(e.workspaceRoot,t.LENSMCP_TSGO_BIN)){const n=new tsgo_check_plugin_1.TsgoCheckPlugin({appName:e.appName,tsConfig:e.tsConfig,workspaceRoot:e.workspaceRoot,...t.LENSMCP_TSGO_BIN?{binPath:t.LENSMCP_TSGO_BIN}:{}}),p=[];n.apply({hooks:{done:{tap:o((a,s)=>p.push(s),"tap")}}});let l;const f=watchTypecheckConfig(e,a=>{l&&(console.log(`[serve] ${e.appName}: ${a} changed \u2014 type-checking again`),n.schedule())});return{built:o(a=>{l=a.ok;for(const s of p)s({hasErrors:o(()=>!a.ok,"hasErrors")})},"built"),dispose:o(()=>{f.close(),n.dispose()},"dispose")}}const r=`${tsgo_check_plugin_1.TSGO_MISSING_CAUSE}. Fell back to fork-ts-checker, which reports to the console only \u2014 so typecheck:// has no producer for this project until it is fixed`;console.warn(`[serve] ${e.appName}: LENSMCP_TYPECHECK=tsgo but ${r}.`),(0,tsgo_check_plugin_1.reportTsgoUnavailable)({appName:e.appName,tsConfig:e.tsConfig,workspaceRoot:e.workspaceRoot,detail:r})}return forkTsCheckerOnItsOwn(e)}k(createAttachedTypecheck,"createAttachedTypecheck"),o(createAttachedTypecheck,"createAttachedTypecheck");function forkTsCheckerOnItsOwn(e){const t=(0,fork_ts_check_reporter_1.loadForkTsChecker)(e.workspaceRoot),c=t?.default??t;if(typeof c!="function")return console.warn(`[serve] ${e.appName}: fork-ts-checker-webpack-plugin is not installed \u2014 this service is not type-checked`),{built:o(()=>{},"built"),dispose:o(()=>{},"dispose")};let r=[],n,p=!1;const l=o(()=>{try{n?.close(()=>{})}catch{}n=void 0},"close"),f=watchTypecheckConfig(e,s=>{p||!n||(console.log(`[serve] ${e.appName}: ${s} changed \u2014 type-checking again with a new fork-ts-checker`),l(),a())}),a=o(()=>{n=require("webpack")({mode:"development",context:e.workspaceRoot,entry:{},infrastructureLogging:{level:"info"},plugins:[{apply(s){s.hooks.afterCompile.tapPromise("LensmcpAttachedTypecheck",()=>new Promise(u=>setTimeout(u,0))),s.hooks.afterCompile.tap("LensmcpAttachedTypecheck",u=>{for(const h of r)u.fileDependencies.add(h)})}},new c({async:!0,typescript:{configFile:e.tsConfig,memoryLimit:e.memoryLimit}}),new fork_ts_check_reporter_1.ForkTsCheckReporterPlugin({appName:e.appName,tsConfig:e.tsConfig,workspaceRoot:e.workspaceRoot})]}).watch({ignored:["**/node_modules/**",`${path.join(e.workspaceRoot,"dist")}/**`]},()=>{})},"start");return{built(s){if(p)return;const u=s.files&&s.files.join(`
2
+ `)!==r.join(`
3
+ `);s.files&&(r=[...s.files]),n?u&&n.invalidate():a()},dispose(){p=!0,f.close(),l()}}}k(forkTsCheckerOnItsOwn,"forkTsCheckerOnItsOwn"),o(forkTsCheckerOnItsOwn,"forkTsCheckerOnItsOwn");function watchTypecheckConfig(e,t){return(0,config_files_1.watchConfigFiles)({files:o(()=>(0,tsgo_check_plugin_1.tsconfigChain)(e.tsConfig),"files"),changed:o(c=>t(c.map(r=>path.relative(e.workspaceRoot,r)||r).join(", ")),"changed"),...e.configPollMs!==void 0?{intervalMs:e.configPollMs}:{}})}k(watchTypecheckConfig,"watchTypecheckConfig"),o(watchTypecheckConfig,"watchTypecheckConfig");
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The shared compiler (issues/open/pod-memory-05): ONE webpack compilation for every service of a workspace
2
+ * The shared compiler (issues/closed/pod-memory-05): ONE webpack compilation for every service of a workspace
3
3
  * instead of one watcher per service. Three processes talk:
4
4
  *
5
5
  * runner (the serve executor, ATTACHED) ⇄ gateway (relay) ⇄ build host (one per workspace)
@@ -168,6 +168,21 @@ export declare function effectivePaths(tsConfig: string, seen?: Set<string>): {
168
168
  paths: Record<string, string[]>;
169
169
  anchorDir: string;
170
170
  } | null;
171
+ /**
172
+ * The tsconfig and every file it extends, as {@link effectivePaths} walks them — what a check's configuration is read
173
+ * from (issues/closed/foodguard-115). The tsconfig itself is always listed, even when it cannot be read: a half-saved
174
+ * file is watched until the next save. A file extended from node_modules changes only with an install, and is left
175
+ * out, as `configFilesOf` leaves it out. Read with this file's own parser, so a service that type-checks with tsgo
176
+ * never loads TypeScript into its process just to list its config files.
177
+ */
178
+ export declare function tsconfigChain(tsConfig: string): string[];
179
+ /**
180
+ * Write the shim for one check, and return its path. Called before EVERY check (issues/closed/foodguard-115): the
181
+ * shim's `paths` REPLACE the ones the tsconfig chain declares, so they are the one part of the configuration tsgo
182
+ * does not read for itself. Written once, a shim kept the aliases the chain had when the service started: FoodGuard
183
+ * added `@foodguard-shared/execution-graph` to `tsconfig.base.json`, the bundle built with it, and every check for
184
+ * the next 80 minutes still reported «TS2307: Cannot find module». The file is left alone when it would not change.
185
+ */
171
186
  export declare function writeShimTsconfig(appName: string, tsConfig: string, workspaceRoot: string): string;
172
187
  export declare class TsgoCheckPlugin {
173
188
  private readonly opts;
@@ -1,5 +1,5 @@
1
- "use strict";var v=Object.defineProperty;var a=(e,t)=>v(e,"name",{value:t,configurable:!0});var b=Object.defineProperty,l=a((e,t)=>b(e,"name",{value:t,configurable:!0}),"l");Object.defineProperty(exports,"__esModule",{value:!0}),exports.TsgoCheckPlugin=exports.TSGO_MISSING_CAUSE=exports.TSGO_PACKAGE=void 0,exports.checkerMaxProcs=checkerMaxProcs,exports.tsgoIncremental=tsgoIncremental,exports.tsgoBuildInfoPath=tsgoBuildInfoPath,exports.tsgoCheckArgs=tsgoCheckArgs,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}a(checkerMaxProcs,"checkerMaxProcs"),l(checkerMaxProcs,"checkerMaxProcs");function tsgoIncremental(e=process.env){const t=(e.LENSMCP_TSGO_INCREMENTAL??"").trim().toLowerCase();return!(t==="0"||t==="false"||t==="off"||t==="no")}a(tsgoIncremental,"tsgoIncremental"),l(tsgoIncremental,"tsgoIncremental");function tsgoBuildInfoPath(e,t){return path.join(t,"tmp","lensmcp-tsgo",`${e}.tsbuildinfo`)}a(tsgoBuildInfoPath,"tsgoBuildInfoPath"),l(tsgoBuildInfoPath,"tsgoBuildInfoPath");function tsgoCheckArgs(e,t){return["--noEmit","--pretty","false",...t?["--incremental","--tsBuildInfoFile",t]:[],"-p",e]}a(tsgoCheckArgs,"tsgoCheckArgs"),l(tsgoCheckArgs,"tsgoCheckArgs");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()}))}a(stopWithTheProcess,"stopWithTheProcess"),l(stopWithTheProcess,"stopWithTheProcess"),exports.TSGO_PACKAGE="@typescript/native-preview";function shimNames(e){return e==="win32"?["tsgo.cmd","tsgo.exe"]:["tsgo"]}a(shimNames,"shimNames"),l(shimNames,"shimNames");function isExecutableFile(e,t){try{if(!fs.statSync(e).isFile())return!1}catch{return!1}if(t==="win32")return!0;try{return fs.accessSync(e,fs.constants.X_OK),!0}catch{return!1}}a(isExecutableFile,"isExecutableFile"),l(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:s}=JSON.parse(fs.readFileSync(i,"utf8"));if(s===exports.TSGO_PACKAGE)return e}catch{}const n=path.dirname(e);if(n===e)break;e=n}}catch{}return null}a(resolveTsgoPackageDir,"resolveTsgoPackageDir"),l(resolveTsgoPackageDir,"resolveTsgoPackageDir");function packageDeclaredBin(e){try{const{bin:t}=JSON.parse(fs.readFileSync(path.join(e,"package.json"),"utf8")),i=typeof t=="string"?t:t?.tsgo;return i?path.join(e,i):null}catch{return null}}a(packageDeclaredBin,"packageDeclaredBin"),l(packageDeclaredBin,"packageDeclaredBin");function ownBinCandidates(e,t){const i=path.resolve(e,"..","..",".bin"),n=shimNames(t).map(o=>path.join(i,o)),s=t==="win32"?null:packageDeclaredBin(e);return s?[s,...n]:n}a(ownBinCandidates,"ownBinCandidates"),l(ownBinCandidates,"ownBinCandidates");function resolveTsgoBin(e,t,i={}){const n=i.platform??process.platform,s=i.isExecutable??(r=>isExecutableFile(r,n));if(t)return s(t)?t:null;for(const r of shimNames(n)){const c=path.join(e,"node_modules",".bin",r);if(s(c))return c}const o=(i.ownPackageDir??resolveTsgoPackageDir)();return o?ownBinCandidates(o,n).find(s)??null:null}a(resolveTsgoBin,"resolveTsgoBin"),l(resolveTsgoBin,"resolveTsgoBin"),exports.TSGO_MISSING_CAUSE=`tsgo binary not found \u2014 @lensmcp/cluster depends on ${exports.TSGO_PACKAGE}, so an absent binary means an incomplete install (reinstall node_modules), a platform with no ${exports.TSGO_PACKAGE} build, or a LENSMCP_TSGO_BIN override pointing at a missing or non-executable file`;function reportTsgoUnavailable(e){try{(0,typecheck_bus_1.publishTypecheckRun)({workspaceRoot:e.workspaceRoot,project:e.appName,tool:"tsgo",tsConfig:e.tsConfig,output:"",durationMs:0,toolError:e.detail,...e.eventFile?{eventFile:e.eventFile}:{}})}catch{}}a(reportTsgoUnavailable,"reportTsgoUnavailable"),l(reportTsgoUnavailable,"reportTsgoUnavailable");function parseJsonc(e){let t="",i=!1,n=!1,s=!1;for(let o=0;o<e.length;o++){const r=e[o],c=e[o+1];if(n){r===`
2
- `&&(n=!1,t+=r);continue}if(s){r==="*"&&c==="/"&&(s=!1,o++);continue}if(i){t+=r,r==="\\"?(t+=c??"",o++):r==='"'&&(i=!1);continue}if(r==='"'){i=!0,t+=r;continue}if(r==="/"&&c==="/"){n=!0,o++;continue}if(r==="/"&&c==="*"){s=!0,o++;continue}t+=r}try{return JSON.parse(t.replace(/,(\s*[}\]])/g,"$1"))}catch{return null}}a(parseJsonc,"parseJsonc"),l(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 n of[i,`${i}.json`,path.join(i,"tsconfig.json")])try{if(fs.statSync(n).isFile())return n}catch{}return null}a(resolveExtends,"resolveExtends"),l(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 n=parseJsonc(i);if(!n)return null;const s=path.dirname(e),o=n.compilerOptions??{},r=Array.isArray(n.extends)?n.extends.filter(p=>typeof p=="string"):typeof n.extends=="string"?[n.extends]:[],c=l(()=>{for(const p of[...r].reverse()){const d=resolveExtends(p,s);if(!d)continue;const f=effectivePaths(d,t);if(f)return f}return null},"inherited"),u=o.paths,h=typeof o.baseUrl=="string"?path.resolve(s,o.baseUrl):void 0;if(!u){const p=c();return p?{paths:p.paths,anchorDir:h??p.anchorDir}:null}return{paths:u,anchorDir:h??c()?.anchorDir??s}}a(effectivePaths,"effectivePaths"),l(effectivePaths,"effectivePaths");function writeShimTsconfig(e,t,i){const n=path.join(i,"tmp","lensmcp-tsgo");fs.mkdirSync(n,{recursive:!0});const s=path.join(n,`${e}.tsconfig.json`),o=effectivePaths(t),r=o?Object.fromEntries(Object.entries(o.paths).map(([c,u])=>[c,(Array.isArray(u)?u:[]).map(h=>path.isAbsolute(h)?h:path.resolve(o.anchorDir,h))])):void 0;return fs.writeFileSync(s,JSON.stringify({extends:t,compilerOptions:{module:"preserve",moduleResolution:"bundler",isolatedModules:!1,baseUrl:null,...r&&Object.keys(r).length?{paths:r}:{}}},null,2)),s}a(writeShimTsconfig,"writeShimTsconfig"),l(writeShimTsconfig,"writeShimTsconfig");class TsgoCheckPlugin{static{a(this,"TsgoCheckPlugin")}static{l(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)(),this.buildInfo=t.incremental??tsgoIncremental()?tsgoBuildInfoPath(t.appName,t.workspaceRoot):void 0}apply(t){t.hooks.done.tap("TsgoCheckPlugin",i=>{i.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(),{onHold:l(i=>this.held(i),"onHold")});this.isIdle()?t.release():this.ticket=t}held(t){if(!this.disposed&&(console.log(`[tsgo] ${this.opts.appName}: check held \u2014 ${t.availableMb} MB free, it waits for ${t.minFreeMb} MB (LENSMCP_TYPECHECK_MIN_FREE_MB)`),this.opts.publishEvents!==!1))try{(0,typecheck_bus_1.publishTypecheckHeld)({workspaceRoot:this.opts.workspaceRoot,project:this.opts.appName,tool:"tsgo",tsConfig:this.opts.tsConfig,availableMb:t.availableMb,minFreeMb:t.minFreeMb,...this.opts.eventFile?{eventFile:this.opts.eventFile}:{}})}catch{}}forgetBuildInfo(){if(this.buildInfo)try{fs.rmSync(this.buildInfo,{force:!0})}catch{}}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(h){return console.warn(`[tsgo] ${this.opts.appName}: could not prepare the check \u2014 ${h.message}`),this.publish({output:"",durationMs:0,toolError:`could not prepare the check: ${h.message}`}),this.leave()}if(!t){this.disabled=!0;const h=`${exports.TSGO_MISSING_CAUSE}. Type checking is disabled for the rest of this session`;return console.warn(`[tsgo] ${this.opts.appName}: ${h}.`),this.publish({output:"",durationMs:0,toolError:h}),this.leave()}this.phase="running",this.dirty=!1;const i=Date.now(),n=i-this.askedAt,s=this.spawnImpl(t,tsgoCheckArgs(this.shimPath,this.buildInfo),{cwd:this.opts.workspaceRoot,stdio:["ignore","pipe","pipe"],env:{...process.env,GOMAXPROCS:process.env.GOMAXPROCS??String(this.opts.maxProcs??checkerMaxProcs())}});this.inflight=s;let o="",r=!1;const c=this.opts.timeoutMs??DEFAULT_TIMEOUT_MS,u=setTimeout(()=>{r=!0,s.kill("SIGKILL")},c);u.unref?.(),s.stdout?.on("data",h=>{o+=h.toString()}),s.stderr?.on("data",h=>{o+=h.toString()}),s.on("error",()=>{clearTimeout(u),this.inflight===s&&(console.warn(`[tsgo] ${this.opts.appName}: failed to spawn ${t}`),this.forgetBuildInfo(),this.publish({output:"",durationMs:Date.now()-i,toolError:`failed to spawn ${t}`}),this.finish(s))}),s.on("close",(h,p)=>{if(clearTimeout(u),this.inflight!==s)return;const d=Date.now()-i,f=(d/1e3).toFixed(1),m=n>=1e3?`${f}s, waited ${(n/1e3).toFixed(1)}s`:`${f}s`;if(this.disposed)return this.finish(s);if(r){const k=`the check was killed after ${Math.round(c/1e3)}s without finishing`;return console.warn(`[tsgo] ${this.opts.appName}: ${k} \u2014 no verdict.`),this.forgetBuildInfo(),this.publish({output:"",durationMs:d,toolError:k}),this.finish(s)}if(p)return this.forgetBuildInfo(),this.finish(s);if(h===0)return console.log(`[tsgo] ${this.opts.appName}: types clean (${m})`),this.publish({output:"",durationMs:d}),this.finish(s);o.trim()&&process.stdout.write(o.endsWith(`
3
- `)?o:`${o}
4
- `);const g=(o.match(/error TS\d+/g)??[]).length;console.log(`[tsgo] ${this.opts.appName}: ${g} type error${g===1?"":"s"} (${m})`),g===0&&this.forgetBuildInfo(),this.publish({output:o,durationMs:d,...g===0?{toolError:`tsgo exited ${h} with no diagnostics: ${firstLine(o)}`}:{}}),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&&(this.inflight.kill("SIGKILL"),this.forgetBuildInfo()),this.ticket?.release(),this.ticket=null)}}exports.TsgoCheckPlugin=TsgoCheckPlugin;function firstLine(e){return e.trim().split(`
1
+ "use strict";var k=Object.defineProperty;var a=(e,t)=>k(e,"name",{value:t,configurable:!0});var b=Object.defineProperty,l=a((e,t)=>b(e,"name",{value:t,configurable:!0}),"l");Object.defineProperty(exports,"__esModule",{value:!0}),exports.TsgoCheckPlugin=exports.TSGO_MISSING_CAUSE=exports.TSGO_PACKAGE=void 0,exports.checkerMaxProcs=checkerMaxProcs,exports.tsgoIncremental=tsgoIncremental,exports.tsgoBuildInfoPath=tsgoBuildInfoPath,exports.tsgoCheckArgs=tsgoCheckArgs,exports.resolveTsgoPackageDir=resolveTsgoPackageDir,exports.resolveTsgoBin=resolveTsgoBin,exports.reportTsgoUnavailable=reportTsgoUnavailable,exports.effectivePaths=effectivePaths,exports.tsconfigChain=tsconfigChain,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}a(checkerMaxProcs,"checkerMaxProcs"),l(checkerMaxProcs,"checkerMaxProcs");function tsgoIncremental(e=process.env){const t=(e.LENSMCP_TSGO_INCREMENTAL??"").trim().toLowerCase();return!(t==="0"||t==="false"||t==="off"||t==="no")}a(tsgoIncremental,"tsgoIncremental"),l(tsgoIncremental,"tsgoIncremental");function tsgoBuildInfoPath(e,t){return path.join(t,"tmp","lensmcp-tsgo",`${e}.tsbuildinfo`)}a(tsgoBuildInfoPath,"tsgoBuildInfoPath"),l(tsgoBuildInfoPath,"tsgoBuildInfoPath");function tsgoCheckArgs(e,t){return["--noEmit","--pretty","false",...t?["--incremental","--tsBuildInfoFile",t]:[],"-p",e]}a(tsgoCheckArgs,"tsgoCheckArgs"),l(tsgoCheckArgs,"tsgoCheckArgs");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()}))}a(stopWithTheProcess,"stopWithTheProcess"),l(stopWithTheProcess,"stopWithTheProcess"),exports.TSGO_PACKAGE="@typescript/native-preview";function shimNames(e){return e==="win32"?["tsgo.cmd","tsgo.exe"]:["tsgo"]}a(shimNames,"shimNames"),l(shimNames,"shimNames");function isExecutableFile(e,t){try{if(!fs.statSync(e).isFile())return!1}catch{return!1}if(t==="win32")return!0;try{return fs.accessSync(e,fs.constants.X_OK),!0}catch{return!1}}a(isExecutableFile,"isExecutableFile"),l(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 n=path.dirname(e);if(n===e)break;e=n}}catch{}return null}a(resolveTsgoPackageDir,"resolveTsgoPackageDir"),l(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}}a(packageDeclaredBin,"packageDeclaredBin"),l(packageDeclaredBin,"packageDeclaredBin");function ownBinCandidates(e,t){const o=path.resolve(e,"..","..",".bin"),n=shimNames(t).map(i=>path.join(o,i)),s=t==="win32"?null:packageDeclaredBin(e);return s?[s,...n]:n}a(ownBinCandidates,"ownBinCandidates"),l(ownBinCandidates,"ownBinCandidates");function resolveTsgoBin(e,t,o={}){const n=o.platform??process.platform,s=o.isExecutable??(r=>isExecutableFile(r,n));if(t)return s(t)?t:null;for(const r of shimNames(n)){const c=path.join(e,"node_modules",".bin",r);if(s(c))return c}const i=(o.ownPackageDir??resolveTsgoPackageDir)();return i?ownBinCandidates(i,n).find(s)??null:null}a(resolveTsgoBin,"resolveTsgoBin"),l(resolveTsgoBin,"resolveTsgoBin"),exports.TSGO_MISSING_CAUSE=`tsgo binary not found \u2014 @lensmcp/cluster depends on ${exports.TSGO_PACKAGE}, so an absent binary means an incomplete install (reinstall node_modules), a platform with no ${exports.TSGO_PACKAGE} build, or a LENSMCP_TSGO_BIN override pointing at a missing or non-executable file`;function reportTsgoUnavailable(e){try{(0,typecheck_bus_1.publishTypecheckRun)({workspaceRoot:e.workspaceRoot,project:e.appName,tool:"tsgo",tsConfig:e.tsConfig,output:"",durationMs:0,toolError:e.detail,...e.eventFile?{eventFile:e.eventFile}:{}})}catch{}}a(reportTsgoUnavailable,"reportTsgoUnavailable"),l(reportTsgoUnavailable,"reportTsgoUnavailable");function parseJsonc(e){let t="",o=!1,n=!1,s=!1;for(let i=0;i<e.length;i++){const r=e[i],c=e[i+1];if(n){r===`
2
+ `&&(n=!1,t+=r);continue}if(s){r==="*"&&c==="/"&&(s=!1,i++);continue}if(o){t+=r,r==="\\"?(t+=c??"",i++):r==='"'&&(o=!1);continue}if(r==='"'){o=!0,t+=r;continue}if(r==="/"&&c==="/"){n=!0,i++;continue}if(r==="/"&&c==="*"){s=!0,i++;continue}t+=r}try{return JSON.parse(t.replace(/,(\s*[}\]])/g,"$1"))}catch{return null}}a(parseJsonc,"parseJsonc"),l(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 n of[o,`${o}.json`,path.join(o,"tsconfig.json")])try{if(fs.statSync(n).isFile())return n}catch{}return null}a(resolveExtends,"resolveExtends"),l(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 n=parseJsonc(o);if(!n)return null;const s=path.dirname(e),i=n.compilerOptions??{},r=Array.isArray(n.extends)?n.extends.filter(p=>typeof p=="string"):typeof n.extends=="string"?[n.extends]:[],c=l(()=>{for(const p of[...r].reverse()){const d=resolveExtends(p,s);if(!d)continue;const f=effectivePaths(d,t);if(f)return f}return null},"inherited"),u=i.paths,h=typeof i.baseUrl=="string"?path.resolve(s,i.baseUrl):void 0;if(!u){const p=c();return p?{paths:p.paths,anchorDir:h??p.anchorDir}:null}return{paths:u,anchorDir:h??c()?.anchorDir??s}}a(effectivePaths,"effectivePaths"),l(effectivePaths,"effectivePaths");function tsconfigChain(e){const t=[],o=l(n=>{if(t.includes(n))return;t.push(n);let s;try{s=parseJsonc(fs.readFileSync(n,"utf8"))}catch{return}const i=s?.extends,r=Array.isArray(i)?i.filter(c=>typeof c=="string"):typeof i=="string"?[i]:[];for(const c of r){const u=resolveExtends(c,path.dirname(n));u&&!u.split(path.sep).includes("node_modules")&&o(u)}},"visit");return o(path.resolve(e)),t}a(tsconfigChain,"tsconfigChain"),l(tsconfigChain,"tsconfigChain");function writeShimTsconfig(e,t,o){const n=path.join(o,"tmp","lensmcp-tsgo");fs.mkdirSync(n,{recursive:!0});const s=path.join(n,`${e}.tsconfig.json`),i=effectivePaths(t),r=i?Object.fromEntries(Object.entries(i.paths).map(([h,p])=>[h,(Array.isArray(p)?p:[]).map(d=>path.isAbsolute(d)?d:path.resolve(i.anchorDir,d))])):void 0,c=JSON.stringify({extends:t,compilerOptions:{module:"preserve",moduleResolution:"bundler",isolatedModules:!1,baseUrl:null,...r&&Object.keys(r).length?{paths:r}:{}}},null,2);let u;try{u=fs.readFileSync(s,"utf8")}catch{}return u!==c&&fs.writeFileSync(s,c),s}a(writeShimTsconfig,"writeShimTsconfig"),l(writeShimTsconfig,"writeShimTsconfig");class TsgoCheckPlugin{static{a(this,"TsgoCheckPlugin")}static{l(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)(),this.buildInfo=t.incremental??tsgoIncremental()?tsgoBuildInfoPath(t.appName,t.workspaceRoot):void 0}apply(t){t.hooks.done.tap("TsgoCheckPlugin",o=>{o.hasErrors()||this.schedule()}),t.hooks.shutdown?.tap?.("TsgoCheckPlugin",()=>this.dispose()),t.hooks.watchClose?.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(),{onHold:l(o=>this.held(o),"onHold")});this.isIdle()?t.release():this.ticket=t}held(t){if(!this.disposed&&(console.log(`[tsgo] ${this.opts.appName}: check held \u2014 ${t.availableMb} MB free, it waits for ${t.minFreeMb} MB (LENSMCP_TYPECHECK_MIN_FREE_MB)`),this.opts.publishEvents!==!1))try{(0,typecheck_bus_1.publishTypecheckHeld)({workspaceRoot:this.opts.workspaceRoot,project:this.opts.appName,tool:"tsgo",tsConfig:this.opts.tsConfig,availableMb:t.availableMb,minFreeMb:t.minFreeMb,...this.opts.eventFile?{eventFile:this.opts.eventFile}:{}})}catch{}}forgetBuildInfo(){if(this.buildInfo)try{fs.rmSync(this.buildInfo,{force:!0})}catch{}}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=writeShimTsconfig(this.opts.appName,this.opts.tsConfig,this.opts.workspaceRoot))}catch(h){return console.warn(`[tsgo] ${this.opts.appName}: could not prepare the check \u2014 ${h.message}`),this.publish({output:"",durationMs:0,toolError:`could not prepare the check: ${h.message}`}),this.leave()}if(!t){this.disabled=!0;const h=`${exports.TSGO_MISSING_CAUSE}. Type checking is disabled for the rest of this session`;return console.warn(`[tsgo] ${this.opts.appName}: ${h}.`),this.publish({output:"",durationMs:0,toolError:h}),this.leave()}this.phase="running",this.dirty=!1;const o=Date.now(),n=o-this.askedAt,s=this.spawnImpl(t,tsgoCheckArgs(this.shimPath,this.buildInfo),{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="",r=!1;const c=this.opts.timeoutMs??DEFAULT_TIMEOUT_MS,u=setTimeout(()=>{r=!0,s.kill("SIGKILL")},c);u.unref?.(),s.stdout?.on("data",h=>{i+=h.toString()}),s.stderr?.on("data",h=>{i+=h.toString()}),s.on("error",()=>{clearTimeout(u),this.inflight===s&&(console.warn(`[tsgo] ${this.opts.appName}: failed to spawn ${t}`),this.forgetBuildInfo(),this.publish({output:"",durationMs:Date.now()-o,toolError:`failed to spawn ${t}`}),this.finish(s))}),s.on("close",(h,p)=>{if(clearTimeout(u),this.inflight!==s)return;const d=Date.now()-o,f=(d/1e3).toFixed(1),m=n>=1e3?`${f}s, waited ${(n/1e3).toFixed(1)}s`:`${f}s`;if(this.disposed)return this.finish(s);if(r){const y=`the check was killed after ${Math.round(c/1e3)}s without finishing`;return console.warn(`[tsgo] ${this.opts.appName}: ${y} \u2014 no verdict.`),this.forgetBuildInfo(),this.publish({output:"",durationMs:d,toolError:y}),this.finish(s)}if(p)return this.forgetBuildInfo(),this.finish(s);if(h===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})`),g===0&&this.forgetBuildInfo(),this.publish({output:i,durationMs:d,...g===0?{toolError:`tsgo exited ${h} 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&&(this.inflight.kill("SIGKILL"),this.forgetBuildInfo()),this.ticket?.release(),this.ticket=null)}}exports.TsgoCheckPlugin=TsgoCheckPlugin;function firstLine(e){return e.trim().split(`
5
5
  `)[0]?.slice(0,300)??""}a(firstLine,"firstLine"),l(firstLine,"firstLine");