@membranehq/cli 1.4.9 → 1.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +40 -32
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
`});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(),
|
|
4
|
-
`),"createExperimentalWarning$2");function
|
|
5
|
-
`)).action(async t=>{try{console.warn(
|
|
6
|
-
`);return
|
|
7
|
-
Membrane API Error:`),a&&console.error(a),console.error(JSON.stringify(
|
|
2
|
+
var Fn=Object.defineProperty;var c=(r,e)=>Fn(r,"name",{value:e,configurable:!0});import*as v from"node:fs";import{mkdirSync as Ln,writeFileSync as jn,readFileSync as Un}from"node:fs";import*as E from"node:path";import{join as _e,dirname as _n}from"node:path";import{URL as Kn,fileURLToPath as qn}from"node:url";import w from"chalk";import{Command as Bn}from"commander";import{WorkspaceElementType as x,MembraneConfigLoader as Wn,MembraneAxiosInstance as Jn,MembraneClient as jt,extractMembraneErrorData as z,WorkspaceElementSpecs as Z,WorkspaceSyncEventType as zn,ConnectorFileUpdateType as Ke,CONSOLE_ACCOUNT_API_TOKEN_PATH as Hn,MEMBRANE_CLI_CLIENT_ID as qe,OAUTH_SCOPE_PLATFORM_USER as Gn,NotFoundError as Vn,getConnectorSpecPath as Yn,getConnectorVersionPath as Ut,CONNECTOR_VERSION_DEVELOPMENT as Be,getMembraneElementPath as Zn,parseMembraneElementPath as ae,compareWorkspaceExports as Xn,WorkspaceElementChangeType as X,setValueAtLocator as We,getDataCollectionCreateFields as Je,excludeWriteOnlyFieldsFromSchema as _t,valueToSchema as Ie,getRequiredFieldsFromSchema as Qn,getValueAtLocator as er,walkSchema as Kt,makeDataLocationPath as qt,getDataCollectionUpdateFields as ze}from"@membranehq/sdk";import He from"lodash/camelCase.js";import Ge from"lodash/upperFirst.js";import tr from"code-block-writer";import nr from"lodash/uniqBy.js";import ce,{createContext as Ve,useState as N,useEffect as fe,useContext as Ye,useId as rr,useRef as Ze,useLayoutEffect as ke,useMemo as or}from"react";import{Box as g,Text as y,useInput as le,render as Xe,Newline as ir}from"ink";import{jsx as u,jsxs as b,Fragment as $e}from"react/jsx-runtime";import Bt from"swr/immutable";import A,{existsSync as Qe,mkdirSync as Wt,statSync as sr,chmodSync as ar,readFileSync as cr,writeFileSync as lr}from"fs";import et from"os";import k from"path";import ur from"conf";import we,{isAxiosError as dr}from"axios";import tt from"jsonwebtoken";import nt from"semver";import{AsyncLocalStorage as hr}from"async_hooks";import{toSentenceCase as pr}from"js-convert-case";import fr from"lodash/isEqual.js";import H from"js-yaml";import*as mr from"node:crypto";import{createHash as gr}from"node:crypto";import yr from"chokidar";import wr from"yaml";import{EventEmitter as Cr}from"events";import{EventSource as Sr}from"eventsource";import rt from"archiver";import Jt from"form-data";import Pe from"unzipper";import*as br from"node:os";import"node:events";import zt from"ink-text-input";import{SWRConfig as vr}from"swr";import Ae from"ink-spinner";import{TextInput as Er,Select as Tr,Spinner as xr}from"@inkjs/ui";import{randomBytes as Ht,createHash as Ir}from"crypto";import{createServer as kr}from"http";import ot from"ora";import{FastMCP as $r}from"fastmcp";import{z as R}from"zod";import Gt from"jszip";import{minimatch as Pr}from"minimatch";import{exec as Ar}from"node:child_process";import it from"lodash/merge.js";import Rr from"@anthropic-ai/sdk";import{faker as Ce}from"@faker-js/faker";import Dr from"lodash/template.js";import Or from"lodash/templateSettings.js";function ue(r){if(r.type){if(Array.isArray(r.type))return{anyOf:r.type.map(t=>ue({...r,type:t}))};if(r.type==="array"){const t={type:"array",items:r.items?ue(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]=ue(n)}return r.anyOf&&(e.anyOf=r.anyOf.map(ue)),r.additionalProperties!==void 0&&(typeof r.additionalProperties=="boolean"?e.additionalProperties=r.additionalProperties:e.additionalProperties=ue(r.additionalProperties)),r.required&&(e.required=r.required),e}c(ue,"convertDataSchemaToOpenAPI");function Nr(r){const{membraneInterfaces:{actions:e}}=r,t=Mr(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(Nr,"generateOpenAPIContent");function Mr(r){const e={};return r.forEach(t=>{const n=Ge(He(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=ue(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=ue(s);i.properties={...i.properties,data:a}}e[`${n}Response`]=i}),e}c(Mr,"generateOpenAPISchemas");function Fr(r){const{membraneInterfaces:{actions:e}}=r,t=nr(e,"key"),n=new tr({indentNumberOfSpaces:2,newLine:`
|
|
3
|
+
`});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(),Lr(n,t),n.toString()}c(Fr,"generateTypeScriptContent");function Lr(r,e){r.writeLine('declare module "@membranehq/sdk" {'),r.indent(()=>{e.forEach(t=>{const n=at(t),o=t?.inputSchema;Re(r,{interfaceName:n,properties:o?.properties,required:o?.required||[]});const i=ct(t),s=t?.customOutputSchema||t?.outputSchema;Re(r,{interfaceName:i,properties:s?.properties,required:s?.required||[],fallbackContent:"result: unknown"}),r.newLine()}),Re(r,{interfaceName:"MembraneClient",methods:e.map(t=>{const n=at(t),o=ct(t);return{name:"action",parameters:`selector: "${t.key}"`,returnType:`ActionAccessor<${n}, ${o}>`}})}),r.newLine(),Re(r,{interfaceName:"ConnectionAccessor",methods:e.map(t=>{const n=at(t),o=ct(t);return{name:"action",parameters:`selector: "${t.key}"`,returnType:`ConnectionLevelActionAccessor<${n}, ${o}>`}})})}),r.writeLine("}")}c(Lr,"generateModuleAugmentation");function Re(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&&jr(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(Re,"generateTypeScriptInterface");function jr(r,e,t){Object.entries(e).forEach(([n,o])=>{const s=t.includes(n)?"":"?",a=st(o);r.writeLine(`readonly ${n}${s}: ${a}`)})}c(jr,"generateTypeScriptProperties");function st(r){return r.type==="string"?r.enum?r.enum.map(e=>`'${e}'`).join(" | "):"string":r.type==="number"||r.type==="integer"?"number":r.type==="boolean"?"boolean":r.type==="array"?`${r.items?st(r.items):"unknown"}[]`:r.type==="object"?r.properties?`{ ${Object.entries(r.properties).map(([t,n])=>{const i=(r.required||[]).includes(t)?"":"?",s=st(n);return`readonly ${t}${i}: ${s}`}).join("; ")} }`:"Record<string, unknown>":"unknown"}c(st,"convertJsonSchemaToTypeScript");function at(r){return`${Ge(He(r.key))}Input`}c(at,"getInputTypeName");function ct(r){return`${Ge(He(r.key))}Output`}c(ct,"getOutputTypeName");async function lt(r){const{out:e}=r;await v.promises.mkdir(e,{recursive:!0});const t=Ur(r);for(const[n,o]of Object.entries(t)){const i=E.join(e,n);await v.promises.writeFile(i,o,"utf-8")}}c(lt,"generateCode");function Ur(r){switch(r.target){case"openapi":return{"openapi.json":Nr(r)};case"typescript":return{"generated.d.ts":Fr(r)};default:throw new Error(`Unsupported target: ${r.target}`)}}c(Ur,"generateContent");const ut=c(()=>[w.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"),w.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),w.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"),w.yellow("\u2502 The codegen command is experimental and subject to rapid changes.\u2502"),w.yellow("\u2502 Features, APIs, and file structures may change without notice. \u2502"),w.yellow("\u2502 Use in production environments is not recommended. \u2502"),w.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(`
|
|
4
|
+
`),"createExperimentalWarning$2");function _r(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",ut()).addHelpText("after",["",w.bold("Examples:"),` ${w.gray("\u25B8")} ${w.cyan("membrane codegen --actions list-files,get-file-by-id --out src/generated --target openapi --schemasOnly")}`,` ${w.gray("\u25B8")} ${w.cyan("membrane install --actions delete-file --out src/generated --target typescript --schemasOnly")}`,"",ut()].join(`
|
|
5
|
+
`)).action(async t=>{try{console.warn(ut()),console.error(w.cyan("\u{1F527} Membrane Codegen")),console.error("Status: Loading membrane interfaces...");const n=await Kr(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 lt(o),console.error(w.green("\u2705 Code generation completed successfully!")),process.exit(0)}catch(n){console.error(w.red("\u274C Code generation failed:")),console.error(n instanceof Error?n.message:"Unknown error occurred"),process.exit(1)}})}c(_r,"setupCodegenCommand");async function Kr(r,e){return await r.fetchElements(),{actions:[...r.getSyncedElementsByType(x.Action).map(t=>t.data)].filter(t=>e.actions.includes(t.key||""))}}c(Kr,"loadMembraneInterfaces");class ye{static{c(this,"ConfigLoader")}static instance=null;sdkLoader;constructor(){this.sdkLoader=new Wn}static getInstance(){return ye.instance||(ye.instance=new ye),ye.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 de=ye.getInstance();function Se(r){return de.loadConfig(r)}c(Se,"readProjectConfig");const qr="membrane",Br="membrane.config.yml",De="https://api.getmembrane.com",Wr="https://console.getmembrane.com";function dt(r){const t=Se()?.consoleUri||Wr;return r?new Kn(r,t).toString():t}c(dt,"getConsoleUrl");function ht(){const r=process.cwd(),e=E.join(r,qr),t=E.join(r,Br),n=e,o=E.join(n,"workspace.yaml");return{membraneDirPath:e,configPath:t,payloadDirPath:n,workspaceDataFilePath:o}}c(ht,"getPaths");function Vt(){return ht().membraneDirPath}c(Vt,"getBasePath");const Oe=k.join(et.homedir(),".membrane");Qe(Oe)?(sr(Oe).mode&511)!==448&&ar(Oe,448):Wt(Oe,{mode:448});const Jr={pat:{type:"string"},workspace:{type:"object"},accessToken:{type:"string"},refreshToken:{type:"string"},expiresAt:{type:"number"},apiUri:{type:"string"}},U=new ur({schema:Jr,configName:"credentials",cwd:k.join(et.homedir(),".membrane"),configFileMode:384}),zr=c(r=>{U.set("pat",r)},"setPat"),Yt=c(()=>U.get("pat"),"getPat"),Hr=c(()=>{U.delete("pat")},"clearPat"),Zt=c((r,e,t)=>{U.set("accessToken",r),U.set("refreshToken",e),t!=null?U.set("expiresAt",Date.now()+t*1e3):U.delete("expiresAt")},"setTokens"),Gr=c(()=>U.get("accessToken"),"getAccessToken"),Ne=c(()=>U.get("refreshToken"),"getRefreshToken"),Vr=c(()=>{const r=U.get("expiresAt");return r?Date.now()>=r-6e4:!0},"isTokenExpired"),Yr=c(()=>{U.delete("accessToken"),U.delete("refreshToken"),U.delete("expiresAt"),U.delete("apiUri")},"clearTokens"),Me=c(()=>U.get("apiUri"),"getApiUri"),Zr=c(r=>{U.set("apiUri",r)},"setApiUri"),Xr=c(()=>!!(U.get("accessToken")||U.get("pat")),"isAuthenticated");class pt{static{c(this,"AccountApiClient")}constructor(e=De){this.apiBaseUrl=e}refreshPromise=null;async refreshAccessToken(){const e=Ne();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 Zt(n.access_token,o,n.expires_in),n.access_token}async getAuthToken(){const e=Gr();if(e&&!Vr())return e;if(Ne())return this.refreshAccessToken();const t=Yt();if(t)return t;throw new Error("Not authenticated. Run `membrane login` or set MEMBRANE_WORKSPACE_KEY and MEMBRANE_WORKSPACE_SECRET.")}async request(e,t={}){const n=t.headers?t.headers instanceof Headers?new Headers(t.headers):new Headers(t.headers):new Headers;if(!n.has("Authorization")){const s=await this.getAuthToken();n.set("Authorization",`Bearer ${s}`)}t.body&&!n.has("Content-Type")&&n.set("Content-Type","application/json");let o=await fetch(`${this.apiBaseUrl}${e}`,{...t,headers:n});if(o.status===401&&Ne()){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 Error(`API request failed: ${o.status} ${o.statusText} - ${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"})}}new pt(Me());const Qr=c(r=>{const e=new pt(Me());return t=>e.get(t)},"createAccountApiFetcher"),eo="membrane",to=["**/node_modules/**","**/.git/**","**/.DS_Store","**/Thumbs.db","**/*.tmp","**/*.swp","**/*.swo","**/*.log","**/*.lock","**/.cache/**","**/.next/**","**/.vscode/**","**/.idea/**","**/.logs/**"];function q(r){return E.join(r,eo)}c(q,"getMembraneDir");const Xt=_e(q(process.cwd()),".logs");class no{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`;Ln(Xt,{recursive:!0});const i=_e(Xt,o),s=this._logs.map(a=>`[${a.timestamp}] ${a.type?.toUpperCase()||"INFO"}: ${a.message}`).join(`
|
|
6
|
+
`);return jn(i,s,"utf-8"),i}catch(t){return console.error("Failed to save logs:",t),null}}}const m=new no,Qt=new hr;class en{static{c(this,"RequestLogger")}constructor(e=Jn){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=Qt.getStore();t.metadata={startTime:Date.now(),skipErrorLog:n};const{method:o,url:i}=this.getRequestDetails(t);return m.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 m.debug(`[Response]: ${n} ${o} - ${s} ${a} (${i}ms)`),t},e),this.interceptorsConfigured=!0}static withSkipErrorLog(e){return Qt.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;m.error(`[Response]: ${t} ${n} - ${i} ${s} (${o}ms)`),e.response.data&&m.error(`[Response Data]: ${JSON.stringify(e.response.data,null,2)}`)}}}function ro(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(ro,"createTrackedClient");class oo{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 en,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=ro(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(`
|
|
7
|
+
Membrane API Error:`),a&&console.error(a),console.error(JSON.stringify(z(s),null,2))):dr(s)?(console.error(`
|
|
8
8
|
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(`
|
|
9
|
-
Unexpected Error:`),a&&console.error(a),console.error(s)),s}return}},"executeRequest");return t?i():Jt.withSkipErrorLog(i)}async generateAccessToken(e,t){return ze.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=Ce(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 kt({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;f.debug(`[${s}] Retrying ${t} (attempt ${a}/${this.maxRetries+1})`);let l=this.retryDelay*Math.pow(2,o);if(this.enableJitter){const d=l*.25*(Math.random()*2-1);l=Math.max(0,l+d)}await new Promise(d=>setTimeout(d,l))}throw n||new Error("Unknown error occurred during retry attempts")}isRetryableError(e){if(!e)return!1;const t=(e.message||e.toString()||"").toLowerCase(),n=e.code;return n&&["econnrefused","enotfound","econnreset","etimedout","ehostunreach","enetunreach"].includes(n.toLowerCase())?!0:["econnrefused","connection refused","network error","timeout","socket hang up","request timeout","dns lookup failed"].some(s=>t.includes(s))}async withTimeout(e,t){let n;const o=new Promise((i,s)=>{n=setTimeout(()=>s(new Error(`Request timeout after ${t}ms`)),t)});try{const i=await Promise.race([e,o]);return n&&clearTimeout(n),i}catch(i){throw n&&clearTimeout(n),i}}async getVersion(){try{return(await this.withClient(t=>t.get("version"),!1))?.version??null}catch{return null}}}const I=new Mr;async function Gt(r){const e=await I.withClient(t=>t.get("org-workspace-id"),!0,r);if(!e)throw new Error("Failed to get workspace ID");return e.id}c(Gt,"getWorkspaceId");const Z={UPDATE:"update",DELETE:"delete",CREATE:"create"},B={INCOMING:"incoming",OUTGOING:"outgoing"},z={[x.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")},[x.Connector]:{element:"connector",elements:"connectors",exportable:!1},[x.Action]:{element:"action",elements:"actions",integrationSpecific:!0,exportCleanup:c(r=>(delete r.integration,r),"exportCleanup")},[x.AppDataSchema]:{element:"appDataSchema",elements:"appDataSchemas"},[x.AppEventType]:{element:"appEventType",elements:"appEventTypes"},[x.DataLinkTable]:{element:"dataLinkTable",elements:"dataLinkTables"},[x.DataSource]:{element:"dataSource",elements:"dataSources",parentKey:"universalDataSourceId",integrationSpecific:!0},[x.FieldMapping]:{element:"fieldMapping",elements:"fieldMappings",integrationSpecific:!0,parentKey:"universalFieldMappingId",exportCleanup:c(r=>(delete r.dataSourceId,r),"exportCleanup")},[x.Flow]:{element:"flow",elements:"flows",integrationSpecific:!0,parentKey:"universalFlowId"},[x.Package]:{element:"package",elements:"packages",integrationSpecific:!0}},Fr=["id","workspaceId","integrationId","createdAt","updatedAt","revision","archivedAt","baseUri","state","appliedToIntegrations","dependencies"],Ht=[x.Action,x.FieldMapping,x.Flow,x.DataSource,x.Package];class M{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||M.extractIntegrationKey(o)}get id(){return M.makeId(this.type,this.key,this.integrationKey)}get dirPath(){const e=V[this.type].apiPath;if(this.integrationKey){const t=V[x.Integration].apiPath;return E.join(t,this.integrationKey,e,this.key)}return E.join(e,this.key)}get path(){return E.join(this.dirPath,"spec.yaml")}get relativePath(){return E.relative(U(process.cwd()),this.path)}get absolutePath(){return E.resolve(E.join(U(process.cwd()),this.path))}isEqual(e){if(this.id!==e.id)return!1;const t=this.clean(),n=e.clean();return Qn(t,n)}hasParent(){if(this.data?.parentUuid)return!0;const e=this.getParentKey();return!!e&&!!this.data?.[e]}clean(){const e={...this.data};return Fr.forEach(t=>{delete e[t]}),Object.keys(e).forEach(t=>{t.match(/universal.*Revision/)&&delete e[t]}),e}getParentKey(){let e="parentId";return z?.[this.type]?.parentKey&&(e=z?.[this.type]?.parentKey),e}static new(e,t,n,o){return new M(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 M(e,t.key,n,t)}static fromPathAndData(e,t){const n=M.parsePath(e);if(!t)return;const o=t?.key||n?.key;return n?M.new(n.type,o,n.integrationKey,t):void 0}static fromElement(e){return new M(e.type,e.key,e.integrationKey,{...e.data})}static idFromPath(e){const t=M.parsePath(e);if(t)return M.makeId(t.type,t.key,t.integrationKey)}static makeId(e,t,n){return e===x.Integration?`${e}:${t}`:M.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(V).map(l=>l.apiPath).join("|"),o=new RegExp(`^(?<elementType>${n})/(?<elementKey>[^/]+)/spec\\.ya?ml$`),i=t.match(o);if(i?.groups){const{elementType:l,elementKey:d}=i.groups,h=this.getElementTypeFromPath(l);if(h)return{type:h,key:d}}const s=new RegExp(`^integrations/(?<integrationKey>[^/]+)/(?<elementType>${n})/(?<elementKey>[^/]+)/spec\\.ya?ml$`),a=t.match(s);if(a?.groups){const{integrationKey:l,elementType:d,elementKey:h}=a.groups,m=this.getElementTypeFromPath(d);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(x).find(t=>V[t].apiPath===e)}static getRelativePath(e){return E.relative(U(process.cwd()),e)}static isIntegrationSpecific(e){return Ht.includes(e)}static canBeIntegrationSpecific(e){return Ht.includes(e)}}class zt{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=[x.Integration,x.Connector],o=Object.keys(z),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 f.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 it(r,e=!0){if(v.existsSync(r))try{const t=v.readFileSync(r,"utf8");return G.load(t)||void 0}catch(t){if(!e)return;if(t instanceof Error){const n=E.relative(process.cwd(),r);throw new Error(`Failed to parse YAML file "${n}": ${t.message}`)}throw t}}c(it,"readYaml$1");function Lr(r,e,t){try{const n=G.dump(e,t);v.writeFileSync(r,n,"utf8")}catch(n){if(n instanceof Error){const o=E.relative(process.cwd(),r);throw new Error(`Failed to write YAML file "${o}": ${n.message}`)}throw n}}c(Lr,"writeYaml$1");class jr extends zt{static{c(this,"LocalWorkspaceElementsRepository")}basePath;constructor(e){super(e),this.basePath=U(process.cwd())}async getElementsByType(e,t){const n=[],o=E.join(this.basePath,V[e].apiPath),i=await this.readElementsInDir(o);n.push(...i);for(const s of t){const a=E.join(this.basePath,V[x.Integration].apiPath,s.key,V[e].apiPath),l=await this.readElementsInDir(a);n.push(...l)}return n.length>0&&f.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=E.join(this.basePath,t.dirPath),o=E.join(this.basePath,t.path);return v.existsSync(n)||v.mkdirSync(n,{recursive:!0}),Lr(o,e.data),f.debug(`[local] Written ${t.relativePath}`),t}async deleteElement(e){const t=E.join(this.basePath,e.path),n=E.join(this.basePath,e.dirPath);v.existsSync(t)&&v.rmSync(t,{force:!0}),this.pruneEmptyDir(n),f.debug(`[local] Deleted ${e.relativePath}`)}async getIntegrations(){const e=E.join(this.basePath,V[x.Integration].apiPath);return this.readElementsInDir(e)}async readElement(e){const t=it(e);if(t)return M.fromPathAndData(e,t)}async readElementsInDir(e){const t=[];if(!v.existsSync(e))return t;const n=v.readdirSync(e);if(n.length===0)return t;const o=n.map(async s=>{const a=E.join(e,s,"spec.yaml");return this.readElement(a)});return(await Promise.all(o)).filter(s=>s!=null)}pruneEmptyDir(e){try{if(!e.startsWith(this.basePath)||e===this.basePath||!v.existsSync(e)||v.readdirSync(e).length>0)return;v.rmdirSync(e),this.pruneEmptyDir(E.dirname(e))}catch(t){console.warn(`Failed to prune empty directory ${e}:`,t)}}}class Ur extends zt{static{c(this,"RemoteWorkspaceElementsRepository")}async getElementsByType(e,t){const n=M.canBeIntegrationSpecific(e),o=await this.findAll(e,n?{layer:"universal"}:{});if(!M.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&&f.debug(`[remote] Fetched ${o.length} ${e}${o.length!==1?"s":""}`),o}async getElement(e){const t=await I.withClient(n=>n[z[e.type].element](e.data.id).get());return M.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 I.withClient(s=>s[z[e.type].elements].create(n)),i=M.fromData(e.type,o);return f.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 I.withClient(a=>a[z[e.type].element](t.data.id).restore());const o=e.clean();if(this.transformElementForUpdate(e,o,n),e.hasParent()&&o.integrationId&&!o.isCustomized)return f.debug(`[remote] Skipped update for ${t.id} (non-customized)`),t;const i=await I.withClient(a=>a[z[e.type].element](t.data.id).put(o)),s=M.fromData(t.type,i);return f.debug(`[remote] Updated ${t.id}`),s}async deleteElement(e){if(!e.data.id)throw new Error("Element must have an id to delete");await I.withClient(t=>t[z[e.type].element](e.data.id).archive()),f.debug(`[remote] Deleted ${e.id}`)}async getIntegrations(){const e=await I.withClient(n=>n.integrations.findAll());if(!e)return[];const t=e.map(n=>M.fromData(x.Integration,n));return t.length>0&&f.debug(`[remote] Fetched ${t.length} integrations`),t}async getByInternalId(e,t){let n;if(n=await I.withClient(o=>o[z[t].element](e).get(),!1),!!n)return M.fromData(t,n)}transformElementForCreate(e,t,n){if(e.integrationKey){const o=n.elements.find(i=>i.type===x.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===x.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===x.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===x.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!==x.Package||!t.elements)return;const o=t.elements.map(i=>{const a=(n.sourceElements||n.elements).find(d=>d.data.id===i.id&&d.type===i.type);if(!a)throw new Error(`Package element ${i.type} with id ${i.id} not found in source workspace for package ${e.id}`);const l=n.elements.find(d=>d.type===i.type&&d.key===a.key&&d.integrationKey===a.integrationKey);if(!l)throw new Error(`Package element ${i.type} with key ${a.key} not found in target workspace for package ${e.id}`);return{id:l.data.id,type:i.type}});t.elements=o}transformParentDependency(e,t,n){if(!e.hasParent())return;const o=e.getParentKey();if(!o)return;const i=n.elements.find(s=>s.type===e.type&&s.key===e.key&&!s.hasParent());if(i)t[o]=i.data.id;else throw new Error(`Parent ${e.getParentKey()} not found for ${e.id}`)}async findAll(e,t={},n){const o=await I.withClient(i=>i[z[e].elements].findAll(t));return o?o.filter(i=>i.key).map(i=>(n&&!i.integrationKey&&(i.integrationKey=n),M.fromData(e,i))):[]}}class st extends or{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 _={Updated:"updated",Deleted:"deleted",Stopped:"stopped"},Kr={ignored:Dr,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 qr extends st{static{c(this,"LocalElementWatcher")}constructor(e){super(),this.options=e,this.membraneDir=U(this.options.cwd),this.lockTimeoutMs=this.options.lockTimeoutMs??1e3}isWatching=!1;watcher;membraneDir;contentCache={};ignoredPaths=new Set;lockTimeoutMs;async start(){this.isWatching||(v.existsSync(this.membraneDir)||v.mkdirSync(this.membraneDir,{recursive:!0}),this.initializeContentCache(),this.watcher=nr.watch(this.membraneDir,Kr),this.watcher.on("add",e=>this.handleFileSystemEvent(_.Updated,e)).on("change",e=>this.handleFileSystemEvent(_.Updated,e)).on("unlink",e=>this.handleFileSystemEvent(_.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(_.Stopped))}getCwd(){return this.options.cwd}async executeWithPathLock(e,t){const n=E.resolve(e);this.ignoredPaths.add(n);try{await t()}finally{setTimeout(()=>{this.ignoredPaths.delete(n)},this.lockTimeoutMs)}}isPathLocked(e){const t=E.resolve(e);if(this.ignoredPaths.has(t))return!0;for(const n of this.ignoredPaths)if(t.startsWith(n+E.sep))return!0;return!1}clearAllLocks(){this.ignoredPaths.clear()}handleFileSystemEvent(e,t){const n=E.relative(this.membraneDir,t);if(this.isPathLocked(t))return;if(e===_.Deleted){this.removeFromCache(n);const a={filePath:t,relativePath:n,data:void 0};f.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&&(f.info(`[local] ${e}: ${s.relativePath}`),this.emit(e,s))}readFileContent(e){return v.readFileSync(e,"utf8")}processFileEvent(e,t){const n=E.relative(this.membraneDir,e);let o;try{o=t?rr.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 er.createHash("sha256").update(e).digest("hex")}updateCache(e,t){if(!t){delete this.contentCache[e];return}this.contentCache[e]=this.getContentHash(t)}removeFromCache(e){delete this.contentCache[e]}clearCache(){Object.keys(this.contentCache).forEach(e=>{delete this.contentCache[e]})}initializeContentCache(){v.existsSync(this.membraneDir)&&this.scanDirectoryForCache(this.membraneDir)}scanDirectoryForCache(e){const t=v.readdirSync(e,{withFileTypes:!0});for(const n of t){const o=E.join(e,n.name);if(n.isDirectory())this.scanDirectoryForCache(o);else if(n.isFile())try{const i=v.readFileSync(o,"utf8"),s=E.relative(this.membraneDir,o);this.updateCache(s,i)}catch{}}}}var at=(r=>(r.Updated="updated",r.ConnectorFileUpdated="connector-file-updated",r.Connected="connected",r.Disconnected="disconnected",r.Error="error",r))(at||{});const Br={debounceMs:2e3,reconnectIntervalMs:5e3,maxReconnectAttempts:1/0,maxBackoffMs:6e4,connectionTimeoutMs:3e5};class _r extends st{static{c(this,"RemoteElementWatcher")}constructor(e=Br){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{f.debug("[remote-events] Connecting to server"),this.eventSource&&(this.eventSource.close(),this.eventSource=void 0);const e=await I.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)}`;f.debug("[remote-events] Subscribing to workspace events"),this.eventSource=new ir(n),this.setupEventSourceHandlers()}catch(e){f.debug(`[remote-events] Failed to connect: ${e}`),this.emit("error",{error:e}),this.scheduleReconnect()}}setupEventSourceHandlers(){this.eventSource&&(this.eventSource.onopen=()=>{f.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){f.debug(`[remote-events] Failed to parse workspace event: ${t}`)}},this.eventSource.onerror=e=>{f.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!==Fn.ElementUpdate)return;const{elementId:t,elementType:n,data:o={}}=e;if(!(!t||!n)){if(n===x.Connector){const{filePath:i,eventType:s,newPath:a}=o;return f.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&&(f.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);f.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&&(f.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 Vt{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 pe="connectors",X="development",ct={};async function Yt(r={}){const{onProgress:e}=r,t=new Set,o=(await I.withClient(d=>d.get("org-workspace-id"))).id,i={};f.info("[connectors] Loading custom connectors"),await I.withClient(d=>d.get(`/connectors?workspaceId=${o}`)),f.info("[connectors] Loading public connectors");const s=ee(),l=(P.existsSync(s)?P.readdirSync(s):[]).filter(d=>{if(d.startsWith("."))return!1;const h=$.join(s,d);try{return P.statSync(h).isDirectory()}catch{return!1}});for(const d of l){f.info(`[connectors] Loading connector from: ${d}`);const h=P.readdirSync($.join(s,d)),m=await lt(d);if(!m)continue;e?.("pushing",m.name),"baseUri"in m&&delete m.baseUri;let p;m.uuid&&(p=await I.withClient(S=>S.get(`/connectors/${m.uuid}`),!1));const w=m.uuid;if(p)i[w]=p.id,f.info(`[connectors] Matched ${m.name} uuid: ${m.uuid}`),p.isPublic||(p.archivedAt&&(f.info(`[connectors] Restoring archived connector ${m.name}`),await I.withClient(S=>S.post(`connectors/${p.id}/restore`))),f.info(`[connectors] Updating connector ${m.name}`),await I.withClient(S=>S.patch(`connectors/${p.id}`,{...m,workspaceId:o})));else if(!i[w]&&!p?.isPublic){let S=!1;try{const O=await ut({connectorId:w});O&&O.isPublic&&(S=!0)}catch{}if(!S){f.info(`[connectors] Creating custom connector ${m.name} (${m.key})`);const O=await I.withClient(N=>N.post("connectors",{...m,workspaceId:o}));i[w]=O.id}}const T=h.filter(S=>P.statSync($.join(s,d,S)).isDirectory());for(const S of T)await Gr({connector:m,version:S,connectorId:i[w]}),t.add(w);e?.("pushed",m.name)}return{connectorsMapping:i,pushedConnectors:Array.from(t)}}c(Yt,"pushConnectors");async function Zt({connectorId:r,connectorVersion:e,allConnectors:t,pulledConnectors:n,pulledConnectorVersions:o}){if(!r||o[r]?.has(e))return;const i=Ut(),s=await ut({connectorId:r});if(!s.isPublic||t){if(!s?.key){console.error(`[connectors] Connector ${r} has no key. Skipping..`),f.error(`[connectors] Connector ${r} has no key. Skipping..`);return}n.has(r)||(await Hr({basePath:i,connector:s}),n.add(r)),o[r]||(o[r]=new Set),o[r].has(e)||(await zr({connector:s,connectorVersion:e,basePath:i}),o[r].add(e))}}c(Zt,"pullRemoteConnector");function ee(){const r=ot();return $.join(r.membraneDirPath,pe)}c(ee,"getConnectorsPath");async function lt(r){const e=$.join(ee(),r,`${r}.yml`);return it(e,!1)}c(lt,"readConnector");async function Wr(r,e){return f.info(`[connectors] Zipping ${r} into ${e}`),new Promise((t,n)=>{const o=P.createWriteStream(e),i=Ve("zip",{zlib:{level:9}});o.on("close",()=>{f.success(`[connectors] Successfully created ${e}`),t()}),o.on("end",()=>{f.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=P.readdirSync(r);for(const a of s){const l=$.join(r,a),d=P.statSync(l);d.isFile()?i.file(l,{name:a}):d.isDirectory()&&i.directory(l,a)}i.finalize()})}c(Wr,"createZipArchive");async function Jr(r,e){return f.info(`[connectors] Unzipping into ${e}`),new Promise((t,n)=>{const o=Re.Parse();o.on("entry",i=>{const s=i.path;if(i.type==="Directory"){const l=$.join(e,s);P.mkdirSync(l,{recursive:!0}),i.autodrain()}else{const l=$.join(e,s),d=$.dirname(l);P.mkdirSync(d,{recursive:!0});const h=P.createWriteStream(l);i.pipe(h),h.on("finish",()=>{})}}),o.on("end",()=>{f.success(`[connectors] Successfully extracted to ${e}`),t()}),o.on("error",i=>{n(i)}),o.write(r),o.end()})}c(Jr,"extractZipArchive");async function Gr({connector:r,version:e,connectorId:t}){const n=$.join(ee(),Q(r),Xt(e)),o=$.join(n,"src"),i=$.join(n,"src.zip"),s=P.existsSync(i);if(P.existsSync(o)&&(f.info(`[connectors] Archiving source code for ${r.name} version ${e}`),await Wr(o,i)),!P.existsSync(i)){f.warning(`[connectors] No source code found for ${r.name} version ${e}`);return}try{const a=new Mt;if(a.append("file",P.createReadStream(i),"file.zip"),f.info(`[connectors] Pushing connector version ${e} for ${r.name}`),e==X)f.info(`[connectors] Uploading connector ${t}`),await I.withClient(l=>l.post(`connectors/${t}/upload`,a,{headers:{...a.getHeaders()}}));else{if(a.append("version",e),a.append("changelog","Imported Version"),(await I.withClient(d=>d.get(`/connectors/${t}/versions`))).find(d=>d.version==e)){f.info(`[connectors] Version ${e} already published`);return}f.info(`[connectors] Publishing version ${e} of connector ${t}`),await I.withClient(d=>d.post(`connectors/${t}/publish-version`,a,{headers:{...a.getHeaders()}}))}f.success(`Successfully pushed connector version ${e} for ${r.name}`)}catch(a){f.error(`Error pushing connector version ${e} for ${r.name}: ${a}`),console.error(`[connectors] Error pushing connector version ${e} for ${r.name}: ${a}`)}finally{!s&&P.existsSync(i)&&(f.info(`[connectors] Cleaning up temporary zip file for ${r.name} version ${e}`),P.unlinkSync(i))}}c(Gr,"pushConnectorVersion");async function ut({connectorId:r}){if(r){if(ct[r])return ct[r];try{const e=await I.withClient(t=>t.get(`connectors/${r}`),!1);return ct[r]=e,e}catch(e){return f.error(`[connectors] Failed to get connector ${r}: ${e}`),console.error(`[connectors] Failed to get connector ${r}: ${e}`),null}}}c(ut,"getConnector");async function Hr({basePath:r,connector:e}){const t=Q(e),n=$.join(r,pe,t);P.mkdirSync(n,{recursive:!0});const o=$.join(n,`${Q(e)}.yml`);P.writeFileSync(o,G.dump(e)),f.info(`[connectors] Pulled connector ${e.name}`)}c(Hr,"pullConnector$1");async function zr({connector:r,connectorVersion:e,basePath:t}){const n=Q(r),o=Xt(e),i=$.join(t,"connectors",n,o),s=await I.withClient(l=>l.get(`connectors/${r.id}/download`,{version:e},{responseType:"arraybuffer",headers:{Accept:"application/zip"},timeout:1e6}));P.mkdirSync(i,{recursive:!0});const a=$.join(i,"src.zip");if(P.writeFileSync(a,s),!e){const l=$.join(i,"src");P.mkdirSync(l,{recursive:!0}),await Jr(s,l)}f.info(`[connectors] Pulled connector version: ${r.name} (${o})`)}c(zr,"pullConnectorVersion");function Q(r){return r.key}c(Q,"getConnectorDirName");function Xt(r){return r??X}c(Xt,"getConnectorVersionDirName");function Vr(r){const e=Ut(),t=Q(r);return $.join(e,pe,t)}c(Vr,"getConnectorDirPath");function Yr(r){return r.match(`${pe}/[^/]+/${X}/src/.*`)!==null}c(Yr,"isConnectorSourceFile");async function Zr(r){const e=r.match(`${pe}/([^/]+)/${X}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await lt(t);if(!o){f.warning(`[connectors] Connector ${t} not found. Ignoring file change`);return}const i=o.id,s=P.readFileSync(r,"utf-8");await I.withClient(a=>a.put(`connectors/${i}/files/${n}`,s,{headers:{"Content-Type":"text/plain"}})),f.info(`[connectors] Pushed file ${n} for connector ${o.name}`)}c(Zr,"putConnectorFile");async function Xr(r){const e=r.match(`${pe}/([^/]+)/${X}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await lt(t);if(!o){f.warning(`[connectors] Connector ${t} not found. Ignoring file change`);return}const i=o.id;await I.withClient(s=>s.delete(`connectors/${i}/files/${n}`)),f.info(`[connectors] Deleted file ${n} for connector ${o.name}`)}c(Xr,"deleteConnectorFile");async function Qr(r,e){try{const t=await I.withClient(s=>s.get(`connectors/${r}`));if(!t){f.warning(`[connectors] Connector ${r} not found`);return}const n=await I.withClient(s=>s.get(`connectors/${r}/files/${e}`)),o=Q(t),i=$.join(ee(),o,X,"src",e);P.mkdirSync($.dirname(i),{recursive:!0}),n!=null?(P.writeFileSync(i,n),f.info(`[connectors] Pulled file ${e} for connector ${t.name}`)):P.existsSync(i)&&(P.unlinkSync(i),f.info(`[connectors] Deleted file ${e} for connector ${t.name}`))}catch(t){f.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(Qr,"pullConnectorFile");async function eo(r,e){const t=await I.withClient(i=>i.get(`connectors/${r}`),!1);if(!t){f.warning(`[connectors] Connector ${r} not found`);return}const n=Q(t),o=$.join(ee(),n,X,"src",e);P.existsSync(o)&&(P.unlinkSync(o),f.info(`[connectors] Deleted file ${e} for connector ${n}`))}c(eo,"deleteLocalConnectorFile");async function to(r,e,t){if(t&&e!==t)try{const n=await I.withClient(l=>l.get(`connectors/${r}`),!1);if(!n){f.warning(`[connectors] Connector ${r} not found`);return}const o=Q(n),i=$.join(ee(),o,X,"src"),s=$.join(i,e),a=$.join(i,t);P.existsSync(s)&&(P.mkdirSync($.dirname(a),{recursive:!0}),P.renameSync(s,a),f.info(`[connectors] Renamed directory from ${e} to ${t} for connector ${o}`))}catch(n){f.error(`[connectors] Failed to rename directory ${e} to ${t} for connector ${r}: ${n}`)}}c(to,"renameLocalConnectorDirectory");async function no(r,e){try{const t=await I.withClient(i=>i.get(`connectors/${r}`),!1);if(!t){f.warning(`[connectors] Connector ${r} not found`);return}const n=Q(t),o=$.join(ee(),n,X,"src",e);if(P.existsSync(o)){const i=$.resolve(ee());if(!$.resolve(o).startsWith(i))return;P.rmSync(o,{recursive:!0,force:!0}),f.info(`[connectors] Deleted directory ${e} for connector ${n}`)}}catch(t){f.error(`[connectors] Failed to delete directory ${e} for connector ${r}: ${t}`)}}c(no,"deleteLocalConnectorDirectory");const F={LogAdded:"logAdded",StateChanged:"stateChanged",StatsChanged:"statsChanged",ConflictsChanged:"conflictsChanged",McpStatusChanged:"mcpStatusChanged",McpServersChanged:"mcpServersChanged",ConfigChanged:"configChanged"};class ro extends st{static{c(this,"WorkspaceNotifications")}constructor(e){super(),this.config=e,f.setNotificationHandler(this)}clientId;heartbeatInterval;isCleaningUp=!1;async connectToRemote(){await this.registerWithRemoteServer(),await this.startHeartbeatLoop()}async setState(e){this.emit(F.StateChanged,{state:e}),await this.emitRemote({status:e})}setConflicts(e){this.emit(F.ConflictsChanged,{conflicts:e})}setConfig(e){this.emit(F.ConfigChanged,{config:e})}setStats(e){this.emit(F.StatsChanged,{stats:e})}addLog(e){this.emit(F.LogAdded,{log:e})}setMcpStatus(e){this.emit(F.McpStatusChanged,{status:e})}async setMcpServers(e){this.emit(F.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 I.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 I.withClient(t=>t.post("/local-clients",{hostname:Nt.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 I.withClient(e=>e.post(`/local-clients/${this.clientId}/keep-alive`,{}))})}async emitRemote(e){this.clientId&&await this.withErrorHandling(async()=>{await I.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 te=new ro({heartbeatIntervalMs:15e3}),Qt=[x.AppDataSchema,x.AppEventType,x.DataLinkTable,x.DataSource,x.FieldMapping,x.Action,x.Flow,x.Package];class Te{static{c(this,"ElementSyncService")}localWatcher=void 0;remoteWatcher=void 0;notifier;changes=[];localCache;remoteCache;localRepo;remoteRepo;pulledConnectors=new Set;pulledConnectorVersions={};constructor(){this.notifier=te,this.localCache=new Vt,this.remoteCache=new Vt,this.localRepo=new jr(this.localCache),this.remoteRepo=new Ur(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 f.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 f.error(`Failed to delete element ${e.id}: ${i}`),i}}async pullConnectors(e=!1){const t=this.remoteCache.getElementsByType(x.Integration).map(n=>n.data);for(const n of t){const o=n.connectorId,i=n.connectorVersion;o&&await Zt({connectorId:o,connectorVersion:i,allConnectors:e,pulledConnectors:this.pulledConnectors,pulledConnectorVersions:this.pulledConnectorVersions})}}async pushConnectors(){const{connectorsMapping:e}=await Yt();this.remoteRepo.setConnectorsMapping(e)}getHandler(e){return e===B.INCOMING?this.localRepo:(this.remoteRepo.setSourceCache(this.localCache),this.remoteRepo)}getCache(e){return e===B.INCOMING?this.localCache:this.remoteCache}async startWatching(){this.localWatcher=new qr({cwd:process.cwd(),lockTimeoutMs:1e3}),this.localWatcher.on(_.Updated,e=>this.handleLocalEvent(e,_.Updated)),this.localWatcher.on(_.Deleted,e=>this.handleLocalEvent(e,_.Deleted)),await this.localWatcher.start(),f.success("[local] Tracking changes.."),this.remoteWatcher=new _r,this.remoteWatcher.on(at.Updated,({elementId:e,elementType:t})=>this.handleRemoteElementEvent(e,t)),this.remoteWatcher.on(at.ConnectorFileUpdated,({connectorId:e,filePath:t,eventType:n,newPath:o})=>this.handleRemoteConnectorFileEvent(e,t,n,o)),await this.remoteWatcher.start(),f.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?(f.info(`[${this.getDirectionLabel(B.INCOMING)}] Deleted: ${s.id}`),this.localWatcher?.executeWithPathLock(s.absolutePath,()=>this.deleteElement(s,B.INCOMING))):void 0}if(f.info(`[${this.getDirectionLabel(B.INCOMING)}] Updated: ${n.id}`),await this.localWatcher?.executeWithPathLock(n.absolutePath,async()=>this.updateElement(n,B.INCOMING)),t===x.Integration){const s=n.data.connectorId,a=n.data.connectorVersion,l=await ut({connectorId:s});if(!l?.key)return;const d=Vr(l);await this.localWatcher?.executeWithPathLock(d,async()=>Zt({connectorId:s,connectorVersion:a,allConnectors:!1,pulledConnectors:this.pulledConnectors,pulledConnectorVersions:this.pulledConnectorVersions}))}}catch(n){f.error(`[sync] Error handling remote event: ${n}`)}}async handleRemoteConnectorFileEvent(e,t,n,o){try{switch(n){case Le.ConnectorFileDeleted:await eo(e,t);break;case Le.ConnectorDirectoryRenamed:await to(e,t,o);break;case Le.ConnectorDirectoryDeleted:await no(e,t);break;default:await Qr(e,t);break}}catch(i){f.error(`[sync] Error handling remote connector file event: ${i}`)}}async handleLocalEvent(e,t){try{if(Yr(e.filePath))switch(t){case _.Updated:await Zr(e.filePath);break;case _.Deleted:await Xr(e.filePath);break}else{let n=M.fromPathAndData(e.filePath,e.data);if(!n){const o=M.idFromPath(e.filePath);if(!o||(n=this.remoteCache.get(o),!n))return}switch(f.info(`[${this.getDirectionLabel(B.OUTGOING)}] ${Xn(t)}: ${n.id}`),t){case _.Updated:await this.updateElement(n,B.OUTGOING);break;case _.Deleted:await this.deleteElement(n,B.OUTGOING);break}}}catch(n){f.error(`[sync] Error handling local event: ${n}`)}}detectIncomingChanges(){this.clearChanges();const e=Te.getChanges(B.INCOMING,this.remoteCache,this.localCache);return this.updateChanges(e),e}detectOutgoingChanges(){this.clearChanges();const e=Te.getChanges(B.OUTGOING,this.localCache,this.remoteCache);return this.updateChanges(e),e}async resolveChanges(){if(!this.needsSync())return;f.info("[resolver] Resolving changes.."),f.info("[resolver] Resolving integration elements");const e=this.changes.filter(o=>o.element.type===x.Integration);await Promise.all(e.map(async o=>this.resolveChange(o))),e.length>0&&(await this.fetchElements(),this.changes=this.changes.length>0&&this.changes[0]?.direction===B.INCOMING?this.detectIncomingChanges():this.detectOutgoingChanges(),this.changes=this.changes.filter(o=>o.element.type!==x.Integration)),f.info("[resolver] Resolving universal elements");const t=this.changes.filter(o=>!o.element.hasParent());for(const o of Qt){const i=t.filter(s=>s.element.type===o);f.info(`[resolver] Resolving ${o} elements`),await Promise.all(i.map(async s=>this.resolveChange(s)))}f.info("[resolver] Resolving integration level elements");const n=this.changes.filter(o=>o.element.hasParent());for(const o of Qt){const i=n.filter(s=>s.element.type===o);f.info(`[resolver] Resolving ${o} elements`),await Promise.all(i.map(async s=>this.resolveChange(s)))}f.success("[resolver] Resolved changes")}async resolveChange(e){switch(e.type){case Z.DELETE:return this.deleteElement(e.element,e.direction);case Z.CREATE:return this.updateElement(e.element,e.direction);case Z.UPDATE:return this.updateElement(e.element,e.direction)}}static getChanges(e,t,n){const o=t.getAllIds(),i=n.getAllIds(),s=new Set([...o,...i]),a=[];for(const l of s){const d=t.get(l),h=n.get(l),m=Te.detectChangeForElement(d,h,e);m&&a.push(m)}return a}updateChanges(e){if(this.changes=e,this.needsForcedSync()){const t=e.filter(n=>n.isConflict);f.warning("[resolver] Conflicts detected"),this.notifier.setConflicts(t)}}clearChanges(){this.changes=[]}getDirectionLabel(e){switch(e){case B.INCOMING:return"local\u2190remote";case B.OUTGOING:return"local\u2192remote"}}static detectChangeForElement(e,t,n){return e&&!t?{type:Z.CREATE,element:e,direction:n,isConflict:!1}:!e&&t?{type:Z.DELETE,element:t,direction:n,isConflict:!0}:e&&t&&!e.isEqual(t)?{type:Z.UPDATE,element:e,direction:n,isConflict:!1}:null}}const ne=E.join(sr.tmpdir(),"membrane-mcp-status"),en=3e4;class oo{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=De(void 0,e),n=tn(e);t&&te.setMcpStatus(t),await te.setMcpServers(n)}catch{f.error("Failed to check MCP status")}}}function De(r,e){try{const t=e||process.cwd();if(!r){const o=tn(t);return o.length===0?null:o[0]}const n=pt(r,t);if(v.existsSync(n)){const o=v.statSync(n),i=new Date;if(i.getTime()-o.mtime.getTime()>en)return Se(r,t),null;const a=v.readFileSync(n,"utf8"),l=JSON.parse(a);if(l.isRunning){const d=new Date(l.lastActivity).getTime();if(i.getTime()-d>en)return Se(r,t),null}return l}}catch{r&&e&&Se(r,e)}return null}c(De,"getMcpStatus");function tn(r){try{const e=r||process.cwd(),t=ht(e);if(!v.existsSync(ne))return[];const n=v.readdirSync(ne),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=De(a,e);l&&o.push(l)}}return o.sort((i,s)=>new Date(s.startTime).getTime()-new Date(i.startTime).getTime())}catch{return[]}}c(tn,"getAllMcpStatusFiles");function dt(r){try{const t={...De(r.processId,r.cwd)||{isRunning:!1,startTime:new Date().toISOString(),lastActivity:new Date().toISOString(),toolsCount:0,totalRequests:0,processId:r.processId,cwd:r.cwd,agentName:process.env.AGENT_NAME||"Unnamed Agent"},...r};v.existsSync(ne)||v.mkdirSync(ne,{recursive:!0});const n=pt(r.processId,r.cwd);v.writeFileSync(n,JSON.stringify(t,null,2))}catch{}}c(dt,"updateMcpStatus");function Se(r,e){try{const t=e||process.cwd();if(r){const n=pt(r,t);v.existsSync(n)&&v.unlinkSync(n)}else{const n=ht(t);if(v.existsSync(ne)){const o=v.readdirSync(ne);for(const i of o)i.match(new RegExp(`^mcp-${n}-\\d+\\.json$`))&&v.unlinkSync(E.join(ne,i))}}}catch{}}c(Se,"clearMcpStatus");function io(r,e){const t=De(r,e);t&&dt({processId:r,cwd:e,totalRequests:t.totalRequests+1,lastRequestTime:new Date().toISOString(),lastActivity:new Date().toISOString()})}c(io,"trackToolExecution");function ht(r){return tr("md5").update(r).digest("hex").slice(0,8)}c(ht,"getCwdHash");function pt(r,e){const t=ht(e);return E.join(ne,`mcp-${t}-${r}.json`)}c(pt,"getStatusFilePath");const Oe={Agent:"agent",Cli:"cli"},k={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 so{static{c(this,"MembraneCLIService")}constructor(e,t,n=()=>process.exit(0)){this.mode=e,this.cwd=t,this.onShutdown=n,this.notifier=te,this.mcpStatusService=new oo,this.syncService=new Te,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(f.setVerboseMode(!!e.verbose),e.rps!==void 0&&I.init({maxRequestsPerSecond:e.rps}),await this.notifier.setState(k.PULLING),await this.syncService.fetchElements(),this.syncService.detectIncomingChanges(),this.syncService.needsForcedSync()&&!e.force){await this.notifier.setState(k.CONFLICTS),e.watch||(t=!0);return}await this.syncService.pullConnectors(e.allConnectors),await this.syncWorkspaces(e)}catch(n){t=!0,f.error(`Failed to pull workspace: ${n}`),await this.notifier.setState(k.ERROR),f.saveLogsToFile("error")}finally{if(e.saveLogs&&f.saveLogsToFile(),t)process.exit(1);else return e?.onComplete?.()}}async pushWorkspace(e={}){let t=!1;try{if(f.setVerboseMode(!!e.verbose),e.rps!==void 0&&I.init({maxRequestsPerSecond:e.rps}),await this.notifier.setState(k.PUSHING),await this.syncService.fetchElements(),this.syncService.detectOutgoingChanges(),this.syncService.needsForcedSync()&&!e.force){await this.notifier.setState(k.CONFLICTS),e.watch||(t=!0);return}await this.syncService.pushConnectors(),await this.syncWorkspaces(e)}catch(n){t=!0,f.error(`Failed to push workspace: ${n}`),await this.notifier.setState(k.ERROR),f.saveLogsToFile("error")}finally{if(e.saveLogs&&f.saveLogsToFile(),t)process.exit(1);else return e?.onComplete?.()}}async syncWorkspaces(e={}){try{e.verbose!==void 0&&f.setVerboseMode(!!e.verbose),await this.notifier.setState(k.RESOLVING),this.syncService.needsSync()&&await this.syncService.resolveChanges();const t=await this.syncService.getStats();this.notifier.setStats(t),await this.notifier.setState(k.SYNCED),e.watch&&(await this.notifier.setState(k.WATCHING),await this.syncService.startWatching())}catch(t){f.error(`Failed to sync local and remote workspaces: ${t}`),await this.notifier.setState(k.ERROR),f.saveLogsToFile("error")}}async init({force:e=!1}={}){if(!(this.initialized&&!e)){await this.notifier.setState(k.NOT_INITIALIZED);try{await this.loadConfig(),le.isCacheDefined()?(await this.initServices(),this.initialized=!0,await this.notifier.setState(k.INITIALIZED)):(this.initialized=!1,await this.notifier.setState(k.SETTING_UP))}catch(t){f.error(`Failed to initialize services: ${t}`),await this.notifier.setState(k.ERROR),f.saveLogsToFile("error"),this.onShutdown()}}}async loadConfig(){this.currentConfig=le.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=le.updateConfig(t);this.currentConfig=o,await this.init({force:!0})}async shutdown(){!this.initialized||this.isShuttingDown||(this.isShuttingDown=!0,this.mode===Oe.Agent&&(await this.notifier.cleanup(),await this.mcpStatusService.stop()),this.initialized=!1,this.onShutdown())}async initServices(){this.mode===Oe.Agent&&(await this.notifier.connectToRemote(),await this.mcpStatusService.start()),this.syncService.clear()}async stopServices(){this.mode===Oe.Agent&&(await this.notifier.cleanup(),await this.mcpStatusService.stop())}setupProcessCleanup(){["SIGINT","SIGTERM","uncaughtException","unhandledRejection"].forEach(t=>process.on(t,()=>this.shutdown())),process.on("beforeExit",t=>{t===0&&this.shutdown()})}}const nn=We(null);function ao({children:r,membraneCLIService:e}){const{data:t}=Ot("/account"),[n,o]=D(k.NOT_INITIALIZED),[i,s]=D([]),[a,l]=D({}),[d,h]=D([]),[m,p]=D(null),T=t?.workspaces?.find(S=>S.workspaceKey===m?.workspaceKey)||null;return he(()=>{const S=c(({state:L})=>o(L),"handleStateChanged"),O=c(({stats:L})=>l(L),"handleStatsChanged"),N=c(({log:L})=>h(xe=>[...xe,L]),"handleLogAdded"),K=c(({conflicts:L})=>s(L),"handleConflictsUpdated"),q=c(({config:L})=>p(L),"handleConfigChanged");return e.notifier.on(F.StateChanged,S),e.notifier.on(F.StatsChanged,O),e.notifier.on(F.LogAdded,N),e.notifier.on(F.ConflictsChanged,K),e.notifier.on(F.ConfigChanged,q),e.init(),()=>{e.notifier.off(F.StateChanged,S),e.notifier.off(F.StatsChanged,O),e.notifier.off(F.LogAdded,N),e.notifier.off(F.ConflictsChanged,K),e.notifier.off(F.ConfigChanged,q)}},[]),u(nn.Provider,{value:{state:n,stats:a,logs:d,currentWorkspace:T,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(ao,"MembraneCLIServiceProvider");function H(){const r=Je(nn);if(!r)throw new Error("useMembraneCLIService must be used within MembraneCLIServiceProvider");return r}c(H,"useMembraneCLIService");const ft=We(null),rn=c(()=>{const r=Je(ft);if(!r)throw new Error("useTree must be used within TreeView");return r},"useTree"),co=c(r=>se.Children.count(r)>0,"hasChildren");function lo(r){const e=rn(),{label:t,value:n,isInitiallyExpanded:o}=r,i=Gn(),s=Ge(e.registerChildItem(t)).current,a=e.isActiveByRef(s),[l,d]=D(o??!1),h={props:r,ref:s,id:i,active:a,expanded:l,setExpanded:d,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:co(p)}}c(lo,"useTreeItem");function fe(r){const e=rn(),t=lo(r),{expanded:n,isParent:o,props:{children:i},setExpanded:s}=t,{renderValue:a=ho}=r,l=t.ref;$e(()=>{function p(w){return r.onInput?.(w)?!0:w.active&&w.key.rightArrow&&!n?(s(!0),!0):w.active&&w.key.leftArrow&&n?(s(!1),!0):!1}c(p,"onInput"),l.onInput=p},[l,r.onInput,n,s]),l.firstChild??={parent:l,index:0};let d=l.firstChild;function h(p){const w=d;return w.nextSibling||(w.nextSibling={parent:l,prevSibling:w,index:w.index+1}),d=w.nextSibling,w.label=p,w}c(h,"registerChildItem");function m(){l.lastRenderedChild=d.prevSibling}return c(m,"commitChildren"),$e(()=>{m()}),b(ke,{children:[b(g,{marginLeft:e.depth*2,children:[u(g,{width:2,children:o&&u(y,{children:n?"\u25BC":"\u25B6"})}),uo(t),a(t)]}),n&&u(ft.Provider,{value:{...e,depth:e.depth+1,registerChildItem:h},children:i})]})}c(fe,"TreeItem");function uo({active:r,label:e}){return u(g,{width:32,children:u(y,{inverse:r,children:e})})}c(uo,"defaultRenderLabel");function ho(r){return u(y,{})}c(ho,"defaultRenderValue");const ue=c(({label:r,onPress:e,hotkey:t})=>u(fe,{label:r,onInput:c(({input:n,key:o,active:i})=>i&&o.return||t&&t in o&&o[t]||n===t?(e(),!0):!1,"onInput"),renderValue:c(()=>u(g,{children:u(y,{children:`${t?` (${t})`:""}`})}),"renderValue")}),"ActionTreeItem"),on=c(({label:r,value:e,onChange:t,disabled:n=!1,mask:o,...i})=>{const[s,a]=D(e),[l,d]=D(!1);return $e(()=>{l||a(e)},[l,e]),u(fe,{label:r,value:e,onInput:c(({key:h,active:m})=>n?!1:l?(h.escape&&d(!1),h.return&&(t(s),d(!1)),!0):m&&h.return?(d(!0),a(e),!0):!1,"onInput"),renderValue:c(()=>{const h=s,m=o?o.repeat(h.length):h;return u(g,{children:n||!l?u(y,{dimColor:!0,children:m}):b(ke,{children:[u(g,{width:m.length+1,children:u(Ft,{...i,focus:l,value:h,onChange:a})}),u(y,{dimColor:!0,children:" \u241B cancel"})]})})},"renderValue")})},"TreeTextField"),po=c(r=>u(on,{...r,mask:"*"}),"SecretField"),W=c(({children:r,showHelp:e=!1})=>{const t=Ge({parent:void 0,label:"<<ROOT>>",index:0}),[n,o]=D(t.current),i={depth:0,isActiveByRef:c(a=>n===a,"isActiveByRef"),registerChildItem:c(()=>t.current,"registerChildItem"),activeItemRef:n};$e(()=>{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"),ae((a,l)=>{if(n.onInput?.({input:a,key:l,active:!0}))return;let d,h;for(const m of s(t.current))if(m.label!=null){if(d===n&&(h=m),m&&m.onInput?.({input:a,key:l,active:m===n}))return;d=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)}),u(ft.Provider,{value:i,children:b(g,{flexDirection:"column",children:[u(fe,{isInitiallyExpanded:!0,label:"rootItem",children:r}),e&&u(g,{marginTop:1,flexDirection:"column",children:u(y,{dimColor:!0,children:"\u2191/\u2193 move \u2022 \u2190 collapse \u2022 \u2192 expand \u2022 Enter/Space select/edit \u2022 Esc exit"})})]})})},"TreeView");W.Item=fe,W.TextField=on;function de({label:r,elementType:e,isActionExcluded:t,toggleAction:n,generateCode:o}){const[i,s]=D([]),{fetchElements:a,getSyncedElementsByType:l}=H();return he(()=>{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]),u(fe,{label:r,children:i.map(d=>u(fe,{label:d.name,children:e===x.Action&&b(ke,{children:[t&&n&&u(ue,{label:`Toggle ${t(d)?"":"(excluded)"}`,onPress:c(()=>{n(d)},"onPress")}),o&&u(ue,{label:"Generate code",onPress:c(()=>{o?.(d)},"onPress")})]})},d.id))})}c(de,"WorkspaceElementsTreeItem");function fo({onComplete:r}){const{config:e,updateConfig:t,fetchElements:n,getSyncedElementsByType:o}=H(),[i,s]=D(""),a=e,l=c(p=>{s(p),setTimeout(()=>s(""),2e3)},"setFlash"),d=c(async(p,w)=>{try{await t({[p]:w}),l("\u2705 Configuration updated!")}catch{l("\u274C Error updating configuration")}},"updateField"),h=c(async()=>{try{if(e){const p=le.saveToFile(e);l(p?"\u2705 Configuration saved successfully!":"\u274C Failed to save configuration"),await n();const w=o(x.Action);await et({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:w.filter(T=>!a?.excludedActionKeys?.includes(T.key)).map(T=>T.data)}}),l("\u2705 Code generated successfully!")}}catch{l("\u274C Error saving configuration")}},"handleSaveConfig"),m=c(async()=>{try{const p=le.loadConfig();p?(await t(p),l("\u2705 Configuration reloaded successfully!")):l("\u274C No configuration found to reload")}catch{l("\u274C Error reloading configuration")}},"handleReloadConfig");return b(g,{flexDirection:"column",gap:1,children:[u(y,{bold:!0,color:"cyan",children:"\u2699\uFE0F Membrane Configuration Manager"}),u(g,{paddingX:2,children:b(W,{showHelp:!0,children:[b(W.Item,{label:"Configuration",isInitiallyExpanded:!0,children:[b(W.Item,{label:"Project",children:[u(W.TextField,{label:"Workspace Key",value:a?.workspaceKey??"",onChange:c(p=>d("workspaceKey",p),"onChange"),disabled:!0}),u(po,{label:"Workspace Secret",value:a?.workspaceSecret??"",onChange:c(p=>d("workspaceSecret",p),"onChange"),disabled:!0}),u(W.TextField,{label:"API URI",value:a?.apiUri??"",onChange:c(p=>d("apiUri",p),"onChange")}),u(W.TextField,{label:"Test Customer ID",value:a?.testCustomerId??"",onChange:c(p=>d("testCustomerId",p),"onChange")})]}),b(W.Item,{label:"Code Generation",isInitiallyExpanded:!0,children:[b(W.Item,{label:"Project Type",isInitiallyExpanded:!0,value:a?.projectType,renderValue:c(({value:p})=>u(y,{children:p==="typescript"?"TypeScript":p==="openapi"?"OpenAPI":"(Not set)"}),"renderValue"),children:[u(ue,{label:"Update to TypeScript",onPress:c(()=>d("projectType","typescript"),"onPress")}),u(ue,{label:"Update to OpenAPI",onPress:c(()=>d("projectType","openapi"),"onPress")})]}),u(W.TextField,{label:"Project dir",value:a?.outputDir??"",onChange:c(p=>d("outputDir",p),"onChange")})]}),b(W.Item,{label:"Workspace Elements",children:[u(de,{label:"Actions",elementType:x.Action,isActionExcluded:c(p=>a?.excludedActionKeys?.includes(p.key)??!1,"isActionExcluded"),toggleAction:c(p=>d("excludedActionKeys",[...a?.excludedActionKeys??[],p.key]),"toggleAction"),generateCode:c(p=>{(async()=>{try{await et({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:[p]}}),l("\u2705 Code generated successfully!")}catch{l("\u274C Error generating code")}})()},"generateCode")}),u(de,{label:"Flows",elementType:x.Flow}),u(de,{label:"Data Sources",elementType:x.DataSource}),u(de,{label:"Field Mappings",elementType:x.FieldMapping}),u(de,{label:"Packages",elementType:x.Package}),u(de,{label:"App Data Schemas",elementType:x.AppDataSchema}),u(de,{label:"App Event Types",elementType:x.AppEventType})]})]}),u(ue,{label:"Save Configuration",onPress:h,hotkey:"s"}),u(ue,{label:"Reload Configuration",onPress:m,hotkey:"r"}),u(ue,{label:"Exit",onPress:c(()=>r?.(),"onPress"),hotkey:"escape"})]})}),i&&u(g,{paddingX:2,children:u(y,{color:i.includes("\u2705")?"green":"red",children:i})})]})}c(fo,"ConfigManager");const sn=We(process.cwd());function mo({cwd:r,children:e}){return u(sn.Provider,{value:r,children:e})}c(mo,"CwdProvider");function go(){return Je(sn)}c(go,"useCwd");function mt({cwd:r,children:e,membraneCLIService:t}){const n=r||process.cwd();return u(mo,{cwd:n,children:u(ar,{value:{fetcher:Pr()},children:u(ao,{membraneCLIService:t,children:e})})})}c(mt,"Layout");function yo(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(`
|
|
10
|
-
`)).action(()=>{
|
|
11
|
-
`)).action(t=>{t.key&&t.secret?
|
|
12
|
-
|
|
9
|
+
Unexpected Error:`),a&&console.error(a),console.error(s)),s}return}},"executeRequest");return t?i():en.withSkipErrorLog(i)}async generateAccessToken(e,t){return tt.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=Se(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 jt({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;m.debug(`[${s}] Retrying ${t} (attempt ${a}/${this.maxRetries+1})`);let l=this.retryDelay*Math.pow(2,o);if(this.enableJitter){const d=l*.25*(Math.random()*2-1);l=Math.max(0,l+d)}await new Promise(d=>setTimeout(d,l))}throw n||new Error("Unknown error occurred during retry attempts")}isRetryableError(e){if(!e)return!1;const t=(e.message||e.toString()||"").toLowerCase(),n=e.code;return n&&["econnrefused","enotfound","econnreset","etimedout","ehostunreach","enetunreach"].includes(n.toLowerCase())?!0:["econnrefused","connection refused","network error","timeout","socket hang up","request timeout","dns lookup failed"].some(s=>t.includes(s))}async withTimeout(e,t){let n;const o=new Promise((i,s)=>{n=setTimeout(()=>s(new Error(`Request timeout after ${t}ms`)),t)});try{const i=await Promise.race([e,o]);return n&&clearTimeout(n),i}catch(i){throw n&&clearTimeout(n),i}}async getVersion(){try{return(await this.withClient(t=>t.get("version"),!1))?.version??null}catch{return null}}async isVersionAtLeast(e){const t=await this.getVersion(),n=t?nt.coerce(t):null,o=nt.coerce(e);return!!(n&&o&&nt.gte(n,o))}}const $=new oo;async function tn(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(tn,"getWorkspaceId");const Q={UPDATE:"update",DELETE:"delete",CREATE:"create"},B={INCOMING:"incoming",OUTGOING:"outgoing"},V={[x.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")},[x.Connector]:{element:"connector",elements:"connectors",exportable:!1},[x.Action]:{element:"action",elements:"actions",integrationSpecific:!0,exportCleanup:c(r=>(delete r.integration,r),"exportCleanup")},[x.AppDataSchema]:{element:"appDataSchema",elements:"appDataSchemas"},[x.AppEventType]:{element:"appEventType",elements:"appEventTypes"},[x.DataLinkTable]:{element:"dataLinkTable",elements:"dataLinkTables"},[x.DataSource]:{element:"dataSource",elements:"dataSources",parentKey:"universalDataSourceId",integrationSpecific:!0},[x.FieldMapping]:{element:"fieldMapping",elements:"fieldMappings",integrationSpecific:!0,parentKey:"universalFieldMappingId",exportCleanup:c(r=>(delete r.dataSourceId,r),"exportCleanup")},[x.Flow]:{element:"flow",elements:"flows",integrationSpecific:!0,parentKey:"universalFlowId"},[x.Package]:{element:"package",elements:"packages",integrationSpecific:!0}},io=["id","workspaceId","integrationId","createdAt","updatedAt","revision","archivedAt","baseUri","state","appliedToIntegrations","dependencies"],nn=[x.Action,x.FieldMapping,x.Flow,x.DataSource,x.Package];class F{static{c(this,"Element")}type;key;integrationKey;data;constructor(e,t,n,o){if(!o)throw new Error("Element must always contain data");if(!t)throw new Error("Element must have a key");this.type=e,this.key=t,this.data=o,this.integrationKey=n||F.extractIntegrationKey(o)}get id(){return F.makeId(this.type,this.key,this.integrationKey)}get dirPath(){const e=Z[this.type].apiPath;if(this.integrationKey){const t=Z[x.Integration].apiPath;return E.join(t,this.integrationKey,e,this.key)}return E.join(e,this.key)}get path(){return E.join(this.dirPath,"spec.yaml")}get relativePath(){return E.relative(q(process.cwd()),this.path)}get absolutePath(){return E.resolve(E.join(q(process.cwd()),this.path))}isEqual(e){if(this.id!==e.id)return!1;const t=this.clean(),n=e.clean();return fr(t,n)}hasParent(){if(this.data?.parentUuid)return!0;const e=this.getParentKey();return!!e&&!!this.data?.[e]}clean(){const e={...this.data};return io.forEach(t=>{delete e[t]}),Object.keys(e).forEach(t=>{t.match(/universal.*Revision/)&&delete e[t]}),e}getParentKey(){let e="parentId";return V?.[this.type]?.parentKey&&(e=V?.[this.type]?.parentKey),e}static new(e,t,n,o){return new F(e,t,n,o)}static fromData(e,t){if(!t?.key)throw new Error(`Element missing key: ${JSON.stringify(t)}`);const n=this.extractIntegrationKey(t);return new F(e,t.key,n,t)}static fromPathAndData(e,t){const n=F.parsePath(e);if(!t)return;const o=t?.key||n?.key;return n?F.new(n.type,o,n.integrationKey,t):void 0}static fromElement(e){return new F(e.type,e.key,e.integrationKey,{...e.data})}static idFromPath(e){const t=F.parsePath(e);if(t)return F.makeId(t.type,t.key,t.integrationKey)}static makeId(e,t,n){return e===x.Integration?`${e}:${t}`:F.isIntegrationSpecific(e)?`${n||"universal"}:${e}:${t}`:`${e}:${t}`}static parsePath(e){const t=this.getRelativePath(e);if(!this.isElementFile(t))return;const n=Object.values(Z).map(l=>l.apiPath).join("|"),o=new RegExp(`^(?<elementType>${n})/(?<elementKey>[^/]+)/spec\\.ya?ml$`),i=t.match(o);if(i?.groups){const{elementType:l,elementKey:d}=i.groups,p=this.getElementTypeFromPath(l);if(p)return{type:p,key:d}}const s=new RegExp(`^integrations/(?<integrationKey>[^/]+)/(?<elementType>${n})/(?<elementKey>[^/]+)/spec\\.ya?ml$`),a=t.match(s);if(a?.groups){const{integrationKey:l,elementType:d,elementKey:p}=a.groups,f=this.getElementTypeFromPath(d);if(f)return{type:f,key:p,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(x).find(t=>Z[t].apiPath===e)}static getRelativePath(e){return E.relative(q(process.cwd()),e)}static isIntegrationSpecific(e){return nn.includes(e)}static canBeIntegrationSpecific(e){return nn.includes(e)}}class rn{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=[x.Integration,x.Connector],o=Object.keys(V),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 m.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 ft(r,e=!0){if(v.existsSync(r))try{const t=v.readFileSync(r,"utf8");return H.load(t)||void 0}catch(t){if(!e)return;if(t instanceof Error){const n=E.relative(process.cwd(),r);throw new Error(`Failed to parse YAML file "${n}": ${t.message}`)}throw t}}c(ft,"readYaml$1");function so(r,e,t){try{const n=H.dump(e,t);v.writeFileSync(r,n,"utf8")}catch(n){if(n instanceof Error){const o=E.relative(process.cwd(),r);throw new Error(`Failed to write YAML file "${o}": ${n.message}`)}throw n}}c(so,"writeYaml$1");class ao extends rn{static{c(this,"LocalWorkspaceElementsRepository")}basePath;constructor(e){super(e),this.basePath=q(process.cwd())}async getElementsByType(e,t){const n=[],o=E.join(this.basePath,Z[e].apiPath),i=await this.readElementsInDir(o);n.push(...i);for(const s of t){const a=E.join(this.basePath,Z[x.Integration].apiPath,s.key,Z[e].apiPath),l=await this.readElementsInDir(a);n.push(...l)}return n.length>0&&m.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=E.join(this.basePath,t.dirPath),o=E.join(this.basePath,t.path);return v.existsSync(n)||v.mkdirSync(n,{recursive:!0}),so(o,e.data),m.debug(`[local] Written ${t.relativePath}`),t}async deleteElement(e){const t=E.join(this.basePath,e.path),n=E.join(this.basePath,e.dirPath);v.existsSync(t)&&v.rmSync(t,{force:!0}),this.pruneEmptyDir(n),m.debug(`[local] Deleted ${e.relativePath}`)}async getIntegrations(){const e=E.join(this.basePath,Z[x.Integration].apiPath);return this.readElementsInDir(e)}async readElement(e){const t=ft(e);if(t)return F.fromPathAndData(e,t)}async readElementsInDir(e){const t=[];if(!v.existsSync(e))return t;const n=v.readdirSync(e);if(n.length===0)return t;const o=n.map(async s=>{const a=E.join(e,s,"spec.yaml");return this.readElement(a)});return(await Promise.all(o)).filter(s=>s!=null)}pruneEmptyDir(e){try{if(!e.startsWith(this.basePath)||e===this.basePath||!v.existsSync(e)||v.readdirSync(e).length>0)return;v.rmdirSync(e),this.pruneEmptyDir(E.dirname(e))}catch(t){console.warn(`Failed to prune empty directory ${e}:`,t)}}}class co extends rn{static{c(this,"RemoteWorkspaceElementsRepository")}async getElementsByType(e,t){const n=F.canBeIntegrationSpecific(e),o=await this.findAll(e,n?{layer:"universal"}:{});if(!F.canBeIntegrationSpecific(e))return o;for(const i of t){const s=i.key,a=i.data.id,l=await this.findAll(e,a?{integrationId:a}:{integrationKey:s},s);o.push(...l)}return o.length>0&&m.debug(`[remote] Fetched ${o.length} ${e}${o.length!==1?"s":""}`),o}async getElement(e){const t=await $.withClient(n=>n[V[e.type].element](e.data.id).get());return F.fromData(e.type,t)}async createElement(e,t){const n=e.clean();if(this.transformElementForCreate(e,n,t),e.hasParent()&&n.integrationId&&!n.isCustomized){const s=e.getParentKey(),a=new Set(["uuid","integrationId",s,"meta","integrationUuid","parentUuid"]);Object.keys(n).forEach(l=>{a.has(l)||delete n[l]})}const o=await $.withClient(s=>s[V[e.type].elements].create(n)),i=F.fromData(e.type,o);return m.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[V[e.type].element](t.data.id).restore());const o=e.clean();if(this.transformElementForUpdate(e,o,n),e.hasParent()&&o.integrationId&&!o.isCustomized)return m.debug(`[remote] Skipped update for ${t.id} (non-customized)`),t;const i=await $.withClient(a=>a[V[e.type].element](t.data.id).put(o)),s=F.fromData(t.type,i);return m.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[V[e.type].element](e.data.id).archive()),m.debug(`[remote] Deleted ${e.id}`)}async getIntegrations(){const e=await $.withClient(n=>n.integrations.findAll());if(!e)return[];const t=e.map(n=>F.fromData(x.Integration,n));return t.length>0&&m.debug(`[remote] Fetched ${t.length} integrations`),t}async getByInternalId(e,t){let n;if(n=await $.withClient(o=>o[V[t].element](e).get(),!1),!!n)return F.fromData(t,n)}transformElementForCreate(e,t,n){if(e.integrationKey){const o=n.elements.find(i=>i.type===x.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===x.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===x.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===x.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!==x.Package||!t.elements)return;const o=t.elements.map(i=>{const a=(n.sourceElements||n.elements).find(d=>d.data.id===i.id&&d.type===i.type);if(!a)throw new Error(`Package element ${i.type} with id ${i.id} not found in source workspace for package ${e.id}`);const l=n.elements.find(d=>d.type===i.type&&d.key===a.key&&d.integrationKey===a.integrationKey);if(!l)throw new Error(`Package element ${i.type} with key ${a.key} not found in target workspace for package ${e.id}`);return{id:l.data.id,type:i.type}});t.elements=o}transformParentDependency(e,t,n){if(!e.hasParent())return;const o=e.getParentKey();if(!o)return;const i=n.elements.find(s=>s.type===e.type&&s.key===e.key&&!s.hasParent());if(i)t[o]=i.data.id;else throw new Error(`Parent ${e.getParentKey()} not found for ${e.id}`)}async findAll(e,t={},n){const o=await $.withClient(i=>i[V[e].elements].findAll(t));return o?o.filter(i=>i.key).map(i=>(n&&!i.integrationKey&&(i.integrationKey=n),F.fromData(e,i))):[]}}class mt extends Cr{static{c(this,"TypedEventEmitter")}on(e,t){return super.on(e,t)}emit(e,...t){return super.emit(e,...t)}off(e,t){return super.off(e,t)}once(e,t){return super.once(e,t)}}const W={Updated:"updated",Deleted:"deleted",Stopped:"stopped"},lo={ignored:to,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 uo extends mt{static{c(this,"LocalElementWatcher")}constructor(e){super(),this.options=e,this.membraneDir=q(this.options.cwd),this.lockTimeoutMs=this.options.lockTimeoutMs??1e3}isWatching=!1;watcher;membraneDir;contentCache={};ignoredPaths=new Set;lockTimeoutMs;async start(){this.isWatching||(v.existsSync(this.membraneDir)||v.mkdirSync(this.membraneDir,{recursive:!0}),this.initializeContentCache(),this.watcher=yr.watch(this.membraneDir,lo),this.watcher.on("add",e=>this.handleFileSystemEvent(W.Updated,e)).on("change",e=>this.handleFileSystemEvent(W.Updated,e)).on("unlink",e=>this.handleFileSystemEvent(W.Deleted,e)).on("ready",()=>this.isWatching=!0))}async stop(){!this.isWatching||!this.watcher||(await this.watcher.close(),this.isWatching=!1,this.watcher=void 0,this.clearCache(),this.clearAllLocks(),this.emit(W.Stopped))}getCwd(){return this.options.cwd}async executeWithPathLock(e,t){const n=E.resolve(e);this.ignoredPaths.add(n);try{await t()}finally{setTimeout(()=>{this.ignoredPaths.delete(n)},this.lockTimeoutMs)}}isPathLocked(e){const t=E.resolve(e);if(this.ignoredPaths.has(t))return!0;for(const n of this.ignoredPaths)if(t.startsWith(n+E.sep))return!0;return!1}clearAllLocks(){this.ignoredPaths.clear()}handleFileSystemEvent(e,t){const n=E.relative(this.membraneDir,t);if(this.isPathLocked(t))return;if(e===W.Deleted){this.removeFromCache(n);const a={filePath:t,relativePath:n,data:void 0};m.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&&(m.info(`[local] ${e}: ${s.relativePath}`),this.emit(e,s))}readFileContent(e){return v.readFileSync(e,"utf8")}processFileEvent(e,t){const n=E.relative(this.membraneDir,e);let o;try{o=t?wr.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 mr.createHash("sha256").update(e).digest("hex")}updateCache(e,t){if(!t){delete this.contentCache[e];return}this.contentCache[e]=this.getContentHash(t)}removeFromCache(e){delete this.contentCache[e]}clearCache(){Object.keys(this.contentCache).forEach(e=>{delete this.contentCache[e]})}initializeContentCache(){v.existsSync(this.membraneDir)&&this.scanDirectoryForCache(this.membraneDir)}scanDirectoryForCache(e){const t=v.readdirSync(e,{withFileTypes:!0});for(const n of t){const o=E.join(e,n.name);if(n.isDirectory())this.scanDirectoryForCache(o);else if(n.isFile())try{const i=v.readFileSync(o,"utf8"),s=E.relative(this.membraneDir,o);this.updateCache(s,i)}catch{}}}}var gt=(r=>(r.Updated="updated",r.ConnectorFileUpdated="connector-file-updated",r.Connected="connected",r.Disconnected="disconnected",r.Error="error",r))(gt||{});const ho={debounceMs:2e3,reconnectIntervalMs:5e3,maxReconnectAttempts:1/0,maxBackoffMs:6e4,connectionTimeoutMs:3e5};class po extends mt{static{c(this,"RemoteElementWatcher")}constructor(e=ho){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{m.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)}`;m.debug("[remote-events] Subscribing to workspace events"),this.eventSource=new Sr(n),this.setupEventSourceHandlers()}catch(e){m.debug(`[remote-events] Failed to connect: ${e}`),this.emit("error",{error:e}),this.scheduleReconnect()}}setupEventSourceHandlers(){this.eventSource&&(this.eventSource.onopen=()=>{m.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){m.debug(`[remote-events] Failed to parse workspace event: ${t}`)}},this.eventSource.onerror=e=>{m.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!==zn.ElementUpdate)return;const{elementId:t,elementType:n,data:o={}}=e;if(!(!t||!n)){if(n===x.Connector){const{filePath:i,eventType:s,newPath:a}=o;return m.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&&(m.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);m.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&&(m.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 me="connectors",ee="development",yt={};async function sn(r={}){const{onProgress:e}=r,t=new Set,o=(await $.withClient(d=>d.get("org-workspace-id"))).id,i={};m.info("[connectors] Loading custom connectors"),await $.withClient(d=>d.get(`/connectors?workspaceId=${o}`)),m.info("[connectors] Loading public connectors");const s=ne(),l=(A.existsSync(s)?A.readdirSync(s):[]).filter(d=>{if(d.startsWith("."))return!1;const p=k.join(s,d);try{return A.statSync(p).isDirectory()}catch{return!1}});for(const d of l){m.info(`[connectors] Loading connector from: ${d}`);const p=A.readdirSync(k.join(s,d)),f=await wt(d);if(!f)continue;e?.("pushing",f.name),"baseUri"in f&&delete f.baseUri;let h;f.uuid&&(h=await $.withClient(S=>S.get(`/connectors/${f.uuid}`),!1));const C=f.uuid;if(h)i[C]=h.id,m.info(`[connectors] Matched ${f.name} uuid: ${f.uuid}`),h.isPublic||(h.archivedAt&&(m.info(`[connectors] Restoring archived connector ${f.name}`),await $.withClient(S=>S.post(`connectors/${h.id}/restore`))),m.info(`[connectors] Updating connector ${f.name}`),await $.withClient(S=>S.patch(`connectors/${h.id}`,{...f,workspaceId:o})));else if(!i[C]&&!h?.isPublic){let S=!1;try{const D=await Ct({connectorId:C});D&&D.isPublic&&(S=!0)}catch{}if(!S){m.info(`[connectors] Creating custom connector ${f.name} (${f.key})`);const D=await $.withClient(O=>O.post("connectors",{...f,workspaceId:o}));i[C]=D.id}}const T=p.filter(S=>A.statSync(k.join(s,d,S)).isDirectory());for(const S of T)await go({connector:f,version:S,connectorId:i[C]}),t.add(C);e?.("pushed",f.name)}return{connectorsMapping:i,pushedConnectors:Array.from(t)}}c(sn,"pushConnectors");async function an({connectorId:r,connectorVersion:e,allConnectors:t,pulledConnectors:n,pulledConnectorVersions:o}){if(!r||o[r]?.has(e))return;const i=Vt(),s=await Ct({connectorId:r});if(!s.isPublic||t){if(!s?.key){console.error(`[connectors] Connector ${r} has no key. Skipping..`),m.error(`[connectors] Connector ${r} has no key. Skipping..`);return}n.has(r)||(await yo({basePath:i,connector:s}),n.add(r)),o[r]||(o[r]=new Set),o[r].has(e)||(await wo({connector:s,connectorVersion:e,basePath:i}),o[r].add(e))}}c(an,"pullRemoteConnector");function ne(){const r=ht();return k.join(r.membraneDirPath,me)}c(ne,"getConnectorsPath");async function wt(r){const e=k.join(ne(),r,`${r}.yml`);return ft(e,!1)}c(wt,"readConnector");async function fo(r,e){return m.info(`[connectors] Zipping ${r} into ${e}`),new Promise((t,n)=>{const o=A.createWriteStream(e),i=rt("zip",{zlib:{level:9}});o.on("close",()=>{m.success(`[connectors] Successfully created ${e}`),t()}),o.on("end",()=>{m.info("[connectors] Data has been drained")}),i.on("warning",a=>{a.code==="ENOENT"?console.warn(a):n(a)}),i.on("error",a=>{n(a)}),i.pipe(o);const s=A.readdirSync(r);for(const a of s){const l=k.join(r,a),d=A.statSync(l);d.isFile()?i.file(l,{name:a}):d.isDirectory()&&i.directory(l,a)}i.finalize()})}c(fo,"createZipArchive");async function mo(r,e){return m.info(`[connectors] Unzipping into ${e}`),new Promise((t,n)=>{const o=Pe.Parse();o.on("entry",i=>{const s=i.path;if(i.type==="Directory"){const l=k.join(e,s);A.mkdirSync(l,{recursive:!0}),i.autodrain()}else{const l=k.join(e,s),d=k.dirname(l);A.mkdirSync(d,{recursive:!0});const p=A.createWriteStream(l);i.pipe(p),p.on("finish",()=>{})}}),o.on("end",()=>{m.success(`[connectors] Successfully extracted to ${e}`),t()}),o.on("error",i=>{n(i)}),o.write(r),o.end()})}c(mo,"extractZipArchive");async function go({connector:r,version:e,connectorId:t}){const n=k.join(ne(),te(r),cn(e)),o=k.join(n,"src"),i=k.join(n,"src.zip"),s=A.existsSync(i);if(A.existsSync(o)&&(m.info(`[connectors] Archiving source code for ${r.name} version ${e}`),await fo(o,i)),!A.existsSync(i)){m.warning(`[connectors] No source code found for ${r.name} version ${e}`);return}try{const a=new Jt;if(a.append("file",A.createReadStream(i),"file.zip"),m.info(`[connectors] Pushing connector version ${e} for ${r.name}`),e==ee)m.info(`[connectors] Uploading connector ${t}`),await $.withClient(l=>l.post(`connectors/${t}/upload`,a,{headers:{...a.getHeaders()}}));else{if(a.append("version",e),a.append("changelog","Imported Version"),(await $.withClient(d=>d.get(`/connectors/${t}/versions`))).find(d=>d.version==e)){m.info(`[connectors] Version ${e} already published`);return}m.info(`[connectors] Publishing version ${e} of connector ${t}`),await $.withClient(d=>d.post(`connectors/${t}/publish-version`,a,{headers:{...a.getHeaders()}}))}m.success(`Successfully pushed connector version ${e} for ${r.name}`)}catch(a){m.error(`Error pushing connector version ${e} for ${r.name}: ${a}`),console.error(`[connectors] Error pushing connector version ${e} for ${r.name}: ${a}`)}finally{!s&&A.existsSync(i)&&(m.info(`[connectors] Cleaning up temporary zip file for ${r.name} version ${e}`),A.unlinkSync(i))}}c(go,"pushConnectorVersion");async function Ct({connectorId:r}){if(r){if(yt[r])return yt[r];try{const e=await $.withClient(t=>t.get(`connectors/${r}`),!1);return yt[r]=e,e}catch(e){return m.error(`[connectors] Failed to get connector ${r}: ${e}`),console.error(`[connectors] Failed to get connector ${r}: ${e}`),null}}}c(Ct,"getConnector");async function yo({basePath:r,connector:e}){const t=te(e),n=k.join(r,me,t);A.mkdirSync(n,{recursive:!0});const o=k.join(n,`${te(e)}.yml`);A.writeFileSync(o,H.dump(e)),m.info(`[connectors] Pulled connector ${e.name}`)}c(yo,"pullConnector$1");async function wo({connector:r,connectorVersion:e,basePath:t}){const n=te(r),o=cn(e),i=k.join(t,"connectors",n,o),s=await $.withClient(l=>l.get(`connectors/${r.id}/download`,{version:e},{responseType:"arraybuffer",headers:{Accept:"application/zip"},timeout:1e6}));A.mkdirSync(i,{recursive:!0});const a=k.join(i,"src.zip");if(A.writeFileSync(a,s),!e){const l=k.join(i,"src");A.mkdirSync(l,{recursive:!0}),await mo(s,l)}m.info(`[connectors] Pulled connector version: ${r.name} (${o})`)}c(wo,"pullConnectorVersion");function te(r){return r.key}c(te,"getConnectorDirName");function cn(r){return r??ee}c(cn,"getConnectorVersionDirName");function Co(r){const e=Vt(),t=te(r);return k.join(e,me,t)}c(Co,"getConnectorDirPath");function So(r){return r.match(`${me}/[^/]+/${ee}/src/.*`)!==null}c(So,"isConnectorSourceFile");async function bo(r){const e=r.match(`${me}/([^/]+)/${ee}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await wt(t);if(!o){m.warning(`[connectors] Connector ${t} not found. Ignoring file change`);return}const i=o.id,s=A.readFileSync(r,"utf-8");await $.withClient(a=>a.put(`connectors/${i}/files/${n}`,s,{headers:{"Content-Type":"text/plain"}})),m.info(`[connectors] Pushed file ${n} for connector ${o.name}`)}c(bo,"putConnectorFile");async function vo(r){const e=r.match(`${me}/([^/]+)/${ee}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await wt(t);if(!o){m.warning(`[connectors] Connector ${t} not found. Ignoring file change`);return}const i=o.id;await $.withClient(s=>s.delete(`connectors/${i}/files/${n}`)),m.info(`[connectors] Deleted file ${n} for connector ${o.name}`)}c(vo,"deleteConnectorFile");async function Eo(r,e){try{const t=await $.withClient(s=>s.get(`connectors/${r}`));if(!t){m.warning(`[connectors] Connector ${r} not found`);return}const n=await $.withClient(s=>s.get(`connectors/${r}/files/${e}`)),o=te(t),i=k.join(ne(),o,ee,"src",e);A.mkdirSync(k.dirname(i),{recursive:!0}),n!=null?(A.writeFileSync(i,n),m.info(`[connectors] Pulled file ${e} for connector ${t.name}`)):A.existsSync(i)&&(A.unlinkSync(i),m.info(`[connectors] Deleted file ${e} for connector ${t.name}`))}catch(t){m.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(Eo,"pullConnectorFile");async function To(r,e){const t=await $.withClient(i=>i.get(`connectors/${r}`),!1);if(!t){m.warning(`[connectors] Connector ${r} not found`);return}const n=te(t),o=k.join(ne(),n,ee,"src",e);A.existsSync(o)&&(A.unlinkSync(o),m.info(`[connectors] Deleted file ${e} for connector ${n}`))}c(To,"deleteLocalConnectorFile");async function xo(r,e,t){if(t&&e!==t)try{const n=await $.withClient(l=>l.get(`connectors/${r}`),!1);if(!n){m.warning(`[connectors] Connector ${r} not found`);return}const o=te(n),i=k.join(ne(),o,ee,"src"),s=k.join(i,e),a=k.join(i,t);A.existsSync(s)&&(A.mkdirSync(k.dirname(a),{recursive:!0}),A.renameSync(s,a),m.info(`[connectors] Renamed directory from ${e} to ${t} for connector ${o}`))}catch(n){m.error(`[connectors] Failed to rename directory ${e} to ${t} for connector ${r}: ${n}`)}}c(xo,"renameLocalConnectorDirectory");async function Io(r,e){try{const t=await $.withClient(i=>i.get(`connectors/${r}`),!1);if(!t){m.warning(`[connectors] Connector ${r} not found`);return}const n=te(t),o=k.join(ne(),n,ee,"src",e);if(A.existsSync(o)){const i=k.resolve(ne());if(!k.resolve(o).startsWith(i))return;A.rmSync(o,{recursive:!0,force:!0}),m.info(`[connectors] Deleted directory ${e} for connector ${n}`)}}catch(t){m.error(`[connectors] Failed to delete directory ${e} for connector ${r}: ${t}`)}}c(Io,"deleteLocalConnectorDirectory");const j={LogAdded:"logAdded",StateChanged:"stateChanged",StatsChanged:"statsChanged",ConflictsChanged:"conflictsChanged",McpStatusChanged:"mcpStatusChanged",McpServersChanged:"mcpServersChanged",ConfigChanged:"configChanged"};class ko extends mt{static{c(this,"WorkspaceNotifications")}constructor(e){super(),this.config=e,m.setNotificationHandler(this)}clientId;heartbeatInterval;isCleaningUp=!1;async connectToRemote(){await this.registerWithRemoteServer(),await this.startHeartbeatLoop()}async setState(e){this.emit(j.StateChanged,{state:e}),await this.emitRemote({status:e})}setConflicts(e){this.emit(j.ConflictsChanged,{conflicts:e})}setConfig(e){this.emit(j.ConfigChanged,{config:e})}setStats(e){this.emit(j.StatsChanged,{stats:e})}addLog(e){this.emit(j.LogAdded,{log:e})}setMcpStatus(e){this.emit(j.McpStatusChanged,{status:e})}async setMcpServers(e){this.emit(j.McpServersChanged,{servers:e}),await this.emitRemote({mcpServers:e.map(t=>({name:t.agentName,totalRequests:t.totalRequests}))})}async cleanup(){!this.clientId||this.isCleaningUp||(this.isCleaningUp=!0,this.heartbeatInterval&&(clearInterval(this.heartbeatInterval),this.heartbeatInterval=void 0),await this.withErrorHandling(async()=>{await $.withClient(e=>e.delete(`/local-clients/${this.clientId}`))}),this.clientId=void 0)}async registerWithRemoteServer(){if(this.clientId)return;const e=await this.withErrorHandling(async()=>await $.withClient(t=>t.post("/local-clients",{hostname:et.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 re=new ko({heartbeatIntervalMs:15e3}),ln=[x.AppDataSchema,x.AppEventType,x.DataLinkTable,x.DataSource,x.FieldMapping,x.Action,x.Flow,x.Package];class xe{static{c(this,"ElementSyncService")}localWatcher=void 0;remoteWatcher=void 0;notifier;changes=[];localCache;remoteCache;localRepo;remoteRepo;pulledConnectors=new Set;pulledConnectorVersions={};constructor(){this.notifier=re,this.localCache=new on,this.remoteCache=new on,this.localRepo=new ao(this.localCache),this.remoteRepo=new co(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 m.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 m.error(`Failed to delete element ${e.id}: ${i}`),i}}async pullConnectors(e=!1){const t=this.remoteCache.getElementsByType(x.Integration).map(n=>n.data);for(const n of t){const o=n.connectorId,i=n.connectorVersion;o&&await an({connectorId:o,connectorVersion:i,allConnectors:e,pulledConnectors:this.pulledConnectors,pulledConnectorVersions:this.pulledConnectorVersions})}}async pushConnectors(){const{connectorsMapping:e}=await sn();this.remoteRepo.setConnectorsMapping(e)}getHandler(e){return e===B.INCOMING?this.localRepo:(this.remoteRepo.setSourceCache(this.localCache),this.remoteRepo)}getCache(e){return e===B.INCOMING?this.localCache:this.remoteCache}async startWatching(){this.localWatcher=new uo({cwd:process.cwd(),lockTimeoutMs:1e3}),this.localWatcher.on(W.Updated,e=>this.handleLocalEvent(e,W.Updated)),this.localWatcher.on(W.Deleted,e=>this.handleLocalEvent(e,W.Deleted)),await this.localWatcher.start(),m.success("[local] Tracking changes.."),this.remoteWatcher=new po,this.remoteWatcher.on(gt.Updated,({elementId:e,elementType:t})=>this.handleRemoteElementEvent(e,t)),this.remoteWatcher.on(gt.ConnectorFileUpdated,({connectorId:e,filePath:t,eventType:n,newPath:o})=>this.handleRemoteConnectorFileEvent(e,t,n,o)),await this.remoteWatcher.start(),m.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?(m.info(`[${this.getDirectionLabel(B.INCOMING)}] Deleted: ${s.id}`),this.localWatcher?.executeWithPathLock(s.absolutePath,()=>this.deleteElement(s,B.INCOMING))):void 0}if(m.info(`[${this.getDirectionLabel(B.INCOMING)}] Updated: ${n.id}`),await this.localWatcher?.executeWithPathLock(n.absolutePath,async()=>this.updateElement(n,B.INCOMING)),t===x.Integration){const s=n.data.connectorId,a=n.data.connectorVersion,l=await Ct({connectorId:s});if(!l?.key)return;const d=Co(l);await this.localWatcher?.executeWithPathLock(d,async()=>an({connectorId:s,connectorVersion:a,allConnectors:!1,pulledConnectors:this.pulledConnectors,pulledConnectorVersions:this.pulledConnectorVersions}))}}catch(n){m.error(`[sync] Error handling remote event: ${n}`)}}async handleRemoteConnectorFileEvent(e,t,n,o){try{switch(n){case Ke.ConnectorFileDeleted:await To(e,t);break;case Ke.ConnectorDirectoryRenamed:await xo(e,t,o);break;case Ke.ConnectorDirectoryDeleted:await Io(e,t);break;default:await Eo(e,t);break}}catch(i){m.error(`[sync] Error handling remote connector file event: ${i}`)}}async handleLocalEvent(e,t){try{if(So(e.filePath))switch(t){case W.Updated:await bo(e.filePath);break;case W.Deleted:await vo(e.filePath);break}else{let n=F.fromPathAndData(e.filePath,e.data);if(!n){const o=F.idFromPath(e.filePath);if(!o||(n=this.remoteCache.get(o),!n))return}switch(m.info(`[${this.getDirectionLabel(B.OUTGOING)}] ${pr(t)}: ${n.id}`),t){case W.Updated:await this.updateElement(n,B.OUTGOING);break;case W.Deleted:await this.deleteElement(n,B.OUTGOING);break}}}catch(n){m.error(`[sync] Error handling local event: ${n}`)}}detectIncomingChanges(){this.clearChanges();const e=xe.getChanges(B.INCOMING,this.remoteCache,this.localCache);return this.updateChanges(e),e}detectOutgoingChanges(){this.clearChanges();const e=xe.getChanges(B.OUTGOING,this.localCache,this.remoteCache);return this.updateChanges(e),e}async resolveChanges(){if(!this.needsSync())return;m.info("[resolver] Resolving changes.."),m.info("[resolver] Resolving integration elements");const e=this.changes.filter(o=>o.element.type===x.Integration);await Promise.all(e.map(async o=>this.resolveChange(o))),e.length>0&&(await this.fetchElements(),this.changes=this.changes.length>0&&this.changes[0]?.direction===B.INCOMING?this.detectIncomingChanges():this.detectOutgoingChanges(),this.changes=this.changes.filter(o=>o.element.type!==x.Integration)),m.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);m.info(`[resolver] Resolving ${o} elements`),await Promise.all(i.map(async s=>this.resolveChange(s)))}m.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);m.info(`[resolver] Resolving ${o} elements`),await Promise.all(i.map(async s=>this.resolveChange(s)))}m.success("[resolver] Resolved changes")}async resolveChange(e){switch(e.type){case Q.DELETE:return this.deleteElement(e.element,e.direction);case Q.CREATE:return this.updateElement(e.element,e.direction);case Q.UPDATE:return this.updateElement(e.element,e.direction)}}static getChanges(e,t,n){const o=t.getAllIds(),i=n.getAllIds(),s=new Set([...o,...i]),a=[];for(const l of s){const d=t.get(l),p=n.get(l),f=xe.detectChangeForElement(d,p,e);f&&a.push(f)}return a}updateChanges(e){if(this.changes=e,this.needsForcedSync()){const t=e.filter(n=>n.isConflict);m.warning("[resolver] Conflicts detected"),this.notifier.setConflicts(t)}}clearChanges(){this.changes=[]}getDirectionLabel(e){switch(e){case B.INCOMING:return"local\u2190remote";case B.OUTGOING:return"local\u2192remote"}}static detectChangeForElement(e,t,n){return e&&!t?{type:Q.CREATE,element:e,direction:n,isConflict:!1}:!e&&t?{type:Q.DELETE,element:t,direction:n,isConflict:!0}:e&&t&&!e.isEqual(t)?{type:Q.UPDATE,element:e,direction:n,isConflict:!1}:null}}const oe=E.join(br.tmpdir(),"membrane-mcp-status"),un=3e4;class $o{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=Fe(void 0,e),n=dn(e);t&&re.setMcpStatus(t),await re.setMcpServers(n)}catch{m.error("Failed to check MCP status")}}}function Fe(r,e){try{const t=e||process.cwd();if(!r){const o=dn(t);return o.length===0?null:o[0]}const n=vt(r,t);if(v.existsSync(n)){const o=v.statSync(n),i=new Date;if(i.getTime()-o.mtime.getTime()>un)return be(r,t),null;const a=v.readFileSync(n,"utf8"),l=JSON.parse(a);if(l.isRunning){const d=new Date(l.lastActivity).getTime();if(i.getTime()-d>un)return be(r,t),null}return l}}catch{r&&e&&be(r,e)}return null}c(Fe,"getMcpStatus");function dn(r){try{const e=r||process.cwd(),t=bt(e);if(!v.existsSync(oe))return[];const n=v.readdirSync(oe),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=Fe(a,e);l&&o.push(l)}}return o.sort((i,s)=>new Date(s.startTime).getTime()-new Date(i.startTime).getTime())}catch{return[]}}c(dn,"getAllMcpStatusFiles");function St(r){try{const t={...Fe(r.processId,r.cwd)||{isRunning:!1,startTime:new Date().toISOString(),lastActivity:new Date().toISOString(),toolsCount:0,totalRequests:0,processId:r.processId,cwd:r.cwd,agentName:process.env.AGENT_NAME||"Unnamed Agent"},...r};v.existsSync(oe)||v.mkdirSync(oe,{recursive:!0});const n=vt(r.processId,r.cwd);v.writeFileSync(n,JSON.stringify(t,null,2))}catch{}}c(St,"updateMcpStatus");function be(r,e){try{const t=e||process.cwd();if(r){const n=vt(r,t);v.existsSync(n)&&v.unlinkSync(n)}else{const n=bt(t);if(v.existsSync(oe)){const o=v.readdirSync(oe);for(const i of o)i.match(new RegExp(`^mcp-${n}-\\d+\\.json$`))&&v.unlinkSync(E.join(oe,i))}}}catch{}}c(be,"clearMcpStatus");function Po(r,e){const t=Fe(r,e);t&&St({processId:r,cwd:e,totalRequests:t.totalRequests+1,lastRequestTime:new Date().toISOString(),lastActivity:new Date().toISOString()})}c(Po,"trackToolExecution");function bt(r){return gr("md5").update(r).digest("hex").slice(0,8)}c(bt,"getCwdHash");function vt(r,e){const t=bt(e);return E.join(oe,`mcp-${t}-${r}.json`)}c(vt,"getStatusFilePath");const Le={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 Ao{static{c(this,"MembraneCLIService")}constructor(e,t,n=()=>process.exit(0)){this.mode=e,this.cwd=t,this.onShutdown=n,this.notifier=re,this.mcpStatusService=new $o,this.syncService=new xe,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(m.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,m.error(`Failed to pull workspace: ${n}`),await this.notifier.setState(P.ERROR),m.saveLogsToFile("error")}finally{if(e.saveLogs&&m.saveLogsToFile(),t)process.exit(1);else return e?.onComplete?.()}}async pushWorkspace(e={}){let t=!1;try{if(m.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,m.error(`Failed to push workspace: ${n}`),await this.notifier.setState(P.ERROR),m.saveLogsToFile("error")}finally{if(e.saveLogs&&m.saveLogsToFile(),t)process.exit(1);else return e?.onComplete?.()}}async syncWorkspaces(e={}){try{e.verbose!==void 0&&m.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){m.error(`Failed to sync local and remote workspaces: ${t}`),await this.notifier.setState(P.ERROR),m.saveLogsToFile("error")}}async init({force:e=!1}={}){if(!(this.initialized&&!e)){await this.notifier.setState(P.NOT_INITIALIZED);try{await this.loadConfig(),de.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){m.error(`Failed to initialize services: ${t}`),await this.notifier.setState(P.ERROR),m.saveLogsToFile("error"),this.onShutdown()}}}async loadConfig(){this.currentConfig=de.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=de.updateConfig(t);this.currentConfig=o,await this.init({force:!0})}async shutdown(){!this.initialized||this.isShuttingDown||(this.isShuttingDown=!0,this.mode===Le.Agent&&(await this.notifier.cleanup(),await this.mcpStatusService.stop()),this.initialized=!1,this.onShutdown())}async initServices(){this.mode===Le.Agent&&(await this.notifier.connectToRemote(),await this.mcpStatusService.start()),this.syncService.clear()}async stopServices(){this.mode===Le.Agent&&(await this.notifier.cleanup(),await this.mcpStatusService.stop())}setupProcessCleanup(){["SIGINT","SIGTERM","uncaughtException","unhandledRejection"].forEach(t=>process.on(t,()=>this.shutdown())),process.on("beforeExit",t=>{t===0&&this.shutdown()})}}const hn=Ve(null);function Ro({children:r,membraneCLIService:e}){const{data:t}=Bt("/account"),[n,o]=N(P.NOT_INITIALIZED),[i,s]=N([]),[a,l]=N({}),[d,p]=N([]),[f,h]=N(null),T=t?.workspaces?.find(S=>S.workspaceKey===f?.workspaceKey)||null;return fe(()=>{const S=c(({state:M})=>o(M),"handleStateChanged"),D=c(({stats:M})=>l(M),"handleStatsChanged"),O=c(({log:M})=>p(Y=>[...Y,M]),"handleLogAdded"),_=c(({conflicts:M})=>s(M),"handleConflictsUpdated"),L=c(({config:M})=>h(M),"handleConfigChanged");return e.notifier.on(j.StateChanged,S),e.notifier.on(j.StatsChanged,D),e.notifier.on(j.LogAdded,O),e.notifier.on(j.ConflictsChanged,_),e.notifier.on(j.ConfigChanged,L),e.init(),()=>{e.notifier.off(j.StateChanged,S),e.notifier.off(j.StatsChanged,D),e.notifier.off(j.LogAdded,O),e.notifier.off(j.ConflictsChanged,_),e.notifier.off(j.ConfigChanged,L)}},[]),u(hn.Provider,{value:{state:n,stats:a,logs:d,currentWorkspace:T,conflicts:i,config:f,updateConfig:c(S=>e.updateConfig(S),"updateConfig"),resolveConflicts:c(S=>e.syncWorkspaces(S),"resolveConflicts"),pull:c(S=>e.pullWorkspace(S),"pull"),push:c(S=>e.pushWorkspace(S),"push"),exit:c(()=>e.shutdown(),"exit"),fetchElements:c(()=>e.fetchElements(),"fetchElements"),getSyncedElementsByType:c(S=>e.getSyncedElementsByType(S),"getSyncedElementsByType")},children:r})}c(Ro,"MembraneCLIServiceProvider");function G(){const r=Ye(hn);if(!r)throw new Error("useMembraneCLIService must be used within MembraneCLIServiceProvider");return r}c(G,"useMembraneCLIService");const Et=Ve(null),pn=c(()=>{const r=Ye(Et);if(!r)throw new Error("useTree must be used within TreeView");return r},"useTree"),Do=c(r=>ce.Children.count(r)>0,"hasChildren");function Oo(r){const e=pn(),{label:t,value:n,isInitiallyExpanded:o}=r,i=rr(),s=Ze(e.registerChildItem(t)).current,a=e.isActiveByRef(s),[l,d]=N(o??!1),p={props:r,ref:s,id:i,active:a,expanded:l,setExpanded:d,label:t,value:n,isInitiallyExpanded:o,isParent:!1},{children:f}=r,h=typeof f=="function"?f(p):f;return{...p,props:{...r,children:h},isParent:Do(h)}}c(Oo,"useTreeItem");function ge(r){const e=pn(),t=Oo(r),{expanded:n,isParent:o,props:{children:i},setExpanded:s}=t,{renderValue:a=Mo}=r,l=t.ref;ke(()=>{function h(C){return r.onInput?.(C)?!0:C.active&&C.key.rightArrow&&!n?(s(!0),!0):C.active&&C.key.leftArrow&&n?(s(!1),!0):!1}c(h,"onInput"),l.onInput=h},[l,r.onInput,n,s]),l.firstChild??={parent:l,index:0};let d=l.firstChild;function p(h){const C=d;return C.nextSibling||(C.nextSibling={parent:l,prevSibling:C,index:C.index+1}),d=C.nextSibling,C.label=h,C}c(p,"registerChildItem");function f(){l.lastRenderedChild=d.prevSibling}return c(f,"commitChildren"),ke(()=>{f()}),b($e,{children:[b(g,{marginLeft:e.depth*2,children:[u(g,{width:2,children:o&&u(y,{children:n?"\u25BC":"\u25B6"})}),No(t),a(t)]}),n&&u(Et.Provider,{value:{...e,depth:e.depth+1,registerChildItem:p},children:i})]})}c(ge,"TreeItem");function No({active:r,label:e}){return u(g,{width:32,children:u(y,{inverse:r,children:e})})}c(No,"defaultRenderLabel");function Mo(r){return u(y,{})}c(Mo,"defaultRenderValue");const he=c(({label:r,onPress:e,hotkey:t})=>u(ge,{label:r,onInput:c(({input:n,key:o,active:i})=>i&&o.return||t&&t in o&&o[t]||n===t?(e(),!0):!1,"onInput"),renderValue:c(()=>u(g,{children:u(y,{children:`${t?` (${t})`:""}`})}),"renderValue")}),"ActionTreeItem"),fn=c(({label:r,value:e,onChange:t,disabled:n=!1,mask:o,...i})=>{const[s,a]=N(e),[l,d]=N(!1);return ke(()=>{l||a(e)},[l,e]),u(ge,{label:r,value:e,onInput:c(({key:p,active:f})=>n?!1:l?(p.escape&&d(!1),p.return&&(t(s),d(!1)),!0):f&&p.return?(d(!0),a(e),!0):!1,"onInput"),renderValue:c(()=>{const p=s,f=o?o.repeat(p.length):p;return u(g,{children:n||!l?u(y,{dimColor:!0,children:f}):b($e,{children:[u(g,{width:f.length+1,children:u(zt,{...i,focus:l,value:p,onChange:a})}),u(y,{dimColor:!0,children:" \u241B cancel"})]})})},"renderValue")})},"TreeTextField"),Fo=c(r=>u(fn,{...r,mask:"*"}),"SecretField"),J=c(({children:r,showHelp:e=!1})=>{const t=Ze({parent:void 0,label:"<<ROOT>>",index:0}),[n,o]=N(t.current),i={depth:0,isActiveByRef:c(a=>n===a,"isActiveByRef"),registerChildItem:c(()=>t.current,"registerChildItem"),activeItemRef:n};ke(()=>{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"),le((a,l)=>{if(n.onInput?.({input:a,key:l,active:!0}))return;let d,p;for(const f of s(t.current))if(f.label!=null){if(d===n&&(p=f),f&&f.onInput?.({input:a,key:l,active:f===n}))return;d=f}l.upArrow?o(f=>f.prevSibling?.lastRenderedChild??f.prevSibling??f.parent??t.current):l.downArrow?o(f=>p??f):l.pageUp?o(()=>t.current.firstChild??t.current):l.pageDown?o(()=>t.current.lastRenderedChild??t.current):l.tab?console.debug({label:n.label,nextSibling:n.nextSibling?.label,prevSibling:n.prevSibling?.label,parent:n.parent?.label,firstChild:n.firstChild?.label,lastRenderedChild:n.lastRenderedChild?.label}):l.leftArrow?o(f=>f.parent??t.current):l.rightArrow&&o(f=>f.lastRenderedChild?f.firstChild:f)}),u(Et.Provider,{value:i,children:b(g,{flexDirection:"column",children:[u(ge,{isInitiallyExpanded:!0,label:"rootItem",children:r}),e&&u(g,{marginTop:1,flexDirection:"column",children:u(y,{dimColor:!0,children:"\u2191/\u2193 move \u2022 \u2190 collapse \u2022 \u2192 expand \u2022 Enter/Space select/edit \u2022 Esc exit"})})]})})},"TreeView");J.Item=ge,J.TextField=fn;function pe({label:r,elementType:e,isActionExcluded:t,toggleAction:n,generateCode:o}){const[i,s]=N([]),{fetchElements:a,getSyncedElementsByType:l}=G();return fe(()=>{c(async()=>{try{await a();const p=l(e);s(p.map(f=>f.data))}catch(p){console.error(String(p))}},"loadElements")()},[e,a,l,s]),u(ge,{label:r,children:i.map(d=>u(ge,{label:d.name,children:e===x.Action&&b($e,{children:[t&&n&&u(he,{label:`Toggle ${t(d)?"":"(excluded)"}`,onPress:c(()=>{n(d)},"onPress")}),o&&u(he,{label:"Generate code",onPress:c(()=>{o?.(d)},"onPress")})]})},d.id))})}c(pe,"WorkspaceElementsTreeItem");function Lo({onComplete:r}){const{config:e,updateConfig:t,fetchElements:n,getSyncedElementsByType:o}=G(),[i,s]=N(""),a=e,l=c(h=>{s(h),setTimeout(()=>s(""),2e3)},"setFlash"),d=c(async(h,C)=>{try{await t({[h]:C}),l("\u2705 Configuration updated!")}catch{l("\u274C Error updating configuration")}},"updateField"),p=c(async()=>{try{if(e){const h=de.saveToFile(e);l(h?"\u2705 Configuration saved successfully!":"\u274C Failed to save configuration"),await n();const C=o(x.Action);await lt({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:C.filter(T=>!a?.excludedActionKeys?.includes(T.key)).map(T=>T.data)}}),l("\u2705 Code generated successfully!")}}catch{l("\u274C Error saving configuration")}},"handleSaveConfig"),f=c(async()=>{try{const h=de.loadConfig();h?(await t(h),l("\u2705 Configuration reloaded successfully!")):l("\u274C No configuration found to reload")}catch{l("\u274C Error reloading configuration")}},"handleReloadConfig");return b(g,{flexDirection:"column",gap:1,children:[u(y,{bold:!0,color:"cyan",children:"\u2699\uFE0F Membrane Configuration Manager"}),u(g,{paddingX:2,children:b(J,{showHelp:!0,children:[b(J.Item,{label:"Configuration",isInitiallyExpanded:!0,children:[b(J.Item,{label:"Project",children:[u(J.TextField,{label:"Workspace Key",value:a?.workspaceKey??"",onChange:c(h=>d("workspaceKey",h),"onChange"),disabled:!0}),u(Fo,{label:"Workspace Secret",value:a?.workspaceSecret??"",onChange:c(h=>d("workspaceSecret",h),"onChange"),disabled:!0}),u(J.TextField,{label:"API URI",value:a?.apiUri??"",onChange:c(h=>d("apiUri",h),"onChange")}),u(J.TextField,{label:"Test Customer ID",value:a?.testCustomerId??"",onChange:c(h=>d("testCustomerId",h),"onChange")})]}),b(J.Item,{label:"Code Generation",isInitiallyExpanded:!0,children:[b(J.Item,{label:"Project Type",isInitiallyExpanded:!0,value:a?.projectType,renderValue:c(({value:h})=>u(y,{children:h==="typescript"?"TypeScript":h==="openapi"?"OpenAPI":"(Not set)"}),"renderValue"),children:[u(he,{label:"Update to TypeScript",onPress:c(()=>d("projectType","typescript"),"onPress")}),u(he,{label:"Update to OpenAPI",onPress:c(()=>d("projectType","openapi"),"onPress")})]}),u(J.TextField,{label:"Project dir",value:a?.outputDir??"",onChange:c(h=>d("outputDir",h),"onChange")})]}),b(J.Item,{label:"Workspace Elements",children:[u(pe,{label:"Actions",elementType:x.Action,isActionExcluded:c(h=>a?.excludedActionKeys?.includes(h.key)??!1,"isActionExcluded"),toggleAction:c(h=>d("excludedActionKeys",[...a?.excludedActionKeys??[],h.key]),"toggleAction"),generateCode:c(h=>{(async()=>{try{await lt({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:[h]}}),l("\u2705 Code generated successfully!")}catch{l("\u274C Error generating code")}})()},"generateCode")}),u(pe,{label:"Flows",elementType:x.Flow}),u(pe,{label:"Data Sources",elementType:x.DataSource}),u(pe,{label:"Field Mappings",elementType:x.FieldMapping}),u(pe,{label:"Packages",elementType:x.Package}),u(pe,{label:"App Data Schemas",elementType:x.AppDataSchema}),u(pe,{label:"App Event Types",elementType:x.AppEventType})]})]}),u(he,{label:"Save Configuration",onPress:p,hotkey:"s"}),u(he,{label:"Reload Configuration",onPress:f,hotkey:"r"}),u(he,{label:"Exit",onPress:c(()=>r?.(),"onPress"),hotkey:"escape"})]})}),i&&u(g,{paddingX:2,children:u(y,{color:i.includes("\u2705")?"green":"red",children:i})})]})}c(Lo,"ConfigManager");const mn=Ve(process.cwd());function jo({cwd:r,children:e}){return u(mn.Provider,{value:r,children:e})}c(jo,"CwdProvider");function Uo(){return Ye(mn)}c(Uo,"useCwd");function Tt({cwd:r,children:e,membraneCLIService:t}){const n=r||process.cwd();return u(jo,{cwd:n,children:u(vr,{value:{fetcher:Qr()},children:u(Ro,{membraneCLIService:t,children:e})})})}c(Tt,"Layout");function _o(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(`
|
|
10
|
+
`)).action(()=>{Xe(ce.createElement(Tt,{membraneCLIService:e,children:ce.createElement(Lo,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(_o,"setupConfigCommand");function Ko({currentPat:r,onSubmit:e}){const[t,n]=N(""),[o,i]=N(!1),[s,a]=N(null),l=dt(`/w/0/${Hn}`);return b(g,{flexDirection:"column",borderStyle:"round",borderTop:!0,width:70,paddingX:1,children:[u(g,{marginTop:-1,marginBottom:1,children:u(y,{bold:!0,children:"\u{1F511} Enter your Personal Access Token"})}),u(y,{children:"Please provide your Personal Access Token. You can find it here:"}),u(g,{marginTop:1,marginBottom:1,children:u(y,{color:"yellow",children:l})}),r&&u(y,{dimColor:!0,children:"Press Enter to keep your current token or type a new one."}),u(zt,{mask:"*",placeholder:`${r?"******":"Enter your token here..."}`,value:t,onChange:n,onSubmit:c(async p=>{a(null),i(!0);try{await e(p),n("")}catch{a("Invalid token. Please try again.")}finally{i(!1)}},"handleSubmit")}),o&&u(g,{marginTop:1,children:b(y,{children:[u(Ae,{type:"dots"})," Validating token..."]})}),s&&u(y,{color:"red",children:s})]})}c(Ko,"PersonalAccessTokenInput");function gn({onExit:r,showEscOption:e=!0}){const[t,n]=N(""),{data:o,error:i,isLoading:s}=Bt("/account"),{updateConfig:a}=G(),l=o?.workspaces,d=s;if(le((S,D)=>{D.escape&&r?.()}),d)return b(g,{children:[u(Ae,{}),u(y,{children:" Fetching workspaces..."})]});if(i)return b(g,{flexDirection:"column",children:[b(y,{color:"red",children:["Error: ",i.message]}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"Press ESC to go back"})})]});const p=l?.filter(S=>S.name.toLowerCase().includes(t.toLowerCase()))??[],f=p.map(S=>({label:S.name,value:S.id})),h=f.length,C=l?.length??0;async function T(S){const D=p.find(L=>L.id===S);if(!D)return;const{key:O,secret:_}=D;!O||!_||(await a({workspaceKey:O,workspaceSecret:_}),r?.())}return c(T,"handleSelect"),b(g,{flexDirection:"column",borderStyle:"round",borderTop:!0,width:70,paddingX:1,children:[u(g,{marginTop:-1,children:u(y,{bold:!0,children:"\u{1F4C1} Select your workspace"})}),b(g,{marginTop:1,children:[u(y,{children:"Search: "}),u(Er,{placeholder:"Enter a search query...",onChange:n})]}),C>5&&b(y,{children:["Showing ",h," of ",C," workspaces."]}),u(g,{marginTop:1,children:u(Tr,{options:f,onChange:c(S=>{S&&T(S)},"onChange")})}),e&&u(g,{marginTop:1,children:u(y,{color:"grey",children:"Press ESC to go back"})})]})}c(gn,"SelectWorkspace");var ve=(r=>(r[r.Authenticate=0]="Authenticate",r[r.ConnectWorkspace=1]="ConnectWorkspace",r))(ve||{});const qo={0:"Authenticate in Membrane",1:"Connect a Membrane Workspace"},xt=[ve.Authenticate,ve.ConnectWorkspace];function yn({onComplete:r}){const{config:e}=G(),[t,n]=N(!1),[o,i]=N(0),s=!!(e?.workspaceKey&&e?.workspaceSecret),a=Yt(),l=xt[o],d=o+1,p=xt.length,f=xt.map((T,S)=>{let D="pending";return S<o?D="done":S===o&&(D="current"),{id:T,label:qo[T],status:D}});async function h(T){const S=a&&T===""?a:T,D=new pt;try{await D.request("/account",{headers:{Authorization:`Bearer ${S}`}}),zr(S),i(O=>O+1)}catch(O){console.error(O)}}c(h,"handlePatSubmit");function C(){n(!0),r&&r()}return c(C,"handleWorkspaceSelected"),le((T,S)=>{s&&S.escape&&r&&r()}),t?u(g,{children:u(y,{children:"\u2705 Setup complete. You are ready to go!"})}):b(g,{flexDirection:"column",alignSelf:"flex-start",gap:1,children:[b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:70,children:[u(g,{marginTop:-1,marginBottom:1,children:b(y,{bold:!0,children:["\u{1F6E0}\uFE0F Setup \u2014"," ",b(y,{color:"cyan",children:["Step ",d," of ",p]}),s&&u(y,{color:"grey",children:" [esc: go back]"})]})}),u(g,{flexDirection:"column",paddingLeft:2,children:f.map(T=>u(Bo,{status:T.status,label:T.label},T.id))})]}),l===ve.Authenticate&&u(Ko,{currentPat:a,onSubmit:h}),l===ve.ConnectWorkspace&&u(gn,{onExit:C,showEscOption:!1})]})}c(yn,"Setup");function Bo({status:r,label:e}){return b(g,{children:[b(g,{width:2,children:[r==="current"&&u(Ae,{type:"dots"}),r==="done"&&u(y,{children:"\u2705"})]}),u(y,{dimColor:r!=="current",children:e})]})}c(Bo,"StepDisplay");function Wo(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(`
|
|
11
|
+
`)).action(t=>{t.key&&t.secret?de.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)):Xe(ce.createElement(Tt,{membraneCLIService:e,children:ce.createElement(yn,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(Wo,"setupInitCommand");const Jo={info:"\u{1F4DD}",success:"\u2728",warning:"\u26A0\uFE0F",error:"\u274C",debug:"\u{1F50D}"},zo={info:w.white,success:w.green,warning:w.yellow,error:w.red,debug:w.gray};class I{static{c(this,"Logger")}static formatMessage(e,t,n={icon:!1}){const o=n.timestamp?`${w.gray(new Date().toISOString())} `:"",i=n.prefix?`${w.gray(n.prefix)} `:"",s=n.suffix?` ${w.gray(n.suffix)}`:"",a=Jo[t],l=zo[t];return`${o}${n.icon?a:""} ${i}${l(e)}${s}`}static info(e,t){let n=w.white;if(t?.color&&(n=w[t.color.toLowerCase()]||w.white),t?.timestamp){const o=new Date().toLocaleTimeString();console.debug(`${w.gray(`[${o}]`)} ${n(e)}`)}else console.debug(n(e))}static group(e,t){}static groupEnd(){}static newLine(){}static success(e,t){console.debug(this.formatMessage(e,"success",t))}static warning(e,t){console.debug(this.formatMessage(e,"warning",t))}static error(e,t){console.error(this.formatMessage(e,"error",t))}static debug(e,t){t?.prefix?console.debug(w.gray(`[${t.prefix}] ${e}`),t.error?`
|
|
12
|
+
${w.red(t.error)}`:""):console.debug(w.gray(e),t?.error?`
|
|
13
|
+
${w.red(t.error)}`:"")}static step(e,t){}static header(e){console.debug(),console.debug(w.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(){}}const Ho=".membrane",Go="config.json";function Vo(r){const e=k.resolve(Ho),t=k.join(e,Go);let n={};Qe(t)&&(n=JSON.parse(cr(t,"utf8")));const o={...n,...r};for(const[i,s]of Object.entries(o))s===void 0&&delete o[i];Qe(e)||Wt(e,{recursive:!0}),lr(t,JSON.stringify(o,null,2)+`
|
|
14
|
+
`,"utf8")}c(Vo,"patchProjectConfig");function Yo(r){r.command("login").description("Log in to Membrane via browser-based OAuth").option("--apiUri <uri>","API base URI",De).option("--no-browser","Print the authorization URL instead of opening a browser").addHelpText("after",["","Examples:"," membrane login # Log in via browser"," membrane login --no-browser # Print URL for manual login"," membrane login --apiUri https://api.example.com # Use custom API",""].join(`
|
|
15
|
+
`)).action(async e=>{try{const t=e.apiUri;I.header("Logging in to Membrane");const n=Zo(),o=Xo(n),{port:i,waitForCode:s,state:a,server:l}=await ti(),d=`http://127.0.0.1:${i}/callback`,p=`${t}/oauth/authorize?response_type=code&client_id=${qe}&redirect_uri=${encodeURIComponent(d)}&code_challenge=${o}&code_challenge_method=S256&scope=${Gn}&state=${a}`,h=(await fetch(p,{redirect:"manual"})).headers.get("location");if(!h)throw new Error("No redirect from authorization endpoint");const C=new URL(h).searchParams.get("authorizationId");if(!C)throw new Error("No authorizationId in authorization redirect");if(!!(process.stdin.isTTY&&e.browser))try{const{default:M}=await import("open");await M(h),I.info("Opening browser for authentication...")}catch{I.info("Could not open browser automatically.")}console.error(` If the browser doesn't open, visit:
|
|
16
|
+
${h}
|
|
17
|
+
`);const S=ot("Waiting for authorization...").start(),D=new AbortController,O=s.then(async M=>{S.text="Exchanging authorization code...";const Y=await fetch(`${t}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:"authorization_code",code:M,redirect_uri:d,client_id:qe,code_verifier:n})});if(!Y.ok)throw new Error(`Token exchange failed: ${Y.status} ${await Y.text()}`);return wn(await Y.json())}),_=oi(t,C,n,D.signal);_.catch(()=>{});const L=await Promise.race([O,_]);D.abort(),l.close(),S.stop(),Hr(),Zt(L.accessToken,L.refreshToken,L.expiresIn),Zr(t),L.defaultWorkspaceId&&Vo({defaultWorkspaceId:L.defaultWorkspaceId,defaultTenantId:L.defaultTenantId}),I.success("Authentication successful!"),process.exit(0)}catch(t){t instanceof Error?I.error(t.message):I.error("An unknown error occurred"),process.exit(1)}})}c(Yo,"setupLoginCommand");function Zo(){return Ht(32).toString("base64url")}c(Zo,"generateCodeVerifier");function Xo(r){return Ir("sha256").update(r).digest("base64url")}c(Xo,"generateCodeChallenge");function wn(r){if(!r.refresh_token)throw new Error("Server did not return a refresh token");return{accessToken:r.access_token,refreshToken:r.refresh_token,expiresIn:r.expires_in,defaultWorkspaceId:r.default_workspace_id,defaultTenantId:r.default_tenant_id}}c(wn,"parseTokenResponse");function Qo(r){return r.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}c(Qo,"escapeHtml");function ei(){return`<!DOCTYPE html><html><body style="font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0a0a0a;color:#fff">
|
|
18
|
+
<div style="text-align:center"><h1>Authorization successful</h1><p style="color:#888">You can close this tab and return to your terminal.</p></div>
|
|
19
|
+
</body></html>`}c(ei,"successPage");function It(r){return`<!DOCTYPE html><html><body style="font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#0a0a0a;color:#fff">
|
|
20
|
+
<div style="text-align:center"><h1>Authorization failed</h1><p style="color:#f87171">${Qo(r)}</p></div>
|
|
21
|
+
</body></html>`}c(It,"errorPage");function ti(){const r=Ht(16).toString("base64url");return new Promise(e=>{let t,n;const o=new Promise((s,a)=>{t=s,n=a}),i=kr((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 h=l.searchParams.get("error_description")??"Authorization was denied";a.writeHead(200,{"Content-Type":"text/html"}),a.end(It(h)),n(new Error(h));return}const p=l.searchParams.get("code");if(l.searchParams.get("state")!==r){a.writeHead(200,{"Content-Type":"text/html"}),a.end(It("State mismatch \u2014 possible CSRF attack. Please try again.")),n(new Error("State mismatch"));return}if(!p){a.writeHead(200,{"Content-Type":"text/html"}),a.end(It("No authorization code received.")),n(new Error("No authorization code received"));return}a.writeHead(200,{"Content-Type":"text/html"}),a.end(ei()),t(p)});i.listen(0,"127.0.0.1",()=>{const s=i.address(),a=typeof s=="object"&&s?s.port:0;e({port:a,waitForCode:o,state:r,server:i})})})}c(ti,"startCallbackServer");const ni=900*1e3,ri=5;async function oi(r,e,t,n){const o=Date.now()+ni;let i=ri;for(;Date.now()<o;){n.throwIfAborted(),await ii(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:qe,code_verifier:t})});if(s.ok)return wn(await s.json());const a=await s.json(),l=a.error??a.message??"";if(l!=="authorization_pending")if(l==="slow_down"){i+=5;continue}else throw l==="expired_token"?new Error("Authorization has expired. Please try again."):new Error(`Token exchange failed: ${s.status} ${l}`)}throw new Error("Authorization has expired. Please try again.")}c(oi,"pollForTokens");function ii(r,e){return new Promise((t,n)=>{const o=setTimeout(t,r);e.addEventListener("abort",()=>{clearTimeout(o),n(e.reason)},{once:!0})})}c(ii,"sleep");function si(r){r.command("logout").description("Log out of Membrane and revoke tokens").option("--apiUri <uri>","API base URI").action(async e=>{try{Xr()||(I.info("You are not logged in."),process.exit(0));const t=Ne(),n=e.apiUri||Me()||De;if(t)try{const o=await fetch(`${n}/oauth/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:t})});o.ok||I.debug(`Server revocation returned ${o.status}`)}catch{I.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.")}Yr(),I.success("Logged out successfully."),process.exit(0)}catch(t){t instanceof Error?I.error(t.message):I.error("An unknown error occurred"),process.exit(1)}})}c(si,"setupLogoutCommand");const ai=86400;async function ci(r,e,t,n){const o={iss:r,isAdmin:!0};return t&&(o.id=t),tt.sign(o,e,{expiresIn:ai})}c(ci,"generateMcpAccessToken");async function li(r,e){return(await we.get(`${r}/docs-json`,{headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}})).data}c(li,"fetchOpenApiSchema");function ie(r,e=!0,t,n=new Set){if(!r)return e?R.string():R.string().optional();if(Object.keys(r).length===0)return e?R.any():R.any().optional();if(r.$ref){const i=r.$ref.replace("#/components/schemas/","");if(n.has(i))return R.any();if(n.add(i),t?.schemas?.[i]){const s=t.schemas[i];return ie(s,e,t,n)}return R.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]=ie(a,l,t,n)}if(Object.keys(i).length>0){if(o=R.object(i),r.additionalProperties)if(typeof r.additionalProperties=="object"){const s=ie(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=ie(r.additionalProperties,!1,t,n);o=R.record(R.string(),s)}else o=R.record(R.string(),R.any())}else if(r.type==="array"){const i=r.items?ie(r.items,!0,t,n):R.any();o=R.array(i)}else if(r.anyOf)o=R.any();else{switch(r.type){case"integer":o=R.coerce.number().int();break;case"number":o=R.coerce.number();break;case"boolean":o=R.coerce.boolean();break;case"string":default:o=R.string();break}r.format==="uuid"?o=R.string().uuid():r.format==="email"?o=R.string().email():r.format==="date"?o=R.string().regex(/^\d{4}-\d{2}-\d{2}$/):r.format==="date-time"&&(o=R.string().datetime()),r.enum&&(o=R.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(ie,"convertOpenApiSchemaToZod");function Cn(r){const e=r.match(/\{([^}]+)\}/g);return e?e.map(t=>t.slice(1,-1)):[]}c(Cn,"extractPathParameters");function ui(r,e,t,n,o,i){const s=r.operationId||`${t}_${e.replace(/[^a-zA-Z0-9]/g,"_")}`,a=r.description||r.summary||`${t.toUpperCase()} ${e}`,l={},d={},p={};if(r.parameters){for(const h of r.parameters)if(h.in==="path")d[h.name]=ie(h.schema,!0,o).describe(h.description||`Path parameter: ${h.name}`);else if(h.in==="query"){const C=h.required===!0;p[h.name]=ie(h.schema,C,o).describe(h.description||`Query parameter: ${h.name}`)}}if(Object.keys(d).length>0&&(l.params=R.object(d).describe("Path parameters")),Object.keys(p).length>0&&(l.query=R.object(p).describe("Query parameters")),r.requestBody&&r.requestBody.content){const h=r.requestBody.required===!0;if(r.requestBody.content["application/json"]){const C=r.requestBody.content["application/json"].schema;C?l.body=ie(C,h,o).describe("Request body (JSON)"):l.body=R.any().describe("Request body (JSON)")}else r.requestBody.content["application/octet-stream"]||r.requestBody.content["text/plain"]?l.body=h?R.string().describe("Request body (binary/text)"):R.string().optional().describe("Request body (binary/text)"):l.body=R.any().describe("Request body")}const f=Object.keys(l).length>0?R.object(l):R.object({});return{name:s,description:a,parameters:f,async execute(h){try{const C=Cn(e);if(C.length>0){if(!h.params)throw new Error(`Missing required path parameters: ${C.join(", ")}`);const L=C.filter(M=>!(M in h.params));if(L.length>0)throw new Error(`Missing required path parameters: ${L.join(", ")}`)}let T=`${n}${e}`;if(h.params)for(const[L,M]of Object.entries(h.params)){const Y=`{${L}}`;T.includes(Y)&&(T=T.replace(Y,String(M)))}const S=Cn(T);if(S.length>0)throw new Error(`Unresolved path parameters: ${S.join(", ")}`);const D=new URLSearchParams;if(h.query)for(const[L,M]of Object.entries(h.query))M!=null&&D.append(L,String(M));D.toString()&&(T+=`?${D.toString()}`);const O={method:t.toUpperCase(),headers:{Authorization:`Bearer ${i}`}};h.body&&t.toLowerCase()!=="get"&&(r.requestBody?.content?.["application/json"]?(O.headers["Content-Type"]="application/json",O.data=h.body):r.requestBody?.content?.["application/octet-stream"]?(O.headers["Content-Type"]="application/octet-stream",O.data=h.body):r.requestBody?.content?.["text/plain"]?(O.headers["Content-Type"]="text/plain",O.data=h.body):(O.headers["Content-Type"]="application/json",O.data=h.body));const _=await we.request({url:T,...O});return{content:[{type:"text",text:_.data===""?"":JSON.stringify(_.data,null,2)}]}}catch(C){return we.isAxiosError(C)?{content:[{type:"text",text:`Error: ${C.response?.data?`HTTP ${C.response.status}: ${C.response.statusText} - ${JSON.stringify(C.response.data)}`:`HTTP ${C.response?.status||"unknown"}: ${C.message}`}`}],isError:!0}:C instanceof Error?{content:[{type:"text",text:`Error: API call failed: ${C.message}`}],isError:!0}:{content:[{type:"text",text:"Error: API call failed with unknown error"}],isError:!0}}}}}c(ui,"createApiTool");function di(r,e,t){const n=[];if(!r.paths)return n;const o=r.components||{};for(const[i,s]of Object.entries(r.paths))if(typeof s=="object"&&s!==null){for(const[a,l]of Object.entries(s))if(["get","post","put","delete","patch"].includes(a)&&l&&typeof l=="object"){const d=ui(l,i,a,e,o,t);n.push(d)}}return n}c(di,"convertOpenApiToTools");function hi(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(`
|
|
22
|
+
`)).action(async()=>{try{process.env.FASTMCP_SUPPRESS_WARNINGS="true";const e=Se(),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()||De;!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 ci(n,o,i),l=await li(s,a),d=di(l,s,a),p=new $r({name:"Membrane API",instructions:`This MCP server lets you interact with Membrane to configure, run, and troubleshoot integrations.
|
|
13
23
|
Use it for anything related to Membrane or integrations.
|
|
14
|
-
`,version:"1.0.0"});for(const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
`)).action(async()=>{try{R.header("Opening Workspace in Browser"),R.info("Loading configuration...");const e=Ce();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");R.info("Retrieving workspace ID...");const t=await Gt(process.cwd()),n=rt(`/w/${t}`);R.info(`Opening ${n}...`);const{default:o}=await import("open");await o(n),R.success("Browser opened successfully")}catch(e){e instanceof Error&&(R.error(e.message),process.exit(1)),R.error("An unknown error occurred"),process.exit(1)}})}c(Po,"setupOpenCommand");async function yt(r,e,t={}){const{jobId:n,accessKey:o}=await e(),i=`${n}:${o}`;f.debug(`[background-job] Started job ${n}`);const s=Date.now(),{pollIntervalMs:a=1e3,timeoutMs:l=3e5,maxRetries:d=3}=t;let h=0;for(;;){if(Date.now()-s>l)throw new Error(`Background job ${n} timed out after ${l}ms`);await new Promise(w=>setTimeout(w,a));let p;try{p=await r.get(`background-jobs/${i}`),h=0}catch(w){if(w instanceof jn&&h<d){h++,f.debug(`[background-job] Job ${n} not found, retrying (${h}/${d})`);continue}throw w}if(p.status==="completed"){if(f.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 w=p.error?.message||"Unknown error";throw f.error(`[background-job] Failed job ${n}: ${w}`),p.error?.stack&&f.error(`Stacktrace: ${p.error.stack}`),new Error(`Background job ${n} failed: ${w}`)}f.debug(`[background-job] Polling job ${n} (status: ${p.status})`)}}c(yt,"pollBackgroundJob");function un(r,e){ve(E.dirname(r)),v.writeFileSync(r,e)}c(un,"writeFile");function Ao(r){v.existsSync(r)&&v.rmSync(r)}c(Ao,"deleteFile");function wt(r){v.existsSync(r)&&v.rmSync(r,{recursive:!0,force:!0})}c(wt,"deleteDir");function Do(r,e=!0){if(v.existsSync(r))try{const t=v.readFileSync(r,"utf8");return G.load(t)||void 0}catch(t){if(!e)return;if(t instanceof Error){const n=E.relative(process.cwd(),r);throw new Error(`Failed to parse YAML file "${n}": ${t.message}`)}throw t}}c(Do,"readYaml");function dn(r,e,t){try{ve(E.dirname(r));const n=G.dump(e,t);v.writeFileSync(r,n,"utf8")}catch(n){if(n instanceof Error){const o=E.relative(process.cwd(),r);throw new Error(`Failed to write YAML file "${o}": ${n.message}`)}throw n}return e}c(dn,"writeYaml");function ve(r){v.existsSync(r)||v.mkdirSync(r,{recursive:!0})}c(ve,"ensureDirExists");function hn(r,e=!0){if(!v.existsSync(r)||!v.statSync(r).isDirectory())return;let t=v.readdirSync(r);t.length>0&&(t.forEach(n=>hn(E.join(r,n),!1)),t=v.readdirSync(r)),t.length===0&&!e&&v.rmdirSync(r)}c(hn,"cleanupEmptyFolders");function Oo(r){const e=r.split(/[\\/]/).join("/");return e.endsWith("/")?e+"**":e}c(Oo,"normalizePattern");async function pn(r,e,t){const n=(e??[]).map(Oo),o=[];if(t){const i=E.join(U(process.cwd()),"connectors");for(const s of Object.values(t)){const a=s.key,l=E.join(i,a),d=E.join(l,`${a}.yml`);v.existsSync(d)&&o.push({name:Un(a),content:v.readFileSync(d,"utf-8")});const h=[...s.versions];v.existsSync(E.join(l,"development"))&&!h.includes("")&&h.push("");for(const m of h){const p=m===""?"development":m,w=E.join(l,p,"src"),T=E.join(l,p,"src.zip"),S=m===""?je:m;v.existsSync(w)?o.push({name:Rt(a,S),content:await No(w)}):v.existsSync(T)&&o.push({name:Rt(a,S),content:v.readFileSync(T)})}}}return new Promise((i,s)=>{const a=Ve("zip",{zlib:{level:9}}),l=[];a.on("data",h=>l.push(h)),a.on("end",()=>i(Buffer.concat(l))),a.on("error",h=>s(h));const d=new Map;for(const h of r[x.Integration]||[])d.set(h.uuid,h.key);for(const[h,m]of Object.entries(r))for(const p of m){const w=d.get(p.integrationUuid),T=Kn(h,p.key,w);n.length>0&&!n.some(S=>hr(T,S))||a.append(G.dump(p),{name:T})}for(const{name:h,content:m}of o)a.append(m,{name:h});a.finalize()})}c(pn,"createMembraneZip");async function No(r){return new Promise((e,t)=>{const n=Ve("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(No,"createConnectorVersionZip");async function Ct(r,e){const t=await jt.loadAsync(r),n=[];for(const[o,i]of Object.entries(t.files)){if(i.dir)continue;const s=ie(o);if(!s)continue;const a=await i.async("string"),l=G.load(a);if(!l)continue;const d=await e(o,l,s);d!==void 0&&n.push(d)}return n}c(Ct,"iterateZipItems");async function Mo(r){const e=await jt.loadAsync(r),t={};for(const[n,o]of Object.entries(e.files)){if(o.dir)continue;const i=ie(n);if(!i)continue;const s=await o.async("string"),a=G.load(s);t[i.type]||(t[i.type]=[]),t[i.type].push(a)}return t}c(Mo,"readMembraneZip");async function fn(r=process.cwd()){const e=await mn(U(r)),t={};for(const{data:n,type:o}of e)t[o]||(t[o]=[]),t[o].push(n);return t}c(fn,"readMembraneDir");async function mn(r){const e=gn(r),t=[];for(const n of e){if(n.isDirectory())continue;const o=ie(n.path);if(!o)continue;const i=await n.readContent(),s=G.load(i),a=E.join(r,n.path);t.push({filePath:a,data:s,type:o.type})}return t}c(mn,"iterateMembraneFiles");function gn(r,e){const t=[];if(e||(e=r),!v.existsSync(e)||e.startsWith(E.join(r,"connectors")))return t;const n=v.readdirSync(e,{withFileTypes:!0});for(const o of n){const i=E.join(e,o.name),s=E.relative(r,i);o.isDirectory()?t.push(...gn(r,i)):o.isFile()&&ie(s)&&t.push({path:s,isDirectory:c(()=>!1,"isDirectory"),readContent:c(async()=>v.readFileSync(i,"utf8"),"readContent")})}return t}c(gn,"getMembraneFiles");function yn(){const r={},e=E.join(U(process.cwd()),"connectors");if(!v.existsSync(e))return r;const t=v.readdirSync(e);for(const n of t){const o=E.join(e,n);if(!v.statSync(o).isDirectory())continue;const i=E.join(o,`${n}.yml`),s=Do(i,!1);if(!s?.uuid)continue;const a=new Set,l=v.readdirSync(o);for(const d of l){if(d.endsWith(".yml"))continue;const h=E.join(o,d);v.statSync(h).isDirectory()&&a.add(d=="development"?"":d)}r[s.uuid]={key:n,id:s.id,versions:Array.from(a)}}return r}c(yn,"readConnectorsDir");function Ee(r,e){const t=E.join(U(process.cwd()),"connectors",r);return e==""||e===je?E.join(t,"development"):e?E.join(t,e):t}c(Ee,"getConnectorPath");const wn=1e3,Cn=12e4;async function Fo(){const r=await I.withClient(async t=>yt(t,()=>t.get("export"),{pollIntervalMs:wn,timeoutMs:Cn}));if(!r)throw new Error("Failed to export workspace");const e=await ge.get(r.downloadUrl,{responseType:"arraybuffer"});return Buffer.from(e.data)}c(Fo,"downloadWorkspaceExport");async function Sn(r,e={}){const t=new Mt;t.append("file",r,{filename:"membrane.zip",contentType:"application/zip"});const n=await I.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 yt(i,()=>Promise.resolve({jobId:a,accessKey:l}),{pollIntervalMs:1e3,timeoutMs:3e5})});if(!n)throw new Error("Failed to import workspace");const o={};for(const[i,s]of Object.entries(n))o[i]=new Set(s||[]);return o}c(Sn,"importWorkspace");async function Lo(r,e){const t=await I.withClient(async o=>yt(o,()=>o.get(`connectors/${r}/export-files`,{version:e}),{pollIntervalMs:wn,timeoutMs:Cn}));if(!t)throw new Error("Failed to export connector version");const n=await ge.get(t.downloadUrl,{responseType:"arraybuffer"});return Buffer.from(n.data)}c(Lo,"exportConnector");const bn=5;function jo(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(`
|
|
18
|
-
`)
|
|
19
|
-
`)).action(async(e,t)=>{const n=Lt({text:"Pushing workspace",color:"white"}).start();try{await ei(e,t,n)}catch(o){n.stop(),ui(o),process.exit(1)}})}c(Qo,"setupPushCommand");async function ei(r,e,t){const n=r.length>0,o=await fn(),i=yn(),s=oi(o,i),a=await ti(),l=await pn(s,n?r:void 0,a?i:void 0);e.force||(t.text="Comparing workspace",await ni(l,n)&&(t.stop(),process.exit(1)));const d=a?Object.keys(i):await ri(t);t.start("Pushing workspace..."),await Sn(l,{partial:n}),t.stop(),ci(s,d),process.exit(0)}c(ei,"pushWorkspace");async function ti(){const r=await I.getVersion(),e=r?ye.coerce(r):null,t=ye.coerce(Xo);return!!(e&&t&&ye.gte(e,t))}c(ti,"checkConnectorImportSupport");async function ni(r,e){const t=await Sn(r,{dryRun:!0,partial:e}),n=t[Y.DELETE].size>0;return n&&(await li(t,r),R.error("Use --force to delete remote elements")),n}c(ni,"checkForConflicts");async function ri(r){return(await Yt({onProgress:c((t,n)=>{t==="pushing"?r.start(`Pushing connector ${n}...`):r.succeed(`Pushed connector ${n}`)},"onProgress")})).pushedConnectors??[]}c(ri,"pushConnectorsLegacy");function oi(r,e){const t=si(r),n=ai(t,e),o={};for(const[i,s]of Object.entries(t)){const a=i;o[a]=(s||[]).map(l=>ii(l,a,n))}return o}c(oi,"resolveLegacyIdReferences");function ii(r,e,t){const n={...r},o=V[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===x.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(ii,"resolveElementIds");function si(r){const e={};for(const[t,n]of Object.entries(r))e[t]=(n||[]).map(o=>o.uuid?o:{...o,uuid:Zo()});return e}c(si,"generateMissingUuids");function ai(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(ai,"buildIdToUuidLookup");function ci(r,e=[]){const t=Object.values(r).reduce((n,o)=>n+(o?.length??0),0)+e.length;R.info(`\u25CF Pushed workspace elements \xB7 ${t}`);for(const n of Object.keys(r).sort()){const o=r[n];R.info(`\u2514\u2500\u2500 ${n}s \xB7 ${o?.length??0}`)}e.length>0&&R.info(`\u2514\u2500\u2500 connectors \xB7 ${e.length}`)}c(ci,"showStats");async function li(r,e){const t=r[Y.DELETE].size;R.info(`\u2299 Push: conflicts detected \xB7 ${t}`),await Ct(e,(n,o)=>{ie(n)&&r[Y.DELETE].has(o.uuid)&&R.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted locally)`)})}c(li,"showConflicts");function ui(r){R.error("\u25A0 Error"),R.error(`\u2514\u2500\u2500 ${r.message}`),R.error(` ${r.stack}`)}c(ui,"showError");const bt=[{id:"claude-code",name:"Claude Code",description:"Anthropic Claude Code agent",actionDescription:"Adding membrane MCP to .mcp.json in the current directory",addConfig:c(()=>{const r=E.join(process.cwd(),".mcp.json"),e={mcpServers:{membrane:{command:"membrane",args:["mcp"],env:{AGENT_NAME:"Claude Code"}}}};let t={};if(v.existsSync(r))try{t=JSON.parse(v.readFileSync(r,"utf8"))}catch{t={}}const n={...t,mcpServers:{...t.mcpServers,...e.mcpServers}};return v.writeFileSync(r,JSON.stringify(n,null,2)),`MCP server configuration added to ${r}`},"addConfig")},{id:"cursor",name:"Cursor",description:"Cursor AI editor",actionDescription:"Adding membrane MCP to .cursor/mcp.json in the current directory",addConfig:c(()=>{const r=E.join(process.cwd(),".cursor"),e=E.join(r,"mcp.json");v.existsSync(r)||v.mkdirSync(r);const t={mcpServers:{membrane:{command:"membrane",args:["mcp"],env:{AGENT_NAME:"Cursor"}}}};let n={};if(v.existsSync(e))try{n=JSON.parse(v.readFileSync(e,"utf8"))}catch{n={}}const o={...n,mcpServers:{...n.mcpServers,...t.mcpServers}};return v.writeFileSync(e,JSON.stringify(o,null,2)),`MCP server configuration added to ${e}`},"addConfig")}];function di({onExit:r,onComplete:e}){const[t,n]=D(0),[o,i]=D(!1),[s,a]=D(null),[l,d]=D(""),[h,m]=D("");ae((T,S)=>{if(l||h){(S.escape||T==="q"||S.return)&&e();return}if(o)S.return||T===" "?p(s):S.escape&&(i(!1),a(null));else if(S.escape)r();else if(S.upArrow||T==="k")n(Math.max(0,t-1));else if(S.downArrow||T==="j")n(Math.min(bt.length-1,t+1));else if(S.return||T===" "){const O=bt[t];a(O),i(!0)}});const p=c(T=>{try{const S=T.addConfig();d(S)}catch(S){m(`Failed to write configuration: ${S.message||S}`)}},"addMcpConfiguration"),w=Math.min(80,process.stdout.columns||80);return l?b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:w,children:[u(g,{marginTop:-1,marginBottom:1,children:b(y,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",u(y,{color:"green",children:"Success"})]})}),b(g,{flexDirection:"column",paddingLeft:2,children:[u(y,{color:"green",children:l}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"The agent will now be able to use Membrane's integration capabilities."})})]}),u(g,{marginTop:1,paddingLeft:2,children:u(y,{color:"white",children:"[esc/q/enter: exit]"})})]}):h?b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:w,children:[u(g,{marginTop:-1,marginBottom:1,children:b(y,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",u(y,{color:"red",children:"Error"})]})}),u(g,{flexDirection:"column",paddingLeft:2,children:u(y,{color:"red",children:h})}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"[esc/q/enter: exit]"})})]}):o&&s?b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:w,children:[u(g,{marginTop:-1,marginBottom:1,children:b(y,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",u(y,{color:"cyan",children:"Confirmation"})]})}),b(g,{flexDirection:"column",paddingLeft:2,children:[b(y,{children:["Connect ",u(y,{bold:!0,children:s.name})," to Membrane via MCP?"]}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"This will add an MCP server configuration that allows the agent to use Membrane's integration capabilities."})}),u(g,{marginTop:1,children:u(y,{color:"yellow",bold:!0,children:s.actionDescription})}),u(g,{marginTop:2,marginBottom:1,children:b(y,{children:[u(y,{color:"white",bold:!0,children:"[Enter] Confirm"})," ",u(y,{color:"gray",children:"[Esc] Cancel"})]})})]})]}):b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:w,children:[u(g,{marginTop:-1,marginBottom:1,children:b(y,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",u(y,{color:"cyan",children:"Select Agent"})]})}),b(g,{flexDirection:"column",paddingLeft:2,children:[u(y,{color:"grey",children:"Choose an agent to connect to Membrane via MCP:"}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"This will add an MCP server configuration that allows the agent to use Membrane's integration capabilities."})}),u(g,{marginTop:1,flexDirection:"column",children:bt.map((T,S)=>b(g,{children:[b(y,{color:t===S?"cyan":"white",children:[t===S?"\u25B6 ":" ",T.name]}),b(y,{color:"grey",children:[" \u2014 ",T.description]})]},T.id))})]}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"[\u2191\u2193: select] [enter: choose] [esc: exit]"})})]})}c(di,"AddMcpServerScreen");function hi(){const[r,e]=D(null),[t,n]=D([]),[o,i]=D(null);return he(()=>{const s=c(({status:l})=>{e(l),i(null)},"handleMcpStatusChanged"),a=c(({servers:l})=>{n(l),i(null)},"handleMcpServersChanged");return te.on(F.McpStatusChanged,s),te.on(F.McpServersChanged,a),()=>{te.off(F.McpStatusChanged,s),te.off(F.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(hi,"useMcpStatus");function pi(){const{error:r,serverCount:e,allMcpServers:t}=hi(),n=Math.min(100,process.stdout.columns||100);return b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:n,children:[u(g,{marginTop:-1,marginBottom:0,flexDirection:"column",children:b(y,{bold:!0,children:["\u{1F916} Connected AI Agents:"," ",r?u(y,{color:"red",children:"error reading status"}):e===0?u(y,{color:"yellow",children:"none"}):u(y,{color:"green",children:e})]})}),!r&&e===0&&u(g,{marginTop:1,children:b(y,{color:"grey",children:["Connect your AI agents to Membrane.",u(zn,{}),"It will give them tools and context to build integrations."]})}),t.length>0&&u(g,{flexDirection:"column",paddingLeft:2,marginTop:1,children:t.map((o,i)=>u(g,{children:b(y,{color:"grey",children:["#",i+1," ",o.agentName,": ",o.totalRequests," calls"]})},o.processId))}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"[a: connect an agent]"})})]})}c(pi,"Agent");const En=c(r=>{switch(r){case"error":return"red";case"success":return"green";case"warning":return"yellow";default:return}},"getLogColor");function Tn(r,e){return e<3?r.slice(0,Math.max(0,e)):r.length<=e?r:`${r.slice(0,e-3)}...`}c(Tn,"truncateText");function fi({children:r}){const{state:e,logs:t}=H();return!e||e===k.NOT_INITIALIZED?b(g,{gap:1,flexDirection:"row",children:[u(ur,{type:"dots"}),u(y,{children:"Initializing..."})]}):e===k.SETTING_UP?u(g,{gap:1,flexDirection:"row",children:u(y,{children:"No workspace selected. Please run `membrane init` to select a workspace."})}):e===k.ERROR?u(g,{flexDirection:"column",children:t.slice().map((n,o)=>u(y,{color:En(n.type),children:n.message},n.timestamp+o))}):r}c(fi,"EnsureInitialized");function mi(){const{stats:r}=H(),e=Object.entries(r).filter(([t,n])=>n>0);return e.length===0?null:b(g,{flexDirection:"column",children:[u(g,{children:u(g,{width:12,children:u(y,{color:"grey",children:"Elements:"})})}),u(g,{flexDirection:"column",marginLeft:1,children:e.map(([t,n])=>b(g,{children:[u(g,{width:20,children:b(y,{children:[t,":"]})}),u(y,{color:"green",children:n})]},t))})]})}c(mi,"ElementStats");const vt=5,gi=6;function yi(){const{logs:r}=H(),[e,t]=D(0),n=Math.min(100,process.stdout.columns||100),o=vt,i=Math.max(0,r.length-o-e),s=r.length-e,a=r.slice(i,s),l=n-gi,d=e<r.length-o,h=e>0;return ae((m,p)=>{if(r.length!==0)if(p.upArrow){const w=Math.max(0,r.length-o);t(T=>Math.min(w,T+1))}else p.downArrow?t(w=>Math.max(0,w-1)):(m==="G"||m==="g")&&t(0)}),b(g,{flexDirection:"column",paddingTop:1,children:[b(y,{color:"grey",children:["Recent Activity (",i+1,"-",s," of ",r.length,"):",r.length>vt&&u(y,{color:"grey",children:" [arrows: scroll] [g: end]"})]}),a.map((m,p)=>u(g,{marginLeft:1,children:u(y,{color:En(m.type),children:Tn(m.message,l)})},m.timestamp+p)),r.length>vt&&b(g,{marginLeft:1,flexDirection:"row",children:[d&&u(y,{color:"grey",children:"\u2191 "}),h&&u(y,{color:"grey",children:"\u2193 "})]})]})}c(yi,"Logs");const Ne=[{value:"sync",label:"Continue (overwrite/delete)",key:""},{value:"exit",label:"Cancel",key:""}];function wi(){const{state:r,resolveConflicts:e,exit:t}=H(),[n,o]=D(0),[i,s]=D(!1),[a,l]=D(!1);return ae((d,h)=>{if(!i){if(h.ctrl&&d.toLowerCase()==="r"){l(!a);return}h.upArrow?o(m=>m>0?m-1:Ne.length-1):h.downArrow?o(m=>m<Ne.length-1?m+1:0):d.toLowerCase()==="y"?o(0):d.toLowerCase()==="n"?o(1):(h.return||d===" ")&&(s(!0),Ne[n].value==="sync"?e({watch:!0}):t())}}),he(()=>{r!==k.CONFLICTS&&i&&s(!1)},[r,i]),b(g,{flexDirection:"column",paddingTop:1,children:[u(g,{children:u(g,{flexDirection:"row",gap:2,children:u(y,{bold:!0,color:"white",children:"Conflicts with remote"})})}),u(g,{children:u(y,{color:"grey",children:"The remote workspace has changes that aren't in your local workspace:"})}),u(g,{marginTop:1,marginLeft:2,children:u(Si,{isExpanded:a})}),b(g,{marginTop:2,flexDirection:"row",gap:1,children:[u(y,{color:"white",bold:!0,children:"What would you like to do?"}),u(y,{color:"grey",children:"[up/down, enter]"})]}),u(g,{children:i?b(g,{flexDirection:"row",gap:1,children:[u(Pe,{type:"dots"}),u(y,{color:"blue",bold:!0,children:"Syncing with remote..."})]}):u(g,{flexDirection:"column",children:Ne.map((d,h)=>u(g,{flexDirection:"column",children:b(g,{flexDirection:"row",gap:1,children:[u(y,{color:n===h?"cyan":"grey",children:n===h?"\u25B6":" "}),u(y,{color:n===h?"cyan":"grey",bold:n===h,children:d.label})]})},d.value))})})]})}c(wi,"ResolveChangesUI");const Ci={[Z.UPDATE]:{incoming:{label:"Elements updated in remote",description:"(to be overwritten from remote)"},outgoing:{label:"Elements updated locally",description:"(to be pushed to remote)"}},[Z.DELETE]:{incoming:{label:"Elements not existing in remote",description:"(to be deleted locally)"},outgoing:{label:"Elements deleted locally",description:"(to be deleted from remote)"}},[Z.CREATE]:{incoming:{label:"Elements created in remote",description:"(to be created locally)"},outgoing:{label:"Elements created locally",description:"(to be created in remote)"}}};function Si({isExpanded:r,showControls:e=!0}){const{conflicts:t}=H(),n=5,o=Hn(()=>{const i={};return t.forEach(s=>{const a=`${s.type}-${s.direction}`;i[a]||(i[a]=[]),i[a].push(s)}),i},[t]);return u(g,{flexDirection:"column",children:Object.entries(o).map(([i,s])=>{if(s.length===0)return null;const[a,l]=i.split("-"),d=Ci[a][l];return b(g,{flexDirection:"column",children:[b(g,{flexDirection:"row",gap:1,children:[b(y,{color:"yellow",children:[d.label," (",s.length,")"]}),u(y,{color:"white",children:d.description})]}),(r?s:s.slice(0,n)).map(h=>u(g,{marginLeft:2,children:b(y,{color:"grey",children:["\u2022 ",h.element.id," (",h.element.relativePath,")"]})},h.element.id)),!r&&s.length>n&&u(g,{marginLeft:2,children:b(y,{color:"cyan",children:["... and ",s.length-n," more",e?" (press Ctrl+R to show all)":""]})}),r&&s.length>n&&e&&u(g,{marginLeft:2,children:u(y,{color:"cyan",children:"(press Ctrl+R to collapse)"})})]},i)})})}c(Si,"Conflicts");function bi(){const{config:r,state:e,logs:t,currentWorkspace:n,pull:o}=H(),i=n?.name,s=i?Tn(i,30):r?.workspaceKey,a=Math.min(100,process.stdout.columns||100);return he(()=>{o({watch:!0})},[]),b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:a,children:[u(g,{marginTop:-1,marginBottom:1,children:b(g,{flexDirection:"row",gap:1,children:[u(y,{bold:!0,children:"\u{1F504} Workspace"}),b(y,{color:Ei(e),children:[" [",vi(e),"] "]})]})}),b(g,{children:[u(g,{width:12,children:u(y,{color:"grey",children:"Local:"})}),u(y,{color:"grey",children:process.cwd()})]}),b(g,{children:[u(g,{width:12,children:u(y,{color:"grey",children:"Remote:"})}),r?.workspaceKey?b(y,{color:"grey",children:[s," [o: open in console] [w: change]"]}):b(y,{children:[u(y,{color:"yellow",children:"not selected"})," [w: select]"]})]}),e===k.CONFLICTS?u(wi,{}):b(ke,{children:[u(g,{paddingTop:1,children:u(mi,{})}),t.length>0&&u(yi,{})]})]})}c(bi,"Workspace");function vi(r){switch(r){case k.PULLING:return"pulling";case k.PUSHING:return"pushing";case k.CONFLICTS:return"conflicts";case k.SYNCED:return"synced";case k.ERROR:return"error";case k.WATCHING:return"tracking changes";case k.RESOLVING:return"resolving";case k.NOT_SYNCED:return"not synced";case k.INITIALIZED:return"initialized";case k.SETTING_UP:return"setup required";default:return"unknown"}}c(vi,"getStatusDisplay");function Ei(r){switch(r){case k.PULLING:return"yellow";case k.PUSHING:return"yellow";case k.CONFLICTS:return"red";case k.SYNCED:return"green";case k.ERROR:return"red";case k.WATCHING:return"green";case k.RESOLVING:return"yellow";case k.NOT_SYNCED:return"grey";case k.SETTING_UP:return"yellow";default:return"grey"}}c(Ei,"getStatusColor");function Ti(){const r=go(),e=Ge(!0),{exit:t,state:n}=H(),[o,i]=D(null),s=o??(n===k.SETTING_UP?"setup":"main");ae(l=>{s==="main"&&(l==="w"&&i("workspace-selection"),l==="a"&&i("add-mcp-server"),l==="o"&&n===k.INITIALIZED&&a(),l==="s"&&i("setup"))});async function a(){try{const l=await Gt(r),d=rt(`/w/${l}`),h=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";pr(`${h} "${d}"`)}catch(l){console.error("Failed to open workspace:",l),t()}}return c(a,"handleOpenWorkspace"),he(()=>(e.current=!0,()=>{e.current=!1}),[]),s==="workspace-selection"?u(an,{onExit:c(()=>i(null),"onExit")}):s==="add-mcp-server"?u(di,{onExit:c(()=>i(null),"onExit"),onComplete:c(()=>i(null),"onComplete")}):s==="setup"?u(cn,{onComplete:c(()=>i(null),"onComplete")},Date.now()):u(fi,{children:b(g,{flexDirection:"column",children:[u(g,{flexGrow:1,children:u(pi,{})}),u(bi,{}),u(g,{paddingLeft:2,children:u(y,{color:"grey",children:"[s: (re-)setup]"})})]})})}c(Ti,"Main");const xi=c(()=>[C.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"),C.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),C.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"),C.yellow("\u2502 Real-time agent mode is experimental and subject to changes. \u2502"),C.yellow("\u2502 Use in production environments is not recommended. \u2502"),C.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(`
|
|
20
|
-
`),"createExperimentalWarning$1");function Ii(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(`
|
|
21
|
-
`)).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?I.init({maxRequestsPerSecond:n}):(f.error(`Invalid RPS value: ${n}. Must be between 1 and 1000.`),process.exit(1))}console.warn(xi()),He(se.createElement(mt,{cwd:process.cwd(),membraneCLIService:e,children:se.createElement(Ti)}))})}c(Ii,"setupSyncCommand");class $i{static{c(this,"BaseRunner")}constructor(e={}){if(this.options=e,this.fsPaths=ot(),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 ki="claude-sonnet-4-20250514";class $t{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=Ce();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 kt({token:await this.createMembraneToken(o),apiUri:o.apiUri}),s=new fr({apiKey:o.anthropicApiKey}),a={complete:c(async({prompt:l,maxTokens:d})=>{const h=await s.messages.create({model:ki,max_tokens:d,messages:[{role:"user",content:l}]});return h.content[0].type==="text"?h.content[0].text:""},"complete")};return new $t({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(),Ye(t,n.getResult());this.writeResults(t)}async readYaml(e){const t=$.join(this.testsDir,this.testBasePath,this.connectionId,e);return it(t)}async writeYaml(e,t){const n=$.join(this.testsDir,this.testBasePath,this.connectionId,e);P.mkdirSync($.dirname(n),{recursive:!0}),P.writeFileSync(n,G.dump(t,{noRefs:!0}))}writeResults(e){const t=$.join(this.testsDir,this.testBasePath,this.connectionId);P.mkdirSync(t,{recursive:!0});const n=$.join(t,"test-results.yaml");P.writeFileSync(n,G.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 ze.sign(n,e.workspaceSecret,o)}}gr.interpolate=/{{([\s\S]+?)}}/g;function Et(r,e){if(typeof r=="string"){const t=mr(r),n={state:e,random:{number:c(()=>we.number.int(),"number"),alphaNumeric:c(i=>we.string.alphanumeric(i),"alphaNumeric")},faker:{company:{name:c(()=>we.company.name(),"name"),catchPhrase:c(()=>we.company.catchPhrase(),"catchPhrase")},internet:{email:c(()=>we.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=>Et(t,e)):typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).map(([t,n])=>[t,Et(n,e)])):r}c(Et,"processNode");function Ri(r,e){return Et(r,e)}c(Ri,"handleTemplate");class Pi{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(`${C.bold.cyan("[start]")} ${C.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(`${C.bold.yellow("[initialized]")} ${C.yellow(e.path)}`)),s=Ri(i,this.environment.state),await e.run(s),console.debug(`${C.bold.green("[success]")} ${C.yellow(e.path)}`),t=!0,o=e.getResult(),Ue(this.result,e.path,o)}catch(l){if(console.error(`${C.bold.red("[error]")} ${C.yellow(e.path)}: ${l}`),this.environment.options.fix&&!n){n=!0;try{await e.fix(l);continue}catch(d){console.error(`${C.bold.red("[fix fail]")} ${C.yellow(e.path)}: ${d}`)}}Ue(this.result,e.path,{error:J(l)}),t=!0,o={error:J(l)}}const a={...s,result:o};await this.environment.writeYaml(e.getTestCasePath(),a)}async runTestSuite(e){await e.run(),Ye(this.result,e.getResult())}}class oe{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(C.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:J(o)}),this.logMsg(`\u274C ${t}: ${o.message}`)}}logMsg(e){console.debug(`${" ".repeat(this.level*2)}${e}`)}getTestCasePath(){return`${this.path}.test.yml`}}function Tt(r,e){const t={};for(const n in e){if(!(n in r)){t[n]=e[n];continue}const o=r[n],i=e[n];if(o&&i&&typeof o=="object"&&typeof i=="object"){if(Array.isArray(o)&&Array.isArray(i)){const s=i.filter(a=>!o.some(l=>{if(typeof l=="object"&&typeof a=="object"&&l!==null&&a!==null&&!Array.isArray(l)&&!Array.isArray(a)){for(const d in a)if(!(d in l)||!xt(l[d],a[d]))return!1;return!0}else return JSON.stringify(l)===JSON.stringify(a)}));s.length>0&&(t[n]=s)}else if(!Array.isArray(o)&&!Array.isArray(i)){const s=Tt(o,i);s!==null&&(t[n]=s)}else t[n]=i;continue}xt(o,i)||(t[n]=i)}return Object.keys(t).length===0?null:t}c(Tt,"getNotMatchingSubFields");function xt(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(xt,"softCompare");class Ai extends oe{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=Ke(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=Pt(n),a=Ie(e.input.fields,s,{skipUnknownFields:!0}),l=Ie(i.record.fields,s),d=Tt(l,a);await this.assert(()=>!d,"Returned fields match created fields",{difference:d,sentFields:a,receivedFields:l})}const o=Bn(n??{});if(o.length>0){const i={};o.forEach(a=>{const l=_n(e.input.fields,a);typeof l<"u"&&Ue(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=Ke(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=J(t),o=Ke(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:
|
|
24
|
+
`,version:"1.0.0"});for(const C of d){const T=C.execute;C.execute=async S=>(Po(process.pid,process.cwd()),T(S)),p.addTool(C)}St({isRunning:!0,startTime:new Date().toISOString(),toolsCount:d.length,lastActivity:new Date().toISOString(),processId:process.pid,cwd:process.cwd(),agentName:process.env.AGENT_NAME||"Unnamed Agent"});const f=setInterval(()=>{St({processId:process.pid,cwd:process.cwd(),lastActivity:new Date().toISOString()})},5e3),h=c(async()=>{clearInterval(f),be(process.pid,process.cwd());try{await p.stop()}catch{}},"cleanup");await p.start({transportType:"stdio"}),process.on("SIGINT",async()=>{await h(),process.exit(0)}),process.on("SIGTERM",async()=>{await h(),process.exit(0)}),process.on("exit",()=>{be(process.pid,process.cwd())}),process.on("uncaughtException",async C=>{console.error("Uncaught exception:",C.message),await h(),process.exit(1)}),process.on("unhandledRejection",async C=>{console.error("Unhandled rejection:",C),await h(),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(hi,"setupMcpCommand");function pi(r){r.command("open").description("Open the workspace in the browser").addHelpText("after",["","Examples:"," membrane open # Open workspace in browser",""].join(`
|
|
25
|
+
`)).action(async()=>{try{I.header("Opening Workspace in Browser"),I.info("Loading configuration...");const e=Se();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");I.info("Retrieving workspace ID...");const t=await tn(process.cwd()),n=dt(`/w/${t}`);I.info(`Opening ${n}...`);const{default:o}=await import("open");await o(n),I.success("Browser opened successfully")}catch(e){e instanceof Error&&(I.error(e.message),process.exit(1)),I.error("An unknown error occurred"),process.exit(1)}})}c(pi,"setupOpenCommand");async function kt(r,e,t={}){const{jobId:n,accessKey:o}=await e(),i=`${n}:${o}`;m.debug(`[background-job] Started job ${n}`);const s=Date.now(),{pollIntervalMs:a=1e3,timeoutMs:l=3e5,maxRetries:d=3}=t;let p=0;for(;;){if(Date.now()-s>l)throw new Error(`Background job ${n} timed out after ${l}ms`);await new Promise(C=>setTimeout(C,a));let h;try{h=await r.get(`background-jobs/${i}`),p=0}catch(C){if(C instanceof Vn&&p<d){p++,m.debug(`[background-job] Job ${n} not found, retrying (${p}/${d})`);continue}throw C}if(h.status==="completed"){if(m.debug(`[background-job] Completed job ${n}`),!h.result)throw new Error(`Background job ${n} completed but returned no result`);return h.result}if(h.status==="failed"){const C=h.error?.message||"Unknown error";throw m.error(`[background-job] Failed job ${n}: ${C}`),h.error?.stack&&m.error(`Stacktrace: ${h.error.stack}`),new Error(`Background job ${n} failed: ${C}`)}m.debug(`[background-job] Polling job ${n} (status: ${h.status})`)}}c(kt,"pollBackgroundJob");const Sn=1e3,bn=12e4;async function fi(){const r=await $.withClient(async t=>kt(t,()=>t.get("export"),{pollIntervalMs:Sn,timeoutMs:bn}));if(!r)throw new Error("Failed to export workspace");const e=await we.get(r.downloadUrl,{responseType:"arraybuffer"});return Buffer.from(e.data)}c(fi,"downloadWorkspaceExport");async function vn(r,e={}){const t=new Jt;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 kt(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(vn,"importWorkspace");async function mi(r,e){const t=await $.withClient(async o=>kt(o,()=>o.get(`connectors/${r}/export-files`,{version:e}),{pollIntervalMs:Sn,timeoutMs:bn}));if(!t)throw new Error("Failed to export connector version");const n=await we.get(t.downloadUrl,{responseType:"arraybuffer"});return Buffer.from(n.data)}c(mi,"exportConnector");function En(r,e){Ee(E.dirname(r)),v.writeFileSync(r,e)}c(En,"writeFile");function gi(r){v.existsSync(r)&&v.rmSync(r)}c(gi,"deleteFile");function $t(r){v.existsSync(r)&&v.rmSync(r,{recursive:!0,force:!0})}c($t,"deleteDir");function yi(r,e=!0){if(v.existsSync(r))try{const t=v.readFileSync(r,"utf8");return H.load(t)||void 0}catch(t){if(!e)return;if(t instanceof Error){const n=E.relative(process.cwd(),r);throw new Error(`Failed to parse YAML file "${n}": ${t.message}`)}throw t}}c(yi,"readYaml");function Tn(r,e,t){try{Ee(E.dirname(r));const n=H.dump(e,t);v.writeFileSync(r,n,"utf8")}catch(n){if(n instanceof Error){const o=E.relative(process.cwd(),r);throw new Error(`Failed to write YAML file "${o}": ${n.message}`)}throw n}return e}c(Tn,"writeYaml");function Ee(r){v.existsSync(r)||v.mkdirSync(r,{recursive:!0})}c(Ee,"ensureDirExists");function xn(r,e=!0){if(!v.existsSync(r)||!v.statSync(r).isDirectory())return;let t=v.readdirSync(r);t.length>0&&(t.forEach(n=>xn(E.join(r,n),!1)),t=v.readdirSync(r)),t.length===0&&!e&&v.rmdirSync(r)}c(xn,"cleanupEmptyFolders");function wi(r){const e=r.split(/[\\/]/).join("/");return e.endsWith("/")?e+"**":e}c(wi,"normalizePattern");async function In(r,e,t){const n=(e??[]).map(wi),o=[];if(t){const i=E.join(q(process.cwd()),"connectors");for(const s of Object.values(t)){const a=s.key,l=E.join(i,a),d=E.join(l,`${a}.yml`);v.existsSync(d)&&o.push({name:Yn(a),content:v.readFileSync(d,"utf-8")});const p=[...s.versions];v.existsSync(E.join(l,"development"))&&!p.includes("")&&p.push("");for(const f of p){const h=f===""?"development":f,C=E.join(l,h,"src"),T=E.join(l,h,"src.zip"),S=f===""?Be:f;v.existsSync(C)?o.push({name:Ut(a,S),content:await Ci(C)}):v.existsSync(T)&&o.push({name:Ut(a,S),content:v.readFileSync(T)})}}}return new Promise((i,s)=>{const a=rt("zip",{zlib:{level:9}}),l=[];a.on("data",p=>l.push(p)),a.on("end",()=>i(Buffer.concat(l))),a.on("error",p=>s(p));const d=new Map;for(const p of r[x.Integration]||[])d.set(p.uuid,p.key);for(const[p,f]of Object.entries(r))for(const h of f){const C=d.get(h.integrationUuid),T=Zn(p,h.key,C);n.length>0&&!n.some(S=>Pr(T,S))||a.append(H.dump(h),{name:T})}for(const{name:p,content:f}of o)a.append(f,{name:p});a.finalize()})}c(In,"createMembraneZip");async function Ci(r){return new Promise((e,t)=>{const n=rt("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(Ci,"createConnectorVersionZip");async function Pt(r,e){const t=await Gt.loadAsync(r),n=[];for(const[o,i]of Object.entries(t.files)){if(i.dir)continue;const s=ae(o);if(!s)continue;const a=await i.async("string"),l=H.load(a);if(!l)continue;const d=await e(o,l,s);d!==void 0&&n.push(d)}return n}c(Pt,"iterateZipItems");async function Si(r){const e=await Gt.loadAsync(r),t={};for(const[n,o]of Object.entries(e.files)){if(o.dir)continue;const i=ae(n);if(!i)continue;const s=await o.async("string"),a=H.load(s);t[i.type]||(t[i.type]=[]),t[i.type].push(a)}return t}c(Si,"readMembraneZip");async function kn(r=process.cwd()){const e=await $n(q(r)),t={};for(const{data:n,type:o}of e)t[o]||(t[o]=[]),t[o].push(n);return t}c(kn,"readMembraneDir");async function $n(r){const e=Pn(r),t=[];for(const n of e){if(n.isDirectory())continue;const o=ae(n.path);if(!o)continue;const i=await n.readContent(),s=H.load(i),a=E.join(r,n.path);t.push({filePath:a,data:s,type:o.type})}return t}c($n,"iterateMembraneFiles");function Pn(r,e){const t=[];if(e||(e=r),!v.existsSync(e)||e.startsWith(E.join(r,"connectors")))return t;const n=v.readdirSync(e,{withFileTypes:!0});for(const o of n){const i=E.join(e,o.name),s=E.relative(r,i);o.isDirectory()?t.push(...Pn(r,i)):o.isFile()&&ae(s)&&t.push({path:s,isDirectory:c(()=>!1,"isDirectory"),readContent:c(async()=>v.readFileSync(i,"utf8"),"readContent")})}return t}c(Pn,"getMembraneFiles");function An(){const r={},e=E.join(q(process.cwd()),"connectors");if(!v.existsSync(e))return r;const t=v.readdirSync(e);for(const n of t){const o=E.join(e,n);if(!v.statSync(o).isDirectory())continue;const i=E.join(o,`${n}.yml`),s=yi(i,!1);if(!s?.uuid)continue;const a=new Set,l=v.readdirSync(o);for(const d of l){if(d.endsWith(".yml"))continue;const p=E.join(o,d);v.statSync(p).isDirectory()&&a.add(d=="development"?"":d)}r[s.uuid]={key:n,id:s.id,versions:Array.from(a)}}return r}c(An,"readConnectorsDir");function Te(r,e){const t=E.join(q(process.cwd()),"connectors",r);return e==""||e===Be?E.join(t,"development"):e?E.join(t,e):t}c(Te,"getConnectorPath");const Rn=5;function bi(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(`
|
|
26
|
+
`)).action(async e=>{const t=ot({text:"Pulling workspace",color:"white"}).start();try{const n=await vi(e,t);t.stop(),ki(n.workspaceExport,n.connectors)}catch(n){t.stop(),Pi(n),process.exit(1)}})}c(bi,"setupPullCommand");async function vi(r,e){const t=await kn(),n=await In(t),o=await fi(),i=await Si(o),{comparison:s}=Xn(t,i);s[X.DELETE].size>0&&!r.force&&(await $i(s,n),I.error("Use --force to delete local elements"),process.exit(1));const l=await $n(q(process.cwd()));for(const{filePath:f,data:h}of l)s[X.DELETE].has(h.uuid)&&gi(f);return xn(q(process.cwd())),await Pt(o,(f,h)=>{if(ae(f)&&(s[X.CREATE].has(h.uuid)||s[X.UPDATE].has(h.uuid))){const T=k.join(q(process.cwd()),f);Tn(T,h)}}),{connectors:await $.isVersionAtLeast("1.8")?await Ei(o,e):await xi(i[x.Integration],e),workspaceExport:i}}c(vi,"pullWorkspace");async function Ei(r,e){e.text="Extracting connectors",$t(k.join(q(process.cwd()),"connectors"));const t=new Set,n=await Pe.Open.buffer(r);for(const o of n.files){if(!o.path.startsWith("connectors/")||o.type==="Directory")continue;const i=k.join(q(process.cwd()),o.path);Ee(k.dirname(i));const s=await o.buffer();if(En(i,s),t.add(o.path.split("/")[1]),o.path.endsWith("/development/src.zip")){const a=k.join(k.dirname(i),"src");Ee(a),await(await Pe.Open.buffer(s)).extract({path:a})}}return Array.from(t)}c(Ei,"extractConnectorsFromExport");async function Ti(r,e,t){if(En(k.join(Te(r,e),"src.zip"),t),!e||e===Be){const n=k.join(Te(r,e),"src");Ee(n),await(await Pe.Open.buffer(t)).extract({path:n})}}c(Ti,"writeConnectorVersion");async function xi(r,e){e.text="Pulling connectors";const t=new Map,{id:n}=await $.withClient(l=>l.get("org-workspace-id")),{items:o=[]}=await $.withClient(l=>l.get(`/connectors?workspaceId=${n}`));for(const l of o){const d=l.uuid??l.id;!l.isPublic&&d&&t.set(d,new Set([""]))}for(const l of r??[]){const{connectorUuid:d,connectorVersion:p}=l;d&&(t.has(d)||t.set(d,new Set),t.get(d).add(p??""))}const i=An();for(const[l,{key:d,versions:p}]of Object.entries(i)){if(!t.has(l)){const h=Te(d);$t(h);continue}const f=t.get(l);for(const h of p)if(!f.has(h)){const C=Te(d,h);$t(C)}}const s=Array.from(t.entries()),a=c((l,d)=>{l==="pulling"?e.start(`Pulling connector ${d}...`):e.succeed(`Pulled connector ${d}`)},"onProgress");for(let l=0;l<s.length;l+=Rn){const d=s.slice(l,l+Rn);await Promise.all(d.map(([p,f])=>Ii(p,Array.from(f),a)))}return Array.from(t.keys())}c(xi,"pullConnectorsLegacy");async function Ii(r,e,t){const n=await $.withClient(d=>d.get(`connectors/${r}/export-json`),!1),o=await $.withClient(d=>d.get(`connectors/${r}`),!1);if(!n||!o||!n.key||!o.key)return;const i=o.name||n.key;t?.("pulling",i);const s={...n,id:o.id,uuid:o.uuid},a=Te(n.key),l=k.join(a,`${n.key}.yml`);Tn(l,s);for(const d of e){const p=await mi(r,d);await Ti(n.key,d,p)}t?.("pulled",i)}c(Ii,"pullConnector");function ki(r,e=[]){const t=Object.values(r).reduce((n,o)=>n+(o?.length??0),0)+e.length;I.info(`\u25CF Pulled workspace elements \xB7 ${t}`);for(const n of Object.keys(r).sort()){const o=r[n];I.info(`\u2514\u2500\u2500 ${n}s \xB7 ${o?.length??0}`)}e.length>0&&I.info(`\u2514\u2500\u2500 connectors \xB7 ${e.length}`)}c(ki,"showStats$1");async function $i(r,e){const t=r[X.DELETE].size;I.info(`\u2299 Pull: conflicts detected \xB7 ${t}`),await Pt(e,(n,o)=>{ae(n)&&r[X.DELETE].has(o.uuid)&&I.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted in remote)`)})}c($i,"showConflicts$1");async function Pi(r){I.error("\u25A0 Error"),I.error(`\u2514\u2500\u2500 ${r.message}`),I.error(` ${r.stack}`)}c(Pi,"showError$1");const K=[];for(let r=0;r<256;++r)K.push((r+256).toString(16).slice(1));function Ai(r,e=0){return(K[r[e+0]]+K[r[e+1]]+K[r[e+2]]+K[r[e+3]]+"-"+K[r[e+4]]+K[r[e+5]]+"-"+K[r[e+6]]+K[r[e+7]]+"-"+K[r[e+8]]+K[r[e+9]]+"-"+K[r[e+10]]+K[r[e+11]]+K[r[e+12]]+K[r[e+13]]+K[r[e+14]]+K[r[e+15]]).toLowerCase()}c(Ai,"unsafeStringify");let At;const Ri=new Uint8Array(16);function Di(){if(!At){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");At=crypto.getRandomValues.bind(crypto)}return At(Ri)}c(Di,"rng");const Oi=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto);var Dn={randomUUID:Oi};function Ni(r,e,t){if(Dn.randomUUID&&!r)return Dn.randomUUID();r=r||{};const n=r.random??r.rng?.()??Di();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,Ai(n)}c(Ni,"v4");function Mi(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(`
|
|
27
|
+
`)).action(async(e,t)=>{const n=ot({text:"Pushing workspace",color:"white"}).start();try{await Fi(e,t,n)}catch(o){n.stop(),Ji(o),process.exit(1)}})}c(Mi,"setupPushCommand");async function Fi(r,e,t){const n=r.length>0,o=await kn(),i=An(),s=Ui(o,i),a=await $.isVersionAtLeast("1.9"),l=await In(s,n?r:void 0,a?i:void 0);e.force||(t.text="Comparing workspace",await Li(l,n)&&(t.stop(),process.exit(1)));const d=a?Object.keys(i):await ji(t);t.start("Pushing workspace..."),await vn(l,{partial:n}),t.stop(),Bi(s,d),process.exit(0)}c(Fi,"pushWorkspace");async function Li(r,e){const t=await vn(r,{dryRun:!0,partial:e}),n=t[X.DELETE].size>0;return n&&(await Wi(t,r),I.error("Use --force to delete remote elements")),n}c(Li,"checkForConflicts");async function ji(r){return(await sn({onProgress:c((t,n)=>{t==="pushing"?r.start(`Pushing connector ${n}...`):r.succeed(`Pushed connector ${n}`)},"onProgress")})).pushedConnectors??[]}c(ji,"pushConnectorsLegacy");function Ui(r,e){const t=Ki(r),n=qi(t,e),o={};for(const[i,s]of Object.entries(t)){const a=i;o[a]=(s||[]).map(l=>_i(l,a,n))}return o}c(Ui,"resolveLegacyIdReferences");function _i(r,e,t){const n={...r},o=Z[e]?.parentFieldKey||"parentId";if(n.integrationId&&!n.integrationUuid&&(n.integrationUuid=t.get(n.integrationId.toString())||n.integrationId,delete n.integrationId),n.connectorId){if(!n.connectorUuid){const i=t.get(n.connectorId.toString());i&&(n.connectorUuid=i)}delete n.connectorId}if(n[o]){const i=t.get(n[o].toString());i&&(n.parentUuid=i)}return e===x.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(_i,"resolveElementIds");function Ki(r){const e={};for(const[t,n]of Object.entries(r))e[t]=(n||[]).map(o=>o.uuid?o:{...o,uuid:Ni()});return e}c(Ki,"generateMissingUuids");function qi(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(qi,"buildIdToUuidLookup");function Bi(r,e=[]){const t=Object.values(r).reduce((n,o)=>n+(o?.length??0),0)+e.length;I.info(`\u25CF Pushed workspace elements \xB7 ${t}`);for(const n of Object.keys(r).sort()){const o=r[n];I.info(`\u2514\u2500\u2500 ${n}s \xB7 ${o?.length??0}`)}e.length>0&&I.info(`\u2514\u2500\u2500 connectors \xB7 ${e.length}`)}c(Bi,"showStats");async function Wi(r,e){const t=r[X.DELETE].size;I.info(`\u2299 Push: conflicts detected \xB7 ${t}`),await Pt(e,(n,o)=>{ae(n)&&r[X.DELETE].has(o.uuid)&&I.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted locally)`)})}c(Wi,"showConflicts");function Ji(r){I.error("\u25A0 Error"),I.error(`\u2514\u2500\u2500 ${r.message}`),I.error(` ${r.stack}`)}c(Ji,"showError");const Rt=[{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=E.join(process.cwd(),".mcp.json"),e={mcpServers:{membrane:{command:"membrane",args:["mcp"],env:{AGENT_NAME:"Claude Code"}}}};let t={};if(v.existsSync(r))try{t=JSON.parse(v.readFileSync(r,"utf8"))}catch{t={}}const n={...t,mcpServers:{...t.mcpServers,...e.mcpServers}};return v.writeFileSync(r,JSON.stringify(n,null,2)),`MCP server configuration added to ${r}`},"addConfig")},{id:"cursor",name:"Cursor",description:"Cursor AI editor",actionDescription:"Adding membrane MCP to .cursor/mcp.json in the current directory",addConfig:c(()=>{const r=E.join(process.cwd(),".cursor"),e=E.join(r,"mcp.json");v.existsSync(r)||v.mkdirSync(r);const t={mcpServers:{membrane:{command:"membrane",args:["mcp"],env:{AGENT_NAME:"Cursor"}}}};let n={};if(v.existsSync(e))try{n=JSON.parse(v.readFileSync(e,"utf8"))}catch{n={}}const o={...n,mcpServers:{...n.mcpServers,...t.mcpServers}};return v.writeFileSync(e,JSON.stringify(o,null,2)),`MCP server configuration added to ${e}`},"addConfig")}];function zi({onExit:r,onComplete:e}){const[t,n]=N(0),[o,i]=N(!1),[s,a]=N(null),[l,d]=N(""),[p,f]=N("");le((T,S)=>{if(l||p){(S.escape||T==="q"||S.return)&&e();return}if(o)S.return||T===" "?h(s):S.escape&&(i(!1),a(null));else if(S.escape)r();else if(S.upArrow||T==="k")n(Math.max(0,t-1));else if(S.downArrow||T==="j")n(Math.min(Rt.length-1,t+1));else if(S.return||T===" "){const D=Rt[t];a(D),i(!0)}});const h=c(T=>{try{const S=T.addConfig();d(S)}catch(S){f(`Failed to write configuration: ${S.message||S}`)}},"addMcpConfiguration"),C=Math.min(80,process.stdout.columns||80);return l?b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:C,children:[u(g,{marginTop:-1,marginBottom:1,children:b(y,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",u(y,{color:"green",children:"Success"})]})}),b(g,{flexDirection:"column",paddingLeft:2,children:[u(y,{color:"green",children:l}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"The agent will now be able to use Membrane's integration capabilities."})})]}),u(g,{marginTop:1,paddingLeft:2,children:u(y,{color:"white",children:"[esc/q/enter: exit]"})})]}):p?b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:C,children:[u(g,{marginTop:-1,marginBottom:1,children:b(y,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",u(y,{color:"red",children:"Error"})]})}),u(g,{flexDirection:"column",paddingLeft:2,children:u(y,{color:"red",children:p})}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"[esc/q/enter: exit]"})})]}):o&&s?b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:C,children:[u(g,{marginTop:-1,marginBottom:1,children:b(y,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",u(y,{color:"cyan",children:"Confirmation"})]})}),b(g,{flexDirection:"column",paddingLeft:2,children:[b(y,{children:["Connect ",u(y,{bold:!0,children:s.name})," to Membrane via MCP?"]}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"This will add an MCP server configuration that allows the agent to use Membrane's integration capabilities."})}),u(g,{marginTop:1,children:u(y,{color:"yellow",bold:!0,children:s.actionDescription})}),u(g,{marginTop:2,marginBottom:1,children:b(y,{children:[u(y,{color:"white",bold:!0,children:"[Enter] Confirm"})," ",u(y,{color:"gray",children:"[Esc] Cancel"})]})})]})]}):b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:C,children:[u(g,{marginTop:-1,marginBottom:1,children:b(y,{bold:!0,children:["\u{1F517} Connect Agent \u2014 ",u(y,{color:"cyan",children:"Select Agent"})]})}),b(g,{flexDirection:"column",paddingLeft:2,children:[u(y,{color:"grey",children:"Choose an agent to connect to Membrane via MCP:"}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"This will add an MCP server configuration that allows the agent to use Membrane's integration capabilities."})}),u(g,{marginTop:1,flexDirection:"column",children:Rt.map((T,S)=>b(g,{children:[b(y,{color:t===S?"cyan":"white",children:[t===S?"\u25B6 ":" ",T.name]}),b(y,{color:"grey",children:[" \u2014 ",T.description]})]},T.id))})]}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"[\u2191\u2193: select] [enter: choose] [esc: exit]"})})]})}c(zi,"AddMcpServerScreen");function Hi(){const[r,e]=N(null),[t,n]=N([]),[o,i]=N(null);return fe(()=>{const s=c(({status:l})=>{e(l),i(null)},"handleMcpStatusChanged"),a=c(({servers:l})=>{n(l),i(null)},"handleMcpServersChanged");return re.on(j.McpStatusChanged,s),re.on(j.McpServersChanged,a),()=>{re.off(j.McpStatusChanged,s),re.off(j.McpServersChanged,a)}},[]),{mcpStatus:r,allMcpServers:t,error:o,isRunning:r?.isRunning||!1,toolsCount:r?.toolsCount||0,totalRequests:r?.totalRequests||0,lastActivity:r?.lastActivity,processId:r?.processId,serverCount:t.length}}c(Hi,"useMcpStatus");function Gi(){const{error:r,serverCount:e,allMcpServers:t}=Hi(),n=Math.min(100,process.stdout.columns||100);return b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:n,children:[u(g,{marginTop:-1,marginBottom:0,flexDirection:"column",children:b(y,{bold:!0,children:["\u{1F916} Connected AI Agents:"," ",r?u(y,{color:"red",children:"error reading status"}):e===0?u(y,{color:"yellow",children:"none"}):u(y,{color:"green",children:e})]})}),!r&&e===0&&u(g,{marginTop:1,children:b(y,{color:"grey",children:["Connect your AI agents to Membrane.",u(ir,{}),"It will give them tools and context to build integrations."]})}),t.length>0&&u(g,{flexDirection:"column",paddingLeft:2,marginTop:1,children:t.map((o,i)=>u(g,{children:b(y,{color:"grey",children:["#",i+1," ",o.agentName,": ",o.totalRequests," calls"]})},o.processId))}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"[a: connect an agent]"})})]})}c(Gi,"Agent");const On=c(r=>{switch(r){case"error":return"red";case"success":return"green";case"warning":return"yellow";default:return}},"getLogColor");function Nn(r,e){return e<3?r.slice(0,Math.max(0,e)):r.length<=e?r:`${r.slice(0,e-3)}...`}c(Nn,"truncateText");function Vi({children:r}){const{state:e,logs:t}=G();return!e||e===P.NOT_INITIALIZED?b(g,{gap:1,flexDirection:"row",children:[u(xr,{type:"dots"}),u(y,{children:"Initializing..."})]}):e===P.SETTING_UP?u(g,{gap:1,flexDirection:"row",children:u(y,{children:"No workspace selected. Please run `membrane init` to select a workspace."})}):e===P.ERROR?u(g,{flexDirection:"column",children:t.slice().map((n,o)=>u(y,{color:On(n.type),children:n.message},n.timestamp+o))}):r}c(Vi,"EnsureInitialized");function Yi(){const{stats:r}=G(),e=Object.entries(r).filter(([t,n])=>n>0);return e.length===0?null:b(g,{flexDirection:"column",children:[u(g,{children:u(g,{width:12,children:u(y,{color:"grey",children:"Elements:"})})}),u(g,{flexDirection:"column",marginLeft:1,children:e.map(([t,n])=>b(g,{children:[u(g,{width:20,children:b(y,{children:[t,":"]})}),u(y,{color:"green",children:n})]},t))})]})}c(Yi,"ElementStats");const Dt=5,Zi=6;function Xi(){const{logs:r}=G(),[e,t]=N(0),n=Math.min(100,process.stdout.columns||100),o=Dt,i=Math.max(0,r.length-o-e),s=r.length-e,a=r.slice(i,s),l=n-Zi,d=e<r.length-o,p=e>0;return le((f,h)=>{if(r.length!==0)if(h.upArrow){const C=Math.max(0,r.length-o);t(T=>Math.min(C,T+1))}else h.downArrow?t(C=>Math.max(0,C-1)):(f==="G"||f==="g")&&t(0)}),b(g,{flexDirection:"column",paddingTop:1,children:[b(y,{color:"grey",children:["Recent Activity (",i+1,"-",s," of ",r.length,"):",r.length>Dt&&u(y,{color:"grey",children:" [arrows: scroll] [g: end]"})]}),a.map((f,h)=>u(g,{marginLeft:1,children:u(y,{color:On(f.type),children:Nn(f.message,l)})},f.timestamp+h)),r.length>Dt&&b(g,{marginLeft:1,flexDirection:"row",children:[d&&u(y,{color:"grey",children:"\u2191 "}),p&&u(y,{color:"grey",children:"\u2193 "})]})]})}c(Xi,"Logs");const je=[{value:"sync",label:"Continue (overwrite/delete)",key:""},{value:"exit",label:"Cancel",key:""}];function Qi(){const{state:r,resolveConflicts:e,exit:t}=G(),[n,o]=N(0),[i,s]=N(!1),[a,l]=N(!1);return le((d,p)=>{if(!i){if(p.ctrl&&d.toLowerCase()==="r"){l(!a);return}p.upArrow?o(f=>f>0?f-1:je.length-1):p.downArrow?o(f=>f<je.length-1?f+1:0):d.toLowerCase()==="y"?o(0):d.toLowerCase()==="n"?o(1):(p.return||d===" ")&&(s(!0),je[n].value==="sync"?e({watch:!0}):t())}}),fe(()=>{r!==P.CONFLICTS&&i&&s(!1)},[r,i]),b(g,{flexDirection:"column",paddingTop:1,children:[u(g,{children:u(g,{flexDirection:"row",gap:2,children:u(y,{bold:!0,color:"white",children:"Conflicts with remote"})})}),u(g,{children:u(y,{color:"grey",children:"The remote workspace has changes that aren't in your local workspace:"})}),u(g,{marginTop:1,marginLeft:2,children:u(ts,{isExpanded:a})}),b(g,{marginTop:2,flexDirection:"row",gap:1,children:[u(y,{color:"white",bold:!0,children:"What would you like to do?"}),u(y,{color:"grey",children:"[up/down, enter]"})]}),u(g,{children:i?b(g,{flexDirection:"row",gap:1,children:[u(Ae,{type:"dots"}),u(y,{color:"blue",bold:!0,children:"Syncing with remote..."})]}):u(g,{flexDirection:"column",children:je.map((d,p)=>u(g,{flexDirection:"column",children:b(g,{flexDirection:"row",gap:1,children:[u(y,{color:n===p?"cyan":"grey",children:n===p?"\u25B6":" "}),u(y,{color:n===p?"cyan":"grey",bold:n===p,children:d.label})]})},d.value))})})]})}c(Qi,"ResolveChangesUI");const es={[Q.UPDATE]:{incoming:{label:"Elements updated in remote",description:"(to be overwritten from remote)"},outgoing:{label:"Elements updated locally",description:"(to be pushed to remote)"}},[Q.DELETE]:{incoming:{label:"Elements not existing in remote",description:"(to be deleted locally)"},outgoing:{label:"Elements deleted locally",description:"(to be deleted from remote)"}},[Q.CREATE]:{incoming:{label:"Elements created in remote",description:"(to be created locally)"},outgoing:{label:"Elements created locally",description:"(to be created in remote)"}}};function ts({isExpanded:r,showControls:e=!0}){const{conflicts:t}=G(),n=5,o=or(()=>{const i={};return t.forEach(s=>{const a=`${s.type}-${s.direction}`;i[a]||(i[a]=[]),i[a].push(s)}),i},[t]);return u(g,{flexDirection:"column",children:Object.entries(o).map(([i,s])=>{if(s.length===0)return null;const[a,l]=i.split("-"),d=es[a][l];return b(g,{flexDirection:"column",children:[b(g,{flexDirection:"row",gap:1,children:[b(y,{color:"yellow",children:[d.label," (",s.length,")"]}),u(y,{color:"white",children:d.description})]}),(r?s:s.slice(0,n)).map(p=>u(g,{marginLeft:2,children:b(y,{color:"grey",children:["\u2022 ",p.element.id," (",p.element.relativePath,")"]})},p.element.id)),!r&&s.length>n&&u(g,{marginLeft:2,children:b(y,{color:"cyan",children:["... and ",s.length-n," more",e?" (press Ctrl+R to show all)":""]})}),r&&s.length>n&&e&&u(g,{marginLeft:2,children:u(y,{color:"cyan",children:"(press Ctrl+R to collapse)"})})]},i)})})}c(ts,"Conflicts");function ns(){const{config:r,state:e,logs:t,currentWorkspace:n,pull:o}=G(),i=n?.name,s=i?Nn(i,30):r?.workspaceKey,a=Math.min(100,process.stdout.columns||100);return fe(()=>{o({watch:!0})},[]),b(g,{flexDirection:"column",paddingX:1,borderStyle:"round",borderTop:!0,width:a,children:[u(g,{marginTop:-1,marginBottom:1,children:b(g,{flexDirection:"row",gap:1,children:[u(y,{bold:!0,children:"\u{1F504} Workspace"}),b(y,{color:os(e),children:[" [",rs(e),"] "]})]})}),b(g,{children:[u(g,{width:12,children:u(y,{color:"grey",children:"Local:"})}),u(y,{color:"grey",children:process.cwd()})]}),b(g,{children:[u(g,{width:12,children:u(y,{color:"grey",children:"Remote:"})}),r?.workspaceKey?b(y,{color:"grey",children:[s," [o: open in console] [w: change]"]}):b(y,{children:[u(y,{color:"yellow",children:"not selected"})," [w: select]"]})]}),e===P.CONFLICTS?u(Qi,{}):b($e,{children:[u(g,{paddingTop:1,children:u(Yi,{})}),t.length>0&&u(Xi,{})]})]})}c(ns,"Workspace");function rs(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(rs,"getStatusDisplay");function os(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(os,"getStatusColor");function is(){const r=Uo(),e=Ze(!0),{exit:t,state:n}=G(),[o,i]=N(null),s=o??(n===P.SETTING_UP?"setup":"main");le(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 tn(r),d=dt(`/w/${l}`),p=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";Ar(`${p} "${d}"`)}catch(l){console.error("Failed to open workspace:",l),t()}}return c(a,"handleOpenWorkspace"),fe(()=>(e.current=!0,()=>{e.current=!1}),[]),s==="workspace-selection"?u(gn,{onExit:c(()=>i(null),"onExit")}):s==="add-mcp-server"?u(zi,{onExit:c(()=>i(null),"onExit"),onComplete:c(()=>i(null),"onComplete")}):s==="setup"?u(yn,{onComplete:c(()=>i(null),"onComplete")},Date.now()):u(Vi,{children:b(g,{flexDirection:"column",children:[u(g,{flexGrow:1,children:u(Gi,{})}),u(ns,{}),u(g,{paddingLeft:2,children:u(y,{color:"grey",children:"[s: (re-)setup]"})})]})})}c(is,"Main");const ss=c(()=>[w.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"),w.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),w.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"),w.yellow("\u2502 Real-time agent mode is experimental and subject to changes. \u2502"),w.yellow("\u2502 Use in production environments is not recommended. \u2502"),w.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(`
|
|
28
|
+
`),"createExperimentalWarning$1");function as(r,e){r.command("sync").description("\u26A0\uFE0F EXPERIMENTAL: Sync workspace data in real-time - This feature is experimental and subject to changes. Use in production environments is not recommended.").option("--watch","Watch for changes and sync automatically",!1).option("--rps <number>","Maximum requests per second (default: 80)",t=>parseInt(t,10)).addHelpText("after",["","Examples:"," membrane sync --watch # Start real-time sync with watch mode"," membrane sync --watch --rps 5 # Limit to 5 requests per second",""].join(`
|
|
29
|
+
`)).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}):(m.error(`Invalid RPS value: ${n}. Must be between 1 and 1000.`),process.exit(1))}console.warn(ss()),Xe(ce.createElement(Tt,{cwd:process.cwd(),membraneCLIService:e,children:ce.createElement(is)}))})}c(as,"setupSyncCommand");class cs{static{c(this,"BaseRunner")}constructor(e={}){if(this.options=e,this.fsPaths=ht(),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 ls="claude-sonnet-4-20250514";class Lt{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=Se();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 jt({token:await this.createMembraneToken(o),apiUri:o.apiUri}),s=new Rr({apiKey:o.anthropicApiKey}),a={complete:c(async({prompt:l,maxTokens:d})=>{const p=await s.messages.create({model:ls,max_tokens:d,messages:[{role:"user",content:l}]});return p.content[0].type==="text"?p.content[0].text:""},"complete")};return new Lt({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(),it(t,n.getResult());this.writeResults(t)}async readYaml(e){const t=k.join(this.testsDir,this.testBasePath,this.connectionId,e);return ft(t)}async writeYaml(e,t){const n=k.join(this.testsDir,this.testBasePath,this.connectionId,e);A.mkdirSync(k.dirname(n),{recursive:!0}),A.writeFileSync(n,H.dump(t,{noRefs:!0}))}writeResults(e){const t=k.join(this.testsDir,this.testBasePath,this.connectionId);A.mkdirSync(t,{recursive:!0});const n=k.join(t,"test-results.yaml");A.writeFileSync(n,H.dump(e,{noRefs:!0})),console.debug(`[TestRunner] Results written to: ${n}`)}static async createMembraneToken(e){const t=e.testCustomerId||"test-customer",n={id:t,name:t},o={issuer:e.workspaceKey,expiresIn:7200,algorithm:"HS512"};return tt.sign(n,e.workspaceSecret,o)}}Or.interpolate=/{{([\s\S]+?)}}/g;function Ot(r,e){if(typeof r=="string"){const t=Dr(r),n={state:e,random:{number:c(()=>Ce.number.int(),"number"),alphaNumeric:c(i=>Ce.string.alphanumeric(i),"alphaNumeric")},faker:{company:{name:c(()=>Ce.company.name(),"name"),catchPhrase:c(()=>Ce.company.catchPhrase(),"catchPhrase")},internet:{email:c(()=>Ce.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=>Ot(t,e)):typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).map(([t,n])=>[t,Ot(n,e)])):r}c(Ot,"processNode");function us(r,e){return Ot(r,e)}c(us,"handleTemplate");class ds{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(`${w.bold.cyan("[start]")} ${w.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(`${w.bold.yellow("[initialized]")} ${w.yellow(e.path)}`)),s=us(i,this.environment.state),await e.run(s),console.debug(`${w.bold.green("[success]")} ${w.yellow(e.path)}`),t=!0,o=e.getResult(),We(this.result,e.path,o)}catch(l){if(console.error(`${w.bold.red("[error]")} ${w.yellow(e.path)}: ${l}`),this.environment.options.fix&&!n){n=!0;try{await e.fix(l);continue}catch(d){console.error(`${w.bold.red("[fix fail]")} ${w.yellow(e.path)}: ${d}`)}}We(this.result,e.path,{error:z(l)}),t=!0,o={error:z(l)}}const a={...s,result:o};await this.environment.writeYaml(e.getTestCasePath(),a)}async runTestSuite(e){await e.run(),it(this.result,e.getResult())}}class se{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(w.bold.yellow("[auto-fix]"),this.path),await this.environment.writeYaml(this.getTestCasePath(),n)}async readTestCase(){const e=this.getTestCasePath();return this.environment.readYaml(e)}async generateConfig(){return{}}async fixTestCase(e){throw new Error(`Auto-fix is not implemented for test ${this.path}`)}getResult(){return{logs:this.logs,assertions:this.assertions}}async assert(e,t,n){try{const o=await e();o?(this.logMsg(`\u2705 ${t}`),this.assertions.push({message:t,result:o})):(this.logMsg(`\u274C ${t}`),this.assertions.push({message:t,result:!1,details:n}))}catch(o){this.assertions.push({message:t,result:!1,details:z(o)}),this.logMsg(`\u274C ${t}: ${o.message}`)}}logMsg(e){console.debug(`${" ".repeat(this.level*2)}${e}`)}getTestCasePath(){return`${this.path}.test.yml`}}function Nt(r,e){const t={};for(const n in e){if(!(n in r)){t[n]=e[n];continue}const o=r[n],i=e[n];if(o&&i&&typeof o=="object"&&typeof i=="object"){if(Array.isArray(o)&&Array.isArray(i)){const s=i.filter(a=>!o.some(l=>{if(typeof l=="object"&&typeof a=="object"&&l!==null&&a!==null&&!Array.isArray(l)&&!Array.isArray(a)){for(const d in a)if(!(d in l)||!Mt(l[d],a[d]))return!1;return!0}else return JSON.stringify(l)===JSON.stringify(a)}));s.length>0&&(t[n]=s)}else if(!Array.isArray(o)&&!Array.isArray(i)){const s=Nt(o,i);s!==null&&(t[n]=s)}else t[n]=i;continue}Mt(o,i)||(t[n]=i)}return Object.keys(t).length===0?null:t}c(Nt,"getNotMatchingSubFields");function Mt(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(Mt,"softCompare");class hs extends se{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=Je(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=_t(n),a=Ie(e.input.fields,s,{skipUnknownFields:!0}),l=Ie(i.record.fields,s),d=Nt(l,a);await this.assert(()=>!d,"Returned fields match created fields",{difference:d,sentFields:a,receivedFields:l})}const o=Qn(n??{});if(o.length>0){const i={};o.forEach(a=>{const l=er(e.input.fields,a);typeof l<"u"&&We(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=Je(this.dataCollection);if(!e?.properties)throw new Error("No fields schema found for data collection");return{input:{fields:await this.generateFieldsWithLLM(e)}}}async fixTestCase({config:e,error:t}){const n=z(t),o=Je(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:
|
|
22
30
|
|
|
23
31
|
${JSON.stringify(o,null,2)}
|
|
24
32
|
|
|
@@ -42,7 +50,7 @@ Format your response as a JSON object with two fields:
|
|
|
42
50
|
"fields": { ... fixed fields ... }
|
|
43
51
|
}.
|
|
44
52
|
|
|
45
|
-
Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,a=await this.environment.llm.complete({prompt:s,maxTokens:1e4}),l=JSON.parse(a.trim());return console.warn(
|
|
53
|
+
Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,a=await this.environment.llm.complete({prompt:s,maxTokens:1e4}),l=JSON.parse(a.trim());return console.warn(w.bold.yellow("[auto-fix]"),`${this.path}:`,l.explanation),{input:{fields:l.fields}}}async generateFieldsWithLLM(e){const t=await this.getExampleRecordsForSchema(e),n=`Generate a valid JSON object that matches this JSONSchema. Return only the JSON object, no other text.
|
|
46
54
|
|
|
47
55
|
${this.getExampleRecordsPrompt(t)}
|
|
48
56
|
|
|
@@ -58,7 +66,7 @@ ${JSON.stringify(o,null,2)}`).join(`
|
|
|
58
66
|
|
|
59
67
|
`)}.
|
|
60
68
|
|
|
61
|
-
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
|
|
69
|
+
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 Kt(e,o=>{if(o.referenceCollection){const i=o.referenceCollection.key,s=o.referenceCollection.parameters,a=`${i}:${JSON.stringify(s||{})}`;t.has(a)||(t.add(a),n.push({key:i,parameters:s}))}return o}),n}async fetchExampleRecords(e){return(await this.environment.client.connection(this.environment.connectionId).dataCollection(e.key).list({parameters:e.parameters})).records.map(n=>({id:n.id,fields:n.fields??{}}))}async getExampleRecordsForSchema(e){const t=await this.findReferenceCollections(e),n={};for(const o of t){const i=qt(o);n[i]=await this.fetchExampleRecords(o)}return n}}class ps extends se{static{c(this,"DataCollectionDeleteTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/delete`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=this.environment.state[this.dataCollectionKey]?.createdRecordId||e?.input?.id;if(!t)throw new Error(`No ID found in state or config for ${this.dataCollectionKey} delete`);if(await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).delete({id:t}),this.dataCollection.findById)try{await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).findById({id:t})}catch(n){if(n?.data?.data?.response?.status===404){await this.assert(()=>!0,"Record is not found after deletion");return}throw n}else await this.assert(()=>!0,"No findById capability, skipping verification")}async generateConfig(){let e=this.environment.state[this.dataCollectionKey]?.createdRecordId;if(!e){if(!this.dataCollection.list)throw new Error(`Can't find a record to test delete operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!t?.records?.length)throw new Error(`No records found to test delete for ${this.dataCollectionKey}`);e=t.records[0].id}return{input:{id:e}}}async fixTestCase({config:e,error:t}){const n=z(t),o=`I'm trying to delete a record from a data collection.
|
|
62
70
|
|
|
63
71
|
I tried to delete a record with this ID:
|
|
64
72
|
|
|
@@ -78,7 +86,7 @@ Format your response as a JSON object with two fields:
|
|
|
78
86
|
"id": "fixed id"
|
|
79
87
|
}.
|
|
80
88
|
|
|
81
|
-
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(
|
|
89
|
+
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class fs extends se{static{c(this,"DataCollectionFindByIdTester")}dataCollectionKey;dataCollection;constructor({environment:e,dataCollectionKey:t,dataCollection:n}){super({environment:e,path:`data/${t}/find-by-id`}),this.dataCollectionKey=t,this.dataCollection=n}async run(e){const t=this.environment.state[this.dataCollectionKey]?.createdRecordId||e?.input?.id;if(!t)throw new Error(`No ID found in state or config for ${this.dataCollectionKey} find-by-id`);const n=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).findById({id:t});await this.assert(()=>!!n.record,"Record is returned from findById"),await this.assert(()=>n.record.id===t,"Returned record ID matches requested ID")}async generateConfig(){let e=this.environment.state[this.dataCollectionKey]?.createdRecordId;if(!e){if(!this.dataCollection.list)throw new Error(`Can't find a record to test findById operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!t?.records?.length)throw new Error(`No records found to test findById for ${this.dataCollectionKey}`);e=t.records[0].id}return{input:{id:e}}}async fixTestCase({config:e,error:t}){const n=z(t),o=`I'm trying to find a record by ID in a data collection.
|
|
82
90
|
|
|
83
91
|
I tried to find a record with this ID:
|
|
84
92
|
|
|
@@ -98,7 +106,7 @@ Format your response as a JSON object with two fields:
|
|
|
98
106
|
"id": "fixed id"
|
|
99
107
|
}.
|
|
100
108
|
|
|
101
|
-
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(
|
|
109
|
+
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class ms extends se{static{c(this,"DataCollectionListTester")}dataCollectionKey;constructor({environment:e,dataCollectionKey:t}){super({environment:e,path:`data/${t}/list`}),this.dataCollectionKey=t}async run(e){const t=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list(e.input);if(await this.assert(()=>Array.isArray(t.records),"Response has records field as array"),e.input.sort){const{field:n,direction:o}=e.input.sort,i=t.records;if(i.length>1)for(let s=1;s<i.length;s++){const a=i[s-1].fields?.[n],l=i[s].fields?.[n];a==null||l==null||(o==="asc"?await this.assert(()=>a<=l,`Records are sorted by ${n} in ascending order`):await this.assert(()=>a>=l,`Records are sorted by ${n} in descending order`))}}}async generateConfig(){return{input:{}}}async fixTestCase({config:e,error:t}){const n=z(t),o=`I'm trying to list records from a data collection.
|
|
102
110
|
|
|
103
111
|
I tried to list records with these parameters:
|
|
104
112
|
|
|
@@ -118,7 +126,7 @@ Format your response as a JSON object with two fields:
|
|
|
118
126
|
"input": { ... fixed parameters ... }
|
|
119
127
|
}.
|
|
120
128
|
|
|
121
|
-
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(
|
|
129
|
+
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input}}}class gs extends se{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(()=>Mt(l,a),`Record field ${s} matches input value - expected ${JSON.stringify(a)} got ${JSON.stringify(l)}`)}}async generateConfig(){if(!this.dataCollection.list)throw new Error(`Can't find a record to test match operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const e=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!e?.records?.length)throw new Error("No records found to test match");const t=e.records[0];if(!t?.fields)throw new Error("First record has no fields to match against");const n={},o=t.fields||{},i=Object.entries(o).filter(([s,a])=>s!=="links"&&a!=null&&a!=="").slice(0,1);if(i.length===0)throw new Error("No usable fields found in record for matching");for(const[s,a]of i)n[s]=a;return{input:{query:n}}}async fixTestCase({config:e,error:t}){const n=z(t),o=`I'm trying to match a record in a data collection.
|
|
122
130
|
|
|
123
131
|
I tried to match a record with this query:
|
|
124
132
|
|
|
@@ -138,12 +146,12 @@ Format your response as a JSON object with two fields:
|
|
|
138
146
|
"query": { ... fixed query ... }
|
|
139
147
|
}.
|
|
140
148
|
|
|
141
|
-
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(
|
|
149
|
+
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{query:s.query}}}}class ys extends se{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(w.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.
|
|
142
150
|
|
|
143
151
|
Record fields:
|
|
144
152
|
${JSON.stringify(e,null,2)}
|
|
145
153
|
|
|
146
|
-
Field value:`;try{return(await this.environment.llm.complete({prompt:t,maxTokens:1e3})).trim()||null}catch{return null}}async fixTestCase({config:e,error:t}){const n=
|
|
154
|
+
Field value:`;try{return(await this.environment.llm.complete({prompt:t,maxTokens:1e3})).trim()||null}catch{return null}}async fixTestCase({config:e,error:t}){const n=z(t),o=`I'm trying to search records in a data collection.
|
|
147
155
|
|
|
148
156
|
I tried to search records with these parameters:
|
|
149
157
|
|
|
@@ -163,7 +171,7 @@ Format your response as a JSON object with two fields:
|
|
|
163
171
|
"input": { ... fixed parameters ... }
|
|
164
172
|
}.
|
|
165
173
|
|
|
166
|
-
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(
|
|
174
|
+
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input,expectedRecordId:e.expectedRecordId}}}class ws extends se{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 Cs extends se{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=ze(this.dataCollection),s=_t(i),a=Ie(e.input.fields,s,{skipUnknownFields:!0}),l=Ie(o.record.fields,s),d=Nt(l,a);await this.assert(()=>!d,"Returned fields match updated fields",{difference:d,sentFields:a,receivedFields:l})}}async generateConfig(){let e=this.environment.state[this.dataCollectionKey]?.createdRecordId;if(!e){if(!this.dataCollection.list)throw new Error(`Can't find a record to test update operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const o=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!o?.records?.length)throw new Error(`No records found to test update for ${this.dataCollectionKey}`);e=o.records[0].id}const t=ze(this.dataCollection);if(!t?.properties)throw new Error("No fields schema found for data collection");const n=await this.generateFieldsWithLLM(t);return{input:{id:e,fields:n}}}async fixTestCase({config:e,error:t}){const n=z(t),o=ze(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:
|
|
167
175
|
|
|
168
176
|
${JSON.stringify(o,null,2)}
|
|
169
177
|
|
|
@@ -187,7 +195,7 @@ Format your response as a JSON object with two fields:
|
|
|
187
195
|
"fields": { ... fixed fields ... }
|
|
188
196
|
}.
|
|
189
197
|
|
|
190
|
-
Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,a=await this.environment.llm.complete({prompt:s,maxTokens:1e4}),l=JSON.parse(a.trim());return console.warn(
|
|
198
|
+
Only return the JSON object, no other text or wrapping (like \`\`\`json or \`\`\`).`,a=await this.environment.llm.complete({prompt:s,maxTokens:1e4}),l=JSON.parse(a.trim());return console.warn(w.bold.yellow("[auto-fix]"),`${this.path}:`,l.explanation),{input:{id:e.input.id,fields:l.fields}}}async generateFieldsWithLLM(e){const t=await this.getExampleRecordsForSchema(e),n=`Generate a valid JSON object that matches this JSONSchema. Return only the JSON object, no other text.
|
|
191
199
|
|
|
192
200
|
${this.getExampleRecordsPrompt(t)}
|
|
193
201
|
|
|
@@ -203,9 +211,9 @@ ${JSON.stringify(o,null,2)}`).join(`
|
|
|
203
211
|
|
|
204
212
|
`)}.
|
|
205
213
|
|
|
206
|
-
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
|
|
207
|
-
`),"createExperimentalWarning");function
|
|
208
|
-
`)).action(async(t,n)=>{try{console.warn(
|
|
209
|
-
${
|
|
214
|
+
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 Kt(e,o=>{if(o.referenceCollection){const i=o.referenceCollection.key,s=o.referenceCollection.parameters,a=`${i}:${JSON.stringify(s||{})}`;t.has(a)||(t.add(a),n.push({key:i,parameters:s}))}return o}),n}async fetchExampleRecords(e){return(await this.environment.client.connection(this.environment.connectionId).dataCollection(e.key).list({parameters:e.parameters})).records.map(n=>({id:n.id,fields:n.fields||{}}))}async getExampleRecordsForSchema(e){const t=await this.findReferenceCollections(e),n={};for(const o of t){const i=qt(o);n[i]=await this.fetchExampleRecords(o)}return n}}const Ft={spec:{testerClass:ws},create:{testerClass:hs,operationKey:"create"},"find-by-id":{testerClass:fs,operationKey:"findById"},list:{testerClass:ms,operationKey:"list"},match:{testerClass:gs,operationKey:"match"},search:{testerClass:ys,operationKey:"search"},update:{testerClass:Cs,operationKey:"update"},delete:{testerClass:ps,operationKey:"delete"}};class Ss extends ds{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);I.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=Ft[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(Ft).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(Ft).filter(([,t])=>{const n="operationKey"in t?t.operationKey:void 0;return this.isOperationAvailable(e,n)}).map(([t])=>t)}displayTestSummary(e){I.info(`\u{1F4CA} ${e} test${e===1?"":"s"} executed`)}}class bs extends cs{static{c(this,"TestRunner")}constructor(e){super(e)}async initialize(){I.debug("Initializing test runner",{prefix:"TestRunner"})}async run(){try{const{testPath:e,path:t,fix:n}=this.options,o=e.split("/");o.length<2&&(I.error("Invalid test path. Expected format: <type>/<name>[/additional/path][/method]"),process.exit(1));const[i,s,...a]=o;i!=="connectors"&&(I.error(`Test type "${i}" is not yet fully implemented. Currently only "connectors" is fully supported.`),I.error("Supported test types: connectors"),process.exit(1));const l=s,d=i,p=[...a,...t?t.split("/"):[]].join("/"),f=await Lt.create({connectionId:l,testBasePath:d,options:{fix:n}}),C=await f.client.get(`connections/${l}/data`),T=[],S=p?p.split("/"):[];if(S.length===0||S[0]==="data"){S[0]==="data"&&S.shift();let O,_;S.length>=1&&(_=S[0],S.length>=2&&S[1].trim()!==""&&(O=S[1]));for(const L of C){if(_&&_!==L.key)continue;const M=new Ss({environment:f,dataCollectionKey:L.key,testMethod:O});T.push(M)}}T.length===0&&(I.error(`No test suites found for path: ${e}${p?"/"+p:""}`),process.exit(1));const D={};for(const O of T){await O.run();const _=O.getResult();I.debug(`Suite ${O.constructor.name} result:`,{prefix:"TestRunner"}),it(D,_)}console.debug("[TestRunner] All results collected:",Object.keys(D)),f.writeResults(D)}catch(e){throw console.error("Error in TestRunner.run():",e),e}}}const Ue=c(()=>[w.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"),w.yellow("\u2502 \u26A0\uFE0F EXPERIMENTAL FEATURE WARNING \u2502"),w.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"),w.yellow("\u2502 The test command is experimental and subject to rapid changes. \u2502"),w.yellow("\u2502 Features, APIs, and file structures may change without notice. \u2502"),w.yellow("\u2502 Use in production environments is not recommended. \u2502"),w.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(`
|
|
215
|
+
`),"createExperimentalWarning");function vs(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",Ue()).action(async()=>{console.warn(Ue()),I.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",["",w.bold("Examples:"),` ${w.gray("\u25B8")} ${w.cyan("membrane test run connectors/netsuite")} # Test all data collections for netsuite connector`,` ${w.gray("\u25B8")} ${w.cyan("membrane test run connectors/netsuite/data/contacts")} # Test specific data collection`,` ${w.gray("\u25B8")} ${w.cyan("membrane test run connectors/netsuite/data/contacts/create")} # Test specific method for data collection`,` ${w.gray("\u25B8")} ${w.cyan("membrane test run connectors/netsuite/data/contacts/delete")} # Test delete method for data collection`,` ${w.gray("\u25B8")} ${w.cyan("membrane test run actions/create-contact")} # Test specific action`,` ${w.gray("\u25B8")} ${w.cyan("membrane test run connectors/hubspot/events")} # Test events for hubspot`,` ${w.gray("\u25B8")} ${w.cyan("membrane test run connectors/salesforce --fix")} # Run tests with auto-fix enabled`,"",w.gray("For more information, visit:"),w.blue(" https://docs.getmembrane.com/docs/development-environment"),"",Ue()].join(`
|
|
216
|
+
`)).action(async(t,n)=>{try{console.warn(Ue()),t||(I.error("Test path is required"),process.exit(1)),I.header(`Testing: ${t}`);const o=new bs({testPath:t,path:n.path,fix:n.fix});await o.initialize(),await o.run(),I.success("Tests completed")}catch(o){o instanceof Error&&(I.error(o.message),process.exit(1)),I.error("An unknown error occurred"),process.exit(1)}})}c(vs,"setupTestCommand");const Es=c(()=>{try{const r=qn(import.meta.url),e=_n(r),t=_e(e,"..","package.json");return JSON.parse(Un(t,"utf-8")).version}catch{return"1.0.0"}},"getPackageVersion"),Mn=Es();function Ts(){process.on("SIGINT",()=>process.exit(130));const r=new Bn().name("membrane").description("Command-line interface for Membrane Agent").version(Mn,"-v, --version","Output the version number").option("--verbose","Enable verbose logging (shows debug messages)");r.configureHelp({sortSubcommands:!0,subcommandTerm:c(n=>w.cyan(n.name()),"subcommandTerm"),commandUsage:c(n=>n.name()==="membrane"?`${w.cyan(n.name())} ${w.gray("[options]")} ${w.cyan("[command]")}`:n.usage(),"commandUsage"),optionTerm:c(n=>{const o=n.flags;return`${w.gray("\u25B8")} ${w.cyan(o)}`},"optionTerm"),subcommandDescription:c(n=>w.gray(n.description()),"subcommandDescription"),optionDescription:c(n=>w.gray(n.description),"optionDescription"),commandDescription:c(n=>w.gray(n.description()),"commandDescription")}),r.addHelpText("beforeAll",`
|
|
217
|
+
${w.bold.cyan("Membrane Agent CLI")} ${w.gray(`v${Mn}`)}
|
|
210
218
|
|
|
211
|
-
`);const e=new
|
|
219
|
+
`);const e=new Ao(Le.Cli,process.cwd());Yo(r),si(r),bi(r),Mi(r),pi(r),vs(r),hi(r),as(r,e),Wo(r,e),_r(r,e),_o(r,e),process.argv.length===2&&(r.outputHelp(),process.exit(0)),r.parse(),r.opts().verbose&&m.setVerboseMode(!0)}c(Ts,"runCLI"),Ts();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@membranehq/cli",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.11",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@buildwithlayer/openapi-to-tools": "^1.3.3",
|
|
31
31
|
"@faker-js/faker": "^9.8.0",
|
|
32
32
|
"@inkjs/ui": "^2.0.0",
|
|
33
|
-
"@membranehq/sdk": "^0.17.
|
|
33
|
+
"@membranehq/sdk": "^0.17.1",
|
|
34
34
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
35
35
|
"@types/js-yaml": "^4.0.9",
|
|
36
36
|
"@types/jsonwebtoken": "^9.0.10",
|