total-recall-brain 3.13.0 → 3.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/README.md +91 -108
  2. package/bin/antigravity.mjs +81 -52
  3. package/bin/total-recall.mjs +32 -57
  4. package/extension/background.js +1 -1
  5. package/extension/options/options.js +9 -3
  6. package/extension/sidepanel/sidepanel.js +0 -2
  7. package/frontend/index.html +4 -3
  8. package/frontend/package.json +1 -0
  9. package/frontend/src/App.tsx +109 -152
  10. package/frontend/src/api.ts +605 -23
  11. package/frontend/src/components/BrainSelector.tsx +211 -199
  12. package/frontend/src/components/DocumentEditorModal.tsx +57 -0
  13. package/frontend/src/components/DocumentTable.tsx +47 -0
  14. package/frontend/src/components/Graph3D.tsx +120 -71
  15. package/frontend/src/components/UsageChart.tsx +3 -3
  16. package/frontend/src/components/brand/BrandMark.tsx +95 -0
  17. package/frontend/src/index.css +286 -86
  18. package/frontend/src/pages/ApiKeysPage.tsx +1878 -215
  19. package/frontend/src/pages/ChatPage.tsx +103 -45
  20. package/frontend/src/pages/DesignDocsPage.tsx +5 -5
  21. package/frontend/src/pages/FilesPage.tsx +10 -6
  22. package/frontend/src/pages/GraphPage.tsx +5 -3
  23. package/frontend/src/pages/HelpPage.tsx +2 -2
  24. package/frontend/src/pages/InboxPage.tsx +82 -0
  25. package/frontend/src/pages/InstructionsPage.tsx +1 -1
  26. package/frontend/src/pages/IntegrationsPage.tsx +21 -10
  27. package/frontend/src/pages/LoginPage.tsx +95 -77
  28. package/frontend/src/pages/MemoryPage.tsx +31 -8
  29. package/frontend/src/pages/OnboardingPage.tsx +690 -0
  30. package/frontend/src/pages/OpenWikiPage.tsx +412 -323
  31. package/frontend/src/pages/SettingsPage.tsx +825 -922
  32. package/frontend/src/pages/SkillsPage.tsx +272 -147
  33. package/frontend/src/pages/UsagePage.tsx +23 -31
  34. package/frontend/src/pages/VaultPage.tsx +223 -0
  35. package/frontend/src/types.ts +13 -0
  36. package/package.json +4 -4
  37. package/scaffold/.agent/skills/total-recall/SKILL.md +43 -4
  38. package/scaffold/.agent/skills/total-recall/modules/README.md +10 -0
  39. package/scaffold/.agent/skills/total-recall/modules/agents/README.md +5 -0
  40. package/scaffold/.agent/skills/total-recall/{skills/tr-cli-agents → modules/agents}/agents.yml +8 -0
  41. package/scaffold/.agent/skills/total-recall/modules/skill-deploy/README.md +9 -0
  42. package/scaffold/.agent/skills/total-recall/openwiki/README.md +10 -0
  43. package/scaffold/.agent/skills/total-recall/openwiki/architecture.md +5 -0
  44. package/scaffold/.agent/skills/total-recall/openwiki/ide.md +10 -0
  45. package/scaffold/.agent/skills/total-recall/openwiki/memory.md +11 -0
  46. package/scaffold/.agent/skills/total-recall/openwiki/secrets.md +7 -0
  47. package/scaffold/.agent/skills/total-recall/openwiki/skills.md +7 -0
  48. package/src/cli/brain.mjs +63 -5
  49. package/src/cli/connect.mjs +11 -19
  50. package/src/cli/daemon.mjs +5 -4
  51. package/src/cli/deploy-ui.mjs +8 -3
  52. package/src/cli/deploy.mjs +84 -27
  53. package/src/cli/ingest/index.mjs +1 -1
  54. package/src/cli/init.mjs +63 -34
  55. package/src/cli/remember.mjs +3 -3
  56. package/src/cli/secret.mjs +812 -0
  57. package/src/cli/setup.mjs +34 -7
  58. package/src/cli/share.mjs +2 -2
  59. package/src/cli/skill.mjs +396 -35
  60. package/src/cli/sync.mjs +4 -4
  61. package/src/cli/task.mjs +287 -0
  62. package/src/core/clarity-rewriter.mjs +5 -5
  63. package/src/core/config.mjs +44 -2
  64. package/src/core/conflict-detector.mjs +5 -5
  65. package/src/core/crons.mjs +54 -0
  66. package/src/core/daemon-loop.mjs +87 -235
  67. package/src/core/dream.mjs +170 -10
  68. package/src/core/env-import.mjs +456 -0
  69. package/src/core/fact-seeker.mjs +14 -14
  70. package/src/core/import-rules.mjs +20 -7
  71. package/src/core/inference-engine.mjs +3 -3
  72. package/src/core/migrate.mjs +14 -8
  73. package/src/core/okf-adapter.mjs +2 -2
  74. package/src/core/operation-validator.mjs +39 -331
  75. package/src/core/optimizer.mjs +7 -0
  76. package/src/core/post-mortem.mjs +2 -2
  77. package/src/core/project-brain.mjs +349 -0
  78. package/src/core/provider-catalog.mjs +296 -0
  79. package/src/core/quick-capture.mjs +1 -1
  80. package/src/core/remote-vault-sync.mjs +194 -0
  81. package/src/core/research-queue.mjs +7 -11
  82. package/src/core/runtime.mjs +33 -9
  83. package/src/core/scheduler.mjs +59 -5
  84. package/src/core/schema.mjs +14 -0
  85. package/src/core/search.mjs +1 -1
  86. package/src/core/secrets-env-export.mjs +323 -0
  87. package/src/core/secrets-rotate.mjs +245 -0
  88. package/src/core/secrets-store.mjs +645 -0
  89. package/src/core/semantic-index.mjs +3 -3
  90. package/src/core/skills-registry.mjs +1062 -0
  91. package/src/core/source-adapters.mjs +4 -1
  92. package/src/core/ssss-host-extension.mjs +94 -0
  93. package/src/core/ssss-kernel-bridge.mjs +530 -0
  94. package/src/core/surface.mjs +14 -0
  95. package/src/core/task-envelope.mjs +298 -0
  96. package/src/core/task-executors.mjs +600 -0
  97. package/src/core/validated-write.mjs +124 -56
  98. package/src/core/vault.mjs +21 -34
  99. package/src/core/webauthn-store.mjs +272 -0
  100. package/src/server/api.mjs +26 -16
  101. package/src/server/auth.mjs +51 -0
  102. package/src/server/index.mjs +3 -3
  103. package/src/server/keys.mjs +30 -4
  104. package/src/server/rest.mjs +198 -25
  105. package/src/server/route-manifest.json +156 -0
  106. package/src/server/routes/_shared.mjs +40 -1
  107. package/src/server/routes/docs.mjs +260 -0
  108. package/src/server/routes/memory.mjs +145 -32
  109. package/src/server/routes/research.mjs +30 -0
  110. package/src/server/routes/secrets.mjs +470 -0
  111. package/src/server/routes/share.mjs +2 -2
  112. package/src/server/routes/skills.mjs +452 -54
  113. package/src/server/routes/sync.mjs +48 -0
  114. package/src/server/routes/webauthn.mjs +184 -0
  115. package/src/server/update-route-manifest.mjs +39 -0
  116. package/templates/onboarding-interview.md +32 -22
  117. package/templates/openwiki/README.md +10 -0
  118. package/templates/openwiki/architecture.md +5 -0
  119. package/templates/openwiki/ide.md +10 -0
  120. package/templates/openwiki/memory.md +11 -0
  121. package/templates/openwiki/secrets.md +7 -0
  122. package/templates/openwiki/skills.md +7 -0
  123. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/SKILL.md +0 -121
  124. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/references/antigravity.txt +0 -20
  125. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/references/claude.txt +0 -58
  126. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/references/codex.txt +0 -81
  127. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/references/gemini.txt +0 -44
  128. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/scripts/.gitkeep +0 -0
  129. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/subagents/.gitkeep +0 -0
  130. package/scaffold/.agent/skills/total-recall/skills/tr-research/SKILL.md +0 -338
  131. package/scaffold/.agent/skills/total-recall/skills/tr-skill/SKILL.md +0 -282
  132. package/scaffold/.agent/skills/total-recall/skills/tr-skill/assets/skill-template/SKILL.md +0 -20
  133. package/scaffold/.agent/skills/total-recall/skills/tr-skill/evals/evals.json +0 -20
  134. package/scaffold/.agent/skills/total-recall/skills/tr-skill/hooks/on-skill-add.sh +0 -14
  135. package/scaffold/.agent/skills/total-recall/skills/tr-skill/hooks/on-skill-delete.sh +0 -14
  136. package/scaffold/.agent/skills/total-recall/skills/tr-skill/learnings/.gitkeep +0 -0
  137. package/scaffold/.agent/skills/total-recall/skills/tr-skill/references/.gitkeep +0 -0
  138. package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/.gitkeep +0 -0
  139. package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/create-skill.sh +0 -65
  140. package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/enforce-skill-optimization.mjs +0 -135
  141. package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/skill-watcher.mjs +0 -64
  142. package/scaffold/.agent/skills/total-recall/skills/tr-skill/subagents/audit-all-skills.md +0 -62
  143. package/scaffold/.agent/skills/total-recall/skills/tr-ssss/SKILL.md +0 -298
  144. package/scaffold/.agent/skills/total-recall/skills/tr-ssss/evals/evals.json +0 -17
  145. package/scaffold/.agent/skills/total-recall/skills/tr-ssss/references/CHANGELOG.md +0 -124
  146. package/scaffold/.agent/skills/total-recall/skills/tr-ssss/references/ssss-spec.md +0 -1325
  147. package/scaffold/.agent/skills/total-recall/skills/tr-ssss/scripts/validate-schema.mjs +0 -232
  148. package/scaffold/.agent/skills/total-recall/skills/tr-ssss/subagents/audit-ssss-node.md +0 -9
  149. /package/scaffold/.agent/skills/total-recall/{skills/tr-cli-agents/evals → modules/skill-deploy/scripts}/.gitkeep +0 -0
  150. /package/scaffold/.agent/skills/total-recall/{skills/tr-skill → modules/skill-deploy}/scripts/find-skills.mjs +0 -0
  151. /package/scaffold/.agent/skills/total-recall/{skills/tr-skill → modules/skill-deploy}/scripts/install-skill.mjs +0 -0
  152. /package/scaffold/.agent/skills/total-recall/{skills/tr-skill → modules/skill-deploy}/scripts/scan-skill.mjs +0 -0
@@ -12,6 +12,8 @@ interface Graph3DProps {
12
12
  onOpenThread: (threadId: string) => void
13
13
  onGroundMemoryNode: (slug: string) => void
14
14
  selectedGroundingNodes: string[]
15
+ /** When false, canvas ignores pointer events (chat background decoration). Default true. */
16
+ interactive?: boolean
15
17
  }
16
18
 
17
19
  interface VisualNode {
@@ -48,6 +50,7 @@ export default function Graph3D({
48
50
  onOpenThread,
49
51
  onGroundMemoryNode,
50
52
  selectedGroundingNodes,
53
+ interactive = true,
51
54
  }: Graph3DProps) {
52
55
  const containerRef = useRef<HTMLDivElement>(null)
53
56
  const canvasRef = useRef<HTMLCanvasElement>(null)
@@ -60,7 +63,7 @@ export default function Graph3D({
60
63
  const [visibleTypes, setVisibleTypes] = useState({
61
64
  research: true,
62
65
  observations: true,
63
- rules: false,
66
+ rules: true,
64
67
  threads: false,
65
68
  })
66
69
 
@@ -191,7 +194,7 @@ export default function Graph3D({
191
194
  source: nodeA,
192
195
  target: targetNode,
193
196
  opacity: 0.7,
194
- color: "rgba(167, 139, 250, 0.55)"
197
+ color: "rgba(96, 165, 250, 0.55)"
195
198
  })
196
199
  }
197
200
  })
@@ -362,7 +365,7 @@ export default function Graph3D({
362
365
  }
363
366
 
364
367
  if (isHighlight) {
365
- ctx.strokeStyle = color || (source.type === "memory" ? "rgba(139, 92, 246, 0.65)" : source.type === "thread" ? "rgba(6, 182, 212, 0.65)" : "rgba(245, 158, 11, 0.65)")
368
+ ctx.strokeStyle = color || (source.type === "memory" ? "rgba(96, 165, 250, 0.55)" : source.type === "thread" ? "rgba(34, 211, 238, 0.55)" : "rgba(251, 191, 36, 0.55)")
366
369
  ctx.lineWidth = 1.8
367
370
  } else {
368
371
  ctx.strokeStyle = color
@@ -398,22 +401,37 @@ export default function Graph3D({
398
401
  size * (isHovered || isSelected ? 2.5 : 1.5)
399
402
  )
400
403
 
401
- let color = "#8b5cf6" // memory observations (purple)
402
- let glowColor = "rgba(139, 92, 246, 0.2)"
403
-
404
+ // Brand-aligned palette: readable on dark, category-distinct
405
+ let color = "#60a5fa" // facts / default memory (sky)
406
+ let glowColor = "rgba(96, 165, 250, 0.28)"
407
+
404
408
  if (node.type === "memory") {
405
- const category = ((node.originalData as MemoryNode).category || 'general').toLowerCase()
406
- const isRule = ['invariants', 'preferences', 'patterns', 'anti-patterns'].includes(category)
407
- if (isRule) {
408
- color = "#6366f1" // developer rules (indigo)
409
- glowColor = "rgba(99, 102, 241, 0.2)"
409
+ const category = ((node.originalData as MemoryNode).category || "general").toLowerCase()
410
+ const palette: Record<string, [string, string]> = {
411
+ invariants: ["#38bdf8", "rgba(56, 189, 248, 0.3)"], // cyan-bright — must-rules
412
+ preferences: ["#818cf8", "rgba(129, 140, 248, 0.28)"], // soft indigo
413
+ patterns: ["#34d399", "rgba(52, 211, 153, 0.28)"], // emerald
414
+ "anti-patterns": ["#f87171", "rgba(248, 113, 113, 0.28)"], // rose
415
+ facts: ["#60a5fa", "rgba(96, 165, 250, 0.28)"], // sky blue
416
+ concepts: ["#a78bfa", "rgba(167, 139, 250, 0.28)"], // violet
417
+ decisions: ["#fbbf24", "rgba(251, 191, 36, 0.28)"], // amber
418
+ lore: ["#c084fc", "rgba(192, 132, 252, 0.25)"], // orchid
419
+ corrections: ["#fb923c", "rgba(251, 146, 60, 0.28)"], // orange
420
+ }
421
+ const pair = palette[category]
422
+ if (pair) {
423
+ color = pair[0]
424
+ glowColor = pair[1]
425
+ } else if (["invariants", "preferences", "patterns", "anti-patterns"].includes(category)) {
426
+ color = "#818cf8"
427
+ glowColor = "rgba(129, 140, 248, 0.28)"
410
428
  }
411
429
  } else if (node.type === "thread") {
412
- color = "#06b6d4" // thread nodes (cyan)
413
- glowColor = "rgba(6, 182, 212, 0.2)"
430
+ color = "#22d3ee" // cyan — sessions
431
+ glowColor = "rgba(34, 211, 238, 0.28)"
414
432
  } else if (node.type === "research") {
415
- color = "#f59e0b" // research nodes (gold)
416
- glowColor = "rgba(245, 158, 11, 0.2)"
433
+ color = "#fbbf24" // amber — research
434
+ glowColor = "rgba(251, 191, 36, 0.28)"
417
435
  }
418
436
 
419
437
  gradient.addColorStop(0, color)
@@ -598,76 +616,110 @@ export default function Graph3D({
598
616
  }
599
617
 
600
618
  return (
601
- <div className="graph-3d-wrapper" ref={containerRef} style={{ position: 'relative', width: '100%', height: '100%', background: 'radial-gradient(circle at center, #0b0f19 0%, #030712 100%)', overflow: 'hidden' }}>
619
+ <div
620
+ className="graph-3d-wrapper"
621
+ ref={containerRef}
622
+ style={{
623
+ position: 'relative',
624
+ width: '100%',
625
+ height: '100%',
626
+ background: 'radial-gradient(ellipse at 50% 40%, #0c1a33 0%, #070b14 55%, #030712 100%)',
627
+ overflow: 'hidden',
628
+ // Isolate stacking so UI chrome always sits above the canvas
629
+ isolation: 'isolate',
630
+ }}
631
+ >
602
632
 
603
- {/* 3D Projection Canvas */}
633
+ {/* 3D Projection Canvas — always under UI chrome */}
604
634
  <canvas
605
635
  ref={canvasRef}
606
- onMouseDown={(e) => handleStartDrag(e.clientX, e.clientY)}
607
- onMouseMove={handleMouseMove}
608
- onMouseUp={handleEndDrag}
609
- onMouseLeave={handleEndDrag}
610
- onClick={handleCanvasClick}
611
- onWheel={handleWheel}
612
- onTouchStart={handleTouchStart}
613
- onTouchMove={handleTouchMove}
614
- onTouchEnd={handleEndDrag}
615
- style={{ cursor: dragging ? "grabbing" : hoveredNode ? "pointer" : "grab", display: "block" }}
636
+ onMouseDown={interactive ? (e) => handleStartDrag(e.clientX, e.clientY) : undefined}
637
+ onMouseMove={interactive ? handleMouseMove : undefined}
638
+ onMouseUp={interactive ? handleEndDrag : undefined}
639
+ onMouseLeave={interactive ? handleEndDrag : undefined}
640
+ onClick={interactive ? handleCanvasClick : undefined}
641
+ onWheel={interactive ? handleWheel : undefined}
642
+ onTouchStart={interactive ? handleTouchStart : undefined}
643
+ onTouchMove={interactive ? handleTouchMove : undefined}
644
+ onTouchEnd={interactive ? handleEndDrag : undefined}
645
+ style={{
646
+ position: 'absolute',
647
+ inset: 0,
648
+ zIndex: 1,
649
+ width: '100%',
650
+ height: '100%',
651
+ display: 'block',
652
+ pointerEvents: interactive ? 'auto' : 'none',
653
+ cursor: interactive
654
+ ? dragging
655
+ ? 'grabbing'
656
+ : hoveredNode
657
+ ? 'pointer'
658
+ : 'grab'
659
+ : 'default',
660
+ }}
616
661
  />
617
662
 
618
663
  {/* Cosmic Floating Background Dust overlay */}
619
- <div style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, pointerEvents: 'none', background: 'radial-gradient(circle at 50% 50%, rgba(139, 92, 246, 0.05) 0%, transparent 60%)' }} />
664
+ <div style={{ position: 'absolute', inset: 0, zIndex: 2, pointerEvents: 'none', background: 'radial-gradient(circle at 50% 45%, rgba(59, 130, 246, 0.08) 0%, transparent 55%)' }} />
620
665
 
621
666
  {/* Floating UI Elements */}
622
- <div style={{ position: 'absolute', top: 20, left: 20, display: 'flex', flexDirection: 'column', gap: 6, pointerEvents: 'none' }}>
623
- <h3 style={{ margin: 0, fontSize: 18, color: '#fff', fontWeight: 700, letterSpacing: '0.5px' }}>Sovereign Mind Matrix</h3>
624
- <p style={{ margin: 0, fontSize: 11, color: 'rgba(255,255,255,0.45)' }}>3D Constellation of Research, Memory & Conversations</p>
667
+ <div style={{ position: 'absolute', top: 16, left: 16, zIndex: 30, display: 'flex', flexDirection: 'column', gap: 6, pointerEvents: 'none', maxWidth: 280 }}>
668
+ <h3 style={{ margin: 0, fontSize: 18, color: '#f1f5f9', fontWeight: 700, letterSpacing: '-0.02em' }}>Memory Constellation</h3>
669
+ <p style={{ margin: 0, fontSize: 11, color: 'rgba(148,163,184,0.85)' }}>Vault · sessions · research — use filters to toggle types</p>
625
670
  </div>
626
671
 
627
672
  {/* Controls Overlay */}
628
- <div style={{ position: 'absolute', bottom: 20, left: 20, display: 'flex', gap: 8 }}>
673
+ {interactive && (
674
+ <div style={{ position: 'absolute', bottom: 20, left: 20, zIndex: 40, display: 'flex', gap: 8, pointerEvents: 'auto' }}>
629
675
  <button
676
+ type="button"
630
677
  onClick={() => setZoom(prev => Math.min(3.0, prev + 0.2))}
631
- style={{ width: 32, height: 32, background: 'rgba(15,23,42,0.6)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: 8, color: '#fff', fontSize: 16, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
678
+ style={{ width: 32, height: 32, background: 'rgba(15,23,42,0.85)', border: '1px solid rgba(255,255,255,0.15)', borderRadius: 8, color: '#fff', fontSize: 16, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
632
679
  title="Zoom In"
633
680
  >
634
681
  +
635
682
  </button>
636
683
  <button
684
+ type="button"
637
685
  onClick={() => setZoom(prev => Math.max(0.5, prev - 0.2))}
638
- style={{ width: 32, height: 32, background: 'rgba(15,23,42,0.6)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: 8, color: '#fff', fontSize: 16, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
686
+ style={{ width: 32, height: 32, background: 'rgba(15,23,42,0.85)', border: '1px solid rgba(255,255,255,0.15)', borderRadius: 8, color: '#fff', fontSize: 16, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
639
687
  title="Zoom Out"
640
688
  >
641
689
  -
642
690
  </button>
643
691
  <button
692
+ type="button"
644
693
  onClick={() => { angleX.current = 0.3; angleY.current = 0.5; setZoom(1.2) }}
645
- style={{ width: 32, height: 32, background: 'rgba(15,23,42,0.6)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: 8, color: '#fff', fontSize: 11, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
694
+ style={{ width: 32, height: 32, background: 'rgba(15,23,42,0.85)', border: '1px solid rgba(255,255,255,0.15)', borderRadius: 8, color: '#fff', fontSize: 11, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
646
695
  title="Reset Camera"
647
696
  >
648
697
  ⟲
649
698
  </button>
650
699
  </div>
700
+ )}
651
701
 
652
- {/* Floating Filter Panel (Top Right) */}
702
+ {/* Floating Filter Panel — left side under title so node drawer (right) never covers it */}
703
+ {interactive && (
653
704
  <div
654
- className="glass"
705
+ className="glass graph-type-filters"
655
706
  style={{
656
707
  position: 'absolute',
657
- top: 20,
658
- right: 20,
708
+ top: 72,
709
+ left: 16,
659
710
  display: 'flex',
660
711
  flexDirection: 'column',
661
712
  gap: 10,
662
- background: 'rgba(10, 15, 30, 0.75)',
713
+ background: 'rgba(10, 15, 30, 0.92)',
663
714
  backdropFilter: 'blur(20px)',
664
715
  WebkitBackdropFilter: 'blur(20px)',
665
716
  padding: '12px 16px',
666
717
  borderRadius: 12,
667
- border: '1px solid rgba(255, 255, 255, 0.08)',
668
- boxShadow: '0 8px 32px rgba(0,0,0,0.3)',
718
+ border: '1px solid rgba(255, 255, 255, 0.12)',
719
+ boxShadow: '0 8px 32px rgba(0,0,0,0.45)',
669
720
  width: 220,
670
- zIndex: 90,
721
+ zIndex: 60,
722
+ pointerEvents: 'auto',
671
723
  }}
672
724
  >
673
725
  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
@@ -680,63 +732,60 @@ export default function Graph3D({
680
732
  </div>
681
733
 
682
734
  <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
683
- {/* 1. Research Projects */}
684
735
  <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11, color: 'var(--text-secondary)', cursor: 'pointer', userSelect: 'none' }}>
685
- <input
686
- type="checkbox"
687
- checked={visibleTypes.research}
736
+ <input
737
+ type="checkbox"
738
+ checked={visibleTypes.research}
688
739
  onChange={() => setVisibleTypes(prev => ({ ...prev, research: !prev.research }))}
689
- style={{ accentColor: '#f59e0b', cursor: 'pointer' }}
740
+ style={{ accentColor: '#fbbf24', cursor: 'pointer' }}
690
741
  />
691
- <span style={{ display: 'inline-block', width: 6, height: 6, borderRadius: '50%', background: '#f59e0b' }} />
692
- <span style={{ flex: 1 }}>Research Projects</span>
742
+ <span style={{ display: 'inline-block', width: 6, height: 6, borderRadius: '50%', background: '#fbbf24', boxShadow: '0 0 6px rgba(251,191,36,0.5)' }} />
743
+ <span style={{ flex: 1 }}>Research</span>
693
744
  <span style={{ fontSize: 9, color: 'var(--text-tertiary)' }}>({researchItems.length})</span>
694
745
  </label>
695
746
 
696
- {/* 2. Observations & Facts */}
697
747
  <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11, color: 'var(--text-secondary)', cursor: 'pointer', userSelect: 'none' }}>
698
- <input
699
- type="checkbox"
700
- checked={visibleTypes.observations}
748
+ <input
749
+ type="checkbox"
750
+ checked={visibleTypes.observations}
701
751
  onChange={() => setVisibleTypes(prev => ({ ...prev, observations: !prev.observations }))}
702
- style={{ accentColor: '#8b5cf6', cursor: 'pointer' }}
752
+ style={{ accentColor: '#60a5fa', cursor: 'pointer' }}
703
753
  />
704
- <span style={{ display: 'inline-block', width: 6, height: 6, borderRadius: '50%', background: '#8b5cf6' }} />
705
- <span style={{ flex: 1 }}>Observations</span>
754
+ <span style={{ display: 'inline-block', width: 6, height: 6, borderRadius: '50%', background: '#60a5fa', boxShadow: '0 0 6px rgba(96,165,250,0.5)' }} />
755
+ <span style={{ flex: 1 }}>Memory</span>
706
756
  <span style={{ fontSize: 9, color: 'var(--text-tertiary)' }}>
707
757
  ({memoryNodes.filter(m => !['invariants', 'preferences', 'patterns', 'anti-patterns'].includes((m.category || 'general').toLowerCase())).length})
708
758
  </span>
709
759
  </label>
710
760
 
711
- {/* 3. Developer Rules */}
712
761
  <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11, color: 'var(--text-secondary)', cursor: 'pointer', userSelect: 'none' }}>
713
- <input
714
- type="checkbox"
715
- checked={visibleTypes.rules}
762
+ <input
763
+ type="checkbox"
764
+ checked={visibleTypes.rules}
716
765
  onChange={() => setVisibleTypes(prev => ({ ...prev, rules: !prev.rules }))}
717
- style={{ accentColor: '#6366f1', cursor: 'pointer' }}
766
+ style={{ accentColor: '#38bdf8', cursor: 'pointer' }}
718
767
  />
719
- <span style={{ display: 'inline-block', width: 6, height: 6, borderRadius: '50%', background: '#6366f1' }} />
720
- <span style={{ flex: 1 }}>Developer Rules</span>
768
+ <span style={{ display: 'inline-block', width: 6, height: 6, borderRadius: '50%', background: 'linear-gradient(90deg,#38bdf8,#f87171)', boxShadow: '0 0 6px rgba(56,189,248,0.4)' }} />
769
+ <span style={{ flex: 1 }}>Rules</span>
721
770
  <span style={{ fontSize: 9, color: 'var(--text-tertiary)' }}>
722
771
  ({memoryNodes.filter(m => ['invariants', 'preferences', 'patterns', 'anti-patterns'].includes((m.category || 'general').toLowerCase())).length})
723
772
  </span>
724
773
  </label>
725
774
 
726
- {/* 4. Chat Threads */}
727
775
  <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11, color: 'var(--text-secondary)', cursor: 'pointer', userSelect: 'none' }}>
728
- <input
729
- type="checkbox"
730
- checked={visibleTypes.threads}
776
+ <input
777
+ type="checkbox"
778
+ checked={visibleTypes.threads}
731
779
  onChange={() => setVisibleTypes(prev => ({ ...prev, threads: !prev.threads }))}
732
- style={{ accentColor: '#06b6d4', cursor: 'pointer' }}
780
+ style={{ accentColor: '#22d3ee', cursor: 'pointer' }}
733
781
  />
734
- <span style={{ display: 'inline-block', width: 6, height: 6, borderRadius: '50%', background: '#06b6d4' }} />
735
- <span style={{ flex: 1 }}>Conversations</span>
782
+ <span style={{ display: 'inline-block', width: 6, height: 6, borderRadius: '50%', background: '#22d3ee', boxShadow: '0 0 6px rgba(34,211,238,0.5)' }} />
783
+ <span style={{ flex: 1 }}>Sessions</span>
736
784
  <span style={{ fontSize: 9, color: 'var(--text-tertiary)' }}>({threads.length})</span>
737
785
  </label>
738
786
  </div>
739
787
  </div>
788
+ )}
740
789
 
741
790
  {/* Selected Node Glass detail overlay drawer */}
742
791
  {selectedNode && (
@@ -4,9 +4,9 @@ import type { UsageData } from '../types';
4
4
 
5
5
  interface UsageChartProps {
6
6
  usageData: UsageData | null;
7
- geminiModels: any[];
8
- claudeModels: any[];
9
- openaiModels: any[];
7
+ geminiModels: unknown[];
8
+ claudeModels: unknown[];
9
+ openaiModels: unknown[];
10
10
  }
11
11
 
12
12
  export const UsageChart: React.FC<UsageChartProps> = ({ usageData }) => {
@@ -0,0 +1,95 @@
1
+ /** Official Total Recall brand marks from portfolio-site assets/logos. */
2
+
3
+ export type BrandVariant = 'lockup' | 'icon' | 'badge' | 'mark'
4
+
5
+ interface BrandMarkProps {
6
+ variant?: BrandVariant
7
+ /** Height in px (width auto). */
8
+ height?: number
9
+ className?: string
10
+ alt?: string
11
+ /** Light plate behind lockup for dark surfaces (PNG has white bg). */
12
+ plate?: boolean
13
+ }
14
+
15
+ const SRC: Record<BrandVariant, string> = {
16
+ lockup: '/brand/total-recall-lockup.png',
17
+ icon: '/brand/total-recall-icon.svg',
18
+ badge: '/brand/total-recall-badge.jpg',
19
+ mark: '/brand/total-recall-mark.svg',
20
+ }
21
+
22
+ export default function BrandMark({
23
+ variant = 'lockup',
24
+ height = 40,
25
+ className = '',
26
+ alt = 'Total Recall',
27
+ plate = false,
28
+ }: BrandMarkProps) {
29
+ const isSquare = variant === 'icon' || variant === 'badge' || variant === 'mark'
30
+ const img = (
31
+ <img
32
+ src={SRC[variant]}
33
+ alt={alt}
34
+ height={height}
35
+ width={isSquare ? height : undefined}
36
+ className={className}
37
+ style={{
38
+ height,
39
+ width: isSquare ? height : 'auto',
40
+ maxWidth: '100%',
41
+ objectFit: 'contain',
42
+ display: 'block',
43
+ }}
44
+ draggable={false}
45
+ />
46
+ )
47
+
48
+ if (!plate) return img
49
+
50
+ return (
51
+ <div
52
+ className="brand-plate"
53
+ style={{
54
+ display: 'inline-flex',
55
+ alignItems: 'center',
56
+ justifyContent: 'center',
57
+ padding: variant === 'lockup' ? '10px 14px' : 8,
58
+ borderRadius: variant === 'lockup' ? 14 : 16,
59
+ background: 'linear-gradient(180deg, #f8fafc 0%, #eef2ff 100%)',
60
+ boxShadow:
61
+ '0 1px 0 rgba(255,255,255,0.6) inset, 0 12px 32px rgba(15, 23, 42, 0.35), 0 0 0 1px rgba(148,163,184,0.25)',
62
+ }}
63
+ >
64
+ {img}
65
+ </div>
66
+ )
67
+ }
68
+
69
+ /** Compact cube-style brand chip for nav / floating chrome. */
70
+ export function BrandChip({ size = 36 }: { size?: number }) {
71
+ return (
72
+ <div
73
+ className="brand-chip"
74
+ style={{
75
+ width: size,
76
+ height: size,
77
+ borderRadius: Math.round(size * 0.28),
78
+ overflow: 'hidden',
79
+ flexShrink: 0,
80
+ boxShadow:
81
+ '0 0 0 1px rgba(96,165,250,0.35), 0 8px 24px rgba(37,99,235,0.25)',
82
+ background: 'linear-gradient(145deg, #1e3a8a, #0b1220)',
83
+ }}
84
+ >
85
+ <img
86
+ src="/brand/total-recall-icon.svg"
87
+ alt=""
88
+ width={size}
89
+ height={size}
90
+ style={{ width: '100%', height: '100%', objectFit: 'cover' }}
91
+ draggable={false}
92
+ />
93
+ </div>
94
+ )
95
+ }