@superglue/cli 0.1.0 → 1.1.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/README.md +79 -0
- package/dist/cli.js +323 -153
- package/dist/skills/superglue/SKILL.md +5 -4
- package/dist/skills/superglue/references/file-servers.md +1 -1
- package/dist/skills/superglue/references/integration.md +10 -9
- package/package.json +2 -2
- package/skills/superglue/SKILL.md +5 -4
- package/skills/superglue/references/file-servers.md +1 -1
- package/skills/superglue/references/integration.md +10 -9
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# superglue CLI
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@superglue/cli)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
Build, test, and manage superglue API integration tools from the command line.
|
|
7
|
+
|
|
8
|
+
## What is superglue?
|
|
9
|
+
|
|
10
|
+
- AI-powered tool builder that works with any API, database or file storage server
|
|
11
|
+
- Abstracts away authentication, documentation handling and data mapping between systems
|
|
12
|
+
- Self-heals tools: when steps fail due to upstream API changes, superglue can auto-repair failures
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### As npm package
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g @superglue/cli
|
|
20
|
+
sg --help
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### As Claude Code Plugin
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
/plugin install github:superglue-ai/cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
sg init # guided setup
|
|
33
|
+
sg system list # verify connection
|
|
34
|
+
sg tool build --config '...' # build a tool
|
|
35
|
+
sg tool run --draft <id> # test it
|
|
36
|
+
sg tool save --draft <id> # save it
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Commands
|
|
40
|
+
|
|
41
|
+
### Tools
|
|
42
|
+
|
|
43
|
+
- `sg tool build` — Build a tool from config
|
|
44
|
+
- `sg tool run` — Run a draft or saved tool
|
|
45
|
+
- `sg tool edit` — Edit via JSON Patch
|
|
46
|
+
- `sg tool save` — Save a draft
|
|
47
|
+
- `sg tool list` — List saved tools
|
|
48
|
+
- `sg tool find` — Search tools
|
|
49
|
+
|
|
50
|
+
### Systems
|
|
51
|
+
|
|
52
|
+
- `sg system create` — Create a system
|
|
53
|
+
- `sg system edit` — Edit system config
|
|
54
|
+
- `sg system list` — List systems
|
|
55
|
+
- `sg system find` — Search systems
|
|
56
|
+
- `sg system call` — Make authenticated API calls
|
|
57
|
+
- `sg system oauth` — Authenticate via OAuth
|
|
58
|
+
- `sg system docs` — Search system documentation
|
|
59
|
+
|
|
60
|
+
### Runs
|
|
61
|
+
|
|
62
|
+
- `sg run list` — List execution runs
|
|
63
|
+
- `sg run get` — Get run details
|
|
64
|
+
|
|
65
|
+
## Documentation
|
|
66
|
+
|
|
67
|
+
- [Full CLI Reference](./skills/superglue/SKILL.md) — Complete command documentation
|
|
68
|
+
- [superglue Docs](https://docs.superglue.cloud) — Platform documentation
|
|
69
|
+
- [API Reference](https://docs.superglue.cloud/api-reference/) — REST API docs
|
|
70
|
+
|
|
71
|
+
## Related
|
|
72
|
+
|
|
73
|
+
- [superglue Web App](https://app.superglue.cloud) — Visual tool builder
|
|
74
|
+
- [@superglue/client](https://www.npmjs.com/package/@superglue/client) — TypeScript SDK
|
|
75
|
+
- [superglue-client](https://pypi.org/project/superglue-client/) — Python SDK
|
|
76
|
+
|
|
77
|
+
## License
|
|
78
|
+
|
|
79
|
+
MIT
|
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
|
|
20966
|
-
function encryptCliApiKey2(apiKey, systemId) {
|
|
20967
|
-
|
|
20968
|
-
|
|
20969
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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,15 @@ 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(
|
|
21648
|
+
fs.writeFileSync(path.join(dir, "config.json"), JSON.stringify(config, null, 2) + "\n", {
|
|
21649
|
+
mode: 384
|
|
21650
|
+
});
|
|
21621
21651
|
}
|
|
21622
|
-
function ensureConfigDirs(config) {
|
|
21623
|
-
const draftsDir = path.join(getConfigDir(), "drafts");
|
|
21652
|
+
function ensureConfigDirs(config, preferLocal) {
|
|
21653
|
+
const draftsDir = path.join(getConfigDir(preferLocal), "drafts");
|
|
21624
21654
|
if (!fs.existsSync(draftsDir)) fs.mkdirSync(draftsDir, { recursive: true });
|
|
21625
21655
|
if (config.output.mode === "stdout+file") {
|
|
21626
21656
|
const outDir = path.resolve(config.output.directory);
|
|
@@ -21644,10 +21674,130 @@ function createClient(config) {
|
|
|
21644
21674
|
// src/commands/init.ts
|
|
21645
21675
|
var fs2 = __toESM(require("fs"));
|
|
21646
21676
|
var path2 = __toESM(require("path"));
|
|
21677
|
+
var os2 = __toESM(require("os"));
|
|
21647
21678
|
var import_shared2 = __toESM(require_dist2());
|
|
21648
21679
|
|
|
21649
21680
|
// src/output.ts
|
|
21650
21681
|
var readline = __toESM(require("readline"));
|
|
21682
|
+
|
|
21683
|
+
// src/version.ts
|
|
21684
|
+
var import_node_child_process = require("child_process");
|
|
21685
|
+
var import_node_util = require("util");
|
|
21686
|
+
|
|
21687
|
+
// package.json
|
|
21688
|
+
var package_default = {
|
|
21689
|
+
name: "@superglue/cli",
|
|
21690
|
+
version: "1.1.0",
|
|
21691
|
+
bin: {
|
|
21692
|
+
sg: "./dist/cli.js"
|
|
21693
|
+
},
|
|
21694
|
+
files: [
|
|
21695
|
+
"dist/",
|
|
21696
|
+
"skills/",
|
|
21697
|
+
"skills.md"
|
|
21698
|
+
],
|
|
21699
|
+
dependencies: {
|
|
21700
|
+
commander: "^13.0.0",
|
|
21701
|
+
"fast-json-patch": "^3.1.1"
|
|
21702
|
+
},
|
|
21703
|
+
devDependencies: {
|
|
21704
|
+
"@superglue/shared": "file:../shared",
|
|
21705
|
+
"@types/node": "^20.0.0",
|
|
21706
|
+
tsup: "^8.0.0",
|
|
21707
|
+
typescript: "^5.0.0"
|
|
21708
|
+
},
|
|
21709
|
+
scripts: {
|
|
21710
|
+
build: "tsup && (cp -r skills dist/ 2>/dev/null || true)",
|
|
21711
|
+
dev: "tsup --watch",
|
|
21712
|
+
"type-check": "tsc --noEmit",
|
|
21713
|
+
prepublishOnly: "npm run build"
|
|
21714
|
+
},
|
|
21715
|
+
publishConfig: {
|
|
21716
|
+
access: "public"
|
|
21717
|
+
}
|
|
21718
|
+
};
|
|
21719
|
+
|
|
21720
|
+
// src/version.ts
|
|
21721
|
+
var execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
|
|
21722
|
+
var CLI_VERSION = package_default.version;
|
|
21723
|
+
function parseVersionPart(part) {
|
|
21724
|
+
const match = part.match(/^(\d+)(?:-(.+))?$/);
|
|
21725
|
+
if (match) {
|
|
21726
|
+
return { numeric: parseInt(match[1], 10), prerelease: match[2] || null };
|
|
21727
|
+
}
|
|
21728
|
+
return { numeric: 0, prerelease: part };
|
|
21729
|
+
}
|
|
21730
|
+
function compareVersions(a, b) {
|
|
21731
|
+
const partsA = a.split(".");
|
|
21732
|
+
const partsB = b.split(".");
|
|
21733
|
+
const maxLen = Math.max(partsA.length, partsB.length);
|
|
21734
|
+
for (let i = 0; i < maxLen; i++) {
|
|
21735
|
+
const parsedA = parseVersionPart(partsA[i] || "0");
|
|
21736
|
+
const parsedB = parseVersionPart(partsB[i] || "0");
|
|
21737
|
+
if (parsedA.numeric < parsedB.numeric) return -1;
|
|
21738
|
+
if (parsedA.numeric > parsedB.numeric) return 1;
|
|
21739
|
+
if (parsedA.prerelease === null && parsedB.prerelease !== null) return 1;
|
|
21740
|
+
if (parsedA.prerelease !== null && parsedB.prerelease === null) return -1;
|
|
21741
|
+
if (parsedA.prerelease !== null && parsedB.prerelease !== null) {
|
|
21742
|
+
if (parsedA.prerelease < parsedB.prerelease) return -1;
|
|
21743
|
+
if (parsedA.prerelease > parsedB.prerelease) return 1;
|
|
21744
|
+
}
|
|
21745
|
+
}
|
|
21746
|
+
return 0;
|
|
21747
|
+
}
|
|
21748
|
+
async function checkVersionCompatibility(endpoint) {
|
|
21749
|
+
try {
|
|
21750
|
+
const healthUrl = `${endpoint.replace(/\/$/, "")}/v1/health`;
|
|
21751
|
+
const response = await fetch(healthUrl, { signal: AbortSignal.timeout(3e3) });
|
|
21752
|
+
if (!response.ok) return;
|
|
21753
|
+
const health = await response.json();
|
|
21754
|
+
if (!health.minCliVersion) return;
|
|
21755
|
+
if (compareVersions(CLI_VERSION, health.minCliVersion) < 0) {
|
|
21756
|
+
console.error("");
|
|
21757
|
+
console.error(`${c.yellow}${c.bold}\u26A0 CLI version ${CLI_VERSION} is outdated.${c.reset}`);
|
|
21758
|
+
console.error(
|
|
21759
|
+
`${c.yellow} Server requires at least v${health.minCliVersion}. Run: ${c.bold}sg update${c.reset}`
|
|
21760
|
+
);
|
|
21761
|
+
console.error("");
|
|
21762
|
+
}
|
|
21763
|
+
} catch {
|
|
21764
|
+
}
|
|
21765
|
+
}
|
|
21766
|
+
async function getLatestNpmVersion() {
|
|
21767
|
+
try {
|
|
21768
|
+
const response = await fetch("https://registry.npmjs.org/@superglue/cli/latest", {
|
|
21769
|
+
signal: AbortSignal.timeout(5e3)
|
|
21770
|
+
});
|
|
21771
|
+
if (!response.ok) return null;
|
|
21772
|
+
const data = await response.json();
|
|
21773
|
+
return data.version || null;
|
|
21774
|
+
} catch {
|
|
21775
|
+
return null;
|
|
21776
|
+
}
|
|
21777
|
+
}
|
|
21778
|
+
async function updateCli() {
|
|
21779
|
+
const latestVersion = await getLatestNpmVersion();
|
|
21780
|
+
if (!latestVersion) {
|
|
21781
|
+
return { success: false, message: "Could not fetch latest version from npm" };
|
|
21782
|
+
}
|
|
21783
|
+
if (compareVersions(CLI_VERSION, latestVersion) >= 0) {
|
|
21784
|
+
return { success: true, message: `Already on latest version (${CLI_VERSION})` };
|
|
21785
|
+
}
|
|
21786
|
+
try {
|
|
21787
|
+
await execAsync("npm install -g @superglue/cli@latest");
|
|
21788
|
+
return {
|
|
21789
|
+
success: true,
|
|
21790
|
+
message: `Updated from ${CLI_VERSION} to ${latestVersion}`
|
|
21791
|
+
};
|
|
21792
|
+
} catch (err) {
|
|
21793
|
+
return {
|
|
21794
|
+
success: false,
|
|
21795
|
+
message: `Update failed: ${err.message}. Try manually: npm install -g @superglue/cli@latest`
|
|
21796
|
+
};
|
|
21797
|
+
}
|
|
21798
|
+
}
|
|
21799
|
+
|
|
21800
|
+
// src/output.ts
|
|
21651
21801
|
var isJsonMode = () => process.argv.includes("--json") || !process.stdout.isTTY;
|
|
21652
21802
|
var c = {
|
|
21653
21803
|
reset: "\x1B[0m",
|
|
@@ -21700,7 +21850,7 @@ function banner() {
|
|
|
21700
21850
|
const after = line.slice(last + 1);
|
|
21701
21851
|
console.log(` ${before}${inv}${inside}${rst}${after}`);
|
|
21702
21852
|
});
|
|
21703
|
-
console.log(` ${d} CLI
|
|
21853
|
+
console.log(` ${d} CLI v${CLI_VERSION}${rst}`);
|
|
21704
21854
|
console.log("");
|
|
21705
21855
|
}
|
|
21706
21856
|
function spinner(message) {
|
|
@@ -21753,6 +21903,11 @@ function error(message, details) {
|
|
|
21753
21903
|
if (details) prettyPrint(details, 4);
|
|
21754
21904
|
}
|
|
21755
21905
|
}
|
|
21906
|
+
function warn(message) {
|
|
21907
|
+
if (!isJsonMode()) {
|
|
21908
|
+
console.log(` ${c.yellow}\u26A0${c.reset} ${message}`);
|
|
21909
|
+
}
|
|
21910
|
+
}
|
|
21756
21911
|
function info(message) {
|
|
21757
21912
|
if (!isJsonMode()) {
|
|
21758
21913
|
console.log(` ${c.dim}${message}${c.reset}`);
|
|
@@ -21945,22 +22100,25 @@ async function promptHidden(message) {
|
|
|
21945
22100
|
let input = "";
|
|
21946
22101
|
const onData = (ch) => {
|
|
21947
22102
|
const s = ch.toString();
|
|
21948
|
-
|
|
21949
|
-
if (
|
|
21950
|
-
|
|
21951
|
-
|
|
21952
|
-
|
|
21953
|
-
|
|
21954
|
-
|
|
21955
|
-
|
|
21956
|
-
|
|
21957
|
-
|
|
21958
|
-
|
|
21959
|
-
|
|
22103
|
+
for (const char of s) {
|
|
22104
|
+
if (char === "\n" || char === "\r") {
|
|
22105
|
+
if (process.stdin.isTTY) process.stdin.setRawMode(false);
|
|
22106
|
+
process.stdin.removeListener("data", onData);
|
|
22107
|
+
process.stdout.write("\n");
|
|
22108
|
+
rl.close();
|
|
22109
|
+
resolve4(input);
|
|
22110
|
+
return;
|
|
22111
|
+
} else if (char === "") {
|
|
22112
|
+
process.exit(130);
|
|
22113
|
+
} else if (char === "\x7F" || char === "\b") {
|
|
22114
|
+
if (input.length > 0) {
|
|
22115
|
+
input = input.slice(0, -1);
|
|
22116
|
+
process.stdout.write("\b \b");
|
|
22117
|
+
}
|
|
22118
|
+
} else {
|
|
22119
|
+
input += char;
|
|
22120
|
+
process.stdout.write(`${c.dim}\u2022${c.reset}`);
|
|
21960
22121
|
}
|
|
21961
|
-
} else {
|
|
21962
|
-
input += s;
|
|
21963
|
-
process.stdout.write(`${c.dim}\u2022${c.reset}`);
|
|
21964
22122
|
}
|
|
21965
22123
|
};
|
|
21966
22124
|
process.stdin.on("data", onData);
|
|
@@ -22039,6 +22197,19 @@ function registerInitCommand(program2) {
|
|
|
22039
22197
|
0
|
|
22040
22198
|
);
|
|
22041
22199
|
const editPolicies = ["confirm", "auto_accept"];
|
|
22200
|
+
heading("Config Location");
|
|
22201
|
+
const homeDir = os2.homedir();
|
|
22202
|
+
const localPath = path2.join(process.cwd(), ".superglue");
|
|
22203
|
+
const globalPath = path2.join(homeDir, ".superglue");
|
|
22204
|
+
const configLocationIdx = await choose(
|
|
22205
|
+
"Where to save config?",
|
|
22206
|
+
[
|
|
22207
|
+
`Project (${localPath}) \u2014 config stays with this project`,
|
|
22208
|
+
`Global (${globalPath}) \u2014 shared across all projects`
|
|
22209
|
+
],
|
|
22210
|
+
0
|
|
22211
|
+
);
|
|
22212
|
+
const preferLocal = configLocationIdx === 0;
|
|
22042
22213
|
const config = {
|
|
22043
22214
|
apiKey,
|
|
22044
22215
|
endpoint,
|
|
@@ -22049,35 +22220,39 @@ function registerInitCommand(program2) {
|
|
|
22049
22220
|
editTool: editPolicies[editPolicyIdx]
|
|
22050
22221
|
}
|
|
22051
22222
|
};
|
|
22052
|
-
writeConfig(config);
|
|
22053
|
-
ensureConfigDirs(config);
|
|
22223
|
+
writeConfig(config, preferLocal);
|
|
22224
|
+
ensureConfigDirs(config, preferLocal);
|
|
22225
|
+
const configDir = getConfigDir(preferLocal);
|
|
22226
|
+
const configRelPath = preferLocal ? ".superglue/config.json" : path2.join(configDir, "config.json");
|
|
22054
22227
|
const gitignorePath = path2.join(process.cwd(), ".gitignore");
|
|
22055
|
-
const ignoreEntries = [
|
|
22056
|
-
if (
|
|
22057
|
-
|
|
22058
|
-
|
|
22059
|
-
|
|
22060
|
-
|
|
22061
|
-
|
|
22228
|
+
const ignoreEntries = [];
|
|
22229
|
+
if (outputMode === "stdout+file" && !path2.isAbsolute(outputDir)) {
|
|
22230
|
+
ignoreEntries.push(`${outputDir}/`);
|
|
22231
|
+
}
|
|
22232
|
+
if (preferLocal) {
|
|
22233
|
+
ignoreEntries.push(".superglue/drafts/", ".superglue/config.json");
|
|
22234
|
+
}
|
|
22235
|
+
if (ignoreEntries.length > 0) {
|
|
22236
|
+
if (fs2.existsSync(gitignorePath)) {
|
|
22237
|
+
const existing = fs2.readFileSync(gitignorePath, "utf-8");
|
|
22238
|
+
const toAdd = ignoreEntries.filter((e) => !existing.includes(e));
|
|
22239
|
+
if (toAdd.length > 0) {
|
|
22240
|
+
fs2.appendFileSync(gitignorePath, "\n# superglue CLI\n" + toAdd.join("\n") + "\n");
|
|
22241
|
+
info("Updated .gitignore");
|
|
22242
|
+
}
|
|
22243
|
+
} else if (preferLocal) {
|
|
22244
|
+
fs2.writeFileSync(gitignorePath, "# superglue CLI\n" + ignoreEntries.join("\n") + "\n");
|
|
22245
|
+
info("Created .gitignore");
|
|
22062
22246
|
}
|
|
22063
|
-
} else {
|
|
22064
|
-
fs2.writeFileSync(gitignorePath, "# superglue CLI\n" + ignoreEntries.join("\n") + "\n");
|
|
22065
|
-
info("Created .gitignore");
|
|
22066
22247
|
}
|
|
22067
22248
|
console.log("");
|
|
22068
|
-
|
|
22069
|
-
|
|
22070
|
-
`
|
|
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
|
-
);
|
|
22249
|
+
success(`Config saved to ${c.bold}${configRelPath}${c.reset}`);
|
|
22250
|
+
if (preferLocal) {
|
|
22251
|
+
success(`Created ${c.bold}.superglue/drafts/${c.reset}`);
|
|
22252
|
+
}
|
|
22075
22253
|
if (outputMode === "stdout+file") {
|
|
22076
|
-
|
|
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
|
-
);
|
|
22254
|
+
success(`Created ${c.bold}${outputDir}/${c.reset}`);
|
|
22079
22255
|
}
|
|
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
22256
|
console.log("");
|
|
22082
22257
|
console.log(` ${c.bold}You're all set!${c.reset} Try these commands:
|
|
22083
22258
|
`);
|
|
@@ -22105,9 +22280,11 @@ var path3 = __toESM(require("path"));
|
|
|
22105
22280
|
function getDraftsDir() {
|
|
22106
22281
|
return path3.join(getConfigDir(), "drafts");
|
|
22107
22282
|
}
|
|
22283
|
+
function encodeDraftId(draftId) {
|
|
22284
|
+
return Buffer.from(draftId, "utf-8").toString("base64url");
|
|
22285
|
+
}
|
|
22108
22286
|
function getDraftPath(draftId) {
|
|
22109
|
-
|
|
22110
|
-
return path3.join(getDraftsDir(), `${safeName}.json`);
|
|
22287
|
+
return path3.join(getDraftsDir(), `${encodeDraftId(draftId)}.json`);
|
|
22111
22288
|
}
|
|
22112
22289
|
function writeDraft(draft) {
|
|
22113
22290
|
const dir = getDraftsDir();
|
|
@@ -22425,11 +22602,11 @@ function registerEditCommand(parent, getContext2) {
|
|
|
22425
22602
|
draftId: workingDraftId,
|
|
22426
22603
|
config: {
|
|
22427
22604
|
...patchedConfig,
|
|
22428
|
-
instruction:
|
|
22605
|
+
instruction: patchedConfig.instruction ?? originalConfig.instruction,
|
|
22429
22606
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22430
22607
|
},
|
|
22431
22608
|
systemIds: patchedConfig.systemIds || [],
|
|
22432
|
-
instruction: patchedConfig.instruction
|
|
22609
|
+
instruction: patchedConfig.instruction ?? "",
|
|
22433
22610
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22434
22611
|
};
|
|
22435
22612
|
writeDraft(draft);
|
|
@@ -22495,8 +22672,8 @@ function registerSaveCommand(parent, getContext2) {
|
|
|
22495
22672
|
process.exit(1);
|
|
22496
22673
|
}
|
|
22497
22674
|
const toolId = opts.id || draft.config.id;
|
|
22675
|
+
const spin = spinner(`Saving tool ${c.bold}${toolId}${c.reset}...`);
|
|
22498
22676
|
try {
|
|
22499
|
-
const spin = spinner(`Saving tool ${c.bold}${toolId}${c.reset}...`);
|
|
22500
22677
|
const saved = await client.upsertWorkflow(toolId, {
|
|
22501
22678
|
...draft.config,
|
|
22502
22679
|
id: toolId,
|
|
@@ -22518,6 +22695,7 @@ function registerSaveCommand(parent, getContext2) {
|
|
|
22518
22695
|
console.log("");
|
|
22519
22696
|
}
|
|
22520
22697
|
} catch (err) {
|
|
22698
|
+
spin.stop();
|
|
22521
22699
|
error(err.message);
|
|
22522
22700
|
process.exit(1);
|
|
22523
22701
|
}
|
|
@@ -22556,7 +22734,7 @@ function registerFindCommand(parent, getContext2) {
|
|
|
22556
22734
|
output({ success: true, tool });
|
|
22557
22735
|
return;
|
|
22558
22736
|
}
|
|
22559
|
-
const searchQuery = query || "*";
|
|
22737
|
+
const searchQuery = (query || "").trim() || "*";
|
|
22560
22738
|
if (searchQuery === "*") {
|
|
22561
22739
|
const { items } = await client.listWorkflows(100);
|
|
22562
22740
|
const tools = items.filter((t) => !t.archived).map((t) => ({
|
|
@@ -22657,10 +22835,10 @@ function registerCreateCommand(parent, getContext2) {
|
|
|
22657
22835
|
if (template.oauth.client_id) oauthCreds.client_id = template.oauth.client_id;
|
|
22658
22836
|
}
|
|
22659
22837
|
systemInput = {
|
|
22838
|
+
...systemInput,
|
|
22660
22839
|
name: systemInput.name || template.name,
|
|
22661
|
-
url: template.apiUrl,
|
|
22840
|
+
url: systemInput.url || template.apiUrl,
|
|
22662
22841
|
templateName: opts.template,
|
|
22663
|
-
...systemInput,
|
|
22664
22842
|
credentials: { ...oauthCreds, ...systemInput.credentials }
|
|
22665
22843
|
};
|
|
22666
22844
|
}
|
|
@@ -22759,7 +22937,9 @@ function registerEditCommand2(parent, getContext2) {
|
|
|
22759
22937
|
url: opts.scrapeUrl,
|
|
22760
22938
|
keywords
|
|
22761
22939
|
});
|
|
22762
|
-
} catch {
|
|
22940
|
+
} catch (scrapeErr) {
|
|
22941
|
+
const errMsg = scrapeErr instanceof Error ? scrapeErr.message : String(scrapeErr || "Unknown error");
|
|
22942
|
+
warn(`Documentation scrape failed for ${opts.scrapeUrl}: ${errMsg}`);
|
|
22763
22943
|
}
|
|
22764
22944
|
}
|
|
22765
22945
|
spin.stop();
|
|
@@ -22875,14 +23055,29 @@ function registerCallCommand(parent, getContext2) {
|
|
|
22875
23055
|
if (body && Object.keys(filePayloads).length > 0) {
|
|
22876
23056
|
try {
|
|
22877
23057
|
let parsed = JSON.parse(body);
|
|
22878
|
-
|
|
22879
|
-
if (typeof
|
|
22880
|
-
const key =
|
|
22881
|
-
if (key in filePayloads)
|
|
23058
|
+
const resolveFileRefs = (obj) => {
|
|
23059
|
+
if (typeof obj === "string" && obj.startsWith("file::")) {
|
|
23060
|
+
const key = obj.slice(6);
|
|
23061
|
+
if (key in filePayloads) return filePayloads[key];
|
|
23062
|
+
error(
|
|
23063
|
+
`Unresolved file reference: file::${key}. Available: ${Object.keys(filePayloads).join(", ") || "(none)"}`
|
|
23064
|
+
);
|
|
23065
|
+
process.exit(1);
|
|
22882
23066
|
}
|
|
22883
|
-
|
|
23067
|
+
if (Array.isArray(obj)) return obj.map(resolveFileRefs);
|
|
23068
|
+
if (obj && typeof obj === "object") {
|
|
23069
|
+
const result = {};
|
|
23070
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
23071
|
+
result[k] = resolveFileRefs(v);
|
|
23072
|
+
}
|
|
23073
|
+
return result;
|
|
23074
|
+
}
|
|
23075
|
+
return obj;
|
|
23076
|
+
};
|
|
23077
|
+
parsed = resolveFileRefs(parsed);
|
|
22884
23078
|
body = JSON.stringify(parsed);
|
|
22885
|
-
} catch {
|
|
23079
|
+
} catch (err) {
|
|
23080
|
+
if (err.message?.startsWith("Unresolved file reference")) throw err;
|
|
22886
23081
|
}
|
|
22887
23082
|
}
|
|
22888
23083
|
const autoExec = process.argv.includes("--yes") || process.argv.includes("-y") || shouldAutoExecute(config.policies.callSystem, method, opts.url);
|
|
@@ -22995,13 +23190,13 @@ function registerDocsCommand(parent, getContext2) {
|
|
|
22995
23190
|
}
|
|
22996
23191
|
|
|
22997
23192
|
// src/commands/system/oauth.ts
|
|
22998
|
-
var
|
|
23193
|
+
var import_node_child_process2 = require("child_process");
|
|
22999
23194
|
var import_shared8 = __toESM(require_dist2());
|
|
23000
23195
|
function openBrowser(url) {
|
|
23001
23196
|
const platform = process.platform;
|
|
23002
23197
|
const cmd = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
23003
23198
|
const args = platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
23004
|
-
(0,
|
|
23199
|
+
(0, import_node_child_process2.spawn)(cmd, args, { detached: true, stdio: "ignore" }).unref();
|
|
23005
23200
|
}
|
|
23006
23201
|
async function pollForTokens(client, systemId, originalToken, timeoutMs = 3e5, intervalMs = 2e3) {
|
|
23007
23202
|
const start = Date.now();
|
|
@@ -23100,10 +23295,21 @@ function registerOAuthCommand(parent, getContext2) {
|
|
|
23100
23295
|
process.exit(1);
|
|
23101
23296
|
}
|
|
23102
23297
|
const originalToken = system.credentials?.access_token;
|
|
23103
|
-
|
|
23298
|
+
let encryptionSecret;
|
|
23299
|
+
let orgId;
|
|
23300
|
+
try {
|
|
23301
|
+
const secretData = await client.getCliOAuthSecret();
|
|
23302
|
+
encryptionSecret = secretData.secret;
|
|
23303
|
+
orgId = secretData.orgId;
|
|
23304
|
+
} catch (err) {
|
|
23305
|
+
error(`Failed to get OAuth encryption secret: ${err.message}`);
|
|
23306
|
+
process.exit(1);
|
|
23307
|
+
}
|
|
23308
|
+
const encryptedApiKey = (0, import_shared8.encryptCliApiKey)(config.apiKey, opts.systemId, encryptionSecret);
|
|
23104
23309
|
const redirectUri = `${config.webEndpoint.replace(/\/$/, "")}/api/auth/callback`;
|
|
23105
23310
|
const state = {
|
|
23106
23311
|
systemId: opts.systemId,
|
|
23312
|
+
orgId,
|
|
23107
23313
|
timestamp: Date.now(),
|
|
23108
23314
|
redirectUri,
|
|
23109
23315
|
token_url: tokenUrl,
|
|
@@ -23150,12 +23356,12 @@ function registerSystemCommands(program2, getContext2) {
|
|
|
23150
23356
|
|
|
23151
23357
|
// src/commands/run/list.ts
|
|
23152
23358
|
function registerListCommand(parent, getContext2) {
|
|
23153
|
-
parent.command("list").description("List recent runs").option("--tool <id>", "Filter by tool ID").option("--status <status>", "Filter by status (running, success, failed, aborted)").option("--source <sources>", "Comma-separated request sources").option("--user <userId>", "Filter by user ID").option("--system-id <id>", "Filter by system ID").option("--limit <n>", "Max results", "10").option("--offset <n>", "Skip first N results", "0").
|
|
23359
|
+
parent.command("list").description("List recent runs").option("--tool <id>", "Filter by tool ID").option("--status <status>", "Filter by status (running, success, failed, aborted)").option("--source <sources>", "Comma-separated request sources").option("--user <userId>", "Filter by user ID").option("--system-id <id>", "Filter by system ID").option("--limit <n>", "Max results", "10").option("--offset <n>", "Skip first N results", "0").action(async (opts) => {
|
|
23154
23360
|
const { client } = getContext2();
|
|
23155
23361
|
try {
|
|
23156
23362
|
const limit = Math.min(parseInt(opts.limit, 10) || 10, 50);
|
|
23157
23363
|
const offset = parseInt(opts.offset, 10) || 0;
|
|
23158
|
-
const page = Math.
|
|
23364
|
+
const page = Math.ceil((offset + 1) / limit);
|
|
23159
23365
|
const requestSources = opts.source?.split(",").filter(Boolean);
|
|
23160
23366
|
const result = await client.listRuns({
|
|
23161
23367
|
toolId: opts.tool,
|
|
@@ -23238,74 +23444,6 @@ function registerRunCommands(program2, getContext2) {
|
|
|
23238
23444
|
registerGetCommand(run, getContext2);
|
|
23239
23445
|
}
|
|
23240
23446
|
|
|
23241
|
-
// src/version.ts
|
|
23242
|
-
var import_node_child_process2 = require("child_process");
|
|
23243
|
-
var import_node_util = require("util");
|
|
23244
|
-
var execAsync = (0, import_node_util.promisify)(import_node_child_process2.exec);
|
|
23245
|
-
var CLI_VERSION = "0.1.0";
|
|
23246
|
-
function compareVersions(a, b) {
|
|
23247
|
-
const partsA = a.split(".").map(Number);
|
|
23248
|
-
const partsB = b.split(".").map(Number);
|
|
23249
|
-
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
|
|
23250
|
-
const numA = partsA[i] || 0;
|
|
23251
|
-
const numB = partsB[i] || 0;
|
|
23252
|
-
if (numA < numB) return -1;
|
|
23253
|
-
if (numA > numB) return 1;
|
|
23254
|
-
}
|
|
23255
|
-
return 0;
|
|
23256
|
-
}
|
|
23257
|
-
async function checkVersionCompatibility(endpoint) {
|
|
23258
|
-
try {
|
|
23259
|
-
const healthUrl = `${endpoint.replace(/\/$/, "")}/v1/health`;
|
|
23260
|
-
const response = await fetch(healthUrl, { signal: AbortSignal.timeout(3e3) });
|
|
23261
|
-
if (!response.ok) return;
|
|
23262
|
-
const health = await response.json();
|
|
23263
|
-
if (!health.minCliVersion) return;
|
|
23264
|
-
if (compareVersions(CLI_VERSION, health.minCliVersion) < 0) {
|
|
23265
|
-
console.error("");
|
|
23266
|
-
console.error(`${c.yellow}${c.bold}\u26A0 CLI version ${CLI_VERSION} is outdated.${c.reset}`);
|
|
23267
|
-
console.error(
|
|
23268
|
-
`${c.yellow} Server requires at least v${health.minCliVersion}. Run: ${c.bold}sg update${c.reset}`
|
|
23269
|
-
);
|
|
23270
|
-
console.error("");
|
|
23271
|
-
}
|
|
23272
|
-
} catch {
|
|
23273
|
-
}
|
|
23274
|
-
}
|
|
23275
|
-
async function getLatestNpmVersion() {
|
|
23276
|
-
try {
|
|
23277
|
-
const response = await fetch("https://registry.npmjs.org/@superglue/cli/latest", {
|
|
23278
|
-
signal: AbortSignal.timeout(5e3)
|
|
23279
|
-
});
|
|
23280
|
-
if (!response.ok) return null;
|
|
23281
|
-
const data = await response.json();
|
|
23282
|
-
return data.version || null;
|
|
23283
|
-
} catch {
|
|
23284
|
-
return null;
|
|
23285
|
-
}
|
|
23286
|
-
}
|
|
23287
|
-
async function updateCli() {
|
|
23288
|
-
const latestVersion = await getLatestNpmVersion();
|
|
23289
|
-
if (!latestVersion) {
|
|
23290
|
-
return { success: false, message: "Could not fetch latest version from npm" };
|
|
23291
|
-
}
|
|
23292
|
-
if (compareVersions(CLI_VERSION, latestVersion) >= 0) {
|
|
23293
|
-
return { success: true, message: `Already on latest version (${CLI_VERSION})` };
|
|
23294
|
-
}
|
|
23295
|
-
try {
|
|
23296
|
-
await execAsync("npm install -g @superglue/cli@latest");
|
|
23297
|
-
return {
|
|
23298
|
-
success: true,
|
|
23299
|
-
message: `Updated from ${CLI_VERSION} to ${latestVersion}`
|
|
23300
|
-
};
|
|
23301
|
-
} catch (err) {
|
|
23302
|
-
return {
|
|
23303
|
-
success: false,
|
|
23304
|
-
message: `Update failed: ${err.message}. Try manually: npm install -g @superglue/cli@latest`
|
|
23305
|
-
};
|
|
23306
|
-
}
|
|
23307
|
-
}
|
|
23308
|
-
|
|
23309
23447
|
// src/commands/update.ts
|
|
23310
23448
|
function registerUpdateCommand(program2) {
|
|
23311
23449
|
program2.command("update").description("Update the superglue CLI to the latest version").option("--check", "Only check for updates, don't install").action(async (opts) => {
|
|
@@ -23317,7 +23455,8 @@ function registerUpdateCommand(program2) {
|
|
|
23317
23455
|
error("Could not fetch latest version from npm");
|
|
23318
23456
|
process.exit(1);
|
|
23319
23457
|
}
|
|
23320
|
-
|
|
23458
|
+
const comparison = compareVersions(CLI_VERSION, latestVersion);
|
|
23459
|
+
if (comparison >= 0) {
|
|
23321
23460
|
success(`You're on the latest version (${CLI_VERSION})`);
|
|
23322
23461
|
} else {
|
|
23323
23462
|
console.log("");
|
|
@@ -23395,10 +23534,41 @@ registerToolCommands(program, getContext);
|
|
|
23395
23534
|
registerSystemCommands(program, getContext);
|
|
23396
23535
|
registerRunCommands(program, getContext);
|
|
23397
23536
|
var commandsRequiringServer = ["tool", "system", "run"];
|
|
23398
|
-
var
|
|
23399
|
-
|
|
23400
|
-
|
|
23401
|
-
|
|
23537
|
+
var globalFlagsWithValues = ["--api-key", "--endpoint"];
|
|
23538
|
+
var globalFlagsNoValue = ["--json", "-y", "--yes", "-h", "--help", "-V", "--version"];
|
|
23539
|
+
function findSubcommand(argv) {
|
|
23540
|
+
let i = 2;
|
|
23541
|
+
while (i < argv.length) {
|
|
23542
|
+
const arg = argv[i];
|
|
23543
|
+
if (globalFlagsWithValues.includes(arg)) {
|
|
23544
|
+
i += 2;
|
|
23545
|
+
} else if (globalFlagsNoValue.includes(arg)) {
|
|
23546
|
+
i += 1;
|
|
23547
|
+
} else if (arg.startsWith("-")) {
|
|
23548
|
+
i += 1;
|
|
23549
|
+
} else {
|
|
23550
|
+
return arg;
|
|
23551
|
+
}
|
|
23552
|
+
}
|
|
23553
|
+
return void 0;
|
|
23554
|
+
}
|
|
23555
|
+
function extractFlagValue(argv, flag) {
|
|
23556
|
+
for (let i = 0; i < argv.length; i++) {
|
|
23557
|
+
const arg = argv[i];
|
|
23558
|
+
if (arg.startsWith(`${flag}=`)) {
|
|
23559
|
+
return arg.slice(flag.length + 1);
|
|
23560
|
+
}
|
|
23561
|
+
if (arg === flag && i + 1 < argv.length) {
|
|
23562
|
+
return argv[i + 1];
|
|
23563
|
+
}
|
|
23564
|
+
}
|
|
23565
|
+
return void 0;
|
|
23566
|
+
}
|
|
23567
|
+
var subcommand = findSubcommand(process.argv);
|
|
23568
|
+
if (subcommand && commandsRequiringServer.includes(subcommand)) {
|
|
23569
|
+
const cliApiKey = extractFlagValue(process.argv, "--api-key");
|
|
23570
|
+
const cliEndpoint = extractFlagValue(process.argv, "--endpoint");
|
|
23571
|
+
const config = resolveConfig({ apiKey: cliApiKey, endpoint: cliEndpoint });
|
|
23402
23572
|
if (config.apiKey) {
|
|
23403
23573
|
checkVersionCompatibility(config.endpoint).then(() => program.parse());
|
|
23404
23574
|
} else {
|
|
@@ -227,14 +227,14 @@ sg system oauth --system-id my_api --grant-type client_credentials --scopes "rea
|
|
|
227
227
|
{
|
|
228
228
|
"id": "unique-step-id",
|
|
229
229
|
"config": {
|
|
230
|
-
"systemId": "
|
|
231
|
-
"url": "https://api.example.com/endpoint?param=<<
|
|
230
|
+
"systemId": "example_system",
|
|
231
|
+
"url": "https://api.example.com/endpoint?param=<<payload_field>>",
|
|
232
232
|
"method": "GET",
|
|
233
233
|
"headers": {
|
|
234
|
-
"Authorization": "Bearer <<
|
|
234
|
+
"Authorization": "Bearer <<example_system_access_token>>"
|
|
235
235
|
},
|
|
236
236
|
"queryParams": { "limit": "10" },
|
|
237
|
-
"body": "{ \"key\": \"<<
|
|
237
|
+
"body": "{ \"key\": \"<<payload_field>>\" }"
|
|
238
238
|
},
|
|
239
239
|
"dataSelector": "(sourceData) => sourceData.previousStep.data.items",
|
|
240
240
|
"transformCode": "(items) => items.map(i => ({ id: i.id, name: i.name }))",
|
|
@@ -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
|
|
12
|
+
export SUPERGLUE_API_ENDPOINT="https://api.superglue.cloud"
|
|
13
13
|
|
|
14
14
|
# Run a tool (sync - waits for completion)
|
|
15
|
-
curl -X POST "$
|
|
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 "$
|
|
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 "$
|
|
27
|
+
curl "$SUPERGLUE_API_ENDPOINT/v1/runs/{runId}" \
|
|
28
28
|
-H "Authorization: Bearer $SUPERGLUE_API_KEY"
|
|
29
29
|
|
|
30
30
|
# List tools
|
|
31
|
-
curl "$
|
|
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 "$
|
|
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 "$
|
|
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
|
|
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": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"bin": {
|
|
5
5
|
"sg": "./dist/cli.js"
|
|
6
6
|
},
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"typescript": "^5.0.0"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
|
-
"build": "tsup && cp -r skills dist/ 2>/dev/null || true",
|
|
23
|
+
"build": "tsup && (cp -r skills dist/ 2>/dev/null || true)",
|
|
24
24
|
"dev": "tsup --watch",
|
|
25
25
|
"type-check": "tsc --noEmit",
|
|
26
26
|
"prepublishOnly": "npm run build"
|
|
@@ -227,14 +227,14 @@ sg system oauth --system-id my_api --grant-type client_credentials --scopes "rea
|
|
|
227
227
|
{
|
|
228
228
|
"id": "unique-step-id",
|
|
229
229
|
"config": {
|
|
230
|
-
"systemId": "
|
|
231
|
-
"url": "https://api.example.com/endpoint?param=<<
|
|
230
|
+
"systemId": "example_system",
|
|
231
|
+
"url": "https://api.example.com/endpoint?param=<<payload_field>>",
|
|
232
232
|
"method": "GET",
|
|
233
233
|
"headers": {
|
|
234
|
-
"Authorization": "Bearer <<
|
|
234
|
+
"Authorization": "Bearer <<example_system_access_token>>"
|
|
235
235
|
},
|
|
236
236
|
"queryParams": { "limit": "10" },
|
|
237
|
-
"body": "{ \"key\": \"<<
|
|
237
|
+
"body": "{ \"key\": \"<<payload_field>>\" }"
|
|
238
238
|
},
|
|
239
239
|
"dataSelector": "(sourceData) => sourceData.previousStep.data.items",
|
|
240
240
|
"transformCode": "(items) => items.map(i => ({ id: i.id, name: i.name }))",
|
|
@@ -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
|
|
12
|
+
export SUPERGLUE_API_ENDPOINT="https://api.superglue.cloud"
|
|
13
13
|
|
|
14
14
|
# Run a tool (sync - waits for completion)
|
|
15
|
-
curl -X POST "$
|
|
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 "$
|
|
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 "$
|
|
27
|
+
curl "$SUPERGLUE_API_ENDPOINT/v1/runs/{runId}" \
|
|
28
28
|
-H "Authorization: Bearer $SUPERGLUE_API_KEY"
|
|
29
29
|
|
|
30
30
|
# List tools
|
|
31
|
-
curl "$
|
|
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 "$
|
|
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 "$
|
|
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
|
|
265
|
+
SUPERGLUE_API_ENDPOINT=https://api.superglue.cloud
|
|
265
266
|
```
|
|
266
267
|
|
|
267
268
|
## Best Practices
|