@hasna/connectors 1.1.18 → 1.2.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/bin/index.js +1175 -290
- package/bin/mcp.js +701 -71
- package/bin/serve.js +768 -141
- package/dist/db/jobs.d.ts +53 -0
- package/dist/db/jobs.test.d.ts +1 -0
- package/dist/db/workflows.d.ts +26 -0
- package/dist/db/workflows.test.d.ts +1 -0
- package/dist/lib/llm.d.ts +38 -0
- package/dist/lib/llm.test.d.ts +1 -0
- package/dist/lib/scheduler.d.ts +20 -0
- package/dist/lib/scheduler.test.d.ts +1 -0
- package/dist/lib/strip.d.ts +20 -0
- package/dist/lib/strip.test.d.ts +1 -0
- package/dist/lib/workflow-runner.d.ts +22 -0
- package/package.json +1 -1
package/bin/mcp.js
CHANGED
|
@@ -26,6 +26,7 @@ var __export = (target, all) => {
|
|
|
26
26
|
set: (newValue) => all[name] = () => newValue
|
|
27
27
|
});
|
|
28
28
|
};
|
|
29
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
29
30
|
|
|
30
31
|
// node_modules/ajv/dist/compile/codegen/code.js
|
|
31
32
|
var require_code = __commonJS((exports) => {
|
|
@@ -6499,6 +6500,629 @@ var require_dist = __commonJS((exports, module) => {
|
|
|
6499
6500
|
exports.default = formatsPlugin;
|
|
6500
6501
|
});
|
|
6501
6502
|
|
|
6503
|
+
// src/db/database.ts
|
|
6504
|
+
var exports_database = {};
|
|
6505
|
+
__export(exports_database, {
|
|
6506
|
+
shortUuid: () => shortUuid,
|
|
6507
|
+
now: () => now,
|
|
6508
|
+
getDatabase: () => getDatabase,
|
|
6509
|
+
closeDatabase: () => closeDatabase
|
|
6510
|
+
});
|
|
6511
|
+
import { Database } from "bun:sqlite";
|
|
6512
|
+
import { join as join6 } from "path";
|
|
6513
|
+
import { homedir as homedir4 } from "os";
|
|
6514
|
+
import { mkdirSync as mkdirSync4 } from "fs";
|
|
6515
|
+
function getDatabase(path) {
|
|
6516
|
+
if (_db)
|
|
6517
|
+
return _db;
|
|
6518
|
+
const dbPath = path ?? DB_PATH;
|
|
6519
|
+
mkdirSync4(join6(dbPath, ".."), { recursive: true });
|
|
6520
|
+
_db = new Database(dbPath);
|
|
6521
|
+
_db.run("PRAGMA journal_mode = WAL");
|
|
6522
|
+
migrate(_db);
|
|
6523
|
+
return _db;
|
|
6524
|
+
}
|
|
6525
|
+
function closeDatabase() {
|
|
6526
|
+
_db?.close();
|
|
6527
|
+
_db = null;
|
|
6528
|
+
}
|
|
6529
|
+
function now() {
|
|
6530
|
+
return new Date().toISOString();
|
|
6531
|
+
}
|
|
6532
|
+
function shortUuid() {
|
|
6533
|
+
return crypto.randomUUID().slice(0, 8);
|
|
6534
|
+
}
|
|
6535
|
+
function migrate(db) {
|
|
6536
|
+
db.run(`
|
|
6537
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
6538
|
+
id TEXT PRIMARY KEY,
|
|
6539
|
+
name TEXT UNIQUE NOT NULL,
|
|
6540
|
+
session_id TEXT,
|
|
6541
|
+
role TEXT NOT NULL DEFAULT 'agent',
|
|
6542
|
+
last_seen_at TEXT NOT NULL,
|
|
6543
|
+
created_at TEXT NOT NULL
|
|
6544
|
+
)
|
|
6545
|
+
`);
|
|
6546
|
+
db.run(`
|
|
6547
|
+
CREATE TABLE IF NOT EXISTS resource_locks (
|
|
6548
|
+
id TEXT PRIMARY KEY,
|
|
6549
|
+
resource_type TEXT NOT NULL CHECK(resource_type IN ('connector', 'agent', 'profile', 'token')),
|
|
6550
|
+
resource_id TEXT NOT NULL,
|
|
6551
|
+
agent_id TEXT NOT NULL,
|
|
6552
|
+
lock_type TEXT NOT NULL DEFAULT 'exclusive' CHECK(lock_type IN ('advisory', 'exclusive')),
|
|
6553
|
+
locked_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
6554
|
+
expires_at TEXT NOT NULL
|
|
6555
|
+
)
|
|
6556
|
+
`);
|
|
6557
|
+
db.run(`
|
|
6558
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_resource_locks_exclusive
|
|
6559
|
+
ON resource_locks(resource_type, resource_id)
|
|
6560
|
+
WHERE lock_type = 'exclusive'
|
|
6561
|
+
`);
|
|
6562
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_resource_locks_agent ON resource_locks(agent_id)`);
|
|
6563
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_resource_locks_expires ON resource_locks(expires_at)`);
|
|
6564
|
+
db.run(`
|
|
6565
|
+
CREATE TABLE IF NOT EXISTS connector_rate_usage (
|
|
6566
|
+
agent_id TEXT NOT NULL,
|
|
6567
|
+
connector TEXT NOT NULL,
|
|
6568
|
+
window_start TEXT NOT NULL,
|
|
6569
|
+
call_count INTEGER NOT NULL DEFAULT 0,
|
|
6570
|
+
PRIMARY KEY (agent_id, connector, window_start)
|
|
6571
|
+
)
|
|
6572
|
+
`);
|
|
6573
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_rate_usage_window ON connector_rate_usage(connector, window_start)`);
|
|
6574
|
+
db.run(`
|
|
6575
|
+
CREATE TABLE IF NOT EXISTS connector_jobs (
|
|
6576
|
+
id TEXT PRIMARY KEY,
|
|
6577
|
+
name TEXT UNIQUE NOT NULL,
|
|
6578
|
+
connector TEXT NOT NULL,
|
|
6579
|
+
command TEXT NOT NULL,
|
|
6580
|
+
args TEXT NOT NULL DEFAULT '[]',
|
|
6581
|
+
cron TEXT NOT NULL,
|
|
6582
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
6583
|
+
strip INTEGER NOT NULL DEFAULT 0,
|
|
6584
|
+
created_at TEXT NOT NULL,
|
|
6585
|
+
last_run_at TEXT
|
|
6586
|
+
)
|
|
6587
|
+
`);
|
|
6588
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_jobs_enabled ON connector_jobs(enabled)`);
|
|
6589
|
+
db.run(`
|
|
6590
|
+
CREATE TABLE IF NOT EXISTS connector_job_runs (
|
|
6591
|
+
id TEXT PRIMARY KEY,
|
|
6592
|
+
job_id TEXT NOT NULL REFERENCES connector_jobs(id) ON DELETE CASCADE,
|
|
6593
|
+
started_at TEXT NOT NULL,
|
|
6594
|
+
finished_at TEXT,
|
|
6595
|
+
exit_code INTEGER,
|
|
6596
|
+
raw_output TEXT,
|
|
6597
|
+
stripped_output TEXT
|
|
6598
|
+
)
|
|
6599
|
+
`);
|
|
6600
|
+
db.run(`CREATE INDEX IF NOT EXISTS idx_job_runs_job ON connector_job_runs(job_id, started_at DESC)`);
|
|
6601
|
+
db.run(`
|
|
6602
|
+
CREATE TABLE IF NOT EXISTS connector_workflows (
|
|
6603
|
+
id TEXT PRIMARY KEY,
|
|
6604
|
+
name TEXT UNIQUE NOT NULL,
|
|
6605
|
+
steps TEXT NOT NULL DEFAULT '[]',
|
|
6606
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
6607
|
+
created_at TEXT NOT NULL
|
|
6608
|
+
)
|
|
6609
|
+
`);
|
|
6610
|
+
}
|
|
6611
|
+
var DB_DIR, DB_PATH, _db = null;
|
|
6612
|
+
var init_database = __esm(() => {
|
|
6613
|
+
DB_DIR = join6(homedir4(), ".connectors");
|
|
6614
|
+
DB_PATH = join6(DB_DIR, "connectors.db");
|
|
6615
|
+
});
|
|
6616
|
+
|
|
6617
|
+
// src/lib/llm.ts
|
|
6618
|
+
var exports_llm = {};
|
|
6619
|
+
__export(exports_llm, {
|
|
6620
|
+
setLlmStrip: () => setLlmStrip,
|
|
6621
|
+
saveLlmConfig: () => saveLlmConfig,
|
|
6622
|
+
maskKey: () => maskKey,
|
|
6623
|
+
isStripEnabled: () => isStripEnabled,
|
|
6624
|
+
getLlmConfig: () => getLlmConfig,
|
|
6625
|
+
PROVIDER_DEFAULTS: () => PROVIDER_DEFAULTS,
|
|
6626
|
+
LLMClient: () => LLMClient
|
|
6627
|
+
});
|
|
6628
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync5 } from "fs";
|
|
6629
|
+
import { join as join7 } from "path";
|
|
6630
|
+
import { homedir as homedir5 } from "os";
|
|
6631
|
+
function getLlmConfigPath() {
|
|
6632
|
+
return join7(homedir5(), ".connectors", "llm.json");
|
|
6633
|
+
}
|
|
6634
|
+
function getLlmConfig() {
|
|
6635
|
+
const path = getLlmConfigPath();
|
|
6636
|
+
if (!existsSync6(path))
|
|
6637
|
+
return null;
|
|
6638
|
+
try {
|
|
6639
|
+
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
6640
|
+
} catch {
|
|
6641
|
+
return null;
|
|
6642
|
+
}
|
|
6643
|
+
}
|
|
6644
|
+
function saveLlmConfig(config2) {
|
|
6645
|
+
const dir = join7(homedir5(), ".connectors");
|
|
6646
|
+
mkdirSync5(dir, { recursive: true });
|
|
6647
|
+
writeFileSync3(getLlmConfigPath(), JSON.stringify(config2, null, 2));
|
|
6648
|
+
}
|
|
6649
|
+
function setLlmStrip(enabled) {
|
|
6650
|
+
const config2 = getLlmConfig();
|
|
6651
|
+
if (!config2)
|
|
6652
|
+
throw new Error("No LLM config found. Run: connectors llm set --provider <provider> --key <key>");
|
|
6653
|
+
saveLlmConfig({ ...config2, strip: enabled });
|
|
6654
|
+
}
|
|
6655
|
+
function isStripEnabled() {
|
|
6656
|
+
return getLlmConfig()?.strip === true;
|
|
6657
|
+
}
|
|
6658
|
+
function maskKey(key) {
|
|
6659
|
+
if (key.length <= 8)
|
|
6660
|
+
return "***";
|
|
6661
|
+
return key.slice(0, 8) + "***";
|
|
6662
|
+
}
|
|
6663
|
+
|
|
6664
|
+
class LLMClient {
|
|
6665
|
+
config;
|
|
6666
|
+
constructor(config2) {
|
|
6667
|
+
this.config = config2;
|
|
6668
|
+
}
|
|
6669
|
+
static fromConfig() {
|
|
6670
|
+
const config2 = getLlmConfig();
|
|
6671
|
+
if (!config2)
|
|
6672
|
+
return null;
|
|
6673
|
+
return new LLMClient(config2);
|
|
6674
|
+
}
|
|
6675
|
+
async complete(prompt, content) {
|
|
6676
|
+
const start = Date.now();
|
|
6677
|
+
const { provider, model, api_key } = this.config;
|
|
6678
|
+
if (provider === "anthropic") {
|
|
6679
|
+
return this._anthropicComplete(prompt, content, start);
|
|
6680
|
+
}
|
|
6681
|
+
const baseUrl = PROVIDER_BASE_URLS[provider];
|
|
6682
|
+
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
6683
|
+
method: "POST",
|
|
6684
|
+
headers: {
|
|
6685
|
+
"Content-Type": "application/json",
|
|
6686
|
+
Authorization: `Bearer ${api_key}`
|
|
6687
|
+
},
|
|
6688
|
+
body: JSON.stringify({
|
|
6689
|
+
model,
|
|
6690
|
+
messages: [
|
|
6691
|
+
{ role: "system", content: prompt },
|
|
6692
|
+
{ role: "user", content }
|
|
6693
|
+
],
|
|
6694
|
+
temperature: 0,
|
|
6695
|
+
max_tokens: 4096
|
|
6696
|
+
})
|
|
6697
|
+
});
|
|
6698
|
+
if (!response.ok) {
|
|
6699
|
+
const error2 = await response.text();
|
|
6700
|
+
throw new Error(`LLM request failed (${provider} ${response.status}): ${error2}`);
|
|
6701
|
+
}
|
|
6702
|
+
const data = await response.json();
|
|
6703
|
+
return {
|
|
6704
|
+
content: data.choices[0].message.content,
|
|
6705
|
+
provider,
|
|
6706
|
+
model,
|
|
6707
|
+
latency_ms: Date.now() - start
|
|
6708
|
+
};
|
|
6709
|
+
}
|
|
6710
|
+
async _anthropicComplete(prompt, content, start) {
|
|
6711
|
+
const { model, api_key } = this.config;
|
|
6712
|
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
6713
|
+
method: "POST",
|
|
6714
|
+
headers: {
|
|
6715
|
+
"Content-Type": "application/json",
|
|
6716
|
+
"x-api-key": api_key,
|
|
6717
|
+
"anthropic-version": "2023-06-01"
|
|
6718
|
+
},
|
|
6719
|
+
body: JSON.stringify({
|
|
6720
|
+
model,
|
|
6721
|
+
system: prompt,
|
|
6722
|
+
messages: [{ role: "user", content }],
|
|
6723
|
+
max_tokens: 4096
|
|
6724
|
+
})
|
|
6725
|
+
});
|
|
6726
|
+
if (!response.ok) {
|
|
6727
|
+
const error2 = await response.text();
|
|
6728
|
+
throw new Error(`LLM request failed (anthropic ${response.status}): ${error2}`);
|
|
6729
|
+
}
|
|
6730
|
+
const data = await response.json();
|
|
6731
|
+
return {
|
|
6732
|
+
content: data.content[0].text,
|
|
6733
|
+
provider: "anthropic",
|
|
6734
|
+
model,
|
|
6735
|
+
latency_ms: Date.now() - start
|
|
6736
|
+
};
|
|
6737
|
+
}
|
|
6738
|
+
}
|
|
6739
|
+
var PROVIDER_BASE_URLS, PROVIDER_DEFAULTS;
|
|
6740
|
+
var init_llm = __esm(() => {
|
|
6741
|
+
PROVIDER_BASE_URLS = {
|
|
6742
|
+
cerebras: "https://api.cerebras.ai/v1",
|
|
6743
|
+
groq: "https://api.groq.com/openai/v1",
|
|
6744
|
+
openai: "https://api.openai.com/v1"
|
|
6745
|
+
};
|
|
6746
|
+
PROVIDER_DEFAULTS = {
|
|
6747
|
+
cerebras: { model: "qwen-3-32b" },
|
|
6748
|
+
groq: { model: "llama-3.3-70b-versatile" },
|
|
6749
|
+
openai: { model: "gpt-4o-mini" },
|
|
6750
|
+
anthropic: { model: "claude-haiku-4-5-20251001" }
|
|
6751
|
+
};
|
|
6752
|
+
});
|
|
6753
|
+
|
|
6754
|
+
// src/lib/strip.ts
|
|
6755
|
+
async function maybeStrip(output, _type = "json") {
|
|
6756
|
+
const config2 = getLlmConfig();
|
|
6757
|
+
if (!config2?.strip)
|
|
6758
|
+
return output;
|
|
6759
|
+
if (!output || output.trim().length === 0)
|
|
6760
|
+
return output;
|
|
6761
|
+
const client = LLMClient.fromConfig();
|
|
6762
|
+
if (!client)
|
|
6763
|
+
return output;
|
|
6764
|
+
try {
|
|
6765
|
+
const result = await client.complete(STRIP_PROMPT, output);
|
|
6766
|
+
return result.content.trim();
|
|
6767
|
+
} catch {
|
|
6768
|
+
return output;
|
|
6769
|
+
}
|
|
6770
|
+
}
|
|
6771
|
+
var STRIP_PROMPT = `You are a data extraction assistant. Your job is to take raw API output and return ONLY the essential, structured data.
|
|
6772
|
+
|
|
6773
|
+
Rules:
|
|
6774
|
+
- Return valid JSON only (no markdown, no explanation)
|
|
6775
|
+
- Remove pagination metadata, rate limit headers, empty fields, null values
|
|
6776
|
+
- Keep all meaningful data fields
|
|
6777
|
+
- If the input is already minimal, return it unchanged
|
|
6778
|
+
- If input is not JSON, extract key facts as a JSON object
|
|
6779
|
+
- Never truncate actual data values`;
|
|
6780
|
+
var init_strip = __esm(() => {
|
|
6781
|
+
init_llm();
|
|
6782
|
+
});
|
|
6783
|
+
|
|
6784
|
+
// src/db/jobs.ts
|
|
6785
|
+
var exports_jobs = {};
|
|
6786
|
+
__export(exports_jobs, {
|
|
6787
|
+
updateJob: () => updateJob,
|
|
6788
|
+
touchJobLastRun: () => touchJobLastRun,
|
|
6789
|
+
listJobs: () => listJobs,
|
|
6790
|
+
listJobRuns: () => listJobRuns,
|
|
6791
|
+
listEnabledJobs: () => listEnabledJobs,
|
|
6792
|
+
getLatestRun: () => getLatestRun,
|
|
6793
|
+
getJobByName: () => getJobByName,
|
|
6794
|
+
getJob: () => getJob,
|
|
6795
|
+
finishJobRun: () => finishJobRun,
|
|
6796
|
+
deleteJob: () => deleteJob,
|
|
6797
|
+
createJobRun: () => createJobRun,
|
|
6798
|
+
createJob: () => createJob
|
|
6799
|
+
});
|
|
6800
|
+
function rowToJob(row) {
|
|
6801
|
+
return {
|
|
6802
|
+
...row,
|
|
6803
|
+
args: JSON.parse(row.args || "[]"),
|
|
6804
|
+
enabled: row.enabled === 1,
|
|
6805
|
+
strip: row.strip === 1
|
|
6806
|
+
};
|
|
6807
|
+
}
|
|
6808
|
+
function createJob(input, db) {
|
|
6809
|
+
const d = db ?? getDatabase();
|
|
6810
|
+
const id = shortUuid();
|
|
6811
|
+
const ts = now();
|
|
6812
|
+
d.run("INSERT INTO connector_jobs (id, name, connector, command, args, cron, enabled, strip, created_at) VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?)", [id, input.name, input.connector, input.command, JSON.stringify(input.args ?? []), input.cron, input.strip ? 1 : 0, ts]);
|
|
6813
|
+
return getJob(id, d);
|
|
6814
|
+
}
|
|
6815
|
+
function getJob(id, db) {
|
|
6816
|
+
const d = db ?? getDatabase();
|
|
6817
|
+
const row = d.query("SELECT * FROM connector_jobs WHERE id = ?").get(id);
|
|
6818
|
+
return row ? rowToJob(row) : null;
|
|
6819
|
+
}
|
|
6820
|
+
function getJobByName(name, db) {
|
|
6821
|
+
const d = db ?? getDatabase();
|
|
6822
|
+
const row = d.query("SELECT * FROM connector_jobs WHERE name = ?").get(name);
|
|
6823
|
+
return row ? rowToJob(row) : null;
|
|
6824
|
+
}
|
|
6825
|
+
function listJobs(db) {
|
|
6826
|
+
const d = db ?? getDatabase();
|
|
6827
|
+
return d.query("SELECT * FROM connector_jobs ORDER BY name").all().map(rowToJob);
|
|
6828
|
+
}
|
|
6829
|
+
function listEnabledJobs(db) {
|
|
6830
|
+
const d = db ?? getDatabase();
|
|
6831
|
+
return d.query("SELECT * FROM connector_jobs WHERE enabled = 1").all().map(rowToJob);
|
|
6832
|
+
}
|
|
6833
|
+
function updateJob(id, input, db) {
|
|
6834
|
+
const d = db ?? getDatabase();
|
|
6835
|
+
const sets = [];
|
|
6836
|
+
const params = [];
|
|
6837
|
+
if (input.name !== undefined) {
|
|
6838
|
+
sets.push("name = ?");
|
|
6839
|
+
params.push(input.name);
|
|
6840
|
+
}
|
|
6841
|
+
if (input.connector !== undefined) {
|
|
6842
|
+
sets.push("connector = ?");
|
|
6843
|
+
params.push(input.connector);
|
|
6844
|
+
}
|
|
6845
|
+
if (input.command !== undefined) {
|
|
6846
|
+
sets.push("command = ?");
|
|
6847
|
+
params.push(input.command);
|
|
6848
|
+
}
|
|
6849
|
+
if (input.args !== undefined) {
|
|
6850
|
+
sets.push("args = ?");
|
|
6851
|
+
params.push(JSON.stringify(input.args));
|
|
6852
|
+
}
|
|
6853
|
+
if (input.cron !== undefined) {
|
|
6854
|
+
sets.push("cron = ?");
|
|
6855
|
+
params.push(input.cron);
|
|
6856
|
+
}
|
|
6857
|
+
if (input.enabled !== undefined) {
|
|
6858
|
+
sets.push("enabled = ?");
|
|
6859
|
+
params.push(input.enabled ? 1 : 0);
|
|
6860
|
+
}
|
|
6861
|
+
if (input.strip !== undefined) {
|
|
6862
|
+
sets.push("strip = ?");
|
|
6863
|
+
params.push(input.strip ? 1 : 0);
|
|
6864
|
+
}
|
|
6865
|
+
if (sets.length === 0)
|
|
6866
|
+
return getJob(id, d);
|
|
6867
|
+
params.push(id);
|
|
6868
|
+
d.run(`UPDATE connector_jobs SET ${sets.join(", ")} WHERE id = ?`, params);
|
|
6869
|
+
return getJob(id, d);
|
|
6870
|
+
}
|
|
6871
|
+
function deleteJob(id, db) {
|
|
6872
|
+
const d = db ?? getDatabase();
|
|
6873
|
+
return d.run("DELETE FROM connector_jobs WHERE id = ?", [id]).changes > 0;
|
|
6874
|
+
}
|
|
6875
|
+
function touchJobLastRun(id, db) {
|
|
6876
|
+
const d = db ?? getDatabase();
|
|
6877
|
+
d.run("UPDATE connector_jobs SET last_run_at = ? WHERE id = ?", [now(), id]);
|
|
6878
|
+
}
|
|
6879
|
+
function createJobRun(jobId, db) {
|
|
6880
|
+
const d = db ?? getDatabase();
|
|
6881
|
+
const id = shortUuid();
|
|
6882
|
+
const ts = now();
|
|
6883
|
+
d.run("INSERT INTO connector_job_runs (id, job_id, started_at) VALUES (?, ?, ?)", [id, jobId, ts]);
|
|
6884
|
+
return { id, job_id: jobId, started_at: ts, finished_at: null, exit_code: null, raw_output: null, stripped_output: null };
|
|
6885
|
+
}
|
|
6886
|
+
function finishJobRun(id, result, db) {
|
|
6887
|
+
const d = db ?? getDatabase();
|
|
6888
|
+
d.run("UPDATE connector_job_runs SET finished_at = ?, exit_code = ?, raw_output = ?, stripped_output = ? WHERE id = ?", [now(), result.exit_code, result.raw_output, result.stripped_output ?? null, id]);
|
|
6889
|
+
}
|
|
6890
|
+
function getLatestRun(jobId, db) {
|
|
6891
|
+
const d = db ?? getDatabase();
|
|
6892
|
+
return d.query("SELECT * FROM connector_job_runs WHERE job_id = ? ORDER BY started_at DESC LIMIT 1").get(jobId);
|
|
6893
|
+
}
|
|
6894
|
+
function listJobRuns(jobId, limit = 20, db) {
|
|
6895
|
+
const d = db ?? getDatabase();
|
|
6896
|
+
return d.query("SELECT * FROM connector_job_runs WHERE job_id = ? ORDER BY started_at DESC LIMIT ?").all(jobId, limit);
|
|
6897
|
+
}
|
|
6898
|
+
var init_jobs = __esm(() => {
|
|
6899
|
+
init_database();
|
|
6900
|
+
});
|
|
6901
|
+
|
|
6902
|
+
// src/lib/scheduler.ts
|
|
6903
|
+
var exports_scheduler = {};
|
|
6904
|
+
__export(exports_scheduler, {
|
|
6905
|
+
triggerJob: () => triggerJob,
|
|
6906
|
+
stopScheduler: () => stopScheduler,
|
|
6907
|
+
startScheduler: () => startScheduler
|
|
6908
|
+
});
|
|
6909
|
+
import { spawn as spawn2 } from "child_process";
|
|
6910
|
+
function cronMatches(cron, d) {
|
|
6911
|
+
const parts = cron.trim().split(/\s+/);
|
|
6912
|
+
if (parts.length !== 5)
|
|
6913
|
+
return false;
|
|
6914
|
+
const [min, hour, dom, mon, dow] = parts;
|
|
6915
|
+
function matches(field, value, min_v, max_v) {
|
|
6916
|
+
if (field === "*")
|
|
6917
|
+
return true;
|
|
6918
|
+
if (field.startsWith("*/")) {
|
|
6919
|
+
const step = parseInt(field.slice(2));
|
|
6920
|
+
return value % step === 0;
|
|
6921
|
+
}
|
|
6922
|
+
if (field.includes("-")) {
|
|
6923
|
+
const [a, b] = field.split("-").map(Number);
|
|
6924
|
+
return value >= a && value <= b;
|
|
6925
|
+
}
|
|
6926
|
+
if (field.includes(",")) {
|
|
6927
|
+
return field.split(",").map(Number).includes(value);
|
|
6928
|
+
}
|
|
6929
|
+
return parseInt(field) === value;
|
|
6930
|
+
}
|
|
6931
|
+
return matches(min, d.getMinutes(), 0, 59) && matches(hour, d.getHours(), 0, 23) && matches(dom, d.getDate(), 1, 31) && matches(mon, d.getMonth() + 1, 1, 12) && matches(dow, d.getDay(), 0, 6);
|
|
6932
|
+
}
|
|
6933
|
+
async function runConnectorCommand2(connector, command, args) {
|
|
6934
|
+
return new Promise((resolve) => {
|
|
6935
|
+
const cmdArgs = [connector, command, ...args, "--format", "json"];
|
|
6936
|
+
const proc = spawn2("connectors", ["run", ...cmdArgs], { shell: false });
|
|
6937
|
+
let output = "";
|
|
6938
|
+
proc.stdout.on("data", (d) => {
|
|
6939
|
+
output += d.toString();
|
|
6940
|
+
});
|
|
6941
|
+
proc.stderr.on("data", (d) => {
|
|
6942
|
+
output += d.toString();
|
|
6943
|
+
});
|
|
6944
|
+
proc.on("close", (code) => resolve({ exitCode: code ?? 1, output }));
|
|
6945
|
+
proc.on("error", () => resolve({ exitCode: 1, output: `Failed to spawn connectors run` }));
|
|
6946
|
+
setTimeout(() => {
|
|
6947
|
+
proc.kill();
|
|
6948
|
+
resolve({ exitCode: 124, output: output + `
|
|
6949
|
+
[timeout]` });
|
|
6950
|
+
}, 60000);
|
|
6951
|
+
});
|
|
6952
|
+
}
|
|
6953
|
+
async function executeJob(job, db) {
|
|
6954
|
+
const run = createJobRun(job.id, db);
|
|
6955
|
+
try {
|
|
6956
|
+
const { exitCode, output } = await runConnectorCommand2(job.connector, job.command, job.args);
|
|
6957
|
+
const stripped = job.strip ? await maybeStrip(output) : undefined;
|
|
6958
|
+
finishJobRun(run.id, { exit_code: exitCode, raw_output: output, stripped_output: stripped }, db);
|
|
6959
|
+
touchJobLastRun(job.id, db);
|
|
6960
|
+
} catch (e) {
|
|
6961
|
+
finishJobRun(run.id, { exit_code: 1, raw_output: String(e) }, db);
|
|
6962
|
+
}
|
|
6963
|
+
}
|
|
6964
|
+
function startScheduler(db) {
|
|
6965
|
+
if (_interval)
|
|
6966
|
+
return;
|
|
6967
|
+
_interval = setInterval(async () => {
|
|
6968
|
+
const now3 = new Date;
|
|
6969
|
+
const currentMinute = now3.getMinutes() + now3.getHours() * 60;
|
|
6970
|
+
if (currentMinute === _lastCheckedMinute)
|
|
6971
|
+
return;
|
|
6972
|
+
_lastCheckedMinute = currentMinute;
|
|
6973
|
+
const jobs = listEnabledJobs(db);
|
|
6974
|
+
for (const job of jobs) {
|
|
6975
|
+
if (cronMatches(job.cron, now3)) {
|
|
6976
|
+
executeJob(job, db).catch(() => {});
|
|
6977
|
+
}
|
|
6978
|
+
}
|
|
6979
|
+
}, 30000);
|
|
6980
|
+
}
|
|
6981
|
+
function stopScheduler() {
|
|
6982
|
+
if (_interval) {
|
|
6983
|
+
clearInterval(_interval);
|
|
6984
|
+
_interval = null;
|
|
6985
|
+
_lastCheckedMinute = -1;
|
|
6986
|
+
}
|
|
6987
|
+
}
|
|
6988
|
+
async function triggerJob(job, db) {
|
|
6989
|
+
const run = createJobRun(job.id, db);
|
|
6990
|
+
const { exitCode, output } = await runConnectorCommand2(job.connector, job.command, job.args);
|
|
6991
|
+
const stripped = job.strip ? await maybeStrip(output) : undefined;
|
|
6992
|
+
finishJobRun(run.id, { exit_code: exitCode, raw_output: output, stripped_output: stripped }, db);
|
|
6993
|
+
touchJobLastRun(job.id, db);
|
|
6994
|
+
return { run_id: run.id, exit_code: exitCode, output: stripped ?? output };
|
|
6995
|
+
}
|
|
6996
|
+
var _interval = null, _lastCheckedMinute = -1;
|
|
6997
|
+
var init_scheduler = __esm(() => {
|
|
6998
|
+
init_jobs();
|
|
6999
|
+
init_strip();
|
|
7000
|
+
});
|
|
7001
|
+
|
|
7002
|
+
// src/db/workflows.ts
|
|
7003
|
+
var exports_workflows = {};
|
|
7004
|
+
__export(exports_workflows, {
|
|
7005
|
+
updateWorkflow: () => updateWorkflow,
|
|
7006
|
+
listWorkflows: () => listWorkflows,
|
|
7007
|
+
getWorkflowByName: () => getWorkflowByName,
|
|
7008
|
+
getWorkflow: () => getWorkflow,
|
|
7009
|
+
deleteWorkflow: () => deleteWorkflow,
|
|
7010
|
+
createWorkflow: () => createWorkflow
|
|
7011
|
+
});
|
|
7012
|
+
function rowToWorkflow(row) {
|
|
7013
|
+
return {
|
|
7014
|
+
...row,
|
|
7015
|
+
steps: JSON.parse(row.steps || "[]"),
|
|
7016
|
+
enabled: row.enabled === 1
|
|
7017
|
+
};
|
|
7018
|
+
}
|
|
7019
|
+
function createWorkflow(input, db) {
|
|
7020
|
+
const d = db ?? getDatabase();
|
|
7021
|
+
const id = shortUuid();
|
|
7022
|
+
d.run("INSERT INTO connector_workflows (id, name, steps, enabled, created_at) VALUES (?, ?, ?, 1, ?)", [id, input.name, JSON.stringify(input.steps), now()]);
|
|
7023
|
+
return getWorkflow(id, d);
|
|
7024
|
+
}
|
|
7025
|
+
function getWorkflow(id, db) {
|
|
7026
|
+
const d = db ?? getDatabase();
|
|
7027
|
+
const row = d.query("SELECT * FROM connector_workflows WHERE id = ?").get(id);
|
|
7028
|
+
return row ? rowToWorkflow(row) : null;
|
|
7029
|
+
}
|
|
7030
|
+
function getWorkflowByName(name, db) {
|
|
7031
|
+
const d = db ?? getDatabase();
|
|
7032
|
+
const row = d.query("SELECT * FROM connector_workflows WHERE name = ?").get(name);
|
|
7033
|
+
return row ? rowToWorkflow(row) : null;
|
|
7034
|
+
}
|
|
7035
|
+
function listWorkflows(db) {
|
|
7036
|
+
const d = db ?? getDatabase();
|
|
7037
|
+
return d.query("SELECT * FROM connector_workflows ORDER BY name").all().map(rowToWorkflow);
|
|
7038
|
+
}
|
|
7039
|
+
function updateWorkflow(id, input, db) {
|
|
7040
|
+
const d = db ?? getDatabase();
|
|
7041
|
+
const sets = [];
|
|
7042
|
+
const params = [];
|
|
7043
|
+
if (input.name !== undefined) {
|
|
7044
|
+
sets.push("name = ?");
|
|
7045
|
+
params.push(input.name);
|
|
7046
|
+
}
|
|
7047
|
+
if (input.steps !== undefined) {
|
|
7048
|
+
sets.push("steps = ?");
|
|
7049
|
+
params.push(JSON.stringify(input.steps));
|
|
7050
|
+
}
|
|
7051
|
+
if (input.enabled !== undefined) {
|
|
7052
|
+
sets.push("enabled = ?");
|
|
7053
|
+
params.push(input.enabled ? 1 : 0);
|
|
7054
|
+
}
|
|
7055
|
+
if (sets.length === 0)
|
|
7056
|
+
return getWorkflow(id, d);
|
|
7057
|
+
params.push(id);
|
|
7058
|
+
d.run(`UPDATE connector_workflows SET ${sets.join(", ")} WHERE id = ?`, params);
|
|
7059
|
+
return getWorkflow(id, d);
|
|
7060
|
+
}
|
|
7061
|
+
function deleteWorkflow(id, db) {
|
|
7062
|
+
const d = db ?? getDatabase();
|
|
7063
|
+
return d.run("DELETE FROM connector_workflows WHERE id = ?", [id]).changes > 0;
|
|
7064
|
+
}
|
|
7065
|
+
var init_workflows = __esm(() => {
|
|
7066
|
+
init_database();
|
|
7067
|
+
});
|
|
7068
|
+
|
|
7069
|
+
// src/lib/workflow-runner.ts
|
|
7070
|
+
var exports_workflow_runner = {};
|
|
7071
|
+
__export(exports_workflow_runner, {
|
|
7072
|
+
runWorkflow: () => runWorkflow
|
|
7073
|
+
});
|
|
7074
|
+
import { spawn as spawn3 } from "child_process";
|
|
7075
|
+
async function runStep(step, previousOutput) {
|
|
7076
|
+
return new Promise((resolve) => {
|
|
7077
|
+
const args = [...step.args ?? []];
|
|
7078
|
+
if (previousOutput && previousOutput.trim()) {
|
|
7079
|
+
args.push("--input", previousOutput.trim().slice(0, 4096));
|
|
7080
|
+
}
|
|
7081
|
+
const cmdArgs = ["run", step.connector, step.command, ...args, "--format", "json"];
|
|
7082
|
+
const proc = spawn3("connectors", cmdArgs, { shell: false });
|
|
7083
|
+
let output = "";
|
|
7084
|
+
proc.stdout.on("data", (d) => {
|
|
7085
|
+
output += d.toString();
|
|
7086
|
+
});
|
|
7087
|
+
proc.stderr.on("data", (d) => {
|
|
7088
|
+
output += d.toString();
|
|
7089
|
+
});
|
|
7090
|
+
proc.on("close", (code) => resolve({ exitCode: code ?? 1, output }));
|
|
7091
|
+
proc.on("error", () => resolve({ exitCode: 1, output: "Failed to spawn connectors" }));
|
|
7092
|
+
setTimeout(() => {
|
|
7093
|
+
proc.kill();
|
|
7094
|
+
resolve({ exitCode: 124, output: output + `
|
|
7095
|
+
[timeout]` });
|
|
7096
|
+
}, 60000);
|
|
7097
|
+
});
|
|
7098
|
+
}
|
|
7099
|
+
async function runWorkflow(workflow) {
|
|
7100
|
+
const results = [];
|
|
7101
|
+
let previousOutput;
|
|
7102
|
+
let success = true;
|
|
7103
|
+
for (let i = 0;i < workflow.steps.length; i++) {
|
|
7104
|
+
const step = workflow.steps[i];
|
|
7105
|
+
const { exitCode, output } = await runStep(step, previousOutput);
|
|
7106
|
+
const stripped = await maybeStrip(output);
|
|
7107
|
+
results.push({ step: i + 1, connector: step.connector, command: step.command, exit_code: exitCode, output: stripped });
|
|
7108
|
+
if (exitCode !== 0) {
|
|
7109
|
+
success = false;
|
|
7110
|
+
break;
|
|
7111
|
+
}
|
|
7112
|
+
previousOutput = stripped;
|
|
7113
|
+
}
|
|
7114
|
+
return {
|
|
7115
|
+
workflow_id: workflow.id,
|
|
7116
|
+
workflow_name: workflow.name,
|
|
7117
|
+
steps: results,
|
|
7118
|
+
success,
|
|
7119
|
+
final_output: results[results.length - 1]?.output ?? ""
|
|
7120
|
+
};
|
|
7121
|
+
}
|
|
7122
|
+
var init_workflow_runner = __esm(() => {
|
|
7123
|
+
init_strip();
|
|
7124
|
+
});
|
|
7125
|
+
|
|
6502
7126
|
// node_modules/zod/v3/external.js
|
|
6503
7127
|
var exports_external = {};
|
|
6504
7128
|
__export(exports_external, {
|
|
@@ -25975,61 +26599,10 @@ async function getConnectorCommandHelp(name, command) {
|
|
|
25975
26599
|
return result.stdout || result.stderr;
|
|
25976
26600
|
}
|
|
25977
26601
|
|
|
25978
|
-
// src/db/database.ts
|
|
25979
|
-
import { Database } from "bun:sqlite";
|
|
25980
|
-
import { join as join6 } from "path";
|
|
25981
|
-
import { homedir as homedir4 } from "os";
|
|
25982
|
-
import { mkdirSync as mkdirSync4 } from "fs";
|
|
25983
|
-
var DB_DIR = join6(homedir4(), ".connectors");
|
|
25984
|
-
var DB_PATH = join6(DB_DIR, "connectors.db");
|
|
25985
|
-
var _db = null;
|
|
25986
|
-
function getDatabase(path) {
|
|
25987
|
-
if (_db)
|
|
25988
|
-
return _db;
|
|
25989
|
-
const dbPath = path ?? DB_PATH;
|
|
25990
|
-
mkdirSync4(join6(dbPath, ".."), { recursive: true });
|
|
25991
|
-
_db = new Database(dbPath);
|
|
25992
|
-
_db.run("PRAGMA journal_mode = WAL");
|
|
25993
|
-
migrate(_db);
|
|
25994
|
-
return _db;
|
|
25995
|
-
}
|
|
25996
|
-
function now() {
|
|
25997
|
-
return new Date().toISOString();
|
|
25998
|
-
}
|
|
25999
|
-
function migrate(db) {
|
|
26000
|
-
db.run(`
|
|
26001
|
-
CREATE TABLE IF NOT EXISTS agents (
|
|
26002
|
-
id TEXT PRIMARY KEY,
|
|
26003
|
-
name TEXT UNIQUE NOT NULL,
|
|
26004
|
-
session_id TEXT,
|
|
26005
|
-
role TEXT NOT NULL DEFAULT 'agent',
|
|
26006
|
-
last_seen_at TEXT NOT NULL,
|
|
26007
|
-
created_at TEXT NOT NULL
|
|
26008
|
-
)
|
|
26009
|
-
`);
|
|
26010
|
-
db.run(`
|
|
26011
|
-
CREATE TABLE IF NOT EXISTS resource_locks (
|
|
26012
|
-
id TEXT PRIMARY KEY,
|
|
26013
|
-
resource_type TEXT NOT NULL CHECK(resource_type IN ('connector', 'agent', 'profile', 'token')),
|
|
26014
|
-
resource_id TEXT NOT NULL,
|
|
26015
|
-
agent_id TEXT NOT NULL,
|
|
26016
|
-
lock_type TEXT NOT NULL DEFAULT 'exclusive' CHECK(lock_type IN ('advisory', 'exclusive')),
|
|
26017
|
-
locked_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
26018
|
-
expires_at TEXT NOT NULL
|
|
26019
|
-
)
|
|
26020
|
-
`);
|
|
26021
|
-
db.run(`
|
|
26022
|
-
CREATE UNIQUE INDEX IF NOT EXISTS idx_resource_locks_exclusive
|
|
26023
|
-
ON resource_locks(resource_type, resource_id)
|
|
26024
|
-
WHERE lock_type = 'exclusive'
|
|
26025
|
-
`);
|
|
26026
|
-
db.run(`CREATE INDEX IF NOT EXISTS idx_resource_locks_agent ON resource_locks(agent_id)`);
|
|
26027
|
-
db.run(`CREATE INDEX IF NOT EXISTS idx_resource_locks_expires ON resource_locks(expires_at)`);
|
|
26028
|
-
}
|
|
26029
|
-
|
|
26030
26602
|
// src/db/agents.ts
|
|
26603
|
+
init_database();
|
|
26031
26604
|
var AGENT_ACTIVE_WINDOW_MS = 30 * 60 * 1000;
|
|
26032
|
-
function
|
|
26605
|
+
function shortUuid2() {
|
|
26033
26606
|
return crypto.randomUUID().slice(0, 8);
|
|
26034
26607
|
}
|
|
26035
26608
|
function isAgentConflict(result) {
|
|
@@ -26066,7 +26639,7 @@ function registerAgent(input, db) {
|
|
|
26066
26639
|
d.run(`UPDATE agents SET ${updates.join(", ")} WHERE id = ?`, params);
|
|
26067
26640
|
return getAgent(existing.id, d);
|
|
26068
26641
|
}
|
|
26069
|
-
const id =
|
|
26642
|
+
const id = shortUuid2();
|
|
26070
26643
|
const ts = now();
|
|
26071
26644
|
d.run(`INSERT INTO agents (id, name, session_id, role, last_seen_at, created_at)
|
|
26072
26645
|
VALUES (?, ?, ?, ?, ?, ?)`, [id, normalizedName, input.session_id ?? null, input.role ?? "agent", ts, ts]);
|
|
@@ -26086,6 +26659,7 @@ function listAgents(db) {
|
|
|
26086
26659
|
}
|
|
26087
26660
|
|
|
26088
26661
|
// src/db/rate.ts
|
|
26662
|
+
init_database();
|
|
26089
26663
|
var AGENT_ACTIVE_WINDOW_MS2 = 30 * 60 * 1000;
|
|
26090
26664
|
var WINDOW_SECONDS = 60;
|
|
26091
26665
|
function ensureRateTable(db) {
|
|
@@ -26153,6 +26727,9 @@ function checkRateBudget(agentId, connector, connectorLimit, consume = true, db)
|
|
|
26153
26727
|
function getRateBudget(agentId, connector, connectorLimit, db) {
|
|
26154
26728
|
return checkRateBudget(agentId, connector, connectorLimit, false, db);
|
|
26155
26729
|
}
|
|
26730
|
+
|
|
26731
|
+
// src/mcp/index.ts
|
|
26732
|
+
init_strip();
|
|
26156
26733
|
// package.json
|
|
26157
26734
|
var package_default = {
|
|
26158
26735
|
name: "@hasna/connectors",
|
|
@@ -26243,6 +26820,9 @@ var package_default = {
|
|
|
26243
26820
|
|
|
26244
26821
|
// src/mcp/index.ts
|
|
26245
26822
|
loadConnectorVersions();
|
|
26823
|
+
async function stripped(text) {
|
|
26824
|
+
return { content: [{ type: "text", text: await maybeStrip(text) }] };
|
|
26825
|
+
}
|
|
26246
26826
|
var server = new McpServer({
|
|
26247
26827
|
name: "connectors",
|
|
26248
26828
|
version: package_default.version
|
|
@@ -26253,20 +26833,7 @@ server.registerTool("search_connectors", {
|
|
|
26253
26833
|
inputSchema: { query: exports_external.string() }
|
|
26254
26834
|
}, async ({ query }) => {
|
|
26255
26835
|
const results = searchConnectors(query);
|
|
26256
|
-
return {
|
|
26257
|
-
content: [
|
|
26258
|
-
{
|
|
26259
|
-
type: "text",
|
|
26260
|
-
text: JSON.stringify(results.map((c) => ({
|
|
26261
|
-
name: c.name,
|
|
26262
|
-
displayName: c.displayName,
|
|
26263
|
-
version: c.version,
|
|
26264
|
-
category: c.category,
|
|
26265
|
-
description: c.description
|
|
26266
|
-
})), null, 2)
|
|
26267
|
-
}
|
|
26268
|
-
]
|
|
26269
|
-
};
|
|
26836
|
+
return stripped(JSON.stringify(results.map((c) => ({ name: c.name, displayName: c.displayName, version: c.version, category: c.category, description: c.description })), null, 2));
|
|
26270
26837
|
});
|
|
26271
26838
|
server.registerTool("list_connectors", {
|
|
26272
26839
|
title: "List Connectors",
|
|
@@ -26299,9 +26866,7 @@ server.registerTool("list_connectors", {
|
|
|
26299
26866
|
category: c.category,
|
|
26300
26867
|
description: c.description
|
|
26301
26868
|
}));
|
|
26302
|
-
return
|
|
26303
|
-
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
26304
|
-
};
|
|
26869
|
+
return stripped(JSON.stringify(data, null, 2));
|
|
26305
26870
|
});
|
|
26306
26871
|
server.registerTool("connector_docs", {
|
|
26307
26872
|
title: "Connector Documentation",
|
|
@@ -26730,6 +27295,71 @@ server.registerTool("describe_tools", {
|
|
|
26730
27295
|
`);
|
|
26731
27296
|
return { content: [{ type: "text", text: result }] };
|
|
26732
27297
|
});
|
|
27298
|
+
server.registerTool("list_jobs", { title: "List Jobs", description: "List scheduled connector jobs.", inputSchema: {} }, async () => {
|
|
27299
|
+
const { listJobs: listJobs2 } = await Promise.resolve().then(() => (init_jobs(), exports_jobs));
|
|
27300
|
+
const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_database(), exports_database));
|
|
27301
|
+
return stripped(JSON.stringify(listJobs2(getDatabase2()), null, 2));
|
|
27302
|
+
});
|
|
27303
|
+
server.registerTool("get_latest_job_run", { title: "Get Latest Job Run", description: "Get the most recent run output for a job.", inputSchema: { name: exports_external.string() } }, async ({ name }) => {
|
|
27304
|
+
const { getJobByName: getJobByName2, getLatestRun: getLatestRun2 } = await Promise.resolve().then(() => (init_jobs(), exports_jobs));
|
|
27305
|
+
const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_database(), exports_database));
|
|
27306
|
+
const db = getDatabase2();
|
|
27307
|
+
const job = getJobByName2(name, db);
|
|
27308
|
+
if (!job)
|
|
27309
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: `Job "${name}" not found` }) }], isError: true };
|
|
27310
|
+
const run = getLatestRun2(job.id, db);
|
|
27311
|
+
return stripped(JSON.stringify(run ?? { message: "No runs yet" }, null, 2));
|
|
27312
|
+
});
|
|
27313
|
+
server.registerTool("run_job", { title: "Run Job", description: "Manually trigger a scheduled job.", inputSchema: { name: exports_external.string() } }, async ({ name }) => {
|
|
27314
|
+
const { getJobByName: getJobByName2 } = await Promise.resolve().then(() => (init_jobs(), exports_jobs));
|
|
27315
|
+
const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_database(), exports_database));
|
|
27316
|
+
const { triggerJob: triggerJob2 } = await Promise.resolve().then(() => (init_scheduler(), exports_scheduler));
|
|
27317
|
+
const db = getDatabase2();
|
|
27318
|
+
const job = getJobByName2(name, db);
|
|
27319
|
+
if (!job)
|
|
27320
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: `Job "${name}" not found` }) }], isError: true };
|
|
27321
|
+
const result = await triggerJob2(job, db);
|
|
27322
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
27323
|
+
});
|
|
27324
|
+
server.registerTool("list_workflows", { title: "List Workflows", description: "List connector workflows.", inputSchema: {} }, async () => {
|
|
27325
|
+
const { listWorkflows: listWorkflows2 } = await Promise.resolve().then(() => (init_workflows(), exports_workflows));
|
|
27326
|
+
const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_database(), exports_database));
|
|
27327
|
+
return stripped(JSON.stringify(listWorkflows2(getDatabase2()), null, 2));
|
|
27328
|
+
});
|
|
27329
|
+
server.registerTool("run_workflow", { title: "Run Workflow", description: "Execute a connector workflow pipeline.", inputSchema: { name: exports_external.string() } }, async ({ name }) => {
|
|
27330
|
+
const { getWorkflowByName: getWorkflowByName2 } = await Promise.resolve().then(() => (init_workflows(), exports_workflows));
|
|
27331
|
+
const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_database(), exports_database));
|
|
27332
|
+
const { runWorkflow: runWorkflow2 } = await Promise.resolve().then(() => (init_workflow_runner(), exports_workflow_runner));
|
|
27333
|
+
const wf = getWorkflowByName2(name, getDatabase2());
|
|
27334
|
+
if (!wf)
|
|
27335
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: `Workflow "${name}" not found` }) }], isError: true };
|
|
27336
|
+
const result = await runWorkflow2(wf);
|
|
27337
|
+
return stripped(JSON.stringify(result, null, 2));
|
|
27338
|
+
});
|
|
27339
|
+
server.registerTool("get_llm_config", {
|
|
27340
|
+
title: "Get LLM Config",
|
|
27341
|
+
description: "Get current LLM provider config and strip status.",
|
|
27342
|
+
inputSchema: {}
|
|
27343
|
+
}, async () => {
|
|
27344
|
+
const { getLlmConfig: getConfig, maskKey: mask } = await Promise.resolve().then(() => (init_llm(), exports_llm));
|
|
27345
|
+
const config2 = getConfig();
|
|
27346
|
+
if (!config2)
|
|
27347
|
+
return { content: [{ type: "text", text: JSON.stringify({ configured: false }) }] };
|
|
27348
|
+
return { content: [{ type: "text", text: JSON.stringify({ configured: true, provider: config2.provider, model: config2.model, key: mask(config2.api_key), strip: config2.strip }) }] };
|
|
27349
|
+
});
|
|
27350
|
+
server.registerTool("set_llm_strip", {
|
|
27351
|
+
title: "Set LLM Strip",
|
|
27352
|
+
description: "Enable or disable global output stripping.",
|
|
27353
|
+
inputSchema: { enabled: exports_external.boolean() }
|
|
27354
|
+
}, async ({ enabled }) => {
|
|
27355
|
+
const { setLlmStrip: setLlmStrip2 } = await Promise.resolve().then(() => (init_llm(), exports_llm));
|
|
27356
|
+
try {
|
|
27357
|
+
setLlmStrip2(enabled);
|
|
27358
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: true, strip: enabled }) }] };
|
|
27359
|
+
} catch (e) {
|
|
27360
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: false, error: e instanceof Error ? e.message : String(e) }) }], isError: true };
|
|
27361
|
+
}
|
|
27362
|
+
});
|
|
26733
27363
|
server.registerTool("register_agent", {
|
|
26734
27364
|
title: "Register Agent",
|
|
26735
27365
|
description: "Register or heartbeat an agent. Returns agent or conflict error.",
|