@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 CHANGED
@@ -1909,7 +1909,7 @@ var package_default;
1909
1909
  var init_package = __esm(() => {
1910
1910
  package_default = {
1911
1911
  name: "@hasna/connectors",
1912
- version: "1.3.25",
1912
+ version: "1.3.26",
1913
1913
  description: "Open source connector library - Install API connectors with a single command",
1914
1914
  type: "module",
1915
1915
  bin: {
@@ -2052,7 +2052,7 @@ var CONNECTOR_NAME_RE, OPERATION_NAME_RE;
2052
2052
  var init_connector = __esm(() => {
2053
2053
  init_errors();
2054
2054
  CONNECTOR_NAME_RE = /^[a-z0-9-]+$/;
2055
- OPERATION_NAME_RE = /^[a-z0-9:._-]+$/;
2055
+ OPERATION_NAME_RE = /^[A-Za-z0-9:._-]+$/;
2056
2056
  });
2057
2057
 
2058
2058
  // src/core/registry.ts
@@ -6913,38 +6913,100 @@ Commands:
6913
6913
  });
6914
6914
  });
6915
6915
 
6916
- // src/core/connectors/googledrive.ts
6916
+ // src/core/connectors/gmail.ts
6917
6917
  import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
6918
6918
  import { homedir } from "os";
6919
6919
  import { basename, join as join2 } from "path";
6920
- async function requestJson(profile, path, params) {
6921
- const response = await request(profile, path, params);
6922
- const text = await response.text();
6923
- return text ? JSON.parse(text) : {};
6920
+ async function modifyMessage(profile, messageId, addLabelIds, removeLabelIds) {
6921
+ return requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}/modify`, {}, {
6922
+ method: "POST",
6923
+ body: {
6924
+ addLabelIds: addLabelIds ?? [],
6925
+ removeLabelIds: removeLabelIds ?? []
6926
+ }
6927
+ });
6924
6928
  }
6925
- async function requestBinary(profile, path, params) {
6926
- return (await request(profile, path, params)).arrayBuffer();
6929
+ async function replyToMessage(profile, messageId, input) {
6930
+ const original = await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: "full" });
6931
+ const headers = headersToObject(original.payload?.headers ?? []);
6932
+ const subject = normalizeReplySubject(headers.Subject ?? headers.subject ?? "");
6933
+ const to = headers.From ?? headers.from ?? "";
6934
+ const messageIdHeader = headers["Message-ID"] ?? headers["Message-Id"] ?? headers["message-id"] ?? "";
6935
+ const references = [headers.References ?? headers.references, messageIdHeader].filter(Boolean).join(" ");
6936
+ const raw = buildRawEmail({
6937
+ to,
6938
+ cc: normalizeStringArray(input.cc),
6939
+ bcc: normalizeStringArray(input.bcc),
6940
+ subject,
6941
+ body: input.body,
6942
+ isHtml: Boolean(input.html ?? input.isHtml),
6943
+ inReplyTo: messageIdHeader,
6944
+ references
6945
+ });
6946
+ return requestJson(profile, "/users/me/messages/send", {}, {
6947
+ method: "POST",
6948
+ body: {
6949
+ raw: Buffer.from(raw).toString("base64url"),
6950
+ threadId: original.threadId
6951
+ }
6952
+ });
6927
6953
  }
6928
- async function request(profile, path, params) {
6954
+ async function downloadAttachments(profile, input) {
6955
+ const messageId = getMessageId(input);
6956
+ const outputDir = input.dir ?? input.outputDir ?? join2(configDirs()[0], "attachments", messageId);
6957
+ mkdirSync(outputDir, { recursive: true });
6958
+ const attachments = input.attachmentId && input.filename ? [{
6959
+ attachmentId: input.attachmentId,
6960
+ filename: input.filename,
6961
+ mimeType: input.mimeType ?? "application/octet-stream",
6962
+ size: 0
6963
+ }] : collectAttachments((await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: "full" })).payload);
6964
+ const downloaded = [];
6965
+ for (const attachment of attachments) {
6966
+ const data = await requestJson(profile, `/users/me/messages/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachment.attachmentId)}`, {});
6967
+ const filename = safeFilename(attachment.filename);
6968
+ const path = join2(outputDir, filename);
6969
+ const buffer = Buffer.from(data.data, "base64url");
6970
+ writeFileSync(path, buffer);
6971
+ downloaded.push({
6972
+ filename,
6973
+ path,
6974
+ size: buffer.length,
6975
+ mimeType: attachment.mimeType
6976
+ });
6977
+ }
6978
+ return downloaded;
6979
+ }
6980
+ async function requestJson(profile, path, params, options = {}) {
6929
6981
  const token = await getValidAccessToken(profile);
6930
- const url = new URL(`${DRIVE_API_BASE}${path}`);
6982
+ const url = new URL(`${GMAIL_API_BASE}${path}`);
6931
6983
  for (const [key, value] of Object.entries(params)) {
6932
6984
  if (value !== undefined && value !== null && value !== "")
6933
- url.searchParams.set(key, String(value));
6985
+ url.searchParams.append(key, String(value));
6934
6986
  }
6935
- const response = await fetch(url, { headers: { Authorization: `Bearer ${token}`, Accept: "application/json" } });
6987
+ const response = await fetch(url, {
6988
+ method: options.method ?? "GET",
6989
+ headers: {
6990
+ Authorization: `Bearer ${token}`,
6991
+ Accept: "application/json",
6992
+ ...options.body ? { "Content-Type": "application/json" } : {}
6993
+ },
6994
+ body: options.body ? JSON.stringify(options.body) : undefined
6995
+ });
6996
+ const text = await response.text();
6997
+ const data = text ? JSON.parse(text) : {};
6936
6998
  if (!response.ok) {
6937
- const body = await response.text().catch(() => "");
6938
- throw new Error(`Google Drive request failed (${response.status}): ${extractGoogleError(body) || response.statusText}`);
6999
+ const error = data;
7000
+ throw new Error(`Gmail request failed (${response.status}): ${error.error?.message ?? response.statusText}`);
6939
7001
  }
6940
- return response;
7002
+ return data;
6941
7003
  }
6942
7004
  async function getValidAccessToken(profile) {
6943
- if (process.env.GOOGLE_ACCESS_TOKEN)
6944
- return process.env.GOOGLE_ACCESS_TOKEN;
7005
+ if (process.env.GMAIL_ACCESS_TOKEN)
7006
+ return process.env.GMAIL_ACCESS_TOKEN;
6945
7007
  const tokens = loadTokens(profile);
6946
7008
  if (!tokens?.accessToken && !tokens?.refreshToken) {
6947
- throw new Error(`Google Drive profile "${profile}" is not authenticated. Run: connectors auth googledrive`);
7009
+ throw new Error(`Gmail profile "${profile}" is not authenticated. Run: connectors auth gmail`);
6948
7010
  }
6949
7011
  if (tokens.accessToken && (!tokens.expiresAt || Date.now() < tokens.expiresAt - REFRESH_BUFFER_MS))
6950
7012
  return tokens.accessToken;
@@ -6955,9 +7017,9 @@ async function getValidAccessToken(profile) {
6955
7017
  async function refreshAccessToken(profile, currentTokens) {
6956
7018
  const credentials = loadCredentials(profile);
6957
7019
  if (!credentials.clientId || !credentials.clientSecret)
6958
- throw new Error("Google Drive OAuth credentials are not configured. Run: connectors auth googledrive");
7020
+ throw new Error("Gmail OAuth credentials are not configured. Run: connectors auth gmail");
6959
7021
  if (!currentTokens.refreshToken)
6960
- throw new Error(`Google Drive profile "${profile}" has no refresh token. Run: connectors auth googledrive`);
7022
+ throw new Error(`Gmail profile "${profile}" has no refresh token. Run: connectors auth gmail`);
6961
7023
  const response = await fetch(TOKEN_URL, {
6962
7024
  method: "POST",
6963
7025
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
@@ -6970,7 +7032,7 @@ async function refreshAccessToken(profile, currentTokens) {
6970
7032
  });
6971
7033
  const data = await response.json().catch(() => ({}));
6972
7034
  if (!response.ok || !data.access_token)
6973
- throw new Error(`Google Drive token refresh failed: ${data.error_description || data.error || response.statusText}`);
7035
+ throw new Error(`Gmail token refresh failed: ${data.error_description || data.error || response.statusText}`);
6974
7036
  const tokens = {
6975
7037
  accessToken: data.access_token,
6976
7038
  refreshToken: currentTokens.refreshToken,
@@ -6997,8 +7059,8 @@ function listProfiles() {
6997
7059
  return Array.from(profiles).sort((a, b) => a.localeCompare(b));
6998
7060
  }
6999
7061
  function loadCredentials(profile) {
7000
- const envClientId = process.env.GOOGLE_CLIENT_ID;
7001
- const envClientSecret = process.env.GOOGLE_CLIENT_SECRET;
7062
+ const envClientId = process.env.GMAIL_CLIENT_ID ?? process.env.GOOGLE_CLIENT_ID;
7063
+ const envClientSecret = process.env.GMAIL_CLIENT_SECRET ?? process.env.GOOGLE_CLIENT_SECRET;
7002
7064
  if (envClientId && envClientSecret)
7003
7065
  return { clientId: envClientId, clientSecret: envClientSecret };
7004
7066
  for (const baseDir of configDirs()) {
@@ -7029,11 +7091,11 @@ function saveTokens(profile, tokens) {
7029
7091
  writeFileSync(join2(profileDir, "tokens.json"), JSON.stringify(tokens, null, 2), { mode: 384 });
7030
7092
  }
7031
7093
  function configDirs() {
7032
- const explicit = process.env.HASNA_GOOGLE_DRIVE_CONNECTOR_DIR ?? process.env.GOOGLE_DRIVE_CONNECTOR_DIR;
7094
+ const explicit = process.env.HASNA_GMAIL_CONNECTOR_DIR ?? process.env.GMAIL_CONNECTOR_DIR;
7033
7095
  if (explicit)
7034
7096
  return [explicit];
7035
7097
  const baseDir = process.env.HASNA_CONNECTORS_DIR ?? join2(homedir(), ".hasna", "connectors");
7036
- return [join2(baseDir, "connect-googledrive"), join2(baseDir, "googledrive")];
7098
+ return [join2(baseDir, "connect-gmail"), join2(baseDir, "gmail")];
7037
7099
  }
7038
7100
  function readJson(path) {
7039
7101
  if (!existsSync2(path))
@@ -7044,6 +7106,378 @@ function readJson(path) {
7044
7106
  return null;
7045
7107
  }
7046
7108
  }
7109
+ function getMessageId(input) {
7110
+ const id = input.messageId ?? (input.args?.[0] != null ? String(input.args[0]) : undefined);
7111
+ if (!id)
7112
+ throw new Error("Gmail messageId is required");
7113
+ return id;
7114
+ }
7115
+ function headersToObject(headers) {
7116
+ const out = {};
7117
+ for (const header of headers)
7118
+ out[header.name] = header.value;
7119
+ return out;
7120
+ }
7121
+ function extractBody(message, preferHtml = false) {
7122
+ if (!message.payload)
7123
+ return "";
7124
+ const targetType = preferHtml ? "text/html" : "text/plain";
7125
+ const parts = [];
7126
+ collectTextParts(message.payload, parts);
7127
+ return parts.find((part) => part.mimeType === targetType)?.data ?? parts.find((part) => part.mimeType.startsWith("text/"))?.data ?? "";
7128
+ }
7129
+ function collectTextParts(part, results) {
7130
+ const mimeType = (part.mimeType ?? "").split(";")[0].trim().toLowerCase();
7131
+ if (part.body?.data && mimeType.startsWith("text/")) {
7132
+ results.push({ mimeType, data: Buffer.from(part.body.data, "base64url").toString("utf8") });
7133
+ }
7134
+ for (const child of part.parts ?? [])
7135
+ collectTextParts(child, results);
7136
+ }
7137
+ function collectAttachments(part, attachments = []) {
7138
+ if (!part)
7139
+ return attachments;
7140
+ if (part.body?.attachmentId && part.filename) {
7141
+ attachments.push({
7142
+ attachmentId: part.body.attachmentId,
7143
+ filename: part.filename,
7144
+ mimeType: part.mimeType ?? "application/octet-stream",
7145
+ size: part.body.size ?? 0,
7146
+ partId: part.partId
7147
+ });
7148
+ }
7149
+ for (const child of part.parts ?? [])
7150
+ collectAttachments(child, attachments);
7151
+ return attachments;
7152
+ }
7153
+ function normalizeStringArray(value) {
7154
+ if (!value)
7155
+ return [];
7156
+ return Array.isArray(value) ? value : value.split(",").map((item) => item.trim()).filter(Boolean);
7157
+ }
7158
+ function normalizeReplySubject(subject) {
7159
+ return subject.toLowerCase().startsWith("re:") ? subject : `Re: ${subject}`;
7160
+ }
7161
+ function buildRawEmail(input) {
7162
+ const headers = [
7163
+ `To: ${input.to}`,
7164
+ input.cc.length ? `Cc: ${input.cc.join(", ")}` : "",
7165
+ input.bcc.length ? `Bcc: ${input.bcc.join(", ")}` : "",
7166
+ `Subject: ${input.subject}`,
7167
+ input.inReplyTo ? `In-Reply-To: ${input.inReplyTo}` : "",
7168
+ input.references ? `References: ${input.references}` : "",
7169
+ "MIME-Version: 1.0",
7170
+ `Content-Type: ${input.isHtml ? "text/html" : "text/plain"}; charset=UTF-8`
7171
+ ].filter(Boolean);
7172
+ return `${headers.join(`\r
7173
+ `)}\r
7174
+ \r
7175
+ ${input.body}`;
7176
+ }
7177
+ function safeFilename(filename) {
7178
+ return basename(filename.replace(/[\u00A0\u2000-\u200B\u202F\u205F\u3000]/g, " ")).replace(/[\/\\]/g, "_");
7179
+ }
7180
+ 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;
7181
+ var init_gmail = __esm(() => {
7182
+ init_zod();
7183
+ init_connector();
7184
+ REFRESH_BUFFER_MS = 5 * 60 * 1000;
7185
+ listMessagesSchema = exports_external.object({
7186
+ max: exports_external.coerce.number().int().positive().max(500).optional(),
7187
+ maxResults: exports_external.coerce.number().int().positive().max(500).optional(),
7188
+ pageToken: exports_external.string().optional(),
7189
+ query: exports_external.string().optional(),
7190
+ q: exports_external.string().optional(),
7191
+ label: exports_external.string().optional(),
7192
+ labelIds: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional(),
7193
+ includeSpamTrash: exports_external.boolean().optional()
7194
+ });
7195
+ messageIdSchema = exports_external.object({
7196
+ args: exports_external.array(exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean()])).optional(),
7197
+ messageId: exports_external.string().optional()
7198
+ });
7199
+ readMessageSchema = messageIdSchema.extend({
7200
+ body: exports_external.boolean().optional(),
7201
+ html: exports_external.boolean().optional(),
7202
+ format: exports_external.enum(["full", "metadata", "minimal", "raw"]).optional()
7203
+ });
7204
+ attachmentListSchema = messageIdSchema;
7205
+ attachmentDownloadSchema = messageIdSchema.extend({
7206
+ attachmentId: exports_external.string().optional(),
7207
+ filename: exports_external.string().optional(),
7208
+ mimeType: exports_external.string().optional(),
7209
+ dir: exports_external.string().optional(),
7210
+ outputDir: exports_external.string().optional()
7211
+ });
7212
+ historyListSchema = exports_external.object({
7213
+ startHistoryId: exports_external.string(),
7214
+ historyTypes: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional(),
7215
+ labelId: exports_external.string().optional(),
7216
+ maxResults: exports_external.coerce.number().int().positive().max(500).optional(),
7217
+ pageToken: exports_external.string().optional()
7218
+ });
7219
+ replySchema = messageIdSchema.extend({
7220
+ body: exports_external.string(),
7221
+ html: exports_external.boolean().optional(),
7222
+ isHtml: exports_external.boolean().optional(),
7223
+ cc: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional(),
7224
+ bcc: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional()
7225
+ });
7226
+ gmailConnector = defineConnector({
7227
+ meta: {
7228
+ name: "gmail",
7229
+ displayName: "Gmail",
7230
+ description: "Profile-aware Gmail mailbox operations for sync, labels, attachments, history, and replies.",
7231
+ category: "communication",
7232
+ tags: ["google", "gmail", "email", "mailbox"]
7233
+ },
7234
+ auth: {
7235
+ type: "oauth2",
7236
+ supportsProfiles: true,
7237
+ fields: [
7238
+ { key: "clientId", env: "GMAIL_CLIENT_ID", label: "OAuth client ID" },
7239
+ { key: "clientSecret", env: "GMAIL_CLIENT_SECRET", label: "OAuth client secret", secret: true }
7240
+ ]
7241
+ },
7242
+ createContext: ({ profile }) => ({ profile: profile || "default" }),
7243
+ operations: {
7244
+ "profiles.list": {
7245
+ summary: "List configured Gmail profiles.",
7246
+ execute: () => ({ profiles: listProfiles() })
7247
+ },
7248
+ "profile.get": {
7249
+ summary: "Get the authenticated Gmail profile.",
7250
+ execute: async ({ context }) => requestJson(context.profile, "/users/me/profile", {})
7251
+ },
7252
+ "messages.list": {
7253
+ summary: "List Gmail messages.",
7254
+ inputSchema: listMessagesSchema,
7255
+ execute: async ({ context }, input) => {
7256
+ const labelIds = normalizeStringArray(input.labelIds ?? input.label);
7257
+ return requestJson(context.profile, "/users/me/messages", {
7258
+ maxResults: input.maxResults ?? input.max ?? 50,
7259
+ pageToken: input.pageToken,
7260
+ q: input.q ?? input.query,
7261
+ labelIds: labelIds.length > 0 ? labelIds.join(",") : undefined,
7262
+ includeSpamTrash: input.includeSpamTrash
7263
+ });
7264
+ }
7265
+ },
7266
+ "messages.read": {
7267
+ summary: "Read a Gmail message with optional extracted body.",
7268
+ inputSchema: readMessageSchema,
7269
+ execute: async ({ context }, input) => {
7270
+ const messageId = getMessageId(input);
7271
+ const message = await requestJson(context.profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: input.format ?? "full" });
7272
+ const headers = headersToObject(message.payload?.headers ?? []);
7273
+ return {
7274
+ ...message,
7275
+ from: headers.From ?? headers.from ?? "",
7276
+ to: headers.To ?? headers.to ?? "",
7277
+ cc: headers.Cc ?? headers.cc ?? "",
7278
+ subject: headers.Subject ?? headers.subject ?? "",
7279
+ date: headers.Date ?? headers.date ?? "",
7280
+ body: input.body ? extractBody(message, Boolean(input.html)) : undefined,
7281
+ size: message.sizeEstimate
7282
+ };
7283
+ }
7284
+ },
7285
+ "messages.getRaw": {
7286
+ summary: "Read raw base64url Gmail message content.",
7287
+ inputSchema: messageIdSchema,
7288
+ execute: async ({ context }, input) => {
7289
+ const messageId = getMessageId(input);
7290
+ return requestJson(context.profile, `/users/me/messages/${encodeURIComponent(messageId)}`, { format: "raw" });
7291
+ }
7292
+ },
7293
+ "messages.mark-read": {
7294
+ summary: "Mark a message as read.",
7295
+ inputSchema: messageIdSchema,
7296
+ execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), undefined, ["UNREAD"])
7297
+ },
7298
+ "messages.mark-unread": {
7299
+ summary: "Mark a message as unread.",
7300
+ inputSchema: messageIdSchema,
7301
+ execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), ["UNREAD"], undefined)
7302
+ },
7303
+ "messages.archive": {
7304
+ summary: "Archive a message by removing the INBOX label.",
7305
+ inputSchema: messageIdSchema,
7306
+ execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), undefined, ["INBOX"])
7307
+ },
7308
+ "messages.star": {
7309
+ summary: "Star a message.",
7310
+ inputSchema: messageIdSchema,
7311
+ execute: async ({ context }, input) => modifyMessage(context.profile, getMessageId(input), ["STARRED"], undefined)
7312
+ },
7313
+ "messages.reply": {
7314
+ summary: "Reply to a Gmail message in the same thread.",
7315
+ inputSchema: replySchema,
7316
+ execute: async ({ context }, input) => replyToMessage(context.profile, getMessageId(input), input)
7317
+ },
7318
+ "attachments.list": {
7319
+ summary: "List Gmail message attachments.",
7320
+ inputSchema: attachmentListSchema,
7321
+ execute: async ({ context }, input) => {
7322
+ const message = await requestJson(context.profile, `/users/me/messages/${encodeURIComponent(getMessageId(input))}`, { format: "full" });
7323
+ return collectAttachments(message.payload);
7324
+ }
7325
+ },
7326
+ "attachments.download": {
7327
+ summary: "Download one or all Gmail message attachments to disk.",
7328
+ inputSchema: attachmentDownloadSchema,
7329
+ execute: async ({ context }, input) => downloadAttachments(context.profile, input)
7330
+ },
7331
+ "labels.list": {
7332
+ summary: "List Gmail labels.",
7333
+ execute: async ({ context }) => requestJson(context.profile, "/users/me/labels", {})
7334
+ },
7335
+ "history.list": {
7336
+ summary: "List Gmail mailbox history from a history id.",
7337
+ inputSchema: historyListSchema,
7338
+ execute: async ({ context }, input) => requestJson(context.profile, "/users/me/history", {
7339
+ startHistoryId: input.startHistoryId,
7340
+ historyTypes: normalizeStringArray(input.historyTypes).join(",") || undefined,
7341
+ labelId: input.labelId,
7342
+ maxResults: input.maxResults,
7343
+ pageToken: input.pageToken
7344
+ })
7345
+ }
7346
+ }
7347
+ });
7348
+ });
7349
+
7350
+ // src/core/connectors/googledrive.ts
7351
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync as readdirSync2, writeFileSync as writeFileSync2 } from "fs";
7352
+ import { homedir as homedir2 } from "os";
7353
+ import { basename as basename2, join as join3 } from "path";
7354
+ async function requestJson2(profile, path, params) {
7355
+ const response = await request(profile, path, params);
7356
+ const text = await response.text();
7357
+ return text ? JSON.parse(text) : {};
7358
+ }
7359
+ async function requestBinary(profile, path, params) {
7360
+ return (await request(profile, path, params)).arrayBuffer();
7361
+ }
7362
+ async function request(profile, path, params) {
7363
+ const token = await getValidAccessToken2(profile);
7364
+ const url = new URL(`${DRIVE_API_BASE}${path}`);
7365
+ for (const [key, value] of Object.entries(params)) {
7366
+ if (value !== undefined && value !== null && value !== "")
7367
+ url.searchParams.set(key, String(value));
7368
+ }
7369
+ const response = await fetch(url, { headers: { Authorization: `Bearer ${token}`, Accept: "application/json" } });
7370
+ if (!response.ok) {
7371
+ const body = await response.text().catch(() => "");
7372
+ throw new Error(`Google Drive request failed (${response.status}): ${extractGoogleError(body) || response.statusText}`);
7373
+ }
7374
+ return response;
7375
+ }
7376
+ async function getValidAccessToken2(profile) {
7377
+ if (process.env.GOOGLE_ACCESS_TOKEN)
7378
+ return process.env.GOOGLE_ACCESS_TOKEN;
7379
+ const tokens = loadTokens2(profile);
7380
+ if (!tokens?.accessToken && !tokens?.refreshToken) {
7381
+ throw new Error(`Google Drive profile "${profile}" is not authenticated. Run: connectors auth googledrive`);
7382
+ }
7383
+ if (tokens.accessToken && (!tokens.expiresAt || Date.now() < tokens.expiresAt - REFRESH_BUFFER_MS2))
7384
+ return tokens.accessToken;
7385
+ if (!tokens.refreshToken)
7386
+ return tokens.accessToken ?? "";
7387
+ return (await refreshAccessToken2(profile, tokens)).accessToken ?? "";
7388
+ }
7389
+ async function refreshAccessToken2(profile, currentTokens) {
7390
+ const credentials = loadCredentials2(profile);
7391
+ if (!credentials.clientId || !credentials.clientSecret)
7392
+ throw new Error("Google Drive OAuth credentials are not configured. Run: connectors auth googledrive");
7393
+ if (!currentTokens.refreshToken)
7394
+ throw new Error(`Google Drive profile "${profile}" has no refresh token. Run: connectors auth googledrive`);
7395
+ const response = await fetch(TOKEN_URL2, {
7396
+ method: "POST",
7397
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
7398
+ body: new URLSearchParams({
7399
+ client_id: credentials.clientId,
7400
+ client_secret: credentials.clientSecret,
7401
+ refresh_token: currentTokens.refreshToken,
7402
+ grant_type: "refresh_token"
7403
+ })
7404
+ });
7405
+ const data = await response.json().catch(() => ({}));
7406
+ if (!response.ok || !data.access_token)
7407
+ throw new Error(`Google Drive token refresh failed: ${data.error_description || data.error || response.statusText}`);
7408
+ const tokens = {
7409
+ accessToken: data.access_token,
7410
+ refreshToken: currentTokens.refreshToken,
7411
+ expiresAt: Date.now() + (data.expires_in ?? 3600) * 1000,
7412
+ tokenType: data.token_type ?? currentTokens.tokenType,
7413
+ scope: data.scope ?? currentTokens.scope
7414
+ };
7415
+ saveTokens2(profile, tokens);
7416
+ return tokens;
7417
+ }
7418
+ function listProfiles2() {
7419
+ const profiles = new Set;
7420
+ for (const baseDir of configDirs2()) {
7421
+ const profilesDir = join3(baseDir, "profiles");
7422
+ if (!existsSync3(profilesDir))
7423
+ continue;
7424
+ for (const entry of readdirSync2(profilesDir, { withFileTypes: true })) {
7425
+ if (entry.isDirectory())
7426
+ profiles.add(entry.name);
7427
+ if (entry.isFile() && entry.name.endsWith(".json"))
7428
+ profiles.add(basename2(entry.name, ".json"));
7429
+ }
7430
+ }
7431
+ return Array.from(profiles).sort((a, b) => a.localeCompare(b));
7432
+ }
7433
+ function loadCredentials2(profile) {
7434
+ const envClientId = process.env.GOOGLE_CLIENT_ID;
7435
+ const envClientSecret = process.env.GOOGLE_CLIENT_SECRET;
7436
+ if (envClientId && envClientSecret)
7437
+ return { clientId: envClientId, clientSecret: envClientSecret };
7438
+ for (const baseDir of configDirs2()) {
7439
+ const credentials = {
7440
+ ...readJson2(join3(baseDir, "credentials.json")),
7441
+ ...readJson2(join3(baseDir, "profiles", profile, "config.json"))
7442
+ };
7443
+ if (credentials.clientId || credentials.clientSecret)
7444
+ return credentials;
7445
+ }
7446
+ return {};
7447
+ }
7448
+ function loadTokens2(profile) {
7449
+ for (const baseDir of configDirs2()) {
7450
+ const fromProfile = readJson2(join3(baseDir, "profiles", profile, "tokens.json"));
7451
+ if (fromProfile)
7452
+ return fromProfile;
7453
+ const flat = readJson2(join3(baseDir, "profiles", `${profile}.json`));
7454
+ if (flat)
7455
+ return flat.tokens ?? (flat.accessToken || flat.refreshToken ? flat : null);
7456
+ }
7457
+ return null;
7458
+ }
7459
+ function saveTokens2(profile, tokens) {
7460
+ const baseDir = configDirs2().find((dir) => existsSync3(dir)) ?? configDirs2()[0];
7461
+ const profileDir = join3(baseDir, "profiles", profile);
7462
+ mkdirSync2(profileDir, { recursive: true });
7463
+ writeFileSync2(join3(profileDir, "tokens.json"), JSON.stringify(tokens, null, 2), { mode: 384 });
7464
+ }
7465
+ function configDirs2() {
7466
+ const explicit = process.env.HASNA_GOOGLE_DRIVE_CONNECTOR_DIR ?? process.env.GOOGLE_DRIVE_CONNECTOR_DIR;
7467
+ if (explicit)
7468
+ return [explicit];
7469
+ const baseDir = process.env.HASNA_CONNECTORS_DIR ?? join3(homedir2(), ".hasna", "connectors");
7470
+ return [join3(baseDir, "connect-googledrive"), join3(baseDir, "googledrive")];
7471
+ }
7472
+ function readJson2(path) {
7473
+ if (!existsSync3(path))
7474
+ return null;
7475
+ try {
7476
+ return JSON.parse(readFileSync2(path, "utf8"));
7477
+ } catch {
7478
+ return null;
7479
+ }
7480
+ }
7047
7481
  function defaultExportMimeType(googleMimeType) {
7048
7482
  if (googleMimeType.endsWith(".document"))
7049
7483
  return DEFAULT_EXPORT_FORMATS.document;
@@ -7068,11 +7502,11 @@ function extractGoogleError(body) {
7068
7502
  return body;
7069
7503
  }
7070
7504
  }
7071
- 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;
7505
+ 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;
7072
7506
  var init_googledrive = __esm(() => {
7073
7507
  init_zod();
7074
7508
  init_connector();
7075
- REFRESH_BUFFER_MS = 5 * 60 * 1000;
7509
+ REFRESH_BUFFER_MS2 = 5 * 60 * 1000;
7076
7510
  DEFAULT_FILE_FIELDS = [
7077
7511
  "id",
7078
7512
  "name",
@@ -7153,12 +7587,12 @@ var init_googledrive = __esm(() => {
7153
7587
  operations: {
7154
7588
  "profiles.list": {
7155
7589
  summary: "List configured Google Drive profiles.",
7156
- execute: () => ({ profiles: listProfiles() })
7590
+ execute: () => ({ profiles: listProfiles2() })
7157
7591
  },
7158
7592
  "files.list": {
7159
7593
  summary: "List Google Drive files.",
7160
7594
  inputSchema: listFilesSchema,
7161
- execute: async ({ context }, input) => requestJson(context.profile, "/files", {
7595
+ execute: async ({ context }, input) => requestJson2(context.profile, "/files", {
7162
7596
  pageSize: input.pageSize ?? 1000,
7163
7597
  pageToken: input.pageToken,
7164
7598
  q: input.q,
@@ -7173,7 +7607,7 @@ var init_googledrive = __esm(() => {
7173
7607
  "files.get": {
7174
7608
  summary: "Get Google Drive file metadata.",
7175
7609
  inputSchema: fileIdSchema,
7176
- execute: async ({ context }, input) => requestJson(context.profile, `/files/${encodeURIComponent(input.fileId)}`, {
7610
+ execute: async ({ context }, input) => requestJson2(context.profile, `/files/${encodeURIComponent(input.fileId)}`, {
7177
7611
  fields: input.fields ?? DEFAULT_FILE_FIELDS,
7178
7612
  supportsAllDrives: true
7179
7613
  })
@@ -7182,7 +7616,7 @@ var init_googledrive = __esm(() => {
7182
7616
  summary: "Download or export a Google Drive file as base64 content.",
7183
7617
  inputSchema: downloadSchema,
7184
7618
  execute: async ({ context }, input) => {
7185
- const file = input.file ?? await requestJson(context.profile, `/files/${encodeURIComponent(input.fileId)}`, { fields: DEFAULT_FILE_FIELDS, supportsAllDrives: true });
7619
+ const file = input.file ?? await requestJson2(context.profile, `/files/${encodeURIComponent(input.fileId)}`, { fields: DEFAULT_FILE_FIELDS, supportsAllDrives: true });
7186
7620
  const exportMimeType = file.mimeType.startsWith("application/vnd.google-apps.") ? input.exportMimeType ?? defaultExportMimeType(file.mimeType) : undefined;
7187
7621
  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 });
7188
7622
  const mimeType = exportMimeType ?? file.mimeType ?? "application/octet-stream";
@@ -7196,7 +7630,7 @@ var init_googledrive = __esm(() => {
7196
7630
  "drives.list": {
7197
7631
  summary: "List Google shared drives.",
7198
7632
  inputSchema: listDrivesSchema,
7199
- execute: async ({ context }, input) => requestJson(context.profile, "/drives", {
7633
+ execute: async ({ context }, input) => requestJson2(context.profile, "/drives", {
7200
7634
  pageSize: input.pageSize ?? 100,
7201
7635
  pageToken: input.pageToken,
7202
7636
  q: input.q
@@ -7279,27 +7713,27 @@ __export(exports_dist, {
7279
7713
  import { createRequire } from "module";
7280
7714
  import { Database } from "bun:sqlite";
7281
7715
  import {
7282
- existsSync as existsSync3,
7283
- mkdirSync as mkdirSync2,
7284
- readdirSync as readdirSync2,
7716
+ existsSync as existsSync4,
7717
+ mkdirSync as mkdirSync3,
7718
+ readdirSync as readdirSync3,
7285
7719
  copyFileSync
7286
7720
  } from "fs";
7287
- import { homedir as homedir2 } from "os";
7288
- import { join as join3, relative } from "path";
7289
- import { existsSync as existsSync22, mkdirSync as mkdirSync22, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
7721
+ import { homedir as homedir3 } from "os";
7722
+ import { join as join4, relative } from "path";
7723
+ import { existsSync as existsSync22, mkdirSync as mkdirSync22, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
7290
7724
  import { homedir as homedir22 } from "os";
7291
7725
  import { join as join22 } from "path";
7292
7726
  import { readdirSync as readdirSync22, existsSync as existsSync32 } from "fs";
7293
7727
  import { join as join32 } from "path";
7294
- import { homedir as homedir3 } from "os";
7728
+ import { homedir as homedir32 } from "os";
7295
7729
  import { hostname } from "os";
7296
- import { existsSync as existsSync4, readFileSync as readFileSync22 } from "fs";
7730
+ import { existsSync as existsSync42, readFileSync as readFileSync22 } from "fs";
7297
7731
  import { homedir as homedir4 } from "os";
7298
- import { join as join4 } from "path";
7299
- import { existsSync as existsSync5, readdirSync as readdirSync3 } from "fs";
7732
+ import { join as join42 } from "path";
7733
+ import { existsSync as existsSync5, readdirSync as readdirSync32 } from "fs";
7300
7734
  import { join as join5 } from "path";
7301
7735
  import { join as join6, dirname as dirname2 } from "path";
7302
- import { existsSync as existsSync6, writeFileSync as writeFileSync22, unlinkSync, mkdirSync as mkdirSync3 } from "fs";
7736
+ import { existsSync as existsSync6, writeFileSync as writeFileSync22, unlinkSync, mkdirSync as mkdirSync32 } from "fs";
7303
7737
  import { homedir as homedir5, platform } from "os";
7304
7738
  function __accessProp2(key) {
7305
7739
  return this[key];
@@ -8182,33 +8616,33 @@ function custom2(check, _params = {}, fatal) {
8182
8616
  return ZodAny2.create();
8183
8617
  }
8184
8618
  function getDataDir(serviceName) {
8185
- const dir = join3(HASNA_DIR, serviceName);
8186
- mkdirSync2(dir, { recursive: true });
8619
+ const dir = join4(HASNA_DIR, serviceName);
8620
+ mkdirSync3(dir, { recursive: true });
8187
8621
  return dir;
8188
8622
  }
8189
8623
  function getDbPath(serviceName) {
8190
8624
  const dir = getDataDir(serviceName);
8191
- return join3(dir, `${serviceName}.db`);
8625
+ return join4(dir, `${serviceName}.db`);
8192
8626
  }
8193
8627
  function migrateDotfile(serviceName) {
8194
- const legacyDir = join3(homedir2(), `.${serviceName}`);
8195
- const newDir = join3(HASNA_DIR, serviceName);
8196
- if (!existsSync3(legacyDir))
8628
+ const legacyDir = join4(homedir3(), `.${serviceName}`);
8629
+ const newDir = join4(HASNA_DIR, serviceName);
8630
+ if (!existsSync4(legacyDir))
8197
8631
  return [];
8198
- if (existsSync3(newDir))
8632
+ if (existsSync4(newDir))
8199
8633
  return [];
8200
- mkdirSync2(newDir, { recursive: true });
8634
+ mkdirSync3(newDir, { recursive: true });
8201
8635
  const migrated = [];
8202
8636
  copyDirRecursive(legacyDir, newDir, legacyDir, migrated);
8203
8637
  return migrated;
8204
8638
  }
8205
8639
  function copyDirRecursive(src, dest, root, migrated) {
8206
- const entries = readdirSync2(src, { withFileTypes: true });
8640
+ const entries = readdirSync3(src, { withFileTypes: true });
8207
8641
  for (const entry of entries) {
8208
- const srcPath = join3(src, entry.name);
8209
- const destPath = join3(dest, entry.name);
8642
+ const srcPath = join4(src, entry.name);
8643
+ const destPath = join4(dest, entry.name);
8210
8644
  if (entry.isDirectory()) {
8211
- mkdirSync2(destPath, { recursive: true });
8645
+ mkdirSync3(destPath, { recursive: true });
8212
8646
  copyDirRecursive(srcPath, destPath, root, migrated);
8213
8647
  } else {
8214
8648
  copyFileSync(srcPath, destPath);
@@ -8217,10 +8651,10 @@ function copyDirRecursive(src, dest, root, migrated) {
8217
8651
  }
8218
8652
  }
8219
8653
  function hasLegacyDotfile(serviceName) {
8220
- return existsSync3(join3(homedir2(), `.${serviceName}`));
8654
+ return existsSync4(join4(homedir3(), `.${serviceName}`));
8221
8655
  }
8222
8656
  function getHasnaDir() {
8223
- mkdirSync2(HASNA_DIR, { recursive: true });
8657
+ mkdirSync3(HASNA_DIR, { recursive: true });
8224
8658
  return HASNA_DIR;
8225
8659
  }
8226
8660
  function getConfigDir() {
@@ -8234,7 +8668,7 @@ function getCloudConfig() {
8234
8668
  return CloudConfigSchema.parse({});
8235
8669
  }
8236
8670
  try {
8237
- const raw = readFileSync2(CONFIG_PATH, "utf-8");
8671
+ const raw = readFileSync3(CONFIG_PATH, "utf-8");
8238
8672
  return CloudConfigSchema.parse(JSON.parse(raw));
8239
8673
  } catch {
8240
8674
  return CloudConfigSchema.parse({});
@@ -8242,7 +8676,7 @@ function getCloudConfig() {
8242
8676
  }
8243
8677
  function saveCloudConfig(config) {
8244
8678
  mkdirSync22(CONFIG_DIR, { recursive: true });
8245
- writeFileSync2(CONFIG_PATH, JSON.stringify(config, null, 2) + `
8679
+ writeFileSync3(CONFIG_PATH, JSON.stringify(config, null, 2) + `
8246
8680
  `, "utf-8");
8247
8681
  }
8248
8682
  function getConnectionString(dbName) {
@@ -8272,7 +8706,7 @@ function isSyncExcludedTable(table) {
8272
8706
  return SYNC_EXCLUDED_TABLE_PATTERNS.some((p) => p.test(table));
8273
8707
  }
8274
8708
  function discoverServices() {
8275
- const dataDir = join32(homedir3(), ".hasna");
8709
+ const dataDir = join32(homedir32(), ".hasna");
8276
8710
  if (!existsSync32(dataDir))
8277
8711
  return [];
8278
8712
  try {
@@ -8294,7 +8728,7 @@ function discoverSyncableServices() {
8294
8728
  return local.filter((s) => pgSet.has(s));
8295
8729
  }
8296
8730
  function getServiceDbPath(service) {
8297
- const dataDir = join32(homedir3(), ".hasna", service);
8731
+ const dataDir = join32(homedir32(), ".hasna", service);
8298
8732
  if (!existsSync32(dataDir))
8299
8733
  return null;
8300
8734
  const candidates = [
@@ -9230,7 +9664,7 @@ function resetAllSyncMeta(db) {
9230
9664
  }
9231
9665
  function getAutoSyncConfig() {
9232
9666
  try {
9233
- if (!existsSync4(AUTO_SYNC_CONFIG_PATH)) {
9667
+ if (!existsSync42(AUTO_SYNC_CONFIG_PATH)) {
9234
9668
  return { ...DEFAULT_AUTO_SYNC_CONFIG };
9235
9669
  }
9236
9670
  const raw = JSON.parse(readFileSync22(AUTO_SYNC_CONFIG_PATH, "utf-8"));
@@ -9348,7 +9782,7 @@ function discoverSyncableServices2() {
9348
9782
  const hasnaDir = getHasnaDir();
9349
9783
  const services = [];
9350
9784
  try {
9351
- const entries = readdirSync3(hasnaDir, { withFileTypes: true });
9785
+ const entries = readdirSync32(hasnaDir, { withFileTypes: true });
9352
9786
  for (const entry of entries) {
9353
9787
  if (!entry.isDirectory())
9354
9788
  continue;
@@ -9518,7 +9952,7 @@ function createLaunchdPlist(intervalMinutes) {
9518
9952
  async function registerLaunchd(intervalMinutes) {
9519
9953
  const plistPath = getLaunchdPlistPath();
9520
9954
  const plistDir = dirname2(plistPath);
9521
- mkdirSync3(plistDir, { recursive: true });
9955
+ mkdirSync32(plistDir, { recursive: true });
9522
9956
  try {
9523
9957
  await Bun.spawn(["launchctl", "unload", plistPath]).exited;
9524
9958
  } catch {}
@@ -9569,7 +10003,7 @@ WantedBy=timers.target
9569
10003
  }
9570
10004
  async function registerSystemd(intervalMinutes) {
9571
10005
  const dir = getSystemdDir();
9572
- mkdirSync3(dir, { recursive: true });
10006
+ mkdirSync32(dir, { recursive: true });
9573
10007
  writeFileSync22(join6(dir, `${SERVICE_NAME}.service`), createSystemdService());
9574
10008
  writeFileSync22(join6(dir, `${SERVICE_NAME}.timer`), createSystemdTimer(intervalMinutes));
9575
10009
  await Bun.spawn(["systemctl", "--user", "daemon-reload"]).exited;
@@ -9594,7 +10028,7 @@ async function registerSyncSchedule(intervalMinutes) {
9594
10028
  if (intervalMinutes <= 0) {
9595
10029
  throw new Error("Interval must be a positive number of minutes.");
9596
10030
  }
9597
- mkdirSync3(CONFIG_DIR2, { recursive: true });
10031
+ mkdirSync32(CONFIG_DIR2, { recursive: true });
9598
10032
  if (platform() === "darwin") {
9599
10033
  await registerLaunchd(intervalMinutes);
9600
10034
  } else {
@@ -18168,7 +18602,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
18168
18602
  init_external2();
18169
18603
  });
18170
18604
  init_dotfile = __esm2(() => {
18171
- HASNA_DIR = join3(homedir2(), ".hasna");
18605
+ HASNA_DIR = join4(homedir3(), ".hasna");
18172
18606
  });
18173
18607
  exports_config = {};
18174
18608
  __export2(exports_config, {
@@ -18264,7 +18698,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
18264
18698
  init_adapter();
18265
18699
  init_config();
18266
18700
  init_discover();
18267
- AUTO_SYNC_CONFIG_PATH = join4(homedir4(), ".hasna", "cloud", "config.json");
18701
+ AUTO_SYNC_CONFIG_PATH = join42(homedir4(), ".hasna", "cloud", "config.json");
18268
18702
  DEFAULT_AUTO_SYNC_CONFIG = {
18269
18703
  auto_sync_on_start: true,
18270
18704
  auto_sync_on_stop: true
@@ -18476,12 +18910,12 @@ var init_database = __esm(() => {
18476
18910
  // src/core/connectors/imessage.ts
18477
18911
  import {
18478
18912
  existsSync as existsSync9,
18479
- mkdirSync as mkdirSync6,
18480
- readFileSync as readFileSync3,
18481
- readdirSync as readdirSync6,
18913
+ mkdirSync as mkdirSync5,
18914
+ readFileSync as readFileSync4,
18915
+ readdirSync as readdirSync5,
18482
18916
  rmSync,
18483
18917
  statSync as statSync2,
18484
- writeFileSync as writeFileSync3
18918
+ writeFileSync as writeFileSync4
18485
18919
  } from "fs";
18486
18920
  import { join as join9 } from "path";
18487
18921
  function buildRootHelp(specs) {
@@ -18539,15 +18973,15 @@ function getCurrentProfile() {
18539
18973
  return "default";
18540
18974
  }
18541
18975
  try {
18542
- return readFileSync3(currentProfileFile, "utf-8").trim() || "default";
18976
+ return readFileSync4(currentProfileFile, "utf-8").trim() || "default";
18543
18977
  } catch {
18544
18978
  return "default";
18545
18979
  }
18546
18980
  }
18547
18981
  function setCurrentProfile(profile) {
18548
18982
  const configDir = getConfigDir2();
18549
- mkdirSync6(configDir, { recursive: true });
18550
- writeFileSync3(join9(configDir, "current_profile"), profile);
18983
+ mkdirSync5(configDir, { recursive: true });
18984
+ writeFileSync4(join9(configDir, "current_profile"), profile);
18551
18985
  }
18552
18986
  function getFlatProfilePath(profile) {
18553
18987
  return join9(getProfilesDir(), `${profile}.json`);
@@ -18557,7 +18991,7 @@ function getDirectoryProfilePath(profile) {
18557
18991
  }
18558
18992
  function loadJsonFile(path) {
18559
18993
  try {
18560
- return JSON.parse(readFileSync3(path, "utf-8"));
18994
+ return JSON.parse(readFileSync4(path, "utf-8"));
18561
18995
  } catch {
18562
18996
  return {};
18563
18997
  }
@@ -18582,8 +19016,8 @@ function loadProfile(profile = getCurrentProfile()) {
18582
19016
  }
18583
19017
  function writeProfile(profile, config) {
18584
19018
  const profilesDir = getProfilesDir();
18585
- mkdirSync6(profilesDir, { recursive: true });
18586
- writeFileSync3(getFlatProfilePath(profile), JSON.stringify(config, null, 2) + `
19019
+ mkdirSync5(profilesDir, { recursive: true });
19020
+ writeFileSync4(getFlatProfilePath(profile), JSON.stringify(config, null, 2) + `
18587
19021
  `);
18588
19022
  }
18589
19023
  function profileExists(profile) {
@@ -18592,14 +19026,14 @@ function profileExists(profile) {
18592
19026
  }
18593
19027
  return existsSync9(getFlatProfilePath(profile)) || existsSync9(join9(getProfilesDir(), profile));
18594
19028
  }
18595
- function listProfiles2() {
19029
+ function listProfiles3() {
18596
19030
  const profilesDir = getProfilesDir();
18597
19031
  const seen = new Set(["default"]);
18598
19032
  if (!existsSync9(profilesDir)) {
18599
19033
  return [...seen];
18600
19034
  }
18601
19035
  try {
18602
- for (const entry of readdirSync6(profilesDir)) {
19036
+ for (const entry of readdirSync5(profilesDir)) {
18603
19037
  const fullPath = join9(profilesDir, entry);
18604
19038
  const stat = statSync2(fullPath);
18605
19039
  if (stat.isDirectory()) {
@@ -18921,7 +19355,7 @@ async function sendMessage(context, input) {
18921
19355
  direction: "outbound"
18922
19356
  });
18923
19357
  }
18924
- async function replyToMessage(context, input) {
19358
+ async function replyToMessage2(context, input) {
18925
19359
  const payload = await bridgeRequest(context, "/messages/reply", {
18926
19360
  method: "POST",
18927
19361
  body: {
@@ -19035,7 +19469,7 @@ async function runProfileCommand2(args, context) {
19035
19469
  switch (subcommand) {
19036
19470
  case "list": {
19037
19471
  const current = getCurrentProfile();
19038
- const profiles = listProfiles2();
19472
+ const profiles = listProfiles3();
19039
19473
  return successOutput({ current, profiles }, context.format, () => profiles.map((profile) => `${profile}${profile === current ? " (active)" : ""}`).join(`
19040
19474
  `));
19041
19475
  }
@@ -19209,7 +19643,7 @@ async function runMessageCommand(args, context) {
19209
19643
  if (!conversationId || !text) {
19210
19644
  return failure2("Usage: connect-imessage message reply --conversation <id> --text <text>");
19211
19645
  }
19212
- return successOutput(await replyToMessage(resolved, {
19646
+ return successOutput(await replyToMessage2(resolved, {
19213
19647
  conversationId,
19214
19648
  text,
19215
19649
  replyToMessageId: asString2(options.replyTo),
@@ -19487,7 +19921,7 @@ var init_imessage = __esm(() => {
19487
19921
  summary: "Reply to an existing conversation through the bridge",
19488
19922
  inputSchema: messageReplyInputSchema,
19489
19923
  async execute({ context }, input) {
19490
- return replyToMessage(context, input);
19924
+ return replyToMessage2(context, input);
19491
19925
  }
19492
19926
  }
19493
19927
  },
@@ -20431,10 +20865,12 @@ var INTERNAL_CONNECTOR_DEFINITIONS, INTERNAL_CONNECTOR_REGISTRY;
20431
20865
  var init_builtins = __esm(() => {
20432
20866
  init_registry();
20433
20867
  init_github();
20868
+ init_gmail();
20434
20869
  init_googledrive();
20435
20870
  init_imessage();
20436
20871
  init_stripe();
20437
20872
  INTERNAL_CONNECTOR_DEFINITIONS = [
20873
+ gmailConnector,
20438
20874
  githubConnector,
20439
20875
  googleDriveConnector,
20440
20876
  imessageConnector,
@@ -26576,7 +27012,7 @@ __export(exports_registry, {
26576
27012
  CONNECTORS: () => CONNECTORS,
26577
27013
  CATEGORIES: () => CATEGORIES
26578
27014
  });
26579
- import { existsSync as existsSync11, readFileSync as readFileSync4 } from "fs";
27015
+ import { existsSync as existsSync11, readFileSync as readFileSync5 } from "fs";
26580
27016
  import { join as join11, dirname as dirname5 } from "path";
26581
27017
  import { fileURLToPath as fileURLToPath3 } from "url";
26582
27018
  function getConnectorsByCategory(category) {
@@ -26748,7 +27184,7 @@ function loadConnectorVersions() {
26748
27184
  try {
26749
27185
  const pkgPath = join11(connectorsDir, `connect-${connector.name}`, "package.json");
26750
27186
  if (existsSync11(pkgPath)) {
26751
- const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
27187
+ const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
26752
27188
  connector.version = pkg.version || "0.0.0";
26753
27189
  continue;
26754
27190
  }
@@ -28471,7 +28907,7 @@ __export(exports_installer, {
28471
28907
  getConnectorDocs: () => getConnectorDocs,
28472
28908
  connectorExists: () => connectorExists
28473
28909
  });
28474
- import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4, readdirSync as readdirSync7, statSync as statSync3, rmSync as rmSync2 } from "fs";
28910
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5, readdirSync as readdirSync6, statSync as statSync3, rmSync as rmSync2 } from "fs";
28475
28911
  import { join as join12, dirname as dirname6 } from "path";
28476
28912
  import { fileURLToPath as fileURLToPath4 } from "url";
28477
28913
  function resolveConnectorsDir() {
@@ -28501,7 +28937,7 @@ function loadEnablementManifest(targetDir) {
28501
28937
  return null;
28502
28938
  }
28503
28939
  try {
28504
- const raw = JSON.parse(readFileSync5(manifestPath, "utf-8"));
28940
+ const raw = JSON.parse(readFileSync6(manifestPath, "utf-8"));
28505
28941
  if (!Array.isArray(raw.connectors)) {
28506
28942
  return null;
28507
28943
  }
@@ -28520,7 +28956,7 @@ function getLegacyInstalledConnectors(targetDir) {
28520
28956
  if (!existsSync12(connectorsDir)) {
28521
28957
  return [];
28522
28958
  }
28523
- return readdirSync7(connectorsDir).filter((entry) => {
28959
+ return readdirSync6(connectorsDir).filter((entry) => {
28524
28960
  const fullPath = join12(connectorsDir, entry);
28525
28961
  return entry.startsWith("connect-") && statSync3(fullPath).isDirectory();
28526
28962
  }).map((entry) => entry.replace("connect-", "")).sort();
@@ -28546,18 +28982,18 @@ ${connectorList}
28546
28982
 
28547
28983
  export type EnabledConnectorName = typeof enabledConnectors[number];
28548
28984
  `;
28549
- writeFileSync4(indexPath, content);
28985
+ writeFileSync5(indexPath, content);
28550
28986
  }
28551
28987
  function writeEnablementManifest(targetDir, connectors18) {
28552
28988
  const connectorsDir = getProjectConnectorsDir(targetDir);
28553
- mkdirSync7(connectorsDir, { recursive: true });
28989
+ mkdirSync6(connectorsDir, { recursive: true });
28554
28990
  const manifest = {
28555
28991
  version: 1,
28556
28992
  mode: "internal",
28557
28993
  updatedAt: new Date().toISOString(),
28558
28994
  connectors: [...new Set(connectors18.map((value) => normalizeConnectorName(value)))].sort()
28559
28995
  };
28560
- writeFileSync4(getEnablementManifestPath(targetDir), JSON.stringify(manifest, null, 2) + `
28996
+ writeFileSync5(getEnablementManifestPath(targetDir), JSON.stringify(manifest, null, 2) + `
28561
28997
  `);
28562
28998
  updateConnectorsIndex(connectorsDir, manifest.connectors);
28563
28999
  }
@@ -28637,7 +29073,7 @@ function getConnectorDocs(name) {
28637
29073
  const connectorPath = getConnectorPath(normalizedName);
28638
29074
  const claudeMdPath = join12(connectorPath, "CLAUDE.md");
28639
29075
  if (existsSync12(claudeMdPath)) {
28640
- return parseConnectorDocs(readFileSync5(claudeMdPath, "utf-8"));
29076
+ return parseConnectorDocs(readFileSync6(claudeMdPath, "utf-8"));
28641
29077
  }
28642
29078
  const internalDocs = getInternalConnectorDefinition(normalizedName)?.docsMarkdown;
28643
29079
  if (internalDocs) {
@@ -28696,10 +29132,10 @@ var init_installer = __esm(() => {
28696
29132
  // src/lib/lock.ts
28697
29133
  import { openSync, closeSync, unlinkSync as unlinkSync2, existsSync as existsSync13, statSync as statSync5 } from "fs";
28698
29134
  import { join as join14 } from "path";
28699
- import { mkdirSync as mkdirSync8 } from "fs";
29135
+ import { mkdirSync as mkdirSync7 } from "fs";
28700
29136
  function lockPath(connector) {
28701
29137
  const dir = join14(getConnectorsHome(), `connect-${connector}`);
28702
- mkdirSync8(dir, { recursive: true });
29138
+ mkdirSync7(dir, { recursive: true });
28703
29139
  return join14(dir, ".write.lock");
28704
29140
  }
28705
29141
  function isStale(path) {
@@ -28760,7 +29196,7 @@ var init_lock = __esm(() => {
28760
29196
  });
28761
29197
 
28762
29198
  // src/server/auth.ts
28763
- import { existsSync as existsSync14, readFileSync as readFileSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync9, readdirSync as readdirSync9, rmSync as rmSync3, statSync as statSync6 } from "fs";
29199
+ import { existsSync as existsSync14, readFileSync as readFileSync7, writeFileSync as writeFileSync6, mkdirSync as mkdirSync8, readdirSync as readdirSync8, rmSync as rmSync3, statSync as statSync6 } from "fs";
28764
29200
  import { randomBytes } from "crypto";
28765
29201
  import { join as join15 } from "path";
28766
29202
  function getAuthType(name) {
@@ -28783,7 +29219,7 @@ function getCurrentProfile2(name) {
28783
29219
  const currentProfileFile = join15(configDir, "current_profile");
28784
29220
  if (existsSync14(currentProfileFile)) {
28785
29221
  try {
28786
- return readFileSync6(currentProfileFile, "utf-8").trim() || "default";
29222
+ return readFileSync7(currentProfileFile, "utf-8").trim() || "default";
28787
29223
  } catch {
28788
29224
  return "default";
28789
29225
  }
@@ -28798,13 +29234,13 @@ function loadProfileConfig(name) {
28798
29234
  const profileFile = join15(configDir, "profiles", `${profile}.json`);
28799
29235
  if (existsSync14(profileFile)) {
28800
29236
  try {
28801
- flatConfig = JSON.parse(readFileSync6(profileFile, "utf-8"));
29237
+ flatConfig = JSON.parse(readFileSync7(profileFile, "utf-8"));
28802
29238
  } catch {}
28803
29239
  }
28804
29240
  const profileDirConfig = join15(configDir, "profiles", profile, "config.json");
28805
29241
  if (existsSync14(profileDirConfig)) {
28806
29242
  try {
28807
- dirConfig = JSON.parse(readFileSync6(profileDirConfig, "utf-8"));
29243
+ dirConfig = JSON.parse(readFileSync7(profileDirConfig, "utf-8"));
28808
29244
  } catch {}
28809
29245
  }
28810
29246
  if (Object.keys(flatConfig).length === 0 && Object.keys(dirConfig).length === 0) {
@@ -28812,13 +29248,13 @@ function loadProfileConfig(name) {
28812
29248
  }
28813
29249
  return { ...flatConfig, ...dirConfig };
28814
29250
  }
28815
- function loadTokens2(name) {
29251
+ function loadTokens3(name) {
28816
29252
  const configDir = getConnectorConfigDir(name);
28817
29253
  const profile = getCurrentProfile2(name);
28818
29254
  const tokensFile = join15(configDir, "profiles", profile, "tokens.json");
28819
29255
  if (existsSync14(tokensFile)) {
28820
29256
  try {
28821
- return JSON.parse(readFileSync6(tokensFile, "utf-8"));
29257
+ return JSON.parse(readFileSync7(tokensFile, "utf-8"));
28822
29258
  } catch {
28823
29259
  return null;
28824
29260
  }
@@ -28857,7 +29293,7 @@ function getAuthStatus(name) {
28857
29293
  const authType = getAuthType(name);
28858
29294
  const docs = getConnectorDocs(name);
28859
29295
  const oauthConfig = authType === "oauth" ? getOAuthConfig(name) : {};
28860
- const tokens = authType === "oauth" ? loadTokens2(name) : null;
29296
+ const tokens = authType === "oauth" ? loadTokens3(name) : null;
28861
29297
  const profileConfig = authType === "oauth" ? loadProfileConfig(name) : {};
28862
29298
  const envVars = (docs?.envVars || []).map((v) => ({
28863
29299
  variable: v.variable,
@@ -28907,15 +29343,15 @@ function _saveApiKey(name, key, field) {
28907
29343
  const keyField = field || guessKeyField(name);
28908
29344
  if (keyField === "clientId" || keyField === "clientSecret") {
28909
29345
  const credentialsFile = join15(configDir, "credentials.json");
28910
- mkdirSync9(configDir, { recursive: true });
29346
+ mkdirSync8(configDir, { recursive: true });
28911
29347
  let creds = {};
28912
29348
  if (existsSync14(credentialsFile)) {
28913
29349
  try {
28914
- creds = JSON.parse(readFileSync6(credentialsFile, "utf-8"));
29350
+ creds = JSON.parse(readFileSync7(credentialsFile, "utf-8"));
28915
29351
  } catch {}
28916
29352
  }
28917
29353
  creds[keyField] = key;
28918
- writeFileSync5(credentialsFile, JSON.stringify(creds, null, 2));
29354
+ writeFileSync6(credentialsFile, JSON.stringify(creds, null, 2));
28919
29355
  return;
28920
29356
  }
28921
29357
  const profileFile = join15(configDir, "profiles", `${profile}.json`);
@@ -28923,10 +29359,10 @@ function _saveApiKey(name, key, field) {
28923
29359
  if (existsSync14(profileFile)) {
28924
29360
  let config = {};
28925
29361
  try {
28926
- config = JSON.parse(readFileSync6(profileFile, "utf-8"));
29362
+ config = JSON.parse(readFileSync7(profileFile, "utf-8"));
28927
29363
  } catch {}
28928
29364
  config[keyField] = key;
28929
- writeFileSync5(profileFile, JSON.stringify(config, null, 2));
29365
+ writeFileSync6(profileFile, JSON.stringify(config, null, 2));
28930
29366
  return;
28931
29367
  }
28932
29368
  if (existsSync14(profileDir)) {
@@ -28934,15 +29370,15 @@ function _saveApiKey(name, key, field) {
28934
29370
  let config = {};
28935
29371
  if (existsSync14(configFile)) {
28936
29372
  try {
28937
- config = JSON.parse(readFileSync6(configFile, "utf-8"));
29373
+ config = JSON.parse(readFileSync7(configFile, "utf-8"));
28938
29374
  } catch {}
28939
29375
  }
28940
29376
  config[keyField] = key;
28941
- writeFileSync5(configFile, JSON.stringify(config, null, 2));
29377
+ writeFileSync6(configFile, JSON.stringify(config, null, 2));
28942
29378
  return;
28943
29379
  }
28944
- mkdirSync9(profileDir, { recursive: true });
28945
- writeFileSync5(join15(profileDir, "config.json"), JSON.stringify({ [keyField]: key }, null, 2));
29380
+ mkdirSync8(profileDir, { recursive: true });
29381
+ writeFileSync6(join15(profileDir, "config.json"), JSON.stringify({ [keyField]: key }, null, 2));
28946
29382
  }
28947
29383
  function guessKeyField(name) {
28948
29384
  const docs = getConnectorDocs(name);
@@ -28963,7 +29399,7 @@ function getOAuthConfig(name) {
28963
29399
  const credentialsFile = join15(configDir, "credentials.json");
28964
29400
  if (existsSync14(credentialsFile)) {
28965
29401
  try {
28966
- const creds = JSON.parse(readFileSync6(credentialsFile, "utf-8"));
29402
+ const creds = JSON.parse(readFileSync7(credentialsFile, "utf-8"));
28967
29403
  return { clientId: creds.clientId, clientSecret: creds.clientSecret };
28968
29404
  } catch {}
28969
29405
  }
@@ -29043,16 +29479,16 @@ function saveOAuthTokens(name, tokens) {
29043
29479
  const configDir = getConnectorConfigDir(name);
29044
29480
  const profile = getCurrentProfile2(name);
29045
29481
  const profileDir = join15(configDir, "profiles", profile);
29046
- mkdirSync9(profileDir, { recursive: true });
29482
+ mkdirSync8(profileDir, { recursive: true });
29047
29483
  const tokensFile = join15(profileDir, "tokens.json");
29048
- writeFileSync5(tokensFile, JSON.stringify(tokens, null, 2), { mode: 384 });
29484
+ writeFileSync6(tokensFile, JSON.stringify(tokens, null, 2), { mode: 384 });
29049
29485
  }
29050
29486
  async function refreshOAuthToken(name) {
29051
29487
  return withWriteLock(name, () => _refreshOAuthToken(name));
29052
29488
  }
29053
29489
  async function _refreshOAuthToken(name) {
29054
29490
  const oauthConfig = getOAuthConfig(name);
29055
- const currentTokens = loadTokens2(name);
29491
+ const currentTokens = loadTokens3(name);
29056
29492
  if (!oauthConfig.clientId || !oauthConfig.clientSecret) {
29057
29493
  throw new Error("OAuth credentials not configured for " + name);
29058
29494
  }
@@ -29085,14 +29521,14 @@ async function _refreshOAuthToken(name) {
29085
29521
  saveOAuthTokens(name, tokens);
29086
29522
  return tokens;
29087
29523
  }
29088
- function listProfiles3(name) {
29524
+ function listProfiles4(name) {
29089
29525
  const configDir = getConnectorConfigDir(name);
29090
29526
  const profilesDir = join15(configDir, "profiles");
29091
29527
  if (!existsSync14(profilesDir))
29092
29528
  return ["default"];
29093
29529
  const seen = new Set;
29094
29530
  try {
29095
- const entries = readdirSync9(profilesDir);
29531
+ const entries = readdirSync8(profilesDir);
29096
29532
  for (const entry of entries) {
29097
29533
  const fullPath = join15(profilesDir, entry);
29098
29534
  const stat = statSync6(fullPath);
@@ -29108,8 +29544,8 @@ function listProfiles3(name) {
29108
29544
  }
29109
29545
  function switchProfile(name, profile) {
29110
29546
  const configDir = getConnectorConfigDir(name);
29111
- mkdirSync9(configDir, { recursive: true });
29112
- writeFileSync5(join15(configDir, "current_profile"), profile);
29547
+ mkdirSync8(configDir, { recursive: true });
29548
+ writeFileSync6(join15(configDir, "current_profile"), profile);
29113
29549
  }
29114
29550
  function deleteProfile2(name, profile) {
29115
29551
  if (profile === "default")
@@ -29388,7 +29824,7 @@ var init_rate = __esm(() => {
29388
29824
  });
29389
29825
 
29390
29826
  // src/lib/llm.ts
29391
- import { existsSync as existsSync15, readFileSync as readFileSync7, writeFileSync as writeFileSync6, mkdirSync as mkdirSync10 } from "fs";
29827
+ import { existsSync as existsSync15, readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync9 } from "fs";
29392
29828
  import { join as join16 } from "path";
29393
29829
  function getLlmConfigPath() {
29394
29830
  return join16(getConnectorsHome(), "llm.json");
@@ -29398,15 +29834,15 @@ function getLlmConfig() {
29398
29834
  if (!existsSync15(path))
29399
29835
  return null;
29400
29836
  try {
29401
- return JSON.parse(readFileSync7(path, "utf-8"));
29837
+ return JSON.parse(readFileSync8(path, "utf-8"));
29402
29838
  } catch {
29403
29839
  return null;
29404
29840
  }
29405
29841
  }
29406
29842
  function saveLlmConfig(config) {
29407
29843
  const dir = getConnectorsHome();
29408
- mkdirSync10(dir, { recursive: true });
29409
- writeFileSync6(getLlmConfigPath(), JSON.stringify(config, null, 2));
29844
+ mkdirSync9(dir, { recursive: true });
29845
+ writeFileSync7(getLlmConfigPath(), JSON.stringify(config, null, 2));
29410
29846
  }
29411
29847
  function setLlmStrip(enabled) {
29412
29848
  const config = getLlmConfig();
@@ -29844,7 +30280,7 @@ var init_workflow_runner = __esm(() => {
29844
30280
  });
29845
30281
 
29846
30282
  // src/lib/runner.ts
29847
- import { existsSync as existsSync16, readdirSync as readdirSync10 } from "fs";
30283
+ import { existsSync as existsSync16, readdirSync as readdirSync9 } from "fs";
29848
30284
  import { join as join17, dirname as dirname7 } from "path";
29849
30285
  import { fileURLToPath as fileURLToPath5 } from "url";
29850
30286
  import { spawn as spawn2 } from "child_process";
@@ -29898,7 +30334,7 @@ function buildEnvWithCredentials(connectorName, baseEnv) {
29898
30334
  }
29899
30335
  if (getAuthType(connectorName) === "oauth") {
29900
30336
  const oauthConfig = getOAuthConfig(connectorName);
29901
- const tokens = loadTokens2(connectorName);
30337
+ const tokens = loadTokens3(connectorName);
29902
30338
  for (const { variable } of getEnvVars(connectorName)) {
29903
30339
  if (env[variable])
29904
30340
  continue;
@@ -30106,8 +30542,8 @@ var exports_serve = {};
30106
30542
  __export(exports_serve, {
30107
30543
  startServer: () => startServer
30108
30544
  });
30109
- import { existsSync as existsSync17, readdirSync as readdirSync11, readFileSync as readFileSync8, writeFileSync as writeFileSync7, mkdirSync as mkdirSync11 } from "fs";
30110
- import { join as join18, dirname as dirname8, extname, basename as basename2 } from "path";
30545
+ import { existsSync as existsSync17, readdirSync as readdirSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync8, mkdirSync as mkdirSync10 } from "fs";
30546
+ import { join as join18, dirname as dirname8, extname, basename as basename3 } from "path";
30111
30547
  import { fileURLToPath as fileURLToPath6 } from "url";
30112
30548
  function logActivity(action, connector, detail) {
30113
30549
  activityLog.unshift({ action, connector, timestamp: Date.now(), detail });
@@ -30656,13 +31092,13 @@ ${result.stderr}`;
30656
31092
  if (!isValidConnectorName(name))
30657
31093
  return json({ error: "Invalid connector name" }, 400, port);
30658
31094
  try {
30659
- const profiles = listProfiles3(name);
31095
+ const profiles = listProfiles4(name);
30660
31096
  const configDir = join18(getConnectorsHome(), name.startsWith("connect-") ? name : `connect-${name}`);
30661
31097
  const currentProfileFile = join18(configDir, "current_profile");
30662
31098
  let current = "default";
30663
31099
  if (existsSync17(currentProfileFile)) {
30664
31100
  try {
30665
- current = readFileSync8(currentProfileFile, "utf-8").trim() || "default";
31101
+ current = readFileSync9(currentProfileFile, "utf-8").trim() || "default";
30666
31102
  } catch {}
30667
31103
  }
30668
31104
  return json({ current, profiles }, 200, port);
@@ -30712,7 +31148,7 @@ ${result.stderr}`;
30712
31148
  const connectDir = getConnectorsHome();
30713
31149
  const result = {};
30714
31150
  if (existsSync17(connectDir)) {
30715
- const entries = readdirSync11(connectDir, { withFileTypes: true });
31151
+ const entries = readdirSync10(connectDir, { withFileTypes: true });
30716
31152
  for (const entry of entries) {
30717
31153
  if (!entry.isDirectory() || !entry.name.startsWith("connect-"))
30718
31154
  continue;
@@ -30721,12 +31157,12 @@ ${result.stderr}`;
30721
31157
  if (!existsSync17(profilesDir))
30722
31158
  continue;
30723
31159
  const profiles = {};
30724
- const profileEntries = readdirSync11(profilesDir, { withFileTypes: true });
31160
+ const profileEntries = readdirSync10(profilesDir, { withFileTypes: true });
30725
31161
  for (const pEntry of profileEntries) {
30726
31162
  if (pEntry.isFile() && pEntry.name.endsWith(".json")) {
30727
- const profileName = basename2(pEntry.name, ".json");
31163
+ const profileName = basename3(pEntry.name, ".json");
30728
31164
  try {
30729
- const config = JSON.parse(readFileSync8(join18(profilesDir, pEntry.name), "utf-8"));
31165
+ const config = JSON.parse(readFileSync9(join18(profilesDir, pEntry.name), "utf-8"));
30730
31166
  profiles[profileName] = config;
30731
31167
  } catch {}
30732
31168
  }
@@ -30734,7 +31170,7 @@ ${result.stderr}`;
30734
31170
  const configPath = join18(profilesDir, pEntry.name, "config.json");
30735
31171
  if (existsSync17(configPath)) {
30736
31172
  try {
30737
- const config = JSON.parse(readFileSync8(configPath, "utf-8"));
31173
+ const config = JSON.parse(readFileSync9(configPath, "utf-8"));
30738
31174
  profiles[pEntry.name] = config;
30739
31175
  } catch {}
30740
31176
  }
@@ -30780,9 +31216,9 @@ ${result.stderr}`;
30780
31216
  for (const [profileName, config] of Object.entries(data.profiles)) {
30781
31217
  if (!config || typeof config !== "object")
30782
31218
  continue;
30783
- mkdirSync11(profilesDir, { recursive: true });
31219
+ mkdirSync10(profilesDir, { recursive: true });
30784
31220
  const profileFile = join18(profilesDir, `${profileName}.json`);
30785
- writeFileSync7(profileFile, JSON.stringify(config, null, 2));
31221
+ writeFileSync8(profileFile, JSON.stringify(config, null, 2));
30786
31222
  imported++;
30787
31223
  }
30788
31224
  }
@@ -32402,7 +32838,7 @@ init_registry2();
32402
32838
  init_installer();
32403
32839
  import { render } from "ink";
32404
32840
  import chalk2 from "chalk";
32405
- import { readdirSync as readdirSync8, statSync as statSync4 } from "fs";
32841
+ import { readdirSync as readdirSync7, statSync as statSync4 } from "fs";
32406
32842
  import { join as join13, relative as relative2 } from "path";
32407
32843
  import { createInterface } from "readline";
32408
32844
  import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
@@ -32417,7 +32853,7 @@ var PRESETS = {
32417
32853
  };
32418
32854
  function listFilesRecursive(dir, base = dir) {
32419
32855
  const files = [];
32420
- for (const entry of readdirSync8(dir)) {
32856
+ for (const entry of readdirSync7(dir)) {
32421
32857
  const fullPath = join13(dir, entry);
32422
32858
  if (statSync4(fullPath).isDirectory()) {
32423
32859
  files.push(...listFilesRecursive(fullPath, base));
@@ -33089,7 +33525,7 @@ init_installer();
33089
33525
  init_auth();
33090
33526
  init_database();
33091
33527
  import chalk4 from "chalk";
33092
- import { existsSync as existsSync18, readdirSync as readdirSync12, statSync as statSync7, readFileSync as readFileSync9 } from "fs";
33528
+ import { existsSync as existsSync18, readdirSync as readdirSync11, statSync as statSync7, readFileSync as readFileSync10 } from "fs";
33093
33529
  import { join as join19 } from "path";
33094
33530
  function registerCommands3(program2) {
33095
33531
  program2.command("status").option("--json", "Output as JSON", false).description("Show auth status of all configured connectors (project + global)").action((options) => {
@@ -33104,7 +33540,7 @@ function registerCommands3(program2) {
33104
33540
  let profile = "default";
33105
33541
  if (existsSync18(currentProfileFile)) {
33106
33542
  try {
33107
- profile = readFileSync9(currentProfileFile, "utf-8").trim() || "default";
33543
+ profile = readFileSync10(currentProfileFile, "utf-8").trim() || "default";
33108
33544
  } catch {}
33109
33545
  }
33110
33546
  let expiryLabel = null;
@@ -33142,7 +33578,7 @@ function registerCommands3(program2) {
33142
33578
  }
33143
33579
  if (existsSync18(configDir)) {
33144
33580
  try {
33145
- const globalDirs = readdirSync12(configDir).filter((f) => {
33581
+ const globalDirs = readdirSync11(configDir).filter((f) => {
33146
33582
  if (!f.startsWith("connect-"))
33147
33583
  return false;
33148
33584
  if (f.startsWith("connect-zzztest"))
@@ -33361,7 +33797,7 @@ init_registry2();
33361
33797
  init_auth();
33362
33798
  init_database();
33363
33799
  import chalk5 from "chalk";
33364
- import { existsSync as existsSync19, readdirSync as readdirSync13, statSync as statSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync8, mkdirSync as mkdirSync12 } from "fs";
33800
+ import { existsSync as existsSync19, readdirSync as readdirSync12, statSync as statSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync9, mkdirSync as mkdirSync11 } from "fs";
33365
33801
  import { join as join20 } from "path";
33366
33802
  import { homedir as homedir8 } from "os";
33367
33803
  import { createInterface as createInterface2 } from "readline";
@@ -33415,7 +33851,7 @@ function redactSecrets(obj) {
33415
33851
  return obj;
33416
33852
  }
33417
33853
  function getOAuthTokenState(name) {
33418
- const tokens = loadTokens2(name);
33854
+ const tokens = loadTokens3(name);
33419
33855
  if (!tokens?.accessToken && !tokens?.refreshToken) {
33420
33856
  return { hasTokens: false, expired: false };
33421
33857
  }
@@ -33734,7 +34170,7 @@ Open this URL to authenticate:
33734
34170
  const configuredNames = [];
33735
34171
  try {
33736
34172
  if (existsSync19(connectorsHome)) {
33737
- const entries = readdirSync13(connectorsHome).filter((e) => e.startsWith("connect-") && statSync8(join20(connectorsHome, e)).isDirectory());
34173
+ const entries = readdirSync12(connectorsHome).filter((e) => e.startsWith("connect-") && statSync8(join20(connectorsHome, e)).isDirectory());
33738
34174
  for (const entry of entries) {
33739
34175
  const profilesDir = join20(connectorsHome, entry, "profiles");
33740
34176
  if (existsSync19(profilesDir)) {
@@ -33789,7 +34225,7 @@ Open this URL to authenticate:
33789
34225
  const connectDir = getConnectorsHome();
33790
34226
  const result = {};
33791
34227
  if (existsSync19(connectDir)) {
33792
- for (const entry of readdirSync13(connectDir)) {
34228
+ for (const entry of readdirSync12(connectDir)) {
33793
34229
  const entryPath = join20(connectDir, entry);
33794
34230
  if (!statSync8(entryPath).isDirectory() || !entry.startsWith("connect-"))
33795
34231
  continue;
@@ -33798,7 +34234,7 @@ Open this URL to authenticate:
33798
34234
  const credentialsPath = join20(entryPath, "credentials.json");
33799
34235
  if (existsSync19(credentialsPath)) {
33800
34236
  try {
33801
- credentials = JSON.parse(readFileSync10(credentialsPath, "utf-8"));
34237
+ credentials = JSON.parse(readFileSync11(credentialsPath, "utf-8"));
33802
34238
  } catch {}
33803
34239
  }
33804
34240
  const profilesDir = join20(entryPath, "profiles");
@@ -33806,11 +34242,11 @@ Open this URL to authenticate:
33806
34242
  continue;
33807
34243
  const profiles = {};
33808
34244
  if (existsSync19(profilesDir)) {
33809
- for (const pEntry of readdirSync13(profilesDir)) {
34245
+ for (const pEntry of readdirSync12(profilesDir)) {
33810
34246
  const pPath = join20(profilesDir, pEntry);
33811
34247
  if (statSync8(pPath).isFile() && pEntry.endsWith(".json")) {
33812
34248
  try {
33813
- profiles[pEntry.replace(/\.json$/, "")] = JSON.parse(readFileSync10(pPath, "utf-8"));
34249
+ profiles[pEntry.replace(/\.json$/, "")] = JSON.parse(readFileSync11(pPath, "utf-8"));
33814
34250
  } catch {}
33815
34251
  } else if (statSync8(pPath).isDirectory()) {
33816
34252
  const configPath = join20(pPath, "config.json");
@@ -33818,12 +34254,12 @@ Open this URL to authenticate:
33818
34254
  let merged = {};
33819
34255
  if (existsSync19(configPath)) {
33820
34256
  try {
33821
- merged = { ...merged, ...JSON.parse(readFileSync10(configPath, "utf-8")) };
34257
+ merged = { ...merged, ...JSON.parse(readFileSync11(configPath, "utf-8")) };
33822
34258
  } catch {}
33823
34259
  }
33824
34260
  if (existsSync19(tokensPath)) {
33825
34261
  try {
33826
- merged = { ...merged, ...JSON.parse(readFileSync10(tokensPath, "utf-8")) };
34262
+ merged = { ...merged, ...JSON.parse(readFileSync11(tokensPath, "utf-8")) };
33827
34263
  } catch {}
33828
34264
  }
33829
34265
  if (Object.keys(merged).length > 0)
@@ -33844,7 +34280,7 @@ Open this URL to authenticate:
33844
34280
  }
33845
34281
  const exportData = JSON.stringify(exportPayload, null, 2);
33846
34282
  if (options.output) {
33847
- writeFileSync8(options.output, exportData);
34283
+ writeFileSync9(options.output, exportData);
33848
34284
  console.log(chalk5.green(`\u2713 Exported to ${options.output}`));
33849
34285
  } else {
33850
34286
  console.log(exportData);
@@ -33867,7 +34303,7 @@ Open this URL to authenticate:
33867
34303
  process.exit(1);
33868
34304
  return;
33869
34305
  }
33870
- raw = readFileSync10(file, "utf-8");
34306
+ raw = readFileSync11(file, "utf-8");
33871
34307
  }
33872
34308
  let data;
33873
34309
  try {
@@ -33897,8 +34333,8 @@ Open this URL to authenticate:
33897
34333
  continue;
33898
34334
  const connectorDir = join20(connectDir, `connect-${connectorName}`);
33899
34335
  if (connData.credentials && typeof connData.credentials === "object") {
33900
- mkdirSync12(connectorDir, { recursive: true });
33901
- writeFileSync8(join20(connectorDir, "credentials.json"), JSON.stringify(connData.credentials, null, 2));
34336
+ mkdirSync11(connectorDir, { recursive: true });
34337
+ writeFileSync9(join20(connectorDir, "credentials.json"), JSON.stringify(connData.credentials, null, 2));
33902
34338
  imported++;
33903
34339
  }
33904
34340
  if (!connData.profiles || typeof connData.profiles !== "object")
@@ -33907,8 +34343,8 @@ Open this URL to authenticate:
33907
34343
  for (const [profileName, config] of Object.entries(connData.profiles)) {
33908
34344
  if (!config || typeof config !== "object")
33909
34345
  continue;
33910
- mkdirSync12(profilesDir, { recursive: true });
33911
- writeFileSync8(join20(profilesDir, `${profileName}.json`), JSON.stringify(config, null, 2));
34346
+ mkdirSync11(profilesDir, { recursive: true });
34347
+ writeFileSync9(join20(profilesDir, `${profileName}.json`), JSON.stringify(config, null, 2));
33912
34348
  imported++;
33913
34349
  }
33914
34350
  }
@@ -33929,7 +34365,7 @@ Open this URL to authenticate:
33929
34365
  }
33930
34366
  return;
33931
34367
  }
33932
- const entries = readdirSync13(oldBase).filter((name) => {
34368
+ const entries = readdirSync12(oldBase).filter((name) => {
33933
34369
  if (!name.startsWith("connect-"))
33934
34370
  return false;
33935
34371
  try {
@@ -33969,9 +34405,9 @@ Open this URL to authenticate:
33969
34405
  }
33970
34406
  if (!options.dryRun) {
33971
34407
  const parentDir = join20(destPath, "..");
33972
- mkdirSync12(parentDir, { recursive: true });
33973
- const content = readFileSync10(srcPath);
33974
- writeFileSync8(destPath, content);
34408
+ mkdirSync11(parentDir, { recursive: true });
34409
+ const content = readFileSync11(srcPath);
34410
+ writeFileSync9(destPath, content);
33975
34411
  }
33976
34412
  copiedFiles.push(relFile);
33977
34413
  }
@@ -34037,7 +34473,7 @@ init_installer();
34037
34473
  init_auth();
34038
34474
  init_database();
34039
34475
  import chalk6 from "chalk";
34040
- import { existsSync as existsSync20, readdirSync as readdirSync14, statSync as statSync9, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
34476
+ import { existsSync as existsSync20, readdirSync as readdirSync13, statSync as statSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
34041
34477
  import { join as join21 } from "path";
34042
34478
 
34043
34479
  // src/lib/test-endpoints.ts
@@ -34425,7 +34861,7 @@ complete -F _connectors connectors`);
34425
34861
  `) + `
34426
34862
  `;
34427
34863
  if (options.output) {
34428
- writeFileSync9(options.output, output);
34864
+ writeFileSync10(options.output, output);
34429
34865
  console.log(chalk6.green(`\u2713 Written to ${options.output} (${vars.length} variables)`));
34430
34866
  } else {
34431
34867
  console.log(output);
@@ -34472,14 +34908,14 @@ Available presets:
34472
34908
  let profile = "default";
34473
34909
  if (existsSync20(currentProfileFile)) {
34474
34910
  try {
34475
- profile = readFileSync11(currentProfileFile, "utf-8").trim() || "default";
34911
+ profile = readFileSync12(currentProfileFile, "utf-8").trim() || "default";
34476
34912
  } catch {}
34477
34913
  }
34478
34914
  connectorDetails.push({ name, configured: auth.configured, authType: auth.type, profile, source: "project" });
34479
34915
  }
34480
34916
  if (existsSync20(configDir)) {
34481
34917
  try {
34482
- const globalDirs = readdirSync14(configDir).filter((f) => {
34918
+ const globalDirs = readdirSync13(configDir).filter((f) => {
34483
34919
  if (!f.startsWith("connect-"))
34484
34920
  return false;
34485
34921
  try {
@@ -34501,7 +34937,7 @@ Available presets:
34501
34937
  let profile = "default";
34502
34938
  if (existsSync20(currentProfileFile)) {
34503
34939
  try {
34504
- profile = readFileSync11(currentProfileFile, "utf-8").trim() || "default";
34940
+ profile = readFileSync12(currentProfileFile, "utf-8").trim() || "default";
34505
34941
  } catch {}
34506
34942
  }
34507
34943
  connectorDetails.push({ name, configured: true, authType: auth.type, profile, source: "global" });
@@ -34620,13 +35056,13 @@ Testing connector credentials...
34620
35056
  const currentProfileFile = join21(connectorConfigDir, "current_profile");
34621
35057
  if (existsSync20(currentProfileFile)) {
34622
35058
  try {
34623
- currentProfile = readFileSync11(currentProfileFile, "utf-8").trim() || "default";
35059
+ currentProfile = readFileSync12(currentProfileFile, "utf-8").trim() || "default";
34624
35060
  } catch {}
34625
35061
  }
34626
35062
  const tokensFile = join21(connectorConfigDir, "profiles", currentProfile, "tokens.json");
34627
35063
  if (existsSync20(tokensFile)) {
34628
35064
  try {
34629
- const tokens = JSON.parse(readFileSync11(tokensFile, "utf-8"));
35065
+ const tokens = JSON.parse(readFileSync12(tokensFile, "utf-8"));
34630
35066
  const isExpired = tokens.expiresAt && Date.now() >= tokens.expiresAt - 60000;
34631
35067
  if (isExpired && tokens.refreshToken) {
34632
35068
  try {
@@ -34647,7 +35083,7 @@ Testing connector credentials...
34647
35083
  const profileFile = join21(connectorConfigDir, "profiles", `${currentProfile}.json`);
34648
35084
  if (existsSync20(profileFile)) {
34649
35085
  try {
34650
- const config = JSON.parse(readFileSync11(profileFile, "utf-8"));
35086
+ const config = JSON.parse(readFileSync12(profileFile, "utf-8"));
34651
35087
  apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
34652
35088
  } catch {}
34653
35089
  }
@@ -34656,7 +35092,7 @@ Testing connector credentials...
34656
35092
  const profileDirConfig = join21(connectorConfigDir, "profiles", currentProfile, "config.json");
34657
35093
  if (existsSync20(profileDirConfig)) {
34658
35094
  try {
34659
- const config = JSON.parse(readFileSync11(profileDirConfig, "utf-8"));
35095
+ const config = JSON.parse(readFileSync12(profileDirConfig, "utf-8"));
34660
35096
  apiKey = Object.values(config).find((v) => typeof v === "string" && v.length > 0);
34661
35097
  } catch {}
34662
35098
  }