@membranehq/cli 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +58 -44
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,37 +1,51 @@
1
1
  #!/usr/bin/env node
2
- var nr=Object.defineProperty;var c=(r,e)=>nr(r,"name",{value:e,configurable:!0});import*as v from"node:fs";import{mkdirSync as rr,writeFileSync as or,readFileSync as ir}from"node:fs";import*as x from"node:path";import{join as Ge,dirname as sr}from"node:path";import{URL as ar,fileURLToPath as cr}from"node:url";import m from"chalk";import{Command as lr}from"commander";import{NotFoundError as ur,MembraneConfigLoader as dr,MembraneAxiosInstance as hr,MembraneClient as Gt,extractMembraneErrorData as z,parseMembraneElementPath as ue,getConnectorSpecPath as pr,getConnectorVersionPath as Vt,CONNECTOR_VERSION_DEVELOPMENT as Ve,WorkspaceElementType as I,getMembraneElementPath as fr,compareWorkspaceExports as Yt,WorkspaceElementSpecs as Z,WorkspaceSyncEventType as mr,ConnectorFileUpdateType as Ye,CONSOLE_ACCOUNT_API_TOKEN_PATH as gr,MEMBRANE_CLI_CLIENT_ID as Ze,OAUTH_SCOPE_PLATFORM_USER as yr,WorkspaceElementChangeType as X,setValueAtLocator as Xe,getDataCollectionCreateFields as Qe,excludeWriteOnlyFieldsFromSchema as Zt,valueToSchema as Ne,getRequiredFieldsFromSchema as wr,getValueAtLocator as Cr,walkSchema as Xt,makeDataLocationPath as Qt,getDataCollectionUpdateFields as et}from"@membranehq/sdk";import xe from"ora";import Ie,{isAxiosError as Sr}from"axios";import en from"form-data";import A,{existsSync as Me,mkdirSync as tn,statSync as br,chmodSync as vr,readFileSync as nn,writeFileSync as Er}from"fs";import tt from"os";import k from"path";import Tr from"conf";import nt from"jsonwebtoken";import rt from"semver";import{AsyncLocalStorage as xr}from"async_hooks";import ot from"archiver";import H from"js-yaml";import rn from"jszip";import{minimatch as Ir}from"minimatch";import it from"lodash/camelCase.js";import st from"lodash/upperFirst.js";import kr from"code-block-writer";import $r from"lodash/uniqBy.js";import de,{createContext as at,useState as N,useEffect as we,useContext as ct,useId as Pr,useRef as lt,useLayoutEffect as Fe,useMemo as Ar}from"react";import{Box as y,Text as w,useInput as he,render as ut,Newline as Rr}from"ink";import{jsx as u,jsxs as b,Fragment as Le}from"react/jsx-runtime";import on from"swr/immutable";import{toSentenceCase as Or}from"js-convert-case";import Dr from"lodash/isEqual.js";import*as Nr from"node:crypto";import{createHash as Mr}from"node:crypto";import Fr from"chokidar";import Lr from"yaml";import{EventEmitter as jr}from"events";import{EventSource as Ur}from"eventsource";import je from"unzipper";import*as Kr from"node:os";import"node:events";import sn from"ink-text-input";import{SWRConfig as _r}from"swr";import{randomUUID as qr,randomBytes as an,createHash as Br}from"crypto";import{createServer as cn}from"http";import Ue from"ink-spinner";import{TextInput as Wr,Select as Jr,Spinner as zr}from"@inkjs/ui";import{FastMCP as Hr}from"fastmcp";import{z as D}from"zod";import{exec as Gr}from"node:child_process";import dt from"lodash/merge.js";import Vr from"@anthropic-ai/sdk";import{faker as ke}from"@faker-js/faker";import Yr from"lodash/template.js";import Zr from"lodash/templateSettings.js";const Xr="membrane",Qr=["**/node_modules/**","**/.git/**","**/.DS_Store","**/Thumbs.db","**/*.tmp","**/*.swp","**/*.swo","**/*.log","**/*.lock","**/.cache/**","**/.next/**","**/.vscode/**","**/.idea/**","**/.logs/**"];function q(r){return x.join(r,Xr)}c(q,"getMembraneDir");const ln=Ge(q(process.cwd()),".logs");class eo{static{c(this,"WorkspaceLogger")}_logs;verboseMode=!1;notificationHandler=null;constructor(){this._logs=[]}setNotificationHandler(e){this.notificationHandler=e}setVerboseMode(e){this.verboseMode=e}getVerboseMode(){return this.verboseMode}get logs(){return[...this._logs]}get latestLogs(){return this._logs.slice(this._logs.length-5)}log(e,t="info"){const n={timestamp:new Date().toISOString(),message:e,type:t};this._logs.push(n),this._logs=this._logs.slice(0,1e3),(t!=="debug"||this.verboseMode)&&this.notificationHandler&&this.notificationHandler.addLog(n)}info(e){this.log(e,"info")}success(e){this.log(e,"success")}warning(e){this.log(e,"warning")}error(e){this.log(e,"error")}debug(e){this.log(e,"debug")}clear(){this._logs=[]}saveLogsToFile(e){if(this._logs.length===0)return null;try{const t=new Date().toISOString().replace(/[:.]/g,"_"),n=e?`-${e}`:"",o=`${t}${n}.txt`;rr(ln,{recursive:!0});const i=Ge(ln,o),s=this._logs.map(a=>`[${a.timestamp}] ${a.type?.toUpperCase()||"INFO"}: ${a.message}`).join(`
3
- `);return or(i,s,"utf-8"),i}catch(t){return console.error("Failed to save logs:",t),null}}}const g=new eo;async function ht(r,e,t={}){const{jobId:n,accessKey:o}=await e(),i=`${n}:${o}`;g.debug(`[background-job] Started job ${n}`);const s=Date.now(),{pollIntervalMs:a=1e3,timeoutMs:l=3e5,maxRetries:d=3}=t;let h=0;for(;;){if(Date.now()-s>l)throw new Error(`Background job ${n} timed out after ${l}ms`);await new Promise(C=>setTimeout(C,a));let p;try{p=await r.get(`background-jobs/${i}`),h=0}catch(C){if(C instanceof ur&&h<d){h++,g.debug(`[background-job] Job ${n} not found, retrying (${h}/${d})`);continue}throw C}if(p.status==="completed"){if(g.debug(`[background-job] Completed job ${n}`),!p.result)throw new Error(`Background job ${n} completed but returned no result`);return p.result}if(p.status==="failed"){const C=p.error?.message||"Unknown error";throw g.error(`[background-job] Failed job ${n}: ${C}`),p.error?.stack&&g.error(`Stacktrace: ${p.error.stack}`),new Error(`Background job ${n} failed: ${C}`)}g.debug(`[background-job] Polling job ${n} (status: ${p.status})`)}}c(ht,"pollBackgroundJob");class Ke extends Error{static{c(this,"ApiError")}statusCode;errorType;errorKey;data;constructor(e,t){const n=to(t);if(n){const{message:o,type:i,key:s,...a}=n,l=typeof o=="string"?o:`API request failed (${e})`;super(l),this.errorType=typeof i=="string"?i:void 0,this.errorKey=typeof s=="string"?s:void 0,this.data=Object.keys(a).length>0?a:void 0}else super(t||`API request failed (${e})`);this.statusCode=e,this.name="ApiError"}format(){const e=[this.message];return this.data&&Object.keys(this.data).length>0&&e.push(JSON.stringify(this.data,null,2)),e.join(`
4
- `)}}function to(r){try{const e=JSON.parse(r);return typeof e=="object"&&e!==null?e:null}catch{return null}}c(to,"tryParseJson");class Ee{static{c(this,"ConfigLoader")}static instance=null;sdkLoader;constructor(){this.sdkLoader=new dr}static getInstance(){return Ee.instance||(Ee.instance=new Ee),Ee.instance}loadConfig(e){e&&e!==this.sdkLoader.getCwd()&&this.sdkLoader.setCwd(e);try{return this.sdkLoader.loadConfig({validate:!0})}catch(t){if(t.message?.includes("Failed to parse"))throw t;return null}}clearCache(){this.sdkLoader.clearCache()}updateConfig(e){return this.sdkLoader.updateConfig(e)}saveToFile(e){return this.sdkLoader.saveToFile(e)}isCacheDefined(){return this.sdkLoader.hasValidConfig()}}const pe=Ee.getInstance();function $e(r){return pe.loadConfig(r)}c($e,"readProjectConfig");const no="membrane",ro="membrane.config.yml",ne="https://api.getmembrane.com",oo="https://console.getmembrane.com";function pt(r){const t=$e()?.consoleUri||oo;return r?new ar(r,t).toString():t}c(pt,"getConsoleUrl");function ft(){const r=process.cwd(),e=x.join(r,no),t=x.join(r,ro),n=e,o=x.join(n,"workspace.yaml");return{membraneDirPath:e,configPath:t,payloadDirPath:n,workspaceDataFilePath:o}}c(ft,"getPaths");function un(){return ft().membraneDirPath}c(un,"getBasePath");const _e=k.join(tt.homedir(),".membrane");Me(_e)?(br(_e).mode&511)!==448&&vr(_e,448):tn(_e,{mode:448});const io={pat:{type:"string"},workspace:{type:"object"},accessToken:{type:"string"},refreshToken:{type:"string"},expiresAt:{type:"number"},apiUri:{type:"string"}},K=new Tr({schema:io,configName:"credentials",cwd:k.join(tt.homedir(),".membrane"),configFileMode:384}),so=c(r=>{K.set("pat",r)},"setPat"),dn=c(()=>K.get("pat"),"getPat"),ao=c(()=>{K.delete("pat")},"clearPat"),hn=c((r,e,t)=>{K.set("accessToken",r),K.set("refreshToken",e),t!=null?K.set("expiresAt",Date.now()+t*1e3):K.delete("expiresAt")},"setTokens"),co=c(()=>K.get("accessToken"),"getAccessToken"),Ce=c(()=>K.get("refreshToken"),"getRefreshToken"),mt=c(()=>{const r=K.get("expiresAt");return r?Date.now()>=r-6e4:!0},"isTokenExpired"),lo=c(()=>{K.delete("accessToken"),K.delete("refreshToken"),K.delete("expiresAt"),K.delete("apiUri")},"clearTokens"),Se=c(()=>K.get("apiUri"),"getApiUri"),uo=c(r=>{K.set("apiUri",r)},"setApiUri"),gt=c(()=>!!(K.get("accessToken")||K.get("pat")),"isAuthenticated");class qe{static{c(this,"AccountApiClient")}refreshPromise=null;explicitBaseUrl;constructor(e){this.explicitBaseUrl=e}get apiBaseUrl(){return this.explicitBaseUrl||Se()||ne}async refreshAccessToken(){const e=Ce();if(!e)throw new Error("No refresh token available. Please run `membrane login`.");const t=await fetch(`${this.apiBaseUrl}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:"refresh_token",refresh_token:e})});if(!t.ok)throw new Error("Failed to refresh access token. Please run `membrane login` again.");const n=await t.json(),o=n.refresh_token??e;return hn(n.access_token,o,n.expires_in),n.access_token}async getAuthToken(){const e=co();if(e&&!mt())return e;if(Ce())return this.refreshAccessToken();const t=dn();if(t)return t;throw new Error("Not authenticated. Run `membrane login` or set MEMBRANE_WORKSPACE_KEY and MEMBRANE_WORKSPACE_SECRET.")}async request(e,t={}){const n=t.headers?t.headers instanceof Headers?new Headers(t.headers):new Headers(t.headers):new Headers;if(!n.has("Authorization")){const s=await this.getAuthToken();n.set("Authorization",`Bearer ${s}`)}t.body&&!n.has("Content-Type")&&n.set("Content-Type","application/json");let o=await fetch(`${this.apiBaseUrl}${e}`,{...t,headers:n});if(o.status===401&&Ce()){const s=await(this.refreshPromise??=this.refreshAccessToken().finally(()=>{this.refreshPromise=null}));n.set("Authorization",`Bearer ${s}`),o=await fetch(`${this.apiBaseUrl}${e}`,{...t,headers:n})}if(!o.ok){const s=await o.text();throw new Ke(o.status,s)}if(o.status===204)return{};const i=await o.text();return JSON.parse(i)}get(e){return this.request(e,{method:"GET"})}post(e,t){return this.request(e,{method:"POST",body:JSON.stringify(t)})}put(e,t){return this.request(e,{method:"PUT",body:JSON.stringify(t)})}patch(e,t){return this.request(e,{method:"PATCH",body:JSON.stringify(t)})}delete(e){return this.request(e,{method:"DELETE"})}}const ho=c(r=>{const e=new qe(r);return t=>e.get(t)},"createAccountApiFetcher"),pn=new xr;class fn{static{c(this,"RequestLogger")}constructor(e=hr){this.axiosInstance=e}interceptorsConfigured=!1;setup(){if(this.interceptorsConfigured)return;const e=c(t=>(this.logError(t),Promise.reject(t)),"errorHandler");this.axiosInstance.interceptors.request.use(t=>{const n=pn.getStore();t.metadata={startTime:Date.now(),skipErrorLog:n};const{method:o,url:i}=this.getRequestDetails(t);return g.debug(`[Request]: ${o} ${i}`),t},e),this.axiosInstance.interceptors.response.use(t=>{const{method:n,url:o}=this.getRequestDetails(t.config),i=this.getDuration(t.config),{status:s,statusText:a}=t;return g.debug(`[Response]: ${n} ${o} - ${s} ${a} (${i}ms)`),t},e),this.interceptorsConfigured=!0}static withSkipErrorLog(e){return pn.run(!0,e)}getRequestDetails(e){const t=e?.method?.toUpperCase()??"UNKNOWN";if(!e?.url)return{method:t,url:"unknown"};if(e.url.startsWith("http"))return{method:t,url:e.url};const o=`${e.baseURL??""}/${e.url}`.replace(/\/+/g,"/").replace(/:\//,"://");return{method:t,url:o}}getDuration(e){return Date.now()-(e?.metadata?.startTime??Date.now())}logError(e){if(e.config?.metadata?.skipErrorLog)return;const{method:t,url:n}=this.getRequestDetails(e.config),o=this.getDuration(e.config);if(e.response){const{status:i,statusText:s}=e.response;g.error(`[Response]: ${t} ${n} - ${i} ${s} (${o}ms)`),e.response.data&&g.error(`[Response Data]: ${JSON.stringify(e.response.data,null,2)}`)}}}function po(r,e){return new Proxy(r,{get(t,n){const o=t[n];return typeof o=="function"?(...i)=>(e.lastCall={method:String(n),args:i},o.apply(t,i)):o}})}c(po,"createTrackedClient");class fo{static{c(this,"MembraneAPIManager")}client=null;currentConfig=null;tokenExpiry=0;requestTimes=[];maxRequestsPerSecond=80;windowSizeMs=1e3;semaphore=0;maxConcurrentRequests;maxRetries;retryDelay;requestTimeout;enableJitter;semaphoreQueue=[];rateLimitMutex=Promise.resolve();requestLogger=null;constructor(e={}){this.init(e)}init(e={}){this.windowSizeMs=e.windowSizeMs??1e3,this.maxRequestsPerSecond=e.maxRequestsPerSecond??80,this.maxConcurrentRequests=e.maxConcurrentRequests??Math.max(1,Math.min(Math.floor(this.maxRequestsPerSecond/4),20)),this.maxRetries=e.maxRetries??3,this.retryDelay=e.retryDelay??1e3,this.requestTimeout=e.requestTimeout??12e4,this.enableJitter=e.enableJitter!==!1,this.requestLogger=new fn,this.requestLogger.setup()}async withClient(e,t=!0,n=process.cwd()){const o={lastCall:null},i=c(async()=>{try{return await this.withRetry(async()=>{const s=await this.getClient(n),a=po(s,o);await this.acquireSemaphore();try{return await this.waitIfNeeded(),this.recordRequest(),await this.withTimeout(e(a),this.requestTimeout)}finally{this.releaseSemaphore()}},"API request")}catch(s){if(t){const a=o.lastCall?`Request: client.${o.lastCall.method}(${o.lastCall.args.map(l=>JSON.stringify(l)).join(", ")})`:null;throw s?.isMembraneError?(console.error(`
5
- Membrane API Error:`),a&&console.error(a),console.error(JSON.stringify(z(s),null,2))):Sr(s)?(console.error(`
2
+ var dr=Object.defineProperty;var c=(r,e)=>dr(r,"name",{value:e,configurable:!0});import*as T from"node:fs";import{mkdirSync as hr,writeFileSync as pr,readFileSync as fr}from"node:fs";import*as I from"node:path";import{join as Ve,dirname as mr}from"node:path";import{URL as gr,fileURLToPath as yr}from"node:url";import p from"chalk";import{Command as wr}from"commander";import{NotFoundError as Cr,MembraneConfigLoader as Sr,MembraneAxiosInstance as br,MembraneClient as Yt,extractMembraneErrorData as V,parseMembraneElementPath as de,getConnectorSpecPath as vr,getConnectorVersionPath as Zt,CONNECTOR_VERSION_DEVELOPMENT as Ye,WorkspaceElementType as k,getMembraneElementPath as Tr,compareWorkspaceExports as Xt,AgentName as Qt,WorkspaceElementSpecs as Q,WorkspaceSyncEventType as Er,ConnectorFileUpdateType as Ze,CONSOLE_ACCOUNT_API_TOKEN_PATH as Ir,OAUTH_SCOPE_TENANT as en,OAUTH_SCOPE_PLATFORM_USER as tn,MEMBRANE_CLI_CLIENT_ID as Me,WorkspaceElementChangeType as ee,setValueAtLocator as Xe,getDataCollectionCreateFields as Qe,excludeWriteOnlyFieldsFromSchema as nn,valueToSchema as je,getRequiredFieldsFromSchema as kr,getValueAtLocator as xr,walkSchema as rn,makeDataLocationPath as on,getDataCollectionUpdateFields as et}from"@membranehq/sdk";import Ce from"ora";import Ie,{isAxiosError as $r}from"axios";import sn from"form-data";import O,{existsSync as Fe,mkdirSync as an,statSync as Ar,chmodSync as Pr,readFileSync as cn,writeFileSync as Or}from"fs";import tt from"os";import x from"path";import Rr from"conf";import nt from"jsonwebtoken";import rt from"semver";import{AsyncLocalStorage as Nr}from"async_hooks";import ot from"archiver";import Y from"js-yaml";import ln from"jszip";import{minimatch as Dr}from"minimatch";import it from"lodash/camelCase.js";import st from"lodash/upperFirst.js";import Lr from"code-block-writer";import Mr from"lodash/uniqBy.js";import he,{createContext as at,useState as L,useEffect as Se,useContext as ct,useId as jr,useRef as lt,useLayoutEffect as Ue,useMemo as Fr}from"react";import{Box as y,Text as w,useInput as pe,render as ut,Newline as Ur}from"ink";import{jsx as d,jsxs as v,Fragment as Ke}from"react/jsx-runtime";import un from"swr/immutable";import{toSentenceCase as Kr}from"js-convert-case";import _r from"lodash/isEqual.js";import*as qr from"node:crypto";import{createHash as Br}from"node:crypto";import Wr from"chokidar";import Jr from"yaml";import{EventEmitter as zr}from"events";import{EventSource as Gr}from"eventsource";import _e from"unzipper";import*as Hr from"node:os";import"node:events";import dn from"ink-text-input";import{SWRConfig as Vr}from"swr";import{randomUUID as Yr,randomBytes as hn,createHash as Zr}from"crypto";import{createServer as pn}from"http";import qe from"ink-spinner";import{TextInput as Xr,Select as Qr,Spinner as eo}from"@inkjs/ui";import{FastMCP as to}from"fastmcp";import{z as D}from"zod";import{exec as no}from"node:child_process";import dt from"lodash/merge.js";import ro from"@anthropic-ai/sdk";import{faker as ke}from"@faker-js/faker";import oo from"lodash/template.js";import io from"lodash/templateSettings.js";const so="membrane",ao=["**/node_modules/**","**/.git/**","**/.DS_Store","**/Thumbs.db","**/*.tmp","**/*.swp","**/*.swo","**/*.log","**/*.lock","**/.cache/**","**/.next/**","**/.vscode/**","**/.idea/**","**/.logs/**"];function W(r){return I.join(r,so)}c(W,"getMembraneDir");const fn=Ve(W(process.cwd()),".logs");class co{static{c(this,"WorkspaceLogger")}_logs;verboseMode=!1;notificationHandler=null;constructor(){this._logs=[]}setNotificationHandler(e){this.notificationHandler=e}setVerboseMode(e){this.verboseMode=e}getVerboseMode(){return this.verboseMode}get logs(){return[...this._logs]}get latestLogs(){return this._logs.slice(this._logs.length-5)}log(e,t="info"){const n={timestamp:new Date().toISOString(),message:e,type:t};this._logs.push(n),this._logs=this._logs.slice(0,1e3),(t!=="debug"||this.verboseMode)&&this.notificationHandler&&this.notificationHandler.addLog(n)}info(e){this.log(e,"info")}success(e){this.log(e,"success")}warning(e){this.log(e,"warning")}error(e){this.log(e,"error")}debug(e){this.log(e,"debug")}clear(){this._logs=[]}saveLogsToFile(e){if(this._logs.length===0)return null;try{const t=new Date().toISOString().replace(/[:.]/g,"_"),n=e?`-${e}`:"",o=`${t}${n}.txt`;hr(fn,{recursive:!0});const i=Ve(fn,o),s=this._logs.map(a=>`[${a.timestamp}] ${a.type?.toUpperCase()||"INFO"}: ${a.message}`).join(`
3
+ `);return pr(i,s,"utf-8"),i}catch(t){return console.error("Failed to save logs:",t),null}}}const g=new co;async function ht(r,e,t={}){const{jobId:n,accessKey:o}=await e(),i=`${n}:${o}`;g.debug(`[background-job] Started job ${n}`);const s=Date.now(),{pollIntervalMs:a=1e3,timeoutMs:l=3e5,maxRetries:u=3}=t;let h=0;for(;;){if(Date.now()-s>l)throw new Error(`Background job ${n} timed out after ${l}ms`);await new Promise(C=>setTimeout(C,a));let f;try{f=await r.get(`background-jobs/${i}`),h=0}catch(C){if(C instanceof Cr&&h<u){h++,g.debug(`[background-job] Job ${n} not found, retrying (${h}/${u})`);continue}throw C}if(f.status==="completed"){if(g.debug(`[background-job] Completed job ${n}`),!f.result)throw new Error(`Background job ${n} completed but returned no result`);return f.result}if(f.status==="failed"){const C=f.error?.message||"Unknown error";throw g.error(`[background-job] Failed job ${n}: ${C}`),f.error?.stack&&g.error(`Stacktrace: ${f.error.stack}`),new Error(`Background job ${n} failed: ${C}`)}g.debug(`[background-job] Polling job ${n} (status: ${f.status})`)}}c(ht,"pollBackgroundJob");class pt extends Error{static{c(this,"ApiError")}statusCode;errorType;errorKey;data;constructor(e,t){const n=lo(t);if(n){const{message:o,type:i,key:s,...a}=n,l=typeof o=="string"?o:`API request failed (${e})`;super(l),this.errorType=typeof i=="string"?i:void 0,this.errorKey=typeof s=="string"?s:void 0,this.data=Object.keys(a).length>0?a:void 0}else super(t||`API request failed (${e})`);this.statusCode=e,this.name="ApiError"}format(){const e=[this.message];return this.data&&Object.keys(this.data).length>0&&e.push(JSON.stringify(this.data,null,2)),e.join(`
4
+ `)}}function lo(r){try{const e=JSON.parse(r);return typeof e=="object"&&e!==null?e:null}catch{return null}}c(lo,"tryParseJson");class Ee{static{c(this,"ConfigLoader")}static instance=null;sdkLoader;constructor(){this.sdkLoader=new Sr}static getInstance(){return Ee.instance||(Ee.instance=new Ee),Ee.instance}loadConfig(e){e&&e!==this.sdkLoader.getCwd()&&this.sdkLoader.setCwd(e);try{return this.sdkLoader.loadConfig({validate:!0})}catch(t){if(t.message?.includes("Failed to parse"))throw t;return null}}clearCache(){this.sdkLoader.clearCache()}updateConfig(e){return this.sdkLoader.updateConfig(e)}saveToFile(e){return this.sdkLoader.saveToFile(e)}isCacheDefined(){return this.sdkLoader.hasValidConfig()}}const fe=Ee.getInstance();function xe(r){return fe.loadConfig(r)}c(xe,"readProjectConfig");const uo="membrane",ho="membrane.config.yml",te="https://api.getmembrane.com",po="https://console.getmembrane.com";function ft(r){const t=xe()?.consoleUri||po;return r?new gr(r,t).toString():t}c(ft,"getConsoleUrl");function mt(){const r=process.cwd(),e=I.join(r,uo),t=I.join(r,ho),n=e,o=I.join(n,"workspace.yaml");return{membraneDirPath:e,configPath:t,payloadDirPath:n,workspaceDataFilePath:o}}c(mt,"getPaths");function mn(){return mt().membraneDirPath}c(mn,"getBasePath");const Be=x.join(tt.homedir(),".membrane");Fe(Be)?(Ar(Be).mode&511)!==448&&Pr(Be,448):an(Be,{mode:448});const fo={pat:{type:"string"},workspace:{type:"object"},accessToken:{type:"string"},refreshToken:{type:"string"},expiresAt:{type:"number"},apiUri:{type:"string"},tokenScope:{type:"string",enum:["platform-user","tenant"]},pendingLoginScope:{type:"string",enum:["platform-user","tenant"]},pendingLoginCodeVerifier:{type:"string"},pendingLoginClientId:{type:"string"},pendingLoginCreatedAt:{type:"number"}},M=new Rr({schema:fo,configName:"credentials",cwd:x.join(tt.homedir(),".membrane"),configFileMode:384}),mo=c(r=>{M.set("pat",r)},"setPat"),gn=c(()=>M.get("pat"),"getPat"),go=c(()=>{M.delete("pat")},"clearPat"),yn=c((r,e,t)=>{M.set({accessToken:r,refreshToken:e}),t!=null?M.set("expiresAt",Date.now()+t*1e3):M.delete("expiresAt")},"setTokens"),yo=c(()=>M.get("accessToken"),"getAccessToken"),be=c(()=>M.get("refreshToken"),"getRefreshToken"),gt=c(()=>{const r=M.get("expiresAt");return r?Date.now()>=r-6e4:!0},"isTokenExpired"),wo=c(()=>{M.delete("accessToken"),M.delete("refreshToken"),M.delete("expiresAt"),M.delete("apiUri"),M.delete("tokenScope"),$e()},"clearTokens"),me=c(()=>M.get("apiUri"),"getApiUri"),wn=c(r=>{M.set("apiUri",r)},"setApiUri"),Co=c(r=>{M.set("tokenScope",r)},"setTokenScope"),yt=c(()=>M.get("tokenScope"),"getTokenScope"),So=c(r=>{M.set({pendingLoginScope:r.scope,pendingLoginCodeVerifier:r.codeVerifier,pendingLoginClientId:r.clientId,pendingLoginCreatedAt:Date.now()})},"setPendingLogin"),bo=600*1e3,vo=c(()=>{const r=M.get("pendingLoginScope"),e=M.get("pendingLoginCodeVerifier"),t=M.get("pendingLoginClientId");if(!r||!e||!t)return;const n=M.get("pendingLoginCreatedAt");if(n&&Date.now()-n>bo){$e();return}return{scope:r,codeVerifier:e,clientId:t}},"getPendingLogin"),$e=c(()=>{M.delete("pendingLoginScope"),M.delete("pendingLoginCodeVerifier"),M.delete("pendingLoginClientId"),M.delete("pendingLoginCreatedAt")},"clearPendingLogin"),wt=c(()=>!!(M.get("accessToken")||M.get("pat")),"hasStoredCredentials");class Ae{static{c(this,"AccountApiClient")}refreshPromise=null;explicitBaseUrl;constructor(e){this.explicitBaseUrl=e}get apiBaseUrl(){return this.explicitBaseUrl||me()||te}async refreshAccessToken(){const e=be();if(!e)throw new Error("No refresh token available. Please run `membrane login`.");const t=await fetch(`${this.apiBaseUrl}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:"refresh_token",refresh_token:e})});if(!t.ok)throw new Error("Failed to refresh access token. Please run `membrane login` again.");const n=await t.json(),o=n.refresh_token??e;return yn(n.access_token,o,n.expires_in),n.access_token}async getAuthToken(){const e=yo();if(e&&!gt())return e;if(be())return this.refreshPromise??=this.refreshAccessToken().finally(()=>{this.refreshPromise=null});const t=gn();if(t)return t;throw new Error("Not authenticated. Run `membrane login` first.")}async getValidAccessToken(){return this.getAuthToken()}async forceRefreshAccessToken(){return this.refreshPromise??=this.refreshAccessToken().finally(()=>{this.refreshPromise=null})}async request(e,t={}){const n=t.headers?t.headers instanceof Headers?new Headers(t.headers):new Headers(t.headers):new Headers;if(!n.has("Authorization")){const s=await this.getAuthToken();n.set("Authorization",`Bearer ${s}`)}t.body&&!n.has("Content-Type")&&n.set("Content-Type","application/json");let o=await fetch(`${this.apiBaseUrl}${e}`,{...t,headers:n});if(o.status===401&&be()){const s=await(this.refreshPromise??=this.refreshAccessToken().finally(()=>{this.refreshPromise=null}));n.set("Authorization",`Bearer ${s}`),o=await fetch(`${this.apiBaseUrl}${e}`,{...t,headers:n})}if(!o.ok){const s=await o.text();throw new pt(o.status,s)}if(o.status===204)return{};const i=await o.text();return JSON.parse(i)}get(e){return this.request(e,{method:"GET"})}post(e,t){return this.request(e,{method:"POST",body:JSON.stringify(t)})}put(e,t){return this.request(e,{method:"PUT",body:JSON.stringify(t)})}patch(e,t){return this.request(e,{method:"PATCH",body:JSON.stringify(t)})}delete(e){return this.request(e,{method:"DELETE"})}}const To=c(r=>{const e=new Ae(r);return t=>e.get(t)},"createAccountApiFetcher"),Cn=new Nr;class Sn{static{c(this,"RequestLogger")}constructor(e=br){this.axiosInstance=e}interceptorsConfigured=!1;setup(){if(this.interceptorsConfigured)return;const e=c(t=>(this.logError(t),Promise.reject(t)),"errorHandler");this.axiosInstance.interceptors.request.use(t=>{const n=Cn.getStore();t.metadata={startTime:Date.now(),skipErrorLog:n};const{method:o,url:i}=this.getRequestDetails(t);return g.debug(`[Request]: ${o} ${i}`),t},e),this.axiosInstance.interceptors.response.use(t=>{const{method:n,url:o}=this.getRequestDetails(t.config),i=this.getDuration(t.config),{status:s,statusText:a}=t;return g.debug(`[Response]: ${n} ${o} - ${s} ${a} (${i}ms)`),t},e),this.interceptorsConfigured=!0}static withSkipErrorLog(e){return Cn.run(!0,e)}getRequestDetails(e){const t=e?.method?.toUpperCase()??"UNKNOWN";if(!e?.url)return{method:t,url:"unknown"};if(e.url.startsWith("http"))return{method:t,url:e.url};const o=`${e.baseURL??""}/${e.url}`.replace(/\/+/g,"/").replace(/:\//,"://");return{method:t,url:o}}getDuration(e){return Date.now()-(e?.metadata?.startTime??Date.now())}logError(e){if(e.config?.metadata?.skipErrorLog)return;const{method:t,url:n}=this.getRequestDetails(e.config),o=this.getDuration(e.config);if(e.response){const{status:i,statusText:s}=e.response;g.error(`[Response]: ${t} ${n} - ${i} ${s} (${o}ms)`),e.response.data&&g.error(`[Response Data]: ${JSON.stringify(e.response.data,null,2)}`)}}}function Eo(r,e){return new Proxy(r,{get(t,n){const o=t[n];return typeof o=="function"?(...i)=>(e.lastCall={method:String(n),args:i},o.apply(t,i)):o}})}c(Eo,"createTrackedClient");class Io{static{c(this,"MembraneAPIManager")}client=null;currentConfig=null;tokenExpiry=0;requestTimes=[];maxRequestsPerSecond=80;windowSizeMs=1e3;semaphore=0;maxConcurrentRequests;maxRetries;retryDelay;requestTimeout;enableJitter;semaphoreQueue=[];rateLimitMutex=Promise.resolve();requestLogger=null;constructor(e={}){this.init(e)}init(e={}){this.windowSizeMs=e.windowSizeMs??1e3,this.maxRequestsPerSecond=e.maxRequestsPerSecond??80,this.maxConcurrentRequests=e.maxConcurrentRequests??Math.max(1,Math.min(Math.floor(this.maxRequestsPerSecond/4),20)),this.maxRetries=e.maxRetries??3,this.retryDelay=e.retryDelay??1e3,this.requestTimeout=e.requestTimeout??12e4,this.enableJitter=e.enableJitter!==!1,this.requestLogger=new Sn,this.requestLogger.setup()}async withClient(e,t=!0,n=process.cwd()){const o={lastCall:null},i=c(async()=>{try{return await this.withRetry(async()=>{const s=await this.getClient(n),a=Eo(s,o);await this.acquireSemaphore();try{return await this.waitIfNeeded(),this.recordRequest(),await this.withTimeout(e(a),this.requestTimeout)}finally{this.releaseSemaphore()}},"API request")}catch(s){if(t){const a=o.lastCall?`Request: client.${o.lastCall.method}(${o.lastCall.args.map(l=>JSON.stringify(l)).join(", ")})`:null;throw s?.isMembraneError?(console.error(`
5
+ Membrane API Error:`),a&&console.error(a),console.error(JSON.stringify(V(s),null,2))):$r(s)?(console.error(`
6
6
  HTTP Error:`),a&&console.error(a),console.error(JSON.stringify({message:s.message,status:s.response?.status,statusText:s.response?.statusText,responseData:s.response?.data},null,2))):(console.error(`
7
- Unexpected Error:`),a&&console.error(a),console.error(s)),s}return}},"executeRequest");return t?i():fn.withSkipErrorLog(i)}async generateAccessToken(e,t){return nt.sign({name:"Membrane Agent",isAdmin:!0,exp:Math.floor(Date.now()/1e3)+3600,iss:e},t,{algorithm:"HS512"})}isTokenValid(){return Date.now()<this.tokenExpiry}getCurrentConfig(e){const t=$e(e);return!t?.workspaceKey||!t?.workspaceSecret?null:{workspaceKey:t.workspaceKey,workspaceSecret:t.workspaceSecret,apiUri:t.apiUri}}async createClient(e){const t=await this.generateAccessToken(e.workspaceKey,e.workspaceSecret);return this.tokenExpiry=Date.now()+36e5,this.currentConfig=e,new Gt({token:t,apiUri:e.apiUri})}async getClient(e=process.cwd()){const t=this.getCurrentConfig(e);if(!t)throw new Error("Unable to create MembraneClient: No workspace configuration found.");const n=!this.currentConfig||this.currentConfig.workspaceKey!==t.workspaceKey||this.currentConfig.workspaceSecret!==t.workspaceSecret||this.currentConfig.apiUri!==t.apiUri,o=!this.isTokenValid()||this.tokenExpiry-Date.now()<3e5;return(!this.client||n||o)&&(this.client=await this.createClient(t)),this.client}clearClient(){this.client=null,this.currentConfig=null,this.tokenExpiry=0,this.requestTimes=[],this.semaphore=0,this.semaphoreQueue=[],this.rateLimitMutex=Promise.resolve()}getCurrentConfigInfo(){return this.currentConfig}async waitIfNeeded(){this.rateLimitMutex=this.rateLimitMutex.then(async()=>{for(this.cleanOldRequests();this.requestTimes.length>=this.maxRequestsPerSecond;){const t=this.requestTimes[0]+this.windowSizeMs-Date.now()+10;if(t>0)await new Promise(n=>setTimeout(n,t)),this.cleanOldRequests();else break}}),await this.rateLimitMutex}recordRequest(){this.requestTimes.push(Date.now())}cleanOldRequests(){const e=Date.now()-this.windowSizeMs;this.requestTimes=this.requestTimes.filter(t=>t>e)}getRequestCount(){return this.cleanOldRequests(),this.requestTimes.length}async acquireSemaphore(){if(this.semaphore<this.maxConcurrentRequests){this.semaphore++;return}return new Promise(e=>{this.semaphoreQueue.push(e)})}releaseSemaphore(){if(this.semaphore--,this.semaphoreQueue.length>0){const e=this.semaphoreQueue.shift();this.semaphore++,e()}}async withRetry(e,t="operation"){let n;for(let o=0;o<=this.maxRetries;o++)try{return await e()}catch(i){if(n=i,!this.isRetryableError(i)||o===this.maxRetries)throw i;const s=new Date().toISOString(),a=o+2;g.debug(`[${s}] Retrying ${t} (attempt ${a}/${this.maxRetries+1})`);let l=this.retryDelay*Math.pow(2,o);if(this.enableJitter){const d=l*.25*(Math.random()*2-1);l=Math.max(0,l+d)}await new Promise(d=>setTimeout(d,l))}throw n||new Error("Unknown error occurred during retry attempts")}isRetryableError(e){if(!e)return!1;const t=(e.message||e.toString()||"").toLowerCase(),n=e.code;return n&&["econnrefused","enotfound","econnreset","etimedout","ehostunreach","enetunreach"].includes(n.toLowerCase())?!0:["econnrefused","connection refused","network error","timeout","socket hang up","request timeout","dns lookup failed"].some(s=>t.includes(s))}async withTimeout(e,t){let n;const o=new Promise((i,s)=>{n=setTimeout(()=>s(new Error(`Request timeout after ${t}ms`)),t)});try{const i=await Promise.race([e,o]);return n&&clearTimeout(n),i}catch(i){throw n&&clearTimeout(n),i}}async getVersion(){try{return(await this.withClient(t=>t.get("version"),!1))?.version??null}catch{return null}}async isVersionAtLeast(e){const t=await this.getVersion(),n=t?rt.coerce(t):null,o=rt.coerce(e);return!!(n&&o&&rt.gte(n,o))}}const $=new fo;async function mn(r){const e=await $.withClient(t=>t.get("org-workspace-id"),!0,r);if(!e)throw new Error("Failed to get workspace ID");return e.id}c(mn,"getWorkspaceId");const gn=1e3,yn=12e4;async function wn(){const r=await $.withClient(async t=>ht(t,()=>t.get("export"),{pollIntervalMs:gn,timeoutMs:yn}));if(!r)throw new Error("Failed to export workspace");const e=await Ie.get(r.downloadUrl,{responseType:"arraybuffer"});return Buffer.from(e.data)}c(wn,"downloadWorkspaceExport");async function Cn(r,e={}){const t=new en;t.append("file",r,{filename:"membrane.zip",contentType:"application/zip"});const n=await $.withClient(async i=>{const s=`import?dryRun=${e.dryRun??!1}&partial=${e.partial??!1}`,{jobId:a,accessKey:l}=await i.post(s,t,{headers:t.getHeaders()});return ht(i,()=>Promise.resolve({jobId:a,accessKey:l}),{pollIntervalMs:1e3,timeoutMs:3e5})});if(!n)throw new Error("Failed to import workspace");return await $.isVersionAtLeast("1.10")?{create:new Set(n.comparison.create||[]),update:new Set(n.comparison.update||[]),delete:new Set(n.comparison.delete||[])}:{create:new Set(n.create||[]),update:new Set(n.update||[]),delete:new Set(n.delete||[])}}c(Cn,"importWorkspace");async function mo(r,e){const t=await $.withClient(async o=>ht(o,()=>o.get(`connectors/${r}/export-files`,{version:e}),{pollIntervalMs:gn,timeoutMs:yn}));if(!t)throw new Error("Failed to export connector version");const n=await Ie.get(t.downloadUrl,{responseType:"arraybuffer"});return Buffer.from(n.data)}c(mo,"exportConnector");function Sn(r,e){Pe(x.dirname(r)),v.writeFileSync(r,e)}c(Sn,"writeFile");function go(r){v.existsSync(r)&&v.rmSync(r)}c(go,"deleteFile");function yt(r){v.existsSync(r)&&v.rmSync(r,{recursive:!0,force:!0})}c(yt,"deleteDir");function yo(r,e=!0){if(v.existsSync(r))try{const t=v.readFileSync(r,"utf8");return H.load(t)||void 0}catch(t){if(!e)return;if(t instanceof Error){const n=x.relative(process.cwd(),r);throw new Error(`Failed to parse YAML file "${n}": ${t.message}`)}throw t}}c(yo,"readYaml$1");function bn(r,e,t){try{Pe(x.dirname(r));const n=H.dump(e,t);v.writeFileSync(r,n,"utf8")}catch(n){if(n instanceof Error){const o=x.relative(process.cwd(),r);throw new Error(`Failed to write YAML file "${o}": ${n.message}`)}throw n}return e}c(bn,"writeYaml$1");function Pe(r){v.existsSync(r)||v.mkdirSync(r,{recursive:!0})}c(Pe,"ensureDirExists");function vn(r,e=!0){if(!v.existsSync(r)||!v.statSync(r).isDirectory())return;let t=v.readdirSync(r);t.length>0&&(t.forEach(n=>vn(x.join(r,n),!1)),t=v.readdirSync(r)),t.length===0&&!e&&v.rmdirSync(r)}c(vn,"cleanupEmptyFolders");function wo(r){const e=r.split(/[\\/]/).join("/");return e.endsWith("/")?e+"**":e}c(wo,"normalizePattern");async function En(r,e,t){const n=(e??[]).map(wo),o=[];if(t){const i=x.join(q(process.cwd()),"connectors");for(const s of Object.values(t)){const a=s.key,l=x.join(i,a),d=x.join(l,`${a}.yml`);v.existsSync(d)&&o.push({name:pr(a),content:v.readFileSync(d,"utf-8")});const h=[...s.versions];v.existsSync(x.join(l,"development"))&&!h.includes("")&&h.push("");for(const f of h){const p=f===""?"development":f,C=x.join(l,p,"src"),E=x.join(l,p,"src.zip"),S=f===""?Ve:f;v.existsSync(C)?o.push({name:Vt(a,S),content:await Co(C)}):v.existsSync(E)&&o.push({name:Vt(a,S),content:v.readFileSync(E)})}}}return new Promise((i,s)=>{const a=ot("zip",{zlib:{level:9}}),l=[];a.on("data",h=>l.push(h)),a.on("end",()=>i(Buffer.concat(l))),a.on("error",h=>s(h));const d=new Map;for(const h of r[I.Integration]||[])d.set(h.uuid,h.key);for(const[h,f]of Object.entries(r))for(const p of f){const C=d.get(p.integrationUuid),E=fr(h,p.key,C);n.length>0&&!n.some(S=>Ir(E,S))||a.append(H.dump(p),{name:E})}for(const{name:h,content:f}of o)a.append(f,{name:h});a.finalize()})}c(En,"createMembraneZip");async function Co(r){return new Promise((e,t)=>{const n=ot("zip",{zlib:{level:9}}),o=[];n.on("data",i=>o.push(i)),n.on("end",()=>e(Buffer.concat(o))),n.on("error",i=>t(i)),n.directory(r,!1),n.finalize()})}c(Co,"createConnectorVersionZip");async function wt(r,e){const t=await rn.loadAsync(r),n=[];for(const[o,i]of Object.entries(t.files)){if(i.dir)continue;const s=ue(o);if(!s)continue;const a=await i.async("string"),l=H.load(a);if(!l)continue;const d=await e(o,l,s);d!==void 0&&n.push(d)}return n}c(wt,"iterateZipItems");async function Tn(r){const e=await rn.loadAsync(r),t={};for(const[n,o]of Object.entries(e.files)){if(o.dir)continue;const i=ue(n);if(!i)continue;const s=await o.async("string"),a=H.load(s);t[i.type]||(t[i.type]=[]),t[i.type].push(a)}return t}c(Tn,"readMembraneZip");async function Ct(r=process.cwd()){const e=await xn(q(r)),t={};for(const{data:n,type:o}of e)t[o]||(t[o]=[]),t[o].push(n);return t}c(Ct,"readMembraneDir");async function xn(r){const e=In(r),t=[];for(const n of e){if(n.isDirectory())continue;const o=ue(n.path);if(!o)continue;const i=await n.readContent(),s=H.load(i),a=x.join(r,n.path);t.push({filePath:a,data:s,type:o.type})}return t}c(xn,"iterateMembraneFiles");function In(r,e){const t=[];if(e||(e=r),!v.existsSync(e)||e.startsWith(x.join(r,"connectors")))return t;const n=v.readdirSync(e,{withFileTypes:!0});for(const o of n){const i=x.join(e,o.name),s=x.relative(r,i);o.isDirectory()?t.push(...In(r,i)):o.isFile()&&ue(s)&&t.push({path:s,isDirectory:c(()=>!1,"isDirectory"),readContent:c(async()=>v.readFileSync(i,"utf8"),"readContent")})}return t}c(In,"getMembraneFiles");function kn(){const r={},e=x.join(q(process.cwd()),"connectors");if(!v.existsSync(e))return r;const t=v.readdirSync(e);for(const n of t){const o=x.join(e,n);if(!v.statSync(o).isDirectory())continue;const i=x.join(o,`${n}.yml`),s=yo(i,!1);if(!s?.uuid)continue;const a=new Set,l=v.readdirSync(o);for(const d of l){if(d.endsWith(".yml"))continue;const h=x.join(o,d);v.statSync(h).isDirectory()&&a.add(d=="development"?"":d)}r[s.uuid]={key:n,id:s.id,versions:Array.from(a)}}return r}c(kn,"readConnectorsDir");function Ae(r,e){const t=x.join(q(process.cwd()),"connectors",r);return e==""||e===Ve?x.join(t,"development"):e?x.join(t,e):t}c(Ae,"getConnectorPath");const So={info:"\u{1F4DD}",success:"\u2728",warning:"\u26A0\uFE0F",error:"\u274C",debug:"\u{1F50D}"},bo={info:m.white,success:m.green,warning:m.yellow,error:m.red,debug:m.gray};class T{static{c(this,"Logger")}static formatMessage(e,t,n={icon:!1}){const o=n.timestamp?`${m.gray(new Date().toISOString())} `:"",i=n.prefix?`${m.gray(n.prefix)} `:"",s=n.suffix?` ${m.gray(n.suffix)}`:"",a=So[t],l=bo[t];return`${o}${n.icon?a:""} ${i}${l(e)}${s}`}static info(e,t){let n=m.white;if(t?.color&&(n=m[t.color.toLowerCase()]||m.white),t?.timestamp){const o=new Date().toLocaleTimeString();console.debug(`${m.gray(`[${o}]`)} ${n(e)}`)}else console.debug(n(e))}static group(e,t){}static groupEnd(){}static newLine(){}static success(e,t){console.debug(this.formatMessage(e,"success",t))}static warning(e,t){console.debug(this.formatMessage(e,"warning",t))}static error(e,t){console.error(this.formatMessage(e,"error",t))}static debug(e,t){t?.prefix?console.debug(m.gray(`[${t.prefix}] ${e}`),t.error?`
8
- ${m.red(t.error)}`:""):console.debug(m.gray(e),t?.error?`
9
- ${m.red(t.error)}`:"")}static step(e,t){}static header(e){console.debug(),console.debug(m.bold.cyan(`\u25B6 ${e}`)),console.debug()}static table(e,t){if(e.length===0)return;const n=t||Object.keys(e[0]),o=e.map(i=>{const s={};return n.forEach(a=>{s[a]=i[a]}),s});console.table(o,n)}static divider(){}}function vo(r){r.command("diff").description("Show what would change on push without applying anything").action(async()=>{const e=xe({text:"Comparing workspace",color:"white"}).start();try{const t=await Ct();e.text="Downloading remote workspace";const n=await wn(),o=await Tn(n);e.stop();const{changes:i,diff:s}=Yt(o,t,{includeDiff:!0}),a=Object.keys(i).length;if(a===0){T.info("No changes detected");return}T.info(`\u25CF Diff \xB7 ${a} change(s)
10
- `),s&&T.info(Eo(s))}catch(t){e.stop(),T.error("\u25A0 Error"),T.error(`\u2514\u2500\u2500 ${t.message}`),process.exit(1)}})}c(vo,"setupDiffCommand");function Eo(r){return r.split(`
11
- `).map(e=>e.startsWith("diff ")?m.bold(e):e.startsWith("index ")||e.startsWith("===")?m.dim(e):e.startsWith("---")?m.bold.red(e):e.startsWith("+++")?m.bold.green(e):e.startsWith("@@")?m.cyan(e):e.startsWith("+")?m.green(e):e.startsWith("-")?m.red(e):e).join(`
12
- `)}c(Eo,"colorizePatch");function fe(r){if(r.type){if(Array.isArray(r.type))return{anyOf:r.type.map(t=>fe({...r,type:t}))};if(r.type==="array"){const t={type:"array",items:r.items?fe(r.items):{type:"object"}};return r.title&&(t.title=r.title),r.description&&(t.description=r.description),r.minItems!==void 0&&(t.minItems=r.minItems),r.maxItems!==void 0&&(t.maxItems=r.maxItems),r.uniqueItems!==void 0&&(t.uniqueItems=r.uniqueItems),t}}const e={};if(r.type&&!Array.isArray(r.type)&&(e.type=r.type),r.title&&(e.title=r.title),r.description&&(e.description=r.description),r.format&&(e.format=r.format),r.enum&&(e.enum=r.enum),r.default!==void 0&&(e.default=r.default),r.minimum!==void 0&&(e.minimum=r.minimum),r.maximum!==void 0&&(e.maximum=r.maximum),r.minLength!==void 0&&(e.minLength=r.minLength),r.maxLength!==void 0&&(e.maxLength=r.maxLength),r.maxItems!==void 0&&(e.maxItems=r.maxItems),r.readOnly!==void 0&&(e.readOnly=r.readOnly),r.writeOnly!==void 0&&(e.writeOnly=r.writeOnly),r.examples&&r.examples.length>0&&(e.example=r.examples[0]),r.properties){e.properties={};for(const[t,n]of Object.entries(r.properties))e.properties[t]=fe(n)}return r.anyOf&&(e.anyOf=r.anyOf.map(fe)),r.additionalProperties!==void 0&&(typeof r.additionalProperties=="boolean"?e.additionalProperties=r.additionalProperties:e.additionalProperties=fe(r.additionalProperties)),r.required&&(e.required=r.required),e}c(fe,"convertDataSchemaToOpenAPI");function To(r){const{membraneInterfaces:{actions:e}}=r,t=xo(e);return JSON.stringify({openapi:"3.0.0",info:{title:"Membrane Actions API",version:"1.0.0",description:"Generated OpenAPI specification for Membrane actions"},paths:{},components:{schemas:t}},null,2)}c(To,"generateOpenAPIContent");function xo(r){const e={};return r.forEach(t=>{const n=st(it(t.key)),o={type:"object",properties:{id:{type:"string",description:"Request ID"},action:{type:"string",enum:[t.key]}},required:["id","action"]};if(t?.inputSchema){const a=fe(t.inputSchema);a.properties&&(o.properties={...o.properties,...a.properties}),a.required&&(o.required=[...o.required||[],...a.required])}e[`${n}Request`]=o;const i={type:"object",properties:{id:{type:"string",description:"Response ID"},success:{type:"boolean"},data:{type:"object"}},required:["id","success"]},s=t?.customOutputSchema||t?.outputSchema;if(s){const a=fe(s);i.properties={...i.properties,data:a}}e[`${n}Response`]=i}),e}c(xo,"generateOpenAPISchemas");function Io(r){const{membraneInterfaces:{actions:e}}=r,t=$r(e,"key"),n=new kr({indentNumberOfSpaces:2,newLine:`
13
- `});return n.writeLine("// Generated TypeScript definitions for Membrane actions"),n.newLine(),n.writeLine("import type {"),n.writeLine(" ActionAccessor,"),n.writeLine(" ConnectionLevelActionAccessor,"),n.writeLine('} from "@membranehq/sdk";'),n.newLine(),ko(n,t),n.toString()}c(Io,"generateTypeScriptContent");function ko(r,e){r.writeLine('declare module "@membranehq/sdk" {'),r.indent(()=>{e.forEach(t=>{const n=bt(t),o=t?.inputSchema;Be(r,{interfaceName:n,properties:o?.properties,required:o?.required||[]});const i=vt(t),s=t?.customOutputSchema||t?.outputSchema;Be(r,{interfaceName:i,properties:s?.properties,required:s?.required||[],fallbackContent:"result: unknown"}),r.newLine()}),Be(r,{interfaceName:"MembraneClient",methods:e.map(t=>{const n=bt(t),o=vt(t);return{name:"action",parameters:`selector: "${t.key}"`,returnType:`ActionAccessor<${n}, ${o}>`}})}),r.newLine(),Be(r,{interfaceName:"ConnectionAccessor",methods:e.map(t=>{const n=bt(t),o=vt(t);return{name:"action",parameters:`selector: "${t.key}"`,returnType:`ConnectionLevelActionAccessor<${n}, ${o}>`}})})}),r.writeLine("}")}c(ko,"generateModuleAugmentation");function Be(r,e){const{interfaceName:t,properties:n,required:o=[],methods:i,fallbackContent:s}=e;r.writeLine(`interface ${t} {`),r.indent(()=>{n&&Object.keys(n).length>0&&$o(r,n,o),i&&i.length>0&&(n&&Object.keys(n).length>0&&r.newLine(),i.forEach((a,l)=>{r.writeLine(`${a.name}(${a.parameters}): ${a.returnType};`),l<i.length-1&&r.newLine()})),s&&(!n||Object.keys(n).length===0)&&(!i||i.length===0)&&r.writeLine(s)}),r.writeLine("}")}c(Be,"generateTypeScriptInterface");function $o(r,e,t){Object.entries(e).forEach(([n,o])=>{const s=t.includes(n)?"":"?",a=St(o);r.writeLine(`readonly ${n}${s}: ${a}`)})}c($o,"generateTypeScriptProperties");function St(r){return r.type==="string"?r.enum?r.enum.map(e=>`'${e}'`).join(" | "):"string":r.type==="number"||r.type==="integer"?"number":r.type==="boolean"?"boolean":r.type==="array"?`${r.items?St(r.items):"unknown"}[]`:r.type==="object"?r.properties?`{ ${Object.entries(r.properties).map(([t,n])=>{const i=(r.required||[]).includes(t)?"":"?",s=St(n);return`readonly ${t}${i}: ${s}`}).join("; ")} }`:"Record<string, unknown>":"unknown"}c(St,"convertJsonSchemaToTypeScript");function bt(r){return`${st(it(r.key))}Input`}c(bt,"getInputTypeName");function vt(r){return`${st(it(r.key))}Output`}c(vt,"getOutputTypeName");async function Et(r){const{out:e}=r;await v.promises.mkdir(e,{recursive:!0});const t=Po(r);for(const[n,o]of Object.entries(t)){const i=x.join(e,n);await v.promises.writeFile(i,o,"utf-8")}}c(Et,"generateCode");function Po(r){switch(r.target){case"openapi":return{"openapi.json":To(r)};case"typescript":return{"generated.d.ts":Io(r)};default:throw new Error(`Unsupported target: ${r.target}`)}}c(Po,"generateContent");const Tt=c(()=>[m.yellow("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),m.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),m.yellow("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),m.yellow("\u2502 The codegen command is experimental and subject to rapid changes.\u2502"),m.yellow("\u2502 Features, APIs, and file structures may change without notice. \u2502"),m.yellow("\u2502 Use in production environments is not recommended. \u2502"),m.yellow("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),""].join(`
14
- `),"createExperimentalWarning$2");function Ao(r,e){r.command("codegen").description("\u26A0\uFE0F EXPERIMENTAL: Generate code for easy integration within projects - This feature is experimental and will be changing rapidly. Use at your own risk.").requiredOption("--actions <actions>",'Comma-separated list of action names (e.g., "list-files,get-file-by-id")').requiredOption("--out <path>","Output directory for generated files").requiredOption("--target <type>","Target format: openapi or typescript").requiredOption("--schemasOnly","Generate only schemas without implementation").addHelpText("after",Tt()).addHelpText("after",["",m.bold("Examples:"),` ${m.gray("\u25B8")} ${m.cyan("membrane codegen --actions list-files,get-file-by-id --out src/generated --target openapi --schemasOnly")}`,` ${m.gray("\u25B8")} ${m.cyan("membrane install --actions delete-file --out src/generated --target typescript --schemasOnly")}`,"",Tt()].join(`
15
- `)).action(async t=>{try{console.warn(Tt()),console.error(m.cyan("\u{1F527} Membrane Codegen")),console.error("Status: Loading membrane interfaces...");const n=await Ro(e,t),o={out:t.out,target:t.target,schemasOnly:t.schemasOnly,membraneInterfaces:n};console.error(`Output: ${o.out}`),console.error(`Target: ${o.target}`),console.error(`Schemas Only: ${o.schemasOnly?"Yes":"No"}`),console.error(`Loaded ${n.actions.length} membrane interfaces`),console.error("Status: Generating code..."),await Et(o),console.error(m.green("\u2705 Code generation completed successfully!")),process.exit(0)}catch(n){console.error(m.red("\u274C Code generation failed:")),console.error(n instanceof Error?n.message:"Unknown error occurred"),process.exit(1)}})}c(Ao,"setupCodegenCommand");async function Ro(r,e){return await r.fetchElements(),{actions:[...r.getSyncedElementsByType(I.Action).map(t=>t.data)].filter(t=>e.actions.includes(t.key||""))}}c(Ro,"loadMembraneInterfaces");const Q={UPDATE:"update",DELETE:"delete",CREATE:"create"},B={INCOMING:"incoming",OUTGOING:"outgoing"},Y={[I.Integration]:{element:"integration",elements:"integrations",exportable:!1,exportCleanup:c(r=>({id:r.id,key:r.key,name:r.name,connectorId:r.connectorId,baseUri:r.baseUri,connectorVersion:r.connectorVersion}),"exportCleanup")},[I.Connector]:{element:"connector",elements:"connectors",exportable:!1},[I.Action]:{element:"action",elements:"actions",integrationSpecific:!0,exportCleanup:c(r=>(delete r.integration,r),"exportCleanup")},[I.AppDataSchema]:{element:"appDataSchema",elements:"appDataSchemas"},[I.AppEventType]:{element:"appEventType",elements:"appEventTypes"},[I.DataLinkTable]:{element:"dataLinkTable",elements:"dataLinkTables"},[I.DataSource]:{element:"dataSource",elements:"dataSources",parentKey:"universalDataSourceId",integrationSpecific:!0},[I.FieldMapping]:{element:"fieldMapping",elements:"fieldMappings",integrationSpecific:!0,parentKey:"universalFieldMappingId",exportCleanup:c(r=>(delete r.dataSourceId,r),"exportCleanup")},[I.Flow]:{element:"flow",elements:"flows",integrationSpecific:!0,parentKey:"universalFlowId"},[I.Package]:{element:"package",elements:"packages",integrationSpecific:!0}},Oo=["id","workspaceId","integrationId","createdAt","updatedAt","revision","archivedAt","baseUri","state","appliedToIntegrations","dependencies"],$n=[I.Action,I.FieldMapping,I.Flow,I.DataSource,I.Package];class F{static{c(this,"Element")}type;key;integrationKey;data;constructor(e,t,n,o){if(!o)throw new Error("Element must always contain data");if(!t)throw new Error("Element must have a key");this.type=e,this.key=t,this.data=o,this.integrationKey=n||F.extractIntegrationKey(o)}get id(){return F.makeId(this.type,this.key,this.integrationKey)}get dirPath(){const e=Z[this.type].apiPath;if(this.integrationKey){const t=Z[I.Integration].apiPath;return x.join(t,this.integrationKey,e,this.key)}return x.join(e,this.key)}get path(){return x.join(this.dirPath,"spec.yaml")}get relativePath(){return x.relative(q(process.cwd()),this.path)}get absolutePath(){return x.resolve(x.join(q(process.cwd()),this.path))}isEqual(e){if(this.id!==e.id)return!1;const t=this.clean(),n=e.clean();return Dr(t,n)}hasParent(){if(this.data?.parentUuid)return!0;const e=this.getParentKey();return!!e&&!!this.data?.[e]}clean(){const e={...this.data};return Oo.forEach(t=>{delete e[t]}),Object.keys(e).forEach(t=>{t.match(/universal.*Revision/)&&delete e[t]}),e}getParentKey(){let e="parentId";return Y?.[this.type]?.parentKey&&(e=Y?.[this.type]?.parentKey),e}static new(e,t,n,o){return new F(e,t,n,o)}static fromData(e,t){if(!t?.key)throw new Error(`Element missing key: ${JSON.stringify(t)}`);const n=this.extractIntegrationKey(t);return new F(e,t.key,n,t)}static fromPathAndData(e,t){const n=F.parsePath(e);if(!t)return;const o=t?.key||n?.key;return n?F.new(n.type,o,n.integrationKey,t):void 0}static fromElement(e){return new F(e.type,e.key,e.integrationKey,{...e.data})}static idFromPath(e){const t=F.parsePath(e);if(t)return F.makeId(t.type,t.key,t.integrationKey)}static makeId(e,t,n){return e===I.Integration?`${e}:${t}`:F.isIntegrationSpecific(e)?`${n||"universal"}:${e}:${t}`:`${e}:${t}`}static parsePath(e){const t=this.getRelativePath(e);if(!this.isElementFile(t))return;const n=Object.values(Z).map(l=>l.apiPath).join("|"),o=new RegExp(`^(?<elementType>${n})/(?<elementKey>[^/]+)/spec\\.ya?ml$`),i=t.match(o);if(i?.groups){const{elementType:l,elementKey:d}=i.groups,h=this.getElementTypeFromPath(l);if(h)return{type:h,key:d}}const s=new RegExp(`^integrations/(?<integrationKey>[^/]+)/(?<elementType>${n})/(?<elementKey>[^/]+)/spec\\.ya?ml$`),a=t.match(s);if(a?.groups){const{integrationKey:l,elementType:d,elementKey:h}=a.groups,f=this.getElementTypeFromPath(d);if(f)return{type:f,key:h,integrationKey:l}}}static extractIntegrationKey(e){return e?.integrationKey||e?.integration?.key||e?.integration_key||void 0}static isElementFile(e){return e.endsWith(".yml")||e.endsWith(".yaml")}static getElementTypeFromPath(e){return Object.values(I).find(t=>Z[t].apiPath===e)}static getRelativePath(e){return x.relative(q(process.cwd()),e)}static isIntegrationSpecific(e){return $n.includes(e)}static canBeIntegrationSpecific(e){return $n.includes(e)}}class Pn{static{c(this,"BaseWorkspaceElementsRepository")}constructor(e){this.cache=e}connectorsMapping;sourceCache;setConnectorsMapping(e){this.connectorsMapping=e}setSourceCache(e){this.sourceCache=e}async getElements(){const e=[];try{const t=await this.getIntegrations();e.push(...t);const n=[I.Integration,I.Connector],o=Object.keys(Y),i=await Promise.all(o.filter(s=>!n.includes(s)).map(async s=>this.getElementsByType(s,t)));for(const s of i)e.push(...s)}catch(t){throw g.error(`Failed to get elements: ${t}`),t}return e}async putElement(e){let t=this.cache.get(e.id);return t&&!e.data.id&&t.data.id&&(e.data.id=t.data.id),!t&&e.data.id&&(t=await this.getByInternalId(e.data.id,e.type,!1)),e.data.id&&t?t=await this.updateElement(e,t,{elements:this.cache.getAll(),connectorsMapping:this.connectorsMapping,sourceElements:this.sourceCache?.getAll()}):t=await this.createElement(e,{elements:this.cache.getAll(),connectorsMapping:this.connectorsMapping,sourceElements:this.sourceCache?.getAll()}),t}async getElementsByType(e,t){return[]}async createElement(e,t){return e}async updateElement(e,t,n){return t}async getElement(e){}async getIntegrations(){return[]}async getByInternalId(e,t,n=!0){}async deleteElement(e,t){}}function xt(r,e=!0){if(v.existsSync(r))try{const t=v.readFileSync(r,"utf8");return H.load(t)||void 0}catch(t){if(!e)return;if(t instanceof Error){const n=x.relative(process.cwd(),r);throw new Error(`Failed to parse YAML file "${n}": ${t.message}`)}throw t}}c(xt,"readYaml");function Do(r,e,t){try{const n=H.dump(e,t);v.writeFileSync(r,n,"utf8")}catch(n){if(n instanceof Error){const o=x.relative(process.cwd(),r);throw new Error(`Failed to write YAML file "${o}": ${n.message}`)}throw n}}c(Do,"writeYaml");class No extends Pn{static{c(this,"LocalWorkspaceElementsRepository")}basePath;constructor(e){super(e),this.basePath=q(process.cwd())}async getElementsByType(e,t){const n=[],o=x.join(this.basePath,Z[e].apiPath),i=await this.readElementsInDir(o);n.push(...i);for(const s of t){const a=x.join(this.basePath,Z[I.Integration].apiPath,s.key,Z[e].apiPath),l=await this.readElementsInDir(a);n.push(...l)}return n.length>0&&g.debug(`[local] Fetched ${n.length} ${e}${n.length!==1?"s":""}`),n}async getElement(e){return this.readElement(e.path)}async createElement(e){return this.updateElement(e,e)}async updateElement(e,t){if(!e.data)throw new Error("Element must have data to write");const n=x.join(this.basePath,t.dirPath),o=x.join(this.basePath,t.path);return v.existsSync(n)||v.mkdirSync(n,{recursive:!0}),Do(o,e.data),g.debug(`[local] Written ${t.relativePath}`),t}async deleteElement(e){const t=x.join(this.basePath,e.path),n=x.join(this.basePath,e.dirPath);v.existsSync(t)&&v.rmSync(t,{force:!0}),this.pruneEmptyDir(n),g.debug(`[local] Deleted ${e.relativePath}`)}async getIntegrations(){const e=x.join(this.basePath,Z[I.Integration].apiPath);return this.readElementsInDir(e)}async readElement(e){const t=xt(e);if(t)return F.fromPathAndData(e,t)}async readElementsInDir(e){const t=[];if(!v.existsSync(e))return t;const n=v.readdirSync(e);if(n.length===0)return t;const o=n.map(async s=>{const a=x.join(e,s,"spec.yaml");return this.readElement(a)});return(await Promise.all(o)).filter(s=>s!=null)}pruneEmptyDir(e){try{if(!e.startsWith(this.basePath)||e===this.basePath||!v.existsSync(e)||v.readdirSync(e).length>0)return;v.rmdirSync(e),this.pruneEmptyDir(x.dirname(e))}catch(t){console.warn(`Failed to prune empty directory ${e}:`,t)}}}class Mo extends Pn{static{c(this,"RemoteWorkspaceElementsRepository")}async getElementsByType(e,t){const n=F.canBeIntegrationSpecific(e),o=await this.findAll(e,n?{layer:"universal"}:{});if(!F.canBeIntegrationSpecific(e))return o;for(const i of t){const s=i.key,a=i.data.id,l=await this.findAll(e,a?{integrationId:a}:{integrationKey:s},s);o.push(...l)}return o.length>0&&g.debug(`[remote] Fetched ${o.length} ${e}${o.length!==1?"s":""}`),o}async getElement(e){const t=await $.withClient(n=>n[Y[e.type].element](e.data.id).get());return F.fromData(e.type,t)}async createElement(e,t){const n=e.clean();if(this.transformElementForCreate(e,n,t),e.hasParent()&&n.integrationId&&!n.isCustomized){const s=e.getParentKey(),a=new Set(["uuid","integrationId",s,"meta","integrationUuid","parentUuid"]);Object.keys(n).forEach(l=>{a.has(l)||delete n[l]})}const o=await $.withClient(s=>s[Y[e.type].elements].create(n)),i=F.fromData(e.type,o);return g.debug(`[remote] Created ${i.id}`),i}async updateElement(e,t,n){if(!e.data.id)throw new Error("Element must have an id to update");t.data.archivedAt&&await $.withClient(a=>a[Y[e.type].element](t.data.id).restore());const o=e.clean();if(this.transformElementForUpdate(e,o,n),e.hasParent()&&o.integrationId&&!o.isCustomized)return g.debug(`[remote] Skipped update for ${t.id} (non-customized)`),t;const i=await $.withClient(a=>a[Y[e.type].element](t.data.id).put(o)),s=F.fromData(t.type,i);return g.debug(`[remote] Updated ${t.id}`),s}async deleteElement(e){if(!e.data.id)throw new Error("Element must have an id to delete");await $.withClient(t=>t[Y[e.type].element](e.data.id).archive()),g.debug(`[remote] Deleted ${e.id}`)}async getIntegrations(){const e=await $.withClient(n=>n.integrations.findAll());if(!e)return[];const t=e.map(n=>F.fromData(I.Integration,n));return t.length>0&&g.debug(`[remote] Fetched ${t.length} integrations`),t}async getByInternalId(e,t){let n;if(n=await $.withClient(o=>o[Y[t].element](e).get(),!1),!!n)return F.fromData(t,n)}transformElementForCreate(e,t,n){if(e.integrationKey){const o=n.elements.find(i=>i.type===I.Integration&&i.key===e.integrationKey);if(o)t.integrationId=o.data.id;else throw new Error(`Dependency integration ${e.integrationKey} not found for ${e.id}`)}if(e.type===I.Integration){const o=n.connectorsMapping?.[t.connectorId];o&&(t.connectorId=o)}this.transformPackageDependencies(e,t,n),this.transformParentDependency(e,t,n)}transformElementForUpdate(e,t,n){if(e.type===I.Integration){const o=n.connectorsMapping?.[t.connectorId];o&&(t.connectorId=o)}if(e.integrationKey){t.integrationKey=e.integrationKey;const o=n.elements.find(i=>i.type===I.Integration&&i.key===e.integrationKey);if(o)t.integrationId=o.data.id;else throw new Error(`Dependency integration ${e.integrationKey} not found for ${e.id}`)}this.transformPackageDependencies(e,t,n),this.transformParentDependency(e,t,n)}transformPackageDependencies(e,t,n){if(e.type!==I.Package||!t.elements)return;const o=t.elements.map(i=>{const a=(n.sourceElements||n.elements).find(d=>d.data.id===i.id&&d.type===i.type);if(!a)throw new Error(`Package element ${i.type} with id ${i.id} not found in source workspace for package ${e.id}`);const l=n.elements.find(d=>d.type===i.type&&d.key===a.key&&d.integrationKey===a.integrationKey);if(!l)throw new Error(`Package element ${i.type} with key ${a.key} not found in target workspace for package ${e.id}`);return{id:l.data.id,type:i.type}});t.elements=o}transformParentDependency(e,t,n){if(!e.hasParent())return;const o=e.getParentKey();if(!o)return;const i=n.elements.find(s=>s.type===e.type&&s.key===e.key&&!s.hasParent());if(i)t[o]=i.data.id;else throw new Error(`Parent ${e.getParentKey()} not found for ${e.id}`)}async findAll(e,t={},n){const o=await $.withClient(i=>i[Y[e].elements].findAll(t));return o?o.filter(i=>i.key).map(i=>(n&&!i.integrationKey&&(i.integrationKey=n),F.fromData(e,i))):[]}}class It extends jr{static{c(this,"TypedEventEmitter")}on(e,t){return super.on(e,t)}emit(e,...t){return super.emit(e,...t)}off(e,t){return super.off(e,t)}once(e,t){return super.once(e,t)}}const W={Updated:"updated",Deleted:"deleted",Stopped:"stopped"},Fo={ignored:Qr,persistent:!0,ignoreInitial:!0,followSymlinks:!1,depth:20,awaitWriteFinish:{stabilityThreshold:500,pollInterval:100},ignorePermissionErrors:!0,atomic:!0,usePolling:!1,alwaysStat:!1,interval:1e3,binaryInterval:300};class Lo extends It{static{c(this,"LocalElementWatcher")}constructor(e){super(),this.options=e,this.membraneDir=q(this.options.cwd),this.lockTimeoutMs=this.options.lockTimeoutMs??1e3}isWatching=!1;watcher;membraneDir;contentCache={};ignoredPaths=new Set;lockTimeoutMs;async start(){this.isWatching||(v.existsSync(this.membraneDir)||v.mkdirSync(this.membraneDir,{recursive:!0}),this.initializeContentCache(),this.watcher=Fr.watch(this.membraneDir,Fo),this.watcher.on("add",e=>this.handleFileSystemEvent(W.Updated,e)).on("change",e=>this.handleFileSystemEvent(W.Updated,e)).on("unlink",e=>this.handleFileSystemEvent(W.Deleted,e)).on("ready",()=>this.isWatching=!0))}async stop(){!this.isWatching||!this.watcher||(await this.watcher.close(),this.isWatching=!1,this.watcher=void 0,this.clearCache(),this.clearAllLocks(),this.emit(W.Stopped))}getCwd(){return this.options.cwd}async executeWithPathLock(e,t){const n=x.resolve(e);this.ignoredPaths.add(n);try{await t()}finally{setTimeout(()=>{this.ignoredPaths.delete(n)},this.lockTimeoutMs)}}isPathLocked(e){const t=x.resolve(e);if(this.ignoredPaths.has(t))return!0;for(const n of this.ignoredPaths)if(t.startsWith(n+x.sep))return!0;return!1}clearAllLocks(){this.ignoredPaths.clear()}handleFileSystemEvent(e,t){const n=x.relative(this.membraneDir,t);if(this.isPathLocked(t))return;if(e===W.Deleted){this.removeFromCache(n);const a={filePath:t,relativePath:n,data:void 0};g.info(`[local] ${e}: ${a.relativePath}`),this.emit(e,a);return}const o=this.readFileContent(t);if(!this.hasContentChanged(n,o))return;const s=this.processFileEvent(t,o);this.updateCache(n,o),s&&(g.info(`[local] ${e}: ${s.relativePath}`),this.emit(e,s))}readFileContent(e){return v.readFileSync(e,"utf8")}processFileEvent(e,t){const n=x.relative(this.membraneDir,e);let o;try{o=t?Lr.parse(t):void 0}catch{o=void 0}return{filePath:e,relativePath:n,data:o}}hasContentChanged(e,t){if(!t)return this.contentCache[e]!==void 0;const n=this.getContentHash(t);return this.contentCache[e]!==n}getContentHash(e){return Nr.createHash("sha256").update(e).digest("hex")}updateCache(e,t){if(!t){delete this.contentCache[e];return}this.contentCache[e]=this.getContentHash(t)}removeFromCache(e){delete this.contentCache[e]}clearCache(){Object.keys(this.contentCache).forEach(e=>{delete this.contentCache[e]})}initializeContentCache(){v.existsSync(this.membraneDir)&&this.scanDirectoryForCache(this.membraneDir)}scanDirectoryForCache(e){const t=v.readdirSync(e,{withFileTypes:!0});for(const n of t){const o=x.join(e,n.name);if(n.isDirectory())this.scanDirectoryForCache(o);else if(n.isFile())try{const i=v.readFileSync(o,"utf8"),s=x.relative(this.membraneDir,o);this.updateCache(s,i)}catch{}}}}var kt=(r=>(r.Updated="updated",r.ConnectorFileUpdated="connector-file-updated",r.Connected="connected",r.Disconnected="disconnected",r.Error="error",r))(kt||{});const jo={debounceMs:2e3,reconnectIntervalMs:5e3,maxReconnectAttempts:1/0,maxBackoffMs:6e4,connectionTimeoutMs:3e5};class Uo extends It{static{c(this,"RemoteElementWatcher")}constructor(e=jo){super(),this.config=e}eventSource;debounceTimeouts=new Map;reconnectAttempts=0;reconnectTimeout;connectionTimeout;isStarted=!1;isConnected=!1;async start(){this.isStarted||(this.isStarted=!0,await this.connect())}async stop(){this.isStarted&&(this.isStarted=!1,this.isConnected=!1,this.clearReconnectTimeout(),this.clearConnectionTimeout(),this.clearAllDebounceTimeouts(),this.eventSource&&(this.eventSource.close(),this.eventSource=void 0))}async connect(){try{g.debug("[remote-events] Connecting to server"),this.eventSource&&(this.eventSource.close(),this.eventSource=void 0);const e=await $.getClient(process.cwd()),t=await e.getToken();if(!t)throw new Error("No auth token available");const n=`${e.apiUri}/sse/workspace?token=${encodeURIComponent(t)}`;g.debug("[remote-events] Subscribing to workspace events"),this.eventSource=new Ur(n),this.setupEventSourceHandlers()}catch(e){g.debug(`[remote-events] Failed to connect: ${e}`),this.emit("error",{error:e}),this.scheduleReconnect()}}setupEventSourceHandlers(){this.eventSource&&(this.eventSource.onopen=()=>{g.debug("[remote-events] Connected to server"),this.reconnectAttempts=0,this.isConnected=!0,this.resetConnectionTimeout(),this.emit("connected",{})},this.eventSource.onmessage=e=>{try{this.resetConnectionTimeout();const t=JSON.parse(e.data);this.handleElementUpdate(t)}catch(t){g.debug(`[remote-events] Failed to parse workspace event: ${t}`)}},this.eventSource.onerror=e=>{g.debug(`[remote-events] Connection error: ${JSON.stringify(e,null,2)}`),this.isConnected=!1,this.clearConnectionTimeout(),this.eventSource&&(this.eventSource.close(),this.eventSource=void 0),this.emit("disconnected",{}),this.isStarted&&this.scheduleReconnect()})}handleElementUpdate(e){if(e.type!==mr.ElementUpdate)return;const{elementId:t,elementType:n,data:o={}}=e;if(!(!t||!n)){if(n===I.Connector){const{filePath:i,eventType:s,newPath:a}=o;return g.debug(`[remote-watcher] Received connector event - elementId: ${t}, filePath: ${i}, eventType: ${s}`),this.scheduleConnectorFileUpdate(t,i,s,a)}return this.scheduleElementUpdate(t,n)}}scheduleElementUpdate(e,t){const n=this.debounceTimeouts.get(e);n&&clearTimeout(n);const o=setTimeout(()=>{this.debounceTimeouts.delete(e),this.emit("updated",{elementId:e,elementType:t})},this.config.debounceMs);this.debounceTimeouts.set(e,o)}scheduleConnectorFileUpdate(e,t,n,o){const i=JSON.stringify({connectorId:e,filePath:t}),s=this.debounceTimeouts.get(i);s&&clearTimeout(s);const a=setTimeout(()=>{this.debounceTimeouts.delete(i),this.emit("connector-file-updated",{connectorId:e,filePath:t,eventType:n,newPath:o})},this.config.debounceMs);this.debounceTimeouts.set(i,a)}scheduleReconnect(){if(!this.isStarted||this.reconnectAttempts>=this.config.maxReconnectAttempts){this.reconnectAttempts>=this.config.maxReconnectAttempts&&(g.error("[remote-events] Max reconnection attempts reached. Connection will not be retried."),this.emit("error",{error:new Error("Max reconnection attempts reached")}));return}this.reconnectTimeout&&clearTimeout(this.reconnectTimeout),this.reconnectAttempts++;const e=this.config.reconnectIntervalMs*Math.pow(2,this.reconnectAttempts-1),t=Math.random()*.3*e,n=Math.min(e+t,this.config.maxBackoffMs);g.debug(`[remote-events] Reconnecting in ${Math.round(n)}ms (attempt ${this.reconnectAttempts})`),this.reconnectTimeout=setTimeout(()=>{this.connect()},n)}clearReconnectTimeout(){this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=void 0)}resetConnectionTimeout(){this.clearConnectionTimeout(),this.connectionTimeout=setTimeout(()=>{this.isConnected&&this.isStarted&&(g.debug("[remote-events] Connection timeout detected, reconnecting..."),this.isConnected=!1,this.eventSource&&(this.eventSource.close(),this.eventSource=void 0),this.scheduleReconnect())},this.config.connectionTimeoutMs)}clearConnectionTimeout(){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=void 0)}clearAllDebounceTimeouts(){this.debounceTimeouts.forEach(e=>clearTimeout(e)),this.debounceTimeouts.clear()}}class An{static{c(this,"ElementsCache")}elements=new Map;typeIndex=new Map;internalIdIndex=new Map;constructor(e){e&&this.addAll(e)}add(e){const t=e.id;this.elements.set(t,e),this.typeIndex.has(e.type)||this.typeIndex.set(e.type,new Set),this.typeIndex.get(e.type).add(t),e.data?.id&&this.internalIdIndex.set(e.data.id,t)}remove(e){const t=e.id,n=this.elements.delete(t);if(n){const o=this.typeIndex.get(e.type);o&&(o.delete(t),o.size===0&&this.typeIndex.delete(e.type)),e.data?.id&&this.internalIdIndex.delete(e.data.id)}return n}put(e){this.elements.has(e.id)&&this.remove(e),this.add(e)}get(e){return this.elements.get(e)}getByInternalId(e){const t=this.internalIdIndex.get(e);if(t)return this.elements.get(t)}getElementsByType(e){const t=this.typeIndex.get(e);return t?Array.from(t).map(n=>this.elements.get(n)).filter(n=>n!==void 0):[]}getAll(){return Array.from(this.elements.values())??[]}getTypes(){return Array.from(this.typeIndex.keys())}addAll(e){for(const t of e)t&&this.add(t)}removeAll(e){for(const t of e)this.remove(t)}getElementIdsByType(e){return this.typeIndex.get(e)}clear(){this.elements.clear(),this.typeIndex.clear(),this.internalIdIndex.clear()}getAllIds(){return new Set(this.elements.keys())}}const be="connectors",ee="development",$t={};async function Rn(r={}){const{onProgress:e}=r,t=new Set,o=(await $.withClient(d=>d.get("org-workspace-id"))).id,i={};g.info("[connectors] Loading custom connectors"),await $.withClient(d=>d.get(`/connectors?workspaceId=${o}`)),g.info("[connectors] Loading public connectors");const s=re(),l=(A.existsSync(s)?A.readdirSync(s):[]).filter(d=>{if(d.startsWith("."))return!1;const h=k.join(s,d);try{return A.statSync(h).isDirectory()}catch{return!1}});for(const d of l){g.info(`[connectors] Loading connector from: ${d}`);const h=A.readdirSync(k.join(s,d)),f=await Pt(d);if(!f)continue;e?.("pushing",f.name),"baseUri"in f&&delete f.baseUri;let p;f.uuid&&(p=await $.withClient(S=>S.get(`/connectors/${f.uuid}`),!1));const C=f.uuid;if(p)i[C]=p.id,g.info(`[connectors] Matched ${f.name} uuid: ${f.uuid}`),p.isPublic||(p.archivedAt&&(g.info(`[connectors] Restoring archived connector ${f.name}`),await $.withClient(S=>S.post(`connectors/${p.id}/restore`))),g.info(`[connectors] Updating connector ${f.name}`),await $.withClient(S=>S.patch(`connectors/${p.id}`,{...f,workspaceId:o})));else if(!i[C]&&!p?.isPublic){let S=!1;try{const R=await At({connectorId:C});R&&R.isPublic&&(S=!0)}catch{}if(!S){g.info(`[connectors] Creating custom connector ${f.name} (${f.key})`);const R=await $.withClient(O=>O.post("connectors",{...f,workspaceId:o}));i[C]=R.id}}const E=h.filter(S=>A.statSync(k.join(s,d,S)).isDirectory());for(const S of E)await qo({connector:f,version:S,connectorId:i[C]}),t.add(C);e?.("pushed",f.name)}return{connectorsMapping:i,pushedConnectors:Array.from(t)}}c(Rn,"pushConnectors");async function On({connectorId:r,connectorVersion:e,allConnectors:t,pulledConnectors:n,pulledConnectorVersions:o}){if(!r||o[r]?.has(e))return;const i=un(),s=await At({connectorId:r});if(!s.isPublic||t){if(!s?.key){console.error(`[connectors] Connector ${r} has no key. Skipping..`),g.error(`[connectors] Connector ${r} has no key. Skipping..`);return}n.has(r)||(await Bo({basePath:i,connector:s}),n.add(r)),o[r]||(o[r]=new Set),o[r].has(e)||(await Wo({connector:s,connectorVersion:e,basePath:i}),o[r].add(e))}}c(On,"pullRemoteConnector");function re(){const r=ft();return k.join(r.membraneDirPath,be)}c(re,"getConnectorsPath");async function Pt(r){const e=k.join(re(),r,`${r}.yml`);return xt(e,!1)}c(Pt,"readConnector");async function Ko(r,e){return g.info(`[connectors] Zipping ${r} into ${e}`),new Promise((t,n)=>{const o=A.createWriteStream(e),i=ot("zip",{zlib:{level:9}});o.on("close",()=>{g.success(`[connectors] Successfully created ${e}`),t()}),o.on("end",()=>{g.info("[connectors] Data has been drained")}),i.on("warning",a=>{a.code==="ENOENT"?console.warn(a):n(a)}),i.on("error",a=>{n(a)}),i.pipe(o);const s=A.readdirSync(r);for(const a of s){const l=k.join(r,a),d=A.statSync(l);d.isFile()?i.file(l,{name:a}):d.isDirectory()&&i.directory(l,a)}i.finalize()})}c(Ko,"createZipArchive");async function _o(r,e){return g.info(`[connectors] Unzipping into ${e}`),new Promise((t,n)=>{const o=je.Parse();o.on("entry",i=>{const s=i.path;if(i.type==="Directory"){const l=k.join(e,s);A.mkdirSync(l,{recursive:!0}),i.autodrain()}else{const l=k.join(e,s),d=k.dirname(l);A.mkdirSync(d,{recursive:!0});const h=A.createWriteStream(l);i.pipe(h),h.on("finish",()=>{})}}),o.on("end",()=>{g.success(`[connectors] Successfully extracted to ${e}`),t()}),o.on("error",i=>{n(i)}),o.write(r),o.end()})}c(_o,"extractZipArchive");async function qo({connector:r,version:e,connectorId:t}){const n=k.join(re(),te(r),Dn(e)),o=k.join(n,"src"),i=k.join(n,"src.zip"),s=A.existsSync(i);if(A.existsSync(o)&&(g.info(`[connectors] Archiving source code for ${r.name} version ${e}`),await Ko(o,i)),!A.existsSync(i)){g.warning(`[connectors] No source code found for ${r.name} version ${e}`);return}try{const a=new en;if(a.append("file",A.createReadStream(i),"file.zip"),g.info(`[connectors] Pushing connector version ${e} for ${r.name}`),e==ee)g.info(`[connectors] Uploading connector ${t}`),await $.withClient(l=>l.post(`connectors/${t}/upload`,a,{headers:{...a.getHeaders()}}));else{if(a.append("version",e),a.append("changelog","Imported Version"),(await $.withClient(d=>d.get(`/connectors/${t}/versions`))).find(d=>d.version==e)){g.info(`[connectors] Version ${e} already published`);return}g.info(`[connectors] Publishing version ${e} of connector ${t}`),await $.withClient(d=>d.post(`connectors/${t}/publish-version`,a,{headers:{...a.getHeaders()}}))}g.success(`Successfully pushed connector version ${e} for ${r.name}`)}catch(a){g.error(`Error pushing connector version ${e} for ${r.name}: ${a}`),console.error(`[connectors] Error pushing connector version ${e} for ${r.name}: ${a}`)}finally{!s&&A.existsSync(i)&&(g.info(`[connectors] Cleaning up temporary zip file for ${r.name} version ${e}`),A.unlinkSync(i))}}c(qo,"pushConnectorVersion");async function At({connectorId:r}){if(r){if($t[r])return $t[r];try{const e=await $.withClient(t=>t.get(`connectors/${r}`),!1);return $t[r]=e,e}catch(e){return g.error(`[connectors] Failed to get connector ${r}: ${e}`),console.error(`[connectors] Failed to get connector ${r}: ${e}`),null}}}c(At,"getConnector");async function Bo({basePath:r,connector:e}){const t=te(e),n=k.join(r,be,t);A.mkdirSync(n,{recursive:!0});const o=k.join(n,`${te(e)}.yml`);A.writeFileSync(o,H.dump(e)),g.info(`[connectors] Pulled connector ${e.name}`)}c(Bo,"pullConnector$1");async function Wo({connector:r,connectorVersion:e,basePath:t}){const n=te(r),o=Dn(e),i=k.join(t,"connectors",n,o),s=await $.withClient(l=>l.get(`connectors/${r.id}/download`,{version:e},{responseType:"arraybuffer",headers:{Accept:"application/zip"},timeout:1e6}));A.mkdirSync(i,{recursive:!0});const a=k.join(i,"src.zip");if(A.writeFileSync(a,s),!e){const l=k.join(i,"src");A.mkdirSync(l,{recursive:!0}),await _o(s,l)}g.info(`[connectors] Pulled connector version: ${r.name} (${o})`)}c(Wo,"pullConnectorVersion");function te(r){return r.key}c(te,"getConnectorDirName");function Dn(r){return r??ee}c(Dn,"getConnectorVersionDirName");function Jo(r){const e=un(),t=te(r);return k.join(e,be,t)}c(Jo,"getConnectorDirPath");function zo(r){return r.match(`${be}/[^/]+/${ee}/src/.*`)!==null}c(zo,"isConnectorSourceFile");async function Ho(r){const e=r.match(`${be}/([^/]+)/${ee}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await Pt(t);if(!o){g.warning(`[connectors] Connector ${t} not found. Ignoring file change`);return}const i=o.id,s=A.readFileSync(r,"utf-8");await $.withClient(a=>a.put(`connectors/${i}/files/${n}`,s,{headers:{"Content-Type":"text/plain"}})),g.info(`[connectors] Pushed file ${n} for connector ${o.name}`)}c(Ho,"putConnectorFile");async function Go(r){const e=r.match(`${be}/([^/]+)/${ee}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await Pt(t);if(!o){g.warning(`[connectors] Connector ${t} not found. Ignoring file change`);return}const i=o.id;await $.withClient(s=>s.delete(`connectors/${i}/files/${n}`)),g.info(`[connectors] Deleted file ${n} for connector ${o.name}`)}c(Go,"deleteConnectorFile");async function Vo(r,e){try{const t=await $.withClient(s=>s.get(`connectors/${r}`));if(!t){g.warning(`[connectors] Connector ${r} not found`);return}const n=await $.withClient(s=>s.get(`connectors/${r}/files/${e}`)),o=te(t),i=k.join(re(),o,ee,"src",e);A.mkdirSync(k.dirname(i),{recursive:!0}),n!=null?(A.writeFileSync(i,n),g.info(`[connectors] Pulled file ${e} for connector ${t.name}`)):A.existsSync(i)&&(A.unlinkSync(i),g.info(`[connectors] Deleted file ${e} for connector ${t.name}`))}catch(t){g.error(`[connectors] Failed to pull connector file ${e} for connector ${r}: ${t}`),console.error(`[connectors] Failed to pull connector file ${e} for connector ${r}: ${t}`)}}c(Vo,"pullConnectorFile");async function Yo(r,e){const t=await $.withClient(i=>i.get(`connectors/${r}`),!1);if(!t){g.warning(`[connectors] Connector ${r} not found`);return}const n=te(t),o=k.join(re(),n,ee,"src",e);A.existsSync(o)&&(A.unlinkSync(o),g.info(`[connectors] Deleted file ${e} for connector ${n}`))}c(Yo,"deleteLocalConnectorFile");async function Zo(r,e,t){if(t&&e!==t)try{const n=await $.withClient(l=>l.get(`connectors/${r}`),!1);if(!n){g.warning(`[connectors] Connector ${r} not found`);return}const o=te(n),i=k.join(re(),o,ee,"src"),s=k.join(i,e),a=k.join(i,t);A.existsSync(s)&&(A.mkdirSync(k.dirname(a),{recursive:!0}),A.renameSync(s,a),g.info(`[connectors] Renamed directory from ${e} to ${t} for connector ${o}`))}catch(n){g.error(`[connectors] Failed to rename directory ${e} to ${t} for connector ${r}: ${n}`)}}c(Zo,"renameLocalConnectorDirectory");async function Xo(r,e){try{const t=await $.withClient(i=>i.get(`connectors/${r}`),!1);if(!t){g.warning(`[connectors] Connector ${r} not found`);return}const n=te(t),o=k.join(re(),n,ee,"src",e);if(A.existsSync(o)){const i=k.resolve(re());if(!k.resolve(o).startsWith(i))return;A.rmSync(o,{recursive:!0,force:!0}),g.info(`[connectors] Deleted directory ${e} for connector ${n}`)}}catch(t){g.error(`[connectors] Failed to delete directory ${e} for connector ${r}: ${t}`)}}c(Xo,"deleteLocalConnectorDirectory");const j={LogAdded:"logAdded",StateChanged:"stateChanged",StatsChanged:"statsChanged",ConflictsChanged:"conflictsChanged",McpStatusChanged:"mcpStatusChanged",McpServersChanged:"mcpServersChanged",ConfigChanged:"configChanged"};class Qo extends It{static{c(this,"WorkspaceNotifications")}constructor(e){super(),this.config=e,g.setNotificationHandler(this)}clientId;heartbeatInterval;isCleaningUp=!1;async connectToRemote(){await this.registerWithRemoteServer(),await this.startHeartbeatLoop()}async setState(e){this.emit(j.StateChanged,{state:e}),await this.emitRemote({status:e})}setConflicts(e){this.emit(j.ConflictsChanged,{conflicts:e})}setConfig(e){this.emit(j.ConfigChanged,{config:e})}setStats(e){this.emit(j.StatsChanged,{stats:e})}addLog(e){this.emit(j.LogAdded,{log:e})}setMcpStatus(e){this.emit(j.McpStatusChanged,{status:e})}async setMcpServers(e){this.emit(j.McpServersChanged,{servers:e}),await this.emitRemote({mcpServers:e.map(t=>({name:t.agentName,totalRequests:t.totalRequests}))})}async cleanup(){!this.clientId||this.isCleaningUp||(this.isCleaningUp=!0,this.heartbeatInterval&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=void 0),await this.withErrorHandling(async()=>{await $.withClient(e=>e.delete(`/local-clients/${this.clientId}`))}),this.clientId=void 0)}async registerWithRemoteServer(){if(this.clientId)return;const e=await this.withErrorHandling(async()=>await $.withClient(t=>t.post("/local-clients",{hostname:tt.hostname(),workingDirectory:process.cwd()})));e?.id?this.clientId=e.id:this.addLog({timestamp:new Date().toISOString(),message:"Failed to register with remote server",type:"error"})}async startHeartbeatLoop(){this.heartbeatInterval=setInterval(async()=>{this.clientId&&await this.sendHeartbeat()},this.config.heartbeatIntervalMs)}async sendHeartbeat(){this.clientId&&await this.withErrorHandling(async()=>{await $.withClient(e=>e.post(`/local-clients/${this.clientId}/keep-alive`,{}))})}async emitRemote(e){this.clientId&&await this.withErrorHandling(async()=>{await $.withClient(t=>t.patch(`/local-clients/${this.clientId}`,e))})}async withErrorHandling(e){try{return await e()}catch(t){const n=t instanceof Error?t.message:String(t);return this.addLog({timestamp:new Date().toISOString(),message:`Failed to connect to remote: ${n}`,type:"error"}),null}}}const oe=new Qo({heartbeatIntervalMs:15e3}),Nn=[I.AppDataSchema,I.AppEventType,I.DataLinkTable,I.DataSource,I.FieldMapping,I.Action,I.Flow,I.Package];class De{static{c(this,"ElementSyncService")}localWatcher=void 0;remoteWatcher=void 0;notifier;changes=[];localCache;remoteCache;localRepo;remoteRepo;pulledConnectors=new Set;pulledConnectorVersions={};constructor(){this.notifier=oe,this.localCache=new An,this.remoteCache=new An,this.localRepo=new No(this.localCache),this.remoteRepo=new Mo(this.remoteCache)}clear(){this.changes=[]}needsForcedSync(){return this.changes.some(e=>e.isConflict)}needsSync(){return this.changes.length>0}async getStats(){const e=this.localCache.getAll(),t={};return e.forEach(n=>{t[n.type]=(t[n.type]||0)+1}),t}async fetchElements(){const e=await this.localRepo.getElements(),t=await this.remoteRepo.getElements();this.localCache.addAll(e),this.remoteCache.addAll(t)}async updateElement(e,t){const n=this.getHandler(t),o=this.getCache(t);try{const i=await n.putElement(e);o.put(i)}catch(i){throw g.error(`Failed to update element ${e.id}: ${i}`),i}}async deleteElement(e,t){const n=this.getHandler(t),o=this.getCache(t);try{await n.deleteElement(e,{elements:n.cache.getAll(),connectorsMapping:n.connectorsMapping}),o.remove(e)}catch(i){throw g.error(`Failed to delete element ${e.id}: ${i}`),i}}async pullConnectors(e=!1){const t=this.remoteCache.getElementsByType(I.Integration).map(n=>n.data);for(const n of t){const o=n.connectorId,i=n.connectorVersion;o&&await On({connectorId:o,connectorVersion:i,allConnectors:e,pulledConnectors:this.pulledConnectors,pulledConnectorVersions:this.pulledConnectorVersions})}}async pushConnectors(){const{connectorsMapping:e}=await Rn();this.remoteRepo.setConnectorsMapping(e)}getHandler(e){return e===B.INCOMING?this.localRepo:(this.remoteRepo.setSourceCache(this.localCache),this.remoteRepo)}getCache(e){return e===B.INCOMING?this.localCache:this.remoteCache}async startWatching(){this.localWatcher=new Lo({cwd:process.cwd(),lockTimeoutMs:1e3}),this.localWatcher.on(W.Updated,e=>this.handleLocalEvent(e,W.Updated)),this.localWatcher.on(W.Deleted,e=>this.handleLocalEvent(e,W.Deleted)),await this.localWatcher.start(),g.success("[local] Tracking changes.."),this.remoteWatcher=new Uo,this.remoteWatcher.on(kt.Updated,({elementId:e,elementType:t})=>this.handleRemoteElementEvent(e,t)),this.remoteWatcher.on(kt.ConnectorFileUpdated,({connectorId:e,filePath:t,eventType:n,newPath:o})=>this.handleRemoteConnectorFileEvent(e,t,n,o)),await this.remoteWatcher.start(),g.success("[remote] Tracking changes..")}async stopWatching(){this.localWatcher&&(await this.localWatcher.stop(),this.localWatcher=void 0),this.remoteWatcher&&(await this.remoteWatcher.stop(),this.remoteWatcher=void 0)}async handleRemoteElementEvent(e,t){try{const n=await this.remoteRepo.getByInternalId(e,t),o=!!n?.data.archivedAt||!!n?.data.isDeactivated;if(!n||o){const s=n||this.remoteCache.getByInternalId(e);return s?(g.info(`[${this.getDirectionLabel(B.INCOMING)}] Deleted: ${s.id}`),this.localWatcher?.executeWithPathLock(s.absolutePath,()=>this.deleteElement(s,B.INCOMING))):void 0}if(g.info(`[${this.getDirectionLabel(B.INCOMING)}] Updated: ${n.id}`),await this.localWatcher?.executeWithPathLock(n.absolutePath,async()=>this.updateElement(n,B.INCOMING)),t===I.Integration){const s=n.data.connectorId,a=n.data.connectorVersion,l=await At({connectorId:s});if(!l?.key)return;const d=Jo(l);await this.localWatcher?.executeWithPathLock(d,async()=>On({connectorId:s,connectorVersion:a,allConnectors:!1,pulledConnectors:this.pulledConnectors,pulledConnectorVersions:this.pulledConnectorVersions}))}}catch(n){g.error(`[sync] Error handling remote event: ${n}`)}}async handleRemoteConnectorFileEvent(e,t,n,o){try{switch(n){case Ye.ConnectorFileDeleted:await Yo(e,t);break;case Ye.ConnectorDirectoryRenamed:await Zo(e,t,o);break;case Ye.ConnectorDirectoryDeleted:await Xo(e,t);break;default:await Vo(e,t);break}}catch(i){g.error(`[sync] Error handling remote connector file event: ${i}`)}}async handleLocalEvent(e,t){try{if(zo(e.filePath))switch(t){case W.Updated:await Ho(e.filePath);break;case W.Deleted:await Go(e.filePath);break}else{let n=F.fromPathAndData(e.filePath,e.data);if(!n){const o=F.idFromPath(e.filePath);if(!o||(n=this.remoteCache.get(o),!n))return}switch(g.info(`[${this.getDirectionLabel(B.OUTGOING)}] ${Or(t)}: ${n.id}`),t){case W.Updated:await this.updateElement(n,B.OUTGOING);break;case W.Deleted:await this.deleteElement(n,B.OUTGOING);break}}}catch(n){g.error(`[sync] Error handling local event: ${n}`)}}detectIncomingChanges(){this.clearChanges();const e=De.getChanges(B.INCOMING,this.remoteCache,this.localCache);return this.updateChanges(e),e}detectOutgoingChanges(){this.clearChanges();const e=De.getChanges(B.OUTGOING,this.localCache,this.remoteCache);return this.updateChanges(e),e}async resolveChanges(){if(!this.needsSync())return;g.info("[resolver] Resolving changes.."),g.info("[resolver] Resolving integration elements");const e=this.changes.filter(o=>o.element.type===I.Integration);await Promise.all(e.map(async o=>this.resolveChange(o))),e.length>0&&(await this.fetchElements(),this.changes=this.changes.length>0&&this.changes[0]?.direction===B.INCOMING?this.detectIncomingChanges():this.detectOutgoingChanges(),this.changes=this.changes.filter(o=>o.element.type!==I.Integration)),g.info("[resolver] Resolving universal elements");const t=this.changes.filter(o=>!o.element.hasParent());for(const o of Nn){const i=t.filter(s=>s.element.type===o);g.info(`[resolver] Resolving ${o} elements`),await Promise.all(i.map(async s=>this.resolveChange(s)))}g.info("[resolver] Resolving integration level elements");const n=this.changes.filter(o=>o.element.hasParent());for(const o of Nn){const i=n.filter(s=>s.element.type===o);g.info(`[resolver] Resolving ${o} elements`),await Promise.all(i.map(async s=>this.resolveChange(s)))}g.success("[resolver] Resolved changes")}async resolveChange(e){switch(e.type){case Q.DELETE:return this.deleteElement(e.element,e.direction);case Q.CREATE:return this.updateElement(e.element,e.direction);case Q.UPDATE:return this.updateElement(e.element,e.direction)}}static getChanges(e,t,n){const o=t.getAllIds(),i=n.getAllIds(),s=new Set([...o,...i]),a=[];for(const l of s){const d=t.get(l),h=n.get(l),f=De.detectChangeForElement(d,h,e);f&&a.push(f)}return a}updateChanges(e){if(this.changes=e,this.needsForcedSync()){const t=e.filter(n=>n.isConflict);g.warning("[resolver] Conflicts detected"),this.notifier.setConflicts(t)}}clearChanges(){this.changes=[]}getDirectionLabel(e){switch(e){case B.INCOMING:return"local\u2190remote";case B.OUTGOING:return"local\u2192remote"}}static detectChangeForElement(e,t,n){return e&&!t?{type:Q.CREATE,element:e,direction:n,isConflict:!1}:!e&&t?{type:Q.DELETE,element:t,direction:n,isConflict:!0}:e&&t&&!e.isEqual(t)?{type:Q.UPDATE,element:e,direction:n,isConflict:!1}:null}}const ie=x.join(Kr.tmpdir(),"membrane-mcp-status"),Mn=3e4;class ei{static{c(this,"McpStatusService")}constructor(e=2e3){this.pollIntervalMs=e}isRunning=!1;pollInterval;async start(){this.isRunning||(this.isRunning=!0,this.pollInterval=setInterval(async()=>await this.checkStatus(),this.pollIntervalMs),await this.checkStatus())}async stop(){this.pollInterval&&(clearInterval(this.pollInterval),this.pollInterval=void 0,this.isRunning=!1)}async checkStatus(){try{const e=process.cwd(),t=We(void 0,e),n=Fn(e);t&&oe.setMcpStatus(t),await oe.setMcpServers(n)}catch{g.error("Failed to check MCP status")}}}function We(r,e){try{const t=e||process.cwd();if(!r){const o=Fn(t);return o.length===0?null:o[0]}const n=Dt(r,t);if(v.existsSync(n)){const o=v.statSync(n),i=new Date;if(i.getTime()-o.mtime.getTime()>Mn)return Re(r,t),null;const a=v.readFileSync(n,"utf8"),l=JSON.parse(a);if(l.isRunning){const d=new Date(l.lastActivity).getTime();if(i.getTime()-d>Mn)return Re(r,t),null}return l}}catch{r&&e&&Re(r,e)}return null}c(We,"getMcpStatus");function Fn(r){try{const e=r||process.cwd(),t=Ot(e);if(!v.existsSync(ie))return[];const n=v.readdirSync(ie),o=[];for(const i of n){const s=i.match(new RegExp(`^mcp-${t}-(\\d+)\\.json$`));if(s){const a=parseInt(s[1],10),l=We(a,e);l&&o.push(l)}}return o.sort((i,s)=>new Date(s.startTime).getTime()-new Date(i.startTime).getTime())}catch{return[]}}c(Fn,"getAllMcpStatusFiles");function Rt(r){try{const t={...We(r.processId,r.cwd)||{isRunning:!1,startTime:new Date().toISOString(),lastActivity:new Date().toISOString(),toolsCount:0,totalRequests:0,processId:r.processId,cwd:r.cwd,agentName:process.env.AGENT_NAME||"Unnamed Agent"},...r};v.existsSync(ie)||v.mkdirSync(ie,{recursive:!0});const n=Dt(r.processId,r.cwd);v.writeFileSync(n,JSON.stringify(t,null,2))}catch{}}c(Rt,"updateMcpStatus");function Re(r,e){try{const t=e||process.cwd();if(r){const n=Dt(r,t);v.existsSync(n)&&v.unlinkSync(n)}else{const n=Ot(t);if(v.existsSync(ie)){const o=v.readdirSync(ie);for(const i of o)i.match(new RegExp(`^mcp-${n}-\\d+\\.json$`))&&v.unlinkSync(x.join(ie,i))}}}catch{}}c(Re,"clearMcpStatus");function ti(r,e){const t=We(r,e);t&&Rt({processId:r,cwd:e,totalRequests:t.totalRequests+1,lastRequestTime:new Date().toISOString(),lastActivity:new Date().toISOString()})}c(ti,"trackToolExecution");function Ot(r){return Mr("md5").update(r).digest("hex").slice(0,8)}c(Ot,"getCwdHash");function Dt(r,e){const t=Ot(e);return x.join(ie,`mcp-${t}-${r}.json`)}c(Dt,"getStatusFilePath");const Je={Agent:"agent",Cli:"cli"},P={NOT_INITIALIZED:"not_initialized",SETTING_UP:"setting_up",INITIALIZED:"initialized",NOT_SYNCED:"not_synced",PULLING:"pulling",PUSHING:"pushing",RESOLVING:"resolving",CONFLICTS:"conflicts",SYNCED:"synced",WATCHING:"watching",ERROR:"error"};class ni{static{c(this,"MembraneCLIService")}constructor(e,t,n=()=>process.exit(0)){this.mode=e,this.cwd=t,this.onShutdown=n,this.notifier=oe,this.mcpStatusService=new ei,this.syncService=new De,this.setupProcessCleanup()}initialized=!1;notifier;mcpStatusService;syncService;isShuttingDown=!1;currentConfig=null;get config(){return this.currentConfig}getSyncedElements(){return this.syncService.localCache.getAll()}getSyncedElementsByType(e){return this.syncService.localCache.getElementsByType(e)}async fetchElements(){await this.syncService.fetchElements()}async pullWorkspace(e={}){let t=!1;try{if(g.setVerboseMode(!!e.verbose),e.rps!==void 0&&$.init({maxRequestsPerSecond:e.rps}),await this.notifier.setState(P.PULLING),await this.syncService.fetchElements(),this.syncService.detectIncomingChanges(),this.syncService.needsForcedSync()&&!e.force){await this.notifier.setState(P.CONFLICTS),e.watch||(t=!0);return}await this.syncService.pullConnectors(e.allConnectors),await this.syncWorkspaces(e)}catch(n){t=!0,g.error(`Failed to pull workspace: ${n}`),await this.notifier.setState(P.ERROR),g.saveLogsToFile("error")}finally{if(e.saveLogs&&g.saveLogsToFile(),t)process.exit(1);else return e?.onComplete?.()}}async pushWorkspace(e={}){let t=!1;try{if(g.setVerboseMode(!!e.verbose),e.rps!==void 0&&$.init({maxRequestsPerSecond:e.rps}),await this.notifier.setState(P.PUSHING),await this.syncService.fetchElements(),this.syncService.detectOutgoingChanges(),this.syncService.needsForcedSync()&&!e.force){await this.notifier.setState(P.CONFLICTS),e.watch||(t=!0);return}await this.syncService.pushConnectors(),await this.syncWorkspaces(e)}catch(n){t=!0,g.error(`Failed to push workspace: ${n}`),await this.notifier.setState(P.ERROR),g.saveLogsToFile("error")}finally{if(e.saveLogs&&g.saveLogsToFile(),t)process.exit(1);else return e?.onComplete?.()}}async syncWorkspaces(e={}){try{e.verbose!==void 0&&g.setVerboseMode(!!e.verbose),await this.notifier.setState(P.RESOLVING),this.syncService.needsSync()&&await this.syncService.resolveChanges();const t=await this.syncService.getStats();this.notifier.setStats(t),await this.notifier.setState(P.SYNCED),e.watch&&(await this.notifier.setState(P.WATCHING),await this.syncService.startWatching())}catch(t){g.error(`Failed to sync local and remote workspaces: ${t}`),await this.notifier.setState(P.ERROR),g.saveLogsToFile("error")}}async init({force:e=!1}={}){if(!(this.initialized&&!e)){await this.notifier.setState(P.NOT_INITIALIZED);try{await this.loadConfig(),pe.isCacheDefined()?(await this.initServices(),this.initialized=!0,await this.notifier.setState(P.INITIALIZED)):(this.initialized=!1,await this.notifier.setState(P.SETTING_UP))}catch(t){g.error(`Failed to initialize services: ${t}`),await this.notifier.setState(P.ERROR),g.saveLogsToFile("error"),this.onShutdown()}}}async loadConfig(){this.currentConfig=pe.loadConfig(this.cwd),this.notifier.setConfig(this.currentConfig)}async updateConfig(e){const t={...this.currentConfig,...e};if(!(JSON.stringify(t)!==JSON.stringify(this.currentConfig)))return;await this.stopServices();const o=pe.updateConfig(t);this.currentConfig=o,await this.init({force:!0})}async shutdown(){!this.initialized||this.isShuttingDown||(this.isShuttingDown=!0,this.mode===Je.Agent&&(await this.notifier.cleanup(),await this.mcpStatusService.stop()),this.initialized=!1,this.onShutdown())}async initServices(){this.mode===Je.Agent&&(await this.notifier.connectToRemote(),await this.mcpStatusService.start()),this.syncService.clear()}async stopServices(){this.mode===Je.Agent&&(await this.notifier.cleanup(),await this.mcpStatusService.stop())}setupProcessCleanup(){["SIGINT","SIGTERM","uncaughtException","unhandledRejection"].forEach(t=>process.on(t,()=>this.shutdown())),process.on("beforeExit",t=>{t===0&&this.shutdown()})}}const Ln=at(null);function ri({children:r,membraneCLIService:e}){const{data:t}=on("/account"),[n,o]=N(P.NOT_INITIALIZED),[i,s]=N([]),[a,l]=N({}),[d,h]=N([]),[f,p]=N(null),E=t?.workspaces?.find(S=>S.workspaceKey===f?.workspaceKey)||null;return we(()=>{const S=c(({state:M})=>o(M),"handleStateChanged"),R=c(({stats:M})=>l(M),"handleStatsChanged"),O=c(({log:M})=>h(ye=>[...ye,M]),"handleLogAdded"),U=c(({conflicts:M})=>s(M),"handleConflictsUpdated"),L=c(({config:M})=>p(M),"handleConfigChanged");return e.notifier.on(j.StateChanged,S),e.notifier.on(j.StatsChanged,R),e.notifier.on(j.LogAdded,O),e.notifier.on(j.ConflictsChanged,U),e.notifier.on(j.ConfigChanged,L),e.init(),()=>{e.notifier.off(j.StateChanged,S),e.notifier.off(j.StatsChanged,R),e.notifier.off(j.LogAdded,O),e.notifier.off(j.ConflictsChanged,U),e.notifier.off(j.ConfigChanged,L)}},[]),u(Ln.Provider,{value:{state:n,stats:a,logs:d,currentWorkspace:E,conflicts:i,config:f,updateConfig:c(S=>e.updateConfig(S),"updateConfig"),resolveConflicts:c(S=>e.syncWorkspaces(S),"resolveConflicts"),pull:c(S=>e.pullWorkspace(S),"pull"),push:c(S=>e.pushWorkspace(S),"push"),exit:c(()=>e.shutdown(),"exit"),fetchElements:c(()=>e.fetchElements(),"fetchElements"),getSyncedElementsByType:c(S=>e.getSyncedElementsByType(S),"getSyncedElementsByType")},children:r})}c(ri,"MembraneCLIServiceProvider");function G(){const r=ct(Ln);if(!r)throw new Error("useMembraneCLIService must be used within MembraneCLIServiceProvider");return r}c(G,"useMembraneCLIService");const Nt=at(null),jn=c(()=>{const r=ct(Nt);if(!r)throw new Error("useTree must be used within TreeView");return r},"useTree"),oi=c(r=>de.Children.count(r)>0,"hasChildren");function ii(r){const e=jn(),{label:t,value:n,isInitiallyExpanded:o}=r,i=Pr(),s=lt(e.registerChildItem(t)).current,a=e.isActiveByRef(s),[l,d]=N(o??!1),h={props:r,ref:s,id:i,active:a,expanded:l,setExpanded:d,label:t,value:n,isInitiallyExpanded:o,isParent:!1},{children:f}=r,p=typeof f=="function"?f(h):f;return{...h,props:{...r,children:p},isParent:oi(p)}}c(ii,"useTreeItem");function ve(r){const e=jn(),t=ii(r),{expanded:n,isParent:o,props:{children:i},setExpanded:s}=t,{renderValue:a=ai}=r,l=t.ref;Fe(()=>{function p(C){return r.onInput?.(C)?!0:C.active&&C.key.rightArrow&&!n?(s(!0),!0):C.active&&C.key.leftArrow&&n?(s(!1),!0):!1}c(p,"onInput"),l.onInput=p},[l,r.onInput,n,s]),l.firstChild??={parent:l,index:0};let d=l.firstChild;function h(p){const C=d;return C.nextSibling||(C.nextSibling={parent:l,prevSibling:C,index:C.index+1}),d=C.nextSibling,C.label=p,C}c(h,"registerChildItem");function f(){l.lastRenderedChild=d.prevSibling}return c(f,"commitChildren"),Fe(()=>{f()}),b(Le,{children:[b(y,{marginLeft:e.depth*2,children:[u(y,{width:2,children:o&&u(w,{children:n?"\u25BC":"\u25B6"})}),si(t),a(t)]}),n&&u(Nt.Provider,{value:{...e,depth:e.depth+1,registerChildItem:h},children:i})]})}c(ve,"TreeItem");function si({active:r,label:e}){return u(y,{width:32,children:u(w,{inverse:r,children:e})})}c(si,"defaultRenderLabel");function ai(r){return u(w,{})}c(ai,"defaultRenderValue");const me=c(({label:r,onPress:e,hotkey:t})=>u(ve,{label:r,onInput:c(({input:n,key:o,active:i})=>i&&o.return||t&&t in o&&o[t]||n===t?(e(),!0):!1,"onInput"),renderValue:c(()=>u(y,{children:u(w,{children:`${t?` (${t})`:""}`})}),"renderValue")}),"ActionTreeItem"),Un=c(({label:r,value:e,onChange:t,disabled:n=!1,mask:o,...i})=>{const[s,a]=N(e),[l,d]=N(!1);return Fe(()=>{l||a(e)},[l,e]),u(ve,{label:r,value:e,onInput:c(({key:h,active:f})=>n?!1:l?(h.escape&&d(!1),h.return&&(t(s),d(!1)),!0):f&&h.return?(d(!0),a(e),!0):!1,"onInput"),renderValue:c(()=>{const h=s,f=o?o.repeat(h.length):h;return u(y,{children:n||!l?u(w,{dimColor:!0,children:f}):b(Le,{children:[u(y,{width:f.length+1,children:u(sn,{...i,focus:l,value:h,onChange:a})}),u(w,{dimColor:!0,children:" \u241B cancel"})]})})},"renderValue")})},"TreeTextField"),ci=c(r=>u(Un,{...r,mask:"*"}),"SecretField"),J=c(({children:r,showHelp:e=!1})=>{const t=lt({parent:void 0,label:"<<ROOT>>",index:0}),[n,o]=N(t.current),i={depth:0,isActiveByRef:c(a=>n===a,"isActiveByRef"),registerChildItem:c(()=>t.current,"registerChildItem"),activeItemRef:n};Fe(()=>{o(a=>a.parent?a.parent.lastRenderedChild&&a.index>a.parent.lastRenderedChild.index?a.parent.lastRenderedChild:a:t.current.firstChild??t.current)});function*s(a){a&&(yield a,yield*s(a.firstChild),a.nextSibling&&a!==a.parent?.lastRenderedChild&&(yield*s(a.nextSibling)))}return c(s,"walkTree"),he((a,l)=>{if(n.onInput?.({input:a,key:l,active:!0}))return;let d,h;for(const f of s(t.current))if(f.label!=null){if(d===n&&(h=f),f&&f.onInput?.({input:a,key:l,active:f===n}))return;d=f}l.upArrow?o(f=>f.prevSibling?.lastRenderedChild??f.prevSibling??f.parent??t.current):l.downArrow?o(f=>h??f):l.pageUp?o(()=>t.current.firstChild??t.current):l.pageDown?o(()=>t.current.lastRenderedChild??t.current):l.tab?console.debug({label:n.label,nextSibling:n.nextSibling?.label,prevSibling:n.prevSibling?.label,parent:n.parent?.label,firstChild:n.firstChild?.label,lastRenderedChild:n.lastRenderedChild?.label}):l.leftArrow?o(f=>f.parent??t.current):l.rightArrow&&o(f=>f.lastRenderedChild?f.firstChild:f)}),u(Nt.Provider,{value:i,children:b(y,{flexDirection:"column",children:[u(ve,{isInitiallyExpanded:!0,label:"rootItem",children:r}),e&&u(y,{marginTop:1,flexDirection:"column",children:u(w,{dimColor:!0,children:"\u2191/\u2193 move \u2022 \u2190 collapse \u2022 \u2192 expand \u2022 Enter/Space select/edit \u2022 Esc exit"})})]})})},"TreeView");J.Item=ve,J.TextField=Un;function ge({label:r,elementType:e,isActionExcluded:t,toggleAction:n,generateCode:o}){const[i,s]=N([]),{fetchElements:a,getSyncedElementsByType:l}=G();return we(()=>{c(async()=>{try{await a();const h=l(e);s(h.map(f=>f.data))}catch(h){console.error(String(h))}},"loadElements")()},[e,a,l,s]),u(ve,{label:r,children:i.map(d=>u(ve,{label:d.name,children:e===I.Action&&b(Le,{children:[t&&n&&u(me,{label:`Toggle ${t(d)?"":"(excluded)"}`,onPress:c(()=>{n(d)},"onPress")}),o&&u(me,{label:"Generate code",onPress:c(()=>{o?.(d)},"onPress")})]})},d.id))})}c(ge,"WorkspaceElementsTreeItem");function li({onComplete:r}){const{config:e,updateConfig:t,fetchElements:n,getSyncedElementsByType:o}=G(),[i,s]=N(""),a=e,l=c(p=>{s(p),setTimeout(()=>s(""),2e3)},"setFlash"),d=c(async(p,C)=>{try{await t({[p]:C}),l("\u2705 Configuration updated!")}catch{l("\u274C Error updating configuration")}},"updateField"),h=c(async()=>{try{if(e){const p=pe.saveToFile(e);l(p?"\u2705 Configuration saved successfully!":"\u274C Failed to save configuration"),await n();const C=o(I.Action);await Et({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:C.filter(E=>!a?.excludedActionKeys?.includes(E.key)).map(E=>E.data)}}),l("\u2705 Code generated successfully!")}}catch{l("\u274C Error saving configuration")}},"handleSaveConfig"),f=c(async()=>{try{const p=pe.loadConfig();p?(await t(p),l("\u2705 Configuration reloaded successfully!")):l("\u274C No configuration found to reload")}catch{l("\u274C Error reloading configuration")}},"handleReloadConfig");return b(y,{flexDirection:"column",gap:1,children:[u(w,{bold:!0,color:"cyan",children:"\u2699\uFE0F Membrane Configuration Manager"}),u(y,{paddingX:2,children:b(J,{showHelp:!0,children:[b(J.Item,{label:"Configuration",isInitiallyExpanded:!0,children:[b(J.Item,{label:"Project",children:[u(J.TextField,{label:"Workspace Key",value:a?.workspaceKey??"",onChange:c(p=>d("workspaceKey",p),"onChange"),disabled:!0}),u(ci,{label:"Workspace Secret",value:a?.workspaceSecret??"",onChange:c(p=>d("workspaceSecret",p),"onChange"),disabled:!0}),u(J.TextField,{label:"API URI",value:a?.apiUri??"",onChange:c(p=>d("apiUri",p),"onChange")}),u(J.TextField,{label:"Test Customer ID",value:a?.testCustomerId??"",onChange:c(p=>d("testCustomerId",p),"onChange")})]}),b(J.Item,{label:"Code Generation",isInitiallyExpanded:!0,children:[b(J.Item,{label:"Project Type",isInitiallyExpanded:!0,value:a?.projectType,renderValue:c(({value:p})=>u(w,{children:p==="typescript"?"TypeScript":p==="openapi"?"OpenAPI":"(Not set)"}),"renderValue"),children:[u(me,{label:"Update to TypeScript",onPress:c(()=>d("projectType","typescript"),"onPress")}),u(me,{label:"Update to OpenAPI",onPress:c(()=>d("projectType","openapi"),"onPress")})]}),u(J.TextField,{label:"Project dir",value:a?.outputDir??"",onChange:c(p=>d("outputDir",p),"onChange")})]}),b(J.Item,{label:"Workspace Elements",children:[u(ge,{label:"Actions",elementType:I.Action,isActionExcluded:c(p=>a?.excludedActionKeys?.includes(p.key)??!1,"isActionExcluded"),toggleAction:c(p=>d("excludedActionKeys",[...a?.excludedActionKeys??[],p.key]),"toggleAction"),generateCode:c(p=>{(async()=>{try{await Et({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:[p]}}),l("\u2705 Code generated successfully!")}catch{l("\u274C Error generating code")}})()},"generateCode")}),u(ge,{label:"Flows",elementType:I.Flow}),u(ge,{label:"Data Sources",elementType:I.DataSource}),u(ge,{label:"Field Mappings",elementType:I.FieldMapping}),u(ge,{label:"Packages",elementType:I.Package}),u(ge,{label:"App Data Schemas",elementType:I.AppDataSchema}),u(ge,{label:"App Event Types",elementType:I.AppEventType})]})]}),u(me,{label:"Save Configuration",onPress:h,hotkey:"s"}),u(me,{label:"Reload Configuration",onPress:f,hotkey:"r"}),u(me,{label:"Exit",onPress:c(()=>r?.(),"onPress"),hotkey:"escape"})]})}),i&&u(y,{paddingX:2,children:u(w,{color:i.includes("\u2705")?"green":"red",children:i})})]})}c(li,"ConfigManager");const Kn=at(process.cwd());function ui({cwd:r,children:e}){return u(Kn.Provider,{value:r,children:e})}c(ui,"CwdProvider");function di(){return ct(Kn)}c(di,"useCwd");function Mt({cwd:r,children:e,membraneCLIService:t}){const n=r||process.cwd();return u(ui,{cwd:n,children:u(_r,{value:{fetcher:ho()},children:u(ri,{membraneCLIService:t,children:e})})})}c(Mt,"Layout");function hi(r,e){r.command("config").alias("install").description("\u26A0\uFE0F EXPERIMENTAL: Manage local membrane configuration with interactive UI").addHelpText("after",["","Examples:"," membrane config # Open interactive config manager",""].join(`
16
- `)).action(()=>{ut(de.createElement(Mt,{membraneCLIService:e,children:de.createElement(li,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(hi,"setupConfigCommand");function _n(r,e){return new Promise((t,n)=>{if(e.aborted){n(e.reason);return}const o=setTimeout(t,r);e.addEventListener("abort",()=>{clearTimeout(o),n(e.reason)},{once:!0})})}c(_n,"sleep");function Ft(r){r instanceof Ke?T.error(r.format()):r instanceof Error?T.error(r.message):T.error("An unknown error occurred"),process.exit(1)}c(Ft,"handleCommandError");function qn(r){return r.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}c(qn,"escapeHtml");const pi="font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0a0a0a;color:#fff";function se(r,e,t="#888"){const n=/^#[0-9a-fA-F]{3,6}$/.test(t)?t:"#888";return`<!DOCTYPE html><html><body style="${pi}">
17
- <div style="text-align:center"><h1>${qn(r)}</h1><p style="color:${n}">${qn(e)}</p></div>
18
- </body></html>`}c(se,"htmlPage");const Bn=".membrane",Wn="config.json";function fi(r){const e=k.resolve(Bn),t=k.join(e,Wn);let n={};Me(t)&&(n=JSON.parse(nn(t,"utf8")));const o={...n,...r};for(const[i,s]of Object.entries(o))s===void 0&&delete o[i];Me(e)||tn(e,{recursive:!0}),Er(t,JSON.stringify(o,null,2)+`
19
- `,"utf8")}c(fi,"patchProjectConfig");function Jn(){try{const r=k.join(k.resolve(Bn),Wn);if(!Me(r))return{};const e=JSON.parse(nn(r,"utf8"));return{defaultWorkspaceKey:e.defaultWorkspaceKey,defaultTenantKey:e.defaultTenantKey}}catch{return{}}}c(Jn,"readProjectDefaults");const mi=3e3,gi=1800*1e3;function yi(r){r.command("connect").description("Create a connection to a third-party service via browser-based OAuth").option("--integrationId <id>","Integration ID").option("--integrationKey <key>","Integration key").option("--connectorId <id>","Connector ID").option("--connectorVersion <version>","Connector version").option("--connectionId <id>","Existing connection ID (for reconnect)").option("--name <name>","Connection name").option("--allowMultipleConnections","Allow multiple connections").option("--connectorParameters <json>","JSON string of connector parameters").option("--workspaceKey <key>","Workspace key").option("--tenantKey <key>","Tenant key (customer internalId)").option("--no-browser","Print URL instead of opening browser").addHelpText("after",["","Examples:"," membrane connect --integrationKey hubspot"," membrane connect --integrationKey hubspot --tenantKey my-customer"," membrane connect --connectorId 123 --workspaceKey my-workspace"," membrane connect --connectionId abc --no-browser",""].join(`
20
- `)).action(async e=>{try{await Ci(e)}catch(t){Ft(t)}})}c(yi,"setupConnectCommand");function wi(){if(!(gt()&&(!mt()||Ce())))throw new Error("Not authenticated. Run `membrane login` first.")}c(wi,"ensureAuthenticated");async function Ci(r){T.header("Creating a connection"),wi();const e=Se()||ne,t=Jn(),n=r.workspaceKey||t.defaultWorkspaceKey;if(!n)throw new Error("No workspace specified. Use --workspaceKey or run `membrane login` to set a default.");const o=r.tenantKey||t.defaultTenantKey;if(!o)throw new Error("No tenant specified. Use --tenantKey or run `membrane login` to set a default.");let i;if(r.connectorParameters){let E;try{E=JSON.parse(r.connectorParameters)}catch{throw new Error("--connectorParameters must be valid JSON")}if(typeof E!="object"||E===null||Array.isArray(E))throw new Error("--connectorParameters must be a JSON object");i=E}const s=new qe,a=c(async()=>{const{token:E}=await s.post(`/workspaces/${n}/access-token`,{tenantKey:o});return E},"fetchTenantToken");let l=await a();const d=qr(),{port:h,server:f,waitForCallback:p}=await Si(d),C=`http://127.0.0.1:${h}/callback?nonce=${d}`;try{const E={redirectUri:C,integrationId:r.integrationId,integrationKey:r.integrationKey,connectorId:r.connectorId,connectorVersion:r.connectorVersion,connectionId:r.connectionId,name:r.name,allowMultipleConnections:r.allowMultipleConnections,connectorParameters:i},S=await Lt(`${e}/connection-requests`,l,{method:"POST",body:JSON.stringify(E)}),R=S.url;if(!!(process.stdin.isTTY&&r.browser))try{const{default:tr}=await import("open");await tr(R),T.info("Opening browser to complete connection...")}catch{T.info("Could not open browser automatically.")}console.error(` If the browser doesn't open, visit:
21
- ${R}
22
- `);const U=xe("Waiting for connection to complete...").start(),L=new AbortController,M=c(async()=>(l=await a(),l),"refreshTenantToken"),ye=p,Ht=bi(e,l,S.requestId,L.signal,M);Ht.catch(()=>{});const Te=await Promise.race([ye,Ht]);if(L.abort(),U.stop(),Te.cancelled&&(T.warning("Connection was cancelled."),process.exit(0)),Te.error)throw new Error(`Connection failed: ${Te.error}`);if(!Te.connectionId)throw new Error("Connection completed but no connection ID received");const le=await Lt(`${e}/connections/${Te.connectionId}`,l);T.success("Connection created successfully!"),console.error(),console.error(` Connection ID: ${le.id}`),le.name&&console.error(` Name: ${le.name}`),le.integrationId&&console.error(` Integration ID: ${le.integrationId}`),le.connectorId&&console.error(` Connector ID: ${le.connectorId}`),console.error(),process.exit(0)}finally{f.close()}}c(Ci,"runConnect");function Si(r){return new Promise(e=>{let t;const n=new Promise(i=>{t=i}),o=cn((i,s)=>{const a=new URL(i.url??"/","http://127.0.0.1");if(a.pathname!=="/callback"){s.writeHead(404),s.end("Not found");return}if(a.searchParams.get("nonce")!==r){s.writeHead(403),s.end("Invalid nonce");return}const l=a.searchParams.get("connectionId"),d=a.searchParams.get("cancelled"),h=a.searchParams.get("error");s.writeHead(200,{"Content-Type":"text/html"}),h?(s.end(se("Connection failed",h,"#f87171")),t({error:h})):d?(s.end(se("Connection cancelled","You can close this tab and return to your terminal.")),t({cancelled:!0})):l?(s.end(se("Connection successful","You can close this tab and return to your terminal.")),t({connectionId:l})):(s.end(se("Connection failed","Unknown callback state","#f87171")),t({error:"Unknown callback state"}))});o.listen(0,"127.0.0.1",()=>{const i=o.address(),s=typeof i=="object"&&i?i.port:0;e({port:s,server:o,waitForCallback:n})})})}c(Si,"startConnectionCallbackServer");async function bi(r,e,t,n,o){let i=e;const s=Date.now()+gi;for(;Date.now()<s;){n.throwIfAborted(),await _n(mi,n),n.throwIfAborted();let a;try{a=await Lt(`${r}/connection-requests/${t}`,i,{signal:n})}catch(l){if(l instanceof Ke&&l.statusCode===401){i=await o();continue}throw l}if(a.status==="success"&&a.resultConnectionId)return{connectionId:a.resultConnectionId};if(a.status==="cancelled")return{cancelled:!0};if(a.status==="error")return{error:a.resultError?.message??"Connection failed"}}throw new Error("Connection timed out after 30 minutes")}c(bi,"pollConnectionRequest");async function Lt(r,e,t){const n={Authorization:`Bearer ${e}`,"Content-Type":"application/json",...t?.headers},o=await fetch(r,{...t,headers:n});if(!o.ok){const i=await o.text();throw new Ke(o.status,i)}return o.json()}c(Lt,"fetchWithToken");function vi({currentPat:r,onSubmit:e}){const[t,n]=N(""),[o,i]=N(!1),[s,a]=N(null),l=pt(`/w/0/${gr}`);return b(y,{flexDirection:"column",borderStyle:"round",borderTop:!0,width:70,paddingX:1,children:[u(y,{marginTop:-1,marginBottom:1,children:u(w,{bold:!0,children:"\u{1F511} Enter your Personal Access Token"})}),u(w,{children:"Please provide your Personal Access Token. You can find it here:"}),u(y,{marginTop:1,marginBottom:1,children:u(w,{color:"yellow",children:l})}),r&&u(w,{dimColor:!0,children:"Press Enter to keep your current token or type a new one."}),u(sn,{mask:"*",placeholder:`${r?"******":"Enter your token here..."}`,value:t,onChange:n,onSubmit:c(async h=>{a(null),i(!0);try{await e(h),n("")}catch{a("Invalid token. Please try again.")}finally{i(!1)}},"handleSubmit")}),o&&u(y,{marginTop:1,children:b(w,{children:[u(Ue,{type:"dots"})," Validating token..."]})}),s&&u(w,{color:"red",children:s})]})}c(vi,"PersonalAccessTokenInput");function zn({onExit:r,showEscOption:e=!0}){const[t,n]=N(""),{data:o,error:i,isLoading:s}=on("/account"),{updateConfig:a}=G(),l=o?.workspaces,d=s;if(he((S,R)=>{R.escape&&r?.()}),d)return b(y,{children:[u(Ue,{}),u(w,{children:" Fetching workspaces..."})]});if(i)return b(y,{flexDirection:"column",children:[b(w,{color:"red",children:["Error: ",i.message]}),u(y,{marginTop:1,children:u(w,{color:"grey",children:"Press ESC to go back"})})]});const h=l?.filter(S=>S.name.toLowerCase().includes(t.toLowerCase()))??[],f=h.map(S=>({label:S.name,value:S.id})),p=f.length,C=l?.length??0;async function E(S){const R=h.find(L=>L.id===S);if(!R)return;const{key:O,secret:U}=R;!O||!U||(await a({workspaceKey:O,workspaceSecret:U}),r?.())}return c(E,"handleSelect"),b(y,{flexDirection:"column",borderStyle:"round",borderTop:!0,width:70,paddingX:1,children:[u(y,{marginTop:-1,children:u(w,{bold:!0,children:"\u{1F4C1} Select your workspace"})}),b(y,{marginTop:1,children:[u(w,{children:"Search: "}),u(Wr,{placeholder:"Enter a search query...",onChange:n})]}),C>5&&b(w,{children:["Showing ",p," of ",C," workspaces."]}),u(y,{marginTop:1,children:u(Jr,{options:f,onChange:c(S=>{S&&E(S)},"onChange")})}),e&&u(y,{marginTop:1,children:u(w,{color:"grey",children:"Press ESC to go back"})})]})}c(zn,"SelectWorkspace");var Oe=(r=>(r[r.Authenticate=0]="Authenticate",r[r.ConnectWorkspace=1]="ConnectWorkspace",r))(Oe||{});const Ei={0:"Authenticate in Membrane",1:"Connect a Membrane Workspace"},jt=[Oe.Authenticate,Oe.ConnectWorkspace];function Hn({onComplete:r}){const{config:e}=G(),[t,n]=N(!1),[o,i]=N(0),s=!!(e?.workspaceKey&&e?.workspaceSecret),a=dn(),l=jt[o],d=o+1,h=jt.length,f=jt.map((E,S)=>{let R="pending";return S<o?R="done":S===o&&(R="current"),{id:E,label:Ei[E],status:R}});async function p(E){const S=a&&E===""?a:E,R=new qe;try{await R.request("/account",{headers:{Authorization:`Bearer ${S}`}}),so(S),i(O=>O+1)}catch(O){console.error(O)}}c(p,"handlePatSubmit");function C(){n(!0),r&&r()}return c(C,"handleWorkspaceSelected"),he((E,S)=>{s&&S.escape&&r&&r()}),t?u(y,{children:u(w,{children:"\u2705 Setup complete. You are ready to go!"})}):b(y,{flexDirection:"column",alignSelf:"flex-start",gap:1,children:[b(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:70,children:[u(y,{marginTop:-1,marginBottom:1,children:b(w,{bold:!0,children:["\u{1F6E0}\uFE0F Setup \u2014"," ",b(w,{color:"cyan",children:["Step ",d," of ",h]}),s&&u(w,{color:"grey",children:" [esc: go back]"})]})}),u(y,{flexDirection:"column",paddingLeft:2,children:f.map(E=>u(Ti,{status:E.status,label:E.label},E.id))})]}),l===Oe.Authenticate&&u(vi,{currentPat:a,onSubmit:p}),l===Oe.ConnectWorkspace&&u(zn,{onExit:C,showEscOption:!1})]})}c(Hn,"Setup");function Ti({status:r,label:e}){return b(y,{children:[b(y,{width:2,children:[r==="current"&&u(Ue,{type:"dots"}),r==="done"&&u(w,{children:"\u2705"})]}),u(w,{dimColor:r!=="current",children:e})]})}c(Ti,"StepDisplay");function xi(r,e){r.command("init").description("Run interactive setup for Membrane project").option("--key <key>","Workspace key for non-interactive setup").option("--secret <secret>","Workspace secret for non-interactive setup").addHelpText("after",["","Examples:"," membrane init # Run interactive setup"," membrane init --key KEY --secret SEC # Non-interactive setup with key and secret",""].join(`
23
- `)).action(t=>{t.key&&t.secret?pe.saveToFile({workspaceKey:t.key,workspaceSecret:t.secret})?(console.error("\u2705 Configuration saved to membrane.config.yml"),process.exit(0)):(console.error("Error writing configuration file"),process.exit(1)):t.key||t.secret?(console.error("Error: Both --key and --secret must be provided for non-interactive mode"),process.exit(1)):ut(de.createElement(Mt,{membraneCLIService:e,children:de.createElement(Hn,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(xi,"setupInitCommand");function Ii(r){r.command("login").description("Log in to Membrane via browser-based OAuth").option("--apiUri <uri>","API base URI",ne).option("--no-browser","Print the authorization URL instead of opening a browser").addHelpText("after",["","Examples:"," membrane login # Log in via browser"," membrane login --no-browser # Print URL for manual login"," membrane login --apiUri https://api.example.com # Use custom API",""].join(`
24
- `)).action(async e=>{try{T.header("Logging in to Membrane");const t=await ki(e.apiUri,e.browser);ao(),hn(t.accessToken,t.refreshToken,t.expiresIn),uo(e.apiUri),t.defaultWorkspaceKey&&fi({defaultWorkspaceKey:t.defaultWorkspaceKey,defaultTenantKey:t.defaultTenantKey}),T.success("Authentication successful!"),process.exit(0)}catch(t){Ft(t)}})}c(Ii,"setupLoginCommand");async function ki(r,e){const t=$i(),n=Pi(t),{port:o,waitForCode:i,state:s,server:a}=await Ai(),l=`http://127.0.0.1:${o}/callback`,d=`${r}/oauth/authorize?response_type=code&client_id=${Ze}&redirect_uri=${encodeURIComponent(l)}&code_challenge=${n}&code_challenge_method=S256&scope=${yr}&state=${s}`,f=(await fetch(d,{redirect:"manual"})).headers.get("location");if(!f)throw a.close(),new Error("No redirect from authorization endpoint");const p=new URL(f).searchParams.get("authorizationId");if(!p)throw a.close(),new Error("No authorizationId in authorization redirect");if(!!(process.stdin.isTTY&&e))try{const{default:L}=await import("open");await L(f),T.info("Opening browser for authentication...")}catch{T.info("Could not open browser automatically.")}console.error(` If the browser doesn't open, visit:
7
+ Unexpected Error:`),a&&console.error(a),console.error(s)),s}return}},"executeRequest");return t?i():Sn.withSkipErrorLog(i)}async generateAccessToken(e,t){return nt.sign({name:"Membrane Agent",isAdmin:!0,exp:Math.floor(Date.now()/1e3)+3600,iss:e},t,{algorithm:"HS512"})}isTokenValid(){return Date.now()<this.tokenExpiry}getCurrentConfig(e){const t=xe(e);return!t?.workspaceKey||!t?.workspaceSecret?null:{workspaceKey:t.workspaceKey,workspaceSecret:t.workspaceSecret,apiUri:t.apiUri}}async createClient(e){const t=await this.generateAccessToken(e.workspaceKey,e.workspaceSecret);return this.tokenExpiry=Date.now()+36e5,this.currentConfig=e,new Yt({token:t,apiUri:e.apiUri})}async getClient(e=process.cwd()){const t=this.getCurrentConfig(e);if(!t)throw new Error("Unable to create MembraneClient: No workspace configuration found.");const n=!this.currentConfig||this.currentConfig.workspaceKey!==t.workspaceKey||this.currentConfig.workspaceSecret!==t.workspaceSecret||this.currentConfig.apiUri!==t.apiUri,o=!this.isTokenValid()||this.tokenExpiry-Date.now()<3e5;return(!this.client||n||o)&&(this.client=await this.createClient(t)),this.client}clearClient(){this.client=null,this.currentConfig=null,this.tokenExpiry=0,this.requestTimes=[],this.semaphore=0,this.semaphoreQueue=[],this.rateLimitMutex=Promise.resolve()}getCurrentConfigInfo(){return this.currentConfig}async waitIfNeeded(){this.rateLimitMutex=this.rateLimitMutex.then(async()=>{for(this.cleanOldRequests();this.requestTimes.length>=this.maxRequestsPerSecond;){const t=this.requestTimes[0]+this.windowSizeMs-Date.now()+10;if(t>0)await new Promise(n=>setTimeout(n,t)),this.cleanOldRequests();else break}}),await this.rateLimitMutex}recordRequest(){this.requestTimes.push(Date.now())}cleanOldRequests(){const e=Date.now()-this.windowSizeMs;this.requestTimes=this.requestTimes.filter(t=>t>e)}getRequestCount(){return this.cleanOldRequests(),this.requestTimes.length}async acquireSemaphore(){if(this.semaphore<this.maxConcurrentRequests){this.semaphore++;return}return new Promise(e=>{this.semaphoreQueue.push(e)})}releaseSemaphore(){if(this.semaphore--,this.semaphoreQueue.length>0){const e=this.semaphoreQueue.shift();this.semaphore++,e()}}async withRetry(e,t="operation"){let n;for(let o=0;o<=this.maxRetries;o++)try{return await e()}catch(i){if(n=i,!this.isRetryableError(i)||o===this.maxRetries)throw i;const s=new Date().toISOString(),a=o+2;g.debug(`[${s}] Retrying ${t} (attempt ${a}/${this.maxRetries+1})`);let l=this.retryDelay*Math.pow(2,o);if(this.enableJitter){const u=l*.25*(Math.random()*2-1);l=Math.max(0,l+u)}await new Promise(u=>setTimeout(u,l))}throw n||new Error("Unknown error occurred during retry attempts")}isRetryableError(e){if(!e)return!1;const t=(e.message||e.toString()||"").toLowerCase(),n=e.code;return n&&["econnrefused","enotfound","econnreset","etimedout","ehostunreach","enetunreach"].includes(n.toLowerCase())?!0:["econnrefused","connection refused","network error","timeout","socket hang up","request timeout","dns lookup failed"].some(s=>t.includes(s))}async withTimeout(e,t){let n;const o=new Promise((i,s)=>{n=setTimeout(()=>s(new Error(`Request timeout after ${t}ms`)),t)});try{const i=await Promise.race([e,o]);return n&&clearTimeout(n),i}catch(i){throw n&&clearTimeout(n),i}}async getVersion(){try{return(await this.withClient(t=>t.get("version"),!1))?.version??null}catch{return null}}async isVersionAtLeast(e){const t=await this.getVersion(),n=t?rt.coerce(t):null,o=rt.coerce(e);return!!(n&&o&&rt.gte(n,o))}}const $=new Io;async function bn(r){const e=await $.withClient(t=>t.get("org-workspace-id"),!0,r);if(!e)throw new Error("Failed to get workspace ID");return e.id}c(bn,"getWorkspaceId");const vn=1e3,Tn=12e4;async function En(){const r=await $.withClient(async t=>ht(t,()=>t.get("export"),{pollIntervalMs:vn,timeoutMs:Tn}));if(!r)throw new Error("Failed to export workspace");const e=await Ie.get(r.downloadUrl,{responseType:"arraybuffer"});return Buffer.from(e.data)}c(En,"downloadWorkspaceExport");async function In(r,e={}){const t=new sn;t.append("file",r,{filename:"membrane.zip",contentType:"application/zip"});const n=await $.withClient(async i=>{const s=`import?dryRun=${e.dryRun??!1}&partial=${e.partial??!1}`,{jobId:a,accessKey:l}=await i.post(s,t,{headers:t.getHeaders()});return ht(i,()=>Promise.resolve({jobId:a,accessKey:l}),{pollIntervalMs:1e3,timeoutMs:3e5})});if(!n)throw new Error("Failed to import workspace");return await $.isVersionAtLeast("1.10")?{create:new Set(n.comparison.create||[]),update:new Set(n.comparison.update||[]),delete:new Set(n.comparison.delete||[])}:{create:new Set(n.create||[]),update:new Set(n.update||[]),delete:new Set(n.delete||[])}}c(In,"importWorkspace");async function ko(r,e){const t=await $.withClient(async o=>ht(o,()=>o.get(`connectors/${r}/export-files`,{version:e}),{pollIntervalMs:vn,timeoutMs:Tn}));if(!t)throw new Error("Failed to export connector version");const n=await Ie.get(t.downloadUrl,{responseType:"arraybuffer"});return Buffer.from(n.data)}c(ko,"exportConnector");function kn(r,e){Pe(I.dirname(r)),T.writeFileSync(r,e)}c(kn,"writeFile");function xo(r){T.existsSync(r)&&T.rmSync(r)}c(xo,"deleteFile");function Ct(r){T.existsSync(r)&&T.rmSync(r,{recursive:!0,force:!0})}c(Ct,"deleteDir");function $o(r,e=!0){if(T.existsSync(r))try{const t=T.readFileSync(r,"utf8");return Y.load(t)||void 0}catch(t){if(!e)return;if(t instanceof Error){const n=I.relative(process.cwd(),r);throw new Error(`Failed to parse YAML file "${n}": ${t.message}`)}throw t}}c($o,"readYaml$1");function xn(r,e,t){try{Pe(I.dirname(r));const n=Y.dump(e,t);T.writeFileSync(r,n,"utf8")}catch(n){if(n instanceof Error){const o=I.relative(process.cwd(),r);throw new Error(`Failed to write YAML file "${o}": ${n.message}`)}throw n}return e}c(xn,"writeYaml$1");function Pe(r){T.existsSync(r)||T.mkdirSync(r,{recursive:!0})}c(Pe,"ensureDirExists");function $n(r,e=!0){if(!T.existsSync(r)||!T.statSync(r).isDirectory())return;let t=T.readdirSync(r);t.length>0&&(t.forEach(n=>$n(I.join(r,n),!1)),t=T.readdirSync(r)),t.length===0&&!e&&T.rmdirSync(r)}c($n,"cleanupEmptyFolders");function Ao(r){const e=r.split(/[\\/]/).join("/");return e.endsWith("/")?e+"**":e}c(Ao,"normalizePattern");async function An(r,e,t){const n=(e??[]).map(Ao),o=[];if(t){const i=I.join(W(process.cwd()),"connectors");for(const s of Object.values(t)){const a=s.key,l=I.join(i,a),u=I.join(l,`${a}.yml`);T.existsSync(u)&&o.push({name:vr(a),content:T.readFileSync(u,"utf-8")});const h=[...s.versions];T.existsSync(I.join(l,"development"))&&!h.includes("")&&h.push("");for(const m of h){const f=m===""?"development":m,C=I.join(l,f,"src"),E=I.join(l,f,"src.zip"),S=m===""?Ye:m;T.existsSync(C)?o.push({name:Zt(a,S),content:await Po(C)}):T.existsSync(E)&&o.push({name:Zt(a,S),content:T.readFileSync(E)})}}}return new Promise((i,s)=>{const a=ot("zip",{zlib:{level:9}}),l=[];a.on("data",h=>l.push(h)),a.on("end",()=>i(Buffer.concat(l))),a.on("error",h=>s(h));const u=new Map;for(const h of r[k.Integration]||[])u.set(h.uuid,h.key);for(const[h,m]of Object.entries(r))for(const f of m){const C=u.get(f.integrationUuid),E=Tr(h,f.key,C);n.length>0&&!n.some(S=>Dr(E,S))||a.append(Y.dump(f),{name:E})}for(const{name:h,content:m}of o)a.append(m,{name:h});a.finalize()})}c(An,"createMembraneZip");async function Po(r){return new Promise((e,t)=>{const n=ot("zip",{zlib:{level:9}}),o=[];n.on("data",i=>o.push(i)),n.on("end",()=>e(Buffer.concat(o))),n.on("error",i=>t(i)),n.directory(r,!1),n.finalize()})}c(Po,"createConnectorVersionZip");async function St(r,e){const t=await ln.loadAsync(r),n=[];for(const[o,i]of Object.entries(t.files)){if(i.dir)continue;const s=de(o);if(!s)continue;const a=await i.async("string"),l=Y.load(a);if(!l)continue;const u=await e(o,l,s);u!==void 0&&n.push(u)}return n}c(St,"iterateZipItems");async function Pn(r){const e=await ln.loadAsync(r),t={};for(const[n,o]of Object.entries(e.files)){if(o.dir)continue;const i=de(n);if(!i)continue;const s=await o.async("string"),a=Y.load(s);t[i.type]||(t[i.type]=[]),t[i.type].push(a)}return t}c(Pn,"readMembraneZip");async function bt(r=process.cwd()){const e=await On(W(r)),t={};for(const{data:n,type:o}of e)t[o]||(t[o]=[]),t[o].push(n);return t}c(bt,"readMembraneDir");async function On(r){const e=Rn(r),t=[];for(const n of e){if(n.isDirectory())continue;const o=de(n.path);if(!o)continue;const i=await n.readContent(),s=Y.load(i),a=I.join(r,n.path);t.push({filePath:a,data:s,type:o.type})}return t}c(On,"iterateMembraneFiles");function Rn(r,e){const t=[];if(e||(e=r),!T.existsSync(e)||e.startsWith(I.join(r,"connectors")))return t;const n=T.readdirSync(e,{withFileTypes:!0});for(const o of n){const i=I.join(e,o.name),s=I.relative(r,i);o.isDirectory()?t.push(...Rn(r,i)):o.isFile()&&de(s)&&t.push({path:s,isDirectory:c(()=>!1,"isDirectory"),readContent:c(async()=>T.readFileSync(i,"utf8"),"readContent")})}return t}c(Rn,"getMembraneFiles");function Nn(){const r={},e=I.join(W(process.cwd()),"connectors");if(!T.existsSync(e))return r;const t=T.readdirSync(e);for(const n of t){const o=I.join(e,n);if(!T.statSync(o).isDirectory())continue;const i=I.join(o,`${n}.yml`),s=$o(i,!1);if(!s?.uuid)continue;const a=new Set,l=T.readdirSync(o);for(const u of l){if(u.endsWith(".yml"))continue;const h=I.join(o,u);T.statSync(h).isDirectory()&&a.add(u=="development"?"":u)}r[s.uuid]={key:n,id:s.id,versions:Array.from(a)}}return r}c(Nn,"readConnectorsDir");function Oe(r,e){const t=I.join(W(process.cwd()),"connectors",r);return e==""||e===Ye?I.join(t,"development"):e?I.join(t,e):t}c(Oe,"getConnectorPath");const Oo={info:"\u{1F4DD}",success:"\u2728",warning:"\u26A0\uFE0F",error:"\u274C",debug:"\u{1F50D}"},Ro={info:p.white,success:p.green,warning:p.yellow,error:p.red,debug:p.gray};class b{static{c(this,"Logger")}static formatMessage(e,t,n={icon:!1}){const o=n.timestamp?`${p.gray(new Date().toISOString())} `:"",i=n.prefix?`${p.gray(n.prefix)} `:"",s=n.suffix?` ${p.gray(n.suffix)}`:"",a=Oo[t],l=Ro[t];return`${o}${n.icon?a:""} ${i}${l(e)}${s}`}static info(e,t){let n=p.white;if(t?.color&&(n=p[t.color.toLowerCase()]||p.white),t?.timestamp){const o=new Date().toLocaleTimeString();console.debug(`${p.gray(`[${o}]`)} ${n(e)}`)}else console.debug(n(e))}static group(e,t){}static groupEnd(){}static newLine(){}static success(e,t){console.debug(this.formatMessage(e,"success",t))}static warning(e,t){console.debug(this.formatMessage(e,"warning",t))}static error(e,t){console.error(this.formatMessage(e,"error",t))}static debug(e,t){t?.prefix?console.debug(p.gray(`[${t.prefix}] ${e}`),t.error?`
8
+ ${p.red(t.error)}`:""):console.debug(p.gray(e),t?.error?`
9
+ ${p.red(t.error)}`:"")}static step(e,t){}static header(e){console.debug(),console.debug(p.bold.cyan(`\u25B6 ${e}`)),console.debug()}static table(e,t){if(e.length===0)return;const n=t||Object.keys(e[0]),o=e.map(i=>{const s={};return n.forEach(a=>{s[a]=i[a]}),s});console.table(o,n)}static divider(){}}function No(r){r.command("diff").description("Show what would change on push without applying anything").action(async()=>{const e=Ce({text:"Comparing workspace",color:"white"}).start();try{const t=await bt();e.text="Downloading remote workspace";const n=await En(),o=await Pn(n);e.stop();const{changes:i,diff:s}=Xt(o,t,{includeDiff:!0}),a=Object.keys(i).length;if(a===0){b.info("No changes detected");return}b.info(`\u25CF Diff \xB7 ${a} change(s)
10
+ `),s&&b.info(Do(s))}catch(t){e.stop(),b.error("\u25A0 Error"),b.error(`\u2514\u2500\u2500 ${t.message}`),process.exit(1)}})}c(No,"setupDiffCommand");function Do(r){return r.split(`
11
+ `).map(e=>e.startsWith("diff ")?p.bold(e):e.startsWith("index ")||e.startsWith("===")?p.dim(e):e.startsWith("---")?p.bold.red(e):e.startsWith("+++")?p.bold.green(e):e.startsWith("@@")?p.cyan(e):e.startsWith("+")?p.green(e):e.startsWith("-")?p.red(e):e).join(`
12
+ `)}c(Do,"colorizePatch");const Dn=".membrane",Ln="config.json";function Lo(r){const e=x.resolve(Dn),t=x.join(e,Ln);let n={};Fe(t)&&(n=JSON.parse(cn(t,"utf8")));const o={...n,...r};for(const[i,s]of Object.entries(o))s===void 0&&delete o[i];Fe(e)||an(e,{recursive:!0}),Or(t,JSON.stringify(o,null,2)+`
13
+ `,"utf8")}c(Lo,"patchProjectConfig");function Mn(){try{const r=x.join(x.resolve(Dn),Ln);if(!Fe(r))return{};const e=JSON.parse(cn(r,"utf8"));return{defaultWorkspaceKey:e.defaultWorkspaceKey,defaultTenantKey:e.defaultTenantKey}}catch{return{}}}c(Mn,"readProjectDefaults");class J{static{c(this,"TenantApiClient")}derivedToken=null;apiUri;directToken;workspaceKey;tenantKey;accountClient;constructor(e){this.apiUri=me()||te,this.accountClient=new Ae,this.directToken=process.env.MEMBRANE_TOKEN||null;const t=Mn();this.workspaceKey=e.workspaceKey||t.defaultWorkspaceKey||"",this.tenantKey=e.tenantKey||t.defaultTenantKey||""}async fetchToken(){const{token:e}=await this.accountClient.post(`/workspaces/${encodeURIComponent(this.workspaceKey)}/access-token`,{tenantKey:this.tenantKey});return this.derivedToken=e,e}async getToken(){if(this.directToken)return this.directToken;if(yt()==="tenant")return this.accountClient.getValidAccessToken();if(!wt()||gt()&&!be())throw new Error("Not authenticated. Run `membrane login` first.");if(!this.workspaceKey)throw new Error("No workspace specified. Use --workspaceKey or run `membrane login` to set a default.");if(!this.tenantKey)throw new Error("No tenant specified. Use --tenantKey or run `membrane login` to set a default.");return this.derivedToken?this.derivedToken:this.fetchToken()}async request(e,t){const n=await this.getToken(),o={};t?.headers&&new Headers(t.headers).forEach((l,u)=>{o[u]=l});const i={Authorization:`Bearer ${n}`,...o};t?.body&&(i["Content-Type"]=i["Content-Type"]??"application/json");let s=await fetch(`${this.apiUri}${e}`,{...t,headers:i});if(s.status===401&&!this.directToken){const a=yt()==="tenant"?await this.accountClient.forceRefreshAccessToken():await this.fetchToken();i.Authorization=`Bearer ${a}`,s=await fetch(`${this.apiUri}${e}`,{...t,headers:i})}if(!s.ok){const a=await s.text();throw new pt(s.status,a)}return s.status===204?{}:s.json()}get(e){return this.request(e,{method:"GET"})}post(e,t){return this.request(e,{method:"POST",body:t!==void 0?JSON.stringify(t):void 0})}}function q(r){r instanceof pt?b.error(r.format()):r instanceof Error?b.error(r.message):b.error("An unknown error occurred"),process.exit(1)}c(q,"handleCommandError");function Mo(r){const e=r.command("action").description("List and run actions (tools) on connections").option("--workspaceKey <key>","Workspace key").option("--tenantKey <key>","Tenant key (customer internalId)");e.command("list").description("List available actions").option("--connectionId <id>","Filter by connection ID").option("--intent <text>","Search by natural language intent").option("--limit <n>","Max results").option("--json","Output as JSON").action(async t=>{try{const o={...e.opts(),...t},i=new J(o),s=new URLSearchParams;t.connectionId&&s.set("connectionId",t.connectionId),t.intent&&s.set("intent",t.intent),t.limit&&s.set("limit",t.limit);const a=s.toString(),l=await i.get(`/actions${a?`?${a}`:""}`);if(o.json)process.stdout.write(JSON.stringify(l,null,2)+`
14
+ `);else{const u=l.items??[];if(u.length===0)console.error(p.gray(" No actions found."));else for(const h of u){const m=h.description?p.gray(` \u2014 ${h.description}`):"";console.error(` ${p.cyan(h.id)} ${h.name||h.key||"(unnamed)"}${m}`)}console.error()}}catch(n){q(n)}}),e.command("run <actionId>").description("Run an action on a connection").option("--connectionId <id>","Connection ID to run the action on").option("--input <json>","Action input as JSON string").option("--json","Output as JSON").action(async(t,n)=>{try{const i={...e.opts(),...n},s=n.connectionId;if(!s)throw new Error("--connectionId is required");const a=new J(i);let l={};if(n.input)try{l=JSON.parse(n.input)}catch{throw new Error("--input must be valid JSON")}const u=new URLSearchParams({connectionId:s}),h=await a.post(`/actions/${encodeURIComponent(t)}/run?${u}`,{input:l});i.json?process.stdout.write(JSON.stringify(h,null,2)+`
15
+ `):(console.error(),console.error(p.green(" Action executed successfully.")),console.error(),process.stdout.write(JSON.stringify(h.output??h,null,2)+`
16
+ `))}catch(o){q(o)}})}c(Mo,"setupActionCommand");function R(r,e,t=14){console.error(` ${p.gray(r.padEnd(t))} ${e}`)}c(R,"printField");const jo=Object.values(Qt),vt=jo.filter(r=>r!==Qt.UNIVERSE);function Fo(r){const e=r.command("agent-session").description("Manage Membrane Agent sessions (build connectors and actions)").option("--workspaceKey <key>","Workspace key").option("--tenantKey <key>","Tenant key (customer internalId)");e.command("list").description("List agent sessions").option("--json","Output as JSON").action(async t=>{try{const n={...e.opts(),...t},i=await new J(n).get("/agent/sessions");if(n.json)process.stdout.write(JSON.stringify(i,null,2)+`
17
+ `);else{const s=i.items??[];if(s.length===0)console.error(p.gray(" No agent sessions found."));else for(const a of s){const l=p.gray(`[${a.status}]`);console.error(` ${p.cyan(a.id)} ${l} ${a.prompt||""}`)}console.error()}}catch(n){q(n)}}),e.command("create").description("Create a new agent session").requiredOption("--message <text>","Task description for the agent").option("--agent <name>",`Agent to run the session (${vt.join(", ")})`).option("--json","Output as JSON").action(async t=>{try{if(t.agent&&!vt.includes(t.agent))throw new Error(`Invalid agent name "${t.agent}". Must be one of: ${vt.join(", ")}`);const n={...e.opts(),...t},i=await new J(n).post("/agent/sessions",{prompt:t.message,...t.agent&&{agentName:t.agent}});n.json?process.stdout.write(JSON.stringify(i,null,2)+`
18
+ `):(console.error(),R("Session ID",i.id),R("Status",i.status),R("State",i.state),console.error())}catch(n){q(n)}}),e.command("get <sessionId>").description("Get agent session status").option("--wait","Long-poll until session is idle or completed").option("--json","Output as JSON").action(async(t,n)=>{try{const o={...e.opts(),...n},i=new J(o),s=new URLSearchParams;n.wait&&s.set("wait","true");const a=s.toString(),l=await i.get(`/agent/sessions/${encodeURIComponent(t)}${a?`?${a}`:""}`);o.json?process.stdout.write(JSON.stringify(l,null,2)+`
19
+ `):(console.error(),R("Session ID",l.id),R("Status",l.status),R("State",l.state),l.prompt&&R("Prompt",l.prompt),l.error&&R("Error",typeof l.error=="string"?l.error:JSON.stringify(l.error)),console.error())}catch(o){q(o)}}),e.command("send <sessionId>").description("Send a follow-up message to an active agent session").requiredOption("--message <text>","Message to send").option("--json","Output as JSON").action(async(t,n)=>{try{const o={...e.opts(),...n},s=await new J(o).post(`/agent/sessions/${encodeURIComponent(t)}/message`,{input:n.message});o.json?process.stdout.write(JSON.stringify(s,null,2)+`
20
+ `):(console.error(),R("Session ID",s.id),R("Status",s.status),R("State",s.state),console.error())}catch(o){q(o)}}),e.command("abort <sessionId>").description("Abort an active agent session").option("--json","Output as JSON").action(async(t,n)=>{try{const o={...e.opts(),...n},s=await new J(o).post(`/agent/sessions/${encodeURIComponent(t)}/interrupt`);o.json?process.stdout.write(JSON.stringify(s,null,2)+`
21
+ `):(console.error(),console.error(p.green(" Session aborted.")),console.error())}catch(o){q(o)}}),e.command("messages <sessionId>").description("Get messages from an agent session").option("--json","Output as JSON").action(async(t,n)=>{try{const o={...e.opts(),...n},s=await new J(o).get(`/agent/sessions/${encodeURIComponent(t)}/messages`);if(o.json)process.stdout.write(JSON.stringify(s,null,2)+`
22
+ `);else{const a=s.items??(Array.isArray(s)?s:[]);if(a.length===0)console.error(p.gray(" No messages found."));else for(const l of a){const u=p.cyan(String(l.role??"unknown")),h=l.content??l.text??JSON.stringify(l);console.error(` ${u}: ${h}`)}console.error()}}catch(o){q(o)}})}c(Fo,"setupAgentSessionCommand");function ge(r){if(r.type){if(Array.isArray(r.type))return{anyOf:r.type.map(t=>ge({...r,type:t}))};if(r.type==="array"){const t={type:"array",items:r.items?ge(r.items):{type:"object"}};return r.title&&(t.title=r.title),r.description&&(t.description=r.description),r.minItems!==void 0&&(t.minItems=r.minItems),r.maxItems!==void 0&&(t.maxItems=r.maxItems),r.uniqueItems!==void 0&&(t.uniqueItems=r.uniqueItems),t}}const e={};if(r.type&&!Array.isArray(r.type)&&(e.type=r.type),r.title&&(e.title=r.title),r.description&&(e.description=r.description),r.format&&(e.format=r.format),r.enum&&(e.enum=r.enum),r.default!==void 0&&(e.default=r.default),r.minimum!==void 0&&(e.minimum=r.minimum),r.maximum!==void 0&&(e.maximum=r.maximum),r.minLength!==void 0&&(e.minLength=r.minLength),r.maxLength!==void 0&&(e.maxLength=r.maxLength),r.maxItems!==void 0&&(e.maxItems=r.maxItems),r.readOnly!==void 0&&(e.readOnly=r.readOnly),r.writeOnly!==void 0&&(e.writeOnly=r.writeOnly),r.examples&&r.examples.length>0&&(e.example=r.examples[0]),r.properties){e.properties={};for(const[t,n]of Object.entries(r.properties))e.properties[t]=ge(n)}return r.anyOf&&(e.anyOf=r.anyOf.map(ge)),r.additionalProperties!==void 0&&(typeof r.additionalProperties=="boolean"?e.additionalProperties=r.additionalProperties:e.additionalProperties=ge(r.additionalProperties)),r.required&&(e.required=r.required),e}c(ge,"convertDataSchemaToOpenAPI");function Uo(r){const{membraneInterfaces:{actions:e}}=r,t=Ko(e);return JSON.stringify({openapi:"3.0.0",info:{title:"Membrane Actions API",version:"1.0.0",description:"Generated OpenAPI specification for Membrane actions"},paths:{},components:{schemas:t}},null,2)}c(Uo,"generateOpenAPIContent");function Ko(r){const e={};return r.forEach(t=>{const n=st(it(t.key)),o={type:"object",properties:{id:{type:"string",description:"Request ID"},action:{type:"string",enum:[t.key]}},required:["id","action"]};if(t?.inputSchema){const a=ge(t.inputSchema);a.properties&&(o.properties={...o.properties,...a.properties}),a.required&&(o.required=[...o.required||[],...a.required])}e[`${n}Request`]=o;const i={type:"object",properties:{id:{type:"string",description:"Response ID"},success:{type:"boolean"},data:{type:"object"}},required:["id","success"]},s=t?.customOutputSchema||t?.outputSchema;if(s){const a=ge(s);i.properties={...i.properties,data:a}}e[`${n}Response`]=i}),e}c(Ko,"generateOpenAPISchemas");function _o(r){const{membraneInterfaces:{actions:e}}=r,t=Mr(e,"key"),n=new Lr({indentNumberOfSpaces:2,newLine:`
23
+ `});return n.writeLine("// Generated TypeScript definitions for Membrane actions"),n.newLine(),n.writeLine("import type {"),n.writeLine(" ActionAccessor,"),n.writeLine(" ConnectionLevelActionAccessor,"),n.writeLine('} from "@membranehq/sdk";'),n.newLine(),qo(n,t),n.toString()}c(_o,"generateTypeScriptContent");function qo(r,e){r.writeLine('declare module "@membranehq/sdk" {'),r.indent(()=>{e.forEach(t=>{const n=Et(t),o=t?.inputSchema;We(r,{interfaceName:n,properties:o?.properties,required:o?.required||[]});const i=It(t),s=t?.customOutputSchema||t?.outputSchema;We(r,{interfaceName:i,properties:s?.properties,required:s?.required||[],fallbackContent:"result: unknown"}),r.newLine()}),We(r,{interfaceName:"MembraneClient",methods:e.map(t=>{const n=Et(t),o=It(t);return{name:"action",parameters:`selector: "${t.key}"`,returnType:`ActionAccessor<${n}, ${o}>`}})}),r.newLine(),We(r,{interfaceName:"ConnectionAccessor",methods:e.map(t=>{const n=Et(t),o=It(t);return{name:"action",parameters:`selector: "${t.key}"`,returnType:`ConnectionLevelActionAccessor<${n}, ${o}>`}})})}),r.writeLine("}")}c(qo,"generateModuleAugmentation");function We(r,e){const{interfaceName:t,properties:n,required:o=[],methods:i,fallbackContent:s}=e;r.writeLine(`interface ${t} {`),r.indent(()=>{n&&Object.keys(n).length>0&&Bo(r,n,o),i&&i.length>0&&(n&&Object.keys(n).length>0&&r.newLine(),i.forEach((a,l)=>{r.writeLine(`${a.name}(${a.parameters}): ${a.returnType};`),l<i.length-1&&r.newLine()})),s&&(!n||Object.keys(n).length===0)&&(!i||i.length===0)&&r.writeLine(s)}),r.writeLine("}")}c(We,"generateTypeScriptInterface");function Bo(r,e,t){Object.entries(e).forEach(([n,o])=>{const s=t.includes(n)?"":"?",a=Tt(o);r.writeLine(`readonly ${n}${s}: ${a}`)})}c(Bo,"generateTypeScriptProperties");function Tt(r){return r.type==="string"?r.enum?r.enum.map(e=>`'${e}'`).join(" | "):"string":r.type==="number"||r.type==="integer"?"number":r.type==="boolean"?"boolean":r.type==="array"?`${r.items?Tt(r.items):"unknown"}[]`:r.type==="object"?r.properties?`{ ${Object.entries(r.properties).map(([t,n])=>{const i=(r.required||[]).includes(t)?"":"?",s=Tt(n);return`readonly ${t}${i}: ${s}`}).join("; ")} }`:"Record<string, unknown>":"unknown"}c(Tt,"convertJsonSchemaToTypeScript");function Et(r){return`${st(it(r.key))}Input`}c(Et,"getInputTypeName");function It(r){return`${st(it(r.key))}Output`}c(It,"getOutputTypeName");async function kt(r){const{out:e}=r;await T.promises.mkdir(e,{recursive:!0});const t=Wo(r);for(const[n,o]of Object.entries(t)){const i=I.join(e,n);await T.promises.writeFile(i,o,"utf-8")}}c(kt,"generateCode");function Wo(r){switch(r.target){case"openapi":return{"openapi.json":Uo(r)};case"typescript":return{"generated.d.ts":_o(r)};default:throw new Error(`Unsupported target: ${r.target}`)}}c(Wo,"generateContent");const xt=c(()=>[p.yellow("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),p.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),p.yellow("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),p.yellow("\u2502 The codegen command is experimental and subject to rapid changes.\u2502"),p.yellow("\u2502 Features, APIs, and file structures may change without notice. \u2502"),p.yellow("\u2502 Use in production environments is not recommended. \u2502"),p.yellow("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),""].join(`
24
+ `),"createExperimentalWarning$2");function Jo(r,e){r.command("codegen").description("\u26A0\uFE0F EXPERIMENTAL: Generate code for easy integration within projects - This feature is experimental and will be changing rapidly. Use at your own risk.").requiredOption("--actions <actions>",'Comma-separated list of action names (e.g., "list-files,get-file-by-id")').requiredOption("--out <path>","Output directory for generated files").requiredOption("--target <type>","Target format: openapi or typescript").requiredOption("--schemasOnly","Generate only schemas without implementation").addHelpText("after",xt()).addHelpText("after",["",p.bold("Examples:"),` ${p.gray("\u25B8")} ${p.cyan("membrane codegen --actions list-files,get-file-by-id --out src/generated --target openapi --schemasOnly")}`,` ${p.gray("\u25B8")} ${p.cyan("membrane install --actions delete-file --out src/generated --target typescript --schemasOnly")}`,"",xt()].join(`
25
+ `)).action(async t=>{try{console.warn(xt()),console.error(p.cyan("\u{1F527} Membrane Codegen")),console.error("Status: Loading membrane interfaces...");const n=await zo(e,t),o={out:t.out,target:t.target,schemasOnly:t.schemasOnly,membraneInterfaces:n};console.error(`Output: ${o.out}`),console.error(`Target: ${o.target}`),console.error(`Schemas Only: ${o.schemasOnly?"Yes":"No"}`),console.error(`Loaded ${n.actions.length} membrane interfaces`),console.error("Status: Generating code..."),await kt(o),console.error(p.green("\u2705 Code generation completed successfully!")),process.exit(0)}catch(n){console.error(p.red("\u274C Code generation failed:")),console.error(n instanceof Error?n.message:"Unknown error occurred"),process.exit(1)}})}c(Jo,"setupCodegenCommand");async function zo(r,e){return await r.fetchElements(),{actions:[...r.getSyncedElementsByType(k.Action).map(t=>t.data)].filter(t=>e.actions.includes(t.key||""))}}c(zo,"loadMembraneInterfaces");const ne={UPDATE:"update",DELETE:"delete",CREATE:"create"},z={INCOMING:"incoming",OUTGOING:"outgoing"},X={[k.Integration]:{element:"integration",elements:"integrations",exportable:!1,exportCleanup:c(r=>({id:r.id,key:r.key,name:r.name,connectorId:r.connectorId,baseUri:r.baseUri,connectorVersion:r.connectorVersion}),"exportCleanup")},[k.Connector]:{element:"connector",elements:"connectors",exportable:!1},[k.Action]:{element:"action",elements:"actions",integrationSpecific:!0,exportCleanup:c(r=>(delete r.integration,r),"exportCleanup")},[k.AppDataSchema]:{element:"appDataSchema",elements:"appDataSchemas"},[k.AppEventType]:{element:"appEventType",elements:"appEventTypes"},[k.DataLinkTable]:{element:"dataLinkTable",elements:"dataLinkTables"},[k.DataSource]:{element:"dataSource",elements:"dataSources",parentKey:"universalDataSourceId",integrationSpecific:!0},[k.FieldMapping]:{element:"fieldMapping",elements:"fieldMappings",integrationSpecific:!0,parentKey:"universalFieldMappingId",exportCleanup:c(r=>(delete r.dataSourceId,r),"exportCleanup")},[k.Flow]:{element:"flow",elements:"flows",integrationSpecific:!0,parentKey:"universalFlowId"},[k.Package]:{element:"package",elements:"packages",integrationSpecific:!0}},Go=["id","workspaceId","integrationId","createdAt","updatedAt","revision","archivedAt","baseUri","state","appliedToIntegrations","dependencies"],jn=[k.Action,k.FieldMapping,k.Flow,k.DataSource,k.Package];class F{static{c(this,"Element")}type;key;integrationKey;data;constructor(e,t,n,o){if(!o)throw new Error("Element must always contain data");if(!t)throw new Error("Element must have a key");this.type=e,this.key=t,this.data=o,this.integrationKey=n||F.extractIntegrationKey(o)}get id(){return F.makeId(this.type,this.key,this.integrationKey)}get dirPath(){const e=Q[this.type].apiPath;if(this.integrationKey){const t=Q[k.Integration].apiPath;return I.join(t,this.integrationKey,e,this.key)}return I.join(e,this.key)}get path(){return I.join(this.dirPath,"spec.yaml")}get relativePath(){return I.relative(W(process.cwd()),this.path)}get absolutePath(){return I.resolve(I.join(W(process.cwd()),this.path))}isEqual(e){if(this.id!==e.id)return!1;const t=this.clean(),n=e.clean();return _r(t,n)}hasParent(){if(this.data?.parentUuid)return!0;const e=this.getParentKey();return!!e&&!!this.data?.[e]}clean(){const e={...this.data};return Go.forEach(t=>{delete e[t]}),Object.keys(e).forEach(t=>{t.match(/universal.*Revision/)&&delete e[t]}),e}getParentKey(){let e="parentId";return X?.[this.type]?.parentKey&&(e=X?.[this.type]?.parentKey),e}static new(e,t,n,o){return new F(e,t,n,o)}static fromData(e,t){if(!t?.key)throw new Error(`Element missing key: ${JSON.stringify(t)}`);const n=this.extractIntegrationKey(t);return new F(e,t.key,n,t)}static fromPathAndData(e,t){const n=F.parsePath(e);if(!t)return;const o=t?.key||n?.key;return n?F.new(n.type,o,n.integrationKey,t):void 0}static fromElement(e){return new F(e.type,e.key,e.integrationKey,{...e.data})}static idFromPath(e){const t=F.parsePath(e);if(t)return F.makeId(t.type,t.key,t.integrationKey)}static makeId(e,t,n){return e===k.Integration?`${e}:${t}`:F.isIntegrationSpecific(e)?`${n||"universal"}:${e}:${t}`:`${e}:${t}`}static parsePath(e){const t=this.getRelativePath(e);if(!this.isElementFile(t))return;const n=Object.values(Q).map(l=>l.apiPath).join("|"),o=new RegExp(`^(?<elementType>${n})/(?<elementKey>[^/]+)/spec\\.ya?ml$`),i=t.match(o);if(i?.groups){const{elementType:l,elementKey:u}=i.groups,h=this.getElementTypeFromPath(l);if(h)return{type:h,key:u}}const s=new RegExp(`^integrations/(?<integrationKey>[^/]+)/(?<elementType>${n})/(?<elementKey>[^/]+)/spec\\.ya?ml$`),a=t.match(s);if(a?.groups){const{integrationKey:l,elementType:u,elementKey:h}=a.groups,m=this.getElementTypeFromPath(u);if(m)return{type:m,key:h,integrationKey:l}}}static extractIntegrationKey(e){return e?.integrationKey||e?.integration?.key||e?.integration_key||void 0}static isElementFile(e){return e.endsWith(".yml")||e.endsWith(".yaml")}static getElementTypeFromPath(e){return Object.values(k).find(t=>Q[t].apiPath===e)}static getRelativePath(e){return I.relative(W(process.cwd()),e)}static isIntegrationSpecific(e){return jn.includes(e)}static canBeIntegrationSpecific(e){return jn.includes(e)}}class Fn{static{c(this,"BaseWorkspaceElementsRepository")}constructor(e){this.cache=e}connectorsMapping;sourceCache;setConnectorsMapping(e){this.connectorsMapping=e}setSourceCache(e){this.sourceCache=e}async getElements(){const e=[];try{const t=await this.getIntegrations();e.push(...t);const n=[k.Integration,k.Connector],o=Object.keys(X),i=await Promise.all(o.filter(s=>!n.includes(s)).map(async s=>this.getElementsByType(s,t)));for(const s of i)e.push(...s)}catch(t){throw g.error(`Failed to get elements: ${t}`),t}return e}async putElement(e){let t=this.cache.get(e.id);return t&&!e.data.id&&t.data.id&&(e.data.id=t.data.id),!t&&e.data.id&&(t=await this.getByInternalId(e.data.id,e.type,!1)),e.data.id&&t?t=await this.updateElement(e,t,{elements:this.cache.getAll(),connectorsMapping:this.connectorsMapping,sourceElements:this.sourceCache?.getAll()}):t=await this.createElement(e,{elements:this.cache.getAll(),connectorsMapping:this.connectorsMapping,sourceElements:this.sourceCache?.getAll()}),t}async getElementsByType(e,t){return[]}async createElement(e,t){return e}async updateElement(e,t,n){return t}async getElement(e){}async getIntegrations(){return[]}async getByInternalId(e,t,n=!0){}async deleteElement(e,t){}}function $t(r,e=!0){if(T.existsSync(r))try{const t=T.readFileSync(r,"utf8");return Y.load(t)||void 0}catch(t){if(!e)return;if(t instanceof Error){const n=I.relative(process.cwd(),r);throw new Error(`Failed to parse YAML file "${n}": ${t.message}`)}throw t}}c($t,"readYaml");function Ho(r,e,t){try{const n=Y.dump(e,t);T.writeFileSync(r,n,"utf8")}catch(n){if(n instanceof Error){const o=I.relative(process.cwd(),r);throw new Error(`Failed to write YAML file "${o}": ${n.message}`)}throw n}}c(Ho,"writeYaml");class Vo extends Fn{static{c(this,"LocalWorkspaceElementsRepository")}basePath;constructor(e){super(e),this.basePath=W(process.cwd())}async getElementsByType(e,t){const n=[],o=I.join(this.basePath,Q[e].apiPath),i=await this.readElementsInDir(o);n.push(...i);for(const s of t){const a=I.join(this.basePath,Q[k.Integration].apiPath,s.key,Q[e].apiPath),l=await this.readElementsInDir(a);n.push(...l)}return n.length>0&&g.debug(`[local] Fetched ${n.length} ${e}${n.length!==1?"s":""}`),n}async getElement(e){return this.readElement(e.path)}async createElement(e){return this.updateElement(e,e)}async updateElement(e,t){if(!e.data)throw new Error("Element must have data to write");const n=I.join(this.basePath,t.dirPath),o=I.join(this.basePath,t.path);return T.existsSync(n)||T.mkdirSync(n,{recursive:!0}),Ho(o,e.data),g.debug(`[local] Written ${t.relativePath}`),t}async deleteElement(e){const t=I.join(this.basePath,e.path),n=I.join(this.basePath,e.dirPath);T.existsSync(t)&&T.rmSync(t,{force:!0}),this.pruneEmptyDir(n),g.debug(`[local] Deleted ${e.relativePath}`)}async getIntegrations(){const e=I.join(this.basePath,Q[k.Integration].apiPath);return this.readElementsInDir(e)}async readElement(e){const t=$t(e);if(t)return F.fromPathAndData(e,t)}async readElementsInDir(e){const t=[];if(!T.existsSync(e))return t;const n=T.readdirSync(e);if(n.length===0)return t;const o=n.map(async s=>{const a=I.join(e,s,"spec.yaml");return this.readElement(a)});return(await Promise.all(o)).filter(s=>s!=null)}pruneEmptyDir(e){try{if(!e.startsWith(this.basePath)||e===this.basePath||!T.existsSync(e)||T.readdirSync(e).length>0)return;T.rmdirSync(e),this.pruneEmptyDir(I.dirname(e))}catch(t){console.warn(`Failed to prune empty directory ${e}:`,t)}}}class Yo extends Fn{static{c(this,"RemoteWorkspaceElementsRepository")}async getElementsByType(e,t){const n=F.canBeIntegrationSpecific(e),o=await this.findAll(e,n?{layer:"universal"}:{});if(!F.canBeIntegrationSpecific(e))return o;for(const i of t){const s=i.key,a=i.data.id,l=await this.findAll(e,a?{integrationId:a}:{integrationKey:s},s);o.push(...l)}return o.length>0&&g.debug(`[remote] Fetched ${o.length} ${e}${o.length!==1?"s":""}`),o}async getElement(e){const t=await $.withClient(n=>n[X[e.type].element](e.data.id).get());return F.fromData(e.type,t)}async createElement(e,t){const n=e.clean();if(this.transformElementForCreate(e,n,t),e.hasParent()&&n.integrationId&&!n.isCustomized){const s=e.getParentKey(),a=new Set(["uuid","integrationId",s,"meta","integrationUuid","parentUuid"]);Object.keys(n).forEach(l=>{a.has(l)||delete n[l]})}const o=await $.withClient(s=>s[X[e.type].elements].create(n)),i=F.fromData(e.type,o);return g.debug(`[remote] Created ${i.id}`),i}async updateElement(e,t,n){if(!e.data.id)throw new Error("Element must have an id to update");t.data.archivedAt&&await $.withClient(a=>a[X[e.type].element](t.data.id).restore());const o=e.clean();if(this.transformElementForUpdate(e,o,n),e.hasParent()&&o.integrationId&&!o.isCustomized)return g.debug(`[remote] Skipped update for ${t.id} (non-customized)`),t;const i=await $.withClient(a=>a[X[e.type].element](t.data.id).put(o)),s=F.fromData(t.type,i);return g.debug(`[remote] Updated ${t.id}`),s}async deleteElement(e){if(!e.data.id)throw new Error("Element must have an id to delete");await $.withClient(t=>t[X[e.type].element](e.data.id).archive()),g.debug(`[remote] Deleted ${e.id}`)}async getIntegrations(){const e=await $.withClient(n=>n.integrations.findAll());if(!e)return[];const t=e.map(n=>F.fromData(k.Integration,n));return t.length>0&&g.debug(`[remote] Fetched ${t.length} integrations`),t}async getByInternalId(e,t){let n;if(n=await $.withClient(o=>o[X[t].element](e).get(),!1),!!n)return F.fromData(t,n)}transformElementForCreate(e,t,n){if(e.integrationKey){const o=n.elements.find(i=>i.type===k.Integration&&i.key===e.integrationKey);if(o)t.integrationId=o.data.id;else throw new Error(`Dependency integration ${e.integrationKey} not found for ${e.id}`)}if(e.type===k.Integration){const o=n.connectorsMapping?.[t.connectorId];o&&(t.connectorId=o)}this.transformPackageDependencies(e,t,n),this.transformParentDependency(e,t,n)}transformElementForUpdate(e,t,n){if(e.type===k.Integration){const o=n.connectorsMapping?.[t.connectorId];o&&(t.connectorId=o)}if(e.integrationKey){t.integrationKey=e.integrationKey;const o=n.elements.find(i=>i.type===k.Integration&&i.key===e.integrationKey);if(o)t.integrationId=o.data.id;else throw new Error(`Dependency integration ${e.integrationKey} not found for ${e.id}`)}this.transformPackageDependencies(e,t,n),this.transformParentDependency(e,t,n)}transformPackageDependencies(e,t,n){if(e.type!==k.Package||!t.elements)return;const o=t.elements.map(i=>{const a=(n.sourceElements||n.elements).find(u=>u.data.id===i.id&&u.type===i.type);if(!a)throw new Error(`Package element ${i.type} with id ${i.id} not found in source workspace for package ${e.id}`);const l=n.elements.find(u=>u.type===i.type&&u.key===a.key&&u.integrationKey===a.integrationKey);if(!l)throw new Error(`Package element ${i.type} with key ${a.key} not found in target workspace for package ${e.id}`);return{id:l.data.id,type:i.type}});t.elements=o}transformParentDependency(e,t,n){if(!e.hasParent())return;const o=e.getParentKey();if(!o)return;const i=n.elements.find(s=>s.type===e.type&&s.key===e.key&&!s.hasParent());if(i)t[o]=i.data.id;else throw new Error(`Parent ${e.getParentKey()} not found for ${e.id}`)}async findAll(e,t={},n){const o=await $.withClient(i=>i[X[e].elements].findAll(t));return o?o.filter(i=>i.key).map(i=>(n&&!i.integrationKey&&(i.integrationKey=n),F.fromData(e,i))):[]}}class At extends zr{static{c(this,"TypedEventEmitter")}on(e,t){return super.on(e,t)}emit(e,...t){return super.emit(e,...t)}off(e,t){return super.off(e,t)}once(e,t){return super.once(e,t)}}const G={Updated:"updated",Deleted:"deleted",Stopped:"stopped"},Zo={ignored:ao,persistent:!0,ignoreInitial:!0,followSymlinks:!1,depth:20,awaitWriteFinish:{stabilityThreshold:500,pollInterval:100},ignorePermissionErrors:!0,atomic:!0,usePolling:!1,alwaysStat:!1,interval:1e3,binaryInterval:300};class Xo extends At{static{c(this,"LocalElementWatcher")}constructor(e){super(),this.options=e,this.membraneDir=W(this.options.cwd),this.lockTimeoutMs=this.options.lockTimeoutMs??1e3}isWatching=!1;watcher;membraneDir;contentCache={};ignoredPaths=new Set;lockTimeoutMs;async start(){this.isWatching||(T.existsSync(this.membraneDir)||T.mkdirSync(this.membraneDir,{recursive:!0}),this.initializeContentCache(),this.watcher=Wr.watch(this.membraneDir,Zo),this.watcher.on("add",e=>this.handleFileSystemEvent(G.Updated,e)).on("change",e=>this.handleFileSystemEvent(G.Updated,e)).on("unlink",e=>this.handleFileSystemEvent(G.Deleted,e)).on("ready",()=>this.isWatching=!0))}async stop(){!this.isWatching||!this.watcher||(await this.watcher.close(),this.isWatching=!1,this.watcher=void 0,this.clearCache(),this.clearAllLocks(),this.emit(G.Stopped))}getCwd(){return this.options.cwd}async executeWithPathLock(e,t){const n=I.resolve(e);this.ignoredPaths.add(n);try{await t()}finally{setTimeout(()=>{this.ignoredPaths.delete(n)},this.lockTimeoutMs)}}isPathLocked(e){const t=I.resolve(e);if(this.ignoredPaths.has(t))return!0;for(const n of this.ignoredPaths)if(t.startsWith(n+I.sep))return!0;return!1}clearAllLocks(){this.ignoredPaths.clear()}handleFileSystemEvent(e,t){const n=I.relative(this.membraneDir,t);if(this.isPathLocked(t))return;if(e===G.Deleted){this.removeFromCache(n);const a={filePath:t,relativePath:n,data:void 0};g.info(`[local] ${e}: ${a.relativePath}`),this.emit(e,a);return}const o=this.readFileContent(t);if(!this.hasContentChanged(n,o))return;const s=this.processFileEvent(t,o);this.updateCache(n,o),s&&(g.info(`[local] ${e}: ${s.relativePath}`),this.emit(e,s))}readFileContent(e){return T.readFileSync(e,"utf8")}processFileEvent(e,t){const n=I.relative(this.membraneDir,e);let o;try{o=t?Jr.parse(t):void 0}catch{o=void 0}return{filePath:e,relativePath:n,data:o}}hasContentChanged(e,t){if(!t)return this.contentCache[e]!==void 0;const n=this.getContentHash(t);return this.contentCache[e]!==n}getContentHash(e){return qr.createHash("sha256").update(e).digest("hex")}updateCache(e,t){if(!t){delete this.contentCache[e];return}this.contentCache[e]=this.getContentHash(t)}removeFromCache(e){delete this.contentCache[e]}clearCache(){Object.keys(this.contentCache).forEach(e=>{delete this.contentCache[e]})}initializeContentCache(){T.existsSync(this.membraneDir)&&this.scanDirectoryForCache(this.membraneDir)}scanDirectoryForCache(e){const t=T.readdirSync(e,{withFileTypes:!0});for(const n of t){const o=I.join(e,n.name);if(n.isDirectory())this.scanDirectoryForCache(o);else if(n.isFile())try{const i=T.readFileSync(o,"utf8"),s=I.relative(this.membraneDir,o);this.updateCache(s,i)}catch{}}}}var Pt=(r=>(r.Updated="updated",r.ConnectorFileUpdated="connector-file-updated",r.Connected="connected",r.Disconnected="disconnected",r.Error="error",r))(Pt||{});const Qo={debounceMs:2e3,reconnectIntervalMs:5e3,maxReconnectAttempts:1/0,maxBackoffMs:6e4,connectionTimeoutMs:3e5};class ei extends At{static{c(this,"RemoteElementWatcher")}constructor(e=Qo){super(),this.config=e}eventSource;debounceTimeouts=new Map;reconnectAttempts=0;reconnectTimeout;connectionTimeout;isStarted=!1;isConnected=!1;async start(){this.isStarted||(this.isStarted=!0,await this.connect())}async stop(){this.isStarted&&(this.isStarted=!1,this.isConnected=!1,this.clearReconnectTimeout(),this.clearConnectionTimeout(),this.clearAllDebounceTimeouts(),this.eventSource&&(this.eventSource.close(),this.eventSource=void 0))}async connect(){try{g.debug("[remote-events] Connecting to server"),this.eventSource&&(this.eventSource.close(),this.eventSource=void 0);const e=await $.getClient(process.cwd()),t=await e.getToken();if(!t)throw new Error("No auth token available");const n=`${e.apiUri}/sse/workspace?token=${encodeURIComponent(t)}`;g.debug("[remote-events] Subscribing to workspace events"),this.eventSource=new Gr(n),this.setupEventSourceHandlers()}catch(e){g.debug(`[remote-events] Failed to connect: ${e}`),this.emit("error",{error:e}),this.scheduleReconnect()}}setupEventSourceHandlers(){this.eventSource&&(this.eventSource.onopen=()=>{g.debug("[remote-events] Connected to server"),this.reconnectAttempts=0,this.isConnected=!0,this.resetConnectionTimeout(),this.emit("connected",{})},this.eventSource.onmessage=e=>{try{this.resetConnectionTimeout();const t=JSON.parse(e.data);this.handleElementUpdate(t)}catch(t){g.debug(`[remote-events] Failed to parse workspace event: ${t}`)}},this.eventSource.onerror=e=>{g.debug(`[remote-events] Connection error: ${JSON.stringify(e,null,2)}`),this.isConnected=!1,this.clearConnectionTimeout(),this.eventSource&&(this.eventSource.close(),this.eventSource=void 0),this.emit("disconnected",{}),this.isStarted&&this.scheduleReconnect()})}handleElementUpdate(e){if(e.type!==Er.ElementUpdate)return;const{elementId:t,elementType:n,data:o={}}=e;if(!(!t||!n)){if(n===k.Connector){const{filePath:i,eventType:s,newPath:a}=o;return g.debug(`[remote-watcher] Received connector event - elementId: ${t}, filePath: ${i}, eventType: ${s}`),this.scheduleConnectorFileUpdate(t,i,s,a)}return this.scheduleElementUpdate(t,n)}}scheduleElementUpdate(e,t){const n=this.debounceTimeouts.get(e);n&&clearTimeout(n);const o=setTimeout(()=>{this.debounceTimeouts.delete(e),this.emit("updated",{elementId:e,elementType:t})},this.config.debounceMs);this.debounceTimeouts.set(e,o)}scheduleConnectorFileUpdate(e,t,n,o){const i=JSON.stringify({connectorId:e,filePath:t}),s=this.debounceTimeouts.get(i);s&&clearTimeout(s);const a=setTimeout(()=>{this.debounceTimeouts.delete(i),this.emit("connector-file-updated",{connectorId:e,filePath:t,eventType:n,newPath:o})},this.config.debounceMs);this.debounceTimeouts.set(i,a)}scheduleReconnect(){if(!this.isStarted||this.reconnectAttempts>=this.config.maxReconnectAttempts){this.reconnectAttempts>=this.config.maxReconnectAttempts&&(g.error("[remote-events] Max reconnection attempts reached. Connection will not be retried."),this.emit("error",{error:new Error("Max reconnection attempts reached")}));return}this.reconnectTimeout&&clearTimeout(this.reconnectTimeout),this.reconnectAttempts++;const e=this.config.reconnectIntervalMs*Math.pow(2,this.reconnectAttempts-1),t=Math.random()*.3*e,n=Math.min(e+t,this.config.maxBackoffMs);g.debug(`[remote-events] Reconnecting in ${Math.round(n)}ms (attempt ${this.reconnectAttempts})`),this.reconnectTimeout=setTimeout(()=>{this.connect()},n)}clearReconnectTimeout(){this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=void 0)}resetConnectionTimeout(){this.clearConnectionTimeout(),this.connectionTimeout=setTimeout(()=>{this.isConnected&&this.isStarted&&(g.debug("[remote-events] Connection timeout detected, reconnecting..."),this.isConnected=!1,this.eventSource&&(this.eventSource.close(),this.eventSource=void 0),this.scheduleReconnect())},this.config.connectionTimeoutMs)}clearConnectionTimeout(){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=void 0)}clearAllDebounceTimeouts(){this.debounceTimeouts.forEach(e=>clearTimeout(e)),this.debounceTimeouts.clear()}}class Un{static{c(this,"ElementsCache")}elements=new Map;typeIndex=new Map;internalIdIndex=new Map;constructor(e){e&&this.addAll(e)}add(e){const t=e.id;this.elements.set(t,e),this.typeIndex.has(e.type)||this.typeIndex.set(e.type,new Set),this.typeIndex.get(e.type).add(t),e.data?.id&&this.internalIdIndex.set(e.data.id,t)}remove(e){const t=e.id,n=this.elements.delete(t);if(n){const o=this.typeIndex.get(e.type);o&&(o.delete(t),o.size===0&&this.typeIndex.delete(e.type)),e.data?.id&&this.internalIdIndex.delete(e.data.id)}return n}put(e){this.elements.has(e.id)&&this.remove(e),this.add(e)}get(e){return this.elements.get(e)}getByInternalId(e){const t=this.internalIdIndex.get(e);if(t)return this.elements.get(t)}getElementsByType(e){const t=this.typeIndex.get(e);return t?Array.from(t).map(n=>this.elements.get(n)).filter(n=>n!==void 0):[]}getAll(){return Array.from(this.elements.values())??[]}getTypes(){return Array.from(this.typeIndex.keys())}addAll(e){for(const t of e)t&&this.add(t)}removeAll(e){for(const t of e)this.remove(t)}getElementIdsByType(e){return this.typeIndex.get(e)}clear(){this.elements.clear(),this.typeIndex.clear(),this.internalIdIndex.clear()}getAllIds(){return new Set(this.elements.keys())}}const ve="connectors",re="development",Ot={};async function Kn(r={}){const{onProgress:e}=r,t=new Set,o=(await $.withClient(u=>u.get("org-workspace-id"))).id,i={};g.info("[connectors] Loading custom connectors"),await $.withClient(u=>u.get(`/connectors?workspaceId=${o}`)),g.info("[connectors] Loading public connectors");const s=ie(),l=(O.existsSync(s)?O.readdirSync(s):[]).filter(u=>{if(u.startsWith("."))return!1;const h=x.join(s,u);try{return O.statSync(h).isDirectory()}catch{return!1}});for(const u of l){g.info(`[connectors] Loading connector from: ${u}`);const h=O.readdirSync(x.join(s,u)),m=await Rt(u);if(!m)continue;e?.("pushing",m.name),"baseUri"in m&&delete m.baseUri;let f;m.uuid&&(f=await $.withClient(S=>S.get(`/connectors/${m.uuid}`),!1));const C=m.uuid;if(f)i[C]=f.id,g.info(`[connectors] Matched ${m.name} uuid: ${m.uuid}`),f.isPublic||(f.archivedAt&&(g.info(`[connectors] Restoring archived connector ${m.name}`),await $.withClient(S=>S.post(`connectors/${f.id}/restore`))),g.info(`[connectors] Updating connector ${m.name}`),await $.withClient(S=>S.patch(`connectors/${f.id}`,{...m,workspaceId:o})));else if(!i[C]&&!f?.isPublic){let S=!1;try{const N=await Nt({connectorId:C});N&&N.isPublic&&(S=!0)}catch{}if(!S){g.info(`[connectors] Creating custom connector ${m.name} (${m.key})`);const N=await $.withClient(P=>P.post("connectors",{...m,workspaceId:o}));i[C]=N.id}}const E=h.filter(S=>O.statSync(x.join(s,u,S)).isDirectory());for(const S of E)await ri({connector:m,version:S,connectorId:i[C]}),t.add(C);e?.("pushed",m.name)}return{connectorsMapping:i,pushedConnectors:Array.from(t)}}c(Kn,"pushConnectors");async function _n({connectorId:r,connectorVersion:e,allConnectors:t,pulledConnectors:n,pulledConnectorVersions:o}){if(!r||o[r]?.has(e))return;const i=mn(),s=await Nt({connectorId:r});if(!s.isPublic||t){if(!s?.key){console.error(`[connectors] Connector ${r} has no key. Skipping..`),g.error(`[connectors] Connector ${r} has no key. Skipping..`);return}n.has(r)||(await oi({basePath:i,connector:s}),n.add(r)),o[r]||(o[r]=new Set),o[r].has(e)||(await ii({connector:s,connectorVersion:e,basePath:i}),o[r].add(e))}}c(_n,"pullRemoteConnector");function ie(){const r=mt();return x.join(r.membraneDirPath,ve)}c(ie,"getConnectorsPath");async function Rt(r){const e=x.join(ie(),r,`${r}.yml`);return $t(e,!1)}c(Rt,"readConnector");async function ti(r,e){return g.info(`[connectors] Zipping ${r} into ${e}`),new Promise((t,n)=>{const o=O.createWriteStream(e),i=ot("zip",{zlib:{level:9}});o.on("close",()=>{g.success(`[connectors] Successfully created ${e}`),t()}),o.on("end",()=>{g.info("[connectors] Data has been drained")}),i.on("warning",a=>{a.code==="ENOENT"?console.warn(a):n(a)}),i.on("error",a=>{n(a)}),i.pipe(o);const s=O.readdirSync(r);for(const a of s){const l=x.join(r,a),u=O.statSync(l);u.isFile()?i.file(l,{name:a}):u.isDirectory()&&i.directory(l,a)}i.finalize()})}c(ti,"createZipArchive");async function ni(r,e){return g.info(`[connectors] Unzipping into ${e}`),new Promise((t,n)=>{const o=_e.Parse();o.on("entry",i=>{const s=i.path;if(i.type==="Directory"){const l=x.join(e,s);O.mkdirSync(l,{recursive:!0}),i.autodrain()}else{const l=x.join(e,s),u=x.dirname(l);O.mkdirSync(u,{recursive:!0});const h=O.createWriteStream(l);i.pipe(h),h.on("finish",()=>{})}}),o.on("end",()=>{g.success(`[connectors] Successfully extracted to ${e}`),t()}),o.on("error",i=>{n(i)}),o.write(r),o.end()})}c(ni,"extractZipArchive");async function ri({connector:r,version:e,connectorId:t}){const n=x.join(ie(),oe(r),qn(e)),o=x.join(n,"src"),i=x.join(n,"src.zip"),s=O.existsSync(i);if(O.existsSync(o)&&(g.info(`[connectors] Archiving source code for ${r.name} version ${e}`),await ti(o,i)),!O.existsSync(i)){g.warning(`[connectors] No source code found for ${r.name} version ${e}`);return}try{const a=new sn;if(a.append("file",O.createReadStream(i),"file.zip"),g.info(`[connectors] Pushing connector version ${e} for ${r.name}`),e==re)g.info(`[connectors] Uploading connector ${t}`),await $.withClient(l=>l.post(`connectors/${t}/upload`,a,{headers:{...a.getHeaders()}}));else{if(a.append("version",e),a.append("changelog","Imported Version"),(await $.withClient(u=>u.get(`/connectors/${t}/versions`))).find(u=>u.version==e)){g.info(`[connectors] Version ${e} already published`);return}g.info(`[connectors] Publishing version ${e} of connector ${t}`),await $.withClient(u=>u.post(`connectors/${t}/publish-version`,a,{headers:{...a.getHeaders()}}))}g.success(`Successfully pushed connector version ${e} for ${r.name}`)}catch(a){g.error(`Error pushing connector version ${e} for ${r.name}: ${a}`),console.error(`[connectors] Error pushing connector version ${e} for ${r.name}: ${a}`)}finally{!s&&O.existsSync(i)&&(g.info(`[connectors] Cleaning up temporary zip file for ${r.name} version ${e}`),O.unlinkSync(i))}}c(ri,"pushConnectorVersion");async function Nt({connectorId:r}){if(r){if(Ot[r])return Ot[r];try{const e=await $.withClient(t=>t.get(`connectors/${r}`),!1);return Ot[r]=e,e}catch(e){return g.error(`[connectors] Failed to get connector ${r}: ${e}`),console.error(`[connectors] Failed to get connector ${r}: ${e}`),null}}}c(Nt,"getConnector");async function oi({basePath:r,connector:e}){const t=oe(e),n=x.join(r,ve,t);O.mkdirSync(n,{recursive:!0});const o=x.join(n,`${oe(e)}.yml`);O.writeFileSync(o,Y.dump(e)),g.info(`[connectors] Pulled connector ${e.name}`)}c(oi,"pullConnector$1");async function ii({connector:r,connectorVersion:e,basePath:t}){const n=oe(r),o=qn(e),i=x.join(t,"connectors",n,o),s=await $.withClient(l=>l.get(`connectors/${r.id}/download`,{version:e},{responseType:"arraybuffer",headers:{Accept:"application/zip"},timeout:1e6}));O.mkdirSync(i,{recursive:!0});const a=x.join(i,"src.zip");if(O.writeFileSync(a,s),!e){const l=x.join(i,"src");O.mkdirSync(l,{recursive:!0}),await ni(s,l)}g.info(`[connectors] Pulled connector version: ${r.name} (${o})`)}c(ii,"pullConnectorVersion");function oe(r){return r.key}c(oe,"getConnectorDirName");function qn(r){return r??re}c(qn,"getConnectorVersionDirName");function si(r){const e=mn(),t=oe(r);return x.join(e,ve,t)}c(si,"getConnectorDirPath");function ai(r){return r.match(`${ve}/[^/]+/${re}/src/.*`)!==null}c(ai,"isConnectorSourceFile");async function ci(r){const e=r.match(`${ve}/([^/]+)/${re}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await Rt(t);if(!o){g.warning(`[connectors] Connector ${t} not found. Ignoring file change`);return}const i=o.id,s=O.readFileSync(r,"utf-8");await $.withClient(a=>a.put(`connectors/${i}/files/${n}`,s,{headers:{"Content-Type":"text/plain"}})),g.info(`[connectors] Pushed file ${n} for connector ${o.name}`)}c(ci,"putConnectorFile");async function li(r){const e=r.match(`${ve}/([^/]+)/${re}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await Rt(t);if(!o){g.warning(`[connectors] Connector ${t} not found. Ignoring file change`);return}const i=o.id;await $.withClient(s=>s.delete(`connectors/${i}/files/${n}`)),g.info(`[connectors] Deleted file ${n} for connector ${o.name}`)}c(li,"deleteConnectorFile");async function ui(r,e){try{const t=await $.withClient(s=>s.get(`connectors/${r}`));if(!t){g.warning(`[connectors] Connector ${r} not found`);return}const n=await $.withClient(s=>s.get(`connectors/${r}/files/${e}`)),o=oe(t),i=x.join(ie(),o,re,"src",e);O.mkdirSync(x.dirname(i),{recursive:!0}),n!=null?(O.writeFileSync(i,n),g.info(`[connectors] Pulled file ${e} for connector ${t.name}`)):O.existsSync(i)&&(O.unlinkSync(i),g.info(`[connectors] Deleted file ${e} for connector ${t.name}`))}catch(t){g.error(`[connectors] Failed to pull connector file ${e} for connector ${r}: ${t}`),console.error(`[connectors] Failed to pull connector file ${e} for connector ${r}: ${t}`)}}c(ui,"pullConnectorFile");async function di(r,e){const t=await $.withClient(i=>i.get(`connectors/${r}`),!1);if(!t){g.warning(`[connectors] Connector ${r} not found`);return}const n=oe(t),o=x.join(ie(),n,re,"src",e);O.existsSync(o)&&(O.unlinkSync(o),g.info(`[connectors] Deleted file ${e} for connector ${n}`))}c(di,"deleteLocalConnectorFile");async function hi(r,e,t){if(t&&e!==t)try{const n=await $.withClient(l=>l.get(`connectors/${r}`),!1);if(!n){g.warning(`[connectors] Connector ${r} not found`);return}const o=oe(n),i=x.join(ie(),o,re,"src"),s=x.join(i,e),a=x.join(i,t);O.existsSync(s)&&(O.mkdirSync(x.dirname(a),{recursive:!0}),O.renameSync(s,a),g.info(`[connectors] Renamed directory from ${e} to ${t} for connector ${o}`))}catch(n){g.error(`[connectors] Failed to rename directory ${e} to ${t} for connector ${r}: ${n}`)}}c(hi,"renameLocalConnectorDirectory");async function pi(r,e){try{const t=await $.withClient(i=>i.get(`connectors/${r}`),!1);if(!t){g.warning(`[connectors] Connector ${r} not found`);return}const n=oe(t),o=x.join(ie(),n,re,"src",e);if(O.existsSync(o)){const i=x.resolve(ie());if(!x.resolve(o).startsWith(i))return;O.rmSync(o,{recursive:!0,force:!0}),g.info(`[connectors] Deleted directory ${e} for connector ${n}`)}}catch(t){g.error(`[connectors] Failed to delete directory ${e} for connector ${r}: ${t}`)}}c(pi,"deleteLocalConnectorDirectory");const U={LogAdded:"logAdded",StateChanged:"stateChanged",StatsChanged:"statsChanged",ConflictsChanged:"conflictsChanged",McpStatusChanged:"mcpStatusChanged",McpServersChanged:"mcpServersChanged",ConfigChanged:"configChanged"};class fi extends At{static{c(this,"WorkspaceNotifications")}constructor(e){super(),this.config=e,g.setNotificationHandler(this)}clientId;heartbeatInterval;isCleaningUp=!1;async connectToRemote(){await this.registerWithRemoteServer(),await this.startHeartbeatLoop()}async setState(e){this.emit(U.StateChanged,{state:e}),await this.emitRemote({status:e})}setConflicts(e){this.emit(U.ConflictsChanged,{conflicts:e})}setConfig(e){this.emit(U.ConfigChanged,{config:e})}setStats(e){this.emit(U.StatsChanged,{stats:e})}addLog(e){this.emit(U.LogAdded,{log:e})}setMcpStatus(e){this.emit(U.McpStatusChanged,{status:e})}async setMcpServers(e){this.emit(U.McpServersChanged,{servers:e}),await this.emitRemote({mcpServers:e.map(t=>({name:t.agentName,totalRequests:t.totalRequests}))})}async cleanup(){!this.clientId||this.isCleaningUp||(this.isCleaningUp=!0,this.heartbeatInterval&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=void 0),await this.withErrorHandling(async()=>{await $.withClient(e=>e.delete(`/local-clients/${this.clientId}`))}),this.clientId=void 0)}async registerWithRemoteServer(){if(this.clientId)return;const e=await this.withErrorHandling(async()=>await $.withClient(t=>t.post("/local-clients",{hostname:tt.hostname(),workingDirectory:process.cwd()})));e?.id?this.clientId=e.id:this.addLog({timestamp:new Date().toISOString(),message:"Failed to register with remote server",type:"error"})}async startHeartbeatLoop(){this.heartbeatInterval=setInterval(async()=>{this.clientId&&await this.sendHeartbeat()},this.config.heartbeatIntervalMs)}async sendHeartbeat(){this.clientId&&await this.withErrorHandling(async()=>{await $.withClient(e=>e.post(`/local-clients/${this.clientId}/keep-alive`,{}))})}async emitRemote(e){this.clientId&&await this.withErrorHandling(async()=>{await $.withClient(t=>t.patch(`/local-clients/${this.clientId}`,e))})}async withErrorHandling(e){try{return await e()}catch(t){const n=t instanceof Error?t.message:String(t);return this.addLog({timestamp:new Date().toISOString(),message:`Failed to connect to remote: ${n}`,type:"error"}),null}}}const se=new fi({heartbeatIntervalMs:15e3}),Bn=[k.AppDataSchema,k.AppEventType,k.DataLinkTable,k.DataSource,k.FieldMapping,k.Action,k.Flow,k.Package];class De{static{c(this,"ElementSyncService")}localWatcher=void 0;remoteWatcher=void 0;notifier;changes=[];localCache;remoteCache;localRepo;remoteRepo;pulledConnectors=new Set;pulledConnectorVersions={};constructor(){this.notifier=se,this.localCache=new Un,this.remoteCache=new Un,this.localRepo=new Vo(this.localCache),this.remoteRepo=new Yo(this.remoteCache)}clear(){this.changes=[]}needsForcedSync(){return this.changes.some(e=>e.isConflict)}needsSync(){return this.changes.length>0}async getStats(){const e=this.localCache.getAll(),t={};return e.forEach(n=>{t[n.type]=(t[n.type]||0)+1}),t}async fetchElements(){const e=await this.localRepo.getElements(),t=await this.remoteRepo.getElements();this.localCache.addAll(e),this.remoteCache.addAll(t)}async updateElement(e,t){const n=this.getHandler(t),o=this.getCache(t);try{const i=await n.putElement(e);o.put(i)}catch(i){throw g.error(`Failed to update element ${e.id}: ${i}`),i}}async deleteElement(e,t){const n=this.getHandler(t),o=this.getCache(t);try{await n.deleteElement(e,{elements:n.cache.getAll(),connectorsMapping:n.connectorsMapping}),o.remove(e)}catch(i){throw g.error(`Failed to delete element ${e.id}: ${i}`),i}}async pullConnectors(e=!1){const t=this.remoteCache.getElementsByType(k.Integration).map(n=>n.data);for(const n of t){const o=n.connectorId,i=n.connectorVersion;o&&await _n({connectorId:o,connectorVersion:i,allConnectors:e,pulledConnectors:this.pulledConnectors,pulledConnectorVersions:this.pulledConnectorVersions})}}async pushConnectors(){const{connectorsMapping:e}=await Kn();this.remoteRepo.setConnectorsMapping(e)}getHandler(e){return e===z.INCOMING?this.localRepo:(this.remoteRepo.setSourceCache(this.localCache),this.remoteRepo)}getCache(e){return e===z.INCOMING?this.localCache:this.remoteCache}async startWatching(){this.localWatcher=new Xo({cwd:process.cwd(),lockTimeoutMs:1e3}),this.localWatcher.on(G.Updated,e=>this.handleLocalEvent(e,G.Updated)),this.localWatcher.on(G.Deleted,e=>this.handleLocalEvent(e,G.Deleted)),await this.localWatcher.start(),g.success("[local] Tracking changes.."),this.remoteWatcher=new ei,this.remoteWatcher.on(Pt.Updated,({elementId:e,elementType:t})=>this.handleRemoteElementEvent(e,t)),this.remoteWatcher.on(Pt.ConnectorFileUpdated,({connectorId:e,filePath:t,eventType:n,newPath:o})=>this.handleRemoteConnectorFileEvent(e,t,n,o)),await this.remoteWatcher.start(),g.success("[remote] Tracking changes..")}async stopWatching(){this.localWatcher&&(await this.localWatcher.stop(),this.localWatcher=void 0),this.remoteWatcher&&(await this.remoteWatcher.stop(),this.remoteWatcher=void 0)}async handleRemoteElementEvent(e,t){try{const n=await this.remoteRepo.getByInternalId(e,t),o=!!n?.data.archivedAt||!!n?.data.isDeactivated;if(!n||o){const s=n||this.remoteCache.getByInternalId(e);return s?(g.info(`[${this.getDirectionLabel(z.INCOMING)}] Deleted: ${s.id}`),this.localWatcher?.executeWithPathLock(s.absolutePath,()=>this.deleteElement(s,z.INCOMING))):void 0}if(g.info(`[${this.getDirectionLabel(z.INCOMING)}] Updated: ${n.id}`),await this.localWatcher?.executeWithPathLock(n.absolutePath,async()=>this.updateElement(n,z.INCOMING)),t===k.Integration){const s=n.data.connectorId,a=n.data.connectorVersion,l=await Nt({connectorId:s});if(!l?.key)return;const u=si(l);await this.localWatcher?.executeWithPathLock(u,async()=>_n({connectorId:s,connectorVersion:a,allConnectors:!1,pulledConnectors:this.pulledConnectors,pulledConnectorVersions:this.pulledConnectorVersions}))}}catch(n){g.error(`[sync] Error handling remote event: ${n}`)}}async handleRemoteConnectorFileEvent(e,t,n,o){try{switch(n){case Ze.ConnectorFileDeleted:await di(e,t);break;case Ze.ConnectorDirectoryRenamed:await hi(e,t,o);break;case Ze.ConnectorDirectoryDeleted:await pi(e,t);break;default:await ui(e,t);break}}catch(i){g.error(`[sync] Error handling remote connector file event: ${i}`)}}async handleLocalEvent(e,t){try{if(ai(e.filePath))switch(t){case G.Updated:await ci(e.filePath);break;case G.Deleted:await li(e.filePath);break}else{let n=F.fromPathAndData(e.filePath,e.data);if(!n){const o=F.idFromPath(e.filePath);if(!o||(n=this.remoteCache.get(o),!n))return}switch(g.info(`[${this.getDirectionLabel(z.OUTGOING)}] ${Kr(t)}: ${n.id}`),t){case G.Updated:await this.updateElement(n,z.OUTGOING);break;case G.Deleted:await this.deleteElement(n,z.OUTGOING);break}}}catch(n){g.error(`[sync] Error handling local event: ${n}`)}}detectIncomingChanges(){this.clearChanges();const e=De.getChanges(z.INCOMING,this.remoteCache,this.localCache);return this.updateChanges(e),e}detectOutgoingChanges(){this.clearChanges();const e=De.getChanges(z.OUTGOING,this.localCache,this.remoteCache);return this.updateChanges(e),e}async resolveChanges(){if(!this.needsSync())return;g.info("[resolver] Resolving changes.."),g.info("[resolver] Resolving integration elements");const e=this.changes.filter(o=>o.element.type===k.Integration);await Promise.all(e.map(async o=>this.resolveChange(o))),e.length>0&&(await this.fetchElements(),this.changes=this.changes.length>0&&this.changes[0]?.direction===z.INCOMING?this.detectIncomingChanges():this.detectOutgoingChanges(),this.changes=this.changes.filter(o=>o.element.type!==k.Integration)),g.info("[resolver] Resolving universal elements");const t=this.changes.filter(o=>!o.element.hasParent());for(const o of Bn){const i=t.filter(s=>s.element.type===o);g.info(`[resolver] Resolving ${o} elements`),await Promise.all(i.map(async s=>this.resolveChange(s)))}g.info("[resolver] Resolving integration level elements");const n=this.changes.filter(o=>o.element.hasParent());for(const o of Bn){const i=n.filter(s=>s.element.type===o);g.info(`[resolver] Resolving ${o} elements`),await Promise.all(i.map(async s=>this.resolveChange(s)))}g.success("[resolver] Resolved changes")}async resolveChange(e){switch(e.type){case ne.DELETE:return this.deleteElement(e.element,e.direction);case ne.CREATE:return this.updateElement(e.element,e.direction);case ne.UPDATE:return this.updateElement(e.element,e.direction)}}static getChanges(e,t,n){const o=t.getAllIds(),i=n.getAllIds(),s=new Set([...o,...i]),a=[];for(const l of s){const u=t.get(l),h=n.get(l),m=De.detectChangeForElement(u,h,e);m&&a.push(m)}return a}updateChanges(e){if(this.changes=e,this.needsForcedSync()){const t=e.filter(n=>n.isConflict);g.warning("[resolver] Conflicts detected"),this.notifier.setConflicts(t)}}clearChanges(){this.changes=[]}getDirectionLabel(e){switch(e){case z.INCOMING:return"local\u2190remote";case z.OUTGOING:return"local\u2192remote"}}static detectChangeForElement(e,t,n){return e&&!t?{type:ne.CREATE,element:e,direction:n,isConflict:!1}:!e&&t?{type:ne.DELETE,element:t,direction:n,isConflict:!0}:e&&t&&!e.isEqual(t)?{type:ne.UPDATE,element:e,direction:n,isConflict:!1}:null}}const ae=I.join(Hr.tmpdir(),"membrane-mcp-status"),Wn=3e4;class mi{static{c(this,"McpStatusService")}constructor(e=2e3){this.pollIntervalMs=e}isRunning=!1;pollInterval;async start(){this.isRunning||(this.isRunning=!0,this.pollInterval=setInterval(async()=>await this.checkStatus(),this.pollIntervalMs),await this.checkStatus())}async stop(){this.pollInterval&&(clearInterval(this.pollInterval),this.pollInterval=void 0,this.isRunning=!1)}async checkStatus(){try{const e=process.cwd(),t=Je(void 0,e),n=Jn(e);t&&se.setMcpStatus(t),await se.setMcpServers(n)}catch{g.error("Failed to check MCP status")}}}function Je(r,e){try{const t=e||process.cwd();if(!r){const o=Jn(t);return o.length===0?null:o[0]}const n=Mt(r,t);if(T.existsSync(n)){const o=T.statSync(n),i=new Date;if(i.getTime()-o.mtime.getTime()>Wn)return Re(r,t),null;const a=T.readFileSync(n,"utf8"),l=JSON.parse(a);if(l.isRunning){const u=new Date(l.lastActivity).getTime();if(i.getTime()-u>Wn)return Re(r,t),null}return l}}catch{r&&e&&Re(r,e)}return null}c(Je,"getMcpStatus");function Jn(r){try{const e=r||process.cwd(),t=Lt(e);if(!T.existsSync(ae))return[];const n=T.readdirSync(ae),o=[];for(const i of n){const s=i.match(new RegExp(`^mcp-${t}-(\\d+)\\.json$`));if(s){const a=parseInt(s[1],10),l=Je(a,e);l&&o.push(l)}}return o.sort((i,s)=>new Date(s.startTime).getTime()-new Date(i.startTime).getTime())}catch{return[]}}c(Jn,"getAllMcpStatusFiles");function Dt(r){try{const t={...Je(r.processId,r.cwd)||{isRunning:!1,startTime:new Date().toISOString(),lastActivity:new Date().toISOString(),toolsCount:0,totalRequests:0,processId:r.processId,cwd:r.cwd,agentName:process.env.AGENT_NAME||"Unnamed Agent"},...r};T.existsSync(ae)||T.mkdirSync(ae,{recursive:!0});const n=Mt(r.processId,r.cwd);T.writeFileSync(n,JSON.stringify(t,null,2))}catch{}}c(Dt,"updateMcpStatus");function Re(r,e){try{const t=e||process.cwd();if(r){const n=Mt(r,t);T.existsSync(n)&&T.unlinkSync(n)}else{const n=Lt(t);if(T.existsSync(ae)){const o=T.readdirSync(ae);for(const i of o)i.match(new RegExp(`^mcp-${n}-\\d+\\.json$`))&&T.unlinkSync(I.join(ae,i))}}}catch{}}c(Re,"clearMcpStatus");function gi(r,e){const t=Je(r,e);t&&Dt({processId:r,cwd:e,totalRequests:t.totalRequests+1,lastRequestTime:new Date().toISOString(),lastActivity:new Date().toISOString()})}c(gi,"trackToolExecution");function Lt(r){return Br("md5").update(r).digest("hex").slice(0,8)}c(Lt,"getCwdHash");function Mt(r,e){const t=Lt(e);return I.join(ae,`mcp-${t}-${r}.json`)}c(Mt,"getStatusFilePath");const ze={Agent:"agent",Cli:"cli"},A={NOT_INITIALIZED:"not_initialized",SETTING_UP:"setting_up",INITIALIZED:"initialized",NOT_SYNCED:"not_synced",PULLING:"pulling",PUSHING:"pushing",RESOLVING:"resolving",CONFLICTS:"conflicts",SYNCED:"synced",WATCHING:"watching",ERROR:"error"};class yi{static{c(this,"MembraneCLIService")}constructor(e,t,n=()=>process.exit(0)){this.mode=e,this.cwd=t,this.onShutdown=n,this.notifier=se,this.mcpStatusService=new mi,this.syncService=new De,this.setupProcessCleanup()}initialized=!1;notifier;mcpStatusService;syncService;isShuttingDown=!1;currentConfig=null;get config(){return this.currentConfig}getSyncedElements(){return this.syncService.localCache.getAll()}getSyncedElementsByType(e){return this.syncService.localCache.getElementsByType(e)}async fetchElements(){await this.syncService.fetchElements()}async pullWorkspace(e={}){let t=!1;try{if(g.setVerboseMode(!!e.verbose),e.rps!==void 0&&$.init({maxRequestsPerSecond:e.rps}),await this.notifier.setState(A.PULLING),await this.syncService.fetchElements(),this.syncService.detectIncomingChanges(),this.syncService.needsForcedSync()&&!e.force){await this.notifier.setState(A.CONFLICTS),e.watch||(t=!0);return}await this.syncService.pullConnectors(e.allConnectors),await this.syncWorkspaces(e)}catch(n){t=!0,g.error(`Failed to pull workspace: ${n}`),await this.notifier.setState(A.ERROR),g.saveLogsToFile("error")}finally{if(e.saveLogs&&g.saveLogsToFile(),t)process.exit(1);else return e?.onComplete?.()}}async pushWorkspace(e={}){let t=!1;try{if(g.setVerboseMode(!!e.verbose),e.rps!==void 0&&$.init({maxRequestsPerSecond:e.rps}),await this.notifier.setState(A.PUSHING),await this.syncService.fetchElements(),this.syncService.detectOutgoingChanges(),this.syncService.needsForcedSync()&&!e.force){await this.notifier.setState(A.CONFLICTS),e.watch||(t=!0);return}await this.syncService.pushConnectors(),await this.syncWorkspaces(e)}catch(n){t=!0,g.error(`Failed to push workspace: ${n}`),await this.notifier.setState(A.ERROR),g.saveLogsToFile("error")}finally{if(e.saveLogs&&g.saveLogsToFile(),t)process.exit(1);else return e?.onComplete?.()}}async syncWorkspaces(e={}){try{e.verbose!==void 0&&g.setVerboseMode(!!e.verbose),await this.notifier.setState(A.RESOLVING),this.syncService.needsSync()&&await this.syncService.resolveChanges();const t=await this.syncService.getStats();this.notifier.setStats(t),await this.notifier.setState(A.SYNCED),e.watch&&(await this.notifier.setState(A.WATCHING),await this.syncService.startWatching())}catch(t){g.error(`Failed to sync local and remote workspaces: ${t}`),await this.notifier.setState(A.ERROR),g.saveLogsToFile("error")}}async init({force:e=!1}={}){if(!(this.initialized&&!e)){await this.notifier.setState(A.NOT_INITIALIZED);try{await this.loadConfig(),fe.isCacheDefined()?(await this.initServices(),this.initialized=!0,await this.notifier.setState(A.INITIALIZED)):(this.initialized=!1,await this.notifier.setState(A.SETTING_UP))}catch(t){g.error(`Failed to initialize services: ${t}`),await this.notifier.setState(A.ERROR),g.saveLogsToFile("error"),this.onShutdown()}}}async loadConfig(){this.currentConfig=fe.loadConfig(this.cwd),this.notifier.setConfig(this.currentConfig)}async updateConfig(e){const t={...this.currentConfig,...e};if(!(JSON.stringify(t)!==JSON.stringify(this.currentConfig)))return;await this.stopServices();const o=fe.updateConfig(t);this.currentConfig=o,await this.init({force:!0})}async shutdown(){!this.initialized||this.isShuttingDown||(this.isShuttingDown=!0,this.mode===ze.Agent&&(await this.notifier.cleanup(),await this.mcpStatusService.stop()),this.initialized=!1,this.onShutdown())}async initServices(){this.mode===ze.Agent&&(await this.notifier.connectToRemote(),await this.mcpStatusService.start()),this.syncService.clear()}async stopServices(){this.mode===ze.Agent&&(await this.notifier.cleanup(),await this.mcpStatusService.stop())}setupProcessCleanup(){["SIGINT","SIGTERM","uncaughtException","unhandledRejection"].forEach(t=>process.on(t,()=>this.shutdown())),process.on("beforeExit",t=>{t===0&&this.shutdown()})}}const zn=at(null);function wi({children:r,membraneCLIService:e}){const{data:t}=un("/account"),[n,o]=L(A.NOT_INITIALIZED),[i,s]=L([]),[a,l]=L({}),[u,h]=L([]),[m,f]=L(null),E=t?.workspaces?.find(S=>S.workspaceKey===m?.workspaceKey)||null;return Se(()=>{const S=c(({state:j})=>o(j),"handleStateChanged"),N=c(({stats:j})=>l(j),"handleStatsChanged"),P=c(({log:j})=>h(Le=>[...Le,j]),"handleLogAdded"),K=c(({conflicts:j})=>s(j),"handleConflictsUpdated"),_=c(({config:j})=>f(j),"handleConfigChanged");return e.notifier.on(U.StateChanged,S),e.notifier.on(U.StatsChanged,N),e.notifier.on(U.LogAdded,P),e.notifier.on(U.ConflictsChanged,K),e.notifier.on(U.ConfigChanged,_),e.init(),()=>{e.notifier.off(U.StateChanged,S),e.notifier.off(U.StatsChanged,N),e.notifier.off(U.LogAdded,P),e.notifier.off(U.ConflictsChanged,K),e.notifier.off(U.ConfigChanged,_)}},[]),d(zn.Provider,{value:{state:n,stats:a,logs:u,currentWorkspace:E,conflicts:i,config:m,updateConfig:c(S=>e.updateConfig(S),"updateConfig"),resolveConflicts:c(S=>e.syncWorkspaces(S),"resolveConflicts"),pull:c(S=>e.pullWorkspace(S),"pull"),push:c(S=>e.pushWorkspace(S),"push"),exit:c(()=>e.shutdown(),"exit"),fetchElements:c(()=>e.fetchElements(),"fetchElements"),getSyncedElementsByType:c(S=>e.getSyncedElementsByType(S),"getSyncedElementsByType")},children:r})}c(wi,"MembraneCLIServiceProvider");function Z(){const r=ct(zn);if(!r)throw new Error("useMembraneCLIService must be used within MembraneCLIServiceProvider");return r}c(Z,"useMembraneCLIService");const jt=at(null),Gn=c(()=>{const r=ct(jt);if(!r)throw new Error("useTree must be used within TreeView");return r},"useTree"),Ci=c(r=>he.Children.count(r)>0,"hasChildren");function Si(r){const e=Gn(),{label:t,value:n,isInitiallyExpanded:o}=r,i=jr(),s=lt(e.registerChildItem(t)).current,a=e.isActiveByRef(s),[l,u]=L(o??!1),h={props:r,ref:s,id:i,active:a,expanded:l,setExpanded:u,label:t,value:n,isInitiallyExpanded:o,isParent:!1},{children:m}=r,f=typeof m=="function"?m(h):m;return{...h,props:{...r,children:f},isParent:Ci(f)}}c(Si,"useTreeItem");function Te(r){const e=Gn(),t=Si(r),{expanded:n,isParent:o,props:{children:i},setExpanded:s}=t,{renderValue:a=vi}=r,l=t.ref;Ue(()=>{function f(C){return r.onInput?.(C)?!0:C.active&&C.key.rightArrow&&!n?(s(!0),!0):C.active&&C.key.leftArrow&&n?(s(!1),!0):!1}c(f,"onInput"),l.onInput=f},[l,r.onInput,n,s]),l.firstChild??={parent:l,index:0};let u=l.firstChild;function h(f){const C=u;return C.nextSibling||(C.nextSibling={parent:l,prevSibling:C,index:C.index+1}),u=C.nextSibling,C.label=f,C}c(h,"registerChildItem");function m(){l.lastRenderedChild=u.prevSibling}return c(m,"commitChildren"),Ue(()=>{m()}),v(Ke,{children:[v(y,{marginLeft:e.depth*2,children:[d(y,{width:2,children:o&&d(w,{children:n?"\u25BC":"\u25B6"})}),bi(t),a(t)]}),n&&d(jt.Provider,{value:{...e,depth:e.depth+1,registerChildItem:h},children:i})]})}c(Te,"TreeItem");function bi({active:r,label:e}){return d(y,{width:32,children:d(w,{inverse:r,children:e})})}c(bi,"defaultRenderLabel");function vi(r){return d(w,{})}c(vi,"defaultRenderValue");const ye=c(({label:r,onPress:e,hotkey:t})=>d(Te,{label:r,onInput:c(({input:n,key:o,active:i})=>i&&o.return||t&&t in o&&o[t]||n===t?(e(),!0):!1,"onInput"),renderValue:c(()=>d(y,{children:d(w,{children:`${t?` (${t})`:""}`})}),"renderValue")}),"ActionTreeItem"),Hn=c(({label:r,value:e,onChange:t,disabled:n=!1,mask:o,...i})=>{const[s,a]=L(e),[l,u]=L(!1);return Ue(()=>{l||a(e)},[l,e]),d(Te,{label:r,value:e,onInput:c(({key:h,active:m})=>n?!1:l?(h.escape&&u(!1),h.return&&(t(s),u(!1)),!0):m&&h.return?(u(!0),a(e),!0):!1,"onInput"),renderValue:c(()=>{const h=s,m=o?o.repeat(h.length):h;return d(y,{children:n||!l?d(w,{dimColor:!0,children:m}):v(Ke,{children:[d(y,{width:m.length+1,children:d(dn,{...i,focus:l,value:h,onChange:a})}),d(w,{dimColor:!0,children:" \u241B cancel"})]})})},"renderValue")})},"TreeTextField"),Ti=c(r=>d(Hn,{...r,mask:"*"}),"SecretField"),H=c(({children:r,showHelp:e=!1})=>{const t=lt({parent:void 0,label:"<<ROOT>>",index:0}),[n,o]=L(t.current),i={depth:0,isActiveByRef:c(a=>n===a,"isActiveByRef"),registerChildItem:c(()=>t.current,"registerChildItem"),activeItemRef:n};Ue(()=>{o(a=>a.parent?a.parent.lastRenderedChild&&a.index>a.parent.lastRenderedChild.index?a.parent.lastRenderedChild:a:t.current.firstChild??t.current)});function*s(a){a&&(yield a,yield*s(a.firstChild),a.nextSibling&&a!==a.parent?.lastRenderedChild&&(yield*s(a.nextSibling)))}return c(s,"walkTree"),pe((a,l)=>{if(n.onInput?.({input:a,key:l,active:!0}))return;let u,h;for(const m of s(t.current))if(m.label!=null){if(u===n&&(h=m),m&&m.onInput?.({input:a,key:l,active:m===n}))return;u=m}l.upArrow?o(m=>m.prevSibling?.lastRenderedChild??m.prevSibling??m.parent??t.current):l.downArrow?o(m=>h??m):l.pageUp?o(()=>t.current.firstChild??t.current):l.pageDown?o(()=>t.current.lastRenderedChild??t.current):l.tab?console.debug({label:n.label,nextSibling:n.nextSibling?.label,prevSibling:n.prevSibling?.label,parent:n.parent?.label,firstChild:n.firstChild?.label,lastRenderedChild:n.lastRenderedChild?.label}):l.leftArrow?o(m=>m.parent??t.current):l.rightArrow&&o(m=>m.lastRenderedChild?m.firstChild:m)}),d(jt.Provider,{value:i,children:v(y,{flexDirection:"column",children:[d(Te,{isInitiallyExpanded:!0,label:"rootItem",children:r}),e&&d(y,{marginTop:1,flexDirection:"column",children:d(w,{dimColor:!0,children:"\u2191/\u2193 move \u2022 \u2190 collapse \u2022 \u2192 expand \u2022 Enter/Space select/edit \u2022 Esc exit"})})]})})},"TreeView");H.Item=Te,H.TextField=Hn;function we({label:r,elementType:e,isActionExcluded:t,toggleAction:n,generateCode:o}){const[i,s]=L([]),{fetchElements:a,getSyncedElementsByType:l}=Z();return Se(()=>{c(async()=>{try{await a();const h=l(e);s(h.map(m=>m.data))}catch(h){console.error(String(h))}},"loadElements")()},[e,a,l,s]),d(Te,{label:r,children:i.map(u=>d(Te,{label:u.name,children:e===k.Action&&v(Ke,{children:[t&&n&&d(ye,{label:`Toggle ${t(u)?"":"(excluded)"}`,onPress:c(()=>{n(u)},"onPress")}),o&&d(ye,{label:"Generate code",onPress:c(()=>{o?.(u)},"onPress")})]})},u.id))})}c(we,"WorkspaceElementsTreeItem");function Ei({onComplete:r}){const{config:e,updateConfig:t,fetchElements:n,getSyncedElementsByType:o}=Z(),[i,s]=L(""),a=e,l=c(f=>{s(f),setTimeout(()=>s(""),2e3)},"setFlash"),u=c(async(f,C)=>{try{await t({[f]:C}),l("\u2705 Configuration updated!")}catch{l("\u274C Error updating configuration")}},"updateField"),h=c(async()=>{try{if(e){const f=fe.saveToFile(e);l(f?"\u2705 Configuration saved successfully!":"\u274C Failed to save configuration"),await n();const C=o(k.Action);await kt({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:C.filter(E=>!a?.excludedActionKeys?.includes(E.key)).map(E=>E.data)}}),l("\u2705 Code generated successfully!")}}catch{l("\u274C Error saving configuration")}},"handleSaveConfig"),m=c(async()=>{try{const f=fe.loadConfig();f?(await t(f),l("\u2705 Configuration reloaded successfully!")):l("\u274C No configuration found to reload")}catch{l("\u274C Error reloading configuration")}},"handleReloadConfig");return v(y,{flexDirection:"column",gap:1,children:[d(w,{bold:!0,color:"cyan",children:"\u2699\uFE0F Membrane Configuration Manager"}),d(y,{paddingX:2,children:v(H,{showHelp:!0,children:[v(H.Item,{label:"Configuration",isInitiallyExpanded:!0,children:[v(H.Item,{label:"Project",children:[d(H.TextField,{label:"Workspace Key",value:a?.workspaceKey??"",onChange:c(f=>u("workspaceKey",f),"onChange"),disabled:!0}),d(Ti,{label:"Workspace Secret",value:a?.workspaceSecret??"",onChange:c(f=>u("workspaceSecret",f),"onChange"),disabled:!0}),d(H.TextField,{label:"API URI",value:a?.apiUri??"",onChange:c(f=>u("apiUri",f),"onChange")}),d(H.TextField,{label:"Test Customer ID",value:a?.testCustomerId??"",onChange:c(f=>u("testCustomerId",f),"onChange")})]}),v(H.Item,{label:"Code Generation",isInitiallyExpanded:!0,children:[v(H.Item,{label:"Project Type",isInitiallyExpanded:!0,value:a?.projectType,renderValue:c(({value:f})=>d(w,{children:f==="typescript"?"TypeScript":f==="openapi"?"OpenAPI":"(Not set)"}),"renderValue"),children:[d(ye,{label:"Update to TypeScript",onPress:c(()=>u("projectType","typescript"),"onPress")}),d(ye,{label:"Update to OpenAPI",onPress:c(()=>u("projectType","openapi"),"onPress")})]}),d(H.TextField,{label:"Project dir",value:a?.outputDir??"",onChange:c(f=>u("outputDir",f),"onChange")})]}),v(H.Item,{label:"Workspace Elements",children:[d(we,{label:"Actions",elementType:k.Action,isActionExcluded:c(f=>a?.excludedActionKeys?.includes(f.key)??!1,"isActionExcluded"),toggleAction:c(f=>u("excludedActionKeys",[...a?.excludedActionKeys??[],f.key]),"toggleAction"),generateCode:c(f=>{(async()=>{try{await kt({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:[f]}}),l("\u2705 Code generated successfully!")}catch{l("\u274C Error generating code")}})()},"generateCode")}),d(we,{label:"Flows",elementType:k.Flow}),d(we,{label:"Data Sources",elementType:k.DataSource}),d(we,{label:"Field Mappings",elementType:k.FieldMapping}),d(we,{label:"Packages",elementType:k.Package}),d(we,{label:"App Data Schemas",elementType:k.AppDataSchema}),d(we,{label:"App Event Types",elementType:k.AppEventType})]})]}),d(ye,{label:"Save Configuration",onPress:h,hotkey:"s"}),d(ye,{label:"Reload Configuration",onPress:m,hotkey:"r"}),d(ye,{label:"Exit",onPress:c(()=>r?.(),"onPress"),hotkey:"escape"})]})}),i&&d(y,{paddingX:2,children:d(w,{color:i.includes("\u2705")?"green":"red",children:i})})]})}c(Ei,"ConfigManager");const Vn=at(process.cwd());function Ii({cwd:r,children:e}){return d(Vn.Provider,{value:r,children:e})}c(Ii,"CwdProvider");function ki(){return ct(Vn)}c(ki,"useCwd");function Ft({cwd:r,children:e,membraneCLIService:t}){const n=r||process.cwd();return d(Ii,{cwd:n,children:d(Vr,{value:{fetcher:To()},children:d(wi,{membraneCLIService:t,children:e})})})}c(Ft,"Layout");function xi(r,e){r.command("config").alias("install").description("\u26A0\uFE0F EXPERIMENTAL: Manage local membrane configuration with interactive UI").addHelpText("after",["","Examples:"," membrane config # Open interactive config manager",""].join(`
26
+ `)).action(()=>{ut(he.createElement(Ft,{membraneCLIService:e,children:he.createElement(Ei,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(xi,"setupConfigCommand");function Yn(r,e){return new Promise((t,n)=>{if(e.aborted){n(e.reason);return}const o=setTimeout(t,r);e.addEventListener("abort",()=>{clearTimeout(o),n(e.reason)},{once:!0})})}c(Yn,"sleep");function Zn(r){return r.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}c(Zn,"escapeHtml");const $i="font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0a0a0a;color:#fff";function ce(r,e,t="#888"){const n=/^#[0-9a-fA-F]{3,6}$/.test(t)?t:"#888";return`<!DOCTYPE html><html><body style="${$i}">
27
+ <div style="text-align:center"><h1>${Zn(r)}</h1><p style="color:${n}">${Zn(e)}</p></div>
28
+ </body></html>`}c(ce,"htmlPage");async function Ut(r,e){return r.post("/connection-requests",e)}c(Ut,"createConnectionRequest");function Xn(r){console.info(),b.info("Open this URL in a browser to complete the connection:"),console.info(` ${r.url}`),console.info(),b.info("Then check the status with:"),console.info(` membrane connection-request get ${r.requestId}`),console.info()}c(Xn,"printConnectionRequestResult");const Ai=3e3,Pi=1800*1e3;function Oi(r){r.command("connect").description("Create a connection to a third-party service via browser-based OAuth").option("--integrationId <id>","Integration ID").option("--integrationKey <key>","Integration key").option("--connectorId <id>","Connector ID").option("--connectorVersion <version>","Connector version").option("--connectionId <id>","Existing connection ID (for reconnect)").option("--name <name>","Connection name").option("--allowMultipleConnections","Allow multiple connections").option("--connectorParameters <json>","JSON string of connector parameters").option("--workspaceKey <key>","Workspace key").option("--tenantKey <key>","Tenant key (customer internalId)").option("--non-interactive","Print URL instead of opening browser").addHelpText("after",["","Examples:"," membrane connect --integrationKey hubspot"," membrane connect --integrationKey hubspot --tenantKey my-customer"," membrane connect --connectorId 123 --workspaceKey my-workspace"," membrane connect --connectionId abc --non-interactive",""].join(`
29
+ `)).action(async e=>{try{await Ri(e)}catch(t){q(t)}})}c(Oi,"setupConnectCommand");async function Ri(r){b.header("Creating a connection");let e;if(r.connectorParameters){let h;try{h=JSON.parse(r.connectorParameters)}catch{throw new Error("--connectorParameters must be valid JSON")}if(typeof h!="object"||h===null||Array.isArray(h))throw new Error("--connectorParameters must be a JSON object");e=h}const t=new J({workspaceKey:r.workspaceKey,tenantKey:r.tenantKey}),n=!!(process.stdin.isTTY&&!r.nonInteractive),o={integrationId:r.integrationId,integrationKey:r.integrationKey,connectorId:r.connectorId,connectorVersion:r.connectorVersion,connectionId:r.connectionId,name:r.name,allowMultipleConnections:r.allowMultipleConnections,connectorParameters:e};if(!n){const h=await Ut(t,o);Xn(h),process.exit(0);return}const i=Yr(),{port:s,server:a,waitForCallback:l}=await Ni(i),u=`http://127.0.0.1:${s}/callback?nonce=${i}`;try{const h=await Ut(t,{...o,redirectUri:u}),m=h.url;try{const{default:K}=await import("open");await K(m),b.info("Opening browser to complete connection...")}catch{b.info("Could not open browser automatically.")}console.error(` If the browser doesn't open, visit:
30
+ ${m}
31
+ `);const f=Ce("Waiting for connection to complete...").start(),C=new AbortController,E=l,S=Di(t,h.requestId,C.signal);S.catch(()=>{});const N=await Promise.race([E,S]);if(C.abort(),f.stop(),N.cancelled&&(b.warning("Connection was cancelled."),process.exit(0)),N.error)throw new Error(`Connection failed: ${N.error}`);if(!N.connectionId)throw new Error("Connection completed but no connection ID received");const P=await t.get(`/connections/${N.connectionId}`);b.success("Connection created successfully!"),console.error(),console.error(` Connection ID: ${P.id}`),P.name&&console.error(` Name: ${P.name}`),P.integrationId&&console.error(` Integration ID: ${P.integrationId}`),P.connectorId&&console.error(` Connector ID: ${P.connectorId}`),console.error(),process.exit(0)}finally{a.close()}}c(Ri,"runConnect");function Ni(r){return new Promise(e=>{let t;const n=new Promise(i=>{t=i}),o=pn((i,s)=>{const a=new URL(i.url??"/","http://127.0.0.1");if(a.pathname!=="/callback"){s.writeHead(404),s.end("Not found");return}if(a.searchParams.get("nonce")!==r){s.writeHead(403),s.end("Invalid nonce");return}const l=a.searchParams.get("connectionId"),u=a.searchParams.get("cancelled"),h=a.searchParams.get("error");s.writeHead(200,{"Content-Type":"text/html"}),h?(s.end(ce("Connection failed",h,"#f87171")),t({error:h})):u?(s.end(ce("Connection cancelled","You can close this tab and return to your terminal.")),t({cancelled:!0})):l?(s.end(ce("Connection successful","You can close this tab and return to your terminal.")),t({connectionId:l})):(s.end(ce("Connection failed","Unknown callback state","#f87171")),t({error:"Unknown callback state"}))});o.listen(0,"127.0.0.1",()=>{const i=o.address(),s=typeof i=="object"&&i?i.port:0;if(!s)throw new Error("Failed to bind local callback server");e({port:s,server:o,waitForCallback:n})})})}c(Ni,"startConnectionCallbackServer");async function Di(r,e,t){const n=Date.now()+Pi;for(;Date.now()<n;){t.throwIfAborted(),await Yn(Ai,t),t.throwIfAborted();const o=await r.request(`/connection-requests/${encodeURIComponent(e)}`,{signal:t});if(o.status==="success"&&o.resultConnectionId)return{connectionId:o.resultConnectionId};if(o.status==="cancelled")return{cancelled:!0};if(o.status==="error")return{error:o.resultError?.message??"Connection failed"}}throw new Error("Connection timed out after 30 minutes")}c(Di,"pollConnectionRequest");function Li(r){const e=r.command("connection").description("Manage connections to external apps").option("--workspaceKey <key>","Workspace key").option("--tenantKey <key>","Tenant key (customer internalId)");e.command("list").description("List all connections").option("--json","Output as JSON").action(async t=>{try{const o={...e.opts(),...t},s=await new J(o).get("/connections");if(o.json)process.stdout.write(JSON.stringify(s,null,2)+`
32
+ `);else{const a=s.items??[];if(a.length===0)console.error(p.gray(" No connections found."));else for(const l of a){const u=l.disconnected?p.red("disconnected"):p.green("connected");console.error(` ${p.cyan(l.id)} ${l.name||p.gray("(unnamed)")} ${u}`)}console.error()}}catch(n){q(n)}}),e.command("get <id>").description("Get a connection by ID").option("--json","Output as JSON").action(async(t,n)=>{try{const i={...e.opts(),...n},a=await new J(i).get(`/connections/${encodeURIComponent(t)}`);i.json?process.stdout.write(JSON.stringify(a,null,2)+`
33
+ `):(console.error(),R("ID",a.id),a.name&&R("Name",a.name),a.connectorId&&R("Connector",a.connectorId),a.integrationId&&R("Integration",a.integrationId),R("Status",a.disconnected?p.red("disconnected"):p.green("connected")),console.error())}catch(o){q(o)}})}c(Li,"setupConnectionCommand");function Mi(r){const e=r.command("connection-request").description("Manage connection requests (OAuth authentication flows)").option("--workspaceKey <key>","Workspace key").option("--tenantKey <key>","Tenant key (customer internalId)");e.command("create").description("Create a connection request for user authentication").option("--connectorId <id>","Connector ID").option("--integrationId <id>","Integration ID").option("--integrationKey <key>","Integration key").option("--connectionId <id>","Existing connection ID (for reconnecting)").option("--name <name>","Connection name").option("--json","Output as JSON").action(async t=>{try{const n={...e.opts(),...t},o=new J(n),i={};t.connectorId&&(i.connectorId=t.connectorId),t.integrationId&&(i.integrationId=t.integrationId),t.integrationKey&&(i.integrationKey=t.integrationKey),t.connectionId&&(i.connectionId=t.connectionId),t.name&&(i.name=t.name);const s=await Ut(o,i);n.json?process.stdout.write(JSON.stringify(s,null,2)+`
34
+ `):Xn(s)}catch(n){q(n)}}),e.command("get <requestId>").description("Check the status of a connection request").option("--json","Output as JSON").action(async(t,n)=>{try{const o={...e.opts(),...n},s=await new J(o).get(`/connection-requests/${encodeURIComponent(t)}`);o.json?process.stdout.write(JSON.stringify(s,null,2)+`
35
+ `):(console.error(),R("Request ID",s.requestId,16),R("Status",s.status,16),s.resultConnectionId&&R("Connection ID",s.resultConnectionId,16),s.resultError&&R("Error",typeof s.resultError=="string"?s.resultError:JSON.stringify(s.resultError),16),console.error())}catch(o){q(o)}})}c(Mi,"setupConnectionRequestCommand");function ji({currentPat:r,onSubmit:e}){const[t,n]=L(""),[o,i]=L(!1),[s,a]=L(null),l=ft(`/w/0/${Ir}`);return v(y,{flexDirection:"column",borderStyle:"round",borderTop:!0,width:70,paddingX:1,children:[d(y,{marginTop:-1,marginBottom:1,children:d(w,{bold:!0,children:"\u{1F511} Enter your Personal Access Token"})}),d(w,{children:"Please provide your Personal Access Token. You can find it here:"}),d(y,{marginTop:1,marginBottom:1,children:d(w,{color:"yellow",children:l})}),r&&d(w,{dimColor:!0,children:"Press Enter to keep your current token or type a new one."}),d(dn,{mask:"*",placeholder:`${r?"******":"Enter your token here..."}`,value:t,onChange:n,onSubmit:c(async h=>{a(null),i(!0);try{await e(h),n("")}catch{a("Invalid token. Please try again.")}finally{i(!1)}},"handleSubmit")}),o&&d(y,{marginTop:1,children:v(w,{children:[d(qe,{type:"dots"})," Validating token..."]})}),s&&d(w,{color:"red",children:s})]})}c(ji,"PersonalAccessTokenInput");function Qn({onExit:r,showEscOption:e=!0}){const[t,n]=L(""),{data:o,error:i,isLoading:s}=un("/account"),{updateConfig:a}=Z(),l=o?.workspaces,u=s;if(pe((S,N)=>{N.escape&&r?.()}),u)return v(y,{children:[d(qe,{}),d(w,{children:" Fetching workspaces..."})]});if(i)return v(y,{flexDirection:"column",children:[v(w,{color:"red",children:["Error: ",i.message]}),d(y,{marginTop:1,children:d(w,{color:"grey",children:"Press ESC to go back"})})]});const h=l?.filter(S=>S.name.toLowerCase().includes(t.toLowerCase()))??[],m=h.map(S=>({label:S.name,value:S.id})),f=m.length,C=l?.length??0;async function E(S){const N=h.find(_=>_.id===S);if(!N)return;const{key:P,secret:K}=N;!P||!K||(await a({workspaceKey:P,workspaceSecret:K}),r?.())}return c(E,"handleSelect"),v(y,{flexDirection:"column",borderStyle:"round",borderTop:!0,width:70,paddingX:1,children:[d(y,{marginTop:-1,children:d(w,{bold:!0,children:"\u{1F4C1} Select your workspace"})}),v(y,{marginTop:1,children:[d(w,{children:"Search: "}),d(Xr,{placeholder:"Enter a search query...",onChange:n})]}),C>5&&v(w,{children:["Showing ",f," of ",C," workspaces."]}),d(y,{marginTop:1,children:d(Qr,{options:m,onChange:c(S=>{S&&E(S)},"onChange")})}),e&&d(y,{marginTop:1,children:d(w,{color:"grey",children:"Press ESC to go back"})})]})}c(Qn,"SelectWorkspace");var Ne=(r=>(r[r.Authenticate=0]="Authenticate",r[r.ConnectWorkspace=1]="ConnectWorkspace",r))(Ne||{});const Fi={0:"Authenticate in Membrane",1:"Connect a Membrane Workspace"},Kt=[Ne.Authenticate,Ne.ConnectWorkspace];function er({onComplete:r}){const{config:e}=Z(),[t,n]=L(!1),[o,i]=L(0),s=!!(e?.workspaceKey&&e?.workspaceSecret),a=gn(),l=Kt[o],u=o+1,h=Kt.length,m=Kt.map((E,S)=>{let N="pending";return S<o?N="done":S===o&&(N="current"),{id:E,label:Fi[E],status:N}});async function f(E){const S=a&&E===""?a:E,N=new Ae;try{await N.request("/account",{headers:{Authorization:`Bearer ${S}`}}),mo(S),i(P=>P+1)}catch(P){console.error(P)}}c(f,"handlePatSubmit");function C(){n(!0),r&&r()}return c(C,"handleWorkspaceSelected"),pe((E,S)=>{s&&S.escape&&r&&r()}),t?d(y,{children:d(w,{children:"\u2705 Setup complete. You are ready to go!"})}):v(y,{flexDirection:"column",alignSelf:"flex-start",gap:1,children:[v(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:70,children:[d(y,{marginTop:-1,marginBottom:1,children:v(w,{bold:!0,children:["\u{1F6E0}\uFE0F Setup \u2014"," ",v(w,{color:"cyan",children:["Step ",u," of ",h]}),s&&d(w,{color:"grey",children:" [esc: go back]"})]})}),d(y,{flexDirection:"column",paddingLeft:2,children:m.map(E=>d(Ui,{status:E.status,label:E.label},E.id))})]}),l===Ne.Authenticate&&d(ji,{currentPat:a,onSubmit:f}),l===Ne.ConnectWorkspace&&d(Qn,{onExit:C,showEscOption:!1})]})}c(er,"Setup");function Ui({status:r,label:e}){return v(y,{children:[v(y,{width:2,children:[r==="current"&&d(qe,{type:"dots"}),r==="done"&&d(w,{children:"\u2705"})]}),d(w,{dimColor:r!=="current",children:e})]})}c(Ui,"StepDisplay");function Ki(r,e){r.command("init").description("Run interactive setup for Membrane project").option("--key <key>","Workspace key for non-interactive setup").option("--secret <secret>","Workspace secret for non-interactive setup").addHelpText("after",["","Examples:"," membrane init # Run interactive setup"," membrane init --key KEY --secret SEC # Non-interactive setup with key and secret",""].join(`
36
+ `)).action(t=>{t.key&&t.secret?fe.saveToFile({workspaceKey:t.key,workspaceSecret:t.secret})?(console.error("\u2705 Configuration saved to membrane.config.yml"),process.exit(0)):(console.error("Error writing configuration file"),process.exit(1)):t.key||t.secret?(console.error("Error: Both --key and --secret must be provided for non-interactive mode"),process.exit(1)):ut(he.createElement(Ft,{membraneCLIService:e,children:he.createElement(er,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(Ki,"setupInitCommand");function _i(r){const e=r.command("login").description("Log in to Membrane").option("--apiUri <uri>","API base URI",te).option("--non-interactive","Print the authorization URL instead of opening a browser").option("--tenant","Log in with tenant-scoped tokens (for workspace/tenant-level access)",!1).addHelpText("after",["","Examples:"," membrane login # Interactive browser login"," membrane login --tenant # Interactive browser login with tenant scope"," membrane login start # Non-interactive: get auth URL"," membrane login complete <code> # Non-interactive: complete with code",""].join(`
37
+ `)).action(async t=>{try{if(t.apiUri=t.apiUri.replace(/\/+$/,""),!!!(process.stdin.isTTY&&!t.nonInteractive)){await nr(t);return}b.header("Logging in to Membrane");const o=t.tenant?en:tn,i=await Wi(t.apiUri,o);tr(i,t),b.success("Authentication successful!"),process.exit(0)}catch(n){q(n)}});e.command("start").description("Start non-interactive login (outputs auth URL)").action(async()=>{try{const t=e.opts();await nr(t)}catch(t){q(t)}}),e.command("complete <code>").description("Complete login with an authorization code from the consent page").action(async t=>{try{await Bi(t)}catch(n){q(n)}})}c(_i,"setupLoginCommand");function tr(r,e){go(),yn(r.accessToken,r.refreshToken,r.expiresIn),wn(e.apiUri),Co(e.tenant?"tenant":"platform-user"),r.defaultWorkspaceKey&&Lo({defaultWorkspaceKey:r.defaultWorkspaceKey,defaultTenantKey:r.defaultTenantKey})}c(tr,"storeTokens");async function nr(r){b.header("Starting non-interactive login");const e=r.tenant?en:tn,{consentUrl:t,codeVerifier:n,clientId:o}=await qi(r.apiUri,e);wn(r.apiUri),So({scope:r.tenant?"tenant":"platform-user",codeVerifier:n,clientId:o}),console.info(),b.info("Open this URL in your browser to authorize:"),console.info(` ${t}`),console.info(),b.info("After approving, copy the authorization code and run:"),console.info(" membrane login complete <code>"),console.info(),process.exit(0)}c(nr,"performLoginStart");async function qi(r,e){const t=rr(),n=or(t),o=Me,i=new URLSearchParams({response_type:"code",client_id:o,code_challenge:n,code_challenge_method:"S256",scope:e,show_code:"true"}),s=`${r}/oauth/authorize?${i}`,l=(await fetch(s,{redirect:"manual"})).headers.get("location");if(!l)throw new Error("No redirect from authorization endpoint");return{consentUrl:l,codeVerifier:t,clientId:o}}c(qi,"prepareNonInteractiveLogin");async function Bi(r){const e=me()||te,t=vo();if(!t){b.error("No pending login found. Run `membrane login start` first."),process.exit(1);return}b.header("Completing login");const n=Ce("Exchanging authorization code...").start();try{const o=await fetch(`${e}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:"authorization_code",code:r,client_id:t.clientId,code_verifier:t.codeVerifier})});if(o.ok){const i=await o.json(),s=_t(i);n.stop(),tr(s,{apiUri:e,nonInteractive:!1,tenant:t.scope==="tenant"}),$e(),b.success("Authentication successful!"),process.exit(0);return}n.stop(),$e(),b.error("Invalid authorization code. Make sure you copied the full code from the consent page.")}catch(o){n.stop(),$e();const i=o instanceof Error?o.message:String(o);b.error(`Login failed: ${i}`)}b.info("To start the login flow, run: membrane login start"),process.exit(1)}c(Bi,"performLoginComplete");async function Wi(r,e){const t=rr(),n=or(t),{port:o,waitForCode:i,state:s,server:a}=await Ji(),l=`http://127.0.0.1:${o}/callback`,u=new URLSearchParams({response_type:"code",client_id:Me,redirect_uri:l,code_challenge:n,code_challenge_method:"S256",scope:e,state:s}),h=`${r}/oauth/authorize?${u}`,f=(await fetch(h,{redirect:"manual"})).headers.get("location");if(!f)throw a.close(),new Error("No redirect from authorization endpoint");const C=new URL(f).searchParams.get("authorizationId");if(!C)throw a.close(),new Error("No authorizationId in authorization redirect");try{const{default:_}=await import("open");await _(f),b.info("Opening browser for authentication...")}catch{b.info("Could not open browser automatically.")}console.error(` If the browser doesn't open, visit:
25
38
  ${f}
26
- `);const E=xe("Waiting for authorization...").start(),S=new AbortController,R=i.then(async L=>{E.text="Exchanging authorization code...";const M=await fetch(`${r}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:"authorization_code",code:L,redirect_uri:l,client_id:Ze,code_verifier:t})});if(!M.ok)throw new Error(`Token exchange failed: ${M.status} ${await M.text()}`);return Gn(await M.json())}),O=Di(r,p,t,S.signal);O.catch(()=>{});const U=await Promise.race([R,O]);return S.abort(),a.close(),E.stop(),U}c(ki,"performLogin");function $i(){return an(32).toString("base64url")}c($i,"generateCodeVerifier");function Pi(r){return Br("sha256").update(r).digest("base64url")}c(Pi,"generateCodeChallenge");function Gn(r){if(!r.refresh_token)throw new Error("Server did not return a refresh token");return{accessToken:r.access_token,refreshToken:r.refresh_token,expiresIn:r.expires_in,defaultWorkspaceKey:r.default_workspace_key,defaultTenantKey:r.default_tenant_key}}c(Gn,"parseTokenResponse");function Ai(){const r=an(16).toString("base64url");return new Promise(e=>{let t,n;const o=new Promise((s,a)=>{t=s,n=a}),i=cn((s,a)=>{const l=new URL(s.url??"/","http://127.0.0.1");if(l.pathname!=="/callback"){a.writeHead(404),a.end("Not found");return}if(l.searchParams.get("error")){const p=l.searchParams.get("error_description")??"Authorization was denied";a.writeHead(200,{"Content-Type":"text/html"}),a.end(se("Authorization failed",p,"#f87171")),n(new Error(p));return}const h=l.searchParams.get("code");if(l.searchParams.get("state")!==r){a.writeHead(200,{"Content-Type":"text/html"}),a.end(se("Authorization failed","State mismatch \u2014 possible CSRF attack. Please try again.","#f87171")),n(new Error("State mismatch"));return}if(!h){a.writeHead(200,{"Content-Type":"text/html"}),a.end(se("Authorization failed","No authorization code received.","#f87171")),n(new Error("No authorization code received"));return}a.writeHead(200,{"Content-Type":"text/html"}),a.end(se("Authorization successful","You can close this tab and return to your terminal.")),t(h)});i.listen(0,"127.0.0.1",()=>{const s=i.address(),a=typeof s=="object"&&s?s.port:0;e({port:a,waitForCode:o,state:r,server:i})})})}c(Ai,"startCallbackServer");const Ri=900*1e3,Oi=5;async function Di(r,e,t,n){const o=Date.now()+Ri;let i=Oi;for(;Date.now()<o;){n.throwIfAborted(),await _n(i*1e3,n),n.throwIfAborted();const s=await fetch(`${r}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:"authorization_code",authorization_id:e,client_id:Ze,code_verifier:t})});if(s.ok)return Gn(await s.json());const a=await s.json(),l=a.error??a.message??"";if(l!=="authorization_pending")if(l==="slow_down"){i+=5;continue}else throw l==="expired_token"?new Error("Authorization has expired. Please try again."):new Error(`Token exchange failed: ${s.status} ${l}`)}throw new Error("Authorization has expired. Please try again.")}c(Di,"pollForTokens");function Ni(r){r.command("logout").description("Log out of Membrane and revoke tokens").option("--apiUri <uri>","API base URI").action(async e=>{try{gt()||(T.info("You are not logged in."),process.exit(0));const t=Ce(),n=e.apiUri||Se()||ne;if(t)try{const o=await fetch(`${n}/oauth/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:t})});o.ok||T.debug(`Server revocation returned ${o.status}`)}catch{T.warning("Could not reach server to revoke token. Local tokens cleared, but the session may still be active on the server. You can revoke it from the console.")}lo(),T.success("Logged out successfully."),process.exit(0)}catch(t){t instanceof Error?T.error(t.message):T.error("An unknown error occurred"),process.exit(1)}})}c(Ni,"setupLogoutCommand");const Mi=86400;async function Fi(r,e,t,n){const o={iss:r,isAdmin:!0};return t&&(o.id=t),nt.sign(o,e,{expiresIn:Mi})}c(Fi,"generateMcpAccessToken");async function Li(r,e){return(await Ie.get(`${r}/docs-json`,{headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}})).data}c(Li,"fetchOpenApiSchema");function ae(r,e=!0,t,n=new Set){if(!r)return e?D.string():D.string().optional();if(Object.keys(r).length===0)return e?D.any():D.any().optional();if(r.$ref){const i=r.$ref.replace("#/components/schemas/","");if(n.has(i))return D.any();if(n.add(i),t?.schemas?.[i]){const s=t.schemas[i];return ae(s,e,t,n)}return D.any()}let o;if(r.type==="object"||r.properties){const i={};if(r.properties)for(const[s,a]of Object.entries(r.properties)){const l=r.required?.includes(s)??!1;i[s]=ae(a,l,t,n)}if(Object.keys(i).length>0){if(o=D.object(i),r.additionalProperties)if(typeof r.additionalProperties=="object"){const s=ae(r.additionalProperties,!1,t,n);o=o.catchall(s)}else r.additionalProperties===!0&&(o=o.passthrough())}else if(r.additionalProperties&&typeof r.additionalProperties=="object"){const s=ae(r.additionalProperties,!1,t,n);o=D.record(D.string(),s)}else o=D.record(D.string(),D.any())}else if(r.type==="array"){const i=r.items?ae(r.items,!0,t,n):D.any();o=D.array(i)}else if(r.anyOf)o=D.any();else{switch(r.type){case"integer":o=D.coerce.number().int();break;case"number":o=D.coerce.number();break;case"boolean":o=D.coerce.boolean();break;case"string":default:o=D.string();break}r.format==="uuid"?o=D.string().uuid():r.format==="email"?o=D.string().email():r.format==="date"?o=D.string().regex(/^\d{4}-\d{2}-\d{2}$/):r.format==="date-time"&&(o=D.string().datetime()),r.enum&&(o=D.enum(r.enum)),(r.type==="integer"||r.type==="number")&&(r.minimum!==void 0&&(o=o.min(r.minimum)),r.maximum!==void 0&&(o=o.max(r.maximum))),r.type==="string"&&(r.minLength!==void 0&&(o=o.min(r.minLength)),r.maxLength!==void 0&&(o=o.max(r.maxLength)))}return e?o:o.optional()}c(ae,"convertOpenApiSchemaToZod");function Vn(r){const e=r.match(/\{([^}]+)\}/g);return e?e.map(t=>t.slice(1,-1)):[]}c(Vn,"extractPathParameters");function ji(r,e,t,n,o,i){const s=r.operationId||`${t}_${e.replace(/[^a-zA-Z0-9]/g,"_")}`,a=r.description||r.summary||`${t.toUpperCase()} ${e}`,l={},d={},h={};if(r.parameters){for(const p of r.parameters)if(p.in==="path")d[p.name]=ae(p.schema,!0,o).describe(p.description||`Path parameter: ${p.name}`);else if(p.in==="query"){const C=p.required===!0;h[p.name]=ae(p.schema,C,o).describe(p.description||`Query parameter: ${p.name}`)}}if(Object.keys(d).length>0&&(l.params=D.object(d).describe("Path parameters")),Object.keys(h).length>0&&(l.query=D.object(h).describe("Query parameters")),r.requestBody&&r.requestBody.content){const p=r.requestBody.required===!0;if(r.requestBody.content["application/json"]){const C=r.requestBody.content["application/json"].schema;C?l.body=ae(C,p,o).describe("Request body (JSON)"):l.body=D.any().describe("Request body (JSON)")}else r.requestBody.content["application/octet-stream"]||r.requestBody.content["text/plain"]?l.body=p?D.string().describe("Request body (binary/text)"):D.string().optional().describe("Request body (binary/text)"):l.body=D.any().describe("Request body")}const f=Object.keys(l).length>0?D.object(l):D.object({});return{name:s,description:a,parameters:f,async execute(p){try{const C=Vn(e);if(C.length>0){if(!p.params)throw new Error(`Missing required path parameters: ${C.join(", ")}`);const L=C.filter(M=>!(M in p.params));if(L.length>0)throw new Error(`Missing required path parameters: ${L.join(", ")}`)}let E=`${n}${e}`;if(p.params)for(const[L,M]of Object.entries(p.params)){const ye=`{${L}}`;E.includes(ye)&&(E=E.replace(ye,String(M)))}const S=Vn(E);if(S.length>0)throw new Error(`Unresolved path parameters: ${S.join(", ")}`);const R=new URLSearchParams;if(p.query)for(const[L,M]of Object.entries(p.query))M!=null&&R.append(L,String(M));R.toString()&&(E+=`?${R.toString()}`);const O={method:t.toUpperCase(),headers:{Authorization:`Bearer ${i}`}};p.body&&t.toLowerCase()!=="get"&&(r.requestBody?.content?.["application/json"]?(O.headers["Content-Type"]="application/json",O.data=p.body):r.requestBody?.content?.["application/octet-stream"]?(O.headers["Content-Type"]="application/octet-stream",O.data=p.body):r.requestBody?.content?.["text/plain"]?(O.headers["Content-Type"]="text/plain",O.data=p.body):(O.headers["Content-Type"]="application/json",O.data=p.body));const U=await Ie.request({url:E,...O});return{content:[{type:"text",text:U.data===""?"":JSON.stringify(U.data,null,2)}]}}catch(C){return Ie.isAxiosError(C)?{content:[{type:"text",text:`Error: ${C.response?.data?`HTTP ${C.response.status}: ${C.response.statusText} - ${JSON.stringify(C.response.data)}`:`HTTP ${C.response?.status||"unknown"}: ${C.message}`}`}],isError:!0}:C instanceof Error?{content:[{type:"text",text:`Error: API call failed: ${C.message}`}],isError:!0}:{content:[{type:"text",text:"Error: API call failed with unknown error"}],isError:!0}}}}}c(ji,"createApiTool");function Ui(r,e,t){const n=[];if(!r.paths)return n;const o=r.components||{};for(const[i,s]of Object.entries(r.paths))if(typeof s=="object"&&s!==null){for(const[a,l]of Object.entries(s))if(["get","post","put","delete","patch"].includes(a)&&l&&typeof l=="object"){const d=ji(l,i,a,e,o,t);n.push(d)}}return n}c(Ui,"convertOpenApiToTools");function Ki(r){r.command("mcp").description("Launch MCP server with OpenAPI endpoints as tools (API URI is read from environment variables or membrane.config.yml)").addHelpText("after",["","Examples:"," membrane mcp # Launch MCP server using API URI from env vars or membrane.config.yml",""].join(`
27
- `)).action(async()=>{try{process.env.FASTMCP_SUPPRESS_WARNINGS="true";const e=$e(),t=process.env.MEMBRANE_ACCESS_TOKEN||e?.accessToken,n=process.env.MEMBRANE_WORKSPACE_KEY||e?.workspaceKey,o=process.env.MEMBRANE_WORKSPACE_SECRET||e?.workspaceSecret,i=process.env.MEMBRANE_TEST_CUSTOMER_ID||e?.testCustomerId,s=process.env.MEMBRANE_API_URI||e?.apiUri||Se()||ne;!t&&(!n||!o)&&(e||(console.error("No configuration found. Please set MEMBRANE_ACCESS_TOKEN, or MEMBRANE_WORKSPACE_KEY and MEMBRANE_WORKSPACE_SECRET environment variables, or run `membrane init` first to create a configuration file."),process.exit(1)),console.error("Missing credentials. Please provide MEMBRANE_ACCESS_TOKEN or workspace key/secret in the configuration file, command line, or environment variables."),process.exit(1));const a=t||await Fi(n,o,i),l=await Li(s,a),d=Ui(l,s,a),h=new Hr({name:"Membrane API",instructions:`This MCP server lets you interact with Membrane to configure, run, and troubleshoot integrations.
39
+ `);const E=Ce("Waiting for authorization...").start(),S=new AbortController,N=i.then(async _=>{E.text="Exchanging authorization code...";const j=await fetch(`${r}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:"authorization_code",code:_,redirect_uri:l,client_id:Me,code_verifier:t})});if(!j.ok)throw new Error(`Token exchange failed: ${j.status} ${await j.text()}`);return _t(await j.json())}),P=Hi(r,C,t,S.signal);P.catch(()=>{});const K=await Promise.race([N,P]);return S.abort(),a.close(),E.stop(),K}c(Wi,"performInteractiveLogin");function rr(){return hn(32).toString("base64url")}c(rr,"generateCodeVerifier");function or(r){return Zr("sha256").update(r).digest("base64url")}c(or,"generateCodeChallenge");function _t(r){if(!r.refresh_token)throw new Error("Server did not return a refresh token. The server may be misconfigured.");return{accessToken:r.access_token,refreshToken:r.refresh_token,expiresIn:r.expires_in,defaultWorkspaceKey:r.default_workspace_key,defaultTenantKey:r.default_tenant_key}}c(_t,"parseTokenResponse");function Ji(){const r=hn(16).toString("base64url");return new Promise(e=>{let t,n;const o=new Promise((s,a)=>{t=s,n=a}),i=pn((s,a)=>{const l=new URL(s.url??"/","http://127.0.0.1");if(l.pathname!=="/callback"){a.writeHead(404),a.end("Not found");return}if(l.searchParams.get("error")){const f=l.searchParams.get("error_description")??"Authorization was denied";a.writeHead(200,{"Content-Type":"text/html"}),a.end(ce("Authorization failed",f,"#f87171")),n(new Error(f));return}const h=l.searchParams.get("code");if(l.searchParams.get("state")!==r){a.writeHead(200,{"Content-Type":"text/html"}),a.end(ce("Authorization failed","State mismatch \u2014 possible CSRF attack. Please try again.","#f87171")),n(new Error("State mismatch"));return}if(!h){a.writeHead(200,{"Content-Type":"text/html"}),a.end(ce("Authorization failed","No authorization code received.","#f87171")),n(new Error("No authorization code received"));return}a.writeHead(200,{"Content-Type":"text/html"}),a.end(ce("Authorization successful","You can close this tab and return to your terminal.")),t(h)});i.listen(0,"127.0.0.1",()=>{const s=i.address(),a=typeof s=="object"&&s?s.port:0;if(!a)throw new Error("Failed to bind local callback server");e({port:a,waitForCode:o,state:r,server:i})})})}c(Ji,"startCallbackServer");const zi=900*1e3,Gi=5;async function Hi(r,e,t,n){const o=Date.now()+zi;let i=Gi;for(;Date.now()<o;){n.throwIfAborted(),await Yn(i*1e3,n),n.throwIfAborted();const s=await fetch(`${r}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:"authorization_code",authorization_id:e,client_id:Me,code_verifier:t})});if(s.ok)return _t(await s.json());let a;try{a=await s.json()}catch{throw new Error(`Token request failed with status ${s.status}`)}const l=a.error??a.message??"";if(l!=="authorization_pending")if(l==="slow_down"){i+=5;continue}else throw l==="expired_token"?new Error("Authorization has expired. Please try again."):new Error(`Token exchange failed: ${s.status} ${l}`)}throw new Error("Authorization has expired. Please try again.")}c(Hi,"pollForTokens");function Vi(r){r.command("logout").description("Log out of Membrane and revoke tokens").option("--apiUri <uri>","API base URI").action(async e=>{try{wt()||(b.info("You are not logged in."),process.exit(0));const t=be(),n=e.apiUri||me()||te;if(t)try{const o=await fetch(`${n}/oauth/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:t})});o.ok||b.debug(`Server revocation returned ${o.status}`)}catch{b.warning("Could not reach server to revoke token. Local tokens cleared, but the session may still be active on the server. You can revoke it from the console.")}wo(),b.success("Logged out successfully."),process.exit(0)}catch(t){t instanceof Error?b.error(t.message):b.error("An unknown error occurred"),process.exit(1)}})}c(Vi,"setupLogoutCommand");const Yi=86400;async function Zi(r,e,t,n){const o={iss:r,isAdmin:!0};return t&&(o.id=t),nt.sign(o,e,{expiresIn:Yi})}c(Zi,"generateMcpAccessToken");async function Xi(r,e){return(await Ie.get(`${r}/docs-json`,{headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}})).data}c(Xi,"fetchOpenApiSchema");function le(r,e=!0,t,n=new Set){if(!r)return e?D.string():D.string().optional();if(Object.keys(r).length===0)return e?D.any():D.any().optional();if(r.$ref){const i=r.$ref.replace("#/components/schemas/","");if(n.has(i))return D.any();if(n.add(i),t?.schemas?.[i]){const s=t.schemas[i];return le(s,e,t,n)}return D.any()}let o;if(r.type==="object"||r.properties){const i={};if(r.properties)for(const[s,a]of Object.entries(r.properties)){const l=r.required?.includes(s)??!1;i[s]=le(a,l,t,n)}if(Object.keys(i).length>0){if(o=D.object(i),r.additionalProperties)if(typeof r.additionalProperties=="object"){const s=le(r.additionalProperties,!1,t,n);o=o.catchall(s)}else r.additionalProperties===!0&&(o=o.passthrough())}else if(r.additionalProperties&&typeof r.additionalProperties=="object"){const s=le(r.additionalProperties,!1,t,n);o=D.record(D.string(),s)}else o=D.record(D.string(),D.any())}else if(r.type==="array"){const i=r.items?le(r.items,!0,t,n):D.any();o=D.array(i)}else if(r.anyOf)o=D.any();else{switch(r.type){case"integer":o=D.coerce.number().int();break;case"number":o=D.coerce.number();break;case"boolean":o=D.coerce.boolean();break;case"string":default:o=D.string();break}r.format==="uuid"?o=D.string().uuid():r.format==="email"?o=D.string().email():r.format==="date"?o=D.string().regex(/^\d{4}-\d{2}-\d{2}$/):r.format==="date-time"&&(o=D.string().datetime()),r.enum&&(o=D.enum(r.enum)),(r.type==="integer"||r.type==="number")&&(r.minimum!==void 0&&(o=o.min(r.minimum)),r.maximum!==void 0&&(o=o.max(r.maximum))),r.type==="string"&&(r.minLength!==void 0&&(o=o.min(r.minLength)),r.maxLength!==void 0&&(o=o.max(r.maxLength)))}return e?o:o.optional()}c(le,"convertOpenApiSchemaToZod");function ir(r){const e=r.match(/\{([^}]+)\}/g);return e?e.map(t=>t.slice(1,-1)):[]}c(ir,"extractPathParameters");function Qi(r,e,t,n,o,i){const s=r.operationId||`${t}_${e.replace(/[^a-zA-Z0-9]/g,"_")}`,a=r.description||r.summary||`${t.toUpperCase()} ${e}`,l={},u={},h={};if(r.parameters){for(const f of r.parameters)if(f.in==="path")u[f.name]=le(f.schema,!0,o).describe(f.description||`Path parameter: ${f.name}`);else if(f.in==="query"){const C=f.required===!0;h[f.name]=le(f.schema,C,o).describe(f.description||`Query parameter: ${f.name}`)}}if(Object.keys(u).length>0&&(l.params=D.object(u).describe("Path parameters")),Object.keys(h).length>0&&(l.query=D.object(h).describe("Query parameters")),r.requestBody&&r.requestBody.content){const f=r.requestBody.required===!0;if(r.requestBody.content["application/json"]){const C=r.requestBody.content["application/json"].schema;C?l.body=le(C,f,o).describe("Request body (JSON)"):l.body=D.any().describe("Request body (JSON)")}else r.requestBody.content["application/octet-stream"]||r.requestBody.content["text/plain"]?l.body=f?D.string().describe("Request body (binary/text)"):D.string().optional().describe("Request body (binary/text)"):l.body=D.any().describe("Request body")}const m=Object.keys(l).length>0?D.object(l):D.object({});return{name:s,description:a,parameters:m,async execute(f){try{const C=ir(e);if(C.length>0){if(!f.params)throw new Error(`Missing required path parameters: ${C.join(", ")}`);const _=C.filter(j=>!(j in f.params));if(_.length>0)throw new Error(`Missing required path parameters: ${_.join(", ")}`)}let E=`${n}${e}`;if(f.params)for(const[_,j]of Object.entries(f.params)){const Le=`{${_}}`;E.includes(Le)&&(E=E.replace(Le,String(j)))}const S=ir(E);if(S.length>0)throw new Error(`Unresolved path parameters: ${S.join(", ")}`);const N=new URLSearchParams;if(f.query)for(const[_,j]of Object.entries(f.query))j!=null&&N.append(_,String(j));N.toString()&&(E+=`?${N.toString()}`);const P={method:t.toUpperCase(),headers:{Authorization:`Bearer ${i}`}};f.body&&t.toLowerCase()!=="get"&&(r.requestBody?.content?.["application/json"]?(P.headers["Content-Type"]="application/json",P.data=f.body):r.requestBody?.content?.["application/octet-stream"]?(P.headers["Content-Type"]="application/octet-stream",P.data=f.body):r.requestBody?.content?.["text/plain"]?(P.headers["Content-Type"]="text/plain",P.data=f.body):(P.headers["Content-Type"]="application/json",P.data=f.body));const K=await Ie.request({url:E,...P});return{content:[{type:"text",text:K.data===""?"":JSON.stringify(K.data,null,2)}]}}catch(C){return Ie.isAxiosError(C)?{content:[{type:"text",text:`Error: ${C.response?.data?`HTTP ${C.response.status}: ${C.response.statusText} - ${JSON.stringify(C.response.data)}`:`HTTP ${C.response?.status||"unknown"}: ${C.message}`}`}],isError:!0}:C instanceof Error?{content:[{type:"text",text:`Error: API call failed: ${C.message}`}],isError:!0}:{content:[{type:"text",text:"Error: API call failed with unknown error"}],isError:!0}}}}}c(Qi,"createApiTool");function es(r,e,t){const n=[];if(!r.paths)return n;const o=r.components||{};for(const[i,s]of Object.entries(r.paths))if(typeof s=="object"&&s!==null){for(const[a,l]of Object.entries(s))if(["get","post","put","delete","patch"].includes(a)&&l&&typeof l=="object"){const u=Qi(l,i,a,e,o,t);n.push(u)}}return n}c(es,"convertOpenApiToTools");function ts(r){r.command("mcp").description("Launch MCP server with OpenAPI endpoints as tools (API URI is read from environment variables or membrane.config.yml)").addHelpText("after",["","Examples:"," membrane mcp # Launch MCP server using API URI from env vars or membrane.config.yml",""].join(`
40
+ `)).action(async()=>{try{process.env.FASTMCP_SUPPRESS_WARNINGS="true";const e=xe(),t=process.env.MEMBRANE_ACCESS_TOKEN||e?.accessToken,n=process.env.MEMBRANE_WORKSPACE_KEY||e?.workspaceKey,o=process.env.MEMBRANE_WORKSPACE_SECRET||e?.workspaceSecret,i=process.env.MEMBRANE_TEST_CUSTOMER_ID||e?.testCustomerId,s=process.env.MEMBRANE_API_URI||e?.apiUri||me()||te;!t&&(!n||!o)&&(e||(console.error("No configuration found. Please set MEMBRANE_ACCESS_TOKEN, or MEMBRANE_WORKSPACE_KEY and MEMBRANE_WORKSPACE_SECRET environment variables, or run `membrane init` first to create a configuration file."),process.exit(1)),console.error("Missing credentials. Please provide MEMBRANE_ACCESS_TOKEN or workspace key/secret in the configuration file, command line, or environment variables."),process.exit(1));const a=t||await Zi(n,o,i),l=await Xi(s,a),u=es(l,s,a),h=new to({name:"Membrane API",instructions:`This MCP server lets you interact with Membrane to configure, run, and troubleshoot integrations.
28
41
  Use it for anything related to Membrane or integrations.
29
- `,version:"1.0.0"});for(const C of d){const E=C.execute;C.execute=async S=>(ti(process.pid,process.cwd()),E(S)),h.addTool(C)}Rt({isRunning:!0,startTime:new Date().toISOString(),toolsCount:d.length,lastActivity:new Date().toISOString(),processId:process.pid,cwd:process.cwd(),agentName:process.env.AGENT_NAME||"Unnamed Agent"});const f=setInterval(()=>{Rt({processId:process.pid,cwd:process.cwd(),lastActivity:new Date().toISOString()})},5e3),p=c(async()=>{clearInterval(f),Re(process.pid,process.cwd());try{await h.stop()}catch{}},"cleanup");await h.start({transportType:"stdio"}),process.on("SIGINT",async()=>{await p(),process.exit(0)}),process.on("SIGTERM",async()=>{await p(),process.exit(0)}),process.on("exit",()=>{Re(process.pid,process.cwd())}),process.on("uncaughtException",async C=>{console.error("Uncaught exception:",C.message),await p(),process.exit(1)}),process.on("unhandledRejection",async C=>{console.error("Unhandled rejection:",C),await p(),process.exit(1)})}catch(e){e instanceof Error&&(console.error(e.message),process.exit(1)),console.error("An unknown error occurred"),process.exit(1)}})}c(Ki,"setupMcpCommand");function _i(r){r.command("open").description("Open the workspace in the browser").addHelpText("after",["","Examples:"," membrane open # Open workspace in browser",""].join(`
30
- `)).action(async()=>{try{T.header("Opening Workspace in Browser"),T.info("Loading configuration...");const e=$e();if(!e)throw new Error("No configuration found. Please set MEMBRANE_WORKSPACE_KEY and MEMBRANE_WORKSPACE_SECRET environment variables, or run `membrane init` first.");if(!e.workspaceKey||!e.workspaceSecret)throw new Error("Missing workspace credentials");T.info("Retrieving workspace ID...");const t=await mn(process.cwd()),n=pt(`/w/${t}`);T.info(`Opening ${n}...`);const{default:o}=await import("open");await o(n),T.success("Browser opened successfully")}catch(e){e instanceof Error&&(T.error(e.message),process.exit(1)),T.error("An unknown error occurred"),process.exit(1)}})}c(_i,"setupOpenCommand");const Yn=5;function qi(r){r.command("pull").description("Pull workspace data from specified workspace").option("--force","Overwrite conflicts with remote data",!1).addHelpText("after",["","Examples:"," membrane pull # Pull from default workspace"," membrane pull --force # Overwrite conflicts with remote data",""].join(`
31
- `)).action(async e=>{const t=xe({text:"Pulling workspace",color:"white"}).start();try{const n=await Bi(e,t);t.stop(),Gi(n.workspaceExport,n.connectors)}catch(n){t.stop(),Yi(n),process.exit(1)}})}c(qi,"setupPullCommand");async function Bi(r,e){const t=await Ct(),n=await En(t),o=await wn(),i=await Tn(o),{comparison:s}=Yt(t,i);s[X.DELETE].size>0&&!r.force&&(await Vi(s,n),T.error("Use --force to delete local elements"),process.exit(1));const l=await xn(q(process.cwd()));for(const{filePath:f,data:p}of l)s[X.DELETE].has(p.uuid)&&go(f);return vn(q(process.cwd())),await wt(o,(f,p)=>{if(ue(f)&&(s[X.CREATE].has(p.uuid)||s[X.UPDATE].has(p.uuid))){const E=k.join(q(process.cwd()),f);bn(E,p)}}),{connectors:await $.isVersionAtLeast("1.8")?await Wi(o,e):await zi(i[I.Integration],e),workspaceExport:i}}c(Bi,"pullWorkspace");async function Wi(r,e){e.text="Extracting connectors",yt(k.join(q(process.cwd()),"connectors"));const t=new Set,n=await je.Open.buffer(r);for(const o of n.files){if(!o.path.startsWith("connectors/")||o.type==="Directory")continue;const i=k.join(q(process.cwd()),o.path);Pe(k.dirname(i));const s=await o.buffer();if(Sn(i,s),t.add(o.path.split("/")[1]),o.path.endsWith("/development/src.zip")){const a=k.join(k.dirname(i),"src");Pe(a),await(await je.Open.buffer(s)).extract({path:a})}}return Array.from(t)}c(Wi,"extractConnectorsFromExport");async function Ji(r,e,t){if(Sn(k.join(Ae(r,e),"src.zip"),t),!e||e===Ve){const n=k.join(Ae(r,e),"src");Pe(n),await(await je.Open.buffer(t)).extract({path:n})}}c(Ji,"writeConnectorVersion");async function zi(r,e){e.text="Pulling connectors";const t=new Map,{id:n}=await $.withClient(l=>l.get("org-workspace-id")),{items:o=[]}=await $.withClient(l=>l.get(`/connectors?workspaceId=${n}`));for(const l of o){const d=l.uuid??l.id;!l.isPublic&&d&&t.set(d,new Set([""]))}for(const l of r??[]){const{connectorUuid:d,connectorVersion:h}=l;d&&(t.has(d)||t.set(d,new Set),t.get(d).add(h??""))}const i=kn();for(const[l,{key:d,versions:h}]of Object.entries(i)){if(!t.has(l)){const p=Ae(d);yt(p);continue}const f=t.get(l);for(const p of h)if(!f.has(p)){const C=Ae(d,p);yt(C)}}const s=Array.from(t.entries()),a=c((l,d)=>{l==="pulling"?e.start(`Pulling connector ${d}...`):e.succeed(`Pulled connector ${d}`)},"onProgress");for(let l=0;l<s.length;l+=Yn){const d=s.slice(l,l+Yn);await Promise.all(d.map(([h,f])=>Hi(h,Array.from(f),a)))}return Array.from(t.keys())}c(zi,"pullConnectorsLegacy");async function Hi(r,e,t){const n=await $.withClient(d=>d.get(`connectors/${r}/export-json`),!1),o=await $.withClient(d=>d.get(`connectors/${r}`),!1);if(!n||!o||!n.key||!o.key)return;const i=o.name||n.key;t?.("pulling",i);const s={...n,id:o.id,uuid:o.uuid},a=Ae(n.key),l=k.join(a,`${n.key}.yml`);bn(l,s);for(const d of e){const h=await mo(r,d);await Ji(n.key,d,h)}t?.("pulled",i)}c(Hi,"pullConnector");function Gi(r,e=[]){const t=Object.values(r).reduce((n,o)=>n+(o?.length??0),0)+e.length;T.info(`\u25CF Pulled workspace elements \xB7 ${t}`);for(const n of Object.keys(r).sort()){const o=r[n];T.info(`\u2514\u2500\u2500 ${n}s \xB7 ${o?.length??0}`)}e.length>0&&T.info(`\u2514\u2500\u2500 connectors \xB7 ${e.length}`)}c(Gi,"showStats$1");async function Vi(r,e){const t=r[X.DELETE].size;T.info(`\u2299 Pull: conflicts detected \xB7 ${t}`),await wt(e,(n,o)=>{ue(n)&&r[X.DELETE].has(o.uuid)&&T.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted in remote)`)})}c(Vi,"showConflicts$1");async function Yi(r){T.error("\u25A0 Error"),T.error(`\u2514\u2500\u2500 ${r.message}`),T.error(` ${r.stack}`)}c(Yi,"showError$1");const _=[];for(let r=0;r<256;++r)_.push((r+256).toString(16).slice(1));function Zi(r,e=0){return(_[r[e+0]]+_[r[e+1]]+_[r[e+2]]+_[r[e+3]]+"-"+_[r[e+4]]+_[r[e+5]]+"-"+_[r[e+6]]+_[r[e+7]]+"-"+_[r[e+8]]+_[r[e+9]]+"-"+_[r[e+10]]+_[r[e+11]]+_[r[e+12]]+_[r[e+13]]+_[r[e+14]]+_[r[e+15]]).toLowerCase()}c(Zi,"unsafeStringify");let Ut;const Xi=new Uint8Array(16);function Qi(){if(!Ut){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");Ut=crypto.getRandomValues.bind(crypto)}return Ut(Xi)}c(Qi,"rng");const es=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto);var Zn={randomUUID:es};function ts(r,e,t){if(Zn.randomUUID&&!r)return Zn.randomUUID();r=r||{};const n=r.random??r.rng?.()??Qi();if(n.length<16)throw new Error("Random bytes length must be >= 16");return n[6]=n[6]&15|64,n[8]=n[8]&63|128,Zi(n)}c(ts,"v4");function ns(r){r.command("push").description("Push workspace data to specified workspace").argument("[files...]","Files, directories, or glob patterns to push").option("--force","Overwrite conflicts with local data",!1).addHelpText("after",["","Examples:"," membrane push # Push all workspace elements"," membrane push data-sources/ # Push all data-sources"," membrane push actions/my-action/spec.yaml # Push specific action"," membrane push flows/*-test/spec.yaml # Push flows matching pattern"," membrane push --force # Overwrite conflicts with local data",""].join(`
32
- `)).action(async(e,t)=>{const n=xe({text:"Pushing workspace",color:"white"}).start();try{await rs(e,t,n)}catch(o){n.stop(),hs(o),process.exit(1)}})}c(ns,"setupPushCommand");async function rs(r,e,t){const n=r.length>0,o=await Ct(),i=kn(),s=ss(o,i),a=await $.isVersionAtLeast("1.9"),l=await En(s,n?r:void 0,a?i:void 0);e.force||(t.text="Comparing workspace",await os(l,n)&&(t.stop(),process.exit(1)));const d=a?Object.keys(i):await is(t);t.start("Pushing workspace..."),await Cn(l,{partial:n}),t.stop(),us(s,d),process.exit(0)}c(rs,"pushWorkspace");async function os(r,e){const t=await Cn(r,{dryRun:!0,partial:e}),n=t[X.DELETE].size>0;return n&&(await ds(t,r),T.error("Use --force to delete remote elements")),n}c(os,"checkForConflicts");async function is(r){return(await Rn({onProgress:c((t,n)=>{t==="pushing"?r.start(`Pushing connector ${n}...`):r.succeed(`Pushed connector ${n}`)},"onProgress")})).pushedConnectors??[]}c(is,"pushConnectorsLegacy");function ss(r,e){const t=cs(r),n=ls(t,e),o={};for(const[i,s]of Object.entries(t)){const a=i;o[a]=(s||[]).map(l=>as(l,a,n))}return o}c(ss,"resolveLegacyIdReferences");function as(r,e,t){const n={...r},o=Z[e]?.parentFieldKey||"parentId";if(n.integrationId&&!n.integrationUuid&&(n.integrationUuid=t.get(n.integrationId.toString())||n.integrationId,delete n.integrationId),n.connectorId){if(!n.connectorUuid){const i=t.get(n.connectorId.toString());i&&(n.connectorUuid=i)}delete n.connectorId}if(n[o]){const i=t.get(n[o].toString());i&&(n.parentUuid=i)}return e===I.Package&&n.elements&&(n.elements=n.elements.map(i=>{if(i.id&&!i.uuid){const s=t.get(i.id.toString());if(s)return{uuid:s,type:i.type}}return i})),delete n.id,n}c(as,"resolveElementIds");function cs(r){const e={};for(const[t,n]of Object.entries(r))e[t]=(n||[]).map(o=>o.uuid?o:{...o,uuid:ts()});return e}c(cs,"generateMissingUuids");function ls(r,e){const t=new Map;for(const n of Object.values(r))for(const o of n||[])o.id&&o.uuid&&t.set(o.id.toString(),o.uuid);for(const[n,o]of Object.entries(e))o.id&&t.set(o.id.toString(),n);return t}c(ls,"buildIdToUuidLookup");function us(r,e=[]){const t=Object.values(r).reduce((n,o)=>n+(o?.length??0),0)+e.length;T.info(`\u25CF Pushed workspace elements \xB7 ${t}`);for(const n of Object.keys(r).sort()){const o=r[n];T.info(`\u2514\u2500\u2500 ${n}s \xB7 ${o?.length??0}`)}e.length>0&&T.info(`\u2514\u2500\u2500 connectors \xB7 ${e.length}`)}c(us,"showStats");async function ds(r,e){const t=r[X.DELETE].size;T.info(`\u2299 Push: conflicts detected \xB7 ${t}`),await wt(e,(n,o)=>{ue(n)&&r[X.DELETE].has(o.uuid)&&T.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted locally)`)})}c(ds,"showConflicts");function hs(r){T.error("\u25A0 Error"),T.error(`\u2514\u2500\u2500 ${r.message}`),T.error(` ${r.stack}`)}c(hs,"showError");function ps(r){r.command("status").description("Show current login status, project settings, and resolved environment").action(async()=>{try{await fs()}catch(e){Ft(e)}})}c(ps,"setupStatusCommand");async function fs(){const r=Se()||ne,e=Jn(),t=gt();if(console.error(),console.error(m.bold.cyan("\u25B6 Membrane CLI Status")),console.error(),V("API",r),!t)V("Auth",m.red("Not logged in"));else{const n=mt(),o=!!Ce();if(n&&!o)V("Auth",m.yellow("Token expired (no refresh token)"));else try{const s=await new qe().get("/account?workspaceId=0");if(s.user?(V("Auth",m.green("Logged in")),V("User",`${s.user.name} (${s.user.email})`)):V("Auth",m.green("Logged in")),s.orgs?.length){const a=s.orgs.map(l=>l.name).join(", ");V("Orgs",a)}}catch{V("Auth",m.yellow("Logged in (could not fetch account details)"))}}e.defaultWorkspaceKey&&V("Workspace",`${e.defaultWorkspaceKey} ${m.gray("(default)")}`),e.defaultTenantKey&&V("Tenant",`${e.defaultTenantKey} ${m.gray("(default)")}`),!e.defaultWorkspaceKey&&!e.defaultTenantKey&&V("Project",m.gray("No project defaults configured")),console.error()}c(fs,"runStatus");function V(r,e){console.error(` ${m.gray(r.padEnd(12))} ${e}`)}c(V,"printField");const Kt=[{id:"claude-code",name:"Claude Code",description:"Anthropic Claude Code agent",actionDescription:"Adding membrane MCP to .mcp.json in the current directory",addConfig:c(()=>{const r=x.join(process.cwd(),".mcp.json"),e={mcpServers:{membrane:{command:"membrane",args:["mcp"],env:{AGENT_NAME:"Claude Code"}}}};let t={};if(v.existsSync(r))try{t=JSON.parse(v.readFileSync(r,"utf8"))}catch{t={}}const n={...t,mcpServers:{...t.mcpServers,...e.mcpServers}};return v.writeFileSync(r,JSON.stringify(n,null,2)),`MCP server configuration added to ${r}`},"addConfig")},{id:"cursor",name:"Cursor",description:"Cursor AI editor",actionDescription:"Adding membrane MCP to .cursor/mcp.json in the current directory",addConfig:c(()=>{const r=x.join(process.cwd(),".cursor"),e=x.join(r,"mcp.json");v.existsSync(r)||v.mkdirSync(r);const t={mcpServers:{membrane:{command:"membrane",args:["mcp"],env:{AGENT_NAME:"Cursor"}}}};let n={};if(v.existsSync(e))try{n=JSON.parse(v.readFileSync(e,"utf8"))}catch{n={}}const o={...n,mcpServers:{...n.mcpServers,...t.mcpServers}};return v.writeFileSync(e,JSON.stringify(o,null,2)),`MCP server configuration added to ${e}`},"addConfig")}];function ms({onExit:r,onComplete:e}){const[t,n]=N(0),[o,i]=N(!1),[s,a]=N(null),[l,d]=N(""),[h,f]=N("");he((E,S)=>{if(l||h){(S.escape||E==="q"||S.return)&&e();return}if(o)S.return||E===" "?p(s):S.escape&&(i(!1),a(null));else if(S.escape)r();else if(S.upArrow||E==="k")n(Math.max(0,t-1));else if(S.downArrow||E==="j")n(Math.min(Kt.length-1,t+1));else if(S.return||E===" "){const R=Kt[t];a(R),i(!0)}});const p=c(E=>{try{const S=E.addConfig();d(S)}catch(S){f(`Failed to write configuration: ${S.message||S}`)}},"addMcpConfiguration"),C=Math.min(80,process.stdout.columns||80);return l?b(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:C,children:[u(y,{marginTop:-1,marginBottom:1,children:b(w,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",u(w,{color:"green",children:"Success"})]})}),b(y,{flexDirection:"column",paddingLeft:2,children:[u(w,{color:"green",children:l}),u(y,{marginTop:1,children:u(w,{color:"grey",children:"The agent will now be able to use Membrane's integration capabilities."})})]}),u(y,{marginTop:1,paddingLeft:2,children:u(w,{color:"white",children:"[esc/q/enter: exit]"})})]}):h?b(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:C,children:[u(y,{marginTop:-1,marginBottom:1,children:b(w,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",u(w,{color:"red",children:"Error"})]})}),u(y,{flexDirection:"column",paddingLeft:2,children:u(w,{color:"red",children:h})}),u(y,{marginTop:1,children:u(w,{color:"grey",children:"[esc/q/enter: exit]"})})]}):o&&s?b(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:C,children:[u(y,{marginTop:-1,marginBottom:1,children:b(w,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",u(w,{color:"cyan",children:"Confirmation"})]})}),b(y,{flexDirection:"column",paddingLeft:2,children:[b(w,{children:["Connect ",u(w,{bold:!0,children:s.name})," to Membrane via MCP?"]}),u(y,{marginTop:1,children:u(w,{color:"grey",children:"This will add an MCP server configuration that allows the agent to use Membrane's integration capabilities."})}),u(y,{marginTop:1,children:u(w,{color:"yellow",bold:!0,children:s.actionDescription})}),u(y,{marginTop:2,marginBottom:1,children:b(w,{children:[u(w,{color:"white",bold:!0,children:"[Enter] Confirm"})," ",u(w,{color:"gray",children:"[Esc] Cancel"})]})})]})]}):b(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:C,children:[u(y,{marginTop:-1,marginBottom:1,children:b(w,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",u(w,{color:"cyan",children:"Select Agent"})]})}),b(y,{flexDirection:"column",paddingLeft:2,children:[u(w,{color:"grey",children:"Choose an agent to connect to Membrane via MCP:"}),u(y,{marginTop:1,children:u(w,{color:"grey",children:"This will add an MCP server configuration that allows the agent to use Membrane's integration capabilities."})}),u(y,{marginTop:1,flexDirection:"column",children:Kt.map((E,S)=>b(y,{children:[b(w,{color:t===S?"cyan":"white",children:[t===S?"\u25B6 ":" ",E.name]}),b(w,{color:"grey",children:[" \u2014 ",E.description]})]},E.id))})]}),u(y,{marginTop:1,children:u(w,{color:"grey",children:"[\u2191\u2193: select] [enter: choose] [esc: exit]"})})]})}c(ms,"AddMcpServerScreen");function gs(){const[r,e]=N(null),[t,n]=N([]),[o,i]=N(null);return we(()=>{const s=c(({status:l})=>{e(l),i(null)},"handleMcpStatusChanged"),a=c(({servers:l})=>{n(l),i(null)},"handleMcpServersChanged");return oe.on(j.McpStatusChanged,s),oe.on(j.McpServersChanged,a),()=>{oe.off(j.McpStatusChanged,s),oe.off(j.McpServersChanged,a)}},[]),{mcpStatus:r,allMcpServers:t,error:o,isRunning:r?.isRunning||!1,toolsCount:r?.toolsCount||0,totalRequests:r?.totalRequests||0,lastActivity:r?.lastActivity,processId:r?.processId,serverCount:t.length}}c(gs,"useMcpStatus");function ys(){const{error:r,serverCount:e,allMcpServers:t}=gs(),n=Math.min(100,process.stdout.columns||100);return b(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:n,children:[u(y,{marginTop:-1,marginBottom:0,flexDirection:"column",children:b(w,{bold:!0,children:["\u{1F916} Connected AI Agents:"," ",r?u(w,{color:"red",children:"error reading status"}):e===0?u(w,{color:"yellow",children:"none"}):u(w,{color:"green",children:e})]})}),!r&&e===0&&u(y,{marginTop:1,children:b(w,{color:"grey",children:["Connect your AI agents to Membrane.",u(Rr,{}),"It will give them tools and context to build integrations."]})}),t.length>0&&u(y,{flexDirection:"column",paddingLeft:2,marginTop:1,children:t.map((o,i)=>u(y,{children:b(w,{color:"grey",children:["#",i+1," ",o.agentName,": ",o.totalRequests," calls"]})},o.processId))}),u(y,{marginTop:1,children:u(w,{color:"grey",children:"[a: connect an agent]"})})]})}c(ys,"Agent");const Xn=c(r=>{switch(r){case"error":return"red";case"success":return"green";case"warning":return"yellow";default:return}},"getLogColor");function Qn(r,e){return e<3?r.slice(0,Math.max(0,e)):r.length<=e?r:`${r.slice(0,e-3)}...`}c(Qn,"truncateText");function ws({children:r}){const{state:e,logs:t}=G();return!e||e===P.NOT_INITIALIZED?b(y,{gap:1,flexDirection:"row",children:[u(zr,{type:"dots"}),u(w,{children:"Initializing..."})]}):e===P.SETTING_UP?u(y,{gap:1,flexDirection:"row",children:u(w,{children:"No workspace selected. Please run `membrane init` to select a workspace."})}):e===P.ERROR?u(y,{flexDirection:"column",children:t.slice().map((n,o)=>u(w,{color:Xn(n.type),children:n.message},n.timestamp+o))}):r}c(ws,"EnsureInitialized");function Cs(){const{stats:r}=G(),e=Object.entries(r).filter(([t,n])=>n>0);return e.length===0?null:b(y,{flexDirection:"column",children:[u(y,{children:u(y,{width:12,children:u(w,{color:"grey",children:"Elements:"})})}),u(y,{flexDirection:"column",marginLeft:1,children:e.map(([t,n])=>b(y,{children:[u(y,{width:20,children:b(w,{children:[t,":"]})}),u(w,{color:"green",children:n})]},t))})]})}c(Cs,"ElementStats");const _t=5,Ss=6;function bs(){const{logs:r}=G(),[e,t]=N(0),n=Math.min(100,process.stdout.columns||100),o=_t,i=Math.max(0,r.length-o-e),s=r.length-e,a=r.slice(i,s),l=n-Ss,d=e<r.length-o,h=e>0;return he((f,p)=>{if(r.length!==0)if(p.upArrow){const C=Math.max(0,r.length-o);t(E=>Math.min(C,E+1))}else p.downArrow?t(C=>Math.max(0,C-1)):(f==="G"||f==="g")&&t(0)}),b(y,{flexDirection:"column",paddingTop:1,children:[b(w,{color:"grey",children:["Recent Activity (",i+1,"-",s," of ",r.length,"):",r.length>_t&&u(w,{color:"grey",children:" [arrows: scroll] [g: end]"})]}),a.map((f,p)=>u(y,{marginLeft:1,children:u(w,{color:Xn(f.type),children:Qn(f.message,l)})},f.timestamp+p)),r.length>_t&&b(y,{marginLeft:1,flexDirection:"row",children:[d&&u(w,{color:"grey",children:"\u2191 "}),h&&u(w,{color:"grey",children:"\u2193 "})]})]})}c(bs,"Logs");const ze=[{value:"sync",label:"Continue (overwrite/delete)",key:""},{value:"exit",label:"Cancel",key:""}];function vs(){const{state:r,resolveConflicts:e,exit:t}=G(),[n,o]=N(0),[i,s]=N(!1),[a,l]=N(!1);return he((d,h)=>{if(!i){if(h.ctrl&&d.toLowerCase()==="r"){l(!a);return}h.upArrow?o(f=>f>0?f-1:ze.length-1):h.downArrow?o(f=>f<ze.length-1?f+1:0):d.toLowerCase()==="y"?o(0):d.toLowerCase()==="n"?o(1):(h.return||d===" ")&&(s(!0),ze[n].value==="sync"?e({watch:!0}):t())}}),we(()=>{r!==P.CONFLICTS&&i&&s(!1)},[r,i]),b(y,{flexDirection:"column",paddingTop:1,children:[u(y,{children:u(y,{flexDirection:"row",gap:2,children:u(w,{bold:!0,color:"white",children:"Conflicts with remote"})})}),u(y,{children:u(w,{color:"grey",children:"The remote workspace has changes that aren't in your local workspace:"})}),u(y,{marginTop:1,marginLeft:2,children:u(Ts,{isExpanded:a})}),b(y,{marginTop:2,flexDirection:"row",gap:1,children:[u(w,{color:"white",bold:!0,children:"What would you like to do?"}),u(w,{color:"grey",children:"[up/down, enter]"})]}),u(y,{children:i?b(y,{flexDirection:"row",gap:1,children:[u(Ue,{type:"dots"}),u(w,{color:"blue",bold:!0,children:"Syncing with remote..."})]}):u(y,{flexDirection:"column",children:ze.map((d,h)=>u(y,{flexDirection:"column",children:b(y,{flexDirection:"row",gap:1,children:[u(w,{color:n===h?"cyan":"grey",children:n===h?"\u25B6":" "}),u(w,{color:n===h?"cyan":"grey",bold:n===h,children:d.label})]})},d.value))})})]})}c(vs,"ResolveChangesUI");const Es={[Q.UPDATE]:{incoming:{label:"Elements updated in remote",description:"(to be overwritten from remote)"},outgoing:{label:"Elements updated locally",description:"(to be pushed to remote)"}},[Q.DELETE]:{incoming:{label:"Elements not existing in remote",description:"(to be deleted locally)"},outgoing:{label:"Elements deleted locally",description:"(to be deleted from remote)"}},[Q.CREATE]:{incoming:{label:"Elements created in remote",description:"(to be created locally)"},outgoing:{label:"Elements created locally",description:"(to be created in remote)"}}};function Ts({isExpanded:r,showControls:e=!0}){const{conflicts:t}=G(),n=5,o=Ar(()=>{const i={};return t.forEach(s=>{const a=`${s.type}-${s.direction}`;i[a]||(i[a]=[]),i[a].push(s)}),i},[t]);return u(y,{flexDirection:"column",children:Object.entries(o).map(([i,s])=>{if(s.length===0)return null;const[a,l]=i.split("-"),d=Es[a][l];return b(y,{flexDirection:"column",children:[b(y,{flexDirection:"row",gap:1,children:[b(w,{color:"yellow",children:[d.label," (",s.length,")"]}),u(w,{color:"white",children:d.description})]}),(r?s:s.slice(0,n)).map(h=>u(y,{marginLeft:2,children:b(w,{color:"grey",children:["\u2022 ",h.element.id," (",h.element.relativePath,")"]})},h.element.id)),!r&&s.length>n&&u(y,{marginLeft:2,children:b(w,{color:"cyan",children:["... and ",s.length-n," more",e?" (press Ctrl+R to show all)":""]})}),r&&s.length>n&&e&&u(y,{marginLeft:2,children:u(w,{color:"cyan",children:"(press Ctrl+R to collapse)"})})]},i)})})}c(Ts,"Conflicts");function xs(){const{config:r,state:e,logs:t,currentWorkspace:n,pull:o}=G(),i=n?.name,s=i?Qn(i,30):r?.workspaceKey,a=Math.min(100,process.stdout.columns||100);return we(()=>{o({watch:!0})},[]),b(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:a,children:[u(y,{marginTop:-1,marginBottom:1,children:b(y,{flexDirection:"row",gap:1,children:[u(w,{bold:!0,children:"\u{1F504} Workspace"}),b(w,{color:ks(e),children:[" [",Is(e),"] "]})]})}),b(y,{children:[u(y,{width:12,children:u(w,{color:"grey",children:"Local:"})}),u(w,{color:"grey",children:process.cwd()})]}),b(y,{children:[u(y,{width:12,children:u(w,{color:"grey",children:"Remote:"})}),r?.workspaceKey?b(w,{color:"grey",children:[s," [o: open in console] [w: change]"]}):b(w,{children:[u(w,{color:"yellow",children:"not selected"})," [w: select]"]})]}),e===P.CONFLICTS?u(vs,{}):b(Le,{children:[u(y,{paddingTop:1,children:u(Cs,{})}),t.length>0&&u(bs,{})]})]})}c(xs,"Workspace");function Is(r){switch(r){case P.PULLING:return"pulling";case P.PUSHING:return"pushing";case P.CONFLICTS:return"conflicts";case P.SYNCED:return"synced";case P.ERROR:return"error";case P.WATCHING:return"tracking changes";case P.RESOLVING:return"resolving";case P.NOT_SYNCED:return"not synced";case P.INITIALIZED:return"initialized";case P.SETTING_UP:return"setup required";default:return"unknown"}}c(Is,"getStatusDisplay");function ks(r){switch(r){case P.PULLING:return"yellow";case P.PUSHING:return"yellow";case P.CONFLICTS:return"red";case P.SYNCED:return"green";case P.ERROR:return"red";case P.WATCHING:return"green";case P.RESOLVING:return"yellow";case P.NOT_SYNCED:return"grey";case P.SETTING_UP:return"yellow";default:return"grey"}}c(ks,"getStatusColor");function $s(){const r=di(),e=lt(!0),{exit:t,state:n}=G(),[o,i]=N(null),s=o??(n===P.SETTING_UP?"setup":"main");he(l=>{s==="main"&&(l==="w"&&i("workspace-selection"),l==="a"&&i("add-mcp-server"),l==="o"&&n===P.INITIALIZED&&a(),l==="s"&&i("setup"))});async function a(){try{const l=await mn(r),d=pt(`/w/${l}`),h=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";Gr(`${h} "${d}"`)}catch(l){console.error("Failed to open workspace:",l),t()}}return c(a,"handleOpenWorkspace"),we(()=>(e.current=!0,()=>{e.current=!1}),[]),s==="workspace-selection"?u(zn,{onExit:c(()=>i(null),"onExit")}):s==="add-mcp-server"?u(ms,{onExit:c(()=>i(null),"onExit"),onComplete:c(()=>i(null),"onComplete")}):s==="setup"?u(Hn,{onComplete:c(()=>i(null),"onComplete")},Date.now()):u(ws,{children:b(y,{flexDirection:"column",children:[u(y,{flexGrow:1,children:u(ys,{})}),u(xs,{}),u(y,{paddingLeft:2,children:u(w,{color:"grey",children:"[s: (re-)setup]"})})]})})}c($s,"Main");const Ps=c(()=>[m.yellow("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),m.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),m.yellow("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),m.yellow("\u2502 Real-time agent mode is experimental and subject to changes. \u2502"),m.yellow("\u2502 Use in production environments is not recommended. \u2502"),m.yellow("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),""].join(`
33
- `),"createExperimentalWarning$1");function As(r,e){r.command("sync").description("\u26A0\uFE0F EXPERIMENTAL: Sync workspace data in real-time - This feature is experimental and subject to changes. Use in production environments is not recommended.").option("--watch","Watch for changes and sync automatically",!1).option("--rps <number>","Maximum requests per second (default: 80)",t=>parseInt(t,10)).addHelpText("after",["","Examples:"," membrane sync --watch # Start real-time sync with watch mode"," membrane sync --watch --rps 5 # Limit to 5 requests per second",""].join(`
34
- `)).action(async t=>{if(t.watch||(console.error("Error: The sync command requires the --watch flag"),console.error("Usage: membrane sync --watch"),process.exit(1)),t.rps!==void 0){const n=t.rps;!isNaN(n)&&n>0&&n<=1e3?$.init({maxRequestsPerSecond:n}):(g.error(`Invalid RPS value: ${n}. Must be between 1 and 1000.`),process.exit(1))}console.warn(Ps()),ut(de.createElement(Mt,{cwd:process.cwd(),membraneCLIService:e,children:de.createElement($s)}))})}c(As,"setupSyncCommand");class Rs{static{c(this,"BaseRunner")}constructor(e={}){if(this.options=e,this.fsPaths=ft(),e&&typeof e=="object"){const t=e;"client"in t&&t.client&&(this.client=t.client),"workspace"in t&&(this.workspace=t.workspace)}}client;workspace;fsPaths}const Os="claude-sonnet-4-20250514";class zt{static{c(this,"TestEnvironment")}client;connectionId;testsDir;testBasePath;options;llm;state={};constructor({connectionId:e,testsDir:t,testBasePath:n,client:o,options:i,llm:s}){this.client=o,this.connectionId=e,this.testsDir=t,this.testBasePath=n,this.llm=s,this.options=i}static async create({connectionId:e,testBasePath:t,options:n}){const o=$e();if(!o)throw new Error("No configuration found. Please set MEMBRANE_WORKSPACE_KEY and MEMBRANE_WORKSPACE_SECRET environment variables, or run `membrane init` first.");if(!o.workspaceKey||!o.workspaceSecret)throw new Error("Missing workspace credentials");if(!o.anthropicApiKey)throw new Error("Anthropic API key not configured. Run `membrane init` to set up testing.");const i=new Gt({token:await this.createMembraneToken(o),apiUri:o.apiUri}),s=new Vr({apiKey:o.anthropicApiKey}),a={complete:c(async({prompt:l,maxTokens:d})=>{const h=await s.messages.create({model:Os,max_tokens:d,messages:[{role:"user",content:l}]});return h.content[0].type==="text"?h.content[0].text:""},"complete")};return new zt({client:i,options:n,connectionId:e,testsDir:"src/testing/tests",testBasePath:t,llm:a})}async run(e){this.state={};const t={};for(const n of e)await n.run(),dt(t,n.getResult());this.writeResults(t)}async readYaml(e){const t=k.join(this.testsDir,this.testBasePath,this.connectionId,e);return xt(t)}async writeYaml(e,t){const n=k.join(this.testsDir,this.testBasePath,this.connectionId,e);A.mkdirSync(k.dirname(n),{recursive:!0}),A.writeFileSync(n,H.dump(t,{noRefs:!0}))}writeResults(e){const t=k.join(this.testsDir,this.testBasePath,this.connectionId);A.mkdirSync(t,{recursive:!0});const n=k.join(t,"test-results.yaml");A.writeFileSync(n,H.dump(e,{noRefs:!0})),console.debug(`[TestRunner] Results written to: ${n}`)}static async createMembraneToken(e){const t=e.testCustomerId||"test-customer",n={id:t,name:t},o={issuer:e.workspaceKey,expiresIn:7200,algorithm:"HS512"};return nt.sign(n,e.workspaceSecret,o)}}Zr.interpolate=/{{([\s\S]+?)}}/g;function qt(r,e){if(typeof r=="string"){const t=Yr(r),n={state:e,random:{number:c(()=>ke.number.int(),"number"),alphaNumeric:c(i=>ke.string.alphanumeric(i),"alphaNumeric")},faker:{company:{name:c(()=>ke.company.name(),"name"),catchPhrase:c(()=>ke.company.catchPhrase(),"catchPhrase")},internet:{email:c(()=>ke.internet.email(),"email")}},entries:e["journal-entries"],orders:e["purchase-orders"]||e["sales-orders"],bills:e["vendor-bills"]},o=t(n);return r.includes("{{")&&r.includes("}}")&&(console.debug(`[TEMPLATE] Input: ${r}`),console.debug(`[TEMPLATE] Output: ${o}`)),o}return Array.isArray(r)?r.map(t=>qt(t,e)):typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).map(([t,n])=>[t,qt(n,e)])):r}c(qt,"processNode");function Ds(r,e){return qt(r,e)}c(Ds,"handleTemplate");class Ns{static{c(this,"BaseTestSuite")}result;environment;constructor({environment:e}){this.environment=e,this.result={}}async run(){}getResult(){return this.result}async runTest(e){console.debug(`${m.bold.cyan("[start]")} ${m.yellow(e.path)}`);let t=!1,n=!1,o={},i={},s;for(;!t;)try{i=await e.readTestCase(),i||(i=await e.generateConfig(),await this.environment.writeYaml(e.getTestCasePath(),i),console.debug(`${m.bold.yellow("[initialized]")} ${m.yellow(e.path)}`)),s=Ds(i,this.environment.state),await e.run(s),console.debug(`${m.bold.green("[success]")} ${m.yellow(e.path)}`),t=!0,o=e.getResult(),Xe(this.result,e.path,o)}catch(l){if(console.error(`${m.bold.red("[error]")} ${m.yellow(e.path)}: ${l}`),this.environment.options.fix&&!n){n=!0;try{await e.fix(l);continue}catch(d){console.error(`${m.bold.red("[fix fail]")} ${m.yellow(e.path)}: ${d}`)}}Xe(this.result,e.path,{error:z(l)}),t=!0,o={error:z(l)}}const a={...s,result:o};await this.environment.writeYaml(e.getTestCasePath(),a)}async runTestSuite(e){await e.run(),dt(this.result,e.getResult())}}class ce{static{c(this,"BaseTester")}environment;level;logs;assertions;resultsLocator;path;constructor({environment:e,path:t}){this.environment=e,this.logs=[],this.assertions=[],this.path=t,this.level=0,this.resultsLocator=""}async fix(e){const t=await this.readTestCase();if(!t)throw new Error(`No config found for test ${this.path}`);const n=await this.fixTestCase({config:t,error:e});console.debug(m.bold.yellow("[auto-fix]"),this.path),await this.environment.writeYaml(this.getTestCasePath(),n)}async readTestCase(){const e=this.getTestCasePath();return this.environment.readYaml(e)}async generateConfig(){return{}}async fixTestCase(e){throw new Error(`Auto-fix is not implemented for test ${this.path}`)}getResult(){return{logs:this.logs,assertions:this.assertions}}async assert(e,t,n){try{const o=await e();o?(this.logMsg(`\u2705 ${t}`),this.assertions.push({message:t,result:o})):(this.logMsg(`\u274C ${t}`),this.assertions.push({message:t,result:!1,details:n}))}catch(o){this.assertions.push({message:t,result:!1,details:z(o)}),this.logMsg(`\u274C ${t}: ${o.message}`)}}logMsg(e){console.debug(`${" ".repeat(this.level*2)}${e}`)}getTestCasePath(){return`${this.path}.test.yml`}}function Bt(r,e){const t={};for(const n in e){if(!(n in r)){t[n]=e[n];continue}const o=r[n],i=e[n];if(o&&i&&typeof o=="object"&&typeof i=="object"){if(Array.isArray(o)&&Array.isArray(i)){const s=i.filter(a=>!o.some(l=>{if(typeof l=="object"&&typeof a=="object"&&l!==null&&a!==null&&!Array.isArray(l)&&!Array.isArray(a)){for(const d in a)if(!(d in l)||!Wt(l[d],a[d]))return!1;return!0}else return JSON.stringify(l)===JSON.stringify(a)}));s.length>0&&(t[n]=s)}else if(!Array.isArray(o)&&!Array.isArray(i)){const s=Bt(o,i);s!==null&&(t[n]=s)}else t[n]=i;continue}Wt(o,i)||(t[n]=i)}return Object.keys(t).length===0?null:t}c(Bt,"getNotMatchingSubFields");function Wt(r,e){if(r==e||r?.toString?.()===e?.toString?.())return!0;const t=new Date(r),n=new Date(e);return!isNaN(t.getTime())&&!isNaN(n.getTime())?t.getTime()===n.getTime():!1}c(Wt,"softCompare");class Ms extends ce{static{c(this,"DataCollectionCreateTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/create`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).create(e.input);await this.assert(()=>!!t.id,"Returned ID of a created record"),t.id&&(this.environment.state[this.dataCollectionKey]={createdRecordId:t.id});const n=Qe(this.dataCollection);if(this.dataCollection.findById){const i=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).findById({id:t.id});await this.assert(()=>!!i.record,"Record is returned from findById"),i.record&&(this.environment.state[this.dataCollectionKey]={createdRecordId:t.id,createdRecord:i.record.fields});const s=Zt(n),a=Ne(e.input.fields,s,{skipUnknownFields:!0}),l=Ne(i.record.fields,s),d=Bt(l,a);await this.assert(()=>!d,"Returned fields match created fields",{difference:d,sentFields:a,receivedFields:l})}const o=wr(n??{});if(o.length>0){const i={};o.forEach(a=>{const l=Cr(e.input.fields,a);typeof l<"u"&&Xe(i,a,l)});const s=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).create({fields:i});await this.assert(()=>!!s.id,"Record can be created with schema-defined required fields only")}}async generateConfig(){const e=Qe(this.dataCollection);if(!e?.properties)throw new Error("No fields schema found for data collection");return{input:{fields:await this.generateFieldsWithLLM(e)}}}async fixTestCase({config:e,error:t}){const n=z(t),o=Qe(this.dataCollection),i=await this.getExampleRecordsForSchema(o),s=`I'm trying to create a data record in a data collection with the following fields schema:
42
+ `,version:"1.0.0"});for(const C of u){const E=C.execute;C.execute=async S=>(gi(process.pid,process.cwd()),E(S)),h.addTool(C)}Dt({isRunning:!0,startTime:new Date().toISOString(),toolsCount:u.length,lastActivity:new Date().toISOString(),processId:process.pid,cwd:process.cwd(),agentName:process.env.AGENT_NAME||"Unnamed Agent"});const m=setInterval(()=>{Dt({processId:process.pid,cwd:process.cwd(),lastActivity:new Date().toISOString()})},5e3),f=c(async()=>{clearInterval(m),Re(process.pid,process.cwd());try{await h.stop()}catch{}},"cleanup");await h.start({transportType:"stdio"}),process.on("SIGINT",async()=>{await f(),process.exit(0)}),process.on("SIGTERM",async()=>{await f(),process.exit(0)}),process.on("exit",()=>{Re(process.pid,process.cwd())}),process.on("uncaughtException",async C=>{console.error("Uncaught exception:",C.message),await f(),process.exit(1)}),process.on("unhandledRejection",async C=>{console.error("Unhandled rejection:",C),await f(),process.exit(1)})}catch(e){e instanceof Error&&(console.error(e.message),process.exit(1)),console.error("An unknown error occurred"),process.exit(1)}})}c(ts,"setupMcpCommand");function ns(r){r.command("open").description("Open the workspace in the browser").addHelpText("after",["","Examples:"," membrane open # Open workspace in browser",""].join(`
43
+ `)).action(async()=>{try{b.header("Opening Workspace in Browser"),b.info("Loading configuration...");const e=xe();if(!e)throw new Error("No configuration found. Please set MEMBRANE_WORKSPACE_KEY and MEMBRANE_WORKSPACE_SECRET environment variables, or run `membrane init` first.");if(!e.workspaceKey||!e.workspaceSecret)throw new Error("Missing workspace credentials");b.info("Retrieving workspace ID...");const t=await bn(process.cwd()),n=ft(`/w/${t}`);b.info(`Opening ${n}...`);const{default:o}=await import("open");await o(n),b.success("Browser opened successfully")}catch(e){e instanceof Error&&(b.error(e.message),process.exit(1)),b.error("An unknown error occurred"),process.exit(1)}})}c(ns,"setupOpenCommand");const sr=5;function rs(r){r.command("pull").description("Pull workspace data from specified workspace").option("--force","Overwrite conflicts with remote data",!1).addHelpText("after",["","Examples:"," membrane pull # Pull from default workspace"," membrane pull --force # Overwrite conflicts with remote data",""].join(`
44
+ `)).action(async e=>{const t=Ce({text:"Pulling workspace",color:"white"}).start();try{const n=await os(e,t);t.stop(),ls(n.workspaceExport,n.connectors)}catch(n){t.stop(),ds(n),process.exit(1)}})}c(rs,"setupPullCommand");async function os(r,e){const t=await bt(),n=await An(t),o=await En(),i=await Pn(o),{comparison:s}=Xt(t,i);s[ee.DELETE].size>0&&!r.force&&(await us(s,n),b.error("Use --force to delete local elements"),process.exit(1));const l=await On(W(process.cwd()));for(const{filePath:m,data:f}of l)s[ee.DELETE].has(f.uuid)&&xo(m);return $n(W(process.cwd())),await St(o,(m,f)=>{if(de(m)&&(s[ee.CREATE].has(f.uuid)||s[ee.UPDATE].has(f.uuid))){const E=x.join(W(process.cwd()),m);xn(E,f)}}),{connectors:await $.isVersionAtLeast("1.8")?await is(o,e):await as(i[k.Integration],e),workspaceExport:i}}c(os,"pullWorkspace");async function is(r,e){e.text="Extracting connectors",Ct(x.join(W(process.cwd()),"connectors"));const t=new Set,n=await _e.Open.buffer(r);for(const o of n.files){if(!o.path.startsWith("connectors/")||o.type==="Directory")continue;const i=x.join(W(process.cwd()),o.path);Pe(x.dirname(i));const s=await o.buffer();if(kn(i,s),t.add(o.path.split("/")[1]),o.path.endsWith("/development/src.zip")){const a=x.join(x.dirname(i),"src");Pe(a),await(await _e.Open.buffer(s)).extract({path:a})}}return Array.from(t)}c(is,"extractConnectorsFromExport");async function ss(r,e,t){if(kn(x.join(Oe(r,e),"src.zip"),t),!e||e===Ye){const n=x.join(Oe(r,e),"src");Pe(n),await(await _e.Open.buffer(t)).extract({path:n})}}c(ss,"writeConnectorVersion");async function as(r,e){e.text="Pulling connectors";const t=new Map,{id:n}=await $.withClient(l=>l.get("org-workspace-id")),{items:o=[]}=await $.withClient(l=>l.get(`/connectors?workspaceId=${n}`));for(const l of o){const u=l.uuid??l.id;!l.isPublic&&u&&t.set(u,new Set([""]))}for(const l of r??[]){const{connectorUuid:u,connectorVersion:h}=l;u&&(t.has(u)||t.set(u,new Set),t.get(u).add(h??""))}const i=Nn();for(const[l,{key:u,versions:h}]of Object.entries(i)){if(!t.has(l)){const f=Oe(u);Ct(f);continue}const m=t.get(l);for(const f of h)if(!m.has(f)){const C=Oe(u,f);Ct(C)}}const s=Array.from(t.entries()),a=c((l,u)=>{l==="pulling"?e.start(`Pulling connector ${u}...`):e.succeed(`Pulled connector ${u}`)},"onProgress");for(let l=0;l<s.length;l+=sr){const u=s.slice(l,l+sr);await Promise.all(u.map(([h,m])=>cs(h,Array.from(m),a)))}return Array.from(t.keys())}c(as,"pullConnectorsLegacy");async function cs(r,e,t){const n=await $.withClient(u=>u.get(`connectors/${r}/export-json`),!1),o=await $.withClient(u=>u.get(`connectors/${r}`),!1);if(!n||!o||!n.key||!o.key)return;const i=o.name||n.key;t?.("pulling",i);const s={...n,id:o.id,uuid:o.uuid},a=Oe(n.key),l=x.join(a,`${n.key}.yml`);xn(l,s);for(const u of e){const h=await ko(r,u);await ss(n.key,u,h)}t?.("pulled",i)}c(cs,"pullConnector");function ls(r,e=[]){const t=Object.values(r).reduce((n,o)=>n+(o?.length??0),0)+e.length;b.info(`\u25CF Pulled workspace elements \xB7 ${t}`);for(const n of Object.keys(r).sort()){const o=r[n];b.info(`\u2514\u2500\u2500 ${n}s \xB7 ${o?.length??0}`)}e.length>0&&b.info(`\u2514\u2500\u2500 connectors \xB7 ${e.length}`)}c(ls,"showStats$1");async function us(r,e){const t=r[ee.DELETE].size;b.info(`\u2299 Pull: conflicts detected \xB7 ${t}`),await St(e,(n,o)=>{de(n)&&r[ee.DELETE].has(o.uuid)&&b.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted in remote)`)})}c(us,"showConflicts$1");async function ds(r){b.error("\u25A0 Error"),b.error(`\u2514\u2500\u2500 ${r.message}`),b.error(` ${r.stack}`)}c(ds,"showError$1");const B=[];for(let r=0;r<256;++r)B.push((r+256).toString(16).slice(1));function hs(r,e=0){return(B[r[e+0]]+B[r[e+1]]+B[r[e+2]]+B[r[e+3]]+"-"+B[r[e+4]]+B[r[e+5]]+"-"+B[r[e+6]]+B[r[e+7]]+"-"+B[r[e+8]]+B[r[e+9]]+"-"+B[r[e+10]]+B[r[e+11]]+B[r[e+12]]+B[r[e+13]]+B[r[e+14]]+B[r[e+15]]).toLowerCase()}c(hs,"unsafeStringify");let qt;const ps=new Uint8Array(16);function fs(){if(!qt){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");qt=crypto.getRandomValues.bind(crypto)}return qt(ps)}c(fs,"rng");const ms=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto);var ar={randomUUID:ms};function gs(r,e,t){if(ar.randomUUID&&!r)return ar.randomUUID();r=r||{};const n=r.random??r.rng?.()??fs();if(n.length<16)throw new Error("Random bytes length must be >= 16");return n[6]=n[6]&15|64,n[8]=n[8]&63|128,hs(n)}c(gs,"v4");function ys(r){r.command("push").description("Push workspace data to specified workspace").argument("[files...]","Files, directories, or glob patterns to push").option("--force","Overwrite conflicts with local data",!1).addHelpText("after",["","Examples:"," membrane push # Push all workspace elements"," membrane push data-sources/ # Push all data-sources"," membrane push actions/my-action/spec.yaml # Push specific action"," membrane push flows/*-test/spec.yaml # Push flows matching pattern"," membrane push --force # Overwrite conflicts with local data",""].join(`
45
+ `)).action(async(e,t)=>{const n=Ce({text:"Pushing workspace",color:"white"}).start();try{await ws(e,t,n)}catch(o){n.stop(),xs(o),process.exit(1)}})}c(ys,"setupPushCommand");async function ws(r,e,t){const n=r.length>0,o=await bt(),i=Nn(),s=bs(o,i),a=await $.isVersionAtLeast("1.9"),l=await An(s,n?r:void 0,a?i:void 0);e.force||(t.text="Comparing workspace",await Cs(l,n)&&(t.stop(),process.exit(1)));const u=a?Object.keys(i):await Ss(t);t.start("Pushing workspace..."),await In(l,{partial:n}),t.stop(),Is(s,u),process.exit(0)}c(ws,"pushWorkspace");async function Cs(r,e){const t=await In(r,{dryRun:!0,partial:e}),n=t[ee.DELETE].size>0;return n&&(await ks(t,r),b.error("Use --force to delete remote elements")),n}c(Cs,"checkForConflicts");async function Ss(r){return(await Kn({onProgress:c((t,n)=>{t==="pushing"?r.start(`Pushing connector ${n}...`):r.succeed(`Pushed connector ${n}`)},"onProgress")})).pushedConnectors??[]}c(Ss,"pushConnectorsLegacy");function bs(r,e){const t=Ts(r),n=Es(t,e),o={};for(const[i,s]of Object.entries(t)){const a=i;o[a]=(s||[]).map(l=>vs(l,a,n))}return o}c(bs,"resolveLegacyIdReferences");function vs(r,e,t){const n={...r},o=Q[e]?.parentFieldKey||"parentId";if(n.integrationId&&!n.integrationUuid&&(n.integrationUuid=t.get(n.integrationId.toString())||n.integrationId,delete n.integrationId),n.connectorId){if(!n.connectorUuid){const i=t.get(n.connectorId.toString());i&&(n.connectorUuid=i)}delete n.connectorId}if(n[o]){const i=t.get(n[o].toString());i&&(n.parentUuid=i)}return e===k.Package&&n.elements&&(n.elements=n.elements.map(i=>{if(i.id&&!i.uuid){const s=t.get(i.id.toString());if(s)return{uuid:s,type:i.type}}return i})),delete n.id,n}c(vs,"resolveElementIds");function Ts(r){const e={};for(const[t,n]of Object.entries(r))e[t]=(n||[]).map(o=>o.uuid?o:{...o,uuid:gs()});return e}c(Ts,"generateMissingUuids");function Es(r,e){const t=new Map;for(const n of Object.values(r))for(const o of n||[])o.id&&o.uuid&&t.set(o.id.toString(),o.uuid);for(const[n,o]of Object.entries(e))o.id&&t.set(o.id.toString(),n);return t}c(Es,"buildIdToUuidLookup");function Is(r,e=[]){const t=Object.values(r).reduce((n,o)=>n+(o?.length??0),0)+e.length;b.info(`\u25CF Pushed workspace elements \xB7 ${t}`);for(const n of Object.keys(r).sort()){const o=r[n];b.info(`\u2514\u2500\u2500 ${n}s \xB7 ${o?.length??0}`)}e.length>0&&b.info(`\u2514\u2500\u2500 connectors \xB7 ${e.length}`)}c(Is,"showStats");async function ks(r,e){const t=r[ee.DELETE].size;b.info(`\u2299 Push: conflicts detected \xB7 ${t}`),await St(e,(n,o)=>{de(n)&&r[ee.DELETE].has(o.uuid)&&b.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted locally)`)})}c(ks,"showConflicts");function xs(r){b.error("\u25A0 Error"),b.error(`\u2514\u2500\u2500 ${r.message}`),b.error(` ${r.stack}`)}c(xs,"showError");function $s(r){r.command("search <query>").description("Search workspace elements (connectors, integrations, actions, etc.)").option("--elementType <type>","Filter by element type (e.g. connector, integration)").option("--limit <n>","Max results").option("--workspaceKey <key>","Workspace key").option("--tenantKey <key>","Tenant key (customer internalId)").option("--json","Output as JSON").action(async(e,t)=>{try{const n=new J(t),o=new URLSearchParams({q:e});t.elementType&&o.set("elementType",t.elementType),t.limit&&o.set("limit",t.limit);const i=await n.get(`/search?${o}`);if(t.json)process.stdout.write(JSON.stringify(i,null,2)+`
46
+ `);else{const s=i.items??[];if(s.length===0)console.error(p.gray(" No results found."));else for(const a of s){const l=a.element,u=p.gray(`[${a.elementType}]`),h=l?.name||l?.key||"(unnamed)",m=p.cyan(String(l?.id??a.id??"(no id)"));console.error(` ${u} ${m} ${h}`)}console.error()}}catch(n){q(n)}})}c($s,"setupSearchCommand");const As="0";function Ps(r){r.command("status").description("Show current login status, project settings, and resolved environment").action(async()=>{try{await Os()}catch(e){q(e)}})}c(Ps,"setupStatusCommand");async function Os(){const r=me()||te,e=Mn(),t=wt();if(console.error(),console.error(p.bold.cyan("\u25B6 Membrane CLI Status")),console.error(),R("API",r),!t)R("Auth",p.red("Not logged in"));else{const n=gt(),o=!!be(),i=yt();if(n&&!o)R("Auth",p.yellow("Token expired (no refresh token)"));else if(i==="tenant"){R("Auth",p.green("Logged in")+p.gray(" (tenant scope)"));try{const a=await new Ae().get("/self"),l=a.workspaceKey??e.defaultWorkspaceKey;l&&R("Workspace",l);const u=a.internalId??e.defaultTenantKey;a.name&&u?R("Tenant",`${a.name} (${u})`):a.name?R("Tenant",a.name):u&&R("Tenant",u)}catch{e.defaultWorkspaceKey&&R("Workspace",e.defaultWorkspaceKey),e.defaultTenantKey&&R("Tenant",e.defaultTenantKey)}}else{try{const a=await new Ae().get(`/account?workspaceId=${As}`);if(a.user?(R("Auth",p.green("Logged in")),R("User",`${a.user.name} (${a.user.email})`)):R("Auth",p.green("Logged in")),a.orgs?.length){const l=a.orgs.map(u=>u.name).join(", ");R("Orgs",l)}}catch{R("Auth",p.yellow("Logged in (could not fetch account details)"))}e.defaultWorkspaceKey&&R("Workspace",`${e.defaultWorkspaceKey} ${p.gray("(default)")}`),e.defaultTenantKey&&R("Tenant",`${e.defaultTenantKey} ${p.gray("(default)")}`),!e.defaultWorkspaceKey&&!e.defaultTenantKey&&R("Project",p.gray("No project defaults configured"))}}console.error()}c(Os,"runStatus");const Bt=[{id:"claude-code",name:"Claude Code",description:"Anthropic Claude Code agent",actionDescription:"Adding membrane MCP to .mcp.json in the current directory",addConfig:c(()=>{const r=I.join(process.cwd(),".mcp.json"),e={mcpServers:{membrane:{command:"membrane",args:["mcp"],env:{AGENT_NAME:"Claude Code"}}}};let t={};if(T.existsSync(r))try{t=JSON.parse(T.readFileSync(r,"utf8"))}catch{t={}}const n={...t,mcpServers:{...t.mcpServers,...e.mcpServers}};return T.writeFileSync(r,JSON.stringify(n,null,2)),`MCP server configuration added to ${r}`},"addConfig")},{id:"cursor",name:"Cursor",description:"Cursor AI editor",actionDescription:"Adding membrane MCP to .cursor/mcp.json in the current directory",addConfig:c(()=>{const r=I.join(process.cwd(),".cursor"),e=I.join(r,"mcp.json");T.existsSync(r)||T.mkdirSync(r);const t={mcpServers:{membrane:{command:"membrane",args:["mcp"],env:{AGENT_NAME:"Cursor"}}}};let n={};if(T.existsSync(e))try{n=JSON.parse(T.readFileSync(e,"utf8"))}catch{n={}}const o={...n,mcpServers:{...n.mcpServers,...t.mcpServers}};return T.writeFileSync(e,JSON.stringify(o,null,2)),`MCP server configuration added to ${e}`},"addConfig")}];function Rs({onExit:r,onComplete:e}){const[t,n]=L(0),[o,i]=L(!1),[s,a]=L(null),[l,u]=L(""),[h,m]=L("");pe((E,S)=>{if(l||h){(S.escape||E==="q"||S.return)&&e();return}if(o)S.return||E===" "?f(s):S.escape&&(i(!1),a(null));else if(S.escape)r();else if(S.upArrow||E==="k")n(Math.max(0,t-1));else if(S.downArrow||E==="j")n(Math.min(Bt.length-1,t+1));else if(S.return||E===" "){const N=Bt[t];a(N),i(!0)}});const f=c(E=>{try{const S=E.addConfig();u(S)}catch(S){m(`Failed to write configuration: ${S.message||S}`)}},"addMcpConfiguration"),C=Math.min(80,process.stdout.columns||80);return l?v(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:C,children:[d(y,{marginTop:-1,marginBottom:1,children:v(w,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",d(w,{color:"green",children:"Success"})]})}),v(y,{flexDirection:"column",paddingLeft:2,children:[d(w,{color:"green",children:l}),d(y,{marginTop:1,children:d(w,{color:"grey",children:"The agent will now be able to use Membrane's integration capabilities."})})]}),d(y,{marginTop:1,paddingLeft:2,children:d(w,{color:"white",children:"[esc/q/enter: exit]"})})]}):h?v(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:C,children:[d(y,{marginTop:-1,marginBottom:1,children:v(w,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",d(w,{color:"red",children:"Error"})]})}),d(y,{flexDirection:"column",paddingLeft:2,children:d(w,{color:"red",children:h})}),d(y,{marginTop:1,children:d(w,{color:"grey",children:"[esc/q/enter: exit]"})})]}):o&&s?v(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:C,children:[d(y,{marginTop:-1,marginBottom:1,children:v(w,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",d(w,{color:"cyan",children:"Confirmation"})]})}),v(y,{flexDirection:"column",paddingLeft:2,children:[v(w,{children:["Connect ",d(w,{bold:!0,children:s.name})," to Membrane via MCP?"]}),d(y,{marginTop:1,children:d(w,{color:"grey",children:"This will add an MCP server configuration that allows the agent to use Membrane's integration capabilities."})}),d(y,{marginTop:1,children:d(w,{color:"yellow",bold:!0,children:s.actionDescription})}),d(y,{marginTop:2,marginBottom:1,children:v(w,{children:[d(w,{color:"white",bold:!0,children:"[Enter] Confirm"})," ",d(w,{color:"gray",children:"[Esc] Cancel"})]})})]})]}):v(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:C,children:[d(y,{marginTop:-1,marginBottom:1,children:v(w,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",d(w,{color:"cyan",children:"Select Agent"})]})}),v(y,{flexDirection:"column",paddingLeft:2,children:[d(w,{color:"grey",children:"Choose an agent to connect to Membrane via MCP:"}),d(y,{marginTop:1,children:d(w,{color:"grey",children:"This will add an MCP server configuration that allows the agent to use Membrane's integration capabilities."})}),d(y,{marginTop:1,flexDirection:"column",children:Bt.map((E,S)=>v(y,{children:[v(w,{color:t===S?"cyan":"white",children:[t===S?"\u25B6 ":" ",E.name]}),v(w,{color:"grey",children:[" \u2014 ",E.description]})]},E.id))})]}),d(y,{marginTop:1,children:d(w,{color:"grey",children:"[\u2191\u2193: select] [enter: choose] [esc: exit]"})})]})}c(Rs,"AddMcpServerScreen");function Ns(){const[r,e]=L(null),[t,n]=L([]),[o,i]=L(null);return Se(()=>{const s=c(({status:l})=>{e(l),i(null)},"handleMcpStatusChanged"),a=c(({servers:l})=>{n(l),i(null)},"handleMcpServersChanged");return se.on(U.McpStatusChanged,s),se.on(U.McpServersChanged,a),()=>{se.off(U.McpStatusChanged,s),se.off(U.McpServersChanged,a)}},[]),{mcpStatus:r,allMcpServers:t,error:o,isRunning:r?.isRunning||!1,toolsCount:r?.toolsCount||0,totalRequests:r?.totalRequests||0,lastActivity:r?.lastActivity,processId:r?.processId,serverCount:t.length}}c(Ns,"useMcpStatus");function Ds(){const{error:r,serverCount:e,allMcpServers:t}=Ns(),n=Math.min(100,process.stdout.columns||100);return v(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:n,children:[d(y,{marginTop:-1,marginBottom:0,flexDirection:"column",children:v(w,{bold:!0,children:["\u{1F916} Connected AI Agents:"," ",r?d(w,{color:"red",children:"error reading status"}):e===0?d(w,{color:"yellow",children:"none"}):d(w,{color:"green",children:e})]})}),!r&&e===0&&d(y,{marginTop:1,children:v(w,{color:"grey",children:["Connect your AI agents to Membrane.",d(Ur,{}),"It will give them tools and context to build integrations."]})}),t.length>0&&d(y,{flexDirection:"column",paddingLeft:2,marginTop:1,children:t.map((o,i)=>d(y,{children:v(w,{color:"grey",children:["#",i+1," ",o.agentName,": ",o.totalRequests," calls"]})},o.processId))}),d(y,{marginTop:1,children:d(w,{color:"grey",children:"[a: connect an agent]"})})]})}c(Ds,"Agent");const cr=c(r=>{switch(r){case"error":return"red";case"success":return"green";case"warning":return"yellow";default:return}},"getLogColor");function lr(r,e){return e<3?r.slice(0,Math.max(0,e)):r.length<=e?r:`${r.slice(0,e-3)}...`}c(lr,"truncateText");function Ls({children:r}){const{state:e,logs:t}=Z();return!e||e===A.NOT_INITIALIZED?v(y,{gap:1,flexDirection:"row",children:[d(eo,{type:"dots"}),d(w,{children:"Initializing..."})]}):e===A.SETTING_UP?d(y,{gap:1,flexDirection:"row",children:d(w,{children:"No workspace selected. Please run `membrane init` to select a workspace."})}):e===A.ERROR?d(y,{flexDirection:"column",children:t.slice().map((n,o)=>d(w,{color:cr(n.type),children:n.message},n.timestamp+o))}):r}c(Ls,"EnsureInitialized");function Ms(){const{stats:r}=Z(),e=Object.entries(r).filter(([t,n])=>n>0);return e.length===0?null:v(y,{flexDirection:"column",children:[d(y,{children:d(y,{width:12,children:d(w,{color:"grey",children:"Elements:"})})}),d(y,{flexDirection:"column",marginLeft:1,children:e.map(([t,n])=>v(y,{children:[d(y,{width:20,children:v(w,{children:[t,":"]})}),d(w,{color:"green",children:n})]},t))})]})}c(Ms,"ElementStats");const Wt=5,js=6;function Fs(){const{logs:r}=Z(),[e,t]=L(0),n=Math.min(100,process.stdout.columns||100),o=Wt,i=Math.max(0,r.length-o-e),s=r.length-e,a=r.slice(i,s),l=n-js,u=e<r.length-o,h=e>0;return pe((m,f)=>{if(r.length!==0)if(f.upArrow){const C=Math.max(0,r.length-o);t(E=>Math.min(C,E+1))}else f.downArrow?t(C=>Math.max(0,C-1)):(m==="G"||m==="g")&&t(0)}),v(y,{flexDirection:"column",paddingTop:1,children:[v(w,{color:"grey",children:["Recent Activity (",i+1,"-",s," of ",r.length,"):",r.length>Wt&&d(w,{color:"grey",children:" [arrows: scroll] [g: end]"})]}),a.map((m,f)=>d(y,{marginLeft:1,children:d(w,{color:cr(m.type),children:lr(m.message,l)})},m.timestamp+f)),r.length>Wt&&v(y,{marginLeft:1,flexDirection:"row",children:[u&&d(w,{color:"grey",children:"\u2191 "}),h&&d(w,{color:"grey",children:"\u2193 "})]})]})}c(Fs,"Logs");const Ge=[{value:"sync",label:"Continue (overwrite/delete)",key:""},{value:"exit",label:"Cancel",key:""}];function Us(){const{state:r,resolveConflicts:e,exit:t}=Z(),[n,o]=L(0),[i,s]=L(!1),[a,l]=L(!1);return pe((u,h)=>{if(!i){if(h.ctrl&&u.toLowerCase()==="r"){l(!a);return}h.upArrow?o(m=>m>0?m-1:Ge.length-1):h.downArrow?o(m=>m<Ge.length-1?m+1:0):u.toLowerCase()==="y"?o(0):u.toLowerCase()==="n"?o(1):(h.return||u===" ")&&(s(!0),Ge[n].value==="sync"?e({watch:!0}):t())}}),Se(()=>{r!==A.CONFLICTS&&i&&s(!1)},[r,i]),v(y,{flexDirection:"column",paddingTop:1,children:[d(y,{children:d(y,{flexDirection:"row",gap:2,children:d(w,{bold:!0,color:"white",children:"Conflicts with remote"})})}),d(y,{children:d(w,{color:"grey",children:"The remote workspace has changes that aren't in your local workspace:"})}),d(y,{marginTop:1,marginLeft:2,children:d(_s,{isExpanded:a})}),v(y,{marginTop:2,flexDirection:"row",gap:1,children:[d(w,{color:"white",bold:!0,children:"What would you like to do?"}),d(w,{color:"grey",children:"[up/down, enter]"})]}),d(y,{children:i?v(y,{flexDirection:"row",gap:1,children:[d(qe,{type:"dots"}),d(w,{color:"blue",bold:!0,children:"Syncing with remote..."})]}):d(y,{flexDirection:"column",children:Ge.map((u,h)=>d(y,{flexDirection:"column",children:v(y,{flexDirection:"row",gap:1,children:[d(w,{color:n===h?"cyan":"grey",children:n===h?"\u25B6":" "}),d(w,{color:n===h?"cyan":"grey",bold:n===h,children:u.label})]})},u.value))})})]})}c(Us,"ResolveChangesUI");const Ks={[ne.UPDATE]:{incoming:{label:"Elements updated in remote",description:"(to be overwritten from remote)"},outgoing:{label:"Elements updated locally",description:"(to be pushed to remote)"}},[ne.DELETE]:{incoming:{label:"Elements not existing in remote",description:"(to be deleted locally)"},outgoing:{label:"Elements deleted locally",description:"(to be deleted from remote)"}},[ne.CREATE]:{incoming:{label:"Elements created in remote",description:"(to be created locally)"},outgoing:{label:"Elements created locally",description:"(to be created in remote)"}}};function _s({isExpanded:r,showControls:e=!0}){const{conflicts:t}=Z(),n=5,o=Fr(()=>{const i={};return t.forEach(s=>{const a=`${s.type}-${s.direction}`;i[a]||(i[a]=[]),i[a].push(s)}),i},[t]);return d(y,{flexDirection:"column",children:Object.entries(o).map(([i,s])=>{if(s.length===0)return null;const[a,l]=i.split("-"),u=Ks[a][l];return v(y,{flexDirection:"column",children:[v(y,{flexDirection:"row",gap:1,children:[v(w,{color:"yellow",children:[u.label," (",s.length,")"]}),d(w,{color:"white",children:u.description})]}),(r?s:s.slice(0,n)).map(h=>d(y,{marginLeft:2,children:v(w,{color:"grey",children:["\u2022 ",h.element.id," (",h.element.relativePath,")"]})},h.element.id)),!r&&s.length>n&&d(y,{marginLeft:2,children:v(w,{color:"cyan",children:["... and ",s.length-n," more",e?" (press Ctrl+R to show all)":""]})}),r&&s.length>n&&e&&d(y,{marginLeft:2,children:d(w,{color:"cyan",children:"(press Ctrl+R to collapse)"})})]},i)})})}c(_s,"Conflicts");function qs(){const{config:r,state:e,logs:t,currentWorkspace:n,pull:o}=Z(),i=n?.name,s=i?lr(i,30):r?.workspaceKey,a=Math.min(100,process.stdout.columns||100);return Se(()=>{o({watch:!0})},[]),v(y,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:a,children:[d(y,{marginTop:-1,marginBottom:1,children:v(y,{flexDirection:"row",gap:1,children:[d(w,{bold:!0,children:"\u{1F504} Workspace"}),v(w,{color:Ws(e),children:[" [",Bs(e),"] "]})]})}),v(y,{children:[d(y,{width:12,children:d(w,{color:"grey",children:"Local:"})}),d(w,{color:"grey",children:process.cwd()})]}),v(y,{children:[d(y,{width:12,children:d(w,{color:"grey",children:"Remote:"})}),r?.workspaceKey?v(w,{color:"grey",children:[s," [o: open in console] [w: change]"]}):v(w,{children:[d(w,{color:"yellow",children:"not selected"})," [w: select]"]})]}),e===A.CONFLICTS?d(Us,{}):v(Ke,{children:[d(y,{paddingTop:1,children:d(Ms,{})}),t.length>0&&d(Fs,{})]})]})}c(qs,"Workspace");function Bs(r){switch(r){case A.PULLING:return"pulling";case A.PUSHING:return"pushing";case A.CONFLICTS:return"conflicts";case A.SYNCED:return"synced";case A.ERROR:return"error";case A.WATCHING:return"tracking changes";case A.RESOLVING:return"resolving";case A.NOT_SYNCED:return"not synced";case A.INITIALIZED:return"initialized";case A.SETTING_UP:return"setup required";default:return"unknown"}}c(Bs,"getStatusDisplay");function Ws(r){switch(r){case A.PULLING:return"yellow";case A.PUSHING:return"yellow";case A.CONFLICTS:return"red";case A.SYNCED:return"green";case A.ERROR:return"red";case A.WATCHING:return"green";case A.RESOLVING:return"yellow";case A.NOT_SYNCED:return"grey";case A.SETTING_UP:return"yellow";default:return"grey"}}c(Ws,"getStatusColor");function Js(){const r=ki(),e=lt(!0),{exit:t,state:n}=Z(),[o,i]=L(null),s=o??(n===A.SETTING_UP?"setup":"main");pe(l=>{s==="main"&&(l==="w"&&i("workspace-selection"),l==="a"&&i("add-mcp-server"),l==="o"&&n===A.INITIALIZED&&a(),l==="s"&&i("setup"))});async function a(){try{const l=await bn(r),u=ft(`/w/${l}`),h=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";no(`${h} "${u}"`)}catch(l){console.error("Failed to open workspace:",l),t()}}return c(a,"handleOpenWorkspace"),Se(()=>(e.current=!0,()=>{e.current=!1}),[]),s==="workspace-selection"?d(Qn,{onExit:c(()=>i(null),"onExit")}):s==="add-mcp-server"?d(Rs,{onExit:c(()=>i(null),"onExit"),onComplete:c(()=>i(null),"onComplete")}):s==="setup"?d(er,{onComplete:c(()=>i(null),"onComplete")},Date.now()):d(Ls,{children:v(y,{flexDirection:"column",children:[d(y,{flexGrow:1,children:d(Ds,{})}),d(qs,{}),d(y,{paddingLeft:2,children:d(w,{color:"grey",children:"[s: (re-)setup]"})})]})})}c(Js,"Main");const zs=c(()=>[p.yellow("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),p.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),p.yellow("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),p.yellow("\u2502 Real-time agent mode is experimental and subject to changes. \u2502"),p.yellow("\u2502 Use in production environments is not recommended. \u2502"),p.yellow("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),""].join(`
47
+ `),"createExperimentalWarning$1");function Gs(r,e){r.command("sync").description("\u26A0\uFE0F EXPERIMENTAL: Sync workspace data in real-time - This feature is experimental and subject to changes. Use in production environments is not recommended.").option("--watch","Watch for changes and sync automatically",!1).option("--rps <number>","Maximum requests per second (default: 80)",t=>parseInt(t,10)).addHelpText("after",["","Examples:"," membrane sync --watch # Start real-time sync with watch mode"," membrane sync --watch --rps 5 # Limit to 5 requests per second",""].join(`
48
+ `)).action(async t=>{if(t.watch||(console.error("Error: The sync command requires the --watch flag"),console.error("Usage: membrane sync --watch"),process.exit(1)),t.rps!==void 0){const n=t.rps;!isNaN(n)&&n>0&&n<=1e3?$.init({maxRequestsPerSecond:n}):(g.error(`Invalid RPS value: ${n}. Must be between 1 and 1000.`),process.exit(1))}console.warn(zs()),ut(he.createElement(Ft,{cwd:process.cwd(),membraneCLIService:e,children:he.createElement(Js)}))})}c(Gs,"setupSyncCommand");class Hs{static{c(this,"BaseRunner")}constructor(e={}){if(this.options=e,this.fsPaths=mt(),e&&typeof e=="object"){const t=e;"client"in t&&t.client&&(this.client=t.client),"workspace"in t&&(this.workspace=t.workspace)}}client;workspace;fsPaths}const Vs="claude-sonnet-4-20250514";class Vt{static{c(this,"TestEnvironment")}client;connectionId;testsDir;testBasePath;options;llm;state={};constructor({connectionId:e,testsDir:t,testBasePath:n,client:o,options:i,llm:s}){this.client=o,this.connectionId=e,this.testsDir=t,this.testBasePath=n,this.llm=s,this.options=i}static async create({connectionId:e,testBasePath:t,options:n}){const o=xe();if(!o)throw new Error("No configuration found. Please set MEMBRANE_WORKSPACE_KEY and MEMBRANE_WORKSPACE_SECRET environment variables, or run `membrane init` first.");if(!o.workspaceKey||!o.workspaceSecret)throw new Error("Missing workspace credentials");if(!o.anthropicApiKey)throw new Error("Anthropic API key not configured. Run `membrane init` to set up testing.");const i=new Yt({token:await this.createMembraneToken(o),apiUri:o.apiUri}),s=new ro({apiKey:o.anthropicApiKey}),a={complete:c(async({prompt:l,maxTokens:u})=>{const h=await s.messages.create({model:Vs,max_tokens:u,messages:[{role:"user",content:l}]});return h.content[0].type==="text"?h.content[0].text:""},"complete")};return new Vt({client:i,options:n,connectionId:e,testsDir:"src/testing/tests",testBasePath:t,llm:a})}async run(e){this.state={};const t={};for(const n of e)await n.run(),dt(t,n.getResult());this.writeResults(t)}async readYaml(e){const t=x.join(this.testsDir,this.testBasePath,this.connectionId,e);return $t(t)}async writeYaml(e,t){const n=x.join(this.testsDir,this.testBasePath,this.connectionId,e);O.mkdirSync(x.dirname(n),{recursive:!0}),O.writeFileSync(n,Y.dump(t,{noRefs:!0}))}writeResults(e){const t=x.join(this.testsDir,this.testBasePath,this.connectionId);O.mkdirSync(t,{recursive:!0});const n=x.join(t,"test-results.yaml");O.writeFileSync(n,Y.dump(e,{noRefs:!0})),console.debug(`[TestRunner] Results written to: ${n}`)}static async createMembraneToken(e){const t=e.testCustomerId||"test-customer",n={id:t,name:t},o={issuer:e.workspaceKey,expiresIn:7200,algorithm:"HS512"};return nt.sign(n,e.workspaceSecret,o)}}io.interpolate=/{{([\s\S]+?)}}/g;function Jt(r,e){if(typeof r=="string"){const t=oo(r),n={state:e,random:{number:c(()=>ke.number.int(),"number"),alphaNumeric:c(i=>ke.string.alphanumeric(i),"alphaNumeric")},faker:{company:{name:c(()=>ke.company.name(),"name"),catchPhrase:c(()=>ke.company.catchPhrase(),"catchPhrase")},internet:{email:c(()=>ke.internet.email(),"email")}},entries:e["journal-entries"],orders:e["purchase-orders"]||e["sales-orders"],bills:e["vendor-bills"]},o=t(n);return r.includes("{{")&&r.includes("}}")&&(console.debug(`[TEMPLATE] Input: ${r}`),console.debug(`[TEMPLATE] Output: ${o}`)),o}return Array.isArray(r)?r.map(t=>Jt(t,e)):typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).map(([t,n])=>[t,Jt(n,e)])):r}c(Jt,"processNode");function Ys(r,e){return Jt(r,e)}c(Ys,"handleTemplate");class Zs{static{c(this,"BaseTestSuite")}result;environment;constructor({environment:e}){this.environment=e,this.result={}}async run(){}getResult(){return this.result}async runTest(e){console.debug(`${p.bold.cyan("[start]")} ${p.yellow(e.path)}`);let t=!1,n=!1,o={},i={},s;for(;!t;)try{i=await e.readTestCase(),i||(i=await e.generateConfig(),await this.environment.writeYaml(e.getTestCasePath(),i),console.debug(`${p.bold.yellow("[initialized]")} ${p.yellow(e.path)}`)),s=Ys(i,this.environment.state),await e.run(s),console.debug(`${p.bold.green("[success]")} ${p.yellow(e.path)}`),t=!0,o=e.getResult(),Xe(this.result,e.path,o)}catch(l){if(console.error(`${p.bold.red("[error]")} ${p.yellow(e.path)}: ${l}`),this.environment.options.fix&&!n){n=!0;try{await e.fix(l);continue}catch(u){console.error(`${p.bold.red("[fix fail]")} ${p.yellow(e.path)}: ${u}`)}}Xe(this.result,e.path,{error:V(l)}),t=!0,o={error:V(l)}}const a={...s,result:o};await this.environment.writeYaml(e.getTestCasePath(),a)}async runTestSuite(e){await e.run(),dt(this.result,e.getResult())}}class ue{static{c(this,"BaseTester")}environment;level;logs;assertions;resultsLocator;path;constructor({environment:e,path:t}){this.environment=e,this.logs=[],this.assertions=[],this.path=t,this.level=0,this.resultsLocator=""}async fix(e){const t=await this.readTestCase();if(!t)throw new Error(`No config found for test ${this.path}`);const n=await this.fixTestCase({config:t,error:e});console.debug(p.bold.yellow("[auto-fix]"),this.path),await this.environment.writeYaml(this.getTestCasePath(),n)}async readTestCase(){const e=this.getTestCasePath();return this.environment.readYaml(e)}async generateConfig(){return{}}async fixTestCase(e){throw new Error(`Auto-fix is not implemented for test ${this.path}`)}getResult(){return{logs:this.logs,assertions:this.assertions}}async assert(e,t,n){try{const o=await e();o?(this.logMsg(`\u2705 ${t}`),this.assertions.push({message:t,result:o})):(this.logMsg(`\u274C ${t}`),this.assertions.push({message:t,result:!1,details:n}))}catch(o){this.assertions.push({message:t,result:!1,details:V(o)}),this.logMsg(`\u274C ${t}: ${o.message}`)}}logMsg(e){console.debug(`${" ".repeat(this.level*2)}${e}`)}getTestCasePath(){return`${this.path}.test.yml`}}function zt(r,e){const t={};for(const n in e){if(!(n in r)){t[n]=e[n];continue}const o=r[n],i=e[n];if(o&&i&&typeof o=="object"&&typeof i=="object"){if(Array.isArray(o)&&Array.isArray(i)){const s=i.filter(a=>!o.some(l=>{if(typeof l=="object"&&typeof a=="object"&&l!==null&&a!==null&&!Array.isArray(l)&&!Array.isArray(a)){for(const u in a)if(!(u in l)||!Gt(l[u],a[u]))return!1;return!0}else return JSON.stringify(l)===JSON.stringify(a)}));s.length>0&&(t[n]=s)}else if(!Array.isArray(o)&&!Array.isArray(i)){const s=zt(o,i);s!==null&&(t[n]=s)}else t[n]=i;continue}Gt(o,i)||(t[n]=i)}return Object.keys(t).length===0?null:t}c(zt,"getNotMatchingSubFields");function Gt(r,e){if(r==e||r?.toString?.()===e?.toString?.())return!0;const t=new Date(r),n=new Date(e);return!isNaN(t.getTime())&&!isNaN(n.getTime())?t.getTime()===n.getTime():!1}c(Gt,"softCompare");class Xs extends ue{static{c(this,"DataCollectionCreateTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/create`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).create(e.input);await this.assert(()=>!!t.id,"Returned ID of a created record"),t.id&&(this.environment.state[this.dataCollectionKey]={createdRecordId:t.id});const n=Qe(this.dataCollection);if(this.dataCollection.findById){const i=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).findById({id:t.id});await this.assert(()=>!!i.record,"Record is returned from findById"),i.record&&(this.environment.state[this.dataCollectionKey]={createdRecordId:t.id,createdRecord:i.record.fields});const s=nn(n),a=je(e.input.fields,s,{skipUnknownFields:!0}),l=je(i.record.fields,s),u=zt(l,a);await this.assert(()=>!u,"Returned fields match created fields",{difference:u,sentFields:a,receivedFields:l})}const o=kr(n??{});if(o.length>0){const i={};o.forEach(a=>{const l=xr(e.input.fields,a);typeof l<"u"&&Xe(i,a,l)});const s=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).create({fields:i});await this.assert(()=>!!s.id,"Record can be created with schema-defined required fields only")}}async generateConfig(){const e=Qe(this.dataCollection);if(!e?.properties)throw new Error("No fields schema found for data collection");return{input:{fields:await this.generateFieldsWithLLM(e)}}}async fixTestCase({config:e,error:t}){const n=V(t),o=Qe(this.dataCollection),i=await this.getExampleRecordsForSchema(o),s=`I'm trying to create a data record in a data collection with the following fields schema:
35
49
 
36
50
  ${JSON.stringify(o,null,2)}
37
51
 
@@ -55,7 +69,7 @@ Format your response as a JSON object with two fields:
55
69
  "fields": { ... fixed fields ... }
56
70
  }.
57
71
 
58
- Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,a=await this.environment.llm.complete({prompt:s,maxTokens:1e4}),l=JSON.parse(a.trim());return console.warn(m.bold.yellow("[auto-fix]"),`${this.path}:`,l.explanation),{input:{fields:l.fields}}}async generateFieldsWithLLM(e){const t=await this.getExampleRecordsForSchema(e),n=`Generate a valid JSON object that matches this JSONSchema. Return only the JSON object, no other text.
72
+ Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,a=await this.environment.llm.complete({prompt:s,maxTokens:1e4}),l=JSON.parse(a.trim());return console.warn(p.bold.yellow("[auto-fix]"),`${this.path}:`,l.explanation),{input:{fields:l.fields}}}async generateFieldsWithLLM(e){const t=await this.getExampleRecordsForSchema(e),n=`Generate a valid JSON object that matches this JSONSchema. Return only the JSON object, no other text.
59
73
 
60
74
  ${this.getExampleRecordsPrompt(t)}
61
75
 
@@ -71,7 +85,7 @@ ${JSON.stringify(o,null,2)}`).join(`
71
85
 
72
86
  `)}.
73
87
 
74
- If you don't have an example for a given collection, leave the field empty instead of coming up with a fake record id.`}async findReferenceCollections(e){const t=new Set,n=[];return Xt(e,o=>{if(o.referenceCollection){const i=o.referenceCollection.key,s=o.referenceCollection.parameters,a=`${i}:${JSON.stringify(s||{})}`;t.has(a)||(t.add(a),n.push({key:i,parameters:s}))}return o}),n}async fetchExampleRecords(e){return(await this.environment.client.connection(this.environment.connectionId).dataCollection(e.key).list({parameters:e.parameters})).records.map(n=>({id:n.id,fields:n.fields??{}}))}async getExampleRecordsForSchema(e){const t=await this.findReferenceCollections(e),n={};for(const o of t){const i=Qt(o);n[i]=await this.fetchExampleRecords(o)}return n}}class Fs extends ce{static{c(this,"DataCollectionDeleteTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/delete`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=this.environment.state[this.dataCollectionKey]?.createdRecordId||e?.input?.id;if(!t)throw new Error(`No ID found in state or config for ${this.dataCollectionKey} delete`);if(await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).delete({id:t}),this.dataCollection.findById)try{await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).findById({id:t})}catch(n){if(n?.data?.data?.response?.status===404){await this.assert(()=>!0,"Record is not found after deletion");return}throw n}else await this.assert(()=>!0,"No findById capability, skipping verification")}async generateConfig(){let e=this.environment.state[this.dataCollectionKey]?.createdRecordId;if(!e){if(!this.dataCollection.list)throw new Error(`Can't find a record to test delete operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!t?.records?.length)throw new Error(`No records found to test delete for ${this.dataCollectionKey}`);e=t.records[0].id}return{input:{id:e}}}async fixTestCase({config:e,error:t}){const n=z(t),o=`I'm trying to delete a record from a data collection.
88
+ If you don't have an example for a given collection, leave the field empty instead of coming up with a fake record id.`}async findReferenceCollections(e){const t=new Set,n=[];return rn(e,o=>{if(o.referenceCollection){const i=o.referenceCollection.key,s=o.referenceCollection.parameters,a=`${i}:${JSON.stringify(s||{})}`;t.has(a)||(t.add(a),n.push({key:i,parameters:s}))}return o}),n}async fetchExampleRecords(e){return(await this.environment.client.connection(this.environment.connectionId).dataCollection(e.key).list({parameters:e.parameters})).records.map(n=>({id:n.id,fields:n.fields??{}}))}async getExampleRecordsForSchema(e){const t=await this.findReferenceCollections(e),n={};for(const o of t){const i=on(o);n[i]=await this.fetchExampleRecords(o)}return n}}class Qs extends ue{static{c(this,"DataCollectionDeleteTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/delete`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=this.environment.state[this.dataCollectionKey]?.createdRecordId||e?.input?.id;if(!t)throw new Error(`No ID found in state or config for ${this.dataCollectionKey} delete`);if(await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).delete({id:t}),this.dataCollection.findById)try{await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).findById({id:t})}catch(n){if(n?.data?.data?.response?.status===404){await this.assert(()=>!0,"Record is not found after deletion");return}throw n}else await this.assert(()=>!0,"No findById capability, skipping verification")}async generateConfig(){let e=this.environment.state[this.dataCollectionKey]?.createdRecordId;if(!e){if(!this.dataCollection.list)throw new Error(`Can't find a record to test delete operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!t?.records?.length)throw new Error(`No records found to test delete for ${this.dataCollectionKey}`);e=t.records[0].id}return{input:{id:e}}}async fixTestCase({config:e,error:t}){const n=V(t),o=`I'm trying to delete a record from a data collection.
75
89
 
76
90
  I tried to delete a record with this ID:
77
91
 
@@ -91,7 +105,7 @@ Format your response as a JSON object with two fields:
91
105
  "id": "fixed id"
92
106
  }.
93
107
 
94
- Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,i=await this.environment.llm.complete({prompt:o,maxTokens:1e3}),s=JSON.parse(i.trim());return console.warn(m.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class Ls extends ce{static{c(this,"DataCollectionFindByIdTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/find-by-id`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=this.environment.state[this.dataCollectionKey]?.createdRecordId||e?.input?.id;if(!t)throw new Error(`No ID found in state or config for ${this.dataCollectionKey} find-by-id`);const n=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).findById({id:t});await this.assert(()=>!!n.record,"Record is returned from findById"),await this.assert(()=>n.record.id===t,"Returned record ID matches requested ID")}async generateConfig(){let e=this.environment.state[this.dataCollectionKey]?.createdRecordId;if(!e){if(!this.dataCollection.list)throw new Error(`Can't find a record to test findById operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!t?.records?.length)throw new Error(`No records found to test findById for ${this.dataCollectionKey}`);e=t.records[0].id}return{input:{id:e}}}async fixTestCase({config:e,error:t}){const n=z(t),o=`I'm trying to find a record by ID in a data collection.
108
+ Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,i=await this.environment.llm.complete({prompt:o,maxTokens:1e3}),s=JSON.parse(i.trim());return console.warn(p.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class ea extends ue{static{c(this,"DataCollectionFindByIdTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/find-by-id`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=this.environment.state[this.dataCollectionKey]?.createdRecordId||e?.input?.id;if(!t)throw new Error(`No ID found in state or config for ${this.dataCollectionKey} find-by-id`);const n=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).findById({id:t});await this.assert(()=>!!n.record,"Record is returned from findById"),await this.assert(()=>n.record.id===t,"Returned record ID matches requested ID")}async generateConfig(){let e=this.environment.state[this.dataCollectionKey]?.createdRecordId;if(!e){if(!this.dataCollection.list)throw new Error(`Can't find a record to test findById operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!t?.records?.length)throw new Error(`No records found to test findById for ${this.dataCollectionKey}`);e=t.records[0].id}return{input:{id:e}}}async fixTestCase({config:e,error:t}){const n=V(t),o=`I'm trying to find a record by ID in a data collection.
95
109
 
96
110
  I tried to find a record with this ID:
97
111
 
@@ -111,7 +125,7 @@ Format your response as a JSON object with two fields:
111
125
  "id": "fixed id"
112
126
  }.
113
127
 
114
- Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,i=await this.environment.llm.complete({prompt:o,maxTokens:1e3}),s=JSON.parse(i.trim());return console.warn(m.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class js extends ce{static{c(this,"DataCollectionListTester")}dataCollectionKey;constructor({environment:e,dataCollectionKey:t}){super({environment:e,path:`data/${t}/list`}),this.dataCollectionKey=t}async run(e){const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list(e.input);if(await this.assert(()=>Array.isArray(t.records),"Response has records field as array"),e.input.sort){const{field:n,direction:o}=e.input.sort,i=t.records;if(i.length>1)for(let s=1;s<i.length;s++){const a=i[s-1].fields?.[n],l=i[s].fields?.[n];a==null||l==null||(o==="asc"?await this.assert(()=>a<=l,`Records are sorted by ${n} in ascending order`):await this.assert(()=>a>=l,`Records are sorted by ${n} in descending order`))}}}async generateConfig(){return{input:{}}}async fixTestCase({config:e,error:t}){const n=z(t),o=`I'm trying to list records from a data collection.
128
+ Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,i=await this.environment.llm.complete({prompt:o,maxTokens:1e3}),s=JSON.parse(i.trim());return console.warn(p.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class ta extends ue{static{c(this,"DataCollectionListTester")}dataCollectionKey;constructor({environment:e,dataCollectionKey:t}){super({environment:e,path:`data/${t}/list`}),this.dataCollectionKey=t}async run(e){const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list(e.input);if(await this.assert(()=>Array.isArray(t.records),"Response has records field as array"),e.input.sort){const{field:n,direction:o}=e.input.sort,i=t.records;if(i.length>1)for(let s=1;s<i.length;s++){const a=i[s-1].fields?.[n],l=i[s].fields?.[n];a==null||l==null||(o==="asc"?await this.assert(()=>a<=l,`Records are sorted by ${n} in ascending order`):await this.assert(()=>a>=l,`Records are sorted by ${n} in descending order`))}}}async generateConfig(){return{input:{}}}async fixTestCase({config:e,error:t}){const n=V(t),o=`I'm trying to list records from a data collection.
115
129
 
116
130
  I tried to list records with these parameters:
117
131
 
@@ -131,7 +145,7 @@ Format your response as a JSON object with two fields:
131
145
  "input": { ... fixed parameters ... }
132
146
  }.
133
147
 
134
- Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,i=await this.environment.llm.complete({prompt:o,maxTokens:1e3}),s=JSON.parse(i.trim());return console.warn(m.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input}}}class Us extends ce{static{c(this,"DataCollectionMatchTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/match`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).match(e.input);await this.assert(()=>!!t.record,"Response contains a record");const n=t.record,i=(await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).findById({id:n.id})).record;for(const[s,a]of Object.entries(e.input.query)){const l=i.fields?.[s];await this.assert(()=>Wt(l,a),`Record field ${s} matches input value - expected ${JSON.stringify(a)} got ${JSON.stringify(l)}`)}}async generateConfig(){if(!this.dataCollection.list)throw new Error(`Can't find a record to test match operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const e=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!e?.records?.length)throw new Error("No records found to test match");const t=e.records[0];if(!t?.fields)throw new Error("First record has no fields to match against");const n={},o=t.fields||{},i=Object.entries(o).filter(([s,a])=>s!=="links"&&a!=null&&a!=="").slice(0,1);if(i.length===0)throw new Error("No usable fields found in record for matching");for(const[s,a]of i)n[s]=a;return{input:{query:n}}}async fixTestCase({config:e,error:t}){const n=z(t),o=`I'm trying to match a record in a data collection.
148
+ Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,i=await this.environment.llm.complete({prompt:o,maxTokens:1e3}),s=JSON.parse(i.trim());return console.warn(p.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input}}}class na extends ue{static{c(this,"DataCollectionMatchTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/match`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).match(e.input);await this.assert(()=>!!t.record,"Response contains a record");const n=t.record,i=(await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).findById({id:n.id})).record;for(const[s,a]of Object.entries(e.input.query)){const l=i.fields?.[s];await this.assert(()=>Gt(l,a),`Record field ${s} matches input value - expected ${JSON.stringify(a)} got ${JSON.stringify(l)}`)}}async generateConfig(){if(!this.dataCollection.list)throw new Error(`Can't find a record to test match operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const e=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!e?.records?.length)throw new Error("No records found to test match");const t=e.records[0];if(!t?.fields)throw new Error("First record has no fields to match against");const n={},o=t.fields||{},i=Object.entries(o).filter(([s,a])=>s!=="links"&&a!=null&&a!=="").slice(0,1);if(i.length===0)throw new Error("No usable fields found in record for matching");for(const[s,a]of i)n[s]=a;return{input:{query:n}}}async fixTestCase({config:e,error:t}){const n=V(t),o=`I'm trying to match a record in a data collection.
135
149
 
136
150
  I tried to match a record with this query:
137
151
 
@@ -151,12 +165,12 @@ Format your response as a JSON object with two fields:
151
165
  "query": { ... fixed query ... }
152
166
  }.
153
167
 
154
- Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,i=await this.environment.llm.complete({prompt:o,maxTokens:1e3}),s=JSON.parse(i.trim());return console.warn(m.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{query:s.query}}}}class Ks extends ce{static{c(this,"DataCollectionSearchTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/search`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).search(e.input);await this.assert(()=>Array.isArray(t.records),"Response has records field as array");const n=t.records.some(o=>o.id===e.expectedRecordId);n||console.debug(m.yellow(`Search query "${e.input.query}" did not return expected record`)),await this.assert(()=>n,"Search returns expected record")}async generateConfig(){if(!this.dataCollection.list)throw new Error(`Can't find a record to test search operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const e=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!e.records.length)throw new Error("No records found to test search");const t=e.records[0],n=await this.getSearchQueryWithLLM(t.fields||{});if(!n)throw new Error("Unable to generate search query. LLM could not identify a suitable field value from the record to use as the search query.");return{input:{query:n},expectedRecordId:t.id}}async getSearchQueryWithLLM(e){const t=`You are given the fields of a record from a data collection. Identify the BEST single field value that a user is MOST likely to type when searching for this record (e.g. name, title, email, external id). Ignore null, empty strings, technical IDs, HTML, and timestamps unless they are obviously human-searchable. Make sure the field value is as unique as possible for this record. RETURN ONLY the field value as a plain string. No additional text, no JSON, no quotes.
168
+ Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,i=await this.environment.llm.complete({prompt:o,maxTokens:1e3}),s=JSON.parse(i.trim());return console.warn(p.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{query:s.query}}}}class ra extends ue{static{c(this,"DataCollectionSearchTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/search`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).search(e.input);await this.assert(()=>Array.isArray(t.records),"Response has records field as array");const n=t.records.some(o=>o.id===e.expectedRecordId);n||console.debug(p.yellow(`Search query "${e.input.query}" did not return expected record`)),await this.assert(()=>n,"Search returns expected record")}async generateConfig(){if(!this.dataCollection.list)throw new Error(`Can't find a record to test search operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const e=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!e.records.length)throw new Error("No records found to test search");const t=e.records[0],n=await this.getSearchQueryWithLLM(t.fields||{});if(!n)throw new Error("Unable to generate search query. LLM could not identify a suitable field value from the record to use as the search query.");return{input:{query:n},expectedRecordId:t.id}}async getSearchQueryWithLLM(e){const t=`You are given the fields of a record from a data collection. Identify the BEST single field value that a user is MOST likely to type when searching for this record (e.g. name, title, email, external id). Ignore null, empty strings, technical IDs, HTML, and timestamps unless they are obviously human-searchable. Make sure the field value is as unique as possible for this record. RETURN ONLY the field value as a plain string. No additional text, no JSON, no quotes.
155
169
 
156
170
  Record fields:
157
171
  ${JSON.stringify(e,null,2)}
158
172
 
159
- Field value:`;try{return(await this.environment.llm.complete({prompt:t,maxTokens:1e3})).trim()||null}catch{return null}}async fixTestCase({config:e,error:t}){const n=z(t),o=`I'm trying to search records in a data collection.
173
+ Field value:`;try{return(await this.environment.llm.complete({prompt:t,maxTokens:1e3})).trim()||null}catch{return null}}async fixTestCase({config:e,error:t}){const n=V(t),o=`I'm trying to search records in a data collection.
160
174
 
161
175
  I tried to search records with these parameters:
162
176
 
@@ -176,7 +190,7 @@ Format your response as a JSON object with two fields:
176
190
  "input": { ... fixed parameters ... }
177
191
  }.
178
192
 
179
- Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,i=await this.environment.llm.complete({prompt:o,maxTokens:1e3}),s=JSON.parse(i.trim());return console.warn(m.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input,expectedRecordId:e.expectedRecordId}}}class _s extends ce{static{c(this,"DataCollectionSpecTester")}dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/spec`}),this.dataCollection=n}async run(){const e=Object.keys(this.dataCollection.fieldsSchema||{}).length;await this.assert(()=>e>0,"Fields schema has field definitions")}}class qs extends ce{static{c(this,"DataCollectionUpdateTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/update`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=this.environment.state[this.dataCollectionKey]?.createdRecordId||e?.input?.id;if(!t)throw new Error(`No ID found in state or config for ${this.dataCollectionKey} update`);const n=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).update({...e.input,id:t});if(await this.assert(()=>!!n.id,"Returned ID of updated record"),this.environment.state[this.dataCollectionKey]||(this.environment.state[this.dataCollectionKey]={}),this.environment.state[this.dataCollectionKey].createdRecordId=n.id,this.dataCollection.findById){const o=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).findById({id:n.id});await this.assert(()=>!!o.record,"Record is returned from findById");const i=et(this.dataCollection),s=Zt(i),a=Ne(e.input.fields,s,{skipUnknownFields:!0}),l=Ne(o.record.fields,s),d=Bt(l,a);await this.assert(()=>!d,"Returned fields match updated fields",{difference:d,sentFields:a,receivedFields:l})}}async generateConfig(){let e=this.environment.state[this.dataCollectionKey]?.createdRecordId;if(!e){if(!this.dataCollection.list)throw new Error(`Can't find a record to test update operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const o=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!o?.records?.length)throw new Error(`No records found to test update for ${this.dataCollectionKey}`);e=o.records[0].id}const t=et(this.dataCollection);if(!t?.properties)throw new Error("No fields schema found for data collection");const n=await this.generateFieldsWithLLM(t);return{input:{id:e,fields:n}}}async fixTestCase({config:e,error:t}){const n=z(t),o=et(this.dataCollection),i=await this.getExampleRecordsForSchema(o),s=`I'm trying to update a data record in a data collection with the following fields schema:
193
+ Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,i=await this.environment.llm.complete({prompt:o,maxTokens:1e3}),s=JSON.parse(i.trim());return console.warn(p.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input,expectedRecordId:e.expectedRecordId}}}class oa extends ue{static{c(this,"DataCollectionSpecTester")}dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/spec`}),this.dataCollection=n}async run(){const e=Object.keys(this.dataCollection.fieldsSchema||{}).length;await this.assert(()=>e>0,"Fields schema has field definitions")}}class ia extends ue{static{c(this,"DataCollectionUpdateTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/update`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=this.environment.state[this.dataCollectionKey]?.createdRecordId||e?.input?.id;if(!t)throw new Error(`No ID found in state or config for ${this.dataCollectionKey} update`);const n=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).update({...e.input,id:t});if(await this.assert(()=>!!n.id,"Returned ID of updated record"),this.environment.state[this.dataCollectionKey]||(this.environment.state[this.dataCollectionKey]={}),this.environment.state[this.dataCollectionKey].createdRecordId=n.id,this.dataCollection.findById){const o=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).findById({id:n.id});await this.assert(()=>!!o.record,"Record is returned from findById");const i=et(this.dataCollection),s=nn(i),a=je(e.input.fields,s,{skipUnknownFields:!0}),l=je(o.record.fields,s),u=zt(l,a);await this.assert(()=>!u,"Returned fields match updated fields",{difference:u,sentFields:a,receivedFields:l})}}async generateConfig(){let e=this.environment.state[this.dataCollectionKey]?.createdRecordId;if(!e){if(!this.dataCollection.list)throw new Error(`Can't find a record to test update operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const o=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!o?.records?.length)throw new Error(`No records found to test update for ${this.dataCollectionKey}`);e=o.records[0].id}const t=et(this.dataCollection);if(!t?.properties)throw new Error("No fields schema found for data collection");const n=await this.generateFieldsWithLLM(t);return{input:{id:e,fields:n}}}async fixTestCase({config:e,error:t}){const n=V(t),o=et(this.dataCollection),i=await this.getExampleRecordsForSchema(o),s=`I'm trying to update a data record in a data collection with the following fields schema:
180
194
 
181
195
  ${JSON.stringify(o,null,2)}
182
196
 
@@ -200,7 +214,7 @@ Format your response as a JSON object with two fields:
200
214
  "fields": { ... fixed fields ... }
201
215
  }.
202
216
 
203
- Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,a=await this.environment.llm.complete({prompt:s,maxTokens:1e4}),l=JSON.parse(a.trim());return console.warn(m.bold.yellow("[auto-fix]"),`${this.path}:`,l.explanation),{input:{id:e.input.id,fields:l.fields}}}async generateFieldsWithLLM(e){const t=await this.getExampleRecordsForSchema(e),n=`Generate a valid JSON object that matches this JSONSchema. Return only the JSON object, no other text.
217
+ Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,a=await this.environment.llm.complete({prompt:s,maxTokens:1e4}),l=JSON.parse(a.trim());return console.warn(p.bold.yellow("[auto-fix]"),`${this.path}:`,l.explanation),{input:{id:e.input.id,fields:l.fields}}}async generateFieldsWithLLM(e){const t=await this.getExampleRecordsForSchema(e),n=`Generate a valid JSON object that matches this JSONSchema. Return only the JSON object, no other text.
204
218
 
205
219
  ${this.getExampleRecordsPrompt(t)}
206
220
 
@@ -216,9 +230,9 @@ ${JSON.stringify(o,null,2)}`).join(`
216
230
 
217
231
  `)}.
218
232
 
219
- If you don't have an example for a given collection, leave the field empty instead of coming up with a fake record id.`}async findReferenceCollections(e){const t=new Set,n=[];return Xt(e,o=>{if(o.referenceCollection){const i=o.referenceCollection.key,s=o.referenceCollection.parameters,a=`${i}:${JSON.stringify(s||{})}`;t.has(a)||(t.add(a),n.push({key:i,parameters:s}))}return o}),n}async fetchExampleRecords(e){return(await this.environment.client.connection(this.environment.connectionId).dataCollection(e.key).list({parameters:e.parameters})).records.map(n=>({id:n.id,fields:n.fields||{}}))}async getExampleRecordsForSchema(e){const t=await this.findReferenceCollections(e),n={};for(const o of t){const i=Qt(o);n[i]=await this.fetchExampleRecords(o)}return n}}const Jt={spec:{testerClass:_s},create:{testerClass:Ms,operationKey:"create"},"find-by-id":{testerClass:Ls,operationKey:"findById"},list:{testerClass:js,operationKey:"list"},match:{testerClass:Us,operationKey:"match"},search:{testerClass:Ks,operationKey:"search"},update:{testerClass:qs,operationKey:"update"},delete:{testerClass:Fs,operationKey:"delete"}};class Bs extends Ns{static{c(this,"DataCollectionTestSuite")}dataCollectionKey;testMethod;constructor({environment:e,dataCollectionKey:t,testMethod:n}){super({environment:e}),this.dataCollectionKey=t,this.testMethod=n}async run(){const e=await this.fetchDataCollection(),t=this.testMethod?[this.createTester(this.testMethod,e)]:this.createAllAvailableTesters(e);T.info("\u{1F680} Running tests...");for(const n of t)await this.runTest(n);this.displayTestSummary(t.length)}async fetchDataCollection(){return this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).get()}isOperationAvailable(e,t){return t?!!e[t]:!0}createTester(e,t){const n=Jt[e];if(!n)throw new Error(`Unknown test method "${e}". Available: ${this.getAvailableTestMethods(t).join(", ")}`);const o="operationKey"in n?n.operationKey:void 0;if(!this.isOperationAvailable(t,o))throw new Error(`${o} operation not available for data collection "${this.dataCollectionKey}"`);return this.instantiateTester(n,t)}createAllAvailableTesters(e){return Object.entries(Jt).filter(([,t])=>{const n="operationKey"in t?t.operationKey:void 0;return this.isOperationAvailable(e,n)}).map(([,t])=>this.instantiateTester(t,e))}instantiateTester(e,t){const n={environment:this.environment,dataCollectionKey:this.dataCollectionKey,dataCollection:t};return new e.testerClass(n)}getAvailableTestMethods(e){return Object.entries(Jt).filter(([,t])=>{const n="operationKey"in t?t.operationKey:void 0;return this.isOperationAvailable(e,n)}).map(([t])=>t)}displayTestSummary(e){T.info(`\u{1F4CA} ${e} test${e===1?"":"s"} executed`)}}class Ws extends Rs{static{c(this,"TestRunner")}constructor(e){super(e)}async initialize(){T.debug("Initializing test runner",{prefix:"TestRunner"})}async run(){try{const{testPath:e,path:t,fix:n}=this.options,o=e.split("/");o.length<2&&(T.error("Invalid test path. Expected format: <type>/<name>[/additional/path][/method]"),process.exit(1));const[i,s,...a]=o;i!=="connectors"&&(T.error(`Test type "${i}" is not yet fully implemented. Currently only "connectors" is fully supported.`),T.error("Supported test types: connectors"),process.exit(1));const l=s,d=i,h=[...a,...t?t.split("/"):[]].join("/"),f=await zt.create({connectionId:l,testBasePath:d,options:{fix:n}}),C=await f.client.get(`connections/${l}/data`),E=[],S=h?h.split("/"):[];if(S.length===0||S[0]==="data"){S[0]==="data"&&S.shift();let O,U;S.length>=1&&(U=S[0],S.length>=2&&S[1].trim()!==""&&(O=S[1]));for(const L of C){if(U&&U!==L.key)continue;const M=new Bs({environment:f,dataCollectionKey:L.key,testMethod:O});E.push(M)}}E.length===0&&(T.error(`No test suites found for path: ${e}${h?"/"+h:""}`),process.exit(1));const R={};for(const O of E){await O.run();const U=O.getResult();T.debug(`Suite ${O.constructor.name} result:`,{prefix:"TestRunner"}),dt(R,U)}console.debug("[TestRunner] All results collected:",Object.keys(R)),f.writeResults(R)}catch(e){throw console.error("Error in TestRunner.run():",e),e}}}const He=c(()=>[m.yellow("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),m.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),m.yellow("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),m.yellow("\u2502 The test command is experimental and subject to rapid changes. \u2502"),m.yellow("\u2502 Features, APIs, and file structures may change without notice. \u2502"),m.yellow("\u2502 Use in production environments is not recommended. \u2502"),m.yellow("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),""].join(`
220
- `),"createExperimentalWarning");function Js(r){r.command("test").description("\u26A0\uFE0F EXPERIMENTAL: Test management commands - This feature is experimental and will be changing rapidly. Use at your own risk.").addHelpText("after",He()).action(async()=>{console.warn(He()),T.error("Please specify a subcommand. Use --help for available options."),process.exit(1)}).command("run").description("Run integration tests for various membrane components").argument("<testPath>",'Test path (e.g., "connectors/netsuite", "actions/create-contact", "connectors/hubspot/data/contacts", "connectors/netsuite/data/contacts/create")').option("-p, --path <path>","Additional path filter within the test scope").option("--fix","Enable auto-fix for test issues").addHelpText("after",["",m.bold("Examples:"),` ${m.gray("\u25B8")} ${m.cyan("membrane test run connectors/netsuite")} # Test all data collections for netsuite connector`,` ${m.gray("\u25B8")} ${m.cyan("membrane test run connectors/netsuite/data/contacts")} # Test specific data collection`,` ${m.gray("\u25B8")} ${m.cyan("membrane test run connectors/netsuite/data/contacts/create")} # Test specific method for data collection`,` ${m.gray("\u25B8")} ${m.cyan("membrane test run connectors/netsuite/data/contacts/delete")} # Test delete method for data collection`,` ${m.gray("\u25B8")} ${m.cyan("membrane test run actions/create-contact")} # Test specific action`,` ${m.gray("\u25B8")} ${m.cyan("membrane test run connectors/hubspot/events")} # Test events for hubspot`,` ${m.gray("\u25B8")} ${m.cyan("membrane test run connectors/salesforce --fix")} # Run tests with auto-fix enabled`,"",m.gray("For more information, visit:"),m.blue(" https://docs.getmembrane.com/docs/development-environment"),"",He()].join(`
221
- `)).action(async(t,n)=>{try{console.warn(He()),t||(T.error("Test path is required"),process.exit(1)),T.header(`Testing: ${t}`);const o=new Ws({testPath:t,path:n.path,fix:n.fix});await o.initialize(),await o.run(),T.success("Tests completed")}catch(o){o instanceof Error&&(T.error(o.message),process.exit(1)),T.error("An unknown error occurred"),process.exit(1)}})}c(Js,"setupTestCommand");const zs=c(()=>{try{const r=cr(import.meta.url),e=sr(r),t=Ge(e,"..","package.json");return JSON.parse(ir(t,"utf-8")).version}catch{return"1.0.0"}},"getPackageVersion"),er=zs();function Hs(){process.on("SIGINT",()=>process.exit(130));const r=new lr().name("membrane").description("Command-line interface for Membrane Agent").version(er,"-v, --version","Output the version number").option("--verbose","Enable verbose logging (shows debug messages)");r.configureHelp({sortSubcommands:!0,subcommandTerm:c(n=>m.cyan(n.name()),"subcommandTerm"),commandUsage:c(n=>n.name()==="membrane"?`${m.cyan(n.name())} ${m.gray("[options]")} ${m.cyan("[command]")}`:n.usage(),"commandUsage"),optionTerm:c(n=>{const o=n.flags;return`${m.gray("\u25B8")} ${m.cyan(o)}`},"optionTerm"),subcommandDescription:c(n=>m.gray(n.description()),"subcommandDescription"),optionDescription:c(n=>m.gray(n.description),"optionDescription"),commandDescription:c(n=>m.gray(n.description()),"commandDescription")}),r.addHelpText("beforeAll",`
222
- ${m.bold.cyan("Membrane Agent CLI")} ${m.gray(`v${er}`)}
233
+ If you don't have an example for a given collection, leave the field empty instead of coming up with a fake record id.`}async findReferenceCollections(e){const t=new Set,n=[];return rn(e,o=>{if(o.referenceCollection){const i=o.referenceCollection.key,s=o.referenceCollection.parameters,a=`${i}:${JSON.stringify(s||{})}`;t.has(a)||(t.add(a),n.push({key:i,parameters:s}))}return o}),n}async fetchExampleRecords(e){return(await this.environment.client.connection(this.environment.connectionId).dataCollection(e.key).list({parameters:e.parameters})).records.map(n=>({id:n.id,fields:n.fields||{}}))}async getExampleRecordsForSchema(e){const t=await this.findReferenceCollections(e),n={};for(const o of t){const i=on(o);n[i]=await this.fetchExampleRecords(o)}return n}}const Ht={spec:{testerClass:oa},create:{testerClass:Xs,operationKey:"create"},"find-by-id":{testerClass:ea,operationKey:"findById"},list:{testerClass:ta,operationKey:"list"},match:{testerClass:na,operationKey:"match"},search:{testerClass:ra,operationKey:"search"},update:{testerClass:ia,operationKey:"update"},delete:{testerClass:Qs,operationKey:"delete"}};class sa extends Zs{static{c(this,"DataCollectionTestSuite")}dataCollectionKey;testMethod;constructor({environment:e,dataCollectionKey:t,testMethod:n}){super({environment:e}),this.dataCollectionKey=t,this.testMethod=n}async run(){const e=await this.fetchDataCollection(),t=this.testMethod?[this.createTester(this.testMethod,e)]:this.createAllAvailableTesters(e);b.info("\u{1F680} Running tests...");for(const n of t)await this.runTest(n);this.displayTestSummary(t.length)}async fetchDataCollection(){return this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).get()}isOperationAvailable(e,t){return t?!!e[t]:!0}createTester(e,t){const n=Ht[e];if(!n)throw new Error(`Unknown test method "${e}". Available: ${this.getAvailableTestMethods(t).join(", ")}`);const o="operationKey"in n?n.operationKey:void 0;if(!this.isOperationAvailable(t,o))throw new Error(`${o} operation not available for data collection "${this.dataCollectionKey}"`);return this.instantiateTester(n,t)}createAllAvailableTesters(e){return Object.entries(Ht).filter(([,t])=>{const n="operationKey"in t?t.operationKey:void 0;return this.isOperationAvailable(e,n)}).map(([,t])=>this.instantiateTester(t,e))}instantiateTester(e,t){const n={environment:this.environment,dataCollectionKey:this.dataCollectionKey,dataCollection:t};return new e.testerClass(n)}getAvailableTestMethods(e){return Object.entries(Ht).filter(([,t])=>{const n="operationKey"in t?t.operationKey:void 0;return this.isOperationAvailable(e,n)}).map(([t])=>t)}displayTestSummary(e){b.info(`\u{1F4CA} ${e} test${e===1?"":"s"} executed`)}}class aa extends Hs{static{c(this,"TestRunner")}constructor(e){super(e)}async initialize(){b.debug("Initializing test runner",{prefix:"TestRunner"})}async run(){try{const{testPath:e,path:t,fix:n}=this.options,o=e.split("/");o.length<2&&(b.error("Invalid test path. Expected format: <type>/<name>[/additional/path][/method]"),process.exit(1));const[i,s,...a]=o;i!=="connectors"&&(b.error(`Test type "${i}" is not yet fully implemented. Currently only "connectors" is fully supported.`),b.error("Supported test types: connectors"),process.exit(1));const l=s,u=i,h=[...a,...t?t.split("/"):[]].join("/"),m=await Vt.create({connectionId:l,testBasePath:u,options:{fix:n}}),C=await m.client.get(`connections/${l}/data`),E=[],S=h?h.split("/"):[];if(S.length===0||S[0]==="data"){S[0]==="data"&&S.shift();let P,K;S.length>=1&&(K=S[0],S.length>=2&&S[1].trim()!==""&&(P=S[1]));for(const _ of C){if(K&&K!==_.key)continue;const j=new sa({environment:m,dataCollectionKey:_.key,testMethod:P});E.push(j)}}E.length===0&&(b.error(`No test suites found for path: ${e}${h?"/"+h:""}`),process.exit(1));const N={};for(const P of E){await P.run();const K=P.getResult();b.debug(`Suite ${P.constructor.name} result:`,{prefix:"TestRunner"}),dt(N,K)}console.debug("[TestRunner] All results collected:",Object.keys(N)),m.writeResults(N)}catch(e){throw console.error("Error in TestRunner.run():",e),e}}}const He=c(()=>[p.yellow("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"),p.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),p.yellow("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"),p.yellow("\u2502 The test command is experimental and subject to rapid changes. \u2502"),p.yellow("\u2502 Features, APIs, and file structures may change without notice. \u2502"),p.yellow("\u2502 Use in production environments is not recommended. \u2502"),p.yellow("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"),""].join(`
234
+ `),"createExperimentalWarning");function ca(r){r.command("test").description("\u26A0\uFE0F EXPERIMENTAL: Test management commands - This feature is experimental and will be changing rapidly. Use at your own risk.").addHelpText("after",He()).action(async()=>{console.warn(He()),b.error("Please specify a subcommand. Use --help for available options."),process.exit(1)}).command("run").description("Run integration tests for various membrane components").argument("<testPath>",'Test path (e.g., "connectors/netsuite", "actions/create-contact", "connectors/hubspot/data/contacts", "connectors/netsuite/data/contacts/create")').option("-p, --path <path>","Additional path filter within the test scope").option("--fix","Enable auto-fix for test issues").addHelpText("after",["",p.bold("Examples:"),` ${p.gray("\u25B8")} ${p.cyan("membrane test run connectors/netsuite")} # Test all data collections for netsuite connector`,` ${p.gray("\u25B8")} ${p.cyan("membrane test run connectors/netsuite/data/contacts")} # Test specific data collection`,` ${p.gray("\u25B8")} ${p.cyan("membrane test run connectors/netsuite/data/contacts/create")} # Test specific method for data collection`,` ${p.gray("\u25B8")} ${p.cyan("membrane test run connectors/netsuite/data/contacts/delete")} # Test delete method for data collection`,` ${p.gray("\u25B8")} ${p.cyan("membrane test run actions/create-contact")} # Test specific action`,` ${p.gray("\u25B8")} ${p.cyan("membrane test run connectors/hubspot/events")} # Test events for hubspot`,` ${p.gray("\u25B8")} ${p.cyan("membrane test run connectors/salesforce --fix")} # Run tests with auto-fix enabled`,"",p.gray("For more information, visit:"),p.blue(" https://docs.getmembrane.com/docs/development-environment"),"",He()].join(`
235
+ `)).action(async(t,n)=>{try{console.warn(He()),t||(b.error("Test path is required"),process.exit(1)),b.header(`Testing: ${t}`);const o=new aa({testPath:t,path:n.path,fix:n.fix});await o.initialize(),await o.run(),b.success("Tests completed")}catch(o){o instanceof Error&&(b.error(o.message),process.exit(1)),b.error("An unknown error occurred"),process.exit(1)}})}c(ca,"setupTestCommand");const la=c(()=>{try{const r=yr(import.meta.url),e=mr(r),t=Ve(e,"..","package.json");return JSON.parse(fr(t,"utf-8")).version}catch{return"1.0.0"}},"getPackageVersion"),ur=la();function ua(){process.on("SIGINT",()=>process.exit(130));const r=new wr().name("membrane").description("Command-line interface for Membrane Agent").version(ur,"-v, --version","Output the version number").option("--verbose","Enable verbose logging (shows debug messages)");r.configureHelp({sortSubcommands:!0,subcommandTerm:c(t=>p.cyan(t.name()),"subcommandTerm"),commandUsage:c(t=>t.name()==="membrane"?`${p.cyan(t.name())} ${p.gray("[options]")} ${p.cyan("[command]")}`:t.usage(),"commandUsage"),optionTerm:c(t=>{const n=t.flags;return`${p.gray("\u25B8")} ${p.cyan(n)}`},"optionTerm"),subcommandDescription:c(t=>p.gray(t.description()),"subcommandDescription"),optionDescription:c(t=>p.gray(t.description),"optionDescription"),commandDescription:c(t=>p.gray(t.description()),"commandDescription")}),r.addHelpText("beforeAll",`
236
+ ${p.bold.cyan("Membrane Agent CLI")} ${p.gray(`v${ur}`)}
223
237
 
224
- `);const e=new ni(Je.Cli,process.cwd());vo(r),Ii(r),Ni(r),yi(r),ps(r),qi(r),ns(r),_i(r),Js(r),Ki(r),As(r,e),xi(r,e),Ao(r,e),hi(r,e),r.hook("preAction",(n,o)=>{const i=o.opts().apiUri||Se()||ne;i!==ne&&console.error(`Using apiUri: ${i}`)}),process.argv.length===2&&(r.outputHelp(),process.exit(0)),r.parse(),r.opts().verbose&&g.setVerboseMode(!0)}c(Hs,"runCLI"),Hs();
238
+ `);const e=new yi(ze.Cli,process.cwd());No(r),_i(r),Vi(r),Oi(r),Li(r),Mi(r),Mo(r),$s(r),Fo(r),Ps(r),rs(r),ys(r),ns(r),ca(r),ts(r),Gs(r,e),Ki(r,e),Jo(r,e),xi(r,e),r.hook("preAction",(t,n)=>{r.opts().verbose&&g.setVerboseMode(!0);const o=n.opts().apiUri||me()||te;o!==te&&console.error(`Using apiUri: ${o}`)}),process.argv.length===2&&(r.outputHelp(),process.exit(0)),r.parse()}c(ua,"runCLI"),ua();