lensmcp 1.25.17 → 1.25.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin.js +1 -1
- package/bundled/bridge.js +38 -37
- package/bundled/capture-runner.js +6 -6
- package/bundled/dashboard-ui/app.css +1 -1
- package/bundled/dashboard-ui/app.js +92 -92
- package/bundled/dashboard-ui/chunks/ReplayView-vO4p7cGp.js +131 -0
- package/bundled/dashboard.js +288 -279
- package/bundled/main.js +228 -221
- package/bundled/shim.js +8 -8
- package/lib/agent-asked.js +4 -4
- package/lib/agent-plugins.js +2 -2
- package/lib/bridge-origins.js +1 -1
- package/lib/call-command.js +2 -2
- package/lib/cli-help.js +3 -3
- package/lib/cli.js +12 -12
- package/lib/dashboard-login.d.ts +9 -2
- package/lib/dashboard-login.js +3 -3
- package/lib/dismiss-command.js +2 -2
- package/lib/duplicate-registration.js +1 -1
- package/lib/forward-signals.js +1 -1
- package/lib/gateway-registration.js +1 -1
- package/lib/guest-graph.js +4 -4
- package/lib/heap-analyzer-main.js +1 -1
- package/lib/heap-analyzer.js +1 -1
- package/lib/hook-memory.js +1 -1
- package/lib/instance-command.js +9 -9
- package/lib/instance-registry.js +2 -2
- package/lib/instance-resources.js +5 -5
- package/lib/instance-worktree.js +6 -6
- package/lib/lens-ignore.js +2 -2
- package/lib/lint-args.js +1 -1
- package/lib/logs-follow.js +1 -1
- package/lib/mcp-mode.js +3 -3
- package/lib/mcp-restart.js +1 -1
- package/lib/mcp-sessions.js +2 -2
- package/lib/mcp-token.js +3 -3
- package/lib/mcp-wiring.js +2 -2
- package/lib/mem-command.js +3 -3
- package/lib/perf-rules-check.js +4 -4
- package/lib/plugin-version.js +3 -3
- package/lib/pod-source-maps.js +1 -1
- package/lib/process-identity.js +1 -1
- package/lib/process-ownership.js +2 -2
- package/lib/project-files.js +1 -1
- package/lib/recycle-policy.js +1 -1
- package/lib/resp-client.js +5 -5
- package/lib/restart-command.js +2 -2
- package/lib/server-bundle.js +2 -2
- package/lib/status-client.js +2 -2
- package/lib/status-policy.js +2 -2
- package/lib/sweep.js +1 -1
- package/lib/upgrade.js +2 -2
- package/lib/workspace-scope.js +2 -2
- package/package.json +4 -4
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/skills/dashboard/SKILL.md +2 -1
- package/plugin/skills/using-lensmcp/SKILL.md +28 -1
- package/plugin/skills/worktrees/SKILL.md +2 -1
- package/plugins/lensmcp/.codex-plugin/plugin.json +1 -1
- package/plugins/lensmcp/skills/lensmcp-dashboard/SKILL.md +2 -1
- package/plugins/lensmcp/skills/using-lensmcp/SKILL.md +27 -1
package/lib/agent-asked.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var h=Object.defineProperty;var o=(
|
|
2
|
-
`)){const
|
|
3
|
-
`).map(
|
|
4
|
-
`),!0):!1}catch{return!1}}o(recordAsked,"recordAsked"),
|
|
1
|
+
"use strict";var h=Object.defineProperty;var o=(n,e)=>h(n,"name",{value:e,configurable:!0});var y=Object.defineProperty,p=o((n,e)=>y(n,"name",{value:e,configurable:!0}),"o");import{execFileSync as x}from"node:child_process";import{randomBytes as k}from"node:crypto";import{appendFileSync as E,existsSync as S,statSync as v}from"node:fs";import{dirname as m,join as g,resolve as w}from"node:path";const $=/(?:^|[\s/])lensmcp(?:\/bin\.js|\.js)?\s+mcp(?:\s|$)/,N=8,F=4;export const ASKED_MAX=300;export function listProcesses(){try{const n=x("ps",["-axo","pid=,ppid=,command="],{encoding:"utf8",timeout:2e3,stdio:["ignore","pipe","ignore"]}),e=[];for(const t of n.split(`
|
|
2
|
+
`)){const s=/^\s*(\d+)\s+(\d+)\s+(.*)$/.exec(t);s&&e.push({pid:Number(s[1]),ppid:Number(s[2]),command:s[3]})}return e}catch{return[]}}o(listProcesses,"listProcesses"),p(listProcesses,"listProcesses");export function shimsOf(n,e){const t=new Map(e.map(i=>[i.pid,i])),s=new Map;for(const i of e)s.set(i.ppid,[...s.get(i.ppid)??[],i]);const c=new Set;let r=t.get(n)?.ppid;for(let i=0;r!==void 0&&r>1&&i<N;i++){c.add(r);const a=[];let f=s.get(r)??[];for(let l=0;f.length&&l<F;l++){const u=[];for(const d of f)d.pid===n||c.has(d.pid)||($.test(d.command)&&a.push(d.pid),u.push(...s.get(d.pid)??[]));f=u}if(a.length)return a;r=t.get(r)?.ppid}return[]}o(shimsOf,"shimsOf"),p(shimsOf,"shimsOf");export function askedTask(n){if(typeof n!="string")return;const e=n.split(`
|
|
3
|
+
`).map(t=>t.replace(/\s+/g," ").trim()).find(t=>t.length>0);if(!(!e||/^\/\S+$/.test(e)))return e.length>ASKED_MAX?`${e.slice(0,ASKED_MAX-1)}\u2026`:e}o(askedTask,"askedTask"),p(askedTask,"askedTask");export function askedEventFile(n,e){if(e.LENSMCP_EVENT_FILE)return e.LENSMCP_EVENT_FILE;let t=w(n);for(;;){try{if(v(g(t,".lensmcp")).isDirectory())return g(t,".lensmcp","events.jsonl")}catch{}const s=m(t);if(s===t)return;t=s}}o(askedEventFile,"askedEventFile"),p(askedEventFile,"askedEventFile");export function askedEvent(n,e,t,s=Date.now()){return{id:`${s.toString(36)}${k(4).toString("hex")}`,sessionId:"pending",timestamp:s,source:"lens",category:"agent",severity:"info",context:{sessionId:"pending"},fingerprint:"agent-asked",title:`asked: ${n.length>80?`${n.slice(0,79)}\u2026`:n}`,raw:{kind:"agent-asked",shims:[...e],text:n,client:t}}}o(askedEvent,"askedEvent"),p(askedEvent,"askedEvent");export function recordAsked(n,e){try{const t=JSON.parse(n||"{}"),s=askedTask(t.prompt);if(!s)return!1;const c=askedEventFile(typeof t.cwd=="string"&&t.cwd?t.cwd:e.cwd,e.env);if(!c||!S(m(c)))return!1;const r=shimsOf(e.self??process.pid,(e.procs??listProcesses)());return r.length?(E(c,`${JSON.stringify(askedEvent(s,r,e.client??"claude-code"))}
|
|
4
|
+
`),!0):!1}catch{return!1}}o(recordAsked,"recordAsked"),p(recordAsked,"recordAsked");
|
package/lib/agent-plugins.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`).filter(Boolean).pop();return{...a,outcome:"failed",detail:f&&f.length>0?f:`\`${
|
|
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");
|
package/lib/bridge-origins.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var c=Object.defineProperty;var s=(t,e)=>c(t,"name",{value:e,configurable:!0});var a=Object.defineProperty,i=s((t,e)=>a(t,"name",{value:e,configurable:!0}),"n");import{readFileSync as l}from"node:fs";export function clusterPageHosts(t){const e=new Set;for(const r of t){if(r.service||typeof r.host!="string")continue;const o=r.host.trim().toLowerCase();o&&e.add(o.startsWith("*.")?o.slice(1):o)}return[...e]}s(clusterPageHosts,"clusterPageHosts"),i(clusterPageHosts,"clusterPageHosts");export function withBridgeAllowedOrigins(t,e){const r=[...new Set([...(t??"").split(/[\s,]+/).filter(Boolean),...e])];return r.length>0?r.join(","):void 0}s(withBridgeAllowedOrigins,"withBridgeAllowedOrigins"),i(withBridgeAllowedOrigins,"withBridgeAllowedOrigins");export function readClusterPageDecls(t){const e=[];for(const r of t)try{const o=JSON.parse(l(r,"utf8")),n=o.cluster??o.davnx;n&&typeof n=="object"&&e.push(n)}catch{}return e}s(readClusterPageDecls,"readClusterPageDecls"),i(readClusterPageDecls,"readClusterPageDecls");
|
package/lib/call-command.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var K=Object.defineProperty;var y=(e,t)=>K(e,"name",{value:t,configurable:!0});var
|
|
2
|
-
`);const L=new Set(["GET","HEAD","POST","PUT","PATCH","DELETE","OPTIONS"]),te=/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/,R={"x-lensmcp-act":"the call presents its own ticket",authorization:"the ticket says who you are \u2014 the gateway puts the browser's token on the request, or stamps the identity","x-lensmcp-flow-id":"the call names its own flow (verify-call-\u2026), so the lens files it as a verify flow",host:"the host is the URL's","content-length":"it is computed from --data","transfer-encoding":"it is computed from --data",connection:"the call opens one connection and closes it"};export function parseCallArgs(e){const t={who:!1,method:"",headers:[],json:!1,maxBody:DEFAULT_MAX_BODY,timeoutMs:DEFAULT_CALL_TIMEOUT_MS},r=[];let o;for(let u=0;u<e.length;u++){const d=e[u],h=l((...s)=>s.find(i=>d===i||d.startsWith(`${i}=`)),"named"),m=l(s=>d===s?e[++u]:d.slice(s.length+1),"valueOf");let a;if(d==="--who")t.who=!0;else if(d==="--json")t.json=!0;else if(a=h("--data","-d")){const s=m(a);if(s===void 0||s==="")return{error:`${a} needs a value: JSON text, or @<file>`};t.data=s}else if(a=h("--header","-H")){const s=m(a),i=s?.indexOf(":")??-1;if(!s||i<=0)return{error:`${a} needs 'name: value'`};const w=s.slice(0,i).trim().toLowerCase(),k=s.slice(i+1).trim();if(!te.test(w)||/[\r\n]/.test(k))return{error:`not a header: '${s}'`};if(R[w])return{error:`-H ${w}: ${R[w]}`};t.headers.push([w,k])}else if(a=h("--request","-X")){const s=m(a)?.trim().toUpperCase();if(!s||!L.has(s))return{error:`${a} needs a method: ${[...L].join(", ")}`};o=s}else if(a=h("--max-body")){const s=Number(m(a));if(!Number.isInteger(s)||s<=0)return{error:"--max-body needs a number of bytes"};t.maxBody=s}else if(a=h("--timeout")){const s=Number(m(a));if(!Number.isFinite(s)||s<=0)return{error:"--timeout needs a number of seconds"};t.timeoutMs=Math.round(s*1e3)}else if(a=h("--as","--tenant","--worktree","--workspace","--cwd")){const s=m(a)?.trim();if(!s)return{error:`${a} needs a value`};t[a.slice(2)]=s}else{if(d.startsWith("-"))return{error:`unknown option ${d}`};d.trim()&&r.push(d.trim())}}if(t.worktree&&t.workspace)return{error:"--worktree or --workspace, not both"};if(t.who)return r.length||t.data!==void 0||t.headers.length||o?{error:"--who lists who can be acted as; it calls nothing"}:t;if(r.length>2)return{error:`one request at a time: [METHOD] <url> (got ${r.map(u=>`'${u}'`).join(" ")})`};if(r.length===2){const u=r[0].toUpperCase();if(!L.has(u))return{error:`'${r[0]}' is not a method: ${[...L].join(", ")}`};if(o&&o!==u)return{error:`two methods: ${u} and ${o}`};o=u}const n=r[r.length-1];if(!n||r.length===1&&L.has(n.toUpperCase())&&!n.includes("/"))return{error:"name the URL: https://<app host>/<path>"};const $=M(n);return"error"in $?$:(t.url=$.href,t.method=o??(t.data!==void 0?"POST":"GET"),t.data!==void 0&&(t.method==="GET"||t.method==="HEAD")?{error:`a ${t.method} carries no body \u2014 POST, PUT or PATCH it`}:t)}y(parseCallArgs,"parseCallArgs"),g(parseCallArgs,"parseCallArgs"),l(parseCallArgs,"parseCallArgs");function M(e){if(e.startsWith("/"))return{error:`name the host too: https://<app host>${e}`};const t=/^[a-z][a-z0-9+.-]*:\/\//i.test(e)?e:`https://${e}`;let r;try{r=new URL(t)}catch{return{error:`not a URL: '${e}'`}}return r.protocol!=="https:"?{error:`the dev gateway serves HTTPS \u2014 call https://${r.host}${r.pathname}${r.search}`}:r.username||r.password?{error:"the ticket says who you are \u2014 leave credentials out of the URL"}:r}y(M,"I"),g(M,"Y"),l(M,"toUrl");export const IDENTITY_MODE_CAVEAT="Identity mode: the browser's token had expired, so no bearer rode along \u2014 the gateway stamped the identity it verified (x-user-id, x-tenant-id, roles). A service that reads the raw bearer itself (forwards it, decodes its `typ`, reads its `sid`) can fail here where the browser's request would not: open the app in the browser once to refresh the token (FoodGuard's access token lives 15 minutes), or rely on identity mode only for routes that read the gateway's identity headers.";const re={token:"token \u2014 the browser's own token rode along, verified and stamped as the browser's request was",identity:"identity \u2014 the gateway stamped the identity it verified; no bearer rode along"};export function identityLine(e){const t=e.name&&e.email?`${e.name} <${e.email}>`:e.name??e.email,r=[`user ${e.user}`,...e.tenant?[`tenant ${e.tenant}`]:[],...e.roles?.length?[`roles ${e.roles.join(", ")}`]:[]].join(", ");return t?`${t} (${r})`:r}y(identityLine,"identityLine"),g(identityLine,"identityLine"),l(identityLine,"identityLine");const se=l(e=>{const t=Math.max(0,Math.round(e/1e3));return t<60?`${t}s ago`:t<3600?`${Math.round(t/60)}m ago`:t<86400?`${Math.round(t/3600)}h ago`:`${Math.round(t/86400)}d ago`},"ago");function N(e,t){return e.map(r=>` ${identityLine(r)} \xB7 ${r.host} \xB7 seen ${se(t-r.lastSeenAt)} \xB7 ${r.mode}`)}y(N,"N"),g(N,"U"),l(N,"identitiesLines");export function verifyFlowId(){return`verify-call-${W(4).toString("hex")}`}y(verifyFlowId,"verifyFlowId"),g(verifyFlowId,"verifyFlowId"),l(verifyFlowId,"verifyFlowId");export async function runCallCommand(e,t){const r=ee(e,t.here),o=r===t.here.key?"this workspace":`'${r}'`,n=r===t.here.key?"this workspace's":`${r}'s`,$=l(()=>({exitCode:2,lines:["No gateway answers on the control socket \u2014 nothing is serving the app. Start it: `lensmcp gateway start`."],result:{error:"no gateway answers \u2014 start it: lensmcp gateway start",wsKey:r}}),"unavailable"),u=l((f,c)=>{const b=c&&typeof c=="object"?c:{},O=typeof b.error=="string"?b.error:`the gateway answered ${f}`;if(f===501){const x="Acting as a signed-in user is turned off on this gateway (LENSMCP_GW_ACT=0) \u2014 start it without that to call the app as someone who signed in.";return{exitCode:1,lines:[x],result:{error:x,wsKey:r}}}if(Array.isArray(b.identities)){const x=b.identities,B=[`Could not act as ${e.as?`'${e.as}'`:"anyone"}${e.tenant?` in tenant '${e.tenant}'`:""} in ${o}: ${O}`];return x.length&&B.push("Who signed in (most recent first):",...N(x,t.now()),"Name one: --as <user id|email|name> [--tenant <id>]."),{exitCode:1,lines:B,result:{error:O,wsKey:r,identities:x}}}if(Array.isArray(b.workspaces))return{exitCode:1,lines:[`${O}.`,`Workspaces the gateway serves: ${b.workspaces.join(", ")||"none"}.`],result:{error:O,wsKey:r,workspaces:b.workspaces}};if(f===404){const x="The running gateway does not know `POST /act` \u2014 it predates `lensmcp call`. Restart it on this version: `lensmcp gateway restart`.";return{exitCode:1,lines:[x],result:{error:x,wsKey:r}}}return{exitCode:1,lines:[`The gateway refused: ${O}.`],result:{error:O,wsKey:r}}},"refused");if(e.who){const f=t.request("GET",`/identities?wsKey=${encodeURIComponent(r)}`);if(!f)return $();if(f.status!==200)return u(f.status,f.json);const c=f.json?.identities??[];return{exitCode:0,lines:c.length?[`${c.length===1?"One person":`${c.length} people`} signed in to ${n} app (most recent first):`,...N(c,t.now()),"Act as one: lensmcp call <url> --as <user id|email|name> [--tenant <id>]."]:[`No one has signed in to ${n} app since the gateway started remembering identities. Sign in once in the browser \u2014 the gateway keeps the identity it verified for 30 days.`],result:{wsKey:r,identities:c}}}let d;if(e.data!==void 0){const f=e.data.startsWith("@");try{d=f?t.readFile(e.data.slice(1)):e.data}catch(c){const b=`--data ${e.data}: ${c.message}`;return{exitCode:2,lines:[b],result:{error:b}}}if(!e.headers.some(([c])=>c==="content-type"))try{JSON.parse(d)}catch{const c=`--data${f?` ${e.data}`:""} is not JSON \u2014 send JSON, or name its type: -H 'content-type: <type>'`;return{exitCode:2,lines:[c],result:{error:c}}}}const h=t.request("POST","/act",{wsKey:r,...e.as?{user:e.as}:{},...e.tenant?{tenant:e.tenant}:{}});if(!h)return $();if(h.status!==200)return u(h.status,h.json);const m=h.json;if(typeof m?.ticket!="string"||!m.identity)return u(h.status,{error:"the gateway answered without a ticket"});const a=m.identity,s=a.mode,i=(t.flowId??verifyFlowId)(),w=e.url,k={accept:"application/json, */*;q=0.5","user-agent":"lensmcp-call",...d!==void 0?{"content-type":"application/json"}:{},...Object.fromEntries(e.headers),"x-lensmcp-act":m.ticket,"x-lensmcp-flow-id":i},T={method:e.method,url:w,wsKey:r,as:a,mode:s,flowId:i},E=s==="identity"?{caveat:IDENTITY_MODE_CAVEAT}:{},C=t.now();let p;try{p=await t.send({method:e.method,url:w,headers:k,...d!==void 0?{body:d}:{},timeoutMs:e.timeoutMs,maxBody:e.maxBody})}catch(f){const c=`The request did not complete: ${U(f,new URL(w),e.timeoutMs)}`;return{exitCode:3,lines:[c],result:{error:c,...T,...E}}}const _=t.now()-C,v=l(f=>{const c=p.headers[f];return Array.isArray(c)?c[0]:c},"h"),j=v("content-type"),S=v("x-request-id"),A=P(p.body,j,p.truncated),F={status:p.status,ms:_,...T,...S?{requestId:S}:{},headers:{...j?{"content-type":j}:{},...v("location")?{location:v("location")}:{},...v("x-trace-id")?{"x-trace-id":v("x-trace-id")}:{}},body:A,...p.truncated?{truncated:!0}:{},...E},I=p.statusText||V[p.status]||"";return{exitCode:0,lines:[`${p.status}${I?` ${I}`:""} \xB7 ${e.method} ${w} \xB7 ${_} ms`,`as ${identityLine(a)}${r===t.here.key?"":` \u2014 in ${r}`}`,`mode ${re[s]}`,`flow ${i} \u2014 what it did: flow_get { flowId: "${i}" }${S?` \xB7 request ${S}`:""}`,...v("location")?[`location ${v("location")} (not followed)`]:[],...s==="identity"?[IDENTITY_MODE_CAVEAT]:[],...p.status===401&&/act ticket/.test(p.body.toString("utf8"))?[`The gateway refused the ticket: it was for ${r}, and ${new URL(w).hostname} may be another workspace's host \u2014 a worktree's hosts carry its name (app.<name>.<project>.localhost); name the workspace with --worktree or --workspace.`]:[],"",A===null?"(no body)":typeof A=="string"?A:JSON.stringify(A,null,2),...p.truncated?[`\u2026 cut at ${e.maxBody} bytes (--max-body raises it)`]:[]],result:F}}y(runCallCommand,"runCallCommand"),g(runCallCommand,"runCallCommand"),l(runCallCommand,"runCallCommand");function P(e,t,r){if(e.length===0)return null;const o=(t??"").toLowerCase();if(!(!o||/json|^text\/|xml|javascript|x-www-form-urlencoded|csv|yaml|graphql/.test(o)))return`\u2039${e.length}${r?"+":""} bytes of ${o.split(";")[0]} \u2014 not shown\u203A`;const n=e.toString("utf8");if(!r&&(/json/.test(o)||/^\s*[[{]/.test(n)))try{return JSON.parse(n)}catch{}return n}y(P,"B"),g(P,"Z"),l(P,"bodyOf");function U(e,t,r){const o=t.hostname,n=e.code??"";return n==="LENSMCP_NOT_LOOPBACK"?e.message:n==="LENSMCP_TIMEOUT"?`no answer within ${Math.round(r/100)/10}s (--timeout raises it).`:n==="ECONNREFUSED"?`nothing listens on ${t.host} \u2014 is the gateway serving it? \`lensmcp gateway status\` lists its hosts.`:n==="ENOTFOUND"||n==="EAI_AGAIN"?`${o} does not resolve \u2014 \`lensmcp trust\` writes the app's hosts into /etc/hosts.`:/CERT|SELF_SIGNED|UNABLE_TO_VERIFY|ALTNAME/.test(n)?`${o}'s certificate does not chain to the lensmcp CA (${lensCaPath()}): ${e.message}. \`lensmcp trust\` mints and trusts it.`:`${e.message}${n&&!e.message.includes(n)?` (${n})`:""}.`}y(U,"q"),g(U,"Q"),l(U,"transportReason");export function lensCaPath(e=process.env){return Q(e.LENSMCP_HOME||Z(),".lensmcp","ca","lensmcp-local-ca.crt")}y(lensCaPath,"lensCaPath"),g(lensCaPath,"lensCaPath"),l(lensCaPath,"lensCaPath");export function isLoopbackAddress(e){const t=e.startsWith("::ffff:")?e.slice(7):e;return t==="::1"||/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(t)}y(isLoopbackAddress,"isLoopbackAddress"),g(isLoopbackAddress,"isLoopbackAddress"),l(isLoopbackAddress,"isLoopbackAddress");const oe=l((e,t)=>J(e,{all:!0},(r,o)=>t(r,o??[])),"systemResolver"),D=l((e,t)=>Object.assign(new Error(`${e} resolves to ${t}, not this machine \u2014 lensmcp call only calls the dev gateway here (the ticket never leaves it).`),{code:"LENSMCP_NOT_LOOPBACK"}),"notLoopback");export function loopbackLookup(e=oe){return((t,r,o)=>{e(t,(n,$)=>{if(n)return o(n,"",0);const u=$.find(h=>!isLoopbackAddress(h.address)),d=$[0];return u||!d?o(D(t,u?.address??"no address"),"",0):r?.all?o(null,$):o(null,d.address,d.family)})})}y(loopbackLookup,"loopbackLookup"),g(loopbackLookup,"loopbackLookup"),l(loopbackLookup,"loopbackLookup");export function httpsCall(e,t={}){const r=new URL(e.url),o=r.hostname.replace(/^\[|\]$/g,"");if(q(o)&&!isLoopbackAddress(o))return Promise.reject(D(o,o));const n=lensCaPath(),$=t.ca??(z(n)?Y(n):void 0);return new Promise((u,d)=>{let h=!1;const m=l(i=>{h||(h=!0,clearTimeout(s),i())},"finish"),a=X({hostname:o,port:r.port?Number(r.port):443,path:`${r.pathname}${r.search}`,method:e.method,headers:{...e.headers,...e.body!==void 0?{"content-length":String(Buffer.byteLength(e.body))}:{}},...q(o)?{}:{servername:o},...$?{ca:$}:{},lookup:loopbackLookup(t.resolve),agent:!1}),s=setTimeout(()=>a.destroy(Object.assign(new Error("timed out"),{code:"LENSMCP_TIMEOUT"})),e.timeoutMs);a.on("error",i=>m(()=>d(i))),a.on("response",i=>{const w=[];let k=0,T=!1;const E=l(()=>({status:i.statusCode??0,...i.statusMessage?{statusText:i.statusMessage}:{},headers:i.headers,body:Buffer.concat(w),truncated:T}),"answer");i.on("data",C=>{if(T)return;const p=e.maxBody-k;if(C.length>p){w.push(C.subarray(0,p)),k+=p,T=!0,m(()=>u(E())),i.destroy();return}w.push(C),k+=C.length}),i.on("end",()=>m(()=>u(E()))),i.on("error",C=>m(()=>d(C)))}),a.end(e.body)})}y(httpsCall,"httpsCall"),g(httpsCall,"httpsCall"),l(httpsCall,"httpsCall");
|
|
1
|
+
"use strict";var K=Object.defineProperty;var y=(e,t)=>K(e,"name",{value:t,configurable:!0});var F=Object.defineProperty,l=y((e,t)=>F(e,"name",{value:t,configurable:!0}),"u");import{randomBytes as H}from"node:crypto";import{lookup as G}from"node:dns";import{existsSync as W,readFileSync as J}from"node:fs";import{STATUS_CODES as z}from"node:http";import{request as Y}from"node:https";import{isIP as U}from"node:net";import{homedir as V}from"node:os";import{join as X}from"node:path";import{targetKey as Z}from"./restart-command.js";export const DEFAULT_MAX_BODY=64*1024,DEFAULT_CALL_TIMEOUT_MS=3e4,CALL_USAGE=["lensmcp call [METHOD] <url> call this workspace's app as the person who most recently signed in to it in the browser"," --data <json> | --data @<file> a JSON body (the method defaults to POST)"," -H '<name>: <value>' a request header (repeatable)"," --as <user id|email|name> --tenant <id> whom to act as"," --worktree <name> | --workspace <key> \u2026 of a worktree of this project (`main`: the main checkout), or any workspace"," --json --max-body <bytes> (default 65536) --timeout <seconds> (default 30) --cwd <dir>","lensmcp call --who [--json] who can be acted as: the people who signed in to the app"].join(`
|
|
2
|
+
`);const E=new Set(["GET","HEAD","POST","PUT","PATCH","DELETE","OPTIONS"]),Q=/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/,_={"x-lensmcp-act":"the call presents its own ticket",authorization:"the ticket says who you are \u2014 the gateway puts the browser's token on the request, or stamps the identity","x-lensmcp-flow-id":"the call names its own flow (verify-call-\u2026), so the lens files it as a verify flow",host:"the host is the URL's","content-length":"it is computed from --data","transfer-encoding":"it is computed from --data",connection:"the call opens one connection and closes it"};export function parseCallArgs(e){const t={who:!1,method:"",headers:[],json:!1,maxBody:DEFAULT_MAX_BODY,timeoutMs:DEFAULT_CALL_TIMEOUT_MS},s=[];let o;for(let u=0;u<e.length;u++){const d=e[u],h=l((...r)=>r.find(i=>d===i||d.startsWith(`${i}=`)),"named"),m=l(r=>d===r?e[++u]:d.slice(r.length+1),"valueOf");let a;if(d==="--who")t.who=!0;else if(d==="--json")t.json=!0;else if(a=h("--data","-d")){const r=m(a);if(r===void 0||r==="")return{error:`${a} needs a value: JSON text, or @<file>`};t.data=r}else if(a=h("--header","-H")){const r=m(a),i=r?.indexOf(":")??-1;if(!r||i<=0)return{error:`${a} needs 'name: value'`};const w=r.slice(0,i).trim().toLowerCase(),b=r.slice(i+1).trim();if(!Q.test(w)||/[\r\n]/.test(b))return{error:`not a header: '${r}'`};if(_[w])return{error:`-H ${w}: ${_[w]}`};t.headers.push([w,b])}else if(a=h("--request","-X")){const r=m(a)?.trim().toUpperCase();if(!r||!E.has(r))return{error:`${a} needs a method: ${[...E].join(", ")}`};o=r}else if(a=h("--max-body")){const r=Number(m(a));if(!Number.isInteger(r)||r<=0)return{error:"--max-body needs a number of bytes"};t.maxBody=r}else if(a=h("--timeout")){const r=Number(m(a));if(!Number.isFinite(r)||r<=0)return{error:"--timeout needs a number of seconds"};t.timeoutMs=Math.round(r*1e3)}else if(a=h("--as","--tenant","--worktree","--workspace","--cwd")){const r=m(a)?.trim();if(!r)return{error:`${a} needs a value`};t[a.slice(2)]=r}else{if(d.startsWith("-"))return{error:`unknown option ${d}`};d.trim()&&s.push(d.trim())}}if(t.worktree&&t.workspace)return{error:"--worktree or --workspace, not both"};if(t.who)return s.length||t.data!==void 0||t.headers.length||o?{error:"--who lists who can be acted as; it calls nothing"}:t;if(s.length>2)return{error:`one request at a time: [METHOD] <url> (got ${s.map(u=>`'${u}'`).join(" ")})`};if(s.length===2){const u=s[0].toUpperCase();if(!E.has(u))return{error:`'${s[0]}' is not a method: ${[...E].join(", ")}`};if(o&&o!==u)return{error:`two methods: ${u} and ${o}`};o=u}const n=s[s.length-1];if(!n||s.length===1&&E.has(n.toUpperCase())&&!n.includes("/"))return{error:"name the URL: https://<app host>/<path>"};const $=I(n);return"error"in $?$:(t.url=$.href,t.method=o??(t.data!==void 0?"POST":"GET"),t.data!==void 0&&(t.method==="GET"||t.method==="HEAD")?{error:`a ${t.method} carries no body \u2014 POST, PUT or PATCH it`}:t)}y(parseCallArgs,"parseCallArgs"),l(parseCallArgs,"parseCallArgs");function I(e){if(e.startsWith("/"))return{error:`name the host too: https://<app host>${e}`};const t=/^[a-z][a-z0-9+.-]*:\/\//i.test(e)?e:`https://${e}`;let s;try{s=new URL(t)}catch{return{error:`not a URL: '${e}'`}}return s.protocol!=="https:"?{error:`the dev gateway serves HTTPS \u2014 call https://${s.host}${s.pathname}${s.search}`}:s.username||s.password?{error:"the ticket says who you are \u2014 leave credentials out of the URL"}:s}y(I,"Y"),l(I,"toUrl");export const IDENTITY_MODE_CAVEAT="Identity mode: the browser's token had expired, so no bearer rode along \u2014 the gateway stamped the identity it verified (x-user-id, x-tenant-id, roles). A service that reads the raw bearer itself (forwards it, decodes its `typ`, reads its `sid`) can fail here where the browser's request would not: open the app in the browser once to refresh the token (FoodGuard's access token lives 15 minutes), or rely on identity mode only for routes that read the gateway's identity headers.";const ee={token:"token \u2014 the browser's own token rode along, verified and stamped as the browser's request was",identity:"identity \u2014 the gateway stamped the identity it verified; no bearer rode along"};export function identityLine(e){const t=e.name&&e.email?`${e.name} <${e.email}>`:e.name??e.email,s=[`user ${e.user}`,...e.tenant?[`tenant ${e.tenant}`]:[],...e.roles?.length?[`roles ${e.roles.join(", ")}`]:[]].join(", ");return t?`${t} (${s})`:s}y(identityLine,"identityLine"),l(identityLine,"identityLine");const te=l(e=>{const t=Math.max(0,Math.round(e/1e3));return t<60?`${t}s ago`:t<3600?`${Math.round(t/60)}m ago`:t<86400?`${Math.round(t/3600)}h ago`:`${Math.round(t/86400)}d ago`},"ago");function N(e,t){return e.map(s=>` ${identityLine(s)} \xB7 ${s.host} \xB7 seen ${te(t-s.lastSeenAt)} \xB7 ${s.mode}`)}y(N,"U"),l(N,"identitiesLines");export function verifyFlowId(){return`verify-call-${H(4).toString("hex")}`}y(verifyFlowId,"verifyFlowId"),l(verifyFlowId,"verifyFlowId");export async function runCallCommand(e,t){const s=Z(e,t.here),o=s===t.here.key?"this workspace":`'${s}'`,n=s===t.here.key?"this workspace's":`${s}'s`,$=l(()=>({exitCode:2,lines:["No gateway answers on the control socket \u2014 nothing is serving the app. Start it: `lensmcp gateway start`."],result:{error:"no gateway answers \u2014 start it: lensmcp gateway start",wsKey:s}}),"unavailable"),u=l((f,c)=>{const g=c&&typeof c=="object"?c:{},C=typeof g.error=="string"?g.error:`the gateway answered ${f}`;if(f===501){const x="Acting as a signed-in user is turned off on this gateway (LENSMCP_GW_ACT=0) \u2014 start it without that to call the app as someone who signed in.";return{exitCode:1,lines:[x],result:{error:x,wsKey:s}}}if(Array.isArray(g.identities)){const x=g.identities,P=[`Could not act as ${e.as?`'${e.as}'`:"anyone"}${e.tenant?` in tenant '${e.tenant}'`:""} in ${o}: ${C}`];return x.length&&P.push("Who signed in (most recent first):",...N(x,t.now()),"Name one: --as <user id|email|name> [--tenant <id>]."),{exitCode:1,lines:P,result:{error:C,wsKey:s,identities:x}}}if(Array.isArray(g.workspaces))return{exitCode:1,lines:[`${C}.`,`Workspaces the gateway serves: ${g.workspaces.join(", ")||"none"}.`],result:{error:C,wsKey:s,workspaces:g.workspaces}};if(f===404){const x="The running gateway does not know `POST /act` \u2014 it predates `lensmcp call`. Restart it on this version: `lensmcp gateway restart`.";return{exitCode:1,lines:[x],result:{error:x,wsKey:s}}}return{exitCode:1,lines:[`The gateway refused: ${C}.`],result:{error:C,wsKey:s}}},"refused");if(e.who){const f=t.request("GET",`/identities?wsKey=${encodeURIComponent(s)}`);if(!f)return $();if(f.status!==200)return u(f.status,f.json);const c=f.json?.identities??[];return{exitCode:0,lines:c.length?[`${c.length===1?"One person":`${c.length} people`} signed in to ${n} app (most recent first):`,...N(c,t.now()),"Act as one: lensmcp call <url> --as <user id|email|name> [--tenant <id>]."]:[`No one has signed in to ${n} app since the gateway started remembering identities. Sign in once in the browser \u2014 the gateway keeps the identity it verified for 30 days.`],result:{wsKey:s,identities:c}}}let d;if(e.data!==void 0){const f=e.data.startsWith("@");try{d=f?t.readFile(e.data.slice(1)):e.data}catch(c){const g=`--data ${e.data}: ${c.message}`;return{exitCode:2,lines:[g],result:{error:g}}}if(!e.headers.some(([c])=>c==="content-type"))try{JSON.parse(d)}catch{const c=`--data${f?` ${e.data}`:""} is not JSON \u2014 send JSON, or name its type: -H 'content-type: <type>'`;return{exitCode:2,lines:[c],result:{error:c}}}}const h=t.request("POST","/act",{wsKey:s,...e.as?{user:e.as}:{},...e.tenant?{tenant:e.tenant}:{}});if(!h)return $();if(h.status!==200)return u(h.status,h.json);const m=h.json;if(typeof m?.ticket!="string"||!m.identity)return u(h.status,{error:"the gateway answered without a ticket"});const a=m.identity,r=a.mode,i=(t.flowId??verifyFlowId)(),w=e.url,b={accept:"application/json, */*;q=0.5","user-agent":"lensmcp-call",...d!==void 0?{"content-type":"application/json"}:{},...Object.fromEntries(e.headers),"x-lensmcp-act":m.ticket,"x-lensmcp-flow-id":i},T={method:e.method,url:w,wsKey:s,as:a,mode:r,flowId:i},O=r==="identity"?{caveat:IDENTITY_MODE_CAVEAT}:{},k=t.now();let p;try{p=await t.send({method:e.method,url:w,headers:b,...d!==void 0?{body:d}:{},timeoutMs:e.timeoutMs,maxBody:e.maxBody})}catch(f){const c=`The request did not complete: ${q(f,new URL(w),e.timeoutMs)}`;return{exitCode:3,lines:[c],result:{error:c,...T,...O}}}const j=t.now()-k,v=l(f=>{const c=p.headers[f];return Array.isArray(c)?c[0]:c},"h"),L=v("content-type"),S=v("x-request-id"),A=B(p.body,L,p.truncated),D={status:p.status,ms:j,...T,...S?{requestId:S}:{},headers:{...L?{"content-type":L}:{},...v("location")?{location:v("location")}:{},...v("x-trace-id")?{"x-trace-id":v("x-trace-id")}:{}},body:A,...p.truncated?{truncated:!0}:{},...O},M=p.statusText||z[p.status]||"";return{exitCode:0,lines:[`${p.status}${M?` ${M}`:""} \xB7 ${e.method} ${w} \xB7 ${j} ms`,`as ${identityLine(a)}${s===t.here.key?"":` \u2014 in ${s}`}`,`mode ${ee[r]}`,`flow ${i} \u2014 what it did: flow_get { flowId: "${i}" }${S?` \xB7 request ${S}`:""}`,...v("location")?[`location ${v("location")} (not followed)`]:[],...r==="identity"?[IDENTITY_MODE_CAVEAT]:[],...p.status===401&&/act ticket/.test(p.body.toString("utf8"))?[`The gateway refused the ticket: it was for ${s}, and ${new URL(w).hostname} may be another workspace's host \u2014 a worktree's hosts carry its name (app.<name>.<project>.localhost); name the workspace with --worktree or --workspace.`]:[],"",A===null?"(no body)":typeof A=="string"?A:JSON.stringify(A,null,2),...p.truncated?[`\u2026 cut at ${e.maxBody} bytes (--max-body raises it)`]:[]],result:D}}y(runCallCommand,"runCallCommand"),l(runCallCommand,"runCallCommand");function B(e,t,s){if(e.length===0)return null;const o=(t??"").toLowerCase();if(!(!o||/json|^text\/|xml|javascript|x-www-form-urlencoded|csv|yaml|graphql/.test(o)))return`\u2039${e.length}${s?"+":""} bytes of ${o.split(";")[0]} \u2014 not shown\u203A`;const n=e.toString("utf8");if(!s&&(/json/.test(o)||/^\s*[[{]/.test(n)))try{return JSON.parse(n)}catch{}return n}y(B,"Z"),l(B,"bodyOf");function q(e,t,s){const o=t.hostname,n=e.code??"";return n==="LENSMCP_NOT_LOOPBACK"?e.message:n==="LENSMCP_TIMEOUT"?`no answer within ${Math.round(s/100)/10}s (--timeout raises it).`:n==="ECONNREFUSED"?`nothing listens on ${t.host} \u2014 is the gateway serving it? \`lensmcp gateway status\` lists its hosts.`:n==="ENOTFOUND"||n==="EAI_AGAIN"?`${o} does not resolve \u2014 \`lensmcp trust\` writes the app's hosts into /etc/hosts.`:/CERT|SELF_SIGNED|UNABLE_TO_VERIFY|ALTNAME/.test(n)?`${o}'s certificate does not chain to the lensmcp CA (${lensCaPath()}): ${e.message}. \`lensmcp trust\` mints and trusts it.`:`${e.message}${n&&!e.message.includes(n)?` (${n})`:""}.`}y(q,"Q"),l(q,"transportReason");export function lensCaPath(e=process.env){return X(e.LENSMCP_HOME||V(),".lensmcp","ca","lensmcp-local-ca.crt")}y(lensCaPath,"lensCaPath"),l(lensCaPath,"lensCaPath");export function isLoopbackAddress(e){const t=e.startsWith("::ffff:")?e.slice(7):e;return t==="::1"||/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(t)}y(isLoopbackAddress,"isLoopbackAddress"),l(isLoopbackAddress,"isLoopbackAddress");const se=l((e,t)=>G(e,{all:!0},(s,o)=>t(s,o??[])),"systemResolver"),R=l((e,t)=>Object.assign(new Error(`${e} resolves to ${t}, not this machine \u2014 lensmcp call only calls the dev gateway here (the ticket never leaves it).`),{code:"LENSMCP_NOT_LOOPBACK"}),"notLoopback");export function loopbackLookup(e=se){return((t,s,o)=>{e(t,(n,$)=>{if(n)return o(n,"",0);const u=$.find(h=>!isLoopbackAddress(h.address)),d=$[0];return u||!d?o(R(t,u?.address??"no address"),"",0):s?.all?o(null,$):o(null,d.address,d.family)})})}y(loopbackLookup,"loopbackLookup"),l(loopbackLookup,"loopbackLookup");export function httpsCall(e,t={}){const s=new URL(e.url),o=s.hostname.replace(/^\[|\]$/g,"");if(U(o)&&!isLoopbackAddress(o))return Promise.reject(R(o,o));const n=lensCaPath(),$=t.ca??(W(n)?J(n):void 0);return new Promise((u,d)=>{let h=!1;const m=l(i=>{h||(h=!0,clearTimeout(r),i())},"finish"),a=Y({hostname:o,port:s.port?Number(s.port):443,path:`${s.pathname}${s.search}`,method:e.method,headers:{...e.headers,...e.body!==void 0?{"content-length":String(Buffer.byteLength(e.body))}:{}},...U(o)?{}:{servername:o},...$?{ca:$}:{},lookup:loopbackLookup(t.resolve),agent:!1}),r=setTimeout(()=>a.destroy(Object.assign(new Error("timed out"),{code:"LENSMCP_TIMEOUT"})),e.timeoutMs);a.on("error",i=>m(()=>d(i))),a.on("response",i=>{const w=[];let b=0,T=!1;const O=l(()=>({status:i.statusCode??0,...i.statusMessage?{statusText:i.statusMessage}:{},headers:i.headers,body:Buffer.concat(w),truncated:T}),"answer");i.on("data",k=>{if(T)return;const p=e.maxBody-b;if(k.length>p){w.push(k.subarray(0,p)),b+=p,T=!0,m(()=>u(O())),i.destroy();return}w.push(k),b+=k.length}),i.on("end",()=>m(()=>u(O()))),i.on("error",k=>m(()=>d(k)))}),a.end(e.body)})}y(httpsCall,"httpsCall"),l(httpsCall,"httpsCall");
|
package/lib/cli-help.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
`);let
|
|
3
|
-
`).replace(/\s+$/,"")}
|
|
1
|
+
"use strict";var g=Object.defineProperty;var o=(t,e)=>g(t,"name",{value:e,configurable:!0});var h=Object.defineProperty,r=o((t,e)=>h(t,"name",{value:e,configurable:!0}),"r");const k=new Set(["rollout","instance","instances"]);export function wantsHelp(t,e){const s=e!==void 0&&k.has(e);for(const n of t){if(s&&n==="--")break;if(n==="--help"||n==="-h")return!0}return!1}o(wantsHelp,"wantsHelp"),r(wantsHelp,"wantsHelp");const d={plugins:"plugin"};function f(t){return/^ {2}\S/.test(t)}o(f,"l"),r(f,"opensBlock");export function commandUsage(t,e){const s=d[e]??e,n=t.split(`
|
|
2
|
+
`);let u=-1;for(let i=0;i<n.length;i++){if(!f(n[i]))continue;const a=n[i].slice(2);if(a===s||a.startsWith(`${s} `)){u=i;break}}if(u===-1)return;let c=u+1;for(;c<n.length&&!f(n[c]);)c++;return["Usage:",...n.slice(u,c)].join(`
|
|
3
|
+
`).replace(/\s+$/,"")}o(commandUsage,"commandUsage"),r(commandUsage,"commandUsage");export function ignoreEpipe(t){t.on("error",e=>{if(e?.code==="EPIPE"){p=!0;for(const s of l)try{s()}catch{}return}throw e})}o(ignoreEpipe,"ignoreEpipe"),r(ignoreEpipe,"ignoreEpipe");const l=new Set;export function onOutputBroken(t){if(p){t();return}l.add(t)}o(onOutputBroken,"onOutputBroken"),r(onOutputBroken,"onOutputBroken");let p=!1;export function isOutputBroken(){return p}o(isOutputBroken,"isOutputBroken"),r(isOutputBroken,"isOutputBroken");export function resetOutputBrokenForTests(){p=!1}o(resetOutputBrokenForTests,"resetOutputBrokenForTests"),r(resetOutputBrokenForTests,"resetOutputBrokenForTests");
|