@memtensor/memos-local-openclaw-plugin 1.0.4-beta.5 → 1.0.4-beta.6
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.
- package/README.md +22 -39
- package/dist/capture/index.d.ts.map +1 -1
- package/dist/capture/index.js +6 -0
- package/dist/capture/index.js.map +1 -1
- package/dist/config.d.ts +1 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -72
- package/dist/config.js.map +1 -1
- package/dist/embedding/index.d.ts +2 -4
- package/dist/embedding/index.d.ts.map +1 -1
- package/dist/embedding/index.js +1 -17
- package/dist/embedding/index.js.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/ingest/providers/index.d.ts +2 -10
- package/dist/ingest/providers/index.d.ts.map +1 -1
- package/dist/ingest/providers/index.js +43 -209
- package/dist/ingest/providers/index.js.map +1 -1
- package/dist/ingest/providers/openai.d.ts +0 -1
- package/dist/ingest/providers/openai.d.ts.map +1 -1
- package/dist/ingest/providers/openai.js +0 -1
- package/dist/ingest/providers/openai.js.map +1 -1
- package/dist/ingest/task-processor.js +1 -1
- package/dist/ingest/task-processor.js.map +1 -1
- package/dist/recall/engine.js +1 -1
- package/dist/recall/engine.js.map +1 -1
- package/dist/shared/llm-call.d.ts +2 -4
- package/dist/shared/llm-call.d.ts.map +1 -1
- package/dist/shared/llm-call.js +81 -20
- package/dist/shared/llm-call.js.map +1 -1
- package/dist/skill/evaluator.d.ts.map +1 -1
- package/dist/skill/evaluator.js +2 -2
- package/dist/skill/evaluator.js.map +1 -1
- package/dist/skill/evolver.d.ts +2 -0
- package/dist/skill/evolver.d.ts.map +1 -1
- package/dist/skill/evolver.js +3 -0
- package/dist/skill/evolver.js.map +1 -1
- package/dist/skill/generator.d.ts.map +1 -1
- package/dist/skill/generator.js +4 -4
- package/dist/skill/generator.js.map +1 -1
- package/dist/skill/upgrader.js +1 -1
- package/dist/skill/upgrader.js.map +1 -1
- package/dist/skill/validator.js +1 -1
- package/dist/skill/validator.js.map +1 -1
- package/dist/storage/ensure-binding.d.ts.map +1 -1
- package/dist/storage/ensure-binding.js +1 -3
- package/dist/storage/ensure-binding.js.map +1 -1
- package/dist/storage/sqlite.d.ts +0 -294
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +0 -821
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/telemetry.d.ts +12 -5
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +135 -38
- package/dist/telemetry.js.map +1 -1
- package/dist/tools/index.d.ts +0 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -3
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/memory-search.d.ts +2 -3
- package/dist/tools/memory-search.d.ts.map +1 -1
- package/dist/tools/memory-search.js +7 -48
- package/dist/tools/memory-search.js.map +1 -1
- package/dist/types.d.ts +2 -49
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +492 -3008
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +0 -45
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +18 -1155
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +42 -430
- package/openclaw.plugin.json +1 -2
- package/package.json +3 -4
- package/scripts/postinstall.cjs +46 -283
- package/skill/memos-memory-guide/SKILL.md +2 -26
- package/src/capture/index.ts +8 -0
- package/src/config.ts +3 -94
- package/src/embedding/index.ts +1 -21
- package/src/index.ts +4 -7
- package/src/ingest/providers/index.ts +46 -246
- package/src/ingest/providers/openai.ts +1 -1
- package/src/ingest/task-processor.ts +1 -1
- package/src/recall/engine.ts +1 -1
- package/src/shared/llm-call.ts +95 -23
- package/src/skill/evaluator.ts +2 -3
- package/src/skill/evolver.ts +5 -0
- package/src/skill/generator.ts +4 -6
- package/src/skill/upgrader.ts +1 -1
- package/src/skill/validator.ts +1 -1
- package/src/storage/ensure-binding.ts +1 -3
- package/src/storage/sqlite.ts +0 -1085
- package/src/telemetry.ts +152 -39
- package/src/tools/index.ts +0 -1
- package/src/tools/memory-search.ts +8 -57
- package/src/types.ts +2 -44
- package/src/viewer/html.ts +492 -3008
- package/src/viewer/server.ts +21 -1070
- package/dist/client/connector.d.ts +0 -30
- package/dist/client/connector.d.ts.map +0 -1
- package/dist/client/connector.js +0 -219
- package/dist/client/connector.js.map +0 -1
- package/dist/client/hub.d.ts +0 -61
- package/dist/client/hub.d.ts.map +0 -1
- package/dist/client/hub.js +0 -148
- package/dist/client/hub.js.map +0 -1
- package/dist/client/skill-sync.d.ts +0 -29
- package/dist/client/skill-sync.d.ts.map +0 -1
- package/dist/client/skill-sync.js +0 -216
- package/dist/client/skill-sync.js.map +0 -1
- package/dist/hub/auth.d.ts +0 -19
- package/dist/hub/auth.d.ts.map +0 -1
- package/dist/hub/auth.js +0 -70
- package/dist/hub/auth.js.map +0 -1
- package/dist/hub/server.d.ts +0 -41
- package/dist/hub/server.d.ts.map +0 -1
- package/dist/hub/server.js +0 -747
- package/dist/hub/server.js.map +0 -1
- package/dist/hub/user-manager.d.ts +0 -29
- package/dist/hub/user-manager.d.ts.map +0 -1
- package/dist/hub/user-manager.js +0 -125
- package/dist/hub/user-manager.js.map +0 -1
- package/dist/openclaw-api.d.ts +0 -53
- package/dist/openclaw-api.d.ts.map +0 -1
- package/dist/openclaw-api.js +0 -189
- package/dist/openclaw-api.js.map +0 -1
- package/dist/sharing/types.contract.d.ts +0 -2
- package/dist/sharing/types.contract.d.ts.map +0 -1
- package/dist/sharing/types.contract.js +0 -3
- package/dist/sharing/types.contract.js.map +0 -1
- package/dist/sharing/types.d.ts +0 -80
- package/dist/sharing/types.d.ts.map +0 -1
- package/dist/sharing/types.js +0 -3
- package/dist/sharing/types.js.map +0 -1
- package/dist/tools/network-memory-detail.d.ts +0 -4
- package/dist/tools/network-memory-detail.d.ts.map +0 -1
- package/dist/tools/network-memory-detail.js +0 -34
- package/dist/tools/network-memory-detail.js.map +0 -1
- package/src/client/connector.ts +0 -218
- package/src/client/hub.ts +0 -189
- package/src/client/skill-sync.ts +0 -202
- package/src/hub/auth.ts +0 -78
- package/src/hub/server.ts +0 -740
- package/src/hub/user-manager.ts +0 -139
- package/src/openclaw-api.ts +0 -287
- package/src/sharing/types.contract.ts +0 -40
- package/src/sharing/types.ts +0 -102
- package/src/tools/network-memory-detail.ts +0 -34
package/dist/viewer/html.js
CHANGED
|
@@ -8,8 +8,7 @@ function viewerHTML(pluginVersion) {
|
|
|
8
8
|
<head>
|
|
9
9
|
<meta charset="UTF-8">
|
|
10
10
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
11
|
-
<
|
|
12
|
-
<title>MemOS 记忆</title>
|
|
11
|
+
<title>OpenClaw Memory - Powered by MemOS</title>
|
|
13
12
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
14
13
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
15
14
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
@@ -62,9 +61,8 @@ function viewerHTML(pluginVersion) {
|
|
|
62
61
|
[data-theme="light"] .analytics-card.amber .ac-value{color:#d97706}
|
|
63
62
|
[data-theme="light"] .analytics-section{background:#fff;border-color:var(--border);box-shadow:0 1px 3px rgba(0,0,0,.04)}
|
|
64
63
|
[data-theme="light"] .analytics-section::before{background:none}
|
|
65
|
-
[data-theme="light"] .chart-bar{box-shadow:
|
|
66
|
-
[data-theme="light"] .chart-bar:hover{box-shadow:0
|
|
67
|
-
[data-theme="light"] .chart-bars::before{opacity:.3}
|
|
64
|
+
[data-theme="light"] .chart-bar{box-shadow:none}
|
|
65
|
+
[data-theme="light"] .chart-bar:hover{box-shadow:0 2px 8px rgba(79,70,229,.15)}
|
|
68
66
|
[data-theme="light"] .tool-chart-tooltip{background:rgba(17,24,39,.92);color:#e8eaed;border-color:rgba(99,102,241,.3);box-shadow:0 8px 24px rgba(0,0,0,.2)}
|
|
69
67
|
[data-theme="light"] .tool-chart-tooltip .tt-time{color:#a5b4fc}
|
|
70
68
|
[data-theme="light"] .tool-chart-tooltip .tt-val{color:#e8eaed}
|
|
@@ -109,16 +107,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
109
107
|
|
|
110
108
|
/* ─── App Layout (dark dashboard, same as www) ─── */
|
|
111
109
|
.app{display:none;flex-direction:column;min-height:100vh}
|
|
112
|
-
.topbar{background:rgba(11,13,17,.88);border-bottom:1px solid var(--border);padding:0
|
|
113
|
-
.topbar .brand{display:flex;align-items:center;gap:
|
|
114
|
-
.topbar .brand .icon{width:
|
|
115
|
-
.topbar .brand .brand-title{font-size:13px;font-weight:500;opacity:.7}
|
|
116
|
-
.topbar .brand .brand-col{display:flex;flex-direction:column;gap:0}
|
|
117
|
-
.topbar .brand .brand-powered{font-size:9px;font-weight:500;color:var(--text-sec);opacity:.55;letter-spacing:.02em;line-height:1}
|
|
110
|
+
.topbar{background:rgba(11,13,17,.88);border-bottom:1px solid var(--border);padding:0 28px;height:56px;display:flex;align-items:center;position:sticky;top:0;z-index:100;backdrop-filter:blur(12px)}
|
|
111
|
+
.topbar .brand{display:flex;align-items:center;gap:10px;font-weight:700;font-size:15px;color:var(--text);letter-spacing:-.02em;flex-shrink:0}
|
|
112
|
+
.topbar .brand .icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;font-size:22px;background:none;border-radius:0}
|
|
118
113
|
.topbar .brand .sub{font-weight:400;color:var(--text-muted);font-size:11px}
|
|
119
|
-
.memos-logo{display:inline-flex;align-items:center}
|
|
120
|
-
.memos-logo svg{height:28px;width:28px}
|
|
121
|
-
.brand-sep{width:1px;height:20px;background:var(--border);opacity:.5;margin:0 2px}
|
|
122
114
|
.version-badge{font-size:10px;font-weight:600;color:var(--text-muted);background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.1);padding:1px 7px;border-radius:6px;margin-left:6px;letter-spacing:.02em;user-select:all}
|
|
123
115
|
[data-theme="light"] .version-badge{background:rgba(0,0,0,.05);border-color:rgba(0,0,0,.08);color:var(--text-sec)}
|
|
124
116
|
.topbar-center{flex:1;display:flex;justify-content:center}
|
|
@@ -156,101 +148,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
156
148
|
.search-bar input:focus{border-color:var(--pri);box-shadow:0 0 0 3px var(--pri-glow)}
|
|
157
149
|
.search-bar .search-icon{position:absolute;left:14px;top:50%;transform:translateY(-50%);color:var(--text-muted);font-size:14px;pointer-events:none}
|
|
158
150
|
.search-meta{font-size:12px;color:var(--text-sec);margin-bottom:14px;padding:0 2px}
|
|
159
|
-
.scope-select{padding:10px 12px;border:1px solid var(--border);border-radius:10px;background:var(--bg-card);color:var(--text);font-size:13px;min-width:110px;outline:none}
|
|
160
|
-
.sharing-inline-meta{font-size:12px;color:var(--text-muted);margin:-8px 0 14px 2px}
|
|
161
|
-
.sharing-sidebar-card{margin:14px 0 18px;border:1px solid var(--border);background:var(--bg-card);border-radius:12px;padding:12px;box-shadow:var(--shadow-sm)}
|
|
162
|
-
.sharing-sidebar-card .title{font-size:12px;font-weight:700;color:var(--text);margin-bottom:8px;text-transform:uppercase;letter-spacing:.04em}
|
|
163
|
-
.sharing-sidebar-card .status{font-size:13px;color:var(--text-sec);line-height:1.5}
|
|
164
|
-
.sharing-sidebar-card .status strong{color:var(--text)}
|
|
165
|
-
.sharing-sidebar-card .hint{margin-top:8px;font-size:11px;color:var(--text-muted)}
|
|
166
|
-
.sharing-sidebar-card .user-row{display:flex;align-items:center;gap:8px;margin-bottom:10px}
|
|
167
|
-
.sharing-sidebar-card .user-row .username{font-size:13px;font-weight:600;color:var(--text)}
|
|
168
|
-
.sharing-sidebar-card .role-badge{display:inline-block;font-size:10px;font-weight:600;padding:2px 8px;border-radius:9999px;line-height:1.4;letter-spacing:.02em}
|
|
169
|
-
.sharing-sidebar-card .role-badge.admin{background:rgba(52,199,89,.15);color:#34c759}
|
|
170
|
-
.sharing-sidebar-card .role-badge.client{background:rgba(175,82,222,.15);color:#af52de}
|
|
171
|
-
.sharing-sidebar-card .info-grid{display:grid;grid-template-columns:auto 1fr;gap:4px 10px;font-size:12px;margin-bottom:8px}
|
|
172
|
-
.sharing-sidebar-card .info-grid .label{color:var(--text-muted);font-weight:500;white-space:nowrap}
|
|
173
|
-
.sharing-sidebar-card .info-grid .value{color:var(--text-sec);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
174
|
-
.sharing-sidebar-card .api-badge{display:inline-block;font-size:10px;font-weight:600;padding:2px 8px;border-radius:9999px;background:rgba(142,142,147,.12);color:var(--text-muted);letter-spacing:.02em}
|
|
175
|
-
[data-theme="light"] .sharing-sidebar-card .role-badge.admin{background:rgba(5,150,105,.1);color:#059669}
|
|
176
|
-
[data-theme="light"] .sharing-sidebar-card .role-badge.client{background:rgba(124,58,237,.1);color:#7c3aed}
|
|
177
|
-
.result-section{margin-bottom:18px;border:1px solid var(--border);border-radius:14px;background:var(--bg-card);overflow:hidden}
|
|
178
|
-
.result-section-header{display:flex;justify-content:space-between;align-items:center;padding:12px 14px;border-bottom:1px solid var(--border);background:rgba(255,255,255,.02)}
|
|
179
|
-
.result-section-title{font-size:14px;font-weight:700;color:var(--text)}
|
|
180
|
-
.result-section-sub{font-size:12px;color:var(--text-muted)}
|
|
181
|
-
.search-hit-list{padding:12px;display:flex;flex-direction:column;gap:10px}
|
|
182
|
-
.search-hit-card,.hub-hit-card,.hub-skill-card{border:1px solid var(--border);border-radius:12px;background:var(--bg);padding:12px;box-shadow:var(--shadow-sm)}
|
|
183
|
-
.search-hit-card .summary,.hub-hit-card .summary,.hub-skill-card .summary{font-size:14px;font-weight:600;color:var(--text);margin-bottom:6px}
|
|
184
|
-
.search-hit-card .excerpt,.hub-hit-card .excerpt,.hub-skill-card .excerpt{font-size:12px;color:var(--text-sec);line-height:1.55;white-space:pre-wrap}
|
|
185
|
-
.search-hit-meta,.hub-hit-meta,.hub-skill-meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px;font-size:11px;color:var(--text-muted)}
|
|
186
|
-
.meta-chip{display:inline-flex;align-items:center;gap:5px;padding:4px 8px;border:1px solid var(--border);border-radius:999px;background:var(--bg-card)}
|
|
187
|
-
.hub-hit-actions,.hub-skill-actions,.task-share-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
|
|
188
|
-
.sharing-settings-grid{display:grid;grid-template-columns:1.1fr .9fr;gap:18px}
|
|
189
|
-
.sharing-panel{border:1px solid var(--border);border-radius:14px;background:var(--bg-card);padding:14px;box-shadow:var(--shadow-sm)}
|
|
190
|
-
.sharing-panel h4{font-size:14px;font-weight:700;color:var(--text);margin:0 0 10px 0}
|
|
191
|
-
.sharing-panel .line{font-size:13px;color:var(--text-sec);margin-bottom:8px;line-height:1.55}
|
|
192
|
-
.sharing-panel .line strong{color:var(--text)}
|
|
193
|
-
.pending-user-list{display:flex;flex-direction:column;gap:10px}
|
|
194
|
-
.pending-user-card{border:1px solid var(--border);border-radius:12px;padding:12px;background:var(--bg)}
|
|
195
|
-
.pending-user-name{font-size:14px;font-weight:700;color:var(--text)}
|
|
196
|
-
.pending-user-meta{font-size:12px;color:var(--text-sec);margin-top:4px}
|
|
197
|
-
.pending-user-actions{display:flex;gap:8px;margin-top:10px}
|
|
198
|
-
/* ─── Admin Panel ─── */
|
|
199
|
-
.admin-header{position:relative;padding:28px 28px 20px;background:linear-gradient(135deg,rgba(99,102,241,.08) 0%,rgba(139,92,246,.06) 50%,rgba(6,182,212,.05) 100%);border:1px solid rgba(99,102,241,.12);border-radius:16px;margin-bottom:20px;overflow:hidden}
|
|
200
|
-
.admin-header::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,var(--violet),var(--pri),var(--cyan));border-radius:16px 16px 0 0}
|
|
201
|
-
.admin-header-top{display:flex;justify-content:space-between;align-items:center}
|
|
202
|
-
.admin-header h2{font-size:20px;font-weight:800;color:var(--text);display:flex;align-items:center;gap:10px;margin:0}
|
|
203
|
-
.admin-header h2 .ah-icon{width:36px;height:36px;border-radius:10px;background:linear-gradient(135deg,var(--pri),var(--violet));display:flex;align-items:center;justify-content:center;font-size:18px;box-shadow:0 4px 12px rgba(99,102,241,.25)}
|
|
204
|
-
.admin-header-sub{font-size:12px;color:var(--text-muted);margin-top:6px}
|
|
205
|
-
.admin-stat-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;margin-top:18px}
|
|
206
|
-
.admin-stat-box{position:relative;text-align:center;padding:16px 8px 14px;background:var(--bg-card);border:1px solid var(--border);border-radius:12px;overflow:hidden;transition:all .2s}
|
|
207
|
-
.admin-stat-box:hover{border-color:rgba(99,102,241,.25);transform:translateY(-1px);box-shadow:0 4px 12px rgba(0,0,0,.06)}
|
|
208
|
-
.admin-stat-box::before{content:'';position:absolute;top:0;left:50%;transform:translateX(-50%);width:40px;height:2px;border-radius:0 0 4px 4px}
|
|
209
|
-
.admin-stat-box:nth-child(1)::before{background:var(--green)}
|
|
210
|
-
.admin-stat-box:nth-child(2)::before{background:var(--amber)}
|
|
211
|
-
.admin-stat-box:nth-child(3)::before{background:var(--violet)}
|
|
212
|
-
.admin-stat-box:nth-child(4)::before{background:var(--cyan)}
|
|
213
|
-
.admin-stat-box:nth-child(5)::before{background:var(--pri)}
|
|
214
|
-
.admin-stat-box:nth-child(6)::before{background:var(--rose)}
|
|
215
|
-
.admin-stat-box .as-icon{font-size:16px;margin-bottom:4px;display:block}
|
|
216
|
-
.admin-stat-box .val{font-size:22px;font-weight:800;color:var(--text);font-variant-numeric:tabular-nums}
|
|
217
|
-
.admin-stat-box .lbl{font-size:10px;color:var(--text-muted);margin-top:3px;letter-spacing:.03em}
|
|
218
|
-
.admin-tabs{display:flex;gap:4px;padding:4px;background:var(--bg);border:1px solid var(--border);border-radius:14px;overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:20px}
|
|
219
|
-
.admin-tab{position:relative;display:flex;align-items:center;gap:6px;padding:9px 16px;border:none;background:transparent;color:var(--text-muted);font-size:13px;font-weight:500;cursor:pointer;border-radius:10px;transition:all .2s;white-space:nowrap;font-family:inherit}
|
|
220
|
-
.admin-tab:hover{background:rgba(99,102,241,.06);color:var(--text)}
|
|
221
|
-
.admin-tab.active{background:var(--bg-card);color:var(--text);font-weight:600;box-shadow:0 2px 8px rgba(0,0,0,.06),0 0 0 1px rgba(99,102,241,.1)}
|
|
222
|
-
.admin-tab .at-icon{font-size:14px;line-height:1}
|
|
223
|
-
.admin-tab .at-count{font-size:10px;font-weight:700;padding:1px 6px;border-radius:8px;background:rgba(99,102,241,.1);color:var(--pri);min-width:18px;text-align:center}
|
|
224
|
-
.admin-tab.active .at-count{background:rgba(99,102,241,.15)}
|
|
225
|
-
.admin-panel{display:none}
|
|
226
|
-
.admin-panel.active{display:block}
|
|
227
|
-
.admin-card{border:1px solid var(--border);border-radius:12px;padding:14px 16px;background:var(--bg-card);margin-bottom:10px;transition:all .2s;position:relative;overflow:hidden}
|
|
228
|
-
.admin-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--pri);opacity:.5}
|
|
229
|
-
.admin-card:hover{border-color:rgba(99,102,241,.25);box-shadow:0 2px 12px rgba(0,0,0,.04);transform:translateY(-1px)}
|
|
230
|
-
.admin-card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}
|
|
231
|
-
.admin-card-title{font-size:14px;font-weight:700;color:var(--text)}
|
|
232
|
-
.admin-card-meta{font-size:12px;color:var(--text-muted);line-height:1.5}
|
|
233
|
-
.admin-card-actions{display:flex;gap:8px;margin-top:10px}
|
|
234
|
-
.admin-badge{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:700;padding:3px 10px;border-radius:999px;letter-spacing:.02em}
|
|
235
|
-
.admin-badge.admin{background:rgba(52,199,89,.15);color:#34c759}
|
|
236
|
-
.admin-badge.member{background:rgba(142,142,147,.12);color:var(--text-muted)}
|
|
237
|
-
.admin-badge.pending{background:rgba(255,159,10,.15);color:#ff9f0a}
|
|
238
|
-
.admin-badge.public{background:rgba(99,102,241,.1);color:var(--pri)}
|
|
239
|
-
.admin-badge.group{background:rgba(139,92,246,.1);color:var(--violet)}
|
|
240
|
-
.admin-empty{font-size:13px;color:var(--text-muted);padding:40px 20px;text-align:center;border:1px dashed var(--border);border-radius:12px;background:var(--bg)}
|
|
241
|
-
.admin-empty .ae-icon{font-size:28px;display:block;margin-bottom:8px;opacity:.5}
|
|
242
|
-
[data-theme="light"] .admin-badge.admin{background:rgba(5,150,105,.1);color:#059669}
|
|
243
|
-
[data-theme="light"] .admin-badge.member{background:rgba(0,0,0,.06);color:#6b7280}
|
|
244
|
-
[data-theme="light"] .admin-badge.pending{background:rgba(245,158,11,.1);color:#d97706}
|
|
245
|
-
[data-theme="light"] .admin-header{background:linear-gradient(135deg,rgba(99,102,241,.05) 0%,rgba(139,92,246,.04) 50%,rgba(6,182,212,.03) 100%)}
|
|
246
|
-
.task-detail-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
247
|
-
.shared-memory-overlay,.shared-memory-overlay.show{display:none}
|
|
248
|
-
.shared-memory-overlay.show{display:flex;position:fixed;inset:0;align-items:center;justify-content:center;background:rgba(0,0,0,.55);z-index:1200;padding:24px}
|
|
249
|
-
.shared-memory-panel{width:min(860px,95vw);max-height:85vh;overflow:auto;border:1px solid var(--border);border-radius:18px;background:var(--bg-card);box-shadow:var(--shadow-lg);padding:20px}
|
|
250
|
-
.shared-memory-panel h3{font-size:18px;color:var(--text);margin-bottom:10px}
|
|
251
|
-
.shared-memory-panel .content{font-size:13px;color:var(--text-sec);line-height:1.7;white-space:pre-wrap;background:var(--bg);border:1px solid var(--border);border-radius:12px;padding:14px;margin-top:12px}
|
|
252
|
-
.hub-source-badge{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;border-radius:999px;background:rgba(34,197,94,.12);color:var(--green);font-size:11px;font-weight:700;border:1px solid rgba(34,197,94,.22)}
|
|
253
|
-
@media (max-width: 960px){.sharing-settings-grid{grid-template-columns:1fr}.search-bar{flex-wrap:wrap}.scope-select{width:100%}.task-detail-actions{width:100%;justify-content:flex-start}}
|
|
254
151
|
|
|
255
152
|
.filter-bar{display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap}
|
|
256
153
|
.filter-chip{padding:5px 14px;border:1px solid var(--border);border-radius:6px;background:transparent;color:var(--text-sec);font-size:12px;font-weight:500;transition:all .15s}
|
|
@@ -297,67 +194,20 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
297
194
|
.memory-card.dedup-inactive{opacity:.55;border-style:dashed}
|
|
298
195
|
.memory-card.dedup-inactive:hover{opacity:.85}
|
|
299
196
|
.dedup-target-link{font-size:11px;color:var(--pri);cursor:pointer;text-decoration:underline;margin-left:4px}
|
|
300
|
-
.memory-modal-overlay{position:fixed;inset:0;background:rgba(
|
|
197
|
+
.memory-modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:9999;display:none;align-items:center;justify-content:center;backdrop-filter:blur(4px)}
|
|
301
198
|
.memory-modal-overlay.show{display:flex}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
.memory-
|
|
307
|
-
|
|
308
|
-
.
|
|
309
|
-
|
|
310
|
-
.
|
|
311
|
-
.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
.memory-modal-title .mm-close{width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:10px;border:1px solid rgba(255,255,255,.06);background:rgba(255,255,255,.04);color:var(--text-sec);cursor:pointer;font-size:16px;transition:all .2s}
|
|
315
|
-
.memory-modal-title .mm-close:hover{background:rgba(255,77,77,.12);border-color:rgba(255,77,77,.2);color:#f87171;transform:rotate(90deg)}
|
|
316
|
-
[data-theme="light"] .memory-modal-title .mm-close{border-color:rgba(0,0,0,.06);background:rgba(0,0,0,.03)}
|
|
317
|
-
[data-theme="light"] .memory-modal-title .mm-close:hover{background:rgba(255,77,77,.08);border-color:rgba(255,77,77,.15)}
|
|
318
|
-
.memory-modal-body{position:relative;z-index:2;padding:0;overflow-y:auto;flex:1}
|
|
319
|
-
.mm-hero{padding:0 24px 20px}
|
|
320
|
-
.mm-hero-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:14px}
|
|
321
|
-
.mm-role-chip{display:inline-flex;align-items:center;gap:5px;font-size:10px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;padding:4px 12px;border-radius:20px;background:linear-gradient(135deg,rgba(99,102,241,.15),rgba(139,92,246,.1));color:#a5b4fc;border:1px solid rgba(99,102,241,.2)}
|
|
322
|
-
.mm-role-chip.user{background:linear-gradient(135deg,rgba(16,185,129,.15),rgba(52,211,153,.1));color:#6ee7b7;border-color:rgba(16,185,129,.2)}
|
|
323
|
-
.mm-role-chip.assistant{background:linear-gradient(135deg,rgba(99,102,241,.15),rgba(139,92,246,.1));color:#a5b4fc;border-color:rgba(99,102,241,.2)}
|
|
324
|
-
.mm-role-chip.system{background:linear-gradient(135deg,rgba(251,191,36,.15),rgba(245,158,11,.1));color:#fcd34d;border-color:rgba(251,191,36,.2)}
|
|
325
|
-
[data-theme="light"] .mm-role-chip{color:#6366f1}
|
|
326
|
-
[data-theme="light"] .mm-role-chip.user{color:#059669}
|
|
327
|
-
[data-theme="light"] .mm-role-chip.assistant{color:#6366f1}
|
|
328
|
-
[data-theme="light"] .mm-role-chip.system{color:#d97706}
|
|
329
|
-
.mm-dedup-chip{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:600;padding:3px 10px;border-radius:20px;text-transform:uppercase;letter-spacing:.04em}
|
|
330
|
-
.mm-dedup-chip.duplicate{background:rgba(239,68,68,.12);color:#fca5a5;border:1px solid rgba(239,68,68,.2)}
|
|
331
|
-
.mm-dedup-chip.merged{background:rgba(251,191,36,.12);color:#fcd34d;border:1px solid rgba(251,191,36,.2)}
|
|
332
|
-
[data-theme="light"] .mm-dedup-chip.duplicate{color:#dc2626}
|
|
333
|
-
[data-theme="light"] .mm-dedup-chip.merged{color:#d97706}
|
|
334
|
-
.mm-id{font-family:'SF Mono',Consolas,'Courier New',monospace;font-size:10px;color:var(--text-muted);background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.06);padding:3px 10px;border-radius:20px;cursor:pointer;transition:all .2s;display:inline-flex;align-items:center;gap:4px}
|
|
335
|
-
.mm-id::before{content:'\u{1F517}';font-size:9px}
|
|
336
|
-
.mm-id:hover{background:rgba(99,102,241,.12);border-color:rgba(99,102,241,.25);color:var(--text)}
|
|
337
|
-
[data-theme="light"] .mm-id{background:rgba(0,0,0,.03);border-color:rgba(0,0,0,.06)}
|
|
338
|
-
[data-theme="light"] .mm-id:hover{background:rgba(99,102,241,.08);border-color:rgba(99,102,241,.15)}
|
|
339
|
-
.mm-summary{font-size:15px;font-weight:600;color:var(--text);line-height:1.6;letter-spacing:-.01em;padding:16px 20px;background:rgba(255,255,255,.02);border-radius:12px;border:1px solid rgba(255,255,255,.04);position:relative}
|
|
340
|
-
.mm-summary::before{content:'';position:absolute;left:0;top:12px;bottom:12px;width:3px;border-radius:2px;background:linear-gradient(180deg,#6366f1,#8b5cf6)}
|
|
341
|
-
[data-theme="light"] .mm-summary{background:rgba(99,102,241,.02);border-color:rgba(99,102,241,.06)}
|
|
342
|
-
.mm-section{padding:0 24px 16px}
|
|
343
|
-
.mm-section-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);margin-bottom:8px;display:flex;align-items:center;gap:6px}
|
|
344
|
-
.mm-section-label::before{content:'';width:6px;height:6px;border-radius:50%;background:linear-gradient(135deg,#6366f1,#8b5cf6);flex-shrink:0}
|
|
345
|
-
.mm-content{font-family:'SF Mono',Consolas,'Courier New',monospace;font-size:12px;line-height:1.75;color:var(--text);white-space:pre-wrap;word-break:break-all;background:rgba(0,0,0,.3);border-radius:12px;padding:16px 18px;max-height:240px;overflow-y:auto;margin:0;border:1px solid rgba(255,255,255,.04);position:relative}
|
|
346
|
-
[data-theme="light"] .mm-content{background:rgba(0,0,0,.03);border-color:rgba(0,0,0,.06)}
|
|
347
|
-
.mm-meta{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:8px;padding:16px 24px;border-top:1px solid rgba(255,255,255,.04);background:rgba(0,0,0,.1)}
|
|
348
|
-
[data-theme="light"] .mm-meta{border-top-color:rgba(0,0,0,.04);background:rgba(0,0,0,.015)}
|
|
349
|
-
.mm-meta-chip{display:flex;flex-direction:column;gap:3px;font-size:11px;color:var(--text-sec);background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.04);padding:10px 12px;border-radius:10px;transition:all .2s}
|
|
350
|
-
.mm-meta-chip:hover{background:rgba(255,255,255,.06);border-color:rgba(99,102,241,.15)}
|
|
351
|
-
[data-theme="light"] .mm-meta-chip{background:rgba(0,0,0,.02);border-color:rgba(0,0,0,.04)}
|
|
352
|
-
[data-theme="light"] .mm-meta-chip:hover{background:rgba(99,102,241,.04);border-color:rgba(99,102,241,.1)}
|
|
353
|
-
.mm-meta-chip strong{color:var(--text-muted);font-weight:600;font-size:9px;text-transform:uppercase;letter-spacing:.06em}
|
|
354
|
-
.mm-meta-chip span{color:var(--text);font-weight:500;font-size:12px;word-break:break-all}
|
|
355
|
-
.mm-dedup{padding:0 24px 16px}
|
|
356
|
-
.mm-dedup-box{background:linear-gradient(135deg,rgba(251,191,36,.06),rgba(245,158,11,.03));border:1px solid rgba(251,191,36,.12);border-radius:12px;padding:14px 16px;font-size:12px;color:var(--text-sec);line-height:1.6;display:flex;align-items:flex-start;gap:8px}
|
|
357
|
-
.mm-dedup-box::before{content:'\u26A0\uFE0F';flex-shrink:0;font-size:14px}
|
|
358
|
-
.mm-footer{padding:12px 24px 16px;display:flex;align-items:center;justify-content:center}
|
|
359
|
-
.mm-footer .dedup-target-link{font-size:11px;color:#818cf8;cursor:pointer;padding:6px 16px;border-radius:8px;border:1px solid rgba(99,102,241,.2);background:rgba(99,102,241,.06);transition:all .2s;font-weight:500}
|
|
360
|
-
.mm-footer .dedup-target-link:hover{background:rgba(99,102,241,.12);border-color:rgba(99,102,241,.3)}
|
|
199
|
+
.memory-modal{background:var(--bg-card);border:1px solid var(--border);border-radius:16px;width:min(600px,90vw);max-height:80vh;display:flex;flex-direction:column;box-shadow:0 20px 60px rgba(0,0,0,.4);animation:modalIn .2s ease-out}
|
|
200
|
+
@keyframes modalIn{from{opacity:0;transform:scale(.95) translateY(10px)}to{opacity:1;transform:scale(1) translateY(0)}}
|
|
201
|
+
.memory-modal-title{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid var(--border);font-size:14px;font-weight:700}
|
|
202
|
+
.memory-modal-body{padding:20px;overflow-y:auto;flex:1}
|
|
203
|
+
.modal-memory-card{display:flex;flex-direction:column;gap:14px}
|
|
204
|
+
.modal-header-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
205
|
+
.modal-field{display:flex;flex-direction:column;gap:4px}
|
|
206
|
+
.modal-field-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:1px;color:var(--text-sec)}
|
|
207
|
+
.modal-field-val{font-size:13px;color:var(--text);line-height:1.5}
|
|
208
|
+
.modal-field-content{font-family:'SF Mono',Consolas,monospace;font-size:12px;line-height:1.6;color:var(--text);white-space:pre-wrap;word-break:break-all;background:rgba(0,0,0,.15);border-radius:8px;padding:12px;max-height:240px;overflow-y:auto;margin:0}
|
|
209
|
+
[data-theme="light"] .modal-field-content{background:rgba(0,0,0,.04)}
|
|
210
|
+
.modal-meta-row{display:flex;flex-wrap:wrap;gap:12px;font-size:11px;color:var(--text-sec);padding:8px 0;border-top:1px dashed var(--border)}
|
|
361
211
|
[data-theme="light"] .merge-history{background:rgba(0,0,0,.04)}
|
|
362
212
|
[data-theme="light"] .merge-history-item{border-bottom-color:rgba(0,0,0,.06)}
|
|
363
213
|
.card-merged-info{margin-top:8px;padding:8px 12px;background:rgba(16,185,129,.06);border:1px dashed rgba(16,185,129,.2);border-radius:8px;font-size:12px;line-height:1.6;color:var(--text-sec)}
|
|
@@ -395,7 +245,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
395
245
|
.form-group textarea{min-height:100px;resize:vertical}
|
|
396
246
|
.modal-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:28px}
|
|
397
247
|
|
|
398
|
-
|
|
399
248
|
/* ─── Toast ─── */
|
|
400
249
|
.emb-banner{display:flex;align-items:center;gap:10px;padding:12px 20px;font-size:13px;font-weight:500;border-radius:10px;margin:0 32px 0;animation:slideIn .3s ease}
|
|
401
250
|
.emb-banner.warning{background:rgba(245,158,11,.1);color:#d97706;border:1px solid rgba(245,158,11,.25)}
|
|
@@ -589,9 +438,9 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
589
438
|
.nav-tabs .tab.active{color:var(--text);background:rgba(255,255,255,.1);border-color:var(--border);box-shadow:0 1px 4px rgba(0,0,0,.15)}
|
|
590
439
|
[data-theme="light"] .nav-tabs{background:rgba(0,0,0,.05)}
|
|
591
440
|
[data-theme="light"] .nav-tabs .tab.active{background:#fff;border-color:rgba(0,0,0,.1);box-shadow:0 1px 3px rgba(0,0,0,.08);color:var(--text)}
|
|
592
|
-
.analytics-view,.settings-view,.logs-view,.migrate-view
|
|
593
|
-
.analytics-view.show,.settings-view.show,.logs-view.show,.migrate-view.show
|
|
594
|
-
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.settings-view,.logs-view,.migrate-view
|
|
441
|
+
.analytics-view,.settings-view,.logs-view,.migrate-view{display:none;flex:1;min-width:0;flex-direction:column;gap:20px}
|
|
442
|
+
.analytics-view.show,.settings-view.show,.logs-view.show,.migrate-view.show{display:flex}
|
|
443
|
+
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.settings-view,.logs-view,.migrate-view{max-width:960px}
|
|
595
444
|
|
|
596
445
|
/* ─── Logs ─── */
|
|
597
446
|
.logs-toolbar{display:flex;align-items:center;justify-content:space-between;padding:8px 0}
|
|
@@ -709,66 +558,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
709
558
|
.settings-section{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:24px 28px}
|
|
710
559
|
.settings-section h3{font-size:13px;font-weight:700;color:var(--text);margin-bottom:16px;display:flex;align-items:center;gap:8px}
|
|
711
560
|
.settings-section h3 .icon{font-size:16px;opacity:.8}
|
|
712
|
-
.settings-tabs-bar{display:flex;gap:4px;margin-bottom:24px;padding:4px;background:var(--bg);border:1px solid var(--border);border-radius:14px;overflow-x:auto;-webkit-overflow-scrolling:touch}
|
|
713
|
-
.settings-tab-btn{position:relative;display:flex;align-items:center;gap:7px;padding:10px 16px;border:none;background:transparent;color:var(--text-muted);font-size:13px;font-weight:500;cursor:pointer;border-radius:10px;transition:all .25s ease;white-space:nowrap;font-family:inherit}
|
|
714
|
-
.settings-tab-btn:hover{background:rgba(99,102,241,.06);color:var(--text)}
|
|
715
|
-
.settings-tab-btn.active{background:var(--bg-card);color:var(--text);font-weight:600;box-shadow:0 2px 8px rgba(0,0,0,.06),0 0 0 1px rgba(99,102,241,.1)}
|
|
716
|
-
.settings-tab-btn .stab-icon{font-size:15px;line-height:1}
|
|
717
|
-
.settings-tab-btn .stab-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}
|
|
718
|
-
.settings-tab-btn[data-tab="models"] .stab-dot{background:#6366f1}
|
|
719
|
-
.settings-tab-btn[data-tab="hub"] .stab-dot{background:#06b6d4}
|
|
720
|
-
.settings-tab-btn[data-tab="general"] .stab-dot{background:#10b981}
|
|
721
|
-
.settings-tab-btn.active .stab-dot{box-shadow:0 0 6px currentColor}
|
|
722
|
-
[data-theme="light"] .settings-tab-btn.active{box-shadow:0 2px 8px rgba(0,0,0,.05),0 0 0 1px rgba(99,102,241,.08)}
|
|
723
|
-
.settings-cards-grid{display:flex;flex-direction:column;gap:24px}
|
|
724
|
-
.settings-card[data-stab]{display:none}
|
|
725
|
-
.settings-card[data-stab].stab-active{display:block}
|
|
726
|
-
.settings-card{position:relative;background:var(--bg-card);border:1px solid var(--border);border-radius:16px;overflow:hidden;transition:border-color .3s,box-shadow .3s}
|
|
727
|
-
.settings-card::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;opacity:.5;transition:opacity .3s}
|
|
728
|
-
.settings-card:hover{border-color:rgba(99,102,241,.25);box-shadow:0 0 24px rgba(99,102,241,.06),0 8px 32px rgba(0,0,0,.1)}
|
|
729
|
-
.settings-card:hover::before{opacity:1}
|
|
730
|
-
.settings-card.card-models::before{background:linear-gradient(90deg,#6366f1,#8b5cf6,#f59e0b)}
|
|
731
|
-
.settings-card.card-hub::before{background:linear-gradient(90deg,#06b6d4,#22d3ee,#67e8f9)}
|
|
732
|
-
.settings-card.card-general::before{background:linear-gradient(90deg,#10b981,#34d399,#6ee7b7)}
|
|
733
|
-
.settings-card-header{display:flex;align-items:center;gap:14px;padding:22px 28px 0}
|
|
734
|
-
.settings-card-icon{width:44px;height:44px;display:flex;align-items:center;justify-content:center;border-radius:12px;font-size:22px;flex-shrink:0;border:1px solid transparent}
|
|
735
|
-
.settings-card-title-wrap{flex:1;min-width:0}
|
|
736
|
-
.settings-card-title{font-size:16px;font-weight:700;color:var(--text);letter-spacing:.01em}
|
|
737
|
-
.settings-card-desc{font-size:11px;color:var(--text-muted);margin-top:3px;font-weight:400;line-height:1.4}
|
|
738
|
-
.settings-card-body{padding:18px 28px 24px}
|
|
739
|
-
.settings-card-divider{height:1px;background:var(--border);margin:18px 0;opacity:.6}
|
|
740
|
-
.settings-card-subtitle{font-size:12px;font-weight:700;color:var(--text-sec);margin-bottom:10px;letter-spacing:.01em}
|
|
741
|
-
.hub-info-card{border:1px solid var(--border);border-radius:12px;padding:14px 16px;background:var(--bg);position:relative;overflow:hidden;margin-bottom:12px}
|
|
742
|
-
.hub-info-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px}
|
|
743
|
-
.hub-info-card.hic-share{border-color:rgba(99,102,241,.2);background:linear-gradient(135deg,rgba(99,102,241,.04),rgba(139,92,246,.03))}
|
|
744
|
-
.hub-info-card.hic-share::before{background:linear-gradient(180deg,var(--pri),var(--violet))}
|
|
745
|
-
.hub-info-card.hic-status::before{background:var(--green)}
|
|
746
|
-
.hub-info-card.hic-team::before{background:var(--violet)}
|
|
747
|
-
.hub-info-card.hic-pending::before{background:var(--amber)}
|
|
748
|
-
.hub-info-card .hic-title{display:flex;align-items:center;gap:8px;font-size:12px;font-weight:700;color:var(--text);margin-bottom:10px}
|
|
749
|
-
.hub-info-card .hic-title .hic-icon{font-size:14px}
|
|
750
|
-
.hub-info-card .hic-grid{display:grid;grid-template-columns:auto 1fr;gap:4px 12px;font-size:12px;align-items:baseline}
|
|
751
|
-
.hub-info-card .hic-grid .hic-label{color:var(--text-muted);white-space:nowrap}
|
|
752
|
-
.hub-info-card .hic-grid .hic-value{color:var(--text);font-weight:500;word-break:break-all}
|
|
753
|
-
.hub-info-card .hic-grid .hic-value.mono{font-family:monospace;font-size:11px;cursor:pointer;user-select:all}
|
|
754
|
-
.hub-info-card .hic-grid .hic-value.mono:hover{color:var(--pri)}
|
|
755
|
-
.hub-info-card .hic-badge{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:600;padding:2px 8px;border-radius:9999px}
|
|
756
|
-
.hub-info-card .hic-badge.connected{background:rgba(52,211,153,.12);color:#34d399}
|
|
757
|
-
.hub-info-card .hic-badge.disconnected{background:rgba(239,68,68,.1);color:#ef4444}
|
|
758
|
-
.hub-info-card .hic-badge.admin{background:rgba(52,199,89,.12);color:#34c759}
|
|
759
|
-
.hub-info-card .hic-badge.pending{background:rgba(251,191,36,.12);color:#fbbf24}
|
|
760
|
-
.hub-info-card .hic-dot{width:6px;height:6px;border-radius:50%;display:inline-block}
|
|
761
|
-
.hub-info-card .hic-dot.green{background:#34d399;box-shadow:0 0 6px #34d399}
|
|
762
|
-
.hub-info-card .hic-dot.red{background:#ef4444}
|
|
763
|
-
.hub-info-card .hic-dot.amber{background:#fbbf24;box-shadow:0 0 4px #fbbf24}
|
|
764
|
-
.hub-info-card .hic-empty{font-size:12px;color:var(--text-muted);text-align:center;padding:12px 0}
|
|
765
|
-
.hub-info-card .hic-actions{display:flex;gap:8px;margin-top:10px}
|
|
766
|
-
[data-theme="light"] .hub-info-card.hic-share{background:linear-gradient(135deg,rgba(99,102,241,.03),rgba(139,92,246,.02))}
|
|
767
|
-
.settings-card .settings-section{background:none;border:none;padding:0;border-radius:0;margin-bottom:16px}
|
|
768
|
-
.settings-card .settings-section:last-child{margin-bottom:0}
|
|
769
|
-
.settings-card .settings-section h3{margin-bottom:12px}
|
|
770
|
-
[data-theme="light"] .settings-card{box-shadow:0 1px 3px rgba(0,0,0,.04)}
|
|
771
|
-
[data-theme="light"] .settings-card:hover{box-shadow:0 0 24px rgba(79,70,229,.05),0 8px 32px rgba(0,0,0,.06)}
|
|
772
561
|
.settings-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
|
|
773
562
|
@media(max-width:800px){.settings-grid{grid-template-columns:1fr}}
|
|
774
563
|
.settings-field{display:flex;flex-direction:column;gap:4px}
|
|
@@ -776,8 +565,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
776
565
|
.settings-field input,.settings-field select{background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:8px 12px;color:var(--text);font-size:13px;font-family:inherit;transition:border-color .15s}
|
|
777
566
|
.settings-field input:focus,.settings-field select:focus{outline:none;border-color:var(--pri)}
|
|
778
567
|
.settings-field input[type="password"]{font-family:'Courier New',monospace;letter-spacing:.05em}
|
|
779
|
-
.field-hint{font-size:10px;color:var(--text-muted);
|
|
780
|
-
.settings-field .field-hint{margin-top:2px}
|
|
568
|
+
.settings-field .field-hint{font-size:10px;color:var(--text-muted);margin-top:2px}
|
|
781
569
|
.settings-field.full-width{grid-column:1/-1}
|
|
782
570
|
.settings-toggle{display:flex;align-items:center;gap:10px;padding:4px 0}
|
|
783
571
|
.settings-toggle label{font-size:12px;font-weight:500;color:var(--text-sec);text-transform:none;letter-spacing:0}
|
|
@@ -793,36 +581,14 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
793
581
|
.test-result.ok{color:#22c55e}
|
|
794
582
|
.test-result.fail{color:var(--rose)}
|
|
795
583
|
.test-result.loading{color:var(--text-muted)}
|
|
796
|
-
.settings-actions{display:flex;gap:12px;justify-content:flex-end;align-items:center;margin-top:
|
|
797
|
-
.settings-actions .btn{
|
|
584
|
+
.settings-actions{display:flex;gap:12px;justify-content:flex-end;align-items:center;margin-top:16px;padding-top:16px;border-top:1px solid var(--border)}
|
|
585
|
+
.settings-actions .btn{min-width:110px;padding:10px 20px;font-size:13px}
|
|
798
586
|
.settings-actions .btn-primary{background:rgba(99,102,241,.08);color:var(--pri);border:1px solid rgba(99,102,241,.25);font-weight:600}
|
|
799
587
|
.settings-actions .btn-primary:hover{background:rgba(99,102,241,.14);border-color:var(--pri)}
|
|
800
588
|
[data-theme="light"] .settings-actions .btn-primary{background:rgba(79,70,229,.06);color:#4f46e5;border:1px solid rgba(79,70,229,.2)}
|
|
801
589
|
[data-theme="light"] .settings-actions .btn-primary:hover{background:rgba(79,70,229,.1);border-color:#4f46e5}
|
|
802
590
|
.settings-saved{display:inline-flex;align-items:center;gap:6px;color:var(--green);font-size:12px;font-weight:600;opacity:0;transition:opacity .3s}
|
|
803
591
|
.settings-saved.show{opacity:1}
|
|
804
|
-
.team-guide{margin-bottom:20px;border:1px solid rgba(6,182,212,.2);border-radius:12px;background:linear-gradient(135deg,rgba(6,182,212,.04),rgba(99,102,241,.03));position:relative;overflow:hidden;padding:20px 22px 18px;display:none}
|
|
805
|
-
.team-guide::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,#06b6d4,#6366f1,#8b5cf6);opacity:.6}
|
|
806
|
-
.team-guide-title{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:700;color:var(--text);margin-bottom:4px}
|
|
807
|
-
.team-guide-subtitle{font-size:11.5px;color:var(--text-muted);line-height:1.6;margin-bottom:16px}
|
|
808
|
-
.team-guide-options{display:grid;grid-template-columns:1fr 1fr;gap:14px}
|
|
809
|
-
@media(max-width:800px){.team-guide-options{grid-template-columns:1fr}}
|
|
810
|
-
.team-guide-opt{border:1px solid var(--border);border-radius:10px;padding:16px;background:var(--bg-card);transition:border-color .2s,box-shadow .2s;cursor:default}
|
|
811
|
-
.team-guide-opt:hover{border-color:rgba(99,102,241,.3);box-shadow:0 4px 16px rgba(0,0,0,.06)}
|
|
812
|
-
.team-guide-opt-header{display:flex;align-items:center;gap:10px;margin-bottom:8px}
|
|
813
|
-
.team-guide-opt-icon{width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:8px;font-size:16px;flex-shrink:0}
|
|
814
|
-
.team-guide-opt-title{font-size:13px;font-weight:700;color:var(--text)}
|
|
815
|
-
.team-guide-opt-desc{font-size:11px;color:var(--text-sec);line-height:1.7;margin-bottom:12px}
|
|
816
|
-
.team-guide-steps{padding:0 0 0 20px;margin:0 0 12px;counter-reset:none}
|
|
817
|
-
.team-guide-steps li{font-size:11px;color:var(--text-muted);line-height:1.9}
|
|
818
|
-
.team-guide-steps li::marker{color:var(--pri);font-weight:700;font-size:11px}
|
|
819
|
-
.team-guide-opt .btn-guide{font-size:11px;padding:5px 14px;border-radius:6px;font-weight:600;border:1px solid rgba(99,102,241,.25);background:rgba(99,102,241,.08);color:var(--pri);cursor:pointer;transition:background .15s,border-color .15s}
|
|
820
|
-
.team-guide-opt .btn-guide:hover{background:rgba(99,102,241,.14);border-color:var(--pri)}
|
|
821
|
-
.team-guide-dismiss{position:absolute;top:10px;right:12px;background:none;border:none;color:var(--text-muted);font-size:15px;cursor:pointer;padding:4px;line-height:1;opacity:.5;transition:opacity .15s}
|
|
822
|
-
.team-guide-dismiss:hover{opacity:1}
|
|
823
|
-
[data-theme="light"] .team-guide{background:linear-gradient(135deg,rgba(6,182,212,.03),rgba(79,70,229,.02));border-color:rgba(6,182,212,.15)}
|
|
824
|
-
[data-theme="light"] .team-guide-opt{box-shadow:0 1px 3px rgba(0,0,0,.03)}
|
|
825
|
-
[data-theme="light"] .team-guide-opt:hover{box-shadow:0 4px 16px rgba(0,0,0,.04)}
|
|
826
592
|
.model-health-bar{margin-bottom:20px;border-radius:var(--radius-lg);overflow:visible}
|
|
827
593
|
.mh-table{width:100%;border-collapse:separate;border-spacing:0;font-size:12px}
|
|
828
594
|
.mh-table th{text-align:left;padding:6px 12px;font-size:10px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em;background:var(--bg);border-bottom:1px solid var(--border)}
|
|
@@ -882,20 +648,18 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
882
648
|
.analytics-section::before{display:none}
|
|
883
649
|
.analytics-section h3{font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.08em;margin-bottom:16px;display:flex;align-items:center;gap:8px}
|
|
884
650
|
.analytics-section h3 .icon{font-size:14px;opacity:.6}
|
|
885
|
-
.chart-bars{display:flex;align-items:flex-end;gap:
|
|
886
|
-
.chart-
|
|
887
|
-
.chart-bar-
|
|
888
|
-
.chart-bar-
|
|
889
|
-
.chart-bar-wrap:hover .chart-bar{opacity:1;filter:brightness(1.2);transform:scaleY(1.02);transform-origin:bottom}
|
|
651
|
+
.chart-bars{display:flex;align-items:flex-end;gap:4px;padding:8px 0;overflow-x:auto;justify-content:center}
|
|
652
|
+
.chart-bar-wrap{flex:1;min-width:28px;max-width:80px;display:flex;flex-direction:column;align-items:center;gap:4px;position:relative}
|
|
653
|
+
.chart-bar-col{width:100%;height:160px;display:flex;flex-direction:column;justify-content:flex-end;align-items:stretch}
|
|
654
|
+
.chart-bar-wrap:hover .chart-bar{opacity:1}
|
|
890
655
|
.chart-bar-wrap:hover .chart-bar-label{color:var(--text)}
|
|
891
656
|
.chart-bar-wrap:hover .chart-tip{opacity:1;transform:translateX(-50%) translateY(0)}
|
|
892
|
-
.chart-tip{position:absolute;top:-
|
|
893
|
-
|
|
894
|
-
.chart-bar{
|
|
895
|
-
.chart-bar.
|
|
896
|
-
.chart-bar.
|
|
897
|
-
.chart-bar
|
|
898
|
-
.chart-bar-label{font-size:8px;line-height:1;min-height:10px;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:40px;text-align:center;transition:color .15s;letter-spacing:0}
|
|
657
|
+
.chart-tip{position:absolute;top:-6px;left:50%;transform:translateX(-50%) translateY(4px);background:var(--bg-card);border:1px solid var(--border-glow);color:var(--text);padding:2px 8px;border-radius:6px;font-size:10px;font-weight:600;white-space:nowrap;z-index:5;pointer-events:none;box-shadow:var(--shadow);opacity:0;transition:all .15s ease}
|
|
658
|
+
.chart-bar{width:100%;border-radius:3px 3px 1px 1px;background:#818cf8;opacity:.75;transition:all .2s ease}
|
|
659
|
+
.chart-bar.violet{background:#6366f1}
|
|
660
|
+
.chart-bar.green{background:var(--green)}
|
|
661
|
+
.chart-bar.zero{background:var(--border);opacity:.3;border-radius:2px}
|
|
662
|
+
.chart-bar-label{font-size:9px;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;text-align:center;transition:color .15s}
|
|
899
663
|
.chart-legend{display:flex;gap:14px;margin-top:12px;flex-wrap:wrap;font-size:11px;color:var(--text-sec);font-weight:500}
|
|
900
664
|
.chart-legend span{display:inline-flex;align-items:center;gap:5px}
|
|
901
665
|
.chart-legend .dot{width:8px;height:8px;border-radius:2px}
|
|
@@ -949,7 +713,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
949
713
|
[data-theme="light"] .auth-theme-toggle .theme-icon-dark{display:none}
|
|
950
714
|
|
|
951
715
|
@media(max-width:1100px){.analytics-cards{grid-template-columns:repeat(3,1fr)}}
|
|
952
|
-
@media(max-width:900px){.main-content{flex-direction:column;padding:20px}.sidebar{width:100%}.sidebar .stats-grid{grid-template-columns:repeat(4,1fr)}.analytics-cards{grid-template-columns:repeat(2,1fr)}.topbar{padding:0 16px;gap:8px}.topbar .brand
|
|
716
|
+
@media(max-width:900px){.main-content{flex-direction:column;padding:20px}.sidebar{width:100%}.sidebar .stats-grid{grid-template-columns:repeat(4,1fr)}.analytics-cards{grid-template-columns:repeat(2,1fr)}.topbar{padding:0 16px;gap:8px}.topbar .brand span{display:none}.topbar-center{justify-content:flex-start}}
|
|
953
717
|
</style>
|
|
954
718
|
</head>
|
|
955
719
|
<body>
|
|
@@ -961,9 +725,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
961
725
|
<button class="auth-theme-toggle" onclick="toggleLang()" aria-label="Switch language"><span data-i18n="lang.switch">EN</span></button>
|
|
962
726
|
</div>
|
|
963
727
|
<div class="auth-card">
|
|
964
|
-
<div class="logo"
|
|
965
|
-
<svg width="56" height="56" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="aLG" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ff4d4d"/><stop offset="100%" stop-color="#991b1b"/></linearGradient></defs><path d="M60 10C30 10 15 35 15 55C15 75 30 95 45 100L45 110L55 110L55 100C55 100 60 102 65 100L65 110L75 110L75 100C90 95 105 75 105 55C105 35 90 10 60 10Z" fill="url(#aLG)"/><path d="M20 45C5 40 0 50 5 60C10 70 20 65 25 55C28 48 25 45 20 45Z" fill="url(#aLG)"/><path d="M100 45C115 40 120 50 115 60C110 70 100 65 95 55C92 48 95 45 100 45Z" fill="url(#aLG)"/><path d="M45 15Q35 5 30 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><path d="M75 15Q85 5 90 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><circle cx="45" cy="35" r="6" fill="#050810"/><circle cx="75" cy="35" r="6" fill="#050810"/><circle cx="46" cy="34" r="2" fill="#00e5cc"/><circle cx="76" cy="34" r="2" fill="#00e5cc"/></svg>
|
|
966
|
-
</div>
|
|
728
|
+
<div class="logo"><svg width="60" height="60" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="aLG" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ff4d4d"/><stop offset="100%" stop-color="#991b1b"/></linearGradient></defs><path d="M60 10C30 10 15 35 15 55C15 75 30 95 45 100L45 110L55 110L55 100C55 100 60 102 65 100L65 110L75 110L75 100C90 95 105 75 105 55C105 35 90 10 60 10Z" fill="url(#aLG)"/><path d="M20 45C5 40 0 50 5 60C10 70 20 65 25 55C28 48 25 45 20 45Z" fill="url(#aLG)"/><path d="M100 45C115 40 120 50 115 60C110 70 100 65 95 55C92 48 95 45 100 45Z" fill="url(#aLG)"/><path d="M45 15Q35 5 30 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><path d="M75 15Q85 5 90 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><circle cx="45" cy="35" r="6" fill="#050810"/><circle cx="75" cy="35" r="6" fill="#050810"/><circle cx="46" cy="34" r="2" fill="#00e5cc"/><circle cx="76" cy="34" r="2" fill="#00e5cc"/></svg></div>
|
|
967
729
|
<h1 data-i18n="title">OpenClaw Memory</h1>
|
|
968
730
|
<p style="font-size:12px;color:var(--text-sec);margin-bottom:6px" data-i18n="subtitle">Powered by MemOS</p>
|
|
969
731
|
<p data-i18n="setup.desc">Set a password to protect your memories</p>
|
|
@@ -981,9 +743,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
981
743
|
<button class="auth-theme-toggle" onclick="toggleLang()" aria-label="Switch language"><span data-i18n="lang.switch">EN</span></button>
|
|
982
744
|
</div>
|
|
983
745
|
<div class="auth-card">
|
|
984
|
-
<div class="logo"
|
|
985
|
-
<svg width="56" height="56" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="bLG" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ff4d4d"/><stop offset="100%" stop-color="#991b1b"/></linearGradient></defs><path d="M60 10C30 10 15 35 15 55C15 75 30 95 45 100L45 110L55 110L55 100C55 100 60 102 65 100L65 110L75 110L75 100C90 95 105 75 105 55C105 35 90 10 60 10Z" fill="url(#bLG)"/><path d="M20 45C5 40 0 50 5 60C10 70 20 65 25 55C28 48 25 45 20 45Z" fill="url(#bLG)"/><path d="M100 45C115 40 120 50 115 60C110 70 100 65 95 55C92 48 95 45 100 45Z" fill="url(#bLG)"/><path d="M45 15Q35 5 30 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><path d="M75 15Q85 5 90 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><circle cx="45" cy="35" r="6" fill="#050810"/><circle cx="75" cy="35" r="6" fill="#050810"/><circle cx="46" cy="34" r="2" fill="#00e5cc"/><circle cx="76" cy="34" r="2" fill="#00e5cc"/></svg>
|
|
986
|
-
</div>
|
|
746
|
+
<div class="logo"><svg width="60" height="60" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="bLG" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ff4d4d"/><stop offset="100%" stop-color="#991b1b"/></linearGradient></defs><path d="M60 10C30 10 15 35 15 55C15 75 30 95 45 100L45 110L55 110L55 100C55 100 60 102 65 100L65 110L75 110L75 100C90 95 105 75 105 55C105 35 90 10 60 10Z" fill="url(#bLG)"/><path d="M20 45C5 40 0 50 5 60C10 70 20 65 25 55C28 48 25 45 20 45Z" fill="url(#bLG)"/><path d="M100 45C115 40 120 50 115 60C110 70 100 65 95 55C92 48 95 45 100 45Z" fill="url(#bLG)"/><path d="M45 15Q35 5 30 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><path d="M75 15Q85 5 90 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><circle cx="45" cy="35" r="6" fill="#050810"/><circle cx="75" cy="35" r="6" fill="#050810"/><circle cx="46" cy="34" r="2" fill="#00e5cc"/><circle cx="76" cy="34" r="2" fill="#00e5cc"/></svg></div>
|
|
987
747
|
<h1 data-i18n="title">OpenClaw Memory</h1>
|
|
988
748
|
<p style="font-size:12px;color:var(--text-sec);margin-bottom:6px" data-i18n="subtitle">Powered by MemOS</p>
|
|
989
749
|
<p data-i18n="login.desc">Enter your password to access memories</p>
|
|
@@ -1035,8 +795,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1035
795
|
<div class="app" id="app">
|
|
1036
796
|
<div class="topbar">
|
|
1037
797
|
<div class="brand">
|
|
1038
|
-
<
|
|
1039
|
-
<
|
|
798
|
+
<div class="icon"><svg width="24" height="24" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg" style="filter:drop-shadow(0 0 8px rgba(255,77,77,.3))"><defs><linearGradient id="tLG" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ff4d4d"/><stop offset="100%" stop-color="#991b1b"/></linearGradient></defs><path d="M60 10C30 10 15 35 15 55C15 75 30 95 45 100L45 110L55 110L55 100C55 100 60 102 65 100L65 110L75 110L75 100C90 95 105 75 105 55C105 35 90 10 60 10Z" fill="url(#tLG)"/><path d="M20 45C5 40 0 50 5 60C10 70 20 65 25 55C28 48 25 45 20 45Z" fill="url(#tLG)"/><path d="M100 45C115 40 120 50 115 60C110 70 100 65 95 55C92 48 95 45 100 45Z" fill="url(#tLG)"/><path d="M45 15Q35 5 30 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><path d="M75 15Q85 5 90 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><circle cx="45" cy="35" r="6" fill="#050810"/><circle cx="75" cy="35" r="6" fill="#050810"/><circle cx="46" cy="34" r="2" fill="#00e5cc"/><circle cx="76" cy="34" r="2" fill="#00e5cc"/></svg></div>
|
|
799
|
+
<span data-i18n="title">OpenClaw Memory</span>${vBadge}
|
|
1040
800
|
</div>
|
|
1041
801
|
<div class="topbar-center">
|
|
1042
802
|
<nav class="nav-tabs">
|
|
@@ -1046,7 +806,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1046
806
|
<button class="tab" data-view="analytics" onclick="switchView('analytics')" data-i18n="tab.analytics">\u{1F4CA} Analytics</button>
|
|
1047
807
|
<button class="tab" data-view="logs" onclick="switchView('logs')" data-i18n="tab.logs">\u{1F4DD} Logs</button>
|
|
1048
808
|
<button class="tab" data-view="import" onclick="switchView('import')" data-i18n="tab.import">\u{1F4E5} Import</button>
|
|
1049
|
-
<button class="tab" data-view="admin" onclick="switchView('admin')" data-i18n="tab.admin">\u{1F6E1} Admin</button>
|
|
1050
809
|
<button class="tab" data-view="settings" onclick="switchView('settings')" data-i18n="tab.settings">\u2699 Settings</button>
|
|
1051
810
|
</nav>
|
|
1052
811
|
</div>
|
|
@@ -1066,16 +825,12 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1066
825
|
<div class="stat-card amber"><div class="stat-value" id="statEmbeddings">-</div><div class="stat-label" data-i18n="stat.embeddings">Embeddings</div></div>
|
|
1067
826
|
<div class="stat-card rose"><div class="stat-value" id="statTimeSpan">-</div><div class="stat-label" data-i18n="stat.days">Days</div></div>
|
|
1068
827
|
</div>
|
|
1069
|
-
<div id="
|
|
1070
|
-
<div
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
</div>
|
|
828
|
+
<div id="sidebarSessionSection">
|
|
829
|
+
<div id="embeddingStatus"></div>
|
|
830
|
+
<div class="section-title" data-i18n="sidebar.sessions">Sessions</div>
|
|
831
|
+
<div class="session-list" id="sessionList"></div>
|
|
832
|
+
<button class="btn btn-sm btn-ghost" style="width:100%;margin-top:20px;justify-content:center;color:var(--text-muted);font-size:11px" onclick="clearAll()" data-i18n="sidebar.clear">\u{1F5D1} Clear All Data</button>
|
|
1075
833
|
</div>
|
|
1076
|
-
<div id="embeddingStatus"></div>
|
|
1077
|
-
<div class="session-list" id="sessionList" style="display:none"></div>
|
|
1078
|
-
<button class="btn btn-sm btn-ghost" style="width:100%;margin-top:20px;justify-content:center;color:var(--text-muted);font-size:11px" onclick="clearAll()" data-i18n="sidebar.clear">\u{1F5D1} Clear All Data</button>
|
|
1079
834
|
</div>
|
|
1080
835
|
|
|
1081
836
|
<div class="feed-wrap" id="feedWrap">
|
|
@@ -1083,17 +838,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1083
838
|
<div class="search-bar">
|
|
1084
839
|
<span class="search-icon">\u{1F50D}</span>
|
|
1085
840
|
<input type="text" id="searchInput" data-i18n-ph="search.placeholder" placeholder="Search memories (supports semantic search)..." oninput="debounceSearch()">
|
|
1086
|
-
<select id="filterOwner" class="filter-select" onchange="onOwnerFilterChange()">
|
|
1087
|
-
<option value="" data-i18n="filter.allowners">All owners</option>
|
|
1088
|
-
<option value="public" data-i18n="filter.public">Public</option>
|
|
1089
|
-
</select>
|
|
1090
|
-
<select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()">
|
|
1091
|
-
<option value="local" data-i18n="scope.local">Local</option>
|
|
1092
|
-
<option value="all" data-i18n="scope.hub">Hub</option>
|
|
1093
|
-
</select>
|
|
1094
841
|
</div>
|
|
1095
842
|
<div class="search-meta" id="searchMeta"></div>
|
|
1096
|
-
<div class="search-meta" id="sharingSearchMeta"></div>
|
|
1097
843
|
<div class="filter-bar" id="filterBar">
|
|
1098
844
|
<button class="filter-chip active" data-role="" onclick="setRoleFilter(this,'')" data-i18n="filter.all">All</button>
|
|
1099
845
|
<button class="filter-chip" data-role="user" onclick="setRoleFilter(this,'user')">User</button>
|
|
@@ -1105,8 +851,9 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1105
851
|
<option value="oldest" data-i18n="filter.oldest">Oldest first</option>
|
|
1106
852
|
</select>
|
|
1107
853
|
<span class="filter-sep"></span>
|
|
1108
|
-
<select id="
|
|
1109
|
-
<option value="" data-i18n="filter.
|
|
854
|
+
<select id="filterOwner" class="filter-select" onchange="applyFilters()">
|
|
855
|
+
<option value="" data-i18n="filter.allowners">All owners</option>
|
|
856
|
+
<option value="public" data-i18n="filter.public">Public</option>
|
|
1110
857
|
</select>
|
|
1111
858
|
</div>
|
|
1112
859
|
<div class="date-filter">
|
|
@@ -1131,10 +878,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1131
878
|
<button class="filter-chip" data-task-status="active" onclick="setTaskStatusFilter(this,'active')" data-i18n="tasks.status.active">Active</button>
|
|
1132
879
|
<button class="filter-chip" data-task-status="completed" onclick="setTaskStatusFilter(this,'completed')" data-i18n="tasks.status.completed">Completed</button>
|
|
1133
880
|
<button class="filter-chip" data-task-status="skipped" onclick="setTaskStatusFilter(this,'skipped')" data-i18n="tasks.status.skipped">Skipped</button>
|
|
1134
|
-
<select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()">
|
|
1135
|
-
<option value="local" data-i18n="scope.local">Local</option>
|
|
1136
|
-
<option value="all" data-i18n="scope.hub">Hub</option>
|
|
1137
|
-
</select>
|
|
1138
881
|
<button class="btn btn-sm btn-ghost" onclick="loadTasks()" style="margin-left:auto" data-i18n="refresh">\u21BB Refresh</button>
|
|
1139
882
|
</div>
|
|
1140
883
|
</div>
|
|
@@ -1144,10 +887,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1144
887
|
<div class="task-detail-panel" onclick="event.stopPropagation()">
|
|
1145
888
|
<div class="task-detail-header">
|
|
1146
889
|
<h2 id="taskDetailTitle"></h2>
|
|
1147
|
-
<
|
|
1148
|
-
<div id="taskShareActions" style="display:flex;gap:8px;align-items:center"></div>
|
|
1149
|
-
<button class="btn btn-icon" onclick="closeTaskDetail()" title="Close">\u2715</button>
|
|
1150
|
-
</div>
|
|
890
|
+
<button class="btn btn-icon" onclick="closeTaskDetail()" title="Close">\u2715</button>
|
|
1151
891
|
</div>
|
|
1152
892
|
<div class="task-detail-meta" id="taskDetailMeta"></div>
|
|
1153
893
|
<div class="task-skill-section" id="taskSkillSection"></div>
|
|
@@ -1158,27 +898,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1158
898
|
</div>
|
|
1159
899
|
</div>
|
|
1160
900
|
</div>
|
|
1161
|
-
<div class="shared-memory-overlay" id="sharedMemoryOverlay" onclick="closeSharedMemoryDetail(event)">
|
|
1162
|
-
<div class="shared-memory-panel" onclick="event.stopPropagation()">
|
|
1163
|
-
<div class="task-detail-header">
|
|
1164
|
-
<h3 id="sharedMemoryTitle">Shared Memory</h3>
|
|
1165
|
-
<button class="btn btn-icon" onclick="closeSharedMemoryDetail()" title="Close">✕</button>
|
|
1166
|
-
</div>
|
|
1167
|
-
<div class="task-detail-meta" id="sharedMemoryMeta"></div>
|
|
1168
|
-
<div class="task-detail-summary" id="sharedMemorySummary"></div>
|
|
1169
|
-
<div class="content" id="sharedMemoryContent"></div>
|
|
1170
|
-
</div>
|
|
1171
|
-
</div>
|
|
1172
901
|
<div class="skills-view" id="skillsView">
|
|
1173
|
-
<div class="search-bar">
|
|
1174
|
-
<span class="search-icon">🔍</span>
|
|
1175
|
-
<input type="text" id="skillSearchInput" placeholder="Search skills..." data-i18n-ph="skills.search.placeholder" oninput="debounceSkillSearch()">
|
|
1176
|
-
<select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()">
|
|
1177
|
-
<option value="local" data-i18n="scope.local">Local</option>
|
|
1178
|
-
<option value="all" data-i18n="scope.hub">Hub</option>
|
|
1179
|
-
</select>
|
|
1180
|
-
</div>
|
|
1181
|
-
<div class="search-meta" id="skillSearchMeta"></div>
|
|
1182
902
|
<div class="tasks-header">
|
|
1183
903
|
<div class="tasks-stats">
|
|
1184
904
|
<div class="tasks-stat"><span class="tasks-stat-value" id="skillsTotalCount">-</span><span class="tasks-stat-label" data-i18n="skills.total">Total Skills</span></div>
|
|
@@ -1202,10 +922,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1202
922
|
</div>
|
|
1203
923
|
</div>
|
|
1204
924
|
<div class="tasks-list" id="skillsList"><div class="spinner"></div></div>
|
|
1205
|
-
<div id="hubSkillsSection" style="display:none;margin-top:16px">
|
|
1206
|
-
<div class="section-title" style="margin-bottom:12px" data-i18n="skills.hub.title">\u{1F310} Hub Skills</div>
|
|
1207
|
-
<div class="tasks-list" id="hubSkillsList"></div>
|
|
1208
|
-
</div>
|
|
1209
925
|
</div>
|
|
1210
926
|
<div class="task-detail-overlay" id="skillDetailOverlay" onclick="closeSkillDetail(event)">
|
|
1211
927
|
<div class="task-detail-panel" onclick="event.stopPropagation()">
|
|
@@ -1219,7 +935,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1219
935
|
</div>
|
|
1220
936
|
<div class="task-detail-meta" id="skillDetailMeta"></div>
|
|
1221
937
|
<div class="skill-detail-desc" id="skillDetailDesc"></div>
|
|
1222
|
-
<div id="skillShareActions" style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:8px 0"></div>
|
|
1223
938
|
<div class="task-detail-chunks-title" data-i18n="skills.files">Skill Files</div>
|
|
1224
939
|
<div class="skill-files-list" id="skillFilesList"></div>
|
|
1225
940
|
<div class="task-detail-chunks-title" id="skillContentTitle" data-i18n="skills.content">SKILL.md Content</div>
|
|
@@ -1285,380 +1000,186 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1285
1000
|
|
|
1286
1001
|
<!-- ─── Settings View ─── -->
|
|
1287
1002
|
<div class="settings-view" id="settingsView">
|
|
1288
|
-
<div class="settings-
|
|
1289
|
-
<
|
|
1290
|
-
<
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
<!-- ══ Card: AI Models (Embedding + Summarizer + Skill) ══ -->
|
|
1296
|
-
<div class="settings-card card-models stab-active" data-stab="models">
|
|
1297
|
-
<div class="settings-card-header">
|
|
1298
|
-
<div class="settings-card-icon" style="background:rgba(99,102,241,.1);border-color:rgba(99,102,241,.15)">\u{1F9E0}</div>
|
|
1299
|
-
<div class="settings-card-title-wrap">
|
|
1300
|
-
<div class="settings-card-title" data-i18n="settings.models">AI Models</div>
|
|
1301
|
-
<div class="settings-card-desc" data-i18n="settings.models.desc">Configure embedding, summarizer and skill evolution models</div>
|
|
1302
|
-
</div>
|
|
1003
|
+
<div class="settings-group" id="settingsModelConfig">
|
|
1004
|
+
<h2 class="settings-group-title"><span data-i18n="settings.modelconfig">Model Configuration</span></h2>
|
|
1005
|
+
<div class="settings-section">
|
|
1006
|
+
<h3><span class="icon">\u{1F4CA}</span> <span data-i18n="settings.modelhealth">Model Health</span></h3>
|
|
1007
|
+
<div class="model-health-bar" id="modelHealthBar">
|
|
1008
|
+
<div style="font-size:12px;color:var(--text-muted);width:100%">Loading model status...</div>
|
|
1303
1009
|
</div>
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
<label>API Key</label>
|
|
1336
|
-
<input type="password" id="cfgEmbApiKey" placeholder="\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022">
|
|
1337
|
-
</div>
|
|
1338
|
-
</div>
|
|
1339
|
-
<div class="test-conn-row">
|
|
1340
|
-
<button class="btn btn-sm btn-ghost" onclick="testModel('embedding')" id="testEmbBtn" data-i18n="settings.test">Test Connection</button>
|
|
1341
|
-
<span class="test-result" id="testEmbResult"></span>
|
|
1342
|
-
</div>
|
|
1343
|
-
|
|
1344
|
-
<div class="settings-card-divider"></div>
|
|
1345
|
-
|
|
1346
|
-
<!-- Summarizer Model section -->
|
|
1347
|
-
<div class="settings-card-subtitle">\u{1F4DD} <span data-i18n="settings.summarizer">Summarizer Model</span></div>
|
|
1348
|
-
<div class="field-hint" style="margin-bottom:10px" data-i18n="settings.summarizer.desc">LLM for memory summarization, deduplication and analysis</div>
|
|
1349
|
-
<div class="settings-grid">
|
|
1350
|
-
<div class="settings-field">
|
|
1351
|
-
<label data-i18n="settings.provider">Provider</label>
|
|
1352
|
-
<select id="cfgSumProvider" onchange="onProviderChange('summarizer')">
|
|
1353
|
-
<option value="openai_compatible">OpenAI Compatible</option>
|
|
1354
|
-
<option value="openai">OpenAI</option>
|
|
1355
|
-
<option value="siliconflow">SiliconFlow (\u7845\u57FA\u6D41\u52A8)</option>
|
|
1356
|
-
<option value="zhipu">Zhipu AI (\u667A\u8C31)</option>
|
|
1357
|
-
<option value="deepseek">DeepSeek</option>
|
|
1358
|
-
<option value="bailian">Alibaba Bailian (\u767E\u70BC)</option>
|
|
1359
|
-
<option value="moonshot">Moonshot (Kimi)</option>
|
|
1360
|
-
<option value="anthropic">Anthropic</option>
|
|
1361
|
-
<option value="gemini">Gemini</option>
|
|
1362
|
-
<option value="azure_openai">Azure OpenAI</option>
|
|
1363
|
-
<option value="bedrock">Bedrock</option>
|
|
1364
|
-
<option value="openclaw">OpenClaw Host</option>
|
|
1365
|
-
</select>
|
|
1366
|
-
</div>
|
|
1367
|
-
<div class="settings-field">
|
|
1368
|
-
<label data-i18n="settings.model">Model</label>
|
|
1369
|
-
<input type="text" id="cfgSumModel" placeholder="e.g. gpt-4o-mini">
|
|
1370
|
-
</div>
|
|
1371
|
-
<div class="settings-field full-width">
|
|
1372
|
-
<label>Endpoint</label>
|
|
1373
|
-
<input type="text" id="cfgSumEndpoint" placeholder="https://...">
|
|
1374
|
-
</div>
|
|
1375
|
-
<div class="settings-field">
|
|
1376
|
-
<label>API Key</label>
|
|
1377
|
-
<input type="password" id="cfgSumApiKey" placeholder="\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022">
|
|
1378
|
-
</div>
|
|
1379
|
-
<div class="settings-field">
|
|
1380
|
-
<label data-i18n="settings.temperature">Temperature</label>
|
|
1381
|
-
<input type="number" id="cfgSumTemp" step="0.1" min="0" max="2" placeholder="0">
|
|
1382
|
-
</div>
|
|
1383
|
-
</div>
|
|
1384
|
-
<div class="test-conn-row">
|
|
1385
|
-
<button class="btn btn-sm btn-ghost" onclick="testModel('summarizer')" id="testSumBtn" data-i18n="settings.test">Test Connection</button>
|
|
1386
|
-
<span class="test-result" id="testSumResult"></span>
|
|
1387
|
-
</div>
|
|
1388
|
-
|
|
1389
|
-
<div class="settings-card-divider"></div>
|
|
1390
|
-
|
|
1391
|
-
<!-- Skill Evolution section -->
|
|
1392
|
-
<div class="settings-card-subtitle">\u{1F527} <span data-i18n="settings.skill">Skill Evolution</span></div>
|
|
1393
|
-
<div class="field-hint" style="margin-bottom:10px" data-i18n="settings.skill.desc">Auto-extract reusable skills from conversation patterns</div>
|
|
1394
|
-
<div class="settings-grid">
|
|
1395
|
-
<div class="settings-toggle">
|
|
1396
|
-
<label class="toggle-switch"><input type="checkbox" id="cfgSkillEnabled"><span class="toggle-slider"></span></label>
|
|
1397
|
-
<label data-i18n="settings.skill.enabled">Enable Skill Evolution</label>
|
|
1398
|
-
</div>
|
|
1399
|
-
<div class="settings-toggle">
|
|
1400
|
-
<label class="toggle-switch"><input type="checkbox" id="cfgSkillAutoInstall"><span class="toggle-slider"></span></label>
|
|
1401
|
-
<label data-i18n="settings.skill.autoinstall">Auto Install Skills</label>
|
|
1402
|
-
</div>
|
|
1403
|
-
<div class="settings-field">
|
|
1404
|
-
<label data-i18n="settings.skill.confidence">Min Confidence</label>
|
|
1405
|
-
<input type="number" id="cfgSkillConfidence" step="0.1" min="0" max="1" placeholder="0.7">
|
|
1406
|
-
</div>
|
|
1407
|
-
<div class="settings-field">
|
|
1408
|
-
<label data-i18n="settings.skill.minchunks">Min Chunks</label>
|
|
1409
|
-
<input type="number" id="cfgSkillMinChunks" placeholder="6">
|
|
1410
|
-
</div>
|
|
1411
|
-
</div>
|
|
1412
|
-
<div style="margin-top:14px">
|
|
1413
|
-
<div class="settings-card-subtitle" style="margin-bottom:4px" data-i18n="settings.skill.model">Skill Dedicated Model</div>
|
|
1414
|
-
<div class="field-hint" style="margin-bottom:12px" data-i18n="settings.skill.model.hint">If not configured, the main Summarizer Model above will be used for skill generation. Configure a dedicated model here for higher quality skill output.</div>
|
|
1415
|
-
<div class="settings-grid">
|
|
1416
|
-
<div class="settings-field">
|
|
1417
|
-
<label data-i18n="settings.provider">Provider</label>
|
|
1418
|
-
<select id="cfgSkillProvider" onchange="onProviderChange('skill')">
|
|
1419
|
-
<option value="">\u2014 <span data-i18n="settings.skill.usemain">Use main summarizer</span> \u2014</option>
|
|
1420
|
-
<option value="openai_compatible">OpenAI Compatible</option>
|
|
1421
|
-
<option value="openai">OpenAI</option>
|
|
1422
|
-
<option value="siliconflow">SiliconFlow (\u7845\u57FA\u6D41\u52A8)</option>
|
|
1423
|
-
<option value="zhipu">Zhipu AI (\u667A\u8C31)</option>
|
|
1424
|
-
<option value="deepseek">DeepSeek</option>
|
|
1425
|
-
<option value="bailian">Alibaba Bailian (\u767E\u70BC)</option>
|
|
1426
|
-
<option value="moonshot">Moonshot (Kimi)</option>
|
|
1427
|
-
<option value="anthropic">Anthropic</option>
|
|
1428
|
-
<option value="gemini">Gemini</option>
|
|
1429
|
-
<option value="azure_openai">Azure OpenAI</option>
|
|
1430
|
-
<option value="bedrock">Bedrock</option>
|
|
1431
|
-
<option value="openclaw">OpenClaw Host</option>
|
|
1432
|
-
</select>
|
|
1433
|
-
</div>
|
|
1434
|
-
<div class="settings-field">
|
|
1435
|
-
<label data-i18n="settings.model">Model</label>
|
|
1436
|
-
<input type="text" id="cfgSkillModel" placeholder="e.g. claude-4.6-opus">
|
|
1437
|
-
</div>
|
|
1438
|
-
<div class="settings-field full-width">
|
|
1439
|
-
<label>Endpoint</label>
|
|
1440
|
-
<input type="text" id="cfgSkillEndpoint" placeholder="https://...">
|
|
1441
|
-
</div>
|
|
1442
|
-
<div class="settings-field">
|
|
1443
|
-
<label>API Key</label>
|
|
1444
|
-
<input type="password" id="cfgSkillApiKey" placeholder="\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022">
|
|
1445
|
-
</div>
|
|
1446
|
-
</div>
|
|
1447
|
-
<div class="test-conn-row">
|
|
1448
|
-
<button class="btn btn-sm btn-ghost" onclick="testModel('skill')" id="testSkillBtn" data-i18n="settings.test">Test Connection</button>
|
|
1449
|
-
<span class="test-result" id="testSkillResult"></span>
|
|
1450
|
-
</div>
|
|
1451
|
-
</div>
|
|
1452
|
-
|
|
1453
|
-
<div class="settings-card-divider"></div>
|
|
1454
|
-
<div class="settings-actions">
|
|
1455
|
-
<span class="settings-saved" id="modelsSaved">\u2713 <span data-i18n="settings.saved">Saved</span></span>
|
|
1456
|
-
<button class="btn btn-ghost" onclick="loadConfig()" data-i18n="settings.reset">Reset</button>
|
|
1457
|
-
<button class="btn btn-primary" onclick="saveModelsConfig()" data-i18n="settings.save">Save Settings</button>
|
|
1458
|
-
</div>
|
|
1459
|
-
<div style="font-size:11px;color:var(--text-muted);text-align:right;margin-top:4px" data-i18n="settings.restart.hint">Some changes require restarting the OpenClaw gateway to take effect.</div>
|
|
1010
|
+
</div>
|
|
1011
|
+
<div class="settings-section">
|
|
1012
|
+
<h3><span class="icon">\u{1F4E1}</span> <span data-i18n="settings.embedding">Embedding Model</span></h3>
|
|
1013
|
+
<div class="settings-grid">
|
|
1014
|
+
<div class="settings-field">
|
|
1015
|
+
<label data-i18n="settings.provider">Provider</label>
|
|
1016
|
+
<select id="cfgEmbProvider" onchange="onProviderChange('embedding')">
|
|
1017
|
+
<option value="openai_compatible">OpenAI Compatible</option>
|
|
1018
|
+
<option value="openai">OpenAI</option>
|
|
1019
|
+
<option value="siliconflow">SiliconFlow (\u7845\u57FA\u6D41\u52A8)</option>
|
|
1020
|
+
<option value="zhipu">Zhipu AI (\u667A\u8C31)</option>
|
|
1021
|
+
<option value="bailian">Alibaba Bailian (\u767E\u70BC)</option>
|
|
1022
|
+
<option value="gemini">Gemini</option>
|
|
1023
|
+
<option value="azure_openai">Azure OpenAI</option>
|
|
1024
|
+
<option value="cohere">Cohere</option>
|
|
1025
|
+
<option value="mistral">Mistral</option>
|
|
1026
|
+
<option value="voyage">Voyage</option>
|
|
1027
|
+
<option value="local">Local</option>
|
|
1028
|
+
</select>
|
|
1029
|
+
</div>
|
|
1030
|
+
<div class="settings-field">
|
|
1031
|
+
<label data-i18n="settings.model">Model</label>
|
|
1032
|
+
<input type="text" id="cfgEmbModel" placeholder="e.g. bge-m3">
|
|
1033
|
+
</div>
|
|
1034
|
+
<div class="settings-field full-width">
|
|
1035
|
+
<label>Endpoint</label>
|
|
1036
|
+
<input type="text" id="cfgEmbEndpoint" placeholder="https://...">
|
|
1037
|
+
</div>
|
|
1038
|
+
<div class="settings-field">
|
|
1039
|
+
<label>API Key</label>
|
|
1040
|
+
<input type="password" id="cfgEmbApiKey" placeholder="\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022">
|
|
1460
1041
|
</div>
|
|
1461
1042
|
</div>
|
|
1043
|
+
<div class="test-conn-row">
|
|
1044
|
+
<button class="btn btn-sm btn-ghost" onclick="testModel('embedding')" id="testEmbBtn" data-i18n="settings.test">Test Connection</button>
|
|
1045
|
+
<span class="test-result" id="testEmbResult"></span>
|
|
1046
|
+
</div>
|
|
1047
|
+
</div>
|
|
1462
1048
|
|
|
1463
|
-
|
|
1464
|
-
<
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
<
|
|
1468
|
-
|
|
1469
|
-
<
|
|
1470
|
-
|
|
1049
|
+
<div class="settings-section">
|
|
1050
|
+
<h3><span class="icon">\u{1F9E0}</span> <span data-i18n="settings.summarizer">Summarizer Model</span></h3>
|
|
1051
|
+
<div class="settings-grid">
|
|
1052
|
+
<div class="settings-field">
|
|
1053
|
+
<label data-i18n="settings.provider">Provider</label>
|
|
1054
|
+
<select id="cfgSumProvider" onchange="onProviderChange('summarizer')">
|
|
1055
|
+
<option value="openai_compatible">OpenAI Compatible</option>
|
|
1056
|
+
<option value="openai">OpenAI</option>
|
|
1057
|
+
<option value="siliconflow">SiliconFlow (\u7845\u57FA\u6D41\u52A8)</option>
|
|
1058
|
+
<option value="zhipu">Zhipu AI (\u667A\u8C31)</option>
|
|
1059
|
+
<option value="deepseek">DeepSeek</option>
|
|
1060
|
+
<option value="bailian">Alibaba Bailian (\u767E\u70BC)</option>
|
|
1061
|
+
<option value="moonshot">Moonshot (Kimi)</option>
|
|
1062
|
+
<option value="anthropic">Anthropic</option>
|
|
1063
|
+
<option value="gemini">Gemini</option>
|
|
1064
|
+
<option value="azure_openai">Azure OpenAI</option>
|
|
1065
|
+
<option value="bedrock">Bedrock</option>
|
|
1066
|
+
</select>
|
|
1471
1067
|
</div>
|
|
1472
|
-
<div class="settings-
|
|
1473
|
-
|
|
1474
|
-
<
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
<li><span data-i18n="guide.join.s2">Enable sharing above, select "Client" mode</span></li>
|
|
1488
|
-
<li><span data-i18n="guide.join.s3">Fill in Hub Address and Team Token, click "Test Connection"</span></li>
|
|
1489
|
-
<li><span data-i18n="guide.join.s4">Save settings and restart the OpenClaw gateway (page refreshes automatically)</span></li>
|
|
1490
|
-
</ol>
|
|
1491
|
-
<button class="btn-guide" onclick="guideGoToHub('client')" data-i18n="guide.join.btn">\u2192 Configure Client Mode</button>
|
|
1492
|
-
</div>
|
|
1493
|
-
<div class="team-guide-opt">
|
|
1494
|
-
<div class="team-guide-opt-header">
|
|
1495
|
-
<div class="team-guide-opt-icon" style="background:rgba(139,92,246,.1);border:1px solid rgba(139,92,246,.15)">\u{1F5A5}\uFE0F</div>
|
|
1496
|
-
<div class="team-guide-opt-title" data-i18n="guide.hub.title">Start Your Own Hub</div>
|
|
1497
|
-
</div>
|
|
1498
|
-
<div class="team-guide-opt-desc" data-i18n="guide.hub.desc">Be the team server. Run a Hub on this device so others can connect and share memories with you.</div>
|
|
1499
|
-
<ol class="team-guide-steps">
|
|
1500
|
-
<li><span data-i18n="guide.hub.s1">Enable sharing above, select "Hub" mode</span></li>
|
|
1501
|
-
<li><span data-i18n="guide.hub.s2">Set a team name, save settings, and restart the gateway (page refreshes automatically)</span></li>
|
|
1502
|
-
<li><span data-i18n="guide.hub.s3">Share the Hub Address and Team Token with your team members</span></li>
|
|
1503
|
-
<li><span data-i18n="guide.hub.s4">Approve join requests in the Admin Panel</span></li>
|
|
1504
|
-
</ol>
|
|
1505
|
-
<button class="btn-guide" onclick="guideGoToHub('hub')" data-i18n="guide.hub.btn">\u2192 Configure Hub Mode</button>
|
|
1506
|
-
</div>
|
|
1507
|
-
</div>
|
|
1508
|
-
</div>
|
|
1509
|
-
|
|
1510
|
-
<div class="field-hint" style="margin-bottom:12px" data-i18n="settings.hub.enable.hint">Enable to share memories, tasks and skills with your team. When disabled, all features work normally in local-only mode.</div>
|
|
1511
|
-
<div class="settings-toggle" style="margin-bottom:16px">
|
|
1512
|
-
<label class="toggle-switch">
|
|
1513
|
-
<input type="checkbox" id="cfgSharingEnabled" onchange="onSharingToggle()">
|
|
1514
|
-
<span class="toggle-slider"></span>
|
|
1515
|
-
</label>
|
|
1516
|
-
<label data-i18n="settings.hub.enable.label">Enable Hub Sharing</label>
|
|
1517
|
-
</div>
|
|
1518
|
-
|
|
1519
|
-
<div id="sharingConfigPanel" style="display:none">
|
|
1520
|
-
<div style="margin-bottom:14px">
|
|
1521
|
-
<label style="font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em;display:block;margin-bottom:6px" data-i18n="settings.hub.role">Role</label>
|
|
1522
|
-
<div style="display:flex;gap:8px">
|
|
1523
|
-
<button class="btn btn-sm" id="btnRoleHub" onclick="selectSharingRole('hub')" data-i18n="settings.hub.role.hub">Hub (Server)</button>
|
|
1524
|
-
<button class="btn btn-sm" id="btnRoleClient" onclick="selectSharingRole('client')" data-i18n="settings.hub.role.client">Client (Connect to Hub)</button>
|
|
1525
|
-
</div>
|
|
1526
|
-
<div class="field-hint" style="margin-top:6px" data-i18n="settings.hub.role.hint">Hub: this device runs the central server. Client: connect to an existing Hub. The two modes are mutually exclusive.</div>
|
|
1527
|
-
</div>
|
|
1528
|
-
|
|
1529
|
-
<div id="hubModeConfig" style="display:none">
|
|
1530
|
-
<input type="hidden" id="cfgHubTeamToken" value="">
|
|
1531
|
-
<div class="settings-grid">
|
|
1532
|
-
<div class="settings-field">
|
|
1533
|
-
<label data-i18n="settings.hub.port">Hub Port</label>
|
|
1534
|
-
<input type="number" id="cfgHubPort" placeholder="18800" value="18800">
|
|
1535
|
-
<div class="field-hint" data-i18n="settings.hub.port.hint">Port for Hub service. Default: 18800</div>
|
|
1536
|
-
</div>
|
|
1537
|
-
<div class="settings-field">
|
|
1538
|
-
<label data-i18n="settings.hub.teamName">Team Name</label>
|
|
1539
|
-
<input type="text" id="cfgHubTeamName" placeholder="My Team">
|
|
1540
|
-
<div class="field-hint" data-i18n="settings.hub.teamName.hint">Your team display name</div>
|
|
1541
|
-
</div>
|
|
1542
|
-
</div>
|
|
1543
|
-
<div id="hubShareInfo" style="display:none;margin-top:14px;background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:14px 18px">
|
|
1544
|
-
<div style="font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em;margin-bottom:10px" data-i18n="settings.hub.shareInfo.title">Share this info with your team members:</div>
|
|
1545
|
-
<div id="hubShareInfoContent" style="display:grid;grid-template-columns:auto 1fr;gap:6px 12px;font-size:12px;align-items:center"></div>
|
|
1546
|
-
</div>
|
|
1547
|
-
<div style="margin-top:16px;display:flex;align-items:center;gap:12px">
|
|
1548
|
-
<button class="btn btn-sm btn-primary" onclick="switchView('admin')" id="hubAdminEntryBtn" style="display:none" data-i18n="sharing.openAdmin">\u{1F6E1} Open Admin Panel</button>
|
|
1549
|
-
</div>
|
|
1550
|
-
</div>
|
|
1551
|
-
|
|
1552
|
-
<div id="clientModeConfig" style="display:none">
|
|
1553
|
-
<div style="background:rgba(99,102,241,.08);border:1px solid rgba(99,102,241,.2);border-radius:10px;padding:14px 18px;margin-bottom:14px;font-size:12px;line-height:1.7;color:var(--text-sec)">
|
|
1554
|
-
<div style="font-weight:700;color:var(--text);margin-bottom:4px" data-i18n="settings.hub.clientSteps.title">Quick Setup (3 steps)</div>
|
|
1555
|
-
<div><span style="color:var(--accent)">1.</span> <span data-i18n="settings.hub.clientSteps.s1">Ask your Hub admin for Hub Address and Team Token</span></div>
|
|
1556
|
-
<div><span style="color:var(--accent)">2.</span> <span data-i18n="settings.hub.clientSteps.s2">Fill them in below, click "Test Connection" to verify</span></div>
|
|
1557
|
-
<div><span style="color:var(--accent)">3.</span> <span data-i18n="settings.hub.clientSteps.s3">Click "Save Settings", then restart OpenClaw gateway (page refreshes automatically)</span></div>
|
|
1558
|
-
</div>
|
|
1559
|
-
<div class="settings-grid">
|
|
1560
|
-
<div class="settings-field full-width">
|
|
1561
|
-
<label data-i18n="settings.hub.hubAddress">Hub Address</label>
|
|
1562
|
-
<input type="text" id="cfgClientHubAddress" placeholder="e.g. 192.168.1.100:18800">
|
|
1563
|
-
<div class="field-hint" data-i18n="settings.hub.hubAddress.hint">Hub server address, e.g. 192.168.1.100:18800 or hub.example.com:18800</div>
|
|
1564
|
-
</div>
|
|
1565
|
-
<div class="settings-field">
|
|
1566
|
-
<label data-i18n="settings.hub.teamTokenClient">Team Token</label>
|
|
1567
|
-
<input type="text" id="cfgClientTeamToken" placeholder="">
|
|
1568
|
-
<div class="field-hint" data-i18n="settings.hub.teamTokenClient.hint">Get this from your Hub admin to join the team</div>
|
|
1569
|
-
</div>
|
|
1570
|
-
<input type="hidden" id="cfgClientUserToken" value="">
|
|
1571
|
-
</div>
|
|
1572
|
-
<div style="margin-top:12px">
|
|
1573
|
-
<button class="btn btn-sm btn-primary" id="btnTestHubConn" onclick="testHubConnection()" data-i18n="settings.hub.testConnection">Test Connection</button>
|
|
1574
|
-
<span id="hubConnTestResult" style="margin-left:10px;font-size:12px"></span>
|
|
1575
|
-
</div>
|
|
1576
|
-
</div>
|
|
1577
|
-
</div>
|
|
1578
|
-
|
|
1579
|
-
<div id="sharingPanelsWrap" style="display:none">
|
|
1580
|
-
<div class="settings-card-divider"></div>
|
|
1581
|
-
<div id="sharingStatusPanel"></div>
|
|
1582
|
-
<div id="sharingTeamPanel"></div>
|
|
1583
|
-
<div id="sharingAdminPanel"></div>
|
|
1584
|
-
</div>
|
|
1585
|
-
|
|
1586
|
-
<div class="settings-card-divider"></div>
|
|
1587
|
-
<div class="settings-actions">
|
|
1588
|
-
<span class="settings-saved" id="hubSaved">\u2713 <span data-i18n="settings.saved">Saved</span></span>
|
|
1589
|
-
<button class="btn btn-ghost" onclick="loadConfig()" data-i18n="settings.reset">Reset</button>
|
|
1590
|
-
<button class="btn btn-primary" onclick="saveHubConfig()" data-i18n="settings.save">Save Settings</button>
|
|
1591
|
-
</div>
|
|
1592
|
-
<div style="font-size:11px;color:var(--text-muted);text-align:right;margin-top:4px" data-i18n="settings.restart.hint">Some changes require restarting the OpenClaw gateway to take effect.</div>
|
|
1068
|
+
<div class="settings-field">
|
|
1069
|
+
<label data-i18n="settings.model">Model</label>
|
|
1070
|
+
<input type="text" id="cfgSumModel" placeholder="e.g. gpt-4o-mini">
|
|
1071
|
+
</div>
|
|
1072
|
+
<div class="settings-field full-width">
|
|
1073
|
+
<label>Endpoint</label>
|
|
1074
|
+
<input type="text" id="cfgSumEndpoint" placeholder="https://...">
|
|
1075
|
+
</div>
|
|
1076
|
+
<div class="settings-field">
|
|
1077
|
+
<label>API Key</label>
|
|
1078
|
+
<input type="password" id="cfgSumApiKey" placeholder="\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022">
|
|
1079
|
+
</div>
|
|
1080
|
+
<div class="settings-field">
|
|
1081
|
+
<label data-i18n="settings.temperature">Temperature</label>
|
|
1082
|
+
<input type="number" id="cfgSumTemp" step="0.1" min="0" max="2" placeholder="0">
|
|
1593
1083
|
</div>
|
|
1594
1084
|
</div>
|
|
1085
|
+
<div class="test-conn-row">
|
|
1086
|
+
<button class="btn btn-sm btn-ghost" onclick="testModel('summarizer')" id="testSumBtn" data-i18n="settings.test">Test Connection</button>
|
|
1087
|
+
<span class="test-result" id="testSumResult"></span>
|
|
1088
|
+
</div>
|
|
1089
|
+
</div>
|
|
1090
|
+
</div>
|
|
1595
1091
|
|
|
1596
|
-
|
|
1597
|
-
<
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
<
|
|
1601
|
-
|
|
1602
|
-
<div class="settings-card-desc" data-i18n="settings.general.desc">System status, ports and telemetry</div>
|
|
1603
|
-
</div>
|
|
1092
|
+
<div class="settings-section">
|
|
1093
|
+
<h3><span class="icon">\u{1F527}</span> <span data-i18n="settings.skill">Skill Evolution</span></h3>
|
|
1094
|
+
<div class="settings-grid">
|
|
1095
|
+
<div class="settings-toggle">
|
|
1096
|
+
<label class="toggle-switch"><input type="checkbox" id="cfgSkillEnabled"><span class="toggle-slider"></span></label>
|
|
1097
|
+
<label data-i18n="settings.skill.enabled">Enable Skill Evolution</label>
|
|
1604
1098
|
</div>
|
|
1605
|
-
<div class="settings-
|
|
1606
|
-
<
|
|
1607
|
-
<
|
|
1608
|
-
|
|
1099
|
+
<div class="settings-toggle">
|
|
1100
|
+
<label class="toggle-switch"><input type="checkbox" id="cfgSkillAutoInstall"><span class="toggle-slider"></span></label>
|
|
1101
|
+
<label data-i18n="settings.skill.autoinstall">Auto Install Skills</label>
|
|
1102
|
+
</div>
|
|
1103
|
+
<div class="settings-field">
|
|
1104
|
+
<label data-i18n="settings.skill.confidence">Min Confidence</label>
|
|
1105
|
+
<input type="number" id="cfgSkillConfidence" step="0.1" min="0" max="1" placeholder="0.7">
|
|
1106
|
+
</div>
|
|
1107
|
+
<div class="settings-field">
|
|
1108
|
+
<label data-i18n="settings.skill.minchunks">Min Chunks</label>
|
|
1109
|
+
<input type="number" id="cfgSkillMinChunks" placeholder="6">
|
|
1110
|
+
</div>
|
|
1111
|
+
</div>
|
|
1112
|
+
<div style="margin-top:16px;padding-top:16px;border-top:1px solid var(--border)">
|
|
1113
|
+
<h4 style="font-size:12px;font-weight:600;color:var(--text-sec);margin-bottom:12px"><span data-i18n="settings.skill.model">Skill Dedicated Model</span></h4>
|
|
1114
|
+
<div class="field-hint" style="margin-bottom:12px" data-i18n="settings.skill.model.hint">If not configured, the main Summarizer Model above will be used for skill generation. Configure a dedicated model here for higher quality skill output.</div>
|
|
1115
|
+
<div class="settings-grid">
|
|
1116
|
+
<div class="settings-field">
|
|
1117
|
+
<label data-i18n="settings.provider">Provider</label>
|
|
1118
|
+
<select id="cfgSkillProvider" onchange="onProviderChange('skill')">
|
|
1119
|
+
<option value="">— <span data-i18n="settings.skill.usemain">Use main summarizer</span> —</option>
|
|
1120
|
+
<option value="openai_compatible">OpenAI Compatible</option>
|
|
1121
|
+
<option value="openai">OpenAI</option>
|
|
1122
|
+
<option value="siliconflow">SiliconFlow (\u7845\u57FA\u6D41\u52A8)</option>
|
|
1123
|
+
<option value="zhipu">Zhipu AI (\u667A\u8C31)</option>
|
|
1124
|
+
<option value="deepseek">DeepSeek</option>
|
|
1125
|
+
<option value="bailian">Alibaba Bailian (\u767E\u70BC)</option>
|
|
1126
|
+
<option value="moonshot">Moonshot (Kimi)</option>
|
|
1127
|
+
<option value="anthropic">Anthropic</option>
|
|
1128
|
+
<option value="gemini">Gemini</option>
|
|
1129
|
+
<option value="azure_openai">Azure OpenAI</option>
|
|
1130
|
+
<option value="bedrock">Bedrock</option>
|
|
1131
|
+
</select>
|
|
1609
1132
|
</div>
|
|
1610
|
-
<div class="settings-
|
|
1611
|
-
|
|
1612
|
-
<
|
|
1613
|
-
<label data-i18n="settings.viewerport">Viewer Port</label>
|
|
1614
|
-
<input type="number" id="cfgViewerPort" placeholder="18799">
|
|
1615
|
-
<div class="field-hint" data-i18n="settings.viewerport.hint">Requires restart to take effect</div>
|
|
1616
|
-
</div>
|
|
1133
|
+
<div class="settings-field">
|
|
1134
|
+
<label data-i18n="settings.model">Model</label>
|
|
1135
|
+
<input type="text" id="cfgSkillModel" placeholder="e.g. claude-4.6-opus">
|
|
1617
1136
|
</div>
|
|
1618
|
-
<div class="settings-
|
|
1619
|
-
|
|
1620
|
-
<
|
|
1621
|
-
<label data-i18n="settings.telemetry.enabled">Enable Anonymous Telemetry</label>
|
|
1137
|
+
<div class="settings-field full-width">
|
|
1138
|
+
<label>Endpoint</label>
|
|
1139
|
+
<input type="text" id="cfgSkillEndpoint" placeholder="https://...">
|
|
1622
1140
|
</div>
|
|
1623
|
-
<div class="field
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
<div class="settings-actions">
|
|
1627
|
-
<span class="settings-saved" id="generalSaved">\u2713 <span data-i18n="settings.saved">Saved</span></span>
|
|
1628
|
-
<button class="btn btn-ghost" onclick="loadConfig()" data-i18n="settings.reset">Reset</button>
|
|
1629
|
-
<button class="btn btn-primary" onclick="saveGeneralConfig()" data-i18n="settings.save">Save Settings</button>
|
|
1141
|
+
<div class="settings-field">
|
|
1142
|
+
<label>API Key</label>
|
|
1143
|
+
<input type="password" id="cfgSkillApiKey" placeholder="\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022">
|
|
1630
1144
|
</div>
|
|
1631
1145
|
</div>
|
|
1146
|
+
<div class="test-conn-row">
|
|
1147
|
+
<button class="btn btn-sm btn-ghost" onclick="testModel('skill')" id="testSkillBtn" data-i18n="settings.test">Test Connection</button>
|
|
1148
|
+
<span class="test-result" id="testSkillResult"></span>
|
|
1149
|
+
</div>
|
|
1632
1150
|
</div>
|
|
1633
|
-
|
|
1634
1151
|
</div>
|
|
1635
1152
|
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
<h2><span class="ah-icon">\u{1F6E1}</span> <span data-i18n="admin.title">Hub Admin Panel</span></h2>
|
|
1646
|
-
<button class="btn btn-sm btn-ghost" onclick="loadAdminData()" style="backdrop-filter:blur(8px)" data-i18n="admin.refresh">\u21BB Refresh</button>
|
|
1153
|
+
<div class="settings-section">
|
|
1154
|
+
<h3><span class="icon">\u{1F4CA}</span> <span data-i18n="settings.telemetry">Telemetry</span></h3>
|
|
1155
|
+
<div class="settings-grid">
|
|
1156
|
+
<div class="settings-toggle">
|
|
1157
|
+
<label class="toggle-switch"><input type="checkbox" id="cfgTelemetryEnabled" checked><span class="toggle-slider"></span></label>
|
|
1158
|
+
<label data-i18n="settings.telemetry.enabled">Enable Anonymous Telemetry</label>
|
|
1159
|
+
</div>
|
|
1160
|
+
<div class="settings-field full-width">
|
|
1161
|
+
<div class="field-hint" data-i18n="settings.telemetry.hint">Anonymous usage analytics to help improve the plugin. Only sends tool names, latencies, and version info. No memory content, queries, or personal data is ever sent.</div>
|
|
1647
1162
|
</div>
|
|
1648
|
-
<div class="admin-header-sub" data-i18n="admin.subtitle">Manage team members, groups, and shared resources</div>
|
|
1649
|
-
<div class="admin-stat-row" id="adminStats"></div>
|
|
1650
1163
|
</div>
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1164
|
+
</div>
|
|
1165
|
+
|
|
1166
|
+
<div class="settings-section">
|
|
1167
|
+
<h3><span class="icon">\u{1F4BE}</span> <span data-i18n="settings.general">General</span></h3>
|
|
1168
|
+
<div class="settings-grid">
|
|
1169
|
+
<div class="settings-field">
|
|
1170
|
+
<label data-i18n="settings.viewerport">Viewer Port</label>
|
|
1171
|
+
<input type="number" id="cfgViewerPort" placeholder="18799">
|
|
1172
|
+
<div class="field-hint" data-i18n="settings.viewerport.hint">Requires restart to take effect</div>
|
|
1173
|
+
</div>
|
|
1656
1174
|
</div>
|
|
1657
|
-
<div class="admin-panel active" id="adminUsersPanel"></div>
|
|
1658
|
-
<div class="admin-panel" id="adminSharedMemoriesPanel"></div>
|
|
1659
|
-
<div class="admin-panel" id="adminMemoriesPanel"></div>
|
|
1660
|
-
<div class="admin-panel" id="adminSkillsPanel"></div>
|
|
1661
1175
|
</div>
|
|
1176
|
+
|
|
1177
|
+
<div class="settings-actions">
|
|
1178
|
+
<span class="settings-saved" id="settingsSaved">\u2713 <span data-i18n="settings.saved">Saved</span></span>
|
|
1179
|
+
<button class="btn btn-ghost" onclick="loadConfig()" data-i18n="settings.reset">Reset</button>
|
|
1180
|
+
<button class="btn btn-primary" onclick="saveConfig()" data-i18n="settings.save">Save Settings</button>
|
|
1181
|
+
</div>
|
|
1182
|
+
<div style="font-size:11px;color:var(--text-muted);text-align:right;margin-top:4px" data-i18n="settings.restart.hint">Some changes require restarting the OpenClaw gateway to take effect.</div>
|
|
1662
1183
|
</div>
|
|
1663
1184
|
|
|
1664
1185
|
<!-- ─── Import Page ─── -->
|
|
@@ -1854,13 +1375,12 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1854
1375
|
|
|
1855
1376
|
<script>
|
|
1856
1377
|
let activeSession=null,activeRole='',editingId=null,searchTimer=null,memoryCache={},currentPage=1,totalPages=1,totalCount=0,PAGE_SIZE=40,metricsDays=30;
|
|
1857
|
-
let memorySearchScope='local',skillSearchScope='local',taskSearchScope='local';
|
|
1858
1378
|
let _embeddingWarningShown=false;
|
|
1859
1379
|
|
|
1860
1380
|
/* ─── i18n ─── */
|
|
1861
1381
|
const I18N={
|
|
1862
1382
|
en:{
|
|
1863
|
-
'title':'
|
|
1383
|
+
'title':'OpenClaw Memory',
|
|
1864
1384
|
'subtitle':'Powered by MemOS',
|
|
1865
1385
|
'setup.desc':'Set a password to protect your memories',
|
|
1866
1386
|
'setup.pw':'Enter a password (4+ characters)',
|
|
@@ -1900,14 +1420,6 @@ const I18N={
|
|
|
1900
1420
|
'skills.active':'Active',
|
|
1901
1421
|
'skills.installed':'Installed',
|
|
1902
1422
|
'skills.public':'Public',
|
|
1903
|
-
'skills.search.placeholder':'Search skills...',
|
|
1904
|
-
'skills.search.local':'Local',
|
|
1905
|
-
'skills.search.noresult':'No matching skills found',
|
|
1906
|
-
'skills.load.error':'Failed to load skills',
|
|
1907
|
-
'skills.hub.title':'\u{1F310} Hub Skills',
|
|
1908
|
-
'scope.local':'Local',
|
|
1909
|
-
'scope.group':'Group',
|
|
1910
|
-
'scope.all':'All',
|
|
1911
1423
|
'skills.visibility.public':'Public',
|
|
1912
1424
|
'skills.visibility.private':'Private',
|
|
1913
1425
|
'skills.setPublic':'Set Public',
|
|
@@ -1946,7 +1458,6 @@ const I18N={
|
|
|
1946
1458
|
'filter.newest':'Newest first',
|
|
1947
1459
|
'filter.oldest':'Oldest first',
|
|
1948
1460
|
'filter.allowners':'All owners',
|
|
1949
|
-
'filter.allsessions':'All sessions',
|
|
1950
1461
|
'filter.public':'Public',
|
|
1951
1462
|
'filter.private':'Private',
|
|
1952
1463
|
'filter.allvisibility':'All visibility',
|
|
@@ -2027,22 +1538,11 @@ const I18N={
|
|
|
2027
1538
|
'tab.import':'\u{1F4E5} Import',
|
|
2028
1539
|
'tab.settings':'\u2699 Settings',
|
|
2029
1540
|
'settings.modelconfig':'Model Configuration',
|
|
2030
|
-
'settings.models':'AI Models',
|
|
2031
|
-
'settings.models.desc':'Configure embedding, summarizer and skill evolution models',
|
|
2032
1541
|
'settings.modelhealth':'Model Health',
|
|
2033
1542
|
'settings.embedding':'Embedding Model',
|
|
2034
1543
|
'settings.summarizer':'Summarizer Model',
|
|
2035
1544
|
'settings.skill':'Skill Evolution',
|
|
2036
1545
|
'settings.general':'General',
|
|
2037
|
-
'settings.embedding.desc':'Vector embedding model for memory search and retrieval',
|
|
2038
|
-
'settings.summarizer.desc':'LLM for memory summarization, deduplication and analysis',
|
|
2039
|
-
'settings.skill.desc':'Auto-extract reusable skills from conversation patterns',
|
|
2040
|
-
'settings.hub.desc':'Share memories, tasks and skills with your team',
|
|
2041
|
-
'settings.general.desc':'System status, ports and telemetry',
|
|
2042
|
-
'settings.hostproxy.embedding':'Use Gateway Model',
|
|
2043
|
-
'settings.hostproxy.completion':'Use Gateway Model',
|
|
2044
|
-
'settings.hostproxy.skill':'Use Gateway Model',
|
|
2045
|
-
'settings.hostproxy.hint.short':'Reuse gateway model config',
|
|
2046
1546
|
'settings.provider':'Provider',
|
|
2047
1547
|
'settings.model':'Model',
|
|
2048
1548
|
'settings.temperature':'Temperature',
|
|
@@ -2051,12 +1551,12 @@ const I18N={
|
|
|
2051
1551
|
'settings.skill.confidence':'Min Confidence',
|
|
2052
1552
|
'settings.skill.minchunks':'Min Chunks',
|
|
2053
1553
|
'settings.skill.model':'Skill Dedicated Model',
|
|
2054
|
-
'settings.skill.model.hint':'
|
|
1554
|
+
'settings.skill.model.hint':'If not configured, the main Summarizer Model above will be used for skill generation. Configure a dedicated model here for higher quality skill output.',
|
|
2055
1555
|
'settings.optional':'Optional',
|
|
2056
1556
|
'settings.skill.usemain':'Use Main Summarizer',
|
|
2057
1557
|
'settings.telemetry':'Telemetry',
|
|
2058
1558
|
'settings.telemetry.enabled':'Enable Anonymous Telemetry',
|
|
2059
|
-
'settings.telemetry.hint':'Only
|
|
1559
|
+
'settings.telemetry.hint':'Anonymous usage analytics to help improve the plugin. Only sends tool names, latencies, and version info. No memory content, queries, or personal data is ever sent.',
|
|
2060
1560
|
'settings.viewerport':'Viewer Port',
|
|
2061
1561
|
'settings.viewerport.hint':'Requires restart to take effect',
|
|
2062
1562
|
'settings.test':'Test Connection',
|
|
@@ -2068,8 +1568,6 @@ const I18N={
|
|
|
2068
1568
|
'settings.reset':'Reset',
|
|
2069
1569
|
'settings.saved':'Saved',
|
|
2070
1570
|
'settings.restart.hint':'Some changes require restarting the OpenClaw gateway to take effect.',
|
|
2071
|
-
'settings.restart.autoRefresh':'Page will refresh automatically after the gateway restarts...',
|
|
2072
|
-
'settings.restart.waiting':'Configuration saved. Waiting for gateway to restart...',
|
|
2073
1571
|
'settings.save.fail':'Failed to save settings',
|
|
2074
1572
|
'settings.save.emb.required':'Embedding model is required. Please configure an embedding model before saving.',
|
|
2075
1573
|
'settings.save.emb.fail':'Embedding model test failed, cannot save',
|
|
@@ -2155,7 +1653,7 @@ const I18N={
|
|
|
2155
1653
|
'skills.related':'Related Tasks',
|
|
2156
1654
|
'skills.download':'\u2B07 Download',
|
|
2157
1655
|
'skills.installed.badge':'Installed',
|
|
2158
|
-
'skills.empty':'No skills yet. Skills are
|
|
1656
|
+
'skills.empty':'No skills yet. Skills are automatically generated from completed tasks that contain reusable experience.',
|
|
2159
1657
|
'skills.loading':'Loading...',
|
|
2160
1658
|
'skills.error':'Error loading skill',
|
|
2161
1659
|
'skills.error.detail':'Failed to load skill: ',
|
|
@@ -2176,222 +1674,6 @@ const I18N={
|
|
|
2176
1674
|
'tasks.error':'Error',
|
|
2177
1675
|
'tasks.error.detail':'Failed to load task details',
|
|
2178
1676
|
'tasks.untitled.related':'Untitled',
|
|
2179
|
-
'tab.admin':'\u{1F6E1} Admin',
|
|
2180
|
-
'settings.hub':'Hub & Team',
|
|
2181
|
-
'settings.hub.enable':'Enable Hub Sharing',
|
|
2182
|
-
'settings.hub.enable.hint':'When off, everything works locally as usual.',
|
|
2183
|
-
'settings.hub.enable.label':'Enable Hub Sharing',
|
|
2184
|
-
'settings.hub.role':'Role',
|
|
2185
|
-
'settings.hub.role.hub':'Hub (Server)',
|
|
2186
|
-
'settings.hub.role.client':'Client (Connect to Hub)',
|
|
2187
|
-
'settings.hub.role.hint':'Hub = run the server; Client = connect to one. These two modes are mutually exclusive.',
|
|
2188
|
-
'settings.hub.port':'Hub Port',
|
|
2189
|
-
'settings.hub.port.hint':'Port for Hub service. Default: 18800',
|
|
2190
|
-
'settings.hub.teamName':'Team Name',
|
|
2191
|
-
'settings.hub.teamName.hint':'Display name for your team',
|
|
2192
|
-
'settings.hub.teamToken':'Team Token',
|
|
2193
|
-
'settings.hub.teamToken.hint':'Auto-generated secret for clients to join. Click to copy. Share this with your team members.',
|
|
2194
|
-
'settings.hub.tokenCopied':'Team Token copied!',
|
|
2195
|
-
'settings.hub.hubSteps.title':'Quick Setup (3 steps)',
|
|
2196
|
-
'settings.hub.hubSteps.s1':'Fill in Team Name below (or keep default)',
|
|
2197
|
-
'settings.hub.hubSteps.s2':'Click "Save Settings", then restart OpenClaw gateway',
|
|
2198
|
-
'settings.hub.hubSteps.s3':'Share the Hub Address and Team Token below with your team members',
|
|
2199
|
-
'settings.hub.clientSteps.title':'Quick Setup (3 steps)',
|
|
2200
|
-
'settings.hub.clientSteps.s1':'Ask your Hub admin for Hub Address and Team Token',
|
|
2201
|
-
'settings.hub.clientSteps.s2':'Fill them in below, click "Test Connection" to verify',
|
|
2202
|
-
'settings.hub.clientSteps.s3':'Click "Save Settings", then restart OpenClaw gateway (page refreshes automatically)',
|
|
2203
|
-
'settings.hub.shareInfo.title':'Share this info with your team members:',
|
|
2204
|
-
'settings.hub.shareInfo.yourIP':'your-IP',
|
|
2205
|
-
'settings.hub.shareInfo.clickCopy':'Click to copy',
|
|
2206
|
-
'settings.hub.restartAlert':'Hub sharing config saved! Please restart the OpenClaw gateway for changes to take effect.\\n\\nRun: openclaw gateway stop && openclaw gateway start',
|
|
2207
|
-
'settings.hub.hubAddress':'Hub Address',
|
|
2208
|
-
'settings.hub.hubAddress.hint':'Hub server address, e.g. 192.168.1.100:18800',
|
|
2209
|
-
'settings.hub.teamTokenClient':'Team Token',
|
|
2210
|
-
'settings.hub.teamTokenClient.hint':'Get this from your Hub admin to join the team',
|
|
2211
|
-
'settings.hub.userToken':'User Token',
|
|
2212
|
-
'settings.hub.userToken.hint':'Usually auto-obtained after joining. Only fill if given by admin.',
|
|
2213
|
-
'settings.hub.testConnection':'Test Connection',
|
|
2214
|
-
'settings.hub.test.noAddr':'Please enter Hub address first',
|
|
2215
|
-
'settings.hub.test.testing':'Testing...',
|
|
2216
|
-
'settings.hub.test.ok':'Connected successfully',
|
|
2217
|
-
'settings.hub.test.fail':'Connection failed',
|
|
2218
|
-
'settings.hub.connection':'Connection Status',
|
|
2219
|
-
'settings.hub.team':'Team & Groups',
|
|
2220
|
-
'settings.hub.adminPending':'Admin Pending Users',
|
|
2221
|
-
'sidebar.hub':'\u{1F310} Team Sharing',
|
|
2222
|
-
'sharing.sidebar.connected':'Connected',
|
|
2223
|
-
'sharing.sidebar.disconnected':'Disconnected',
|
|
2224
|
-
'sharing.sidebar.pending':'Pending Approval',
|
|
2225
|
-
'sharing.sidebar.rejected':'Rejected',
|
|
2226
|
-
'sharing.sidebar.starting':'Starting...',
|
|
2227
|
-
'sharing.sidebar.notConfigured':'Not configured',
|
|
2228
|
-
'sharing.sidebar.identity':'Identity:',
|
|
2229
|
-
'sharing.sidebar.admin':'Admin',
|
|
2230
|
-
'sharing.sidebar.targetHub':'Target Hub:',
|
|
2231
|
-
'sharing.pendingApproval.hint':'Your join request has been submitted. Please wait for the Hub admin to approve.',
|
|
2232
|
-
'sharing.rejected.hint':'Your join request was rejected by the Hub admin. Please contact the admin or retry.',
|
|
2233
|
-
'sharing.retryJoin':'Retry Join',
|
|
2234
|
-
'sharing.retryJoin.hint':'Clears local data and re-submits the join request',
|
|
2235
|
-
'sharing.retryJoin.confirm':'This will clear your current connection and re-submit a join request. Continue?',
|
|
2236
|
-
'sharing.retryJoin.success':'Join request re-submitted. Waiting for admin approval.',
|
|
2237
|
-
'sharing.retryJoin.fail':'Failed to retry join',
|
|
2238
|
-
'sharing.cannotJoinSelf':'Cannot join your own Hub. Please enter a remote Hub address.',
|
|
2239
|
-
'scope.hub':'Hub',
|
|
2240
|
-
'memory.detail.title':'Memory Detail',
|
|
2241
|
-
'memory.detail.loading':'Loading...',
|
|
2242
|
-
'memory.detail.notFound':'Memory not found',
|
|
2243
|
-
'memory.detail.copyId':'Click to copy ID',
|
|
2244
|
-
'memory.detail.created':'Created ',
|
|
2245
|
-
'memory.detail.updated':'Updated ',
|
|
2246
|
-
'memory.detail.viewTarget':'View target: ',
|
|
2247
|
-
'admin.title':'Hub Admin Panel',
|
|
2248
|
-
'admin.subtitle':'Manage team members and shared resources',
|
|
2249
|
-
'admin.refresh':'\u21BB Refresh',
|
|
2250
|
-
'admin.tab.users':'Users',
|
|
2251
|
-
'admin.tab.groups':'Groups',
|
|
2252
|
-
'admin.tab.memories':'Shared Tasks',
|
|
2253
|
-
'admin.tab.skills':'Shared Skills',
|
|
2254
|
-
'admin.stat.activeUsers':'Active Users',
|
|
2255
|
-
'admin.stat.pending':'Pending',
|
|
2256
|
-
'admin.stat.groups':'Groups',
|
|
2257
|
-
'admin.stat.sharedTasks':'Shared Tasks',
|
|
2258
|
-
'admin.stat.sharedSkills':'Shared Skills',
|
|
2259
|
-
'admin.stat.sharedMemories':'Shared Memories',
|
|
2260
|
-
'admin.pendingApproval':'Pending Approval',
|
|
2261
|
-
'admin.activeUsers':'Active Users',
|
|
2262
|
-
'admin.noActiveUsers':'No active users.',
|
|
2263
|
-
'admin.approve':'Approve',
|
|
2264
|
-
'admin.reject':'Reject',
|
|
2265
|
-
'admin.device':'Device: ',
|
|
2266
|
-
'admin.groups':'Groups',
|
|
2267
|
-
'admin.newGroup':'+ New Group',
|
|
2268
|
-
'admin.groupName':'Group name',
|
|
2269
|
-
'admin.groupDesc':'Description (optional)',
|
|
2270
|
-
'admin.create':'Create',
|
|
2271
|
-
'admin.cancel':'Cancel',
|
|
2272
|
-
'admin.delete':'Delete',
|
|
2273
|
-
'admin.members':'Members',
|
|
2274
|
-
'admin.noGroups':'No groups created yet.',
|
|
2275
|
-
'admin.noMembers':'No members.',
|
|
2276
|
-
'admin.add':'Add',
|
|
2277
|
-
'admin.remove':'Remove',
|
|
2278
|
-
'admin.sharedTasks':'Shared Tasks',
|
|
2279
|
-
'admin.noSharedTasks':'No shared tasks on Hub.',
|
|
2280
|
-
'admin.owner':'Owner: ',
|
|
2281
|
-
'admin.group':'Group: ',
|
|
2282
|
-
'admin.chunks':'Chunks: ',
|
|
2283
|
-
'admin.updated':'Updated: ',
|
|
2284
|
-
'admin.sharedSkills':'Shared Skills',
|
|
2285
|
-
'admin.noSharedSkills':'No shared skills on Hub.',
|
|
2286
|
-
'admin.sharedMemories':'Shared Memories',
|
|
2287
|
-
'admin.noSharedMemories':'No shared memories on Hub.',
|
|
2288
|
-
'admin.tab.sharedMemories':'Shared Memories',
|
|
2289
|
-
'admin.version':'v',
|
|
2290
|
-
'admin.quality':'Quality: ',
|
|
2291
|
-
'admin.membersCount':'Members ({n}):',
|
|
2292
|
-
'admin.noMembersYet':'No members yet.',
|
|
2293
|
-
'admin.loadFailed':'Failed to load admin data: ',
|
|
2294
|
-
'admin.noPermission':'You do not have admin permissions to access this panel.',
|
|
2295
|
-
'admin.groupsFailed':'Failed to load groups: ',
|
|
2296
|
-
'toast.userApproved':'User approved',
|
|
2297
|
-
'toast.userRejected':'User rejected',
|
|
2298
|
-
'toast.approveFail':'Approve failed',
|
|
2299
|
-
'toast.rejectFail':'Reject failed',
|
|
2300
|
-
'toast.groupCreated':'Group created',
|
|
2301
|
-
'toast.groupDeleted':'Group deleted',
|
|
2302
|
-
'toast.memberAdded':'Member added',
|
|
2303
|
-
'toast.memberRemoved':'Member removed',
|
|
2304
|
-
'toast.taskRemoved':'Task removed',
|
|
2305
|
-
'toast.skillRemoved':'Skill removed',
|
|
2306
|
-
'toast.memoryRemoved':'Memory removed',
|
|
2307
|
-
'toast.createFail':'Create failed',
|
|
2308
|
-
'toast.deleteFail':'Delete failed',
|
|
2309
|
-
'toast.addFail':'Add failed',
|
|
2310
|
-
'toast.removeFail':'Remove failed',
|
|
2311
|
-
'toast.groupNameRequired':'Group name is required',
|
|
2312
|
-
'confirm.rejectUser':'Reject this user?',
|
|
2313
|
-
'confirm.removeGroupMember':'Remove this member from the group?',
|
|
2314
|
-
'confirm.removeMember':'Remove this member?',
|
|
2315
|
-
'confirm.deleteGroup':'Delete group "{name}"? Members will be removed.',
|
|
2316
|
-
'confirm.deleteGroupShort':'Delete group "{name}"?',
|
|
2317
|
-
'confirm.removeTask':'Remove shared task "{name}" from Hub? This cannot be undone.',
|
|
2318
|
-
'confirm.removeSkill':'Remove shared skill "{name}" from Hub? This cannot be undone.',
|
|
2319
|
-
'confirm.removeMemory':'Remove shared memory "{name}" from Hub? This cannot be undone.',
|
|
2320
|
-
'sharing.disabled':'Sharing disabled',
|
|
2321
|
-
'sharing.disabled.hint':'Enable sharing in plugin config to connect a Hub.',
|
|
2322
|
-
'sharing.hubAdmin':'Hub Admin',
|
|
2323
|
-
'sharing.client':'Client',
|
|
2324
|
-
'sharing.hubMode':'Hub mode',
|
|
2325
|
-
'sharing.hubMode.status':'Status: not connected to self',
|
|
2326
|
-
'sharing.hubMode.hint':'Configure sharing.client with hubAddress and userToken pointing to this Hub to enable admin UI.',
|
|
2327
|
-
'sharing.clientConfigured':'Client configured',
|
|
2328
|
-
'sharing.clientDisconnected':'Status: disconnected',
|
|
2329
|
-
'sharing.clientDisconnected.hint':'Viewer will keep showing local data; Hub actions may fail until the connection is restored.',
|
|
2330
|
-
'sharing.clientNotConfigured':'Client not configured',
|
|
2331
|
-
'sharing.clientNotConfigured.hint':'Set hubAddress and userToken in sharing.client to enable team features.',
|
|
2332
|
-
'sharing.settingsDisabled':'Sharing is disabled.',
|
|
2333
|
-
'sharing.settingsDisabled.hint':'Enable sharing in config to use Hub memory and skill collaboration.',
|
|
2334
|
-
'sharing.noTeam':'No team connection.',
|
|
2335
|
-
'sharing.adminUnavailable':'Admin tools unavailable.',
|
|
2336
|
-
'sharing.adminEnabled':'Admin controls enabled',
|
|
2337
|
-
'sharing.adminPendingHint':'Pending users will appear below.',
|
|
2338
|
-
'sharing.notAdmin':'Current user is not an admin.',
|
|
2339
|
-
'sharing.pendingLoadFail':'Failed to load pending users: ',
|
|
2340
|
-
'sharing.noPending':'No pending users.',
|
|
2341
|
-
'sharing.manageGroups':'Manage Groups',
|
|
2342
|
-
'sharing.openAdmin':'Open Admin Panel',
|
|
2343
|
-
'sharing.saveUsername':'Save',
|
|
2344
|
-
'sharing.username.invalid':'Username must be 2-32 characters',
|
|
2345
|
-
'sharing.username.taken':'Username already taken',
|
|
2346
|
-
'sharing.username.updated':'Username updated',
|
|
2347
|
-
'sharing.username.error':'Failed to update username',
|
|
2348
|
-
'sharing.hubNotConfigured':'Hub is running but client connection is not configured.',
|
|
2349
|
-
'sharing.hubNotConfigured.hint':'Add sharing.client.hubAddress and sharing.client.userToken pointing to this Hub to enable the admin interface.',
|
|
2350
|
-
'sharing.notConnected':'Not connected to Hub.',
|
|
2351
|
-
'sharing.role':'Role:',
|
|
2352
|
-
'sharing.mode':'Mode:',
|
|
2353
|
-
'sharing.role.hub':'Server (hosting the Hub)',
|
|
2354
|
-
'sharing.role.client':'Member (connected to Hub)',
|
|
2355
|
-
'sharing.clientConfiguredLabel':'Client configured:',
|
|
2356
|
-
'sharing.configuredHub':'Configured Hub:',
|
|
2357
|
-
'sharing.connected':'Connected:',
|
|
2358
|
-
'sharing.yes':'yes',
|
|
2359
|
-
'sharing.no':'no',
|
|
2360
|
-
'sharing.user':'User:',
|
|
2361
|
-
'sharing.team':'Team:',
|
|
2362
|
-
'sharing.groups':'Groups:',
|
|
2363
|
-
'sharing.loading':'Loading...',
|
|
2364
|
-
'sharing.loadingGroups':'Loading groups...',
|
|
2365
|
-
'sharing.noGroupsYet':'No groups yet.',
|
|
2366
|
-
'search.localResults':'Local Results',
|
|
2367
|
-
'search.hubResults':'Hub Results',
|
|
2368
|
-
'search.noLocal':'No local results.',
|
|
2369
|
-
'search.noHub':'No Hub results.',
|
|
2370
|
-
'search.viewDetail':'View Detail',
|
|
2371
|
-
'search.sharedMemory':'Shared Memory',
|
|
2372
|
-
'search.loadFailed':'Failed to load shared memory',
|
|
2373
|
-
'share.alreadyShared':'Shared',
|
|
2374
|
-
'share.shareBtn':'Share',
|
|
2375
|
-
'share.updateBtn':'Update',
|
|
2376
|
-
'share.unshareBtn':'Unshare',
|
|
2377
|
-
'toast.taskShared':'Task shared',
|
|
2378
|
-
'toast.taskShareFail':'Task share failed',
|
|
2379
|
-
'toast.taskUnshared':'Task unshared',
|
|
2380
|
-
'toast.taskUnshareFail':'Task unshare failed',
|
|
2381
|
-
'toast.memoryShared':'Memory shared',
|
|
2382
|
-
'toast.memoryShareFail':'Memory share failed',
|
|
2383
|
-
'toast.memoryUnshared':'Memory unshared',
|
|
2384
|
-
'toast.memoryUnshareFail':'Memory unshare failed',
|
|
2385
|
-
'toast.skillShared':'Skill shared',
|
|
2386
|
-
'toast.skillShareFail':'Skill share failed',
|
|
2387
|
-
'toast.skillUnshared':'Skill unshared',
|
|
2388
|
-
'toast.skillUnshareFail':'Skill unshare failed',
|
|
2389
|
-
'share.memoryVisibilityPrompt':'Share visibility (public or group):',
|
|
2390
|
-
'share.memoryUnshareConfirm':'Unshare this memory?',
|
|
2391
|
-
'share.group':'Group',
|
|
2392
|
-
'share.public':'Public',
|
|
2393
|
-
'toast.skillPulled':'Skill pulled to local storage',
|
|
2394
|
-
'toast.skillPullFail':'Skill pull failed',
|
|
2395
1677
|
'task.edit':'Edit',
|
|
2396
1678
|
'task.delete':'Delete',
|
|
2397
1679
|
'task.save':'Save',
|
|
@@ -2416,40 +1698,11 @@ const I18N={
|
|
|
2416
1698
|
'update.installing':'Installing...',
|
|
2417
1699
|
'update.success':'Updated!',
|
|
2418
1700
|
'update.failed':'Update failed',
|
|
2419
|
-
'update.restarting':'Restarting service
|
|
2420
|
-
'update.dismiss':'Dismiss'
|
|
2421
|
-
'sharing.disable.confirm.hub':'You are about to shut down the Hub server.\\n\\nWhat will happen:\\n\\u2022 All connected team members will be disconnected\\n\\u2022 They will no longer be able to sync memories, tasks, or skills\\n\\u2022 Shared data is preserved and will be available when you re-enable\\n\\nAre you sure?',
|
|
2422
|
-
'sharing.disable.confirm.client':'You are about to disconnect from the team Hub.\\n\\nWhat will happen:\\n\\u2022 You will no longer receive shared memories, tasks, or skills from the team\\n\\u2022 Your local data is preserved and will not be affected\\n\\u2022 You can reconnect later by re-enabling sharing\\n\\nAre you sure?',
|
|
2423
|
-
'sharing.disable.restartAlert':'Sharing has been disabled. Please restart the OpenClaw gateway for the change to take effect.\\n\\nRun: openclaw gateway stop && openclaw gateway start',
|
|
2424
|
-
'admin.notEnabled.title':'Team sharing is not enabled',
|
|
2425
|
-
'admin.notEnabled.desc':'The Admin Panel is used to manage team members, shared memories, tasks, and skills. To use this feature, you need to enable Hub sharing first.',
|
|
2426
|
-
'admin.notEnabled.setupHub':'Set Up as Hub Server',
|
|
2427
|
-
'admin.notEnabled.joinTeam':'Join an Existing Team',
|
|
2428
|
-
'admin.notEnabled.hint':'If you have previously configured sharing, your data is still preserved. Re-enabling sharing will restore access to all shared content.',
|
|
2429
|
-
'sharing.disconnected.hint':'Unable to reach the Hub server. The Hub may be offline or the network is unavailable.',
|
|
2430
|
-
'sharing.retryConnection':'Retry Connection',
|
|
2431
|
-
'sharing.retryConnection.loading':'Connecting...',
|
|
2432
|
-
'sharing.retryConnection.success':'Connected successfully!',
|
|
2433
|
-
'sharing.retryConnection.fail':'Still unable to connect. Check if the Hub is online.',
|
|
2434
|
-
'guide.title':'Get Started with Team Collaboration',
|
|
2435
|
-
'guide.subtitle':'MemOS supports team memory sharing. Choose one of the following options to enable collaboration, or continue using local-only mode.',
|
|
2436
|
-
'guide.join.title':'Join a Remote Team',
|
|
2437
|
-
'guide.join.desc':'Your team already has a Hub running? Join it to share memories, tasks and skills with team members.',
|
|
2438
|
-
'guide.join.s1':'Ask your Hub admin for the Hub Address and Team Token',
|
|
2439
|
-
'guide.join.s2':'Go to Settings \u2192 Hub & Team, enable sharing, select "Client" mode',
|
|
2440
|
-
'guide.join.s3':'Fill in Hub Address and Team Token, click "Test Connection"',
|
|
2441
|
-
'guide.join.s4':'Save settings and restart the OpenClaw gateway (page refreshes automatically)',
|
|
2442
|
-
'guide.join.btn':'\u2192 Configure Client Mode',
|
|
2443
|
-
'guide.hub.title':'Start Your Own Hub',
|
|
2444
|
-
'guide.hub.desc':'Be the team server. Run a Hub on this device so others can connect and share memories with you.',
|
|
2445
|
-
'guide.hub.s1':'Go to Settings \u2192 Hub & Team, enable sharing, select "Hub" mode',
|
|
2446
|
-
'guide.hub.s2':'Set a team name, save settings, and restart the gateway (page refreshes automatically)',
|
|
2447
|
-
'guide.hub.s3':'Share the Hub Address and Team Token with your team members',
|
|
2448
|
-
'guide.hub.s4':'Approve join requests in the Admin Panel',
|
|
2449
|
-
'guide.hub.btn':'\u2192 Configure Hub Mode'
|
|
1701
|
+
'update.restarting':'Restarting service...',
|
|
1702
|
+
'update.dismiss':'Dismiss'
|
|
2450
1703
|
},
|
|
2451
1704
|
zh:{
|
|
2452
|
-
'title':'
|
|
1705
|
+
'title':'OpenClaw 记忆',
|
|
2453
1706
|
'subtitle':'由 MemOS 驱动',
|
|
2454
1707
|
'setup.desc':'设置密码以保护你的记忆数据',
|
|
2455
1708
|
'setup.pw':'输入密码(至少4位)',
|
|
@@ -2489,14 +1742,6 @@ const I18N={
|
|
|
2489
1742
|
'skills.active':'生效中',
|
|
2490
1743
|
'skills.installed':'已安装',
|
|
2491
1744
|
'skills.public':'公开',
|
|
2492
|
-
'skills.search.placeholder':'搜索技能...',
|
|
2493
|
-
'skills.search.local':'本地',
|
|
2494
|
-
'skills.search.noresult':'未找到匹配的技能',
|
|
2495
|
-
'skills.load.error':'加载技能失败',
|
|
2496
|
-
'skills.hub.title':'\u{1F310} Hub 共享技能',
|
|
2497
|
-
'scope.local':'本地',
|
|
2498
|
-
'scope.group':'团队',
|
|
2499
|
-
'scope.all':'全部',
|
|
2500
1745
|
'skills.visibility.public':'公开',
|
|
2501
1746
|
'skills.visibility.private':'私有',
|
|
2502
1747
|
'skills.setPublic':'设为公开',
|
|
@@ -2535,7 +1780,6 @@ const I18N={
|
|
|
2535
1780
|
'filter.newest':'最新优先',
|
|
2536
1781
|
'filter.oldest':'最早优先',
|
|
2537
1782
|
'filter.allowners':'所有归属',
|
|
2538
|
-
'filter.allsessions':'全部会话',
|
|
2539
1783
|
'filter.public':'公开',
|
|
2540
1784
|
'filter.private':'私有',
|
|
2541
1785
|
'filter.allvisibility':'所有可见性',
|
|
@@ -2616,22 +1860,11 @@ const I18N={
|
|
|
2616
1860
|
'tab.import':'\u{1F4E5} 导入',
|
|
2617
1861
|
'tab.settings':'\u2699 设置',
|
|
2618
1862
|
'settings.modelconfig':'模型配置',
|
|
2619
|
-
'settings.models':'AI 模型',
|
|
2620
|
-
'settings.models.desc':'配置嵌入模型、摘要模型和技能进化模型',
|
|
2621
1863
|
'settings.modelhealth':'模型健康',
|
|
2622
1864
|
'settings.embedding':'嵌入模型',
|
|
2623
1865
|
'settings.summarizer':'摘要模型',
|
|
2624
1866
|
'settings.skill':'技能进化',
|
|
2625
1867
|
'settings.general':'通用设置',
|
|
2626
|
-
'settings.embedding.desc':'向量嵌入模型,用于记忆检索和语义搜索',
|
|
2627
|
-
'settings.summarizer.desc':'大语言模型,用于记忆摘要、去重和分析',
|
|
2628
|
-
'settings.skill.desc':'从对话模式中自动提取可复用的技能',
|
|
2629
|
-
'settings.hub.desc':'与团队共享记忆、任务和技能',
|
|
2630
|
-
'settings.general.desc':'系统状态、端口和数据统计',
|
|
2631
|
-
'settings.hostproxy.embedding':'复用网关模型',
|
|
2632
|
-
'settings.hostproxy.completion':'复用网关模型',
|
|
2633
|
-
'settings.hostproxy.skill':'复用网关模型',
|
|
2634
|
-
'settings.hostproxy.hint.short':'复用网关已有的模型配置',
|
|
2635
1868
|
'settings.provider':'服务商',
|
|
2636
1869
|
'settings.model':'模型',
|
|
2637
1870
|
'settings.temperature':'温度',
|
|
@@ -2640,12 +1873,12 @@ const I18N={
|
|
|
2640
1873
|
'settings.skill.confidence':'最低置信度',
|
|
2641
1874
|
'settings.skill.minchunks':'最少记忆片段',
|
|
2642
1875
|
'settings.skill.model':'技能专用模型',
|
|
2643
|
-
'settings.skill.model.hint':'
|
|
1876
|
+
'settings.skill.model.hint':'不配置时默认使用上方的摘要模型进行技能生成。如需更高质量的技能输出,可在此单独配置一个更强的模型。',
|
|
2644
1877
|
'settings.optional':'可选',
|
|
2645
1878
|
'settings.skill.usemain':'使用主摘要模型',
|
|
2646
1879
|
'settings.telemetry':'数据统计',
|
|
2647
1880
|
'settings.telemetry.enabled':'启用匿名数据统计',
|
|
2648
|
-
'settings.telemetry.hint':'
|
|
1881
|
+
'settings.telemetry.hint':'匿名使用统计,帮助改进插件。仅发送工具名称、响应时间和版本信息,不会发送任何记忆内容、搜索查询或个人数据。',
|
|
2649
1882
|
'settings.viewerport':'Viewer 端口',
|
|
2650
1883
|
'settings.viewerport.hint':'修改后需重启网关生效',
|
|
2651
1884
|
'settings.test':'测试连接',
|
|
@@ -2657,8 +1890,6 @@ const I18N={
|
|
|
2657
1890
|
'settings.reset':'重置',
|
|
2658
1891
|
'settings.saved':'已保存',
|
|
2659
1892
|
'settings.restart.hint':'部分设置修改后需要重启 OpenClaw 网关才能生效。',
|
|
2660
|
-
'settings.restart.autoRefresh':'网关重启后页面将自动刷新...',
|
|
2661
|
-
'settings.restart.waiting':'配置已保存,正在等待网关重启...',
|
|
2662
1893
|
'settings.save.fail':'保存设置失败',
|
|
2663
1894
|
'settings.save.emb.required':'嵌入模型为必填项,请先配置嵌入模型再保存。',
|
|
2664
1895
|
'settings.save.emb.fail':'嵌入模型测试失败,无法保存',
|
|
@@ -2744,7 +1975,7 @@ const I18N={
|
|
|
2744
1975
|
'skills.related':'关联任务',
|
|
2745
1976
|
'skills.download':'\u2B07 下载',
|
|
2746
1977
|
'skills.installed.badge':'已安装',
|
|
2747
|
-
'skills.empty':'
|
|
1978
|
+
'skills.empty':'暂无技能。技能会从已完成的、包含可复用经验的任务中自动生成。',
|
|
2748
1979
|
'skills.loading':'加载中...',
|
|
2749
1980
|
'skills.error':'加载技能失败',
|
|
2750
1981
|
'skills.error.detail':'加载技能失败:',
|
|
@@ -2765,222 +1996,6 @@ const I18N={
|
|
|
2765
1996
|
'tasks.error':'出错了',
|
|
2766
1997
|
'tasks.error.detail':'加载任务详情失败',
|
|
2767
1998
|
'tasks.untitled.related':'未命名',
|
|
2768
|
-
'tab.admin':'\u{1F6E1} 管理',
|
|
2769
|
-
'settings.hub':'Hub 与团队',
|
|
2770
|
-
'settings.hub.enable':'启用 Hub 共享',
|
|
2771
|
-
'settings.hub.enable.hint':'关闭时仅本地使用,不影响其他功能。',
|
|
2772
|
-
'settings.hub.enable.label':'启用 Hub 共享',
|
|
2773
|
-
'settings.hub.role':'角色',
|
|
2774
|
-
'settings.hub.role.hub':'Hub(服务端)',
|
|
2775
|
-
'settings.hub.role.client':'Client(连接到 Hub)',
|
|
2776
|
-
'settings.hub.role.hint':'Hub = 本机做服务端;Client = 连接别人的服务端。两种模式互斥,不能同时使用。',
|
|
2777
|
-
'settings.hub.port':'Hub 端口',
|
|
2778
|
-
'settings.hub.port.hint':'Hub 服务端口,默认 18800',
|
|
2779
|
-
'settings.hub.teamName':'团队名称',
|
|
2780
|
-
'settings.hub.teamName.hint':'你的团队显示名称',
|
|
2781
|
-
'settings.hub.teamToken':'团队令牌',
|
|
2782
|
-
'settings.hub.teamToken.hint':'自动生成的密钥,点击可复制。请将此令牌分享给团队成员。',
|
|
2783
|
-
'settings.hub.tokenCopied':'团队令牌已复制!',
|
|
2784
|
-
'settings.hub.hubSteps.title':'快速配置(3 步)',
|
|
2785
|
-
'settings.hub.hubSteps.s1':'填写下方团队名称(或保持默认)',
|
|
2786
|
-
'settings.hub.hubSteps.s2':'点击"保存设置",然后重启 OpenClaw 网关',
|
|
2787
|
-
'settings.hub.hubSteps.s3':'将下方的 Hub 地址和团队令牌分享给团队成员',
|
|
2788
|
-
'settings.hub.clientSteps.title':'快速配置(3 步)',
|
|
2789
|
-
'settings.hub.clientSteps.s1':'向 Hub 管理员获取 Hub 地址和团队令牌',
|
|
2790
|
-
'settings.hub.clientSteps.s2':'填入下方,点击"测试连接"验证连通性',
|
|
2791
|
-
'settings.hub.clientSteps.s3':'点击「保存设置」,然后重启 OpenClaw 网关(页面会自动刷新)',
|
|
2792
|
-
'settings.hub.shareInfo.title':'请将以下信息分享给团队成员:',
|
|
2793
|
-
'settings.hub.shareInfo.yourIP':'你的IP',
|
|
2794
|
-
'settings.hub.shareInfo.clickCopy':'点击复制',
|
|
2795
|
-
'settings.hub.restartAlert':'Hub 共享配置已保存!请重启 OpenClaw 网关使配置生效。\\n\\n执行命令:openclaw gateway stop && openclaw gateway start',
|
|
2796
|
-
'settings.hub.hubAddress':'Hub 地址',
|
|
2797
|
-
'settings.hub.hubAddress.hint':'Hub 服务器地址,如 192.168.1.100:18800',
|
|
2798
|
-
'settings.hub.teamTokenClient':'团队令牌',
|
|
2799
|
-
'settings.hub.teamTokenClient.hint':'向 Hub 管理员获取此令牌以加入团队',
|
|
2800
|
-
'settings.hub.userToken':'用户令牌',
|
|
2801
|
-
'settings.hub.userToken.hint':'通常在加入团队后自动获取,无需手动填写。',
|
|
2802
|
-
'settings.hub.testConnection':'测试连接',
|
|
2803
|
-
'settings.hub.test.noAddr':'请先输入 Hub 地址',
|
|
2804
|
-
'settings.hub.test.testing':'测试中...',
|
|
2805
|
-
'settings.hub.test.ok':'连接成功',
|
|
2806
|
-
'settings.hub.test.fail':'连接失败',
|
|
2807
|
-
'settings.hub.connection':'连接状态',
|
|
2808
|
-
'settings.hub.team':'团队与分组',
|
|
2809
|
-
'settings.hub.adminPending':'管理员待审用户',
|
|
2810
|
-
'sidebar.hub':'\u{1F310} 团队共享',
|
|
2811
|
-
'sharing.sidebar.connected':'已连接',
|
|
2812
|
-
'sharing.sidebar.disconnected':'已断开',
|
|
2813
|
-
'sharing.sidebar.pending':'等待审核',
|
|
2814
|
-
'sharing.sidebar.rejected':'已拒绝',
|
|
2815
|
-
'sharing.sidebar.starting':'启动中...',
|
|
2816
|
-
'sharing.sidebar.notConfigured':'未配置',
|
|
2817
|
-
'sharing.sidebar.identity':'身份:',
|
|
2818
|
-
'sharing.sidebar.admin':'管理员',
|
|
2819
|
-
'sharing.sidebar.targetHub':'目标 Hub:',
|
|
2820
|
-
'sharing.pendingApproval.hint':'加入申请已提交,请等待 Hub 管理员审核通过。',
|
|
2821
|
-
'sharing.rejected.hint':'您的加入申请已被 Hub 管理员拒绝,请联系管理员或重新申请。',
|
|
2822
|
-
'sharing.retryJoin':'重新申请',
|
|
2823
|
-
'sharing.retryJoin.hint':'清除本地连接数据并重新提交加入申请',
|
|
2824
|
-
'sharing.retryJoin.confirm':'这将清除当前连接数据并重新提交加入申请,是否继续?',
|
|
2825
|
-
'sharing.retryJoin.success':'加入申请已重新提交,请等待管理员审核。',
|
|
2826
|
-
'sharing.retryJoin.fail':'重新申请失败',
|
|
2827
|
-
'sharing.cannotJoinSelf':'不能加入自己的 Hub,请输入远程 Hub 地址。',
|
|
2828
|
-
'scope.hub':'Hub',
|
|
2829
|
-
'memory.detail.title':'记忆详情',
|
|
2830
|
-
'memory.detail.loading':'加载中...',
|
|
2831
|
-
'memory.detail.notFound':'未找到该记忆',
|
|
2832
|
-
'memory.detail.copyId':'点击复制 ID',
|
|
2833
|
-
'memory.detail.created':'创建于 ',
|
|
2834
|
-
'memory.detail.updated':'更新于 ',
|
|
2835
|
-
'memory.detail.viewTarget':'查看目标: ',
|
|
2836
|
-
'admin.title':'Hub 管理面板',
|
|
2837
|
-
'admin.subtitle':'管理团队成员和共享资源',
|
|
2838
|
-
'admin.refresh':'\u21BB 刷新',
|
|
2839
|
-
'admin.tab.users':'用户',
|
|
2840
|
-
'admin.tab.groups':'分组',
|
|
2841
|
-
'admin.tab.memories':'共享任务',
|
|
2842
|
-
'admin.tab.skills':'共享技能',
|
|
2843
|
-
'admin.stat.activeUsers':'活跃用户',
|
|
2844
|
-
'admin.stat.pending':'待审核',
|
|
2845
|
-
'admin.stat.groups':'分组',
|
|
2846
|
-
'admin.stat.sharedTasks':'共享任务',
|
|
2847
|
-
'admin.stat.sharedSkills':'共享技能',
|
|
2848
|
-
'admin.stat.sharedMemories':'共享记忆',
|
|
2849
|
-
'admin.pendingApproval':'待审批',
|
|
2850
|
-
'admin.activeUsers':'活跃用户',
|
|
2851
|
-
'admin.noActiveUsers':'暂无活跃用户。',
|
|
2852
|
-
'admin.approve':'批准',
|
|
2853
|
-
'admin.reject':'拒绝',
|
|
2854
|
-
'admin.device':'设备:',
|
|
2855
|
-
'admin.groups':'分组',
|
|
2856
|
-
'admin.newGroup':'+ 新建分组',
|
|
2857
|
-
'admin.groupName':'分组名称',
|
|
2858
|
-
'admin.groupDesc':'描述(可选)',
|
|
2859
|
-
'admin.create':'创建',
|
|
2860
|
-
'admin.cancel':'取消',
|
|
2861
|
-
'admin.delete':'删除',
|
|
2862
|
-
'admin.members':'成员',
|
|
2863
|
-
'admin.noGroups':'暂无分组。',
|
|
2864
|
-
'admin.noMembers':'暂无成员。',
|
|
2865
|
-
'admin.add':'添加',
|
|
2866
|
-
'admin.remove':'移除',
|
|
2867
|
-
'admin.sharedTasks':'共享任务',
|
|
2868
|
-
'admin.noSharedTasks':'Hub 上暂无共享任务。',
|
|
2869
|
-
'admin.owner':'归属:',
|
|
2870
|
-
'admin.group':'分组:',
|
|
2871
|
-
'admin.chunks':'记忆片段:',
|
|
2872
|
-
'admin.updated':'更新于:',
|
|
2873
|
-
'admin.sharedSkills':'共享技能',
|
|
2874
|
-
'admin.noSharedSkills':'Hub 上暂无共享技能。',
|
|
2875
|
-
'admin.sharedMemories':'共享记忆',
|
|
2876
|
-
'admin.noSharedMemories':'Hub 上暂无共享记忆。',
|
|
2877
|
-
'admin.tab.sharedMemories':'共享记忆',
|
|
2878
|
-
'admin.version':'v',
|
|
2879
|
-
'admin.quality':'质量:',
|
|
2880
|
-
'admin.membersCount':'成员({n}):',
|
|
2881
|
-
'admin.noMembersYet':'暂无成员。',
|
|
2882
|
-
'admin.loadFailed':'加载管理数据失败:',
|
|
2883
|
-
'admin.noPermission':'您没有管理员权限,无法访问此面板。',
|
|
2884
|
-
'admin.groupsFailed':'加载分组失败:',
|
|
2885
|
-
'toast.userApproved':'用户已批准',
|
|
2886
|
-
'toast.userRejected':'用户已拒绝',
|
|
2887
|
-
'toast.approveFail':'批准失败',
|
|
2888
|
-
'toast.rejectFail':'拒绝失败',
|
|
2889
|
-
'toast.groupCreated':'分组已创建',
|
|
2890
|
-
'toast.groupDeleted':'分组已删除',
|
|
2891
|
-
'toast.memberAdded':'成员已添加',
|
|
2892
|
-
'toast.memberRemoved':'成员已移除',
|
|
2893
|
-
'toast.taskRemoved':'任务已移除',
|
|
2894
|
-
'toast.skillRemoved':'技能已移除',
|
|
2895
|
-
'toast.memoryRemoved':'记忆已移除',
|
|
2896
|
-
'toast.createFail':'创建失败',
|
|
2897
|
-
'toast.deleteFail':'删除失败',
|
|
2898
|
-
'toast.addFail':'添加失败',
|
|
2899
|
-
'toast.removeFail':'移除失败',
|
|
2900
|
-
'toast.groupNameRequired':'请输入分组名称',
|
|
2901
|
-
'confirm.rejectUser':'确定要拒绝此用户吗?',
|
|
2902
|
-
'confirm.removeGroupMember':'确定要将此成员移出分组吗?',
|
|
2903
|
-
'confirm.removeMember':'确定要移除此成员吗?',
|
|
2904
|
-
'confirm.deleteGroup':'确定要删除分组「{name}」吗?成员将被移除。',
|
|
2905
|
-
'confirm.deleteGroupShort':'确定要删除分组「{name}」吗?',
|
|
2906
|
-
'confirm.removeTask':'确定要从 Hub 移除共享任务「{name}」吗?此操作不可撤销。',
|
|
2907
|
-
'confirm.removeSkill':'确定要从 Hub 移除共享技能「{name}」吗?此操作不可撤销。',
|
|
2908
|
-
'confirm.removeMemory':'确定要从 Hub 移除共享记忆「{name}」吗?此操作不可撤销。',
|
|
2909
|
-
'sharing.disabled':'共享已禁用',
|
|
2910
|
-
'sharing.disabled.hint':'在插件配置中启用共享以连接 Hub。',
|
|
2911
|
-
'sharing.hubAdmin':'Hub 管理员',
|
|
2912
|
-
'sharing.client':'客户端',
|
|
2913
|
-
'sharing.hubMode':'Hub 模式',
|
|
2914
|
-
'sharing.hubMode.status':'状态:未连接到自身',
|
|
2915
|
-
'sharing.hubMode.hint':'配置 sharing.client 的 hubAddress 和 userToken 指向此 Hub 以启用管理界面。',
|
|
2916
|
-
'sharing.clientConfigured':'客户端已配置',
|
|
2917
|
-
'sharing.clientDisconnected':'状态:已断开',
|
|
2918
|
-
'sharing.clientDisconnected.hint':'查看器将继续显示本地数据;Hub 操作可能在连接恢复前失败。',
|
|
2919
|
-
'sharing.clientNotConfigured':'客户端未配置',
|
|
2920
|
-
'sharing.clientNotConfigured.hint':'设置 sharing.client 中的 hubAddress 和 userToken 以启用团队功能。',
|
|
2921
|
-
'sharing.settingsDisabled':'共享已禁用。',
|
|
2922
|
-
'sharing.settingsDisabled.hint':'在配置中启用共享以使用 Hub 记忆和技能协作。',
|
|
2923
|
-
'sharing.noTeam':'无团队连接。',
|
|
2924
|
-
'sharing.adminUnavailable':'管理工具不可用。',
|
|
2925
|
-
'sharing.adminEnabled':'管理控制已启用',
|
|
2926
|
-
'sharing.adminPendingHint':'待审用户将显示在下方。',
|
|
2927
|
-
'sharing.notAdmin':'当前用户不是管理员。',
|
|
2928
|
-
'sharing.pendingLoadFail':'加载待审用户失败:',
|
|
2929
|
-
'sharing.noPending':'暂无待审用户。',
|
|
2930
|
-
'sharing.manageGroups':'管理分组',
|
|
2931
|
-
'sharing.openAdmin':'打开管理面板',
|
|
2932
|
-
'sharing.saveUsername':'保存',
|
|
2933
|
-
'sharing.username.invalid':'用户名需 2-32 个字符',
|
|
2934
|
-
'sharing.username.taken':'用户名已被占用',
|
|
2935
|
-
'sharing.username.updated':'用户名已更新',
|
|
2936
|
-
'sharing.username.error':'更新用户名失败',
|
|
2937
|
-
'sharing.hubNotConfigured':'Hub 正在运行,但客户端连接未配置。',
|
|
2938
|
-
'sharing.hubNotConfigured.hint':'添加 sharing.client.hubAddress 和 sharing.client.userToken 指向此 Hub 以启用管理界面。',
|
|
2939
|
-
'sharing.notConnected':'未连接到 Hub。',
|
|
2940
|
-
'sharing.role':'角色:',
|
|
2941
|
-
'sharing.mode':'身份:',
|
|
2942
|
-
'sharing.role.hub':'服务端(Hub 主机)',
|
|
2943
|
-
'sharing.role.client':'成员(连接到 Hub)',
|
|
2944
|
-
'sharing.clientConfiguredLabel':'客户端已配置:',
|
|
2945
|
-
'sharing.configuredHub':'配置的 Hub:',
|
|
2946
|
-
'sharing.connected':'已连接:',
|
|
2947
|
-
'sharing.yes':'是',
|
|
2948
|
-
'sharing.no':'否',
|
|
2949
|
-
'sharing.user':'用户:',
|
|
2950
|
-
'sharing.team':'团队:',
|
|
2951
|
-
'sharing.groups':'分组:',
|
|
2952
|
-
'sharing.loading':'加载中...',
|
|
2953
|
-
'sharing.loadingGroups':'正在加载分组...',
|
|
2954
|
-
'sharing.noGroupsYet':'暂无分组。',
|
|
2955
|
-
'search.localResults':'本地结果',
|
|
2956
|
-
'search.hubResults':'Hub 结果',
|
|
2957
|
-
'search.noLocal':'无本地结果。',
|
|
2958
|
-
'search.noHub':'无 Hub 结果。',
|
|
2959
|
-
'search.viewDetail':'查看详情',
|
|
2960
|
-
'search.sharedMemory':'共享记忆',
|
|
2961
|
-
'search.loadFailed':'加载共享记忆失败',
|
|
2962
|
-
'share.alreadyShared':'已共享',
|
|
2963
|
-
'share.shareBtn':'共享',
|
|
2964
|
-
'share.updateBtn':'更新共享',
|
|
2965
|
-
'share.unshareBtn':'取消共享',
|
|
2966
|
-
'toast.taskShared':'任务已共享',
|
|
2967
|
-
'toast.taskShareFail':'任务共享失败',
|
|
2968
|
-
'toast.taskUnshared':'任务已取消共享',
|
|
2969
|
-
'toast.taskUnshareFail':'取消共享失败',
|
|
2970
|
-
'toast.memoryShared':'记忆已共享',
|
|
2971
|
-
'toast.memoryShareFail':'记忆共享失败',
|
|
2972
|
-
'toast.memoryUnshared':'记忆已取消共享',
|
|
2973
|
-
'toast.memoryUnshareFail':'记忆取消共享失败',
|
|
2974
|
-
'toast.skillShared':'技能已共享',
|
|
2975
|
-
'toast.skillShareFail':'技能共享失败',
|
|
2976
|
-
'toast.skillUnshared':'技能已取消共享',
|
|
2977
|
-
'toast.skillUnshareFail':'技能取消共享失败',
|
|
2978
|
-
'share.memoryVisibilityPrompt':'共享可见性(public 或 group):',
|
|
2979
|
-
'share.memoryUnshareConfirm':'取消共享此记忆?',
|
|
2980
|
-
'share.group':'团队',
|
|
2981
|
-
'share.public':'公开',
|
|
2982
|
-
'toast.skillPulled':'技能已拉取到本地',
|
|
2983
|
-
'toast.skillPullFail':'技能拉取失败',
|
|
2984
1999
|
'task.edit':'编辑',
|
|
2985
2000
|
'task.delete':'删除',
|
|
2986
2001
|
'task.save':'保存',
|
|
@@ -3005,37 +2020,8 @@ const I18N={
|
|
|
3005
2020
|
'update.installing':'安装中...',
|
|
3006
2021
|
'update.success':'更新完成',
|
|
3007
2022
|
'update.failed':'更新失败',
|
|
3008
|
-
'update.restarting':'
|
|
3009
|
-
'update.dismiss':'关闭'
|
|
3010
|
-
'sharing.disable.confirm.hub':'你即将关闭 Hub 服务。\\n\\n关闭后将会:\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 他们将无法继续同步记忆、任务和技能\\n\\u2022 已共享的数据会保留,重新开启后仍可使用\\n\\n确定要关闭吗?',
|
|
3011
|
-
'sharing.disable.confirm.client':'你即将断开与团队 Hub 的连接。\\n\\n断开后将会:\\n\\u2022 你将无法再接收团队共享的记忆、任务和技能\\n\\u2022 你的本地数据不受影响,会完整保留\\n\\u2022 之后可以随时重新开启共享来恢复连接\\n\\n确定要断开吗?',
|
|
3012
|
-
'sharing.disable.restartAlert':'共享已关闭。请重启 OpenClaw 网关使更改生效。\\n\\n执行命令:openclaw gateway stop && openclaw gateway start',
|
|
3013
|
-
'admin.notEnabled.title':'团队共享尚未开启',
|
|
3014
|
-
'admin.notEnabled.desc':'管理面板用于管理团队成员、共享的记忆、任务和技能。使用此功能前,需要先开启 Hub 共享。',
|
|
3015
|
-
'admin.notEnabled.setupHub':'配置为 Hub 服务端',
|
|
3016
|
-
'admin.notEnabled.joinTeam':'加入已有团队',
|
|
3017
|
-
'admin.notEnabled.hint':'如果之前配置过共享,你的数据仍然保留。重新开启共享即可恢复访问所有共享内容。',
|
|
3018
|
-
'sharing.disconnected.hint':'无法连接到 Hub 服务器,Hub 可能已下线或网络不可用。',
|
|
3019
|
-
'sharing.retryConnection':'重试连接',
|
|
3020
|
-
'sharing.retryConnection.loading':'连接中...',
|
|
3021
|
-
'sharing.retryConnection.success':'连接成功!',
|
|
3022
|
-
'sharing.retryConnection.fail':'仍然无法连接,请检查 Hub 是否在线。',
|
|
3023
|
-
'guide.title':'开始团队协作',
|
|
3024
|
-
'guide.subtitle':'MemOS 支持团队记忆共享。选择以下方式之一开启协作,或继续使用纯本地模式。',
|
|
3025
|
-
'guide.join.title':'加入远程团队',
|
|
3026
|
-
'guide.join.desc':'你的团队已有 Hub 在运行?加入即可与团队成员共享记忆、任务和技能。',
|
|
3027
|
-
'guide.join.s1':'向 Hub 管理员索取 Hub 地址和 Team Token',
|
|
3028
|
-
'guide.join.s2':'前往「设置 → Hub & Team」,开启共享,选择「Client」模式',
|
|
3029
|
-
'guide.join.s3':'填写 Hub 地址和 Team Token,点击「测试连接」',
|
|
3030
|
-
'guide.join.s4':'保存设置并重启 OpenClaw 网关(页面会自动刷新)',
|
|
3031
|
-
'guide.join.btn':'\u2192 配置 Client 模式',
|
|
3032
|
-
'guide.hub.title':'自建 Hub 服务',
|
|
3033
|
-
'guide.hub.desc':'将本机作为团队服务端,让其他成员连接过来共享记忆。',
|
|
3034
|
-
'guide.hub.s1':'前往「设置 → Hub & Team」,开启共享,选择「Hub」模式',
|
|
3035
|
-
'guide.hub.s2':'设置团队名称,保存设置后重启网关(页面会自动刷新)',
|
|
3036
|
-
'guide.hub.s3':'将 Hub 地址和 Team Token 分享给团队成员',
|
|
3037
|
-
'guide.hub.s4':'在管理面板中审批加入请求',
|
|
3038
|
-
'guide.hub.btn':'\u2192 配置 Hub 模式'
|
|
2023
|
+
'update.restarting':'正在重启服务...',
|
|
2024
|
+
'update.dismiss':'关闭'
|
|
3039
2025
|
}
|
|
3040
2026
|
};
|
|
3041
2027
|
const LANG_KEY='memos-viewer-lang';
|
|
@@ -3055,1276 +2041,138 @@ function applyI18n(){
|
|
|
3055
2041
|
});
|
|
3056
2042
|
const step2=document.getElementById('resetStep2Desc');
|
|
3057
2043
|
if(step2) step2.innerHTML=t('reset.step2.desc.pre')+'<span style="font-family:monospace;font-size:12px;color:var(--pri)">password reset token: <strong>a1b2c3d4e5f6...</strong></span>'+t('reset.step2.desc.post');
|
|
3058
|
-
document.title=t('title')+' - MemOS';
|
|
3059
|
-
if(typeof loadStats==='function' && document.getElementById('app').style.display==='flex'){loadStats();}
|
|
3060
|
-
if(document.querySelector('.analytics-view.show') && typeof loadMetrics==='function'){loadMetrics();}
|
|
3061
|
-
}
|
|
3062
|
-
|
|
3063
|
-
/* ─── Auth flow ─── */
|
|
3064
|
-
async function checkAuth(){
|
|
3065
|
-
const r=await fetch('/api/auth/status');
|
|
3066
|
-
const d=await r.json();
|
|
3067
|
-
if(d.needsSetup){
|
|
3068
|
-
document.getElementById('setupScreen').style.display='flex';
|
|
3069
|
-
document.getElementById('setupPw').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('setupPw2').focus()});
|
|
3070
|
-
document.getElementById('setupPw2').addEventListener('keydown',e=>{if(e.key==='Enter')doSetup()});
|
|
3071
|
-
} else if(!d.loggedIn){
|
|
3072
|
-
document.getElementById('loginScreen').style.display='flex';
|
|
3073
|
-
document.getElementById('loginPw').addEventListener('keydown',e=>{if(e.key==='Enter')doLogin()});
|
|
3074
|
-
} else {
|
|
3075
|
-
enterApp();
|
|
3076
|
-
}
|
|
3077
|
-
}
|
|
3078
|
-
|
|
3079
|
-
async function doSetup(){
|
|
3080
|
-
const pw=document.getElementById('setupPw').value;
|
|
3081
|
-
const pw2=document.getElementById('setupPw2').value;
|
|
3082
|
-
const err=document.getElementById('setupErr');
|
|
3083
|
-
if(pw.length<4){err.textContent=t('setup.err.short');return}
|
|
3084
|
-
if(pw!==pw2){err.textContent=t('setup.err.mismatch');return}
|
|
3085
|
-
const r=await fetch('/api/auth/setup',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:pw})});
|
|
3086
|
-
const d=await r.json();
|
|
3087
|
-
if(d.ok){document.getElementById('setupScreen').style.display='none';enterApp();}
|
|
3088
|
-
else{err.textContent=d.error||t('setup.err.fail')}
|
|
3089
|
-
}
|
|
3090
|
-
|
|
3091
|
-
async function doLogin(){
|
|
3092
|
-
const pw=document.getElementById('loginPw').value;
|
|
3093
|
-
const err=document.getElementById('loginErr');
|
|
3094
|
-
const r=await fetch('/api/auth/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:pw})});
|
|
3095
|
-
const d=await r.json();
|
|
3096
|
-
if(d.ok){document.getElementById('loginScreen').style.display='none';enterApp();}
|
|
3097
|
-
else{err.textContent=t('login.err');document.getElementById('loginPw').value='';document.getElementById('loginPw').focus();}
|
|
3098
|
-
}
|
|
3099
|
-
|
|
3100
|
-
async function doLogout(){
|
|
3101
|
-
await fetch('/api/auth/logout',{method:'POST'});
|
|
3102
|
-
location.reload();
|
|
3103
|
-
}
|
|
3104
|
-
|
|
3105
|
-
function showResetForm(){
|
|
3106
|
-
document.getElementById('loginForm').style.display='none';
|
|
3107
|
-
document.getElementById('resetForm').style.display='block';
|
|
3108
|
-
document.getElementById('resetToken').focus();
|
|
3109
|
-
}
|
|
3110
|
-
|
|
3111
|
-
function showLoginForm(){
|
|
3112
|
-
document.getElementById('resetForm').style.display='none';
|
|
3113
|
-
document.getElementById('loginForm').style.display='block';
|
|
3114
|
-
document.getElementById('loginPw').focus();
|
|
3115
|
-
}
|
|
3116
|
-
|
|
3117
|
-
function copyCmd(el){
|
|
3118
|
-
const code=el.querySelector('code').textContent;
|
|
3119
|
-
navigator.clipboard.writeText(code).then(()=>{
|
|
3120
|
-
el.classList.add('copied');
|
|
3121
|
-
el.querySelector('.copy-hint').textContent=t('copy.done');
|
|
3122
|
-
setTimeout(()=>{el.classList.remove('copied');el.querySelector('.copy-hint').textContent=t('copy.hint')},2000);
|
|
3123
|
-
});
|
|
3124
|
-
}
|
|
3125
|
-
|
|
3126
|
-
async function doReset(){
|
|
3127
|
-
const token=document.getElementById('resetToken').value.trim();
|
|
3128
|
-
const pw=document.getElementById('resetNewPw').value;
|
|
3129
|
-
const pw2=document.getElementById('resetNewPw2').value;
|
|
3130
|
-
const err=document.getElementById('resetErr');
|
|
3131
|
-
if(!token){err.textContent=t('reset.err.token');return}
|
|
3132
|
-
if(pw.length<4){err.textContent=t('reset.err.short');return}
|
|
3133
|
-
if(pw!==pw2){err.textContent=t('reset.err.mismatch');return}
|
|
3134
|
-
const r=await fetch('/api/auth/reset',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({token,newPassword:pw})});
|
|
3135
|
-
const d=await r.json();
|
|
3136
|
-
if(d.ok){document.getElementById('loginScreen').style.display='none';enterApp();}
|
|
3137
|
-
else{err.textContent=d.error||t('reset.err.fail')}
|
|
3138
|
-
}
|
|
3139
|
-
|
|
3140
|
-
var _sharingRole='client';
|
|
3141
|
-
function _genToken(len){
|
|
3142
|
-
var a=new Uint8Array(len||18);crypto.getRandomValues(a);
|
|
3143
|
-
return btoa(String.fromCharCode.apply(null,a)).replace(/\\+/g,'-').replace(/\\//g,'_').replace(/=+$/,'');
|
|
3144
|
-
}
|
|
3145
|
-
function onSharingToggle(){
|
|
3146
|
-
var on=document.getElementById('cfgSharingEnabled').checked;
|
|
3147
|
-
document.getElementById('sharingConfigPanel').style.display=on?'block':'none';
|
|
3148
|
-
if(on) selectSharingRole(_sharingRole);
|
|
3149
|
-
}
|
|
3150
|
-
function selectSharingRole(role){
|
|
3151
|
-
_sharingRole=role;
|
|
3152
|
-
document.getElementById('btnRoleHub').className='btn btn-sm'+(role==='hub'?' btn-primary':'');
|
|
3153
|
-
document.getElementById('btnRoleClient').className='btn btn-sm'+(role==='client'?' btn-primary':'');
|
|
3154
|
-
document.getElementById('hubModeConfig').style.display=role==='hub'?'block':'none';
|
|
3155
|
-
document.getElementById('clientModeConfig').style.display=role==='client'?'block':'none';
|
|
3156
|
-
var sp=document.getElementById('sharingStatusPanel');
|
|
3157
|
-
var tp=document.getElementById('sharingTeamPanel');
|
|
3158
|
-
var ap=document.getElementById('sharingAdminPanel');
|
|
3159
|
-
if(role==='client'){
|
|
3160
|
-
if(sp) sp.style.display='none';
|
|
3161
|
-
if(tp) tp.style.display='none';
|
|
3162
|
-
if(ap) ap.style.display='none';
|
|
3163
|
-
}else{
|
|
3164
|
-
if(sp) sp.style.display='';
|
|
3165
|
-
if(tp) tp.style.display='';
|
|
3166
|
-
if(ap) ap.style.display='';
|
|
3167
|
-
}
|
|
3168
|
-
if(role==='hub'){
|
|
3169
|
-
var tk=document.getElementById('cfgHubTeamToken');
|
|
3170
|
-
if(!tk.value.trim()) tk.value=_genToken(18);
|
|
3171
|
-
var tn=document.getElementById('cfgHubTeamName');
|
|
3172
|
-
if(!tn.value.trim()) tn.value='My Team';
|
|
3173
|
-
}
|
|
3174
|
-
}
|
|
3175
|
-
var _cachedLocalIP='';
|
|
3176
|
-
function updateHubShareInfo(){
|
|
3177
|
-
var panel=document.getElementById('hubShareInfo');
|
|
3178
|
-
var content=document.getElementById('hubShareInfoContent');
|
|
3179
|
-
if(!panel||!content) return;
|
|
3180
|
-
var tokenEl=document.getElementById('cfgHubTeamToken');
|
|
3181
|
-
var token=tokenEl?tokenEl.value.trim():'';
|
|
3182
|
-
var port=document.getElementById('cfgHubPort').value.trim()||'18800';
|
|
3183
|
-
if(!token||_sharingRole!=='hub'){panel.style.display='none';return;}
|
|
3184
|
-
panel.style.display='block';
|
|
3185
|
-
var cpStyle='cursor:pointer;background:rgba(99,102,241,.06);border:1px solid rgba(99,102,241,.15);border-radius:6px;padding:4px 10px;font-family:var(--mono);font-size:12px;color:var(--text);transition:all .15s;user-select:all';
|
|
3186
|
-
var renderShare=function(ip){
|
|
3187
|
-
var addr=ip?(ip+':'+esc(port)):('<'+t('settings.hub.shareInfo.yourIP')+'>:'+esc(port));
|
|
3188
|
-
var tip=t('settings.hub.shareInfo.clickCopy');
|
|
3189
|
-
content.innerHTML=
|
|
3190
|
-
'<span style="font-size:11px;color:var(--text-muted);font-weight:500">Hub '+t('settings.hub.hubAddress')+'</span>'+
|
|
3191
|
-
'<span style="'+cpStyle+'" onclick="navigator.clipboard.writeText(this.textContent);toast('Copied!','success')" title="'+tip+'">'+addr+'</span>'+
|
|
3192
|
-
'<span style="font-size:11px;color:var(--text-muted);font-weight:500">Team Token</span>'+
|
|
3193
|
-
'<span style="'+cpStyle+'" onclick="navigator.clipboard.writeText(this.textContent);toast('Copied!','success')" title="'+tip+'">'+esc(token)+'</span>';
|
|
3194
|
-
};
|
|
3195
|
-
if(_cachedLocalIP){renderShare(_cachedLocalIP);return;}
|
|
3196
|
-
renderShare('');
|
|
3197
|
-
fetch('/api/local-ips').then(function(r){return r.json()}).then(function(d){
|
|
3198
|
-
if(d.ips&&d.ips.length>0){_cachedLocalIP=d.ips[0];renderShare(_cachedLocalIP);}
|
|
3199
|
-
}).catch(function(){});
|
|
3200
|
-
}
|
|
3201
|
-
async function testHubConnection(){
|
|
3202
|
-
var btn=document.getElementById('btnTestHubConn');
|
|
3203
|
-
var result=document.getElementById('hubConnTestResult');
|
|
3204
|
-
var addr=document.getElementById('cfgClientHubAddress').value.trim();
|
|
3205
|
-
if(!addr){result.innerHTML='<span style="color:var(--rose)">\u274C '+t('settings.hub.test.noAddr')+'</span>';return;}
|
|
3206
|
-
btn.disabled=true;result.innerHTML=t('settings.hub.test.testing');
|
|
3207
|
-
try{
|
|
3208
|
-
var ipsData=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
3209
|
-
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ipsData.ips||[]);
|
|
3210
|
-
var parsed=new URL(addr.indexOf('://')>-1?addr:'http://'+addr);
|
|
3211
|
-
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
3212
|
-
result.innerHTML='<span style="color:var(--rose)">\u274C '+t('sharing.cannotJoinSelf')+'</span>';
|
|
3213
|
-
btn.disabled=false;return;
|
|
3214
|
-
}
|
|
3215
|
-
}catch(e){}
|
|
3216
|
-
try{
|
|
3217
|
-
var url=addr.match(/^https?:\\/\\//)?addr:'http://'+addr;
|
|
3218
|
-
url=url.replace(/\\/+$/,'');
|
|
3219
|
-
var r=await fetch('/api/sharing/test-hub',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({hubUrl:url})});
|
|
3220
|
-
var d=await r.json();
|
|
3221
|
-
if(d.ok){
|
|
3222
|
-
result.innerHTML='<span style="color:var(--green)">\u2705 '+t('settings.hub.test.ok')+(d.teamName?' — '+esc(d.teamName):'')+'</span>';
|
|
3223
|
-
}else{
|
|
3224
|
-
var errMsg=d.error==='cannot_join_self'?t('sharing.cannotJoinSelf'):(d.error||t('settings.hub.test.fail'));
|
|
3225
|
-
result.innerHTML='<span style="color:var(--rose)">\u274C '+errMsg+'</span>';
|
|
3226
|
-
}
|
|
3227
|
-
}catch(e){
|
|
3228
|
-
result.innerHTML='<span style="color:var(--rose)">\u274C '+esc(String(e))+'</span>';
|
|
3229
|
-
}finally{btn.disabled=false;}
|
|
3230
|
-
}
|
|
3231
|
-
|
|
3232
|
-
function enterApp(){
|
|
3233
|
-
document.getElementById('app').style.display='flex';
|
|
3234
|
-
loadAll();
|
|
3235
|
-
}
|
|
3236
|
-
|
|
3237
|
-
function switchSettingsTab(tab,btn){
|
|
3238
|
-
document.querySelectorAll('.settings-tab-btn').forEach(function(b){b.classList.remove('active')});
|
|
3239
|
-
if(btn){btn.classList.add('active')}
|
|
3240
|
-
else{var b=document.querySelector('.settings-tab-btn[data-tab="'+tab+'"]');if(b)b.classList.add('active')}
|
|
3241
|
-
document.querySelectorAll('.settings-card[data-stab]').forEach(function(c){
|
|
3242
|
-
if(c.dataset.stab===tab){c.classList.add('stab-active')}else{c.classList.remove('stab-active')}
|
|
3243
|
-
});
|
|
3244
|
-
}
|
|
3245
|
-
|
|
3246
|
-
function switchView(view){
|
|
3247
|
-
document.querySelectorAll('.nav-tabs .tab').forEach(t=>t.classList.toggle('active',t.dataset.view===view));
|
|
3248
|
-
const feedWrap=document.getElementById('feedWrap');
|
|
3249
|
-
const analyticsView=document.getElementById('analyticsView');
|
|
3250
|
-
const tasksView=document.getElementById('tasksView');
|
|
3251
|
-
const skillsView=document.getElementById('skillsView');
|
|
3252
|
-
const logsView=document.getElementById('logsView');
|
|
3253
|
-
const settingsView=document.getElementById('settingsView');
|
|
3254
|
-
const migrateView=document.getElementById('migrateView');
|
|
3255
|
-
const adminView=document.getElementById('adminView');
|
|
3256
|
-
const sidebar=document.getElementById('sidebar');
|
|
3257
|
-
feedWrap.classList.add('hide');
|
|
3258
|
-
analyticsView.classList.remove('show');
|
|
3259
|
-
tasksView.classList.remove('show');
|
|
3260
|
-
skillsView.classList.remove('show');
|
|
3261
|
-
logsView.classList.remove('show');
|
|
3262
|
-
settingsView.classList.remove('show');
|
|
3263
|
-
migrateView.classList.remove('show');
|
|
3264
|
-
if(adminView) adminView.classList.remove('show');
|
|
3265
|
-
var sessionSection=document.getElementById('sidebarSessionSection');
|
|
3266
|
-
if(view==='memories'){
|
|
3267
|
-
feedWrap.classList.remove('hide');
|
|
3268
|
-
if(sessionSection){sessionSection.style.visibility='';sessionSection.style.pointerEvents='';}
|
|
3269
|
-
} else if(view==='tasks'||view==='skills'){
|
|
3270
|
-
if(sessionSection){sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3271
|
-
if(view==='tasks'){tasksView.classList.add('show');loadTasks();}
|
|
3272
|
-
else{skillsView.classList.add('show');loadSkills();}
|
|
3273
|
-
} else {
|
|
3274
|
-
if(sessionSection){sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3275
|
-
if(view==='analytics'){
|
|
3276
|
-
analyticsView.classList.add('show');
|
|
3277
|
-
loadMetrics();
|
|
3278
|
-
} else if(view==='logs'){
|
|
3279
|
-
logsView.classList.add('show');
|
|
3280
|
-
loadLogs();
|
|
3281
|
-
} else if(view==='settings'){
|
|
3282
|
-
settingsView.classList.add('show');
|
|
3283
|
-
loadConfig();
|
|
3284
|
-
loadModelHealth();
|
|
3285
|
-
} else if(view==='import'){
|
|
3286
|
-
migrateView.classList.add('show');
|
|
3287
|
-
if(!window._migrateRunning) migrateScan(false);
|
|
3288
|
-
} else if(view==='admin'){
|
|
3289
|
-
if(adminView){adminView.classList.add('show');loadAdminData();}
|
|
3290
|
-
}
|
|
3291
|
-
}
|
|
3292
|
-
}
|
|
3293
|
-
|
|
3294
|
-
function onMemoryScopeChange(){
|
|
3295
|
-
memorySearchScope=document.getElementById('memorySearchScope')?.value||'local';
|
|
3296
|
-
if(document.getElementById('searchInput').value.trim()) doSearch(document.getElementById('searchInput').value);
|
|
3297
|
-
else if(memorySearchScope!=='local') { document.getElementById('sharingSearchMeta').textContent=''; loadHubMemories(); }
|
|
3298
|
-
else { document.getElementById('sharingSearchMeta').textContent=''; loadMemories(); }
|
|
3299
|
-
}
|
|
3300
|
-
|
|
3301
|
-
function onSkillScopeChange(){
|
|
3302
|
-
skillSearchScope=document.getElementById('skillSearchScope')?.value||'local';
|
|
3303
|
-
loadSkills();
|
|
3304
|
-
}
|
|
3305
|
-
|
|
3306
|
-
function onTaskScopeChange(){
|
|
3307
|
-
taskSearchScope=document.getElementById('taskSearchScope')?.value||'local';
|
|
3308
|
-
tasksPage=0;
|
|
3309
|
-
loadTasks();
|
|
3310
|
-
}
|
|
3311
|
-
|
|
3312
|
-
async function loadSharingStatus(forcePending){
|
|
3313
|
-
try{
|
|
3314
|
-
const r=await fetch('/api/sharing/status');
|
|
3315
|
-
const d=await r.json();
|
|
3316
|
-
sharingStatusCache=d;
|
|
3317
|
-
renderSharingSidebar(d);
|
|
3318
|
-
renderSharingSettings(d);
|
|
3319
|
-
updateTeamGuide(d);
|
|
3320
|
-
if(forcePending && d && d.admin && d.admin.canManageUsers) loadSharingPendingUsers();
|
|
3321
|
-
}catch(e){
|
|
3322
|
-
renderSharingSidebar(null);
|
|
3323
|
-
renderSharingSettings(null);
|
|
3324
|
-
updateTeamGuide(null);
|
|
3325
|
-
}
|
|
3326
|
-
}
|
|
3327
|
-
|
|
3328
|
-
function renderSharingSidebar(data){
|
|
3329
|
-
var section=document.getElementById('sidebarSharingSection');
|
|
3330
|
-
var statusEl=document.getElementById('sharingSidebarStatus');
|
|
3331
|
-
var hintEl=document.getElementById('sharingSidebarHint');
|
|
3332
|
-
var badgeEl=document.getElementById('sharingSidebarConnBadge');
|
|
3333
|
-
if(!statusEl||!hintEl) return;
|
|
3334
|
-
if(!data||!data.enabled){
|
|
3335
|
-
if(section) section.style.display='none';
|
|
3336
|
-
window._isHubAdmin=false;
|
|
3337
|
-
return;
|
|
3338
|
-
}
|
|
3339
|
-
if(section) section.style.display='block';
|
|
3340
|
-
var conn=data.connection||{};
|
|
3341
|
-
function setBadge(color,text,glow){
|
|
3342
|
-
if(!badgeEl)return;
|
|
3343
|
-
badgeEl.innerHTML='<span style="display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:600;padding:2px 8px;border-radius:9999px;background:'+color+'15;color:'+color+'"><span style="display:inline-block;width:6px;height:6px;border-radius:50%;background:'+color+(glow?';box-shadow:0 0 4px '+color:'')+'"></span>'+esc(text)+'</span>';
|
|
3344
|
-
}
|
|
3345
|
-
if(data.role==='hub'){
|
|
3346
|
-
setBadge('#34d399',t('sharing.sidebar.connected'),true);
|
|
3347
|
-
statusEl.innerHTML='';
|
|
3348
|
-
hintEl.textContent='';
|
|
3349
|
-
}else if(conn.pendingApproval&&conn.user){
|
|
3350
|
-
setBadge('#fbbf24',t('sharing.sidebar.pending'),false);
|
|
3351
|
-
var html='<div class="info-grid">';
|
|
3352
|
-
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username)+'</span>';
|
|
3353
|
-
if(conn.teamName) html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName)+'</span>';
|
|
3354
|
-
html+='</div>';
|
|
3355
|
-
statusEl.innerHTML=html;
|
|
3356
|
-
hintEl.textContent=t('sharing.pendingApproval.hint');
|
|
3357
|
-
}else if(conn.rejected&&conn.user){
|
|
3358
|
-
setBadge('#ef4444',t('sharing.sidebar.rejected'),false);
|
|
3359
|
-
var html='<div class="info-grid">';
|
|
3360
|
-
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username||'-')+'</span>';
|
|
3361
|
-
if(conn.teamName) html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName)+'</span>';
|
|
3362
|
-
html+='</div>';
|
|
3363
|
-
statusEl.innerHTML=html;
|
|
3364
|
-
hintEl.textContent=t('sharing.rejected.hint');
|
|
3365
|
-
}else if(conn.connected&&conn.user){
|
|
3366
|
-
var isAdmin=conn.user.role==='admin';
|
|
3367
|
-
setBadge('#34d399',t('sharing.sidebar.connected'),true);
|
|
3368
|
-
var html='<div class="info-grid">';
|
|
3369
|
-
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username)+(isAdmin?' <span class="role-badge admin">'+t('sharing.sidebar.admin')+'</span>':'')+'</span>';
|
|
3370
|
-
html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName||'-')+'</span>';
|
|
3371
|
-
html+='</div>';
|
|
3372
|
-
statusEl.innerHTML=html;
|
|
3373
|
-
hintEl.innerHTML='';
|
|
3374
|
-
}else if(data.clientConfigured){
|
|
3375
|
-
setBadge('#ef4444',t('sharing.sidebar.disconnected'),false);
|
|
3376
|
-
statusEl.innerHTML='<div style="font-size:11px;color:var(--text-muted)">'+t('sharing.sidebar.targetHub')+' '+esc(data.hubUrl||'')+'</div>';
|
|
3377
|
-
hintEl.innerHTML=esc(t('sharing.clientDisconnected.hint'))+'<br><a href="#" onclick="retryConnection();return false;" style="color:var(--pri);font-size:11px;text-decoration:none">'+t('sharing.retryConnection')+'</a>';
|
|
3378
|
-
}else{
|
|
3379
|
-
setBadge('#888',t('sharing.sidebar.notConfigured'),false);
|
|
3380
|
-
statusEl.innerHTML='';
|
|
3381
|
-
hintEl.textContent=t('sharing.clientNotConfigured.hint');
|
|
3382
|
-
}
|
|
3383
|
-
}
|
|
3384
|
-
|
|
3385
|
-
function renderSharingSettings(data){
|
|
3386
|
-
var statusEl=document.getElementById('sharingStatusPanel');
|
|
3387
|
-
var teamEl=document.getElementById('sharingTeamPanel');
|
|
3388
|
-
var adminEl=document.getElementById('sharingAdminPanel');
|
|
3389
|
-
var panelsWrap=document.getElementById('sharingPanelsWrap');
|
|
3390
|
-
if(!statusEl||!teamEl||!adminEl) return;
|
|
3391
|
-
if(!data||!data.enabled){
|
|
3392
|
-
statusEl.innerHTML='';teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3393
|
-
if(panelsWrap) panelsWrap.style.display='none';
|
|
3394
|
-
return;
|
|
3395
|
-
}
|
|
3396
|
-
if(panelsWrap) panelsWrap.style.display='';
|
|
3397
|
-
var conn=data.connection||{};
|
|
3398
|
-
var user=conn.user||{};
|
|
3399
|
-
var actualRole=data.role||_sharingRole||'client';
|
|
3400
|
-
if(data.role) _sharingRole=data.role;
|
|
3401
|
-
var isAdmin=(data.admin&&data.admin.canManageUsers)||(conn.connected&&user.role==='admin')||(actualRole==='hub');
|
|
3402
|
-
window._isHubAdmin=isAdmin;
|
|
3403
|
-
var hubAdminBtn=document.getElementById('hubAdminEntryBtn');
|
|
3404
|
-
|
|
3405
|
-
if(actualRole==='hub'){
|
|
3406
|
-
statusEl.innerHTML='';teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3407
|
-
if(hubAdminBtn) hubAdminBtn.style.display=isAdmin?'':'none';
|
|
3408
|
-
return;
|
|
3409
|
-
}
|
|
3410
|
-
|
|
3411
|
-
if(actualRole==='client'){
|
|
3412
|
-
statusEl.style.display='none';teamEl.style.display='none';adminEl.style.display='none';
|
|
3413
|
-
if(hubAdminBtn) hubAdminBtn.style.display='none';
|
|
3414
|
-
|
|
3415
|
-
var connBadge;
|
|
3416
|
-
if(conn.pendingApproval){
|
|
3417
|
-
connBadge='<span class="hic-badge pending"><span class="hic-dot amber"></span>'+t('sharing.sidebar.pending')+'</span>';
|
|
3418
|
-
}else if(conn.rejected){
|
|
3419
|
-
connBadge='<span class="hic-badge disconnected"><span class="hic-dot red"></span>'+t('sharing.sidebar.rejected')+'</span>';
|
|
3420
|
-
}else if(conn.connected){
|
|
3421
|
-
connBadge='<span class="hic-badge connected"><span class="hic-dot green"></span>'+t('sharing.sidebar.connected')+'</span>';
|
|
3422
|
-
}else{
|
|
3423
|
-
connBadge='<span class="hic-badge disconnected"><span class="hic-dot red"></span>'+t('sharing.sidebar.disconnected')+'</span>';
|
|
3424
|
-
}
|
|
3425
|
-
statusEl.style.display='';
|
|
3426
|
-
var sh='<div class="hub-info-card hic-status"><div class="hic-title"><span class="hic-icon">\u{1F517}</span>'+t('settings.hub.connection')+' '+connBadge+'</div><div class="hic-grid">';
|
|
3427
|
-
if(conn.pendingApproval&&user.username){
|
|
3428
|
-
sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value">'+esc(user.username)+'</span>';
|
|
3429
|
-
sh+='</div><div class="hic-empty" style="color:#f59e0b">'+t('sharing.pendingApproval.hint')+'</div></div>';
|
|
3430
|
-
}else if(conn.rejected){
|
|
3431
|
-
if(user.username) sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value">'+esc(user.username)+'</span>';
|
|
3432
|
-
sh+='</div><div class="hic-empty" style="color:#ef4444">'+t('sharing.rejected.hint')+'</div>'+
|
|
3433
|
-
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" onclick="retryHubJoin()">'+t('sharing.retryJoin')+'</button>'+
|
|
3434
|
-
'<span style="font-size:11px;color:var(--text-muted);margin-left:8px">'+t('sharing.retryJoin.hint')+'</span></div></div>';
|
|
3435
|
-
}else if(conn.connected&&user.username){
|
|
3436
|
-
sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value" style="display:flex;align-items:center;gap:6px">'+
|
|
3437
|
-
'<input type="text" id="hubUsernameInput" value="'+esc(user.username)+'" style="border:1px solid var(--border);border-radius:6px;padding:3px 8px;font-size:12px;background:var(--bg);color:var(--text);width:120px;font-family:inherit" />'+
|
|
3438
|
-
'<button class="btn btn-sm" onclick="updateHubUsername()" style="padding:2px 10px;font-size:11px">'+t('sharing.saveUsername')+'</button>'+
|
|
3439
|
-
'</span>';
|
|
3440
|
-
sh+='<span class="hic-label">'+t('sharing.team')+'</span><span class="hic-value">'+esc(conn.teamName||'-')+'</span>';
|
|
3441
|
-
sh+='</div></div>';
|
|
3442
|
-
}else{
|
|
3443
|
-
sh+='</div><div class="hic-empty" style="color:var(--text-muted)">'+t('sharing.disconnected.hint')+'</div>'+
|
|
3444
|
-
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" id="btnRetryConn" onclick="retryConnection()">'+t('sharing.retryConnection')+'</button>'+
|
|
3445
|
-
'<span id="retryConnResult" style="margin-left:10px;font-size:11px"></span></div></div>';
|
|
3446
|
-
}
|
|
3447
|
-
statusEl.innerHTML=sh;
|
|
3448
|
-
teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3449
|
-
return;
|
|
3450
|
-
}
|
|
3451
|
-
|
|
3452
|
-
statusEl.innerHTML='';teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3453
|
-
}
|
|
3454
|
-
|
|
3455
|
-
async function retryConnection(){
|
|
3456
|
-
var btn=document.getElementById('btnRetryConn');
|
|
3457
|
-
var result=document.getElementById('retryConnResult');
|
|
3458
|
-
if(btn){btn.disabled=true;btn.textContent=t('sharing.retryConnection.loading');}
|
|
3459
|
-
if(result) result.innerHTML='<span style="color:var(--text-muted)">'+t('sharing.retryConnection.loading')+'</span>';
|
|
3460
|
-
try{
|
|
3461
|
-
await loadSharingStatus(false);
|
|
3462
|
-
var d=sharingStatusCache;
|
|
3463
|
-
if(d&&d.connection&&d.connection.connected){
|
|
3464
|
-
toast(t('sharing.retryConnection.success'),'success');
|
|
3465
|
-
if(result) result.innerHTML='<span style="color:#22c55e">\\u2705 '+t('sharing.retryConnection.success')+'</span>';
|
|
3466
|
-
}else{
|
|
3467
|
-
if(result) result.innerHTML='<span style="color:#ef4444">'+t('sharing.retryConnection.fail')+'</span>';
|
|
3468
|
-
}
|
|
3469
|
-
}catch(e){
|
|
3470
|
-
if(result) result.innerHTML='<span style="color:#ef4444">'+t('sharing.retryConnection.fail')+'</span>';
|
|
3471
|
-
}
|
|
3472
|
-
if(btn){btn.disabled=false;btn.textContent=t('sharing.retryConnection');}
|
|
3473
|
-
}
|
|
3474
|
-
|
|
3475
|
-
async function retryHubJoin(){
|
|
3476
|
-
if(!confirm(t('sharing.retryJoin.confirm'))) return;
|
|
3477
|
-
try{
|
|
3478
|
-
var r=await fetch('/api/sharing/retry-join',{method:'POST',headers:{'Content-Type':'application/json'}});
|
|
3479
|
-
var d=await r.json();
|
|
3480
|
-
if(d.ok){
|
|
3481
|
-
toast(t('sharing.retryJoin.success'),'success');
|
|
3482
|
-
setTimeout(function(){location.reload();},1500);
|
|
3483
|
-
}else{
|
|
3484
|
-
toast(d.error||t('sharing.retryJoin.fail'),'error');
|
|
3485
|
-
}
|
|
3486
|
-
}catch(e){toast(t('sharing.retryJoin.fail')+': '+e.message,'error');}
|
|
3487
|
-
}
|
|
3488
|
-
|
|
3489
|
-
async function updateHubUsername(){
|
|
3490
|
-
var input=document.getElementById('hubUsernameInput');
|
|
3491
|
-
if(!input) return;
|
|
3492
|
-
var newName=input.value.trim();
|
|
3493
|
-
if(!newName||newName.length<2||newName.length>32){
|
|
3494
|
-
toast(t('sharing.username.invalid'),'error');
|
|
3495
|
-
return;
|
|
3496
|
-
}
|
|
3497
|
-
try{
|
|
3498
|
-
var r=await fetch('/api/sharing/update-username',{
|
|
3499
|
-
method:'POST',
|
|
3500
|
-
headers:{'Content-Type':'application/json'},
|
|
3501
|
-
body:JSON.stringify({username:newName})
|
|
3502
|
-
});
|
|
3503
|
-
var d=await r.json();
|
|
3504
|
-
if(d.error==='username_taken'){
|
|
3505
|
-
toast(t('sharing.username.taken'),'error');
|
|
3506
|
-
return;
|
|
3507
|
-
}
|
|
3508
|
-
if(d.error){
|
|
3509
|
-
toast(d.error,'error');
|
|
3510
|
-
return;
|
|
3511
|
-
}
|
|
3512
|
-
toast(t('sharing.username.updated'),'success');
|
|
3513
|
-
loadSharingStatus(false);
|
|
3514
|
-
}catch(e){
|
|
3515
|
-
toast(t('sharing.username.error'),'error');
|
|
3516
|
-
}
|
|
3517
|
-
}
|
|
3518
|
-
|
|
3519
|
-
async function loadSharingPendingUsers(){
|
|
3520
|
-
if(_sharingRole==='client') return;
|
|
3521
|
-
var el=document.getElementById('sharingAdminPanel');
|
|
3522
|
-
if(!el) return;
|
|
3523
|
-
el.innerHTML=t('sharing.loading');
|
|
3524
|
-
try{
|
|
3525
|
-
const r=await fetch('/api/sharing/pending-users');
|
|
3526
|
-
const d=await r.json();
|
|
3527
|
-
const users=Array.isArray(d.users)?d.users:[];
|
|
3528
|
-
renderSharingPendingUsers(users, d.error, sharingStatusCache&&sharingStatusCache.admin?sharingStatusCache.admin.rejectSupported:false);
|
|
3529
|
-
}catch(e){
|
|
3530
|
-
el.innerHTML='<div class="line">'+t('sharing.pendingLoadFail')+esc(String(e))+'</div>';
|
|
3531
|
-
}
|
|
3532
|
-
}
|
|
3533
|
-
|
|
3534
|
-
function renderSharingPendingUsers(users, error, rejectSupported){
|
|
3535
|
-
var el=document.getElementById('sharingAdminPanel');
|
|
3536
|
-
if(!el) return;
|
|
3537
|
-
var wrap='<div class="hub-info-card hic-pending"><div class="hic-title"><span class="hic-icon">\u{1F6E1}</span>'+t('settings.hub.adminPending')+' <span class="hic-badge pending"><span class="hic-dot amber"></span>'+(users?users.length:0)+'</span></div>';
|
|
3538
|
-
if(error){
|
|
3539
|
-
el.innerHTML=wrap+'<div class="hic-empty">'+esc(error)+'</div></div>';
|
|
3540
|
-
return;
|
|
3541
|
-
}
|
|
3542
|
-
if(!users||users.length===0){
|
|
3543
|
-
el.innerHTML=wrap+'<div class="hic-empty">'+t('sharing.noPending')+'</div></div>';
|
|
3544
|
-
return;
|
|
3545
|
-
}
|
|
3546
|
-
el.innerHTML=wrap+users.map(function(user){
|
|
3547
|
-
return '<div style="display:flex;align-items:center;justify-content:space-between;padding:8px 0;border-top:1px solid var(--border)">'+
|
|
3548
|
-
'<div><div style="font-size:13px;font-weight:600;color:var(--text)">'+esc(user.username||user.id||'')+'</div>'+
|
|
3549
|
-
'<div style="font-size:11px;color:var(--text-muted)">'+t('admin.device')+esc(user.deviceName||'unknown')+'</div></div>'+
|
|
3550
|
-
'<div class="hic-actions" style="margin:0">'+
|
|
3551
|
-
'<button class="btn btn-sm btn-primary" onclick="approveSharingUser("'+escAttr(user.id)+'","'+escAttr(user.username||'')+'")">'+t('admin.approve')+'</button>'+
|
|
3552
|
-
(rejectSupported?'<button class="btn btn-sm btn-ghost" style="color:var(--rose)" onclick="rejectSharingUser("'+escAttr(user.id)+'","'+escAttr(user.username||'')+'")">'+t('admin.reject')+'</button>':'')+
|
|
3553
|
-
'</div></div>';
|
|
3554
|
-
}).join('')+'</div>';
|
|
3555
|
-
}
|
|
3556
|
-
|
|
3557
|
-
async function approveSharingUser(userId,username){
|
|
3558
|
-
try{
|
|
3559
|
-
const r=await fetch('/api/sharing/approve-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
3560
|
-
const d=await r.json();
|
|
3561
|
-
if(d.ok){toast(t('toast.userApproved'),'success');loadSharingPendingUsers();loadSharingStatus(true);} else {toast(d.error||t('toast.approveFail'),'error');}
|
|
3562
|
-
}catch(e){toast(t('toast.approveFail')+': '+e.message,'error');}
|
|
3563
|
-
}
|
|
3564
|
-
|
|
3565
|
-
async function rejectSharingUser(userId,username){
|
|
3566
|
-
try{
|
|
3567
|
-
const r=await fetch('/api/sharing/reject-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
3568
|
-
const d=await r.json();
|
|
3569
|
-
if(d.ok){toast(t('toast.userRejected'),'success');loadSharingPendingUsers();} else {toast(d.error||t('toast.rejectFail'),'error');}
|
|
3570
|
-
}catch(e){toast(t('toast.rejectFail')+': '+e.message,'error');}
|
|
3571
|
-
}
|
|
3572
|
-
|
|
3573
|
-
/* ─── Team Setup Guide ─── */
|
|
3574
|
-
var TEAM_GUIDE_DISMISSED_KEY='memos-team-guide-dismissed';
|
|
3575
|
-
function updateTeamGuide(sharingData){
|
|
3576
|
-
var el=document.getElementById('teamSetupGuide');
|
|
3577
|
-
if(!el) return;
|
|
3578
|
-
if(localStorage.getItem(TEAM_GUIDE_DISMISSED_KEY)==='1'){el.style.display='none';return;}
|
|
3579
|
-
var isConfigured=sharingData&&sharingData.enabled;
|
|
3580
|
-
el.style.display=isConfigured?'none':'block';
|
|
3581
|
-
}
|
|
3582
|
-
function dismissTeamGuide(){
|
|
3583
|
-
localStorage.setItem(TEAM_GUIDE_DISMISSED_KEY,'1');
|
|
3584
|
-
var el=document.getElementById('teamSetupGuide');
|
|
3585
|
-
if(el) el.style.display='none';
|
|
3586
|
-
}
|
|
3587
|
-
function guideGoToHub(role){
|
|
3588
|
-
switchSettingsTab('hub',document.querySelector('.settings-tab-btn[data-tab="hub"]'));
|
|
3589
|
-
var chk=document.getElementById('cfgSharingEnabled');
|
|
3590
|
-
if(chk&&!chk.checked){chk.checked=true;onSharingToggle();}
|
|
3591
|
-
selectSharingRole(role);
|
|
3592
|
-
var card=document.getElementById('settingsSharingConfig');
|
|
3593
|
-
if(card) card.scrollIntoView({behavior:'smooth',block:'start'});
|
|
3594
|
-
}
|
|
3595
|
-
|
|
3596
|
-
/* ─── Group Manager ─── */
|
|
3597
|
-
var groupManagerUsers=[];
|
|
3598
|
-
async function loadGroupManager(){
|
|
3599
|
-
var panel=document.getElementById('groupManagerPanel');
|
|
3600
|
-
if(!panel) return;
|
|
3601
|
-
panel.style.display='block';
|
|
3602
|
-
panel.innerHTML=t('sharing.loadingGroups');
|
|
3603
|
-
try{
|
|
3604
|
-
var [gr,ur]=await Promise.all([
|
|
3605
|
-
fetch('/api/sharing/groups').then(function(r){return r.json();}),
|
|
3606
|
-
fetch('/api/sharing/users').then(function(r){return r.json();})
|
|
3607
|
-
]);
|
|
3608
|
-
var groups=Array.isArray(gr.groups)?gr.groups:[];
|
|
3609
|
-
groupManagerUsers=Array.isArray(ur.users)?ur.users:[];
|
|
3610
|
-
renderGroupManager(panel,groups);
|
|
3611
|
-
}catch(e){panel.innerHTML=t('admin.groupsFailed')+esc(String(e));}
|
|
3612
|
-
}
|
|
3613
|
-
function renderGroupManager(panel,groups){
|
|
3614
|
-
var html='<div style="margin-bottom:8px;display:flex;gap:8px;align-items:center;font-size:12px">'+
|
|
3615
|
-
'<strong>'+t('admin.groups')+' ('+groups.length+')</strong>'+
|
|
3616
|
-
'<button class="btn btn-sm" onclick="showCreateGroupForm()" style="font-size:11px">'+t('admin.newGroup')+'</button>'+
|
|
3617
|
-
'</div>';
|
|
3618
|
-
html+='<div id="createGroupForm" style="display:none;margin-bottom:10px;padding:10px;background:var(--bg);border:1px solid var(--border);border-radius:8px;font-size:12px">'+
|
|
3619
|
-
'<input id="newGroupName" type="text" placeholder="'+t('admin.groupName')+'" style="width:60%;padding:4px 8px;border:1px solid var(--border);border-radius:6px;font-size:12px;margin-right:6px;background:var(--bg);color:var(--text)">'+
|
|
3620
|
-
'<input id="newGroupDesc" type="text" placeholder="'+t('admin.groupDesc')+'" style="width:60%;padding:4px 8px;border:1px solid var(--border);border-radius:6px;font-size:12px;margin-right:6px;margin-top:6px;background:var(--bg);color:var(--text)">'+
|
|
3621
|
-
'<div style="margin-top:6px"><button class="btn btn-sm btn-primary" onclick="createGroup()" style="font-size:11px">'+t('admin.create')+'</button> '+
|
|
3622
|
-
'<button class="btn btn-sm btn-ghost" onclick="hideCreateGroupForm()" style="font-size:11px">'+t('admin.cancel')+'</button></div>'+
|
|
3623
|
-
'</div>';
|
|
3624
|
-
if(groups.length===0){
|
|
3625
|
-
html+='<div style="font-size:12px;color:var(--text-muted);padding:6px 0">'+t('sharing.noGroupsYet')+'</div>';
|
|
3626
|
-
}else{
|
|
3627
|
-
html+='<div style="display:flex;flex-direction:column;gap:6px">';
|
|
3628
|
-
for(var i=0;i<groups.length;i++){
|
|
3629
|
-
var g=groups[i];
|
|
3630
|
-
html+='<div style="padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;font-size:12px">'+
|
|
3631
|
-
'<div style="display:flex;justify-content:space-between;align-items:center">'+
|
|
3632
|
-
'<div><strong style="font-size:12px">'+esc(g.name)+'</strong>'+(g.description?' — <span style="color:var(--text-sec);font-size:11px">'+esc(g.description)+'</span>':'')+'</div>'+
|
|
3633
|
-
'<div style="display:flex;gap:6px">'+
|
|
3634
|
-
'<button class="btn btn-sm" onclick="toggleGroupMembers("'+escAttr(g.id)+'")" style="font-size:11px;padding:2px 8px">'+t('admin.members')+'</button>'+
|
|
3635
|
-
'<button class="btn btn-sm btn-ghost" onclick="deleteGroup("'+escAttr(g.id)+'","'+escAttr(g.name)+'")" style="color:#ef4444;font-size:11px;padding:2px 8px">'+t('admin.delete')+'</button>'+
|
|
3636
|
-
'</div>'+
|
|
3637
|
-
'</div>'+
|
|
3638
|
-
'<div id="groupMembers_'+escAttr(g.id)+'" style="display:none;margin-top:6px;font-size:12px"></div>'+
|
|
3639
|
-
'</div>';
|
|
3640
|
-
}
|
|
3641
|
-
html+='</div>';
|
|
3642
|
-
}
|
|
3643
|
-
panel.innerHTML=html;
|
|
3644
|
-
}
|
|
3645
|
-
function showCreateGroupForm(){var f=document.getElementById('createGroupForm');if(f)f.style.display='block';}
|
|
3646
|
-
function hideCreateGroupForm(){var f=document.getElementById('createGroupForm');if(f)f.style.display='none';}
|
|
3647
|
-
async function createGroup(){
|
|
3648
|
-
var name=(document.getElementById('newGroupName')).value.trim();
|
|
3649
|
-
var desc=(document.getElementById('newGroupDesc')).value.trim();
|
|
3650
|
-
if(!name){toast(t('toast.groupNameRequired'),'error');return;}
|
|
3651
|
-
try{
|
|
3652
|
-
var r=await fetch('/api/sharing/groups',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:name,description:desc})});
|
|
3653
|
-
var d=await r.json();
|
|
3654
|
-
if(d.ok){toast(t('toast.groupCreated'),'success');hideCreateGroupForm();loadGroupManager();}else{toast(d.error||t('toast.createFail'),'error');}
|
|
3655
|
-
}catch(e){toast(t('toast.createFail')+': '+e.message,'error');}
|
|
3656
|
-
}
|
|
3657
|
-
async function deleteGroup(groupId,groupName){
|
|
3658
|
-
if(!confirm(t('confirm.deleteGroup').replace('{name}',groupName))) return;
|
|
3659
|
-
try{
|
|
3660
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId),{method:'DELETE'});
|
|
3661
|
-
var d=await r.json();
|
|
3662
|
-
if(d.ok){toast(t('toast.groupDeleted'),'success');loadGroupManager();}else{toast(d.error||t('toast.deleteFail'),'error');}
|
|
3663
|
-
}catch(e){toast(t('toast.deleteFail')+': '+e.message,'error');}
|
|
3664
|
-
}
|
|
3665
|
-
async function toggleGroupMembers(groupId){
|
|
3666
|
-
var el=document.getElementById('groupMembers_'+groupId);
|
|
3667
|
-
if(!el) return;
|
|
3668
|
-
if(el.style.display!=='none'){el.style.display='none';return;}
|
|
3669
|
-
el.style.display='block';
|
|
3670
|
-
el.innerHTML=t('sharing.loading');
|
|
3671
|
-
try{
|
|
3672
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members');
|
|
3673
|
-
var d=await r.json();
|
|
3674
|
-
var members=Array.isArray(d.members)?d.members:[];
|
|
3675
|
-
renderGroupMembers(el,groupId,members);
|
|
3676
|
-
}catch(e){el.innerHTML=t('admin.groupsFailed')+esc(String(e));}
|
|
3677
|
-
}
|
|
3678
|
-
function renderGroupMembers(el,groupId,members){
|
|
3679
|
-
var html='<div style="font-size:12px;margin-bottom:6px;color:var(--text-sec)">'+t('admin.membersCount').replace('{n}',members.length)+'</div>';
|
|
3680
|
-
if(members.length>0){
|
|
3681
|
-
html+='<div style="display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px">';
|
|
3682
|
-
for(var i=0;i<members.length;i++){
|
|
3683
|
-
var m=members[i];
|
|
3684
|
-
html+='<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;background:var(--bg-card);border:1px solid var(--border);border-radius:12px;font-size:12px">'+
|
|
3685
|
-
esc(m.username||m.userId)+
|
|
3686
|
-
' <button style="background:none;border:none;color:#ef4444;cursor:pointer;font-size:11px;padding:0 2px" onclick="removeGroupMember("'+escAttr(groupId)+'","'+escAttr(m.userId)+'")">×</button>'+
|
|
3687
|
-
'</span>';
|
|
3688
|
-
}
|
|
3689
|
-
html+='</div>';
|
|
3690
|
-
}else{
|
|
3691
|
-
html+='<div style="font-size:12px;color:var(--text-muted);margin-bottom:8px">'+t('admin.noMembersYet')+'</div>';
|
|
3692
|
-
}
|
|
3693
|
-
var memberIds=new Set(members.map(function(m){return m.userId;}));
|
|
3694
|
-
var available=groupManagerUsers.filter(function(u){return !memberIds.has(u.id);});
|
|
3695
|
-
if(available.length>0){
|
|
3696
|
-
html+='<div style="display:flex;gap:6px;align-items:center">'+
|
|
3697
|
-
'<select id="addMemberSelect_'+escAttr(groupId)+'" style="padding:4px 8px;border:1px solid var(--border);border-radius:6px;font-size:12px">';
|
|
3698
|
-
for(var j=0;j<available.length;j++){
|
|
3699
|
-
html+='<option value="'+escAttr(available[j].id)+'">'+esc(available[j].username)+'</option>';
|
|
3700
|
-
}
|
|
3701
|
-
html+='</select>'+
|
|
3702
|
-
'<button class="btn btn-sm" onclick="addGroupMember("'+escAttr(groupId)+'")">'+t('admin.add')+'</button>'+
|
|
3703
|
-
'</div>';
|
|
3704
|
-
}
|
|
3705
|
-
el.innerHTML=html;
|
|
3706
|
-
}
|
|
3707
|
-
async function addGroupMember(groupId){
|
|
3708
|
-
var sel=document.getElementById('addMemberSelect_'+groupId);
|
|
3709
|
-
if(!sel) return;
|
|
3710
|
-
var userId=sel.value;
|
|
3711
|
-
if(!userId) return;
|
|
3712
|
-
try{
|
|
3713
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId})});
|
|
3714
|
-
var d=await r.json();
|
|
3715
|
-
if(d.ok){toast(t('toast.memberAdded'),'success');reloadGroupMembers(groupId);}else{toast(d.error||t('toast.addFail'),'error');}
|
|
3716
|
-
}catch(e){toast(t('toast.addFail')+': '+e.message,'error');}
|
|
3717
|
-
}
|
|
3718
|
-
async function removeGroupMember(groupId,userId){
|
|
3719
|
-
if(!confirm(t('confirm.removeGroupMember'))) return;
|
|
3720
|
-
try{
|
|
3721
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members',{method:'DELETE',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId})});
|
|
3722
|
-
var d=await r.json();
|
|
3723
|
-
if(d.ok){toast(t('toast.memberRemoved'),'success');reloadGroupMembers(groupId);}else{toast(d.error||t('toast.removeFail'),'error');}
|
|
3724
|
-
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
3725
|
-
}
|
|
3726
|
-
async function reloadGroupMembers(groupId){
|
|
3727
|
-
var el=document.getElementById('groupMembers_'+groupId);
|
|
3728
|
-
if(!el) return;
|
|
3729
|
-
el.style.display='block';
|
|
3730
|
-
el.innerHTML=t('sharing.loading');
|
|
3731
|
-
try{
|
|
3732
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members');
|
|
3733
|
-
var d=await r.json();
|
|
3734
|
-
var members=Array.isArray(d.members)?d.members:[];
|
|
3735
|
-
renderGroupMembers(el,groupId,members);
|
|
3736
|
-
}catch(e){el.innerHTML=t('admin.groupsFailed')+esc(String(e));}
|
|
3737
|
-
}
|
|
3738
|
-
|
|
3739
|
-
/* ─── Hub Admin Panel ─── */
|
|
3740
|
-
var adminDataCache={users:[],groups:[],tasks:[],skills:[],memories:[]};
|
|
3741
|
-
|
|
3742
|
-
function switchAdminTab(tab,btn){
|
|
3743
|
-
document.querySelectorAll('.admin-tabs .admin-tab').forEach(function(t){t.classList.remove('active');});
|
|
3744
|
-
btn.classList.add('active');
|
|
3745
|
-
document.querySelectorAll('.admin-panel').forEach(function(p){p.classList.remove('active');});
|
|
3746
|
-
var panel=document.getElementById('admin'+tab.charAt(0).toUpperCase()+tab.slice(1)+'Panel');
|
|
3747
|
-
if(panel) panel.classList.add('active');
|
|
3748
|
-
}
|
|
3749
|
-
|
|
3750
|
-
function adminGoSetup(role){
|
|
3751
|
-
switchView('settings');
|
|
3752
|
-
setTimeout(function(){guideGoToHub(role);},200);
|
|
3753
|
-
}
|
|
3754
|
-
|
|
3755
|
-
async function loadAdminData(){
|
|
3756
|
-
var notEnabledEl=document.getElementById('adminNotEnabled');
|
|
3757
|
-
var mainEl=document.getElementById('adminMainContent');
|
|
3758
|
-
var sharingOn=sharingStatusCache&&sharingStatusCache.enabled;
|
|
3759
|
-
if(!sharingOn){
|
|
3760
|
-
if(mainEl) mainEl.style.display='none';
|
|
3761
|
-
if(notEnabledEl){
|
|
3762
|
-
notEnabledEl.style.display='block';
|
|
3763
|
-
notEnabledEl.innerHTML=
|
|
3764
|
-
'<div style="text-align:center;padding:60px 32px;max-width:520px;margin:0 auto">'+
|
|
3765
|
-
'<div style="font-size:48px;margin-bottom:16px">\u{1F6E1}</div>'+
|
|
3766
|
-
'<div style="font-size:18px;font-weight:700;color:var(--text);margin-bottom:8px">'+t('admin.notEnabled.title')+'</div>'+
|
|
3767
|
-
'<div style="font-size:13px;color:var(--text-sec);line-height:1.7;margin-bottom:24px">'+t('admin.notEnabled.desc')+'</div>'+
|
|
3768
|
-
'<div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap">'+
|
|
3769
|
-
'<button class="btn btn-primary" style="padding:8px 20px;font-size:13px" onclick="adminGoSetup("hub")">'+t('admin.notEnabled.setupHub')+'</button>'+
|
|
3770
|
-
'<button class="btn btn-ghost" style="padding:8px 20px;font-size:13px" onclick="adminGoSetup("client")">'+t('admin.notEnabled.joinTeam')+'</button>'+
|
|
3771
|
-
'</div>'+
|
|
3772
|
-
'<div style="font-size:11px;color:var(--text-muted);margin-top:20px;line-height:1.6">'+t('admin.notEnabled.hint')+'</div>'+
|
|
3773
|
-
'</div>';
|
|
3774
|
-
}
|
|
3775
|
-
return;
|
|
3776
|
-
}
|
|
3777
|
-
if(notEnabledEl) notEnabledEl.style.display='none';
|
|
3778
|
-
if(mainEl) mainEl.style.display='';
|
|
3779
|
-
if(!window._isHubAdmin){
|
|
3780
|
-
var statsEl=document.getElementById('adminStats');
|
|
3781
|
-
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.noPermission')+'</div>';
|
|
3782
|
-
return;
|
|
3783
|
-
}
|
|
3784
|
-
try{
|
|
3785
|
-
var [usersR,tasksR,skillsR,pendingR,memoriesR]=await Promise.all([
|
|
3786
|
-
fetch('/api/sharing/users').then(function(r){return r.json();}),
|
|
3787
|
-
fetch('/api/admin/shared-tasks').then(function(r){return r.json();}),
|
|
3788
|
-
fetch('/api/admin/shared-skills').then(function(r){return r.json();}),
|
|
3789
|
-
fetch('/api/sharing/pending-users').then(function(r){return r.json();}),
|
|
3790
|
-
fetch('/api/admin/shared-memories').then(function(r){return r.json();})
|
|
3791
|
-
]);
|
|
3792
|
-
adminDataCache.users=Array.isArray(usersR.users)?usersR.users:[];
|
|
3793
|
-
adminDataCache.groups=[];
|
|
3794
|
-
adminDataCache.tasks=Array.isArray(tasksR.tasks)?tasksR.tasks:[];
|
|
3795
|
-
adminDataCache.skills=Array.isArray(skillsR.skills)?skillsR.skills:[];
|
|
3796
|
-
adminDataCache.memories=Array.isArray(memoriesR.memories)?memoriesR.memories:[];
|
|
3797
|
-
var pending=Array.isArray(pendingR.users)?pendingR.users:[];
|
|
3798
|
-
renderAdminStats(pending.length);
|
|
3799
|
-
renderAdminUsers(adminDataCache.users, pending);
|
|
3800
|
-
renderAdminMemories(adminDataCache.tasks);
|
|
3801
|
-
renderAdminSkills(adminDataCache.skills);
|
|
3802
|
-
renderAdminSharedMemories(adminDataCache.memories);
|
|
3803
|
-
}catch(e){
|
|
3804
|
-
var statsEl=document.getElementById('adminStats');
|
|
3805
|
-
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.loadFailed')+esc(String(e))+'</div>';
|
|
3806
|
-
}
|
|
3807
|
-
}
|
|
3808
|
-
|
|
3809
|
-
function renderAdminStats(pendingCount){
|
|
3810
|
-
var el=document.getElementById('adminStats');
|
|
3811
|
-
if(!el) return;
|
|
3812
|
-
el.innerHTML=
|
|
3813
|
-
'<div class="admin-stat-box"><span class="as-icon">\u{1F465}</span><div class="val">'+adminDataCache.users.length+'</div><div class="lbl">'+t('admin.stat.activeUsers')+'</div></div>'+
|
|
3814
|
-
'<div class="admin-stat-box"><span class="as-icon">\u{23F3}</span><div class="val">'+pendingCount+'</div><div class="lbl">'+t('admin.stat.pending')+'</div></div>'+
|
|
3815
|
-
'<div class="admin-stat-box"><span class="as-icon">\u{1F4CB}</span><div class="val">'+adminDataCache.tasks.length+'</div><div class="lbl">'+t('admin.stat.sharedTasks')+'</div></div>'+
|
|
3816
|
-
'<div class="admin-stat-box"><span class="as-icon">\u{1F9E0}</span><div class="val">'+adminDataCache.skills.length+'</div><div class="lbl">'+t('admin.stat.sharedSkills')+'</div></div>'+
|
|
3817
|
-
'<div class="admin-stat-box"><span class="as-icon">\u{1F4AD}</span><div class="val">'+(adminDataCache.memories||[]).length+'</div><div class="lbl">'+t('admin.stat.sharedMemories')+'</div></div>';
|
|
3818
|
-
var tc=document.getElementById('adminTabCountUsers');if(tc)tc.textContent=adminDataCache.users.length+pendingCount;
|
|
3819
|
-
tc=document.getElementById('adminTabCountMemories');if(tc)tc.textContent=(adminDataCache.memories||[]).length;
|
|
3820
|
-
tc=document.getElementById('adminTabCountTasks');if(tc)tc.textContent=adminDataCache.tasks.length;
|
|
3821
|
-
tc=document.getElementById('adminTabCountSkills');if(tc)tc.textContent=adminDataCache.skills.length;
|
|
3822
|
-
}
|
|
3823
|
-
|
|
3824
|
-
function renderAdminUsers(users,pending){
|
|
3825
|
-
var el=document.getElementById('adminUsersPanel');
|
|
3826
|
-
if(!el) return;
|
|
3827
|
-
var html='';
|
|
3828
|
-
if(pending&&pending.length>0){
|
|
3829
|
-
html+='<div style="margin-bottom:16px"><h3 style="font-size:14px;font-weight:600;color:var(--amber);margin-bottom:10px">'+t('admin.pendingApproval')+' ('+pending.length+')</h3>';
|
|
3830
|
-
for(var p=0;p<pending.length;p++){
|
|
3831
|
-
var pu=pending[p];
|
|
3832
|
-
html+='<div class="admin-card"><div class="admin-card-header"><div class="admin-card-title">'+esc(pu.username||pu.id||'Unknown')+'</div><span class="admin-badge pending">pending</span></div>'+
|
|
3833
|
-
'<div class="admin-card-meta">'+t('admin.device')+esc(pu.deviceName||'unknown')+'</div>'+
|
|
3834
|
-
'<div class="admin-card-actions">'+
|
|
3835
|
-
'<button class="btn btn-sm btn-primary" onclick="adminApproveUser("'+escAttr(pu.id)+'","'+escAttr(pu.username||'')+'")">'+t('admin.approve')+'</button>'+
|
|
3836
|
-
'<button class="btn btn-sm btn-ghost" onclick="adminRejectUser("'+escAttr(pu.id)+'")" style="color:var(--rose)">'+t('admin.reject')+'</button>'+
|
|
3837
|
-
'</div></div>';
|
|
3838
|
-
}
|
|
3839
|
-
html+='</div>';
|
|
3840
|
-
}
|
|
3841
|
-
html+='<h3 style="font-size:14px;font-weight:600;color:var(--text);margin-bottom:10px">'+t('admin.activeUsers')+' ('+users.length+')</h3>';
|
|
3842
|
-
if(users.length===0){
|
|
3843
|
-
html+='<div class="admin-empty"><span class="ae-icon">\u{1F465}</span>'+t('admin.noActiveUsers')+'</div>';
|
|
3844
|
-
}else{
|
|
3845
|
-
for(var i=0;i<users.length;i++){
|
|
3846
|
-
var u=users[i];
|
|
3847
|
-
html+='<div class="admin-card"><div class="admin-card-header"><div class="admin-card-title">'+esc(u.username||u.id)+'</div>'+
|
|
3848
|
-
'<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span></div>'+
|
|
3849
|
-
'<div class="admin-card-meta">ID: '+esc(u.id)+(u.status?' \u00B7 Status: '+esc(u.status):'')+'</div></div>';
|
|
3850
|
-
}
|
|
3851
|
-
}
|
|
3852
|
-
el.innerHTML=html;
|
|
3853
|
-
}
|
|
3854
|
-
|
|
3855
|
-
async function adminApproveUser(userId,username){
|
|
3856
|
-
try{
|
|
3857
|
-
var r=await fetch('/api/sharing/approve-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
3858
|
-
var d=await r.json();
|
|
3859
|
-
if(d.ok){toast(t('toast.userApproved'),'success');loadAdminData();}else{toast(d.error||t('toast.approveFail'),'error');}
|
|
3860
|
-
}catch(e){toast(t('toast.approveFail')+': '+e.message,'error');}
|
|
3861
|
-
}
|
|
3862
|
-
async function adminRejectUser(userId){
|
|
3863
|
-
if(!confirm(t('confirm.rejectUser'))) return;
|
|
3864
|
-
try{
|
|
3865
|
-
var r=await fetch('/api/sharing/reject-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId})});
|
|
3866
|
-
var d=await r.json();
|
|
3867
|
-
if(d.ok){toast(t('toast.userRejected'),'success');loadAdminData();}else{toast(d.error||t('toast.rejectFail'),'error');}
|
|
3868
|
-
}catch(e){toast(t('toast.rejectFail')+': '+e.message,'error');}
|
|
3869
|
-
}
|
|
3870
|
-
|
|
3871
|
-
function renderAdminGroups(groups){
|
|
3872
|
-
var el=document.getElementById('adminGroupsPanel');
|
|
3873
|
-
if(!el) return;
|
|
3874
|
-
var html='<div style="margin-bottom:12px;display:flex;justify-content:space-between;align-items:center">'+
|
|
3875
|
-
'<h3 style="font-size:14px;font-weight:600;color:var(--text)">'+t('admin.groups')+' ('+groups.length+')</h3>'+
|
|
3876
|
-
'<button class="btn btn-sm btn-primary" onclick="showAdminCreateGroup()">'+t('admin.newGroup')+'</button></div>';
|
|
3877
|
-
html+='<div id="adminCreateGroupForm" style="display:none;margin-bottom:14px;padding:14px;background:var(--bg);border:1px solid var(--border);border-radius:10px">'+
|
|
3878
|
-
'<div style="display:flex;flex-direction:column;gap:8px">'+
|
|
3879
|
-
'<input id="adminNewGroupName" type="text" placeholder="'+t('admin.groupName')+'" style="padding:8px 12px;border:1px solid var(--border);border-radius:8px;font-size:13px;background:var(--bg-card);color:var(--text)">'+
|
|
3880
|
-
'<input id="adminNewGroupDesc" type="text" placeholder="'+t('admin.groupDesc')+'" style="padding:8px 12px;border:1px solid var(--border);border-radius:8px;font-size:13px;background:var(--bg-card);color:var(--text)">'+
|
|
3881
|
-
'<div style="display:flex;gap:8px"><button class="btn btn-sm btn-primary" onclick="adminCreateGroup()">'+t('admin.create')+'</button>'+
|
|
3882
|
-
'<button class="btn btn-sm btn-ghost" onclick="hideAdminCreateGroup()">'+t('admin.cancel')+'</button></div></div></div>';
|
|
3883
|
-
if(groups.length===0){
|
|
3884
|
-
html+='<div class="admin-empty"><span class="ae-icon">\u{1F4C2}</span>'+t('admin.noGroups')+'</div>';
|
|
3885
|
-
}else{
|
|
3886
|
-
for(var i=0;i<groups.length;i++){
|
|
3887
|
-
var g=groups[i];
|
|
3888
|
-
html+='<div class="admin-card"><div class="admin-card-header"><div class="admin-card-title">'+esc(g.name)+'</div>'+
|
|
3889
|
-
'<button class="btn btn-sm btn-ghost" onclick="adminDeleteGroup("'+escAttr(g.id)+'","'+escAttr(g.name)+'")" style="color:var(--rose);font-size:11px">'+t('admin.delete')+'</button></div>'+
|
|
3890
|
-
(g.description?'<div class="admin-card-meta">'+esc(g.description)+'</div>':'')+
|
|
3891
|
-
'<div id="adminGroupMembers_'+escAttr(g.id)+'" style="margin-top:10px"></div>'+
|
|
3892
|
-
'</div>';
|
|
3893
|
-
}
|
|
3894
|
-
}
|
|
3895
|
-
el.innerHTML=html;
|
|
3896
|
-
for(var i=0;i<groups.length;i++){adminLoadGroupMembers(groups[i].id);}
|
|
3897
|
-
}
|
|
3898
|
-
function showAdminCreateGroup(){var f=document.getElementById('adminCreateGroupForm');if(f)f.style.display='block';}
|
|
3899
|
-
function hideAdminCreateGroup(){var f=document.getElementById('adminCreateGroupForm');if(f)f.style.display='none';}
|
|
3900
|
-
async function adminCreateGroup(){
|
|
3901
|
-
var name=(document.getElementById('adminNewGroupName')).value.trim();
|
|
3902
|
-
var desc=(document.getElementById('adminNewGroupDesc')).value.trim();
|
|
3903
|
-
if(!name){toast(t('toast.groupNameRequired'),'error');return;}
|
|
3904
|
-
try{
|
|
3905
|
-
var r=await fetch('/api/sharing/groups',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:name,description:desc})});
|
|
3906
|
-
var d=await r.json();
|
|
3907
|
-
if(d.ok||d.id){toast(t('toast.groupCreated'),'success');hideAdminCreateGroup();loadAdminData();}else{toast(d.error||t('toast.createFail'),'error');}
|
|
3908
|
-
}catch(e){toast(t('toast.createFail')+': '+e.message,'error');}
|
|
3909
|
-
}
|
|
3910
|
-
async function adminDeleteGroup(groupId,groupName){
|
|
3911
|
-
if(!confirm(t('confirm.deleteGroupShort').replace('{name}',groupName))) return;
|
|
3912
|
-
try{
|
|
3913
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId),{method:'DELETE'});
|
|
3914
|
-
var d=await r.json();
|
|
3915
|
-
if(d.ok){toast(t('toast.groupDeleted'),'success');loadAdminData();}else{toast(d.error||t('toast.deleteFail'),'error');}
|
|
3916
|
-
}catch(e){toast(t('toast.deleteFail')+': '+e.message,'error');}
|
|
3917
|
-
}
|
|
3918
|
-
async function adminLoadGroupMembers(groupId){
|
|
3919
|
-
var el=document.getElementById('adminGroupMembers_'+groupId);
|
|
3920
|
-
if(!el) return;
|
|
3921
|
-
el.innerHTML=t('sharing.loading');
|
|
3922
|
-
try{
|
|
3923
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members');
|
|
3924
|
-
var d=await r.json();
|
|
3925
|
-
var members=Array.isArray(d.members)?d.members:[];
|
|
3926
|
-
var html='<div style="font-size:12px;margin-bottom:6px;color:var(--text-sec)">'+t('admin.membersCount').replace('{n}',members.length)+'</div>';
|
|
3927
|
-
if(members.length>0){
|
|
3928
|
-
html+='<div style="display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px">';
|
|
3929
|
-
for(var i=0;i<members.length;i++){
|
|
3930
|
-
var m=members[i];
|
|
3931
|
-
html+='<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;background:var(--bg-card);border:1px solid var(--border);border-radius:12px;font-size:12px">'+
|
|
3932
|
-
esc(m.username||m.userId)+
|
|
3933
|
-
' <button style="background:none;border:none;color:#ef4444;cursor:pointer;font-size:11px;padding:0 2px" onclick="adminRemoveGroupMember("'+escAttr(groupId)+'","'+escAttr(m.userId)+'")">×</button></span>';
|
|
3934
|
-
}
|
|
3935
|
-
html+='</div>';
|
|
3936
|
-
}else{
|
|
3937
|
-
html+='<div style="font-size:12px;color:var(--text-muted);margin-bottom:8px">'+t('admin.noMembers')+'</div>';
|
|
3938
|
-
}
|
|
3939
|
-
var memberIds=new Set(members.map(function(m){return m.userId;}));
|
|
3940
|
-
var available=adminDataCache.users.filter(function(u){return !memberIds.has(u.id);});
|
|
3941
|
-
if(available.length>0){
|
|
3942
|
-
html+='<div style="display:flex;gap:6px;align-items:center">'+
|
|
3943
|
-
'<select id="adminAddMember_'+escAttr(groupId)+'" style="padding:4px 8px;border:1px solid var(--border);border-radius:6px;font-size:12px;background:var(--bg-card);color:var(--text)">';
|
|
3944
|
-
for(var j=0;j<available.length;j++){
|
|
3945
|
-
html+='<option value="'+escAttr(available[j].id)+'">'+esc(available[j].username)+'</option>';
|
|
3946
|
-
}
|
|
3947
|
-
html+='</select><button class="btn btn-sm" onclick="adminAddGroupMember("'+escAttr(groupId)+'")">'+t('admin.add')+'</button></div>';
|
|
3948
|
-
}
|
|
3949
|
-
el.innerHTML=html;
|
|
3950
|
-
}catch(e){el.innerHTML=t('admin.groupsFailed')+esc(String(e));}
|
|
3951
|
-
}
|
|
3952
|
-
async function adminAddGroupMember(groupId){
|
|
3953
|
-
var sel=document.getElementById('adminAddMember_'+groupId);
|
|
3954
|
-
if(!sel) return;
|
|
3955
|
-
try{
|
|
3956
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:sel.value})});
|
|
3957
|
-
var d=await r.json();
|
|
3958
|
-
if(d.ok){toast(t('toast.memberAdded'),'success');adminLoadGroupMembers(groupId);}else{toast(d.error||t('toast.addFail'),'error');}
|
|
3959
|
-
}catch(e){toast(t('toast.addFail')+': '+e.message,'error');}
|
|
3960
|
-
}
|
|
3961
|
-
async function adminRemoveGroupMember(groupId,userId){
|
|
3962
|
-
if(!confirm(t('confirm.removeMember'))) return;
|
|
3963
|
-
try{
|
|
3964
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members',{method:'DELETE',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId})});
|
|
3965
|
-
var d=await r.json();
|
|
3966
|
-
if(d.ok){toast(t('toast.memberRemoved'),'success');adminLoadGroupMembers(groupId);}else{toast(d.error||t('toast.removeFail'),'error');}
|
|
3967
|
-
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
3968
|
-
}
|
|
3969
|
-
|
|
3970
|
-
function renderAdminMemories(tasks){
|
|
3971
|
-
var el=document.getElementById('adminMemoriesPanel');
|
|
3972
|
-
if(!el) return;
|
|
3973
|
-
adminTasksCache=tasks;
|
|
3974
|
-
var html='<h3 style="font-size:14px;font-weight:600;color:var(--text);margin-bottom:10px">'+t('admin.sharedTasks')+' ('+tasks.length+')</h3>';
|
|
3975
|
-
if(tasks.length===0){
|
|
3976
|
-
html+='<div class="admin-empty"><span class="ae-icon">\u{1F4CB}</span>'+t('admin.noSharedTasks')+'</div>';
|
|
3977
|
-
}else{
|
|
3978
|
-
for(var i=0;i<tasks.length;i++){
|
|
3979
|
-
var tk=tasks[i];
|
|
3980
|
-
html+='<div class="admin-card" onclick="openHubTaskDetailFromCache(\\\'admin\\\','+i+')" style="cursor:pointer"><div class="admin-card-header"><div class="admin-card-title">'+esc(tk.title||tk.id)+'</div>'+
|
|
3981
|
-
'</div>'+
|
|
3982
|
-
'<div class="admin-card-meta">'+
|
|
3983
|
-
t('admin.owner')+esc(tk.ownerName||tk.sourceUserId||'unknown')+
|
|
3984
|
-
(tk.chunkCount!=null?' \u00B7 '+t('admin.chunks')+tk.chunkCount:'')+
|
|
3985
|
-
' \u00B7 '+t('admin.updated')+new Date(tk.updatedAt||tk.createdAt).toLocaleDateString()+
|
|
3986
|
-
'</div>'+
|
|
3987
|
-
'<div class="admin-card-actions">'+
|
|
3988
|
-
'<button class="btn btn-sm btn-ghost" onclick="event.stopPropagation();adminDeleteTask("'+escAttr(tk.id)+'","'+escAttr(tk.title||tk.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>'+
|
|
3989
|
-
'</div></div>';
|
|
3990
|
-
}
|
|
3991
|
-
}
|
|
3992
|
-
el.innerHTML=html;
|
|
3993
|
-
}
|
|
3994
|
-
|
|
3995
|
-
async function adminDeleteTask(taskId,taskTitle){
|
|
3996
|
-
if(!confirm(t('confirm.removeTask').replace('{name}',taskTitle))) return;
|
|
3997
|
-
try{
|
|
3998
|
-
var r=await fetch('/api/admin/shared-tasks/'+encodeURIComponent(taskId),{method:'DELETE'});
|
|
3999
|
-
var d=await r.json();
|
|
4000
|
-
if(d.ok){toast(t('toast.taskRemoved'),'success');loadAdminData();}else{toast(d.error||t('toast.removeFail'),'error');}
|
|
4001
|
-
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
4002
|
-
}
|
|
4003
|
-
|
|
4004
|
-
function renderAdminSkills(skills){
|
|
4005
|
-
var el=document.getElementById('adminSkillsPanel');
|
|
4006
|
-
if(!el) return;
|
|
4007
|
-
adminSkillsCache=skills;
|
|
4008
|
-
var html='<h3 style="font-size:14px;font-weight:600;color:var(--text);margin-bottom:10px">'+t('admin.sharedSkills')+' ('+skills.length+')</h3>';
|
|
4009
|
-
if(skills.length===0){
|
|
4010
|
-
html+='<div class="admin-empty"><span class="ae-icon">\u{1F9E0}</span>'+t('admin.noSharedSkills')+'</div>';
|
|
4011
|
-
}else{
|
|
4012
|
-
for(var i=0;i<skills.length;i++){
|
|
4013
|
-
var s=skills[i];
|
|
4014
|
-
html+='<div class="admin-card" onclick="openHubSkillDetailFromCache(\\\'admin\\\','+i+')" style="cursor:pointer"><div class="admin-card-header"><div class="admin-card-title">'+esc(s.name||s.id)+'</div>'+
|
|
4015
|
-
'</div>'+
|
|
4016
|
-
'<div class="admin-card-meta">'+
|
|
4017
|
-
(s.description?esc(s.description)+'<br>':'')+
|
|
4018
|
-
t('admin.owner')+esc(s.ownerName||s.sourceUserId||'unknown')+
|
|
4019
|
-
(s.version!=null?' \u00B7 '+t('admin.version')+s.version:'')+
|
|
4020
|
-
(s.qualityScore!=null?' \u00B7 '+t('admin.quality')+s.qualityScore:'')+
|
|
4021
|
-
'</div>'+
|
|
4022
|
-
'<div class="admin-card-actions">'+
|
|
4023
|
-
'<button class="btn btn-sm btn-ghost" onclick="event.stopPropagation();adminDeleteSkill("'+escAttr(s.id)+'","'+escAttr(s.name||s.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>'+
|
|
4024
|
-
'</div></div>';
|
|
4025
|
-
}
|
|
4026
|
-
}
|
|
4027
|
-
el.innerHTML=html;
|
|
4028
|
-
}
|
|
4029
|
-
|
|
4030
|
-
async function adminDeleteSkill(skillId,skillName){
|
|
4031
|
-
if(!confirm(t('confirm.removeSkill').replace('{name}',skillName))) return;
|
|
4032
|
-
try{
|
|
4033
|
-
var r=await fetch('/api/admin/shared-skills/'+encodeURIComponent(skillId),{method:'DELETE'});
|
|
4034
|
-
var d=await r.json();
|
|
4035
|
-
if(d.ok){toast(t('toast.skillRemoved'),'success');loadAdminData();}else{toast(d.error||t('toast.removeFail'),'error');}
|
|
4036
|
-
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
4037
|
-
}
|
|
4038
|
-
|
|
4039
|
-
function renderAdminSharedMemories(memories){
|
|
4040
|
-
var el=document.getElementById('adminSharedMemoriesPanel');
|
|
4041
|
-
if(!el) return;
|
|
4042
|
-
adminMemoriesCache=memories||[];
|
|
4043
|
-
var html='<h3 style="font-size:14px;font-weight:600;color:var(--text);margin-bottom:10px">'+t('admin.sharedMemories')+' ('+(memories||[]).length+')</h3>';
|
|
4044
|
-
if(!memories||memories.length===0){
|
|
4045
|
-
html+='<div class="admin-empty"><span class="ae-icon">\u{1F4AD}</span>'+t('admin.noSharedMemories')+'</div>';
|
|
4046
|
-
}else{
|
|
4047
|
-
for(var i=0;i<memories.length;i++){
|
|
4048
|
-
var m=memories[i];
|
|
4049
|
-
html+='<div class="admin-card" onclick="openHubMemoryDetail(\\\'admin\\\','+i+')" style="cursor:pointer"><div class="admin-card-header"><div class="admin-card-title">'+esc(m.summary||m.content?.slice(0,80)||m.id)+'</div>'+
|
|
4050
|
-
'</div>'+
|
|
4051
|
-
'<div class="admin-card-meta">'+
|
|
4052
|
-
t('admin.owner')+esc(m.ownerName||m.sourceUserId||'unknown')+
|
|
4053
|
-
(m.kind?' \u00B7 Kind: '+esc(m.kind):'')+
|
|
4054
|
-
(m.role?' \u00B7 Role: '+esc(m.role):'')+
|
|
4055
|
-
' \u00B7 '+t('admin.updated')+new Date(m.updatedAt||m.createdAt).toLocaleDateString()+
|
|
4056
|
-
'</div>'+
|
|
4057
|
-
'<div class="admin-card-actions">'+
|
|
4058
|
-
'<button class="btn btn-sm btn-ghost" onclick="event.stopPropagation();adminDeleteMemory("'+escAttr(m.id)+'","'+escAttr(m.summary||m.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>'+
|
|
4059
|
-
'</div></div>';
|
|
4060
|
-
}
|
|
4061
|
-
}
|
|
4062
|
-
el.innerHTML=html;
|
|
4063
|
-
}
|
|
4064
|
-
|
|
4065
|
-
async function adminDeleteMemory(memoryId,memoryTitle){
|
|
4066
|
-
if(!confirm(t('confirm.removeMemory').replace('{name}',memoryTitle))) return;
|
|
4067
|
-
try{
|
|
4068
|
-
var r=await fetch('/api/admin/shared-memories/'+encodeURIComponent(memoryId),{method:'DELETE'});
|
|
4069
|
-
var d=await r.json();
|
|
4070
|
-
if(d.ok){toast(t('toast.memoryRemoved'),'success');loadAdminData();}else{toast(d.error||t('toast.removeFail'),'error');}
|
|
4071
|
-
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
4072
|
-
}
|
|
4073
|
-
|
|
4074
|
-
function renderSharingMemorySearchResults(data,query){
|
|
4075
|
-
const list=document.getElementById('memoryList');
|
|
4076
|
-
const localHits=(data&&data.local&&Array.isArray(data.local.hits))?data.local.hits:[];
|
|
4077
|
-
const hubHits=(data&&data.hub&&Array.isArray(data.hub.hits))?data.hub.hits:[];
|
|
4078
|
-
document.getElementById('searchMeta').textContent='Search results for "'+query+'"';
|
|
4079
|
-
document.getElementById('sharingSearchMeta').textContent='Local '+localHits.length+' · Hub '+hubHits.length;
|
|
4080
|
-
document.getElementById('pagination').innerHTML='';
|
|
4081
|
-
list.innerHTML=''+
|
|
4082
|
-
'<div class="result-section">'+
|
|
4083
|
-
'<div class="result-section-header"><div class="result-section-title">'+t('search.localResults')+'</div><div class="result-section-sub">'+localHits.length+' hit(s)</div></div>'+
|
|
4084
|
-
'<div class="search-hit-list">'+(localHits.length?localHits.map(function(hit,idx){
|
|
4085
|
-
return '<div class="search-hit-card">'+
|
|
4086
|
-
'<div class="summary">'+(idx+1)+'. '+esc(hit.summary||'(no summary)')+'</div>'+
|
|
4087
|
-
'<div class="excerpt">'+esc(hit.excerpt||'')+'</div>'+
|
|
4088
|
-
'<div class="search-hit-meta">'+
|
|
4089
|
-
'<span class="meta-chip">role: '+esc(hit.role||'unknown')+'</span>'+
|
|
4090
|
-
(hit.score!=null?'<span class="meta-chip">score: '+Math.round(hit.score*100)+'%</span>':'')+
|
|
4091
|
-
(hit.taskId?'<span class="meta-chip">task: '+esc(hit.taskId)+'</span>':'')+
|
|
4092
|
-
'</div>'+
|
|
4093
|
-
'</div>';
|
|
4094
|
-
}).join(''):'<div class="search-hit-card"><div class="excerpt">'+t('search.noLocal')+'</div></div>')+'</div>'+
|
|
4095
|
-
'</div>'+
|
|
4096
|
-
'<div class="result-section">'+
|
|
4097
|
-
'<div class="result-section-header"><div class="result-section-title">'+t('search.hubResults')+'</div><div class="result-section-sub">'+hubHits.length+' hit(s)</div></div>'+
|
|
4098
|
-
'<div class="search-hit-list">'+(hubHits.length?hubHits.map(function(hit,idx){
|
|
4099
|
-
return '<div class="hub-hit-card">'+
|
|
4100
|
-
'<div class="summary">'+(idx+1)+'. '+esc(hit.summary||'(no summary)')+'</div>'+
|
|
4101
|
-
'<div class="excerpt">'+esc(hit.excerpt||'')+'</div>'+
|
|
4102
|
-
'<div class="hub-hit-meta">'+
|
|
4103
|
-
'<span class="meta-chip">owner: '+esc(hit.ownerName||'unknown')+'</span>'+
|
|
4104
|
-
(hit.groupName?'<span class="meta-chip">group: '+esc(hit.groupName)+'</span>':'')+
|
|
4105
|
-
'<span class="meta-chip">visibility: '+esc(hit.visibility||'hub')+'</span>'+
|
|
4106
|
-
'</div>'+
|
|
4107
|
-
'<div class="hub-hit-actions">'+
|
|
4108
|
-
'<button class="btn btn-sm" onclick="openSharedMemoryDetail("'+escAttr(hit.remoteHitId)+'","'+escAttr(hit.summary||t('search.sharedMemory'))+'","'+escAttr(hit.ownerName||'')+'","'+escAttr(hit.groupName||'')+'")">'+t('search.viewDetail')+'</button>'+
|
|
4109
|
-
'</div>'+
|
|
4110
|
-
'</div>';
|
|
4111
|
-
}).join(''):'<div class="hub-hit-card"><div class="excerpt">'+t('search.noHub')+'</div></div>')+'</div>'+
|
|
4112
|
-
'</div>';
|
|
4113
|
-
}
|
|
4114
|
-
|
|
4115
|
-
async function openSharedMemoryDetail(remoteHitId,title,owner,groupName){
|
|
4116
|
-
currentSharedMemoryHitId=remoteHitId;
|
|
4117
|
-
document.getElementById('sharedMemoryOverlay').classList.add('show');
|
|
4118
|
-
document.getElementById('sharedMemoryTitle').textContent=title||t('search.sharedMemory');
|
|
4119
|
-
document.getElementById('sharedMemoryMeta').innerHTML='<span class="meta-item">Hub</span>'+(owner?'<span class="meta-item">'+t('admin.owner')+esc(owner)+'</span>':'')+(groupName?'<span class="meta-item">'+t('admin.group')+esc(groupName)+'</span>':'');
|
|
4120
|
-
document.getElementById('sharedMemorySummary').textContent=t('sharing.loading');
|
|
4121
|
-
document.getElementById('sharedMemoryContent').textContent='';
|
|
4122
|
-
try{
|
|
4123
|
-
const r=await fetch('/api/sharing/memory-detail',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({remoteHitId:remoteHitId})});
|
|
4124
|
-
const d=await r.json();
|
|
4125
|
-
if(d.error) throw new Error(d.error);
|
|
4126
|
-
document.getElementById('sharedMemorySummary').textContent=d.summary||'';
|
|
4127
|
-
document.getElementById('sharedMemoryContent').textContent=d.content||'';
|
|
4128
|
-
}catch(e){
|
|
4129
|
-
document.getElementById('sharedMemorySummary').textContent=t('search.loadFailed');
|
|
4130
|
-
document.getElementById('sharedMemoryContent').textContent=String(e.message||e);
|
|
4131
|
-
}
|
|
4132
|
-
}
|
|
4133
|
-
|
|
4134
|
-
function closeSharedMemoryDetail(event){
|
|
4135
|
-
if(event && event.target!==document.getElementById('sharedMemoryOverlay')) return;
|
|
4136
|
-
document.getElementById('sharedMemoryOverlay').classList.remove('show');
|
|
4137
|
-
}
|
|
4138
|
-
|
|
4139
|
-
async function openHubMemoryDetail(cacheKey,idx){
|
|
4140
|
-
var arr=cacheKey==='admin'?adminMemoriesCache:hubMemoriesCache;
|
|
4141
|
-
var m=arr[idx];
|
|
4142
|
-
if(!m) return;
|
|
4143
|
-
var overlay=document.getElementById('sharedMemoryOverlay');
|
|
4144
|
-
overlay.classList.add('show');
|
|
4145
|
-
document.getElementById('sharedMemoryTitle').textContent=m.summary||m.content?.slice(0,80)||'(no summary)';
|
|
4146
|
-
var metaHtml='<span class="meta-item">\\u{1F310} Hub</span>'+
|
|
4147
|
-
(m.ownerName?'<span class="meta-item">'+t('admin.owner')+esc(m.ownerName)+'</span>':'')+
|
|
4148
|
-
(m.groupName?'<span class="meta-item">'+t('admin.group')+esc(m.groupName)+'</span>':'')+
|
|
4149
|
-
(m.kind?'<span class="meta-item">Kind: '+esc(m.kind)+'</span>':'')+
|
|
4150
|
-
(m.role?'<span class="meta-item">Role: '+esc(m.role)+'</span>':'')+
|
|
4151
|
-
'<span class="meta-item">visibility: '+esc(m.visibility||'hub')+'</span>'+
|
|
4152
|
-
'<span class="meta-item">'+new Date(m.updatedAt||m.createdAt||0).toLocaleString(dateLoc())+'</span>';
|
|
4153
|
-
document.getElementById('sharedMemoryMeta').innerHTML=metaHtml;
|
|
4154
|
-
document.getElementById('sharedMemorySummary').textContent=m.summary||'';
|
|
4155
|
-
document.getElementById('sharedMemoryContent').textContent=m.content||t('sharing.loading');
|
|
4156
|
-
// try to fetch full content from Hub API
|
|
4157
|
-
var remoteId=m.remoteHitId||m.id;
|
|
4158
|
-
if(remoteId){
|
|
4159
|
-
try{
|
|
4160
|
-
var r=await fetch('/api/sharing/memory-detail',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({remoteHitId:remoteId})});
|
|
4161
|
-
var d=await r.json();
|
|
4162
|
-
if(!d.error&&(d.content||d.summary)){
|
|
4163
|
-
if(d.summary) document.getElementById('sharedMemorySummary').textContent=d.summary;
|
|
4164
|
-
document.getElementById('sharedMemoryContent').textContent=d.content||m.content||'';
|
|
4165
|
-
}
|
|
4166
|
-
}catch(e){}
|
|
4167
|
-
}
|
|
4168
|
-
}
|
|
4169
|
-
|
|
4170
|
-
function openHubTaskDetailFromCache(cacheKey,idx){
|
|
4171
|
-
var arr=cacheKey==='admin'?adminTasksCache:hubTasksCache;
|
|
4172
|
-
var task=arr[idx];
|
|
4173
|
-
if(!task) return;
|
|
4174
|
-
var overlay=document.getElementById('taskDetailOverlay');
|
|
4175
|
-
overlay.classList.add('show');
|
|
4176
|
-
document.getElementById('taskDetailTitle').textContent=task.title||'(no title)';
|
|
4177
|
-
document.getElementById('taskShareActions').innerHTML='';
|
|
4178
|
-
var meta=[
|
|
4179
|
-
'<span class="meta-item">\\u{1F310} Hub</span>',
|
|
4180
|
-
task.status?'<span class="meta-item"><span class="task-status-badge '+task.status+'">'+esc(task.status)+'</span></span>':'',
|
|
4181
|
-
'<span class="meta-item">'+t('admin.owner')+esc(task.ownerName||'unknown')+'</span>',
|
|
4182
|
-
task.groupName?'<span class="meta-item">'+t('admin.group')+esc(task.groupName)+'</span>':'',
|
|
4183
|
-
'<span class="meta-item">visibility: '+esc(task.visibility||'hub')+'</span>',
|
|
4184
|
-
task.chunkCount!=null?'<span class="meta-item">\\u{1F4DD} '+esc(String(task.chunkCount))+' '+t('tasks.chunks.label')+'</span>':'',
|
|
4185
|
-
task.startedAt?'<span class="meta-item">\\u{1F4C5} '+formatTime(task.startedAt)+'</span>':'',
|
|
4186
|
-
task.endedAt?'<span class="meta-item">\\u2192 '+formatTime(task.endedAt)+'</span>':'',
|
|
4187
|
-
(task.updatedAt||task.createdAt)?'<span class="meta-item">'+t('admin.updated')+new Date(task.updatedAt||task.createdAt).toLocaleString(dateLoc())+'</span>':'',
|
|
4188
|
-
task.sourceTaskId?'<div style="width:100%;margin-top:4px"><span class="meta-item" style="width:100%">'+t('tasks.taskid')+'<span class="task-id-full">'+esc(task.sourceTaskId)+'</span></span></div>':'',
|
|
4189
|
-
].filter(Boolean);
|
|
4190
|
-
document.getElementById('taskDetailMeta').innerHTML=meta.join('');
|
|
4191
|
-
document.getElementById('taskSkillSection').innerHTML='';
|
|
4192
|
-
document.getElementById('taskSkillSection').className='task-skill-section';
|
|
4193
|
-
document.getElementById('taskDetailSummary').innerHTML=task.summary?renderSummaryHtml(task.summary):'<div style="color:var(--text-muted);font-size:13px">'+t('tasks.nochunks')+'</div>';
|
|
4194
|
-
document.getElementById('taskDetailChunks').innerHTML='<div style="color:var(--text-muted);padding:12px;font-size:13px">'+t('tasks.nochunks')+'</div>';
|
|
4195
|
-
}
|
|
4196
|
-
|
|
4197
|
-
function openHubSkillDetailFromCache(cacheKey,idx){
|
|
4198
|
-
var arr=cacheKey==='admin'?adminSkillsCache:hubSkillsCache;
|
|
4199
|
-
var skill=arr[idx];
|
|
4200
|
-
if(!skill) return;
|
|
4201
|
-
var overlay=document.getElementById('skillDetailOverlay');
|
|
4202
|
-
overlay.classList.add('show');
|
|
4203
|
-
document.getElementById('skillDetailTitle').textContent='\\u{1F9E0} '+(skill.name||'(no name)');
|
|
4204
|
-
var qs=skill.qualityScore;
|
|
4205
|
-
var qsBadge=(qs!==null&&qs!==undefined)?'<span class="meta-item"><span class="skill-badge quality '+(qs>=7?'high':qs>=5?'mid':'low')+'">\\u2605 '+(+qs).toFixed(1)+'/10</span></span>':'';
|
|
4206
|
-
var meta=[
|
|
4207
|
-
'<span class="meta-item">\\u{1F310} Hub</span>',
|
|
4208
|
-
skill.version!=null?'<span class="meta-item"><span class="skill-badge version">v'+skill.version+'</span></span>':'',
|
|
4209
|
-
skill.status?'<span class="meta-item"><span class="skill-badge status-'+skill.status+'">'+esc(skill.status)+'</span></span>':'',
|
|
4210
|
-
'<span class="meta-item">visibility: '+esc(skill.visibility||'hub')+'</span>',
|
|
4211
|
-
qsBadge,
|
|
4212
|
-
'<span class="meta-item">'+t('admin.owner')+esc(skill.ownerName||'unknown')+'</span>',
|
|
4213
|
-
skill.groupName?'<span class="meta-item">'+t('admin.group')+esc(skill.groupName)+'</span>':'',
|
|
4214
|
-
(skill.updatedAt||skill.createdAt)?'<span class="meta-item">'+t('admin.updated')+new Date(skill.updatedAt||skill.createdAt).toLocaleString(dateLoc())+'</span>':'',
|
|
4215
|
-
].filter(Boolean);
|
|
4216
|
-
document.getElementById('skillDetailMeta').innerHTML=meta.join('');
|
|
4217
|
-
document.getElementById('skillDetailDesc').textContent=skill.description||'';
|
|
4218
|
-
document.getElementById('skillFilesList').innerHTML='';
|
|
4219
|
-
document.getElementById('skillDetailContent').innerHTML=skill.content?'<pre>'+esc(skill.content)+'</pre>':'';
|
|
4220
|
-
document.getElementById('skillVersionsList').innerHTML='';
|
|
4221
|
-
document.getElementById('skillRelatedTasks').innerHTML='';
|
|
4222
|
-
var visBtn=document.getElementById('skillVisibilityBtn');
|
|
4223
|
-
if(visBtn) visBtn.style.display='none';
|
|
4224
|
-
var dlBtn=document.getElementById('skillDownloadBtn');
|
|
4225
|
-
if(dlBtn) dlBtn.style.display='none';
|
|
4226
|
-
var shareBtn=document.getElementById('skillShareActions');
|
|
4227
|
-
if(shareBtn) shareBtn.innerHTML='';
|
|
2044
|
+
document.title=t('title')+' - MemOS';
|
|
2045
|
+
if(typeof loadStats==='function' && document.getElementById('app').style.display==='flex'){loadStats();}
|
|
2046
|
+
if(document.querySelector('.analytics-view.show') && typeof loadMetrics==='function'){loadMetrics();}
|
|
4228
2047
|
}
|
|
4229
2048
|
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
2049
|
+
/* ─── Auth flow ─── */
|
|
2050
|
+
async function checkAuth(){
|
|
2051
|
+
const r=await fetch('/api/auth/status');
|
|
2052
|
+
const d=await r.json();
|
|
2053
|
+
if(d.needsSetup){
|
|
2054
|
+
document.getElementById('setupScreen').style.display='flex';
|
|
2055
|
+
document.getElementById('setupPw').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('setupPw2').focus()});
|
|
2056
|
+
document.getElementById('setupPw2').addEventListener('keydown',e=>{if(e.key==='Enter')doSetup()});
|
|
2057
|
+
} else if(!d.loggedIn){
|
|
2058
|
+
document.getElementById('loginScreen').style.display='flex';
|
|
2059
|
+
document.getElementById('loginPw').addEventListener('keydown',e=>{if(e.key==='Enter')doLogin()});
|
|
2060
|
+
} else {
|
|
2061
|
+
enterApp();
|
|
4242
2062
|
}
|
|
4243
|
-
el.innerHTML=statusHtml+
|
|
4244
|
-
'<button class="btn btn-sm" onclick="shareCurrentTask()">'+(isShared?t('share.updateBtn'):t('share.shareBtn'))+'</button>'+
|
|
4245
|
-
(isShared?'<button class="btn btn-sm btn-ghost" onclick="unshareCurrentTask()">'+t('share.unshareBtn')+'</button>':'');
|
|
4246
2063
|
}
|
|
4247
2064
|
|
|
4248
|
-
async function
|
|
4249
|
-
|
|
4250
|
-
const
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
2065
|
+
async function doSetup(){
|
|
2066
|
+
const pw=document.getElementById('setupPw').value;
|
|
2067
|
+
const pw2=document.getElementById('setupPw2').value;
|
|
2068
|
+
const err=document.getElementById('setupErr');
|
|
2069
|
+
if(pw.length<4){err.textContent=t('setup.err.short');return}
|
|
2070
|
+
if(pw!==pw2){err.textContent=t('setup.err.mismatch');return}
|
|
2071
|
+
const r=await fetch('/api/auth/setup',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:pw})});
|
|
2072
|
+
const d=await r.json();
|
|
2073
|
+
if(d.ok){document.getElementById('setupScreen').style.display='none';enterApp();}
|
|
2074
|
+
else{err.textContent=d.error||t('setup.err.fail')}
|
|
4256
2075
|
}
|
|
4257
2076
|
|
|
4258
|
-
async function
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
2077
|
+
async function doLogin(){
|
|
2078
|
+
const pw=document.getElementById('loginPw').value;
|
|
2079
|
+
const err=document.getElementById('loginErr');
|
|
2080
|
+
const r=await fetch('/api/auth/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:pw})});
|
|
2081
|
+
const d=await r.json();
|
|
2082
|
+
if(d.ok){document.getElementById('loginScreen').style.display='none';enterApp();}
|
|
2083
|
+
else{err.textContent=t('login.err');document.getElementById('loginPw').value='';document.getElementById('loginPw').focus();}
|
|
4265
2084
|
}
|
|
4266
2085
|
|
|
4267
|
-
function
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
if(!skill||!skill.id){el.innerHTML='';return;}
|
|
4271
|
-
const current=(skill.sharingVisibility||null);
|
|
4272
|
-
const isShared=!!current;
|
|
4273
|
-
var statusHtml='';
|
|
4274
|
-
if(isShared){
|
|
4275
|
-
statusHtml='<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;background:#22c55e22;border:1px solid #22c55e44;border-radius:12px;font-size:12px;color:#22c55e">\u2713 '+t('share.alreadyShared')+'</span>';
|
|
4276
|
-
}
|
|
4277
|
-
el.innerHTML=statusHtml+
|
|
4278
|
-
'<button class="btn btn-sm" onclick="shareCurrentSkill()">'+(isShared?t('share.updateBtn'):t('share.shareBtn'))+'</button>'+
|
|
4279
|
-
(isShared?'<button class="btn btn-sm btn-ghost" onclick="unshareCurrentSkill()">'+t('share.unshareBtn')+'</button>':'');
|
|
2086
|
+
async function doLogout(){
|
|
2087
|
+
await fetch('/api/auth/logout',{method:'POST'});
|
|
2088
|
+
location.reload();
|
|
4280
2089
|
}
|
|
4281
2090
|
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
const r=await fetch('/api/sharing/skills/share',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({skillId:currentSkillDetail.id,visibility:visibility})});
|
|
4287
|
-
const d=await r.json();
|
|
4288
|
-
if(d.ok){toast(t('toast.skillShared'),'success');currentSkillDetail.sharingVisibility=visibility;renderSkillShareActions(currentSkillDetail);} else {toast(d.error||t('toast.skillShareFail'),'error');}
|
|
4289
|
-
}catch(e){toast(t('toast.skillShareFail')+': '+e.message,'error');}
|
|
2091
|
+
function showResetForm(){
|
|
2092
|
+
document.getElementById('loginForm').style.display='none';
|
|
2093
|
+
document.getElementById('resetForm').style.display='block';
|
|
2094
|
+
document.getElementById('resetToken').focus();
|
|
4290
2095
|
}
|
|
4291
2096
|
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
const d=await r.json();
|
|
4297
|
-
if(d.ok){toast(t('toast.skillUnshared'),'success');currentSkillDetail.sharingVisibility=null;renderSkillShareActions(currentSkillDetail);} else {toast(d.error||t('toast.skillUnshareFail'),'error');}
|
|
4298
|
-
}catch(e){toast(t('toast.skillUnshareFail')+': '+e.message,'error');}
|
|
2097
|
+
function showLoginForm(){
|
|
2098
|
+
document.getElementById('resetForm').style.display='none';
|
|
2099
|
+
document.getElementById('loginForm').style.display='block';
|
|
2100
|
+
document.getElementById('loginPw').focus();
|
|
4299
2101
|
}
|
|
4300
2102
|
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
2103
|
+
function copyCmd(el){
|
|
2104
|
+
const code=el.querySelector('code').textContent;
|
|
2105
|
+
navigator.clipboard.writeText(code).then(()=>{
|
|
2106
|
+
el.classList.add('copied');
|
|
2107
|
+
el.querySelector('.copy-hint').textContent=t('copy.done');
|
|
2108
|
+
setTimeout(()=>{el.classList.remove('copied');el.querySelector('.copy-hint').textContent=t('copy.hint')},2000);
|
|
2109
|
+
});
|
|
4307
2110
|
}
|
|
4308
2111
|
|
|
4309
|
-
async function
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
2112
|
+
async function doReset(){
|
|
2113
|
+
const token=document.getElementById('resetToken').value.trim();
|
|
2114
|
+
const pw=document.getElementById('resetNewPw').value;
|
|
2115
|
+
const pw2=document.getElementById('resetNewPw2').value;
|
|
2116
|
+
const err=document.getElementById('resetErr');
|
|
2117
|
+
if(!token){err.textContent=t('reset.err.token');return}
|
|
2118
|
+
if(pw.length<4){err.textContent=t('reset.err.short');return}
|
|
2119
|
+
if(pw!==pw2){err.textContent=t('reset.err.mismatch');return}
|
|
2120
|
+
const r=await fetch('/api/auth/reset',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({token,newPassword:pw})});
|
|
2121
|
+
const d=await r.json();
|
|
2122
|
+
if(d.ok){document.getElementById('loginScreen').style.display='none';enterApp();}
|
|
2123
|
+
else{err.textContent=d.error||t('reset.err.fail')}
|
|
4315
2124
|
}
|
|
4316
2125
|
|
|
4317
|
-
function
|
|
4318
|
-
|
|
4319
|
-
|
|
2126
|
+
function enterApp(){
|
|
2127
|
+
document.getElementById('app').style.display='flex';
|
|
2128
|
+
loadAll();
|
|
4320
2129
|
}
|
|
4321
2130
|
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
2131
|
+
function switchView(view){
|
|
2132
|
+
document.querySelectorAll('.nav-tabs .tab').forEach(t=>t.classList.toggle('active',t.dataset.view===view));
|
|
2133
|
+
const feedWrap=document.getElementById('feedWrap');
|
|
2134
|
+
const analyticsView=document.getElementById('analyticsView');
|
|
2135
|
+
const tasksView=document.getElementById('tasksView');
|
|
2136
|
+
const skillsView=document.getElementById('skillsView');
|
|
2137
|
+
const logsView=document.getElementById('logsView');
|
|
2138
|
+
const settingsView=document.getElementById('settingsView');
|
|
2139
|
+
const migrateView=document.getElementById('migrateView');
|
|
2140
|
+
const sidebar=document.getElementById('sidebar');
|
|
2141
|
+
feedWrap.classList.add('hide');
|
|
2142
|
+
analyticsView.classList.remove('show');
|
|
2143
|
+
tasksView.classList.remove('show');
|
|
2144
|
+
skillsView.classList.remove('show');
|
|
2145
|
+
logsView.classList.remove('show');
|
|
2146
|
+
settingsView.classList.remove('show');
|
|
2147
|
+
migrateView.classList.remove('show');
|
|
2148
|
+
const sessionSection=document.getElementById('sidebarSessionSection');
|
|
2149
|
+
if(view==='memories'){
|
|
2150
|
+
feedWrap.classList.remove('hide');
|
|
2151
|
+
sessionSection.style.visibility='';
|
|
2152
|
+
sessionSection.style.pointerEvents='';
|
|
2153
|
+
} else if(view==='tasks'||view==='skills'){
|
|
2154
|
+
sessionSection.style.visibility='hidden';
|
|
2155
|
+
sessionSection.style.pointerEvents='none';
|
|
2156
|
+
if(view==='tasks'){tasksView.classList.add('show');loadTasks();}
|
|
2157
|
+
else{skillsView.classList.add('show');loadSkills();}
|
|
2158
|
+
} else {
|
|
2159
|
+
sessionSection.style.visibility='hidden';
|
|
2160
|
+
sessionSection.style.pointerEvents='none';
|
|
2161
|
+
if(view==='analytics'){
|
|
2162
|
+
analyticsView.classList.add('show');
|
|
2163
|
+
loadMetrics();
|
|
2164
|
+
} else if(view==='logs'){
|
|
2165
|
+
logsView.classList.add('show');
|
|
2166
|
+
loadLogs();
|
|
2167
|
+
} else if(view==='settings'){
|
|
2168
|
+
settingsView.classList.add('show');
|
|
2169
|
+
loadConfig();
|
|
2170
|
+
loadModelHealth();
|
|
2171
|
+
} else if(view==='import'){
|
|
2172
|
+
migrateView.classList.add('show');
|
|
2173
|
+
if(!window._migrateRunning) migrateScan(false);
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
4328
2176
|
}
|
|
4329
2177
|
|
|
4330
2178
|
// ─── Logs ───
|
|
@@ -4383,7 +2231,7 @@ function renderLogToolFilter(tools,current){
|
|
|
4383
2231
|
|
|
4384
2232
|
function formatLogTime(ts){
|
|
4385
2233
|
const d=new Date(ts);
|
|
4386
|
-
const time=d.toLocaleTimeString(
|
|
2234
|
+
const time=d.toLocaleTimeString('zh-CN',{hour:'2-digit',minute:'2-digit',second:'2-digit',hour12:false});
|
|
4387
2235
|
const y=d.getFullYear();
|
|
4388
2236
|
const m=String(d.getMonth()+1).padStart(2,'0');
|
|
4389
2237
|
const day=String(d.getDate()).padStart(2,'0');
|
|
@@ -4644,7 +2492,6 @@ function setMetricsDays(d){
|
|
|
4644
2492
|
}
|
|
4645
2493
|
|
|
4646
2494
|
async function loadMetrics(){
|
|
4647
|
-
try{
|
|
4648
2495
|
const r=await fetch('/api/metrics?days='+metricsDays);
|
|
4649
2496
|
const d=await r.json();
|
|
4650
2497
|
document.getElementById('mTotal').textContent=formatNum(d.totals.memories);
|
|
@@ -4653,11 +2500,9 @@ async function loadMetrics(){
|
|
|
4653
2500
|
document.getElementById('mEmbeddings').textContent=formatNum(d.totals.embeddings);
|
|
4654
2501
|
renderChartWrites(d.writesPerDay);
|
|
4655
2502
|
loadToolMetrics();
|
|
4656
|
-
}catch(e){console.error('loadMetrics',e)}
|
|
4657
2503
|
}
|
|
4658
2504
|
|
|
4659
2505
|
function formatNum(n){return n>=1e6?(n/1e6).toFixed(1)+'M':n>=1e3?(n/1e3).toFixed(1)+'k':String(n);}
|
|
4660
|
-
function dateLoc(){return curLang==='zh'?'zh-CN':'en-US';}
|
|
4661
2506
|
|
|
4662
2507
|
/* ─── Tasks View Logic ─── */
|
|
4663
2508
|
let tasksStatusFilter='';
|
|
@@ -4673,24 +2518,29 @@ function setTaskStatusFilter(btn,status){
|
|
|
4673
2518
|
}
|
|
4674
2519
|
|
|
4675
2520
|
async function loadTasks(){
|
|
4676
|
-
const scope=document.getElementById('taskSearchScope')?document.getElementById('taskSearchScope').value:taskSearchScope;
|
|
4677
|
-
taskSearchScope=scope||'local';
|
|
4678
|
-
if(taskSearchScope!=='local'){ return loadHubTasks(); }
|
|
4679
2521
|
const list=document.getElementById('tasksList');
|
|
4680
2522
|
list.innerHTML='<div class="spinner"></div>';
|
|
4681
2523
|
try{
|
|
4682
2524
|
const params=new URLSearchParams({limit:String(TASKS_PER_PAGE),offset:String(tasksPage*TASKS_PER_PAGE)});
|
|
4683
2525
|
if(tasksStatusFilter) params.set('status',tasksStatusFilter);
|
|
4684
|
-
const
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
]);
|
|
2526
|
+
const r=await fetch('/api/tasks?'+params);
|
|
2527
|
+
const data=await r.json();
|
|
2528
|
+
|
|
2529
|
+
// stats
|
|
2530
|
+
const allR=await fetch('/api/tasks?limit=1&offset=0');
|
|
2531
|
+
const allD=await allR.json();
|
|
4691
2532
|
document.getElementById('tasksTotalCount').textContent=formatNum(allD.total);
|
|
2533
|
+
|
|
2534
|
+
const activeR=await fetch('/api/tasks?status=active&limit=1&offset=0');
|
|
2535
|
+
const activeD=await activeR.json();
|
|
4692
2536
|
document.getElementById('tasksActiveCount').textContent=formatNum(activeD.total);
|
|
2537
|
+
|
|
2538
|
+
const compR=await fetch('/api/tasks?status=completed&limit=1&offset=0');
|
|
2539
|
+
const compD=await compR.json();
|
|
4693
2540
|
document.getElementById('tasksCompletedCount').textContent=formatNum(compD.total);
|
|
2541
|
+
|
|
2542
|
+
const skipR=await fetch('/api/tasks?status=skipped&limit=1&offset=0');
|
|
2543
|
+
const skipD=await skipR.json();
|
|
4694
2544
|
document.getElementById('tasksSkippedCount').textContent=formatNum(skipD.total);
|
|
4695
2545
|
|
|
4696
2546
|
if(!data.tasks||data.tasks.length===0){
|
|
@@ -4756,16 +2606,13 @@ async function openTaskDetail(taskId){
|
|
|
4756
2606
|
document.getElementById('taskSkillSection').className='task-skill-section';
|
|
4757
2607
|
document.getElementById('taskDetailSummary').textContent='';
|
|
4758
2608
|
document.getElementById('taskDetailChunks').innerHTML='<div class="spinner"></div>';
|
|
4759
|
-
document.getElementById('taskShareActions').innerHTML='';
|
|
4760
2609
|
document.getElementById('taskDetailActions').innerHTML='';
|
|
4761
2610
|
|
|
4762
2611
|
try{
|
|
4763
2612
|
const r=await fetch('/api/task/'+taskId);
|
|
4764
2613
|
const task=await r.json();
|
|
4765
|
-
currentTaskDetail=task;
|
|
4766
2614
|
|
|
4767
2615
|
document.getElementById('taskDetailTitle').textContent=task.title||t('tasks.untitled');
|
|
4768
|
-
renderTaskShareActions(task);
|
|
4769
2616
|
|
|
4770
2617
|
const meta=[
|
|
4771
2618
|
'<span class="meta-item"><span class="task-status-badge '+task.status+'">'+t('tasks.status.'+task.status)+'</span></span>',
|
|
@@ -4934,177 +2781,60 @@ function setSkillStatusFilter(btn,status){
|
|
|
4934
2781
|
|
|
4935
2782
|
async function loadSkills(){
|
|
4936
2783
|
const list=document.getElementById('skillsList');
|
|
4937
|
-
const hubList=document.getElementById('hubSkillsList');
|
|
4938
2784
|
list.innerHTML='<div class="spinner"></div>';
|
|
4939
|
-
var hubSection=document.getElementById('hubSkillsSection');
|
|
4940
|
-
if(hubList){
|
|
4941
|
-
if(skillSearchScope==='local'){
|
|
4942
|
-
if(hubSection) hubSection.style.display='none';
|
|
4943
|
-
}else{
|
|
4944
|
-
if(hubSection) hubSection.style.display='block';
|
|
4945
|
-
hubList.innerHTML='<div class="spinner"></div>';
|
|
4946
|
-
}
|
|
4947
|
-
}
|
|
4948
|
-
|
|
4949
|
-
const query=(document.getElementById('skillSearchInput')?.value||'').trim();
|
|
4950
|
-
const scope=document.getElementById('skillSearchScope') ? document.getElementById('skillSearchScope').value : skillSearchScope;
|
|
4951
|
-
skillSearchScope=scope||'local';
|
|
4952
|
-
|
|
4953
2785
|
try{
|
|
4954
2786
|
const params=new URLSearchParams();
|
|
4955
2787
|
if(skillsStatusFilter) params.set('status',skillsStatusFilter);
|
|
4956
2788
|
const visFilter=document.getElementById('skillVisibilityFilter')?.value;
|
|
4957
2789
|
if(visFilter) params.set('visibility',visFilter);
|
|
2790
|
+
const r=await fetch('/api/skills?'+params);
|
|
2791
|
+
const data=await r.json();
|
|
4958
2792
|
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
localSkills=localSkills.filter(skill=>{
|
|
4965
|
-
const haystack=[skill.name,skill.description,skill.tags].filter(Boolean).join(' ').toLowerCase();
|
|
4966
|
-
return haystack.includes(q);
|
|
4967
|
-
});
|
|
4968
|
-
}
|
|
4969
|
-
|
|
4970
|
-
const renderLocalCards=function(skills){
|
|
4971
|
-
if(!skills||skills.length===0){
|
|
4972
|
-
return '<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+(query?t('skills.search.noresult'):t('skills.empty'))+'</div>';
|
|
4973
|
-
}
|
|
4974
|
-
return skills.map(skill=>{
|
|
4975
|
-
const timeStr=formatTime(skill.createdAt);
|
|
4976
|
-
const tags=parseTags(skill.tags);
|
|
4977
|
-
const installedClass=skill.installed?'installed':'';
|
|
4978
|
-
const statusClass=skill.status==='archived'?'archived':(skill.status==='draft'?'draft':'');
|
|
4979
|
-
const sourceLabel=tags.includes('hub-import')?'hub-import':skill.sourceType;
|
|
4980
|
-
const qs=skill.qualityScore;
|
|
4981
|
-
const qsBadge=qs!==null&&qs!==undefined?'<span class="skill-badge quality '+(qs>=7?'high':qs>=5?'mid':'low')+'">★ '+qs.toFixed(1)+'</span>':'';
|
|
4982
|
-
const visBadge=skill.visibility==='public'?'<span class="skill-badge visibility-public">🌐 '+t('skills.visibility.public')+'</span>':'';
|
|
4983
|
-
return '<div class="skill-card '+installedClass+' '+statusClass+'" onclick="openSkillDetail("'+escAttr(skill.id)+'")">'+
|
|
4984
|
-
'<div class="skill-card-top">'+
|
|
4985
|
-
'<div class="skill-card-name">🧠 '+esc(skill.name)+'</div>'+
|
|
4986
|
-
'<div class="skill-card-badges">'+
|
|
4987
|
-
qsBadge+
|
|
4988
|
-
'<span class="skill-badge version">v'+skill.version+'</span>'+
|
|
4989
|
-
visBadge+
|
|
4990
|
-
(skill.installed?'<span class="skill-badge installed">'+t('skills.installed.badge')+'</span>':'')+
|
|
4991
|
-
'<span class="skill-badge status-'+skill.status+'">'+t('skills.status.'+skill.status)+'</span>'+
|
|
4992
|
-
'</div>'+
|
|
4993
|
-
'</div>'+
|
|
4994
|
-
'<div class="skill-card-desc">'+esc(skill.description)+'</div>'+
|
|
4995
|
-
'<div class="skill-card-bottom">'+
|
|
4996
|
-
'<span class="tag"><span class="icon">📅</span> '+timeStr+'</span>'+
|
|
4997
|
-
'<span class="tag"><span class="icon">📦</span> '+sourceLabel+'</span>'+
|
|
4998
|
-
(tags.length>0?'<div class="skill-card-tags">'+tags.map(t=>'<span class="skill-tag">'+esc(t)+'</span>').join('')+'</div>':'')+
|
|
4999
|
-
'</div>'+
|
|
5000
|
-
'</div>';
|
|
5001
|
-
}).join('');
|
|
5002
|
-
};
|
|
5003
|
-
|
|
5004
|
-
list.innerHTML=renderLocalCards(localSkills);
|
|
5005
|
-
|
|
5006
|
-
if(skillSearchScope==='local'){
|
|
5007
|
-
if(hubSection) hubSection.style.display='none';
|
|
5008
|
-
document.getElementById('skillSearchMeta').textContent=query?(t('skills.search.local')+' '+localSkills.length):'';
|
|
5009
|
-
document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
|
|
5010
|
-
document.getElementById('skillsActiveCount').textContent=formatNum(localSkills.filter(s=>s.status==='active').length);
|
|
5011
|
-
document.getElementById('skillsDraftCount').textContent=formatNum(localSkills.filter(s=>s.status==='draft').length);
|
|
5012
|
-
document.getElementById('skillsInstalledCount').textContent=formatNum(localSkills.filter(s=>s.installed).length);
|
|
5013
|
-
document.getElementById('skillsPublicCount').textContent=formatNum(localSkills.filter(s=>s.visibility==='public').length);
|
|
5014
|
-
return;
|
|
5015
|
-
}
|
|
2793
|
+
document.getElementById('skillsTotalCount').textContent=formatNum(data.skills.length);
|
|
2794
|
+
document.getElementById('skillsActiveCount').textContent=formatNum(data.skills.filter(s=>s.status==='active').length);
|
|
2795
|
+
document.getElementById('skillsDraftCount').textContent=formatNum(data.skills.filter(s=>s.status==='draft').length);
|
|
2796
|
+
document.getElementById('skillsInstalledCount').textContent=formatNum(data.skills.filter(s=>s.installed).length);
|
|
2797
|
+
document.getElementById('skillsPublicCount').textContent=formatNum(data.skills.filter(s=>s.visibility==='public').length);
|
|
5016
2798
|
|
|
5017
|
-
if(!
|
|
5018
|
-
|
|
5019
|
-
if(hubList){ loadHubSkills(hubList); }
|
|
5020
|
-
document.getElementById('skillSearchMeta').textContent=t('skills.search.local')+' '+localSkills.length;
|
|
5021
|
-
document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
|
|
5022
|
-
document.getElementById('skillsActiveCount').textContent=formatNum(localSkills.filter(s=>s.status==='active').length);
|
|
5023
|
-
document.getElementById('skillsDraftCount').textContent=formatNum(localSkills.filter(s=>s.status==='draft').length);
|
|
5024
|
-
document.getElementById('skillsInstalledCount').textContent=formatNum(localSkills.filter(s=>s.installed).length);
|
|
5025
|
-
document.getElementById('skillsPublicCount').textContent=formatNum(localSkills.filter(s=>s.visibility==='public').length);
|
|
2799
|
+
if(!data.skills||data.skills.length===0){
|
|
2800
|
+
list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+t('skills.empty')+'</div>';
|
|
5026
2801
|
return;
|
|
5027
2802
|
}
|
|
5028
2803
|
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
if(hubList){
|
|
5047
|
-
if(hubSection) hubSection.style.display=hubHits.length?'block':'none';
|
|
5048
|
-
hubList.innerHTML=hubHits.length?hubHits.map(function(skill){
|
|
5049
|
-
return '<div class="hub-skill-card">'+
|
|
5050
|
-
'<div class="summary">'+esc(skill.name)+'</div>'+
|
|
5051
|
-
'<div class="excerpt">'+esc(skill.description||'')+'</div>'+
|
|
5052
|
-
'<div class="hub-skill-meta">'+
|
|
5053
|
-
'<span class="meta-chip">owner: '+esc(skill.ownerName||'unknown')+'</span>'+
|
|
5054
|
-
(skill.groupName?'<span class="meta-chip">group: '+esc(skill.groupName)+'</span>':'')+
|
|
5055
|
-
'<span class="meta-chip">visibility: '+esc(skill.visibility||'hub')+'</span>'+
|
|
5056
|
-
(skill.version!=null?'<span class="meta-chip">v'+skill.version+'</span>':'')+
|
|
2804
|
+
list.innerHTML=data.skills.map(skill=>{
|
|
2805
|
+
const timeStr=formatTime(skill.createdAt);
|
|
2806
|
+
const tags=parseTags(skill.tags);
|
|
2807
|
+
const installedClass=skill.installed?'installed':'';
|
|
2808
|
+
const statusClass=skill.status==='archived'?'archived':(skill.status==='draft'?'draft':'');
|
|
2809
|
+
const qs=skill.qualityScore;
|
|
2810
|
+
const qsBadge=qs!==null&&qs!==undefined?'<span class="skill-badge quality '+(qs>=7?'high':qs>=5?'mid':'low')+'">\\u2605 '+qs.toFixed(1)+'</span>':'';
|
|
2811
|
+
const visBadge=skill.visibility==='public'?'<span class="skill-badge visibility-public">\\u{1F310} '+t('skills.visibility.public')+'</span>':'';
|
|
2812
|
+
return '<div class="skill-card '+installedClass+' '+statusClass+'" onclick="openSkillDetail(\\''+skill.id+'\\')">'+
|
|
2813
|
+
'<div class="skill-card-top">'+
|
|
2814
|
+
'<div class="skill-card-name">\\u{1F9E0} '+esc(skill.name)+'</div>'+
|
|
2815
|
+
'<div class="skill-card-badges">'+
|
|
2816
|
+
qsBadge+
|
|
2817
|
+
'<span class="skill-badge version">v'+skill.version+'</span>'+
|
|
2818
|
+
visBadge+
|
|
2819
|
+
(skill.installed?'<span class="skill-badge installed">'+t('skills.installed.badge')+'</span>':'')+
|
|
2820
|
+
'<span class="skill-badge status-'+skill.status+'">'+t('skills.status.'+skill.status)+'</span>'+
|
|
5057
2821
|
'</div>'+
|
|
5058
|
-
'<div class="hub-skill-actions"><button class="btn btn-sm" onclick="event.stopPropagation();pullHubSkill("'+escAttr(skill.skillId)+'")">Pull to Local</button></div>'+
|
|
5059
|
-
'</div>';
|
|
5060
|
-
}).join(''):'';
|
|
5061
|
-
}
|
|
5062
|
-
|
|
5063
|
-
document.getElementById('skillSearchMeta').textContent=t('skills.search.local')+' '+localHits.length+(hubHits.length?' · Hub '+hubHits.length:'');
|
|
5064
|
-
document.getElementById('skillsTotalCount').textContent=formatNum(localHits.length+hubHits.length);
|
|
5065
|
-
document.getElementById('skillsActiveCount').textContent=formatNum(localHits.length);
|
|
5066
|
-
document.getElementById('skillsDraftCount').textContent='0';
|
|
5067
|
-
document.getElementById('skillsInstalledCount').textContent='-';
|
|
5068
|
-
document.getElementById('skillsPublicCount').textContent=formatNum(hubHits.filter(function(s){return s.visibility==='public';}).length);
|
|
5069
|
-
}catch(e){
|
|
5070
|
-
list.innerHTML='<div style="text-align:center;padding:24px;color:var(--rose)">'+t('skills.load.error')+': '+esc(String(e))+'</div>';
|
|
5071
|
-
if(hubList){
|
|
5072
|
-
hubList.innerHTML='<div style="text-align:center;padding:24px;color:var(--rose)">'+t('skills.load.error')+'</div>';
|
|
5073
|
-
}
|
|
5074
|
-
}
|
|
5075
|
-
}
|
|
5076
|
-
|
|
5077
|
-
async function loadHubSkills(hubList){
|
|
5078
|
-
if(!hubList) hubList=document.getElementById('hubSkillsList');
|
|
5079
|
-
if(!hubList) return;
|
|
5080
|
-
var hubSection=document.getElementById('hubSkillsSection');
|
|
5081
|
-
hubList.innerHTML='<div class="spinner"></div>';
|
|
5082
|
-
try{
|
|
5083
|
-
const r=await fetch('/api/sharing/skills/list?limit=40');
|
|
5084
|
-
const d=await r.json();
|
|
5085
|
-
const skills=Array.isArray(d.skills)?d.skills:[];
|
|
5086
|
-
hubSkillsCache=skills;
|
|
5087
|
-
if(!skills.length){
|
|
5088
|
-
if(hubSection) hubSection.style.display='none';
|
|
5089
|
-
return;
|
|
5090
|
-
}
|
|
5091
|
-
if(hubSection) hubSection.style.display='block';
|
|
5092
|
-
hubList.innerHTML=skills.map(function(skill,idx){
|
|
5093
|
-
return '<div class="hub-skill-card" onclick="openHubSkillDetailFromCache(\\\'hub\\\',' +idx+')" style="cursor:pointer">'+
|
|
5094
|
-
'<div class="summary">'+esc(skill.name)+'</div>'+
|
|
5095
|
-
'<div class="excerpt">'+esc(skill.description||'')+'</div>'+
|
|
5096
|
-
'<div class="hub-skill-meta">'+
|
|
5097
|
-
'<span class="meta-chip">owner: '+esc(skill.ownerName||'unknown')+'</span>'+
|
|
5098
|
-
(skill.groupName?'<span class="meta-chip">group: '+esc(skill.groupName)+'</span>':'')+
|
|
5099
|
-
'<span class="meta-chip">visibility: '+esc(skill.visibility||'hub')+'</span>'+
|
|
5100
|
-
(skill.version!=null?'<span class="meta-chip">v'+skill.version+'</span>':'')+
|
|
5101
2822
|
'</div>'+
|
|
5102
|
-
'<div class="
|
|
2823
|
+
'<div class="skill-card-desc">'+esc(skill.description)+'</div>'+
|
|
2824
|
+
'<div class="skill-card-bottom">'+
|
|
2825
|
+
'<span class="tag"><span class="icon">\\u{1F4C5}</span> '+timeStr+'</span>'+
|
|
2826
|
+
'<span class="tag"><span class="icon">\\u{1F4E6}</span> '+skill.sourceType+'</span>'+
|
|
2827
|
+
(tags.length>0?'<div class="skill-card-tags">'+tags.map(t=>'<span class="skill-tag">'+esc(t)+'</span>').join('')+'</div>':'')+
|
|
2828
|
+
'</div>'+
|
|
2829
|
+
'<div class="card-actions" onclick="event.stopPropagation()">'+
|
|
2830
|
+
'<button class="btn btn-sm btn-ghost" onclick="openSkillDetail(\\''+skill.id+'\\')">'+t('card.expand')+'</button>'+
|
|
2831
|
+
(skill.visibility==='public'?'<button class="btn btn-sm btn-ghost" onclick="toggleSkillPublic(\\''+skill.id+'\\',false)">\\u{1F512} '+t('skills.setPrivate')+'</button>':'<button class="btn btn-sm btn-ghost" onclick="toggleSkillPublic(\\''+skill.id+'\\',true)">\\u{1F310} '+t('skills.setPublic')+'</button>')+
|
|
2832
|
+
'<button class="btn btn-sm btn-ghost" style="color:var(--accent)" onclick="deleteSkill(\\''+skill.id+'\\')">'+t('skill.delete')+'</button>'+
|
|
2833
|
+
'</div>'+
|
|
5103
2834
|
'</div>';
|
|
5104
2835
|
}).join('');
|
|
5105
2836
|
}catch(e){
|
|
5106
|
-
|
|
5107
|
-
hubList.innerHTML='';
|
|
2837
|
+
list.innerHTML='<div style="text-align:center;padding:24px;color:var(--rose)">Failed to load skills: '+esc(String(e))+'</div>';
|
|
5108
2838
|
}
|
|
5109
2839
|
}
|
|
5110
2840
|
|
|
@@ -5113,7 +2843,6 @@ function parseTags(tagsStr){
|
|
|
5113
2843
|
}
|
|
5114
2844
|
|
|
5115
2845
|
let currentSkillId='';
|
|
5116
|
-
let currentSkillDetail=null;
|
|
5117
2846
|
|
|
5118
2847
|
async function openSkillDetail(skillId){
|
|
5119
2848
|
currentSkillId=skillId;
|
|
@@ -5126,8 +2855,6 @@ async function openSkillDetail(skillId){
|
|
|
5126
2855
|
document.getElementById('skillDetailContent').innerHTML='<div class="spinner"></div>';
|
|
5127
2856
|
document.getElementById('skillVersionsList').innerHTML='<div class="spinner"></div>';
|
|
5128
2857
|
document.getElementById('skillRelatedTasks').innerHTML='';
|
|
5129
|
-
var vb=document.getElementById('skillVisibilityBtn');if(vb)vb.style.display='';
|
|
5130
|
-
var db=document.getElementById('skillDownloadBtn');if(db)db.style.display='';
|
|
5131
2858
|
document.getElementById('skillDetailActions').innerHTML='';
|
|
5132
2859
|
|
|
5133
2860
|
try{
|
|
@@ -5173,8 +2900,6 @@ async function openSkillDetail(skillId){
|
|
|
5173
2900
|
}
|
|
5174
2901
|
|
|
5175
2902
|
document.getElementById('skillDetailDesc').textContent=skill.description;
|
|
5176
|
-
currentSkillDetail=skill;
|
|
5177
|
-
renderSkillShareActions(skill);
|
|
5178
2903
|
|
|
5179
2904
|
if(files.length>0){
|
|
5180
2905
|
const fileIcons={'skill':'\\u{1F4D6}','script':'\\u{2699}','reference':'\\u{1F4CE}','file':'\\u{1F4C4}'};
|
|
@@ -5382,9 +3107,6 @@ function timeAgo(ts){
|
|
|
5382
3107
|
}
|
|
5383
3108
|
|
|
5384
3109
|
/* ─── Settings / Config ─── */
|
|
5385
|
-
function syncHostToggles(){}
|
|
5386
|
-
function onProviderChange(){}
|
|
5387
|
-
|
|
5388
3110
|
async function loadConfig(){
|
|
5389
3111
|
try{
|
|
5390
3112
|
const r=await fetch('/api/config');
|
|
@@ -5419,26 +3141,6 @@ async function loadConfig(){
|
|
|
5419
3141
|
|
|
5420
3142
|
const tel=cfg.telemetry||{};
|
|
5421
3143
|
document.getElementById('cfgTelemetryEnabled').checked=tel.enabled!==false;
|
|
5422
|
-
|
|
5423
|
-
const sharing=cfg.sharing||{};
|
|
5424
|
-
const caps=sharing.capabilities||{};
|
|
5425
|
-
const embProv=(cfg.embedding||{}).provider;
|
|
5426
|
-
const sumProv=(cfg.summarizer||{}).provider;
|
|
5427
|
-
const skProv=((cfg.skillEvolution||{}).summarizer||{}).provider;
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
document.getElementById('cfgSharingEnabled').checked=!!sharing.enabled;
|
|
5431
|
-
_sharingRole=sharing.role||'client';
|
|
5432
|
-
var hub=sharing.hub||{};
|
|
5433
|
-
var client=sharing.client||{};
|
|
5434
|
-
document.getElementById('cfgHubPort').value=hub.port||18800;
|
|
5435
|
-
document.getElementById('cfgHubTeamName').value=hub.teamName||'';
|
|
5436
|
-
document.getElementById('cfgHubTeamToken').value=hub.teamToken||'';
|
|
5437
|
-
document.getElementById('cfgClientHubAddress').value=client.hubAddress||'';
|
|
5438
|
-
document.getElementById('cfgClientTeamToken').value=client.teamToken||'';
|
|
5439
|
-
document.getElementById('cfgClientUserToken').value=client.userToken||'';
|
|
5440
|
-
onSharingToggle();
|
|
5441
|
-
updateHubShareInfo();
|
|
5442
3144
|
}catch(e){
|
|
5443
3145
|
console.error('loadConfig error',e);
|
|
5444
3146
|
}
|
|
@@ -5471,36 +3173,9 @@ function onProviderChange(section){
|
|
|
5471
3173
|
if(m[2]==='chat'&&def.chatModel&&!mdEl.value.trim()) mdEl.value=def.chatModel;
|
|
5472
3174
|
}
|
|
5473
3175
|
|
|
5474
|
-
function
|
|
5475
|
-
var
|
|
5476
|
-
if(!el)return;
|
|
5477
|
-
el.classList.add('show');
|
|
5478
|
-
setTimeout(function(){el.classList.remove('show');},2500);
|
|
5479
|
-
}
|
|
5480
|
-
|
|
5481
|
-
async function doSaveConfig(cfg, btnEl, savedId){
|
|
5482
|
-
btnEl.disabled=true;btnEl.textContent=t('settings.test.loading');
|
|
5483
|
-
function done(){btnEl.disabled=false;btnEl.textContent=t('settings.save');}
|
|
5484
|
-
try{
|
|
5485
|
-
const r=await fetch('/api/config',{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(cfg)});
|
|
5486
|
-
if(r.status===401){done();toast(t('settings.session.expired'),'error');return false;}
|
|
5487
|
-
if(!r.ok) throw new Error(await r.text());
|
|
5488
|
-
flashSaved(savedId);
|
|
5489
|
-
toast(t('settings.saved'),'success');
|
|
5490
|
-
done();
|
|
5491
|
-
return true;
|
|
5492
|
-
}catch(e){
|
|
5493
|
-
toast(t('settings.save.fail')+': '+e.message,'error');
|
|
5494
|
-
done();
|
|
5495
|
-
return false;
|
|
5496
|
-
}
|
|
5497
|
-
}
|
|
5498
|
-
|
|
5499
|
-
async function saveModelsConfig(){
|
|
5500
|
-
var card=document.querySelector('.card-models');
|
|
5501
|
-
var saveBtn=card.querySelector('.settings-actions .btn-primary');
|
|
3176
|
+
async function saveConfig(){
|
|
3177
|
+
var saveBtn=document.querySelector('.settings-actions .btn-primary');
|
|
5502
3178
|
saveBtn.disabled=true;saveBtn.textContent=t('settings.test.loading');
|
|
5503
|
-
function done(){saveBtn.disabled=false;saveBtn.textContent=t('settings.save');}
|
|
5504
3179
|
|
|
5505
3180
|
const cfg={};
|
|
5506
3181
|
const embP=document.getElementById('cfgEmbProvider').value;
|
|
@@ -5541,8 +3216,16 @@ async function saveModelsConfig(){
|
|
|
5541
3216
|
if(skApiKey) cfg.skillEvolution.summarizer.apiKey=skApiKey;
|
|
5542
3217
|
}
|
|
5543
3218
|
|
|
3219
|
+
const vp=document.getElementById('cfgViewerPort').value.trim();
|
|
3220
|
+
if(vp) cfg.viewerPort=Number(vp);
|
|
3221
|
+
cfg.telemetry={enabled:document.getElementById('cfgTelemetryEnabled').checked};
|
|
3222
|
+
|
|
3223
|
+
function done(){saveBtn.disabled=false;saveBtn.textContent=t('settings.save');}
|
|
3224
|
+
|
|
3225
|
+
// 1) Embedding model is required
|
|
5544
3226
|
if(!embP||embP===''){done();toast(t('settings.save.emb.required'),'error');return;}
|
|
5545
3227
|
|
|
3228
|
+
// 2) Test embedding
|
|
5546
3229
|
try{
|
|
5547
3230
|
var er=await fetch('/api/test-model',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({type:'embedding',provider:cfg.embedding.provider,model:cfg.embedding.model||'',endpoint:cfg.embedding.endpoint||'',apiKey:cfg.embedding.apiKey||''})});
|
|
5548
3231
|
if(er.status===401){done();toast(t('settings.session.expired'),'error');return;}
|
|
@@ -5551,6 +3234,7 @@ async function saveModelsConfig(){
|
|
|
5551
3234
|
document.getElementById('testEmbResult').className='test-result ok';document.getElementById('testEmbResult').innerHTML='\\u2705 '+t('settings.test.ok');
|
|
5552
3235
|
}catch(e){done();toast(t('settings.save.emb.fail')+': '+e.message,'error');return;}
|
|
5553
3236
|
|
|
3237
|
+
// 3) Test summarizer if user filled it
|
|
5554
3238
|
if(hasSumConfig&&cfg.summarizer){
|
|
5555
3239
|
try{
|
|
5556
3240
|
var sr=await fetch('/api/test-model',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({type:'summarizer',provider:cfg.summarizer.provider,model:cfg.summarizer.model||'',endpoint:cfg.summarizer.endpoint||'',apiKey:cfg.summarizer.apiKey||''})});
|
|
@@ -5561,6 +3245,7 @@ async function saveModelsConfig(){
|
|
|
5561
3245
|
}catch(e){done();toast(t('settings.save.sum.fail')+': '+e.message,'error');return;}
|
|
5562
3246
|
}
|
|
5563
3247
|
|
|
3248
|
+
// 4) Test skill model if user filled it
|
|
5564
3249
|
if(hasSkillConfig&&cfg.skillEvolution.summarizer){
|
|
5565
3250
|
try{
|
|
5566
3251
|
var kr=await fetch('/api/test-model',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({type:'summarizer',provider:cfg.skillEvolution.summarizer.provider,model:cfg.skillEvolution.summarizer.model||'',endpoint:cfg.skillEvolution.summarizer.endpoint||'',apiKey:cfg.skillEvolution.summarizer.apiKey||''})});
|
|
@@ -5571,6 +3256,7 @@ async function saveModelsConfig(){
|
|
|
5571
3256
|
}catch(e){done();toast(t('settings.save.skill.fail')+': '+e.message,'error');return;}
|
|
5572
3257
|
}
|
|
5573
3258
|
|
|
3259
|
+
// 5) If summarizer or skill model not configured, check OpenClaw fallback and confirm
|
|
5574
3260
|
if(!hasSumConfig||!hasSkillConfig){
|
|
5575
3261
|
try{
|
|
5576
3262
|
var fr=await fetch('/api/fallback-model');
|
|
@@ -5584,84 +3270,17 @@ async function saveModelsConfig(){
|
|
|
5584
3270
|
}catch(e){}
|
|
5585
3271
|
}
|
|
5586
3272
|
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
cfg.sharing={
|
|
5599
|
-
enabled:sharingEnabled,
|
|
5600
|
-
role:_sharingRole,
|
|
5601
|
-
capabilities:{}
|
|
5602
|
-
};
|
|
5603
|
-
if(sharingEnabled&&_sharingRole==='hub'){
|
|
5604
|
-
var hubPort=document.getElementById('cfgHubPort').value.trim();
|
|
5605
|
-
var hubTeamName=document.getElementById('cfgHubTeamName').value.trim();
|
|
5606
|
-
var hubTeamToken=document.getElementById('cfgHubTeamToken').value.trim();
|
|
5607
|
-
cfg.sharing.hub={port:hubPort?Number(hubPort):18800};
|
|
5608
|
-
if(hubTeamName) cfg.sharing.hub.teamName=hubTeamName;
|
|
5609
|
-
if(hubTeamToken) cfg.sharing.hub.teamToken=hubTeamToken;
|
|
5610
|
-
cfg.sharing.client={hubAddress:'',userToken:'',teamToken:''};
|
|
5611
|
-
}
|
|
5612
|
-
if(sharingEnabled&&_sharingRole==='client'){
|
|
5613
|
-
var clientAddr=document.getElementById('cfgClientHubAddress').value.trim();
|
|
5614
|
-
var clientTeamToken=document.getElementById('cfgClientTeamToken').value.trim();
|
|
5615
|
-
var clientUserToken=document.getElementById('cfgClientUserToken').value.trim();
|
|
5616
|
-
cfg.sharing.client={};
|
|
5617
|
-
if(clientAddr) cfg.sharing.client.hubAddress=clientAddr;
|
|
5618
|
-
if(clientTeamToken) cfg.sharing.client.teamToken=clientTeamToken;
|
|
5619
|
-
if(clientUserToken) cfg.sharing.client.userToken=clientUserToken;
|
|
5620
|
-
cfg.sharing.hub={port:18800,teamName:'',teamToken:''};
|
|
5621
|
-
if(clientAddr){
|
|
5622
|
-
try{
|
|
5623
|
-
var ips=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
5624
|
-
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ips.ips||[]);
|
|
5625
|
-
var parsed=new URL(clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr);
|
|
5626
|
-
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
5627
|
-
done();toast(t('sharing.cannotJoinSelf'),'error');return;
|
|
5628
|
-
}
|
|
5629
|
-
}catch(e){}
|
|
5630
|
-
}
|
|
5631
|
-
}
|
|
5632
|
-
|
|
5633
|
-
var prevSharingEnabled=sharingStatusCache&&sharingStatusCache.enabled;
|
|
5634
|
-
var prevRole=sharingStatusCache&&sharingStatusCache.role;
|
|
5635
|
-
if(prevSharingEnabled&&!sharingEnabled){
|
|
5636
|
-
var confirmMsg=prevRole==='hub'?t('sharing.disable.confirm.hub'):t('sharing.disable.confirm.client');
|
|
5637
|
-
if(!confirm(confirmMsg)){done();return;}
|
|
5638
|
-
}
|
|
5639
|
-
|
|
5640
|
-
var ok=await doSaveConfig(cfg, saveBtn, 'hubSaved');
|
|
5641
|
-
if(ok){
|
|
5642
|
-
loadSharingStatus(false);
|
|
5643
|
-
var needsRestart=sharingEnabled||(prevSharingEnabled&&!sharingEnabled);
|
|
5644
|
-
if(sharingEnabled) updateHubShareInfo();
|
|
5645
|
-
if(needsRestart){
|
|
5646
|
-
setTimeout(function(){showRestartOverlay(t('settings.restart.waiting'));},300);
|
|
5647
|
-
}
|
|
5648
|
-
}
|
|
5649
|
-
}
|
|
5650
|
-
|
|
5651
|
-
async function saveGeneralConfig(){
|
|
5652
|
-
var card=document.querySelector('.card-general');
|
|
5653
|
-
var saveBtn=card.querySelector('.settings-actions .btn-primary');
|
|
5654
|
-
|
|
5655
|
-
const cfg={};
|
|
5656
|
-
const vp=document.getElementById('cfgViewerPort').value.trim();
|
|
5657
|
-
if(vp) cfg.viewerPort=Number(vp);
|
|
5658
|
-
cfg.telemetry={enabled:document.getElementById('cfgTelemetryEnabled').checked};
|
|
5659
|
-
|
|
5660
|
-
await doSaveConfig(cfg, saveBtn, 'generalSaved');
|
|
5661
|
-
}
|
|
5662
|
-
|
|
5663
|
-
async function saveConfig(){
|
|
5664
|
-
await saveModelsConfig();
|
|
3273
|
+
// 6) All tests passed, save
|
|
3274
|
+
try{
|
|
3275
|
+
const r=await fetch('/api/config',{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(cfg)});
|
|
3276
|
+
if(!r.ok) throw new Error(await r.text());
|
|
3277
|
+
const el=document.getElementById('settingsSaved');
|
|
3278
|
+
el.classList.add('show');
|
|
3279
|
+
setTimeout(()=>el.classList.remove('show'),2500);
|
|
3280
|
+
toast(t('settings.saved'),'success');
|
|
3281
|
+
}catch(e){
|
|
3282
|
+
toast(t('settings.save.fail')+': '+e.message,'error');
|
|
3283
|
+
}finally{done();}
|
|
5665
3284
|
}
|
|
5666
3285
|
|
|
5667
3286
|
async function testModel(type){
|
|
@@ -5762,7 +3381,7 @@ function formatDuration(ms){
|
|
|
5762
3381
|
|
|
5763
3382
|
function formatTime(ts){
|
|
5764
3383
|
if(!ts) return '-';
|
|
5765
|
-
return new Date(ts).toLocaleString(
|
|
3384
|
+
return new Date(ts).toLocaleString('zh-CN',{month:'2-digit',day:'2-digit',hour:'2-digit',minute:'2-digit'});
|
|
5766
3385
|
}
|
|
5767
3386
|
|
|
5768
3387
|
function fillDays(rows,days){
|
|
@@ -5774,7 +3393,7 @@ function fillDays(rows,days){
|
|
|
5774
3393
|
const row=map.get(dateStr)||{};
|
|
5775
3394
|
out.push({date:dateStr,count:row.count??0,list:row.list??0,search:row.search??0,total:(row.list??0)+(row.search??0)});
|
|
5776
3395
|
}
|
|
5777
|
-
if(days>
|
|
3396
|
+
if(days>21){
|
|
5778
3397
|
const weeks=[];let i=0;
|
|
5779
3398
|
while(i<out.length){
|
|
5780
3399
|
const chunk=out.slice(i,i+7);
|
|
@@ -5792,23 +3411,19 @@ function fillDays(rows,days){
|
|
|
5792
3411
|
}
|
|
5793
3412
|
|
|
5794
3413
|
function renderBars(el,data,valueKey,H){
|
|
5795
|
-
|
|
5796
|
-
if(vals.every(
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
el.innerHTML=data.map(
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
var showLabel=(idx%labelStep===0)||(idx===n-1);
|
|
5804
|
-
var label=showLabel?rawDate:'';
|
|
5805
|
-
var tipDate=r.date.length>=10?r.date.slice(5,10):'';
|
|
5806
|
-
var tipText=tipDate?(tipDate+': '+v):(''+v);
|
|
3414
|
+
const vals=data.map(d=>d[valueKey]??0);
|
|
3415
|
+
if(vals.every(v=>v===0)){el.innerHTML='<div style="color:var(--text-muted);font-size:13px;padding:20px;text-align:center">'+t('chart.nodata')+'</div>';return;}
|
|
3416
|
+
const max=Math.max(1,...vals);
|
|
3417
|
+
const nonZero=vals.filter(v=>v>0).length;
|
|
3418
|
+
const barStyle=data.length<=7?'min-width:40px;max-width:120px':'';
|
|
3419
|
+
el.innerHTML=data.map(r=>{
|
|
3420
|
+
const v=r[valueKey]??0;
|
|
3421
|
+
const label=r.date.includes('~')?r.date:(r.date.length>5?r.date.slice(5):r.date);
|
|
5807
3422
|
if(v===0){
|
|
5808
|
-
return '<div class="chart-bar-wrap"><div class="chart-tip">
|
|
3423
|
+
return '<div class="chart-bar-wrap" style="'+barStyle+'"><div class="chart-tip">0</div><div class="chart-bar-col"><div class="chart-bar zero" style="height:2px"></div></div><div class="chart-bar-label">'+label+'</div></div>';
|
|
5809
3424
|
}
|
|
5810
|
-
|
|
5811
|
-
return '<div class="chart-bar-wrap"><div class="chart-tip">'+
|
|
3425
|
+
const h=Math.max(8,Math.round((v/max)*H));
|
|
3426
|
+
return '<div class="chart-bar-wrap" style="'+barStyle+'"><div class="chart-tip">'+v+'</div><div class="chart-bar-col"><div class="chart-bar" style="height:'+h+'px"></div></div><div class="chart-bar-label">'+label+'</div></div>';
|
|
5812
3427
|
}).join('');
|
|
5813
3428
|
}
|
|
5814
3429
|
|
|
@@ -5819,31 +3434,25 @@ function renderChartWrites(rows){
|
|
|
5819
3434
|
}
|
|
5820
3435
|
|
|
5821
3436
|
function renderChartCalls(rows){
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
if(vals.every(
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
el.innerHTML=filled.map(function(r,idx){
|
|
5831
|
-
var rawDate=r.date.includes('~')?r.date:(r.date.length>5?r.date.slice(5):'');
|
|
5832
|
-
var showLabel=(idx%labelStep===0)||(idx===n-1);
|
|
5833
|
-
var label=showLabel?rawDate:'';
|
|
5834
|
-
var tipDate=r.date.length>=10?r.date.slice(5,10):'';
|
|
3437
|
+
const el=document.getElementById('chartCalls');
|
|
3438
|
+
const filled=fillDays(rows?.map(r=>({date:r.date,list:r.list,search:r.search})),metricsDays);
|
|
3439
|
+
const vals=filled.map(f=>f.total);
|
|
3440
|
+
if(vals.every(v=>v===0)){el.innerHTML='<div style="color:var(--text-muted);font-size:13px;padding:20px;text-align:center">'+t('chart.nocalls')+'</div>';return;}
|
|
3441
|
+
const max=Math.max(1,...vals);
|
|
3442
|
+
const H=160;
|
|
3443
|
+
el.innerHTML=filled.map(r=>{
|
|
3444
|
+
const label=r.date.includes('~')?r.date:(r.date.length>5?r.date.slice(5):r.date);
|
|
5835
3445
|
if(r.total===0){
|
|
5836
|
-
|
|
5837
|
-
return '<div class="chart-bar-wrap"><div class="chart-tip">'+tipZero+'</div><div class="chart-bar-col"><div class="chart-bar zero" style="height:3px"></div></div><div class="chart-bar-label">'+label+'</div></div>';
|
|
3446
|
+
return '<div class="chart-bar-wrap"><div class="chart-tip">0</div><div class="chart-bar-col"><div class="chart-bar zero" style="height:2px"></div></div><div class="chart-bar-label">'+label+'</div></div>';
|
|
5838
3447
|
}
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
3448
|
+
const totalH=Math.max(8,Math.round((r.total/max)*H));
|
|
3449
|
+
const listH=r.list?Math.max(3,Math.round((r.list/r.total)*totalH)):0;
|
|
3450
|
+
const searchH=r.search?totalH-listH:0;
|
|
3451
|
+
const tip='List: '+r.list+', Search: '+r.search;
|
|
3452
|
+
let bars='';
|
|
5844
3453
|
if(searchH>0) bars+='<div class="chart-bar violet" style="height:'+searchH+'px"></div>';
|
|
5845
3454
|
if(listH>0) bars+='<div class="chart-bar" style="height:'+listH+'px"></div>';
|
|
5846
|
-
return '<div class="chart-bar-wrap"><div class="chart-tip">'+tip+'</div><div class="chart-bar-col"><div style="display:flex;flex-direction:column;gap:1px
|
|
3455
|
+
return '<div class="chart-bar-wrap"><div class="chart-tip">'+tip+'</div><div class="chart-bar-col"><div style="display:flex;flex-direction:column;gap:1px">'+bars+'</div></div><div class="chart-bar-label">'+label+'</div></div>';
|
|
5847
3456
|
}).join('');
|
|
5848
3457
|
}
|
|
5849
3458
|
|
|
@@ -6023,33 +3632,18 @@ function renderToolAgg(data){
|
|
|
6023
3632
|
'</tbody></table>';
|
|
6024
3633
|
}
|
|
6025
3634
|
|
|
6026
|
-
/* ─── Sharing status polling ─── */
|
|
6027
|
-
var _sharingPollTimer=null;
|
|
6028
|
-
function startSharingPoll(){
|
|
6029
|
-
stopSharingPoll();
|
|
6030
|
-
_sharingPollTimer=setInterval(function(){
|
|
6031
|
-
if(sharingStatusCache&&sharingStatusCache.enabled) loadSharingStatus(false);
|
|
6032
|
-
},30000);
|
|
6033
|
-
}
|
|
6034
|
-
function stopSharingPoll(){
|
|
6035
|
-
if(_sharingPollTimer){clearInterval(_sharingPollTimer);_sharingPollTimer=null;}
|
|
6036
|
-
}
|
|
6037
|
-
|
|
6038
3635
|
/* ─── Data loading ─── */
|
|
6039
3636
|
async function loadAll(){
|
|
6040
|
-
await Promise.all([loadStats(),loadMemories()
|
|
3637
|
+
await Promise.all([loadStats(),loadMemories()]);
|
|
6041
3638
|
checkMigrateStatus();
|
|
6042
3639
|
connectPPSSE();
|
|
6043
3640
|
checkForUpdate();
|
|
6044
|
-
startSharingPoll();
|
|
6045
3641
|
}
|
|
6046
3642
|
|
|
6047
|
-
async function loadStats(
|
|
3643
|
+
async function loadStats(){
|
|
6048
3644
|
let d;
|
|
6049
3645
|
try{
|
|
6050
|
-
|
|
6051
|
-
if(ownerFilter) statsUrl+='?owner='+encodeURIComponent(ownerFilter);
|
|
6052
|
-
const r=await fetch(statsUrl);
|
|
3646
|
+
const r=await fetch('/api/stats');
|
|
6053
3647
|
d=await r.json();
|
|
6054
3648
|
}catch(e){ d={}; }
|
|
6055
3649
|
if(!d||typeof d!=='object') d={};
|
|
@@ -6105,17 +3699,6 @@ async function loadStats(ownerFilter){
|
|
|
6105
3699
|
sl.innerHTML+='<div class="session-item'+(isActive?' active':'')+'" onclick="filterSession(\\''+s.session_key.replace(/'/g,"\\\\'")+'\\')"><span title="'+s.session_key+'">'+name+'</span><span class="count">'+s.count+'</span></div>';
|
|
6106
3700
|
});
|
|
6107
3701
|
|
|
6108
|
-
const fSel=document.getElementById('filterSession');
|
|
6109
|
-
if(fSel){
|
|
6110
|
-
const curVal=activeSession||'';
|
|
6111
|
-
var sessionCount=(d.sessions||[]).length;
|
|
6112
|
-
fSel.innerHTML='<option value="">'+t('filter.allsessions')+' ('+sessionCount+')</option>';
|
|
6113
|
-
(d.sessions||[]).forEach(s=>{
|
|
6114
|
-
const sName=s.session_key.length>30?s.session_key.slice(0,12)+'...'+s.session_key.slice(-10):s.session_key;
|
|
6115
|
-
fSel.innerHTML+='<option value="'+s.session_key.replace(/"/g,'"')+'"'+(s.session_key===curVal?' selected':'')+'>'+sName+' ('+s.count+')</option>';
|
|
6116
|
-
});
|
|
6117
|
-
}
|
|
6118
|
-
|
|
6119
3702
|
const ownerSel=document.getElementById('filterOwner');
|
|
6120
3703
|
if(ownerSel && d.owners && d.owners.length>0){
|
|
6121
3704
|
const curVal=ownerSel.value;
|
|
@@ -6127,32 +3710,6 @@ async function loadStats(ownerFilter){
|
|
|
6127
3710
|
}
|
|
6128
3711
|
}
|
|
6129
3712
|
|
|
6130
|
-
function onOwnerFilterChange(){
|
|
6131
|
-
var owner=document.getElementById('filterOwner').value;
|
|
6132
|
-
activeSession=null;
|
|
6133
|
-
currentPage=1;
|
|
6134
|
-
refreshSessionDropdown(owner);
|
|
6135
|
-
applyFilters();
|
|
6136
|
-
}
|
|
6137
|
-
|
|
6138
|
-
async function refreshSessionDropdown(ownerFilter){
|
|
6139
|
-
try{
|
|
6140
|
-
var statsUrl='/api/stats';
|
|
6141
|
-
if(ownerFilter) statsUrl+='?owner='+encodeURIComponent(ownerFilter);
|
|
6142
|
-
var r=await fetch(statsUrl);
|
|
6143
|
-
var d=await r.json();
|
|
6144
|
-
var sessions=d.sessions||[];
|
|
6145
|
-
var fSel=document.getElementById('filterSession');
|
|
6146
|
-
if(fSel){
|
|
6147
|
-
fSel.innerHTML='<option value="">'+t('filter.allsessions')+' ('+sessions.length+')</option>';
|
|
6148
|
-
sessions.forEach(function(s){
|
|
6149
|
-
var sName=s.session_key.length>30?s.session_key.slice(0,12)+'...'+s.session_key.slice(-10):s.session_key;
|
|
6150
|
-
fSel.innerHTML+='<option value="'+s.session_key.replace(/"/g,'"')+'">'+sName+' ('+s.count+')</option>';
|
|
6151
|
-
});
|
|
6152
|
-
}
|
|
6153
|
-
}catch(e){}
|
|
6154
|
-
}
|
|
6155
|
-
|
|
6156
3713
|
function getFilterParams(){
|
|
6157
3714
|
const p=new URLSearchParams();
|
|
6158
3715
|
if(activeSession) p.set('session',activeSession);
|
|
@@ -6191,16 +3748,22 @@ async function loadMemories(page){
|
|
|
6191
3748
|
}
|
|
6192
3749
|
}
|
|
6193
3750
|
|
|
6194
|
-
async function
|
|
3751
|
+
async function doSearch(q){
|
|
3752
|
+
if(!q.trim()){currentPage=1;loadMemories();return}
|
|
6195
3753
|
const list=document.getElementById('memoryList');
|
|
6196
3754
|
list.innerHTML='<div class="spinner"></div>';
|
|
6197
3755
|
try{
|
|
6198
|
-
const
|
|
3756
|
+
const p=getFilterParams();
|
|
3757
|
+
p.set('q',q);
|
|
3758
|
+
const r=await fetch('/api/search?'+p.toString());
|
|
6199
3759
|
const d=await r.json();
|
|
6200
|
-
const
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
3760
|
+
const total=d.total||0;
|
|
3761
|
+
const meta=[];
|
|
3762
|
+
if(d.vectorCount>0) meta.push(d.vectorCount+t('search.meta.semantic'));
|
|
3763
|
+
if(d.ftsCount>0) meta.push(d.ftsCount+t('search.meta.text'));
|
|
3764
|
+
meta.push(total+t('search.meta.results'));
|
|
3765
|
+
document.getElementById('searchMeta').textContent=meta.join(' \\u00B7 ');
|
|
3766
|
+
renderMemories(d.results||[]);
|
|
6204
3767
|
document.getElementById('pagination').innerHTML='';
|
|
6205
3768
|
}catch(e){
|
|
6206
3769
|
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
@@ -6209,51 +3772,6 @@ async function loadHubMemories(){
|
|
|
6209
3772
|
}
|
|
6210
3773
|
}
|
|
6211
3774
|
|
|
6212
|
-
async function doSearch(query){
|
|
6213
|
-
query=(query||'').trim();
|
|
6214
|
-
if(!query){loadMemories();return;}
|
|
6215
|
-
var scope=document.getElementById('memorySearchScope')?.value||memorySearchScope||'local';
|
|
6216
|
-
var list=document.getElementById('memoryList');
|
|
6217
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
6218
|
-
if(scope!=='local'){
|
|
6219
|
-
try{
|
|
6220
|
-
var r=await fetch('/api/sharing/search/memories',{
|
|
6221
|
-
method:'POST',
|
|
6222
|
-
headers:{'Content-Type':'application/json'},
|
|
6223
|
-
body:JSON.stringify({query:query,scope:scope,maxResults:20,role:activeRole||undefined})
|
|
6224
|
-
});
|
|
6225
|
-
var data=await r.json();
|
|
6226
|
-
renderSharingMemorySearchResults(data,query);
|
|
6227
|
-
}catch(e){
|
|
6228
|
-
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
6229
|
-
document.getElementById('sharingSearchMeta').textContent='';
|
|
6230
|
-
renderMemories([]);
|
|
6231
|
-
document.getElementById('pagination').innerHTML='';
|
|
6232
|
-
}
|
|
6233
|
-
} else {
|
|
6234
|
-
try{
|
|
6235
|
-
var p=getFilterParams();
|
|
6236
|
-
p.set('q',query);
|
|
6237
|
-
var r=await fetch('/api/search?'+p.toString());
|
|
6238
|
-
var d=await r.json();
|
|
6239
|
-
var total=d.total||0;
|
|
6240
|
-
var meta=[];
|
|
6241
|
-
if(d.vectorCount>0) meta.push(d.vectorCount+t('search.meta.semantic'));
|
|
6242
|
-
if(d.ftsCount>0) meta.push(d.ftsCount+t('search.meta.text'));
|
|
6243
|
-
meta.push(total+t('search.meta.results'));
|
|
6244
|
-
document.getElementById('searchMeta').textContent=meta.join(' \u00B7 ');
|
|
6245
|
-
document.getElementById('sharingSearchMeta').textContent='';
|
|
6246
|
-
renderMemories(d.results||[]);
|
|
6247
|
-
document.getElementById('pagination').innerHTML='';
|
|
6248
|
-
}catch(e){
|
|
6249
|
-
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
6250
|
-
document.getElementById('sharingSearchMeta').textContent='';
|
|
6251
|
-
renderMemories([]);
|
|
6252
|
-
document.getElementById('pagination').innerHTML='';
|
|
6253
|
-
}
|
|
6254
|
-
}
|
|
6255
|
-
}
|
|
6256
|
-
|
|
6257
3775
|
function debounceSearch(){
|
|
6258
3776
|
clearTimeout(searchTimer);
|
|
6259
3777
|
searchTimer=setTimeout(()=>doSearch(document.getElementById('searchInput').value),350);
|
|
@@ -6262,12 +3780,6 @@ function debounceSearch(){
|
|
|
6262
3780
|
function filterSession(key){
|
|
6263
3781
|
activeSession=key;
|
|
6264
3782
|
currentPage=1;
|
|
6265
|
-
var fSel=document.getElementById('filterSession');
|
|
6266
|
-
if(fSel) fSel.value=key||'';
|
|
6267
|
-
document.querySelectorAll('#sessionList .session-item').forEach(function(el,i){
|
|
6268
|
-
if(i===0) el.classList.toggle('active',!key);
|
|
6269
|
-
else el.classList.toggle('active',el.querySelector('span')?.title===key);
|
|
6270
|
-
});
|
|
6271
3783
|
loadAll();
|
|
6272
3784
|
}
|
|
6273
3785
|
|
|
@@ -6303,7 +3815,7 @@ function renderMemories(items){
|
|
|
6303
3815
|
}
|
|
6304
3816
|
items.forEach(m=>{memoryCache[m.id]=m});
|
|
6305
3817
|
list.innerHTML=items.map(m=>{
|
|
6306
|
-
const time=m.created_at?new Date(typeof m.created_at==='number'?m.created_at:m.created_at).toLocaleString(
|
|
3818
|
+
const time=m.created_at?new Date(typeof m.created_at==='number'?m.created_at:m.created_at).toLocaleString('zh-CN'):'';
|
|
6307
3819
|
const role=m.role||'user';
|
|
6308
3820
|
const rawSummary=m.summary||'';
|
|
6309
3821
|
const rawContent=m.content||'';
|
|
@@ -6315,7 +3827,7 @@ function renderMemories(items){
|
|
|
6315
3827
|
const mc=m.merge_count||0;
|
|
6316
3828
|
const cardTitle=esc(rawSummary||rawContent||'');
|
|
6317
3829
|
const mergeBadge=mc>0?'<span class="merge-badge">\\u{1F504} '+t('card.evolved')+' '+mc+t('card.times')+'</span>':'';
|
|
6318
|
-
const updatedAt=(m.updated_at&&m.updated_at>m.created_at)?'<span class="card-updated">'+t('card.updated')+' '+new Date(m.updated_at).toLocaleString(
|
|
3830
|
+
const updatedAt=(m.updated_at&&m.updated_at>m.created_at)?'<span class="card-updated">'+t('card.updated')+' '+new Date(m.updated_at).toLocaleString('zh-CN')+'</span>':'';
|
|
6319
3831
|
const ds=m.dedup_status||'active';
|
|
6320
3832
|
const isInactive=ds==='merged';
|
|
6321
3833
|
const dedupBadge=ds==='duplicate'?'<span class="dedup-badge duplicate">'+t('card.dedupDuplicate')+'</span>':ds==='merged'?'<span class="dedup-badge merged">'+t('card.dedupMerged')+'</span>':'';
|
|
@@ -6324,8 +3836,6 @@ function renderMemories(items){
|
|
|
6324
3836
|
const ownerVal=m.owner||'agent:main';
|
|
6325
3837
|
const isPublicMem=ownerVal==='public';
|
|
6326
3838
|
const ownerBadge=isPublicMem?'<span class="owner-badge public">\\u{1F310} '+t('filter.public')+'</span>':'<span class="owner-badge agent">\\u{1F512} '+t('filter.private')+'</span>';
|
|
6327
|
-
const memShared=m.sharingVisibility||null;
|
|
6328
|
-
const memShareBadge=memShared?'<span style="display:inline-flex;align-items:center;gap:3px;padding:2px 8px;background:#22c55e22;border:1px solid #22c55e44;border-radius:10px;font-size:11px;color:#22c55e">\\u2713 '+(memShared==='group'?t('share.group'):t('share.public'))+'</span>':'';
|
|
6329
3839
|
let dedupInfo='';
|
|
6330
3840
|
if(ds==='duplicate'||ds==='merged'){
|
|
6331
3841
|
const reason=m.dedup_reason?'<span style="font-size:11px;color:var(--text-muted)">'+t('card.dedupReason')+esc(m.dedup_reason)+'</span>':'';
|
|
@@ -6339,7 +3849,7 @@ function renderMemories(items){
|
|
|
6339
3849
|
if(hist.length>0){
|
|
6340
3850
|
historyHtml='<div class="merge-history" id="history-'+id+'" style="display:none"><div style="font-weight:600;margin-bottom:8px;font-size:12px">'+t('card.evolveHistory')+' ('+hist.length+')</div>';
|
|
6341
3851
|
hist.forEach(function(h){
|
|
6342
|
-
const ht=h.at?new Date(h.at).toLocaleString(
|
|
3852
|
+
const ht=h.at?new Date(h.at).toLocaleString('zh-CN'):'';
|
|
6343
3853
|
historyHtml+='<div class="merge-history-item"><span class="merge-action '+h.action+'">'+h.action+'</span> <span style="color:var(--text-muted)">'+ht+'</span><br>'+esc(h.reason||'');
|
|
6344
3854
|
if(h.from) historyHtml+='<br><span style="opacity:.6">'+t('card.oldSummary')+':</span> '+esc(h.from);
|
|
6345
3855
|
if(h.to) historyHtml+='<br><span style="opacity:.6">'+t('card.newSummary')+':</span> '+esc(h.to);
|
|
@@ -6375,7 +3885,6 @@ function renderMemories(items){
|
|
|
6375
3885
|
(mc>0?'<button class="btn btn-sm btn-ghost" onclick="toggleHistory(\\''+id+'\\')">'+t('card.evolveHistory')+'</button>':'')+
|
|
6376
3886
|
'<button class="btn btn-sm btn-ghost" onclick="openEditModal(\\''+id+'\\')">'+t('card.edit')+'</button>'+
|
|
6377
3887
|
(isPublicMem?'<button class="btn btn-sm btn-ghost" onclick="toggleMemoryPublic(\\''+id+'\\',false)">\\u{1F512} '+t('skills.setPrivate')+'</button>':'<button class="btn btn-sm btn-ghost mem-public-btn" onclick="toggleMemoryPublic(\\''+id+'\\',true)">\\u{1F310} '+t('skills.setPublic')+'</button>')+
|
|
6378
|
-
(memShared?'<button class="btn btn-sm btn-ghost" onclick="unshareMemory(\\''+id+'\\')">'+t('share.unshareBtn')+'</button>':'<button class="btn btn-sm btn-ghost" onclick="shareMemoryPrompt(\\''+id+'\\')">'+t('share.shareBtn')+'</button>')+
|
|
6379
3888
|
'<button class="btn btn-sm btn-ghost" style="color:var(--accent)" onclick="deleteMemory(\\''+id+'\\')">'+t('card.delete')+'</button>'+
|
|
6380
3889
|
vscore+
|
|
6381
3890
|
'</div></div>';
|
|
@@ -6434,50 +3943,38 @@ function scrollToMemory(targetId){
|
|
|
6434
3943
|
}
|
|
6435
3944
|
showMemoryModal(targetId);
|
|
6436
3945
|
}
|
|
6437
|
-
function fmtModalDate(v){
|
|
6438
|
-
if(!v) return '-';
|
|
6439
|
-
var d=new Date(v);
|
|
6440
|
-
if(isNaN(d.getTime())) return '-';
|
|
6441
|
-
return d.toLocaleString(dateLoc());
|
|
6442
|
-
}
|
|
6443
3946
|
async function showMemoryModal(chunkId){
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
body.innerHTML='<div style="text-align:center;padding:
|
|
3947
|
+
const overlay=document.getElementById('memoryModal');
|
|
3948
|
+
const body=document.getElementById('memoryModalBody');
|
|
3949
|
+
body.innerHTML='<div style="text-align:center;padding:40px;color:var(--text-sec)">Loading...</div>';
|
|
6447
3950
|
overlay.classList.add('show');
|
|
6448
3951
|
try{
|
|
6449
|
-
|
|
6450
|
-
if(!res.ok){body.innerHTML='<div style="text-align:center;padding:
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
if(
|
|
6469
|
-
|
|
6470
|
-
if(m.
|
|
6471
|
-
if(m.
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
}
|
|
6476
|
-
if(m.dedup_target&&m.dedup_target!==chunkId){
|
|
6477
|
-
h+='<div class="mm-footer"><span class="dedup-target-link" onclick="closeMemoryModal();scrollToMemory(\\''+m.dedup_target+'\\')">'+t('memory.detail.viewTarget')+' '+m.dedup_target.slice(0,8)+'...</span></div>';
|
|
6478
|
-
}
|
|
6479
|
-
body.innerHTML=h;
|
|
6480
|
-
}catch(e){body.innerHTML='<div style="text-align:center;padding:56px"><div style="font-size:32px;margin-bottom:12px">\u26A0\uFE0F</div><div style="color:#f87171;font-size:13px">'+esc(String(e))+'</div></div>';}
|
|
3952
|
+
const res=await fetch('/api/memory/'+encodeURIComponent(chunkId));
|
|
3953
|
+
if(!res.ok){body.innerHTML='<div style="text-align:center;padding:40px;color:#f87171">Memory not found</div>';return;}
|
|
3954
|
+
const data=await res.json();
|
|
3955
|
+
const m=data.memory;
|
|
3956
|
+
const role=(m.role||'unknown').toUpperCase();
|
|
3957
|
+
const roleCls=(m.role||'').toLowerCase();
|
|
3958
|
+
const ds=m.dedup_status||'active';
|
|
3959
|
+
const time=new Date(m.created_at).toLocaleString('zh-CN');
|
|
3960
|
+
const updated=m.updated_at?new Date(m.updated_at).toLocaleString('zh-CN'):'';
|
|
3961
|
+
let html='<div class="modal-memory-card">';
|
|
3962
|
+
html+='<div class="modal-header-row"><span class="role-tag '+roleCls+'">'+role+'</span>';
|
|
3963
|
+
if(ds!=='active') html+='<span class="dedup-badge '+(ds==='duplicate'?'duplicate':'merged')+'">'+ds+'</span>';
|
|
3964
|
+
html+='</div>';
|
|
3965
|
+
html+='<div class="modal-field"><div class="modal-field-label">ID</div><div class="modal-field-val" style="font-family:monospace;font-size:11px">'+esc(m.id)+'</div></div>';
|
|
3966
|
+
html+='<div class="modal-field"><div class="modal-field-label">Summary</div><div class="modal-field-val" style="font-size:14px;font-weight:600">'+esc(m.summary||'')+'</div></div>';
|
|
3967
|
+
html+='<div class="modal-field"><div class="modal-field-label">Content</div><pre class="modal-field-content">'+esc(m.content||'')+'</pre></div>';
|
|
3968
|
+
html+='<div class="modal-meta-row">';
|
|
3969
|
+
html+='<span><strong>Session:</strong> '+esc(m.session_key||'')+'</span>';
|
|
3970
|
+
html+='<span><strong>Created:</strong> '+time+'</span>';
|
|
3971
|
+
if(updated) html+='<span><strong>Updated:</strong> '+updated+'</span>';
|
|
3972
|
+
html+='</div>';
|
|
3973
|
+
if(m.dedup_reason) html+='<div class="modal-field"><div class="modal-field-label">Dedup Reason</div><div class="modal-field-val">'+esc(m.dedup_reason)+'</div></div>';
|
|
3974
|
+
if(m.dedup_target&&m.dedup_target!==chunkId) html+='<div class="modal-field"><span class="dedup-target-link" onclick="closeMemoryModal();scrollToMemory(\\''+m.dedup_target+'\\')">View target: '+m.dedup_target.slice(0,8)+'...</span></div>';
|
|
3975
|
+
html+='</div>';
|
|
3976
|
+
body.innerHTML=html;
|
|
3977
|
+
}catch(e){body.innerHTML='<div style="text-align:center;padding:40px;color:#f87171">Error: '+esc(String(e))+'</div>';}
|
|
6481
3978
|
}
|
|
6482
3979
|
function closeMemoryModal(){document.getElementById('memoryModal').classList.remove('show');}
|
|
6483
3980
|
|
|
@@ -7192,27 +4689,13 @@ function initViewerTheme(){const s=localStorage.getItem(VIEWER_THEME_KEY);const
|
|
|
7192
4689
|
function toggleViewerTheme(){const el=document.documentElement;const cur=el.getAttribute('data-theme')||'dark';const next=cur==='dark'?'light':'dark';el.setAttribute('data-theme',next);localStorage.setItem(VIEWER_THEME_KEY,next);}
|
|
7193
4690
|
initViewerTheme();
|
|
7194
4691
|
|
|
7195
|
-
/* ─── Restart overlay ─── */
|
|
7196
|
-
function showRestartOverlay(msg){
|
|
7197
|
-
var existing=document.getElementById('restartOverlay');
|
|
7198
|
-
if(existing) existing.remove();
|
|
7199
|
-
var ov=document.createElement('div');
|
|
7200
|
-
ov.id='restartOverlay';
|
|
7201
|
-
ov.style.cssText='position:fixed;inset:0;z-index:99999;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(0,0,0,.55);backdrop-filter:blur(6px);color:#fff;font-family:inherit';
|
|
7202
|
-
ov.innerHTML='<div style="display:flex;flex-direction:column;align-items:center;gap:16px;max-width:400px;text-align:center"><div style="width:36px;height:36px;border:3px solid rgba(255,255,255,.2);border-top-color:#fff;border-radius:50%;animation:spin 1s linear infinite"></div><div style="font-size:15px;font-weight:600">'+esc(msg||t('update.restarting'))+'</div><div id="restartOverlayHint" style="font-size:12px;opacity:.6">'+t('settings.restart.autoRefresh')+'</div></div>';
|
|
7203
|
-
document.body.appendChild(ov);
|
|
7204
|
-
waitForGatewayAndReload(60);
|
|
7205
|
-
}
|
|
7206
|
-
|
|
7207
4692
|
/* ─── Update check ─── */
|
|
7208
4693
|
function waitForGatewayAndReload(maxAttempts,attempt){
|
|
7209
4694
|
attempt=attempt||0;
|
|
7210
|
-
|
|
7211
|
-
if(attempt>=maxAttempts){forceReload();return;}
|
|
4695
|
+
if(attempt>=maxAttempts){window.location.reload();return;}
|
|
7212
4696
|
setTimeout(function(){
|
|
7213
|
-
fetch('/api/auth/status').then(function(
|
|
7214
|
-
|
|
7215
|
-
else waitForGatewayAndReload(maxAttempts,attempt+1);
|
|
4697
|
+
fetch('/api/auth/status').then(function(){
|
|
4698
|
+
window.location.reload();
|
|
7216
4699
|
}).catch(function(){waitForGatewayAndReload(maxAttempts,attempt+1);});
|
|
7217
4700
|
},3000);
|
|
7218
4701
|
}
|
|
@@ -7224,9 +4707,10 @@ function doUpdateInstall(packageSpec,btnEl,statusEl){
|
|
|
7224
4707
|
.then(function(r){return r.json()})
|
|
7225
4708
|
.then(function(d){
|
|
7226
4709
|
if(d.ok){
|
|
7227
|
-
btnEl.textContent=t('update.success')
|
|
4710
|
+
btnEl.textContent=t('update.success');
|
|
7228
4711
|
btnEl.style.cssText='background:rgba(34,197,94,.15);color:#22c55e;border:1px solid rgba(34,197,94,.3);border-radius:6px;padding:4px 14px;font-size:12px;font-weight:600;cursor:default;white-space:nowrap';
|
|
7229
|
-
|
|
4712
|
+
if(statusEl)statusEl.textContent=t('update.restarting');
|
|
4713
|
+
waitForGatewayAndReload(40);
|
|
7230
4714
|
}else{
|
|
7231
4715
|
btnEl.textContent=t('update.btn');
|
|
7232
4716
|
btnEl.style.cssText='background:none;border:1px solid currentColor;border-radius:6px;padding:4px 14px;font-size:12px;font-weight:600;color:inherit;cursor:pointer;white-space:nowrap;opacity:.85';
|
|
@@ -7288,8 +4772,8 @@ checkAuth();
|
|
|
7288
4772
|
<div class="memory-modal-overlay" id="memoryModal" onclick="if(event.target===this)closeMemoryModal()">
|
|
7289
4773
|
<div class="memory-modal">
|
|
7290
4774
|
<div class="memory-modal-title">
|
|
7291
|
-
<
|
|
7292
|
-
<button class="
|
|
4775
|
+
<span>Memory Detail</span>
|
|
4776
|
+
<button class="btn btn-sm btn-ghost" onclick="closeMemoryModal()" style="font-size:16px;padding:2px 8px">×</button>
|
|
7293
4777
|
</div>
|
|
7294
4778
|
<div class="memory-modal-body" id="memoryModalBody"></div>
|
|
7295
4779
|
</div>
|