@superglue/cli 1.1.14 → 1.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1925,7 +1925,9 @@ var require_types = __commonJS({
1925
1925
  RemoveScope2["ENTRY"] = "ENTRY";
1926
1926
  })(RemoveScope || (exports2.RemoveScope = RemoveScope = {}));
1927
1927
  function isRequestConfig(config) {
1928
- return config?.type === "request" || !config?.type;
1928
+ if (!config || typeof config !== "object")
1929
+ return false;
1930
+ return config.type === "request" || !("type" in config) || config.type === void 0;
1929
1931
  }
1930
1932
  function isTransformConfig(config) {
1931
1933
  return config?.type === "transform";
@@ -2415,6 +2417,7 @@ Use parameterized queries with $1, $2, etc. placeholders:
2415
2417
  }
2416
2418
  }
2417
2419
  },
2420
+ outputTransform: `(sourceData) => { const quote = sourceData.fetchStock?.data?.["Global Quote"] || {}; return { symbol: quote["01. symbol"] || sourceData.symbol || "AAPL", price: parseFloat(quote["05. price"] || "0").toFixed(2), change: quote["09. change"] || "0", changePercent: quote["10. change percent"] || "0%", volume: parseInt(quote["06. volume"] || "0").toLocaleString(), tradingDay: quote["07. latest trading day"] || "N/A", emailSent: sourceData.sendEmail?.success || false }; }`,
2418
2421
  instruction: "Fetches the current stock quote from Alpha Vantage and sends an email with the stock information to your registered email address."
2419
2422
  }
2420
2423
  ]
@@ -2454,6 +2457,25 @@ var require_templates = __commonJS({
2454
2457
  preferredAuthType: "apikey",
2455
2458
  keywords: ["database", "cache", "redis", "key-value", "nosql", "api key"]
2456
2459
  },
2460
+ azure_sql: {
2461
+ name: "azure_sql",
2462
+ apiUrl: "sqlserver://<<host>>:1433;database=<<database>>",
2463
+ regex: "^.*(azure.*sql|sql.*azure|database\\.windows\\.net).*$",
2464
+ icon: "default",
2465
+ docsUrl: "https://learn.microsoft.com/en-us/azure/azure-sql/",
2466
+ preferredAuthType: "apikey",
2467
+ keywords: [
2468
+ "database",
2469
+ "sql",
2470
+ "azure",
2471
+ "query",
2472
+ "table",
2473
+ "schema",
2474
+ "connection",
2475
+ "mssql",
2476
+ "sqlserver"
2477
+ ]
2478
+ },
2457
2479
  stripe: {
2458
2480
  name: "stripe",
2459
2481
  apiUrl: "https://api.stripe.com",
@@ -2539,6 +2561,30 @@ var require_templates = __commonJS({
2539
2561
  "memberships"
2540
2562
  ]
2541
2563
  },
2564
+ hrworks: {
2565
+ name: "hrworks",
2566
+ apiUrl: "https://api.hrworks.de/v2",
2567
+ regex: "(^|.*\\b)(hr\\s?works|hrworks)(\\b.*|$)",
2568
+ icon: "default",
2569
+ docsUrl: "https://developers.hrworks.de/",
2570
+ preferredAuthType: "apikey",
2571
+ keywords: [
2572
+ "hr",
2573
+ "employee",
2574
+ "absence",
2575
+ "vacation",
2576
+ "payroll",
2577
+ "personnel",
2578
+ "time_tracking",
2579
+ "human_resources",
2580
+ "working_time",
2581
+ "attendance",
2582
+ "onboarding",
2583
+ "applicant_management",
2584
+ "travel_expenses",
2585
+ "sick_leave"
2586
+ ]
2587
+ },
2542
2588
  attio: {
2543
2589
  name: "attio",
2544
2590
  apiUrl: "https://api.attio.com/v2/",
@@ -2805,6 +2851,15 @@ var require_templates = __commonJS({
2805
2851
  "oauth"
2806
2852
  ]
2807
2853
  },
2854
+ granola: {
2855
+ name: "granola",
2856
+ apiUrl: "https://public-api.granola.ai",
2857
+ regex: "^.*granola.*$",
2858
+ icon: "default",
2859
+ docsUrl: "https://docs.granola.ai",
2860
+ preferredAuthType: "apikey",
2861
+ keywords: ["meeting", "notes", "transcript", "summary", "ai", "recording"]
2862
+ },
2808
2863
  googleDrive: {
2809
2864
  name: "googleDrive",
2810
2865
  apiUrl: "https://www.googleapis.com/drive/v3",
@@ -4306,6 +4361,58 @@ HEADERS: { "Authorization": "Bearer <<token>>", "Content-Type": "application/jso
4306
4361
  "api key"
4307
4362
  ]
4308
4363
  },
4364
+ creatio: {
4365
+ name: "creatio",
4366
+ apiUrl: "https://<<instance>>.creatio.com/0/odata",
4367
+ regex: "^(.*\\.)?creatio\\.com(/.*)?$",
4368
+ icon: "default",
4369
+ docsUrl: "https://academy.creatio.com/docs/developer/integrations_and_api/data_services/odata/overview",
4370
+ preferredAuthType: "oauth",
4371
+ oauth: {
4372
+ authUrl: "https://<<instance>>.creatio.com/0/connect/authorize",
4373
+ tokenUrl: "https://<<instance>>.creatio.com/0/connect/token",
4374
+ scopes: "offline_access",
4375
+ grant_type: "authorization_code"
4376
+ },
4377
+ systemSpecificInstructions: `Creatio uses OIDC-compliant OAuth endpoints. The standard /ServiceModel/AuthService.svc/Authorize and /rest/oauth/token endpoints are behind IIS session auth and will NOT work for OAuth flows \u2014 you MUST use the /0/connect/* OIDC endpoints instead.
4378
+
4379
+ To discover the correct endpoints for any Creatio instance, fetch: https://<instance>.creatio.com/0/.well-known/openid-configuration
4380
+
4381
+ This returns authorization_endpoint, token_endpoint, and other OIDC URLs.
4382
+
4383
+ IMPORTANT \u2014 Scopes:
4384
+ - "offline_access" gets you a refresh token but may not grant API access alone.
4385
+ - To get actual API access, the user needs the ApplicationAccess scope: "offline_access ApplicationAccess_<GUID>"
4386
+ - The GUID is found in Creatio: System Designer \u2192 Lookups \u2192 "OAuth resources" \u2192 Name column (strip dashes).
4387
+ - The OAuth app in Creatio must also have this resource added under its permitted resources.
4388
+
4389
+ OAuth App Setup in Creatio:
4390
+ 1. System Designer \u2192 "OAuth 2.0 integrated applications" \u2192 create app with grant type "On behalf of a user (authorization code)"
4391
+ 2. Set redirect URI to the superglue callback URL
4392
+ 3. Under the app's permitted resources, add the ApplicationAccess resource
4393
+ 4. Note the Client ID and Client Secret
4394
+
4395
+ API Base URLs:
4396
+ - OData 4: https://<instance>.creatio.com/0/odata/ (e.g., /0/odata/Contact)
4397
+ - OData 3: https://<instance>.creatio.com/0/ServiceModel/EntityDataService.svc/ (e.g., /EntityDataService.svc/ContactCollection)
4398
+ - Use Bearer token auth: Authorization: Bearer <access_token>`,
4399
+ keywords: [
4400
+ "contacts",
4401
+ "accounts",
4402
+ "leads",
4403
+ "opportunities",
4404
+ "activities",
4405
+ "cases",
4406
+ "orders",
4407
+ "products",
4408
+ "invoices",
4409
+ "campaigns",
4410
+ "crm",
4411
+ "bpm",
4412
+ "odata",
4413
+ "oauth"
4414
+ ]
4415
+ },
4309
4416
  sanity: {
4310
4417
  name: "sanity",
4311
4418
  apiUrl: "https://api.sanity.io",
@@ -5365,7 +5472,7 @@ CUSTOM APIs: Publishers expose custom API pages at /api/{publisher}/{group}/{ver
5365
5472
  },
5366
5473
  googleAds: {
5367
5474
  name: "googleAds",
5368
- apiUrl: "https://googleads.googleapis.com/v20",
5475
+ apiUrl: "https://googleads.googleapis.com/v23",
5369
5476
  regex: "^.*(googleads\\.googleapis|developers\\.google\\.com/google-ads|adwords\\.google).*$",
5370
5477
  icon: "googleads",
5371
5478
  docsUrl: "https://developers.google.com/google-ads/api/docs/concepts/overview",
@@ -5373,11 +5480,24 @@ CUSTOM APIs: Publishers expose custom API pages at /api/{publisher}/{group}/{ver
5373
5480
  oauth: {
5374
5481
  authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
5375
5482
  tokenUrl: "https://oauth2.googleapis.com/token",
5376
- scopes: "https://www.googleapis.com/auth/adwords https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile openid"
5483
+ scopes: "https://www.googleapis.com/auth/adwords"
5377
5484
  },
5485
+ systemSpecificInstructions: `Google Ads API requires BOTH OAuth AND a developer token on every request.
5486
+
5487
+ REQUIRED HEADERS:
5488
+ - Authorization: Bearer <access_token>
5489
+ - developer-token: <22-char token from https://ads.google.com/aw/apicenter>
5490
+ - login-customer-id: <manager-account-id without hyphens> (only when calling through a manager account)
5491
+
5492
+ SETUP: User needs a Google Ads Manager account, a Google Cloud project with OAuth credentials, and a developer token (applied for via the API Center). New tokens start as test-only; production access requires a follow-up application.
5493
+
5494
+ QUERYING (GAQL): Use Google Ads Query Language via:
5495
+ - POST /v23/customers/{customerId}/googleAds:searchStream (streaming, recommended)
5496
+ - POST /v23/customers/{customerId}/googleAds:search (paginated)
5497
+ Example: SELECT campaign.name, metrics.impressions FROM campaign WHERE segments.date DURING LAST_30_DAYS`,
5378
5498
  keywords: [
5379
5499
  "campaigns",
5380
- "ad groups",
5500
+ "ad_groups",
5381
5501
  "ads",
5382
5502
  "keywords",
5383
5503
  "GAQL",
@@ -5390,6 +5510,9 @@ CUSTOM APIs: Publishers expose custom API pages at /api/{publisher}/{group}/{ver
5390
5510
  "accounts",
5391
5511
  "billing",
5392
5512
  "targeting",
5513
+ "search_terms",
5514
+ "metrics",
5515
+ "segments",
5393
5516
  "oauth"
5394
5517
  ]
5395
5518
  },
@@ -5446,6 +5569,33 @@ CUSTOM APIs: Publishers expose custom API pages at /api/{publisher}/{group}/{ver
5446
5569
  "api key"
5447
5570
  ]
5448
5571
  },
5572
+ circleback: {
5573
+ name: "circleback",
5574
+ apiUrl: "https://app.circleback.ai",
5575
+ regex: "^.*circleback.*$",
5576
+ icon: "default",
5577
+ docsUrl: "https://support.circleback.ai/en/articles/13249081-circleback-mcp",
5578
+ preferredAuthType: "oauth",
5579
+ systemSpecificInstructions: `Circleback has NO traditional REST API. Data access is exclusively via their MCP server.
5580
+
5581
+ MCP ENDPOINT: https://app.circleback.ai/api/mcp
5582
+ PROTOCOL: JSON-RPC 2.0 over Streamable HTTP transport
5583
+ AUTH: OAuth 2.0 with dynamic client registration (no app registration needed).
5584
+
5585
+ AVAILABLE DATA: meetings, transcripts, action items, calendar events, emails, people, companies.`,
5586
+ keywords: [
5587
+ "meetings",
5588
+ "transcripts",
5589
+ "notes",
5590
+ "action_items",
5591
+ "calendar_events",
5592
+ "attendees",
5593
+ "summaries",
5594
+ "people",
5595
+ "companies",
5596
+ "emails"
5597
+ ]
5598
+ },
5449
5599
  firecrawl: {
5450
5600
  name: "firecrawl",
5451
5601
  apiUrl: "https://api.firecrawl.dev/v1",
@@ -5710,6 +5860,8 @@ var require_type_utils = __commonJS({
5710
5860
  exports2.PAGINATION_TYPE_MAP = void 0;
5711
5861
  exports2.mapPaginationType = mapPaginationType;
5712
5862
  exports2.mapFailureBehavior = mapFailureBehavior;
5863
+ exports2.validateToolStructure = validateToolStructure;
5864
+ var types_js_1 = require_types();
5713
5865
  exports2.PAGINATION_TYPE_MAP = {
5714
5866
  OFFSET_BASED: "offsetBased",
5715
5867
  PAGE_BASED: "pageBased",
@@ -5729,6 +5881,50 @@ var require_type_utils = __commonJS({
5729
5881
  return void 0;
5730
5882
  return internal.toLowerCase();
5731
5883
  }
5884
+ function validateToolStructure(tool) {
5885
+ if (!tool || typeof tool !== "object") {
5886
+ return { valid: false, error: "Tool must be an object" };
5887
+ }
5888
+ const candidate = tool;
5889
+ if (!candidate.id || typeof candidate.id !== "string") {
5890
+ return { valid: false, error: "Tool must have a valid 'id' string" };
5891
+ }
5892
+ if (!Array.isArray(candidate.steps)) {
5893
+ return { valid: false, error: "Tool must have a 'steps' array" };
5894
+ }
5895
+ if (candidate.steps.length === 0 && !candidate.outputTransform) {
5896
+ return { valid: false, error: "Tool must have at least one step or an outputTransform" };
5897
+ }
5898
+ for (let i = 0; i < candidate.steps.length; i++) {
5899
+ const step = candidate.steps[i];
5900
+ const stepLabel = step?.id ? `Step ${i + 1} (${step.id})` : `Step ${i + 1}`;
5901
+ if (!step?.id) {
5902
+ return { valid: false, error: `Step ${i + 1}: missing 'id'` };
5903
+ }
5904
+ if (!step.config) {
5905
+ return { valid: false, error: `${stepLabel}: missing 'config'` };
5906
+ }
5907
+ if ((0, types_js_1.isTransformConfig)(step.config)) {
5908
+ if (!step.config.transformCode) {
5909
+ return {
5910
+ valid: false,
5911
+ error: `${stepLabel}: transform step missing 'transformCode'`
5912
+ };
5913
+ }
5914
+ continue;
5915
+ }
5916
+ if (!(0, types_js_1.isRequestConfig)(step.config)) {
5917
+ return {
5918
+ valid: false,
5919
+ error: `${stepLabel}: unknown step config type`
5920
+ };
5921
+ }
5922
+ if (typeof step.config.url !== "string" || step.config.url.trim().length === 0) {
5923
+ return { valid: false, error: `${stepLabel}: request step missing 'url'` };
5924
+ }
5925
+ }
5926
+ return { valid: true };
5927
+ }
5732
5928
  }
5733
5929
  });
5734
5930
 
@@ -21697,12 +21893,18 @@ var require_superglue_client = __commonJS({
21697
21893
  const response = await this.restRequest("GET", `/v1/tools?limit=${limit}&page=${page}${archiveParam}`);
21698
21894
  return { items: response.data, total: response.total };
21699
21895
  }
21896
+ async createWorkflow(id, input) {
21897
+ return this.restRequest("POST", "/v1/tools", { ...input, id });
21898
+ }
21899
+ async updateWorkflow(id, input) {
21900
+ return this.restRequest("PUT", `/v1/tools/${encodeURIComponent(id)}`, input);
21901
+ }
21700
21902
  async upsertWorkflow(id, input) {
21701
21903
  const existing = await this.getWorkflow(id);
21702
21904
  if (existing) {
21703
- return this.restRequest("PUT", `/v1/tools/${encodeURIComponent(id)}`, input);
21905
+ return this.updateWorkflow(id, input);
21704
21906
  } else {
21705
- return this.restRequest("POST", "/v1/tools", { id, ...input });
21907
+ return this.createWorkflow(id, input);
21706
21908
  }
21707
21909
  }
21708
21910
  async deleteWorkflow(id) {
package/dist/dist/cli.js CHANGED
@@ -1925,7 +1925,9 @@ var require_types = __commonJS({
1925
1925
  RemoveScope2["ENTRY"] = "ENTRY";
1926
1926
  })(RemoveScope || (exports2.RemoveScope = RemoveScope = {}));
1927
1927
  function isRequestConfig(config) {
1928
- return config?.type === "request" || !config?.type;
1928
+ if (!config || typeof config !== "object")
1929
+ return false;
1930
+ return config.type === "request" || !("type" in config) || config.type === void 0;
1929
1931
  }
1930
1932
  function isTransformConfig(config) {
1931
1933
  return config?.type === "transform";
@@ -2415,6 +2417,7 @@ Use parameterized queries with $1, $2, etc. placeholders:
2415
2417
  }
2416
2418
  }
2417
2419
  },
2420
+ outputTransform: `(sourceData) => { const quote = sourceData.fetchStock?.data?.["Global Quote"] || {}; return { symbol: quote["01. symbol"] || sourceData.symbol || "AAPL", price: parseFloat(quote["05. price"] || "0").toFixed(2), change: quote["09. change"] || "0", changePercent: quote["10. change percent"] || "0%", volume: parseInt(quote["06. volume"] || "0").toLocaleString(), tradingDay: quote["07. latest trading day"] || "N/A", emailSent: sourceData.sendEmail?.success || false }; }`,
2418
2421
  instruction: "Fetches the current stock quote from Alpha Vantage and sends an email with the stock information to your registered email address."
2419
2422
  }
2420
2423
  ]
@@ -2454,6 +2457,25 @@ var require_templates = __commonJS({
2454
2457
  preferredAuthType: "apikey",
2455
2458
  keywords: ["database", "cache", "redis", "key-value", "nosql", "api key"]
2456
2459
  },
2460
+ azure_sql: {
2461
+ name: "azure_sql",
2462
+ apiUrl: "sqlserver://<<host>>:1433;database=<<database>>",
2463
+ regex: "^.*(azure.*sql|sql.*azure|database\\.windows\\.net).*$",
2464
+ icon: "default",
2465
+ docsUrl: "https://learn.microsoft.com/en-us/azure/azure-sql/",
2466
+ preferredAuthType: "apikey",
2467
+ keywords: [
2468
+ "database",
2469
+ "sql",
2470
+ "azure",
2471
+ "query",
2472
+ "table",
2473
+ "schema",
2474
+ "connection",
2475
+ "mssql",
2476
+ "sqlserver"
2477
+ ]
2478
+ },
2457
2479
  stripe: {
2458
2480
  name: "stripe",
2459
2481
  apiUrl: "https://api.stripe.com",
@@ -2539,6 +2561,30 @@ var require_templates = __commonJS({
2539
2561
  "memberships"
2540
2562
  ]
2541
2563
  },
2564
+ hrworks: {
2565
+ name: "hrworks",
2566
+ apiUrl: "https://api.hrworks.de/v2",
2567
+ regex: "(^|.*\\b)(hr\\s?works|hrworks)(\\b.*|$)",
2568
+ icon: "default",
2569
+ docsUrl: "https://developers.hrworks.de/",
2570
+ preferredAuthType: "apikey",
2571
+ keywords: [
2572
+ "hr",
2573
+ "employee",
2574
+ "absence",
2575
+ "vacation",
2576
+ "payroll",
2577
+ "personnel",
2578
+ "time_tracking",
2579
+ "human_resources",
2580
+ "working_time",
2581
+ "attendance",
2582
+ "onboarding",
2583
+ "applicant_management",
2584
+ "travel_expenses",
2585
+ "sick_leave"
2586
+ ]
2587
+ },
2542
2588
  attio: {
2543
2589
  name: "attio",
2544
2590
  apiUrl: "https://api.attio.com/v2/",
@@ -2805,6 +2851,15 @@ var require_templates = __commonJS({
2805
2851
  "oauth"
2806
2852
  ]
2807
2853
  },
2854
+ granola: {
2855
+ name: "granola",
2856
+ apiUrl: "https://public-api.granola.ai",
2857
+ regex: "^.*granola.*$",
2858
+ icon: "default",
2859
+ docsUrl: "https://docs.granola.ai",
2860
+ preferredAuthType: "apikey",
2861
+ keywords: ["meeting", "notes", "transcript", "summary", "ai", "recording"]
2862
+ },
2808
2863
  googleDrive: {
2809
2864
  name: "googleDrive",
2810
2865
  apiUrl: "https://www.googleapis.com/drive/v3",
@@ -4306,6 +4361,58 @@ HEADERS: { "Authorization": "Bearer <<token>>", "Content-Type": "application/jso
4306
4361
  "api key"
4307
4362
  ]
4308
4363
  },
4364
+ creatio: {
4365
+ name: "creatio",
4366
+ apiUrl: "https://<<instance>>.creatio.com/0/odata",
4367
+ regex: "^(.*\\.)?creatio\\.com(/.*)?$",
4368
+ icon: "default",
4369
+ docsUrl: "https://academy.creatio.com/docs/developer/integrations_and_api/data_services/odata/overview",
4370
+ preferredAuthType: "oauth",
4371
+ oauth: {
4372
+ authUrl: "https://<<instance>>.creatio.com/0/connect/authorize",
4373
+ tokenUrl: "https://<<instance>>.creatio.com/0/connect/token",
4374
+ scopes: "offline_access",
4375
+ grant_type: "authorization_code"
4376
+ },
4377
+ systemSpecificInstructions: `Creatio uses OIDC-compliant OAuth endpoints. The standard /ServiceModel/AuthService.svc/Authorize and /rest/oauth/token endpoints are behind IIS session auth and will NOT work for OAuth flows \u2014 you MUST use the /0/connect/* OIDC endpoints instead.
4378
+
4379
+ To discover the correct endpoints for any Creatio instance, fetch: https://<instance>.creatio.com/0/.well-known/openid-configuration
4380
+
4381
+ This returns authorization_endpoint, token_endpoint, and other OIDC URLs.
4382
+
4383
+ IMPORTANT \u2014 Scopes:
4384
+ - "offline_access" gets you a refresh token but may not grant API access alone.
4385
+ - To get actual API access, the user needs the ApplicationAccess scope: "offline_access ApplicationAccess_<GUID>"
4386
+ - The GUID is found in Creatio: System Designer \u2192 Lookups \u2192 "OAuth resources" \u2192 Name column (strip dashes).
4387
+ - The OAuth app in Creatio must also have this resource added under its permitted resources.
4388
+
4389
+ OAuth App Setup in Creatio:
4390
+ 1. System Designer \u2192 "OAuth 2.0 integrated applications" \u2192 create app with grant type "On behalf of a user (authorization code)"
4391
+ 2. Set redirect URI to the superglue callback URL
4392
+ 3. Under the app's permitted resources, add the ApplicationAccess resource
4393
+ 4. Note the Client ID and Client Secret
4394
+
4395
+ API Base URLs:
4396
+ - OData 4: https://<instance>.creatio.com/0/odata/ (e.g., /0/odata/Contact)
4397
+ - OData 3: https://<instance>.creatio.com/0/ServiceModel/EntityDataService.svc/ (e.g., /EntityDataService.svc/ContactCollection)
4398
+ - Use Bearer token auth: Authorization: Bearer <access_token>`,
4399
+ keywords: [
4400
+ "contacts",
4401
+ "accounts",
4402
+ "leads",
4403
+ "opportunities",
4404
+ "activities",
4405
+ "cases",
4406
+ "orders",
4407
+ "products",
4408
+ "invoices",
4409
+ "campaigns",
4410
+ "crm",
4411
+ "bpm",
4412
+ "odata",
4413
+ "oauth"
4414
+ ]
4415
+ },
4309
4416
  sanity: {
4310
4417
  name: "sanity",
4311
4418
  apiUrl: "https://api.sanity.io",
@@ -5365,7 +5472,7 @@ CUSTOM APIs: Publishers expose custom API pages at /api/{publisher}/{group}/{ver
5365
5472
  },
5366
5473
  googleAds: {
5367
5474
  name: "googleAds",
5368
- apiUrl: "https://googleads.googleapis.com/v20",
5475
+ apiUrl: "https://googleads.googleapis.com/v23",
5369
5476
  regex: "^.*(googleads\\.googleapis|developers\\.google\\.com/google-ads|adwords\\.google).*$",
5370
5477
  icon: "googleads",
5371
5478
  docsUrl: "https://developers.google.com/google-ads/api/docs/concepts/overview",
@@ -5373,11 +5480,24 @@ CUSTOM APIs: Publishers expose custom API pages at /api/{publisher}/{group}/{ver
5373
5480
  oauth: {
5374
5481
  authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
5375
5482
  tokenUrl: "https://oauth2.googleapis.com/token",
5376
- scopes: "https://www.googleapis.com/auth/adwords https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile openid"
5483
+ scopes: "https://www.googleapis.com/auth/adwords"
5377
5484
  },
5485
+ systemSpecificInstructions: `Google Ads API requires BOTH OAuth AND a developer token on every request.
5486
+
5487
+ REQUIRED HEADERS:
5488
+ - Authorization: Bearer <access_token>
5489
+ - developer-token: <22-char token from https://ads.google.com/aw/apicenter>
5490
+ - login-customer-id: <manager-account-id without hyphens> (only when calling through a manager account)
5491
+
5492
+ SETUP: User needs a Google Ads Manager account, a Google Cloud project with OAuth credentials, and a developer token (applied for via the API Center). New tokens start as test-only; production access requires a follow-up application.
5493
+
5494
+ QUERYING (GAQL): Use Google Ads Query Language via:
5495
+ - POST /v23/customers/{customerId}/googleAds:searchStream (streaming, recommended)
5496
+ - POST /v23/customers/{customerId}/googleAds:search (paginated)
5497
+ Example: SELECT campaign.name, metrics.impressions FROM campaign WHERE segments.date DURING LAST_30_DAYS`,
5378
5498
  keywords: [
5379
5499
  "campaigns",
5380
- "ad groups",
5500
+ "ad_groups",
5381
5501
  "ads",
5382
5502
  "keywords",
5383
5503
  "GAQL",
@@ -5390,6 +5510,9 @@ CUSTOM APIs: Publishers expose custom API pages at /api/{publisher}/{group}/{ver
5390
5510
  "accounts",
5391
5511
  "billing",
5392
5512
  "targeting",
5513
+ "search_terms",
5514
+ "metrics",
5515
+ "segments",
5393
5516
  "oauth"
5394
5517
  ]
5395
5518
  },
@@ -5446,6 +5569,33 @@ CUSTOM APIs: Publishers expose custom API pages at /api/{publisher}/{group}/{ver
5446
5569
  "api key"
5447
5570
  ]
5448
5571
  },
5572
+ circleback: {
5573
+ name: "circleback",
5574
+ apiUrl: "https://app.circleback.ai",
5575
+ regex: "^.*circleback.*$",
5576
+ icon: "default",
5577
+ docsUrl: "https://support.circleback.ai/en/articles/13249081-circleback-mcp",
5578
+ preferredAuthType: "oauth",
5579
+ systemSpecificInstructions: `Circleback has NO traditional REST API. Data access is exclusively via their MCP server.
5580
+
5581
+ MCP ENDPOINT: https://app.circleback.ai/api/mcp
5582
+ PROTOCOL: JSON-RPC 2.0 over Streamable HTTP transport
5583
+ AUTH: OAuth 2.0 with dynamic client registration (no app registration needed).
5584
+
5585
+ AVAILABLE DATA: meetings, transcripts, action items, calendar events, emails, people, companies.`,
5586
+ keywords: [
5587
+ "meetings",
5588
+ "transcripts",
5589
+ "notes",
5590
+ "action_items",
5591
+ "calendar_events",
5592
+ "attendees",
5593
+ "summaries",
5594
+ "people",
5595
+ "companies",
5596
+ "emails"
5597
+ ]
5598
+ },
5449
5599
  firecrawl: {
5450
5600
  name: "firecrawl",
5451
5601
  apiUrl: "https://api.firecrawl.dev/v1",
@@ -5710,6 +5860,8 @@ var require_type_utils = __commonJS({
5710
5860
  exports2.PAGINATION_TYPE_MAP = void 0;
5711
5861
  exports2.mapPaginationType = mapPaginationType;
5712
5862
  exports2.mapFailureBehavior = mapFailureBehavior;
5863
+ exports2.validateToolStructure = validateToolStructure;
5864
+ var types_js_1 = require_types();
5713
5865
  exports2.PAGINATION_TYPE_MAP = {
5714
5866
  OFFSET_BASED: "offsetBased",
5715
5867
  PAGE_BASED: "pageBased",
@@ -5729,6 +5881,50 @@ var require_type_utils = __commonJS({
5729
5881
  return void 0;
5730
5882
  return internal.toLowerCase();
5731
5883
  }
5884
+ function validateToolStructure(tool) {
5885
+ if (!tool || typeof tool !== "object") {
5886
+ return { valid: false, error: "Tool must be an object" };
5887
+ }
5888
+ const candidate = tool;
5889
+ if (!candidate.id || typeof candidate.id !== "string") {
5890
+ return { valid: false, error: "Tool must have a valid 'id' string" };
5891
+ }
5892
+ if (!Array.isArray(candidate.steps)) {
5893
+ return { valid: false, error: "Tool must have a 'steps' array" };
5894
+ }
5895
+ if (candidate.steps.length === 0 && !candidate.outputTransform) {
5896
+ return { valid: false, error: "Tool must have at least one step or an outputTransform" };
5897
+ }
5898
+ for (let i = 0; i < candidate.steps.length; i++) {
5899
+ const step = candidate.steps[i];
5900
+ const stepLabel = step?.id ? `Step ${i + 1} (${step.id})` : `Step ${i + 1}`;
5901
+ if (!step?.id) {
5902
+ return { valid: false, error: `Step ${i + 1}: missing 'id'` };
5903
+ }
5904
+ if (!step.config) {
5905
+ return { valid: false, error: `${stepLabel}: missing 'config'` };
5906
+ }
5907
+ if ((0, types_js_1.isTransformConfig)(step.config)) {
5908
+ if (!step.config.transformCode) {
5909
+ return {
5910
+ valid: false,
5911
+ error: `${stepLabel}: transform step missing 'transformCode'`
5912
+ };
5913
+ }
5914
+ continue;
5915
+ }
5916
+ if (!(0, types_js_1.isRequestConfig)(step.config)) {
5917
+ return {
5918
+ valid: false,
5919
+ error: `${stepLabel}: unknown step config type`
5920
+ };
5921
+ }
5922
+ if (typeof step.config.url !== "string" || step.config.url.trim().length === 0) {
5923
+ return { valid: false, error: `${stepLabel}: request step missing 'url'` };
5924
+ }
5925
+ }
5926
+ return { valid: true };
5927
+ }
5732
5928
  }
5733
5929
  });
5734
5930
 
@@ -21697,12 +21893,18 @@ var require_superglue_client = __commonJS({
21697
21893
  const response = await this.restRequest("GET", `/v1/tools?limit=${limit}&page=${page}${archiveParam}`);
21698
21894
  return { items: response.data, total: response.total };
21699
21895
  }
21896
+ async createWorkflow(id, input) {
21897
+ return this.restRequest("POST", "/v1/tools", { ...input, id });
21898
+ }
21899
+ async updateWorkflow(id, input) {
21900
+ return this.restRequest("PUT", `/v1/tools/${encodeURIComponent(id)}`, input);
21901
+ }
21700
21902
  async upsertWorkflow(id, input) {
21701
21903
  const existing = await this.getWorkflow(id);
21702
21904
  if (existing) {
21703
- return this.restRequest("PUT", `/v1/tools/${encodeURIComponent(id)}`, input);
21905
+ return this.updateWorkflow(id, input);
21704
21906
  } else {
21705
- return this.restRequest("POST", "/v1/tools", { id, ...input });
21907
+ return this.createWorkflow(id, input);
21706
21908
  }
21707
21909
  }
21708
21910
  async deleteWorkflow(id) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superglue/cli",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "bin": {
5
5
  "sg": "./dist/cli.js"
6
6
  },