@superglue/cli 1.1.138 → 1.1.140

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "superglue",
3
3
  "description": "Build, test, and manage superglue tools via the sg CLI. Use when working with superglue tools, systems, APIs, SDKs, or the sg command.",
4
- "version": "1.1.138",
4
+ "version": "1.1.140",
5
5
  "author": {
6
6
  "name": "superglue",
7
7
  "email": "hello@superglue.cloud"
package/dist/cli.js CHANGED
@@ -1754,7 +1754,7 @@ ${o}`;break;case"retry":Lz(o)&&(r[i]=o);break;case"id":Pz(o)&&(r[i]=o);break;cas
1754
1754
  `);t.stack=r?`${r}
1755
1755
  ${o}`:i.stack}V.exports.fetch=function(e,r=void 0){return iDe(e,r).catch(n=>{throw Jz?eH(n,Jz):n&&typeof n=="object"&&Error.captureStackTrace(n,V.exports.fetch),n})};V.exports.Headers=Za().Headers;V.exports.Response=gd().Response;V.exports.Request=vu().Request;V.exports.FormData=hh().FormData;var{setGlobalOrigin:oDe,getGlobalOrigin:sDe}=AS();V.exports.setGlobalOrigin=oDe;V.exports.getGlobalOrigin=sDe;var{CacheStorage:aDe}=Mq(),{kConstruct:cDe}=$e();V.exports.caches=new aDe(cDe);var{deleteCookie:uDe,getCookies:lDe,getSetCookies:ADe,setCookie:dDe,parseCookie:fDe}=Yq();V.exports.deleteCookie=uDe;V.exports.getCookies=lDe;V.exports.getSetCookies=ADe;V.exports.setCookie=dDe;V.exports.parseCookie=fDe;var{parseMIMEType:pDe,serializeAMimeType:gDe}=fn();V.exports.parseMIMEType=pDe;V.exports.serializeAMimeType=gDe;var{CloseEvent:hDe,ErrorEvent:mDe,MessageEvent:yDe}=Um(),{WebSocket:EDe,ping:IDe}=vz();V.exports.WebSocket=EDe;V.exports.CloseEvent=hDe;V.exports.ErrorEvent=mDe;V.exports.MessageEvent=yDe;V.exports.ping=IDe;V.exports.WebSocketStream=Uz().WebSocketStream;V.exports.WebSocketError=$w().WebSocketError;V.exports.request=vd(Lu.request);V.exports.stream=vd(Lu.stream);V.exports.pipeline=vd(Lu.pipeline);V.exports.connect=vd(Lu.connect);V.exports.upgrade=vd(Lu.upgrade);V.exports.MockClient=G_e;V.exports.MockCallHistory=V_e;V.exports.MockCallHistoryLog=Y_e;V.exports.MockPool=J_e;V.exports.MockAgent=W_e;V.exports.SnapshotAgent=Z_e;V.exports.mockErrors=K_e;var{EventSource:CDe}=Wz();V.exports.EventSource=CDe;function bDe(){globalThis.fetch=V.exports.fetch,globalThis.Headers=V.exports.Headers,globalThis.Response=V.exports.Response,globalThis.Request=V.exports.Request,globalThis.FormData=V.exports.FormData,globalThis.WebSocket=V.exports.WebSocket,globalThis.CloseEvent=V.exports.CloseEvent,globalThis.ErrorEvent=V.exports.ErrorEvent,globalThis.MessageEvent=V.exports.MessageEvent,globalThis.EventSource=V.exports.EventSource}V.exports.install=bDe});var nH=h(Fu=>{"use strict";Object.defineProperty(Fu,"__esModule",{value:!0});Fu.SuperglueClient=Fu.SuperglueHttpError=void 0;var Pu=br(),Ho=NC(),SDe=ab(),BDe=px(),QDe=Vn(),Go=Tc(),wDe=$l(),Dd=14400*1e3,_d;if(typeof globalThis.process<"u"&&globalThis.process.versions?.node)try{let{Agent:t}=tH();_d=new t({headersTimeout:Dd,bodyTimeout:Dd})}catch{}function rH(t){if(t?.aborted)throw t.reason??new DOMException("Aborted","AbortError")}var Wm=class extends Error{constructor(e,r,n,i){super(e),this.status=r,this.code=n,this.details=i,this.name="SuperglueHttpError"}};Fu.SuperglueHttpError=Wm;var Vw=class{constructor({apiKey:e,apiEndpoint:r,onInfrastructureError:n,refreshToken:i,sseTokenProvider:o,tokenProvider:s}){if(!e&&!s)throw new Error("SuperglueClient requires either apiKey or tokenProvider");this.tokenProvider=s??(async()=>e),this.apiEndpoint=r??"https://api.superglue.cloud",this.sseManager=new SDe.SSELogSubscriptionManager(this.apiEndpoint,o??this.tokenProvider,i),this.onInfrastructureError=n,this.refreshToken=i}async getApiKey(){return this.tokenProvider()}async fetchWithAuthRetry(e,r){let n=await this.getApiKey(),i=await e(n);if(i.status!==401||!this.refreshToken)return i;rH(r);let o=await this.refreshToken();return rH(r),!o||o===n?i:(i.body?.cancel(),e(o))}isInfrastructureError(e){return(0,QDe.isAbortError)(e)?!1:!!(e instanceof TypeError&&e.message.toLowerCase().includes("fetch")||e instanceof Error&&e.name==="TimeoutError")}async restRequest(e,r,n,i,o){let a=await(await this.restResponse({method:e,path:r,body:n,extraHeaders:i,requestInit:o})).text();if(a)return JSON.parse(a)}async restResponse({method:e,path:r,body:n,extraHeaders:i,requestInit:o}){let s=`${this.apiEndpoint.replace(/\/$/,"")}${r}`,a=n!=null,c=typeof FormData<"u"&&n instanceof FormData,u=A=>{let d={Authorization:`Bearer ${A}`,...i};return a&&!c&&e!=="GET"&&(d["Content-Type"]="application/json"),fetch(s,{...o,method:e,headers:d,body:a?c?n:JSON.stringify(n):void 0,signal:o?.signal??AbortSignal.timeout(Dd),..._d?{dispatcher:_d}:{}})},l;try{l=await this.fetchWithAuthRetry(u,o?.signal)}catch(A){throw this.isInfrastructureError(A)&&this.onInfrastructureError?.(),A}if(!l.ok)throw await this.buildHttpError(l);return l}async uploadFiles(e,r){if(typeof r?.process!="boolean")throw new Error("process must be a boolean");if(e.length===0)return[];let n=e.map(l=>({...l,contentLength:l.contentLength??this.getUploadContentLength(l.content)})),o=(await this.restRequest("POST","/v1/files/uploads",{process:r.process,files:n.map(({fileName:l,contentType:A,contentLength:d})=>({fileName:l,contentLength:d,...A?{contentType:A}:{}}))})).data.files;if(o.length!==n.length)throw await Promise.all(o.map(l=>this.deleteFileUpload(l.id).catch(()=>{}))),new Error("Upload response did not match the selected files");let s=await Promise.allSettled(o.map(async(l,A)=>{let d=n[A],f=await fetch(l.uploadUrl,{method:"PUT",body:d.content,headers:d.contentType?{"Content-Type":d.contentType}:void 0,signal:AbortSignal.timeout(Math.min(Dd,l.expiresIn*1e3))});if(!f.ok)throw new Error(`Upload failed for ${d.fileName}: ${f.status} ${f.statusText}`);return l.id})),a=s.flatMap(l=>l.status==="fulfilled"?[l.value]:[]),c=new Map;if(a.length>0)try{let l=await this.restRequest("POST","/v1/files/uploads/complete",{fileIds:a});c=new Map(l.data.files.map(A=>[A.id,A]))}catch(l){c=new Map(a.map(A=>[A,{id:A,fileName:n[o.findIndex(d=>d.id===A)]?.fileName||A,contentLength:n[o.findIndex(d=>d.id===A)]?.contentLength||0,status:"failed",error:l instanceof Error?l.message:String(l)}]))}let u=o.map((l,A)=>{let d=s[A],f=n[A];return d.status==="rejected"?{id:l.id,fileName:f.fileName,contentLength:f.contentLength,status:"failed",error:d.reason instanceof Error?d.reason.message:String(d.reason)}:c.get(l.id)||{id:l.id,fileName:f.fileName,contentLength:f.contentLength,status:"failed",error:"Upload completion returned no result"}});return await Promise.all(u.filter(l=>l.status==="failed").map(l=>this.deleteFileUpload(l.id).catch(()=>{}))),u}async deleteFileUpload(e){await this.restRequest("DELETE",`/v1/files/uploads/${encodeURIComponent(e)}`)}getUploadContentLength(e){return typeof e=="string"?new TextEncoder().encode(e).byteLength:e instanceof Uint8Array?e.byteLength:e.size}async buildHttpError(e){e.status>=500&&this.onInfrastructureError?.();let r=await e.text(),n=`HTTP ${e.status}: ${r}`,i,o;try{let s=JSON.parse(r);s&&typeof s=="object"&&!Array.isArray(s)&&(o=s),typeof s?.code=="string"&&(i=s.code);let a=s.error;typeof a=="string"?n=a:a&&typeof a=="object"&&(n=a.message||JSON.stringify(a))}catch{}return new Wm(n,e.status,i,o)}async streamRequest(e,r,n){let i=e.includes("?")?"&":"?",o=`${this.apiEndpoint.replace(/\/$/,"")}${e}${i}stream=true`,s=u=>fetch(o,{method:"POST",headers:{Authorization:`Bearer ${u}`,Accept:"text/event-stream","Content-Type":"application/json"},body:JSON.stringify(r),signal:n??AbortSignal.timeout(Dd),..._d?{dispatcher:_d}:{}}),a;try{a=await this.fetchWithAuthRetry(s,n)}catch(u){throw this.isInfrastructureError(u)&&this.onInfrastructureError?.(),u}if(!a.ok)throw await this.buildHttpError(a);if(!(a.headers.get("content-type")||"").includes("text/event-stream")){let u=await a.text();return u?JSON.parse(u):void 0}try{return await(0,BDe.consumeEventStreamResult)(a)}catch(u){throw this.isInfrastructureError(u)&&this.onInfrastructureError?.(),u}}async subscribeToLogsSSE(e={}){return this.sseManager.subscribeToLogs(e)}async disconnect(){await this.sseManager.disconnect()}async getMe(){return this.restRequest("GET","/v1/me")}async completeOnboarding(){return this.restRequest("POST","/v1/me/onboarding/complete")}async runTool(e){let r=await this.restRequest("POST",`/v1/tools/${encodeURIComponent(e.toolId)}/run`,{inputs:e.payload,files:e.files,credentials:e.credentials,includeStepResultData:e.includeStepResultData,options:e.options,runId:e.runId,stateFixture:e.stateFixture},void 0,e.signal?{signal:e.signal}:void 0);return{success:r.status==="success",data:r.data,error:r.error,tool:r.tool,stepResults:r.stepResults?.map(n=>({...n}))||[],...r.fileArtifacts&&r.fileArtifacts.length>0?{fileArtifacts:r.fileArtifacts}:{},...r.metadata?.warnings?.length?{warnings:r.metadata.warnings}:{}}}async runToolConfig(e){let r=e.createRun?"/v1/tools/run?createRun=true":"/v1/tools/run",n=await this.restRequest("POST",r,{tool:e.tool,payload:e.payload,files:e.files,credentials:e.credentials,includeStepResultData:e.includeStepResultData,options:e.options,runId:e.runId,stateFixture:e.stateFixture,executionKind:e.executionKind,parentToolId:e.parentToolId,draftId:e.draftId},e.traceId?{"X-Trace-Id":e.traceId}:void 0,e.signal?{signal:e.signal}:void 0);return{success:n.status?n.status==="success":n.success??!1,data:n.data,error:n.error,tool:n.tool||e.tool,stepResults:n.stepResults?.map(o=>({...o}))||[],...n.fileArtifacts&&n.fileArtifacts.length>0?{fileArtifacts:n.fileArtifacts}:{},...n.metadata?.warnings?.length?{warnings:n.metadata.warnings}:{}}}async abortToolExecution(e){return{success:!0,runId:(await this.restRequest("POST",`/v1/runs/${encodeURIComponent(e)}/cancel`)).runId}}async executeStep({step:e,payload:r,files:n,previousResults:i,credentials:o,options:s,runId:a,systemIds:c,createRun:u,parentToolId:l,stepIndex:A,stepId:d,signal:f,stream:g}){let I={step:e,payload:r,files:n,previousResults:i,credentials:o,options:s,runId:a,systemIds:c,createRun:u,parentToolId:l,stepIndex:A,stepId:d};return g?this.streamRequest("/v1/tools/step/run",I,f):this.restRequest("POST","/v1/tools/step/run",I,void 0,f?{signal:f}:void 0)}async abortStep(e){return this.restRequest("POST","/v1/tools/step/abort",{runId:e})}async executeTransformOnly({outputTransform:e,outputSchema:r,inputSchema:n,payload:i,files:o,stepResults:s,options:a,runId:c,createRun:u,parentToolId:l,stepId:A,signal:d,stream:f}){let g={outputTransform:e,outputSchema:r,inputSchema:n,payload:i,files:o,stepResults:s,options:a,runId:c,createRun:u,parentToolId:l,stepId:A};return f?this.streamRequest("/v1/tools/transform/run",g,d):this.restRequest("POST","/v1/tools/transform/run",g,void 0,d?{signal:d}:void 0)}async createRun({toolId:e,toolConfig:r,toolResult:n,stepResults:i,toolPayload:o,status:s,error:a,startedAt:c,completedAt:u,executionKind:l,parentToolId:A,draftId:d}){return this.restRequest("POST","/v1/runs",{toolId:e,toolConfig:r,toolResult:n,stepResults:i,toolPayload:o,status:s,error:a,startedAt:(0,Go.toUTCISOString)(c,"run.startedAt"),completedAt:(0,Go.toUTCISOString)(u,"run.completedAt"),executionKind:l,parentToolId:A,draftId:d})}async checkRunLimit(){return(await this.restRequest("POST","/v1/runs/check-limit")).data}async extract({file:e,envelope:r}){if(!e)throw new Error("File must be provided for extract.");let n=new FormData;n.append("file",e);let i=r?"/v1/extract?envelope=true":"/v1/extract";return this.restRequest("POST",i,n)}mapOpenAPIRunToRun(e){let r={running:Pu.RunStatus.RUNNING,success:Pu.RunStatus.SUCCESS,failed:Pu.RunStatus.FAILED,aborted:Pu.RunStatus.ABORTED};return{runId:e.runId??e.id,toolId:e.toolId,tool:e.tool,systemIds:e.systemIds,status:r[e.status]??Pu.RunStatus.FAILED,toolPayload:e.toolPayload,data:e.data,toolResult:e.data,error:e.error,stepResults:e.stepResults,options:e.options,requestSource:e.requestSource,traceId:e.traceId,resultStorageUri:e.resultStorageUri,userId:e.userId,userEmail:e.userEmail,userName:e.userName,metadata:{...e.metadata,executionKind:e.metadata?.executionKind??Pu.RunExecutionKind.FULL},fileArtifacts:e.fileArtifacts}}mapOpenAPIScheduleToToolSchedule(e){return{...e,lastRunAt:e.lastRunAt?(0,Go.requireUTCDate)(e.lastRunAt,"schedule.lastRunAt"):void 0,nextRunAt:(0,Go.requireUTCDate)(e.nextRunAt,"schedule.nextRunAt"),createdAt:(0,Go.requireUTCDate)(e.createdAt,"schedule.createdAt"),updatedAt:(0,Go.requireUTCDate)(e.updatedAt,"schedule.updatedAt")}}async listRuns(e={}){let r=(0,Ho.createSearchListQueryParams)(e);e.toolId!==void 0&&r.set("toolId",e.toolId),e.searchUserIds?.length&&r.set("searchUserIds",e.searchUserIds.join(",")),e.includeTotal!==void 0&&r.set("includeTotal",String(e.includeTotal)),e.startedAfter!==void 0&&r.set("startedAfter",e.startedAfter instanceof Date?(0,Go.toUTCISOString)(e.startedAfter,"run.startedAfter"):e.startedAfter),e.statuses!==void 0?r.set("status",e.statuses.join(",")):e.status!==void 0&&r.set("status",e.status),e.requestSources!==void 0&&r.set("requestSources",e.requestSources.join(",")),e.executionKinds!==void 0&&r.set("executionKinds",e.executionKinds.join(",")),e.userId!==void 0&&r.set("userId",e.userId),e.systemId!==void 0&&r.set("systemId",e.systemId),e.systemIds!==void 0&&r.set("systemIds",e.systemIds.join(","));let n=r.size>0?`?${r.toString()}`:"",i=await this.restRequest("GET",`/v1/runs${n}`,void 0,void 0,{signal:e.signal});return{data:i.data.map(o=>this.mapOpenAPIRunToRun(o)),total:i.total,page:i.page,limit:i.limit,hasMore:i.hasMore}}async getActivityCounts(e){let r=new URLSearchParams;e?.from&&r.set("from",e.from instanceof Date?(0,Go.toUTCISOString)(e.from,"activity.from"):e.from),e?.to&&r.set("to",e.to instanceof Date?(0,Go.toUTCISOString)(e.to,"activity.to"):e.to);let n=r.toString();return(await this.restRequest("GET",`/v1/activity/counts${n?`?${n}`:""}`,void 0,void 0,{signal:e?.signal})).counts}async getRun(e){try{let r=await this.restRequest("GET",`/v1/runs/${encodeURIComponent(e)}`);return this.mapOpenAPIRunToRun(r)}catch(r){if(r.message?.includes("404")||r.message?.includes("not found"))return null;throw r}}async getTool(e){try{return await this.restRequest("GET",`/v1/tools/${encodeURIComponent(e)}`)}catch(r){if(r.message?.includes("404")||r.message?.includes("not found")||r.message?.includes("403")||r.message?.includes("not allowed"))return null;throw r}}async getToolState(e){return(await this.restRequest("GET",`/v1/tools/${encodeURIComponent(e)}/state`)).state}async setToolState(e,r){await this.restRequest("PUT",`/v1/tools/${encodeURIComponent(e)}/state`,{state:r})}async deleteToolState(e){return(await this.restRequest("DELETE",`/v1/tools/${encodeURIComponent(e)}/state`)).deletedKeys}async archiveTool(e,r=!0){return this.updateTool(e,{archived:r})}async bulkArchiveTools(e,r=!0){return this.restRequest("POST","/v1/tools/bulk/archive",{ids:e,archived:r})}async bulkDeleteTools(e){return this.restRequest("POST","/v1/tools/bulk/delete",{ids:e})}async listTools(e={}){let r=(0,Ho.createListQueryParams)(e);e.includeArchived!==void 0&&r.set("includeArchived",String(e.includeArchived));let n=r.size>0?`?${r.toString()}`:"";return this.restRequest("GET",`/v1/tools${n}`)}async listAllTools(e={}){return(0,Ho.listAllPages)((r,n)=>this.listTools({...e,page:r,limit:n}))}async createTool(e,r){return this.restRequest("POST","/v1/tools",{...r,id:e})}async updateTool(e,r){return this.restRequest("PUT",`/v1/tools/${encodeURIComponent(e)}`,r)}async deleteTool(e){try{return await this.restRequest("DELETE",`/v1/tools/${encodeURIComponent(e)}`),!0}catch(r){if(r.message?.includes("404"))return!1;throw r}}async renameTool(e,r){return this.restRequest("POST",`/v1/tools/${encodeURIComponent(e)}/rename`,{newId:r})}async getWorkflow(e){return this.getTool(e)}async archiveWorkflow(e,r=!0){return this.upsertWorkflow(e,{archived:r})}async createWorkflow(e,r){return this.createTool(e,r)}async updateWorkflow(e,r){return this.updateTool(e,r)}async upsertWorkflow(e,r){return await this.getTool(e)?this.updateTool(e,r):this.createTool(e,r)}async deleteWorkflow(e){return this.deleteTool(e)}async renameWorkflow(e,r){return this.renameTool(e,r)}async listSchedules(e={}){let r=(0,Ho.createListQueryParams)(e),n=r.size>0?`?${r.toString()}`:"",i=e.toolId?`/v1/tools/${encodeURIComponent(e.toolId)}/schedules${n}`:`/v1/schedules${n}`,o=await this.restRequest("GET",i);return{...o,data:o.data.map(s=>this.mapOpenAPIScheduleToToolSchedule(s))}}async listAllSchedules(e={}){return(0,Ho.listAllPages)((r,n)=>this.listSchedules({...e,page:r,limit:n}))}async getToolSchedule(e,r){try{let n=await this.restRequest("GET",`/v1/tools/${encodeURIComponent(e)}/schedules/${encodeURIComponent(r)}`);return this.mapOpenAPIScheduleToToolSchedule(n)}catch(n){if(n.message?.includes("404")||n.message?.includes("not found"))return null;throw n}}async createToolSchedule(e,r){let n=await this.restRequest("POST",`/v1/tools/${encodeURIComponent(e)}/schedules`,{...r,timezone:r.timezone||(0,wDe.getRuntimeTimezone)()});return this.mapOpenAPIScheduleToToolSchedule(n)}async updateToolSchedule(e,r,n){let i=await this.restRequest("PUT",`/v1/tools/${encodeURIComponent(e)}/schedules/${encodeURIComponent(r)}`,n);return this.mapOpenAPIScheduleToToolSchedule(i)}async deleteToolSchedule(e,r){return await this.restRequest("DELETE",`/v1/tools/${encodeURIComponent(e)}/schedules/${encodeURIComponent(r)}`),!0}async bulkSetSchedulesEnabled(e,r){return this.restRequest("POST","/v1/schedules/bulk/enable",{ids:e,enabled:r})}async bulkDeleteSchedules(e){return this.restRequest("POST","/v1/schedules/bulk/delete",{ids:e})}async listCredentials(e={}){let r=(0,Ho.createListQueryParams)(e);e.systemId!==void 0&&r.set("systemId",e.systemId);let n=r.size>0?`?${r.toString()}`:"";return this.restRequest("GET",`/v1/credentials${n}`)}async listAllCredentials(e={}){return(0,Ho.listAllPages)((r,n)=>this.listCredentials({...e,page:r,limit:n}))}async createCredentials(e){return(await this.restRequest("POST","/v1/credentials",e)).data}async replaceCredentials(e,r){return(await this.restRequest("PUT",`/v1/credentials/${encodeURIComponent(e)}`,{credentials:r})).data}async updateCredentials(e,r){return(await this.restRequest("PATCH",`/v1/credentials/${encodeURIComponent(e)}`,r)).data}async deleteCredentials(e){await this.restRequest("DELETE",`/v1/credentials/${encodeURIComponent(e)}`)}async setDefaultCredentials(e){await this.restRequest("POST",`/v1/credentials/${encodeURIComponent(e)}/default`)}async listSystems(e={}){let r=(0,Ho.createListQueryParams)(e),n=r.size>0?`?${r.toString()}`:"";return this.restRequest("GET",`/v1/systems${n}`)}async listAllSystems(e={}){return(0,Ho.listAllPages)((r,n)=>this.listSystems({...e,page:r,limit:n}))}async getSystem(e){return(await this.restRequest("GET",`/v1/systems/${encodeURIComponent(e)}`)).data}async createSystem(e){return(await this.restRequest("POST","/v1/systems",e)).data}async updateSystem(e,r){return(await this.restRequest("PATCH",`/v1/systems/${encodeURIComponent(e)}`,r)).data}async deleteSystem(e){return await this.restRequest("DELETE",`/v1/systems/${encodeURIComponent(e)}`),!0}async bulkDeleteSystems(e){return this.restRequest("POST","/v1/systems/bulk/delete",{ids:e})}async createOAuthExchange(e){return(await this.restRequest("POST","/v1/oauth/exchanges",e)).data}async completeOAuthExchange(e,r){return(await this.restRequest("POST",`/v1/oauth/exchanges/${encodeURIComponent(e)}/complete`,r)).data}async searchSystemDocumentation(e,r){return(await this.restRequest("POST",`/v1/systems/${encodeURIComponent(e)}/documentation/search`,{keywords:r})).data}async triggerSystemDocumentationScrapeJob(e,r){return(await this.restRequest("POST",`/v1/systems/${encodeURIComponent(e)}/documentation/scrape`,r)).data}async fetchOpenApiSpec(e,r,n){return(await this.restRequest("POST",`/v1/systems/${encodeURIComponent(e)}/documentation/openapi`,{url:r,link:n?.link})).data}async uploadSystemDocumentationFiles(e,r,n){let i=await this.uploadFiles(r,{process:!0}),o=i.flatMap(s=>s.status==="uploaded"?[s.id]:[]);if(o.length>0)try{await this.restRequest("POST",`/v1/systems/${encodeURIComponent(e)}/documentation/files`,{fileIds:o,link:n?.link!==!1})}catch(s){throw await Promise.all(o.map(a=>this.deleteFileUpload(a).catch(()=>{}))),s}if(!n?.settle){let s=i.filter(a=>a.status==="failed");if(s.length>0)throw new Error(s.map(a=>a.error).join("; "))}return i}async listSystemDocumentationFiles(e,r){let n=new URLSearchParams;r?.length&&n.set("fileIds",r.join(","));let i=n.size>0?`?${n.toString()}`:"";return(await this.restRequest("GET",`/v1/systems/${encodeURIComponent(e)}/documentation/files${i}`)).data}async getSystemDocumentationFileContent(e,r,n){return(await this.restRequest("GET",`/v1/systems/${encodeURIComponent(e)}/documentation/files/${encodeURIComponent(r)}/content?processed=${n.processed}`)).data}async deleteSystemDocumentationFile(e,r){await this.restRequest("DELETE",`/v1/systems/${encodeURIComponent(e)}/documentation/files/${encodeURIComponent(r)}`)}async generateCredentialsLink(e){try{return{success:!0,credentialsUrl:(await this.restRequest("POST","/v1/authenticate",e||{})).data.credentialsUrl}}catch(r){return{success:!1,error:r.message}}}};Fu.SuperglueClient=Vw});var oH=h(it=>{"use strict";Object.defineProperty(it,"__esModule",{value:!0});it.UnquotedKeyStrategy=it.TripleQuoteStrategy=it.TrailingCommaStrategy=it.SingleQuoteStrategy=it.PythonLiteralStrategy=it.CommentStrategy=it.ResilientJsonParser=it.RepairStrategy=void 0;it.parseJsonResilient=vDe;it.parseJSON=_De;it.isValidJson=DDe;it.prettyPrintJson=TDe;it.minifyJson=RDe;var Fn=class{validate(e){try{return JSON.parse(e),!0}catch{return!1}}};it.RepairStrategy=Fn;var Jm=class extends Fn{constructor(){super(...arguments),this.name="TripleQuoteRepair",this.description="Converts triple-quoted strings to proper JSON, parsing nested JSON content"}canApply(e){return/"""/.test(e)}apply(e){return e.replace(/"""([\s\S]*?)"""/g,(r,n)=>{let i=n.trim();if(i.startsWith("{")&&i.endsWith("}")||i.startsWith("[")&&i.endsWith("]"))try{let s=JSON.parse(i);return JSON.stringify(s)}catch{return`"${n.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t")}"`}return`"${n.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t")}"`})}};it.TripleQuoteStrategy=Jm;var Zm=class extends Fn{constructor(){super(...arguments),this.name="PythonLiteralRepair",this.description="Converts Python literals to JavaScript equivalents"}canApply(e){return/\b(None|True|False)\b/.test(e)}apply(e){return e.replace(/\bNone\b/g,"null").replace(/\bTrue\b/g,"true").replace(/\bFalse\b/g,"false")}};it.PythonLiteralStrategy=Zm;var Km=class extends Fn{constructor(){super(...arguments),this.name="TrailingCommaRepair",this.description="Removes trailing commas from objects and arrays"}canApply(e){return/,\s*[}\]]/.test(e)}apply(e){return e.replace(/,(\s*[}\]])/g,"$1")}};it.TrailingCommaStrategy=Km;var Xm=class extends Fn{constructor(){super(...arguments),this.name="SingleQuoteRepair",this.description="Converts single quotes to double quotes"}canApply(e){return/[{,]\s*'[^']*'\s*:/.test(e)||/:\s*'[^']*'/.test(e)}apply(e){let r=e.replace(/([{,]\s*)'([^']+)'(\s*:)/g,'$1"$2"$3');return r=r.replace(/(:\s*)'([^']+)'(\s*[,}])/g,'$1"$2"$3'),r}};it.SingleQuoteStrategy=Xm;var ey=class extends Fn{constructor(){super(...arguments),this.name="UnquotedKeyRepair",this.description="Adds quotes to unquoted object keys"}canApply(e){return/[{,]\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*:/.test(e)}apply(e){return e.replace(/([{,]\s*)([a-zA-Z_$][a-zA-Z0-9_$]*)(\s*:)/g,'$1"$2"$3')}};it.UnquotedKeyStrategy=ey;var ty=class extends Fn{constructor(){super(...arguments),this.name="CommentRemoval",this.description="Removes JavaScript-style comments"}canApply(e){return/\/\/.*$|\/\*[\s\S]*?\*\//m.test(e)}apply(e){let r=e.replace(/\/\/.*$/gm,"");return r=r.replace(/\/\*[\s\S]*?\*\//g,""),r}};it.CommentStrategy=ty;var Yw=class extends Fn{constructor(){super(...arguments),this.name="UnescapedControlCharactersRepair",this.description="Escapes unescaped control characters (newlines, tabs, etc.) in JSON strings"}canApply(e){try{return JSON.parse(e),!1}catch(r){let n=r.message||"";return n.includes("control character")||n.includes("Bad control")||n.includes("Unexpected token")&&/[\n\r\t]/.test(e)}}apply(e){let r="",n=!1,i=!1;for(let o=0;o<e.length;o++){let s=e[o],a=o>0?e[o-1]:"";if(i){r+=s,i=!1;continue}if(s==="\\"&&n){r+=s,i=!0;continue}if(s==='"'&&a!=="\\"){n=!n,r+=s;continue}if(n)switch(s){case`
1756
1756
  `:r+="\\n";break;case"\r":r+="\\r";break;case" ":r+="\\t";break;case"\b":r+="\\b";break;case"\f":r+="\\f";break;default:let c=s.charCodeAt(0);c<32?r+="\\u"+("0000"+c.toString(16)).slice(-4):r+=s}else r+=s}return r}},Ww=class extends Fn{constructor(){super(...arguments),this.name="TrailingCharactersRepair",this.description="Removes trailing characters after valid JSON structure"}canApply(e){let r=e.trim();if(!r.startsWith("{")&&!r.startsWith("["))return!1;let n=0,i=0,o=!1,s=!1;for(let a=0;a<r.length;a++){let c=r[a];if(o)s?s=!1:c==="\\"?s=!0:c==='"'&&(o=!1);else if(c==='"')o=!0;else if(c==="{")n++;else if(c==="}"){if(n--,n===0&&i===0&&a>0&&a<r.length-1)return!0}else if(c==="[")i++;else if(c==="]"&&(i--,i===0&&n===0&&a>0&&a<r.length-1))return!0}return!1}apply(e){let r=e.trim(),n=0,i=0,o=!1,s=!1,a=-1;for(let c=0;c<r.length;c++){let u=r[c];if(o)s?s=!1:u==="\\"?s=!0:u==='"'&&(o=!1);else if(u==='"')o=!0;else if(u==="{")n++;else if(u==="}"){if(n--,n===0&&i===0&&c>0){a=c;break}}else if(u==="[")i++;else if(u==="]"&&(i--,i===0&&n===0&&c>0)){a=c;break}}return a>0&&a<r.length-1?r.substring(0,a+1):e}},$u=class{constructor(e={}){this.strategies=[],this.repairLog=[],this.options={attemptRepair:!0,maxDepth:10,preserveStringsOnFailure:!1,logRepairs:!1,...e},this.initializeDefaultStrategies(),e.customStrategies&&this.strategies.push(...e.customStrategies)}initializeDefaultStrategies(){this.strategies=[new Jm,new Xm,new Yw,new Ww,new Zm,new Km,new ey,new ty]}parse(e){let r=Date.now();this.repairLog=[];let n=e instanceof Buffer?e.toString("utf8"):String(e);try{return{success:!0,data:JSON.parse(n),metadata:{parseTime:Date.now()-r,strategiesApplied:[]}}}catch(s){if(!this.options.attemptRepair)return{success:!1,error:`JSON parse error: ${s}`,metadata:{parseTime:Date.now()-r}}}let i=n,o=[];for(let s of this.strategies)if(s.canApply(i)){let a=i;if(i=s.apply(i),a!==i){o.push(s.name),this.repairLog.push(s.description),this.options.logRepairs&&console.log(`Applied ${s.name}: ${s.description}`);try{return{success:!0,data:JSON.parse(i),repairs:this.repairLog,metadata:{parseTime:Date.now()-r,strategiesApplied:o}}}catch{}}}try{return{success:!0,data:JSON.parse(i),repairs:this.repairLog,metadata:{parseTime:Date.now()-r,strategiesApplied:o}}}catch(s){let a=this.aggressiveFallback(i);return a.success?{...a,repairs:[...this.repairLog,"Applied aggressive fallback"],metadata:{parseTime:Date.now()-r,strategiesApplied:[...o,"AggressiveFallback"]}}:{success:!1,error:`Failed to parse JSON after applying ${o.length} strategies: ${s}`,repairs:this.repairLog,metadata:{parseTime:Date.now()-r,strategiesApplied:o}}}}aggressiveFallback(e){try{let r=e.indexOf("{"),n=e.indexOf("[");if(r===-1&&n===-1)return{success:!1,error:"No JSON-like structure found"};let i=r===-1?n:n===-1?r:Math.min(r,n),o=e.substring(i);for(let a of this.strategies)a.canApply(o)&&(o=a.apply(o));return{success:!0,data:JSON.parse(o)}}catch(r){return{success:!1,error:`Aggressive fallback failed: ${r}`}}}addStrategy(e){this.strategies.push(e)}removeStrategy(e){this.strategies=this.strategies.filter(r=>r.name!==e)}getStrategies(){return this.strategies.map(e=>e.name)}};it.ResilientJsonParser=$u;var iH=new $u;function vDe(t,e){return(e?new $u(e):iH).parse(t)}function _De(t){let e=iH.parse(t);if(e.success)return e.repairs&&e.repairs.length>0&&console.log("JSON parsed with repairs:",e.repairs),e.data;throw new Error(`Failed to parse JSON: ${e.error}`)}function DDe(t){try{return JSON.parse(t),!0}catch{return!1}}function TDe(t,e=2){return JSON.stringify(t,null,e)}function RDe(t){let r=new $u().parse(t);if(r.success)return JSON.stringify(r.data);throw new Error("Cannot minify invalid JSON")}});var zr=h(X=>{"use strict";var kDe=X&&X.__createBinding||(Object.create?(function(t,e,r,n){n===void 0&&(n=r);var i=Object.getOwnPropertyDescriptor(e,r);(!i||("get"in i?!e.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,n,i)}):(function(t,e,r,n){n===void 0&&(n=r),t[n]=e[r]})),de=X&&X.__exportStar||function(t,e){for(var r in t)r!=="default"&&!Object.prototype.hasOwnProperty.call(e,r)&&kDe(e,t,r)};Object.defineProperty(X,"__esModule",{value:!0});X.SSELogSubscriptionManager=X.SuperglueHttpError=X.SuperglueClient=void 0;de(qR(),X);de(aU(),X);de(yU(),X);de(IU(),X);de(QU(),X);de(wU(),X);de(_U(),X);de(AA(),X);de(YU(),X);de(WU(),X);de(JU(),X);de(ZU(),X);de(NC(),X);de(XU(),X);de(tM(),X);de(rM(),X);de(nM(),X);de(UC(),X);de(oM(),X);de(aM(),X);de(cM(),X);de(lM(),X);de(Vd(),X);de(dM(),X);de(fM(),X);de(gM(),X);de(yM(),X);de(EM(),X);de(QM(),X);de(vM(),X);de(DM(),X);de(SC(),X);de(FM(),X);de(jM(),X);de(Dg(),X);de(tx(),X);de(ib(),X);de(ox(),X);de(ux(),X);de(Ax(),X);de(br(),X);de(Vn(),X);de(dx(),X);de(fx(),X);de(Mg(),X);de(Tc(),X);de($l(),X);var sH=nH();Object.defineProperty(X,"SuperglueClient",{enumerable:!0,get:function(){return sH.SuperglueClient}});Object.defineProperty(X,"SuperglueHttpError",{enumerable:!0,get:function(){return sH.SuperglueHttpError}});var NDe=ab();Object.defineProperty(X,"SSELogSubscriptionManager",{enumerable:!0,get:function(){return NDe.SSELogSubscriptionManager}});de(oH(),X)});var My=require("commander");var Ir=he(require("fs")),uH=he(require("os")),Vo=he(require("path")),Td=he(zr()),aH=new Set(["runner","builder","admin"]),cH={output:{mode:"stdout",directory:".superglue/output"},preset:"admin"};function Yo(t){let e=Vo.join(process.cwd(),".superglue"),r=uH.homedir();if(!r)return e;let n=Vo.join(r,".superglue");return t===!0?e:t===!1?n:Ir.existsSync(Vo.join(e,"config.json"))?e:n}function Jw(t){return Vo.join(Yo(t),"config.json")}function ry(t){let e=Jw(t);if(!Ir.existsSync(e))return{};try{return JSON.parse(Ir.readFileSync(e,"utf-8"))}catch{return{}}}function ju(t){let e=ry(),r=t.apiKey||(0,Td.readProcessEnvironmentValue)("SUPERGLUE_API_KEY")||e.apiKey||"",n=t.endpoint||(0,Td.readProcessEnvironmentValue)("SUPERGLUE_API_ENDPOINT")||e.endpoint||"https://api.superglue.cloud",i=(0,Td.readProcessEnvironmentValue)("SUPERGLUE_WEB_ENDPOINT")||e.webEndpoint||n.replace(/:3002\b/,":3001").replace(/api\.superglue/,"app.superglue"),o=(0,Td.readProcessEnvironmentValue)("SUPERGLUE_CLI_PRESET"),s=o&&aH.has(o)?o:e.preset&&aH.has(e.preset)?e.preset:"admin";return{...cH,...e,apiKey:r,endpoint:n,webEndpoint:i,preset:s,output:{...cH.output,...e.output}}}function ny(t,e){let r=Yo(e);Ir.existsSync(r)||Ir.mkdirSync(r,{recursive:!0}),Ir.writeFileSync(Vo.join(r,"config.json"),JSON.stringify(t,null,2)+`
1757
- `,{mode:384})}function iy(t,e){let r=Vo.join(Yo(e),"drafts");if(Ir.existsSync(r)||Ir.mkdirSync(r,{recursive:!0}),t.output.mode==="stdout+file"){let n=Vo.resolve(t.output.directory);Ir.existsSync(n)||Ir.mkdirSync(n,{recursive:!0})}}var nv=he(zr());var Zw=he(require("readline"));var dH=require("child_process"),fH=require("util");var lH={name:"@superglue/cli",version:"1.1.138",bin:{sg:"./dist/cli.js"},files:[".claude-plugin/","dist/","skills/","LICENSE"],dependencies:{commander:"15.0.0-0","fast-json-patch":"3.1.1"},devDependencies:{"@superglue/shared":"file:../shared","@types/node":"25.5.0",tsup:"8.5.1",typescript:"5.8.3"},scripts:{build:"tsup && (cp -r skills dist/ 2>/dev/null || true)",dev:"tsup --watch","type-check":"tsc --noEmit",prepublishOnly:"npm run build"},publishConfig:{access:"public"}};var UDe=(0,fH.promisify)(dH.exec),or=lH.version;function AH(t){let e=t.match(/^(\d+)(?:-(.+))?$/);return e?{numeric:parseInt(e[1],10),prerelease:e[2]||null}:{numeric:0,prerelease:t}}function sy(t,e){let r=t.split("."),n=e.split("."),i=Math.max(r.length,n.length);for(let o=0;o<i;o++){let s=AH(r[o]||"0"),a=AH(n[o]||"0");if(s.numeric<a.numeric)return-1;if(s.numeric>a.numeric||s.prerelease===null&&a.prerelease!==null)return 1;if(s.prerelease!==null&&a.prerelease===null)return-1;if(s.prerelease!==null&&a.prerelease!==null){if(s.prerelease<a.prerelease)return-1;if(s.prerelease>a.prerelease)return 1}}return 0}async function ay(){try{let t=await fetch("https://registry.npmjs.org/@superglue/cli/latest",{signal:AbortSignal.timeout(5e3)});return t.ok&&(await t.json()).version||null}catch{return null}}var oy=null;function pH(){le()&&(oy=ay())}async function gH(){if(!(!le()||!oy)){try{let t=new Promise(r=>{setTimeout(()=>r(null),2e3).unref()}),e=await Promise.race([oy,t]);e&&sy(or,e)<0&&(console.error(""),console.error(`${m.cyan}${m.bold} Update available: ${or} \u2192 ${e}${m.reset}`),console.error(`${m.cyan} Run ${m.bold}sg update${m.reset}${m.cyan} to upgrade${m.reset}`),console.error(""))}catch{}oy=null}}async function hH(){let t=await ay();if(!t)return{success:!1,message:"Could not fetch latest version from npm"};if(sy(or,t)>=0)return{success:!0,message:`Already on latest version (${or})`};try{return await UDe("npm install -g @superglue/cli@latest"),{success:!0,message:`Updated from ${or} to ${t}`}}catch(e){return{success:!1,message:`Update failed: ${e.message}. Try manually: npm install -g @superglue/cli@latest`}}}var le=()=>process.argv.includes("--table")&&process.stdout.isTTY,bn=()=>process.argv.includes("--full"),m={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",italic:"\x1B[3m",underline:"\x1B[4m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",cyan:"\x1B[36m",white:"\x1B[37m",gray:"\x1B[90m",bgRed:"\x1B[41m",bgGreen:"\x1B[42m",bgYellow:"\x1B[43m",bgBlue:"\x1B[44m",bgMagenta:"\x1B[45m",bgCyan:"\x1B[46m"};function mH(t,e){let r=e||t;return`\x1B]8;;${t}\x07${m.underline}${m.cyan}${r}${m.reset}\x1B]8;;\x07`}function yH(){if(!le())return;let t=m.reset,e=m.dim,r="\x1B[47;30m",n=[" #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@- "," =@@@- @@@@ "," @@@ @@% "," -@@ @@@@= @@@ @@@ @@@@@#@ @@@@@@@ @@@@@@@ @@@@@@ @@@ @@@ @@@ @@@@@@* %@@ "," @@ @@@ *@ @@@ @@@ @@@ :@@ @@@ @@@ -@@ @@@ @% @@@ @@@ @@@ @@* @@# "," #@@ @@@# @@@ @@@ @@@ :@@ @@@ @@@ -@@ @@@ @@@ @@@ @@@ @@* @@ "," @@- @@@@= @@@ @@@ @@@@@@@ @@@@@@ @@@@@@@ @@@ @@% @@@ @@@ @@@ @@@@@. @@."," #@% .@@@@ @@@ @@@ @@@ @@@ @@@ -@@ @@@ @@% @@@ @@@ @@@ @@* @@ "," @@ @ @@@ @@@ @@@ @@@ @@@ @@@ -@@ @@@ @@% @@@ @@@ @@@ @@* *@@ "," -@@ @@@@= @@@@@@ @@@ @@@@@@@ @@@ -@@ @@@@@@ @@@@@@% @@@@@@. @@@@@@* #@@ "," :@@* @@@ "," %@@@ =@@@. "," :@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@% "];console.log(""),n.forEach(i=>{let o=i.search(/\S/),s=i.length-[...i].reverse().join("").search(/\S/)-1;if(o===-1)return console.log(" "+i);let a=i.slice(0,o),c=i.slice(o,s+1).split("").map(l=>l===" "?" ":"\u2588").join(""),u=i.slice(s+1);console.log(` ${a}${r}${c}${t}${u}`)}),console.log(` ${e} CLI v${or}${t}`),console.log("")}function tt(t){if(!le())return{stop:()=>{},update:()=>{},log:()=>{}};let e=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],r=0,n=t,i=()=>process.stdout.write("\r\x1B[2K"),o=()=>{process.stdout.write(`\r ${m.cyan}${e[r++%e.length]}${m.reset} ${n}`)},s=setInterval(o,80);return{update:a=>{n=a},log:a=>{i(),console.log(` ${m.dim}\u2502${m.reset} ${a}`),o()},stop:a=>{clearInterval(s),i(),a&&console.log(` ${a}`)}}}function ne(t){le()?cy(t):console.log(JSON.stringify(t,null,2))}function we(t,e){le()?(console.log(` ${m.green}\u2713${m.reset} ${t}`),e&&cy(e,4)):console.log(JSON.stringify({success:!0,message:t,...e&&typeof e=="object"?e:{data:e}}))}function _(t,e){le()?(console.error(` ${m.red}\u2717${m.reset} ${t}`),e&&cy(e,4)):console.error(JSON.stringify({success:!1,error:t,details:e}))}function EH(t){le()&&console.log(` ${m.yellow}\u26A0${m.reset} ${t}`)}function Wt(t){le()&&console.log(` ${m.dim}${t}${m.reset}`)}function Wo(t){le()&&(console.log(`
1757
+ `,{mode:384})}function iy(t,e){let r=Vo.join(Yo(e),"drafts");if(Ir.existsSync(r)||Ir.mkdirSync(r,{recursive:!0}),t.output.mode==="stdout+file"){let n=Vo.resolve(t.output.directory);Ir.existsSync(n)||Ir.mkdirSync(n,{recursive:!0})}}var nv=he(zr());var Zw=he(require("readline"));var dH=require("child_process"),fH=require("util");var lH={name:"@superglue/cli",version:"1.1.140",bin:{sg:"./dist/cli.js"},files:[".claude-plugin/","dist/","skills/","LICENSE"],dependencies:{commander:"15.0.0-0","fast-json-patch":"3.1.1"},devDependencies:{"@superglue/shared":"file:../shared","@types/node":"25.5.0",tsup:"8.5.1",typescript:"5.8.3"},scripts:{build:"tsup && (cp -r skills dist/ 2>/dev/null || true)",dev:"tsup --watch","type-check":"tsc --noEmit",prepublishOnly:"npm run build"},publishConfig:{access:"public"}};var UDe=(0,fH.promisify)(dH.exec),or=lH.version;function AH(t){let e=t.match(/^(\d+)(?:-(.+))?$/);return e?{numeric:parseInt(e[1],10),prerelease:e[2]||null}:{numeric:0,prerelease:t}}function sy(t,e){let r=t.split("."),n=e.split("."),i=Math.max(r.length,n.length);for(let o=0;o<i;o++){let s=AH(r[o]||"0"),a=AH(n[o]||"0");if(s.numeric<a.numeric)return-1;if(s.numeric>a.numeric||s.prerelease===null&&a.prerelease!==null)return 1;if(s.prerelease!==null&&a.prerelease===null)return-1;if(s.prerelease!==null&&a.prerelease!==null){if(s.prerelease<a.prerelease)return-1;if(s.prerelease>a.prerelease)return 1}}return 0}async function ay(){try{let t=await fetch("https://registry.npmjs.org/@superglue/cli/latest",{signal:AbortSignal.timeout(5e3)});return t.ok&&(await t.json()).version||null}catch{return null}}var oy=null;function pH(){le()&&(oy=ay())}async function gH(){if(!(!le()||!oy)){try{let t=new Promise(r=>{setTimeout(()=>r(null),2e3).unref()}),e=await Promise.race([oy,t]);e&&sy(or,e)<0&&(console.error(""),console.error(`${m.cyan}${m.bold} Update available: ${or} \u2192 ${e}${m.reset}`),console.error(`${m.cyan} Run ${m.bold}sg update${m.reset}${m.cyan} to upgrade${m.reset}`),console.error(""))}catch{}oy=null}}async function hH(){let t=await ay();if(!t)return{success:!1,message:"Could not fetch latest version from npm"};if(sy(or,t)>=0)return{success:!0,message:`Already on latest version (${or})`};try{return await UDe("npm install -g @superglue/cli@latest"),{success:!0,message:`Updated from ${or} to ${t}`}}catch(e){return{success:!1,message:`Update failed: ${e.message}. Try manually: npm install -g @superglue/cli@latest`}}}var le=()=>process.argv.includes("--table")&&process.stdout.isTTY,bn=()=>process.argv.includes("--full"),m={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",italic:"\x1B[3m",underline:"\x1B[4m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",cyan:"\x1B[36m",white:"\x1B[37m",gray:"\x1B[90m",bgRed:"\x1B[41m",bgGreen:"\x1B[42m",bgYellow:"\x1B[43m",bgBlue:"\x1B[44m",bgMagenta:"\x1B[45m",bgCyan:"\x1B[46m"};function mH(t,e){let r=e||t;return`\x1B]8;;${t}\x07${m.underline}${m.cyan}${r}${m.reset}\x1B]8;;\x07`}function yH(){if(!le())return;let t=m.reset,e=m.dim,r="\x1B[47;30m",n=[" #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@- "," =@@@- @@@@ "," @@@ @@% "," -@@ @@@@= @@@ @@@ @@@@@#@ @@@@@@@ @@@@@@@ @@@@@@ @@@ @@@ @@@ @@@@@@* %@@ "," @@ @@@ *@ @@@ @@@ @@@ :@@ @@@ @@@ -@@ @@@ @% @@@ @@@ @@@ @@* @@# "," #@@ @@@# @@@ @@@ @@@ :@@ @@@ @@@ -@@ @@@ @@@ @@@ @@@ @@* @@ "," @@- @@@@= @@@ @@@ @@@@@@@ @@@@@@ @@@@@@@ @@@ @@% @@@ @@@ @@@ @@@@@. @@."," #@% .@@@@ @@@ @@@ @@@ @@@ @@@ -@@ @@@ @@% @@@ @@@ @@@ @@* @@ "," @@ @ @@@ @@@ @@@ @@@ @@@ @@@ -@@ @@@ @@% @@@ @@@ @@@ @@* *@@ "," -@@ @@@@= @@@@@@ @@@ @@@@@@@ @@@ -@@ @@@@@@ @@@@@@% @@@@@@. @@@@@@* #@@ "," :@@* @@@ "," %@@@ =@@@. "," :@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@% "];console.log(""),n.forEach(i=>{let o=i.search(/\S/),s=i.length-[...i].reverse().join("").search(/\S/)-1;if(o===-1)return console.log(" "+i);let a=i.slice(0,o),c=i.slice(o,s+1).split("").map(l=>l===" "?" ":"\u2588").join(""),u=i.slice(s+1);console.log(` ${a}${r}${c}${t}${u}`)}),console.log(` ${e} CLI v${or}${t}`),console.log("")}function tt(t){if(!le())return{stop:()=>{},update:()=>{},log:()=>{}};let e=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],r=0,n=t,i=()=>process.stdout.write("\r\x1B[2K"),o=()=>{process.stdout.write(`\r ${m.cyan}${e[r++%e.length]}${m.reset} ${n}`)},s=setInterval(o,80);return{update:a=>{n=a},log:a=>{i(),console.log(` ${m.dim}\u2502${m.reset} ${a}`),o()},stop:a=>{clearInterval(s),i(),a&&console.log(` ${a}`)}}}function ne(t){le()?cy(t):console.log(JSON.stringify(t,null,2))}function we(t,e){le()?(console.log(` ${m.green}\u2713${m.reset} ${t}`),e&&cy(e,4)):console.log(JSON.stringify({success:!0,message:t,...e&&typeof e=="object"?e:{data:e}}))}function _(t,e){le()?(console.error(` ${m.red}\u2717${m.reset} ${t}`),e&&cy(e,4)):console.error(JSON.stringify({success:!1,error:t,details:e}))}function EH(t){le()&&console.log(` ${m.yellow}\u26A0${m.reset} ${t}`)}function Wt(t){le()&&console.log(` ${m.dim}${t}${m.reset}`)}function Wo(t){le()&&(console.log(`
1758
1758
  ${m.bold}${m.cyan}${t}${m.reset}`),console.log(` ${m.dim}${"\u2500".repeat(t.length)}${m.reset}`))}function uo(t,e,r){if(!le()){console.log(JSON.stringify({success:!0,total:r?.total??t.length,items:t}));return}if(t.length===0){console.log(`
1759
1759
  ${m.dim}0 results${m.reset}
1760
1760
  `);return}let n=e||Object.keys(t[0]),i=bn()?1/0:60,o=n.map(l=>Math.min(i,Math.max(l.length,...t.map(A=>String(A[l]??"").replace(/[\n\r]+/g," ").trim().length))));console.log("");let s=n.map((l,A)=>`${m.bold}${m.cyan}${l.toUpperCase().padEnd(o[A])}${m.reset}`).join(" ");console.log(` ${s}`);let a=o.map(l=>`${m.dim}${"\u2500".repeat(l)}${m.reset}`).join(`${m.dim}\u2500\u2500${m.reset}`);console.log(` ${a}`);for(let l of t){let A=n.map((d,f)=>{let g=String(l[d]??"").replace(/[\n\r]+/g," ").trim();if(g.length>i){let b=`\u2026 (${g.length})`;g=g.slice(0,Math.max(0,i-b.length))+`${m.dim}${b}${m.reset}`}return d==="status"?`${{success:m.green,running:m.yellow,failed:m.red,aborted:m.red,error:m.red,pending:m.dim}[g.toLowerCase()]||""}${g.padEnd(o[f])}${m.reset}`:g.padEnd(o[f])}).join(" ");console.log(` ${A}`)}let c=r?.total??t.length,u=c===t.length?`${t.length} result${t.length===1?"":"s"}`:`${t.length} of ${c} result${c===1?"":"s"}`;console.log(`
@@ -360,11 +360,11 @@ Transform steps do NOT have `systemId`, `url`, `method`, `headers`, `body`, `que
360
360
 
361
361
  **Step behavior fields:**
362
362
 
363
- | Field | Type | Description |
364
- | ----------------- | ------- | ---------------------------------------------------- |
365
- | `dataSelector` | string | JS function controlling step input and loop mode |
366
- | `failureBehavior` | string | `fail` (default) or `continue` |
367
- | `modify` | boolean | Set `true` only when the step writes/updates/deletes |
363
+ | Field | Type | Description |
364
+ | ----------------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
365
+ | `dataSelector` | string | JS function controlling step input and loop mode |
366
+ | `failureBehavior` | string | `fail` (default) or `continue` |
367
+ | `modify` | boolean | Defaults to `false`. Set `true` when the step writes, updates, or deletes live data or has transform side effects |
368
368
 
369
369
  ### Expression Syntax (`<<>>`)
370
370
 
@@ -645,7 +645,7 @@ curl -X POST "https://api.superglue.cloud/v1/hooks/{toolId}?token=$SUPERGLUE_API
645
645
  - **Regex literals in transforms** — `/.../ ` literals and complex escapes corrupt during serialization. Use `new RegExp()`, `.split()`, or `new URL()` instead
646
646
  - **Complex bodies inline** — for bodies built from multiple steps, use a preceding transform step rather than stuffing multi-statement logic into `<<>>` expressions
647
647
  - **Double-encoded JSON** — when the body contains nested/stringified JSON (e.g. LLM APIs), have `<<>>` expressions return a string via `JSON.stringify(...)`, and use a single expression for the whole body rather than mixing `<<>>` with static JSON
648
- - **POST for read-only ops** — GraphQL queries via POST should have `modify: false`. Don't rely on HTTP method alone
648
+ - **Live-data writes** — Set `modify: true` for writes, updates, deletes, and transform side effects. Judge side effects, not HTTP method alone
649
649
  - **Saving without approval** — always present `sg tool run` results and ask before `sg tool save`
650
650
  - **Reserved key collisions** — payload inputs or step ids named after reserved/injected keys (see Naming Rules) are rejected at save time; pick a different name instead of retrying
651
651
 
@@ -61,7 +61,7 @@ Same as HTTP — credentials are placed in headers using `<<systemId_credentialK
61
61
 
62
62
  ### Queries vs Mutations
63
63
 
64
- - **Queries** (read-only): set `modify: false` on the step (this is the default)
64
+ - **Queries** (read-only): omit `modify`; it defaults to `false`.
65
65
  - **Mutations** (write): set `modify: true`
66
66
 
67
67
  Both use `method: "POST"` — do not rely on HTTP method to distinguish read vs write.
@@ -264,7 +264,7 @@ When an HTTP step downloads a file (PDF, CSV, binary response), set `outputFile:
264
264
  - Putting pagination variables in the config but not setting a `pagination` block, or vice versa
265
265
  - Using `<<currentItem.id>>` — must use arrow function syntax: `<<(sourceData) => sourceData.currentItem.id>>`
266
266
  - Mixing multiple `<<>>` expressions in one body string when the API expects nested JSON — use a transform step instead
267
- - Setting `method: "POST"` for GraphQL queries without `modify: false` — POST that only reads should not be marked as modifying
267
+ - Set `modify: true` for requests that write, update, or delete live data. Judge side effects, not HTTP method alone.
268
268
 
269
269
  ## Error Recovery
270
270
 
@@ -25,12 +25,12 @@ sg system call --system-id netsuite \
25
25
 
26
26
  ### Fields
27
27
 
28
- | Field | Required | Notes |
29
- | ---------- | ---------- | -------------------------------------------------------------------------------------------------------- |
30
- | `url` | yes | `suitecloud://<account>.app.netsuite.com`. No path, port, or credentials. |
31
- | `body` | yes | JSON string with `operation` and the operation's inputs |
32
- | `systemId` | yes | The NetSuite system. Its OAuth sign-in is used for the login. |
33
- | `modify` | tool steps | `false` for reads, `true` for `deploy`. `deploy` changes the live account. `sg system call` has no flag. |
28
+ | Field | Required | Notes |
29
+ | ---------- | ---------- | ----------------------------------------------------------------------------------------------------------- |
30
+ | `url` | yes | `suitecloud://<account>.app.netsuite.com`. No path, port, or credentials. |
31
+ | `body` | yes | JSON string with `operation` and the operation's inputs |
32
+ | `systemId` | yes | The NetSuite system. Its OAuth sign-in is used for the login. |
33
+ | `modify` | tool steps | Defaults to `false`. Set `true` for `deploy`, which changes the live account. `sg system call` has no flag. |
34
34
 
35
35
  `<account>` is the account ID in host form: lowercase, with `_` written as `-` (`1234567_SB1` becomes `1234567-sb1`). It is the same prefix as the host of the system's REST URL.
36
36
 
@@ -28,7 +28,7 @@ If the user is asking general questions (not building):
28
28
 
29
29
  ## Cloud Usage Tiers
30
30
 
31
- - Cloud tiers are **Trial**, **Pro**, **Team**, and **Enterprise**; billing-enabled apps expose upgrades through the in-app **Upgrade Plan** button, not a separate Billing page.
31
+ - Cloud tiers are **Trial**, **Pro**, **Team**, and **Enterprise**. Plan controls are described under Web App UI Layout.
32
32
  - **Trial** includes 1M input tokens and 100 runs lifetime; **Pro** is €59/$69 per month with 3M input tokens/user/month and 3,000 runs/user/month.
33
33
  - **Team** is €99/$119 per seat/month with 5M input tokens/user/month and 5,000 runs/user/month; Team includes organization management, activity tracking, and custom MCP servers.
34
34
  - **Enterprise** is custom-priced with unlimited usage limits by default, enterprise access controls, and self-hosting/on-prem options.
@@ -79,7 +79,6 @@ Brain contains context-source setup, playbooks, artifacts, and files. Capabiliti
79
79
  The persistent left sidebar contains these top-level items:
80
80
 
81
81
  - **Agents** — expands the project and session tree. **New session** starts a session within a project or without one. `/` opens an unscoped session; saved sessions open `/agents/{sessionId}`. Archived projects and their sessions are hidden. A briefing run appears here after the user opens it from the briefing email or **Last briefing**.
82
- - **Projects** (`/projects`, detail at `/projects/{projectId}`) — tasks, resources, and project sessions. The **New project** card creates directly; the top-right **Create project** button starts agent-assisted planning. Projects support sharing, archive, and deletion; resource permissions remain separate.
83
82
  - **Brain** — expandable group for context and focused work:
84
83
  - **Setup** (`/brain`) — context-source connections that use only the current user's personal credentials.
85
84
  - **Playbooks** (`/playbooks`, detail at `/playbooks/{playbookId}`) — reusable guidance for recurring work. Built-in and custom playbooks share one grid; built-ins are labeled and can be duplicated.
@@ -97,15 +96,20 @@ The persistent left sidebar contains these top-level items:
97
96
  - **Access Rules** (`/admin/access`) — role and access-rule configuration; visible to admins on paid tiers. Use the access-rules reference for RBAC behavior, base roles, and personal roles.
98
97
  - **Organization** (`/organization`) — visible on paid tiers as a standalone page without tabs. It shows members, invitations, role assignment, and member-management actions; management actions are admin-gated.
99
98
 
100
- Below the navigation, the sidebar shows the current organization menu. Opening it shows the signed-in user email and menu items for **API Keys** (`/api-keys`), **Settings** (`/settings`, admin-only), **Switch organization**, and **Sign Out**. When billing is enabled, the sidebar also shows **Upgrade Plan** for non-enterprise organizations; it opens the in-app upgrade flow. There is no separate in-app Billing page.
99
+ The right panel's **Projects** tab is on every page and replaces a Projects page; `/projects` opens it. It lists projects, pinned first. Its **+** starts agent-assisted project planning; projects are created only through the agent. Project detail pages (`/projects/{projectId}`) have **Tasks** and **Resources** tabs. Projects support sharing, archive, and deletion; resource permissions remain separate.
100
+
101
+ Below the navigation, the sidebar shows the current organization menu. Opening it shows the signed-in user and menu items for **API Keys** (`/api-keys`), **Switch organization**, and **Sign Out**. Admins see a separate **Settings** link (`/settings`) below it.
102
+
103
+ When cloud billing is enabled, Trial organizations see **Upgrade Plan** in the sidebar. Pro and Team organizations see **Manage Plan** in the organization menu, including a Stripe portal link for admins. Enterprise organizations see neither. There is no separate Billing page.
101
104
 
102
105
  **API Keys** (`/api-keys`) is a standalone page with a simple own-key editor for superglue API keys used by API, SDK, CLI headless/API-key auth, webhook, and non-OAuth MCP clients. Org users can create, copy, delete, and re-scope their own keys.
103
106
 
104
107
  **Settings** (`/settings`) is an admin-only standalone page with distinct sections:
105
108
 
106
- - **Organization** — organization name and organization logo settings.
109
+ - **Organization** — organization name, logo, and the brand guidelines agents follow when creating artifacts.
107
110
  - **Run Settings** — run preferences: draft/single-step run visibility, run result storage, member run visibility, and delete-all-runs.
108
111
  - **Notifications** — run-alert channels for Slack and email (on failure, success, completion, or daily/weekly summaries). Slack setup opens `/settings/notifications/slack`; email setup opens `/settings/notifications/email`.
112
+ - **Timeouts** — Enterprise only: organization-level execution, protocol, and connection timeouts.
109
113
 
110
114
  ## Internals
111
115
 
@@ -135,5 +139,8 @@ Steps are routed to execution strategies by protocol (first match wins):
135
139
  6. MongoDB → URL starts with `mongodb://` or `mongodb+srv://`
136
140
  7. FTP/SFTP → URL starts with `ftp://`, `ftps://`, or `sftp://`
137
141
  8. SMB → URL starts with `smb://`
142
+ 9. ODBC → URL starts with `odbc://`
143
+ 10. Gateway scripts → URL starts with `script://` (Secure Gateway tunnels only)
144
+ 11. NetSuite SuiteCloud → URL starts with `suitecloud://`
138
145
 
139
146
  All user-provided JS (data selectors, transforms, stop conditions) runs in an isolated Deno sandbox.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superglue/cli",
3
- "version": "1.1.138",
3
+ "version": "1.1.140",
4
4
  "bin": {
5
5
  "sg": "./dist/cli.js"
6
6
  },
@@ -360,11 +360,11 @@ Transform steps do NOT have `systemId`, `url`, `method`, `headers`, `body`, `que
360
360
 
361
361
  **Step behavior fields:**
362
362
 
363
- | Field | Type | Description |
364
- | ----------------- | ------- | ---------------------------------------------------- |
365
- | `dataSelector` | string | JS function controlling step input and loop mode |
366
- | `failureBehavior` | string | `fail` (default) or `continue` |
367
- | `modify` | boolean | Set `true` only when the step writes/updates/deletes |
363
+ | Field | Type | Description |
364
+ | ----------------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
365
+ | `dataSelector` | string | JS function controlling step input and loop mode |
366
+ | `failureBehavior` | string | `fail` (default) or `continue` |
367
+ | `modify` | boolean | Defaults to `false`. Set `true` when the step writes, updates, or deletes live data or has transform side effects |
368
368
 
369
369
  ### Expression Syntax (`<<>>`)
370
370
 
@@ -645,7 +645,7 @@ curl -X POST "https://api.superglue.cloud/v1/hooks/{toolId}?token=$SUPERGLUE_API
645
645
  - **Regex literals in transforms** — `/.../ ` literals and complex escapes corrupt during serialization. Use `new RegExp()`, `.split()`, or `new URL()` instead
646
646
  - **Complex bodies inline** — for bodies built from multiple steps, use a preceding transform step rather than stuffing multi-statement logic into `<<>>` expressions
647
647
  - **Double-encoded JSON** — when the body contains nested/stringified JSON (e.g. LLM APIs), have `<<>>` expressions return a string via `JSON.stringify(...)`, and use a single expression for the whole body rather than mixing `<<>>` with static JSON
648
- - **POST for read-only ops** — GraphQL queries via POST should have `modify: false`. Don't rely on HTTP method alone
648
+ - **Live-data writes** — Set `modify: true` for writes, updates, deletes, and transform side effects. Judge side effects, not HTTP method alone
649
649
  - **Saving without approval** — always present `sg tool run` results and ask before `sg tool save`
650
650
  - **Reserved key collisions** — payload inputs or step ids named after reserved/injected keys (see Naming Rules) are rejected at save time; pick a different name instead of retrying
651
651
 
@@ -61,7 +61,7 @@ Same as HTTP — credentials are placed in headers using `<<systemId_credentialK
61
61
 
62
62
  ### Queries vs Mutations
63
63
 
64
- - **Queries** (read-only): set `modify: false` on the step (this is the default)
64
+ - **Queries** (read-only): omit `modify`; it defaults to `false`.
65
65
  - **Mutations** (write): set `modify: true`
66
66
 
67
67
  Both use `method: "POST"` — do not rely on HTTP method to distinguish read vs write.
@@ -264,7 +264,7 @@ When an HTTP step downloads a file (PDF, CSV, binary response), set `outputFile:
264
264
  - Putting pagination variables in the config but not setting a `pagination` block, or vice versa
265
265
  - Using `<<currentItem.id>>` — must use arrow function syntax: `<<(sourceData) => sourceData.currentItem.id>>`
266
266
  - Mixing multiple `<<>>` expressions in one body string when the API expects nested JSON — use a transform step instead
267
- - Setting `method: "POST"` for GraphQL queries without `modify: false` — POST that only reads should not be marked as modifying
267
+ - Set `modify: true` for requests that write, update, or delete live data. Judge side effects, not HTTP method alone.
268
268
 
269
269
  ## Error Recovery
270
270
 
@@ -25,12 +25,12 @@ sg system call --system-id netsuite \
25
25
 
26
26
  ### Fields
27
27
 
28
- | Field | Required | Notes |
29
- | ---------- | ---------- | -------------------------------------------------------------------------------------------------------- |
30
- | `url` | yes | `suitecloud://<account>.app.netsuite.com`. No path, port, or credentials. |
31
- | `body` | yes | JSON string with `operation` and the operation's inputs |
32
- | `systemId` | yes | The NetSuite system. Its OAuth sign-in is used for the login. |
33
- | `modify` | tool steps | `false` for reads, `true` for `deploy`. `deploy` changes the live account. `sg system call` has no flag. |
28
+ | Field | Required | Notes |
29
+ | ---------- | ---------- | ----------------------------------------------------------------------------------------------------------- |
30
+ | `url` | yes | `suitecloud://<account>.app.netsuite.com`. No path, port, or credentials. |
31
+ | `body` | yes | JSON string with `operation` and the operation's inputs |
32
+ | `systemId` | yes | The NetSuite system. Its OAuth sign-in is used for the login. |
33
+ | `modify` | tool steps | Defaults to `false`. Set `true` for `deploy`, which changes the live account. `sg system call` has no flag. |
34
34
 
35
35
  `<account>` is the account ID in host form: lowercase, with `_` written as `-` (`1234567_SB1` becomes `1234567-sb1`). It is the same prefix as the host of the system's REST URL.
36
36
 
@@ -28,7 +28,7 @@ If the user is asking general questions (not building):
28
28
 
29
29
  ## Cloud Usage Tiers
30
30
 
31
- - Cloud tiers are **Trial**, **Pro**, **Team**, and **Enterprise**; billing-enabled apps expose upgrades through the in-app **Upgrade Plan** button, not a separate Billing page.
31
+ - Cloud tiers are **Trial**, **Pro**, **Team**, and **Enterprise**. Plan controls are described under Web App UI Layout.
32
32
  - **Trial** includes 1M input tokens and 100 runs lifetime; **Pro** is €59/$69 per month with 3M input tokens/user/month and 3,000 runs/user/month.
33
33
  - **Team** is €99/$119 per seat/month with 5M input tokens/user/month and 5,000 runs/user/month; Team includes organization management, activity tracking, and custom MCP servers.
34
34
  - **Enterprise** is custom-priced with unlimited usage limits by default, enterprise access controls, and self-hosting/on-prem options.
@@ -79,7 +79,6 @@ Brain contains context-source setup, playbooks, artifacts, and files. Capabiliti
79
79
  The persistent left sidebar contains these top-level items:
80
80
 
81
81
  - **Agents** — expands the project and session tree. **New session** starts a session within a project or without one. `/` opens an unscoped session; saved sessions open `/agents/{sessionId}`. Archived projects and their sessions are hidden. A briefing run appears here after the user opens it from the briefing email or **Last briefing**.
82
- - **Projects** (`/projects`, detail at `/projects/{projectId}`) — tasks, resources, and project sessions. The **New project** card creates directly; the top-right **Create project** button starts agent-assisted planning. Projects support sharing, archive, and deletion; resource permissions remain separate.
83
82
  - **Brain** — expandable group for context and focused work:
84
83
  - **Setup** (`/brain`) — context-source connections that use only the current user's personal credentials.
85
84
  - **Playbooks** (`/playbooks`, detail at `/playbooks/{playbookId}`) — reusable guidance for recurring work. Built-in and custom playbooks share one grid; built-ins are labeled and can be duplicated.
@@ -97,15 +96,20 @@ The persistent left sidebar contains these top-level items:
97
96
  - **Access Rules** (`/admin/access`) — role and access-rule configuration; visible to admins on paid tiers. Use the access-rules reference for RBAC behavior, base roles, and personal roles.
98
97
  - **Organization** (`/organization`) — visible on paid tiers as a standalone page without tabs. It shows members, invitations, role assignment, and member-management actions; management actions are admin-gated.
99
98
 
100
- Below the navigation, the sidebar shows the current organization menu. Opening it shows the signed-in user email and menu items for **API Keys** (`/api-keys`), **Settings** (`/settings`, admin-only), **Switch organization**, and **Sign Out**. When billing is enabled, the sidebar also shows **Upgrade Plan** for non-enterprise organizations; it opens the in-app upgrade flow. There is no separate in-app Billing page.
99
+ The right panel's **Projects** tab is on every page and replaces a Projects page; `/projects` opens it. It lists projects, pinned first. Its **+** starts agent-assisted project planning; projects are created only through the agent. Project detail pages (`/projects/{projectId}`) have **Tasks** and **Resources** tabs. Projects support sharing, archive, and deletion; resource permissions remain separate.
100
+
101
+ Below the navigation, the sidebar shows the current organization menu. Opening it shows the signed-in user and menu items for **API Keys** (`/api-keys`), **Switch organization**, and **Sign Out**. Admins see a separate **Settings** link (`/settings`) below it.
102
+
103
+ When cloud billing is enabled, Trial organizations see **Upgrade Plan** in the sidebar. Pro and Team organizations see **Manage Plan** in the organization menu, including a Stripe portal link for admins. Enterprise organizations see neither. There is no separate Billing page.
101
104
 
102
105
  **API Keys** (`/api-keys`) is a standalone page with a simple own-key editor for superglue API keys used by API, SDK, CLI headless/API-key auth, webhook, and non-OAuth MCP clients. Org users can create, copy, delete, and re-scope their own keys.
103
106
 
104
107
  **Settings** (`/settings`) is an admin-only standalone page with distinct sections:
105
108
 
106
- - **Organization** — organization name and organization logo settings.
109
+ - **Organization** — organization name, logo, and the brand guidelines agents follow when creating artifacts.
107
110
  - **Run Settings** — run preferences: draft/single-step run visibility, run result storage, member run visibility, and delete-all-runs.
108
111
  - **Notifications** — run-alert channels for Slack and email (on failure, success, completion, or daily/weekly summaries). Slack setup opens `/settings/notifications/slack`; email setup opens `/settings/notifications/email`.
112
+ - **Timeouts** — Enterprise only: organization-level execution, protocol, and connection timeouts.
109
113
 
110
114
  ## Internals
111
115
 
@@ -135,5 +139,8 @@ Steps are routed to execution strategies by protocol (first match wins):
135
139
  6. MongoDB → URL starts with `mongodb://` or `mongodb+srv://`
136
140
  7. FTP/SFTP → URL starts with `ftp://`, `ftps://`, or `sftp://`
137
141
  8. SMB → URL starts with `smb://`
142
+ 9. ODBC → URL starts with `odbc://`
143
+ 10. Gateway scripts → URL starts with `script://` (Secure Gateway tunnels only)
144
+ 11. NetSuite SuiteCloud → URL starts with `suitecloud://`
138
145
 
139
146
  All user-provided JS (data selectors, transforms, stop conditions) runs in an isolated Deno sandbox.