@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/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 = /^[a-z0-9:._-]+$/;
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/googledrive.ts
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 requestJson(profile, path, params) {
11479
- const response = await request(profile, path, params);
11480
- const text = await response.text();
11481
- return text ? JSON.parse(text) : {};
11482
- }
11483
- async function requestBinary(profile, path, params) {
11484
- return (await request(profile, path, params)).arrayBuffer();
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 request(profile, path, params) {
11538
+ async function requestJson(profile, path, params, options = {}) {
11487
11539
  const token = await getValidAccessToken(profile);
11488
- const url = new URL(`${DRIVE_API_BASE}${path}`);
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.set(key, String(value));
11543
+ url.searchParams.append(key, String(value));
11492
11544
  }
11493
- const response = await fetch(url, { headers: { Authorization: `Bearer ${token}`, Accept: "application/json" } });
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 body = await response.text().catch(() => "");
11496
- throw new Error(`Google Drive request failed (${response.status}): ${extractGoogleError(body) || response.statusText}`);
11557
+ const error2 = data;
11558
+ throw new Error(`Gmail request failed (${response.status}): ${error2.error?.message ?? response.statusText}`);
11497
11559
  }
11498
- return response;
11560
+ return data;
11499
11561
  }
11500
11562
  async function getValidAccessToken(profile) {
11501
- if (process.env.GOOGLE_ACCESS_TOKEN)
11502
- return process.env.GOOGLE_ACCESS_TOKEN;
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(`Google Drive profile "${profile}" is not authenticated. Run: connectors auth googledrive`);
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("Google Drive OAuth credentials are not configured. Run: connectors auth googledrive");
11578
+ throw new Error("Gmail OAuth credentials are not configured. Run: connectors auth gmail");
11517
11579
  if (!currentTokens.refreshToken)
11518
- throw new Error(`Google Drive profile "${profile}" has no refresh token. Run: connectors auth googledrive`);
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(`Google Drive token refresh failed: ${data.error_description || data.error || response.statusText}`);
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.HASNA_GOOGLE_DRIVE_CONNECTOR_DIR ?? process.env.GOOGLE_DRIVE_CONNECTOR_DIR;
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-googledrive"), join2(baseDir, "googledrive")];
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", TOKEN_URL = "https://oauth2.googleapis.com/token", REFRESH_BUFFER_MS, DEFAULT_FILE_FIELDS, DEFAULT_EXPORT_FORMATS, EXPORT_EXTENSIONS, listFilesSchema, listDrivesSchema, fileIdSchema, downloadSchema, googleDriveConnector;
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
- REFRESH_BUFFER_MS = 5 * 60 * 1000;
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: listProfiles() })
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) => requestJson(context.profile, "/files", {
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) => requestJson(context.profile, `/files/${encodeURIComponent(input.fileId)}`, {
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 requestJson(context.profile, `/files/${encodeURIComponent(input.fileId)}`, { fields: DEFAULT_FILE_FIELDS, supportsAllDrives: true });
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) => requestJson(context.profile, "/drives", {
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.25",
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 existsSync3,
11864
- mkdirSync as mkdirSync2,
11865
- readdirSync as readdirSync2,
12297
+ existsSync as existsSync4,
12298
+ mkdirSync as mkdirSync3,
12299
+ readdirSync as readdirSync3,
11866
12300
  copyFileSync
11867
12301
  } from "fs";
11868
- import { homedir as homedir2 } from "os";
11869
- import { join as join3, relative } from "path";
11870
- import { existsSync as existsSync22, mkdirSync as mkdirSync22, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
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 homedir3 } from "os";
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 join4 } from "path";
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 = join3(HASNA_DIR, serviceName);
12752
- mkdirSync2(dir, { recursive: true });
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 join3(dir, `${serviceName}.db`);
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 = readFileSync2(CONFIG_PATH, "utf-8");
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
- writeFileSync2(CONFIG_PATH, JSON.stringify(config2, null, 2) + `
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(homedir3(), ".hasna");
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(homedir3(), ".hasna", service);
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 = join3(homedir2(), ".hasna");
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 = join4(homedir4(), ".hasna", "cloud", "config.json");
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 mkdirSync3, existsSync as existsSync4, readdirSync as readdirSync3, copyFileSync as copyFileSync2, statSync } from "fs";
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 (!existsSync4(sourceDir)) {
22335
+ if (!existsSync5(sourceDir)) {
21902
22336
  return;
21903
22337
  }
21904
- mkdirSync3(targetDir, { recursive: true });
21905
- for (const entry of readdirSync3(sourceDir)) {
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 (!existsSync4(targetPath)) {
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
- mkdirSync3(newDir, { recursive: true });
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
- mkdirSync3(dirname3(dbPath), { recursive: true });
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 existsSync5,
22077
- mkdirSync as mkdirSync4,
22078
- readFileSync as readFileSync3,
22079
- readdirSync as readdirSync4,
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 writeFileSync3
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 (!existsSync5(currentProfileFile)) {
22570
+ if (!existsSync6(currentProfileFile)) {
22137
22571
  return "default";
22138
22572
  }
22139
22573
  try {
22140
- return readFileSync3(currentProfileFile, "utf-8").trim() || "default";
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
- mkdirSync4(configDir, { recursive: true });
22148
- writeFileSync3(join7(configDir, "current_profile"), profile);
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(readFileSync3(path, "utf-8"));
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 = existsSync5(getFlatProfilePath(profile)) ? loadJsonFile(getFlatProfilePath(profile)) : {};
22175
- const directoryConfig = existsSync5(getDirectoryProfilePath(profile)) ? loadJsonFile(getDirectoryProfilePath(profile)) : {};
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
- mkdirSync4(profilesDir, { recursive: true });
22184
- writeFileSync3(getFlatProfilePath(profile), JSON.stringify(config2, null, 2) + `
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 existsSync5(getFlatProfilePath(profile)) || existsSync5(join7(getProfilesDir(), profile));
22625
+ return existsSync6(getFlatProfilePath(profile)) || existsSync6(join7(getProfilesDir(), profile));
22192
22626
  }
22193
- function listProfiles2() {
22627
+ function listProfiles3() {
22194
22628
  const profilesDir = getProfilesDir();
22195
22629
  const seen = new Set(["default"]);
22196
- if (!existsSync5(profilesDir)) {
22630
+ if (!existsSync6(profilesDir)) {
22197
22631
  return [...seen];
22198
22632
  }
22199
22633
  try {
22200
- for (const entry of readdirSync4(profilesDir)) {
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 (existsSync5(flatPath)) {
22657
+ if (existsSync6(flatPath)) {
22224
22658
  rmSync(flatPath);
22225
22659
  }
22226
- if (existsSync5(directoryPath)) {
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 replyToMessage(context, input) {
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 = listProfiles2();
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 replyToMessage(resolved, {
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 replyToMessage(context, input);
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 existsSync6 } from "fs";
23153
- import { dirname as dirname4, join as join8 } from "path";
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
- join8(__dirname3, "..", "..", "..", "connectors", "connect-stripe"),
23158
- join8(__dirname3, "..", "..", "connectors", "connect-stripe"),
23159
- join8(__dirname3, "..", "connectors", "connect-stripe"),
23160
- join8(process.cwd(), "connectors", "connect-stripe")
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 (existsSync6(candidate)) {
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(join8(CONNECTOR_DIR2, "src", "api", "index.ts")).href);
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(join8(CONNECTOR_DIR2, "src", "utils", "config.ts")).href);
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 existsSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5 } from "fs";
24059
- import { join as join10 } from "path";
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 join10(getConnectorsHome(), "llm.json");
24497
+ return join11(getConnectorsHome(), "llm.json");
24062
24498
  }
24063
24499
  function getLlmConfig() {
24064
24500
  const path = getLlmConfigPath();
24065
- if (!existsSync8(path))
24501
+ if (!existsSync9(path))
24066
24502
  return null;
24067
24503
  try {
24068
- return JSON.parse(readFileSync5(path, "utf-8"));
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
- mkdirSync5(dir, { recursive: true });
24076
- writeFileSync4(getLlmConfigPath(), JSON.stringify(config2, null, 2));
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 existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5, readdirSync as readdirSync5, statSync as statSync3, rmSync as rmSync2 } from "fs";
24196
- import { join as join11, dirname as dirname6 } from "path";
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 = join11(__dirname4, "..", "connectors");
24200
- if (existsSync9(fromBin))
24635
+ const fromBin = join12(__dirname4, "..", "connectors");
24636
+ if (existsSync10(fromBin))
24201
24637
  return fromBin;
24202
- const fromSrc = join11(__dirname4, "..", "..", "connectors");
24203
- if (existsSync9(fromSrc))
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 join11(targetDir, PROJECT_CONNECTORS_DIRNAME);
24647
+ return join12(targetDir, PROJECT_CONNECTORS_DIRNAME);
24212
24648
  }
24213
24649
  function getEnablementManifestPath(targetDir) {
24214
- return join11(getProjectConnectorsDir(targetDir), ENABLEMENT_MANIFEST_FILENAME);
24650
+ return join12(getProjectConnectorsDir(targetDir), ENABLEMENT_MANIFEST_FILENAME);
24215
24651
  }
24216
24652
  function getLegacyInstallPath(targetDir, name) {
24217
- return join11(getProjectConnectorsDir(targetDir), `connect-${normalizeConnectorName(name)}`);
24653
+ return join12(getProjectConnectorsDir(targetDir), `connect-${normalizeConnectorName(name)}`);
24218
24654
  }
24219
24655
  function loadEnablementManifest(targetDir) {
24220
24656
  const manifestPath = getEnablementManifestPath(targetDir);
24221
- if (!existsSync9(manifestPath)) {
24657
+ if (!existsSync10(manifestPath)) {
24222
24658
  return null;
24223
24659
  }
24224
24660
  try {
24225
- const raw = JSON.parse(readFileSync6(manifestPath, "utf-8"));
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 (!existsSync9(connectorsDir)) {
24677
+ if (!existsSync10(connectorsDir)) {
24242
24678
  return [];
24243
24679
  }
24244
- return readdirSync5(connectorsDir).filter((entry) => {
24245
- const fullPath = join11(connectorsDir, entry);
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 = join11(connectorsDir, ENABLEMENT_INDEX_FILENAME);
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
- writeFileSync5(indexPath, content);
24706
+ writeFileSync6(indexPath, content);
24271
24707
  }
24272
24708
  function writeEnablementManifest(targetDir, connectors18) {
24273
24709
  const connectorsDir = getProjectConnectorsDir(targetDir);
24274
- mkdirSync6(connectorsDir, { recursive: true });
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
- writeFileSync5(getEnablementManifestPath(targetDir), JSON.stringify(manifest, null, 2) + `
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 join11(CONNECTORS_DIR, connectorName);
24723
+ return join12(CONNECTORS_DIR, connectorName);
24288
24724
  }
24289
24725
  function connectorExists(name) {
24290
24726
  const normalizedName = normalizeConnectorName(name);
24291
- return hasInternalConnectorDefinition(normalizedName) || existsSync9(getConnectorPath(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 && existsSync9(legacyInstallPath)) {
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 = join11(connectorPath, "CLAUDE.md");
24360
- if (existsSync9(claudeMdPath)) {
24361
- return parseConnectorDocs(readFileSync6(claudeMdPath, "utf-8"));
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 (existsSync9(legacyInstallPath)) {
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 existsSync10, statSync as statSync4 } from "fs";
24488
- import { join as join12 } from "path";
24489
- import { mkdirSync as mkdirSync7 } from "fs";
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 = join12(getConnectorsHome(), `connect-${connector}`);
24492
- mkdirSync7(dir, { recursive: true });
24493
- return join12(dir, ".write.lock");
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 (existsSync10(path) && isStale(path)) {
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 existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync6, mkdirSync as mkdirSync8, readdirSync as readdirSync6, rmSync as rmSync3, statSync as statSync5 } from "fs";
24554
- import { join as join13 } from "path";
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 join13(getConnectorsHome(), connectorName);
25004
+ return join14(getConnectorsHome(), connectorName);
24569
25005
  }
24570
25006
  function getCurrentProfile2(name) {
24571
25007
  const configDir = getConnectorConfigDir(name);
24572
- const currentProfileFile = join13(configDir, "current_profile");
24573
- if (existsSync11(currentProfileFile)) {
25008
+ const currentProfileFile = join14(configDir, "current_profile");
25009
+ if (existsSync12(currentProfileFile)) {
24574
25010
  try {
24575
- return readFileSync7(currentProfileFile, "utf-8").trim() || "default";
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 = join13(configDir, "profiles", `${profile}.json`);
24588
- if (existsSync11(profileFile)) {
25023
+ const profileFile = join14(configDir, "profiles", `${profile}.json`);
25024
+ if (existsSync12(profileFile)) {
24589
25025
  try {
24590
- flatConfig = JSON.parse(readFileSync7(profileFile, "utf-8"));
25026
+ flatConfig = JSON.parse(readFileSync8(profileFile, "utf-8"));
24591
25027
  } catch {}
24592
25028
  }
24593
- const profileDirConfig = join13(configDir, "profiles", profile, "config.json");
24594
- if (existsSync11(profileDirConfig)) {
25029
+ const profileDirConfig = join14(configDir, "profiles", profile, "config.json");
25030
+ if (existsSync12(profileDirConfig)) {
24595
25031
  try {
24596
- dirConfig = JSON.parse(readFileSync7(profileDirConfig, "utf-8"));
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 loadTokens2(name) {
25040
+ function loadTokens3(name) {
24605
25041
  const configDir = getConnectorConfigDir(name);
24606
25042
  const profile = getCurrentProfile2(name);
24607
- const tokensFile = join13(configDir, "profiles", profile, "tokens.json");
24608
- if (existsSync11(tokensFile)) {
25043
+ const tokensFile = join14(configDir, "profiles", profile, "tokens.json");
25044
+ if (existsSync12(tokensFile)) {
24609
25045
  try {
24610
- return JSON.parse(readFileSync7(tokensFile, "utf-8"));
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" ? loadTokens2(name) : null;
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 = join13(configDir, "credentials.json");
24699
- mkdirSync8(configDir, { recursive: true });
25134
+ const credentialsFile = join14(configDir, "credentials.json");
25135
+ mkdirSync9(configDir, { recursive: true });
24700
25136
  let creds = {};
24701
- if (existsSync11(credentialsFile)) {
25137
+ if (existsSync12(credentialsFile)) {
24702
25138
  try {
24703
- creds = JSON.parse(readFileSync7(credentialsFile, "utf-8"));
25139
+ creds = JSON.parse(readFileSync8(credentialsFile, "utf-8"));
24704
25140
  } catch {}
24705
25141
  }
24706
25142
  creds[keyField] = key;
24707
- writeFileSync6(credentialsFile, JSON.stringify(creds, null, 2));
25143
+ writeFileSync7(credentialsFile, JSON.stringify(creds, null, 2));
24708
25144
  return;
24709
25145
  }
24710
- const profileFile = join13(configDir, "profiles", `${profile}.json`);
24711
- const profileDir = join13(configDir, "profiles", profile);
24712
- if (existsSync11(profileFile)) {
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(readFileSync7(profileFile, "utf-8"));
25151
+ config2 = JSON.parse(readFileSync8(profileFile, "utf-8"));
24716
25152
  } catch {}
24717
25153
  config2[keyField] = key;
24718
- writeFileSync6(profileFile, JSON.stringify(config2, null, 2));
25154
+ writeFileSync7(profileFile, JSON.stringify(config2, null, 2));
24719
25155
  return;
24720
25156
  }
24721
- if (existsSync11(profileDir)) {
24722
- const configFile = join13(profileDir, "config.json");
25157
+ if (existsSync12(profileDir)) {
25158
+ const configFile = join14(profileDir, "config.json");
24723
25159
  let config2 = {};
24724
- if (existsSync11(configFile)) {
25160
+ if (existsSync12(configFile)) {
24725
25161
  try {
24726
- config2 = JSON.parse(readFileSync7(configFile, "utf-8"));
25162
+ config2 = JSON.parse(readFileSync8(configFile, "utf-8"));
24727
25163
  } catch {}
24728
25164
  }
24729
25165
  config2[keyField] = key;
24730
- writeFileSync6(configFile, JSON.stringify(config2, null, 2));
25166
+ writeFileSync7(configFile, JSON.stringify(config2, null, 2));
24731
25167
  return;
24732
25168
  }
24733
- mkdirSync8(profileDir, { recursive: true });
24734
- writeFileSync6(join13(profileDir, "config.json"), JSON.stringify({ [keyField]: key }, null, 2));
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 = join13(configDir, "credentials.json");
24753
- if (existsSync11(credentialsFile)) {
25188
+ const credentialsFile = join14(configDir, "credentials.json");
25189
+ if (existsSync12(credentialsFile)) {
24754
25190
  try {
24755
- const creds = JSON.parse(readFileSync7(credentialsFile, "utf-8"));
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 = join13(configDir, "profiles", profile);
24769
- mkdirSync8(profileDir, { recursive: true });
24770
- const tokensFile = join13(profileDir, "tokens.json");
24771
- writeFileSync6(tokensFile, JSON.stringify(tokens, null, 2), { mode: 384 });
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 = loadTokens2(name);
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 existsSync13, readdirSync as readdirSync7 } from "fs";
24872
- import { join as join15, dirname as dirname7 } from "path";
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 = join15(__dirname5, "..", "connectors");
24877
- if (existsSync13(fromBin))
25312
+ const fromBin = join16(__dirname5, "..", "connectors");
25313
+ if (existsSync14(fromBin))
24878
25314
  return fromBin;
24879
- const fromSrc = join15(__dirname5, "..", "..", "connectors");
24880
- if (existsSync13(fromSrc))
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 = loadTokens2(connectorName);
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 = join15(CONNECTORS_DIR2, `connect-${safeName}`);
24947
- const cliPath = join15(connectorDir, "src", "cli", "index.ts");
24948
- if (existsSync13(cliPath))
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 = readdirSync7(CONNECTORS_DIR2);
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 existsSync7, readFileSync as readFileSync4 } from "fs";
34255
- import { join as join9, dirname as dirname5 } from "path";
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
- join9(thisDir, "..", "connectors"),
40527
- join9(thisDir, "..", "..", "connectors")
40962
+ join10(thisDir, "..", "connectors"),
40963
+ join10(thisDir, "..", "..", "connectors")
40528
40964
  ];
40529
- const connectorsDir = candidates.find((d) => existsSync7(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 = join9(connectorsDir, `connect-${connector.name}`, "package.json");
40535
- if (existsSync7(pkgPath)) {
40536
- const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
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 existsSync12, readFileSync as readFileSync8 } from "fs";
40861
- import { join as join14 } from "path";
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 = loadTokens2(name);
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 = join14(connectorsHome, connectorDirName, "profiles", "default", "tokens.json");
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 (existsSync12(tokensPath)) {
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(readFileSync8(tokensPath, "utf-8"));
41472
+ const tokenData = JSON.parse(readFileSync9(tokensPath, "utf-8"));
41037
41473
  return {
41038
41474
  content: [{
41039
41475
  type: "text",