lensmcp 1.25.17 → 1.25.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/bin.js +1 -1
  2. package/bundled/bridge.js +38 -37
  3. package/bundled/capture-runner.js +6 -6
  4. package/bundled/dashboard-ui/app.css +1 -1
  5. package/bundled/dashboard-ui/app.js +92 -92
  6. package/bundled/dashboard-ui/chunks/ReplayView-vO4p7cGp.js +131 -0
  7. package/bundled/dashboard.js +288 -279
  8. package/bundled/main.js +228 -221
  9. package/bundled/shim.js +8 -8
  10. package/lib/agent-asked.js +4 -4
  11. package/lib/agent-plugins.js +2 -2
  12. package/lib/bridge-origins.js +1 -1
  13. package/lib/call-command.js +2 -2
  14. package/lib/cli-help.js +3 -3
  15. package/lib/cli.js +12 -12
  16. package/lib/dashboard-login.d.ts +9 -2
  17. package/lib/dashboard-login.js +3 -3
  18. package/lib/dismiss-command.js +2 -2
  19. package/lib/duplicate-registration.js +1 -1
  20. package/lib/forward-signals.js +1 -1
  21. package/lib/gateway-registration.js +1 -1
  22. package/lib/guest-graph.js +4 -4
  23. package/lib/heap-analyzer-main.js +1 -1
  24. package/lib/heap-analyzer.js +1 -1
  25. package/lib/hook-memory.js +1 -1
  26. package/lib/instance-command.js +9 -9
  27. package/lib/instance-registry.js +2 -2
  28. package/lib/instance-resources.js +5 -5
  29. package/lib/instance-worktree.js +6 -6
  30. package/lib/lens-ignore.js +2 -2
  31. package/lib/lint-args.js +1 -1
  32. package/lib/logs-follow.js +1 -1
  33. package/lib/mcp-mode.js +3 -3
  34. package/lib/mcp-restart.js +1 -1
  35. package/lib/mcp-sessions.js +2 -2
  36. package/lib/mcp-token.js +3 -3
  37. package/lib/mcp-wiring.js +2 -2
  38. package/lib/mem-command.js +3 -3
  39. package/lib/perf-rules-check.js +4 -4
  40. package/lib/plugin-version.js +3 -3
  41. package/lib/pod-source-maps.js +1 -1
  42. package/lib/process-identity.js +1 -1
  43. package/lib/process-ownership.js +2 -2
  44. package/lib/project-files.js +1 -1
  45. package/lib/recycle-policy.js +1 -1
  46. package/lib/resp-client.js +5 -5
  47. package/lib/restart-command.js +2 -2
  48. package/lib/server-bundle.js +2 -2
  49. package/lib/status-client.js +2 -2
  50. package/lib/status-policy.js +2 -2
  51. package/lib/sweep.js +1 -1
  52. package/lib/upgrade.js +2 -2
  53. package/lib/workspace-scope.js +2 -2
  54. package/package.json +4 -4
  55. package/plugin/.claude-plugin/plugin.json +1 -1
  56. package/plugin/skills/dashboard/SKILL.md +2 -1
  57. package/plugin/skills/using-lensmcp/SKILL.md +28 -1
  58. package/plugin/skills/worktrees/SKILL.md +2 -1
  59. package/plugins/lensmcp/.codex-plugin/plugin.json +1 -1
  60. package/plugins/lensmcp/skills/lensmcp-dashboard/SKILL.md +2 -1
  61. package/plugins/lensmcp/skills/using-lensmcp/SKILL.md +27 -1
@@ -1 +1 @@
1
- "use strict";var a=Object.defineProperty;var o=(e,r)=>a(e,"name",{value:r,configurable:!0});var l=Object.defineProperty,i=o((e,r)=>l(e,"name",{value:r,configurable:!0}),"o"),d=Object.defineProperty,p=i((e,r)=>d(e,"name",{value:r,configurable:!0}),"n");import{portListeners as u,proveOwnServer as c}from"./process-ownership.js";export function planMcpRestart(e){const r=e.identity;if(!r)return{kill:!1,reason:"no shared MCP server answered \u2014 the next session starts one on the new bundle"};if(!r.root||r.root!==e.expectedRoot)return{kill:!1,reason:`the server on this port serves ${r.root?`'${r.root}'`:"an unknown workspace"}, not ${e.expectedRoot} \u2014 left alone`};if(e.expectedKey&&r.key&&r.key!==e.expectedKey)return{kill:!1,reason:`the server on this port serves workspace '${r.key}', not '${e.expectedKey}' \u2014 left alone`};if(typeof r.pid!="number"||!Number.isInteger(r.pid)||r.pid<=1)return{kill:!1,reason:"the shared MCP server did not report a usable pid \u2014 cannot restart it safely"};if(e.selfPid!==void 0&&r.pid===e.selfPid)return{kill:!1,reason:"the reported pid is this process \u2014 refusing to signal ourselves"};const s=e.stopFor??(r.version===void 0?`serving a bundle older than ${e.targetVersion} (it predates the version field)`:r.version!==e.targetVersion?`serving ${r.version}, not ${e.targetVersion}`:void 0);if(!s)return{kill:!1,reason:`already serving ${e.targetVersion}`};const n=e.facts??{listeners:u(e.port),uid:process.getuid?.()},t=c({claimedPid:r.pid,listeners:n.listeners,uid:n.uid,selfPid:e.selfPid??process.pid});return!t.owned||t.pid===void 0?{kill:!1,reason:`${s}, but the process on :${e.port} is not provably this account's lensmcp server (${t.reason}) \u2014 left alone; stop it by hand: lsof -nP -iTCP:${e.port} -sTCP:LISTEN`}:{kill:!0,pid:t.pid,reason:s}}o(planMcpRestart,"planMcpRestart"),i(planMcpRestart,"planMcpRestart"),p(planMcpRestart,"planMcpRestart");
1
+ "use strict";var i=Object.defineProperty;var o=(e,r)=>i(e,"name",{value:r,configurable:!0});var a=Object.defineProperty,l=o((e,r)=>a(e,"name",{value:r,configurable:!0}),"n");import{portListeners as d,proveOwnServer as p}from"./process-ownership.js";export function planMcpRestart(e){const r=e.identity;if(!r)return{kill:!1,reason:"no shared MCP server answered \u2014 the next session starts one on the new bundle"};if(!r.root||r.root!==e.expectedRoot)return{kill:!1,reason:`the server on this port serves ${r.root?`'${r.root}'`:"an unknown workspace"}, not ${e.expectedRoot} \u2014 left alone`};if(e.expectedKey&&r.key&&r.key!==e.expectedKey)return{kill:!1,reason:`the server on this port serves workspace '${r.key}', not '${e.expectedKey}' \u2014 left alone`};if(typeof r.pid!="number"||!Number.isInteger(r.pid)||r.pid<=1)return{kill:!1,reason:"the shared MCP server did not report a usable pid \u2014 cannot restart it safely"};if(e.selfPid!==void 0&&r.pid===e.selfPid)return{kill:!1,reason:"the reported pid is this process \u2014 refusing to signal ourselves"};const s=e.stopFor??(r.version===void 0?`serving a bundle older than ${e.targetVersion} (it predates the version field)`:r.version!==e.targetVersion?`serving ${r.version}, not ${e.targetVersion}`:void 0);if(!s)return{kill:!1,reason:`already serving ${e.targetVersion}`};const n=e.facts??{listeners:d(e.port),uid:process.getuid?.()},t=p({claimedPid:r.pid,listeners:n.listeners,uid:n.uid,selfPid:e.selfPid??process.pid});return!t.owned||t.pid===void 0?{kill:!1,reason:`${s}, but the process on :${e.port} is not provably this account's lensmcp server (${t.reason}) \u2014 left alone; stop it by hand: lsof -nP -iTCP:${e.port} -sTCP:LISTEN`}:{kill:!0,pid:t.pid,reason:s}}o(planMcpRestart,"planMcpRestart"),l(planMcpRestart,"planMcpRestart");
@@ -1,2 +1,2 @@
1
- "use strict";var f=Object.defineProperty;var n=(r,e)=>f(r,"name",{value:e,configurable:!0});var S=Object.defineProperty,s=n((r,e)=>S(r,"name",{value:e,configurable:!0}),"s"),m=Object.defineProperty,o=s((r,e)=>m(r,"name",{value:e,configurable:!0}),"i");import{mkdirSync as v,readdirSync as y,readFileSync as h,unlinkSync as l,writeFileSync as g}from"node:fs";import{join as c}from"node:path";export const MCP_SESSIONS_DIR=c(".lensmcp","mcp-sessions");export function pidAlive(r){try{return process.kill(r,0),!0}catch(e){return e.code==="EPERM"}}n(pidAlive,"pidAlive"),s(pidAlive,"pidAlive"),o(pidAlive,"pidAlive");function a(r,e){return c(r,MCP_SESSIONS_DIR,`${e}.json`)}n(a,"p"),s(a,"d"),o(a,"sessionFile");function u(r){try{const e=Number(JSON.parse(h(r,"utf8")).pid);return Number.isInteger(e)&&e>1?e:void 0}catch{return}}n(u,"u"),s(u,"l"),o(u,"recordedPid");function d(r){const e=c(r,MCP_SESSIONS_DIR);let i;try{i=y(e).filter(t=>t.endsWith(".json"))}catch{return[]}return i.map(t=>({path:c(e,t),pid:u(c(e,t))}))}n(d,"a"),s(d,"u"),o(d,"sessionFiles");export function registerMcpSession(r,e=process.pid,i=pidAlive){try{v(c(r,MCP_SESSIONS_DIR),{recursive:!0,mode:448});for(const p of d(r))if(!(p.pid!==void 0&&p.pid!==e&&i(p.pid)))try{l(p.path)}catch{}const t={pid:e,startedAt:new Date().toISOString()};g(a(r,e),JSON.stringify(t)+`
2
- `,{mode:384})}catch{return()=>{}}return()=>{try{l(a(r,e))}catch{}}}n(registerMcpSession,"registerMcpSession"),s(registerMcpSession,"registerMcpSession"),o(registerMcpSession,"registerMcpSession");export function liveMcpSessions(r,e=pidAlive){return d(r).map(i=>i.pid).filter(i=>i!==void 0&&e(i)).sort((i,t)=>i-t)}n(liveMcpSessions,"liveMcpSessions"),s(liveMcpSessions,"liveMcpSessions"),o(liveMcpSessions,"liveMcpSessions");
1
+ "use strict";var f=Object.defineProperty;var s=(r,e)=>f(r,"name",{value:e,configurable:!0});var l=Object.defineProperty,n=s((r,e)=>l(r,"name",{value:e,configurable:!0}),"i");import{mkdirSync as S,readdirSync as m,readFileSync as y,unlinkSync as d,writeFileSync as v}from"node:fs";import{join as o}from"node:path";export const MCP_SESSIONS_DIR=o(".lensmcp","mcp-sessions");export function pidAlive(r){try{return process.kill(r,0),!0}catch(e){return e.code==="EPERM"}}s(pidAlive,"pidAlive"),n(pidAlive,"pidAlive");function p(r,e){return o(r,MCP_SESSIONS_DIR,`${e}.json`)}s(p,"d"),n(p,"sessionFile");function u(r){try{const e=Number(JSON.parse(y(r,"utf8")).pid);return Number.isInteger(e)&&e>1?e:void 0}catch{return}}s(u,"l"),n(u,"recordedPid");function a(r){const e=o(r,MCP_SESSIONS_DIR);let t;try{t=m(e).filter(i=>i.endsWith(".json"))}catch{return[]}return t.map(i=>({path:o(e,i),pid:u(o(e,i))}))}s(a,"u"),n(a,"sessionFiles");export function registerMcpSession(r,e=process.pid,t=pidAlive){try{S(o(r,MCP_SESSIONS_DIR),{recursive:!0,mode:448});for(const c of a(r))if(!(c.pid!==void 0&&c.pid!==e&&t(c.pid)))try{d(c.path)}catch{}const i={pid:e,startedAt:new Date().toISOString()};v(p(r,e),JSON.stringify(i)+`
2
+ `,{mode:384})}catch{return()=>{}}return()=>{try{d(p(r,e))}catch{}}}s(registerMcpSession,"registerMcpSession"),n(registerMcpSession,"registerMcpSession");export function liveMcpSessions(r,e=pidAlive){return a(r).map(t=>t.pid).filter(t=>t!==void 0&&e(t)).sort((t,i)=>t-i)}s(liveMcpSessions,"liveMcpSessions"),n(liveMcpSessions,"liveMcpSessions");
package/lib/mcp-token.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var s=Object.defineProperty;var r=(e,t)=>s(e,"name",{value:t,configurable:!0});var f=Object.defineProperty,n=r((e,t)=>f(e,"name",{value:t,configurable:!0}),"r"),d=Object.defineProperty,i=n((e,t)=>d(e,"name",{value:t,configurable:!0}),"n");import{createHmac as p,randomBytes as m,timingSafeEqual as l}from"node:crypto";import{lstatSync as y,readFileSync as P}from"node:fs";import{homedir as h}from"node:os";import{join as M}from"node:path";export function mcpTokenPath(e=process.env){return M(e.LENSMCP_HOME||h(),".lensmcp","mcp-token")}r(mcpTokenPath,"mcpTokenPath"),n(mcpTokenPath,"mcpTokenPath"),i(mcpTokenPath,"mcpTokenPath");export function readMcpToken(e=process.env){if(e.LENSMCP_ALLOW_INSECURE==="1")return;const t=e.LENSMCP_MCP_TOKEN?.trim();if(t)return t;const c=mcpTokenPath(e);try{const o=y(c);return!o.isFile()||typeof process.getuid=="function"&&o.uid!==process.getuid()?void 0:P(c,"utf8").trim()||void 0}catch{return}}r(readMcpToken,"readMcpToken"),n(readMcpToken,"readMcpToken"),i(readMcpToken,"readMcpToken");export function newProofNonce(){return m(16).toString("hex")}r(newProofNonce,"newProofNonce"),n(newProofNonce,"newProofNonce"),i(newProofNonce,"newProofNonce");export function mcpIdentityProof(e,t,c){return p("sha256",e).update(`lensmcp-mcp-identity
1
+ "use strict";var a=Object.defineProperty;var r=(e,t)=>a(e,"name",{value:t,configurable:!0});var u=Object.defineProperty,o=r((e,t)=>u(e,"name",{value:t,configurable:!0}),"n");import{createHmac as f,randomBytes as d,timingSafeEqual as p}from"node:crypto";import{lstatSync as m,readFileSync as l}from"node:fs";import{homedir as y}from"node:os";import{join as P}from"node:path";export function mcpTokenPath(e=process.env){return P(e.LENSMCP_HOME||y(),".lensmcp","mcp-token")}r(mcpTokenPath,"mcpTokenPath"),o(mcpTokenPath,"mcpTokenPath");export function readMcpToken(e=process.env){if(e.LENSMCP_ALLOW_INSECURE==="1")return;const t=e.LENSMCP_MCP_TOKEN?.trim();if(t)return t;const i=mcpTokenPath(e);try{const n=m(i);return!n.isFile()||typeof process.getuid=="function"&&n.uid!==process.getuid()?void 0:l(i,"utf8").trim()||void 0}catch{return}}r(readMcpToken,"readMcpToken"),o(readMcpToken,"readMcpToken");export function newProofNonce(){return d(16).toString("hex")}r(newProofNonce,"newProofNonce"),o(newProofNonce,"newProofNonce");export function mcpIdentityProof(e,t,i){return f("sha256",e).update(`lensmcp-mcp-identity
2
2
  ${t}
3
- ${c}`).digest("hex")}r(mcpIdentityProof,"mcpIdentityProof"),n(mcpIdentityProof,"mcpIdentityProof"),i(mcpIdentityProof,"mcpIdentityProof");export function verifyMcpIdentityProof(e,t,c,o){if(typeof o!="string")return!1;const a=Buffer.from(mcpIdentityProof(e,t,c),"utf8"),u=Buffer.from(o,"utf8");return u.length===a.length&&l(u,a)}r(verifyMcpIdentityProof,"verifyMcpIdentityProof"),n(verifyMcpIdentityProof,"verifyMcpIdentityProof"),i(verifyMcpIdentityProof,"verifyMcpIdentityProof");export function legacyMcpServerRemedy(e){return`restart it: \`lensmcp setup\`, or stop what \`lsof -nP -iTCP:${e} -sTCP:LISTEN\` names if it is yours \u2014 the next agent session starts a current one`}r(legacyMcpServerRemedy,"legacyMcpServerRemedy"),n(legacyMcpServerRemedy,"legacyMcpServerRemedy"),i(legacyMcpServerRemedy,"legacyMcpServerRemedy");export function unidentifiedVerdict(e,t=!1){return t?{}:{refused:`:${e} does not report MCP authentication (no lensmcp identity \u2014 an older server, or not one at all)`,remedy:legacyMcpServerRemedy(e)}}r(unidentifiedVerdict,"unidentifiedVerdict"),n(unidentifiedVerdict,"unidentifiedVerdict"),i(unidentifiedVerdict,"unidentifiedVerdict");export function credentialVerdict(e,t,c,o,a=!1){return e.auth!=="token"?a?{}:{refused:`:${t} predates MCP authentication (it asks for no token)`,remedy:legacyMcpServerRemedy(t)}:o?verifyMcpIdentityProof(o,t,c,e.proof)?{authorization:`Bearer ${o}`}:{refused:`:${t} could not prove it holds this account's MCP token \u2014 not sending it`}:{refused:`:${t} requires an MCP token and this account has none (~/.lensmcp/mcp-token or LENSMCP_MCP_TOKEN)`}}r(credentialVerdict,"credentialVerdict"),n(credentialVerdict,"credentialVerdict"),i(credentialVerdict,"credentialVerdict");export function curlHeaderConfig(e){return`header = "authorization: ${e.replace(/["\\]/g,"")}"
4
- `}r(curlHeaderConfig,"curlHeaderConfig"),n(curlHeaderConfig,"curlHeaderConfig"),i(curlHeaderConfig,"curlHeaderConfig");
3
+ ${i}`).digest("hex")}r(mcpIdentityProof,"mcpIdentityProof"),o(mcpIdentityProof,"mcpIdentityProof");export function verifyMcpIdentityProof(e,t,i,n){if(typeof n!="string")return!1;const c=Buffer.from(mcpIdentityProof(e,t,i),"utf8"),s=Buffer.from(n,"utf8");return s.length===c.length&&p(s,c)}r(verifyMcpIdentityProof,"verifyMcpIdentityProof"),o(verifyMcpIdentityProof,"verifyMcpIdentityProof");export function legacyMcpServerRemedy(e){return`restart it: \`lensmcp setup\`, or stop what \`lsof -nP -iTCP:${e} -sTCP:LISTEN\` names if it is yours \u2014 the next agent session starts a current one`}r(legacyMcpServerRemedy,"legacyMcpServerRemedy"),o(legacyMcpServerRemedy,"legacyMcpServerRemedy");export function unidentifiedVerdict(e,t=!1){return t?{}:{refused:`:${e} does not report MCP authentication (no lensmcp identity \u2014 an older server, or not one at all)`,remedy:legacyMcpServerRemedy(e)}}r(unidentifiedVerdict,"unidentifiedVerdict"),o(unidentifiedVerdict,"unidentifiedVerdict");export function credentialVerdict(e,t,i,n,c=!1){return e.auth!=="token"?c?{}:{refused:`:${t} predates MCP authentication (it asks for no token)`,remedy:legacyMcpServerRemedy(t)}:n?verifyMcpIdentityProof(n,t,i,e.proof)?{authorization:`Bearer ${n}`}:{refused:`:${t} could not prove it holds this account's MCP token \u2014 not sending it`}:{refused:`:${t} requires an MCP token and this account has none (~/.lensmcp/mcp-token or LENSMCP_MCP_TOKEN)`}}r(credentialVerdict,"credentialVerdict"),o(credentialVerdict,"credentialVerdict");export function curlHeaderConfig(e){return`header = "authorization: ${e.replace(/["\\]/g,"")}"
4
+ `}r(curlHeaderConfig,"curlHeaderConfig"),o(curlHeaderConfig,"curlHeaderConfig");
package/lib/mcp-wiring.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var O=Object.defineProperty;var i=(t,r)=>O(t,"name",{value:r,configurable:!0});var U=Object.defineProperty,c=i((t,r)=>U(t,"name",{value:r,configurable:!0}),"i"),j=Object.defineProperty,s=c((t,r)=>j(t,"name",{value:r,configurable:!0}),"i");import{spawnSync as g}from"node:child_process";import{existsSync as L,mkdirSync as R,readFileSync as $,writeFileSync as x}from"node:fs";import{request as N}from"node:http";import{dirname as H,join as v}from"node:path";import{applyConfigMcpMode as T,migrateUnchosenMcpPin as V,resolveMcpModeWithSource as F,sharedMcpUrl as E}from"./mcp-mode.js";import{readLensConfig as S}from"./workspace-scope.js";import{credentialVerdict as W,curlHeaderConfig as _,unidentifiedVerdict as k,newProofNonce as I,readMcpToken as J}from"./mcp-token.js";export const LENS_CONFIG=v(".lensmcp","config.json");function y(t){try{return $(t,"utf8")}catch{return}}i(y,"M"),c(y,"C"),s(y,"read");export function effectiveMcpMode(t,r,n=process.env){return resolveEffectiveMcpMode(t,r,n).mode}i(effectiveMcpMode,"effectiveMcpMode"),c(effectiveMcpMode,"effectiveMcpMode"),s(effectiveMcpMode,"effectiveMcpMode");export function resolveEffectiveMcpMode(t,r,n=process.env){return F({flag:r,env:n.LENSMCP_MCP_MODE,config:S(t).mcp?.mode})}i(resolveEffectiveMcpMode,"resolveEffectiveMcpMode"),c(resolveEffectiveMcpMode,"resolveEffectiveMcpMode"),s(resolveEffectiveMcpMode,"resolveEffectiveMcpMode");export function wireMcpMode(t,r){const n=S(t).ports.mcpHttp,e=v(t,LENS_CONFIG),o=T(y(e),r);if(o.changed){const a=H(e);L(a)||R(a,{recursive:!0}),x(e,o.json)}return{mode:r,url:E(n),port:n,wrote:o.changed}}i(wireMcpMode,"wireMcpMode"),c(wireMcpMode,"wireMcpMode"),s(wireMcpMode,"wireMcpMode");export function migrateUnchosenMcpModePin(t,r=!1){const n=v(t,LENS_CONFIG),e=y(n);if(e===void 0)return!1;const o=V(e,new Date().toISOString());if(!o.migrated)return!1;if(r)return!0;try{return x(n,o.json),!0}catch{return!1}}i(migrateUnchosenMcpModePin,"migrateUnchosenMcpModePin"),c(migrateUnchosenMcpModePin,"migrateUnchosenMcpModePin"),s(migrateUnchosenMcpModePin,"migrateUnchosenMcpModePin");export function readMcpWiring(t,r=process.env){const n=S(t).ports.mcpHttp,{mode:e,source:o}=resolveEffectiveMcpMode(t,void 0,r);return{mode:e,source:o,port:n,url:E(n)}}i(readMcpWiring,"readMcpWiring"),c(readMcpWiring,"readMcpWiring"),s(readMcpWiring,"readMcpWiring");const b=JSON.stringify({jsonrpc:"2.0",id:1,method:"initialize",params:{protocolVersion:"2025-06-18",capabilities:{},clientInfo:{name:"lensmcp-doctor",version:"1"}}});export function parseInitializeResponse(t){const r=t.split(`
2
- `).find(e=>e.startsWith("data:")),n=r?r.slice(5).trim():t.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"),c(parseInitializeResponse,"parseInitializeResponse"),s(parseInitializeResponse,"parseInitializeResponse");function h(t,r){return`${t.protocol}//${t.host}/lensmcp/identity?nonce=${r}`}i(h,"S"),c(h,"N"),s(h,"identityProbeUrl");function M(t,r,n,e){try{const o=JSON.parse(t.trim());return o.kind!=="lensmcp-mcp-identity"?k(r,f(e)):W(o,r,n,J(e),f(e))}catch{return k(r,f(e))}}i(M,"k"),c(M,"w"),s(M,"verdictFromIdentity");function f(t){return t.LENSMCP_ALLOW_INSECURE==="1"}i(f,"m"),c(f,"f"),s(f,"allowsInsecure");function P(t,r,n){const e=I(),o=g("curl",["-s","--max-time",String(r),h(t,e)],{encoding:"utf8"});return o.error||o.status!==0?{}:M(o.stdout??"",Number(t.port),e,n)}i(P,"w"),c(P,"$"),s(P,"mcpCredentialSync");export function probeSharedMcpSync(t,r=2,n=process.env){let e;try{e=new URL(t)}catch{return{ok:!1,error:`not a URL: ${t}`}}const o=P(e,r,n);if(o.refused)return{ok:!1,error:o.refused,...o.remedy?{remedy:o.remedy}:{}};const a=g("curl",["-s","--max-time",String(r),...o.authorization?["--config","-"]:[],"-X","POST",t,"-H","content-type: application/json","-H","accept: application/json, text/event-stream","-d",b],{encoding:"utf8",...o.authorization?{input:_(o.authorization)}:{}});if(a.error||a.status!==0)return{ok:!1,error:"nothing listening"};const u=(a.stdout??"").trim();return u?parseInitializeResponse(u):{ok:!1,error:"empty response"}}i(probeSharedMcpSync,"probeSharedMcpSync"),c(probeSharedMcpSync,"probeSharedMcpSync"),s(probeSharedMcpSync,"probeSharedMcpSync");export function probeIdentitySync(t,r=2){const n=g("curl",["-s","--max-time",String(r),`http://127.0.0.1:${t}/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"),c(probeIdentitySync,"probeIdentitySync"),s(probeIdentitySync,"probeIdentitySync");function C(t,r,n){const e=I();return new Promise(o=>{const a=N(h(t,e),{timeout:r},u=>{let d="";u.setEncoding("utf8"),u.on("data",m=>{d.length<64e3&&(d+=m)}),u.on("end",()=>o((u.statusCode??0)===200?M(d,Number(t.port),e,n):k(Number(t.port),f(n))))});a.on("timeout",()=>{a.destroy(),o({})}),a.on("error",()=>o({})),a.end()})}i(C,"E"),c(C,"H"),s(C,"mcpCredential");export async function probeSharedMcp(t,r=2500,n=process.env){let e;try{e=new URL(t)}catch{return{ok:!1,error:`not a URL: ${t}`}}const o=await C(e,r,n);return o.refused?{ok:!1,error:o.refused,...o.remedy?{remedy:o.remedy}:{}}:new Promise(a=>{let u=!1;const d=s(p=>{u||(u=!0,a(p))},"finish"),m=N({hostname:e.hostname,port:e.port,path:e.pathname,method:"POST",timeout:r,headers:{"content-type":"application/json",accept:"application/json, text/event-stream","content-length":Buffer.byteLength(b),...o.authorization?{authorization:o.authorization}:{}}},p=>{let l="";p.setEncoding("utf8"),p.on("data",z=>{l+=z,(l.includes('"result"')||l.length>64e3)&&p.destroy()});const w=s(()=>{if(p.statusCode===401){d({ok:!1,error:"HTTP 401 \u2014 the server requires this account's MCP token (~/.lensmcp/mcp-token)"});return}if((p.statusCode??0)>=400){d({ok:!1,error:`HTTP ${p.statusCode}`});return}d(parseInitializeResponse(l))},"settle");p.on("end",w),p.on("close",w)});m.on("timeout",()=>{m.destroy(),d({ok:!1,error:`no response within ${r}ms`})}),m.on("error",p=>{d({ok:!1,error:p.code==="ECONNREFUSED"?"nothing listening":p.message??"request failed"})}),m.end(b)})}i(probeSharedMcp,"probeSharedMcp"),c(probeSharedMcp,"probeSharedMcp"),s(probeSharedMcp,"probeSharedMcp");
1
+ "use strict";var z=Object.defineProperty;var i=(r,t)=>z(r,"name",{value:t,configurable:!0});var I=Object.defineProperty,s=i((r,t)=>I(r,"name",{value:t,configurable:!0}),"i");import{spawnSync as l}from"node:child_process";import{existsSync as L,mkdirSync as U,readFileSync as j,writeFileSync as x}from"node:fs";import{request as C}from"node:http";import{dirname as R,join as y}from"node:path";import{applyConfigMcpMode as $,migrateUnchosenMcpPin as H,resolveMcpModeWithSource as T,sharedMcpUrl as P}from"./mcp-mode.js";import{readLensConfig as h}from"./workspace-scope.js";import{credentialVerdict as V,curlHeaderConfig as _,unidentifiedVerdict as g,newProofNonce as N,readMcpToken as F}from"./mcp-token.js";export const LENS_CONFIG=y(".lensmcp","config.json");function M(r){try{return j(r,"utf8")}catch{return}}i(M,"C"),s(M,"read");export function effectiveMcpMode(r,t,n=process.env){return resolveEffectiveMcpMode(r,t,n).mode}i(effectiveMcpMode,"effectiveMcpMode"),s(effectiveMcpMode,"effectiveMcpMode");export function resolveEffectiveMcpMode(r,t,n=process.env){return T({flag:t,env:n.LENSMCP_MCP_MODE,config:h(r).mcp?.mode})}i(resolveEffectiveMcpMode,"resolveEffectiveMcpMode"),s(resolveEffectiveMcpMode,"resolveEffectiveMcpMode");export function wireMcpMode(r,t){const n=h(r).ports.mcpHttp,e=y(r,LENS_CONFIG),o=$(M(e),t);if(o.changed){const c=R(e);L(c)||U(c,{recursive:!0}),x(e,o.json)}return{mode:t,url:P(n),port:n,wrote:o.changed}}i(wireMcpMode,"wireMcpMode"),s(wireMcpMode,"wireMcpMode");export function migrateUnchosenMcpModePin(r,t=!1){const n=y(r,LENS_CONFIG),e=M(n);if(e===void 0)return!1;const o=H(e,new Date().toISOString());if(!o.migrated)return!1;if(t)return!0;try{return x(n,o.json),!0}catch{return!1}}i(migrateUnchosenMcpModePin,"migrateUnchosenMcpModePin"),s(migrateUnchosenMcpModePin,"migrateUnchosenMcpModePin");export function readMcpWiring(r,t=process.env){const n=h(r).ports.mcpHttp,{mode:e,source:o}=resolveEffectiveMcpMode(r,void 0,t);return{mode:e,source:o,port:n,url:P(n)}}i(readMcpWiring,"readMcpWiring"),s(readMcpWiring,"readMcpWiring");const v=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"),s(parseInitializeResponse,"parseInitializeResponse");function S(r,t){return`${r.protocol}//${r.host}/lensmcp/identity?nonce=${t}`}i(S,"N"),s(S,"identityProbeUrl");function k(r,t,n,e){try{const o=JSON.parse(r.trim());return o.kind!=="lensmcp-mcp-identity"?g(t,m(e)):V(o,t,n,F(e),m(e))}catch{return g(t,m(e))}}i(k,"w"),s(k,"verdictFromIdentity");function m(r){return r.LENSMCP_ALLOW_INSECURE==="1"}i(m,"f"),s(m,"allowsInsecure");function w(r,t,n){const e=N(),o=l("curl",["-s","--max-time",String(t),S(r,e)],{encoding:"utf8"});return o.error||o.status!==0?{}:k(o.stdout??"",Number(r.port),e,n)}i(w,"$"),s(w,"mcpCredentialSync");export function probeSharedMcpSync(r,t=2,n=process.env){let e;try{e=new URL(r)}catch{return{ok:!1,error:`not a URL: ${r}`}}const o=w(e,t,n);if(o.refused)return{ok:!1,error:o.refused,...o.remedy?{remedy:o.remedy}:{}};const c=l("curl",["-s","--max-time",String(t),...o.authorization?["--config","-"]:[],"-X","POST",r,"-H","content-type: application/json","-H","accept: application/json, text/event-stream","-d",v],{encoding:"utf8",...o.authorization?{input:_(o.authorization)}:{}});if(c.error||c.status!==0)return{ok:!1,error:"nothing listening"};const p=(c.stdout??"").trim();return p?parseInitializeResponse(p):{ok:!1,error:"empty response"}}i(probeSharedMcpSync,"probeSharedMcpSync"),s(probeSharedMcpSync,"probeSharedMcpSync");export function probeIdentitySync(r,t=2){const n=l("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"),s(probeIdentitySync,"probeIdentitySync");function E(r,t,n){const e=N();return new Promise(o=>{const c=C(S(r,e),{timeout:t},p=>{let u="";p.setEncoding("utf8"),p.on("data",d=>{u.length<64e3&&(u+=d)}),p.on("end",()=>o((p.statusCode??0)===200?k(u,Number(r.port),e,n):g(Number(r.port),m(n))))});c.on("timeout",()=>{c.destroy(),o({})}),c.on("error",()=>o({})),c.end()})}i(E,"H"),s(E,"mcpCredential");export async function probeSharedMcp(r,t=2500,n=process.env){let e;try{e=new URL(r)}catch{return{ok:!1,error:`not a URL: ${r}`}}const o=await E(e,t,n);return o.refused?{ok:!1,error:o.refused,...o.remedy?{remedy:o.remedy}:{}}:new Promise(c=>{let p=!1;const u=s(a=>{p||(p=!0,c(a))},"finish"),d=C({hostname:e.hostname,port:e.port,path:e.pathname,method:"POST",timeout:t,headers:{"content-type":"application/json",accept:"application/json, text/event-stream","content-length":Buffer.byteLength(v),...o.authorization?{authorization:o.authorization}:{}}},a=>{let f="";a.setEncoding("utf8"),a.on("data",O=>{f+=O,(f.includes('"result"')||f.length>64e3)&&a.destroy()});const b=s(()=>{if(a.statusCode===401){u({ok:!1,error:"HTTP 401 \u2014 the server requires this account's MCP token (~/.lensmcp/mcp-token)"});return}if((a.statusCode??0)>=400){u({ok:!1,error:`HTTP ${a.statusCode}`});return}u(parseInitializeResponse(f))},"settle");a.on("end",b),a.on("close",b)});d.on("timeout",()=>{d.destroy(),u({ok:!1,error:`no response within ${t}ms`})}),d.on("error",a=>{u({ok:!1,error:a.code==="ECONNREFUSED"?"nothing listening":a.message??"request failed"})}),d.end(v)})}i(probeSharedMcp,"probeSharedMcp"),s(probeSharedMcp,"probeSharedMcp");
@@ -1,3 +1,3 @@
1
- "use strict";var k=Object.defineProperty;var m=(s,r)=>k(s,"name",{value:r,configurable:!0});var E=Object.defineProperty,v=m((s,r)=>E(s,"name",{value:r,configurable:!0}),"m"),j=Object.defineProperty,c=v((s,r)=>j(s,"name",{value:r,configurable:!0}),"p");import{spawn as P}from"node:child_process";import{readFileSync as z}from"node:fs";import{request as O}from"node:http";import{renderHeapAnalysis as B}from"./heap-analyzer.js";export const MEM_USAGE="Usage: lensmcp mem [<service>] [--snapshot [--pod <id>] [--max-mb <n>] [--analyze]] [--file <snapshot> --analyze] [--top <n>] [--all] [--json] [--cwd <dir>]";export function socketOwnerGone(s){try{const r=Number(z(`${s}.owner`,"utf8").trim());return!Number.isInteger(r)||r<=0||process.kill(r,0),!1}catch(r){return r.code==="ESRCH"}}m(socketOwnerGone,"socketOwnerGone"),v(socketOwnerGone,"socketOwnerGone"),c(socketOwnerGone,"socketOwnerGone");export function socketRequest(s,r,t,o=1e4){return new Promise(n=>{const e=O({socketPath:s,path:t,method:r},a=>{let l="";a.on("data",i=>l+=i),a.on("end",()=>n({status:a.statusCode??0,body:l})),a.on("error",()=>n(null))});e.setTimeout(o,()=>e.destroy()),e.on("error",()=>n(null)),e.end()})}m(socketRequest,"socketRequest"),v(socketRequest,"socketRequest"),c(socketRequest,"socketRequest");export async function readServiceMemory(s){const r=await socketRequest(s.sock,"GET","/webpack/memory");if(!r)return{service:s.service,wsKey:s.wsKey,error:"no answer \u2014 the devserver may have crashed leaving a stale socket"};if(r.status===404)return{service:s.service,wsKey:s.wsKey,error:"its devserver predates pod memory reports \u2014 restart the service"};try{return{service:s.service,wsKey:s.wsKey,memory:JSON.parse(r.body)}}catch{return{service:s.service,wsKey:s.wsKey,error:`unexpected answer: ${r.body.slice(0,120)}`}}}m(readServiceMemory,"readServiceMemory"),v(readServiceMemory,"readServiceMemory"),c(readServiceMemory,"readServiceMemory");const M=1024*1024,d=c(s=>s===void 0?"\u2014":s>=1024*M?`${(s/(1024*M)).toFixed(1)} GB`:`${Math.round(s/M)} MB`,"mb"),S=c((s,r)=>{const t=Math.max(0,Math.round((r-s)/1e3));return t<90?`${t}s ago`:t<5400?`${Math.round(t/60)}m ago`:`${Math.round(t/3600)}h ago`},"ago"),b=c(s=>s.wsKey?`${s.wsKey}/${s.service}`:s.service,"name");export function renderMemTable(s,r=Date.now()){const t=[["SERVICE","POD","PID","LIVE","RESERVED","RSS","BASELINE","SWAPS","RETAINED","LAST REPORT"]],o=[];for(const a of s){if(!a.memory){o.push(` ${b(a)}: ${a.error??"no answer"}`);continue}for(const l of a.memory.pods){const i=l.latest;t.push([b(a),`#${l.id}${l.retiring?" (retiring)":""}`,String(l.pid),d(i?.live),d(i?.reserved),d(i?.rss),d(i?.baseline??(i?.trigger==="boot"?i.live:void 0)),i?String(i.swaps):"\u2014",l.retained.length?l.retained.map(f=>`gen ${f.gen}`).join(", "):"\u2014",i?`${i.trigger} \xB7 ${S(i.at,r)}`:"none yet"])}}const n=t[0].map((a,l)=>Math.max(...t.map(i=>i[l].length))),e=t.map(a=>` ${a.map((l,i)=>l.padEnd(n[i])).join(" ")}`.trimEnd());return[...t.length>1?e:[" (no pods reporting)"],...o]}m(renderMemTable,"renderMemTable"),v(renderMemTable,"renderMemTable"),c(renderMemTable,"renderMemTable");export function renderMemDetail(s,r=Date.now()){if(!s.memory)return[`${b(s)}: ${s.error??"no answer"}`];const t=[`${b(s)} (${s.memory.project}) \u2014 bundle ${s.memory.bundle.path}`];for(const o of s.memory.pods){const n=o.latest;if(t.push(""),t.push(`pod #${o.id} pid ${o.pid}${o.retiring?" (retiring)":""}${o.healthy?"":" (not serving)"}`),!n){t.push(" no report yet");continue}t.push(` ${d(n.live)} live after a full GC \xB7 ${d(n.reserved)} reserved \xB7 rss ${d(n.rss)} \xB7 external ${d(n.external)} \xB7 young generation ${d(n.youngGen)} \xB7 limit ${d(n.limit)}`),t.push(` generation ${n.gen} after ${n.swaps} swap${n.swaps===1?"":"s"}`+(n.baseline?` \xB7 boot baseline ${d(n.baseline)} (${(n.live/n.baseline).toFixed(1)}\xD7)`:"")+(n.containers!==void 0?` \xB7 ${n.containers} Nest container${n.containers===1?"":"s"}`:"")+` \xB7 source maps ${n.sourceMaps?"on":"off"}`),t.push(" history:");for(const e of o.history.slice(-8)){const a=e.previousAlive===!1?`gen ${e.previousGen} freed`:e.previousAlive?`gen ${e.previousGen} still in memory`:"";t.push(` ${S(e.at,r).padEnd(8)} ${e.trigger.padEnd(16)} live ${d(e.live).padStart(7)} before GC ${d(e.used).padStart(7)} GC ${e.gcMs} ms ${a}`.trimEnd())}for(const e of o.retained){const a=e.counts?` \u2014 live: ${Object.entries(e.counts).map(([l,i])=>`${l} ${i}`).join(", ")}`:"";t.push(` RETAINED: generation ${e.gen}, closed ${S(e.closedAt,r)}, survived ${e.gcs} full GCs (still alive: ${e.alive.join(", ")})${a}`)}}return s.memory.pods.some(o=>o.retained.length)&&(t.push(""),t.push(`See what keeps it: lensmcp mem ${s.service} --snapshot --analyze`)),t}m(renderMemDetail,"renderMemDetail"),v(renderMemDetail,"renderMemDetail"),c(renderMemDetail,"renderMemDetail");function C(s){const r={json:!1,snapshot:!1,analyze:!1,all:!1};for(let t=0;t<s.length;t++){const o=s[t],n=c(()=>{const a=o.indexOf("=");if(a>=0)return o.slice(a+1);const l=s[t+1];if(!(l===void 0||l.startsWith("--")))return t++,l},"value"),e=o.startsWith("--")?o.split("=")[0]:o;if(e==="--json")r.json=!0;else if(e==="--snapshot")r.snapshot=!0;else if(e==="--analyze")r.analyze=!0;else if(e==="--all")r.all=!0;else if(e==="--pod")r.pod=Number(n());else if(e==="--max-mb")r.maxMb=Number(n());else if(e==="--top")r.top=Number(n());else if(e==="--file")r.file=n();else if(e==="--cwd")r.cwd=n();else{if(o.startsWith("--"))return`unknown flag ${o}`;if(!r.service)r.service=o;else return`unexpected argument ${o}`}}return r.pod!==void 0&&!(Number.isInteger(r.pod)&&r.pod>0)?"--pod takes a pod id (the N of Child#N)":r.top!==void 0&&!(Number.isInteger(r.top)&&r.top>0)?"--top takes a positive number":r.maxMb!==void 0&&!(Number.isFinite(r.maxMb)&&r.maxMb>0)?"--max-mb takes a positive number of MB":r.maxMb!==void 0&&!r.snapshot?"--max-mb is for --snapshot":r.snapshot&&!r.service?"--snapshot needs a service":r.file&&!r.analyze?"--file is for --analyze":r}m(C,"C"),v(C,"j"),c(C,"parseMemArgs");export function runHeapAnalyzer(s,r,t){return new Promise(o=>{const n=[`--max-old-space-size=${t.maxMb}`,s,r,"--max-mb",String(t.maxMb),...t.top?["--top",String(t.top)]:[],...t.bundlePath?["--bundle",t.bundlePath]:[]],e=P(process.execPath,n,{stdio:["ignore","pipe","pipe"]});let a="",l="";e.stdout.on("data",i=>a+=i),e.stderr.on("data",i=>l+=i),e.on("error",i=>o({error:`could not start the analyser: ${i.message}`})),e.on("close",(i,f)=>{try{const y=JSON.parse(a.trim().split(`
2
- `).pop()??"");o(y)}catch{o({error:f||/heap out of memory|Allocation failed/i.test(l)?`the analyser ran out of its ${t.maxMb} MB \u2014 raise LENSMCP_HEAP_ANALYZE_MAX_MB`:`the analyser failed (exit ${i??f}): ${l.trim().split(`
3
- `).slice(-3).join(" ")}`})}})})}m(runHeapAnalyzer,"runHeapAnalyzer"),v(runHeapAnalyzer,"runHeapAnalyzer"),c(runHeapAnalyzer,"runHeapAnalyzer");export function analyzerCapMb(s){const r=Number(s.LENSMCP_HEAP_ANALYZE_MAX_MB);return Number.isFinite(r)&&r>=64?Math.floor(r):2048}m(analyzerCapMb,"analyzerCapMb"),v(analyzerCapMb,"analyzerCapMb"),c(analyzerCapMb,"analyzerCapMb");export async function runMemCommand(s,r,t,o,n){const e=C(s);if(typeof e=="string")return o(e),o(MEM_USAGE),{exitCode:2};const a=n.env??process.env,l=e.cwd??r;if(e.file){const u=await runHeapAnalyzer(n.analyzerScript,e.file,{maxMb:analyzerCapMb(a),...e.top?{top:e.top}:{}});return x(u,e.json,t,o)}const i=n.discover();if(!e.service){const u=e.all?void 0:n.workspaceKey(l),$=u===void 0?i:i.filter(g=>g.wsKey===u||g.wsKey==="");if($.length===0)return e.json?t(JSON.stringify({services:[]})):t(`No running services${u?` in workspace '${u}'`:""} (no devserver control sockets under $TMPDIR).${u&&i.length?" Use --all for every workspace.":""}`),{exitCode:0};const A=await Promise.all($.map(readServiceMemory));if(e.json)return t(JSON.stringify({services:A},null,2)),{exitCode:0};t(`Pod memory${u?` \u2014 workspace '${u}'`:""} (live = heap after a full GC):`);for(const g of renderMemTable(A))t(g);return t(""),t("Details: lensmcp mem <service> \xB7 what keeps a retained generation: lensmcp mem <service> --snapshot --analyze"),{exitCode:0}}const f=n.resolveService(e.service,i,l,o);if(!f)return{exitCode:1};if(!e.snapshot){const u=await readServiceMemory(f);if(e.json)t(JSON.stringify(u,null,2));else for(const $ of renderMemDetail(u))t($);return{exitCode:u.memory?0:1}}e.json||t(`Asking ${f.service} for a heap snapshot \u2014 the pod pauses while V8 writes it\u2026`);const y=new URLSearchParams;e.pod&&y.set("pod",String(e.pod)),e.maxMb!==void 0&&y.set("maxMb",String(e.maxMb));const N=y.toString(),h=await socketRequest(f.sock,"POST",`/webpack/heap${N?`?${N}`:""}`,11*6e4);if(!h)return o(`Cannot reach ${f.service} \u2014 the devserver may have crashed leaving a stale socket.`),{exitCode:1};let p;try{p=JSON.parse(h.body)}catch{return o(h.status===404?`${f.service}'s devserver predates heap snapshots \u2014 restart the service.`:`Unexpected answer: ${h.body.slice(0,200)}`),{exitCode:1}}if(!p.ok||!p.file)return e.json?t(JSON.stringify({snapshot:p},null,2)):o(`No snapshot: ${p.refused??p.error??`HTTP ${h.status}`}`),{exitCode:1};if(e.json||(t(`Wrote ${d(p.bytes)} in ${((p.ms??0)/1e3).toFixed(1)}s from pod #${p.pod}: ${p.file}`),p.closedAlive?.length&&t(` closed generation(s) still in memory when it was taken: ${p.closedAlive.join(", ")}`)),!e.analyze)return e.json?t(JSON.stringify({snapshot:p},null,2)):t(`Analyse it: lensmcp mem --file ${p.file} --analyze (or open it in Chrome DevTools \u2192 Memory)`),{exitCode:0};const w=await runHeapAnalyzer(n.analyzerScript,p.file,{maxMb:analyzerCapMb(a),...e.top?{top:e.top}:{},...p.bundle?{bundlePath:p.bundle}:{}});return e.json?(t(JSON.stringify({snapshot:p,analysis:w},null,2)),{exitCode:"error"in w?1:0}):(t(""),x(w,!1,t,o))}m(runMemCommand,"runMemCommand"),v(runMemCommand,"runMemCommand"),c(runMemCommand,"runMemCommand");function x(s,r,t,o){if(r)return t(JSON.stringify({analysis:s},null,2)),{exitCode:"error"in s?1:0};if("error"in s)return o(`Analysis failed: ${s.error}`),{exitCode:1};for(const n of B(s))t(n);return{exitCode:0}}m(x,"M"),v(x,"S"),c(x,"printAnalysis");
1
+ "use strict";var A=Object.defineProperty;var m=(o,s)=>A(o,"name",{value:s,configurable:!0});var E=Object.defineProperty,c=m((o,s)=>E(o,"name",{value:s,configurable:!0}),"p");import{spawn as k}from"node:child_process";import{readFileSync as j}from"node:fs";import{request as P}from"node:http";import{renderHeapAnalysis as z}from"./heap-analyzer.js";export const MEM_USAGE="Usage: lensmcp mem [<service>] [--snapshot [--pod <id>] [--max-mb <n>] [--analyze]] [--file <snapshot> --analyze] [--top <n>] [--all] [--json] [--cwd <dir>]";export function socketOwnerGone(o){try{const s=Number(j(`${o}.owner`,"utf8").trim());return!Number.isInteger(s)||s<=0||process.kill(s,0),!1}catch(s){return s.code==="ESRCH"}}m(socketOwnerGone,"socketOwnerGone"),c(socketOwnerGone,"socketOwnerGone");export function socketRequest(o,s,r,n=1e4){return new Promise(t=>{const e=P({socketPath:o,path:r,method:s},a=>{let l="";a.on("data",i=>l+=i),a.on("end",()=>t({status:a.statusCode??0,body:l})),a.on("error",()=>t(null))});e.setTimeout(n,()=>e.destroy()),e.on("error",()=>t(null)),e.end()})}m(socketRequest,"socketRequest"),c(socketRequest,"socketRequest");export async function readServiceMemory(o){const s=await socketRequest(o.sock,"GET","/webpack/memory");if(!s)return{service:o.service,wsKey:o.wsKey,error:"no answer \u2014 the devserver may have crashed leaving a stale socket"};if(s.status===404)return{service:o.service,wsKey:o.wsKey,error:"its devserver predates pod memory reports \u2014 restart the service"};try{return{service:o.service,wsKey:o.wsKey,memory:JSON.parse(s.body)}}catch{return{service:o.service,wsKey:o.wsKey,error:`unexpected answer: ${s.body.slice(0,120)}`}}}m(readServiceMemory,"readServiceMemory"),c(readServiceMemory,"readServiceMemory");const b=1024*1024,d=c(o=>o===void 0?"\u2014":o>=1024*b?`${(o/(1024*b)).toFixed(1)} GB`:`${Math.round(o/b)} MB`,"mb"),w=c((o,s)=>{const r=Math.max(0,Math.round((s-o)/1e3));return r<90?`${r}s ago`:r<5400?`${Math.round(r/60)}m ago`:`${Math.round(r/3600)}h ago`},"ago"),g=c(o=>o.wsKey?`${o.wsKey}/${o.service}`:o.service,"name");export function renderMemTable(o,s=Date.now()){const r=[["SERVICE","POD","PID","LIVE","RESERVED","RSS","BASELINE","SWAPS","RETAINED","LAST REPORT"]],n=[];for(const a of o){if(!a.memory){n.push(` ${g(a)}: ${a.error??"no answer"}`);continue}for(const l of a.memory.pods){const i=l.latest;r.push([g(a),`#${l.id}${l.retiring?" (retiring)":""}`,String(l.pid),d(i?.live),d(i?.reserved),d(i?.rss),d(i?.baseline??(i?.trigger==="boot"?i.live:void 0)),i?String(i.swaps):"\u2014",l.retained.length?l.retained.map(f=>`gen ${f.gen}`).join(", "):"\u2014",i?`${i.trigger} \xB7 ${w(i.at,s)}`:"none yet"])}}const t=r[0].map((a,l)=>Math.max(...r.map(i=>i[l].length))),e=r.map(a=>` ${a.map((l,i)=>l.padEnd(t[i])).join(" ")}`.trimEnd());return[...r.length>1?e:[" (no pods reporting)"],...n]}m(renderMemTable,"renderMemTable"),c(renderMemTable,"renderMemTable");export function renderMemDetail(o,s=Date.now()){if(!o.memory)return[`${g(o)}: ${o.error??"no answer"}`];const r=[`${g(o)} (${o.memory.project}) \u2014 bundle ${o.memory.bundle.path}`];for(const n of o.memory.pods){const t=n.latest;if(r.push(""),r.push(`pod #${n.id} pid ${n.pid}${n.retiring?" (retiring)":""}${n.healthy?"":" (not serving)"}`),!t){r.push(" no report yet");continue}r.push(` ${d(t.live)} live after a full GC \xB7 ${d(t.reserved)} reserved \xB7 rss ${d(t.rss)} \xB7 external ${d(t.external)} \xB7 young generation ${d(t.youngGen)} \xB7 limit ${d(t.limit)}`),r.push(` generation ${t.gen} after ${t.swaps} swap${t.swaps===1?"":"s"}`+(t.baseline?` \xB7 boot baseline ${d(t.baseline)} (${(t.live/t.baseline).toFixed(1)}\xD7)`:"")+(t.containers!==void 0?` \xB7 ${t.containers} Nest container${t.containers===1?"":"s"}`:"")+` \xB7 source maps ${t.sourceMaps?"on":"off"}`),r.push(" history:");for(const e of n.history.slice(-8)){const a=e.previousAlive===!1?`gen ${e.previousGen} freed`:e.previousAlive?`gen ${e.previousGen} still in memory`:"";r.push(` ${w(e.at,s).padEnd(8)} ${e.trigger.padEnd(16)} live ${d(e.live).padStart(7)} before GC ${d(e.used).padStart(7)} GC ${e.gcMs} ms ${a}`.trimEnd())}for(const e of n.retained){const a=e.counts?` \u2014 live: ${Object.entries(e.counts).map(([l,i])=>`${l} ${i}`).join(", ")}`:"";r.push(` RETAINED: generation ${e.gen}, closed ${w(e.closedAt,s)}, survived ${e.gcs} full GCs (still alive: ${e.alive.join(", ")})${a}`)}}return o.memory.pods.some(n=>n.retained.length)&&(r.push(""),r.push(`See what keeps it: lensmcp mem ${o.service} --snapshot --analyze`)),r}m(renderMemDetail,"renderMemDetail"),c(renderMemDetail,"renderMemDetail");function C(o){const s={json:!1,snapshot:!1,analyze:!1,all:!1};for(let r=0;r<o.length;r++){const n=o[r],t=c(()=>{const a=n.indexOf("=");if(a>=0)return n.slice(a+1);const l=o[r+1];if(!(l===void 0||l.startsWith("--")))return r++,l},"value"),e=n.startsWith("--")?n.split("=")[0]:n;if(e==="--json")s.json=!0;else if(e==="--snapshot")s.snapshot=!0;else if(e==="--analyze")s.analyze=!0;else if(e==="--all")s.all=!0;else if(e==="--pod")s.pod=Number(t());else if(e==="--max-mb")s.maxMb=Number(t());else if(e==="--top")s.top=Number(t());else if(e==="--file")s.file=t();else if(e==="--cwd")s.cwd=t();else{if(n.startsWith("--"))return`unknown flag ${n}`;if(!s.service)s.service=n;else return`unexpected argument ${n}`}}return s.pod!==void 0&&!(Number.isInteger(s.pod)&&s.pod>0)?"--pod takes a pod id (the N of Child#N)":s.top!==void 0&&!(Number.isInteger(s.top)&&s.top>0)?"--top takes a positive number":s.maxMb!==void 0&&!(Number.isFinite(s.maxMb)&&s.maxMb>0)?"--max-mb takes a positive number of MB":s.maxMb!==void 0&&!s.snapshot?"--max-mb is for --snapshot":s.snapshot&&!s.service?"--snapshot needs a service":s.file&&!s.analyze?"--file is for --analyze":s}m(C,"j"),c(C,"parseMemArgs");export function runHeapAnalyzer(o,s,r){return new Promise(n=>{const t=[`--max-old-space-size=${r.maxMb}`,o,s,"--max-mb",String(r.maxMb),...r.top?["--top",String(r.top)]:[],...r.bundlePath?["--bundle",r.bundlePath]:[]],e=k(process.execPath,t,{stdio:["ignore","pipe","pipe"]});let a="",l="";e.stdout.on("data",i=>a+=i),e.stderr.on("data",i=>l+=i),e.on("error",i=>n({error:`could not start the analyser: ${i.message}`})),e.on("close",(i,f)=>{try{const v=JSON.parse(a.trim().split(`
2
+ `).pop()??"");n(v)}catch{n({error:f||/heap out of memory|Allocation failed/i.test(l)?`the analyser ran out of its ${r.maxMb} MB \u2014 raise LENSMCP_HEAP_ANALYZE_MAX_MB`:`the analyser failed (exit ${i??f}): ${l.trim().split(`
3
+ `).slice(-3).join(" ")}`})}})})}m(runHeapAnalyzer,"runHeapAnalyzer"),c(runHeapAnalyzer,"runHeapAnalyzer");export function analyzerCapMb(o){const s=Number(o.LENSMCP_HEAP_ANALYZE_MAX_MB);return Number.isFinite(s)&&s>=64?Math.floor(s):2048}m(analyzerCapMb,"analyzerCapMb"),c(analyzerCapMb,"analyzerCapMb");export async function runMemCommand(o,s,r,n,t){const e=C(o);if(typeof e=="string")return n(e),n(MEM_USAGE),{exitCode:2};const a=t.env??process.env,l=e.cwd??s;if(e.file){const u=await runHeapAnalyzer(t.analyzerScript,e.file,{maxMb:analyzerCapMb(a),...e.top?{top:e.top}:{}});return M(u,e.json,r,n)}const i=t.discover();if(!e.service){const u=e.all?void 0:t.workspaceKey(l),y=u===void 0?i:i.filter($=>$.wsKey===u||$.wsKey==="");if(y.length===0)return e.json?r(JSON.stringify({services:[]})):r(`No running services${u?` in workspace '${u}'`:""} (no devserver control sockets under $TMPDIR).${u&&i.length?" Use --all for every workspace.":""}`),{exitCode:0};const N=await Promise.all(y.map(readServiceMemory));if(e.json)return r(JSON.stringify({services:N},null,2)),{exitCode:0};r(`Pod memory${u?` \u2014 workspace '${u}'`:""} (live = heap after a full GC):`);for(const $ of renderMemTable(N))r($);return r(""),r("Details: lensmcp mem <service> \xB7 what keeps a retained generation: lensmcp mem <service> --snapshot --analyze"),{exitCode:0}}const f=t.resolveService(e.service,i,l,n);if(!f)return{exitCode:1};if(!e.snapshot){const u=await readServiceMemory(f);if(e.json)r(JSON.stringify(u,null,2));else for(const y of renderMemDetail(u))r(y);return{exitCode:u.memory?0:1}}e.json||r(`Asking ${f.service} for a heap snapshot \u2014 the pod pauses while V8 writes it\u2026`);const v=new URLSearchParams;e.pod&&v.set("pod",String(e.pod)),e.maxMb!==void 0&&v.set("maxMb",String(e.maxMb));const S=v.toString(),h=await socketRequest(f.sock,"POST",`/webpack/heap${S?`?${S}`:""}`,11*6e4);if(!h)return n(`Cannot reach ${f.service} \u2014 the devserver may have crashed leaving a stale socket.`),{exitCode:1};let p;try{p=JSON.parse(h.body)}catch{return n(h.status===404?`${f.service}'s devserver predates heap snapshots \u2014 restart the service.`:`Unexpected answer: ${h.body.slice(0,200)}`),{exitCode:1}}if(!p.ok||!p.file)return e.json?r(JSON.stringify({snapshot:p},null,2)):n(`No snapshot: ${p.refused??p.error??`HTTP ${h.status}`}`),{exitCode:1};if(e.json||(r(`Wrote ${d(p.bytes)} in ${((p.ms??0)/1e3).toFixed(1)}s from pod #${p.pod}: ${p.file}`),p.closedAlive?.length&&r(` closed generation(s) still in memory when it was taken: ${p.closedAlive.join(", ")}`)),!e.analyze)return e.json?r(JSON.stringify({snapshot:p},null,2)):r(`Analyse it: lensmcp mem --file ${p.file} --analyze (or open it in Chrome DevTools \u2192 Memory)`),{exitCode:0};const x=await runHeapAnalyzer(t.analyzerScript,p.file,{maxMb:analyzerCapMb(a),...e.top?{top:e.top}:{},...p.bundle?{bundlePath:p.bundle}:{}});return e.json?(r(JSON.stringify({snapshot:p,analysis:x},null,2)),{exitCode:"error"in x?1:0}):(r(""),M(x,!1,r,n))}m(runMemCommand,"runMemCommand"),c(runMemCommand,"runMemCommand");function M(o,s,r,n){if(s)return r(JSON.stringify({analysis:o},null,2)),{exitCode:"error"in o?1:0};if("error"in o)return n(`Analysis failed: ${o.error}`),{exitCode:1};for(const t of z(o))r(t);return{exitCode:0}}m(M,"S"),c(M,"printAnalysis");
@@ -1,4 +1,4 @@
1
- "use strict";var m=Object.defineProperty;var c=(n,r)=>m(n,"name",{value:r,configurable:!0});var j=Object.defineProperty,u=c((n,r)=>j(n,"name",{value:r,configurable:!0}),"c"),x=Object.defineProperty,l=u((n,r)=>x(n,"name",{value:r,configurable:!0}),"c");import{closeSync as w,existsSync as h,fstatSync as S,openSync as L,readSync as A}from"node:fs";import{join as P}from"node:path";import{withLensSession as F}from"./status-client.js";const b=8*1024*1024,d=l(n=>typeof n=="object"&&n!==null&&!Array.isArray(n),"isObj"),f=l(n=>typeof n=="string"&&n?n:void 0,"text");export function asFindingLine(n){if(!d(n))return;const r=f(n.rule),t=f(n.project),i=f(n.subject),e=f(n.title);if(!r||!t||!i||!e)return;const s=Array.isArray(n.fix)?n.fix.filter(o=>typeof o=="string"):[];return{rule:r,project:t,subject:i,severity:f(n.severity)??"warning",title:e,fix:s,...f(n.verify)?{verify:f(n.verify)}:{},...f(n.docs)?{docs:f(n.docs)}:{}}}c(asFindingLine,"asFindingLine"),u(asFindingLine,"asFindingLine"),l(asFindingLine,"asFindingLine");function p(n,r){if(!h(n))return"";const t=L(n,"r");try{const i=S(t).size,e=Math.max(0,i-r),s=Buffer.alloc(i-e);A(t,s,0,s.length,e);const o=s.toString("utf8");return e>0?o.slice(o.indexOf(`
2
- `)+1):o}finally{w(t)}}c(p,"g"),u(p,"$"),l(p,"tail");export function foldPerfRuleLines(n){const r=new Map;for(const t of n){if(!t.includes('"perf-rule-'))continue;let i;try{i=JSON.parse(t)}catch{continue}const e=d(i)?i.raw:void 0;if(!d(e))continue;const s=f(e.rule),o=f(e.project);if(!s||!o)continue;if(e.kind==="perf-rule-scan"){const a=new Set(Array.isArray(e.open)?e.open.filter(g=>typeof g=="string"):[]);for(const[g,y]of r)y.rule===s&&y.project===o&&!a.has(y.subject)&&r.delete(g);continue}const v=f(e.subject);if(!v)continue;const $=`${s}\0${o}\0${v}`;if(e.kind==="perf-rule-retracted")r.delete($);else if(e.kind==="perf-rule-finding"){const a=asFindingLine(e);a&&r.set($,a)}}return[...r.values()]}c(foldPerfRuleLines,"foldPerfRuleLines"),u(foldPerfRuleLines,"foldPerfRuleLines"),l(foldPerfRuleLines,"foldPerfRuleLines");export async function readPerfFindings(n,r){const t=await F({cwd:n,env:r,budgetMs:2e3,clientName:"lensmcp-doctor"},async o=>o.read("perf://rules"));if(t.available&&d(t.value)&&Array.isArray(t.value.findings))return{source:"lens",findings:t.value.findings.map(asFindingLine).filter(o=>!!o)};const i=t.available?"the lens has no perf://rules (an older server)":t.reason,e=r.LENSMCP_EVENT_FILE||P(n,".lensmcp","events.jsonl");if(!h(e))return{source:"none",findings:[],note:i};const s=`${p(`${e}.1`,b)}
3
- ${p(e,b)}`.split(`
4
- `);return{source:"bus",findings:foldPerfRuleLines(s),note:i}}c(readPerfFindings,"readPerfFindings"),u(readPerfFindings,"readPerfFindings"),l(readPerfFindings,"readPerfFindings");export function perfRulesVerdict(n){const r=n.source==="lens"?"the running lens":n.source==="bus"?"the bus file (build rules only \u2014 the pod rules need the running lens)":"";if(n.source==="none")return{status:"pass",detail:`not checked \u2014 no running lens and no bus file${n.note?` (${n.note})`:""}`};if(n.findings.length===0)return{status:"pass",detail:`no open performance findings (from ${r})`};const t=n.findings.slice(0,3).map(s=>`${s.rule} \xB7 ${s.title}`),i=n.findings.length>t.length?` (+${n.findings.length-t.length} more)`:"",e=n.findings[0];return{status:"warn",detail:`${n.findings.length} open (from ${r}): ${t.join(" | ")}${i}`,hint:`${e.rule} \u2014 ${e.fix[0]??"see its fix steps"}${e.verify?` Verify: ${e.verify}`:""} Every finding's steps: perf://rules (or observe_current_status)${e.docs?`; why and how to prevent it: ${e.docs}`:""}.`}}c(perfRulesVerdict,"perfRulesVerdict"),u(perfRulesVerdict,"perfRulesVerdict"),l(perfRulesVerdict,"perfRulesVerdict");
1
+ "use strict";var b=Object.defineProperty;var c=(e,t)=>b(e,"name",{value:t,configurable:!0});var m=Object.defineProperty,u=c((e,t)=>m(e,"name",{value:t,configurable:!0}),"c");import{closeSync as j,existsSync as $,fstatSync as x,openSync as w,readSync as S}from"node:fs";import{join as A}from"node:path";import{withLensSession as L}from"./status-client.js";const h=8*1024*1024,a=u(e=>typeof e=="object"&&e!==null&&!Array.isArray(e),"isObj"),f=u(e=>typeof e=="string"&&e?e:void 0,"text");export function asFindingLine(e){if(!a(e))return;const t=f(e.rule),r=f(e.project),i=f(e.subject),n=f(e.title);if(!t||!r||!i||!n)return;const s=Array.isArray(e.fix)?e.fix.filter(o=>typeof o=="string"):[];return{rule:t,project:r,subject:i,severity:f(e.severity)??"warning",title:n,fix:s,...f(e.verify)?{verify:f(e.verify)}:{},...f(e.docs)?{docs:f(e.docs)}:{}}}c(asFindingLine,"asFindingLine"),u(asFindingLine,"asFindingLine");function g(e,t){if(!$(e))return"";const r=w(e,"r");try{const i=x(r).size,n=Math.max(0,i-t),s=Buffer.alloc(i-n);S(r,s,0,s.length,n);const o=s.toString("utf8");return n>0?o.slice(o.indexOf(`
2
+ `)+1):o}finally{j(r)}}c(g,"$"),u(g,"tail");export function foldPerfRuleLines(e){const t=new Map;for(const r of e){if(!r.includes('"perf-rule-'))continue;let i;try{i=JSON.parse(r)}catch{continue}const n=a(i)?i.raw:void 0;if(!a(n))continue;const s=f(n.rule),o=f(n.project);if(!s||!o)continue;if(n.kind==="perf-rule-scan"){const l=new Set(Array.isArray(n.open)?n.open.filter(d=>typeof d=="string"):[]);for(const[d,p]of t)p.rule===s&&p.project===o&&!l.has(p.subject)&&t.delete(d);continue}const y=f(n.subject);if(!y)continue;const v=`${s}\0${o}\0${y}`;if(n.kind==="perf-rule-retracted")t.delete(v);else if(n.kind==="perf-rule-finding"){const l=asFindingLine(n);l&&t.set(v,l)}}return[...t.values()]}c(foldPerfRuleLines,"foldPerfRuleLines"),u(foldPerfRuleLines,"foldPerfRuleLines");export async function readPerfFindings(e,t){const r=await L({cwd:e,env:t,budgetMs:2e3,clientName:"lensmcp-doctor"},async o=>o.read("perf://rules"));if(r.available&&a(r.value)&&Array.isArray(r.value.findings))return{source:"lens",findings:r.value.findings.map(asFindingLine).filter(o=>!!o)};const i=r.available?"the lens has no perf://rules (an older server)":r.reason,n=t.LENSMCP_EVENT_FILE||A(e,".lensmcp","events.jsonl");if(!$(n))return{source:"none",findings:[],note:i};const s=`${g(`${n}.1`,h)}
3
+ ${g(n,h)}`.split(`
4
+ `);return{source:"bus",findings:foldPerfRuleLines(s),note:i}}c(readPerfFindings,"readPerfFindings"),u(readPerfFindings,"readPerfFindings");export function perfRulesVerdict(e){const t=e.source==="lens"?"the running lens":e.source==="bus"?"the bus file (build rules only \u2014 the pod rules need the running lens)":"";if(e.source==="none")return{status:"pass",detail:`not checked \u2014 no running lens and no bus file${e.note?` (${e.note})`:""}`};if(e.findings.length===0)return{status:"pass",detail:`no open performance findings (from ${t})`};const r=e.findings.slice(0,3).map(s=>`${s.rule} \xB7 ${s.title}`),i=e.findings.length>r.length?` (+${e.findings.length-r.length} more)`:"",n=e.findings[0];return{status:"warn",detail:`${e.findings.length} open (from ${t}): ${r.join(" | ")}${i}`,hint:`${n.rule} \u2014 ${n.fix[0]??"see its fix steps"}${n.verify?` Verify: ${n.verify}`:""} Every finding's steps: perf://rules (or observe_current_status)${n.docs?`; why and how to prevent it: ${n.docs}`:""}.`}}c(perfRulesVerdict,"perfRulesVerdict"),u(perfRulesVerdict,"perfRulesVerdict");
@@ -1,3 +1,3 @@
1
- "use strict";var j=Object.defineProperty;var s=(e,n)=>j(e,"name",{value:n,configurable:!0});var x=Object.defineProperty,u=s((e,n)=>x(e,"name",{value:n,configurable:!0}),"c"),k=Object.defineProperty,i=u((e,n)=>k(e,"name",{value:n,configurable:!0}),"r");import{spawnSync as v}from"node:child_process";import{existsSync as P,readFileSync as w}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(w(e,"utf8"))}catch{return}}s(g,"d"),u(g,"f"),i(g,"readJson");function m(e){const n=g(e)?.version;return typeof n=="string"&&n.length>0?n:void 0}s(m,"g"),u(m,"g"),i(m,"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"),u(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[c,a]=t.split("@");if(!(c!==PLUGIN_NAME||!a))for(const p of Array.isArray(r)?r:[r]){if(typeof p!="object"||p===null)continue;const l=p;typeof l.version=="string"&&o.push({id:t,marketplace:a,version:l.version,...typeof l.scope=="string"?{scope:l.scope}:{},...typeof l.projectPath=="string"?{projectPath:l.projectPath}:{}})}}return o}s(readInstalledPlugins,"readInstalledPlugins"),u(readInstalledPlugins,"readInstalledPlugins"),i(readInstalledPlugins,"readInstalledPlugins");export function readVersions(e){const n={};if(e.pluginRoot){const r=m(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=m(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"),u(readVersions,"readVersions"),i(readVersions,"readVersions");export function compareVersions(e,n){const o=i(c=>{const a=c.trim().replace(/^v/,"").split(/[-+]/)[0];if(a===void 0)return;const p=a.split(".");if(p.length===0||p.length>3)return;const l=p.map(f=>/^\d+$/.test(f)?Number(f):Number.NaN);return l.some(Number.isNaN)?void 0:[l[0]??0,l[1]??0,l[2]??0]},"parse"),t=o(e),r=o(n);if(!(!t||!r)){for(let c=0;c<3;c++){const a=(t[c]??0)-(r[c]??0);if(a!==0)return a<0?-1:1}return 0}}s(compareVersions,"compareVersions"),u(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"),u(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"),u(updateCommands,"updateCommands"),i(updateCommands,"updateCommands");export function formatSkewContext(e){const n=e.expectedSource==="project"?"this project\u2019s node_modules":"the running CLI";if(e.direction==="ahead")return`LensMCP plugin ${e.plugin} is newer than lensmcp ${e.expected} (${n}) \u2014 a newer lensmcp in another workspace installed it. Its skills may name tools this lens does not have yet: \`lensmcp upgrade\` brings this project up to it.`;const o=[`LensMCP plugin is out of step: plugin ${e.plugin} vs lensmcp ${e.expected} (${n}). The plugin\u2019s skills, hooks and wiring are from ${e.plugin} \u2014 update before relying on them:`,...updateCommands(e).map(t=>` ${t}`)," \u2026then restart Claude Code for the new plugin to load."];return e.cliSkew&&o.push(` (also: the lensmcp CLI on PATH is ${e.cliSkew.cli} while this project depends on ${e.cliSkew.project}.)`),o.join(`
2
- `)}s(formatSkewContext,"formatSkewContext"),u(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}:{}};if(n.direction==="ahead")return{outcome:"ahead",from:n.plugin,to:n.expected};const o=updateCommands(n);for(const r of o){const[c,...a]=r.split(" "),p=c===void 0?void 0:e.run(c,a);if(!p)return{outcome:"manual",from:n.plugin,to:n.expected,commands:o,detail:`\`${c??"claude"}\` is not on PATH`};if(p.code!==0)return{outcome:"manual",from:n.plugin,to:n.expected,commands:o,detail:(p.stderr??"").trim().split(`
3
- `)[0]||`\`${r}\` exited ${p.code}`}}const t=e.installed?.();return t!==void 0&&t===n.plugin?{outcome:"manual",from:n.plugin,to:n.expected,commands:o,detail:`\`claude plugin update\` left it at ${t} \u2014 its marketplace offers no ${n.expected}`}:{outcome:"updated",from:n.plugin,to:t??n.expected,commands:o}}s(syncPlugin,"syncPlugin"),u(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"),u(spawnRunner,"spawnRunner"),i(spawnRunner,"spawnRunner");export const pluginManifestPath=i(e=>d(e,".claude-plugin","plugin.json"),"pluginManifestPath"),isPluginRoot=i(e=>P(pluginManifestPath(e)),"isPluginRoot");
1
+ "use strict";var h=Object.defineProperty;var c=(t,e)=>h(t,"name",{value:e,configurable:!0});var j=Object.defineProperty,r=c((t,e)=>j(t,"name",{value:e,configurable:!0}),"r");import{spawnSync as x}from"node:child_process";import{existsSync as k,readFileSync as v}from"node:fs";import{homedir as m}from"node:os";import{join as a}from"node:path";export const PLUGIN_NAME="lensmcp";function d(t){try{return JSON.parse(v(t,"utf8"))}catch{return}}c(d,"f"),r(d,"readJson");function g(t){const e=d(t)?.version;return typeof e=="string"&&e.length>0?e:void 0}c(g,"g"),r(g,"readVersionField");export function readInstalledPlugin(t,e=m()){const n=readInstalledPlugins(e);if(n.length!==0)return n.find(o=>o.projectPath===t)??n.find(o=>o.scope==="user")??n[0]}c(readInstalledPlugin,"readInstalledPlugin"),r(readInstalledPlugin,"readInstalledPlugin");export function readInstalledPlugins(t=m()){const e=d(a(t,".claude","plugins","installed_plugins.json"))?.plugins;if(!e||typeof e!="object")return[];const n=[];for(const[o,i]of Object.entries(e)){const[s,l]=o.split("@");if(!(s!==PLUGIN_NAME||!l))for(const p of Array.isArray(i)?i:[i]){if(typeof p!="object"||p===null)continue;const u=p;typeof u.version=="string"&&n.push({id:o,marketplace:l,version:u.version,...typeof u.scope=="string"?{scope:u.scope}:{},...typeof u.projectPath=="string"?{projectPath:u.projectPath}:{}})}}return n}c(readInstalledPlugins,"readInstalledPlugins"),r(readInstalledPlugins,"readInstalledPlugins");export function readVersions(t){const e={};if(t.pluginRoot){const i=g(a(t.pluginRoot,".claude-plugin","plugin.json"));i&&(e.plugin=i,e.pluginSource="plugin-root")}const n=readInstalledPlugin(t.cwd,t.home);n&&(e.pluginId=n.id,e.pluginMarketplace=n.marketplace,n.scope&&(e.pluginScope=n.scope),e.plugin||(e.plugin=n.version,e.pluginSource="install-index"));const o=g(a(t.cwd,"node_modules","lensmcp","package.json"));return o&&(e.project=o),t.cliVersion&&t.cliVersion!=="0.0.0"&&(e.cli=t.cliVersion),e}c(readVersions,"readVersions"),r(readVersions,"readVersions");export function compareVersions(t,e){const n=r(s=>{const l=s.trim().replace(/^v/,"").split(/[-+]/)[0];if(l===void 0)return;const p=l.split(".");if(p.length===0||p.length>3)return;const u=p.map(f=>/^\d+$/.test(f)?Number(f):Number.NaN);return u.some(Number.isNaN)?void 0:[u[0]??0,u[1]??0,u[2]??0]},"parse"),o=n(t),i=n(e);if(!(!o||!i)){for(let s=0;s<3;s++){const l=(o[s]??0)-(i[s]??0);if(l!==0)return l<0?-1:1}return 0}}c(compareVersions,"compareVersions"),r(compareVersions,"compareVersions");export function detectSkew(t){const e=t.plugin,n=t.project??t.cli;if(!e||!n||e===n)return;const o=compareVersions(e,n);if(o===void 0||o===0)return;const i=t.cli&&t.project&&t.cli!==t.project?{cli:t.cli,project:t.project}:void 0;return{mismatch:!0,plugin:e,expected:n,expectedSource:t.project?"project":"cli",direction:o<0?"behind":"ahead",...t.pluginId?{pluginId:t.pluginId}:{},...t.pluginMarketplace?{marketplace:t.pluginMarketplace}:{},...t.pluginScope?{scope:t.pluginScope}:{},...i?{cliSkew:i}:{}}}c(detectSkew,"detectSkew"),r(detectSkew,"detectSkew");export function updateCommands(t){const e=t.pluginId??PLUGIN_NAME,n=t.scope&&t.scope!=="user"?` --scope ${t.scope}`:"";return[...t.marketplace?[`claude plugin marketplace update ${t.marketplace}`]:[],`claude plugin update ${e}${n}`]}c(updateCommands,"updateCommands"),r(updateCommands,"updateCommands");export function formatSkewContext(t){const e=t.expectedSource==="project"?"this project\u2019s node_modules":"the running CLI";if(t.direction==="ahead")return`LensMCP plugin ${t.plugin} is newer than lensmcp ${t.expected} (${e}) \u2014 a newer lensmcp in another workspace installed it. Its skills may name tools this lens does not have yet: \`lensmcp upgrade\` brings this project up to it.`;const n=[`LensMCP plugin is out of step: plugin ${t.plugin} vs lensmcp ${t.expected} (${e}). The plugin\u2019s skills, hooks and wiring are from ${t.plugin} \u2014 update before relying on them:`,...updateCommands(t).map(o=>` ${o}`)," \u2026then restart Claude Code for the new plugin to load."];return t.cliSkew&&n.push(` (also: the lensmcp CLI on PATH is ${t.cliSkew.cli} while this project depends on ${t.cliSkew.project}.)`),n.join(`
2
+ `)}c(formatSkewContext,"formatSkewContext"),r(formatSkewContext,"formatSkewContext");export function syncPlugin(t){const e=detectSkew(t.facts);if(!e)return{outcome:t.facts.plugin!==void 0&&(t.facts.project??t.facts.cli)!==void 0?"current":"unknown",...t.facts.plugin?{from:t.facts.plugin}:{}};if(e.direction==="ahead")return{outcome:"ahead",from:e.plugin,to:e.expected};const n=updateCommands(e);for(const i of n){const[s,...l]=i.split(" "),p=s===void 0?void 0:t.run(s,l);if(!p)return{outcome:"manual",from:e.plugin,to:e.expected,commands:n,detail:`\`${s??"claude"}\` is not on PATH`};if(p.code!==0)return{outcome:"manual",from:e.plugin,to:e.expected,commands:n,detail:(p.stderr??"").trim().split(`
3
+ `)[0]||`\`${i}\` exited ${p.code}`}}const o=t.installed?.();return o!==void 0&&o===e.plugin?{outcome:"manual",from:e.plugin,to:e.expected,commands:n,detail:`\`claude plugin update\` left it at ${o} \u2014 its marketplace offers no ${e.expected}`}:{outcome:"updated",from:e.plugin,to:o??e.expected,commands:n}}c(syncPlugin,"syncPlugin"),r(syncPlugin,"syncPlugin");export function spawnRunner(t,e=6e4){return(n,o)=>{try{const i=x(n,o,{encoding:"utf8",timeout:e,env:t,stdio:["ignore","pipe","pipe"]});return i.error&&i.error.code==="ENOENT"?void 0:{code:i.status??1,...i.stderr?{stderr:i.stderr}:{}}}catch{return}}}c(spawnRunner,"spawnRunner"),r(spawnRunner,"spawnRunner");export const pluginManifestPath=r(t=>a(t,".claude-plugin","plugin.json"),"pluginManifestPath"),isPluginRoot=r(t=>k(pluginManifestPath(t)),"isPluginRoot");
@@ -1 +1 @@
1
- "use strict";var M=Object.defineProperty;var c=(t,e)=>M(t,"name",{value:e,configurable:!0});var $=Object.defineProperty,i=c((t,e)=>$(t,"name",{value:e,configurable:!0}),"c"),b=Object.defineProperty,u=i((t,e)=>b(t,"name",{value:e,configurable:!0}),"i");import{createReadStream as x}from"node:fs";import{stat as w}from"node:fs/promises";import{StringDecoder as y}from"node:string_decoder";const d=Buffer.from('eval("'),f=Buffer.from("sourceMappingURL=data:application/json"),g=/[^\u0000-ÿ]/g;function h(t,e,r=0){let n=0;for(let a=t.indexOf(e,r);a>=0;a=t.indexOf(e,a+e.length))n+=1;return n}c(h,"d"),i(h,"f"),u(h,"countIn");export async function inspectBundle(t){let e;try{e=(await w(t)).size}catch{return}const r=Math.max(d.length,f.length)-1;let n=0,a=0,s=0,o=Buffer.alloc(0);const l=new y("utf8");try{for await(const v of x(t,{highWaterMark:4*1024*1024})){const m=v,p=Buffer.concat([o,m]);n+=h(p,d,Math.max(0,o.length-d.length+1)),a+=h(p,f,Math.max(0,o.length-f.length+1)),o=p.subarray(Math.max(0,p.length-r)),s+=l.write(m).match(g)?.length??0}s+=l.end().match(g)?.length??0}catch{return}return{path:t,bytes:e,evalModules:n,evalSourceMaps:n>0&&a>0,nonLatin1:s}}c(inspectBundle,"inspectBundle"),i(inspectBundle,"inspectBundle"),u(inspectBundle,"inspectBundle");export const LARGE_BUNDLE_BYTES=10*1024*1024;export function sourceMapCost(t){const e=t.bundle;if(!e||e.evalModules===0||t.sourceMaps!==!0)return;const r=e.bytes>=LARGE_BUNDLE_BYTES,n=e.nonLatin1>0;if(!r&&!n)return;const a=`${(e.bytes/(1024*1024)).toFixed(1)} MB`,s=u((o,l)=>`${o.toLocaleString()} ${l}${o===1?"":"s"}`,"n");return`${t.service}: ${a}${n?`, two-byte (${s(e.nonLatin1,"character")} past Latin-1)`:""} bundle of ${s(e.evalModules,"eval-wrapped module")}${e.evalSourceMaps?" with inline source maps":""}, run with source maps enabled`}c(sourceMapCost,"sourceMapCost"),i(sourceMapCost,"sourceMapCost"),u(sourceMapCost,"sourceMapCost");export function sourceMapVerdict(t,e=[]){const r=e.length?` (not inspected: ${e.join("; ")})`:"";if(t.length===0)return{status:"pass",detail:`not checked \u2014 no service of this workspace is running${r}`};const n=t.map(sourceMapCost).filter(a=>a!==void 0);return n.length===0?{status:"pass",detail:`${t.length} running service${t.length===1?"":"s"} inspected${r}`}:{status:"warn",detail:`each live app copy keeps its bundle as text several times \u2014 ${n.join(" \xB7 ")}${r}`,hint:"build the dev bundle without eval source maps (the serve target's `devtool`, or LENSMCP_DEV_DEVTOOL: `eval`, or an external `cheap-module-source-map`), or run the pods without --enable-source-maps \u2014 see issues pod-memory-03"}}c(sourceMapVerdict,"sourceMapVerdict"),i(sourceMapVerdict,"sourceMapVerdict"),u(sourceMapVerdict,"sourceMapVerdict");
1
+ "use strict";var v=Object.defineProperty;var c=(t,e)=>v(t,"name",{value:e,configurable:!0});var M=Object.defineProperty,i=c((t,e)=>M(t,"name",{value:e,configurable:!0}),"i");import{createReadStream as $}from"node:fs";import{stat as b}from"node:fs/promises";import{StringDecoder as x}from"node:string_decoder";const p=Buffer.from('eval("'),h=Buffer.from("sourceMappingURL=data:application/json"),m=/[^\u0000-ÿ]/g;function d(t,e,r=0){let n=0;for(let a=t.indexOf(e,r);a>=0;a=t.indexOf(e,a+e.length))n+=1;return n}c(d,"f"),i(d,"countIn");export async function inspectBundle(t){let e;try{e=(await b(t)).size}catch{return}const r=Math.max(p.length,h.length)-1;let n=0,a=0,s=0,o=Buffer.alloc(0);const u=new x("utf8");try{for await(const g of $(t,{highWaterMark:4*1024*1024})){const f=g,l=Buffer.concat([o,f]);n+=d(l,p,Math.max(0,o.length-p.length+1)),a+=d(l,h,Math.max(0,o.length-h.length+1)),o=l.subarray(Math.max(0,l.length-r)),s+=u.write(f).match(m)?.length??0}s+=u.end().match(m)?.length??0}catch{return}return{path:t,bytes:e,evalModules:n,evalSourceMaps:n>0&&a>0,nonLatin1:s}}c(inspectBundle,"inspectBundle"),i(inspectBundle,"inspectBundle");export const LARGE_BUNDLE_BYTES=10*1024*1024;export function sourceMapCost(t){const e=t.bundle;if(!e||e.evalModules===0||t.sourceMaps!==!0)return;const r=e.bytes>=LARGE_BUNDLE_BYTES,n=e.nonLatin1>0;if(!r&&!n)return;const a=`${(e.bytes/(1024*1024)).toFixed(1)} MB`,s=i((o,u)=>`${o.toLocaleString()} ${u}${o===1?"":"s"}`,"n");return`${t.service}: ${a}${n?`, two-byte (${s(e.nonLatin1,"character")} past Latin-1)`:""} bundle of ${s(e.evalModules,"eval-wrapped module")}${e.evalSourceMaps?" with inline source maps":""}, run with source maps enabled`}c(sourceMapCost,"sourceMapCost"),i(sourceMapCost,"sourceMapCost");export function sourceMapVerdict(t,e=[]){const r=e.length?` (not inspected: ${e.join("; ")})`:"";if(t.length===0)return{status:"pass",detail:`not checked \u2014 no service of this workspace is running${r}`};const n=t.map(sourceMapCost).filter(a=>a!==void 0);return n.length===0?{status:"pass",detail:`${t.length} running service${t.length===1?"":"s"} inspected${r}`}:{status:"warn",detail:`each live app copy keeps its bundle as text several times \u2014 ${n.join(" \xB7 ")}${r}`,hint:"build the dev bundle without eval source maps (the serve target's `devtool`, or LENSMCP_DEV_DEVTOOL: `eval`, or an external `cheap-module-source-map`), or run the pods without --enable-source-maps \u2014 see issues pod-memory-03"}}c(sourceMapVerdict,"sourceMapVerdict"),i(sourceMapVerdict,"sourceMapVerdict");
@@ -1 +1 @@
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");
1
+ "use strict";var u=Object.defineProperty;var i=(r,t)=>u(r,"name",{value:t,configurable:!0});var p=Object.defineProperty,s=i((r,t)=>p(r,"name",{value:t,configurable:!0}),"n");import{execFileSync as d}from"node:child_process";import{readFileSync as m,writeFileSync as f}from"node:fs";function a(r){if(!r||r<=0||process.platform==="win32")return"";try{return d("ps",["-p",String(r),"-o","lstart="],{encoding:"utf8",timeout:2e3,stdio:["ignore","pipe","ignore"]}).trim()}catch{return""}}i(a,"f"),s(a,"processStamp");const c=2;export function writeTrackedPid(r,t){const e={pid:t,stamp:a(t)||void 0};f(r,JSON.stringify(e),{mode:384})}i(writeTrackedPid,"writeTrackedPid"),s(writeTrackedPid,"writeTrackedPid");export function readTrackedPid(r){let t;try{t=m(r,"utf8").trim()}catch{return}if(!t)return;if(t.startsWith("{"))try{const n=JSON.parse(t),o=Number(n.pid);return!Number.isInteger(o)||o<c?void 0:{pid:o,stamp:typeof n.stamp=="string"&&n.stamp?n.stamp:void 0}}catch{return}if(!/^-?\d+$/.test(t))return;const e=Number(t);if(!(!Number.isInteger(e)||e<c))return{pid:e,stamp:void 0}}i(readTrackedPid,"readTrackedPid"),s(readTrackedPid,"readTrackedPid");export function stillSameProcess(r,t){if(!Number.isInteger(r)||r<c)return!1;const e=a(r);return e?t?e===t:!0:!1}i(stillSameProcess,"stillSameProcess"),s(stillSameProcess,"stillSameProcess");
@@ -1,2 +1,2 @@
1
- "use strict";var c=Object.defineProperty;var o=(t,e)=>c(t,"name",{value:e,configurable:!0});var a=Object.defineProperty,i=o((t,e)=>a(t,"name",{value:e,configurable:!0}),"r"),m=Object.defineProperty,p=i((t,e)=>m(t,"name",{value:e,configurable:!0}),"r");import{spawnSync as d}from"node:child_process";export const LENSMCP_SERVER_COMMAND=/(?:^|[\s/])(?:bundled|lensmcp-mcp\/dist)\/main\.js(?:\s|$)/;export function proveOwnServer(t){const e=t.claimedPid;if(typeof e!="number"||!Number.isInteger(e)||e<=1||e===t.selfPid)return{owned:!1,reason:"it reports no pid that could be stopped safely"};const r=[...new Set(t.listeners.map(n=>n.pid))];if(r.length!==1||r[0]!==e)return{owned:!1,reason:r.length===0?"the process holding the port could not be identified":`pid ${e} is not what holds the port`};const s=t.listeners.find(n=>n.pid===e);return t.uid===void 0||s.uid!==t.uid?{owned:!1,reason:`pid ${e} belongs to another account \u2014 never stopped from here`}:LENSMCP_SERVER_COMMAND.test(s.command)?{owned:!0,pid:e,reason:`pid ${e} is this account's lensmcp server`}:{owned:!1,reason:`pid ${e} is not a lensmcp server process`}}o(proveOwnServer,"proveOwnServer"),i(proveOwnServer,"proveOwnServer"),p(proveOwnServer,"proveOwnServer");export function parseLsofListeners(t){const e=[];let r;for(const s of t.split(`
2
- `))if(s.startsWith("p"))r=Number(s.slice(1));else if(s.startsWith("u")&&r!==void 0&&Number.isInteger(r)){const n=Number(s.slice(1));Number.isInteger(n)&&!e.some(u=>u.pid===r)&&e.push({pid:r,uid:n})}return e}o(parseLsofListeners,"parseLsofListeners"),i(parseLsofListeners,"parseLsofListeners"),p(parseLsofListeners,"parseLsofListeners");export function portListeners(t){const e=d("lsof",["-nP",`-iTCP:${t}`,"-sTCP:LISTEN","-Fpu"],{encoding:"utf8",timeout:3e3});return e.error||typeof e.stdout!="string"?[]:parseLsofListeners(e.stdout).map(r=>{const s=d("ps",["-ww","-o","command=","-p",String(r.pid)],{encoding:"utf8",timeout:3e3});return{...r,command:typeof s.stdout=="string"?s.stdout.trim():""}})}o(portListeners,"portListeners"),i(portListeners,"portListeners"),p(portListeners,"portListeners");
1
+ "use strict";var u=Object.defineProperty;var r=(t,e)=>u(t,"name",{value:e,configurable:!0});var c=Object.defineProperty,i=r((t,e)=>c(t,"name",{value:e,configurable:!0}),"r");import{spawnSync as p}from"node:child_process";export const LENSMCP_SERVER_COMMAND=/(?:^|[\s/])(?:bundled|lensmcp-mcp\/dist)\/main\.js(?:\s|$)/;export function proveOwnServer(t){const e=t.claimedPid;if(typeof e!="number"||!Number.isInteger(e)||e<=1||e===t.selfPid)return{owned:!1,reason:"it reports no pid that could be stopped safely"};const s=[...new Set(t.listeners.map(o=>o.pid))];if(s.length!==1||s[0]!==e)return{owned:!1,reason:s.length===0?"the process holding the port could not be identified":`pid ${e} is not what holds the port`};const n=t.listeners.find(o=>o.pid===e);return t.uid===void 0||n.uid!==t.uid?{owned:!1,reason:`pid ${e} belongs to another account \u2014 never stopped from here`}:LENSMCP_SERVER_COMMAND.test(n.command)?{owned:!0,pid:e,reason:`pid ${e} is this account's lensmcp server`}:{owned:!1,reason:`pid ${e} is not a lensmcp server process`}}r(proveOwnServer,"proveOwnServer"),i(proveOwnServer,"proveOwnServer");export function parseLsofListeners(t){const e=[];let s;for(const n of t.split(`
2
+ `))if(n.startsWith("p"))s=Number(n.slice(1));else if(n.startsWith("u")&&s!==void 0&&Number.isInteger(s)){const o=Number(n.slice(1));Number.isInteger(o)&&!e.some(d=>d.pid===s)&&e.push({pid:s,uid:o})}return e}r(parseLsofListeners,"parseLsofListeners"),i(parseLsofListeners,"parseLsofListeners");export function portListeners(t){const e=p("lsof",["-nP",`-iTCP:${t}`,"-sTCP:LISTEN","-Fpu"],{encoding:"utf8",timeout:3e3});return e.error||typeof e.stdout!="string"?[]:parseLsofListeners(e.stdout).map(s=>{const n=p("ps",["-ww","-o","command=","-p",String(s.pid)],{encoding:"utf8",timeout:3e3});return{...s,command:typeof n.stdout=="string"?n.stdout.trim():""}})}r(portListeners,"portListeners"),i(portListeners,"portListeners");
@@ -1 +1 @@
1
- "use strict";var F=Object.defineProperty;var o=(e,t)=>F(e,"name",{value:t,configurable:!0});var x=Object.defineProperty,l=o((e,t)=>x(e,"name",{value:t,configurable:!0}),"n"),j=Object.defineProperty,h=l((e,t)=>j(e,"name",{value:t,configurable:!0}),"d");import{spawnSync as v}from"node:child_process";import{readdirSync as P}from"node:fs";import{join as f}from"node:path";export const SKIP=new Set(["node_modules","dist","build",".git",".nx",".lensmcp","coverage","tmp",".cache",".yarn"]);export function gitListFiles(e){const t=v("git",["ls-files","-z","--cached","--others","--exclude-standard"],{cwd:e,encoding:"utf8",timeout:3e4,maxBuffer:536870912});if(!(t.status!==0||typeof t.stdout!="string"))return t.stdout.split("\0").filter(Boolean)}o(gitListFiles,"gitListFiles"),l(gitListFiles,"gitListFiles"),h(gitListFiles,"gitListFiles");export function walkProjectFiles(e,t,u=6,g=6e3,y=gitListFiles){const d=y(e);if(d){const r=new Set;for(const n of d){const s=n.split("/"),i=s[s.length-1],p=s.slice(0,-1);p.length>u||!t(i)||p.some(m=>SKIP.has(m)||m.startsWith("."))||r.add(f(e,...s))}return[...r]}const a=[],c=[{dir:e,depth:0}];let w=0;for(;c.length>0;){const{dir:r,depth:n}=c.pop();let s;try{s=P(r,{withFileTypes:!0})}catch{continue}for(const i of s){if(w++>g)return a;if(i.isDirectory()){if(SKIP.has(i.name)||i.name.startsWith("."))continue;n<u&&c.push({dir:f(r,i.name),depth:n+1})}else i.isFile()&&t(i.name)&&a.push(f(r,i.name))}}return a}o(walkProjectFiles,"walkProjectFiles"),l(walkProjectFiles,"walkProjectFiles"),h(walkProjectFiles,"walkProjectFiles");
1
+ "use strict";var w=Object.defineProperty;var n=(e,t)=>w(e,"name",{value:t,configurable:!0});var x=Object.defineProperty,m=n((e,t)=>x(e,"name",{value:t,configurable:!0}),"d");import{spawnSync as F}from"node:child_process";import{readdirSync as S}from"node:fs";import{join as l}from"node:path";export const SKIP=new Set(["node_modules","dist","build",".git",".nx",".lensmcp","coverage","tmp",".cache",".yarn"]);export function gitListFiles(e){const t=F("git",["ls-files","-z","--cached","--others","--exclude-standard"],{cwd:e,encoding:"utf8",timeout:3e4,maxBuffer:536870912});if(!(t.status!==0||typeof t.stdout!="string"))return t.stdout.split("\0").filter(Boolean)}n(gitListFiles,"gitListFiles"),m(gitListFiles,"gitListFiles");export function walkProjectFiles(e,t,d=6,h=6e3,g=gitListFiles){const f=g(e);if(f){const o=new Set;for(const r of f){const i=r.split("/"),s=i[i.length-1],u=i.slice(0,-1);u.length>d||!t(s)||u.some(p=>SKIP.has(p)||p.startsWith("."))||o.add(l(e,...i))}return[...o]}const c=[],a=[{dir:e,depth:0}];let y=0;for(;a.length>0;){const{dir:o,depth:r}=a.pop();let i;try{i=S(o,{withFileTypes:!0})}catch{continue}for(const s of i){if(y++>h)return c;if(s.isDirectory()){if(SKIP.has(s.name)||s.name.startsWith("."))continue;r<d&&a.push({dir:l(o,s.name),depth:r+1})}else s.isFile()&&t(s.name)&&c.push(l(o,s.name))}}return c}n(walkProjectFiles,"walkProjectFiles"),m(walkProjectFiles,"walkProjectFiles");
@@ -1 +1 @@
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");
1
+ "use strict";var o=Object.defineProperty;var r=(e,n)=>o(e,"name",{value:n,configurable:!0});var s=Object.defineProperty,c=r((e,n)=>s(e,"name",{value:n,configurable:!0}),"r");import{createHash as i}from"node:crypto";export function hashConfig(e){if(e!==void 0)return i("sha256").update(e).digest("hex").slice(0,12)}r(hashConfig,"hashConfig"),c(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");
@@ -1,5 +1,5 @@
1
- "use strict";var R=Object.defineProperty;var v=(e,r)=>R(e,"name",{value:r,configurable:!0});var $=Object.defineProperty,w=v((e,r)=>$(e,"name",{value:r,configurable:!0}),"v"),g=Object.defineProperty,p=w((e,r)=>g(e,"name",{value:r,configurable:!0}),"l");import*as b from"node:net";import*as C from"node:tls";export class RespError extends Error{static{v(this,"RespError")}static{w(this,"RespError")}static{p(this,"RespError")}}export function parseReply(e,r=0){if(r>=e.length)return;const o=e.indexOf(`\r
2
- `,r);if(o<0)return;const l=String.fromCharCode(e[r]??0),u=e.toString("utf8",r+1,o),t=o+2;switch(l){case"+":return{value:u,end:t};case"-":return{value:new RespError(u),end:t};case":":return{value:Number(u),end:t};case"$":{const n=Number(u);return n<0?{value:null,end:t}:e.length<t+n+2?void 0:{value:e.toString("utf8",t,t+n),end:t+n+2}}case"*":{const n=Number(u);if(n<0)return{value:null,end:t};const i=[];let d=t;for(let h=0;h<n;h++){const f=parseReply(e,d);if(!f)return;i.push(f.value),d=f.end}return{value:i,end:d}}default:throw new RespError(`unexpected reply type ${JSON.stringify(l)}`)}}v(parseReply,"parseReply"),w(parseReply,"parseReply"),p(parseReply,"parseReply");export function encodeCommand(e){const r=[`*${e.length}\r
3
- `];for(const o of e)r.push(`$${Buffer.byteLength(o)}\r
4
- ${o}\r
5
- `);return Buffer.from(r.join(""))}v(encodeCommand,"encodeCommand"),w(encodeCommand,"encodeCommand"),p(encodeCommand,"encodeCommand");export async function connectResp(e,r=5e3){const o=new URL(e);if(o.protocol!=="redis:"&&o.protocol!=="rediss:")throw new Error(`not a redis URL: ${o.protocol}`);const l=o.hostname||"127.0.0.1",u=Number(o.port||6379),t=await new Promise((a,c)=>{const s=o.protocol==="rediss:"?C.connect({host:l,port:u,servername:l}):b.connect({host:l,port:u}),m=setTimeout(()=>{s.destroy(),c(new Error(`could not reach ${l}:${u} in ${r} ms`))},r);s.once(o.protocol==="rediss:"?"secureConnect":"connect",()=>{clearTimeout(m),a(s)}),s.once("error",y=>{clearTimeout(m),c(y)})});let n=Buffer.alloc(0);const i=[],d=p(a=>{for(;i.length;)i.shift()?.reject(a)},"failAll");t.on("data",a=>{for(n=Buffer.concat([n,a]);;){let c;try{c=parseReply(n)}catch(m){d(m),t.destroy();return}if(!c)return;n=n.subarray(c.end);const s=i.shift();s&&(c.value instanceof RespError?s.reject(c.value):s.resolve(c.value))}}),t.on("error",d),t.on("close",()=>d(new Error("connection closed")));const h={command(a){return new Promise((c,s)=>{const m=setTimeout(()=>s(new Error(`no reply to ${a[0]} in ${r} ms`)),r);i.push({resolve:p(y=>{clearTimeout(m),c(y)},"resolve"),reject:p(y=>{clearTimeout(m),s(y)},"reject")}),t.write(encodeCommand(a))})},close(){t.end(),t.destroy()}},f=decodeURIComponent(o.password);if(f)try{await h.command(o.username?["AUTH",decodeURIComponent(o.username),f]:["AUTH",f])}catch(a){throw h.close(),a}return h}v(connectResp,"connectResp"),w(connectResp,"connectResp"),p(connectResp,"connectResp");
1
+ "use strict";var y=Object.defineProperty;var v=(r,o)=>y(r,"name",{value:o,configurable:!0});var $=Object.defineProperty,p=v((r,o)=>$(r,"name",{value:o,configurable:!0}),"l");import*as g from"node:net";import*as R from"node:tls";export class RespError extends Error{static{v(this,"RespError")}static{p(this,"RespError")}}export function parseReply(r,o=0){if(o>=r.length)return;const t=r.indexOf(`\r
2
+ `,o);if(t<0)return;const l=String.fromCharCode(r[o]??0),u=r.toString("utf8",o+1,t),e=t+2;switch(l){case"+":return{value:u,end:e};case"-":return{value:new RespError(u),end:e};case":":return{value:Number(u),end:e};case"$":{const n=Number(u);return n<0?{value:null,end:e}:r.length<e+n+2?void 0:{value:r.toString("utf8",e,e+n),end:e+n+2}}case"*":{const n=Number(u);if(n<0)return{value:null,end:e};const i=[];let d=e;for(let h=0;h<n;h++){const f=parseReply(r,d);if(!f)return;i.push(f.value),d=f.end}return{value:i,end:d}}default:throw new RespError(`unexpected reply type ${JSON.stringify(l)}`)}}v(parseReply,"parseReply"),p(parseReply,"parseReply");export function encodeCommand(r){const o=[`*${r.length}\r
3
+ `];for(const t of r)o.push(`$${Buffer.byteLength(t)}\r
4
+ ${t}\r
5
+ `);return Buffer.from(o.join(""))}v(encodeCommand,"encodeCommand"),p(encodeCommand,"encodeCommand");export async function connectResp(r,o=5e3){const t=new URL(r);if(t.protocol!=="redis:"&&t.protocol!=="rediss:")throw new Error(`not a redis URL: ${t.protocol}`);const l=t.hostname||"127.0.0.1",u=Number(t.port||6379),e=await new Promise((a,c)=>{const s=t.protocol==="rediss:"?R.connect({host:l,port:u,servername:l}):g.connect({host:l,port:u}),m=setTimeout(()=>{s.destroy(),c(new Error(`could not reach ${l}:${u} in ${o} ms`))},o);s.once(t.protocol==="rediss:"?"secureConnect":"connect",()=>{clearTimeout(m),a(s)}),s.once("error",w=>{clearTimeout(m),c(w)})});let n=Buffer.alloc(0);const i=[],d=p(a=>{for(;i.length;)i.shift()?.reject(a)},"failAll");e.on("data",a=>{for(n=Buffer.concat([n,a]);;){let c;try{c=parseReply(n)}catch(m){d(m),e.destroy();return}if(!c)return;n=n.subarray(c.end);const s=i.shift();s&&(c.value instanceof RespError?s.reject(c.value):s.resolve(c.value))}}),e.on("error",d),e.on("close",()=>d(new Error("connection closed")));const h={command(a){return new Promise((c,s)=>{const m=setTimeout(()=>s(new Error(`no reply to ${a[0]} in ${o} ms`)),o);i.push({resolve:p(w=>{clearTimeout(m),c(w)},"resolve"),reject:p(w=>{clearTimeout(m),s(w)},"reject")}),e.write(encodeCommand(a))})},close(){e.end(),e.destroy()}},f=decodeURIComponent(t.password);if(f)try{await h.command(t.username?["AUTH",decodeURIComponent(t.username),f]:["AUTH",f])}catch(a){throw h.close(),a}return h}v(connectResp,"connectResp"),p(connectResp,"connectResp");
@@ -1,2 +1,2 @@
1
- "use strict";var y=Object.defineProperty;var h=(e,t)=>y(e,"name",{value:t,configurable:!0});var b=Object.defineProperty,v=h((e,t)=>b(e,"name",{value:t,configurable:!0}),"h"),j=Object.defineProperty,a=v((e,t)=>j(e,"name",{value:t,configurable:!0}),"o");export const DEFAULT_WAIT_MS=3e5,RESTART_USAGE=["lensmcp restart <service> restart a service of this workspace: a new tree beside the old one, which goes once the new one answers","lensmcp restart <service> --worktree <name> \u2026 of a worktree of this project (`main`: the main checkout)","lensmcp restart <service> --workspace <key> \u2026 of any workspace the gateway serves","lensmcp restart <service> --hard stop it first, then start it (nothing serves in between)","lensmcp restart <service> --status [--wait <s>] how its latest restart went (and wait for it to settle); starts none",' --wait <seconds> (default 300) | --no-wait --reason "<why>" --json --cwd <dir>'].join(`
2
- `);export function parseRestartArgs(e){const t={hard:!1,status:!1,waitMs:3e5,json:!1};let n=!1;for(let c=0;c<e.length;c++){const r=e[c],i=a(s=>r===s?e[++c]:r.startsWith(`${s}=`)?r.slice(s.length+1):void 0,"valued"),o=a(s=>r===s||r.startsWith(`${s}=`),"named");if(r==="--hard")t.hard=!0;else if(r==="--status")t.status=!0;else if(r==="--json")t.json=!0;else if(r==="--no-wait")t.waitMs=0,n=!0;else if(o("--wait")){const s=Number(i("--wait"));if(!Number.isFinite(s)||s<0)return{error:"--wait needs a number of seconds"};t.waitMs=Math.round(s*1e3),n=!0}else if(o("--worktree")||o("--workspace")||o("--reason")||o("--cwd")){const s=r.split("=")[0],w=i(s)?.trim();if(!w)return{error:`${s} needs a value`};t[s.slice(2)]=w}else{if(r.startsWith("-"))return{error:`unknown option ${r}`};if(t.service!==void 0)return{error:`one service at a time (got '${t.service}' and '${r}')`};r.trim()&&(t.service=r.trim())}}return t.service?t.worktree&&t.workspace?{error:"--worktree or --workspace, not both"}:(t.status&&!n&&(t.waitMs=0),t):{error:"name the service \u2014 its Nx project name"}}h(parseRestartArgs,"parseRestartArgs"),v(parseRestartArgs,"parseRestartArgs"),a(parseRestartArgs,"parseRestartArgs");export function targetKey(e,t){return e.workspace?e.workspace:e.worktree?e.worktree==="main"?t.baseKey:`${t.baseKey}-${e.worktree}`:t.key}h(targetKey,"targetKey"),v(targetKey,"targetKey"),a(targetKey,"targetKey");const C=500,K={rolling:"a new tree started beside the old one, which kept serving until the new one answered",hard:"stopped, then started \u2014 nothing served in between",start:"it was down; started"},$=a(e=>`${Math.round(e/100)/10}s`,"secs");export async function runRestartCommand(e,t){const n=targetKey(e,t.here),c=n===t.here.key?"":` (${n})`,r=`${e.service}${c}`,i=a(d=>({wsKey:n,service:e.service,...d&&typeof d=="object"?d:{}}),"view"),o=a(()=>({exitCode:2,lines:["No gateway answers on the control socket \u2014 nothing is serving the services. Start it: `lensmcp gateway start`."],result:{ok:!1,wsKey:n,service:e.service,error:"no gateway answers"}}),"unavailable"),s=a((d,l)=>{const g=[`Could not restart ${r}: ${l.error??`the gateway answered ${d}`}.`];return l.services?.length&&g.push(`Its services: ${l.services.join(", ")}.`),l.workspaces?.length&&g.push(`Workspaces the gateway serves: ${l.workspaces.join(", ")}.`),{exitCode:1,lines:g,result:{ok:!1,...l}}},"refused"),w=a(()=>t.request("GET",`/restart?wsKey=${encodeURIComponent(n)}&service=${encodeURIComponent(e.service)}`),"read"),p=e.status?w():t.request("POST","/restart",{wsKey:n,service:e.service,...e.hard?{hard:!0}:{},reason:e.reason??"lensmcp restart"});if(!p)return o();let u=i(p.json);if(p.status!==(e.status?200:202))return s(p.status,u);const m=u.already===!0,k=t.now()+(u.restart?e.waitMs:0);for(;!u.restart?.done&&t.now()<k;){await t.sleep(C);const d=w();d?.status===200&&(u={...i(d.json),already:m})}return f(u,r,t.now(),e.waitMs>0)}h(runRestartCommand,"runRestartCommand"),v(runRestartCommand,"runRestartCommand"),a(runRestartCommand,"runRestartCommand");function f(e,t,n,c){const r=e.restart,i={wsKey:e.wsKey,service:e.service,state:e.state,...e.generation!==void 0?{generation:e.generation}:{},...r?{restart:r}:{},...e.already?{joined:!0}:{}};if(!r)return{exitCode:0,lines:[`${t} has not been restarted through the gateway since it started; it is ${e.state??"unknown"}.`],result:{ok:!0,...i}};const o=e.already?" (one was already under way \u2014 this is that one)":"";if(r.done?.ok)return{exitCode:0,lines:[`${t} restarted${o}: generation ${r.done.generation??"?"} serving after ${$(r.done.at-r.startedAt)} \u2014 ${K[r.how]}.`],result:{ok:!0,done:!0,...i}};if(r.done){const w=r.how==="rolling"&&/kept serving/.test(r.done.error??"");return{exitCode:1,lines:[`${t} did not restart${o}: ${r.done.error??"no reason given"} (after ${$(r.done.at-r.startedAt)}).`,w?`It still serves generation ${r.fromGeneration??"?"}. Read its log: \`lensmcp logs ${e.service}\`.`:`Read its log: \`lensmcp logs ${e.service}\`.`],result:{ok:!1,done:!0,...i}}}const s=`\`lensmcp restart ${e.service}${t!==e.service?` --workspace ${e.wsKey}`:""} --status\``;return{exitCode:c?3:0,lines:[`${t} is restarting${o} (${r.how}${r.fromGeneration!==void 0?`, from generation ${r.fromGeneration}`:""}, ${$(n-r.startedAt)} so far)${c?" \u2014 not settled within the wait":""}. See how it went: ${s}.`],result:{ok:!0,done:!1,...i}}}h(f,"g"),v(f,"g"),a(f,"settledOrNot");
1
+ "use strict";var m=Object.defineProperty;var h=(e,t)=>m(e,"name",{value:t,configurable:!0});var y=Object.defineProperty,a=h((e,t)=>y(e,"name",{value:t,configurable:!0}),"o");export const DEFAULT_WAIT_MS=3e5,RESTART_USAGE=["lensmcp restart <service> restart a service of this workspace: a new tree beside the old one, which goes once the new one answers","lensmcp restart <service> --worktree <name> \u2026 of a worktree of this project (`main`: the main checkout)","lensmcp restart <service> --workspace <key> \u2026 of any workspace the gateway serves","lensmcp restart <service> --hard stop it first, then start it (nothing serves in between)","lensmcp restart <service> --status [--wait <s>] how its latest restart went (and wait for it to settle); starts none",' --wait <seconds> (default 300) | --no-wait --reason "<why>" --json --cwd <dir>'].join(`
2
+ `);export function parseRestartArgs(e){const t={hard:!1,status:!1,waitMs:3e5,json:!1};let n=!1;for(let c=0;c<e.length;c++){const r=e[c],i=a(s=>r===s?e[++c]:r.startsWith(`${s}=`)?r.slice(s.length+1):void 0,"valued"),o=a(s=>r===s||r.startsWith(`${s}=`),"named");if(r==="--hard")t.hard=!0;else if(r==="--status")t.status=!0;else if(r==="--json")t.json=!0;else if(r==="--no-wait")t.waitMs=0,n=!0;else if(o("--wait")){const s=Number(i("--wait"));if(!Number.isFinite(s)||s<0)return{error:"--wait needs a number of seconds"};t.waitMs=Math.round(s*1e3),n=!0}else if(o("--worktree")||o("--workspace")||o("--reason")||o("--cwd")){const s=r.split("=")[0],d=i(s)?.trim();if(!d)return{error:`${s} needs a value`};t[s.slice(2)]=d}else{if(r.startsWith("-"))return{error:`unknown option ${r}`};if(t.service!==void 0)return{error:`one service at a time (got '${t.service}' and '${r}')`};r.trim()&&(t.service=r.trim())}}return t.service?t.worktree&&t.workspace?{error:"--worktree or --workspace, not both"}:(t.status&&!n&&(t.waitMs=0),t):{error:"name the service \u2014 its Nx project name"}}h(parseRestartArgs,"parseRestartArgs"),a(parseRestartArgs,"parseRestartArgs");export function targetKey(e,t){return e.workspace?e.workspace:e.worktree?e.worktree==="main"?t.baseKey:`${t.baseKey}-${e.worktree}`:t.key}h(targetKey,"targetKey"),a(targetKey,"targetKey");const b=500,j={rolling:"a new tree started beside the old one, which kept serving until the new one answered",hard:"stopped, then started \u2014 nothing served in between",start:"it was down; started"},$=a(e=>`${Math.round(e/100)/10}s`,"secs");export async function runRestartCommand(e,t){const n=targetKey(e,t.here),c=n===t.here.key?"":` (${n})`,r=`${e.service}${c}`,i=a(w=>({wsKey:n,service:e.service,...w&&typeof w=="object"?w:{}}),"view"),o=a(()=>({exitCode:2,lines:["No gateway answers on the control socket \u2014 nothing is serving the services. Start it: `lensmcp gateway start`."],result:{ok:!1,wsKey:n,service:e.service,error:"no gateway answers"}}),"unavailable"),s=a((w,l)=>{const p=[`Could not restart ${r}: ${l.error??`the gateway answered ${w}`}.`];return l.services?.length&&p.push(`Its services: ${l.services.join(", ")}.`),l.workspaces?.length&&p.push(`Workspaces the gateway serves: ${l.workspaces.join(", ")}.`),{exitCode:1,lines:p,result:{ok:!1,...l}}},"refused"),d=a(()=>t.request("GET",`/restart?wsKey=${encodeURIComponent(n)}&service=${encodeURIComponent(e.service)}`),"read"),v=e.status?d():t.request("POST","/restart",{wsKey:n,service:e.service,...e.hard?{hard:!0}:{},reason:e.reason??"lensmcp restart"});if(!v)return o();let u=i(v.json);if(v.status!==(e.status?200:202))return s(v.status,u);const f=u.already===!0,k=t.now()+(u.restart?e.waitMs:0);for(;!u.restart?.done&&t.now()<k;){await t.sleep(b);const w=d();w?.status===200&&(u={...i(w.json),already:f})}return g(u,r,t.now(),e.waitMs>0)}h(runRestartCommand,"runRestartCommand"),a(runRestartCommand,"runRestartCommand");function g(e,t,n,c){const r=e.restart,i={wsKey:e.wsKey,service:e.service,state:e.state,...e.generation!==void 0?{generation:e.generation}:{},...r?{restart:r}:{},...e.already?{joined:!0}:{}};if(!r)return{exitCode:0,lines:[`${t} has not been restarted through the gateway since it started; it is ${e.state??"unknown"}.`],result:{ok:!0,...i}};const o=e.already?" (one was already under way \u2014 this is that one)":"";if(r.done?.ok)return{exitCode:0,lines:[`${t} restarted${o}: generation ${r.done.generation??"?"} serving after ${$(r.done.at-r.startedAt)} \u2014 ${j[r.how]}.`],result:{ok:!0,done:!0,...i}};if(r.done){const d=r.how==="rolling"&&/kept serving/.test(r.done.error??"");return{exitCode:1,lines:[`${t} did not restart${o}: ${r.done.error??"no reason given"} (after ${$(r.done.at-r.startedAt)}).`,d?`It still serves generation ${r.fromGeneration??"?"}. Read its log: \`lensmcp logs ${e.service}\`.`:`Read its log: \`lensmcp logs ${e.service}\`.`],result:{ok:!1,done:!0,...i}}}const s=`\`lensmcp restart ${e.service}${t!==e.service?` --workspace ${e.wsKey}`:""} --status\``;return{exitCode:c?3:0,lines:[`${t} is restarting${o} (${r.how}${r.fromGeneration!==void 0?`, from generation ${r.fromGeneration}`:""}, ${$(n-r.startedAt)} so far)${c?" \u2014 not settled within the wait":""}. See how it went: ${s}.`],result:{ok:!0,done:!1,...i}}}h(g,"g"),a(g,"settledOrNot");
@@ -1,5 +1,5 @@
1
- "use strict";var m=Object.defineProperty;var o=(r,e)=>m(r,"name",{value:e,configurable:!0});var v=Object.defineProperty,t=o((r,e)=>v(r,"name",{value:e,configurable:!0}),"n"),f=Object.defineProperty,i=t((r,e)=>f(r,"name",{value:e,configurable:!0}),"o");import{existsSync as l}from"node:fs";import{dirname as b,join as u}from"node:path";export const MCP_SERVER_PROJECT="@lensmcp/lensmcp-mcp",MCP_SERVER_DIST_DIR="servers/lensmcp-mcp/dist",BUNDLED_DIR="bundled",MCP_SERVER_BUNDLES=["main.js","shim.js","dashboard.js"];const E=5;export function locateServerBundle(r,e,p){const s=u(p,BUNDLED_DIR,e);if(l(s))return s;let n=r;for(let a=0;a<E;a++){const c=u(n,MCP_SERVER_DIST_DIR,e);if(l(c))return c;const d=b(n);if(d===n)break;n=d}}o(locateServerBundle,"locateServerBundle"),t(locateServerBundle,"locateServerBundle"),i(locateServerBundle,"locateServerBundle");export function serverBundleNotFound(r,e){return`Could not locate the ${r}.
1
+ "use strict";var p=Object.defineProperty;var n=(r,e)=>p(r,"name",{value:e,configurable:!0});var m=Object.defineProperty,d=n((r,e)=>m(r,"name",{value:e,configurable:!0}),"o");import{existsSync as a}from"node:fs";import{dirname as f,join as l}from"node:path";export const MCP_SERVER_PROJECT="@lensmcp/lensmcp-mcp",MCP_SERVER_DIST_DIR="servers/lensmcp-mcp/dist",BUNDLED_DIR="bundled",MCP_SERVER_BUNDLES=["main.js","shim.js","dashboard.js"];const v=5;export function locateServerBundle(r,e,u){const t=l(u,BUNDLED_DIR,e);if(a(t))return t;let o=r;for(let s=0;s<v;s++){const i=l(o,MCP_SERVER_DIST_DIR,e);if(a(i))return i;const c=f(o);if(c===o)break;o=c}}n(locateServerBundle,"locateServerBundle"),d(locateServerBundle,"locateServerBundle");export function serverBundleNotFound(r,e){return`Could not locate the ${r}.
2
2
  Looked in (in order):
3
3
  \u2022 <cli-package>/${BUNDLED_DIR}/${e} (published bin)
4
4
  \u2022 <workspace>/${MCP_SERVER_DIST_DIR}/${e} (dev build)
5
- For dev: \`yarn nx build ${MCP_SERVER_PROJECT}\`.`}o(serverBundleNotFound,"serverBundleNotFound"),t(serverBundleNotFound,"serverBundleNotFound"),i(serverBundleNotFound,"serverBundleNotFound");
5
+ For dev: \`yarn nx build ${MCP_SERVER_PROJECT}\`.`}n(serverBundleNotFound,"serverBundleNotFound"),d(serverBundleNotFound,"serverBundleNotFound");
@@ -1,2 +1,2 @@
1
- "use strict";var j=Object.defineProperty;var u=(t,r)=>j(t,"name",{value:r,configurable:!0});var M=Object.defineProperty,l=u((t,r)=>M(t,"name",{value:r,configurable:!0}),"u"),k=Object.defineProperty,a=l((t,r)=>k(t,"name",{value:r,configurable:!0}),"a");import{readLensConfig as T}from"./workspace-scope.js";import{mcpModeSwitchHint as D,sharedMcpUrl as E}from"./mcp-mode.js";import{resolveEffectiveMcpMode as $}from"./mcp-wiring.js";import{credentialVerdict as N,newProofNonce as A,readMcpToken as P}from"./mcp-token.js";import{freshnessOf as C}from"./status-policy.js";export const IDENTITY_PATH="/lensmcp/identity",IDENTITY_KIND="lensmcp-mcp-identity";export function resolveSource(t,r){const n=T(t),e=n.ports.mcpHttp,{mode:s,source:o}=$(t,void 0,r);return{workspace:n.key,mode:s,modeSource:o,port:e,url:E(e)}}u(resolveSource,"resolveSource"),l(resolveSource,"resolveSource"),a(resolveSource,"resolveSource");function b(t){const r=Date.now()+t;return{remaining:a(()=>Math.max(0,r-Date.now()),"remaining"),expired:a(()=>Date.now()>=r,"expired")}}u(b,"g"),l(b,"D"),a(b,"deadline");async function v(t,r,n){const e=n.remaining();if(e<=0)return;const s=new AbortController,o=setTimeout(()=>s.abort(),e);try{return await fetch(t,{...r,signal:s.signal})}catch{return}finally{clearTimeout(o)}}u(v,"y"),l(v,"h"),a(v,"fetchWithin");async function y(t,r,n,e,s){const o=await v(t,{method:"POST",headers:{"content-type":"application/json",accept:"application/json, text/event-stream",...s?{authorization:s}:{},...r?{"mcp-session-id":r}:{}},body:JSON.stringify(n)},e);if(!o)return;if(o.status===202)return{res:o};const i=await o.text().catch(()=>"");return{res:o,...parseFrame(i)===void 0?{}:{json:parseFrame(i)}}}u(y,"v"),l(y,"w"),a(y,"rpc");export function parseFrame(t){const r=t.split(`
2
- `).find(e=>e.startsWith("data:")),n=(r?r.slice(5):t).trim();if(n)try{const e=JSON.parse(n);return typeof e=="object"&&e!==null?e:void 0}catch{return}}u(parseFrame,"parseFrame"),l(parseFrame,"parseFrame"),a(parseFrame,"parseFrame");export function parseResourceResult(t){const r=t?.result;if(typeof r!="object"||r===null)return;const n=r.contents;if(!Array.isArray(n)||n.length===0)return;const e=n[0];if(typeof e!="object"||e===null)return;const s=e.text;if(typeof s=="string")try{return JSON.parse(s)}catch{return}}u(parseResourceResult,"parseResourceResult"),l(parseResourceResult,"parseResourceResult"),a(parseResourceResult,"parseResourceResult");async function x(t,r,n,e){const s=A(),o=await v(`http://127.0.0.1:${t}${IDENTITY_PATH}?nonce=${s}`,{headers:{accept:"application/json"}},n);if(!o)return{stranger:"no server on this workspace\u2019s MCP port"};if(!o.ok)return await o.text().catch(()=>{}),{stranger:`the process on :${t} does not serve a lensmcp identity`};const i=await o.json().catch(()=>{});if(typeof i!="object"||i===null)return{stranger:`unreadable identity on :${t}`};const c=i;if(c.kind!==IDENTITY_KIND)return{stranger:`the process on :${t} is not a lensmcp server`};if(c.key!==r)return{stranger:`:${t} serves workspace "${String(c.key)}", not "${r}"`};const d=N(c,t,s,P(e),e.LENSMCP_ALLOW_INSECURE==="1");return d.refused?{stranger:d.remedy?`${d.refused} \u2014 ${d.remedy}`:d.refused}:d.authorization?{authorization:d.authorization}:{}}u(x,"x"),l(x,"$"),a(x,"verifyIdentity");export const DEFAULT_BUDGET_MS=2e3;export class SessionUnavailable extends Error{static{u(this,"SessionUnavailable")}static{l(this,"SessionUnavailable")}static{a(this,"SessionUnavailable")}}export function parseToolResult(t){const r=t?.error;if(typeof r=="object"&&r!==null){const c=r.message;return{ok:!1,value:void 0,text:typeof c=="string"?c:"the server refused the call"}}const n=t?.result;if(typeof n!="object"||n===null)return{ok:!1,value:void 0,text:"the server did not answer the call"};const e=n,s=(Array.isArray(e.content)?e.content:[])[0],o=typeof s=="object"&&s!==null&&typeof s.text=="string"?s.text:"";let i=e.structuredContent;if(i===void 0&&o)try{i=JSON.parse(o)}catch{i=void 0}return{ok:e.isError!==!0,value:i,text:o}}u(parseToolResult,"parseToolResult"),l(parseToolResult,"parseToolResult"),a(parseToolResult,"parseToolResult");export async function withLensSession(t,r){const n=Date.now(),e=resolveSource(t.cwd,t.env),s=b(t.budgetMs??DEFAULT_BUDGET_MS),o=a(f=>({available:!1,source:e,reason:f,elapsedMs:Date.now()-n}),"fail");if(e.mode!=="shared")return o(`MCP mode is embedded \u2014 there is no shared server to read (${D({mode:e.mode,source:e.modeSource})})`);const i=await x(e.port,e.workspace,s,t.env);if(i.stranger)return o(i.stranger);const c=i.authorization,d=await y(e.url,void 0,{jsonrpc:"2.0",id:1,method:"initialize",params:{protocolVersion:"2025-06-18",capabilities:{},clientInfo:{name:t.clientName??"lensmcp-status",version:"1"}}},s,c);if(!d||!d.res.ok)return o("the shared MCP server did not accept a session");const w=d.res.headers.get("mcp-session-id")??void 0,S=a(async()=>{w&&await v(e.url,{method:"DELETE",headers:{"mcp-session-id":w,...c?{authorization:c}:{}}},s)},"close");try{await y(e.url,w,{jsonrpc:"2.0",method:"notifications/initialized"},s,c);let f=1;const g=a((p,m)=>y(e.url,w,{jsonrpc:"2.0",id:++f,method:p,...m===void 0?{}:{params:m}},s,c),"ask");return{available:!0,source:e,value:await r({read:a(async p=>parseResourceResult((await g("resources/read",{uri:p}))?.json),"read"),tools:a(async()=>{const p=(await g("tools/list"))?.json?.result,m=typeof p=="object"&&p!==null?p.tools:void 0;return Array.isArray(m)?m.flatMap(h=>typeof h=="object"&&h!==null&&typeof h.name=="string"?[h.name]:[]):[]},"tools"),call:a(async(p,m)=>{const h=await g("tools/call",{name:p,arguments:m});return h?parseToolResult(h.json):{ok:!1,value:void 0,text:"the shared MCP server did not answer in time"}},"call"),expired:a(()=>s.expired(),"expired")}),elapsedMs:Date.now()-n}}catch(f){if(f instanceof SessionUnavailable)return o(f.message);throw f}finally{await S()}}u(withLensSession,"withLensSession"),l(withLensSession,"withLensSession"),a(withLensSession,"withLensSession");export async function readStatus(t){const r=await withLensSession(t,async n=>{const e=await n.read("agent://current-status");if(typeof e!="object"||e===null)throw new SessionUnavailable("the shared MCP server did not return agent://current-status");const s=e,o=new Map;for(const i of t.verify?.(s)??[]){if(n.expired())break;const c=await n.read(i);c!==void 0&&o.set(i,C(c))}return{status:s,evidence:o}});return r.available?{available:!0,source:r.source,status:r.value.status,evidence:r.value.evidence,elapsedMs:r.elapsedMs}:r}u(readStatus,"readStatus"),l(readStatus,"readStatus"),a(readStatus,"readStatus");
1
+ "use strict";var j=Object.defineProperty;var u=(t,r)=>j(t,"name",{value:r,configurable:!0});var M=Object.defineProperty,a=u((t,r)=>M(t,"name",{value:r,configurable:!0}),"a");import{readLensConfig as S}from"./workspace-scope.js";import{mcpModeSwitchHint as k,sharedMcpUrl as T}from"./mcp-mode.js";import{resolveEffectiveMcpMode as E}from"./mcp-wiring.js";import{credentialVerdict as D,newProofNonce as $,readMcpToken as N}from"./mcp-token.js";import{freshnessOf as A}from"./status-policy.js";export const IDENTITY_PATH="/lensmcp/identity",IDENTITY_KIND="lensmcp-mcp-identity";export function resolveSource(t,r){const o=S(t),e=o.ports.mcpHttp,{mode:n,source:s}=E(t,void 0,r);return{workspace:o.key,mode:n,modeSource:s,port:e,url:T(e)}}u(resolveSource,"resolveSource"),a(resolveSource,"resolveSource");function g(t){const r=Date.now()+t;return{remaining:a(()=>Math.max(0,r-Date.now()),"remaining"),expired:a(()=>Date.now()>=r,"expired")}}u(g,"D"),a(g,"deadline");async function y(t,r,o){const e=o.remaining();if(e<=0)return;const n=new AbortController,s=setTimeout(()=>n.abort(),e);try{return await fetch(t,{...r,signal:n.signal})}catch{return}finally{clearTimeout(s)}}u(y,"h"),a(y,"fetchWithin");async function v(t,r,o,e,n){const s=await y(t,{method:"POST",headers:{"content-type":"application/json",accept:"application/json, text/event-stream",...n?{authorization:n}:{},...r?{"mcp-session-id":r}:{}},body:JSON.stringify(o)},e);if(!s)return;if(s.status===202)return{res:s};const i=await s.text().catch(()=>"");return{res:s,...parseFrame(i)===void 0?{}:{json:parseFrame(i)}}}u(v,"w"),a(v,"rpc");export function parseFrame(t){const r=t.split(`
2
+ `).find(e=>e.startsWith("data:")),o=(r?r.slice(5):t).trim();if(o)try{const e=JSON.parse(o);return typeof e=="object"&&e!==null?e:void 0}catch{return}}u(parseFrame,"parseFrame"),a(parseFrame,"parseFrame");export function parseResourceResult(t){const r=t?.result;if(typeof r!="object"||r===null)return;const o=r.contents;if(!Array.isArray(o)||o.length===0)return;const e=o[0];if(typeof e!="object"||e===null)return;const n=e.text;if(typeof n=="string")try{return JSON.parse(n)}catch{return}}u(parseResourceResult,"parseResourceResult"),a(parseResourceResult,"parseResourceResult");async function x(t,r,o,e){const n=$(),s=await y(`http://127.0.0.1:${t}${IDENTITY_PATH}?nonce=${n}`,{headers:{accept:"application/json"}},o);if(!s)return{stranger:"no server on this workspace\u2019s MCP port"};if(!s.ok)return await s.text().catch(()=>{}),{stranger:`the process on :${t} does not serve a lensmcp identity`};const i=await s.json().catch(()=>{});if(typeof i!="object"||i===null)return{stranger:`unreadable identity on :${t}`};const c=i;if(c.kind!==IDENTITY_KIND)return{stranger:`the process on :${t} is not a lensmcp server`};if(c.key!==r)return{stranger:`:${t} serves workspace "${String(c.key)}", not "${r}"`};const l=D(c,t,n,N(e),e.LENSMCP_ALLOW_INSECURE==="1");return l.refused?{stranger:l.remedy?`${l.refused} \u2014 ${l.remedy}`:l.refused}:l.authorization?{authorization:l.authorization}:{}}u(x,"$"),a(x,"verifyIdentity");export const DEFAULT_BUDGET_MS=2e3;export class SessionUnavailable extends Error{static{u(this,"SessionUnavailable")}static{a(this,"SessionUnavailable")}}export function parseToolResult(t){const r=t?.error;if(typeof r=="object"&&r!==null){const c=r.message;return{ok:!1,value:void 0,text:typeof c=="string"?c:"the server refused the call"}}const o=t?.result;if(typeof o!="object"||o===null)return{ok:!1,value:void 0,text:"the server did not answer the call"};const e=o,n=(Array.isArray(e.content)?e.content:[])[0],s=typeof n=="object"&&n!==null&&typeof n.text=="string"?n.text:"";let i=e.structuredContent;if(i===void 0&&s)try{i=JSON.parse(s)}catch{i=void 0}return{ok:e.isError!==!0,value:i,text:s}}u(parseToolResult,"parseToolResult"),a(parseToolResult,"parseToolResult");export async function withLensSession(t,r){const o=Date.now(),e=resolveSource(t.cwd,t.env),n=g(t.budgetMs??DEFAULT_BUDGET_MS),s=a(p=>({available:!1,source:e,reason:p,elapsedMs:Date.now()-o}),"fail");if(e.mode!=="shared")return s(`MCP mode is embedded \u2014 there is no shared server to read (${k({mode:e.mode,source:e.modeSource})})`);const i=await x(e.port,e.workspace,n,t.env);if(i.stranger)return s(i.stranger);const c=i.authorization,l=await v(e.url,void 0,{jsonrpc:"2.0",id:1,method:"initialize",params:{protocolVersion:"2025-06-18",capabilities:{},clientInfo:{name:t.clientName??"lensmcp-status",version:"1"}}},n,c);if(!l||!l.res.ok)return s("the shared MCP server did not accept a session");const h=l.res.headers.get("mcp-session-id")??void 0,b=a(async()=>{h&&await y(e.url,{method:"DELETE",headers:{"mcp-session-id":h,...c?{authorization:c}:{}}},n)},"close");try{await v(e.url,h,{jsonrpc:"2.0",method:"notifications/initialized"},n,c);let p=1;const w=a((d,f)=>v(e.url,h,{jsonrpc:"2.0",id:++p,method:d,...f===void 0?{}:{params:f}},n,c),"ask");return{available:!0,source:e,value:await r({read:a(async d=>parseResourceResult((await w("resources/read",{uri:d}))?.json),"read"),tools:a(async()=>{const d=(await w("tools/list"))?.json?.result,f=typeof d=="object"&&d!==null?d.tools:void 0;return Array.isArray(f)?f.flatMap(m=>typeof m=="object"&&m!==null&&typeof m.name=="string"?[m.name]:[]):[]},"tools"),call:a(async(d,f)=>{const m=await w("tools/call",{name:d,arguments:f});return m?parseToolResult(m.json):{ok:!1,value:void 0,text:"the shared MCP server did not answer in time"}},"call"),expired:a(()=>n.expired(),"expired")}),elapsedMs:Date.now()-o}}catch(p){if(p instanceof SessionUnavailable)return s(p.message);throw p}finally{await b()}}u(withLensSession,"withLensSession"),a(withLensSession,"withLensSession");export async function readStatus(t){const r=await withLensSession(t,async o=>{const e=await o.read("agent://current-status");if(typeof e!="object"||e===null)throw new SessionUnavailable("the shared MCP server did not return agent://current-status");const n=e,s=new Map;for(const i of t.verify?.(n)??[]){if(o.expired())break;const c=await o.read(i);c!==void 0&&s.set(i,A(c))}return{status:n,evidence:s}});return r.available?{available:!0,source:r.source,status:r.value.status,evidence:r.value.evidence,elapsedMs:r.elapsedMs}:r}u(readStatus,"readStatus"),a(readStatus,"readStatus");
@@ -1,2 +1,2 @@
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");
1
+ "use strict";var v=Object.defineProperty;var r=(n,t)=>v(n,"name",{value:t,configurable:!0});var m=Object.defineProperty,o=r((n,t)=>m(n,"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 p=o(n=>typeof n=="object"&&n!==null&&!Array.isArray(n),"isRecord"),g=o(n=>typeof n=="number"&&Number.isFinite(n)?n:void 0,"asFiniteNumber");function f(n,t){if(!Array.isArray(n))return;let e;for(const s of n){if(!p(s))continue;const i=g(s[t]);i!==void 0&&(e===void 0||i>e)&&(e=i)}return e}r(f,"h"),o(f,"newestIn");export function freshnessOf(n){if(!p(n))return{};const t=typeof n.producer=="string"?n.producer:void 0,e=g(n.lastRunAt)??g(n.lastReportedAt)??f(n.producers,"lastReportedAt")??f(n.producers,"lastRunAt"),s=f(n.entries,"timestamp")??f(n.failures,"timestamp")??f(n.violations,"timestamp");return{...t===void 0?{}:{declaredProducer:t},...n.stale===!0?{declaredStale:!0}:{},...e===void 0?{}:{ranAt:e},...s===void 0?{}:{newestItemAt:s},...g(n.ageMs)===void 0?{}:{ageMs:g(n.ageMs)}}}r(freshnessOf,"freshnessOf"),o(freshnessOf,"freshnessOf");const h=o((n,t)=>n===void 0?void 0:Math.max(0,t-n),"ageFrom");export function candidateSignals(n){return(n.signals??[]).filter(t=>HOOK_SIGNAL_CLASS[t.kind]!==void 0&&(t.state==="failed"||t.state==="warning")&&t.producer==="connected")}r(candidateSignals,"candidateSignals"),o(candidateSignals,"candidateSignals");export function judge(n,t,e,s=OBSERVATION_WINDOW_MS){const i=HOOK_SIGNAL_CLASS[n.kind];if(i===void 0)return{kind:n.kind,reason:"out-of-scope"};if(n.state!=="failed"&&n.state!=="warning")return{kind:n.kind,reason:"not-actionable"};if(n.producer!=="connected"||t?.declaredProducer==="none")return{kind:n.kind,reason:"no-producer"};const c=n.reads?.[0]??n.resource,u={kind:n.kind,state:n.state,...n.count===void 0?{}:{count:n.count},read:c,detail:n.detail};if(n.stale===!0||t?.declaredStale===!0){const l=t?.ageMs??h(t?.ranAt,e);return{...u,stale:!0,...l===void 0?{}:{ageMs:l}}}if(i==="check"){const l=h(t?.ranAt,e);return l===void 0?{kind:n.kind,reason:"no-freshness-evidence"}:{...u,stale:!1,ageMs:l}}const a=t?.newestItemAt;if(a===void 0)return{kind:n.kind,reason:"no-freshness-evidence"};const d=Math.max(0,e-a);return d>s?{kind:n.kind,reason:"stale-observation"}:{...u,stale:!1,ageMs:d}}r(judge,"judge"),o(judge,"judge");const b=o(n=>"state"in n,"isFinding");export function select(n,t,e,s=OBSERVATION_WINDOW_MS){const i=[],c=[],u=[];for(const a of n.signals??[]){a.producer==="none"&&HOOK_SIGNAL_CLASS[a.kind]!==void 0&&u.push(a.kind);const d=judge(a,t.get(a.resource),e,s);b(d)?i.push(d):d.reason!=="out-of-scope"&&d.reason!=="not-actionable"&&c.push(d)}return i.sort((a,d)=>a.state===d.state?(d.count??0)-(a.count??0):a.state==="failed"?-1:1),{findings:i,suppressed:c,unmonitored:u}}r(select,"select"),o(select,"select");export function describeAge(n){return n<6e4?`${Math.max(1,Math.round(n/1e3))}s ago`:n<36e5?`${Math.round(n/6e4)}m ago`:`${Math.round(n/36e5)}h ago`}r(describeAge,"describeAge"),o(describeAge,"describeAge");function k(n){return n.read.startsWith("runtime://browser")?"browser runtime error":"server-side error"}r(k,"g"),o(k,"runtimeNoun");export function describeCount(n){const t=n.kind==="runtime"?k(n):`${n.kind} ${n.state==="failed"?"error":"warning"}`,e=n.count===1?"":"s";return`${n.count===void 0?"":`${n.count} `}${t}${e}`}r(describeCount,"describeCount"),o(describeCount,"describeCount");export function describeWhen(n){return n.stale?`last checked ${n.ageMs===void 0?"a while ago":describeAge(n.ageMs)}, nothing has re-run since`:n.ageMs===void 0?"recency unknown":describeAge(n.ageMs)}r(describeWhen,"describeWhen"),o(describeWhen,"describeWhen");export function findingLine(n){return`${n.kind}: ${describeCount(n)} (${describeWhen(n)}) \u2192 read ${n.read}`}r(findingLine,"findingLine"),o(findingLine,"findingLine");export function formatContext(n,t={}){const{findings:e,unmonitored:s}=n;if(e.length===0)return;const i=[`LensMCP${t.workspace?` (${t.workspace})`:""}: ${e.length===1?"1 signal needs":`${e.length} signals need`} attention.`,...e.map(c=>` \u2022 ${findingLine(c)}`)];return t.includeUnmonitored&&s.length>0&&i.push(` (unmonitored, so unknown rather than clean: ${s.join(", ")})`),i.push(" Verify before acting \u2014 these are observations, not a fresh build."),i.join(`
2
+ `)}r(formatContext,"formatContext"),o(formatContext,"formatContext");export const HOOK_EVENTS=["Stop","SessionStart","SubagentStop"],isHookEvent=o(n=>typeof n=="string"&&HOOK_EVENTS.includes(n),"isHookEvent");export function hookPayload(n,t){return JSON.stringify({hookSpecificOutput:{hookEventName:n,additionalContext:t}})}r(hookPayload,"hookPayload"),o(hookPayload,"hookPayload");export function findingsDigest(n){return n.map(t=>`${t.kind}:${t.state}:${t.count??""}`).sort().join("|")}r(findingsDigest,"findingsDigest"),o(findingsDigest,"findingsDigest");
package/lib/sweep.js CHANGED
@@ -1 +1 @@
1
- "use strict";var S=Object.defineProperty;var c=(n,e)=>S(n,"name",{value:e,configurable:!0});var $=Object.defineProperty,a=c((n,e)=>$(n,"name",{value:e,configurable:!0}),"s"),w=Object.defineProperty,r=a((n,e)=>w(n,"name",{value:e,configurable:!0}),"e");import{chmodSync as l,mkdirSync as G,openSync as x,readdirSync as g,renameSync as h,rmSync as N,statSync as f,unlinkSync as _}from"node:fs";import{join as u}from"node:path";const m=r(n=>{try{N(n,{force:!0})}catch{}},"removeQuietly");export function sweepLensRuntimeFiles(n,e){const t=u(n,".lensmcp"),o=u(t,"events.jsonl");m(`${o}.old`),m(`${e}.old`);const y=(()=>{const s=Number(process.env.LENSMCP_EVENT_MAX_FILES);return Number.isFinite(s)&&s>=1&&s<=20?Math.floor(s):5})(),i=64*1024*1024;try{for(const s of g(t)){const L=/^events\.jsonl\.(\d+)$/.exec(s);if(!L)continue;const d=Number(L[1]),p=u(t,s);if(d<1||d>y)m(p);else try{f(p).size>i&&m(p)}catch{}}}catch{}const E=16*1024*1024;try{f(e).size>E&&(shiftLogGenerations(e,b),h(e,`${e}.1`))}catch{}}c(sweepLensRuntimeFiles,"sweepLensRuntimeFiles"),a(sweepLensRuntimeFiles,"sweepLensRuntimeFiles"),r(sweepLensRuntimeFiles,"sweepLensRuntimeFiles");const b=3;export function shiftLogGenerations(n,e){try{_(`${n}.${e}`)}catch{}for(let t=e-1;t>=1;t--)try{h(`${n}.${t}`,`${n}.${t+1}`)}catch{}}c(shiftLogGenerations,"shiftLogGenerations"),a(shiftLogGenerations,"shiftLogGenerations"),r(shiftLogGenerations,"shiftLogGenerations");const F=/\.log(\.\d+)?$/,v=r(n=>typeof process.getuid!="function"||n===process.getuid(),"ownedByMe");export function secureLensLogs(n){const e=u(n,".lensmcp");try{G(e,{recursive:!0,mode:448});const o=f(e);(o.mode&63)!==0&&v(o.uid)&&l(e,448)}catch{}let t;try{t=g(e)}catch{return}for(const o of t){if(!F.test(o))continue;const y=u(e,o);try{const i=f(y);i.isFile()&&(i.mode&63)!==0&&v(i.uid)&&l(y,384)}catch{}}}c(secureLensLogs,"secureLensLogs"),a(secureLensLogs,"secureLensLogs"),r(secureLensLogs,"secureLensLogs");export const GATEWAY_LOG_ENV="LENSMCP_GATEWAY_LOG";export function gatewayDaemonEnv(n,e){return{...n,[GATEWAY_LOG_ENV]:e}}c(gatewayDaemonEnv,"gatewayDaemonEnv"),a(gatewayDaemonEnv,"gatewayDaemonEnv"),r(gatewayDaemonEnv,"gatewayDaemonEnv");export function openGatewayLog(n,e){sweepLensRuntimeFiles(n,e),secureLensLogs(n);const t=x(e,"a",384);try{l(e,384)}catch{}return t}c(openGatewayLog,"openGatewayLog"),a(openGatewayLog,"openGatewayLog"),r(openGatewayLog,"openGatewayLog");
1
+ "use strict";var $=Object.defineProperty;var s=(t,e)=>$(t,"name",{value:e,configurable:!0});var E=Object.defineProperty,r=s((t,e)=>E(t,"name",{value:e,configurable:!0}),"e");import{chmodSync as p,mkdirSync as v,openSync as G,readdirSync as L,renameSync as h,rmSync as x,statSync as y,unlinkSync as N}from"node:fs";import{join as i}from"node:path";const f=r(t=>{try{x(t,{force:!0})}catch{}},"removeQuietly");export function sweepLensRuntimeFiles(t,e){const o=i(t,".lensmcp"),n=i(o,"events.jsonl");f(`${n}.old`),f(`${e}.old`);const u=(()=>{const c=Number(process.env.LENSMCP_EVENT_MAX_FILES);return Number.isFinite(c)&&c>=1&&c<=20?Math.floor(c):5})(),a=64*1024*1024;try{for(const c of L(o)){const d=/^events\.jsonl\.(\d+)$/.exec(c);if(!d)continue;const l=Number(d[1]),m=i(o,c);if(l<1||l>u)f(m);else try{y(m).size>a&&f(m)}catch{}}}catch{}const S=16*1024*1024;try{y(e).size>S&&(shiftLogGenerations(e,_),h(e,`${e}.1`))}catch{}}s(sweepLensRuntimeFiles,"sweepLensRuntimeFiles"),r(sweepLensRuntimeFiles,"sweepLensRuntimeFiles");const _=3;export function shiftLogGenerations(t,e){try{N(`${t}.${e}`)}catch{}for(let o=e-1;o>=1;o--)try{h(`${t}.${o}`,`${t}.${o+1}`)}catch{}}s(shiftLogGenerations,"shiftLogGenerations"),r(shiftLogGenerations,"shiftLogGenerations");const w=/\.log(\.\d+)?$/,g=r(t=>typeof process.getuid!="function"||t===process.getuid(),"ownedByMe");export function secureLensLogs(t){const e=i(t,".lensmcp");try{v(e,{recursive:!0,mode:448});const n=y(e);(n.mode&63)!==0&&g(n.uid)&&p(e,448)}catch{}let o;try{o=L(e)}catch{return}for(const n of o){if(!w.test(n))continue;const u=i(e,n);try{const a=y(u);a.isFile()&&(a.mode&63)!==0&&g(a.uid)&&p(u,384)}catch{}}}s(secureLensLogs,"secureLensLogs"),r(secureLensLogs,"secureLensLogs");export const GATEWAY_LOG_ENV="LENSMCP_GATEWAY_LOG";export function gatewayDaemonEnv(t,e){return{...t,[GATEWAY_LOG_ENV]:e}}s(gatewayDaemonEnv,"gatewayDaemonEnv"),r(gatewayDaemonEnv,"gatewayDaemonEnv");export function openGatewayLog(t,e){sweepLensRuntimeFiles(t,e),secureLensLogs(t);const o=G(e,"a",384);try{p(e,384)}catch{}return o}s(openGatewayLog,"openGatewayLog"),r(openGatewayLog,"openGatewayLog");