@memtensor/memos-local-openclaw-plugin 1.0.4-beta.4 → 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 +471 -2974
- 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 +471 -2974
- 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, restart the OpenClaw gateway, then refresh this page</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, restart the gateway, then refresh this page</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", restart OpenClaw gateway, then refresh this page</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',
|
|
@@ -2067,7 +1567,7 @@ const I18N={
|
|
|
2067
1567
|
'settings.save':'Save Settings',
|
|
2068
1568
|
'settings.reset':'Reset',
|
|
2069
1569
|
'settings.saved':'Saved',
|
|
2070
|
-
'settings.restart.hint':'Some changes require restarting the OpenClaw gateway to take effect.
|
|
1570
|
+
'settings.restart.hint':'Some changes require restarting the OpenClaw gateway to take effect.',
|
|
2071
1571
|
'settings.save.fail':'Failed to save settings',
|
|
2072
1572
|
'settings.save.emb.required':'Embedding model is required. Please configure an embedding model before saving.',
|
|
2073
1573
|
'settings.save.emb.fail':'Embedding model test failed, cannot save',
|
|
@@ -2153,7 +1653,7 @@ const I18N={
|
|
|
2153
1653
|
'skills.related':'Related Tasks',
|
|
2154
1654
|
'skills.download':'\u2B07 Download',
|
|
2155
1655
|
'skills.installed.badge':'Installed',
|
|
2156
|
-
'skills.empty':'No skills yet. Skills are
|
|
1656
|
+
'skills.empty':'No skills yet. Skills are automatically generated from completed tasks that contain reusable experience.',
|
|
2157
1657
|
'skills.loading':'Loading...',
|
|
2158
1658
|
'skills.error':'Error loading skill',
|
|
2159
1659
|
'skills.error.detail':'Failed to load skill: ',
|
|
@@ -2174,222 +1674,6 @@ const I18N={
|
|
|
2174
1674
|
'tasks.error':'Error',
|
|
2175
1675
|
'tasks.error.detail':'Failed to load task details',
|
|
2176
1676
|
'tasks.untitled.related':'Untitled',
|
|
2177
|
-
'tab.admin':'\u{1F6E1} Admin',
|
|
2178
|
-
'settings.hub':'Hub & Team',
|
|
2179
|
-
'settings.hub.enable':'Enable Hub Sharing',
|
|
2180
|
-
'settings.hub.enable.hint':'When off, everything works locally as usual.',
|
|
2181
|
-
'settings.hub.enable.label':'Enable Hub Sharing',
|
|
2182
|
-
'settings.hub.role':'Role',
|
|
2183
|
-
'settings.hub.role.hub':'Hub (Server)',
|
|
2184
|
-
'settings.hub.role.client':'Client (Connect to Hub)',
|
|
2185
|
-
'settings.hub.role.hint':'Hub = run the server; Client = connect to one. These two modes are mutually exclusive.',
|
|
2186
|
-
'settings.hub.port':'Hub Port',
|
|
2187
|
-
'settings.hub.port.hint':'Port for Hub service. Default: 18800',
|
|
2188
|
-
'settings.hub.teamName':'Team Name',
|
|
2189
|
-
'settings.hub.teamName.hint':'Display name for your team',
|
|
2190
|
-
'settings.hub.teamToken':'Team Token',
|
|
2191
|
-
'settings.hub.teamToken.hint':'Auto-generated secret for clients to join. Click to copy. Share this with your team members.',
|
|
2192
|
-
'settings.hub.tokenCopied':'Team Token copied!',
|
|
2193
|
-
'settings.hub.hubSteps.title':'Quick Setup (3 steps)',
|
|
2194
|
-
'settings.hub.hubSteps.s1':'Fill in Team Name below (or keep default)',
|
|
2195
|
-
'settings.hub.hubSteps.s2':'Click "Save Settings", then restart OpenClaw gateway',
|
|
2196
|
-
'settings.hub.hubSteps.s3':'Share the Hub Address and Team Token below with your team members',
|
|
2197
|
-
'settings.hub.clientSteps.title':'Quick Setup (3 steps)',
|
|
2198
|
-
'settings.hub.clientSteps.s1':'Ask your Hub admin for Hub Address and Team Token',
|
|
2199
|
-
'settings.hub.clientSteps.s2':'Fill them in below, click "Test Connection" to verify',
|
|
2200
|
-
'settings.hub.clientSteps.s3':'Click "Save Settings", restart OpenClaw gateway, then refresh this page',
|
|
2201
|
-
'settings.hub.shareInfo.title':'Share this info with your team members:',
|
|
2202
|
-
'settings.hub.shareInfo.yourIP':'your-IP',
|
|
2203
|
-
'settings.hub.shareInfo.clickCopy':'Click to copy',
|
|
2204
|
-
'settings.hub.restartAlert':'Hub sharing config saved! Please restart the OpenClaw gateway for changes to take effect, then refresh this page.\\n\\nRun: openclaw gateway stop && openclaw gateway start',
|
|
2205
|
-
'settings.hub.hubAddress':'Hub Address',
|
|
2206
|
-
'settings.hub.hubAddress.hint':'Hub server address, e.g. 192.168.1.100:18800',
|
|
2207
|
-
'settings.hub.teamTokenClient':'Team Token',
|
|
2208
|
-
'settings.hub.teamTokenClient.hint':'Get this from your Hub admin to join the team',
|
|
2209
|
-
'settings.hub.userToken':'User Token',
|
|
2210
|
-
'settings.hub.userToken.hint':'Usually auto-obtained after joining. Only fill if given by admin.',
|
|
2211
|
-
'settings.hub.testConnection':'Test Connection',
|
|
2212
|
-
'settings.hub.test.noAddr':'Please enter Hub address first',
|
|
2213
|
-
'settings.hub.test.testing':'Testing...',
|
|
2214
|
-
'settings.hub.test.ok':'Connected successfully',
|
|
2215
|
-
'settings.hub.test.fail':'Connection failed',
|
|
2216
|
-
'settings.hub.connection':'Connection Status',
|
|
2217
|
-
'settings.hub.team':'Team & Groups',
|
|
2218
|
-
'settings.hub.adminPending':'Admin Pending Users',
|
|
2219
|
-
'sidebar.hub':'\u{1F310} Team Sharing',
|
|
2220
|
-
'sharing.sidebar.connected':'Connected',
|
|
2221
|
-
'sharing.sidebar.disconnected':'Disconnected',
|
|
2222
|
-
'sharing.sidebar.pending':'Pending Approval',
|
|
2223
|
-
'sharing.sidebar.rejected':'Rejected',
|
|
2224
|
-
'sharing.sidebar.starting':'Starting...',
|
|
2225
|
-
'sharing.sidebar.notConfigured':'Not configured',
|
|
2226
|
-
'sharing.sidebar.identity':'Identity:',
|
|
2227
|
-
'sharing.sidebar.admin':'Admin',
|
|
2228
|
-
'sharing.sidebar.targetHub':'Target Hub:',
|
|
2229
|
-
'sharing.pendingApproval.hint':'Your join request has been submitted. Please wait for the Hub admin to approve.',
|
|
2230
|
-
'sharing.rejected.hint':'Your join request was rejected by the Hub admin. Please contact the admin or retry.',
|
|
2231
|
-
'sharing.retryJoin':'Retry Join',
|
|
2232
|
-
'sharing.retryJoin.hint':'Clears local data and re-submits the join request',
|
|
2233
|
-
'sharing.retryJoin.confirm':'This will clear your current connection and re-submit a join request. Continue?',
|
|
2234
|
-
'sharing.retryJoin.success':'Join request re-submitted. Waiting for admin approval.',
|
|
2235
|
-
'sharing.retryJoin.fail':'Failed to retry join',
|
|
2236
|
-
'sharing.cannotJoinSelf':'Cannot join your own Hub. Please enter a remote Hub address.',
|
|
2237
|
-
'scope.hub':'Hub',
|
|
2238
|
-
'memory.detail.title':'Memory Detail',
|
|
2239
|
-
'memory.detail.loading':'Loading...',
|
|
2240
|
-
'memory.detail.notFound':'Memory not found',
|
|
2241
|
-
'memory.detail.copyId':'Click to copy ID',
|
|
2242
|
-
'memory.detail.created':'Created ',
|
|
2243
|
-
'memory.detail.updated':'Updated ',
|
|
2244
|
-
'memory.detail.viewTarget':'View target: ',
|
|
2245
|
-
'admin.title':'Hub Admin Panel',
|
|
2246
|
-
'admin.subtitle':'Manage team members and shared resources',
|
|
2247
|
-
'admin.refresh':'\u21BB Refresh',
|
|
2248
|
-
'admin.tab.users':'Users',
|
|
2249
|
-
'admin.tab.groups':'Groups',
|
|
2250
|
-
'admin.tab.memories':'Shared Tasks',
|
|
2251
|
-
'admin.tab.skills':'Shared Skills',
|
|
2252
|
-
'admin.stat.activeUsers':'Active Users',
|
|
2253
|
-
'admin.stat.pending':'Pending',
|
|
2254
|
-
'admin.stat.groups':'Groups',
|
|
2255
|
-
'admin.stat.sharedTasks':'Shared Tasks',
|
|
2256
|
-
'admin.stat.sharedSkills':'Shared Skills',
|
|
2257
|
-
'admin.stat.sharedMemories':'Shared Memories',
|
|
2258
|
-
'admin.pendingApproval':'Pending Approval',
|
|
2259
|
-
'admin.activeUsers':'Active Users',
|
|
2260
|
-
'admin.noActiveUsers':'No active users.',
|
|
2261
|
-
'admin.approve':'Approve',
|
|
2262
|
-
'admin.reject':'Reject',
|
|
2263
|
-
'admin.device':'Device: ',
|
|
2264
|
-
'admin.groups':'Groups',
|
|
2265
|
-
'admin.newGroup':'+ New Group',
|
|
2266
|
-
'admin.groupName':'Group name',
|
|
2267
|
-
'admin.groupDesc':'Description (optional)',
|
|
2268
|
-
'admin.create':'Create',
|
|
2269
|
-
'admin.cancel':'Cancel',
|
|
2270
|
-
'admin.delete':'Delete',
|
|
2271
|
-
'admin.members':'Members',
|
|
2272
|
-
'admin.noGroups':'No groups created yet.',
|
|
2273
|
-
'admin.noMembers':'No members.',
|
|
2274
|
-
'admin.add':'Add',
|
|
2275
|
-
'admin.remove':'Remove',
|
|
2276
|
-
'admin.sharedTasks':'Shared Tasks',
|
|
2277
|
-
'admin.noSharedTasks':'No shared tasks on Hub.',
|
|
2278
|
-
'admin.owner':'Owner: ',
|
|
2279
|
-
'admin.group':'Group: ',
|
|
2280
|
-
'admin.chunks':'Chunks: ',
|
|
2281
|
-
'admin.updated':'Updated: ',
|
|
2282
|
-
'admin.sharedSkills':'Shared Skills',
|
|
2283
|
-
'admin.noSharedSkills':'No shared skills on Hub.',
|
|
2284
|
-
'admin.sharedMemories':'Shared Memories',
|
|
2285
|
-
'admin.noSharedMemories':'No shared memories on Hub.',
|
|
2286
|
-
'admin.tab.sharedMemories':'Shared Memories',
|
|
2287
|
-
'admin.version':'v',
|
|
2288
|
-
'admin.quality':'Quality: ',
|
|
2289
|
-
'admin.membersCount':'Members ({n}):',
|
|
2290
|
-
'admin.noMembersYet':'No members yet.',
|
|
2291
|
-
'admin.loadFailed':'Failed to load admin data: ',
|
|
2292
|
-
'admin.noPermission':'You do not have admin permissions to access this panel.',
|
|
2293
|
-
'admin.groupsFailed':'Failed to load groups: ',
|
|
2294
|
-
'toast.userApproved':'User approved',
|
|
2295
|
-
'toast.userRejected':'User rejected',
|
|
2296
|
-
'toast.approveFail':'Approve failed',
|
|
2297
|
-
'toast.rejectFail':'Reject failed',
|
|
2298
|
-
'toast.groupCreated':'Group created',
|
|
2299
|
-
'toast.groupDeleted':'Group deleted',
|
|
2300
|
-
'toast.memberAdded':'Member added',
|
|
2301
|
-
'toast.memberRemoved':'Member removed',
|
|
2302
|
-
'toast.taskRemoved':'Task removed',
|
|
2303
|
-
'toast.skillRemoved':'Skill removed',
|
|
2304
|
-
'toast.memoryRemoved':'Memory removed',
|
|
2305
|
-
'toast.createFail':'Create failed',
|
|
2306
|
-
'toast.deleteFail':'Delete failed',
|
|
2307
|
-
'toast.addFail':'Add failed',
|
|
2308
|
-
'toast.removeFail':'Remove failed',
|
|
2309
|
-
'toast.groupNameRequired':'Group name is required',
|
|
2310
|
-
'confirm.rejectUser':'Reject this user?',
|
|
2311
|
-
'confirm.removeGroupMember':'Remove this member from the group?',
|
|
2312
|
-
'confirm.removeMember':'Remove this member?',
|
|
2313
|
-
'confirm.deleteGroup':'Delete group "{name}"? Members will be removed.',
|
|
2314
|
-
'confirm.deleteGroupShort':'Delete group "{name}"?',
|
|
2315
|
-
'confirm.removeTask':'Remove shared task "{name}" from Hub? This cannot be undone.',
|
|
2316
|
-
'confirm.removeSkill':'Remove shared skill "{name}" from Hub? This cannot be undone.',
|
|
2317
|
-
'confirm.removeMemory':'Remove shared memory "{name}" from Hub? This cannot be undone.',
|
|
2318
|
-
'sharing.disabled':'Sharing disabled',
|
|
2319
|
-
'sharing.disabled.hint':'Enable sharing in plugin config to connect a Hub.',
|
|
2320
|
-
'sharing.hubAdmin':'Hub Admin',
|
|
2321
|
-
'sharing.client':'Client',
|
|
2322
|
-
'sharing.hubMode':'Hub mode',
|
|
2323
|
-
'sharing.hubMode.status':'Status: not connected to self',
|
|
2324
|
-
'sharing.hubMode.hint':'Configure sharing.client with hubAddress and userToken pointing to this Hub to enable admin UI.',
|
|
2325
|
-
'sharing.clientConfigured':'Client configured',
|
|
2326
|
-
'sharing.clientDisconnected':'Status: disconnected',
|
|
2327
|
-
'sharing.clientDisconnected.hint':'Viewer will keep showing local data; Hub actions may fail until the connection is restored.',
|
|
2328
|
-
'sharing.clientNotConfigured':'Client not configured',
|
|
2329
|
-
'sharing.clientNotConfigured.hint':'Set hubAddress and userToken in sharing.client to enable team features.',
|
|
2330
|
-
'sharing.settingsDisabled':'Sharing is disabled.',
|
|
2331
|
-
'sharing.settingsDisabled.hint':'Enable sharing in config to use Hub memory and skill collaboration.',
|
|
2332
|
-
'sharing.noTeam':'No team connection.',
|
|
2333
|
-
'sharing.adminUnavailable':'Admin tools unavailable.',
|
|
2334
|
-
'sharing.adminEnabled':'Admin controls enabled',
|
|
2335
|
-
'sharing.adminPendingHint':'Pending users will appear below.',
|
|
2336
|
-
'sharing.notAdmin':'Current user is not an admin.',
|
|
2337
|
-
'sharing.pendingLoadFail':'Failed to load pending users: ',
|
|
2338
|
-
'sharing.noPending':'No pending users.',
|
|
2339
|
-
'sharing.manageGroups':'Manage Groups',
|
|
2340
|
-
'sharing.openAdmin':'Open Admin Panel',
|
|
2341
|
-
'sharing.saveUsername':'Save',
|
|
2342
|
-
'sharing.username.invalid':'Username must be 2-32 characters',
|
|
2343
|
-
'sharing.username.taken':'Username already taken',
|
|
2344
|
-
'sharing.username.updated':'Username updated',
|
|
2345
|
-
'sharing.username.error':'Failed to update username',
|
|
2346
|
-
'sharing.hubNotConfigured':'Hub is running but client connection is not configured.',
|
|
2347
|
-
'sharing.hubNotConfigured.hint':'Add sharing.client.hubAddress and sharing.client.userToken pointing to this Hub to enable the admin interface.',
|
|
2348
|
-
'sharing.notConnected':'Not connected to Hub.',
|
|
2349
|
-
'sharing.role':'Role:',
|
|
2350
|
-
'sharing.mode':'Mode:',
|
|
2351
|
-
'sharing.role.hub':'Server (hosting the Hub)',
|
|
2352
|
-
'sharing.role.client':'Member (connected to Hub)',
|
|
2353
|
-
'sharing.clientConfiguredLabel':'Client configured:',
|
|
2354
|
-
'sharing.configuredHub':'Configured Hub:',
|
|
2355
|
-
'sharing.connected':'Connected:',
|
|
2356
|
-
'sharing.yes':'yes',
|
|
2357
|
-
'sharing.no':'no',
|
|
2358
|
-
'sharing.user':'User:',
|
|
2359
|
-
'sharing.team':'Team:',
|
|
2360
|
-
'sharing.groups':'Groups:',
|
|
2361
|
-
'sharing.loading':'Loading...',
|
|
2362
|
-
'sharing.loadingGroups':'Loading groups...',
|
|
2363
|
-
'sharing.noGroupsYet':'No groups yet.',
|
|
2364
|
-
'search.localResults':'Local Results',
|
|
2365
|
-
'search.hubResults':'Hub Results',
|
|
2366
|
-
'search.noLocal':'No local results.',
|
|
2367
|
-
'search.noHub':'No Hub results.',
|
|
2368
|
-
'search.viewDetail':'View Detail',
|
|
2369
|
-
'search.sharedMemory':'Shared Memory',
|
|
2370
|
-
'search.loadFailed':'Failed to load shared memory',
|
|
2371
|
-
'share.alreadyShared':'Shared',
|
|
2372
|
-
'share.shareBtn':'Share',
|
|
2373
|
-
'share.updateBtn':'Update',
|
|
2374
|
-
'share.unshareBtn':'Unshare',
|
|
2375
|
-
'toast.taskShared':'Task shared',
|
|
2376
|
-
'toast.taskShareFail':'Task share failed',
|
|
2377
|
-
'toast.taskUnshared':'Task unshared',
|
|
2378
|
-
'toast.taskUnshareFail':'Task unshare failed',
|
|
2379
|
-
'toast.memoryShared':'Memory shared',
|
|
2380
|
-
'toast.memoryShareFail':'Memory share failed',
|
|
2381
|
-
'toast.memoryUnshared':'Memory unshared',
|
|
2382
|
-
'toast.memoryUnshareFail':'Memory unshare failed',
|
|
2383
|
-
'toast.skillShared':'Skill shared',
|
|
2384
|
-
'toast.skillShareFail':'Skill share failed',
|
|
2385
|
-
'toast.skillUnshared':'Skill unshared',
|
|
2386
|
-
'toast.skillUnshareFail':'Skill unshare failed',
|
|
2387
|
-
'share.memoryVisibilityPrompt':'Share visibility (public or group):',
|
|
2388
|
-
'share.memoryUnshareConfirm':'Unshare this memory?',
|
|
2389
|
-
'share.group':'Group',
|
|
2390
|
-
'share.public':'Public',
|
|
2391
|
-
'toast.skillPulled':'Skill pulled to local storage',
|
|
2392
|
-
'toast.skillPullFail':'Skill pull failed',
|
|
2393
1677
|
'task.edit':'Edit',
|
|
2394
1678
|
'task.delete':'Delete',
|
|
2395
1679
|
'task.save':'Save',
|
|
@@ -2414,40 +1698,11 @@ const I18N={
|
|
|
2414
1698
|
'update.installing':'Installing...',
|
|
2415
1699
|
'update.success':'Updated!',
|
|
2416
1700
|
'update.failed':'Update failed',
|
|
2417
|
-
'update.restarting':'Restarting service
|
|
2418
|
-
'update.dismiss':'Dismiss'
|
|
2419
|
-
'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?',
|
|
2420
|
-
'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?',
|
|
2421
|
-
'sharing.disable.restartAlert':'Sharing has been disabled. Please restart the OpenClaw gateway for the change to take effect, then refresh this page.\\n\\nRun: openclaw gateway stop && openclaw gateway start',
|
|
2422
|
-
'admin.notEnabled.title':'Team sharing is not enabled',
|
|
2423
|
-
'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.',
|
|
2424
|
-
'admin.notEnabled.setupHub':'Set Up as Hub Server',
|
|
2425
|
-
'admin.notEnabled.joinTeam':'Join an Existing Team',
|
|
2426
|
-
'admin.notEnabled.hint':'If you have previously configured sharing, your data is still preserved. Re-enabling sharing will restore access to all shared content.',
|
|
2427
|
-
'sharing.disconnected.hint':'Unable to reach the Hub server. The Hub may be offline or the network is unavailable.',
|
|
2428
|
-
'sharing.retryConnection':'Retry Connection',
|
|
2429
|
-
'sharing.retryConnection.loading':'Connecting...',
|
|
2430
|
-
'sharing.retryConnection.success':'Connected successfully!',
|
|
2431
|
-
'sharing.retryConnection.fail':'Still unable to connect. Check if the Hub is online.',
|
|
2432
|
-
'guide.title':'Get Started with Team Collaboration',
|
|
2433
|
-
'guide.subtitle':'MemOS supports team memory sharing. Choose one of the following options to enable collaboration, or continue using local-only mode.',
|
|
2434
|
-
'guide.join.title':'Join a Remote Team',
|
|
2435
|
-
'guide.join.desc':'Your team already has a Hub running? Join it to share memories, tasks and skills with team members.',
|
|
2436
|
-
'guide.join.s1':'Ask your Hub admin for the Hub Address and Team Token',
|
|
2437
|
-
'guide.join.s2':'Go to Settings \u2192 Hub & Team, enable sharing, select "Client" mode',
|
|
2438
|
-
'guide.join.s3':'Fill in Hub Address and Team Token, click "Test Connection"',
|
|
2439
|
-
'guide.join.s4':'Save settings, restart the OpenClaw gateway, then refresh this page',
|
|
2440
|
-
'guide.join.btn':'\u2192 Configure Client Mode',
|
|
2441
|
-
'guide.hub.title':'Start Your Own Hub',
|
|
2442
|
-
'guide.hub.desc':'Be the team server. Run a Hub on this device so others can connect and share memories with you.',
|
|
2443
|
-
'guide.hub.s1':'Go to Settings \u2192 Hub & Team, enable sharing, select "Hub" mode',
|
|
2444
|
-
'guide.hub.s2':'Set a team name, save settings, restart the gateway, then refresh this page',
|
|
2445
|
-
'guide.hub.s3':'Share the Hub Address and Team Token with your team members',
|
|
2446
|
-
'guide.hub.s4':'Approve join requests in the Admin Panel',
|
|
2447
|
-
'guide.hub.btn':'\u2192 Configure Hub Mode'
|
|
1701
|
+
'update.restarting':'Restarting service...',
|
|
1702
|
+
'update.dismiss':'Dismiss'
|
|
2448
1703
|
},
|
|
2449
1704
|
zh:{
|
|
2450
|
-
'title':'
|
|
1705
|
+
'title':'OpenClaw 记忆',
|
|
2451
1706
|
'subtitle':'由 MemOS 驱动',
|
|
2452
1707
|
'setup.desc':'设置密码以保护你的记忆数据',
|
|
2453
1708
|
'setup.pw':'输入密码(至少4位)',
|
|
@@ -2487,14 +1742,6 @@ const I18N={
|
|
|
2487
1742
|
'skills.active':'生效中',
|
|
2488
1743
|
'skills.installed':'已安装',
|
|
2489
1744
|
'skills.public':'公开',
|
|
2490
|
-
'skills.search.placeholder':'搜索技能...',
|
|
2491
|
-
'skills.search.local':'本地',
|
|
2492
|
-
'skills.search.noresult':'未找到匹配的技能',
|
|
2493
|
-
'skills.load.error':'加载技能失败',
|
|
2494
|
-
'skills.hub.title':'\u{1F310} Hub 共享技能',
|
|
2495
|
-
'scope.local':'本地',
|
|
2496
|
-
'scope.group':'团队',
|
|
2497
|
-
'scope.all':'全部',
|
|
2498
1745
|
'skills.visibility.public':'公开',
|
|
2499
1746
|
'skills.visibility.private':'私有',
|
|
2500
1747
|
'skills.setPublic':'设为公开',
|
|
@@ -2533,7 +1780,6 @@ const I18N={
|
|
|
2533
1780
|
'filter.newest':'最新优先',
|
|
2534
1781
|
'filter.oldest':'最早优先',
|
|
2535
1782
|
'filter.allowners':'所有归属',
|
|
2536
|
-
'filter.allsessions':'全部会话',
|
|
2537
1783
|
'filter.public':'公开',
|
|
2538
1784
|
'filter.private':'私有',
|
|
2539
1785
|
'filter.allvisibility':'所有可见性',
|
|
@@ -2614,22 +1860,11 @@ const I18N={
|
|
|
2614
1860
|
'tab.import':'\u{1F4E5} 导入',
|
|
2615
1861
|
'tab.settings':'\u2699 设置',
|
|
2616
1862
|
'settings.modelconfig':'模型配置',
|
|
2617
|
-
'settings.models':'AI 模型',
|
|
2618
|
-
'settings.models.desc':'配置嵌入模型、摘要模型和技能进化模型',
|
|
2619
1863
|
'settings.modelhealth':'模型健康',
|
|
2620
1864
|
'settings.embedding':'嵌入模型',
|
|
2621
1865
|
'settings.summarizer':'摘要模型',
|
|
2622
1866
|
'settings.skill':'技能进化',
|
|
2623
1867
|
'settings.general':'通用设置',
|
|
2624
|
-
'settings.embedding.desc':'向量嵌入模型,用于记忆检索和语义搜索',
|
|
2625
|
-
'settings.summarizer.desc':'大语言模型,用于记忆摘要、去重和分析',
|
|
2626
|
-
'settings.skill.desc':'从对话模式中自动提取可复用的技能',
|
|
2627
|
-
'settings.hub.desc':'与团队共享记忆、任务和技能',
|
|
2628
|
-
'settings.general.desc':'系统状态、端口和数据统计',
|
|
2629
|
-
'settings.hostproxy.embedding':'复用网关模型',
|
|
2630
|
-
'settings.hostproxy.completion':'复用网关模型',
|
|
2631
|
-
'settings.hostproxy.skill':'复用网关模型',
|
|
2632
|
-
'settings.hostproxy.hint.short':'复用网关已有的模型配置',
|
|
2633
1868
|
'settings.provider':'服务商',
|
|
2634
1869
|
'settings.model':'模型',
|
|
2635
1870
|
'settings.temperature':'温度',
|
|
@@ -2638,12 +1873,12 @@ const I18N={
|
|
|
2638
1873
|
'settings.skill.confidence':'最低置信度',
|
|
2639
1874
|
'settings.skill.minchunks':'最少记忆片段',
|
|
2640
1875
|
'settings.skill.model':'技能专用模型',
|
|
2641
|
-
'settings.skill.model.hint':'
|
|
1876
|
+
'settings.skill.model.hint':'不配置时默认使用上方的摘要模型进行技能生成。如需更高质量的技能输出,可在此单独配置一个更强的模型。',
|
|
2642
1877
|
'settings.optional':'可选',
|
|
2643
1878
|
'settings.skill.usemain':'使用主摘要模型',
|
|
2644
1879
|
'settings.telemetry':'数据统计',
|
|
2645
1880
|
'settings.telemetry.enabled':'启用匿名数据统计',
|
|
2646
|
-
'settings.telemetry.hint':'
|
|
1881
|
+
'settings.telemetry.hint':'匿名使用统计,帮助改进插件。仅发送工具名称、响应时间和版本信息,不会发送任何记忆内容、搜索查询或个人数据。',
|
|
2647
1882
|
'settings.viewerport':'Viewer 端口',
|
|
2648
1883
|
'settings.viewerport.hint':'修改后需重启网关生效',
|
|
2649
1884
|
'settings.test':'测试连接',
|
|
@@ -2654,7 +1889,7 @@ const I18N={
|
|
|
2654
1889
|
'settings.save':'保存设置',
|
|
2655
1890
|
'settings.reset':'重置',
|
|
2656
1891
|
'settings.saved':'已保存',
|
|
2657
|
-
'settings.restart.hint':'部分设置修改后需要重启 OpenClaw
|
|
1892
|
+
'settings.restart.hint':'部分设置修改后需要重启 OpenClaw 网关才能生效。',
|
|
2658
1893
|
'settings.save.fail':'保存设置失败',
|
|
2659
1894
|
'settings.save.emb.required':'嵌入模型为必填项,请先配置嵌入模型再保存。',
|
|
2660
1895
|
'settings.save.emb.fail':'嵌入模型测试失败,无法保存',
|
|
@@ -2740,7 +1975,7 @@ const I18N={
|
|
|
2740
1975
|
'skills.related':'关联任务',
|
|
2741
1976
|
'skills.download':'\u2B07 下载',
|
|
2742
1977
|
'skills.installed.badge':'已安装',
|
|
2743
|
-
'skills.empty':'
|
|
1978
|
+
'skills.empty':'暂无技能。技能会从已完成的、包含可复用经验的任务中自动生成。',
|
|
2744
1979
|
'skills.loading':'加载中...',
|
|
2745
1980
|
'skills.error':'加载技能失败',
|
|
2746
1981
|
'skills.error.detail':'加载技能失败:',
|
|
@@ -2761,222 +1996,6 @@ const I18N={
|
|
|
2761
1996
|
'tasks.error':'出错了',
|
|
2762
1997
|
'tasks.error.detail':'加载任务详情失败',
|
|
2763
1998
|
'tasks.untitled.related':'未命名',
|
|
2764
|
-
'tab.admin':'\u{1F6E1} 管理',
|
|
2765
|
-
'settings.hub':'Hub 与团队',
|
|
2766
|
-
'settings.hub.enable':'启用 Hub 共享',
|
|
2767
|
-
'settings.hub.enable.hint':'关闭时仅本地使用,不影响其他功能。',
|
|
2768
|
-
'settings.hub.enable.label':'启用 Hub 共享',
|
|
2769
|
-
'settings.hub.role':'角色',
|
|
2770
|
-
'settings.hub.role.hub':'Hub(服务端)',
|
|
2771
|
-
'settings.hub.role.client':'Client(连接到 Hub)',
|
|
2772
|
-
'settings.hub.role.hint':'Hub = 本机做服务端;Client = 连接别人的服务端。两种模式互斥,不能同时使用。',
|
|
2773
|
-
'settings.hub.port':'Hub 端口',
|
|
2774
|
-
'settings.hub.port.hint':'Hub 服务端口,默认 18800',
|
|
2775
|
-
'settings.hub.teamName':'团队名称',
|
|
2776
|
-
'settings.hub.teamName.hint':'你的团队显示名称',
|
|
2777
|
-
'settings.hub.teamToken':'团队令牌',
|
|
2778
|
-
'settings.hub.teamToken.hint':'自动生成的密钥,点击可复制。请将此令牌分享给团队成员。',
|
|
2779
|
-
'settings.hub.tokenCopied':'团队令牌已复制!',
|
|
2780
|
-
'settings.hub.hubSteps.title':'快速配置(3 步)',
|
|
2781
|
-
'settings.hub.hubSteps.s1':'填写下方团队名称(或保持默认)',
|
|
2782
|
-
'settings.hub.hubSteps.s2':'点击"保存设置",然后重启 OpenClaw 网关',
|
|
2783
|
-
'settings.hub.hubSteps.s3':'将下方的 Hub 地址和团队令牌分享给团队成员',
|
|
2784
|
-
'settings.hub.clientSteps.title':'快速配置(3 步)',
|
|
2785
|
-
'settings.hub.clientSteps.s1':'向 Hub 管理员获取 Hub 地址和团队令牌',
|
|
2786
|
-
'settings.hub.clientSteps.s2':'填入下方,点击"测试连接"验证连通性',
|
|
2787
|
-
'settings.hub.clientSteps.s3':'点击「保存设置」,重启 OpenClaw 网关,然后刷新此页面',
|
|
2788
|
-
'settings.hub.shareInfo.title':'请将以下信息分享给团队成员:',
|
|
2789
|
-
'settings.hub.shareInfo.yourIP':'你的IP',
|
|
2790
|
-
'settings.hub.shareInfo.clickCopy':'点击复制',
|
|
2791
|
-
'settings.hub.restartAlert':'Hub 共享配置已保存!请重启 OpenClaw 网关使配置生效,重启后请刷新此页面。\\n\\n执行命令:openclaw gateway stop && openclaw gateway start',
|
|
2792
|
-
'settings.hub.hubAddress':'Hub 地址',
|
|
2793
|
-
'settings.hub.hubAddress.hint':'Hub 服务器地址,如 192.168.1.100:18800',
|
|
2794
|
-
'settings.hub.teamTokenClient':'团队令牌',
|
|
2795
|
-
'settings.hub.teamTokenClient.hint':'向 Hub 管理员获取此令牌以加入团队',
|
|
2796
|
-
'settings.hub.userToken':'用户令牌',
|
|
2797
|
-
'settings.hub.userToken.hint':'通常在加入团队后自动获取,无需手动填写。',
|
|
2798
|
-
'settings.hub.testConnection':'测试连接',
|
|
2799
|
-
'settings.hub.test.noAddr':'请先输入 Hub 地址',
|
|
2800
|
-
'settings.hub.test.testing':'测试中...',
|
|
2801
|
-
'settings.hub.test.ok':'连接成功',
|
|
2802
|
-
'settings.hub.test.fail':'连接失败',
|
|
2803
|
-
'settings.hub.connection':'连接状态',
|
|
2804
|
-
'settings.hub.team':'团队与分组',
|
|
2805
|
-
'settings.hub.adminPending':'管理员待审用户',
|
|
2806
|
-
'sidebar.hub':'\u{1F310} 团队共享',
|
|
2807
|
-
'sharing.sidebar.connected':'已连接',
|
|
2808
|
-
'sharing.sidebar.disconnected':'已断开',
|
|
2809
|
-
'sharing.sidebar.pending':'等待审核',
|
|
2810
|
-
'sharing.sidebar.rejected':'已拒绝',
|
|
2811
|
-
'sharing.sidebar.starting':'启动中...',
|
|
2812
|
-
'sharing.sidebar.notConfigured':'未配置',
|
|
2813
|
-
'sharing.sidebar.identity':'身份:',
|
|
2814
|
-
'sharing.sidebar.admin':'管理员',
|
|
2815
|
-
'sharing.sidebar.targetHub':'目标 Hub:',
|
|
2816
|
-
'sharing.pendingApproval.hint':'加入申请已提交,请等待 Hub 管理员审核通过。',
|
|
2817
|
-
'sharing.rejected.hint':'您的加入申请已被 Hub 管理员拒绝,请联系管理员或重新申请。',
|
|
2818
|
-
'sharing.retryJoin':'重新申请',
|
|
2819
|
-
'sharing.retryJoin.hint':'清除本地连接数据并重新提交加入申请',
|
|
2820
|
-
'sharing.retryJoin.confirm':'这将清除当前连接数据并重新提交加入申请,是否继续?',
|
|
2821
|
-
'sharing.retryJoin.success':'加入申请已重新提交,请等待管理员审核。',
|
|
2822
|
-
'sharing.retryJoin.fail':'重新申请失败',
|
|
2823
|
-
'sharing.cannotJoinSelf':'不能加入自己的 Hub,请输入远程 Hub 地址。',
|
|
2824
|
-
'scope.hub':'Hub',
|
|
2825
|
-
'memory.detail.title':'记忆详情',
|
|
2826
|
-
'memory.detail.loading':'加载中...',
|
|
2827
|
-
'memory.detail.notFound':'未找到该记忆',
|
|
2828
|
-
'memory.detail.copyId':'点击复制 ID',
|
|
2829
|
-
'memory.detail.created':'创建于 ',
|
|
2830
|
-
'memory.detail.updated':'更新于 ',
|
|
2831
|
-
'memory.detail.viewTarget':'查看目标: ',
|
|
2832
|
-
'admin.title':'Hub 管理面板',
|
|
2833
|
-
'admin.subtitle':'管理团队成员和共享资源',
|
|
2834
|
-
'admin.refresh':'\u21BB 刷新',
|
|
2835
|
-
'admin.tab.users':'用户',
|
|
2836
|
-
'admin.tab.groups':'分组',
|
|
2837
|
-
'admin.tab.memories':'共享任务',
|
|
2838
|
-
'admin.tab.skills':'共享技能',
|
|
2839
|
-
'admin.stat.activeUsers':'活跃用户',
|
|
2840
|
-
'admin.stat.pending':'待审核',
|
|
2841
|
-
'admin.stat.groups':'分组',
|
|
2842
|
-
'admin.stat.sharedTasks':'共享任务',
|
|
2843
|
-
'admin.stat.sharedSkills':'共享技能',
|
|
2844
|
-
'admin.stat.sharedMemories':'共享记忆',
|
|
2845
|
-
'admin.pendingApproval':'待审批',
|
|
2846
|
-
'admin.activeUsers':'活跃用户',
|
|
2847
|
-
'admin.noActiveUsers':'暂无活跃用户。',
|
|
2848
|
-
'admin.approve':'批准',
|
|
2849
|
-
'admin.reject':'拒绝',
|
|
2850
|
-
'admin.device':'设备:',
|
|
2851
|
-
'admin.groups':'分组',
|
|
2852
|
-
'admin.newGroup':'+ 新建分组',
|
|
2853
|
-
'admin.groupName':'分组名称',
|
|
2854
|
-
'admin.groupDesc':'描述(可选)',
|
|
2855
|
-
'admin.create':'创建',
|
|
2856
|
-
'admin.cancel':'取消',
|
|
2857
|
-
'admin.delete':'删除',
|
|
2858
|
-
'admin.members':'成员',
|
|
2859
|
-
'admin.noGroups':'暂无分组。',
|
|
2860
|
-
'admin.noMembers':'暂无成员。',
|
|
2861
|
-
'admin.add':'添加',
|
|
2862
|
-
'admin.remove':'移除',
|
|
2863
|
-
'admin.sharedTasks':'共享任务',
|
|
2864
|
-
'admin.noSharedTasks':'Hub 上暂无共享任务。',
|
|
2865
|
-
'admin.owner':'归属:',
|
|
2866
|
-
'admin.group':'分组:',
|
|
2867
|
-
'admin.chunks':'记忆片段:',
|
|
2868
|
-
'admin.updated':'更新于:',
|
|
2869
|
-
'admin.sharedSkills':'共享技能',
|
|
2870
|
-
'admin.noSharedSkills':'Hub 上暂无共享技能。',
|
|
2871
|
-
'admin.sharedMemories':'共享记忆',
|
|
2872
|
-
'admin.noSharedMemories':'Hub 上暂无共享记忆。',
|
|
2873
|
-
'admin.tab.sharedMemories':'共享记忆',
|
|
2874
|
-
'admin.version':'v',
|
|
2875
|
-
'admin.quality':'质量:',
|
|
2876
|
-
'admin.membersCount':'成员({n}):',
|
|
2877
|
-
'admin.noMembersYet':'暂无成员。',
|
|
2878
|
-
'admin.loadFailed':'加载管理数据失败:',
|
|
2879
|
-
'admin.noPermission':'您没有管理员权限,无法访问此面板。',
|
|
2880
|
-
'admin.groupsFailed':'加载分组失败:',
|
|
2881
|
-
'toast.userApproved':'用户已批准',
|
|
2882
|
-
'toast.userRejected':'用户已拒绝',
|
|
2883
|
-
'toast.approveFail':'批准失败',
|
|
2884
|
-
'toast.rejectFail':'拒绝失败',
|
|
2885
|
-
'toast.groupCreated':'分组已创建',
|
|
2886
|
-
'toast.groupDeleted':'分组已删除',
|
|
2887
|
-
'toast.memberAdded':'成员已添加',
|
|
2888
|
-
'toast.memberRemoved':'成员已移除',
|
|
2889
|
-
'toast.taskRemoved':'任务已移除',
|
|
2890
|
-
'toast.skillRemoved':'技能已移除',
|
|
2891
|
-
'toast.memoryRemoved':'记忆已移除',
|
|
2892
|
-
'toast.createFail':'创建失败',
|
|
2893
|
-
'toast.deleteFail':'删除失败',
|
|
2894
|
-
'toast.addFail':'添加失败',
|
|
2895
|
-
'toast.removeFail':'移除失败',
|
|
2896
|
-
'toast.groupNameRequired':'请输入分组名称',
|
|
2897
|
-
'confirm.rejectUser':'确定要拒绝此用户吗?',
|
|
2898
|
-
'confirm.removeGroupMember':'确定要将此成员移出分组吗?',
|
|
2899
|
-
'confirm.removeMember':'确定要移除此成员吗?',
|
|
2900
|
-
'confirm.deleteGroup':'确定要删除分组「{name}」吗?成员将被移除。',
|
|
2901
|
-
'confirm.deleteGroupShort':'确定要删除分组「{name}」吗?',
|
|
2902
|
-
'confirm.removeTask':'确定要从 Hub 移除共享任务「{name}」吗?此操作不可撤销。',
|
|
2903
|
-
'confirm.removeSkill':'确定要从 Hub 移除共享技能「{name}」吗?此操作不可撤销。',
|
|
2904
|
-
'confirm.removeMemory':'确定要从 Hub 移除共享记忆「{name}」吗?此操作不可撤销。',
|
|
2905
|
-
'sharing.disabled':'共享已禁用',
|
|
2906
|
-
'sharing.disabled.hint':'在插件配置中启用共享以连接 Hub。',
|
|
2907
|
-
'sharing.hubAdmin':'Hub 管理员',
|
|
2908
|
-
'sharing.client':'客户端',
|
|
2909
|
-
'sharing.hubMode':'Hub 模式',
|
|
2910
|
-
'sharing.hubMode.status':'状态:未连接到自身',
|
|
2911
|
-
'sharing.hubMode.hint':'配置 sharing.client 的 hubAddress 和 userToken 指向此 Hub 以启用管理界面。',
|
|
2912
|
-
'sharing.clientConfigured':'客户端已配置',
|
|
2913
|
-
'sharing.clientDisconnected':'状态:已断开',
|
|
2914
|
-
'sharing.clientDisconnected.hint':'查看器将继续显示本地数据;Hub 操作可能在连接恢复前失败。',
|
|
2915
|
-
'sharing.clientNotConfigured':'客户端未配置',
|
|
2916
|
-
'sharing.clientNotConfigured.hint':'设置 sharing.client 中的 hubAddress 和 userToken 以启用团队功能。',
|
|
2917
|
-
'sharing.settingsDisabled':'共享已禁用。',
|
|
2918
|
-
'sharing.settingsDisabled.hint':'在配置中启用共享以使用 Hub 记忆和技能协作。',
|
|
2919
|
-
'sharing.noTeam':'无团队连接。',
|
|
2920
|
-
'sharing.adminUnavailable':'管理工具不可用。',
|
|
2921
|
-
'sharing.adminEnabled':'管理控制已启用',
|
|
2922
|
-
'sharing.adminPendingHint':'待审用户将显示在下方。',
|
|
2923
|
-
'sharing.notAdmin':'当前用户不是管理员。',
|
|
2924
|
-
'sharing.pendingLoadFail':'加载待审用户失败:',
|
|
2925
|
-
'sharing.noPending':'暂无待审用户。',
|
|
2926
|
-
'sharing.manageGroups':'管理分组',
|
|
2927
|
-
'sharing.openAdmin':'打开管理面板',
|
|
2928
|
-
'sharing.saveUsername':'保存',
|
|
2929
|
-
'sharing.username.invalid':'用户名需 2-32 个字符',
|
|
2930
|
-
'sharing.username.taken':'用户名已被占用',
|
|
2931
|
-
'sharing.username.updated':'用户名已更新',
|
|
2932
|
-
'sharing.username.error':'更新用户名失败',
|
|
2933
|
-
'sharing.hubNotConfigured':'Hub 正在运行,但客户端连接未配置。',
|
|
2934
|
-
'sharing.hubNotConfigured.hint':'添加 sharing.client.hubAddress 和 sharing.client.userToken 指向此 Hub 以启用管理界面。',
|
|
2935
|
-
'sharing.notConnected':'未连接到 Hub。',
|
|
2936
|
-
'sharing.role':'角色:',
|
|
2937
|
-
'sharing.mode':'身份:',
|
|
2938
|
-
'sharing.role.hub':'服务端(Hub 主机)',
|
|
2939
|
-
'sharing.role.client':'成员(连接到 Hub)',
|
|
2940
|
-
'sharing.clientConfiguredLabel':'客户端已配置:',
|
|
2941
|
-
'sharing.configuredHub':'配置的 Hub:',
|
|
2942
|
-
'sharing.connected':'已连接:',
|
|
2943
|
-
'sharing.yes':'是',
|
|
2944
|
-
'sharing.no':'否',
|
|
2945
|
-
'sharing.user':'用户:',
|
|
2946
|
-
'sharing.team':'团队:',
|
|
2947
|
-
'sharing.groups':'分组:',
|
|
2948
|
-
'sharing.loading':'加载中...',
|
|
2949
|
-
'sharing.loadingGroups':'正在加载分组...',
|
|
2950
|
-
'sharing.noGroupsYet':'暂无分组。',
|
|
2951
|
-
'search.localResults':'本地结果',
|
|
2952
|
-
'search.hubResults':'Hub 结果',
|
|
2953
|
-
'search.noLocal':'无本地结果。',
|
|
2954
|
-
'search.noHub':'无 Hub 结果。',
|
|
2955
|
-
'search.viewDetail':'查看详情',
|
|
2956
|
-
'search.sharedMemory':'共享记忆',
|
|
2957
|
-
'search.loadFailed':'加载共享记忆失败',
|
|
2958
|
-
'share.alreadyShared':'已共享',
|
|
2959
|
-
'share.shareBtn':'共享',
|
|
2960
|
-
'share.updateBtn':'更新共享',
|
|
2961
|
-
'share.unshareBtn':'取消共享',
|
|
2962
|
-
'toast.taskShared':'任务已共享',
|
|
2963
|
-
'toast.taskShareFail':'任务共享失败',
|
|
2964
|
-
'toast.taskUnshared':'任务已取消共享',
|
|
2965
|
-
'toast.taskUnshareFail':'取消共享失败',
|
|
2966
|
-
'toast.memoryShared':'记忆已共享',
|
|
2967
|
-
'toast.memoryShareFail':'记忆共享失败',
|
|
2968
|
-
'toast.memoryUnshared':'记忆已取消共享',
|
|
2969
|
-
'toast.memoryUnshareFail':'记忆取消共享失败',
|
|
2970
|
-
'toast.skillShared':'技能已共享',
|
|
2971
|
-
'toast.skillShareFail':'技能共享失败',
|
|
2972
|
-
'toast.skillUnshared':'技能已取消共享',
|
|
2973
|
-
'toast.skillUnshareFail':'技能取消共享失败',
|
|
2974
|
-
'share.memoryVisibilityPrompt':'共享可见性(public 或 group):',
|
|
2975
|
-
'share.memoryUnshareConfirm':'取消共享此记忆?',
|
|
2976
|
-
'share.group':'团队',
|
|
2977
|
-
'share.public':'公开',
|
|
2978
|
-
'toast.skillPulled':'技能已拉取到本地',
|
|
2979
|
-
'toast.skillPullFail':'技能拉取失败',
|
|
2980
1999
|
'task.edit':'编辑',
|
|
2981
2000
|
'task.delete':'删除',
|
|
2982
2001
|
'task.save':'保存',
|
|
@@ -3001,37 +2020,8 @@ const I18N={
|
|
|
3001
2020
|
'update.installing':'安装中...',
|
|
3002
2021
|
'update.success':'更新完成',
|
|
3003
2022
|
'update.failed':'更新失败',
|
|
3004
|
-
'update.restarting':'
|
|
3005
|
-
'update.dismiss':'关闭'
|
|
3006
|
-
'sharing.disable.confirm.hub':'你即将关闭 Hub 服务。\\n\\n关闭后将会:\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 他们将无法继续同步记忆、任务和技能\\n\\u2022 已共享的数据会保留,重新开启后仍可使用\\n\\n确定要关闭吗?',
|
|
3007
|
-
'sharing.disable.confirm.client':'你即将断开与团队 Hub 的连接。\\n\\n断开后将会:\\n\\u2022 你将无法再接收团队共享的记忆、任务和技能\\n\\u2022 你的本地数据不受影响,会完整保留\\n\\u2022 之后可以随时重新开启共享来恢复连接\\n\\n确定要断开吗?',
|
|
3008
|
-
'sharing.disable.restartAlert':'共享已关闭。请重启 OpenClaw 网关使更改生效,重启后请刷新此页面。\\n\\n执行命令:openclaw gateway stop && openclaw gateway start',
|
|
3009
|
-
'admin.notEnabled.title':'团队共享尚未开启',
|
|
3010
|
-
'admin.notEnabled.desc':'管理面板用于管理团队成员、共享的记忆、任务和技能。使用此功能前,需要先开启 Hub 共享。',
|
|
3011
|
-
'admin.notEnabled.setupHub':'配置为 Hub 服务端',
|
|
3012
|
-
'admin.notEnabled.joinTeam':'加入已有团队',
|
|
3013
|
-
'admin.notEnabled.hint':'如果之前配置过共享,你的数据仍然保留。重新开启共享即可恢复访问所有共享内容。',
|
|
3014
|
-
'sharing.disconnected.hint':'无法连接到 Hub 服务器,Hub 可能已下线或网络不可用。',
|
|
3015
|
-
'sharing.retryConnection':'重试连接',
|
|
3016
|
-
'sharing.retryConnection.loading':'连接中...',
|
|
3017
|
-
'sharing.retryConnection.success':'连接成功!',
|
|
3018
|
-
'sharing.retryConnection.fail':'仍然无法连接,请检查 Hub 是否在线。',
|
|
3019
|
-
'guide.title':'开始团队协作',
|
|
3020
|
-
'guide.subtitle':'MemOS 支持团队记忆共享。选择以下方式之一开启协作,或继续使用纯本地模式。',
|
|
3021
|
-
'guide.join.title':'加入远程团队',
|
|
3022
|
-
'guide.join.desc':'你的团队已有 Hub 在运行?加入即可与团队成员共享记忆、任务和技能。',
|
|
3023
|
-
'guide.join.s1':'向 Hub 管理员索取 Hub 地址和 Team Token',
|
|
3024
|
-
'guide.join.s2':'前往「设置 → Hub & Team」,开启共享,选择「Client」模式',
|
|
3025
|
-
'guide.join.s3':'填写 Hub 地址和 Team Token,点击「测试连接」',
|
|
3026
|
-
'guide.join.s4':'保存设置,重启 OpenClaw 网关,然后刷新此页面',
|
|
3027
|
-
'guide.join.btn':'\u2192 配置 Client 模式',
|
|
3028
|
-
'guide.hub.title':'自建 Hub 服务',
|
|
3029
|
-
'guide.hub.desc':'将本机作为团队服务端,让其他成员连接过来共享记忆。',
|
|
3030
|
-
'guide.hub.s1':'前往「设置 → Hub & Team」,开启共享,选择「Hub」模式',
|
|
3031
|
-
'guide.hub.s2':'设置团队名称,保存设置后重启网关,然后刷新此页面',
|
|
3032
|
-
'guide.hub.s3':'将 Hub 地址和 Team Token 分享给团队成员',
|
|
3033
|
-
'guide.hub.s4':'在管理面板中审批加入请求',
|
|
3034
|
-
'guide.hub.btn':'\u2192 配置 Hub 模式'
|
|
2023
|
+
'update.restarting':'正在重启服务...',
|
|
2024
|
+
'update.dismiss':'关闭'
|
|
3035
2025
|
}
|
|
3036
2026
|
};
|
|
3037
2027
|
const LANG_KEY='memos-viewer-lang';
|
|
@@ -3133,112 +2123,11 @@ async function doReset(){
|
|
|
3133
2123
|
else{err.textContent=d.error||t('reset.err.fail')}
|
|
3134
2124
|
}
|
|
3135
2125
|
|
|
3136
|
-
var _sharingRole='client';
|
|
3137
|
-
function _genToken(len){
|
|
3138
|
-
var a=new Uint8Array(len||18);crypto.getRandomValues(a);
|
|
3139
|
-
return btoa(String.fromCharCode.apply(null,a)).replace(/\\+/g,'-').replace(/\\//g,'_').replace(/=+$/,'');
|
|
3140
|
-
}
|
|
3141
|
-
function onSharingToggle(){
|
|
3142
|
-
var on=document.getElementById('cfgSharingEnabled').checked;
|
|
3143
|
-
document.getElementById('sharingConfigPanel').style.display=on?'block':'none';
|
|
3144
|
-
if(on) selectSharingRole(_sharingRole);
|
|
3145
|
-
}
|
|
3146
|
-
function selectSharingRole(role){
|
|
3147
|
-
_sharingRole=role;
|
|
3148
|
-
document.getElementById('btnRoleHub').className='btn btn-sm'+(role==='hub'?' btn-primary':'');
|
|
3149
|
-
document.getElementById('btnRoleClient').className='btn btn-sm'+(role==='client'?' btn-primary':'');
|
|
3150
|
-
document.getElementById('hubModeConfig').style.display=role==='hub'?'block':'none';
|
|
3151
|
-
document.getElementById('clientModeConfig').style.display=role==='client'?'block':'none';
|
|
3152
|
-
var sp=document.getElementById('sharingStatusPanel');
|
|
3153
|
-
var tp=document.getElementById('sharingTeamPanel');
|
|
3154
|
-
var ap=document.getElementById('sharingAdminPanel');
|
|
3155
|
-
if(role==='client'){
|
|
3156
|
-
if(sp) sp.style.display='none';
|
|
3157
|
-
if(tp) tp.style.display='none';
|
|
3158
|
-
if(ap) ap.style.display='none';
|
|
3159
|
-
}else{
|
|
3160
|
-
if(sp) sp.style.display='';
|
|
3161
|
-
if(tp) tp.style.display='';
|
|
3162
|
-
if(ap) ap.style.display='';
|
|
3163
|
-
}
|
|
3164
|
-
if(role==='hub'){
|
|
3165
|
-
var tk=document.getElementById('cfgHubTeamToken');
|
|
3166
|
-
if(!tk.value.trim()) tk.value=_genToken(18);
|
|
3167
|
-
var tn=document.getElementById('cfgHubTeamName');
|
|
3168
|
-
if(!tn.value.trim()) tn.value='My Team';
|
|
3169
|
-
}
|
|
3170
|
-
}
|
|
3171
|
-
var _cachedLocalIP='';
|
|
3172
|
-
function updateHubShareInfo(){
|
|
3173
|
-
var panel=document.getElementById('hubShareInfo');
|
|
3174
|
-
var content=document.getElementById('hubShareInfoContent');
|
|
3175
|
-
if(!panel||!content) return;
|
|
3176
|
-
var tokenEl=document.getElementById('cfgHubTeamToken');
|
|
3177
|
-
var token=tokenEl?tokenEl.value.trim():'';
|
|
3178
|
-
var port=document.getElementById('cfgHubPort').value.trim()||'18800';
|
|
3179
|
-
if(!token||_sharingRole!=='hub'){panel.style.display='none';return;}
|
|
3180
|
-
panel.style.display='block';
|
|
3181
|
-
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';
|
|
3182
|
-
var renderShare=function(ip){
|
|
3183
|
-
var addr=ip?(ip+':'+esc(port)):('<'+t('settings.hub.shareInfo.yourIP')+'>:'+esc(port));
|
|
3184
|
-
var tip=t('settings.hub.shareInfo.clickCopy');
|
|
3185
|
-
content.innerHTML=
|
|
3186
|
-
'<span style="font-size:11px;color:var(--text-muted);font-weight:500">Hub '+t('settings.hub.hubAddress')+'</span>'+
|
|
3187
|
-
'<span style="'+cpStyle+'" onclick="navigator.clipboard.writeText(this.textContent);toast('Copied!','success')" title="'+tip+'">'+addr+'</span>'+
|
|
3188
|
-
'<span style="font-size:11px;color:var(--text-muted);font-weight:500">Team Token</span>'+
|
|
3189
|
-
'<span style="'+cpStyle+'" onclick="navigator.clipboard.writeText(this.textContent);toast('Copied!','success')" title="'+tip+'">'+esc(token)+'</span>';
|
|
3190
|
-
};
|
|
3191
|
-
if(_cachedLocalIP){renderShare(_cachedLocalIP);return;}
|
|
3192
|
-
renderShare('');
|
|
3193
|
-
fetch('/api/local-ips').then(function(r){return r.json()}).then(function(d){
|
|
3194
|
-
if(d.ips&&d.ips.length>0){_cachedLocalIP=d.ips[0];renderShare(_cachedLocalIP);}
|
|
3195
|
-
}).catch(function(){});
|
|
3196
|
-
}
|
|
3197
|
-
async function testHubConnection(){
|
|
3198
|
-
var btn=document.getElementById('btnTestHubConn');
|
|
3199
|
-
var result=document.getElementById('hubConnTestResult');
|
|
3200
|
-
var addr=document.getElementById('cfgClientHubAddress').value.trim();
|
|
3201
|
-
if(!addr){result.innerHTML='<span style="color:var(--rose)">\u274C '+t('settings.hub.test.noAddr')+'</span>';return;}
|
|
3202
|
-
btn.disabled=true;result.innerHTML=t('settings.hub.test.testing');
|
|
3203
|
-
try{
|
|
3204
|
-
var ipsData=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
3205
|
-
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ipsData.ips||[]);
|
|
3206
|
-
var parsed=new URL(addr.indexOf('://')>-1?addr:'http://'+addr);
|
|
3207
|
-
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
3208
|
-
result.innerHTML='<span style="color:var(--rose)">\u274C '+t('sharing.cannotJoinSelf')+'</span>';
|
|
3209
|
-
btn.disabled=false;return;
|
|
3210
|
-
}
|
|
3211
|
-
}catch(e){}
|
|
3212
|
-
try{
|
|
3213
|
-
var url=addr.match(/^https?:\\/\\//)?addr:'http://'+addr;
|
|
3214
|
-
url=url.replace(/\\/+$/,'');
|
|
3215
|
-
var r=await fetch('/api/sharing/test-hub',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({hubUrl:url})});
|
|
3216
|
-
var d=await r.json();
|
|
3217
|
-
if(d.ok){
|
|
3218
|
-
result.innerHTML='<span style="color:var(--green)">\u2705 '+t('settings.hub.test.ok')+(d.teamName?' — '+esc(d.teamName):'')+'</span>';
|
|
3219
|
-
}else{
|
|
3220
|
-
var errMsg=d.error==='cannot_join_self'?t('sharing.cannotJoinSelf'):(d.error||t('settings.hub.test.fail'));
|
|
3221
|
-
result.innerHTML='<span style="color:var(--rose)">\u274C '+errMsg+'</span>';
|
|
3222
|
-
}
|
|
3223
|
-
}catch(e){
|
|
3224
|
-
result.innerHTML='<span style="color:var(--rose)">\u274C '+esc(String(e))+'</span>';
|
|
3225
|
-
}finally{btn.disabled=false;}
|
|
3226
|
-
}
|
|
3227
|
-
|
|
3228
2126
|
function enterApp(){
|
|
3229
2127
|
document.getElementById('app').style.display='flex';
|
|
3230
2128
|
loadAll();
|
|
3231
2129
|
}
|
|
3232
2130
|
|
|
3233
|
-
function switchSettingsTab(tab,btn){
|
|
3234
|
-
document.querySelectorAll('.settings-tab-btn').forEach(function(b){b.classList.remove('active')});
|
|
3235
|
-
if(btn){btn.classList.add('active')}
|
|
3236
|
-
else{var b=document.querySelector('.settings-tab-btn[data-tab="'+tab+'"]');if(b)b.classList.add('active')}
|
|
3237
|
-
document.querySelectorAll('.settings-card[data-stab]').forEach(function(c){
|
|
3238
|
-
if(c.dataset.stab===tab){c.classList.add('stab-active')}else{c.classList.remove('stab-active')}
|
|
3239
|
-
});
|
|
3240
|
-
}
|
|
3241
|
-
|
|
3242
2131
|
function switchView(view){
|
|
3243
2132
|
document.querySelectorAll('.nav-tabs .tab').forEach(t=>t.classList.toggle('active',t.dataset.view===view));
|
|
3244
2133
|
const feedWrap=document.getElementById('feedWrap');
|
|
@@ -3248,7 +2137,6 @@ function switchView(view){
|
|
|
3248
2137
|
const logsView=document.getElementById('logsView');
|
|
3249
2138
|
const settingsView=document.getElementById('settingsView');
|
|
3250
2139
|
const migrateView=document.getElementById('migrateView');
|
|
3251
|
-
const adminView=document.getElementById('adminView');
|
|
3252
2140
|
const sidebar=document.getElementById('sidebar');
|
|
3253
2141
|
feedWrap.classList.add('hide');
|
|
3254
2142
|
analyticsView.classList.remove('show');
|
|
@@ -3257,17 +2145,19 @@ function switchView(view){
|
|
|
3257
2145
|
logsView.classList.remove('show');
|
|
3258
2146
|
settingsView.classList.remove('show');
|
|
3259
2147
|
migrateView.classList.remove('show');
|
|
3260
|
-
|
|
3261
|
-
var sessionSection=document.getElementById('sidebarSessionSection');
|
|
2148
|
+
const sessionSection=document.getElementById('sidebarSessionSection');
|
|
3262
2149
|
if(view==='memories'){
|
|
3263
2150
|
feedWrap.classList.remove('hide');
|
|
3264
|
-
|
|
2151
|
+
sessionSection.style.visibility='';
|
|
2152
|
+
sessionSection.style.pointerEvents='';
|
|
3265
2153
|
} else if(view==='tasks'||view==='skills'){
|
|
3266
|
-
|
|
2154
|
+
sessionSection.style.visibility='hidden';
|
|
2155
|
+
sessionSection.style.pointerEvents='none';
|
|
3267
2156
|
if(view==='tasks'){tasksView.classList.add('show');loadTasks();}
|
|
3268
2157
|
else{skillsView.classList.add('show');loadSkills();}
|
|
3269
2158
|
} else {
|
|
3270
|
-
|
|
2159
|
+
sessionSection.style.visibility='hidden';
|
|
2160
|
+
sessionSection.style.pointerEvents='none';
|
|
3271
2161
|
if(view==='analytics'){
|
|
3272
2162
|
analyticsView.classList.add('show');
|
|
3273
2163
|
loadMetrics();
|
|
@@ -3281,1142 +2171,104 @@ function switchView(view){
|
|
|
3281
2171
|
} else if(view==='import'){
|
|
3282
2172
|
migrateView.classList.add('show');
|
|
3283
2173
|
if(!window._migrateRunning) migrateScan(false);
|
|
3284
|
-
} else if(view==='admin'){
|
|
3285
|
-
if(adminView){adminView.classList.add('show');loadAdminData();}
|
|
3286
2174
|
}
|
|
3287
2175
|
}
|
|
3288
2176
|
}
|
|
3289
2177
|
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
function onSkillScopeChange(){
|
|
3298
|
-
skillSearchScope=document.getElementById('skillSearchScope')?.value||'local';
|
|
3299
|
-
loadSkills();
|
|
3300
|
-
}
|
|
3301
|
-
|
|
3302
|
-
function onTaskScopeChange(){
|
|
3303
|
-
taskSearchScope=document.getElementById('taskSearchScope')?.value||'local';
|
|
3304
|
-
tasksPage=0;
|
|
3305
|
-
loadTasks();
|
|
3306
|
-
}
|
|
3307
|
-
|
|
3308
|
-
async function loadSharingStatus(forcePending){
|
|
2178
|
+
// ─── Logs ───
|
|
2179
|
+
let logAutoTimer=null;
|
|
2180
|
+
let logPage=1;
|
|
2181
|
+
const LOG_PAGE_SIZE=20;
|
|
2182
|
+
async function loadLogs(page){
|
|
2183
|
+
if(typeof page==='number') logPage=page;
|
|
3309
2184
|
try{
|
|
3310
|
-
const
|
|
3311
|
-
const
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
}
|
|
2185
|
+
const toolFilter=document.getElementById('logToolFilter').value;
|
|
2186
|
+
const offset=(logPage-1)*LOG_PAGE_SIZE;
|
|
2187
|
+
const url='/api/logs?limit='+LOG_PAGE_SIZE+'&offset='+offset+(toolFilter?'&tool='+encodeURIComponent(toolFilter):'');
|
|
2188
|
+
const [logsRes,toolsRes]=await Promise.all([fetch(url),fetch('/api/log-tools')]);
|
|
2189
|
+
if(!logsRes.ok) return;
|
|
2190
|
+
const logsData=await logsRes.json();
|
|
2191
|
+
const toolsData=await toolsRes.json();
|
|
2192
|
+
renderLogToolFilter(toolsData.tools||[],toolFilter);
|
|
2193
|
+
renderLogs(logsData.logs||[]);
|
|
2194
|
+
renderLogPagination(logsData.page||1,logsData.totalPages||1,logsData.total||0);
|
|
2195
|
+
startLogAutoRefresh();
|
|
2196
|
+
}catch(e){console.error('loadLogs',e)}
|
|
3322
2197
|
}
|
|
3323
|
-
|
|
3324
|
-
function
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
if(section) section.style.display='block';
|
|
3336
|
-
var conn=data.connection||{};
|
|
3337
|
-
function setBadge(color,text,glow){
|
|
3338
|
-
if(!badgeEl)return;
|
|
3339
|
-
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>';
|
|
3340
|
-
}
|
|
3341
|
-
if(data.role==='hub'){
|
|
3342
|
-
setBadge('#34d399',t('sharing.sidebar.connected'),true);
|
|
3343
|
-
statusEl.innerHTML='';
|
|
3344
|
-
hintEl.textContent='';
|
|
3345
|
-
}else if(conn.pendingApproval&&conn.user){
|
|
3346
|
-
setBadge('#fbbf24',t('sharing.sidebar.pending'),false);
|
|
3347
|
-
var html='<div class="info-grid">';
|
|
3348
|
-
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username)+'</span>';
|
|
3349
|
-
if(conn.teamName) html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName)+'</span>';
|
|
3350
|
-
html+='</div>';
|
|
3351
|
-
statusEl.innerHTML=html;
|
|
3352
|
-
hintEl.textContent=t('sharing.pendingApproval.hint');
|
|
3353
|
-
}else if(conn.rejected&&conn.user){
|
|
3354
|
-
setBadge('#ef4444',t('sharing.sidebar.rejected'),false);
|
|
3355
|
-
var html='<div class="info-grid">';
|
|
3356
|
-
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username||'-')+'</span>';
|
|
3357
|
-
if(conn.teamName) html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName)+'</span>';
|
|
3358
|
-
html+='</div>';
|
|
3359
|
-
statusEl.innerHTML=html;
|
|
3360
|
-
hintEl.textContent=t('sharing.rejected.hint');
|
|
3361
|
-
}else if(conn.connected&&conn.user){
|
|
3362
|
-
var isAdmin=conn.user.role==='admin';
|
|
3363
|
-
setBadge('#34d399',t('sharing.sidebar.connected'),true);
|
|
3364
|
-
var html='<div class="info-grid">';
|
|
3365
|
-
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>';
|
|
3366
|
-
html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName||'-')+'</span>';
|
|
3367
|
-
html+='</div>';
|
|
3368
|
-
statusEl.innerHTML=html;
|
|
3369
|
-
hintEl.innerHTML='';
|
|
3370
|
-
}else if(data.clientConfigured){
|
|
3371
|
-
setBadge('#ef4444',t('sharing.sidebar.disconnected'),false);
|
|
3372
|
-
statusEl.innerHTML='<div style="font-size:11px;color:var(--text-muted)">'+t('sharing.sidebar.targetHub')+' '+esc(data.hubUrl||'')+'</div>';
|
|
3373
|
-
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>';
|
|
3374
|
-
}else{
|
|
3375
|
-
setBadge('#888',t('sharing.sidebar.notConfigured'),false);
|
|
3376
|
-
statusEl.innerHTML='';
|
|
3377
|
-
hintEl.textContent=t('sharing.clientNotConfigured.hint');
|
|
2198
|
+
function onLogFilterChange(){logPage=1;loadLogs(1);}
|
|
2199
|
+
function renderLogPagination(page,totalPages,total){
|
|
2200
|
+
const el=document.getElementById('logsPagination');
|
|
2201
|
+
if(!el||totalPages<=1){if(el)el.innerHTML='';return;}
|
|
2202
|
+
const pages=[];
|
|
2203
|
+
const range=2;
|
|
2204
|
+
for(let i=1;i<=totalPages;i++){
|
|
2205
|
+
if(i===1||i===totalPages||Math.abs(i-page)<=range){
|
|
2206
|
+
pages.push(i);
|
|
2207
|
+
}else if(pages[pages.length-1]!=='...'){
|
|
2208
|
+
pages.push('...');
|
|
2209
|
+
}
|
|
3378
2210
|
}
|
|
2211
|
+
let html='<div class="logs-pagination">';
|
|
2212
|
+
html+='<button class="btn btn-sm btn-ghost" '+(page<=1?'disabled':'')+' onclick="loadLogs('+(page-1)+')">\u2039</button>';
|
|
2213
|
+
pages.forEach(p=>{
|
|
2214
|
+
if(p==='...'){html+='<span class="page-ellipsis">\u2026</span>';}
|
|
2215
|
+
else{html+='<button class="btn btn-sm '+(p===page?'btn-primary':'btn-ghost')+'" onclick="loadLogs('+p+')">'+p+'</button>';}
|
|
2216
|
+
});
|
|
2217
|
+
html+='<button class="btn btn-sm btn-ghost" '+(page>=totalPages?'disabled':'')+' onclick="loadLogs('+(page+1)+')">\u203A</button>';
|
|
2218
|
+
html+='<span class="page-total">'+total+' total</span>';
|
|
2219
|
+
html+='</div>';
|
|
2220
|
+
el.innerHTML=html;
|
|
3379
2221
|
}
|
|
3380
2222
|
|
|
3381
|
-
function
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
if(panelsWrap) panelsWrap.style.display='none';
|
|
3390
|
-
return;
|
|
3391
|
-
}
|
|
3392
|
-
if(panelsWrap) panelsWrap.style.display='';
|
|
3393
|
-
var conn=data.connection||{};
|
|
3394
|
-
var user=conn.user||{};
|
|
3395
|
-
var actualRole=data.role||_sharingRole||'client';
|
|
3396
|
-
if(data.role) _sharingRole=data.role;
|
|
3397
|
-
var isAdmin=(data.admin&&data.admin.canManageUsers)||(conn.connected&&user.role==='admin')||(actualRole==='hub');
|
|
3398
|
-
window._isHubAdmin=isAdmin;
|
|
3399
|
-
var hubAdminBtn=document.getElementById('hubAdminEntryBtn');
|
|
3400
|
-
|
|
3401
|
-
if(actualRole==='hub'){
|
|
3402
|
-
statusEl.innerHTML='';teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3403
|
-
if(hubAdminBtn) hubAdminBtn.style.display=isAdmin?'':'none';
|
|
3404
|
-
return;
|
|
3405
|
-
}
|
|
3406
|
-
|
|
3407
|
-
if(actualRole==='client'){
|
|
3408
|
-
statusEl.style.display='none';teamEl.style.display='none';adminEl.style.display='none';
|
|
3409
|
-
if(hubAdminBtn) hubAdminBtn.style.display='none';
|
|
3410
|
-
|
|
3411
|
-
var connBadge;
|
|
3412
|
-
if(conn.pendingApproval){
|
|
3413
|
-
connBadge='<span class="hic-badge pending"><span class="hic-dot amber"></span>'+t('sharing.sidebar.pending')+'</span>';
|
|
3414
|
-
}else if(conn.rejected){
|
|
3415
|
-
connBadge='<span class="hic-badge disconnected"><span class="hic-dot red"></span>'+t('sharing.sidebar.rejected')+'</span>';
|
|
3416
|
-
}else if(conn.connected){
|
|
3417
|
-
connBadge='<span class="hic-badge connected"><span class="hic-dot green"></span>'+t('sharing.sidebar.connected')+'</span>';
|
|
3418
|
-
}else{
|
|
3419
|
-
connBadge='<span class="hic-badge disconnected"><span class="hic-dot red"></span>'+t('sharing.sidebar.disconnected')+'</span>';
|
|
3420
|
-
}
|
|
3421
|
-
statusEl.style.display='';
|
|
3422
|
-
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">';
|
|
3423
|
-
if(conn.pendingApproval&&user.username){
|
|
3424
|
-
sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value">'+esc(user.username)+'</span>';
|
|
3425
|
-
sh+='</div><div class="hic-empty" style="color:#f59e0b">'+t('sharing.pendingApproval.hint')+'</div></div>';
|
|
3426
|
-
}else if(conn.rejected){
|
|
3427
|
-
if(user.username) sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value">'+esc(user.username)+'</span>';
|
|
3428
|
-
sh+='</div><div class="hic-empty" style="color:#ef4444">'+t('sharing.rejected.hint')+'</div>'+
|
|
3429
|
-
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" onclick="retryHubJoin()">'+t('sharing.retryJoin')+'</button>'+
|
|
3430
|
-
'<span style="font-size:11px;color:var(--text-muted);margin-left:8px">'+t('sharing.retryJoin.hint')+'</span></div></div>';
|
|
3431
|
-
}else if(conn.connected&&user.username){
|
|
3432
|
-
sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value" style="display:flex;align-items:center;gap:6px">'+
|
|
3433
|
-
'<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" />'+
|
|
3434
|
-
'<button class="btn btn-sm" onclick="updateHubUsername()" style="padding:2px 10px;font-size:11px">'+t('sharing.saveUsername')+'</button>'+
|
|
3435
|
-
'</span>';
|
|
3436
|
-
sh+='<span class="hic-label">'+t('sharing.team')+'</span><span class="hic-value">'+esc(conn.teamName||'-')+'</span>';
|
|
3437
|
-
sh+='</div></div>';
|
|
3438
|
-
}else{
|
|
3439
|
-
sh+='</div><div class="hic-empty" style="color:var(--text-muted)">'+t('sharing.disconnected.hint')+'</div>'+
|
|
3440
|
-
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" id="btnRetryConn" onclick="retryConnection()">'+t('sharing.retryConnection')+'</button>'+
|
|
3441
|
-
'<span id="retryConnResult" style="margin-left:10px;font-size:11px"></span></div></div>';
|
|
3442
|
-
}
|
|
3443
|
-
statusEl.innerHTML=sh;
|
|
3444
|
-
teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3445
|
-
return;
|
|
3446
|
-
}
|
|
2223
|
+
function renderLogToolFilter(tools,current){
|
|
2224
|
+
const sel=document.getElementById('logToolFilter');
|
|
2225
|
+
const opts=['<option value="">'+t('logs.allTools')+'</option>'];
|
|
2226
|
+
tools.forEach(tn=>{
|
|
2227
|
+
opts.push('<option value="'+tn+'"'+(tn===current?' selected':'')+'>'+tn+'</option>');
|
|
2228
|
+
});
|
|
2229
|
+
sel.innerHTML=opts.join('');
|
|
2230
|
+
}
|
|
3447
2231
|
|
|
3448
|
-
|
|
2232
|
+
function formatLogTime(ts){
|
|
2233
|
+
const d=new Date(ts);
|
|
2234
|
+
const time=d.toLocaleTimeString('zh-CN',{hour:'2-digit',minute:'2-digit',second:'2-digit',hour12:false});
|
|
2235
|
+
const y=d.getFullYear();
|
|
2236
|
+
const m=String(d.getMonth()+1).padStart(2,'0');
|
|
2237
|
+
const day=String(d.getDate()).padStart(2,'0');
|
|
2238
|
+
return y+'-'+m+'-'+day+' '+time;
|
|
3449
2239
|
}
|
|
3450
2240
|
|
|
3451
|
-
|
|
3452
|
-
var
|
|
3453
|
-
var
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
}
|
|
3463
|
-
|
|
2241
|
+
function parseMemoryAddEntries(out){
|
|
2242
|
+
var lines=out.split('\\n');
|
|
2243
|
+
var results=[];
|
|
2244
|
+
for(var i=0;i<lines.length;i++){
|
|
2245
|
+
var line=lines[i].trim();
|
|
2246
|
+
if(!line) continue;
|
|
2247
|
+
if(line.startsWith('{')){
|
|
2248
|
+
try{
|
|
2249
|
+
var obj=JSON.parse(line);
|
|
2250
|
+
if(obj.role&&obj.action){results.push({role:obj.role,action:obj.action,summary:obj.summary||'',content:obj.content||'',reason:obj.reason||''});continue;}
|
|
2251
|
+
}catch(e){}
|
|
2252
|
+
}
|
|
2253
|
+
var rm=line.match(/^\\[(\\w+)\\]\\s*([^\u2192]+)\u2192/);
|
|
2254
|
+
if(rm){
|
|
2255
|
+
var role=rm[1],actionRaw=rm[2].trim();
|
|
2256
|
+
var action='stored';
|
|
2257
|
+
if(actionRaw.indexOf('exact-dup')>=0||actionRaw.indexOf('\u23ED')>=0) action='exact-dup';
|
|
2258
|
+
else if(actionRaw.indexOf('dedup')>=0||actionRaw.indexOf('\uD83D\uDD01')>=0) action='dedup';
|
|
2259
|
+
else if(actionRaw.indexOf('merged')>=0||actionRaw.indexOf('\uD83D\uDD00')>=0) action='merged';
|
|
2260
|
+
else if(actionRaw.indexOf('error')>=0||actionRaw.indexOf('\u274C')>=0) action='error';
|
|
2261
|
+
var afterArrow=line.replace(/^\\[\\w+\\]\\s*[^\u2192]+\u2192\\s*/,'');
|
|
2262
|
+
var contentLines=[afterArrow];
|
|
2263
|
+
while(i+1<lines.length&&!lines[i+1].trim().startsWith('[')&&!lines[i+1].trim().startsWith('{')){
|
|
2264
|
+
i++;
|
|
2265
|
+
if(lines[i].trim()) contentLines.push(lines[i]);
|
|
2266
|
+
else contentLines.push('');
|
|
2267
|
+
}
|
|
2268
|
+
results.push({role:role,action:action,summary:'',content:contentLines.join('\\n'),reason:''});
|
|
3464
2269
|
}
|
|
3465
|
-
}catch(e){
|
|
3466
|
-
if(result) result.innerHTML='<span style="color:#ef4444">'+t('sharing.retryConnection.fail')+'</span>';
|
|
3467
2270
|
}
|
|
3468
|
-
|
|
3469
|
-
}
|
|
3470
|
-
|
|
3471
|
-
async function retryHubJoin(){
|
|
3472
|
-
if(!confirm(t('sharing.retryJoin.confirm'))) return;
|
|
3473
|
-
try{
|
|
3474
|
-
var r=await fetch('/api/sharing/retry-join',{method:'POST',headers:{'Content-Type':'application/json'}});
|
|
3475
|
-
var d=await r.json();
|
|
3476
|
-
if(d.ok){
|
|
3477
|
-
toast(t('sharing.retryJoin.success'),'success');
|
|
3478
|
-
setTimeout(function(){location.reload();},1500);
|
|
3479
|
-
}else{
|
|
3480
|
-
toast(d.error||t('sharing.retryJoin.fail'),'error');
|
|
3481
|
-
}
|
|
3482
|
-
}catch(e){toast(t('sharing.retryJoin.fail')+': '+e.message,'error');}
|
|
3483
|
-
}
|
|
3484
|
-
|
|
3485
|
-
async function updateHubUsername(){
|
|
3486
|
-
var input=document.getElementById('hubUsernameInput');
|
|
3487
|
-
if(!input) return;
|
|
3488
|
-
var newName=input.value.trim();
|
|
3489
|
-
if(!newName||newName.length<2||newName.length>32){
|
|
3490
|
-
toast(t('sharing.username.invalid'),'error');
|
|
3491
|
-
return;
|
|
3492
|
-
}
|
|
3493
|
-
try{
|
|
3494
|
-
var r=await fetch('/api/sharing/update-username',{
|
|
3495
|
-
method:'POST',
|
|
3496
|
-
headers:{'Content-Type':'application/json'},
|
|
3497
|
-
body:JSON.stringify({username:newName})
|
|
3498
|
-
});
|
|
3499
|
-
var d=await r.json();
|
|
3500
|
-
if(d.error==='username_taken'){
|
|
3501
|
-
toast(t('sharing.username.taken'),'error');
|
|
3502
|
-
return;
|
|
3503
|
-
}
|
|
3504
|
-
if(d.error){
|
|
3505
|
-
toast(d.error,'error');
|
|
3506
|
-
return;
|
|
3507
|
-
}
|
|
3508
|
-
toast(t('sharing.username.updated'),'success');
|
|
3509
|
-
loadSharingStatus(false);
|
|
3510
|
-
}catch(e){
|
|
3511
|
-
toast(t('sharing.username.error'),'error');
|
|
3512
|
-
}
|
|
3513
|
-
}
|
|
3514
|
-
|
|
3515
|
-
async function loadSharingPendingUsers(){
|
|
3516
|
-
if(_sharingRole==='client') return;
|
|
3517
|
-
var el=document.getElementById('sharingAdminPanel');
|
|
3518
|
-
if(!el) return;
|
|
3519
|
-
el.innerHTML=t('sharing.loading');
|
|
3520
|
-
try{
|
|
3521
|
-
const r=await fetch('/api/sharing/pending-users');
|
|
3522
|
-
const d=await r.json();
|
|
3523
|
-
const users=Array.isArray(d.users)?d.users:[];
|
|
3524
|
-
renderSharingPendingUsers(users, d.error, sharingStatusCache&&sharingStatusCache.admin?sharingStatusCache.admin.rejectSupported:false);
|
|
3525
|
-
}catch(e){
|
|
3526
|
-
el.innerHTML='<div class="line">'+t('sharing.pendingLoadFail')+esc(String(e))+'</div>';
|
|
3527
|
-
}
|
|
3528
|
-
}
|
|
3529
|
-
|
|
3530
|
-
function renderSharingPendingUsers(users, error, rejectSupported){
|
|
3531
|
-
var el=document.getElementById('sharingAdminPanel');
|
|
3532
|
-
if(!el) return;
|
|
3533
|
-
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>';
|
|
3534
|
-
if(error){
|
|
3535
|
-
el.innerHTML=wrap+'<div class="hic-empty">'+esc(error)+'</div></div>';
|
|
3536
|
-
return;
|
|
3537
|
-
}
|
|
3538
|
-
if(!users||users.length===0){
|
|
3539
|
-
el.innerHTML=wrap+'<div class="hic-empty">'+t('sharing.noPending')+'</div></div>';
|
|
3540
|
-
return;
|
|
3541
|
-
}
|
|
3542
|
-
el.innerHTML=wrap+users.map(function(user){
|
|
3543
|
-
return '<div style="display:flex;align-items:center;justify-content:space-between;padding:8px 0;border-top:1px solid var(--border)">'+
|
|
3544
|
-
'<div><div style="font-size:13px;font-weight:600;color:var(--text)">'+esc(user.username||user.id||'')+'</div>'+
|
|
3545
|
-
'<div style="font-size:11px;color:var(--text-muted)">'+t('admin.device')+esc(user.deviceName||'unknown')+'</div></div>'+
|
|
3546
|
-
'<div class="hic-actions" style="margin:0">'+
|
|
3547
|
-
'<button class="btn btn-sm btn-primary" onclick="approveSharingUser("'+escAttr(user.id)+'","'+escAttr(user.username||'')+'")">'+t('admin.approve')+'</button>'+
|
|
3548
|
-
(rejectSupported?'<button class="btn btn-sm btn-ghost" style="color:var(--rose)" onclick="rejectSharingUser("'+escAttr(user.id)+'","'+escAttr(user.username||'')+'")">'+t('admin.reject')+'</button>':'')+
|
|
3549
|
-
'</div></div>';
|
|
3550
|
-
}).join('')+'</div>';
|
|
3551
|
-
}
|
|
3552
|
-
|
|
3553
|
-
async function approveSharingUser(userId,username){
|
|
3554
|
-
try{
|
|
3555
|
-
const r=await fetch('/api/sharing/approve-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
3556
|
-
const d=await r.json();
|
|
3557
|
-
if(d.ok){toast(t('toast.userApproved'),'success');loadSharingPendingUsers();loadSharingStatus(true);} else {toast(d.error||t('toast.approveFail'),'error');}
|
|
3558
|
-
}catch(e){toast(t('toast.approveFail')+': '+e.message,'error');}
|
|
3559
|
-
}
|
|
3560
|
-
|
|
3561
|
-
async function rejectSharingUser(userId,username){
|
|
3562
|
-
try{
|
|
3563
|
-
const r=await fetch('/api/sharing/reject-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
3564
|
-
const d=await r.json();
|
|
3565
|
-
if(d.ok){toast(t('toast.userRejected'),'success');loadSharingPendingUsers();} else {toast(d.error||t('toast.rejectFail'),'error');}
|
|
3566
|
-
}catch(e){toast(t('toast.rejectFail')+': '+e.message,'error');}
|
|
3567
|
-
}
|
|
3568
|
-
|
|
3569
|
-
/* ─── Team Setup Guide ─── */
|
|
3570
|
-
var TEAM_GUIDE_DISMISSED_KEY='memos-team-guide-dismissed';
|
|
3571
|
-
function updateTeamGuide(sharingData){
|
|
3572
|
-
var el=document.getElementById('teamSetupGuide');
|
|
3573
|
-
if(!el) return;
|
|
3574
|
-
if(localStorage.getItem(TEAM_GUIDE_DISMISSED_KEY)==='1'){el.style.display='none';return;}
|
|
3575
|
-
var isConfigured=sharingData&&sharingData.enabled;
|
|
3576
|
-
el.style.display=isConfigured?'none':'block';
|
|
3577
|
-
}
|
|
3578
|
-
function dismissTeamGuide(){
|
|
3579
|
-
localStorage.setItem(TEAM_GUIDE_DISMISSED_KEY,'1');
|
|
3580
|
-
var el=document.getElementById('teamSetupGuide');
|
|
3581
|
-
if(el) el.style.display='none';
|
|
3582
|
-
}
|
|
3583
|
-
function guideGoToHub(role){
|
|
3584
|
-
switchSettingsTab('hub',document.querySelector('.settings-tab-btn[data-tab="hub"]'));
|
|
3585
|
-
var chk=document.getElementById('cfgSharingEnabled');
|
|
3586
|
-
if(chk&&!chk.checked){chk.checked=true;onSharingToggle();}
|
|
3587
|
-
selectSharingRole(role);
|
|
3588
|
-
var card=document.getElementById('settingsSharingConfig');
|
|
3589
|
-
if(card) card.scrollIntoView({behavior:'smooth',block:'start'});
|
|
3590
|
-
}
|
|
3591
|
-
|
|
3592
|
-
/* ─── Group Manager ─── */
|
|
3593
|
-
var groupManagerUsers=[];
|
|
3594
|
-
async function loadGroupManager(){
|
|
3595
|
-
var panel=document.getElementById('groupManagerPanel');
|
|
3596
|
-
if(!panel) return;
|
|
3597
|
-
panel.style.display='block';
|
|
3598
|
-
panel.innerHTML=t('sharing.loadingGroups');
|
|
3599
|
-
try{
|
|
3600
|
-
var [gr,ur]=await Promise.all([
|
|
3601
|
-
fetch('/api/sharing/groups').then(function(r){return r.json();}),
|
|
3602
|
-
fetch('/api/sharing/users').then(function(r){return r.json();})
|
|
3603
|
-
]);
|
|
3604
|
-
var groups=Array.isArray(gr.groups)?gr.groups:[];
|
|
3605
|
-
groupManagerUsers=Array.isArray(ur.users)?ur.users:[];
|
|
3606
|
-
renderGroupManager(panel,groups);
|
|
3607
|
-
}catch(e){panel.innerHTML=t('admin.groupsFailed')+esc(String(e));}
|
|
3608
|
-
}
|
|
3609
|
-
function renderGroupManager(panel,groups){
|
|
3610
|
-
var html='<div style="margin-bottom:8px;display:flex;gap:8px;align-items:center;font-size:12px">'+
|
|
3611
|
-
'<strong>'+t('admin.groups')+' ('+groups.length+')</strong>'+
|
|
3612
|
-
'<button class="btn btn-sm" onclick="showCreateGroupForm()" style="font-size:11px">'+t('admin.newGroup')+'</button>'+
|
|
3613
|
-
'</div>';
|
|
3614
|
-
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">'+
|
|
3615
|
-
'<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)">'+
|
|
3616
|
-
'<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)">'+
|
|
3617
|
-
'<div style="margin-top:6px"><button class="btn btn-sm btn-primary" onclick="createGroup()" style="font-size:11px">'+t('admin.create')+'</button> '+
|
|
3618
|
-
'<button class="btn btn-sm btn-ghost" onclick="hideCreateGroupForm()" style="font-size:11px">'+t('admin.cancel')+'</button></div>'+
|
|
3619
|
-
'</div>';
|
|
3620
|
-
if(groups.length===0){
|
|
3621
|
-
html+='<div style="font-size:12px;color:var(--text-muted);padding:6px 0">'+t('sharing.noGroupsYet')+'</div>';
|
|
3622
|
-
}else{
|
|
3623
|
-
html+='<div style="display:flex;flex-direction:column;gap:6px">';
|
|
3624
|
-
for(var i=0;i<groups.length;i++){
|
|
3625
|
-
var g=groups[i];
|
|
3626
|
-
html+='<div style="padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:8px;font-size:12px">'+
|
|
3627
|
-
'<div style="display:flex;justify-content:space-between;align-items:center">'+
|
|
3628
|
-
'<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>'+
|
|
3629
|
-
'<div style="display:flex;gap:6px">'+
|
|
3630
|
-
'<button class="btn btn-sm" onclick="toggleGroupMembers("'+escAttr(g.id)+'")" style="font-size:11px;padding:2px 8px">'+t('admin.members')+'</button>'+
|
|
3631
|
-
'<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>'+
|
|
3632
|
-
'</div>'+
|
|
3633
|
-
'</div>'+
|
|
3634
|
-
'<div id="groupMembers_'+escAttr(g.id)+'" style="display:none;margin-top:6px;font-size:12px"></div>'+
|
|
3635
|
-
'</div>';
|
|
3636
|
-
}
|
|
3637
|
-
html+='</div>';
|
|
3638
|
-
}
|
|
3639
|
-
panel.innerHTML=html;
|
|
3640
|
-
}
|
|
3641
|
-
function showCreateGroupForm(){var f=document.getElementById('createGroupForm');if(f)f.style.display='block';}
|
|
3642
|
-
function hideCreateGroupForm(){var f=document.getElementById('createGroupForm');if(f)f.style.display='none';}
|
|
3643
|
-
async function createGroup(){
|
|
3644
|
-
var name=(document.getElementById('newGroupName')).value.trim();
|
|
3645
|
-
var desc=(document.getElementById('newGroupDesc')).value.trim();
|
|
3646
|
-
if(!name){toast(t('toast.groupNameRequired'),'error');return;}
|
|
3647
|
-
try{
|
|
3648
|
-
var r=await fetch('/api/sharing/groups',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:name,description:desc})});
|
|
3649
|
-
var d=await r.json();
|
|
3650
|
-
if(d.ok){toast(t('toast.groupCreated'),'success');hideCreateGroupForm();loadGroupManager();}else{toast(d.error||t('toast.createFail'),'error');}
|
|
3651
|
-
}catch(e){toast(t('toast.createFail')+': '+e.message,'error');}
|
|
3652
|
-
}
|
|
3653
|
-
async function deleteGroup(groupId,groupName){
|
|
3654
|
-
if(!confirm(t('confirm.deleteGroup').replace('{name}',groupName))) return;
|
|
3655
|
-
try{
|
|
3656
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId),{method:'DELETE'});
|
|
3657
|
-
var d=await r.json();
|
|
3658
|
-
if(d.ok){toast(t('toast.groupDeleted'),'success');loadGroupManager();}else{toast(d.error||t('toast.deleteFail'),'error');}
|
|
3659
|
-
}catch(e){toast(t('toast.deleteFail')+': '+e.message,'error');}
|
|
3660
|
-
}
|
|
3661
|
-
async function toggleGroupMembers(groupId){
|
|
3662
|
-
var el=document.getElementById('groupMembers_'+groupId);
|
|
3663
|
-
if(!el) return;
|
|
3664
|
-
if(el.style.display!=='none'){el.style.display='none';return;}
|
|
3665
|
-
el.style.display='block';
|
|
3666
|
-
el.innerHTML=t('sharing.loading');
|
|
3667
|
-
try{
|
|
3668
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members');
|
|
3669
|
-
var d=await r.json();
|
|
3670
|
-
var members=Array.isArray(d.members)?d.members:[];
|
|
3671
|
-
renderGroupMembers(el,groupId,members);
|
|
3672
|
-
}catch(e){el.innerHTML=t('admin.groupsFailed')+esc(String(e));}
|
|
3673
|
-
}
|
|
3674
|
-
function renderGroupMembers(el,groupId,members){
|
|
3675
|
-
var html='<div style="font-size:12px;margin-bottom:6px;color:var(--text-sec)">'+t('admin.membersCount').replace('{n}',members.length)+'</div>';
|
|
3676
|
-
if(members.length>0){
|
|
3677
|
-
html+='<div style="display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px">';
|
|
3678
|
-
for(var i=0;i<members.length;i++){
|
|
3679
|
-
var m=members[i];
|
|
3680
|
-
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">'+
|
|
3681
|
-
esc(m.username||m.userId)+
|
|
3682
|
-
' <button style="background:none;border:none;color:#ef4444;cursor:pointer;font-size:11px;padding:0 2px" onclick="removeGroupMember("'+escAttr(groupId)+'","'+escAttr(m.userId)+'")">×</button>'+
|
|
3683
|
-
'</span>';
|
|
3684
|
-
}
|
|
3685
|
-
html+='</div>';
|
|
3686
|
-
}else{
|
|
3687
|
-
html+='<div style="font-size:12px;color:var(--text-muted);margin-bottom:8px">'+t('admin.noMembersYet')+'</div>';
|
|
3688
|
-
}
|
|
3689
|
-
var memberIds=new Set(members.map(function(m){return m.userId;}));
|
|
3690
|
-
var available=groupManagerUsers.filter(function(u){return !memberIds.has(u.id);});
|
|
3691
|
-
if(available.length>0){
|
|
3692
|
-
html+='<div style="display:flex;gap:6px;align-items:center">'+
|
|
3693
|
-
'<select id="addMemberSelect_'+escAttr(groupId)+'" style="padding:4px 8px;border:1px solid var(--border);border-radius:6px;font-size:12px">';
|
|
3694
|
-
for(var j=0;j<available.length;j++){
|
|
3695
|
-
html+='<option value="'+escAttr(available[j].id)+'">'+esc(available[j].username)+'</option>';
|
|
3696
|
-
}
|
|
3697
|
-
html+='</select>'+
|
|
3698
|
-
'<button class="btn btn-sm" onclick="addGroupMember("'+escAttr(groupId)+'")">'+t('admin.add')+'</button>'+
|
|
3699
|
-
'</div>';
|
|
3700
|
-
}
|
|
3701
|
-
el.innerHTML=html;
|
|
3702
|
-
}
|
|
3703
|
-
async function addGroupMember(groupId){
|
|
3704
|
-
var sel=document.getElementById('addMemberSelect_'+groupId);
|
|
3705
|
-
if(!sel) return;
|
|
3706
|
-
var userId=sel.value;
|
|
3707
|
-
if(!userId) return;
|
|
3708
|
-
try{
|
|
3709
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId})});
|
|
3710
|
-
var d=await r.json();
|
|
3711
|
-
if(d.ok){toast(t('toast.memberAdded'),'success');reloadGroupMembers(groupId);}else{toast(d.error||t('toast.addFail'),'error');}
|
|
3712
|
-
}catch(e){toast(t('toast.addFail')+': '+e.message,'error');}
|
|
3713
|
-
}
|
|
3714
|
-
async function removeGroupMember(groupId,userId){
|
|
3715
|
-
if(!confirm(t('confirm.removeGroupMember'))) return;
|
|
3716
|
-
try{
|
|
3717
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members',{method:'DELETE',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId})});
|
|
3718
|
-
var d=await r.json();
|
|
3719
|
-
if(d.ok){toast(t('toast.memberRemoved'),'success');reloadGroupMembers(groupId);}else{toast(d.error||t('toast.removeFail'),'error');}
|
|
3720
|
-
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
3721
|
-
}
|
|
3722
|
-
async function reloadGroupMembers(groupId){
|
|
3723
|
-
var el=document.getElementById('groupMembers_'+groupId);
|
|
3724
|
-
if(!el) return;
|
|
3725
|
-
el.style.display='block';
|
|
3726
|
-
el.innerHTML=t('sharing.loading');
|
|
3727
|
-
try{
|
|
3728
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members');
|
|
3729
|
-
var d=await r.json();
|
|
3730
|
-
var members=Array.isArray(d.members)?d.members:[];
|
|
3731
|
-
renderGroupMembers(el,groupId,members);
|
|
3732
|
-
}catch(e){el.innerHTML=t('admin.groupsFailed')+esc(String(e));}
|
|
3733
|
-
}
|
|
3734
|
-
|
|
3735
|
-
/* ─── Hub Admin Panel ─── */
|
|
3736
|
-
var adminDataCache={users:[],groups:[],tasks:[],skills:[],memories:[]};
|
|
3737
|
-
|
|
3738
|
-
function switchAdminTab(tab,btn){
|
|
3739
|
-
document.querySelectorAll('.admin-tabs .admin-tab').forEach(function(t){t.classList.remove('active');});
|
|
3740
|
-
btn.classList.add('active');
|
|
3741
|
-
document.querySelectorAll('.admin-panel').forEach(function(p){p.classList.remove('active');});
|
|
3742
|
-
var panel=document.getElementById('admin'+tab.charAt(0).toUpperCase()+tab.slice(1)+'Panel');
|
|
3743
|
-
if(panel) panel.classList.add('active');
|
|
3744
|
-
}
|
|
3745
|
-
|
|
3746
|
-
function adminGoSetup(role){
|
|
3747
|
-
switchView('settings');
|
|
3748
|
-
setTimeout(function(){guideGoToHub(role);},200);
|
|
3749
|
-
}
|
|
3750
|
-
|
|
3751
|
-
async function loadAdminData(){
|
|
3752
|
-
var notEnabledEl=document.getElementById('adminNotEnabled');
|
|
3753
|
-
var mainEl=document.getElementById('adminMainContent');
|
|
3754
|
-
var sharingOn=sharingStatusCache&&sharingStatusCache.enabled;
|
|
3755
|
-
if(!sharingOn){
|
|
3756
|
-
if(mainEl) mainEl.style.display='none';
|
|
3757
|
-
if(notEnabledEl){
|
|
3758
|
-
notEnabledEl.style.display='block';
|
|
3759
|
-
notEnabledEl.innerHTML=
|
|
3760
|
-
'<div style="text-align:center;padding:60px 32px;max-width:520px;margin:0 auto">'+
|
|
3761
|
-
'<div style="font-size:48px;margin-bottom:16px">\u{1F6E1}</div>'+
|
|
3762
|
-
'<div style="font-size:18px;font-weight:700;color:var(--text);margin-bottom:8px">'+t('admin.notEnabled.title')+'</div>'+
|
|
3763
|
-
'<div style="font-size:13px;color:var(--text-sec);line-height:1.7;margin-bottom:24px">'+t('admin.notEnabled.desc')+'</div>'+
|
|
3764
|
-
'<div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap">'+
|
|
3765
|
-
'<button class="btn btn-primary" style="padding:8px 20px;font-size:13px" onclick="adminGoSetup("hub")">'+t('admin.notEnabled.setupHub')+'</button>'+
|
|
3766
|
-
'<button class="btn btn-ghost" style="padding:8px 20px;font-size:13px" onclick="adminGoSetup("client")">'+t('admin.notEnabled.joinTeam')+'</button>'+
|
|
3767
|
-
'</div>'+
|
|
3768
|
-
'<div style="font-size:11px;color:var(--text-muted);margin-top:20px;line-height:1.6">'+t('admin.notEnabled.hint')+'</div>'+
|
|
3769
|
-
'</div>';
|
|
3770
|
-
}
|
|
3771
|
-
return;
|
|
3772
|
-
}
|
|
3773
|
-
if(notEnabledEl) notEnabledEl.style.display='none';
|
|
3774
|
-
if(mainEl) mainEl.style.display='';
|
|
3775
|
-
if(!window._isHubAdmin){
|
|
3776
|
-
var statsEl=document.getElementById('adminStats');
|
|
3777
|
-
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.noPermission')+'</div>';
|
|
3778
|
-
return;
|
|
3779
|
-
}
|
|
3780
|
-
try{
|
|
3781
|
-
var [usersR,tasksR,skillsR,pendingR,memoriesR]=await Promise.all([
|
|
3782
|
-
fetch('/api/sharing/users').then(function(r){return r.json();}),
|
|
3783
|
-
fetch('/api/admin/shared-tasks').then(function(r){return r.json();}),
|
|
3784
|
-
fetch('/api/admin/shared-skills').then(function(r){return r.json();}),
|
|
3785
|
-
fetch('/api/sharing/pending-users').then(function(r){return r.json();}),
|
|
3786
|
-
fetch('/api/admin/shared-memories').then(function(r){return r.json();})
|
|
3787
|
-
]);
|
|
3788
|
-
adminDataCache.users=Array.isArray(usersR.users)?usersR.users:[];
|
|
3789
|
-
adminDataCache.groups=[];
|
|
3790
|
-
adminDataCache.tasks=Array.isArray(tasksR.tasks)?tasksR.tasks:[];
|
|
3791
|
-
adminDataCache.skills=Array.isArray(skillsR.skills)?skillsR.skills:[];
|
|
3792
|
-
adminDataCache.memories=Array.isArray(memoriesR.memories)?memoriesR.memories:[];
|
|
3793
|
-
var pending=Array.isArray(pendingR.users)?pendingR.users:[];
|
|
3794
|
-
renderAdminStats(pending.length);
|
|
3795
|
-
renderAdminUsers(adminDataCache.users, pending);
|
|
3796
|
-
renderAdminMemories(adminDataCache.tasks);
|
|
3797
|
-
renderAdminSkills(adminDataCache.skills);
|
|
3798
|
-
renderAdminSharedMemories(adminDataCache.memories);
|
|
3799
|
-
}catch(e){
|
|
3800
|
-
var statsEl=document.getElementById('adminStats');
|
|
3801
|
-
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.loadFailed')+esc(String(e))+'</div>';
|
|
3802
|
-
}
|
|
3803
|
-
}
|
|
3804
|
-
|
|
3805
|
-
function renderAdminStats(pendingCount){
|
|
3806
|
-
var el=document.getElementById('adminStats');
|
|
3807
|
-
if(!el) return;
|
|
3808
|
-
el.innerHTML=
|
|
3809
|
-
'<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>'+
|
|
3810
|
-
'<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>'+
|
|
3811
|
-
'<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>'+
|
|
3812
|
-
'<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>'+
|
|
3813
|
-
'<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>';
|
|
3814
|
-
var tc=document.getElementById('adminTabCountUsers');if(tc)tc.textContent=adminDataCache.users.length+pendingCount;
|
|
3815
|
-
tc=document.getElementById('adminTabCountMemories');if(tc)tc.textContent=(adminDataCache.memories||[]).length;
|
|
3816
|
-
tc=document.getElementById('adminTabCountTasks');if(tc)tc.textContent=adminDataCache.tasks.length;
|
|
3817
|
-
tc=document.getElementById('adminTabCountSkills');if(tc)tc.textContent=adminDataCache.skills.length;
|
|
3818
|
-
}
|
|
3819
|
-
|
|
3820
|
-
function renderAdminUsers(users,pending){
|
|
3821
|
-
var el=document.getElementById('adminUsersPanel');
|
|
3822
|
-
if(!el) return;
|
|
3823
|
-
var html='';
|
|
3824
|
-
if(pending&&pending.length>0){
|
|
3825
|
-
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>';
|
|
3826
|
-
for(var p=0;p<pending.length;p++){
|
|
3827
|
-
var pu=pending[p];
|
|
3828
|
-
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>'+
|
|
3829
|
-
'<div class="admin-card-meta">'+t('admin.device')+esc(pu.deviceName||'unknown')+'</div>'+
|
|
3830
|
-
'<div class="admin-card-actions">'+
|
|
3831
|
-
'<button class="btn btn-sm btn-primary" onclick="adminApproveUser("'+escAttr(pu.id)+'","'+escAttr(pu.username||'')+'")">'+t('admin.approve')+'</button>'+
|
|
3832
|
-
'<button class="btn btn-sm btn-ghost" onclick="adminRejectUser("'+escAttr(pu.id)+'")" style="color:var(--rose)">'+t('admin.reject')+'</button>'+
|
|
3833
|
-
'</div></div>';
|
|
3834
|
-
}
|
|
3835
|
-
html+='</div>';
|
|
3836
|
-
}
|
|
3837
|
-
html+='<h3 style="font-size:14px;font-weight:600;color:var(--text);margin-bottom:10px">'+t('admin.activeUsers')+' ('+users.length+')</h3>';
|
|
3838
|
-
if(users.length===0){
|
|
3839
|
-
html+='<div class="admin-empty"><span class="ae-icon">\u{1F465}</span>'+t('admin.noActiveUsers')+'</div>';
|
|
3840
|
-
}else{
|
|
3841
|
-
for(var i=0;i<users.length;i++){
|
|
3842
|
-
var u=users[i];
|
|
3843
|
-
html+='<div class="admin-card"><div class="admin-card-header"><div class="admin-card-title">'+esc(u.username||u.id)+'</div>'+
|
|
3844
|
-
'<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span></div>'+
|
|
3845
|
-
'<div class="admin-card-meta">ID: '+esc(u.id)+(u.status?' \u00B7 Status: '+esc(u.status):'')+'</div></div>';
|
|
3846
|
-
}
|
|
3847
|
-
}
|
|
3848
|
-
el.innerHTML=html;
|
|
3849
|
-
}
|
|
3850
|
-
|
|
3851
|
-
async function adminApproveUser(userId,username){
|
|
3852
|
-
try{
|
|
3853
|
-
var r=await fetch('/api/sharing/approve-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
3854
|
-
var d=await r.json();
|
|
3855
|
-
if(d.ok){toast(t('toast.userApproved'),'success');loadAdminData();}else{toast(d.error||t('toast.approveFail'),'error');}
|
|
3856
|
-
}catch(e){toast(t('toast.approveFail')+': '+e.message,'error');}
|
|
3857
|
-
}
|
|
3858
|
-
async function adminRejectUser(userId){
|
|
3859
|
-
if(!confirm(t('confirm.rejectUser'))) return;
|
|
3860
|
-
try{
|
|
3861
|
-
var r=await fetch('/api/sharing/reject-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId})});
|
|
3862
|
-
var d=await r.json();
|
|
3863
|
-
if(d.ok){toast(t('toast.userRejected'),'success');loadAdminData();}else{toast(d.error||t('toast.rejectFail'),'error');}
|
|
3864
|
-
}catch(e){toast(t('toast.rejectFail')+': '+e.message,'error');}
|
|
3865
|
-
}
|
|
3866
|
-
|
|
3867
|
-
function renderAdminGroups(groups){
|
|
3868
|
-
var el=document.getElementById('adminGroupsPanel');
|
|
3869
|
-
if(!el) return;
|
|
3870
|
-
var html='<div style="margin-bottom:12px;display:flex;justify-content:space-between;align-items:center">'+
|
|
3871
|
-
'<h3 style="font-size:14px;font-weight:600;color:var(--text)">'+t('admin.groups')+' ('+groups.length+')</h3>'+
|
|
3872
|
-
'<button class="btn btn-sm btn-primary" onclick="showAdminCreateGroup()">'+t('admin.newGroup')+'</button></div>';
|
|
3873
|
-
html+='<div id="adminCreateGroupForm" style="display:none;margin-bottom:14px;padding:14px;background:var(--bg);border:1px solid var(--border);border-radius:10px">'+
|
|
3874
|
-
'<div style="display:flex;flex-direction:column;gap:8px">'+
|
|
3875
|
-
'<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)">'+
|
|
3876
|
-
'<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)">'+
|
|
3877
|
-
'<div style="display:flex;gap:8px"><button class="btn btn-sm btn-primary" onclick="adminCreateGroup()">'+t('admin.create')+'</button>'+
|
|
3878
|
-
'<button class="btn btn-sm btn-ghost" onclick="hideAdminCreateGroup()">'+t('admin.cancel')+'</button></div></div></div>';
|
|
3879
|
-
if(groups.length===0){
|
|
3880
|
-
html+='<div class="admin-empty"><span class="ae-icon">\u{1F4C2}</span>'+t('admin.noGroups')+'</div>';
|
|
3881
|
-
}else{
|
|
3882
|
-
for(var i=0;i<groups.length;i++){
|
|
3883
|
-
var g=groups[i];
|
|
3884
|
-
html+='<div class="admin-card"><div class="admin-card-header"><div class="admin-card-title">'+esc(g.name)+'</div>'+
|
|
3885
|
-
'<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>'+
|
|
3886
|
-
(g.description?'<div class="admin-card-meta">'+esc(g.description)+'</div>':'')+
|
|
3887
|
-
'<div id="adminGroupMembers_'+escAttr(g.id)+'" style="margin-top:10px"></div>'+
|
|
3888
|
-
'</div>';
|
|
3889
|
-
}
|
|
3890
|
-
}
|
|
3891
|
-
el.innerHTML=html;
|
|
3892
|
-
for(var i=0;i<groups.length;i++){adminLoadGroupMembers(groups[i].id);}
|
|
3893
|
-
}
|
|
3894
|
-
function showAdminCreateGroup(){var f=document.getElementById('adminCreateGroupForm');if(f)f.style.display='block';}
|
|
3895
|
-
function hideAdminCreateGroup(){var f=document.getElementById('adminCreateGroupForm');if(f)f.style.display='none';}
|
|
3896
|
-
async function adminCreateGroup(){
|
|
3897
|
-
var name=(document.getElementById('adminNewGroupName')).value.trim();
|
|
3898
|
-
var desc=(document.getElementById('adminNewGroupDesc')).value.trim();
|
|
3899
|
-
if(!name){toast(t('toast.groupNameRequired'),'error');return;}
|
|
3900
|
-
try{
|
|
3901
|
-
var r=await fetch('/api/sharing/groups',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:name,description:desc})});
|
|
3902
|
-
var d=await r.json();
|
|
3903
|
-
if(d.ok||d.id){toast(t('toast.groupCreated'),'success');hideAdminCreateGroup();loadAdminData();}else{toast(d.error||t('toast.createFail'),'error');}
|
|
3904
|
-
}catch(e){toast(t('toast.createFail')+': '+e.message,'error');}
|
|
3905
|
-
}
|
|
3906
|
-
async function adminDeleteGroup(groupId,groupName){
|
|
3907
|
-
if(!confirm(t('confirm.deleteGroupShort').replace('{name}',groupName))) return;
|
|
3908
|
-
try{
|
|
3909
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId),{method:'DELETE'});
|
|
3910
|
-
var d=await r.json();
|
|
3911
|
-
if(d.ok){toast(t('toast.groupDeleted'),'success');loadAdminData();}else{toast(d.error||t('toast.deleteFail'),'error');}
|
|
3912
|
-
}catch(e){toast(t('toast.deleteFail')+': '+e.message,'error');}
|
|
3913
|
-
}
|
|
3914
|
-
async function adminLoadGroupMembers(groupId){
|
|
3915
|
-
var el=document.getElementById('adminGroupMembers_'+groupId);
|
|
3916
|
-
if(!el) return;
|
|
3917
|
-
el.innerHTML=t('sharing.loading');
|
|
3918
|
-
try{
|
|
3919
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members');
|
|
3920
|
-
var d=await r.json();
|
|
3921
|
-
var members=Array.isArray(d.members)?d.members:[];
|
|
3922
|
-
var html='<div style="font-size:12px;margin-bottom:6px;color:var(--text-sec)">'+t('admin.membersCount').replace('{n}',members.length)+'</div>';
|
|
3923
|
-
if(members.length>0){
|
|
3924
|
-
html+='<div style="display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px">';
|
|
3925
|
-
for(var i=0;i<members.length;i++){
|
|
3926
|
-
var m=members[i];
|
|
3927
|
-
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">'+
|
|
3928
|
-
esc(m.username||m.userId)+
|
|
3929
|
-
' <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>';
|
|
3930
|
-
}
|
|
3931
|
-
html+='</div>';
|
|
3932
|
-
}else{
|
|
3933
|
-
html+='<div style="font-size:12px;color:var(--text-muted);margin-bottom:8px">'+t('admin.noMembers')+'</div>';
|
|
3934
|
-
}
|
|
3935
|
-
var memberIds=new Set(members.map(function(m){return m.userId;}));
|
|
3936
|
-
var available=adminDataCache.users.filter(function(u){return !memberIds.has(u.id);});
|
|
3937
|
-
if(available.length>0){
|
|
3938
|
-
html+='<div style="display:flex;gap:6px;align-items:center">'+
|
|
3939
|
-
'<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)">';
|
|
3940
|
-
for(var j=0;j<available.length;j++){
|
|
3941
|
-
html+='<option value="'+escAttr(available[j].id)+'">'+esc(available[j].username)+'</option>';
|
|
3942
|
-
}
|
|
3943
|
-
html+='</select><button class="btn btn-sm" onclick="adminAddGroupMember("'+escAttr(groupId)+'")">'+t('admin.add')+'</button></div>';
|
|
3944
|
-
}
|
|
3945
|
-
el.innerHTML=html;
|
|
3946
|
-
}catch(e){el.innerHTML=t('admin.groupsFailed')+esc(String(e));}
|
|
3947
|
-
}
|
|
3948
|
-
async function adminAddGroupMember(groupId){
|
|
3949
|
-
var sel=document.getElementById('adminAddMember_'+groupId);
|
|
3950
|
-
if(!sel) return;
|
|
3951
|
-
try{
|
|
3952
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:sel.value})});
|
|
3953
|
-
var d=await r.json();
|
|
3954
|
-
if(d.ok){toast(t('toast.memberAdded'),'success');adminLoadGroupMembers(groupId);}else{toast(d.error||t('toast.addFail'),'error');}
|
|
3955
|
-
}catch(e){toast(t('toast.addFail')+': '+e.message,'error');}
|
|
3956
|
-
}
|
|
3957
|
-
async function adminRemoveGroupMember(groupId,userId){
|
|
3958
|
-
if(!confirm(t('confirm.removeMember'))) return;
|
|
3959
|
-
try{
|
|
3960
|
-
var r=await fetch('/api/sharing/groups/'+encodeURIComponent(groupId)+'/members',{method:'DELETE',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId})});
|
|
3961
|
-
var d=await r.json();
|
|
3962
|
-
if(d.ok){toast(t('toast.memberRemoved'),'success');adminLoadGroupMembers(groupId);}else{toast(d.error||t('toast.removeFail'),'error');}
|
|
3963
|
-
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
3964
|
-
}
|
|
3965
|
-
|
|
3966
|
-
function renderAdminMemories(tasks){
|
|
3967
|
-
var el=document.getElementById('adminMemoriesPanel');
|
|
3968
|
-
if(!el) return;
|
|
3969
|
-
adminTasksCache=tasks;
|
|
3970
|
-
var html='<h3 style="font-size:14px;font-weight:600;color:var(--text);margin-bottom:10px">'+t('admin.sharedTasks')+' ('+tasks.length+')</h3>';
|
|
3971
|
-
if(tasks.length===0){
|
|
3972
|
-
html+='<div class="admin-empty"><span class="ae-icon">\u{1F4CB}</span>'+t('admin.noSharedTasks')+'</div>';
|
|
3973
|
-
}else{
|
|
3974
|
-
for(var i=0;i<tasks.length;i++){
|
|
3975
|
-
var tk=tasks[i];
|
|
3976
|
-
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>'+
|
|
3977
|
-
'</div>'+
|
|
3978
|
-
'<div class="admin-card-meta">'+
|
|
3979
|
-
t('admin.owner')+esc(tk.ownerName||tk.sourceUserId||'unknown')+
|
|
3980
|
-
(tk.chunkCount!=null?' \u00B7 '+t('admin.chunks')+tk.chunkCount:'')+
|
|
3981
|
-
' \u00B7 '+t('admin.updated')+new Date(tk.updatedAt||tk.createdAt).toLocaleDateString()+
|
|
3982
|
-
'</div>'+
|
|
3983
|
-
'<div class="admin-card-actions">'+
|
|
3984
|
-
'<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>'+
|
|
3985
|
-
'</div></div>';
|
|
3986
|
-
}
|
|
3987
|
-
}
|
|
3988
|
-
el.innerHTML=html;
|
|
3989
|
-
}
|
|
3990
|
-
|
|
3991
|
-
async function adminDeleteTask(taskId,taskTitle){
|
|
3992
|
-
if(!confirm(t('confirm.removeTask').replace('{name}',taskTitle))) return;
|
|
3993
|
-
try{
|
|
3994
|
-
var r=await fetch('/api/admin/shared-tasks/'+encodeURIComponent(taskId),{method:'DELETE'});
|
|
3995
|
-
var d=await r.json();
|
|
3996
|
-
if(d.ok){toast(t('toast.taskRemoved'),'success');loadAdminData();}else{toast(d.error||t('toast.removeFail'),'error');}
|
|
3997
|
-
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
3998
|
-
}
|
|
3999
|
-
|
|
4000
|
-
function renderAdminSkills(skills){
|
|
4001
|
-
var el=document.getElementById('adminSkillsPanel');
|
|
4002
|
-
if(!el) return;
|
|
4003
|
-
adminSkillsCache=skills;
|
|
4004
|
-
var html='<h3 style="font-size:14px;font-weight:600;color:var(--text);margin-bottom:10px">'+t('admin.sharedSkills')+' ('+skills.length+')</h3>';
|
|
4005
|
-
if(skills.length===0){
|
|
4006
|
-
html+='<div class="admin-empty"><span class="ae-icon">\u{1F9E0}</span>'+t('admin.noSharedSkills')+'</div>';
|
|
4007
|
-
}else{
|
|
4008
|
-
for(var i=0;i<skills.length;i++){
|
|
4009
|
-
var s=skills[i];
|
|
4010
|
-
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>'+
|
|
4011
|
-
'</div>'+
|
|
4012
|
-
'<div class="admin-card-meta">'+
|
|
4013
|
-
(s.description?esc(s.description)+'<br>':'')+
|
|
4014
|
-
t('admin.owner')+esc(s.ownerName||s.sourceUserId||'unknown')+
|
|
4015
|
-
(s.version!=null?' \u00B7 '+t('admin.version')+s.version:'')+
|
|
4016
|
-
(s.qualityScore!=null?' \u00B7 '+t('admin.quality')+s.qualityScore:'')+
|
|
4017
|
-
'</div>'+
|
|
4018
|
-
'<div class="admin-card-actions">'+
|
|
4019
|
-
'<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>'+
|
|
4020
|
-
'</div></div>';
|
|
4021
|
-
}
|
|
4022
|
-
}
|
|
4023
|
-
el.innerHTML=html;
|
|
4024
|
-
}
|
|
4025
|
-
|
|
4026
|
-
async function adminDeleteSkill(skillId,skillName){
|
|
4027
|
-
if(!confirm(t('confirm.removeSkill').replace('{name}',skillName))) return;
|
|
4028
|
-
try{
|
|
4029
|
-
var r=await fetch('/api/admin/shared-skills/'+encodeURIComponent(skillId),{method:'DELETE'});
|
|
4030
|
-
var d=await r.json();
|
|
4031
|
-
if(d.ok){toast(t('toast.skillRemoved'),'success');loadAdminData();}else{toast(d.error||t('toast.removeFail'),'error');}
|
|
4032
|
-
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
4033
|
-
}
|
|
4034
|
-
|
|
4035
|
-
function renderAdminSharedMemories(memories){
|
|
4036
|
-
var el=document.getElementById('adminSharedMemoriesPanel');
|
|
4037
|
-
if(!el) return;
|
|
4038
|
-
adminMemoriesCache=memories||[];
|
|
4039
|
-
var html='<h3 style="font-size:14px;font-weight:600;color:var(--text);margin-bottom:10px">'+t('admin.sharedMemories')+' ('+(memories||[]).length+')</h3>';
|
|
4040
|
-
if(!memories||memories.length===0){
|
|
4041
|
-
html+='<div class="admin-empty"><span class="ae-icon">\u{1F4AD}</span>'+t('admin.noSharedMemories')+'</div>';
|
|
4042
|
-
}else{
|
|
4043
|
-
for(var i=0;i<memories.length;i++){
|
|
4044
|
-
var m=memories[i];
|
|
4045
|
-
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>'+
|
|
4046
|
-
'</div>'+
|
|
4047
|
-
'<div class="admin-card-meta">'+
|
|
4048
|
-
t('admin.owner')+esc(m.ownerName||m.sourceUserId||'unknown')+
|
|
4049
|
-
(m.kind?' \u00B7 Kind: '+esc(m.kind):'')+
|
|
4050
|
-
(m.role?' \u00B7 Role: '+esc(m.role):'')+
|
|
4051
|
-
' \u00B7 '+t('admin.updated')+new Date(m.updatedAt||m.createdAt).toLocaleDateString()+
|
|
4052
|
-
'</div>'+
|
|
4053
|
-
'<div class="admin-card-actions">'+
|
|
4054
|
-
'<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>'+
|
|
4055
|
-
'</div></div>';
|
|
4056
|
-
}
|
|
4057
|
-
}
|
|
4058
|
-
el.innerHTML=html;
|
|
4059
|
-
}
|
|
4060
|
-
|
|
4061
|
-
async function adminDeleteMemory(memoryId,memoryTitle){
|
|
4062
|
-
if(!confirm(t('confirm.removeMemory').replace('{name}',memoryTitle))) return;
|
|
4063
|
-
try{
|
|
4064
|
-
var r=await fetch('/api/admin/shared-memories/'+encodeURIComponent(memoryId),{method:'DELETE'});
|
|
4065
|
-
var d=await r.json();
|
|
4066
|
-
if(d.ok){toast(t('toast.memoryRemoved'),'success');loadAdminData();}else{toast(d.error||t('toast.removeFail'),'error');}
|
|
4067
|
-
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
4068
|
-
}
|
|
4069
|
-
|
|
4070
|
-
function renderSharingMemorySearchResults(data,query){
|
|
4071
|
-
const list=document.getElementById('memoryList');
|
|
4072
|
-
const localHits=(data&&data.local&&Array.isArray(data.local.hits))?data.local.hits:[];
|
|
4073
|
-
const hubHits=(data&&data.hub&&Array.isArray(data.hub.hits))?data.hub.hits:[];
|
|
4074
|
-
document.getElementById('searchMeta').textContent='Search results for "'+query+'"';
|
|
4075
|
-
document.getElementById('sharingSearchMeta').textContent='Local '+localHits.length+' · Hub '+hubHits.length;
|
|
4076
|
-
document.getElementById('pagination').innerHTML='';
|
|
4077
|
-
list.innerHTML=''+
|
|
4078
|
-
'<div class="result-section">'+
|
|
4079
|
-
'<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>'+
|
|
4080
|
-
'<div class="search-hit-list">'+(localHits.length?localHits.map(function(hit,idx){
|
|
4081
|
-
return '<div class="search-hit-card">'+
|
|
4082
|
-
'<div class="summary">'+(idx+1)+'. '+esc(hit.summary||'(no summary)')+'</div>'+
|
|
4083
|
-
'<div class="excerpt">'+esc(hit.excerpt||'')+'</div>'+
|
|
4084
|
-
'<div class="search-hit-meta">'+
|
|
4085
|
-
'<span class="meta-chip">role: '+esc(hit.role||'unknown')+'</span>'+
|
|
4086
|
-
(hit.score!=null?'<span class="meta-chip">score: '+Math.round(hit.score*100)+'%</span>':'')+
|
|
4087
|
-
(hit.taskId?'<span class="meta-chip">task: '+esc(hit.taskId)+'</span>':'')+
|
|
4088
|
-
'</div>'+
|
|
4089
|
-
'</div>';
|
|
4090
|
-
}).join(''):'<div class="search-hit-card"><div class="excerpt">'+t('search.noLocal')+'</div></div>')+'</div>'+
|
|
4091
|
-
'</div>'+
|
|
4092
|
-
'<div class="result-section">'+
|
|
4093
|
-
'<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>'+
|
|
4094
|
-
'<div class="search-hit-list">'+(hubHits.length?hubHits.map(function(hit,idx){
|
|
4095
|
-
return '<div class="hub-hit-card">'+
|
|
4096
|
-
'<div class="summary">'+(idx+1)+'. '+esc(hit.summary||'(no summary)')+'</div>'+
|
|
4097
|
-
'<div class="excerpt">'+esc(hit.excerpt||'')+'</div>'+
|
|
4098
|
-
'<div class="hub-hit-meta">'+
|
|
4099
|
-
'<span class="meta-chip">owner: '+esc(hit.ownerName||'unknown')+'</span>'+
|
|
4100
|
-
(hit.groupName?'<span class="meta-chip">group: '+esc(hit.groupName)+'</span>':'')+
|
|
4101
|
-
'<span class="meta-chip">visibility: '+esc(hit.visibility||'hub')+'</span>'+
|
|
4102
|
-
'</div>'+
|
|
4103
|
-
'<div class="hub-hit-actions">'+
|
|
4104
|
-
'<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>'+
|
|
4105
|
-
'</div>'+
|
|
4106
|
-
'</div>';
|
|
4107
|
-
}).join(''):'<div class="hub-hit-card"><div class="excerpt">'+t('search.noHub')+'</div></div>')+'</div>'+
|
|
4108
|
-
'</div>';
|
|
4109
|
-
}
|
|
4110
|
-
|
|
4111
|
-
async function openSharedMemoryDetail(remoteHitId,title,owner,groupName){
|
|
4112
|
-
currentSharedMemoryHitId=remoteHitId;
|
|
4113
|
-
document.getElementById('sharedMemoryOverlay').classList.add('show');
|
|
4114
|
-
document.getElementById('sharedMemoryTitle').textContent=title||t('search.sharedMemory');
|
|
4115
|
-
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>':'');
|
|
4116
|
-
document.getElementById('sharedMemorySummary').textContent=t('sharing.loading');
|
|
4117
|
-
document.getElementById('sharedMemoryContent').textContent='';
|
|
4118
|
-
try{
|
|
4119
|
-
const r=await fetch('/api/sharing/memory-detail',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({remoteHitId:remoteHitId})});
|
|
4120
|
-
const d=await r.json();
|
|
4121
|
-
if(d.error) throw new Error(d.error);
|
|
4122
|
-
document.getElementById('sharedMemorySummary').textContent=d.summary||'';
|
|
4123
|
-
document.getElementById('sharedMemoryContent').textContent=d.content||'';
|
|
4124
|
-
}catch(e){
|
|
4125
|
-
document.getElementById('sharedMemorySummary').textContent=t('search.loadFailed');
|
|
4126
|
-
document.getElementById('sharedMemoryContent').textContent=String(e.message||e);
|
|
4127
|
-
}
|
|
4128
|
-
}
|
|
4129
|
-
|
|
4130
|
-
function closeSharedMemoryDetail(event){
|
|
4131
|
-
if(event && event.target!==document.getElementById('sharedMemoryOverlay')) return;
|
|
4132
|
-
document.getElementById('sharedMemoryOverlay').classList.remove('show');
|
|
4133
|
-
}
|
|
4134
|
-
|
|
4135
|
-
async function openHubMemoryDetail(cacheKey,idx){
|
|
4136
|
-
var arr=cacheKey==='admin'?adminMemoriesCache:hubMemoriesCache;
|
|
4137
|
-
var m=arr[idx];
|
|
4138
|
-
if(!m) return;
|
|
4139
|
-
var overlay=document.getElementById('sharedMemoryOverlay');
|
|
4140
|
-
overlay.classList.add('show');
|
|
4141
|
-
document.getElementById('sharedMemoryTitle').textContent=m.summary||m.content?.slice(0,80)||'(no summary)';
|
|
4142
|
-
var metaHtml='<span class="meta-item">\\u{1F310} Hub</span>'+
|
|
4143
|
-
(m.ownerName?'<span class="meta-item">'+t('admin.owner')+esc(m.ownerName)+'</span>':'')+
|
|
4144
|
-
(m.groupName?'<span class="meta-item">'+t('admin.group')+esc(m.groupName)+'</span>':'')+
|
|
4145
|
-
(m.kind?'<span class="meta-item">Kind: '+esc(m.kind)+'</span>':'')+
|
|
4146
|
-
(m.role?'<span class="meta-item">Role: '+esc(m.role)+'</span>':'')+
|
|
4147
|
-
'<span class="meta-item">visibility: '+esc(m.visibility||'hub')+'</span>'+
|
|
4148
|
-
'<span class="meta-item">'+new Date(m.updatedAt||m.createdAt||0).toLocaleString(dateLoc())+'</span>';
|
|
4149
|
-
document.getElementById('sharedMemoryMeta').innerHTML=metaHtml;
|
|
4150
|
-
document.getElementById('sharedMemorySummary').textContent=m.summary||'';
|
|
4151
|
-
document.getElementById('sharedMemoryContent').textContent=m.content||t('sharing.loading');
|
|
4152
|
-
// try to fetch full content from Hub API
|
|
4153
|
-
var remoteId=m.remoteHitId||m.id;
|
|
4154
|
-
if(remoteId){
|
|
4155
|
-
try{
|
|
4156
|
-
var r=await fetch('/api/sharing/memory-detail',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({remoteHitId:remoteId})});
|
|
4157
|
-
var d=await r.json();
|
|
4158
|
-
if(!d.error&&(d.content||d.summary)){
|
|
4159
|
-
if(d.summary) document.getElementById('sharedMemorySummary').textContent=d.summary;
|
|
4160
|
-
document.getElementById('sharedMemoryContent').textContent=d.content||m.content||'';
|
|
4161
|
-
}
|
|
4162
|
-
}catch(e){}
|
|
4163
|
-
}
|
|
4164
|
-
}
|
|
4165
|
-
|
|
4166
|
-
function openHubTaskDetailFromCache(cacheKey,idx){
|
|
4167
|
-
var arr=cacheKey==='admin'?adminTasksCache:hubTasksCache;
|
|
4168
|
-
var task=arr[idx];
|
|
4169
|
-
if(!task) return;
|
|
4170
|
-
var overlay=document.getElementById('taskDetailOverlay');
|
|
4171
|
-
overlay.classList.add('show');
|
|
4172
|
-
document.getElementById('taskDetailTitle').textContent=task.title||'(no title)';
|
|
4173
|
-
document.getElementById('taskShareActions').innerHTML='';
|
|
4174
|
-
var meta=[
|
|
4175
|
-
'<span class="meta-item">\\u{1F310} Hub</span>',
|
|
4176
|
-
task.status?'<span class="meta-item"><span class="task-status-badge '+task.status+'">'+esc(task.status)+'</span></span>':'',
|
|
4177
|
-
'<span class="meta-item">'+t('admin.owner')+esc(task.ownerName||'unknown')+'</span>',
|
|
4178
|
-
task.groupName?'<span class="meta-item">'+t('admin.group')+esc(task.groupName)+'</span>':'',
|
|
4179
|
-
'<span class="meta-item">visibility: '+esc(task.visibility||'hub')+'</span>',
|
|
4180
|
-
task.chunkCount!=null?'<span class="meta-item">\\u{1F4DD} '+esc(String(task.chunkCount))+' '+t('tasks.chunks.label')+'</span>':'',
|
|
4181
|
-
task.startedAt?'<span class="meta-item">\\u{1F4C5} '+formatTime(task.startedAt)+'</span>':'',
|
|
4182
|
-
task.endedAt?'<span class="meta-item">\\u2192 '+formatTime(task.endedAt)+'</span>':'',
|
|
4183
|
-
(task.updatedAt||task.createdAt)?'<span class="meta-item">'+t('admin.updated')+new Date(task.updatedAt||task.createdAt).toLocaleString(dateLoc())+'</span>':'',
|
|
4184
|
-
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>':'',
|
|
4185
|
-
].filter(Boolean);
|
|
4186
|
-
document.getElementById('taskDetailMeta').innerHTML=meta.join('');
|
|
4187
|
-
document.getElementById('taskSkillSection').innerHTML='';
|
|
4188
|
-
document.getElementById('taskSkillSection').className='task-skill-section';
|
|
4189
|
-
document.getElementById('taskDetailSummary').innerHTML=task.summary?renderSummaryHtml(task.summary):'<div style="color:var(--text-muted);font-size:13px">'+t('tasks.nochunks')+'</div>';
|
|
4190
|
-
document.getElementById('taskDetailChunks').innerHTML='<div style="color:var(--text-muted);padding:12px;font-size:13px">'+t('tasks.nochunks')+'</div>';
|
|
4191
|
-
}
|
|
4192
|
-
|
|
4193
|
-
function openHubSkillDetailFromCache(cacheKey,idx){
|
|
4194
|
-
var arr=cacheKey==='admin'?adminSkillsCache:hubSkillsCache;
|
|
4195
|
-
var skill=arr[idx];
|
|
4196
|
-
if(!skill) return;
|
|
4197
|
-
var overlay=document.getElementById('skillDetailOverlay');
|
|
4198
|
-
overlay.classList.add('show');
|
|
4199
|
-
document.getElementById('skillDetailTitle').textContent='\\u{1F9E0} '+(skill.name||'(no name)');
|
|
4200
|
-
var qs=skill.qualityScore;
|
|
4201
|
-
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>':'';
|
|
4202
|
-
var meta=[
|
|
4203
|
-
'<span class="meta-item">\\u{1F310} Hub</span>',
|
|
4204
|
-
skill.version!=null?'<span class="meta-item"><span class="skill-badge version">v'+skill.version+'</span></span>':'',
|
|
4205
|
-
skill.status?'<span class="meta-item"><span class="skill-badge status-'+skill.status+'">'+esc(skill.status)+'</span></span>':'',
|
|
4206
|
-
'<span class="meta-item">visibility: '+esc(skill.visibility||'hub')+'</span>',
|
|
4207
|
-
qsBadge,
|
|
4208
|
-
'<span class="meta-item">'+t('admin.owner')+esc(skill.ownerName||'unknown')+'</span>',
|
|
4209
|
-
skill.groupName?'<span class="meta-item">'+t('admin.group')+esc(skill.groupName)+'</span>':'',
|
|
4210
|
-
(skill.updatedAt||skill.createdAt)?'<span class="meta-item">'+t('admin.updated')+new Date(skill.updatedAt||skill.createdAt).toLocaleString(dateLoc())+'</span>':'',
|
|
4211
|
-
].filter(Boolean);
|
|
4212
|
-
document.getElementById('skillDetailMeta').innerHTML=meta.join('');
|
|
4213
|
-
document.getElementById('skillDetailDesc').textContent=skill.description||'';
|
|
4214
|
-
document.getElementById('skillFilesList').innerHTML='';
|
|
4215
|
-
document.getElementById('skillDetailContent').innerHTML=skill.content?'<pre>'+esc(skill.content)+'</pre>':'';
|
|
4216
|
-
document.getElementById('skillVersionsList').innerHTML='';
|
|
4217
|
-
document.getElementById('skillRelatedTasks').innerHTML='';
|
|
4218
|
-
var visBtn=document.getElementById('skillVisibilityBtn');
|
|
4219
|
-
if(visBtn) visBtn.style.display='none';
|
|
4220
|
-
var dlBtn=document.getElementById('skillDownloadBtn');
|
|
4221
|
-
if(dlBtn) dlBtn.style.display='none';
|
|
4222
|
-
var shareBtn=document.getElementById('skillShareActions');
|
|
4223
|
-
if(shareBtn) shareBtn.innerHTML='';
|
|
4224
|
-
}
|
|
4225
|
-
|
|
4226
|
-
function escAttr(s){return String(s||'').replace(/&/g,'&').replace(/'/g,''').replace(/"/g,'"').replace(/</g,'<').replace(/>/g,'>');}
|
|
4227
|
-
|
|
4228
|
-
function renderTaskShareActions(task){
|
|
4229
|
-
currentTaskDetail=task||null;
|
|
4230
|
-
const el=document.getElementById('taskShareActions');
|
|
4231
|
-
if(!el){return;}
|
|
4232
|
-
if(!task||!task.id){el.innerHTML='';return;}
|
|
4233
|
-
const current=(task.sharingVisibility||task.visibility||null);
|
|
4234
|
-
const isShared=!!current;
|
|
4235
|
-
var statusHtml='';
|
|
4236
|
-
if(isShared){
|
|
4237
|
-
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>';
|
|
4238
|
-
}
|
|
4239
|
-
el.innerHTML=statusHtml+
|
|
4240
|
-
'<button class="btn btn-sm" onclick="shareCurrentTask()">'+(isShared?t('share.updateBtn'):t('share.shareBtn'))+'</button>'+
|
|
4241
|
-
(isShared?'<button class="btn btn-sm btn-ghost" onclick="unshareCurrentTask()">'+t('share.unshareBtn')+'</button>':'');
|
|
4242
|
-
}
|
|
4243
|
-
|
|
4244
|
-
async function shareCurrentTask(){
|
|
4245
|
-
if(!currentTaskDetail) return;
|
|
4246
|
-
const visibility='public';
|
|
4247
|
-
try{
|
|
4248
|
-
const r=await fetch('/api/sharing/tasks/share',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({taskId:currentTaskDetail.id,visibility:visibility})});
|
|
4249
|
-
const d=await r.json();
|
|
4250
|
-
if(d.ok||d.shared){toast(t('toast.taskShared'),'success');currentTaskDetail.sharingVisibility=visibility;renderTaskShareActions(currentTaskDetail);} else {toast(d.error||t('toast.taskShareFail'),'error');}
|
|
4251
|
-
}catch(e){toast(t('toast.taskShareFail')+': '+e.message,'error');}
|
|
4252
|
-
}
|
|
4253
|
-
|
|
4254
|
-
async function unshareCurrentTask(){
|
|
4255
|
-
if(!currentTaskDetail) return;
|
|
4256
|
-
try{
|
|
4257
|
-
const r=await fetch('/api/sharing/tasks/unshare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({taskId:currentTaskDetail.id})});
|
|
4258
|
-
const d=await r.json();
|
|
4259
|
-
if(d.ok||d.unshared){toast(t('toast.taskUnshared'),'success');currentTaskDetail.sharingVisibility=null;renderTaskShareActions(currentTaskDetail);} else {toast(d.error||t('toast.taskUnshareFail'),'error');}
|
|
4260
|
-
}catch(e){toast(t('toast.taskUnshareFail')+': '+e.message,'error');}
|
|
4261
|
-
}
|
|
4262
|
-
|
|
4263
|
-
function renderSkillShareActions(skill){
|
|
4264
|
-
const el=document.getElementById('skillShareActions');
|
|
4265
|
-
if(!el){return;}
|
|
4266
|
-
if(!skill||!skill.id){el.innerHTML='';return;}
|
|
4267
|
-
const current=(skill.sharingVisibility||null);
|
|
4268
|
-
const isShared=!!current;
|
|
4269
|
-
var statusHtml='';
|
|
4270
|
-
if(isShared){
|
|
4271
|
-
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>';
|
|
4272
|
-
}
|
|
4273
|
-
el.innerHTML=statusHtml+
|
|
4274
|
-
'<button class="btn btn-sm" onclick="shareCurrentSkill()">'+(isShared?t('share.updateBtn'):t('share.shareBtn'))+'</button>'+
|
|
4275
|
-
(isShared?'<button class="btn btn-sm btn-ghost" onclick="unshareCurrentSkill()">'+t('share.unshareBtn')+'</button>':'');
|
|
4276
|
-
}
|
|
4277
|
-
|
|
4278
|
-
async function shareCurrentSkill(){
|
|
4279
|
-
if(!currentSkillDetail) return;
|
|
4280
|
-
const visibility='public';
|
|
4281
|
-
try{
|
|
4282
|
-
const r=await fetch('/api/sharing/skills/share',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({skillId:currentSkillDetail.id,visibility:visibility})});
|
|
4283
|
-
const d=await r.json();
|
|
4284
|
-
if(d.ok){toast(t('toast.skillShared'),'success');currentSkillDetail.sharingVisibility=visibility;renderSkillShareActions(currentSkillDetail);} else {toast(d.error||t('toast.skillShareFail'),'error');}
|
|
4285
|
-
}catch(e){toast(t('toast.skillShareFail')+': '+e.message,'error');}
|
|
4286
|
-
}
|
|
4287
|
-
|
|
4288
|
-
async function unshareCurrentSkill(){
|
|
4289
|
-
if(!currentSkillDetail) return;
|
|
4290
|
-
try{
|
|
4291
|
-
const r=await fetch('/api/sharing/skills/unshare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({skillId:currentSkillDetail.id})});
|
|
4292
|
-
const d=await r.json();
|
|
4293
|
-
if(d.ok){toast(t('toast.skillUnshared'),'success');currentSkillDetail.sharingVisibility=null;renderSkillShareActions(currentSkillDetail);} else {toast(d.error||t('toast.skillUnshareFail'),'error');}
|
|
4294
|
-
}catch(e){toast(t('toast.skillUnshareFail')+': '+e.message,'error');}
|
|
4295
|
-
}
|
|
4296
|
-
|
|
4297
|
-
async function shareMemoryPrompt(chunkId){
|
|
4298
|
-
try{
|
|
4299
|
-
const r=await fetch('/api/sharing/memories/share',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({chunkId:chunkId,visibility:'public'})});
|
|
4300
|
-
const d=await r.json();
|
|
4301
|
-
if(d.ok){toast(t('toast.memoryShared'),'success');loadMemories();} else {toast(d.error||t('toast.memoryShareFail'),'error');}
|
|
4302
|
-
}catch(e){toast(t('toast.memoryShareFail')+': '+e.message,'error');}
|
|
4303
|
-
}
|
|
4304
|
-
|
|
4305
|
-
async function unshareMemory(chunkId){
|
|
4306
|
-
try{
|
|
4307
|
-
const r=await fetch('/api/sharing/memories/unshare',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({chunkId:chunkId})});
|
|
4308
|
-
const d=await r.json();
|
|
4309
|
-
if(d.ok){toast(t('toast.memoryUnshared'),'success');loadMemories();} else {toast(d.error||t('toast.memoryUnshareFail'),'error');}
|
|
4310
|
-
}catch(e){toast(t('toast.memoryUnshareFail')+': '+e.message,'error');}
|
|
4311
|
-
}
|
|
4312
|
-
|
|
4313
|
-
function debounceSkillSearch(){
|
|
4314
|
-
clearTimeout(skillSearchTimer);
|
|
4315
|
-
skillSearchTimer=setTimeout(function(){loadSkills();},300);
|
|
4316
|
-
}
|
|
4317
|
-
|
|
4318
|
-
async function pullHubSkill(skillId){
|
|
4319
|
-
try{
|
|
4320
|
-
const r=await fetch('/api/sharing/skills/pull',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({skillId:skillId})});
|
|
4321
|
-
const d=await r.json();
|
|
4322
|
-
if(d.ok||d.pulled||d.details){toast(t('toast.skillPulled'),'success');loadSkills();} else {toast(d.error||t('toast.skillPullFail'),'error');}
|
|
4323
|
-
}catch(e){toast(t('toast.skillPullFail')+': '+e.message,'error');}
|
|
4324
|
-
}
|
|
4325
|
-
|
|
4326
|
-
// ─── Logs ───
|
|
4327
|
-
let logAutoTimer=null;
|
|
4328
|
-
let logPage=1;
|
|
4329
|
-
const LOG_PAGE_SIZE=20;
|
|
4330
|
-
async function loadLogs(page){
|
|
4331
|
-
if(typeof page==='number') logPage=page;
|
|
4332
|
-
try{
|
|
4333
|
-
const toolFilter=document.getElementById('logToolFilter').value;
|
|
4334
|
-
const offset=(logPage-1)*LOG_PAGE_SIZE;
|
|
4335
|
-
const url='/api/logs?limit='+LOG_PAGE_SIZE+'&offset='+offset+(toolFilter?'&tool='+encodeURIComponent(toolFilter):'');
|
|
4336
|
-
const [logsRes,toolsRes]=await Promise.all([fetch(url),fetch('/api/log-tools')]);
|
|
4337
|
-
if(!logsRes.ok) return;
|
|
4338
|
-
const logsData=await logsRes.json();
|
|
4339
|
-
const toolsData=await toolsRes.json();
|
|
4340
|
-
renderLogToolFilter(toolsData.tools||[],toolFilter);
|
|
4341
|
-
renderLogs(logsData.logs||[]);
|
|
4342
|
-
renderLogPagination(logsData.page||1,logsData.totalPages||1,logsData.total||0);
|
|
4343
|
-
startLogAutoRefresh();
|
|
4344
|
-
}catch(e){console.error('loadLogs',e)}
|
|
4345
|
-
}
|
|
4346
|
-
function onLogFilterChange(){logPage=1;loadLogs(1);}
|
|
4347
|
-
function renderLogPagination(page,totalPages,total){
|
|
4348
|
-
const el=document.getElementById('logsPagination');
|
|
4349
|
-
if(!el||totalPages<=1){if(el)el.innerHTML='';return;}
|
|
4350
|
-
const pages=[];
|
|
4351
|
-
const range=2;
|
|
4352
|
-
for(let i=1;i<=totalPages;i++){
|
|
4353
|
-
if(i===1||i===totalPages||Math.abs(i-page)<=range){
|
|
4354
|
-
pages.push(i);
|
|
4355
|
-
}else if(pages[pages.length-1]!=='...'){
|
|
4356
|
-
pages.push('...');
|
|
4357
|
-
}
|
|
4358
|
-
}
|
|
4359
|
-
let html='<div class="logs-pagination">';
|
|
4360
|
-
html+='<button class="btn btn-sm btn-ghost" '+(page<=1?'disabled':'')+' onclick="loadLogs('+(page-1)+')">\u2039</button>';
|
|
4361
|
-
pages.forEach(p=>{
|
|
4362
|
-
if(p==='...'){html+='<span class="page-ellipsis">\u2026</span>';}
|
|
4363
|
-
else{html+='<button class="btn btn-sm '+(p===page?'btn-primary':'btn-ghost')+'" onclick="loadLogs('+p+')">'+p+'</button>';}
|
|
4364
|
-
});
|
|
4365
|
-
html+='<button class="btn btn-sm btn-ghost" '+(page>=totalPages?'disabled':'')+' onclick="loadLogs('+(page+1)+')">\u203A</button>';
|
|
4366
|
-
html+='<span class="page-total">'+total+' total</span>';
|
|
4367
|
-
html+='</div>';
|
|
4368
|
-
el.innerHTML=html;
|
|
4369
|
-
}
|
|
4370
|
-
|
|
4371
|
-
function renderLogToolFilter(tools,current){
|
|
4372
|
-
const sel=document.getElementById('logToolFilter');
|
|
4373
|
-
const opts=['<option value="">'+t('logs.allTools')+'</option>'];
|
|
4374
|
-
tools.forEach(tn=>{
|
|
4375
|
-
opts.push('<option value="'+tn+'"'+(tn===current?' selected':'')+'>'+tn+'</option>');
|
|
4376
|
-
});
|
|
4377
|
-
sel.innerHTML=opts.join('');
|
|
4378
|
-
}
|
|
4379
|
-
|
|
4380
|
-
function formatLogTime(ts){
|
|
4381
|
-
const d=new Date(ts);
|
|
4382
|
-
const time=d.toLocaleTimeString(dateLoc(),{hour:'2-digit',minute:'2-digit',second:'2-digit',hour12:false});
|
|
4383
|
-
const y=d.getFullYear();
|
|
4384
|
-
const m=String(d.getMonth()+1).padStart(2,'0');
|
|
4385
|
-
const day=String(d.getDate()).padStart(2,'0');
|
|
4386
|
-
return y+'-'+m+'-'+day+' '+time;
|
|
4387
|
-
}
|
|
4388
|
-
|
|
4389
|
-
function parseMemoryAddEntries(out){
|
|
4390
|
-
var lines=out.split('\\n');
|
|
4391
|
-
var results=[];
|
|
4392
|
-
for(var i=0;i<lines.length;i++){
|
|
4393
|
-
var line=lines[i].trim();
|
|
4394
|
-
if(!line) continue;
|
|
4395
|
-
if(line.startsWith('{')){
|
|
4396
|
-
try{
|
|
4397
|
-
var obj=JSON.parse(line);
|
|
4398
|
-
if(obj.role&&obj.action){results.push({role:obj.role,action:obj.action,summary:obj.summary||'',content:obj.content||'',reason:obj.reason||''});continue;}
|
|
4399
|
-
}catch(e){}
|
|
4400
|
-
}
|
|
4401
|
-
var rm=line.match(/^\\[(\\w+)\\]\\s*([^\u2192]+)\u2192/);
|
|
4402
|
-
if(rm){
|
|
4403
|
-
var role=rm[1],actionRaw=rm[2].trim();
|
|
4404
|
-
var action='stored';
|
|
4405
|
-
if(actionRaw.indexOf('exact-dup')>=0||actionRaw.indexOf('\u23ED')>=0) action='exact-dup';
|
|
4406
|
-
else if(actionRaw.indexOf('dedup')>=0||actionRaw.indexOf('\uD83D\uDD01')>=0) action='dedup';
|
|
4407
|
-
else if(actionRaw.indexOf('merged')>=0||actionRaw.indexOf('\uD83D\uDD00')>=0) action='merged';
|
|
4408
|
-
else if(actionRaw.indexOf('error')>=0||actionRaw.indexOf('\u274C')>=0) action='error';
|
|
4409
|
-
var afterArrow=line.replace(/^\\[\\w+\\]\\s*[^\u2192]+\u2192\\s*/,'');
|
|
4410
|
-
var contentLines=[afterArrow];
|
|
4411
|
-
while(i+1<lines.length&&!lines[i+1].trim().startsWith('[')&&!lines[i+1].trim().startsWith('{')){
|
|
4412
|
-
i++;
|
|
4413
|
-
if(lines[i].trim()) contentLines.push(lines[i]);
|
|
4414
|
-
else contentLines.push('');
|
|
4415
|
-
}
|
|
4416
|
-
results.push({role:role,action:action,summary:'',content:contentLines.join('\\n'),reason:''});
|
|
4417
|
-
}
|
|
4418
|
-
}
|
|
4419
|
-
return results;
|
|
2271
|
+
return results;
|
|
4420
2272
|
}
|
|
4421
2273
|
|
|
4422
2274
|
function buildLogSummary(lg){
|
|
@@ -4640,7 +2492,6 @@ function setMetricsDays(d){
|
|
|
4640
2492
|
}
|
|
4641
2493
|
|
|
4642
2494
|
async function loadMetrics(){
|
|
4643
|
-
try{
|
|
4644
2495
|
const r=await fetch('/api/metrics?days='+metricsDays);
|
|
4645
2496
|
const d=await r.json();
|
|
4646
2497
|
document.getElementById('mTotal').textContent=formatNum(d.totals.memories);
|
|
@@ -4649,11 +2500,9 @@ async function loadMetrics(){
|
|
|
4649
2500
|
document.getElementById('mEmbeddings').textContent=formatNum(d.totals.embeddings);
|
|
4650
2501
|
renderChartWrites(d.writesPerDay);
|
|
4651
2502
|
loadToolMetrics();
|
|
4652
|
-
}catch(e){console.error('loadMetrics',e)}
|
|
4653
2503
|
}
|
|
4654
2504
|
|
|
4655
2505
|
function formatNum(n){return n>=1e6?(n/1e6).toFixed(1)+'M':n>=1e3?(n/1e3).toFixed(1)+'k':String(n);}
|
|
4656
|
-
function dateLoc(){return curLang==='zh'?'zh-CN':'en-US';}
|
|
4657
2506
|
|
|
4658
2507
|
/* ─── Tasks View Logic ─── */
|
|
4659
2508
|
let tasksStatusFilter='';
|
|
@@ -4669,24 +2518,29 @@ function setTaskStatusFilter(btn,status){
|
|
|
4669
2518
|
}
|
|
4670
2519
|
|
|
4671
2520
|
async function loadTasks(){
|
|
4672
|
-
const scope=document.getElementById('taskSearchScope')?document.getElementById('taskSearchScope').value:taskSearchScope;
|
|
4673
|
-
taskSearchScope=scope||'local';
|
|
4674
|
-
if(taskSearchScope!=='local'){ return loadHubTasks(); }
|
|
4675
2521
|
const list=document.getElementById('tasksList');
|
|
4676
2522
|
list.innerHTML='<div class="spinner"></div>';
|
|
4677
2523
|
try{
|
|
4678
2524
|
const params=new URLSearchParams({limit:String(TASKS_PER_PAGE),offset:String(tasksPage*TASKS_PER_PAGE)});
|
|
4679
2525
|
if(tasksStatusFilter) params.set('status',tasksStatusFilter);
|
|
4680
|
-
const
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
]);
|
|
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();
|
|
4687
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();
|
|
4688
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();
|
|
4689
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();
|
|
4690
2544
|
document.getElementById('tasksSkippedCount').textContent=formatNum(skipD.total);
|
|
4691
2545
|
|
|
4692
2546
|
if(!data.tasks||data.tasks.length===0){
|
|
@@ -4752,16 +2606,13 @@ async function openTaskDetail(taskId){
|
|
|
4752
2606
|
document.getElementById('taskSkillSection').className='task-skill-section';
|
|
4753
2607
|
document.getElementById('taskDetailSummary').textContent='';
|
|
4754
2608
|
document.getElementById('taskDetailChunks').innerHTML='<div class="spinner"></div>';
|
|
4755
|
-
document.getElementById('taskShareActions').innerHTML='';
|
|
4756
2609
|
document.getElementById('taskDetailActions').innerHTML='';
|
|
4757
2610
|
|
|
4758
2611
|
try{
|
|
4759
2612
|
const r=await fetch('/api/task/'+taskId);
|
|
4760
2613
|
const task=await r.json();
|
|
4761
|
-
currentTaskDetail=task;
|
|
4762
2614
|
|
|
4763
2615
|
document.getElementById('taskDetailTitle').textContent=task.title||t('tasks.untitled');
|
|
4764
|
-
renderTaskShareActions(task);
|
|
4765
2616
|
|
|
4766
2617
|
const meta=[
|
|
4767
2618
|
'<span class="meta-item"><span class="task-status-badge '+task.status+'">'+t('tasks.status.'+task.status)+'</span></span>',
|
|
@@ -4930,177 +2781,60 @@ function setSkillStatusFilter(btn,status){
|
|
|
4930
2781
|
|
|
4931
2782
|
async function loadSkills(){
|
|
4932
2783
|
const list=document.getElementById('skillsList');
|
|
4933
|
-
const hubList=document.getElementById('hubSkillsList');
|
|
4934
2784
|
list.innerHTML='<div class="spinner"></div>';
|
|
4935
|
-
var hubSection=document.getElementById('hubSkillsSection');
|
|
4936
|
-
if(hubList){
|
|
4937
|
-
if(skillSearchScope==='local'){
|
|
4938
|
-
if(hubSection) hubSection.style.display='none';
|
|
4939
|
-
}else{
|
|
4940
|
-
if(hubSection) hubSection.style.display='block';
|
|
4941
|
-
hubList.innerHTML='<div class="spinner"></div>';
|
|
4942
|
-
}
|
|
4943
|
-
}
|
|
4944
|
-
|
|
4945
|
-
const query=(document.getElementById('skillSearchInput')?.value||'').trim();
|
|
4946
|
-
const scope=document.getElementById('skillSearchScope') ? document.getElementById('skillSearchScope').value : skillSearchScope;
|
|
4947
|
-
skillSearchScope=scope||'local';
|
|
4948
|
-
|
|
4949
2785
|
try{
|
|
4950
2786
|
const params=new URLSearchParams();
|
|
4951
2787
|
if(skillsStatusFilter) params.set('status',skillsStatusFilter);
|
|
4952
2788
|
const visFilter=document.getElementById('skillVisibilityFilter')?.value;
|
|
4953
2789
|
if(visFilter) params.set('visibility',visFilter);
|
|
2790
|
+
const r=await fetch('/api/skills?'+params);
|
|
2791
|
+
const data=await r.json();
|
|
4954
2792
|
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
localSkills=localSkills.filter(skill=>{
|
|
4961
|
-
const haystack=[skill.name,skill.description,skill.tags].filter(Boolean).join(' ').toLowerCase();
|
|
4962
|
-
return haystack.includes(q);
|
|
4963
|
-
});
|
|
4964
|
-
}
|
|
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);
|
|
4965
2798
|
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
return '<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+(query?t('skills.search.noresult'):t('skills.empty'))+'</div>';
|
|
4969
|
-
}
|
|
4970
|
-
return skills.map(skill=>{
|
|
4971
|
-
const timeStr=formatTime(skill.createdAt);
|
|
4972
|
-
const tags=parseTags(skill.tags);
|
|
4973
|
-
const installedClass=skill.installed?'installed':'';
|
|
4974
|
-
const statusClass=skill.status==='archived'?'archived':(skill.status==='draft'?'draft':'');
|
|
4975
|
-
const sourceLabel=tags.includes('hub-import')?'hub-import':skill.sourceType;
|
|
4976
|
-
const qs=skill.qualityScore;
|
|
4977
|
-
const qsBadge=qs!==null&&qs!==undefined?'<span class="skill-badge quality '+(qs>=7?'high':qs>=5?'mid':'low')+'">★ '+qs.toFixed(1)+'</span>':'';
|
|
4978
|
-
const visBadge=skill.visibility==='public'?'<span class="skill-badge visibility-public">🌐 '+t('skills.visibility.public')+'</span>':'';
|
|
4979
|
-
return '<div class="skill-card '+installedClass+' '+statusClass+'" onclick="openSkillDetail("'+escAttr(skill.id)+'")">'+
|
|
4980
|
-
'<div class="skill-card-top">'+
|
|
4981
|
-
'<div class="skill-card-name">🧠 '+esc(skill.name)+'</div>'+
|
|
4982
|
-
'<div class="skill-card-badges">'+
|
|
4983
|
-
qsBadge+
|
|
4984
|
-
'<span class="skill-badge version">v'+skill.version+'</span>'+
|
|
4985
|
-
visBadge+
|
|
4986
|
-
(skill.installed?'<span class="skill-badge installed">'+t('skills.installed.badge')+'</span>':'')+
|
|
4987
|
-
'<span class="skill-badge status-'+skill.status+'">'+t('skills.status.'+skill.status)+'</span>'+
|
|
4988
|
-
'</div>'+
|
|
4989
|
-
'</div>'+
|
|
4990
|
-
'<div class="skill-card-desc">'+esc(skill.description)+'</div>'+
|
|
4991
|
-
'<div class="skill-card-bottom">'+
|
|
4992
|
-
'<span class="tag"><span class="icon">📅</span> '+timeStr+'</span>'+
|
|
4993
|
-
'<span class="tag"><span class="icon">📦</span> '+sourceLabel+'</span>'+
|
|
4994
|
-
(tags.length>0?'<div class="skill-card-tags">'+tags.map(t=>'<span class="skill-tag">'+esc(t)+'</span>').join('')+'</div>':'')+
|
|
4995
|
-
'</div>'+
|
|
4996
|
-
'</div>';
|
|
4997
|
-
}).join('');
|
|
4998
|
-
};
|
|
4999
|
-
|
|
5000
|
-
list.innerHTML=renderLocalCards(localSkills);
|
|
5001
|
-
|
|
5002
|
-
if(skillSearchScope==='local'){
|
|
5003
|
-
if(hubSection) hubSection.style.display='none';
|
|
5004
|
-
document.getElementById('skillSearchMeta').textContent=query?(t('skills.search.local')+' '+localSkills.length):'';
|
|
5005
|
-
document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
|
|
5006
|
-
document.getElementById('skillsActiveCount').textContent=formatNum(localSkills.filter(s=>s.status==='active').length);
|
|
5007
|
-
document.getElementById('skillsDraftCount').textContent=formatNum(localSkills.filter(s=>s.status==='draft').length);
|
|
5008
|
-
document.getElementById('skillsInstalledCount').textContent=formatNum(localSkills.filter(s=>s.installed).length);
|
|
5009
|
-
document.getElementById('skillsPublicCount').textContent=formatNum(localSkills.filter(s=>s.visibility==='public').length);
|
|
5010
|
-
return;
|
|
5011
|
-
}
|
|
5012
|
-
|
|
5013
|
-
if(!query){
|
|
5014
|
-
if(hubSection) hubSection.style.display='block';
|
|
5015
|
-
if(hubList){ loadHubSkills(hubList); }
|
|
5016
|
-
document.getElementById('skillSearchMeta').textContent=t('skills.search.local')+' '+localSkills.length;
|
|
5017
|
-
document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
|
|
5018
|
-
document.getElementById('skillsActiveCount').textContent=formatNum(localSkills.filter(s=>s.status==='active').length);
|
|
5019
|
-
document.getElementById('skillsDraftCount').textContent=formatNum(localSkills.filter(s=>s.status==='draft').length);
|
|
5020
|
-
document.getElementById('skillsInstalledCount').textContent=formatNum(localSkills.filter(s=>s.installed).length);
|
|
5021
|
-
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>';
|
|
5022
2801
|
return;
|
|
5023
2802
|
}
|
|
5024
2803
|
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
if(hubList){
|
|
5043
|
-
if(hubSection) hubSection.style.display=hubHits.length?'block':'none';
|
|
5044
|
-
hubList.innerHTML=hubHits.length?hubHits.map(function(skill){
|
|
5045
|
-
return '<div class="hub-skill-card">'+
|
|
5046
|
-
'<div class="summary">'+esc(skill.name)+'</div>'+
|
|
5047
|
-
'<div class="excerpt">'+esc(skill.description||'')+'</div>'+
|
|
5048
|
-
'<div class="hub-skill-meta">'+
|
|
5049
|
-
'<span class="meta-chip">owner: '+esc(skill.ownerName||'unknown')+'</span>'+
|
|
5050
|
-
(skill.groupName?'<span class="meta-chip">group: '+esc(skill.groupName)+'</span>':'')+
|
|
5051
|
-
'<span class="meta-chip">visibility: '+esc(skill.visibility||'hub')+'</span>'+
|
|
5052
|
-
(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>'+
|
|
5053
2821
|
'</div>'+
|
|
5054
|
-
'<div class="hub-skill-actions"><button class="btn btn-sm" onclick="event.stopPropagation();pullHubSkill("'+escAttr(skill.skillId)+'")">Pull to Local</button></div>'+
|
|
5055
|
-
'</div>';
|
|
5056
|
-
}).join(''):'';
|
|
5057
|
-
}
|
|
5058
|
-
|
|
5059
|
-
document.getElementById('skillSearchMeta').textContent=t('skills.search.local')+' '+localHits.length+(hubHits.length?' · Hub '+hubHits.length:'');
|
|
5060
|
-
document.getElementById('skillsTotalCount').textContent=formatNum(localHits.length+hubHits.length);
|
|
5061
|
-
document.getElementById('skillsActiveCount').textContent=formatNum(localHits.length);
|
|
5062
|
-
document.getElementById('skillsDraftCount').textContent='0';
|
|
5063
|
-
document.getElementById('skillsInstalledCount').textContent='-';
|
|
5064
|
-
document.getElementById('skillsPublicCount').textContent=formatNum(hubHits.filter(function(s){return s.visibility==='public';}).length);
|
|
5065
|
-
}catch(e){
|
|
5066
|
-
list.innerHTML='<div style="text-align:center;padding:24px;color:var(--rose)">'+t('skills.load.error')+': '+esc(String(e))+'</div>';
|
|
5067
|
-
if(hubList){
|
|
5068
|
-
hubList.innerHTML='<div style="text-align:center;padding:24px;color:var(--rose)">'+t('skills.load.error')+'</div>';
|
|
5069
|
-
}
|
|
5070
|
-
}
|
|
5071
|
-
}
|
|
5072
|
-
|
|
5073
|
-
async function loadHubSkills(hubList){
|
|
5074
|
-
if(!hubList) hubList=document.getElementById('hubSkillsList');
|
|
5075
|
-
if(!hubList) return;
|
|
5076
|
-
var hubSection=document.getElementById('hubSkillsSection');
|
|
5077
|
-
hubList.innerHTML='<div class="spinner"></div>';
|
|
5078
|
-
try{
|
|
5079
|
-
const r=await fetch('/api/sharing/skills/list?limit=40');
|
|
5080
|
-
const d=await r.json();
|
|
5081
|
-
const skills=Array.isArray(d.skills)?d.skills:[];
|
|
5082
|
-
hubSkillsCache=skills;
|
|
5083
|
-
if(!skills.length){
|
|
5084
|
-
if(hubSection) hubSection.style.display='none';
|
|
5085
|
-
return;
|
|
5086
|
-
}
|
|
5087
|
-
if(hubSection) hubSection.style.display='block';
|
|
5088
|
-
hubList.innerHTML=skills.map(function(skill,idx){
|
|
5089
|
-
return '<div class="hub-skill-card" onclick="openHubSkillDetailFromCache(\\\'hub\\\',' +idx+')" style="cursor:pointer">'+
|
|
5090
|
-
'<div class="summary">'+esc(skill.name)+'</div>'+
|
|
5091
|
-
'<div class="excerpt">'+esc(skill.description||'')+'</div>'+
|
|
5092
|
-
'<div class="hub-skill-meta">'+
|
|
5093
|
-
'<span class="meta-chip">owner: '+esc(skill.ownerName||'unknown')+'</span>'+
|
|
5094
|
-
(skill.groupName?'<span class="meta-chip">group: '+esc(skill.groupName)+'</span>':'')+
|
|
5095
|
-
'<span class="meta-chip">visibility: '+esc(skill.visibility||'hub')+'</span>'+
|
|
5096
|
-
(skill.version!=null?'<span class="meta-chip">v'+skill.version+'</span>':'')+
|
|
5097
2822
|
'</div>'+
|
|
5098
|
-
'<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>'+
|
|
5099
2834
|
'</div>';
|
|
5100
2835
|
}).join('');
|
|
5101
2836
|
}catch(e){
|
|
5102
|
-
|
|
5103
|
-
hubList.innerHTML='';
|
|
2837
|
+
list.innerHTML='<div style="text-align:center;padding:24px;color:var(--rose)">Failed to load skills: '+esc(String(e))+'</div>';
|
|
5104
2838
|
}
|
|
5105
2839
|
}
|
|
5106
2840
|
|
|
@@ -5109,7 +2843,6 @@ function parseTags(tagsStr){
|
|
|
5109
2843
|
}
|
|
5110
2844
|
|
|
5111
2845
|
let currentSkillId='';
|
|
5112
|
-
let currentSkillDetail=null;
|
|
5113
2846
|
|
|
5114
2847
|
async function openSkillDetail(skillId){
|
|
5115
2848
|
currentSkillId=skillId;
|
|
@@ -5122,8 +2855,6 @@ async function openSkillDetail(skillId){
|
|
|
5122
2855
|
document.getElementById('skillDetailContent').innerHTML='<div class="spinner"></div>';
|
|
5123
2856
|
document.getElementById('skillVersionsList').innerHTML='<div class="spinner"></div>';
|
|
5124
2857
|
document.getElementById('skillRelatedTasks').innerHTML='';
|
|
5125
|
-
var vb=document.getElementById('skillVisibilityBtn');if(vb)vb.style.display='';
|
|
5126
|
-
var db=document.getElementById('skillDownloadBtn');if(db)db.style.display='';
|
|
5127
2858
|
document.getElementById('skillDetailActions').innerHTML='';
|
|
5128
2859
|
|
|
5129
2860
|
try{
|
|
@@ -5169,8 +2900,6 @@ async function openSkillDetail(skillId){
|
|
|
5169
2900
|
}
|
|
5170
2901
|
|
|
5171
2902
|
document.getElementById('skillDetailDesc').textContent=skill.description;
|
|
5172
|
-
currentSkillDetail=skill;
|
|
5173
|
-
renderSkillShareActions(skill);
|
|
5174
2903
|
|
|
5175
2904
|
if(files.length>0){
|
|
5176
2905
|
const fileIcons={'skill':'\\u{1F4D6}','script':'\\u{2699}','reference':'\\u{1F4CE}','file':'\\u{1F4C4}'};
|
|
@@ -5378,9 +3107,6 @@ function timeAgo(ts){
|
|
|
5378
3107
|
}
|
|
5379
3108
|
|
|
5380
3109
|
/* ─── Settings / Config ─── */
|
|
5381
|
-
function syncHostToggles(){}
|
|
5382
|
-
function onProviderChange(){}
|
|
5383
|
-
|
|
5384
3110
|
async function loadConfig(){
|
|
5385
3111
|
try{
|
|
5386
3112
|
const r=await fetch('/api/config');
|
|
@@ -5415,26 +3141,6 @@ async function loadConfig(){
|
|
|
5415
3141
|
|
|
5416
3142
|
const tel=cfg.telemetry||{};
|
|
5417
3143
|
document.getElementById('cfgTelemetryEnabled').checked=tel.enabled!==false;
|
|
5418
|
-
|
|
5419
|
-
const sharing=cfg.sharing||{};
|
|
5420
|
-
const caps=sharing.capabilities||{};
|
|
5421
|
-
const embProv=(cfg.embedding||{}).provider;
|
|
5422
|
-
const sumProv=(cfg.summarizer||{}).provider;
|
|
5423
|
-
const skProv=((cfg.skillEvolution||{}).summarizer||{}).provider;
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
document.getElementById('cfgSharingEnabled').checked=!!sharing.enabled;
|
|
5427
|
-
_sharingRole=sharing.role||'client';
|
|
5428
|
-
var hub=sharing.hub||{};
|
|
5429
|
-
var client=sharing.client||{};
|
|
5430
|
-
document.getElementById('cfgHubPort').value=hub.port||18800;
|
|
5431
|
-
document.getElementById('cfgHubTeamName').value=hub.teamName||'';
|
|
5432
|
-
document.getElementById('cfgHubTeamToken').value=hub.teamToken||'';
|
|
5433
|
-
document.getElementById('cfgClientHubAddress').value=client.hubAddress||'';
|
|
5434
|
-
document.getElementById('cfgClientTeamToken').value=client.teamToken||'';
|
|
5435
|
-
document.getElementById('cfgClientUserToken').value=client.userToken||'';
|
|
5436
|
-
onSharingToggle();
|
|
5437
|
-
updateHubShareInfo();
|
|
5438
3144
|
}catch(e){
|
|
5439
3145
|
console.error('loadConfig error',e);
|
|
5440
3146
|
}
|
|
@@ -5467,36 +3173,9 @@ function onProviderChange(section){
|
|
|
5467
3173
|
if(m[2]==='chat'&&def.chatModel&&!mdEl.value.trim()) mdEl.value=def.chatModel;
|
|
5468
3174
|
}
|
|
5469
3175
|
|
|
5470
|
-
function
|
|
5471
|
-
var
|
|
5472
|
-
if(!el)return;
|
|
5473
|
-
el.classList.add('show');
|
|
5474
|
-
setTimeout(function(){el.classList.remove('show');},2500);
|
|
5475
|
-
}
|
|
5476
|
-
|
|
5477
|
-
async function doSaveConfig(cfg, btnEl, savedId){
|
|
5478
|
-
btnEl.disabled=true;btnEl.textContent=t('settings.test.loading');
|
|
5479
|
-
function done(){btnEl.disabled=false;btnEl.textContent=t('settings.save');}
|
|
5480
|
-
try{
|
|
5481
|
-
const r=await fetch('/api/config',{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(cfg)});
|
|
5482
|
-
if(r.status===401){done();toast(t('settings.session.expired'),'error');return false;}
|
|
5483
|
-
if(!r.ok) throw new Error(await r.text());
|
|
5484
|
-
flashSaved(savedId);
|
|
5485
|
-
toast(t('settings.saved'),'success');
|
|
5486
|
-
done();
|
|
5487
|
-
return true;
|
|
5488
|
-
}catch(e){
|
|
5489
|
-
toast(t('settings.save.fail')+': '+e.message,'error');
|
|
5490
|
-
done();
|
|
5491
|
-
return false;
|
|
5492
|
-
}
|
|
5493
|
-
}
|
|
5494
|
-
|
|
5495
|
-
async function saveModelsConfig(){
|
|
5496
|
-
var card=document.querySelector('.card-models');
|
|
5497
|
-
var saveBtn=card.querySelector('.settings-actions .btn-primary');
|
|
3176
|
+
async function saveConfig(){
|
|
3177
|
+
var saveBtn=document.querySelector('.settings-actions .btn-primary');
|
|
5498
3178
|
saveBtn.disabled=true;saveBtn.textContent=t('settings.test.loading');
|
|
5499
|
-
function done(){saveBtn.disabled=false;saveBtn.textContent=t('settings.save');}
|
|
5500
3179
|
|
|
5501
3180
|
const cfg={};
|
|
5502
3181
|
const embP=document.getElementById('cfgEmbProvider').value;
|
|
@@ -5537,8 +3216,16 @@ async function saveModelsConfig(){
|
|
|
5537
3216
|
if(skApiKey) cfg.skillEvolution.summarizer.apiKey=skApiKey;
|
|
5538
3217
|
}
|
|
5539
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
|
|
5540
3226
|
if(!embP||embP===''){done();toast(t('settings.save.emb.required'),'error');return;}
|
|
5541
3227
|
|
|
3228
|
+
// 2) Test embedding
|
|
5542
3229
|
try{
|
|
5543
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||''})});
|
|
5544
3231
|
if(er.status===401){done();toast(t('settings.session.expired'),'error');return;}
|
|
@@ -5547,6 +3234,7 @@ async function saveModelsConfig(){
|
|
|
5547
3234
|
document.getElementById('testEmbResult').className='test-result ok';document.getElementById('testEmbResult').innerHTML='\\u2705 '+t('settings.test.ok');
|
|
5548
3235
|
}catch(e){done();toast(t('settings.save.emb.fail')+': '+e.message,'error');return;}
|
|
5549
3236
|
|
|
3237
|
+
// 3) Test summarizer if user filled it
|
|
5550
3238
|
if(hasSumConfig&&cfg.summarizer){
|
|
5551
3239
|
try{
|
|
5552
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||''})});
|
|
@@ -5557,6 +3245,7 @@ async function saveModelsConfig(){
|
|
|
5557
3245
|
}catch(e){done();toast(t('settings.save.sum.fail')+': '+e.message,'error');return;}
|
|
5558
3246
|
}
|
|
5559
3247
|
|
|
3248
|
+
// 4) Test skill model if user filled it
|
|
5560
3249
|
if(hasSkillConfig&&cfg.skillEvolution.summarizer){
|
|
5561
3250
|
try{
|
|
5562
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||''})});
|
|
@@ -5567,6 +3256,7 @@ async function saveModelsConfig(){
|
|
|
5567
3256
|
}catch(e){done();toast(t('settings.save.skill.fail')+': '+e.message,'error');return;}
|
|
5568
3257
|
}
|
|
5569
3258
|
|
|
3259
|
+
// 5) If summarizer or skill model not configured, check OpenClaw fallback and confirm
|
|
5570
3260
|
if(!hasSumConfig||!hasSkillConfig){
|
|
5571
3261
|
try{
|
|
5572
3262
|
var fr=await fetch('/api/fallback-model');
|
|
@@ -5580,86 +3270,17 @@ async function saveModelsConfig(){
|
|
|
5580
3270
|
}catch(e){}
|
|
5581
3271
|
}
|
|
5582
3272
|
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
cfg.sharing={
|
|
5595
|
-
enabled:sharingEnabled,
|
|
5596
|
-
role:_sharingRole,
|
|
5597
|
-
capabilities:{}
|
|
5598
|
-
};
|
|
5599
|
-
if(sharingEnabled&&_sharingRole==='hub'){
|
|
5600
|
-
var hubPort=document.getElementById('cfgHubPort').value.trim();
|
|
5601
|
-
var hubTeamName=document.getElementById('cfgHubTeamName').value.trim();
|
|
5602
|
-
var hubTeamToken=document.getElementById('cfgHubTeamToken').value.trim();
|
|
5603
|
-
cfg.sharing.hub={port:hubPort?Number(hubPort):18800};
|
|
5604
|
-
if(hubTeamName) cfg.sharing.hub.teamName=hubTeamName;
|
|
5605
|
-
if(hubTeamToken) cfg.sharing.hub.teamToken=hubTeamToken;
|
|
5606
|
-
cfg.sharing.client={hubAddress:'',userToken:'',teamToken:''};
|
|
5607
|
-
}
|
|
5608
|
-
if(sharingEnabled&&_sharingRole==='client'){
|
|
5609
|
-
var clientAddr=document.getElementById('cfgClientHubAddress').value.trim();
|
|
5610
|
-
var clientTeamToken=document.getElementById('cfgClientTeamToken').value.trim();
|
|
5611
|
-
var clientUserToken=document.getElementById('cfgClientUserToken').value.trim();
|
|
5612
|
-
cfg.sharing.client={};
|
|
5613
|
-
if(clientAddr) cfg.sharing.client.hubAddress=clientAddr;
|
|
5614
|
-
if(clientTeamToken) cfg.sharing.client.teamToken=clientTeamToken;
|
|
5615
|
-
if(clientUserToken) cfg.sharing.client.userToken=clientUserToken;
|
|
5616
|
-
cfg.sharing.hub={port:18800,teamName:'',teamToken:''};
|
|
5617
|
-
if(clientAddr){
|
|
5618
|
-
try{
|
|
5619
|
-
var ips=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
5620
|
-
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ips.ips||[]);
|
|
5621
|
-
var parsed=new URL(clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr);
|
|
5622
|
-
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
5623
|
-
done();toast(t('sharing.cannotJoinSelf'),'error');return;
|
|
5624
|
-
}
|
|
5625
|
-
}catch(e){}
|
|
5626
|
-
}
|
|
5627
|
-
}
|
|
5628
|
-
|
|
5629
|
-
var prevSharingEnabled=sharingStatusCache&&sharingStatusCache.enabled;
|
|
5630
|
-
var prevRole=sharingStatusCache&&sharingStatusCache.role;
|
|
5631
|
-
if(prevSharingEnabled&&!sharingEnabled){
|
|
5632
|
-
var confirmMsg=prevRole==='hub'?t('sharing.disable.confirm.hub'):t('sharing.disable.confirm.client');
|
|
5633
|
-
if(!confirm(confirmMsg)){done();return;}
|
|
5634
|
-
}
|
|
5635
|
-
|
|
5636
|
-
var ok=await doSaveConfig(cfg, saveBtn, 'hubSaved');
|
|
5637
|
-
if(ok){
|
|
5638
|
-
loadSharingStatus(false);
|
|
5639
|
-
if(sharingEnabled){
|
|
5640
|
-
updateHubShareInfo();
|
|
5641
|
-
setTimeout(function(){alert(t('settings.hub.restartAlert'));},300);
|
|
5642
|
-
}
|
|
5643
|
-
if(prevSharingEnabled&&!sharingEnabled){
|
|
5644
|
-
setTimeout(function(){alert(t('sharing.disable.restartAlert'));},300);
|
|
5645
|
-
}
|
|
5646
|
-
}
|
|
5647
|
-
}
|
|
5648
|
-
|
|
5649
|
-
async function saveGeneralConfig(){
|
|
5650
|
-
var card=document.querySelector('.card-general');
|
|
5651
|
-
var saveBtn=card.querySelector('.settings-actions .btn-primary');
|
|
5652
|
-
|
|
5653
|
-
const cfg={};
|
|
5654
|
-
const vp=document.getElementById('cfgViewerPort').value.trim();
|
|
5655
|
-
if(vp) cfg.viewerPort=Number(vp);
|
|
5656
|
-
cfg.telemetry={enabled:document.getElementById('cfgTelemetryEnabled').checked};
|
|
5657
|
-
|
|
5658
|
-
await doSaveConfig(cfg, saveBtn, 'generalSaved');
|
|
5659
|
-
}
|
|
5660
|
-
|
|
5661
|
-
async function saveConfig(){
|
|
5662
|
-
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();}
|
|
5663
3284
|
}
|
|
5664
3285
|
|
|
5665
3286
|
async function testModel(type){
|
|
@@ -5760,7 +3381,7 @@ function formatDuration(ms){
|
|
|
5760
3381
|
|
|
5761
3382
|
function formatTime(ts){
|
|
5762
3383
|
if(!ts) return '-';
|
|
5763
|
-
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'});
|
|
5764
3385
|
}
|
|
5765
3386
|
|
|
5766
3387
|
function fillDays(rows,days){
|
|
@@ -5772,7 +3393,7 @@ function fillDays(rows,days){
|
|
|
5772
3393
|
const row=map.get(dateStr)||{};
|
|
5773
3394
|
out.push({date:dateStr,count:row.count??0,list:row.list??0,search:row.search??0,total:(row.list??0)+(row.search??0)});
|
|
5774
3395
|
}
|
|
5775
|
-
if(days>
|
|
3396
|
+
if(days>21){
|
|
5776
3397
|
const weeks=[];let i=0;
|
|
5777
3398
|
while(i<out.length){
|
|
5778
3399
|
const chunk=out.slice(i,i+7);
|
|
@@ -5790,23 +3411,19 @@ function fillDays(rows,days){
|
|
|
5790
3411
|
}
|
|
5791
3412
|
|
|
5792
3413
|
function renderBars(el,data,valueKey,H){
|
|
5793
|
-
|
|
5794
|
-
if(vals.every(
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
el.innerHTML=data.map(
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
var showLabel=(idx%labelStep===0)||(idx===n-1);
|
|
5802
|
-
var label=showLabel?rawDate:'';
|
|
5803
|
-
var tipDate=r.date.length>=10?r.date.slice(5,10):'';
|
|
5804
|
-
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);
|
|
5805
3422
|
if(v===0){
|
|
5806
|
-
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>';
|
|
5807
3424
|
}
|
|
5808
|
-
|
|
5809
|
-
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>';
|
|
5810
3427
|
}).join('');
|
|
5811
3428
|
}
|
|
5812
3429
|
|
|
@@ -5817,31 +3434,25 @@ function renderChartWrites(rows){
|
|
|
5817
3434
|
}
|
|
5818
3435
|
|
|
5819
3436
|
function renderChartCalls(rows){
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
if(vals.every(
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
el.innerHTML=filled.map(function(r,idx){
|
|
5829
|
-
var rawDate=r.date.includes('~')?r.date:(r.date.length>5?r.date.slice(5):'');
|
|
5830
|
-
var showLabel=(idx%labelStep===0)||(idx===n-1);
|
|
5831
|
-
var label=showLabel?rawDate:'';
|
|
5832
|
-
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);
|
|
5833
3445
|
if(r.total===0){
|
|
5834
|
-
|
|
5835
|
-
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>';
|
|
5836
3447
|
}
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
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='';
|
|
5842
3453
|
if(searchH>0) bars+='<div class="chart-bar violet" style="height:'+searchH+'px"></div>';
|
|
5843
3454
|
if(listH>0) bars+='<div class="chart-bar" style="height:'+listH+'px"></div>';
|
|
5844
|
-
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>';
|
|
5845
3456
|
}).join('');
|
|
5846
3457
|
}
|
|
5847
3458
|
|
|
@@ -6021,33 +3632,18 @@ function renderToolAgg(data){
|
|
|
6021
3632
|
'</tbody></table>';
|
|
6022
3633
|
}
|
|
6023
3634
|
|
|
6024
|
-
/* ─── Sharing status polling ─── */
|
|
6025
|
-
var _sharingPollTimer=null;
|
|
6026
|
-
function startSharingPoll(){
|
|
6027
|
-
stopSharingPoll();
|
|
6028
|
-
_sharingPollTimer=setInterval(function(){
|
|
6029
|
-
if(sharingStatusCache&&sharingStatusCache.enabled) loadSharingStatus(false);
|
|
6030
|
-
},30000);
|
|
6031
|
-
}
|
|
6032
|
-
function stopSharingPoll(){
|
|
6033
|
-
if(_sharingPollTimer){clearInterval(_sharingPollTimer);_sharingPollTimer=null;}
|
|
6034
|
-
}
|
|
6035
|
-
|
|
6036
3635
|
/* ─── Data loading ─── */
|
|
6037
3636
|
async function loadAll(){
|
|
6038
|
-
await Promise.all([loadStats(),loadMemories()
|
|
3637
|
+
await Promise.all([loadStats(),loadMemories()]);
|
|
6039
3638
|
checkMigrateStatus();
|
|
6040
3639
|
connectPPSSE();
|
|
6041
3640
|
checkForUpdate();
|
|
6042
|
-
startSharingPoll();
|
|
6043
3641
|
}
|
|
6044
3642
|
|
|
6045
|
-
async function loadStats(
|
|
3643
|
+
async function loadStats(){
|
|
6046
3644
|
let d;
|
|
6047
3645
|
try{
|
|
6048
|
-
|
|
6049
|
-
if(ownerFilter) statsUrl+='?owner='+encodeURIComponent(ownerFilter);
|
|
6050
|
-
const r=await fetch(statsUrl);
|
|
3646
|
+
const r=await fetch('/api/stats');
|
|
6051
3647
|
d=await r.json();
|
|
6052
3648
|
}catch(e){ d={}; }
|
|
6053
3649
|
if(!d||typeof d!=='object') d={};
|
|
@@ -6103,17 +3699,6 @@ async function loadStats(ownerFilter){
|
|
|
6103
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>';
|
|
6104
3700
|
});
|
|
6105
3701
|
|
|
6106
|
-
const fSel=document.getElementById('filterSession');
|
|
6107
|
-
if(fSel){
|
|
6108
|
-
const curVal=activeSession||'';
|
|
6109
|
-
var sessionCount=(d.sessions||[]).length;
|
|
6110
|
-
fSel.innerHTML='<option value="">'+t('filter.allsessions')+' ('+sessionCount+')</option>';
|
|
6111
|
-
(d.sessions||[]).forEach(s=>{
|
|
6112
|
-
const sName=s.session_key.length>30?s.session_key.slice(0,12)+'...'+s.session_key.slice(-10):s.session_key;
|
|
6113
|
-
fSel.innerHTML+='<option value="'+s.session_key.replace(/"/g,'"')+'"'+(s.session_key===curVal?' selected':'')+'>'+sName+' ('+s.count+')</option>';
|
|
6114
|
-
});
|
|
6115
|
-
}
|
|
6116
|
-
|
|
6117
3702
|
const ownerSel=document.getElementById('filterOwner');
|
|
6118
3703
|
if(ownerSel && d.owners && d.owners.length>0){
|
|
6119
3704
|
const curVal=ownerSel.value;
|
|
@@ -6125,32 +3710,6 @@ async function loadStats(ownerFilter){
|
|
|
6125
3710
|
}
|
|
6126
3711
|
}
|
|
6127
3712
|
|
|
6128
|
-
function onOwnerFilterChange(){
|
|
6129
|
-
var owner=document.getElementById('filterOwner').value;
|
|
6130
|
-
activeSession=null;
|
|
6131
|
-
currentPage=1;
|
|
6132
|
-
refreshSessionDropdown(owner);
|
|
6133
|
-
applyFilters();
|
|
6134
|
-
}
|
|
6135
|
-
|
|
6136
|
-
async function refreshSessionDropdown(ownerFilter){
|
|
6137
|
-
try{
|
|
6138
|
-
var statsUrl='/api/stats';
|
|
6139
|
-
if(ownerFilter) statsUrl+='?owner='+encodeURIComponent(ownerFilter);
|
|
6140
|
-
var r=await fetch(statsUrl);
|
|
6141
|
-
var d=await r.json();
|
|
6142
|
-
var sessions=d.sessions||[];
|
|
6143
|
-
var fSel=document.getElementById('filterSession');
|
|
6144
|
-
if(fSel){
|
|
6145
|
-
fSel.innerHTML='<option value="">'+t('filter.allsessions')+' ('+sessions.length+')</option>';
|
|
6146
|
-
sessions.forEach(function(s){
|
|
6147
|
-
var sName=s.session_key.length>30?s.session_key.slice(0,12)+'...'+s.session_key.slice(-10):s.session_key;
|
|
6148
|
-
fSel.innerHTML+='<option value="'+s.session_key.replace(/"/g,'"')+'">'+sName+' ('+s.count+')</option>';
|
|
6149
|
-
});
|
|
6150
|
-
}
|
|
6151
|
-
}catch(e){}
|
|
6152
|
-
}
|
|
6153
|
-
|
|
6154
3713
|
function getFilterParams(){
|
|
6155
3714
|
const p=new URLSearchParams();
|
|
6156
3715
|
if(activeSession) p.set('session',activeSession);
|
|
@@ -6189,16 +3748,22 @@ async function loadMemories(page){
|
|
|
6189
3748
|
}
|
|
6190
3749
|
}
|
|
6191
3750
|
|
|
6192
|
-
async function
|
|
3751
|
+
async function doSearch(q){
|
|
3752
|
+
if(!q.trim()){currentPage=1;loadMemories();return}
|
|
6193
3753
|
const list=document.getElementById('memoryList');
|
|
6194
3754
|
list.innerHTML='<div class="spinner"></div>';
|
|
6195
3755
|
try{
|
|
6196
|
-
const
|
|
3756
|
+
const p=getFilterParams();
|
|
3757
|
+
p.set('q',q);
|
|
3758
|
+
const r=await fetch('/api/search?'+p.toString());
|
|
6197
3759
|
const d=await r.json();
|
|
6198
|
-
const
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
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||[]);
|
|
6202
3767
|
document.getElementById('pagination').innerHTML='';
|
|
6203
3768
|
}catch(e){
|
|
6204
3769
|
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
@@ -6207,51 +3772,6 @@ async function loadHubMemories(){
|
|
|
6207
3772
|
}
|
|
6208
3773
|
}
|
|
6209
3774
|
|
|
6210
|
-
async function doSearch(query){
|
|
6211
|
-
query=(query||'').trim();
|
|
6212
|
-
if(!query){loadMemories();return;}
|
|
6213
|
-
var scope=document.getElementById('memorySearchScope')?.value||memorySearchScope||'local';
|
|
6214
|
-
var list=document.getElementById('memoryList');
|
|
6215
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
6216
|
-
if(scope!=='local'){
|
|
6217
|
-
try{
|
|
6218
|
-
var r=await fetch('/api/sharing/search/memories',{
|
|
6219
|
-
method:'POST',
|
|
6220
|
-
headers:{'Content-Type':'application/json'},
|
|
6221
|
-
body:JSON.stringify({query:query,scope:scope,maxResults:20,role:activeRole||undefined})
|
|
6222
|
-
});
|
|
6223
|
-
var data=await r.json();
|
|
6224
|
-
renderSharingMemorySearchResults(data,query);
|
|
6225
|
-
}catch(e){
|
|
6226
|
-
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
6227
|
-
document.getElementById('sharingSearchMeta').textContent='';
|
|
6228
|
-
renderMemories([]);
|
|
6229
|
-
document.getElementById('pagination').innerHTML='';
|
|
6230
|
-
}
|
|
6231
|
-
} else {
|
|
6232
|
-
try{
|
|
6233
|
-
var p=getFilterParams();
|
|
6234
|
-
p.set('q',query);
|
|
6235
|
-
var r=await fetch('/api/search?'+p.toString());
|
|
6236
|
-
var d=await r.json();
|
|
6237
|
-
var total=d.total||0;
|
|
6238
|
-
var meta=[];
|
|
6239
|
-
if(d.vectorCount>0) meta.push(d.vectorCount+t('search.meta.semantic'));
|
|
6240
|
-
if(d.ftsCount>0) meta.push(d.ftsCount+t('search.meta.text'));
|
|
6241
|
-
meta.push(total+t('search.meta.results'));
|
|
6242
|
-
document.getElementById('searchMeta').textContent=meta.join(' \u00B7 ');
|
|
6243
|
-
document.getElementById('sharingSearchMeta').textContent='';
|
|
6244
|
-
renderMemories(d.results||[]);
|
|
6245
|
-
document.getElementById('pagination').innerHTML='';
|
|
6246
|
-
}catch(e){
|
|
6247
|
-
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
6248
|
-
document.getElementById('sharingSearchMeta').textContent='';
|
|
6249
|
-
renderMemories([]);
|
|
6250
|
-
document.getElementById('pagination').innerHTML='';
|
|
6251
|
-
}
|
|
6252
|
-
}
|
|
6253
|
-
}
|
|
6254
|
-
|
|
6255
3775
|
function debounceSearch(){
|
|
6256
3776
|
clearTimeout(searchTimer);
|
|
6257
3777
|
searchTimer=setTimeout(()=>doSearch(document.getElementById('searchInput').value),350);
|
|
@@ -6260,12 +3780,6 @@ function debounceSearch(){
|
|
|
6260
3780
|
function filterSession(key){
|
|
6261
3781
|
activeSession=key;
|
|
6262
3782
|
currentPage=1;
|
|
6263
|
-
var fSel=document.getElementById('filterSession');
|
|
6264
|
-
if(fSel) fSel.value=key||'';
|
|
6265
|
-
document.querySelectorAll('#sessionList .session-item').forEach(function(el,i){
|
|
6266
|
-
if(i===0) el.classList.toggle('active',!key);
|
|
6267
|
-
else el.classList.toggle('active',el.querySelector('span')?.title===key);
|
|
6268
|
-
});
|
|
6269
3783
|
loadAll();
|
|
6270
3784
|
}
|
|
6271
3785
|
|
|
@@ -6301,7 +3815,7 @@ function renderMemories(items){
|
|
|
6301
3815
|
}
|
|
6302
3816
|
items.forEach(m=>{memoryCache[m.id]=m});
|
|
6303
3817
|
list.innerHTML=items.map(m=>{
|
|
6304
|
-
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'):'';
|
|
6305
3819
|
const role=m.role||'user';
|
|
6306
3820
|
const rawSummary=m.summary||'';
|
|
6307
3821
|
const rawContent=m.content||'';
|
|
@@ -6313,7 +3827,7 @@ function renderMemories(items){
|
|
|
6313
3827
|
const mc=m.merge_count||0;
|
|
6314
3828
|
const cardTitle=esc(rawSummary||rawContent||'');
|
|
6315
3829
|
const mergeBadge=mc>0?'<span class="merge-badge">\\u{1F504} '+t('card.evolved')+' '+mc+t('card.times')+'</span>':'';
|
|
6316
|
-
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>':'';
|
|
6317
3831
|
const ds=m.dedup_status||'active';
|
|
6318
3832
|
const isInactive=ds==='merged';
|
|
6319
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>':'';
|
|
@@ -6322,8 +3836,6 @@ function renderMemories(items){
|
|
|
6322
3836
|
const ownerVal=m.owner||'agent:main';
|
|
6323
3837
|
const isPublicMem=ownerVal==='public';
|
|
6324
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>';
|
|
6325
|
-
const memShared=m.sharingVisibility||null;
|
|
6326
|
-
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>':'';
|
|
6327
3839
|
let dedupInfo='';
|
|
6328
3840
|
if(ds==='duplicate'||ds==='merged'){
|
|
6329
3841
|
const reason=m.dedup_reason?'<span style="font-size:11px;color:var(--text-muted)">'+t('card.dedupReason')+esc(m.dedup_reason)+'</span>':'';
|
|
@@ -6337,7 +3849,7 @@ function renderMemories(items){
|
|
|
6337
3849
|
if(hist.length>0){
|
|
6338
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>';
|
|
6339
3851
|
hist.forEach(function(h){
|
|
6340
|
-
const ht=h.at?new Date(h.at).toLocaleString(
|
|
3852
|
+
const ht=h.at?new Date(h.at).toLocaleString('zh-CN'):'';
|
|
6341
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||'');
|
|
6342
3854
|
if(h.from) historyHtml+='<br><span style="opacity:.6">'+t('card.oldSummary')+':</span> '+esc(h.from);
|
|
6343
3855
|
if(h.to) historyHtml+='<br><span style="opacity:.6">'+t('card.newSummary')+':</span> '+esc(h.to);
|
|
@@ -6373,7 +3885,6 @@ function renderMemories(items){
|
|
|
6373
3885
|
(mc>0?'<button class="btn btn-sm btn-ghost" onclick="toggleHistory(\\''+id+'\\')">'+t('card.evolveHistory')+'</button>':'')+
|
|
6374
3886
|
'<button class="btn btn-sm btn-ghost" onclick="openEditModal(\\''+id+'\\')">'+t('card.edit')+'</button>'+
|
|
6375
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>')+
|
|
6376
|
-
(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>')+
|
|
6377
3888
|
'<button class="btn btn-sm btn-ghost" style="color:var(--accent)" onclick="deleteMemory(\\''+id+'\\')">'+t('card.delete')+'</button>'+
|
|
6378
3889
|
vscore+
|
|
6379
3890
|
'</div></div>';
|
|
@@ -6432,50 +3943,38 @@ function scrollToMemory(targetId){
|
|
|
6432
3943
|
}
|
|
6433
3944
|
showMemoryModal(targetId);
|
|
6434
3945
|
}
|
|
6435
|
-
function fmtModalDate(v){
|
|
6436
|
-
if(!v) return '-';
|
|
6437
|
-
var d=new Date(v);
|
|
6438
|
-
if(isNaN(d.getTime())) return '-';
|
|
6439
|
-
return d.toLocaleString(dateLoc());
|
|
6440
|
-
}
|
|
6441
3946
|
async function showMemoryModal(chunkId){
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
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>';
|
|
6445
3950
|
overlay.classList.add('show');
|
|
6446
3951
|
try{
|
|
6447
|
-
|
|
6448
|
-
if(!res.ok){body.innerHTML='<div style="text-align:center;padding:
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
if(
|
|
6467
|
-
|
|
6468
|
-
if(m.
|
|
6469
|
-
if(m.
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
}
|
|
6474
|
-
if(m.dedup_target&&m.dedup_target!==chunkId){
|
|
6475
|
-
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>';
|
|
6476
|
-
}
|
|
6477
|
-
body.innerHTML=h;
|
|
6478
|
-
}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>';}
|
|
6479
3978
|
}
|
|
6480
3979
|
function closeMemoryModal(){document.getElementById('memoryModal').classList.remove('show');}
|
|
6481
3980
|
|
|
@@ -7193,12 +4692,10 @@ initViewerTheme();
|
|
|
7193
4692
|
/* ─── Update check ─── */
|
|
7194
4693
|
function waitForGatewayAndReload(maxAttempts,attempt){
|
|
7195
4694
|
attempt=attempt||0;
|
|
7196
|
-
|
|
7197
|
-
if(attempt>=maxAttempts){forceReload();return;}
|
|
4695
|
+
if(attempt>=maxAttempts){window.location.reload();return;}
|
|
7198
4696
|
setTimeout(function(){
|
|
7199
|
-
fetch('/api/auth/status').then(function(
|
|
7200
|
-
|
|
7201
|
-
else waitForGatewayAndReload(maxAttempts,attempt+1);
|
|
4697
|
+
fetch('/api/auth/status').then(function(){
|
|
4698
|
+
window.location.reload();
|
|
7202
4699
|
}).catch(function(){waitForGatewayAndReload(maxAttempts,attempt+1);});
|
|
7203
4700
|
},3000);
|
|
7204
4701
|
}
|
|
@@ -7210,7 +4707,7 @@ function doUpdateInstall(packageSpec,btnEl,statusEl){
|
|
|
7210
4707
|
.then(function(r){return r.json()})
|
|
7211
4708
|
.then(function(d){
|
|
7212
4709
|
if(d.ok){
|
|
7213
|
-
btnEl.textContent=t('update.success')
|
|
4710
|
+
btnEl.textContent=t('update.success');
|
|
7214
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';
|
|
7215
4712
|
if(statusEl)statusEl.textContent=t('update.restarting');
|
|
7216
4713
|
waitForGatewayAndReload(40);
|
|
@@ -7275,8 +4772,8 @@ checkAuth();
|
|
|
7275
4772
|
<div class="memory-modal-overlay" id="memoryModal" onclick="if(event.target===this)closeMemoryModal()">
|
|
7276
4773
|
<div class="memory-modal">
|
|
7277
4774
|
<div class="memory-modal-title">
|
|
7278
|
-
<
|
|
7279
|
-
<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>
|
|
7280
4777
|
</div>
|
|
7281
4778
|
<div class="memory-modal-body" id="memoryModalBody"></div>
|
|
7282
4779
|
</div>
|