lensmcp 1.23.3 → 1.23.4
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/bin.js +1 -1
- package/lib/agent-plugins.js +2 -2
- package/lib/cli-help.js +3 -3
- package/lib/cli.js +16 -16
- package/lib/duplicate-registration.js +1 -1
- package/lib/hook-memory.js +1 -1
- package/lib/mcp-mode.js +2 -2
- package/lib/mcp-restart.js +1 -1
- package/lib/mcp-wiring.js +2 -2
- package/lib/plugin-version.js +3 -3
- package/lib/process-identity.js +1 -1
- package/lib/recycle-policy.js +1 -1
- package/lib/status-client.js +2 -2
- package/lib/status-policy.js +2 -2
- package/lib/sweep.js +1 -1
- package/lib/upgrade.js +1 -1
- package/lib/workspace-scope.js +2 -2
- package/package.json +3 -3
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugins/lensmcp/.codex-plugin/plugin.json +1 -1
package/bin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";import{runCli as
|
|
2
|
+
"use strict";import{runCli as r}from"./lib/cli.js";import{ignoreEpipe as e}from"./lib/cli-help.js";e(process.stdout),e(process.stderr),r({cwd:process.cwd(),argv:process.argv.slice(2)}).then(s=>{process.exit(s.exitCode)},s=>{console.error(s instanceof Error?s.stack??s.message:String(s)),process.exit(1)});
|
package/lib/agent-plugins.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`).filter(Boolean).pop();return{...a,outcome:"failed",detail:f&&f.length>0?f:`\`${
|
|
1
|
+
"use strict";var y=Object.defineProperty;var l=(e,n)=>y(e,"name",{value:n,configurable:!0});var P=Object.defineProperty,u=l((e,n)=>P(e,"name",{value:n,configurable:!0}),"l"),j=Object.defineProperty,d=u((e,n)=>j(e,"name",{value:n,configurable:!0}),"d");import{spawnSync as A}from"node:child_process";import{existsSync as v,readFileSync as x}from"node:fs";import{dirname as I,isAbsolute as h,join as c,resolve as b}from"node:path";export const MARKETPLACE="lensmcp-marketplace",PLUGIN="lensmcp",PLUGIN_ID=`${PLUGIN}@${MARKETPLACE}`,AGENTS=[{id:"claude",label:"Claude Code",bin:"claude",manifest:".claude-plugin/marketplace.json",pluginManifest:"plugin/.claude-plugin/plugin.json",since:"1.9.0",restartHint:"restart Claude Code (or run /plugin) for the new version to load"},{id:"codex",label:"Codex",bin:"codex",manifest:".agents/plugins/marketplace.json",pluginManifest:"plugins/lensmcp/.codex-plugin/plugin.json",since:"1.20.0",restartHint:"start a new Codex thread for the plugin to load"}];export function agentById(e){return AGENTS.find(n=>n.id===e)}l(agentById,"agentById"),u(agentById,"agentById"),d(agentById,"agentById");export function resolvePluginRoot(e){const n=e.exists??v,t=d(r=>{try{const s=JSON.parse(x(c(r,"package.json"),"utf8"));return typeof s.version=="string"?s.version:void 0}catch{return}},"readVersion"),i=d((r,s)=>{const a=t(r);return{root:r,source:s,...a?{version:a}:{}}},"decorate");if(e.from){const r=h(e.from)?e.from:b(e.cwd,e.from);return n(c(r,"package.json"))?i(r,"flag"):void 0}let o=b(e.cwd);for(let r=0;r<8;r++){const s=c(o,"node_modules","lensmcp");if(n(c(s,"package.json")))return i(s,"workspace");const a=I(o);if(a===o)break;o=a}if(e.selfRoot&&n(c(e.selfRoot,"package.json")))return i(e.selfRoot,"self")}l(resolvePluginRoot,"resolvePluginRoot"),u(resolvePluginRoot,"resolvePluginRoot"),d(resolvePluginRoot,"resolvePluginRoot");export function readPluginManifestVersion(e,n){try{const t=JSON.parse(x(c(e,n.pluginManifest),"utf8"));return typeof t.version=="string"?t.version:void 0}catch{return}}l(readPluginManifestVersion,"readPluginManifestVersion"),u(readPluginManifestVersion,"readPluginManifestVersion"),d(readPluginManifestVersion,"readPluginManifestVersion");export function planAgentInstall(e,n){if(e.id==="codex")return[[e.bin,"plugin","marketplace","add",n.root],[e.bin,"plugin","add",PLUGIN_ID]];const t=n.scope?["--scope",n.scope]:[];return[[e.bin,"plugin","marketplace","add",n.root],[e.bin,"plugin","marketplace","update",MARKETPLACE],[e.bin,"plugin","install",PLUGIN_ID,...t,"--yes"]]}l(planAgentInstall,"planAgentInstall"),u(planAgentInstall,"planAgentInstall"),d(planAgentInstall,"planAgentInstall");export function installAgentPlugin(e,n,t){const i=t.exists??v,o=planAgentInstall(e,n),r=o.map(g=>g.join(" ")),s=readPluginManifestVersion(n.root,e),a={agent:e.id,label:e.label,commands:r,...s?{version:s}:{}};if(!i(c(n.root,e.manifest)))return{...a,outcome:"skipped-not-packaged",detail:`${n.root} ships no ${e.manifest} \u2014 the ${e.label} plugin arrived in lensmcp ${e.since}. Upgrade first: \`lensmcp upgrade\`.`};for(const g of o){const[m,...k]=g,p=m===void 0?void 0:t.run(m,k);if(!p)return{...a,outcome:"skipped-no-cli",detail:`\`${e.bin}\` is not on PATH`};if(p.code!==0){const f=(p.stderr??p.stdout??"").trim().split(`
|
|
2
|
+
`).filter(Boolean).pop();return{...a,outcome:"failed",detail:f&&f.length>0?f:`\`${g.join(" ")}\` exited ${p.code}`}}}return{...a,outcome:"installed",restartHint:e.restartHint}}l(installAgentPlugin,"installAgentPlugin"),u(installAgentPlugin,"installAgentPlugin"),d(installAgentPlugin,"installAgentPlugin");export function spawnAgentRunner(e,n=12e4){return(t,i)=>{try{const o=A(t,i,{encoding:"utf8",timeout:n,env:e,stdio:["ignore","pipe","pipe"]});return o.error&&o.error.code==="ENOENT"?void 0:{code:o.status??1,...o.stdout?{stdout:o.stdout}:{},...o.stderr?{stderr:o.stderr}:{}}}catch{return}}}l(spawnAgentRunner,"spawnAgentRunner"),u(spawnAgentRunner,"spawnAgentRunner"),d(spawnAgentRunner,"spawnAgentRunner");export function codexInstalledVersion(e){const n=e("codex",["plugin","list","--json"]);if(!(!n||n.code!==0||!n.stdout))try{const t=(JSON.parse(n.stdout).installed??[]).find(i=>i.pluginId===PLUGIN_ID||i.name===PLUGIN&&i.marketplaceName===MARKETPLACE)?.version;return typeof t=="string"?t:void 0}catch{return}}l(codexInstalledVersion,"codexInstalledVersion"),u(codexInstalledVersion,"codexInstalledVersion"),d(codexInstalledVersion,"codexInstalledVersion");
|
package/lib/cli-help.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`);let
|
|
3
|
-
`).replace(/\s+$/,"")}o(commandUsage,"commandUsage"),
|
|
1
|
+
"use strict";var k=Object.defineProperty;var r=(t,e)=>k(t,"name",{value:e,configurable:!0});var O=Object.defineProperty,o=r((t,e)=>O(t,"name",{value:e,configurable:!0}),"o"),d=Object.defineProperty,u=o((t,e)=>d(t,"name",{value:e,configurable:!0}),"r");const B=new Set(["rollout"]);export function wantsHelp(t,e){const s=e!==void 0&&B.has(e);for(const n of t){if(s&&n==="--")break;if(n==="--help"||n==="-h")return!0}return!1}r(wantsHelp,"wantsHelp"),o(wantsHelp,"wantsHelp"),u(wantsHelp,"wantsHelp");const h={plugins:"plugin"};function a(t){return/^ {2}\S/.test(t)}r(a,"f"),o(a,"l"),u(a,"opensBlock");export function commandUsage(t,e){const s=h[e]??e,n=t.split(`
|
|
2
|
+
`);let p=-1;for(let i=0;i<n.length;i++){if(!a(n[i]))continue;const l=n[i].slice(2);if(l===s||l.startsWith(`${s} `)){p=i;break}}if(p===-1)return;let c=p+1;for(;c<n.length&&!a(n[c]);)c++;return["Usage:",...n.slice(p,c)].join(`
|
|
3
|
+
`).replace(/\s+$/,"")}r(commandUsage,"commandUsage"),o(commandUsage,"commandUsage"),u(commandUsage,"commandUsage");export function ignoreEpipe(t){t.on("error",e=>{if(e?.code==="EPIPE"){f=!0;for(const s of g)try{s()}catch{}return}throw e})}r(ignoreEpipe,"ignoreEpipe"),o(ignoreEpipe,"ignoreEpipe"),u(ignoreEpipe,"ignoreEpipe");const g=new Set;export function onOutputBroken(t){if(f){t();return}g.add(t)}r(onOutputBroken,"onOutputBroken"),o(onOutputBroken,"onOutputBroken"),u(onOutputBroken,"onOutputBroken");let f=!1;export function isOutputBroken(){return f}r(isOutputBroken,"isOutputBroken"),o(isOutputBroken,"isOutputBroken"),u(isOutputBroken,"isOutputBroken");export function resetOutputBrokenForTests(){f=!1}r(resetOutputBrokenForTests,"resetOutputBrokenForTests"),o(resetOutputBrokenForTests,"resetOutputBrokenForTests"),u(resetOutputBrokenForTests,"resetOutputBrokenForTests");
|
package/lib/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var Zt=Object.defineProperty;var p=(t,n)=>Zt(t,"name",{value:n,configurable:!0});var Qt=Object.defineProperty,g=p((t,n)=>Qt(t,"name",{value:n,configurable:!0}),"p"),es=Object.defineProperty,l=g((t,n)=>es(t,"name",{value:n,configurable:!0}),"l");import{spawn as ts,spawnSync as M}from"node:child_process";import{existsSync as S,mkdirSync as Z,openSync as ss,readFileSync as B,readdirSync as ge,realpathSync as ns,rmSync as os,statSync as Tt,writeFileSync as z}from"node:fs";import{request as Mt}from"node:http";import{homedir as rs,tmpdir as as}from"node:os";import{basename as he,dirname as _,isAbsolute as is,join as w,relative as Lt,resolve as L}from"node:path";import{fileURLToPath as cs}from"node:url";import{ensureLensConfig as q,readLensConfig as ds}from"./workspace-scope.js";import{commandUsage as ls,onOutputBroken as us,wantsHelp as ps}from"./cli-help.js";import{decideRecycle as gs,hashConfig as hs}from"./recycle-policy.js";import{planMcpRestart as Ot}from"./mcp-restart.js";import{detectDuplicateRegistration as fs,disabledMcpServers as Rt,mcpServerNames as At,pluginEnabledInSettings as It}from"./duplicate-registration.js";import{readTrackedPid as ms,stillSameProcess as ws,writeTrackedPid as _t}from"./process-identity.js";import{remember as ys,shouldAnnounce as vs}from"./hook-memory.js";import{isMcpMode as Dt}from"./mcp-mode.js";import{effectiveMcpMode as ks,LENS_CONFIG as $s,probeIdentitySync as Ft,probeSharedMcp as Kt,probeSharedMcpSync as bs,readMcpWiring as ce,wireMcpMode as Cs}from"./mcp-wiring.js";import{sweepLensRuntimeFiles as Gt}from"./sweep.js";import{candidateSignals as xs,findingLine as Ss,findingsDigest as js,formatContext as Ns,hookPayload as Ht,isHookEvent as Bt,select as Ps}from"./status-policy.js";import{DEFAULT_BUDGET_MS as Es,readStatus as Ts}from"./status-client.js";import{detectSkew as Ms,formatSkewContext as Vt,readInstalledPlugin as Jt,readInstalledPlugins as Wt,readVersions as Ut,spawnRunner as Ls,syncPlugin as Os,updateCommands as Rs}from"./plugin-version.js";import{AGENTS as zt,agentById as As,codexInstalledVersion as Is,installAgentPlugin as _s,MARKETPLACE as Ds,PLUGIN_ID as Q,readPluginManifestVersion as Fs,resolvePluginRoot as qt,spawnAgentRunner as Yt}from"./agent-plugins.js";import{detectGlobalInstall as Ks,detectPackageManager as Gs,planRestart as Hs,readConnectedWorkspaces as Bs,rewriteLensmcpDeps as Vs}from"./upgrade.js";const fe=`lensmcp \u2014 CLI for LensMCP (FrontMCP-based observability for coding agents)
|
|
2
2
|
|
|
3
3
|
Usage:
|
|
4
4
|
lensmcp <command> [options]
|
|
@@ -167,32 +167,32 @@ Commands:
|
|
|
167
167
|
listening" link in \`lensmcp logs <service>\`.
|
|
168
168
|
--version Print the lensmcp version.
|
|
169
169
|
--help Show this help.
|
|
170
|
-
`;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(
|
|
170
|
+
`;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(fe),{exitCode:0};if(s==="--version"||s==="-V")return n(U()),{exitCode:0};if(ps(o,s))return n(ls(fe,s)??fe),{exitCode:0};switch(s){case"setup":return Ze(t,o,n,e);case"mcp":return Ie(t,o,n,e);case"dashboard":return _e(t,o,n,e);case"gateway":return me(t,o,n,e);case"bridge":return ze(t,o,n,e);case"install":return $e(t,o,n,e);case"plugin":case"plugins":return ut(t,o,n,e);case"upgrade":return ft(t,o,n,e);case"trust":return be(t,o,n,e);case"status":return Qe(t,o,n);case"version-check":return et(t,o,n);case"doctor":return tt(t,o,n);case"prune":return Re(t,o,n,e);case"rollout":return yt(t,o,e);case"logs":return Pt(t,o,n,e);case"debug":return Et(t,o,n,e);default:return e(`Unknown command: ${s}`),e(fe),{exitCode:2,message:`Unknown command: ${s}`}}}p(runCli,"runCli"),g(runCli,"runCli"),l(runCli,"runCli");function Re(t,n,e,s){const o=R(n,{string:["--cwd"],boolean:["--force"]}),r=L(b(o.flags["--cwd"])??t.cwd),a=w(r,".lensmcp"),c=w(a,"gateway.log"),d=l(()=>{try{return ge(a).reduce((m,y)=>{try{return m+Tt(w(a,y)).size}catch{return m}},0)}catch{return 0}},"dirBytes"),i=l(m=>`${(m/1048576).toFixed(1)} MB`,"mb"),u=d();if(u===0)return e(`nothing to prune \u2014 no .lensmcp runtime files at ${a}`),{exitCode:0};if(o.flags["--force"]!==!0&&Ae(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/foodguard/13). Stop it first:"),s(" lensmcp gateway stop"),s("\u2026or pass --force if you accept losing recent history."),{exitCode:1,message:"gateway running"};Gt(r,c);const h=d();return e(`pruned ${a}`),e(` ${i(u)} \u2192 ${i(h)} (reclaimed ${i(Math.max(0,u-h))})`),{exitCode:0}}p(Re,"et"),g(Re,"Wn"),l(Re,"runPrune");function Ae(t){try{return ye(w(t,"gateway.pid"))!==void 0}catch{return!1}}p(Ae,"tt"),g(Ae,"Un"),l(Ae,"gatewayPidAlive");function Ie(t,n,e,s){const o=R(n,{string:["--cwd","--transport","--port","--mcp"]}),r=L(b(o.flags["--cwd"])??t.cwd),a=q(r),c=b(o.flags["--transport"])??t.env?.LENSMCP_TRANSPORT??"stdio",d=b(o.flags["--port"])??t.env?.LENSMCP_PORT??String(a.ports.mcpHttp),i=ks(r,b(o.flags["--mcp"]),{...process.env,...t.env??{}})==="shared"&&c==="stdio",u=i?kt(r)??le(r):le(r);if(!u)return s(`Could not locate the lensmcp-mcp server bundle.
|
|
171
171
|
Looked in (in order):
|
|
172
172
|
\u2022 <cli-package>/bundled/main.js (published bin)
|
|
173
173
|
\u2022 <workspace>/apps/lensmcp-mcp/dist/main.js (dev build)
|
|
174
|
-
For dev: \`yarn nx build @lensmcp/lensmcp-mcp\`.`),{exitCode:1};ie(r);const
|
|
174
|
+
For dev: \`yarn nx build @lensmcp/lensmcp-mcp\`.`),{exitCode:1};ie(r);const h=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(r,".lensmcp","events.jsonl"),m={...process.env,...t.env??{},LENSMCP_TRANSPORT:c,LENSMCP_PORT:d,LENSMCP_EVENT_FILE:h},y=i?[u,"--cwd",r]:[u];return{exitCode:M(process.execPath,y,{cwd:r,stdio:"inherit",env:m}).status??1}}p(Ie,"st"),g(Ie,"qn"),l(Ie,"runMcp");function _e(t,n,e,s){const o=R(n,{string:["--cwd","--port","--base"]}),r=L(b(o.flags["--cwd"])??t.cwd),a=q(r),c=b(o.flags["--port"])??t.env?.LENSMCP_DASHBOARD_PORT??String(a.ports.dashboard),d=b(o.flags["--base"])??t.env?.LENSMCP_DASHBOARD_BASE??"",i=ue(r,"dashboard.js");if(!i)return s(`Could not locate the lensmcp dashboard bundle.
|
|
175
175
|
Looked in (in order):
|
|
176
176
|
\u2022 <cli-package>/bundled/dashboard.js (published bin)
|
|
177
177
|
\u2022 <workspace>/servers/lensmcp-mcp/dist/dashboard.js (dev build)
|
|
178
|
-
For dev: \`yarn nx build @lensmcp/lensmcp-mcp\`.`),{exitCode:1};ie(r);const u=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??
|
|
179
|
-
%{http_code}`,"--unix-socket",s,"-X",t,`http://localhost${n}`];e!==void 0&&o.push("-H","content-type: application/json","-d",JSON.stringify(e));const r=
|
|
178
|
+
For dev: \`yarn nx build @lensmcp/lensmcp-mcp\`.`),{exitCode:1};ie(r);const u=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 ${u})`),{exitCode:M(process.execPath,[i],{cwd:r,stdio:"inherit",env:{...process.env,...t.env??{},LENSMCP_DASHBOARD_PORT:c,LENSMCP_DASHBOARD_BASE:d,LENSMCP_EVENT_FILE:u}}).status??1}}p(_e,"nt"),g(_e,"zn"),l(_e,"runDashboard");function De(){return w(process.env.LENSMCP_HOME||rs(),".lensmcp","control.sock")}p(De,"ot"),g(De,"Yn"),l(De,"controlSocketPath");function O(t,n,e){const s=De();if(!S(s))return null;const o=["-s","-o","-","-w",`
|
|
179
|
+
%{http_code}`,"--unix-socket",s,"-X",t,`http://localhost${n}`];e!==void 0&&o.push("-H","content-type: application/json","-d",JSON.stringify(e));const r=M("curl",o,{encoding:"utf8",timeout:5e3});if(r.status!==0||typeof r.stdout!="string"||r.stdout.length===0)return null;const a=r.stdout.split(`
|
|
180
180
|
`),c=Number(a.pop());let d=null;try{const i=a.join(`
|
|
181
|
-
`).trim();d=i?JSON.parse(i):null}catch{}return Number.isFinite(c)?{status:c,json:d}:null}p(O,"R"),l(O,"daemonRequest");function
|
|
182
|
-
Free it first (stop that process), then \`lensmcp gateway start\`.`),{exitCode:1}}const E=ct(c,$(o.flags["--project"]),$(o.flags["--target"]));if(!E)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 S=ae(c);if(!S)return s("Could not find the `nx` binary in the workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};Ve(c,u);const L=es(u,"a"),I=Qt(S,["run",`${E.project}:${E.target}`],{cwd:c,detached:!0,stdio:["ignore",L,L],env:{...process.env,...t.env??{}}});return I.unref(),I.pid&&Ke(i,I.pid),e(`gateway starting \u2192 ${E.project}:${E.target} (pid ${I.pid??"?"})`),e(` dashboard \u2192 ${f}`),e(` logs \u2192 ${u}`),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"),v=l(()=>{if(x(g)&&H(c)===void 0){let S=d.key;try{S=JSON.parse(K(g,"utf8")).wsKey??d.key}catch{}const L=O("POST","/unregister",{wsKey:S});return V(g),e(L&&L.status===200?`unregistered '${S}' from the shared gateway daemon.`:"unregister sent (the daemon may already be gone)."),{exitCode:0}}V(g);const{pid:y,healed:h}=se(i,c);if(y===void 0)return e("gateway not running."),V(i),{exitCode:0};h&&e(`healed: found an orphaned gateway (pid ${y}) the pid file had lost \u2014 stopping it.`),ne(y);let b=!1;if(!ke(6e3)){b=!0,ne(y,"SIGKILL");const S=H(c);if(S!==void 0)try{process.kill(S,"SIGKILL")}catch{}else G().length>0&&e(":443 is still held by a process that is not this workspace's gateway \u2014 leaving it alone.");ke(3e3)}const E=H(c);return E!==void 0&&E!==y&&(ne(E,"SIGKILL"),b=!0),V(i),b&&ee(c,t.env,()=>{}),e(`gateway stopped (pid ${y})${b?" \u2014 forced (a child ignored SIGTERM)":""}.`),{exitCode:0}},"stop"),k=l(()=>{const{pid:y,healed:h}=se(i,c),b=y!==void 0&&te(y)?classifyAliveGateway({oursOn443:H(c)!==void 0,port443Held:G().length>0,pidFileAgeMs:ve(i)}):void 0,E=b==="serving"||b==="booting";if(a){const j=O("GET","/status"),A=j?.status===200&&j.json&&typeof j.json=="object"?j.json:null,z=x(g),Yt=E?"daemon":A&&z?"guest":A?"other":"stopped";return e(JSON.stringify({thisWorkspace:d.key,role:Yt,dashboardUrl:f,chooserUrl:"https://lensmcp.local/",logFile:u,daemonLogFile:(()=>{const fe=Se();return fe&&fe!==c?m(fe,".lensmcp","gateway.log"):u})(),mcp:je(c,t.env??process.env),daemon:A?.daemon??null,workspaces:A?.workspaces??[],services:A?.services??[]})),{exitCode:E||A&&z?0:1}}const S=O("GET","/list"),L=S?.status===200&&S.json&&typeof S.json=="object"?S.json.workspaces??[]:[],I=l(()=>{if(L.length!==0){e(` workspaces (${L.length} registered):`);for(const j of L)e(` \u2022 ${j.key} (${j.routes??0} routes, ${j.services??0} services)${j.key===d.key?" \u2190 this workspace":""}`)}},"printWorkspaces"),N=l(()=>{const j=je(c,t.env??process.env);e(j.mode==="shared"?` mcp \u2192 shared ${j.url} ${j.healthy?"(up)":`(DOWN \u2014 ${j.error??"no answer"})`}`:" mcp \u2192 stdio (one server per agent session)")},"printMcp"),F=l(()=>{const j=O("GET","/status"),A=j?.status===200&&j.json&&typeof j.json=="object"?j.json.daemon:void 0,z=re(c);A?.version&&z&&A.version!==z&&e(` version \u2192 the daemon runs ${A.version} but this workspace depends on ${z} \u2014 \`lensmcp upgrade\` reconciles everything (or restart the daemon workspace's gateway).`)},"printVersionSkew");if(E)return e(b==="booting"?`gateway: starting (pid ${y}) \u2014 :443 not bound yet`:`gateway: running (pid ${y}) \u2014 DAEMON on :443${h?" \u2014 recovered a stale pid file":""}`),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${f}`),e(" chooser \u2192 https://lensmcp.local/"),e(` logs \u2192 ${u}`),N(),F(),I(),{exitCode:0};if(x(g)&&S?.status===200){const j=G()[0];e(`gateway: registered into a shared daemon${j!==void 0?` (pid ${j})`:""} \u2014 this workspace is a guest`),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${f}`),e(` logs \u2192 ${u} (this workspace's pods)`);const A=Se();return A&&A!==c&&e(` ${m(A,".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)"),N(),F(),I(),{exitCode:0}}return b==="zombie"?(e(`gateway: NOT serving \u2014 tracked pid ${y} 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 ${u}`),N(),I(),{exitCode:1}):(e("gateway: stopped"),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${f}`),N(),{exitCode:1})},"status"),C=l(()=>{const y=O("GET","/status");if(y?.status!==200||!y.json||typeof y.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 h=y.json;if(a)return e(JSON.stringify(h)),{exitCode:0};e(`daemon: pid ${h.daemon?.pid??"?"} \xB7 owner ${h.daemon?.wsKey??"?"}${h.daemon?.version?` \xB7 lensmcp ${h.daemon.version}`:""}`);for(const b of h.workspaces??[]){e(` ${b.isDaemon?"\u2605":"\xB7"} ${b.key.padEnd(16)} ${String(b.routes??0).padStart(3)} routes ${String(b.services??0).padStart(3)} services ${b.root??""}`);for(const E of(h.services??[]).filter(S=>(S.wsKey??h.daemon?.wsKey)===b.key))e(` ${E.project.padEnd(16)} ${(E.state??"unknown").padEnd(9)} ${E.host??""}`)}return{exitCode:0}},"list");switch(r){case"start":return w();case"stop":return v();case"list":return C();case"restart":return v(),ee(c,t.env,e),w();case"status":return k();default:return s(`Unknown gateway subcommand: ${r} (use start | stop | status | restart | list)`),{exitCode:2}}}p(me,"_e"),l(me,"runGateway");function ee(t,n,e){const s=ae(t);if(!s){e(" (graph refresh skipped \u2014 no nx binary found in the workspace)");return}const o={...process.env,...n??{}},r=l(a=>T(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(ee,"te"),l(ee,"refreshNxGraph");function we(t,n,e,s){if(e&&s)return{project:e,target:s};const o=J(t,r=>r==="project.json");for(const r of o){let a;try{a=JSON.parse(D(r))}catch{continue}const c=a.name??de(_(r));for(const[d,i]of Object.entries(a.targets??{}))if(i.executor===n)return{project:e??c,target:s??d}}}p(we,"Ie"),l(we,"scanExecutorTarget");function ct(t,n,e){return we(t,"@lensmcp/cluster:gateway",n,e)||(n||e?{project:n??"gateway",target:e??"serve"}:void 0)}p(ct,"et"),l(ct,"findGatewayTarget");function dt(t,n,e){return we(t,"@lensmcp/cluster:trust",n,e)||(n?{project:n,target:e??"trust"}:lt(t,"gateway")?{project:"gateway",target:e??"trust"}:void 0)}p(dt,"nt"),l(dt,"findTrustTarget");function lt(t,n){for(const e of J(t,s=>s==="project.json"))try{if((JSON.parse(D(e)).name??de(_(e)))===n)return!0}catch{}return!1}p(lt,"tt"),l(lt,"projectExists");function ye(t){const n=hs(t);if(n)return fs(n.pid,n.stamp)?n.pid:void 0}p(ye,"De"),l(ye,"readPid");function te(t){try{return process.kill(t,0),!0}catch(n){return n.code==="EPERM"}}p(te,"se"),l(te,"isAlive");function G(){try{const t=T("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(G,"K"),l(G,"pidsOnPort443");function ut(t){try{return(T("ps",["-o","command=","-p",String(t)],{encoding:"utf8"}).stdout??"").trim()}catch{return""}}p(ut,"st"),l(ut,"processCmd");function H(t){const n=m(t,"node_modules","nx","dist","bin","run-executor.js"),e=m(t,"node_modules","@lensmcp","cluster");for(const s of G()){const o=ut(s);if(o.includes(n)||o.includes(e))return s}}p(H,"G"),l(H,"gatewayOnPort443");function ve(t){try{return Date.now()-Oe(t).mtimeMs}catch{return}}p(ve,"Fe"),l(ve,"pidFileAgeMs");const Bs=18e4;export function classifyAliveGateway(t){if(t.oursOn443)return"serving";const n=t.pidFileAgeMs!==void 0&&t.pidFileAgeMs<(t.bootGraceMs??Bs);return!t.port443Held&&n?"booting":"zombie"}p(classifyAliveGateway,"classifyAliveGateway"),l(classifyAliveGateway,"classifyAliveGateway");function se(t,n){const e=ye(t);if(e!==void 0&&te(e))return{pid:e,healed:!1};const s=H(n);if(s!==void 0){try{Ke(t,s)}catch{}return{pid:s,healed:!0}}return{healed:!1}}p(se,"re"),l(se,"reconcileGateway");function ne(t,n="SIGTERM"){try{process.kill(-t,n)}catch{try{process.kill(t,n)}catch{}}}p(ne,"oe"),l(ne,"killGatewayTree");function ke(t){const n=Date.now()+t;for(;;){if(G().length===0)return!0;if(Date.now()>=n)return!1;T("sleep",["0.15"])}}p(ke,"Ke"),l(ke,"waitForPortFree");function pt(t){const n=T("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(pt,"ot"),l(pt,"probeHostTrust");function gt(t){for(const n of J(t,e=>e==="project.json"))try{const e=JSON.parse(K(n,"utf8")),s=(e.cluster??e.davnx)?.host;if(s&&!s.includes("*"))return s}catch{}}p(gt,"it"),l(gt,"firstClusterHost");function V(t){try{ss(t,{force:!0})}catch{}}p(V,"B"),l(V,"rmFile");function ht(t,n,e,s){const o=R(n,{string:["--cwd","--host","--port"]}),r=M($(o.flags["--cwd"])??t.cwd),a=U(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=Gt(r);if(!i)return s(`Could not locate the lensmcp bridge bundle.
|
|
181
|
+
`).trim();d=i?JSON.parse(i):null}catch{}return Number.isFinite(c)?{status:c,json:d}:null}p(O,"O"),g(O,"R"),l(O,"daemonRequest");function Fe(){const t=O("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(Fe,"rt"),g(Fe,"Xn"),l(Fe,"daemonWsKey");function Ke(t){const n={};for(const e of J(t,s=>s==="project.json"))try{const s=JSON.parse(B(e,"utf8")),o=_(e);n[s.name??he(o)]={root:Lt(t,o)||"."}}catch{}return n}p(Ke,"at"),g(Ke,"Zn"),l(Ke,"buildProjectsMap");function Ge(t){const n=w(t,"node_modules",".bin",process.platform==="win32"?"nx.cmd":"nx");if(!S(n))return;const e=M(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(Ge,"it"),g(Ge,"Qn"),l(Ge,"buildProjectDependencies");function de(t,n){const e=Ge(t);return{wsKey:n,root:t,projects:Ke(t),...e?{projectDependencies:e}:{}}}p(de,"ue"),g(de,"pe"),l(de,"gatewayRegistrationBody");function me(t,n,e,s){const o=R(n,{string:["--cwd","--project","--target"]}),r=(o.positional[0]??"status").toLowerCase(),a=n.includes("--json"),c=L(b(o.flags["--cwd"])??t.cwd),d=q(c),i=w(c,".lensmcp","gateway.pid"),u=w(c,".lensmcp","gateway.log"),h=w(c,".lensmcp","registered.json"),m=`https://lensmcp.local${d.dashboardBasePath}/`,y=l(()=>{const{pid:v,healed:f}=se(i,c);if(v!==void 0&&te(v)){const P=classifyAliveGateway({oursOn443:G(c)!==void 0,port443Held:K().length>0,pidFileAgeMs:ve(i)});if(P==="serving")return f&&e(`healed: adopted a running gateway (pid ${v}) the pid file had lost \u2014 no duplicate started.`),e(`gateway already running (pid ${v}).`),e(` dashboard \u2192 ${m}`),{exitCode:0};if(P==="booting")return e(`gateway starting (pid ${v}) \u2014 :443 not bound yet.`),e(` dashboard \u2192 ${m}`),e(` logs \u2192 ${u}`),{exitCode:0};ne(v,"SIGKILL"),V(i),ee(c,t.env,()=>{}),e(`reaped a dead gateway (pid ${v} was alive but nothing served :443 for this workspace).`)}const C=K()[0];if(C!==void 0){const P=O("GET","/list");if(P!==null){if(P.status===200&&P.json&&typeof P.json=="object"&&(P.json.workspaces??[]).some(N=>N.key===d.key))return Z(_(h),{recursive:!0}),z(h,JSON.stringify({wsKey:d.key})),e(`already registered into the shared gateway daemon (pid ${C}).`),e(` dashboard \u2192 ${m}`),{exitCode:0};const H=O("POST","/register",de(c,d.key));return H&&H.status===200?(Z(_(h),{recursive:!0}),z(h,JSON.stringify({wsKey:d.key})),e(`registered '${d.key}' into the shared gateway daemon (pid ${C}).`),e(` dashboard \u2192 ${m}`),e(" the daemon hosts this workspace's services + dashboard; `lensmcp gateway stop` unregisters."),{exitCode:0}):(s(`failed to register into the gateway daemon: ${H?JSON.stringify(H.json):"no response from the control socket"}`),{exitCode:1})}return s(`port :443 is held by pid ${C}, which is not this workspace's gateway.
|
|
182
|
+
Free it first (stop that process), then \`lensmcp gateway start\`.`),{exitCode:1}}const T=He(c,b(o.flags["--project"]),b(o.flags["--target"]));if(!T)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 j=ae(c);if(!j)return s("Could not find the `nx` binary in the workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};Gt(c,u);const A=ss(u,"a"),F=ts(j,["run",`${T.project}:${T.target}`],{cwd:c,detached:!0,stdio:["ignore",A,A],env:{...process.env,...t.env??{}}});return F.unref(),F.pid&&_t(i,F.pid),e(`gateway starting \u2192 ${T.project}:${T.target} (pid ${F.pid??"?"})`),e(` dashboard \u2192 ${m}`),e(` logs \u2192 ${u}`),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"),k=l(()=>{if(S(h)&&G(c)===void 0){let j=d.key;try{j=JSON.parse(B(h,"utf8")).wsKey??d.key}catch{}const A=O("POST","/unregister",{wsKey:j});return V(h),e(A&&A.status===200?`unregistered '${j}' from the shared gateway daemon.`:"unregister sent (the daemon may already be gone)."),{exitCode:0}}V(h);const{pid:v,healed:f}=se(i,c);if(v===void 0)return e("gateway not running."),V(i),{exitCode:0};f&&e(`healed: found an orphaned gateway (pid ${v}) the pid file had lost \u2014 stopping it.`),ne(v);let C=!1;if(!ke(6e3)){C=!0,ne(v,"SIGKILL");const j=G(c);if(j!==void 0)try{process.kill(j,"SIGKILL")}catch{}else K().length>0&&e(":443 is still held by a process that is not this workspace's gateway \u2014 leaving it alone.");ke(3e3)}const T=G(c);return T!==void 0&&T!==v&&(ne(T,"SIGKILL"),C=!0),V(i),C&&ee(c,t.env,()=>{}),e(`gateway stopped (pid ${v})${C?" \u2014 forced (a child ignored SIGTERM)":""}.`),{exitCode:0}},"stop"),$=l(()=>{const{pid:v,healed:f}=se(i,c),C=v!==void 0&&te(v)?classifyAliveGateway({oursOn443:G(c)!==void 0,port443Held:K().length>0,pidFileAgeMs:ve(i)}):void 0,T=C==="serving"||C==="booting";if(a){const N=O("GET","/status"),I=N?.status===200&&N.json&&typeof N.json=="object"?N.json:null,X=S(h),Xt=T?"daemon":I&&X?"guest":I?"other":"stopped";return e(JSON.stringify({thisWorkspace:d.key,role:Xt,dashboardUrl:m,chooserUrl:"https://lensmcp.local/",logFile:u,daemonLogFile:(()=>{const Oe=Se();return Oe&&Oe!==c?w(Oe,".lensmcp","gateway.log"):u})(),mcp:je(c,t.env??process.env),daemon:I?.daemon??null,workspaces:I?.workspaces??[],services:I?.services??[]})),{exitCode:T||I&&X?0:1}}const j=O("GET","/list"),A=j?.status===200&&j.json&&typeof j.json=="object"?j.json.workspaces??[]:[],F=l(()=>{if(A.length!==0){e(` workspaces (${A.length} registered):`);for(const N of A)e(` \u2022 ${N.key} (${N.routes??0} routes, ${N.services??0} services)${N.key===d.key?" \u2190 this workspace":""}`)}},"printWorkspaces"),P=l(()=>{const N=je(c,t.env??process.env);e(N.mode==="shared"?` mcp \u2192 shared ${N.url} ${N.healthy?"(up)":`(DOWN \u2014 ${N.error??"no answer"})`}`:" mcp \u2192 stdio (one server per agent session)")},"printMcp"),H=l(()=>{const N=O("GET","/status"),I=N?.status===200&&N.json&&typeof N.json=="object"?N.json.daemon:void 0,X=re(c);I?.version&&X&&I.version!==X&&e(` version \u2192 the daemon runs ${I.version} but this workspace depends on ${X} \u2014 \`lensmcp upgrade\` reconciles everything (or restart the daemon workspace's gateway).`)},"printVersionSkew");if(T)return e(C==="booting"?`gateway: starting (pid ${v}) \u2014 :443 not bound yet`:`gateway: running (pid ${v}) \u2014 DAEMON on :443${f?" \u2014 recovered a stale pid file":""}`),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${m}`),e(" chooser \u2192 https://lensmcp.local/"),e(` logs \u2192 ${u}`),P(),H(),F(),{exitCode:0};if(S(h)&&j?.status===200){const N=K()[0];e(`gateway: registered into a shared daemon${N!==void 0?` (pid ${N})`:""} \u2014 this workspace is a guest`),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${m}`),e(` logs \u2192 ${u} (this workspace's pods)`);const I=Se();return I&&I!==c&&e(` ${w(I,".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)"),P(),H(),F(),{exitCode:0}}return C==="zombie"?(e(`gateway: NOT serving \u2014 tracked pid ${v} 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 ${u}`),P(),F(),{exitCode:1}):(e("gateway: stopped"),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${m}`),P(),{exitCode:1})},"status"),x=l(()=>{const v=O("GET","/status");if(v?.status!==200||!v.json||typeof v.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 f=v.json;if(a)return e(JSON.stringify(f)),{exitCode:0};e(`daemon: pid ${f.daemon?.pid??"?"} \xB7 owner ${f.daemon?.wsKey??"?"}${f.daemon?.version?` \xB7 lensmcp ${f.daemon.version}`:""}`);for(const C of f.workspaces??[]){e(` ${C.isDaemon?"\u2605":"\xB7"} ${C.key.padEnd(16)} ${String(C.routes??0).padStart(3)} routes ${String(C.services??0).padStart(3)} services ${C.root??""}`);for(const T of(f.services??[]).filter(j=>(j.wsKey??f.daemon?.wsKey)===C.key))e(` ${T.project.padEnd(16)} ${(T.state??"unknown").padEnd(9)} ${T.host??""}`)}return{exitCode:0}},"list");switch(r){case"start":return y();case"stop":return k();case"list":return x();case"restart":return k(),ee(c,t.env,e),y();case"status":return $();default:return s(`Unknown gateway subcommand: ${r} (use start | stop | status | restart | list)`),{exitCode:2}}}p(me,"me"),g(me,"_e"),l(me,"runGateway");function ee(t,n,e){const s=ae(t);if(!s){e(" (graph refresh skipped \u2014 no nx binary found in the workspace)");return}const o={...process.env,...n??{}},r=l(a=>M(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(ee,"ee"),g(ee,"te"),l(ee,"refreshNxGraph");function we(t,n,e,s){if(e&&s)return{project:e,target:s};const o=J(t,r=>r==="project.json");for(const r of o){let a;try{a=JSON.parse(D(r))}catch{continue}const c=a.name??he(_(r));for(const[d,i]of Object.entries(a.targets??{}))if(i.executor===n)return{project:e??c,target:s??d}}}p(we,"we"),g(we,"Ie"),l(we,"scanExecutorTarget");function He(t,n,e){return we(t,"@lensmcp/cluster:gateway",n,e)||(n||e?{project:n??"gateway",target:e??"serve"}:void 0)}p(He,"ct"),g(He,"et"),l(He,"findGatewayTarget");function Be(t,n,e){return we(t,"@lensmcp/cluster:trust",n,e)||(n?{project:n,target:e??"trust"}:Ve(t,"gateway")?{project:"gateway",target:e??"trust"}:void 0)}p(Be,"dt"),g(Be,"nt"),l(Be,"findTrustTarget");function Ve(t,n){for(const e of J(t,s=>s==="project.json"))try{if((JSON.parse(D(e)).name??he(_(e)))===n)return!0}catch{}return!1}p(Ve,"lt"),g(Ve,"tt"),l(Ve,"projectExists");function ye(t){const n=ms(t);if(n)return ws(n.pid,n.stamp)?n.pid:void 0}p(ye,"ye"),g(ye,"De"),l(ye,"readPid");function te(t){try{return process.kill(t,0),!0}catch(n){return n.code==="EPERM"}}p(te,"te"),g(te,"se"),l(te,"isAlive");function K(){try{const t=M("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(K,"G"),g(K,"K"),l(K,"pidsOnPort443");function Je(t){try{return(M("ps",["-o","command=","-p",String(t)],{encoding:"utf8"}).stdout??"").trim()}catch{return""}}p(Je,"ut"),g(Je,"st"),l(Je,"processCmd");function G(t){const n=w(t,"node_modules","nx","dist","bin","run-executor.js"),e=w(t,"node_modules","@lensmcp","cluster");for(const s of K()){const o=Je(s);if(o.includes(n)||o.includes(e))return s}}p(G,"H"),g(G,"G"),l(G,"gatewayOnPort443");function ve(t){try{return Date.now()-Tt(t).mtimeMs}catch{return}}p(ve,"ve"),g(ve,"Fe"),l(ve,"pidFileAgeMs");const Js=18e4;export function classifyAliveGateway(t){if(t.oursOn443)return"serving";const n=t.pidFileAgeMs!==void 0&&t.pidFileAgeMs<(t.bootGraceMs??Js);return!t.port443Held&&n?"booting":"zombie"}p(classifyAliveGateway,"classifyAliveGateway"),g(classifyAliveGateway,"classifyAliveGateway"),l(classifyAliveGateway,"classifyAliveGateway");function se(t,n){const e=ye(t);if(e!==void 0&&te(e))return{pid:e,healed:!1};const s=G(n);if(s!==void 0){try{_t(t,s)}catch{}return{pid:s,healed:!0}}return{healed:!1}}p(se,"se"),g(se,"re"),l(se,"reconcileGateway");function ne(t,n="SIGTERM"){try{process.kill(-t,n)}catch{try{process.kill(t,n)}catch{}}}p(ne,"ne"),g(ne,"oe"),l(ne,"killGatewayTree");function ke(t){const n=Date.now()+t;for(;;){if(K().length===0)return!0;if(Date.now()>=n)return!1;M("sleep",["0.15"])}}p(ke,"ke"),g(ke,"Ke"),l(ke,"waitForPortFree");function We(t){const n=M("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(We,"pt"),g(We,"ot"),l(We,"probeHostTrust");function Ue(t){for(const n of J(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(Ue,"gt"),g(Ue,"it"),l(Ue,"firstClusterHost");function V(t){try{os(t,{force:!0})}catch{}}p(V,"V"),g(V,"B"),l(V,"rmFile");function ze(t,n,e,s){const o=R(n,{string:["--cwd","--host","--port"]}),r=L(b(o.flags["--cwd"])??t.cwd),a=q(r),c=b(o.flags["--host"])??t.env?.LENSMCP_WS_HOST??process.env.LENSMCP_WS_HOST,d=b(o.flags["--port"])??t.env?.LENSMCP_WS_PORT??process.env.LENSMCP_WS_PORT??String(a.ports.bridge),i=$t(r);if(!i)return s(`Could not locate the lensmcp bridge bundle.
|
|
183
183
|
Looked in (in order):
|
|
184
184
|
\u2022 <cli-package>/bundled/bridge.js (published bin)
|
|
185
185
|
\u2022 <workspace>/libs/bridge/dist/main.js (dev build)
|
|
186
|
-
For dev: \`yarn nx build @lensmcp/bridge\`.`),{exitCode:1};ie(r);const u=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??
|
|
187
|
-
`)}catch{}}p(ft,"ct"),l(ft,"writeSetupState");async function mt(t,n,e,s){const o=Ge(n)?n:Q(t,e).mode,r=$s(t,o);if(s(""),s(`[mcp] mode \u2192 ${o}`),r.wrote&&s(` wrote ${vs}`),o==="embedded"){s(" every agent session builds its OWN MCP server, and keeps serving"),s(" the bundle it started with until that session exits."),s(" one shared server for the workspace: `lensmcp setup --mcp shared`");return}s(` sessions proxy into ONE shared server at ${r.url}`),s(" .mcp.json is unchanged \u2014 `lensmcp mcp` becomes a thin stdio shim.");const a=await Be(r.url);if(!a.ok){s(` \xB7 not up yet (${a.error??"unknown"}) \u2014 the next session starts it on demand`);return}const c=re(t)??q(),d=_e({identity:He(r.port),targetVersion:c,expectedRoot:Pe(t),expectedKey:U(t).key,selfPid:process.pid});if(!d.kill){s(` \u2713 already up \u2014 ${a.server??"MCP"} (protocol ${a.protocolVersion??"?"}) \u2014 ${d.reason}`);return}try{process.kill(d.pid,"SIGTERM"),s(` \u21BA restarted the shared server \u2014 it was ${d.reason}; the next session brings it up on ${c}`)}catch(i){s(` ! the shared server is ${d.reason} and could not be stopped (pid ${d.pid}): ${i.message}`)}}p(mt,"dt"),l(mt,"applyMcpModeStep");function wt(t,n,e){const s=Ye({cwd:t,cliVersion:q()}),o=Ms({run:Ts(n),facts:s});if(!(o.outcome==="current"||o.outcome==="unknown")){if(e(""),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(wt,"lt"),l(wt,"applyPluginSyncStep");async function yt(t,n,e,s){const o=R(n,{string:["--cwd","--mcp"],boolean:["--no-recycle"]}),r=M($(o.flags["--cwd"])??t.cwd),a={...t,cwd:r},c=$(o.flags["--mcp"]);if(c!==void 0&&!Ge(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=$e(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=be(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 u=U(r).key,g=us({previous:xe(r),current:Ce(r),disabled:o.flags["--no-recycle"]===!0}),f=g.recycle?Wt(r,u,e,g.reason):(e(` \xB7 pods left running \u2014 ${g.reason}`),{killed:0,stale:0});Ut(a,r,u,e),await mt(r,c,t.env??process.env,e);try{wt(r,{...process.env,...t.env??{}},e)}catch{}return ft(r,g.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(yt,"pt"),l(yt,"runSetup");async function vt(t,n,e){const s=R(n,{string:["--cwd","--hook","--timeout","--session"],boolean:["--json","--quiet"]}),o=M($(s.flags["--cwd"])??t.cwd),r=$(s.flags["--hook"]),a=We(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,u=Number($(s.flags["--timeout"])??""),g=Number.isFinite(u)&&u>0?u:Ns,f={...process.env,...t.env??{}};try{const w=await Ps({cwd:o,env:f,budgetMs:g,verify:l(C=>bs(C).map(y=>y.resource),"verify")});if(!w.available)return d&&!i?e(JSON.stringify({available:!1,workspace:w.source.workspace,mode:w.source.mode,reason:w.reason,elapsedMs:w.elapsedMs})):i||e(`lensmcp status \u2014 ${w.source.workspace}: unavailable (${w.reason})`),{exitCode:0};const v=js(w.status,w.evidence,Date.now()),k=Ss(v,{workspace:w.source.workspace,includeUnmonitored:a==="SessionStart"||!i});if(d)return i&&k===void 0?{exitCode:0}:(e(JSON.stringify({available:!0,workspace:w.source.workspace,mode:w.source.mode,url:w.source.url,aggregate:w.status.status??"unknown",elapsedMs:w.elapsedMs,findings:v.findings,suppressed:v.suppressed,unmonitored:v.unmonitored})),{exitCode:0});if(a){const C=xs(v.findings);return ws(c,C)?(k!==void 0&&e(Je(a,k)),c&&ms(c,C),{exitCode:0}):{exitCode:0}}if(i)return k!==void 0&&e(k),{exitCode:0};if(e(`lensmcp status \u2014 ${w.source.workspace} (${w.source.mode}, ${w.source.url})`),e(` aggregate says: ${w.status.status??"unknown"} (read in ${w.elapsedMs}ms)`),v.findings.length===0)e(" nothing actionable that this command can vouch for.");else for(const C of v.findings)e(` \u2022 ${Cs(C)}`);for(const C of v.suppressed)e(` \xB7 not reported \u2014 ${C.kind}: ${C.reason}`);return v.unmonitored.length>0&&e(` \xB7 unmonitored (unknown, NOT clean): ${v.unmonitored.join(", ")}`),{exitCode:0}}catch(w){return i||e(`lensmcp status: unavailable (${w instanceof Error?w.message:String(w)})`),{exitCode:0}}}p(vt,"ut"),l(vt,"runStatus");function kt(t,n,e){const s=R(n,{string:["--cwd","--hook","--plugin-root"],boolean:["--json","--quiet"]}),o=M($(s.flags["--cwd"])??t.cwd),r=$(s.flags["--hook"]),a=We(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 u=Ye({cwd:o,cliVersion:q(),...i?{pluginRoot:i}:{}}),g=Es(u);if(c)return d&&!g?{exitCode:0}:(e(JSON.stringify({...u,skew:g??null})),{exitCode:0});if(a)return g&&e(Je(a,Ue(g))),{exitCode:0};if(d)return g&&e(Ue(g)),{exitCode:0};if(e(`lensmcp version-check \u2014 ${u.pluginId??"lensmcp plugin"}`),e(` plugin ${u.plugin??"unknown"}${u.pluginSource?` (${u.pluginSource})`:""}`),e(` project ${u.project??"unknown"} (node_modules/lensmcp)`),e(` cli ${u.cli??"unknown"} (the binary running now)`),!g)return e(u.plugin&&(u.project??u.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 f of Ls(g))e(` ${f}`);return{exitCode:0}}catch(u){return d||e(`lensmcp version-check: unavailable (${u instanceof Error?u.message:String(u)})`),{exitCode:0}}}p(kt,"ft"),l(kt,"runVersionCheck");async function $t(t,n,e){const s=R(n,{string:["--cwd"],boolean:["--json"]}),o=M($(s.flags["--cwd"])??t.cwd),r=s.flags["--json"]===!0,a=[];bt(a),Ct(o,a),xt(o,a),St(o,t.env??process.env,a),await jt(o,t.env??process.env,a),Nt(o,a),Pt(o,a),Et(o,a),Tt(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 u=i.status==="pass"?"\u2713":i.status==="warn"?"!":"\u2717";e(`${u} ${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($t,"gt"),l($t,"runDoctor");function P(t,n,e,s,o){t.push({status:n,label:e,detail:s,hint:o})}p(P,"P"),l(P,"add");function bt(t){const n=Number(process.versions.node.split(".")[0]);n>=20?P(t,"pass",`Node ${process.versions.node}`):n>=18?P(t,"warn",`Node ${process.versions.node}`,"older than recommended","upgrade to Node 20+ for best results"):P(t,"fail",`Node ${process.versions.node}`,"too old","LensMCP needs Node 18+ (20+ recommended)")}p(bt,"ht"),l(bt,"checkNode");function Ct(t,n){const e=m(t,"nx.json");if(!x(e)){P(n,"fail","nx.json at workspace root","missing","run `lensmcp` from inside a Nx workspace");return}let s;try{s=JSON.parse(K(e,"utf8"))}catch(r){P(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");P(n,o?"pass":"fail","@lensmcp/nx-plugin registered in nx.json#plugins",o?void 0:"not registered",o?void 0:"run `lensmcp install`"),P(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(Ct,"mt"),l(Ct,"checkWorkspace");function xt(t,n){const e=m(t,".mcp.json");if(!x(e)){P(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(K(e,"utf8")),o=!!s.mcpServers&&!!s.mcpServers.lensmcp;P(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){P(n,"warn",".mcp.json parses",s.message,"fix the JSON syntax in .mcp.json")}}p(xt,"wt"),l(xt,"checkMcpConfig");function St(t,n,e){const s=Z(m(t,".claude","settings.json")),o=Z(m(t,".claude","settings.local.json")),r=Ze({cwd:t}),a=r?Z(m(r.root,"plugin",".mcp.json")):void 0,c=De(a),d=ze(),i=Fe(s,X)||Fe(o,X)||d.some(g=>g.scope==="user"||g.projectPath===t),u=gs({workspaceServers:De(Z(m(t,".mcp.json"))),pluginServers:c,pluginEnabled:i,pluginReadable:a!==void 0,disabledServers:[...Ie(s),...Ie(o)],sharedMcp:Q(t,n).mode==="shared"});P(e,u.duplicated||u.indeterminate?"warn":"pass","the MCP server is registered exactly once",u.duplicated||u.indeterminate?u.detail:void 0,u.duplicated||u.indeterminate?u.hint:void 0)}p(St,"yt"),l(St,"checkDuplicateRegistration");function Se(){const t=O("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(Se,"Ve"),l(Se,"daemonOwnerRoot");function Z(t){try{return JSON.parse(K(t,"utf8"))}catch{return}}p(Z,"Z"),l(Z,"readJsonFile");async function jt(t,n,e){const s=Q(t,n);if(P(e,"pass","MCP mode",s.mode==="shared"?`shared \u2014 sessions proxy into ${s.url}`:"embedded \u2014 one MCP server per agent session",s.mode==="shared"?void 0:"one shared server: `lensmcp setup --mcp shared`"),s.mode!=="shared")return;const o=await Be(s.url);P(e,o.ok?"pass":"warn","shared MCP server",o.ok?`${o.server??"MCP"} @ ${s.url} (protocol ${o.protocolVersion??"?"})`:`not running at ${s.url} \u2014 ${o.error??"no answer"}`,o.ok?void 0:"the next agent session starts it on demand; `lensmcp gateway start` starts it now")}p(jt,"vt"),l(jt,"checkMcpMode");function je(t,n){const e=Q(t,n);if(e.mode!=="shared")return{mode:e.mode,url:e.url,port:e.port,healthy:!1};const s=ks(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}:{}}}p(je,"We"),l(je,"mcpStatusBlock");function Nt(t,n){const e=pe(t);P(n,e?"pass":"fail","lensmcp-mcp server bundle reachable",e??"missing",e?void 0:"dev: `yarn nx build @lensmcp/lensmcp-mcp`")}p(Nt,"kt"),l(Nt,"checkServerBundle");function Pt(t,n){const e=m(t,".lensmcp");P(n,x(e)?"pass":"warn",".lensmcp/ runtime directory",x(e)?void 0:"not created yet",x(e)?void 0:"created automatically on first `lensmcp mcp` run");const s=m(t,".gitignore"),o=(x(s)?D(s):"").split(`
|
|
188
|
-
`).some(r=>r.trim()===".lensmcp/"||r.trim()===".lensmcp");
|
|
189
|
-
${
|
|
190
|
-
`).filter(Boolean).pop():void 0;if(!o||!/^\d+\.\d+\.\d+/.test(o)){e("Could not resolve the latest lensmcp version from the npm registry \u2014 pass one explicitly: `lensmcp upgrade 1.20.1`.");return}return o}p(Ot,"xt"),l(
|
|
186
|
+
For dev: \`yarn nx build @lensmcp/bridge\`.`),{exitCode:1};ie(r);const u=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(r,".lensmcp","events.jsonl"),h={...process.env,...t.env??{},LENSMCP_EVENT_FILE:u};return c&&(h.LENSMCP_WS_HOST=c),d&&(h.LENSMCP_WS_PORT=d),e(`lensmcp bridge \u2192 ws://${c??"127.0.0.1"}:${d??"5747"} (forwarding to ${u})`),{exitCode:M(process.execPath,[i],{cwd:r,stdio:"inherit",env:h}).status??1}}p(ze,"ht"),g(ze,"at"),l(ze,"runBridge");function $e(t,n,e,s){const o=R(n,{string:["--cwd","--register-host-config"],boolean:["--skip-format","--yes"]}),r=L(b(o.flags["--cwd"])??t.cwd);if(!S(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=ae(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:M(a,c,{cwd:r,stdio:"inherit",env:{...process.env,...t.env??{}}}).status??1}}p($e,"$e"),g($e,"Ge"),l($e,"runInstall");function be(t,n,e,s){const o=R(n,{string:["--cwd","--project","--target"]}),r=L(b(o.flags["--cwd"])??t.cwd);if(!S(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=ae(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=Be(r,b(o.flags["--project"]),b(o.flags["--target"])),d=O("GET","/list")?.status===200&&G(r)===void 0;if(!c){if(s("This workspace has no trust target \u2014 no project declares the `@lensmcp/cluster:trust` executor."),s(""),d){const u=Fe();s(` A shared gateway daemon${u?` (owned by '${u}')`:""} 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}}bt()||e(" note: trust runs `sudo` for the CA + /etc/hosts \u2014 run it in a real terminal if a step is needed."),d&&(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 ${d?"/etc/hosts":"the CA + /etc/hosts"})`);const i=M(a,["run",`${c.project}:${c.target}`],{cwd:r,stdio:"inherit",env:{...process.env,...t.env??{},...d?{LENSMCP_TRUST_HOSTS_ONLY:"1"}:{}}});if(d&&i.status===0){const u=Ue(r);if(u){const h=We(u);e(""),e(h==="trusted"?` \u2713 ${u} \u2192 served by the daemon with a TRUSTED cert \u2014 you're set (restart the browser once if it cached an error).`:h==="untrusted"?` \u2717 ${u} \u2192 the daemon's cert is NOT trusted yet. Run \`lensmcp trust\` in the DAEMON workspace (it owns the CA), then restart your browser.`:` ? ${u} \u2192 couldn't reach it to verify (is the daemon running?). /etc/hosts is set; TLS rides the daemon's CA.`)}}return{exitCode:i.status??1}}p(be,"be"),g(be,"He"),l(be,"runTrust");function Ce(t){const n=re(t)??U(),e=hs(D(w(t,".lensmcp","config.json")));return{version:n,...e?{configHash:e}:{}}}p(Ce,"Ce"),g(Ce,"Je"),l(Ce,"currentRecycleStamp");function xe(t){const n=Y(w(t,".lensmcp","setup-state.json"))?.recycled;return n&&typeof n=="object"?n:void 0}p(xe,"xe"),g(xe,"Be"),l(xe,"readRecycleStamp");function qe(t,n){ie(t);const e={version:U(),completedAt:new Date().toISOString(),steps:{install:!0,trust:!0},recycled:n?Ce(t):xe(t)??{}};try{z(w(t,".lensmcp","setup-state.json"),`${JSON.stringify(e,null,2)}
|
|
187
|
+
`)}catch{}}p(qe,"ft"),g(qe,"ct"),l(qe,"writeSetupState");async function Ye(t,n,e,s){const o=Dt(n)?n:ce(t,e).mode,r=Cs(t,o);if(s(""),s(`[mcp] mode \u2192 ${o}`),r.wrote&&s(` wrote ${$s}`),o==="embedded"){s(" every agent session builds its OWN MCP server, and keeps serving"),s(" the bundle it started with until that session exits."),s(" one shared server for the workspace: `lensmcp setup --mcp shared`");return}s(` sessions proxy into ONE shared server at ${r.url}`),s(" .mcp.json is unchanged \u2014 `lensmcp mcp` becomes a thin stdio shim.");const a=await Kt(r.url);if(!a.ok){s(` \xB7 not up yet (${a.error??"unknown"}) \u2014 the next session starts it on demand`);return}const c=re(t)??U(),d=Ot({identity:Ft(r.port),targetVersion:c,expectedRoot:Pe(t),expectedKey:q(t).key,selfPid:process.pid});if(!d.kill){s(` \u2713 already up \u2014 ${a.server??"MCP"} (protocol ${a.protocolVersion??"?"}) \u2014 ${d.reason}`);return}try{process.kill(d.pid,"SIGTERM"),s(` \u21BA restarted the shared server \u2014 it was ${d.reason}; the next session brings it up on ${c}`)}catch(i){s(` ! the shared server is ${d.reason} and could not be stopped (pid ${d.pid}): ${i.message}`)}}p(Ye,"mt"),g(Ye,"dt"),l(Ye,"applyMcpModeStep");function Xe(t,n,e){const s=Ut({cwd:t,cliVersion:U()}),o=Os({run:Ls(n),facts:s});if(!(o.outcome==="current"||o.outcome==="unknown")){if(e(""),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(Xe,"wt"),g(Xe,"lt"),l(Xe,"applyPluginSyncStep");async function Ze(t,n,e,s){const o=R(n,{string:["--cwd","--mcp"],boolean:["--no-recycle"]}),r=L(b(o.flags["--cwd"])??t.cwd),a={...t,cwd:r},c=b(o.flags["--mcp"]);if(c!==void 0&&!Dt(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=$e(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=be(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 u=q(r).key,h=gs({previous:xe(r),current:Ce(r),disabled:o.flags["--no-recycle"]===!0}),m=h.recycle?jt(r,u,e,h.reason):(e(` \xB7 pods left running \u2014 ${h.reason}`),{killed:0,stale:0});Nt(a,r,u,e),await Ye(r,c,t.env??process.env,e);try{Xe(r,{...process.env,...t.env??{}},e)}catch{}return qe(r,h.recycle),e(""),e("\u2713 setup complete."),(m.killed>0||m.stale>0)&&e(` recycled ${m.killed} pod${m.killed===1?"":"s"}`+(m.stale>0?` (+${m.stale} stale socket${m.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(Ze,"yt"),g(Ze,"pt"),l(Ze,"runSetup");async function Qe(t,n,e){const s=R(n,{string:["--cwd","--hook","--timeout","--session"],boolean:["--json","--quiet"]}),o=L(b(s.flags["--cwd"])??t.cwd),r=b(s.flags["--hook"]),a=Bt(r)?r:void 0,c=b(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,u=Number(b(s.flags["--timeout"])??""),h=Number.isFinite(u)&&u>0?u:Es,m={...process.env,...t.env??{}};try{const y=await Ts({cwd:o,env:m,budgetMs:h,verify:l(x=>xs(x).map(v=>v.resource),"verify")});if(!y.available)return d&&!i?e(JSON.stringify({available:!1,workspace:y.source.workspace,mode:y.source.mode,reason:y.reason,elapsedMs:y.elapsedMs})):i||e(`lensmcp status \u2014 ${y.source.workspace}: unavailable (${y.reason})`),{exitCode:0};const k=Ps(y.status,y.evidence,Date.now()),$=Ns(k,{workspace:y.source.workspace,includeUnmonitored:a==="SessionStart"||!i});if(d)return i&&$===void 0?{exitCode:0}:(e(JSON.stringify({available:!0,workspace:y.source.workspace,mode:y.source.mode,url:y.source.url,aggregate:y.status.status??"unknown",elapsedMs:y.elapsedMs,findings:k.findings,suppressed:k.suppressed,unmonitored:k.unmonitored})),{exitCode:0});if(a){const x=js(k.findings);return vs(c,x)?($!==void 0&&e(Ht(a,$)),c&&ys(c,x),{exitCode:0}):{exitCode:0}}if(i)return $!==void 0&&e($),{exitCode:0};if(e(`lensmcp status \u2014 ${y.source.workspace} (${y.source.mode}, ${y.source.url})`),e(` aggregate says: ${y.status.status??"unknown"} (read in ${y.elapsedMs}ms)`),k.findings.length===0)e(" nothing actionable that this command can vouch for.");else for(const x of k.findings)e(` \u2022 ${Ss(x)}`);for(const x of k.suppressed)e(` \xB7 not reported \u2014 ${x.kind}: ${x.reason}`);return k.unmonitored.length>0&&e(` \xB7 unmonitored (unknown, NOT clean): ${k.unmonitored.join(", ")}`),{exitCode:0}}catch(y){return i||e(`lensmcp status: unavailable (${y instanceof Error?y.message:String(y)})`),{exitCode:0}}}p(Qe,"vt"),g(Qe,"ut"),l(Qe,"runStatus");function et(t,n,e){const s=R(n,{string:["--cwd","--hook","--plugin-root"],boolean:["--json","--quiet"]}),o=L(b(s.flags["--cwd"])??t.cwd),r=b(s.flags["--hook"]),a=Bt(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=b(s.flags["--plugin-root"]);try{const u=Ut({cwd:o,cliVersion:U(),...i?{pluginRoot:i}:{}}),h=Ms(u);if(c)return d&&!h?{exitCode:0}:(e(JSON.stringify({...u,skew:h??null})),{exitCode:0});if(a)return h&&e(Ht(a,Vt(h))),{exitCode:0};if(d)return h&&e(Vt(h)),{exitCode:0};if(e(`lensmcp version-check \u2014 ${u.pluginId??"lensmcp plugin"}`),e(` plugin ${u.plugin??"unknown"}${u.pluginSource?` (${u.pluginSource})`:""}`),e(` project ${u.project??"unknown"} (node_modules/lensmcp)`),e(` cli ${u.cli??"unknown"} (the binary running now)`),!h)return e(u.plugin&&(u.project??u.cli)?" \u2713 in step.":" ? cannot compare \u2014 one of the versions is unreadable (staying silent)."),{exitCode:0};e(` \u2717 the plugin is ${h.direction} \u2014 update it, then restart Claude Code:`);for(const m of Rs(h))e(` ${m}`);return{exitCode:0}}catch(u){return d||e(`lensmcp version-check: unavailable (${u instanceof Error?u.message:String(u)})`),{exitCode:0}}}p(et,"kt"),g(et,"ft"),l(et,"runVersionCheck");async function tt(t,n,e){const s=R(n,{string:["--cwd"],boolean:["--json"]}),o=L(b(s.flags["--cwd"])??t.cwd),r=s.flags["--json"]===!0,a=[];st(a),nt(o,a),ot(o,a),rt(o,t.env??process.env,a),await at(o,t.env??process.env,a),it(o,a),ct(o,a),dt(o,a),lt(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 u=i.status==="pass"?"\u2713":i.status==="warn"?"!":"\u2717";e(`${u} ${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(tt,"$t"),g(tt,"gt"),l(tt,"runDoctor");function E(t,n,e,s,o){t.push({status:n,label:e,detail:s,hint:o})}p(E,"P"),g(E,"P"),l(E,"add");function st(t){const n=Number(process.versions.node.split(".")[0]);n>=20?E(t,"pass",`Node ${process.versions.node}`):n>=18?E(t,"warn",`Node ${process.versions.node}`,"older than recommended","upgrade to Node 20+ for best results"):E(t,"fail",`Node ${process.versions.node}`,"too old","LensMCP needs Node 18+ (20+ recommended)")}p(st,"bt"),g(st,"ht"),l(st,"checkNode");function nt(t,n){const e=w(t,"nx.json");if(!S(e)){E(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){E(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");E(n,o?"pass":"fail","@lensmcp/nx-plugin registered in nx.json#plugins",o?void 0:"not registered",o?void 0:"run `lensmcp install`"),E(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(nt,"Ct"),g(nt,"mt"),l(nt,"checkWorkspace");function ot(t,n){const e=w(t,".mcp.json");if(!S(e)){E(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;E(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){E(n,"warn",".mcp.json parses",s.message,"fix the JSON syntax in .mcp.json")}}p(ot,"xt"),g(ot,"wt"),l(ot,"checkMcpConfig");function rt(t,n,e){const s=Y(w(t,".claude","settings.json")),o=Y(w(t,".claude","settings.local.json")),r=qt({cwd:t}),a=r?Y(w(r.root,"plugin",".mcp.json")):void 0,c=At(a),d=Wt(),i=It(s,Q)||It(o,Q)||d.some(h=>h.scope==="user"||h.projectPath===t),u=fs({workspaceServers:At(Y(w(t,".mcp.json"))),pluginServers:c,pluginEnabled:i,pluginReadable:a!==void 0,disabledServers:[...Rt(s),...Rt(o)],sharedMcp:ce(t,n).mode==="shared"});E(e,u.duplicated||u.indeterminate?"warn":"pass","the MCP server is registered exactly once",u.duplicated||u.indeterminate?u.detail:void 0,u.duplicated||u.indeterminate?u.hint:void 0)}p(rt,"St"),g(rt,"yt"),l(rt,"checkDuplicateRegistration");function Se(){const t=O("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(Se,"Se"),g(Se,"Ve"),l(Se,"daemonOwnerRoot");function Y(t){try{return JSON.parse(B(t,"utf8"))}catch{return}}p(Y,"Z"),g(Y,"Z"),l(Y,"readJsonFile");async function at(t,n,e){const s=ce(t,n);if(E(e,"pass","MCP mode",s.mode==="shared"?`shared \u2014 sessions proxy into ${s.url}`:"embedded \u2014 one MCP server per agent session",s.mode==="shared"?void 0:"one shared server: `lensmcp setup --mcp shared`"),s.mode!=="shared")return;const o=await Kt(s.url);E(e,o.ok?"pass":"warn","shared MCP server",o.ok?`${o.server??"MCP"} @ ${s.url} (protocol ${o.protocolVersion??"?"})`:`not running at ${s.url} \u2014 ${o.error??"no answer"}`,o.ok?void 0:"the next agent session starts it on demand; `lensmcp gateway start` starts it now")}p(at,"jt"),g(at,"vt"),l(at,"checkMcpMode");function je(t,n){const e=ce(t,n);if(e.mode!=="shared")return{mode:e.mode,url:e.url,port:e.port,healthy:!1};const s=bs(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}:{}}}p(je,"je"),g(je,"We"),l(je,"mcpStatusBlock");function it(t,n){const e=le(t);E(n,e?"pass":"fail","lensmcp-mcp server bundle reachable",e??"missing",e?void 0:"dev: `yarn nx build @lensmcp/lensmcp-mcp`")}p(it,"Nt"),g(it,"kt"),l(it,"checkServerBundle");function ct(t,n){const e=w(t,".lensmcp");E(n,S(e)?"pass":"warn",".lensmcp/ runtime directory",S(e)?void 0:"not created yet",S(e)?void 0:"created automatically on first `lensmcp mcp` run");const s=w(t,".gitignore"),o=(S(s)?D(s):"").split(`
|
|
188
|
+
`).some(r=>r.trim()===".lensmcp/"||r.trim()===".lensmcp");E(n,o?"pass":"warn",".gitignore excludes .lensmcp/",o?void 0:"not ignored",o?void 0:"add `.lensmcp/` to .gitignore (lensmcp install does this)")}p(ct,"Pt"),g(ct,"$t"),l(ct,"checkRuntimeDir");function dt(t,n){const e=J(t,d=>/^vite\.config\.[cm]?[jt]s$/.test(d)),s=e.filter(d=>/lensmcpVitePlugin|@lensmcp\/vite-plugin/.test(D(d)));if(e.length>0){const d=s.length===e.length;E(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=J(t,d=>d==="main.ts").filter(d=>/NestFactory\.create|createLensmcpNestApp/.test(D(d))),r=o.filter(d=>/createLensmcpNestApp/.test(D(d)));if(o.length>0){const d=r.length===o.length;E(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=J(t,d=>d==="project.json"||d==="package.json").map(d=>D(d)),c=a.filter(d=>/"agent-dev"/.test(d));a.some(d=>/@lensmcp\/cluster:gateway/.test(d))?E(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):E(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(dt,"Et"),g(dt,"bt"),l(dt,"checkProjectWiring");function lt(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&&S(n)?n:void 0)??e.find(o=>S(o));E(t,s?"pass":"warn","Chrome for browser:// capture",s?he(s):"not found",s?void 0:"install Chrome or set CHROME_PATH (only needed for browser capture)")}p(lt,"Tt"),g(lt,"Ct"),l(lt,"checkChrome");function D(t){try{return B(t,"utf8")}catch{return""}}p(D,"D"),g(D,"I"),l(D,"safeRead");function J(t,n,e=6,s=6e3){const o=new Set(["node_modules","dist","build",".git",".nx",".lensmcp","coverage","tmp",".cache",".yarn"]),r=[],a=[{dir:t,depth:0}];let c=0;for(;a.length>0;){const{dir:d,depth:i}=a.pop();let u;try{u=ge(d,{withFileTypes:!0})}catch{continue}for(const h of u){if(c++>s)return r;if(h.isDirectory()){if(o.has(h.name)||h.name.startsWith("."))continue;i<e&&a.push({dir:w(d,h.name),depth:i+1})}else h.isFile()&&n(h.name)&&r.push(w(d,h.name))}}return r}p(J,"J"),g(J,"V"),l(J,"walkProjectFiles");function ut(t,n,e,s){const o=R(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=L(b(o.flags["--cwd"])??t.cwd),c=o.positional[1]?.toLowerCase(),d=c?As(c):void 0;if(c&&!d)return s(`Unknown agent: ${c} (use claude | codex)`),{exitCode:2};const i=d?[d]:[...zt],u=b(o.flags["--from"]),h=qt({cwd:a,...u?{from:u}:{},selfRoot:oe()});if(!h)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: ${h.root}${h.version?` (lensmcp ${h.version})`:""}`+(h.source==="self"?" \u2014 the running CLI itself (no workspace install found; prefer a workspace)":""));const m=Yt({...process.env,...t.env??{}});if(r==="status"){for(const $ of i){const x=Fs(h.root,$),v=$.id==="claude"?Jt(a)?.version:Is(m),f=v?x?v===x?`installed ${v} \u2014 current`:`installed ${v}, the package ships ${x} \u2014 \`lensmcp plugin install ${$.id}\``:`installed ${v} (this package ships no ${$.label} plugin \u2014 it arrived in ${$.since})`:`not installed \u2014 \`lensmcp plugin install ${$.id}\``;e(` ${$.label.padEnd(11)} \u2192 ${f}`)}return{exitCode:0}}const y=b(o.flags["--scope"]);let k=!1;for(const $ of i){const x=$.id==="claude"?y??Jt(a)?.scope:void 0,v=_s($,{root:h.root,...x?{scope:x}:{}},{run:m});switch(v.outcome){case"installed":e(` ${$.label.padEnd(11)} \u2192 installed${v.version?` ${v.version}`:""} \u2014 ${v.restartHint}`);break;case"skipped-no-cli":d&&(k=!0),e(` ${$.label.padEnd(11)} \u2192 skipped (${v.detail})`);break;case"skipped-not-packaged":d&&(k=!0),e(` ${$.label.padEnd(11)} \u2192 skipped \u2014 ${v.detail}`);break;case"failed":k=!0,s(` ${$.label.padEnd(11)} \u2192 FAILED \u2014 ${v.detail}`),s(` run by hand:${v.commands.map(f=>`
|
|
189
|
+
${f}`).join("")}`);break}}return{exitCode:k?1:0}}p(ut,"Mt"),g(ut,"St"),l(ut,"runPlugin");function Ne(){const t=O("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(Ne,"Ne"),g(Ne,"Ue"),l(Ne,"snapshotDaemon");function pt(t){let n=L(t);for(let e=0;e<8;e++){const s=w(n,"package.json");if(S(s)&&/"(?:lensmcp|@lensmcp\/[^"]+)"\s*:/.test(D(s)))return{key:ds(n).key,root:n};const o=_(n);if(o===n)break;n=o}}p(pt,"Lt"),g(pt,"jt"),l(pt,"findLensmcpWorkspace");function gt(t,n,e){if(t){const r=t.replace(/^v/,"");if(!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(r)){e(`Not a version: ${t} (expected e.g. 1.20.1)`);return}return r}const s=n("npm",["view","lensmcp","version"]),o=s&&s.code===0?(s.stdout??"").trim().split(`
|
|
190
|
+
`).filter(Boolean).pop():void 0;if(!o||!/^\d+\.\d+\.\d+/.test(o)){e("Could not resolve the latest lensmcp version from the npm registry \u2014 pass one explicitly: `lensmcp upgrade 1.20.1`.");return}return o}p(gt,"Ot"),g(gt,"xt"),l(gt,"resolveTargetVersion");function ht(t,n,e,s){for(const o of t){let r;try{r=ce(o.root,process.env)}catch{continue}if(r.mode!=="shared")continue;const a=Ot({identity:Ft(r.port),targetVersion:n,expectedRoot:Pe(o.root),expectedKey:o.key,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(ht,"Rt"),g(ht,"Nt"),l(ht,"restartSharedMcpServers");function Pe(t){try{return ns(t)}catch{return t}}p(Pe,"Pe"),g(Pe,"qe"),l(Pe,"canonicalRootPath");async function ft(t,n,e,s){const o=R(n,{string:["--cwd"],boolean:["--dry-run","--no-install","--no-plugins","--no-global","--no-restart"]}),r=L(b(o.flags["--cwd"])??t.cwd),a=o.flags["--dry-run"]===!0,c={...process.env,...t.env??{}},d=Yt(c),i=gt(o.positional[0],d,s);if(!i)return{exitCode:1};const u=Bs(),h=pt(r),m=[],y=new Set;for(const f of[...h?[h]:[],...u])y.has(f.root)||(y.add(f.root),m.push(f));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 k=Ne();e(`upgrade \u2192 lensmcp ${i}${a?" (dry run \u2014 nothing will be changed)":""}`),k.wsKey&&e(` daemon \u2192 '${k.wsKey}' on :443${k.version?`, running ${k.version}`:""}, hosting ${k.registeredKeys.length} workspace${k.registeredKeys.length===1?"":"s"}`),e(` will change \u2192 ${m.length} workspace${m.length===1?"":"s"} (${m.map(f=>f.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"}`);const $=[];let x=0;for(const f of m){const C=w(f.root,"package.json"),T=D(C);if(!T){x++,s(` ${f.key}: cannot read ${C} \u2014 skipped`);continue}const j=Vs(T,i);for(const P of j.skipped.filter(H=>H.reason==="non-version-spec"))e(` ${f.key}: left ${P.section}.${P.name} at '${P.spec}' (not a plain version \u2014 a link:/workspace: pin is deliberate)`);if(j.changes.length===0){const P=re(f.root);e(` ${f.key}: package.json already at ${i}${P&&P!==i?` \u2014 but node_modules holds ${P}; run its install`:""}`);continue}if(e(` ${f.key}: ${j.changes.length} dep${j.changes.length===1?"":"s"} \u2192 ${i} (${j.changes.map(P=>P.name).join(", ")})`),a){$.push(f);continue}if(z(C,j.text),o.flags["--no-install"]===!0){$.push(f),e(" install skipped (--no-install) \u2014 run it before restarting anything.");continue}const A=Gs(f.root);e(` ${A.name} ${A.install.join(" ")} (${f.root})`);const F=M(A.name,A.install,{cwd:f.root,stdio:"inherit",env:c});if((F.status??1)!==0){x++,s(` ${f.key}: \`${A.name} ${A.install.join(" ")}\` exited ${F.status??"by signal"} \u2014 fix it and re-run \`lensmcp upgrade ${i}\` (the rewrite is already in place).`);continue}$.push(f)}if(o.flags["--no-global"]!==!0){const f=Ks(d);f&&f.version!==i?a?e(` global \u2192 ${f.version} \u2192 ${i} (npm i -g lensmcp@${i})`):(e(` global \u2192 ${f.version} \u2192 ${i}`),(M("npm",["install","-g",`lensmcp@${i}`],{stdio:"inherit",env:c,timeout:3e5}).status??1)!==0&&(x++,s(` the global install failed \u2014 run by hand: npm i -g lensmcp@${i}`))):f&&e(` global \u2192 already ${f.version}`)}if(o.flags["--no-plugins"]!==!0){const f=[k.wsKey?m.find(C=>C.key===k.wsKey):void 0,...$,...m].find(C=>!!C&&S(w(C.root,"node_modules","lensmcp","package.json")));f?a?e(` plugins \u2192 would re-install Claude Code + Codex from ${w(f.root,"node_modules","lensmcp")}`):wt(w(f.root,"node_modules","lensmcp"),r,c,e,s):e(" plugins \u2192 skipped (no workspace has lensmcp installed to point the marketplaces at)")}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."),{exitCode:x>0?1:0};const v=Hs({...k.wsKey?{daemonWsKey:k.wsKey}:{},...k.version?{daemonVersion:k.version}:{},targetVersion:i,registeredKeys:k.registeredKeys,known:u,upgraded:$});if(o.flags["--no-install"]!==!0&&ht(m,i,a,e),v.steps.length===0)return e(` restart \u2192 nothing to do${v.note?` (${v.note})`:""}`),{exitCode:x>0?1:0};for(const f of v.steps){if(a){e(` restart \u2192 would ${f.action==="restart"?`restart the daemon ('${f.key}')`:`re-register '${f.key}'`}${f.reason==="rehost"?" (not upgraded \u2014 re-hosted so the daemon restart does not drop it)":f.reason==="stale-daemon"?" (its files are current but the process still runs the old bundle)":""}`);continue}if(f.action==="restart"){if(e(` restart \u2192 gateway daemon ('${f.key}') \u2026`),me({...t,cwd:f.root},["restart"],e,s).exitCode!==0){x++,s(` the daemon restart ('${f.key}') failed \u2014 fix it, then \`lensmcp gateway start\` in each guest workspace.`);break}if(!await mt(18e4)){x++,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{const C=O("POST","/register",de(f.root,f.key));if(C&&C.status===200){try{Z(w(f.root,".lensmcp"),{recursive:!0}),z(w(f.root,".lensmcp","registered.json"),JSON.stringify({wsKey:f.key}))}catch{}e(` restart \u2192 re-registered '${f.key}'${f.reason==="rehost"?" (not upgraded \u2014 re-hosted after the daemon restart)":""}`)}else x++,s(` re-registering '${f.key}' failed \u2014 run \`lensmcp gateway start\` in ${f.root}.`)}}if(!a){const f=Ne();f.version&&e(f.version===i?` daemon \u2192 now running ${f.version} \u2713`:` daemon \u2192 still reports ${f.version} (expected ${i}) \u2014 check \`lensmcp gateway status\`.`)}return{exitCode:x>0?1:0}}p(ft,"At"),g(ft,"Pt"),l(ft,"runUpgrade");async function mt(t){const n=Date.now()+t;for(;;){if(O("GET","/list")?.status===200)return!0;if(Date.now()>=n)return!1;await new Promise(e=>setTimeout(e,2e3))}}p(mt,"_t"),g(mt,"Et"),l(mt,"waitForDaemon");function wt(t,n,e,s,o){const r=l((a,c,d)=>{try{const i=M(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??""}
|
|
191
191
|
${i.stdout??""}`.trim().split(`
|
|
192
|
-
`).filter(Boolean).pop()||`exited ${i.status}`}:{ok:!0}}catch(i){return{ok:!1,detail:i.message}}},"exec");for(const a of
|
|
192
|
+
`).filter(Boolean).pop()||`exited ${i.status}`}:{ok:!0}}catch(i){return{ok:!1,detail:i.message}}},"exec");for(const a of zt){if(!S(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",Q]);s(i.ok?` plugins \u2192 Codex installed \u2014 ${a.restartHint}`:` plugins \u2192 Codex install failed (${i.detail}) \u2014 run: codex plugin add ${Q}`);continue}r(a.bin,["plugin","marketplace","update",Ds]);const d=Wt();if(d.length===0){const i=r(a.bin,["plugin","install",Q,"--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 ${Q} --yes`);continue}for(const i of d){const u=i.scope&&i.scope!=="user"?["--scope",i.scope]:[],h=r(a.bin,["plugin","update",i.id,...u],i.projectPath??n),m=i.projectPath?` (${i.projectPath})`:"";h.ok?s(` plugins \u2192 Claude Code updated${m} \u2014 ${a.restartHint}`):(o(` plugins \u2192 Claude Code update failed${m}: ${h.detail}`),o(` run by hand${i.projectPath?` from ${i.projectPath}`:""}: claude plugin update ${i.id}${u.length>0?` --scope ${i.scope}`:""}`))}}}p(wt,"It"),g(wt,"Tt"),l(wt,"syncAgentPlugins");function oe(){let t=_(cs(import.meta.url));for(let n=0;n<4;n++){if(S(w(t,"package.json")))return t;const e=_(t);if(e===t)break;t=e}return t}p(oe,"oe"),g(oe,"ie"),l(oe,"cliPackageRoot");function re(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(re,"re"),g(re,"ae"),l(re,"readProjectLensmcpVersion");function U(){try{return JSON.parse(B(w(oe(),"package.json"),"utf8")).version}catch{return"0.0.0"}}p(U,"q"),g(U,"z"),l(U,"readCliVersion");function yt(t,n,e){const s=L(t.cwd),o=vt(s);return o?{exitCode:M(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).
|
|
193
193
|
Looked for main.rollout.js (walking up from cwd):
|
|
194
194
|
\u2022 <dir>/node_modules/@lensmcp/cluster/executors/gateway/main.rollout.js
|
|
195
195
|
\u2022 <dir>/dist/libs/cluster/executors/gateway/main.rollout.js
|
|
196
|
-
Install @lensmcp/cluster, or \`yarn nx build @lensmcp/cluster\` in the workspace.`),{exitCode:1})}p(Dt,"Mt"),l(
|
|
197
|
-
`)[0]?.trim());return Number.isInteger(e)&&e>0?e:void 0}catch{return}}p(Ee,"ze"),l(Ee,"pidOnSocket");function Te(t){try{const n=
|
|
198
|
-
`).find(e=>e.startsWith("n"));return n&&n.slice(1).trim()||void 0}catch{return}}p(Bt,"_t"),l(
|
|
196
|
+
Install @lensmcp/cluster, or \`yarn nx build @lensmcp/cluster\` in the workspace.`),{exitCode:1})}p(yt,"Dt"),g(yt,"Mt"),l(yt,"runRollout");function vt(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(S(o))return o;const s=_(n);if(s===n)break;n=s}}p(vt,"Ft"),g(vt,"Lt"),l(vt,"findRolloutBundle");function le(t){return ue(t,"main.js")}p(le,"pe"),g(le,"ue"),l(le,"findMcpBinary");function kt(t){return ue(t,"shim.js")}p(kt,"Kt"),g(kt,"Rt"),l(kt,"findShimBinary");function ue(t,n){const e=w(oe(),"bundled",n);if(S(e))return e;const s=w(t,"servers","lensmcp-mcp","dist",n);if(S(s))return s;let o=t;for(let r=0;r<5;r++){const a=w(o,"servers","lensmcp-mcp","dist",n);if(S(a))return a;const c=_(o);if(c===o)break;o=c}}p(ue,"ge"),g(ue,"fe"),l(ue,"findServerBundle");function $t(t){const n=w(oe(),"bundled","bridge.js");if(S(n))return n;let e=t;for(let s=0;s<5;s++){const o=w(e,"libs","bridge","dist","main.js");if(S(o))return o;const r=_(e);if(r===e)break;e=r}}p($t,"Gt"),g($t,"Ot"),l($t,"findBridgeBundle");function ae(t){let n=t;for(let e=0;e<5;e++){const s=w(n,"node_modules",".bin","nx");if(S(s))return s;const o=_(n);if(o===n)break;n=o}}p(ae,"ae"),g(ae,"ce"),l(ae,"findNxBinary");function ie(t){const n=w(t,".lensmcp");S(n)||Z(n,{recursive:!0})}p(ie,"ie"),g(ie,"de"),l(ie,"ensureLensmcpDir");function bt(){return!!(process.stdin.isTTY&&process.stdout.isTTY)}p(bt,"Ht"),g(bt,"At"),l(bt,"isInteractive");function pe(){const t=as(),n=[],e=l((s,o)=>{try{for(const r of ge(s,{withFileTypes:!0})){if(!r.isDirectory()||!r.name.endsWith("-devserver"))continue;const a=w(s,r.name,"parent.sock");S(a)&&n.push({service:r.name.slice(0,-10),wsKey:o,sock:a})}}catch{}},"scan");e(t,"");try{for(const s of ge(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(pe,"he"),g(pe,"ge"),l(pe,"discoverDevserverSocks");const W=l(t=>t.wsKey?`${t.wsKey}/${t.service}`:t.service,"fullServiceName");function Ee(t){try{const n=M("lsof",["-t",t],{encoding:"utf8"}),e=Number((n.stdout??"").split(`
|
|
197
|
+
`)[0]?.trim());return Number.isInteger(e)&&e>0?e:void 0}catch{return}}p(Ee,"Ee"),g(Ee,"ze"),l(Ee,"pidOnSocket");function Te(t){try{const n=M("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(Te,"Te"),g(Te,"Ye"),l(Te,"pgidOf");function Ct(t){try{const n=(M("lsof",["-a","-p",String(t),"-d","cwd","-Fn"],{encoding:"utf8"}).stdout??"").split(`
|
|
198
|
+
`).find(e=>e.startsWith("n"));return n&&n.slice(1).trim()||void 0}catch{return}}p(Ct,"Bt"),g(Ct,"_t"),l(Ct,"cwdOfPid");function xt(t,n){const e=Lt(L(t),L(n));return e===""||!e.startsWith("..")&&!is(e)}p(xt,"Vt"),g(xt,"It"),l(xt,"isInside");function St(t,n){return pe().filter(e=>{if(e.wsKey)return e.wsKey===n;const s=Ee(e.sock),o=s!==void 0?Ct(s):void 0;return o!==void 0&&xt(t,o)})}p(St,"Jt"),g(St,"Dt"),l(St,"workspaceDevservers");function jt(t,n,e,s){const o=St(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,...K()]){const i=Te(d);i!==void 0&&r.add(i)}let a=0,c=0;for(const d of o){const i=W(d),u=Ee(d.sock);if(u===void 0){V(d.sock),e(` \u2713 ${i} \u2014 stale socket removed (no process held it)`),c++;continue}const h=Te(u),m=h!==void 0&&!r.has(h),y=l(k=>{try{m?process.kill(-h,k):process.kill(u,k)}catch{}},"signal");y("SIGTERM"),Me(u,5e3)||(y("SIGKILL"),Me(u,2e3)),V(d.sock),e(` \u2713 ${i} \u2014 stopped (pid ${u}${m?`, group ${h}`:", parent only"})`),a++}return{killed:a,stale:c}}p(jt,"Wt"),g(jt,"Ft"),l(jt,"reapWorkspacePods");function Me(t,n){const e=Date.now()+n;for(;;){if(!te(t))return!0;if(Date.now()>=e)return!1;M("sleep",["0.15"])}}p(Me,"Me"),g(Me,"Xe"),l(Me,"waitForPidGone");function Nt(t,n,e,s){const o=w(n,".lensmcp","gateway.pid"),r=w(n,".lensmcp","registered.json"),{pid:a,healed:c}=se(o,n);if(c&&s(` healed: adopted a running gateway (pid ${a}) the pid file had lost.`),ee(n,t.env,u=>s(` ${u}`)),G(n)!==void 0){s(` gateway: this workspace owns the :443 daemon (pid ${a??"?"}) \u2014 left running, pods respawn fresh.`);return}const d=O("GET","/list");if(d?.status!==200){s(" gateway: not running. Start it when you are ready: lensmcp gateway start");return}if(d.json&&typeof d.json=="object"&&(d.json.workspaces??[]).some(u=>u.key===e)){Z(_(r),{recursive:!0}),z(r,JSON.stringify({wsKey:e})),s(` gateway: '${e}' is already registered into the shared daemon \u2014 left serving.`);return}const i=O("POST","/register",de(n,e));if(i&&i.status===200){Z(_(r),{recursive:!0}),z(r,JSON.stringify({wsKey:e})),s(` gateway: registered '${e}' into the shared daemon \u2014 it now hosts this workspace.`);return}s(" gateway: a shared daemon is up but registering this workspace failed \u2014 run `lensmcp gateway start`.")}p(Nt,"Ut"),g(Nt,"Kt"),l(Nt,"reconcileGatewayAfterSetup");function Le(t,n,e,s){let o=n.filter(r=>r.service===t||W(r)===t);if(o.length>1)try{const r=q(e).key,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(W).join(", ")}`),null):o.length>1?(s(`"${t}" is ambiguous \u2014 use one of: ${o.map(W).join(", ")}`),null):o[0]}p(Le,"Le"),g(Le,"Ze"),l(Le,"resolveServiceSock");async function Pt(t,n,e,s){const o=R(n,{string:["--tail","--cwd"],boolean:["--no-follow","--plain","--color"]}),r=o.positional[0],a=pe();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 y of a)e(` ${W(y)}`)}return{exitCode:0}}const c=Le(r,a,L(b(o.flags["--cwd"])??t.cwd),s);if(!c)return{exitCode:1};const d=o.flags["--no-follow"]!==!0,i=Number(b(o.flags["--tail"])??NaN),u=Number.isInteger(i)&&i>=0?i:100,h=o.flags["--plain"]===!0||o.flags["--color"]!==!0&&!process.stdout.isTTY,m=`/webpack/logs?tail=${u}&follow=${d?1:0}${h?"&plain=1":""}`;return new Promise(y=>{const k=Mt({socketPath:c.sock,path:m,method:"GET"},$=>{$.on("data",x=>process.stdout.write(x)),us(()=>{$.destroy(),y({exitCode:0})}),$.on("end",()=>y({exitCode:0})),$.on("error",()=>y({exitCode:1}))});k.on("error",$=>{s(`Cannot attach to ${W(c)}: ${$.message}`),s("The devserver may have crashed leaving a stale socket \u2014 restart the service and retry."),y({exitCode:1})}),k.end()})}p(Pt,"qt"),g(Pt,"Gt"),l(Pt,"runLogs");async function Et(t,n,e,s){const o=R(n,{string:["--port","--cwd"]}),r=o.positional[0],a=pe();if(!r)return s("Usage: lensmcp debug <service> [--port <base>]"),a.length>0&&s(`Running: ${a.map(W).join(", ")}`),{exitCode:2};const c=Le(r,a,L(b(o.flags["--cwd"])??t.cwd),s);if(!c)return{exitCode:1};const d=Number(b(o.flags["--port"])??"")||void 0,i=`/webpack/debug${d?`?port=${d}`:""}`,u=await new Promise(m=>{const y=Mt({socketPath:c.sock,path:i,method:"POST"},k=>{let $="";k.on("data",x=>$+=x),k.on("end",()=>m($)),k.on("error",()=>m(null))});y.on("error",()=>m(null)),y.end()});if(u===null)return s(`Cannot reach ${W(c)} \u2014 the devserver may have crashed leaving a stale socket.`),{exitCode:1};let h;try{h=JSON.parse(u)}catch{return s(`Unexpected response from the devserver: ${u.slice(0,200)}`),{exitCode:1}}e(`Inspectors open on ${W(c)} \u2014 in place, no restart:`);for(const m of h.pods??[])e(` pod #${m.id} ${m.inspectorUrl??"(no url reported \u2014 check lensmcp logs)"}`);for(const m of h.workers??[])e(` worker ${m.name} 127.0.0.1:${m.port}`);return e(h.fixedPorts&&h.basePort?`Attach WebStorm (Run \u2192 Attach to Node.js/Chrome) to 127.0.0.1:${h.basePort} \u2014 or click the "Debugger listening" link in \`lensmcp logs ${r}\`.`:"Attach WebStorm (Run \u2192 Attach to Node.js/Chrome) using one of the URLs above \u2014 the ports are ephemeral, so there is no fixed address to configure. Set LENSMCP_DEBUG_FIXED_PORTS=1 if you need a stable one."),{exitCode:0}}p(Et,"zt"),g(Et,"Ht"),l(Et,"runDebug");function b(t){if(t!==void 0)return typeof t=="string"?t:void 0}p(b,"$"),g(b,"k"),l(b,"stringFlag");function R(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 u=t[a+1];u===void 0||u.startsWith("--")?o[i]="":(o[i]=u,a++)}else o[i]=d===-1?!0:c.slice(d+1)}else r.push(c)}return{flags:o,positional:r}}p(R,"R"),g(R,"O"),l(R,"parseFlags");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var d=Object.defineProperty;var r=(e,t)=>d(e,"name",{value:t,configurable:!0});var p=Object.defineProperty,s=r((e,t)=>p(e,"name",{value:t,configurable:!0}),"s"),u=Object.defineProperty,a=s((e,t)=>u(e,"name",{value:t,configurable:!0}),"s");export function detectDuplicateRegistration(e){const t=new Set(e.disabledServers??[]),n=new Set(e.pluginServers),i=e.pluginEnabled?[...new Set(e.workspaceServers)].filter(l=>n.has(l)&&!t.has(l)):[];if(e.pluginReadable===!1)return{duplicated:!1,names:[],indeterminate:!0,detail:"could not read the plugin manifest \u2014 cannot tell whether the server is registered twice",hint:"run `lensmcp plugin status` to check the plugin install, then re-run doctor"};if(i.length===0)return{duplicated:!1,names:[],indeterminate:!1,detail:"one registration",hint:""};const o=i.join(", "),c=e.sharedMcp?`'${o}' is registered TWICE \u2014 once in this workspace's .mcp.json and once by the enabled Claude plugin. On shared MCP mode both routes proxy into the SAME server, so there is one event window; the cost is a redundant client shim per agent session.`:`'${o}' is registered TWICE \u2014 once in this workspace's .mcp.json and once by the enabled Claude plugin, so every agent session starts two servers (each with its own event window).`;return{duplicated:!0,names:i,indeterminate:!1,detail:c,hint:`Add "disabledMcpjsonServers": ["${i[0]}"] to .claude/settings.local.json to keep the plugin's copy, or remove the plugin (\`/plugin\` \u2192 uninstall) to keep the .mcp.json one. (settings.local.json is the file Claude Code itself writes these to.)`}}r(detectDuplicateRegistration,"detectDuplicateRegistration"),s(detectDuplicateRegistration,"detectDuplicateRegistration"),a(detectDuplicateRegistration,"detectDuplicateRegistration");export function mcpServerNames(e){const t=e?.mcpServers;return!t||typeof t!="object"||Array.isArray(t)?[]:Object.keys(t)}r(mcpServerNames,"mcpServerNames"),s(mcpServerNames,"mcpServerNames"),a(mcpServerNames,"mcpServerNames");export function pluginEnabledInSettings(e,t){const n=e?.enabledPlugins;return!n||typeof n!="object"?!1:n[t]===!0}r(pluginEnabledInSettings,"pluginEnabledInSettings"),s(pluginEnabledInSettings,"pluginEnabledInSettings"),a(pluginEnabledInSettings,"pluginEnabledInSettings");export function disabledMcpServers(e){const t=e?.disabledMcpjsonServers;return Array.isArray(t)?t.filter(n=>typeof n=="string"):[]}r(disabledMcpServers,"disabledMcpServers"),s(disabledMcpServers,"disabledMcpServers"),a(disabledMcpServers,"disabledMcpServers");
|
package/lib/hook-memory.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var i=Object.defineProperty;var n=(e,r)=>i(e,"name",{value:r,configurable:!0});var l=Object.defineProperty,t=n((e,r)=>l(e,"name",{value:r,configurable:!0}),"n"),f=Object.defineProperty,o=t((e,r)=>f(e,"name",{value:r,configurable:!0}),"t");import{lstatSync as y,chmodSync as d,mkdirSync as h,readFileSync as p,rmSync as m,writeFileSync as b}from"node:fs";import{tmpdir as A}from"node:os";import{join as u}from"node:path";const S=o(e=>e.replace(/[^A-Za-z0-9._-]/g,"_").slice(0,100)||"unknown","safeKey");export const memoryPathFor=o((e,r=A())=>u(r,"lensmcp-hook",`${S(e)}.digest`),"memoryPathFor");export function lastAnnounced(e,r){try{return p(memoryPathFor(e,r),"utf8")}catch{return}}n(lastAnnounced,"lastAnnounced"),t(lastAnnounced,"lastAnnounced"),o(lastAnnounced,"lastAnnounced");export function remember(e,r,a){const c=memoryPathFor(e,a);try{if(!r){m(c,{force:!0});return}s(u(c,"..")),m(c,{force:!0}),b(c,r,{flag:"wx",mode:384})}catch{}}n(remember,"remember"),t(remember,"remember"),o(remember,"remember");function s(e){try{h(e,{recursive:!0,mode:448})}catch{}try{const r=y(e);r.isDirectory()&&(r.mode&63)!==0&&d(e,448)}catch{}}n(s,"i"),t(s,"h"),o(s,"ensureOwnerOnlyDir");export function shouldAnnounce(e,r,a){return r?e?lastAnnounced(e,a)!==r:!0:!1}n(shouldAnnounce,"shouldAnnounce"),t(shouldAnnounce,"shouldAnnounce"),o(shouldAnnounce,"shouldAnnounce");
|
package/lib/mcp-mode.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`;return{json:
|
|
1
|
+
"use strict";var M=Object.defineProperty;var o=(e,r)=>M(e,"name",{value:r,configurable:!0});var s=Object.defineProperty,t=o((e,r)=>s(e,"name",{value:r,configurable:!0}),"o"),f=Object.defineProperty,n=t((e,r)=>f(e,"name",{value:r,configurable:!0}),"e");export const DEFAULT_MCP_MODE="embedded",SHARED_MCP_ENTRY_PATH="/mcp",SHARED_MCP_BIND_ADDRESS="127.0.0.1";export function isMcpMode(e){return e==="embedded"||e==="shared"}o(isMcpMode,"isMcpMode"),t(isMcpMode,"isMcpMode"),n(isMcpMode,"isMcpMode");export function sharedMcpUrl(e,r=SHARED_MCP_BIND_ADDRESS){return`http://${r}:${e}${SHARED_MCP_ENTRY_PATH}`}o(sharedMcpUrl,"sharedMcpUrl"),t(sharedMcpUrl,"sharedMcpUrl"),n(sharedMcpUrl,"sharedMcpUrl");export function resolveMcpMode(e={}){for(const r of[e.flag,e.env,e.config])if(isMcpMode(r))return r;return DEFAULT_MCP_MODE}o(resolveMcpMode,"resolveMcpMode"),t(resolveMcpMode,"resolveMcpMode"),n(resolveMcpMode,"resolveMcpMode");function p(e){if(!e||!e.trim())return{};try{const r=JSON.parse(e);return r&&typeof r=="object"&&!Array.isArray(r)?r:{}}catch{return{}}}o(p,"i"),t(p,"i"),n(p,"parseObject");export function applyConfigMcpMode(e,r){const a=p(e),c=a.mcp,d=c&&typeof c=="object"&&!Array.isArray(c)?{...c,mode:r}:{mode:r},i=JSON.stringify({...a,mcp:d},null,2)+`
|
|
2
|
+
`;return{json:i,changed:i!==e}}o(applyConfigMcpMode,"applyConfigMcpMode"),t(applyConfigMcpMode,"applyConfigMcpMode"),n(applyConfigMcpMode,"applyConfigMcpMode");
|
package/lib/mcp-restart.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var s=Object.defineProperty;var o=(r,e)=>s(r,"name",{value:e,configurable:!0});var t=Object.defineProperty,n=o((r,e)=>t(r,"name",{value:e,configurable:!0}),"o"),i=Object.defineProperty,a=n((r,e)=>i(r,"name",{value:e,configurable:!0}),"s");export function planMcpRestart(r){const e=r.identity;return e?!e.root||e.root!==r.expectedRoot?{kill:!1,reason:`the server on this port serves ${e.root?`'${e.root}'`:"an unknown workspace"}, not ${r.expectedRoot} \u2014 left alone`}:r.expectedKey&&e.key&&e.key!==r.expectedKey?{kill:!1,reason:`the server on this port serves workspace '${e.key}', not '${r.expectedKey}' \u2014 left alone`}:typeof e.pid!="number"||!Number.isInteger(e.pid)||e.pid<=1?{kill:!1,reason:"the shared MCP server did not report a usable pid \u2014 cannot restart it safely"}:r.selfPid!==void 0&&e.pid===r.selfPid?{kill:!1,reason:"the reported pid is this process \u2014 refusing to signal ourselves"}:e.version===void 0?{kill:!0,pid:e.pid,reason:`serving a bundle older than ${r.targetVersion} (it predates the version field)`}:e.version!==r.targetVersion?{kill:!0,pid:e.pid,reason:`serving ${e.version}, not ${r.targetVersion}`}:{kill:!1,reason:`already serving ${r.targetVersion}`}:{kill:!1,reason:"no shared MCP server answered \u2014 the next session starts one on the new bundle"}}o(planMcpRestart,"planMcpRestart"),n(planMcpRestart,"planMcpRestart"),a(planMcpRestart,"planMcpRestart");
|
package/lib/mcp-wiring.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`).find(e=>e.startsWith("data:")),n=
|
|
1
|
+
"use strict";var v=Object.defineProperty;var i=(r,t)=>v(r,"name",{value:t,configurable:!0});var b=Object.defineProperty,p=i((r,t)=>b(r,"name",{value:t,configurable:!0}),"i"),k=Object.defineProperty,s=p((r,t)=>k(r,"name",{value:t,configurable:!0}),"i");import{spawnSync as g}from"node:child_process";import{existsSync as x,mkdirSync as j,readFileSync as I,writeFileSync as O}from"node:fs";import{request as w}from"node:http";import{dirname as N,join as h}from"node:path";import{applyConfigMcpMode as C,resolveMcpMode as P,sharedMcpUrl as M}from"./mcp-mode.js";import{readLensConfig as l}from"./workspace-scope.js";export const LENS_CONFIG=h(".lensmcp","config.json");function m(r){try{return I(r,"utf8")}catch{return}}i(m,"g"),p(m,"b"),s(m,"read");export function effectiveMcpMode(r,t,n=process.env){return P({flag:t,env:n.LENSMCP_MCP_MODE,config:l(r).mcp?.mode})}i(effectiveMcpMode,"effectiveMcpMode"),p(effectiveMcpMode,"effectiveMcpMode"),s(effectiveMcpMode,"effectiveMcpMode");export function wireMcpMode(r,t){const n=l(r).ports.mcpHttp,e=h(r,LENS_CONFIG),c=C(m(e),t);if(c.changed){const a=N(e);x(a)||j(a,{recursive:!0}),O(e,c.json)}return{mode:t,url:M(n),port:n,wrote:c.changed}}i(wireMcpMode,"wireMcpMode"),p(wireMcpMode,"wireMcpMode"),s(wireMcpMode,"wireMcpMode");export function readMcpWiring(r,t=process.env){const n=l(r).ports.mcpHttp;return{mode:effectiveMcpMode(r,void 0,t),port:n,url:M(n)}}i(readMcpWiring,"readMcpWiring"),p(readMcpWiring,"readMcpWiring"),s(readMcpWiring,"readMcpWiring");const f=JSON.stringify({jsonrpc:"2.0",id:1,method:"initialize",params:{protocolVersion:"2025-06-18",capabilities:{},clientInfo:{name:"lensmcp-doctor",version:"1"}}});export function parseInitializeResponse(r){const t=r.split(`
|
|
2
|
+
`).find(e=>e.startsWith("data:")),n=t?t.slice(5).trim():r.trim();try{const e=JSON.parse(n);return e.result?{ok:!0,...e.result.serverInfo?.name?{server:e.result.serverInfo.name}:{},...e.result.protocolVersion?{protocolVersion:e.result.protocolVersion}:{}}:{ok:!1,error:"no initialize result"}}catch{return{ok:!1,error:"unreadable initialize response"}}}i(parseInitializeResponse,"parseInitializeResponse"),p(parseInitializeResponse,"parseInitializeResponse"),s(parseInitializeResponse,"parseInitializeResponse");export function probeSharedMcpSync(r,t=2){const n=g("curl",["-s","--max-time",String(t),"-X","POST",r,"-H","content-type: application/json","-H","accept: application/json, text/event-stream","-d",f],{encoding:"utf8"});if(n.error||n.status!==0)return{ok:!1,error:"nothing listening"};const e=(n.stdout??"").trim();return e?parseInitializeResponse(e):{ok:!1,error:"empty response"}}i(probeSharedMcpSync,"probeSharedMcpSync"),p(probeSharedMcpSync,"probeSharedMcpSync"),s(probeSharedMcpSync,"probeSharedMcpSync");export function probeIdentitySync(r,t=2){const n=g("curl",["-s","--max-time",String(t),`http://127.0.0.1:${r}/lensmcp/identity`],{encoding:"utf8"});if(!(n.error||n.status!==0))try{const e=JSON.parse((n.stdout??"").trim());return e.kind!=="lensmcp-mcp-identity"?void 0:{...typeof e.key=="string"?{key:e.key}:{},...typeof e.root=="string"?{root:e.root}:{},...typeof e.pid=="number"?{pid:e.pid}:{},...typeof e.version=="string"?{version:e.version}:{}}}catch{return}}i(probeIdentitySync,"probeIdentitySync"),p(probeIdentitySync,"probeIdentitySync"),s(probeIdentitySync,"probeIdentitySync");export function probeSharedMcp(r,t=2500){return new Promise(n=>{let e=!1;const c=s(o=>{e||(e=!0,n(o))},"finish");let a;try{a=new URL(r)}catch{c({ok:!1,error:`not a URL: ${r}`});return}const d=w({hostname:a.hostname,port:a.port,path:a.pathname,method:"POST",timeout:t,headers:{"content-type":"application/json",accept:"application/json, text/event-stream","content-length":Buffer.byteLength(f)}},o=>{let u="";o.setEncoding("utf8"),o.on("data",S=>{u+=S,(u.includes('"result"')||u.length>64e3)&&o.destroy()});const y=s(()=>{if((o.statusCode??0)>=400){c({ok:!1,error:`HTTP ${o.statusCode}`});return}c(parseInitializeResponse(u))},"settle");o.on("end",y),o.on("close",y)});d.on("timeout",()=>{d.destroy(),c({ok:!1,error:`no response within ${t}ms`})}),d.on("error",o=>{c({ok:!1,error:o.code==="ECONNREFUSED"?"nothing listening":o.message??"request failed"})}),d.end(f)})}i(probeSharedMcp,"probeSharedMcp"),p(probeSharedMcp,"probeSharedMcp"),s(probeSharedMcp,"probeSharedMcp");
|
package/lib/plugin-version.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`)}s(formatSkewContext,"formatSkewContext"),i(formatSkewContext,"formatSkewContext");export function syncPlugin(
|
|
3
|
-
`)[0]||`\`${
|
|
1
|
+
"use strict";var j=Object.defineProperty;var s=(e,n)=>j(e,"name",{value:n,configurable:!0});var x=Object.defineProperty,p=s((e,n)=>x(e,"name",{value:n,configurable:!0}),"s"),k=Object.defineProperty,i=p((e,n)=>k(e,"name",{value:n,configurable:!0}),"i");import{spawnSync as v}from"node:child_process";import{existsSync as P,readFileSync as S}from"node:fs";import{homedir as h}from"node:os";import{join as d}from"node:path";export const PLUGIN_NAME="lensmcp";function g(e){try{return JSON.parse(S(e,"utf8"))}catch{return}}s(g,"d"),p(g,"a"),i(g,"readJson");function f(e){const n=g(e)?.version;return typeof n=="string"&&n.length>0?n:void 0}s(f,"g"),p(f,"g"),i(f,"readVersionField");export function readInstalledPlugin(e,n=h()){const o=readInstalledPlugins(n);if(o.length!==0)return o.find(t=>t.projectPath===e)??o.find(t=>t.scope==="user")??o[0]}s(readInstalledPlugin,"readInstalledPlugin"),p(readInstalledPlugin,"readInstalledPlugin"),i(readInstalledPlugin,"readInstalledPlugin");export function readInstalledPlugins(e=h()){const n=g(d(e,".claude","plugins","installed_plugins.json"))?.plugins;if(!n||typeof n!="object")return[];const o=[];for(const[t,r]of Object.entries(n)){const[l,c]=t.split("@");if(!(l!==PLUGIN_NAME||!c))for(const a of Array.isArray(r)?r:[r]){if(typeof a!="object"||a===null)continue;const u=a;typeof u.version=="string"&&o.push({id:t,marketplace:c,version:u.version,...typeof u.scope=="string"?{scope:u.scope}:{},...typeof u.projectPath=="string"?{projectPath:u.projectPath}:{}})}}return o}s(readInstalledPlugins,"readInstalledPlugins"),p(readInstalledPlugins,"readInstalledPlugins"),i(readInstalledPlugins,"readInstalledPlugins");export function readVersions(e){const n={};if(e.pluginRoot){const r=f(d(e.pluginRoot,".claude-plugin","plugin.json"));r&&(n.plugin=r,n.pluginSource="plugin-root")}const o=readInstalledPlugin(e.cwd,e.home);o&&(n.pluginId=o.id,n.pluginMarketplace=o.marketplace,o.scope&&(n.pluginScope=o.scope),n.plugin||(n.plugin=o.version,n.pluginSource="install-index"));const t=f(d(e.cwd,"node_modules","lensmcp","package.json"));return t&&(n.project=t),e.cliVersion&&e.cliVersion!=="0.0.0"&&(n.cli=e.cliVersion),n}s(readVersions,"readVersions"),p(readVersions,"readVersions"),i(readVersions,"readVersions");export function compareVersions(e,n){const o=i(l=>{const c=l.trim().replace(/^v/,"").split(/[-+]/)[0];if(c===void 0)return;const a=c.split(".");if(a.length===0||a.length>3)return;const u=a.map(m=>/^\d+$/.test(m)?Number(m):Number.NaN);return u.some(Number.isNaN)?void 0:[u[0]??0,u[1]??0,u[2]??0]},"parse"),t=o(e),r=o(n);if(!(!t||!r)){for(let l=0;l<3;l++){const c=(t[l]??0)-(r[l]??0);if(c!==0)return c<0?-1:1}return 0}}s(compareVersions,"compareVersions"),p(compareVersions,"compareVersions"),i(compareVersions,"compareVersions");export function detectSkew(e){const n=e.plugin,o=e.project??e.cli;if(!n||!o||n===o)return;const t=compareVersions(n,o);if(t===void 0||t===0)return;const r=e.cli&&e.project&&e.cli!==e.project?{cli:e.cli,project:e.project}:void 0;return{mismatch:!0,plugin:n,expected:o,expectedSource:e.project?"project":"cli",direction:t<0?"behind":"ahead",...e.pluginId?{pluginId:e.pluginId}:{},...e.pluginMarketplace?{marketplace:e.pluginMarketplace}:{},...e.pluginScope?{scope:e.pluginScope}:{},...r?{cliSkew:r}:{}}}s(detectSkew,"detectSkew"),p(detectSkew,"detectSkew"),i(detectSkew,"detectSkew");export function updateCommands(e){const n=e.pluginId??PLUGIN_NAME,o=e.scope&&e.scope!=="user"?` --scope ${e.scope}`:"";return[...e.marketplace?[`claude plugin marketplace update ${e.marketplace}`]:[],`claude plugin update ${n}${o}`]}s(updateCommands,"updateCommands"),p(updateCommands,"updateCommands"),i(updateCommands,"updateCommands");export function formatSkewContext(e){const n=[`LensMCP plugin is out of step: plugin ${e.plugin} vs lensmcp ${e.expected} (${e.expectedSource==="project"?"this project\u2019s node_modules":"the running CLI"}). The plugin\u2019s skills, hooks and wiring are from ${e.plugin} \u2014 update before relying on them:`,...updateCommands(e).map(o=>` ${o}`)," \u2026then restart Claude Code for the new plugin to load."];return e.cliSkew&&n.push(` (also: the lensmcp CLI on PATH is ${e.cliSkew.cli} while this project depends on ${e.cliSkew.project}.)`),n.join(`
|
|
2
|
+
`)}s(formatSkewContext,"formatSkewContext"),p(formatSkewContext,"formatSkewContext"),i(formatSkewContext,"formatSkewContext");export function syncPlugin(e){const n=detectSkew(e.facts);if(!n)return{outcome:e.facts.plugin!==void 0&&(e.facts.project??e.facts.cli)!==void 0?"current":"unknown",...e.facts.plugin?{from:e.facts.plugin}:{}};const o=updateCommands(n);for(const t of o){const[r,...l]=t.split(" "),c=r===void 0?void 0:e.run(r,l);if(!c)return{outcome:"manual",from:n.plugin,to:n.expected,commands:o,detail:`\`${r??"claude"}\` is not on PATH`};if(c.code!==0)return{outcome:"manual",from:n.plugin,to:n.expected,commands:o,detail:(c.stderr??"").trim().split(`
|
|
3
|
+
`)[0]||`\`${t}\` exited ${c.code}`}}return{outcome:"updated",from:n.plugin,to:n.expected,commands:o}}s(syncPlugin,"syncPlugin"),p(syncPlugin,"syncPlugin"),i(syncPlugin,"syncPlugin");export function spawnRunner(e,n=6e4){return(o,t)=>{try{const r=v(o,t,{encoding:"utf8",timeout:n,env:e,stdio:["ignore","pipe","pipe"]});return r.error&&r.error.code==="ENOENT"?void 0:{code:r.status??1,...r.stderr?{stderr:r.stderr}:{}}}catch{return}}}s(spawnRunner,"spawnRunner"),p(spawnRunner,"spawnRunner"),i(spawnRunner,"spawnRunner");export const pluginManifestPath=i(e=>d(e,".claude-plugin","plugin.json"),"pluginManifestPath"),isPluginRoot=i(e=>P(pluginManifestPath(e)),"isPluginRoot");
|
package/lib/process-identity.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var u=Object.defineProperty;var i=(r,
|
|
1
|
+
"use strict";var u=Object.defineProperty;var i=(r,e)=>u(r,"name",{value:e,configurable:!0});var p=Object.defineProperty,n=i((r,e)=>p(r,"name",{value:e,configurable:!0}),"i"),m=Object.defineProperty,a=n((r,e)=>m(r,"name",{value:e,configurable:!0}),"n");import{execFileSync as f}from"node:child_process";import{readFileSync as l,writeFileSync as g}from"node:fs";function o(r){if(!r||r<=0||process.platform==="win32")return"";try{return f("ps",["-p",String(r),"-o","lstart="],{encoding:"utf8",timeout:2e3,stdio:["ignore","pipe","ignore"]}).trim()}catch{return""}}i(o,"a"),n(o,"f"),a(o,"processStamp");const d=2;export function writeTrackedPid(r,e){const t={pid:e,stamp:o(e)||void 0};g(r,JSON.stringify(t),{mode:384})}i(writeTrackedPid,"writeTrackedPid"),n(writeTrackedPid,"writeTrackedPid"),a(writeTrackedPid,"writeTrackedPid");export function readTrackedPid(r){let e;try{e=l(r,"utf8").trim()}catch{return}if(!e)return;if(e.startsWith("{"))try{const s=JSON.parse(e),c=Number(s.pid);return!Number.isInteger(c)||c<d?void 0:{pid:c,stamp:typeof s.stamp=="string"&&s.stamp?s.stamp:void 0}}catch{return}if(!/^-?\d+$/.test(e))return;const t=Number(e);if(!(!Number.isInteger(t)||t<d))return{pid:t,stamp:void 0}}i(readTrackedPid,"readTrackedPid"),n(readTrackedPid,"readTrackedPid"),a(readTrackedPid,"readTrackedPid");export function stillSameProcess(r,e){if(!Number.isInteger(r)||r<d)return!1;const t=o(r);return t?e?t===e:!0:!1}i(stillSameProcess,"stillSameProcess"),n(stillSameProcess,"stillSameProcess"),a(stillSameProcess,"stillSameProcess");
|
package/lib/recycle-policy.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var i=Object.defineProperty;var r=(e,n)=>i(e,"name",{value:n,configurable:!0});var s=Object.defineProperty,c=r((e,n)=>s(e,"name",{value:n,configurable:!0}),"r"),a=Object.defineProperty,o=c((e,n)=>a(e,"name",{value:n,configurable:!0}),"r");import{createHash as t}from"node:crypto";export function hashConfig(e){if(e!==void 0)return t("sha256").update(e).digest("hex").slice(0,12)}r(hashConfig,"hashConfig"),c(hashConfig,"hashConfig"),o(hashConfig,"hashConfig");export function decideRecycle(e){if(e.disabled)return{recycle:!1,reason:"--no-recycle"};const n=e.previous;return!n||n.version===void 0&&n.configHash===void 0?{recycle:!0,reason:"first setup on this machine"}:n.version!==e.current.version?{recycle:!0,reason:`lensmcp ${n.version??"unknown"} \u2192 ${e.current.version??"unknown"}`}:n.configHash!==e.current.configHash?{recycle:!0,reason:".lensmcp/config.json changed"}:{recycle:!1,reason:`nothing changed since the last setup (lensmcp ${e.current.version??"unknown"})`}}r(decideRecycle,"decideRecycle"),c(decideRecycle,"decideRecycle"),o(decideRecycle,"decideRecycle");
|
package/lib/status-client.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`).find(
|
|
1
|
+
"use strict";var x=Object.defineProperty;var i=(e,r)=>x(e,"name",{value:r,configurable:!0});var M=Object.defineProperty,c=i((e,r)=>M(e,"name",{value:r,configurable:!0}),"i"),D=Object.defineProperty,o=c((e,r)=>D(e,"name",{value:r,configurable:!0}),"i");import{readLensConfig as k}from"./workspace-scope.js";import{sharedMcpUrl as S}from"./mcp-mode.js";import{effectiveMcpMode as T}from"./mcp-wiring.js";import{freshnessOf as P}from"./status-policy.js";export const IDENTITY_PATH="/lensmcp/identity",IDENTITY_KIND="lensmcp-mcp-identity";export function resolveSource(e,r){const n=k(e),t=n.ports.mcpHttp;return{workspace:n.key,mode:T(e,void 0,r),port:t,url:S(t)}}i(resolveSource,"resolveSource"),c(resolveSource,"resolveSource"),o(resolveSource,"resolveSource");function v(e){const r=Date.now()+e;return{remaining:o(()=>Math.max(0,r-Date.now()),"remaining"),expired:o(()=>Date.now()>=r,"expired")}}i(v,"w"),c(v,"M"),o(v,"deadline");async function u(e,r,n){const t=n.remaining();if(t<=0)return;const s=new AbortController,a=setTimeout(()=>s.abort(),t);try{return await fetch(e,{...r,signal:s.signal})}catch{return}finally{clearTimeout(a)}}i(u,"l"),c(u,"l"),o(u,"fetchWithin");async function p(e,r,n,t){const s=await u(e,{method:"POST",headers:{"content-type":"application/json",accept:"application/json, text/event-stream",...r?{"mcp-session-id":r}:{}},body:JSON.stringify(n)},t);if(!s)return;if(s.status===202)return{res:s};const a=await s.text().catch(()=>"");return{res:s,...parseFrame(a)===void 0?{}:{json:parseFrame(a)}}}i(p,"f"),c(p,"m"),o(p,"rpc");export function parseFrame(e){const r=e.split(`
|
|
2
|
+
`).find(t=>t.startsWith("data:")),n=(r?r.slice(5):e).trim();if(n)try{const t=JSON.parse(n);return typeof t=="object"&&t!==null?t:void 0}catch{return}}i(parseFrame,"parseFrame"),c(parseFrame,"parseFrame"),o(parseFrame,"parseFrame");export function parseResourceResult(e){const r=e?.result;if(typeof r!="object"||r===null)return;const n=r.contents;if(!Array.isArray(n)||n.length===0)return;const t=n[0];if(typeof t!="object"||t===null)return;const s=t.text;if(typeof s=="string")try{return JSON.parse(s)}catch{return}}i(parseResourceResult,"parseResourceResult"),c(parseResourceResult,"parseResourceResult"),o(parseResourceResult,"parseResourceResult");async function w(e,r,n){const t=await u(`http://127.0.0.1:${e}${IDENTITY_PATH}`,{headers:{accept:"application/json"}},n);if(!t)return"no server on this workspace\u2019s MCP port";if(!t.ok)return await t.text().catch(()=>{}),`the process on :${e} does not serve a lensmcp identity`;const s=await t.json().catch(()=>{});if(typeof s!="object"||s===null)return`unreadable identity on :${e}`;const a=s;if(a.kind!==IDENTITY_KIND)return`the process on :${e} is not a lensmcp server`;if(a.key!==r)return`:${e} serves workspace "${String(a.key)}", not "${r}"`}i(w,"b"),c(w,"D"),o(w,"verifyIdentity");export const DEFAULT_BUDGET_MS=2e3;export async function readStatus(e){const r=Date.now(),n=resolveSource(e.cwd,e.env),t=v(e.budgetMs??DEFAULT_BUDGET_MS),s=o(l=>({available:!1,source:n,reason:l,elapsedMs:Date.now()-r}),"fail");if(n.mode!=="shared")return s("MCP mode is embedded \u2014 there is no shared server to read (`lensmcp setup --mcp shared`)");const a=await w(n.port,n.workspace,t);if(a)return s(a);const h=await p(n.url,void 0,{jsonrpc:"2.0",id:1,method:"initialize",params:{protocolVersion:"2025-06-18",capabilities:{},clientInfo:{name:"lensmcp-status",version:"1"}}},t);if(!h||!h.res.ok)return s("the shared MCP server did not accept a session");const d=h.res.headers.get("mcp-session-id")??void 0,j=o(async()=>{d&&await u(n.url,{method:"DELETE",headers:{"mcp-session-id":d}},t)},"close");try{await p(n.url,d,{jsonrpc:"2.0",method:"notifications/initialized"},t);const l=o(async f=>{const m=await p(n.url,d,{jsonrpc:"2.0",id:2,method:"resources/read",params:{uri:f}},t);return parseResourceResult(m?.json)},"read"),y=await l("agent://current-status");if(typeof y!="object"||y===null)return s("the shared MCP server did not return agent://current-status");const b=y,g=new Map;for(const f of e.verify?.(b)??[]){if(t.expired())break;const m=await l(f);m!==void 0&&g.set(f,P(m))}return{available:!0,source:n,status:b,evidence:g,elapsedMs:Date.now()-r}}finally{await j()}}i(readStatus,"readStatus"),c(readStatus,"readStatus"),o(readStatus,"readStatus");
|
package/lib/status-policy.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`)}r(formatContext,"formatContext"),o(formatContext,"formatContext");export const HOOK_EVENTS=["Stop","SessionStart","SubagentStop"],isHookEvent=o(
|
|
1
|
+
"use strict";var m=Object.defineProperty;var r=(e,t)=>m(e,"name",{value:t,configurable:!0});var b=Object.defineProperty,s=r((e,t)=>b(e,"name",{value:t,configurable:!0}),"r"),$=Object.defineProperty,o=s((e,t)=>$(e,"name",{value:t,configurable:!0}),"r");export const HOOK_SIGNAL_CLASS={typecheck:"check",lint:"check",build:"check",runtime:"observation",cluster:"observation"},OBSERVATION_WINDOW_MS=30*6e4;const k=o(e=>typeof e=="object"&&e!==null&&!Array.isArray(e),"isRecord"),p=o(e=>typeof e=="number"&&Number.isFinite(e)?e:void 0,"asFiniteNumber");function u(e,t){if(!Array.isArray(e))return;let n;for(const a of e){if(!k(a))continue;const i=p(a[t]);i!==void 0&&(n===void 0||i>n)&&(n=i)}return n}r(u,"f"),s(u,"h"),o(u,"newestIn");export function freshnessOf(e){if(!k(e))return{};const t=typeof e.producer=="string"?e.producer:void 0,n=p(e.lastRunAt)??p(e.lastReportedAt)??u(e.producers,"lastReportedAt")??u(e.producers,"lastRunAt"),a=u(e.entries,"timestamp")??u(e.failures,"timestamp")??u(e.violations,"timestamp");return{...t===void 0?{}:{declaredProducer:t},...e.stale===!0?{declaredStale:!0}:{},...n===void 0?{}:{ranAt:n},...a===void 0?{}:{newestItemAt:a},...p(e.ageMs)===void 0?{}:{ageMs:p(e.ageMs)}}}r(freshnessOf,"freshnessOf"),s(freshnessOf,"freshnessOf"),o(freshnessOf,"freshnessOf");const v=o((e,t)=>e===void 0?void 0:Math.max(0,t-e),"ageFrom");export function candidateSignals(e){return(e.signals??[]).filter(t=>HOOK_SIGNAL_CLASS[t.kind]!==void 0&&(t.state==="failed"||t.state==="warning")&&t.producer==="connected")}r(candidateSignals,"candidateSignals"),s(candidateSignals,"candidateSignals"),o(candidateSignals,"candidateSignals");export function judge(e,t,n,a=OBSERVATION_WINDOW_MS){const i=HOOK_SIGNAL_CLASS[e.kind];if(i===void 0)return{kind:e.kind,reason:"out-of-scope"};if(e.state!=="failed"&&e.state!=="warning")return{kind:e.kind,reason:"not-actionable"};if(e.producer!=="connected"||t?.declaredProducer==="none")return{kind:e.kind,reason:"no-producer"};const f=e.reads?.[0]??e.resource,l={kind:e.kind,state:e.state,...e.count===void 0?{}:{count:e.count},read:f,detail:e.detail};if(e.stale===!0||t?.declaredStale===!0){const g=t?.ageMs??v(t?.ranAt,n);return{...l,stale:!0,...g===void 0?{}:{ageMs:g}}}if(i==="check"){const g=v(t?.ranAt,n);return g===void 0?{kind:e.kind,reason:"no-freshness-evidence"}:{...l,stale:!1,ageMs:g}}const d=t?.newestItemAt;if(d===void 0)return{kind:e.kind,reason:"no-freshness-evidence"};const c=Math.max(0,n-d);return c>a?{kind:e.kind,reason:"stale-observation"}:{...l,stale:!1,ageMs:c}}r(judge,"judge"),s(judge,"judge"),o(judge,"judge");const x=o(e=>"state"in e,"isFinding");export function select(e,t,n,a=OBSERVATION_WINDOW_MS){const i=[],f=[],l=[];for(const d of e.signals??[]){d.producer==="none"&&HOOK_SIGNAL_CLASS[d.kind]!==void 0&&l.push(d.kind);const c=judge(d,t.get(d.resource),n,a);x(c)?i.push(c):c.reason!=="out-of-scope"&&c.reason!=="not-actionable"&&f.push(c)}return i.sort((d,c)=>d.state===c.state?(c.count??0)-(d.count??0):d.state==="failed"?-1:1),{findings:i,suppressed:f,unmonitored:l}}r(select,"select"),s(select,"select"),o(select,"select");export function describeAge(e){return e<6e4?`${Math.max(1,Math.round(e/1e3))}s ago`:e<36e5?`${Math.round(e/6e4)}m ago`:`${Math.round(e/36e5)}h ago`}r(describeAge,"describeAge"),s(describeAge,"describeAge"),o(describeAge,"describeAge");function h(e){return e.read.startsWith("runtime://browser")?"browser runtime error":"server-side error"}r(h,"k"),s(h,"g"),o(h,"runtimeNoun");export function describeCount(e){const t=e.kind==="runtime"?h(e):`${e.kind} ${e.state==="failed"?"error":"warning"}`,n=e.count===1?"":"s";return`${e.count===void 0?"":`${e.count} `}${t}${n}`}r(describeCount,"describeCount"),s(describeCount,"describeCount"),o(describeCount,"describeCount");export function describeWhen(e){return e.stale?`last checked ${e.ageMs===void 0?"a while ago":describeAge(e.ageMs)}, nothing has re-run since`:e.ageMs===void 0?"recency unknown":describeAge(e.ageMs)}r(describeWhen,"describeWhen"),s(describeWhen,"describeWhen"),o(describeWhen,"describeWhen");export function findingLine(e){return`${e.kind}: ${describeCount(e)} (${describeWhen(e)}) \u2192 read ${e.read}`}r(findingLine,"findingLine"),s(findingLine,"findingLine"),o(findingLine,"findingLine");export function formatContext(e,t={}){const{findings:n,unmonitored:a}=e;if(n.length===0)return;const i=[`LensMCP${t.workspace?` (${t.workspace})`:""}: ${n.length===1?"1 signal needs":`${n.length} signals need`} attention.`,...n.map(f=>` \u2022 ${findingLine(f)}`)];return t.includeUnmonitored&&a.length>0&&i.push(` (unmonitored, so unknown rather than clean: ${a.join(", ")})`),i.push(" Verify before acting \u2014 these are observations, not a fresh build."),i.join(`
|
|
2
|
+
`)}r(formatContext,"formatContext"),s(formatContext,"formatContext"),o(formatContext,"formatContext");export const HOOK_EVENTS=["Stop","SessionStart","SubagentStop"],isHookEvent=o(e=>typeof e=="string"&&HOOK_EVENTS.includes(e),"isHookEvent");export function hookPayload(e,t){return JSON.stringify({hookSpecificOutput:{hookEventName:e,additionalContext:t}})}r(hookPayload,"hookPayload"),s(hookPayload,"hookPayload"),o(hookPayload,"hookPayload");export function findingsDigest(e){return e.map(t=>`${t.kind}:${t.state}:${t.count??""}`).sort().join("|")}r(findingsDigest,"findingsDigest"),s(findingsDigest,"findingsDigest"),o(findingsDigest,"findingsDigest");
|
package/lib/sweep.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var d=Object.defineProperty;var o=(n,e)=>d(n,"name",{value:e,configurable:!0});var S=Object.defineProperty,l=o((n,e)=>S(n,"name",{value:e,configurable:!0}),"r"),h=Object.defineProperty,u=l((n,e)=>h(n,"name",{value:e,configurable:!0}),"r");import{readdirSync as N,renameSync as j,rmSync as F,statSync as f}from"node:fs";import{join as i}from"node:path";const t=u(n=>{try{F(n,{force:!0})}catch{}},"removeQuietly");export function sweepLensRuntimeFiles(n,e){const r=i(n,".lensmcp"),y=i(r,"events.jsonl");t(`${y}.old`),t(`${e}.old`);const p=(()=>{const s=Number(process.env.LENSMCP_EVENT_MAX_FILES);return Number.isFinite(s)&&s>=1&&s<=20?Math.floor(s):5})(),v=64*1024*1024;try{for(const s of N(r)){const a=/^events\.jsonl\.(\d+)$/.exec(s);if(!a)continue;const m=Number(a[1]),c=i(r,s);if(m<1||m>p)t(c);else try{f(c).size>v&&t(c)}catch{}}}catch{}const b=16*1024*1024;try{f(e).size>b&&j(e,`${e}.1`)}catch{}}o(sweepLensRuntimeFiles,"sweepLensRuntimeFiles"),l(sweepLensRuntimeFiles,"sweepLensRuntimeFiles"),u(sweepLensRuntimeFiles,"sweepLensRuntimeFiles");
|
package/lib/upgrade.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var v=Object.defineProperty;var d=(e,n)=>v(e,"name",{value:n,configurable:!0});var w=Object.defineProperty,u=d((e,n)=>w(e,"name",{value:n,configurable:!0}),"d"),x=Object.defineProperty,f=u((e,n)=>x(e,"name",{value:n,configurable:!0}),"p");import{existsSync as h,readFileSync as l}from"node:fs";import{homedir as b}from"node:os";import{join as g}from"node:path";export const UPGRADE_SECTIONS=["dependencies","devDependencies","optionalDependencies","resolutions","overrides"];export function isLensmcpPackage(e){return e==="lensmcp"||e.startsWith("@lensmcp/")}d(isLensmcpPackage,"isLensmcpPackage"),u(isLensmcpPackage,"isLensmcpPackage"),f(isLensmcpPackage,"isLensmcpPackage");export function readConnectedWorkspaces(e={}){const n=e.home??process.env.LENSMCP_HOME??b(),c=e.exists??h,o=e.readFile??(s=>l(s,"utf8"));let r;try{r=JSON.parse(o(g(n,".lensmcp","workspaces.json")))}catch{return[]}if(!Array.isArray(r))return[];const i=new Set,p=[];for(const s of r){if(!s||typeof s!="object")continue;const{key:t,root:a}=s;typeof t!="string"||typeof a!="string"||a.length===0||i.has(a)||c(g(a,"package.json"))&&(i.add(a),p.push({key:t,root:a}))}return p}d(readConnectedWorkspaces,"readConnectedWorkspaces"),u(readConnectedWorkspaces,"readConnectedWorkspaces"),f(readConnectedWorkspaces,"readConnectedWorkspaces");export function versionPrefix(e){const n=/^([~^]?)(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/.exec(e.trim());return n?n[1]:void 0}d(versionPrefix,"versionPrefix"),u(versionPrefix,"versionPrefix"),f(versionPrefix,"versionPrefix");function m(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}d(m,"m"),u(m,"l"),f(m,"escapeRegExp");export function rewriteLensmcpDeps(e,n){let c;try{c=JSON.parse(e)}catch{return{text:e,changes:[],skipped:[]}}const o=[],r=[];for(const p of UPGRADE_SECTIONS){const s=c[p];if(!(!s||typeof s!="object"))for(const[t,a]of Object.entries(s)){if(typeof a!="string"||!isLensmcpPackage(t))continue;const y=versionPrefix(a);if(y===void 0){r.push({name:t,section:p,spec:a,reason:"non-version-spec"});continue}const k=`${y}${n}`;if(k===a){r.push({name:t,section:p,spec:a,reason:"already-current"});continue}o.push({name:t,section:p,from:a,to:k})}}let i=e;for(const p of o){const s=new RegExp(`("${m(p.name)}"\\s*:\\s*)"${m(p.from)}"`,"g");i=i.replace(s,`$1"${p.to}"`)}return{text:i,changes:o,skipped:r}}d(rewriteLensmcpDeps,"rewriteLensmcpDeps"),u(rewriteLensmcpDeps,"rewriteLensmcpDeps"),f(rewriteLensmcpDeps,"rewriteLensmcpDeps");export function detectPackageManager(e,n=h,c=o=>l(o,"utf8")){let o;try{const i=JSON.parse(c(g(e,"package.json")));typeof i.packageManager=="string"&&(o=i.packageManager.split("@")[0])}catch{}const r=f(i=>({name:i,install:["install"]}),"manager");return o==="yarn"||o==="npm"||o==="pnpm"||o==="bun"?r(o):n(g(e,"yarn.lock"))?r("yarn"):n(g(e,"pnpm-lock.yaml"))?r("pnpm"):n(g(e,"bun.lockb"))?r("bun"):r("npm")}d(detectPackageManager,"detectPackageManager"),u(detectPackageManager,"detectPackageManager"),f(detectPackageManager,"detectPackageManager");export function detectGlobalInstall(e,n=c=>l(c,"utf8")){const c=e("npm",["root","-g"]);if(!c||c.code!==0||!c.stdout)return;const o=c.stdout.trim();if(o)try{const r=JSON.parse(n(g(o,"lensmcp","package.json")));return typeof r.version=="string"?{version:r.version,root:o}:void 0}catch{return}}d(detectGlobalInstall,"detectGlobalInstall"),u(detectGlobalInstall,"detectGlobalInstall"),f(detectGlobalInstall,"detectGlobalInstall");export function planRestart(e){const n=new Map(e.known.map(t=>[t.key,t.root]));for(const t of e.upgraded)n.set(t.key,t.root);const c=new Set(e.upgraded.map(t=>t.key)),o=new Set(e.registeredKeys),r=e.daemonWsKey!==void 0&&e.daemonVersion!==void 0&&e.targetVersion!==void 0&&e.daemonVersion!==e.targetVersion;if(e.upgraded.length===0&&!r)return{steps:[],note:"nothing was upgraded"};if(!e.daemonWsKey)return{steps:[],note:"no gateway daemon is running \u2014 the next `lensmcp gateway start` picks up the new version"};const i=e.upgraded.find(t=>t.key===e.daemonWsKey),p=i?.root??n.get(e.daemonWsKey),s=[];if(i||r&&p){s.push({key:e.daemonWsKey,root:p,action:"restart",reason:i?"upgraded":"stale-daemon"});for(const t of e.registeredKeys){if(t===e.daemonWsKey)continue;const a=n.get(t);a&&s.push({key:t,root:a,action:"reregister",reason:c.has(t)?"upgraded":"rehost"})}return{steps:s}}if(r&&!p)return{steps:[],note:`the daemon ('${e.daemonWsKey}') runs ${e.daemonVersion} but its root is unknown \u2014 restart it with \`lensmcp gateway restart\` in its workspace`};for(const t of e.upgraded)o.has(t.key)&&s.push({key:t.key,root:t.root,action:"reregister",reason:"upgraded"});return s.length===0?{steps:[],note:`the running daemon ('${e.daemonWsKey}') hosts none of the upgraded workspaces`}:{steps:s}}d(planRestart,"planRestart"),u(planRestart,"planRestart"),f(planRestart,"planRestart");
|
package/lib/workspace-scope.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`;return(!
|
|
1
|
+
"use strict";var g=Object.defineProperty;var s=(n,e)=>g(n,"name",{value:e,configurable:!0});var m=Object.defineProperty,t=s((n,e)=>m(n,"name",{value:e,configurable:!0}),"o"),y=Object.defineProperty,a=t((n,e)=>y(n,"name",{value:e,configurable:!0}),"o");import{existsSync as d,mkdirSync as h,readFileSync as l,writeFileSync as b}from"node:fs";import{basename as v,join as c}from"node:path";function p(n,e){let r=2166136261;for(let o=0;o<n.length;o++)r^=n.charCodeAt(o),r=Math.imul(r,16777619);return Math.abs(r|0)%e}s(p,"d"),t(p,"l"),a(p,"hashToRange");export function slugify(n){return n.toLowerCase().replace(/^@[^/]+\//,"").replace(/[^a-z0-9]+/g,"-").replace(/(^-|-$)/g,"")||"workspace"}s(slugify,"slugify"),t(slugify,"slugify"),a(slugify,"slugify");export function resolveWorkspaceKey(n){const e=i(c(n,"nx.json"));if(e?.lensmcp?.key)return slugify(e.lensmcp.key);const r=i(c(n,"package.json"));return r?.name?slugify(r.name):e?.name?slugify(e.name):slugify(v(n))}s(resolveWorkspaceKey,"resolveWorkspaceKey"),t(resolveWorkspaceKey,"resolveWorkspaceKey"),a(resolveWorkspaceKey,"resolveWorkspaceKey");const u={dashboard:4321,mcpHttp:4500,bridge:5747};export function derivePorts(n){const e=p(n,200);return{dashboard:u.dashboard+e,mcpHttp:u.mcpHttp+e,bridge:u.bridge+e}}s(derivePorts,"derivePorts"),t(derivePorts,"derivePorts"),a(derivePorts,"derivePorts");export function deriveConfig(n){const e=resolveWorkspaceKey(n);return{schemaVersion:1,key:e,ports:derivePorts(e),dashboardBasePath:"/"+e}}s(deriveConfig,"deriveConfig"),t(deriveConfig,"deriveConfig"),a(deriveConfig,"deriveConfig");export function readLensConfig(n){const e=deriveConfig(n),r=i(c(n,".lensmcp","config.json"));if(!r)return e;const o=r.key?slugify(r.key):e.key;return{...r,schemaVersion:1,key:o,ports:{...e.ports,...r.ports??{}},dashboardBasePath:r.dashboardBasePath??"/"+o,...r.mcp?{mcp:{...r.mcp}}:{}}}s(readLensConfig,"readLensConfig"),t(readLensConfig,"readLensConfig"),a(readLensConfig,"readLensConfig");export function ensureLensConfig(n){const e=readLensConfig(n),r=c(n,".lensmcp");d(r)||h(r,{recursive:!0});const o=c(r,"config.json"),f=JSON.stringify(e,null,2)+`
|
|
2
|
+
`;return(!d(o)||l(o,"utf8")!==f)&&b(o,f),e}s(ensureLensConfig,"ensureLensConfig"),t(ensureLensConfig,"ensureLensConfig"),a(ensureLensConfig,"ensureLensConfig");function i(n){try{return JSON.parse(l(n,"utf8"))}catch{return}}s(i,"c"),t(i,"a"),a(i,"readJson");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lensmcp",
|
|
3
|
-
"version": "1.23.
|
|
3
|
+
"version": "1.23.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@frontmcp/sdk": "^1.8.5",
|
|
21
|
-
"@lensmcp/cluster": "1.23.
|
|
22
|
-
"@lensmcp/nx-plugin": "1.23.
|
|
21
|
+
"@lensmcp/cluster": "1.23.4",
|
|
22
|
+
"@lensmcp/nx-plugin": "1.23.4",
|
|
23
23
|
"reflect-metadata": "^0.2.2",
|
|
24
24
|
"tslib": "^2.3.0",
|
|
25
25
|
"vectoriadb": "^2.2.0"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "lensmcp",
|
|
3
3
|
"displayName": "LensMCP",
|
|
4
4
|
"description": "The observability lens for coding agents. One command brings up the dev cluster gateway (every project.json `cluster` decl → its host on :443), the per-project lens dashboard at https://lensmcp.local/<project>/, and the MCP server your agent connects to — scoped automatically to whatever project you opened Claude Code in.",
|
|
5
|
-
"version": "1.23.
|
|
5
|
+
"version": "1.23.4",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "David Antoon",
|
|
8
8
|
"email": "davidmantoon@gmail.com"
|