@lensmcp/nx-plugin 1.18.4 → 1.18.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/executors/agent-build/agent-build.js +2 -86
- package/executors/agent-dev/agent-dev.js +4 -425
- package/executors/agent-verify/agent-verify.js +3 -166
- package/generators/init/init.js +9 -167
- package/generators/setup-nest/setup-nest.js +8 -281
- package/generators/setup-vite/setup-vite.js +5 -125
- package/index.js +1 -21
- package/lens-frontend.js +1 -205
- package/package.json +1 -1
|
@@ -1,125 +1,5 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
exports.setupViteGenerator =
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const IMPORT_LINE = `import { lensmcpVitePlugin } from '@lensmcp/vite-plugin';`;
|
|
7
|
-
/**
|
|
8
|
-
* Wires LensMCP into a host Vite project. Idempotent on every step.
|
|
9
|
-
*
|
|
10
|
-
* 1. Locate the project's vite.config.{ts,mts,js,mjs,cts,cjs}.
|
|
11
|
-
* 2. Add `import { lensmcpVitePlugin } from '@lensmcp/vite-plugin'`
|
|
12
|
-
* near the top (after the last existing import).
|
|
13
|
-
* 3. Insert `lensmcpVitePlugin({ enabled: mode !== 'production' })`
|
|
14
|
-
* into the `plugins` array if not already present. We do *not*
|
|
15
|
-
* AST-edit — we use string heuristics on the standard
|
|
16
|
-
* `defineConfig({ plugins: [...] })` shape. If the file is too
|
|
17
|
-
* custom for the heuristics, we print a diff hint and bail.
|
|
18
|
-
* 4. Add Nx targets: agent-dev, agent-build, agent-verify.
|
|
19
|
-
*/
|
|
20
|
-
async function setupViteGenerator(tree, rawOptions) {
|
|
21
|
-
const options = {
|
|
22
|
-
project: rawOptions.project,
|
|
23
|
-
skipFormat: rawOptions.skipFormat ?? false,
|
|
24
|
-
};
|
|
25
|
-
const project = (0, devkit_1.readProjectConfiguration)(tree, options.project);
|
|
26
|
-
const viteConfigPath = findViteConfig(tree, project.root);
|
|
27
|
-
if (!viteConfigPath) {
|
|
28
|
-
throw new Error(`setup-vite: no vite.config.{ts,mts,js,mjs,cts,cjs} found under ${project.root}.`);
|
|
29
|
-
}
|
|
30
|
-
const original = tree.read(viteConfigPath, 'utf-8') ?? '';
|
|
31
|
-
const patched = patchViteConfig(original);
|
|
32
|
-
if (patched === null) {
|
|
33
|
-
throw new Error(`setup-vite: could not safely patch ${viteConfigPath}.\n` +
|
|
34
|
-
`Expected a defineConfig({ plugins: [...] }) or defineConfig(({ mode }) => ({ plugins: [...] })) shape.\n` +
|
|
35
|
-
`Edit manually: add \`${IMPORT_LINE}\` and push \`lensmcpVitePlugin({ enabled: mode !== 'production' })\` into the plugins array.`);
|
|
36
|
-
}
|
|
37
|
-
if (patched !== original) {
|
|
38
|
-
tree.write(viteConfigPath, patched);
|
|
39
|
-
}
|
|
40
|
-
// Idempotent Nx target additions.
|
|
41
|
-
const targets = { ...(project.targets ?? {}) };
|
|
42
|
-
if (!targets['agent-dev']) {
|
|
43
|
-
targets['agent-dev'] = {
|
|
44
|
-
executor: '@lensmcp/nx-plugin:agent-dev',
|
|
45
|
-
options: {
|
|
46
|
-
kind: 'vite-react',
|
|
47
|
-
chrome: true,
|
|
48
|
-
headless: true,
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
project.targets = targets;
|
|
52
|
-
(0, devkit_1.updateProjectConfiguration)(tree, options.project, project);
|
|
53
|
-
}
|
|
54
|
-
if (!options.skipFormat) {
|
|
55
|
-
await (0, devkit_1.formatFiles)(tree);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
exports.default = setupViteGenerator;
|
|
59
|
-
// ---------- helpers ----------
|
|
60
|
-
function findViteConfig(tree, root) {
|
|
61
|
-
// Nx generates `vite.config.mts` for ESM workspaces — cover every Vite-supported extension.
|
|
62
|
-
for (const name of [
|
|
63
|
-
'vite.config.ts',
|
|
64
|
-
'vite.config.mts',
|
|
65
|
-
'vite.config.js',
|
|
66
|
-
'vite.config.mjs',
|
|
67
|
-
'vite.config.cts',
|
|
68
|
-
'vite.config.cjs',
|
|
69
|
-
]) {
|
|
70
|
-
const p = (0, devkit_1.joinPathFragments)(root, name);
|
|
71
|
-
if (tree.exists(p))
|
|
72
|
-
return p;
|
|
73
|
-
}
|
|
74
|
-
return undefined;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* String-heuristic patch:
|
|
78
|
-
*
|
|
79
|
-
* 1. If the file already imports `@lensmcp/vite-plugin` and mentions
|
|
80
|
-
* `lensmcpVitePlugin(` in the plugins array, return unchanged.
|
|
81
|
-
* 2. Otherwise insert the import near the top (after the last
|
|
82
|
-
* `import …` line) and add the plugin call to the plugins array
|
|
83
|
-
* declared by `plugins: [` (first occurrence).
|
|
84
|
-
*
|
|
85
|
-
* If neither anchor is found, return `null` so the generator can ask
|
|
86
|
-
* the user to patch manually.
|
|
87
|
-
*/
|
|
88
|
-
function patchViteConfig(src) {
|
|
89
|
-
const hasImport = src.includes("from '@lensmcp/vite-plugin'") || src.includes('from "@lensmcp/vite-plugin"');
|
|
90
|
-
const hasPluginCall = /lensmcpVitePlugin\s*\(/.test(src);
|
|
91
|
-
if (hasImport && hasPluginCall)
|
|
92
|
-
return src;
|
|
93
|
-
const pluginsAnchor = src.indexOf('plugins:');
|
|
94
|
-
if (pluginsAnchor === -1)
|
|
95
|
-
return null;
|
|
96
|
-
const bracketStart = src.indexOf('[', pluginsAnchor);
|
|
97
|
-
if (bracketStart === -1)
|
|
98
|
-
return null;
|
|
99
|
-
let withImport = src;
|
|
100
|
-
if (!hasImport) {
|
|
101
|
-
const importLines = [...src.matchAll(/^\s*import .+;?\s*$/gm)];
|
|
102
|
-
const lastImport = importLines.length > 0 ? importLines[importLines.length - 1] : null;
|
|
103
|
-
if (lastImport && lastImport.index !== undefined) {
|
|
104
|
-
const insertAt = lastImport.index + lastImport[0].length;
|
|
105
|
-
withImport = src.slice(0, insertAt) + `\n${IMPORT_LINE}` + src.slice(insertAt);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
withImport = `${IMPORT_LINE}\n` + src;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
if (hasPluginCall)
|
|
112
|
-
return withImport;
|
|
113
|
-
const adjBracket = withImport.indexOf('[', withImport.indexOf('plugins:'));
|
|
114
|
-
const before = withImport.slice(0, adjBracket + 1);
|
|
115
|
-
const after = withImport.slice(adjBracket + 1);
|
|
116
|
-
// Insert at the start of the array with a trailing comma if the array isn't empty.
|
|
117
|
-
const trimmedAfter = after.replace(/^\s*/, '');
|
|
118
|
-
const startsClosed = trimmedAfter.startsWith(']');
|
|
119
|
-
const separator = startsClosed ? '' : ', ';
|
|
120
|
-
// `mode` is only in scope for the function-form config (`defineConfig(({ mode }) => …)`).
|
|
121
|
-
// For the object form, gate on NODE_ENV instead of emitting code that doesn't compile.
|
|
122
|
-
const hasModeInScope = /defineConfig\s*\(\s*(?:async\s*)?\(\s*\{[^}]*\bmode\b[^}]*\}/.test(withImport);
|
|
123
|
-
const enabledExpr = hasModeInScope ? "mode !== 'production'" : "process.env.NODE_ENV !== 'production'";
|
|
124
|
-
return `${before}lensmcpVitePlugin({ enabled: ${enabledExpr} })${separator}${after}`;
|
|
125
|
-
}
|
|
1
|
+
"use strict";var v=Object.defineProperty;var p=(e,t)=>v(e,"name",{value:t,configurable:!0});var m=Object.defineProperty,l=p((e,t)=>m(e,"name",{value:t,configurable:!0}),"l");Object.defineProperty(exports,"__esModule",{value:!0}),exports.setupViteGenerator=setupViteGenerator,exports.patchViteConfig=patchViteConfig;const devkit_1=require("@nx/devkit"),IMPORT_LINE="import { lensmcpVitePlugin } from '@lensmcp/vite-plugin';";async function setupViteGenerator(e,t){const o={project:t.project,skipFormat:t.skipFormat??!1},i=(0,devkit_1.readProjectConfiguration)(e,o.project),n=findViteConfig(e,i.root);if(!n)throw new Error(`setup-vite: no vite.config.{ts,mts,js,mjs,cts,cjs} found under ${i.root}.`);const r=e.read(n,"utf-8")??"",c=patchViteConfig(r);if(c===null)throw new Error(`setup-vite: could not safely patch ${n}.
|
|
2
|
+
Expected a defineConfig({ plugins: [...] }) or defineConfig(({ mode }) => ({ plugins: [...] })) shape.
|
|
3
|
+
Edit manually: add \`${IMPORT_LINE}\` and push \`lensmcpVitePlugin({ enabled: mode !== 'production' })\` into the plugins array.`);c!==r&&e.write(n,c);const s={...i.targets??{}};s["agent-dev"]||(s["agent-dev"]={executor:"@lensmcp/nx-plugin:agent-dev",options:{kind:"vite-react",chrome:!0,headless:!0}},i.targets=s,(0,devkit_1.updateProjectConfiguration)(e,o.project,i)),o.skipFormat||await(0,devkit_1.formatFiles)(e)}p(setupViteGenerator,"setupViteGenerator"),l(setupViteGenerator,"setupViteGenerator"),exports.default=setupViteGenerator;function findViteConfig(e,t){for(const o of["vite.config.ts","vite.config.mts","vite.config.js","vite.config.mjs","vite.config.cts","vite.config.cjs"]){const i=(0,devkit_1.joinPathFragments)(t,o);if(e.exists(i))return i}}p(findViteConfig,"findViteConfig"),l(findViteConfig,"findViteConfig");function patchViteConfig(e){const t=e.includes("from '@lensmcp/vite-plugin'")||e.includes('from "@lensmcp/vite-plugin"'),o=/lensmcpVitePlugin\s*\(/.test(e);if(t&&o)return e;const i=e.indexOf("plugins:");if(i===-1||e.indexOf("[",i)===-1)return null;let n=e;if(!t){const a=[...e.matchAll(/^\s*import .+;?\s*$/gm)],u=a.length>0?a[a.length-1]:null;if(u&&u.index!==void 0){const f=u.index+u[0].length;n=e.slice(0,f)+`
|
|
4
|
+
${IMPORT_LINE}`+e.slice(f)}else n=`${IMPORT_LINE}
|
|
5
|
+
`+e}if(o)return n;const r=n.indexOf("[",n.indexOf("plugins:")),c=n.slice(0,r+1),s=n.slice(r+1),d=s.replace(/^\s*/,"").startsWith("]")?"":", ",g=/defineConfig\s*\(\s*(?:async\s*)?\(\s*\{[^}]*\bmode\b[^}]*\}/.test(n)?"mode !== 'production'":"process.env.NODE_ENV !== 'production'";return`${c}lensmcpVitePlugin({ enabled: ${g} })${d}${s}`}p(patchViteConfig,"patchViteConfig"),l(patchViteConfig,"patchViteConfig");
|
package/index.js
CHANGED
|
@@ -1,21 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = exports.agentVerifyExecutor = exports.agentBuildExecutor = exports.agentDevExecutor = exports.patchAppModule = exports.patchMainBootstrap = exports.setupNestGenerator = exports.patchViteConfig = exports.setupViteGenerator = exports.initGenerator = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
var init_js_1 = require("./generators/init/init.js");
|
|
6
|
-
Object.defineProperty(exports, "initGenerator", { enumerable: true, get: function () { return init_js_1.initGenerator; } });
|
|
7
|
-
var setup_vite_js_1 = require("./generators/setup-vite/setup-vite.js");
|
|
8
|
-
Object.defineProperty(exports, "setupViteGenerator", { enumerable: true, get: function () { return setup_vite_js_1.setupViteGenerator; } });
|
|
9
|
-
Object.defineProperty(exports, "patchViteConfig", { enumerable: true, get: function () { return setup_vite_js_1.patchViteConfig; } });
|
|
10
|
-
var setup_nest_js_1 = require("./generators/setup-nest/setup-nest.js");
|
|
11
|
-
Object.defineProperty(exports, "setupNestGenerator", { enumerable: true, get: function () { return setup_nest_js_1.setupNestGenerator; } });
|
|
12
|
-
Object.defineProperty(exports, "patchMainBootstrap", { enumerable: true, get: function () { return setup_nest_js_1.patchMainBootstrap; } });
|
|
13
|
-
Object.defineProperty(exports, "patchAppModule", { enumerable: true, get: function () { return setup_nest_js_1.patchAppModule; } });
|
|
14
|
-
var agent_dev_js_1 = require("./executors/agent-dev/agent-dev.js");
|
|
15
|
-
Object.defineProperty(exports, "agentDevExecutor", { enumerable: true, get: function () { return tslib_1.__importDefault(agent_dev_js_1).default; } });
|
|
16
|
-
var agent_build_js_1 = require("./executors/agent-build/agent-build.js");
|
|
17
|
-
Object.defineProperty(exports, "agentBuildExecutor", { enumerable: true, get: function () { return tslib_1.__importDefault(agent_build_js_1).default; } });
|
|
18
|
-
var agent_verify_js_1 = require("./executors/agent-verify/agent-verify.js");
|
|
19
|
-
Object.defineProperty(exports, "agentVerifyExecutor", { enumerable: true, get: function () { return tslib_1.__importDefault(agent_verify_js_1).default; } });
|
|
20
|
-
var init_js_2 = require("./generators/init/init.js");
|
|
21
|
-
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return init_js_2.initGenerator; } });
|
|
1
|
+
"use strict";var i=Object.defineProperty;var o=(t,r)=>i(t,"name",{value:r,configurable:!0});var n=Object.defineProperty,e=o((t,r)=>n(t,"name",{value:r,configurable:!0}),"e");Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=exports.agentVerifyExecutor=exports.agentBuildExecutor=exports.agentDevExecutor=exports.patchAppModule=exports.patchMainBootstrap=exports.setupNestGenerator=exports.patchViteConfig=exports.setupViteGenerator=exports.initGenerator=void 0;const tslib_1=require("tslib");var init_js_1=require("./generators/init/init.js");Object.defineProperty(exports,"initGenerator",{enumerable:!0,get:e(function(){return init_js_1.initGenerator},"get")});var setup_vite_js_1=require("./generators/setup-vite/setup-vite.js");Object.defineProperty(exports,"setupViteGenerator",{enumerable:!0,get:e(function(){return setup_vite_js_1.setupViteGenerator},"get")}),Object.defineProperty(exports,"patchViteConfig",{enumerable:!0,get:e(function(){return setup_vite_js_1.patchViteConfig},"get")});var setup_nest_js_1=require("./generators/setup-nest/setup-nest.js");Object.defineProperty(exports,"setupNestGenerator",{enumerable:!0,get:e(function(){return setup_nest_js_1.setupNestGenerator},"get")}),Object.defineProperty(exports,"patchMainBootstrap",{enumerable:!0,get:e(function(){return setup_nest_js_1.patchMainBootstrap},"get")}),Object.defineProperty(exports,"patchAppModule",{enumerable:!0,get:e(function(){return setup_nest_js_1.patchAppModule},"get")});var agent_dev_js_1=require("./executors/agent-dev/agent-dev.js");Object.defineProperty(exports,"agentDevExecutor",{enumerable:!0,get:e(function(){return tslib_1.__importDefault(agent_dev_js_1).default},"get")});var agent_build_js_1=require("./executors/agent-build/agent-build.js");Object.defineProperty(exports,"agentBuildExecutor",{enumerable:!0,get:e(function(){return tslib_1.__importDefault(agent_build_js_1).default},"get")});var agent_verify_js_1=require("./executors/agent-verify/agent-verify.js");Object.defineProperty(exports,"agentVerifyExecutor",{enumerable:!0,get:e(function(){return tslib_1.__importDefault(agent_verify_js_1).default},"get")});var init_js_2=require("./generators/init/init.js");Object.defineProperty(exports,"default",{enumerable:!0,get:e(function(){return init_js_2.initGenerator},"get")});
|
package/lens-frontend.js
CHANGED
|
@@ -1,205 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.spawnLensFrontend = spawnLensFrontend;
|
|
4
|
-
exports.locateBin = locateBin;
|
|
5
|
-
exports.resolveFirstExisting = resolveFirstExisting;
|
|
6
|
-
exports.globalNodeModules = globalNodeModules;
|
|
7
|
-
exports.findMcpBundle = findMcpBundle;
|
|
8
|
-
exports.findDashboardBundle = findDashboardBundle;
|
|
9
|
-
exports.findCaptureRunner = findCaptureRunner;
|
|
10
|
-
exports.findBridgeBundle = findBridgeBundle;
|
|
11
|
-
/**
|
|
12
|
-
* Shared "run ONE frontend project under the lens" machinery.
|
|
13
|
-
*
|
|
14
|
-
* The SAME logic is needed in two places:
|
|
15
|
-
*
|
|
16
|
-
* 1. `agent-dev` (standalone, per-app) — `nx run web:agent-dev`. There it ALSO
|
|
17
|
-
* spawns the cluster-wide singletons (the MCP server + the dashboard), since
|
|
18
|
-
* nothing else owns them.
|
|
19
|
-
* 2. `@lensmcp/cluster`'s gateway (`nx run gateway:serve`, `lens: true` apps).
|
|
20
|
-
* There the gateway owns the singletons (ONE dashboard + ONE MCP server
|
|
21
|
-
* cluster-wide), so a `lens:true` app must run ONLY its Vite + the lens
|
|
22
|
-
* instrumentation + browser capture — never its own dashboard/MCP (they'd
|
|
23
|
-
* collide on :4321 / :3000).
|
|
24
|
-
*
|
|
25
|
-
* This module factors out the per-app half — Vite (with `@lensmcp/vite-plugin`
|
|
26
|
-
* already wired in the host's vite.config) + the optional browser-capture
|
|
27
|
-
* runner — plus the bundle/bin resolvers both callers share. The singleton half
|
|
28
|
-
* (dashboard + MCP) stays with each caller, because WHO owns the singletons is
|
|
29
|
-
* exactly what differs between the two.
|
|
30
|
-
*
|
|
31
|
-
* No `@nx/devkit` import here on purpose: the cluster gateway calls this from a
|
|
32
|
-
* plain runtime context, so the helper takes only POJOs + a `spawnChild`
|
|
33
|
-
* callback the caller supplies (so children join the caller's lifecycle/teardown).
|
|
34
|
-
*/
|
|
35
|
-
const node_child_process_1 = require("node:child_process");
|
|
36
|
-
const node_fs_1 = require("node:fs");
|
|
37
|
-
const node_path_1 = require("node:path");
|
|
38
|
-
/**
|
|
39
|
-
* Spawn ONE frontend project under the lens: its Vite dev server (lens plugin
|
|
40
|
-
* already wired by `setup-vite`) + an optional browser-capture sidecar, both
|
|
41
|
-
* publishing to the shared event bus. Does NOT spawn the dashboard or MCP
|
|
42
|
-
* server — those are singletons the CALLER owns.
|
|
43
|
-
*
|
|
44
|
-
* Returns the resolved dev port/URL so the gateway can route its TCP upstream
|
|
45
|
-
* at it. Throws only if Vite can't be located; capture is best-effort.
|
|
46
|
-
*/
|
|
47
|
-
function spawnLensFrontend(options, spawnChild) {
|
|
48
|
-
const log = options.log ?? ((l) => console.log(l));
|
|
49
|
-
const { projectRoot, workspaceRoot, eventFile } = options;
|
|
50
|
-
const chrome = options.chrome !== false;
|
|
51
|
-
const headless = options.headless !== false;
|
|
52
|
-
const viteBin = options.viteBin ?? locateBin('vite', [projectRoot, workspaceRoot]);
|
|
53
|
-
if (!viteBin) {
|
|
54
|
-
throw new Error('[lens] Could not find the vite binary in node_modules/.bin.');
|
|
55
|
-
}
|
|
56
|
-
// Pin the dev port so the gateway upstream + the capture target are
|
|
57
|
-
// deterministic. When chrome capture is on we always fix it (strictPort).
|
|
58
|
-
const devPort = options.port ?? (chrome ? 5173 : undefined);
|
|
59
|
-
const viteArgs = [
|
|
60
|
-
'--config',
|
|
61
|
-
resolveFirstExisting(['vite.config.ts', 'vite.config.mts', 'vite.config.js', 'vite.config.mjs', 'vite.config.cts', 'vite.config.cjs'], projectRoot) ?? (0, node_path_1.join)(projectRoot, 'vite.config.ts'),
|
|
62
|
-
projectRoot,
|
|
63
|
-
];
|
|
64
|
-
if (devPort !== undefined) {
|
|
65
|
-
viteArgs.push('--port', String(devPort), '--strictPort');
|
|
66
|
-
}
|
|
67
|
-
const bridgeEnv = { LENSMCP_EVENT_FILE: eventFile, ...(options.viteEnv ?? {}) };
|
|
68
|
-
const labelPrefix = options.labelPrefix ?? '';
|
|
69
|
-
log(`[lens] starting Vite for ${options.project ?? projectRoot}${devPort ? ` on :${devPort}` : ''}`);
|
|
70
|
-
const vite = spawnChild(`${labelPrefix}vite`, viteBin, viteArgs, bridgeEnv);
|
|
71
|
-
const devUrl = options.openUrl ?? (devPort ? `http://localhost:${devPort}/` : undefined);
|
|
72
|
-
// ONE capture runner PER LENS FRONTEND — this duplication is deliberate, not
|
|
73
|
-
// a bug to consolidate. Seeing two `capture-runner.js` processes is the normal
|
|
74
|
-
// shape when the gateway hosts more than one lens frontend: its own
|
|
75
|
-
// (`bootSingletonsAndApps`) plus each REGISTERED workspace's
|
|
76
|
-
// (`hostWorkspaceApps`, model-A hosting). Each one captures a DIFFERENT dev
|
|
77
|
-
// URL and appends to a DIFFERENT workspace's event bus (`eventFile`), so they
|
|
78
|
-
// cannot be merged into a singleton without losing per-workspace isolation —
|
|
79
|
-
// the same isolation the labelPrefix above exists to protect. What made the
|
|
80
|
-
// duplication expensive was that each runner held a headless Chrome open for
|
|
81
|
-
// the whole dev session; capture is demand-driven now (see
|
|
82
|
-
// `@lensmcp/browser-capture`), so an idle runner owns no browser at all.
|
|
83
|
-
if (chrome) {
|
|
84
|
-
const captureRunner = findCaptureRunner(workspaceRoot);
|
|
85
|
-
if (!captureRunner) {
|
|
86
|
-
log("[lens] browser-capture runner not found — skipping live capture. Install the self-contained CLI: `npm i -D lensmcp` (it ships `bundled/capture-runner.js`).");
|
|
87
|
-
}
|
|
88
|
-
else if (!devUrl) {
|
|
89
|
-
log('[lens] no dev URL/port resolved — skipping live capture.');
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
log(`[lens] starting browser capture → ${devUrl}`);
|
|
93
|
-
spawnChild(`${labelPrefix}browser-capture`, process.execPath, [captureRunner], {
|
|
94
|
-
...bridgeEnv,
|
|
95
|
-
LENSMCP_DEV_URL: devUrl,
|
|
96
|
-
LENSMCP_TOKENS_FILE: (0, node_path_1.join)(workspaceRoot, 'lensmcp.tokens.json'),
|
|
97
|
-
LENSMCP_RULES_FILE: (0, node_path_1.join)(workspaceRoot, 'lensmcp.rules.json'),
|
|
98
|
-
LENSMCP_HEADLESS: headless === false ? 'false' : 'true',
|
|
99
|
-
}, true, // optional — its exit never tears down the session
|
|
100
|
-
{ delayMs: 10_000, max: 5 });
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return {
|
|
104
|
-
...(devPort !== undefined ? { devPort } : {}),
|
|
105
|
-
...(devUrl ? { devUrl } : {}),
|
|
106
|
-
vite,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
// ---------- bundle / bin resolvers (shared by both callers) ----------
|
|
110
|
-
function locateBin(name, roots) {
|
|
111
|
-
for (const root of roots) {
|
|
112
|
-
const candidate = (0, node_path_1.join)(root, 'node_modules', '.bin', name);
|
|
113
|
-
if ((0, node_fs_1.existsSync)(candidate))
|
|
114
|
-
return candidate;
|
|
115
|
-
}
|
|
116
|
-
return undefined;
|
|
117
|
-
}
|
|
118
|
-
function resolveFirstExisting(names, root) {
|
|
119
|
-
for (const n of names) {
|
|
120
|
-
const p = (0, node_path_1.join)(root, n);
|
|
121
|
-
if ((0, node_fs_1.existsSync)(p))
|
|
122
|
-
return p;
|
|
123
|
-
}
|
|
124
|
-
return undefined;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* The global npm root — `npm i -g lensmcp` puts the bundled artefacts there,
|
|
128
|
-
* not in the host workspace. Fast path derives it from the running node binary
|
|
129
|
-
* (nvm/standard unix layout); `npm root -g` is the fallback. Cached for the
|
|
130
|
-
* process lifetime.
|
|
131
|
-
*/
|
|
132
|
-
let cachedGlobalRoot;
|
|
133
|
-
function globalNodeModules() {
|
|
134
|
-
if (cachedGlobalRoot !== undefined)
|
|
135
|
-
return cachedGlobalRoot ?? undefined;
|
|
136
|
-
const guess = (0, node_path_1.resolve)((0, node_path_1.dirname)(process.execPath), '..', 'lib', 'node_modules');
|
|
137
|
-
if ((0, node_fs_1.existsSync)(guess)) {
|
|
138
|
-
cachedGlobalRoot = guess;
|
|
139
|
-
return guess;
|
|
140
|
-
}
|
|
141
|
-
try {
|
|
142
|
-
const out = (0, node_child_process_1.execSync)('npm root -g', { encoding: 'utf8', timeout: 5000 }).trim();
|
|
143
|
-
cachedGlobalRoot = out && (0, node_fs_1.existsSync)(out) ? out : null;
|
|
144
|
-
}
|
|
145
|
-
catch {
|
|
146
|
-
cachedGlobalRoot = null;
|
|
147
|
-
}
|
|
148
|
-
return cachedGlobalRoot ?? undefined;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Resolve the LensMCP MCP server bundle — the self-contained `lensmcp` CLI
|
|
152
|
-
* bundle (`bundled/main.js`), else the in-repo dev build. See the doc on
|
|
153
|
-
* `findCaptureRunner` for why we never reach into an unpublished `@lensmcp/*`.
|
|
154
|
-
*/
|
|
155
|
-
function findMcpBundle(workspaceRoot) {
|
|
156
|
-
const globalRoot = globalNodeModules();
|
|
157
|
-
return firstExisting([
|
|
158
|
-
(0, node_path_1.join)(workspaceRoot, 'node_modules', 'lensmcp', 'bundled', 'main.js'),
|
|
159
|
-
...(globalRoot ? [(0, node_path_1.join)(globalRoot, 'lensmcp', 'bundled', 'main.js')] : []),
|
|
160
|
-
// In-repo dev build (four-bucket layout) — never in a host's node_modules.
|
|
161
|
-
(0, node_path_1.join)(workspaceRoot, 'servers', 'lensmcp-mcp', 'dist', 'main.js'),
|
|
162
|
-
]);
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Resolve the lens DASHBOARD bundle — the human web view (`bundled/dashboard.js`,
|
|
166
|
-
* default :4321). Same shipping story as the MCP bundle.
|
|
167
|
-
*/
|
|
168
|
-
function findDashboardBundle(workspaceRoot) {
|
|
169
|
-
const globalRoot = globalNodeModules();
|
|
170
|
-
return firstExisting([
|
|
171
|
-
(0, node_path_1.join)(workspaceRoot, 'node_modules', 'lensmcp', 'bundled', 'dashboard.js'),
|
|
172
|
-
...(globalRoot ? [(0, node_path_1.join)(globalRoot, 'lensmcp', 'bundled', 'dashboard.js')] : []),
|
|
173
|
-
// In-repo dev build — never in a host's node_modules.
|
|
174
|
-
(0, node_path_1.join)(workspaceRoot, 'servers', 'lensmcp-mcp', 'dist', 'dashboard.js'),
|
|
175
|
-
]);
|
|
176
|
-
}
|
|
177
|
-
function findCaptureRunner(workspaceRoot) {
|
|
178
|
-
const globalRoot = globalNodeModules();
|
|
179
|
-
return firstExisting([
|
|
180
|
-
(0, node_path_1.join)(workspaceRoot, 'node_modules', 'lensmcp', 'bundled', 'capture-runner.js'),
|
|
181
|
-
...(globalRoot ? [(0, node_path_1.join)(globalRoot, 'lensmcp', 'bundled', 'capture-runner.js')] : []),
|
|
182
|
-
// In-repo dev build — never in a host's node_modules.
|
|
183
|
-
(0, node_path_1.join)(workspaceRoot, 'libs', 'browser-capture', 'dist', 'capture-runner.js'),
|
|
184
|
-
]);
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Resolve the standalone browser-event bridge runner — the self-contained
|
|
188
|
-
* `lensmcp` package's `bundled/bridge.js`, else the in-repo dev build.
|
|
189
|
-
*/
|
|
190
|
-
function findBridgeBundle(workspaceRoot) {
|
|
191
|
-
const globalRoot = globalNodeModules();
|
|
192
|
-
return firstExisting([
|
|
193
|
-
(0, node_path_1.join)(workspaceRoot, 'node_modules', 'lensmcp', 'bundled', 'bridge.js'),
|
|
194
|
-
...(globalRoot ? [(0, node_path_1.join)(globalRoot, 'lensmcp', 'bundled', 'bridge.js')] : []),
|
|
195
|
-
// In-repo dev build — never in a host's node_modules.
|
|
196
|
-
(0, node_path_1.join)(workspaceRoot, 'libs', 'bridge', 'dist', 'main.js'),
|
|
197
|
-
]);
|
|
198
|
-
}
|
|
199
|
-
function firstExisting(candidates) {
|
|
200
|
-
for (const c of candidates) {
|
|
201
|
-
if ((0, node_fs_1.existsSync)(c))
|
|
202
|
-
return c;
|
|
203
|
-
}
|
|
204
|
-
return undefined;
|
|
205
|
-
}
|
|
1
|
+
"use strict";var _=Object.defineProperty;var s=(n,e)=>_(n,"name",{value:e,configurable:!0});var g=Object.defineProperty,t=s((n,e)=>g(n,"name",{value:e,configurable:!0}),"t");Object.defineProperty(exports,"__esModule",{value:!0}),exports.spawnLensFrontend=spawnLensFrontend,exports.locateBin=locateBin,exports.resolveFirstExisting=resolveFirstExisting,exports.globalNodeModules=globalNodeModules,exports.findMcpBundle=findMcpBundle,exports.findDashboardBundle=findDashboardBundle,exports.findCaptureRunner=findCaptureRunner,exports.findBridgeBundle=findBridgeBundle;const node_child_process_1=require("node:child_process"),node_fs_1=require("node:fs"),node_path_1=require("node:path");function spawnLensFrontend(n,e){const i=n.log??(l=>console.log(l)),{projectRoot:o,workspaceRoot:c,eventFile:v}=n,u=n.chrome!==!1,b=n.headless!==!1,p=n.viteBin??locateBin("vite",[o,c]);if(!p)throw new Error("[lens] Could not find the vite binary in node_modules/.bin.");const r=n.port??(u?5173:void 0),a=["--config",resolveFirstExisting(["vite.config.ts","vite.config.mts","vite.config.js","vite.config.mjs","vite.config.cts","vite.config.cjs"],o)??(0,node_path_1.join)(o,"vite.config.ts"),o];r!==void 0&&a.push("--port",String(r),"--strictPort");const f={LENSMCP_EVENT_FILE:v,...n.viteEnv??{}},j=n.labelPrefix??"";i(`[lens] starting Vite for ${n.project??o}${r?` on :${r}`:""}`);const m=e(`${j}vite`,p,a,f),d=n.openUrl??(r?`http://localhost:${r}/`:void 0);if(u){const l=findCaptureRunner(c);l?d?(i(`[lens] starting browser capture \u2192 ${d}`),e(`${j}browser-capture`,process.execPath,[l],{...f,LENSMCP_DEV_URL:d,LENSMCP_TOKENS_FILE:(0,node_path_1.join)(c,"lensmcp.tokens.json"),LENSMCP_RULES_FILE:(0,node_path_1.join)(c,"lensmcp.rules.json"),LENSMCP_HEADLESS:b===!1?"false":"true"},!0,{delayMs:1e4,max:5})):i("[lens] no dev URL/port resolved \u2014 skipping live capture."):i("[lens] browser-capture runner not found \u2014 skipping live capture. Install the self-contained CLI: `npm i -D lensmcp` (it ships `bundled/capture-runner.js`).")}return{...r!==void 0?{devPort:r}:{},...d?{devUrl:d}:{},vite:m}}s(spawnLensFrontend,"spawnLensFrontend"),t(spawnLensFrontend,"spawnLensFrontend");function locateBin(n,e){for(const i of e){const o=(0,node_path_1.join)(i,"node_modules",".bin",n);if((0,node_fs_1.existsSync)(o))return o}}s(locateBin,"locateBin"),t(locateBin,"locateBin");function resolveFirstExisting(n,e){for(const i of n){const o=(0,node_path_1.join)(e,i);if((0,node_fs_1.existsSync)(o))return o}}s(resolveFirstExisting,"resolveFirstExisting"),t(resolveFirstExisting,"resolveFirstExisting");let cachedGlobalRoot;function globalNodeModules(){if(cachedGlobalRoot!==void 0)return cachedGlobalRoot??void 0;const n=(0,node_path_1.resolve)((0,node_path_1.dirname)(process.execPath),"..","lib","node_modules");if((0,node_fs_1.existsSync)(n))return cachedGlobalRoot=n,n;try{const e=(0,node_child_process_1.execSync)("npm root -g",{encoding:"utf8",timeout:5e3}).trim();cachedGlobalRoot=e&&(0,node_fs_1.existsSync)(e)?e:null}catch{cachedGlobalRoot=null}return cachedGlobalRoot??void 0}s(globalNodeModules,"globalNodeModules"),t(globalNodeModules,"globalNodeModules");function findMcpBundle(n){const e=globalNodeModules();return firstExisting([(0,node_path_1.join)(n,"node_modules","lensmcp","bundled","main.js"),...e?[(0,node_path_1.join)(e,"lensmcp","bundled","main.js")]:[],(0,node_path_1.join)(n,"servers","lensmcp-mcp","dist","main.js")])}s(findMcpBundle,"findMcpBundle"),t(findMcpBundle,"findMcpBundle");function findDashboardBundle(n){const e=globalNodeModules();return firstExisting([(0,node_path_1.join)(n,"node_modules","lensmcp","bundled","dashboard.js"),...e?[(0,node_path_1.join)(e,"lensmcp","bundled","dashboard.js")]:[],(0,node_path_1.join)(n,"servers","lensmcp-mcp","dist","dashboard.js")])}s(findDashboardBundle,"findDashboardBundle"),t(findDashboardBundle,"findDashboardBundle");function findCaptureRunner(n){const e=globalNodeModules();return firstExisting([(0,node_path_1.join)(n,"node_modules","lensmcp","bundled","capture-runner.js"),...e?[(0,node_path_1.join)(e,"lensmcp","bundled","capture-runner.js")]:[],(0,node_path_1.join)(n,"libs","browser-capture","dist","capture-runner.js")])}s(findCaptureRunner,"findCaptureRunner"),t(findCaptureRunner,"findCaptureRunner");function findBridgeBundle(n){const e=globalNodeModules();return firstExisting([(0,node_path_1.join)(n,"node_modules","lensmcp","bundled","bridge.js"),...e?[(0,node_path_1.join)(e,"lensmcp","bundled","bridge.js")]:[],(0,node_path_1.join)(n,"libs","bridge","dist","main.js")])}s(findBridgeBundle,"findBridgeBundle"),t(findBridgeBundle,"findBridgeBundle");function firstExisting(n){for(const e of n)if((0,node_fs_1.existsSync)(e))return e}s(firstExisting,"firstExisting"),t(firstExisting,"firstExisting");
|