@membranehq/cli 1.4.3 → 1.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +28 -28
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -1,24 +1,24 @@
1
1
  #!/usr/bin/env node
2
- var vn=Object.defineProperty;var c=(r,e)=>vn(r,"name",{value:e,configurable:!0});import*as v from"node:fs";import{mkdirSync as En,writeFileSync as Tn,readFileSync as xn}from"node:fs";import*as x from"node:path";import{join as Oe,dirname as In}from"node:path";import{fileURLToPath as $n}from"node:url";import w from"chalk";import{Command as kn}from"commander";import{WorkspaceElementType as T,MembraneConfigLoader as Rn,MembraneAxiosInstance as Pn,MembraneClient as vt,extractMembraneErrorData as J,WorkspaceElementSpecs as V,WorkspaceSyncEventType as An,ConnectorFileUpdateType as Ne,NotFoundError as Dn,getMembraneElementPath as On,parseMembraneElementPath as ie,CONNECTOR_VERSION_DEVELOPMENT as Et,compareWorkspaceExports as Nn,WorkspaceElementChangeType as Y,setValueAtLocator as Me,getDataCollectionCreateFields as Fe,excludeWriteOnlyFieldsFromSchema as Tt,valueToSchema as ve,getRequiredFieldsFromSchema as Mn,getValueAtLocator as Fn,walkSchema as xt,makeDataLocationPath as It,getDataCollectionUpdateFields as Le}from"@membranehq/sdk";import je from"lodash/camelCase.js";import Ue from"lodash/upperFirst.js";import Ln from"code-block-writer";import jn from"lodash/uniqBy.js";import se,{createContext as Ke,useState as D,useEffect as he,useContext as qe,useId as Un,useRef as Be,useLayoutEffect as Ee,useMemo as Kn}from"react";import{Box as g,Text as y,useInput as ae,render as _e,Newline as qn}from"ink";import{jsx as u,jsxs as b,Fragment as Te}from"react/jsx-runtime";import $t from"swr/immutable";import kt from"os";import R from"path";import Bn from"conf";import ge,{isAxiosError as _n}from"axios";import We from"jsonwebtoken";import{AsyncLocalStorage as Wn}from"async_hooks";import{toSentenceCase as Jn}from"js-convert-case";import Gn from"lodash/isEqual.js";import G from"js-yaml";import*as Hn from"node:crypto";import{createHash as zn}from"node:crypto";import Vn from"chokidar";import Yn from"yaml";import{EventEmitter as Zn}from"events";import{EventSource as Xn}from"eventsource";import P from"fs";import Rt from"archiver";import Pt from"form-data";import At from"unzipper";import*as Qn from"node:os";import"node:events";import Dt from"ink-text-input";import{SWRConfig as er}from"swr";import xe from"ink-spinner";import{TextInput as tr,Select as nr,Spinner as rr}from"@inkjs/ui";import{FastMCP as or}from"fastmcp";import{z as A}from"zod";import Ot from"ora";import Nt from"jszip";import{minimatch as ir}from"minimatch";import{exec as sr}from"node:child_process";import Je from"lodash/merge.js";import ar from"@anthropic-ai/sdk";import{faker as ye}from"@faker-js/faker";import cr from"lodash/template.js";import lr from"lodash/templateSettings.js";function ce(r){if(r.type){if(Array.isArray(r.type))return{anyOf:r.type.map(t=>ce({...r,type:t}))};if(r.type==="array"){const t={type:"array",items:r.items?ce(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]=ce(n)}return r.anyOf&&(e.anyOf=r.anyOf.map(ce)),r.additionalProperties!==void 0&&(typeof r.additionalProperties=="boolean"?e.additionalProperties=r.additionalProperties:e.additionalProperties=ce(r.additionalProperties)),r.required&&(e.required=r.required),e}c(ce,"convertDataSchemaToOpenAPI");function ur(r){const{membraneInterfaces:{actions:e}}=r,t=dr(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(ur,"generateOpenAPIContent");function dr(r){const e={};return r.forEach(t=>{const n=Ue(je(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=ce(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=ce(s);i.properties={...i.properties,data:a}}e[`${n}Response`]=i}),e}c(dr,"generateOpenAPISchemas");function hr(r){const{membraneInterfaces:{actions:e}}=r,t=jn(e,"key"),n=new Ln({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(),pr(n,t),n.toString()}c(hr,"generateTypeScriptContent");function pr(r,e){r.writeLine('declare module "@membranehq/sdk" {'),r.indent(()=>{e.forEach(t=>{const n=He(t),o=t?.inputSchema;Ie(r,{interfaceName:n,properties:o?.properties,required:o?.required||[]});const i=ze(t),s=t?.customOutputSchema||t?.outputSchema;Ie(r,{interfaceName:i,properties:s?.properties,required:s?.required||[],fallbackContent:"result: unknown"}),r.newLine()}),Ie(r,{interfaceName:"MembraneClient",methods:e.map(t=>{const n=He(t),o=ze(t);return{name:"action",parameters:`selector: "${t.key}"`,returnType:`ActionAccessor<${n}, ${o}>`}})}),r.newLine(),Ie(r,{interfaceName:"ConnectionAccessor",methods:e.map(t=>{const n=He(t),o=ze(t);return{name:"action",parameters:`selector: "${t.key}"`,returnType:`ConnectionLevelActionAccessor<${n}, ${o}>`}})})}),r.writeLine("}")}c(pr,"generateModuleAugmentation");function Ie(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&&fr(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(Ie,"generateTypeScriptInterface");function fr(r,e,t){Object.entries(e).forEach(([n,o])=>{const s=t.includes(n)?"":"?",a=Ge(o);r.writeLine(`readonly ${n}${s}: ${a}`)})}c(fr,"generateTypeScriptProperties");function Ge(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?Ge(r.items):"unknown"}[]`:r.type==="object"?r.properties?`{ ${Object.entries(r.properties).map(([t,n])=>{const i=(r.required||[]).includes(t)?"":"?",s=Ge(n);return`readonly ${t}${i}: ${s}`}).join("; ")} }`:"Record<string, unknown>":"unknown"}c(Ge,"convertJsonSchemaToTypeScript");function He(r){return`${Ue(je(r.key))}Input`}c(He,"getInputTypeName");function ze(r){return`${Ue(je(r.key))}Output`}c(ze,"getOutputTypeName");async function Ve(r){const{out:e}=r;await v.promises.mkdir(e,{recursive:!0});const t=mr(r);for(const[n,o]of Object.entries(t)){const i=x.join(e,n);await v.promises.writeFile(i,o,"utf-8")}}c(Ve,"generateCode");function mr(r){switch(r.target){case"openapi":return{"openapi.json":ur(r)};case"typescript":return{"generated.d.ts":hr(r)};default:throw new Error(`Unsupported target: ${r.target}`)}}c(mr,"generateContent");const Ye=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 gr(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",Ye()).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")}`,"",Ye()].join(`
5
- `)).action(async t=>{try{console.warn(Ye()),console.error(w.cyan("\u{1F527} Membrane Codegen")),console.error("Status: Loading membrane interfaces...");const n=await yr(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 Ve(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(gr,"setupCodegenCommand");async function yr(r,e){return await r.fetchElements(),{actions:[...r.getSyncedElementsByType(T.Action).map(t=>t.data)].filter(t=>e.actions.includes(t.key||""))}}c(yr,"loadMembraneInterfaces");const wr="membrane",Cr="membrane.config.yml",Ze="https://api.integration.app",Sr="https://console.integration.app";function Xe(){const r=process.cwd(),e=x.join(r,wr),t=x.join(r,Cr),n=e,o=x.join(n,"workspace.yaml");return{membraneDirPath:e,configPath:t,payloadDirPath:n,workspaceDataFilePath:o}}c(Xe,"getPaths");function Mt(){return Xe().membraneDirPath}c(Mt,"getBasePath");const br={pat:{type:"string"},workspace:{type:"object"}},Ft=new Bn({schema:br,configName:"config",cwd:R.join(kt.homedir(),".membrane")}),vr=c(r=>{Ft.set("pat",r)},"setPat"),Lt=c(()=>Ft.get("pat"),"getPat");class jt{static{c(this,"AccountApiClient")}constructor(e=Ze){this.apiBaseUrl=e}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=Lt();if(!s)throw new Error("Personal Access Token not found.");n.set("Authorization",`Bearer ${s}`)}t.body&&!n.has("Content-Type")&&n.set("Content-Type","application/json");const 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"})}}const Er=c(r=>{const e=new jt(Ze);return t=>e.get(t)},"createAccountApiFetcher");class me{static{c(this,"ConfigLoader")}static instance=null;sdkLoader;constructor(){this.sdkLoader=new Rn}static getInstance(){return me.instance||(me.instance=new me),me.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 le=me.getInstance();function $e(r){return le.loadConfig(r)}c($e,"readProjectConfig");const Tr="membrane",xr=["**/node_modules/**","**/.git/**","**/.DS_Store","**/Thumbs.db","**/*.tmp","**/*.swp","**/*.swo","**/*.log","**/*.lock","**/.cache/**","**/.next/**","**/.vscode/**","**/.idea/**","**/.logs/**"];function _(r){return x.join(r,Tr)}c(_,"getMembraneDir");const Ut=Oe(_(process.cwd()),".logs");class Ir{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`;En(Ut,{recursive:!0});const i=Oe(Ut,o),s=this._logs.map(a=>`[${a.timestamp}] ${a.type?.toUpperCase()||"INFO"}: ${a.message}`).join(`
6
- `);return Tn(i,s,"utf-8"),i}catch(t){return console.error("Failed to save logs:",t),null}}}const m=new Ir,Kt=new Wn;class qt{static{c(this,"RequestLogger")}constructor(e=Pn){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=Kt.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 Kt.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 $r(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($r,"createTrackedClient");class kr{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 qt,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=$r(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(J(s),null,2))):_n(s)?(console.error(`
2
+ var xn=Object.defineProperty;var c=(r,e)=>xn(r,"name",{value:e,configurable:!0});import*as v from"node:fs";import{mkdirSync as In,writeFileSync as $n,readFileSync as kn}from"node:fs";import*as x from"node:path";import{join as Me,dirname as Rn}from"node:path";import{URL as Pn,fileURLToPath as An}from"node:url";import w from"chalk";import{Command as Dn}from"commander";import{WorkspaceElementType as T,MembraneConfigLoader as On,MembraneAxiosInstance as Nn,MembraneClient as xt,extractMembraneErrorData as J,WorkspaceElementSpecs as V,WorkspaceSyncEventType as Mn,ConnectorFileUpdateType as Fe,CONSOLE_ACCOUNT_API_TOKEN_PATH as Fn,NotFoundError as Ln,getMembraneElementPath as jn,parseMembraneElementPath as ie,CONNECTOR_VERSION_DEVELOPMENT as It,compareWorkspaceExports as Un,WorkspaceElementChangeType as Y,setValueAtLocator as Le,getDataCollectionCreateFields as je,excludeWriteOnlyFieldsFromSchema as $t,valueToSchema as xe,getRequiredFieldsFromSchema as Kn,getValueAtLocator as qn,walkSchema as kt,makeDataLocationPath as Rt,getDataCollectionUpdateFields as Ue}from"@membranehq/sdk";import Ke from"lodash/camelCase.js";import qe from"lodash/upperFirst.js";import Bn from"code-block-writer";import _n from"lodash/uniqBy.js";import se,{createContext as Be,useState as D,useEffect as he,useContext as _e,useId as Wn,useRef as We,useLayoutEffect as Ie,useMemo as Jn}from"react";import{Box as g,Text as y,useInput as ae,render as Je,Newline as Gn}from"ink";import{jsx as u,jsxs as b,Fragment as $e}from"react/jsx-runtime";import Pt from"swr/immutable";import At from"os";import I from"path";import Hn from"conf";import ge,{isAxiosError as zn}from"axios";import Ge from"jsonwebtoken";import{AsyncLocalStorage as Vn}from"async_hooks";import{toSentenceCase as Yn}from"js-convert-case";import Zn from"lodash/isEqual.js";import G from"js-yaml";import*as Xn from"node:crypto";import{createHash as Qn}from"node:crypto";import er from"chokidar";import tr from"yaml";import{EventEmitter as nr}from"events";import{EventSource as rr}from"eventsource";import P from"fs";import Dt from"archiver";import Ot from"form-data";import ke from"unzipper";import*as or from"node:os";import"node:events";import Nt from"ink-text-input";import{SWRConfig as ir}from"swr";import Re from"ink-spinner";import{TextInput as sr,Select as ar,Spinner as cr}from"@inkjs/ui";import{FastMCP as lr}from"fastmcp";import{z as A}from"zod";import Mt from"semver";import Ft from"ora";import Lt from"jszip";import{minimatch as ur}from"minimatch";import{exec as dr}from"node:child_process";import He from"lodash/merge.js";import hr from"@anthropic-ai/sdk";import{faker as ye}from"@faker-js/faker";import pr from"lodash/template.js";import fr from"lodash/templateSettings.js";function ce(r){if(r.type){if(Array.isArray(r.type))return{anyOf:r.type.map(t=>ce({...r,type:t}))};if(r.type==="array"){const t={type:"array",items:r.items?ce(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]=ce(n)}return r.anyOf&&(e.anyOf=r.anyOf.map(ce)),r.additionalProperties!==void 0&&(typeof r.additionalProperties=="boolean"?e.additionalProperties=r.additionalProperties:e.additionalProperties=ce(r.additionalProperties)),r.required&&(e.required=r.required),e}c(ce,"convertDataSchemaToOpenAPI");function mr(r){const{membraneInterfaces:{actions:e}}=r,t=gr(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(mr,"generateOpenAPIContent");function gr(r){const e={};return r.forEach(t=>{const n=qe(Ke(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=ce(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=ce(s);i.properties={...i.properties,data:a}}e[`${n}Response`]=i}),e}c(gr,"generateOpenAPISchemas");function yr(r){const{membraneInterfaces:{actions:e}}=r,t=_n(e,"key"),n=new Bn({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(),wr(n,t),n.toString()}c(yr,"generateTypeScriptContent");function wr(r,e){r.writeLine('declare module "@membranehq/sdk" {'),r.indent(()=>{e.forEach(t=>{const n=Ve(t),o=t?.inputSchema;Pe(r,{interfaceName:n,properties:o?.properties,required:o?.required||[]});const i=Ye(t),s=t?.customOutputSchema||t?.outputSchema;Pe(r,{interfaceName:i,properties:s?.properties,required:s?.required||[],fallbackContent:"result: unknown"}),r.newLine()}),Pe(r,{interfaceName:"MembraneClient",methods:e.map(t=>{const n=Ve(t),o=Ye(t);return{name:"action",parameters:`selector: "${t.key}"`,returnType:`ActionAccessor<${n}, ${o}>`}})}),r.newLine(),Pe(r,{interfaceName:"ConnectionAccessor",methods:e.map(t=>{const n=Ve(t),o=Ye(t);return{name:"action",parameters:`selector: "${t.key}"`,returnType:`ConnectionLevelActionAccessor<${n}, ${o}>`}})})}),r.writeLine("}")}c(wr,"generateModuleAugmentation");function Pe(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&&Cr(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(Pe,"generateTypeScriptInterface");function Cr(r,e,t){Object.entries(e).forEach(([n,o])=>{const s=t.includes(n)?"":"?",a=ze(o);r.writeLine(`readonly ${n}${s}: ${a}`)})}c(Cr,"generateTypeScriptProperties");function ze(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?ze(r.items):"unknown"}[]`:r.type==="object"?r.properties?`{ ${Object.entries(r.properties).map(([t,n])=>{const i=(r.required||[]).includes(t)?"":"?",s=ze(n);return`readonly ${t}${i}: ${s}`}).join("; ")} }`:"Record<string, unknown>":"unknown"}c(ze,"convertJsonSchemaToTypeScript");function Ve(r){return`${qe(Ke(r.key))}Input`}c(Ve,"getInputTypeName");function Ye(r){return`${qe(Ke(r.key))}Output`}c(Ye,"getOutputTypeName");async function Ze(r){const{out:e}=r;await v.promises.mkdir(e,{recursive:!0});const t=Sr(r);for(const[n,o]of Object.entries(t)){const i=x.join(e,n);await v.promises.writeFile(i,o,"utf-8")}}c(Ze,"generateCode");function Sr(r){switch(r.target){case"openapi":return{"openapi.json":mr(r)};case"typescript":return{"generated.d.ts":yr(r)};default:throw new Error(`Unsupported target: ${r.target}`)}}c(Sr,"generateContent");const Xe=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 br(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",Xe()).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")}`,"",Xe()].join(`
5
+ `)).action(async t=>{try{console.warn(Xe()),console.error(w.cyan("\u{1F527} Membrane Codegen")),console.error("Status: Loading membrane interfaces...");const n=await vr(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 Ze(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(br,"setupCodegenCommand");async function vr(r,e){return await r.fetchElements(),{actions:[...r.getSyncedElementsByType(T.Action).map(t=>t.data)].filter(t=>e.actions.includes(t.key||""))}}c(vr,"loadMembraneInterfaces");class me{static{c(this,"ConfigLoader")}static instance=null;sdkLoader;constructor(){this.sdkLoader=new On}static getInstance(){return me.instance||(me.instance=new me),me.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 le=me.getInstance();function we(r){return le.loadConfig(r)}c(we,"readProjectConfig");const Er="membrane",Tr="membrane.config.yml",Qe="https://api.getmembrane.com",xr="https://console.getmembrane.com";function et(r){const t=we()?.consoleUri||xr;return r?new Pn(r,t).toString():t}c(et,"getConsoleUrl");function tt(){const r=process.cwd(),e=x.join(r,Er),t=x.join(r,Tr),n=e,o=x.join(n,"workspace.yaml");return{membraneDirPath:e,configPath:t,payloadDirPath:n,workspaceDataFilePath:o}}c(tt,"getPaths");function jt(){return tt().membraneDirPath}c(jt,"getBasePath");const Ir={pat:{type:"string"},workspace:{type:"object"}},Ut=new Hn({schema:Ir,configName:"config",cwd:I.join(At.homedir(),".membrane")}),$r=c(r=>{Ut.set("pat",r)},"setPat"),Kt=c(()=>Ut.get("pat"),"getPat");class qt{static{c(this,"AccountApiClient")}constructor(e=Qe){this.apiBaseUrl=e}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=Kt();if(!s)throw new Error("Personal Access Token not found.");n.set("Authorization",`Bearer ${s}`)}t.body&&!n.has("Content-Type")&&n.set("Content-Type","application/json");const 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"})}}const kr=c(r=>{const e=new qt(Qe);return t=>e.get(t)},"createAccountApiFetcher"),Rr="membrane",Pr=["**/node_modules/**","**/.git/**","**/.DS_Store","**/Thumbs.db","**/*.tmp","**/*.swp","**/*.swo","**/*.log","**/*.lock","**/.cache/**","**/.next/**","**/.vscode/**","**/.idea/**","**/.logs/**"];function q(r){return x.join(r,Rr)}c(q,"getMembraneDir");const Bt=Me(q(process.cwd()),".logs");class Ar{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`;In(Bt,{recursive:!0});const i=Me(Bt,o),s=this._logs.map(a=>`[${a.timestamp}] ${a.type?.toUpperCase()||"INFO"}: ${a.message}`).join(`
6
+ `);return $n(i,s,"utf-8"),i}catch(t){return console.error("Failed to save logs:",t),null}}}const m=new Ar,_t=new Vn;class Wt{static{c(this,"RequestLogger")}constructor(e=Nn){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=_t.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 _t.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 Dr(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(Dr,"createTrackedClient");class Or{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 Wt,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=Dr(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(J(s),null,2))):zn(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():qt.withSkipErrorLog(i)}async generateAccessToken(e,t){return We.sign({name:"Membrane Agent",isAdmin:!0,exp:Math.floor(Date.now()/1e3)+3600,iss:e},t,{algorithm:"HS512"})}isTokenValid(){return Date.now()<this.tokenExpiry}getCurrentConfig(e){const t=$e(e);return!t?.workspaceKey||!t?.workspaceSecret?null:{workspaceKey:t.workspaceKey,workspaceSecret:t.workspaceSecret,apiUri:t.apiUri}}async createClient(e){const t=await this.generateAccessToken(e.workspaceKey,e.workspaceSecret);return this.tokenExpiry=Date.now()+36e5,this.currentConfig=e,new vt({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}}}const I=new kr;async function Bt(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(Bt,"getWorkspaceId");const Z={UPDATE:"update",DELETE:"delete",CREATE:"create"},q={INCOMING:"incoming",OUTGOING:"outgoing"},z={[T.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")},[T.Connector]:{element:"connector",elements:"connectors",exportable:!1},[T.Action]:{element:"action",elements:"actions",integrationSpecific:!0,exportCleanup:c(r=>(delete r.integration,r),"exportCleanup")},[T.AppDataSchema]:{element:"appDataSchema",elements:"appDataSchemas"},[T.AppEventType]:{element:"appEventType",elements:"appEventTypes"},[T.DataLinkTable]:{element:"dataLinkTable",elements:"dataLinkTables"},[T.DataSource]:{element:"dataSource",elements:"dataSources",parentKey:"universalDataSourceId",integrationSpecific:!0},[T.FieldMapping]:{element:"fieldMapping",elements:"fieldMappings",integrationSpecific:!0,parentKey:"universalFieldMappingId",exportCleanup:c(r=>(delete r.dataSourceId,r),"exportCleanup")},[T.Flow]:{element:"flow",elements:"flows",integrationSpecific:!0,parentKey:"universalFlowId"},[T.Package]:{element:"package",elements:"packages",integrationSpecific:!0}},Rr=["id","workspaceId","integrationId","createdAt","updatedAt","revision","archivedAt","baseUri","state","appliedToIntegrations","dependencies"],_t=[T.Action,T.FieldMapping,T.Flow,T.DataSource,T.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[T.Integration].apiPath;return x.join(t,this.integrationKey,e,this.key)}return x.join(e,this.key)}get path(){return x.join(this.dirPath,"spec.yaml")}get relativePath(){return x.relative(_(process.cwd()),this.path)}get absolutePath(){return x.resolve(x.join(_(process.cwd()),this.path))}isEqual(e){if(this.id!==e.id)return!1;const t=this.clean(),n=e.clean();return Gn(t,n)}hasParent(){if(this.data?.parentUuid)return!0;const e=this.getParentKey();return!!e&&!!this.data?.[e]}clean(){const e={...this.data};return Rr.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===T.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,p=this.getElementTypeFromPath(d);if(p)return{type:p,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(T).find(t=>V[t].apiPath===e)}static getRelativePath(e){return x.relative(_(process.cwd()),e)}static isIntegrationSpecific(e){return _t.includes(e)}static canBeIntegrationSpecific(e){return _t.includes(e)}}class Wt{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=[T.Integration,T.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 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 Qe(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=x.relative(process.cwd(),r);throw new Error(`Failed to parse YAML file "${n}": ${t.message}`)}throw t}}c(Qe,"readYaml$1");function Pr(r,e,t){try{const n=G.dump(e,t);v.writeFileSync(r,n,"utf8")}catch(n){if(n instanceof Error){const o=x.relative(process.cwd(),r);throw new Error(`Failed to write YAML file "${o}": ${n.message}`)}throw n}}c(Pr,"writeYaml$1");class Ar extends Wt{static{c(this,"LocalWorkspaceElementsRepository")}basePath;constructor(e){super(e),this.basePath=_(process.cwd())}async getElementsByType(e,t){const n=[],o=x.join(this.basePath,V[e].apiPath),i=await this.readElementsInDir(o);n.push(...i);for(const s of t){const a=x.join(this.basePath,V[T.Integration].apiPath,s.key,V[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=x.join(this.basePath,t.dirPath),o=x.join(this.basePath,t.path);return v.existsSync(n)||v.mkdirSync(n,{recursive:!0}),Pr(o,e.data),m.debug(`[local] Written ${t.relativePath}`),t}async deleteElement(e){const t=x.join(this.basePath,e.path),n=x.join(this.basePath,e.dirPath);v.existsSync(t)&&v.rmSync(t,{force:!0}),this.pruneEmptyDir(n),m.debug(`[local] Deleted ${e.relativePath}`)}async getIntegrations(){const e=x.join(this.basePath,V[T.Integration].apiPath);return this.readElementsInDir(e)}async readElement(e){const t=Qe(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=x.join(e,s,"spec.yaml");return this.readElement(a)});return(await Promise.all(o)).filter(s=>s!=null)}pruneEmptyDir(e){try{if(!e.startsWith(this.basePath)||e===this.basePath||!v.existsSync(e)||v.readdirSync(e).length>0)return;v.rmdirSync(e),this.pruneEmptyDir(x.dirname(e))}catch(t){console.warn(`Failed to prune empty directory ${e}:`,t)}}}class Dr extends Wt{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&&m.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 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 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 m.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 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 I.withClient(t=>t[z[e.type].element](e.data.id).archive()),m.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(T.Integration,n));return t.length>0&&m.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===T.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===T.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===T.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===T.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!==T.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 et extends Zn{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 B={Updated:"updated",Deleted:"deleted",Stopped:"stopped"},Or={ignored:xr,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 Nr extends et{static{c(this,"LocalElementWatcher")}constructor(e){super(),this.options=e,this.membraneDir=_(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=Vn.watch(this.membraneDir,Or),this.watcher.on("add",e=>this.handleFileSystemEvent(B.Updated,e)).on("change",e=>this.handleFileSystemEvent(B.Updated,e)).on("unlink",e=>this.handleFileSystemEvent(B.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(B.Stopped))}getCwd(){return this.options.cwd}async executeWithPathLock(e,t){const n=x.resolve(e);this.ignoredPaths.add(n);try{await t()}finally{setTimeout(()=>{this.ignoredPaths.delete(n)},this.lockTimeoutMs)}}isPathLocked(e){const t=x.resolve(e);if(this.ignoredPaths.has(t))return!0;for(const n of this.ignoredPaths)if(t.startsWith(n+x.sep))return!0;return!1}clearAllLocks(){this.ignoredPaths.clear()}handleFileSystemEvent(e,t){const n=x.relative(this.membraneDir,t);if(this.isPathLocked(t))return;if(e===B.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=x.relative(this.membraneDir,e);let o;try{o=t?Yn.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 Hn.createHash("sha256").update(e).digest("hex")}updateCache(e,t){if(!t){delete this.contentCache[e];return}this.contentCache[e]=this.getContentHash(t)}removeFromCache(e){delete this.contentCache[e]}clearCache(){Object.keys(this.contentCache).forEach(e=>{delete this.contentCache[e]})}initializeContentCache(){v.existsSync(this.membraneDir)&&this.scanDirectoryForCache(this.membraneDir)}scanDirectoryForCache(e){const t=v.readdirSync(e,{withFileTypes:!0});for(const n of t){const o=x.join(e,n.name);if(n.isDirectory())this.scanDirectoryForCache(o);else if(n.isFile())try{const i=v.readFileSync(o,"utf8"),s=x.relative(this.membraneDir,o);this.updateCache(s,i)}catch{}}}}var tt=(r=>(r.Updated="updated",r.ConnectorFileUpdated="connector-file-updated",r.Connected="connected",r.Disconnected="disconnected",r.Error="error",r))(tt||{});const Mr={debounceMs:2e3,reconnectIntervalMs:5e3,maxReconnectAttempts:1/0,maxBackoffMs:6e4,connectionTimeoutMs:3e5};class Fr extends et{static{c(this,"RemoteElementWatcher")}constructor(e=Mr){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 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)}`;m.debug("[remote-events] Subscribing to workspace events"),this.eventSource=new Xn(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!==An.ElementUpdate)return;const{elementId:t,elementType:n,data:o={}}=e;if(!(!t||!n)){if(n===T.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 Jt{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",nt={};async function Gt(r={}){const{onProgress:e}=r,t=new Set,o=(await I.withClient(d=>d.get("org-workspace-id"))).id,i={};m.info("[connectors] Loading custom connectors"),await I.withClient(d=>d.get(`/connectors?workspaceId=${o}`)),m.info("[connectors] Loading public connectors");const s=ee(),l=(P.existsSync(s)?P.readdirSync(s):[]).filter(d=>{if(d.startsWith("."))return!1;const h=R.join(s,d);try{return P.statSync(h).isDirectory()}catch{return!1}});for(const d of l){m.info(`[connectors] Loading connector from: ${d}`);const h=P.readdirSync(R.join(s,d)),p=await rt(d);if(!p)continue;e?.("pushing",p.name),"baseUri"in p&&delete p.baseUri;let f;if(p.uuid&&(f=await I.withClient(E=>E.get(`/connectors/${p.uuid}`),!1)),f)i[p.id]=f.id,m.info(`[connectors] Matched ${p.name} uuid: ${p.uuid}`),f.isPublic||(f.archivedAt&&(m.info(`[connectors] Restoring archived connector ${p.name}`),await I.withClient(E=>E.post(`connectors/${f.id}/restore`))),m.info(`[connectors] Updating connector ${p.name}`),await I.withClient(E=>E.patch(`connectors/${f.id}`,{...p,workspaceId:o})));else if(!i[p.id]&&!f?.isPublic){let E=!1;try{const S=await ot({connectorId:p.id});S&&S.isPublic&&(E=!0)}catch{}if(!E){m.info(`[connectors] Creating custom connector ${p.name} (${p.key})`);const S=await I.withClient(N=>N.post("connectors",{...p,workspaceId:o}));i[p.id]=S.id}}const C=h.filter(E=>P.statSync(R.join(s,d,E)).isDirectory());for(const E of C)await Ur({connector:p,version:E,connectorId:i[p.id]}),t.add(p.id);e?.("pushed",p.name)}return{connectorsMapping:i,pushedConnectors:Array.from(t)}}c(Gt,"pushConnectors");async function Ht({connectorId:r,connectorVersion:e,allConnectors:t,pulledConnectors:n,pulledConnectorVersions:o}){if(!r||o[r]?.has(e))return;const i=Mt(),s=await ot({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 Kr({basePath:i,connector:s}),n.add(r)),o[r]||(o[r]=new Set),o[r].has(e)||(await qr({connector:s,connectorVersion:e,basePath:i}),o[r].add(e))}}c(Ht,"pullRemoteConnector");function ee(){const r=Xe();return R.join(r.membraneDirPath,pe)}c(ee,"getConnectorsPath");async function rt(r){const e=R.join(ee(),r,`${r}.yml`);return Qe(e,!1)}c(rt,"readConnector");async function Lr(r,e){return m.info(`[connectors] Zipping ${r} into ${e}`),new Promise((t,n)=>{const o=P.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=P.readdirSync(r);for(const a of s){const l=R.join(r,a),d=P.statSync(l);d.isFile()?i.file(l,{name:a}):d.isDirectory()&&i.directory(l,a)}i.finalize()})}c(Lr,"createZipArchive");async function jr(r,e){return m.info(`[connectors] Unzipping into ${e}`),new Promise((t,n)=>{const o=At.Parse();o.on("entry",i=>{const s=i.path;if(i.type==="Directory"){const l=R.join(e,s);P.mkdirSync(l,{recursive:!0}),i.autodrain()}else{const l=R.join(e,s),d=R.dirname(l);P.mkdirSync(d,{recursive:!0});const h=P.createWriteStream(l);i.pipe(h),h.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(jr,"extractZipArchive");async function Ur({connector:r,version:e,connectorId:t}){const n=R.join(ee(),Q(r),zt(e)),o=R.join(n,"src"),i=R.join(n,"src.zip"),s=P.existsSync(i);if(P.existsSync(o)&&(m.info(`[connectors] Archiving source code for ${r.name} version ${e}`),await Lr(o,i)),!P.existsSync(i)){m.warning(`[connectors] No source code found for ${r.name} version ${e}`);return}try{const a=new Pt;if(a.append("file",P.createReadStream(i),"file.zip"),m.info(`[connectors] Pushing connector version ${e} for ${r.name}`),e==X)m.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)){m.info(`[connectors] Version ${e} already published`);return}m.info(`[connectors] Publishing version ${e} of connector ${t}`),await I.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&&P.existsSync(i)&&(m.info(`[connectors] Cleaning up temporary zip file for ${r.name} version ${e}`),P.unlinkSync(i))}}c(Ur,"pushConnectorVersion");async function ot({connectorId:r}){if(r){if(nt[r])return nt[r];try{const e=await I.withClient(t=>t.get(`connectors/${r}`),!1);return nt[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(ot,"getConnector");async function Kr({basePath:r,connector:e}){const t=Q(e),n=R.join(r,pe,t);P.mkdirSync(n,{recursive:!0});const o=R.join(n,`${Q(e)}.yml`);P.writeFileSync(o,G.dump(e)),m.info(`[connectors] Pulled connector ${e.name}`)}c(Kr,"pullConnector$1");async function qr({connector:r,connectorVersion:e,basePath:t}){const n=Q(r),o=zt(e),i=R.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=R.join(i,"src.zip");if(P.writeFileSync(a,s),!e){const l=R.join(i,"src");P.mkdirSync(l,{recursive:!0}),await jr(s,l)}m.info(`[connectors] Pulled connector version: ${r.name} (${o})`)}c(qr,"pullConnectorVersion");function Q(r){return r.key}c(Q,"getConnectorDirName");function zt(r){return r??X}c(zt,"getConnectorVersionDirName");function Br(r){const e=Mt(),t=Q(r);return R.join(e,pe,t)}c(Br,"getConnectorDirPath");function _r(r){return r.match(`${pe}/[^/]+/${X}/src/.*`)!==null}c(_r,"isConnectorSourceFile");async function Wr(r){const e=r.match(`${pe}/([^/]+)/${X}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await rt(t);if(!o){m.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"}})),m.info(`[connectors] Pushed file ${n} for connector ${o.name}`)}c(Wr,"putConnectorFile");async function Jr(r){const e=r.match(`${pe}/([^/]+)/${X}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await rt(t);if(!o){m.warning(`[connectors] Connector ${t} not found. Ignoring file change`);return}const i=o.id;await I.withClient(s=>s.delete(`connectors/${i}/files/${n}`)),m.info(`[connectors] Deleted file ${n} for connector ${o.name}`)}c(Jr,"deleteConnectorFile");async function Gr(r,e){try{const t=await I.withClient(s=>s.get(`connectors/${r}`));if(!t){m.warning(`[connectors] Connector ${r} not found`);return}const n=await I.withClient(s=>s.get(`connectors/${r}/files/${e}`)),o=Q(t),i=R.join(ee(),o,X,"src",e);P.mkdirSync(R.dirname(i),{recursive:!0}),n!=null?(P.writeFileSync(i,n),m.info(`[connectors] Pulled file ${e} for connector ${t.name}`)):P.existsSync(i)&&(P.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(Gr,"pullConnectorFile");async function Hr(r,e){const t=await I.withClient(i=>i.get(`connectors/${r}`),!1);if(!t){m.warning(`[connectors] Connector ${r} not found`);return}const n=Q(t),o=R.join(ee(),n,X,"src",e);P.existsSync(o)&&(P.unlinkSync(o),m.info(`[connectors] Deleted file ${e} for connector ${n}`))}c(Hr,"deleteLocalConnectorFile");async function zr(r,e,t){if(t&&e!==t)try{const n=await I.withClient(l=>l.get(`connectors/${r}`),!1);if(!n){m.warning(`[connectors] Connector ${r} not found`);return}const o=Q(n),i=R.join(ee(),o,X,"src"),s=R.join(i,e),a=R.join(i,t);P.existsSync(s)&&(P.mkdirSync(R.dirname(a),{recursive:!0}),P.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(zr,"renameLocalConnectorDirectory");async function Vr(r,e){try{const t=await I.withClient(i=>i.get(`connectors/${r}`),!1);if(!t){m.warning(`[connectors] Connector ${r} not found`);return}const n=Q(t),o=R.join(ee(),n,X,"src",e);if(P.existsSync(o)){const i=R.resolve(ee());if(!R.resolve(o).startsWith(i))return;P.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(Vr,"deleteLocalConnectorDirectory");const F={LogAdded:"logAdded",StateChanged:"stateChanged",StatsChanged:"statsChanged",ConflictsChanged:"conflictsChanged",McpStatusChanged:"mcpStatusChanged",McpServersChanged:"mcpServersChanged",ConfigChanged:"configChanged"};class Yr extends et{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(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:kt.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 Yr({heartbeatIntervalMs:15e3}),Vt=[T.AppDataSchema,T.AppEventType,T.DataLinkTable,T.DataSource,T.FieldMapping,T.Action,T.Flow,T.Package];class Se{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 Jt,this.remoteCache=new Jt,this.localRepo=new Ar(this.localCache),this.remoteRepo=new Dr(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(T.Integration).map(n=>n.data);for(const n of t){const o=n.connectorId,i=n.connectorVersion;o&&await Ht({connectorId:o,connectorVersion:i,allConnectors:e,pulledConnectors:this.pulledConnectors,pulledConnectorVersions:this.pulledConnectorVersions})}}async pushConnectors(){const{connectorsMapping:e}=await Gt();this.remoteRepo.setConnectorsMapping(e)}getHandler(e){return e===q.INCOMING?this.localRepo:(this.remoteRepo.setSourceCache(this.localCache),this.remoteRepo)}getCache(e){return e===q.INCOMING?this.localCache:this.remoteCache}async startWatching(){this.localWatcher=new Nr({cwd:process.cwd(),lockTimeoutMs:1e3}),this.localWatcher.on(B.Updated,e=>this.handleLocalEvent(e,B.Updated)),this.localWatcher.on(B.Deleted,e=>this.handleLocalEvent(e,B.Deleted)),await this.localWatcher.start(),m.success("[local] Tracking changes.."),this.remoteWatcher=new Fr,this.remoteWatcher.on(tt.Updated,({elementId:e,elementType:t})=>this.handleRemoteElementEvent(e,t)),this.remoteWatcher.on(tt.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(q.INCOMING)}] Deleted: ${s.id}`),this.localWatcher?.executeWithPathLock(s.absolutePath,()=>this.deleteElement(s,q.INCOMING))):void 0}if(m.info(`[${this.getDirectionLabel(q.INCOMING)}] Updated: ${n.id}`),await this.localWatcher?.executeWithPathLock(n.absolutePath,async()=>this.updateElement(n,q.INCOMING)),t===T.Integration){const s=n.data.connectorId,a=n.data.connectorVersion,l=await ot({connectorId:s});if(!l?.key)return;const d=Br(l);await this.localWatcher?.executeWithPathLock(d,async()=>Ht({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 Ne.ConnectorFileDeleted:await Hr(e,t);break;case Ne.ConnectorDirectoryRenamed:await zr(e,t,o);break;case Ne.ConnectorDirectoryDeleted:await Vr(e,t);break;default:await Gr(e,t);break}}catch(i){m.error(`[sync] Error handling remote connector file event: ${i}`)}}async handleLocalEvent(e,t){try{if(_r(e.filePath))switch(t){case B.Updated:await Wr(e.filePath);break;case B.Deleted:await Jr(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(m.info(`[${this.getDirectionLabel(q.OUTGOING)}] ${Jn(t)}: ${n.id}`),t){case B.Updated:await this.updateElement(n,q.OUTGOING);break;case B.Deleted:await this.deleteElement(n,q.OUTGOING);break}}}catch(n){m.error(`[sync] Error handling local event: ${n}`)}}detectIncomingChanges(){this.clearChanges();const e=Se.getChanges(q.INCOMING,this.remoteCache,this.localCache);return this.updateChanges(e),e}detectOutgoingChanges(){this.clearChanges();const e=Se.getChanges(q.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===T.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===q.INCOMING?this.detectIncomingChanges():this.detectOutgoingChanges(),this.changes=this.changes.filter(o=>o.element.type!==T.Integration)),m.info("[resolver] Resolving universal elements");const t=this.changes.filter(o=>!o.element.hasParent());for(const o of Vt){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 Vt){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 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),p=Se.detectChangeForElement(d,h,e);p&&a.push(p)}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 q.INCOMING:return"local\u2190remote";case q.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=x.join(Qn.tmpdir(),"membrane-mcp-status"),Yt=3e4;class Zr{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=ke(void 0,e),n=Zt(e);t&&te.setMcpStatus(t),await te.setMcpServers(n)}catch{m.error("Failed to check MCP status")}}}function ke(r,e){try{const t=e||process.cwd();if(!r){const o=Zt(t);return o.length===0?null:o[0]}const n=at(r,t);if(v.existsSync(n)){const o=v.statSync(n),i=new Date;if(i.getTime()-o.mtime.getTime()>Yt)return we(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>Yt)return we(r,t),null}return l}}catch{r&&e&&we(r,e)}return null}c(ke,"getMcpStatus");function Zt(r){try{const e=r||process.cwd(),t=st(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=ke(a,e);l&&o.push(l)}}return o.sort((i,s)=>new Date(s.startTime).getTime()-new Date(i.startTime).getTime())}catch{return[]}}c(Zt,"getAllMcpStatusFiles");function it(r){try{const t={...ke(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=at(r.processId,r.cwd);v.writeFileSync(n,JSON.stringify(t,null,2))}catch{}}c(it,"updateMcpStatus");function we(r,e){try{const t=e||process.cwd();if(r){const n=at(r,t);v.existsSync(n)&&v.unlinkSync(n)}else{const n=st(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(x.join(ne,i))}}}catch{}}c(we,"clearMcpStatus");function Xr(r,e){const t=ke(r,e);t&&it({processId:r,cwd:e,totalRequests:t.totalRequests+1,lastRequestTime:new Date().toISOString(),lastActivity:new Date().toISOString()})}c(Xr,"trackToolExecution");function st(r){return zn("md5").update(r).digest("hex").slice(0,8)}c(st,"getCwdHash");function at(r,e){const t=st(e);return x.join(ne,`mcp-${t}-${r}.json`)}c(at,"getStatusFilePath");const Re={Agent:"agent",Cli:"cli"},$={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 Qr{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 Zr,this.syncService=new Se,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&&I.init({maxRequestsPerSecond:e.rps}),await this.notifier.setState($.PULLING),await this.syncService.fetchElements(),this.syncService.detectIncomingChanges(),this.syncService.needsForcedSync()&&!e.force){await this.notifier.setState($.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($.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&&I.init({maxRequestsPerSecond:e.rps}),await this.notifier.setState($.PUSHING),await this.syncService.fetchElements(),this.syncService.detectOutgoingChanges(),this.syncService.needsForcedSync()&&!e.force){await this.notifier.setState($.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($.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($.RESOLVING),this.syncService.needsSync()&&await this.syncService.resolveChanges();const t=await this.syncService.getStats();this.notifier.setStats(t),await this.notifier.setState($.SYNCED),e.watch&&(await this.notifier.setState($.WATCHING),await this.syncService.startWatching())}catch(t){m.error(`Failed to sync local and remote workspaces: ${t}`),await this.notifier.setState($.ERROR),m.saveLogsToFile("error")}}async init({force:e=!1}={}){if(!(this.initialized&&!e)){await this.notifier.setState($.NOT_INITIALIZED);try{await this.loadConfig(),le.isCacheDefined()?(await this.initServices(),this.initialized=!0,await this.notifier.setState($.INITIALIZED)):(this.initialized=!1,await this.notifier.setState($.SETTING_UP))}catch(t){m.error(`Failed to initialize services: ${t}`),await this.notifier.setState($.ERROR),m.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===Re.Agent&&(await this.notifier.cleanup(),await this.mcpStatusService.stop()),this.initialized=!1,this.onShutdown())}async initServices(){this.mode===Re.Agent&&(await this.notifier.connectToRemote(),await this.mcpStatusService.start()),this.syncService.clear()}async stopServices(){this.mode===Re.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 Xt=Ke(null);function eo({children:r,membraneCLIService:e}){const{data:t}=$t("/account"),[n,o]=D($.NOT_INITIALIZED),[i,s]=D([]),[a,l]=D({}),[d,h]=D([]),[p,f]=D(null),E=t?.workspaces?.find(S=>S.workspaceKey===p?.workspaceKey)||null;return he(()=>{const S=c(({state:L})=>o(L),"handleStateChanged"),N=c(({stats:L})=>l(L),"handleStatsChanged"),O=c(({log:L})=>h(be=>[...be,L]),"handleLogAdded"),U=c(({conflicts:L})=>s(L),"handleConflictsUpdated"),K=c(({config:L})=>f(L),"handleConfigChanged");return e.notifier.on(F.StateChanged,S),e.notifier.on(F.StatsChanged,N),e.notifier.on(F.LogAdded,O),e.notifier.on(F.ConflictsChanged,U),e.notifier.on(F.ConfigChanged,K),e.init(),()=>{e.notifier.off(F.StateChanged,S),e.notifier.off(F.StatsChanged,N),e.notifier.off(F.LogAdded,O),e.notifier.off(F.ConflictsChanged,U),e.notifier.off(F.ConfigChanged,K)}},[]),u(Xt.Provider,{value:{state:n,stats:a,logs:d,currentWorkspace:E,conflicts:i,config:p,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(eo,"MembraneCLIServiceProvider");function H(){const r=qe(Xt);if(!r)throw new Error("useMembraneCLIService must be used within MembraneCLIServiceProvider");return r}c(H,"useMembraneCLIService");const ct=Ke(null),Qt=c(()=>{const r=qe(ct);if(!r)throw new Error("useTree must be used within TreeView");return r},"useTree"),to=c(r=>se.Children.count(r)>0,"hasChildren");function no(r){const e=Qt(),{label:t,value:n,isInitiallyExpanded:o}=r,i=Un(),s=Be(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:p}=r,f=typeof p=="function"?p(h):p;return{...h,props:{...r,children:f},isParent:to(f)}}c(no,"useTreeItem");function fe(r){const e=Qt(),t=no(r),{expanded:n,isParent:o,props:{children:i},setExpanded:s}=t,{renderValue:a=oo}=r,l=t.ref;Ee(()=>{function f(C){return r.onInput?.(C)?!0:C.active&&C.key.rightArrow&&!n?(s(!0),!0):C.active&&C.key.leftArrow&&n?(s(!1),!0):!1}c(f,"onInput"),l.onInput=f},[l,r.onInput,n,s]),l.firstChild??={parent:l,index:0};let d=l.firstChild;function h(f){const C=d;return C.nextSibling||(C.nextSibling={parent:l,prevSibling:C,index:C.index+1}),d=C.nextSibling,C.label=f,C}c(h,"registerChildItem");function p(){l.lastRenderedChild=d.prevSibling}return c(p,"commitChildren"),Ee(()=>{p()}),b(Te,{children:[b(g,{marginLeft:e.depth*2,children:[u(g,{width:2,children:o&&u(y,{children:n?"\u25BC":"\u25B6"})}),ro(t),a(t)]}),n&&u(ct.Provider,{value:{...e,depth:e.depth+1,registerChildItem:h},children:i})]})}c(fe,"TreeItem");function ro({active:r,label:e}){return u(g,{width:32,children:u(y,{inverse:r,children:e})})}c(ro,"defaultRenderLabel");function oo(r){return u(y,{})}c(oo,"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"),en=c(({label:r,value:e,onChange:t,disabled:n=!1,mask:o,...i})=>{const[s,a]=D(e),[l,d]=D(!1);return Ee(()=>{l||a(e)},[l,e]),u(fe,{label:r,value:e,onInput:c(({key:h,active:p})=>n?!1:l?(h.escape&&d(!1),h.return&&(t(s),d(!1)),!0):p&&h.return?(d(!0),a(e),!0):!1,"onInput"),renderValue:c(()=>{const h=s,p=o?o.repeat(h.length):h;return u(g,{children:n||!l?u(y,{dimColor:!0,children:p}):b(Te,{children:[u(g,{width:p.length+1,children:u(Dt,{...i,focus:l,value:h,onChange:a})}),u(y,{dimColor:!0,children:" \u241B cancel"})]})})},"renderValue")})},"TreeTextField"),io=c(r=>u(en,{...r,mask:"*"}),"SecretField"),W=c(({children:r,showHelp:e=!1})=>{const t=Be({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};Ee(()=>{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 p of s(t.current))if(p.label!=null){if(d===n&&(h=p),p&&p.onInput?.({input:a,key:l,active:p===n}))return;d=p}l.upArrow?o(p=>p.prevSibling?.lastRenderedChild??p.prevSibling??p.parent??t.current):l.downArrow?o(p=>h??p):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(p=>p.parent??t.current):l.rightArrow&&o(p=>p.lastRenderedChild?p.firstChild:p)}),u(ct.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=en;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(p=>p.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===T.Action&&b(Te,{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 so({onComplete:r}){const{config:e,updateConfig:t,fetchElements:n,getSyncedElementsByType:o}=H(),[i,s]=D(""),a=e,l=c(f=>{s(f),setTimeout(()=>s(""),2e3)},"setFlash"),d=c(async(f,C)=>{try{await t({[f]:C}),l("\u2705 Configuration updated!")}catch{l("\u274C Error updating configuration")}},"updateField"),h=c(async()=>{try{if(e){const f=le.saveToFile(e);l(f?"\u2705 Configuration saved successfully!":"\u274C Failed to save configuration"),await n();const C=o(T.Action);await Ve({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:C.filter(E=>!a?.excludedActionKeys?.includes(E.key)).map(E=>E.data)}}),l("\u2705 Code generated successfully!")}}catch{l("\u274C Error saving configuration")}},"handleSaveConfig"),p=c(async()=>{try{const f=le.loadConfig();f?(await t(f),l("\u2705 Configuration reloaded successfully!")):l("\u274C No configuration found to reload")}catch{l("\u274C Error reloading configuration")}},"handleReloadConfig");return 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(f=>d("workspaceKey",f),"onChange"),disabled:!0}),u(io,{label:"Workspace Secret",value:a?.workspaceSecret??"",onChange:c(f=>d("workspaceSecret",f),"onChange"),disabled:!0}),u(W.TextField,{label:"API URI",value:a?.apiUri??"",onChange:c(f=>d("apiUri",f),"onChange")}),u(W.TextField,{label:"Test Customer ID",value:a?.testCustomerId??"",onChange:c(f=>d("testCustomerId",f),"onChange")})]}),b(W.Item,{label:"Code Generation",isInitiallyExpanded:!0,children:[b(W.Item,{label:"Project Type",isInitiallyExpanded:!0,value:a?.projectType,renderValue:c(({value:f})=>u(y,{children:f==="typescript"?"TypeScript":f==="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(f=>d("outputDir",f),"onChange")})]}),b(W.Item,{label:"Workspace Elements",children:[u(de,{label:"Actions",elementType:T.Action,isActionExcluded:c(f=>a?.excludedActionKeys?.includes(f.key)??!1,"isActionExcluded"),toggleAction:c(f=>d("excludedActionKeys",[...a?.excludedActionKeys??[],f.key]),"toggleAction"),generateCode:c(f=>{(async()=>{try{await Ve({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:[f]}}),l("\u2705 Code generated successfully!")}catch{l("\u274C Error generating code")}})()},"generateCode")}),u(de,{label:"Flows",elementType:T.Flow}),u(de,{label:"Data Sources",elementType:T.DataSource}),u(de,{label:"Field Mappings",elementType:T.FieldMapping}),u(de,{label:"Packages",elementType:T.Package}),u(de,{label:"App Data Schemas",elementType:T.AppDataSchema}),u(de,{label:"App Event Types",elementType:T.AppEventType})]})]}),u(ue,{label:"Save Configuration",onPress:h,hotkey:"s"}),u(ue,{label:"Reload Configuration",onPress:p,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(so,"ConfigManager");const tn=Ke(process.cwd());function ao({cwd:r,children:e}){return u(tn.Provider,{value:r,children:e})}c(ao,"CwdProvider");function co(){return qe(tn)}c(co,"useCwd");function lt({cwd:r,children:e,membraneCLIService:t}){const n=r||process.cwd();return u(ao,{cwd:n,children:u(er,{value:{fetcher:Er()},children:u(eo,{membraneCLIService:t,children:e})})})}c(lt,"Layout");function lo(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(()=>{_e(se.createElement(lt,{membraneCLIService:e,children:se.createElement(so,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(lo,"setupConfigCommand");function uo({currentPat:r,onSubmit:e}){const[t,n]=D(""),[o,i]=D(!1),[s,a]=D(null);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:"https://console.integration.app/w/0/manage-account/api-token"})}),r&&u(y,{dimColor:!0,children:"Press Enter to keep your current token or type a new one."}),u(Dt,{mask:"*",placeholder:`${r?"******":"Enter your token here..."}`,value:t,onChange:n,onSubmit:c(async d=>{a(null),i(!0);try{await e(d),n("")}catch{a("Invalid token. Please try again.")}finally{i(!1)}},"handleSubmit")}),o&&u(g,{marginTop:1,children:b(y,{children:[u(xe,{type:"dots"})," Validating token..."]})}),s&&u(y,{color:"red",children:s})]})}c(uo,"PersonalAccessTokenInput");function nn({onExit:r,showEscOption:e=!0}){const[t,n]=D(""),{data:o,error:i,isLoading:s}=$t("/account"),{updateConfig:a}=H(),l=o?.workspaces,d=s;if(ae((S,N)=>{N.escape&&r?.()}),d)return b(g,{children:[u(xe,{}),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 h=l?.filter(S=>S.name.toLowerCase().includes(t.toLowerCase()))??[],p=h.map(S=>({label:S.name,value:S.id})),f=p.length,C=l?.length??0;async function E(S){const N=h.find(K=>K.id===S);if(!N)return;const{key:O,secret:U}=N;!O||!U||(await a({workspaceKey:O,workspaceSecret:U}),r?.())}return c(E,"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(tr,{placeholder:"Enter a search query...",onChange:n})]}),C>5&&b(y,{children:["Showing ",f," of ",C," workspaces."]}),u(g,{marginTop:1,children:u(nr,{options:p,onChange:c(S=>{S&&E(S)},"onChange")})}),e&&u(g,{marginTop:1,children:u(y,{color:"grey",children:"Press ESC to go back"})})]})}c(nn,"SelectWorkspace");var Ce=(r=>(r[r.Authenticate=0]="Authenticate",r[r.ConnectWorkspace=1]="ConnectWorkspace",r))(Ce||{});const ho={0:"Authenticate in Membrane",1:"Connect a Membrane Workspace"},ut=[Ce.Authenticate,Ce.ConnectWorkspace];function rn({onComplete:r}){const{config:e}=H(),[t,n]=D(!1),[o,i]=D(0),s=!!(e?.workspaceKey&&e?.workspaceSecret),a=Lt(),l=ut[o],d=o+1,h=ut.length,p=ut.map((E,S)=>{let N="pending";return S<o?N="done":S===o&&(N="current"),{id:E,label:ho[E],status:N}});async function f(E){const S=a&&E===""?a:E,N=new jt;try{await N.request("/account",{headers:{Authorization:`Bearer ${S}`}}),vr(S),i(O=>O+1)}catch(O){console.error(O)}}c(f,"handlePatSubmit");function C(){n(!0),r&&r()}return c(C,"handleWorkspaceSelected"),ae((E,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 ",h]}),s&&u(y,{color:"grey",children:" [esc: go back]"})]})}),u(g,{flexDirection:"column",paddingLeft:2,children:p.map(E=>u(po,{status:E.status,label:E.label},E.id))})]}),l===Ce.Authenticate&&u(uo,{currentPat:a,onSubmit:f}),l===Ce.ConnectWorkspace&&u(nn,{onExit:C,showEscOption:!1})]})}c(rn,"Setup");function po({status:r,label:e}){return b(g,{children:[b(g,{width:2,children:[r==="current"&&u(xe,{type:"dots"}),r==="done"&&u(y,{children:"\u2705"})]}),u(y,{dimColor:r!=="current",children:e})]})}c(po,"StepDisplay");function fo(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?le.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)):_e(se.createElement(lt,{membraneCLIService:e,children:se.createElement(rn,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(fo,"setupInitCommand");const mo=86400;async function go(r,e,t,n){const o={iss:r,isAdmin:!0};return t&&(o.id=t),We.sign(o,e,{expiresIn:mo})}c(go,"generateMcpAccessToken");async function yo(r,e){return(await ge.get(`${r}/docs-json`,{headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}})).data}c(yo,"fetchOpenApiSchema");function re(r,e=!0,t,n=new Set){if(!r)return e?A.string():A.string().optional();if(Object.keys(r).length===0)return e?A.any():A.any().optional();if(r.$ref){const i=r.$ref.replace("#/components/schemas/","");if(n.has(i))return A.any();if(n.add(i),t?.schemas?.[i]){const s=t.schemas[i];return re(s,e,t,n)}return A.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]=re(a,l,t,n)}if(Object.keys(i).length>0){if(o=A.object(i),r.additionalProperties)if(typeof r.additionalProperties=="object"){const s=re(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=re(r.additionalProperties,!1,t,n);o=A.record(A.string(),s)}else o=A.record(A.string(),A.any())}else if(r.type==="array"){const i=r.items?re(r.items,!0,t,n):A.any();o=A.array(i)}else if(r.anyOf)o=A.any();else{switch(r.type){case"integer":o=A.coerce.number().int();break;case"number":o=A.coerce.number();break;case"boolean":o=A.coerce.boolean();break;case"string":default:o=A.string();break}r.format==="uuid"?o=A.string().uuid():r.format==="email"?o=A.string().email():r.format==="date"?o=A.string().regex(/^\d{4}-\d{2}-\d{2}$/):r.format==="date-time"&&(o=A.string().datetime()),r.enum&&(o=A.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(re,"convertOpenApiSchemaToZod");function on(r){const e=r.match(/\{([^}]+)\}/g);return e?e.map(t=>t.slice(1,-1)):[]}c(on,"extractPathParameters");function wo(r,e,t,n,o,i){const s=r.operationId||`${t}_${e.replace(/[^a-zA-Z0-9]/g,"_")}`,a=r.description||r.summary||`${t.toUpperCase()} ${e}`,l={},d={},h={};if(r.parameters){for(const f of r.parameters)if(f.in==="path")d[f.name]=re(f.schema,!0,o).describe(f.description||`Path parameter: ${f.name}`);else if(f.in==="query"){const C=f.required===!0;h[f.name]=re(f.schema,C,o).describe(f.description||`Query parameter: ${f.name}`)}}if(Object.keys(d).length>0&&(l.params=A.object(d).describe("Path parameters")),Object.keys(h).length>0&&(l.query=A.object(h).describe("Query parameters")),r.requestBody&&r.requestBody.content){const f=r.requestBody.required===!0;if(r.requestBody.content["application/json"]){const C=r.requestBody.content["application/json"].schema;C?l.body=re(C,f,o).describe("Request body (JSON)"):l.body=A.any().describe("Request body (JSON)")}else r.requestBody.content["application/octet-stream"]||r.requestBody.content["text/plain"]?l.body=f?A.string().describe("Request body (binary/text)"):A.string().optional().describe("Request body (binary/text)"):l.body=A.any().describe("Request body")}const p=Object.keys(l).length>0?A.object(l):A.object({});return{name:s,description:a,parameters:p,async execute(f){try{const C=on(e);if(C.length>0){if(!f.params)throw new Error(`Missing required path parameters: ${C.join(", ")}`);const K=C.filter(L=>!(L in f.params));if(K.length>0)throw new Error(`Missing required path parameters: ${K.join(", ")}`)}let E=`${n}${e}`;if(f.params)for(const[K,L]of Object.entries(f.params)){const be=`{${K}}`;E.includes(be)&&(E=E.replace(be,String(L)))}const S=on(E);if(S.length>0)throw new Error(`Unresolved path parameters: ${S.join(", ")}`);const N=new URLSearchParams;if(f.query)for(const[K,L]of Object.entries(f.query))L!=null&&N.append(K,String(L));N.toString()&&(E+=`?${N.toString()}`);const O={method:t.toUpperCase(),headers:{Authorization:`Bearer ${i}`}};f.body&&t.toLowerCase()!=="get"&&(r.requestBody?.content?.["application/json"]?(O.headers["Content-Type"]="application/json",O.data=f.body):r.requestBody?.content?.["application/octet-stream"]?(O.headers["Content-Type"]="application/octet-stream",O.data=f.body):r.requestBody?.content?.["text/plain"]?(O.headers["Content-Type"]="text/plain",O.data=f.body):(O.headers["Content-Type"]="application/json",O.data=f.body));const U=await ge.request({url:E,...O});return{content:[{type:"text",text:U.data===""?"":JSON.stringify(U.data,null,2)}]}}catch(C){return ge.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(wo,"createApiTool");function Co(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=wo(l,i,a,e,o,t);n.push(d)}}return n}c(Co,"convertOpenApiToTools");function So(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(`
12
- `)).action(async()=>{try{process.env.FASTMCP_SUPPRESS_WARNINGS="true";const e=$e(),t=process.env.MEMBRANE_ACCESS_TOKEN||e?.accessToken,n=process.env.MEMBRANE_WORKSPACE_KEY||e?.workspaceKey,o=process.env.MEMBRANE_WORKSPACE_SECRET||e?.workspaceSecret,i=process.env.MEMBRANE_TEST_CUSTOMER_ID||e?.testCustomerId,s=process.env.MEMBRANE_API_URI||e?.apiUri||Ze;!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 go(n,o,i),l=await yo(s,a),d=Co(l,s,a),h=new or({name:"Membrane API",instructions:`This MCP server lets you interact with Membrane to configure, run, and troubleshoot integrations.
9
+ Unexpected Error:`),a&&console.error(a),console.error(s)),s}return}},"executeRequest");return t?i():Wt.withSkipErrorLog(i)}async generateAccessToken(e,t){return Ge.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=we(e);return!t?.workspaceKey||!t?.workspaceSecret?null:{workspaceKey:t.workspaceKey,workspaceSecret:t.workspaceSecret,apiUri:t.apiUri}}async createClient(e){const t=await this.generateAccessToken(e.workspaceKey,e.workspaceSecret);return this.tokenExpiry=Date.now()+36e5,this.currentConfig=e,new xt({token:t,apiUri:e.apiUri})}async getClient(e=process.cwd()){const t=this.getCurrentConfig(e);if(!t)throw new Error("Unable to create MembraneClient: No workspace configuration found.");const n=!this.currentConfig||this.currentConfig.workspaceKey!==t.workspaceKey||this.currentConfig.workspaceSecret!==t.workspaceSecret||this.currentConfig.apiUri!==t.apiUri,o=!this.isTokenValid()||this.tokenExpiry-Date.now()<3e5;return(!this.client||n||o)&&(this.client=await this.createClient(t)),this.client}clearClient(){this.client=null,this.currentConfig=null,this.tokenExpiry=0,this.requestTimes=[],this.semaphore=0,this.semaphoreQueue=[],this.rateLimitMutex=Promise.resolve()}getCurrentConfigInfo(){return this.currentConfig}async waitIfNeeded(){this.rateLimitMutex=this.rateLimitMutex.then(async()=>{for(this.cleanOldRequests();this.requestTimes.length>=this.maxRequestsPerSecond;){const t=this.requestTimes[0]+this.windowSizeMs-Date.now()+10;if(t>0)await new Promise(n=>setTimeout(n,t)),this.cleanOldRequests();else break}}),await this.rateLimitMutex}recordRequest(){this.requestTimes.push(Date.now())}cleanOldRequests(){const e=Date.now()-this.windowSizeMs;this.requestTimes=this.requestTimes.filter(t=>t>e)}getRequestCount(){return this.cleanOldRequests(),this.requestTimes.length}async acquireSemaphore(){if(this.semaphore<this.maxConcurrentRequests){this.semaphore++;return}return new Promise(e=>{this.semaphoreQueue.push(e)})}releaseSemaphore(){if(this.semaphore--,this.semaphoreQueue.length>0){const e=this.semaphoreQueue.shift();this.semaphore++,e()}}async withRetry(e,t="operation"){let n;for(let o=0;o<=this.maxRetries;o++)try{return await e()}catch(i){if(n=i,!this.isRetryableError(i)||o===this.maxRetries)throw i;const s=new Date().toISOString(),a=o+2;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}}}const $=new Or;async function Jt(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(Jt,"getWorkspaceId");const Z={UPDATE:"update",DELETE:"delete",CREATE:"create"},B={INCOMING:"incoming",OUTGOING:"outgoing"},z={[T.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")},[T.Connector]:{element:"connector",elements:"connectors",exportable:!1},[T.Action]:{element:"action",elements:"actions",integrationSpecific:!0,exportCleanup:c(r=>(delete r.integration,r),"exportCleanup")},[T.AppDataSchema]:{element:"appDataSchema",elements:"appDataSchemas"},[T.AppEventType]:{element:"appEventType",elements:"appEventTypes"},[T.DataLinkTable]:{element:"dataLinkTable",elements:"dataLinkTables"},[T.DataSource]:{element:"dataSource",elements:"dataSources",parentKey:"universalDataSourceId",integrationSpecific:!0},[T.FieldMapping]:{element:"fieldMapping",elements:"fieldMappings",integrationSpecific:!0,parentKey:"universalFieldMappingId",exportCleanup:c(r=>(delete r.dataSourceId,r),"exportCleanup")},[T.Flow]:{element:"flow",elements:"flows",integrationSpecific:!0,parentKey:"universalFlowId"},[T.Package]:{element:"package",elements:"packages",integrationSpecific:!0}},Nr=["id","workspaceId","integrationId","createdAt","updatedAt","revision","archivedAt","baseUri","state","appliedToIntegrations","dependencies"],Gt=[T.Action,T.FieldMapping,T.Flow,T.DataSource,T.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[T.Integration].apiPath;return x.join(t,this.integrationKey,e,this.key)}return x.join(e,this.key)}get path(){return x.join(this.dirPath,"spec.yaml")}get relativePath(){return x.relative(q(process.cwd()),this.path)}get absolutePath(){return x.resolve(x.join(q(process.cwd()),this.path))}isEqual(e){if(this.id!==e.id)return!1;const t=this.clean(),n=e.clean();return Zn(t,n)}hasParent(){if(this.data?.parentUuid)return!0;const e=this.getParentKey();return!!e&&!!this.data?.[e]}clean(){const e={...this.data};return Nr.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===T.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,f=this.getElementTypeFromPath(d);if(f)return{type:f,key:h,integrationKey:l}}}static extractIntegrationKey(e){return e?.integrationKey||e?.integration?.key||e?.integration_key||void 0}static isElementFile(e){return e.endsWith(".yml")||e.endsWith(".yaml")}static getElementTypeFromPath(e){return Object.values(T).find(t=>V[t].apiPath===e)}static getRelativePath(e){return x.relative(q(process.cwd()),e)}static isIntegrationSpecific(e){return Gt.includes(e)}static canBeIntegrationSpecific(e){return Gt.includes(e)}}class Ht{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=[T.Integration,T.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 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 nt(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=x.relative(process.cwd(),r);throw new Error(`Failed to parse YAML file "${n}": ${t.message}`)}throw t}}c(nt,"readYaml$1");function Mr(r,e,t){try{const n=G.dump(e,t);v.writeFileSync(r,n,"utf8")}catch(n){if(n instanceof Error){const o=x.relative(process.cwd(),r);throw new Error(`Failed to write YAML file "${o}": ${n.message}`)}throw n}}c(Mr,"writeYaml$1");class Fr extends Ht{static{c(this,"LocalWorkspaceElementsRepository")}basePath;constructor(e){super(e),this.basePath=q(process.cwd())}async getElementsByType(e,t){const n=[],o=x.join(this.basePath,V[e].apiPath),i=await this.readElementsInDir(o);n.push(...i);for(const s of t){const a=x.join(this.basePath,V[T.Integration].apiPath,s.key,V[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=x.join(this.basePath,t.dirPath),o=x.join(this.basePath,t.path);return v.existsSync(n)||v.mkdirSync(n,{recursive:!0}),Mr(o,e.data),m.debug(`[local] Written ${t.relativePath}`),t}async deleteElement(e){const t=x.join(this.basePath,e.path),n=x.join(this.basePath,e.dirPath);v.existsSync(t)&&v.rmSync(t,{force:!0}),this.pruneEmptyDir(n),m.debug(`[local] Deleted ${e.relativePath}`)}async getIntegrations(){const e=x.join(this.basePath,V[T.Integration].apiPath);return this.readElementsInDir(e)}async readElement(e){const t=nt(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=x.join(e,s,"spec.yaml");return this.readElement(a)});return(await Promise.all(o)).filter(s=>s!=null)}pruneEmptyDir(e){try{if(!e.startsWith(this.basePath)||e===this.basePath||!v.existsSync(e)||v.readdirSync(e).length>0)return;v.rmdirSync(e),this.pruneEmptyDir(x.dirname(e))}catch(t){console.warn(`Failed to prune empty directory ${e}:`,t)}}}class Lr extends Ht{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&&m.debug(`[remote] Fetched ${o.length} ${e}${o.length!==1?"s":""}`),o}async getElement(e){const t=await $.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 $.withClient(s=>s[z[e.type].elements].create(n)),i=M.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[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 m.debug(`[remote] Skipped update for ${t.id} (non-customized)`),t;const i=await $.withClient(a=>a[z[e.type].element](t.data.id).put(o)),s=M.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[z[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=>M.fromData(T.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[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===T.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===T.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===T.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===T.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!==T.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[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 rt extends nr{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"},jr={ignored:Pr,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 Ur extends rt{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=er.watch(this.membraneDir,jr),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=x.resolve(e);this.ignoredPaths.add(n);try{await t()}finally{setTimeout(()=>{this.ignoredPaths.delete(n)},this.lockTimeoutMs)}}isPathLocked(e){const t=x.resolve(e);if(this.ignoredPaths.has(t))return!0;for(const n of this.ignoredPaths)if(t.startsWith(n+x.sep))return!0;return!1}clearAllLocks(){this.ignoredPaths.clear()}handleFileSystemEvent(e,t){const n=x.relative(this.membraneDir,t);if(this.isPathLocked(t))return;if(e===_.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=x.relative(this.membraneDir,e);let o;try{o=t?tr.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 Xn.createHash("sha256").update(e).digest("hex")}updateCache(e,t){if(!t){delete this.contentCache[e];return}this.contentCache[e]=this.getContentHash(t)}removeFromCache(e){delete this.contentCache[e]}clearCache(){Object.keys(this.contentCache).forEach(e=>{delete this.contentCache[e]})}initializeContentCache(){v.existsSync(this.membraneDir)&&this.scanDirectoryForCache(this.membraneDir)}scanDirectoryForCache(e){const t=v.readdirSync(e,{withFileTypes:!0});for(const n of t){const o=x.join(e,n.name);if(n.isDirectory())this.scanDirectoryForCache(o);else if(n.isFile())try{const i=v.readFileSync(o,"utf8"),s=x.relative(this.membraneDir,o);this.updateCache(s,i)}catch{}}}}var ot=(r=>(r.Updated="updated",r.ConnectorFileUpdated="connector-file-updated",r.Connected="connected",r.Disconnected="disconnected",r.Error="error",r))(ot||{});const Kr={debounceMs:2e3,reconnectIntervalMs:5e3,maxReconnectAttempts:1/0,maxBackoffMs:6e4,connectionTimeoutMs:3e5};class qr extends rt{static{c(this,"RemoteElementWatcher")}constructor(e=Kr){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 rr(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!==Mn.ElementUpdate)return;const{elementId:t,elementType:n,data:o={}}=e;if(!(!t||!n)){if(n===T.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 zt{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",it={};async function Vt(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=ee(),l=(P.existsSync(s)?P.readdirSync(s):[]).filter(d=>{if(d.startsWith("."))return!1;const h=I.join(s,d);try{return P.statSync(h).isDirectory()}catch{return!1}});for(const d of l){m.info(`[connectors] Loading connector from: ${d}`);const h=P.readdirSync(I.join(s,d)),f=await st(d);if(!f)continue;e?.("pushing",f.name),"baseUri"in f&&delete f.baseUri;let p;if(f.uuid&&(p=await $.withClient(E=>E.get(`/connectors/${f.uuid}`),!1)),p)i[f.id]=p.id,m.info(`[connectors] Matched ${f.name} uuid: ${f.uuid}`),p.isPublic||(p.archivedAt&&(m.info(`[connectors] Restoring archived connector ${f.name}`),await $.withClient(E=>E.post(`connectors/${p.id}/restore`))),m.info(`[connectors] Updating connector ${f.name}`),await $.withClient(E=>E.patch(`connectors/${p.id}`,{...f,workspaceId:o})));else if(!i[f.id]&&!p?.isPublic){let E=!1;try{const S=await at({connectorId:f.id});S&&S.isPublic&&(E=!0)}catch{}if(!E){m.info(`[connectors] Creating custom connector ${f.name} (${f.key})`);const S=await $.withClient(N=>N.post("connectors",{...f,workspaceId:o}));i[f.id]=S.id}}const C=h.filter(E=>P.statSync(I.join(s,d,E)).isDirectory());for(const E of C)await Wr({connector:f,version:E,connectorId:i[f.id]}),t.add(f.id);e?.("pushed",f.name)}return{connectorsMapping:i,pushedConnectors:Array.from(t)}}c(Vt,"pushConnectors");async function Yt({connectorId:r,connectorVersion:e,allConnectors:t,pulledConnectors:n,pulledConnectorVersions:o}){if(!r||o[r]?.has(e))return;const i=jt(),s=await at({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 Jr({basePath:i,connector:s}),n.add(r)),o[r]||(o[r]=new Set),o[r].has(e)||(await Gr({connector:s,connectorVersion:e,basePath:i}),o[r].add(e))}}c(Yt,"pullRemoteConnector");function ee(){const r=tt();return I.join(r.membraneDirPath,pe)}c(ee,"getConnectorsPath");async function st(r){const e=I.join(ee(),r,`${r}.yml`);return nt(e,!1)}c(st,"readConnector");async function Br(r,e){return m.info(`[connectors] Zipping ${r} into ${e}`),new Promise((t,n)=>{const o=P.createWriteStream(e),i=Dt("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=P.readdirSync(r);for(const a of s){const l=I.join(r,a),d=P.statSync(l);d.isFile()?i.file(l,{name:a}):d.isDirectory()&&i.directory(l,a)}i.finalize()})}c(Br,"createZipArchive");async function _r(r,e){return m.info(`[connectors] Unzipping into ${e}`),new Promise((t,n)=>{const o=ke.Parse();o.on("entry",i=>{const s=i.path;if(i.type==="Directory"){const l=I.join(e,s);P.mkdirSync(l,{recursive:!0}),i.autodrain()}else{const l=I.join(e,s),d=I.dirname(l);P.mkdirSync(d,{recursive:!0});const h=P.createWriteStream(l);i.pipe(h),h.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(_r,"extractZipArchive");async function Wr({connector:r,version:e,connectorId:t}){const n=I.join(ee(),Q(r),Zt(e)),o=I.join(n,"src"),i=I.join(n,"src.zip"),s=P.existsSync(i);if(P.existsSync(o)&&(m.info(`[connectors] Archiving source code for ${r.name} version ${e}`),await Br(o,i)),!P.existsSync(i)){m.warning(`[connectors] No source code found for ${r.name} version ${e}`);return}try{const a=new Ot;if(a.append("file",P.createReadStream(i),"file.zip"),m.info(`[connectors] Pushing connector version ${e} for ${r.name}`),e==X)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&&P.existsSync(i)&&(m.info(`[connectors] Cleaning up temporary zip file for ${r.name} version ${e}`),P.unlinkSync(i))}}c(Wr,"pushConnectorVersion");async function at({connectorId:r}){if(r){if(it[r])return it[r];try{const e=await $.withClient(t=>t.get(`connectors/${r}`),!1);return it[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(at,"getConnector");async function Jr({basePath:r,connector:e}){const t=Q(e),n=I.join(r,pe,t);P.mkdirSync(n,{recursive:!0});const o=I.join(n,`${Q(e)}.yml`);P.writeFileSync(o,G.dump(e)),m.info(`[connectors] Pulled connector ${e.name}`)}c(Jr,"pullConnector$1");async function Gr({connector:r,connectorVersion:e,basePath:t}){const n=Q(r),o=Zt(e),i=I.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}));P.mkdirSync(i,{recursive:!0});const a=I.join(i,"src.zip");if(P.writeFileSync(a,s),!e){const l=I.join(i,"src");P.mkdirSync(l,{recursive:!0}),await _r(s,l)}m.info(`[connectors] Pulled connector version: ${r.name} (${o})`)}c(Gr,"pullConnectorVersion");function Q(r){return r.key}c(Q,"getConnectorDirName");function Zt(r){return r??X}c(Zt,"getConnectorVersionDirName");function Hr(r){const e=jt(),t=Q(r);return I.join(e,pe,t)}c(Hr,"getConnectorDirPath");function zr(r){return r.match(`${pe}/[^/]+/${X}/src/.*`)!==null}c(zr,"isConnectorSourceFile");async function Vr(r){const e=r.match(`${pe}/([^/]+)/${X}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await st(t);if(!o){m.warning(`[connectors] Connector ${t} not found. Ignoring file change`);return}const i=o.id,s=P.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(Vr,"putConnectorFile");async function Yr(r){const e=r.match(`${pe}/([^/]+)/${X}/src/(.*)`);if(!e)return;const t=e[1],n=e[2],o=await st(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(Yr,"deleteConnectorFile");async function Zr(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=Q(t),i=I.join(ee(),o,X,"src",e);P.mkdirSync(I.dirname(i),{recursive:!0}),n!=null?(P.writeFileSync(i,n),m.info(`[connectors] Pulled file ${e} for connector ${t.name}`)):P.existsSync(i)&&(P.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(Zr,"pullConnectorFile");async function Xr(r,e){const t=await $.withClient(i=>i.get(`connectors/${r}`),!1);if(!t){m.warning(`[connectors] Connector ${r} not found`);return}const n=Q(t),o=I.join(ee(),n,X,"src",e);P.existsSync(o)&&(P.unlinkSync(o),m.info(`[connectors] Deleted file ${e} for connector ${n}`))}c(Xr,"deleteLocalConnectorFile");async function Qr(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=Q(n),i=I.join(ee(),o,X,"src"),s=I.join(i,e),a=I.join(i,t);P.existsSync(s)&&(P.mkdirSync(I.dirname(a),{recursive:!0}),P.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(Qr,"renameLocalConnectorDirectory");async function eo(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=Q(t),o=I.join(ee(),n,X,"src",e);if(P.existsSync(o)){const i=I.resolve(ee());if(!I.resolve(o).startsWith(i))return;P.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(eo,"deleteLocalConnectorDirectory");const F={LogAdded:"logAdded",StateChanged:"stateChanged",StatsChanged:"statsChanged",ConflictsChanged:"conflictsChanged",McpStatusChanged:"mcpStatusChanged",McpServersChanged:"mcpServersChanged",ConfigChanged:"configChanged"};class to extends rt{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(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 $.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:At.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 te=new to({heartbeatIntervalMs:15e3}),Xt=[T.AppDataSchema,T.AppEventType,T.DataLinkTable,T.DataSource,T.FieldMapping,T.Action,T.Flow,T.Package];class Ee{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 zt,this.remoteCache=new zt,this.localRepo=new Fr(this.localCache),this.remoteRepo=new Lr(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(T.Integration).map(n=>n.data);for(const n of t){const o=n.connectorId,i=n.connectorVersion;o&&await Yt({connectorId:o,connectorVersion:i,allConnectors:e,pulledConnectors:this.pulledConnectors,pulledConnectorVersions:this.pulledConnectorVersions})}}async pushConnectors(){const{connectorsMapping:e}=await Vt();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 Ur({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(),m.success("[local] Tracking changes.."),this.remoteWatcher=new qr,this.remoteWatcher.on(ot.Updated,({elementId:e,elementType:t})=>this.handleRemoteElementEvent(e,t)),this.remoteWatcher.on(ot.ConnectorFileUpdated,({connectorId:e,filePath:t,eventType:n,newPath:o})=>this.handleRemoteConnectorFileEvent(e,t,n,o)),await this.remoteWatcher.start(),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===T.Integration){const s=n.data.connectorId,a=n.data.connectorVersion,l=await at({connectorId:s});if(!l?.key)return;const d=Hr(l);await this.localWatcher?.executeWithPathLock(d,async()=>Yt({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 Fe.ConnectorFileDeleted:await Xr(e,t);break;case Fe.ConnectorDirectoryRenamed:await Qr(e,t,o);break;case Fe.ConnectorDirectoryDeleted:await eo(e,t);break;default:await Zr(e,t);break}}catch(i){m.error(`[sync] Error handling remote connector file event: ${i}`)}}async handleLocalEvent(e,t){try{if(zr(e.filePath))switch(t){case _.Updated:await Vr(e.filePath);break;case _.Deleted:await Yr(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(m.info(`[${this.getDirectionLabel(B.OUTGOING)}] ${Yn(t)}: ${n.id}`),t){case _.Updated:await this.updateElement(n,B.OUTGOING);break;case _.Deleted:await this.deleteElement(n,B.OUTGOING);break}}}catch(n){m.error(`[sync] Error handling local event: ${n}`)}}detectIncomingChanges(){this.clearChanges();const e=Ee.getChanges(B.INCOMING,this.remoteCache,this.localCache);return this.updateChanges(e),e}detectOutgoingChanges(){this.clearChanges();const e=Ee.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===T.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!==T.Integration)),m.info("[resolver] Resolving universal elements");const t=this.changes.filter(o=>!o.element.hasParent());for(const o of Xt){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 Xt){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 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),f=Ee.detectChangeForElement(d,h,e);f&&a.push(f)}return a}updateChanges(e){if(this.changes=e,this.needsForcedSync()){const t=e.filter(n=>n.isConflict);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: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=x.join(or.tmpdir(),"membrane-mcp-status"),Qt=3e4;class no{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=Ae(void 0,e),n=en(e);t&&te.setMcpStatus(t),await te.setMcpServers(n)}catch{m.error("Failed to check MCP status")}}}function Ae(r,e){try{const t=e||process.cwd();if(!r){const o=en(t);return o.length===0?null:o[0]}const n=ut(r,t);if(v.existsSync(n)){const o=v.statSync(n),i=new Date;if(i.getTime()-o.mtime.getTime()>Qt)return Ce(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>Qt)return Ce(r,t),null}return l}}catch{r&&e&&Ce(r,e)}return null}c(Ae,"getMcpStatus");function en(r){try{const e=r||process.cwd(),t=lt(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=Ae(a,e);l&&o.push(l)}}return o.sort((i,s)=>new Date(s.startTime).getTime()-new Date(i.startTime).getTime())}catch{return[]}}c(en,"getAllMcpStatusFiles");function ct(r){try{const t={...Ae(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=ut(r.processId,r.cwd);v.writeFileSync(n,JSON.stringify(t,null,2))}catch{}}c(ct,"updateMcpStatus");function Ce(r,e){try{const t=e||process.cwd();if(r){const n=ut(r,t);v.existsSync(n)&&v.unlinkSync(n)}else{const n=lt(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(x.join(ne,i))}}}catch{}}c(Ce,"clearMcpStatus");function ro(r,e){const t=Ae(r,e);t&&ct({processId:r,cwd:e,totalRequests:t.totalRequests+1,lastRequestTime:new Date().toISOString(),lastActivity:new Date().toISOString()})}c(ro,"trackToolExecution");function lt(r){return Qn("md5").update(r).digest("hex").slice(0,8)}c(lt,"getCwdHash");function ut(r,e){const t=lt(e);return x.join(ne,`mcp-${t}-${r}.json`)}c(ut,"getStatusFilePath");const De={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 oo{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 no,this.syncService=new Ee,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(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,m.error(`Failed to pull workspace: ${n}`),await this.notifier.setState(k.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(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,m.error(`Failed to push workspace: ${n}`),await this.notifier.setState(k.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(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){m.error(`Failed to sync local and remote workspaces: ${t}`),await this.notifier.setState(k.ERROR),m.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){m.error(`Failed to initialize services: ${t}`),await this.notifier.setState(k.ERROR),m.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===De.Agent&&(await this.notifier.cleanup(),await this.mcpStatusService.stop()),this.initialized=!1,this.onShutdown())}async initServices(){this.mode===De.Agent&&(await this.notifier.connectToRemote(),await this.mcpStatusService.start()),this.syncService.clear()}async stopServices(){this.mode===De.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 tn=Be(null);function io({children:r,membraneCLIService:e}){const{data:t}=Pt("/account"),[n,o]=D(k.NOT_INITIALIZED),[i,s]=D([]),[a,l]=D({}),[d,h]=D([]),[f,p]=D(null),E=t?.workspaces?.find(S=>S.workspaceKey===f?.workspaceKey)||null;return he(()=>{const S=c(({state:L})=>o(L),"handleStateChanged"),N=c(({stats:L})=>l(L),"handleStatsChanged"),O=c(({log:L})=>h(Te=>[...Te,L]),"handleLogAdded"),U=c(({conflicts:L})=>s(L),"handleConflictsUpdated"),K=c(({config:L})=>p(L),"handleConfigChanged");return e.notifier.on(F.StateChanged,S),e.notifier.on(F.StatsChanged,N),e.notifier.on(F.LogAdded,O),e.notifier.on(F.ConflictsChanged,U),e.notifier.on(F.ConfigChanged,K),e.init(),()=>{e.notifier.off(F.StateChanged,S),e.notifier.off(F.StatsChanged,N),e.notifier.off(F.LogAdded,O),e.notifier.off(F.ConflictsChanged,U),e.notifier.off(F.ConfigChanged,K)}},[]),u(tn.Provider,{value:{state:n,stats:a,logs:d,currentWorkspace:E,conflicts:i,config:f,updateConfig:c(S=>e.updateConfig(S),"updateConfig"),resolveConflicts:c(S=>e.syncWorkspaces(S),"resolveConflicts"),pull:c(S=>e.pullWorkspace(S),"pull"),push:c(S=>e.pushWorkspace(S),"push"),exit:c(()=>e.shutdown(),"exit"),fetchElements:c(()=>e.fetchElements(),"fetchElements"),getSyncedElementsByType:c(S=>e.getSyncedElementsByType(S),"getSyncedElementsByType")},children:r})}c(io,"MembraneCLIServiceProvider");function H(){const r=_e(tn);if(!r)throw new Error("useMembraneCLIService must be used within MembraneCLIServiceProvider");return r}c(H,"useMembraneCLIService");const dt=Be(null),nn=c(()=>{const r=_e(dt);if(!r)throw new Error("useTree must be used within TreeView");return r},"useTree"),so=c(r=>se.Children.count(r)>0,"hasChildren");function ao(r){const e=nn(),{label:t,value:n,isInitiallyExpanded:o}=r,i=Wn(),s=We(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:f}=r,p=typeof f=="function"?f(h):f;return{...h,props:{...r,children:p},isParent:so(p)}}c(ao,"useTreeItem");function fe(r){const e=nn(),t=ao(r),{expanded:n,isParent:o,props:{children:i},setExpanded:s}=t,{renderValue:a=lo}=r,l=t.ref;Ie(()=>{function p(C){return r.onInput?.(C)?!0:C.active&&C.key.rightArrow&&!n?(s(!0),!0):C.active&&C.key.leftArrow&&n?(s(!1),!0):!1}c(p,"onInput"),l.onInput=p},[l,r.onInput,n,s]),l.firstChild??={parent:l,index:0};let d=l.firstChild;function h(p){const C=d;return C.nextSibling||(C.nextSibling={parent:l,prevSibling:C,index:C.index+1}),d=C.nextSibling,C.label=p,C}c(h,"registerChildItem");function f(){l.lastRenderedChild=d.prevSibling}return c(f,"commitChildren"),Ie(()=>{f()}),b($e,{children:[b(g,{marginLeft:e.depth*2,children:[u(g,{width:2,children:o&&u(y,{children:n?"\u25BC":"\u25B6"})}),co(t),a(t)]}),n&&u(dt.Provider,{value:{...e,depth:e.depth+1,registerChildItem:h},children:i})]})}c(fe,"TreeItem");function co({active:r,label:e}){return u(g,{width:32,children:u(y,{inverse:r,children:e})})}c(co,"defaultRenderLabel");function lo(r){return u(y,{})}c(lo,"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"),rn=c(({label:r,value:e,onChange:t,disabled:n=!1,mask:o,...i})=>{const[s,a]=D(e),[l,d]=D(!1);return Ie(()=>{l||a(e)},[l,e]),u(fe,{label:r,value:e,onInput:c(({key:h,active:f})=>n?!1:l?(h.escape&&d(!1),h.return&&(t(s),d(!1)),!0):f&&h.return?(d(!0),a(e),!0):!1,"onInput"),renderValue:c(()=>{const h=s,f=o?o.repeat(h.length):h;return u(g,{children:n||!l?u(y,{dimColor:!0,children:f}):b($e,{children:[u(g,{width:f.length+1,children:u(Nt,{...i,focus:l,value:h,onChange:a})}),u(y,{dimColor:!0,children:" \u241B cancel"})]})})},"renderValue")})},"TreeTextField"),uo=c(r=>u(rn,{...r,mask:"*"}),"SecretField"),W=c(({children:r,showHelp:e=!1})=>{const t=We({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};Ie(()=>{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 f of s(t.current))if(f.label!=null){if(d===n&&(h=f),f&&f.onInput?.({input:a,key:l,active:f===n}))return;d=f}l.upArrow?o(f=>f.prevSibling?.lastRenderedChild??f.prevSibling??f.parent??t.current):l.downArrow?o(f=>h??f):l.pageUp?o(()=>t.current.firstChild??t.current):l.pageDown?o(()=>t.current.lastRenderedChild??t.current):l.tab?console.debug({label:n.label,nextSibling:n.nextSibling?.label,prevSibling:n.prevSibling?.label,parent:n.parent?.label,firstChild:n.firstChild?.label,lastRenderedChild:n.lastRenderedChild?.label}):l.leftArrow?o(f=>f.parent??t.current):l.rightArrow&&o(f=>f.lastRenderedChild?f.firstChild:f)}),u(dt.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=rn;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(f=>f.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===T.Action&&b($e,{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 ho({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,C)=>{try{await t({[p]:C}),l("\u2705 Configuration updated!")}catch{l("\u274C Error updating configuration")}},"updateField"),h=c(async()=>{try{if(e){const p=le.saveToFile(e);l(p?"\u2705 Configuration saved successfully!":"\u274C Failed to save configuration"),await n();const C=o(T.Action);await Ze({out:a?.outputDir??"",target:a?.projectType??"typescript",schemasOnly:!1,membraneInterfaces:{actions:C.filter(E=>!a?.excludedActionKeys?.includes(E.key)).map(E=>E.data)}}),l("\u2705 Code generated successfully!")}}catch{l("\u274C Error saving configuration")}},"handleSaveConfig"),f=c(async()=>{try{const p=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(uo,{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:T.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 Ze({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:T.Flow}),u(de,{label:"Data Sources",elementType:T.DataSource}),u(de,{label:"Field Mappings",elementType:T.FieldMapping}),u(de,{label:"Packages",elementType:T.Package}),u(de,{label:"App Data Schemas",elementType:T.AppDataSchema}),u(de,{label:"App Event Types",elementType:T.AppEventType})]})]}),u(ue,{label:"Save Configuration",onPress:h,hotkey:"s"}),u(ue,{label:"Reload Configuration",onPress:f,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(ho,"ConfigManager");const on=Be(process.cwd());function po({cwd:r,children:e}){return u(on.Provider,{value:r,children:e})}c(po,"CwdProvider");function fo(){return _e(on)}c(fo,"useCwd");function ht({cwd:r,children:e,membraneCLIService:t}){const n=r||process.cwd();return u(po,{cwd:n,children:u(ir,{value:{fetcher:kr()},children:u(io,{membraneCLIService:t,children:e})})})}c(ht,"Layout");function mo(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(()=>{Je(se.createElement(ht,{membraneCLIService:e,children:se.createElement(ho,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(mo,"setupConfigCommand");function go({currentPat:r,onSubmit:e}){const[t,n]=D(""),[o,i]=D(!1),[s,a]=D(null),l=et(`/w/0/${Fn}`);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(Nt,{mask:"*",placeholder:`${r?"******":"Enter your token here..."}`,value:t,onChange:n,onSubmit:c(async h=>{a(null),i(!0);try{await e(h),n("")}catch{a("Invalid token. Please try again.")}finally{i(!1)}},"handleSubmit")}),o&&u(g,{marginTop:1,children:b(y,{children:[u(Re,{type:"dots"})," Validating token..."]})}),s&&u(y,{color:"red",children:s})]})}c(go,"PersonalAccessTokenInput");function sn({onExit:r,showEscOption:e=!0}){const[t,n]=D(""),{data:o,error:i,isLoading:s}=Pt("/account"),{updateConfig:a}=H(),l=o?.workspaces,d=s;if(ae((S,N)=>{N.escape&&r?.()}),d)return b(g,{children:[u(Re,{}),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 h=l?.filter(S=>S.name.toLowerCase().includes(t.toLowerCase()))??[],f=h.map(S=>({label:S.name,value:S.id})),p=f.length,C=l?.length??0;async function E(S){const N=h.find(K=>K.id===S);if(!N)return;const{key:O,secret:U}=N;!O||!U||(await a({workspaceKey:O,workspaceSecret:U}),r?.())}return c(E,"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(sr,{placeholder:"Enter a search query...",onChange:n})]}),C>5&&b(y,{children:["Showing ",p," of ",C," workspaces."]}),u(g,{marginTop:1,children:u(ar,{options:f,onChange:c(S=>{S&&E(S)},"onChange")})}),e&&u(g,{marginTop:1,children:u(y,{color:"grey",children:"Press ESC to go back"})})]})}c(sn,"SelectWorkspace");var Se=(r=>(r[r.Authenticate=0]="Authenticate",r[r.ConnectWorkspace=1]="ConnectWorkspace",r))(Se||{});const yo={0:"Authenticate in Membrane",1:"Connect a Membrane Workspace"},pt=[Se.Authenticate,Se.ConnectWorkspace];function an({onComplete:r}){const{config:e}=H(),[t,n]=D(!1),[o,i]=D(0),s=!!(e?.workspaceKey&&e?.workspaceSecret),a=Kt(),l=pt[o],d=o+1,h=pt.length,f=pt.map((E,S)=>{let N="pending";return S<o?N="done":S===o&&(N="current"),{id:E,label:yo[E],status:N}});async function p(E){const S=a&&E===""?a:E,N=new qt;try{await N.request("/account",{headers:{Authorization:`Bearer ${S}`}}),$r(S),i(O=>O+1)}catch(O){console.error(O)}}c(p,"handlePatSubmit");function C(){n(!0),r&&r()}return c(C,"handleWorkspaceSelected"),ae((E,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 ",h]}),s&&u(y,{color:"grey",children:" [esc: go back]"})]})}),u(g,{flexDirection:"column",paddingLeft:2,children:f.map(E=>u(wo,{status:E.status,label:E.label},E.id))})]}),l===Se.Authenticate&&u(go,{currentPat:a,onSubmit:p}),l===Se.ConnectWorkspace&&u(sn,{onExit:C,showEscOption:!1})]})}c(an,"Setup");function wo({status:r,label:e}){return b(g,{children:[b(g,{width:2,children:[r==="current"&&u(Re,{type:"dots"}),r==="done"&&u(y,{children:"\u2705"})]}),u(y,{dimColor:r!=="current",children:e})]})}c(wo,"StepDisplay");function Co(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?le.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)):Je(se.createElement(ht,{membraneCLIService:e,children:se.createElement(an,{onComplete:c(()=>process.exit(0),"onComplete")})}))})}c(Co,"setupInitCommand");const So=86400;async function bo(r,e,t,n){const o={iss:r,isAdmin:!0};return t&&(o.id=t),Ge.sign(o,e,{expiresIn:So})}c(bo,"generateMcpAccessToken");async function vo(r,e){return(await ge.get(`${r}/docs-json`,{headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}})).data}c(vo,"fetchOpenApiSchema");function re(r,e=!0,t,n=new Set){if(!r)return e?A.string():A.string().optional();if(Object.keys(r).length===0)return e?A.any():A.any().optional();if(r.$ref){const i=r.$ref.replace("#/components/schemas/","");if(n.has(i))return A.any();if(n.add(i),t?.schemas?.[i]){const s=t.schemas[i];return re(s,e,t,n)}return A.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]=re(a,l,t,n)}if(Object.keys(i).length>0){if(o=A.object(i),r.additionalProperties)if(typeof r.additionalProperties=="object"){const s=re(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=re(r.additionalProperties,!1,t,n);o=A.record(A.string(),s)}else o=A.record(A.string(),A.any())}else if(r.type==="array"){const i=r.items?re(r.items,!0,t,n):A.any();o=A.array(i)}else if(r.anyOf)o=A.any();else{switch(r.type){case"integer":o=A.coerce.number().int();break;case"number":o=A.coerce.number();break;case"boolean":o=A.coerce.boolean();break;case"string":default:o=A.string();break}r.format==="uuid"?o=A.string().uuid():r.format==="email"?o=A.string().email():r.format==="date"?o=A.string().regex(/^\d{4}-\d{2}-\d{2}$/):r.format==="date-time"&&(o=A.string().datetime()),r.enum&&(o=A.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(re,"convertOpenApiSchemaToZod");function cn(r){const e=r.match(/\{([^}]+)\}/g);return e?e.map(t=>t.slice(1,-1)):[]}c(cn,"extractPathParameters");function Eo(r,e,t,n,o,i){const s=r.operationId||`${t}_${e.replace(/[^a-zA-Z0-9]/g,"_")}`,a=r.description||r.summary||`${t.toUpperCase()} ${e}`,l={},d={},h={};if(r.parameters){for(const p of r.parameters)if(p.in==="path")d[p.name]=re(p.schema,!0,o).describe(p.description||`Path parameter: ${p.name}`);else if(p.in==="query"){const C=p.required===!0;h[p.name]=re(p.schema,C,o).describe(p.description||`Query parameter: ${p.name}`)}}if(Object.keys(d).length>0&&(l.params=A.object(d).describe("Path parameters")),Object.keys(h).length>0&&(l.query=A.object(h).describe("Query parameters")),r.requestBody&&r.requestBody.content){const p=r.requestBody.required===!0;if(r.requestBody.content["application/json"]){const C=r.requestBody.content["application/json"].schema;C?l.body=re(C,p,o).describe("Request body (JSON)"):l.body=A.any().describe("Request body (JSON)")}else r.requestBody.content["application/octet-stream"]||r.requestBody.content["text/plain"]?l.body=p?A.string().describe("Request body (binary/text)"):A.string().optional().describe("Request body (binary/text)"):l.body=A.any().describe("Request body")}const f=Object.keys(l).length>0?A.object(l):A.object({});return{name:s,description:a,parameters:f,async execute(p){try{const C=cn(e);if(C.length>0){if(!p.params)throw new Error(`Missing required path parameters: ${C.join(", ")}`);const K=C.filter(L=>!(L in p.params));if(K.length>0)throw new Error(`Missing required path parameters: ${K.join(", ")}`)}let E=`${n}${e}`;if(p.params)for(const[K,L]of Object.entries(p.params)){const Te=`{${K}}`;E.includes(Te)&&(E=E.replace(Te,String(L)))}const S=cn(E);if(S.length>0)throw new Error(`Unresolved path parameters: ${S.join(", ")}`);const N=new URLSearchParams;if(p.query)for(const[K,L]of Object.entries(p.query))L!=null&&N.append(K,String(L));N.toString()&&(E+=`?${N.toString()}`);const O={method:t.toUpperCase(),headers:{Authorization:`Bearer ${i}`}};p.body&&t.toLowerCase()!=="get"&&(r.requestBody?.content?.["application/json"]?(O.headers["Content-Type"]="application/json",O.data=p.body):r.requestBody?.content?.["application/octet-stream"]?(O.headers["Content-Type"]="application/octet-stream",O.data=p.body):r.requestBody?.content?.["text/plain"]?(O.headers["Content-Type"]="text/plain",O.data=p.body):(O.headers["Content-Type"]="application/json",O.data=p.body));const U=await ge.request({url:E,...O});return{content:[{type:"text",text:U.data===""?"":JSON.stringify(U.data,null,2)}]}}catch(C){return ge.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(Eo,"createApiTool");function To(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=Eo(l,i,a,e,o,t);n.push(d)}}return n}c(To,"convertOpenApiToTools");function xo(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(`
12
+ `)).action(async()=>{try{process.env.FASTMCP_SUPPRESS_WARNINGS="true";const e=we(),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||Qe;!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 bo(n,o,i),l=await vo(s,a),d=To(l,s,a),h=new lr({name:"Membrane API",instructions:`This MCP server lets you interact with Membrane to configure, run, and troubleshoot integrations.
13
13
  Use it for anything related to Membrane or integrations.
14
- `,version:"1.0.0"});for(const C of d){const E=C.execute;C.execute=async S=>(Xr(process.pid,process.cwd()),E(S)),h.addTool(C)}it({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 p=setInterval(()=>{it({processId:process.pid,cwd:process.cwd(),lastActivity:new Date().toISOString()})},5e3),f=c(async()=>{clearInterval(p),we(process.pid,process.cwd());try{await h.stop()}catch{}},"cleanup");await h.start({transportType:"stdio"}),process.on("SIGINT",async()=>{await f(),process.exit(0)}),process.on("SIGTERM",async()=>{await f(),process.exit(0)}),process.on("exit",()=>{we(process.pid,process.cwd())}),process.on("uncaughtException",async C=>{console.error("Uncaught exception:",C.message),await f(),process.exit(1)}),process.on("unhandledRejection",async C=>{console.error("Unhandled rejection:",C),await f(),process.exit(1)})}catch(e){e instanceof Error&&(console.error(e.message),process.exit(1)),console.error("An unknown error occurred"),process.exit(1)}})}c(So,"setupMcpCommand");const bo={info:"\u{1F4DD}",success:"\u2728",warning:"\u26A0\uFE0F",error:"\u274C",debug:"\u{1F50D}"},vo={info:w.white,success:w.green,warning:w.yellow,error:w.red,debug:w.gray};class k{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=bo[t],l=vo[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?`
14
+ `,version:"1.0.0"});for(const C of d){const E=C.execute;C.execute=async S=>(ro(process.pid,process.cwd()),E(S)),h.addTool(C)}ct({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(()=>{ct({processId:process.pid,cwd:process.cwd(),lastActivity:new Date().toISOString()})},5e3),p=c(async()=>{clearInterval(f),Ce(process.pid,process.cwd());try{await h.stop()}catch{}},"cleanup");await h.start({transportType:"stdio"}),process.on("SIGINT",async()=>{await p(),process.exit(0)}),process.on("SIGTERM",async()=>{await p(),process.exit(0)}),process.on("exit",()=>{Ce(process.pid,process.cwd())}),process.on("uncaughtException",async C=>{console.error("Uncaught exception:",C.message),await p(),process.exit(1)}),process.on("unhandledRejection",async C=>{console.error("Unhandled rejection:",C),await p(),process.exit(1)})}catch(e){e instanceof Error&&(console.error(e.message),process.exit(1)),console.error("An unknown error occurred"),process.exit(1)}})}c(xo,"setupMcpCommand");const Io={info:"\u{1F4DD}",success:"\u2728",warning:"\u26A0\uFE0F",error:"\u274C",debug:"\u{1F50D}"},$o={info:w.white,success:w.green,warning:w.yellow,error:w.red,debug:w.gray};class R{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=Io[t],l=$o[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?`
15
15
  ${w.red(t.error)}`:""):console.debug(w.gray(e),t?.error?`
16
- ${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(){}}function Eo(r){r.command("open").description("Open the workspace in the browser").addHelpText("after",["","Examples:"," membrane open # Open workspace in browser",""].join(`
17
- `)).action(async()=>{try{k.header("Opening Workspace in Browser"),k.info("Loading configuration...");const e=$e();if(!e)throw new Error("No configuration found. Please set MEMBRANE_WORKSPACE_KEY and MEMBRANE_WORKSPACE_SECRET environment variables, or run `membrane init` first.");if(!e.workspaceKey||!e.workspaceSecret)throw new Error("Missing workspace credentials");k.info("Retrieving workspace ID...");const t=await Bt(process.cwd()),n=`${e.consoleUri||Sr}/w/${t}`;k.info(`Opening ${n}...`);const{default:o}=await import("open");await o(n),k.success("Browser opened successfully")}catch(e){e instanceof Error&&(k.error(e.message),process.exit(1)),k.error("An unknown error occurred"),process.exit(1)}})}c(Eo,"setupOpenCommand");async function dt(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 h=0;for(;;){if(Date.now()-s>l)throw new Error(`Background job ${n} timed out after ${l}ms`);await new Promise(C=>setTimeout(C,a));let f;try{f=await r.get(`background-jobs/${i}`),h=0}catch(C){if(C instanceof Dn&&h<d){h++,m.debug(`[background-job] Job ${n} not found, retrying (${h}/${d})`);continue}throw C}if(f.status==="completed"){if(m.debug(`[background-job] Completed job ${n}`),!f.result)throw new Error(`Background job ${n} completed but returned no result`);return f.result}if(f.status==="failed"){const C=f.error?.message||"Unknown error";throw m.error(`[background-job] Failed job ${n}: ${C}`),f.error?.stack&&m.error(`Stacktrace: ${f.error.stack}`),new Error(`Background job ${n} failed: ${C}`)}m.debug(`[background-job] Polling job ${n} (status: ${f.status})`)}}c(dt,"pollBackgroundJob");function To(r,e){ht(x.dirname(r)),v.writeFileSync(r,e)}c(To,"writeFile");function xo(r){v.existsSync(r)&&v.rmSync(r)}c(xo,"deleteFile");function sn(r){v.existsSync(r)&&v.rmSync(r,{recursive:!0,force:!0})}c(sn,"deleteDir");function Io(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=x.relative(process.cwd(),r);throw new Error(`Failed to parse YAML file "${n}": ${t.message}`)}throw t}}c(Io,"readYaml");function an(r,e,t){try{ht(x.dirname(r));const n=G.dump(e,t);v.writeFileSync(r,n,"utf8")}catch(n){if(n instanceof Error){const o=x.relative(process.cwd(),r);throw new Error(`Failed to write YAML file "${o}": ${n.message}`)}throw n}return e}c(an,"writeYaml");function ht(r){v.existsSync(r)||v.mkdirSync(r,{recursive:!0})}c(ht,"ensureDirExists");function cn(r,e=!0){if(!v.existsSync(r)||!v.statSync(r).isDirectory())return;let t=v.readdirSync(r);t.length>0&&(t.forEach(n=>cn(x.join(r,n),!1)),t=v.readdirSync(r)),t.length===0&&!e&&v.rmdirSync(r)}c(cn,"cleanupEmptyFolders");function $o(r){const e=r.split(/[\\/]/).join("/");return e.endsWith("/")?e+"**":e}c($o,"normalizePattern");async function ln(r,e=[]){return new Promise(async(t,n)=>{const o=e.map($o),i=Rt("zip",{zlib:{level:9}}),s=[];i.on("data",l=>s.push(l)),i.on("end",()=>t(Buffer.concat(s))),i.on("error",l=>n(l));const a=new Map;for(const l of r[T.Integration]||[])a.set(l.uuid,l.key);for(const[l,d]of Object.entries(r))for(const h of d){const p=h.key,f=a.get(h.integrationUuid),C=On(l,p,f);if(o.length>0&&!o.some(S=>ir(C,S)))continue;const E=G.dump(h);i.append(E,{name:C})}i.finalize()})}c(ln,"createMembraneZip");async function pt(r,e){const t=await Nt.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(pt,"iterateZipItems");async function ko(r){const e=await Nt.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(ko,"readMembraneZip");async function un(r=process.cwd()){const e=await dn(_(r)),t={};for(const{data:n,type:o}of e)t[o]||(t[o]=[]),t[o].push(n);return t}c(un,"readMembraneDir");async function dn(r){const e=hn(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=x.join(r,n.path);t.push({filePath:a,data:s,type:o.type})}return t}c(dn,"iterateMembraneFiles");function hn(r,e){const t=[];if(e||(e=r),!v.existsSync(e)||e.startsWith(x.join(r,"connectors")))return t;const n=v.readdirSync(e,{withFileTypes:!0});for(const o of n){const i=x.join(e,o.name),s=x.relative(r,i);o.isDirectory()?t.push(...hn(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(hn,"getMembraneFiles");function pn(){const r={},e=x.join(_(process.cwd()),"connectors");if(!v.existsSync(e))return r;const t=v.readdirSync(e);for(const n of t){const o=x.join(e,n);if(!v.statSync(o).isDirectory())continue;const i=x.join(o,`${n}.yml`),s=Io(i,!1);if(!s?.uuid)continue;const a=new Set,l=v.readdirSync(o);for(const d of l){if(d.endsWith(".yml"))continue;const h=x.join(o,d);v.statSync(h).isDirectory()&&a.add(d=="development"?"":d)}r[s.uuid]={key:n,id:s.id,versions:Array.from(a)}}return r}c(pn,"readConnectorsDir");function Pe(r,e){const t=x.join(_(process.cwd()),"connectors",r);return e==""||e===Et?x.join(t,"development"):e?x.join(t,e):t}c(Pe,"getConnectorPath");const fn=300,mn=6e4;async function Ro(){const r=await I.withClient(async t=>dt(t,()=>t.get("export"),{pollIntervalMs:fn,timeoutMs:mn}));if(!r)throw new Error("Failed to export workspace");const e=await ge.get(r.downloadUrl,{responseType:"arraybuffer"});return Buffer.from(e.data)}c(Ro,"downloadWorkspaceExport");async function gn(r,e={}){const t=new Pt;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 dt(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(gn,"importWorkspace");async function Po(r,e){const t=await I.withClient(async o=>dt(o,()=>o.get(`connectors/${r}/export-files`,{version:e}),{pollIntervalMs:fn,timeoutMs:mn}));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(Po,"exportConnector");const yn=5;function Ao(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
- `)).action(async e=>{const t=Ot({text:"Pulling workspace",color:"white"}).start();try{const n=await Do(e,t);t.stop(),Mo(n.workspaceExport,n.connectors)}catch(n){t.stop(),Lo(n),process.exit(1)}})}c(Ao,"setupPullCommand");async function Do(r,e){const t=await un(),n=await ln(t),o=await Ro(),i=await ko(o),{comparison:s}=Nn(t,i);s[Y.DELETE].size>0&&!r.force&&(await Fo(s,n),k.error("Use --force to delete local elements"),process.exit(1));const l=await dn(_(process.cwd()));for(const{filePath:h,data:p}of l)s[Y.DELETE].has(p.uuid)&&xo(h);return cn(_(process.cwd())),await pt(o,(h,p)=>{if(ie(h)&&(s[Y.CREATE].has(p.uuid)||s[Y.UPDATE].has(p.uuid))){const C=R.join(_(process.cwd()),h);an(C,p)}}),{connectors:await Oo(i[T.Integration],e),workspaceExport:i}}c(Do,"pullWorkspace");async function Oo(r,e){e.text="Pulling connectors";const t=new Map,{id:n}=await I.withClient(d=>d.get("org-workspace-id")),{items:o=[]}=await I.withClient(d=>d.get(`/connectors?workspaceId=${n}`));for(const d of o){const h=d.uuid??d.id;!d.isPublic&&h&&t.set(h,new Set([""]))}for(const d of r??[]){const{connectorUuid:h,connectorVersion:p}=d;h&&(t.has(h)||t.set(h,new Set),t.get(h).add(p??""))}const i=pn();for(const[d,{key:h,versions:p}]of Object.entries(i)){if(!t.has(d)){const C=Pe(h);sn(C);continue}const f=t.get(d);for(const C of p)if(!f.has(C)){const E=Pe(h,C);sn(E)}}const s=Array.from(t.entries()),a=s.length,l=c((d,h)=>{d==="pulling"?e.start(`Pulling connector ${h}...`):e.succeed(`Pulled connector ${h}`)},"onProgress");for(let d=0;d<a;d+=yn){const h=s.slice(d,d+yn);await Promise.all(h.map(([p,f])=>No(p,Array.from(f),l)))}return Array.from(t.keys())}c(Oo,"pullConnectors");async function No(r,e,t){const n=await I.withClient(d=>d.get(`connectors/${r}/export-json`),!1),o=await I.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=Pe(n.key),l=R.join(a,`${n.key}.yml`);an(l,s);for(const d of e){const h=await Po(r,d),p=Pe(n.key,d);if(To(R.join(p,"src.zip"),h),!d||d===Et){const f=R.join(p,"src");ht(f),await(await At.Open.buffer(h)).extract({path:f})}}t?.("pulled",i)}c(No,"pullConnector");function Mo(r,e=[]){const t=Object.values(r).reduce((n,o)=>n+(o?.length??0),0)+e.length;k.info(`\u25CF Pulled workspace elements \xB7 ${t}`);for(const n of Object.keys(r).sort()){const o=r[n];k.info(`\u2514\u2500\u2500 ${n}s \xB7 ${o?.length??0}`)}e.length>0&&k.info(`\u2514\u2500\u2500 connectors \xB7 ${e.length}`)}c(Mo,"showStats$1");async function Fo(r,e){const t=r[Y.DELETE].size;k.info(`\u2299 Pull: conflicts detected \xB7 ${t}`),await pt(e,(n,o)=>{ie(n)&&r[Y.DELETE].has(o.uuid)&&k.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted in remote)`)})}c(Fo,"showConflicts$1");async function Lo(r){k.error("\u25A0 Error"),k.error(`\u2514\u2500\u2500 ${r.message}`),k.error(` ${r.stack}`)}c(Lo,"showError$1");const j=[];for(let r=0;r<256;++r)j.push((r+256).toString(16).slice(1));function jo(r,e=0){return(j[r[e+0]]+j[r[e+1]]+j[r[e+2]]+j[r[e+3]]+"-"+j[r[e+4]]+j[r[e+5]]+"-"+j[r[e+6]]+j[r[e+7]]+"-"+j[r[e+8]]+j[r[e+9]]+"-"+j[r[e+10]]+j[r[e+11]]+j[r[e+12]]+j[r[e+13]]+j[r[e+14]]+j[r[e+15]]).toLowerCase()}c(jo,"unsafeStringify");let ft;const Uo=new Uint8Array(16);function Ko(){if(!ft){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");ft=crypto.getRandomValues.bind(crypto)}return ft(Uo)}c(Ko,"rng");const qo=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto);var wn={randomUUID:qo};function Bo(r,e,t){if(wn.randomUUID&&!r)return wn.randomUUID();r=r||{};const n=r.random??r.rng?.()??Ko();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,jo(n)}c(Bo,"v4");function _o(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(`
19
- `)).action(async(e,t)=>{const n=Ot({text:"Pushing workspace",color:"white"}).start();try{await Wo(e,t,n)}catch(o){n.stop(),Yo(o),process.exit(1)}})}c(_o,"setupPushCommand");async function Wo(r,e,t){const n=r.length>0,o=await un(),i=pn(),s=Jo(o,i),a=await ln(s,n?r:void 0);t.text="Comparing workspace";const l=await gn(a,{dryRun:!0,partial:n});l[Y.DELETE].size>0&&!e.force&&(t.stop(),await Vo(l,a),k.error("Use --force to delete remote elements"),process.exit(1));const{pushedConnectors:h=[]}=await Gt({onProgress:c((p,f)=>{p==="pushing"?t.start(`Pushing connector ${f}...`):t.succeed(`Pushed connector ${f}`)},"onProgress")});t.start("Pushing workspace..."),await gn(a,{partial:n}),t.stop(),zo(s,h),process.exit(0)}c(Wo,"pushWorkspace");function Jo(r,e){const t=Go(r),n=Ho(t,e),o={};for(const[i,s]of Object.entries(t)){const a=i,l=V[a]?.parentFieldKey||"parentId";o[a]=(s||[]).map(d=>{const h={...d};if(h.integrationId&&!h.integrationUuid&&(h.integrationUuid=n.get(h.integrationId.toString())||h.integrationId,delete h.integrationId),h.connectorId){if(!h.connectorUuid){const p=n.get(h.connectorId.toString());p&&(h.connectorUuid=p)}delete h.connectorId}if(h[l]){const p=h[l].toString(),f=n.get(p);f&&(h.parentUuid=f)}return a===T.Package&&h.elements&&(h.elements=h.elements.map(p=>{if(p.id&&!p.uuid){const f=n.get(p.id.toString());if(f)return{uuid:f,type:p.type}}return p})),delete h.id,h})}return o}c(Jo,"resolveLegacyIdReferences");function Go(r){const e={};for(const[t,n]of Object.entries(r))e[t]=(n||[]).map(o=>o.uuid?o:{...o,uuid:Bo()});return e}c(Go,"generateMissingUuids");function Ho(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(Ho,"buildIdToUuidLookup");function zo(r,e=[]){const t=Object.values(r).reduce((n,o)=>n+(o?.length??0),0)+e.length;k.info(`\u25CF Pushed workspace elements \xB7 ${t}`);for(const n of Object.keys(r).sort()){const o=r[n];k.info(`\u2514\u2500\u2500 ${n}s \xB7 ${o?.length??0}`)}e.length>0&&k.info(`\u2514\u2500\u2500 connectors \xB7 ${e.length}`)}c(zo,"showStats");async function Vo(r,e){const t=r[Y.DELETE].size;k.info(`\u2299 Push: conflicts detected \xB7 ${t}`),await pt(e,(n,o)=>{ie(n)&&r[Y.DELETE].has(o.uuid)&&k.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted locally)`)})}c(Vo,"showConflicts");async function Yo(r){k.error("\u25A0 Error"),k.error(`\u2514\u2500\u2500 ${r.message}`),k.error(` ${r.stack}`)}c(Yo,"showError");const mt=[{id:"claude-code",name:"Claude Code",description:"Anthropic Claude Code agent",actionDescription:"Adding membrane MCP to .mcp.json in the current directory",addConfig:c(()=>{const r=x.join(process.cwd(),".mcp.json"),e={mcpServers:{membrane:{command:"membrane",args:["mcp"],env:{AGENT_NAME:"Claude Code"}}}};let t={};if(v.existsSync(r))try{t=JSON.parse(v.readFileSync(r,"utf8"))}catch{t={}}const n={...t,mcpServers:{...t.mcpServers,...e.mcpServers}};return v.writeFileSync(r,JSON.stringify(n,null,2)),`MCP server configuration added to ${r}`},"addConfig")},{id:"cursor",name:"Cursor",description:"Cursor AI editor",actionDescription:"Adding membrane MCP to .cursor/mcp.json in the current directory",addConfig:c(()=>{const r=x.join(process.cwd(),".cursor"),e=x.join(r,"mcp.json");v.existsSync(r)||v.mkdirSync(r);const t={mcpServers:{membrane:{command:"membrane",args:["mcp"],env:{AGENT_NAME:"Cursor"}}}};let n={};if(v.existsSync(e))try{n=JSON.parse(v.readFileSync(e,"utf8"))}catch{n={}}const o={...n,mcpServers:{...n.mcpServers,...t.mcpServers}};return v.writeFileSync(e,JSON.stringify(o,null,2)),`MCP server configuration added to ${e}`},"addConfig")}];function Zo({onExit:r,onComplete:e}){const[t,n]=D(0),[o,i]=D(!1),[s,a]=D(null),[l,d]=D(""),[h,p]=D("");ae((E,S)=>{if(l||h){(S.escape||E==="q"||S.return)&&e();return}if(o)S.return||E===" "?f(s):S.escape&&(i(!1),a(null));else if(S.escape)r();else if(S.upArrow||E==="k")n(Math.max(0,t-1));else if(S.downArrow||E==="j")n(Math.min(mt.length-1,t+1));else if(S.return||E===" "){const N=mt[t];a(N),i(!0)}});const f=c(E=>{try{const S=E.addConfig();d(S)}catch(S){p(`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]"})})]}):h?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: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: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:mt.map((E,S)=>b(g,{children:[b(y,{color:t===S?"cyan":"white",children:[t===S?"\u25B6 ":" ",E.name]}),b(y,{color:"grey",children:[" \u2014 ",E.description]})]},E.id))})]}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"[\u2191\u2193: select] [enter: choose] [esc: exit]"})})]})}c(Zo,"AddMcpServerScreen");function Xo(){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(Xo,"useMcpStatus");function Qo(){const{error:r,serverCount:e,allMcpServers:t}=Xo(),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(qn,{}),"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(Qo,"Agent");const Cn=c(r=>{switch(r){case"error":return"red";case"success":return"green";case"warning":return"yellow";default:return}},"getLogColor");function Sn(r,e){return e<3?r.slice(0,Math.max(0,e)):r.length<=e?r:`${r.slice(0,e-3)}...`}c(Sn,"truncateText");function ei({children:r}){const{state:e,logs:t}=H();return!e||e===$.NOT_INITIALIZED?b(g,{gap:1,flexDirection:"row",children:[u(rr,{type:"dots"}),u(y,{children:"Initializing..."})]}):e===$.SETTING_UP?u(g,{gap:1,flexDirection:"row",children:u(y,{children:"No workspace selected. Please run `membrane init` to select a workspace."})}):e===$.ERROR?u(g,{flexDirection:"column",children:t.slice().map((n,o)=>u(y,{color:Cn(n.type),children:n.message},n.timestamp+o))}):r}c(ei,"EnsureInitialized");function ti(){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(ti,"ElementStats");const gt=5,ni=6;function ri(){const{logs:r}=H(),[e,t]=D(0),n=Math.min(100,process.stdout.columns||100),o=gt,i=Math.max(0,r.length-o-e),s=r.length-e,a=r.slice(i,s),l=n-ni,d=e<r.length-o,h=e>0;return ae((p,f)=>{if(r.length!==0)if(f.upArrow){const C=Math.max(0,r.length-o);t(E=>Math.min(C,E+1))}else f.downArrow?t(C=>Math.max(0,C-1)):(p==="G"||p==="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>gt&&u(y,{color:"grey",children:" [arrows: scroll] [g: end]"})]}),a.map((p,f)=>u(g,{marginLeft:1,children:u(y,{color:Cn(p.type),children:Sn(p.message,l)})},p.timestamp+f)),r.length>gt&&b(g,{marginLeft:1,flexDirection:"row",children:[d&&u(y,{color:"grey",children:"\u2191 "}),h&&u(y,{color:"grey",children:"\u2193 "})]})]})}c(ri,"Logs");const Ae=[{value:"sync",label:"Continue (overwrite/delete)",key:""},{value:"exit",label:"Cancel",key:""}];function oi(){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(p=>p>0?p-1:Ae.length-1):h.downArrow?o(p=>p<Ae.length-1?p+1:0):d.toLowerCase()==="y"?o(0):d.toLowerCase()==="n"?o(1):(h.return||d===" ")&&(s(!0),Ae[n].value==="sync"?e({watch:!0}):t())}}),he(()=>{r!==$.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(xe,{type:"dots"}),u(y,{color:"blue",bold:!0,children:"Syncing with remote..."})]}):u(g,{flexDirection:"column",children:Ae.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(oi,"ResolveChangesUI");const ii={[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=Kn(()=>{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=ii[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 ai(){const{config:r,state:e,logs:t,currentWorkspace:n,pull:o}=H(),i=n?.name,s=i?Sn(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:li(e),children:[" [",ci(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===$.CONFLICTS?u(oi,{}):b(Te,{children:[u(g,{paddingTop:1,children:u(ti,{})}),t.length>0&&u(ri,{})]})]})}c(ai,"Workspace");function ci(r){switch(r){case $.PULLING:return"pulling";case $.PUSHING:return"pushing";case $.CONFLICTS:return"conflicts";case $.SYNCED:return"synced";case $.ERROR:return"error";case $.WATCHING:return"tracking changes";case $.RESOLVING:return"resolving";case $.NOT_SYNCED:return"not synced";case $.INITIALIZED:return"initialized";case $.SETTING_UP:return"setup required";default:return"unknown"}}c(ci,"getStatusDisplay");function li(r){switch(r){case $.PULLING:return"yellow";case $.PUSHING:return"yellow";case $.CONFLICTS:return"red";case $.SYNCED:return"green";case $.ERROR:return"red";case $.WATCHING:return"green";case $.RESOLVING:return"yellow";case $.NOT_SYNCED:return"grey";case $.SETTING_UP:return"yellow";default:return"grey"}}c(li,"getStatusColor");const ui="https://console.integration.app/w";function di(){const r=co(),e=Be(!0),{exit:t,state:n}=H(),[o,i]=D(null),s=o??(n===$.SETTING_UP?"setup":"main");ae(l=>{s==="main"&&(l==="w"&&i("workspace-selection"),l==="a"&&i("add-mcp-server"),l==="o"&&n===$.INITIALIZED&&a(),l==="s"&&i("setup"))});async function a(){try{const l=await Bt(r),d=`${ui}/${l}`,h=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";sr(`${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(nn,{onExit:c(()=>i(null),"onExit")}):s==="add-mcp-server"?u(Zo,{onExit:c(()=>i(null),"onExit"),onComplete:c(()=>i(null),"onComplete")}):s==="setup"?u(rn,{onComplete:c(()=>i(null),"onComplete")},Date.now()):u(ei,{children:b(g,{flexDirection:"column",children:[u(g,{flexGrow:1,children:u(Qo,{})}),u(ai,{}),u(g,{paddingLeft:2,children:u(y,{color:"grey",children:"[s: (re-)setup]"})})]})})}c(di,"Main");const hi=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(`
20
- `),"createExperimentalWarning$1");function pi(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}):(m.error(`Invalid RPS value: ${n}. Must be between 1 and 1000.`),process.exit(1))}console.warn(hi()),_e(se.createElement(lt,{cwd:process.cwd(),membraneCLIService:e,children:se.createElement(di)}))})}c(pi,"setupSyncCommand");class fi{static{c(this,"BaseRunner")}constructor(e={}){if(this.options=e,this.fsPaths=Xe(),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 mi="claude-sonnet-4-20250514";class bt{static{c(this,"TestEnvironment")}client;connectionId;testsDir;testBasePath;options;llm;state={};constructor({connectionId:e,testsDir:t,testBasePath:n,client:o,options:i,llm:s}){this.client=o,this.connectionId=e,this.testsDir=t,this.testBasePath=n,this.llm=s,this.options=i}static async create({connectionId:e,testBasePath:t,options:n}){const o=$e();if(!o)throw new Error("No configuration found. Please set MEMBRANE_WORKSPACE_KEY and MEMBRANE_WORKSPACE_SECRET environment variables, or run `membrane init` first.");if(!o.workspaceKey||!o.workspaceSecret)throw new Error("Missing workspace credentials");if(!o.anthropicApiKey)throw new Error("Anthropic API key not configured. Run `membrane init` to set up testing.");const i=new vt({token:await this.createMembraneToken(o),apiUri:o.apiUri}),s=new ar({apiKey:o.anthropicApiKey}),a={complete:c(async({prompt:l,maxTokens:d})=>{const h=await s.messages.create({model:mi,max_tokens:d,messages:[{role:"user",content:l}]});return h.content[0].type==="text"?h.content[0].text:""},"complete")};return new bt({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(),Je(t,n.getResult());this.writeResults(t)}async readYaml(e){const t=R.join(this.testsDir,this.testBasePath,this.connectionId,e);return Qe(t)}async writeYaml(e,t){const n=R.join(this.testsDir,this.testBasePath,this.connectionId,e);P.mkdirSync(R.dirname(n),{recursive:!0}),P.writeFileSync(n,G.dump(t,{noRefs:!0}))}writeResults(e){const t=R.join(this.testsDir,this.testBasePath,this.connectionId);P.mkdirSync(t,{recursive:!0});const n=R.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 We.sign(n,e.workspaceSecret,o)}}lr.interpolate=/{{([\s\S]+?)}}/g;function yt(r,e){if(typeof r=="string"){const t=cr(r),n={state:e,random:{number:c(()=>ye.number.int(),"number"),alphaNumeric:c(i=>ye.string.alphanumeric(i),"alphaNumeric")},faker:{company:{name:c(()=>ye.company.name(),"name"),catchPhrase:c(()=>ye.company.catchPhrase(),"catchPhrase")},internet:{email:c(()=>ye.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=>yt(t,e)):typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).map(([t,n])=>[t,yt(n,e)])):r}c(yt,"processNode");function gi(r,e){return yt(r,e)}c(gi,"handleTemplate");class yi{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=gi(i,this.environment.state),await e.run(s),console.debug(`${w.bold.green("[success]")} ${w.yellow(e.path)}`),t=!0,o=e.getResult(),Me(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}`)}}Me(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(),Je(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(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:J(o)}),this.logMsg(`\u274C ${t}: ${o.message}`)}}logMsg(e){console.debug(`${" ".repeat(this.level*2)}${e}`)}getTestCasePath(){return`${this.path}.test.yml`}}function wt(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)||!Ct(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=wt(o,i);s!==null&&(t[n]=s)}else t[n]=i;continue}Ct(o,i)||(t[n]=i)}return Object.keys(t).length===0?null:t}c(wt,"getNotMatchingSubFields");function Ct(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(Ct,"softCompare");class wi 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=Fe(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=Tt(n),a=ve(e.input.fields,s,{skipUnknownFields:!0}),l=ve(i.record.fields,s),d=wt(l,a);await this.assert(()=>!d,"Returned fields match created fields",{difference:d,sentFields:a,receivedFields:l})}const o=Mn(n??{});if(o.length>0){const i={};o.forEach(a=>{const l=Fn(e.input.fields,a);typeof l<"u"&&Me(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=Fe(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=Fe(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:
16
+ ${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(){}}function ko(r){r.command("open").description("Open the workspace in the browser").addHelpText("after",["","Examples:"," membrane open # Open workspace in browser",""].join(`
17
+ `)).action(async()=>{try{R.header("Opening Workspace in Browser"),R.info("Loading configuration...");const e=we();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 Jt(process.cwd()),n=et(`/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(ko,"setupOpenCommand");async function ft(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 h=0;for(;;){if(Date.now()-s>l)throw new Error(`Background job ${n} timed out after ${l}ms`);await new Promise(C=>setTimeout(C,a));let p;try{p=await r.get(`background-jobs/${i}`),h=0}catch(C){if(C instanceof Ln&&h<d){h++,m.debug(`[background-job] Job ${n} not found, retrying (${h}/${d})`);continue}throw C}if(p.status==="completed"){if(m.debug(`[background-job] Completed job ${n}`),!p.result)throw new Error(`Background job ${n} completed but returned no result`);return p.result}if(p.status==="failed"){const C=p.error?.message||"Unknown error";throw m.error(`[background-job] Failed job ${n}: ${C}`),p.error?.stack&&m.error(`Stacktrace: ${p.error.stack}`),new Error(`Background job ${n} failed: ${C}`)}m.debug(`[background-job] Polling job ${n} (status: ${p.status})`)}}c(ft,"pollBackgroundJob");function ln(r,e){be(x.dirname(r)),v.writeFileSync(r,e)}c(ln,"writeFile");function Ro(r){v.existsSync(r)&&v.rmSync(r)}c(Ro,"deleteFile");function mt(r){v.existsSync(r)&&v.rmSync(r,{recursive:!0,force:!0})}c(mt,"deleteDir");function Po(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=x.relative(process.cwd(),r);throw new Error(`Failed to parse YAML file "${n}": ${t.message}`)}throw t}}c(Po,"readYaml");function un(r,e,t){try{be(x.dirname(r));const n=G.dump(e,t);v.writeFileSync(r,n,"utf8")}catch(n){if(n instanceof Error){const o=x.relative(process.cwd(),r);throw new Error(`Failed to write YAML file "${o}": ${n.message}`)}throw n}return e}c(un,"writeYaml");function be(r){v.existsSync(r)||v.mkdirSync(r,{recursive:!0})}c(be,"ensureDirExists");function dn(r,e=!0){if(!v.existsSync(r)||!v.statSync(r).isDirectory())return;let t=v.readdirSync(r);t.length>0&&(t.forEach(n=>dn(x.join(r,n),!1)),t=v.readdirSync(r)),t.length===0&&!e&&v.rmdirSync(r)}c(dn,"cleanupEmptyFolders");function Ao(r){const e=r.split(/[\\/]/).join("/");return e.endsWith("/")?e+"**":e}c(Ao,"normalizePattern");async function hn(r,e=[]){return new Promise(async(t,n)=>{const o=e.map(Ao),i=Dt("zip",{zlib:{level:9}}),s=[];i.on("data",l=>s.push(l)),i.on("end",()=>t(Buffer.concat(s))),i.on("error",l=>n(l));const a=new Map;for(const l of r[T.Integration]||[])a.set(l.uuid,l.key);for(const[l,d]of Object.entries(r))for(const h of d){const f=h.key,p=a.get(h.integrationUuid),C=jn(l,f,p);if(o.length>0&&!o.some(S=>ur(C,S)))continue;const E=G.dump(h);i.append(E,{name:C})}i.finalize()})}c(hn,"createMembraneZip");async function gt(r,e){const t=await Lt.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(gt,"iterateZipItems");async function Do(r){const e=await Lt.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(Do,"readMembraneZip");async function pn(r=process.cwd()){const e=await fn(q(r)),t={};for(const{data:n,type:o}of e)t[o]||(t[o]=[]),t[o].push(n);return t}c(pn,"readMembraneDir");async function fn(r){const e=mn(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=x.join(r,n.path);t.push({filePath:a,data:s,type:o.type})}return t}c(fn,"iterateMembraneFiles");function mn(r,e){const t=[];if(e||(e=r),!v.existsSync(e)||e.startsWith(x.join(r,"connectors")))return t;const n=v.readdirSync(e,{withFileTypes:!0});for(const o of n){const i=x.join(e,o.name),s=x.relative(r,i);o.isDirectory()?t.push(...mn(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(mn,"getMembraneFiles");function gn(){const r={},e=x.join(q(process.cwd()),"connectors");if(!v.existsSync(e))return r;const t=v.readdirSync(e);for(const n of t){const o=x.join(e,n);if(!v.statSync(o).isDirectory())continue;const i=x.join(o,`${n}.yml`),s=Po(i,!1);if(!s?.uuid)continue;const a=new Set,l=v.readdirSync(o);for(const d of l){if(d.endsWith(".yml"))continue;const h=x.join(o,d);v.statSync(h).isDirectory()&&a.add(d=="development"?"":d)}r[s.uuid]={key:n,id:s.id,versions:Array.from(a)}}return r}c(gn,"readConnectorsDir");function ve(r,e){const t=x.join(q(process.cwd()),"connectors",r);return e==""||e===It?x.join(t,"development"):e?x.join(t,e):t}c(ve,"getConnectorPath");const yn=1e3,wn=12e4;async function Oo(){const r=await $.withClient(async t=>ft(t,()=>t.get("export"),{pollIntervalMs:yn,timeoutMs:wn}));if(!r)throw new Error("Failed to export workspace");const e=await ge.get(r.downloadUrl,{responseType:"arraybuffer"});return Buffer.from(e.data)}c(Oo,"downloadWorkspaceExport");async function Cn(r,e={}){const t=new Ot;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 ft(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(Cn,"importWorkspace");async function No(r,e){const t=await $.withClient(async o=>ft(o,()=>o.get(`connectors/${r}/export-files`,{version:e}),{pollIntervalMs:yn,timeoutMs:wn}));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(No,"exportConnector");const Sn=5;function Mo(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
+ `)).action(async e=>{const t=Ft({text:"Pulling workspace",color:"white"}).start();try{const n=await Fo(e,t);t.stop(),qo(n.workspaceExport,n.connectors)}catch(n){t.stop(),_o(n),process.exit(1)}})}c(Mo,"setupPullCommand");async function Fo(r,e){const t=await pn(),n=await hn(t),o=await Oo(),i=await Do(o),{comparison:s}=Un(t,i);s[Y.DELETE].size>0&&!r.force&&(await Bo(s,n),R.error("Use --force to delete local elements"),process.exit(1));const l=await fn(q(process.cwd()));for(const{filePath:p,data:C}of l)s[Y.DELETE].has(C.uuid)&&Ro(p);dn(q(process.cwd())),await gt(o,(p,C)=>{if(ie(p)&&(s[Y.CREATE].has(C.uuid)||s[Y.UPDATE].has(C.uuid))){const S=I.join(q(process.cwd()),p);un(S,C)}});const d=await $.getVersion(),h=d?Mt.coerce(d):null;return{connectors:h&&Mt.gte(h,"1.8.0")?await Lo(o,e):await Uo(i[T.Integration],e),workspaceExport:i}}c(Fo,"pullWorkspace");async function Lo(r,e){e.text="Extracting connectors",mt(I.join(q(process.cwd()),"connectors"));const t=new Set,n=await ke.Open.buffer(r);for(const o of n.files){if(!o.path.startsWith("connectors/")||o.type==="Directory")continue;const i=I.join(q(process.cwd()),o.path);be(I.dirname(i));const s=await o.buffer();if(ln(i,s),t.add(o.path.split("/")[1]),o.path.endsWith("/development/src.zip")){const a=I.join(I.dirname(i),"src");be(a),await(await ke.Open.buffer(s)).extract({path:a})}}return Array.from(t)}c(Lo,"extractConnectorsFromExport");async function jo(r,e,t){if(ln(I.join(ve(r,e),"src.zip"),t),!e||e===It){const n=I.join(ve(r,e),"src");be(n),await(await ke.Open.buffer(t)).extract({path:n})}}c(jo,"writeConnectorVersion");async function Uo(r,e){e.text="Pulling connectors";const t=new Map,{id:n}=await $.withClient(l=>l.get("org-workspace-id")),{items:o=[]}=await $.withClient(l=>l.get(`/connectors?workspaceId=${n}`));for(const l of o){const d=l.uuid??l.id;!l.isPublic&&d&&t.set(d,new Set([""]))}for(const l of r??[]){const{connectorUuid:d,connectorVersion:h}=l;d&&(t.has(d)||t.set(d,new Set),t.get(d).add(h??""))}const i=gn();for(const[l,{key:d,versions:h}]of Object.entries(i)){if(!t.has(l)){const p=ve(d);mt(p);continue}const f=t.get(l);for(const p of h)if(!f.has(p)){const C=ve(d,p);mt(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+=Sn){const d=s.slice(l,l+Sn);await Promise.all(d.map(([h,f])=>Ko(h,Array.from(f),a)))}return Array.from(t.keys())}c(Uo,"pullConnectorsLegacy");async function Ko(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=ve(n.key),l=I.join(a,`${n.key}.yml`);un(l,s);for(const d of e){const h=await No(r,d);await jo(n.key,d,h)}t?.("pulled",i)}c(Ko,"pullConnector");function qo(r,e=[]){const t=Object.values(r).reduce((n,o)=>n+(o?.length??0),0)+e.length;R.info(`\u25CF Pulled 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(qo,"showStats$1");async function Bo(r,e){const t=r[Y.DELETE].size;R.info(`\u2299 Pull: conflicts detected \xB7 ${t}`),await gt(e,(n,o)=>{ie(n)&&r[Y.DELETE].has(o.uuid)&&R.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted in remote)`)})}c(Bo,"showConflicts$1");async function _o(r){R.error("\u25A0 Error"),R.error(`\u2514\u2500\u2500 ${r.message}`),R.error(` ${r.stack}`)}c(_o,"showError$1");const j=[];for(let r=0;r<256;++r)j.push((r+256).toString(16).slice(1));function Wo(r,e=0){return(j[r[e+0]]+j[r[e+1]]+j[r[e+2]]+j[r[e+3]]+"-"+j[r[e+4]]+j[r[e+5]]+"-"+j[r[e+6]]+j[r[e+7]]+"-"+j[r[e+8]]+j[r[e+9]]+"-"+j[r[e+10]]+j[r[e+11]]+j[r[e+12]]+j[r[e+13]]+j[r[e+14]]+j[r[e+15]]).toLowerCase()}c(Wo,"unsafeStringify");let yt;const Jo=new Uint8Array(16);function Go(){if(!yt){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");yt=crypto.getRandomValues.bind(crypto)}return yt(Jo)}c(Go,"rng");const Ho=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto);var bn={randomUUID:Ho};function zo(r,e,t){if(bn.randomUUID&&!r)return bn.randomUUID();r=r||{};const n=r.random??r.rng?.()??Go();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,Wo(n)}c(zo,"v4");function Vo(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(`
19
+ `)).action(async(e,t)=>{const n=Ft({text:"Pushing workspace",color:"white"}).start();try{await Yo(e,t,n)}catch(o){n.stop(),ni(o),process.exit(1)}})}c(Vo,"setupPushCommand");async function Yo(r,e,t){const n=r.length>0,o=await pn(),i=gn(),s=Zo(o,i),a=await hn(s,n?r:void 0);t.text="Comparing workspace";const l=await Cn(a,{dryRun:!0,partial:n});l[Y.DELETE].size>0&&!e.force&&(t.stop(),await ti(l,a),R.error("Use --force to delete remote elements"),process.exit(1));const{pushedConnectors:h=[]}=await Vt({onProgress:c((f,p)=>{f==="pushing"?t.start(`Pushing connector ${p}...`):t.succeed(`Pushed connector ${p}`)},"onProgress")});t.start("Pushing workspace..."),await Cn(a,{partial:n}),t.stop(),ei(s,h),process.exit(0)}c(Yo,"pushWorkspace");function Zo(r,e){const t=Xo(r),n=Qo(t,e),o={};for(const[i,s]of Object.entries(t)){const a=i,l=V[a]?.parentFieldKey||"parentId";o[a]=(s||[]).map(d=>{const h={...d};if(h.integrationId&&!h.integrationUuid&&(h.integrationUuid=n.get(h.integrationId.toString())||h.integrationId,delete h.integrationId),h.connectorId){if(!h.connectorUuid){const f=n.get(h.connectorId.toString());f&&(h.connectorUuid=f)}delete h.connectorId}if(h[l]){const f=h[l].toString(),p=n.get(f);p&&(h.parentUuid=p)}return a===T.Package&&h.elements&&(h.elements=h.elements.map(f=>{if(f.id&&!f.uuid){const p=n.get(f.id.toString());if(p)return{uuid:p,type:f.type}}return f})),delete h.id,h})}return o}c(Zo,"resolveLegacyIdReferences");function Xo(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(Xo,"generateMissingUuids");function Qo(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(Qo,"buildIdToUuidLookup");function ei(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(ei,"showStats");async function ti(r,e){const t=r[Y.DELETE].size;R.info(`\u2299 Push: conflicts detected \xB7 ${t}`),await gt(e,(n,o)=>{ie(n)&&r[Y.DELETE].has(o.uuid)&&R.info(`\u2514\u2500\u2500 ./membrane/${n} (deleted locally)`)})}c(ti,"showConflicts");async function ni(r){R.error("\u25A0 Error"),R.error(`\u2514\u2500\u2500 ${r.message}`),R.error(` ${r.stack}`)}c(ni,"showError");const wt=[{id:"claude-code",name:"Claude Code",description:"Anthropic Claude Code agent",actionDescription:"Adding membrane MCP to .mcp.json in the current directory",addConfig:c(()=>{const r=x.join(process.cwd(),".mcp.json"),e={mcpServers:{membrane:{command:"membrane",args:["mcp"],env:{AGENT_NAME:"Claude Code"}}}};let t={};if(v.existsSync(r))try{t=JSON.parse(v.readFileSync(r,"utf8"))}catch{t={}}const n={...t,mcpServers:{...t.mcpServers,...e.mcpServers}};return v.writeFileSync(r,JSON.stringify(n,null,2)),`MCP server configuration added to ${r}`},"addConfig")},{id:"cursor",name:"Cursor",description:"Cursor AI editor",actionDescription:"Adding membrane MCP to .cursor/mcp.json in the current directory",addConfig:c(()=>{const r=x.join(process.cwd(),".cursor"),e=x.join(r,"mcp.json");v.existsSync(r)||v.mkdirSync(r);const t={mcpServers:{membrane:{command:"membrane",args:["mcp"],env:{AGENT_NAME:"Cursor"}}}};let n={};if(v.existsSync(e))try{n=JSON.parse(v.readFileSync(e,"utf8"))}catch{n={}}const o={...n,mcpServers:{...n.mcpServers,...t.mcpServers}};return v.writeFileSync(e,JSON.stringify(o,null,2)),`MCP server configuration added to ${e}`},"addConfig")}];function ri({onExit:r,onComplete:e}){const[t,n]=D(0),[o,i]=D(!1),[s,a]=D(null),[l,d]=D(""),[h,f]=D("");ae((E,S)=>{if(l||h){(S.escape||E==="q"||S.return)&&e();return}if(o)S.return||E===" "?p(s):S.escape&&(i(!1),a(null));else if(S.escape)r();else if(S.upArrow||E==="k")n(Math.max(0,t-1));else if(S.downArrow||E==="j")n(Math.min(wt.length-1,t+1));else if(S.return||E===" "){const N=wt[t];a(N),i(!0)}});const p=c(E=>{try{const S=E.addConfig();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]"})})]}):h?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: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: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:wt.map((E,S)=>b(g,{children:[b(y,{color:t===S?"cyan":"white",children:[t===S?"\u25B6 ":" ",E.name]}),b(y,{color:"grey",children:[" \u2014 ",E.description]})]},E.id))})]}),u(g,{marginTop:1,children:u(y,{color:"grey",children:"[\u2191\u2193: select] [enter: choose] [esc: exit]"})})]})}c(ri,"AddMcpServerScreen");function oi(){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(oi,"useMcpStatus");function ii(){const{error:r,serverCount:e,allMcpServers:t}=oi(),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(Gn,{}),"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(ii,"Agent");const vn=c(r=>{switch(r){case"error":return"red";case"success":return"green";case"warning":return"yellow";default:return}},"getLogColor");function En(r,e){return e<3?r.slice(0,Math.max(0,e)):r.length<=e?r:`${r.slice(0,e-3)}...`}c(En,"truncateText");function si({children:r}){const{state:e,logs:t}=H();return!e||e===k.NOT_INITIALIZED?b(g,{gap:1,flexDirection:"row",children:[u(cr,{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:vn(n.type),children:n.message},n.timestamp+o))}):r}c(si,"EnsureInitialized");function ai(){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(ai,"ElementStats");const Ct=5,ci=6;function li(){const{logs:r}=H(),[e,t]=D(0),n=Math.min(100,process.stdout.columns||100),o=Ct,i=Math.max(0,r.length-o-e),s=r.length-e,a=r.slice(i,s),l=n-ci,d=e<r.length-o,h=e>0;return ae((f,p)=>{if(r.length!==0)if(p.upArrow){const C=Math.max(0,r.length-o);t(E=>Math.min(C,E+1))}else p.downArrow?t(C=>Math.max(0,C-1)):(f==="G"||f==="g")&&t(0)}),b(g,{flexDirection:"column",paddingTop:1,children:[b(y,{color:"grey",children:["Recent Activity (",i+1,"-",s," of ",r.length,"):",r.length>Ct&&u(y,{color:"grey",children:" [arrows: scroll] [g: end]"})]}),a.map((f,p)=>u(g,{marginLeft:1,children:u(y,{color:vn(f.type),children:En(f.message,l)})},f.timestamp+p)),r.length>Ct&&b(g,{marginLeft:1,flexDirection:"row",children:[d&&u(y,{color:"grey",children:"\u2191 "}),h&&u(y,{color:"grey",children:"\u2193 "})]})]})}c(li,"Logs");const Oe=[{value:"sync",label:"Continue (overwrite/delete)",key:""},{value:"exit",label:"Cancel",key:""}];function ui(){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(f=>f>0?f-1:Oe.length-1):h.downArrow?o(f=>f<Oe.length-1?f+1:0):d.toLowerCase()==="y"?o(0):d.toLowerCase()==="n"?o(1):(h.return||d===" ")&&(s(!0),Oe[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(hi,{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(Re,{type:"dots"}),u(y,{color:"blue",bold:!0,children:"Syncing with remote..."})]}):u(g,{flexDirection:"column",children:Oe.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(ui,"ResolveChangesUI");const di={[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 hi({isExpanded:r,showControls:e=!0}){const{conflicts:t}=H(),n=5,o=Jn(()=>{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=di[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(hi,"Conflicts");function pi(){const{config:r,state:e,logs:t,currentWorkspace:n,pull:o}=H(),i=n?.name,s=i?En(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:mi(e),children:[" [",fi(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(ui,{}):b($e,{children:[u(g,{paddingTop:1,children:u(ai,{})}),t.length>0&&u(li,{})]})]})}c(pi,"Workspace");function fi(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(fi,"getStatusDisplay");function mi(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(mi,"getStatusColor");function gi(){const r=fo(),e=We(!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 Jt(r),d=et(`/w/${l}`),h=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";dr(`${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(sn,{onExit:c(()=>i(null),"onExit")}):s==="add-mcp-server"?u(ri,{onExit:c(()=>i(null),"onExit"),onComplete:c(()=>i(null),"onComplete")}):s==="setup"?u(an,{onComplete:c(()=>i(null),"onComplete")},Date.now()):u(si,{children:b(g,{flexDirection:"column",children:[u(g,{flexGrow:1,children:u(ii,{})}),u(pi,{}),u(g,{paddingLeft:2,children:u(y,{color:"grey",children:"[s: (re-)setup]"})})]})})}c(gi,"Main");const yi=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(`
20
+ `),"createExperimentalWarning$1");function wi(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?$.init({maxRequestsPerSecond:n}):(m.error(`Invalid RPS value: ${n}. Must be between 1 and 1000.`),process.exit(1))}console.warn(yi()),Je(se.createElement(ht,{cwd:process.cwd(),membraneCLIService:e,children:se.createElement(gi)}))})}c(wi,"setupSyncCommand");class Ci{static{c(this,"BaseRunner")}constructor(e={}){if(this.options=e,this.fsPaths=tt(),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 Si="claude-sonnet-4-20250514";class Tt{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=we();if(!o)throw new Error("No configuration found. Please set MEMBRANE_WORKSPACE_KEY and MEMBRANE_WORKSPACE_SECRET environment variables, or run `membrane init` first.");if(!o.workspaceKey||!o.workspaceSecret)throw new Error("Missing workspace credentials");if(!o.anthropicApiKey)throw new Error("Anthropic API key not configured. Run `membrane init` to set up testing.");const i=new xt({token:await this.createMembraneToken(o),apiUri:o.apiUri}),s=new hr({apiKey:o.anthropicApiKey}),a={complete:c(async({prompt:l,maxTokens:d})=>{const h=await s.messages.create({model:Si,max_tokens:d,messages:[{role:"user",content:l}]});return h.content[0].type==="text"?h.content[0].text:""},"complete")};return new Tt({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(),He(t,n.getResult());this.writeResults(t)}async readYaml(e){const t=I.join(this.testsDir,this.testBasePath,this.connectionId,e);return nt(t)}async writeYaml(e,t){const n=I.join(this.testsDir,this.testBasePath,this.connectionId,e);P.mkdirSync(I.dirname(n),{recursive:!0}),P.writeFileSync(n,G.dump(t,{noRefs:!0}))}writeResults(e){const t=I.join(this.testsDir,this.testBasePath,this.connectionId);P.mkdirSync(t,{recursive:!0});const n=I.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 Ge.sign(n,e.workspaceSecret,o)}}fr.interpolate=/{{([\s\S]+?)}}/g;function St(r,e){if(typeof r=="string"){const t=pr(r),n={state:e,random:{number:c(()=>ye.number.int(),"number"),alphaNumeric:c(i=>ye.string.alphanumeric(i),"alphaNumeric")},faker:{company:{name:c(()=>ye.company.name(),"name"),catchPhrase:c(()=>ye.company.catchPhrase(),"catchPhrase")},internet:{email:c(()=>ye.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=>St(t,e)):typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).map(([t,n])=>[t,St(n,e)])):r}c(St,"processNode");function bi(r,e){return St(r,e)}c(bi,"handleTemplate");class vi{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=bi(i,this.environment.state),await e.run(s),console.debug(`${w.bold.green("[success]")} ${w.yellow(e.path)}`),t=!0,o=e.getResult(),Le(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}`)}}Le(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(),He(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(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:J(o)}),this.logMsg(`\u274C ${t}: ${o.message}`)}}logMsg(e){console.debug(`${" ".repeat(this.level*2)}${e}`)}getTestCasePath(){return`${this.path}.test.yml`}}function bt(r,e){const t={};for(const n in e){if(!(n in r)){t[n]=e[n];continue}const o=r[n],i=e[n];if(o&&i&&typeof o=="object"&&typeof i=="object"){if(Array.isArray(o)&&Array.isArray(i)){const s=i.filter(a=>!o.some(l=>{if(typeof l=="object"&&typeof a=="object"&&l!==null&&a!==null&&!Array.isArray(l)&&!Array.isArray(a)){for(const d in a)if(!(d in l)||!vt(l[d],a[d]))return!1;return!0}else return JSON.stringify(l)===JSON.stringify(a)}));s.length>0&&(t[n]=s)}else if(!Array.isArray(o)&&!Array.isArray(i)){const s=bt(o,i);s!==null&&(t[n]=s)}else t[n]=i;continue}vt(o,i)||(t[n]=i)}return Object.keys(t).length===0?null:t}c(bt,"getNotMatchingSubFields");function vt(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(vt,"softCompare");class Ei 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=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=xe(e.input.fields,s,{skipUnknownFields:!0}),l=xe(i.record.fields,s),d=bt(l,a);await this.assert(()=>!d,"Returned fields match created fields",{difference:d,sentFields:a,receivedFields:l})}const o=Kn(n??{});if(o.length>0){const i={};o.forEach(a=>{const l=qn(e.input.fields,a);typeof l<"u"&&Le(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=J(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
22
 
23
23
  ${JSON.stringify(o,null,2)}
24
24
 
@@ -58,7 +58,7 @@ ${JSON.stringify(o,null,2)}`).join(`
58
58
 
59
59
  `)}.
60
60
 
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 xt(e,o=>{if(o.referenceCollection){const i=o.referenceCollection.key,s=o.referenceCollection.parameters,a=`${i}:${JSON.stringify(s||{})}`;t.has(a)||(t.add(a),n.push({key:i,parameters:s}))}return o}),n}async fetchExampleRecords(e){return(await this.environment.client.connection(this.environment.connectionId).dataCollection(e.key).list({parameters:e.parameters})).records.map(n=>({id:n.id,fields:n.fields??{}}))}async getExampleRecordsForSchema(e){const t=await this.findReferenceCollections(e),n={};for(const o of t){const i=It(o);n[i]=await this.fetchExampleRecords(o)}return n}}class Ci extends oe{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`);try{await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).delete({id:t})}catch(n){throw n}if(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=J(t),o=`I'm trying to delete a record from a data collection.
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 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=Rt(o);n[i]=await this.fetchExampleRecords(o)}return n}}class Ti extends oe{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`);try{await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).delete({id:t})}catch(n){throw n}if(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=J(t),o=`I'm trying to delete a record from a data collection.
62
62
 
63
63
  I tried to delete a record with this ID:
64
64
 
@@ -78,7 +78,7 @@ Format your response as a JSON object with two fields:
78
78
  "id": "fixed id"
79
79
  }.
80
80
 
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class Si extends oe{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=J(t),o=`I'm trying to find a record by ID in a data collection.
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class xi extends oe{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=J(t),o=`I'm trying to find a record by ID in a data collection.
82
82
 
83
83
  I tried to find a record with this ID:
84
84
 
@@ -98,7 +98,7 @@ Format your response as a JSON object with two fields:
98
98
  "id": "fixed id"
99
99
  }.
100
100
 
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class bi extends oe{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=J(t),o=`I'm trying to list records from a data collection.
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{id:s.id}}}}class Ii extends oe{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=J(t),o=`I'm trying to list records from a data collection.
102
102
 
103
103
  I tried to list records with these parameters:
104
104
 
@@ -118,7 +118,7 @@ Format your response as a JSON object with two fields:
118
118
  "input": { ... fixed parameters ... }
119
119
  }.
120
120
 
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input}}}class vi extends oe{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(()=>Ct(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=J(t),o=`I'm trying to match a record in a data collection.
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input}}}class $i extends oe{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(()=>vt(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=J(t),o=`I'm trying to match a record in a data collection.
122
122
 
123
123
  I tried to match a record with this query:
124
124
 
@@ -138,7 +138,7 @@ Format your response as a JSON object with two fields:
138
138
  "query": { ... fixed query ... }
139
139
  }.
140
140
 
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{query:s.query}}}}class Ei extends oe{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.
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:{query:s.query}}}}class ki extends oe{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
142
 
143
143
  Record fields:
144
144
  ${JSON.stringify(e,null,2)}
@@ -163,7 +163,7 @@ Format your response as a JSON object with two fields:
163
163
  "input": { ... fixed parameters ... }
164
164
  }.
165
165
 
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input,expectedRecordId:e.expectedRecordId}}}class Ti extends oe{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 xi extends oe{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=Le(this.dataCollection),s=Tt(i),a=ve(e.input.fields,s,{skipUnknownFields:!0}),l=ve(o.record.fields,s),d=wt(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=Le(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=J(t),o=Le(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:
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(w.bold.yellow("[auto-fix]"),`${this.path}:`,s.explanation),{input:s.input,expectedRecordId:e.expectedRecordId}}}class Ri extends oe{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 Pi extends oe{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=Ue(this.dataCollection),s=$t(i),a=xe(e.input.fields,s,{skipUnknownFields:!0}),l=xe(o.record.fields,s),d=bt(l,a);await this.assert(()=>!d,"Returned fields match updated fields",{difference:d,sentFields:a,receivedFields:l})}}async generateConfig(){let e=this.environment.state[this.dataCollectionKey]?.createdRecordId;if(!e){if(!this.dataCollection.list)throw new Error(`Can't find a record to test update operation for ${this.dataCollectionKey}. List operation is not implemented for this data collection`);const o=await this.environment.client.connection(this.environment.connectionId).dataCollection(this.dataCollectionKey).list({});if(!o?.records?.length)throw new Error(`No records found to test update for ${this.dataCollectionKey}`);e=o.records[0].id}const t=Ue(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=J(t),o=Ue(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
167
 
168
168
  ${JSON.stringify(o,null,2)}
169
169
 
@@ -203,9 +203,9 @@ ${JSON.stringify(o,null,2)}`).join(`
203
203
 
204
204
  `)}.
205
205
 
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 xt(e,o=>{if(o.referenceCollection){const i=o.referenceCollection.key,s=o.referenceCollection.parameters,a=`${i}:${JSON.stringify(s||{})}`;t.has(a)||(t.add(a),n.push({key:i,parameters:s}))}return o}),n}async fetchExampleRecords(e){return(await this.environment.client.connection(this.environment.connectionId).dataCollection(e.key).list({parameters:e.parameters})).records.map(n=>({id:n.id,fields:n.fields||{}}))}async getExampleRecordsForSchema(e){const t=await this.findReferenceCollections(e),n={};for(const o of t){const i=It(o);n[i]=await this.fetchExampleRecords(o)}return n}}const St={spec:{testerClass:Ti},create:{testerClass:wi,operationKey:"create"},"find-by-id":{testerClass:Si,operationKey:"findById"},list:{testerClass:bi,operationKey:"list"},match:{testerClass:vi,operationKey:"match"},search:{testerClass:Ei,operationKey:"search"},update:{testerClass:xi,operationKey:"update"},delete:{testerClass:Ci,operationKey:"delete"}};class Ii extends yi{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);k.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=St[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(St).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(St).filter(([,t])=>{const n="operationKey"in t?t.operationKey:void 0;return this.isOperationAvailable(e,n)}).map(([t])=>t)}displayTestSummary(e){k.info(`\u{1F4CA} ${e} test${e===1?"":"s"} executed`)}}class $i extends fi{static{c(this,"TestRunner")}constructor(e){super(e)}async initialize(){k.debug("Initializing test runner",{prefix:"TestRunner"})}async run(){try{const{testPath:e,path:t,fix:n}=this.options,o=e.split("/");o.length<2&&(k.error("Invalid test path. Expected format: <type>/<name>[/additional/path][/method]"),process.exit(1));const[i,s,...a]=o;i!=="connectors"&&(k.error(`Test type "${i}" is not yet fully implemented. Currently only "connectors" is fully supported.`),k.error("Supported test types: connectors"),process.exit(1));const l=s,d=i,h=[...a,...t?t.split("/"):[]].join("/"),p=await bt.create({connectionId:l,testBasePath:d,options:{fix:n}}),C=await p.client.get(`connections/${l}/data`),E=[],S=h?h.split("/"):[];if(S.length===0||S[0]==="data"){S[0]==="data"&&S.shift();let O,U;S.length>=1&&(U=S[0],S.length>=2&&S[1].trim()!==""&&(O=S[1]));for(const K of C){if(U&&U!==K.key)continue;const L=new Ii({environment:p,dataCollectionKey:K.key,testMethod:O});E.push(L)}}E.length===0&&(k.error(`No test suites found for path: ${e}${h?"/"+h:""}`),process.exit(1));const N={};for(const O of E){await O.run();const U=O.getResult();k.debug(`Suite ${O.constructor.name} result:`,{prefix:"TestRunner"}),Je(N,U)}console.debug("[TestRunner] All results collected:",Object.keys(N)),p.writeResults(N)}catch(e){throw console.error("Error in TestRunner.run():",e),e}}}const De=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(`
207
- `),"createExperimentalWarning");function ki(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",De()).action(async()=>{console.warn(De()),k.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.integration.app/cli"),"",De()].join(`
208
- `)).action(async(t,n)=>{try{console.warn(De()),t||(k.error("Test path is required"),process.exit(1)),k.header(`Testing: ${t}`);const o=new $i({testPath:t,path:n.path,fix:n.fix});await o.initialize(),await o.run(),k.success("Tests completed")}catch(o){o instanceof Error&&(k.error(o.message),process.exit(1)),k.error("An unknown error occurred"),process.exit(1)}})}c(ki,"setupTestCommand");const Ri=c(()=>{try{const r=$n(import.meta.url),e=In(r),t=Oe(e,"..","package.json");return JSON.parse(xn(t,"utf-8")).version}catch{return"1.0.0"}},"getPackageVersion"),bn=Ri();function Pi(){process.on("SIGINT",()=>process.exit(130));const r=new kn().name("membrane").description("Command-line interface for Membrane Agent").version(bn,"-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",`
209
- ${w.bold.cyan("Membrane Agent CLI")} ${w.gray(`v${bn}`)}
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 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=Rt(o);n[i]=await this.fetchExampleRecords(o)}return n}}const Et={spec:{testerClass:Ri},create:{testerClass:Ei,operationKey:"create"},"find-by-id":{testerClass:xi,operationKey:"findById"},list:{testerClass:Ii,operationKey:"list"},match:{testerClass:$i,operationKey:"match"},search:{testerClass:ki,operationKey:"search"},update:{testerClass:Pi,operationKey:"update"},delete:{testerClass:Ti,operationKey:"delete"}};class Ai extends vi{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);R.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=Et[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(Et).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(Et).filter(([,t])=>{const n="operationKey"in t?t.operationKey:void 0;return this.isOperationAvailable(e,n)}).map(([t])=>t)}displayTestSummary(e){R.info(`\u{1F4CA} ${e} test${e===1?"":"s"} executed`)}}class Di extends Ci{static{c(this,"TestRunner")}constructor(e){super(e)}async initialize(){R.debug("Initializing test runner",{prefix:"TestRunner"})}async run(){try{const{testPath:e,path:t,fix:n}=this.options,o=e.split("/");o.length<2&&(R.error("Invalid test path. Expected format: <type>/<name>[/additional/path][/method]"),process.exit(1));const[i,s,...a]=o;i!=="connectors"&&(R.error(`Test type "${i}" is not yet fully implemented. Currently only "connectors" is fully supported.`),R.error("Supported test types: connectors"),process.exit(1));const l=s,d=i,h=[...a,...t?t.split("/"):[]].join("/"),f=await Tt.create({connectionId:l,testBasePath:d,options:{fix:n}}),C=await f.client.get(`connections/${l}/data`),E=[],S=h?h.split("/"):[];if(S.length===0||S[0]==="data"){S[0]==="data"&&S.shift();let O,U;S.length>=1&&(U=S[0],S.length>=2&&S[1].trim()!==""&&(O=S[1]));for(const K of C){if(U&&U!==K.key)continue;const L=new Ai({environment:f,dataCollectionKey:K.key,testMethod:O});E.push(L)}}E.length===0&&(R.error(`No test suites found for path: ${e}${h?"/"+h:""}`),process.exit(1));const N={};for(const O of E){await O.run();const U=O.getResult();R.debug(`Suite ${O.constructor.name} result:`,{prefix:"TestRunner"}),He(N,U)}console.debug("[TestRunner] All results collected:",Object.keys(N)),f.writeResults(N)}catch(e){throw console.error("Error in TestRunner.run():",e),e}}}const Ne=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(`
207
+ `),"createExperimentalWarning");function Oi(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",Ne()).action(async()=>{console.warn(Ne()),R.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"),"",Ne()].join(`
208
+ `)).action(async(t,n)=>{try{console.warn(Ne()),t||(R.error("Test path is required"),process.exit(1)),R.header(`Testing: ${t}`);const o=new Di({testPath:t,path:n.path,fix:n.fix});await o.initialize(),await o.run(),R.success("Tests completed")}catch(o){o instanceof Error&&(R.error(o.message),process.exit(1)),R.error("An unknown error occurred"),process.exit(1)}})}c(Oi,"setupTestCommand");const Ni=c(()=>{try{const r=An(import.meta.url),e=Rn(r),t=Me(e,"..","package.json");return JSON.parse(kn(t,"utf-8")).version}catch{return"1.0.0"}},"getPackageVersion"),Tn=Ni();function Mi(){process.on("SIGINT",()=>process.exit(130));const r=new Dn().name("membrane").description("Command-line interface for Membrane Agent").version(Tn,"-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",`
209
+ ${w.bold.cyan("Membrane Agent CLI")} ${w.gray(`v${Tn}`)}
210
210
 
211
- `);const e=new Qr(Re.Cli,process.cwd());Ao(r),_o(r),Eo(r),ki(r),So(r),pi(r,e),fo(r,e),gr(r,e),lo(r,e),process.argv.length===2&&(r.outputHelp(),process.exit(0)),r.parse(),r.opts().verbose&&m.setVerboseMode(!0)}c(Pi,"runCLI"),Pi();
211
+ `);const e=new oo(De.Cli,process.cwd());Mo(r),Vo(r),ko(r),Oi(r),xo(r),wi(r,e),Co(r,e),br(r,e),mo(r,e),process.argv.length===2&&(r.outputHelp(),process.exit(0)),r.parse(),r.opts().verbose&&m.setVerboseMode(!0)}c(Mi,"runCLI"),Mi();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@membranehq/cli",
3
- "version": "1.4.3",
3
+ "version": "1.4.5",
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.14.0",
33
+ "@membranehq/sdk": "^0.15.0",
34
34
  "@modelcontextprotocol/sdk": "^1.25.2",
35
35
  "@types/js-yaml": "^4.0.9",
36
36
  "@types/jsonwebtoken": "^9.0.10",
@@ -63,6 +63,7 @@
63
63
  "ora": "^9.0.0",
64
64
  "react": "^18.3.1",
65
65
  "react-dom": "^18.3.1",
66
+ "semver": "^7.7.3",
66
67
  "swr": "^2.3.4",
67
68
  "unzipper": "^0.12.3",
68
69
  "yaml": "^2.6.1",