aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDhravya Shah <[email protected]>2025-10-20 18:15:07 -0700
committerGitHub <[email protected]>2025-10-20 18:15:07 -0700
commit88faba05adec152f5f57d005b835fa2729a6046f (patch)
tree443c52d8f8df733a865240fab9c4568229661da0
parentMerge pull request #501 from supermemoryai/10-19-fix_tools_update_the_docs_fo... (diff)
parentfeat: auto capture disabled by default (diff)
downloadsupermemory-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
-rw-r--r--apps/browser-extension/entrypoints/content/chatgpt.ts10
-rw-r--r--apps/browser-extension/entrypoints/content/claude.ts10
-rw-r--r--apps/browser-extension/entrypoints/content/t3.ts77
-rw-r--r--apps/browser-extension/entrypoints/popup/App.tsx109
-rw-r--r--apps/browser-extension/utils/constants.ts1
-rw-r--r--apps/browser-extension/wxt.config.ts2
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/*",