@membranehq/cli 1.8.1 → 1.8.3

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 +50 -50
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -1,54 +1,54 @@
1
1
  #!/usr/bin/env node
2
- var mr=Object.defineProperty;var c=(r,e)=>mr(r,"name",{value:e,configurable:!0});import*as T from"node:fs";import{mkdirSync as gr,writeFileSync as yr,readFileSync as wr}from"node:fs";import*as I from"node:path";import{join as Ve,dirname as Cr}from"node:path";import{URL as Sr,fileURLToPath as br}from"node:url";import f from"chalk";import{Command as vr}from"commander";import{NotFoundError as Tr,MembraneConfigLoader as Er,MembraneAxiosInstance as Ir,MembraneClient as Zt,extractMembraneErrorData as V,parseMembraneElementPath as de,getConnectorSpecPath as kr,getConnectorVersionPath as Xt,CONNECTOR_VERSION_DEVELOPMENT as Ye,WorkspaceElementType as k,getMembraneElementPath as xr,compareWorkspaceExports as Qt,AgentName as en,WorkspaceElementSpecs as Q,WorkspaceSyncEventType as $r,ConnectorFileUpdateType as Ze,CONSOLE_ACCOUNT_API_TOKEN_PATH as Pr,OAUTH_SCOPE_TENANT as tn,OAUTH_SCOPE_PLATFORM_USER as nn,MEMBRANE_CLI_CLIENT_ID as Me,WorkspaceElementChangeType as ee,HttpRequestMethod as Ar,setValueAtLocator as Xe,getDataCollectionCreateFields as Qe,excludeWriteOnlyFieldsFromSchema as rn,valueToSchema as je,getRequiredFieldsFromSchema as Or,getValueAtLocator as Rr,walkSchema as on,makeDataLocationPath as sn,getDataCollectionUpdateFields as et}from"@membranehq/sdk";import Ce from"ora";import Ie,{isAxiosError as Nr}from"axios";import an from"form-data";import O,{existsSync as Fe,mkdirSync as cn,statSync as Dr,chmodSync as Lr,readFileSync as ln,writeFileSync as Mr}from"fs";import tt from"os";import x from"path";import jr from"conf";import nt from"jsonwebtoken";import rt from"semver";import{AsyncLocalStorage as Fr}from"async_hooks";import ot from"archiver";import Y from"js-yaml";import un from"jszip";import{minimatch as Ur}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 he,{createContext as at,useContext as ct,useId as qr,useRef as lt,useState as L,useLayoutEffect as Ue,useEffect as Se,useMemo as Br}from"react";import{Box as w,Text as C,useInput as pe,render as ut,Newline as Wr}from"ink";import{jsxs as v,Fragment as Ke,jsx as d}from"react/jsx-runtime";import"node:events";import dn from"ink-text-input";import{SWRConfig as Jr}from"swr";import hn from"swr/immutable";import{toSentenceCase as zr}from"js-convert-case";import Gr from"lodash/isEqual.js";import*as Hr from"node:crypto";import{createHash as Vr}from"node:crypto";import Yr from"chokidar";import Zr from"yaml";import{EventEmitter as Xr}from"events";import{EventSource as Qr}from"eventsource";import _e from"unzipper";import*as eo from"node:os";import{randomUUID as to,randomBytes as pn,createHash as no}from"crypto";import{createServer as fn}from"http";import qe from"ink-spinner";import{TextInput as ro,Select as oo,Spinner as io}from"@inkjs/ui";import{FastMCP as so}from"fastmcp";import{z as D}from"zod";import{exec as ao}from"node:child_process";import dt from"lodash/merge.js";import co from"@anthropic-ai/sdk";import{faker as ke}from"@faker-js/faker";import lo from"lodash/template.js";import uo from"lodash/templateSettings.js";const ho="membrane",po=["**/node_modules/**","**/.git/**","**/.DS_Store","**/Thumbs.db","**/*.tmp","**/*.swp","**/*.swo","**/*.log","**/*.lock","**/.cache/**","**/.next/**","**/.vscode/**","**/.idea/**","**/.logs/**"];function W(r){return I.join(r,ho)}c(W,"getMembraneDir");const mn=Ve(W(process.cwd()),".logs");class fo{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`;gr(mn,{recursive:!0});const i=Ve(mn,o),s=this._logs.map(a=>`[${a.timestamp}] ${a.type?.toUpperCase()||"INFO"}: ${a.message}`).join(`
3
- `);return yr(i,s,"utf-8"),i}catch(t){return console.error("Failed to save logs:",t),null}}}const g=new fo;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(y=>setTimeout(y,a));let p;try{p=await r.get(`background-jobs/${i}`),h=0}catch(y){if(y instanceof Tr&&h<u){h++,g.debug(`[background-job] Job ${n} not found, retrying (${h}/${u})`);continue}throw y}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 y=p.error?.message||"Unknown error";throw g.error(`[background-job] Failed job ${n}: ${y}`),p.error?.stack&&g.error(`Stacktrace: ${p.error.stack}`),new Error(`Background job ${n} failed: ${y}`)}g.debug(`[background-job] Polling job ${n} (status: ${p.status})`)}}c(ht,"pollBackgroundJob");class pt extends Error{static{c(this,"ApiError")}statusCode;errorType;errorKey;data;constructor(e,t){const n=mo(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 mo(r){try{const e=JSON.parse(r);return typeof e=="object"&&e!==null?e:null}catch{return null}}c(mo,"tryParseJson");class Ee{static{c(this,"ConfigLoader")}static instance=null;sdkLoader;constructor(){this.sdkLoader=new Er}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 go="membrane",yo="membrane.config.yml",te="https://api.getmembrane.com",wo="https://console.getmembrane.com";function ft(r){const t=xe()?.consoleUri||wo;return r?new Sr(r,t).toString():t}c(ft,"getConsoleUrl");function mt(){const r=process.cwd(),e=I.join(r,go),t=I.join(r,yo),n=e,o=I.join(n,"workspace.yaml");return{membraneDirPath:e,configPath:t,payloadDirPath:n,workspaceDataFilePath:o}}c(mt,"getPaths");function gn(){return mt().membraneDirPath}c(gn,"getBasePath");const Be=x.join(tt.homedir(),".membrane");Fe(Be)?(Dr(Be).mode&511)!==448&&Lr(Be,448):cn(Be,{mode:448});const Co={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 jr({schema:Co,configName:"credentials",cwd:x.join(tt.homedir(),".membrane"),configFileMode:384}),So=c(r=>{M.set("pat",r)},"setPat"),yn=c(()=>M.get("pat"),"getPat"),bo=c(()=>{M.delete("pat")},"clearPat"),wn=c((r,e,t)=>{M.set({accessToken:r,refreshToken:e}),t!=null?M.set("expiresAt",Date.now()+t*1e3):M.delete("expiresAt")},"setTokens"),vo=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"),To=c(()=>{M.delete("accessToken"),M.delete("refreshToken"),M.delete("expiresAt"),M.delete("apiUri"),M.delete("tokenScope"),$e()},"clearTokens"),me=c(()=>M.get("apiUri"),"getApiUri"),Cn=c(r=>{M.set("apiUri",r)},"setApiUri"),Eo=c(r=>{M.set("tokenScope",r)},"setTokenScope"),yt=c(()=>M.get("tokenScope"),"getTokenScope"),Io=c(r=>{M.set({pendingLoginScope:r.scope,pendingLoginCodeVerifier:r.codeVerifier,pendingLoginClientId:r.clientId,pendingLoginCreatedAt:Date.now()})},"setPendingLogin"),ko=600*1e3,xo=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>ko){$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 Pe{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 wn(n.access_token,o,n.expires_in),n.access_token}async getAuthToken(){const e=vo();if(e&&!gt())return e;if(be())return this.refreshPromise??=this.refreshAccessToken().finally(()=>{this.refreshPromise=null});const t=yn();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 $o=c(r=>{const e=new Pe(r);return t=>e.get(t)},"createAccountApiFetcher"),Sn=new Fr;class bn{static{c(this,"RequestLogger")}constructor(e=Ir){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=Sn.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 Sn.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 Ao{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 bn,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(V(s),null,2))):Nr(s)?(console.error(`
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():bn.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 Zt({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 Ao;async function vn(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(vn,"getWorkspaceId");const Tn=1e3,En=12e4;async function In(){const r=await $.withClient(async t=>ht(t,()=>t.get("export"),{pollIntervalMs:Tn,timeoutMs:En}));if(!r)throw new Error("Failed to export workspace");const e=await Ie.get(r.downloadUrl,{responseType:"arraybuffer"});return Buffer.from(e.data)}c(In,"downloadWorkspaceExport");async function kn(r,e={}){const t=new an;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(kn,"importWorkspace");async function Oo(r,e){const t=await $.withClient(async o=>ht(o,()=>o.get(`connectors/${r}/export-files`,{version:e}),{pollIntervalMs:Tn,timeoutMs:En}));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(Oo,"exportConnector");function xn(r,e){Ae(I.dirname(r)),T.writeFileSync(r,e)}c(xn,"writeFile");function Ro(r){T.existsSync(r)&&T.rmSync(r)}c(Ro,"deleteFile");function Ct(r){T.existsSync(r)&&T.rmSync(r,{recursive:!0,force:!0})}c(Ct,"deleteDir");function No(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(No,"readYaml$1");function $n(r,e,t){try{Ae(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($n,"writeYaml$1");function Ae(r){T.existsSync(r)||T.mkdirSync(r,{recursive:!0})}c(Ae,"ensureDirExists");function Pn(r,e=!0){if(!T.existsSync(r)||!T.statSync(r).isDirectory())return;let t=T.readdirSync(r);t.length>0&&(t.forEach(n=>Pn(I.join(r,n),!1)),t=T.readdirSync(r)),t.length===0&&!e&&T.rmdirSync(r)}c(Pn,"cleanupEmptyFolders");function Do(r){const e=r.split(/[\\/]/).join("/");return e.endsWith("/")?e+"**":e}c(Do,"normalizePattern");async function An(r,e,t){const n=(e??[]).map(Do),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:kr(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 p=m===""?"development":m,y=I.join(l,p,"src"),E=I.join(l,p,"src.zip"),S=m===""?Ye:m;T.existsSync(y)?o.push({name:Xt(a,S),content:await Lo(y)}):T.existsSync(E)&&o.push({name:Xt(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 p of m){const y=u.get(p.integrationUuid),E=xr(h,p.key,y);n.length>0&&!n.some(S=>Ur(E,S))||a.append(Y.dump(p),{name:E})}for(const{name:h,content:m}of o)a.append(m,{name:h});a.finalize()})}c(An,"createMembraneZip");async function Lo(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(Lo,"createConnectorVersionZip");async function St(r,e){const t=await un.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 On(r){const e=await un.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(On,"readMembraneZip");async function bt(r=process.cwd()){const e=await Rn(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 Rn(r){const e=Nn(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(Rn,"iterateMembraneFiles");function Nn(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(...Nn(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(Nn,"getMembraneFiles");function Dn(){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=No(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(Dn,"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 Mo={info:"\u{1F4DD}",success:"\u2728",warning:"\u26A0\uFE0F",error:"\u274C",debug:"\u{1F50D}"},jo={info:f.white,success:f.green,warning:f.yellow,error:f.red,debug:f.gray};class b{static{c(this,"Logger")}static formatMessage(e,t,n={icon:!1}){const o=n.timestamp?`${f.gray(new Date().toISOString())} `:"",i=n.prefix?`${f.gray(n.prefix)} `:"",s=n.suffix?` ${f.gray(n.suffix)}`:"",a=Mo[t],l=jo[t];return`${o}${n.icon?a:""} ${i}${l(e)}${s}`}static info(e,t){let n=f.white;if(t?.color&&(n=f[t.color.toLowerCase()]||f.white),t?.timestamp){const o=new Date().toLocaleTimeString();console.debug(`${f.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.info(this.formatMessage(e,"error",t))}static debug(e,t){t?.prefix?console.debug(f.gray(`[${t.prefix}] ${e}`),t.error?`
2
+ var mr=Object.defineProperty;var c=(r,e)=>mr(r,"name",{value:e,configurable:!0});import f from"chalk";import{Command as gr}from"commander";import*as T from"node:fs";import{mkdirSync as yr,writeFileSync as wr,readFileSync as Cr}from"node:fs";import*as I from"node:path";import{join as Ve,dirname as Sr}from"node:path";import{URL as br,fileURLToPath as vr}from"node:url";import{MembraneConfigLoader as Tr,AgentName as Zt,WorkspaceElementType as k,MembraneAxiosInstance as Er,MembraneClient as Xt,extractMembraneErrorData as V,WorkspaceElementSpecs as Q,WorkspaceSyncEventType as Ir,ConnectorFileUpdateType as Ye,NotFoundError as kr,parseMembraneElementPath as de,getConnectorSpecPath as xr,getConnectorVersionPath as Qt,CONNECTOR_VERSION_DEVELOPMENT as Ze,getMembraneElementPath as $r,compareWorkspaceExports as en,CONSOLE_ACCOUNT_API_TOKEN_PATH as Pr,OAUTH_SCOPE_TENANT as tn,OAUTH_SCOPE_PLATFORM_USER as nn,MEMBRANE_CLI_CLIENT_ID as Me,WorkspaceElementChangeType as ee,HttpRequestMethod as Ar,getDataCollectionCreateFields as Xe,excludeWriteOnlyFieldsFromSchema as rn,valueToSchema as je,getRequiredFieldsFromSchema as Or,getValueAtLocator as Rr,setValueAtLocator as Qe,walkSchema as on,makeDataLocationPath as sn,getDataCollectionUpdateFields as et}from"@membranehq/sdk";import O,{existsSync as Fe,readFileSync as an,mkdirSync as cn,writeFileSync as Nr,statSync as Dr,chmodSync as Lr}from"fs";import x from"path";import Mr from"conf";import tt from"os";import nt from"lodash/camelCase.js";import rt from"lodash/upperFirst.js";import jr from"code-block-writer";import Fr from"lodash/uniqBy.js";import{Box as w,Text as C,useInput as he,render as ot,Newline as Ur}from"ink";import pe,{createContext as it,useContext as st,useId as Kr,useRef as at,useState as L,useLayoutEffect as Ue,useEffect as Ce,useMemo as _r}from"react";import{jsxs as v,Fragment as Ke,jsx as d}from"react/jsx-runtime";import"node:events";import ln from"ink-text-input";import{SWRConfig as qr}from"swr";import un from"swr/immutable";import Ie,{isAxiosError as Br}from"axios";import ct from"jsonwebtoken";import lt from"semver";import{AsyncLocalStorage as Wr}from"async_hooks";import{toSentenceCase as Jr}from"js-convert-case";import zr from"lodash/isEqual.js";import Y from"js-yaml";import Gr from"chokidar";import*as Hr from"node:crypto";import{createHash as Vr}from"node:crypto";import Yr from"yaml";import{EventEmitter as Zr}from"events";import{EventSource as Xr}from"eventsource";import ut from"archiver";import dn from"form-data";import _e from"unzipper";import*as Qr from"node:os";import{randomUUID as eo,randomBytes as hn,createHash as to}from"crypto";import{createServer as pn}from"http";import Se from"ora";import fn from"jszip";import{minimatch as no}from"minimatch";import qe from"ink-spinner";import{TextInput as ro,Select as oo,Spinner as io}from"@inkjs/ui";import{FastMCP as so}from"fastmcp";import{z as D}from"zod";import{exec as ao}from"node:child_process";import dt from"lodash/merge.js";import co from"@anthropic-ai/sdk";import{faker as ke}from"@faker-js/faker";import lo from"lodash/template.js";import uo from"lodash/templateSettings.js";class ht extends Error{static{c(this,"ApiError")}statusCode;errorType;errorKey;data;constructor(e,t){const n=ho(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(`
3
+ `)}}function ho(r){try{const e=JSON.parse(r);return typeof e=="object"&&e!==null?e:null}catch{return null}}c(ho,"tryParseJson");class Ee{static{c(this,"ConfigLoader")}static instance=null;sdkLoader;constructor(){this.sdkLoader=new Tr}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 po="membrane",fo="membrane.config.yml",te="https://api.getmembrane.com",mo="https://console.getmembrane.com";function pt(r){const t=xe()?.consoleUri||mo;return r?new br(r,t).toString():t}c(pt,"getConsoleUrl");function ft(){const r=process.cwd(),e=I.join(r,po),t=I.join(r,fo),n=e,o=I.join(n,"workspace.yaml");return{membraneDirPath:e,configPath:t,payloadDirPath:n,workspaceDataFilePath:o}}c(ft,"getPaths");function mn(){return ft().membraneDirPath}c(mn,"getBasePath");const gn=".membrane",yn="config.json";function go(r){const e=x.resolve(gn),t=x.join(e,yn);let n={};Fe(t)&&(n=JSON.parse(an(t,"utf8")));const o={...n,...r};for(const[i,s]of Object.entries(o))s===void 0&&delete o[i];Fe(e)||cn(e,{recursive:!0}),Nr(t,JSON.stringify(o,null,2)+`
4
+ `,"utf8")}c(go,"patchProjectConfig");function wn(){try{const r=x.join(x.resolve(gn),yn);if(!Fe(r))return{};const e=JSON.parse(an(r,"utf8"));return{defaultWorkspaceKey:e.defaultWorkspaceKey,defaultTenantKey:e.defaultTenantKey}}catch{return{}}}c(wn,"readProjectDefaults");const Be=x.join(tt.homedir(),".membrane");Fe(Be)?(Dr(Be).mode&511)!==448&&Lr(Be,448):cn(Be,{mode:448});const yo={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 Mr({schema:yo,configName:"credentials",cwd:x.join(tt.homedir(),".membrane"),configFileMode:384}),wo=c(r=>{M.set("pat",r)},"setPat"),Cn=c(()=>M.get("pat"),"getPat"),Co=c(()=>{M.delete("pat")},"clearPat"),Sn=c((r,e,t)=>{M.set({accessToken:r,refreshToken:e}),t!=null?M.set("expiresAt",Date.now()+t*1e3):M.delete("expiresAt")},"setTokens"),So=c(()=>M.get("accessToken"),"getAccessToken"),be=c(()=>M.get("refreshToken"),"getRefreshToken"),mt=c(()=>{const r=M.get("expiresAt");return r?Date.now()>=r-6e4:!0},"isTokenExpired"),bo=c(()=>{M.delete("accessToken"),M.delete("refreshToken"),M.delete("expiresAt"),M.delete("apiUri"),M.delete("tokenScope"),$e()},"clearTokens"),me=c(()=>M.get("apiUri"),"getApiUri"),bn=c(r=>{M.set("apiUri",r)},"setApiUri"),vo=c(r=>{M.set("tokenScope",r)},"setTokenScope"),gt=c(()=>M.get("tokenScope"),"getTokenScope"),To=c(r=>{M.set({pendingLoginScope:r.scope,pendingLoginCodeVerifier:r.codeVerifier,pendingLoginClientId:r.clientId,pendingLoginCreatedAt:Date.now()})},"setPendingLogin"),Eo=600*1e3,Io=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>Eo){$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"),yt=c(()=>!!(M.get("accessToken")||M.get("pat")),"hasStoredCredentials");class Pe{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 Sn(n.access_token,o,n.expires_in),n.access_token}async getAuthToken(){const e=So();if(e&&!mt())return e;if(be())return this.refreshPromise??=this.refreshAccessToken().finally(()=>{this.refreshPromise=null});const t=Cn();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 ht(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 ko=c(r=>{const e=new Pe(r);return t=>e.get(t)},"createAccountApiFetcher");class W{static{c(this,"TenantApiClient")}derivedToken=null;apiUri;directToken;workspaceKey;tenantKey;accountClient;constructor(e){this.apiUri=me()||te,this.accountClient=new Pe,this.directToken=process.env.MEMBRANE_TOKEN||null;const t=wn();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(gt()==="tenant")return this.accountClient.getValidAccessToken();if(!yt()||mt()&&!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=gt()==="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 ht(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})}}const xo={info:"\u{1F4DD}",success:"\u2728",warning:"\u26A0\uFE0F",error:"\u274C",debug:"\u{1F50D}"},$o={info:f.white,success:f.green,warning:f.yellow,error:f.red,debug:f.gray};class b{static{c(this,"Logger")}static formatMessage(e,t,n={icon:!1}){const o=n.timestamp?`${f.gray(new Date().toISOString())} `:"",i=n.prefix?`${f.gray(n.prefix)} `:"",s=n.suffix?` ${f.gray(n.suffix)}`:"",a=xo[t],l=$o[t];return`${o}${n.icon?a:""} ${i}${l(e)}${s}`}static info(e,t){let n=f.white;if(t?.color&&(n=f[t.color.toLowerCase()]||f.white),t?.timestamp){const o=new Date().toLocaleTimeString();console.debug(`${f.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.info(this.formatMessage(e,"error",t))}static debug(e,t){t?.prefix?console.debug(f.gray(`[${t.prefix}] ${e}`),t.error?`
8
5
  ${f.red(t.error)}`:""):console.debug(f.gray(e),t?.error?`
9
- ${f.red(t.error)}`:"")}static step(e,t){}static header(e){console.debug(),console.debug(f.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 Fo(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 In(),o=await On(n);e.stop();const{changes:i,diff:s}=Qt(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(Uo(s))}catch(t){e.stop(),b.error("\u25A0 Error"),b.error(`\u2514\u2500\u2500 ${t.message}`),process.exit(1)}})}c(Fo,"setupDiffCommand");function Uo(r){return r.split(`
11
- `).map(e=>e.startsWith("diff ")?f.bold(e):e.startsWith("index ")||e.startsWith("===")?f.dim(e):e.startsWith("---")?f.bold.red(e):e.startsWith("+++")?f.bold.green(e):e.startsWith("@@")?f.cyan(e):e.startsWith("+")?f.green(e):e.startsWith("-")?f.red(e):e).join(`
12
- `)}c(Uo,"colorizePatch");const Ln=".membrane",Mn="config.json";function Ko(r){const e=x.resolve(Ln),t=x.join(e,Mn);let n={};Fe(t)&&(n=JSON.parse(ln(t,"utf8")));const o={...n,...r};for(const[i,s]of Object.entries(o))s===void 0&&delete o[i];Fe(e)||cn(e,{recursive:!0}),Mr(t,JSON.stringify(o,null,2)+`
13
- `,"utf8")}c(Ko,"patchProjectConfig");function jn(){try{const r=x.join(x.resolve(Ln),Mn);if(!Fe(r))return{};const e=JSON.parse(ln(r,"utf8"));return{defaultWorkspaceKey:e.defaultWorkspaceKey,defaultTenantKey:e.defaultTenantKey}}catch{return{}}}c(jn,"readProjectDefaults");class J{static{c(this,"TenantApiClient")}derivedToken=null;apiUri;directToken;workspaceKey;tenantKey;accountClient;constructor(e){this.apiUri=me()||te,this.accountClient=new Pe,this.directToken=process.env.MEMBRANE_TOKEN||null;const t=jn();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 _o(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("--cursor <cursor>","Pagination cursor").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),t.cursor&&s.set("cursor",t.cursor);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(f.gray(" No actions found."));else for(const h of u){const m=h.description?f.gray(` \u2014 ${h.description}`):"";console.error(` ${f.cyan(h.id)} ${h.name||h.key||"(unnamed)"}${m}`)}l.cursor&&console.error(f.gray(` Returned ${u.length} elements. Run with --cursor ${l.cursor} to get the next page.`)),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)+`
6
+ ${f.red(t.error)}`:"")}static step(e,t){}static header(e){console.debug(),console.debug(f.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 q(r){r instanceof ht?b.error(r.format()):r instanceof Error?b.error(r.message):b.error("An unknown error occurred"),process.exit(1)}c(q,"handleCommandError");function Po(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("--cursor <cursor>","Pagination cursor").option("--json","Output as JSON").action(async t=>{try{const o={...e.opts(),...t},i=new W(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),t.cursor&&s.set("cursor",t.cursor);const a=s.toString(),l=await i.get(`/actions${a?`?${a}`:""}`);if(o.json)process.stdout.write(JSON.stringify(l,null,2)+`
7
+ `);else{const u=l.items??[];if(u.length===0)console.error(f.gray(" No actions found."));else for(const h of u){const m=h.description?f.gray(` \u2014 ${h.description}`):"";console.error(` ${f.cyan(h.id)} ${h.name||h.key||"(unnamed)"}${m}`)}l.cursor&&console.error(f.gray(` Returned ${u.length} elements. Run with --cursor ${l.cursor} to get the next page.`)),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 W(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
8
  `):(console.error(),console.error(f.green(" Action executed successfully.")),console.error(),process.stdout.write(JSON.stringify(h.output??h,null,2)+`
16
- `))}catch(o){q(o)}})}c(_o,"setupActionCommand");function A(r,e,t=14){console.error(` ${f.gray(r.padEnd(t))} ${e}`)}c(A,"printField");const qo=Object.values(en),vt=qo.filter(r=>r!==en.UNIVERSE);function Bo(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(f.gray(" No agent sessions found."));else for(const a of s){const l=f.gray(`[${a.status}]`);console.error(` ${f.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(),A("Session ID",i.id),A("Status",i.status),A("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("--timeout <seconds>","Timeout in seconds for --wait (1-60, default 30)").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"),n.timeout&&s.set("timeout",n.timeout));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(),A("Session ID",l.id),l.agentName&&A("Agent",l.agentName),A("State",l.state),l.prompt&&A("Prompt",l.prompt),l.summary&&A("Summary",l.summary),l.error&&A("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(),A("Session ID",s.id),A("Status",s.status),A("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(f.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(f.gray(" No messages found."));else for(const l of a){const u=f.cyan(String(l.role??"unknown")),h=l.content??l.text??JSON.stringify(l);console.error(` ${u}: ${h}`)}console.error()}}catch(o){q(o)}})}c(Bo,"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 Wo(r){const{membraneInterfaces:{actions:e}}=r,t=Jo(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(Wo,"generateOpenAPIContent");function Jo(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(Jo,"generateOpenAPISchemas");function zo(r){const{membraneInterfaces:{actions:e}}=r,t=_r(e,"key"),n=new Kr({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(),Go(n,t),n.toString()}c(zo,"generateTypeScriptContent");function Go(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(Go,"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&&Ho(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 Ho(r,e,t){Object.entries(e).forEach(([n,o])=>{const s=t.includes(n)?"":"?",a=Tt(o);r.writeLine(`readonly ${n}${s}: ${a}`)})}c(Ho,"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=Vo(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 Vo(r){switch(r.target){case"openapi":return{"openapi.json":Wo(r)};case"typescript":return{"generated.d.ts":zo(r)};default:throw new Error(`Unsupported target: ${r.target}`)}}c(Vo,"generateContent");const xt=c(()=>[f.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"),f.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),f.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"),f.yellow("\u2502 The codegen command is experimental and subject to rapid changes.\u2502"),f.yellow("\u2502 Features, APIs, and file structures may change without notice. \u2502"),f.yellow("\u2502 Use in production environments is not recommended. \u2502"),f.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 Yo(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",["",f.bold("Examples:"),` ${f.gray("\u25B8")} ${f.cyan("membrane codegen --actions list-files,get-file-by-id --out src/generated --target openapi --schemasOnly")}`,` ${f.gray("\u25B8")} ${f.cyan("membrane install --actions delete-file --out src/generated --target typescript --schemasOnly")}`,"",xt()].join(`
25
- `)).action(async t=>{try{console.warn(xt()),console.error(f.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(f.green("\u2705 Code generation completed successfully!")),process.exit(0)}catch(n){console.error(f.red("\u274C Code generation failed:")),console.error(n instanceof Error?n.message:"Unknown error occurred"),process.exit(1)}})}c(Yo,"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 Fn=at(null);function Z(){const r=ct(Fn);if(!r)throw new Error("useMembraneCLIService must be used within MembraneCLIServiceProvider");return r}c(Z,"useMembraneCLIService");const $t=at(null),Un=c(()=>{const r=ct($t);if(!r)throw new Error("useTree must be used within TreeView");return r},"useTree"),Xo=c(r=>he.Children.count(r)>0,"hasChildren");function Qo(r){const e=Un(),{label:t,value:n,isInitiallyExpanded:o}=r,i=qr(),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,p=typeof m=="function"?m(h):m;return{...h,props:{...r,children:p},isParent:Xo(p)}}c(Qo,"useTreeItem");function ve(r){const e=Un(),t=Qo(r),{expanded:n,isParent:o,props:{children:i},setExpanded:s}=t,{renderValue:a=ti}=r,l=t.ref;Ue(()=>{function p(y){return r.onInput?.(y)?!0:y.active&&y.key.rightArrow&&!n?(s(!0),!0):y.active&&y.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 u=l.firstChild;function h(p){const y=u;return y.nextSibling||(y.nextSibling={parent:l,prevSibling:y,index:y.index+1}),u=y.nextSibling,y.label=p,y}c(h,"registerChildItem");function m(){l.lastRenderedChild=u.prevSibling}return c(m,"commitChildren"),Ue(()=>{m()}),v(Ke,{children:[v(w,{marginLeft:e.depth*2,children:[d(w,{width:2,children:o&&d(C,{children:n?"\u25BC":"\u25B6"})}),ei(t),a(t)]}),n&&d($t.Provider,{value:{...e,depth:e.depth+1,registerChildItem:h},children:i})]})}c(ve,"TreeItem");function ei({active:r,label:e}){return d(w,{width:32,children:d(C,{inverse:r,children:e})})}c(ei,"defaultRenderLabel");function ti(r){return d(C,{})}c(ti,"defaultRenderValue");const ye=c(({label:r,onPress:e,hotkey:t})=>d(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(()=>d(w,{children:d(C,{children:`${t?` (${t})`:""}`})}),"renderValue")}),"ActionTreeItem"),Kn=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(ve,{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(w,{children:n||!l?d(C,{dimColor:!0,children:m}):v(Ke,{children:[d(w,{width:m.length+1,children:d(dn,{...i,focus:l,value:h,onChange:a})}),d(C,{dimColor:!0,children:" \u241B cancel"})]})})},"renderValue")})},"TreeTextField"),ni=c(r=>d(Kn,{...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($t.Provider,{value:i,children:v(w,{flexDirection:"column",children:[d(ve,{isInitiallyExpanded:!0,label:"rootItem",children:r}),e&&d(w,{marginTop:1,flexDirection:"column",children:d(C,{dimColor:!0,children:"\u2191/\u2193 move \u2022 \u2190 collapse \u2022 \u2192 expand \u2022 Enter/Space select/edit \u2022 Esc exit"})})]})})},"TreeView");H.Item=ve,H.TextField=Kn;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(ve,{label:r,children:i.map(u=>d(ve,{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 ri({onComplete:r}){const{config:e,updateConfig:t,fetchElements:n,getSyncedElementsByType:o}=Z(),[i,s]=L(""),a=e,l=c(p=>{s(p),setTimeout(()=>s(""),2e3)},"setFlash"),u=c(async(p,y)=>{try{await t({[p]:y}),l("\u2705 Configuration updated!")}catch{l("\u274C Error updating configuration")}},"updateField"),h=c(async()=>{try{if(e){const p=fe.saveToFile(e);l(p?"\u2705 Configuration saved successfully!":"\u274C Failed to save configuration"),await n();const y=o(k.Action);await kt({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:y.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 p=fe.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 v(w,{flexDirection:"column",gap:1,children:[d(C,{bold:!0,color:"cyan",children:"\u2699\uFE0F Membrane Configuration Manager"}),d(w,{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(p=>u("workspaceKey",p),"onChange"),disabled:!0}),d(ni,{label:"Workspace Secret",value:a?.workspaceSecret??"",onChange:c(p=>u("workspaceSecret",p),"onChange"),disabled:!0}),d(H.TextField,{label:"API URI",value:a?.apiUri??"",onChange:c(p=>u("apiUri",p),"onChange")}),d(H.TextField,{label:"Test Customer ID",value:a?.testCustomerId??"",onChange:c(p=>u("testCustomerId",p),"onChange")})]}),v(H.Item,{label:"Code Generation",isInitiallyExpanded:!0,children:[v(H.Item,{label:"Project Type",isInitiallyExpanded:!0,value:a?.projectType,renderValue:c(({value:p})=>d(C,{children:p==="typescript"?"TypeScript":p==="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(p=>u("outputDir",p),"onChange")})]}),v(H.Item,{label:"Workspace Elements",children:[d(we,{label:"Actions",elementType:k.Action,isActionExcluded:c(p=>a?.excludedActionKeys?.includes(p.key)??!1,"isActionExcluded"),toggleAction:c(p=>u("excludedActionKeys",[...a?.excludedActionKeys??[],p.key]),"toggleAction"),generateCode:c(p=>{(async()=>{try{await kt({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:[p]}}),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(w,{paddingX:2,children:d(C,{color:i.includes("\u2705")?"green":"red",children:i})})]})}c(ri,"ConfigManager");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}},oi=["id","workspaceId","integrationId","createdAt","updatedAt","revision","archivedAt","baseUri","state","appliedToIntegrations","dependencies"],_n=[k.Action,k.FieldMapping,k.Flow,k.DataSource,k.Package];class K{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||K.extractIntegrationKey(o)}get id(){return K.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 Gr(t,n)}hasParent(){if(this.data?.parentUuid)return!0;const e=this.getParentKey();return!!e&&!!this.data?.[e]}clean(){const e={...this.data};return oi.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 K(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 K(e,t.key,n,t)}static fromPathAndData(e,t){const n=K.parsePath(e);if(!t)return;const o=t?.key||n?.key;return n?K.new(n.type,o,n.integrationKey,t):void 0}static fromElement(e){return new K(e.type,e.key,e.integrationKey,{...e.data})}static idFromPath(e){const t=K.parsePath(e);if(t)return K.makeId(t.type,t.key,t.integrationKey)}static makeId(e,t,n){return e===k.Integration?`${e}:${t}`:K.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 _n.includes(e)}static canBeIntegrationSpecific(e){return _n.includes(e)}}class qn{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 Pt(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(Pt,"readYaml");function ii(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(ii,"writeYaml");class si extends qn{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}),ii(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=Pt(e);if(t)return K.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 ai extends qn{static{c(this,"RemoteWorkspaceElementsRepository")}async getElementsByType(e,t){const n=K.canBeIntegrationSpecific(e),o=await this.findAll(e,n?{layer:"universal"}:{});if(!K.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 K.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=K.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=K.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=>K.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 K.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),K.fromData(e,i))):[]}}class At extends Xr{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"},ci={ignored:po,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 li 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=Yr.watch(this.membraneDir,ci),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?Zr.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 Hr.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 Ot=(r=>(r.Updated="updated",r.ConnectorFileUpdated="connector-file-updated",r.Connected="connected",r.Disconnected="disconnected",r.Error="error",r))(Ot||{});const ui={debounceMs:2e3,reconnectIntervalMs:5e3,maxReconnectAttempts:1/0,maxBackoffMs:6e4,connectionTimeoutMs:3e5};class di extends At{static{c(this,"RemoteElementWatcher")}constructor(e=ui){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 Qr(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!==$r.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 Bn{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 Te="connectors",re="development",Rt={};async function Wn(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 Nt(u);if(!m)continue;e?.("pushing",m.name),"baseUri"in m&&delete m.baseUri;let p;m.uuid&&(p=await $.withClient(S=>S.get(`/connectors/${m.uuid}`),!1));const y=m.uuid;if(p)i[y]=p.id,g.info(`[connectors] Matched ${m.name} uuid: ${m.uuid}`),p.isPublic||(p.archivedAt&&(g.info(`[connectors] Restoring archived connector ${m.name}`),await $.withClient(S=>S.post(`connectors/${p.id}/restore`))),g.info(`[connectors] Updating connector ${m.name}`),await $.withClient(S=>S.patch(`connectors/${p.id}`,{...m,workspaceId:o})));else if(!i[y]&&!p?.isPublic){let S=!1;try{const N=await Dt({connectorId:y});N&&N.isPublic&&(S=!0)}catch{}if(!S){g.info(`[connectors] Creating custom connector ${m.name} (${m.key})`);const N=await $.withClient(R=>R.post("connectors",{...m,workspaceId:o}));i[y]=N.id}}const E=h.filter(S=>O.statSync(x.join(s,u,S)).isDirectory());for(const S of E)await fi({connector:m,version:S,connectorId:i[y]}),t.add(y);e?.("pushed",m.name)}return{connectorsMapping:i,pushedConnectors:Array.from(t)}}c(Wn,"pushConnectors");async function Jn({connectorId:r,connectorVersion:e,allConnectors:t,pulledConnectors:n,pulledConnectorVersions:o}){if(!r||o[r]?.has(e))return;const i=gn(),s=await Dt({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 mi({basePath:i,connector:s}),n.add(r)),o[r]||(o[r]=new Set),o[r].has(e)||(await gi({connector:s,connectorVersion:e,basePath:i}),o[r].add(e))}}c(Jn,"pullRemoteConnector");function ie(){const r=mt();return x.join(r.membraneDirPath,Te)}c(ie,"getConnectorsPath");async function Nt(r){const e=x.join(ie(),r,`${r}.yml`);return Pt(e,!1)}c(Nt,"readConnector");async function hi(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(hi,"createZipArchive");async function pi(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(pi,"extractZipArchive");async function fi({connector:r,version:e,connectorId:t}){const n=x.join(ie(),oe(r),zn(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 hi(o,i)),!O.existsSync(i)){g.warning(`[connectors] No source code found for ${r.name} version ${e}`);return}try{const a=new an;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(fi,"pushConnectorVersion");async function Dt({connectorId:r}){if(r){if(Rt[r])return Rt[r];try{const e=await $.withClient(t=>t.get(`connectors/${r}`),!1);return Rt[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(Dt,"getConnector");async function mi({basePath:r,connector:e}){const t=oe(e),n=x.join(r,Te,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(mi,"pullConnector$1");async function gi({connector:r,connectorVersion:e,basePath:t}){const n=oe(r),o=zn(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 pi(s,l)}g.info(`[connectors] Pulled connector version: ${r.name} (${o})`)}c(gi,"pullConnectorVersion");function oe(r){return r.key}c(oe,"getConnectorDirName");function zn(r){return r??re}c(zn,"getConnectorVersionDirName");function yi(r){const e=gn(),t=oe(r);return x.join(e,Te,t)}c(yi,"getConnectorDirPath");function wi(r){return r.match(`${Te}/[^/]+/${re}/src/.*`)!==null}c(wi,"isConnectorSourceFile");async function Ci(r){const e=r.match(`${Te}/([^/]+)/${re}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await Nt(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 Si(r){const e=r.match(`${Te}/([^/]+)/${re}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await Nt(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(Si,"deleteConnectorFile");async function bi(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(bi,"pullConnectorFile");async function vi(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(vi,"deleteLocalConnectorFile");async function Ti(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(Ti,"renameLocalConnectorDirectory");async function Ei(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(Ei,"deleteLocalConnectorDirectory");const _={LogAdded:"logAdded",StateChanged:"stateChanged",StatsChanged:"statsChanged",ConflictsChanged:"conflictsChanged",McpStatusChanged:"mcpStatusChanged",McpServersChanged:"mcpServersChanged",ConfigChanged:"configChanged"};class Ii 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(_.StateChanged,{state:e}),await this.emitRemote({status:e})}setConflicts(e){this.emit(_.ConflictsChanged,{conflicts:e})}setConfig(e){this.emit(_.ConfigChanged,{config:e})}setStats(e){this.emit(_.StatsChanged,{stats:e})}addLog(e){this.emit(_.LogAdded,{log:e})}setMcpStatus(e){this.emit(_.McpStatusChanged,{status:e})}async setMcpServers(e){this.emit(_.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 Ii({heartbeatIntervalMs:15e3}),Gn=[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 Bn,this.remoteCache=new Bn,this.localRepo=new si(this.localCache),this.remoteRepo=new ai(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 Jn({connectorId:o,connectorVersion:i,allConnectors:e,pulledConnectors:this.pulledConnectors,pulledConnectorVersions:this.pulledConnectorVersions})}}async pushConnectors(){const{connectorsMapping:e}=await Wn();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 li({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 di,this.remoteWatcher.on(Ot.Updated,({elementId:e,elementType:t})=>this.handleRemoteElementEvent(e,t)),this.remoteWatcher.on(Ot.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 Dt({connectorId:s});if(!l?.key)return;const u=yi(l);await this.localWatcher?.executeWithPathLock(u,async()=>Jn({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 vi(e,t);break;case Ze.ConnectorDirectoryRenamed:await Ti(e,t,o);break;case Ze.ConnectorDirectoryDeleted:await Ei(e,t);break;default:await bi(e,t);break}}catch(i){g.error(`[sync] Error handling remote connector file event: ${i}`)}}async handleLocalEvent(e,t){try{if(wi(e.filePath))switch(t){case G.Updated:await Ci(e.filePath);break;case G.Deleted:await Si(e.filePath);break}else{let n=K.fromPathAndData(e.filePath,e.data);if(!n){const o=K.idFromPath(e.filePath);if(!o||(n=this.remoteCache.get(o),!n))return}switch(g.info(`[${this.getDirectionLabel(z.OUTGOING)}] ${zr(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 Gn){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 Gn){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(eo.tmpdir(),"membrane-mcp-status"),Hn=3e4;class ki{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=Vn(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=Vn(t);return o.length===0?null:o[0]}const n=jt(r,t);if(T.existsSync(n)){const o=T.statSync(n),i=new Date;if(i.getTime()-o.mtime.getTime()>Hn)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>Hn)return Re(r,t),null}return l}}catch{r&&e&&Re(r,e)}return null}c(Je,"getMcpStatus");function Vn(r){try{const e=r||process.cwd(),t=Mt(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(Vn,"getAllMcpStatusFiles");function Lt(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=jt(r.processId,r.cwd);T.writeFileSync(n,JSON.stringify(t,null,2))}catch{}}c(Lt,"updateMcpStatus");function Re(r,e){try{const t=e||process.cwd();if(r){const n=jt(r,t);T.existsSync(n)&&T.unlinkSync(n)}else{const n=Mt(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 xi(r,e){const t=Je(r,e);t&&Lt({processId:r,cwd:e,totalRequests:t.totalRequests+1,lastRequestTime:new Date().toISOString(),lastActivity:new Date().toISOString()})}c(xi,"trackToolExecution");function Mt(r){return Vr("md5").update(r).digest("hex").slice(0,8)}c(Mt,"getCwdHash");function jt(r,e){const t=Mt(e);return I.join(ae,`mcp-${t}-${r}.json`)}c(jt,"getStatusFilePath");const ze={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 $i{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 ki,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(),fe.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=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()})}}function Pi({children:r,membraneCLIService:e}){const{data:t}=hn("/account"),[n,o]=L(P.NOT_INITIALIZED),[i,s]=L([]),[a,l]=L({}),[u,h]=L([]),[m,p]=L(null),E=t?.workspaces?.find(S=>S.workspaceKey===m?.workspaceKey)||null;return Se(()=>{const S=c(({state:F})=>o(F),"handleStateChanged"),N=c(({stats:F})=>l(F),"handleStatsChanged"),R=c(({log:F})=>h(Le=>[...Le,F]),"handleLogAdded"),j=c(({conflicts:F})=>s(F),"handleConflictsUpdated"),U=c(({config:F})=>p(F),"handleConfigChanged");return e.notifier.on(_.StateChanged,S),e.notifier.on(_.StatsChanged,N),e.notifier.on(_.LogAdded,R),e.notifier.on(_.ConflictsChanged,j),e.notifier.on(_.ConfigChanged,U),e.init(),()=>{e.notifier.off(_.StateChanged,S),e.notifier.off(_.StatsChanged,N),e.notifier.off(_.LogAdded,R),e.notifier.off(_.ConflictsChanged,j),e.notifier.off(_.ConfigChanged,U)}},[]),d(Fn.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(Pi,"MembraneCLIServiceProvider");const Yn=at(process.cwd());function Ai(){return ct(Yn)}c(Ai,"useCwd");function Oi({cwd:r,children:e}){return d(Yn.Provider,{value:r,children:e})}c(Oi,"CwdProvider");function Ft({cwd:r,children:e,membraneCLIService:t}){const n=r||process.cwd();return d(Oi,{cwd:n,children:d(Jr,{value:{fetcher:$o()},children:d(Pi,{membraneCLIService:t,children:e})})})}c(Ft,"Layout");function Ri(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(ri,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(Ri,"setupConfigCommand");function Zn(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(Zn,"sleep");function Xn(r){return r.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}c(Xn,"escapeHtml");const Ni="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="${Ni}">
27
- <div style="text-align:center"><h1>${Xn(r)}</h1><p style="color:${n}">${Xn(e)}</p></div>
28
- </body></html>`}c(ce,"htmlPage");async function Ut(r,e){return r.post("/connection-requests",e)}c(Ut,"createConnectionRequest");function Qn(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(Qn,"printConnectionRequestResult");const Di=3e3,Li=1800*1e3;function Mi(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("--connectorKey <key>","Connector key").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 --connectorKey hubspot --workspaceKey my-workspace"," membrane connect --connectionId abc --non-interactive",""].join(`
29
- `)).action(async e=>{try{await ji(e)}catch(t){q(t)}})}c(Mi,"setupConnectCommand");async function ji(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,connectorKey:r.connectorKey,connectorVersion:r.connectorVersion,connectionId:r.connectionId,name:r.name,allowMultipleConnections:r.allowMultipleConnections,connectorParameters:e};if(!n){const h=await Ut(t,o);Qn(h),process.exit(0);return}const i=to(),{port:s,server:a,waitForCallback:l}=await Fi(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:U}=await import("open");await U(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:
9
+ `))}catch(o){q(o)}})}c(Po,"setupActionCommand");function A(r,e,t=14){console.error(` ${f.gray(r.padEnd(t))} ${e}`)}c(A,"printField");const Ao=Object.values(Zt),wt=Ao.filter(r=>r!==Zt.UNIVERSE);function Oo(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 W(n).get("/agent/sessions");if(n.json)process.stdout.write(JSON.stringify(i,null,2)+`
10
+ `);else{const s=i.items??[];if(s.length===0)console.error(f.gray(" No agent sessions found."));else for(const a of s){const l=f.gray(`[${a.status}]`);console.error(` ${f.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 (${wt.join(", ")})`).option("--json","Output as JSON").action(async t=>{try{if(t.agent&&!wt.includes(t.agent))throw new Error(`Invalid agent name "${t.agent}". Must be one of: ${wt.join(", ")}`);const n={...e.opts(),...t},i=await new W(n).post("/agent/sessions",{prompt:t.message,...t.agent&&{agentName:t.agent}});n.json?process.stdout.write(JSON.stringify(i,null,2)+`
11
+ `):(console.error(),A("Session ID",i.id),A("Status",i.status),A("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("--timeout <seconds>","Timeout in seconds for --wait (1-60, default 30)").option("--json","Output as JSON").action(async(t,n)=>{try{const o={...e.opts(),...n},i=new W(o),s=new URLSearchParams;n.wait&&(s.set("wait","true"),n.timeout&&s.set("timeout",n.timeout));const a=s.toString(),l=await i.get(`/agent/sessions/${encodeURIComponent(t)}${a?`?${a}`:""}`);o.json?process.stdout.write(JSON.stringify(l,null,2)+`
12
+ `):(console.error(),A("Session ID",l.id),l.agentName&&A("Agent",l.agentName),A("State",l.state),l.prompt&&A("Prompt",l.prompt),l.summary&&A("Summary",l.summary),l.error&&A("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 W(o).post(`/agent/sessions/${encodeURIComponent(t)}/message`,{input:n.message});o.json?process.stdout.write(JSON.stringify(s,null,2)+`
13
+ `):(console.error(),A("Session ID",s.id),A("Status",s.status),A("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 W(o).post(`/agent/sessions/${encodeURIComponent(t)}/interrupt`);o.json?process.stdout.write(JSON.stringify(s,null,2)+`
14
+ `):(console.error(),console.error(f.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 W(o).get(`/agent/sessions/${encodeURIComponent(t)}/messages`);if(o.json)process.stdout.write(JSON.stringify(s,null,2)+`
15
+ `);else{const a=s.items??(Array.isArray(s)?s:[]);if(a.length===0)console.error(f.gray(" No messages found."));else for(const l of a){const u=f.cyan(String(l.role??"unknown")),h=l.content??l.text??JSON.stringify(l);console.error(` ${u}: ${h}`)}console.error()}}catch(o){q(o)}})}c(Oo,"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 Ro(r){const{membraneInterfaces:{actions:e}}=r,t=No(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(Ro,"generateOpenAPIContent");function No(r){const e={};return r.forEach(t=>{const n=rt(nt(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(No,"generateOpenAPISchemas");function Do(r){const{membraneInterfaces:{actions:e}}=r,t=Fr(e,"key"),n=new jr({indentNumberOfSpaces:2,newLine:`
16
+ `});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(),Lo(n,t),n.toString()}c(Do,"generateTypeScriptContent");function Lo(r,e){r.writeLine('declare module "@membranehq/sdk" {'),r.indent(()=>{e.forEach(t=>{const n=St(t),o=t?.inputSchema;We(r,{interfaceName:n,properties:o?.properties,required:o?.required||[]});const i=bt(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=St(t),o=bt(t);return{name:"action",parameters:`selector: "${t.key}"`,returnType:`ActionAccessor<${n}, ${o}>`}})}),r.newLine(),We(r,{interfaceName:"ConnectionAccessor",methods:e.map(t=>{const n=St(t),o=bt(t);return{name:"action",parameters:`selector: "${t.key}"`,returnType:`ConnectionLevelActionAccessor<${n}, ${o}>`}})})}),r.writeLine("}")}c(Lo,"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&&Mo(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 Mo(r,e,t){Object.entries(e).forEach(([n,o])=>{const s=t.includes(n)?"":"?",a=Ct(o);r.writeLine(`readonly ${n}${s}: ${a}`)})}c(Mo,"generateTypeScriptProperties");function Ct(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?Ct(r.items):"unknown"}[]`:r.type==="object"?r.properties?`{ ${Object.entries(r.properties).map(([t,n])=>{const i=(r.required||[]).includes(t)?"":"?",s=Ct(n);return`readonly ${t}${i}: ${s}`}).join("; ")} }`:"Record<string, unknown>":"unknown"}c(Ct,"convertJsonSchemaToTypeScript");function St(r){return`${rt(nt(r.key))}Input`}c(St,"getInputTypeName");function bt(r){return`${rt(nt(r.key))}Output`}c(bt,"getOutputTypeName");async function vt(r){const{out:e}=r;await T.promises.mkdir(e,{recursive:!0});const t=jo(r);for(const[n,o]of Object.entries(t)){const i=I.join(e,n);await T.promises.writeFile(i,o,"utf-8")}}c(vt,"generateCode");function jo(r){switch(r.target){case"openapi":return{"openapi.json":Ro(r)};case"typescript":return{"generated.d.ts":Do(r)};default:throw new Error(`Unsupported target: ${r.target}`)}}c(jo,"generateContent");const Tt=c(()=>[f.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"),f.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),f.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"),f.yellow("\u2502 The codegen command is experimental and subject to rapid changes.\u2502"),f.yellow("\u2502 Features, APIs, and file structures may change without notice. \u2502"),f.yellow("\u2502 Use in production environments is not recommended. \u2502"),f.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(`
17
+ `),"createExperimentalWarning$2");function Fo(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",["",f.bold("Examples:"),` ${f.gray("\u25B8")} ${f.cyan("membrane codegen --actions list-files,get-file-by-id --out src/generated --target openapi --schemasOnly")}`,` ${f.gray("\u25B8")} ${f.cyan("membrane install --actions delete-file --out src/generated --target typescript --schemasOnly")}`,"",Tt()].join(`
18
+ `)).action(async t=>{try{console.warn(Tt()),console.error(f.cyan("\u{1F527} Membrane Codegen")),console.error("Status: Loading membrane interfaces...");const n=await Uo(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 vt(o),console.error(f.green("\u2705 Code generation completed successfully!")),process.exit(0)}catch(n){console.error(f.red("\u274C Code generation failed:")),console.error(n instanceof Error?n.message:"Unknown error occurred"),process.exit(1)}})}c(Fo,"setupCodegenCommand");async function Uo(r,e){return await r.fetchElements(),{actions:[...r.getSyncedElementsByType(k.Action).map(t=>t.data)].filter(t=>e.actions.includes(t.key||""))}}c(Uo,"loadMembraneInterfaces");const vn=it(null);function Z(){const r=st(vn);if(!r)throw new Error("useMembraneCLIService must be used within MembraneCLIServiceProvider");return r}c(Z,"useMembraneCLIService");const Et=it(null),Tn=c(()=>{const r=st(Et);if(!r)throw new Error("useTree must be used within TreeView");return r},"useTree"),Ko=c(r=>pe.Children.count(r)>0,"hasChildren");function _o(r){const e=Tn(),{label:t,value:n,isInitiallyExpanded:o}=r,i=Kr(),s=at(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,p=typeof m=="function"?m(h):m;return{...h,props:{...r,children:p},isParent:Ko(p)}}c(_o,"useTreeItem");function ve(r){const e=Tn(),t=_o(r),{expanded:n,isParent:o,props:{children:i},setExpanded:s}=t,{renderValue:a=Bo}=r,l=t.ref;Ue(()=>{function p(y){return r.onInput?.(y)?!0:y.active&&y.key.rightArrow&&!n?(s(!0),!0):y.active&&y.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 u=l.firstChild;function h(p){const y=u;return y.nextSibling||(y.nextSibling={parent:l,prevSibling:y,index:y.index+1}),u=y.nextSibling,y.label=p,y}c(h,"registerChildItem");function m(){l.lastRenderedChild=u.prevSibling}return c(m,"commitChildren"),Ue(()=>{m()}),v(Ke,{children:[v(w,{marginLeft:e.depth*2,children:[d(w,{width:2,children:o&&d(C,{children:n?"\u25BC":"\u25B6"})}),qo(t),a(t)]}),n&&d(Et.Provider,{value:{...e,depth:e.depth+1,registerChildItem:h},children:i})]})}c(ve,"TreeItem");function qo({active:r,label:e}){return d(w,{width:32,children:d(C,{inverse:r,children:e})})}c(qo,"defaultRenderLabel");function Bo(r){return d(C,{})}c(Bo,"defaultRenderValue");const ye=c(({label:r,onPress:e,hotkey:t})=>d(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(()=>d(w,{children:d(C,{children:`${t?` (${t})`:""}`})}),"renderValue")}),"ActionTreeItem"),En=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(ve,{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(w,{children:n||!l?d(C,{dimColor:!0,children:m}):v(Ke,{children:[d(w,{width:m.length+1,children:d(ln,{...i,focus:l,value:h,onChange:a})}),d(C,{dimColor:!0,children:" \u241B cancel"})]})})},"renderValue")})},"TreeTextField"),Wo=c(r=>d(En,{...r,mask:"*"}),"SecretField"),H=c(({children:r,showHelp:e=!1})=>{const t=at({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"),he((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(Et.Provider,{value:i,children:v(w,{flexDirection:"column",children:[d(ve,{isInitiallyExpanded:!0,label:"rootItem",children:r}),e&&d(w,{marginTop:1,flexDirection:"column",children:d(C,{dimColor:!0,children:"\u2191/\u2193 move \u2022 \u2190 collapse \u2022 \u2192 expand \u2022 Enter/Space select/edit \u2022 Esc exit"})})]})})},"TreeView");H.Item=ve,H.TextField=En;function we({label:r,elementType:e,isActionExcluded:t,toggleAction:n,generateCode:o}){const[i,s]=L([]),{fetchElements:a,getSyncedElementsByType:l}=Z();return Ce(()=>{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(ve,{label:r,children:i.map(u=>d(ve,{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 Jo({onComplete:r}){const{config:e,updateConfig:t,fetchElements:n,getSyncedElementsByType:o}=Z(),[i,s]=L(""),a=e,l=c(p=>{s(p),setTimeout(()=>s(""),2e3)},"setFlash"),u=c(async(p,y)=>{try{await t({[p]:y}),l("\u2705 Configuration updated!")}catch{l("\u274C Error updating configuration")}},"updateField"),h=c(async()=>{try{if(e){const p=fe.saveToFile(e);l(p?"\u2705 Configuration saved successfully!":"\u274C Failed to save configuration"),await n();const y=o(k.Action);await vt({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:y.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 p=fe.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 v(w,{flexDirection:"column",gap:1,children:[d(C,{bold:!0,color:"cyan",children:"\u2699\uFE0F Membrane Configuration Manager"}),d(w,{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(p=>u("workspaceKey",p),"onChange"),disabled:!0}),d(Wo,{label:"Workspace Secret",value:a?.workspaceSecret??"",onChange:c(p=>u("workspaceSecret",p),"onChange"),disabled:!0}),d(H.TextField,{label:"API URI",value:a?.apiUri??"",onChange:c(p=>u("apiUri",p),"onChange")}),d(H.TextField,{label:"Test Customer ID",value:a?.testCustomerId??"",onChange:c(p=>u("testCustomerId",p),"onChange")})]}),v(H.Item,{label:"Code Generation",isInitiallyExpanded:!0,children:[v(H.Item,{label:"Project Type",isInitiallyExpanded:!0,value:a?.projectType,renderValue:c(({value:p})=>d(C,{children:p==="typescript"?"TypeScript":p==="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(p=>u("outputDir",p),"onChange")})]}),v(H.Item,{label:"Workspace Elements",children:[d(we,{label:"Actions",elementType:k.Action,isActionExcluded:c(p=>a?.excludedActionKeys?.includes(p.key)??!1,"isActionExcluded"),toggleAction:c(p=>u("excludedActionKeys",[...a?.excludedActionKeys??[],p.key]),"toggleAction"),generateCode:c(p=>{(async()=>{try{await vt({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:[p]}}),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(w,{paddingX:2,children:d(C,{color:i.includes("\u2705")?"green":"red",children:i})})]})}c(Jo,"ConfigManager");const zo="membrane",Go=["**/node_modules/**","**/.git/**","**/.DS_Store","**/Thumbs.db","**/*.tmp","**/*.swp","**/*.swo","**/*.log","**/*.lock","**/.cache/**","**/.next/**","**/.vscode/**","**/.idea/**","**/.logs/**"];function J(r){return I.join(r,zo)}c(J,"getMembraneDir");const In=Ve(J(process.cwd()),".logs");class Ho{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`;yr(In,{recursive:!0});const i=Ve(In,o),s=this._logs.map(a=>`[${a.timestamp}] ${a.type?.toUpperCase()||"INFO"}: ${a.message}`).join(`
19
+ `);return wr(i,s,"utf-8"),i}catch(t){return console.error("Failed to save logs:",t),null}}}const g=new Ho,kn=new Wr;class xn{static{c(this,"RequestLogger")}constructor(e=Er){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=kn.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 kn.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 Vo(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(Vo,"createTrackedClient");class Yo{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 xn,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=Vo(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(`
20
+ Membrane API Error:`),a&&console.error(a),console.error(JSON.stringify(V(s),null,2))):Br(s)?(console.error(`
21
+ 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(`
22
+ Unexpected Error:`),a&&console.error(a),console.error(s)),s}return}},"executeRequest");return t?i():xn.withSkipErrorLog(i)}async generateAccessToken(e,t){return ct.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 Xt({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?lt.coerce(t):null,o=lt.coerce(e);return!!(n&&o&&lt.gte(n,o))}}const $=new Yo;async function $n(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($n,"getWorkspaceId");const 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}},Zo=["id","workspaceId","integrationId","createdAt","updatedAt","revision","archivedAt","baseUri","state","appliedToIntegrations","dependencies"],Pn=[k.Action,k.FieldMapping,k.Flow,k.DataSource,k.Package];class K{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||K.extractIntegrationKey(o)}get id(){return K.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(J(process.cwd()),this.path)}get absolutePath(){return I.resolve(I.join(J(process.cwd()),this.path))}isEqual(e){if(this.id!==e.id)return!1;const t=this.clean(),n=e.clean();return zr(t,n)}hasParent(){if(this.data?.parentUuid)return!0;const e=this.getParentKey();return!!e&&!!this.data?.[e]}clean(){const e={...this.data};return Zo.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 K(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 K(e,t.key,n,t)}static fromPathAndData(e,t){const n=K.parsePath(e);if(!t)return;const o=t?.key||n?.key;return n?K.new(n.type,o,n.integrationKey,t):void 0}static fromElement(e){return new K(e.type,e.key,e.integrationKey,{...e.data})}static idFromPath(e){const t=K.parsePath(e);if(t)return K.makeId(t.type,t.key,t.integrationKey)}static makeId(e,t,n){return e===k.Integration?`${e}:${t}`:K.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(J(process.cwd()),e)}static isIntegrationSpecific(e){return Pn.includes(e)}static canBeIntegrationSpecific(e){return Pn.includes(e)}}function It(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(It,"readYaml$1");function Xo(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(Xo,"writeYaml$1");class An{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){}}class Qo extends An{static{c(this,"LocalWorkspaceElementsRepository")}basePath;constructor(e){super(e),this.basePath=J(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}),Xo(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=It(e);if(t)return K.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 ei extends An{static{c(this,"RemoteWorkspaceElementsRepository")}async getElementsByType(e,t){const n=K.canBeIntegrationSpecific(e),o=await this.findAll(e,n?{layer:"universal"}:{});if(!K.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 K.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=K.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=K.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=>K.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 K.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),K.fromData(e,i))):[]}}class kt 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"},ti={ignored:Go,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 ni extends kt{static{c(this,"LocalElementWatcher")}constructor(e){super(),this.options=e,this.membraneDir=J(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=Gr.watch(this.membraneDir,ti),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?Yr.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 Hr.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 xt=(r=>(r.Updated="updated",r.ConnectorFileUpdated="connector-file-updated",r.Connected="connected",r.Disconnected="disconnected",r.Error="error",r))(xt||{});const ri={debounceMs:2e3,reconnectIntervalMs:5e3,maxReconnectAttempts:1/0,maxBackoffMs:6e4,connectionTimeoutMs:3e5};class oi extends kt{static{c(this,"RemoteElementWatcher")}constructor(e=ri){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 Xr(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!==Ir.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 On{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 Te="connectors",ne="development",$t={};async function Rn(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 Pt(u);if(!m)continue;e?.("pushing",m.name),"baseUri"in m&&delete m.baseUri;let p;m.uuid&&(p=await $.withClient(S=>S.get(`/connectors/${m.uuid}`),!1));const y=m.uuid;if(p)i[y]=p.id,g.info(`[connectors] Matched ${m.name} uuid: ${m.uuid}`),p.isPublic||(p.archivedAt&&(g.info(`[connectors] Restoring archived connector ${m.name}`),await $.withClient(S=>S.post(`connectors/${p.id}/restore`))),g.info(`[connectors] Updating connector ${m.name}`),await $.withClient(S=>S.patch(`connectors/${p.id}`,{...m,workspaceId:o})));else if(!i[y]&&!p?.isPublic){let S=!1;try{const N=await At({connectorId:y});N&&N.isPublic&&(S=!0)}catch{}if(!S){g.info(`[connectors] Creating custom connector ${m.name} (${m.key})`);const N=await $.withClient(R=>R.post("connectors",{...m,workspaceId:o}));i[y]=N.id}}const E=h.filter(S=>O.statSync(x.join(s,u,S)).isDirectory());for(const S of E)await ai({connector:m,version:S,connectorId:i[y]}),t.add(y);e?.("pushed",m.name)}return{connectorsMapping:i,pushedConnectors:Array.from(t)}}c(Rn,"pushConnectors");async function Nn({connectorId:r,connectorVersion:e,allConnectors:t,pulledConnectors:n,pulledConnectorVersions:o}){if(!r||o[r]?.has(e))return;const i=mn(),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 ci({basePath:i,connector:s}),n.add(r)),o[r]||(o[r]=new Set),o[r].has(e)||(await li({connector:s,connectorVersion:e,basePath:i}),o[r].add(e))}}c(Nn,"pullRemoteConnector");function ie(){const r=ft();return x.join(r.membraneDirPath,Te)}c(ie,"getConnectorsPath");async function Pt(r){const e=x.join(ie(),r,`${r}.yml`);return It(e,!1)}c(Pt,"readConnector");async function ii(r,e){return g.info(`[connectors] Zipping ${r} into ${e}`),new Promise((t,n)=>{const o=O.createWriteStream(e),i=ut("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(ii,"createZipArchive");async function si(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(si,"extractZipArchive");async function ai({connector:r,version:e,connectorId:t}){const n=x.join(ie(),re(r),Dn(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 ii(o,i)),!O.existsSync(i)){g.warning(`[connectors] No source code found for ${r.name} version ${e}`);return}try{const a=new dn;if(a.append("file",O.createReadStream(i),"file.zip"),g.info(`[connectors] Pushing connector version ${e} for ${r.name}`),e==ne)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(ai,"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 ci({basePath:r,connector:e}){const t=re(e),n=x.join(r,Te,t);O.mkdirSync(n,{recursive:!0});const o=x.join(n,`${re(e)}.yml`);O.writeFileSync(o,Y.dump(e)),g.info(`[connectors] Pulled connector ${e.name}`)}c(ci,"pullConnector$1");async function li({connector:r,connectorVersion:e,basePath:t}){const n=re(r),o=Dn(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 si(s,l)}g.info(`[connectors] Pulled connector version: ${r.name} (${o})`)}c(li,"pullConnectorVersion");function re(r){return r.key}c(re,"getConnectorDirName");function Dn(r){return r??ne}c(Dn,"getConnectorVersionDirName");function ui(r){const e=mn(),t=re(r);return x.join(e,Te,t)}c(ui,"getConnectorDirPath");function di(r){return r.match(`${Te}/[^/]+/${ne}/src/.*`)!==null}c(di,"isConnectorSourceFile");async function hi(r){const e=r.match(`${Te}/([^/]+)/${ne}/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=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(hi,"putConnectorFile");async function pi(r){const e=r.match(`${Te}/([^/]+)/${ne}/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(pi,"deleteConnectorFile");async function fi(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=re(t),i=x.join(ie(),o,ne,"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(fi,"pullConnectorFile");async function mi(r,e){const t=await $.withClient(i=>i.get(`connectors/${r}`),!1);if(!t){g.warning(`[connectors] Connector ${r} not found`);return}const n=re(t),o=x.join(ie(),n,ne,"src",e);O.existsSync(o)&&(O.unlinkSync(o),g.info(`[connectors] Deleted file ${e} for connector ${n}`))}c(mi,"deleteLocalConnectorFile");async function gi(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=re(n),i=x.join(ie(),o,ne,"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(gi,"renameLocalConnectorDirectory");async function yi(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=re(t),o=x.join(ie(),n,ne,"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(yi,"deleteLocalConnectorDirectory");const _={LogAdded:"logAdded",StateChanged:"stateChanged",StatsChanged:"statsChanged",ConflictsChanged:"conflictsChanged",McpStatusChanged:"mcpStatusChanged",McpServersChanged:"mcpServersChanged",ConfigChanged:"configChanged"};class wi extends kt{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(_.StateChanged,{state:e}),await this.emitRemote({status:e})}setConflicts(e){this.emit(_.ConflictsChanged,{conflicts:e})}setConfig(e){this.emit(_.ConfigChanged,{config:e})}setStats(e){this.emit(_.StatsChanged,{stats:e})}addLog(e){this.emit(_.LogAdded,{log:e})}setMcpStatus(e){this.emit(_.McpStatusChanged,{status:e})}async setMcpServers(e){this.emit(_.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 wi({heartbeatIntervalMs:15e3}),oe={UPDATE:"update",DELETE:"delete",CREATE:"create"},z={INCOMING:"incoming",OUTGOING:"outgoing"},Ln=[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 On,this.remoteCache=new On,this.localRepo=new Qo(this.localCache),this.remoteRepo=new ei(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 Nn({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===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 ni({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 oi,this.remoteWatcher.on(xt.Updated,({elementId:e,elementType:t})=>this.handleRemoteElementEvent(e,t)),this.remoteWatcher.on(xt.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 At({connectorId:s});if(!l?.key)return;const u=ui(l);await this.localWatcher?.executeWithPathLock(u,async()=>Nn({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 mi(e,t);break;case Ye.ConnectorDirectoryRenamed:await gi(e,t,o);break;case Ye.ConnectorDirectoryDeleted:await yi(e,t);break;default:await fi(e,t);break}}catch(i){g.error(`[sync] Error handling remote connector file event: ${i}`)}}async handleLocalEvent(e,t){try{if(di(e.filePath))switch(t){case G.Updated:await hi(e.filePath);break;case G.Deleted:await pi(e.filePath);break}else{let n=K.fromPathAndData(e.filePath,e.data);if(!n){const o=K.idFromPath(e.filePath);if(!o||(n=this.remoteCache.get(o),!n))return}switch(g.info(`[${this.getDirectionLabel(z.OUTGOING)}] ${Jr(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 Ln){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 Ln){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 oe.DELETE:return this.deleteElement(e.element,e.direction);case oe.CREATE:return this.updateElement(e.element,e.direction);case oe.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:oe.CREATE,element:e,direction:n,isConflict:!1}:!e&&t?{type:oe.DELETE,element:t,direction:n,isConflict:!0}:e&&t&&!e.isEqual(t)?{type:oe.UPDATE,element:e,direction:n,isConflict:!1}:null}}const ae=I.join(Qr.tmpdir(),"membrane-mcp-status"),Mn=3e4;class Ci{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=Nt(r,t);if(T.existsSync(n)){const o=T.statSync(n),i=new Date;if(i.getTime()-o.mtime.getTime()>Mn)return Ae(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>Mn)return Ae(r,t),null}return l}}catch{r&&e&&Ae(r,e)}return null}c(Je,"getMcpStatus");function jn(r){try{const e=r||process.cwd(),t=Rt(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 Ot(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=Nt(r.processId,r.cwd);T.writeFileSync(n,JSON.stringify(t,null,2))}catch{}}c(Ot,"updateMcpStatus");function Ae(r,e){try{const t=e||process.cwd();if(r){const n=Nt(r,t);T.existsSync(n)&&T.unlinkSync(n)}else{const n=Rt(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(Ae,"clearMcpStatus");function Si(r,e){const t=Je(r,e);t&&Ot({processId:r,cwd:e,totalRequests:t.totalRequests+1,lastRequestTime:new Date().toISOString(),lastActivity:new Date().toISOString()})}c(Si,"trackToolExecution");function Rt(r){return Vr("md5").update(r).digest("hex").slice(0,8)}c(Rt,"getCwdHash");function Nt(r,e){const t=Rt(e);return I.join(ae,`mcp-${t}-${r}.json`)}c(Nt,"getStatusFilePath");const ze={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 bi{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 Ci,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(),fe.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=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()})}}function vi({children:r,membraneCLIService:e}){const{data:t}=un("/account"),[n,o]=L(P.NOT_INITIALIZED),[i,s]=L([]),[a,l]=L({}),[u,h]=L([]),[m,p]=L(null),E=t?.workspaces?.find(S=>S.workspaceKey===m?.workspaceKey)||null;return Ce(()=>{const S=c(({state:F})=>o(F),"handleStateChanged"),N=c(({stats:F})=>l(F),"handleStatsChanged"),R=c(({log:F})=>h(Le=>[...Le,F]),"handleLogAdded"),j=c(({conflicts:F})=>s(F),"handleConflictsUpdated"),U=c(({config:F})=>p(F),"handleConfigChanged");return e.notifier.on(_.StateChanged,S),e.notifier.on(_.StatsChanged,N),e.notifier.on(_.LogAdded,R),e.notifier.on(_.ConflictsChanged,j),e.notifier.on(_.ConfigChanged,U),e.init(),()=>{e.notifier.off(_.StateChanged,S),e.notifier.off(_.StatsChanged,N),e.notifier.off(_.LogAdded,R),e.notifier.off(_.ConflictsChanged,j),e.notifier.off(_.ConfigChanged,U)}},[]),d(vn.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(vi,"MembraneCLIServiceProvider");const Fn=it(process.cwd());function Ti(){return st(Fn)}c(Ti,"useCwd");function Ei({cwd:r,children:e}){return d(Fn.Provider,{value:r,children:e})}c(Ei,"CwdProvider");function Dt({cwd:r,children:e,membraneCLIService:t}){const n=r||process.cwd();return d(Ei,{cwd:n,children:d(qr,{value:{fetcher:ko()},children:d(vi,{membraneCLIService:t,children:e})})})}c(Dt,"Layout");function Ii(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(`
23
+ `)).action(()=>{ot(pe.createElement(Dt,{membraneCLIService:e,children:pe.createElement(Jo,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(Ii,"setupConfigCommand");function Un(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(Un,"sleep");function Kn(r){return r.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}c(Kn,"escapeHtml");const ki="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="${ki}">
24
+ <div style="text-align:center"><h1>${Kn(r)}</h1><p style="color:${n}">${Kn(e)}</p></div>
25
+ </body></html>`}c(ce,"htmlPage");async function Lt(r,e){return r.post("/connection-requests",e)}c(Lt,"createConnectionRequest");function _n(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(_n,"printConnectionRequestResult");const xi=3e3,$i=1800*1e3;function Pi(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("--connectorKey <key>","Connector key").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 --connectorKey hubspot --workspaceKey my-workspace"," membrane connect --connectionId abc --non-interactive",""].join(`
26
+ `)).action(async e=>{try{await Ai(e)}catch(t){q(t)}})}c(Pi,"setupConnectCommand");async function Ai(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 W({workspaceKey:r.workspaceKey,tenantKey:r.tenantKey}),n=!!(process.stdin.isTTY&&!r.nonInteractive),o={integrationId:r.integrationId,integrationKey:r.integrationKey,connectorId:r.connectorId,connectorKey:r.connectorKey,connectorVersion:r.connectorVersion,connectionId:r.connectionId,name:r.name,allowMultipleConnections:r.allowMultipleConnections,connectorParameters:e};if(!n){const h=await Lt(t,o);_n(h),process.exit(0);return}const i=eo(),{port:s,server:a,waitForCallback:l}=await Oi(i),u=`http://127.0.0.1:${s}/callback?nonce=${i}`;try{const h=await Lt(t,{...o,redirectUri:u}),m=h.url;try{const{default:U}=await import("open");await U(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
27
  ${m}
31
- `);const p=Ce("Waiting for connection to complete...").start(),y=new AbortController,E=c(()=>{y.abort(),p.stop(),a.closeAllConnections(),a.close(),process.exit(130)},"onSigint");process.once("SIGINT",E);const S=l,N=Ui(t,h.requestId,y.signal);N.catch(()=>{});const R=await Promise.race([S,N]);if(y.abort(),p.stop(),process.removeListener("SIGINT",E),R.cancelled&&(b.warning("Connection was cancelled."),process.exit(0)),R.error)throw new Error(`Connection failed: ${R.error}`);if(!R.connectionId)throw new Error("Connection completed but no connection ID received");const j=await t.get(`/connections/${R.connectionId}`);b.success("Connection created successfully!"),console.error(),console.error(` Connection ID: ${j.id}`),j.name&&console.error(` Name: ${j.name}`),j.integrationId&&console.error(` Integration ID: ${j.integrationId}`),j.connectorId&&console.error(` Connector ID: ${j.connectorId}`),console.error(),process.exit(0)}finally{a.closeAllConnections(),a.close()}}c(ji,"runConnect");function Fi(r){return new Promise(e=>{let t;const n=new Promise(i=>{t=i}),o=fn((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(Fi,"startConnectionCallbackServer");async function Ui(r,e,t){const n=Date.now()+Li;for(;Date.now()<n;){t.throwIfAborted(),await Zn(Di,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(Ui,"pollConnectionRequest");function Ki(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("--limit <n>","Max results").option("--cursor <cursor>","Pagination cursor").option("--json","Output as JSON").action(async t=>{try{const o={...e.opts(),...t},i=new J(o),s=new URLSearchParams;t.limit&&s.set("limit",t.limit),t.cursor&&s.set("cursor",t.cursor);const a=s.toString(),l=await i.get(`/connections${a?`?${a}`:""}`);if(o.json)process.stdout.write(JSON.stringify(l,null,2)+`
32
- `);else{const u=l.items??[];if(u.length===0)console.error(f.gray(" No connections found."));else for(const h of u){const m=h.disconnected?f.red("disconnected"):f.green("connected");console.error(` ${f.cyan(h.id)} ${h.name||f.gray("(unnamed)")} ${m}`)}l.cursor&&console.error(f.gray(` Returned ${u.length} elements. Run with --cursor ${l.cursor} to get the next page.`)),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(),A("ID",a.id),a.name&&A("Name",a.name),a.connectorId&&A("Connector",a.connectorId),a.integrationId&&A("Integration",a.integrationId),A("Status",a.disconnected?f.red("disconnected"):f.green("connected")),console.error())}catch(o){q(o)}})}c(Ki,"setupConnectionCommand");function _i(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
- `):Qn(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(),A("Request ID",s.requestId,16),A("Status",s.status,16),s.resultConnectionId&&A("Connection ID",s.resultConnectionId,16),s.resultError&&A("Error",typeof s.resultError=="string"?s.resultError:JSON.stringify(s.resultError),16),console.error())}catch(o){q(o)}})}c(_i,"setupConnectionRequestCommand");function qi({currentPat:r,onSubmit:e}){const[t,n]=L(""),[o,i]=L(!1),[s,a]=L(null),l=ft(`/w/0/${Pr}`);return v(w,{flexDirection:"column",borderStyle:"round",borderTop:!0,width:70,paddingX:1,children:[d(w,{marginTop:-1,marginBottom:1,children:d(C,{bold:!0,children:"\u{1F511} Enter your Personal Access Token"})}),d(C,{children:"Please provide your Personal Access Token. You can find it here:"}),d(w,{marginTop:1,marginBottom:1,children:d(C,{color:"yellow",children:l})}),r&&d(C,{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(w,{marginTop:1,children:v(C,{children:[d(qe,{type:"dots"})," Validating token..."]})}),s&&d(C,{color:"red",children:s})]})}c(qi,"PersonalAccessTokenInput");function er({onExit:r,showEscOption:e=!0}){const[t,n]=L(""),{data:o,error:i,isLoading:s}=hn("/account"),{updateConfig:a}=Z(),l=o?.workspaces,u=s;if(pe((S,N)=>{N.escape&&r?.()}),u)return v(w,{children:[d(qe,{}),d(C,{children:" Fetching workspaces..."})]});if(i)return v(w,{flexDirection:"column",children:[v(C,{color:"red",children:["Error: ",i.message]}),d(w,{marginTop:1,children:d(C,{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})),p=m.length,y=l?.length??0;async function E(S){const N=h.find(U=>U.id===S);if(!N)return;const{key:R,secret:j}=N;!R||!j||(await a({workspaceKey:R,workspaceSecret:j}),r?.())}return c(E,"handleSelect"),v(w,{flexDirection:"column",borderStyle:"round",borderTop:!0,width:70,paddingX:1,children:[d(w,{marginTop:-1,children:d(C,{bold:!0,children:"\u{1F4C1} Select your workspace"})}),v(w,{marginTop:1,children:[d(C,{children:"Search: "}),d(ro,{placeholder:"Enter a search query...",onChange:n})]}),y>5&&v(C,{children:["Showing ",p," of ",y," workspaces."]}),d(w,{marginTop:1,children:d(oo,{options:m,onChange:c(S=>{S&&E(S)},"onChange")})}),e&&d(w,{marginTop:1,children:d(C,{color:"grey",children:"Press ESC to go back"})})]})}c(er,"SelectWorkspace");var Ne=(r=>(r[r.Authenticate=0]="Authenticate",r[r.ConnectWorkspace=1]="ConnectWorkspace",r))(Ne||{});const Bi={0:"Authenticate in Membrane",1:"Connect a Membrane Workspace"},Kt=[Ne.Authenticate,Ne.ConnectWorkspace];function tr({onComplete:r}){const{config:e}=Z(),[t,n]=L(!1),[o,i]=L(0),s=!!(e?.workspaceKey&&e?.workspaceSecret),a=yn(),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:Bi[E],status:N}});async function p(E){const S=a&&E===""?a:E,N=new Pe;try{await N.request("/account",{headers:{Authorization:`Bearer ${S}`}}),So(S),i(R=>R+1)}catch(R){console.error(R)}}c(p,"handlePatSubmit");function y(){n(!0),r&&r()}return c(y,"handleWorkspaceSelected"),pe((E,S)=>{s&&S.escape&&r&&r()}),t?d(w,{children:d(C,{children:"\u2705 Setup complete. You are ready to go!"})}):v(w,{flexDirection:"column",alignSelf:"flex-start",gap:1,children:[v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:70,children:[d(w,{marginTop:-1,marginBottom:1,children:v(C,{bold:!0,children:["\u{1F6E0}\uFE0F Setup \u2014"," ",v(C,{color:"cyan",children:["Step ",u," of ",h]}),s&&d(C,{color:"grey",children:" [esc: go back]"})]})}),d(w,{flexDirection:"column",paddingLeft:2,children:m.map(E=>d(Wi,{status:E.status,label:E.label},E.id))})]}),l===Ne.Authenticate&&d(qi,{currentPat:a,onSubmit:p}),l===Ne.ConnectWorkspace&&d(er,{onExit:y,showEscOption:!1})]})}c(tr,"Setup");function Wi({status:r,label:e}){return v(w,{children:[v(w,{width:2,children:[r==="current"&&d(qe,{type:"dots"}),r==="done"&&d(C,{children:"\u2705"})]}),d(C,{dimColor:r!=="current",children:e})]})}c(Wi,"StepDisplay");function Ji(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(tr,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(Ji,"setupInitCommand");function zi(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 rr(t);return}b.header("Logging in to Membrane");const o=t.tenant?tn:nn,i=await Vi(t.apiUri,o);nr(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 rr(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 Hi(t)}catch(n){q(n)}})}c(zi,"setupLoginCommand");function nr(r,e){bo(),wn(r.accessToken,r.refreshToken,r.expiresIn),Cn(e.apiUri),Eo(e.tenant?"tenant":"platform-user"),r.defaultWorkspaceKey&&Ko({defaultWorkspaceKey:r.defaultWorkspaceKey,defaultTenantKey:r.defaultTenantKey})}c(nr,"storeTokens");async function rr(r){b.header("Starting non-interactive login");const e=r.tenant?tn:nn,{consentUrl:t,codeVerifier:n,clientId:o}=await Gi(r.apiUri,e);Cn(r.apiUri),Io({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(rr,"performLoginStart");async function Gi(r,e){const t=or(),n=ir(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(Gi,"prepareNonInteractiveLogin");async function Hi(r){const e=me()||te,t=xo();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(),nr(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(Hi,"performLoginComplete");async function Vi(r,e){const t=or(),n=ir(t),{port:o,waitForCode:i,state:s,server:a}=await Yi(),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}`,p=(await fetch(h,{redirect:"manual"})).headers.get("location");if(!p)throw a.close(),new Error("No redirect from authorization endpoint");const y=new URL(p).searchParams.get("authorizationId");if(!y)throw a.close(),new Error("No authorizationId in authorization redirect");try{const{default:U}=await import("open");await U(p),b.info("Opening browser for authentication...")}catch{b.info("Could not open browser automatically.")}console.error(` If the browser doesn't open, visit:
28
+ `);const p=Se("Waiting for connection to complete...").start(),y=new AbortController,E=c(()=>{y.abort(),p.stop(),a.closeAllConnections(),a.close(),process.exit(130)},"onSigint");process.once("SIGINT",E);const S=l,N=Ri(t,h.requestId,y.signal);N.catch(()=>{});const R=await Promise.race([S,N]);if(y.abort(),p.stop(),process.removeListener("SIGINT",E),R.cancelled&&(b.warning("Connection was cancelled."),process.exit(0)),R.error)throw new Error(`Connection failed: ${R.error}`);if(!R.connectionId)throw new Error("Connection completed but no connection ID received");const j=await t.get(`/connections/${R.connectionId}`);b.success("Connection created successfully!"),console.error(),console.error(` Connection ID: ${j.id}`),j.name&&console.error(` Name: ${j.name}`),j.integrationId&&console.error(` Integration ID: ${j.integrationId}`),j.connectorId&&console.error(` Connector ID: ${j.connectorId}`),console.error(),process.exit(0)}finally{a.closeAllConnections(),a.close()}}c(Ai,"runConnect");function Oi(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(Oi,"startConnectionCallbackServer");async function Ri(r,e,t){const n=Date.now()+$i;for(;Date.now()<n;){t.throwIfAborted(),await Un(xi,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(Ri,"pollConnectionRequest");function Ni(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 W(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 Lt(o,i);n.json?process.stdout.write(JSON.stringify(s,null,2)+`
29
+ `):_n(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 W(o).get(`/connection-requests/${encodeURIComponent(t)}`);o.json?process.stdout.write(JSON.stringify(s,null,2)+`
30
+ `):(console.error(),A("Request ID",s.requestId,16),A("Status",s.status,16),s.resultConnectionId&&A("Connection ID",s.resultConnectionId,16),s.resultError&&A("Error",typeof s.resultError=="string"?s.resultError:JSON.stringify(s.resultError),16),console.error())}catch(o){q(o)}})}c(Ni,"setupConnectionRequestCommand");function Di(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("--limit <n>","Max results").option("--cursor <cursor>","Pagination cursor").option("--json","Output as JSON").action(async t=>{try{const o={...e.opts(),...t},i=new W(o),s=new URLSearchParams;t.limit&&s.set("limit",t.limit),t.cursor&&s.set("cursor",t.cursor);const a=s.toString(),l=await i.get(`/connections${a?`?${a}`:""}`);if(o.json)process.stdout.write(JSON.stringify(l,null,2)+`
31
+ `);else{const u=l.items??[];if(u.length===0)console.error(f.gray(" No connections found."));else for(const h of u){const m=h.disconnected?f.red("disconnected"):f.green("connected");console.error(` ${f.cyan(h.id)} ${h.name||f.gray("(unnamed)")} ${m}`)}l.cursor&&console.error(f.gray(` Returned ${u.length} elements. Run with --cursor ${l.cursor} to get the next page.`)),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 W(i).get(`/connections/${encodeURIComponent(t)}`);i.json?process.stdout.write(JSON.stringify(a,null,2)+`
32
+ `):(console.error(),A("ID",a.id),a.name&&A("Name",a.name),a.connectorId&&A("Connector",a.connectorId),a.integrationId&&A("Integration",a.integrationId),A("Status",a.disconnected?f.red("disconnected"):f.green("connected")),console.error())}catch(o){q(o)}})}c(Di,"setupConnectionCommand");async function Mt(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(y=>setTimeout(y,a));let p;try{p=await r.get(`background-jobs/${i}`),h=0}catch(y){if(y instanceof kr&&h<u){h++,g.debug(`[background-job] Job ${n} not found, retrying (${h}/${u})`);continue}throw y}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 y=p.error?.message||"Unknown error";throw g.error(`[background-job] Failed job ${n}: ${y}`),p.error?.stack&&g.error(`Stacktrace: ${p.error.stack}`),new Error(`Background job ${n} failed: ${y}`)}g.debug(`[background-job] Polling job ${n} (status: ${p.status})`)}}c(Mt,"pollBackgroundJob");const qn=1e3,Bn=12e4;async function Wn(){const r=await $.withClient(async t=>Mt(t,()=>t.get("export"),{pollIntervalMs:qn,timeoutMs:Bn}));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 Jn(r,e={}){const t=new dn;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 Mt(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(Jn,"importWorkspace");async function Li(r,e){const t=await $.withClient(async o=>Mt(o,()=>o.get(`connectors/${r}/export-files`,{version:e}),{pollIntervalMs:qn,timeoutMs:Bn}));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(Li,"exportConnector");function zn(r,e){Oe(I.dirname(r)),T.writeFileSync(r,e)}c(zn,"writeFile");function Mi(r){T.existsSync(r)&&T.rmSync(r)}c(Mi,"deleteFile");function jt(r){T.existsSync(r)&&T.rmSync(r,{recursive:!0,force:!0})}c(jt,"deleteDir");function ji(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(ji,"readYaml");function Gn(r,e,t){try{Oe(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(Gn,"writeYaml");function Oe(r){T.existsSync(r)||T.mkdirSync(r,{recursive:!0})}c(Oe,"ensureDirExists");function Hn(r,e=!0){if(!T.existsSync(r)||!T.statSync(r).isDirectory())return;let t=T.readdirSync(r);t.length>0&&(t.forEach(n=>Hn(I.join(r,n),!1)),t=T.readdirSync(r)),t.length===0&&!e&&T.rmdirSync(r)}c(Hn,"cleanupEmptyFolders");function Fi(r){const e=r.split(/[\\/]/).join("/");return e.endsWith("/")?e+"**":e}c(Fi,"normalizePattern");async function Vn(r,e,t){const n=(e??[]).map(Fi),o=[];if(t){const i=I.join(J(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:xr(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 p=m===""?"development":m,y=I.join(l,p,"src"),E=I.join(l,p,"src.zip"),S=m===""?Ze:m;T.existsSync(y)?o.push({name:Qt(a,S),content:await Ui(y)}):T.existsSync(E)&&o.push({name:Qt(a,S),content:T.readFileSync(E)})}}}return new Promise((i,s)=>{const a=ut("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 p of m){const y=u.get(p.integrationUuid),E=$r(h,p.key,y);n.length>0&&!n.some(S=>no(E,S))||a.append(Y.dump(p),{name:E})}for(const{name:h,content:m}of o)a.append(m,{name:h});a.finalize()})}c(Vn,"createMembraneZip");async function Ui(r){return new Promise((e,t)=>{const n=ut("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(Ui,"createConnectorVersionZip");async function Ft(r,e){const t=await fn.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(Ft,"iterateZipItems");async function Yn(r){const e=await fn.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(Yn,"readMembraneZip");async function Ut(r=process.cwd()){const e=await Zn(J(r)),t={};for(const{data:n,type:o}of e)t[o]||(t[o]=[]),t[o].push(n);return t}c(Ut,"readMembraneDir");async function Zn(r){const e=Xn(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(Zn,"iterateMembraneFiles");function Xn(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(...Xn(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(Xn,"getMembraneFiles");function Qn(){const r={},e=I.join(J(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=ji(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(Qn,"readConnectorsDir");function Re(r,e){const t=I.join(J(process.cwd()),"connectors",r);return e==""||e===Ze?I.join(t,"development"):e?I.join(t,e):t}c(Re,"getConnectorPath");function Ki(r){r.command("diff").description("Show what would change on push without applying anything").action(async()=>{const e=Se({text:"Comparing workspace",color:"white"}).start();try{const t=await Ut();e.text="Downloading remote workspace";const n=await Wn(),o=await Yn(n);e.stop();const{changes:i,diff:s}=en(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)
33
+ `),s&&b.info(_i(s))}catch(t){e.stop(),b.error("\u25A0 Error"),b.error(`\u2514\u2500\u2500 ${t.message}`),process.exit(1)}})}c(Ki,"setupDiffCommand");function _i(r){return r.split(`
34
+ `).map(e=>e.startsWith("diff ")?f.bold(e):e.startsWith("index ")||e.startsWith("===")?f.dim(e):e.startsWith("---")?f.bold.red(e):e.startsWith("+++")?f.bold.green(e):e.startsWith("@@")?f.cyan(e):e.startsWith("+")?f.green(e):e.startsWith("-")?f.red(e):e).join(`
35
+ `)}c(_i,"colorizePatch");var Ne=(r=>(r[r.Authenticate=0]="Authenticate",r[r.ConnectWorkspace=1]="ConnectWorkspace",r))(Ne||{});const qi={0:"Authenticate in Membrane",1:"Connect a Membrane Workspace"};function Bi({currentPat:r,onSubmit:e}){const[t,n]=L(""),[o,i]=L(!1),[s,a]=L(null),l=pt(`/w/0/${Pr}`);return v(w,{flexDirection:"column",borderStyle:"round",borderTop:!0,width:70,paddingX:1,children:[d(w,{marginTop:-1,marginBottom:1,children:d(C,{bold:!0,children:"\u{1F511} Enter your Personal Access Token"})}),d(C,{children:"Please provide your Personal Access Token. You can find it here:"}),d(w,{marginTop:1,marginBottom:1,children:d(C,{color:"yellow",children:l})}),r&&d(C,{dimColor:!0,children:"Press Enter to keep your current token or type a new one."}),d(ln,{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(w,{marginTop:1,children:v(C,{children:[d(qe,{type:"dots"})," Validating token..."]})}),s&&d(C,{color:"red",children:s})]})}c(Bi,"PersonalAccessTokenInput");function er({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(he((S,N)=>{N.escape&&r?.()}),u)return v(w,{children:[d(qe,{}),d(C,{children:" Fetching workspaces..."})]});if(i)return v(w,{flexDirection:"column",children:[v(C,{color:"red",children:["Error: ",i.message]}),d(w,{marginTop:1,children:d(C,{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})),p=m.length,y=l?.length??0;async function E(S){const N=h.find(U=>U.id===S);if(!N)return;const{key:R,secret:j}=N;!R||!j||(await a({workspaceKey:R,workspaceSecret:j}),r?.())}return c(E,"handleSelect"),v(w,{flexDirection:"column",borderStyle:"round",borderTop:!0,width:70,paddingX:1,children:[d(w,{marginTop:-1,children:d(C,{bold:!0,children:"\u{1F4C1} Select your workspace"})}),v(w,{marginTop:1,children:[d(C,{children:"Search: "}),d(ro,{placeholder:"Enter a search query...",onChange:n})]}),y>5&&v(C,{children:["Showing ",p," of ",y," workspaces."]}),d(w,{marginTop:1,children:d(oo,{options:m,onChange:c(S=>{S&&E(S)},"onChange")})}),e&&d(w,{marginTop:1,children:d(C,{color:"grey",children:"Press ESC to go back"})})]})}c(er,"SelectWorkspace");const Kt=[Ne.Authenticate,Ne.ConnectWorkspace];function tr({onComplete:r}){const{config:e}=Z(),[t,n]=L(!1),[o,i]=L(0),s=!!(e?.workspaceKey&&e?.workspaceSecret),a=Cn(),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:qi[E],status:N}});async function p(E){const S=a&&E===""?a:E,N=new Pe;try{await N.request("/account",{headers:{Authorization:`Bearer ${S}`}}),wo(S),i(R=>R+1)}catch(R){console.error(R)}}c(p,"handlePatSubmit");function y(){n(!0),r&&r()}return c(y,"handleWorkspaceSelected"),he((E,S)=>{s&&S.escape&&r&&r()}),t?d(w,{children:d(C,{children:"\u2705 Setup complete. You are ready to go!"})}):v(w,{flexDirection:"column",alignSelf:"flex-start",gap:1,children:[v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:70,children:[d(w,{marginTop:-1,marginBottom:1,children:v(C,{bold:!0,children:["\u{1F6E0}\uFE0F Setup \u2014"," ",v(C,{color:"cyan",children:["Step ",u," of ",h]}),s&&d(C,{color:"grey",children:" [esc: go back]"})]})}),d(w,{flexDirection:"column",paddingLeft:2,children:m.map(E=>d(Wi,{status:E.status,label:E.label},E.id))})]}),l===Ne.Authenticate&&d(Bi,{currentPat:a,onSubmit:p}),l===Ne.ConnectWorkspace&&d(er,{onExit:y,showEscOption:!1})]})}c(tr,"Setup");function Wi({status:r,label:e}){return v(w,{children:[v(w,{width:2,children:[r==="current"&&d(qe,{type:"dots"}),r==="done"&&d(C,{children:"\u2705"})]}),d(C,{dimColor:r!=="current",children:e})]})}c(Wi,"StepDisplay");function Ji(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)):ot(pe.createElement(Dt,{membraneCLIService:e,children:pe.createElement(tr,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(Ji,"setupInitCommand");function zi(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 rr(t);return}b.header("Logging in to Membrane");const o=t.tenant?tn:nn,i=await Vi(t.apiUri,o);nr(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 rr(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 Hi(t)}catch(n){q(n)}})}c(zi,"setupLoginCommand");function nr(r,e){Co(),Sn(r.accessToken,r.refreshToken,r.expiresIn),bn(e.apiUri),vo(e.tenant?"tenant":"platform-user"),r.defaultWorkspaceKey&&go({defaultWorkspaceKey:r.defaultWorkspaceKey,defaultTenantKey:r.defaultTenantKey})}c(nr,"storeTokens");async function rr(r){b.header("Starting non-interactive login");const e=r.tenant?tn:nn,{consentUrl:t,codeVerifier:n,clientId:o}=await Gi(r.apiUri,e);bn(r.apiUri),To({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(rr,"performLoginStart");async function Gi(r,e){const t=or(),n=ir(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(Gi,"prepareNonInteractiveLogin");async function Hi(r){const e=me()||te,t=Io();if(!t){b.error("No pending login found. Run `membrane login start` first."),process.exit(1);return}b.header("Completing login");const n=Se("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(),nr(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(Hi,"performLoginComplete");async function Vi(r,e){const t=or(),n=ir(t),{port:o,waitForCode:i,state:s,server:a}=await Yi(),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}`,p=(await fetch(h,{redirect:"manual"})).headers.get("location");if(!p)throw a.close(),new Error("No redirect from authorization endpoint");const y=new URL(p).searchParams.get("authorizationId");if(!y)throw a.close(),new Error("No authorizationId in authorization redirect");try{const{default:U}=await import("open");await U(p),b.info("Opening browser for authentication...")}catch{b.info("Could not open browser automatically.")}console.error(` If the browser doesn't open, visit:
38
38
  ${p}
39
- `);const E=Ce("Waiting for authorization...").start(),S=new AbortController,N=c(()=>{S.abort(),E.stop(),a.closeAllConnections(),a.close(),process.exit(130)},"onSigint");process.once("SIGINT",N);const R=i.then(async U=>{E.text="Exchanging authorization code...";const F=await fetch(`${r}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:"authorization_code",code:U,redirect_uri:l,client_id:Me,code_verifier:t})});if(!F.ok)throw new Error(`Token exchange failed: ${F.status} ${await F.text()}`);return _t(await F.json())}),j=Qi(r,y,t,S.signal);j.catch(()=>{});try{const U=await Promise.race([R,j]);return S.abort(),E.stop(),process.removeListener("SIGINT",N),U}finally{a.closeAllConnections(),a.close()}}c(Vi,"performInteractiveLogin");function or(){return pn(32).toString("base64url")}c(or,"generateCodeVerifier");function ir(r){return no("sha256").update(r).digest("base64url")}c(ir,"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 Yi(){const r=pn(16).toString("base64url");return new Promise(e=>{let t,n;const o=new Promise((s,a)=>{t=s,n=a}),i=fn((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(ce("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(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(Yi,"startCallbackServer");const Zi=900*1e3,Xi=5;async function Qi(r,e,t,n){const o=Date.now()+Zi;let i=Xi;for(;Date.now()<o;){n.throwIfAborted(),await Zn(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(Qi,"pollForTokens");function es(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.")}To(),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(es,"setupLogoutCommand");const ts=86400;async function ns(r,e,t,n){const o={iss:r,isAdmin:!0};return t&&(o.id=t),nt.sign(o,e,{expiresIn:ts})}c(ns,"generateMcpAccessToken");async function rs(r,e){return(await Ie.get(`${r}/docs-json`,{headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}})).data}c(rs,"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 sr(r){const e=r.match(/\{([^}]+)\}/g);return e?e.map(t=>t.slice(1,-1)):[]}c(sr,"extractPathParameters");function os(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 p of r.parameters)if(p.in==="path")u[p.name]=le(p.schema,!0,o).describe(p.description||`Path parameter: ${p.name}`);else if(p.in==="query"){const y=p.required===!0;h[p.name]=le(p.schema,y,o).describe(p.description||`Query parameter: ${p.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 p=r.requestBody.required===!0;if(r.requestBody.content["application/json"]){const y=r.requestBody.content["application/json"].schema;y?l.body=le(y,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 m=Object.keys(l).length>0?D.object(l):D.object({});return{name:s,description:a,parameters:m,async execute(p){try{const y=sr(e);if(y.length>0){if(!p.params)throw new Error(`Missing required path parameters: ${y.join(", ")}`);const U=y.filter(F=>!(F in p.params));if(U.length>0)throw new Error(`Missing required path parameters: ${U.join(", ")}`)}let E=`${n}${e}`;if(p.params)for(const[U,F]of Object.entries(p.params)){const Le=`{${U}}`;E.includes(Le)&&(E=E.replace(Le,String(F)))}const S=sr(E);if(S.length>0)throw new Error(`Unresolved path parameters: ${S.join(", ")}`);const N=new URLSearchParams;if(p.query)for(const[U,F]of Object.entries(p.query))F!=null&&N.append(U,String(F));N.toString()&&(E+=`?${N.toString()}`);const R={method:t.toUpperCase(),headers:{Authorization:`Bearer ${i}`}};p.body&&t.toLowerCase()!=="get"&&(r.requestBody?.content?.["application/json"]?(R.headers["Content-Type"]="application/json",R.data=p.body):r.requestBody?.content?.["application/octet-stream"]?(R.headers["Content-Type"]="application/octet-stream",R.data=p.body):r.requestBody?.content?.["text/plain"]?(R.headers["Content-Type"]="text/plain",R.data=p.body):(R.headers["Content-Type"]="application/json",R.data=p.body));const j=await Ie.request({url:E,...R});return{content:[{type:"text",text:j.data===""?"":JSON.stringify(j.data,null,2)}]}}catch(y){return Ie.isAxiosError(y)?{content:[{type:"text",text:`Error: ${y.response?.data?`HTTP ${y.response.status}: ${y.response.statusText} - ${JSON.stringify(y.response.data)}`:`HTTP ${y.response?.status||"unknown"}: ${y.message}`}`}],isError:!0}:y instanceof Error?{content:[{type:"text",text:`Error: API call failed: ${y.message}`}],isError:!0}:{content:[{type:"text",text:"Error: API call failed with unknown error"}],isError:!0}}}}}c(os,"createApiTool");function is(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=os(l,i,a,e,o,t);n.push(u)}}return n}c(is,"convertOpenApiToTools");function ss(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(`
39
+ `);const E=Se("Waiting for authorization...").start(),S=new AbortController,N=c(()=>{S.abort(),E.stop(),a.closeAllConnections(),a.close(),process.exit(130)},"onSigint");process.once("SIGINT",N);const R=i.then(async U=>{E.text="Exchanging authorization code...";const F=await fetch(`${r}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:"authorization_code",code:U,redirect_uri:l,client_id:Me,code_verifier:t})});if(!F.ok)throw new Error(`Token exchange failed: ${F.status} ${await F.text()}`);return _t(await F.json())}),j=Qi(r,y,t,S.signal);j.catch(()=>{});try{const U=await Promise.race([R,j]);return S.abort(),E.stop(),process.removeListener("SIGINT",N),U}finally{a.closeAllConnections(),a.close()}}c(Vi,"performInteractiveLogin");function or(){return hn(32).toString("base64url")}c(or,"generateCodeVerifier");function ir(r){return to("sha256").update(r).digest("base64url")}c(ir,"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 Yi(){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 p=l.searchParams.get("error_description")??"Authorization was denied";a.writeHead(200,{"Content-Type":"text/html"}),a.end(ce("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(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(Yi,"startCallbackServer");const Zi=900*1e3,Xi=5;async function Qi(r,e,t,n){const o=Date.now()+Zi;let i=Xi;for(;Date.now()<o;){n.throwIfAborted(),await Un(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(Qi,"pollForTokens");function es(r){r.command("logout").description("Log out of Membrane and revoke tokens").option("--apiUri <uri>","API base URI").action(async e=>{try{yt()||(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.")}bo(),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(es,"setupLogoutCommand");const ts=86400;async function ns(r,e,t,n){const o={iss:r,isAdmin:!0};return t&&(o.id=t),ct.sign(o,e,{expiresIn:ts})}c(ns,"generateMcpAccessToken");async function rs(r,e){return(await Ie.get(`${r}/docs-json`,{headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}})).data}c(rs,"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 sr(r){const e=r.match(/\{([^}]+)\}/g);return e?e.map(t=>t.slice(1,-1)):[]}c(sr,"extractPathParameters");function os(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 p of r.parameters)if(p.in==="path")u[p.name]=le(p.schema,!0,o).describe(p.description||`Path parameter: ${p.name}`);else if(p.in==="query"){const y=p.required===!0;h[p.name]=le(p.schema,y,o).describe(p.description||`Query parameter: ${p.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 p=r.requestBody.required===!0;if(r.requestBody.content["application/json"]){const y=r.requestBody.content["application/json"].schema;y?l.body=le(y,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 m=Object.keys(l).length>0?D.object(l):D.object({});return{name:s,description:a,parameters:m,async execute(p){try{const y=sr(e);if(y.length>0){if(!p.params)throw new Error(`Missing required path parameters: ${y.join(", ")}`);const U=y.filter(F=>!(F in p.params));if(U.length>0)throw new Error(`Missing required path parameters: ${U.join(", ")}`)}let E=`${n}${e}`;if(p.params)for(const[U,F]of Object.entries(p.params)){const Le=`{${U}}`;E.includes(Le)&&(E=E.replace(Le,String(F)))}const S=sr(E);if(S.length>0)throw new Error(`Unresolved path parameters: ${S.join(", ")}`);const N=new URLSearchParams;if(p.query)for(const[U,F]of Object.entries(p.query))F!=null&&N.append(U,String(F));N.toString()&&(E+=`?${N.toString()}`);const R={method:t.toUpperCase(),headers:{Authorization:`Bearer ${i}`}};p.body&&t.toLowerCase()!=="get"&&(r.requestBody?.content?.["application/json"]?(R.headers["Content-Type"]="application/json",R.data=p.body):r.requestBody?.content?.["application/octet-stream"]?(R.headers["Content-Type"]="application/octet-stream",R.data=p.body):r.requestBody?.content?.["text/plain"]?(R.headers["Content-Type"]="text/plain",R.data=p.body):(R.headers["Content-Type"]="application/json",R.data=p.body));const j=await Ie.request({url:E,...R});return{content:[{type:"text",text:j.data===""?"":JSON.stringify(j.data,null,2)}]}}catch(y){return Ie.isAxiosError(y)?{content:[{type:"text",text:`Error: ${y.response?.data?`HTTP ${y.response.status}: ${y.response.statusText} - ${JSON.stringify(y.response.data)}`:`HTTP ${y.response?.status||"unknown"}: ${y.message}`}`}],isError:!0}:y instanceof Error?{content:[{type:"text",text:`Error: API call failed: ${y.message}`}],isError:!0}:{content:[{type:"text",text:"Error: API call failed with unknown error"}],isError:!0}}}}}c(os,"createApiTool");function is(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=os(l,i,a,e,o,t);n.push(u)}}return n}c(is,"convertOpenApiToTools");function ss(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
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 ns(n,o,i),l=await rs(s,a),u=is(l,s,a),h=new so({name:"Membrane API",instructions:`This MCP server lets you interact with Membrane to configure, run, and troubleshoot integrations.
41
41
  Use it for anything related to Membrane or integrations.
42
- `,version:"1.0.0"});for(const y of u){const E=y.execute;y.execute=async S=>(xi(process.pid,process.cwd()),E(S)),h.addTool(y)}Lt({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(()=>{Lt({processId:process.pid,cwd:process.cwd(),lastActivity:new Date().toISOString()})},5e3),p=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 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 y=>{console.error("Uncaught exception:",y.message),await p(),process.exit(1)}),process.on("unhandledRejection",async y=>{console.error("Unhandled rejection:",y),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(ss,"setupMcpCommand");function as(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 vn(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(as,"setupOpenCommand");const ar=5;function cs(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 ls(e,t);t.stop(),fs(n.workspaceExport,n.connectors)}catch(n){t.stop(),gs(n),process.exit(1)}})}c(cs,"setupPullCommand");async function ls(r,e){const t=await bt(),n=await An(t),o=await In(),i=await On(o),{comparison:s}=Qt(t,i);s[ee.DELETE].size>0&&!r.force&&(await ms(s,n),b.error("Use --force to delete local elements"),process.exit(1));const l=await Rn(W(process.cwd()));for(const{filePath:m,data:p}of l)s[ee.DELETE].has(p.uuid)&&Ro(m);return Pn(W(process.cwd())),await St(o,(m,p)=>{if(de(m)&&(s[ee.CREATE].has(p.uuid)||s[ee.UPDATE].has(p.uuid))){const E=x.join(W(process.cwd()),m);$n(E,p)}}),{connectors:await $.isVersionAtLeast("1.8")?await us(o,e):await hs(i[k.Integration],e),workspaceExport:i}}c(ls,"pullWorkspace");async function us(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);Ae(x.dirname(i));const s=await o.buffer();if(xn(i,s),t.add(o.path.split("/")[1]),o.path.endsWith("/development/src.zip")){const a=x.join(x.dirname(i),"src");Ae(a),await(await _e.Open.buffer(s)).extract({path:a})}}return Array.from(t)}c(us,"extractConnectorsFromExport");async function ds(r,e,t){if(xn(x.join(Oe(r,e),"src.zip"),t),!e||e===Ye){const n=x.join(Oe(r,e),"src");Ae(n),await(await _e.Open.buffer(t)).extract({path:n})}}c(ds,"writeConnectorVersion");async function hs(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=Dn();for(const[l,{key:u,versions:h}]of Object.entries(i)){if(!t.has(l)){const p=Oe(u);Ct(p);continue}const m=t.get(l);for(const p of h)if(!m.has(p)){const y=Oe(u,p);Ct(y)}}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+=ar){const u=s.slice(l,l+ar);await Promise.all(u.map(([h,m])=>ps(h,Array.from(m),a)))}return Array.from(t.keys())}c(hs,"pullConnectorsLegacy");async function ps(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`);$n(l,s);for(const u of e){const h=await Oo(r,u);await ds(n.key,u,h)}t?.("pulled",i)}c(ps,"pullConnector");function fs(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(fs,"showStats$1");async function ms(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(ms,"showConflicts$1");async function gs(r){b.error("\u25A0 Error"),b.error(`\u2514\u2500\u2500 ${r.message}`),b.error(` ${r.stack}`)}c(gs,"showError$1");const B=[];for(let r=0;r<256;++r)B.push((r+256).toString(16).slice(1));function ys(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(ys,"unsafeStringify");let qt;const ws=new Uint8Array(16);function Cs(){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(ws)}c(Cs,"rng");const Ss=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto);var cr={randomUUID:Ss};function bs(r,e,t){if(cr.randomUUID&&!r)return cr.randomUUID();r=r||{};const n=r.random??r.rng?.()??Cs();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,ys(n)}c(bs,"v4");function vs(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 Ts(e,t,n)}catch(o){n.stop(),Rs(o),process.exit(1)}})}c(vs,"setupPushCommand");async function Ts(r,e,t){const n=r.length>0,o=await bt(),i=Dn(),s=ks(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 Es(l,n)&&(t.stop(),process.exit(1)));const u=a?Object.keys(i):await Is(t);t.start("Pushing workspace..."),await kn(l,{partial:n}),t.stop(),As(s,u),process.exit(0)}c(Ts,"pushWorkspace");async function Es(r,e){const t=await kn(r,{dryRun:!0,partial:e}),n=t[ee.DELETE].size>0;return n&&(await Os(t,r),b.error("Use --force to delete remote elements")),n}c(Es,"checkForConflicts");async function Is(r){return(await Wn({onProgress:c((t,n)=>{t==="pushing"?r.start(`Pushing connector ${n}...`):r.succeed(`Pushed connector ${n}`)},"onProgress")})).pushedConnectors??[]}c(Is,"pushConnectorsLegacy");function ks(r,e){const t=$s(r),n=Ps(t,e),o={};for(const[i,s]of Object.entries(t)){const a=i;o[a]=(s||[]).map(l=>xs(l,a,n))}return o}c(ks,"resolveLegacyIdReferences");function xs(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(xs,"resolveElementIds");function $s(r){const e={};for(const[t,n]of Object.entries(r))e[t]=(n||[]).map(o=>o.uuid?o:{...o,uuid:bs()});return e}c($s,"generateMissingUuids");function Ps(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(Ps,"buildIdToUuidLookup");function As(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(As,"showStats");async function Os(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(Os,"showConflicts");function Rs(r){b.error("\u25A0 Error"),b.error(`\u2514\u2500\u2500 ${r.message}`),b.error(` ${r.stack}`)}c(Rs,"showError");const lr=new Set(Object.values(Ar));function Bt(r,e=[]){return e.push(r),e}c(Bt,"collectOption");function ur(r,e,t){for(const n of e){const o=r.indexOf(n);if(o>0)return{key:r.slice(0,o).trim(),value:r.slice(o+n.length).trim()}}throw new Error(`${t} must be in key=value format`)}c(ur,"parseKeyValue");function Ns(r=[]){const e={};for(const t of r){const{key:n,value:o}=ur(t,[":","="],"--header");if(!n)throw new Error("--header key cannot be empty");e[n]=o}return e}c(Ns,"parseHeaderEntries");function dr(r=[],e){const t={};for(const n of r){const{key:o,value:i}=ur(n,["="],e);if(!o)throw new Error(`${e} key cannot be empty`);t[o]=i}return t}c(dr,"parseMapEntries");function Ds(r,e){if(r!==void 0){if(e)return r;try{return JSON.parse(r)}catch{return r}}}c(Ds,"parseData");function Ls(r){const[e,t=""]=r.split("?",2),n={},o=new URLSearchParams(t);for(const[i,s]of o.entries())n[i]=s;return{path:e,query:n}}c(Ls,"parsePathAndQuery");function Ms(r){r.command("request <connectionId> <path>").description("Make a curl-like HTTP request through a connection").option("--workspaceKey <key>","Workspace key").option("--tenantKey <key>","Tenant key (customer internalId)").option("-X, --method <method>","HTTP method (GET, POST, PUT, PATCH, DELETE)","GET").option("-H, --header <key:value>","Request header (repeatable)",Bt,[]).option("--query <key=value>","Query parameter (repeatable)",Bt,[]).option("--pathParam <key=value>","Path parameter replacement (repeatable)",Bt,[]).option("-d, --data <value>","Request body (JSON auto-parsed unless --rawData)").option("--rawData","Send --data as raw string").option("--json","Output full response object as JSON").action(async(e,t,n)=>{try{const o=(n.method||"GET").toUpperCase();if(!lr.has(o))throw new Error(`--method must be one of ${Array.from(lr).join(", ")}`);const i=new J(n),s=Ls(t),a=dr(n.query,"--query"),l={...s.query,...a},u=dr(n.pathParam,"--pathParam"),h=Ns(n.header),m=Ds(n.data,n.rawData),p={path:s.path,method:o};Object.keys(l).length>0&&(p.query=l),Object.keys(u).length>0&&(p.pathParameters=u),Object.keys(h).length>0&&(p.headers=h),m!==void 0&&(p.data=m);const y=await i.post(`/connections/${encodeURIComponent(e)}/request`,p);if(n.json){process.stdout.write(JSON.stringify(y,null,2)+`
42
+ `,version:"1.0.0"});for(const y of u){const E=y.execute;y.execute=async S=>(Si(process.pid,process.cwd()),E(S)),h.addTool(y)}Ot({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(()=>{Ot({processId:process.pid,cwd:process.cwd(),lastActivity:new Date().toISOString()})},5e3),p=c(async()=>{clearInterval(m),Ae(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",()=>{Ae(process.pid,process.cwd())}),process.on("uncaughtException",async y=>{console.error("Uncaught exception:",y.message),await p(),process.exit(1)}),process.on("unhandledRejection",async y=>{console.error("Unhandled rejection:",y),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(ss,"setupMcpCommand");function as(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 $n(process.cwd()),n=pt(`/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(as,"setupOpenCommand");const ar=5;function cs(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=Se({text:"Pulling workspace",color:"white"}).start();try{const n=await ls(e,t);t.stop(),fs(n.workspaceExport,n.connectors)}catch(n){t.stop(),gs(n),process.exit(1)}})}c(cs,"setupPullCommand");async function ls(r,e){const t=await Ut(),n=await Vn(t),o=await Wn(),i=await Yn(o),{comparison:s}=en(t,i);s[ee.DELETE].size>0&&!r.force&&(await ms(s,n),b.error("Use --force to delete local elements"),process.exit(1));const l=await Zn(J(process.cwd()));for(const{filePath:m,data:p}of l)s[ee.DELETE].has(p.uuid)&&Mi(m);return Hn(J(process.cwd())),await Ft(o,(m,p)=>{if(de(m)&&(s[ee.CREATE].has(p.uuid)||s[ee.UPDATE].has(p.uuid))){const E=x.join(J(process.cwd()),m);Gn(E,p)}}),{connectors:await $.isVersionAtLeast("1.8")?await us(o,e):await hs(i[k.Integration],e),workspaceExport:i}}c(ls,"pullWorkspace");async function us(r,e){e.text="Extracting connectors",jt(x.join(J(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(J(process.cwd()),o.path);Oe(x.dirname(i));const s=await o.buffer();if(zn(i,s),t.add(o.path.split("/")[1]),o.path.endsWith("/development/src.zip")){const a=x.join(x.dirname(i),"src");Oe(a),await(await _e.Open.buffer(s)).extract({path:a})}}return Array.from(t)}c(us,"extractConnectorsFromExport");async function ds(r,e,t){if(zn(x.join(Re(r,e),"src.zip"),t),!e||e===Ze){const n=x.join(Re(r,e),"src");Oe(n),await(await _e.Open.buffer(t)).extract({path:n})}}c(ds,"writeConnectorVersion");async function hs(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=Qn();for(const[l,{key:u,versions:h}]of Object.entries(i)){if(!t.has(l)){const p=Re(u);jt(p);continue}const m=t.get(l);for(const p of h)if(!m.has(p)){const y=Re(u,p);jt(y)}}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+=ar){const u=s.slice(l,l+ar);await Promise.all(u.map(([h,m])=>ps(h,Array.from(m),a)))}return Array.from(t.keys())}c(hs,"pullConnectorsLegacy");async function ps(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=Re(n.key),l=x.join(a,`${n.key}.yml`);Gn(l,s);for(const u of e){const h=await Li(r,u);await ds(n.key,u,h)}t?.("pulled",i)}c(ps,"pullConnector");function fs(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(fs,"showStats$1");async function ms(r,e){const t=r[ee.DELETE].size;b.info(`\u2299 Pull: conflicts detected \xB7 ${t}`),await Ft(e,(n,o)=>{de(n)&&r[ee.DELETE].has(o.uuid)&&b.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted in remote)`)})}c(ms,"showConflicts$1");async function gs(r){b.error("\u25A0 Error"),b.error(`\u2514\u2500\u2500 ${r.message}`),b.error(` ${r.stack}`)}c(gs,"showError$1");const B=[];for(let r=0;r<256;++r)B.push((r+256).toString(16).slice(1));function ys(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(ys,"unsafeStringify");let qt;const ws=new Uint8Array(16);function Cs(){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(ws)}c(Cs,"rng");const Ss=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto);var cr={randomUUID:Ss};function bs(r,e,t){if(cr.randomUUID&&!r)return cr.randomUUID();r=r||{};const n=r.random??r.rng?.()??Cs();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,ys(n)}c(bs,"v4");function vs(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=Se({text:"Pushing workspace",color:"white"}).start();try{await Ts(e,t,n)}catch(o){n.stop(),Rs(o),process.exit(1)}})}c(vs,"setupPushCommand");async function Ts(r,e,t){const n=r.length>0,o=await Ut(),i=Qn(),s=ks(o,i),a=await $.isVersionAtLeast("1.9"),l=await Vn(s,n?r:void 0,a?i:void 0);e.force||(t.text="Comparing workspace",await Es(l,n)&&(t.stop(),process.exit(1)));const u=a?Object.keys(i):await Is(t);t.start("Pushing workspace..."),await Jn(l,{partial:n}),t.stop(),As(s,u),process.exit(0)}c(Ts,"pushWorkspace");async function Es(r,e){const t=await Jn(r,{dryRun:!0,partial:e}),n=t[ee.DELETE].size>0;return n&&(await Os(t,r),b.error("Use --force to delete remote elements")),n}c(Es,"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 ks(r,e){const t=$s(r),n=Ps(t,e),o={};for(const[i,s]of Object.entries(t)){const a=i;o[a]=(s||[]).map(l=>xs(l,a,n))}return o}c(ks,"resolveLegacyIdReferences");function xs(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(xs,"resolveElementIds");function $s(r){const e={};for(const[t,n]of Object.entries(r))e[t]=(n||[]).map(o=>o.uuid?o:{...o,uuid:bs()});return e}c($s,"generateMissingUuids");function Ps(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(Ps,"buildIdToUuidLookup");function As(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(As,"showStats");async function Os(r,e){const t=r[ee.DELETE].size;b.info(`\u2299 Push: conflicts detected \xB7 ${t}`),await Ft(e,(n,o)=>{de(n)&&r[ee.DELETE].has(o.uuid)&&b.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted locally)`)})}c(Os,"showConflicts");function Rs(r){b.error("\u25A0 Error"),b.error(`\u2514\u2500\u2500 ${r.message}`),b.error(` ${r.stack}`)}c(Rs,"showError");const lr=new Set(Object.values(Ar));function Bt(r,e=[]){return e.push(r),e}c(Bt,"collectOption");function ur(r,e,t){for(const n of e){const o=r.indexOf(n);if(o>0)return{key:r.slice(0,o).trim(),value:r.slice(o+n.length).trim()}}throw new Error(`${t} must be in key=value format`)}c(ur,"parseKeyValue");function Ns(r=[]){const e={};for(const t of r){const{key:n,value:o}=ur(t,[":","="],"--header");if(!n)throw new Error("--header key cannot be empty");e[n]=o}return e}c(Ns,"parseHeaderEntries");function dr(r=[],e){const t={};for(const n of r){const{key:o,value:i}=ur(n,["="],e);if(!o)throw new Error(`${e} key cannot be empty`);t[o]=i}return t}c(dr,"parseMapEntries");function Ds(r,e){if(r!==void 0){if(e)return r;try{return JSON.parse(r)}catch{return r}}}c(Ds,"parseData");function Ls(r){const[e,t=""]=r.split("?",2),n={},o=new URLSearchParams(t);for(const[i,s]of o.entries())n[i]=s;return{path:e,query:n}}c(Ls,"parsePathAndQuery");function Ms(r){r.command("request <connectionId> <path>").description("Make a curl-like HTTP request through a connection").option("--workspaceKey <key>","Workspace key").option("--tenantKey <key>","Tenant key (customer internalId)").option("-X, --method <method>","HTTP method (GET, POST, PUT, PATCH, DELETE)","GET").option("-H, --header <key:value>","Request header (repeatable)",Bt,[]).option("--query <key=value>","Query parameter (repeatable)",Bt,[]).option("--pathParam <key=value>","Path parameter replacement (repeatable)",Bt,[]).option("-d, --data <value>","Request body (JSON auto-parsed unless --rawData)").option("--rawData","Send --data as raw string").option("--json","Output full response object as JSON").action(async(e,t,n)=>{try{const o=(n.method||"GET").toUpperCase();if(!lr.has(o))throw new Error(`--method must be one of ${Array.from(lr).join(", ")}`);const i=new W(n),s=Ls(t),a=dr(n.query,"--query"),l={...s.query,...a},u=dr(n.pathParam,"--pathParam"),h=Ns(n.header),m=Ds(n.data,n.rawData),p={path:s.path,method:o};Object.keys(l).length>0&&(p.query=l),Object.keys(u).length>0&&(p.pathParameters=u),Object.keys(h).length>0&&(p.headers=h),m!==void 0&&(p.data=m);const y=await i.post(`/connections/${encodeURIComponent(e)}/request`,p);if(n.json){process.stdout.write(JSON.stringify(y,null,2)+`
46
46
  `);return}const E=Object.prototype.hasOwnProperty.call(y,"data")?y.data:y;if(typeof E=="string"){process.stdout.write(`${E}
47
47
  `);return}process.stdout.write(JSON.stringify(E,null,2)+`
48
- `)}catch(o){q(o)}})}c(Ms,"setupRequestCommand");function js(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)+`
49
- `);else{const s=i.items??[];if(s.length===0)console.error(f.gray(" No results found."));else for(const a of s){const l=a.element,u=f.gray(`[${a.elementType}]`),h=l?.name||l?.key||"(unnamed)",m=f.cyan(String(l?.id??a.id??"(no id)"));console.error(` ${u} ${m} ${h}`)}console.error()}}catch(n){q(n)}})}c(js,"setupSearchCommand");const Fs="0";function Us(r){r.command("status").description("Show current login status, project settings, and resolved environment").action(async()=>{try{await Ks()}catch(e){q(e)}})}c(Us,"setupStatusCommand");async function Ks(){const r=me()||te,e=jn(),t=wt();if(console.error(),console.error(f.bold.cyan("\u25B6 Membrane CLI Status")),console.error(),A("API",r),!t)A("Auth",f.red("Not logged in"));else{const n=gt(),o=!!be(),i=yt();if(n&&!o)A("Auth",f.yellow("Token expired (no refresh token)"));else if(i==="tenant"){A("Auth",f.green("Logged in")+f.gray(" (tenant scope)"));try{const a=await new Pe().get("/self"),l=a.workspaceKey??e.defaultWorkspaceKey;l&&A("Workspace",l);const u=a.internalId??e.defaultTenantKey;a.name&&u?A("Tenant",`${a.name} (${u})`):a.name?A("Tenant",a.name):u&&A("Tenant",u)}catch{e.defaultWorkspaceKey&&A("Workspace",e.defaultWorkspaceKey),e.defaultTenantKey&&A("Tenant",e.defaultTenantKey)}}else{try{const a=await new Pe().get(`/account?workspaceId=${Fs}`);if(a.user?(A("Auth",f.green("Logged in")),A("User",`${a.user.name} (${a.user.email})`)):A("Auth",f.green("Logged in")),a.orgs?.length){const l=a.orgs.map(u=>u.name).join(", ");A("Orgs",l)}}catch{A("Auth",f.yellow("Logged in (could not fetch account details)"))}e.defaultWorkspaceKey&&A("Workspace",`${e.defaultWorkspaceKey} ${f.gray("(default)")}`),e.defaultTenantKey&&A("Tenant",`${e.defaultTenantKey} ${f.gray("(default)")}`),!e.defaultWorkspaceKey&&!e.defaultTenantKey&&A("Project",f.gray("No project defaults configured"))}}console.error()}c(Ks,"runStatus");const Wt=[{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 _s({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===" "?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(Wt.length-1,t+1));else if(S.return||E===" "){const N=Wt[t];a(N),i(!0)}});const p=c(E=>{try{const S=E.addConfig();u(S)}catch(S){m(`Failed to write configuration: ${S.message||S}`)}},"addMcpConfiguration"),y=Math.min(80,process.stdout.columns||80);return l?v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:y,children:[d(w,{marginTop:-1,marginBottom:1,children:v(C,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",d(C,{color:"green",children:"Success"})]})}),v(w,{flexDirection:"column",paddingLeft:2,children:[d(C,{color:"green",children:l}),d(w,{marginTop:1,children:d(C,{color:"grey",children:"The agent will now be able to use Membrane's integration capabilities."})})]}),d(w,{marginTop:1,paddingLeft:2,children:d(C,{color:"white",children:"[esc/q/enter: exit]"})})]}):h?v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:y,children:[d(w,{marginTop:-1,marginBottom:1,children:v(C,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",d(C,{color:"red",children:"Error"})]})}),d(w,{flexDirection:"column",paddingLeft:2,children:d(C,{color:"red",children:h})}),d(w,{marginTop:1,children:d(C,{color:"grey",children:"[esc/q/enter: exit]"})})]}):o&&s?v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:y,children:[d(w,{marginTop:-1,marginBottom:1,children:v(C,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",d(C,{color:"cyan",children:"Confirmation"})]})}),v(w,{flexDirection:"column",paddingLeft:2,children:[v(C,{children:["Connect ",d(C,{bold:!0,children:s.name})," to Membrane via MCP?"]}),d(w,{marginTop:1,children:d(C,{color:"grey",children:"This will add an MCP server configuration that allows the agent to use Membrane's integration capabilities."})}),d(w,{marginTop:1,children:d(C,{color:"yellow",bold:!0,children:s.actionDescription})}),d(w,{marginTop:2,marginBottom:1,children:v(C,{children:[d(C,{color:"white",bold:!0,children:"[Enter] Confirm"})," ",d(C,{color:"gray",children:"[Esc] Cancel"})]})})]})]}):v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:y,children:[d(w,{marginTop:-1,marginBottom:1,children:v(C,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",d(C,{color:"cyan",children:"Select Agent"})]})}),v(w,{flexDirection:"column",paddingLeft:2,children:[d(C,{color:"grey",children:"Choose an agent to connect to Membrane via MCP:"}),d(w,{marginTop:1,children:d(C,{color:"grey",children:"This will add an MCP server configuration that allows the agent to use Membrane's integration capabilities."})}),d(w,{marginTop:1,flexDirection:"column",children:Wt.map((E,S)=>v(w,{children:[v(C,{color:t===S?"cyan":"white",children:[t===S?"\u25B6 ":" ",E.name]}),v(C,{color:"grey",children:[" \u2014 ",E.description]})]},E.id))})]}),d(w,{marginTop:1,children:d(C,{color:"grey",children:"[\u2191\u2193: select] [enter: choose] [esc: exit]"})})]})}c(_s,"AddMcpServerScreen");function qs(){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(_.McpStatusChanged,s),se.on(_.McpServersChanged,a),()=>{se.off(_.McpStatusChanged,s),se.off(_.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(qs,"useMcpStatus");function Bs(){const{error:r,serverCount:e,allMcpServers:t}=qs(),n=Math.min(100,process.stdout.columns||100);return v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:n,children:[d(w,{marginTop:-1,marginBottom:0,flexDirection:"column",children:v(C,{bold:!0,children:["\u{1F916} Connected AI Agents:"," ",r?d(C,{color:"red",children:"error reading status"}):e===0?d(C,{color:"yellow",children:"none"}):d(C,{color:"green",children:e})]})}),!r&&e===0&&d(w,{marginTop:1,children:v(C,{color:"grey",children:["Connect your AI agents to Membrane.",d(Wr,{}),"It will give them tools and context to build integrations."]})}),t.length>0&&d(w,{flexDirection:"column",paddingLeft:2,marginTop:1,children:t.map((o,i)=>d(w,{children:v(C,{color:"grey",children:["#",i+1," ",o.agentName,": ",o.totalRequests," calls"]})},o.processId))}),d(w,{marginTop:1,children:d(C,{color:"grey",children:"[a: connect an agent]"})})]})}c(Bs,"Agent");const hr=c(r=>{switch(r){case"error":return"red";case"success":return"green";case"warning":return"yellow";default:return}},"getLogColor");function pr(r,e){return e<3?r.slice(0,Math.max(0,e)):r.length<=e?r:`${r.slice(0,e-3)}...`}c(pr,"truncateText");function Ws({children:r}){const{state:e,logs:t}=Z();return!e||e===P.NOT_INITIALIZED?v(w,{gap:1,flexDirection:"row",children:[d(io,{type:"dots"}),d(C,{children:"Initializing..."})]}):e===P.SETTING_UP?d(w,{gap:1,flexDirection:"row",children:d(C,{children:"No workspace selected. Please run `membrane init` to select a workspace."})}):e===P.ERROR?d(w,{flexDirection:"column",children:t.slice().map((n,o)=>d(C,{color:hr(n.type),children:n.message},n.timestamp+o))}):r}c(Ws,"EnsureInitialized");function Js(){const{stats:r}=Z(),e=Object.entries(r).filter(([t,n])=>n>0);return e.length===0?null:v(w,{flexDirection:"column",children:[d(w,{children:d(w,{width:12,children:d(C,{color:"grey",children:"Elements:"})})}),d(w,{flexDirection:"column",marginLeft:1,children:e.map(([t,n])=>v(w,{children:[d(w,{width:20,children:v(C,{children:[t,":"]})}),d(C,{color:"green",children:n})]},t))})]})}c(Js,"ElementStats");const Jt=5,zs=6;function Gs(){const{logs:r}=Z(),[e,t]=L(0),n=Math.min(100,process.stdout.columns||100),o=Jt,i=Math.max(0,r.length-o-e),s=r.length-e,a=r.slice(i,s),l=n-zs,u=e<r.length-o,h=e>0;return pe((m,p)=>{if(r.length!==0)if(p.upArrow){const y=Math.max(0,r.length-o);t(E=>Math.min(y,E+1))}else p.downArrow?t(y=>Math.max(0,y-1)):(m==="G"||m==="g")&&t(0)}),v(w,{flexDirection:"column",paddingTop:1,children:[v(C,{color:"grey",children:["Recent Activity (",i+1,"-",s," of ",r.length,"):",r.length>Jt&&d(C,{color:"grey",children:" [arrows: scroll] [g: end]"})]}),a.map((m,p)=>d(w,{marginLeft:1,children:d(C,{color:hr(m.type),children:pr(m.message,l)})},m.timestamp+p)),r.length>Jt&&v(w,{marginLeft:1,flexDirection:"row",children:[u&&d(C,{color:"grey",children:"\u2191 "}),h&&d(C,{color:"grey",children:"\u2193 "})]})]})}c(Gs,"Logs");const Ge=[{value:"sync",label:"Continue (overwrite/delete)",key:""},{value:"exit",label:"Cancel",key:""}];function Hs(){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!==P.CONFLICTS&&i&&s(!1)},[r,i]),v(w,{flexDirection:"column",paddingTop:1,children:[d(w,{children:d(w,{flexDirection:"row",gap:2,children:d(C,{bold:!0,color:"white",children:"Conflicts with remote"})})}),d(w,{children:d(C,{color:"grey",children:"The remote workspace has changes that aren't in your local workspace:"})}),d(w,{marginTop:1,marginLeft:2,children:d(Ys,{isExpanded:a})}),v(w,{marginTop:2,flexDirection:"row",gap:1,children:[d(C,{color:"white",bold:!0,children:"What would you like to do?"}),d(C,{color:"grey",children:"[up/down, enter]"})]}),d(w,{children:i?v(w,{flexDirection:"row",gap:1,children:[d(qe,{type:"dots"}),d(C,{color:"blue",bold:!0,children:"Syncing with remote..."})]}):d(w,{flexDirection:"column",children:Ge.map((u,h)=>d(w,{flexDirection:"column",children:v(w,{flexDirection:"row",gap:1,children:[d(C,{color:n===h?"cyan":"grey",children:n===h?"\u25B6":" "}),d(C,{color:n===h?"cyan":"grey",bold:n===h,children:u.label})]})},u.value))})})]})}c(Hs,"ResolveChangesUI");const Vs={[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 Ys({isExpanded:r,showControls:e=!0}){const{conflicts:t}=Z(),n=5,o=Br(()=>{const i={};return t.forEach(s=>{const a=`${s.type}-${s.direction}`;i[a]||(i[a]=[]),i[a].push(s)}),i},[t]);return d(w,{flexDirection:"column",children:Object.entries(o).map(([i,s])=>{if(s.length===0)return null;const[a,l]=i.split("-"),u=Vs[a][l];return v(w,{flexDirection:"column",children:[v(w,{flexDirection:"row",gap:1,children:[v(C,{color:"yellow",children:[u.label," (",s.length,")"]}),d(C,{color:"white",children:u.description})]}),(r?s:s.slice(0,n)).map(h=>d(w,{marginLeft:2,children:v(C,{color:"grey",children:["\u2022 ",h.element.id," (",h.element.relativePath,")"]})},h.element.id)),!r&&s.length>n&&d(w,{marginLeft:2,children:v(C,{color:"cyan",children:["... and ",s.length-n," more",e?" (press Ctrl+R to show all)":""]})}),r&&s.length>n&&e&&d(w,{marginLeft:2,children:d(C,{color:"cyan",children:"(press Ctrl+R to collapse)"})})]},i)})})}c(Ys,"Conflicts");function Zs(){const{config:r,state:e,logs:t,currentWorkspace:n,pull:o}=Z(),i=n?.name,s=i?pr(i,30):r?.workspaceKey,a=Math.min(100,process.stdout.columns||100);return Se(()=>{o({watch:!0})},[]),v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:a,children:[d(w,{marginTop:-1,marginBottom:1,children:v(w,{flexDirection:"row",gap:1,children:[d(C,{bold:!0,children:"\u{1F504} Workspace"}),v(C,{color:Qs(e),children:[" [",Xs(e),"] "]})]})}),v(w,{children:[d(w,{width:12,children:d(C,{color:"grey",children:"Local:"})}),d(C,{color:"grey",children:process.cwd()})]}),v(w,{children:[d(w,{width:12,children:d(C,{color:"grey",children:"Remote:"})}),r?.workspaceKey?v(C,{color:"grey",children:[s," [o: open in console] [w: change]"]}):v(C,{children:[d(C,{color:"yellow",children:"not selected"})," [w: select]"]})]}),e===P.CONFLICTS?d(Hs,{}):v(Ke,{children:[d(w,{paddingTop:1,children:d(Js,{})}),t.length>0&&d(Gs,{})]})]})}c(Zs,"Workspace");function Xs(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(Xs,"getStatusDisplay");function Qs(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(Qs,"getStatusColor");function ea(){const r=Ai(),e=lt(!0),{exit:t,state:n}=Z(),[o,i]=L(null),s=o??(n===P.SETTING_UP?"setup":"main");pe(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 vn(r),u=ft(`/w/${l}`),h=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";ao(`${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(er,{onExit:c(()=>i(null),"onExit")}):s==="add-mcp-server"?d(_s,{onExit:c(()=>i(null),"onExit"),onComplete:c(()=>i(null),"onComplete")}):s==="setup"?d(tr,{onComplete:c(()=>i(null),"onComplete")},Date.now()):d(Ws,{children:v(w,{flexDirection:"column",children:[d(w,{flexGrow:1,children:d(Bs,{})}),d(Zs,{}),d(w,{paddingLeft:2,children:d(C,{color:"grey",children:"[s: (re-)setup]"})})]})})}c(ea,"Main");const ta=c(()=>[f.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"),f.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),f.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"),f.yellow("\u2502 Real-time agent mode is experimental and subject to changes. \u2502"),f.yellow("\u2502 Use in production environments is not recommended. \u2502"),f.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(`
48
+ `)}catch(o){q(o)}})}c(Ms,"setupRequestCommand");function js(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 W(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)+`
49
+ `);else{const s=i.items??[];if(s.length===0)console.error(f.gray(" No results found."));else for(const a of s){const l=a.element,u=f.gray(`[${a.elementType}]`),h=l?.name||l?.key||"(unnamed)",m=f.cyan(String(l?.id??a.id??"(no id)"));console.error(` ${u} ${m} ${h}`)}console.error()}}catch(n){q(n)}})}c(js,"setupSearchCommand");const Fs="0";function Us(r){r.command("status").description("Show current login status, project settings, and resolved environment").action(async()=>{try{await Ks()}catch(e){q(e)}})}c(Us,"setupStatusCommand");async function Ks(){const r=me()||te,e=wn(),t=yt();if(console.error(),console.error(f.bold.cyan("\u25B6 Membrane CLI Status")),console.error(),A("API",r),!t)A("Auth",f.red("Not logged in"));else{const n=mt(),o=!!be(),i=gt();if(n&&!o)A("Auth",f.yellow("Token expired (no refresh token)"));else if(i==="tenant"){A("Auth",f.green("Logged in")+f.gray(" (tenant scope)"));try{const a=await new Pe().get("/self"),l=a.workspaceKey??e.defaultWorkspaceKey;l&&A("Workspace",l);const u=a.internalId??e.defaultTenantKey;a.name&&u?A("Tenant",`${a.name} (${u})`):a.name?A("Tenant",a.name):u&&A("Tenant",u)}catch{e.defaultWorkspaceKey&&A("Workspace",e.defaultWorkspaceKey),e.defaultTenantKey&&A("Tenant",e.defaultTenantKey)}}else{try{const a=await new Pe().get(`/account?workspaceId=${Fs}`);if(a.user?(A("Auth",f.green("Logged in")),A("User",`${a.user.name} (${a.user.email})`)):A("Auth",f.green("Logged in")),a.orgs?.length){const l=a.orgs.map(u=>u.name).join(", ");A("Orgs",l)}}catch{A("Auth",f.yellow("Logged in (could not fetch account details)"))}e.defaultWorkspaceKey&&A("Workspace",`${e.defaultWorkspaceKey} ${f.gray("(default)")}`),e.defaultTenantKey&&A("Tenant",`${e.defaultTenantKey} ${f.gray("(default)")}`),!e.defaultWorkspaceKey&&!e.defaultTenantKey&&A("Project",f.gray("No project defaults configured"))}}console.error()}c(Ks,"runStatus");const Wt=[{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 _s({onExit:r,onComplete:e}){const[t,n]=L(0),[o,i]=L(!1),[s,a]=L(null),[l,u]=L(""),[h,m]=L("");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(Wt.length-1,t+1));else if(S.return||E===" "){const N=Wt[t];a(N),i(!0)}});const p=c(E=>{try{const S=E.addConfig();u(S)}catch(S){m(`Failed to write configuration: ${S.message||S}`)}},"addMcpConfiguration"),y=Math.min(80,process.stdout.columns||80);return l?v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:y,children:[d(w,{marginTop:-1,marginBottom:1,children:v(C,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",d(C,{color:"green",children:"Success"})]})}),v(w,{flexDirection:"column",paddingLeft:2,children:[d(C,{color:"green",children:l}),d(w,{marginTop:1,children:d(C,{color:"grey",children:"The agent will now be able to use Membrane's integration capabilities."})})]}),d(w,{marginTop:1,paddingLeft:2,children:d(C,{color:"white",children:"[esc/q/enter: exit]"})})]}):h?v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:y,children:[d(w,{marginTop:-1,marginBottom:1,children:v(C,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",d(C,{color:"red",children:"Error"})]})}),d(w,{flexDirection:"column",paddingLeft:2,children:d(C,{color:"red",children:h})}),d(w,{marginTop:1,children:d(C,{color:"grey",children:"[esc/q/enter: exit]"})})]}):o&&s?v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:y,children:[d(w,{marginTop:-1,marginBottom:1,children:v(C,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",d(C,{color:"cyan",children:"Confirmation"})]})}),v(w,{flexDirection:"column",paddingLeft:2,children:[v(C,{children:["Connect ",d(C,{bold:!0,children:s.name})," to Membrane via MCP?"]}),d(w,{marginTop:1,children:d(C,{color:"grey",children:"This will add an MCP server configuration that allows the agent to use Membrane's integration capabilities."})}),d(w,{marginTop:1,children:d(C,{color:"yellow",bold:!0,children:s.actionDescription})}),d(w,{marginTop:2,marginBottom:1,children:v(C,{children:[d(C,{color:"white",bold:!0,children:"[Enter] Confirm"})," ",d(C,{color:"gray",children:"[Esc] Cancel"})]})})]})]}):v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:y,children:[d(w,{marginTop:-1,marginBottom:1,children:v(C,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",d(C,{color:"cyan",children:"Select Agent"})]})}),v(w,{flexDirection:"column",paddingLeft:2,children:[d(C,{color:"grey",children:"Choose an agent to connect to Membrane via MCP:"}),d(w,{marginTop:1,children:d(C,{color:"grey",children:"This will add an MCP server configuration that allows the agent to use Membrane's integration capabilities."})}),d(w,{marginTop:1,flexDirection:"column",children:Wt.map((E,S)=>v(w,{children:[v(C,{color:t===S?"cyan":"white",children:[t===S?"\u25B6 ":" ",E.name]}),v(C,{color:"grey",children:[" \u2014 ",E.description]})]},E.id))})]}),d(w,{marginTop:1,children:d(C,{color:"grey",children:"[\u2191\u2193: select] [enter: choose] [esc: exit]"})})]})}c(_s,"AddMcpServerScreen");function qs(){const[r,e]=L(null),[t,n]=L([]),[o,i]=L(null);return Ce(()=>{const s=c(({status:l})=>{e(l),i(null)},"handleMcpStatusChanged"),a=c(({servers:l})=>{n(l),i(null)},"handleMcpServersChanged");return se.on(_.McpStatusChanged,s),se.on(_.McpServersChanged,a),()=>{se.off(_.McpStatusChanged,s),se.off(_.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(qs,"useMcpStatus");function Bs(){const{error:r,serverCount:e,allMcpServers:t}=qs(),n=Math.min(100,process.stdout.columns||100);return v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:n,children:[d(w,{marginTop:-1,marginBottom:0,flexDirection:"column",children:v(C,{bold:!0,children:["\u{1F916} Connected AI Agents:"," ",r?d(C,{color:"red",children:"error reading status"}):e===0?d(C,{color:"yellow",children:"none"}):d(C,{color:"green",children:e})]})}),!r&&e===0&&d(w,{marginTop:1,children:v(C,{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(w,{flexDirection:"column",paddingLeft:2,marginTop:1,children:t.map((o,i)=>d(w,{children:v(C,{color:"grey",children:["#",i+1," ",o.agentName,": ",o.totalRequests," calls"]})},o.processId))}),d(w,{marginTop:1,children:d(C,{color:"grey",children:"[a: connect an agent]"})})]})}c(Bs,"Agent");const hr=c(r=>{switch(r){case"error":return"red";case"success":return"green";case"warning":return"yellow";default:return}},"getLogColor");function pr(r,e){return e<3?r.slice(0,Math.max(0,e)):r.length<=e?r:`${r.slice(0,e-3)}...`}c(pr,"truncateText");function Ws({children:r}){const{state:e,logs:t}=Z();return!e||e===P.NOT_INITIALIZED?v(w,{gap:1,flexDirection:"row",children:[d(io,{type:"dots"}),d(C,{children:"Initializing..."})]}):e===P.SETTING_UP?d(w,{gap:1,flexDirection:"row",children:d(C,{children:"No workspace selected. Please run `membrane init` to select a workspace."})}):e===P.ERROR?d(w,{flexDirection:"column",children:t.slice().map((n,o)=>d(C,{color:hr(n.type),children:n.message},n.timestamp+o))}):r}c(Ws,"EnsureInitialized");function Js(){const{stats:r}=Z(),e=Object.entries(r).filter(([t,n])=>n>0);return e.length===0?null:v(w,{flexDirection:"column",children:[d(w,{children:d(w,{width:12,children:d(C,{color:"grey",children:"Elements:"})})}),d(w,{flexDirection:"column",marginLeft:1,children:e.map(([t,n])=>v(w,{children:[d(w,{width:20,children:v(C,{children:[t,":"]})}),d(C,{color:"green",children:n})]},t))})]})}c(Js,"ElementStats");const Jt=5,zs=6;function Gs(){const{logs:r}=Z(),[e,t]=L(0),n=Math.min(100,process.stdout.columns||100),o=Jt,i=Math.max(0,r.length-o-e),s=r.length-e,a=r.slice(i,s),l=n-zs,u=e<r.length-o,h=e>0;return he((m,p)=>{if(r.length!==0)if(p.upArrow){const y=Math.max(0,r.length-o);t(E=>Math.min(y,E+1))}else p.downArrow?t(y=>Math.max(0,y-1)):(m==="G"||m==="g")&&t(0)}),v(w,{flexDirection:"column",paddingTop:1,children:[v(C,{color:"grey",children:["Recent Activity (",i+1,"-",s," of ",r.length,"):",r.length>Jt&&d(C,{color:"grey",children:" [arrows: scroll] [g: end]"})]}),a.map((m,p)=>d(w,{marginLeft:1,children:d(C,{color:hr(m.type),children:pr(m.message,l)})},m.timestamp+p)),r.length>Jt&&v(w,{marginLeft:1,flexDirection:"row",children:[u&&d(C,{color:"grey",children:"\u2191 "}),h&&d(C,{color:"grey",children:"\u2193 "})]})]})}c(Gs,"Logs");const Ge=[{value:"sync",label:"Continue (overwrite/delete)",key:""},{value:"exit",label:"Cancel",key:""}];function Hs(){const{state:r,resolveConflicts:e,exit:t}=Z(),[n,o]=L(0),[i,s]=L(!1),[a,l]=L(!1);return he((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())}}),Ce(()=>{r!==P.CONFLICTS&&i&&s(!1)},[r,i]),v(w,{flexDirection:"column",paddingTop:1,children:[d(w,{children:d(w,{flexDirection:"row",gap:2,children:d(C,{bold:!0,color:"white",children:"Conflicts with remote"})})}),d(w,{children:d(C,{color:"grey",children:"The remote workspace has changes that aren't in your local workspace:"})}),d(w,{marginTop:1,marginLeft:2,children:d(Ys,{isExpanded:a})}),v(w,{marginTop:2,flexDirection:"row",gap:1,children:[d(C,{color:"white",bold:!0,children:"What would you like to do?"}),d(C,{color:"grey",children:"[up/down, enter]"})]}),d(w,{children:i?v(w,{flexDirection:"row",gap:1,children:[d(qe,{type:"dots"}),d(C,{color:"blue",bold:!0,children:"Syncing with remote..."})]}):d(w,{flexDirection:"column",children:Ge.map((u,h)=>d(w,{flexDirection:"column",children:v(w,{flexDirection:"row",gap:1,children:[d(C,{color:n===h?"cyan":"grey",children:n===h?"\u25B6":" "}),d(C,{color:n===h?"cyan":"grey",bold:n===h,children:u.label})]})},u.value))})})]})}c(Hs,"ResolveChangesUI");const Vs={[oe.UPDATE]:{incoming:{label:"Elements updated in remote",description:"(to be overwritten from remote)"},outgoing:{label:"Elements updated locally",description:"(to be pushed to remote)"}},[oe.DELETE]:{incoming:{label:"Elements not existing in remote",description:"(to be deleted locally)"},outgoing:{label:"Elements deleted locally",description:"(to be deleted from remote)"}},[oe.CREATE]:{incoming:{label:"Elements created in remote",description:"(to be created locally)"},outgoing:{label:"Elements created locally",description:"(to be created in remote)"}}};function Ys({isExpanded:r,showControls:e=!0}){const{conflicts:t}=Z(),n=5,o=_r(()=>{const i={};return t.forEach(s=>{const a=`${s.type}-${s.direction}`;i[a]||(i[a]=[]),i[a].push(s)}),i},[t]);return d(w,{flexDirection:"column",children:Object.entries(o).map(([i,s])=>{if(s.length===0)return null;const[a,l]=i.split("-"),u=Vs[a][l];return v(w,{flexDirection:"column",children:[v(w,{flexDirection:"row",gap:1,children:[v(C,{color:"yellow",children:[u.label," (",s.length,")"]}),d(C,{color:"white",children:u.description})]}),(r?s:s.slice(0,n)).map(h=>d(w,{marginLeft:2,children:v(C,{color:"grey",children:["\u2022 ",h.element.id," (",h.element.relativePath,")"]})},h.element.id)),!r&&s.length>n&&d(w,{marginLeft:2,children:v(C,{color:"cyan",children:["... and ",s.length-n," more",e?" (press Ctrl+R to show all)":""]})}),r&&s.length>n&&e&&d(w,{marginLeft:2,children:d(C,{color:"cyan",children:"(press Ctrl+R to collapse)"})})]},i)})})}c(Ys,"Conflicts");function Zs(){const{config:r,state:e,logs:t,currentWorkspace:n,pull:o}=Z(),i=n?.name,s=i?pr(i,30):r?.workspaceKey,a=Math.min(100,process.stdout.columns||100);return Ce(()=>{o({watch:!0})},[]),v(w,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:a,children:[d(w,{marginTop:-1,marginBottom:1,children:v(w,{flexDirection:"row",gap:1,children:[d(C,{bold:!0,children:"\u{1F504} Workspace"}),v(C,{color:Qs(e),children:[" [",Xs(e),"] "]})]})}),v(w,{children:[d(w,{width:12,children:d(C,{color:"grey",children:"Local:"})}),d(C,{color:"grey",children:process.cwd()})]}),v(w,{children:[d(w,{width:12,children:d(C,{color:"grey",children:"Remote:"})}),r?.workspaceKey?v(C,{color:"grey",children:[s," [o: open in console] [w: change]"]}):v(C,{children:[d(C,{color:"yellow",children:"not selected"})," [w: select]"]})]}),e===P.CONFLICTS?d(Hs,{}):v(Ke,{children:[d(w,{paddingTop:1,children:d(Js,{})}),t.length>0&&d(Gs,{})]})]})}c(Zs,"Workspace");function Xs(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(Xs,"getStatusDisplay");function Qs(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(Qs,"getStatusColor");function ea(){const r=Ti(),e=at(!0),{exit:t,state:n}=Z(),[o,i]=L(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 $n(r),u=pt(`/w/${l}`),h=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";ao(`${h} "${u}"`)}catch(l){console.error("Failed to open workspace:",l),t()}}return c(a,"handleOpenWorkspace"),Ce(()=>(e.current=!0,()=>{e.current=!1}),[]),s==="workspace-selection"?d(er,{onExit:c(()=>i(null),"onExit")}):s==="add-mcp-server"?d(_s,{onExit:c(()=>i(null),"onExit"),onComplete:c(()=>i(null),"onComplete")}):s==="setup"?d(tr,{onComplete:c(()=>i(null),"onComplete")},Date.now()):d(Ws,{children:v(w,{flexDirection:"column",children:[d(w,{flexGrow:1,children:d(Bs,{})}),d(Zs,{}),d(w,{paddingLeft:2,children:d(C,{color:"grey",children:"[s: (re-)setup]"})})]})})}c(ea,"Main");const ta=c(()=>[f.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"),f.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),f.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"),f.yellow("\u2502 Real-time agent mode is experimental and subject to changes. \u2502"),f.yellow("\u2502 Use in production environments is not recommended. \u2502"),f.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(`
50
50
  `),"createExperimentalWarning$1");function na(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(`
51
- `)).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(ta()),ut(he.createElement(Ft,{cwd:process.cwd(),membraneCLIService:e,children:he.createElement(ea)}))})}c(na,"setupSyncCommand");class ra{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 oa="claude-sonnet-4-20250514";class Yt{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 Zt({token:await this.createMembraneToken(o),apiUri:o.apiUri}),s=new co({apiKey:o.anthropicApiKey}),a={complete:c(async({prompt:l,maxTokens:u})=>{const h=await s.messages.create({model:oa,max_tokens:u,messages:[{role:"user",content:l}]});return h.content[0].type==="text"?h.content[0].text:""},"complete")};return new Yt({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 Pt(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)}}uo.interpolate=/{{([\s\S]+?)}}/g;function zt(r,e){if(typeof r=="string"){const t=lo(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=>zt(t,e)):typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).map(([t,n])=>[t,zt(n,e)])):r}c(zt,"processNode");function ia(r,e){return zt(r,e)}c(ia,"handleTemplate");class sa{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(`${f.bold.cyan("[start]")} ${f.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(`${f.bold.yellow("[initialized]")} ${f.yellow(e.path)}`)),s=ia(i,this.environment.state),await e.run(s),console.debug(`${f.bold.green("[success]")} ${f.yellow(e.path)}`),t=!0,o=e.getResult(),Xe(this.result,e.path,o)}catch(l){if(console.error(`${f.bold.red("[error]")} ${f.yellow(e.path)}: ${l}`),this.environment.options.fix&&!n){n=!0;try{await e.fix(l);continue}catch(u){console.error(`${f.bold.red("[fix fail]")} ${f.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(f.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 Gt(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)||!Ht(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=Gt(o,i);s!==null&&(t[n]=s)}else t[n]=i;continue}Ht(o,i)||(t[n]=i)}return Object.keys(t).length===0?null:t}c(Gt,"getNotMatchingSubFields");function Ht(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(Ht,"softCompare");class aa 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=rn(n),a=je(e.input.fields,s,{skipUnknownFields:!0}),l=je(i.record.fields,s),u=Gt(l,a);await this.assert(()=>!u,"Returned fields match created fields",{difference:u,sentFields:a,receivedFields:l})}const o=Or(n??{});if(o.length>0){const i={};o.forEach(a=>{const l=Rr(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:
51
+ `)).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(ta()),ot(pe.createElement(Dt,{cwd:process.cwd(),membraneCLIService:e,children:pe.createElement(ea)}))})}c(na,"setupSyncCommand");const ra="claude-sonnet-4-20250514";class Yt{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 Xt({token:await this.createMembraneToken(o),apiUri:o.apiUri}),s=new co({apiKey:o.anthropicApiKey}),a={complete:c(async({prompt:l,maxTokens:u})=>{const h=await s.messages.create({model:ra,max_tokens:u,messages:[{role:"user",content:l}]});return h.content[0].type==="text"?h.content[0].text:""},"complete")};return new Yt({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 It(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 ct.sign(n,e.workspaceSecret,o)}}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 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(f.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`}}class oa 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=Xe(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=rn(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=Or(n??{});if(o.length>0){const i={};o.forEach(a=>{const l=Rr(e.input.fields,a);typeof l<"u"&&Qe(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=Xe(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=Xe(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:
52
52
 
53
53
  ${JSON.stringify(o,null,2)}
54
54
 
@@ -88,7 +88,7 @@ ${JSON.stringify(o,null,2)}`).join(`
88
88
 
89
89
  `)}.
90
90
 
91
- 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 on(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=sn(o);n[i]=await this.fetchExampleRecords(o)}return n}}class ca 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.
91
+ 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 on(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=sn(o);n[i]=await this.fetchExampleRecords(o)}return n}}class ia 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.
92
92
 
93
93
  I tried to delete a record with this ID:
94
94
 
@@ -108,7 +108,7 @@ Format your response as a JSON object with two fields:
108
108
  "id": "fixed id"
109
109
  }.
110
110
 
111
- 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(f.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class la 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.
111
+ 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(f.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class sa 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.
112
112
 
113
113
  I tried to find a record with this ID:
114
114
 
@@ -128,7 +128,7 @@ Format your response as a JSON object with two fields:
128
128
  "id": "fixed id"
129
129
  }.
130
130
 
131
- 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(f.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class ua 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.
131
+ 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(f.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class aa 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.
132
132
 
133
133
  I tried to list records with these parameters:
134
134
 
@@ -148,7 +148,7 @@ Format your response as a JSON object with two fields:
148
148
  "input": { ... fixed parameters ... }
149
149
  }.
150
150
 
151
- 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(f.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input}}}class da 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(()=>Ht(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.
151
+ 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(f.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input}}}class ca 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.
152
152
 
153
153
  I tried to match a record with this query:
154
154
 
@@ -168,7 +168,7 @@ Format your response as a JSON object with two fields:
168
168
  "query": { ... fixed query ... }
169
169
  }.
170
170
 
171
- 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(f.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{query:s.query}}}}class ha 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(f.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.
171
+ 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(f.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{query:s.query}}}}class la 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(f.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.
172
172
 
173
173
  Record fields:
174
174
  ${JSON.stringify(e,null,2)}
@@ -193,7 +193,7 @@ Format your response as a JSON object with two fields:
193
193
  "input": { ... fixed parameters ... }
194
194
  }.
195
195
 
196
- 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(f.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input,expectedRecordId:e.expectedRecordId}}}class pa 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 fa 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=rn(i),a=je(e.input.fields,s,{skipUnknownFields:!0}),l=je(o.record.fields,s),u=Gt(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:
196
+ 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(f.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input,expectedRecordId:e.expectedRecordId}}}class ua 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 da 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=rn(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:
197
197
 
198
198
  ${JSON.stringify(o,null,2)}
199
199
 
@@ -233,9 +233,9 @@ ${JSON.stringify(o,null,2)}`).join(`
233
233
 
234
234
  `)}.
235
235
 
236
- 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 on(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=sn(o);n[i]=await this.fetchExampleRecords(o)}return n}}const Vt={spec:{testerClass:pa},create:{testerClass:aa,operationKey:"create"},"find-by-id":{testerClass:la,operationKey:"findById"},list:{testerClass:ua,operationKey:"list"},match:{testerClass:da,operationKey:"match"},search:{testerClass:ha,operationKey:"search"},update:{testerClass:fa,operationKey:"update"},delete:{testerClass:ca,operationKey:"delete"}};class ma extends sa{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=Vt[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(Vt).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(Vt).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 ga extends ra{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 Yt.create({connectionId:l,testBasePath:u,options:{fix:n}}),y=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 R,j;S.length>=1&&(j=S[0],S.length>=2&&S[1].trim()!==""&&(R=S[1]));for(const U of y){if(j&&j!==U.key)continue;const F=new ma({environment:m,dataCollectionKey:U.key,testMethod:R});E.push(F)}}E.length===0&&(b.error(`No test suites found for path: ${e}${h?"/"+h:""}`),process.exit(1));const N={};for(const R of E){await R.run();const j=R.getResult();b.debug(`Suite ${R.constructor.name} result:`,{prefix:"TestRunner"}),dt(N,j)}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(()=>[f.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"),f.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),f.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"),f.yellow("\u2502 The test command is experimental and subject to rapid changes. \u2502"),f.yellow("\u2502 Features, APIs, and file structures may change without notice. \u2502"),f.yellow("\u2502 Use in production environments is not recommended. \u2502"),f.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(`
236
+ 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 on(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=sn(o);n[i]=await this.fetchExampleRecords(o)}return n}}uo.interpolate=/{{([\s\S]+?)}}/g;function Ht(r,e){if(typeof r=="string"){const t=lo(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=>Ht(t,e)):typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).map(([t,n])=>[t,Ht(n,e)])):r}c(Ht,"processNode");function ha(r,e){return Ht(r,e)}c(ha,"handleTemplate");class pa{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(`${f.bold.cyan("[start]")} ${f.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(`${f.bold.yellow("[initialized]")} ${f.yellow(e.path)}`)),s=ha(i,this.environment.state),await e.run(s),console.debug(`${f.bold.green("[success]")} ${f.yellow(e.path)}`),t=!0,o=e.getResult(),Qe(this.result,e.path,o)}catch(l){if(console.error(`${f.bold.red("[error]")} ${f.yellow(e.path)}: ${l}`),this.environment.options.fix&&!n){n=!0;try{await e.fix(l);continue}catch(u){console.error(`${f.bold.red("[fix fail]")} ${f.yellow(e.path)}: ${u}`)}}Qe(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())}}const Vt={spec:{testerClass:ua},create:{testerClass:oa,operationKey:"create"},"find-by-id":{testerClass:sa,operationKey:"findById"},list:{testerClass:aa,operationKey:"list"},match:{testerClass:ca,operationKey:"match"},search:{testerClass:la,operationKey:"search"},update:{testerClass:da,operationKey:"update"},delete:{testerClass:ia,operationKey:"delete"}};class fa extends pa{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=Vt[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(Vt).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(Vt).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 ma{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}class ga extends ma{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 Yt.create({connectionId:l,testBasePath:u,options:{fix:n}}),y=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 R,j;S.length>=1&&(j=S[0],S.length>=2&&S[1].trim()!==""&&(R=S[1]));for(const U of y){if(j&&j!==U.key)continue;const F=new fa({environment:m,dataCollectionKey:U.key,testMethod:R});E.push(F)}}E.length===0&&(b.error(`No test suites found for path: ${e}${h?"/"+h:""}`),process.exit(1));const N={};for(const R of E){await R.run();const j=R.getResult();b.debug(`Suite ${R.constructor.name} result:`,{prefix:"TestRunner"}),dt(N,j)}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(()=>[f.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"),f.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),f.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"),f.yellow("\u2502 The test command is experimental and subject to rapid changes. \u2502"),f.yellow("\u2502 Features, APIs, and file structures may change without notice. \u2502"),f.yellow("\u2502 Use in production environments is not recommended. \u2502"),f.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(`
237
237
  `),"createExperimentalWarning");function ya(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",["",f.bold("Examples:"),` ${f.gray("\u25B8")} ${f.cyan("membrane test run connectors/netsuite")} # Test all data collections for netsuite connector`,` ${f.gray("\u25B8")} ${f.cyan("membrane test run connectors/netsuite/data/contacts")} # Test specific data collection`,` ${f.gray("\u25B8")} ${f.cyan("membrane test run connectors/netsuite/data/contacts/create")} # Test specific method for data collection`,` ${f.gray("\u25B8")} ${f.cyan("membrane test run connectors/netsuite/data/contacts/delete")} # Test delete method for data collection`,` ${f.gray("\u25B8")} ${f.cyan("membrane test run actions/create-contact")} # Test specific action`,` ${f.gray("\u25B8")} ${f.cyan("membrane test run connectors/hubspot/events")} # Test events for hubspot`,` ${f.gray("\u25B8")} ${f.cyan("membrane test run connectors/salesforce --fix")} # Run tests with auto-fix enabled`,"",f.gray("For more information, visit:"),f.blue(" https://docs.getmembrane.com/docs/development-environment"),"",He()].join(`
238
- `)).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 ga({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(ya,"setupTestCommand");const wa=c(()=>{try{const r=br(import.meta.url),e=Cr(r),t=Ve(e,"..","package.json");return JSON.parse(wr(t,"utf-8")).version}catch{return"1.0.0"}},"getPackageVersion"),fr=wa();function Ca(){process.on("SIGINT",()=>process.exit(130));const r=new vr().name("membrane").description("Command-line interface for Membrane Agent").version(fr,"-v, --version","Output the version number").option("--verbose","Enable verbose logging (shows debug messages)");r.configureHelp({sortSubcommands:!0,subcommandTerm:c(t=>f.cyan(t.name()),"subcommandTerm"),commandUsage:c(t=>t.name()==="membrane"?`${f.cyan(t.name())} ${f.gray("[options]")} ${f.cyan("[command]")}`:t.usage(),"commandUsage"),optionTerm:c(t=>{const n=t.flags;return`${f.gray("\u25B8")} ${f.cyan(n)}`},"optionTerm"),subcommandDescription:c(t=>f.gray(t.description()),"subcommandDescription"),optionDescription:c(t=>f.gray(t.description),"optionDescription"),commandDescription:c(t=>f.gray(t.description()),"commandDescription")}),r.addHelpText("beforeAll",`
238
+ `)).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 ga({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(ya,"setupTestCommand");const wa=c(()=>{try{const r=vr(import.meta.url),e=Sr(r),t=Ve(e,"..","package.json");return JSON.parse(Cr(t,"utf-8")).version}catch{return"1.0.0"}},"getPackageVersion"),fr=wa();function Ca(){process.on("SIGINT",()=>process.exit(130));const r=new gr().name("membrane").description("Command-line interface for Membrane Agent").version(fr,"-v, --version","Output the version number").option("--verbose","Enable verbose logging (shows debug messages)");r.configureHelp({sortSubcommands:!0,subcommandTerm:c(t=>f.cyan(t.name()),"subcommandTerm"),commandUsage:c(t=>t.name()==="membrane"?`${f.cyan(t.name())} ${f.gray("[options]")} ${f.cyan("[command]")}`:t.usage(),"commandUsage"),optionTerm:c(t=>{const n=t.flags;return`${f.gray("\u25B8")} ${f.cyan(n)}`},"optionTerm"),subcommandDescription:c(t=>f.gray(t.description()),"subcommandDescription"),optionDescription:c(t=>f.gray(t.description),"optionDescription"),commandDescription:c(t=>f.gray(t.description()),"commandDescription")}),r.addHelpText("beforeAll",`
239
239
  ${f.bold.cyan("Membrane Agent CLI")} ${f.gray(`v${fr}`)}
240
240
 
241
- `);const e=new $i(ze.Cli,process.cwd());Fo(r),zi(r),es(r),Mi(r),Ki(r),_i(r),_o(r),Ms(r),js(r),Bo(r),Us(r),cs(r),vs(r),as(r),ya(r),ss(r),na(r,e),Ji(r,e),Yo(r,e),Ri(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(Ca,"runCLI"),Ca();
241
+ `);const e=new bi(ze.Cli,process.cwd());Ki(r),zi(r),es(r),Pi(r),Di(r),Ni(r),Po(r),Ms(r),js(r),Oo(r),Us(r),cs(r),vs(r),as(r),ya(r),ss(r),na(r,e),Ji(r,e),Fo(r,e),Ii(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(Ca,"runCLI"),Ca();