@hasna/connectors 1.3.7 → 1.3.8
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 +283 -253
- package/bin/mcp.js +241 -238
- package/bin/serve.js +106 -77
- package/dist/db/database.d.ts +6 -0
- package/dist/index.js +82 -46
- package/dist/lib/llm.d.ts +1 -1
- package/dist/lib/lock.d.ts +1 -1
- package/package.json +1 -1
package/bin/mcp.js
CHANGED
|
@@ -6509,6 +6509,158 @@ var require_dist = __commonJS((exports, module) => {
|
|
|
6509
6509
|
exports.default = formatsPlugin;
|
|
6510
6510
|
});
|
|
6511
6511
|
|
|
6512
|
+
// src/db/database.ts
|
|
6513
|
+
var exports_database = {};
|
|
6514
|
+
__export(exports_database, {
|
|
6515
|
+
shortUuid: () => shortUuid,
|
|
6516
|
+
now: () => now,
|
|
6517
|
+
getDatabase: () => getDatabase,
|
|
6518
|
+
getConnectorsHome: () => getConnectorsHome,
|
|
6519
|
+
closeDatabase: () => closeDatabase
|
|
6520
|
+
});
|
|
6521
|
+
import { Database } from "bun:sqlite";
|
|
6522
|
+
import { join as join2 } from "path";
|
|
6523
|
+
import { homedir } from "os";
|
|
6524
|
+
import { mkdirSync, existsSync as existsSync2, readdirSync, copyFileSync, statSync } from "fs";
|
|
6525
|
+
function getConnectorsHome() {
|
|
6526
|
+
const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir();
|
|
6527
|
+
const newDir = join2(home, ".hasna", "connectors");
|
|
6528
|
+
const oldDir = join2(home, ".connectors");
|
|
6529
|
+
if (existsSync2(oldDir) && !existsSync2(newDir)) {
|
|
6530
|
+
mkdirSync(newDir, { recursive: true });
|
|
6531
|
+
try {
|
|
6532
|
+
for (const file of readdirSync(oldDir)) {
|
|
6533
|
+
const oldPath = join2(oldDir, file);
|
|
6534
|
+
const newPath = join2(newDir, file);
|
|
6535
|
+
try {
|
|
6536
|
+
if (statSync(oldPath).isFile()) {
|
|
6537
|
+
copyFileSync(oldPath, newPath);
|
|
6538
|
+
}
|
|
6539
|
+
} catch {}
|
|
6540
|
+
}
|
|
6541
|
+
} catch {}
|
|
6542
|
+
}
|
|
6543
|
+
mkdirSync(newDir, { recursive: true });
|
|
6544
|
+
return newDir;
|
|
6545
|
+
}
|
|
6546
|
+
function getDatabase(path) {
|
|
6547
|
+
if (_db)
|
|
6548
|
+
return _db;
|
|
6549
|
+
const dbPath = path ?? DB_PATH;
|
|
6550
|
+
mkdirSync(join2(dbPath, ".."), { recursive: true });
|
|
6551
|
+
_db = new Database(dbPath);
|
|
6552
|
+
_db.run("PRAGMA journal_mode = WAL");
|
|
6553
|
+
migrate(_db);
|
|
6554
|
+
return _db;
|
|
6555
|
+
}
|
|
6556
|
+
function closeDatabase() {
|
|
6557
|
+
_db?.close();
|
|
6558
|
+
_db = null;
|
|
6559
|
+
}
|
|
6560
|
+
function now() {
|
|
6561
|
+
return new Date().toISOString();
|
|
6562
|
+
}
|
|
6563
|
+
function shortUuid() {
|
|
6564
|
+
return crypto.randomUUID().slice(0, 8);
|
|
6565
|
+
}
|
|
6566
|
+
function migrate(db) {
|
|
6567
|
+
db.run(`
|
|
6568
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
6569
|
+
id TEXT PRIMARY KEY,
|
|
6570
|
+
name TEXT UNIQUE NOT NULL,
|
|
6571
|
+
session_id TEXT,
|
|
6572
|
+
role TEXT NOT NULL DEFAULT 'agent',
|
|
6573
|
+
last_seen_at TEXT NOT NULL,
|
|
6574
|
+
created_at TEXT NOT NULL
|
|
6575
|
+
)
|
|
6576
|
+
`);
|
|
6577
|
+
db.run(`
|
|
6578
|
+
CREATE TABLE IF NOT EXISTS resource_locks (
|
|
6579
|
+
id TEXT PRIMARY KEY,
|
|
6580
|
+
resource_type TEXT NOT NULL CHECK(resource_type IN ('connector', 'agent', 'profile', 'token')),
|
|
6581
|
+
resource_id TEXT NOT NULL,
|
|
6582
|
+
agent_id TEXT NOT NULL,
|
|
6583
|
+
lock_type TEXT NOT NULL DEFAULT 'exclusive' CHECK(lock_type IN ('advisory', 'exclusive')),
|
|
6584
|
+
locked_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
6585
|
+
expires_at TEXT NOT NULL
|
|
6586
|
+
)
|
|
6587
|
+
`);
|
|
6588
|
+
db.run(`
|
|
6589
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_resource_locks_exclusive
|
|
6590
|
+
ON resource_locks(resource_type, resource_id)
|
|
6591
|
+
WHERE lock_type = 'exclusive'
|
|
6592
|
+
`);
|
|
6593
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_resource_locks_agent ON resource_locks(agent_id)`);
|
|
6594
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_resource_locks_expires ON resource_locks(expires_at)`);
|
|
6595
|
+
db.run(`
|
|
6596
|
+
CREATE TABLE IF NOT EXISTS connector_rate_usage (
|
|
6597
|
+
agent_id TEXT NOT NULL,
|
|
6598
|
+
connector TEXT NOT NULL,
|
|
6599
|
+
window_start TEXT NOT NULL,
|
|
6600
|
+
call_count INTEGER NOT NULL DEFAULT 0,
|
|
6601
|
+
PRIMARY KEY (agent_id, connector, window_start)
|
|
6602
|
+
)
|
|
6603
|
+
`);
|
|
6604
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_rate_usage_window ON connector_rate_usage(connector, window_start)`);
|
|
6605
|
+
db.run(`
|
|
6606
|
+
CREATE TABLE IF NOT EXISTS connector_jobs (
|
|
6607
|
+
id TEXT PRIMARY KEY,
|
|
6608
|
+
name TEXT UNIQUE NOT NULL,
|
|
6609
|
+
connector TEXT NOT NULL,
|
|
6610
|
+
command TEXT NOT NULL,
|
|
6611
|
+
args TEXT NOT NULL DEFAULT '[]',
|
|
6612
|
+
cron TEXT NOT NULL,
|
|
6613
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
6614
|
+
strip INTEGER NOT NULL DEFAULT 0,
|
|
6615
|
+
created_at TEXT NOT NULL,
|
|
6616
|
+
last_run_at TEXT
|
|
6617
|
+
)
|
|
6618
|
+
`);
|
|
6619
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_jobs_enabled ON connector_jobs(enabled)`);
|
|
6620
|
+
db.run(`
|
|
6621
|
+
CREATE TABLE IF NOT EXISTS connector_job_runs (
|
|
6622
|
+
id TEXT PRIMARY KEY,
|
|
6623
|
+
job_id TEXT NOT NULL REFERENCES connector_jobs(id) ON DELETE CASCADE,
|
|
6624
|
+
started_at TEXT NOT NULL,
|
|
6625
|
+
finished_at TEXT,
|
|
6626
|
+
exit_code INTEGER,
|
|
6627
|
+
raw_output TEXT,
|
|
6628
|
+
stripped_output TEXT
|
|
6629
|
+
)
|
|
6630
|
+
`);
|
|
6631
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_job_runs_job ON connector_job_runs(job_id, started_at DESC)`);
|
|
6632
|
+
db.run(`
|
|
6633
|
+
CREATE TABLE IF NOT EXISTS connector_workflows (
|
|
6634
|
+
id TEXT PRIMARY KEY,
|
|
6635
|
+
name TEXT UNIQUE NOT NULL,
|
|
6636
|
+
steps TEXT NOT NULL DEFAULT '[]',
|
|
6637
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
6638
|
+
created_at TEXT NOT NULL
|
|
6639
|
+
)
|
|
6640
|
+
`);
|
|
6641
|
+
db.run(`
|
|
6642
|
+
CREATE TABLE IF NOT EXISTS connector_usage (
|
|
6643
|
+
id TEXT PRIMARY KEY,
|
|
6644
|
+
connector TEXT NOT NULL,
|
|
6645
|
+
action TEXT NOT NULL,
|
|
6646
|
+
agent_id TEXT,
|
|
6647
|
+
timestamp TEXT NOT NULL
|
|
6648
|
+
)
|
|
6649
|
+
`);
|
|
6650
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_usage_connector ON connector_usage(connector, timestamp DESC)`);
|
|
6651
|
+
db.run(`
|
|
6652
|
+
CREATE TABLE IF NOT EXISTS connector_promotions (
|
|
6653
|
+
connector TEXT UNIQUE NOT NULL,
|
|
6654
|
+
promoted_at TEXT NOT NULL
|
|
6655
|
+
)
|
|
6656
|
+
`);
|
|
6657
|
+
}
|
|
6658
|
+
var DB_DIR, DB_PATH, _db = null;
|
|
6659
|
+
var init_database = __esm(() => {
|
|
6660
|
+
DB_DIR = getConnectorsHome();
|
|
6661
|
+
DB_PATH = join2(DB_DIR, "connectors.db");
|
|
6662
|
+
});
|
|
6663
|
+
|
|
6512
6664
|
// src/lib/installer.ts
|
|
6513
6665
|
var exports_installer = {};
|
|
6514
6666
|
__export(exports_installer, {
|
|
@@ -6520,25 +6672,24 @@ __export(exports_installer, {
|
|
|
6520
6672
|
getConnectorDocs: () => getConnectorDocs,
|
|
6521
6673
|
connectorExists: () => connectorExists
|
|
6522
6674
|
});
|
|
6523
|
-
import { existsSync as
|
|
6524
|
-
import {
|
|
6525
|
-
import { join as join2, dirname as dirname2 } from "path";
|
|
6675
|
+
import { existsSync as existsSync3, cpSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync, readdirSync as readdirSync2, statSync as statSync2, rmSync } from "fs";
|
|
6676
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
6526
6677
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6527
6678
|
function resolveConnectorsDir() {
|
|
6528
|
-
const fromBin =
|
|
6529
|
-
if (
|
|
6679
|
+
const fromBin = join3(__dirname2, "..", "connectors");
|
|
6680
|
+
if (existsSync3(fromBin))
|
|
6530
6681
|
return fromBin;
|
|
6531
|
-
const fromSrc =
|
|
6532
|
-
if (
|
|
6682
|
+
const fromSrc = join3(__dirname2, "..", "..", "connectors");
|
|
6683
|
+
if (existsSync3(fromSrc))
|
|
6533
6684
|
return fromSrc;
|
|
6534
6685
|
return fromBin;
|
|
6535
6686
|
}
|
|
6536
6687
|
function getConnectorPath(name) {
|
|
6537
6688
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
6538
|
-
return
|
|
6689
|
+
return join3(CONNECTORS_DIR, connectorName);
|
|
6539
6690
|
}
|
|
6540
6691
|
function connectorExists(name) {
|
|
6541
|
-
return
|
|
6692
|
+
return existsSync3(getConnectorPath(name));
|
|
6542
6693
|
}
|
|
6543
6694
|
function installConnector(name, options = {}) {
|
|
6544
6695
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
@@ -6551,16 +6702,16 @@ function installConnector(name, options = {}) {
|
|
|
6551
6702
|
}
|
|
6552
6703
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
6553
6704
|
const sourcePath = getConnectorPath(name);
|
|
6554
|
-
const destDir =
|
|
6555
|
-
const destPath =
|
|
6556
|
-
if (!
|
|
6705
|
+
const destDir = join3(targetDir, ".connectors");
|
|
6706
|
+
const destPath = join3(destDir, connectorName);
|
|
6707
|
+
if (!existsSync3(sourcePath)) {
|
|
6557
6708
|
return {
|
|
6558
6709
|
connector: name,
|
|
6559
6710
|
success: false,
|
|
6560
6711
|
error: `Connector '${name}' not found`
|
|
6561
6712
|
};
|
|
6562
6713
|
}
|
|
6563
|
-
if (
|
|
6714
|
+
if (existsSync3(destPath) && !overwrite) {
|
|
6564
6715
|
return {
|
|
6565
6716
|
connector: name,
|
|
6566
6717
|
success: false,
|
|
@@ -6569,22 +6720,22 @@ function installConnector(name, options = {}) {
|
|
|
6569
6720
|
};
|
|
6570
6721
|
}
|
|
6571
6722
|
try {
|
|
6572
|
-
if (!
|
|
6573
|
-
|
|
6723
|
+
if (!existsSync3(destDir)) {
|
|
6724
|
+
mkdirSync2(destDir, { recursive: true });
|
|
6574
6725
|
}
|
|
6575
6726
|
cpSync(sourcePath, destPath, { recursive: true });
|
|
6576
|
-
const homeCredDir =
|
|
6577
|
-
if (
|
|
6727
|
+
const homeCredDir = join3(getConnectorsHome(), connectorName);
|
|
6728
|
+
if (existsSync3(homeCredDir)) {
|
|
6578
6729
|
const filesToCopy = ["credentials.json", "current_profile"];
|
|
6579
6730
|
for (const file of filesToCopy) {
|
|
6580
|
-
const src =
|
|
6581
|
-
if (
|
|
6582
|
-
cpSync(src,
|
|
6731
|
+
const src = join3(homeCredDir, file);
|
|
6732
|
+
if (existsSync3(src)) {
|
|
6733
|
+
cpSync(src, join3(destPath, file));
|
|
6583
6734
|
}
|
|
6584
6735
|
}
|
|
6585
|
-
const profilesDir =
|
|
6586
|
-
if (
|
|
6587
|
-
cpSync(profilesDir,
|
|
6736
|
+
const profilesDir = join3(homeCredDir, "profiles");
|
|
6737
|
+
if (existsSync3(profilesDir)) {
|
|
6738
|
+
cpSync(profilesDir, join3(destPath, "profiles"), { recursive: true });
|
|
6588
6739
|
}
|
|
6589
6740
|
}
|
|
6590
6741
|
updateConnectorsIndex(destDir);
|
|
@@ -6605,8 +6756,8 @@ function installConnectors(names, options = {}) {
|
|
|
6605
6756
|
return names.map((name) => installConnector(name, options));
|
|
6606
6757
|
}
|
|
6607
6758
|
function updateConnectorsIndex(connectorsDir) {
|
|
6608
|
-
const indexPath =
|
|
6609
|
-
const connectors =
|
|
6759
|
+
const indexPath = join3(connectorsDir, "index.ts");
|
|
6760
|
+
const connectors = readdirSync2(connectorsDir).filter((f) => f.startsWith("connect-") && !f.includes("."));
|
|
6610
6761
|
const exports = connectors.map((c) => {
|
|
6611
6762
|
const name = c.replace("connect-", "");
|
|
6612
6763
|
return `export * as ${name} from './${c}/src/index.js';`;
|
|
@@ -6622,19 +6773,19 @@ ${exports}
|
|
|
6622
6773
|
writeFileSync(indexPath, content);
|
|
6623
6774
|
}
|
|
6624
6775
|
function getInstalledConnectors(targetDir = process.cwd()) {
|
|
6625
|
-
const connectorsDir =
|
|
6626
|
-
if (!
|
|
6776
|
+
const connectorsDir = join3(targetDir, ".connectors");
|
|
6777
|
+
if (!existsSync3(connectorsDir)) {
|
|
6627
6778
|
return [];
|
|
6628
6779
|
}
|
|
6629
|
-
return
|
|
6630
|
-
const fullPath =
|
|
6631
|
-
return f.startsWith("connect-") &&
|
|
6780
|
+
return readdirSync2(connectorsDir).filter((f) => {
|
|
6781
|
+
const fullPath = join3(connectorsDir, f);
|
|
6782
|
+
return f.startsWith("connect-") && statSync2(fullPath).isDirectory();
|
|
6632
6783
|
}).map((f) => f.replace("connect-", ""));
|
|
6633
6784
|
}
|
|
6634
6785
|
function getConnectorDocs(name) {
|
|
6635
6786
|
const connectorPath = getConnectorPath(name);
|
|
6636
|
-
const claudeMdPath =
|
|
6637
|
-
if (!
|
|
6787
|
+
const claudeMdPath = join3(connectorPath, "CLAUDE.md");
|
|
6788
|
+
if (!existsSync3(claudeMdPath))
|
|
6638
6789
|
return null;
|
|
6639
6790
|
const raw = readFileSync2(claudeMdPath, "utf-8");
|
|
6640
6791
|
return {
|
|
@@ -6675,9 +6826,9 @@ function parseEnvVarsTable(section) {
|
|
|
6675
6826
|
}
|
|
6676
6827
|
function removeConnector(name, targetDir = process.cwd()) {
|
|
6677
6828
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
6678
|
-
const connectorsDir =
|
|
6679
|
-
const connectorPath =
|
|
6680
|
-
if (!
|
|
6829
|
+
const connectorsDir = join3(targetDir, ".connectors");
|
|
6830
|
+
const connectorPath = join3(connectorsDir, connectorName);
|
|
6831
|
+
if (!existsSync3(connectorPath)) {
|
|
6681
6832
|
return false;
|
|
6682
6833
|
}
|
|
6683
6834
|
rmSync(connectorPath, { recursive: true });
|
|
@@ -6686,140 +6837,11 @@ function removeConnector(name, targetDir = process.cwd()) {
|
|
|
6686
6837
|
}
|
|
6687
6838
|
var __dirname2, CONNECTORS_DIR;
|
|
6688
6839
|
var init_installer = __esm(() => {
|
|
6840
|
+
init_database();
|
|
6689
6841
|
__dirname2 = dirname2(fileURLToPath2(import.meta.url));
|
|
6690
6842
|
CONNECTORS_DIR = resolveConnectorsDir();
|
|
6691
6843
|
});
|
|
6692
6844
|
|
|
6693
|
-
// src/db/database.ts
|
|
6694
|
-
var exports_database = {};
|
|
6695
|
-
__export(exports_database, {
|
|
6696
|
-
shortUuid: () => shortUuid,
|
|
6697
|
-
now: () => now,
|
|
6698
|
-
getDatabase: () => getDatabase,
|
|
6699
|
-
closeDatabase: () => closeDatabase
|
|
6700
|
-
});
|
|
6701
|
-
import { Database } from "bun:sqlite";
|
|
6702
|
-
import { join as join6 } from "path";
|
|
6703
|
-
import { homedir as homedir4 } from "os";
|
|
6704
|
-
import { mkdirSync as mkdirSync4 } from "fs";
|
|
6705
|
-
function getDatabase(path) {
|
|
6706
|
-
if (_db)
|
|
6707
|
-
return _db;
|
|
6708
|
-
const dbPath = path ?? DB_PATH;
|
|
6709
|
-
mkdirSync4(join6(dbPath, ".."), { recursive: true });
|
|
6710
|
-
_db = new Database(dbPath);
|
|
6711
|
-
_db.run("PRAGMA journal_mode = WAL");
|
|
6712
|
-
migrate(_db);
|
|
6713
|
-
return _db;
|
|
6714
|
-
}
|
|
6715
|
-
function closeDatabase() {
|
|
6716
|
-
_db?.close();
|
|
6717
|
-
_db = null;
|
|
6718
|
-
}
|
|
6719
|
-
function now() {
|
|
6720
|
-
return new Date().toISOString();
|
|
6721
|
-
}
|
|
6722
|
-
function shortUuid() {
|
|
6723
|
-
return crypto.randomUUID().slice(0, 8);
|
|
6724
|
-
}
|
|
6725
|
-
function migrate(db) {
|
|
6726
|
-
db.run(`
|
|
6727
|
-
CREATE TABLE IF NOT EXISTS agents (
|
|
6728
|
-
id TEXT PRIMARY KEY,
|
|
6729
|
-
name TEXT UNIQUE NOT NULL,
|
|
6730
|
-
session_id TEXT,
|
|
6731
|
-
role TEXT NOT NULL DEFAULT 'agent',
|
|
6732
|
-
last_seen_at TEXT NOT NULL,
|
|
6733
|
-
created_at TEXT NOT NULL
|
|
6734
|
-
)
|
|
6735
|
-
`);
|
|
6736
|
-
db.run(`
|
|
6737
|
-
CREATE TABLE IF NOT EXISTS resource_locks (
|
|
6738
|
-
id TEXT PRIMARY KEY,
|
|
6739
|
-
resource_type TEXT NOT NULL CHECK(resource_type IN ('connector', 'agent', 'profile', 'token')),
|
|
6740
|
-
resource_id TEXT NOT NULL,
|
|
6741
|
-
agent_id TEXT NOT NULL,
|
|
6742
|
-
lock_type TEXT NOT NULL DEFAULT 'exclusive' CHECK(lock_type IN ('advisory', 'exclusive')),
|
|
6743
|
-
locked_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
6744
|
-
expires_at TEXT NOT NULL
|
|
6745
|
-
)
|
|
6746
|
-
`);
|
|
6747
|
-
db.run(`
|
|
6748
|
-
CREATE UNIQUE INDEX IF NOT EXISTS idx_resource_locks_exclusive
|
|
6749
|
-
ON resource_locks(resource_type, resource_id)
|
|
6750
|
-
WHERE lock_type = 'exclusive'
|
|
6751
|
-
`);
|
|
6752
|
-
db.run(`CREATE INDEX IF NOT EXISTS idx_resource_locks_agent ON resource_locks(agent_id)`);
|
|
6753
|
-
db.run(`CREATE INDEX IF NOT EXISTS idx_resource_locks_expires ON resource_locks(expires_at)`);
|
|
6754
|
-
db.run(`
|
|
6755
|
-
CREATE TABLE IF NOT EXISTS connector_rate_usage (
|
|
6756
|
-
agent_id TEXT NOT NULL,
|
|
6757
|
-
connector TEXT NOT NULL,
|
|
6758
|
-
window_start TEXT NOT NULL,
|
|
6759
|
-
call_count INTEGER NOT NULL DEFAULT 0,
|
|
6760
|
-
PRIMARY KEY (agent_id, connector, window_start)
|
|
6761
|
-
)
|
|
6762
|
-
`);
|
|
6763
|
-
db.run(`CREATE INDEX IF NOT EXISTS idx_rate_usage_window ON connector_rate_usage(connector, window_start)`);
|
|
6764
|
-
db.run(`
|
|
6765
|
-
CREATE TABLE IF NOT EXISTS connector_jobs (
|
|
6766
|
-
id TEXT PRIMARY KEY,
|
|
6767
|
-
name TEXT UNIQUE NOT NULL,
|
|
6768
|
-
connector TEXT NOT NULL,
|
|
6769
|
-
command TEXT NOT NULL,
|
|
6770
|
-
args TEXT NOT NULL DEFAULT '[]',
|
|
6771
|
-
cron TEXT NOT NULL,
|
|
6772
|
-
enabled INTEGER NOT NULL DEFAULT 1,
|
|
6773
|
-
strip INTEGER NOT NULL DEFAULT 0,
|
|
6774
|
-
created_at TEXT NOT NULL,
|
|
6775
|
-
last_run_at TEXT
|
|
6776
|
-
)
|
|
6777
|
-
`);
|
|
6778
|
-
db.run(`CREATE INDEX IF NOT EXISTS idx_jobs_enabled ON connector_jobs(enabled)`);
|
|
6779
|
-
db.run(`
|
|
6780
|
-
CREATE TABLE IF NOT EXISTS connector_job_runs (
|
|
6781
|
-
id TEXT PRIMARY KEY,
|
|
6782
|
-
job_id TEXT NOT NULL REFERENCES connector_jobs(id) ON DELETE CASCADE,
|
|
6783
|
-
started_at TEXT NOT NULL,
|
|
6784
|
-
finished_at TEXT,
|
|
6785
|
-
exit_code INTEGER,
|
|
6786
|
-
raw_output TEXT,
|
|
6787
|
-
stripped_output TEXT
|
|
6788
|
-
)
|
|
6789
|
-
`);
|
|
6790
|
-
db.run(`CREATE INDEX IF NOT EXISTS idx_job_runs_job ON connector_job_runs(job_id, started_at DESC)`);
|
|
6791
|
-
db.run(`
|
|
6792
|
-
CREATE TABLE IF NOT EXISTS connector_workflows (
|
|
6793
|
-
id TEXT PRIMARY KEY,
|
|
6794
|
-
name TEXT UNIQUE NOT NULL,
|
|
6795
|
-
steps TEXT NOT NULL DEFAULT '[]',
|
|
6796
|
-
enabled INTEGER NOT NULL DEFAULT 1,
|
|
6797
|
-
created_at TEXT NOT NULL
|
|
6798
|
-
)
|
|
6799
|
-
`);
|
|
6800
|
-
db.run(`
|
|
6801
|
-
CREATE TABLE IF NOT EXISTS connector_usage (
|
|
6802
|
-
id TEXT PRIMARY KEY,
|
|
6803
|
-
connector TEXT NOT NULL,
|
|
6804
|
-
action TEXT NOT NULL,
|
|
6805
|
-
agent_id TEXT,
|
|
6806
|
-
timestamp TEXT NOT NULL
|
|
6807
|
-
)
|
|
6808
|
-
`);
|
|
6809
|
-
db.run(`CREATE INDEX IF NOT EXISTS idx_usage_connector ON connector_usage(connector, timestamp DESC)`);
|
|
6810
|
-
db.run(`
|
|
6811
|
-
CREATE TABLE IF NOT EXISTS connector_promotions (
|
|
6812
|
-
connector TEXT UNIQUE NOT NULL,
|
|
6813
|
-
promoted_at TEXT NOT NULL
|
|
6814
|
-
)
|
|
6815
|
-
`);
|
|
6816
|
-
}
|
|
6817
|
-
var DB_DIR, DB_PATH, _db = null;
|
|
6818
|
-
var init_database = __esm(() => {
|
|
6819
|
-
DB_DIR = join6(homedir4(), ".connectors");
|
|
6820
|
-
DB_PATH = join6(DB_DIR, "connectors.db");
|
|
6821
|
-
});
|
|
6822
|
-
|
|
6823
6845
|
// src/lib/llm.ts
|
|
6824
6846
|
var exports_llm = {};
|
|
6825
6847
|
__export(exports_llm, {
|
|
@@ -6831,15 +6853,14 @@ __export(exports_llm, {
|
|
|
6831
6853
|
PROVIDER_DEFAULTS: () => PROVIDER_DEFAULTS,
|
|
6832
6854
|
LLMClient: () => LLMClient
|
|
6833
6855
|
});
|
|
6834
|
-
import { existsSync as
|
|
6856
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync5 } from "fs";
|
|
6835
6857
|
import { join as join7 } from "path";
|
|
6836
|
-
import { homedir as homedir5 } from "os";
|
|
6837
6858
|
function getLlmConfigPath() {
|
|
6838
|
-
return join7(
|
|
6859
|
+
return join7(getConnectorsHome(), "llm.json");
|
|
6839
6860
|
}
|
|
6840
6861
|
function getLlmConfig() {
|
|
6841
6862
|
const path = getLlmConfigPath();
|
|
6842
|
-
if (!
|
|
6863
|
+
if (!existsSync7(path))
|
|
6843
6864
|
return null;
|
|
6844
6865
|
try {
|
|
6845
6866
|
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
@@ -6848,7 +6869,7 @@ function getLlmConfig() {
|
|
|
6848
6869
|
}
|
|
6849
6870
|
}
|
|
6850
6871
|
function saveLlmConfig(config2) {
|
|
6851
|
-
const dir =
|
|
6872
|
+
const dir = getConnectorsHome();
|
|
6852
6873
|
mkdirSync5(dir, { recursive: true });
|
|
6853
6874
|
writeFileSync3(getLlmConfigPath(), JSON.stringify(config2, null, 2));
|
|
6854
6875
|
}
|
|
@@ -6944,6 +6965,7 @@ class LLMClient {
|
|
|
6944
6965
|
}
|
|
6945
6966
|
var PROVIDER_BASE_URLS, PROVIDER_DEFAULTS;
|
|
6946
6967
|
var init_llm = __esm(() => {
|
|
6968
|
+
init_database();
|
|
6947
6969
|
PROVIDER_BASE_URLS = {
|
|
6948
6970
|
cerebras: "https://api.cerebras.ai/v1",
|
|
6949
6971
|
groq: "https://api.groq.com/openai/v1",
|
|
@@ -20795,6 +20817,13 @@ var CONNECTORS = [
|
|
|
20795
20817
|
category: "Data & Analytics",
|
|
20796
20818
|
tags: ["weather", "data"]
|
|
20797
20819
|
},
|
|
20820
|
+
{
|
|
20821
|
+
name: "arxiv",
|
|
20822
|
+
displayName: "arXiv",
|
|
20823
|
+
description: "Research paper search and retrieval",
|
|
20824
|
+
category: "Data & Analytics",
|
|
20825
|
+
tags: ["research", "papers", "academic"]
|
|
20826
|
+
},
|
|
20798
20827
|
{
|
|
20799
20828
|
name: "brandsight",
|
|
20800
20829
|
displayName: "Brandsight",
|
|
@@ -26486,16 +26515,15 @@ function loadConnectorVersions() {
|
|
|
26486
26515
|
init_installer();
|
|
26487
26516
|
|
|
26488
26517
|
// src/server/auth.ts
|
|
26489
|
-
import { existsSync as
|
|
26518
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync4, readdirSync as readdirSync3, rmSync as rmSync2, statSync as statSync4 } from "fs";
|
|
26490
26519
|
init_installer();
|
|
26491
|
-
import {
|
|
26492
|
-
import { join as join4 } from "path";
|
|
26520
|
+
import { join as join5 } from "path";
|
|
26493
26521
|
|
|
26494
26522
|
// src/lib/lock.ts
|
|
26495
|
-
|
|
26496
|
-
import {
|
|
26497
|
-
import {
|
|
26498
|
-
import { mkdirSync as
|
|
26523
|
+
init_database();
|
|
26524
|
+
import { openSync, closeSync, unlinkSync, existsSync as existsSync4, statSync as statSync3 } from "fs";
|
|
26525
|
+
import { join as join4 } from "path";
|
|
26526
|
+
import { mkdirSync as mkdirSync3 } from "fs";
|
|
26499
26527
|
var LOCK_TIMEOUT_MS = 5000;
|
|
26500
26528
|
var LOCK_RETRY_MS = 100;
|
|
26501
26529
|
var STALE_LOCK_MS = 30000;
|
|
@@ -26509,20 +26537,20 @@ class LockTimeoutError extends Error {
|
|
|
26509
26537
|
}
|
|
26510
26538
|
}
|
|
26511
26539
|
function lockPath(connector) {
|
|
26512
|
-
const dir =
|
|
26513
|
-
|
|
26514
|
-
return
|
|
26540
|
+
const dir = join4(getConnectorsHome(), `connect-${connector}`);
|
|
26541
|
+
mkdirSync3(dir, { recursive: true });
|
|
26542
|
+
return join4(dir, ".write.lock");
|
|
26515
26543
|
}
|
|
26516
26544
|
function isStale(path) {
|
|
26517
26545
|
try {
|
|
26518
|
-
const stat =
|
|
26546
|
+
const stat = statSync3(path);
|
|
26519
26547
|
return Date.now() - stat.mtimeMs > STALE_LOCK_MS;
|
|
26520
26548
|
} catch {
|
|
26521
26549
|
return false;
|
|
26522
26550
|
}
|
|
26523
26551
|
}
|
|
26524
26552
|
function tryAcquire(path) {
|
|
26525
|
-
if (
|
|
26553
|
+
if (existsSync4(path) && isStale(path)) {
|
|
26526
26554
|
try {
|
|
26527
26555
|
unlinkSync(path);
|
|
26528
26556
|
} catch {}
|
|
@@ -26559,6 +26587,7 @@ async function withWriteLock(connector, fn) {
|
|
|
26559
26587
|
}
|
|
26560
26588
|
|
|
26561
26589
|
// src/server/auth.ts
|
|
26590
|
+
init_database();
|
|
26562
26591
|
var oauthStateStore = new Map;
|
|
26563
26592
|
var GOOGLE_SCOPES = {
|
|
26564
26593
|
gmail: [
|
|
@@ -26611,12 +26640,12 @@ function getAuthType(name) {
|
|
|
26611
26640
|
}
|
|
26612
26641
|
function getConnectorConfigDir(name) {
|
|
26613
26642
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
26614
|
-
return
|
|
26643
|
+
return join5(getConnectorsHome(), connectorName);
|
|
26615
26644
|
}
|
|
26616
26645
|
function getCurrentProfile(name) {
|
|
26617
26646
|
const configDir = getConnectorConfigDir(name);
|
|
26618
|
-
const currentProfileFile =
|
|
26619
|
-
if (
|
|
26647
|
+
const currentProfileFile = join5(configDir, "current_profile");
|
|
26648
|
+
if (existsSync5(currentProfileFile)) {
|
|
26620
26649
|
try {
|
|
26621
26650
|
return readFileSync3(currentProfileFile, "utf-8").trim() || "default";
|
|
26622
26651
|
} catch {
|
|
@@ -26630,14 +26659,14 @@ function loadProfileConfig(name) {
|
|
|
26630
26659
|
const profile = getCurrentProfile(name);
|
|
26631
26660
|
let flatConfig = {};
|
|
26632
26661
|
let dirConfig = {};
|
|
26633
|
-
const profileFile =
|
|
26634
|
-
if (
|
|
26662
|
+
const profileFile = join5(configDir, "profiles", `${profile}.json`);
|
|
26663
|
+
if (existsSync5(profileFile)) {
|
|
26635
26664
|
try {
|
|
26636
26665
|
flatConfig = JSON.parse(readFileSync3(profileFile, "utf-8"));
|
|
26637
26666
|
} catch {}
|
|
26638
26667
|
}
|
|
26639
|
-
const profileDirConfig =
|
|
26640
|
-
if (
|
|
26668
|
+
const profileDirConfig = join5(configDir, "profiles", profile, "config.json");
|
|
26669
|
+
if (existsSync5(profileDirConfig)) {
|
|
26641
26670
|
try {
|
|
26642
26671
|
dirConfig = JSON.parse(readFileSync3(profileDirConfig, "utf-8"));
|
|
26643
26672
|
} catch {}
|
|
@@ -26650,8 +26679,8 @@ function loadProfileConfig(name) {
|
|
|
26650
26679
|
function loadTokens(name) {
|
|
26651
26680
|
const configDir = getConnectorConfigDir(name);
|
|
26652
26681
|
const profile = getCurrentProfile(name);
|
|
26653
|
-
const tokensFile =
|
|
26654
|
-
if (
|
|
26682
|
+
const tokensFile = join5(configDir, "profiles", profile, "tokens.json");
|
|
26683
|
+
if (existsSync5(tokensFile)) {
|
|
26655
26684
|
try {
|
|
26656
26685
|
return JSON.parse(readFileSync3(tokensFile, "utf-8"));
|
|
26657
26686
|
} catch {
|
|
@@ -26716,10 +26745,10 @@ function _saveApiKey(name, key, field) {
|
|
|
26716
26745
|
const profile = getCurrentProfile(name);
|
|
26717
26746
|
const keyField = field || guessKeyField(name);
|
|
26718
26747
|
if (keyField === "clientId" || keyField === "clientSecret") {
|
|
26719
|
-
const credentialsFile =
|
|
26720
|
-
|
|
26748
|
+
const credentialsFile = join5(configDir, "credentials.json");
|
|
26749
|
+
mkdirSync4(configDir, { recursive: true });
|
|
26721
26750
|
let creds = {};
|
|
26722
|
-
if (
|
|
26751
|
+
if (existsSync5(credentialsFile)) {
|
|
26723
26752
|
try {
|
|
26724
26753
|
creds = JSON.parse(readFileSync3(credentialsFile, "utf-8"));
|
|
26725
26754
|
} catch {}
|
|
@@ -26728,9 +26757,9 @@ function _saveApiKey(name, key, field) {
|
|
|
26728
26757
|
writeFileSync2(credentialsFile, JSON.stringify(creds, null, 2));
|
|
26729
26758
|
return;
|
|
26730
26759
|
}
|
|
26731
|
-
const profileFile =
|
|
26732
|
-
const profileDir =
|
|
26733
|
-
if (
|
|
26760
|
+
const profileFile = join5(configDir, "profiles", `${profile}.json`);
|
|
26761
|
+
const profileDir = join5(configDir, "profiles", profile);
|
|
26762
|
+
if (existsSync5(profileFile)) {
|
|
26734
26763
|
let config2 = {};
|
|
26735
26764
|
try {
|
|
26736
26765
|
config2 = JSON.parse(readFileSync3(profileFile, "utf-8"));
|
|
@@ -26739,10 +26768,10 @@ function _saveApiKey(name, key, field) {
|
|
|
26739
26768
|
writeFileSync2(profileFile, JSON.stringify(config2, null, 2));
|
|
26740
26769
|
return;
|
|
26741
26770
|
}
|
|
26742
|
-
if (
|
|
26743
|
-
const configFile =
|
|
26771
|
+
if (existsSync5(profileDir)) {
|
|
26772
|
+
const configFile = join5(profileDir, "config.json");
|
|
26744
26773
|
let config2 = {};
|
|
26745
|
-
if (
|
|
26774
|
+
if (existsSync5(configFile)) {
|
|
26746
26775
|
try {
|
|
26747
26776
|
config2 = JSON.parse(readFileSync3(configFile, "utf-8"));
|
|
26748
26777
|
} catch {}
|
|
@@ -26751,8 +26780,8 @@ function _saveApiKey(name, key, field) {
|
|
|
26751
26780
|
writeFileSync2(configFile, JSON.stringify(config2, null, 2));
|
|
26752
26781
|
return;
|
|
26753
26782
|
}
|
|
26754
|
-
|
|
26755
|
-
writeFileSync2(
|
|
26783
|
+
mkdirSync4(profileDir, { recursive: true });
|
|
26784
|
+
writeFileSync2(join5(profileDir, "config.json"), JSON.stringify({ [keyField]: key }, null, 2));
|
|
26756
26785
|
}
|
|
26757
26786
|
function guessKeyField(name) {
|
|
26758
26787
|
const docs = getConnectorDocs(name);
|
|
@@ -26770,17 +26799,17 @@ function guessKeyField(name) {
|
|
|
26770
26799
|
}
|
|
26771
26800
|
|
|
26772
26801
|
// src/lib/runner.ts
|
|
26773
|
-
import { existsSync as
|
|
26774
|
-
import { join as
|
|
26802
|
+
import { existsSync as existsSync6 } from "fs";
|
|
26803
|
+
import { join as join6, dirname as dirname3 } from "path";
|
|
26775
26804
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
26776
26805
|
import { spawn } from "child_process";
|
|
26777
26806
|
var __dirname3 = dirname3(fileURLToPath3(import.meta.url));
|
|
26778
26807
|
function resolveConnectorsDir2() {
|
|
26779
|
-
const fromBin =
|
|
26780
|
-
if (
|
|
26808
|
+
const fromBin = join6(__dirname3, "..", "connectors");
|
|
26809
|
+
if (existsSync6(fromBin))
|
|
26781
26810
|
return fromBin;
|
|
26782
|
-
const fromSrc =
|
|
26783
|
-
if (
|
|
26811
|
+
const fromSrc = join6(__dirname3, "..", "..", "connectors");
|
|
26812
|
+
if (existsSync6(fromSrc))
|
|
26784
26813
|
return fromSrc;
|
|
26785
26814
|
return fromBin;
|
|
26786
26815
|
}
|
|
@@ -26820,9 +26849,9 @@ function buildEnvWithCredentials(connectorName, baseEnv) {
|
|
|
26820
26849
|
}
|
|
26821
26850
|
function getConnectorCliPath(name) {
|
|
26822
26851
|
const safeName = name.replace(/[^a-z0-9-]/g, "");
|
|
26823
|
-
const connectorDir =
|
|
26824
|
-
const cliPath =
|
|
26825
|
-
if (
|
|
26852
|
+
const connectorDir = join6(CONNECTORS_DIR2, `connect-${safeName}`);
|
|
26853
|
+
const cliPath = join6(connectorDir, "src", "cli", "index.ts");
|
|
26854
|
+
if (existsSync6(cliPath))
|
|
26826
26855
|
return cliPath;
|
|
26827
26856
|
return null;
|
|
26828
26857
|
}
|
|
@@ -27035,7 +27064,7 @@ init_strip();
|
|
|
27035
27064
|
// package.json
|
|
27036
27065
|
var package_default = {
|
|
27037
27066
|
name: "@hasna/connectors",
|
|
27038
|
-
version: "1.3.
|
|
27067
|
+
version: "1.3.8",
|
|
27039
27068
|
description: "Open source connector library - Install API connectors with a single command",
|
|
27040
27069
|
type: "module",
|
|
27041
27070
|
bin: {
|
|
@@ -27741,32 +27770,6 @@ server.registerTool("get_rate_budget", {
|
|
|
27741
27770
|
const result = getRateBudget(agent_id, connector, limit);
|
|
27742
27771
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
27743
27772
|
});
|
|
27744
|
-
var _agentReg = new Map;
|
|
27745
|
-
server.tool("register_agent", "Register this agent session. Returns agent_id for use in heartbeat/set_focus.", { name: exports_external.string(), session_id: exports_external.string().optional() }, async (a) => {
|
|
27746
|
-
const existing = [..._agentReg.values()].find((x) => x.name === a.name);
|
|
27747
|
-
if (existing) {
|
|
27748
|
-
existing.last_seen_at = new Date().toISOString();
|
|
27749
|
-
return { content: [{ type: "text", text: JSON.stringify(existing) }] };
|
|
27750
|
-
}
|
|
27751
|
-
const id = Math.random().toString(36).slice(2, 10);
|
|
27752
|
-
const ag = { id, name: a.name, last_seen_at: new Date().toISOString() };
|
|
27753
|
-
_agentReg.set(id, ag);
|
|
27754
|
-
return { content: [{ type: "text", text: JSON.stringify(ag) }] };
|
|
27755
|
-
});
|
|
27756
|
-
server.tool("heartbeat", "Update last_seen_at to signal agent is active.", { agent_id: exports_external.string() }, async (a) => {
|
|
27757
|
-
const ag = _agentReg.get(a.agent_id);
|
|
27758
|
-
if (!ag)
|
|
27759
|
-
return { content: [{ type: "text", text: `Agent not found: ${a.agent_id}` }], isError: true };
|
|
27760
|
-
ag.last_seen_at = new Date().toISOString();
|
|
27761
|
-
return { content: [{ type: "text", text: `\u2665 ${ag.name} \u2014 active` }] };
|
|
27762
|
-
});
|
|
27763
|
-
server.tool("set_focus", "Set active project context for this agent session.", { agent_id: exports_external.string(), project_id: exports_external.string().optional() }, async (a) => {
|
|
27764
|
-
const ag = _agentReg.get(a.agent_id);
|
|
27765
|
-
if (!ag)
|
|
27766
|
-
return { content: [{ type: "text", text: `Agent not found: ${a.agent_id}` }], isError: true };
|
|
27767
|
-
ag.project_id = a.project_id;
|
|
27768
|
-
return { content: [{ type: "text", text: a.project_id ? `Focus: ${a.project_id}` : "Focus cleared" }] };
|
|
27769
|
-
});
|
|
27770
27773
|
async function main() {
|
|
27771
27774
|
const transport = new StdioServerTransport;
|
|
27772
27775
|
await server.connect(transport);
|