lensmcp 1.23.13 → 1.24.0

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 (63) hide show
  1. package/bundled/bridge.js +27 -27
  2. package/bundled/capture-runner.js +26 -26
  3. package/bundled/dashboard-ui/app.css +1 -1
  4. package/bundled/dashboard-ui/app.js +17 -17
  5. package/bundled/dashboard.js +98 -64
  6. package/bundled/lint-runner.js +3 -3
  7. package/bundled/main.js +43 -40
  8. package/bundled/shim.js +47 -43
  9. package/lib/bridge-origins.d.ts +16 -0
  10. package/lib/bridge-origins.js +1 -0
  11. package/lib/cli.js +53 -42
  12. package/lib/dashboard-login.d.ts +17 -0
  13. package/lib/dashboard-login.js +3 -0
  14. package/lib/duplicate-registration.d.ts +6 -3
  15. package/lib/duplicate-registration.js +1 -1
  16. package/lib/forward-signals.d.ts +24 -0
  17. package/lib/forward-signals.js +1 -0
  18. package/lib/guest-graph.d.ts +44 -0
  19. package/lib/guest-graph.js +4 -0
  20. package/lib/heap-analyzer-main.d.ts +1 -0
  21. package/lib/heap-analyzer-main.js +3 -0
  22. package/lib/heap-analyzer.d.ts +109 -0
  23. package/lib/heap-analyzer.js +1 -0
  24. package/lib/lint-args.d.ts +1 -1
  25. package/lib/mcp-mode.d.ts +92 -10
  26. package/lib/mcp-mode.js +3 -2
  27. package/lib/mcp-restart.d.ts +20 -1
  28. package/lib/mcp-restart.js +1 -1
  29. package/lib/mcp-sessions.d.ts +20 -0
  30. package/lib/mcp-sessions.js +2 -0
  31. package/lib/mcp-token.d.ts +48 -0
  32. package/lib/mcp-token.js +4 -0
  33. package/lib/mcp-wiring.d.ts +20 -5
  34. package/lib/mcp-wiring.js +2 -2
  35. package/lib/mem-command.d.ts +106 -0
  36. package/lib/mem-command.js +3 -0
  37. package/lib/perf-rules-check.d.ts +35 -0
  38. package/lib/perf-rules-check.js +4 -0
  39. package/lib/pod-source-maps.d.ts +31 -0
  40. package/lib/pod-source-maps.js +1 -0
  41. package/lib/process-ownership.d.ts +30 -0
  42. package/lib/process-ownership.js +2 -0
  43. package/lib/server-bundle.d.ts +19 -0
  44. package/lib/server-bundle.js +5 -0
  45. package/lib/status-client.d.ts +4 -1
  46. package/lib/status-client.js +2 -2
  47. package/lib/sweep.d.ts +15 -0
  48. package/lib/sweep.js +1 -1
  49. package/lib/workspace-scope.d.ts +26 -9
  50. package/package.json +4 -4
  51. package/plugin/.claude-plugin/plugin.json +1 -1
  52. package/plugin/scripts/dashboard-open.sh +26 -6
  53. package/plugin/skills/dashboard/SKILL.md +3 -1
  54. package/plugin/skills/using-lensmcp/SKILL.md +27 -0
  55. package/plugin/skills/using-lensmcp/rules/bundle-heavy-barrel-import.md +79 -0
  56. package/plugin/skills/using-lensmcp/rules/pod-heap-budget.md +53 -0
  57. package/plugin/skills/using-lensmcp/rules/pod-retained-generation.md +38 -0
  58. package/plugins/lensmcp/.codex-plugin/plugin.json +1 -1
  59. package/plugins/lensmcp/skills/lensmcp-dashboard/SKILL.md +5 -2
  60. package/plugins/lensmcp/skills/using-lensmcp/SKILL.md +21 -0
  61. package/plugins/lensmcp/skills/using-lensmcp/rules/bundle-heavy-barrel-import.md +79 -0
  62. package/plugins/lensmcp/skills/using-lensmcp/rules/pod-heap-budget.md +53 -0
  63. package/plugins/lensmcp/skills/using-lensmcp/rules/pod-retained-generation.md +38 -0
@@ -0,0 +1,16 @@
1
+ /** The part of a project's `cluster` (legacy `davnx`) declaration the bridge allowlist reads. */
2
+ export interface ClusterPageDecl {
3
+ /** The public dev hostname the gateway serves the project under (`app.shop.local`, `*.shop.local`). */
4
+ host?: string;
5
+ /** Set for a pod service — a backend, never a page the client runtime runs in. */
6
+ service?: string;
7
+ }
8
+ /**
9
+ * Every frontend `host` the gateway routes, as an allowlist entry. Pod services are skipped (backends,
10
+ * not pages); a wildcard host (`*.shop.local`) becomes the subdomain form (`.shop.local`).
11
+ */
12
+ export declare function clusterPageHosts(decls: readonly ClusterPageDecl[]): string[];
13
+ /** `existing` (a caller's own allowlist) plus `hosts`, comma-joined and de-duplicated; undefined when both are empty. */
14
+ export declare function withBridgeAllowedOrigins(existing: string | undefined, hosts: readonly string[]): string | undefined;
15
+ /** The declarations in the given `project.json` files; unreadable ones are skipped. */
16
+ export declare function readClusterPageDecls(projectFiles: readonly string[]): ClusterPageDecl[];
@@ -0,0 +1 @@
1
+ "use strict";var c=Object.defineProperty;var s=(t,e)=>c(t,"name",{value:e,configurable:!0});var a=Object.defineProperty,i=s((t,e)=>a(t,"name",{value:e,configurable:!0}),"n");import{readFileSync as l}from"node:fs";export function clusterPageHosts(t){const e=new Set;for(const r of t){if(r.service||typeof r.host!="string")continue;const o=r.host.trim().toLowerCase();o&&e.add(o.startsWith("*.")?o.slice(1):o)}return[...e]}s(clusterPageHosts,"clusterPageHosts"),i(clusterPageHosts,"clusterPageHosts");export function withBridgeAllowedOrigins(t,e){const r=[...new Set([...(t??"").split(/[\s,]+/).filter(Boolean),...e])];return r.length>0?r.join(","):void 0}s(withBridgeAllowedOrigins,"withBridgeAllowedOrigins"),i(withBridgeAllowedOrigins,"withBridgeAllowedOrigins");export function readClusterPageDecls(t){const e=[];for(const r of t)try{const o=JSON.parse(l(r,"utf8")),n=o.cluster??o.davnx;n&&typeof n=="object"&&e.push(n)}catch{}return e}s(readClusterPageDecls,"readClusterPageDecls"),i(readClusterPageDecls,"readClusterPageDecls");
package/lib/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var os=Object.defineProperty;var p=(t,n)=>os(t,"name",{value:n,configurable:!0});var rs=Object.defineProperty,d=p((t,n)=>rs(t,"name",{value:n,configurable:!0}),"d");import{spawn as is,spawnSync as M}from"node:child_process";import{existsSync as S,mkdirSync as Z,openSync as as,readFileSync as V,readdirSync as ce,realpathSync as cs,rmSync as ls,statSync as Re,writeFileSync as q}from"node:fs";import{request as Ae}from"node:http";import{homedir as ds,tmpdir as us}from"node:os";import{basename as le,dirname as _,isAbsolute as ps,join as m,relative as Ie,resolve as L}from"node:path";import{fileURLToPath as gs}from"node:url";import{ensureLensConfig as z,readLensConfig as hs}from"./workspace-scope.js";import{commandUsage as fs,onOutputBroken as ms,wantsHelp as ws}from"./cli-help.js";import{splitLintArgs as ys}from"./lint-args.js";import{decideRecycle as vs,hashConfig as ks}from"./recycle-policy.js";import{planMcpRestart as _e}from"./mcp-restart.js";import{detectDuplicateRegistration as $s,disabledMcpServers as De,mcpServerNames as Fe,pluginEnabledInSettings as Ke}from"./duplicate-registration.js";import{readTrackedPid as bs,stillSameProcess as Cs,writeTrackedPid as Ge}from"./process-identity.js";import{remember as xs,shouldAnnounce as Ss}from"./hook-memory.js";import{isMcpMode as Ve}from"./mcp-mode.js";import{effectiveMcpMode as js,LENS_CONFIG as Ns,probeIdentitySync as He,probeSharedMcp as Be,probeSharedMcpSync as Ps,readMcpWiring as te,wireMcpMode as Es}from"./mcp-wiring.js";import{sweepLensRuntimeFiles as Je}from"./sweep.js";import{candidateSignals as Ts,findingLine as Ms,findingsDigest as Ls,formatContext as Os,hookPayload as We,isHookEvent as Ue,select as Rs}from"./status-policy.js";import{DEFAULT_BUDGET_MS as As,readStatus as Is,withLensSession as _s}from"./status-client.js";import{DISMISS_USAGE as Ds,parseDismissArgs as Fs,runDismissCommand as Ks}from"./dismiss-command.js";import{otherCheckoutLines as qe,refusalMessage as de,registrationState as ze}from"./gateway-registration.js";import{detectSkew as Gs,formatSkewContext as Ye,readInstalledPlugin as Xe,readInstalledPlugins as Ze,readVersions as Qe,spawnRunner as Vs,syncPlugin as Hs,updateCommands as Bs}from"./plugin-version.js";import{AGENTS as et,agentById as Js,codexInstalledVersion as Ws,installAgentPlugin as Us,MARKETPLACE as qs,PLUGIN_ID as Q,readPluginManifestVersion as zs,resolvePluginRoot as tt,spawnAgentRunner as st}from"./agent-plugins.js";import{detectGlobalInstall as Ys,daemonVerdict as Xs,detectPackageManager as Zs,installLanded as nt,lensPackagesIn as Qs,missingFromRegistry as en,needsInstall as tn,planRestart as sn,readConnectedWorkspaces as nn,registryAnswer as on,rewriteLensmcpDeps as rn,setupReminder as an}from"./upgrade.js";const ue=`lensmcp \u2014 CLI for LensMCP (FrontMCP-based observability for coding agents)
1
+ "use strict";var ys=Object.defineProperty;var h=(t,n)=>ys(t,"name",{value:n,configurable:!0});var vs=Object.defineProperty,l=h((t,n)=>vs(t,"name",{value:n,configurable:!0}),"l");import{spawn as ks,spawnSync as R}from"node:child_process";import{existsSync as P,mkdirSync as Q,readFileSync as B,readdirSync as le,realpathSync as $s,rmSync as bs,statSync as Ge,writeFileSync as q}from"node:fs";import{request as Be}from"node:http";import{homedir as Cs,tmpdir as Ss}from"node:os";import{basename as ue,dirname as _,isAbsolute as xs,join as w,relative as Ve,resolve as L}from"node:path";import{fileURLToPath as He,pathToFileURL as js}from"node:url";import{ensureLensConfig as Y,readLensConfig as ve}from"./workspace-scope.js";import{commandUsage as Ns,onOutputBroken as Ps,wantsHelp as Es}from"./cli-help.js";import{splitLintArgs as Ms}from"./lint-args.js";import{decideRecycle as Ls,hashConfig as Ts}from"./recycle-policy.js";import{planMcpRestart as We}from"./mcp-restart.js";import{detectDuplicateRegistration as Rs,disabledMcpServers as Ue,mcpServerNames as Je,pluginEnabledInSettings as ze}from"./duplicate-registration.js";import{readTrackedPid as Os,stillSameProcess as As,writeTrackedPid as qe}from"./process-identity.js";import{clusterPageHosts as Is,readClusterPageDecls as _s,withBridgeAllowedOrigins as Ds}from"./bridge-origins.js";import{runForwardingSignals as ke}from"./forward-signals.js";import{liveMcpSessions as Fs,registerMcpSession as Ks}from"./mcp-sessions.js";import{dashboardLoginUrl as Ye}from"./dashboard-login.js";import{remember as Gs,shouldAnnounce as Bs}from"./hook-memory.js";import{isMcpMode as Xe,MCP_MODE_SOURCE_LABELS as Ze,MCP_PIN_MIGRATION_NOTICE as $e,mcpModeSwitchHint as pe}from"./mcp-mode.js";import{effectiveMcpMode as Vs,LENS_CONFIG as Hs,migrateUnchosenMcpModePin as be,probeIdentitySync as Qe,probeSharedMcp as et,probeSharedMcpSync as Ws,readMcpWiring as ne,wireMcpMode as Us}from"./mcp-wiring.js";import{openGatewayLog as Js,secureLensLogs as zs,sweepLensRuntimeFiles as qs}from"./sweep.js";import{candidateSignals as Ys,findingLine as Xs,findingsDigest as Zs,formatContext as Qs,hookPayload as tt,isHookEvent as st,select as en}from"./status-policy.js";import{DEFAULT_BUDGET_MS as tn,readStatus as sn,withLensSession as nn}from"./status-client.js";import{readServiceMemory as on,runMemCommand as rn}from"./mem-command.js";import{inspectBundle as an,sourceMapVerdict as cn}from"./pod-source-maps.js";import{perfRulesVerdict as dn,readPerfFindings as ln}from"./perf-rules-check.js";import{DISMISS_USAGE as un,parseDismissArgs as pn,runDismissCommand as hn}from"./dismiss-command.js";import{otherCheckoutLines as nt,refusalMessage as he,registrationState as ot}from"./gateway-registration.js";import{controlRequest as gn,graphVerdictLine as Ce,registrationGraphFields as fn}from"./guest-graph.js";import{locateServerBundle as mn,MCP_SERVER_PROJECT as wn,serverBundleNotFound as rt}from"./server-bundle.js";import{detectSkew as yn,formatSkewContext as it,readInstalledPlugin as at,readInstalledPlugins as ct,readVersions as dt,spawnRunner as vn,syncPlugin as kn,updateCommands as $n}from"./plugin-version.js";import{AGENTS as lt,agentById as bn,codexInstalledVersion as Cn,installAgentPlugin as Sn,MARKETPLACE as xn,PLUGIN_ID as ee,readPluginManifestVersion as jn,resolvePluginRoot as ut,spawnAgentRunner as pt}from"./agent-plugins.js";import{detectGlobalInstall as Nn,daemonVerdict as Pn,detectPackageManager as En,installLanded as ht,lensPackagesIn as Mn,missingFromRegistry as Ln,needsInstall as Tn,planRestart as Rn,readConnectedWorkspaces as On,registryAnswer as An,rewriteLensmcpDeps as In,setupReminder as _n}from"./upgrade.js";const ge=`lensmcp \u2014 CLI for LensMCP (FrontMCP-based observability for coding agents)
2
2
 
3
3
  Usage:
4
4
  lensmcp <command> [options]
@@ -20,27 +20,33 @@ Commands:
20
20
  other workspaces' pods are never touched. sudo self-prompts
21
21
  only for the steps that need it \u2014 run in a real terminal.
22
22
  Then \`lensmcp gateway start\`.
23
- --mcp picks how each agent session serves the lens
24
- (.mcp.json is NOT changed either way):
25
- embedded (default) every session builds its own MCP
23
+ --mcp persists how each agent session serves the lens
24
+ into .lensmcp/config.json, as your choice (\`modeSource:
25
+ "user"\`; .mcp.json is NOT changed either way); without
26
+ it, setup leaves a choice alone \u2014 an \`embedded\` pin an
27
+ older setup wrote on its own moves to the default, once:
28
+ shared (default) \`lensmcp mcp\` is a thin stdio shim
29
+ into ONE shared server per workspace (this
30
+ workspace's own \`ports.mcpHttp\`), starting it on
31
+ demand and reconnecting across restarts, so an
32
+ upgrade reaches live sessions. N sessions cost
33
+ one server plus N pipes. Falls back to an
34
+ embedded server if the shared one cannot be
35
+ started or attached.
36
+ embedded the opt-out: every session builds its own MCP
26
37
  server in-process, and a session started before
27
38
  an upgrade keeps serving the OLD bundle until it
28
39
  exits \u2014 measured at 2+ days on one machine.
29
- shared \`lensmcp mcp\` becomes a thin stdio shim into
30
- ONE shared server per workspace (this workspace's
31
- own \`ports.mcpHttp\`), starting it on demand and
32
- reconnecting across restarts. N sessions cost one
33
- server plus N pipes. Falls back to embedded if
34
- the shared server cannot be reached.
35
40
  mcp [--cwd <dir>] [--transport stdio|http] [--port <n>] [--mcp embedded|shared]
36
41
  Launch the LensMCP MCP server. Default transport is
37
42
  stdio (set LENSMCP_TRANSPORT=http or pass --transport
38
43
  for HTTP on --port, which defaults to this workspace's
39
- derived \`ports.mcpHttp\`). With --mcp shared (or
40
- LENSMCP_MCP_MODE=shared, or \`mcp.mode\` in
41
- .lensmcp/config.json) the stdio process is a thin SHIM
42
- into the workspace's one shared server instead of a full
43
- in-process server.
44
+ derived \`ports.mcpHttp\`). Over stdio it is, by default,
45
+ a thin SHIM, run in this process, into the workspace's
46
+ one shared server (started on demand; an embedded
47
+ server if that fails). --mcp embedded (or
48
+ LENSMCP_MCP_MODE=embedded, or \`lensmcp setup --mcp
49
+ embedded\`) builds a full server instead.
44
50
  dashboard [--cwd <dir>] [--port <n>] [--base <path>]
45
51
  Serve a live web view of the lens (flows, signals,
46
52
  stories, status). Port defaults to the per-workspace
@@ -131,9 +137,12 @@ Commands:
131
137
  doctor [--cwd <dir>] [--json]
132
138
  Diagnose the install: Node, workspace + plugin,
133
139
  .mcp.json server entry, MCP bundle, per-project
134
- vite/nest wiring, agent-dev targets, and Chrome for
135
- browser capture. \`--json\` emits a machine-readable
136
- report (for the agent). Exits non-zero on errors.
140
+ vite/nest wiring, agent-dev targets, Chrome for
141
+ browser capture, and \u2014 for every running service \u2014 an
142
+ eval devtool with source maps keeping its bundle in
143
+ memory as text several times. \`--json\` emits a
144
+ machine-readable report (for the agent). Exits
145
+ non-zero on errors.
137
146
  prune [--cwd <dir>] [--force]
138
147
  Reclaim this workspace's .lensmcp bus files \u2014 legacy
139
148
  \`.old\` files, generations past the retention horizon,
@@ -191,39 +200,41 @@ Commands:
191
200
  SIGUSR1). Then attach WebStorm (Attach to Node.js/
192
201
  Chrome) to the printed port, or click the "Debugger
193
202
  listening" link in \`lensmcp logs <service>\`.
203
+ mem [service] [--snapshot [--pod <id>] [--analyze]] [--file <snapshot> --analyze] [--top <n>] [--all] [--json] [--cwd <dir>]
204
+ What each pod of a running service weighs: its heap
205
+ after a full GC, reserved heap, rss, boot baseline and
206
+ swaps \u2014 and any closed hot-swap generation it has
207
+ proven is still in memory. No <service> tables every
208
+ service of this workspace (--all: every workspace).
209
+ --snapshot makes ONE pod write a heap snapshot of itself
210
+ (no inspector port; a 0600 file under .lensmcp/heap/,
211
+ refused above LENSMCP_HEAP_SNAPSHOT_MAX_MB or when the
212
+ machine is short of memory); --analyze reads it in a
213
+ separate, capped process: the largest retainers, bytes
214
+ by package/module, and the shortest path that keeps a
215
+ closed generation alive. Reads the control socket.
194
216
  --version Print the lensmcp version.
195
217
  --help Show this help.
196
- `;export async function runCli(t){const n=t.out??(r=>console.log(r)),e=t.err??(r=>console.error(r)),[s,...o]=t.argv;if(!s||s==="--help"||s==="-h")return n(ue),{exitCode:0};if(s==="--version"||s==="-V")return n(X()),{exitCode:0};if(ws(o,s))return n(fs(ue,s)??ue),{exitCode:0};switch(s){case"setup":return xt(t,o,n,e);case"mcp":return it(t,o,n,e);case"dashboard":return at(t,o,n,e);case"gateway":return we(t,o,n,e);case"bridge":return yt(t,o,n,e);case"install":return be(t,o,n,e);case"plugin":case"plugins":return _t(t,o,n,e);case"upgrade":return Gt(t,o,n,e);case"trust":return Ce(t,o,n,e);case"status":return St(t,o,n);case"version-check":return jt(t,o,n);case"doctor":return Nt(t,o,n);case"prune":return ot(t,o,n,e);case"rollout":return Bt(t,o,e);case"logs":return ts(t,o,n,e);case"dismiss":return vt(t,o,n,e);case"lint":return kt(t,o,e);case"debug":return ss(t,o,n,e);default:return e(`Unknown command: ${s}`),e(ue),{exitCode:2,message:`Unknown command: ${s}`}}}p(runCli,"runCli"),d(runCli,"runCli");function ot(t,n,e,s){const o=I(n,{string:["--cwd"],boolean:["--force"]}),r=L(b(o.flags["--cwd"])??t.cwd),i=m(r,".lensmcp"),c=m(i,"gateway.log"),l=d(()=>{try{return ce(i).reduce((f,w)=>{try{return f+Re(m(i,w)).size}catch{return f}},0)}catch{return 0}},"dirBytes"),a=d(f=>`${(f/1048576).toFixed(1)} MB`,"mb"),u=l();if(u===0)return e(`nothing to prune \u2014 no .lensmcp runtime files at ${i}`),{exitCode:0};if(o.flags["--force"]!==!0&&rt(i))return s("a gateway is running for this workspace \u2014 pruning now can drop a generation a live"),s("writer is still counting (issues/foodguard/13). Stop it first:"),s(" lensmcp gateway stop"),s("\u2026or pass --force if you accept losing recent history."),{exitCode:1,message:"gateway running"};Je(r,c);const h=l();return e(`pruned ${i}`),e(` ${a(u)} \u2192 ${a(h)} (reclaimed ${a(Math.max(0,u-h))})`),{exitCode:0}}p(ot,"at"),d(ot,"runPrune");function rt(t){try{return ve(m(t,"gateway.pid"))!==void 0}catch{return!1}}p(rt,"ct"),d(rt,"gatewayPidAlive");function it(t,n,e,s){const o=I(n,{string:["--cwd","--transport","--port","--mcp"]}),r=L(b(o.flags["--cwd"])??t.cwd),i=z(r),c=b(o.flags["--transport"])??t.env?.LENSMCP_TRANSPORT??"stdio",l=b(o.flags["--port"])??t.env?.LENSMCP_PORT??String(i.ports.mcpHttp),a=js(r,b(o.flags["--mcp"]),{...process.env,...t.env??{}})==="shared"&&c==="stdio",u=a?Wt(r)??ge(r):ge(r);if(!u)return s(`Could not locate the lensmcp-mcp server bundle.
197
- Looked in (in order):
198
- \u2022 <cli-package>/bundled/main.js (published bin)
199
- \u2022 <workspace>/apps/lensmcp-mcp/dist/main.js (dev build)
200
- For dev: \`yarn nx build @lensmcp/lensmcp-mcp\`.`),{exitCode:1};ae(r);const h=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??m(r,".lensmcp","events.jsonl"),f={...process.env,...t.env??{},LENSMCP_TRANSPORT:c,LENSMCP_PORT:l,LENSMCP_EVENT_FILE:h},w=a?[u,"--cwd",r]:[u];return{exitCode:M(process.execPath,w,{cwd:r,stdio:"inherit",env:f}).status??1}}p(it,"dt"),d(it,"runMcp");function at(t,n,e,s){const o=I(n,{string:["--cwd","--port","--base"]}),r=L(b(o.flags["--cwd"])??t.cwd),i=z(r),c=b(o.flags["--port"])??t.env?.LENSMCP_DASHBOARD_PORT??String(i.ports.dashboard),l=b(o.flags["--base"])??t.env?.LENSMCP_DASHBOARD_BASE??"",a=he(r,"dashboard.js");if(!a)return s(`Could not locate the lensmcp dashboard bundle.
201
- Looked in (in order):
202
- \u2022 <cli-package>/bundled/dashboard.js (published bin)
203
- \u2022 <workspace>/servers/lensmcp-mcp/dist/dashboard.js (dev build)
204
- For dev: \`yarn nx build @lensmcp/lensmcp-mcp\`.`),{exitCode:1};ae(r);const u=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??m(r,".lensmcp","events.jsonl");return e(`lensmcp dashboard \u2192 http://localhost:${c}${l||"/"} (reading ${u})`),{exitCode:M(process.execPath,[a],{cwd:r,stdio:"inherit",env:{...process.env,...t.env??{},LENSMCP_DASHBOARD_PORT:c,LENSMCP_DASHBOARD_BASE:l,LENSMCP_EVENT_FILE:u}}).status??1}}p(at,"lt"),d(at,"runDashboard");function ct(){return m(process.env.LENSMCP_HOME||ds(),".lensmcp","control.sock")}p(ct,"pt"),d(ct,"controlSocketPath");function A(t,n,e){const s=ct();if(!S(s))return null;const o=["-s","-o","-","-w",`
205
- %{http_code}`,"--unix-socket",s,"-X",t,`http://localhost${n}`];e!==void 0&&o.push("-H","content-type: application/json","-d",JSON.stringify(e));const r=M("curl",o,{encoding:"utf8",timeout:5e3});if(r.status!==0||typeof r.stdout!="string"||r.stdout.length===0)return null;const i=r.stdout.split(`
206
- `),c=Number(i.pop());let l=null;try{const a=i.join(`
207
- `).trim();l=a?JSON.parse(a):null}catch{}return Number.isFinite(c)?{status:c,json:l}:null}p(A,"A"),d(A,"daemonRequest");function lt(){const t=A("GET","/status");if(t?.status!==200||!t.json||typeof t.json!="object")return;const n=t.json.daemon;return typeof n?.wsKey=="string"&&n.wsKey.length>0?n.wsKey:void 0}p(lt,"ut"),d(lt,"daemonWsKey");function dt(t){const n={};for(const e of U(t,s=>s==="project.json"))try{const s=JSON.parse(V(e,"utf8")),o=_(e);n[s.name??le(o)]={root:Ie(t,o)||"."}}catch{}return n}p(dt,"ft"),d(dt,"buildProjectsMap");function ut(t){const n=m(t,"node_modules",".bin",process.platform==="win32"?"nx.cmd":"nx");if(!S(n))return;const e=M(n,["graph","--print"],{cwd:t,encoding:"utf8",timeout:15e3,maxBuffer:32*1024*1024});if(!(e.status!==0||typeof e.stdout!="string"))try{const s=JSON.parse(e.stdout).graph?.dependencies;return s?Object.fromEntries(Object.entries(s).map(([o,r])=>[o,r.flatMap(i=>typeof i.target=="string"?[i.target]:[])])):void 0}catch{return}}p(ut,"gt"),d(ut,"buildProjectDependencies");function pe(t,n){const e=ut(t);return{wsKey:n,root:t,projects:dt(t),...e?{projectDependencies:e}:{}}}p(pe,"ue"),d(pe,"gatewayRegistrationBody");function we(t,n,e,s){const o=I(n,{string:["--cwd","--project","--target"]}),r=(o.positional[0]??"status").toLowerCase(),i=n.includes("--json"),c=L(b(o.flags["--cwd"])??t.cwd),l=z(c),a=m(c,".lensmcp","gateway.pid"),u=m(c,".lensmcp","gateway.log"),h=m(c,".lensmcp","registered.json"),f=`https://lensmcp.local${l.dashboardBasePath}/`,w=d(()=>{const{pid:v,healed:E}=oe(a,c);if(v!==void 0&&ne(v)){const O=classifyAliveGateway({oursOn443:B(c)!==void 0,port443Held:H().length>0,pidFileAgeMs:ke(a)});if(O==="serving")return E&&e(`healed: adopted a running gateway (pid ${v}) the pid file had lost \u2014 no duplicate started.`),e(`gateway already running (pid ${v}).`),e(` dashboard \u2192 ${f}`),{exitCode:0};if(O==="booting")return e(`gateway starting (pid ${v}) \u2014 :443 not bound yet.`),e(` dashboard \u2192 ${f}`),e(` logs \u2192 ${u}`),{exitCode:0};re(v,"SIGKILL"),W(a),se(c,t.env,()=>{}),e(`reaped a dead gateway (pid ${v} was alive but nothing served :443 for this workspace).`)}const g=H()[0];if(g!==void 0){const O=A("GET","/list");if(O!==null){const F=O.status===200&&O.json&&typeof O.json=="object"?O.json.workspaces??[]:[],j=ze(F,l.key,c);if(j.kind==="other-checkout"){for(const K of qe(l.key,j.root,c))s(K);return{exitCode:1}}if(j.kind==="mine")return Z(_(h),{recursive:!0}),q(h,JSON.stringify({wsKey:l.key})),e(`already registered into the shared gateway daemon (pid ${g}).`),e(` dashboard \u2192 ${f}`),{exitCode:0};const P=A("POST","/register",pe(c,l.key));return P&&P.status===200?(Z(_(h),{recursive:!0}),q(h,JSON.stringify({wsKey:l.key})),e(`registered '${l.key}' into the shared gateway daemon (pid ${g}).`),e(` dashboard \u2192 ${f}`),e(" the daemon hosts this workspace's services + dashboard; `lensmcp gateway stop` unregisters."),{exitCode:0}):(s(`failed to register into the gateway daemon: ${de(P)??(P?JSON.stringify(P.json):"no response from the control socket")}`),{exitCode:1})}return s(`port :443 is held by pid ${g}, which is not this workspace's gateway.
208
- Free it first (stop that process), then \`lensmcp gateway start\`.`),{exitCode:1}}const y=pt(c,b(o.flags["--project"]),b(o.flags["--target"]));if(!y)return s(`This workspace ('${l.key}') has no gateway target \u2014 no project declares the`),s("`@lensmcp/cluster:gateway` executor, so there is nothing here to launch on :443."),s(""),s(" \u2022 Joining a shared gateway? Start it in the workspace that OWNS it, then run"),s(" `lensmcp gateway start` here \u2014 this workspace registers into it (no local target needed)."),s(" \u2022 Should this workspace host its own gateway? Scaffold it: `lensmcp install`"),s(" (or `lensmcp setup` for the full install + trust bootstrap)."),s(" \u2022 Already have a differently-named target? `lensmcp gateway start --project <p> --target <t>`."),{exitCode:1};const x=ie(c);if(!x)return s("Could not find the `nx` binary in the workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};Je(c,u);const N=as(u,"a"),R=is(x,["run",`${y.project}:${y.target}`],{cwd:c,detached:!0,stdio:["ignore",N,N],env:{...process.env,...t.env??{}}});return R.unref(),R.pid&&Ge(a,R.pid),e(`gateway starting \u2192 ${y.project}:${y.target} (pid ${R.pid??"?"})`),e(` dashboard \u2192 ${f}`),e(` logs \u2192 ${u}`),e(" note: binding :443 needs privilege \u2014 if it fails, run the gateway target with sudo,"),e(" and run `nx run gateway:trust` once for the *.local hosts + TLS."),{exitCode:0}},"start"),k=d(()=>{if(S(h)&&B(c)===void 0){let x=l.key;try{x=JSON.parse(V(h,"utf8")).wsKey??l.key}catch{}const N=A("POST","/unregister",{wsKey:x,root:c});W(h);const R=de(N);return e(R??(N&&N.status===200?`unregistered '${x}' from the shared gateway daemon.`:"unregister sent (the daemon may already be gone).")),{exitCode:0}}W(h);const{pid:v,healed:E}=oe(a,c);if(v===void 0)return e("gateway not running."),W(a),{exitCode:0};E&&e(`healed: found an orphaned gateway (pid ${v}) the pid file had lost \u2014 stopping it.`),re(v);let g=!1;if(!$e(6e3)){g=!0,re(v,"SIGKILL");const x=B(c);if(x!==void 0)try{process.kill(x,"SIGKILL")}catch{}else H().length>0&&e(":443 is still held by a process that is not this workspace's gateway \u2014 leaving it alone.");$e(3e3)}const y=B(c);return y!==void 0&&y!==v&&(re(y,"SIGKILL"),g=!0),W(a),g&&se(c,t.env,()=>{}),e(`gateway stopped (pid ${v})${g?" \u2014 forced (a child ignored SIGTERM)":""}.`),{exitCode:0}},"stop"),$=d(()=>{const{pid:v,healed:E}=oe(a,c),g=v!==void 0&&ne(v)?classifyAliveGateway({oursOn443:B(c)!==void 0,port443Held:H().length>0,pidFileAgeMs:ke(a)}):void 0,y=g==="serving"||g==="booting";if(i){const j=A("GET","/status"),P=j?.status===200&&j.json&&typeof j.json=="object"?j.json:null,K=S(h),ns=y?"daemon":P&&K?"guest":P?"other":"stopped";return e(JSON.stringify({thisWorkspace:l.key,role:ns,dashboardUrl:f,chooserUrl:"https://lensmcp.local/",logFile:u,daemonLogFile:(()=>{const me=je();return me&&me!==c?m(me,".lensmcp","gateway.log"):u})(),mcp:Ne(c,t.env??process.env),daemon:P?.daemon??null,workspaces:P?.workspaces??[],services:P?.services??[]})),{exitCode:y||P&&K?0:1}}const x=A("GET","/list"),N=x?.status===200&&x.json&&typeof x.json=="object"?x.json.workspaces??[]:[],R=d(()=>{if(N.length!==0){e(` workspaces (${N.length} registered):`);for(const j of N)e(` \u2022 ${j.key} (${j.routes??0} routes, ${j.services??0} services)${j.key===l.key?" \u2190 this workspace":""}`)}},"printWorkspaces"),O=d(()=>{const j=Ne(c,t.env??process.env);e(j.mode==="shared"?` mcp \u2192 shared ${j.url} ${j.healthy?"(up)":`(DOWN \u2014 ${j.error??"no answer"})`}`:" mcp \u2192 stdio (one server per agent session)")},"printMcp"),F=d(()=>{const j=A("GET","/status"),P=j?.status===200&&j.json&&typeof j.json=="object"?j.json.daemon:void 0,K=G(c);P?.version&&K&&P.version!==K&&e(` version \u2192 the daemon runs ${P.version} but this workspace depends on ${K} \u2014 \`lensmcp upgrade\` reconciles everything (or restart the daemon workspace's gateway).`)},"printVersionSkew");if(y)return e(g==="booting"?`gateway: starting (pid ${v}) \u2014 :443 not bound yet`:`gateway: running (pid ${v}) \u2014 DAEMON on :443${E?" \u2014 recovered a stale pid file":""}`),e(` workspace \u2192 ${l.key}`),e(` dashboard \u2192 ${f}`),e(" chooser \u2192 https://lensmcp.local/"),e(` logs \u2192 ${u}`),O(),F(),R(),{exitCode:0};if(S(h)&&x?.status===200){const j=H()[0];e(`gateway: registered into a shared daemon${j!==void 0?` (pid ${j})`:""} \u2014 this workspace is a guest`),e(` workspace \u2192 ${l.key}`),e(` dashboard \u2192 ${f}`),e(` logs \u2192 ${u} (this workspace's pods)`);const P=je();return P&&P!==c&&e(` ${m(P,".lensmcp","gateway.log")} (the daemon's own log \u2014 gateway-level lines land there)`),e(" attach \u2192 `lensmcp logs <service>` (live, from any workspace)"),e(" stop \u2192 `lensmcp gateway stop` (unregisters; the daemon keeps running)"),O(),F(),R(),{exitCode:0}}return g==="zombie"?(e(`gateway: NOT serving \u2014 tracked pid ${v} is alive but nothing holds :443 for this workspace`),e(" (a crashed gateway under a wedged nx wrapper) \u2014 run `lensmcp gateway restart` to recover."),e(` workspace \u2192 ${l.key}`),e(` logs \u2192 ${u}`),O(),R(),{exitCode:1}):(e("gateway: stopped"),e(` workspace \u2192 ${l.key}`),e(` dashboard \u2192 ${f}`),O(),{exitCode:1})},"status"),C=d(()=>{const v=A("GET","/status");if(v?.status!==200||!v.json||typeof v.json!="object")return e(i?JSON.stringify({daemon:null,workspaces:[],services:[]}):"gateway: no daemon answers on the control socket \u2014 nothing is hosted."),{exitCode:1};const E=v.json;if(i)return e(JSON.stringify(E)),{exitCode:0};e(`daemon: pid ${E.daemon?.pid??"?"} \xB7 owner ${E.daemon?.wsKey??"?"}${E.daemon?.version?` \xB7 lensmcp ${E.daemon.version}`:""}`);for(const g of E.workspaces??[]){e(` ${g.isDaemon?"\u2605":"\xB7"} ${g.key.padEnd(16)} ${String(g.routes??0).padStart(3)} routes ${String(g.services??0).padStart(3)} services ${g.root??""}`);for(const y of(E.services??[]).filter(x=>(x.wsKey??E.daemon?.wsKey)===g.key))e(` ${y.project.padEnd(16)} ${(y.state??"unknown").padEnd(9)} ${y.host??""}`)}return{exitCode:0}},"list");switch(r){case"start":return w();case"stop":return k();case"list":return C();case"restart":return k(),se(c,t.env,e),w();case"status":return $();default:return s(`Unknown gateway subcommand: ${r} (use start | stop | status | restart | list)`),{exitCode:2}}}p(we,"Ke"),d(we,"runGateway");function se(t,n,e){const s=ie(t);if(!s){e(" (graph refresh skipped \u2014 no nx binary found in the workspace)");return}const o={...process.env,...n??{}},r=d(i=>M(s,i,{cwd:t,env:o,stdio:"ignore"}).status===0,"tryNx");if(r(["reset","--only-daemon"])||r(["daemon","--stop"])){e(" nx project graph refreshed \u2014 a lib/app added since boot will now resolve.");return}e(" (graph refresh best-effort failed \u2014 if a new project does not resolve, run `nx reset`)")}p(se,"oe"),d(se,"refreshNxGraph");function ye(t,n,e,s){if(e&&s)return{project:e,target:s};const o=U(t,r=>r==="project.json");for(const r of o){let i;try{i=JSON.parse(D(r))}catch{continue}const c=i.name??le(_(r));for(const[l,a]of Object.entries(i.targets??{}))if(a.executor===n)return{project:e??c,target:s??l}}}p(ye,"Ge"),d(ye,"scanExecutorTarget");function pt(t,n,e){return ye(t,"@lensmcp/cluster:gateway",n,e)||(n||e?{project:n??"gateway",target:e??"serve"}:void 0)}p(pt,"ht"),d(pt,"findGatewayTarget");function gt(t,n,e){return ye(t,"@lensmcp/cluster:trust",n,e)||(n?{project:n,target:e??"trust"}:ht(t,"gateway")?{project:"gateway",target:e??"trust"}:void 0)}p(gt,"mt"),d(gt,"findTrustTarget");function ht(t,n){for(const e of U(t,s=>s==="project.json"))try{if((JSON.parse(D(e)).name??le(_(e)))===n)return!0}catch{}return!1}p(ht,"wt"),d(ht,"projectExists");function ve(t){const n=bs(t);if(n)return Cs(n.pid,n.stamp)?n.pid:void 0}p(ve,"He"),d(ve,"readPid");function ne(t){try{return process.kill(t,0),!0}catch(n){return n.code==="EPERM"}}p(ne,"ie"),d(ne,"isAlive");function H(){try{const t=M("lsof",["-nP","-iTCP:443","-sTCP:LISTEN","-t"],{encoding:"utf8"});return t.status!==0||!t.stdout?[]:[...new Set(t.stdout.split(/\s+/).map(Number).filter(n=>Number.isInteger(n)&&n>0))]}catch{return[]}}p(H,"V"),d(H,"pidsOnPort443");function ft(t){try{return(M("ps",["-o","command=","-p",String(t)],{encoding:"utf8"}).stdout??"").trim()}catch{return""}}p(ft,"yt"),d(ft,"processCmd");function B(t){const n=m(t,"node_modules","nx","dist","bin","run-executor.js"),e=m(t,"node_modules","@lensmcp","cluster");for(const s of H()){const o=ft(s);if(o.includes(n)||o.includes(e))return s}}p(B,"B"),d(B,"gatewayOnPort443");function ke(t){try{return Date.now()-Re(t).mtimeMs}catch{return}}p(ke,"Ve"),d(ke,"pidFileAgeMs");const cn=18e4;export function classifyAliveGateway(t){if(t.oursOn443)return"serving";const n=t.pidFileAgeMs!==void 0&&t.pidFileAgeMs<(t.bootGraceMs??cn);return!t.port443Held&&n?"booting":"zombie"}p(classifyAliveGateway,"classifyAliveGateway"),d(classifyAliveGateway,"classifyAliveGateway");function oe(t,n){const e=ve(t);if(e!==void 0&&ne(e))return{pid:e,healed:!1};const s=B(n);if(s!==void 0){try{Ge(t,s)}catch{}return{pid:s,healed:!0}}return{healed:!1}}p(oe,"ae"),d(oe,"reconcileGateway");function re(t,n="SIGTERM"){try{process.kill(-t,n)}catch{try{process.kill(t,n)}catch{}}}p(re,"ce"),d(re,"killGatewayTree");function $e(t){const n=Date.now()+t;for(;;){if(H().length===0)return!0;if(Date.now()>=n)return!1;M("sleep",["0.15"])}}p($e,"Be"),d($e,"waitForPortFree");function mt(t){const n=M("curl",["-s","-o","/dev/null","-m","8","-w","%{ssl_verify_result}",`https://${t}/`],{encoding:"utf8"}),e=(n.stdout??"").trim();return n.status===0&&e==="0"?"trusted":e&&e!=="0"?"untrusted":"unknown"}p(mt,"kt"),d(mt,"probeHostTrust");function wt(t){for(const n of U(t,e=>e==="project.json"))try{const e=JSON.parse(V(n,"utf8")),s=(e.cluster??e.davnx)?.host;if(s&&!s.includes("*"))return s}catch{}}p(wt,"$t"),d(wt,"firstClusterHost");function W(t){try{ls(t,{force:!0})}catch{}}p(W,"U"),d(W,"rmFile");function yt(t,n,e,s){const o=I(n,{string:["--cwd","--host","--port"]}),r=L(b(o.flags["--cwd"])??t.cwd),i=z(r),c=b(o.flags["--host"])??t.env?.LENSMCP_WS_HOST??process.env.LENSMCP_WS_HOST,l=b(o.flags["--port"])??t.env?.LENSMCP_WS_PORT??process.env.LENSMCP_WS_PORT??String(i.ports.bridge),a=Ut(r);if(!a)return s(`Could not locate the lensmcp bridge bundle.
218
+ `;export async function runCli(t){const n=t.out??(r=>console.log(r)),e=t.err??(r=>console.error(r)),[s,...o]=t.argv;if(!s||s==="--help"||s==="-h")return n(ge),{exitCode:0};if(s==="--version"||s==="-V")return n(Z()),{exitCode:0};if(Es(o,s))return n(Ns(ge,s)??ge),{exitCode:0};switch(s){case"setup":return At(t,o,n,e);case"mcp":return mt(t,o,n,e);case"dashboard":return yt(t,o,n,e);case"gateway":return Se(t,o,n,e);case"bridge":return Et(t,o,n,e);case"install":return Ee(t,o,n,e);case"plugin":case"plugins":return zt(t,o,n,e);case"upgrade":return Zt(t,o,n,e);case"trust":return Me(t,o,n,e);case"status":return It(t,o,n);case"version-check":return _t(t,o,n);case"doctor":return Dt(t,o,n);case"prune":return gt(t,o,n,e);case"rollout":return ts(t,o,e);case"logs":return ps(t,o,n,e);case"dismiss":return Mt(t,o,n,e);case"lint":return Lt(t,o,e);case"debug":return hs(t,o,n,e);case"mem":return gs(t,o,n,e);default:return e(`Unknown command: ${s}`),e(ge),{exitCode:2,message:`Unknown command: ${s}`}}}h(runCli,"runCli"),l(runCli,"runCli");function gt(t,n,e,s){const o=I(n,{string:["--cwd"],boolean:["--force"]}),r=L(b(o.flags["--cwd"])??t.cwd),i=w(r,".lensmcp"),c=w(i,"gateway.log"),d=l(()=>{try{return le(i).reduce((f,m)=>{try{return f+Ge(w(i,m)).size}catch{return f}},0)}catch{return 0}},"dirBytes"),a=l(f=>`${(f/1048576).toFixed(1)} MB`,"mb"),u=d();if(u===0)return e(`nothing to prune \u2014 no .lensmcp runtime files at ${i}`),{exitCode:0};if(o.flags["--force"]!==!0&&ft(i))return s("a gateway is running for this workspace \u2014 pruning now can drop a generation a live"),s("writer is still counting (issues/closed/foodguard-13). Stop it first:"),s(" lensmcp gateway stop"),s("\u2026or pass --force if you accept losing recent history."),{exitCode:1,message:"gateway running"};qs(r,c),zs(r);const p=d();return e(`pruned ${i}`),e(` ${a(u)} \u2192 ${a(p)} (reclaimed ${a(Math.max(0,u-p))})`),{exitCode:0}}h(gt,"Rt"),l(gt,"runPrune");function ft(t){try{return je(w(t,"gateway.pid"))!==void 0}catch{return!1}}h(ft,"Ot"),l(ft,"gatewayPidAlive");async function mt(t,n,e,s){const o=I(n,{string:["--cwd","--transport","--port","--mcp"]}),r=L(b(o.flags["--cwd"])??t.cwd),i=Y(r),c=b(o.flags["--transport"])??t.env?.LENSMCP_TRANSPORT??"stdio",d=b(o.flags["--port"])??t.env?.LENSMCP_PORT??String(i.ports.mcpHttp),a=Vs(r,b(o.flags["--mcp"]),{...process.env,...t.env??{}})==="shared"&&c==="stdio",u=a?ns(r):void 0,p=u??_e(r);if(!p)return s(rt("lensmcp-mcp server bundle","main.js")),{exitCode:1};de(r);const f=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(r,".lensmcp","events.jsonl"),m={...t.env??{},LENSMCP_TRANSPORT:c,LENSMCP_PORT:d,LENSMCP_EVENT_FILE:f};if(u)return{exitCode:await wt(u,r,m)};const v={...process.env,...m};if(c!=="stdio")return{exitCode:await ke({label:`the MCP server (${p})`,args:[p],cwd:r,env:v},s)};const k=a?[p,"--cwd",r]:[p];return{exitCode:R(process.execPath,k,{cwd:r,stdio:"inherit",env:v}).status??1}}h(mt,"_t"),l(mt,"runMcp");async function wt(t,n,e){for(const[o,r]of Object.entries(e))r===void 0?delete process.env[o]:process.env[o]=r;process.chdir(n),process.once("exit",Ks(n));const s=await import(js(t).href);return typeof s.runShim!="function"?new Promise(()=>{}):s.runShim({cwd:n})}h(wt,"At"),l(wt,"runShimInProcess");async function yt(t,n,e,s){const o=I(n,{string:["--cwd","--port","--base"]}),r=L(b(o.flags["--cwd"])??t.cwd),i=Y(r),c=b(o.flags["--port"])??t.env?.LENSMCP_DASHBOARD_PORT??String(i.ports.dashboard),d=b(o.flags["--base"])??t.env?.LENSMCP_DASHBOARD_BASE??"",a=me(r,"dashboard.js");if(!a)return s(rt("lensmcp dashboard bundle","dashboard.js")),{exitCode:1};de(r);const u=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(r,".lensmcp","events.jsonl");return e(`lensmcp dashboard \u2192 http://localhost:${c}${d||"/"} (reading ${u})`),{exitCode:await ke({label:`the dashboard (${a})`,args:[a],cwd:r,env:{...process.env,...t.env??{},LENSMCP_DASHBOARD_PORT:c,LENSMCP_DASHBOARD_BASE:d,LENSMCP_EVENT_FILE:u}},s)}}h(yt,"It"),l(yt,"runDashboard");function vt(){return w(process.env.LENSMCP_HOME||Cs(),".lensmcp","control.sock")}h(vt,"Dt"),l(vt,"controlSocketPath");function A(t,n,e){const s=vt();return P(s)?gn(s,t,n,e):null}h(A,"_"),l(A,"daemonRequest");function kt(){const t=A("GET","/status");if(t?.status!==200||!t.json||typeof t.json!="object")return;const n=t.json.daemon;return typeof n?.wsKey=="string"&&n.wsKey.length>0?n.wsKey:void 0}h(kt,"Ft"),l(kt,"daemonWsKey");function $t(t){const n={};for(const e of W(t,s=>s==="project.json"))try{const s=JSON.parse(B(e,"utf8")),o=_(e);n[s.name??ue(o)]={root:Ve(t,o)||"."}}catch{}return n}h($t,"Kt"),l($t,"buildProjectsMap");function bt(t){const n=w(t,"node_modules",".bin",process.platform==="win32"?"nx.cmd":"nx");if(!P(n))return;const e=R(n,["graph","--print"],{cwd:t,encoding:"utf8",timeout:15e3,maxBuffer:32*1024*1024});if(!(e.status!==0||typeof e.stdout!="string"))try{const s=JSON.parse(e.stdout).graph?.dependencies;return s?Object.fromEntries(Object.entries(s).map(([o,r])=>[o,r.flatMap(i=>typeof i.target=="string"?[i.target]:[])])):void 0}catch{return}}h(bt,"Gt"),l(bt,"buildProjectDependencies");function fe(t,n){return{wsKey:n,root:t,projects:$t(t),...fn(t,()=>bt(t))}}h(fe,"ke"),l(fe,"gatewayRegistrationBody");function Se(t,n,e,s){const o=I(n,{string:["--cwd","--project","--target"]}),r=(o.positional[0]??"status").toLowerCase(),i=n.includes("--json"),c=L(b(o.flags["--cwd"])??t.cwd),d=Y(c),a=w(c,".lensmcp","gateway.pid"),u=w(c,".lensmcp","gateway.log"),p=w(c,".lensmcp","registered.json"),f=`https://lensmcp.local${d.dashboardBasePath}/`,m=l(()=>{const $=Ye(f,c,{...process.env,...t.env??{}});$&&e(` sign in \u2192 ${$} (one use, 10 min \u2014 then this browser stays signed in)`)},"printSignIn"),v=l(()=>{const{pid:$,healed:g}=ie(a,c);if($!==void 0&&re($)){const T=classifyAliveGateway({oursOn443:H(c)!==void 0,port443Held:V().length>0,pidFileAgeMs:Ne(a)});if(T==="serving")return g&&e(`healed: adopted a running gateway (pid ${$}) the pid file had lost \u2014 no duplicate started.`),e(`gateway already running (pid ${$}).`),e(` dashboard \u2192 ${f}`),m(),{exitCode:0};if(T==="booting")return e(`gateway starting (pid ${$}) \u2014 :443 not bound yet.`),e(` dashboard \u2192 ${f}`),m(),e(` logs \u2192 ${u}`),{exitCode:0};ae($,"SIGKILL"),J(a),oe(c,t.env,()=>{}),e(`reaped a dead gateway (pid ${$} was alive but nothing served :443 for this workspace).`)}const y=V()[0];if(y!==void 0){const T=A("GET","/list");if(T!==null){const z=T.status===200&&T.json&&typeof T.json=="object"?T.json.workspaces??[]:[],C=ot(z,d.key,c);if(C.kind==="other-checkout"){for(const K of nt(d.key,C.root,c))s(K);return{exitCode:1}}if(C.kind==="mine")return Q(_(p),{recursive:!0}),q(p,JSON.stringify({wsKey:d.key})),e(`already registered into the shared gateway daemon (pid ${y}).`),e(` dashboard \u2192 ${f}`),m(),{exitCode:0};const E=A("POST","/register",fe(c,d.key));if(E&&E.status===200){Q(_(p),{recursive:!0}),q(p,JSON.stringify({wsKey:d.key})),e(`registered '${d.key}' into the shared gateway daemon (pid ${y}).`),e(` dashboard \u2192 ${f}`);const K=Ce(E.json);return K&&e(K),m(),e(" the daemon hosts this workspace's services + dashboard; `lensmcp gateway stop` unregisters."),{exitCode:0}}return s(`failed to register into the gateway daemon: ${he(E)??(E?JSON.stringify(E.json):"no response from the control socket")}`),{exitCode:1}}return s(`port :443 is held by pid ${y}, which is not this workspace's gateway.
219
+ Free it first (stop that process), then \`lensmcp gateway start\`.`),{exitCode:1}}const S=Ct(c,b(o.flags["--project"]),b(o.flags["--target"]));if(!S)return s(`This workspace ('${d.key}') has no gateway target \u2014 no project declares the`),s("`@lensmcp/cluster:gateway` executor, so there is nothing here to launch on :443."),s(""),s(" \u2022 Joining a shared gateway? Start it in the workspace that OWNS it, then run"),s(" `lensmcp gateway start` here \u2014 this workspace registers into it (no local target needed)."),s(" \u2022 Should this workspace host its own gateway? Scaffold it: `lensmcp install`"),s(" (or `lensmcp setup` for the full install + trust bootstrap)."),s(" \u2022 Already have a differently-named target? `lensmcp gateway start --project <p> --target <t>`."),{exitCode:1};const x=ce(c);if(!x)return s("Could not find the `nx` binary in the workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};const O=Js(c,u),D=ks(x,["run",`${S.project}:${S.target}`],{cwd:c,detached:!0,stdio:["ignore",O,O],env:{...process.env,...t.env??{}}});return D.unref(),D.pid&&qe(a,D.pid),e(`gateway starting \u2192 ${S.project}:${S.target} (pid ${D.pid??"?"})`),e(` dashboard \u2192 ${f}`),m(),e(` logs \u2192 ${u}`),e(" note: binding :443 needs privilege \u2014 if it fails, run the gateway target with sudo,"),e(" and run `nx run gateway:trust` once for the *.local hosts + TLS."),{exitCode:0}},"start"),k=l(()=>{if(P(p)&&H(c)===void 0){let x=d.key;try{x=JSON.parse(B(p,"utf8")).wsKey??d.key}catch{}const O=A("POST","/unregister",{wsKey:x,root:c});J(p);const D=he(O);return e(D??(O&&O.status===200?`unregistered '${x}' from the shared gateway daemon.`:"unregister sent (the daemon may already be gone).")),{exitCode:0}}J(p);const{pid:$,healed:g}=ie(a,c);if($===void 0)return e("gateway not running."),J(a),{exitCode:0};g&&e(`healed: found an orphaned gateway (pid ${$}) the pid file had lost \u2014 stopping it.`),ae($);let y=!1;if(!Pe(6e3)){y=!0,ae($,"SIGKILL");const x=H(c);if(x!==void 0)try{process.kill(x,"SIGKILL")}catch{}else V().length>0&&e(":443 is still held by a process that is not this workspace's gateway \u2014 leaving it alone.");Pe(3e3)}const S=H(c);return S!==void 0&&S!==$&&(ae(S,"SIGKILL"),y=!0),J(a),y&&oe(c,t.env,()=>{}),e(`gateway stopped (pid ${$})${y?" \u2014 forced (a child ignored SIGTERM)":""}.`),{exitCode:0}},"stop"),j=l(()=>{const{pid:$,healed:g}=ie(a,c),y=$!==void 0&&re($)?classifyAliveGateway({oursOn443:H(c)!==void 0,port443Held:V().length>0,pidFileAgeMs:Ne(a)}):void 0,S=y==="serving"||y==="booting";if(i){const C=A("GET","/status"),E=C?.status===200&&C.json&&typeof C.json=="object"?C.json:null,K=P(p),ws=S?"daemon":E&&K?"guest":E?"other":"stopped";return e(JSON.stringify({thisWorkspace:d.key,role:ws,dashboardUrl:f,dashboardLoginUrl:Ye(f,c,{...process.env,...t.env??{}})??null,chooserUrl:"https://lensmcp.local/",logFile:u,daemonLogFile:(()=>{const ye=Re();return ye&&ye!==c?w(ye,".lensmcp","gateway.log"):u})(),mcp:Oe(c,t.env??process.env),daemon:E?.daemon??null,workspaces:E?.workspaces??[],services:E?.services??[]})),{exitCode:S||E&&K?0:1}}const x=A("GET","/list"),O=x?.status===200&&x.json&&typeof x.json=="object"?x.json.workspaces??[]:[],D=l(()=>{if(O.length!==0){e(` workspaces (${O.length} registered):`);for(const C of O)e(` \u2022 ${C.key} (${C.routes??0} routes, ${C.services??0} services)${C.key===d.key?" \u2190 this workspace":""}`)}},"printWorkspaces"),T=l(()=>{const C=Oe(c,t.env??process.env);e(C.mode==="shared"?` mcp \u2192 shared ${C.url} ${C.healthy?"(up)":C.remedy?`(REFUSED \u2014 ${C.error}; ${C.remedy})`:`(DOWN \u2014 ${C.error??"no answer"})`}`:" mcp \u2192 embedded (one server per agent session \u2014 opted out of shared)")},"printMcp"),z=l(()=>{const C=A("GET","/status"),E=C?.status===200&&C.json&&typeof C.json=="object"?C.json.daemon:void 0,K=G(c);E?.version&&K&&E.version!==K&&e(` version \u2192 the daemon runs ${E.version} but this workspace depends on ${K} \u2014 \`lensmcp upgrade\` reconciles everything (or restart the daemon workspace's gateway).`)},"printVersionSkew");if(S)return e(y==="booting"?`gateway: starting (pid ${$}) \u2014 :443 not bound yet`:`gateway: running (pid ${$}) \u2014 DAEMON on :443${g?" \u2014 recovered a stale pid file":""}`),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${f}`),m(),e(" chooser \u2192 https://lensmcp.local/"),e(` logs \u2192 ${u}`),T(),z(),D(),{exitCode:0};if(P(p)&&x?.status===200){const C=V()[0];e(`gateway: registered into a shared daemon${C!==void 0?` (pid ${C})`:""} \u2014 this workspace is a guest`),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${f}`),m(),e(` logs \u2192 ${u} (this workspace's pods)`);const E=Re();return E&&E!==c&&e(` ${w(E,".lensmcp","gateway.log")} (the daemon's own log \u2014 gateway-level lines land there)`),e(" attach \u2192 `lensmcp logs <service>` (live, from any workspace)"),e(" stop \u2192 `lensmcp gateway stop` (unregisters; the daemon keeps running)"),T(),z(),D(),{exitCode:0}}return y==="zombie"?(e(`gateway: NOT serving \u2014 tracked pid ${$} is alive but nothing holds :443 for this workspace`),e(" (a crashed gateway under a wedged nx wrapper) \u2014 run `lensmcp gateway restart` to recover."),e(` workspace \u2192 ${d.key}`),e(` logs \u2192 ${u}`),T(),D(),{exitCode:1}):(e("gateway: stopped"),e(` workspace \u2192 ${d.key}`),e(` dashboard \u2192 ${f}`),m(),T(),{exitCode:1})},"status"),M=l(()=>{const $=A("GET","/status");if($?.status!==200||!$.json||typeof $.json!="object")return e(i?JSON.stringify({daemon:null,workspaces:[],services:[]}):"gateway: no daemon answers on the control socket \u2014 nothing is hosted."),{exitCode:1};const g=$.json;if(i)return e(JSON.stringify(g)),{exitCode:0};e(`daemon: pid ${g.daemon?.pid??"?"} \xB7 owner ${g.daemon?.wsKey??"?"}${g.daemon?.version?` \xB7 lensmcp ${g.daemon.version}`:""}`);for(const y of g.workspaces??[]){e(` ${y.isDaemon?"\u2605":"\xB7"} ${y.key.padEnd(16)} ${String(y.routes??0).padStart(3)} routes ${String(y.services??0).padStart(3)} services ${y.root??""}`);for(const S of(g.services??[]).filter(x=>(x.wsKey??g.daemon?.wsKey)===y.key))e(` ${S.project.padEnd(16)} ${(S.state??"unknown").padEnd(9)} ${S.host??""}`)}return{exitCode:0}},"list");switch(r){case"start":return v();case"stop":return k();case"list":return M();case"restart":return k(),oe(c,t.env,e),v();case"status":return j();default:return s(`Unknown gateway subcommand: ${r} (use start | stop | status | restart | list)`),{exitCode:2}}}h(Se,"Ye"),l(Se,"runGateway");function oe(t,n,e){const s=ce(t);if(!s){e(" (graph refresh skipped \u2014 no nx binary found in the workspace)");return}const o={...process.env,...n??{}},r=l(i=>R(s,i,{cwd:t,env:o,stdio:"ignore"}).status===0,"tryNx");if(r(["reset","--only-daemon"])||r(["daemon","--stop"])){e(" nx project graph refreshed \u2014 a lib/app added since boot will now resolve.");return}e(" (graph refresh best-effort failed \u2014 if a new project does not resolve, run `nx reset`)")}h(oe,"ce"),l(oe,"refreshNxGraph");function xe(t,n,e,s){if(e&&s)return{project:e,target:s};const o=W(t,r=>r==="project.json");for(const r of o){let i;try{i=JSON.parse(F(r))}catch{continue}const c=i.name??ue(_(r));for(const[d,a]of Object.entries(i.targets??{}))if(a.executor===n)return{project:e??c,target:s??d}}}h(xe,"Xe"),l(xe,"scanExecutorTarget");function Ct(t,n,e){return xe(t,"@lensmcp/cluster:gateway",n,e)||(n||e?{project:n??"gateway",target:e??"serve"}:void 0)}h(Ct,"Ht"),l(Ct,"findGatewayTarget");function St(t,n,e){return xe(t,"@lensmcp/cluster:trust",n,e)||(n?{project:n,target:e??"trust"}:xt(t,"gateway")?{project:"gateway",target:e??"trust"}:void 0)}h(St,"Vt"),l(St,"findTrustTarget");function xt(t,n){for(const e of W(t,s=>s==="project.json"))try{if((JSON.parse(F(e)).name??ue(_(e)))===n)return!0}catch{}return!1}h(xt,"Bt"),l(xt,"projectExists");function je(t){const n=Os(t);if(n)return As(n.pid,n.stamp)?n.pid:void 0}h(je,"Ze"),l(je,"readPid");function re(t){try{return process.kill(t,0),!0}catch(n){return n.code==="EPERM"}}h(re,"de"),l(re,"isAlive");function V(){try{const t=R("lsof",["-nP","-iTCP:443","-sTCP:LISTEN","-t"],{encoding:"utf8"});return t.status!==0||!t.stdout?[]:[...new Set(t.stdout.split(/\s+/).map(Number).filter(n=>Number.isInteger(n)&&n>0))]}catch{return[]}}h(V,"V"),l(V,"pidsOnPort443");function jt(t){try{return(R("ps",["-o","command=","-p",String(t)],{encoding:"utf8"}).stdout??"").trim()}catch{return""}}h(jt,"Wt"),l(jt,"processCmd");function H(t){const n=w(t,"node_modules","nx","dist","bin","run-executor.js"),e=w(t,"node_modules","@lensmcp","cluster");for(const s of V()){const o=jt(s);if(o.includes(n)||o.includes(e))return s}}h(H,"B"),l(H,"gatewayOnPort443");function Ne(t){try{return Date.now()-Ge(t).mtimeMs}catch{return}}h(Ne,"Qe"),l(Ne,"pidFileAgeMs");const Dn=18e4;export function classifyAliveGateway(t){if(t.oursOn443)return"serving";const n=t.pidFileAgeMs!==void 0&&t.pidFileAgeMs<(t.bootGraceMs??Dn);return!t.port443Held&&n?"booting":"zombie"}h(classifyAliveGateway,"classifyAliveGateway"),l(classifyAliveGateway,"classifyAliveGateway");function ie(t,n){const e=je(t);if(e!==void 0&&re(e))return{pid:e,healed:!1};const s=H(n);if(s!==void 0){try{qe(t,s)}catch{}return{pid:s,healed:!0}}return{healed:!1}}h(ie,"le"),l(ie,"reconcileGateway");function ae(t,n="SIGTERM"){try{process.kill(-t,n)}catch{try{process.kill(t,n)}catch{}}}h(ae,"pe"),l(ae,"killGatewayTree");function Pe(t){const n=Date.now()+t;for(;;){if(V().length===0)return!0;if(Date.now()>=n)return!1;R("sleep",["0.15"])}}h(Pe,"en"),l(Pe,"waitForPortFree");function Nt(t){const n=R("curl",["-s","-o","/dev/null","-m","8","-w","%{ssl_verify_result}",`https://${t}/`],{encoding:"utf8"}),e=(n.stdout??"").trim();return n.status===0&&e==="0"?"trusted":e&&e!=="0"?"untrusted":"unknown"}h(Nt,"Ut"),l(Nt,"probeHostTrust");function Pt(t){for(const n of W(t,e=>e==="project.json"))try{const e=JSON.parse(B(n,"utf8")),s=(e.cluster??e.davnx)?.host;if(s&&!s.includes("*"))return s}catch{}}h(Pt,"qt"),l(Pt,"firstClusterHost");function J(t){try{bs(t,{force:!0})}catch{}}h(J,"z"),l(J,"rmFile");async function Et(t,n,e,s){const o=I(n,{string:["--cwd","--host","--port"]}),r=L(b(o.flags["--cwd"])??t.cwd),i=Y(r),c=b(o.flags["--host"])??t.env?.LENSMCP_WS_HOST??process.env.LENSMCP_WS_HOST,d=b(o.flags["--port"])??t.env?.LENSMCP_WS_PORT??process.env.LENSMCP_WS_PORT??String(i.ports.bridge),a=os(r);if(!a)return s(`Could not locate the lensmcp bridge bundle.
209
220
  Looked in (in order):
210
221
  \u2022 <cli-package>/bundled/bridge.js (published bin)
211
222
  \u2022 <workspace>/libs/bridge/dist/main.js (dev build)
212
- For dev: \`yarn nx build @lensmcp/bridge\`.`),{exitCode:1};ae(r);const u=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??m(r,".lensmcp","events.jsonl"),h={...process.env,...t.env??{},LENSMCP_EVENT_FILE:u};return c&&(h.LENSMCP_WS_HOST=c),l&&(h.LENSMCP_WS_PORT=l),e(`lensmcp bridge \u2192 ws://${c??"127.0.0.1"}:${l??"5747"} (forwarding to ${u})`),{exitCode:M(process.execPath,[a],{cwd:r,stdio:"inherit",env:h}).status??1}}p(yt,"bt"),d(yt,"runBridge");async function vt(t,n,e,s){const o=Fs(n);if("error"in o)return s(`lensmcp dismiss: ${o.error}`),s(Ds),{exitCode:2};const r=L(o.cwd??t.cwd),i={...process.env,...t.env??{}},c=await Ks(o,{session:d(l=>_s({cwd:r,env:i,budgetMs:8e3,clientName:"lensmcp-dismiss"},l),"session")});for(const l of c.lines)(c.exitCode===2?s:e)(l);return{exitCode:c.exitCode}}p(vt,"Ct"),d(vt,"runDismiss");function kt(t,n,e){const s=ys(n),o=L(s.cwd??t.cwd),r=qt(o);if(!r)return e(`Could not locate the lensmcp lint runner.
223
+ For dev: \`yarn nx build @lensmcp/bridge\`.`),{exitCode:1};de(r);const u=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(r,".lensmcp","events.jsonl"),p={...process.env,...t.env??{},LENSMCP_EVENT_FILE:u};c&&(p.LENSMCP_WS_HOST=c),d&&(p.LENSMCP_WS_PORT=d);const f=Is(_s(W(r,v=>v==="project.json"))),m=Ds(p.LENSMCP_BRIDGE_ALLOWED_ORIGINS,f);return m&&(p.LENSMCP_BRIDGE_ALLOWED_ORIGINS=m),e(`lensmcp bridge \u2192 ws://${c??"127.0.0.1"}:${d??"5747"} (forwarding to ${u})`),f.length>0&&e(` admitting this workspace's cluster hosts: ${f.join(", ")}`),{exitCode:await ke({label:`the bridge (${a})`,args:[a],cwd:r,env:p},s)}}h(Et,"zt"),l(Et,"runBridge");async function Mt(t,n,e,s){const o=pn(n);if("error"in o)return s(`lensmcp dismiss: ${o.error}`),s(un),{exitCode:2};const r=L(o.cwd??t.cwd),i={...process.env,...t.env??{}},c=await hn(o,{session:l(d=>nn({cwd:r,env:i,budgetMs:8e3,clientName:"lensmcp-dismiss"},d),"session")});for(const d of c.lines)(c.exitCode===2?s:e)(d);return{exitCode:c.exitCode}}h(Mt,"Yt"),l(Mt,"runDismiss");function Lt(t,n,e){const s=Ms(n),o=L(s.cwd??t.cwd),r=rs(o);if(!r)return e(`Could not locate the lensmcp lint runner.
213
224
  Looked in (in order):
214
225
  \u2022 <cli-package>/bundled/lint-runner.js (published bin)
215
226
  \u2022 <workspace>/libs/session/dist/lint-runner.js (dev build)
216
- For dev: \`yarn nx build @lensmcp/session\`.`),{exitCode:2};const i=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??m(o,".lensmcp","events.jsonl");return{exitCode:M(process.execPath,[r,...s.runnerArgs],{cwd:o,stdio:"inherit",env:{...process.env,...t.env??{},LENSMCP_EVENT_FILE:i}}).status??2}}p(kt,"St"),d(kt,"runLint");function be(t,n,e,s){const o=I(n,{string:["--cwd","--register-host-config"],boolean:["--skip-format","--yes"]}),r=L(b(o.flags["--cwd"])??t.cwd);if(!S(m(r,"nx.json")))return s(`No nx.json found at ${r}.`),s("Run `lensmcp install` from inside a Nx workspace."),{exitCode:1};const i=ie(r);if(!i)return s("Could not find the `nx` binary in the host workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};const c=["g","@lensmcp/nx-plugin:init","--no-interactive"];return o.flags["--skip-format"]===!0&&c.push("--skipFormat"),o.flags["--register-host-config"]&&c.push(`--registerHostConfig=${String(o.flags["--register-host-config"])}`),e(`> ${i} ${c.join(" ")}`),{exitCode:M(i,c,{cwd:r,stdio:"inherit",env:{...process.env,...t.env??{}}}).status??1}}p(be,"Je"),d(be,"runInstall");function Ce(t,n,e,s){const o=I(n,{string:["--cwd","--project","--target"]}),r=L(b(o.flags["--cwd"])??t.cwd);if(!S(m(r,"nx.json")))return s(`No nx.json found at ${r}.`),s("Run `lensmcp trust` from inside a Nx workspace (after `lensmcp install`)."),{exitCode:1};const i=ie(r);if(!i)return s("Could not find the `nx` binary in the workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};const c=gt(r,b(o.flags["--project"]),b(o.flags["--target"])),l=A("GET","/list")?.status===200&&B(r)===void 0;if(!c){if(s("This workspace has no trust target \u2014 no project declares the `@lensmcp/cluster:trust` executor."),s(""),l){const u=lt();s(` A shared gateway daemon${u?` (owned by '${u}')`:""} already serves this workspace, and`),s(" TLS rides ITS certificate authority. Run `lensmcp trust` in THAT workspace \u2014 it owns the CA \u2014"),s(" and this workspace is trusted too (restart the browser once if it cached a cert error).")}else s(" \u2022 Should this workspace own its gateway (and its CA)? Scaffold it first: `lensmcp install`,"),s(" then re-run `lensmcp trust`."),s(" \u2022 Joining a shared gateway? Run `lensmcp trust` in the workspace that owns the daemon.");return s(" \u2022 Already have a differently-named target? `lensmcp trust --project <p> --target <t>`."),{exitCode:1}}zt()||e(" note: trust runs `sudo` for the CA + /etc/hosts \u2014 run it in a real terminal if a step is needed."),l&&(e(" a shared gateway daemon serves this workspace \u2014 TLS rides ITS (already-trusted) CA, not a separate"),e(" one here. Setting up /etc/hosts only (trusting the CA is the DAEMON workspace's job).")),e(`> ${i} run ${c.project}:${c.target} (sudo prompts inline for ${l?"/etc/hosts":"the CA + /etc/hosts"})`);const a=M(i,["run",`${c.project}:${c.target}`],{cwd:r,stdio:"inherit",env:{...process.env,...t.env??{},...l?{LENSMCP_TRUST_HOSTS_ONLY:"1"}:{}}});if(l&&a.status===0){const u=wt(r);if(u){const h=mt(u);e(""),e(h==="trusted"?` \u2713 ${u} \u2192 served by the daemon with a TRUSTED cert \u2014 you're set (restart the browser once if it cached an error).`:h==="untrusted"?` \u2717 ${u} \u2192 the daemon's cert is NOT trusted yet. Run \`lensmcp trust\` in the DAEMON workspace (it owns the CA), then restart your browser.`:` ? ${u} \u2192 couldn't reach it to verify (is the daemon running?). /etc/hosts is set; TLS rides the daemon's CA.`)}}return{exitCode:a.status??1}}p(Ce,"We"),d(Ce,"runTrust");function xe(t){const n=G(t)??X(),e=ks(D(m(t,".lensmcp","config.json")));return{version:n,...e?{configHash:e}:{}}}p(xe,"Ue"),d(xe,"currentRecycleStamp");function Se(t){const n=Y(m(t,".lensmcp","setup-state.json"))?.recycled;return n&&typeof n=="object"?n:void 0}p(Se,"qe"),d(Se,"readRecycleStamp");function $t(t,n){ae(t);const e={version:X(),completedAt:new Date().toISOString(),steps:{install:!0,trust:!0},recycled:n?xe(t):Se(t)??{}};try{q(m(t,".lensmcp","setup-state.json"),`${JSON.stringify(e,null,2)}
217
- `)}catch{}}p($t,"jt"),d($t,"writeSetupState");async function bt(t,n,e,s){const o=Ve(n)?n:te(t,e).mode,r=Es(t,o);if(s(""),s(`[mcp] mode \u2192 ${o}`),r.wrote&&s(` wrote ${Ns}`),o==="embedded"){s(" every agent session builds its OWN MCP server, and keeps serving"),s(" the bundle it started with until that session exits."),s(" one shared server for the workspace: `lensmcp setup --mcp shared`");return}s(` sessions proxy into ONE shared server at ${r.url}`),s(" .mcp.json is unchanged \u2014 `lensmcp mcp` becomes a thin stdio shim.");const i=await Be(r.url);if(!i.ok){s(` \xB7 not up yet (${i.error??"unknown"}) \u2014 the next session starts it on demand`);return}const c=G(t)??X(),l=_e({identity:He(r.port),targetVersion:c,expectedRoot:Ee(t),expectedKey:z(t).key,selfPid:process.pid});if(!l.kill){s(` \u2713 already up \u2014 ${i.server??"MCP"} (protocol ${i.protocolVersion??"?"}) \u2014 ${l.reason}`);return}try{process.kill(l.pid,"SIGTERM"),s(` \u21BA restarted the shared server \u2014 it was ${l.reason}; the next session brings it up on ${c}`)}catch(a){s(` ! the shared server is ${l.reason} and could not be stopped (pid ${l.pid}): ${a.message}`)}}p(bt,"xt"),d(bt,"applyMcpModeStep");function Ct(t,n,e){const s=Qe({cwd:t,cliVersion:X()}),o=Hs({run:Vs(n),facts:s});if(!(o.outcome==="current"||o.outcome==="unknown")){if(e(""),o.outcome==="updated"){e(`[plugin] ${o.from} \u2192 ${o.to}`),e(" restart Claude Code for the new plugin to load.");return}e(`[plugin] the Claude Code plugin is ${o.from}, this lensmcp is ${o.to}.`),e(` could not update it automatically (${o.detail??"unknown reason"}). Run:`);for(const r of o.commands??[])e(` ${r}`);e(" \u2026then restart Claude Code.")}}p(Ct,"Nt"),d(Ct,"applyPluginSyncStep");async function xt(t,n,e,s){const o=I(n,{string:["--cwd","--mcp"],boolean:["--no-recycle"]}),r=L(b(o.flags["--cwd"])??t.cwd),i={...t,cwd:r},c=b(o.flags["--mcp"]);if(c!==void 0&&!Ve(c))return s(`setup: --mcp must be "embedded" or "shared" (got "${c}").`),{exitCode:1};e("lensmcp setup \u2014 first-time bootstrap (install \u2192 trust \u2192 pods)"),e(""),e("[1/3] install \u2014 plugin, .mcp.json, nx config, vite/nest wiring");const l=be(i,n,e,s);if(l.exitCode!==0)return s(""),s("setup: the install step failed \u2014 fix the above and re-run `lensmcp setup`."),l;e(""),e("[2/3] trust \u2014 dev CA \u2192 System keychain, /etc/hosts, DNS flush (sudo)");const a=Ce(i,n,e,s);if(a.exitCode!==0)return s(""),s("setup: the trust step failed \u2014 run `lensmcp setup` directly in a terminal so sudo can prompt."),a;e(""),e("[3/3] pods \u2014 recycle this workspace's devservers, reconcile the gateway");const u=z(r).key,h=vs({previous:Se(r),current:xe(r),disabled:o.flags["--no-recycle"]===!0}),f=h.recycle?Qt(r,u,e,h.reason):(e(` \xB7 pods left running \u2014 ${h.reason}`),{killed:0,stale:0});es(i,r,u,e),await bt(r,c,t.env??process.env,e);try{Ct(r,{...process.env,...t.env??{}},e)}catch{}return $t(r,h.recycle),e(""),e("\u2713 setup complete."),(f.killed>0||f.stale>0)&&e(` recycled ${f.killed} pod${f.killed===1?"":"s"}`+(f.stale>0?` (+${f.stale} stale socket${f.stale===1?"":"s"} cleared)`:"")+" \u2014 they come back on the new wiring."),e(" next: lensmcp gateway start (the :443 front door \u2014 needs sudo)"),e(" verify: lensmcp doctor"),{exitCode:0}}p(xt,"Pt"),d(xt,"runSetup");async function St(t,n,e){const s=I(n,{string:["--cwd","--hook","--timeout","--session"],boolean:["--json","--quiet"]}),o=L(b(s.flags["--cwd"])??t.cwd),r=b(s.flags["--hook"]),i=Ue(r)?r:void 0,c=b(s.flags["--session"]);if(r!==void 0&&i===void 0)return{exitCode:0};const l=s.flags["--json"]===!0,a=s.flags["--quiet"]===!0||r!==void 0,u=Number(b(s.flags["--timeout"])??""),h=Number.isFinite(u)&&u>0?u:As,f={...process.env,...t.env??{}};try{const w=await Is({cwd:o,env:f,budgetMs:h,verify:d(C=>Ts(C).map(v=>v.resource),"verify")});if(!w.available)return l&&!a?e(JSON.stringify({available:!1,workspace:w.source.workspace,mode:w.source.mode,reason:w.reason,elapsedMs:w.elapsedMs})):a||e(`lensmcp status \u2014 ${w.source.workspace}: unavailable (${w.reason})`),{exitCode:0};const k=Rs(w.status,w.evidence,Date.now()),$=Os(k,{workspace:w.source.workspace,includeUnmonitored:i==="SessionStart"||!a});if(l)return a&&$===void 0?{exitCode:0}:(e(JSON.stringify({available:!0,workspace:w.source.workspace,mode:w.source.mode,url:w.source.url,aggregate:w.status.status??"unknown",elapsedMs:w.elapsedMs,findings:k.findings,suppressed:k.suppressed,unmonitored:k.unmonitored})),{exitCode:0});if(i){const C=Ls(k.findings);return Ss(c,C)?($!==void 0&&e(We(i,$)),c&&xs(c,C),{exitCode:0}):{exitCode:0}}if(a)return $!==void 0&&e($),{exitCode:0};if(e(`lensmcp status \u2014 ${w.source.workspace} (${w.source.mode}, ${w.source.url})`),e(` aggregate says: ${w.status.status??"unknown"} (read in ${w.elapsedMs}ms)`),k.findings.length===0)e(" nothing actionable that this command can vouch for.");else for(const C of k.findings)e(` \u2022 ${Ms(C)}`);for(const C of k.suppressed)e(` \xB7 not reported \u2014 ${C.kind}: ${C.reason}`);return k.unmonitored.length>0&&e(` \xB7 unmonitored (unknown, NOT clean): ${k.unmonitored.join(", ")}`),{exitCode:0}}catch(w){return a||e(`lensmcp status: unavailable (${w instanceof Error?w.message:String(w)})`),{exitCode:0}}}p(St,"Et"),d(St,"runStatus");function jt(t,n,e){const s=I(n,{string:["--cwd","--hook","--plugin-root"],boolean:["--json","--quiet"]}),o=L(b(s.flags["--cwd"])??t.cwd),r=b(s.flags["--hook"]),i=Ue(r)?r:void 0;if(r!==void 0&&i===void 0)return{exitCode:0};const c=s.flags["--json"]===!0,l=s.flags["--quiet"]===!0||r!==void 0,a=b(s.flags["--plugin-root"]);try{const u=Qe({cwd:o,cliVersion:X(),...a?{pluginRoot:a}:{}}),h=Gs(u);if(c)return l&&!h?{exitCode:0}:(e(JSON.stringify({...u,skew:h??null})),{exitCode:0});if(i)return h&&e(We(i,Ye(h))),{exitCode:0};if(l)return h&&e(Ye(h)),{exitCode:0};if(e(`lensmcp version-check \u2014 ${u.pluginId??"lensmcp plugin"}`),e(` plugin ${u.plugin??"unknown"}${u.pluginSource?` (${u.pluginSource})`:""}`),e(` project ${u.project??"unknown"} (node_modules/lensmcp)`),e(` cli ${u.cli??"unknown"} (the binary running now)`),!h)return e(u.plugin&&(u.project??u.cli)?" \u2713 in step.":" ? cannot compare \u2014 one of the versions is unreadable (staying silent)."),{exitCode:0};e(` \u2717 the plugin is ${h.direction} \u2014 update it, then restart Claude Code:`);for(const f of Bs(h))e(` ${f}`);return{exitCode:0}}catch(u){return l||e(`lensmcp version-check: unavailable (${u instanceof Error?u.message:String(u)})`),{exitCode:0}}}p(jt,"Mt"),d(jt,"runVersionCheck");async function Nt(t,n,e){const s=I(n,{string:["--cwd"],boolean:["--json"]}),o=L(b(s.flags["--cwd"])??t.cwd),r=s.flags["--json"]===!0,i=[];Pt(i),Et(o,i),Tt(o,i),Mt(o,t.env??process.env,i),await Lt(o,t.env??process.env,i),Ot(o,i),Rt(o,i),At(o,i),It(i);const c=i.some(a=>a.status==="fail"),l=i.some(a=>a.status==="warn");if(r)return e(JSON.stringify({ok:!c,summary:{total:i.length,failed:i.filter(a=>a.status==="fail").length,warnings:i.filter(a=>a.status==="warn").length},checks:i},null,2)),{exitCode:c?1:0};for(const a of i){const u=a.status==="pass"?"\u2713":a.status==="warn"?"!":"\u2717";e(`${u} ${a.label}${a.detail?` \u2014 ${a.detail}`:""}`),a.status!=="pass"&&a.hint&&e(` \u21B3 ${a.hint}`)}return e(""),e(c?"doctor: issues found (see \u2717 above).":l?"doctor: ok, with warnings (!).":"doctor: all checks passed."),{exitCode:c?1:0}}p(Nt,"Tt"),d(Nt,"runDoctor");function T(t,n,e,s,o){t.push({status:n,label:e,detail:s,hint:o})}p(T,"T"),d(T,"add");function Pt(t){const n=Number(process.versions.node.split(".")[0]);n>=20?T(t,"pass",`Node ${process.versions.node}`):n>=18?T(t,"warn",`Node ${process.versions.node}`,"older than recommended","upgrade to Node 20+ for best results"):T(t,"fail",`Node ${process.versions.node}`,"too old","LensMCP needs Node 18+ (20+ recommended)")}p(Pt,"Lt"),d(Pt,"checkNode");function Et(t,n){const e=m(t,"nx.json");if(!S(e)){T(n,"fail","nx.json at workspace root","missing","run `lensmcp` from inside a Nx workspace");return}let s;try{s=JSON.parse(V(e,"utf8"))}catch(r){T(n,"fail","nx.json parses",r.message,"fix the JSON syntax in nx.json");return}const o=(s.plugins??[]).some(r=>typeof r=="string"?r==="@lensmcp/nx-plugin":!!r&&typeof r=="object"&&r.plugin==="@lensmcp/nx-plugin");T(n,o?"pass":"fail","@lensmcp/nx-plugin registered in nx.json#plugins",o?void 0:"not registered",o?void 0:"run `lensmcp install`"),T(n,s.lensmcp?.schemaVersion===1?"pass":"warn","lensmcp config block in nx.json",s.lensmcp?.schemaVersion===1?void 0:"missing",s.lensmcp?.schemaVersion===1?void 0:"run `lensmcp install` to write the config defaults")}p(Et,"Rt"),d(Et,"checkWorkspace");function Tt(t,n){const e=m(t,".mcp.json");if(!S(e)){T(n,"warn",".mcp.json with a lensmcp server","missing","run `lensmcp install` so agents auto-discover the MCP server");return}try{const s=JSON.parse(V(e,"utf8")),o=!!s.mcpServers&&!!s.mcpServers.lensmcp;T(n,o?"pass":"warn",".mcp.json registers the lensmcp MCP server",o?void 0:"no lensmcp entry",o?void 0:"run `lensmcp install`")}catch(s){T(n,"warn",".mcp.json parses",s.message,"fix the JSON syntax in .mcp.json")}}p(Tt,"Ot"),d(Tt,"checkMcpConfig");function Mt(t,n,e){const s=Y(m(t,".claude","settings.json")),o=Y(m(t,".claude","settings.local.json")),r=tt({cwd:t}),i=r?Y(m(r.root,"plugin",".mcp.json")):void 0,c=Fe(i),l=Ze(),a=Ke(s,Q)||Ke(o,Q)||l.some(h=>h.scope==="user"||h.projectPath===t),u=$s({workspaceServers:Fe(Y(m(t,".mcp.json"))),pluginServers:c,pluginEnabled:a,pluginReadable:i!==void 0,disabledServers:[...De(s),...De(o)],sharedMcp:te(t,n).mode==="shared"});T(e,u.duplicated||u.indeterminate?"warn":"pass","the MCP server is registered exactly once",u.duplicated||u.indeterminate?u.detail:void 0,u.duplicated||u.indeterminate?u.hint:void 0)}p(Mt,"At"),d(Mt,"checkDuplicateRegistration");function je(){const t=A("GET","/status");if(!t||t.status!==200)return;const n=t.json?.daemon,e=t.json?.workspaces;if(!(!n?.wsKey||!Array.isArray(e)))return e.find(s=>s.key===n.wsKey)?.root}p(je,"ze"),d(je,"daemonOwnerRoot");function Y(t){try{return JSON.parse(V(t,"utf8"))}catch{return}}p(Y,"X"),d(Y,"readJsonFile");async function Lt(t,n,e){const s=te(t,n);if(T(e,"pass","MCP mode",s.mode==="shared"?`shared \u2014 sessions proxy into ${s.url}`:"embedded \u2014 one MCP server per agent session",s.mode==="shared"?void 0:"one shared server: `lensmcp setup --mcp shared`"),s.mode!=="shared")return;const o=await Be(s.url);T(e,o.ok?"pass":"warn","shared MCP server",o.ok?`${o.server??"MCP"} @ ${s.url} (protocol ${o.protocolVersion??"?"})`:`not running at ${s.url} \u2014 ${o.error??"no answer"}`,o.ok?void 0:"the next agent session starts it on demand; `lensmcp gateway start` starts it now")}p(Lt,"_t"),d(Lt,"checkMcpMode");function Ne(t,n){const e=te(t,n);if(e.mode!=="shared")return{mode:e.mode,url:e.url,port:e.port,healthy:!1};const s=Ps(e.url);return{mode:e.mode,url:e.url,port:e.port,healthy:s.ok,...s.server?{server:s.server}:{},...s.error?{error:s.error}:{}}}p(Ne,"Ye"),d(Ne,"mcpStatusBlock");function Ot(t,n){const e=ge(t);T(n,e?"pass":"fail","lensmcp-mcp server bundle reachable",e??"missing",e?void 0:"dev: `yarn nx build @lensmcp/lensmcp-mcp`")}p(Ot,"It"),d(Ot,"checkServerBundle");function Rt(t,n){const e=m(t,".lensmcp");T(n,S(e)?"pass":"warn",".lensmcp/ runtime directory",S(e)?void 0:"not created yet",S(e)?void 0:"created automatically on first `lensmcp mcp` run");const s=m(t,".gitignore"),o=(S(s)?D(s):"").split(`
218
- `).some(r=>r.trim()===".lensmcp/"||r.trim()===".lensmcp");T(n,o?"pass":"warn",".gitignore excludes .lensmcp/",o?void 0:"not ignored",o?void 0:"add `.lensmcp/` to .gitignore (lensmcp install does this)")}p(Rt,"Dt"),d(Rt,"checkRuntimeDir");function At(t,n){const e=U(t,l=>/^vite\.config\.[cm]?[jt]s$/.test(l)),s=e.filter(l=>/lensmcpVitePlugin|@lensmcp\/vite-plugin/.test(D(l)));if(e.length>0){const l=s.length===e.length;T(n,l?"pass":"warn",`Vite wiring: ${s.length}/${e.length} config(s) use the LensMCP plugin`,void 0,l?void 0:"wire each: `nx g @lensmcp/nx-plugin:setup-vite <project>`")}const o=U(t,l=>l==="main.ts").filter(l=>/NestFactory\.create|createLensmcpNestApp/.test(D(l))),r=o.filter(l=>/createLensmcpNestApp/.test(D(l)));if(o.length>0){const l=r.length===o.length;T(n,l?"pass":"warn",`Nest wiring: ${r.length}/${o.length} bootstrap(s) use createLensmcpNestApp`,void 0,l?void 0:"wire each: `nx g @lensmcp/nx-plugin:setup-nest <project>`")}const i=U(t,l=>l==="project.json"||l==="package.json").map(l=>D(l)),c=i.filter(l=>/"agent-dev"/.test(l));i.some(l=>/@lensmcp\/cluster:gateway/.test(l))?T(n,"pass","dev lifecycle: cluster gateway owns it (agent-dev not required)",c.length>0?`${c.length} project(s) ALSO declare agent-dev \u2014 that races the gateway`:void 0,c.length>0?"remove agent-dev from gateway-managed projects; the gateway already serves them":void 0):T(n,c.length>0?"pass":"warn",`agent-dev targets: ${c.length} project(s)`,void 0,c.length>0?void 0:"no project wired \u2014 run setup-vite / setup-nest")}p(At,"Ft"),d(At,"checkProjectWiring");function It(t){const n=process.env.CHROME_PATH,e=process.platform==="darwin"?["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium"]:process.platform==="win32"?["C:/Program Files/Google/Chrome/Application/chrome.exe","C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"]:["/usr/bin/google-chrome","/usr/bin/chromium-browser","/usr/bin/chromium","/usr/bin/google-chrome-stable"],s=(n&&S(n)?n:void 0)??e.find(o=>S(o));T(t,s?"pass":"warn","Chrome for browser:// capture",s?le(s):"not found",s?void 0:"install Chrome or set CHROME_PATH (only needed for browser capture)")}p(It,"Kt"),d(It,"checkChrome");function D(t){try{return V(t,"utf8")}catch{return""}}p(D,"D"),d(D,"safeRead");function U(t,n,e=6,s=6e3){const o=new Set(["node_modules","dist","build",".git",".nx",".lensmcp","coverage","tmp",".cache",".yarn"]),r=[],i=[{dir:t,depth:0}];let c=0;for(;i.length>0;){const{dir:l,depth:a}=i.pop();let u;try{u=ce(l,{withFileTypes:!0})}catch{continue}for(const h of u){if(c++>s)return r;if(h.isDirectory()){if(o.has(h.name)||h.name.startsWith("."))continue;a<e&&i.push({dir:m(l,h.name),depth:a+1})}else h.isFile()&&n(h.name)&&r.push(m(l,h.name))}}return r}p(U,"q"),d(U,"walkProjectFiles");function _t(t,n,e,s){const o=I(n,{string:["--cwd","--from","--scope"]}),r=(o.positional[0]??"").toLowerCase();if(r!=="install"&&r!=="status")return s("Usage: lensmcp plugin <install|status> [claude|codex] [--from <dir>] [--scope <user|project|local>] [--cwd <dir>]"),{exitCode:2};const i=L(b(o.flags["--cwd"])??t.cwd),c=o.positional[1]?.toLowerCase(),l=c?Js(c):void 0;if(c&&!l)return s(`Unknown agent: ${c} (use claude | codex)`),{exitCode:2};const a=l?[l]:[...et],u=b(o.flags["--from"]),h=tt({cwd:i,...u?{from:u}:{},selfRoot:ee()});if(!h)return s("Could not find a lensmcp package to install the plugins from."),s("Run inside a workspace with lensmcp installed, or pass --from <package-root>."),{exitCode:1};e(`plugin package: ${h.root}${h.version?` (lensmcp ${h.version})`:""}`+(h.source==="self"?" \u2014 the running CLI itself (no workspace install found; prefer a workspace)":""));const f=st({...process.env,...t.env??{}});if(r==="status"){for(const $ of a){const C=zs(h.root,$),v=$.id==="claude"?Xe(i)?.version:Ws(f),E=v?C?v===C?`installed ${v} \u2014 current`:`installed ${v}, the package ships ${C} \u2014 \`lensmcp plugin install ${$.id}\``:`installed ${v} (this package ships no ${$.label} plugin \u2014 it arrived in ${$.since})`:`not installed \u2014 \`lensmcp plugin install ${$.id}\``;e(` ${$.label.padEnd(11)} \u2192 ${E}`)}return{exitCode:0}}const w=b(o.flags["--scope"]);let k=!1;for(const $ of a){const C=$.id==="claude"?w??Xe(i)?.scope:void 0,v=Us($,{root:h.root,...C?{scope:C}:{}},{run:f});switch(v.outcome){case"installed":e(` ${$.label.padEnd(11)} \u2192 installed${v.version?` ${v.version}`:""} \u2014 ${v.restartHint}`);break;case"skipped-no-cli":l&&(k=!0),e(` ${$.label.padEnd(11)} \u2192 skipped (${v.detail})`);break;case"skipped-not-packaged":l&&(k=!0),e(` ${$.label.padEnd(11)} \u2192 skipped \u2014 ${v.detail}`);break;case"failed":k=!0,s(` ${$.label.padEnd(11)} \u2192 FAILED \u2014 ${v.detail}`),s(` run by hand:${v.commands.map(E=>`
219
- ${E}`).join("")}`);break}}return{exitCode:k?1:0}}p(_t,"Gt"),d(_t,"runPlugin");function Pe(){const t=A("GET","/status");if(t?.status!==200||!t.json||typeof t.json!="object")return{registeredKeys:[]};const n=t.json;return{...typeof n.daemon?.wsKey=="string"?{wsKey:n.daemon.wsKey}:{},...typeof n.daemon?.version=="string"?{version:n.daemon.version}:{},registeredKeys:(n.workspaces??[]).flatMap(e=>typeof e.key=="string"?[e.key]:[])}}p(Pe,"Xe"),d(Pe,"snapshotDaemon");function Dt(t){let n=L(t);for(let e=0;e<8;e++){const s=m(n,"package.json");if(S(s)&&/"(?:lensmcp|@lensmcp\/[^"]+)"\s*:/.test(D(s)))return{key:hs(n).key,root:n};const o=_(n);if(o===n)break;n=o}}p(Dt,"Ht"),d(Dt,"findLensmcpWorkspace");function Ft(t,n,e,s=!1){if(t){const i=t.replace(/^v/,"");if(!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(i)){e(`Not a version: ${t} (expected e.g. 1.20.1)`);return}if(!s&&on(n("npm",["view",`lensmcp@${i}`,"version"]),i)==="absent"){const c=n("npm",["view","lensmcp","version"]),l=c&&c.code===0?(c.stdout??"").trim().split(`
220
- `).filter(Boolean).pop():void 0;e(`lensmcp ${i} is not on the npm registry${l?` (the newest there is ${l})`:""} \u2014 nothing was changed.`),e("If it was published a moment ago, run this again in a minute. `--no-registry-check` skips the question.");return}return i}const o=n("npm",["view","lensmcp","version"]),r=o&&o.code===0?(o.stdout??"").trim().split(`
221
- `).filter(Boolean).pop():void 0;if(!r||!/^\d+\.\d+\.\d+/.test(r)){e("Could not resolve the latest lensmcp version from the npm registry \u2014 pass one explicitly: `lensmcp upgrade 1.20.1`.");return}return r}p(Ft,"Vt"),d(Ft,"resolveTargetVersion");function Kt(t,n,e,s){for(const o of t){let r;try{r=te(o.root,process.env)}catch{continue}if(r.mode!=="shared")continue;const i=_e({identity:He(r.port),targetVersion:n,expectedRoot:Ee(o.root),expectedKey:o.key,selfPid:process.pid});if(!i.kill){s(` mcp \u2192 '${o.key}' :${r.port} \u2014 ${i.reason}`);continue}if(e){s(` mcp \u2192 would restart '${o.key}' :${r.port} (pid ${i.pid}) \u2014 ${i.reason}`);continue}try{process.kill(i.pid,"SIGTERM"),s(` mcp \u2192 restarted '${o.key}' :${r.port} \u2014 was ${i.reason}; the next session respawns it on ${n}`)}catch(c){s(` mcp \u2192 could not stop '${o.key}' :${r.port} (pid ${i.pid}): ${c.message}`)}}}p(Kt,"Bt"),d(Kt,"restartSharedMcpServers");function Ee(t){try{return cs(t)}catch{return t}}p(Ee,"Ze"),d(Ee,"canonicalRootPath");async function Gt(t,n,e,s){const o=I(n,{string:["--cwd"],boolean:["--dry-run","--no-install","--no-plugins","--no-global","--no-restart","--no-registry-check"]}),r=L(b(o.flags["--cwd"])??t.cwd),i=o.flags["--dry-run"]===!0,c={...process.env,...t.env??{}},l=st(c),a=Ft(o.positional[0],l,s,o.flags["--no-registry-check"]===!0);if(!a)return{exitCode:1};const u=nn(),h=Dt(r),f=[],w=new Set;for(const g of[...h?[h]:[],...u])w.has(g.root)||(w.add(g.root),f.push(g));if(f.length===0)return s("No LensMCP workspace found: ~/.lensmcp/workspaces.json is empty and no package.json above the current directory depends on lensmcp."),{exitCode:1};const k=Pe();if(e(`upgrade \u2192 lensmcp ${a}${i?" (dry run \u2014 nothing will be changed)":""}`),k.wsKey&&e(` daemon \u2192 '${k.wsKey}' on :443${k.version?`, running ${k.version}`:""}, hosting ${k.registeredKeys.length} workspace${k.registeredKeys.length===1?"":"s"}`),e(` will change \u2192 ${f.length} workspace${f.length===1?"":"s"} (${f.map(g=>g.key).join(", ")})${o.flags["--no-install"]===!0?"":" + install"}${o.flags["--no-global"]===!0?"":" + the global CLI"}${o.flags["--no-plugins"]===!0?"":" + the Claude/Codex plugins"}${o.flags["--no-restart"]===!0?"":" + the :443 daemon"}`),o.flags["--no-registry-check"]!==!0){const g=Qs(f.flatMap(x=>["package.json","yarn.lock","package-lock.json","pnpm-lock.yaml"].map(N=>D(m(x.root,N))))),y=en(g,a,x=>l("npm",["view",`${x}@${a}`,"version"]));if(y.length===0&&e(` registry \u2192 all ${g.length} packages these workspaces install are published at ${a}`),y.length>0)return s(`lensmcp ${a} is not fully published yet \u2014 ${y.length} of the ${g.length} packages these workspaces install are not on the npm registry at ${a}:`),s(` ${y.join(", ")}`),s("A release publishes its packages one by one; run this again in a minute. Nothing was changed. (`--no-registry-check` skips the question.)"),{exitCode:1}}const $=[];let C=0;for(const g of f){const y=m(g.root,"package.json"),x=D(y);if(!x){C++,s(` ${g.key}: cannot read ${y} \u2014 skipped`);continue}const N=rn(x,a);for(const P of N.skipped.filter(K=>K.reason==="non-version-spec"))e(` ${g.key}: left ${P.section}.${P.name} at '${P.spec}' (not a plain version \u2014 a link:/workspace: pin is deliberate)`);const R=N.changes.length>0,O=G(g.root);if(!tn({rewritten:R,...O?{installedVersion:O}:{},targetVersion:a})){e(` ${g.key}: already at ${a}`);continue}if(e(R?` ${g.key}: ${N.changes.length} dep${N.changes.length===1?"":"s"} \u2192 ${a} (${N.changes.map(P=>P.name).join(", ")})`:` ${g.key}: package.json is at ${a} but node_modules holds ${O??"no lensmcp"} \u2014 an earlier install did not land`),i){$.push(g);continue}if(R&&q(y,N.text),o.flags["--no-install"]===!0){$.push(g),e(" install skipped (--no-install) \u2014 run it before restarting anything.");continue}const F=Zs(g.root);e(` ${F.name} ${F.install.join(" ")} (${g.root})`);const j=M(F.name,F.install,{cwd:g.root,stdio:"inherit",env:c});if((j.status??1)!==0){C++,s(` ${g.key}: \`${F.name} ${F.install.join(" ")}\` exited ${j.status??"by signal"} \u2014 fix it and re-run \`lensmcp upgrade ${a}\` (the rewrite is already in place).`);continue}$.push(g)}if(o.flags["--no-global"]!==!0){const g=Ys(l);g&&g.version!==a?i?e(` global \u2192 ${g.version} \u2192 ${a} (npm i -g lensmcp@${a})`):(e(` global \u2192 ${g.version} \u2192 ${a}`),(M("npm",["install","-g",`lensmcp@${a}`],{stdio:"inherit",env:c,timeout:3e5}).status??1)!==0&&(C++,s(` the global install failed \u2014 run by hand: npm i -g lensmcp@${a}`))):g&&e(` global \u2192 already ${g.version}`)}if(o.flags["--no-plugins"]!==!0){const g=[k.wsKey?f.find(y=>y.key===k.wsKey):void 0,...$,...f].find(y=>!!y&&S(m(y.root,"node_modules","lensmcp","package.json")));g?!i&&o.flags["--no-install"]!==!0&&!nt(G(g.root),a)?e(` plugins \u2192 skipped (${g.key} still holds ${G(g.root)??"no lensmcp"} \u2014 there is no ${a} package on disk to install them from)`):i?e(` plugins \u2192 would re-install Claude Code + Codex from ${m(g.root,"node_modules","lensmcp")}`):Ht(m(g.root,"node_modules","lensmcp"),r,c,e,s):e(" plugins \u2192 skipped (no workspace has lensmcp installed to point the marketplaces at)")}const v=d(()=>{if(!i)for(const g of f){const y=Y(m(g.root,".lensmcp","setup-state.json"))?.version,x=G(g.root),N=an({key:g.key,root:g.root,...typeof y=="string"?{setupVersion:y}:{},...x?{installedVersion:x}:{}});N&&e(N)}return{exitCode:C>0?1:0}},"finish");if(o.flags["--no-restart"]===!0)return e(" restart \u2192 skipped (--no-restart) \u2014 the daemon keeps serving the OLD code until `lensmcp gateway restart` runs in its workspace."),v();const E=sn({...k.wsKey?{daemonWsKey:k.wsKey}:{},...k.version?{daemonVersion:k.version}:{},targetVersion:a,registeredKeys:k.registeredKeys,known:u,upgraded:$});if(o.flags["--no-install"]!==!0){const g=i?f:f.filter(y=>nt(G(y.root),a));for(const y of f)g.includes(y)||e(` mcp \u2192 '${y.key}' left alone \u2014 its install did not land, so there is no ${a} bundle to restart it onto`);Kt(g,a,i,e)}if(E.steps.length===0)return e(` restart \u2192 nothing to do${E.note?` (${E.note})`:""}`),v();for(const g of E.steps){if(i){e(` restart \u2192 would ${g.action==="restart"?`restart the daemon ('${g.key}')`:`re-register '${g.key}'`}${g.reason==="rehost"?" (not upgraded \u2014 re-hosted so the daemon restart does not drop it)":g.reason==="stale-daemon"?" (its files are current but the process still runs the old bundle)":""}`);continue}if(g.action==="restart"){if(e(` restart \u2192 gateway daemon ('${g.key}') \u2026`),we({...t,cwd:g.root},["restart"],e,s).exitCode!==0){C++,s(` the daemon restart ('${g.key}') failed \u2014 fix it, then \`lensmcp gateway start\` in each guest workspace.`);break}if(!await Vt(18e4)){C++,s(" the restarted daemon did not answer within 3 minutes \u2014 check `lensmcp gateway status`; guests need `lensmcp gateway start` once it is up.");break}}else{const y=A("POST","/register",pe(g.root,g.key));if(y&&y.status===200){try{Z(m(g.root,".lensmcp"),{recursive:!0}),q(m(g.root,".lensmcp","registered.json"),JSON.stringify({wsKey:g.key}))}catch{}e(` restart \u2192 re-registered '${g.key}'${g.reason==="rehost"?" (not upgraded \u2014 re-hosted after the daemon restart)":""}`)}else C++,s(` re-registering '${g.key}' failed \u2014 ${de(y)??`run \`lensmcp gateway start\` in ${g.root}`}.`)}}if(!i){const g=Pe();if(g.version){const y=g.wsKey?f.find(R=>R.key===g.wsKey)?.root:void 0,x=y?G(y):void 0,N=Xs({reported:g.version,target:a,...x?{ownerInstalled:x}:{},...y?{ownerRoot:y}:{}});N.ok?e(N.line):(C++,s(N.line))}}return v()}p(Gt,"Jt"),d(Gt,"runUpgrade");async function Vt(t){const n=Date.now()+t;for(;;){if(A("GET","/list")?.status===200)return!0;if(Date.now()>=n)return!1;await new Promise(e=>setTimeout(e,2e3))}}p(Vt,"Wt"),d(Vt,"waitForDaemon");function Ht(t,n,e,s,o){const r=d((i,c,l)=>{try{const a=M(i,c,{encoding:"utf8",timeout:12e4,env:e,stdio:["ignore","pipe","pipe"],...l?{cwd:l}:{}});return a.error&&a.error.code==="ENOENT"?{ok:!1,detail:`\`${i}\` is not on PATH`}:(a.status??1)!==0?{ok:!1,detail:`${a.stderr??""}
227
+ For dev: \`yarn nx build @lensmcp/session\`.`),{exitCode:2};const i=t.env?.LENSMCP_EVENT_FILE??process.env.LENSMCP_EVENT_FILE??w(o,".lensmcp","events.jsonl");return{exitCode:R(process.execPath,[r,...s.runnerArgs],{cwd:o,stdio:"inherit",env:{...process.env,...t.env??{},LENSMCP_EVENT_FILE:i}}).status??2}}h(Lt,"Xt"),l(Lt,"runLint");function Ee(t,n,e,s){const o=I(n,{string:["--cwd","--register-host-config"],boolean:["--skip-format","--yes"]}),r=L(b(o.flags["--cwd"])??t.cwd);if(!P(w(r,"nx.json")))return s(`No nx.json found at ${r}.`),s("Run `lensmcp install` from inside a Nx workspace."),{exitCode:1};const i=ce(r);if(!i)return s("Could not find the `nx` binary in the host workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};const c=["g","@lensmcp/nx-plugin:init","--no-interactive"];return o.flags["--skip-format"]===!0&&c.push("--skipFormat"),o.flags["--register-host-config"]&&c.push(`--registerHostConfig=${String(o.flags["--register-host-config"])}`),e(`> ${i} ${c.join(" ")}`),{exitCode:R(i,c,{cwd:r,stdio:"inherit",env:{...process.env,...t.env??{}}}).status??1}}h(Ee,"nn"),l(Ee,"runInstall");function Me(t,n,e,s){const o=I(n,{string:["--cwd","--project","--target"]}),r=L(b(o.flags["--cwd"])??t.cwd);if(!P(w(r,"nx.json")))return s(`No nx.json found at ${r}.`),s("Run `lensmcp trust` from inside a Nx workspace (after `lensmcp install`)."),{exitCode:1};const i=ce(r);if(!i)return s("Could not find the `nx` binary in the workspace. Install Nx first: `yarn add -D nx`."),{exitCode:1};const c=St(r,b(o.flags["--project"]),b(o.flags["--target"])),d=A("GET","/list")?.status===200&&H(r)===void 0;if(!c){if(s("This workspace has no trust target \u2014 no project declares the `@lensmcp/cluster:trust` executor."),s(""),d){const u=kt();s(` A shared gateway daemon${u?` (owned by '${u}')`:""} already serves this workspace, and`),s(" TLS rides ITS certificate authority. Run `lensmcp trust` in THAT workspace \u2014 it owns the CA \u2014"),s(" and this workspace is trusted too (restart the browser once if it cached a cert error).")}else s(" \u2022 Should this workspace own its gateway (and its CA)? Scaffold it first: `lensmcp install`,"),s(" then re-run `lensmcp trust`."),s(" \u2022 Joining a shared gateway? Run `lensmcp trust` in the workspace that owns the daemon.");return s(" \u2022 Already have a differently-named target? `lensmcp trust --project <p> --target <t>`."),{exitCode:1}}is()||e(" note: trust runs `sudo` for the CA + /etc/hosts \u2014 run it in a real terminal if a step is needed."),d&&(e(" a shared gateway daemon serves this workspace \u2014 TLS rides ITS (already-trusted) CA, not a separate"),e(" one here. Setting up /etc/hosts only (trusting the CA is the DAEMON workspace's job).")),e(`> ${i} run ${c.project}:${c.target} (sudo prompts inline for ${d?"/etc/hosts":"the CA + /etc/hosts"})`);const a=R(i,["run",`${c.project}:${c.target}`],{cwd:r,stdio:"inherit",env:{...process.env,...t.env??{},...d?{LENSMCP_TRUST_HOSTS_ONLY:"1"}:{}}});if(d&&a.status===0){const u=Pt(r);if(u){const p=Nt(u);e(""),e(p==="trusted"?` \u2713 ${u} \u2192 served by the daemon with a TRUSTED cert \u2014 you're set (restart the browser once if it cached an error).`:p==="untrusted"?` \u2717 ${u} \u2192 the daemon's cert is NOT trusted yet. Run \`lensmcp trust\` in the DAEMON workspace (it owns the CA), then restart your browser.`:` ? ${u} \u2192 couldn't reach it to verify (is the daemon running?). /etc/hosts is set; TLS rides the daemon's CA.`)}}return{exitCode:a.status??1}}h(Me,"tn"),l(Me,"runTrust");function Le(t){const n=G(t)??Z(),e=Ts(F(w(t,".lensmcp","config.json")));return{version:n,...e?{configHash:e}:{}}}h(Le,"sn"),l(Le,"currentRecycleStamp");function Te(t){const n=X(w(t,".lensmcp","setup-state.json"))?.recycled;return n&&typeof n=="object"?n:void 0}h(Te,"rn"),l(Te,"readRecycleStamp");function Tt(t,n){de(t);const e={version:Z(),completedAt:new Date().toISOString(),steps:{install:!0,trust:!0},recycled:n?Le(t):Te(t)??{}};try{q(w(t,".lensmcp","setup-state.json"),`${JSON.stringify(e,null,2)}
228
+ `)}catch{}}h(Tt,"Zt"),l(Tt,"writeSetupState");async function Rt(t,n,e,s){const o=Xe(n)?Us(t,n):void 0,r=!o&&be(t),i=ne(t,e),c=o?{mode:o.mode,source:"flag"}:i,d=c.mode;if(s(""),s(`[mcp] mode \u2192 ${d} (${Ze[c.source]})`),o?.wrote&&s(` wrote ${Hs}`),r&&s(` ${$e}`),d==="embedded"){s(" every agent session builds its OWN MCP server, and keeps serving"),s(" the bundle it started with until that session exits."),s(` ${pe(c)}`);return}s(` sessions proxy into ONE shared server at ${i.url}`),s(" .mcp.json is unchanged \u2014 `lensmcp mcp` is a thin stdio shim into it."),s(` ${pe(c)}`);const a=await et(i.url);if(!a.ok&&!a.remedy){s(` \xB7 not up yet (${a.error??"unknown"}) \u2014 the next session starts it on demand`);return}a.ok||s(` ! refused: ${a.error}`);const u=G(t)??Z(),p=We({identity:Qe(i.port),targetVersion:u,expectedRoot:Ie(t),expectedKey:Y(t).key,port:i.port,selfPid:process.pid});if(!p.kill){s(a.ok?` \u2713 already up \u2014 ${a.server??"MCP"} (protocol ${a.protocolVersion??"?"}) \u2014 ${p.reason}`:` ! not restarted (${p.reason}) \u2014 ${a.remedy}`);return}try{process.kill(p.pid,"SIGTERM"),s(` \u21BA restarted the shared server \u2014 it was ${p.reason}; the next session brings it up on ${u}`)}catch(f){s(` ! the shared server is ${p.reason} and could not be stopped (pid ${p.pid}): ${f.message}`)}}h(Rt,"Qt"),l(Rt,"applyMcpModeStep");function Ot(t,n,e){const s=dt({cwd:t,cliVersion:Z()}),o=kn({run:vn(n),facts:s});if(!(o.outcome==="current"||o.outcome==="unknown")){if(e(""),o.outcome==="updated"){e(`[plugin] ${o.from} \u2192 ${o.to}`),e(" restart Claude Code for the new plugin to load.");return}e(`[plugin] the Claude Code plugin is ${o.from}, this lensmcp is ${o.to}.`),e(` could not update it automatically (${o.detail??"unknown reason"}). Run:`);for(const r of o.commands??[])e(` ${r}`);e(" \u2026then restart Claude Code.")}}h(Ot,"es"),l(Ot,"applyPluginSyncStep");async function At(t,n,e,s){const o=I(n,{string:["--cwd","--mcp"],boolean:["--no-recycle"]}),r=L(b(o.flags["--cwd"])??t.cwd),i={...t,cwd:r},c=b(o.flags["--mcp"]);if(c!==void 0&&!Xe(c))return s(`setup: --mcp must be "embedded" or "shared" (got "${c}").`),{exitCode:1};e("lensmcp setup \u2014 first-time bootstrap (install \u2192 trust \u2192 pods)"),e(""),e("[1/3] install \u2014 plugin, .mcp.json, nx config, vite/nest wiring");const d=Ee(i,n,e,s);if(d.exitCode!==0)return s(""),s("setup: the install step failed \u2014 fix the above and re-run `lensmcp setup`."),d;e(""),e("[2/3] trust \u2014 dev CA \u2192 System keychain, /etc/hosts, DNS flush (sudo)");const a=Me(i,n,e,s);if(a.exitCode!==0)return s(""),s("setup: the trust step failed \u2014 run `lensmcp setup` directly in a terminal so sudo can prompt."),a;e(""),e("[3/3] pods \u2014 recycle this workspace's devservers, reconcile the gateway");const u=Y(r).key,p=Ls({previous:Te(r),current:Le(r),disabled:o.flags["--no-recycle"]===!0}),f=p.recycle?ls(r,u,e,p.reason):(e(` \xB7 pods left running \u2014 ${p.reason}`),{killed:0,stale:0});us(i,r,u,e),await Rt(r,c,t.env??process.env,e);try{Ot(r,{...process.env,...t.env??{}},e)}catch{}return Tt(r,p.recycle),e(""),e("\u2713 setup complete."),(f.killed>0||f.stale>0)&&e(` recycled ${f.killed} pod${f.killed===1?"":"s"}`+(f.stale>0?` (+${f.stale} stale socket${f.stale===1?"":"s"} cleared)`:"")+" \u2014 they come back on the new wiring."),e(" next: lensmcp gateway start (the :443 front door \u2014 needs sudo)"),e(" verify: lensmcp doctor"),{exitCode:0}}h(At,"ns"),l(At,"runSetup");async function It(t,n,e){const s=I(n,{string:["--cwd","--hook","--timeout","--session"],boolean:["--json","--quiet"]}),o=L(b(s.flags["--cwd"])??t.cwd),r=b(s.flags["--hook"]),i=st(r)?r:void 0,c=b(s.flags["--session"]);if(r!==void 0&&i===void 0)return{exitCode:0};const d=s.flags["--json"]===!0,a=s.flags["--quiet"]===!0||r!==void 0,u=Number(b(s.flags["--timeout"])??""),p=Number.isFinite(u)&&u>0?u:tn,f={...process.env,...t.env??{}};try{const m=await sn({cwd:o,env:f,budgetMs:p,verify:l(j=>Ys(j).map(M=>M.resource),"verify")});if(!m.available)return d&&!a?e(JSON.stringify({available:!1,workspace:m.source.workspace,mode:m.source.mode,reason:m.reason,elapsedMs:m.elapsedMs})):a||e(`lensmcp status \u2014 ${m.source.workspace}: unavailable (${m.reason})`),{exitCode:0};const v=en(m.status,m.evidence,Date.now()),k=Qs(v,{workspace:m.source.workspace,includeUnmonitored:i==="SessionStart"||!a});if(d)return a&&k===void 0?{exitCode:0}:(e(JSON.stringify({available:!0,workspace:m.source.workspace,mode:m.source.mode,url:m.source.url,aggregate:m.status.status??"unknown",elapsedMs:m.elapsedMs,findings:v.findings,suppressed:v.suppressed,unmonitored:v.unmonitored})),{exitCode:0});if(i){const j=Zs(v.findings);return Bs(c,j)?(k!==void 0&&e(tt(i,k)),c&&Gs(c,j),{exitCode:0}):{exitCode:0}}if(a)return k!==void 0&&e(k),{exitCode:0};if(e(`lensmcp status \u2014 ${m.source.workspace} (${m.source.mode}, ${m.source.url})`),e(` aggregate says: ${m.status.status??"unknown"} (read in ${m.elapsedMs}ms)`),v.findings.length===0)e(" nothing actionable that this command can vouch for.");else for(const j of v.findings)e(` \u2022 ${Xs(j)}`);for(const j of v.suppressed)e(` \xB7 not reported \u2014 ${j.kind}: ${j.reason}`);return v.unmonitored.length>0&&e(` \xB7 unmonitored (unknown, NOT clean): ${v.unmonitored.join(", ")}`),{exitCode:0}}catch(m){return a||e(`lensmcp status: unavailable (${m instanceof Error?m.message:String(m)})`),{exitCode:0}}}h(It,"ts"),l(It,"runStatus");function _t(t,n,e){const s=I(n,{string:["--cwd","--hook","--plugin-root"],boolean:["--json","--quiet"]}),o=L(b(s.flags["--cwd"])??t.cwd),r=b(s.flags["--hook"]),i=st(r)?r:void 0;if(r!==void 0&&i===void 0)return{exitCode:0};const c=s.flags["--json"]===!0,d=s.flags["--quiet"]===!0||r!==void 0,a=b(s.flags["--plugin-root"]);try{const u=dt({cwd:o,cliVersion:Z(),...a?{pluginRoot:a}:{}}),p=yn(u);if(c)return d&&!p?{exitCode:0}:(e(JSON.stringify({...u,skew:p??null})),{exitCode:0});if(i)return p&&e(tt(i,it(p))),{exitCode:0};if(d)return p&&e(it(p)),{exitCode:0};if(e(`lensmcp version-check \u2014 ${u.pluginId??"lensmcp plugin"}`),e(` plugin ${u.plugin??"unknown"}${u.pluginSource?` (${u.pluginSource})`:""}`),e(` project ${u.project??"unknown"} (node_modules/lensmcp)`),e(` cli ${u.cli??"unknown"} (the binary running now)`),!p)return e(u.plugin&&(u.project??u.cli)?" \u2713 in step.":" ? cannot compare \u2014 one of the versions is unreadable (staying silent)."),{exitCode:0};e(` \u2717 the plugin is ${p.direction} \u2014 update it, then restart Claude Code:`);for(const f of $n(p))e(` ${f}`);return{exitCode:0}}catch(u){return d||e(`lensmcp version-check: unavailable (${u instanceof Error?u.message:String(u)})`),{exitCode:0}}}h(_t,"ss"),l(_t,"runVersionCheck");async function Dt(t,n,e){const s=I(n,{string:["--cwd"],boolean:["--json"]}),o=L(b(s.flags["--cwd"])??t.cwd),r=s.flags["--json"]===!0,i=[];Ft(i),Kt(o,i),Gt(o,i),Bt(o,t.env??process.env,i),await Vt(o,t.env??process.env,i),Ht(o,i),Wt(o,i),Ut(o,i),Jt(i),await fs(o,i),await ms(o,t.env??process.env,i);const c=i.some(a=>a.status==="fail"),d=i.some(a=>a.status==="warn");if(r)return e(JSON.stringify({ok:!c,summary:{total:i.length,failed:i.filter(a=>a.status==="fail").length,warnings:i.filter(a=>a.status==="warn").length},checks:i},null,2)),{exitCode:c?1:0};for(const a of i){const u=a.status==="pass"?"\u2713":a.status==="info"?"\xB7":a.status==="warn"?"!":"\u2717";e(`${u} ${a.label}${a.detail?` \u2014 ${a.detail}`:""}`),a.status!=="pass"&&a.hint&&e(` \u21B3 ${a.hint}`)}return e(""),e(c?"doctor: issues found (see \u2717 above).":d?"doctor: ok, with warnings (!).":"doctor: all checks passed."),{exitCode:c?1:0}}h(Dt,"rs"),l(Dt,"runDoctor");function N(t,n,e,s,o){t.push({status:n,label:e,detail:s,hint:o})}h(N,"P"),l(N,"add");function Ft(t){const n=Number(process.versions.node.split(".")[0]);n>=20?N(t,"pass",`Node ${process.versions.node}`):n>=18?N(t,"warn",`Node ${process.versions.node}`,"older than recommended","upgrade to Node 20+ for best results"):N(t,"fail",`Node ${process.versions.node}`,"too old","LensMCP needs Node 18+ (20+ recommended)")}h(Ft,"os"),l(Ft,"checkNode");function Kt(t,n){const e=w(t,"nx.json");if(!P(e)){N(n,"fail","nx.json at workspace root","missing","run `lensmcp` from inside a Nx workspace");return}let s;try{s=JSON.parse(B(e,"utf8"))}catch(r){N(n,"fail","nx.json parses",r.message,"fix the JSON syntax in nx.json");return}const o=(s.plugins??[]).some(r=>typeof r=="string"?r==="@lensmcp/nx-plugin":!!r&&typeof r=="object"&&r.plugin==="@lensmcp/nx-plugin");N(n,o?"pass":"fail","@lensmcp/nx-plugin registered in nx.json#plugins",o?void 0:"not registered",o?void 0:"run `lensmcp install`"),N(n,s.lensmcp?.schemaVersion===1?"pass":"warn","lensmcp config block in nx.json",s.lensmcp?.schemaVersion===1?void 0:"missing",s.lensmcp?.schemaVersion===1?void 0:"run `lensmcp install` to write the config defaults")}h(Kt,"is"),l(Kt,"checkWorkspace");function Gt(t,n){const e=w(t,".mcp.json");if(!P(e)){N(n,"warn",".mcp.json with a lensmcp server","missing","run `lensmcp install` so agents auto-discover the MCP server");return}try{const s=JSON.parse(B(e,"utf8")),o=!!s.mcpServers&&!!s.mcpServers.lensmcp;N(n,o?"pass":"warn",".mcp.json registers the lensmcp MCP server",o?void 0:"no lensmcp entry",o?void 0:"run `lensmcp install`")}catch(s){N(n,"warn",".mcp.json parses",s.message,"fix the JSON syntax in .mcp.json")}}h(Gt,"as"),l(Gt,"checkMcpConfig");function Bt(t,n,e){const s=X(w(t,".claude","settings.json")),o=X(w(t,".claude","settings.local.json")),r=ut({cwd:t}),i=r?X(w(r.root,"plugin",".mcp.json")):void 0,c=Je(i),d=ct(),a=ze(s,ee)||ze(o,ee)||d.some(p=>p.scope==="user"||p.projectPath===t),u=Rs({workspaceServers:Je(X(w(t,".mcp.json"))),pluginServers:c,pluginEnabled:a,pluginReadable:i!==void 0,disabledServers:[...Ue(s),...Ue(o)],mcpMode:ne(t,n).mode});N(e,u.duplicated||u.indeterminate?"warn":"pass","the MCP server is registered exactly once",u.duplicated||u.indeterminate?u.detail:void 0,u.duplicated||u.indeterminate?u.hint:void 0)}h(Bt,"cs"),l(Bt,"checkDuplicateRegistration");function Re(){const t=A("GET","/status");if(!t||t.status!==200)return;const n=t.json?.daemon,e=t.json?.workspaces;if(!(!n?.wsKey||!Array.isArray(e)))return e.find(s=>s.key===n.wsKey)?.root}h(Re,"on"),l(Re,"daemonOwnerRoot");function X(t){try{return JSON.parse(B(t,"utf8"))}catch{return}}h(X,"Z"),l(X,"readJsonFile");async function Vt(t,n,e){be(t)&&N(e,"info","MCP mode pin",$e);const s=ne(t,n),o=Ze[s.source];if(N(e,"pass","MCP mode",s.mode==="shared"?`shared (${o}) \u2014 sessions proxy into ${s.url}`:`embedded (${o}) \u2014 one MCP server per agent session; ${pe(s)}`,pe(s)),s.mode!=="shared")return;const r=await et(s.url);if(r.ok){N(e,"pass","shared MCP server",`${r.server??"MCP"} @ ${s.url} (protocol ${r.protocolVersion??"?"})`);return}if(r.remedy){N(e,"warn","shared MCP server",`not usable at ${s.url} \u2014 ${r.error??"refused"}`,r.remedy);return}const i=Fs(t);if(i.length===0){N(e,"info","shared MCP server",`not running at ${s.url} \u2014 no agent session is open on this workspace; the next one starts it`,"`lensmcp gateway start` starts it now");return}const c=`${i.length} agent session${i.length===1?" is":"s are"} open (pid ${i.join(", ")})`;N(e,"warn","shared MCP server",`not running at ${s.url} \u2014 ${r.error??"no answer"}, yet ${c}`,"each is on an embedded fallback or restarts the server on its next call \u2014 its stderr names why it could not attach; `lensmcp gateway start` starts it now")}h(Vt,"ds"),l(Vt,"checkMcpMode");function Oe(t,n){const e=ne(t,n);if(e.mode!=="shared")return{mode:e.mode,url:e.url,port:e.port,healthy:!1};const s=Ws(e.url);return{mode:e.mode,url:e.url,port:e.port,healthy:s.ok,...s.server?{server:s.server}:{},...s.error?{error:s.error}:{},...s.remedy?{remedy:s.remedy}:{}}}h(Oe,"an"),l(Oe,"mcpStatusBlock");function Ht(t,n){const e=_e(t);N(n,e?"pass":"fail","lensmcp-mcp server bundle reachable",e??"missing",e?void 0:`dev: \`yarn nx build ${wn}\``)}h(Ht,"ls"),l(Ht,"checkServerBundle");function Wt(t,n){const e=w(t,".lensmcp");N(n,P(e)?"pass":"warn",".lensmcp/ runtime directory",P(e)?void 0:"not created yet",P(e)?void 0:"created automatically on first `lensmcp mcp` run");const s=w(t,".gitignore"),o=(P(s)?F(s):"").split(`
229
+ `).some(r=>r.trim()===".lensmcp/"||r.trim()===".lensmcp");N(n,o?"pass":"warn",".gitignore excludes .lensmcp/",o?void 0:"not ignored",o?void 0:"add `.lensmcp/` to .gitignore (lensmcp install does this)")}h(Wt,"ps"),l(Wt,"checkRuntimeDir");function Ut(t,n){const e=W(t,d=>/^vite\.config\.[cm]?[jt]s$/.test(d)),s=e.filter(d=>/lensmcpVitePlugin|@lensmcp\/vite-plugin/.test(F(d)));if(e.length>0){const d=s.length===e.length;N(n,d?"pass":"warn",`Vite wiring: ${s.length}/${e.length} config(s) use the LensMCP plugin`,void 0,d?void 0:"wire each: `nx g @lensmcp/nx-plugin:setup-vite <project>`")}const o=W(t,d=>d==="main.ts").filter(d=>/NestFactory\.create|createLensmcpNestApp/.test(F(d))),r=o.filter(d=>/createLensmcpNestApp/.test(F(d)));if(o.length>0){const d=r.length===o.length;N(n,d?"pass":"warn",`Nest wiring: ${r.length}/${o.length} bootstrap(s) use createLensmcpNestApp`,void 0,d?void 0:"wire each: `nx g @lensmcp/nx-plugin:setup-nest <project>`")}const i=W(t,d=>d==="project.json"||d==="package.json").map(d=>F(d)),c=i.filter(d=>/"agent-dev"/.test(d));i.some(d=>/@lensmcp\/cluster:gateway/.test(d))?N(n,"pass","dev lifecycle: cluster gateway owns it (agent-dev not required)",c.length>0?`${c.length} project(s) ALSO declare agent-dev \u2014 that races the gateway`:void 0,c.length>0?"remove agent-dev from gateway-managed projects; the gateway already serves them":void 0):N(n,c.length>0?"pass":"warn",`agent-dev targets: ${c.length} project(s)`,void 0,c.length>0?void 0:"no project wired \u2014 run setup-vite / setup-nest")}h(Ut,"us"),l(Ut,"checkProjectWiring");function Jt(t){const n=process.env.CHROME_PATH,e=process.platform==="darwin"?["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium"]:process.platform==="win32"?["C:/Program Files/Google/Chrome/Application/chrome.exe","C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"]:["/usr/bin/google-chrome","/usr/bin/chromium-browser","/usr/bin/chromium","/usr/bin/google-chrome-stable"],s=(n&&P(n)?n:void 0)??e.find(o=>P(o));N(t,s?"pass":"warn","Chrome for browser:// capture",s?ue(s):"not found",s?void 0:"install Chrome or set CHROME_PATH (only needed for browser capture)")}h(Jt,"fs"),l(Jt,"checkChrome");function F(t){try{return B(t,"utf8")}catch{return""}}h(F,"F"),l(F,"safeRead");function W(t,n,e=6,s=6e3){const o=new Set(["node_modules","dist","build",".git",".nx",".lensmcp","coverage","tmp",".cache",".yarn"]),r=[],i=[{dir:t,depth:0}];let c=0;for(;i.length>0;){const{dir:d,depth:a}=i.pop();let u;try{u=le(d,{withFileTypes:!0})}catch{continue}for(const p of u){if(c++>s)return r;if(p.isDirectory()){if(o.has(p.name)||p.name.startsWith("."))continue;a<e&&i.push({dir:w(d,p.name),depth:a+1})}else p.isFile()&&n(p.name)&&r.push(w(d,p.name))}}return r}h(W,"W"),l(W,"walkProjectFiles");function zt(t,n,e,s){const o=I(n,{string:["--cwd","--from","--scope"]}),r=(o.positional[0]??"").toLowerCase();if(r!=="install"&&r!=="status")return s("Usage: lensmcp plugin <install|status> [claude|codex] [--from <dir>] [--scope <user|project|local>] [--cwd <dir>]"),{exitCode:2};const i=L(b(o.flags["--cwd"])??t.cwd),c=o.positional[1]?.toLowerCase(),d=c?bn(c):void 0;if(c&&!d)return s(`Unknown agent: ${c} (use claude | codex)`),{exitCode:2};const a=d?[d]:[...lt],u=b(o.flags["--from"]),p=ut({cwd:i,...u?{from:u}:{},selfRoot:te()});if(!p)return s("Could not find a lensmcp package to install the plugins from."),s("Run inside a workspace with lensmcp installed, or pass --from <package-root>."),{exitCode:1};e(`plugin package: ${p.root}${p.version?` (lensmcp ${p.version})`:""}`+(p.source==="self"?" \u2014 the running CLI itself (no workspace install found; prefer a workspace)":""));const f=pt({...process.env,...t.env??{}});if(r==="status"){for(const k of a){const j=jn(p.root,k),M=k.id==="claude"?at(i)?.version:Cn(f),$=M?j?M===j?`installed ${M} \u2014 current`:`installed ${M}, the package ships ${j} \u2014 \`lensmcp plugin install ${k.id}\``:`installed ${M} (this package ships no ${k.label} plugin \u2014 it arrived in ${k.since})`:`not installed \u2014 \`lensmcp plugin install ${k.id}\``;e(` ${k.label.padEnd(11)} \u2192 ${$}`)}return{exitCode:0}}const m=b(o.flags["--scope"]);let v=!1;for(const k of a){const j=k.id==="claude"?m??at(i)?.scope:void 0,M=Sn(k,{root:p.root,...j?{scope:j}:{}},{run:f});switch(M.outcome){case"installed":e(` ${k.label.padEnd(11)} \u2192 installed${M.version?` ${M.version}`:""} \u2014 ${M.restartHint}`);break;case"skipped-no-cli":d&&(v=!0),e(` ${k.label.padEnd(11)} \u2192 skipped (${M.detail})`);break;case"skipped-not-packaged":d&&(v=!0),e(` ${k.label.padEnd(11)} \u2192 skipped \u2014 ${M.detail}`);break;case"failed":v=!0,s(` ${k.label.padEnd(11)} \u2192 FAILED \u2014 ${M.detail}`),s(` run by hand:${M.commands.map($=>`
230
+ ${$}`).join("")}`);break}}return{exitCode:v?1:0}}h(zt,"hs"),l(zt,"runPlugin");function Ae(){const t=A("GET","/status");if(t?.status!==200||!t.json||typeof t.json!="object")return{registeredKeys:[]};const n=t.json;return{...typeof n.daemon?.wsKey=="string"?{wsKey:n.daemon.wsKey}:{},...typeof n.daemon?.version=="string"?{version:n.daemon.version}:{},registeredKeys:(n.workspaces??[]).flatMap(e=>typeof e.key=="string"?[e.key]:[])}}h(Ae,"cn"),l(Ae,"snapshotDaemon");function qt(t){let n=L(t);for(let e=0;e<8;e++){const s=w(n,"package.json");if(P(s)&&/"(?:lensmcp|@lensmcp\/[^"]+)"\s*:/.test(F(s)))return{key:ve(n).key,root:n};const o=_(n);if(o===n)break;n=o}}h(qt,"gs"),l(qt,"findLensmcpWorkspace");function Yt(t,n,e,s=!1){if(t){const i=t.replace(/^v/,"");if(!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(i)){e(`Not a version: ${t} (expected e.g. 1.20.1)`);return}if(!s&&An(n("npm",["view",`lensmcp@${i}`,"version"]),i)==="absent"){const c=n("npm",["view","lensmcp","version"]),d=c&&c.code===0?(c.stdout??"").trim().split(`
231
+ `).filter(Boolean).pop():void 0;e(`lensmcp ${i} is not on the npm registry${d?` (the newest there is ${d})`:""} \u2014 nothing was changed.`),e("If it was published a moment ago, run this again in a minute. `--no-registry-check` skips the question.");return}return i}const o=n("npm",["view","lensmcp","version"]),r=o&&o.code===0?(o.stdout??"").trim().split(`
232
+ `).filter(Boolean).pop():void 0;if(!r||!/^\d+\.\d+\.\d+/.test(r)){e("Could not resolve the latest lensmcp version from the npm registry \u2014 pass one explicitly: `lensmcp upgrade 1.20.1`.");return}return r}h(Yt,"ms"),l(Yt,"resolveTargetVersion");function Xt(t,n,e,s){for(const o of t){let r;try{r=ne(o.root,process.env)}catch{continue}if(r.mode!=="shared")continue;const i=We({identity:Qe(r.port),targetVersion:n,expectedRoot:Ie(o.root),expectedKey:o.key,port:r.port,selfPid:process.pid});if(!i.kill){s(` mcp \u2192 '${o.key}' :${r.port} \u2014 ${i.reason}`);continue}if(e){s(` mcp \u2192 would restart '${o.key}' :${r.port} (pid ${i.pid}) \u2014 ${i.reason}`);continue}try{process.kill(i.pid,"SIGTERM"),s(` mcp \u2192 restarted '${o.key}' :${r.port} \u2014 was ${i.reason}; the next session respawns it on ${n}`)}catch(c){s(` mcp \u2192 could not stop '${o.key}' :${r.port} (pid ${i.pid}): ${c.message}`)}}}h(Xt,"ws"),l(Xt,"restartSharedMcpServers");function Ie(t){try{return $s(t)}catch{return t}}h(Ie,"dn"),l(Ie,"canonicalRootPath");async function Zt(t,n,e,s){const o=I(n,{string:["--cwd"],boolean:["--dry-run","--no-install","--no-plugins","--no-global","--no-restart","--no-registry-check"]}),r=L(b(o.flags["--cwd"])??t.cwd),i=o.flags["--dry-run"]===!0,c={...process.env,...t.env??{}},d=pt(c),a=Yt(o.positional[0],d,s,o.flags["--no-registry-check"]===!0);if(!a)return{exitCode:1};const u=On(),p=qt(r),f=[],m=new Set;for(const g of[...p?[p]:[],...u])m.has(g.root)||(m.add(g.root),f.push(g));if(f.length===0)return s("No LensMCP workspace found: ~/.lensmcp/workspaces.json is empty and no package.json above the current directory depends on lensmcp."),{exitCode:1};const v=Ae();if(e(`upgrade \u2192 lensmcp ${a}${i?" (dry run \u2014 nothing will be changed)":""}`),v.wsKey&&e(` daemon \u2192 '${v.wsKey}' on :443${v.version?`, running ${v.version}`:""}, hosting ${v.registeredKeys.length} workspace${v.registeredKeys.length===1?"":"s"}`),e(` will change \u2192 ${f.length} workspace${f.length===1?"":"s"} (${f.map(g=>g.key).join(", ")})${o.flags["--no-install"]===!0?"":" + install"}${o.flags["--no-global"]===!0?"":" + the global CLI"}${o.flags["--no-plugins"]===!0?"":" + the Claude/Codex plugins"}${o.flags["--no-restart"]===!0?"":" + the :443 daemon"}`),o.flags["--no-registry-check"]!==!0){const g=Mn(f.flatMap(S=>["package.json","yarn.lock","package-lock.json","pnpm-lock.yaml"].map(x=>F(w(S.root,x))))),y=Ln(g,a,S=>d("npm",["view",`${S}@${a}`,"version"]));if(y.length===0&&e(` registry \u2192 all ${g.length} packages these workspaces install are published at ${a}`),y.length>0)return s(`lensmcp ${a} is not fully published yet \u2014 ${y.length} of the ${g.length} packages these workspaces install are not on the npm registry at ${a}:`),s(` ${y.join(", ")}`),s("A release publishes its packages one by one; run this again in a minute. Nothing was changed. (`--no-registry-check` skips the question.)"),{exitCode:1}}const k=[];let j=0;for(const g of f){const y=w(g.root,"package.json"),S=F(y);if(!S){j++,s(` ${g.key}: cannot read ${y} \u2014 skipped`);continue}const x=In(S,a);for(const C of x.skipped.filter(E=>E.reason==="non-version-spec"))e(` ${g.key}: left ${C.section}.${C.name} at '${C.spec}' (not a plain version \u2014 a link:/workspace: pin is deliberate)`);const O=x.changes.length>0,D=G(g.root);if(!Tn({rewritten:O,...D?{installedVersion:D}:{},targetVersion:a})){e(` ${g.key}: already at ${a}`);continue}if(e(O?` ${g.key}: ${x.changes.length} dep${x.changes.length===1?"":"s"} \u2192 ${a} (${x.changes.map(C=>C.name).join(", ")})`:` ${g.key}: package.json is at ${a} but node_modules holds ${D??"no lensmcp"} \u2014 an earlier install did not land`),i){k.push(g);continue}if(O&&q(y,x.text),o.flags["--no-install"]===!0){k.push(g),e(" install skipped (--no-install) \u2014 run it before restarting anything.");continue}const T=En(g.root);e(` ${T.name} ${T.install.join(" ")} (${g.root})`);const z=R(T.name,T.install,{cwd:g.root,stdio:"inherit",env:c});if((z.status??1)!==0){j++,s(` ${g.key}: \`${T.name} ${T.install.join(" ")}\` exited ${z.status??"by signal"} \u2014 fix it and re-run \`lensmcp upgrade ${a}\` (the rewrite is already in place).`);continue}k.push(g)}for(const g of f)be(g.root,i)&&e(` mcp \u2192 '${g.key}'${i?" (dry run \u2014 not written)":""}: ${$e}`);if(o.flags["--no-global"]!==!0){const g=Nn(d);g&&g.version!==a?i?e(` global \u2192 ${g.version} \u2192 ${a} (npm i -g lensmcp@${a})`):(e(` global \u2192 ${g.version} \u2192 ${a}`),(R("npm",["install","-g",`lensmcp@${a}`],{stdio:"inherit",env:c,timeout:3e5}).status??1)!==0&&(j++,s(` the global install failed \u2014 run by hand: npm i -g lensmcp@${a}`))):g&&e(` global \u2192 already ${g.version}`)}if(o.flags["--no-plugins"]!==!0){const g=[v.wsKey?f.find(y=>y.key===v.wsKey):void 0,...k,...f].find(y=>!!y&&P(w(y.root,"node_modules","lensmcp","package.json")));g?!i&&o.flags["--no-install"]!==!0&&!ht(G(g.root),a)?e(` plugins \u2192 skipped (${g.key} still holds ${G(g.root)??"no lensmcp"} \u2014 there is no ${a} package on disk to install them from)`):i?e(` plugins \u2192 would re-install Claude Code + Codex from ${w(g.root,"node_modules","lensmcp")}`):es(w(g.root,"node_modules","lensmcp"),r,c,e,s):e(" plugins \u2192 skipped (no workspace has lensmcp installed to point the marketplaces at)")}const M=l(()=>{if(!i)for(const g of f){const y=X(w(g.root,".lensmcp","setup-state.json"))?.version,S=G(g.root),x=_n({key:g.key,root:g.root,...typeof y=="string"?{setupVersion:y}:{},...S?{installedVersion:S}:{}});x&&e(x)}return{exitCode:j>0?1:0}},"finish");if(o.flags["--no-restart"]===!0)return e(" restart \u2192 skipped (--no-restart) \u2014 the daemon keeps serving the OLD code until `lensmcp gateway restart` runs in its workspace."),M();const $=Rn({...v.wsKey?{daemonWsKey:v.wsKey}:{},...v.version?{daemonVersion:v.version}:{},targetVersion:a,registeredKeys:v.registeredKeys,known:u,upgraded:k});if(o.flags["--no-install"]!==!0){const g=i?f:f.filter(y=>ht(G(y.root),a));for(const y of f)g.includes(y)||e(` mcp \u2192 '${y.key}' left alone \u2014 its install did not land, so there is no ${a} bundle to restart it onto`);Xt(g,a,i,e)}if($.steps.length===0)return e(` restart \u2192 nothing to do${$.note?` (${$.note})`:""}`),M();for(const g of $.steps){if(i){e(` restart \u2192 would ${g.action==="restart"?`restart the daemon ('${g.key}')`:`re-register '${g.key}'`}${g.reason==="rehost"?" (not upgraded \u2014 re-hosted so the daemon restart does not drop it)":g.reason==="stale-daemon"?" (its files are current but the process still runs the old bundle)":""}`);continue}if(g.action==="restart"){if(e(` restart \u2192 gateway daemon ('${g.key}') \u2026`),Se({...t,cwd:g.root},["restart"],e,s).exitCode!==0){j++,s(` the daemon restart ('${g.key}') failed \u2014 fix it, then \`lensmcp gateway start\` in each guest workspace.`);break}if(!await Qt(18e4)){j++,s(" the restarted daemon did not answer within 3 minutes \u2014 check `lensmcp gateway status`; guests need `lensmcp gateway start` once it is up.");break}}else{const y=A("POST","/register",fe(g.root,g.key));if(y&&y.status===200){try{Q(w(g.root,".lensmcp"),{recursive:!0}),q(w(g.root,".lensmcp","registered.json"),JSON.stringify({wsKey:g.key}))}catch{}e(` restart \u2192 re-registered '${g.key}'${g.reason==="rehost"?" (not upgraded \u2014 re-hosted after the daemon restart)":""}`);const S=Ce(y.json);S&&e(S)}else j++,s(` re-registering '${g.key}' failed \u2014 ${he(y)??`run \`lensmcp gateway start\` in ${g.root}`}.`)}}if(!i){const g=Ae();if(g.version){const y=g.wsKey?f.find(O=>O.key===g.wsKey)?.root:void 0,S=y?G(y):void 0,x=Pn({reported:g.version,target:a,...S?{ownerInstalled:S}:{},...y?{ownerRoot:y}:{}});x.ok?e(x.line):(j++,s(x.line))}}return M()}h(Zt,"ys"),l(Zt,"runUpgrade");async function Qt(t){const n=Date.now()+t;for(;;){if(A("GET","/list")?.status===200)return!0;if(Date.now()>=n)return!1;await new Promise(e=>setTimeout(e,2e3))}}h(Qt,"vs"),l(Qt,"waitForDaemon");function es(t,n,e,s,o){const r=l((i,c,d)=>{try{const a=R(i,c,{encoding:"utf8",timeout:12e4,env:e,stdio:["ignore","pipe","pipe"],...d?{cwd:d}:{}});return a.error&&a.error.code==="ENOENT"?{ok:!1,detail:`\`${i}\` is not on PATH`}:(a.status??1)!==0?{ok:!1,detail:`${a.stderr??""}
222
233
  ${a.stdout??""}`.trim().split(`
223
- `).filter(Boolean).pop()||`exited ${a.status}`}:{ok:!0}}catch(a){return{ok:!1,detail:a.message}}},"exec");for(const i of et){if(!S(m(t,i.manifest))){s(` plugins \u2192 ${i.label} skipped \u2014 ${t} ships no ${i.manifest} (the plugin arrived in ${i.since})`);continue}const c=r(i.bin,["plugin","marketplace","add",t]);if(!c.ok){s(` plugins \u2192 ${i.label} skipped (${c.detail})`);continue}if(i.id==="codex"){const a=r(i.bin,["plugin","add",Q]);s(a.ok?` plugins \u2192 Codex installed \u2014 ${i.restartHint}`:` plugins \u2192 Codex install failed (${a.detail}) \u2014 run: codex plugin add ${Q}`);continue}r(i.bin,["plugin","marketplace","update",qs]);const l=Ze();if(l.length===0){const a=r(i.bin,["plugin","install",Q,"--yes"]);s(a.ok?` plugins \u2192 Claude Code installed \u2014 ${i.restartHint}`:` plugins \u2192 Claude Code install failed (${a.detail}) \u2014 run: claude plugin install ${Q} --yes`);continue}for(const a of l){const u=a.scope&&a.scope!=="user"?["--scope",a.scope]:[],h=r(i.bin,["plugin","update",a.id,...u],a.projectPath??n),f=a.projectPath?` (${a.projectPath})`:"";h.ok?s(` plugins \u2192 Claude Code updated${f} \u2014 ${i.restartHint}`):(o(` plugins \u2192 Claude Code update failed${f}: ${h.detail}`),o(` run by hand${a.projectPath?` from ${a.projectPath}`:""}: claude plugin update ${a.id}${u.length>0?` --scope ${a.scope}`:""}`))}}}p(Ht,"Ut"),d(Ht,"syncAgentPlugins");function ee(){let t=_(gs(import.meta.url));for(let n=0;n<4;n++){if(S(m(t,"package.json")))return t;const e=_(t);if(e===t)break;t=e}return t}p(ee,"ee"),d(ee,"cliPackageRoot");function G(t){try{const n=JSON.parse(V(m(t,"node_modules","lensmcp","package.json"),"utf8"));return typeof n.version=="string"?n.version:void 0}catch{return}}p(G,"G"),d(G,"readProjectLensmcpVersion");function X(){try{return JSON.parse(V(m(ee(),"package.json"),"utf8")).version}catch{return"0.0.0"}}p(X,"Z"),d(X,"readCliVersion");function Bt(t,n,e){const s=L(t.cwd),o=Jt(s);return o?{exitCode:M(process.execPath,[o,...n],{stdio:"inherit",cwd:s,env:{...process.env,...t.env}}).status??1}:(e(`Could not locate the lensmcp rollout helper (@lensmcp/cluster).
234
+ `).filter(Boolean).pop()||`exited ${a.status}`}:{ok:!0}}catch(a){return{ok:!1,detail:a.message}}},"exec");for(const i of lt){if(!P(w(t,i.manifest))){s(` plugins \u2192 ${i.label} skipped \u2014 ${t} ships no ${i.manifest} (the plugin arrived in ${i.since})`);continue}const c=r(i.bin,["plugin","marketplace","add",t]);if(!c.ok){s(` plugins \u2192 ${i.label} skipped (${c.detail})`);continue}if(i.id==="codex"){const a=r(i.bin,["plugin","add",ee]);s(a.ok?` plugins \u2192 Codex installed \u2014 ${i.restartHint}`:` plugins \u2192 Codex install failed (${a.detail}) \u2014 run: codex plugin add ${ee}`);continue}r(i.bin,["plugin","marketplace","update",xn]);const d=ct();if(d.length===0){const a=r(i.bin,["plugin","install",ee,"--yes"]);s(a.ok?` plugins \u2192 Claude Code installed \u2014 ${i.restartHint}`:` plugins \u2192 Claude Code install failed (${a.detail}) \u2014 run: claude plugin install ${ee} --yes`);continue}for(const a of d){const u=a.scope&&a.scope!=="user"?["--scope",a.scope]:[],p=r(i.bin,["plugin","update",a.id,...u],a.projectPath??n),f=a.projectPath?` (${a.projectPath})`:"";p.ok?s(` plugins \u2192 Claude Code updated${f} \u2014 ${i.restartHint}`):(o(` plugins \u2192 Claude Code update failed${f}: ${p.detail}`),o(` run by hand${a.projectPath?` from ${a.projectPath}`:""}: claude plugin update ${a.id}${u.length>0?` --scope ${a.scope}`:""}`))}}}h(es,"ks"),l(es,"syncAgentPlugins");function te(){let t=_(He(import.meta.url));for(let n=0;n<4;n++){if(P(w(t,"package.json")))return t;const e=_(t);if(e===t)break;t=e}return t}h(te,"ne"),l(te,"cliPackageRoot");function G(t){try{const n=JSON.parse(B(w(t,"node_modules","lensmcp","package.json"),"utf8"));return typeof n.version=="string"?n.version:void 0}catch{return}}h(G,"G"),l(G,"readProjectLensmcpVersion");function Z(){try{return JSON.parse(B(w(te(),"package.json"),"utf8")).version}catch{return"0.0.0"}}h(Z,"Q"),l(Z,"readCliVersion");function ts(t,n,e){const s=L(t.cwd),o=ss(s);return o?{exitCode:R(process.execPath,[o,...n],{stdio:"inherit",cwd:s,env:{...process.env,...t.env}}).status??1}:(e(`Could not locate the lensmcp rollout helper (@lensmcp/cluster).
224
235
  Looked for main.rollout.js (walking up from cwd):
225
236
  \u2022 <dir>/node_modules/@lensmcp/cluster/executors/gateway/main.rollout.js
226
237
  \u2022 <dir>/dist/libs/cluster/executors/gateway/main.rollout.js
227
- Install @lensmcp/cluster, or \`yarn nx build @lensmcp/cluster\` in the workspace.`),{exitCode:1})}p(Bt,"qt"),d(Bt,"runRollout");function Jt(t){let n=t;for(let e=0;e<6;e++){for(const o of[m(n,"node_modules","@lensmcp","cluster","executors","gateway","main.rollout.js"),m(n,"dist","libs","cluster","executors","gateway","main.rollout.js")])if(S(o))return o;const s=_(n);if(s===n)break;n=s}}p(Jt,"zt"),d(Jt,"findRolloutBundle");function ge(t){return he(t,"main.js")}p(ge,"fe"),d(ge,"findMcpBinary");function Wt(t){return he(t,"shim.js")}p(Wt,"Yt"),d(Wt,"findShimBinary");function he(t,n){const e=m(ee(),"bundled",n);if(S(e))return e;const s=m(t,"servers","lensmcp-mcp","dist",n);if(S(s))return s;let o=t;for(let r=0;r<5;r++){const i=m(o,"servers","lensmcp-mcp","dist",n);if(S(i))return i;const c=_(o);if(c===o)break;o=c}}p(he,"ge"),d(he,"findServerBundle");function Ut(t){const n=m(ee(),"bundled","bridge.js");if(S(n))return n;let e=t;for(let s=0;s<5;s++){const o=m(e,"libs","bridge","dist","main.js");if(S(o))return o;const r=_(e);if(r===e)break;e=r}}p(Ut,"Xt"),d(Ut,"findBridgeBundle");function qt(t){const n=m(ee(),"bundled","lint-runner.js");if(S(n))return n;let e=t;for(let s=0;s<5;s++){const o=m(e,"libs","session","dist","lint-runner.js");if(S(o))return o;const r=_(e);if(r===e)break;e=r}}p(qt,"Zt"),d(qt,"findLintRunner");function ie(t){let n=t;for(let e=0;e<5;e++){const s=m(n,"node_modules",".bin","nx");if(S(s))return s;const o=_(n);if(o===n)break;n=o}}p(ie,"de"),d(ie,"findNxBinary");function ae(t){const n=m(t,".lensmcp");S(n)||Z(n,{recursive:!0})}p(ae,"le"),d(ae,"ensureLensmcpDir");function zt(){return!!(process.stdin.isTTY&&process.stdout.isTTY)}p(zt,"Qt"),d(zt,"isInteractive");function fe(){const t=us(),n=[],e=d((s,o)=>{try{for(const r of ce(s,{withFileTypes:!0})){if(!r.isDirectory()||!r.name.endsWith("-devserver"))continue;const i=m(s,r.name,"parent.sock");S(i)&&n.push({service:r.name.slice(0,-10),wsKey:o,sock:i})}}catch{}},"scan");e(t,"");try{for(const s of ce(t,{withFileTypes:!0}))s.isDirectory()&&/^[a-z0-9][a-z0-9-]*$/.test(s.name)&&!s.name.endsWith("-devserver")&&e(m(t,s.name),s.name)}catch{}return n.sort((s,o)=>`${s.wsKey}/${s.service}`.localeCompare(`${o.wsKey}/${o.service}`))}p(fe,"he"),d(fe,"discoverDevserverSocks");const J=d(t=>t.wsKey?`${t.wsKey}/${t.service}`:t.service,"fullServiceName");function Te(t){try{const n=M("lsof",["-t",t],{encoding:"utf8"}),e=Number((n.stdout??"").split(`
228
- `)[0]?.trim());return Number.isInteger(e)&&e>0?e:void 0}catch{return}}p(Te,"Qe"),d(Te,"pidOnSocket");function Me(t){try{const n=M("ps",["-o","pgid=","-p",String(t)],{encoding:"utf8"}),e=Number((n.stdout??"").trim());return Number.isInteger(e)&&e>1?e:void 0}catch{return}}p(Me,"en"),d(Me,"pgidOf");function Yt(t){try{const n=(M("lsof",["-a","-p",String(t),"-d","cwd","-Fn"],{encoding:"utf8"}).stdout??"").split(`
229
- `).find(e=>e.startsWith("n"));return n&&n.slice(1).trim()||void 0}catch{return}}p(Yt,"es"),d(Yt,"cwdOfPid");function Xt(t,n){const e=Ie(L(t),L(n));return e===""||!e.startsWith("..")&&!ps(e)}p(Xt,"ns"),d(Xt,"isInside");function Zt(t,n){return fe().filter(e=>{if(e.wsKey)return e.wsKey===n;const s=Te(e.sock),o=s!==void 0?Yt(s):void 0;return o!==void 0&&Xt(t,o)})}p(Zt,"ts"),d(Zt,"workspaceDevservers");function Qt(t,n,e,s){const o=Zt(t,n);if(o.length===0)return e(" no devserver pods running for this workspace \u2014 nothing to recycle."),{killed:0,stale:0};s&&e(` \xB7 recycling ${o.length} pod${o.length===1?"":"s"} because ${s}`);const r=new Set;for(const l of[process.pid,...H()]){const a=Me(l);a!==void 0&&r.add(a)}let i=0,c=0;for(const l of o){const a=J(l),u=Te(l.sock);if(u===void 0){W(l.sock),e(` \u2713 ${a} \u2014 stale socket removed (no process held it)`),c++;continue}const h=Me(u),f=h!==void 0&&!r.has(h),w=d(k=>{try{f?process.kill(-h,k):process.kill(u,k)}catch{}},"signal");w("SIGTERM"),Le(u,5e3)||(w("SIGKILL"),Le(u,2e3)),W(l.sock),e(` \u2713 ${a} \u2014 stopped (pid ${u}${f?`, group ${h}`:", parent only"})`),i++}return{killed:i,stale:c}}p(Qt,"ss"),d(Qt,"reapWorkspacePods");function Le(t,n){const e=Date.now()+n;for(;;){if(!ne(t))return!0;if(Date.now()>=e)return!1;M("sleep",["0.15"])}}p(Le,"nn"),d(Le,"waitForPidGone");function es(t,n,e,s){const o=m(n,".lensmcp","gateway.pid"),r=m(n,".lensmcp","registered.json"),{pid:i,healed:c}=oe(o,n);if(c&&s(` healed: adopted a running gateway (pid ${i}) the pid file had lost.`),se(n,t.env,f=>s(` ${f}`)),B(n)!==void 0){s(` gateway: this workspace owns the :443 daemon (pid ${i??"?"}) \u2014 left running, pods respawn fresh.`);return}const l=A("GET","/list");if(l?.status!==200){s(" gateway: not running. Start it when you are ready: lensmcp gateway start");return}const a=l.json&&typeof l.json=="object"?l.json.workspaces??[]:[],u=ze(a,e,n);if(u.kind==="other-checkout"){for(const f of qe(e,u.root,n))s(` gateway: ${f}`);return}if(u.kind==="mine"){Z(_(r),{recursive:!0}),q(r,JSON.stringify({wsKey:e})),s(` gateway: '${e}' is already registered into the shared daemon \u2014 left serving.`);return}const h=A("POST","/register",pe(n,e));if(h&&h.status===200){Z(_(r),{recursive:!0}),q(r,JSON.stringify({wsKey:e})),s(` gateway: registered '${e}' into the shared daemon \u2014 it now hosts this workspace.`);return}s(` gateway: a shared daemon is up but registering this workspace failed \u2014 ${de(h)??"run `lensmcp gateway start`"}.`)}p(es,"rs"),d(es,"reconcileGatewayAfterSetup");function Oe(t,n,e,s){let o=n.filter(r=>r.service===t||J(r)===t);if(o.length>1)try{const r=z(e).key,i=o.filter(c=>c.wsKey===r);i.length===1&&(o=i)}catch{}return o.length===0?(s(`No running service named "${t}".`),n.length>0&&s(`Running: ${n.map(J).join(", ")}`),null):o.length>1?(s(`"${t}" is ambiguous \u2014 use one of: ${o.map(J).join(", ")}`),null):o[0]}p(Oe,"tn"),d(Oe,"resolveServiceSock");async function ts(t,n,e,s){const o=I(n,{string:["--tail","--cwd"],boolean:["--no-follow","--plain","--color"]}),r=o.positional[0],i=fe();if(!r){if(i.length===0)e("No running services found (no devserver control sockets under $TMPDIR)."),e("Start one with `yarn nx serve <project>` or `lensmcp gateway start`.");else{e("Running services \u2014 attach with `lensmcp logs <service>`:");for(const w of i)e(` ${J(w)}`)}return{exitCode:0}}const c=Oe(r,i,L(b(o.flags["--cwd"])??t.cwd),s);if(!c)return{exitCode:1};const l=o.flags["--no-follow"]!==!0,a=Number(b(o.flags["--tail"])??NaN),u=Number.isInteger(a)&&a>=0?a:100,h=o.flags["--plain"]===!0||o.flags["--color"]!==!0&&!process.stdout.isTTY,f=`/webpack/logs?tail=${u}&follow=${l?1:0}${h?"&plain=1":""}`;return new Promise(w=>{const k=Ae({socketPath:c.sock,path:f,method:"GET"},$=>{$.on("data",C=>process.stdout.write(C)),ms(()=>{$.destroy(),w({exitCode:0})}),$.on("end",()=>w({exitCode:0})),$.on("error",()=>w({exitCode:1}))});k.on("error",$=>{s(`Cannot attach to ${J(c)}: ${$.message}`),s("The devserver may have crashed leaving a stale socket \u2014 restart the service and retry."),w({exitCode:1})}),k.end()})}p(ts,"os"),d(ts,"runLogs");async function ss(t,n,e,s){const o=I(n,{string:["--port","--cwd"]}),r=o.positional[0],i=fe();if(!r)return s("Usage: lensmcp debug <service> [--port <base>]"),i.length>0&&s(`Running: ${i.map(J).join(", ")}`),{exitCode:2};const c=Oe(r,i,L(b(o.flags["--cwd"])??t.cwd),s);if(!c)return{exitCode:1};const l=Number(b(o.flags["--port"])??"")||void 0,a=`/webpack/debug${l?`?port=${l}`:""}`,u=await new Promise(f=>{const w=Ae({socketPath:c.sock,path:a,method:"POST"},k=>{let $="";k.on("data",C=>$+=C),k.on("end",()=>f($)),k.on("error",()=>f(null))});w.on("error",()=>f(null)),w.end()});if(u===null)return s(`Cannot reach ${J(c)} \u2014 the devserver may have crashed leaving a stale socket.`),{exitCode:1};let h;try{h=JSON.parse(u)}catch{return s(`Unexpected response from the devserver: ${u.slice(0,200)}`),{exitCode:1}}e(`Inspectors open on ${J(c)} \u2014 in place, no restart:`);for(const f of h.pods??[])e(` pod #${f.id} ${f.inspectorUrl??"(no url reported \u2014 check lensmcp logs)"}`);for(const f of h.workers??[])e(` worker ${f.name} 127.0.0.1:${f.port}`);return e(h.fixedPorts&&h.basePort?`Attach WebStorm (Run \u2192 Attach to Node.js/Chrome) to 127.0.0.1:${h.basePort} \u2014 or click the "Debugger listening" link in \`lensmcp logs ${r}\`.`:"Attach WebStorm (Run \u2192 Attach to Node.js/Chrome) using one of the URLs above \u2014 the ports are ephemeral, so there is no fixed address to configure. Set LENSMCP_DEBUG_FIXED_PORTS=1 if you need a stable one."),{exitCode:0}}p(ss,"is"),d(ss,"runDebug");function b(t){if(t!==void 0)return typeof t=="string"?t:void 0}p(b,"b"),d(b,"stringFlag");function I(t,n={}){const e=new Set(n.string??[]),s=new Set(n.boolean??[]),o={},r=[];for(let i=0;i<t.length;i++){const c=t[i];if(c.startsWith("--")){const l=c.indexOf("="),a=l===-1?c:c.slice(0,l);if(s.has(a))o[a]=!0;else if(e.has(a))if(l!==-1)o[a]=c.slice(l+1);else{const u=t[i+1];u===void 0||u.startsWith("--")?o[a]="":(o[a]=u,i++)}else o[a]=l===-1?!0:c.slice(l+1)}else r.push(c)}return{flags:o,positional:r}}p(I,"_"),d(I,"parseFlags");
238
+ Install @lensmcp/cluster, or \`yarn nx build @lensmcp/cluster\` in the workspace.`),{exitCode:1})}h(ts,"$s"),l(ts,"runRollout");function ss(t){let n=t;for(let e=0;e<6;e++){for(const o of[w(n,"node_modules","@lensmcp","cluster","executors","gateway","main.rollout.js"),w(n,"dist","libs","cluster","executors","gateway","main.rollout.js")])if(P(o))return o;const s=_(n);if(s===n)break;n=s}}h(ss,"bs"),l(ss,"findRolloutBundle");function _e(t){return me(t,"main.js")}h(_e,"ln"),l(_e,"findMcpBinary");function ns(t){return me(t,"shim.js")}h(ns,"Cs"),l(ns,"findShimBinary");function me(t,n){return mn(t,n,te())}h(me,"$e"),l(me,"findServerBundle");function os(t){const n=w(te(),"bundled","bridge.js");if(P(n))return n;let e=t;for(let s=0;s<5;s++){const o=w(e,"libs","bridge","dist","main.js");if(P(o))return o;const r=_(e);if(r===e)break;e=r}}h(os,"Ss"),l(os,"findBridgeBundle");function rs(t){const n=w(te(),"bundled","lint-runner.js");if(P(n))return n;let e=t;for(let s=0;s<5;s++){const o=w(e,"libs","session","dist","lint-runner.js");if(P(o))return o;const r=_(e);if(r===e)break;e=r}}h(rs,"js"),l(rs,"findLintRunner");function ce(t){let n=t;for(let e=0;e<5;e++){const s=w(n,"node_modules",".bin","nx");if(P(s))return s;const o=_(n);if(o===n)break;n=o}}h(ce,"ue"),l(ce,"findNxBinary");function de(t){const n=w(t,".lensmcp");P(n)||Q(n,{recursive:!0})}h(de,"fe"),l(de,"ensureLensmcpDir");function is(){return!!(process.stdin.isTTY&&process.stdout.isTTY)}h(is,"xs"),l(is,"isInteractive");function se(){const t=Ss(),n=[],e=l((s,o)=>{try{for(const r of le(s,{withFileTypes:!0})){if(!r.isDirectory()||!r.name.endsWith("-devserver"))continue;const i=w(s,r.name,"parent.sock");P(i)&&n.push({service:r.name.slice(0,-10),wsKey:o,sock:i})}}catch{}},"scan");e(t,"");try{for(const s of le(t,{withFileTypes:!0}))s.isDirectory()&&/^[a-z0-9][a-z0-9-]*$/.test(s.name)&&!s.name.endsWith("-devserver")&&e(w(t,s.name),s.name)}catch{}return n.sort((s,o)=>`${s.wsKey}/${s.service}`.localeCompare(`${o.wsKey}/${o.service}`))}h(se,"te"),l(se,"discoverDevserverSocks");const U=l(t=>t.wsKey?`${t.wsKey}/${t.service}`:t.service,"fullServiceName");function De(t){try{const n=R("lsof",["-t",t],{encoding:"utf8"}),e=Number((n.stdout??"").split(`
239
+ `)[0]?.trim());return Number.isInteger(e)&&e>0?e:void 0}catch{return}}h(De,"pn"),l(De,"pidOnSocket");function Fe(t){try{const n=R("ps",["-o","pgid=","-p",String(t)],{encoding:"utf8"}),e=Number((n.stdout??"").trim());return Number.isInteger(e)&&e>1?e:void 0}catch{return}}h(Fe,"un"),l(Fe,"pgidOf");function as(t){try{const n=(R("lsof",["-a","-p",String(t),"-d","cwd","-Fn"],{encoding:"utf8"}).stdout??"").split(`
240
+ `).find(e=>e.startsWith("n"));return n&&n.slice(1).trim()||void 0}catch{return}}h(as,"Ps"),l(as,"cwdOfPid");function cs(t,n){const e=Ve(L(t),L(n));return e===""||!e.startsWith("..")&&!xs(e)}h(cs,"Ns"),l(cs,"isInside");function ds(t,n){return se().filter(e=>{if(e.wsKey)return e.wsKey===n;const s=De(e.sock),o=s!==void 0?as(s):void 0;return o!==void 0&&cs(t,o)})}h(ds,"Es"),l(ds,"workspaceDevservers");function ls(t,n,e,s){const o=ds(t,n);if(o.length===0)return e(" no devserver pods running for this workspace \u2014 nothing to recycle."),{killed:0,stale:0};s&&e(` \xB7 recycling ${o.length} pod${o.length===1?"":"s"} because ${s}`);const r=new Set;for(const d of[process.pid,...V()]){const a=Fe(d);a!==void 0&&r.add(a)}let i=0,c=0;for(const d of o){const a=U(d),u=De(d.sock);if(u===void 0){J(d.sock),e(` \u2713 ${a} \u2014 stale socket removed (no process held it)`),c++;continue}const p=Fe(u),f=p!==void 0&&!r.has(p),m=l(v=>{try{f?process.kill(-p,v):process.kill(u,v)}catch{}},"signal");m("SIGTERM"),Ke(u,5e3)||(m("SIGKILL"),Ke(u,2e3)),J(d.sock),e(` \u2713 ${a} \u2014 stopped (pid ${u}${f?`, group ${p}`:", parent only"})`),i++}return{killed:i,stale:c}}h(ls,"Ms"),l(ls,"reapWorkspacePods");function Ke(t,n){const e=Date.now()+n;for(;;){if(!re(t))return!0;if(Date.now()>=e)return!1;R("sleep",["0.15"])}}h(Ke,"fn"),l(Ke,"waitForPidGone");function us(t,n,e,s){const o=w(n,".lensmcp","gateway.pid"),r=w(n,".lensmcp","registered.json"),{pid:i,healed:c}=ie(o,n);if(c&&s(` healed: adopted a running gateway (pid ${i}) the pid file had lost.`),oe(n,t.env,f=>s(` ${f}`)),H(n)!==void 0){s(` gateway: this workspace owns the :443 daemon (pid ${i??"?"}) \u2014 left running, pods respawn fresh.`);return}const d=A("GET","/list");if(d?.status!==200){s(" gateway: not running. Start it when you are ready: lensmcp gateway start");return}const a=d.json&&typeof d.json=="object"?d.json.workspaces??[]:[],u=ot(a,e,n);if(u.kind==="other-checkout"){for(const f of nt(e,u.root,n))s(` gateway: ${f}`);return}if(u.kind==="mine"){Q(_(r),{recursive:!0}),q(r,JSON.stringify({wsKey:e})),s(` gateway: '${e}' is already registered into the shared daemon \u2014 left serving.`);return}const p=A("POST","/register",fe(n,e));if(p&&p.status===200){Q(_(r),{recursive:!0}),q(r,JSON.stringify({wsKey:e})),s(` gateway: registered '${e}' into the shared daemon \u2014 it now hosts this workspace.`);const f=Ce(p.json);f&&s(f);return}s(` gateway: a shared daemon is up but registering this workspace failed \u2014 ${he(p)??"run `lensmcp gateway start`"}.`)}h(us,"Ls"),l(us,"reconcileGatewayAfterSetup");function we(t,n,e,s){let o=n.filter(r=>r.service===t||U(r)===t);if(o.length>1)try{const r=Y(e).key,i=o.filter(c=>c.wsKey===r);i.length===1&&(o=i)}catch{}return o.length===0?(s(`No running service named "${t}".`),n.length>0&&s(`Running: ${n.map(U).join(", ")}`),null):o.length>1?(s(`"${t}" is ambiguous \u2014 use one of: ${o.map(U).join(", ")}`),null):o[0]}h(we,"be"),l(we,"resolveServiceSock");async function ps(t,n,e,s){const o=I(n,{string:["--tail","--cwd"],boolean:["--no-follow","--plain","--color"]}),r=o.positional[0],i=se();if(!r){if(i.length===0)e("No running services found (no devserver control sockets under $TMPDIR)."),e("Start one with `yarn nx serve <project>` or `lensmcp gateway start`.");else{e("Running services \u2014 attach with `lensmcp logs <service>`:");for(const m of i)e(` ${U(m)}`)}return{exitCode:0}}const c=we(r,i,L(b(o.flags["--cwd"])??t.cwd),s);if(!c)return{exitCode:1};const d=o.flags["--no-follow"]!==!0,a=Number(b(o.flags["--tail"])??NaN),u=Number.isInteger(a)&&a>=0?a:100,p=o.flags["--plain"]===!0||o.flags["--color"]!==!0&&!process.stdout.isTTY,f=`/webpack/logs?tail=${u}&follow=${d?1:0}${p?"&plain=1":""}`;return new Promise(m=>{const v=Be({socketPath:c.sock,path:f,method:"GET"},k=>{k.on("data",j=>process.stdout.write(j)),Ps(()=>{k.destroy(),m({exitCode:0})}),k.on("end",()=>m({exitCode:0})),k.on("error",()=>m({exitCode:1}))});v.on("error",k=>{s(`Cannot attach to ${U(c)}: ${k.message}`),s("The devserver may have crashed leaving a stale socket \u2014 restart the service and retry."),m({exitCode:1})}),v.end()})}h(ps,"Ts"),l(ps,"runLogs");async function hs(t,n,e,s){const o=I(n,{string:["--port","--cwd"]}),r=o.positional[0],i=se();if(!r)return s("Usage: lensmcp debug <service> [--port <base>]"),i.length>0&&s(`Running: ${i.map(U).join(", ")}`),{exitCode:2};const c=we(r,i,L(b(o.flags["--cwd"])??t.cwd),s);if(!c)return{exitCode:1};const d=Number(b(o.flags["--port"])??"")||void 0,a=`/webpack/debug${d?`?port=${d}`:""}`,u=await new Promise(f=>{const m=Be({socketPath:c.sock,path:a,method:"POST"},v=>{let k="";v.on("data",j=>k+=j),v.on("end",()=>f(k)),v.on("error",()=>f(null))});m.on("error",()=>f(null)),m.end()});if(u===null)return s(`Cannot reach ${U(c)} \u2014 the devserver may have crashed leaving a stale socket.`),{exitCode:1};let p;try{p=JSON.parse(u)}catch{return s(`Unexpected response from the devserver: ${u.slice(0,200)}`),{exitCode:1}}e(`Inspectors open on ${U(c)} \u2014 in place, no restart:`);for(const f of p.pods??[])e(` pod #${f.id} ${f.inspectorUrl??"(no url reported \u2014 check lensmcp logs)"}`);for(const f of p.workers??[])e(` worker ${f.name} ${f.inspectorUrl??`127.0.0.1:${f.port}`}`);return e(p.fixedPorts&&p.basePort?`Attach WebStorm (Run \u2192 Attach to Node.js/Chrome) to 127.0.0.1:${p.basePort} \u2014 or click the "Debugger listening" link in \`lensmcp logs ${r}\`.`:`Attach with one of the URLs above \u2014 Chrome DevTools (devtools://devtools/bundled/js_app.html?ws=<host:port/uuid>), VS Code (attach, "websocketAddress"), or WebStorm's click-to-attach on the URL. The ports are ephemeral and do not answer /json/list, so a host:port attach finds nothing; set LENSMCP_DEBUG_FIXED_PORTS=1 if your IDE needs one.`),{exitCode:0}}h(hs,"Rs"),l(hs,"runDebug");async function gs(t,n,e,s){return rn(n,t.cwd,e,s,{discover:se,resolveService:we,workspaceKey:l(o=>{try{return ve(o).key}catch{return}},"workspaceKey"),analyzerScript:w(_(He(import.meta.url)),"heap-analyzer-main.js"),env:t.env??process.env})}h(gs,"Os"),l(gs,"runMem");async function fs(t,n){let e;try{e=ve(t).key}catch{e=void 0}const s=[],o=[];for(const i of se().filter(c=>c.wsKey===e||c.wsKey==="")){const c=await on(i);if(!c.memory){i.wsKey===e&&o.push(`${i.service}: ${c.error??"no answer"}`);continue}const d=c.memory.bundle.path;if(i.wsKey===""&&!d.startsWith(t+"/"))continue;const a=c.memory.pods.map(p=>p.latest?.sourceMaps).filter(p=>typeof p=="boolean"),u=await an(d);s.push({service:i.service,...a.length?{sourceMaps:a.some(Boolean)}:{},...u?{bundle:u}:{}})}const r=cn(s,o);N(n,r.status,"running services keep one copy of their bundle text",r.detail,r.hint)}h(fs,"_s"),l(fs,"checkPodSourceMaps");async function ms(t,n,e){const s=dn(await ln(t,n));N(e,s.status,"performance rules (perf://rules)",s.detail,s.hint)}h(ms,"As"),l(ms,"checkPerfRules");function b(t){if(t!==void 0)return typeof t=="string"?t:void 0}h(b,"b"),l(b,"stringFlag");function I(t,n={}){const e=new Set(n.string??[]),s=new Set(n.boolean??[]),o={},r=[];for(let i=0;i<t.length;i++){const c=t[i];if(c.startsWith("--")){const d=c.indexOf("="),a=d===-1?c:c.slice(0,d);if(s.has(a))o[a]=!0;else if(e.has(a))if(d!==-1)o[a]=c.slice(d+1);else{const u=t[i+1];u===void 0||u.startsWith("--")?o[a]="":(o[a]=u,i++)}else o[a]=d===-1?!0:c.slice(d+1)}else r.push(c)}return{flags:o,positional:r}}h(I,"A"),l(I,"parseFlags");
@@ -0,0 +1,17 @@
1
+ /** Must equal the dashboard's `LOGIN_PARAM`. */
2
+ export declare const LOGIN_PARAM = "__lensmcp_login";
3
+ /** Must equal the dashboard's `LOGIN_TTL_MS`. */
4
+ export declare const LOGIN_TTL_MS: number;
5
+ export declare function dashboardTokenPath(workspaceRoot: string): string;
6
+ /**
7
+ * The workspace's dashboard token, or undefined when there is none to sign in with — none minted yet,
8
+ * or `LENSMCP_ALLOW_INSECURE=1` (the dashboard then asks for nothing, so a link would be noise).
9
+ */
10
+ export declare function readDashboardToken(workspaceRoot: string, env?: NodeJS.ProcessEnv): string | undefined;
11
+ /** `<expiry ms>.<nonce>.<hmac>` — exactly what the dashboard's `LoginLedger` redeems. */
12
+ export declare function mintDashboardLoginCode(token: string, now: number, nonce?: string): string;
13
+ /**
14
+ * A sign-in link for `pageUrl` (the dashboard's own URL, e.g. `https://lensmcp.local/<key>/`), or
15
+ * undefined when the workspace has no token to sign in with.
16
+ */
17
+ export declare function dashboardLoginUrl(pageUrl: string, workspaceRoot: string, env?: NodeJS.ProcessEnv, now?: number): string | undefined;
@@ -0,0 +1,3 @@
1
+ "use strict";var i=Object.defineProperty;var a=(o,r)=>i(o,"name",{value:r,configurable:!0});var d=Object.defineProperty,s=a((o,r)=>d(o,"name",{value:r,configurable:!0}),"i");import{createHmac as c,randomBytes as u}from"node:crypto";import{lstatSync as p,readFileSync as f}from"node:fs";import{join as h}from"node:path";export const LOGIN_PARAM="__lensmcp_login",LOGIN_TTL_MS=10*6e4;export function dashboardTokenPath(o){return h(o,".lensmcp","dashboard-token")}a(dashboardTokenPath,"dashboardTokenPath"),s(dashboardTokenPath,"dashboardTokenPath");export function readDashboardToken(o,r=process.env){if(r.LENSMCP_ALLOW_INSECURE==="1")return;const e=r.LENSMCP_DASHBOARD_TOKEN?.trim();if(e)return e;const t=dashboardTokenPath(o);try{const n=p(t);return!n.isFile()||typeof process.getuid=="function"&&n.uid!==process.getuid()?void 0:f(t,"utf8").trim()||void 0}catch{return}}a(readDashboardToken,"readDashboardToken"),s(readDashboardToken,"readDashboardToken");export function mintDashboardLoginCode(o,r,e=u(16).toString("hex")){const t=r+LOGIN_TTL_MS,n=c("sha256",o).update(`lensmcp-dashboard-login
2
+ ${t}
3
+ ${e}`).digest("hex");return`${t}.${e}.${n}`}a(mintDashboardLoginCode,"mintDashboardLoginCode"),s(mintDashboardLoginCode,"mintDashboardLoginCode");export function dashboardLoginUrl(o,r,e=process.env,t=Date.now()){const n=readDashboardToken(r,e);if(n)return`${o}${o.includes("?")?"&":"?"}${LOGIN_PARAM}=${mintDashboardLoginCode(n,t)}`}a(dashboardLoginUrl,"dashboardLoginUrl"),s(dashboardLoginUrl,"dashboardLoginUrl");