-
- Usage this period
+
+
+ {hasPaidPlan ? (
+
+ Credits
- Top-up credits{" "}
-
- (optional)
-
+ Top-up credits
- {creditRemaining > 0 ? "Add more" : "Add credits"}
+ {creditRemaining > 0 ? "Add more" : "Buy credits"}
- ) : null}
-
+
+ ) : null}
Invoice history
diff --git a/apps/web/components/settings/org-context.tsx b/apps/web/components/settings/org-context.tsx
index dac97f7e..8c17ed01 100644
--- a/apps/web/components/settings/org-context.tsx
+++ b/apps/web/components/settings/org-context.tsx
@@ -94,7 +94,7 @@ function PillButton({
children: React.ReactNode
onClick: () => void
disabled?: boolean
- variant?: "default" | "danger" | "primary"
+ variant?: "default" | "ghost" | "primary"
}) {
return (
-
setConfirmDialog(null)}>
+ setConfirmDialog(null)}
+ variant="ghost"
+ >
CANCEL
{updateSettings.isPending && (
From fc08bd891fe5d998e29560a3218a623584c94781 Mon Sep 17 00:00:00 2001
From: Vedant Mahajan
Date: Fri, 29 May 2026 23:47:19 +0530
Subject: [PATCH 4/9] Add memory drawer (#1015)
Co-authored-by: Ishaan Gupta
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5
---
.../document-modal/graph-list-memories.tsx | 7 +-
apps/web/components/document-modal/index.tsx | 279 ++++++++++++------
.../memory-graph/src/components/legend.tsx | 33 ++-
.../src/components/memory-graph.tsx | 10 +-
4 files changed, 226 insertions(+), 103 deletions(-)
diff --git a/apps/web/components/document-modal/graph-list-memories.tsx b/apps/web/components/document-modal/graph-list-memories.tsx
index c8f4ae8d..313424e7 100644
--- a/apps/web/components/document-modal/graph-list-memories.tsx
+++ b/apps/web/components/document-modal/graph-list-memories.tsx
@@ -169,9 +169,11 @@ function VersionStatus({
export function GraphListMemories({
memoryEntries,
documentId,
+ className,
}: {
memoryEntries: MemoryEntry[]
documentId?: string
+ className?: string
}) {
const { effectiveContainerTags } = useProject()
const [expandedMemories, setExpandedMemories] = useState>(
@@ -193,7 +195,10 @@ export function GraphListMemories({
return (
!open && onClose()}>
-
+ const hasPluginInsights =
+ pluginDocument &&
+ pluginDocument.kind !== "claude-code-doc" &&
+ pluginDocument.kind !== "openclaw-session"
+ const hasDocumentInsights = Boolean(
+ hasPluginInsights ||
+ _document?.summary ||
+ pluginDocument?.summary ||
+ (_document?.memoryEntries && _document.memoryEntries.length > 0),
+ )
+
+ const documentPreview = (
+
+
+
+ )
+
+ const documentInsights = (
+
+ {hasPluginInsights &&
}
+ {_document && (_document.summary || pluginDocument?.summary) && (
+
+ )}
+ {_document?.memoryEntries && _document.memoryEntries.length > 0 && (
+
+ )}
+
+ )
+
+ const modalContent = (
+ <>
+ {isMobile ? (
+
+ {_document?.title} - Document
+
+ ) : (
{_document?.title} - Document
-
-
-
-
-
- {pluginDocument?.kind === "claude-code-doc" &&
- _document?.customId && (
-
- )}
-
- {_document?.url && (
-
- {!isMobile && (
- Visit source
- )}
-
-
+ )}
+
+
+
+
+
+ {pluginDocument?.kind === "claude-code-doc" &&
+ _document?.customId && (
+
)}
+
+ {_document?.url && (
+
+ {!isMobile && Visit source}
+
+
+ )}
+ {isMobile ? (
+
+ ) : (
Close
-
+ )}
-
-
+ {isMobile && hasDocumentInsights ? (
+
+
+
+ Content
+
+
+ Insights
+
+
+
+ {documentPreview}
+
+
-
-
-
- {pluginDocument &&
- pluginDocument.kind !== "claude-code-doc" &&
- pluginDocument.kind !== "openclaw-session" && (
-
- )}
- {_document && (_document.summary || pluginDocument?.summary) && (
-
- )}
- {_document?.memoryEntries && _document.memoryEntries.length > 0 && (
-
- )}
-
+ {documentInsights}
+
+
+ ) : isMobile ? (
+
{documentPreview}
+ ) : (
+
+ {documentPreview}
+ {documentInsights}
+ )}
+ >
+ )
+
+ if (isMobile) {
+ return (
+
!open && onClose()}
+ shouldScaleBackground
+ >
+ div:first-child]:bg-[#3A4252] [&>div:first-child]:h-1 [&>div:first-child]:w-9 [&>div:first-child]:mt-2.5 [&>div:first-child]:mb-1",
+ dmSansClassName(),
+ )}
+ style={{
+ boxShadow:
+ "0 -12px 40px rgba(0, 0, 0, 0.45), 0.711px 0.711px 0.711px 0 rgba(255, 255, 255, 0.10) inset",
+ }}
+ >
+
+ {modalContent}
+
+
+
+ )
+ }
+
+ return (
+
!open && onClose()}>
+
+ {modalContent}
)
diff --git a/packages/memory-graph/src/components/legend.tsx b/packages/memory-graph/src/components/legend.tsx
index 724efdd7..bd6b2f3a 100644
--- a/packages/memory-graph/src/components/legend.tsx
+++ b/packages/memory-graph/src/components/legend.tsx
@@ -6,6 +6,8 @@ interface LegendProps {
edges?: GraphEdge[]
isLoading?: boolean
colors: GraphThemeColors
+ compact?: boolean
+ maxHeight?: number
}
function HexagonIcon({
@@ -191,6 +193,8 @@ export const Legend = memo(function Legend({
edges = [],
isLoading: _isLoading = false,
colors,
+ compact = false,
+ maxHeight,
}: LegendProps) {
const [isExpanded, setIsExpanded] = useState(false)
const [connectionsExpanded, setConnectionsExpanded] = useState(true)
@@ -201,7 +205,8 @@ export const Legend = memo(function Legend({
const outerStyle: React.CSSProperties = {
overflow: "hidden",
- width: 214,
+ width: compact ? "min(214px, calc(100vw - 32px))" : 214,
+ maxWidth: "100%",
}
const cardStyle: React.CSSProperties = {
@@ -209,6 +214,7 @@ export const Legend = memo(function Legend({
backgroundColor: colors.controlBg,
border: `1px solid ${colors.controlBorder}`,
boxShadow: "0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1)",
+ maxHeight,
}
const headerBtnStyle: React.CSSProperties = {
@@ -217,6 +223,7 @@ export const Legend = memo(function Legend({
alignItems: "center",
gap: 6,
width: "100%",
+ justifyContent: "flex-start",
cursor: "pointer",
outline: "none",
background: "none",
@@ -263,6 +270,21 @@ export const Legend = memo(function Legend({
gap: 8,
}
+ const expandedContentStyle: React.CSSProperties = {
+ marginTop: 16,
+ display: "flex",
+ flexDirection: "column",
+ gap: 16,
+ ...(compact
+ ? {
+ maxHeight: maxHeight ? Math.max(maxHeight - 56, 112) : 220,
+ overflowY: "auto",
+ overscrollBehavior: "contain",
+ paddingRight: 2,
+ }
+ : {}),
+ }
+
return (
@@ -281,14 +303,7 @@ export const Legend = memo(function Legend({
{isExpanded && (
-
+
{/* Statistics section */}
Statistics
diff --git a/packages/memory-graph/src/components/memory-graph.tsx b/packages/memory-graph/src/components/memory-graph.tsx
index ed5ec094..dd82f490 100644
--- a/packages/memory-graph/src/components/memory-graph.tsx
+++ b/packages/memory-graph/src/components/memory-graph.tsx
@@ -83,6 +83,9 @@ export function MemoryGraph({
const graphFitHeight = isCompactViewport
? Math.max(containerSize.height - 170, 240)
: containerSize.height
+ const compactLegendMaxHeight = isCompactViewport
+ ? Math.max(containerSize.height - 104, 160)
+ : undefined
// Rebuild version chain index during render (not in an effect) so that
// the chain data is up-to-date when getChain() is called in useMemo below.
@@ -644,13 +647,14 @@ export function MemoryGraph({
const bottomLeftStackStyle: React.CSSProperties = {
position: "absolute",
- bottom: 16,
- left: 16,
+ bottom: isCompactViewport ? 12 : 16,
+ left: isCompactViewport ? 12 : 16,
zIndex: 20,
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
gap: 8,
+ maxWidth: isCompactViewport ? "calc(100% - 24px)" : undefined,
}
return (
@@ -722,7 +726,9 @@ export function MemoryGraph({
From ab068e2ba57867733702cd66086ce52f1563125b Mon Sep 17 00:00:00 2001
From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com>
Date: Fri, 29 May 2026 19:54:13 +0000
Subject: [PATCH 5/9] fix(web): restore Nova onboarding analytics events
(#1023)
The onboarding rework moved the flow to app/(app)/onboarding and dropped the funnel tracking, so onboarding_completed stopped firing on 2026-05-02.
- Wire onboarding_step_viewed across idle/processing/done/error transitions
- Fire onboarding_completed on real completion (status=done) with source + memories_count
- onboarding_profile_submitted now carries { source }
- Add onboarding_skipped { from_step }
- Remove dead onboardingCompleted() from InitialHeader and unused name/relatable helpers
---
apps/web/app/(app)/onboarding/page.tsx | 29 ++++++++++++++--
apps/web/components/initial-header.tsx | 2 --
apps/web/components/integrations-view.tsx | 42 +++++++++++++++++++----
apps/web/lib/analytics.ts | 42 ++++++++++++-----------
4 files changed, 84 insertions(+), 31 deletions(-)
diff --git a/apps/web/app/(app)/onboarding/page.tsx b/apps/web/app/(app)/onboarding/page.tsx
index 2c5eaf07..3d67b3ba 100644
--- a/apps/web/app/(app)/onboarding/page.tsx
+++ b/apps/web/app/(app)/onboarding/page.tsx
@@ -41,7 +41,7 @@ import {
CheckCircle2,
Loader2,
} from "lucide-react"
-import { analytics } from "@/lib/analytics"
+import { analytics, type OnboardingStep } from "@/lib/analytics"
import { consumePendingConnectUrl } from "@/lib/constants"
type DetectedSource = "x" | "linkedin" | "resume" | null
@@ -378,6 +378,13 @@ function isAccountSource(source: DetectedSource): source is "x" | "linkedin" {
return source === "x" || source === "linkedin"
}
+const STATUS_TO_STEP: Record
= {
+ idle: "profile_input",
+ processing: "processing",
+ done: "done",
+ error: "error",
+}
+
function useSpotlightAutoRotation(
status: Status,
pauseSpotlight: boolean,
@@ -555,6 +562,7 @@ export default function OnboardingPage() {
const fileRef = useRef(null)
const pollingRef = useRef | null>(null)
const skippingRef = useRef(false)
+ const completedTrackedRef = useRef(false)
const [isSkipping, setIsSkipping] = useState(false)
const [spotlightCategory, setSpotlightCategory] =
useState("productivity")
@@ -591,6 +599,21 @@ export default function OnboardingPage() {
usePollingCleanup(pollingRef)
useDoneAnimation(status, setStampLanded, setVisibleSnippets)
+ // biome-ignore lint/correctness/useExhaustiveDependencies: fire per status transition only
+ useEffect(() => {
+ analytics.onboardingStepViewed({
+ step: STATUS_TO_STEP[status],
+ trigger: "auto",
+ })
+ if (status === "done" && !completedTrackedRef.current) {
+ completedTrackedRef.current = true
+ analytics.onboardingCompleted({
+ source: isAccountSource(detected) ? detected : undefined,
+ memories_count: memoriesCount,
+ })
+ }
+ }, [status])
+
const handleChange = (v: string) => {
setValue(v)
setDetected(detectSource(v))
@@ -619,6 +642,7 @@ export default function OnboardingPage() {
if (skippingRef.current) return
skippingRef.current = true
setIsSkipping(true)
+ analytics.onboardingSkipped({ from_step: STATUS_TO_STEP[status] })
try {
await ensureOrg()
const pendingPath = consumePendingConnectUrl()
@@ -628,7 +652,7 @@ export default function OnboardingPage() {
skippingRef.current = false
setIsSkipping(false)
}
- }, [ensureOrg, router])
+ }, [ensureOrg, router, status])
const pollDocument = useCallback((docId: string) => {
const maxAttempts = 60
@@ -688,6 +712,7 @@ export default function OnboardingPage() {
const handleSubmit = useCallback(
async (source: "x" | "linkedin" | "resume", resumeFileOverride?: File) => {
+ analytics.onboardingProfileSubmitted({ source })
setStatus("processing")
setSpotlightCategory("productivity")
setPauseSpotlight(false)
diff --git a/apps/web/components/initial-header.tsx b/apps/web/components/initial-header.tsx
index 831fb77c..95bc9628 100644
--- a/apps/web/components/initial-header.tsx
+++ b/apps/web/components/initial-header.tsx
@@ -4,7 +4,6 @@ import { Logo } from "@ui/assets/Logo"
import { Button } from "@ui/components/button"
import { useRouter } from "next/navigation"
import { useOrgOnboarding } from "@hooks/use-org-onboarding"
-import { analytics } from "@/lib/analytics"
import { consumePendingConnectUrl } from "@/lib/constants"
import { cn } from "@lib/utils"
@@ -23,7 +22,6 @@ export function InitialHeader({
const handleSkip = () => {
markOrgOnboarded()
- analytics.onboardingCompleted()
const pendingPath = consumePendingConnectUrl()
router.push(pendingPath ?? "/")
}
diff --git a/apps/web/components/integrations-view.tsx b/apps/web/components/integrations-view.tsx
index e602f070..5a5a7161 100644
--- a/apps/web/components/integrations-view.tsx
+++ b/apps/web/components/integrations-view.tsx
@@ -1135,7 +1135,10 @@ export function IntegrationsView() {
}
throw new Error(response.error?.message || "Failed to connect")
},
- onMutate: (provider) => setConnectingProvider(provider),
+ onMutate: (provider) => {
+ setConnectingProvider(provider)
+ analytics.connectionAuthStarted({ provider })
+ },
onError: (err) => {
setConnectingProvider(null)
toast.error("Failed to connect", {
@@ -1349,6 +1352,13 @@ export function IntegrationsView() {
return true
})
+ const trackCard = (item: Item) =>
+ analytics.integrationCardClicked({
+ kind: item.kind,
+ id: item.id,
+ name: item.name,
+ })
+
const renderRight = (item: Item): ReactNode => {
switch (item.kind) {
case "plugin": {
@@ -1370,7 +1380,10 @@ export function IntegrationsView() {
const busy = connectingPlugin === item.pluginId
return (
createPluginKeyMutation.mutate(item.pluginId)}
+ onClick={() => {
+ trackCard(item)
+ createPluginKeyMutation.mutate(item.pluginId)
+ }}
disabled={!!connectingPlugin}
>
{busy ? (
@@ -1397,7 +1410,10 @@ export function IntegrationsView() {
const busy = connectingProvider === item.provider
return (
addConnectionMutation.mutate(item.provider)}
+ onClick={() => {
+ trackCard(item)
+ addConnectionMutation.mutate(item.provider)
+ }}
disabled={!!connectingProvider}
>
{busy ? (
@@ -1415,6 +1431,7 @@ export function IntegrationsView() {
return (
{
+ trackCard(item)
window.open(
(item.action as { type: "external"; href: string }).href,
"_blank",
@@ -1431,12 +1448,13 @@ export function IntegrationsView() {
}
return (
+ onClick={() => {
+ trackCard(item)
setViewMode(
(item.action as { type: "view"; viewMode: ViewParamValue })
.viewMode,
)
- }
+ }}
>
Connect
@@ -1444,13 +1462,23 @@ export function IntegrationsView() {
}
case "mcp-client":
return (
- openMcpClient(item.clientKey)}>
+ {
+ trackCard(item)
+ openMcpClient(item.clientKey)
+ }}
+ >
Connect
)
case "import":
return (
- setViewMode(item.viewMode)}>
+ {
+ trackCard(item)
+ setViewMode(item.viewMode)
+ }}
+ >
Connect
)
diff --git a/apps/web/lib/analytics.ts b/apps/web/lib/analytics.ts
index d762654e..132ebeb3 100644
--- a/apps/web/lib/analytics.ts
+++ b/apps/web/lib/analytics.ts
@@ -1,5 +1,8 @@
import posthog from "posthog-js"
+export type OnboardingStep = "profile_input" | "processing" | "done" | "error"
+export type OnboardingSource = "x" | "linkedin" | "resume"
+
// Helper function to safely capture events
const safeCapture = (
eventName: string,
@@ -40,12 +43,13 @@ export const analytics = {
upgradeCompleted: () => safeCapture("upgrade_completed"),
billingPortalOpened: () => safeCapture("billing_portal_opened"),
- connectionAdded: (provider: string) =>
- safeCapture("connection_added", { provider }),
connectionDeleted: () => safeCapture("connection_deleted"),
- connectionAuthStarted: () => safeCapture("connection_auth_started"),
- connectionAuthCompleted: () => safeCapture("connection_auth_completed"),
- connectionAuthFailed: () => safeCapture("connection_auth_failed"),
+ connectionAuthStarted: (props: { provider: string }) =>
+ safeCapture("connection_auth_started", props),
+
+ // integrations surface (main Nova page)
+ integrationCardClicked: (props: { kind: string; id: string; name: string }) =>
+ safeCapture("integration_card_clicked", props),
nextAppResearchCtaDismissed: () =>
safeCapture("next_app_research_cta_dismissed"),
@@ -72,21 +76,13 @@ export const analytics = {
addDocumentModalOpened: () => safeCapture("add_document_modal_opened"),
// onboarding analytics
- onboardingStepViewed: (props: { step: string; trigger: "user" | "auto" }) =>
- safeCapture("onboarding_step_viewed", props),
+ onboardingStepViewed: (props: {
+ step: OnboardingStep
+ trigger: "user" | "auto"
+ }) => safeCapture("onboarding_step_viewed", props),
- onboardingNameSubmitted: (props: { name_length: number }) =>
- safeCapture("onboarding_name_submitted", props),
-
- onboardingProfileSubmitted: (props: {
- has_twitter: boolean
- has_linkedin: boolean
- other_links_count: number
- description_length: number
- }) => safeCapture("onboarding_profile_submitted", props),
-
- onboardingRelatableSelected: (props: { options: string[] }) =>
- safeCapture("onboarding_relatable_selected", props),
+ onboardingProfileSubmitted: (props: { source: OnboardingSource }) =>
+ safeCapture("onboarding_profile_submitted", props),
onboardingIntegrationClicked: (props: { integration: string }) =>
safeCapture("onboarding_integration_clicked", props),
@@ -100,7 +96,13 @@ export const analytics = {
onboardingXBookmarksDetailOpened: () =>
safeCapture("onboarding_x_bookmarks_detail_opened"),
- onboardingCompleted: () => safeCapture("onboarding_completed"),
+ onboardingSkipped: (props: { from_step: OnboardingStep }) =>
+ safeCapture("onboarding_skipped", props),
+
+ onboardingCompleted: (props?: {
+ source?: OnboardingSource
+ memories_count?: number
+ }) => safeCapture("onboarding_completed", props),
// main app analytics
searchOpened: (props: {
From 3160358bfdf1a69b2664bdf42797bddb2b2d809f Mon Sep 17 00:00:00 2001
From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com>
Date: Sat, 30 May 2026 16:38:10 +0000
Subject: [PATCH 6/9] fix(extension): resolve sign-in loop and stale spaces
(#1016)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## What
Fixes two bugs reported by a customer (Plain T-1289) using the Supermemory browser extension.
### Bug 1 — extension sign-in loop
When a user logs out of the _extension_ but is still authenticated in the _web app_, the extension's Sign-in button opens `/login`, which short-circuited via a bare `router.replace("/")`. That path never carried the `extension-auth-success` flag the dashboard waits on before `postMessage`\-ing the session token to the extension content script — so the extension never received a token and stayed stuck on "Sign in" indefinitely.
Now the already-authenticated redirect carries `?extension-auth-success=true`, matching the existing fresh-login callback behavior (no new token exposure).
### Bug 2 — stale / deleted spaces
The extension's stored default space (`local:sm-default-project`) was only set when none existed, never reconciled. After renaming/deleting spaces in the web app, the popup kept showing save buttons pointing at dead spaces. Now the popup reconciles the stored default against the freshly-fetched live list: resets to the first space if the stored one was deleted, and refreshes the cached copy (label/containerTag) if it was renamed.
---
.../browser-extension/entrypoints/popup/App.tsx | 17 ++++++++++++++---
apps/browser-extension/wxt.config.ts | 2 +-
apps/web/app/(auth)/login/page.tsx | 13 +++++--------
3 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/apps/browser-extension/entrypoints/popup/App.tsx b/apps/browser-extension/entrypoints/popup/App.tsx
index 498a75a2..ac646ff7 100644
--- a/apps/browser-extension/entrypoints/popup/App.tsx
+++ b/apps/browser-extension/entrypoints/popup/App.tsx
@@ -175,10 +175,21 @@ function App() {
setShowProjectSelector(true)
}
+ // Reconcile stored default against live list: reset if deleted, refresh if renamed.
useEffect(() => {
- if (!defaultProject && projects.length > 0) {
- const firstProject = projects[0]
- setDefaultProjectMutation.mutate(firstProject)
+ if (projects.length === 0) return
+ if (!defaultProject) {
+ setDefaultProjectMutation.mutate(projects[0])
+ return
+ }
+ const live = projects.find((p) => p.id === defaultProject.id)
+ if (!live) {
+ setDefaultProjectMutation.mutate(projects[0])
+ } else if (
+ live.name !== defaultProject.name ||
+ live.containerTag !== defaultProject.containerTag
+ ) {
+ setDefaultProjectMutation.mutate(live)
}
}, [defaultProject, projects, setDefaultProjectMutation])
diff --git a/apps/browser-extension/wxt.config.ts b/apps/browser-extension/wxt.config.ts
index c810e73f..b7b6147f 100644
--- a/apps/browser-extension/wxt.config.ts
+++ b/apps/browser-extension/wxt.config.ts
@@ -29,7 +29,7 @@ export default defineConfig({
manifest: {
name: "supermemory",
homepage_url: "https://supermemory.ai",
- version: "6.1.3",
+ version: "6.1.4",
permissions: ["storage", "activeTab", "webRequest", "tabs"],
host_permissions: [
"*://x.com/*",
diff --git a/apps/web/app/(auth)/login/page.tsx b/apps/web/app/(auth)/login/page.tsx
index 49fc56fc..dbdacdfc 100644
--- a/apps/web/app/(auth)/login/page.tsx
+++ b/apps/web/app/(auth)/login/page.tsx
@@ -140,14 +140,11 @@ export default function LoginPage() {
)
return
}
- router.replace("/")
- }, [
- sessionPending,
- sessionData?.session,
- oauthQueryForResume,
- params,
- router,
- ])
+ // Carry the flag so the dashboard posts the session token to the extension (else: sign-in loop).
+ const dest = new URL("/", window.location.origin)
+ dest.searchParams.set("extension-auth-success", "true")
+ window.location.assign(dest.toString())
+ }, [sessionPending, sessionData?.session, oauthQueryForResume, params])
// Get redirect URL from query params
const redirectUrl = params.get("redirect")
From 7c2de3c9e5d242094ac841447bbf1ac26a22f806 Mon Sep 17 00:00:00 2001
From: Ishaan Gupta
Date: Sun, 31 May 2026 03:17:44 +0530
Subject: [PATCH 7/9] add web upgrade plans UI (#1022)
---
apps/web/components/header.tsx | 32 ++
apps/web/components/settings/billing.tsx | 379 +++++++++++++++++++++--
apps/web/lib/url-helpers.ts | 18 ++
3 files changed, 405 insertions(+), 24 deletions(-)
diff --git a/apps/web/components/header.tsx b/apps/web/components/header.tsx
index fd81bf52..c70c62d0 100644
--- a/apps/web/components/header.tsx
+++ b/apps/web/components/header.tsx
@@ -19,6 +19,7 @@ import {
import { Button } from "@ui/components/button"
import { cn } from "@lib/utils"
import { dmSansClassName } from "@/lib/fonts"
+import { getBillingSettingsUrl } from "@/lib/url-helpers"
import { GraphIcon, IntegrationsIcon } from "@/components/integration-icons"
import {
DropdownMenu,
@@ -80,6 +81,7 @@ export function Header({ onAddMemory, onOpenSearch }: HeaderProps) {
feedbackParam,
)
const { viewMode, setViewMode } = useViewMode()
+ const billingSettingsUrl = getBillingSettingsUrl()
const handleFeedback = () => setFeedbackOpen(true)
@@ -352,6 +354,15 @@ export function Header({ onAddMemory, onOpenSearch }: HeaderProps) {
"linear-gradient(180deg, #0A0E14 0%, #05070A 100%)",
}}
>
+
+
+
+ Upgrade
+
+
) : (
<>
+
+
+
+
+
+ Upgrade
+
+
+
+
+ setPlanPage(0)}
+ disabled={planPage === 0}
+ className="flex size-8 items-center justify-center rounded-full border border-white/[0.08] bg-white/[0.02] text-[#A3A3A3] transition-colors hover:bg-white/[0.05] hover:text-[#FAFAFA] disabled:cursor-not-allowed disabled:opacity-35"
+ aria-label="Show Free and Pro plans"
+ >
+
+
+ setPlanPage(1)}
+ disabled={planPage === 1}
+ className="flex size-8 items-center justify-center rounded-full border border-white/[0.08] bg-white/[0.02] text-[#A3A3A3] transition-colors hover:bg-white/[0.05] hover:text-[#FAFAFA] disabled:cursor-not-allowed disabled:opacity-35"
+ aria-label="Show Scale and Enterprise plans"
+ >
+
+
+
+ ) : undefined
+ }
+ >
+ Plans
+
+
+
+
+ {PLAN_CARDS.map((plan) => (
+
+ ))}
+
+
+ {ADVANCED_PLAN_CARDS.map((plan) => (
+
+ ))}
+
+
+
+ {isPlanCarouselActive ? null : (
+
+ {
+ setIsPlanCarouselActive(true)
+ setPlanPage(1)
+ }}
+ className={cn(
+ dmSans125ClassName(),
+ "inline-flex items-center justify-center gap-2 text-[13px] font-semibold text-[#A3A3A3] transition-colors hover:text-[#FAFAFA]",
+ )}
+ >
+
+ Other plans
+
+
+ →
+
+
+
+ )}
+
+
Date: Sun, 31 May 2026 03:26:51 +0530
Subject: [PATCH 8/9] fix settings/integrations responsiveness (#1003)
---
apps/web/components/settings/integrations.tsx | 45 ++++++++++++-------
1 file changed, 30 insertions(+), 15 deletions(-)
diff --git a/apps/web/components/settings/integrations.tsx b/apps/web/components/settings/integrations.tsx
index 125cec90..355a51e1 100644
--- a/apps/web/components/settings/integrations.tsx
+++ b/apps/web/components/settings/integrations.tsx
@@ -84,7 +84,7 @@ function PillButton({
className={cn(
"relative flex items-center justify-center gap-2",
"bg-[#0D121A]",
- "rounded-full h-11 px-4 flex-1",
+ "rounded-full h-11 min-w-0 px-3 flex-1 sm:px-4",
"cursor-pointer transition-opacity hover:opacity-80",
"shadow-[inset_1.5px_1.5px_4.5px_rgba(0,0,0,0.7)]",
"disabled:opacity-50 disabled:cursor-not-allowed",
@@ -244,6 +244,15 @@ export default function Integrations() {
analytics.extensionInstallClicked()
}
+ const addShortcutLabel =
+ createApiKeyMutation.isPending && selectedShortcutType === "add"
+ ? "Creating..."
+ : "Add shortcut"
+ const searchShortcutLabel =
+ createApiKeyMutation.isPending && selectedShortcutType === "search"
+ ? "Creating..."
+ : "Search shortcut"
+
const handleDialogClose = (open: boolean) => {
setShowApiKeyModal(open)
if (!open) {
@@ -331,7 +340,7 @@ export default function Integrations() {
-
+
handleShortcutClick("add")}
disabled={createApiKeyMutation.isPending}
@@ -342,11 +351,14 @@ export default function Integrations() {
) : (
)}
-
- {createApiKeyMutation.isPending &&
- selectedShortcutType === "add"
- ? "Creating..."
- : "Add memory shortcut"}
+
+ {addShortcutLabel}
+
+ {createApiKeyMutation.isPending &&
+ selectedShortcutType === "add"
+ ? "Creating..."
+ : "Add memory shortcut"}
+
)}
-
- {createApiKeyMutation.isPending &&
- selectedShortcutType === "search"
- ? "Creating..."
- : "Search memory shortcut"}
+
+ {searchShortcutLabel}
+
+ {createApiKeyMutation.isPending &&
+ selectedShortcutType === "search"
+ ? "Creating..."
+ : "Search memory shortcut"}
+
@@ -397,7 +412,7 @@ export default function Integrations() {
-
+
)}
-
+
{createRaycastApiKeyMutation.isPending
? "Generating..."
: "Get API key"}
@@ -415,7 +430,7 @@ export default function Integrations() {
-
+
Install extension
From 4eb8399358ce0383214862b705307acc7cb06889 Mon Sep 17 00:00:00 2001
From: Dhravya Shah
Date: Sat, 30 May 2026 16:35:37 -0700
Subject: [PATCH 9/9] Enhance README with additional context on usage
Expanded description to include personal/company use.
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index a134afad..7760c85b 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
- State-of-the-art memory and context engine for AI.
+ State-of-the-art memory and context engine for AI. And yes - you can use it as a company/personal brain.