diff --git a/apps/web/components/chat/index.tsx b/apps/web/components/chat/index.tsx index 70f01d062..1e29535d6 100644 --- a/apps/web/components/chat/index.tsx +++ b/apps/web/components/chat/index.tsx @@ -1612,11 +1612,11 @@ export function ChatSidebar({ ] for (const t of filtered) { const ts = new Date(t.updatedAt).getTime() - if (ts >= startOfToday) buckets[0].items.push(t) - else if (ts >= startOfToday - day) buckets[1].items.push(t) - else if (ts >= startOfToday - 7 * day) buckets[2].items.push(t) - else if (ts >= startOfToday - 30 * day) buckets[3].items.push(t) - else buckets[4].items.push(t) + if (ts >= startOfToday) buckets[0]?.items.push(t) + else if (ts >= startOfToday - day) buckets[1]?.items.push(t) + else if (ts >= startOfToday - 7 * day) buckets[2]?.items.push(t) + else if (ts >= startOfToday - 30 * day) buckets[3]?.items.push(t) + else buckets[4]?.items.push(t) } return buckets.filter((b) => b.items.length > 0) }, [threads, historySearch]) diff --git a/apps/web/components/memory-graph/graph-card.tsx b/apps/web/components/memory-graph/graph-card.tsx index de8bed3d2..083bb2862 100644 --- a/apps/web/components/memory-graph/graph-card.tsx +++ b/apps/web/components/memory-graph/graph-card.tsx @@ -67,15 +67,13 @@ export function StaticGraphPreview({ const result: { x1: number; y1: number; x2: number; y2: number }[] = [] const edgeCount = Math.min(nodes.length - 1, 20) for (let i = 0; i < edgeCount; i++) { - const a = Math.floor(rand() * nodes.length) - let b = Math.floor(rand() * nodes.length) - if (b === a) b = (a + 1) % nodes.length - result.push({ - x1: nodes[a]?.x, - y1: nodes[a]?.y, - x2: nodes[b]?.x, - y2: nodes[b]?.y, - }) + const aIdx = Math.floor(rand() * nodes.length) + let bIdx = Math.floor(rand() * nodes.length) + if (bIdx === aIdx) bIdx = (aIdx + 1) % nodes.length + const a = nodes[aIdx] + const b = nodes[bIdx] + if (!a || !b) continue + result.push({ x1: a.x, y1: a.y, x2: b.x, y2: b.y }) } return result }, [nodes]) diff --git a/apps/web/components/orbit-memory.tsx b/apps/web/components/orbit-memory.tsx index 757d2a6df..8923da13f 100644 --- a/apps/web/components/orbit-memory.tsx +++ b/apps/web/components/orbit-memory.tsx @@ -48,7 +48,7 @@ const INTEG: { key?: string label?: string sub?: string - ring: number + ring: 0 | 1 ang: number size: number dim: boolean @@ -76,8 +76,8 @@ const DW = 780 const DH = 1024 const CX = 390 const CY = 512 -const RR = [200, 335] -const SPEED = [1.0, 0.78] +const RR: [number, number] = [200, 335] +const SPEED: [number, number] = [1.0, 0.78] const DRAW: [number, number, number, string][] = [ [125, 0.28, 1.7, "#74a8f6"], [200, 0.18, 1.9, "#4389ff"], @@ -167,16 +167,15 @@ export default function OrbitMemory({ track.setAttribute("stroke-opacity", "0") dtrack.setAttribute("stroke-opacity", "0") for (let k = 0; k < NC; k++) { - cms[k].setAttribute("opacity", "0") - cmgs[k].setAttribute("opacity", "0") - oms[k].setAttribute("opacity", "0") - omgs[k].setAttribute("opacity", "0") + cms[k]?.setAttribute("opacity", "0") + cmgs[k]?.setAttribute("opacity", "0") + oms[k]?.setAttribute("opacity", "0") + omgs[k]?.setAttribute("opacity", "0") } } let angle = 0 const place = () => { - for (let i = 0; i < INTEG.length; i++) { - const it = INTEG[i] + for (const [i, it] of INTEG.entries()) { const a = ((it.ang + angle * SPEED[it.ring]) * Math.PI) / 180 const R = RR[it.ring] const ux = CX + R * Math.cos(a) @@ -199,8 +198,8 @@ export default function OrbitMemory({ const DISC = 700 const INN: number[] = [] const OUT: number[] = [] - for (let i = 0; i < INTEG.length; i++) { - ;(INTEG[i].ring === 0 ? INN : OUT).push(i) + for (const [i, it] of INTEG.entries()) { + ;(it.ring === 0 ? INN : OUT).push(i) } let phase = "orbit" let pT0 = 0 @@ -259,12 +258,16 @@ export default function OrbitMemory({ const ay = pyc - uy * HL const bx = pxc + ux * HL const by = pyc + uy * HL - setLine(gr[k], ax, ay, bx, by) - setLine(cr[k], ax, ay, bx, by) - setLine(gl[k], ax, ay, bx, by) + const grad = gr[k] + const comet = cr[k] + const glow = gl[k] + if (!grad || !comet || !glow) continue + setLine(grad, ax, ay, bx, by) + setLine(comet, ax, ay, bx, by) + setLine(glow, ax, ay, bx, by) const o = Math.sin(f * Math.PI) * P - cr[k].setAttribute("opacity", o.toFixed(2)) - gl[k].setAttribute("opacity", (0.6 * o).toFixed(2)) + comet.setAttribute("opacity", o.toFixed(2)) + glow.setAttribute("opacity", (0.6 * o).toFixed(2)) } } const frame = (now: number) => { @@ -276,13 +279,13 @@ export default function OrbitMemory({ if (phase === "orbit" && pt > ORBIT) { phase = "receive" pT0 = now - src = INN[(ci * 5) % INN.length] - dst = OUT[(ci * 7) % OUT.length] + src = INN[(ci * 5) % INN.length] ?? 0 + dst = OUT[(ci * 7) % OUT.length] ?? 0 ci++ nodes[src]?.classList.add("sm-active") stage.style.setProperty( "--cm", - `rgb(${ACCENT[INTEG[src].key!] || "91,157,255"})`, + `rgb(${ACCENT[INTEG[src]?.key ?? ""] || "91,157,255"})`, ) } else if (phase === "receive" && pt > RECV) { phase = "send" @@ -318,8 +321,8 @@ export default function OrbitMemory({ seg( now, track, - INTEG[src]._x!, - INTEG[src]._y!, + INTEG[src]?._x ?? 0, + INTEG[src]?._y ?? 0, ps, grads, cms, @@ -330,8 +333,8 @@ export default function OrbitMemory({ seg( now, dtrack, - INTEG[dst]._x!, - INTEG[dst]._y!, + INTEG[dst]?._x ?? 0, + INTEG[dst]?._y ?? 0, pd, ogrs, oms, @@ -508,7 +511,9 @@ export default function OrbitMemory({ {it.sub} @@ -518,7 +523,9 @@ export default function OrbitMemory({ )} diff --git a/apps/web/components/settings/integrations.tsx b/apps/web/components/settings/integrations.tsx index 355a51e12..a04db3838 100644 --- a/apps/web/components/settings/integrations.tsx +++ b/apps/web/components/settings/integrations.tsx @@ -152,7 +152,10 @@ export default function Integrations() { name: `ios-${generateId().slice(0, 8)}`, prefix: `sm_${org?.id}_`, }) - return res.key + if (res.error) + throw new Error("Failed to create API key", { cause: res.error }) + if (!res.data?.key) throw new Error("API key missing from response") + return res.data.key }, onSuccess: (key) => { setApiKey(key) @@ -182,7 +185,7 @@ export default function Integrations() { prefix: `sm_${org.id}_`, }) if (res.error) - throw new Error(res.error.message ?? "Failed to create API key") + throw new Error("Failed to create API key", { cause: res.error }) if (!res.data?.key) throw new Error("API key missing from response") return res.data.key }, diff --git a/apps/web/components/user-profile-menu.tsx b/apps/web/components/user-profile-menu.tsx index ea034d733..1854cde8a 100644 --- a/apps/web/components/user-profile-menu.tsx +++ b/apps/web/components/user-profile-menu.tsx @@ -79,9 +79,11 @@ export function UserProfileMenu({ const initials = (() => { if (user.name) { const parts = user.name.trim().split(/\s+/) + const first = parts[0] ?? "" + const last = parts[parts.length - 1] ?? "" return parts.length >= 2 - ? `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase() - : parts[0].slice(0, 2).toUpperCase() + ? `${first.slice(0, 1)}${last.slice(0, 1)}`.toUpperCase() + : first.slice(0, 2).toUpperCase() } if (user.email) return user.email.slice(0, 2).toUpperCase() return "SM" diff --git a/apps/web/hooks/use-reset-organization.ts b/apps/web/hooks/use-reset-organization.ts index 4c71580fb..f920d55ee 100644 --- a/apps/web/hooks/use-reset-organization.ts +++ b/apps/web/hooks/use-reset-organization.ts @@ -11,7 +11,7 @@ export function useResetOrganization() { mutationFn: async (body: { confirmation: string }) => { const res = await $fetch("@post/settings/reset", { body, - retry: { attempts: 0 }, + retry: 0, }) if (res.error) { const e = res.error as Record diff --git a/apps/web/stores/chat.ts b/apps/web/stores/chat.ts index 456217b7f..f815bb826 100644 --- a/apps/web/stores/chat.ts +++ b/apps/web/stores/chat.ts @@ -27,8 +27,6 @@ export function areUIMessageArraysEqual( return false } - if (msgA.content !== msgB.content) return false - if (JSON.stringify(msgA.parts) !== JSON.stringify(msgB.parts)) { return false } @@ -202,7 +200,8 @@ export function usePersistentChat() { ) const conversations: ConversationSummary[] = (() => { - const convs = projectState?.conversations ?? {} + const convs: Record = + projectState?.conversations ?? {} return Object.entries(convs).map(([id, rec]) => ({ id, title: rec.title, diff --git a/apps/web/stores/index.ts b/apps/web/stores/index.ts index e13cccef6..85dd569a0 100644 --- a/apps/web/stores/index.ts +++ b/apps/web/stores/index.ts @@ -21,7 +21,7 @@ export function useProject() { const normalizedProjects = selectedProjects.length === 0 ? [defaultTag] : selectedProjects - const selectedProject = normalizedProjects[0] + const selectedProject = normalizedProjects[0] ?? defaultTag const effectiveContainerTags = normalizedProjects diff --git a/packages/memory-graph/src/hooks/use-graph-data.ts b/packages/memory-graph/src/hooks/use-graph-data.ts index aed2d6f01..71fd3a29f 100644 --- a/packages/memory-graph/src/hooks/use-graph-data.ts +++ b/packages/memory-graph/src/hooks/use-graph-data.ts @@ -507,8 +507,7 @@ export function useGraphData( // Golden angle (~137.5 deg) produces optimal packing in a spiral const goldenAngle = Math.PI * (3 - Math.sqrt(5)) - for (let docIdx = 0; docIdx < docCount; docIdx++) { - const doc = documents[docIdx] + for (const [docIdx, doc] of documents.entries()) { const docCluster = getDocumentClusterAssignment(doc, clusterAssignments) const angle = docIdx * goldenAngle const radius = spiralScale * Math.sqrt((docIdx + 1) / docCount) diff --git a/packages/ui/assets/icons.tsx b/packages/ui/assets/icons.tsx index 7aaece871..035328661 100644 --- a/packages/ui/assets/icons.tsx +++ b/packages/ui/assets/icons.tsx @@ -1,3 +1,5 @@ +import type { CSSProperties } from "react" + export const OneDrive = ({ className }: { className?: string }) => ( ( ) -export const SyncLogoIcon = ({ className }: { className?: string }) => { +export const SyncLogoIcon = ({ + className, + style, +}: { + className?: string + style?: CSSProperties +}) => { return ( { fill="none" xmlns="http://www.w3.org/2000/svg" className={className} + style={style} > Sync Logo