@memtensor/memos-local-openclaw-plugin 0.1.2 → 0.1.4

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 (77) hide show
  1. package/.env.example +13 -5
  2. package/README.md +180 -68
  3. package/dist/capture/index.d.ts +5 -7
  4. package/dist/capture/index.d.ts.map +1 -1
  5. package/dist/capture/index.js +72 -43
  6. package/dist/capture/index.js.map +1 -1
  7. package/dist/ingest/providers/anthropic.d.ts +2 -0
  8. package/dist/ingest/providers/anthropic.d.ts.map +1 -1
  9. package/dist/ingest/providers/anthropic.js +110 -1
  10. package/dist/ingest/providers/anthropic.js.map +1 -1
  11. package/dist/ingest/providers/bedrock.d.ts +2 -5
  12. package/dist/ingest/providers/bedrock.d.ts.map +1 -1
  13. package/dist/ingest/providers/bedrock.js +110 -6
  14. package/dist/ingest/providers/bedrock.js.map +1 -1
  15. package/dist/ingest/providers/gemini.d.ts +2 -0
  16. package/dist/ingest/providers/gemini.d.ts.map +1 -1
  17. package/dist/ingest/providers/gemini.js +106 -1
  18. package/dist/ingest/providers/gemini.js.map +1 -1
  19. package/dist/ingest/providers/index.d.ts +9 -0
  20. package/dist/ingest/providers/index.d.ts.map +1 -1
  21. package/dist/ingest/providers/index.js +66 -4
  22. package/dist/ingest/providers/index.js.map +1 -1
  23. package/dist/ingest/providers/openai.d.ts +2 -0
  24. package/dist/ingest/providers/openai.d.ts.map +1 -1
  25. package/dist/ingest/providers/openai.js +112 -1
  26. package/dist/ingest/providers/openai.js.map +1 -1
  27. package/dist/ingest/task-processor.d.ts +63 -0
  28. package/dist/ingest/task-processor.d.ts.map +1 -0
  29. package/dist/ingest/task-processor.js +339 -0
  30. package/dist/ingest/task-processor.js.map +1 -0
  31. package/dist/ingest/worker.d.ts +1 -1
  32. package/dist/ingest/worker.d.ts.map +1 -1
  33. package/dist/ingest/worker.js +18 -13
  34. package/dist/ingest/worker.js.map +1 -1
  35. package/dist/recall/engine.d.ts +1 -0
  36. package/dist/recall/engine.d.ts.map +1 -1
  37. package/dist/recall/engine.js +21 -11
  38. package/dist/recall/engine.js.map +1 -1
  39. package/dist/recall/mmr.d.ts.map +1 -1
  40. package/dist/recall/mmr.js +3 -1
  41. package/dist/recall/mmr.js.map +1 -1
  42. package/dist/storage/sqlite.d.ts +67 -1
  43. package/dist/storage/sqlite.d.ts.map +1 -1
  44. package/dist/storage/sqlite.js +251 -5
  45. package/dist/storage/sqlite.js.map +1 -1
  46. package/dist/types.d.ts +15 -0
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/types.js +2 -0
  49. package/dist/types.js.map +1 -1
  50. package/dist/viewer/html.d.ts +1 -1
  51. package/dist/viewer/html.d.ts.map +1 -1
  52. package/dist/viewer/html.js +955 -115
  53. package/dist/viewer/html.js.map +1 -1
  54. package/dist/viewer/server.d.ts +3 -0
  55. package/dist/viewer/server.d.ts.map +1 -1
  56. package/dist/viewer/server.js +59 -1
  57. package/dist/viewer/server.js.map +1 -1
  58. package/index.ts +221 -45
  59. package/openclaw.plugin.json +20 -45
  60. package/package.json +3 -4
  61. package/skill/SKILL.md +59 -0
  62. package/src/capture/index.ts +85 -45
  63. package/src/ingest/providers/anthropic.ts +128 -1
  64. package/src/ingest/providers/bedrock.ts +130 -6
  65. package/src/ingest/providers/gemini.ts +128 -1
  66. package/src/ingest/providers/index.ts +74 -8
  67. package/src/ingest/providers/openai.ts +130 -1
  68. package/src/ingest/task-processor.ts +380 -0
  69. package/src/ingest/worker.ts +21 -15
  70. package/src/recall/engine.ts +22 -12
  71. package/src/recall/mmr.ts +3 -1
  72. package/src/storage/sqlite.ts +298 -5
  73. package/src/types.ts +19 -0
  74. package/src/viewer/html.ts +955 -115
  75. package/src/viewer/server.ts +63 -1
  76. package/SKILL.md +0 -43
  77. package/www/index.html +0 -606
package/www/index.html DELETED
@@ -1,606 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width,initial-scale=1.0">
6
- <title>MemOS Local — Official Memory Plugin for OpenClaw</title>
7
- <meta name="description" content="The official local memory plugin for OpenClaw. Full-write conversation memory, hybrid search, semantic chunking, and a built-in web viewer. Install from npm.">
8
- <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🦞</text></svg>">
9
- <link rel="preconnect" href="https://fonts.googleapis.com">
10
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
12
- <style>
13
- *{margin:0;padding:0;box-sizing:border-box}
14
- :root{
15
- --bg:#050510;--bg-card:rgba(255,255,255,.03);--bg-card-hover:rgba(255,255,255,.06);
16
- --border:rgba(255,255,255,.08);--border-glow:rgba(0,153,204,.3);
17
- --text:#f0f4f8;--text-sec:#8b95a5;--text-thr:#5a6373;
18
- --pri:#00bbee;--pri-glow:rgba(0,187,238,.15);--pri-dark:#0088aa;
19
- --accent:#e63946;--accent-glow:rgba(230,57,70,.15);
20
- --green:#10b981;--violet:#8b5cf6;--amber:#f59e0b;
21
- --font:'Inter',system-ui,-apple-system,sans-serif;
22
- --mono:'SF Mono','Fira Code','JetBrains Mono',monospace;
23
- }
24
- html{scroll-behavior:smooth}
25
- body{font-family:var(--font);color:var(--text);background:var(--bg);line-height:1.7;overflow-x:hidden}
26
- a{color:var(--pri);text-decoration:none;transition:color .2s}
27
- a:hover{color:#4dd9ff}
28
-
29
- /* ── Noise & Gradient BG ── */
30
- .page-bg{position:fixed;inset:0;z-index:-1;pointer-events:none}
31
- .page-bg::before{content:'';position:absolute;inset:0;background:radial-gradient(ellipse 80% 60% at 50% -10%,rgba(0,153,204,.12),transparent 60%),radial-gradient(ellipse 50% 40% at 80% 20%,rgba(139,92,246,.08),transparent 50%),radial-gradient(ellipse 40% 30% at 20% 80%,rgba(230,57,70,.06),transparent 50%)}
32
- .page-bg::after{content:'';position:absolute;inset:0;background:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.03'/%3E%3C/svg%3E");opacity:.5}
33
-
34
- .container{max-width:1200px;margin:0 auto;padding:0 24px}
35
-
36
- /* ── Nav ── */
37
- nav{position:fixed;top:0;left:0;right:0;z-index:100;padding:0 24px;backdrop-filter:blur(16px);background:rgba(5,5,16,.7);border-bottom:1px solid var(--border)}
38
- nav .inner{max-width:1200px;margin:0 auto;display:flex;align-items:center;height:64px}
39
- nav .brand{display:flex;align-items:center;gap:10px;font-weight:700;font-size:17px}
40
- nav .brand .icon{font-size:26px}
41
- nav .brand .sub{font-size:10px;color:var(--text-sec);font-weight:400;display:block;line-height:1.1}
42
- nav .links{margin-left:auto;display:flex;align-items:center;gap:8px}
43
- nav .links a{color:var(--text-sec);font-size:13px;font-weight:500;padding:6px 14px;border-radius:6px;transition:all .2s}
44
- nav .links a:hover{color:var(--text);background:rgba(255,255,255,.06)}
45
- nav .btn-nav{background:var(--pri)!important;color:#000!important;font-weight:600;border-radius:8px;padding:7px 18px!important}
46
- nav .btn-nav:hover{background:#4dd9ff!important}
47
-
48
- /* ── Hero ── */
49
- .hero{padding:160px 0 100px;text-align:center;position:relative}
50
- .hero-badge{display:inline-flex;align-items:center;gap:8px;background:var(--pri-glow);border:1px solid rgba(0,187,238,.2);padding:6px 18px;border-radius:24px;font-size:13px;font-weight:500;color:var(--pri);margin-bottom:28px;animation:fadeUp .6s ease}
51
- .hero-badge .dot{width:6px;height:6px;background:var(--green);border-radius:50%;animation:pulse 2s infinite}
52
- @keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
53
- .hero h1{font-size:clamp(38px,6vw,72px);font-weight:900;letter-spacing:-.03em;line-height:1.08;margin-bottom:24px;animation:fadeUp .6s ease .1s both}
54
- .hero h1 .gradient{background:linear-gradient(135deg,var(--pri),var(--violet),var(--accent));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
55
- .hero .desc{font-size:clamp(16px,2vw,20px);color:var(--text-sec);max-width:640px;margin:0 auto 40px;line-height:1.7;animation:fadeUp .6s ease .2s both}
56
- .hero .ctas{display:flex;gap:14px;justify-content:center;flex-wrap:wrap;animation:fadeUp .6s ease .3s both}
57
- .btn{display:inline-flex;align-items:center;gap:8px;padding:12px 28px;border-radius:10px;font-size:15px;font-weight:600;border:none;cursor:pointer;transition:all .25s;text-decoration:none}
58
- .btn-primary{background:var(--pri);color:#000}
59
- .btn-primary:hover{background:#4dd9ff;transform:translateY(-1px);box-shadow:0 8px 30px rgba(0,187,238,.25)}
60
- .btn-outline{background:transparent;color:var(--text);border:1px solid var(--border)}
61
- .btn-outline:hover{border-color:var(--pri);color:var(--pri);background:var(--pri-glow)}
62
- @keyframes fadeUp{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}
63
-
64
- /* ── Hero Terminal ── */
65
- .hero-visual{max-width:760px;margin:60px auto 0;animation:fadeUp .6s ease .4s both}
66
- .terminal{background:rgba(15,23,42,.8);border:1px solid var(--border);border-radius:14px;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,.4)}
67
- .terminal-bar{display:flex;align-items:center;gap:8px;padding:12px 16px;background:rgba(255,255,255,.03);border-bottom:1px solid var(--border)}
68
- .terminal-dot{width:12px;height:12px;border-radius:50%}
69
- .terminal-dot.r{background:#ff5f57}.terminal-dot.y{background:#ffbd2e}.terminal-dot.g{background:#28ca42}
70
- .terminal-title{flex:1;text-align:center;font-size:12px;color:var(--text-thr)}
71
- .terminal-body{padding:20px;font-family:var(--mono);font-size:13px;line-height:1.8;color:#a0aec0}
72
- .terminal-body .prompt{color:var(--green)}
73
- .terminal-body .cmd{color:var(--text)}
74
- .terminal-body .output{color:var(--text-sec)}
75
- .terminal-body .highlight{color:var(--pri)}
76
- .terminal-body .success{color:var(--green)}
77
- .terminal-body .dim{color:var(--text-thr)}
78
-
79
- /* ── Stats ── */
80
- .stats{display:flex;justify-content:center;gap:48px;padding:60px 0;flex-wrap:wrap}
81
- .stat{text-align:center}
82
- .stat .num{font-size:36px;font-weight:800;background:linear-gradient(135deg,var(--pri),var(--violet));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
83
- .stat .label{font-size:13px;color:var(--text-thr);margin-top:4px}
84
-
85
- /* ── Section ── */
86
- .section{padding:100px 0}
87
- .section-header{text-align:center;margin-bottom:56px}
88
- .section-badge{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--pri);margin-bottom:16px}
89
- .section-badge .line{width:20px;height:1px;background:var(--pri)}
90
- .section h2{font-size:clamp(28px,4vw,44px);font-weight:800;letter-spacing:-.02em;margin-bottom:16px}
91
- .section h2 .accent{color:var(--pri)}
92
- .section .section-desc{color:var(--text-sec);font-size:17px;max-width:580px;margin:0 auto}
93
-
94
- /* ── Feature Grid ── */
95
- .feature-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
96
- .feature-card{background:var(--bg-card);border:1px solid var(--border);border-radius:14px;padding:28px;transition:all .3s;position:relative;overflow:hidden}
97
- .feature-card::before{content:'';position:absolute;top:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent,var(--pri),transparent);opacity:0;transition:opacity .3s}
98
- .feature-card:hover{background:var(--bg-card-hover);border-color:var(--border-glow);transform:translateY(-2px)}
99
- .feature-card:hover::before{opacity:1}
100
- .feature-icon{width:44px;height:44px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:22px;margin-bottom:16px}
101
- .feature-icon.blue{background:rgba(0,187,238,.12)}
102
- .feature-icon.violet{background:rgba(139,92,246,.12)}
103
- .feature-icon.green{background:rgba(16,185,129,.12)}
104
- .feature-icon.amber{background:rgba(245,158,11,.12)}
105
- .feature-icon.red{background:rgba(230,57,70,.12)}
106
- .feature-icon.pink{background:rgba(236,72,153,.12)}
107
- .feature-card h3{font-size:16px;font-weight:700;margin-bottom:8px}
108
- .feature-card p{font-size:14px;color:var(--text-sec);line-height:1.7}
109
-
110
- /* ── Architecture ── */
111
- .arch-flow{display:flex;align-items:stretch;gap:2px;justify-content:center;flex-wrap:wrap;padding:20px 0}
112
- .arch-step{flex:1;min-width:120px;max-width:180px;background:var(--bg-card);border:1px solid var(--border);border-radius:12px;padding:20px 16px;text-align:center;transition:all .3s;position:relative}
113
- .arch-step:hover{border-color:var(--border-glow);background:var(--bg-card-hover)}
114
- .arch-step .step-num{position:absolute;top:-10px;left:50%;transform:translateX(-50%);background:var(--pri);color:#000;font-size:11px;font-weight:700;width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center}
115
- .arch-step .step-icon{font-size:28px;margin-bottom:8px}
116
- .arch-step h4{font-size:13px;font-weight:700;margin-bottom:4px}
117
- .arch-step p{font-size:11px;color:var(--text-thr);line-height:1.5}
118
- .arch-arrow{display:flex;align-items:center;color:var(--text-thr);font-size:20px;padding:0 4px}
119
-
120
- /* ── Code Preview ── */
121
- .code-section{display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:center}
122
- .code-text h3{font-size:26px;font-weight:800;margin-bottom:16px}
123
- .code-text p{color:var(--text-sec);font-size:15px;margin-bottom:20px;line-height:1.8}
124
- .code-text .tag{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;padding:4px 12px;border-radius:6px;margin-right:6px;margin-bottom:6px}
125
- .tag.t-blue{background:rgba(0,187,238,.1);color:var(--pri)}
126
- .tag.t-violet{background:rgba(139,92,246,.1);color:var(--violet)}
127
- .tag.t-green{background:rgba(16,185,129,.1);color:var(--green)}
128
- .code-block{background:rgba(15,23,42,.6);border:1px solid var(--border);border-radius:14px;overflow:hidden}
129
- .code-block .code-header{display:flex;align-items:center;gap:8px;padding:12px 16px;background:rgba(255,255,255,.02);border-bottom:1px solid var(--border);font-size:12px;color:var(--text-thr)}
130
- .code-block .code-header .dot{width:10px;height:10px;border-radius:50%;margin-right:2px}
131
- .code-block pre{padding:20px;font-family:var(--mono);font-size:12.5px;line-height:1.8;color:#a0aec0;overflow-x:auto}
132
- .code-block .kw{color:#7dd3fc}.code-block .str{color:#86efac}.code-block .cmt{color:#475569}.code-block .fn{color:#c4b5fd}.code-block .num{color:#fbbf24}
133
-
134
- /* ── Providers ── */
135
- .provider-grid{display:flex;flex-wrap:wrap;justify-content:center;gap:16px;padding:20px 0}
136
- .provider{background:var(--bg-card);border:1px solid var(--border);border-radius:10px;padding:16px 24px;display:flex;align-items:center;gap:10px;font-size:14px;font-weight:500;transition:all .2s}
137
- .provider:hover{border-color:var(--border-glow);background:var(--bg-card-hover)}
138
- .provider .p-icon{font-size:22px}
139
-
140
- /* ── CTA ── */
141
- .cta-section{text-align:center;padding:100px 0 120px;position:relative}
142
- .cta-section::before{content:'';position:absolute;inset:0;background:radial-gradient(ellipse 60% 50% at 50% 80%,rgba(0,153,204,.08),transparent);pointer-events:none}
143
- .cta-section h2{font-size:clamp(30px,4vw,48px);font-weight:900;margin-bottom:16px}
144
- .cta-section .desc{color:var(--text-sec);font-size:17px;max-width:500px;margin:0 auto 36px}
145
-
146
- /* ── Footer ── */
147
- footer{border-top:1px solid var(--border);padding:40px 0}
148
- footer .inner{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:16px}
149
- footer .brand{display:flex;align-items:center;gap:8px;font-weight:700;font-size:15px}
150
- footer .brand .icon{font-size:20px}
151
- footer .links{display:flex;gap:24px}
152
- footer .links a{color:var(--text-thr);font-size:13px;transition:color .2s}
153
- footer .links a:hover{color:var(--text)}
154
- footer .copy{color:var(--text-thr);font-size:12px;width:100%;text-align:center;margin-top:16px}
155
-
156
- /* ── Responsive ── */
157
- @media(max-width:900px){
158
- .feature-grid{grid-template-columns:1fr}
159
- .code-section{grid-template-columns:1fr;gap:24px}
160
- .arch-flow{flex-direction:column;align-items:center}
161
- .arch-arrow{transform:rotate(90deg)}
162
- .stats{gap:24px}
163
- }
164
- @media(max-width:600px){
165
- nav .links a:not(.btn-nav):not(.lang-switch){display:none}
166
- .hero{padding:120px 0 60px}
167
- }
168
-
169
- /* ── Bilingual ── */
170
- body.lang-en .lang-zh{display:none !important}
171
- body.lang-zh .lang-en{display:none !important}
172
- /* 语言切换:最右侧,分段式 pill */
173
- .lang-switch{display:inline-flex;align-items:stretch;margin-left:16px;padding:3px;background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:20px;box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}
174
- .lang-switch .lang-btn{background:transparent;border:none;color:var(--text-thr);padding:5px 14px;font-size:12px;font-weight:600;cursor:pointer;border-radius:16px;transition:all .25s ease;min-width:36px}
175
- .lang-switch .lang-btn:first-child{border-radius:16px 0 0 16px}
176
- .lang-switch .lang-btn:last-child{border-radius:0 16px 16px 0}
177
- .lang-switch .lang-btn:hover{color:var(--text-sec)}
178
- .lang-switch .lang-btn.active{background:var(--pri);color:#000;box-shadow:0 1px 3px rgba(0,0,0,.2)}
179
- .lang-switch .lang-btn.active:hover{background:#4dd9ff;color:#000}
180
-
181
- /* ── Security/Local theme ── */
182
- .hero-tagline{font-size:14px;color:var(--green);margin-top:12px;display:flex;align-items:center;justify-content:center;gap:12px;flex-wrap:wrap}
183
- .hero-tagline span{display:inline-flex;align-items:center;gap:6px}
184
- .hero-tagline .dot{width:6px;height:6px;border-radius:50%;background:var(--green)}
185
- .security-badge{display:inline-flex;align-items:center;gap:6px;background:rgba(16,185,129,.12);border:1px solid rgba(16,185,129,.3);color:var(--green);padding:6px 14px;border-radius:20px;font-size:12px;font-weight:600;margin-left:10px}
186
- </style>
187
- </head>
188
- <body>
189
- <div class="page-bg"></div>
190
-
191
- <!-- ════════ Nav ════════ -->
192
- <nav>
193
- <div class="inner">
194
- <div class="brand">
195
- <span class="icon">🦞</span>
196
- <span>OpenClaw<span class="sub lang-zh">由 MemOS 驱动 · 记忆插件</span><span class="sub lang-en">Powered by MemOS · Memory Plugin</span></span>
197
- </div>
198
- <div class="links">
199
- <a href="#features" class="lang-zh">功能</a>
200
- <a href="#features" class="lang-en">Features</a>
201
- <a href="#architecture" class="lang-zh">架构</a>
202
- <a href="#architecture" class="lang-en">Architecture</a>
203
- <a href="#code" class="lang-zh">快速开始</a>
204
- <a href="#code" class="lang-en">Code</a>
205
- <a href="#providers" class="lang-zh">服务商</a>
206
- <a href="#providers" class="lang-en">Providers</a>
207
- <a href="./docs/index.html" class="btn-nav lang-zh">文档 →</a>
208
- <a href="./docs/index.html" class="btn-nav lang-en">Docs →</a>
209
- <span class="lang-switch" aria-label="Language">
210
- <button type="button" class="lang-btn active" data-lang="zh" title="中文">中</button>
211
- <button type="button" class="lang-btn" data-lang="en" title="English">EN</button>
212
- </span>
213
- </div>
214
- </div>
215
- </nav>
216
-
217
- <!-- ════════ Hero ════════ -->
218
- <section class="hero">
219
- <div class="container">
220
- <div class="hero-badge">
221
- <span class="lang-zh"><span class="dot"></span> OpenClaw 官方插件 · 从 npm 安装</span>
222
- <span class="lang-en"><span class="dot"></span> Official OpenClaw Plugin · Install from npm</span>
223
- </div>
224
- <h1>
225
- <span class="lang-zh">为 <span class="gradient">OpenClaw</span> 提供<br>持久化记忆</span>
226
- <span class="lang-en">Persistent Memory<br>for <span class="gradient">OpenClaw</span></span>
227
- </h1>
228
- <p class="desc">
229
- <span class="lang-zh">官方本地记忆插件。对话全部落盘在本机,语义检索、即时召回。从 npm 安装,无需克隆与编译。</span>
230
- <span class="lang-en">The official local memory plugin. Every conversation stays on your machine, semantically indexed and instantly recalled. Install from npm — no clone, no build.</span>
231
- </p>
232
- <div class="hero-tagline">
233
- <span class="lang-zh"><span class="dot"></span>数据 100% 存于本机</span>
234
- <span class="lang-en"><span class="dot"></span>100% on-device</span>
235
- <span class="lang-zh">零上云 · 密码保护</span>
236
- <span class="lang-en">No cloud · Password-protected</span>
237
- </div>
238
- <div class="ctas">
239
- <a href="#quickstart" class="btn btn-primary lang-zh">从 npm 安装</a>
240
- <a href="#quickstart" class="btn btn-primary lang-en">Install from npm</a>
241
- <a href="https://www.npmjs.com/package/@memtensor/memos-local-openclaw-plugin" class="btn btn-outline" target="_blank" rel="noopener">
242
- <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M0 7.334v8h6.666v1.332H12v-1.332h12v-8H0zm6.666 6.664H5.334v-4H3.999v4H1.335V8.667h5.331v5.331zm4 0v1.336H8.001V8.667h5.334v5.331h-2.669zm12.001 0h-1.33v-4h-1.336v4h-1.335V8.667h3.999v5.331zM10.665 10H12v2.667h-1.335V10z"/></svg>
243
- npm
244
- </a>
245
- <a href="https://github.com/MemTensor/MemOS" class="btn btn-outline" target="_blank" rel="noopener">
246
- <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
247
- GitHub
248
- </a>
249
- </div>
250
-
251
- <div class="hero-visual">
252
- <div class="terminal">
253
- <div class="terminal-bar">
254
- <span class="terminal-dot r"></span>
255
- <span class="terminal-dot y"></span>
256
- <span class="terminal-dot g"></span>
257
- <span class="terminal-title lang-zh">终端 — 从 npm 安装</span>
258
- <span class="terminal-title lang-en">Terminal — Install from npm</span>
259
- </div>
260
- <div class="terminal-body">
261
- <div><span class="prompt">$</span> <span class="cmd">openclaw plugins install @memtensor/memos-local-openclaw-plugin</span></div>
262
- <div class="output">Fetching from registry.npmjs.org…</div>
263
- <div class="output">Installing to ~/.openclaw/extensions/…</div>
264
- <div class="output success">✓ Installed plugin: memos-local</div>
265
- <div style="height:12px"></div>
266
- <div><span class="prompt">$</span> <span class="cmd">openclaw gateway start</span></div>
267
- <div class="output">memos-local: initialized <span class="dim">(db: ~/.openclaw/memos-local/memos.db)</span></div>
268
- <div class="output">memos-local: started <span class="dim">(embedding: openai_compatible)</span></div>
269
- <div class="output highlight">╔══════════════════════════════════════════╗</div>
270
- <div class="output highlight">║ MemOS Memory Viewer → <span class="success">http://127.0.0.1:18799</span></div>
271
- <div class="output highlight">╚══════════════════════════════════════════╝</div>
272
- </div>
273
- </div>
274
- </div>
275
- </div>
276
- </section>
277
-
278
- <!-- ════════ Stats ════════ -->
279
- <div class="stats">
280
- <div class="stat"><div class="num">7</div><div class="label lang-zh">检索流水线步骤</div><div class="label lang-en">Retrieval Pipeline Steps</div></div>
281
- <div class="stat"><div class="num">6+</div><div class="label lang-zh">嵌入模型服务商</div><div class="label lang-en">Embedding Providers</div></div>
282
- <div class="stat"><div class="num">4</div><div class="label lang-zh">Agent 工具</div><div class="label lang-en">Agent Tools</div></div>
283
- <div class="stat"><div class="num">100%</div><div class="label lang-zh">本地 · 隐私</div><div class="label lang-en">Local & Private</div></div>
284
- </div>
285
-
286
- <!-- ════════ Features ════════ -->
287
- <section class="section" id="features">
288
- <div class="container">
289
- <div class="section-header">
290
- <div class="section-badge"><span class="line"></span> <span class="lang-zh">功能</span><span class="lang-en">Features</span> <span class="line"></span></div>
291
- <h2><span class="lang-zh">OpenClaw Agent 需要的<span class="accent">记忆能力</span>,一应俱全</span><span class="lang-en">Everything Your OpenClaw Agent Needs to <span class="accent">Remember</span></span></h2>
292
- <p class="section-desc"><span class="lang-zh">为 OpenClaw 打造的完整记忆系统:捕获、索引、召回,<strong>全部在本地完成</strong>。</span><span class="lang-en">A complete memory system built for OpenClaw. Capture, index, and recall every conversation — <strong>all on your machine</strong>.</span></p>
293
- </div>
294
-
295
- <div class="feature-grid">
296
- <div class="feature-card">
297
- <div class="feature-icon blue">💾</div>
298
- <h3><span class="lang-zh">全量写入</span><span class="lang-en">Full-Write Capture</span></h3>
299
- <p><span class="lang-zh">每次对话结束后自动捕获并存入本机。从 npm 安装、配置即用。</span><span class="lang-en">Every user/assistant conversation is captured and stored locally after each turn. Install from npm, add config, go.</span></p>
300
- </div>
301
- <div class="feature-card">
302
- <div class="feature-icon violet">🔍</div>
303
- <h3><span class="lang-zh">混合检索</span><span class="lang-en">Hybrid Retrieval</span></h3>
304
- <p><span class="lang-zh">FTS5 关键词 + 向量语义双路召回,RRF 融合为统一排序。</span><span class="lang-en">FTS5 keyword + vector semantic dual-channel; RRF fusion merges rankings into one score.</span></p>
305
- </div>
306
- <div class="feature-card">
307
- <div class="feature-icon green">🧠</div>
308
- <h3><span class="lang-zh">语义分片</span><span class="lang-en">Semantic Chunking</span></h3>
309
- <p><span class="lang-zh">按代码块、函数体、段落等语义边界切分,不在函数中间截断。</span><span class="lang-en">Splits by code blocks, function bodies, paragraphs. Never cuts mid-function.</span></p>
310
- </div>
311
- <div class="feature-card">
312
- <div class="feature-icon amber">📝</div>
313
- <h3><span class="lang-zh">LLM 摘要</span><span class="lang-en">LLM Summarization</span></h3>
314
- <p><span class="lang-zh">每个分片一句话摘要,加速检索与浏览。</span><span class="lang-en">One-sentence summary per chunk for fast search and browsing.</span></p>
315
- </div>
316
- <div class="feature-card">
317
- <div class="feature-icon red">🎯</div>
318
- <h3><span class="lang-zh">MMR 多样性</span><span class="lang-en">MMR Diversity</span></h3>
319
- <p><span class="lang-zh">MMR 重排保证结果既相关又多样,避免重复。</span><span class="lang-en">MMR reranking for relevant, diverse results — no near-duplicates in top-K.</span></p>
320
- </div>
321
- <div class="feature-card">
322
- <div class="feature-icon pink">⏱️</div>
323
- <h3><span class="lang-zh">时间衰减</span><span class="lang-en">Recency Decay</span></h3>
324
- <p><span class="lang-zh">可配置半衰期,近期记忆权重更高,旧的高相关记忆仍保留。</span><span class="lang-en">Configurable decay biases recent memories while keeping highly relevant older ones.</span></p>
325
- </div>
326
- <div class="feature-card">
327
- <div class="feature-icon blue">🌐</div>
328
- <h3><span class="lang-zh">Web 记忆管理</span><span class="lang-en">Web Memory Viewer</span></h3>
329
- <p><span class="lang-zh">内置管理页:浏览、搜索、CRUD、分页、过滤,<strong>密码保护、仅本机可访问</strong>。</span><span class="lang-en">Built-in dashboard: browse, search, CRUD, pagination, filters. <strong>Password-protected, localhost only</strong>.</span></p>
330
- </div>
331
- <div class="feature-card">
332
- <div class="feature-icon violet">🔐</div>
333
- <h3><span class="lang-zh">本地优先 · 安全隐私</span><span class="lang-en">Local-First · Secure & Private</span></h3>
334
- <p><span class="lang-zh"><strong>数据 100% 存于本机</strong>,SQLite 本地库,零上云、无埋点。Viewer 仅监听 127.0.0.1,密码保护。</span><span class="lang-en"><strong>100% on-device</strong> — SQLite on your machine, no cloud uploads, no telemetry. Viewer binds to 127.0.0.1 only, password-protected.</span></p>
335
- </div>
336
- <div class="feature-card">
337
- <div class="feature-icon green">🔌</div>
338
- <h3><span class="lang-zh">多服务商</span><span class="lang-en">Multi-Provider</span></h3>
339
- <p><span class="lang-zh">Embedding/摘要支持 OpenAI、Anthropic、Gemini、Cohere、Voyage、Bedrock 等,可降级到本地模型。</span><span class="lang-en">OpenAI, Anthropic, Gemini, Cohere, Voyage, Mistral, Bedrock; falls back to local model.</span></p>
340
- </div>
341
- </div>
342
- </div>
343
- </section>
344
-
345
- <!-- ════════ Architecture ════════ -->
346
- <section class="section" id="architecture">
347
- <div class="container">
348
- <div class="section-header">
349
- <div class="section-badge"><span class="line"></span> <span class="lang-zh">架构</span><span class="lang-en">Architecture</span> <span class="line"></span></div>
350
- <h2><span class="lang-zh">如何<span class="accent">工作</span></span><span class="lang-en">How It <span class="accent">Works</span></span></h2>
351
- <p class="section-desc"><span class="lang-zh">7 步检索流水线:相关性、多样性、时间衰减兼顾。</span><span class="lang-en">A 7-step retrieval pipeline balancing relevance, diversity, and recency.</span></p>
352
- </div>
353
-
354
- <h3 style="text-align:center;font-size:14px;color:var(--text-sec);margin-bottom:24px;font-weight:500" class="lang-zh">写入路径 — 每次 agent 轮次自动捕获</h3>
355
- <h3 style="text-align:center;font-size:14px;color:var(--text-sec);margin-bottom:24px;font-weight:500" class="lang-en">Write Path — Automatic capture on every agent turn</h3>
356
- <div class="arch-flow">
357
- <div class="arch-step"><span class="step-num">1</span><div class="step-icon">💬</div><h4>Capture</h4><p>Filter user &amp; assistant messages</p></div>
358
- <div class="arch-arrow">→</div>
359
- <div class="arch-step"><span class="step-num">2</span><div class="step-icon">✂️</div><h4>Chunk</h4><p>Semantic-aware text splitting</p></div>
360
- <div class="arch-arrow">→</div>
361
- <div class="arch-step"><span class="step-num">3</span><div class="step-icon">📝</div><h4>Summarize</h4><p>LLM one-sentence summary</p></div>
362
- <div class="arch-arrow">→</div>
363
- <div class="arch-step"><span class="step-num">4</span><div class="step-icon">🧮</div><h4>Embed</h4><p>Vector embedding generation</p></div>
364
- <div class="arch-arrow">→</div>
365
- <div class="arch-step"><span class="step-num">5</span><div class="step-icon">🔄</div><h4>Dedup</h4><p>Cosine similarity ≥ 0.93 merge</p></div>
366
- <div class="arch-arrow">→</div>
367
- <div class="arch-step"><span class="step-num">6</span><div class="step-icon">💾</div><h4>Store</h4><p>SQLite + FTS5 + Vector</p></div>
368
- </div>
369
-
370
- <div style="height:48px"></div>
371
-
372
- <h3 style="text-align:center;font-size:14px;color:var(--text-sec);margin-bottom:24px;font-weight:500" class="lang-zh">读取路径 — 混合检索与多阶段排序</h3>
373
- <h3 style="text-align:center;font-size:14px;color:var(--text-sec);margin-bottom:24px;font-weight:500" class="lang-en">Read Path — Hybrid search with multi-stage ranking</h3>
374
- <div class="arch-flow">
375
- <div class="arch-step"><span class="step-num">1</span><div class="step-icon">🔍</div><h4>Dual Recall</h4><p>FTS5 + Vector search</p></div>
376
- <div class="arch-arrow">→</div>
377
- <div class="arch-step"><span class="step-num">2</span><div class="step-icon">🔀</div><h4>RRF Fusion</h4><p>Rank-based score merge</p></div>
378
- <div class="arch-arrow">→</div>
379
- <div class="arch-step"><span class="step-num">3</span><div class="step-icon">🎯</div><h4>MMR Rerank</h4><p>Diversity optimization</p></div>
380
- <div class="arch-arrow">→</div>
381
- <div class="arch-step"><span class="step-num">4</span><div class="step-icon">⏱️</div><h4>Decay</h4><p>Time-based recency bias</p></div>
382
- <div class="arch-arrow">→</div>
383
- <div class="arch-step"><span class="step-num">5</span><div class="step-icon">✅</div><h4>Filter</h4><p>Score threshold + Top-K</p></div>
384
- </div>
385
- </div>
386
- </section>
387
-
388
- <!-- ════════ Code Preview ════════ -->
389
- <section class="section" id="code">
390
- <div class="container">
391
- <div class="section-header">
392
- <div class="section-badge"><span class="line"></span> <span class="lang-zh">快速开始</span><span class="lang-en">Quick Start</span> <span class="line"></span></div>
393
- <h2><span class="lang-zh">几分钟<span class="accent">上手</span></span><span class="lang-en">Up and Running in <span class="accent">Minutes</span></span></h2>
394
- </div>
395
-
396
- <div class="code-section" id="quickstart">
397
- <div class="code-text">
398
- <h3><span class="lang-zh">从 npm 安装并配置</span><span class="lang-en">Install from npm &amp; Configure</span></h3>
399
- <p><span class="lang-zh">从 npm 安装,无需克隆或构建。在 openclaw.json 中加上插件配置(embedding/summarizer 可选),然后<strong>启动或重启 gateway</strong>。Memory Viewer 只有在网关运行时才会在 http://127.0.0.1:18799 提供。</span><span class="lang-en">Install from npm — no clone or build. Add OpenClaw config (embedding/summarizer optional), then <strong>start or restart the gateway</strong>. The Memory Viewer is only available at http://127.0.0.1:18799 when the gateway is running.</span></p>
400
- <div>
401
- <span class="tag t-blue">npm</span>
402
- <span class="tag t-violet">OpenClaw</span>
403
- <span class="tag t-green">Zero build</span>
404
- </div>
405
- </div>
406
- <div class="code-block">
407
- <div class="code-header">
408
- <span class="dot r" style="width:10px;height:10px;border-radius:50%;background:#ff5f57"></span>
409
- <span class="dot" style="width:10px;height:10px;border-radius:50%;background:#ffbd2e"></span>
410
- <span class="dot" style="width:10px;height:10px;border-radius:50%;background:#28ca42"></span>
411
- <span style="flex:1"></span>
412
- terminal
413
- </div>
414
- <pre><span class="cmt"># Install from npm (pulls latest)</span>
415
- <span class="kw">openclaw</span> plugins install @memtensor/memos-local-openclaw-plugin
416
-
417
- <span class="cmt"># Add plugin slot + config to ~/.openclaw/openclaw.json, then:</span>
418
- <span class="kw">openclaw</span> gateway start</pre>
419
- </div>
420
- </div>
421
-
422
- <div style="height:64px"></div>
423
-
424
- <div class="code-section" style="direction:rtl">
425
- <div class="code-text" style="direction:ltr">
426
- <h3><span class="lang-zh">搜索记忆</span><span class="lang-en">Search Memories</span></h3>
427
- <p><span class="lang-zh">OpenClaw agent 会自动调用 <code style="background:rgba(0,187,238,.1);color:var(--pri);padding:2px 8px;border-radius:4px;font-size:13px">memory_search</code> 回忆过往对话,返回摘要、摘录、相关度与角色标签。</span><span class="lang-en">Your OpenClaw agent uses <code style="background:rgba(0,187,238,.1);color:var(--pri);padding:2px 8px;border-radius:4px;font-size:13px">memory_search</code> to recall past conversations — summaries, excerpts, scores, role labels.</span></p>
428
- <div>
429
- <span class="tag t-blue">Hybrid Search</span>
430
- <span class="tag t-violet">Vector + FTS5</span>
431
- <span class="tag t-green">Score Ranking</span>
432
- </div>
433
- </div>
434
- <div class="code-block" style="direction:ltr">
435
- <div class="code-header">
436
- <span class="dot" style="width:10px;height:10px;border-radius:50%;background:#ff5f57"></span>
437
- <span class="dot" style="width:10px;height:10px;border-radius:50%;background:#ffbd2e"></span>
438
- <span class="dot" style="width:10px;height:10px;border-radius:50%;background:#28ca42"></span>
439
- <span style="flex:1"></span>
440
- memory_search response
441
- </div>
442
- <pre><span class="cmt">// Agent calls memory_search({ query: "password reset" })</span>
443
-
444
- Found <span class="num">3</span> memories (minScore=<span class="num">0.45</span>):
445
-
446
- <span class="num">1.</span> <span class="kw">[USER said]</span> [score=<span class="num">0.847</span>]
447
- Requested password reset feature for Memory Viewer
448
- <span class="str">Evidence: "密码忘记了怎么办..."</span>
449
-
450
- <span class="num">2.</span> <span class="fn">[ASSISTANT replied]</span> [score=<span class="num">0.791</span>]
451
- Implemented reset token mechanism via gateway logs
452
- <span class="str">Evidence: "Added /api/auth/reset endpoint..."</span>
453
-
454
- <span class="num">3.</span> <span class="kw">[USER said]</span> [score=<span class="num">0.683</span>]
455
- Asked about authentication and session management
456
- <span class="str">Evidence: "Web viewer needs password protection..."</span></pre>
457
- </div>
458
- </div>
459
-
460
- <div style="height:64px"></div>
461
-
462
- <div class="code-section">
463
- <div class="code-text">
464
- <h3><span class="lang-zh">在 JSON 中配置</span><span class="lang-en">Configure in JSON</span></h3>
465
- <p><span class="lang-zh">检索参数、去重阈值、时间衰减等均可配置,全部可选,有合理默认值。</span><span class="lang-en">Fine-tune retrieval, dedup, decay, etc. All optional with sensible defaults.</span></p>
466
- <div>
467
- <span class="tag t-blue">RRF k=60</span>
468
- <span class="tag t-violet">MMR λ=0.7</span>
469
- <span class="tag t-green">Decay 14d</span>
470
- </div>
471
- </div>
472
- <div class="code-block">
473
- <div class="code-header">
474
- <span class="dot" style="width:10px;height:10px;border-radius:50%;background:#ff5f57"></span>
475
- <span class="dot" style="width:10px;height:10px;border-radius:50%;background:#ffbd2e"></span>
476
- <span class="dot" style="width:10px;height:10px;border-radius:50%;background:#28ca42"></span>
477
- <span style="flex:1"></span>
478
- openclaw.json
479
- </div>
480
- <pre>{
481
- <span class="str">"plugins"</span>: {
482
- <span class="str">"slots"</span>: { <span class="str">"memory"</span>: <span class="str">"memos-local"</span> },
483
- <span class="str">"entries"</span>: {
484
- <span class="str">"memos-local"</span>: {
485
- <span class="str">"enabled"</span>: <span class="kw">true</span>,
486
- <span class="str">"config"</span>: {
487
- <span class="str">"embedding"</span>: {
488
- <span class="str">"provider"</span>: <span class="str">"openai_compatible"</span>,
489
- <span class="str">"model"</span>: <span class="str">"bge-m3"</span>
490
- },
491
- <span class="str">"summarizer"</span>: {
492
- <span class="str">"provider"</span>: <span class="str">"openai_compatible"</span>,
493
- <span class="str">"model"</span>: <span class="str">"gpt-4o-mini"</span>
494
- }
495
- }
496
- }
497
- }
498
- }
499
- }</pre>
500
- </div>
501
- </div>
502
- </div>
503
- </section>
504
-
505
- <!-- ════════ Providers ════════ -->
506
- <section class="section" id="providers">
507
- <div class="container">
508
- <div class="section-header">
509
- <div class="section-badge"><span class="line"></span> <span class="lang-zh">服务商</span><span class="lang-en">Providers</span> <span class="line"></span></div>
510
- <h2><span class="lang-zh">适配你的<span class="accent">技术栈</span></span><span class="lang-en">Works with Your <span class="accent">Stack</span></span></h2>
511
- <p class="section-desc"><span class="lang-zh">任意 embedding/摘要服务商均可接入;离线时可降级到本地模型。</span><span class="lang-en">Any embedding or summarization provider. Falls back to local models when offline.</span></p>
512
- </div>
513
-
514
- <div class="provider-grid">
515
- <div class="provider"><span class="p-icon">🤖</span> OpenAI</div>
516
- <div class="provider"><span class="p-icon">🧠</span> Anthropic</div>
517
- <div class="provider"><span class="p-icon">💎</span> Gemini</div>
518
- <div class="provider"><span class="p-icon">☁️</span> AWS Bedrock</div>
519
- <div class="provider"><span class="p-icon">🔷</span> Cohere</div>
520
- <div class="provider"><span class="p-icon">🚀</span> Voyage AI</div>
521
- <div class="provider"><span class="p-icon">🌀</span> Mistral</div>
522
- <div class="provider"><span class="p-icon">💻</span> Local (Xenova)</div>
523
- </div>
524
-
525
- <p style="text-align:center;color:var(--text-thr);font-size:13px;margin-top:20px">
526
- <span class="lang-zh">任意 OpenAI 兼容 API 即插即用。可用 <code style="color:var(--text-sec);background:rgba(255,255,255,.05);padding:2px 6px;border-radius:4px;font-size:12px">${ENV_VAR}</code> 占位符管理密钥。</span>
527
- <span class="lang-en">Any OpenAI-compatible API works. Use <code style="color:var(--text-sec);background:rgba(255,255,255,.05);padding:2px 6px;border-radius:4px;font-size:12px">${ENV_VAR}</code> for secure keys.</span>
528
- </p>
529
- </div>
530
- </section>
531
-
532
- <!-- ════════ CTA ════════ -->
533
- <section class="cta-section">
534
- <div class="container">
535
- <h2><span class="lang-zh">为 OpenClaw Agent 赋予<span class="gradient" style="background:linear-gradient(135deg,var(--pri),var(--violet));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text">持久记忆</span></span><span class="lang-en">Give Your OpenClaw Agent a <span class="gradient" style="background:linear-gradient(135deg,var(--pri),var(--violet));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text">Memory</span></span></h2>
536
- <p class="desc"><span class="lang-zh">官方记忆插件 · 从 npm 安装,无需克隆与构建。<br>本地存储、安全隐私 · MIT 许可。</span><span class="lang-en">Official memory plugin. Install from npm — no clone, no build.<br>Local-first, secure &amp; private. MIT licensed.</span></p>
537
- <div style="display:flex;gap:14px;justify-content:center;flex-wrap:wrap">
538
- <a href="https://www.npmjs.com/package/@memtensor/memos-local-openclaw-plugin" class="btn btn-primary" target="_blank" rel="noopener">
539
- <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M0 7.334v8h6.666v1.332H12v-1.332h12v-8H0zm6.666 6.664H5.334v-4H3.999v4H1.335V8.667h5.331v5.331zm4 0v1.336H8.001V8.667h5.334v5.331h-2.669zm12.001 0h-1.33v-4h-1.336v4h-1.335V8.667h3.999v5.331zM10.665 10H12v2.667h-1.335V10z"/></svg>
540
- <span class="lang-zh">从 npm 安装</span><span class="lang-en">Install from npm</span>
541
- </a>
542
- <a href="./docs/index.html" class="btn btn-outline lang-zh">查看文档 →</a>
543
- <a href="./docs/index.html" class="btn btn-outline lang-en">Read the Docs →</a>
544
- <a href="https://github.com/MemTensor/MemOS" class="btn btn-outline" target="_blank" rel="noopener">GitHub</a>
545
- </div>
546
- </div>
547
- </section>
548
-
549
- <!-- ════════ Footer ════════ -->
550
- <footer>
551
- <div class="container">
552
- <div class="inner">
553
- <div class="brand"><span class="icon">🦞</span> OpenClaw · Powered by MemOS</div>
554
- <div class="links">
555
- <a href="./docs/index.html" class="lang-zh">文档</a>
556
- <a href="./docs/index.html" class="lang-en">Documentation</a>
557
- <a href="https://www.npmjs.com/package/@memtensor/memos-local-openclaw-plugin" target="_blank" rel="noopener">npm</a>
558
- <a href="https://github.com/MemTensor/MemOS" target="_blank" rel="noopener">GitHub</a>
559
- <a href="https://github.com/MemTensor/MemOS/issues" target="_blank" rel="noopener">Issues</a>
560
- <a href="https://github.com/MemTensor/MemOS/blob/main/LICENSE" target="_blank" rel="noopener">MIT License</a>
561
- </div>
562
- </div>
563
- <div class="copy"><span class="lang-zh">© 2026 MemTensor. OpenClaw 官方记忆插件,本地优先 · 安全隐私。MIT 许可。</span><span class="lang-en">© 2026 MemTensor. Official OpenClaw memory plugin. Local-first, secure. MIT license.</span></div>
564
- </div>
565
- </footer>
566
-
567
- <!-- ── Language toggle ── -->
568
- <script>
569
- (function(){
570
- var key='memos-local-lang';
571
- var lang=(typeof localStorage!=='undefined'&&localStorage.getItem(key))||'zh';
572
- document.body.classList.add('lang-'+lang);
573
- document.querySelectorAll('.lang-btn').forEach(function(btn){
574
- btn.classList.toggle('active',btn.getAttribute('data-lang')===lang);
575
- btn.addEventListener('click',function(){
576
- var L=this.getAttribute('data-lang');
577
- document.body.classList.remove('lang-zh','lang-en');
578
- document.body.classList.add('lang-'+L);
579
- try{localStorage.setItem(key,L);}catch(e){}
580
- document.querySelectorAll('.lang-btn').forEach(function(b){b.classList.toggle('active',b.getAttribute('data-lang')===L);});
581
- });
582
- });
583
- })();
584
- </script>
585
- <!-- ── Scroll animations ── -->
586
- <script>
587
- (function(){
588
- const observer=new IntersectionObserver((entries)=>{
589
- entries.forEach(e=>{
590
- if(e.isIntersecting){
591
- e.target.style.opacity='1';
592
- e.target.style.transform='translateY(0)';
593
- }
594
- });
595
- },{threshold:0.1,rootMargin:'0px 0px -40px 0px'});
596
-
597
- document.querySelectorAll('.feature-card,.arch-step,.provider,.code-section,.stat').forEach(el=>{
598
- el.style.opacity='0';
599
- el.style.transform='translateY(24px)';
600
- el.style.transition='opacity .5s ease, transform .5s ease';
601
- observer.observe(el);
602
- });
603
- })();
604
- </script>
605
- </body>
606
- </html>