lensmcp 1.20.0 → 1.21.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.
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "lensmcp-marketplace",
3
+ "interface": {
4
+ "displayName": "LensMCP Marketplace"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "lensmcp",
9
+ "source": {
10
+ "source": "local",
11
+ "path": "./plugins/lensmcp"
12
+ },
13
+ "policy": {
14
+ "installation": "AVAILABLE",
15
+ "authentication": "ON_INSTALL"
16
+ },
17
+ "category": "Developer Tools"
18
+ }
19
+ ]
20
+ }
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > The observability lens for coding agents — run the MCP server your agent connects to and watch your apps live.
4
4
 
5
- **LensMCP** gives coding agents (and you) eyes on running applications. It captures traces, flows, and logs from your app and exposes them through an [MCP](https://modelcontextprotocol.io) server, so an agent can ask *"what just happened?"* and get a real answer — request flows, state changes, errors, and browser activity — instead of guessing from source code alone.
5
+ **LensMCP** gives coding agents (and you) eyes on running applications. It captures traces, flows, and logs from your app and exposes them through an [MCP](https://modelcontextprotocol.io) server, so an agent can ask _"what just happened?"_ and get a real answer — request flows, state changes, errors, and browser activity — instead of guessing from source code alone.
6
6
 
7
7
  `lensmcp` is the CLI. It runs the LensMCP MCP server (over stdio or HTTP) that agents discover and connect to, and it serves a local **dashboard** where you can browse Flows, Cluster, Logs, and Resources captured from your running apps. It also ships helpers to wire LensMCP into your workspace (`install`) and to diagnose your setup (`doctor`).
8
8
 
@@ -20,15 +20,17 @@ Requires **Node 18+** (Node 20+ recommended; this workspace pins Node 26 via `.n
20
20
  lensmcp <command> [options]
21
21
  ```
22
22
 
23
- | Command | Description |
24
- | --- | --- |
25
- | `lensmcp mcp` | Launch the LensMCP MCP server that agents connect to. Defaults to **stdio**; set `--transport http` (or `LENSMCP_TRANSPORT=http`) to serve over HTTP on `--port` (default **3000**). |
26
- | `lensmcp dashboard` | Serve the live web view of the lens — Flows, Cluster, Logs, Resources — on `--port` (default **4321**). |
27
- | `lensmcp install` | Install LensMCP into the host Nx workspace (delegates to `nx g @lensmcp/nx-plugin:init`). Wires `.mcp.json` so agents auto-discover the server, plus `.gitignore` and config. Idempotent. |
28
- | `lensmcp doctor` | Diagnose the install: Node version, workspace + plugin registration, `.mcp.json` entry, MCP bundle, per-project Vite/Nest wiring, `agent-dev` targets, and Chrome for browser capture. |
29
- | `lensmcp rollout` | Edit the gateway rollout config (`@lensmcp/cluster`) `add-cohort`, `set-weight`, `promote`, `abort`, `add-rule`, `remove-rule`, `status`. |
30
- | `lensmcp --version` | Print the installed `lensmcp` version. |
31
- | `lensmcp --help` | Show usage. |
23
+ | Command | Description |
24
+ | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
25
+ | `lensmcp mcp` | Launch the LensMCP MCP server that agents connect to. Defaults to **stdio**; set `--transport http` (or `LENSMCP_TRANSPORT=http`) to serve over HTTP on `--port` (default **3000**). |
26
+ | `lensmcp dashboard` | Serve the live web view of the lens — Flows, Cluster, Logs, Resources — on `--port` (default **4321**). |
27
+ | `lensmcp install` | Install LensMCP into the host Nx workspace (delegates to `nx g @lensmcp/nx-plugin:init`). Wires `.mcp.json` so agents auto-discover the server, plus `.gitignore` and config. Idempotent. |
28
+ | `lensmcp plugin` | Install the LensMCP plugin into the coding agents on this machine **Claude Code and Codex** — from the lensmcp package the workspace depends on. `plugin status` compares installed vs packaged versions. Idempotent; the same command upgrades. |
29
+ | `lensmcp upgrade` | Move **every connected workspace** (`~/.lensmcp/workspaces.json` + the current one) onto one lensmcp version: rewrite `lensmcp`/`@lensmcp/*` in each package.json, run each workspace's package manager, refresh a global install + both agent plugins, then restart the gateway daemon and re-register its guests. |
30
+ | `lensmcp doctor` | Diagnose the install: Node version, workspace + plugin registration, `.mcp.json` entry, MCP bundle, per-project Vite/Nest wiring, `agent-dev` targets, and Chrome for browser capture. |
31
+ | `lensmcp rollout` | Edit the gateway rollout config (`@lensmcp/cluster`) — `add-cohort`, `set-weight`, `promote`, `abort`, `add-rule`, `remove-rule`, `status`. |
32
+ | `lensmcp --version` | Print the installed `lensmcp` version. |
33
+ | `lensmcp --help` | Show usage. |
32
34
 
33
35
  ### `lensmcp mcp`
34
36
 
@@ -36,11 +38,11 @@ lensmcp <command> [options]
36
38
  lensmcp mcp [--cwd <dir>] [--transport stdio|http] [--port <n>]
37
39
  ```
38
40
 
39
- | Flag | Default | Description |
40
- | --- | --- | --- |
41
- | `--cwd <dir>` | current directory | Workspace root the server runs against. |
42
- | `--transport <stdio\|http>` | `stdio` | Transport agents connect over. `stdio` for local agents (Claude Code, Cursor); `http` to expose an HTTP endpoint. |
43
- | `--port <n>` | `3000` | HTTP port (used when transport is `http`). |
41
+ | Flag | Default | Description |
42
+ | --------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------- |
43
+ | `--cwd <dir>` | current directory | Workspace root the server runs against. |
44
+ | `--transport <stdio\|http>` | `stdio` | Transport agents connect over. `stdio` for local agents (Claude Code, Cursor); `http` to expose an HTTP endpoint. |
45
+ | `--port <n>` | `3000` | HTTP port (used when transport is `http`). |
44
46
 
45
47
  Reads/writes the cross-process event file at `<cwd>/.lensmcp/events.jsonl` (override with `LENSMCP_EVENT_FILE`) — the same file your instrumented apps write to, so ingest and producers rendezvous with zero extra config.
46
48
 
@@ -50,10 +52,10 @@ Reads/writes the cross-process event file at `<cwd>/.lensmcp/events.jsonl` (over
50
52
  lensmcp dashboard [--cwd <dir>] [--port <n>]
51
53
  ```
52
54
 
53
- | Flag | Default | Description |
54
- | --- | --- | --- |
55
- | `--cwd <dir>` | current directory | Workspace root to read events from. |
56
- | `--port <n>` | `4321` | Port to serve the dashboard on (`http://localhost:<port>`). |
55
+ | Flag | Default | Description |
56
+ | ------------- | ----------------- | ----------------------------------------------------------- |
57
+ | `--cwd <dir>` | current directory | Workspace root to read events from. |
58
+ | `--port <n>` | `4321` | Port to serve the dashboard on (`http://localhost:<port>`). |
57
59
 
58
60
  Tails the same `.lensmcp/events.jsonl` the MCP server uses, so the dashboard shows the identical live flows, signals, and resources your agent sees.
59
61
 
@@ -65,6 +67,44 @@ lensmcp install [--cwd <dir>] [--skip-format] [--register-host-config <mode>]
65
67
 
66
68
  Run from inside an Nx workspace (requires `nx.json` and a local `nx` binary). Delegates to `nx g @lensmcp/nx-plugin:init --no-interactive`. Use `--skip-format` to skip post-generation formatting and `--register-host-config <mode>` to control how the host config is registered.
67
69
 
70
+ ### `lensmcp plugin`
71
+
72
+ ```bash
73
+ lensmcp plugin <install|status> [claude|codex] [--from <dir>] [--scope <user|project|local>] [--cwd <dir>]
74
+ ```
75
+
76
+ Installs the LensMCP plugin into the coding agents on this machine, from the lensmcp
77
+ package the workspace at `--cwd` depends on (walks up to the nearest
78
+ `node_modules/lensmcp`; `--from` overrides). Idempotent, and the **same command
79
+ upgrades**: both agents treat the package directory as a live marketplace source, so a
80
+ re-install re-reads whatever version is installed there. An agent whose CLI is not on
81
+ PATH is skipped. `--scope` (Claude Code only) picks the install scope, defaulting to the
82
+ scope of the existing install.
83
+
84
+ ### `lensmcp upgrade`
85
+
86
+ ```bash
87
+ lensmcp upgrade [version] [--dry-run] [--no-install] [--no-plugins] [--no-global] [--no-restart]
88
+ ```
89
+
90
+ One command that moves the whole machine to one lensmcp version (latest by default), in
91
+ the only order that works:
92
+
93
+ 1. rewrite `lensmcp` + `@lensmcp/*` lines in every connected workspace's package.json
94
+ (the gateway registry `~/.lensmcp/workspaces.json` plus the workspace you run it in;
95
+ `^`/`~` operators are kept, `link:`/`workspace:` pins are reported and never touched),
96
+ 2. run each workspace's **own** package manager install (`packageManager` field, then lockfile),
97
+ 3. move a machine-global `npm i -g lensmcp` when one exists (it shadows every project for a bare `lensmcp`),
98
+ 4. re-install the Claude Code + Codex plugins from the fresh package,
99
+ 5. restart the gateway daemon and **re-register every workspace it hosted** — the daemon
100
+ keeps the bundle it loaded at start forever, and an owner restart drops its guests, so
101
+ both halves are mandatory. A daemon that *reports* a version (1.21+) is restarted even
102
+ when no package.json moved, if it provably lags the target.
103
+
104
+ Per-workspace failure posture: one failed install never blocks the others, every failure
105
+ names the command that finishes the job by hand, and re-running converges. `--dry-run`
106
+ prints the full plan without changing anything.
107
+
68
108
  ### `lensmcp doctor`
69
109
 
70
110
  ```bash
@@ -83,13 +123,13 @@ Edits a gateway rollout config with validated, atomic writes that the production
83
123
 
84
124
  ## Environment variables
85
125
 
86
- | Variable | Used by | Default |
87
- | --- | --- | --- |
88
- | `LENSMCP_TRANSPORT` | `mcp` | `stdio` (overridden by `--transport`) |
89
- | `LENSMCP_PORT` | `mcp` | `3000` (overridden by `--port`) |
90
- | `LENSMCP_DASHBOARD_PORT` | `dashboard` | `4321` (overridden by `--port`) |
91
- | `LENSMCP_EVENT_FILE` | `mcp`, `dashboard` | `<cwd>/.lensmcp/events.jsonl` |
92
- | `CHROME_PATH` | `doctor` | auto-detected (browser capture only) |
126
+ | Variable | Used by | Default |
127
+ | ------------------------ | ------------------ | ------------------------------------- |
128
+ | `LENSMCP_TRANSPORT` | `mcp` | `stdio` (overridden by `--transport`) |
129
+ | `LENSMCP_PORT` | `mcp` | `3000` (overridden by `--port`) |
130
+ | `LENSMCP_DASHBOARD_PORT` | `dashboard` | `4321` (overridden by `--port`) |
131
+ | `LENSMCP_EVENT_FILE` | `mcp`, `dashboard` | `<cwd>/.lensmcp/events.jsonl` |
132
+ | `CHROME_PATH` | `doctor` | auto-detected (browser capture only) |
93
133
 
94
134
  ## Quick start
95
135
 
@@ -113,6 +153,30 @@ lensmcp mcp --transport http --port 3000 # or expose over HTTP
113
153
 
114
154
  Most local agents (Claude Code, Cursor, VS Code) read `.mcp.json` and launch `lensmcp mcp` over stdio automatically after `lensmcp install` — no manual wiring needed.
115
155
 
156
+ ### Agent plugins (Claude Code + Codex)
157
+
158
+ The npm package ships a plugin per agent — Claude Code (`plugin/`) and Codex
159
+ (`plugins/lensmcp/`), each with LensMCP skills and project-scoped MCP wiring. One command
160
+ installs (or upgrades) both, pointing each agent's directory marketplace at this
161
+ workspace's `node_modules/lensmcp` so it moves with the dependency:
162
+
163
+ ```bash
164
+ npx -y lensmcp plugin install # both agents; a missing CLI is skipped, not an error
165
+ npx -y lensmcp plugin install codex # just one
166
+ npx -y lensmcp plugin status # installed vs packaged versions
167
+ ```
168
+
169
+ Under the hood that is the documented marketplace-add + plugin-add pair per agent — run
170
+ them by hand if you prefer:
171
+
172
+ ```bash
173
+ codex plugin marketplace add ./node_modules/lensmcp
174
+ codex plugin add lensmcp@lensmcp-marketplace
175
+ ```
176
+
177
+ Start a new Codex thread after installation. The existing Claude Code plugin remains available
178
+ separately and is unchanged.
179
+
116
180
  ## How it fits
117
181
 
118
182
  `lensmcp` is the entry point of the LensMCP toolchain. [`@lensmcp/nx-plugin`](https://github.com/kiwiapps-ltd/lensmcp) wires LensMCP into your workspace and projects; the instrumentation libraries (`@lensmcp/vite-plugin`, `@lensmcp/nest-instrumentation`, `@lensmcp/react-instrumentation`, and friends) capture flows, state, and logs from running apps into `.lensmcp/events.jsonl`; and [`@lensmcp/cluster`](https://github.com/kiwiapps-ltd/lensmcp) powers the gateway and targeted rollouts driven by `lensmcp rollout`.
package/bin.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- "use strict";import{runCli as e}from"./lib/cli.js";e({cwd:process.cwd(),argv:process.argv.slice(2)}).then(s=>{process.exit(s.exitCode)},s=>{console.error(s instanceof Error?s.stack??s.message:String(s)),process.exit(1)});
2
+ "use strict";import{runCli as r}from"./lib/cli.js";r({cwd:process.cwd(),argv:process.argv.slice(2)}).then(e=>{process.exit(e.exitCode)},e=>{console.error(e instanceof Error?e.stack??e.message:String(e)),process.exit(1)});
@@ -0,0 +1,103 @@
1
+ /** The marketplace both manifests declare — one name, so `<plugin>@<marketplace>` is agent-agnostic. */
2
+ export declare const MARKETPLACE = "lensmcp-marketplace";
3
+ export declare const PLUGIN = "lensmcp";
4
+ export declare const PLUGIN_ID = "lensmcp@lensmcp-marketplace";
5
+ export type AgentId = 'claude' | 'codex';
6
+ export interface AgentDefinition {
7
+ id: AgentId;
8
+ label: string;
9
+ /** The agent's CLI binary, as invoked. */
10
+ bin: string;
11
+ /** Package-relative marketplace manifest. Its presence PROVES this agent's plugin ships in that version. */
12
+ manifest: string;
13
+ /** Package-relative plugin manifest — read for the version we are about to install. */
14
+ pluginManifest: string;
15
+ /** The lensmcp version that first shipped this agent's plugin (named when the manifest is missing). */
16
+ since: string;
17
+ restartHint: string;
18
+ }
19
+ export declare const AGENTS: readonly AgentDefinition[];
20
+ export declare function agentById(id: string): AgentDefinition | undefined;
21
+ export interface ResolveRootOptions {
22
+ cwd: string;
23
+ /** `--from <dir>` — an explicit package root, taken at face value. */
24
+ from?: string;
25
+ /** The running CLI's own package root (`cliPackageRoot()`), used when the workspace has no install. */
26
+ selfRoot?: string;
27
+ /** Injected for tests. */
28
+ exists?: (path: string) => boolean;
29
+ }
30
+ export interface ResolvedRoot {
31
+ root: string;
32
+ source: 'flag' | 'workspace' | 'self';
33
+ /** The lensmcp version at that root, when readable. */
34
+ version?: string;
35
+ }
36
+ /**
37
+ * The directory an agent's `marketplace add` is pointed at.
38
+ *
39
+ * WORKSPACE FIRST, self last, and the order is load-bearing: the marketplace is a
40
+ * DIRECTORY source, so whatever is on disk there is the version the agent installs
41
+ * and keeps re-reading. Pointing it at the running CLI (often a global or an `npx`
42
+ * cache) would pin the agent to a version the project does not use and cannot
43
+ * upgrade — precisely the plugin/project skew this toolchain already had to grow a
44
+ * detector for. `node_modules/lensmcp` moves with `lensmcp upgrade`; nothing else does.
45
+ */
46
+ export declare function resolvePluginRoot(options: ResolveRootOptions): ResolvedRoot | undefined;
47
+ /** The version stamped into an agent's plugin manifest at publish time (`scripts/prepare-dist.mjs`). */
48
+ export declare function readPluginManifestVersion(root: string, agent: AgentDefinition): string | undefined;
49
+ export interface PlanOptions {
50
+ /** Absolute package root the marketplace points at. */
51
+ root: string;
52
+ /** Claude only — `user` (its default) | `project` | `local`. Omitted = the agent's default. */
53
+ scope?: string;
54
+ }
55
+ /**
56
+ * The exact commands, in order. Every one of them is idempotent (verified against
57
+ * both CLIs): re-adding a marketplace at the same path is a no-op that exits 0, and
58
+ * re-installing an installed plugin re-reads the directory source — which is how an
59
+ * UPGRADE happens here too. So `plugin install` is the same command whether nothing,
60
+ * an old version, or the current version is installed, and there is no
61
+ * install-vs-update branch to get wrong.
62
+ */
63
+ export declare function planAgentInstall(agent: AgentDefinition, options: PlanOptions): string[][];
64
+ export type AgentInstallOutcome =
65
+ /** Every command exited 0. */
66
+ 'installed'
67
+ /** The agent's CLI is not on PATH — not an error, this machine just has no Codex/Claude. */
68
+ | 'skipped-no-cli'
69
+ /** This lensmcp version ships no plugin for that agent. Actionable: upgrade lensmcp. */
70
+ | 'skipped-not-packaged'
71
+ /** A command failed. Actionable, and never fatal to the other agents. */
72
+ | 'failed';
73
+ export interface AgentInstallResult {
74
+ agent: AgentId;
75
+ label: string;
76
+ outcome: AgentInstallOutcome;
77
+ /** The version the plugin manifest declares (what the agent ends up with). */
78
+ version?: string;
79
+ /** What was run (or what to run, when it could not be). */
80
+ commands: string[];
81
+ detail?: string;
82
+ restartHint?: string;
83
+ }
84
+ export interface InstallDeps {
85
+ /** Run a command; `undefined` means the binary was not found (ENOENT). */
86
+ run: (bin: string, args: string[]) => {
87
+ code: number;
88
+ stdout?: string;
89
+ stderr?: string;
90
+ } | undefined;
91
+ exists?: (path: string) => boolean;
92
+ }
93
+ export declare function installAgentPlugin(agent: AgentDefinition, options: PlanOptions, deps: InstallDeps): AgentInstallResult;
94
+ /** The real runner — bounded, non-interactive, never throws. */
95
+ export declare function spawnAgentRunner(env: NodeJS.ProcessEnv, timeoutMs?: number): InstallDeps['run'];
96
+ /**
97
+ * The version Codex has installed, from `codex plugin list --json`.
98
+ *
99
+ * Unlike Claude Code there is no index file contract to read (its state lives in
100
+ * `~/.codex` with no documented layout), so this one IS a subprocess — acceptable
101
+ * for an explicit `plugin status`, which is not on a hook path.
102
+ */
103
+ export declare function codexInstalledVersion(run: InstallDeps['run']): string | undefined;
@@ -0,0 +1,2 @@
1
+ "use strict";var k=Object.defineProperty;var l=(t,e)=>k(t,"name",{value:e,configurable:!0});var y=Object.defineProperty,c=l((t,e)=>y(t,"name",{value:e,configurable:!0}),"d");import{spawnSync as j}from"node:child_process";import{existsSync as m,readFileSync as v}from"node:fs";import{dirname as A,isAbsolute as P,join as d,resolve as x}from"node:path";export const MARKETPLACE="lensmcp-marketplace",PLUGIN="lensmcp",PLUGIN_ID=`${PLUGIN}@${MARKETPLACE}`,AGENTS=[{id:"claude",label:"Claude Code",bin:"claude",manifest:".claude-plugin/marketplace.json",pluginManifest:"plugin/.claude-plugin/plugin.json",since:"1.9.0",restartHint:"restart Claude Code (or run /plugin) for the new version to load"},{id:"codex",label:"Codex",bin:"codex",manifest:".agents/plugins/marketplace.json",pluginManifest:"plugins/lensmcp/.codex-plugin/plugin.json",since:"1.20.0",restartHint:"start a new Codex thread for the plugin to load"}];export function agentById(t){return AGENTS.find(e=>e.id===t)}l(agentById,"agentById"),c(agentById,"agentById");export function resolvePluginRoot(t){const e=t.exists??m,o=c(r=>{try{const s=JSON.parse(v(d(r,"package.json"),"utf8"));return typeof s.version=="string"?s.version:void 0}catch{return}},"readVersion"),i=c((r,s)=>{const a=o(r);return{root:r,source:s,...a?{version:a}:{}}},"decorate");if(t.from){const r=P(t.from)?t.from:x(t.cwd,t.from);return e(d(r,"package.json"))?i(r,"flag"):void 0}let n=x(t.cwd);for(let r=0;r<8;r++){const s=d(n,"node_modules","lensmcp");if(e(d(s,"package.json")))return i(s,"workspace");const a=A(n);if(a===n)break;n=a}if(t.selfRoot&&e(d(t.selfRoot,"package.json")))return i(t.selfRoot,"self")}l(resolvePluginRoot,"resolvePluginRoot"),c(resolvePluginRoot,"resolvePluginRoot");export function readPluginManifestVersion(t,e){try{const o=JSON.parse(v(d(t,e.pluginManifest),"utf8"));return typeof o.version=="string"?o.version:void 0}catch{return}}l(readPluginManifestVersion,"readPluginManifestVersion"),c(readPluginManifestVersion,"readPluginManifestVersion");export function planAgentInstall(t,e){if(t.id==="codex")return[[t.bin,"plugin","marketplace","add",e.root],[t.bin,"plugin","add",PLUGIN_ID]];const o=e.scope?["--scope",e.scope]:[];return[[t.bin,"plugin","marketplace","add",e.root],[t.bin,"plugin","marketplace","update",MARKETPLACE],[t.bin,"plugin","install",PLUGIN_ID,...o,"--yes"]]}l(planAgentInstall,"planAgentInstall"),c(planAgentInstall,"planAgentInstall");export function installAgentPlugin(t,e,o){const i=o.exists??m,n=planAgentInstall(t,e),r=n.map(p=>p.join(" ")),s=readPluginManifestVersion(e.root,t),a={agent:t.id,label:t.label,commands:r,...s?{version:s}:{}};if(!i(d(e.root,t.manifest)))return{...a,outcome:"skipped-not-packaged",detail:`${e.root} ships no ${t.manifest} \u2014 the ${t.label} plugin arrived in lensmcp ${t.since}. Upgrade first: \`lensmcp upgrade\`.`};for(const p of n){const[g,...b]=p,u=g===void 0?void 0:o.run(g,b);if(!u)return{...a,outcome:"skipped-no-cli",detail:`\`${t.bin}\` is not on PATH`};if(u.code!==0){const f=(u.stderr??u.stdout??"").trim().split(`
2
+ `).filter(Boolean).pop();return{...a,outcome:"failed",detail:f&&f.length>0?f:`\`${p.join(" ")}\` exited ${u.code}`}}}return{...a,outcome:"installed",restartHint:t.restartHint}}l(installAgentPlugin,"installAgentPlugin"),c(installAgentPlugin,"installAgentPlugin");export function spawnAgentRunner(t,e=12e4){return(o,i)=>{try{const n=j(o,i,{encoding:"utf8",timeout:e,env:t,stdio:["ignore","pipe","pipe"]});return n.error&&n.error.code==="ENOENT"?void 0:{code:n.status??1,...n.stdout?{stdout:n.stdout}:{},...n.stderr?{stderr:n.stderr}:{}}}catch{return}}}l(spawnAgentRunner,"spawnAgentRunner"),c(spawnAgentRunner,"spawnAgentRunner");export function codexInstalledVersion(t){const e=t("codex",["plugin","list","--json"]);if(!(!e||e.code!==0||!e.stdout))try{const o=(JSON.parse(e.stdout).installed??[]).find(i=>i.pluginId===PLUGIN_ID||i.name===PLUGIN&&i.marketplaceName===MARKETPLACE)?.version;return typeof o=="string"?o:void 0}catch{return}}l(codexInstalledVersion,"codexInstalledVersion"),c(codexInstalledVersion,"codexInstalledVersion");