@hasna/connectors 1.3.45 → 1.3.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/bin/index.js +792 -130
- package/bin/mcp.js +438 -52
- package/bin/serve.js +438 -52
- package/connectors/cloudflare-workers/.env.example +5 -0
- package/connectors/cloudflare-workers/AGENTS.md +11 -0
- package/connectors/cloudflare-workers/CLAUDE.md +11 -0
- package/connectors/cloudflare-workers/README.md +45 -0
- package/connectors/cloudflare-workers/package.json +47 -0
- package/connectors/cloudflare-workers/src/api/client.test.ts +144 -0
- package/connectors/cloudflare-workers/src/api/client.ts +386 -0
- package/connectors/cloudflare-workers/src/api/index.ts +1 -0
- package/connectors/cloudflare-workers/src/cli/index.ts +206 -0
- package/connectors/cloudflare-workers/src/index.ts +16 -0
- package/connectors/cloudflare-workers/src/types/index.ts +53 -0
- package/connectors/cloudflare-workers/src/utils/config.ts +61 -0
- package/connectors/cloudflare-workers/src/utils/output.ts +26 -0
- package/connectors/cloudflare-workers/tsconfig.build.json +4 -0
- package/connectors/cloudflare-workers/tsconfig.json +14 -0
- package/connectors/tidio/.env.example +3 -2
- package/connectors/tidio/CLAUDE.md +21 -96
- package/connectors/tidio/README.md +22 -18
- package/connectors/tidio/package.json +4 -2
- package/connectors/tidio/src/api/client.ts +26 -15
- package/connectors/tidio/src/api/index.ts +185 -128
- package/connectors/tidio/src/api/tidio.test.ts +175 -44
- package/connectors/tidio/src/cli/index.ts +154 -388
- package/connectors/tidio/src/index.ts +5 -3
- package/connectors/tidio/src/types/index.ts +135 -82
- package/connectors/tidio/src/utils/config.ts +90 -44
- package/connectors/wandb/.env.example +7 -0
- package/connectors/wandb/AGENTS.md +43 -0
- package/connectors/wandb/CLAUDE.md +67 -0
- package/connectors/wandb/README.md +65 -0
- package/connectors/wandb/package.json +52 -0
- package/connectors/wandb/src/api/client.test.ts +116 -0
- package/connectors/wandb/src/api/client.ts +83 -0
- package/connectors/wandb/src/api/graphql.ts +9 -0
- package/connectors/wandb/src/api/index.ts +36 -0
- package/connectors/wandb/src/api/projects.ts +36 -0
- package/connectors/wandb/src/api/viewer.ts +20 -0
- package/connectors/wandb/src/cli/index.ts +265 -0
- package/connectors/wandb/src/index.ts +22 -0
- package/connectors/wandb/src/types/index.ts +75 -0
- package/connectors/wandb/src/utils/config.ts +164 -0
- package/connectors/wandb/src/utils/output.ts +119 -0
- package/connectors/wandb/tsconfig.json +16 -0
- package/connectors/weights-biases/.env.example +7 -0
- package/connectors/weights-biases/CLAUDE.md +65 -0
- package/connectors/weights-biases/README.md +62 -0
- package/connectors/weights-biases/package.json +53 -0
- package/connectors/weights-biases/src/api/client.test.ts +46 -0
- package/connectors/weights-biases/src/api/client.ts +119 -0
- package/connectors/weights-biases/src/api/events.ts +18 -0
- package/connectors/weights-biases/src/api/index.ts +56 -0
- package/connectors/weights-biases/src/api/runs.ts +28 -0
- package/connectors/weights-biases/src/api/search.ts +10 -0
- package/connectors/weights-biases/src/cli/index.ts +289 -0
- package/connectors/weights-biases/src/index.ts +19 -0
- package/connectors/weights-biases/src/types/index.ts +92 -0
- package/connectors/weights-biases/src/utils/config.ts +168 -0
- package/connectors/weights-biases/src/utils/output.ts +116 -0
- package/connectors/weights-biases/tsconfig.json +16 -0
- package/connectors/zoominfo/.env.example +4 -0
- package/connectors/zoominfo/AGENTS.md +26 -0
- package/connectors/zoominfo/CLAUDE.md +20 -0
- package/connectors/zoominfo/README.md +69 -0
- package/connectors/zoominfo/package.json +52 -0
- package/connectors/zoominfo/src/api/client.test.ts +140 -0
- package/connectors/zoominfo/src/api/client.ts +228 -0
- package/connectors/zoominfo/src/api/index.ts +1 -0
- package/connectors/zoominfo/src/cli/index.ts +179 -0
- package/connectors/zoominfo/src/index.ts +3 -0
- package/connectors/zoominfo/src/types/index.ts +39 -0
- package/connectors/zoominfo/src/utils/config.ts +61 -0
- package/connectors/zoominfo/src/utils/output.ts +27 -0
- package/connectors/zoominfo/tsconfig.json +20 -0
- package/connectors/zotero/.env.example +7 -0
- package/connectors/zotero/.npmrc.example +2 -0
- package/connectors/zotero/AGENTS.md +40 -0
- package/connectors/zotero/CLAUDE.md +69 -0
- package/connectors/zotero/README.md +91 -0
- package/connectors/zotero/package.json +43 -0
- package/connectors/zotero/src/api/attachments.ts +130 -0
- package/connectors/zotero/src/api/client.test.ts +166 -0
- package/connectors/zotero/src/api/client.ts +169 -0
- package/connectors/zotero/src/api/collections.ts +26 -0
- package/connectors/zotero/src/api/index.ts +45 -0
- package/connectors/zotero/src/api/items.ts +64 -0
- package/connectors/zotero/src/cli/index.ts +386 -0
- package/connectors/zotero/src/index.ts +28 -0
- package/connectors/zotero/src/types/index.ts +129 -0
- package/connectors/zotero/src/utils/config.ts +245 -0
- package/connectors/zotero/src/utils/output.ts +119 -0
- package/connectors/zotero/tsconfig.json +16 -0
- package/connectors/zymbly/.env.example +2 -0
- package/connectors/zymbly/AGENTS.md +11 -0
- package/connectors/zymbly/CLAUDE.md +5 -0
- package/connectors/zymbly/README.md +35 -0
- package/connectors/zymbly/package.json +52 -0
- package/connectors/zymbly/src/api/client.test.ts +110 -0
- package/connectors/zymbly/src/api/client.ts +166 -0
- package/connectors/zymbly/src/api/index.ts +1 -0
- package/connectors/zymbly/src/cli/index.ts +156 -0
- package/connectors/zymbly/src/index.ts +12 -0
- package/connectors/zymbly/src/types/index.ts +34 -0
- package/connectors/zymbly/src/utils/config.ts +52 -0
- package/connectors/zymbly/src/utils/output.ts +17 -0
- package/connectors/zymbly/tsconfig.json +13 -0
- package/dist/index.js +45 -2
- package/dist/lib/compact-output.d.ts +40 -0
- package/dist/mcp/tools/jobs.d.ts +32 -0
- package/dist/mcp/tools/jobs.test.d.ts +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
HttpMethod,
|
|
3
|
+
JsonObject,
|
|
4
|
+
QueryParams,
|
|
5
|
+
RequestOptions,
|
|
6
|
+
ZymblyConfig,
|
|
7
|
+
} from "../types";
|
|
8
|
+
import { ZymblyApiError } from "../types";
|
|
9
|
+
|
|
10
|
+
const DEFAULT_BASE_URL = "https://api.zymbly.com/v1";
|
|
11
|
+
|
|
12
|
+
function normalizePath(path: string): string {
|
|
13
|
+
const trimmed = path.trim();
|
|
14
|
+
if (!trimmed) {
|
|
15
|
+
throw new Error("Zymbly API path is required");
|
|
16
|
+
}
|
|
17
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
18
|
+
throw new Error("Zymbly API paths must be relative, not absolute URLs");
|
|
19
|
+
}
|
|
20
|
+
const normalized = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
21
|
+
if (normalized.split("/").some((part) => part === "..")) {
|
|
22
|
+
throw new Error("Zymbly API paths cannot contain parent-directory segments");
|
|
23
|
+
}
|
|
24
|
+
return normalized;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function encodePath(value: string | number): string {
|
|
28
|
+
return encodeURIComponent(String(value));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function appendQuery(url: URL, query?: QueryParams): void {
|
|
32
|
+
if (!query) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
for (const [key, value] of Object.entries(query)) {
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
for (const item of value) {
|
|
38
|
+
if (item !== undefined && item !== null) {
|
|
39
|
+
url.searchParams.append(key, String(item));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (value !== undefined && value !== null) {
|
|
45
|
+
url.searchParams.set(key, String(value));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function parseResponse(text: string, contentType: string | null): unknown {
|
|
51
|
+
if (!text) {
|
|
52
|
+
return {};
|
|
53
|
+
}
|
|
54
|
+
if (contentType?.includes("json") || text.startsWith("{") || text.startsWith("[")) {
|
|
55
|
+
try {
|
|
56
|
+
return JSON.parse(text);
|
|
57
|
+
} catch {
|
|
58
|
+
return { raw: text };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return text;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function extractErrorMessage(data: unknown, fallback: string): string {
|
|
65
|
+
if (typeof data === "string" && data.trim()) {
|
|
66
|
+
return data.slice(0, 500);
|
|
67
|
+
}
|
|
68
|
+
if (data && typeof data === "object") {
|
|
69
|
+
const record = data as Record<string, unknown>;
|
|
70
|
+
const message = record.message ?? record.error ?? record.detail ?? record.title;
|
|
71
|
+
if (typeof message === "string" && message.trim()) {
|
|
72
|
+
return message;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return fallback;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export class ZymblyClient {
|
|
79
|
+
private readonly apiKey?: string;
|
|
80
|
+
private readonly baseUrl: string;
|
|
81
|
+
|
|
82
|
+
constructor(config: ZymblyConfig = {}) {
|
|
83
|
+
this.apiKey = config.apiKey;
|
|
84
|
+
this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async request<T = unknown>(path: string, options: RequestOptions = {}): Promise<T> {
|
|
88
|
+
const method = options.method || (options.body ? "POST" : "GET");
|
|
89
|
+
const url = this.buildUrl(path, options.query);
|
|
90
|
+
const headers: Record<string, string> = {
|
|
91
|
+
Accept: "application/json",
|
|
92
|
+
...options.headers,
|
|
93
|
+
};
|
|
94
|
+
const body = this.prepareBody(method, options);
|
|
95
|
+
if (body !== undefined && !headers["Content-Type"]) {
|
|
96
|
+
headers["Content-Type"] = "application/json";
|
|
97
|
+
}
|
|
98
|
+
if (options.auth !== false) {
|
|
99
|
+
headers.Authorization = `Bearer ${this.requireApiKey()}`;
|
|
100
|
+
}
|
|
101
|
+
const response = await fetch(url.toString(), { method, headers, body });
|
|
102
|
+
const text = await response.text();
|
|
103
|
+
const data = parseResponse(text, response.headers.get("content-type"));
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
throw new ZymblyApiError(
|
|
106
|
+
extractErrorMessage(data, response.statusText || `Zymbly request failed with ${response.status}`),
|
|
107
|
+
response.status,
|
|
108
|
+
data,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
return data as T;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
listWorkOrders<T = unknown>(query?: QueryParams): Promise<T> {
|
|
115
|
+
return this.request<T>("/work-orders", { query });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
getWorkOrder<T = unknown>(workOrderId: string): Promise<T> {
|
|
119
|
+
return this.request<T>(`/work-orders/${encodePath(workOrderId)}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
searchParts<T = unknown>(query?: QueryParams): Promise<T> {
|
|
123
|
+
return this.request<T>("/parts", { query });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
createMaintenanceNote<T = unknown>(workOrderId: string, note: string): Promise<T> {
|
|
127
|
+
return this.request<T>(`/work-orders/${encodePath(workOrderId)}/notes`, {
|
|
128
|
+
method: "POST",
|
|
129
|
+
body: { note },
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
createMaintenanceNoteWithBody<T = unknown>(workOrderId: string, body: JsonObject): Promise<T> {
|
|
134
|
+
return this.request<T>(`/work-orders/${encodePath(workOrderId)}/notes`, {
|
|
135
|
+
method: "POST",
|
|
136
|
+
body,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
rawRequest<T = unknown>(method: HttpMethod, path: string, options: Omit<RequestOptions, "method"> = {}): Promise<T> {
|
|
141
|
+
return this.request<T>(path, { ...options, method });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private buildUrl(path: string, query?: QueryParams): URL {
|
|
145
|
+
const url = new URL(`${this.baseUrl}${normalizePath(path)}`);
|
|
146
|
+
appendQuery(url, query);
|
|
147
|
+
return url;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private prepareBody(method: HttpMethod, options: RequestOptions): string | undefined {
|
|
151
|
+
if (method === "GET") {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
if (options.body === undefined) {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
return typeof options.body === "string" ? options.body : JSON.stringify(options.body);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private requireApiKey(): string {
|
|
161
|
+
if (!this.apiKey) {
|
|
162
|
+
throw new Error("Zymbly API key is required. Use config set-key or set ZYMBLY_API_KEY.");
|
|
163
|
+
}
|
|
164
|
+
return this.apiKey;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ZymblyClient } from "./client";
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { ZymblyClient } from "../api";
|
|
4
|
+
import type { HttpMethod, JsonObject, JsonValue, OutputFormat, QueryParams, QueryValue } from "../types";
|
|
5
|
+
import {
|
|
6
|
+
clearConfig,
|
|
7
|
+
getApiKey,
|
|
8
|
+
getBaseUrl,
|
|
9
|
+
getConfigPath,
|
|
10
|
+
setApiKey,
|
|
11
|
+
setBaseUrl,
|
|
12
|
+
} from "../utils/config";
|
|
13
|
+
import { error, print, success } from "../utils/output";
|
|
14
|
+
|
|
15
|
+
const VERSION = "0.0.1";
|
|
16
|
+
const DEFAULT_BASE_URL = "https://api.zymbly.com/v1";
|
|
17
|
+
|
|
18
|
+
function parseJson(value: string | undefined, label: string): JsonValue {
|
|
19
|
+
if (!value) {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(value) as JsonValue;
|
|
24
|
+
} catch (err) {
|
|
25
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
26
|
+
throw new Error(`Invalid ${label}: ${message}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function parseObject(value: string | undefined, label: string): JsonObject {
|
|
31
|
+
const parsed = parseJson(value, label);
|
|
32
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
33
|
+
throw new Error(`${label} must be a JSON object`);
|
|
34
|
+
}
|
|
35
|
+
return parsed as JsonObject;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function parseQueryParams(value: string | undefined): QueryParams | undefined {
|
|
39
|
+
if (!value) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
const parsed = parseObject(value, "query");
|
|
43
|
+
const query: QueryParams = {};
|
|
44
|
+
for (const [key, entry] of Object.entries(parsed)) {
|
|
45
|
+
if (Array.isArray(entry)) {
|
|
46
|
+
query[key] = entry.map((item) => {
|
|
47
|
+
if (typeof item === "string" || typeof item === "number" || typeof item === "boolean" || item === null || item === undefined) {
|
|
48
|
+
return item as QueryValue;
|
|
49
|
+
}
|
|
50
|
+
throw new Error(`query.${key} must contain only string, number, boolean, null, or undefined values`);
|
|
51
|
+
});
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (typeof entry === "string" || typeof entry === "number" || typeof entry === "boolean" || entry === null || entry === undefined) {
|
|
55
|
+
query[key] = entry as QueryValue;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
throw new Error(`query.${key} must be a string, number, boolean, null, or an array of those values`);
|
|
59
|
+
}
|
|
60
|
+
return query;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getFormat(command: Command): OutputFormat {
|
|
64
|
+
return (command.optsWithGlobals().format || "pretty") as OutputFormat;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getClient(command: Command): ZymblyClient {
|
|
68
|
+
const options = command.optsWithGlobals();
|
|
69
|
+
const apiKey = options.apiKey || getApiKey();
|
|
70
|
+
const baseUrl = options.baseUrl || getBaseUrl();
|
|
71
|
+
if (!apiKey) {
|
|
72
|
+
error("No Zymbly API key configured. Use config set-key or set ZYMBLY_API_KEY.");
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
return new ZymblyClient({ apiKey, baseUrl });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function run(command: Command, action: (client: ZymblyClient) => Promise<unknown>): Promise<void> {
|
|
79
|
+
try {
|
|
80
|
+
print(await action(getClient(command)), getFormat(command));
|
|
81
|
+
} catch (err) {
|
|
82
|
+
error(err instanceof Error ? err.message : String(err));
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const program = new Command()
|
|
88
|
+
.name("connect-zymbly")
|
|
89
|
+
.description("Zymbly aircraft maintenance API connector")
|
|
90
|
+
.version(VERSION)
|
|
91
|
+
.option("-k, --api-key <key>", "Zymbly API key")
|
|
92
|
+
.option("--base-url <url>", "API base URL", DEFAULT_BASE_URL)
|
|
93
|
+
.option("-f, --format <format>", "Output format: json or pretty", "pretty");
|
|
94
|
+
|
|
95
|
+
const config = program.command("config").description("Manage local configuration");
|
|
96
|
+
config.command("set-key <key>").description("Save API key").action((key: string) => {
|
|
97
|
+
setApiKey(key);
|
|
98
|
+
success("Zymbly API key saved");
|
|
99
|
+
});
|
|
100
|
+
config.command("set-base-url <url>").description("Save API base URL").action((url: string) => {
|
|
101
|
+
setBaseUrl(url);
|
|
102
|
+
success("Zymbly base URL saved");
|
|
103
|
+
});
|
|
104
|
+
config.command("show").description("Show current configuration").action(() => {
|
|
105
|
+
const key = getApiKey();
|
|
106
|
+
print({
|
|
107
|
+
configPath: getConfigPath(),
|
|
108
|
+
baseUrl: getBaseUrl() || DEFAULT_BASE_URL,
|
|
109
|
+
apiKey: key ? `${key.slice(0, 6)}...` : null,
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
config.command("clear").description("Clear local configuration").action(() => {
|
|
113
|
+
clearConfig();
|
|
114
|
+
success("Zymbly configuration cleared");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const workOrders = program.command("work-orders").description("Manage work orders");
|
|
118
|
+
workOrders
|
|
119
|
+
.command("list")
|
|
120
|
+
.description("List work orders")
|
|
121
|
+
.option("-q, --query <json>", "Query params JSON object")
|
|
122
|
+
.action((opts, cmd) => run(cmd, (client) => client.listWorkOrders(parseQueryParams(opts.query))));
|
|
123
|
+
workOrders
|
|
124
|
+
.command("get <workOrderId>")
|
|
125
|
+
.description("Get a work order by ID")
|
|
126
|
+
.action((workOrderId: string, _opts, cmd) => run(cmd, (client) => client.getWorkOrder(workOrderId)));
|
|
127
|
+
|
|
128
|
+
const parts = program.command("parts").description("Search aircraft parts");
|
|
129
|
+
parts
|
|
130
|
+
.command("search")
|
|
131
|
+
.description("Search parts catalog")
|
|
132
|
+
.option("-q, --query <json>", "Query params JSON object")
|
|
133
|
+
.action((opts, cmd) => run(cmd, (client) => client.searchParts(parseQueryParams(opts.query))));
|
|
134
|
+
|
|
135
|
+
const notes = program.command("notes").description("Maintenance notes");
|
|
136
|
+
notes
|
|
137
|
+
.command("create <workOrderId>")
|
|
138
|
+
.description("Create a maintenance note on a work order")
|
|
139
|
+
.requiredOption("-n, --note <text>", "Note text")
|
|
140
|
+
.action((workOrderId: string, opts, cmd) => run(cmd, (client) => client.createMaintenanceNote(workOrderId, opts.note)));
|
|
141
|
+
|
|
142
|
+
program
|
|
143
|
+
.command("raw <method> <path>")
|
|
144
|
+
.description("Call a raw Zymbly API path")
|
|
145
|
+
.option("-b, --body <json>", "JSON body")
|
|
146
|
+
.option("-q, --query <json>", "Query params JSON object")
|
|
147
|
+
.action((method: string, path: string, opts, cmd) =>
|
|
148
|
+
run(cmd, (client) =>
|
|
149
|
+
client.rawRequest(method.toUpperCase() as HttpMethod, path, {
|
|
150
|
+
body: opts.body ? parseJson(opts.body, "body") : undefined,
|
|
151
|
+
query: parseQueryParams(opts.query),
|
|
152
|
+
}),
|
|
153
|
+
),
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
program.parse();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
2
|
+
export type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
3
|
+
export interface JsonObject {
|
|
4
|
+
[key: string]: JsonValue | undefined;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
8
|
+
export type OutputFormat = "json" | "pretty";
|
|
9
|
+
export type QueryValue = string | number | boolean | null | undefined;
|
|
10
|
+
export type QueryParams = Record<string, QueryValue | QueryValue[]>;
|
|
11
|
+
|
|
12
|
+
export interface ZymblyConfig {
|
|
13
|
+
apiKey?: string;
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface RequestOptions {
|
|
18
|
+
method?: HttpMethod;
|
|
19
|
+
body?: JsonValue | string;
|
|
20
|
+
headers?: Record<string, string>;
|
|
21
|
+
query?: QueryParams;
|
|
22
|
+
auth?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class ZymblyApiError extends Error {
|
|
26
|
+
constructor(
|
|
27
|
+
message: string,
|
|
28
|
+
public readonly status: number,
|
|
29
|
+
public readonly details?: unknown,
|
|
30
|
+
) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.name = "ZymblyApiError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
|
|
5
|
+
interface StoredConfig {
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const CONFIG_PATH = join(homedir(), ".config", "hasna-connectors", "zymbly.json");
|
|
11
|
+
|
|
12
|
+
function readConfig(): StoredConfig {
|
|
13
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(readFileSync(CONFIG_PATH, "utf8")) as StoredConfig;
|
|
18
|
+
} catch {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function writeConfig(config: StoredConfig): void {
|
|
24
|
+
mkdirSync(dirname(CONFIG_PATH), { recursive: true });
|
|
25
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function getConfigPath(): string {
|
|
29
|
+
return CONFIG_PATH;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function getApiKey(): string | undefined {
|
|
33
|
+
return process.env.ZYMBLY_API_KEY || readConfig().apiKey;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getBaseUrl(): string | undefined {
|
|
37
|
+
return process.env.ZYMBLY_BASE_URL || readConfig().baseUrl;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function setApiKey(apiKey: string): void {
|
|
41
|
+
writeConfig({ ...readConfig(), apiKey });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function setBaseUrl(baseUrl: string): void {
|
|
45
|
+
writeConfig({ ...readConfig(), baseUrl });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function clearConfig(): void {
|
|
49
|
+
if (existsSync(CONFIG_PATH)) {
|
|
50
|
+
rmSync(CONFIG_PATH);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OutputFormat } from "../types";
|
|
2
|
+
|
|
3
|
+
export function print(data: unknown, format: OutputFormat = "pretty"): void {
|
|
4
|
+
if (format === "json") {
|
|
5
|
+
console.log(JSON.stringify(data));
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
console.log(JSON.stringify(data, null, 2));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function error(message: string): void {
|
|
12
|
+
console.error(message);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function success(message: string): void {
|
|
16
|
+
console.log(message);
|
|
17
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -5764,7 +5764,7 @@ function extractGoogleError(body) {
|
|
|
5764
5764
|
// package.json
|
|
5765
5765
|
var package_default = {
|
|
5766
5766
|
name: "@hasna/connectors",
|
|
5767
|
-
version: "1.3.
|
|
5767
|
+
version: "1.3.46",
|
|
5768
5768
|
description: "Open source connector library - Install API connectors with a single command",
|
|
5769
5769
|
type: "module",
|
|
5770
5770
|
bin: {
|
|
@@ -5796,11 +5796,12 @@ var package_default = {
|
|
|
5796
5796
|
"build:dashboard": "cd dashboard && bun run build",
|
|
5797
5797
|
postinstall: 'mkdir -p $HOME/.hasna/connectors 2>/dev/null || true; [ "$SKIP_DASHBOARD" = "1" ] || [ ! -f dashboard/package.json ] || [ -d dashboard/node_modules ] || (cd dashboard && bun install)',
|
|
5798
5798
|
dev: "bun run ./src/cli/index.tsx",
|
|
5799
|
+
"check:package-secrets": "bun run scripts/check-package-secrets.ts",
|
|
5799
5800
|
typecheck: "tsc --noEmit && tsc -p tsconfig.social.json --noEmit",
|
|
5800
5801
|
test: "bun test",
|
|
5801
5802
|
"secrets:scan:npmrc": "bun run scripts/scan-npmrc-auth.mjs",
|
|
5802
5803
|
"sdk:build": "cd sdk && bun run build",
|
|
5803
|
-
prepublishOnly: "bun run secrets:scan:npmrc && bun run build && bun test"
|
|
5804
|
+
prepublishOnly: "bun run secrets:scan:npmrc && bun run check:package-secrets && bun run build && bun test"
|
|
5804
5805
|
},
|
|
5805
5806
|
keywords: [
|
|
5806
5807
|
"connectors",
|
|
@@ -18603,6 +18604,13 @@ var connectors = [
|
|
|
18603
18604
|
category: "AI & ML",
|
|
18604
18605
|
tags: ["transcription", "meetings", "ai"]
|
|
18605
18606
|
},
|
|
18607
|
+
{
|
|
18608
|
+
name: "wandb",
|
|
18609
|
+
displayName: "Weights & Biases",
|
|
18610
|
+
description: "ML experiment tracking and run management via GraphQL",
|
|
18611
|
+
category: "AI & ML",
|
|
18612
|
+
tags: ["ml", "experiments", "tracking"]
|
|
18613
|
+
},
|
|
18606
18614
|
{
|
|
18607
18615
|
name: "wato",
|
|
18608
18616
|
displayName: "Wato",
|
|
@@ -18610,6 +18618,13 @@ var connectors = [
|
|
|
18610
18618
|
category: "AI & ML",
|
|
18611
18619
|
tags: ["ai", "agents", "memory", "workflows"]
|
|
18612
18620
|
},
|
|
18621
|
+
{
|
|
18622
|
+
name: "weights-biases",
|
|
18623
|
+
displayName: "Weights & Biases",
|
|
18624
|
+
description: "ML experiment tracking (runs, events, search)",
|
|
18625
|
+
category: "AI & ML",
|
|
18626
|
+
tags: ["ai", "ml", "wandb", "experiment-tracking"]
|
|
18627
|
+
},
|
|
18613
18628
|
{
|
|
18614
18629
|
name: "wavelineextract",
|
|
18615
18630
|
displayName: "Waveline Extract",
|
|
@@ -20248,6 +20263,20 @@ var connectors3 = [
|
|
|
20248
20263
|
description: "HR platform for employees, leave, attendance, and timesheets",
|
|
20249
20264
|
category: "Business Tools",
|
|
20250
20265
|
tags: ["hr", "employees", "zoho"]
|
|
20266
|
+
},
|
|
20267
|
+
{
|
|
20268
|
+
name: "zymbly",
|
|
20269
|
+
displayName: "Zymbly",
|
|
20270
|
+
description: "Aircraft maintenance and CMMS platform for work orders, parts, and maintenance notes",
|
|
20271
|
+
category: "Business Tools",
|
|
20272
|
+
tags: ["maintenance", "aircraft", "work-orders", "cmms"]
|
|
20273
|
+
},
|
|
20274
|
+
{
|
|
20275
|
+
name: "zotero",
|
|
20276
|
+
displayName: "Zotero",
|
|
20277
|
+
description: "Bibliography and reference library API for items, collections, and attachments",
|
|
20278
|
+
category: "Business Tools",
|
|
20279
|
+
tags: ["bibliography", "citations", "research", "library", "references"]
|
|
20251
20280
|
}
|
|
20252
20281
|
];
|
|
20253
20282
|
|
|
@@ -22758,6 +22787,13 @@ var connectors9 = [
|
|
|
22758
22787
|
category: "Developer Tools",
|
|
22759
22788
|
tags: ["cdn", "dns", "edge"]
|
|
22760
22789
|
},
|
|
22790
|
+
{
|
|
22791
|
+
name: "cloudflare-workers",
|
|
22792
|
+
displayName: "Cloudflare Workers",
|
|
22793
|
+
description: "Cloudflare Workers REST API connector for scripts, multipart uploads, routes, deployments, versions, secrets, cron schedules, tails, subdomains, beta Workers, and scoped raw account or zone requests",
|
|
22794
|
+
category: "Developer Tools",
|
|
22795
|
+
tags: ["cloudflare", "workers", "serverless", "edge", "deployments", "developer-tools"]
|
|
22796
|
+
},
|
|
22761
22797
|
{
|
|
22762
22798
|
name: "googlecloud",
|
|
22763
22799
|
displayName: "Google Cloud",
|
|
@@ -25150,6 +25186,13 @@ var connectors14 = [
|
|
|
25150
25186
|
description: "Reviews and user-generated content platform for e-commerce",
|
|
25151
25187
|
category: "Marketing & Sales",
|
|
25152
25188
|
tags: ["reviews", "ugc", "ecommerce", "marketing"]
|
|
25189
|
+
},
|
|
25190
|
+
{
|
|
25191
|
+
name: "zoominfo",
|
|
25192
|
+
displayName: "ZoomInfo",
|
|
25193
|
+
description: "ZoomInfo B2B sales intelligence API for contact and company search, enrichment, lookup, and output field discovery",
|
|
25194
|
+
category: "Marketing & Sales",
|
|
25195
|
+
tags: ["sales-intelligence", "enrichment", "contacts", "companies", "b2b"]
|
|
25153
25196
|
}
|
|
25154
25197
|
];
|
|
25155
25198
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ConnectorMeta } from "./registry.js";
|
|
2
|
+
export declare const DEFAULT_COMPACT_LIMIT = 20;
|
|
3
|
+
export declare const DEFAULT_MCP_LIMIT = 20;
|
|
4
|
+
export declare const MAX_COMPACT_LIMIT = 100;
|
|
5
|
+
export declare const DEFAULT_TEXT_WIDTH = 96;
|
|
6
|
+
export declare const DEFAULT_OUTPUT_CHARS = 6000;
|
|
7
|
+
export type ParseIntResult = {
|
|
8
|
+
value: number | undefined;
|
|
9
|
+
error?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function parseNonNegativeInt(raw: string | undefined, flag: string): ParseIntResult;
|
|
12
|
+
export declare function normalizeLimit(value: number | undefined, fallback: number, max?: number): number;
|
|
13
|
+
export declare function parseCursor(raw: string | undefined): ParseIntResult;
|
|
14
|
+
export declare function pageItems<T>(items: T[], options: {
|
|
15
|
+
offset?: number;
|
|
16
|
+
limit?: number;
|
|
17
|
+
}): {
|
|
18
|
+
items: T[];
|
|
19
|
+
total: number;
|
|
20
|
+
offset: number;
|
|
21
|
+
limit: number | null;
|
|
22
|
+
nextOffset: number | null;
|
|
23
|
+
};
|
|
24
|
+
export declare function truncateText(value: string | undefined, max?: number): string;
|
|
25
|
+
export declare function firstNonEmptyLines(value: string | undefined, maxLines: number, maxWidth?: number): string[];
|
|
26
|
+
export declare function compactConnector(connector: ConnectorMeta, descriptionWidth?: number): {
|
|
27
|
+
name: string;
|
|
28
|
+
displayName: string;
|
|
29
|
+
version: string | undefined;
|
|
30
|
+
category: string;
|
|
31
|
+
description: string;
|
|
32
|
+
};
|
|
33
|
+
export declare function maybeTruncateOutput(text: string, options?: {
|
|
34
|
+
maxChars?: number;
|
|
35
|
+
enabled?: boolean;
|
|
36
|
+
hint?: string;
|
|
37
|
+
}): {
|
|
38
|
+
text: string;
|
|
39
|
+
truncated: boolean;
|
|
40
|
+
};
|
package/dist/mcp/tools/jobs.d.ts
CHANGED
|
@@ -1,7 +1,39 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { type WorkflowResult } from "../../lib/workflow-runner.js";
|
|
3
|
+
import { triggerJob } from "../../lib/scheduler.js";
|
|
4
|
+
type JobExecutionResult = Awaited<ReturnType<typeof triggerJob>>;
|
|
5
|
+
type ExecutionCompactOptions = {
|
|
6
|
+
verbose?: boolean;
|
|
7
|
+
maxOutputChars?: number;
|
|
8
|
+
};
|
|
9
|
+
export declare function compactJobExecutionResult(result: JobExecutionResult, options?: ExecutionCompactOptions): {
|
|
10
|
+
output: string;
|
|
11
|
+
outputTruncated: boolean;
|
|
12
|
+
hint: string | undefined;
|
|
13
|
+
run_id: string;
|
|
14
|
+
exit_code: number;
|
|
15
|
+
};
|
|
16
|
+
export declare function compactWorkflowExecutionResult(result: WorkflowResult, options?: ExecutionCompactOptions): {
|
|
17
|
+
steps: {
|
|
18
|
+
output: string;
|
|
19
|
+
outputTruncated: boolean;
|
|
20
|
+
step: number;
|
|
21
|
+
connector: string;
|
|
22
|
+
command: string;
|
|
23
|
+
exit_code: number;
|
|
24
|
+
}[];
|
|
25
|
+
final_output: string;
|
|
26
|
+
finalOutputTruncated: boolean;
|
|
27
|
+
truncatedOutputs: number;
|
|
28
|
+
hint: string | undefined;
|
|
29
|
+
workflow_id: string;
|
|
30
|
+
workflow_name: string;
|
|
31
|
+
success: boolean;
|
|
32
|
+
};
|
|
2
33
|
export declare function registerJobsTools(server: McpServer, stripped: (text: string) => Promise<{
|
|
3
34
|
content: {
|
|
4
35
|
type: "text";
|
|
5
36
|
text: string;
|
|
6
37
|
}[];
|
|
7
38
|
}>): void;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/connectors",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.46",
|
|
4
4
|
"description": "Open source connector library - Install API connectors with a single command",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -32,11 +32,12 @@
|
|
|
32
32
|
"build:dashboard": "cd dashboard && bun run build",
|
|
33
33
|
"postinstall": "mkdir -p $HOME/.hasna/connectors 2>/dev/null || true; [ \"$SKIP_DASHBOARD\" = \"1\" ] || [ ! -f dashboard/package.json ] || [ -d dashboard/node_modules ] || (cd dashboard && bun install)",
|
|
34
34
|
"dev": "bun run ./src/cli/index.tsx",
|
|
35
|
+
"check:package-secrets": "bun run scripts/check-package-secrets.ts",
|
|
35
36
|
"typecheck": "tsc --noEmit && tsc -p tsconfig.social.json --noEmit",
|
|
36
37
|
"test": "bun test",
|
|
37
38
|
"secrets:scan:npmrc": "bun run scripts/scan-npmrc-auth.mjs",
|
|
38
39
|
"sdk:build": "cd sdk && bun run build",
|
|
39
|
-
"prepublishOnly": "bun run secrets:scan:npmrc && bun run build && bun test"
|
|
40
|
+
"prepublishOnly": "bun run secrets:scan:npmrc && bun run check:package-secrets && bun run build && bun test"
|
|
40
41
|
},
|
|
41
42
|
"keywords": [
|
|
42
43
|
"connectors",
|