lensmcp 1.25.21 → 1.25.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var js=Object.defineProperty;var p=(t,n)=>js(t,"name",{value:n,configurable:!0});var Ns=Object.defineProperty,l=p((t,n)=>Ns(t,"name",{value:n,configurable:!0}),"d");import{spawn as Ps,spawnSync as A}from"node:child_process";import{existsSync as E,mkdirSync as ee,readFileSync as B,readdirSync as be,realpathSync as Es,rmSync as Ms,statSync as qe,writeFileSync as X}from"node:fs";import{request as ze}from"node:http";import{homedir as Ts,tmpdir as Ls}from"node:os";import{basename as pe,dirname as D,isAbsolute as Rs,join as w,relative as Ye,resolve as T}from"node:path";import{fileURLToPath as Xe,pathToFileURL as Os}from"node:url";import{ensureLensConfig as Z,isInstanceConfig as Ce,podNamespace as he,readLensConfig as J}from"./workspace-scope.js";import{commandUsage as As,onOutputBroken as _s,wantsHelp as Is}from"./cli-help.js";import{logsFollow as Ds}from"./logs-follow.js";import{splitLintArgs as Fs}from"./lint-args.js";import{decideRecycle as Gs,hashConfig as Ks}from"./recycle-policy.js";import{planMcpRestart as Se}from"./mcp-restart.js";import{detectDuplicateRegistration as Bs,disabledMcpServers as Ze,mcpServerNames as Qe,pluginEnabledInSettings as et}from"./duplicate-registration.js";import{readTrackedPid as Vs,stillSameProcess as Hs,writeTrackedPid as tt}from"./process-identity.js";import{clusterPageHosts as Ws,readClusterPageDecls as Us,withBridgeAllowedOrigins as Js}from"./bridge-origins.js";import{runForwardingSignals as xe}from"./forward-signals.js";import{liveMcpSessions as qs,registerMcpSession as zs}from"./mcp-sessions.js";import{dashboardLoginUrl as ge}from"./dashboard-login.js";import{recordAsked as Ys}from"./agent-asked.js";import{remember as Xs,shouldAnnounce as Zs}from"./hook-memory.js";import{isMcpMode as st,MCP_MODE_SOURCE_LABELS as nt,MCP_PIN_MIGRATION_NOTICE as je,mcpModeSwitchHint as me}from"./mcp-mode.js";import{effectiveMcpMode as Qs,LENS_CONFIG as en,migrateUnchosenMcpModePin as Ne,probeIdentitySync as Pe,probeSharedMcp as ot,probeSharedMcpSync as tn,readMcpWiring as te,wireMcpMode as sn}from"./mcp-wiring.js";import{gatewayDaemonEnv as nn,openGatewayLog as on,secureLensLogs as rn,sweepLensRuntimeFiles as an}from"./sweep.js";import{candidateSignals as cn,findingLine as dn,findingsDigest as ln,formatContext as un,hookPayload as rt,isHookEvent as at,select as pn}from"./status-policy.js";import{DEFAULT_BUDGET_MS as hn,readStatus as gn,withLensSession as mn}from"./status-client.js";import{readServiceMemory as fn,runMemCommand as wn,socketOwnerGone as yn}from"./mem-command.js";import{runInstance as vn}from"./instance-command.js";import{walkProjectFiles as q}from"./project-files.js";import{LENS_SHARED_DIRS as kn,lensIgnoreVerdict as $n}from"./lens-ignore.js";import{inspectBundle as bn,sourceMapVerdict as Cn}from"./pod-source-maps.js";import{perfRulesVerdict as Sn,readPerfFindings as xn}from"./perf-rules-check.js";import{DISMISS_USAGE as jn,parseDismissArgs as Nn,runDismissCommand as Pn}from"./dismiss-command.js";import{parseRestartArgs as En,RESTART_USAGE as Mn,runRestartCommand as Tn}from"./restart-command.js";import{CALL_USAGE as Ln,httpsCall as Rn,parseCallArgs as On,runCallCommand as An}from"./call-command.js";import{otherCheckoutLines as it,refusalMessage as fe,registrationState as Ee}from"./gateway-registration.js";import{controlRequest as _n,graphVerdictLine as Me,registrationGraphFields as In}from"./guest-graph.js";import{locateServerBundle as Dn,MCP_SERVER_PROJECT as Fn,serverBundleNotFound as ct}from"./server-bundle.js";import{detectSkew as Gn,formatSkewContext as dt,readInstalledPlugin as Te,readInstalledPlugins as lt,readVersions as ut,spawnRunner as Kn,syncPlugin as Bn,updateCommands as Vn}from"./plugin-version.js";import{AGENTS as pt,agentById as Hn,codexInstalledVersion as Wn,installAgentPlugin as Un,MARKETPLACE as Jn,PLUGIN_ID as se,readPluginManifestVersion as qn,resolvePluginRoot as ht,spawnAgentRunner as gt}from"./agent-plugins.js";import{detectGlobalInstall as zn,daemonVerdict as Yn,detectPackageManager as Xn,installLanded as mt,installedCliFor as ft,lensPackagesIn as Zn,missingFromRegistry as Qn,needsInstall as eo,planRestart as to,readConnectedWorkspaces as so,registryAnswer as no,restartGatewayWith as oo,rewriteLensmcpDeps as ro,setupAfterUpgrade as ao,setupWith as io,upgradeTargets as co}from"./upgrade.js";const we=`lensmcp \u2014 CLI for LensMCP (FrontMCP-based observability for coding agents)
1
+ "use strict";var js=Object.defineProperty;var p=(t,n)=>js(t,"name",{value:n,configurable:!0});var Ns=Object.defineProperty,l=p((t,n)=>Ns(t,"name",{value:n,configurable:!0}),"d");import{spawn as Ps,spawnSync as A}from"node:child_process";import{existsSync as E,mkdirSync as Q,readFileSync as B,readdirSync as Ce,realpathSync as Es,rmSync as Ms,statSync as qe,writeFileSync as X}from"node:fs";import{request as ze}from"node:http";import{homedir as Ts,tmpdir as Ls}from"node:os";import{basename as pe,dirname as D,isAbsolute as Rs,join as w,relative as Ye,resolve as T}from"node:path";import{fileURLToPath as Xe,pathToFileURL as Os}from"node:url";import{ensureLensConfig as ee,isInstanceConfig as he,podNamespace as ge,readLensConfig as H}from"./workspace-scope.js";import{commandUsage as As,onOutputBroken as _s,wantsHelp as Is}from"./cli-help.js";import{logsFollow as Ds}from"./logs-follow.js";import{splitLintArgs as Fs}from"./lint-args.js";import{decideRecycle as Gs,hashConfig as Ks}from"./recycle-policy.js";import{planMcpRestart as Se}from"./mcp-restart.js";import{detectDuplicateRegistration as Bs,disabledMcpServers as Ze,mcpServerNames as Qe,pluginEnabledInSettings as et}from"./duplicate-registration.js";import{readTrackedPid as Vs,stillSameProcess as Hs,writeTrackedPid as tt}from"./process-identity.js";import{clusterPageHosts as Ws,readClusterPageDecls as Us,withBridgeAllowedOrigins as Js}from"./bridge-origins.js";import{runForwardingSignals as xe}from"./forward-signals.js";import{liveMcpSessions as qs,registerMcpSession as zs}from"./mcp-sessions.js";import{dashboardLoginUrl as me}from"./dashboard-login.js";import{recordAsked as Ys}from"./agent-asked.js";import{remember as Xs,shouldAnnounce as Zs}from"./hook-memory.js";import{isMcpMode as st,MCP_MODE_SOURCE_LABELS as nt,MCP_PIN_MIGRATION_NOTICE as je,mcpModeSwitchHint as fe}from"./mcp-mode.js";import{effectiveMcpMode as Qs,LENS_CONFIG as en,migrateUnchosenMcpModePin as Ne,probeIdentitySync as Pe,probeSharedMcp as ot,probeSharedMcpSync as tn,readMcpWiring as te,wireMcpMode as sn}from"./mcp-wiring.js";import{gatewayDaemonEnv as nn,openGatewayLog as on,secureLensLogs as rn,sweepLensRuntimeFiles as an}from"./sweep.js";import{candidateSignals as cn,findingLine as dn,findingsDigest as ln,formatContext as un,hookPayload as rt,isHookEvent as at,select as pn}from"./status-policy.js";import{DEFAULT_BUDGET_MS as hn,readStatus as gn,withLensSession as mn}from"./status-client.js";import{readServiceMemory as fn,runMemCommand as wn,socketOwnerGone as yn}from"./mem-command.js";import{runInstance as vn}from"./instance-command.js";import{walkProjectFiles as q}from"./project-files.js";import{LENS_SHARED_DIRS as kn,lensIgnoreVerdict as $n}from"./lens-ignore.js";import{inspectBundle as bn,sourceMapVerdict as Cn}from"./pod-source-maps.js";import{perfRulesVerdict as Sn,readPerfFindings as xn}from"./perf-rules-check.js";import{DISMISS_USAGE as jn,parseDismissArgs as Nn,runDismissCommand as Pn}from"./dismiss-command.js";import{parseRestartArgs as En,RESTART_USAGE as Mn,runRestartCommand as Tn}from"./restart-command.js";import{CALL_USAGE as Ln,httpsCall as Rn,parseCallArgs as On,runCallCommand as An}from"./call-command.js";import{otherCheckoutLines as it,refusalMessage as we,registrationState as Ee}from"./gateway-registration.js";import{controlRequest as _n,graphVerdictLine as Me,registrationGraphFields as In}from"./guest-graph.js";import{locateServerBundle as Dn,MCP_SERVER_PROJECT as Fn,serverBundleNotFound as ct}from"./server-bundle.js";import{detectSkew as Gn,formatSkewContext as dt,readInstalledPlugin as Te,readInstalledPlugins as lt,readVersions as ut,spawnRunner as Kn,syncPlugin as Bn,updateCommands as Vn}from"./plugin-version.js";import{AGENTS as pt,agentById as Hn,codexInstalledVersion as Wn,installAgentPlugin as Un,MARKETPLACE as Jn,PLUGIN_ID as se,readPluginManifestVersion as qn,resolvePluginRoot as ht,spawnAgentRunner as gt}from"./agent-plugins.js";import{detectGlobalInstall as zn,daemonVerdict as Yn,detectPackageManager as Xn,installLanded as mt,installedCliFor as ft,lensPackagesIn as Zn,missingFromRegistry as Qn,needsInstall as eo,planRestart as to,readConnectedWorkspaces as so,registryAnswer as no,restartGatewayWith as oo,rewriteLensmcpDeps as ro,setupAfterUpgrade as ao,setupWith as io,upgradeTargets as co}from"./upgrade.js";const ye=`lensmcp \u2014 CLI for LensMCP (FrontMCP-based observability for coding agents)
2
2
 
3
3
  Usage:
4
4
  lensmcp <command> [options]
@@ -284,25 +284,25 @@ Commands:
284
284
  once its work is committed.
285
285
  --version Print the lensmcp version.
286
286
  --help Show this help.
287
- `;export async function runCli(t){const n=t.out??(r=>console.log(r)),e=t.err??(r=>console.error(r)),[s,...o]=t.argv;if(!s||s==="--help"||s==="-h")return n(we),{exitCode:0};if(s==="--version"||s==="-V")return n(Y()),{exitCode:0};if(Is(o,s))return n(As(we,s)??we),{exitCode:0};switch(s){case"setup":return Kt(t,o,n,e);case"mcp":return vt(t,o,n,e);case"dashboard":return $t(t,o,n,e);case"gateway":return Le(t,o,n,e);case"bridge":return Rt(t,o,n,e);case"install":return Ie(t,o,n,e);case"plugin":case"plugins":return ts(t,o,n,e);case"upgrade":return rs(t,o,n,e);case"trust":return De(t,o,n,e);case"status":return Vt(t,o,n);case"version-check":return Ht(t,o,n);case"doctor":return Wt(t,o,n);case"prune":return wt(t,o,n,e);case"rollout":return cs(t,o,e);case"logs":return vs(t,o,n,e);case"dismiss":return Ot(t,o,n,e);case"lint":return It(t,o,e);case"debug":return ks(t,o,n,e);case"mem":return bs(t,o,n,e);case"restart":return At(t,o,n,e);case"call":return _t(t,o,n,e);case"instance":case"instances":return $s(t,o,n,e);case"agent":return Bt(t,o);default:return e(`Unknown command: ${s}`),e(we),{exitCode:2,message:`Unknown command: ${s}`}}}p(runCli,"runCli"),l(runCli,"runCli");function wt(t,n,e,s){const o=I(n,{string:["--cwd"],boolean:["--force"]}),r=T($(o.flags["--cwd"])??t.cwd),a=w(r,".lensmcp"),c=w(a,"gateway.log"),d=l(()=>{try{return be(a).reduce((m,f)=>{try{return m+qe(w(a,f)).size}catch{return m}},0)}catch{return 0}},"dirBytes"),i=l(m=>`${(m/1048576).toFixed(1)} MB`,"mb"),h=d();if(h===0)return e(`nothing to prune \u2014 no .lensmcp runtime files at ${a}`),{exitCode:0};if(o.flags["--force"]!==!0&&yt(a))return s("a gateway is running for this workspace \u2014 pruning now can drop a generation a live"),s("writer is still counting (issues/closed/foodguard-13). Stop it first:"),s(" lensmcp gateway stop"),s("\u2026or pass --force if you accept losing recent history."),{exitCode:1,message:"gateway running"};an(r,c),rn(r);const g=d();return e(`pruned ${a}`),e(` ${i(h)} \u2192 ${i(g)} (reclaimed ${i(Math.max(0,h-g))})`),{exitCode:0}}p(wt,"Qn"),l(wt,"runPrune");function yt(t){try{return Oe(w(t,"gateway.pid"))!==void 0}catch{return!1}}p(yt,"es"),l(yt,"gatewayPidAlive");async function vt(t,n,e,s){const o=I(n,{string:["--cwd","--transport","--port","--mcp"]}),r=T($(o.flags["--cwd"])??t.cwd),a=Z(r),c=$(o.flags["--transport"])??t.env?.LENSMCP_TRANSPORT??"stdio",d=$(o.flags["--port"])??t.env?.LENSMCP_PORT??String(a.ports.mcpHttp),i=Qs(r,$(o.flags["--mcp"]),{...process.env,...t.env??{}})==="shared"&&c==="stdio",h=i?ls(r):void 0,g=h??He(r);if(!g)return s(ct("lensmcp-mcp server bundle","main.js")),{exitCode:1};ue(r);const m=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(r,".lensmcp","events.jsonl"),f={...t.env??{},LENSMCP_TRANSPORT:c,LENSMCP_PORT:d,LENSMCP_EVENT_FILE:m};if(h)return{exitCode:await kt(h,r,f)};const v={...process.env,...f};if(c!=="stdio")return{exitCode:await xe({label:`the MCP server (${g})`,args:[g],cwd:r,env:v},s)};const b=i?[g,"--cwd",r]:[g];return{exitCode:A(process.execPath,b,{cwd:r,stdio:"inherit",env:v}).status??1}}p(vt,"ts"),l(vt,"runMcp");async function kt(t,n,e){for(const[o,r]of Object.entries(e))r===void 0?delete process.env[o]:process.env[o]=r;process.chdir(n),process.once("exit",zs(n));const s=await import(Os(t).href);return typeof s.runShim!="function"?new Promise(()=>{}):s.runShim({cwd:n})}p(kt,"ns"),l(kt,"runShimInProcess");async function $t(t,n,e,s){const o=I(n,{string:["--cwd","--port","--base"]}),r=T($(o.flags["--cwd"])??t.cwd),a=Z(r);if(!$(o.flags["--port"])&&!t.env?.LENSMCP_DASHBOARD_PORT){const g=R("GET","/list");if(g?.status===200&&(g.json?.workspaces??[]).some(m=>m.key===a.key)){const m=`https://lensmcp.local${a.dashboardBasePath}/`;e(`lensmcp dashboard \u2192 the gateway already runs this workspace's dashboard: ${m}`);const f=ge(m,r,{...process.env,...t.env??{}});return f&&e(` sign in \u2192 ${f} (one use, 10 min \u2014 then this browser stays signed in)`),e(" (another, standalone: `lensmcp dashboard --port <a free port>`)"),{exitCode:0}}}const c=$(o.flags["--port"])??t.env?.LENSMCP_DASHBOARD_PORT??String(a.ports.dashboard),d=$(o.flags["--base"])??t.env?.LENSMCP_DASHBOARD_BASE??"",i=ve(r,"dashboard.js");if(!i)return s(ct("lensmcp dashboard bundle","dashboard.js")),{exitCode:1};ue(r);const h=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(r,".lensmcp","events.jsonl");return e(`lensmcp dashboard \u2192 http://localhost:${c}${d||"/"} (reading ${h})`),{exitCode:await xe({label:`the dashboard (${i})`,args:[i],cwd:r,env:{...process.env,...t.env??{},LENSMCP_DASHBOARD_PORT:c,LENSMCP_DASHBOARD_BASE:d,LENSMCP_EVENT_FILE:h}},s)}}p($t,"ss"),l($t,"runDashboard");function bt(){return w(process.env.LENSMCP_HOME||Ts(),".lensmcp","control.sock")}p(bt,"rs"),l(bt,"controlSocketPath");function R(t,n,e){const s=bt();return E(s)?_n(s,t,n,e):null}p(R,"R"),l(R,"daemonRequest");async function Ct(t,n,e){for(;;){const s=R("GET","/list"),o=s?.status===200&&s.json&&typeof s.json=="object"?s.json.workspaces??[]:[];if(Ee(o,t,n).kind==="mine")return!0;if(Date.now()>=e)return!1;await new Promise(r=>setTimeout(r,500))}}p(Ct,"os"),l(Ct,"servedFrom");function St(){const t=R("GET","/status");if(t?.status!==200||!t.json||typeof t.json!="object")return;const n=t.json.daemon;return typeof n?.wsKey=="string"&&n.wsKey.length>0?n.wsKey:void 0}p(St,"is"),l(St,"daemonWsKey");function xt(t){const n={};for(const e of q(t,s=>s==="project.json"))try{const s=JSON.parse(B(e,"utf8")),o=D(e);n[s.name??pe(o)]={root:Ye(t,o)||"."}}catch{}return n}p(xt,"as"),l(xt,"buildProjectsMap");function jt(t){const n=w(t,"node_modules",".bin",process.platform==="win32"?"nx.cmd":"nx");if(!E(n))return;const e=A(n,["graph","--print"],{cwd:t,encoding:"utf8",timeout:15e3,maxBuffer:32*1024*1024});if(!(e.status!==0||typeof e.stdout!="string"))try{const s=JSON.parse(e.stdout).graph?.dependencies;return s?Object.fromEntries(Object.entries(s).map(([o,r])=>[o,r.flatMap(a=>typeof a.target=="string"?[a.target]:[])])):void 0}catch{return}}p(jt,"cs"),l(jt,"buildProjectDependencies");function re(t,n){return{wsKey:n,root:t,projects:xt(t),...In(t,()=>jt(t))}}p(re,"le"),l(re,"gatewayRegistrationBody");function Le(t,n,e,s){const o=I(n,{string:["--cwd","--project","--target"]}),r=(o.positional[0]??"status").toLowerCase(),a=n.includes("--json"),c=T($(o.flags["--cwd"])??t.cwd),d=Z(c),i=w(c,".lensmcp","gateway.pid"),h=w(c,".lensmcp","gateway.log"),g=w(c,".lensmcp","registered.json"),m=`https://lensmcp.local${d.dashboardBasePath}/`,f=l(()=>{const C=ge(m,c,{...process.env,...t.env??{}});C&&e(` sign in \u2192 ${C} (one use, 10 min \u2014 then this browser stays signed in)`)},"printSignIn"),v=l(()=>{const{pid:C,healed:_}=ce(i,c);if(C!==void 0&&ie(C)){const O=classifyAliveGateway({oursOn443:W(c)!==void 0,port443Held:H().length>0,pidFileAgeMs:Ae(i)});if(O==="serving")return _&&e(`healed: adopted a running gateway (pid ${C}) the pid file had lost \u2014 no duplicate started.`),e(`gateway already running (pid ${C}).`),e(` dashboard \u2192 ${m}`),f(),{exitCode:0};if(O==="booting")return e(`gateway starting (pid ${C}) \u2014 :443 not bound yet.`),e(` dashboard \u2192 ${m}`),f(),e(` logs \u2192 ${h}`),{exitCode:0};de(C,"SIGKILL"),z(i),ae(c,t.env,()=>{}),e(`reaped a dead gateway (pid ${C} was alive but nothing served :443 for this workspace).`)}const u=H()[0];if(u!==void 0){const O=R("GET","/list");if(O!==null){const G=O.status===200&&O.json&&typeof O.json=="object"?O.json.workspaces??[]:[],S=Ee(G,d.key,c);if(S.kind==="other-checkout"){for(const F of it(d.key,S.root,c))s(F);return{exitCode:1}}if(S.kind==="mine")return ee(D(g),{recursive:!0}),X(g,JSON.stringify({wsKey:d.key})),e(`already registered into the shared gateway daemon (pid ${u}).`),e(` dashboard \u2192 ${m}`),f(),{exitCode:0};const j=R("POST","/register",re(c,d.key));if(j&&j.status===200){ee(D(g),{recursive:!0}),X(g,JSON.stringify({wsKey:d.key})),e(`registered '${d.key}' into the shared gateway daemon (pid ${u}).`),e(` dashboard \u2192 ${m}`);const F=Me(j.json);return F&&e(F),f(),e(" the daemon hosts this workspace's services + dashboard; `lensmcp gateway stop` unregisters."),{exitCode:0}}return s(`failed to register into the gateway daemon: ${fe(j)??(j?JSON.stringify(j.json):"no response from the control socket")}`),{exitCode:1}}return s(`port :443 is held by pid ${u}, which is not this workspace's gateway.
288
- Free it first (stop that process), then \`lensmcp gateway start\`.`),{exitCode:1}}const y=Nt(c,$(o.flags["--project"]),$(o.flags["--target"]));if(!y)return s(`This workspace ('${d.key}') has no gateway target \u2014 no project declares the`),s("`@lensmcp/cluster:gateway` executor, so there is nothing here to launch on :443."),s(""),s(" \u2022 Joining a shared gateway? Start it in the workspace that OWNS it, then run"),s(" `lensmcp gateway start` here \u2014 this workspace registers into it (no local target needed)."),s(" \u2022 Should this workspace host its own gateway? Scaffold it: `lensmcp install`"),s(" (or `lensmcp setup` for the full install + trust bootstrap)."),s(" \u2022 Already have a differently-named target? `lensmcp gateway start --project <p> --target <t>`."),{exitCode:1};const x=le(c);if(!x)return s("Could not find the `nx` binary in the workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};const P=on(c,h),L=Ps(x,["run",`${y.project}:${y.target}`],{cwd:c,detached:!0,stdio:["ignore",P,P],env:nn({...process.env,...t.env??{}},h)});return L.unref(),L.pid&&tt(i,L.pid),e(`gateway starting \u2192 ${y.project}:${y.target} (pid ${L.pid??"?"})`),e(` dashboard \u2192 ${m}`),f(),e(` logs \u2192 ${h}`),e(" note: binding :443 needs privilege \u2014 if it fails, run the gateway target with sudo,"),e(" and run `nx run gateway:trust` once for the *.local hosts + TLS."),{exitCode:0}},"start"),b=l(()=>{if(E(g)&&W(c)===void 0){let x=d.key;try{x=JSON.parse(B(g,"utf8")).wsKey??d.key}catch{}const P=R("POST","/unregister",{wsKey:x,root:c});z(g);const L=fe(P);return e(L??(P&&P.status===200?`unregistered '${x}' from the shared gateway daemon.`:"unregister sent (the daemon may already be gone).")),{exitCode:0}}z(g);const{pid:C,healed:_}=ce(i,c);if(C===void 0)return e("gateway not running."),z(i),{exitCode:0};_&&e(`healed: found an orphaned gateway (pid ${C}) the pid file had lost \u2014 stopping it.`),de(C);let u=!1;if(!_e(6e3)){u=!0,de(C,"SIGKILL");const x=W(c);if(x!==void 0)try{process.kill(x,"SIGKILL")}catch{}else H().length>0&&e(":443 is still held by a process that is not this workspace's gateway \u2014 leaving it alone.");_e(3e3)}const y=W(c);return y!==void 0&&y!==C&&(de(y,"SIGKILL"),u=!0),z(i),u&&ae(c,t.env,()=>{}),e(`gateway stopped (pid ${C})${u?" \u2014 forced (a child ignored SIGTERM)":""}.`),{exitCode:0}},"stop"),k=l(()=>{const{pid:C,healed:_}=ce(i,c),u=C!==void 0&&ie(C)?classifyAliveGateway({oursOn443:W(c)!==void 0,port443Held:H().length>0,pidFileAgeMs:Ae(i)}):void 0,y=u==="serving"||u==="booting";if(a){const S=R("GET","/status"),j=S?.status===200&&S.json&&typeof S.json=="object"?S.json:null,F=E(g),xs=y?"daemon":j&&F?"guest":j?"other":"stopped";return e(JSON.stringify({thisWorkspace:d.key,role:xs,dashboardUrl:m,dashboardLoginUrl:ge(m,c,{...process.env,...t.env??{}})??null,chooserUrl:"https://lensmcp.local/",logFile:h,daemonLogFile:(()=>{const $e=Ke();return $e&&$e!==c?w($e,".lensmcp","gateway.log"):h})(),mcp:Be(c,t.env??process.env),daemon:j?.daemon??null,workspaces:j?.workspaces??[],services:j?.services??[]})),{exitCode:y||j&&F?0:1}}const x=R("GET","/list"),P=x?.status===200&&x.json&&typeof x.json=="object"?x.json.workspaces??[]:[],L=l(()=>{if(P.length!==0){e(` workspaces (${P.length} registered):`);for(const S of P){if(e(` \u2022 ${S.key} (${S.routes??0} routes, ${S.services??0} services)${S.key===d.key?" \u2190 this workspace":""}`),S.key===d.key||!S.root)continue;const j=ge(`https://lensmcp.local${J(S.root).dashboardBasePath}/`,S.root,{...process.env,...t.env??{},LENSMCP_DASHBOARD_TOKEN:void 0});j&&e(` sign in \u2192 ${j}`)}}},"printWorkspaces"),O=l(()=>{const S=Be(c,t.env??process.env);e(S.mode==="shared"?` mcp \u2192 shared ${S.url} ${S.healthy?"(up)":S.remedy?`(REFUSED \u2014 ${S.error}; ${S.remedy})`:`(DOWN \u2014 ${S.error??"no answer"})`}`:" mcp \u2192 embedded (one server per agent session \u2014 opted out of shared)")},"printMcp"),G=l(()=>{const S=R("GET","/status"),j=S?.status===200&&S.json&&typeof S.json=="object"?S.json.daemon:void 0,F=V(c);j?.version&&F&&j.version!==F&&e(` version \u2192 the daemon runs ${j.version} but this workspace depends on ${F} \u2014 \`lensmcp upgrade\` reconciles everything (or restart the daemon workspace's gateway).`)},"printVersionSkew");if(y)return e(u==="booting"?`gateway: starting (pid ${C}) \u2014 :443 not bound yet`:`gateway: running (pid ${C}) \u2014 DAEMON on :443${_?" \u2014 recovered a stale pid file":""}`),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${m}`),f(),e(" chooser \u2192 https://lensmcp.local/"),e(` logs \u2192 ${h}`),O(),G(),L(),{exitCode:0};if(E(g)&&x?.status===200){const S=H()[0];e(`gateway: registered into a shared daemon${S!==void 0?` (pid ${S})`:""} \u2014 this workspace is a guest`),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${m}`),f(),e(` logs \u2192 ${h} (this workspace's pods)`);const j=Ke();return j&&j!==c&&e(` ${w(j,".lensmcp","gateway.log")} (the daemon's own log \u2014 gateway-level lines land there)`),e(" attach \u2192 `lensmcp logs <service>` (live, from any workspace)"),e(" stop \u2192 `lensmcp gateway stop` (unregisters; the daemon keeps running)"),O(),G(),L(),{exitCode:0}}return u==="zombie"?(e(`gateway: NOT serving \u2014 tracked pid ${C} is alive but nothing holds :443 for this workspace`),e(" (a crashed gateway under a wedged nx wrapper) \u2014 run `lensmcp gateway restart` to recover."),e(` workspace \u2192 ${d.key}`),e(` logs \u2192 ${h}`),O(),L(),{exitCode:1}):(e("gateway: stopped"),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${m}`),f(),O(),{exitCode:1})},"status"),M=l(()=>{const C=R("GET","/status");if(C?.status!==200||!C.json||typeof C.json!="object")return e(a?JSON.stringify({daemon:null,workspaces:[],services:[]}):"gateway: no daemon answers on the control socket \u2014 nothing is hosted."),{exitCode:1};const _=C.json;if(a)return e(JSON.stringify(_)),{exitCode:0};e(`daemon: pid ${_.daemon?.pid??"?"} \xB7 owner ${_.daemon?.wsKey??"?"}${_.daemon?.version?` \xB7 lensmcp ${_.daemon.version}`:""}`);for(const u of _.workspaces??[]){e(` ${u.isDaemon?"\u2605":"\xB7"} ${u.key.padEnd(16)} ${String(u.routes??0).padStart(3)} routes ${String(u.services??0).padStart(3)} services ${u.root??""}`);for(const y of(_.services??[]).filter(x=>(x.wsKey??_.daemon?.wsKey)===u.key))e(` ${y.project.padEnd(16)} ${(y.state??"unknown").padEnd(9)} ${y.host??""}`)}return{exitCode:0}},"list");switch(r){case"start":return v();case"stop":return b();case"list":return M();case"restart":return b(),ae(c,t.env,e),v();case"status":return k();default:return s(`Unknown gateway subcommand: ${r} (use start | stop | status | restart | list)`),{exitCode:2}}}p(Le,"et"),l(Le,"runGateway");function ae(t,n,e){const s=le(t);if(!s){e(" (graph refresh skipped \u2014 no nx binary found in the workspace)");return}const o={...process.env,...n??{}},r=l(a=>A(s,a,{cwd:t,env:o,stdio:"ignore"}).status===0,"tryNx");if(r(["reset","--only-daemon"])||r(["daemon","--stop"])){e(" nx project graph refreshed \u2014 a lib/app added since boot will now resolve.");return}e(" (graph refresh best-effort failed \u2014 if a new project does not resolve, run `nx reset`)")}p(ae,"pe"),l(ae,"refreshNxGraph");function Re(t,n,e,s){if(e&&s)return{project:e,target:s};const o=q(t,r=>r==="project.json");for(const r of o){let a;try{a=JSON.parse(K(r))}catch{continue}const c=a.name??pe(D(r));for(const[d,i]of Object.entries(a.targets??{}))if(i.executor===n)return{project:e??c,target:s??d}}}p(Re,"tt"),l(Re,"scanExecutorTarget");function Nt(t,n,e){return Re(t,"@lensmcp/cluster:gateway",n,e)||(n||e?{project:n??"gateway",target:e??"serve"}:void 0)}p(Nt,"ds"),l(Nt,"findGatewayTarget");function Pt(t,n,e){return Re(t,"@lensmcp/cluster:trust",n,e)||(n?{project:n,target:e??"trust"}:Et(t,"gateway")?{project:"gateway",target:e??"trust"}:void 0)}p(Pt,"ls"),l(Pt,"findTrustTarget");function Et(t,n){for(const e of q(t,s=>s==="project.json"))try{if((JSON.parse(K(e)).name??pe(D(e)))===n)return!0}catch{}return!1}p(Et,"ps"),l(Et,"projectExists");function Oe(t){const n=Vs(t);if(n)return Hs(n.pid,n.stamp)?n.pid:void 0}p(Oe,"nt"),l(Oe,"readPid");function ie(t){try{return process.kill(t,0),!0}catch(n){return n.code==="EPERM"}}p(ie,"ue"),l(ie,"isAlive");function H(){try{const t=A("lsof",["-nP","-iTCP:443","-sTCP:LISTEN","-t"],{encoding:"utf8"});return t.status!==0||!t.stdout?[]:[...new Set(t.stdout.split(/\s+/).map(Number).filter(n=>Number.isInteger(n)&&n>0))]}catch{return[]}}p(H,"U"),l(H,"pidsOnPort443");function Mt(t){try{return(A("ps",["-o","command=","-p",String(t)],{encoding:"utf8"}).stdout??"").trim()}catch{return""}}p(Mt,"us"),l(Mt,"processCmd");function W(t){const n=w(t,"node_modules","nx","dist","bin","run-executor.js"),e=w(t,"node_modules","@lensmcp","cluster");for(const s of H()){const o=Mt(s);if(o.includes(n)||o.includes(e))return s}}p(W,"J"),l(W,"gatewayOnPort443");function Ae(t){try{return Date.now()-qe(t).mtimeMs}catch{return}}p(Ae,"st"),l(Ae,"pidFileAgeMs");const lo=18e4;export function classifyAliveGateway(t){if(t.oursOn443)return"serving";const n=t.pidFileAgeMs!==void 0&&t.pidFileAgeMs<(t.bootGraceMs??lo);return!t.port443Held&&n?"booting":"zombie"}p(classifyAliveGateway,"classifyAliveGateway"),l(classifyAliveGateway,"classifyAliveGateway");function ce(t,n){const e=Oe(t);if(e!==void 0&&ie(e))return{pid:e,healed:!1};const s=W(n);if(s!==void 0){try{tt(t,s)}catch{}return{pid:s,healed:!0}}return{healed:!1}}p(ce,"fe"),l(ce,"reconcileGateway");function de(t,n="SIGTERM"){try{process.kill(-t,n)}catch{try{process.kill(t,n)}catch{}}}p(de,"he"),l(de,"killGatewayTree");function _e(t){const n=Date.now()+t;for(;;){if(H().length===0)return!0;if(Date.now()>=n)return!1;A("sleep",["0.15"])}}p(_e,"rt"),l(_e,"waitForPortFree");function Tt(t){const n=A("curl",["-s","-o","/dev/null","-m","8","-w","%{ssl_verify_result}",`https://${t}/`],{encoding:"utf8"}),e=(n.stdout??"").trim();return n.status===0&&e==="0"?"trusted":e&&e!=="0"?"untrusted":"unknown"}p(Tt,"hs"),l(Tt,"probeHostTrust");function Lt(t){for(const n of q(t,e=>e==="project.json"))try{const e=JSON.parse(B(n,"utf8")),s=(e.cluster??e.davnx)?.host;if(s&&!s.includes("*"))return s}catch{}}p(Lt,"gs"),l(Lt,"firstClusterHost");function z(t){try{Ms(t,{force:!0})}catch{}}p(z,"Y"),l(z,"rmFile");async function Rt(t,n,e,s){const o=I(n,{string:["--cwd","--host","--port"]}),r=T($(o.flags["--cwd"])??t.cwd),a=Z(r),c=$(o.flags["--host"])??t.env?.LENSMCP_WS_HOST??process.env.LENSMCP_WS_HOST,d=$(o.flags["--port"])??t.env?.LENSMCP_WS_PORT??process.env.LENSMCP_WS_PORT??String(a.ports.bridge),i=us(r);if(!i)return s(`Could not locate the lensmcp bridge bundle.
287
+ `;export async function runCli(t){const n=t.out??(r=>console.log(r)),e=t.err??(r=>console.error(r)),[s,...o]=t.argv;if(!s||s==="--help"||s==="-h")return n(ye),{exitCode:0};if(s==="--version"||s==="-V")return n(Y()),{exitCode:0};if(Is(o,s))return n(As(ye,s)??ye),{exitCode:0};switch(s){case"setup":return Kt(t,o,n,e);case"mcp":return vt(t,o,n,e);case"dashboard":return $t(t,o,n,e);case"gateway":return Le(t,o,n,e);case"bridge":return Rt(t,o,n,e);case"install":return Ie(t,o,n,e);case"plugin":case"plugins":return ts(t,o,n,e);case"upgrade":return rs(t,o,n,e);case"trust":return De(t,o,n,e);case"status":return Vt(t,o,n);case"version-check":return Ht(t,o,n);case"doctor":return Wt(t,o,n);case"prune":return wt(t,o,n,e);case"rollout":return cs(t,o,e);case"logs":return vs(t,o,n,e);case"dismiss":return Ot(t,o,n,e);case"lint":return It(t,o,e);case"debug":return ks(t,o,n,e);case"mem":return bs(t,o,n,e);case"restart":return At(t,o,n,e);case"call":return _t(t,o,n,e);case"instance":case"instances":return $s(t,o,n,e);case"agent":return Bt(t,o);default:return e(`Unknown command: ${s}`),e(ye),{exitCode:2,message:`Unknown command: ${s}`}}}p(runCli,"runCli"),l(runCli,"runCli");function wt(t,n,e,s){const o=I(n,{string:["--cwd"],boolean:["--force"]}),r=T($(o.flags["--cwd"])??t.cwd),a=w(r,".lensmcp"),c=w(a,"gateway.log"),d=l(()=>{try{return Ce(a).reduce((m,f)=>{try{return m+qe(w(a,f)).size}catch{return m}},0)}catch{return 0}},"dirBytes"),i=l(m=>`${(m/1048576).toFixed(1)} MB`,"mb"),h=d();if(h===0)return e(`nothing to prune \u2014 no .lensmcp runtime files at ${a}`),{exitCode:0};if(o.flags["--force"]!==!0&&yt(a))return s("a gateway is running for this workspace \u2014 pruning now can drop a generation a live"),s("writer is still counting (issues/closed/foodguard-13). Stop it first:"),s(" lensmcp gateway stop"),s("\u2026or pass --force if you accept losing recent history."),{exitCode:1,message:"gateway running"};an(r,c),rn(r);const g=d();return e(`pruned ${a}`),e(` ${i(h)} \u2192 ${i(g)} (reclaimed ${i(Math.max(0,h-g))})`),{exitCode:0}}p(wt,"Qn"),l(wt,"runPrune");function yt(t){try{return Oe(w(t,"gateway.pid"))!==void 0}catch{return!1}}p(yt,"es"),l(yt,"gatewayPidAlive");async function vt(t,n,e,s){const o=I(n,{string:["--cwd","--transport","--port","--mcp"]}),r=T($(o.flags["--cwd"])??t.cwd),a=ee(r),c=$(o.flags["--transport"])??t.env?.LENSMCP_TRANSPORT??"stdio",d=$(o.flags["--port"])??t.env?.LENSMCP_PORT??String(a.ports.mcpHttp),i=Qs(r,$(o.flags["--mcp"]),{...process.env,...t.env??{}})==="shared"&&c==="stdio",h=i?ls(r):void 0,g=h??He(r);if(!g)return s(ct("lensmcp-mcp server bundle","main.js")),{exitCode:1};ue(r);const m=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(r,".lensmcp","events.jsonl"),f={...t.env??{},LENSMCP_TRANSPORT:c,LENSMCP_PORT:d,LENSMCP_EVENT_FILE:m};if(h)return{exitCode:await kt(h,r,f)};const v={...process.env,...f};if(c!=="stdio")return{exitCode:await xe({label:`the MCP server (${g})`,args:[g],cwd:r,env:v},s)};const b=i?[g,"--cwd",r]:[g];return{exitCode:A(process.execPath,b,{cwd:r,stdio:"inherit",env:v}).status??1}}p(vt,"ts"),l(vt,"runMcp");async function kt(t,n,e){for(const[o,r]of Object.entries(e))r===void 0?delete process.env[o]:process.env[o]=r;process.chdir(n),process.once("exit",zs(n));const s=await import(Os(t).href);return typeof s.runShim!="function"?new Promise(()=>{}):s.runShim({cwd:n})}p(kt,"ns"),l(kt,"runShimInProcess");async function $t(t,n,e,s){const o=I(n,{string:["--cwd","--port","--base"]}),r=T($(o.flags["--cwd"])??t.cwd),a=ee(r);if(!$(o.flags["--port"])&&!t.env?.LENSMCP_DASHBOARD_PORT){const g=R("GET","/list");if(g?.status===200&&(g.json?.workspaces??[]).some(m=>m.key===a.key)){const m=`https://lensmcp.local${a.dashboardBasePath}/`;e(`lensmcp dashboard \u2192 the gateway already runs this workspace's dashboard: ${m}`);const f=me(m,r,{...process.env,...t.env??{}});return f&&e(` sign in \u2192 ${f} (one use, 10 min \u2014 then this browser stays signed in)`),e(" (another, standalone: `lensmcp dashboard --port <a free port>`)"),{exitCode:0}}}const c=$(o.flags["--port"])??t.env?.LENSMCP_DASHBOARD_PORT??String(a.ports.dashboard),d=$(o.flags["--base"])??t.env?.LENSMCP_DASHBOARD_BASE??"",i=ke(r,"dashboard.js");if(!i)return s(ct("lensmcp dashboard bundle","dashboard.js")),{exitCode:1};ue(r);const h=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(r,".lensmcp","events.jsonl");return e(`lensmcp dashboard \u2192 http://localhost:${c}${d||"/"} (reading ${h})`),{exitCode:await xe({label:`the dashboard (${i})`,args:[i],cwd:r,env:{...process.env,...t.env??{},LENSMCP_DASHBOARD_PORT:c,LENSMCP_DASHBOARD_BASE:d,LENSMCP_EVENT_FILE:h}},s)}}p($t,"ss"),l($t,"runDashboard");function bt(){return w(process.env.LENSMCP_HOME||Ts(),".lensmcp","control.sock")}p(bt,"rs"),l(bt,"controlSocketPath");function R(t,n,e){const s=bt();return E(s)?_n(s,t,n,e):null}p(R,"R"),l(R,"daemonRequest");async function Ct(t,n,e){for(;;){const s=R("GET","/list"),o=s?.status===200&&s.json&&typeof s.json=="object"?s.json.workspaces??[]:[];if(Ee(o,t,n).kind==="mine")return!0;if(Date.now()>=e)return!1;await new Promise(r=>setTimeout(r,500))}}p(Ct,"os"),l(Ct,"servedFrom");function St(){const t=R("GET","/status");if(t?.status!==200||!t.json||typeof t.json!="object")return;const n=t.json.daemon;return typeof n?.wsKey=="string"&&n.wsKey.length>0?n.wsKey:void 0}p(St,"is"),l(St,"daemonWsKey");function xt(t){const n={};for(const e of q(t,s=>s==="project.json"))try{const s=JSON.parse(B(e,"utf8")),o=D(e);n[s.name??pe(o)]={root:Ye(t,o)||"."}}catch{}return n}p(xt,"as"),l(xt,"buildProjectsMap");function jt(t){const n=w(t,"node_modules",".bin",process.platform==="win32"?"nx.cmd":"nx");if(!E(n))return;const e=A(n,["graph","--print"],{cwd:t,encoding:"utf8",timeout:15e3,maxBuffer:32*1024*1024});if(!(e.status!==0||typeof e.stdout!="string"))try{const s=JSON.parse(e.stdout).graph?.dependencies;return s?Object.fromEntries(Object.entries(s).map(([o,r])=>[o,r.flatMap(a=>typeof a.target=="string"?[a.target]:[])])):void 0}catch{return}}p(jt,"cs"),l(jt,"buildProjectDependencies");function re(t,n){return{wsKey:n,root:t,projects:xt(t),...In(t,()=>jt(t))}}p(re,"pe"),l(re,"gatewayRegistrationBody");function Le(t,n,e,s){const o=I(n,{string:["--cwd","--project","--target"]}),r=(o.positional[0]??"status").toLowerCase(),a=n.includes("--json"),c=T($(o.flags["--cwd"])??t.cwd),d=ee(c),i=w(c,".lensmcp","gateway.pid"),h=w(c,".lensmcp","gateway.log"),g=w(c,".lensmcp","registered.json"),m=`https://lensmcp.local${d.dashboardBasePath}/`,f=l(()=>{const C=me(m,c,{...process.env,...t.env??{}});C&&e(` sign in \u2192 ${C} (one use, 10 min \u2014 then this browser stays signed in)`)},"printSignIn"),v=l(()=>{const{pid:C,healed:_}=ce(i,c);if(C!==void 0&&ie(C)){const O=classifyAliveGateway({oursOn443:U(c)!==void 0,port443Held:W().length>0,pidFileAgeMs:Ae(i)});if(O==="serving")return _&&e(`healed: adopted a running gateway (pid ${C}) the pid file had lost \u2014 no duplicate started.`),e(`gateway already running (pid ${C}).`),e(` dashboard \u2192 ${m}`),f(),{exitCode:0};if(O==="booting")return e(`gateway starting (pid ${C}) \u2014 :443 not bound yet.`),e(` dashboard \u2192 ${m}`),f(),e(` logs \u2192 ${h}`),{exitCode:0};de(C,"SIGKILL"),z(i),ae(c,t.env,()=>{}),e(`reaped a dead gateway (pid ${C} was alive but nothing served :443 for this workspace).`)}const u=W()[0];if(u!==void 0){const O=R("GET","/list");if(O!==null){const G=O.status===200&&O.json&&typeof O.json=="object"?O.json.workspaces??[]:[],S=Ee(G,d.key,c);if(S.kind==="other-checkout"){for(const F of it(d.key,S.root,c))s(F);return{exitCode:1}}if(S.kind==="mine")return Q(D(g),{recursive:!0}),X(g,JSON.stringify({wsKey:d.key})),e(`already registered into the shared gateway daemon (pid ${u}).`),e(` dashboard \u2192 ${m}`),f(),{exitCode:0};const j=R("POST","/register",re(c,d.key));if(j&&j.status===200){Q(D(g),{recursive:!0}),X(g,JSON.stringify({wsKey:d.key})),e(`registered '${d.key}' into the shared gateway daemon (pid ${u}).`),e(` dashboard \u2192 ${m}`);const F=Me(j.json);return F&&e(F),f(),e(" the daemon hosts this workspace's services + dashboard; `lensmcp gateway stop` unregisters."),{exitCode:0}}return s(`failed to register into the gateway daemon: ${we(j)??(j?JSON.stringify(j.json):"no response from the control socket")}`),{exitCode:1}}return s(`port :443 is held by pid ${u}, which is not this workspace's gateway.
288
+ Free it first (stop that process), then \`lensmcp gateway start\`.`),{exitCode:1}}const y=Nt(c,$(o.flags["--project"]),$(o.flags["--target"]));if(!y)return s(`This workspace ('${d.key}') has no gateway target \u2014 no project declares the`),s("`@lensmcp/cluster:gateway` executor, so there is nothing here to launch on :443."),s(""),s(" \u2022 Joining a shared gateway? Start it in the workspace that OWNS it, then run"),s(" `lensmcp gateway start` here \u2014 this workspace registers into it (no local target needed)."),s(" \u2022 Should this workspace host its own gateway? Scaffold it: `lensmcp install`"),s(" (or `lensmcp setup` for the full install + trust bootstrap)."),s(" \u2022 Already have a differently-named target? `lensmcp gateway start --project <p> --target <t>`."),{exitCode:1};const x=le(c);if(!x)return s("Could not find the `nx` binary in the workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};const P=on(c,h),L=Ps(x,["run",`${y.project}:${y.target}`],{cwd:c,detached:!0,stdio:["ignore",P,P],env:nn({...process.env,...t.env??{}},h)});return L.unref(),L.pid&&tt(i,L.pid),e(`gateway starting \u2192 ${y.project}:${y.target} (pid ${L.pid??"?"})`),e(` dashboard \u2192 ${m}`),f(),e(` logs \u2192 ${h}`),e(" note: binding :443 needs privilege \u2014 if it fails, run the gateway target with sudo,"),e(" and run `nx run gateway:trust` once for the *.local hosts + TLS."),{exitCode:0}},"start"),b=l(()=>{if(E(g)&&U(c)===void 0){let x=d.key;try{x=JSON.parse(B(g,"utf8")).wsKey??d.key}catch{}const P=R("POST","/unregister",{wsKey:x,root:c});z(g);const L=we(P);return e(L??(P&&P.status===200?`unregistered '${x}' from the shared gateway daemon.`:"unregister sent (the daemon may already be gone).")),{exitCode:0}}z(g);const{pid:C,healed:_}=ce(i,c);if(C===void 0)return e("gateway not running."),z(i),{exitCode:0};_&&e(`healed: found an orphaned gateway (pid ${C}) the pid file had lost \u2014 stopping it.`),de(C);let u=!1;if(!_e(6e3)){u=!0,de(C,"SIGKILL");const x=U(c);if(x!==void 0)try{process.kill(x,"SIGKILL")}catch{}else W().length>0&&e(":443 is still held by a process that is not this workspace's gateway \u2014 leaving it alone.");_e(3e3)}const y=U(c);return y!==void 0&&y!==C&&(de(y,"SIGKILL"),u=!0),z(i),u&&ae(c,t.env,()=>{}),e(`gateway stopped (pid ${C})${u?" \u2014 forced (a child ignored SIGTERM)":""}.`),{exitCode:0}},"stop"),k=l(()=>{const{pid:C,healed:_}=ce(i,c),u=C!==void 0&&ie(C)?classifyAliveGateway({oursOn443:U(c)!==void 0,port443Held:W().length>0,pidFileAgeMs:Ae(i)}):void 0,y=u==="serving"||u==="booting";if(a){const S=R("GET","/status"),j=S?.status===200&&S.json&&typeof S.json=="object"?S.json:null,F=E(g),xs=y?"daemon":j&&F?"guest":j?"other":"stopped";return e(JSON.stringify({thisWorkspace:d.key,role:xs,dashboardUrl:m,dashboardLoginUrl:me(m,c,{...process.env,...t.env??{}})??null,chooserUrl:"https://lensmcp.local/",logFile:h,daemonLogFile:(()=>{const be=Ke();return be&&be!==c?w(be,".lensmcp","gateway.log"):h})(),mcp:Be(c,t.env??process.env),daemon:j?.daemon??null,workspaces:j?.workspaces??[],services:j?.services??[]})),{exitCode:y||j&&F?0:1}}const x=R("GET","/list"),P=x?.status===200&&x.json&&typeof x.json=="object"?x.json.workspaces??[]:[],L=l(()=>{if(P.length!==0){e(` workspaces (${P.length} registered):`);for(const S of P){if(e(` \u2022 ${S.key} (${S.routes??0} routes, ${S.services??0} services)${S.key===d.key?" \u2190 this workspace":""}`),S.key===d.key||!S.root)continue;const j=me(`https://lensmcp.local${H(S.root).dashboardBasePath}/`,S.root,{...process.env,...t.env??{},LENSMCP_DASHBOARD_TOKEN:void 0});j&&e(` sign in \u2192 ${j}`)}}},"printWorkspaces"),O=l(()=>{const S=Be(c,t.env??process.env);e(S.mode==="shared"?` mcp \u2192 shared ${S.url} ${S.healthy?"(up)":S.remedy?`(REFUSED \u2014 ${S.error}; ${S.remedy})`:`(DOWN \u2014 ${S.error??"no answer"})`}`:" mcp \u2192 embedded (one server per agent session \u2014 opted out of shared)")},"printMcp"),G=l(()=>{const S=R("GET","/status"),j=S?.status===200&&S.json&&typeof S.json=="object"?S.json.daemon:void 0,F=V(c);j?.version&&F&&j.version!==F&&e(` version \u2192 the daemon runs ${j.version} but this workspace depends on ${F} \u2014 \`lensmcp upgrade\` reconciles everything (or restart the daemon workspace's gateway).`)},"printVersionSkew");if(y)return e(u==="booting"?`gateway: starting (pid ${C}) \u2014 :443 not bound yet`:`gateway: running (pid ${C}) \u2014 DAEMON on :443${_?" \u2014 recovered a stale pid file":""}`),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${m}`),f(),e(" chooser \u2192 https://lensmcp.local/"),e(` logs \u2192 ${h}`),O(),G(),L(),{exitCode:0};if(E(g)&&x?.status===200){const S=W()[0];e(`gateway: registered into a shared daemon${S!==void 0?` (pid ${S})`:""} \u2014 this workspace is a guest`),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${m}`),f(),e(` logs \u2192 ${h} (this workspace's pods)`);const j=Ke();return j&&j!==c&&e(` ${w(j,".lensmcp","gateway.log")} (the daemon's own log \u2014 gateway-level lines land there)`),e(" attach \u2192 `lensmcp logs <service>` (live, from any workspace)"),e(" stop \u2192 `lensmcp gateway stop` (unregisters; the daemon keeps running)"),O(),G(),L(),{exitCode:0}}return u==="zombie"?(e(`gateway: NOT serving \u2014 tracked pid ${C} is alive but nothing holds :443 for this workspace`),e(" (a crashed gateway under a wedged nx wrapper) \u2014 run `lensmcp gateway restart` to recover."),e(` workspace \u2192 ${d.key}`),e(` logs \u2192 ${h}`),O(),L(),{exitCode:1}):(e("gateway: stopped"),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${m}`),f(),O(),{exitCode:1})},"status"),M=l(()=>{const C=R("GET","/status");if(C?.status!==200||!C.json||typeof C.json!="object")return e(a?JSON.stringify({daemon:null,workspaces:[],services:[]}):"gateway: no daemon answers on the control socket \u2014 nothing is hosted."),{exitCode:1};const _=C.json;if(a)return e(JSON.stringify(_)),{exitCode:0};e(`daemon: pid ${_.daemon?.pid??"?"} \xB7 owner ${_.daemon?.wsKey??"?"}${_.daemon?.version?` \xB7 lensmcp ${_.daemon.version}`:""}`);for(const u of _.workspaces??[]){e(` ${u.isDaemon?"\u2605":"\xB7"} ${u.key.padEnd(16)} ${String(u.routes??0).padStart(3)} routes ${String(u.services??0).padStart(3)} services ${u.root??""}`);for(const y of(_.services??[]).filter(x=>(x.wsKey??_.daemon?.wsKey)===u.key))e(` ${y.project.padEnd(16)} ${(y.state??"unknown").padEnd(9)} ${y.host??""}`)}return{exitCode:0}},"list");switch(r){case"start":return v();case"stop":return b();case"list":return M();case"restart":return b(),ae(c,t.env,e),v();case"status":return k();default:return s(`Unknown gateway subcommand: ${r} (use start | stop | status | restart | list)`),{exitCode:2}}}p(Le,"et"),l(Le,"runGateway");function ae(t,n,e){const s=le(t);if(!s){e(" (graph refresh skipped \u2014 no nx binary found in the workspace)");return}const o={...process.env,...n??{}},r=l(a=>A(s,a,{cwd:t,env:o,stdio:"ignore"}).status===0,"tryNx");if(r(["reset","--only-daemon"])||r(["daemon","--stop"])){e(" nx project graph refreshed \u2014 a lib/app added since boot will now resolve.");return}e(" (graph refresh best-effort failed \u2014 if a new project does not resolve, run `nx reset`)")}p(ae,"ue"),l(ae,"refreshNxGraph");function Re(t,n,e,s){if(e&&s)return{project:e,target:s};const o=q(t,r=>r==="project.json");for(const r of o){let a;try{a=JSON.parse(K(r))}catch{continue}const c=a.name??pe(D(r));for(const[d,i]of Object.entries(a.targets??{}))if(i.executor===n)return{project:e??c,target:s??d}}}p(Re,"tt"),l(Re,"scanExecutorTarget");function Nt(t,n,e){return Re(t,"@lensmcp/cluster:gateway",n,e)||(n||e?{project:n??"gateway",target:e??"serve"}:void 0)}p(Nt,"ds"),l(Nt,"findGatewayTarget");function Pt(t,n,e){return Re(t,"@lensmcp/cluster:trust",n,e)||(n?{project:n,target:e??"trust"}:Et(t,"gateway")?{project:"gateway",target:e??"trust"}:void 0)}p(Pt,"ls"),l(Pt,"findTrustTarget");function Et(t,n){for(const e of q(t,s=>s==="project.json"))try{if((JSON.parse(K(e)).name??pe(D(e)))===n)return!0}catch{}return!1}p(Et,"ps"),l(Et,"projectExists");function Oe(t){const n=Vs(t);if(n)return Hs(n.pid,n.stamp)?n.pid:void 0}p(Oe,"nt"),l(Oe,"readPid");function ie(t){try{return process.kill(t,0),!0}catch(n){return n.code==="EPERM"}}p(ie,"fe"),l(ie,"isAlive");function W(){try{const t=A("lsof",["-nP","-iTCP:443","-sTCP:LISTEN","-t"],{encoding:"utf8"});return t.status!==0||!t.stdout?[]:[...new Set(t.stdout.split(/\s+/).map(Number).filter(n=>Number.isInteger(n)&&n>0))]}catch{return[]}}p(W,"U"),l(W,"pidsOnPort443");function Mt(t){try{return(A("ps",["-o","command=","-p",String(t)],{encoding:"utf8"}).stdout??"").trim()}catch{return""}}p(Mt,"us"),l(Mt,"processCmd");function U(t){const n=w(t,"node_modules","nx","dist","bin","run-executor.js"),e=w(t,"node_modules","@lensmcp","cluster");for(const s of W()){const o=Mt(s);if(o.includes(n)||o.includes(e))return s}}p(U,"J"),l(U,"gatewayOnPort443");function Ae(t){try{return Date.now()-qe(t).mtimeMs}catch{return}}p(Ae,"st"),l(Ae,"pidFileAgeMs");const lo=18e4;export function classifyAliveGateway(t){if(t.oursOn443)return"serving";const n=t.pidFileAgeMs!==void 0&&t.pidFileAgeMs<(t.bootGraceMs??lo);return!t.port443Held&&n?"booting":"zombie"}p(classifyAliveGateway,"classifyAliveGateway"),l(classifyAliveGateway,"classifyAliveGateway");function ce(t,n){const e=Oe(t);if(e!==void 0&&ie(e))return{pid:e,healed:!1};const s=U(n);if(s!==void 0){try{tt(t,s)}catch{}return{pid:s,healed:!0}}return{healed:!1}}p(ce,"he"),l(ce,"reconcileGateway");function de(t,n="SIGTERM"){try{process.kill(-t,n)}catch{try{process.kill(t,n)}catch{}}}p(de,"ge"),l(de,"killGatewayTree");function _e(t){const n=Date.now()+t;for(;;){if(W().length===0)return!0;if(Date.now()>=n)return!1;A("sleep",["0.15"])}}p(_e,"rt"),l(_e,"waitForPortFree");function Tt(t){const n=A("curl",["-s","-o","/dev/null","-m","8","-w","%{ssl_verify_result}",`https://${t}/`],{encoding:"utf8"}),e=(n.stdout??"").trim();return n.status===0&&e==="0"?"trusted":e&&e!=="0"?"untrusted":"unknown"}p(Tt,"hs"),l(Tt,"probeHostTrust");function Lt(t){for(const n of q(t,e=>e==="project.json"))try{const e=JSON.parse(B(n,"utf8")),s=(e.cluster??e.davnx)?.host;if(s&&!s.includes("*"))return s}catch{}}p(Lt,"gs"),l(Lt,"firstClusterHost");function z(t){try{Ms(t,{force:!0})}catch{}}p(z,"z"),l(z,"rmFile");async function Rt(t,n,e,s){const o=I(n,{string:["--cwd","--host","--port"]}),r=T($(o.flags["--cwd"])??t.cwd),a=ee(r),c=$(o.flags["--host"])??t.env?.LENSMCP_WS_HOST??process.env.LENSMCP_WS_HOST,d=$(o.flags["--port"])??t.env?.LENSMCP_WS_PORT??process.env.LENSMCP_WS_PORT??String(a.ports.bridge),i=us(r);if(!i)return s(`Could not locate the lensmcp bridge bundle.
289
289
  Looked in (in order):
290
290
  \u2022 <cli-package>/bundled/bridge.js (published bin)
291
291
  \u2022 <workspace>/libs/bridge/dist/main.js (dev build)
292
- For dev: \`yarn nx build @lensmcp/bridge\`.`),{exitCode:1};ue(r);const h=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(r,".lensmcp","events.jsonl"),g={...process.env,...t.env??{},LENSMCP_EVENT_FILE:h};c&&(g.LENSMCP_WS_HOST=c),d&&(g.LENSMCP_WS_PORT=d);const m=Ws(Us(q(r,v=>v==="project.json"))),f=Js(g.LENSMCP_BRIDGE_ALLOWED_ORIGINS,m);return f&&(g.LENSMCP_BRIDGE_ALLOWED_ORIGINS=f),e(`lensmcp bridge \u2192 ws://${c??"127.0.0.1"}:${d??"5747"} (forwarding to ${h})`),m.length>0&&e(` admitting this workspace's cluster hosts: ${m.join(", ")}`),{exitCode:await xe({label:`the bridge (${i})`,args:[i],cwd:r,env:g},s)}}p(Rt,"ms"),l(Rt,"runBridge");async function Ot(t,n,e,s){const o=Nn(n);if("error"in o)return s(`lensmcp dismiss: ${o.error}`),s(jn),{exitCode:2};const r=T(o.cwd??t.cwd),a={...process.env,...t.env??{}},c=await Pn(o,{session:l(d=>mn({cwd:r,env:a,budgetMs:8e3,clientName:"lensmcp-dismiss"},d),"session")});for(const d of c.lines)(c.exitCode===2?s:e)(d);return{exitCode:c.exitCode}}p(Ot,"ws"),l(Ot,"runDismiss");async function At(t,n,e,s){const o=En(n);if("error"in o)return s(`lensmcp restart: ${o.error}`),s(Mn),{exitCode:2};const r=J(T(o.cwd??t.cwd)),a=Ce(r)?r.instance:void 0,c=await Tn(o,{here:{key:r.key,baseKey:a?.baseKey??r.key,...a?{instance:a.name}:{}},request:l((d,i,h)=>R(d,i,h),"request"),now:l(()=>Date.now(),"now"),sleep:l(d=>new Promise(i=>setTimeout(i,d)),"sleep")});if(o.json)e(JSON.stringify({...c.result,answer:c.lines.join(" ")},null,2));else for(const d of c.lines)(c.exitCode===0||c.exitCode===3?e:s)(d);return{exitCode:c.exitCode}}p(At,"ys"),l(At,"runRestart");async function _t(t,n,e,s){const o=On(n);if("error"in o)return s(`lensmcp call: ${o.error}`),s(Ln),{exitCode:2};const r=T(o.cwd??t.cwd),a=J(r),c=Ce(a)?a.instance:void 0,d=await An(o,{here:{key:a.key,baseKey:c?.baseKey??a.key,...c?{instance:c.name}:{}},request:l((i,h,g)=>R(i,h,g),"request"),send:l(i=>Rn(i),"send"),readFile:l(i=>B(T(r,i),"utf8"),"readFile"),now:l(()=>Date.now(),"now")});if(o.json)e(JSON.stringify(d.result,null,2));else for(const i of d.lines)(d.exitCode===0?e:s)(i);return{exitCode:d.exitCode}}p(_t,"vs"),l(_t,"runCall");function It(t,n,e){const s=Fs(n),o=T(s.cwd??t.cwd),r=ps(o);if(!r)return e(`Could not locate the lensmcp lint runner.
292
+ For dev: \`yarn nx build @lensmcp/bridge\`.`),{exitCode:1};ue(r);const h=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(r,".lensmcp","events.jsonl"),g={...process.env,...t.env??{},LENSMCP_EVENT_FILE:h};c&&(g.LENSMCP_WS_HOST=c),d&&(g.LENSMCP_WS_PORT=d);const m=Ws(Us(q(r,v=>v==="project.json"))),f=Js(g.LENSMCP_BRIDGE_ALLOWED_ORIGINS,m);return f&&(g.LENSMCP_BRIDGE_ALLOWED_ORIGINS=f),e(`lensmcp bridge \u2192 ws://${c??"127.0.0.1"}:${d??"5747"} (forwarding to ${h})`),m.length>0&&e(` admitting this workspace's cluster hosts: ${m.join(", ")}`),{exitCode:await xe({label:`the bridge (${i})`,args:[i],cwd:r,env:g},s)}}p(Rt,"ms"),l(Rt,"runBridge");async function Ot(t,n,e,s){const o=Nn(n);if("error"in o)return s(`lensmcp dismiss: ${o.error}`),s(jn),{exitCode:2};const r=T(o.cwd??t.cwd),a={...process.env,...t.env??{}},c=await Pn(o,{session:l(d=>mn({cwd:r,env:a,budgetMs:8e3,clientName:"lensmcp-dismiss"},d),"session")});for(const d of c.lines)(c.exitCode===2?s:e)(d);return{exitCode:c.exitCode}}p(Ot,"ws"),l(Ot,"runDismiss");async function At(t,n,e,s){const o=En(n);if("error"in o)return s(`lensmcp restart: ${o.error}`),s(Mn),{exitCode:2};const r=H(T(o.cwd??t.cwd)),a=he(r)?r.instance:void 0,c=await Tn(o,{here:{key:r.key,baseKey:a?.baseKey??r.key,...a?{instance:a.name}:{}},request:l((d,i,h)=>R(d,i,h),"request"),now:l(()=>Date.now(),"now"),sleep:l(d=>new Promise(i=>setTimeout(i,d)),"sleep")});if(o.json)e(JSON.stringify({...c.result,answer:c.lines.join(" ")},null,2));else for(const d of c.lines)(c.exitCode===0||c.exitCode===3?e:s)(d);return{exitCode:c.exitCode}}p(At,"ys"),l(At,"runRestart");async function _t(t,n,e,s){const o=On(n);if("error"in o)return s(`lensmcp call: ${o.error}`),s(Ln),{exitCode:2};const r=T(o.cwd??t.cwd),a=H(r),c=he(a)?a.instance:void 0,d=await An(o,{here:{key:a.key,baseKey:c?.baseKey??a.key,...c?{instance:c.name}:{}},request:l((i,h,g)=>R(i,h,g),"request"),send:l(i=>Rn(i),"send"),readFile:l(i=>B(T(r,i),"utf8"),"readFile"),now:l(()=>Date.now(),"now")});if(o.json)e(JSON.stringify(d.result,null,2));else for(const i of d.lines)(d.exitCode===0?e:s)(i);return{exitCode:d.exitCode}}p(_t,"vs"),l(_t,"runCall");function It(t,n,e){const s=Fs(n),o=T(s.cwd??t.cwd),r=ps(o);if(!r)return e(`Could not locate the lensmcp lint runner.
293
293
  Looked in (in order):
294
294
  \u2022 <cli-package>/bundled/lint-runner.js (published bin)
295
295
  \u2022 <workspace>/libs/session/dist/lint-runner.js (dev build)
296
- For dev: \`yarn nx build @lensmcp/session\`.`),{exitCode:2};const a=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(o,".lensmcp","events.jsonl");return{exitCode:A(process.execPath,[r,...s.runnerArgs],{cwd:o,stdio:"inherit",env:{...process.env,...t.env??{},LENSMCP_EVENT_FILE:a}}).status??2}}p(It,"ks"),l(It,"runLint");function Ie(t,n,e,s){const o=I(n,{string:["--cwd","--register-host-config"],boolean:["--skip-format","--yes"]}),r=T($(o.flags["--cwd"])??t.cwd);if(!E(w(r,"nx.json")))return s(`No nx.json found at ${r}.`),s("Run `lensmcp install` from inside a Nx workspace."),{exitCode:1};const a=le(r);if(!a)return s("Could not find the `nx` binary in the host workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};const c=["g","@lensmcp/nx-plugin:init","--no-interactive"];return o.flags["--skip-format"]===!0&&c.push("--skipFormat"),o.flags["--register-host-config"]&&c.push(`--registerHostConfig=${String(o.flags["--register-host-config"])}`),e(`> ${a} ${c.join(" ")}`),{exitCode:A(a,c,{cwd:r,stdio:"inherit",env:{...process.env,...t.env??{}}}).status??1}}p(Ie,"ot"),l(Ie,"runInstall");function De(t,n,e,s){const o=I(n,{string:["--cwd","--project","--target"]}),r=T($(o.flags["--cwd"])??t.cwd);if(!E(w(r,"nx.json")))return s(`No nx.json found at ${r}.`),s("Run `lensmcp trust` from inside a Nx workspace (after `lensmcp install`)."),{exitCode:1};const a=le(r);if(!a)return s("Could not find the `nx` binary in the workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};const c=Pt(r,$(o.flags["--project"]),$(o.flags["--target"])),d=R("GET","/list"),i=d?.status===200&&W(r)===void 0;if(!c){if(s("This workspace has no trust target \u2014 no project declares the `@lensmcp/cluster:trust` executor."),s(""),i){const g=St();s(` A shared gateway daemon${g?` (owned by '${g}')`:""} already serves this workspace, and`),s(" TLS rides ITS certificate authority. Run `lensmcp trust` in THAT workspace \u2014 it owns the CA \u2014"),s(" and this workspace is trusted too (restart the browser once if it cached a cert error).")}else s(" \u2022 Should this workspace own its gateway (and its CA)? Scaffold it first: `lensmcp install`,"),s(" then re-run `lensmcp trust`."),s(" \u2022 Joining a shared gateway? Run `lensmcp trust` in the workspace that owns the daemon.");return s(" \u2022 Already have a differently-named target? `lensmcp trust --project <p> --target <t>`."),{exitCode:1}}hs()||e(" note: trust runs `sudo` for the CA + /etc/hosts \u2014 run it in a real terminal if a step is needed."),i&&(e(" a shared gateway daemon serves this workspace \u2014 TLS rides ITS (already-trusted) CA, not a separate"),e(" one here. Setting up /etc/hosts only (trusting the CA is the DAEMON workspace's job).")),e(`> ${a} run ${c.project}:${c.target} (sudo prompts inline for ${i?"/etc/hosts":"the CA + /etc/hosts"})`);const h=A(a,["run",`${c.project}:${c.target}`],{cwd:r,stdio:"inherit",env:{...process.env,...t.env??{},...i?{LENSMCP_TRUST_HOSTS_ONLY:"1"}:{}}});if(i&&h.status===0){const g=Lt(r);if(g){const m=Tt(g);e(""),m==="trusted"?e(` \u2713 ${g} \u2192 served by the daemon with a TRUSTED cert \u2014 you're set (restart the browser once if it cached an error).`):m==="untrusted"&&!(d?.json?.workspaces??[]).some(f=>f.key===J(r).key)?e(` ? ${g} \u2192 not on the daemon's cert yet \u2014 a workspace's hosts join it when the workspace registers (\`lensmcp gateway start\`, or setup's next step). Still refused after that? Run \`lensmcp trust\` in the DAEMON workspace.`):e(m==="untrusted"?` \u2717 ${g} \u2192 the daemon's cert is NOT trusted yet. Run \`lensmcp trust\` in the DAEMON workspace (it owns the CA), then restart your browser.`:` ? ${g} \u2192 couldn't reach it to verify (is the daemon running?). /etc/hosts is set; TLS rides the daemon's CA.`)}}return{exitCode:h.status??1}}p(De,"it"),l(De,"runTrust");function Fe(t){const n=V(t)??Y(),e=Ks(K(w(t,".lensmcp","config.json")));return{version:n,...e?{configHash:e}:{}}}p(Fe,"at"),l(Fe,"currentRecycleStamp");function Ge(t){const n=Q(w(t,".lensmcp","setup-state.json"))?.recycled;return n&&typeof n=="object"?n:void 0}p(Ge,"ct"),l(Ge,"readRecycleStamp");function Dt(t,n){ue(t);const e={version:Y(),completedAt:new Date().toISOString(),steps:{install:!0,trust:!0},recycled:n?Fe(t):Ge(t)??{}};try{X(w(t,".lensmcp","setup-state.json"),`${JSON.stringify(e,null,2)}
297
- `)}catch{}}p(Dt,"$s"),l(Dt,"writeSetupState");async function Ft(t,n,e,s){const o=st(n)?sn(t,n):void 0,r=!o&&Ne(t),a=te(t,e),c=o?{mode:o.mode,source:"flag"}:a,d=c.mode;if(s(""),s(`[mcp] mode \u2192 ${d} (${nt[c.source]})`),o?.wrote&&s(` wrote ${en}`),r&&s(` ${je}`),d==="embedded"){s(" every agent session builds its OWN MCP server, and keeps serving"),s(" the bundle it started with until that session exits."),s(` ${me(c)}`);return}s(` sessions proxy into ONE shared server at ${a.url}`),s(" .mcp.json is unchanged \u2014 `lensmcp mcp` is a thin stdio shim into it."),s(` ${me(c)}`);const i=await ot(a.url);if(!i.ok&&!i.remedy){s(` \xB7 not up yet (${i.error??"unknown"}) \u2014 the next session starts it on demand`);return}i.ok||s(` ! refused: ${i.error}`);const h=V(t)??Y(),g=Se({identity:Pe(a.port),targetVersion:h,expectedRoot:ye(t),expectedKey:Z(t).key,port:a.port,selfPid:process.pid});if(!g.kill){s(i.ok?` \u2713 already up \u2014 ${i.server??"MCP"} (protocol ${i.protocolVersion??"?"}) \u2014 ${g.reason}`:` ! not restarted (${g.reason}) \u2014 ${i.remedy}`);return}try{process.kill(g.pid,"SIGTERM"),s(` \u21BA restarted the shared server \u2014 it was ${g.reason}; the next session brings it up on ${h}`)}catch(m){s(` ! the shared server is ${g.reason} and could not be stopped (pid ${g.pid}): ${m.message}`)}}p(Ft,"bs"),l(Ft,"applyMcpModeStep");function Gt(t,n,e){const s=ut({cwd:t,cliVersion:Y()}),o=Bn({run:Kn(n),facts:s,installed:l(()=>Te(t)?.version,"installed")});if(!(o.outcome==="current"||o.outcome==="unknown")){if(e(""),o.outcome==="ahead"){e(`[plugin] ${o.from} \u2014 newer than this workspace's lensmcp ${o.to}; another workspace's lensmcp installed it, and it stays.`),e(" `lensmcp upgrade` brings this workspace up to it.");return}if(o.outcome==="updated"){e(`[plugin] ${o.from} \u2192 ${o.to}`),e(" restart Claude Code for the new plugin to load.");return}e(`[plugin] the Claude Code plugin is ${o.from}, this lensmcp is ${o.to}.`),e(` could not update it automatically (${o.detail??"unknown reason"}). Run:`);for(const r of o.commands??[])e(` ${r}`);e(" \u2026then restart Claude Code.")}}p(Gt,"Cs"),l(Gt,"applyPluginSyncStep");async function Kt(t,n,e,s){const o=I(n,{string:["--cwd","--mcp"],boolean:["--no-recycle"]}),r=T($(o.flags["--cwd"])??t.cwd),a={...t,cwd:r},c=$(o.flags["--mcp"]);if(c!==void 0&&!st(c))return s(`setup: --mcp must be "embedded" or "shared" (got "${c}").`),{exitCode:1};e("lensmcp setup \u2014 first-time bootstrap (install \u2192 trust \u2192 pods)"),e(""),e("[1/3] install \u2014 plugin, .mcp.json, nx config, vite/nest wiring");const d=Ie(a,n,e,s);if(d.exitCode!==0)return s(""),s("setup: the install step failed \u2014 fix the above and re-run `lensmcp setup`."),d;e(""),e("[2/3] trust \u2014 dev CA \u2192 System keychain, /etc/hosts, DNS flush (sudo)");const i=De(a,n,e,s);if(i.exitCode!==0)return s(""),s("setup: the trust step failed \u2014 run `lensmcp setup` directly in a terminal so sudo can prompt."),i;e(""),e("[3/3] pods \u2014 recycle this workspace's devservers, reconcile the gateway");const h=Z(r),g=h.key,m=Gs({previous:Ge(r),current:Fe(r),disabled:o.flags["--no-recycle"]===!0}),f=m.recycle?ws(r,he(h),e,m.reason):(e(` \xB7 pods left running \u2014 ${m.reason}`),{killed:0,stale:0});ys(a,r,g,e),await Ft(r,c,t.env??process.env,e);try{Gt(r,{...process.env,...t.env??{}},e)}catch{}return Dt(r,m.recycle),e(""),e("\u2713 setup complete."),(f.killed>0||f.stale>0)&&e(` recycled ${f.killed} pod${f.killed===1?"":"s"}`+(f.stale>0?` (+${f.stale} stale socket${f.stale===1?"":"s"} cleared)`:"")+" \u2014 they come back on the new wiring."),e(" next: lensmcp gateway start (the :443 front door \u2014 needs sudo)"),e(" verify: lensmcp doctor"),{exitCode:0}}p(Kt,"Ss"),l(Kt,"runSetup");async function Bt(t,n){if(n[0]!=="asked")return{exitCode:0};const e=await new Promise(s=>{if(process.stdin.isTTY){s("");return}let o="";const r=setTimeout(()=>s(o),2e3);r.unref?.(),process.stdin.setEncoding("utf8"),process.stdin.on("data",a=>{o+=a,o.length>1e6&&(clearTimeout(r),s(o))}),process.stdin.on("end",()=>{clearTimeout(r),s(o)}),process.stdin.on("error",()=>{clearTimeout(r),s(o)})});return Ys(e,{env:{...process.env,...t.env??{}},cwd:t.cwd}),{exitCode:0}}p(Bt,"js"),l(Bt,"runAgent");async function Vt(t,n,e){const s=I(n,{string:["--cwd","--hook","--timeout","--session"],boolean:["--json","--quiet"]}),o=T($(s.flags["--cwd"])??t.cwd),r=$(s.flags["--hook"]),a=at(r)?r:void 0,c=$(s.flags["--session"]);if(r!==void 0&&a===void 0)return{exitCode:0};const d=s.flags["--json"]===!0,i=s.flags["--quiet"]===!0||r!==void 0,h=Number($(s.flags["--timeout"])??""),g=Number.isFinite(h)&&h>0?h:hn,m={...process.env,...t.env??{}};try{const f=await gn({cwd:o,env:m,budgetMs:g,verify:l(k=>cn(k).map(M=>M.resource),"verify")});if(!f.available)return d&&!i?e(JSON.stringify({available:!1,workspace:f.source.workspace,mode:f.source.mode,reason:f.reason,elapsedMs:f.elapsedMs})):i||e(`lensmcp status \u2014 ${f.source.workspace}: unavailable (${f.reason})`),{exitCode:0};const v=pn(f.status,f.evidence,Date.now()),b=un(v,{workspace:f.source.workspace,includeUnmonitored:a==="SessionStart"||!i});if(d)return i&&b===void 0?{exitCode:0}:(e(JSON.stringify({available:!0,workspace:f.source.workspace,mode:f.source.mode,url:f.source.url,aggregate:f.status.status??"unknown",elapsedMs:f.elapsedMs,findings:v.findings,suppressed:v.suppressed,unmonitored:v.unmonitored})),{exitCode:0});if(a){const k=ln(v.findings);return Zs(c,k)?(b!==void 0&&e(rt(a,b)),c&&Xs(c,k),{exitCode:0}):{exitCode:0}}if(i)return b!==void 0&&e(b),{exitCode:0};if(e(`lensmcp status \u2014 ${f.source.workspace} (${f.source.mode}, ${f.source.url})`),e(` aggregate says: ${f.status.status??"unknown"} (read in ${f.elapsedMs}ms)`),v.findings.length===0)e(" nothing actionable that this command can vouch for.");else for(const k of v.findings)e(` \u2022 ${dn(k)}`);for(const k of v.suppressed)e(` \xB7 not reported \u2014 ${k.kind}: ${k.reason}`);return v.unmonitored.length>0&&e(` \xB7 unmonitored (unknown, NOT clean): ${v.unmonitored.join(", ")}`),{exitCode:0}}catch(f){return i||e(`lensmcp status: unavailable (${f instanceof Error?f.message:String(f)})`),{exitCode:0}}}p(Vt,"xs"),l(Vt,"runStatus");function Ht(t,n,e){const s=I(n,{string:["--cwd","--hook","--plugin-root"],boolean:["--json","--quiet"]}),o=T($(s.flags["--cwd"])??t.cwd),r=$(s.flags["--hook"]),a=at(r)?r:void 0;if(r!==void 0&&a===void 0)return{exitCode:0};const c=s.flags["--json"]===!0,d=s.flags["--quiet"]===!0||r!==void 0,i=$(s.flags["--plugin-root"]);try{const h=ut({cwd:o,cliVersion:Y(),...i?{pluginRoot:i}:{}}),g=Gn(h);if(c)return d&&!g?{exitCode:0}:(e(JSON.stringify({...h,skew:g??null})),{exitCode:0});if(a)return g&&e(rt(a,dt(g))),{exitCode:0};if(d)return g&&e(dt(g)),{exitCode:0};if(e(`lensmcp version-check \u2014 ${h.pluginId??"lensmcp plugin"}`),e(` plugin ${h.plugin??"unknown"}${h.pluginSource?` (${h.pluginSource})`:""}`),e(` project ${h.project??"unknown"} (node_modules/lensmcp)`),e(` cli ${h.cli??"unknown"} (the binary running now)`),!g)return e(h.plugin&&(h.project??h.cli)?" \u2713 in step.":" ? cannot compare \u2014 one of the versions is unreadable (staying silent)."),{exitCode:0};e(` \u2717 the plugin is ${g.direction} \u2014 update it, then restart Claude Code:`);for(const m of Vn(g))e(` ${m}`);return{exitCode:0}}catch(h){return d||e(`lensmcp version-check: unavailable (${h instanceof Error?h.message:String(h)})`),{exitCode:0}}}p(Ht,"Ps"),l(Ht,"runVersionCheck");async function Wt(t,n,e){const s=I(n,{string:["--cwd"],boolean:["--json"]}),o=T($(s.flags["--cwd"])??t.cwd),r=s.flags["--json"]===!0,a=[];Ut(a),Jt(o,a),qt(o,a),zt(o,t.env??process.env,a),await Yt(o,t.env??process.env,a),Xt(o,a),Zt(o,a),Qt(o,a),es(a),await Cs(o,a),await Ss(o,t.env??process.env,a);const c=a.some(i=>i.status==="fail"),d=a.some(i=>i.status==="warn");if(r)return e(JSON.stringify({ok:!c,summary:{total:a.length,failed:a.filter(i=>i.status==="fail").length,warnings:a.filter(i=>i.status==="warn").length},checks:a},null,2)),{exitCode:c?1:0};for(const i of a){const h=i.status==="pass"?"\u2713":i.status==="info"?"\xB7":i.status==="warn"?"!":"\u2717";e(`${h} ${i.label}${i.detail?` \u2014 ${i.detail}`:""}`),i.status!=="pass"&&i.hint&&e(` \u21B3 ${i.hint}`)}return e(""),e(c?"doctor: issues found (see \u2717 above).":d?"doctor: ok, with warnings (!).":"doctor: all checks passed."),{exitCode:c?1:0}}p(Wt,"Es"),l(Wt,"runDoctor");function N(t,n,e,s,o){t.push({status:n,label:e,detail:s,hint:o})}p(N,"x"),l(N,"add");function Ut(t){const n=Number(process.versions.node.split(".")[0]);n>=20?N(t,"pass",`Node ${process.versions.node}`):n>=18?N(t,"warn",`Node ${process.versions.node}`,"older than recommended","upgrade to Node 20+ for best results"):N(t,"fail",`Node ${process.versions.node}`,"too old","LensMCP needs Node 18+ (20+ recommended)")}p(Ut,"Ns"),l(Ut,"checkNode");function Jt(t,n){const e=w(t,"nx.json");if(!E(e)){N(n,"fail","nx.json at workspace root","missing","run `lensmcp` from inside a Nx workspace");return}let s;try{s=JSON.parse(B(e,"utf8"))}catch(r){N(n,"fail","nx.json parses",r.message,"fix the JSON syntax in nx.json");return}const o=(s.plugins??[]).some(r=>typeof r=="string"?r==="@lensmcp/nx-plugin":!!r&&typeof r=="object"&&r.plugin==="@lensmcp/nx-plugin");N(n,o?"pass":"fail","@lensmcp/nx-plugin registered in nx.json#plugins",o?void 0:"not registered",o?void 0:"run `lensmcp install`"),N(n,s.lensmcp?.schemaVersion===1?"pass":"warn","lensmcp config block in nx.json",s.lensmcp?.schemaVersion===1?void 0:"missing",s.lensmcp?.schemaVersion===1?void 0:"run `lensmcp install` to write the config defaults")}p(Jt,"Ms"),l(Jt,"checkWorkspace");function qt(t,n){const e=w(t,".mcp.json");if(!E(e)){N(n,"warn",".mcp.json with a lensmcp server","missing","run `lensmcp install` so agents auto-discover the MCP server");return}try{const s=JSON.parse(B(e,"utf8")),o=!!s.mcpServers&&!!s.mcpServers.lensmcp;N(n,o?"pass":"warn",".mcp.json registers the lensmcp MCP server",o?void 0:"no lensmcp entry",o?void 0:"run `lensmcp install`")}catch(s){N(n,"warn",".mcp.json parses",s.message,"fix the JSON syntax in .mcp.json")}}p(qt,"Ts"),l(qt,"checkMcpConfig");function zt(t,n,e){const s=Q(w(t,".claude","settings.json")),o=Q(w(t,".claude","settings.local.json")),r=ht({cwd:t}),a=r?Q(w(r.root,"plugin",".mcp.json")):void 0,c=Qe(a),d=lt(),i=et(s,se)||et(o,se)||d.some(g=>g.scope==="user"||g.projectPath===t),h=Bs({workspaceServers:Qe(Q(w(t,".mcp.json"))),pluginServers:c,pluginEnabled:i,pluginReadable:a!==void 0,disabledServers:[...Ze(s),...Ze(o)],mcpMode:te(t,n).mode});N(e,h.duplicated||h.indeterminate?"warn":"pass","the MCP server is registered exactly once",h.duplicated||h.indeterminate?h.detail:void 0,h.duplicated||h.indeterminate?h.hint:void 0)}p(zt,"Ls"),l(zt,"checkDuplicateRegistration");function Ke(){const t=R("GET","/status");if(!t||t.status!==200)return;const n=t.json?.daemon,e=t.json?.workspaces;if(!(!n?.wsKey||!Array.isArray(e)))return e.find(s=>s.key===n.wsKey)?.root}p(Ke,"dt"),l(Ke,"daemonOwnerRoot");function Q(t){try{return JSON.parse(B(t,"utf8"))}catch{return}}p(Q,"te"),l(Q,"readJsonFile");async function Yt(t,n,e){Ne(t)&&N(e,"info","MCP mode pin",je);const s=te(t,n),o=nt[s.source];if(N(e,"pass","MCP mode",s.mode==="shared"?`shared (${o}) \u2014 sessions proxy into ${s.url}`:`embedded (${o}) \u2014 one MCP server per agent session; ${me(s)}`,me(s)),s.mode!=="shared")return;const r=await ot(s.url);if(r.ok){N(e,"pass","shared MCP server",`${r.server??"MCP"} @ ${s.url} (protocol ${r.protocolVersion??"?"})`);return}if(r.remedy){N(e,"warn","shared MCP server",`not usable at ${s.url} \u2014 ${r.error??"refused"}`,r.remedy);return}const a=qs(t);if(a.length===0){N(e,"info","shared MCP server",`not running at ${s.url} \u2014 no agent session is open on this workspace; the next one starts it`,"`lensmcp gateway start` starts it now");return}const c=`${a.length} agent session${a.length===1?" is":"s are"} open (pid ${a.join(", ")})`;N(e,"warn","shared MCP server",`not running at ${s.url} \u2014 ${r.error??"no answer"}, yet ${c}`,"each is on an embedded fallback or restarts the server on its next call \u2014 its stderr names why it could not attach; `lensmcp gateway start` starts it now")}p(Yt,"Rs"),l(Yt,"checkMcpMode");function Be(t,n){const e=te(t,n);if(e.mode!=="shared")return{mode:e.mode,url:e.url,port:e.port,healthy:!1};const s=tn(e.url);return{mode:e.mode,url:e.url,port:e.port,healthy:s.ok,...s.server?{server:s.server}:{},...s.error?{error:s.error}:{},...s.remedy?{remedy:s.remedy}:{}}}p(Be,"lt"),l(Be,"mcpStatusBlock");function Xt(t,n){const e=He(t);N(n,e?"pass":"fail","lensmcp-mcp server bundle reachable",e??"missing",e?void 0:`dev: \`yarn nx build ${Fn}\``)}p(Xt,"Os"),l(Xt,"checkServerBundle");function Zt(t,n){const e=w(t,".lensmcp");N(n,E(e)?"pass":"warn",".lensmcp/ runtime directory",E(e)?void 0:"not created yet",E(e)?void 0:"created automatically on first `lensmcp mcp` run");const s=$n(t);N(n,s.runtimeIgnored?"pass":"warn",".gitignore keeps .lensmcp/ runtime state out of git",s.runtimeIgnored?void 0:"not ignored \u2014 events, logs and tokens could be committed",s.runtimeIgnored?void 0:"add `**/.lensmcp/*` to .gitignore (lensmcp install does this)"),N(n,s.sharedIgnored.length?"warn":"pass",`.gitignore keeps the team's .lensmcp folders (${kn.map(o=>`${o}/`).join(", ")})`,s.sharedIgnored.length?`${s.by} ignores ${s.sharedIgnored.map(o=>`.lensmcp/${o}/`).join(", ")} \u2014 the analyzer instructions in it would not reach the team`:void 0,s.sharedIgnored.length?"ignore `**/.lensmcp/*` instead of `.lensmcp/` and add `!**/.lensmcp/<folder>/` for each \u2014 lensmcp install rewrites it":void 0)}p(Zt,"_s"),l(Zt,"checkRuntimeDir");function Qt(t,n){const e=q(t,d=>/^vite\.config\.[cm]?[jt]s$/.test(d)),s=e.filter(d=>/lensmcpVitePlugin|@lensmcp\/vite-plugin/.test(K(d)));if(e.length>0){const d=s.length===e.length;N(n,d?"pass":"warn",`Vite wiring: ${s.length}/${e.length} config(s) use the LensMCP plugin`,void 0,d?void 0:"wire each: `nx g @lensmcp/nx-plugin:setup-vite <project>`")}const o=q(t,d=>d==="main.ts").filter(d=>/NestFactory\.create|createLensmcpNestApp/.test(K(d))),r=o.filter(d=>/createLensmcpNestApp/.test(K(d)));if(o.length>0){const d=r.length===o.length;N(n,d?"pass":"warn",`Nest wiring: ${r.length}/${o.length} bootstrap(s) use createLensmcpNestApp`,void 0,d?void 0:"wire each: `nx g @lensmcp/nx-plugin:setup-nest <project>`")}const a=q(t,d=>d==="project.json"||d==="package.json").map(d=>K(d)),c=a.filter(d=>/"agent-dev"/.test(d));a.some(d=>/@lensmcp\/cluster:gateway/.test(d))?N(n,"pass","dev lifecycle: cluster gateway owns it (agent-dev not required)",c.length>0?`${c.length} project(s) ALSO declare agent-dev \u2014 that races the gateway`:void 0,c.length>0?"remove agent-dev from gateway-managed projects; the gateway already serves them":void 0):N(n,c.length>0?"pass":"warn",`agent-dev targets: ${c.length} project(s)`,void 0,c.length>0?void 0:"no project wired \u2014 run setup-vite / setup-nest")}p(Qt,"As"),l(Qt,"checkProjectWiring");function es(t){const n=process.env.CHROME_PATH,e=process.platform==="darwin"?["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium"]:process.platform==="win32"?["C:/Program Files/Google/Chrome/Application/chrome.exe","C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"]:["/usr/bin/google-chrome","/usr/bin/chromium-browser","/usr/bin/chromium","/usr/bin/google-chrome-stable"],s=(n&&E(n)?n:void 0)??e.find(o=>E(o));N(t,s?"pass":"warn","Chrome for browser:// capture",s?pe(s):"not found",s?void 0:"install Chrome or set CHROME_PATH (only needed for browser capture)")}p(es,"Is"),l(es,"checkChrome");function K(t){try{return B(t,"utf8")}catch{return""}}p(K,"K"),l(K,"safeRead");function ts(t,n,e,s){const o=I(n,{string:["--cwd","--from","--scope"]}),r=(o.positional[0]??"").toLowerCase();if(r!=="install"&&r!=="status")return s("Usage: lensmcp plugin <install|status> [claude|codex] [--from <dir>] [--scope <user|project|local>] [--cwd <dir>]"),{exitCode:2};const a=T($(o.flags["--cwd"])??t.cwd),c=o.positional[1]?.toLowerCase(),d=c?Hn(c):void 0;if(c&&!d)return s(`Unknown agent: ${c} (use claude | codex)`),{exitCode:2};const i=d?[d]:[...pt],h=$(o.flags["--from"]),g=ht({cwd:a,...h?{from:h}:{},selfRoot:ne()});if(!g)return s("Could not find a lensmcp package to install the plugins from."),s("Run inside a workspace with lensmcp installed, or pass --from <package-root>."),{exitCode:1};e(`plugin package: ${g.root}${g.version?` (lensmcp ${g.version})`:""}`+(g.source==="self"?" \u2014 the running CLI itself (no workspace install found; prefer a workspace)":""));const m=gt({...process.env,...t.env??{}});if(r==="status"){for(const b of i){const k=qn(g.root,b),M=b.id==="claude"?Te(a)?.version:Wn(m),C=M?k?M===k?`installed ${M} \u2014 current`:`installed ${M}, the package ships ${k} \u2014 \`lensmcp plugin install ${b.id}\``:`installed ${M} (this package ships no ${b.label} plugin \u2014 it arrived in ${b.since})`:`not installed \u2014 \`lensmcp plugin install ${b.id}\``;e(` ${b.label.padEnd(11)} \u2192 ${C}`)}return{exitCode:0}}const f=$(o.flags["--scope"]);let v=!1;for(const b of i){const k=b.id==="claude"?f??Te(a)?.scope:void 0,M=Un(b,{root:g.root,...k?{scope:k}:{}},{run:m});switch(M.outcome){case"installed":e(` ${b.label.padEnd(11)} \u2192 installed${M.version?` ${M.version}`:""} \u2014 ${M.restartHint}`);break;case"skipped-no-cli":d&&(v=!0),e(` ${b.label.padEnd(11)} \u2192 skipped (${M.detail})`);break;case"skipped-not-packaged":d&&(v=!0),e(` ${b.label.padEnd(11)} \u2192 skipped \u2014 ${M.detail}`);break;case"failed":v=!0,s(` ${b.label.padEnd(11)} \u2192 FAILED \u2014 ${M.detail}`),s(` run by hand:${M.commands.map(C=>`
298
- ${C}`).join("")}`);break}}return{exitCode:v?1:0}}p(ts,"Ds"),l(ts,"runPlugin");function Ve(){const t=R("GET","/status");if(t?.status!==200||!t.json||typeof t.json!="object")return{registeredKeys:[]};const n=t.json;return{...typeof n.daemon?.wsKey=="string"?{wsKey:n.daemon.wsKey}:{},...typeof n.daemon?.version=="string"?{version:n.daemon.version}:{},registeredKeys:(n.workspaces??[]).flatMap(e=>typeof e.key=="string"?[e.key]:[])}}p(Ve,"pt"),l(Ve,"snapshotDaemon");function ss(t){let n=T(t);for(let e=0;e<8;e++){const s=w(n,"package.json");if(E(s)&&/"(?:lensmcp|@lensmcp\/[^"]+)"\s*:/.test(K(s)))return{key:J(n).key,root:n};const o=D(n);if(o===n)break;n=o}}p(ss,"Fs"),l(ss,"findLensmcpWorkspace");function ns(t,n,e,s=!1){if(t){const a=t.replace(/^v/,"");if(!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(a)){e(`Not a version: ${t} (expected e.g. 1.20.1)`);return}if(!s&&no(n("npm",["view",`lensmcp@${a}`,"version"]),a)==="absent"){const c=n("npm",["view","lensmcp","version"]),d=c&&c.code===0?(c.stdout??"").trim().split(`
296
+ For dev: \`yarn nx build @lensmcp/session\`.`),{exitCode:2};const a=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(o,".lensmcp","events.jsonl");return{exitCode:A(process.execPath,[r,...s.runnerArgs],{cwd:o,stdio:"inherit",env:{...process.env,...t.env??{},LENSMCP_EVENT_FILE:a}}).status??2}}p(It,"ks"),l(It,"runLint");function Ie(t,n,e,s){const o=I(n,{string:["--cwd","--register-host-config"],boolean:["--skip-format","--yes"]}),r=T($(o.flags["--cwd"])??t.cwd);if(!E(w(r,"nx.json")))return s(`No nx.json found at ${r}.`),s("Run `lensmcp install` from inside a Nx workspace."),{exitCode:1};const a=le(r);if(!a)return s("Could not find the `nx` binary in the host workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};const c=["g","@lensmcp/nx-plugin:init","--no-interactive"];return o.flags["--skip-format"]===!0&&c.push("--skipFormat"),o.flags["--register-host-config"]&&c.push(`--registerHostConfig=${String(o.flags["--register-host-config"])}`),e(`> ${a} ${c.join(" ")}`),{exitCode:A(a,c,{cwd:r,stdio:"inherit",env:{...process.env,...t.env??{}}}).status??1}}p(Ie,"ot"),l(Ie,"runInstall");function De(t,n,e,s){const o=I(n,{string:["--cwd","--project","--target"]}),r=T($(o.flags["--cwd"])??t.cwd);if(!E(w(r,"nx.json")))return s(`No nx.json found at ${r}.`),s("Run `lensmcp trust` from inside a Nx workspace (after `lensmcp install`)."),{exitCode:1};const a=le(r);if(!a)return s("Could not find the `nx` binary in the workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};const c=Pt(r,$(o.flags["--project"]),$(o.flags["--target"])),d=R("GET","/list"),i=d?.status===200&&U(r)===void 0;if(!c){if(s("This workspace has no trust target \u2014 no project declares the `@lensmcp/cluster:trust` executor."),s(""),i){const g=St();s(` A shared gateway daemon${g?` (owned by '${g}')`:""} already serves this workspace, and`),s(" TLS rides ITS certificate authority. Run `lensmcp trust` in THAT workspace \u2014 it owns the CA \u2014"),s(" and this workspace is trusted too (restart the browser once if it cached a cert error).")}else s(" \u2022 Should this workspace own its gateway (and its CA)? Scaffold it first: `lensmcp install`,"),s(" then re-run `lensmcp trust`."),s(" \u2022 Joining a shared gateway? Run `lensmcp trust` in the workspace that owns the daemon.");return s(" \u2022 Already have a differently-named target? `lensmcp trust --project <p> --target <t>`."),{exitCode:1}}hs()||e(" note: trust runs `sudo` for the CA + /etc/hosts \u2014 run it in a real terminal if a step is needed."),i&&(e(" a shared gateway daemon serves this workspace \u2014 TLS rides ITS (already-trusted) CA, not a separate"),e(" one here. Setting up /etc/hosts only (trusting the CA is the DAEMON workspace's job).")),e(`> ${a} run ${c.project}:${c.target} (sudo prompts inline for ${i?"/etc/hosts":"the CA + /etc/hosts"})`);const h=A(a,["run",`${c.project}:${c.target}`],{cwd:r,stdio:"inherit",env:{...process.env,...t.env??{},...i?{LENSMCP_TRUST_HOSTS_ONLY:"1"}:{}}});if(i&&h.status===0){const g=Lt(r);if(g){const m=Tt(g);e(""),m==="trusted"?e(` \u2713 ${g} \u2192 served by the daemon with a TRUSTED cert \u2014 you're set (restart the browser once if it cached an error).`):m==="untrusted"&&!(d?.json?.workspaces??[]).some(f=>f.key===H(r).key)?e(` ? ${g} \u2192 not on the daemon's cert yet \u2014 a workspace's hosts join it when the workspace registers (\`lensmcp gateway start\`, or setup's next step). Still refused after that? Run \`lensmcp trust\` in the DAEMON workspace.`):e(m==="untrusted"?` \u2717 ${g} \u2192 the daemon's cert is NOT trusted yet. Run \`lensmcp trust\` in the DAEMON workspace (it owns the CA), then restart your browser.`:` ? ${g} \u2192 couldn't reach it to verify (is the daemon running?). /etc/hosts is set; TLS rides the daemon's CA.`)}}return{exitCode:h.status??1}}p(De,"it"),l(De,"runTrust");function Fe(t){const n=V(t)??Y(),e=Ks(K(w(t,".lensmcp","config.json")));return{version:n,...e?{configHash:e}:{}}}p(Fe,"at"),l(Fe,"currentRecycleStamp");function Ge(t){const n=Z(w(t,".lensmcp","setup-state.json"))?.recycled;return n&&typeof n=="object"?n:void 0}p(Ge,"ct"),l(Ge,"readRecycleStamp");function Dt(t,n){ue(t);const e={version:Y(),completedAt:new Date().toISOString(),steps:{install:!0,trust:!0},recycled:n?Fe(t):Ge(t)??{}};try{X(w(t,".lensmcp","setup-state.json"),`${JSON.stringify(e,null,2)}
297
+ `)}catch{}}p(Dt,"$s"),l(Dt,"writeSetupState");async function Ft(t,n,e,s){const o=st(n)?sn(t,n):void 0,r=!o&&Ne(t),a=te(t,e),c=o?{mode:o.mode,source:"flag"}:a,d=c.mode;if(s(""),s(`[mcp] mode \u2192 ${d} (${nt[c.source]})`),o?.wrote&&s(` wrote ${en}`),r&&s(` ${je}`),d==="embedded"){s(" every agent session builds its OWN MCP server, and keeps serving"),s(" the bundle it started with until that session exits."),s(` ${fe(c)}`);return}s(` sessions proxy into ONE shared server at ${a.url}`),s(" .mcp.json is unchanged \u2014 `lensmcp mcp` is a thin stdio shim into it."),s(` ${fe(c)}`);const i=await ot(a.url);if(!i.ok&&!i.remedy){s(` \xB7 not up yet (${i.error??"unknown"}) \u2014 the next session starts it on demand`);return}i.ok||s(` ! refused: ${i.error}`);const h=V(t)??Y(),g=Se({identity:Pe(a.port),targetVersion:h,expectedRoot:ve(t),expectedKey:ee(t).key,port:a.port,selfPid:process.pid});if(!g.kill){s(i.ok?` \u2713 already up \u2014 ${i.server??"MCP"} (protocol ${i.protocolVersion??"?"}) \u2014 ${g.reason}`:` ! not restarted (${g.reason}) \u2014 ${i.remedy}`);return}try{process.kill(g.pid,"SIGTERM"),s(` \u21BA restarted the shared server \u2014 it was ${g.reason}; the next session brings it up on ${h}`)}catch(m){s(` ! the shared server is ${g.reason} and could not be stopped (pid ${g.pid}): ${m.message}`)}}p(Ft,"bs"),l(Ft,"applyMcpModeStep");function Gt(t,n,e){const s=ut({cwd:t,cliVersion:Y()}),o=Bn({run:Kn(n),facts:s,installed:l(()=>Te(t)?.version,"installed")});if(!(o.outcome==="current"||o.outcome==="unknown")){if(e(""),o.outcome==="ahead"){e(`[plugin] ${o.from} \u2014 newer than this workspace's lensmcp ${o.to}; another workspace's lensmcp installed it, and it stays.`),e(" `lensmcp upgrade` brings this workspace up to it.");return}if(o.outcome==="updated"){e(`[plugin] ${o.from} \u2192 ${o.to}`),e(" restart Claude Code for the new plugin to load.");return}e(`[plugin] the Claude Code plugin is ${o.from}, this lensmcp is ${o.to}.`),e(` could not update it automatically (${o.detail??"unknown reason"}). Run:`);for(const r of o.commands??[])e(` ${r}`);e(" \u2026then restart Claude Code.")}}p(Gt,"Cs"),l(Gt,"applyPluginSyncStep");async function Kt(t,n,e,s){const o=I(n,{string:["--cwd","--mcp"],boolean:["--no-recycle"]}),r=T($(o.flags["--cwd"])??t.cwd),a={...t,cwd:r},c=$(o.flags["--mcp"]);if(c!==void 0&&!st(c))return s(`setup: --mcp must be "embedded" or "shared" (got "${c}").`),{exitCode:1};e("lensmcp setup \u2014 first-time bootstrap (install \u2192 trust \u2192 pods)"),e(""),e("[1/3] install \u2014 plugin, .mcp.json, nx config, vite/nest wiring");const d=Ie(a,n,e,s);if(d.exitCode!==0)return s(""),s("setup: the install step failed \u2014 fix the above and re-run `lensmcp setup`."),d;e(""),e("[2/3] trust \u2014 dev CA \u2192 System keychain, /etc/hosts, DNS flush (sudo)");const i=De(a,n,e,s);if(i.exitCode!==0)return s(""),s("setup: the trust step failed \u2014 run `lensmcp setup` directly in a terminal so sudo can prompt."),i;e(""),e("[3/3] pods \u2014 recycle this workspace's devservers, reconcile the gateway");const h=ee(r),g=h.key,m=Gs({previous:Ge(r),current:Fe(r),disabled:o.flags["--no-recycle"]===!0}),f=m.recycle?ws(r,ge(h),e,m.reason):(e(` \xB7 pods left running \u2014 ${m.reason}`),{killed:0,stale:0});ys(a,r,g,e),await Ft(r,c,t.env??process.env,e);try{Gt(r,{...process.env,...t.env??{}},e)}catch{}return Dt(r,m.recycle),e(""),e("\u2713 setup complete."),(f.killed>0||f.stale>0)&&e(` recycled ${f.killed} pod${f.killed===1?"":"s"}`+(f.stale>0?` (+${f.stale} stale socket${f.stale===1?"":"s"} cleared)`:"")+" \u2014 they come back on the new wiring."),e(" next: lensmcp gateway start (the :443 front door \u2014 needs sudo)"),e(" verify: lensmcp doctor"),{exitCode:0}}p(Kt,"Ss"),l(Kt,"runSetup");async function Bt(t,n){if(n[0]!=="asked")return{exitCode:0};const e=await new Promise(s=>{if(process.stdin.isTTY){s("");return}let o="";const r=setTimeout(()=>s(o),2e3);r.unref?.(),process.stdin.setEncoding("utf8"),process.stdin.on("data",a=>{o+=a,o.length>1e6&&(clearTimeout(r),s(o))}),process.stdin.on("end",()=>{clearTimeout(r),s(o)}),process.stdin.on("error",()=>{clearTimeout(r),s(o)})});return Ys(e,{env:{...process.env,...t.env??{}},cwd:t.cwd}),{exitCode:0}}p(Bt,"js"),l(Bt,"runAgent");async function Vt(t,n,e){const s=I(n,{string:["--cwd","--hook","--timeout","--session"],boolean:["--json","--quiet"]}),o=T($(s.flags["--cwd"])??t.cwd),r=$(s.flags["--hook"]),a=at(r)?r:void 0,c=$(s.flags["--session"]);if(r!==void 0&&a===void 0)return{exitCode:0};const d=s.flags["--json"]===!0,i=s.flags["--quiet"]===!0||r!==void 0,h=Number($(s.flags["--timeout"])??""),g=Number.isFinite(h)&&h>0?h:hn,m={...process.env,...t.env??{}};try{const f=await gn({cwd:o,env:m,budgetMs:g,verify:l(k=>cn(k).map(M=>M.resource),"verify")});if(!f.available)return d&&!i?e(JSON.stringify({available:!1,workspace:f.source.workspace,mode:f.source.mode,reason:f.reason,elapsedMs:f.elapsedMs})):i||e(`lensmcp status \u2014 ${f.source.workspace}: unavailable (${f.reason})`),{exitCode:0};const v=pn(f.status,f.evidence,Date.now()),b=un(v,{workspace:f.source.workspace,includeUnmonitored:a==="SessionStart"||!i});if(d)return i&&b===void 0?{exitCode:0}:(e(JSON.stringify({available:!0,workspace:f.source.workspace,mode:f.source.mode,url:f.source.url,aggregate:f.status.status??"unknown",elapsedMs:f.elapsedMs,findings:v.findings,suppressed:v.suppressed,unmonitored:v.unmonitored})),{exitCode:0});if(a){const k=ln(v.findings);return Zs(c,k)?(b!==void 0&&e(rt(a,b)),c&&Xs(c,k),{exitCode:0}):{exitCode:0}}if(i)return b!==void 0&&e(b),{exitCode:0};if(e(`lensmcp status \u2014 ${f.source.workspace} (${f.source.mode}, ${f.source.url})`),e(` aggregate says: ${f.status.status??"unknown"} (read in ${f.elapsedMs}ms)`),v.findings.length===0)e(" nothing actionable that this command can vouch for.");else for(const k of v.findings)e(` \u2022 ${dn(k)}`);for(const k of v.suppressed)e(` \xB7 not reported \u2014 ${k.kind}: ${k.reason}`);return v.unmonitored.length>0&&e(` \xB7 unmonitored (unknown, NOT clean): ${v.unmonitored.join(", ")}`),{exitCode:0}}catch(f){return i||e(`lensmcp status: unavailable (${f instanceof Error?f.message:String(f)})`),{exitCode:0}}}p(Vt,"xs"),l(Vt,"runStatus");function Ht(t,n,e){const s=I(n,{string:["--cwd","--hook","--plugin-root"],boolean:["--json","--quiet"]}),o=T($(s.flags["--cwd"])??t.cwd),r=$(s.flags["--hook"]),a=at(r)?r:void 0;if(r!==void 0&&a===void 0)return{exitCode:0};const c=s.flags["--json"]===!0,d=s.flags["--quiet"]===!0||r!==void 0,i=$(s.flags["--plugin-root"]);try{const h=ut({cwd:o,cliVersion:Y(),...i?{pluginRoot:i}:{}}),g=Gn(h);if(c)return d&&!g?{exitCode:0}:(e(JSON.stringify({...h,skew:g??null})),{exitCode:0});if(a)return g&&e(rt(a,dt(g))),{exitCode:0};if(d)return g&&e(dt(g)),{exitCode:0};if(e(`lensmcp version-check \u2014 ${h.pluginId??"lensmcp plugin"}`),e(` plugin ${h.plugin??"unknown"}${h.pluginSource?` (${h.pluginSource})`:""}`),e(` project ${h.project??"unknown"} (node_modules/lensmcp)`),e(` cli ${h.cli??"unknown"} (the binary running now)`),!g)return e(h.plugin&&(h.project??h.cli)?" \u2713 in step.":" ? cannot compare \u2014 one of the versions is unreadable (staying silent)."),{exitCode:0};e(` \u2717 the plugin is ${g.direction} \u2014 update it, then restart Claude Code:`);for(const m of Vn(g))e(` ${m}`);return{exitCode:0}}catch(h){return d||e(`lensmcp version-check: unavailable (${h instanceof Error?h.message:String(h)})`),{exitCode:0}}}p(Ht,"Ps"),l(Ht,"runVersionCheck");async function Wt(t,n,e){const s=I(n,{string:["--cwd"],boolean:["--json"]}),o=T($(s.flags["--cwd"])??t.cwd),r=s.flags["--json"]===!0,a=[];Ut(a),Jt(o,a),qt(o,a),zt(o,t.env??process.env,a),await Yt(o,t.env??process.env,a),Xt(o,a),Zt(o,a),Qt(o,a),es(a),await Cs(o,a),await Ss(o,t.env??process.env,a);const c=a.some(i=>i.status==="fail"),d=a.some(i=>i.status==="warn");if(r)return e(JSON.stringify({ok:!c,summary:{total:a.length,failed:a.filter(i=>i.status==="fail").length,warnings:a.filter(i=>i.status==="warn").length},checks:a},null,2)),{exitCode:c?1:0};for(const i of a){const h=i.status==="pass"?"\u2713":i.status==="info"?"\xB7":i.status==="warn"?"!":"\u2717";e(`${h} ${i.label}${i.detail?` \u2014 ${i.detail}`:""}`),i.status!=="pass"&&i.hint&&e(` \u21B3 ${i.hint}`)}return e(""),e(c?"doctor: issues found (see \u2717 above).":d?"doctor: ok, with warnings (!).":"doctor: all checks passed."),{exitCode:c?1:0}}p(Wt,"Es"),l(Wt,"runDoctor");function N(t,n,e,s,o){t.push({status:n,label:e,detail:s,hint:o})}p(N,"x"),l(N,"add");function Ut(t){const n=Number(process.versions.node.split(".")[0]);n>=20?N(t,"pass",`Node ${process.versions.node}`):n>=18?N(t,"warn",`Node ${process.versions.node}`,"older than recommended","upgrade to Node 20+ for best results"):N(t,"fail",`Node ${process.versions.node}`,"too old","LensMCP needs Node 18+ (20+ recommended)")}p(Ut,"Ns"),l(Ut,"checkNode");function Jt(t,n){const e=w(t,"nx.json");if(!E(e)){N(n,"fail","nx.json at workspace root","missing","run `lensmcp` from inside a Nx workspace");return}let s;try{s=JSON.parse(B(e,"utf8"))}catch(r){N(n,"fail","nx.json parses",r.message,"fix the JSON syntax in nx.json");return}const o=(s.plugins??[]).some(r=>typeof r=="string"?r==="@lensmcp/nx-plugin":!!r&&typeof r=="object"&&r.plugin==="@lensmcp/nx-plugin");N(n,o?"pass":"fail","@lensmcp/nx-plugin registered in nx.json#plugins",o?void 0:"not registered",o?void 0:"run `lensmcp install`"),N(n,s.lensmcp?.schemaVersion===1?"pass":"warn","lensmcp config block in nx.json",s.lensmcp?.schemaVersion===1?void 0:"missing",s.lensmcp?.schemaVersion===1?void 0:"run `lensmcp install` to write the config defaults")}p(Jt,"Ms"),l(Jt,"checkWorkspace");function qt(t,n){const e=w(t,".mcp.json");if(!E(e)){N(n,"warn",".mcp.json with a lensmcp server","missing","run `lensmcp install` so agents auto-discover the MCP server");return}try{const s=JSON.parse(B(e,"utf8")),o=!!s.mcpServers&&!!s.mcpServers.lensmcp;N(n,o?"pass":"warn",".mcp.json registers the lensmcp MCP server",o?void 0:"no lensmcp entry",o?void 0:"run `lensmcp install`")}catch(s){N(n,"warn",".mcp.json parses",s.message,"fix the JSON syntax in .mcp.json")}}p(qt,"Ts"),l(qt,"checkMcpConfig");function zt(t,n,e){const s=Z(w(t,".claude","settings.json")),o=Z(w(t,".claude","settings.local.json")),r=ht({cwd:t}),a=r?Z(w(r.root,"plugin",".mcp.json")):void 0,c=Qe(a),d=lt(),i=et(s,se)||et(o,se)||d.some(g=>g.scope==="user"||g.projectPath===t),h=Bs({workspaceServers:Qe(Z(w(t,".mcp.json"))),pluginServers:c,pluginEnabled:i,pluginReadable:a!==void 0,disabledServers:[...Ze(s),...Ze(o)],mcpMode:te(t,n).mode});N(e,h.duplicated||h.indeterminate?"warn":"pass","the MCP server is registered exactly once",h.duplicated||h.indeterminate?h.detail:void 0,h.duplicated||h.indeterminate?h.hint:void 0)}p(zt,"Ls"),l(zt,"checkDuplicateRegistration");function Ke(){const t=R("GET","/status");if(!t||t.status!==200)return;const n=t.json?.daemon,e=t.json?.workspaces;if(!(!n?.wsKey||!Array.isArray(e)))return e.find(s=>s.key===n.wsKey)?.root}p(Ke,"dt"),l(Ke,"daemonOwnerRoot");function Z(t){try{return JSON.parse(B(t,"utf8"))}catch{return}}p(Z,"te"),l(Z,"readJsonFile");async function Yt(t,n,e){Ne(t)&&N(e,"info","MCP mode pin",je);const s=te(t,n),o=nt[s.source];if(N(e,"pass","MCP mode",s.mode==="shared"?`shared (${o}) \u2014 sessions proxy into ${s.url}`:`embedded (${o}) \u2014 one MCP server per agent session; ${fe(s)}`,fe(s)),s.mode!=="shared")return;const r=await ot(s.url);if(r.ok){N(e,"pass","shared MCP server",`${r.server??"MCP"} @ ${s.url} (protocol ${r.protocolVersion??"?"})`);return}if(r.remedy){N(e,"warn","shared MCP server",`not usable at ${s.url} \u2014 ${r.error??"refused"}`,r.remedy);return}const a=qs(t);if(a.length===0){N(e,"info","shared MCP server",`not running at ${s.url} \u2014 no agent session is open on this workspace; the next one starts it`,"`lensmcp gateway start` starts it now");return}const c=`${a.length} agent session${a.length===1?" is":"s are"} open (pid ${a.join(", ")})`;N(e,"warn","shared MCP server",`not running at ${s.url} \u2014 ${r.error??"no answer"}, yet ${c}`,"each is on an embedded fallback or restarts the server on its next call \u2014 its stderr names why it could not attach; `lensmcp gateway start` starts it now")}p(Yt,"Rs"),l(Yt,"checkMcpMode");function Be(t,n){const e=te(t,n);if(e.mode!=="shared")return{mode:e.mode,url:e.url,port:e.port,healthy:!1};const s=tn(e.url);return{mode:e.mode,url:e.url,port:e.port,healthy:s.ok,...s.server?{server:s.server}:{},...s.error?{error:s.error}:{},...s.remedy?{remedy:s.remedy}:{}}}p(Be,"lt"),l(Be,"mcpStatusBlock");function Xt(t,n){const e=He(t);N(n,e?"pass":"fail","lensmcp-mcp server bundle reachable",e??"missing",e?void 0:`dev: \`yarn nx build ${Fn}\``)}p(Xt,"Os"),l(Xt,"checkServerBundle");function Zt(t,n){const e=w(t,".lensmcp");N(n,E(e)?"pass":"warn",".lensmcp/ runtime directory",E(e)?void 0:"not created yet",E(e)?void 0:"created automatically on first `lensmcp mcp` run");const s=$n(t);N(n,s.runtimeIgnored?"pass":"warn",".gitignore keeps .lensmcp/ runtime state out of git",s.runtimeIgnored?void 0:"not ignored \u2014 events, logs and tokens could be committed",s.runtimeIgnored?void 0:"add `**/.lensmcp/*` to .gitignore (lensmcp install does this)"),N(n,s.sharedIgnored.length?"warn":"pass",`.gitignore keeps the team's .lensmcp folders (${kn.map(o=>`${o}/`).join(", ")})`,s.sharedIgnored.length?`${s.by} ignores ${s.sharedIgnored.map(o=>`.lensmcp/${o}/`).join(", ")} \u2014 the analyzer instructions in it would not reach the team`:void 0,s.sharedIgnored.length?"ignore `**/.lensmcp/*` instead of `.lensmcp/` and add `!**/.lensmcp/<folder>/` for each \u2014 lensmcp install rewrites it":void 0)}p(Zt,"_s"),l(Zt,"checkRuntimeDir");function Qt(t,n){const e=q(t,d=>/^vite\.config\.[cm]?[jt]s$/.test(d)),s=e.filter(d=>/lensmcpVitePlugin|@lensmcp\/vite-plugin/.test(K(d)));if(e.length>0){const d=s.length===e.length;N(n,d?"pass":"warn",`Vite wiring: ${s.length}/${e.length} config(s) use the LensMCP plugin`,void 0,d?void 0:"wire each: `nx g @lensmcp/nx-plugin:setup-vite <project>`")}const o=q(t,d=>d==="main.ts").filter(d=>/NestFactory\.create|createLensmcpNestApp/.test(K(d))),r=o.filter(d=>/createLensmcpNestApp/.test(K(d)));if(o.length>0){const d=r.length===o.length;N(n,d?"pass":"warn",`Nest wiring: ${r.length}/${o.length} bootstrap(s) use createLensmcpNestApp`,void 0,d?void 0:"wire each: `nx g @lensmcp/nx-plugin:setup-nest <project>`")}const a=q(t,d=>d==="project.json"||d==="package.json").map(d=>K(d)),c=a.filter(d=>/"agent-dev"/.test(d));a.some(d=>/@lensmcp\/cluster:gateway/.test(d))?N(n,"pass","dev lifecycle: cluster gateway owns it (agent-dev not required)",c.length>0?`${c.length} project(s) ALSO declare agent-dev \u2014 that races the gateway`:void 0,c.length>0?"remove agent-dev from gateway-managed projects; the gateway already serves them":void 0):N(n,c.length>0?"pass":"warn",`agent-dev targets: ${c.length} project(s)`,void 0,c.length>0?void 0:"no project wired \u2014 run setup-vite / setup-nest")}p(Qt,"As"),l(Qt,"checkProjectWiring");function es(t){const n=process.env.CHROME_PATH,e=process.platform==="darwin"?["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium"]:process.platform==="win32"?["C:/Program Files/Google/Chrome/Application/chrome.exe","C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"]:["/usr/bin/google-chrome","/usr/bin/chromium-browser","/usr/bin/chromium","/usr/bin/google-chrome-stable"],s=(n&&E(n)?n:void 0)??e.find(o=>E(o));N(t,s?"pass":"warn","Chrome for browser:// capture",s?pe(s):"not found",s?void 0:"install Chrome or set CHROME_PATH (only needed for browser capture)")}p(es,"Is"),l(es,"checkChrome");function K(t){try{return B(t,"utf8")}catch{return""}}p(K,"K"),l(K,"safeRead");function ts(t,n,e,s){const o=I(n,{string:["--cwd","--from","--scope"]}),r=(o.positional[0]??"").toLowerCase();if(r!=="install"&&r!=="status")return s("Usage: lensmcp plugin <install|status> [claude|codex] [--from <dir>] [--scope <user|project|local>] [--cwd <dir>]"),{exitCode:2};const a=T($(o.flags["--cwd"])??t.cwd),c=o.positional[1]?.toLowerCase(),d=c?Hn(c):void 0;if(c&&!d)return s(`Unknown agent: ${c} (use claude | codex)`),{exitCode:2};const i=d?[d]:[...pt],h=$(o.flags["--from"]),g=ht({cwd:a,...h?{from:h}:{},selfRoot:ne()});if(!g)return s("Could not find a lensmcp package to install the plugins from."),s("Run inside a workspace with lensmcp installed, or pass --from <package-root>."),{exitCode:1};e(`plugin package: ${g.root}${g.version?` (lensmcp ${g.version})`:""}`+(g.source==="self"?" \u2014 the running CLI itself (no workspace install found; prefer a workspace)":""));const m=gt({...process.env,...t.env??{}});if(r==="status"){for(const b of i){const k=qn(g.root,b),M=b.id==="claude"?Te(a)?.version:Wn(m),C=M?k?M===k?`installed ${M} \u2014 current`:`installed ${M}, the package ships ${k} \u2014 \`lensmcp plugin install ${b.id}\``:`installed ${M} (this package ships no ${b.label} plugin \u2014 it arrived in ${b.since})`:`not installed \u2014 \`lensmcp plugin install ${b.id}\``;e(` ${b.label.padEnd(11)} \u2192 ${C}`)}return{exitCode:0}}const f=$(o.flags["--scope"]);let v=!1;for(const b of i){const k=b.id==="claude"?f??Te(a)?.scope:void 0,M=Un(b,{root:g.root,...k?{scope:k}:{}},{run:m});switch(M.outcome){case"installed":e(` ${b.label.padEnd(11)} \u2192 installed${M.version?` ${M.version}`:""} \u2014 ${M.restartHint}`);break;case"skipped-no-cli":d&&(v=!0),e(` ${b.label.padEnd(11)} \u2192 skipped (${M.detail})`);break;case"skipped-not-packaged":d&&(v=!0),e(` ${b.label.padEnd(11)} \u2192 skipped \u2014 ${M.detail}`);break;case"failed":v=!0,s(` ${b.label.padEnd(11)} \u2192 FAILED \u2014 ${M.detail}`),s(` run by hand:${M.commands.map(C=>`
298
+ ${C}`).join("")}`);break}}return{exitCode:v?1:0}}p(ts,"Ds"),l(ts,"runPlugin");function Ve(){const t=R("GET","/status");if(t?.status!==200||!t.json||typeof t.json!="object")return{registeredKeys:[]};const n=t.json;return{...typeof n.daemon?.wsKey=="string"?{wsKey:n.daemon.wsKey}:{},...typeof n.daemon?.version=="string"?{version:n.daemon.version}:{},registeredKeys:(n.workspaces??[]).flatMap(e=>typeof e.key=="string"?[e.key]:[])}}p(Ve,"pt"),l(Ve,"snapshotDaemon");function ss(t){let n=T(t);for(let e=0;e<8;e++){const s=w(n,"package.json");if(E(s)&&/"(?:lensmcp|@lensmcp\/[^"]+)"\s*:/.test(K(s)))return{key:H(n).key,root:n};const o=D(n);if(o===n)break;n=o}}p(ss,"Fs"),l(ss,"findLensmcpWorkspace");function ns(t,n,e,s=!1){if(t){const a=t.replace(/^v/,"");if(!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(a)){e(`Not a version: ${t} (expected e.g. 1.20.1)`);return}if(!s&&no(n("npm",["view",`lensmcp@${a}`,"version"]),a)==="absent"){const c=n("npm",["view","lensmcp","version"]),d=c&&c.code===0?(c.stdout??"").trim().split(`
299
299
  `).filter(Boolean).pop():void 0;e(`lensmcp ${a} is not on the npm registry${d?` (the newest there is ${d})`:""} \u2014 nothing was changed.`),e("If it was published a moment ago, run this again in a minute. `--no-registry-check` skips the question.");return}return a}const o=n("npm",["view","lensmcp","version"]),r=o&&o.code===0?(o.stdout??"").trim().split(`
300
- `).filter(Boolean).pop():void 0;if(!r||!/^\d+\.\d+\.\d+/.test(r)){e("Could not resolve the latest lensmcp version from the npm registry \u2014 pass one explicitly: `lensmcp upgrade 1.20.1`.");return}return r}p(ns,"Gs"),l(ns,"resolveTargetVersion");function os(t,n,e,s){for(const o of t){let r;try{r=te(o.root,process.env)}catch{continue}if(r.mode!=="shared")continue;const a=Se({identity:Pe(r.port),targetVersion:n,expectedRoot:ye(o.root),expectedKey:o.key,port:r.port,selfPid:process.pid});if(!a.kill){s(` mcp \u2192 '${o.key}' :${r.port} \u2014 ${a.reason}`);continue}if(e){s(` mcp \u2192 would restart '${o.key}' :${r.port} (pid ${a.pid}) \u2014 ${a.reason}`);continue}try{process.kill(a.pid,"SIGTERM"),s(` mcp \u2192 restarted '${o.key}' :${r.port} \u2014 was ${a.reason}; the next session respawns it on ${n}`)}catch(c){s(` mcp \u2192 could not stop '${o.key}' :${r.port} (pid ${a.pid}): ${c.message}`)}}}p(os,"Ks"),l(os,"restartSharedMcpServers");function ye(t){try{return Es(t)}catch{return t}}p(ye,"Ee"),l(ye,"canonicalRootPath");async function rs(t,n,e,s){const o=I(n,{string:["--cwd"],boolean:["--dry-run","--no-install","--no-plugins","--no-global","--no-restart","--no-registry-check","--no-setup"]}),r=T($(o.flags["--cwd"])??t.cwd),a=o.flags["--dry-run"]===!0,c={...process.env,...t.env??{}},d=gt(c),i=ns(o.positional[0],d,s,o.flags["--no-registry-check"]===!0);if(!i)return{exitCode:1};const h=so(),g=ss(r),{targets:m,instances:f}=co(g,h,u=>Ce(J(u)));if(m.length===0&&f.length>0)return s(`Only worktree instances here (${f.map(u=>u.key).join(", ")}): an instance runs its own commit's lens and \`upgrade\` leaves it alone. Run it in the main checkout.`),{exitCode:1};if(m.length===0)return s("No LensMCP workspace found: ~/.lensmcp/workspaces.json is empty and no package.json above the current directory depends on lensmcp."),{exitCode:1};const v=Ve();if(e(`upgrade \u2192 lensmcp ${i}${a?" (dry run \u2014 nothing will be changed)":""}`),v.wsKey&&e(` daemon \u2192 '${v.wsKey}' on :443${v.version?`, running ${v.version}`:""}, hosting ${v.registeredKeys.length} workspace${v.registeredKeys.length===1?"":"s"}`),e(` will change \u2192 ${m.length} workspace${m.length===1?"":"s"} (${m.map(u=>u.key).join(", ")})${o.flags["--no-install"]===!0?"":" + install"}${o.flags["--no-global"]===!0?"":" + the global CLI"}${o.flags["--no-plugins"]===!0?"":" + the Claude/Codex plugins"}${o.flags["--no-restart"]===!0?"":" + the :443 daemon"}`),f.length>0&&e(` instances \u2192 left as they are: ${f.map(u=>u.key).join(", ")} (a worktree runs its own commit's lens; upgrade it from its branch)`),o.flags["--no-registry-check"]!==!0){const u=Zn(m.flatMap(x=>["package.json","yarn.lock","package-lock.json","pnpm-lock.yaml"].map(P=>K(w(x.root,P))))),y=Qn(u,i,x=>d("npm",["view",`${x}@${i}`,"version"]));if(y.length===0&&e(` registry \u2192 all ${u.length} packages these workspaces install are published at ${i}`),y.length>0)return s(`lensmcp ${i} is not fully published yet \u2014 ${y.length} of the ${u.length} packages these workspaces install are not on the npm registry at ${i}:`),s(` ${y.join(", ")}`),s("A release publishes its packages one by one; run this again in a minute. Nothing was changed. (`--no-registry-check` skips the question.)"),{exitCode:1}}const b=[];let k=0;for(const u of m){const y=w(u.root,"package.json"),x=K(y);if(!x){k++,s(` ${u.key}: cannot read ${y} \u2014 skipped`);continue}const P=ro(x,i);for(const j of P.skipped.filter(F=>F.reason==="non-version-spec"))e(` ${u.key}: left ${j.section}.${j.name} at '${j.spec}' (not a plain version \u2014 a link:/workspace: pin is deliberate)`);const L=P.changes.length>0,O=V(u.root);if(!eo({rewritten:L,...O?{installedVersion:O}:{},targetVersion:i})){e(` ${u.key}: already at ${i}`);continue}if(e(L?` ${u.key}: ${P.changes.length} dep${P.changes.length===1?"":"s"} \u2192 ${i} (${P.changes.map(j=>j.name).join(", ")})`:` ${u.key}: package.json is at ${i} but node_modules holds ${O??"no lensmcp"} \u2014 an earlier install did not land`),a){b.push(u);continue}if(L&&X(y,P.text),o.flags["--no-install"]===!0){b.push(u),e(" install skipped (--no-install) \u2014 run it before restarting anything.");continue}const G=Xn(u.root);e(` ${G.name} ${G.install.join(" ")} (${u.root})`);const S=A(G.name,G.install,{cwd:u.root,stdio:"inherit",env:c});if((S.status??1)!==0){k++,s(` ${u.key}: \`${G.name} ${G.install.join(" ")}\` exited ${S.status??"by signal"} \u2014 fix it and re-run \`lensmcp upgrade ${i}\` (the rewrite is already in place).`);continue}b.push(u)}for(const u of m)Ne(u.root,a)&&e(` mcp \u2192 '${u.key}'${a?" (dry run \u2014 not written)":""}: ${je}`);if(o.flags["--no-global"]!==!0){const u=zn(d);u&&u.version!==i?a?e(` global \u2192 ${u.version} \u2192 ${i} (npm i -g lensmcp@${i})`):(e(` global \u2192 ${u.version} \u2192 ${i}`),(A("npm",["install","-g",`lensmcp@${i}`],{stdio:"inherit",env:c,timeout:3e5}).status??1)!==0&&(k++,s(` the global install failed \u2014 run by hand: npm i -g lensmcp@${i}`))):u&&e(` global \u2192 already ${u.version}`)}if(o.flags["--no-plugins"]!==!0){const u=[v.wsKey?m.find(y=>y.key===v.wsKey):void 0,...b,...m].find(y=>!!y&&E(w(y.root,"node_modules","lensmcp","package.json")));u?!a&&o.flags["--no-install"]!==!0&&!mt(V(u.root),i)?e(` plugins \u2192 skipped (${u.key} still holds ${V(u.root)??"no lensmcp"} \u2014 there is no ${i} package on disk to install them from)`):a?e(` plugins \u2192 would re-install Claude Code + Codex from ${w(u.root,"node_modules","lensmcp")}`):is(w(u.root,"node_modules","lensmcp"),r,c,e,s):e(" plugins \u2192 skipped (no workspace has lensmcp installed to point the marketplaces at)")}const M=l(()=>{if(a)return o.flags["--no-setup"]!==!0&&o.flags["--no-restart"]!==!0&&e(` setup \u2192 would run \`lensmcp setup --no-recycle\` with lensmcp ${i} in each workspace whose setup is then behind (\`--no-setup\` skips it)`),{exitCode:k>0?1:0};for(const u of m){const y=Q(w(u.root,".lensmcp","setup-state.json"))?.version,x=V(u.root),P=ft(u.root,i),L=ao({key:u.key,root:u.root,targetVersion:i,...typeof y=="string"?{setupVersion:y}:{},...x?{installedVersion:x}:{},...P?{bin:P}:{},skip:o.flags["--no-setup"]===!0||o.flags["--no-restart"]===!0});if(L.action==="remind"&&e(L.line),L.action!=="run")continue;e(` setup \u2192 '${u.key}': lensmcp setup --no-recycle with lensmcp ${i} (the lens tools are gated until it has run) \u2026`);const O=io(L.bin,u.root,c);O===0?e(` setup \u2192 '${u.key}' is set up for ${i} \u2014 the lens tools are open`):(k++,s(` setup \u2192 '${u.key}': \`lensmcp setup\` exited ${O} \u2014 the lens tools stay gated; run \`lensmcp setup\` in ${u.root} in a terminal.`))}return{exitCode:k>0?1:0}},"finish");if(o.flags["--no-restart"]===!0)return e(" restart \u2192 skipped (--no-restart) \u2014 the daemon keeps serving the OLD code until `lensmcp gateway restart` runs in its workspace."),M();const C=to({...v.wsKey?{daemonWsKey:v.wsKey}:{},...v.version?{daemonVersion:v.version}:{},targetVersion:i,registeredKeys:v.registeredKeys,known:h,upgraded:b});if(o.flags["--no-install"]!==!0){const u=a?m:m.filter(y=>mt(V(y.root),i));for(const y of m)u.includes(y)||e(` mcp \u2192 '${y.key}' left alone \u2014 its install did not land, so there is no ${i} bundle to restart it onto`);os(u,i,a,e)}if(C.steps.length===0)return e(` restart \u2192 nothing to do${C.note?` (${C.note})`:""}`),M();let _;for(const u of C.steps){if(a){e(` restart \u2192 would ${u.action==="restart"?`restart the daemon ('${u.key}')`:`re-register '${u.key}'`}${u.reason==="rehost"?" (not upgraded \u2014 re-hosted so the daemon restart does not drop it)":u.reason==="stale-daemon"?" (its files are current but the process still runs the old bundle)":""}`);continue}if(u.action==="restart"){const y=ft(u.root,i);if(e(` restart \u2192 gateway daemon ('${u.key}') ${y?`with lensmcp ${i}`:`in-process (no lensmcp ${i} on disk in ${u.root})`} \u2026`),(y?oo(y,u.root,c):Le({...t,cwd:u.root},["restart"],e,s).exitCode)!==0){k++,s(` the daemon restart ('${u.key}') failed \u2014 fix it, then \`lensmcp gateway start\` in each guest workspace.`);break}if(!await as(18e4)){k++,s(" the restarted daemon did not answer within 3 minutes \u2014 check `lensmcp gateway status`; guests need `lensmcp gateway start` once it is up.");break}}else{if(await Ct(u.key,u.root,_??=Date.now()+15e3)){e(` restart \u2192 '${u.key}' is back \u2014 the daemon re-hosted it`);continue}const y=R("POST","/register",re(u.root,u.key));if(y&&y.status===200){try{ee(w(u.root,".lensmcp"),{recursive:!0}),X(w(u.root,".lensmcp","registered.json"),JSON.stringify({wsKey:u.key}))}catch{}e(` restart \u2192 re-registered '${u.key}'${u.reason==="rehost"?" (not upgraded \u2014 re-hosted after the daemon restart)":""}`);const x=Me(y.json);x&&e(x)}else k++,s(` re-registering '${u.key}' failed \u2014 ${fe(y)??`run \`lensmcp gateway start\` in ${u.root}`}.`)}}if(!a){const u=Ve();if(u.version){const y=u.wsKey?m.find(L=>L.key===u.wsKey)?.root:void 0,x=y?V(y):void 0,P=Yn({reported:u.version,target:i,...x?{ownerInstalled:x}:{},...y?{ownerRoot:y}:{}});P.ok?e(P.line):(k++,s(P.line))}}return M()}p(rs,"Hs"),l(rs,"runUpgrade");async function as(t){const n=Date.now()+t;for(;;){if(R("GET","/list")?.status===200)return!0;if(Date.now()>=n)return!1;await new Promise(e=>setTimeout(e,2e3))}}p(as,"Vs"),l(as,"waitForDaemon");function is(t,n,e,s,o){const r=l((a,c,d)=>{try{const i=A(a,c,{encoding:"utf8",timeout:12e4,env:e,stdio:["ignore","pipe","pipe"],...d?{cwd:d}:{}});return i.error&&i.error.code==="ENOENT"?{ok:!1,detail:`\`${a}\` is not on PATH`}:(i.status??1)!==0?{ok:!1,detail:`${i.stderr??""}
300
+ `).filter(Boolean).pop():void 0;if(!r||!/^\d+\.\d+\.\d+/.test(r)){e("Could not resolve the latest lensmcp version from the npm registry \u2014 pass one explicitly: `lensmcp upgrade 1.20.1`.");return}return r}p(ns,"Gs"),l(ns,"resolveTargetVersion");function os(t,n,e,s){for(const o of t){let r;try{r=te(o.root,process.env)}catch{continue}if(r.mode!=="shared")continue;const a=Se({identity:Pe(r.port),targetVersion:n,expectedRoot:ve(o.root),expectedKey:o.key,port:r.port,selfPid:process.pid});if(!a.kill){s(` mcp \u2192 '${o.key}' :${r.port} \u2014 ${a.reason}`);continue}if(e){s(` mcp \u2192 would restart '${o.key}' :${r.port} (pid ${a.pid}) \u2014 ${a.reason}`);continue}try{process.kill(a.pid,"SIGTERM"),s(` mcp \u2192 restarted '${o.key}' :${r.port} \u2014 was ${a.reason}; the next session respawns it on ${n}`)}catch(c){s(` mcp \u2192 could not stop '${o.key}' :${r.port} (pid ${a.pid}): ${c.message}`)}}}p(os,"Ks"),l(os,"restartSharedMcpServers");function ve(t){try{return Es(t)}catch{return t}}p(ve,"Ee"),l(ve,"canonicalRootPath");async function rs(t,n,e,s){const o=I(n,{string:["--cwd"],boolean:["--dry-run","--no-install","--no-plugins","--no-global","--no-restart","--no-registry-check","--no-setup"]}),r=T($(o.flags["--cwd"])??t.cwd),a=o.flags["--dry-run"]===!0,c={...process.env,...t.env??{}},d=gt(c),i=ns(o.positional[0],d,s,o.flags["--no-registry-check"]===!0);if(!i)return{exitCode:1};const h=so(),g=ss(r),{targets:m,instances:f}=co(g,h,u=>he(H(u)));if(m.length===0&&f.length>0)return s(`Only worktree instances here (${f.map(u=>u.key).join(", ")}): an instance runs its own commit's lens and \`upgrade\` leaves it alone. Run it in the main checkout.`),{exitCode:1};if(m.length===0)return s("No LensMCP workspace found: ~/.lensmcp/workspaces.json is empty and no package.json above the current directory depends on lensmcp."),{exitCode:1};const v=Ve();if(e(`upgrade \u2192 lensmcp ${i}${a?" (dry run \u2014 nothing will be changed)":""}`),v.wsKey&&e(` daemon \u2192 '${v.wsKey}' on :443${v.version?`, running ${v.version}`:""}, hosting ${v.registeredKeys.length} workspace${v.registeredKeys.length===1?"":"s"}`),e(` will change \u2192 ${m.length} workspace${m.length===1?"":"s"} (${m.map(u=>u.key).join(", ")})${o.flags["--no-install"]===!0?"":" + install"}${o.flags["--no-global"]===!0?"":" + the global CLI"}${o.flags["--no-plugins"]===!0?"":" + the Claude/Codex plugins"}${o.flags["--no-restart"]===!0?"":" + the :443 daemon"}`),f.length>0&&e(` instances \u2192 left as they are: ${f.map(u=>u.key).join(", ")} (a worktree runs its own commit's lens; upgrade it from its branch)`),o.flags["--no-registry-check"]!==!0){const u=Zn(m.flatMap(x=>["package.json","yarn.lock","package-lock.json","pnpm-lock.yaml"].map(P=>K(w(x.root,P))))),y=Qn(u,i,x=>d("npm",["view",`${x}@${i}`,"version"]));if(y.length===0&&e(` registry \u2192 all ${u.length} packages these workspaces install are published at ${i}`),y.length>0)return s(`lensmcp ${i} is not fully published yet \u2014 ${y.length} of the ${u.length} packages these workspaces install are not on the npm registry at ${i}:`),s(` ${y.join(", ")}`),s("A release publishes its packages one by one; run this again in a minute. Nothing was changed. (`--no-registry-check` skips the question.)"),{exitCode:1}}const b=[];let k=0;for(const u of m){const y=w(u.root,"package.json"),x=K(y);if(!x){k++,s(` ${u.key}: cannot read ${y} \u2014 skipped`);continue}const P=ro(x,i);for(const j of P.skipped.filter(F=>F.reason==="non-version-spec"))e(` ${u.key}: left ${j.section}.${j.name} at '${j.spec}' (not a plain version \u2014 a link:/workspace: pin is deliberate)`);const L=P.changes.length>0,O=V(u.root);if(!eo({rewritten:L,...O?{installedVersion:O}:{},targetVersion:i})){e(` ${u.key}: already at ${i}`);continue}if(e(L?` ${u.key}: ${P.changes.length} dep${P.changes.length===1?"":"s"} \u2192 ${i} (${P.changes.map(j=>j.name).join(", ")})`:` ${u.key}: package.json is at ${i} but node_modules holds ${O??"no lensmcp"} \u2014 an earlier install did not land`),a){b.push(u);continue}if(L&&X(y,P.text),o.flags["--no-install"]===!0){b.push(u),e(" install skipped (--no-install) \u2014 run it before restarting anything.");continue}const G=Xn(u.root);e(` ${G.name} ${G.install.join(" ")} (${u.root})`);const S=A(G.name,G.install,{cwd:u.root,stdio:"inherit",env:c});if((S.status??1)!==0){k++,s(` ${u.key}: \`${G.name} ${G.install.join(" ")}\` exited ${S.status??"by signal"} \u2014 fix it and re-run \`lensmcp upgrade ${i}\` (the rewrite is already in place).`);continue}b.push(u)}for(const u of m)Ne(u.root,a)&&e(` mcp \u2192 '${u.key}'${a?" (dry run \u2014 not written)":""}: ${je}`);if(o.flags["--no-global"]!==!0){const u=zn(d);u&&u.version!==i?a?e(` global \u2192 ${u.version} \u2192 ${i} (npm i -g lensmcp@${i})`):(e(` global \u2192 ${u.version} \u2192 ${i}`),(A("npm",["install","-g",`lensmcp@${i}`],{stdio:"inherit",env:c,timeout:3e5}).status??1)!==0&&(k++,s(` the global install failed \u2014 run by hand: npm i -g lensmcp@${i}`))):u&&e(` global \u2192 already ${u.version}`)}if(o.flags["--no-plugins"]!==!0){const u=[v.wsKey?m.find(y=>y.key===v.wsKey):void 0,...b,...m].find(y=>!!y&&E(w(y.root,"node_modules","lensmcp","package.json")));u?!a&&o.flags["--no-install"]!==!0&&!mt(V(u.root),i)?e(` plugins \u2192 skipped (${u.key} still holds ${V(u.root)??"no lensmcp"} \u2014 there is no ${i} package on disk to install them from)`):a?e(` plugins \u2192 would re-install Claude Code + Codex from ${w(u.root,"node_modules","lensmcp")}`):is(w(u.root,"node_modules","lensmcp"),r,c,e,s):e(" plugins \u2192 skipped (no workspace has lensmcp installed to point the marketplaces at)")}const M=l(()=>{if(a)return o.flags["--no-setup"]!==!0&&o.flags["--no-restart"]!==!0&&e(` setup \u2192 would run \`lensmcp setup --no-recycle\` with lensmcp ${i} in each workspace whose setup is then behind (\`--no-setup\` skips it)`),{exitCode:k>0?1:0};for(const u of m){const y=Z(w(u.root,".lensmcp","setup-state.json"))?.version,x=V(u.root),P=ft(u.root,i),L=ao({key:u.key,root:u.root,targetVersion:i,...typeof y=="string"?{setupVersion:y}:{},...x?{installedVersion:x}:{},...P?{bin:P}:{},skip:o.flags["--no-setup"]===!0||o.flags["--no-restart"]===!0});if(L.action==="remind"&&e(L.line),L.action!=="run")continue;e(` setup \u2192 '${u.key}': lensmcp setup --no-recycle with lensmcp ${i} (the lens tools are gated until it has run) \u2026`);const O=io(L.bin,u.root,c);O===0?e(` setup \u2192 '${u.key}' is set up for ${i} \u2014 the lens tools are open`):(k++,s(` setup \u2192 '${u.key}': \`lensmcp setup\` exited ${O} \u2014 the lens tools stay gated; run \`lensmcp setup\` in ${u.root} in a terminal.`))}return{exitCode:k>0?1:0}},"finish");if(o.flags["--no-restart"]===!0)return e(" restart \u2192 skipped (--no-restart) \u2014 the daemon keeps serving the OLD code until `lensmcp gateway restart` runs in its workspace."),M();const C=to({...v.wsKey?{daemonWsKey:v.wsKey}:{},...v.version?{daemonVersion:v.version}:{},targetVersion:i,registeredKeys:v.registeredKeys,known:h,upgraded:b});if(o.flags["--no-install"]!==!0){const u=a?m:m.filter(y=>mt(V(y.root),i));for(const y of m)u.includes(y)||e(` mcp \u2192 '${y.key}' left alone \u2014 its install did not land, so there is no ${i} bundle to restart it onto`);os(u,i,a,e)}if(C.steps.length===0)return e(` restart \u2192 nothing to do${C.note?` (${C.note})`:""}`),M();let _;for(const u of C.steps){if(a){e(` restart \u2192 would ${u.action==="restart"?`restart the daemon ('${u.key}')`:`re-register '${u.key}'`}${u.reason==="rehost"?" (not upgraded \u2014 re-hosted so the daemon restart does not drop it)":u.reason==="stale-daemon"?" (its files are current but the process still runs the old bundle)":""}`);continue}if(u.action==="restart"){const y=ft(u.root,i);if(e(` restart \u2192 gateway daemon ('${u.key}') ${y?`with lensmcp ${i}`:`in-process (no lensmcp ${i} on disk in ${u.root})`} \u2026`),(y?oo(y,u.root,c):Le({...t,cwd:u.root},["restart"],e,s).exitCode)!==0){k++,s(` the daemon restart ('${u.key}') failed \u2014 fix it, then \`lensmcp gateway start\` in each guest workspace.`);break}if(!await as(18e4)){k++,s(" the restarted daemon did not answer within 3 minutes \u2014 check `lensmcp gateway status`; guests need `lensmcp gateway start` once it is up.");break}}else{if(await Ct(u.key,u.root,_??=Date.now()+15e3)){e(` restart \u2192 '${u.key}' is back \u2014 the daemon re-hosted it`);continue}const y=R("POST","/register",re(u.root,u.key));if(y&&y.status===200){try{Q(w(u.root,".lensmcp"),{recursive:!0}),X(w(u.root,".lensmcp","registered.json"),JSON.stringify({wsKey:u.key}))}catch{}e(` restart \u2192 re-registered '${u.key}'${u.reason==="rehost"?" (not upgraded \u2014 re-hosted after the daemon restart)":""}`);const x=Me(y.json);x&&e(x)}else k++,s(` re-registering '${u.key}' failed \u2014 ${we(y)??`run \`lensmcp gateway start\` in ${u.root}`}.`)}}if(!a){const u=Ve();if(u.version){const y=u.wsKey?m.find(L=>L.key===u.wsKey)?.root:void 0,x=y?V(y):void 0,P=Yn({reported:u.version,target:i,...x?{ownerInstalled:x}:{},...y?{ownerRoot:y}:{}});P.ok?e(P.line):(k++,s(P.line))}}return M()}p(rs,"Hs"),l(rs,"runUpgrade");async function as(t){const n=Date.now()+t;for(;;){if(R("GET","/list")?.status===200)return!0;if(Date.now()>=n)return!1;await new Promise(e=>setTimeout(e,2e3))}}p(as,"Vs"),l(as,"waitForDaemon");function is(t,n,e,s,o){const r=l((a,c,d)=>{try{const i=A(a,c,{encoding:"utf8",timeout:12e4,env:e,stdio:["ignore","pipe","pipe"],...d?{cwd:d}:{}});return i.error&&i.error.code==="ENOENT"?{ok:!1,detail:`\`${a}\` is not on PATH`}:(i.status??1)!==0?{ok:!1,detail:`${i.stderr??""}
301
301
  ${i.stdout??""}`.trim().split(`
302
- `).filter(Boolean).pop()||`exited ${i.status}`}:{ok:!0}}catch(i){return{ok:!1,detail:i.message}}},"exec");for(const a of pt){if(!E(w(t,a.manifest))){s(` plugins \u2192 ${a.label} skipped \u2014 ${t} ships no ${a.manifest} (the plugin arrived in ${a.since})`);continue}const c=r(a.bin,["plugin","marketplace","add",t]);if(!c.ok){s(` plugins \u2192 ${a.label} skipped (${c.detail})`);continue}if(a.id==="codex"){const i=r(a.bin,["plugin","add",se]);s(i.ok?` plugins \u2192 Codex installed \u2014 ${a.restartHint}`:` plugins \u2192 Codex install failed (${i.detail}) \u2014 run: codex plugin add ${se}`);continue}r(a.bin,["plugin","marketplace","update",Jn]);const d=lt();if(d.length===0){const i=r(a.bin,["plugin","install",se,"--yes"]);s(i.ok?` plugins \u2192 Claude Code installed \u2014 ${a.restartHint}`:` plugins \u2192 Claude Code install failed (${i.detail}) \u2014 run: claude plugin install ${se} --yes`);continue}for(const i of d){const h=i.scope&&i.scope!=="user"?["--scope",i.scope]:[],g=r(a.bin,["plugin","update",i.id,...h],i.projectPath??n),m=i.projectPath?` (${i.projectPath})`:"";g.ok?s(` plugins \u2192 Claude Code updated${m} \u2014 ${a.restartHint}`):(o(` plugins \u2192 Claude Code update failed${m}: ${g.detail}`),o(` run by hand${i.projectPath?` from ${i.projectPath}`:""}: claude plugin update ${i.id}${h.length>0?` --scope ${i.scope}`:""}`))}}}p(is,"Bs"),l(is,"syncAgentPlugins");function ne(){let t=D(Xe(import.meta.url));for(let n=0;n<4;n++){if(E(w(t,"package.json")))return t;const e=D(t);if(e===t)break;t=e}return t}p(ne,"ne"),l(ne,"cliPackageRoot");function V(t){try{const n=JSON.parse(B(w(t,"node_modules","lensmcp","package.json"),"utf8"));return typeof n.version=="string"?n.version:void 0}catch{return}}p(V,"H"),l(V,"readProjectLensmcpVersion");function Y(){try{return JSON.parse(B(w(ne(),"package.json"),"utf8")).version}catch{return"0.0.0"}}p(Y,"X"),l(Y,"readCliVersion");function cs(t,n,e){const s=T(t.cwd),o=ds(s);return o?{exitCode:A(process.execPath,[o,...n],{stdio:"inherit",cwd:s,env:{...process.env,...t.env}}).status??1}:(e(`Could not locate the lensmcp rollout helper (@lensmcp/cluster).
302
+ `).filter(Boolean).pop()||`exited ${i.status}`}:{ok:!0}}catch(i){return{ok:!1,detail:i.message}}},"exec");for(const a of pt){if(!E(w(t,a.manifest))){s(` plugins \u2192 ${a.label} skipped \u2014 ${t} ships no ${a.manifest} (the plugin arrived in ${a.since})`);continue}const c=r(a.bin,["plugin","marketplace","add",t]);if(!c.ok){s(` plugins \u2192 ${a.label} skipped (${c.detail})`);continue}if(a.id==="codex"){const i=r(a.bin,["plugin","add",se]);s(i.ok?` plugins \u2192 Codex installed \u2014 ${a.restartHint}`:` plugins \u2192 Codex install failed (${i.detail}) \u2014 run: codex plugin add ${se}`);continue}r(a.bin,["plugin","marketplace","update",Jn]);const d=lt();if(d.length===0){const i=r(a.bin,["plugin","install",se,"--yes"]);s(i.ok?` plugins \u2192 Claude Code installed \u2014 ${a.restartHint}`:` plugins \u2192 Claude Code install failed (${i.detail}) \u2014 run: claude plugin install ${se} --yes`);continue}for(const i of d){const h=i.scope&&i.scope!=="user"?["--scope",i.scope]:[],g=r(a.bin,["plugin","update",i.id,...h],i.projectPath??n),m=i.projectPath?` (${i.projectPath})`:"";g.ok?s(` plugins \u2192 Claude Code updated${m} \u2014 ${a.restartHint}`):(o(` plugins \u2192 Claude Code update failed${m}: ${g.detail}`),o(` run by hand${i.projectPath?` from ${i.projectPath}`:""}: claude plugin update ${i.id}${h.length>0?` --scope ${i.scope}`:""}`))}}}p(is,"Bs"),l(is,"syncAgentPlugins");function ne(){let t=D(Xe(import.meta.url));for(let n=0;n<4;n++){if(E(w(t,"package.json")))return t;const e=D(t);if(e===t)break;t=e}return t}p(ne,"ne"),l(ne,"cliPackageRoot");function V(t){try{const n=JSON.parse(B(w(t,"node_modules","lensmcp","package.json"),"utf8"));return typeof n.version=="string"?n.version:void 0}catch{return}}p(V,"V"),l(V,"readProjectLensmcpVersion");function Y(){try{return JSON.parse(B(w(ne(),"package.json"),"utf8")).version}catch{return"0.0.0"}}p(Y,"Y"),l(Y,"readCliVersion");function cs(t,n,e){const s=T(t.cwd),o=ds(s);return o?{exitCode:A(process.execPath,[o,...n],{stdio:"inherit",cwd:s,env:{...process.env,...t.env}}).status??1}:(e(`Could not locate the lensmcp rollout helper (@lensmcp/cluster).
303
303
  Looked for main.rollout.js (walking up from cwd):
304
304
  \u2022 <dir>/node_modules/@lensmcp/cluster/executors/gateway/main.rollout.js
305
305
  \u2022 <dir>/dist/libs/cluster/executors/gateway/main.rollout.js
306
- Install @lensmcp/cluster, or \`yarn nx build @lensmcp/cluster\` in the workspace.`),{exitCode:1})}p(cs,"Ws"),l(cs,"runRollout");function ds(t){let n=t;for(let e=0;e<6;e++){for(const o of[w(n,"node_modules","@lensmcp","cluster","executors","gateway","main.rollout.js"),w(n,"dist","libs","cluster","executors","gateway","main.rollout.js")])if(E(o))return o;const s=D(n);if(s===n)break;n=s}}p(ds,"Us"),l(ds,"findRolloutBundle");function He(t){return ve(t,"main.js")}p(He,"ut"),l(He,"findMcpBinary");function ls(t){return ve(t,"shim.js")}p(ls,"Js"),l(ls,"findShimBinary");function ve(t,n){return Dn(t,n,ne())}p(ve,"Ne"),l(ve,"findServerBundle");function us(t){const n=w(ne(),"bundled","bridge.js");if(E(n))return n;let e=t;for(let s=0;s<5;s++){const o=w(e,"libs","bridge","dist","main.js");if(E(o))return o;const r=D(e);if(r===e)break;e=r}}p(us,"qs"),l(us,"findBridgeBundle");function ps(t){const n=w(ne(),"bundled","lint-runner.js");if(E(n))return n;let e=t;for(let s=0;s<5;s++){const o=w(e,"libs","session","dist","lint-runner.js");if(E(o))return o;const r=D(e);if(r===e)break;e=r}}p(ps,"zs"),l(ps,"findLintRunner");function le(t){let n=t;for(let e=0;e<5;e++){const s=w(n,"node_modules",".bin","nx");if(E(s))return s;const o=D(n);if(o===n)break;n=o}}p(le,"ge"),l(le,"findNxBinary");function ue(t){const n=w(t,".lensmcp");E(n)||ee(n,{recursive:!0})}p(ue,"me"),l(ue,"ensureLensmcpDir");function hs(){return!!(process.stdin.isTTY&&process.stdout.isTTY)}p(hs,"Ys"),l(hs,"isInteractive");function oe(){const t=Ls(),n=[],e=l((s,o)=>{try{for(const r of be(s,{withFileTypes:!0})){if(!r.isDirectory()||!r.name.endsWith("-devserver"))continue;const a=w(s,r.name,"parent.sock");E(a)&&!yn(a)&&n.push({service:r.name.slice(0,-10),wsKey:o,sock:a})}}catch{}},"scan");e(t,"");try{for(const s of be(t,{withFileTypes:!0}))s.isDirectory()&&/^[a-z0-9][a-z0-9-]*$/.test(s.name)&&!s.name.endsWith("-devserver")&&e(w(t,s.name),s.name)}catch{}return n.sort((s,o)=>`${s.wsKey}/${s.service}`.localeCompare(`${o.wsKey}/${o.service}`))}p(oe,"se"),l(oe,"discoverDevserverSocks");const U=l(t=>t.wsKey?`${t.wsKey}/${t.service}`:t.service,"fullServiceName");function We(t){try{const n=A("lsof",["-t",t],{encoding:"utf8"}),e=Number((n.stdout??"").split(`
306
+ Install @lensmcp/cluster, or \`yarn nx build @lensmcp/cluster\` in the workspace.`),{exitCode:1})}p(cs,"Ws"),l(cs,"runRollout");function ds(t){let n=t;for(let e=0;e<6;e++){for(const o of[w(n,"node_modules","@lensmcp","cluster","executors","gateway","main.rollout.js"),w(n,"dist","libs","cluster","executors","gateway","main.rollout.js")])if(E(o))return o;const s=D(n);if(s===n)break;n=s}}p(ds,"Us"),l(ds,"findRolloutBundle");function He(t){return ke(t,"main.js")}p(He,"ut"),l(He,"findMcpBinary");function ls(t){return ke(t,"shim.js")}p(ls,"Js"),l(ls,"findShimBinary");function ke(t,n){return Dn(t,n,ne())}p(ke,"Ne"),l(ke,"findServerBundle");function us(t){const n=w(ne(),"bundled","bridge.js");if(E(n))return n;let e=t;for(let s=0;s<5;s++){const o=w(e,"libs","bridge","dist","main.js");if(E(o))return o;const r=D(e);if(r===e)break;e=r}}p(us,"qs"),l(us,"findBridgeBundle");function ps(t){const n=w(ne(),"bundled","lint-runner.js");if(E(n))return n;let e=t;for(let s=0;s<5;s++){const o=w(e,"libs","session","dist","lint-runner.js");if(E(o))return o;const r=D(e);if(r===e)break;e=r}}p(ps,"zs"),l(ps,"findLintRunner");function le(t){let n=t;for(let e=0;e<5;e++){const s=w(n,"node_modules",".bin","nx");if(E(s))return s;const o=D(n);if(o===n)break;n=o}}p(le,"me"),l(le,"findNxBinary");function ue(t){const n=w(t,".lensmcp");E(n)||Q(n,{recursive:!0})}p(ue,"we"),l(ue,"ensureLensmcpDir");function hs(){return!!(process.stdin.isTTY&&process.stdout.isTTY)}p(hs,"Ys"),l(hs,"isInteractive");function oe(){const t=Ls(),n=[],e=l((s,o)=>{try{for(const r of Ce(s,{withFileTypes:!0})){if(!r.isDirectory()||!r.name.endsWith("-devserver"))continue;const a=w(s,r.name,"parent.sock");E(a)&&!yn(a)&&n.push({service:r.name.slice(0,-10),wsKey:o,sock:a})}}catch{}},"scan");e(t,"");try{for(const s of Ce(t,{withFileTypes:!0}))s.isDirectory()&&/^[a-z0-9][a-z0-9-]*$/.test(s.name)&&!s.name.endsWith("-devserver")&&e(w(t,s.name),s.name)}catch{}return n.sort((s,o)=>`${s.wsKey}/${s.service}`.localeCompare(`${o.wsKey}/${o.service}`))}p(oe,"se"),l(oe,"discoverDevserverSocks");const J=l(t=>t.wsKey?`${t.wsKey}/${t.service}`:t.service,"fullServiceName");function We(t){try{const n=A("lsof",["-t",t],{encoding:"utf8"}),e=Number((n.stdout??"").split(`
307
307
  `)[0]?.trim());return Number.isInteger(e)&&e>0?e:void 0}catch{return}}p(We,"ft"),l(We,"pidOnSocket");function Ue(t){try{const n=A("ps",["-o","pgid=","-p",String(t)],{encoding:"utf8"}),e=Number((n.stdout??"").trim());return Number.isInteger(e)&&e>1?e:void 0}catch{return}}p(Ue,"ht"),l(Ue,"pgidOf");function gs(t){try{const n=(A("lsof",["-a","-p",String(t),"-d","cwd","-Fn"],{encoding:"utf8"}).stdout??"").split(`
308
- `).find(e=>e.startsWith("n"));return n&&n.slice(1).trim()||void 0}catch{return}}p(gs,"Xs"),l(gs,"cwdOfPid");function ms(t,n){const e=Ye(T(t),T(n));return e===""||!e.startsWith("..")&&!Rs(e)}p(ms,"Zs"),l(ms,"isInside");function fs(t,n){return oe().filter(e=>{if(e.wsKey)return e.wsKey===n;const s=We(e.sock),o=s!==void 0?gs(s):void 0;return o!==void 0&&ms(t,o)})}p(fs,"Qs"),l(fs,"workspaceDevservers");function ws(t,n,e,s){const o=fs(t,n);if(o.length===0)return e(" no devserver pods running for this workspace \u2014 nothing to recycle."),{killed:0,stale:0};s&&e(` \xB7 recycling ${o.length} pod${o.length===1?"":"s"} because ${s}`);const r=new Set;for(const d of[process.pid,...H()]){const i=Ue(d);i!==void 0&&r.add(i)}let a=0,c=0;for(const d of o){const i=U(d),h=We(d.sock);if(h===void 0){z(d.sock),e(` \u2713 ${i} \u2014 stale socket removed (no process held it)`),c++;continue}const g=Ue(h),m=g!==void 0&&!r.has(g),f=l(v=>{try{m?process.kill(-g,v):process.kill(h,v)}catch{}},"signal");f("SIGTERM"),Je(h,5e3)||(f("SIGKILL"),Je(h,2e3)),z(d.sock),e(` \u2713 ${i} \u2014 stopped (pid ${h}${m?`, group ${g}`:", parent only"})`),a++}return{killed:a,stale:c}}p(ws,"er"),l(ws,"reapWorkspacePods");function Je(t,n){const e=Date.now()+n;for(;;){if(!ie(t))return!0;if(Date.now()>=e)return!1;A("sleep",["0.15"])}}p(Je,"gt"),l(Je,"waitForPidGone");function ys(t,n,e,s){const o=w(n,".lensmcp","gateway.pid"),r=w(n,".lensmcp","registered.json"),{pid:a,healed:c}=ce(o,n);if(c&&s(` healed: adopted a running gateway (pid ${a}) the pid file had lost.`),ae(n,t.env,m=>s(` ${m}`)),W(n)!==void 0){s(` gateway: this workspace owns the :443 daemon (pid ${a??"?"}) \u2014 left running, pods respawn fresh.`);return}const d=R("GET","/list");if(d?.status!==200){s(" gateway: not running. Start it when you are ready: lensmcp gateway start");return}const i=d.json&&typeof d.json=="object"?d.json.workspaces??[]:[],h=Ee(i,e,n);if(h.kind==="other-checkout"){for(const m of it(e,h.root,n))s(` gateway: ${m}`);return}if(h.kind==="mine"){ee(D(r),{recursive:!0}),X(r,JSON.stringify({wsKey:e})),s(` gateway: '${e}' is already registered into the shared daemon \u2014 left serving.`);return}const g=R("POST","/register",re(n,e));if(g&&g.status===200){ee(D(r),{recursive:!0}),X(r,JSON.stringify({wsKey:e})),s(` gateway: registered '${e}' into the shared daemon \u2014 it now hosts this workspace.`);const m=Me(g.json);m&&s(m);return}s(` gateway: a shared daemon is up but registering this workspace failed \u2014 ${fe(g)??"run `lensmcp gateway start`"}.`)}p(ys,"tr"),l(ys,"reconcileGatewayAfterSetup");function ke(t,n,e,s){let o=n.filter(r=>r.service===t||U(r)===t);if(o.length>1)try{const r=he(Z(e)),a=o.filter(c=>c.wsKey===r);a.length===1&&(o=a)}catch{}return o.length===0?(s(`No running service named "${t}".`),n.length>0&&s(`Running: ${n.map(U).join(", ")}`),null):o.length>1?(s(`"${t}" is ambiguous \u2014 use one of: ${o.map(U).join(", ")}`),null):o[0]}p(ke,"Me"),l(ke,"resolveServiceSock");async function vs(t,n,e,s){const o=I(n,{string:["--tail","--cwd"],boolean:["--no-follow","--follow","--plain","--color"]}),r=o.positional[0],a=oe();if(!r){if(a.length===0)e("No running services found (no devserver control sockets under $TMPDIR)."),e("Start one with `yarn nx serve <project>` or `lensmcp gateway start`.");else{e("Running services \u2014 attach with `lensmcp logs <service>`:");for(const v of a)e(` ${U(v)}`)}return{exitCode:0}}const c=ke(r,a,T($(o.flags["--cwd"])??t.cwd),s);if(!c)return{exitCode:1};const{follow:d,hint:i}=Ds({noFollow:o.flags["--no-follow"]===!0,follow:o.flags["--follow"]===!0,color:o.flags["--color"]===!0,isTTY:process.stdout.isTTY===!0}),h=Number($(o.flags["--tail"])??NaN),g=Number.isInteger(h)&&h>=0?h:100,m=o.flags["--plain"]===!0||o.flags["--color"]!==!0&&!process.stdout.isTTY,f=`/webpack/logs?tail=${g}&follow=${d?1:0}${m?"&plain=1":""}`;return new Promise(v=>{const b=ze({socketPath:c.sock,path:f,method:"GET"},k=>{k.on("data",M=>process.stdout.write(M)),_s(()=>{k.destroy(),v({exitCode:0})}),k.on("end",()=>{i&&s(i),v({exitCode:0})}),k.on("error",()=>v({exitCode:1}))});b.on("error",k=>{s(`Cannot attach to ${U(c)}: ${k.message}`),s("The devserver may have crashed leaving a stale socket \u2014 restart the service and retry."),v({exitCode:1})}),b.end()})}p(vs,"nr"),l(vs,"runLogs");async function ks(t,n,e,s){const o=I(n,{string:["--port","--cwd"]}),r=o.positional[0],a=oe();if(!r)return s("Usage: lensmcp debug <service> [--port <base>]"),a.length>0&&s(`Running: ${a.map(U).join(", ")}`),{exitCode:2};const c=ke(r,a,T($(o.flags["--cwd"])??t.cwd),s);if(!c)return{exitCode:1};const d=Number($(o.flags["--port"])??"")||void 0,i=`/webpack/debug${d?`?port=${d}`:""}`,h=await new Promise(m=>{const f=ze({socketPath:c.sock,path:i,method:"POST"},v=>{let b="";v.on("data",k=>b+=k),v.on("end",()=>m(b)),v.on("error",()=>m(null))});f.on("error",()=>m(null)),f.end()});if(h===null)return s(`Cannot reach ${U(c)} \u2014 the devserver may have crashed leaving a stale socket.`),{exitCode:1};let g;try{g=JSON.parse(h)}catch{return s(`Unexpected response from the devserver: ${h.slice(0,200)}`),{exitCode:1}}e(`Inspectors open on ${U(c)} \u2014 in place, no restart:`);for(const m of g.pods??[])e(` pod #${m.id} ${m.inspectorUrl??"(no url reported \u2014 check lensmcp logs)"}`);for(const m of g.workers??[])e(` worker ${m.name} ${m.inspectorUrl??`127.0.0.1:${m.port}`}`);return e(g.fixedPorts&&g.basePort?`Attach WebStorm (Run \u2192 Attach to Node.js/Chrome) to 127.0.0.1:${g.basePort} \u2014 or click the "Debugger listening" link in \`lensmcp logs ${r}\`.`:`Attach with one of the URLs above \u2014 Chrome DevTools (devtools://devtools/bundled/js_app.html?ws=<host:port/uuid>), VS Code (attach, "websocketAddress"), or WebStorm's click-to-attach on the URL. The ports are ephemeral and do not answer /json/list, so a host:port attach finds nothing; set LENSMCP_DEBUG_FIXED_PORTS=1 if your IDE needs one.`),{exitCode:0}}p(ks,"sr"),l(ks,"runDebug");async function $s(t,n,e,s){return vn(n,t.cwd,{daemonRequest:R,registrationBody:re,git:l((o,r)=>{const a=A("git",r,{cwd:o,encoding:"utf8",timeout:1e4});return a.status===0&&typeof a.stdout=="string"&&a.stdout.trim()?a.stdout.trim():void 0},"git"),stopMcpServer:l((o,r)=>{let a;try{a=te(o,t.env??process.env).port}catch{return}const c=Se({identity:Pe(a),targetVersion:Y(),expectedRoot:ye(o),expectedKey:r,port:a,selfPid:process.pid,stopFor:"its worktree instance was removed"});if(!c.kill)return c.reason.startsWith("no shared MCP server answered")?void 0:`left :${a} alone \u2014 ${c.reason}`;try{return process.kill(c.pid,"SIGTERM"),`stopped its lens server :${a} (pid ${c.pid})`}catch(d){return`could not stop its lens server :${a} (pid ${c.pid}): ${d.message}`}},"stopMcpServer"),env:t.env??process.env},e,s)}p($s,"rr"),l($s,"runInstance");async function bs(t,n,e,s){return wn(n,t.cwd,e,s,{discover:oe,resolveService:ke,workspaceKey:l(o=>{try{return he(J(o))}catch{return}},"workspaceKey"),analyzerScript:w(D(Xe(import.meta.url)),"heap-analyzer-main.js"),env:t.env??process.env})}p(bs,"or"),l(bs,"runMem");async function Cs(t,n){let e;try{e=he(J(t))}catch{e=void 0}const s=[],o=[];for(const a of oe().filter(c=>c.wsKey===e||c.wsKey==="")){const c=await fn(a);if(!c.memory){a.wsKey===e&&o.push(`${a.service}: ${c.error??"no answer"}`);continue}const d=c.memory.bundle.path;if(a.wsKey===""&&!d.startsWith(t+"/"))continue;const i=c.memory.pods.map(g=>g.latest?.sourceMaps).filter(g=>typeof g=="boolean"),h=await bn(d);s.push({service:a.service,...i.length?{sourceMaps:i.some(Boolean)}:{},...h?{bundle:h}:{}})}const r=Cn(s,o);N(n,r.status,"running services keep one copy of their bundle text",r.detail,r.hint)}p(Cs,"ir"),l(Cs,"checkPodSourceMaps");async function Ss(t,n,e){const s=Sn(await xn(t,n));N(e,s.status,"performance rules (perf://rules)",s.detail,s.hint)}p(Ss,"ar"),l(Ss,"checkPerfRules");function $(t){if(t!==void 0)return typeof t=="string"?t:void 0}p($,"C"),l($,"stringFlag");function I(t,n={}){const e=new Set(n.string??[]),s=new Set(n.boolean??[]),o={},r=[];for(let a=0;a<t.length;a++){const c=t[a];if(c.startsWith("--")){const d=c.indexOf("="),i=d===-1?c:c.slice(0,d);if(s.has(i))o[i]=!0;else if(e.has(i))if(d!==-1)o[i]=c.slice(d+1);else{const h=t[a+1];h===void 0||h.startsWith("--")?o[i]="":(o[i]=h,a++)}else o[i]=d===-1?!0:c.slice(d+1)}else r.push(c)}return{flags:o,positional:r}}p(I,"I"),l(I,"parseFlags");
308
+ `).find(e=>e.startsWith("n"));return n&&n.slice(1).trim()||void 0}catch{return}}p(gs,"Xs"),l(gs,"cwdOfPid");function ms(t,n){const e=Ye(T(t),T(n));return e===""||!e.startsWith("..")&&!Rs(e)}p(ms,"Zs"),l(ms,"isInside");function fs(t,n){return oe().filter(e=>{if(e.wsKey)return e.wsKey===n;const s=We(e.sock),o=s!==void 0?gs(s):void 0;return o!==void 0&&ms(t,o)})}p(fs,"Qs"),l(fs,"workspaceDevservers");function ws(t,n,e,s){const o=fs(t,n);if(o.length===0)return e(" no devserver pods running for this workspace \u2014 nothing to recycle."),{killed:0,stale:0};s&&e(` \xB7 recycling ${o.length} pod${o.length===1?"":"s"} because ${s}`);const r=new Set;for(const d of[process.pid,...W()]){const i=Ue(d);i!==void 0&&r.add(i)}let a=0,c=0;for(const d of o){const i=J(d),h=We(d.sock);if(h===void 0){z(d.sock),e(` \u2713 ${i} \u2014 stale socket removed (no process held it)`),c++;continue}const g=Ue(h),m=g!==void 0&&!r.has(g),f=l(v=>{try{m?process.kill(-g,v):process.kill(h,v)}catch{}},"signal");f("SIGTERM"),Je(h,5e3)||(f("SIGKILL"),Je(h,2e3)),z(d.sock),e(` \u2713 ${i} \u2014 stopped (pid ${h}${m?`, group ${g}`:", parent only"})`),a++}return{killed:a,stale:c}}p(ws,"er"),l(ws,"reapWorkspacePods");function Je(t,n){const e=Date.now()+n;for(;;){if(!ie(t))return!0;if(Date.now()>=e)return!1;A("sleep",["0.15"])}}p(Je,"gt"),l(Je,"waitForPidGone");function ys(t,n,e,s){const o=w(n,".lensmcp","gateway.pid"),r=w(n,".lensmcp","registered.json"),{pid:a,healed:c}=ce(o,n);if(c&&s(` healed: adopted a running gateway (pid ${a}) the pid file had lost.`),ae(n,t.env,m=>s(` ${m}`)),U(n)!==void 0){s(` gateway: this workspace owns the :443 daemon (pid ${a??"?"}) \u2014 left running, pods respawn fresh.`);return}const d=R("GET","/list");if(d?.status!==200){s(" gateway: not running. Start it when you are ready: lensmcp gateway start");return}const i=d.json&&typeof d.json=="object"?d.json.workspaces??[]:[],h=Ee(i,e,n);if(h.kind==="other-checkout"){for(const m of it(e,h.root,n))s(` gateway: ${m}`);return}if(h.kind==="mine"){Q(D(r),{recursive:!0}),X(r,JSON.stringify({wsKey:e})),s(` gateway: '${e}' is already registered into the shared daemon \u2014 left serving.`);return}const g=R("POST","/register",re(n,e));if(g&&g.status===200){Q(D(r),{recursive:!0}),X(r,JSON.stringify({wsKey:e})),s(` gateway: registered '${e}' into the shared daemon \u2014 it now hosts this workspace.`);const m=Me(g.json);m&&s(m);return}s(` gateway: a shared daemon is up but registering this workspace failed \u2014 ${we(g)??"run `lensmcp gateway start`"}.`)}p(ys,"tr"),l(ys,"reconcileGatewayAfterSetup");function $e(t,n,e,s){let o=n.filter(r=>r.service===t||J(r)===t);if(!t.includes("/"))try{const r=H(e),a=ge(r),c=o.filter(d=>d.wsKey===a);(he(r)||o.length>1&&c.length===1)&&(o=c)}catch{}return o.length===0?(s(`No running service named "${t}".`),n.length>0&&s(`Running: ${n.map(J).join(", ")}`),null):o.length>1?(s(`"${t}" is ambiguous \u2014 use one of: ${o.map(J).join(", ")}`),null):o[0]}p($e,"Me"),l($e,"resolveServiceSock");async function vs(t,n,e,s){const o=I(n,{string:["--tail","--cwd"],boolean:["--no-follow","--follow","--plain","--color"]}),r=o.positional[0],a=oe();if(!r){if(a.length===0)e("No running services found (no devserver control sockets under $TMPDIR)."),e("Start one with `yarn nx serve <project>` or `lensmcp gateway start`.");else{e("Running services \u2014 attach with `lensmcp logs <service>`:");for(const v of a)e(` ${J(v)}`)}return{exitCode:0}}const c=$e(r,a,T($(o.flags["--cwd"])??t.cwd),s);if(!c)return{exitCode:1};const{follow:d,hint:i}=Ds({noFollow:o.flags["--no-follow"]===!0,follow:o.flags["--follow"]===!0,color:o.flags["--color"]===!0,isTTY:process.stdout.isTTY===!0}),h=Number($(o.flags["--tail"])??NaN),g=Number.isInteger(h)&&h>=0?h:100,m=o.flags["--plain"]===!0||o.flags["--color"]!==!0&&!process.stdout.isTTY,f=`/webpack/logs?tail=${g}&follow=${d?1:0}${m?"&plain=1":""}`;return new Promise(v=>{const b=ze({socketPath:c.sock,path:f,method:"GET"},k=>{k.on("data",M=>process.stdout.write(M)),_s(()=>{k.destroy(),v({exitCode:0})}),k.on("end",()=>{i&&s(i),v({exitCode:0})}),k.on("error",()=>v({exitCode:1}))});b.on("error",k=>{s(`Cannot attach to ${J(c)}: ${k.message}`),s("The devserver may have crashed leaving a stale socket \u2014 restart the service and retry."),v({exitCode:1})}),b.end()})}p(vs,"nr"),l(vs,"runLogs");async function ks(t,n,e,s){const o=I(n,{string:["--port","--cwd"]}),r=o.positional[0],a=oe();if(!r)return s("Usage: lensmcp debug <service> [--port <base>]"),a.length>0&&s(`Running: ${a.map(J).join(", ")}`),{exitCode:2};const c=$e(r,a,T($(o.flags["--cwd"])??t.cwd),s);if(!c)return{exitCode:1};const d=Number($(o.flags["--port"])??"")||void 0,i=`/webpack/debug${d?`?port=${d}`:""}`,h=await new Promise(m=>{const f=ze({socketPath:c.sock,path:i,method:"POST"},v=>{let b="";v.on("data",k=>b+=k),v.on("end",()=>m(b)),v.on("error",()=>m(null))});f.on("error",()=>m(null)),f.end()});if(h===null)return s(`Cannot reach ${J(c)} \u2014 the devserver may have crashed leaving a stale socket.`),{exitCode:1};let g;try{g=JSON.parse(h)}catch{return s(`Unexpected response from the devserver: ${h.slice(0,200)}`),{exitCode:1}}e(`Inspectors open on ${J(c)} \u2014 in place, no restart:`);for(const m of g.pods??[])e(` pod #${m.id} ${m.inspectorUrl??"(no url reported \u2014 check lensmcp logs)"}`);for(const m of g.workers??[])e(` worker ${m.name} ${m.inspectorUrl??`127.0.0.1:${m.port}`}`);return e(g.fixedPorts&&g.basePort?`Attach WebStorm (Run \u2192 Attach to Node.js/Chrome) to 127.0.0.1:${g.basePort} \u2014 or click the "Debugger listening" link in \`lensmcp logs ${r}\`.`:`Attach with one of the URLs above \u2014 Chrome DevTools (devtools://devtools/bundled/js_app.html?ws=<host:port/uuid>), VS Code (attach, "websocketAddress"), or WebStorm's click-to-attach on the URL. The ports are ephemeral and do not answer /json/list, so a host:port attach finds nothing; set LENSMCP_DEBUG_FIXED_PORTS=1 if your IDE needs one.`),{exitCode:0}}p(ks,"sr"),l(ks,"runDebug");async function $s(t,n,e,s){return vn(n,t.cwd,{daemonRequest:R,registrationBody:re,git:l((o,r)=>{const a=A("git",r,{cwd:o,encoding:"utf8",timeout:1e4});return a.status===0&&typeof a.stdout=="string"&&a.stdout.trim()?a.stdout.trim():void 0},"git"),stopMcpServer:l((o,r)=>{let a;try{a=te(o,t.env??process.env).port}catch{return}const c=Se({identity:Pe(a),targetVersion:Y(),expectedRoot:ve(o),expectedKey:r,port:a,selfPid:process.pid,stopFor:"its worktree instance was removed"});if(!c.kill)return c.reason.startsWith("no shared MCP server answered")?void 0:`left :${a} alone \u2014 ${c.reason}`;try{return process.kill(c.pid,"SIGTERM"),`stopped its lens server :${a} (pid ${c.pid})`}catch(d){return`could not stop its lens server :${a} (pid ${c.pid}): ${d.message}`}},"stopMcpServer"),env:t.env??process.env},e,s)}p($s,"rr"),l($s,"runInstance");async function bs(t,n,e,s){return wn(n,t.cwd,e,s,{discover:oe,resolveService:$e,workspaceKey:l(o=>{try{return ge(H(o))}catch{return}},"workspaceKey"),analyzerScript:w(D(Xe(import.meta.url)),"heap-analyzer-main.js"),env:t.env??process.env})}p(bs,"or"),l(bs,"runMem");async function Cs(t,n){let e;try{e=ge(H(t))}catch{e=void 0}const s=[],o=[];for(const a of oe().filter(c=>c.wsKey===e||c.wsKey==="")){const c=await fn(a);if(!c.memory){a.wsKey===e&&o.push(`${a.service}: ${c.error??"no answer"}`);continue}const d=c.memory.bundle.path;if(a.wsKey===""&&!d.startsWith(t+"/"))continue;const i=c.memory.pods.map(g=>g.latest?.sourceMaps).filter(g=>typeof g=="boolean"),h=await bn(d);s.push({service:a.service,...i.length?{sourceMaps:i.some(Boolean)}:{},...h?{bundle:h}:{}})}const r=Cn(s,o);N(n,r.status,"running services keep one copy of their bundle text",r.detail,r.hint)}p(Cs,"ir"),l(Cs,"checkPodSourceMaps");async function Ss(t,n,e){const s=Sn(await xn(t,n));N(e,s.status,"performance rules (perf://rules)",s.detail,s.hint)}p(Ss,"ar"),l(Ss,"checkPerfRules");function $(t){if(t!==void 0)return typeof t=="string"?t:void 0}p($,"C"),l($,"stringFlag");function I(t,n={}){const e=new Set(n.string??[]),s=new Set(n.boolean??[]),o={},r=[];for(let a=0;a<t.length;a++){const c=t[a];if(c.startsWith("--")){const d=c.indexOf("="),i=d===-1?c:c.slice(0,d);if(s.has(i))o[i]=!0;else if(e.has(i))if(d!==-1)o[i]=c.slice(d+1);else{const h=t[a+1];h===void 0||h.startsWith("--")?o[i]="":(o[i]=h,a++)}else o[i]=d===-1?!0:c.slice(d+1)}else r.push(c)}return{flags:o,positional:r}}p(I,"I"),l(I,"parseFlags");
@@ -58,7 +58,7 @@ export interface InstanceResult {
58
58
  exitCode: number;
59
59
  instance?: StartedInstance;
60
60
  }
61
- export declare const INSTANCE_USAGE = "Usage:\n lensmcp instance create <name> [--branch <branch> | --detach] [--from <commit>] [--frozen] [--no-prepare] [--share-stores] [--json] [--cwd <dir>]\n Make a git worktree of this checkout and start it as an instance (what a coding agent's\n MCP worktree_create runs): on <branch> (default lensmcp/<name>, made from --from, default\n HEAD), in nx.json \u2192 lensmcp.instances.worktrees (default .lensmcp/worktrees/<name>).\n lensmcp instance start [--name <name>] [--apex <apex>] [--frozen | --live] [--prepare | --no-prepare] [--share-stores] [--cwd <dir>]\n Serve this checkout beside the main one, under hosts named after it, with its own\n data (nx.json \u2192 lensmcp.instances). In a git worktree the name defaults to the\n worktree folder's. --frozen: serve the commit as it is \u2014 each service compiles\n once, no watcher, no type checker (--live undoes it; the default is live).\n --share-stores: start a project that declares no resources.\n lensmcp instance list [--json]\n lensmcp instance status [<name>] [--json] [--cwd <dir>]\n lensmcp instance exec [<name>] [--cwd <dir>] -- <command> [args\u2026]\n Run a command with the instance's variables (LENSMCP_HOST_<PROJECT>, \u2026).\n lensmcp instance stop [<name>] [--cwd <dir>]\n Unregister it from the gateway (its services stop); `start` brings it back.\n lensmcp instance rm [<name>] [--keep-data] [--worktree [--delete-branch] [--force]] [--json] [--cwd <dir>]\n Stop it, drop the data the lens made for it, and clear its lens state. --worktree also\n removes the git worktree \u2014 refused while it has uncommitted changes, unless --force;\n --delete-branch deletes a branch the lens made, once merged (--force: even unmerged).\n lensmcp instance prune [--dry-run]\n Remove every instance whose folder is gone, data included.";
61
+ export declare const INSTANCE_USAGE = "Usage:\n lensmcp instance create <name> [--branch <branch> | --detach] [--from <commit>] [--frozen] [--no-prepare] [--share-stores] [--json] [--cwd <dir>]\n Make a git worktree of this checkout and start it as an instance (what a coding agent's\n MCP worktree_create runs): on <branch> (default lensmcp/<name>, made from --from, default\n HEAD), in nx.json \u2192 lensmcp.instances.worktrees (default .lensmcp/worktrees/<name>).\n lensmcp instance start [--name <name>] [--apex <apex>] [--frozen | --live] [--prepare | --no-prepare] [--share-stores] [--cwd <dir>]\n Serve this checkout beside the main one, under hosts named after it, with its own\n data (nx.json \u2192 lensmcp.instances). In a git worktree the name defaults to the\n worktree folder's. --frozen: serve the commit as it is \u2014 each service compiles\n once, no watcher, no type checker (--live undoes it; the default is live).\n --share-stores: start a project that declares no resources.\n Preparation must succeed before services start; failed or unfinished preparation retries\n on the next start. --prepare runs it again; --no-prepare explicitly skips it for this start.\n lensmcp instance list [--json]\n lensmcp instance status [<name>] [--json] [--cwd <dir>]\n lensmcp instance exec [<name>] [--cwd <dir>] -- <command> [args\u2026]\n Run a command with the instance's variables (LENSMCP_HOST_<PROJECT>, \u2026).\n lensmcp instance stop [<name>] [--cwd <dir>]\n Unregister it from the gateway (its services stop); `start` brings it back.\n lensmcp instance rm [<name>] [--keep-data] [--worktree [--delete-branch] [--force]] [--json] [--cwd <dir>]\n Stop it, drop the data the lens made for it, and clear its lens state. --worktree also\n removes the git worktree \u2014 refused while it has uncommitted changes, unless --force;\n --delete-branch deletes a branch the lens made, once merged (--force: even unmerged).\n lensmcp instance prune [--dry-run]\n Remove every instance whose folder is gone, data included.";
62
62
  /** A linked worktree's facts, from git. */
63
63
  export interface WorktreeInfo {
64
64
  /** The checkout's top-level directory. */