@hasna/connectors 0.3.1 → 0.3.2
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/bin/index.js +229 -59
- package/bin/mcp.js +214 -71
- package/bin/serve.js +0 -16
- package/connectors/connect-aws/package.json +4 -1
- package/connectors/connect-aws/src/api/awsses.ts +311 -0
- package/connectors/connect-aws/src/api/client.ts +1 -0
- package/connectors/connect-aws/src/api/index.ts +5 -1
- package/connectors/connect-aws/src/index.ts +1 -1
- package/connectors/connect-aws/src/types/index.ts +91 -0
- package/dashboard/dist/assets/index-CSlS3oNV.css +1 -0
- package/dashboard/dist/assets/index-sSIkMXYs.js +284 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +121 -0
- package/dist/lib/runner.d.ts +44 -0
- package/dist/lib/runner.test.d.ts +1 -0
- package/package.json +3 -1
- package/dashboard/dist/assets/index-DmR_QNtT.css +0 -1
- package/dashboard/dist/assets/index-Dp-apHbC.js +0 -284
package/bin/index.js
CHANGED
|
@@ -4519,9 +4519,9 @@ var exports_serve = {};
|
|
|
4519
4519
|
__export(exports_serve, {
|
|
4520
4520
|
startServer: () => startServer
|
|
4521
4521
|
});
|
|
4522
|
-
import { existsSync as
|
|
4523
|
-
import { join as
|
|
4524
|
-
import { fileURLToPath as
|
|
4522
|
+
import { existsSync as existsSync5, readdirSync as readdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
4523
|
+
import { join as join5, dirname as dirname4, extname, basename } from "path";
|
|
4524
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
4525
4525
|
import { homedir as homedir2 } from "os";
|
|
4526
4526
|
function logActivity(action, connector, detail) {
|
|
4527
4527
|
activityLog.unshift({ action, connector, timestamp: Date.now(), detail });
|
|
@@ -4532,21 +4532,21 @@ function logActivity(action, connector, detail) {
|
|
|
4532
4532
|
function resolveDashboardDir() {
|
|
4533
4533
|
const candidates = [];
|
|
4534
4534
|
try {
|
|
4535
|
-
const scriptDir =
|
|
4536
|
-
candidates.push(
|
|
4537
|
-
candidates.push(
|
|
4535
|
+
const scriptDir = dirname4(fileURLToPath4(import.meta.url));
|
|
4536
|
+
candidates.push(join5(scriptDir, "..", "dashboard", "dist"));
|
|
4537
|
+
candidates.push(join5(scriptDir, "..", "..", "dashboard", "dist"));
|
|
4538
4538
|
} catch {}
|
|
4539
4539
|
if (process.argv[1]) {
|
|
4540
|
-
const mainDir =
|
|
4541
|
-
candidates.push(
|
|
4542
|
-
candidates.push(
|
|
4540
|
+
const mainDir = dirname4(process.argv[1]);
|
|
4541
|
+
candidates.push(join5(mainDir, "..", "dashboard", "dist"));
|
|
4542
|
+
candidates.push(join5(mainDir, "..", "..", "dashboard", "dist"));
|
|
4543
4543
|
}
|
|
4544
|
-
candidates.push(
|
|
4544
|
+
candidates.push(join5(process.cwd(), "dashboard", "dist"));
|
|
4545
4545
|
for (const candidate of candidates) {
|
|
4546
|
-
if (
|
|
4546
|
+
if (existsSync5(candidate))
|
|
4547
4547
|
return candidate;
|
|
4548
4548
|
}
|
|
4549
|
-
return
|
|
4549
|
+
return join5(process.cwd(), "dashboard", "dist");
|
|
4550
4550
|
}
|
|
4551
4551
|
function json(data, status = 200, port) {
|
|
4552
4552
|
return new Response(JSON.stringify(data), {
|
|
@@ -4594,7 +4594,7 @@ function errorPage(title, message, hint) {
|
|
|
4594
4594
|
</body></html>`;
|
|
4595
4595
|
}
|
|
4596
4596
|
function serveStaticFile(filePath) {
|
|
4597
|
-
if (!
|
|
4597
|
+
if (!existsSync5(filePath))
|
|
4598
4598
|
return null;
|
|
4599
4599
|
const ext = extname(filePath);
|
|
4600
4600
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -4618,7 +4618,7 @@ async function startServer(requestedPort, options) {
|
|
|
4618
4618
|
const shouldOpen = options?.open ?? true;
|
|
4619
4619
|
loadConnectorVersions();
|
|
4620
4620
|
const dashboardDir = resolveDashboardDir();
|
|
4621
|
-
const dashboardExists =
|
|
4621
|
+
const dashboardExists = existsSync5(dashboardDir);
|
|
4622
4622
|
if (!dashboardExists) {
|
|
4623
4623
|
console.error(`
|
|
4624
4624
|
Dashboard not found at: ${dashboardDir}`);
|
|
@@ -4774,10 +4774,10 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
4774
4774
|
return json({ error: "Invalid connector name" }, 400, port);
|
|
4775
4775
|
try {
|
|
4776
4776
|
const profiles = listProfiles(name);
|
|
4777
|
-
const configDir =
|
|
4778
|
-
const currentProfileFile =
|
|
4777
|
+
const configDir = join5(homedir2(), ".connectors", name.startsWith("connect-") ? name : `connect-${name}`);
|
|
4778
|
+
const currentProfileFile = join5(configDir, "current_profile");
|
|
4779
4779
|
let current = "default";
|
|
4780
|
-
if (
|
|
4780
|
+
if (existsSync5(currentProfileFile)) {
|
|
4781
4781
|
try {
|
|
4782
4782
|
current = readFileSync4(currentProfileFile, "utf-8").trim() || "default";
|
|
4783
4783
|
} catch {}
|
|
@@ -4826,16 +4826,16 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
4826
4826
|
}
|
|
4827
4827
|
if (path === "/api/export" && method === "GET") {
|
|
4828
4828
|
try {
|
|
4829
|
-
const connectDir =
|
|
4829
|
+
const connectDir = join5(homedir2(), ".connectors");
|
|
4830
4830
|
const result = {};
|
|
4831
|
-
if (
|
|
4831
|
+
if (existsSync5(connectDir)) {
|
|
4832
4832
|
const entries = readdirSync3(connectDir, { withFileTypes: true });
|
|
4833
4833
|
for (const entry of entries) {
|
|
4834
4834
|
if (!entry.isDirectory() || !entry.name.startsWith("connect-"))
|
|
4835
4835
|
continue;
|
|
4836
4836
|
const connectorName = entry.name.replace(/^connect-/, "");
|
|
4837
|
-
const profilesDir =
|
|
4838
|
-
if (!
|
|
4837
|
+
const profilesDir = join5(connectDir, entry.name, "profiles");
|
|
4838
|
+
if (!existsSync5(profilesDir))
|
|
4839
4839
|
continue;
|
|
4840
4840
|
const profiles = {};
|
|
4841
4841
|
const profileEntries = readdirSync3(profilesDir, { withFileTypes: true });
|
|
@@ -4843,13 +4843,13 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
4843
4843
|
if (pEntry.isFile() && pEntry.name.endsWith(".json")) {
|
|
4844
4844
|
const profileName = basename(pEntry.name, ".json");
|
|
4845
4845
|
try {
|
|
4846
|
-
const config = JSON.parse(readFileSync4(
|
|
4846
|
+
const config = JSON.parse(readFileSync4(join5(profilesDir, pEntry.name), "utf-8"));
|
|
4847
4847
|
profiles[profileName] = config;
|
|
4848
4848
|
} catch {}
|
|
4849
4849
|
}
|
|
4850
4850
|
if (pEntry.isDirectory()) {
|
|
4851
|
-
const configPath =
|
|
4852
|
-
if (
|
|
4851
|
+
const configPath = join5(profilesDir, pEntry.name, "config.json");
|
|
4852
|
+
if (existsSync5(configPath)) {
|
|
4853
4853
|
try {
|
|
4854
4854
|
const config = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
4855
4855
|
profiles[pEntry.name] = config;
|
|
@@ -4886,19 +4886,19 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
4886
4886
|
return json({ error: "Invalid import format: missing 'connectors' object" }, 400, port);
|
|
4887
4887
|
}
|
|
4888
4888
|
let imported = 0;
|
|
4889
|
-
const connectDir =
|
|
4889
|
+
const connectDir = join5(homedir2(), ".connectors");
|
|
4890
4890
|
for (const [connectorName, data] of Object.entries(body.connectors)) {
|
|
4891
4891
|
if (!isValidConnectorName(connectorName))
|
|
4892
4892
|
continue;
|
|
4893
4893
|
if (!data.profiles || typeof data.profiles !== "object")
|
|
4894
4894
|
continue;
|
|
4895
|
-
const connectorDir =
|
|
4896
|
-
const profilesDir =
|
|
4895
|
+
const connectorDir = join5(connectDir, `connect-${connectorName}`);
|
|
4896
|
+
const profilesDir = join5(connectorDir, "profiles");
|
|
4897
4897
|
for (const [profileName, config] of Object.entries(data.profiles)) {
|
|
4898
4898
|
if (!config || typeof config !== "object")
|
|
4899
4899
|
continue;
|
|
4900
4900
|
mkdirSync3(profilesDir, { recursive: true });
|
|
4901
|
-
const profileFile =
|
|
4901
|
+
const profileFile = join5(profilesDir, `${profileName}.json`);
|
|
4902
4902
|
writeFileSync3(profileFile, JSON.stringify(config, null, 2));
|
|
4903
4903
|
imported++;
|
|
4904
4904
|
}
|
|
@@ -4965,12 +4965,12 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
4965
4965
|
}
|
|
4966
4966
|
if (dashboardExists && (method === "GET" || method === "HEAD")) {
|
|
4967
4967
|
if (path !== "/") {
|
|
4968
|
-
const filePath =
|
|
4968
|
+
const filePath = join5(dashboardDir, path);
|
|
4969
4969
|
const res2 = serveStaticFile(filePath);
|
|
4970
4970
|
if (res2)
|
|
4971
4971
|
return res2;
|
|
4972
4972
|
}
|
|
4973
|
-
const indexPath =
|
|
4973
|
+
const indexPath = join5(dashboardDir, "index.html");
|
|
4974
4974
|
const res = serveStaticFile(indexPath);
|
|
4975
4975
|
if (res)
|
|
4976
4976
|
return res;
|
|
@@ -6513,9 +6513,9 @@ function App({ initialConnectors, overwrite = false }) {
|
|
|
6513
6513
|
init_registry();
|
|
6514
6514
|
init_installer();
|
|
6515
6515
|
init_auth();
|
|
6516
|
-
import { readdirSync as readdirSync4, existsSync as
|
|
6516
|
+
import { readdirSync as readdirSync4, existsSync as existsSync6, statSync as statSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "fs";
|
|
6517
6517
|
import { homedir as homedir3 } from "os";
|
|
6518
|
-
import { join as
|
|
6518
|
+
import { join as join6, relative } from "path";
|
|
6519
6519
|
|
|
6520
6520
|
// src/lib/test-endpoints.ts
|
|
6521
6521
|
var TEST_ENDPOINTS = {
|
|
@@ -6588,6 +6588,107 @@ var TEST_ENDPOINTS = {
|
|
|
6588
6588
|
|
|
6589
6589
|
// src/cli/index.tsx
|
|
6590
6590
|
import { createInterface } from "readline";
|
|
6591
|
+
|
|
6592
|
+
// src/lib/runner.ts
|
|
6593
|
+
import { existsSync as existsSync4 } from "fs";
|
|
6594
|
+
import { join as join4, dirname as dirname3 } from "path";
|
|
6595
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6596
|
+
import { spawn } from "child_process";
|
|
6597
|
+
var __dirname3 = dirname3(fileURLToPath3(import.meta.url));
|
|
6598
|
+
function resolveConnectorsDir2() {
|
|
6599
|
+
const fromBin = join4(__dirname3, "..", "connectors");
|
|
6600
|
+
if (existsSync4(fromBin))
|
|
6601
|
+
return fromBin;
|
|
6602
|
+
const fromSrc = join4(__dirname3, "..", "..", "connectors");
|
|
6603
|
+
if (existsSync4(fromSrc))
|
|
6604
|
+
return fromSrc;
|
|
6605
|
+
return fromBin;
|
|
6606
|
+
}
|
|
6607
|
+
var CONNECTORS_DIR2 = resolveConnectorsDir2();
|
|
6608
|
+
function getConnectorCliPath(name) {
|
|
6609
|
+
const safeName = name.replace(/[^a-z0-9-]/g, "");
|
|
6610
|
+
const connectorDir = join4(CONNECTORS_DIR2, `connect-${safeName}`);
|
|
6611
|
+
const cliPath = join4(connectorDir, "src", "cli", "index.ts");
|
|
6612
|
+
if (existsSync4(cliPath))
|
|
6613
|
+
return cliPath;
|
|
6614
|
+
return null;
|
|
6615
|
+
}
|
|
6616
|
+
function runConnectorCommand(name, args, timeoutMs = 30000) {
|
|
6617
|
+
const cliPath = getConnectorCliPath(name);
|
|
6618
|
+
if (!cliPath) {
|
|
6619
|
+
return Promise.resolve({
|
|
6620
|
+
stdout: "",
|
|
6621
|
+
stderr: `Connector '${name}' not found or has no CLI.`,
|
|
6622
|
+
exitCode: 1,
|
|
6623
|
+
success: false
|
|
6624
|
+
});
|
|
6625
|
+
}
|
|
6626
|
+
return new Promise((resolve) => {
|
|
6627
|
+
const proc = spawn("bun", ["run", cliPath, ...args], {
|
|
6628
|
+
timeout: timeoutMs,
|
|
6629
|
+
env: { ...process.env },
|
|
6630
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
6631
|
+
});
|
|
6632
|
+
let stdout = "";
|
|
6633
|
+
let stderr = "";
|
|
6634
|
+
proc.stdout.on("data", (data) => {
|
|
6635
|
+
stdout += data.toString();
|
|
6636
|
+
});
|
|
6637
|
+
proc.stderr.on("data", (data) => {
|
|
6638
|
+
stderr += data.toString();
|
|
6639
|
+
});
|
|
6640
|
+
proc.on("close", (code) => {
|
|
6641
|
+
resolve({
|
|
6642
|
+
stdout: stdout.trim(),
|
|
6643
|
+
stderr: stderr.trim(),
|
|
6644
|
+
exitCode: code ?? 1,
|
|
6645
|
+
success: code === 0
|
|
6646
|
+
});
|
|
6647
|
+
});
|
|
6648
|
+
proc.on("error", (err) => {
|
|
6649
|
+
resolve({
|
|
6650
|
+
stdout: "",
|
|
6651
|
+
stderr: err.message,
|
|
6652
|
+
exitCode: 1,
|
|
6653
|
+
success: false
|
|
6654
|
+
});
|
|
6655
|
+
});
|
|
6656
|
+
});
|
|
6657
|
+
}
|
|
6658
|
+
async function getConnectorOperations(name) {
|
|
6659
|
+
const cliPath = getConnectorCliPath(name);
|
|
6660
|
+
if (!cliPath) {
|
|
6661
|
+
return { commands: [], helpText: "", hasCli: false };
|
|
6662
|
+
}
|
|
6663
|
+
const result = await runConnectorCommand(name, ["--help"]);
|
|
6664
|
+
const helpText = result.stdout || result.stderr;
|
|
6665
|
+
const commands = [];
|
|
6666
|
+
const lines = helpText.split(`
|
|
6667
|
+
`);
|
|
6668
|
+
let inCommands = false;
|
|
6669
|
+
for (const line of lines) {
|
|
6670
|
+
if (line.trim().startsWith("Commands:")) {
|
|
6671
|
+
inCommands = true;
|
|
6672
|
+
continue;
|
|
6673
|
+
}
|
|
6674
|
+
if (inCommands) {
|
|
6675
|
+
const match = line.match(/^\s{2,}(\S+)/);
|
|
6676
|
+
if (match && match[1] !== "help") {
|
|
6677
|
+
commands.push(match[1]);
|
|
6678
|
+
}
|
|
6679
|
+
if (line.trim() === "" && commands.length > 0) {
|
|
6680
|
+
inCommands = false;
|
|
6681
|
+
}
|
|
6682
|
+
}
|
|
6683
|
+
}
|
|
6684
|
+
return { commands, helpText, hasCli: true };
|
|
6685
|
+
}
|
|
6686
|
+
async function getConnectorCommandHelp(name, command) {
|
|
6687
|
+
const result = await runConnectorCommand(name, [command, "--help"]);
|
|
6688
|
+
return result.stdout || result.stderr;
|
|
6689
|
+
}
|
|
6690
|
+
|
|
6691
|
+
// src/cli/index.tsx
|
|
6591
6692
|
import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
|
|
6592
6693
|
loadConnectorVersions();
|
|
6593
6694
|
var isTTY = process.stdout.isTTY ?? false;
|
|
@@ -6600,7 +6701,7 @@ var PRESETS = {
|
|
|
6600
6701
|
commerce: { description: "Commerce and finance", connectors: ["stripe", "shopify", "revolut", "mercury", "pandadoc"] }
|
|
6601
6702
|
};
|
|
6602
6703
|
var program2 = new Command;
|
|
6603
|
-
program2.name("connectors").description("Install API connectors for your project").version("0.3.
|
|
6704
|
+
program2.name("connectors").description("Install API connectors for your project").version("0.3.2");
|
|
6604
6705
|
program2.command("interactive", { isDefault: true }).alias("i").description("Interactive connector browser").action(() => {
|
|
6605
6706
|
if (!isTTY) {
|
|
6606
6707
|
console.log(`Non-interactive environment detected. Use a subcommand:
|
|
@@ -6621,7 +6722,7 @@ Run 'connectors --help' for full usage.`);
|
|
|
6621
6722
|
function listFilesRecursive(dir, base = dir) {
|
|
6622
6723
|
const files = [];
|
|
6623
6724
|
for (const entry of readdirSync4(dir)) {
|
|
6624
|
-
const fullPath =
|
|
6725
|
+
const fullPath = join6(dir, entry);
|
|
6625
6726
|
if (statSync3(fullPath).isDirectory()) {
|
|
6626
6727
|
files.push(...listFilesRecursive(fullPath, base));
|
|
6627
6728
|
} else {
|
|
@@ -6670,7 +6771,7 @@ program2.command("install").alias("add").argument("[connectors...]", "Connectors
|
|
|
6670
6771
|
}
|
|
6671
6772
|
if (options.dryRun) {
|
|
6672
6773
|
const installed = getInstalledConnectors();
|
|
6673
|
-
const destDir =
|
|
6774
|
+
const destDir = join6(process.cwd(), ".connectors");
|
|
6674
6775
|
const actions = [];
|
|
6675
6776
|
for (const name of connectors) {
|
|
6676
6777
|
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
@@ -6688,7 +6789,7 @@ program2.command("install").alias("add").argument("[connectors...]", "Connectors
|
|
|
6688
6789
|
}
|
|
6689
6790
|
const connectorDirName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
6690
6791
|
const sourcePath = getConnectorPath(name);
|
|
6691
|
-
const destPath =
|
|
6792
|
+
const destPath = join6(destDir, connectorDirName);
|
|
6692
6793
|
const alreadyInstalled = installed.includes(name);
|
|
6693
6794
|
const files = listFilesRecursive(sourcePath);
|
|
6694
6795
|
const importLine = `export * as ${name} from './${connectorDirName}/src/index.js';`;
|
|
@@ -7661,27 +7762,27 @@ Next steps:
|
|
|
7661
7762
|
process.exit(results.every((r) => r.success) ? 0 : 1);
|
|
7662
7763
|
});
|
|
7663
7764
|
program2.command("export").option("-o, --output <file>", "Write to file instead of stdout").description("Export all connector credentials as JSON backup").action((options) => {
|
|
7664
|
-
const connectDir =
|
|
7765
|
+
const connectDir = join6(homedir3(), ".connectors");
|
|
7665
7766
|
const result = {};
|
|
7666
|
-
if (
|
|
7767
|
+
if (existsSync6(connectDir)) {
|
|
7667
7768
|
for (const entry of readdirSync4(connectDir)) {
|
|
7668
|
-
const entryPath =
|
|
7769
|
+
const entryPath = join6(connectDir, entry);
|
|
7669
7770
|
if (!statSync3(entryPath).isDirectory() || !entry.startsWith("connect-"))
|
|
7670
7771
|
continue;
|
|
7671
7772
|
const connectorName = entry.replace(/^connect-/, "");
|
|
7672
|
-
const profilesDir =
|
|
7673
|
-
if (!
|
|
7773
|
+
const profilesDir = join6(entryPath, "profiles");
|
|
7774
|
+
if (!existsSync6(profilesDir))
|
|
7674
7775
|
continue;
|
|
7675
7776
|
const profiles = {};
|
|
7676
7777
|
for (const pEntry of readdirSync4(profilesDir)) {
|
|
7677
|
-
const pPath =
|
|
7778
|
+
const pPath = join6(profilesDir, pEntry);
|
|
7678
7779
|
if (statSync3(pPath).isFile() && pEntry.endsWith(".json")) {
|
|
7679
7780
|
try {
|
|
7680
7781
|
profiles[pEntry.replace(/\.json$/, "")] = JSON.parse(readFileSync5(pPath, "utf-8"));
|
|
7681
7782
|
} catch {}
|
|
7682
7783
|
} else if (statSync3(pPath).isDirectory()) {
|
|
7683
|
-
const configPath =
|
|
7684
|
-
if (
|
|
7784
|
+
const configPath = join6(pPath, "config.json");
|
|
7785
|
+
if (existsSync6(configPath)) {
|
|
7685
7786
|
try {
|
|
7686
7787
|
profiles[pEntry] = JSON.parse(readFileSync5(configPath, "utf-8"));
|
|
7687
7788
|
} catch {}
|
|
@@ -7708,7 +7809,7 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
7708
7809
|
chunks.push(chunk.toString());
|
|
7709
7810
|
raw = chunks.join("");
|
|
7710
7811
|
} else {
|
|
7711
|
-
if (!
|
|
7812
|
+
if (!existsSync6(file)) {
|
|
7712
7813
|
if (options.json) {
|
|
7713
7814
|
console.log(JSON.stringify({ error: `File not found: ${file}` }));
|
|
7714
7815
|
} else {
|
|
@@ -7740,19 +7841,19 @@ program2.command("import").argument("<file>", "JSON backup file to import (use -
|
|
|
7740
7841
|
process.exit(1);
|
|
7741
7842
|
return;
|
|
7742
7843
|
}
|
|
7743
|
-
const connectDir =
|
|
7844
|
+
const connectDir = join6(homedir3(), ".connectors");
|
|
7744
7845
|
let imported = 0;
|
|
7745
7846
|
for (const [connectorName, connData] of Object.entries(data.connectors)) {
|
|
7746
7847
|
if (!/^[a-z0-9-]+$/.test(connectorName))
|
|
7747
7848
|
continue;
|
|
7748
7849
|
if (!connData.profiles || typeof connData.profiles !== "object")
|
|
7749
7850
|
continue;
|
|
7750
|
-
const profilesDir =
|
|
7851
|
+
const profilesDir = join6(connectDir, `connect-${connectorName}`, "profiles");
|
|
7751
7852
|
for (const [profileName, config] of Object.entries(connData.profiles)) {
|
|
7752
7853
|
if (!config || typeof config !== "object")
|
|
7753
7854
|
continue;
|
|
7754
7855
|
mkdirSync4(profilesDir, { recursive: true });
|
|
7755
|
-
writeFileSync4(
|
|
7856
|
+
writeFileSync4(join6(profilesDir, `${profileName}.json`), JSON.stringify(config, null, 2));
|
|
7756
7857
|
imported++;
|
|
7757
7858
|
}
|
|
7758
7859
|
}
|
|
@@ -7977,7 +8078,7 @@ Available presets:
|
|
|
7977
8078
|
`));
|
|
7978
8079
|
});
|
|
7979
8080
|
program2.command("whoami").option("--json", "Output as JSON", false).description("Show current setup: config dir, installed connectors, auth status").action((options) => {
|
|
7980
|
-
const configDir =
|
|
8081
|
+
const configDir = join6(homedir3(), ".connectors");
|
|
7981
8082
|
const installed = getInstalledConnectors();
|
|
7982
8083
|
const version = "0.3.1";
|
|
7983
8084
|
let configured = 0;
|
|
@@ -7989,10 +8090,10 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
7989
8090
|
configured++;
|
|
7990
8091
|
else
|
|
7991
8092
|
unconfigured++;
|
|
7992
|
-
const connectorConfigDir =
|
|
7993
|
-
const currentProfileFile =
|
|
8093
|
+
const connectorConfigDir = join6(configDir, name.startsWith("connect-") ? name : `connect-${name}`);
|
|
8094
|
+
const currentProfileFile = join6(connectorConfigDir, "current_profile");
|
|
7994
8095
|
let profile = "default";
|
|
7995
|
-
if (
|
|
8096
|
+
if (existsSync6(currentProfileFile)) {
|
|
7996
8097
|
try {
|
|
7997
8098
|
profile = readFileSync5(currentProfileFile, "utf-8").trim() || "default";
|
|
7998
8099
|
} catch {}
|
|
@@ -8003,7 +8104,7 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
8003
8104
|
console.log(JSON.stringify({
|
|
8004
8105
|
version,
|
|
8005
8106
|
configDir,
|
|
8006
|
-
configDirExists:
|
|
8107
|
+
configDirExists: existsSync6(configDir),
|
|
8007
8108
|
installed: installed.length,
|
|
8008
8109
|
configured,
|
|
8009
8110
|
unconfigured,
|
|
@@ -8015,7 +8116,7 @@ program2.command("whoami").option("--json", "Output as JSON", false).description
|
|
|
8015
8116
|
Connectors Setup
|
|
8016
8117
|
`));
|
|
8017
8118
|
console.log(` Version: ${chalk2.cyan(version)}`);
|
|
8018
|
-
console.log(` Config: ${configDir}${
|
|
8119
|
+
console.log(` Config: ${configDir}${existsSync6(configDir) ? "" : chalk2.dim(" (not created yet)")}`);
|
|
8019
8120
|
console.log(` Installed: ${installed.length} connector${installed.length !== 1 ? "s" : ""}`);
|
|
8020
8121
|
console.log(` Configured: ${chalk2.green(String(configured))} ready, ${unconfigured > 0 ? chalk2.red(String(unconfigured)) : chalk2.dim("0")} need auth`);
|
|
8021
8122
|
if (connectorDetails.length > 0) {
|
|
@@ -8087,17 +8188,17 @@ Testing connector credentials...
|
|
|
8087
8188
|
}
|
|
8088
8189
|
}
|
|
8089
8190
|
if (!apiKey) {
|
|
8090
|
-
const connectorConfigDir =
|
|
8091
|
-
const profileFile =
|
|
8092
|
-
if (
|
|
8191
|
+
const connectorConfigDir = join6(homedir3(), ".connectors", name.startsWith("connect-") ? name : `connect-${name}`);
|
|
8192
|
+
const profileFile = join6(connectorConfigDir, "profiles", "default.json");
|
|
8193
|
+
if (existsSync6(profileFile)) {
|
|
8093
8194
|
try {
|
|
8094
8195
|
const config = JSON.parse(readFileSync5(profileFile, "utf-8"));
|
|
8095
8196
|
apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
|
|
8096
8197
|
} catch {}
|
|
8097
8198
|
}
|
|
8098
8199
|
if (!apiKey) {
|
|
8099
|
-
const profileDirConfig =
|
|
8100
|
-
if (
|
|
8200
|
+
const profileDirConfig = join6(connectorConfigDir, "profiles", "default", "config.json");
|
|
8201
|
+
if (existsSync6(profileDirConfig)) {
|
|
8101
8202
|
try {
|
|
8102
8203
|
const config = JSON.parse(readFileSync5(profileDirConfig, "utf-8"));
|
|
8103
8204
|
apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
|
|
@@ -8159,4 +8260,73 @@ Testing connector credentials...
|
|
|
8159
8260
|
}
|
|
8160
8261
|
process.exit(results.some((r) => r.status === "fail") ? 1 : 0);
|
|
8161
8262
|
});
|
|
8263
|
+
program2.command("ops").description("List available API operations for a connector").argument("<name>", "Connector name (e.g. stripe, gmail)").argument("[command]", "Get detailed help for a specific subcommand").option("--json", "Output as JSON").action(async (name, command, options) => {
|
|
8264
|
+
const meta = getConnector(name);
|
|
8265
|
+
if (!meta) {
|
|
8266
|
+
console.error(chalk2.red(`Connector '${name}' not found.`));
|
|
8267
|
+
process.exit(1);
|
|
8268
|
+
}
|
|
8269
|
+
if (!getConnectorCliPath(name)) {
|
|
8270
|
+
console.error(chalk2.red(`Connector '${name}' does not have a CLI.`));
|
|
8271
|
+
process.exit(1);
|
|
8272
|
+
}
|
|
8273
|
+
if (command) {
|
|
8274
|
+
const help = await getConnectorCommandHelp(name, command);
|
|
8275
|
+
if (options.json) {
|
|
8276
|
+
console.log(JSON.stringify({ connector: name, command, help }, null, 2));
|
|
8277
|
+
} else {
|
|
8278
|
+
console.log(chalk2.bold(`
|
|
8279
|
+
${meta.displayName} \u2192 ${command}
|
|
8280
|
+
`));
|
|
8281
|
+
console.log(help);
|
|
8282
|
+
}
|
|
8283
|
+
return;
|
|
8284
|
+
}
|
|
8285
|
+
const ops = await getConnectorOperations(name);
|
|
8286
|
+
if (options.json) {
|
|
8287
|
+
console.log(JSON.stringify({
|
|
8288
|
+
connector: name,
|
|
8289
|
+
displayName: meta.displayName,
|
|
8290
|
+
commands: ops.commands
|
|
8291
|
+
}, null, 2));
|
|
8292
|
+
} else {
|
|
8293
|
+
console.log(chalk2.bold(`
|
|
8294
|
+
${meta.displayName} operations:
|
|
8295
|
+
`));
|
|
8296
|
+
if (ops.commands.length > 0) {
|
|
8297
|
+
for (const cmd of ops.commands) {
|
|
8298
|
+
console.log(` ${chalk2.cyan(cmd)}`);
|
|
8299
|
+
}
|
|
8300
|
+
console.log(chalk2.dim(`
|
|
8301
|
+
Run ${chalk2.white(`connectors ops ${name} <command>`)} for details`));
|
|
8302
|
+
console.log(chalk2.dim(` Run ${chalk2.white(`connectors run ${name} <command> [args...]`)} to execute
|
|
8303
|
+
`));
|
|
8304
|
+
} else {
|
|
8305
|
+
console.log(ops.helpText);
|
|
8306
|
+
}
|
|
8307
|
+
}
|
|
8308
|
+
});
|
|
8309
|
+
program2.command("run").description("Execute an API operation on a connector").argument("<name>", "Connector name (e.g. stripe, gmail)").argument("[args...]", "Command arguments (e.g. products list --limit 5)").option("--timeout <ms>", "Timeout in milliseconds", "30000").allowUnknownOption(true).action(async (name, args, options) => {
|
|
8310
|
+
const meta = getConnector(name);
|
|
8311
|
+
if (!meta) {
|
|
8312
|
+
console.error(chalk2.red(`Connector '${name}' not found.`));
|
|
8313
|
+
process.exit(1);
|
|
8314
|
+
}
|
|
8315
|
+
if (!getConnectorCliPath(name)) {
|
|
8316
|
+
console.error(chalk2.red(`Connector '${name}' does not have a CLI.`));
|
|
8317
|
+
process.exit(1);
|
|
8318
|
+
}
|
|
8319
|
+
if (args.length === 0) {
|
|
8320
|
+
console.error(chalk2.yellow(`No command specified. Run ${chalk2.white(`connectors ops ${name}`)} to see available operations.`));
|
|
8321
|
+
process.exit(1);
|
|
8322
|
+
}
|
|
8323
|
+
const result = await runConnectorCommand(name, args, parseInt(options.timeout));
|
|
8324
|
+
if (result.stdout) {
|
|
8325
|
+
console.log(result.stdout);
|
|
8326
|
+
}
|
|
8327
|
+
if (result.stderr) {
|
|
8328
|
+
console.error(result.stderr);
|
|
8329
|
+
}
|
|
8330
|
+
process.exit(result.exitCode);
|
|
8331
|
+
});
|
|
8162
8332
|
program2.parse();
|