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
This commit is contained in:
Dhravya Shah 2025-10-20 18:15:07 -07:00 committed by GitHub
commit 88faba05ad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 167 additions and 42 deletions

View file

@ -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 = ""

View file

@ -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(

View file

@ -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 container = targetContainers[0]
if (!container) {
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)
})
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,

View file

@ -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>
)}

View file

@ -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
/**

View file

@ -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/*",