@hasna/connectors 1.3.25 → 1.3.26
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 +606 -170
- package/bin/mcp.js +633 -197
- package/bin/serve.js +654 -222
- package/dist/core/connectors/gmail.d.ts +5 -0
- package/dist/index.js +595 -163
- package/package.json +1 -1
package/bin/mcp.js
CHANGED
|
@@ -10573,7 +10573,7 @@ var CONNECTOR_NAME_RE, OPERATION_NAME_RE;
|
|
|
10573
10573
|
var init_connector = __esm(() => {
|
|
10574
10574
|
init_errors2();
|
|
10575
10575
|
CONNECTOR_NAME_RE = /^[a-z0-9-]+$/;
|
|
10576
|
-
OPERATION_NAME_RE = /^[
|
|
10576
|
+
OPERATION_NAME_RE = /^[A-Za-z0-9:._-]+$/;
|
|
10577
10577
|
});
|
|
10578
10578
|
|
|
10579
10579
|
// src/core/registry.ts
|
|
@@ -11471,38 +11471,100 @@ Commands:
|
|
|
11471
11471
|
});
|
|
11472
11472
|
});
|
|
11473
11473
|
|
|
11474
|
-
// src/core/connectors/
|
|
11474
|
+
// src/core/connectors/gmail.ts
|
|
11475
11475
|
import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
|
|
11476
11476
|
import { homedir } from "os";
|
|
11477
11477
|
import { basename, join as join2 } from "path";
|
|
11478
|
-
async function
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
|
|
11478
|
+
async function modifyMessage(profile, messageId, addLabelIds, removeLabelIds) {
|
|
11479
|
+
return requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}/modify`, {}, {
|
|
11480
|
+
method: "POST",
|
|
11481
|
+
body: {
|
|
11482
|
+
addLabelIds: addLabelIds ?? [],
|
|
11483
|
+
removeLabelIds: removeLabelIds ?? []
|
|
11484
|
+
}
|
|
11485
|
+
});
|
|
11486
|
+
}
|
|
11487
|
+
async function replyToMessage(profile, messageId, input) {
|
|
11488
|
+
const original = await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: "full" });
|
|
11489
|
+
const headers = headersToObject(original.payload?.headers ?? []);
|
|
11490
|
+
const subject = normalizeReplySubject(headers.Subject ?? headers.subject ?? "");
|
|
11491
|
+
const to = headers.From ?? headers.from ?? "";
|
|
11492
|
+
const messageIdHeader = headers["Message-ID"] ?? headers["Message-Id"] ?? headers["message-id"] ?? "";
|
|
11493
|
+
const references = [headers.References ?? headers.references, messageIdHeader].filter(Boolean).join(" ");
|
|
11494
|
+
const raw = buildRawEmail({
|
|
11495
|
+
to,
|
|
11496
|
+
cc: normalizeStringArray(input.cc),
|
|
11497
|
+
bcc: normalizeStringArray(input.bcc),
|
|
11498
|
+
subject,
|
|
11499
|
+
body: input.body,
|
|
11500
|
+
isHtml: Boolean(input.html ?? input.isHtml),
|
|
11501
|
+
inReplyTo: messageIdHeader,
|
|
11502
|
+
references
|
|
11503
|
+
});
|
|
11504
|
+
return requestJson(profile, "/users/me/messages/send", {}, {
|
|
11505
|
+
method: "POST",
|
|
11506
|
+
body: {
|
|
11507
|
+
raw: Buffer.from(raw).toString("base64url"),
|
|
11508
|
+
threadId: original.threadId
|
|
11509
|
+
}
|
|
11510
|
+
});
|
|
11511
|
+
}
|
|
11512
|
+
async function downloadAttachments(profile, input) {
|
|
11513
|
+
const messageId = getMessageId(input);
|
|
11514
|
+
const outputDir = input.dir ?? input.outputDir ?? join2(configDirs()[0], "attachments", messageId);
|
|
11515
|
+
mkdirSync(outputDir, { recursive: true });
|
|
11516
|
+
const attachments = input.attachmentId && input.filename ? [{
|
|
11517
|
+
attachmentId: input.attachmentId,
|
|
11518
|
+
filename: input.filename,
|
|
11519
|
+
mimeType: input.mimeType ?? "application/octet-stream",
|
|
11520
|
+
size: 0
|
|
11521
|
+
}] : collectAttachments((await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: "full" })).payload);
|
|
11522
|
+
const downloaded = [];
|
|
11523
|
+
for (const attachment of attachments) {
|
|
11524
|
+
const data = await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachment.attachmentId)}`, {});
|
|
11525
|
+
const filename = safeFilename(attachment.filename);
|
|
11526
|
+
const path = join2(outputDir, filename);
|
|
11527
|
+
const buffer = Buffer.from(data.data, "base64url");
|
|
11528
|
+
writeFileSync(path, buffer);
|
|
11529
|
+
downloaded.push({
|
|
11530
|
+
filename,
|
|
11531
|
+
path,
|
|
11532
|
+
size: buffer.length,
|
|
11533
|
+
mimeType: attachment.mimeType
|
|
11534
|
+
});
|
|
11535
|
+
}
|
|
11536
|
+
return downloaded;
|
|
11485
11537
|
}
|
|
11486
|
-
async function
|
|
11538
|
+
async function requestJson(profile, path, params, options = {}) {
|
|
11487
11539
|
const token = await getValidAccessToken(profile);
|
|
11488
|
-
const url = new URL(`${
|
|
11540
|
+
const url = new URL(`${GMAIL_API_BASE}${path}`);
|
|
11489
11541
|
for (const [key, value] of Object.entries(params)) {
|
|
11490
11542
|
if (value !== undefined && value !== null && value !== "")
|
|
11491
|
-
url.searchParams.
|
|
11543
|
+
url.searchParams.append(key, String(value));
|
|
11492
11544
|
}
|
|
11493
|
-
const response = await fetch(url, {
|
|
11545
|
+
const response = await fetch(url, {
|
|
11546
|
+
method: options.method ?? "GET",
|
|
11547
|
+
headers: {
|
|
11548
|
+
Authorization: `Bearer ${token}`,
|
|
11549
|
+
Accept: "application/json",
|
|
11550
|
+
...options.body ? { "Content-Type": "application/json" } : {}
|
|
11551
|
+
},
|
|
11552
|
+
body: options.body ? JSON.stringify(options.body) : undefined
|
|
11553
|
+
});
|
|
11554
|
+
const text = await response.text();
|
|
11555
|
+
const data = text ? JSON.parse(text) : {};
|
|
11494
11556
|
if (!response.ok) {
|
|
11495
|
-
const
|
|
11496
|
-
throw new Error(`
|
|
11557
|
+
const error2 = data;
|
|
11558
|
+
throw new Error(`Gmail request failed (${response.status}): ${error2.error?.message ?? response.statusText}`);
|
|
11497
11559
|
}
|
|
11498
|
-
return
|
|
11560
|
+
return data;
|
|
11499
11561
|
}
|
|
11500
11562
|
async function getValidAccessToken(profile) {
|
|
11501
|
-
if (process.env.
|
|
11502
|
-
return process.env.
|
|
11563
|
+
if (process.env.GMAIL_ACCESS_TOKEN)
|
|
11564
|
+
return process.env.GMAIL_ACCESS_TOKEN;
|
|
11503
11565
|
const tokens = loadTokens(profile);
|
|
11504
11566
|
if (!tokens?.accessToken && !tokens?.refreshToken) {
|
|
11505
|
-
throw new Error(`
|
|
11567
|
+
throw new Error(`Gmail profile "${profile}" is not authenticated. Run: connectors auth gmail`);
|
|
11506
11568
|
}
|
|
11507
11569
|
if (tokens.accessToken && (!tokens.expiresAt || Date.now() < tokens.expiresAt - REFRESH_BUFFER_MS))
|
|
11508
11570
|
return tokens.accessToken;
|
|
@@ -11513,9 +11575,9 @@ async function getValidAccessToken(profile) {
|
|
|
11513
11575
|
async function refreshAccessToken(profile, currentTokens) {
|
|
11514
11576
|
const credentials = loadCredentials(profile);
|
|
11515
11577
|
if (!credentials.clientId || !credentials.clientSecret)
|
|
11516
|
-
throw new Error("
|
|
11578
|
+
throw new Error("Gmail OAuth credentials are not configured. Run: connectors auth gmail");
|
|
11517
11579
|
if (!currentTokens.refreshToken)
|
|
11518
|
-
throw new Error(`
|
|
11580
|
+
throw new Error(`Gmail profile "${profile}" has no refresh token. Run: connectors auth gmail`);
|
|
11519
11581
|
const response = await fetch(TOKEN_URL, {
|
|
11520
11582
|
method: "POST",
|
|
11521
11583
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
@@ -11528,7 +11590,7 @@ async function refreshAccessToken(profile, currentTokens) {
|
|
|
11528
11590
|
});
|
|
11529
11591
|
const data = await response.json().catch(() => ({}));
|
|
11530
11592
|
if (!response.ok || !data.access_token)
|
|
11531
|
-
throw new Error(`
|
|
11593
|
+
throw new Error(`Gmail token refresh failed: ${data.error_description || data.error || response.statusText}`);
|
|
11532
11594
|
const tokens = {
|
|
11533
11595
|
accessToken: data.access_token,
|
|
11534
11596
|
refreshToken: currentTokens.refreshToken,
|
|
@@ -11555,8 +11617,8 @@ function listProfiles() {
|
|
|
11555
11617
|
return Array.from(profiles).sort((a, b) => a.localeCompare(b));
|
|
11556
11618
|
}
|
|
11557
11619
|
function loadCredentials(profile) {
|
|
11558
|
-
const envClientId = process.env.GOOGLE_CLIENT_ID;
|
|
11559
|
-
const envClientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
|
11620
|
+
const envClientId = process.env.GMAIL_CLIENT_ID ?? process.env.GOOGLE_CLIENT_ID;
|
|
11621
|
+
const envClientSecret = process.env.GMAIL_CLIENT_SECRET ?? process.env.GOOGLE_CLIENT_SECRET;
|
|
11560
11622
|
if (envClientId && envClientSecret)
|
|
11561
11623
|
return { clientId: envClientId, clientSecret: envClientSecret };
|
|
11562
11624
|
for (const baseDir of configDirs()) {
|
|
@@ -11587,11 +11649,11 @@ function saveTokens(profile, tokens) {
|
|
|
11587
11649
|
writeFileSync(join2(profileDir, "tokens.json"), JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
11588
11650
|
}
|
|
11589
11651
|
function configDirs() {
|
|
11590
|
-
const explicit = process.env.
|
|
11652
|
+
const explicit = process.env.HASNA_GMAIL_CONNECTOR_DIR ?? process.env.GMAIL_CONNECTOR_DIR;
|
|
11591
11653
|
if (explicit)
|
|
11592
11654
|
return [explicit];
|
|
11593
11655
|
const baseDir = process.env.HASNA_CONNECTORS_DIR ?? join2(homedir(), ".hasna", "connectors");
|
|
11594
|
-
return [join2(baseDir, "connect-
|
|
11656
|
+
return [join2(baseDir, "connect-gmail"), join2(baseDir, "gmail")];
|
|
11595
11657
|
}
|
|
11596
11658
|
function readJson(path) {
|
|
11597
11659
|
if (!existsSync2(path))
|
|
@@ -11602,6 +11664,378 @@ function readJson(path) {
|
|
|
11602
11664
|
return null;
|
|
11603
11665
|
}
|
|
11604
11666
|
}
|
|
11667
|
+
function getMessageId(input) {
|
|
11668
|
+
const id = input.messageId ?? (input.args?.[0] != null ? String(input.args[0]) : undefined);
|
|
11669
|
+
if (!id)
|
|
11670
|
+
throw new Error("Gmail messageId is required");
|
|
11671
|
+
return id;
|
|
11672
|
+
}
|
|
11673
|
+
function headersToObject(headers) {
|
|
11674
|
+
const out = {};
|
|
11675
|
+
for (const header of headers)
|
|
11676
|
+
out[header.name] = header.value;
|
|
11677
|
+
return out;
|
|
11678
|
+
}
|
|
11679
|
+
function extractBody(message, preferHtml = false) {
|
|
11680
|
+
if (!message.payload)
|
|
11681
|
+
return "";
|
|
11682
|
+
const targetType = preferHtml ? "text/html" : "text/plain";
|
|
11683
|
+
const parts = [];
|
|
11684
|
+
collectTextParts(message.payload, parts);
|
|
11685
|
+
return parts.find((part) => part.mimeType === targetType)?.data ?? parts.find((part) => part.mimeType.startsWith("text/"))?.data ?? "";
|
|
11686
|
+
}
|
|
11687
|
+
function collectTextParts(part, results) {
|
|
11688
|
+
const mimeType = (part.mimeType ?? "").split(";")[0].trim().toLowerCase();
|
|
11689
|
+
if (part.body?.data && mimeType.startsWith("text/")) {
|
|
11690
|
+
results.push({ mimeType, data: Buffer.from(part.body.data, "base64url").toString("utf8") });
|
|
11691
|
+
}
|
|
11692
|
+
for (const child of part.parts ?? [])
|
|
11693
|
+
collectTextParts(child, results);
|
|
11694
|
+
}
|
|
11695
|
+
function collectAttachments(part, attachments = []) {
|
|
11696
|
+
if (!part)
|
|
11697
|
+
return attachments;
|
|
11698
|
+
if (part.body?.attachmentId && part.filename) {
|
|
11699
|
+
attachments.push({
|
|
11700
|
+
attachmentId: part.body.attachmentId,
|
|
11701
|
+
filename: part.filename,
|
|
11702
|
+
mimeType: part.mimeType ?? "application/octet-stream",
|
|
11703
|
+
size: part.body.size ?? 0,
|
|
11704
|
+
partId: part.partId
|
|
11705
|
+
});
|
|
11706
|
+
}
|
|
11707
|
+
for (const child of part.parts ?? [])
|
|
11708
|
+
collectAttachments(child, attachments);
|
|
11709
|
+
return attachments;
|
|
11710
|
+
}
|
|
11711
|
+
function normalizeStringArray(value) {
|
|
11712
|
+
if (!value)
|
|
11713
|
+
return [];
|
|
11714
|
+
return Array.isArray(value) ? value : value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
11715
|
+
}
|
|
11716
|
+
function normalizeReplySubject(subject) {
|
|
11717
|
+
return subject.toLowerCase().startsWith("re:") ? subject : `Re: ${subject}`;
|
|
11718
|
+
}
|
|
11719
|
+
function buildRawEmail(input) {
|
|
11720
|
+
const headers = [
|
|
11721
|
+
`To: ${input.to}`,
|
|
11722
|
+
input.cc.length ? `Cc: ${input.cc.join(", ")}` : "",
|
|
11723
|
+
input.bcc.length ? `Bcc: ${input.bcc.join(", ")}` : "",
|
|
11724
|
+
`Subject: ${input.subject}`,
|
|
11725
|
+
input.inReplyTo ? `In-Reply-To: ${input.inReplyTo}` : "",
|
|
11726
|
+
input.references ? `References: ${input.references}` : "",
|
|
11727
|
+
"MIME-Version: 1.0",
|
|
11728
|
+
`Content-Type: ${input.isHtml ? "text/html" : "text/plain"}; charset=UTF-8`
|
|
11729
|
+
].filter(Boolean);
|
|
11730
|
+
return `${headers.join(`\r
|
|
11731
|
+
`)}\r
|
|
11732
|
+
\r
|
|
11733
|
+
${input.body}`;
|
|
11734
|
+
}
|
|
11735
|
+
function safeFilename(filename) {
|
|
11736
|
+
return basename(filename.replace(/[\u00A0\u2000-\u200B\u202F\u205F\u3000]/g, " ")).replace(/[\/\\]/g, "_");
|
|
11737
|
+
}
|
|
11738
|
+
var GMAIL_API_BASE = "https://gmail.googleapis.com/gmail/v1", TOKEN_URL = "https://oauth2.googleapis.com/token", REFRESH_BUFFER_MS, listMessagesSchema, messageIdSchema, readMessageSchema, attachmentListSchema, attachmentDownloadSchema, historyListSchema, replySchema, gmailConnector;
|
|
11739
|
+
var init_gmail = __esm(() => {
|
|
11740
|
+
init_zod();
|
|
11741
|
+
init_connector();
|
|
11742
|
+
REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
11743
|
+
listMessagesSchema = exports_external.object({
|
|
11744
|
+
max: exports_external.coerce.number().int().positive().max(500).optional(),
|
|
11745
|
+
maxResults: exports_external.coerce.number().int().positive().max(500).optional(),
|
|
11746
|
+
pageToken: exports_external.string().optional(),
|
|
11747
|
+
query: exports_external.string().optional(),
|
|
11748
|
+
q: exports_external.string().optional(),
|
|
11749
|
+
label: exports_external.string().optional(),
|
|
11750
|
+
labelIds: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional(),
|
|
11751
|
+
includeSpamTrash: exports_external.boolean().optional()
|
|
11752
|
+
});
|
|
11753
|
+
messageIdSchema = exports_external.object({
|
|
11754
|
+
args: exports_external.array(exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean()])).optional(),
|
|
11755
|
+
messageId: exports_external.string().optional()
|
|
11756
|
+
});
|
|
11757
|
+
readMessageSchema = messageIdSchema.extend({
|
|
11758
|
+
body: exports_external.boolean().optional(),
|
|
11759
|
+
html: exports_external.boolean().optional(),
|
|
11760
|
+
format: exports_external.enum(["full", "metadata", "minimal", "raw"]).optional()
|
|
11761
|
+
});
|
|
11762
|
+
attachmentListSchema = messageIdSchema;
|
|
11763
|
+
attachmentDownloadSchema = messageIdSchema.extend({
|
|
11764
|
+
attachmentId: exports_external.string().optional(),
|
|
11765
|
+
filename: exports_external.string().optional(),
|
|
11766
|
+
mimeType: exports_external.string().optional(),
|
|
11767
|
+
dir: exports_external.string().optional(),
|
|
11768
|
+
outputDir: exports_external.string().optional()
|
|
11769
|
+
});
|
|
11770
|
+
historyListSchema = exports_external.object({
|
|
11771
|
+
startHistoryId: exports_external.string(),
|
|
11772
|
+
historyTypes: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional(),
|
|
11773
|
+
labelId: exports_external.string().optional(),
|
|
11774
|
+
maxResults: exports_external.coerce.number().int().positive().max(500).optional(),
|
|
11775
|
+
pageToken: exports_external.string().optional()
|
|
11776
|
+
});
|
|
11777
|
+
replySchema = messageIdSchema.extend({
|
|
11778
|
+
body: exports_external.string(),
|
|
11779
|
+
html: exports_external.boolean().optional(),
|
|
11780
|
+
isHtml: exports_external.boolean().optional(),
|
|
11781
|
+
cc: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional(),
|
|
11782
|
+
bcc: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional()
|
|
11783
|
+
});
|
|
11784
|
+
gmailConnector = defineConnector({
|
|
11785
|
+
meta: {
|
|
11786
|
+
name: "gmail",
|
|
11787
|
+
displayName: "Gmail",
|
|
11788
|
+
description: "Profile-aware Gmail mailbox operations for sync, labels, attachments, history, and replies.",
|
|
11789
|
+
category: "communication",
|
|
11790
|
+
tags: ["google", "gmail", "email", "mailbox"]
|
|
11791
|
+
},
|
|
11792
|
+
auth: {
|
|
11793
|
+
type: "oauth2",
|
|
11794
|
+
supportsProfiles: true,
|
|
11795
|
+
fields: [
|
|
11796
|
+
{ key: "clientId", env: "GMAIL_CLIENT_ID", label: "OAuth client ID" },
|
|
11797
|
+
{ key: "clientSecret", env: "GMAIL_CLIENT_SECRET", label: "OAuth client secret", secret: true }
|
|
11798
|
+
]
|
|
11799
|
+
},
|
|
11800
|
+
createContext: ({ profile }) => ({ profile: profile || "default" }),
|
|
11801
|
+
operations: {
|
|
11802
|
+
"profiles.list": {
|
|
11803
|
+
summary: "List configured Gmail profiles.",
|
|
11804
|
+
execute: () => ({ profiles: listProfiles() })
|
|
11805
|
+
},
|
|
11806
|
+
"profile.get": {
|
|
11807
|
+
summary: "Get the authenticated Gmail profile.",
|
|
11808
|
+
execute: async ({ context }) => requestJson(context.profile, "/users/me/profile", {})
|
|
11809
|
+
},
|
|
11810
|
+
"messages.list": {
|
|
11811
|
+
summary: "List Gmail messages.",
|
|
11812
|
+
inputSchema: listMessagesSchema,
|
|
11813
|
+
execute: async ({ context }, input) => {
|
|
11814
|
+
const labelIds = normalizeStringArray(input.labelIds ?? input.label);
|
|
11815
|
+
return requestJson(context.profile, "/users/me/messages", {
|
|
11816
|
+
maxResults: input.maxResults ?? input.max ?? 50,
|
|
11817
|
+
pageToken: input.pageToken,
|
|
11818
|
+
q: input.q ?? input.query,
|
|
11819
|
+
labelIds: labelIds.length > 0 ? labelIds.join(",") : undefined,
|
|
11820
|
+
includeSpamTrash: input.includeSpamTrash
|
|
11821
|
+
});
|
|
11822
|
+
}
|
|
11823
|
+
},
|
|
11824
|
+
"messages.read": {
|
|
11825
|
+
summary: "Read a Gmail message with optional extracted body.",
|
|
11826
|
+
inputSchema: readMessageSchema,
|
|
11827
|
+
execute: async ({ context }, input) => {
|
|
11828
|
+
const messageId = getMessageId(input);
|
|
11829
|
+
const message = await requestJson(context.profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: input.format ?? "full" });
|
|
11830
|
+
const headers = headersToObject(message.payload?.headers ?? []);
|
|
11831
|
+
return {
|
|
11832
|
+
...message,
|
|
11833
|
+
from: headers.From ?? headers.from ?? "",
|
|
11834
|
+
to: headers.To ?? headers.to ?? "",
|
|
11835
|
+
cc: headers.Cc ?? headers.cc ?? "",
|
|
11836
|
+
subject: headers.Subject ?? headers.subject ?? "",
|
|
11837
|
+
date: headers.Date ?? headers.date ?? "",
|
|
11838
|
+
body: input.body ? extractBody(message, Boolean(input.html)) : undefined,
|
|
11839
|
+
size: message.sizeEstimate
|
|
11840
|
+
};
|
|
11841
|
+
}
|
|
11842
|
+
},
|
|
11843
|
+
"messages.getRaw": {
|
|
11844
|
+
summary: "Read raw base64url Gmail message content.",
|
|
11845
|
+
inputSchema: messageIdSchema,
|
|
11846
|
+
execute: async ({ context }, input) => {
|
|
11847
|
+
const messageId = getMessageId(input);
|
|
11848
|
+
return requestJson(context.profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: "raw" });
|
|
11849
|
+
}
|
|
11850
|
+
},
|
|
11851
|
+
"messages.mark-read": {
|
|
11852
|
+
summary: "Mark a message as read.",
|
|
11853
|
+
inputSchema: messageIdSchema,
|
|
11854
|
+
execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), undefined, ["UNREAD"])
|
|
11855
|
+
},
|
|
11856
|
+
"messages.mark-unread": {
|
|
11857
|
+
summary: "Mark a message as unread.",
|
|
11858
|
+
inputSchema: messageIdSchema,
|
|
11859
|
+
execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), ["UNREAD"], undefined)
|
|
11860
|
+
},
|
|
11861
|
+
"messages.archive": {
|
|
11862
|
+
summary: "Archive a message by removing the INBOX label.",
|
|
11863
|
+
inputSchema: messageIdSchema,
|
|
11864
|
+
execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), undefined, ["INBOX"])
|
|
11865
|
+
},
|
|
11866
|
+
"messages.star": {
|
|
11867
|
+
summary: "Star a message.",
|
|
11868
|
+
inputSchema: messageIdSchema,
|
|
11869
|
+
execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), ["STARRED"], undefined)
|
|
11870
|
+
},
|
|
11871
|
+
"messages.reply": {
|
|
11872
|
+
summary: "Reply to a Gmail message in the same thread.",
|
|
11873
|
+
inputSchema: replySchema,
|
|
11874
|
+
execute: async ({ context }, input) => replyToMessage(context.profile, getMessageId(input), input)
|
|
11875
|
+
},
|
|
11876
|
+
"attachments.list": {
|
|
11877
|
+
summary: "List Gmail message attachments.",
|
|
11878
|
+
inputSchema: attachmentListSchema,
|
|
11879
|
+
execute: async ({ context }, input) => {
|
|
11880
|
+
const message = await requestJson(context.profile, `/users/me/messages/${encodeURIComponent(getMessageId(input))}`, { format: "full" });
|
|
11881
|
+
return collectAttachments(message.payload);
|
|
11882
|
+
}
|
|
11883
|
+
},
|
|
11884
|
+
"attachments.download": {
|
|
11885
|
+
summary: "Download one or all Gmail message attachments to disk.",
|
|
11886
|
+
inputSchema: attachmentDownloadSchema,
|
|
11887
|
+
execute: async ({ context }, input) => downloadAttachments(context.profile, input)
|
|
11888
|
+
},
|
|
11889
|
+
"labels.list": {
|
|
11890
|
+
summary: "List Gmail labels.",
|
|
11891
|
+
execute: async ({ context }) => requestJson(context.profile, "/users/me/labels", {})
|
|
11892
|
+
},
|
|
11893
|
+
"history.list": {
|
|
11894
|
+
summary: "List Gmail mailbox history from a history id.",
|
|
11895
|
+
inputSchema: historyListSchema,
|
|
11896
|
+
execute: async ({ context }, input) => requestJson(context.profile, "/users/me/history", {
|
|
11897
|
+
startHistoryId: input.startHistoryId,
|
|
11898
|
+
historyTypes: normalizeStringArray(input.historyTypes).join(",") || undefined,
|
|
11899
|
+
labelId: input.labelId,
|
|
11900
|
+
maxResults: input.maxResults,
|
|
11901
|
+
pageToken: input.pageToken
|
|
11902
|
+
})
|
|
11903
|
+
}
|
|
11904
|
+
}
|
|
11905
|
+
});
|
|
11906
|
+
});
|
|
11907
|
+
|
|
11908
|
+
// src/core/connectors/googledrive.ts
|
|
11909
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
11910
|
+
import { homedir as homedir2 } from "os";
|
|
11911
|
+
import { basename as basename2, join as join3 } from "path";
|
|
11912
|
+
async function requestJson2(profile, path, params) {
|
|
11913
|
+
const response = await request(profile, path, params);
|
|
11914
|
+
const text = await response.text();
|
|
11915
|
+
return text ? JSON.parse(text) : {};
|
|
11916
|
+
}
|
|
11917
|
+
async function requestBinary(profile, path, params) {
|
|
11918
|
+
return (await request(profile, path, params)).arrayBuffer();
|
|
11919
|
+
}
|
|
11920
|
+
async function request(profile, path, params) {
|
|
11921
|
+
const token = await getValidAccessToken2(profile);
|
|
11922
|
+
const url = new URL(`${DRIVE_API_BASE}${path}`);
|
|
11923
|
+
for (const [key, value] of Object.entries(params)) {
|
|
11924
|
+
if (value !== undefined && value !== null && value !== "")
|
|
11925
|
+
url.searchParams.set(key, String(value));
|
|
11926
|
+
}
|
|
11927
|
+
const response = await fetch(url, { headers: { Authorization: `Bearer ${token}`, Accept: "application/json" } });
|
|
11928
|
+
if (!response.ok) {
|
|
11929
|
+
const body = await response.text().catch(() => "");
|
|
11930
|
+
throw new Error(`Google Drive request failed (${response.status}): ${extractGoogleError(body) || response.statusText}`);
|
|
11931
|
+
}
|
|
11932
|
+
return response;
|
|
11933
|
+
}
|
|
11934
|
+
async function getValidAccessToken2(profile) {
|
|
11935
|
+
if (process.env.GOOGLE_ACCESS_TOKEN)
|
|
11936
|
+
return process.env.GOOGLE_ACCESS_TOKEN;
|
|
11937
|
+
const tokens = loadTokens2(profile);
|
|
11938
|
+
if (!tokens?.accessToken && !tokens?.refreshToken) {
|
|
11939
|
+
throw new Error(`Google Drive profile "${profile}" is not authenticated. Run: connectors auth googledrive`);
|
|
11940
|
+
}
|
|
11941
|
+
if (tokens.accessToken && (!tokens.expiresAt || Date.now() < tokens.expiresAt - REFRESH_BUFFER_MS2))
|
|
11942
|
+
return tokens.accessToken;
|
|
11943
|
+
if (!tokens.refreshToken)
|
|
11944
|
+
return tokens.accessToken ?? "";
|
|
11945
|
+
return (await refreshAccessToken2(profile, tokens)).accessToken ?? "";
|
|
11946
|
+
}
|
|
11947
|
+
async function refreshAccessToken2(profile, currentTokens) {
|
|
11948
|
+
const credentials = loadCredentials2(profile);
|
|
11949
|
+
if (!credentials.clientId || !credentials.clientSecret)
|
|
11950
|
+
throw new Error("Google Drive OAuth credentials are not configured. Run: connectors auth googledrive");
|
|
11951
|
+
if (!currentTokens.refreshToken)
|
|
11952
|
+
throw new Error(`Google Drive profile "${profile}" has no refresh token. Run: connectors auth googledrive`);
|
|
11953
|
+
const response = await fetch(TOKEN_URL2, {
|
|
11954
|
+
method: "POST",
|
|
11955
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
11956
|
+
body: new URLSearchParams({
|
|
11957
|
+
client_id: credentials.clientId,
|
|
11958
|
+
client_secret: credentials.clientSecret,
|
|
11959
|
+
refresh_token: currentTokens.refreshToken,
|
|
11960
|
+
grant_type: "refresh_token"
|
|
11961
|
+
})
|
|
11962
|
+
});
|
|
11963
|
+
const data = await response.json().catch(() => ({}));
|
|
11964
|
+
if (!response.ok || !data.access_token)
|
|
11965
|
+
throw new Error(`Google Drive token refresh failed: ${data.error_description || data.error || response.statusText}`);
|
|
11966
|
+
const tokens = {
|
|
11967
|
+
accessToken: data.access_token,
|
|
11968
|
+
refreshToken: currentTokens.refreshToken,
|
|
11969
|
+
expiresAt: Date.now() + (data.expires_in ?? 3600) * 1000,
|
|
11970
|
+
tokenType: data.token_type ?? currentTokens.tokenType,
|
|
11971
|
+
scope: data.scope ?? currentTokens.scope
|
|
11972
|
+
};
|
|
11973
|
+
saveTokens2(profile, tokens);
|
|
11974
|
+
return tokens;
|
|
11975
|
+
}
|
|
11976
|
+
function listProfiles2() {
|
|
11977
|
+
const profiles = new Set;
|
|
11978
|
+
for (const baseDir of configDirs2()) {
|
|
11979
|
+
const profilesDir = join3(baseDir, "profiles");
|
|
11980
|
+
if (!existsSync3(profilesDir))
|
|
11981
|
+
continue;
|
|
11982
|
+
for (const entry of readdirSync2(profilesDir, { withFileTypes: true })) {
|
|
11983
|
+
if (entry.isDirectory())
|
|
11984
|
+
profiles.add(entry.name);
|
|
11985
|
+
if (entry.isFile() && entry.name.endsWith(".json"))
|
|
11986
|
+
profiles.add(basename2(entry.name, ".json"));
|
|
11987
|
+
}
|
|
11988
|
+
}
|
|
11989
|
+
return Array.from(profiles).sort((a, b) => a.localeCompare(b));
|
|
11990
|
+
}
|
|
11991
|
+
function loadCredentials2(profile) {
|
|
11992
|
+
const envClientId = process.env.GOOGLE_CLIENT_ID;
|
|
11993
|
+
const envClientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
|
11994
|
+
if (envClientId && envClientSecret)
|
|
11995
|
+
return { clientId: envClientId, clientSecret: envClientSecret };
|
|
11996
|
+
for (const baseDir of configDirs2()) {
|
|
11997
|
+
const credentials = {
|
|
11998
|
+
...readJson2(join3(baseDir, "credentials.json")),
|
|
11999
|
+
...readJson2(join3(baseDir, "profiles", profile, "config.json"))
|
|
12000
|
+
};
|
|
12001
|
+
if (credentials.clientId || credentials.clientSecret)
|
|
12002
|
+
return credentials;
|
|
12003
|
+
}
|
|
12004
|
+
return {};
|
|
12005
|
+
}
|
|
12006
|
+
function loadTokens2(profile) {
|
|
12007
|
+
for (const baseDir of configDirs2()) {
|
|
12008
|
+
const fromProfile = readJson2(join3(baseDir, "profiles", profile, "tokens.json"));
|
|
12009
|
+
if (fromProfile)
|
|
12010
|
+
return fromProfile;
|
|
12011
|
+
const flat = readJson2(join3(baseDir, "profiles", `${profile}.json`));
|
|
12012
|
+
if (flat)
|
|
12013
|
+
return flat.tokens ?? (flat.accessToken || flat.refreshToken ? flat : null);
|
|
12014
|
+
}
|
|
12015
|
+
return null;
|
|
12016
|
+
}
|
|
12017
|
+
function saveTokens2(profile, tokens) {
|
|
12018
|
+
const baseDir = configDirs2().find((dir) => existsSync3(dir)) ?? configDirs2()[0];
|
|
12019
|
+
const profileDir = join3(baseDir, "profiles", profile);
|
|
12020
|
+
mkdirSync2(profileDir, { recursive: true });
|
|
12021
|
+
writeFileSync2(join3(profileDir, "tokens.json"), JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
12022
|
+
}
|
|
12023
|
+
function configDirs2() {
|
|
12024
|
+
const explicit = process.env.HASNA_GOOGLE_DRIVE_CONNECTOR_DIR ?? process.env.GOOGLE_DRIVE_CONNECTOR_DIR;
|
|
12025
|
+
if (explicit)
|
|
12026
|
+
return [explicit];
|
|
12027
|
+
const baseDir = process.env.HASNA_CONNECTORS_DIR ?? join3(homedir2(), ".hasna", "connectors");
|
|
12028
|
+
return [join3(baseDir, "connect-googledrive"), join3(baseDir, "googledrive")];
|
|
12029
|
+
}
|
|
12030
|
+
function readJson2(path) {
|
|
12031
|
+
if (!existsSync3(path))
|
|
12032
|
+
return null;
|
|
12033
|
+
try {
|
|
12034
|
+
return JSON.parse(readFileSync2(path, "utf8"));
|
|
12035
|
+
} catch {
|
|
12036
|
+
return null;
|
|
12037
|
+
}
|
|
12038
|
+
}
|
|
11605
12039
|
function defaultExportMimeType(googleMimeType) {
|
|
11606
12040
|
if (googleMimeType.endsWith(".document"))
|
|
11607
12041
|
return DEFAULT_EXPORT_FORMATS.document;
|
|
@@ -11626,11 +12060,11 @@ function extractGoogleError(body) {
|
|
|
11626
12060
|
return body;
|
|
11627
12061
|
}
|
|
11628
12062
|
}
|
|
11629
|
-
var DRIVE_API_BASE = "https://www.googleapis.com/drive/v3",
|
|
12063
|
+
var DRIVE_API_BASE = "https://www.googleapis.com/drive/v3", TOKEN_URL2 = "https://oauth2.googleapis.com/token", REFRESH_BUFFER_MS2, DEFAULT_FILE_FIELDS, DEFAULT_EXPORT_FORMATS, EXPORT_EXTENSIONS, listFilesSchema, listDrivesSchema, fileIdSchema, downloadSchema, googleDriveConnector;
|
|
11630
12064
|
var init_googledrive = __esm(() => {
|
|
11631
12065
|
init_zod();
|
|
11632
12066
|
init_connector();
|
|
11633
|
-
|
|
12067
|
+
REFRESH_BUFFER_MS2 = 5 * 60 * 1000;
|
|
11634
12068
|
DEFAULT_FILE_FIELDS = [
|
|
11635
12069
|
"id",
|
|
11636
12070
|
"name",
|
|
@@ -11711,12 +12145,12 @@ var init_googledrive = __esm(() => {
|
|
|
11711
12145
|
operations: {
|
|
11712
12146
|
"profiles.list": {
|
|
11713
12147
|
summary: "List configured Google Drive profiles.",
|
|
11714
|
-
execute: () => ({ profiles:
|
|
12148
|
+
execute: () => ({ profiles: listProfiles2() })
|
|
11715
12149
|
},
|
|
11716
12150
|
"files.list": {
|
|
11717
12151
|
summary: "List Google Drive files.",
|
|
11718
12152
|
inputSchema: listFilesSchema,
|
|
11719
|
-
execute: async ({ context }, input) =>
|
|
12153
|
+
execute: async ({ context }, input) => requestJson2(context.profile, "/files", {
|
|
11720
12154
|
pageSize: input.pageSize ?? 1000,
|
|
11721
12155
|
pageToken: input.pageToken,
|
|
11722
12156
|
q: input.q,
|
|
@@ -11731,7 +12165,7 @@ var init_googledrive = __esm(() => {
|
|
|
11731
12165
|
"files.get": {
|
|
11732
12166
|
summary: "Get Google Drive file metadata.",
|
|
11733
12167
|
inputSchema: fileIdSchema,
|
|
11734
|
-
execute: async ({ context }, input) =>
|
|
12168
|
+
execute: async ({ context }, input) => requestJson2(context.profile, `/files/${encodeURIComponent(input.fileId)}`, {
|
|
11735
12169
|
fields: input.fields ?? DEFAULT_FILE_FIELDS,
|
|
11736
12170
|
supportsAllDrives: true
|
|
11737
12171
|
})
|
|
@@ -11740,7 +12174,7 @@ var init_googledrive = __esm(() => {
|
|
|
11740
12174
|
summary: "Download or export a Google Drive file as base64 content.",
|
|
11741
12175
|
inputSchema: downloadSchema,
|
|
11742
12176
|
execute: async ({ context }, input) => {
|
|
11743
|
-
const file = input.file ?? await
|
|
12177
|
+
const file = input.file ?? await requestJson2(context.profile, `/files/${encodeURIComponent(input.fileId)}`, { fields: DEFAULT_FILE_FIELDS, supportsAllDrives: true });
|
|
11744
12178
|
const exportMimeType = file.mimeType.startsWith("application/vnd.google-apps.") ? input.exportMimeType ?? defaultExportMimeType(file.mimeType) : undefined;
|
|
11745
12179
|
const data = await requestBinary(context.profile, exportMimeType ? `/files/${encodeURIComponent(file.id)}/export` : `/files/${encodeURIComponent(file.id)}`, exportMimeType ? { mimeType: exportMimeType, supportsAllDrives: true } : { alt: "media", supportsAllDrives: true });
|
|
11746
12180
|
const mimeType = exportMimeType ?? file.mimeType ?? "application/octet-stream";
|
|
@@ -11754,7 +12188,7 @@ var init_googledrive = __esm(() => {
|
|
|
11754
12188
|
"drives.list": {
|
|
11755
12189
|
summary: "List Google shared drives.",
|
|
11756
12190
|
inputSchema: listDrivesSchema,
|
|
11757
|
-
execute: async ({ context }, input) =>
|
|
12191
|
+
execute: async ({ context }, input) => requestJson2(context.profile, "/drives", {
|
|
11758
12192
|
pageSize: input.pageSize ?? 100,
|
|
11759
12193
|
pageToken: input.pageToken,
|
|
11760
12194
|
q: input.q
|
|
@@ -11769,7 +12203,7 @@ var package_default;
|
|
|
11769
12203
|
var init_package = __esm(() => {
|
|
11770
12204
|
package_default = {
|
|
11771
12205
|
name: "@hasna/connectors",
|
|
11772
|
-
version: "1.3.
|
|
12206
|
+
version: "1.3.26",
|
|
11773
12207
|
description: "Open source connector library - Install API connectors with a single command",
|
|
11774
12208
|
type: "module",
|
|
11775
12209
|
bin: {
|
|
@@ -11860,22 +12294,22 @@ var init_package = __esm(() => {
|
|
|
11860
12294
|
import { createRequire } from "module";
|
|
11861
12295
|
import { Database } from "bun:sqlite";
|
|
11862
12296
|
import {
|
|
11863
|
-
existsSync as
|
|
11864
|
-
mkdirSync as
|
|
11865
|
-
readdirSync as
|
|
12297
|
+
existsSync as existsSync4,
|
|
12298
|
+
mkdirSync as mkdirSync3,
|
|
12299
|
+
readdirSync as readdirSync3,
|
|
11866
12300
|
copyFileSync
|
|
11867
12301
|
} from "fs";
|
|
11868
|
-
import { homedir as
|
|
11869
|
-
import { join as
|
|
11870
|
-
import { existsSync as existsSync22, mkdirSync as mkdirSync22, readFileSync as
|
|
12302
|
+
import { homedir as homedir3 } from "os";
|
|
12303
|
+
import { join as join4, relative } from "path";
|
|
12304
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync22, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
11871
12305
|
import { homedir as homedir22 } from "os";
|
|
11872
12306
|
import { join as join22 } from "path";
|
|
11873
12307
|
import { readdirSync as readdirSync22, existsSync as existsSync32 } from "fs";
|
|
11874
12308
|
import { join as join32 } from "path";
|
|
11875
|
-
import { homedir as
|
|
12309
|
+
import { homedir as homedir32 } from "os";
|
|
11876
12310
|
import { hostname as hostname2 } from "os";
|
|
11877
12311
|
import { homedir as homedir4 } from "os";
|
|
11878
|
-
import { join as
|
|
12312
|
+
import { join as join42 } from "path";
|
|
11879
12313
|
import { join as join6, dirname as dirname2 } from "path";
|
|
11880
12314
|
import { homedir as homedir5, platform } from "os";
|
|
11881
12315
|
function __accessProp2(key) {
|
|
@@ -12748,13 +13182,13 @@ function custom3(check2, _params = {}, fatal) {
|
|
|
12748
13182
|
return ZodAny2.create();
|
|
12749
13183
|
}
|
|
12750
13184
|
function getDataDir(serviceName) {
|
|
12751
|
-
const dir =
|
|
12752
|
-
|
|
13185
|
+
const dir = join4(HASNA_DIR, serviceName);
|
|
13186
|
+
mkdirSync3(dir, { recursive: true });
|
|
12753
13187
|
return dir;
|
|
12754
13188
|
}
|
|
12755
13189
|
function getDbPath(serviceName) {
|
|
12756
13190
|
const dir = getDataDir(serviceName);
|
|
12757
|
-
return
|
|
13191
|
+
return join4(dir, `${serviceName}.db`);
|
|
12758
13192
|
}
|
|
12759
13193
|
function getConfigDir() {
|
|
12760
13194
|
return CONFIG_DIR;
|
|
@@ -12767,7 +13201,7 @@ function getCloudConfig() {
|
|
|
12767
13201
|
return CloudConfigSchema.parse({});
|
|
12768
13202
|
}
|
|
12769
13203
|
try {
|
|
12770
|
-
const raw =
|
|
13204
|
+
const raw = readFileSync3(CONFIG_PATH, "utf-8");
|
|
12771
13205
|
return CloudConfigSchema.parse(JSON.parse(raw));
|
|
12772
13206
|
} catch {
|
|
12773
13207
|
return CloudConfigSchema.parse({});
|
|
@@ -12775,7 +13209,7 @@ function getCloudConfig() {
|
|
|
12775
13209
|
}
|
|
12776
13210
|
function saveCloudConfig(config2) {
|
|
12777
13211
|
mkdirSync22(CONFIG_DIR, { recursive: true });
|
|
12778
|
-
|
|
13212
|
+
writeFileSync3(CONFIG_PATH, JSON.stringify(config2, null, 2) + `
|
|
12779
13213
|
`, "utf-8");
|
|
12780
13214
|
}
|
|
12781
13215
|
function getConnectionString(dbName) {
|
|
@@ -12805,7 +13239,7 @@ function isSyncExcludedTable(table) {
|
|
|
12805
13239
|
return SYNC_EXCLUDED_TABLE_PATTERNS.some((p) => p.test(table));
|
|
12806
13240
|
}
|
|
12807
13241
|
function discoverServices() {
|
|
12808
|
-
const dataDir = join32(
|
|
13242
|
+
const dataDir = join32(homedir32(), ".hasna");
|
|
12809
13243
|
if (!existsSync32(dataDir))
|
|
12810
13244
|
return [];
|
|
12811
13245
|
try {
|
|
@@ -12827,7 +13261,7 @@ function discoverSyncableServices() {
|
|
|
12827
13261
|
return local.filter((s) => pgSet.has(s));
|
|
12828
13262
|
}
|
|
12829
13263
|
function getServiceDbPath(service) {
|
|
12830
|
-
const dataDir = join32(
|
|
13264
|
+
const dataDir = join32(homedir32(), ".hasna", service);
|
|
12831
13265
|
if (!existsSync32(dataDir))
|
|
12832
13266
|
return null;
|
|
12833
13267
|
const candidates = [
|
|
@@ -21771,7 +22205,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
21771
22205
|
init_external2();
|
|
21772
22206
|
});
|
|
21773
22207
|
init_dotfile = __esm2(() => {
|
|
21774
|
-
HASNA_DIR =
|
|
22208
|
+
HASNA_DIR = join4(homedir3(), ".hasna");
|
|
21775
22209
|
});
|
|
21776
22210
|
exports_config = {};
|
|
21777
22211
|
__export2(exports_config, {
|
|
@@ -21867,7 +22301,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
21867
22301
|
init_adapter();
|
|
21868
22302
|
init_config();
|
|
21869
22303
|
init_discover();
|
|
21870
|
-
AUTO_SYNC_CONFIG_PATH =
|
|
22304
|
+
AUTO_SYNC_CONFIG_PATH = join42(homedir4(), ".hasna", "cloud", "config.json");
|
|
21871
22305
|
init_config();
|
|
21872
22306
|
init_adapter();
|
|
21873
22307
|
init_dotfile();
|
|
@@ -21896,13 +22330,13 @@ __export(exports_database, {
|
|
|
21896
22330
|
});
|
|
21897
22331
|
import { dirname as dirname3, join as join5 } from "path";
|
|
21898
22332
|
import { homedir as homedir6 } from "os";
|
|
21899
|
-
import { mkdirSync as
|
|
22333
|
+
import { mkdirSync as mkdirSync4, existsSync as existsSync5, readdirSync as readdirSync4, copyFileSync as copyFileSync2, statSync } from "fs";
|
|
21900
22334
|
function mergeDirectoryContents(sourceDir, targetDir) {
|
|
21901
|
-
if (!
|
|
22335
|
+
if (!existsSync5(sourceDir)) {
|
|
21902
22336
|
return;
|
|
21903
22337
|
}
|
|
21904
|
-
|
|
21905
|
-
for (const entry of
|
|
22338
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
22339
|
+
for (const entry of readdirSync4(sourceDir)) {
|
|
21906
22340
|
const sourcePath = join5(sourceDir, entry);
|
|
21907
22341
|
const targetPath = join5(targetDir, entry);
|
|
21908
22342
|
try {
|
|
@@ -21911,7 +22345,7 @@ function mergeDirectoryContents(sourceDir, targetDir) {
|
|
|
21911
22345
|
mergeDirectoryContents(sourcePath, targetPath);
|
|
21912
22346
|
continue;
|
|
21913
22347
|
}
|
|
21914
|
-
if (!
|
|
22348
|
+
if (!existsSync5(targetPath)) {
|
|
21915
22349
|
copyFileSync2(sourcePath, targetPath);
|
|
21916
22350
|
}
|
|
21917
22351
|
} catch {}
|
|
@@ -21921,7 +22355,7 @@ function getConnectorsHome() {
|
|
|
21921
22355
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir6();
|
|
21922
22356
|
const newDir = join5(home, ".hasna", "connectors");
|
|
21923
22357
|
const legacyDirs = [join5(home, ".connectors"), join5(home, ".connect")];
|
|
21924
|
-
|
|
22358
|
+
mkdirSync4(newDir, { recursive: true });
|
|
21925
22359
|
for (const legacyDir of legacyDirs) {
|
|
21926
22360
|
try {
|
|
21927
22361
|
mergeDirectoryContents(legacyDir, newDir);
|
|
@@ -21939,7 +22373,7 @@ function getDatabase(path) {
|
|
|
21939
22373
|
_dbPath = null;
|
|
21940
22374
|
}
|
|
21941
22375
|
if (dbPath !== ":memory:") {
|
|
21942
|
-
|
|
22376
|
+
mkdirSync4(dirname3(dbPath), { recursive: true });
|
|
21943
22377
|
}
|
|
21944
22378
|
_db = new SqliteAdapter(dbPath);
|
|
21945
22379
|
_dbPath = dbPath;
|
|
@@ -22073,13 +22507,13 @@ var init_database = __esm(() => {
|
|
|
22073
22507
|
|
|
22074
22508
|
// src/core/connectors/imessage.ts
|
|
22075
22509
|
import {
|
|
22076
|
-
existsSync as
|
|
22077
|
-
mkdirSync as
|
|
22078
|
-
readFileSync as
|
|
22079
|
-
readdirSync as
|
|
22510
|
+
existsSync as existsSync6,
|
|
22511
|
+
mkdirSync as mkdirSync5,
|
|
22512
|
+
readFileSync as readFileSync4,
|
|
22513
|
+
readdirSync as readdirSync5,
|
|
22080
22514
|
rmSync,
|
|
22081
22515
|
statSync as statSync2,
|
|
22082
|
-
writeFileSync as
|
|
22516
|
+
writeFileSync as writeFileSync4
|
|
22083
22517
|
} from "fs";
|
|
22084
22518
|
import { join as join7 } from "path";
|
|
22085
22519
|
function buildRootHelp(specs) {
|
|
@@ -22133,19 +22567,19 @@ function getProfilesDir() {
|
|
|
22133
22567
|
}
|
|
22134
22568
|
function getCurrentProfile() {
|
|
22135
22569
|
const currentProfileFile = join7(getConfigDir2(), "current_profile");
|
|
22136
|
-
if (!
|
|
22570
|
+
if (!existsSync6(currentProfileFile)) {
|
|
22137
22571
|
return "default";
|
|
22138
22572
|
}
|
|
22139
22573
|
try {
|
|
22140
|
-
return
|
|
22574
|
+
return readFileSync4(currentProfileFile, "utf-8").trim() || "default";
|
|
22141
22575
|
} catch {
|
|
22142
22576
|
return "default";
|
|
22143
22577
|
}
|
|
22144
22578
|
}
|
|
22145
22579
|
function setCurrentProfile(profile) {
|
|
22146
22580
|
const configDir = getConfigDir2();
|
|
22147
|
-
|
|
22148
|
-
|
|
22581
|
+
mkdirSync5(configDir, { recursive: true });
|
|
22582
|
+
writeFileSync4(join7(configDir, "current_profile"), profile);
|
|
22149
22583
|
}
|
|
22150
22584
|
function getFlatProfilePath(profile) {
|
|
22151
22585
|
return join7(getProfilesDir(), `${profile}.json`);
|
|
@@ -22155,7 +22589,7 @@ function getDirectoryProfilePath(profile) {
|
|
|
22155
22589
|
}
|
|
22156
22590
|
function loadJsonFile(path) {
|
|
22157
22591
|
try {
|
|
22158
|
-
return JSON.parse(
|
|
22592
|
+
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
22159
22593
|
} catch {
|
|
22160
22594
|
return {};
|
|
22161
22595
|
}
|
|
@@ -22171,8 +22605,8 @@ function sanitizeProfileConfig(config2) {
|
|
|
22171
22605
|
};
|
|
22172
22606
|
}
|
|
22173
22607
|
function loadProfile(profile = getCurrentProfile()) {
|
|
22174
|
-
const flatConfig =
|
|
22175
|
-
const directoryConfig =
|
|
22608
|
+
const flatConfig = existsSync6(getFlatProfilePath(profile)) ? loadJsonFile(getFlatProfilePath(profile)) : {};
|
|
22609
|
+
const directoryConfig = existsSync6(getDirectoryProfilePath(profile)) ? loadJsonFile(getDirectoryProfilePath(profile)) : {};
|
|
22176
22610
|
return sanitizeProfileConfig({
|
|
22177
22611
|
...flatConfig,
|
|
22178
22612
|
...directoryConfig
|
|
@@ -22180,24 +22614,24 @@ function loadProfile(profile = getCurrentProfile()) {
|
|
|
22180
22614
|
}
|
|
22181
22615
|
function writeProfile(profile, config2) {
|
|
22182
22616
|
const profilesDir = getProfilesDir();
|
|
22183
|
-
|
|
22184
|
-
|
|
22617
|
+
mkdirSync5(profilesDir, { recursive: true });
|
|
22618
|
+
writeFileSync4(getFlatProfilePath(profile), JSON.stringify(config2, null, 2) + `
|
|
22185
22619
|
`);
|
|
22186
22620
|
}
|
|
22187
22621
|
function profileExists(profile) {
|
|
22188
22622
|
if (profile === "default") {
|
|
22189
22623
|
return true;
|
|
22190
22624
|
}
|
|
22191
|
-
return
|
|
22625
|
+
return existsSync6(getFlatProfilePath(profile)) || existsSync6(join7(getProfilesDir(), profile));
|
|
22192
22626
|
}
|
|
22193
|
-
function
|
|
22627
|
+
function listProfiles3() {
|
|
22194
22628
|
const profilesDir = getProfilesDir();
|
|
22195
22629
|
const seen = new Set(["default"]);
|
|
22196
|
-
if (!
|
|
22630
|
+
if (!existsSync6(profilesDir)) {
|
|
22197
22631
|
return [...seen];
|
|
22198
22632
|
}
|
|
22199
22633
|
try {
|
|
22200
|
-
for (const entry of
|
|
22634
|
+
for (const entry of readdirSync5(profilesDir)) {
|
|
22201
22635
|
const fullPath = join7(profilesDir, entry);
|
|
22202
22636
|
const stat = statSync2(fullPath);
|
|
22203
22637
|
if (stat.isDirectory()) {
|
|
@@ -22220,10 +22654,10 @@ function createProfile(profile, config2 = {}) {
|
|
|
22220
22654
|
function clearProfile(profile = getCurrentProfile()) {
|
|
22221
22655
|
const flatPath = getFlatProfilePath(profile);
|
|
22222
22656
|
const directoryPath = join7(getProfilesDir(), profile);
|
|
22223
|
-
if (
|
|
22657
|
+
if (existsSync6(flatPath)) {
|
|
22224
22658
|
rmSync(flatPath);
|
|
22225
22659
|
}
|
|
22226
|
-
if (
|
|
22660
|
+
if (existsSync6(directoryPath)) {
|
|
22227
22661
|
rmSync(directoryPath, { recursive: true, force: true });
|
|
22228
22662
|
}
|
|
22229
22663
|
}
|
|
@@ -22519,7 +22953,7 @@ async function sendMessage(context, input) {
|
|
|
22519
22953
|
direction: "outbound"
|
|
22520
22954
|
});
|
|
22521
22955
|
}
|
|
22522
|
-
async function
|
|
22956
|
+
async function replyToMessage2(context, input) {
|
|
22523
22957
|
const payload = await bridgeRequest(context, "/messages/reply", {
|
|
22524
22958
|
method: "POST",
|
|
22525
22959
|
body: {
|
|
@@ -22633,7 +23067,7 @@ async function runProfileCommand2(args, context) {
|
|
|
22633
23067
|
switch (subcommand) {
|
|
22634
23068
|
case "list": {
|
|
22635
23069
|
const current = getCurrentProfile();
|
|
22636
|
-
const profiles =
|
|
23070
|
+
const profiles = listProfiles3();
|
|
22637
23071
|
return successOutput({ current, profiles }, context.format, () => profiles.map((profile) => `${profile}${profile === current ? " (active)" : ""}`).join(`
|
|
22638
23072
|
`));
|
|
22639
23073
|
}
|
|
@@ -22807,7 +23241,7 @@ async function runMessageCommand(args, context) {
|
|
|
22807
23241
|
if (!conversationId || !text) {
|
|
22808
23242
|
return failure2("Usage: connect-imessage message reply --conversation <id> --text <text>");
|
|
22809
23243
|
}
|
|
22810
|
-
return successOutput(await
|
|
23244
|
+
return successOutput(await replyToMessage2(resolved, {
|
|
22811
23245
|
conversationId,
|
|
22812
23246
|
text,
|
|
22813
23247
|
replyToMessageId: asString2(options.replyTo),
|
|
@@ -23085,7 +23519,7 @@ var init_imessage = __esm(() => {
|
|
|
23085
23519
|
summary: "Reply to an existing conversation through the bridge",
|
|
23086
23520
|
inputSchema: messageReplyInputSchema,
|
|
23087
23521
|
async execute({ context }, input) {
|
|
23088
|
-
return
|
|
23522
|
+
return replyToMessage2(context, input);
|
|
23089
23523
|
}
|
|
23090
23524
|
}
|
|
23091
23525
|
},
|
|
@@ -23149,18 +23583,18 @@ var init_imessage = __esm(() => {
|
|
|
23149
23583
|
});
|
|
23150
23584
|
|
|
23151
23585
|
// src/core/connectors/stripe.ts
|
|
23152
|
-
import { existsSync as
|
|
23153
|
-
import { dirname as dirname4, join as
|
|
23586
|
+
import { existsSync as existsSync7 } from "fs";
|
|
23587
|
+
import { dirname as dirname4, join as join9 } from "path";
|
|
23154
23588
|
import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "url";
|
|
23155
23589
|
function resolveStripeConnectorDir() {
|
|
23156
23590
|
const candidates = [
|
|
23157
|
-
|
|
23158
|
-
|
|
23159
|
-
|
|
23160
|
-
|
|
23591
|
+
join9(__dirname3, "..", "..", "..", "connectors", "connect-stripe"),
|
|
23592
|
+
join9(__dirname3, "..", "..", "connectors", "connect-stripe"),
|
|
23593
|
+
join9(__dirname3, "..", "connectors", "connect-stripe"),
|
|
23594
|
+
join9(process.cwd(), "connectors", "connect-stripe")
|
|
23161
23595
|
];
|
|
23162
23596
|
for (const candidate of candidates) {
|
|
23163
|
-
if (
|
|
23597
|
+
if (existsSync7(candidate)) {
|
|
23164
23598
|
return candidate;
|
|
23165
23599
|
}
|
|
23166
23600
|
}
|
|
@@ -23208,10 +23642,10 @@ function buildCommandHelp2(spec) {
|
|
|
23208
23642
|
`);
|
|
23209
23643
|
}
|
|
23210
23644
|
async function loadStripeApiModule() {
|
|
23211
|
-
return await import(pathToFileURL2(
|
|
23645
|
+
return await import(pathToFileURL2(join9(CONNECTOR_DIR2, "src", "api", "index.ts")).href);
|
|
23212
23646
|
}
|
|
23213
23647
|
async function loadStripeConfigModule() {
|
|
23214
|
-
return await import(pathToFileURL2(
|
|
23648
|
+
return await import(pathToFileURL2(join9(CONNECTOR_DIR2, "src", "utils", "config.ts")).href);
|
|
23215
23649
|
}
|
|
23216
23650
|
function extractGlobalArgs3(args) {
|
|
23217
23651
|
const remaining = [];
|
|
@@ -24032,10 +24466,12 @@ var INTERNAL_CONNECTOR_DEFINITIONS, INTERNAL_CONNECTOR_REGISTRY;
|
|
|
24032
24466
|
var init_builtins = __esm(() => {
|
|
24033
24467
|
init_registry();
|
|
24034
24468
|
init_github();
|
|
24469
|
+
init_gmail();
|
|
24035
24470
|
init_googledrive();
|
|
24036
24471
|
init_imessage();
|
|
24037
24472
|
init_stripe();
|
|
24038
24473
|
INTERNAL_CONNECTOR_DEFINITIONS = [
|
|
24474
|
+
gmailConnector,
|
|
24039
24475
|
githubConnector,
|
|
24040
24476
|
googleDriveConnector,
|
|
24041
24477
|
imessageConnector,
|
|
@@ -24055,25 +24491,25 @@ __export(exports_llm, {
|
|
|
24055
24491
|
PROVIDER_DEFAULTS: () => PROVIDER_DEFAULTS,
|
|
24056
24492
|
LLMClient: () => LLMClient
|
|
24057
24493
|
});
|
|
24058
|
-
import { existsSync as
|
|
24059
|
-
import { join as
|
|
24494
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6 } from "fs";
|
|
24495
|
+
import { join as join11 } from "path";
|
|
24060
24496
|
function getLlmConfigPath() {
|
|
24061
|
-
return
|
|
24497
|
+
return join11(getConnectorsHome(), "llm.json");
|
|
24062
24498
|
}
|
|
24063
24499
|
function getLlmConfig() {
|
|
24064
24500
|
const path = getLlmConfigPath();
|
|
24065
|
-
if (!
|
|
24501
|
+
if (!existsSync9(path))
|
|
24066
24502
|
return null;
|
|
24067
24503
|
try {
|
|
24068
|
-
return JSON.parse(
|
|
24504
|
+
return JSON.parse(readFileSync6(path, "utf-8"));
|
|
24069
24505
|
} catch {
|
|
24070
24506
|
return null;
|
|
24071
24507
|
}
|
|
24072
24508
|
}
|
|
24073
24509
|
function saveLlmConfig(config2) {
|
|
24074
24510
|
const dir = getConnectorsHome();
|
|
24075
|
-
|
|
24076
|
-
|
|
24511
|
+
mkdirSync6(dir, { recursive: true });
|
|
24512
|
+
writeFileSync5(getLlmConfigPath(), JSON.stringify(config2, null, 2));
|
|
24077
24513
|
}
|
|
24078
24514
|
function setLlmStrip(enabled) {
|
|
24079
24515
|
const config2 = getLlmConfig();
|
|
@@ -24192,15 +24628,15 @@ __export(exports_installer, {
|
|
|
24192
24628
|
getConnectorDocs: () => getConnectorDocs,
|
|
24193
24629
|
connectorExists: () => connectorExists
|
|
24194
24630
|
});
|
|
24195
|
-
import { existsSync as
|
|
24196
|
-
import { join as
|
|
24631
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync6, readdirSync as readdirSync6, statSync as statSync3, rmSync as rmSync2 } from "fs";
|
|
24632
|
+
import { join as join12, dirname as dirname6 } from "path";
|
|
24197
24633
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
24198
24634
|
function resolveConnectorsDir() {
|
|
24199
|
-
const fromBin =
|
|
24200
|
-
if (
|
|
24635
|
+
const fromBin = join12(__dirname4, "..", "connectors");
|
|
24636
|
+
if (existsSync10(fromBin))
|
|
24201
24637
|
return fromBin;
|
|
24202
|
-
const fromSrc =
|
|
24203
|
-
if (
|
|
24638
|
+
const fromSrc = join12(__dirname4, "..", "..", "connectors");
|
|
24639
|
+
if (existsSync10(fromSrc))
|
|
24204
24640
|
return fromSrc;
|
|
24205
24641
|
return fromBin;
|
|
24206
24642
|
}
|
|
@@ -24208,21 +24644,21 @@ function normalizeConnectorName(name) {
|
|
|
24208
24644
|
return name.startsWith("connect-") ? name.slice("connect-".length) : name;
|
|
24209
24645
|
}
|
|
24210
24646
|
function getProjectConnectorsDir(targetDir) {
|
|
24211
|
-
return
|
|
24647
|
+
return join12(targetDir, PROJECT_CONNECTORS_DIRNAME);
|
|
24212
24648
|
}
|
|
24213
24649
|
function getEnablementManifestPath(targetDir) {
|
|
24214
|
-
return
|
|
24650
|
+
return join12(getProjectConnectorsDir(targetDir), ENABLEMENT_MANIFEST_FILENAME);
|
|
24215
24651
|
}
|
|
24216
24652
|
function getLegacyInstallPath(targetDir, name) {
|
|
24217
|
-
return
|
|
24653
|
+
return join12(getProjectConnectorsDir(targetDir), `connect-${normalizeConnectorName(name)}`);
|
|
24218
24654
|
}
|
|
24219
24655
|
function loadEnablementManifest(targetDir) {
|
|
24220
24656
|
const manifestPath = getEnablementManifestPath(targetDir);
|
|
24221
|
-
if (!
|
|
24657
|
+
if (!existsSync10(manifestPath)) {
|
|
24222
24658
|
return null;
|
|
24223
24659
|
}
|
|
24224
24660
|
try {
|
|
24225
|
-
const raw = JSON.parse(
|
|
24661
|
+
const raw = JSON.parse(readFileSync7(manifestPath, "utf-8"));
|
|
24226
24662
|
if (!Array.isArray(raw.connectors)) {
|
|
24227
24663
|
return null;
|
|
24228
24664
|
}
|
|
@@ -24238,11 +24674,11 @@ function loadEnablementManifest(targetDir) {
|
|
|
24238
24674
|
}
|
|
24239
24675
|
function getLegacyInstalledConnectors(targetDir) {
|
|
24240
24676
|
const connectorsDir = getProjectConnectorsDir(targetDir);
|
|
24241
|
-
if (!
|
|
24677
|
+
if (!existsSync10(connectorsDir)) {
|
|
24242
24678
|
return [];
|
|
24243
24679
|
}
|
|
24244
|
-
return
|
|
24245
|
-
const fullPath =
|
|
24680
|
+
return readdirSync6(connectorsDir).filter((entry) => {
|
|
24681
|
+
const fullPath = join12(connectorsDir, entry);
|
|
24246
24682
|
return entry.startsWith("connect-") && statSync3(fullPath).isDirectory();
|
|
24247
24683
|
}).map((entry) => entry.replace("connect-", "")).sort();
|
|
24248
24684
|
}
|
|
@@ -24251,7 +24687,7 @@ function getEnabledConnectors(targetDir) {
|
|
|
24251
24687
|
return [...new Set([...manifestConnectors, ...getLegacyInstalledConnectors(targetDir)])].sort();
|
|
24252
24688
|
}
|
|
24253
24689
|
function updateConnectorsIndex(connectorsDir, connectors18) {
|
|
24254
|
-
const indexPath =
|
|
24690
|
+
const indexPath = join12(connectorsDir, ENABLEMENT_INDEX_FILENAME);
|
|
24255
24691
|
const connectorList = connectors18.map((connector) => ` "${connector}",`).join(`
|
|
24256
24692
|
`);
|
|
24257
24693
|
const content = `/**
|
|
@@ -24267,28 +24703,28 @@ ${connectorList}
|
|
|
24267
24703
|
|
|
24268
24704
|
export type EnabledConnectorName = typeof enabledConnectors[number];
|
|
24269
24705
|
`;
|
|
24270
|
-
|
|
24706
|
+
writeFileSync6(indexPath, content);
|
|
24271
24707
|
}
|
|
24272
24708
|
function writeEnablementManifest(targetDir, connectors18) {
|
|
24273
24709
|
const connectorsDir = getProjectConnectorsDir(targetDir);
|
|
24274
|
-
|
|
24710
|
+
mkdirSync7(connectorsDir, { recursive: true });
|
|
24275
24711
|
const manifest = {
|
|
24276
24712
|
version: 1,
|
|
24277
24713
|
mode: "internal",
|
|
24278
24714
|
updatedAt: new Date().toISOString(),
|
|
24279
24715
|
connectors: [...new Set(connectors18.map((value) => normalizeConnectorName(value)))].sort()
|
|
24280
24716
|
};
|
|
24281
|
-
|
|
24717
|
+
writeFileSync6(getEnablementManifestPath(targetDir), JSON.stringify(manifest, null, 2) + `
|
|
24282
24718
|
`);
|
|
24283
24719
|
updateConnectorsIndex(connectorsDir, manifest.connectors);
|
|
24284
24720
|
}
|
|
24285
24721
|
function getConnectorPath(name) {
|
|
24286
24722
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
24287
|
-
return
|
|
24723
|
+
return join12(CONNECTORS_DIR, connectorName);
|
|
24288
24724
|
}
|
|
24289
24725
|
function connectorExists(name) {
|
|
24290
24726
|
const normalizedName = normalizeConnectorName(name);
|
|
24291
|
-
return hasInternalConnectorDefinition(normalizedName) ||
|
|
24727
|
+
return hasInternalConnectorDefinition(normalizedName) || existsSync10(getConnectorPath(normalizedName));
|
|
24292
24728
|
}
|
|
24293
24729
|
function installConnector(name, options = {}) {
|
|
24294
24730
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
@@ -24321,7 +24757,7 @@ function installConnector(name, options = {}) {
|
|
|
24321
24757
|
try {
|
|
24322
24758
|
const nextEnabled = [...new Set([...installed, normalizedName])].sort();
|
|
24323
24759
|
writeEnablementManifest(targetDir, nextEnabled);
|
|
24324
|
-
if (overwrite &&
|
|
24760
|
+
if (overwrite && existsSync10(legacyInstallPath)) {
|
|
24325
24761
|
rmSync2(legacyInstallPath, { recursive: true });
|
|
24326
24762
|
}
|
|
24327
24763
|
return {
|
|
@@ -24356,9 +24792,9 @@ function parseConnectorDocs(raw) {
|
|
|
24356
24792
|
function getConnectorDocs(name) {
|
|
24357
24793
|
const normalizedName = normalizeConnectorName(name);
|
|
24358
24794
|
const connectorPath = getConnectorPath(normalizedName);
|
|
24359
|
-
const claudeMdPath =
|
|
24360
|
-
if (
|
|
24361
|
-
return parseConnectorDocs(
|
|
24795
|
+
const claudeMdPath = join12(connectorPath, "CLAUDE.md");
|
|
24796
|
+
if (existsSync10(claudeMdPath)) {
|
|
24797
|
+
return parseConnectorDocs(readFileSync7(claudeMdPath, "utf-8"));
|
|
24362
24798
|
}
|
|
24363
24799
|
const internalDocs = getInternalConnectorDefinition(normalizedName)?.docsMarkdown;
|
|
24364
24800
|
if (internalDocs) {
|
|
@@ -24402,7 +24838,7 @@ function removeConnector(name, targetDir = process.cwd()) {
|
|
|
24402
24838
|
const nextEnabled = installed.filter((connector) => connector !== normalizedName);
|
|
24403
24839
|
writeEnablementManifest(targetDir, nextEnabled);
|
|
24404
24840
|
const legacyInstallPath = getLegacyInstallPath(targetDir, normalizedName);
|
|
24405
|
-
if (
|
|
24841
|
+
if (existsSync10(legacyInstallPath)) {
|
|
24406
24842
|
rmSync2(legacyInstallPath, { recursive: true });
|
|
24407
24843
|
}
|
|
24408
24844
|
return true;
|
|
@@ -24484,13 +24920,13 @@ var init_usage = __esm(() => {
|
|
|
24484
24920
|
});
|
|
24485
24921
|
|
|
24486
24922
|
// src/lib/lock.ts
|
|
24487
|
-
import { openSync, closeSync, unlinkSync, existsSync as
|
|
24488
|
-
import { join as
|
|
24489
|
-
import { mkdirSync as
|
|
24923
|
+
import { openSync, closeSync, unlinkSync, existsSync as existsSync11, statSync as statSync4 } from "fs";
|
|
24924
|
+
import { join as join13 } from "path";
|
|
24925
|
+
import { mkdirSync as mkdirSync8 } from "fs";
|
|
24490
24926
|
function lockPath(connector) {
|
|
24491
|
-
const dir =
|
|
24492
|
-
|
|
24493
|
-
return
|
|
24927
|
+
const dir = join13(getConnectorsHome(), `connect-${connector}`);
|
|
24928
|
+
mkdirSync8(dir, { recursive: true });
|
|
24929
|
+
return join13(dir, ".write.lock");
|
|
24494
24930
|
}
|
|
24495
24931
|
function isStale(path) {
|
|
24496
24932
|
try {
|
|
@@ -24501,7 +24937,7 @@ function isStale(path) {
|
|
|
24501
24937
|
}
|
|
24502
24938
|
}
|
|
24503
24939
|
function tryAcquire(path) {
|
|
24504
|
-
if (
|
|
24940
|
+
if (existsSync11(path) && isStale(path)) {
|
|
24505
24941
|
try {
|
|
24506
24942
|
unlinkSync(path);
|
|
24507
24943
|
} catch {}
|
|
@@ -24550,8 +24986,8 @@ var init_lock = __esm(() => {
|
|
|
24550
24986
|
});
|
|
24551
24987
|
|
|
24552
24988
|
// src/server/auth.ts
|
|
24553
|
-
import { existsSync as
|
|
24554
|
-
import { join as
|
|
24989
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync9, readdirSync as readdirSync7, rmSync as rmSync3, statSync as statSync5 } from "fs";
|
|
24990
|
+
import { join as join14 } from "path";
|
|
24555
24991
|
function getAuthType(name) {
|
|
24556
24992
|
const docs = getConnectorDocs(name);
|
|
24557
24993
|
if (!docs?.auth)
|
|
@@ -24565,14 +25001,14 @@ function getAuthType(name) {
|
|
|
24565
25001
|
}
|
|
24566
25002
|
function getConnectorConfigDir(name) {
|
|
24567
25003
|
const connectorName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
24568
|
-
return
|
|
25004
|
+
return join14(getConnectorsHome(), connectorName);
|
|
24569
25005
|
}
|
|
24570
25006
|
function getCurrentProfile2(name) {
|
|
24571
25007
|
const configDir = getConnectorConfigDir(name);
|
|
24572
|
-
const currentProfileFile =
|
|
24573
|
-
if (
|
|
25008
|
+
const currentProfileFile = join14(configDir, "current_profile");
|
|
25009
|
+
if (existsSync12(currentProfileFile)) {
|
|
24574
25010
|
try {
|
|
24575
|
-
return
|
|
25011
|
+
return readFileSync8(currentProfileFile, "utf-8").trim() || "default";
|
|
24576
25012
|
} catch {
|
|
24577
25013
|
return "default";
|
|
24578
25014
|
}
|
|
@@ -24584,16 +25020,16 @@ function loadProfileConfig(name) {
|
|
|
24584
25020
|
const profile = getCurrentProfile2(name);
|
|
24585
25021
|
let flatConfig = {};
|
|
24586
25022
|
let dirConfig = {};
|
|
24587
|
-
const profileFile =
|
|
24588
|
-
if (
|
|
25023
|
+
const profileFile = join14(configDir, "profiles", `${profile}.json`);
|
|
25024
|
+
if (existsSync12(profileFile)) {
|
|
24589
25025
|
try {
|
|
24590
|
-
flatConfig = JSON.parse(
|
|
25026
|
+
flatConfig = JSON.parse(readFileSync8(profileFile, "utf-8"));
|
|
24591
25027
|
} catch {}
|
|
24592
25028
|
}
|
|
24593
|
-
const profileDirConfig =
|
|
24594
|
-
if (
|
|
25029
|
+
const profileDirConfig = join14(configDir, "profiles", profile, "config.json");
|
|
25030
|
+
if (existsSync12(profileDirConfig)) {
|
|
24595
25031
|
try {
|
|
24596
|
-
dirConfig = JSON.parse(
|
|
25032
|
+
dirConfig = JSON.parse(readFileSync8(profileDirConfig, "utf-8"));
|
|
24597
25033
|
} catch {}
|
|
24598
25034
|
}
|
|
24599
25035
|
if (Object.keys(flatConfig).length === 0 && Object.keys(dirConfig).length === 0) {
|
|
@@ -24601,13 +25037,13 @@ function loadProfileConfig(name) {
|
|
|
24601
25037
|
}
|
|
24602
25038
|
return { ...flatConfig, ...dirConfig };
|
|
24603
25039
|
}
|
|
24604
|
-
function
|
|
25040
|
+
function loadTokens3(name) {
|
|
24605
25041
|
const configDir = getConnectorConfigDir(name);
|
|
24606
25042
|
const profile = getCurrentProfile2(name);
|
|
24607
|
-
const tokensFile =
|
|
24608
|
-
if (
|
|
25043
|
+
const tokensFile = join14(configDir, "profiles", profile, "tokens.json");
|
|
25044
|
+
if (existsSync12(tokensFile)) {
|
|
24609
25045
|
try {
|
|
24610
|
-
return JSON.parse(
|
|
25046
|
+
return JSON.parse(readFileSync8(tokensFile, "utf-8"));
|
|
24611
25047
|
} catch {
|
|
24612
25048
|
return null;
|
|
24613
25049
|
}
|
|
@@ -24646,7 +25082,7 @@ function getAuthStatus(name) {
|
|
|
24646
25082
|
const authType = getAuthType(name);
|
|
24647
25083
|
const docs = getConnectorDocs(name);
|
|
24648
25084
|
const oauthConfig = authType === "oauth" ? getOAuthConfig(name) : {};
|
|
24649
|
-
const tokens = authType === "oauth" ?
|
|
25085
|
+
const tokens = authType === "oauth" ? loadTokens3(name) : null;
|
|
24650
25086
|
const profileConfig = authType === "oauth" ? loadProfileConfig(name) : {};
|
|
24651
25087
|
const envVars = (docs?.envVars || []).map((v) => ({
|
|
24652
25088
|
variable: v.variable,
|
|
@@ -24695,43 +25131,43 @@ function _saveApiKey(name, key, field) {
|
|
|
24695
25131
|
const profile = getCurrentProfile2(name);
|
|
24696
25132
|
const keyField = field || guessKeyField(name);
|
|
24697
25133
|
if (keyField === "clientId" || keyField === "clientSecret") {
|
|
24698
|
-
const credentialsFile =
|
|
24699
|
-
|
|
25134
|
+
const credentialsFile = join14(configDir, "credentials.json");
|
|
25135
|
+
mkdirSync9(configDir, { recursive: true });
|
|
24700
25136
|
let creds = {};
|
|
24701
|
-
if (
|
|
25137
|
+
if (existsSync12(credentialsFile)) {
|
|
24702
25138
|
try {
|
|
24703
|
-
creds = JSON.parse(
|
|
25139
|
+
creds = JSON.parse(readFileSync8(credentialsFile, "utf-8"));
|
|
24704
25140
|
} catch {}
|
|
24705
25141
|
}
|
|
24706
25142
|
creds[keyField] = key;
|
|
24707
|
-
|
|
25143
|
+
writeFileSync7(credentialsFile, JSON.stringify(creds, null, 2));
|
|
24708
25144
|
return;
|
|
24709
25145
|
}
|
|
24710
|
-
const profileFile =
|
|
24711
|
-
const profileDir =
|
|
24712
|
-
if (
|
|
25146
|
+
const profileFile = join14(configDir, "profiles", `${profile}.json`);
|
|
25147
|
+
const profileDir = join14(configDir, "profiles", profile);
|
|
25148
|
+
if (existsSync12(profileFile)) {
|
|
24713
25149
|
let config2 = {};
|
|
24714
25150
|
try {
|
|
24715
|
-
config2 = JSON.parse(
|
|
25151
|
+
config2 = JSON.parse(readFileSync8(profileFile, "utf-8"));
|
|
24716
25152
|
} catch {}
|
|
24717
25153
|
config2[keyField] = key;
|
|
24718
|
-
|
|
25154
|
+
writeFileSync7(profileFile, JSON.stringify(config2, null, 2));
|
|
24719
25155
|
return;
|
|
24720
25156
|
}
|
|
24721
|
-
if (
|
|
24722
|
-
const configFile =
|
|
25157
|
+
if (existsSync12(profileDir)) {
|
|
25158
|
+
const configFile = join14(profileDir, "config.json");
|
|
24723
25159
|
let config2 = {};
|
|
24724
|
-
if (
|
|
25160
|
+
if (existsSync12(configFile)) {
|
|
24725
25161
|
try {
|
|
24726
|
-
config2 = JSON.parse(
|
|
25162
|
+
config2 = JSON.parse(readFileSync8(configFile, "utf-8"));
|
|
24727
25163
|
} catch {}
|
|
24728
25164
|
}
|
|
24729
25165
|
config2[keyField] = key;
|
|
24730
|
-
|
|
25166
|
+
writeFileSync7(configFile, JSON.stringify(config2, null, 2));
|
|
24731
25167
|
return;
|
|
24732
25168
|
}
|
|
24733
|
-
|
|
24734
|
-
|
|
25169
|
+
mkdirSync9(profileDir, { recursive: true });
|
|
25170
|
+
writeFileSync7(join14(profileDir, "config.json"), JSON.stringify({ [keyField]: key }, null, 2));
|
|
24735
25171
|
}
|
|
24736
25172
|
function guessKeyField(name) {
|
|
24737
25173
|
const docs = getConnectorDocs(name);
|
|
@@ -24749,10 +25185,10 @@ function guessKeyField(name) {
|
|
|
24749
25185
|
}
|
|
24750
25186
|
function getOAuthConfig(name) {
|
|
24751
25187
|
const configDir = getConnectorConfigDir(name);
|
|
24752
|
-
const credentialsFile =
|
|
24753
|
-
if (
|
|
25188
|
+
const credentialsFile = join14(configDir, "credentials.json");
|
|
25189
|
+
if (existsSync12(credentialsFile)) {
|
|
24754
25190
|
try {
|
|
24755
|
-
const creds = JSON.parse(
|
|
25191
|
+
const creds = JSON.parse(readFileSync8(credentialsFile, "utf-8"));
|
|
24756
25192
|
return { clientId: creds.clientId, clientSecret: creds.clientSecret };
|
|
24757
25193
|
} catch {}
|
|
24758
25194
|
}
|
|
@@ -24765,17 +25201,17 @@ function getOAuthConfig(name) {
|
|
|
24765
25201
|
function saveOAuthTokens(name, tokens) {
|
|
24766
25202
|
const configDir = getConnectorConfigDir(name);
|
|
24767
25203
|
const profile = getCurrentProfile2(name);
|
|
24768
|
-
const profileDir =
|
|
24769
|
-
|
|
24770
|
-
const tokensFile =
|
|
24771
|
-
|
|
25204
|
+
const profileDir = join14(configDir, "profiles", profile);
|
|
25205
|
+
mkdirSync9(profileDir, { recursive: true });
|
|
25206
|
+
const tokensFile = join14(profileDir, "tokens.json");
|
|
25207
|
+
writeFileSync7(tokensFile, JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
24772
25208
|
}
|
|
24773
25209
|
async function refreshOAuthToken(name) {
|
|
24774
25210
|
return withWriteLock(name, () => _refreshOAuthToken(name));
|
|
24775
25211
|
}
|
|
24776
25212
|
async function _refreshOAuthToken(name) {
|
|
24777
25213
|
const oauthConfig = getOAuthConfig(name);
|
|
24778
|
-
const currentTokens =
|
|
25214
|
+
const currentTokens = loadTokens3(name);
|
|
24779
25215
|
if (!oauthConfig.clientId || !oauthConfig.clientSecret) {
|
|
24780
25216
|
throw new Error("OAuth credentials not configured for " + name);
|
|
24781
25217
|
}
|
|
@@ -24868,16 +25304,16 @@ __export(exports_runner, {
|
|
|
24868
25304
|
buildEnvWithCredentials: () => buildEnvWithCredentials,
|
|
24869
25305
|
buildConnectorOperationArgs: () => buildConnectorOperationArgs
|
|
24870
25306
|
});
|
|
24871
|
-
import { existsSync as
|
|
24872
|
-
import { join as
|
|
25307
|
+
import { existsSync as existsSync14, readdirSync as readdirSync8 } from "fs";
|
|
25308
|
+
import { join as join16, dirname as dirname7 } from "path";
|
|
24873
25309
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
24874
25310
|
import { spawn as spawn2 } from "child_process";
|
|
24875
25311
|
function resolveConnectorsDir2() {
|
|
24876
|
-
const fromBin =
|
|
24877
|
-
if (
|
|
25312
|
+
const fromBin = join16(__dirname5, "..", "connectors");
|
|
25313
|
+
if (existsSync14(fromBin))
|
|
24878
25314
|
return fromBin;
|
|
24879
|
-
const fromSrc =
|
|
24880
|
-
if (
|
|
25315
|
+
const fromSrc = join16(__dirname5, "..", "..", "connectors");
|
|
25316
|
+
if (existsSync14(fromSrc))
|
|
24881
25317
|
return fromSrc;
|
|
24882
25318
|
return fromBin;
|
|
24883
25319
|
}
|
|
@@ -24922,7 +25358,7 @@ function buildEnvWithCredentials(connectorName, baseEnv) {
|
|
|
24922
25358
|
}
|
|
24923
25359
|
if (getAuthType(connectorName) === "oauth") {
|
|
24924
25360
|
const oauthConfig = getOAuthConfig(connectorName);
|
|
24925
|
-
const tokens =
|
|
25361
|
+
const tokens = loadTokens3(connectorName);
|
|
24926
25362
|
for (const { variable } of getEnvVars(connectorName)) {
|
|
24927
25363
|
if (env[variable])
|
|
24928
25364
|
continue;
|
|
@@ -24943,9 +25379,9 @@ function buildEnvWithCredentials(connectorName, baseEnv) {
|
|
|
24943
25379
|
}
|
|
24944
25380
|
function getConnectorCliPath(name) {
|
|
24945
25381
|
const safeName = name.replace(/[^a-z0-9-]/g, "");
|
|
24946
|
-
const connectorDir =
|
|
24947
|
-
const cliPath =
|
|
24948
|
-
if (
|
|
25382
|
+
const connectorDir = join16(CONNECTORS_DIR2, `connect-${safeName}`);
|
|
25383
|
+
const cliPath = join16(connectorDir, "src", "cli", "index.ts");
|
|
25384
|
+
if (existsSync14(cliPath))
|
|
24949
25385
|
return cliPath;
|
|
24950
25386
|
return null;
|
|
24951
25387
|
}
|
|
@@ -25217,7 +25653,7 @@ async function getConnectorCommandHelp(name, command) {
|
|
|
25217
25653
|
function getConnectorsWithCli() {
|
|
25218
25654
|
const connectors18 = new Set;
|
|
25219
25655
|
try {
|
|
25220
|
-
const dirs =
|
|
25656
|
+
const dirs = readdirSync8(CONNECTORS_DIR2);
|
|
25221
25657
|
for (const dir of dirs) {
|
|
25222
25658
|
if (!dir.startsWith("connect-"))
|
|
25223
25659
|
continue;
|
|
@@ -34251,8 +34687,8 @@ class StdioServerTransport {
|
|
|
34251
34687
|
|
|
34252
34688
|
// src/lib/registry.ts
|
|
34253
34689
|
init_builtins();
|
|
34254
|
-
import { existsSync as
|
|
34255
|
-
import { join as
|
|
34690
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
|
|
34691
|
+
import { join as join10, dirname as dirname5 } from "path";
|
|
34256
34692
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
34257
34693
|
|
|
34258
34694
|
// src/lib/fuzzy.ts
|
|
@@ -40523,17 +40959,17 @@ function loadConnectorVersions() {
|
|
|
40523
40959
|
versionsLoaded = true;
|
|
40524
40960
|
const thisDir = dirname5(fileURLToPath3(import.meta.url));
|
|
40525
40961
|
const candidates = [
|
|
40526
|
-
|
|
40527
|
-
|
|
40962
|
+
join10(thisDir, "..", "connectors"),
|
|
40963
|
+
join10(thisDir, "..", "..", "connectors")
|
|
40528
40964
|
];
|
|
40529
|
-
const connectorsDir = candidates.find((d) =>
|
|
40965
|
+
const connectorsDir = candidates.find((d) => existsSync8(d));
|
|
40530
40966
|
if (!connectorsDir)
|
|
40531
40967
|
return;
|
|
40532
40968
|
for (const connector of CONNECTORS) {
|
|
40533
40969
|
try {
|
|
40534
|
-
const pkgPath =
|
|
40535
|
-
if (
|
|
40536
|
-
const pkg = JSON.parse(
|
|
40970
|
+
const pkgPath = join10(connectorsDir, `connect-${connector.name}`, "package.json");
|
|
40971
|
+
if (existsSync8(pkgPath)) {
|
|
40972
|
+
const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
40537
40973
|
connector.version = pkg.version || "0.0.0";
|
|
40538
40974
|
continue;
|
|
40539
40975
|
}
|
|
@@ -40857,8 +41293,8 @@ function registerManagementTools(server, stripped) {
|
|
|
40857
41293
|
init_zod();
|
|
40858
41294
|
init_auth();
|
|
40859
41295
|
init_database();
|
|
40860
|
-
import { existsSync as
|
|
40861
|
-
import { join as
|
|
41296
|
+
import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
|
|
41297
|
+
import { join as join15 } from "path";
|
|
40862
41298
|
import { spawn } from "child_process";
|
|
40863
41299
|
function registerAuthTools(server, stripped) {
|
|
40864
41300
|
server.registerTool("connector_auth_status", {
|
|
@@ -40977,7 +41413,7 @@ function registerAuthTools(server, stripped) {
|
|
|
40977
41413
|
};
|
|
40978
41414
|
}
|
|
40979
41415
|
}
|
|
40980
|
-
const tokens =
|
|
41416
|
+
const tokens = loadTokens3(name);
|
|
40981
41417
|
if (tokens?.accessToken && tokens?.refreshToken) {
|
|
40982
41418
|
if (tokens.expiresAt && Date.now() < tokens.expiresAt - 60000) {
|
|
40983
41419
|
const mins = Math.floor((tokens.expiresAt - Date.now()) / 60000);
|
|
@@ -40995,7 +41431,7 @@ function registerAuthTools(server, stripped) {
|
|
|
40995
41431
|
if (noBrowser) {
|
|
40996
41432
|
const connectorsHome = getConnectorsHome();
|
|
40997
41433
|
const connectorDirName = name.startsWith("connect-") ? name : `connect-${name}`;
|
|
40998
|
-
const tokensPath =
|
|
41434
|
+
const tokensPath = join15(connectorsHome, connectorDirName, "profiles", "default", "tokens.json");
|
|
40999
41435
|
let serverRunning = false;
|
|
41000
41436
|
try {
|
|
41001
41437
|
await fetch(`http://localhost:${serverPort}/api/connectors`);
|
|
@@ -41014,7 +41450,7 @@ function registerAuthTools(server, stripped) {
|
|
|
41014
41450
|
const maxAttempts = 120;
|
|
41015
41451
|
while (attempts < maxAttempts) {
|
|
41016
41452
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
41017
|
-
if (
|
|
41453
|
+
if (existsSync13(tokensPath)) {
|
|
41018
41454
|
break;
|
|
41019
41455
|
}
|
|
41020
41456
|
attempts++;
|
|
@@ -41033,7 +41469,7 @@ function registerAuthTools(server, stripped) {
|
|
|
41033
41469
|
};
|
|
41034
41470
|
}
|
|
41035
41471
|
try {
|
|
41036
|
-
const tokenData = JSON.parse(
|
|
41472
|
+
const tokenData = JSON.parse(readFileSync9(tokensPath, "utf-8"));
|
|
41037
41473
|
return {
|
|
41038
41474
|
content: [{
|
|
41039
41475
|
type: "text",
|