@superglue/cli 0.1.0 → 1.0.0

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
@@ -20962,23 +20962,32 @@ var require_cli_oauth = __commonJS({
20962
20962
  Object.defineProperty(exports2, "__esModule", { value: true });
20963
20963
  exports2.encryptCliApiKey = encryptCliApiKey2;
20964
20964
  exports2.decryptCliApiKey = decryptCliApiKey;
20965
- var crypto_1 = __importDefault(require("crypto"));
20966
- function encryptCliApiKey2(apiKey, systemId) {
20967
- const key = crypto_1.default.createHash("sha256").update(`cli-oauth-${systemId}`).digest();
20968
- const iv = crypto_1.default.randomBytes(16);
20969
- const cipher = crypto_1.default.createCipheriv("aes-256-cbc", key, iv);
20965
+ var node_crypto_1 = __importDefault(require("crypto"));
20966
+ function encryptCliApiKey2(apiKey, systemId, secret) {
20967
+ if (!secret) {
20968
+ throw new Error("Server secret required for CLI OAuth encryption");
20969
+ }
20970
+ const key = node_crypto_1.default.createHash("sha256").update(`${secret}:cli-oauth:${systemId}`).digest();
20971
+ const iv = node_crypto_1.default.randomBytes(12);
20972
+ const cipher = node_crypto_1.default.createCipheriv("aes-256-gcm", key, iv);
20970
20973
  let encrypted = cipher.update(apiKey, "utf8", "hex");
20971
20974
  encrypted += cipher.final("hex");
20972
- return `${iv.toString("hex")}:${encrypted}`;
20975
+ const authTag = cipher.getAuthTag().toString("hex");
20976
+ return `${iv.toString("hex")}:${encrypted}:${authTag}`;
20973
20977
  }
20974
- function decryptCliApiKey(encrypted, systemId) {
20978
+ function decryptCliApiKey(encrypted, systemId, secret) {
20979
+ if (!secret) {
20980
+ return null;
20981
+ }
20975
20982
  try {
20976
- const [ivHex, encryptedHex] = encrypted.split(":");
20977
- if (!ivHex || !encryptedHex)
20983
+ const [ivHex, encryptedHex, authTagHex] = encrypted.split(":");
20984
+ if (!ivHex || !encryptedHex || !authTagHex)
20978
20985
  return null;
20979
- const key = crypto_1.default.createHash("sha256").update(`cli-oauth-${systemId}`).digest();
20986
+ const key = node_crypto_1.default.createHash("sha256").update(`${secret}:cli-oauth:${systemId}`).digest();
20980
20987
  const iv = Buffer.from(ivHex, "hex");
20981
- const decipher = crypto_1.default.createDecipheriv("aes-256-cbc", key, iv);
20988
+ const authTag = Buffer.from(authTagHex, "hex");
20989
+ const decipher = node_crypto_1.default.createDecipheriv("aes-256-gcm", key, iv);
20990
+ decipher.setAuthTag(authTag);
20982
20991
  let decrypted = decipher.update(encryptedHex, "hex", "utf8");
20983
20992
  decrypted += decipher.final("utf8");
20984
20993
  return decrypted;
@@ -21454,6 +21463,14 @@ var require_superglue_client = __commonJS({
21454
21463
  const response = await this.restRequest("GET", `/v1/oauth/templates/${encodeURIComponent(params.templateId)}/credentials`);
21455
21464
  return response.data;
21456
21465
  }
21466
+ /**
21467
+ * Get the CLI OAuth encryption secret and orgId.
21468
+ * Used by CLI to encrypt API keys in OAuth state parameters.
21469
+ */
21470
+ async getCliOAuthSecret() {
21471
+ const response = await this.restRequest("GET", "/v1/oauth/cli-secret");
21472
+ return response.data;
21473
+ }
21457
21474
  async triggerSystemDocumentationScrapeJob(systemId, options) {
21458
21475
  const response = await this.restRequest("POST", `/v1/systems/${encodeURIComponent(systemId)}/documentation/scrape`, options);
21459
21476
  return response.data;
@@ -21571,6 +21588,7 @@ var import_commander = require("commander");
21571
21588
 
21572
21589
  // src/config.ts
21573
21590
  var fs = __toESM(require("fs"));
21591
+ var os = __toESM(require("os"));
21574
21592
  var path = __toESM(require("path"));
21575
21593
  var DEFAULT_CONFIG = {
21576
21594
  output: { mode: "stdout", directory: ".superglue/output" },
@@ -21579,16 +21597,26 @@ var DEFAULT_CONFIG = {
21579
21597
  editTool: "confirm"
21580
21598
  }
21581
21599
  };
21582
- function getConfigDir() {
21600
+ function getConfigDir(preferLocal) {
21583
21601
  const localDir = path.join(process.cwd(), ".superglue");
21602
+ const homeDir = os.homedir();
21603
+ if (!homeDir) {
21604
+ return localDir;
21605
+ }
21606
+ const globalDir = path.join(homeDir, ".superglue");
21607
+ if (preferLocal === true) {
21608
+ return localDir;
21609
+ }
21610
+ if (preferLocal === false) {
21611
+ return globalDir;
21612
+ }
21584
21613
  if (fs.existsSync(path.join(localDir, "config.json"))) {
21585
21614
  return localDir;
21586
21615
  }
21587
- const homeDir = process.env.HOME || process.env.USERPROFILE || "";
21588
- return path.join(homeDir, ".superglue");
21616
+ return globalDir;
21589
21617
  }
21590
- function getConfigPath() {
21591
- return path.join(getConfigDir(), "config.json");
21618
+ function getConfigPath(preferLocal) {
21619
+ return path.join(getConfigDir(preferLocal), "config.json");
21592
21620
  }
21593
21621
  function loadConfigFile() {
21594
21622
  const configPath = getConfigPath();
@@ -21614,13 +21642,13 @@ function resolveConfig(flags) {
21614
21642
  policies: { ...DEFAULT_CONFIG.policies, ...file.policies }
21615
21643
  };
21616
21644
  }
21617
- function writeConfig(config) {
21618
- const dir = getConfigDir();
21645
+ function writeConfig(config, preferLocal) {
21646
+ const dir = getConfigDir(preferLocal);
21619
21647
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
21620
- fs.writeFileSync(getConfigPath(), JSON.stringify(config, null, 2) + "\n");
21648
+ fs.writeFileSync(path.join(dir, "config.json"), JSON.stringify(config, null, 2) + "\n");
21621
21649
  }
21622
- function ensureConfigDirs(config) {
21623
- const draftsDir = path.join(getConfigDir(), "drafts");
21650
+ function ensureConfigDirs(config, preferLocal) {
21651
+ const draftsDir = path.join(getConfigDir(preferLocal), "drafts");
21624
21652
  if (!fs.existsSync(draftsDir)) fs.mkdirSync(draftsDir, { recursive: true });
21625
21653
  if (config.output.mode === "stdout+file") {
21626
21654
  const outDir = path.resolve(config.output.directory);
@@ -21644,6 +21672,7 @@ function createClient(config) {
21644
21672
  // src/commands/init.ts
21645
21673
  var fs2 = __toESM(require("fs"));
21646
21674
  var path2 = __toESM(require("path"));
21675
+ var os2 = __toESM(require("os"));
21647
21676
  var import_shared2 = __toESM(require_dist2());
21648
21677
 
21649
21678
  // src/output.ts
@@ -22039,6 +22068,19 @@ function registerInitCommand(program2) {
22039
22068
  0
22040
22069
  );
22041
22070
  const editPolicies = ["confirm", "auto_accept"];
22071
+ heading("Config Location");
22072
+ const homeDir = os2.homedir();
22073
+ const localPath = path2.join(process.cwd(), ".superglue");
22074
+ const globalPath = path2.join(homeDir, ".superglue");
22075
+ const configLocationIdx = await choose(
22076
+ "Where to save config?",
22077
+ [
22078
+ `Project (${localPath}) \u2014 config stays with this project`,
22079
+ `Global (${globalPath}) \u2014 shared across all projects`
22080
+ ],
22081
+ 0
22082
+ );
22083
+ const preferLocal = configLocationIdx === 0;
22042
22084
  const config = {
22043
22085
  apiKey,
22044
22086
  endpoint,
@@ -22049,35 +22091,39 @@ function registerInitCommand(program2) {
22049
22091
  editTool: editPolicies[editPolicyIdx]
22050
22092
  }
22051
22093
  };
22052
- writeConfig(config);
22053
- ensureConfigDirs(config);
22094
+ writeConfig(config, preferLocal);
22095
+ ensureConfigDirs(config, preferLocal);
22096
+ const configDir = getConfigDir(preferLocal);
22097
+ const configRelPath = preferLocal ? ".superglue/config.json" : path2.join(configDir, "config.json");
22054
22098
  const gitignorePath = path2.join(process.cwd(), ".gitignore");
22055
- const ignoreEntries = [".superglue/drafts/", `${outputDir}/`, ".superglue/config.json"];
22056
- if (fs2.existsSync(gitignorePath)) {
22057
- const existing = fs2.readFileSync(gitignorePath, "utf-8");
22058
- const toAdd = ignoreEntries.filter((e) => !existing.includes(e));
22059
- if (toAdd.length > 0) {
22060
- fs2.appendFileSync(gitignorePath, "\n# superglue CLI\n" + toAdd.join("\n") + "\n");
22061
- info("Updated .gitignore");
22099
+ const ignoreEntries = [];
22100
+ if (outputMode === "stdout+file" && !path2.isAbsolute(outputDir)) {
22101
+ ignoreEntries.push(`${outputDir}/`);
22102
+ }
22103
+ if (preferLocal) {
22104
+ ignoreEntries.push(".superglue/drafts/", ".superglue/config.json");
22105
+ }
22106
+ if (ignoreEntries.length > 0) {
22107
+ if (fs2.existsSync(gitignorePath)) {
22108
+ const existing = fs2.readFileSync(gitignorePath, "utf-8");
22109
+ const toAdd = ignoreEntries.filter((e) => !existing.includes(e));
22110
+ if (toAdd.length > 0) {
22111
+ fs2.appendFileSync(gitignorePath, "\n# superglue CLI\n" + toAdd.join("\n") + "\n");
22112
+ info("Updated .gitignore");
22113
+ }
22114
+ } else if (preferLocal) {
22115
+ fs2.writeFileSync(gitignorePath, "# superglue CLI\n" + ignoreEntries.join("\n") + "\n");
22116
+ info("Created .gitignore");
22062
22117
  }
22063
- } else {
22064
- fs2.writeFileSync(gitignorePath, "# superglue CLI\n" + ignoreEntries.join("\n") + "\n");
22065
- info("Created .gitignore");
22066
22118
  }
22067
22119
  console.log("");
22068
- console.log(` ${c.dim}\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510${c.reset}`);
22069
- console.log(
22070
- ` ${c.dim}\u2502${c.reset} ${c.green}\u2713${c.reset} Config saved to ${c.bold}.superglue/config.json${c.reset} ${c.dim}\u2502${c.reset}`
22071
- );
22072
- console.log(
22073
- ` ${c.dim}\u2502${c.reset} ${c.green}\u2713${c.reset} Created ${c.bold}.superglue/drafts/${c.reset} ${c.dim}\u2502${c.reset}`
22074
- );
22120
+ success(`Config saved to ${c.bold}${configRelPath}${c.reset}`);
22121
+ if (preferLocal) {
22122
+ success(`Created ${c.bold}.superglue/drafts/${c.reset}`);
22123
+ }
22075
22124
  if (outputMode === "stdout+file") {
22076
- console.log(
22077
- ` ${c.dim}\u2502${c.reset} ${c.green}\u2713${c.reset} Created ${c.bold}${outputDir}/${c.reset}${"".padEnd(Math.max(0, 27 - outputDir.length))}${c.dim}\u2502${c.reset}`
22078
- );
22125
+ success(`Created ${c.bold}${outputDir}/${c.reset}`);
22079
22126
  }
22080
- console.log(` ${c.dim}\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518${c.reset}`);
22081
22127
  console.log("");
22082
22128
  console.log(` ${c.bold}You're all set!${c.reset} Try these commands:
22083
22129
  `);
@@ -23100,10 +23146,21 @@ function registerOAuthCommand(parent, getContext2) {
23100
23146
  process.exit(1);
23101
23147
  }
23102
23148
  const originalToken = system.credentials?.access_token;
23103
- const encryptedApiKey = (0, import_shared8.encryptCliApiKey)(config.apiKey, opts.systemId);
23149
+ let encryptionSecret;
23150
+ let orgId;
23151
+ try {
23152
+ const secretData = await client.getCliOAuthSecret();
23153
+ encryptionSecret = secretData.secret;
23154
+ orgId = secretData.orgId;
23155
+ } catch (err) {
23156
+ error(`Failed to get OAuth encryption secret: ${err.message}`);
23157
+ process.exit(1);
23158
+ }
23159
+ const encryptedApiKey = (0, import_shared8.encryptCliApiKey)(config.apiKey, opts.systemId, encryptionSecret);
23104
23160
  const redirectUri = `${config.webEndpoint.replace(/\/$/, "")}/api/auth/callback`;
23105
23161
  const state = {
23106
23162
  systemId: opts.systemId,
23163
+ orgId,
23107
23164
  timestamp: Date.now(),
23108
23165
  redirectUri,
23109
23166
  token_url: tokenUrl,
@@ -23241,8 +23298,43 @@ function registerRunCommands(program2, getContext2) {
23241
23298
  // src/version.ts
23242
23299
  var import_node_child_process2 = require("child_process");
23243
23300
  var import_node_util = require("util");
23301
+
23302
+ // package.json
23303
+ var package_default = {
23304
+ name: "@superglue/cli",
23305
+ version: "1.0.0",
23306
+ bin: {
23307
+ sg: "./dist/cli.js"
23308
+ },
23309
+ files: [
23310
+ "dist/",
23311
+ "skills/",
23312
+ "skills.md"
23313
+ ],
23314
+ dependencies: {
23315
+ commander: "^13.0.0",
23316
+ "fast-json-patch": "^3.1.1"
23317
+ },
23318
+ devDependencies: {
23319
+ "@superglue/shared": "file:../shared",
23320
+ "@types/node": "^20.0.0",
23321
+ tsup: "^8.0.0",
23322
+ typescript: "^5.0.0"
23323
+ },
23324
+ scripts: {
23325
+ build: "tsup && cp -r skills dist/ 2>/dev/null || true",
23326
+ dev: "tsup --watch",
23327
+ "type-check": "tsc --noEmit",
23328
+ prepublishOnly: "npm run build"
23329
+ },
23330
+ publishConfig: {
23331
+ access: "public"
23332
+ }
23333
+ };
23334
+
23335
+ // src/version.ts
23244
23336
  var execAsync = (0, import_node_util.promisify)(import_node_child_process2.exec);
23245
- var CLI_VERSION = "0.1.0";
23337
+ var CLI_VERSION = package_default.version;
23246
23338
  function compareVersions(a, b) {
23247
23339
  const partsA = a.split(".").map(Number);
23248
23340
  const partsB = b.split(".").map(Number);
@@ -23317,7 +23409,8 @@ function registerUpdateCommand(program2) {
23317
23409
  error("Could not fetch latest version from npm");
23318
23410
  process.exit(1);
23319
23411
  }
23320
- if (latestVersion === CLI_VERSION) {
23412
+ const comparison = compareVersions(CLI_VERSION, latestVersion);
23413
+ if (comparison >= 0) {
23321
23414
  success(`You're on the latest version (${CLI_VERSION})`);
23322
23415
  } else {
23323
23416
  console.log("");
@@ -23395,10 +23488,31 @@ registerToolCommands(program, getContext);
23395
23488
  registerSystemCommands(program, getContext);
23396
23489
  registerRunCommands(program, getContext);
23397
23490
  var commandsRequiringServer = ["tool", "system", "run"];
23398
- var firstArg = process.argv[2];
23399
- if (firstArg && commandsRequiringServer.includes(firstArg)) {
23400
- const opts = program.opts();
23401
- const config = resolveConfig({ apiKey: opts.apiKey, endpoint: opts.endpoint });
23491
+ var globalFlagsWithValues = ["--api-key", "--endpoint"];
23492
+ var globalFlagsNoValue = ["--json", "-y", "--yes", "-h", "--help", "-V", "--version"];
23493
+ function findSubcommand(argv) {
23494
+ let i = 2;
23495
+ while (i < argv.length) {
23496
+ const arg = argv[i];
23497
+ if (globalFlagsWithValues.includes(arg)) {
23498
+ i += 2;
23499
+ } else if (globalFlagsNoValue.includes(arg)) {
23500
+ i += 1;
23501
+ } else if (arg.startsWith("-")) {
23502
+ i += 1;
23503
+ } else {
23504
+ return arg;
23505
+ }
23506
+ }
23507
+ return void 0;
23508
+ }
23509
+ var subcommand = findSubcommand(process.argv);
23510
+ if (subcommand && commandsRequiringServer.includes(subcommand)) {
23511
+ const apiKeyIdx = process.argv.indexOf("--api-key");
23512
+ const endpointIdx = process.argv.indexOf("--endpoint");
23513
+ const cliApiKey = apiKeyIdx !== -1 ? process.argv[apiKeyIdx + 1] : void 0;
23514
+ const cliEndpoint = endpointIdx !== -1 ? process.argv[endpointIdx + 1] : void 0;
23515
+ const config = resolveConfig({ apiKey: cliApiKey, endpoint: cliEndpoint });
23402
23516
  if (config.apiKey) {
23403
23517
  checkVersionCompatibility(config.endpoint).then(() => program.parse());
23404
23518
  } else {
@@ -620,6 +620,7 @@ const { data } = await runTool("my-tool-id", { inputs: { userId: "123" } });
620
620
  ### Python SDK
621
621
 
622
622
  ```python
623
+ import os
623
624
  from superglue_client import SuperglueClient
624
625
  from superglue_client.api.tools import run_tool
625
626
  client = SuperglueClient(base_url="https://api.superglue.cloud/v1", token=os.environ["SUPERGLUE_API_KEY"])
@@ -7,36 +7,36 @@ After building and saving tools with the CLI, integrate them into your applicati
7
7
  For any language, use the REST API directly:
8
8
 
9
9
  ```bash
10
- # Set your API key
10
+ # Set your API key and endpoint
11
11
  export SUPERGLUE_API_KEY="your-api-key"
12
- export SUPERGLUE_ENDPOINT="https://api.superglue.cloud"
12
+ export SUPERGLUE_API_ENDPOINT="https://api.superglue.cloud"
13
13
 
14
14
  # Run a tool (sync - waits for completion)
15
- curl -X POST "$SUPERGLUE_ENDPOINT/v1/tools/my-tool-id/run" \
15
+ curl -X POST "$SUPERGLUE_API_ENDPOINT/v1/tools/my-tool-id/run" \
16
16
  -H "Authorization: Bearer $SUPERGLUE_API_KEY" \
17
17
  -H "Content-Type: application/json" \
18
18
  -d '{"inputs": {"userId": "123"}, "options": {"async": false}}'
19
19
 
20
20
  # Run a tool (async - returns immediately)
21
- curl -X POST "$SUPERGLUE_ENDPOINT/v1/tools/my-tool-id/run" \
21
+ curl -X POST "$SUPERGLUE_API_ENDPOINT/v1/tools/my-tool-id/run" \
22
22
  -H "Authorization: Bearer $SUPERGLUE_API_KEY" \
23
23
  -H "Content-Type: application/json" \
24
24
  -d '{"inputs": {"userId": "123"}, "options": {"async": true}}'
25
25
 
26
26
  # Get run status/result
27
- curl "$SUPERGLUE_ENDPOINT/v1/runs/{runId}" \
27
+ curl "$SUPERGLUE_API_ENDPOINT/v1/runs/{runId}" \
28
28
  -H "Authorization: Bearer $SUPERGLUE_API_KEY"
29
29
 
30
30
  # List tools
31
- curl "$SUPERGLUE_ENDPOINT/v1/tools?page=1&limit=50" \
31
+ curl "$SUPERGLUE_API_ENDPOINT/v1/tools?page=1&limit=50" \
32
32
  -H "Authorization: Bearer $SUPERGLUE_API_KEY"
33
33
 
34
34
  # Get tool details
35
- curl "$SUPERGLUE_ENDPOINT/v1/tools/my-tool-id" \
35
+ curl "$SUPERGLUE_API_ENDPOINT/v1/tools/my-tool-id" \
36
36
  -H "Authorization: Bearer $SUPERGLUE_API_KEY"
37
37
 
38
38
  # Cancel a running tool
39
- curl -X POST "$SUPERGLUE_ENDPOINT/v1/runs/{runId}/cancel" \
39
+ curl -X POST "$SUPERGLUE_API_ENDPOINT/v1/runs/{runId}/cancel" \
40
40
  -H "Authorization: Bearer $SUPERGLUE_API_KEY"
41
41
  ```
42
42
 
@@ -144,6 +144,7 @@ const { data: systems } = await listSystems();
144
144
  ## Python Usage
145
145
 
146
146
  ```python
147
+ import os
147
148
  from superglue_client import SuperglueClient
148
149
  from superglue_client.api.tools import run_tool, list_tools, get_tool
149
150
  from superglue_client.api.runs import get_run
@@ -261,7 +262,7 @@ async function runWithFallback(inputs: Record<string, any>) {
261
262
  SUPERGLUE_API_KEY=your-api-key
262
263
 
263
264
  # Optional (defaults to hosted)
264
- SUPERGLUE_API_ENDPOINT=https://api.superglue.cloud/v1
265
+ SUPERGLUE_API_ENDPOINT=https://api.superglue.cloud
265
266
  ```
266
267
 
267
268
  ## Best Practices
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superglue/cli",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
4
  "bin": {
5
5
  "sg": "./dist/cli.js"
6
6
  },
@@ -620,6 +620,7 @@ const { data } = await runTool("my-tool-id", { inputs: { userId: "123" } });
620
620
  ### Python SDK
621
621
 
622
622
  ```python
623
+ import os
623
624
  from superglue_client import SuperglueClient
624
625
  from superglue_client.api.tools import run_tool
625
626
  client = SuperglueClient(base_url="https://api.superglue.cloud/v1", token=os.environ["SUPERGLUE_API_KEY"])
@@ -7,36 +7,36 @@ After building and saving tools with the CLI, integrate them into your applicati
7
7
  For any language, use the REST API directly:
8
8
 
9
9
  ```bash
10
- # Set your API key
10
+ # Set your API key and endpoint
11
11
  export SUPERGLUE_API_KEY="your-api-key"
12
- export SUPERGLUE_ENDPOINT="https://api.superglue.cloud"
12
+ export SUPERGLUE_API_ENDPOINT="https://api.superglue.cloud"
13
13
 
14
14
  # Run a tool (sync - waits for completion)
15
- curl -X POST "$SUPERGLUE_ENDPOINT/v1/tools/my-tool-id/run" \
15
+ curl -X POST "$SUPERGLUE_API_ENDPOINT/v1/tools/my-tool-id/run" \
16
16
  -H "Authorization: Bearer $SUPERGLUE_API_KEY" \
17
17
  -H "Content-Type: application/json" \
18
18
  -d '{"inputs": {"userId": "123"}, "options": {"async": false}}'
19
19
 
20
20
  # Run a tool (async - returns immediately)
21
- curl -X POST "$SUPERGLUE_ENDPOINT/v1/tools/my-tool-id/run" \
21
+ curl -X POST "$SUPERGLUE_API_ENDPOINT/v1/tools/my-tool-id/run" \
22
22
  -H "Authorization: Bearer $SUPERGLUE_API_KEY" \
23
23
  -H "Content-Type: application/json" \
24
24
  -d '{"inputs": {"userId": "123"}, "options": {"async": true}}'
25
25
 
26
26
  # Get run status/result
27
- curl "$SUPERGLUE_ENDPOINT/v1/runs/{runId}" \
27
+ curl "$SUPERGLUE_API_ENDPOINT/v1/runs/{runId}" \
28
28
  -H "Authorization: Bearer $SUPERGLUE_API_KEY"
29
29
 
30
30
  # List tools
31
- curl "$SUPERGLUE_ENDPOINT/v1/tools?page=1&limit=50" \
31
+ curl "$SUPERGLUE_API_ENDPOINT/v1/tools?page=1&limit=50" \
32
32
  -H "Authorization: Bearer $SUPERGLUE_API_KEY"
33
33
 
34
34
  # Get tool details
35
- curl "$SUPERGLUE_ENDPOINT/v1/tools/my-tool-id" \
35
+ curl "$SUPERGLUE_API_ENDPOINT/v1/tools/my-tool-id" \
36
36
  -H "Authorization: Bearer $SUPERGLUE_API_KEY"
37
37
 
38
38
  # Cancel a running tool
39
- curl -X POST "$SUPERGLUE_ENDPOINT/v1/runs/{runId}/cancel" \
39
+ curl -X POST "$SUPERGLUE_API_ENDPOINT/v1/runs/{runId}/cancel" \
40
40
  -H "Authorization: Bearer $SUPERGLUE_API_KEY"
41
41
  ```
42
42
 
@@ -144,6 +144,7 @@ const { data: systems } = await listSystems();
144
144
  ## Python Usage
145
145
 
146
146
  ```python
147
+ import os
147
148
  from superglue_client import SuperglueClient
148
149
  from superglue_client.api.tools import run_tool, list_tools, get_tool
149
150
  from superglue_client.api.runs import get_run
@@ -261,7 +262,7 @@ async function runWithFallback(inputs: Record<string, any>) {
261
262
  SUPERGLUE_API_KEY=your-api-key
262
263
 
263
264
  # Optional (defaults to hosted)
264
- SUPERGLUE_API_ENDPOINT=https://api.superglue.cloud/v1
265
+ SUPERGLUE_API_ENDPOINT=https://api.superglue.cloud
265
266
  ```
266
267
 
267
268
  ## Best Practices