aboutsummaryrefslogtreecommitdiff
path: root/apps/browser-extension/entrypoints
diff options
context:
space:
mode:
authorDhravya Shah <[email protected]>2025-09-18 20:16:57 -0700
committerDhravya Shah <[email protected]>2025-09-18 20:30:04 -0700
commitdd3122a4831eac3507b7feb8ba2f1816be5eb3cf (patch)
tree4c3eda087974eaaea0b91c85f839eaa8650522e8 /apps/browser-extension/entrypoints
parentnewish get started page (diff)
downloadsupermemory-09-18-format_browser_extension.tar.xz
supermemory-09-18-format_browser_extension.zip
format browser extension09-18-format_browser_extension
Diffstat (limited to 'apps/browser-extension/entrypoints')
-rw-r--r--apps/browser-extension/entrypoints/background.ts156
-rw-r--r--apps/browser-extension/entrypoints/content/chatgpt.ts497
-rw-r--r--apps/browser-extension/entrypoints/content/claude.ts421
-rw-r--r--apps/browser-extension/entrypoints/content/index.ts64
-rw-r--r--apps/browser-extension/entrypoints/content/shared.ts46
-rw-r--r--apps/browser-extension/entrypoints/content/t3.ts455
-rw-r--r--apps/browser-extension/entrypoints/content/twitter.ts60
-rw-r--r--apps/browser-extension/entrypoints/popup/App.tsx155
-rw-r--r--apps/browser-extension/entrypoints/popup/main.tsx16
-rw-r--r--apps/browser-extension/entrypoints/welcome/Welcome.tsx6
-rw-r--r--apps/browser-extension/entrypoints/welcome/main.tsx16
11 files changed, 958 insertions, 934 deletions
diff --git a/apps/browser-extension/entrypoints/background.ts b/apps/browser-extension/entrypoints/background.ts
index 9d46a5e9..b71b54c7 100644
--- a/apps/browser-extension/entrypoints/background.ts
+++ b/apps/browser-extension/entrypoints/background.ts
@@ -1,52 +1,52 @@
-import { getDefaultProject, saveMemory, searchMemories } from "../utils/api"
+import { getDefaultProject, saveMemory, searchMemories } from "../utils/api";
import {
CONTAINER_TAGS,
CONTEXT_MENU_IDS,
MESSAGE_TYPES,
POSTHOG_EVENT_KEY,
-} from "../utils/constants"
-import { trackEvent } from "../utils/posthog"
-import { captureTwitterTokens } from "../utils/twitter-auth"
+} from "../utils/constants";
+import { trackEvent } from "../utils/posthog";
+import { captureTwitterTokens } from "../utils/twitter-auth";
import {
type TwitterImportConfig,
TwitterImporter,
-} from "../utils/twitter-import"
+} from "../utils/twitter-import";
import type {
ExtensionMessage,
MemoryData,
MemoryPayload,
-} from "../utils/types"
+} from "../utils/types";
export default defineBackground(() => {
- let twitterImporter: TwitterImporter | null = null
+ let twitterImporter: TwitterImporter | null = null;
browser.runtime.onInstalled.addListener(async (details) => {
browser.contextMenus.create({
id: CONTEXT_MENU_IDS.SAVE_TO_SUPERMEMORY,
title: "sync to supermemory",
contexts: ["selection", "page", "link"],
- })
+ });
if (details.reason === "install") {
await trackEvent("extension_installed", {
reason: details.reason,
version: browser.runtime.getManifest().version,
- })
+ });
browser.tabs.create({
url: browser.runtime.getURL("/welcome.html"),
- })
+ });
}
- })
+ });
// Intercept Twitter requests to capture authentication headers.
browser.webRequest.onBeforeSendHeaders.addListener(
(details) => {
- captureTwitterTokens(details)
- return {}
+ captureTwitterTokens(details);
+ return {};
},
{ urls: ["*://x.com/*", "*://twitter.com/*"] },
["requestHeaders", "extraHeaders"],
- )
+ );
// Handle context menu clicks.
browser.contextMenus.onClicked.addListener(async (info, tab) => {
@@ -56,27 +56,27 @@ export default defineBackground(() => {
await browser.tabs.sendMessage(tab.id, {
action: MESSAGE_TYPES.SAVE_MEMORY,
actionSource: "context_menu",
- })
+ });
} catch (error) {
- console.error("Failed to send message to content script:", error)
+ console.error("Failed to send message to content script:", error);
}
}
}
- })
+ });
// Send message to current active tab.
const sendMessageToCurrentTab = async (message: string) => {
const tabs = await browser.tabs.query({
active: true,
currentWindow: true,
- })
+ });
if (tabs.length > 0 && tabs[0].id) {
await browser.tabs.sendMessage(tabs[0].id, {
type: MESSAGE_TYPES.IMPORT_UPDATE,
importedMessage: message,
- })
+ });
}
- }
+ };
/**
* Send import completion message
@@ -85,14 +85,14 @@ export default defineBackground(() => {
const tabs = await browser.tabs.query({
active: true,
currentWindow: true,
- })
+ });
if (tabs.length > 0 && tabs[0].id) {
await browser.tabs.sendMessage(tabs[0].id, {
type: MESSAGE_TYPES.IMPORT_DONE,
totalImported,
- })
+ });
}
- }
+ };
/**
* Save memory to supermemory API
@@ -102,14 +102,14 @@ export default defineBackground(() => {
actionSource: string,
): Promise<{ success: boolean; data?: unknown; error?: string }> => {
try {
- let containerTag: string = CONTAINER_TAGS.DEFAULT_PROJECT
+ let containerTag: string = CONTAINER_TAGS.DEFAULT_PROJECT;
try {
- const defaultProject = await getDefaultProject()
+ const defaultProject = await getDefaultProject();
if (defaultProject?.containerTag) {
- containerTag = defaultProject.containerTag
+ containerTag = defaultProject.containerTag;
}
} catch (error) {
- console.warn("Failed to get default project, using fallback:", error)
+ console.warn("Failed to get default project, using fallback:", error);
}
const payload: MemoryPayload = {
@@ -118,48 +118,48 @@ export default defineBackground(() => {
data.content ||
`${data.highlightedText}\n\n${data.html}\n\n${data?.url}`,
metadata: { sm_source: "consumer" },
- }
+ };
- const responseData = await saveMemory(payload)
+ const responseData = await saveMemory(payload);
await trackEvent(POSTHOG_EVENT_KEY.SAVE_MEMORY_ATTEMPTED, {
source: `${POSTHOG_EVENT_KEY.SOURCE}_${actionSource}`,
has_highlight: !!data.highlightedText,
url_domain: data.url ? new URL(data.url).hostname : undefined,
- })
+ });
- return { success: true, data: responseData }
+ return { success: true, data: responseData };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
- }
+ };
}
- }
+ };
const getRelatedMemories = async (
data: string,
eventSource: string,
): Promise<{ success: boolean; data?: unknown; error?: string }> => {
try {
- const responseData = await searchMemories(data)
+ const responseData = await searchMemories(data);
const response = responseData as {
- results?: Array<{ memory?: string }>
- }
- const memories: string[] = []
+ results?: Array<{ memory?: string }>;
+ };
+ const memories: string[] = [];
response.results?.forEach((result, index) => {
- memories.push(`${index + 1}. ${result.memory} \n`)
- })
- console.log("Memories:", memories)
- await trackEvent(eventSource)
- return { success: true, data: memories }
+ memories.push(`${index + 1}. ${result.memory} \n`);
+ });
+ console.log("Memories:", memories);
+ await trackEvent(eventSource);
+ return { success: true, data: memories };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
- }
+ };
}
- }
+ };
/**
* Handle extension messages
@@ -172,83 +172,83 @@ export default defineBackground(() => {
onProgress: sendMessageToCurrentTab,
onComplete: sendImportDoneMessage,
onError: async (error: Error) => {
- await sendMessageToCurrentTab(`Error: ${error.message}`)
+ await sendMessageToCurrentTab(`Error: ${error.message}`);
},
- }
+ };
- twitterImporter = new TwitterImporter(importConfig)
- twitterImporter.startImport().catch(console.error)
- sendResponse({ success: true })
- return true
+ twitterImporter = new TwitterImporter(importConfig);
+ twitterImporter.startImport().catch(console.error);
+ sendResponse({ success: true });
+ return true;
}
// Handle regular memory save request
if (message.action === MESSAGE_TYPES.SAVE_MEMORY) {
- ;(async () => {
+ (async () => {
try {
const result = await saveMemoryToSupermemory(
message.data as MemoryData,
message.actionSource || "unknown",
- )
- sendResponse(result)
+ );
+ sendResponse(result);
} catch (error) {
sendResponse({
success: false,
error: error instanceof Error ? error.message : "Unknown error",
- })
+ });
}
- })()
- return true
+ })();
+ return true;
}
if (message.action === MESSAGE_TYPES.GET_RELATED_MEMORIES) {
- ;(async () => {
+ (async () => {
try {
const result = await getRelatedMemories(
message.data as string,
message.actionSource || "unknown",
- )
- sendResponse(result)
+ );
+ sendResponse(result);
} catch (error) {
sendResponse({
success: false,
error: error instanceof Error ? error.message : "Unknown error",
- })
+ });
}
- })()
- return true
+ })();
+ return true;
}
if (message.action === MESSAGE_TYPES.CAPTURE_PROMPT) {
- ;(async () => {
+ (async () => {
try {
const messageData = message.data as {
- prompt: string
- platform: string
- source: string
- }
- console.log("=== PROMPT CAPTURED ===")
- console.log(messageData)
- console.log("========================")
+ prompt: string;
+ platform: string;
+ source: string;
+ };
+ console.log("=== PROMPT CAPTURED ===");
+ console.log(messageData);
+ console.log("========================");
const memoryData: MemoryData = {
content: messageData.prompt,
- }
+ };
const result = await saveMemoryToSupermemory(
memoryData,
`prompt_capture_${messageData.platform}`,
- )
- sendResponse(result)
+ );
+ sendResponse(result);
} catch (error) {
sendResponse({
success: false,
error: error instanceof Error ? error.message : "Unknown error",
- })
+ });
}
- })()
- return true
+ })();
+ return true;
}
},
- )
-})
+ );
+});
diff --git a/apps/browser-extension/entrypoints/content/chatgpt.ts b/apps/browser-extension/entrypoints/content/chatgpt.ts
index 73e0354f..4657acb7 100644
--- a/apps/browser-extension/entrypoints/content/chatgpt.ts
+++ b/apps/browser-extension/entrypoints/content/chatgpt.ts
@@ -5,78 +5,78 @@ import {
POSTHOG_EVENT_KEY,
STORAGE_KEYS,
UI_CONFIG,
-} from "../../utils/constants"
+} from "../../utils/constants";
import {
createChatGPTInputBarElement,
DOMUtils,
-} from "../../utils/ui-components"
+} from "../../utils/ui-components";
-let chatGPTDebounceTimeout: NodeJS.Timeout | null = null
-let chatGPTRouteObserver: MutationObserver | null = null
-let chatGPTUrlCheckInterval: NodeJS.Timeout | null = null
-let chatGPTObserverThrottle: NodeJS.Timeout | null = null
+let chatGPTDebounceTimeout: NodeJS.Timeout | null = null;
+let chatGPTRouteObserver: MutationObserver | null = null;
+let chatGPTUrlCheckInterval: NodeJS.Timeout | null = null;
+let chatGPTObserverThrottle: NodeJS.Timeout | null = null;
export function initializeChatGPT() {
if (!DOMUtils.isOnDomain(DOMAINS.CHATGPT)) {
- return
+ return;
}
if (document.body.hasAttribute("data-chatgpt-initialized")) {
- return
+ return;
}
setTimeout(() => {
- addSupermemoryButtonToMemoriesDialog()
- addSaveChatGPTElementBeforeComposerBtn()
- setupChatGPTAutoFetch()
- }, 2000)
+ addSupermemoryButtonToMemoriesDialog();
+ addSaveChatGPTElementBeforeComposerBtn();
+ setupChatGPTAutoFetch();
+ }, 2000);
- setupChatGPTPromptCapture()
+ setupChatGPTPromptCapture();
- setupChatGPTRouteChangeDetection()
+ setupChatGPTRouteChangeDetection();
- document.body.setAttribute("data-chatgpt-initialized", "true")
+ document.body.setAttribute("data-chatgpt-initialized", "true");
}
function setupChatGPTRouteChangeDetection() {
if (chatGPTRouteObserver) {
- chatGPTRouteObserver.disconnect()
+ chatGPTRouteObserver.disconnect();
}
if (chatGPTUrlCheckInterval) {
- clearInterval(chatGPTUrlCheckInterval)
+ clearInterval(chatGPTUrlCheckInterval);
}
if (chatGPTObserverThrottle) {
- clearTimeout(chatGPTObserverThrottle)
- chatGPTObserverThrottle = null
+ clearTimeout(chatGPTObserverThrottle);
+ chatGPTObserverThrottle = null;
}
- let currentUrl = window.location.href
+ let currentUrl = window.location.href;
const checkForRouteChange = () => {
if (window.location.href !== currentUrl) {
- currentUrl = window.location.href
- console.log("ChatGPT route changed, re-adding supermemory elements")
+ currentUrl = window.location.href;
+ console.log("ChatGPT route changed, re-adding supermemory elements");
setTimeout(() => {
- addSupermemoryButtonToMemoriesDialog()
- addSaveChatGPTElementBeforeComposerBtn()
- setupChatGPTAutoFetch()
- }, 1000)
+ addSupermemoryButtonToMemoriesDialog();
+ addSaveChatGPTElementBeforeComposerBtn();
+ setupChatGPTAutoFetch();
+ }, 1000);
}
- }
+ };
- chatGPTUrlCheckInterval = setInterval(checkForRouteChange, 2000)
+ chatGPTUrlCheckInterval = setInterval(checkForRouteChange, 2000);
chatGPTRouteObserver = new MutationObserver((mutations) => {
if (chatGPTObserverThrottle) {
- return
+ return;
}
- let shouldRecheck = false
+ let shouldRecheck = false;
mutations.forEach((mutation) => {
if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
- const element = node as Element
+ const element = node as Element;
if (
element.querySelector?.("#prompt-textarea") ||
element.querySelector?.("button.composer-btn") ||
@@ -84,65 +84,65 @@ function setupChatGPTRouteChangeDetection() {
element.matches?.("#prompt-textarea") ||
element.id === "prompt-textarea"
) {
- shouldRecheck = true
+ shouldRecheck = true;
}
}
- })
+ });
}
- })
+ });
if (shouldRecheck) {
chatGPTObserverThrottle = setTimeout(() => {
try {
- chatGPTObserverThrottle = null
- addSupermemoryButtonToMemoriesDialog()
- addSaveChatGPTElementBeforeComposerBtn()
- setupChatGPTAutoFetch()
+ chatGPTObserverThrottle = null;
+ addSupermemoryButtonToMemoriesDialog();
+ addSaveChatGPTElementBeforeComposerBtn();
+ setupChatGPTAutoFetch();
} catch (error) {
- console.error("Error in ChatGPT observer callback:", error)
+ console.error("Error in ChatGPT observer callback:", error);
}
- }, 300)
+ }, 300);
}
- })
+ });
try {
chatGPTRouteObserver.observe(document.body, {
childList: true,
subtree: true,
- })
+ });
} catch (error) {
- console.error("Failed to set up ChatGPT route observer:", error)
+ console.error("Failed to set up ChatGPT route observer:", error);
if (chatGPTUrlCheckInterval) {
- clearInterval(chatGPTUrlCheckInterval)
+ clearInterval(chatGPTUrlCheckInterval);
}
- chatGPTUrlCheckInterval = setInterval(checkForRouteChange, 1000)
+ chatGPTUrlCheckInterval = setInterval(checkForRouteChange, 1000);
}
}
async function getRelatedMemoriesForChatGPT(actionSource: string) {
try {
const userQuery =
- document.getElementById("prompt-textarea")?.textContent || ""
+ document.getElementById("prompt-textarea")?.textContent || "";
const icon = document.querySelectorAll(
'[id*="sm-chatgpt-input-bar-element-before-composer"]',
- )[0]
+ )[0];
- const iconElement = icon as HTMLElement
+ const iconElement = icon as HTMLElement;
if (!iconElement) {
- console.warn("ChatGPT icon element not found, cannot update feedback")
- return
+ console.warn("ChatGPT icon element not found, cannot update feedback");
+ return;
}
- updateChatGPTIconFeedback("Searching memories...", iconElement)
+ updateChatGPTIconFeedback("Searching memories...", iconElement);
const timeoutPromise = new Promise((_, reject) =>
setTimeout(
() => reject(new Error("Memory search timeout")),
UI_CONFIG.API_REQUEST_TIMEOUT,
),
- )
+ );
const response = await Promise.race([
browser.runtime.sendMessage({
@@ -151,78 +151,78 @@ async function getRelatedMemoriesForChatGPT(actionSource: string) {
actionSource: actionSource,
}),
timeoutPromise,
- ])
+ ]);
if (response?.success && response?.data) {
- const promptElement = document.getElementById("prompt-textarea")
+ const promptElement = document.getElementById("prompt-textarea");
if (promptElement) {
- promptElement.dataset.supermemories = `<div>Supermemories of user (only for the reference): ${response.data}</div>`
+ promptElement.dataset.supermemories = `<div>Supermemories of user (only for the reference): ${response.data}</div>`;
console.log(
"Prompt element dataset:",
promptElement.dataset.supermemories,
- )
+ );
- iconElement.dataset.memoriesData = response.data
+ iconElement.dataset.memoriesData = response.data;
- updateChatGPTIconFeedback("Included Memories", iconElement)
+ updateChatGPTIconFeedback("Included Memories", iconElement);
} else {
console.warn(
"ChatGPT prompt element not found after successful memory fetch",
- )
- updateChatGPTIconFeedback("Memories found", iconElement)
+ );
+ updateChatGPTIconFeedback("Memories found", iconElement);
}
} else {
- console.warn("No memories found or API response invalid")
- updateChatGPTIconFeedback("No memories found", iconElement)
+ console.warn("No memories found or API response invalid");
+ updateChatGPTIconFeedback("No memories found", iconElement);
}
} catch (error) {
- console.error("Error getting related memories:", error)
+ console.error("Error getting related memories:", error);
try {
const icon = document.querySelectorAll(
'[id*="sm-chatgpt-input-bar-element-before-composer"]',
- )[0] as HTMLElement
+ )[0] as HTMLElement;
if (icon) {
- updateChatGPTIconFeedback("Error fetching memories", icon)
+ updateChatGPTIconFeedback("Error fetching memories", icon);
}
} catch (feedbackError) {
- console.error("Failed to update error feedback:", feedbackError)
+ console.error("Failed to update error feedback:", feedbackError);
}
}
}
function addSupermemoryButtonToMemoriesDialog() {
- const dialogs = document.querySelectorAll('[role="dialog"]')
- let memoriesDialog: HTMLElement | null = null
+ const dialogs = document.querySelectorAll('[role="dialog"]');
+ let memoriesDialog: HTMLElement | null = null;
for (const dialog of dialogs) {
- const headerText = dialog.querySelector("h2")
+ const headerText = dialog.querySelector("h2");
if (headerText?.textContent?.includes("Saved memories")) {
- memoriesDialog = dialog as HTMLElement
- break
+ memoriesDialog = dialog as HTMLElement;
+ break;
}
}
- if (!memoriesDialog) return
+ if (!memoriesDialog) return;
- if (memoriesDialog.querySelector("#supermemory-save-button")) return
+ if (memoriesDialog.querySelector("#supermemory-save-button")) return;
const deleteAllContainer = memoriesDialog.querySelector(
".mt-5.flex.justify-end",
- )
- if (!deleteAllContainer) return
+ );
+ if (!deleteAllContainer) return;
- const supermemoryButton = document.createElement("button")
- supermemoryButton.id = "supermemory-save-button"
- supermemoryButton.className = "btn relative btn-primary-outline mr-2"
+ const supermemoryButton = document.createElement("button");
+ supermemoryButton.id = "supermemory-save-button";
+ supermemoryButton.className = "btn relative btn-primary-outline mr-2";
- const iconUrl = browser.runtime.getURL("/icon-16.png")
+ const iconUrl = browser.runtime.getURL("/icon-16.png");
supermemoryButton.innerHTML = `
<div class="flex items-center justify-center gap-2">
<img src="${iconUrl}" alt="supermemory" style="width: 16px; height: 16px; flex-shrink: 0; border-radius: 2px;" />
Save to supermemory
</div>
- `
+ `;
supermemoryButton.style.cssText = `
background: #1C2026 !important;
@@ -234,54 +234,54 @@ function addSupermemoryButtonToMemoriesDialog() {
font-size: 14px !important;
margin-right: 8px !important;
cursor: pointer !important;
- `
+ `;
supermemoryButton.addEventListener("mouseenter", () => {
- supermemoryButton.style.backgroundColor = "#2B2E33"
- })
+ supermemoryButton.style.backgroundColor = "#2B2E33";
+ });
supermemoryButton.addEventListener("mouseleave", () => {
- supermemoryButton.style.backgroundColor = "#1C2026"
- })
+ supermemoryButton.style.backgroundColor = "#1C2026";
+ });
supermemoryButton.addEventListener("click", async () => {
- await saveMemoriesToSupermemory()
- })
+ await saveMemoriesToSupermemory();
+ });
deleteAllContainer.insertBefore(
supermemoryButton,
deleteAllContainer.firstChild,
- )
+ );
}
async function saveMemoriesToSupermemory() {
try {
- DOMUtils.showToast("loading")
+ DOMUtils.showToast("loading");
- const memoriesTable = document.querySelector('[role="dialog"] table tbody')
+ const memoriesTable = document.querySelector('[role="dialog"] table tbody');
if (!memoriesTable) {
- DOMUtils.showToast("error")
- return
+ DOMUtils.showToast("error");
+ return;
}
- const memoryRows = memoriesTable.querySelectorAll("tr")
- const memories: string[] = []
+ const memoryRows = memoriesTable.querySelectorAll("tr");
+ const memories: string[] = [];
memoryRows.forEach((row) => {
- const memoryCell = row.querySelector("td .py-2.whitespace-pre-wrap")
+ const memoryCell = row.querySelector("td .py-2.whitespace-pre-wrap");
if (memoryCell?.textContent) {
- memories.push(memoryCell.textContent.trim())
+ memories.push(memoryCell.textContent.trim());
}
- })
+ });
- console.log("Memories:", memories)
+ console.log("Memories:", memories);
if (memories.length === 0) {
- DOMUtils.showToast("error")
- return
+ DOMUtils.showToast("error");
+ return;
}
- const combinedContent = `ChatGPT Saved Memories:\n\n${memories.map((memory, index) => `${index + 1}. ${memory}`).join("\n\n")}`
+ const combinedContent = `ChatGPT Saved Memories:\n\n${memories.map((memory, index) => `${index + 1}. ${memory}`).join("\n\n")}`;
const response = await browser.runtime.sendMessage({
action: MESSAGE_TYPES.SAVE_MEMORY,
@@ -289,18 +289,18 @@ async function saveMemoriesToSupermemory() {
html: combinedContent,
},
actionSource: "chatgpt_memories_dialog",
- })
+ });
- console.log({ response })
+ console.log({ response });
if (response.success) {
- DOMUtils.showToast("success")
+ DOMUtils.showToast("success");
} else {
- DOMUtils.showToast("error")
+ DOMUtils.showToast("error");
}
} catch (error) {
- console.error("Error saving memories to supermemory:", error)
- DOMUtils.showToast("error")
+ console.error("Error saving memories to supermemory:", error);
+ DOMUtils.showToast("error");
}
}
@@ -310,10 +310,10 @@ function updateChatGPTIconFeedback(
resetAfter = 0,
) {
if (!iconElement.dataset.originalHtml) {
- iconElement.dataset.originalHtml = iconElement.innerHTML
+ iconElement.dataset.originalHtml = iconElement.innerHTML;
}
- const feedbackDiv = document.createElement("div")
+ const feedbackDiv = document.createElement("div");
feedbackDiv.style.cssText = `
display: flex;
align-items: center;
@@ -326,15 +326,15 @@ function updateChatGPTIconFeedback(
font-weight: 500;
cursor: ${message === "Included Memories" ? "pointer" : "default"};
position: relative;
- `
+ `;
feedbackDiv.innerHTML = `
<span>✓</span>
<span>${message}</span>
- `
+ `;
if (message === "Included Memories" && iconElement.dataset.memoriesData) {
- const popup = document.createElement("div")
+ const popup = document.createElement("div");
popup.style.cssText = `
position: fixed;
bottom: 80px;
@@ -352,9 +352,9 @@ function updateChatGPTIconFeedback(
z-index: 999999;
display: none;
border: 1px solid #333;
- `
+ `;
- const header = document.createElement("div")
+ const header = document.createElement("div");
header.style.cssText = `
display: flex;
justify-content: space-between;
@@ -362,28 +362,28 @@ function updateChatGPTIconFeedback(
padding: 8px;
border-bottom: 1px solid #333;
opacity: 0.8;
- `
+ `;
header.innerHTML = `
<span style="font-weight: 600; color: #fff;">Included Memories</span>
- `
+ `;
- const content = document.createElement("div")
+ const content = document.createElement("div");
content.style.cssText = `
padding: 0;
max-height: 300px;
overflow-y: auto;
- `
+ `;
- const memoriesText = iconElement.dataset.memoriesData || ""
- console.log("Memories text:", memoriesText)
+ const memoriesText = iconElement.dataset.memoriesData || "";
+ console.log("Memories text:", memoriesText);
const individualMemories = memoriesText
.split(/[,\n]/)
.map((memory) => memory.trim())
- .filter((memory) => memory.length > 0 && memory !== ",")
- console.log("Individual memories:", individualMemories)
+ .filter((memory) => memory.length > 0 && memory !== ",");
+ console.log("Individual memories:", individualMemories);
individualMemories.forEach((memory, index) => {
- const memoryItem = document.createElement("div")
+ const memoryItem = document.createElement("div");
memoryItem.style.cssText = `
display: flex;
align-items: center;
@@ -391,16 +391,16 @@ function updateChatGPTIconFeedback(
padding: 10px;
font-size: 13px;
line-height: 1.4;
- `
+ `;
- const memoryText = document.createElement("div")
+ const memoryText = document.createElement("div");
memoryText.style.cssText = `
flex: 1;
color: #e5e5e5;
- `
- memoryText.textContent = memory.trim()
+ `;
+ memoryText.textContent = memory.trim();
- const removeBtn = document.createElement("button")
+ const removeBtn = document.createElement("button");
removeBtn.style.cssText = `
background: transparent;
color: #9ca3af;
@@ -413,252 +413,255 @@ function updateChatGPTIconFeedback(
display: flex;
align-items: center;
justify-content: center;
- `
- removeBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>`
- removeBtn.dataset.memoryIndex = index.toString()
+ `;
+ removeBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>`;
+ removeBtn.dataset.memoryIndex = index.toString();
removeBtn.addEventListener("mouseenter", () => {
- removeBtn.style.color = "#ef4444"
- })
+ removeBtn.style.color = "#ef4444";
+ });
removeBtn.addEventListener("mouseleave", () => {
- removeBtn.style.color = "#9ca3af"
- })
+ removeBtn.style.color = "#9ca3af";
+ });
- memoryItem.appendChild(memoryText)
- memoryItem.appendChild(removeBtn)
- content.appendChild(memoryItem)
- })
+ memoryItem.appendChild(memoryText);
+ memoryItem.appendChild(removeBtn);
+ content.appendChild(memoryItem);
+ });
- popup.appendChild(header)
- popup.appendChild(content)
- document.body.appendChild(popup)
+ popup.appendChild(header);
+ popup.appendChild(content);
+ document.body.appendChild(popup);
feedbackDiv.addEventListener("mouseenter", () => {
- const textSpan = feedbackDiv.querySelector("span:last-child")
+ const textSpan = feedbackDiv.querySelector("span:last-child");
if (textSpan) {
- textSpan.textContent = "Click to see memories"
+ textSpan.textContent = "Click to see memories";
}
- })
+ });
feedbackDiv.addEventListener("mouseleave", () => {
- const textSpan = feedbackDiv.querySelector("span:last-child")
+ const textSpan = feedbackDiv.querySelector("span:last-child");
if (textSpan) {
- textSpan.textContent = "Included Memories"
+ textSpan.textContent = "Included Memories";
}
- })
+ });
feedbackDiv.addEventListener("click", (e) => {
- e.stopPropagation()
- popup.style.display = "block"
- })
+ e.stopPropagation();
+ popup.style.display = "block";
+ });
document.addEventListener("click", (e) => {
if (!popup.contains(e.target as Node)) {
- popup.style.display = "none"
+ popup.style.display = "none";
}
- })
+ });
content.querySelectorAll("button[data-memory-index]").forEach((button) => {
- const htmlButton = button as HTMLButtonElement
+ const htmlButton = button as HTMLButtonElement;
htmlButton.addEventListener("click", () => {
- const index = Number.parseInt(htmlButton.dataset.memoryIndex || "0", 10)
- const memoryItem = htmlButton.parentElement
+ const index = Number.parseInt(
+ htmlButton.dataset.memoryIndex || "0",
+ 10,
+ );
+ const memoryItem = htmlButton.parentElement;
if (memoryItem) {
- content.removeChild(memoryItem)
+ content.removeChild(memoryItem);
}
const currentMemories = (iconElement.dataset.memoriesData || "")
.split(/[,\n]/)
.map((memory) => memory.trim())
- .filter((memory) => memory.length > 0 && memory !== ",")
- currentMemories.splice(index, 1)
+ .filter((memory) => memory.length > 0 && memory !== ",");
+ currentMemories.splice(index, 1);
- const updatedMemories = currentMemories.join(" ,")
+ const updatedMemories = currentMemories.join(" ,");
- iconElement.dataset.memoriesData = updatedMemories
+ iconElement.dataset.memoriesData = updatedMemories;
- const promptElement = document.getElementById("prompt-textarea")
+ const promptElement = document.getElementById("prompt-textarea");
if (promptElement) {
- promptElement.dataset.supermemories = `<div>Supermemories of user (only for the reference): ${updatedMemories}</div>`
+ promptElement.dataset.supermemories = `<div>Supermemories of user (only for the reference): ${updatedMemories}</div>`;
}
content
.querySelectorAll("button[data-memory-index]")
.forEach((btn, newIndex) => {
- const htmlBtn = btn as HTMLButtonElement
- htmlBtn.dataset.memoryIndex = newIndex.toString()
- })
+ const htmlBtn = btn as HTMLButtonElement;
+ htmlBtn.dataset.memoryIndex = newIndex.toString();
+ });
if (currentMemories.length <= 1) {
if (promptElement?.dataset.supermemories) {
- delete promptElement.dataset.supermemories
- delete iconElement.dataset.memoriesData
- iconElement.innerHTML = iconElement.dataset.originalHtml || ""
- delete iconElement.dataset.originalHtml
+ delete promptElement.dataset.supermemories;
+ delete iconElement.dataset.memoriesData;
+ iconElement.innerHTML = iconElement.dataset.originalHtml || "";
+ delete iconElement.dataset.originalHtml;
}
- popup.style.display = "none"
+ popup.style.display = "none";
if (document.body.contains(popup)) {
- document.body.removeChild(popup)
+ document.body.removeChild(popup);
}
}
- })
- })
+ });
+ });
setTimeout(() => {
if (document.body.contains(popup)) {
- document.body.removeChild(popup)
+ document.body.removeChild(popup);
}
- }, 300000)
+ }, 300000);
}
- iconElement.innerHTML = ""
- iconElement.appendChild(feedbackDiv)
+ iconElement.innerHTML = "";
+ iconElement.appendChild(feedbackDiv);
if (resetAfter > 0) {
setTimeout(() => {
- iconElement.innerHTML = iconElement.dataset.originalHtml || ""
- delete iconElement.dataset.originalHtml
- }, resetAfter)
+ iconElement.innerHTML = iconElement.dataset.originalHtml || "";
+ delete iconElement.dataset.originalHtml;
+ }, resetAfter);
}
}
function addSaveChatGPTElementBeforeComposerBtn() {
- const composerButtons = document.querySelectorAll("button.composer-btn")
+ const composerButtons = document.querySelectorAll("button.composer-btn");
composerButtons.forEach((button) => {
if (button.hasAttribute("data-supermemory-icon-added-before")) {
- return
+ return;
}
- const parent = button.parentElement
- if (!parent) return
+ const parent = button.parentElement;
+ if (!parent) return;
- const parentSiblings = parent.parentElement?.children
- if (!parentSiblings) return
+ const parentSiblings = parent.parentElement?.children;
+ if (!parentSiblings) return;
- let hasSpeechButtonSibling = false
+ let hasSpeechButtonSibling = false;
for (const sibling of parentSiblings) {
if (
sibling.getAttribute("data-testid") ===
"composer-speech-button-container"
) {
- hasSpeechButtonSibling = true
- break
+ hasSpeechButtonSibling = true;
+ break;
}
}
- if (!hasSpeechButtonSibling) return
+ if (!hasSpeechButtonSibling) return;
- const grandParent = parent.parentElement
- if (!grandParent) return
+ const grandParent = parent.parentElement;
+ if (!grandParent) return;
const existingIcon = grandParent.querySelector(
`#${ELEMENT_IDS.CHATGPT_INPUT_BAR_ELEMENT}-before-composer`,
- )
+ );
if (existingIcon) {
- button.setAttribute("data-supermemory-icon-added-before", "true")
- return
+ button.setAttribute("data-supermemory-icon-added-before", "true");
+ return;
}
const saveChatGPTElement = createChatGPTInputBarElement(async () => {
await getRelatedMemoriesForChatGPT(
POSTHOG_EVENT_KEY.CHATGPT_CHAT_MEMORIES_SEARCHED,
- )
- })
+ );
+ });
- saveChatGPTElement.id = `${ELEMENT_IDS.CHATGPT_INPUT_BAR_ELEMENT}-before-composer-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`
+ saveChatGPTElement.id = `${ELEMENT_IDS.CHATGPT_INPUT_BAR_ELEMENT}-before-composer-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
- button.setAttribute("data-supermemory-icon-added-before", "true")
+ button.setAttribute("data-supermemory-icon-added-before", "true");
- grandParent.insertBefore(saveChatGPTElement, parent)
+ grandParent.insertBefore(saveChatGPTElement, parent);
- setupChatGPTAutoFetch()
- })
+ setupChatGPTAutoFetch();
+ });
}
async function setupChatGPTAutoFetch() {
const result = await chrome.storage.local.get([
STORAGE_KEYS.AUTO_SEARCH_ENABLED,
- ])
- const autoSearchEnabled = result[STORAGE_KEYS.AUTO_SEARCH_ENABLED] ?? false
+ ]);
+ const autoSearchEnabled = result[STORAGE_KEYS.AUTO_SEARCH_ENABLED] ?? false;
if (!autoSearchEnabled) {
- return
+ return;
}
- const promptTextarea = document.getElementById("prompt-textarea")
+ const promptTextarea = document.getElementById("prompt-textarea");
if (
!promptTextarea ||
promptTextarea.hasAttribute("data-supermemory-auto-fetch")
) {
- return
+ return;
}
- promptTextarea.setAttribute("data-supermemory-auto-fetch", "true")
+ promptTextarea.setAttribute("data-supermemory-auto-fetch", "true");
const handleInput = () => {
if (chatGPTDebounceTimeout) {
- clearTimeout(chatGPTDebounceTimeout)
+ clearTimeout(chatGPTDebounceTimeout);
}
chatGPTDebounceTimeout = setTimeout(async () => {
- const content = promptTextarea.textContent?.trim() || ""
+ const content = promptTextarea.textContent?.trim() || "";
if (content.length > 2) {
await getRelatedMemoriesForChatGPT(
POSTHOG_EVENT_KEY.CHATGPT_CHAT_MEMORIES_AUTO_SEARCHED,
- )
+ );
} else if (content.length === 0) {
const icons = document.querySelectorAll(
'[id*="sm-chatgpt-input-bar-element-before-composer"]',
- )
+ );
icons.forEach((icon) => {
- const iconElement = icon as HTMLElement
+ const iconElement = icon as HTMLElement;
if (iconElement.dataset.originalHtml) {
- iconElement.innerHTML = iconElement.dataset.originalHtml
- delete iconElement.dataset.originalHtml
- delete iconElement.dataset.memoriesData
+ iconElement.innerHTML = iconElement.dataset.originalHtml;
+ delete iconElement.dataset.originalHtml;
+ delete iconElement.dataset.memoriesData;
}
- })
+ });
if (promptTextarea.dataset.supermemories) {
- delete promptTextarea.dataset.supermemories
+ delete promptTextarea.dataset.supermemories;
}
}
- }, UI_CONFIG.AUTO_SEARCH_DEBOUNCE_DELAY)
- }
+ }, UI_CONFIG.AUTO_SEARCH_DEBOUNCE_DELAY);
+ };
- promptTextarea.addEventListener("input", handleInput)
+ promptTextarea.addEventListener("input", handleInput);
}
function setupChatGPTPromptCapture() {
if (document.body.hasAttribute("data-chatgpt-prompt-capture-setup")) {
- return
+ return;
}
- document.body.setAttribute("data-chatgpt-prompt-capture-setup", "true")
+ document.body.setAttribute("data-chatgpt-prompt-capture-setup", "true");
const capturePromptContent = async (source: string) => {
- const promptTextarea = document.getElementById("prompt-textarea")
+ const promptTextarea = document.getElementById("prompt-textarea");
- let promptContent = ""
+ let promptContent = "";
if (promptTextarea) {
- promptContent = promptTextarea.textContent || ""
+ promptContent = promptTextarea.textContent || "";
}
- const storedMemories = promptTextarea?.dataset.supermemories
+ const storedMemories = promptTextarea?.dataset.supermemories;
if (
storedMemories &&
promptTextarea &&
!promptContent.includes("Supermemories of user")
) {
- promptTextarea.innerHTML = `${promptTextarea.innerHTML} ${storedMemories}`
- promptContent = promptTextarea.textContent || ""
+ promptTextarea.innerHTML = `${promptTextarea.innerHTML} ${storedMemories}`;
+ promptContent = promptTextarea.textContent || "";
}
if (promptTextarea && promptContent.trim()) {
- console.log(`ChatGPT prompt submitted via ${source}:`, promptContent)
+ console.log(`ChatGPT prompt submitted via ${source}:`, promptContent);
try {
await browser.runtime.sendMessage({
@@ -668,57 +671,57 @@ function setupChatGPTPromptCapture() {
platform: "chatgpt",
source: source,
},
- })
+ });
} catch (error) {
- console.error("Error sending ChatGPT prompt to background:", error)
+ console.error("Error sending ChatGPT prompt to background:", error);
}
}
const icons = document.querySelectorAll(
'[id*="sm-chatgpt-input-bar-element-before-composer"]',
- )
+ );
icons.forEach((icon) => {
- const iconElement = icon as HTMLElement
+ const iconElement = icon as HTMLElement;
if (iconElement.dataset.originalHtml) {
- iconElement.innerHTML = iconElement.dataset.originalHtml
- delete iconElement.dataset.originalHtml
- delete iconElement.dataset.memoriesData
+ iconElement.innerHTML = iconElement.dataset.originalHtml;
+ delete iconElement.dataset.originalHtml;
+ delete iconElement.dataset.memoriesData;
}
- })
+ });
if (promptTextarea?.dataset.supermemories) {
- delete promptTextarea.dataset.supermemories
+ delete promptTextarea.dataset.supermemories;
}
- }
+ };
document.addEventListener(
"click",
async (event) => {
- const target = event.target as HTMLElement
+ const target = event.target as HTMLElement;
if (
target.id === "composer-submit-button" ||
target.closest("#composer-submit-button")
) {
- await capturePromptContent("button click")
+ await capturePromptContent("button click");
}
},
true,
- )
+ );
document.addEventListener(
"keydown",
async (event) => {
- const target = event.target as HTMLElement
+ const target = event.target as HTMLElement;
if (
target.id === "prompt-textarea" &&
event.key === "Enter" &&
!event.shiftKey
) {
- await capturePromptContent("Enter key")
+ await capturePromptContent("Enter key");
}
},
true,
- )
+ );
}
diff --git a/apps/browser-extension/entrypoints/content/claude.ts b/apps/browser-extension/entrypoints/content/claude.ts
index e0853d41..e5832bf7 100644
--- a/apps/browser-extension/entrypoints/content/claude.ts
+++ b/apps/browser-extension/entrypoints/content/claude.ts
@@ -5,210 +5,210 @@ import {
POSTHOG_EVENT_KEY,
STORAGE_KEYS,
UI_CONFIG,
-} from "../../utils/constants"
+} from "../../utils/constants";
import {
createClaudeInputBarElement,
DOMUtils,
-} from "../../utils/ui-components"
+} from "../../utils/ui-components";
-let claudeDebounceTimeout: NodeJS.Timeout | null = null
-let claudeRouteObserver: MutationObserver | null = null
-let claudeUrlCheckInterval: NodeJS.Timeout | null = null
-let claudeObserverThrottle: NodeJS.Timeout | null = null
+let claudeDebounceTimeout: NodeJS.Timeout | null = null;
+let claudeRouteObserver: MutationObserver | null = null;
+let claudeUrlCheckInterval: NodeJS.Timeout | null = null;
+let claudeObserverThrottle: NodeJS.Timeout | null = null;
export function initializeClaude() {
if (!DOMUtils.isOnDomain(DOMAINS.CLAUDE)) {
- return
+ return;
}
if (document.body.hasAttribute("data-claude-initialized")) {
- return
+ return;
}
setTimeout(() => {
- addSupermemoryIconToClaudeInput()
- setupClaudeAutoFetch()
- }, 2000)
+ addSupermemoryIconToClaudeInput();
+ setupClaudeAutoFetch();
+ }, 2000);
- setupClaudePromptCapture()
+ setupClaudePromptCapture();
- setupClaudeRouteChangeDetection()
+ setupClaudeRouteChangeDetection();
- document.body.setAttribute("data-claude-initialized", "true")
+ document.body.setAttribute("data-claude-initialized", "true");
}
function setupClaudeRouteChangeDetection() {
if (claudeRouteObserver) {
- claudeRouteObserver.disconnect()
+ claudeRouteObserver.disconnect();
}
if (claudeUrlCheckInterval) {
- clearInterval(claudeUrlCheckInterval)
+ clearInterval(claudeUrlCheckInterval);
}
if (claudeObserverThrottle) {
- clearTimeout(claudeObserverThrottle)
- claudeObserverThrottle = null
+ clearTimeout(claudeObserverThrottle);
+ claudeObserverThrottle = null;
}
- let currentUrl = window.location.href
+ let currentUrl = window.location.href;
const checkForRouteChange = () => {
if (window.location.href !== currentUrl) {
- currentUrl = window.location.href
- console.log("Claude route changed, re-adding supermemory icon")
+ currentUrl = window.location.href;
+ console.log("Claude route changed, re-adding supermemory icon");
setTimeout(() => {
- addSupermemoryIconToClaudeInput()
- setupClaudeAutoFetch()
- }, 1000)
+ addSupermemoryIconToClaudeInput();
+ setupClaudeAutoFetch();
+ }, 1000);
}
- }
+ };
- claudeUrlCheckInterval = setInterval(checkForRouteChange, 2000)
+ claudeUrlCheckInterval = setInterval(checkForRouteChange, 2000);
claudeRouteObserver = new MutationObserver((mutations) => {
if (claudeObserverThrottle) {
- return
+ return;
}
- let shouldRecheck = false
+ let shouldRecheck = false;
mutations.forEach((mutation) => {
if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
- const element = node as Element
+ const element = node as Element;
if (
element.querySelector?.('div[contenteditable="true"]') ||
element.querySelector?.("textarea") ||
element.matches?.('div[contenteditable="true"]') ||
element.matches?.("textarea")
) {
- shouldRecheck = true
+ shouldRecheck = true;
}
}
- })
+ });
}
- })
+ });
if (shouldRecheck) {
claudeObserverThrottle = setTimeout(() => {
try {
- claudeObserverThrottle = null
- addSupermemoryIconToClaudeInput()
- setupClaudeAutoFetch()
+ claudeObserverThrottle = null;
+ addSupermemoryIconToClaudeInput();
+ setupClaudeAutoFetch();
} catch (error) {
- console.error("Error in Claude observer callback:", error)
+ console.error("Error in Claude observer callback:", error);
}
- }, 300)
+ }, 300);
}
- })
+ });
try {
claudeRouteObserver.observe(document.body, {
childList: true,
subtree: true,
- })
+ });
} catch (error) {
- console.error("Failed to set up Claude route observer:", error)
+ console.error("Failed to set up Claude route observer:", error);
if (claudeUrlCheckInterval) {
- clearInterval(claudeUrlCheckInterval)
+ clearInterval(claudeUrlCheckInterval);
}
- claudeUrlCheckInterval = setInterval(checkForRouteChange, 1000)
+ claudeUrlCheckInterval = setInterval(checkForRouteChange, 1000);
}
}
function addSupermemoryIconToClaudeInput() {
const targetContainers = document.querySelectorAll(
".relative.flex-1.flex.items-center.gap-2.shrink.min-w-0",
- )
+ );
targetContainers.forEach((container) => {
if (container.hasAttribute("data-supermemory-icon-added")) {
- return
+ return;
}
const existingIcon = container.querySelector(
`#${ELEMENT_IDS.CLAUDE_INPUT_BAR_ELEMENT}`,
- )
+ );
if (existingIcon) {
- container.setAttribute("data-supermemory-icon-added", "true")
- return
+ container.setAttribute("data-supermemory-icon-added", "true");
+ return;
}
const supermemoryIcon = createClaudeInputBarElement(async () => {
await getRelatedMemoriesForClaude(
POSTHOG_EVENT_KEY.CLAUDE_CHAT_MEMORIES_SEARCHED,
- )
- })
+ );
+ });
- supermemoryIcon.id = `${ELEMENT_IDS.CLAUDE_INPUT_BAR_ELEMENT}-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`
+ supermemoryIcon.id = `${ELEMENT_IDS.CLAUDE_INPUT_BAR_ELEMENT}-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
- container.setAttribute("data-supermemory-icon-added", "true")
+ container.setAttribute("data-supermemory-icon-added", "true");
- container.insertBefore(supermemoryIcon, container.firstChild)
- })
+ container.insertBefore(supermemoryIcon, container.firstChild);
+ });
}
async function getRelatedMemoriesForClaude(actionSource: string) {
try {
- let userQuery = ""
+ let userQuery = "";
const supermemoryContainer = document.querySelector(
'[data-supermemory-icon-added="true"]',
- )
+ );
if (supermemoryContainer?.parentElement?.previousElementSibling) {
const pTag =
supermemoryContainer.parentElement.previousElementSibling.querySelector(
"p",
- )
- userQuery = pTag?.innerText || pTag?.textContent || ""
+ );
+ userQuery = pTag?.innerText || pTag?.textContent || "";
}
if (!userQuery.trim()) {
const textareaElement = document.querySelector(
'div[contenteditable="true"]',
- ) as HTMLElement
+ ) as HTMLElement;
userQuery =
- textareaElement?.innerText || textareaElement?.textContent || ""
+ textareaElement?.innerText || textareaElement?.textContent || "";
}
if (!userQuery.trim()) {
const inputElements = document.querySelectorAll(
'div[contenteditable="true"], textarea, input[type="text"]',
- )
+ );
for (const element of inputElements) {
const text =
(element as HTMLElement).innerText ||
- (element as HTMLInputElement).value
+ (element as HTMLInputElement).value;
if (text?.trim()) {
- userQuery = text.trim()
- break
+ userQuery = text.trim();
+ break;
}
}
}
- console.log("Claude query extracted:", userQuery)
+ console.log("Claude query extracted:", userQuery);
if (!userQuery.trim()) {
- console.log("No query text found for Claude")
- return
+ console.log("No query text found for Claude");
+ return;
}
- const icon = document.querySelector('[id*="sm-claude-input-bar-element"]')
+ const icon = document.querySelector('[id*="sm-claude-input-bar-element"]');
- const iconElement = icon as HTMLElement
+ const iconElement = icon as HTMLElement;
if (!iconElement) {
- console.warn("Claude icon element not found, cannot update feedback")
- return
+ console.warn("Claude icon element not found, cannot update feedback");
+ return;
}
- updateClaudeIconFeedback("Searching memories...", iconElement)
+ updateClaudeIconFeedback("Searching memories...", iconElement);
const timeoutPromise = new Promise((_, reject) =>
setTimeout(
() => reject(new Error("Memory search timeout")),
UI_CONFIG.API_REQUEST_TIMEOUT,
),
- )
+ );
const response = await Promise.race([
browser.runtime.sendMessage({
@@ -217,46 +217,46 @@ async function getRelatedMemoriesForClaude(actionSource: string) {
actionSource: actionSource,
}),
timeoutPromise,
- ])
+ ]);
- console.log("Claude memories response:", response)
+ console.log("Claude memories response:", response);
if (response?.success && response?.data) {
const textareaElement = document.querySelector(
'div[contenteditable="true"]',
- ) as HTMLElement
+ ) as HTMLElement;
if (textareaElement) {
- textareaElement.dataset.supermemories = `<div>Supermemories of user (only for the reference): ${response.data}</div>`
+ textareaElement.dataset.supermemories = `<div>Supermemories of user (only for the reference): ${response.data}</div>`;
console.log(
"Text element dataset:",
textareaElement.dataset.supermemories,
- )
+ );
- iconElement.dataset.memoriesData = response.data
+ iconElement.dataset.memoriesData = response.data;
- updateClaudeIconFeedback("Included Memories", iconElement)
+ updateClaudeIconFeedback("Included Memories", iconElement);
} else {
console.warn(
"Claude input area not found after successful memory fetch",
- )
- updateClaudeIconFeedback("Memories found", iconElement)
+ );
+ updateClaudeIconFeedback("Memories found", iconElement);
}
} else {
- console.warn("No memories found or API response invalid for Claude")
- updateClaudeIconFeedback("No memories found", iconElement)
+ console.warn("No memories found or API response invalid for Claude");
+ updateClaudeIconFeedback("No memories found", iconElement);
}
} catch (error) {
- console.error("Error getting related memories for Claude:", error)
+ console.error("Error getting related memories for Claude:", error);
try {
const icon = document.querySelector(
'[id*="sm-claude-input-bar-element"]',
- ) as HTMLElement
+ ) as HTMLElement;
if (icon) {
- updateClaudeIconFeedback("Error fetching memories", icon)
+ updateClaudeIconFeedback("Error fetching memories", icon);
}
} catch (feedbackError) {
- console.error("Failed to update Claude error feedback:", feedbackError)
+ console.error("Failed to update Claude error feedback:", feedbackError);
}
}
}
@@ -267,10 +267,10 @@ function updateClaudeIconFeedback(
resetAfter = 0,
) {
if (!iconElement.dataset.originalHtml) {
- iconElement.dataset.originalHtml = iconElement.innerHTML
+ iconElement.dataset.originalHtml = iconElement.innerHTML;
}
- const feedbackDiv = document.createElement("div")
+ const feedbackDiv = document.createElement("div");
feedbackDiv.style.cssText = `
display: flex;
align-items: center;
@@ -283,15 +283,15 @@ function updateClaudeIconFeedback(
font-weight: 500;
cursor: ${message === "Included Memories" ? "pointer" : "default"};
position: relative;
- `
+ `;
feedbackDiv.innerHTML = `
<span>✓</span>
<span>${message}</span>
- `
+ `;
if (message === "Included Memories" && iconElement.dataset.memoriesData) {
- const popup = document.createElement("div")
+ const popup = document.createElement("div");
popup.style.cssText = `
position: fixed;
bottom: 80px;
@@ -309,9 +309,9 @@ function updateClaudeIconFeedback(
z-index: 999999;
display: none;
border: 1px solid #333;
- `
+ `;
- const header = document.createElement("div")
+ const header = document.createElement("div");
header.style.cssText = `
display: flex;
justify-content: space-between;
@@ -319,28 +319,28 @@ function updateClaudeIconFeedback(
padding: 8px;
border-bottom: 1px solid #333;
opacity: 0.8;
- `
+ `;
header.innerHTML = `
<span style="font-weight: 600; color: #fff;">Included Memories</span>
- `
+ `;
- const content = document.createElement("div")
+ const content = document.createElement("div");
content.style.cssText = `
padding: 0;
max-height: 300px;
overflow-y: auto;
- `
+ `;
- const memoriesText = iconElement.dataset.memoriesData || ""
- console.log("Memories text:", memoriesText)
+ const memoriesText = iconElement.dataset.memoriesData || "";
+ console.log("Memories text:", memoriesText);
const individualMemories = memoriesText
.split(/[,\n]/)
.map((memory) => memory.trim())
- .filter((memory) => memory.length > 0 && memory !== ",")
- console.log("Individual memories:", individualMemories)
+ .filter((memory) => memory.length > 0 && memory !== ",");
+ console.log("Individual memories:", individualMemories);
individualMemories.forEach((memory, index) => {
- const memoryItem = document.createElement("div")
+ const memoryItem = document.createElement("div");
memoryItem.style.cssText = `
display: flex;
align-items: center;
@@ -348,16 +348,16 @@ function updateClaudeIconFeedback(
padding: 10px;
font-size: 13px;
line-height: 1.4;
- `
+ `;
- const memoryText = document.createElement("div")
+ const memoryText = document.createElement("div");
memoryText.style.cssText = `
flex: 1;
color: #e5e5e5;
- `
- memoryText.textContent = memory.trim()
+ `;
+ memoryText.textContent = memory.trim();
- const removeBtn = document.createElement("button")
+ const removeBtn = document.createElement("button");
removeBtn.style.cssText = `
background: transparent;
color: #9ca3af;
@@ -370,154 +370,159 @@ function updateClaudeIconFeedback(
display: flex;
align-items: center;
justify-content: center;
- `
- removeBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>`
- removeBtn.dataset.memoryIndex = index.toString()
+ `;
+ removeBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>`;
+ removeBtn.dataset.memoryIndex = index.toString();
removeBtn.addEventListener("mouseenter", () => {
- removeBtn.style.color = "#ef4444"
- })
+ removeBtn.style.color = "#ef4444";
+ });
removeBtn.addEventListener("mouseleave", () => {
- removeBtn.style.color = "#9ca3af"
- })
+ removeBtn.style.color = "#9ca3af";
+ });
- memoryItem.appendChild(memoryText)
- memoryItem.appendChild(removeBtn)
- content.appendChild(memoryItem)
- })
+ memoryItem.appendChild(memoryText);
+ memoryItem.appendChild(removeBtn);
+ content.appendChild(memoryItem);
+ });
- popup.appendChild(header)
- popup.appendChild(content)
- document.body.appendChild(popup)
+ popup.appendChild(header);
+ popup.appendChild(content);
+ document.body.appendChild(popup);
feedbackDiv.addEventListener("mouseenter", () => {
- const textSpan = feedbackDiv.querySelector("span:last-child")
+ const textSpan = feedbackDiv.querySelector("span:last-child");
if (textSpan) {
- textSpan.textContent = "Click to see memories"
+ textSpan.textContent = "Click to see memories";
}
- })
+ });
feedbackDiv.addEventListener("mouseleave", () => {
- const textSpan = feedbackDiv.querySelector("span:last-child")
+ const textSpan = feedbackDiv.querySelector("span:last-child");
if (textSpan) {
- textSpan.textContent = "Included Memories"
+ textSpan.textContent = "Included Memories";
}
- })
+ });
feedbackDiv.addEventListener("click", (e) => {
- e.stopPropagation()
- popup.style.display = "block"
- })
+ e.stopPropagation();
+ popup.style.display = "block";
+ });
document.addEventListener("click", (e) => {
if (!popup.contains(e.target as Node)) {
- popup.style.display = "none"
+ popup.style.display = "none";
}
- })
+ });
content.querySelectorAll("button[data-memory-index]").forEach((button) => {
- const htmlButton = button as HTMLButtonElement
+ const htmlButton = button as HTMLButtonElement;
htmlButton.addEventListener("click", () => {
- const index = Number.parseInt(htmlButton.dataset.memoryIndex || "0", 10)
- const memoryItem = htmlButton.parentElement
+ const index = Number.parseInt(
+ htmlButton.dataset.memoryIndex || "0",
+ 10,
+ );
+ const memoryItem = htmlButton.parentElement;
if (memoryItem) {
- content.removeChild(memoryItem)
+ content.removeChild(memoryItem);
}
const currentMemories = (iconElement.dataset.memoriesData || "")
.split(/[,\n]/)
.map((memory) => memory.trim())
- .filter((memory) => memory.length > 0 && memory !== ",")
- currentMemories.splice(index, 1)
+ .filter((memory) => memory.length > 0 && memory !== ",");
+ currentMemories.splice(index, 1);
- const updatedMemories = currentMemories.join(" ,")
+ const updatedMemories = currentMemories.join(" ,");
- iconElement.dataset.memoriesData = updatedMemories
+ iconElement.dataset.memoriesData = updatedMemories;
const textareaElement = document.querySelector(
'div[contenteditable="true"]',
- ) as HTMLElement
+ ) as HTMLElement;
if (textareaElement) {
- textareaElement.dataset.supermemories = `<div>Supermemories of user (only for the reference): ${updatedMemories}</div>`
+ textareaElement.dataset.supermemories = `<div>Supermemories of user (only for the reference): ${updatedMemories}</div>`;
}
content
.querySelectorAll("button[data-memory-index]")
.forEach((btn, newIndex) => {
- const htmlBtn = btn as HTMLButtonElement
- htmlBtn.dataset.memoryIndex = newIndex.toString()
- })
+ const htmlBtn = btn as HTMLButtonElement;
+ htmlBtn.dataset.memoryIndex = newIndex.toString();
+ });
if (currentMemories.length <= 1) {
if (textareaElement?.dataset.supermemories) {
- delete textareaElement.dataset.supermemories
- delete iconElement.dataset.memoriesData
- iconElement.innerHTML = iconElement.dataset.originalHtml || ""
- delete iconElement.dataset.originalHtml
+ delete textareaElement.dataset.supermemories;
+ delete iconElement.dataset.memoriesData;
+ iconElement.innerHTML = iconElement.dataset.originalHtml || "";
+ delete iconElement.dataset.originalHtml;
}
- popup.style.display = "none"
+ popup.style.display = "none";
if (document.body.contains(popup)) {
- document.body.removeChild(popup)
+ document.body.removeChild(popup);
}
}
- })
- })
+ });
+ });
setTimeout(() => {
if (document.body.contains(popup)) {
- document.body.removeChild(popup)
+ document.body.removeChild(popup);
}
- }, 300000)
+ }, 300000);
}
- iconElement.innerHTML = ""
- iconElement.appendChild(feedbackDiv)
+ iconElement.innerHTML = "";
+ iconElement.appendChild(feedbackDiv);
if (resetAfter > 0) {
setTimeout(() => {
- iconElement.innerHTML = iconElement.dataset.originalHtml || ""
- delete iconElement.dataset.originalHtml
- }, resetAfter)
+ iconElement.innerHTML = iconElement.dataset.originalHtml || "";
+ delete iconElement.dataset.originalHtml;
+ }, resetAfter);
}
}
function setupClaudePromptCapture() {
if (document.body.hasAttribute("data-claude-prompt-capture-setup")) {
- return
+ return;
}
- document.body.setAttribute("data-claude-prompt-capture-setup", "true")
+ document.body.setAttribute("data-claude-prompt-capture-setup", "true");
const captureClaudePromptContent = async (source: string) => {
- let promptContent = ""
+ let promptContent = "";
const contentEditableDiv = document.querySelector(
'div[contenteditable="true"]',
- ) as HTMLElement
+ ) as HTMLElement;
if (contentEditableDiv) {
promptContent =
- contentEditableDiv.textContent || contentEditableDiv.innerText || ""
+ contentEditableDiv.textContent || contentEditableDiv.innerText || "";
}
if (!promptContent) {
- const textarea = document.querySelector("textarea") as HTMLTextAreaElement
+ const textarea = document.querySelector(
+ "textarea",
+ ) as HTMLTextAreaElement;
if (textarea) {
- promptContent = textarea.value || ""
+ promptContent = textarea.value || "";
}
}
- const storedMemories = contentEditableDiv?.dataset.supermemories
+ const storedMemories = contentEditableDiv?.dataset.supermemories;
if (
storedMemories &&
contentEditableDiv &&
!promptContent.includes("Supermemories of user")
) {
- contentEditableDiv.innerHTML = `${contentEditableDiv.innerHTML} ${storedMemories}`
+ contentEditableDiv.innerHTML = `${contentEditableDiv.innerHTML} ${storedMemories}`;
promptContent =
- contentEditableDiv.textContent || contentEditableDiv.innerText || ""
+ contentEditableDiv.textContent || contentEditableDiv.innerText || "";
}
if (promptContent.trim()) {
- console.log(`Claude prompt submitted via ${source}:`, promptContent)
+ console.log(`Claude prompt submitted via ${source}:`, promptContent);
try {
await browser.runtime.sendMessage({
@@ -527,52 +532,52 @@ function setupClaudePromptCapture() {
platform: "claude",
source: source,
},
- })
+ });
} catch (error) {
- console.error("Error sending Claude prompt to background:", error)
+ console.error("Error sending Claude prompt to background:", error);
}
}
const icons = document.querySelectorAll(
'[id*="sm-claude-input-bar-element"]',
- )
+ );
icons.forEach((icon) => {
- const iconElement = icon as HTMLElement
+ const iconElement = icon as HTMLElement;
if (iconElement.dataset.originalHtml) {
- iconElement.innerHTML = iconElement.dataset.originalHtml
- delete iconElement.dataset.originalHtml
- delete iconElement.dataset.memoriesData
+ iconElement.innerHTML = iconElement.dataset.originalHtml;
+ delete iconElement.dataset.originalHtml;
+ delete iconElement.dataset.memoriesData;
}
- })
+ });
if (contentEditableDiv?.dataset.supermemories) {
- delete contentEditableDiv.dataset.supermemories
+ delete contentEditableDiv.dataset.supermemories;
}
- }
+ };
document.addEventListener(
"click",
async (event) => {
- const target = event.target as HTMLElement
+ const target = event.target as HTMLElement;
const sendButton =
target.closest(
"button.inline-flex.items-center.justify-center.relative.shrink-0.can-focus.select-none",
) ||
target.closest('button[class*="bg-accent-main-000"]') ||
- target.closest('button[class*="rounded-lg"]')
+ target.closest('button[class*="rounded-lg"]');
if (sendButton) {
- await captureClaudePromptContent("button click")
+ await captureClaudePromptContent("button click");
}
},
true,
- )
+ );
document.addEventListener(
"keydown",
async (event) => {
- const target = event.target as HTMLElement
+ const target = event.target as HTMLElement;
if (
(target.matches('div[contenteditable="true"]') ||
@@ -582,67 +587,67 @@ function setupClaudePromptCapture() {
event.key === "Enter" &&
!event.shiftKey
) {
- await captureClaudePromptContent("Enter key")
+ await captureClaudePromptContent("Enter key");
}
},
true,
- )
+ );
}
async function setupClaudeAutoFetch() {
const result = await chrome.storage.local.get([
STORAGE_KEYS.AUTO_SEARCH_ENABLED,
- ])
- const autoSearchEnabled = result[STORAGE_KEYS.AUTO_SEARCH_ENABLED] ?? false
+ ]);
+ const autoSearchEnabled = result[STORAGE_KEYS.AUTO_SEARCH_ENABLED] ?? false;
if (!autoSearchEnabled) {
- return
+ return;
}
const textareaElement = document.querySelector(
'div[contenteditable="true"]',
- ) as HTMLElement
+ ) as HTMLElement;
if (
!textareaElement ||
textareaElement.hasAttribute("data-supermemory-auto-fetch")
) {
- return
+ return;
}
- textareaElement.setAttribute("data-supermemory-auto-fetch", "true")
+ textareaElement.setAttribute("data-supermemory-auto-fetch", "true");
const handleInput = () => {
if (claudeDebounceTimeout) {
- clearTimeout(claudeDebounceTimeout)
+ clearTimeout(claudeDebounceTimeout);
}
claudeDebounceTimeout = setTimeout(async () => {
- const content = textareaElement.textContent?.trim() || ""
+ const content = textareaElement.textContent?.trim() || "";
if (content.length > 2) {
await getRelatedMemoriesForClaude(
POSTHOG_EVENT_KEY.CLAUDE_CHAT_MEMORIES_AUTO_SEARCHED,
- )
+ );
} else if (content.length === 0) {
const icons = document.querySelectorAll(
'[id*="sm-claude-input-bar-element"]',
- )
+ );
icons.forEach((icon) => {
- const iconElement = icon as HTMLElement
+ const iconElement = icon as HTMLElement;
if (iconElement.dataset.originalHtml) {
- iconElement.innerHTML = iconElement.dataset.originalHtml
- delete iconElement.dataset.originalHtml
- delete iconElement.dataset.memoriesData
+ iconElement.innerHTML = iconElement.dataset.originalHtml;
+ delete iconElement.dataset.originalHtml;
+ delete iconElement.dataset.memoriesData;
}
- })
+ });
if (textareaElement.dataset.supermemories) {
- delete textareaElement.dataset.supermemories
+ delete textareaElement.dataset.supermemories;
}
}
- }, UI_CONFIG.AUTO_SEARCH_DEBOUNCE_DELAY)
- }
+ }, UI_CONFIG.AUTO_SEARCH_DEBOUNCE_DELAY);
+ };
- textareaElement.addEventListener("input", handleInput)
+ textareaElement.addEventListener("input", handleInput);
}
diff --git a/apps/browser-extension/entrypoints/content/index.ts b/apps/browser-extension/entrypoints/content/index.ts
index a79f50fb..829c2fa9 100644
--- a/apps/browser-extension/entrypoints/content/index.ts
+++ b/apps/browser-extension/entrypoints/content/index.ts
@@ -1,10 +1,18 @@
-import { DOMAINS, MESSAGE_TYPES } from "../../utils/constants"
-import { DOMUtils } from "../../utils/ui-components"
-import { initializeChatGPT } from "./chatgpt"
-import { initializeClaude } from "./claude"
-import { saveMemory, setupGlobalKeyboardShortcut, setupStorageListener } from "./shared"
-import { initializeT3 } from "./t3"
-import { handleTwitterNavigation, initializeTwitter, updateTwitterImportUI } from "./twitter"
+import { DOMAINS, MESSAGE_TYPES } from "../../utils/constants";
+import { DOMUtils } from "../../utils/ui-components";
+import { initializeChatGPT } from "./chatgpt";
+import { initializeClaude } from "./claude";
+import {
+ saveMemory,
+ setupGlobalKeyboardShortcut,
+ setupStorageListener,
+} from "./shared";
+import { initializeT3 } from "./t3";
+import {
+ handleTwitterNavigation,
+ initializeTwitter,
+ updateTwitterImportUI,
+} from "./twitter";
export default defineContentScript({
matches: ["<all_urls>"],
@@ -12,56 +20,56 @@ export default defineContentScript({
// Setup global event listeners
browser.runtime.onMessage.addListener(async (message) => {
if (message.action === MESSAGE_TYPES.SHOW_TOAST) {
- DOMUtils.showToast(message.state)
+ DOMUtils.showToast(message.state);
} else if (message.action === MESSAGE_TYPES.SAVE_MEMORY) {
- await saveMemory()
+ await saveMemory();
} else if (message.type === MESSAGE_TYPES.IMPORT_UPDATE) {
- updateTwitterImportUI(message)
+ updateTwitterImportUI(message);
} else if (message.type === MESSAGE_TYPES.IMPORT_DONE) {
- updateTwitterImportUI(message)
+ updateTwitterImportUI(message);
}
- })
+ });
// Setup global keyboard shortcuts
- setupGlobalKeyboardShortcut()
+ setupGlobalKeyboardShortcut();
// Setup storage listener
- setupStorageListener()
+ setupStorageListener();
// Observer for dynamic content changes
const observeForDynamicChanges = () => {
const observer = new MutationObserver(() => {
if (DOMUtils.isOnDomain(DOMAINS.CHATGPT)) {
- initializeChatGPT()
+ initializeChatGPT();
}
if (DOMUtils.isOnDomain(DOMAINS.CLAUDE)) {
- initializeClaude()
+ initializeClaude();
}
if (DOMUtils.isOnDomain(DOMAINS.T3)) {
- initializeT3()
+ initializeT3();
}
if (DOMUtils.isOnDomain(DOMAINS.TWITTER)) {
- handleTwitterNavigation()
+ handleTwitterNavigation();
}
- })
+ });
observer.observe(document.body, {
childList: true,
subtree: true,
- })
- }
+ });
+ };
// Initialize platform-specific functionality
- initializeChatGPT()
- initializeClaude()
- initializeT3()
- initializeTwitter()
+ initializeChatGPT();
+ initializeClaude();
+ initializeT3();
+ initializeTwitter();
// Start observing for dynamic changes
if (document.readyState === "loading") {
- document.addEventListener("DOMContentLoaded", observeForDynamicChanges)
+ document.addEventListener("DOMContentLoaded", observeForDynamicChanges);
} else {
- observeForDynamicChanges()
+ observeForDynamicChanges();
}
},
-}) \ No newline at end of file
+});
diff --git a/apps/browser-extension/entrypoints/content/shared.ts b/apps/browser-extension/entrypoints/content/shared.ts
index d8b665c5..8c6aae65 100644
--- a/apps/browser-extension/entrypoints/content/shared.ts
+++ b/apps/browser-extension/entrypoints/content/shared.ts
@@ -1,13 +1,13 @@
-import { MESSAGE_TYPES, STORAGE_KEYS } from "../../utils/constants"
-import { DOMUtils } from "../../utils/ui-components"
+import { MESSAGE_TYPES, STORAGE_KEYS } from "../../utils/constants";
+import { DOMUtils } from "../../utils/ui-components";
export async function saveMemory() {
try {
- DOMUtils.showToast("loading")
+ DOMUtils.showToast("loading");
- const highlightedText = window.getSelection()?.toString() || ""
- const url = window.location.href
- const html = document.documentElement.outerHTML
+ const highlightedText = window.getSelection()?.toString() || "";
+ const url = window.location.href;
+ const html = document.documentElement.outerHTML;
const response = await browser.runtime.sendMessage({
action: MESSAGE_TYPES.SAVE_MEMORY,
@@ -17,17 +17,17 @@ export async function saveMemory() {
url,
},
actionSource: "context_menu",
- })
+ });
- console.log("Response from enxtension:", response)
+ console.log("Response from enxtension:", response);
if (response.success) {
- DOMUtils.showToast("success")
+ DOMUtils.showToast("success");
} else {
- DOMUtils.showToast("error")
+ DOMUtils.showToast("error");
}
} catch (error) {
- console.error("Error saving memory:", error)
- DOMUtils.showToast("error")
+ console.error("Error saving memory:", error);
+ DOMUtils.showToast("error");
}
}
@@ -38,19 +38,19 @@ export function setupGlobalKeyboardShortcut() {
event.shiftKey &&
event.key === "m"
) {
- event.preventDefault()
- await saveMemory()
+ event.preventDefault();
+ await saveMemory();
}
- })
+ });
}
export function setupStorageListener() {
window.addEventListener("message", (event) => {
if (event.source !== window) {
- return
+ return;
}
- const bearerToken = event.data.token
- const userData = event.data.userData
+ const bearerToken = event.data.token;
+ const userData = event.data.userData;
if (bearerToken && userData) {
if (
!(
@@ -61,8 +61,8 @@ export function setupStorageListener() {
) {
console.log(
"Bearer token and user data is only allowed to be used on localhost or supermemory.ai",
- )
- return
+ );
+ return;
}
chrome.storage.local.set(
@@ -71,7 +71,7 @@ export function setupStorageListener() {
[STORAGE_KEYS.USER_DATA]: userData,
},
() => {},
- )
+ );
}
- })
-} \ No newline at end of file
+ });
+}
diff --git a/apps/browser-extension/entrypoints/content/t3.ts b/apps/browser-extension/entrypoints/content/t3.ts
index 4332076e..d630ffe5 100644
--- a/apps/browser-extension/entrypoints/content/t3.ts
+++ b/apps/browser-extension/entrypoints/content/t3.ts
@@ -5,204 +5,206 @@ import {
POSTHOG_EVENT_KEY,
STORAGE_KEYS,
UI_CONFIG,
-} from "../../utils/constants"
-import { createT3InputBarElement, DOMUtils } from "../../utils/ui-components"
+} from "../../utils/constants";
+import { createT3InputBarElement, DOMUtils } from "../../utils/ui-components";
-let t3DebounceTimeout: NodeJS.Timeout | null = null
-let t3RouteObserver: MutationObserver | null = null
-let t3UrlCheckInterval: NodeJS.Timeout | null = null
-let t3ObserverThrottle: NodeJS.Timeout | null = null
+let t3DebounceTimeout: NodeJS.Timeout | null = null;
+let t3RouteObserver: MutationObserver | null = null;
+let t3UrlCheckInterval: NodeJS.Timeout | null = null;
+let t3ObserverThrottle: NodeJS.Timeout | null = null;
export function initializeT3() {
if (!DOMUtils.isOnDomain(DOMAINS.T3)) {
- return
+ return;
}
if (document.body.hasAttribute("data-t3-initialized")) {
- return
+ return;
}
setTimeout(() => {
- console.log("Adding supermemory icon to T3 input")
- addSupermemoryIconToT3Input()
- setupT3AutoFetch()
- }, 2000)
+ console.log("Adding supermemory icon to T3 input");
+ addSupermemoryIconToT3Input();
+ setupT3AutoFetch();
+ }, 2000);
- setupT3PromptCapture()
+ setupT3PromptCapture();
- setupT3RouteChangeDetection()
+ setupT3RouteChangeDetection();
- document.body.setAttribute("data-t3-initialized", "true")
+ document.body.setAttribute("data-t3-initialized", "true");
}
function setupT3RouteChangeDetection() {
if (t3RouteObserver) {
- t3RouteObserver.disconnect()
+ t3RouteObserver.disconnect();
}
if (t3UrlCheckInterval) {
- clearInterval(t3UrlCheckInterval)
+ clearInterval(t3UrlCheckInterval);
}
if (t3ObserverThrottle) {
- clearTimeout(t3ObserverThrottle)
- t3ObserverThrottle = null
+ clearTimeout(t3ObserverThrottle);
+ t3ObserverThrottle = null;
}
- let currentUrl = window.location.href
+ let currentUrl = window.location.href;
const checkForRouteChange = () => {
if (window.location.href !== currentUrl) {
- currentUrl = window.location.href
- console.log("T3 route changed, re-adding supermemory icon")
+ currentUrl = window.location.href;
+ console.log("T3 route changed, re-adding supermemory icon");
setTimeout(() => {
- addSupermemoryIconToT3Input()
- setupT3AutoFetch()
- }, 1000)
+ addSupermemoryIconToT3Input();
+ setupT3AutoFetch();
+ }, 1000);
}
- }
+ };
- t3UrlCheckInterval = setInterval(checkForRouteChange, 2000)
+ t3UrlCheckInterval = setInterval(checkForRouteChange, 2000);
t3RouteObserver = new MutationObserver((mutations) => {
if (t3ObserverThrottle) {
- return
+ return;
}
- let shouldRecheck = false
+ let shouldRecheck = false;
mutations.forEach((mutation) => {
if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
- const element = node as Element
+ const element = node as Element;
if (
element.querySelector?.("textarea") ||
element.querySelector?.('div[contenteditable="true"]') ||
element.matches?.("textarea") ||
element.matches?.('div[contenteditable="true"]')
) {
- shouldRecheck = true
+ shouldRecheck = true;
}
}
- })
+ });
}
- })
+ });
if (shouldRecheck) {
t3ObserverThrottle = setTimeout(() => {
try {
- t3ObserverThrottle = null
- addSupermemoryIconToT3Input()
- setupT3AutoFetch()
+ t3ObserverThrottle = null;
+ addSupermemoryIconToT3Input();
+ setupT3AutoFetch();
} catch (error) {
- console.error("Error in T3 observer callback:", error)
+ console.error("Error in T3 observer callback:", error);
}
- }, 300)
+ }, 300);
}
- })
+ });
try {
t3RouteObserver.observe(document.body, {
childList: true,
subtree: true,
- })
+ });
} catch (error) {
- console.error("Failed to set up T3 route observer:", error)
+ console.error("Failed to set up T3 route observer:", error);
if (t3UrlCheckInterval) {
- clearInterval(t3UrlCheckInterval)
+ clearInterval(t3UrlCheckInterval);
}
- t3UrlCheckInterval = setInterval(checkForRouteChange, 1000)
+ t3UrlCheckInterval = setInterval(checkForRouteChange, 1000);
}
}
function addSupermemoryIconToT3Input() {
const targetContainers = document.querySelectorAll(
".flex.min-w-0.items-center.gap-2.overflow-hidden",
- )
+ );
targetContainers.forEach((container) => {
if (container.hasAttribute("data-supermemory-icon-added")) {
- return
+ return;
}
const existingIcon = container.querySelector(
`#${ELEMENT_IDS.T3_INPUT_BAR_ELEMENT}`,
- )
+ );
if (existingIcon) {
- container.setAttribute("data-supermemory-icon-added", "true")
- return
+ container.setAttribute("data-supermemory-icon-added", "true");
+ return;
}
const supermemoryIcon = createT3InputBarElement(async () => {
- await getRelatedMemoriesForT3(POSTHOG_EVENT_KEY.T3_CHAT_MEMORIES_SEARCHED)
- })
+ await getRelatedMemoriesForT3(
+ POSTHOG_EVENT_KEY.T3_CHAT_MEMORIES_SEARCHED,
+ );
+ });
- supermemoryIcon.id = `${ELEMENT_IDS.T3_INPUT_BAR_ELEMENT}-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`
+ supermemoryIcon.id = `${ELEMENT_IDS.T3_INPUT_BAR_ELEMENT}-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
- container.setAttribute("data-supermemory-icon-added", "true")
+ container.setAttribute("data-supermemory-icon-added", "true");
- container.insertBefore(supermemoryIcon, container.firstChild)
- })
+ container.insertBefore(supermemoryIcon, container.firstChild);
+ });
}
async function getRelatedMemoriesForT3(actionSource: string) {
try {
- let userQuery = ""
+ let userQuery = "";
const supermemoryContainer = document.querySelector(
'[data-supermemory-icon-added="true"]',
- )
+ );
if (
supermemoryContainer?.parentElement?.parentElement?.previousElementSibling
) {
const textareaElement =
supermemoryContainer.parentElement.parentElement.previousElementSibling.querySelector(
"textarea",
- )
- userQuery = textareaElement?.value || ""
+ );
+ userQuery = textareaElement?.value || "";
}
if (!userQuery.trim()) {
const textareaElement = document.querySelector(
'div[contenteditable="true"]',
- ) as HTMLElement
+ ) as HTMLElement;
userQuery =
- textareaElement?.innerText || textareaElement?.textContent || ""
+ textareaElement?.innerText || textareaElement?.textContent || "";
}
if (!userQuery.trim()) {
- const textareas = document.querySelectorAll("textarea")
+ const textareas = document.querySelectorAll("textarea");
for (const textarea of textareas) {
- const text = (textarea as HTMLTextAreaElement).value
+ const text = (textarea as HTMLTextAreaElement).value;
if (text?.trim()) {
- userQuery = text.trim()
- break
+ userQuery = text.trim();
+ break;
}
}
}
- console.log("T3 query extracted:", userQuery)
+ console.log("T3 query extracted:", userQuery);
if (!userQuery.trim()) {
- console.log("No query text found for T3")
- return
+ console.log("No query text found for T3");
+ return;
}
- const icon = document.querySelector('[id*="sm-t3-input-bar-element"]')
+ const icon = document.querySelector('[id*="sm-t3-input-bar-element"]');
- const iconElement = icon as HTMLElement
+ const iconElement = icon as HTMLElement;
if (!iconElement) {
- console.warn("T3 icon element not found, cannot update feedback")
- return
+ console.warn("T3 icon element not found, cannot update feedback");
+ return;
}
- updateT3IconFeedback("Searching memories...", iconElement)
+ updateT3IconFeedback("Searching memories...", iconElement);
const timeoutPromise = new Promise((_, reject) =>
setTimeout(
() => reject(new Error("Memory search timeout")),
UI_CONFIG.API_REQUEST_TIMEOUT,
),
- )
+ );
const response = await Promise.race([
browser.runtime.sendMessage({
@@ -211,15 +213,15 @@ async function getRelatedMemoriesForT3(actionSource: string) {
actionSource: actionSource,
}),
timeoutPromise,
- ])
+ ]);
- console.log("T3 memories response:", response)
+ console.log("T3 memories response:", response);
if (response?.success && response?.data) {
- let textareaElement = null
+ let textareaElement = null;
const supermemoryContainer = document.querySelector(
'[data-supermemory-icon-added="true"]',
- )
+ );
if (
supermemoryContainer?.parentElement?.parentElement
?.previousElementSibling
@@ -227,46 +229,46 @@ async function getRelatedMemoriesForT3(actionSource: string) {
textareaElement =
supermemoryContainer.parentElement.parentElement.previousElementSibling.querySelector(
"textarea",
- )
+ );
}
if (!textareaElement) {
textareaElement = document.querySelector(
'div[contenteditable="true"]',
- ) as HTMLElement
+ ) as HTMLElement;
}
if (textareaElement) {
if (textareaElement.tagName === "TEXTAREA") {
- ;(textareaElement as HTMLTextAreaElement).dataset.supermemories =
- `<br>Supermemories of user (only for the reference): ${response.data}</br>`
+ (textareaElement as HTMLTextAreaElement).dataset.supermemories =
+ `<br>Supermemories of user (only for the reference): ${response.data}</br>`;
} else {
- ;(textareaElement as HTMLElement).dataset.supermemories =
- `<br>Supermemories of user (only for the reference): ${response.data}</br>`
+ (textareaElement as HTMLElement).dataset.supermemories =
+ `<br>Supermemories of user (only for the reference): ${response.data}</br>`;
}
- iconElement.dataset.memoriesData = response.data
+ iconElement.dataset.memoriesData = response.data;
- updateT3IconFeedback("Included Memories", iconElement)
+ updateT3IconFeedback("Included Memories", iconElement);
} else {
- console.warn("T3 input area not found after successful memory fetch")
- updateT3IconFeedback("Memories found", iconElement)
+ console.warn("T3 input area not found after successful memory fetch");
+ updateT3IconFeedback("Memories found", iconElement);
}
} else {
- console.warn("No memories found or API response invalid for T3")
- updateT3IconFeedback("No memories found", iconElement)
+ console.warn("No memories found or API response invalid for T3");
+ updateT3IconFeedback("No memories found", iconElement);
}
} catch (error) {
- console.error("Error getting related memories for T3:", error)
+ console.error("Error getting related memories for T3:", error);
try {
const icon = document.querySelector(
'[id*="sm-t3-input-bar-element"]',
- ) as HTMLElement
+ ) as HTMLElement;
if (icon) {
- updateT3IconFeedback("Error fetching memories", icon)
+ updateT3IconFeedback("Error fetching memories", icon);
}
} catch (feedbackError) {
- console.error("Failed to update T3 error feedback:", feedbackError)
+ console.error("Failed to update T3 error feedback:", feedbackError);
}
}
}
@@ -277,10 +279,10 @@ function updateT3IconFeedback(
resetAfter = 0,
) {
if (!iconElement.dataset.originalHtml) {
- iconElement.dataset.originalHtml = iconElement.innerHTML
+ iconElement.dataset.originalHtml = iconElement.innerHTML;
}
- const feedbackDiv = document.createElement("div")
+ const feedbackDiv = document.createElement("div");
feedbackDiv.style.cssText = `
display: flex;
align-items: center;
@@ -293,15 +295,15 @@ function updateT3IconFeedback(
font-weight: 500;
cursor: ${message === "Included Memories" ? "pointer" : "default"};
position: relative;
- `
+ `;
feedbackDiv.innerHTML = `
<span>✓</span>
<span>${message}</span>
- `
+ `;
if (message === "Included Memories" && iconElement.dataset.memoriesData) {
- const popup = document.createElement("div")
+ const popup = document.createElement("div");
popup.style.cssText = `
position: fixed;
bottom: 80px;
@@ -319,9 +321,9 @@ function updateT3IconFeedback(
z-index: 999999;
display: none;
border: 1px solid #333;
- `
+ `;
- const header = document.createElement("div")
+ const header = document.createElement("div");
header.style.cssText = `
display: flex;
justify-content: space-between;
@@ -329,28 +331,28 @@ function updateT3IconFeedback(
padding: 8px;
border-bottom: 1px solid #333;
opacity: 0.8;
- `
+ `;
header.innerHTML = `
<span style="font-weight: 600; color: #fff;">Included Memories</span>
- `
+ `;
- const content = document.createElement("div")
+ const content = document.createElement("div");
content.style.cssText = `
padding: 0;
max-height: 300px;
overflow-y: auto;
- `
+ `;
- const memoriesText = iconElement.dataset.memoriesData || ""
- console.log("Memories text:", memoriesText)
+ const memoriesText = iconElement.dataset.memoriesData || "";
+ console.log("Memories text:", memoriesText);
const individualMemories = memoriesText
.split(/[,\n]/)
.map((memory) => memory.trim())
- .filter((memory) => memory.length > 0 && memory !== ",")
- console.log("Individual memories:", individualMemories)
+ .filter((memory) => memory.length > 0 && memory !== ",");
+ console.log("Individual memories:", individualMemories);
individualMemories.forEach((memory, index) => {
- const memoryItem = document.createElement("div")
+ const memoryItem = document.createElement("div");
memoryItem.style.cssText = `
display: flex;
align-items: center;
@@ -358,16 +360,16 @@ function updateT3IconFeedback(
padding: 10px;
font-size: 13px;
line-height: 1.4;
- `
+ `;
- const memoryText = document.createElement("div")
+ const memoryText = document.createElement("div");
memoryText.style.cssText = `
flex: 1;
color: #e5e5e5;
- `
- memoryText.textContent = memory.trim()
+ `;
+ memoryText.textContent = memory.trim();
- const removeBtn = document.createElement("button")
+ const removeBtn = document.createElement("button");
removeBtn.style.cssText = `
background: transparent;
color: #9ca3af;
@@ -380,164 +382,169 @@ function updateT3IconFeedback(
display: flex;
align-items: center;
justify-content: center;
- `
- removeBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>`
- removeBtn.dataset.memoryIndex = index.toString()
+ `;
+ removeBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>`;
+ removeBtn.dataset.memoryIndex = index.toString();
removeBtn.addEventListener("mouseenter", () => {
- removeBtn.style.color = "#ef4444"
- })
+ removeBtn.style.color = "#ef4444";
+ });
removeBtn.addEventListener("mouseleave", () => {
- removeBtn.style.color = "#9ca3af"
- })
+ removeBtn.style.color = "#9ca3af";
+ });
- memoryItem.appendChild(memoryText)
- memoryItem.appendChild(removeBtn)
- content.appendChild(memoryItem)
- })
+ memoryItem.appendChild(memoryText);
+ memoryItem.appendChild(removeBtn);
+ content.appendChild(memoryItem);
+ });
- popup.appendChild(header)
- popup.appendChild(content)
- document.body.appendChild(popup)
+ popup.appendChild(header);
+ popup.appendChild(content);
+ document.body.appendChild(popup);
feedbackDiv.addEventListener("mouseenter", () => {
- const textSpan = feedbackDiv.querySelector("span:last-child")
+ const textSpan = feedbackDiv.querySelector("span:last-child");
if (textSpan) {
- textSpan.textContent = "Click to see memories"
+ textSpan.textContent = "Click to see memories";
}
- })
+ });
feedbackDiv.addEventListener("mouseleave", () => {
- const textSpan = feedbackDiv.querySelector("span:last-child")
+ const textSpan = feedbackDiv.querySelector("span:last-child");
if (textSpan) {
- textSpan.textContent = "Included Memories"
+ textSpan.textContent = "Included Memories";
}
- })
+ });
feedbackDiv.addEventListener("click", (e) => {
- e.stopPropagation()
- popup.style.display = "block"
- })
+ e.stopPropagation();
+ popup.style.display = "block";
+ });
document.addEventListener("click", (e) => {
if (!popup.contains(e.target as Node)) {
- popup.style.display = "none"
+ popup.style.display = "none";
}
- })
+ });
content.querySelectorAll("button[data-memory-index]").forEach((button) => {
- const htmlButton = button as HTMLButtonElement
+ const htmlButton = button as HTMLButtonElement;
htmlButton.addEventListener("click", () => {
- const index = Number.parseInt(htmlButton.dataset.memoryIndex || "0", 10)
- const memoryItem = htmlButton.parentElement
+ const index = Number.parseInt(
+ htmlButton.dataset.memoryIndex || "0",
+ 10,
+ );
+ const memoryItem = htmlButton.parentElement;
if (memoryItem) {
- content.removeChild(memoryItem)
+ content.removeChild(memoryItem);
}
const currentMemories = (iconElement.dataset.memoriesData || "")
.split(/[,\n]/)
.map((memory) => memory.trim())
- .filter((memory) => memory.length > 0 && memory !== ",")
- currentMemories.splice(index, 1)
+ .filter((memory) => memory.length > 0 && memory !== ",");
+ currentMemories.splice(index, 1);
- const updatedMemories = currentMemories.join(" ,")
+ const updatedMemories = currentMemories.join(" ,");
- iconElement.dataset.memoriesData = updatedMemories
+ iconElement.dataset.memoriesData = updatedMemories;
const textareaElement =
(document.querySelector("textarea") as HTMLTextAreaElement) ||
- (document.querySelector('div[contenteditable="true"]') as HTMLElement)
+ (document.querySelector(
+ 'div[contenteditable="true"]',
+ ) as HTMLElement);
if (textareaElement) {
- textareaElement.dataset.supermemories = `<div>Supermemories of user (only for the reference): ${updatedMemories}</div>`
+ textareaElement.dataset.supermemories = `<div>Supermemories of user (only for the reference): ${updatedMemories}</div>`;
}
content
.querySelectorAll("button[data-memory-index]")
.forEach((btn, newIndex) => {
- const htmlBtn = btn as HTMLButtonElement
- htmlBtn.dataset.memoryIndex = newIndex.toString()
- })
+ const htmlBtn = btn as HTMLButtonElement;
+ htmlBtn.dataset.memoryIndex = newIndex.toString();
+ });
if (currentMemories.length <= 1) {
if (textareaElement?.dataset.supermemories) {
- delete textareaElement.dataset.supermemories
- delete iconElement.dataset.memoriesData
- iconElement.innerHTML = iconElement.dataset.originalHtml || ""
- delete iconElement.dataset.originalHtml
+ delete textareaElement.dataset.supermemories;
+ delete iconElement.dataset.memoriesData;
+ iconElement.innerHTML = iconElement.dataset.originalHtml || "";
+ delete iconElement.dataset.originalHtml;
}
- popup.style.display = "none"
+ popup.style.display = "none";
if (document.body.contains(popup)) {
- document.body.removeChild(popup)
+ document.body.removeChild(popup);
}
}
- })
- })
+ });
+ });
setTimeout(() => {
if (document.body.contains(popup)) {
- document.body.removeChild(popup)
+ document.body.removeChild(popup);
}
- }, 300000)
+ }, 300000);
}
- iconElement.innerHTML = ""
- iconElement.appendChild(feedbackDiv)
+ iconElement.innerHTML = "";
+ iconElement.appendChild(feedbackDiv);
if (resetAfter > 0) {
setTimeout(() => {
- iconElement.innerHTML = iconElement.dataset.originalHtml || ""
- delete iconElement.dataset.originalHtml
- }, resetAfter)
+ iconElement.innerHTML = iconElement.dataset.originalHtml || "";
+ delete iconElement.dataset.originalHtml;
+ }, resetAfter);
}
}
function setupT3PromptCapture() {
if (document.body.hasAttribute("data-t3-prompt-capture-setup")) {
- return
+ return;
}
- document.body.setAttribute("data-t3-prompt-capture-setup", "true")
+ document.body.setAttribute("data-t3-prompt-capture-setup", "true");
const captureT3PromptContent = async (source: string) => {
- let promptContent = ""
+ let promptContent = "";
- const textarea = document.querySelector("textarea") as HTMLTextAreaElement
+ const textarea = document.querySelector("textarea") as HTMLTextAreaElement;
if (textarea) {
- promptContent = textarea.value || ""
+ promptContent = textarea.value || "";
}
if (!promptContent) {
const contentEditableDiv = document.querySelector(
'div[contenteditable="true"]',
- ) as HTMLElement
+ ) as HTMLElement;
if (contentEditableDiv) {
promptContent =
- contentEditableDiv.textContent || contentEditableDiv.innerText || ""
+ contentEditableDiv.textContent || contentEditableDiv.innerText || "";
}
}
const textareaElement =
textarea ||
- (document.querySelector('div[contenteditable="true"]') as HTMLElement)
- const storedMemories = textareaElement?.dataset.supermemories
+ (document.querySelector('div[contenteditable="true"]') as HTMLElement);
+ const storedMemories = textareaElement?.dataset.supermemories;
if (
storedMemories &&
textareaElement &&
!promptContent.includes("Supermemories of user")
) {
if (textareaElement.tagName === "TEXTAREA") {
- ;(textareaElement as HTMLTextAreaElement).value =
- `${promptContent} ${storedMemories}`
- promptContent = (textareaElement as HTMLTextAreaElement).value
+ (textareaElement as HTMLTextAreaElement).value =
+ `${promptContent} ${storedMemories}`;
+ promptContent = (textareaElement as HTMLTextAreaElement).value;
} else {
- textareaElement.innerHTML = `${textareaElement.innerHTML} ${storedMemories}`
+ textareaElement.innerHTML = `${textareaElement.innerHTML} ${storedMemories}`;
promptContent =
- textareaElement.textContent || textareaElement.innerText || ""
+ textareaElement.textContent || textareaElement.innerText || "";
}
}
if (promptContent.trim()) {
- console.log(`T3 prompt submitted via ${source}:`, promptContent)
+ console.log(`T3 prompt submitted via ${source}:`, promptContent);
try {
await browser.runtime.sendMessage({
@@ -547,48 +554,48 @@ function setupT3PromptCapture() {
platform: "t3",
source: source,
},
- })
+ });
} catch (error) {
- console.error("Error sending T3 prompt to background:", error)
+ console.error("Error sending T3 prompt to background:", error);
}
}
- const icons = document.querySelectorAll('[id*="sm-t3-input-bar-element"]')
+ const icons = document.querySelectorAll('[id*="sm-t3-input-bar-element"]');
icons.forEach((icon) => {
- const iconElement = icon as HTMLElement
+ const iconElement = icon as HTMLElement;
if (iconElement.dataset.originalHtml) {
- iconElement.innerHTML = iconElement.dataset.originalHtml
- delete iconElement.dataset.originalHtml
- delete iconElement.dataset.memoriesData
+ iconElement.innerHTML = iconElement.dataset.originalHtml;
+ delete iconElement.dataset.originalHtml;
+ delete iconElement.dataset.memoriesData;
}
- })
+ });
if (textareaElement?.dataset.supermemories) {
- delete textareaElement.dataset.supermemories
+ delete textareaElement.dataset.supermemories;
}
- }
+ };
document.addEventListener(
"click",
async (event) => {
- const target = event.target as HTMLElement
+ const target = event.target as HTMLElement;
const sendButton =
target.closest("button.focus-visible\\:ring-ring") ||
target.closest('button[class*="bg-[rgb(162,59,103)]"]') ||
- target.closest('button[class*="rounded-lg"]')
+ target.closest('button[class*="rounded-lg"]');
if (sendButton) {
- await captureT3PromptContent("button click")
+ await captureT3PromptContent("button click");
}
},
true,
- )
+ );
document.addEventListener(
"keydown",
async (event) => {
- const target = event.target as HTMLElement
+ const target = event.target as HTMLElement;
if (
(target.matches("textarea") ||
@@ -597,9 +604,9 @@ function setupT3PromptCapture() {
!event.shiftKey
) {
if (target.matches("textarea")) {
- const promptContent = (target as HTMLTextAreaElement).value || ""
+ const promptContent = (target as HTMLTextAreaElement).value || "";
if (promptContent.trim()) {
- console.log("T3 prompt submitted via Enter key:", promptContent)
+ console.log("T3 prompt submitted via Enter key:", promptContent);
try {
await browser.runtime.sendMessage({
@@ -610,83 +617,83 @@ function setupT3PromptCapture() {
source: "Enter key",
},
actionSource: "t3",
- })
+ });
} catch (error) {
console.error(
"Error sending T3 textarea prompt to background:",
error,
- )
+ );
}
}
} else {
- await captureT3PromptContent("Enter key")
+ await captureT3PromptContent("Enter key");
}
}
},
true,
- )
+ );
}
async function setupT3AutoFetch() {
const result = await chrome.storage.local.get([
STORAGE_KEYS.AUTO_SEARCH_ENABLED,
- ])
- const autoSearchEnabled = result[STORAGE_KEYS.AUTO_SEARCH_ENABLED] ?? false
+ ]);
+ const autoSearchEnabled = result[STORAGE_KEYS.AUTO_SEARCH_ENABLED] ?? false;
if (!autoSearchEnabled) {
- return
+ return;
}
const textareaElement =
(document.querySelector("textarea") as HTMLTextAreaElement) ||
- (document.querySelector('div[contenteditable="true"]') as HTMLElement)
+ (document.querySelector('div[contenteditable="true"]') as HTMLElement);
if (
!textareaElement ||
textareaElement.hasAttribute("data-supermemory-auto-fetch")
) {
- return
+ return;
}
- textareaElement.setAttribute("data-supermemory-auto-fetch", "true")
+ textareaElement.setAttribute("data-supermemory-auto-fetch", "true");
const handleInput = () => {
if (t3DebounceTimeout) {
- clearTimeout(t3DebounceTimeout)
+ clearTimeout(t3DebounceTimeout);
}
t3DebounceTimeout = setTimeout(async () => {
- let content = ""
+ let content = "";
if (textareaElement.tagName === "TEXTAREA") {
- content = (textareaElement as HTMLTextAreaElement).value?.trim() || ""
+ content = (textareaElement as HTMLTextAreaElement).value?.trim() || "";
} else {
- content = textareaElement.textContent?.trim() || ""
+ content = textareaElement.textContent?.trim() || "";
}
if (content.length > 2) {
await getRelatedMemoriesForT3(
POSTHOG_EVENT_KEY.T3_CHAT_MEMORIES_AUTO_SEARCHED,
- )
+ );
} else if (content.length === 0) {
const icons = document.querySelectorAll(
'[id*="sm-t3-input-bar-element"]',
- )
+ );
icons.forEach((icon) => {
- const iconElement = icon as HTMLElement
+ const iconElement = icon as HTMLElement;
if (iconElement.dataset.originalHtml) {
- iconElement.innerHTML = iconElement.dataset.originalHtml
- delete iconElement.dataset.originalHtml
- delete iconElement.dataset.memoriesData
+ iconElement.innerHTML = iconElement.dataset.originalHtml;
+ delete iconElement.dataset.originalHtml;
+ delete iconElement.dataset.memoriesData;
}
- })
+ });
if (textareaElement.dataset.supermemories) {
- delete textareaElement.dataset.supermemories
+ delete textareaElement.dataset.supermemories;
}
}
- }, UI_CONFIG.AUTO_SEARCH_DEBOUNCE_DELAY)
- }
+ }, UI_CONFIG.AUTO_SEARCH_DEBOUNCE_DELAY);
+ };
- textareaElement.addEventListener("input", handleInput)
+ textareaElement.addEventListener("input", handleInput);
}
diff --git a/apps/browser-extension/entrypoints/content/twitter.ts b/apps/browser-extension/entrypoints/content/twitter.ts
index 15c6ec50..272983cf 100644
--- a/apps/browser-extension/entrypoints/content/twitter.ts
+++ b/apps/browser-extension/entrypoints/content/twitter.ts
@@ -3,24 +3,24 @@ import {
ELEMENT_IDS,
MESSAGE_TYPES,
POSTHOG_EVENT_KEY,
-} from "../../utils/constants"
-import { trackEvent } from "../../utils/posthog"
-import { createTwitterImportButton, DOMUtils } from "../../utils/ui-components"
+} from "../../utils/constants";
+import { trackEvent } from "../../utils/posthog";
+import { createTwitterImportButton, DOMUtils } from "../../utils/ui-components";
export function initializeTwitter() {
if (!DOMUtils.isOnDomain(DOMAINS.TWITTER)) {
- return
+ return;
}
// Initial setup
if (window.location.pathname === "/i/bookmarks") {
setTimeout(() => {
- addTwitterImportButton()
- }, 2000)
+ addTwitterImportButton();
+ }, 2000);
} else {
// Remove button if not on bookmarks page
if (DOMUtils.elementExists(ELEMENT_IDS.TWITTER_IMPORT_BUTTON)) {
- DOMUtils.removeElement(ELEMENT_IDS.TWITTER_IMPORT_BUTTON)
+ DOMUtils.removeElement(ELEMENT_IDS.TWITTER_IMPORT_BUTTON);
}
}
}
@@ -28,75 +28,75 @@ export function initializeTwitter() {
function addTwitterImportButton() {
// Only show the import button on the bookmarks page
if (window.location.pathname !== "/i/bookmarks") {
- return
+ return;
}
if (DOMUtils.elementExists(ELEMENT_IDS.TWITTER_IMPORT_BUTTON)) {
- return
+ return;
}
const button = createTwitterImportButton(async () => {
try {
await browser.runtime.sendMessage({
type: MESSAGE_TYPES.BATCH_IMPORT_ALL,
- })
+ });
await trackEvent(POSTHOG_EVENT_KEY.TWITTER_IMPORT_STARTED, {
source: `${POSTHOG_EVENT_KEY.SOURCE}_content_script`,
- })
+ });
} catch (error) {
- console.error("Error starting import:", error)
+ console.error("Error starting import:", error);
}
- })
+ });
- document.body.appendChild(button)
+ document.body.appendChild(button);
}
export function updateTwitterImportUI(message: {
- type: string
- importedMessage?: string
- totalImported?: number
+ type: string;
+ importedMessage?: string;
+ totalImported?: number;
}) {
const importButton = document.getElementById(
ELEMENT_IDS.TWITTER_IMPORT_BUTTON,
- )
- if (!importButton) return
+ );
+ if (!importButton) return;
- const iconUrl = browser.runtime.getURL("/icon-16.png")
+ const iconUrl = browser.runtime.getURL("/icon-16.png");
if (message.type === MESSAGE_TYPES.IMPORT_UPDATE) {
importButton.innerHTML = `
<img src="${iconUrl}" width="20" height="20" alt="Save to Memory" style="border-radius: 4px;" />
<span style="font-weight: 500; font-size: 14px;">${message.importedMessage}</span>
- `
- importButton.style.cursor = "default"
+ `;
+ importButton.style.cursor = "default";
}
if (message.type === MESSAGE_TYPES.IMPORT_DONE) {
importButton.innerHTML = `
<img src="${iconUrl}" width="20" height="20" alt="Save to Memory" style="border-radius: 4px;" />
<span style="font-weight: 500; font-size: 14px; color: #059669;">✓ Imported ${message.totalImported} tweets!</span>
- `
+ `;
setTimeout(() => {
importButton.innerHTML = `
<img src="${iconUrl}" width="20" height="20" alt="Save to Memory" style="border-radius: 4px;" />
<span style="font-weight: 500; font-size: 14px;">Import Bookmarks</span>
- `
- importButton.style.cursor = "pointer"
- }, 3000)
+ `;
+ importButton.style.cursor = "pointer";
+ }, 3000);
}
}
export function handleTwitterNavigation() {
if (!DOMUtils.isOnDomain(DOMAINS.TWITTER)) {
- return
+ return;
}
if (window.location.pathname === "/i/bookmarks") {
- addTwitterImportButton()
+ addTwitterImportButton();
} else {
if (DOMUtils.elementExists(ELEMENT_IDS.TWITTER_IMPORT_BUTTON)) {
- DOMUtils.removeElement(ELEMENT_IDS.TWITTER_IMPORT_BUTTON)
+ DOMUtils.removeElement(ELEMENT_IDS.TWITTER_IMPORT_BUTTON);
}
}
-} \ No newline at end of file
+}
diff --git a/apps/browser-extension/entrypoints/popup/App.tsx b/apps/browser-extension/entrypoints/popup/App.tsx
index 3e4f15e2..3d4aeedd 100644
--- a/apps/browser-extension/entrypoints/popup/App.tsx
+++ b/apps/browser-extension/entrypoints/popup/App.tsx
@@ -1,34 +1,35 @@
-import { useQueryClient } from "@tanstack/react-query"
-import { useEffect, useState } from "react"
-import "./App.css"
-import { MESSAGE_TYPES, STORAGE_KEYS } from "../../utils/constants"
+import { useQueryClient } from "@tanstack/react-query";
+import { useEffect, useState } from "react";
+import "./App.css";
+import { MESSAGE_TYPES, STORAGE_KEYS } from "../../utils/constants";
import {
useDefaultProject,
useProjects,
useSetDefaultProject,
-} from "../../utils/query-hooks"
-import type { Project } from "../../utils/types"
+} from "../../utils/query-hooks";
+import type { Project } from "../../utils/types";
function App() {
- const [userSignedIn, setUserSignedIn] = useState<boolean>(false)
- const [loading, setLoading] = useState<boolean>(true)
- const [showProjectSelector, setShowProjectSelector] = useState<boolean>(false)
- const [currentUrl, setCurrentUrl] = useState<string>("")
- const [currentTitle, setCurrentTitle] = useState<string>("")
- const [saving, setSaving] = useState<boolean>(false)
+ const [userSignedIn, setUserSignedIn] = useState<boolean>(false);
+ const [loading, setLoading] = useState<boolean>(true);
+ const [showProjectSelector, setShowProjectSelector] =
+ useState<boolean>(false);
+ const [currentUrl, setCurrentUrl] = useState<string>("");
+ const [currentTitle, setCurrentTitle] = useState<string>("");
+ const [saving, setSaving] = useState<boolean>(false);
const [activeTab, setActiveTab] = useState<"save" | "imports" | "settings">(
"save",
- )
- const [autoSearchEnabled, setAutoSearchEnabled] = useState<boolean>(false)
+ );
+ const [autoSearchEnabled, setAutoSearchEnabled] = useState<boolean>(false);
- const queryClient = useQueryClient()
+ const queryClient = useQueryClient();
const { data: projects = [], isLoading: loadingProjects } = useProjects({
enabled: userSignedIn,
- })
+ });
const { data: defaultProject } = useDefaultProject({
enabled: userSignedIn,
- })
- const setDefaultProjectMutation = useSetDefaultProject()
+ });
+ const setDefaultProjectMutation = useSetDefaultProject();
useEffect(() => {
const checkAuthStatus = async () => {
@@ -36,131 +37,131 @@ function App() {
const result = await chrome.storage.local.get([
STORAGE_KEYS.BEARER_TOKEN,
STORAGE_KEYS.AUTO_SEARCH_ENABLED,
- ])
- const isSignedIn = !!result[STORAGE_KEYS.BEARER_TOKEN]
- setUserSignedIn(isSignedIn)
+ ]);
+ const isSignedIn = !!result[STORAGE_KEYS.BEARER_TOKEN];
+ setUserSignedIn(isSignedIn);
const autoSearchSetting =
- result[STORAGE_KEYS.AUTO_SEARCH_ENABLED] ?? false
- setAutoSearchEnabled(autoSearchSetting)
+ result[STORAGE_KEYS.AUTO_SEARCH_ENABLED] ?? false;
+ setAutoSearchEnabled(autoSearchSetting);
} catch (error) {
- console.error("Error checking auth status:", error)
- setUserSignedIn(false)
+ console.error("Error checking auth status:", error);
+ setUserSignedIn(false);
} finally {
- setLoading(false)
+ setLoading(false);
}
- }
+ };
const getCurrentTab = async () => {
try {
const tabs = await chrome.tabs.query({
active: true,
currentWindow: true,
- })
+ });
if (tabs.length > 0 && tabs[0].url && tabs[0].title) {
- setCurrentUrl(tabs[0].url)
- setCurrentTitle(tabs[0].title)
+ setCurrentUrl(tabs[0].url);
+ setCurrentTitle(tabs[0].title);
}
} catch (error) {
- console.error("Error getting current tab:", error)
+ console.error("Error getting current tab:", error);
}
- }
+ };
- checkAuthStatus()
- getCurrentTab()
- }, [])
+ checkAuthStatus();
+ getCurrentTab();
+ }, []);
const handleProjectSelect = (project: Project) => {
setDefaultProjectMutation.mutate(project, {
onSuccess: () => {
- setShowProjectSelector(false)
+ setShowProjectSelector(false);
},
onError: (error) => {
- console.error("Error setting default project:", error)
+ console.error("Error setting default project:", error);
},
- })
- }
+ });
+ };
const handleShowProjectSelector = () => {
- setShowProjectSelector(true)
- }
+ setShowProjectSelector(true);
+ };
useEffect(() => {
if (!defaultProject && projects.length > 0) {
- const firstProject = projects[0]
- setDefaultProjectMutation.mutate(firstProject)
+ const firstProject = projects[0];
+ setDefaultProjectMutation.mutate(firstProject);
}
- }, [defaultProject, projects, setDefaultProjectMutation])
+ }, [defaultProject, projects, setDefaultProjectMutation]);
const handleSaveCurrentPage = async () => {
- setSaving(true)
+ setSaving(true);
try {
const tabs = await chrome.tabs.query({
active: true,
currentWindow: true,
- })
+ });
if (tabs.length > 0 && tabs[0].id) {
const response = await chrome.tabs.sendMessage(tabs[0].id, {
action: MESSAGE_TYPES.SAVE_MEMORY,
actionSource: "popup",
- })
+ });
if (response?.success) {
await chrome.tabs.sendMessage(tabs[0].id, {
action: MESSAGE_TYPES.SHOW_TOAST,
state: "success",
- })
+ });
}
- window.close()
+ window.close();
}
} catch (error) {
- console.error("Failed to save current page:", error)
+ console.error("Failed to save current page:", error);
try {
const tabs = await chrome.tabs.query({
active: true,
currentWindow: true,
- })
+ });
if (tabs.length > 0 && tabs[0].id) {
await chrome.tabs.sendMessage(tabs[0].id, {
action: MESSAGE_TYPES.SHOW_TOAST,
state: "error",
- })
+ });
}
} catch (toastError) {
- console.error("Failed to show error toast:", toastError)
+ console.error("Failed to show error toast:", toastError);
}
- window.close()
+ window.close();
} finally {
- setSaving(false)
+ setSaving(false);
}
- }
+ };
const handleAutoSearchToggle = async (enabled: boolean) => {
try {
await chrome.storage.local.set({
[STORAGE_KEYS.AUTO_SEARCH_ENABLED]: enabled,
- })
- setAutoSearchEnabled(enabled)
+ });
+ setAutoSearchEnabled(enabled);
} catch (error) {
- console.error("Error updating auto search setting:", error)
+ console.error("Error updating auto search setting:", error);
}
- }
+ };
const handleSignOut = async () => {
try {
- await chrome.storage.local.remove([STORAGE_KEYS.BEARER_TOKEN])
- await chrome.storage.local.remove([STORAGE_KEYS.USER_DATA])
- await chrome.storage.local.remove([STORAGE_KEYS.DEFAULT_PROJECT])
- setUserSignedIn(false)
- queryClient.clear()
+ await chrome.storage.local.remove([STORAGE_KEYS.BEARER_TOKEN]);
+ await chrome.storage.local.remove([STORAGE_KEYS.USER_DATA]);
+ await chrome.storage.local.remove([STORAGE_KEYS.DEFAULT_PROJECT]);
+ setUserSignedIn(false);
+ queryClient.clear();
} catch (error) {
- console.error("Error signing out:", error)
+ console.error("Error signing out:", error);
}
- }
+ };
if (loading) {
return (
@@ -179,7 +180,7 @@ function App() {
<div>Loading...</div>
</div>
</div>
- )
+ );
}
return (
@@ -330,7 +331,7 @@ function App() {
onClick={() => {
chrome.tabs.create({
url: "https://chatgpt.com/#settings/Personalization",
- })
+ });
}}
type="button"
>
@@ -361,17 +362,17 @@ function App() {
const [activeTab] = await chrome.tabs.query({
active: true,
currentWindow: true,
- })
+ });
- const targetUrl = "https://x.com/i/bookmarks"
+ const targetUrl = "https://x.com/i/bookmarks";
if (activeTab?.url === targetUrl) {
- return
+ return;
}
await chrome.tabs.create({
url: targetUrl,
- })
+ });
}}
type="button"
>
@@ -504,7 +505,7 @@ function App() {
<button
className="bg-transparent border-none text-blue-500 cursor-pointer underline text-sm p-0 hover:text-blue-700"
onClick={() => {
- window.open("mailto:[email protected]", "_blank")
+ window.open("mailto:[email protected]", "_blank");
}}
type="button"
>
@@ -519,7 +520,7 @@ function App() {
url: import.meta.env.PROD
? "https://app.supermemory.ai/login"
: "http://localhost:3000/login",
- })
+ });
}}
type="button"
>
@@ -530,7 +531,7 @@ function App() {
)}
</div>
</div>
- )
+ );
}
-export default App
+export default App;
diff --git a/apps/browser-extension/entrypoints/popup/main.tsx b/apps/browser-extension/entrypoints/popup/main.tsx
index 746e1018..5376a552 100644
--- a/apps/browser-extension/entrypoints/popup/main.tsx
+++ b/apps/browser-extension/entrypoints/popup/main.tsx
@@ -1,11 +1,11 @@
-import { QueryClientProvider } from "@tanstack/react-query"
-import React from "react"
-import ReactDOM from "react-dom/client"
-import { queryClient } from "../../utils/query-client"
-import App from "./App.js"
-import "./style.css"
+import { QueryClientProvider } from "@tanstack/react-query";
+import React from "react";
+import ReactDOM from "react-dom/client";
+import { queryClient } from "../../utils/query-client";
+import App from "./App.js";
+import "./style.css";
-const rootElement = document.getElementById("root")
+const rootElement = document.getElementById("root");
if (rootElement) {
ReactDOM.createRoot(rootElement).render(
<React.StrictMode>
@@ -13,5 +13,5 @@ if (rootElement) {
<App />
</QueryClientProvider>
</React.StrictMode>,
- )
+ );
}
diff --git a/apps/browser-extension/entrypoints/welcome/Welcome.tsx b/apps/browser-extension/entrypoints/welcome/Welcome.tsx
index 9463eba4..00bd01cc 100644
--- a/apps/browser-extension/entrypoints/welcome/Welcome.tsx
+++ b/apps/browser-extension/entrypoints/welcome/Welcome.tsx
@@ -77,7 +77,7 @@ function Welcome() {
url: import.meta.env.PROD
? "https://app.supermemory.ai/login"
: "http://localhost:3000/login",
- })
+ });
}}
type="button"
>
@@ -101,7 +101,7 @@ function Welcome() {
</div>
</div>
</div>
- )
+ );
}
-export default Welcome
+export default Welcome;
diff --git a/apps/browser-extension/entrypoints/welcome/main.tsx b/apps/browser-extension/entrypoints/welcome/main.tsx
index 2df8dbf1..84ad6b8c 100644
--- a/apps/browser-extension/entrypoints/welcome/main.tsx
+++ b/apps/browser-extension/entrypoints/welcome/main.tsx
@@ -1,11 +1,11 @@
-import { QueryClientProvider } from "@tanstack/react-query"
-import React from "react"
-import ReactDOM from "react-dom/client"
-import { queryClient } from "../../utils/query-client"
-import Welcome from "./Welcome"
-import "./welcome.css"
+import { QueryClientProvider } from "@tanstack/react-query";
+import React from "react";
+import ReactDOM from "react-dom/client";
+import { queryClient } from "../../utils/query-client";
+import Welcome from "./Welcome";
+import "./welcome.css";
-const rootElement = document.getElementById("root")
+const rootElement = document.getElementById("root");
if (rootElement) {
ReactDOM.createRoot(rootElement).render(
<React.StrictMode>
@@ -13,5 +13,5 @@ if (rootElement) {
<Welcome />
</QueryClientProvider>
</React.StrictMode>,
- )
+ );
}