diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index a56fbe5..8f8d352 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "superglue", "description": "Build, test, and manage superglue tools via the sg CLI. Use when working with superglue tools, systems, APIs, SDKs, or the sg command.", - "version": "1.1.33", + "version": "1.1.34", "author": { "name": "superglue", "email": "hello@superglue.cloud" diff --git a/_shared/index.js b/_shared/index.js index fde8431..b7fc600 100644 --- a/_shared/index.js +++ b/_shared/index.js @@ -565,7 +565,7 @@ WRITING DATA: POST /source/{destinationSourceId}/user and POST /source/{destinat ACTIVITY TYPES: Call GET /activityTypes before posting activities \u2014 the activityType field must match an accepted value for the room. -DEPRECATED ENDPOINTS: GET /user/{email} and GET /members are deprecated; use V2 equivalents instead.`},teamcity:{name:"teamcity",apiUrl:"https://{host}/app/rest",regex:"^.*(teamcity|jetbrains[\\s._-]?teamcity|\\/app\\/rest).*$",icon:"teamcity",docsUrl:"https://www.jetbrains.com/help/teamcity/rest/teamcity-rest-api-documentation.html",preferredAuthType:"api_key",keywords:["builds","projects","agents","artifacts","vcs roots","build configurations","build chains","test reports","deployments"],systemSpecificInstructions:"TeamCity is self-hosted; the API base URL is https://{host}/app/rest where {host} is your TeamCity server hostname. Tokens are personal access tokens created per-user under My Settings & Tools \u2192 Access Tokens \u2014 not a global admin panel. Use as Authorization: Bearer . The OpenAPI spec is available at runtime on the server itself at /app/rest/swagger.json. Basic auth is available via /httpAuth/app/rest/... as a fallback. The API version segment (e.g. /app/rest/2018.1/...) is optional; omitting it uses the latest version."}};de.systemOptions=[{value:"manual",label:"Custom API",icon:"default"},...Object.entries(de.systems).map(([o,e])=>({value:o,label:o.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim(),icon:e.icon||"default"}))];function fl(o){if(o.templateName&&de.systems[o.templateName])return{key:o.templateName,template:de.systems[o.templateName]};if(o.id&&de.systems[o.id])return{key:o.id,template:de.systems[o.id]};if(o.id){let e=o.id.replace(/-\d+$/,"");if(e!==o.id&&de.systems[e])return{key:e,template:de.systems[e]}}if(o.name&&de.systems[o.name])return{key:o.name,template:de.systems[o.name]};if(o.url){let e=/^[a-z][a-z0-9+.-]*:\/\//i.test(o.url)?o.url:`https://${o.url}`,t=[];for(let[a,i]of Object.entries(de.systems))try{if(new RegExp(i.regex).test(e)){let s=i.regex.length+(i.regex.includes("(?!")?100:0);t.push({key:a,template:i,specificity:s})}}catch{console.error(`Invalid regex pattern for system: ${a}`)}if(t.length>0){let a=t.sort((i,s)=>s.specificity-i.specificity)[0];return{key:a.key,template:a.template}}}return null}function j_(o){return!o||o.length===0?[]:[...new Set(o)]}function C_(o){return de.systems[o]?.oauth||null}function Q_(o){let e=Xp(o),t=e.type==="oauth2"?e.config||{}:{},a=o.credentials||{},i=fl(o)?.template.oauth,s=a.tokenAuthMethod,r=t.tokenAuthMethod,n=a.tokenContentType,c=t.tokenContentType,m=i?.extraHeaders,l=i?.extraBodyParams,g=(0,hl.parseJsonRecord)(t.extraHeaders),d=(0,hl.parseJsonRecord)(t.extraBodyParams),u=(0,hl.parseJsonRecord)(a.extraHeaders),p=(0,hl.parseJsonRecord)(a.extraBodyParams);return u&&(m=u),p&&(l=p),g&&(m=g),d&&(l=d),{tokenAuthMethod:r==="body"||r==="basic_auth"?r:s==="body"||s==="basic_auth"?s:i?.tokenAuthMethod,tokenContentType:c==="form"||c==="json"?c:n==="form"||n==="json"?n:i?.tokenContentType,extraHeaders:m,extraBodyParams:l}}function B_(o){let e=Xp(o);if(e.type==="oauth2"&&e.tokenUrl)return e.tokenUrl;let t=fl(o)?.template.oauth;if(t?.tokenUrl)return t.tokenUrl;if(!o.url)throw new Error(`Cannot determine OAuth token URL for system ${o.id}: no url or token_url provided`);try{return`${new URL(o.url.startsWith("http")?o.url:`https://${o.url}`).origin}/oauth/token`}catch{return`${o.url}/oauth/token`}}});var wq=b(De=>{"use strict";Object.defineProperty(De,"__esModule",{value:!0});De.KNOWLEDGE_BASE_CHANGE_LABEL=De.SYSTEM_PLAYGROUND_DRAFT_ID=void 0;De.buildCreateSystemEnvironmentPrompts=D_;De.normalizeSystemKnowledgeBaseInput=kq;De.buildSystemPendingOutput=Aq;De.getSystemFieldDisplayLabel=U_;De.formatSystemChangePreview=kl;De.formatCredentialDisplayValue=M_;De.buildMergedSystemPlaygroundConfig=O_;De.summarizeSystemPlaygroundChanges=__;De.convertUploadToClientPayload=F_;var bl=vn(),Os=xa(),oh=eh(),S_=/\.(json|yaml|yml)$|openapi|swagger|\/v[23]\//i;De.SYSTEM_PLAYGROUND_DRAFT_ID="@playground-draft";De.KNOWLEDGE_BASE_CHANGE_LABEL="Knowledge base";function D_({systemId:o,systemName:e,targetEnv:t}){let a=t==="dev"?"development":"production",i=t==="dev"?"development/sandbox":"production";return{userPrompt:`Create a ${a} version of the "${e}" system.`,hiddenStarterMessage:`Create a ${a} version of the "${e}" system with the same ID (${o}) but environment='${t}'. The ${t} system should have the same structure but with ${i} credentials.`,hideUserMessage:!0}}var R_={name:"Display name",url:"System endpoint",instructions:"Usage instructions",specificinstructions:"Usage instructions",credentialownership:"Credential source",credentialmode:"Credential source"};function T_(o,e){return o==="openapi"||o==="scrape"?o:S_.test(e)?"openapi":"scrape"}function yl(o){return Array.isArray(o)?[...new Set(o.map(e=>String(e||"").trim()).filter(Boolean))]:[]}function kq(o){let e=o?.knowledgeBase&&typeof o.knowledgeBase=="object"&&!Array.isArray(o.knowledgeBase)?o.knowledgeBase:null,t=typeof e?.files=="string"&&e.files.trim().length>0?e.files:void 0,a=[];if(Array.isArray(e?.addUrls))for(let r of e.addUrls){if(!r||typeof r!="object")continue;let n=r.url;if(typeof n!="string")continue;let c=n.trim();c&&a.push({url:c,source:T_(r.source,c)})}let i=new Set,s=a.filter(r=>{let n=`${r.source}:${r.url.toLowerCase()}`;return i.has(n)?!1:(i.add(n),!0)});return{...t?{files:t}:{},urls:s,removeDocumentIds:yl(e?.removeDocumentIds)}}function Aq(o){let e={...o||{}},{templateId:t,endpoint:a,auth:i,askForUserInputs:s,...r}=e,n=(0,bl.mapAgentAuthInput)(i).authentication;if(t){let c=oh.systems[t];if(c){let m=(0,oh.mergeSystemTemplateAuthentication)({authentication:n||r.authentication,template:c});e={name:c.name,url:c.apiUrl,...r,templateName:t,...a?{url:a}:{},...m?{authentication:m}:{}}}}else e={...r,...a?{url:a}:{},...n?{authentication:n}:{}};return{status:"awaiting_user_input",pendingInputs:(0,bl.normalizeAskForUserInputs)(o?.askForUserInputs),systemConfig:e}}function N_(o){return o.replace(/^\/+/,"").replace(/\s+/g,"").toLowerCase()}function fq(o){return o.length>240?`${o.slice(0,240)}...`:o}function bq(o){return o?o.type==="api_key"?"API key":o.type==="basic_auth"?"Basic auth":o.type==="connection_string"?"Connection string":o.type==="oauth2"?"OAuth 2.0":"No auth":"None"}function yq(o){let e=o.authentication;if(e?.type!=="oauth2")return null;if(e.oauthClientMode)return e.oauthClientMode==="managed"?"superglue-managed":"Custom";let t=o.templateName?oh.systems[o.templateName]?.oauth?.client_id:void 0;return t&&e.clientId===t?"superglue-managed":"Custom"}function U_(o){let e=o.trim();if(!e)return"System";let t="Credential \xB7 ";if(e.startsWith(t))return e.slice(t.length);let a=N_(e);return a==="knowledgebase"?De.KNOWLEDGE_BASE_CHANGE_LABEL:R_[a]||e}function kl(o,e="(empty)"){if(o==null||o==="")return e;if(typeof o=="string"){let t=o.trim();return t?fq(t):e}return typeof o=="number"||typeof o=="boolean"?String(o):fq((0,Os.safeStringify)(o,0))}function M_(o,e){return e==null||e===""?"(empty)":(0,Os.isSensitiveCredentialKey)(o)?typeof e=="object"?"****":(0,Os.maskCredentialValue)(o,e)||"(empty)":kl(e)}function O_({draft:o,input:e,mode:t}){let a=t==="create"?Aq(e).systemConfig||{}:e||{},{draftId:i,documentationUrl:s,openApiUrl:r,files:n,knowledgeBase:c,removeDocumentIds:m,removeCredentialKeys:l,scrapeUrl:g,scrapeKeywords:d,endpoint:u,auth:p,credentials:f,requiredCredentialKeys:w,environment:k,...A}=a,v=o.system,T=p!==void 0?t==="edit"?(0,bl.mergeAgentAuthInput)(v.authentication,p):(0,bl.mapAgentAuthInput)(p).authentication:void 0,j=A.name??v.name,S=j?(0,Os.slugify)(j):"",C=A.id??(v.id||S),D=!!T||A.authentication!==void 0?T||A.authentication:v.authentication;return{id:C,name:j,url:u??A.url??v.url,templateName:A.templateName??v.templateName,icon:A.icon??v.icon,environment:k==="dev"||k==="prod"?k:v.environment,specificInstructions:A.specificInstructions??v.specificInstructions,requiredCredentialKeys:w!==void 0?yl(w):v.requiredCredentialKeys,authentication:D,tunnel:A.tunnel!==void 0?A.tunnel:v.tunnel}}function __({previous:o,next:e,input:t}){let a=[],i=(r,n,c)=>{(n||"")!==(c||"")&&a.push({label:r,value:`${kl(n)} -> ${kl(c)}`})};for(let[r,n,c]of[["Display name",o.name,e.name],["System endpoint",o.url,e.url],["Template",o.templateName,e.templateName],["Icon",o.icon,e.icon],["Usage instructions",o.specificInstructions,e.specificInstructions],["Required secrets",yl(o.requiredCredentialKeys).join(", "),yl(e.requiredCredentialKeys).join(", ")]])i(r,n,c);if((0,Os.safeStringify)(o.authentication||null,0)!==(0,Os.safeStringify)(e.authentication||null,0)){let r=yq(o),n=yq(e);r&&n&&r!==n&&a.push({label:"OAuth client",value:`${r} -> ${n}`});let c=bq(o.authentication),m=bq(e.authentication);a.push({label:"Authentication configuration",value:c===m?`Updated ${m} settings`:`${c} -> ${m}`})}let s=kq(t);s.files&&a.push({label:De.KNOWLEDGE_BASE_CHANGE_LABEL,value:"Documentation file uploads staged"});for(let r of s.urls)a.push({label:De.KNOWLEDGE_BASE_CHANGE_LABEL,value:r.source==="openapi"?`OpenAPI URL staged: ${r.url}`:`Documentation URL staged: ${r.url}`});for(let r of s.removeDocumentIds)a.push({label:De.KNOWLEDGE_BASE_CHANGE_LABEL,value:`Document removed: ${r}`});return a}async function F_(o){if(o.sourceKind==="resolved-payload"&&o.content!==void 0)return{fileName:o.fileName,content:o.content,contentType:o.contentType,contentLength:o.contentLength};if(o.file)return{fileName:o.fileName,content:o.file,contentType:o.contentType,contentLength:o.contentLength};throw new Error(`Missing upload content for ${o.fileName}`)}});var qq=b(Ye=>{"use strict";Object.defineProperty(Ye,"__esModule",{value:!0});Ye.PAGINATION_RUNTIME_KEYS=Ye.RESERVED_RUNTIME_KEYS=void 0;Ye.getToolDeclaredInputKeys=xq;Ye.toolHasActivePagination=th;Ye.collectToolKeyCollisions=H_;Ye.formatToolKeyCollisionError=Y_;Ye.getCollidingRuntimePayloadKeys=G_;Ye.formatPayloadKeyCollisionError=V_;var L_=ft(),vq=xa();Ye.RESERVED_RUNTIME_KEYS=["__files__","currentItem","sg_auth_email","sg_auth_jwt"];Ye.PAGINATION_RUNTIME_KEYS=["page","offset","cursor","limit","pageSize"];function P_(o){if(!o)return null;if(typeof o=="string")try{let e=JSON.parse(o);return e&&typeof e=="object"?e:null}catch{return null}return typeof o=="object"?o:null}function xq(o){let t=P_(o)?.properties;if(!t||typeof t!="object")return[];let a=Object.keys(t),i=t.payload;return i&&t.credentials&&a.every(r=>r==="payload"||r==="credentials")?i&&typeof i=="object"&&i.properties&&typeof i.properties=="object"?Object.keys(i.properties):[]:a}function th(o){return(o.steps||[]).some(e=>(0,L_.isRequestConfig)(e.config)&&e.config.pagination&&e.config.pagination.type!=="disabled")}function zq(o){return o==="__files__"?"the runtime file map":o==="currentItem"?"the loop iteration variable":o==="sg_auth_email"?"the authenticated user's email":o==="sg_auth_jwt"?"a signed JWT proving the authenticated user's identity":"a runtime-injected value"}function H_({tool:o}){let e=[],t=xq(o.inputSchema),a=(o.steps||[]).map(g=>g.id).filter(Boolean),i=th(o),s=new Set(Ye.RESERVED_RUNTIME_KEYS),r=new Set(Ye.PAGINATION_RUNTIME_KEYS),n=(0,vq.getToolSystemIds)(o).map(g=>`${g}_`),c=new Set;for(let g of a)c.has(g)&&e.push({key:g,source:"stepId",kind:"duplicate-step-id",message:`Step id "${g}" is used by more than one step. Each step result is stored under its step id, so duplicate ids overwrite each other. Rename one of the steps.`}),c.add(g);let m=(g,d)=>{let u=d==="input"?`Input "${g}"`:`Step id "${g}"`;s.has(g)&&e.push({key:g,source:d,kind:"reserved",message:`${u} collides with ${zq(g)}, which the runtime injects into sourceData. Choose a different name.`}),i&&r.has(g)&&e.push({key:g,source:d,kind:"pagination",message:`${u} collides with the pagination variable "${g}" and this tool has a paginated step, so the value would override the runtime's pagination counter. Rename it (e.g. "max_results" instead of "limit").`});let p=n.find(f=>g.startsWith(f));p&&e.push({key:g,source:d,kind:"credential",message:`${u} starts with "${p}", the credential namespace of a system this tool uses. Credentials always win over payload values, so this name is reserved even if no such credential exists yet. Choose a name without the system prefix.`})};for(let g of t)m(g,"input");for(let g of c)m(g,"stepId");let l=new Set(a);for(let g of t)l.has(g)&&e.push({key:g,source:"input",kind:"step-id",message:`Input "${g}" has the same name as a step id. The step result overwrites the input value in sourceData after that step runs. Rename the input or the step.`});return e}function Y_(o){let e=o.map(t=>`- ${t.message}`);return`Tool has ${o.length} key name collision${o.length===1?"":"s"} with the runtime namespace: +DEPRECATED ENDPOINTS: GET /user/{email} and GET /members are deprecated; use V2 equivalents instead.`},teamcity:{name:"teamcity",apiUrl:"https://{host}/app/rest",regex:"^.*(teamcity|jetbrains[\\s._-]?teamcity|\\/app\\/rest).*$",icon:"teamcity",docsUrl:"https://www.jetbrains.com/help/teamcity/rest/teamcity-rest-api-documentation.html",preferredAuthType:"api_key",keywords:["builds","projects","agents","artifacts","vcs roots","build configurations","build chains","test reports","deployments"],systemSpecificInstructions:"TeamCity is self-hosted; the API base URL is https://{host}/app/rest where {host} is your TeamCity server hostname. Tokens are personal access tokens created per-user under My Settings & Tools \u2192 Access Tokens \u2014 not a global admin panel. Use as Authorization: Bearer . The OpenAPI spec is available at runtime on the server itself at /app/rest/swagger.json. Basic auth is available via /httpAuth/app/rest/... as a fallback. The API version segment (e.g. /app/rest/2018.1/...) is optional; omitting it uses the latest version."},expensify:{name:"expensify",apiUrl:"https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations",regex:"^.*(expensify|integrations\\.expensify\\.com).*$",icon:"expensify",docsUrl:"https://integrations.expensify.com/Integration-Server/doc/",preferredAuthType:"api_key",keywords:["report","expense","policy","employee","category","tag","card","domain","receipt","transaction","approver","reimbursement"],systemSpecificInstructions:`Expensify uses a non-standard single-endpoint API: all requests are POSTs to https://integrations.expensify.com/Integration-Server/ExpensifyIntegrations with credentials (partnerUserID and partnerUserSecret) embedded in the JSON body under a "credentials" key, not in headers. Obtain partnerUserID and partnerUserSecret exclusively from https://www.expensify.com/tools/integrations/ \u2014 this page is not reachable from the main account settings. Report creation requires explicit enablement by emailing concierge@expensify.com. The card reconciliation export requires the credentials to belong to a domain admin account. To operate on another user's data via the "userEmail" parameter, that user must first grant third-party access to your partner account.`}};de.systemOptions=[{value:"manual",label:"Custom API",icon:"default"},...Object.entries(de.systems).map(([o,e])=>({value:o,label:o.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim(),icon:e.icon||"default"}))];function fl(o){if(o.templateName&&de.systems[o.templateName])return{key:o.templateName,template:de.systems[o.templateName]};if(o.id&&de.systems[o.id])return{key:o.id,template:de.systems[o.id]};if(o.id){let e=o.id.replace(/-\d+$/,"");if(e!==o.id&&de.systems[e])return{key:e,template:de.systems[e]}}if(o.name&&de.systems[o.name])return{key:o.name,template:de.systems[o.name]};if(o.url){let e=/^[a-z][a-z0-9+.-]*:\/\//i.test(o.url)?o.url:`https://${o.url}`,t=[];for(let[a,i]of Object.entries(de.systems))try{if(new RegExp(i.regex).test(e)){let s=i.regex.length+(i.regex.includes("(?!")?100:0);t.push({key:a,template:i,specificity:s})}}catch{console.error(`Invalid regex pattern for system: ${a}`)}if(t.length>0){let a=t.sort((i,s)=>s.specificity-i.specificity)[0];return{key:a.key,template:a.template}}}return null}function j_(o){return!o||o.length===0?[]:[...new Set(o)]}function C_(o){return de.systems[o]?.oauth||null}function Q_(o){let e=Xp(o),t=e.type==="oauth2"?e.config||{}:{},a=o.credentials||{},i=fl(o)?.template.oauth,s=a.tokenAuthMethod,r=t.tokenAuthMethod,n=a.tokenContentType,c=t.tokenContentType,m=i?.extraHeaders,l=i?.extraBodyParams,g=(0,hl.parseJsonRecord)(t.extraHeaders),d=(0,hl.parseJsonRecord)(t.extraBodyParams),u=(0,hl.parseJsonRecord)(a.extraHeaders),p=(0,hl.parseJsonRecord)(a.extraBodyParams);return u&&(m=u),p&&(l=p),g&&(m=g),d&&(l=d),{tokenAuthMethod:r==="body"||r==="basic_auth"?r:s==="body"||s==="basic_auth"?s:i?.tokenAuthMethod,tokenContentType:c==="form"||c==="json"?c:n==="form"||n==="json"?n:i?.tokenContentType,extraHeaders:m,extraBodyParams:l}}function B_(o){let e=Xp(o);if(e.type==="oauth2"&&e.tokenUrl)return e.tokenUrl;let t=fl(o)?.template.oauth;if(t?.tokenUrl)return t.tokenUrl;if(!o.url)throw new Error(`Cannot determine OAuth token URL for system ${o.id}: no url or token_url provided`);try{return`${new URL(o.url.startsWith("http")?o.url:`https://${o.url}`).origin}/oauth/token`}catch{return`${o.url}/oauth/token`}}});var wq=b(De=>{"use strict";Object.defineProperty(De,"__esModule",{value:!0});De.KNOWLEDGE_BASE_CHANGE_LABEL=De.SYSTEM_PLAYGROUND_DRAFT_ID=void 0;De.buildCreateSystemEnvironmentPrompts=D_;De.normalizeSystemKnowledgeBaseInput=kq;De.buildSystemPendingOutput=Aq;De.getSystemFieldDisplayLabel=U_;De.formatSystemChangePreview=kl;De.formatCredentialDisplayValue=M_;De.buildMergedSystemPlaygroundConfig=O_;De.summarizeSystemPlaygroundChanges=__;De.convertUploadToClientPayload=F_;var bl=vn(),Os=xa(),oh=eh(),S_=/\.(json|yaml|yml)$|openapi|swagger|\/v[23]\//i;De.SYSTEM_PLAYGROUND_DRAFT_ID="@playground-draft";De.KNOWLEDGE_BASE_CHANGE_LABEL="Knowledge base";function D_({systemId:o,systemName:e,targetEnv:t}){let a=t==="dev"?"development":"production",i=t==="dev"?"development/sandbox":"production";return{userPrompt:`Create a ${a} version of the "${e}" system.`,hiddenStarterMessage:`Create a ${a} version of the "${e}" system with the same ID (${o}) but environment='${t}'. The ${t} system should have the same structure but with ${i} credentials.`,hideUserMessage:!0}}var R_={name:"Display name",url:"System endpoint",instructions:"Usage instructions",specificinstructions:"Usage instructions",credentialownership:"Credential source",credentialmode:"Credential source"};function T_(o,e){return o==="openapi"||o==="scrape"?o:S_.test(e)?"openapi":"scrape"}function yl(o){return Array.isArray(o)?[...new Set(o.map(e=>String(e||"").trim()).filter(Boolean))]:[]}function kq(o){let e=o?.knowledgeBase&&typeof o.knowledgeBase=="object"&&!Array.isArray(o.knowledgeBase)?o.knowledgeBase:null,t=typeof e?.files=="string"&&e.files.trim().length>0?e.files:void 0,a=[];if(Array.isArray(e?.addUrls))for(let r of e.addUrls){if(!r||typeof r!="object")continue;let n=r.url;if(typeof n!="string")continue;let c=n.trim();c&&a.push({url:c,source:T_(r.source,c)})}let i=new Set,s=a.filter(r=>{let n=`${r.source}:${r.url.toLowerCase()}`;return i.has(n)?!1:(i.add(n),!0)});return{...t?{files:t}:{},urls:s,removeDocumentIds:yl(e?.removeDocumentIds)}}function Aq(o){let e={...o||{}},{templateId:t,endpoint:a,auth:i,askForUserInputs:s,...r}=e,n=(0,bl.mapAgentAuthInput)(i).authentication;if(t){let c=oh.systems[t];if(c){let m=(0,oh.mergeSystemTemplateAuthentication)({authentication:n||r.authentication,template:c});e={name:c.name,url:c.apiUrl,...r,templateName:t,...a?{url:a}:{},...m?{authentication:m}:{}}}}else e={...r,...a?{url:a}:{},...n?{authentication:n}:{}};return{status:"awaiting_user_input",pendingInputs:(0,bl.normalizeAskForUserInputs)(o?.askForUserInputs),systemConfig:e}}function N_(o){return o.replace(/^\/+/,"").replace(/\s+/g,"").toLowerCase()}function fq(o){return o.length>240?`${o.slice(0,240)}...`:o}function bq(o){return o?o.type==="api_key"?"API key":o.type==="basic_auth"?"Basic auth":o.type==="connection_string"?"Connection string":o.type==="oauth2"?"OAuth 2.0":"No auth":"None"}function yq(o){let e=o.authentication;if(e?.type!=="oauth2")return null;if(e.oauthClientMode)return e.oauthClientMode==="managed"?"superglue-managed":"Custom";let t=o.templateName?oh.systems[o.templateName]?.oauth?.client_id:void 0;return t&&e.clientId===t?"superglue-managed":"Custom"}function U_(o){let e=o.trim();if(!e)return"System";let t="Credential \xB7 ";if(e.startsWith(t))return e.slice(t.length);let a=N_(e);return a==="knowledgebase"?De.KNOWLEDGE_BASE_CHANGE_LABEL:R_[a]||e}function kl(o,e="(empty)"){if(o==null||o==="")return e;if(typeof o=="string"){let t=o.trim();return t?fq(t):e}return typeof o=="number"||typeof o=="boolean"?String(o):fq((0,Os.safeStringify)(o,0))}function M_(o,e){return e==null||e===""?"(empty)":(0,Os.isSensitiveCredentialKey)(o)?typeof e=="object"?"****":(0,Os.maskCredentialValue)(o,e)||"(empty)":kl(e)}function O_({draft:o,input:e,mode:t}){let a=t==="create"?Aq(e).systemConfig||{}:e||{},{draftId:i,documentationUrl:s,openApiUrl:r,files:n,knowledgeBase:c,removeDocumentIds:m,removeCredentialKeys:l,scrapeUrl:g,scrapeKeywords:d,endpoint:u,auth:p,credentials:f,requiredCredentialKeys:w,environment:k,...A}=a,v=o.system,T=p!==void 0?t==="edit"?(0,bl.mergeAgentAuthInput)(v.authentication,p):(0,bl.mapAgentAuthInput)(p).authentication:void 0,j=A.name??v.name,S=j?(0,Os.slugify)(j):"",C=A.id??(v.id||S),D=!!T||A.authentication!==void 0?T||A.authentication:v.authentication;return{id:C,name:j,url:u??A.url??v.url,templateName:A.templateName??v.templateName,icon:A.icon??v.icon,environment:k==="dev"||k==="prod"?k:v.environment,specificInstructions:A.specificInstructions??v.specificInstructions,requiredCredentialKeys:w!==void 0?yl(w):v.requiredCredentialKeys,authentication:D,tunnel:A.tunnel!==void 0?A.tunnel:v.tunnel}}function __({previous:o,next:e,input:t}){let a=[],i=(r,n,c)=>{(n||"")!==(c||"")&&a.push({label:r,value:`${kl(n)} -> ${kl(c)}`})};for(let[r,n,c]of[["Display name",o.name,e.name],["System endpoint",o.url,e.url],["Template",o.templateName,e.templateName],["Icon",o.icon,e.icon],["Usage instructions",o.specificInstructions,e.specificInstructions],["Required secrets",yl(o.requiredCredentialKeys).join(", "),yl(e.requiredCredentialKeys).join(", ")]])i(r,n,c);if((0,Os.safeStringify)(o.authentication||null,0)!==(0,Os.safeStringify)(e.authentication||null,0)){let r=yq(o),n=yq(e);r&&n&&r!==n&&a.push({label:"OAuth client",value:`${r} -> ${n}`});let c=bq(o.authentication),m=bq(e.authentication);a.push({label:"Authentication configuration",value:c===m?`Updated ${m} settings`:`${c} -> ${m}`})}let s=kq(t);s.files&&a.push({label:De.KNOWLEDGE_BASE_CHANGE_LABEL,value:"Documentation file uploads staged"});for(let r of s.urls)a.push({label:De.KNOWLEDGE_BASE_CHANGE_LABEL,value:r.source==="openapi"?`OpenAPI URL staged: ${r.url}`:`Documentation URL staged: ${r.url}`});for(let r of s.removeDocumentIds)a.push({label:De.KNOWLEDGE_BASE_CHANGE_LABEL,value:`Document removed: ${r}`});return a}async function F_(o){if(o.sourceKind==="resolved-payload"&&o.content!==void 0)return{fileName:o.fileName,content:o.content,contentType:o.contentType,contentLength:o.contentLength};if(o.file)return{fileName:o.fileName,content:o.file,contentType:o.contentType,contentLength:o.contentLength};throw new Error(`Missing upload content for ${o.fileName}`)}});var qq=b(Ye=>{"use strict";Object.defineProperty(Ye,"__esModule",{value:!0});Ye.PAGINATION_RUNTIME_KEYS=Ye.RESERVED_RUNTIME_KEYS=void 0;Ye.getToolDeclaredInputKeys=xq;Ye.toolHasActivePagination=th;Ye.collectToolKeyCollisions=H_;Ye.formatToolKeyCollisionError=Y_;Ye.getCollidingRuntimePayloadKeys=G_;Ye.formatPayloadKeyCollisionError=V_;var L_=ft(),vq=xa();Ye.RESERVED_RUNTIME_KEYS=["__files__","currentItem","sg_auth_email","sg_auth_jwt"];Ye.PAGINATION_RUNTIME_KEYS=["page","offset","cursor","limit","pageSize"];function P_(o){if(!o)return null;if(typeof o=="string")try{let e=JSON.parse(o);return e&&typeof e=="object"?e:null}catch{return null}return typeof o=="object"?o:null}function xq(o){let t=P_(o)?.properties;if(!t||typeof t!="object")return[];let a=Object.keys(t),i=t.payload;return i&&t.credentials&&a.every(r=>r==="payload"||r==="credentials")?i&&typeof i=="object"&&i.properties&&typeof i.properties=="object"?Object.keys(i.properties):[]:a}function th(o){return(o.steps||[]).some(e=>(0,L_.isRequestConfig)(e.config)&&e.config.pagination&&e.config.pagination.type!=="disabled")}function zq(o){return o==="__files__"?"the runtime file map":o==="currentItem"?"the loop iteration variable":o==="sg_auth_email"?"the authenticated user's email":o==="sg_auth_jwt"?"a signed JWT proving the authenticated user's identity":"a runtime-injected value"}function H_({tool:o}){let e=[],t=xq(o.inputSchema),a=(o.steps||[]).map(g=>g.id).filter(Boolean),i=th(o),s=new Set(Ye.RESERVED_RUNTIME_KEYS),r=new Set(Ye.PAGINATION_RUNTIME_KEYS),n=(0,vq.getToolSystemIds)(o).map(g=>`${g}_`),c=new Set;for(let g of a)c.has(g)&&e.push({key:g,source:"stepId",kind:"duplicate-step-id",message:`Step id "${g}" is used by more than one step. Each step result is stored under its step id, so duplicate ids overwrite each other. Rename one of the steps.`}),c.add(g);let m=(g,d)=>{let u=d==="input"?`Input "${g}"`:`Step id "${g}"`;s.has(g)&&e.push({key:g,source:d,kind:"reserved",message:`${u} collides with ${zq(g)}, which the runtime injects into sourceData. Choose a different name.`}),i&&r.has(g)&&e.push({key:g,source:d,kind:"pagination",message:`${u} collides with the pagination variable "${g}" and this tool has a paginated step, so the value would override the runtime's pagination counter. Rename it (e.g. "max_results" instead of "limit").`});let p=n.find(f=>g.startsWith(f));p&&e.push({key:g,source:d,kind:"credential",message:`${u} starts with "${p}", the credential namespace of a system this tool uses. Credentials always win over payload values, so this name is reserved even if no such credential exists yet. Choose a name without the system prefix.`})};for(let g of t)m(g,"input");for(let g of c)m(g,"stepId");let l=new Set(a);for(let g of t)l.has(g)&&e.push({key:g,source:"input",kind:"step-id",message:`Input "${g}" has the same name as a step id. The step result overwrites the input value in sourceData after that step runs. Rename the input or the step.`});return e}function Y_(o){let e=o.map(t=>`- ${t.message}`);return`Tool has ${o.length} key name collision${o.length===1?"":"s"} with the runtime namespace: ${e.join(` `)}`}function G_({payload:o,tool:e}){let t=[],a=new Set(Ye.RESERVED_RUNTIME_KEYS),i=new Set(Ye.PAGINATION_RUNTIME_KEYS),s=new Set((e.steps||[]).map(c=>c.id).filter(Boolean)),r=th(e),n=(0,vq.getToolSystemIds)(e).map(c=>`${c}_`);for(let c of Object.keys(o)){a.has(c)&&t.push({key:c,kind:"reserved",message:`Payload key "${c}" collides with ${zq(c)}, which the runtime injects into sourceData. Remove or rename it.`}),s.has(c)&&t.push({key:c,kind:"step-id",message:`Payload key "${c}" has the same name as a step id. The step result overwrites the payload value in sourceData after that step runs. Remove or rename it.`}),r&&i.has(c)&&t.push({key:c,kind:"pagination",message:`Payload key "${c}" collides with a pagination variable and this tool has a paginated step, so it would override the runtime's pagination counter. Remove or rename it.`});let m=n.find(l=>c.startsWith(l));m&&t.push({key:c,kind:"credential",message:`Payload key "${c}" starts with "${m}", the credential namespace of a system this tool uses. Credentials always win over payload values. Remove or rename it.`})}return t}function V_(o){let e=o.map(t=>`- ${t.message}`);return`Payload has ${o.length} key name collision${o.length===1?"":"s"} with the runtime namespace: ${e.join(` diff --git a/_shared/types.d.ts b/_shared/types.d.ts index 151ff50..ddc3767 100644 --- a/_shared/types.d.ts +++ b/_shared/types.d.ts @@ -733,6 +733,10 @@ export type AccessRulesContext = Record & { systemId?: string; userId?: string; }>; + availablePlaybooks?: Array<{ + id: string; + name?: string; + }>; isEditing: boolean; }; export interface FrontendDrafts { diff --git a/package.json b/package.json index d9c9c9f..25179d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@superglue/cli", - "version": "1.1.33", + "version": "1.1.34", "bin": { "sg": "./dist/cli.js" },