@lensmcp/nx-plugin 1.21.5 → 1.22.1

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.
@@ -23,4 +23,15 @@ interface ExecutorResult {
23
23
  * what's happening. Ctrl-C triggers a clean teardown.
24
24
  */
25
25
  export default function agentDevExecutor(options: AgentDevExecutorSchema, context: ExecutorContext): Promise<ExecutorResult>;
26
+ /**
27
+ * May automatic capture point a browser at this URL?
28
+ *
29
+ * Loopback only, unless `LENSMCP_CAPTURE_ALLOW_REMOTE=1` says otherwise. `agent-dev` starts capture
30
+ * by DEFAULT, so `openUrl` is the one place a workspace config decides what a browser on the
31
+ * developer's machine renders — and, with the sandbox restored (issues/codex-security/60), a target
32
+ * on the open internet is a decision worth stating rather than inheriting.
33
+ *
34
+ * Anything that does not parse, and any scheme other than http/https, is not local.
35
+ */
36
+ export declare function isLocalCaptureTarget(url: string, env?: NodeJS.ProcessEnv): boolean;
26
37
  export {};
@@ -1,4 +1,4 @@
1
- "use strict";var L=Object.defineProperty;var E=(t,o)=>L(t,"name",{value:o,configurable:!0});var T=Object.defineProperty,l=E((t,o)=>T(t,"name",{value:o,configurable:!0}),"l");Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=agentDevExecutor;const node_child_process_1=require("node:child_process"),node_fs_1=require("node:fs"),node_path_1=require("node:path"),lens_frontend_1=require("../../lens-frontend");async function agentDevExecutor(t,o){const n={kind:t.kind??"vite-react",chrome:t.chrome??!0,headless:t.headless??!0,node:t.node??!0,devTarget:t.devTarget,projectRoot:t.projectRoot,port:t.port,openUrl:t.openUrl,devCommand:t.devCommand,wsPort:t.wsPort};if(n.kind!=="vite-react"&&n.kind!=="nestjs"&&n.kind!=="imported")return console.error(`[agent-dev] supported kinds are "vite-react", "nestjs", "imported" (got "${n.kind}").`),{success:!1};const P=o.projectName,d=n.projectRoot?(0,node_path_1.resolve)(o.root,n.projectRoot):P&&o.projectsConfigurations?(0,node_path_1.resolve)(o.root,o.projectsConfigurations.projects[P]?.root??"."):o.root;if(n.kind==="nestjs")return runNestjs(d,o);if(n.kind==="imported")return runImported(d,o,{devCommand:n.devCommand,chrome:n.chrome,headless:n.headless,openUrl:n.openUrl,wsPort:n.wsPort??5747,node:n.node});const a=(0,lens_frontend_1.findMcpBundle)(o.root);a||console.warn("[agent-dev] No lensmcp-mcp bundle found \u2014 skipping MCP server. Install the self-contained CLI: `npm i -D lensmcp` (it ships `bundled/main.js`).");const S=[],c=new Map;let s=!1;function p(e,r,v,g,C=!1,i){const w=(0,node_child_process_1.spawn)(r,v,{cwd:d,env:{...process.env,...g??{}},stdio:"inherit"});return S.push(w),w.on("exit",(f,h)=>{if(!s){if(C){const N=c.get(e)??0;if(i&&N<i.max){c.set(e,N+1),console.warn(`[agent-dev] ${e} exited (code=${f} sig=${h}); respawning in ${Math.round(i.delayMs/1e3)}s (${N+1}/${i.max}).`),setTimeout(()=>{s||p(e,r,v,g,C,i)},i.delayMs).unref?.();return}console.warn(`[agent-dev] ${e} exited (code=${f} sig=${h}); continuing.`);return}console.warn(`[agent-dev] ${e} exited unexpectedly (code=${f} sig=${h}); shutting down others.`),u()}}),w}E(p,"d"),l(p,"spawnChild");function u(){if(!s){s=!0;for(const e of S)try{e.kill("SIGTERM")}catch{}}}E(u,"a"),l(u,"shutdown"),process.on("SIGINT",u),process.on("SIGTERM",u);const m=process.env.LENSMCP_EVENT_FILE??(0,node_path_1.join)(o.root,".lensmcp","events.jsonl");try{(0,node_fs_1.mkdirSync)((0,node_path_1.dirname)(m),{recursive:!0});const e=(0,node_fs_1.statSync)(m,{throwIfNoEntry:!1});!e||Date.now()-e.mtimeMs>6e4?(0,node_fs_1.writeFileSync)(m,""):console.log("[agent-dev] event bridge is active (written <60s ago) \u2014 appending, not truncating.")}catch{}const M={LENSMCP_EVENT_FILE:m};console.log(`[agent-dev] event bridge \u2192 ${m}`);try{(0,lens_frontend_1.spawnLensFrontend)({projectRoot:d,workspaceRoot:o.root,...P?{project:P}:{},eventFile:m,...n.port!==void 0?{port:n.port}:{},chrome:n.chrome,headless:n.headless,...n.openUrl?{openUrl:n.openUrl}:{},log:l(e=>console.log(e),"log")},p)}catch(e){return console.error(e.message),u(),{success:!1}}return a&&(console.log(`[agent-dev] starting LensMCP MCP server (${a})`),p("lensmcp-mcp",process.execPath,[a],{...M,LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_PORT:process.env.LENSMCP_PORT??"3000"})),new Promise(e=>{const r=l(()=>{s?Promise.allSettled(S.map(v=>new Promise(g=>{v.exitCode!==null?g():v.on("exit",()=>g())}))).then(()=>e({success:!0})):setTimeout(r,500)},"tick");r()})}E(agentDevExecutor,"agentDevExecutor"),l(agentDevExecutor,"agentDevExecutor");async function runNestjs(t,o){const n=o.projectName,P=(n?o.projectsConfigurations?.projects[n]?.targets?.build:void 0)?.options?.outputPath,d=[...typeof P=="string"?[(0,node_path_1.join)(o.root,P,"main.js")]:[],(0,node_path_1.join)(t,"dist","main.js"),(0,node_path_1.join)(o.root,"dist",(0,node_path_1.relative)(o.root,t),"main.js")],a=d.find(c=>(0,node_fs_1.existsSync)(c));if(!a)return console.error(`[agent-dev] No built NestJS entry found. Looked in:
2
- `+d.map(c=>` \u2022 ${c}`).join(`
1
+ "use strict";var L=Object.defineProperty;var P=(t,o)=>L(t,"name",{value:o,configurable:!0});var M=Object.defineProperty,d=P((t,o)=>M(t,"name",{value:o,configurable:!0}),"d");Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=agentDevExecutor,exports.isLocalCaptureTarget=isLocalCaptureTarget;const node_child_process_1=require("node:child_process"),node_fs_1=require("node:fs"),node_path_1=require("node:path"),lens_frontend_1=require("../../lens-frontend");async function agentDevExecutor(t,o){const e={kind:t.kind??"vite-react",chrome:t.chrome??!0,headless:t.headless??!0,node:t.node??!0,devTarget:t.devTarget,projectRoot:t.projectRoot,port:t.port,openUrl:t.openUrl,devCommand:t.devCommand,wsPort:t.wsPort};if(e.kind!=="vite-react"&&e.kind!=="nestjs"&&e.kind!=="imported")return console.error(`[agent-dev] supported kinds are "vite-react", "nestjs", "imported" (got "${e.kind}").`),{success:!1};const r=o.projectName,p=e.projectRoot?(0,node_path_1.resolve)(o.root,e.projectRoot):r&&o.projectsConfigurations?(0,node_path_1.resolve)(o.root,o.projectsConfigurations.projects[r]?.root??"."):o.root;if(e.kind==="nestjs")return runNestjs(p,o);if(e.kind==="imported")return runImported(p,o,{devCommand:e.devCommand,chrome:e.chrome,headless:e.headless,openUrl:e.openUrl,wsPort:e.wsPort??5747,node:e.node});const l=(0,lens_frontend_1.findMcpBundle)(o.root);l||console.warn("[agent-dev] No lensmcp-mcp bundle found \u2014 skipping MCP server. Install the self-contained CLI: `npm i -D lensmcp` (it ships `bundled/main.js`).");const h=[],c=new Map;let s=!1;function u(n,i,v,f,w=!1,a){const C=(0,node_child_process_1.spawn)(i,v,{cwd:p,env:{...process.env,...f??{}},stdio:"inherit"});return h.push(C),C.on("exit",(S,E)=>{if(!s){if(w){const N=c.get(n)??0;if(a&&N<a.max){c.set(n,N+1),console.warn(`[agent-dev] ${n} exited (code=${S} sig=${E}); respawning in ${Math.round(a.delayMs/1e3)}s (${N+1}/${a.max}).`),setTimeout(()=>{s||u(n,i,v,f,w,a)},a.delayMs).unref?.();return}console.warn(`[agent-dev] ${n} exited (code=${S} sig=${E}); continuing.`);return}console.warn(`[agent-dev] ${n} exited unexpectedly (code=${S} sig=${E}); shutting down others.`),m()}}),C}P(u,"l"),d(u,"spawnChild");function m(){if(!s){s=!0;for(const n of h)try{n.kill("SIGTERM")}catch{}}}P(m,"u"),d(m,"shutdown"),process.on("SIGINT",m),process.on("SIGTERM",m);const g=process.env.LENSMCP_EVENT_FILE??(0,node_path_1.join)(o.root,".lensmcp","events.jsonl");try{(0,node_fs_1.mkdirSync)((0,node_path_1.dirname)(g),{recursive:!0});const n=(0,node_fs_1.statSync)(g,{throwIfNoEntry:!1});!n||Date.now()-n.mtimeMs>6e4?(0,node_fs_1.writeFileSync)(g,""):console.log("[agent-dev] event bridge is active (written <60s ago) \u2014 appending, not truncating.")}catch{}const _={LENSMCP_EVENT_FILE:g};console.log(`[agent-dev] event bridge \u2192 ${g}`);try{(0,lens_frontend_1.spawnLensFrontend)({projectRoot:p,workspaceRoot:o.root,...r?{project:r}:{},eventFile:g,...e.port!==void 0?{port:e.port}:{},chrome:e.chrome,headless:e.headless,...e.openUrl?{openUrl:e.openUrl}:{},log:d(n=>console.log(n),"log")},u)}catch(n){return console.error(n.message),m(),{success:!1}}return l&&(console.log(`[agent-dev] starting LensMCP MCP server (${l})`),u("lensmcp-mcp",process.execPath,[l],{..._,LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_PORT:process.env.LENSMCP_PORT??"3000"})),new Promise(n=>{const i=d(()=>{s?Promise.allSettled(h.map(v=>new Promise(f=>{v.exitCode!==null?f():v.on("exit",()=>f())}))).then(()=>n({success:!0})):setTimeout(i,500)},"tick");i()})}P(agentDevExecutor,"agentDevExecutor"),d(agentDevExecutor,"agentDevExecutor");async function runNestjs(t,o){const e=o.projectName,r=(e?o.projectsConfigurations?.projects[e]?.targets?.build:void 0)?.options?.outputPath,p=[...typeof r=="string"?[(0,node_path_1.join)(o.root,r,"main.js")]:[],(0,node_path_1.join)(t,"dist","main.js"),(0,node_path_1.join)(o.root,"dist",(0,node_path_1.relative)(o.root,t),"main.js")],l=p.find(c=>(0,node_fs_1.existsSync)(c));if(!l)return console.error(`[agent-dev] No built NestJS entry found. Looked in:
2
+ `+p.map(c=>` \u2022 ${c}`).join(`
3
3
  `)+`
4
- Build first: \`nx build ${n??"<project>"}\`.`),{success:!1};console.log(`[agent-dev] node ${a}`);const S=(0,node_child_process_1.spawn)(process.execPath,[a],{cwd:t,stdio:"inherit",env:{...process.env,LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_EVENT_FILE:process.env.LENSMCP_EVENT_FILE??(0,node_path_1.join)(o.root,".lensmcp","events.jsonl")}});return new Promise(c=>{const s=l(()=>{try{S.kill("SIGTERM")}catch{}},"onSignal");process.on("SIGINT",s),process.on("SIGTERM",s),S.on("exit",p=>{process.off("SIGINT",s),process.off("SIGTERM",s),c({success:p===0})})})}E(runNestjs,"runNestjs"),l(runNestjs,"runNestjs");async function runImported(t,o,n){if(!n.devCommand)return console.error('[agent-dev] kind="imported" needs a `devCommand` (your dev-server command, e.g. "npm run dev").\n Add it to the agent-dev target options, or pass `--devCommand "npm run dev"`.'),{success:!1};const P=(0,lens_frontend_1.findBridgeBundle)(o.root);if(!P)return console.error("[agent-dev] No lensmcp bridge bundle found. Install the self-contained CLI: `npm i -D lensmcp` (it ships `bundled/bridge.js`)."),{success:!1};const d=(0,lens_frontend_1.findMcpBundle)(o.root);d||console.warn("[agent-dev] No lensmcp-mcp bundle found \u2014 skipping MCP server. Install the self-contained CLI: `npm i -D lensmcp`.");const a=[],S=new Map;let c=!1;function s(e,r,v,g,C=!1,i,w=!1){const f=(0,node_child_process_1.spawn)(r,v,{cwd:t,env:{...process.env,...g??{}},stdio:"inherit",shell:w});return a.push(f),f.on("exit",(h,N)=>{if(!c){if(C){const _=S.get(e)??0;if(i&&_<i.max){S.set(e,_+1),console.warn(`[agent-dev] ${e} exited (code=${h} sig=${N}); respawning in ${Math.round(i.delayMs/1e3)}s (${_+1}/${i.max}).`),setTimeout(()=>{c||s(e,r,v,g,C,i,w)},i.delayMs).unref?.();return}console.warn(`[agent-dev] ${e} exited (code=${h} sig=${N}); continuing.`);return}console.warn(`[agent-dev] ${e} exited unexpectedly (code=${h} sig=${N}); shutting down others.`),p()}}),f}E(s,"r"),l(s,"spawnChild");function p(){if(!c){c=!0;for(const e of a)try{e.kill("SIGTERM")}catch{}}}E(p,"d"),l(p,"shutdown"),process.on("SIGINT",p),process.on("SIGTERM",p);const u=process.env.LENSMCP_EVENT_FILE??(0,node_path_1.join)(o.root,".lensmcp","events.jsonl");try{(0,node_fs_1.mkdirSync)((0,node_path_1.dirname)(u),{recursive:!0});const e=(0,node_fs_1.statSync)(u,{throwIfNoEntry:!1});!e||Date.now()-e.mtimeMs>6e4?(0,node_fs_1.writeFileSync)(u,""):console.log("[agent-dev] event bridge is active (written <60s ago) \u2014 appending, not truncating.")}catch{}const m={LENSMCP_EVENT_FILE:u};console.log(`[agent-dev] event bridge \u2192 ${u}`),console.log(`[agent-dev] starting bridge \u2192 ws://127.0.0.1:${n.wsPort}`),s("bridge",process.execPath,[P],{...m,LENSMCP_WS_HOST:process.env.LENSMCP_WS_HOST??"127.0.0.1",LENSMCP_WS_PORT:String(n.wsPort)}),d&&(console.log(`[agent-dev] starting LensMCP MCP server (${d})`),s("lensmcp-mcp",process.execPath,[d],{...m,LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_PORT:process.env.LENSMCP_PORT??"3000"}));const M={...m,LENSMCP_WS_PORT:String(n.wsPort)};if(n.node)if([t,o.root].some(e=>(0,node_fs_1.existsSync)((0,node_path_1.join)(e,"node_modules","@lensmcp","node-instrumentation")))){const e="--import @lensmcp/node-instrumentation/register";M.NODE_OPTIONS=process.env.NODE_OPTIONS?`${process.env.NODE_OPTIONS} ${e}`:e,console.log("[agent-dev] backend taps: NODE_OPTIONS += --import @lensmcp/node-instrumentation/register")}else console.warn("[agent-dev] @lensmcp/node-instrumentation not installed \u2014 skipping backend taps. Add it: `npm i -D @lensmcp/node-instrumentation`.");if(console.log(`[agent-dev] front-end seam: add \`import '@lensmcp/client-runtime/auto'\` to your app entry (connects to ws://127.0.0.1:${n.wsPort}).`),console.log(`[agent-dev] starting dev command: ${n.devCommand}`),s("dev",n.devCommand,[],M,!1,void 0,!0),n.chrome){const e=(0,lens_frontend_1.findCaptureRunner)(o.root),r=n.openUrl;e?r?(console.log(`[agent-dev] starting browser capture \u2192 ${r}`),s("browser-capture",process.execPath,[e],{...m,LENSMCP_DEV_URL:r,LENSMCP_TOKENS_FILE:(0,node_path_1.join)(o.root,"lensmcp.tokens.json"),LENSMCP_RULES_FILE:(0,node_path_1.join)(o.root,"lensmcp.rules.json"),LENSMCP_HEADLESS:n.headless===!1?"false":"true"},!0,{delayMs:1e4,max:5})):console.warn("[agent-dev] no `openUrl` provided \u2014 skipping Chrome capture (set openUrl to your dev URL)."):console.warn("[agent-dev] browser-capture runner not found \u2014 skipping live capture. Install the self-contained CLI: `npm i -D lensmcp`.")}return new Promise(e=>{const r=l(()=>{c?Promise.allSettled(a.map(v=>new Promise(g=>{v.exitCode!==null?g():v.on("exit",()=>g())}))).then(()=>e({success:!0})):setTimeout(r,500)},"tick");r()})}E(runImported,"runImported"),l(runImported,"runImported");
4
+ Build first: \`nx build ${e??"<project>"}\`.`),{success:!1};console.log(`[agent-dev] node ${l}`);const h=(0,node_child_process_1.spawn)(process.execPath,[l],{cwd:t,stdio:"inherit",env:{...process.env,LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_EVENT_FILE:process.env.LENSMCP_EVENT_FILE??(0,node_path_1.join)(o.root,".lensmcp","events.jsonl")}});return new Promise(c=>{const s=d(()=>{try{h.kill("SIGTERM")}catch{}},"onSignal");process.on("SIGINT",s),process.on("SIGTERM",s),h.on("exit",u=>{process.off("SIGINT",s),process.off("SIGTERM",s),c({success:u===0})})})}P(runNestjs,"runNestjs"),d(runNestjs,"runNestjs");async function runImported(t,o,e){if(!e.devCommand)return console.error('[agent-dev] kind="imported" needs a `devCommand` (your dev-server command, e.g. "npm run dev").\n Add it to the agent-dev target options, or pass `--devCommand "npm run dev"`.'),{success:!1};const r=(0,lens_frontend_1.findBridgeBundle)(o.root);if(!r)return console.error("[agent-dev] No lensmcp bridge bundle found. Install the self-contained CLI: `npm i -D lensmcp` (it ships `bundled/bridge.js`)."),{success:!1};const p=(0,lens_frontend_1.findMcpBundle)(o.root);p||console.warn("[agent-dev] No lensmcp-mcp bundle found \u2014 skipping MCP server. Install the self-contained CLI: `npm i -D lensmcp`.");const l=[],h=new Map;let c=!1;function s(n,i,v,f,w=!1,a,C=!1){const S=(0,node_child_process_1.spawn)(i,v,{cwd:t,env:{...process.env,...f??{}},stdio:"inherit",shell:C});return l.push(S),S.on("exit",(E,N)=>{if(!c){if(w){const T=h.get(n)??0;if(a&&T<a.max){h.set(n,T+1),console.warn(`[agent-dev] ${n} exited (code=${E} sig=${N}); respawning in ${Math.round(a.delayMs/1e3)}s (${T+1}/${a.max}).`),setTimeout(()=>{c||s(n,i,v,f,w,a,C)},a.delayMs).unref?.();return}console.warn(`[agent-dev] ${n} exited (code=${E} sig=${N}); continuing.`);return}console.warn(`[agent-dev] ${n} exited unexpectedly (code=${E} sig=${N}); shutting down others.`),u()}}),S}P(s,"r"),d(s,"spawnChild");function u(){if(!c){c=!0;for(const n of l)try{n.kill("SIGTERM")}catch{}}}P(u,"l"),d(u,"shutdown"),process.on("SIGINT",u),process.on("SIGTERM",u);const m=process.env.LENSMCP_EVENT_FILE??(0,node_path_1.join)(o.root,".lensmcp","events.jsonl");try{(0,node_fs_1.mkdirSync)((0,node_path_1.dirname)(m),{recursive:!0});const n=(0,node_fs_1.statSync)(m,{throwIfNoEntry:!1});!n||Date.now()-n.mtimeMs>6e4?(0,node_fs_1.writeFileSync)(m,""):console.log("[agent-dev] event bridge is active (written <60s ago) \u2014 appending, not truncating.")}catch{}const g={LENSMCP_EVENT_FILE:m};console.log(`[agent-dev] event bridge \u2192 ${m}`),console.log(`[agent-dev] starting bridge \u2192 ws://127.0.0.1:${e.wsPort}`),s("bridge",process.execPath,[r],{...g,LENSMCP_WS_HOST:process.env.LENSMCP_WS_HOST??"127.0.0.1",LENSMCP_WS_PORT:String(e.wsPort)}),p&&(console.log(`[agent-dev] starting LensMCP MCP server (${p})`),s("lensmcp-mcp",process.execPath,[p],{...g,LENSMCP_TRANSPORT:process.env.LENSMCP_TRANSPORT??"http",LENSMCP_PORT:process.env.LENSMCP_PORT??"3000"}));const _={...g,LENSMCP_WS_PORT:String(e.wsPort)};if(e.node)if([t,o.root].some(n=>(0,node_fs_1.existsSync)((0,node_path_1.join)(n,"node_modules","@lensmcp","node-instrumentation")))){const n="--import @lensmcp/node-instrumentation/register";_.NODE_OPTIONS=process.env.NODE_OPTIONS?`${process.env.NODE_OPTIONS} ${n}`:n,console.log("[agent-dev] backend taps: NODE_OPTIONS += --import @lensmcp/node-instrumentation/register")}else console.warn("[agent-dev] @lensmcp/node-instrumentation not installed \u2014 skipping backend taps. Add it: `npm i -D @lensmcp/node-instrumentation`.");if(console.log(`[agent-dev] front-end seam: add \`import '@lensmcp/client-runtime/auto'\` to your app entry (connects to ws://127.0.0.1:${e.wsPort}).`),console.log(`[agent-dev] starting dev command: ${e.devCommand}`),s("dev",e.devCommand,[],_,!1,void 0,!0),e.chrome){const n=(0,lens_frontend_1.findCaptureRunner)(o.root),i=e.openUrl;n?i?(console.log(`[agent-dev] starting browser capture \u2192 ${i}`),s("browser-capture",process.execPath,[n],{...g,LENSMCP_DEV_URL:i,LENSMCP_TOKENS_FILE:(0,node_path_1.join)(o.root,"lensmcp.tokens.json"),LENSMCP_RULES_FILE:(0,node_path_1.join)(o.root,"lensmcp.rules.json"),LENSMCP_HEADLESS:e.headless===!1?"false":"true"},!0,{delayMs:1e4,max:5})):console.warn("[agent-dev] no `openUrl` provided \u2014 skipping Chrome capture (set openUrl to your dev URL)."):console.warn("[agent-dev] browser-capture runner not found \u2014 skipping live capture. Install the self-contained CLI: `npm i -D lensmcp`.")}return new Promise(n=>{const i=d(()=>{c?Promise.allSettled(l.map(v=>new Promise(f=>{v.exitCode!==null?f():v.on("exit",()=>f())}))).then(()=>n({success:!0})):setTimeout(i,500)},"tick");i()})}P(runImported,"runImported"),d(runImported,"runImported");function isLocalCaptureTarget(t,o=process.env){if(o.LENSMCP_CAPTURE_ALLOW_REMOTE==="1")return!0;let e;try{e=new URL(t)}catch{return!1}if(e.protocol!=="http:"&&e.protocol!=="https:")return!1;const r=e.hostname.toLowerCase();return r==="localhost"||r==="[::1]"||r==="::1"?!0:/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(r)}P(isLocalCaptureTarget,"isLocalCaptureTarget"),d(isLocalCaptureTarget,"isLocalCaptureTarget");
@@ -1,8 +1,16 @@
1
+ import { spawnSync } from 'node:child_process';
1
2
  import type { ExecutorContext } from '@nx/devkit';
2
3
  import type { AgentVerifyExecutorSchema } from './schema';
3
4
  interface ExecutorResult {
4
5
  success: boolean;
5
6
  }
7
+ /**
8
+ * `errored` is not `failed` (issues/codex-security/53). A stage that could not RUN — the binary
9
+ * vanished, the child was killed, its output overran the capture buffer — says nothing about whether
10
+ * the code is correct, and reporting it as a failure tells the agent its fix did not work when the
11
+ * verification never reached a verdict.
12
+ */
13
+ type StageResult = 'passed' | 'failed' | 'skipped' | 'errored';
6
14
  /**
7
15
  * `agent-verify` — the deterministic verification loop the agent runs
8
16
  * to know "did my fix work?".
@@ -18,4 +26,32 @@ interface ExecutorResult {
18
26
  * from `latest.json`.
19
27
  */
20
28
  export default function agentVerifyExecutor(options: AgentVerifyExecutorSchema, context: ExecutorContext): Promise<ExecutorResult>;
29
+ interface StageOutcome {
30
+ result: StageResult;
31
+ exitCode?: number;
32
+ summary?: string;
33
+ }
34
+ /**
35
+ * Run a verify sub-command, capturing its output and re-emitting it INDENTED.
36
+ *
37
+ * agent-verify deliberately runs commands that may fail — it IS the agent's
38
+ * edit→verify loop, so a failing stage is a normal, expected outcome. In CI a
39
+ * raw tool error printed at column 0 (`file(line,col): error TS....`) is picked
40
+ * up by GitHub's problem matchers and turned into a spurious build *annotation*.
41
+ * Indenting every line by two spaces keeps the output fully readable while
42
+ * defeating the matchers (they anchor on a non-space first character), so a
43
+ * verify failure never masquerades as a CI error.
44
+ *
45
+ * `r.error` is inspected, because "the tool could not be run" and "the tool said no" are different
46
+ * answers and only one of them is about the code.
47
+ */
48
+ export declare function runStageCommand(label: string, bin: string, args: string[], cwd: string, spawn?: typeof spawnSync): StageOutcome;
49
+ /** The spawn result → a stage outcome. Split out so every branch is reachable from a test. */
50
+ export declare function classifyStage(r: {
51
+ error?: Error & {
52
+ code?: string;
53
+ };
54
+ status?: number | null;
55
+ signal?: NodeJS.Signals | null;
56
+ }): StageOutcome;
21
57
  export {};
@@ -1,3 +1,3 @@
1
- "use strict";var k=Object.defineProperty;var d=(s,e)=>k(s,"name",{value:e,configurable:!0});var g=Object.defineProperty,l=d((s,e)=>g(s,"name",{value:e,configurable:!0}),"l");Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=agentVerifyExecutor;const node_child_process_1=require("node:child_process"),node_fs_1=require("node:fs"),node_path_1=require("node:path");async function agentVerifyExecutor(s,e){const i={kind:s.kind??"vite-react",skipTypecheck:s.skipTypecheck??!1,skipLint:s.skipLint??!1,skipBuild:s.skipBuild??!1,projectRoot:s.projectRoot},n=e.projectName??null,o=i.projectRoot?(0,node_path_1.resolve)(e.root,i.projectRoot):n&&e.projectsConfigurations?(0,node_path_1.resolve)(e.root,e.projectsConfigurations.projects[n]?.root??"."):e.root,c=Date.now(),r=[];if(i.skipTypecheck)r.push({name:"typecheck",result:"skipped",durationMs:0});else{const t=locateBin("tsc",[o,e.root]),a=resolveFirstExisting(["tsconfig.json"],o);if(!t||!a)r.push({name:"typecheck",result:"skipped",durationMs:0,summary:"no tsc/tsconfig"});else{const u=Date.now(),p=runStageCommand("tsc --noEmit",t,["--noEmit","-p",a],o);r.push({name:"typecheck",result:p.status===0?"passed":"failed",durationMs:Date.now()-u,exitCode:p.status??-1})}}if(i.skipLint)r.push({name:"lint",result:"skipped",durationMs:0});else{const t=locateBin("eslint",[o,e.root]);if(!t)r.push({name:"lint",result:"skipped",durationMs:0,summary:"no eslint"});else{const a=Date.now(),u=runStageCommand("eslint .",t,["."],o);r.push({name:"lint",result:u.status===0?"passed":"failed",durationMs:Date.now()-a,exitCode:u.status??-1})}}if(i.skipBuild)r.push({name:"build",result:"skipped",durationMs:0});else{const t=locateBin("vite",[o,e.root]);if(!t)r.push({name:"build",result:"skipped",durationMs:0,summary:"no vite"});else{const a=resolveFirstExisting(["vite.config.ts","vite.config.js","vite.config.mjs"],o)??(0,node_path_1.join)(o,"vite.config.ts"),u=Date.now(),p=runStageCommand("vite build",t,["build","--config",a,o],o);r.push({name:"build",result:p.status===0?"passed":"failed",durationMs:Date.now()-u,exitCode:p.status??-1})}}const m=r.some(t=>t.result==="failed")?"failed":"passed",f={schemaVersion:1,project:n,timestamp:new Date(c).toISOString(),durationMs:Date.now()-c,status:m,stages:r},y=(0,node_path_1.join)(e.root,".lensmcp","verifications");try{(0,node_fs_1.mkdirSync)(y,{recursive:!0});const t=c,a=`${(n??"app").replace(/[^a-zA-Z0-9_-]+/g,"-")}-${t}.json`;(0,node_fs_1.writeFileSync)((0,node_path_1.join)(y,a),JSON.stringify(f,null,2)+`
2
- `),(0,node_fs_1.writeFileSync)((0,node_path_1.join)(y,"latest.json"),JSON.stringify(f,null,2)+`
3
- `)}catch(t){console.warn(`[agent-verify] could not write report: ${t.message}`)}for(const t of f.stages)console.log(`[agent-verify] ${t.name}: ${t.result}${t.exitCode!==void 0?` (exit ${t.exitCode})`:""}`);return console.log(`[agent-verify] ${m} in ${f.durationMs}ms`),{success:m==="passed"}}d(agentVerifyExecutor,"agentVerifyExecutor"),l(agentVerifyExecutor,"agentVerifyExecutor");function runStageCommand(s,e,i,n){console.log(`[agent-verify] ${s}`);const o=(0,node_child_process_1.spawnSync)(e,i,{cwd:n,encoding:"utf8"}),c=`${o.stdout??""}${o.stderr??""}`;return c.trim()&&process.stdout.write(c.replace(/^(?=.)/gm," ")),o}d(runStageCommand,"runStageCommand"),l(runStageCommand,"runStageCommand");function locateBin(s,e){for(const i of e){const n=(0,node_path_1.join)(i,"node_modules",".bin",s);if((0,node_fs_1.existsSync)(n))return n}}d(locateBin,"locateBin"),l(locateBin,"locateBin");function resolveFirstExisting(s,e){for(const i of s){const n=(0,node_path_1.join)(e,i);if((0,node_fs_1.existsSync)(n))return n}}d(resolveFirstExisting,"resolveFirstExisting"),l(resolveFirstExisting,"resolveFirstExisting"),node_path_1.dirname;
1
+ "use strict";var v=Object.defineProperty;var u=(e,o)=>v(e,"name",{value:o,configurable:!0});var g=Object.defineProperty,d=u((e,o)=>g(e,"name",{value:o,configurable:!0}),"d");Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=agentVerifyExecutor,exports.runStageCommand=runStageCommand,exports.classifyStage=classifyStage;const node_child_process_1=require("node:child_process"),node_fs_1=require("node:fs"),node_path_1=require("node:path");async function agentVerifyExecutor(e,o){const r={kind:e.kind??"vite-react",skipTypecheck:e.skipTypecheck??!1,skipLint:e.skipLint??!1,skipBuild:e.skipBuild??!1,projectRoot:e.projectRoot},n=o.projectName??null,i=r.projectRoot?(0,node_path_1.resolve)(o.root,r.projectRoot):n&&o.projectsConfigurations?(0,node_path_1.resolve)(o.root,o.projectsConfigurations.projects[n]?.root??"."):o.root,c=Date.now(),s=[];if(r.skipTypecheck)s.push({name:"typecheck",result:"skipped",durationMs:0});else{const t=locateBin("tsc",[i,o.root]),a=resolveFirstExisting(["tsconfig.json"],i);if(!t||!a)s.push({name:"typecheck",result:"skipped",durationMs:0,summary:"no tsc/tsconfig"});else{const l=Date.now(),y=runStageCommand("tsc --noEmit",t,["--noEmit","-p",a],i);s.push({name:"typecheck",durationMs:Date.now()-l,...y})}}if(r.skipLint)s.push({name:"lint",result:"skipped",durationMs:0});else{const t=locateBin("eslint",[i,o.root]);if(!t)s.push({name:"lint",result:"skipped",durationMs:0,summary:"no eslint"});else{const a=Date.now(),l=runStageCommand("eslint .",t,["."],i);s.push({name:"lint",durationMs:Date.now()-a,...l})}}if(r.skipBuild)s.push({name:"build",result:"skipped",durationMs:0});else{const t=locateBin("vite",[i,o.root]);if(!t)s.push({name:"build",result:"skipped",durationMs:0,summary:"no vite"});else{const a=resolveFirstExisting(["vite.config.ts","vite.config.js","vite.config.mjs"],i)??(0,node_path_1.join)(i,"vite.config.ts"),l=Date.now(),y=runStageCommand("vite build",t,["build","--config",a,i],i);s.push({name:"build",durationMs:Date.now()-l,...y})}}const f=s.some(t=>t.result==="errored")?"errored":s.some(t=>t.result==="failed")?"failed":"passed",p={schemaVersion:1,project:n,timestamp:new Date(c).toISOString(),durationMs:Date.now()-c,status:f,stages:s},m=(0,node_path_1.join)(o.root,".lensmcp","verifications");try{(0,node_fs_1.mkdirSync)(m,{recursive:!0});const t=c,a=`${(n??"app").replace(/[^a-zA-Z0-9_-]+/g,"-")}-${t}.json`;(0,node_fs_1.writeFileSync)((0,node_path_1.join)(m,a),JSON.stringify(p,null,2)+`
2
+ `),(0,node_fs_1.writeFileSync)((0,node_path_1.join)(m,"latest.json"),JSON.stringify(p,null,2)+`
3
+ `)}catch(t){console.warn(`[agent-verify] could not write report: ${t.message}`)}for(const t of p.stages){const a=t.exitCode!==void 0?` (exit ${t.exitCode})`:t.summary?` \u2014 ${t.summary}`:"";console.log(`[agent-verify] ${t.name}: ${t.result}${a}`)}return console.log(`[agent-verify] ${f} in ${p.durationMs}ms`),{success:f==="passed"}}u(agentVerifyExecutor,"agentVerifyExecutor"),d(agentVerifyExecutor,"agentVerifyExecutor");const STAGE_MAX_BUFFER=(()=>{const e=Number(process.env.LENSMCP_VERIFY_MAX_BUFFER);return Number.isFinite(e)&&e>0?Math.floor(e):64*1024*1024})();function runStageCommand(e,o,r,n,i=node_child_process_1.spawnSync){console.log(`[agent-verify] ${e}`);const c=i(o,r,{cwd:n,encoding:"utf8",maxBuffer:STAGE_MAX_BUFFER}),s=`${c.stdout??""}${c.stderr??""}`;return s.trim()&&process.stdout.write(s.replace(/^(?=.)/gm," ")),classifyStage(c)}u(runStageCommand,"runStageCommand"),d(runStageCommand,"runStageCommand");function classifyStage(e){return e.error?{result:"errored",summary:e.error.code==="ENOBUFS"?`output exceeded the ${STAGE_MAX_BUFFER}-byte capture buffer \u2014 the verification did not reach a verdict (raise LENSMCP_VERIFY_MAX_BUFFER)`:`could not run: ${e.error.message}`}:e.status===null||e.status===void 0?{result:"errored",summary:`terminated${e.signal?` by ${e.signal}`:""} without an exit status`}:{result:e.status===0?"passed":"failed",exitCode:e.status}}u(classifyStage,"classifyStage"),d(classifyStage,"classifyStage");function locateBin(e,o){for(const r of o){const n=(0,node_path_1.join)(r,"node_modules",".bin",e);if((0,node_fs_1.existsSync)(n))return n}}u(locateBin,"locateBin"),d(locateBin,"locateBin");function resolveFirstExisting(e,o){for(const r of e){const n=(0,node_path_1.join)(o,r);if((0,node_fs_1.existsSync)(n))return n}}u(resolveFirstExisting,"resolveFirstExisting"),d(resolveFirstExisting,"resolveFirstExisting"),node_path_1.dirname;
@@ -1,4 +1,39 @@
1
1
  import { type Tree } from '@nx/devkit';
2
2
  import type { InitGeneratorSchema } from './schema';
3
3
  export declare function initGenerator(tree: Tree, rawOptions?: InitGeneratorSchema): Promise<void>;
4
+ /**
5
+ * The stdio MCP server entry a host agent uses to launch LensMCP.
6
+ *
7
+ * issues/codex-security/61: this was `npx -y lensmcp mcp` — an UNVERSIONED specifier that `-y`
8
+ * installs without a word. The spec is not resolved through the workspace lockfile, so every
9
+ * uncached launch could fetch whatever the registry currently answers with, and package lifecycle
10
+ * and bin code then runs with the coding agent user's privileges. A compromised publisher,
11
+ * namespace or registry is the whole attack, and the entry that invites it is committed to the
12
+ * repository, where nobody re-reads it.
13
+ *
14
+ * Two branches, both of which pin:
15
+ *
16
+ * - the workspace already has `lensmcp` installed → `npx --no`, which resolves through
17
+ * `node_modules` and FAILS rather than fetching. The lockfile is then the pin, which is the
18
+ * strongest available and the common case immediately after this generator runs;
19
+ * - it does not → an exact `lensmcp@<version>` taken from this plugin's own version. The
20
+ * `@lensmcp/*` closure is released together with exact internal pins, so the plugin's version is
21
+ * the CLI's. `--yes` stays on that branch deliberately: an MCP host launches a stdio server with
22
+ * no TTY, so a suppressed prompt does not become a visible question — it becomes a hang. The
23
+ * mutable reference was the defect; the pin is what removes it, and the committed specifier is
24
+ * now something a reviewer can audit.
25
+ */
26
+ export declare function mcpServerEntry(workspaceRoot: string, deps?: {
27
+ exists?: (p: string) => boolean;
28
+ version?: string;
29
+ }): {
30
+ command: string;
31
+ args: string[];
32
+ };
33
+ /**
34
+ * This plugin's own version, for the pin above. Walks up from the compiled module rather than
35
+ * hard-coding a depth, because the published package root and the source tree sit at different
36
+ * levels. Returns undefined rather than guessing — an unpinned specifier is better than a wrong one.
37
+ */
38
+ export declare function pluginVersion(from?: string): string | undefined;
4
39
  export default initGenerator;
@@ -1,9 +1,9 @@
1
- "use strict";var f=Object.defineProperty;var p=(n,t)=>f(n,"name",{value:t,configurable:!0});var m=Object.defineProperty,a=p((n,t)=>m(n,"name",{value:t,configurable:!0}),"a");Object.defineProperty(exports,"__esModule",{value:!0}),exports.initGenerator=initGenerator;const devkit_1=require("@nx/devkit"),DEFAULT_LENSMCP_CONFIG={schemaVersion:1,storage:"memory",transport:"stdio",retention:{sessions:5,events:5e3,screenshots:50,buildReports:20,visualFrames:200,heapSnapshots:3,tracesWithErrors:20,verifications:10},redaction:{headers:["authorization","cookie","set-cookie","x-api-key"],paths:["password","token","secret","apiKey","api_key"]},channels:{blockingStatusChanged:{enabled:!0,minSeverity:"error"},memoryLeakSuspected:{enabled:!0,minSeverity:"warning"},bundleRegression:{enabled:!0,minSeverity:"warning"},visualViolationBlocking:{enabled:!0,minSeverity:"error"},verificationCompleted:{enabled:!0,minSeverity:"info"}},thresholds:{dbInLoop:5,nPlusOne:3,renderStorm:5,slowRouteMs:500,slowRenderMs:16}},LENSMCP_GITIGNORE_MARKER="# LensMCP runtime artifacts (per-session storage)",LENSMCP_GITIGNORE_ENTRY=".lensmcp/";async function initGenerator(n,t={}){const s={skipFormat:t.skipFormat??!1,registerHostConfig:t.registerHostConfig??"auto"},e=[];if(n.exists("nx.json"))(0,devkit_1.updateJson)(n,"nx.json",r=>{r.plugins=Array.isArray(r.plugins)?r.plugins:[],r.plugins.some(o=>typeof o=="string"?o==="@lensmcp/nx-plugin":o&&typeof o=="object"&&"plugin"in o?o.plugin==="@lensmcp/nx-plugin":!1)||(r.plugins.push("@lensmcp/nx-plugin"),e.push("nx.json: registered @lensmcp/nx-plugin"));const d=r.lensmcp??{};return r.lensmcp=mergeDeep(DEFAULT_LENSMCP_CONFIG,d),(!("lensmcp"in r)||Object.keys(d).length===0)&&e.push("nx.json: added workspace-wide `lensmcp` config block"),r});else throw new Error("No nx.json found at the workspace root. Are you in a Nx workspace?");const i=".gitignore",c=n.exists(i)?n.read(i,"utf-8")??"":"";if(!c.split(`
2
- `).some(r=>r.trim()===LENSMCP_GITIGNORE_ENTRY)){const r=c.endsWith(`
1
+ "use strict";var f=Object.defineProperty;var p=(s,r)=>f(s,"name",{value:r,configurable:!0});var d=Object.defineProperty,c=p((s,r)=>d(s,"name",{value:r,configurable:!0}),"c");Object.defineProperty(exports,"__esModule",{value:!0}),exports.initGenerator=initGenerator,exports.mcpServerEntry=mcpServerEntry,exports.pluginVersion=pluginVersion;const node_fs_1=require("node:fs"),node_path_1=require("node:path"),devkit_1=require("@nx/devkit"),DEFAULT_LENSMCP_CONFIG={schemaVersion:1,storage:"memory",transport:"stdio",retention:{sessions:5,events:5e3,screenshots:50,buildReports:20,visualFrames:200,heapSnapshots:3,tracesWithErrors:20,verifications:10},redaction:{headers:["authorization","cookie","set-cookie","x-api-key"],paths:["password","token","secret","apiKey","api_key"]},channels:{blockingStatusChanged:{enabled:!0,minSeverity:"error"},memoryLeakSuspected:{enabled:!0,minSeverity:"warning"},bundleRegression:{enabled:!0,minSeverity:"warning"},visualViolationBlocking:{enabled:!0,minSeverity:"error"},verificationCompleted:{enabled:!0,minSeverity:"info"}},thresholds:{dbInLoop:5,nPlusOne:3,renderStorm:5,slowRouteMs:500,slowRenderMs:16}},LENSMCP_GITIGNORE_MARKER="# LensMCP runtime artifacts (per-session storage)",LENSMCP_GITIGNORE_ENTRY=".lensmcp/";async function initGenerator(s,r={}){const n={skipFormat:r.skipFormat??!1,registerHostConfig:r.registerHostConfig??"auto"},e=[];if(s.exists("nx.json"))(0,devkit_1.updateJson)(s,"nx.json",i=>{i.plugins=Array.isArray(i.plugins)?i.plugins:[],i.plugins.some(a=>typeof a=="string"?a==="@lensmcp/nx-plugin":a&&typeof a=="object"&&"plugin"in a?a.plugin==="@lensmcp/nx-plugin":!1)||(i.plugins.push("@lensmcp/nx-plugin"),e.push("nx.json: registered @lensmcp/nx-plugin"));const g=i.lensmcp??{};return i.lensmcp=mergeDeep(DEFAULT_LENSMCP_CONFIG,g),(!("lensmcp"in i)||Object.keys(g).length===0)&&e.push("nx.json: added workspace-wide `lensmcp` config block"),i});else throw new Error("No nx.json found at the workspace root. Are you in a Nx workspace?");const t=".gitignore",o=s.exists(t)?s.read(t,"utf-8")??"":"";if(!o.split(`
2
+ `).some(i=>i.trim()===LENSMCP_GITIGNORE_ENTRY)){const i=o.endsWith(`
3
3
  `)?"":`
4
- `;n.write(i,`${c}${r}
4
+ `;s.write(t,`${o}${i}
5
5
  ${LENSMCP_GITIGNORE_MARKER}
6
6
  ${LENSMCP_GITIGNORE_ENTRY}
7
- `),e.push(`${i}: added \`${LENSMCP_GITIGNORE_ENTRY}\``)}const l=(0,devkit_1.joinPathFragments)(".lensmcp",".keep");n.exists(l)||(n.write(l,""),e.push(`${l}: created`));const u=(0,devkit_1.joinPathFragments)(".lensmcp","install-trail.json"),g=(n.exists(u)?JSON.parse(n.read(u,"utf-8")??"{}"):void 0)??{schemaVersion:1,installedAt:new Date().toISOString(),steps:[]};g.steps.push(...e),n.write(u,JSON.stringify(g,null,2)+`
8
- `),s.registerHostConfig!=="never"&&registerWorkspaceMcpConfig(n,e),s.skipFormat||await(0,devkit_1.formatFiles)(n)}p(initGenerator,"initGenerator"),a(initGenerator,"initGenerator");const LENSMCP_MCP_SERVER_ENTRY={command:"npx",args:["-y","lensmcp","mcp"]};function registerWorkspaceMcpConfig(n,t){const s=".mcp.json";let e={};if(n.exists(s))try{e=JSON.parse(n.read(s,"utf-8")??"{}")}catch{e={}}(!e||typeof e!="object")&&(e={}),(!e.mcpServers||typeof e.mcpServers!="object")&&(e.mcpServers={}),!e.mcpServers.lensmcp&&(e.mcpServers.lensmcp={...LENSMCP_MCP_SERVER_ENTRY},n.write(s,JSON.stringify(e,null,2)+`
9
- `),t.push(".mcp.json: registered lensmcp MCP server (stdio)"))}p(registerWorkspaceMcpConfig,"registerWorkspaceMcpConfig"),a(registerWorkspaceMcpConfig,"registerWorkspaceMcpConfig"),exports.default=initGenerator;function mergeDeep(n,t){const s={...n};for(const[e,i]of Object.entries(t))i!==null&&typeof i=="object"&&!Array.isArray(i)&&s[e]!==null&&typeof s[e]=="object"&&!Array.isArray(s[e])?s[e]=mergeDeep(s[e],i):s[e]=i;return s}p(mergeDeep,"mergeDeep"),a(mergeDeep,"mergeDeep");
7
+ `),e.push(`${t}: added \`${LENSMCP_GITIGNORE_ENTRY}\``)}const l=(0,devkit_1.joinPathFragments)(".lensmcp",".keep");s.exists(l)||(s.write(l,""),e.push(`${l}: created`));const m=(0,devkit_1.joinPathFragments)(".lensmcp","install-trail.json"),u=(s.exists(m)?JSON.parse(s.read(m,"utf-8")??"{}"):void 0)??{schemaVersion:1,installedAt:new Date().toISOString(),steps:[]};u.steps.push(...e),s.write(m,JSON.stringify(u,null,2)+`
8
+ `),n.registerHostConfig!=="never"&&registerWorkspaceMcpConfig(s,e),n.skipFormat||await(0,devkit_1.formatFiles)(s)}p(initGenerator,"initGenerator"),c(initGenerator,"initGenerator");function mcpServerEntry(s,r={}){if((r.exists??node_fs_1.existsSync)((0,node_path_1.join)(s,"node_modules",".bin","lensmcp")))return{command:"npx",args:["--no","lensmcp","mcp"]};const n="version"in r?r.version:pluginVersion();return{command:"npx",args:["--yes",n?`lensmcp@${n}`:"lensmcp","mcp"]}}p(mcpServerEntry,"mcpServerEntry"),c(mcpServerEntry,"mcpServerEntry");function pluginVersion(s=__dirname){let r=s;for(let n=0;n<6;n++){const e=(0,node_path_1.join)(r,"package.json");try{if((0,node_fs_1.existsSync)(e)){const o=JSON.parse((0,node_fs_1.readFileSync)(e,"utf-8"));if(o.name==="@lensmcp/nx-plugin"&&typeof o.version=="string")return o.version}}catch{}const t=(0,node_path_1.dirname)(r);if(t===r)break;r=t}}p(pluginVersion,"pluginVersion"),c(pluginVersion,"pluginVersion");function registerWorkspaceMcpConfig(s,r){const n=".mcp.json";let e={};if(s.exists(n))try{e=JSON.parse(s.read(n,"utf-8")??"{}")}catch{e={}}if((!e||typeof e!="object")&&(e={}),(!e.mcpServers||typeof e.mcpServers!="object")&&(e.mcpServers={}),e.mcpServers.lensmcp)return;const t=mcpServerEntry(s.root);e.mcpServers.lensmcp=t,s.write(n,JSON.stringify(e,null,2)+`
9
+ `),r.push(`.mcp.json: registered lensmcp MCP server (stdio, ${t.args.join(" ")})`)}p(registerWorkspaceMcpConfig,"registerWorkspaceMcpConfig"),c(registerWorkspaceMcpConfig,"registerWorkspaceMcpConfig"),exports.default=initGenerator;function mergeDeep(s,r){const n={...s};for(const[e,t]of Object.entries(r))t!==null&&typeof t=="object"&&!Array.isArray(t)&&n[e]!==null&&typeof n[e]=="object"&&!Array.isArray(n[e])?n[e]=mergeDeep(n[e],t):n[e]=t;return n}p(mergeDeep,"mergeDeep"),c(mergeDeep,"mergeDeep");
@@ -1,8 +1,8 @@
1
- "use strict";var h=Object.defineProperty;var c=(e,r)=>h(e,"name",{value:r,configurable:!0});var A=Object.defineProperty,i=c((e,r)=>A(e,"name",{value:r,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.setupNestGenerator=setupNestGenerator,exports.findAppModule=findAppModule,exports.patchMainBootstrap=patchMainBootstrap,exports.patchAppModule=patchAppModule;const devkit_1=require("@nx/devkit"),BOOTSTRAP_IMPORT="import { createLensmcpNestApp } from '@lensmcp/nest-instrumentation';",IMPORT_LINE="import { LensmcpModule } from '@lensmcp/nest-instrumentation';",MODULE_CALL="LensmcpModule.forRoot({ projectName: '__PROJECT__' })";async function setupNestGenerator(e,r){const n={project:r.project,skipFormat:r.skipFormat??!1},t=(0,devkit_1.readProjectConfiguration)(e,n.project),s=findMain(e,t.root);if(!s)throw new Error(`setup-nest: no main.ts found under ${t.root}/src.`);const o=e.read(s,"utf-8")??"",p=patchMainBootstrap(o,n.project);if(p===null)throw new Error(`setup-nest: could not safely patch ${s}.
2
- Expected a \`NestFactory.create(AppModule)\` bootstrap call. Edit manually: replace it with \`createLensmcpNestApp(AppModule, { projectName: '${n.project}' })\` and import it from '@lensmcp/nest-instrumentation'.
3
- (Or use the module form: add \`${IMPORT_LINE}\` and push ${MODULE_CALL.replace("__PROJECT__",n.project)} into the @Module imports array.)`);p!==o&&e.write(s,p);const a={...t.targets??{}};a["agent-dev"]||(a["agent-dev"]={executor:"@lensmcp/nx-plugin:agent-dev",options:{kind:"nestjs"}},t.targets=a,(0,devkit_1.updateProjectConfiguration)(e,n.project,t)),n.skipFormat||await(0,devkit_1.formatFiles)(e)}c(setupNestGenerator,"setupNestGenerator"),i(setupNestGenerator,"setupNestGenerator"),exports.default=setupNestGenerator;function findMain(e,r){for(const n of["src/main.ts","main.ts","src/index.ts"]){const t=(0,devkit_1.joinPathFragments)(r,n);if(e.exists(t))return t}}c(findMain,"findMain"),i(findMain,"findMain");function findAppModule(e,r){for(const n of["src/app.module.ts","app.module.ts"]){const t=(0,devkit_1.joinPathFragments)(r,n);if(e.exists(t))return t}}c(findAppModule,"findAppModule"),i(findAppModule,"findAppModule");const CREATE_CALL_RE=/NestFactory\s*\.\s*create\s*(?:<[\s\S]*?>)?\s*\(/;function patchMainBootstrap(e,r){if(/createLensmcpNestApp\s*\(/.test(e))return e;const n=CREATE_CALL_RE.exec(e);if(!n)return null;const t=n.index+n[0].length-1,s=matchingParen(e,t);if(s===-1)return null;const o=e.slice(t+1,s),{moduleArg:p,restArg:a}=splitTopLevelArgs(o);if(!p.trim())return null;const u=r.replace(/\\/g,"\\\\").replace(/'/g,"\\'"),m=a.trim(),d=m?`{ projectName: '${u}', nestOptions: ${m} }`:`{ projectName: '${u}' }`,f=`createLensmcpNestApp(${p.trim()}, ${d})`;let l=e.slice(0,n.index)+f+e.slice(s+1);return l=addBootstrapImport(l),l=dropUnusedNestFactoryImport(l),l}c(patchMainBootstrap,"patchMainBootstrap"),i(patchMainBootstrap,"patchMainBootstrap");function addBootstrapImport(e){if(/createLensmcpNestApp[\s\S]*?from\s*['"]@lensmcp\/nest-instrumentation['"]/.test(e))return e;const r=[...e.matchAll(/^\s*import .+;?\s*$/gm)],n=r.length?r[r.length-1]:null;if(n&&n.index!==void 0){const t=n.index+n[0].length;return e.slice(0,t)+`
4
- ${BOOTSTRAP_IMPORT}`+e.slice(t)}return`${BOOTSTRAP_IMPORT}
5
- ${e}`}c(addBootstrapImport,"addBootstrapImport"),i(addBootstrapImport,"addBootstrapImport");function dropUnusedNestFactoryImport(e){if(/\bNestFactory\b/.test(stripNestFactoryImportSpan(e).rest))return e;const{match:r}=stripNestFactoryImportSpan(e);if(!r)return e;const n=r.names.filter(s=>s!=="NestFactory");if(n.length===0)return e.slice(0,r.start)+e.slice(r.end).replace(/^\n/,"");const t=`import { ${n.join(", ")} } from '@nestjs/core';`;return e.slice(0,r.start)+t+e.slice(r.end)}c(dropUnusedNestFactoryImport,"dropUnusedNestFactoryImport"),i(dropUnusedNestFactoryImport,"dropUnusedNestFactoryImport");function stripNestFactoryImportSpan(e){const r=/import\s*\{([^}]*)\}\s*from\s*['"]@nestjs\/core['"];?/.exec(e);if(!r)return{match:null,rest:e};const n=r[1].split(",").map(p=>p.trim()).filter(Boolean),t=r.index,s=r.index+r[0].length,o=e.slice(0,t)+e.slice(s);return{match:{start:t,end:s,names:n},rest:o}}c(stripNestFactoryImportSpan,"stripNestFactoryImportSpan"),i(stripNestFactoryImportSpan,"stripNestFactoryImportSpan");function matchingParen(e,r){let n=0;for(let t=r;t<e.length;t++){const s=skipNonCode(e,t);if(s>t){t=s-1;continue}const o=e[t];if(o==="(")n++;else if(o===")"&&(n--,n===0))return t}return-1}c(matchingParen,"matchingParen"),i(matchingParen,"matchingParen");function splitTopLevelArgs(e){let r=0;for(let n=0;n<e.length;n++){const t=skipNonCode(e,n);if(t>n){n=t-1;continue}const s=e[n];if(s==="("||s==="["||s==="{")r++;else if(s===")"||s==="]"||s==="}")r--;else if(s===","&&r===0)return{moduleArg:e.slice(0,n),restArg:e.slice(n+1)}}return{moduleArg:e,restArg:""}}c(splitTopLevelArgs,"splitTopLevelArgs"),i(splitTopLevelArgs,"splitTopLevelArgs");function skipNonCode(e,r){const n=e[r];if(n==='"'||n==="'"||n==="`"){for(let t=r+1;t<e.length;t++){if(e[t]==="\\"){t++;continue}if(e[t]===n)return t+1}return e.length}if(n==="/"&&e[r+1]==="/"){const t=e.indexOf(`
6
- `,r);return t===-1?e.length:t}if(n==="/"&&e[r+1]==="*"){const t=e.indexOf("*/",r+2);return t===-1?e.length:t+2}return r}c(skipNonCode,"skipNonCode"),i(skipNonCode,"skipNonCode");function patchAppModule(e,r){const n=e.includes("from '@lensmcp/nest-instrumentation'")||e.includes('from "@lensmcp/nest-instrumentation"'),t=/LensmcpModule\s*\.\s*forRoot\s*\(/.test(e);if(n&&t)return e;const s=e.indexOf("imports:");if(s===-1||e.indexOf("[",s)===-1)return null;let o=e;if(!n){const f=[...e.matchAll(/^\s*import .+;?\s*$/gm)],l=f.length>0?f[f.length-1]:null;if(l&&l.index!==void 0){const g=l.index+l[0].length;o=e.slice(0,g)+`
1
+ "use strict";var h=Object.defineProperty;var c=(e,r)=>h(e,"name",{value:r,configurable:!0});var A=Object.defineProperty,i=c((e,r)=>A(e,"name",{value:r,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.setupNestGenerator=setupNestGenerator,exports.findAppModule=findAppModule,exports.patchMainBootstrap=patchMainBootstrap,exports.patchAppModule=patchAppModule;const devkit_1=require("@nx/devkit"),BOOTSTRAP_IMPORT="import { createLensmcpNestApp } from '@lensmcp/nest-instrumentation';",IMPORT_LINE="import { LensmcpModule } from '@lensmcp/nest-instrumentation';",MODULE_CALL="LensmcpModule.forRoot({ projectName: '__PROJECT__' })";async function setupNestGenerator(e,r){const t={project:r.project,skipFormat:r.skipFormat??!1},n=(0,devkit_1.readProjectConfiguration)(e,t.project),s=findMain(e,n.root);if(!s)throw new Error(`setup-nest: no main.ts found under ${n.root}/src.`);const o=e.read(s,"utf-8")??"",p=patchMainBootstrap(o,t.project);if(p===null)throw new Error(`setup-nest: could not safely patch ${s}.
2
+ Expected a \`NestFactory.create(AppModule)\` bootstrap call. Edit manually: replace it with \`createLensmcpNestApp(AppModule, { projectName: '${t.project}' })\` and import it from '@lensmcp/nest-instrumentation'.
3
+ (Or use the module form: add \`${IMPORT_LINE}\` and push ${MODULE_CALL.replace("__PROJECT__",t.project)} into the @Module imports array.)`);p!==o&&e.write(s,p);const a={...n.targets??{}};a["agent-dev"]||(a["agent-dev"]={executor:"@lensmcp/nx-plugin:agent-dev",options:{kind:"nestjs"}},n.targets=a,(0,devkit_1.updateProjectConfiguration)(e,t.project,n)),t.skipFormat||await(0,devkit_1.formatFiles)(e)}c(setupNestGenerator,"setupNestGenerator"),i(setupNestGenerator,"setupNestGenerator"),exports.default=setupNestGenerator;function findMain(e,r){for(const t of["src/main.ts","main.ts","src/index.ts"]){const n=(0,devkit_1.joinPathFragments)(r,t);if(e.exists(n))return n}}c(findMain,"findMain"),i(findMain,"findMain");function findAppModule(e,r){for(const t of["src/app.module.ts","app.module.ts"]){const n=(0,devkit_1.joinPathFragments)(r,t);if(e.exists(n))return n}}c(findAppModule,"findAppModule"),i(findAppModule,"findAppModule");const CREATE_CALL_RE=/NestFactory\s*\.\s*create\s*(<[\s\S]*?>)?\s*\(/;function patchMainBootstrap(e,r){if(/createLensmcpNestApp\s*\(/.test(e))return e;const t=CREATE_CALL_RE.exec(e);if(!t)return null;const n=t.index+t[0].length-1,s=matchingParen(e,n);if(s===-1)return null;const o=e.slice(n+1,s),{moduleArg:p,restArg:a}=splitTopLevelArgs(o);if(!p.trim())return null;const u=r.replace(/\\/g,"\\\\").replace(/'/g,"\\'"),m=a.trim(),d=m?`{ projectName: '${u}', nestOptions: ${m} }`:`{ projectName: '${u}' }`,f=`createLensmcpNestApp${(t[1]??"").trim()}(${p.trim()}, ${d})`;let l=e.slice(0,t.index)+f+e.slice(s+1);return l=addBootstrapImport(l),l=dropUnusedNestFactoryImport(l),l}c(patchMainBootstrap,"patchMainBootstrap"),i(patchMainBootstrap,"patchMainBootstrap");function addBootstrapImport(e){if(/createLensmcpNestApp[\s\S]*?from\s*['"]@lensmcp\/nest-instrumentation['"]/.test(e))return e;const r=[...e.matchAll(/^\s*import .+;?\s*$/gm)],t=r.length?r[r.length-1]:null;if(t&&t.index!==void 0){const n=t.index+t[0].length;return e.slice(0,n)+`
4
+ ${BOOTSTRAP_IMPORT}`+e.slice(n)}return`${BOOTSTRAP_IMPORT}
5
+ ${e}`}c(addBootstrapImport,"addBootstrapImport"),i(addBootstrapImport,"addBootstrapImport");function dropUnusedNestFactoryImport(e){if(/\bNestFactory\b/.test(stripNestFactoryImportSpan(e).rest))return e;const{match:r}=stripNestFactoryImportSpan(e);if(!r)return e;const t=r.names.filter(s=>s!=="NestFactory");if(t.length===0)return e.slice(0,r.start)+e.slice(r.end).replace(/^\n/,"");const n=`import { ${t.join(", ")} } from '@nestjs/core';`;return e.slice(0,r.start)+n+e.slice(r.end)}c(dropUnusedNestFactoryImport,"dropUnusedNestFactoryImport"),i(dropUnusedNestFactoryImport,"dropUnusedNestFactoryImport");function stripNestFactoryImportSpan(e){const r=/import\s*\{([^}]*)\}\s*from\s*['"]@nestjs\/core['"];?/.exec(e);if(!r)return{match:null,rest:e};const t=r[1].split(",").map(p=>p.trim()).filter(Boolean),n=r.index,s=r.index+r[0].length,o=e.slice(0,n)+e.slice(s);return{match:{start:n,end:s,names:t},rest:o}}c(stripNestFactoryImportSpan,"stripNestFactoryImportSpan"),i(stripNestFactoryImportSpan,"stripNestFactoryImportSpan");function matchingParen(e,r){let t=0;for(let n=r;n<e.length;n++){const s=skipNonCode(e,n);if(s>n){n=s-1;continue}const o=e[n];if(o==="(")t++;else if(o===")"&&(t--,t===0))return n}return-1}c(matchingParen,"matchingParen"),i(matchingParen,"matchingParen");function splitTopLevelArgs(e){let r=0;for(let t=0;t<e.length;t++){const n=skipNonCode(e,t);if(n>t){t=n-1;continue}const s=e[t];if(s==="("||s==="["||s==="{")r++;else if(s===")"||s==="]"||s==="}")r--;else if(s===","&&r===0)return{moduleArg:e.slice(0,t),restArg:e.slice(t+1)}}return{moduleArg:e,restArg:""}}c(splitTopLevelArgs,"splitTopLevelArgs"),i(splitTopLevelArgs,"splitTopLevelArgs");function skipNonCode(e,r){const t=e[r];if(t==='"'||t==="'"||t==="`"){for(let n=r+1;n<e.length;n++){if(e[n]==="\\"){n++;continue}if(e[n]===t)return n+1}return e.length}if(t==="/"&&e[r+1]==="/"){const n=e.indexOf(`
6
+ `,r);return n===-1?e.length:n}if(t==="/"&&e[r+1]==="*"){const n=e.indexOf("*/",r+2);return n===-1?e.length:n+2}return r}c(skipNonCode,"skipNonCode"),i(skipNonCode,"skipNonCode");function patchAppModule(e,r){const t=e.includes("from '@lensmcp/nest-instrumentation'")||e.includes('from "@lensmcp/nest-instrumentation"'),n=/LensmcpModule\s*\.\s*forRoot\s*\(/.test(e);if(t&&n)return e;const s=e.indexOf("imports:");if(s===-1||e.indexOf("[",s)===-1)return null;let o=e;if(!t){const f=[...e.matchAll(/^\s*import .+;?\s*$/gm)],l=f.length>0?f[f.length-1]:null;if(l&&l.index!==void 0){const g=l.index+l[0].length;o=e.slice(0,g)+`
7
7
  ${IMPORT_LINE}`+e.slice(g)}else o=`${IMPORT_LINE}
8
- `+e}if(t)return o;const p=o.indexOf("[",o.indexOf("imports:")),a=o.slice(0,p+1),u=o.slice(p+1),m=u.replace(/^\s*/,"").startsWith("]")?"":", ",d=MODULE_CALL.replace("__PROJECT__",r);return`${a}${d}${m}${u}`}c(patchAppModule,"patchAppModule"),i(patchAppModule,"patchAppModule");
8
+ `+e}if(n)return o;const p=o.indexOf("[",o.indexOf("imports:")),a=o.slice(0,p+1),u=o.slice(p+1),m=u.replace(/^\s*/,"").startsWith("]")?"":", ",d=MODULE_CALL.replace("__PROJECT__",r);return`${a}${d}${m}${u}`}c(patchAppModule,"patchAppModule"),i(patchAppModule,"patchAppModule");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lensmcp/nx-plugin",
3
- "version": "1.21.5",
3
+ "version": "1.22.1",
4
4
  "main": "./index.js",
5
5
  "module": "./index.js",
6
6
  "types": "./index.d.ts",