diff options
| author | Dhravya Shah <[email protected]> | 2025-10-20 18:15:07 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-10-20 18:15:07 -0700 |
| commit | 88faba05adec152f5f57d005b835fa2729a6046f (patch) | |
| tree | 443c52d8f8df733a865240fab9c4568229661da0 /apps | |
| parent | Merge pull request #501 from supermemoryai/10-19-fix_tools_update_the_docs_fo... (diff) | |
| parent | feat: auto capture disabled by default (diff) | |
| download | supermemory-88faba05adec152f5f57d005b835fa2729a6046f.tar.xz supermemory-88faba05adec152f5f57d005b835fa2729a6046f.zip | |
Merge pull request #500 from supermemoryai/10-19-chore_browser-extension_t3_chat_search_memories
feat(browser-extension): setting to enable/disable auto prompt captures
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/browser-extension/entrypoints/content/chatgpt.ts | 10 | ||||
| -rw-r--r-- | apps/browser-extension/entrypoints/content/claude.ts | 10 | ||||
| -rw-r--r-- | apps/browser-extension/entrypoints/content/t3.ts | 77 | ||||
| -rw-r--r-- | apps/browser-extension/entrypoints/popup/App.tsx | 109 | ||||
| -rw-r--r-- | apps/browser-extension/utils/constants.ts | 1 | ||||
| -rw-r--r-- | apps/browser-extension/wxt.config.ts | 2 |
6 files changed, 167 insertions, 42 deletions
diff --git a/apps/browser-extension/entrypoints/content/chatgpt.ts b/apps/browser-extension/entrypoints/content/chatgpt.ts index 73e0354f..20308728 100644 --- a/apps/browser-extension/entrypoints/content/chatgpt.ts +++ b/apps/browser-extension/entrypoints/content/chatgpt.ts @@ -640,6 +640,16 @@ function setupChatGPTPromptCapture() { document.body.setAttribute("data-chatgpt-prompt-capture-setup", "true") const capturePromptContent = async (source: string) => { + const result = await chrome.storage.local.get([ + STORAGE_KEYS.AUTO_CAPTURE_PROMPTS_ENABLED, + ]) + const autoCapturePromptsEnabled = + result[STORAGE_KEYS.AUTO_CAPTURE_PROMPTS_ENABLED] ?? false + + if (!autoCapturePromptsEnabled) { + console.log("Auto capture prompts is disabled, skipping prompt capture") + return + } const promptTextarea = document.getElementById("prompt-textarea") let promptContent = "" diff --git a/apps/browser-extension/entrypoints/content/claude.ts b/apps/browser-extension/entrypoints/content/claude.ts index e0853d41..88874a3f 100644 --- a/apps/browser-extension/entrypoints/content/claude.ts +++ b/apps/browser-extension/entrypoints/content/claude.ts @@ -488,6 +488,16 @@ function setupClaudePromptCapture() { } document.body.setAttribute("data-claude-prompt-capture-setup", "true") const captureClaudePromptContent = async (source: string) => { + const result = await chrome.storage.local.get([ + STORAGE_KEYS.AUTO_CAPTURE_PROMPTS_ENABLED, + ]) + const autoCapturePromptsEnabled = + result[STORAGE_KEYS.AUTO_CAPTURE_PROMPTS_ENABLED] ?? false + + if (!autoCapturePromptsEnabled) { + console.log("Auto capture prompts is disabled, skipping prompt capture") + return + } let promptContent = "" const contentEditableDiv = document.querySelector( diff --git a/apps/browser-extension/entrypoints/content/t3.ts b/apps/browser-extension/entrypoints/content/t3.ts index 4332076e..d1229e6d 100644 --- a/apps/browser-extension/entrypoints/content/t3.ts +++ b/apps/browser-extension/entrypoints/content/t3.ts @@ -115,32 +115,35 @@ function setupT3RouteChangeDetection() { function addSupermemoryIconToT3Input() { const targetContainers = document.querySelectorAll( - ".flex.min-w-0.items-center.gap-2.overflow-hidden", + ".flex.min-w-0.items-center.gap-2", ) - targetContainers.forEach((container) => { - if (container.hasAttribute("data-supermemory-icon-added")) { - return - } - - const existingIcon = container.querySelector( - `#${ELEMENT_IDS.T3_INPUT_BAR_ELEMENT}`, - ) - if (existingIcon) { - container.setAttribute("data-supermemory-icon-added", "true") - return - } - - const supermemoryIcon = createT3InputBarElement(async () => { - await getRelatedMemoriesForT3(POSTHOG_EVENT_KEY.T3_CHAT_MEMORIES_SEARCHED) - }) + const container = targetContainers[0] + if (!container) { + return + } - supermemoryIcon.id = `${ELEMENT_IDS.T3_INPUT_BAR_ELEMENT}-${Date.now()}-${Math.random().toString(36).substring(2, 11)}` + if (container.hasAttribute("data-supermemory-icon-added")) { + return + } + const existingIcon = container.querySelector( + `#${ELEMENT_IDS.T3_INPUT_BAR_ELEMENT}`, + ) + if (existingIcon) { container.setAttribute("data-supermemory-icon-added", "true") + return + } - container.insertBefore(supermemoryIcon, container.firstChild) + const supermemoryIcon = createT3InputBarElement(async () => { + 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)}` + + container.setAttribute("data-supermemory-icon-added", "true") + + container.insertBefore(supermemoryIcon, container.firstChild) } async function getRelatedMemoriesForT3(actionSource: string) { @@ -150,11 +153,9 @@ async function getRelatedMemoriesForT3(actionSource: string) { const supermemoryContainer = document.querySelector( '[data-supermemory-icon-added="true"]', ) - if ( - supermemoryContainer?.parentElement?.parentElement?.previousElementSibling - ) { + if (supermemoryContainer?.parentElement?.previousElementSibling) { const textareaElement = - supermemoryContainer.parentElement.parentElement.previousElementSibling.querySelector( + supermemoryContainer.parentElement.previousElementSibling.querySelector( "textarea", ) userQuery = textareaElement?.value || "" @@ -220,12 +221,9 @@ async function getRelatedMemoriesForT3(actionSource: string) { const supermemoryContainer = document.querySelector( '[data-supermemory-icon-added="true"]', ) - if ( - supermemoryContainer?.parentElement?.parentElement - ?.previousElementSibling - ) { + if (supermemoryContainer?.parentElement?.previousElementSibling) { textareaElement = - supermemoryContainer.parentElement.parentElement.previousElementSibling.querySelector( + supermemoryContainer.parentElement.previousElementSibling.querySelector( "textarea", ) } @@ -499,6 +497,16 @@ function setupT3PromptCapture() { document.body.setAttribute("data-t3-prompt-capture-setup", "true") const captureT3PromptContent = async (source: string) => { + const result = await chrome.storage.local.get([ + STORAGE_KEYS.AUTO_CAPTURE_PROMPTS_ENABLED, + ]) + const autoCapturePromptsEnabled = + result[STORAGE_KEYS.AUTO_CAPTURE_PROMPTS_ENABLED] ?? false + + if (!autoCapturePromptsEnabled) { + console.log("Auto capture prompts is disabled, skipping prompt capture") + return + } let promptContent = "" const textarea = document.querySelector("textarea") as HTMLTextAreaElement @@ -601,6 +609,19 @@ function setupT3PromptCapture() { if (promptContent.trim()) { console.log("T3 prompt submitted via Enter key:", promptContent) + const result = await chrome.storage.local.get([ + STORAGE_KEYS.AUTO_CAPTURE_PROMPTS_ENABLED, + ]) + const autoCapturePromptsEnabled = + result[STORAGE_KEYS.AUTO_CAPTURE_PROMPTS_ENABLED] ?? false + + if (!autoCapturePromptsEnabled) { + console.log( + "Auto capture prompts is disabled, skipping prompt capture", + ) + return + } + try { await browser.runtime.sendMessage({ action: MESSAGE_TYPES.CAPTURE_PROMPT, diff --git a/apps/browser-extension/entrypoints/popup/App.tsx b/apps/browser-extension/entrypoints/popup/App.tsx index c6e8468c..06aee4a4 100644 --- a/apps/browser-extension/entrypoints/popup/App.tsx +++ b/apps/browser-extension/entrypoints/popup/App.tsx @@ -11,6 +11,57 @@ import { } from "../../utils/query-hooks" import type { Project } from "../../utils/types" +const Tooltip = ({ + children, + content, +}: { + children: React.ReactNode + content: string +}) => { + const [isVisible, setIsVisible] = useState(false) + + return ( + <div className="relative inline-flex items-center gap-1"> + <button + type="button" + onMouseEnter={() => setIsVisible(true)} + onMouseLeave={() => setIsVisible(false)} + className="cursor-help bg-transparent border-none p-0 text-left" + > + {children} + </button> + <button + type="button" + onMouseEnter={() => setIsVisible(true)} + onMouseLeave={() => setIsVisible(false)} + className="cursor-help bg-transparent border-none p-0 text-gray-400 hover:text-gray-600 transition-colors" + > + <svg + width="14" + height="14" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + strokeWidth="2" + strokeLinecap="round" + strokeLinejoin="round" + > + <title>More information</title> + <circle cx="12" cy="12" r="10" /> + <path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" /> + <line x1="12" y1="17" x2="12.01" y2="17" /> + </svg> + </button> + {isVisible && ( + <div className="absolute z-50 px-2 py-1 text-xs text-white bg-gray-800 rounded shadow-lg bottom-full right-0 mb-1 max-w-xs break-words"> + {content} + <div className="absolute top-full right-4 w-0 h-0 border-l-4 border-r-4 border-t-4 border-transparent border-t-gray-800" /> + </div> + )} + </div> + ) +} + function App() { const [userSignedIn, setUserSignedIn] = useState<boolean>(false) const [loading, setLoading] = useState<boolean>(true) @@ -22,6 +73,8 @@ function App() { "save", ) const [autoSearchEnabled, setAutoSearchEnabled] = useState<boolean>(false) + const [autoCapturePromptsEnabled, setAutoCapturePromptsEnabled] = + useState<boolean>(false) const [authInvalidated, setAuthInvalidated] = useState<boolean>(false) const queryClient = useQueryClient() @@ -43,6 +96,7 @@ function App() { const result = await chrome.storage.local.get([ STORAGE_KEYS.BEARER_TOKEN, STORAGE_KEYS.AUTO_SEARCH_ENABLED, + STORAGE_KEYS.AUTO_CAPTURE_PROMPTS_ENABLED, ]) const hasToken = !!result[STORAGE_KEYS.BEARER_TOKEN] @@ -70,6 +124,10 @@ function App() { const autoSearchSetting = result[STORAGE_KEYS.AUTO_SEARCH_ENABLED] ?? false setAutoSearchEnabled(autoSearchSetting) + + const autoCapturePromptsSetting = + result[STORAGE_KEYS.AUTO_CAPTURE_PROMPTS_ENABLED] ?? false + setAutoCapturePromptsEnabled(autoCapturePromptsSetting) } catch (error) { console.error("Error checking auth status:", error) setUserSignedIn(false) @@ -178,6 +236,17 @@ function App() { } } + const handleAutoCapturePromptsToggle = async (enabled: boolean) => { + try { + await chrome.storage.local.set({ + [STORAGE_KEYS.AUTO_CAPTURE_PROMPTS_ENABLED]: enabled, + }) + setAutoCapturePromptsEnabled(enabled) + } catch (error) { + console.error("Error updating auto capture prompts setting:", error) + } + } + const handleSignOut = async () => { try { await chrome.storage.local.remove([STORAGE_KEYS.BEARER_TOKEN]) @@ -457,15 +526,13 @@ function App() { <h3 className="text-base font-semibold text-black mb-3"> Chat Integration </h3> - <div className="flex items-center justify-between p-3 bg-gray-50 rounded-lg border border-gray-200"> - <div className="flex flex-col"> - <span className="text-sm font-medium text-black"> - Auto Search Memories - </span> - <span className="text-xs text-gray-500"> - Automatically search your memories while typing in chat - apps - </span> + <div className="flex items-center justify-between p-3 bg-gray-50 rounded-lg border border-gray-200 mb-3"> + <div className="flex items-center"> + <Tooltip content="Automatically search your memories while typing in chat apps"> + <span className="text-sm font-medium text-black cursor-help"> + Auto Search Memories + </span> + </Tooltip> </div> <label className="relative inline-flex items-center cursor-pointer"> <input @@ -479,10 +546,26 @@ function App() { <div className="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-gray-700" /> </label> </div> - <p className="text-xs text-gray-500 mt-2"> - When enabled, supermemory will search your memories as you - type in ChatGPT, Claude, and T3.chat - </p> + <div className="flex items-center justify-between p-3 bg-gray-50 rounded-lg border border-gray-200"> + <div className="flex items-center"> + <Tooltip content="Automatically save your prompts as memories in chat apps"> + <span className="text-sm font-medium text-black cursor-help"> + Auto Capture Prompts + </span> + </Tooltip> + </div> + <label className="relative inline-flex items-center cursor-pointer"> + <input + checked={autoCapturePromptsEnabled} + className="sr-only peer" + onChange={(e) => + handleAutoCapturePromptsToggle(e.target.checked) + } + type="checkbox" + /> + <div className="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-gray-700" /> + </label> + </div> </div> </div> )} diff --git a/apps/browser-extension/utils/constants.ts b/apps/browser-extension/utils/constants.ts index d459a0f0..16baaabd 100644 --- a/apps/browser-extension/utils/constants.ts +++ b/apps/browser-extension/utils/constants.ts @@ -22,6 +22,7 @@ export const STORAGE_KEYS = { TWITTER_AUTH_TOKEN: "twitter-auth-token", DEFAULT_PROJECT: "sm-default-project", AUTO_SEARCH_ENABLED: "sm-auto-search-enabled", + AUTO_CAPTURE_PROMPTS_ENABLED: "sm-auto-capture-prompts-enabled", } as const /** diff --git a/apps/browser-extension/wxt.config.ts b/apps/browser-extension/wxt.config.ts index 20435b6c..36c2863e 100644 --- a/apps/browser-extension/wxt.config.ts +++ b/apps/browser-extension/wxt.config.ts @@ -11,7 +11,7 @@ export default defineConfig({ manifest: { name: "supermemory", homepage_url: "https://supermemory.ai", - version: "6.0.100", + version: "6.0.101", permissions: ["contextMenus", "storage", "activeTab", "webRequest", "tabs"], host_permissions: [ "*://x.com/*", |