@membranehq/cli 1.4.1-beta.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -39
- package/dist/index.js +2 -2
- package/package.json +18 -18
package/README.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# Membrane CLI
|
|
2
2
|
|
|
3
|
-
A command-line interface for working with Membrane in
|
|
3
|
+
A command-line interface for working with Membrane in local development environment.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
|
+
|
|
6
7
|
```bash
|
|
7
8
|
npm install -g @membranehq/cli
|
|
8
9
|
# or
|
|
@@ -11,25 +12,43 @@ yarn global add @membranehq/cli
|
|
|
11
12
|
bun install -g @membranehq/cli
|
|
12
13
|
# or
|
|
13
14
|
pnpm install -g @membranehq/cli
|
|
14
|
-
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## Quick Start
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
```bash
|
|
20
|
+
# Initialize with your workspace credentials (interactive)
|
|
21
|
+
membrane init
|
|
22
|
+
|
|
23
|
+
# Or non-interactive
|
|
24
|
+
membrane init --key <key> --secret <secret>
|
|
25
|
+
|
|
26
|
+
# Pull workspace elements
|
|
27
|
+
membrane pull
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
# Make changes, then push back
|
|
30
|
+
membrane push
|
|
31
|
+
```
|
|
22
32
|
|
|
23
|
-
|
|
33
|
+
See the Configuration section below for alternative ways to configure credentials.
|
|
34
|
+
|
|
35
|
+
## Commands
|
|
24
36
|
|
|
25
|
-
## Commands Reference
|
|
26
37
|
```bash
|
|
27
|
-
#
|
|
38
|
+
# Initialize workspace configuration
|
|
39
|
+
membrane init --key <key> --secret <secret>
|
|
40
|
+
|
|
41
|
+
# Pull workspace elements from remote
|
|
42
|
+
membrane pull [--force]
|
|
43
|
+
|
|
44
|
+
# Push workspace elements to remote
|
|
45
|
+
membrane push [--force]
|
|
46
|
+
|
|
47
|
+
# Get help
|
|
28
48
|
membrane --help
|
|
29
|
-
# View membrane <command> help
|
|
30
49
|
membrane <command> --help
|
|
31
50
|
|
|
32
|
-
# Check
|
|
51
|
+
# Check version
|
|
33
52
|
membrane --version
|
|
34
53
|
```
|
|
35
54
|
|
|
@@ -42,8 +61,9 @@ The CLI can be configured using either environment variables or a configuration
|
|
|
42
61
|
```bash
|
|
43
62
|
export MEMBRANE_WORKSPACE_KEY=<your-workspace-key>
|
|
44
63
|
export MEMBRANE_WORKSPACE_SECRET=<your-workspace-secret>
|
|
45
|
-
export MEMBRANE_API_URI=https://api.your-membrane-instance.com #
|
|
46
|
-
export
|
|
64
|
+
export MEMBRANE_API_URI=https://api.your-membrane-instance.com # Optional: for self-hosted instances (default: https://api.integration.app)
|
|
65
|
+
export MEMBRANE_CONSOLE_URI=https://console.your-membrane-instance.com # Optional: for self-hosted instances (default: https://console.integration.app)
|
|
66
|
+
export MEMBRANE_TEST_CUSTOMER_ID=<test-customer-id> # Optional: for testing integrations
|
|
47
67
|
```
|
|
48
68
|
|
|
49
69
|
### Configuration File
|
|
@@ -53,9 +73,12 @@ The CLI uses a configuration file at `membrane.config.yml`:
|
|
|
53
73
|
```yaml
|
|
54
74
|
workspaceKey: <your-workspace-key>
|
|
55
75
|
workspaceSecret: <your-workspace-secret>
|
|
76
|
+
|
|
56
77
|
# Optional
|
|
57
|
-
apiUri: https://api.your-membrane-instance.com #
|
|
58
|
-
|
|
78
|
+
apiUri: https://api.your-membrane-instance.com # For self-hosted instances (default: https://api.integration.app)
|
|
79
|
+
consoleUri: https://console.your-membrane-instance.com # For self-hosted instances (default: https://console.integration.app)
|
|
80
|
+
|
|
81
|
+
testCustomerId: test-customer # Internal ID of customer for testing integrations
|
|
59
82
|
```
|
|
60
83
|
|
|
61
84
|
**Note:** When both environment variables and configuration file are present, environment variables take precedence.
|
|
@@ -68,46 +91,46 @@ testCustomerId: test-customer # Internal id of the customer to be used for testi
|
|
|
68
91
|
|
|
69
92
|
`membrane` folder can and should be stored in version control to keep your integration configurations versioned.
|
|
70
93
|
|
|
71
|
-
##
|
|
94
|
+
## Transferring elements between workspaces with `pull` and `push`
|
|
72
95
|
|
|
73
|
-
The CLI provides a `pull` and `push` command to
|
|
96
|
+
The CLI provides a `pull` and `push` command to transfer workspace elements between environments. You'd typically use this to move integrations, actions, flows, and other configurations from development to production.
|
|
74
97
|
|
|
75
|
-
**
|
|
98
|
+
**How it works:**
|
|
76
99
|
|
|
77
|
-
|
|
78
|
-
membrane pull
|
|
100
|
+
Workspace elements (integrations, actions, data sources, flows, field mappings, etc.) are stored as YAML files in the `./membrane` directory. Each element has a unique UUID that identifies it across workspaces.
|
|
79
101
|
|
|
80
|
-
|
|
102
|
+
When you **pull**, the CLI:
|
|
81
103
|
|
|
82
|
-
|
|
83
|
-
|
|
104
|
+
- Exports all elements from the remote workspace as YAML
|
|
105
|
+
- Compares them with your local `./membrane` directory by UUID
|
|
106
|
+
- Identifies what's new, changed, or deleted in the remote workspace
|
|
107
|
+
- Downloads connector source code for custom connectors
|
|
108
|
+
- Updates your local files to match the remote state
|
|
84
109
|
|
|
85
|
-
**
|
|
110
|
+
When you **push**, the CLI:
|
|
86
111
|
|
|
87
|
-
|
|
112
|
+
- Packages your local `./membrane` directory as an export
|
|
113
|
+
- Compares it with the current state of the remote workspace
|
|
114
|
+
- Identifies what's new, changed, or deleted locally
|
|
115
|
+
- Uploads connector source code for custom connectors
|
|
116
|
+
- Applies the changes to the remote workspace
|
|
88
117
|
|
|
89
|
-
|
|
118
|
+
Changes are applied in dependency order (integrations before integration-level elements, parents before children) to maintain referential integrity. Conflicts occur when an element exists in only one location; use `--force` to resolve by preferring the source.
|
|
90
119
|
|
|
91
|
-
|
|
92
|
-
echo "📝 Setting up development workspace credentials..."
|
|
93
|
-
export MEMBRANE_WORKSPACE_KEY="dev-workspace-key-123"
|
|
94
|
-
export MEMBRANE_WORKSPACE_SECRET="dev-workspace-secret-456"
|
|
120
|
+
**Example:**
|
|
95
121
|
|
|
96
|
-
|
|
97
|
-
|
|
122
|
+
```bash
|
|
123
|
+
# Pull from development workspace
|
|
124
|
+
export MEMBRANE_WORKSPACE_KEY="dev-workspace-key"
|
|
125
|
+
export MEMBRANE_WORKSPACE_SECRET="dev-workspace-secret"
|
|
98
126
|
membrane pull
|
|
99
127
|
|
|
100
|
-
#
|
|
101
|
-
|
|
102
|
-
export
|
|
103
|
-
export MEMBRANE_WORKSPACE_SECRET="prod-workspace-secret-012"
|
|
104
|
-
|
|
105
|
-
# Step 4: Push changes to production workspace
|
|
106
|
-
echo "⬆️ Pushing changes to production workspace..."
|
|
128
|
+
# Push to production workspace
|
|
129
|
+
export MEMBRANE_WORKSPACE_KEY="prod-workspace-key"
|
|
130
|
+
export MEMBRANE_WORKSPACE_SECRET="prod-workspace-secret"
|
|
107
131
|
membrane push
|
|
108
132
|
```
|
|
109
133
|
|
|
110
|
-
|
|
111
134
|
## License
|
|
112
135
|
|
|
113
|
-
MIT
|
|
136
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var vn=Object.defineProperty;var c=(r,e)=>vn(r,"name",{value:e,configurable:!0})
|
|
|
6
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
7
|
Membrane API Error:`),a&&console.error(a),console.error(JSON.stringify(J(s),null,2))):_n(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.log({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(`
|
|
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
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
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
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.
|
|
@@ -16,7 +16,7 @@ ${w.red(t.error)}`:""):console.debug(w.gray(e),t?.error?`
|
|
|
16
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
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
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();h.parentUuid=n.get(p)||p}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(`
|
|
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
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
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:
|
|
22
22
|
|
package/package.json
CHANGED
|
@@ -1,44 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@membranehq/cli",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
|
+
"description": "",
|
|
4
5
|
"keywords": [
|
|
5
6
|
"cli",
|
|
6
7
|
"integration",
|
|
7
8
|
"membrane"
|
|
8
9
|
],
|
|
9
10
|
"author": "",
|
|
10
|
-
"type": "module",
|
|
11
|
-
"description": "",
|
|
12
|
-
"source": "./src/index.ts",
|
|
13
11
|
"bin": {
|
|
14
12
|
"membrane": "./dist/index.js"
|
|
15
13
|
},
|
|
16
|
-
"
|
|
17
|
-
"node": ">=20"
|
|
18
|
-
},
|
|
19
|
-
"exports": {
|
|
20
|
-
".": {
|
|
21
|
-
"import": "./dist/index.js",
|
|
22
|
-
"types": "./dist/index.d.ts"
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
"main": "dist/index.js",
|
|
14
|
+
"source": "./src/index.ts",
|
|
26
15
|
"files": [
|
|
27
16
|
"dist",
|
|
28
17
|
"package.json",
|
|
29
18
|
"README.md"
|
|
30
19
|
],
|
|
20
|
+
"type": "module",
|
|
21
|
+
"main": "dist/index.js",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
31
28
|
"dependencies": {
|
|
32
29
|
"@anthropic-ai/sdk": "0.62.0",
|
|
33
30
|
"@buildwithlayer/openapi-to-tools": "^1.3.3",
|
|
34
31
|
"@faker-js/faker": "^9.8.0",
|
|
35
32
|
"@inkjs/ui": "^2.0.0",
|
|
36
|
-
"@membranehq/sdk": "^0.
|
|
33
|
+
"@membranehq/sdk": "^0.13.0",
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
37
35
|
"@types/js-yaml": "^4.0.9",
|
|
38
36
|
"@types/jsonwebtoken": "^9.0.10",
|
|
39
37
|
"@types/lodash": "^4.17.17",
|
|
40
|
-
"@types/react": "18.3.12",
|
|
41
|
-
"@types/react-dom": "18.3.7",
|
|
42
38
|
"archiver": "^7.0.1",
|
|
43
39
|
"axios": "^1.12.0",
|
|
44
40
|
"axios-logger": "^2.8.1",
|
|
@@ -50,10 +46,12 @@
|
|
|
50
46
|
"eventsource": "^4.0.0",
|
|
51
47
|
"fastmcp": "^3.23.1",
|
|
52
48
|
"form-data": "^4.0.4",
|
|
49
|
+
"hono": "4.11.4",
|
|
53
50
|
"ink": "^5.2.1",
|
|
54
51
|
"ink-select-input": "^6.2.0",
|
|
55
52
|
"ink-spinner": "^5.0.0",
|
|
56
53
|
"ink-text-input": "^6.0.0",
|
|
54
|
+
"js-convert-case": "^4.2.0",
|
|
57
55
|
"js-yaml": "^4.1.0",
|
|
58
56
|
"jsonwebtoken": "^9.0.3",
|
|
59
57
|
"jszip": "^3.10.1",
|
|
@@ -68,7 +66,9 @@
|
|
|
68
66
|
"swr": "^2.3.4",
|
|
69
67
|
"unzipper": "^0.12.3",
|
|
70
68
|
"yaml": "^2.6.1",
|
|
71
|
-
"js-convert-case": "^4.2.0",
|
|
72
69
|
"zod": "^4.0.0"
|
|
70
|
+
},
|
|
71
|
+
"engines": {
|
|
72
|
+
"node": ">=20"
|
|
73
73
|
}
|
|
74
74
|
}
|