@memtensor/memos-local-openclaw-plugin 0.1.9 → 0.2.0
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/.env.example +6 -0
- package/README.md +90 -25
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/embedding/local.d.ts.map +1 -1
- package/dist/embedding/local.js +3 -2
- package/dist/embedding/local.js.map +1 -1
- package/dist/skill/evaluator.js +1 -1
- package/dist/skill/evaluator.js.map +1 -1
- package/dist/skill/generator.js +1 -1
- 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/sqlite.d.ts +4 -0
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +19 -0
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/telemetry.d.ts +37 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +179 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +6 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/viewer/html.d.ts +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +828 -52
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +25 -1
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +807 -0
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +31 -3
- package/openclaw.plugin.json +3 -3
- package/package.json +4 -3
- package/src/config.ts +11 -0
- package/src/embedding/local.ts +3 -2
- package/src/skill/evaluator.ts +1 -1
- package/src/skill/generator.ts +1 -1
- package/src/skill/upgrader.ts +1 -1
- package/src/skill/validator.ts +1 -1
- package/src/storage/sqlite.ts +29 -0
- package/src/telemetry.ts +160 -0
- package/src/types.ts +7 -1
- package/src/viewer/html.ts +828 -52
- package/src/viewer/server.ts +818 -1
package/src/viewer/html.ts
CHANGED
|
@@ -178,6 +178,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
178
178
|
.dedup-badge{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:600;padding:3px 10px;border-radius:8px}
|
|
179
179
|
.dedup-badge.duplicate{background:rgba(245,158,11,.12);color:#f59e0b}
|
|
180
180
|
.dedup-badge.merged{background:rgba(59,130,246,.12);color:#60a5fa}
|
|
181
|
+
.import-badge{display:inline-flex;align-items:center;gap:4px;background:rgba(236,72,153,.1);color:#ec4899;font-size:10px;font-weight:600;padding:3px 10px;border-radius:8px}
|
|
182
|
+
[data-theme="light"] .import-badge{background:rgba(219,39,119,.08);color:#db2777}
|
|
181
183
|
.memory-card.dedup-inactive{opacity:.55;border-style:dashed}
|
|
182
184
|
.memory-card.dedup-inactive:hover{opacity:.85}
|
|
183
185
|
.dedup-target-link{font-size:11px;color:var(--pri);cursor:pointer;text-decoration:underline;margin-left:4px}
|
|
@@ -403,8 +405,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
403
405
|
.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)}
|
|
404
406
|
[data-theme="light"] .nav-tabs{background:rgba(0,0,0,.05)}
|
|
405
407
|
[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)}
|
|
406
|
-
.analytics-view,.settings-view,.logs-view{display:none;flex:1;min-width:0;flex-direction:column;gap:20px}
|
|
407
|
-
.analytics-view.show,.settings-view.show,.logs-view.show{display:flex}
|
|
408
|
+
.analytics-view,.settings-view,.logs-view,.migrate-view{display:none;flex:1;min-width:0;flex-direction:column;gap:20px}
|
|
409
|
+
.analytics-view.show,.settings-view.show,.logs-view.show,.migrate-view.show{display:flex}
|
|
408
410
|
|
|
409
411
|
/* ─── Logs ─── */
|
|
410
412
|
.logs-toolbar{display:flex;align-items:center;justify-content:space-between;padding:8px 0}
|
|
@@ -500,6 +502,24 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
500
502
|
[data-theme="light"] .settings-actions .btn-primary:hover{background:rgba(79,70,229,.1);border-color:#4f46e5}
|
|
501
503
|
.settings-saved{display:inline-flex;align-items:center;gap:6px;color:var(--green);font-size:12px;font-weight:600;opacity:0;transition:opacity .3s}
|
|
502
504
|
.settings-saved.show{opacity:1}
|
|
505
|
+
.migrate-log-item{display:flex;align-items:flex-start;gap:10px;padding:8px 14px;border-bottom:1px solid var(--border);animation:migrateFadeIn .3s ease}
|
|
506
|
+
.migrate-log-item:last-child{border-bottom:none}
|
|
507
|
+
.migrate-log-item .log-icon{flex-shrink:0;width:18px;height:18px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;margin-top:2px}
|
|
508
|
+
.migrate-log-item .log-icon.stored{background:rgba(34,197,94,.12);color:#22c55e}
|
|
509
|
+
.migrate-log-item .log-icon.skipped{background:rgba(245,158,11,.12);color:#f59e0b}
|
|
510
|
+
.migrate-log-item .log-icon.merged{background:rgba(59,130,246,.12);color:#3b82f6}
|
|
511
|
+
.migrate-log-item .log-icon.error{background:rgba(239,68,68,.12);color:#ef4444}
|
|
512
|
+
.migrate-log-item .log-icon.duplicate{background:rgba(245,158,11,.12);color:#f59e0b}
|
|
513
|
+
.migrate-log-item .log-body{flex:1;min-width:0}
|
|
514
|
+
.migrate-log-item .log-preview{color:var(--text);font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
|
|
515
|
+
.migrate-log-item .log-meta{display:flex;gap:8px;font-size:9px;color:var(--text-muted);margin-top:2px}
|
|
516
|
+
.migrate-log-item .log-meta .tag{padding:1px 6px;border-radius:4px;font-weight:600;letter-spacing:.02em}
|
|
517
|
+
.migrate-log-item .log-meta .tag.stored{background:rgba(34,197,94,.1);color:#22c55e}
|
|
518
|
+
.migrate-log-item .log-meta .tag.skipped{background:rgba(245,158,11,.1);color:#f59e0b}
|
|
519
|
+
.migrate-log-item .log-meta .tag.merged{background:rgba(59,130,246,.1);color:#3b82f6}
|
|
520
|
+
.migrate-log-item .log-meta .tag.error{background:rgba(239,68,68,.1);color:#ef4444}
|
|
521
|
+
.migrate-log-item .log-meta .tag.duplicate{background:rgba(245,158,11,.1);color:#f59e0b}
|
|
522
|
+
@keyframes migrateFadeIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
|
|
503
523
|
.feed-wrap{flex:1;min-width:0;display:flex;flex-direction:column}
|
|
504
524
|
.feed-wrap.hide{display:none}
|
|
505
525
|
.analytics-cards{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
|
|
@@ -682,6 +702,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
682
702
|
<button class="tab" data-view="skills" onclick="switchView('skills')" data-i18n="tab.skills">\u{1F9E0} Skills</button>
|
|
683
703
|
<button class="tab" data-view="analytics" onclick="switchView('analytics')" data-i18n="tab.analytics">\u{1F4CA} Analytics</button>
|
|
684
704
|
<button class="tab" data-view="logs" onclick="switchView('logs')" data-i18n="tab.logs">\u{1F4DD} Logs</button>
|
|
705
|
+
<button class="tab" data-view="import" onclick="switchView('import')" data-i18n="tab.import">\u{1F4E5} Import</button>
|
|
685
706
|
<button class="tab" data-view="settings" onclick="switchView('settings')" data-i18n="tab.settings">\u2699 Settings</button>
|
|
686
707
|
</nav>
|
|
687
708
|
</div>
|
|
@@ -962,38 +983,17 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
962
983
|
<input type="number" id="cfgSkillMinChunks" placeholder="6">
|
|
963
984
|
</div>
|
|
964
985
|
</div>
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
<option value="gemini">Gemini</option>
|
|
977
|
-
<option value="azure_openai">Azure OpenAI</option>
|
|
978
|
-
<option value="bedrock">Bedrock</option>
|
|
979
|
-
</select>
|
|
980
|
-
</div>
|
|
981
|
-
<div class="settings-field">
|
|
982
|
-
<label data-i18n="settings.model">Model</label>
|
|
983
|
-
<input type="text" id="cfgSkillModel" placeholder="e.g. claude-4.6-opus">
|
|
984
|
-
</div>
|
|
985
|
-
<div class="settings-field full-width">
|
|
986
|
-
<label>Endpoint</label>
|
|
987
|
-
<input type="text" id="cfgSkillEndpoint" placeholder="https://...">
|
|
988
|
-
</div>
|
|
989
|
-
<div class="settings-field">
|
|
990
|
-
<label>API Key</label>
|
|
991
|
-
<input type="password" id="cfgSkillApiKey" placeholder="\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022">
|
|
992
|
-
</div>
|
|
993
|
-
<div class="settings-field">
|
|
994
|
-
<label data-i18n="settings.temperature">Temperature</label>
|
|
995
|
-
<input type="number" id="cfgSkillTemp" step="0.1" min="0" max="2" placeholder="0.2">
|
|
996
|
-
</div>
|
|
986
|
+
</div>
|
|
987
|
+
|
|
988
|
+
<div class="settings-section">
|
|
989
|
+
<h3><span class="icon">\u{1F4CA}</span> <span data-i18n="settings.telemetry">Telemetry</span></h3>
|
|
990
|
+
<div class="settings-grid">
|
|
991
|
+
<div class="settings-toggle">
|
|
992
|
+
<label class="toggle-switch"><input type="checkbox" id="cfgTelemetryEnabled" checked><span class="toggle-slider"></span></label>
|
|
993
|
+
<label data-i18n="settings.telemetry.enabled">Enable Anonymous Telemetry</label>
|
|
994
|
+
</div>
|
|
995
|
+
<div class="settings-field full-width">
|
|
996
|
+
<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>
|
|
997
997
|
</div>
|
|
998
998
|
</div>
|
|
999
999
|
</div>
|
|
@@ -1017,6 +1017,160 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1017
1017
|
<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>
|
|
1018
1018
|
</div>
|
|
1019
1019
|
|
|
1020
|
+
<!-- ─── Import Page ─── -->
|
|
1021
|
+
<div class="migrate-view" id="migrateView">
|
|
1022
|
+
<div class="settings-section" style="border:1px solid rgba(99,102,241,.15)">
|
|
1023
|
+
<h3><span class="icon">\u{1F4E5}</span> <span data-i18n="migrate.title">Import OpenClaw Memory</span></h3>
|
|
1024
|
+
<p style="font-size:12px;color:var(--text-sec);margin-bottom:12px;line-height:1.6" data-i18n="migrate.desc">Migrate your existing OpenClaw built-in memories and conversation history into this plugin. The import process uses smart deduplication to avoid duplicates.</p>
|
|
1025
|
+
|
|
1026
|
+
<div style="background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:14px 18px;margin-bottom:16px;font-size:12px;line-height:1.7;color:var(--text-sec)">
|
|
1027
|
+
<div style="font-weight:700;color:var(--text);margin-bottom:8px" data-i18n="migrate.modes.title">Three ways to use:</div>
|
|
1028
|
+
<div style="display:flex;flex-direction:column;gap:6px">
|
|
1029
|
+
<div><span style="font-weight:600;color:var(--accent)" data-i18n="migrate.mode1.label">\u2460 Import memories only (fast)</span><span data-i18n="migrate.mode1.desc"> — Click "Start Import" to quickly migrate all memory chunks and conversations. No task/skill generation. Suitable when you just need the raw data.</span></div>
|
|
1030
|
+
<div><span style="font-weight:600;color:var(--accent)" data-i18n="migrate.mode2.label">\u2461 Import + generate tasks & skills (slow, serial)</span><span data-i18n="migrate.mode2.desc"> — After importing memories, enable "Generate Tasks" and/or "Trigger Skill Evolution" below to analyze conversations one by one. This takes longer as each session is processed by LLM sequentially.</span></div>
|
|
1031
|
+
<div><span style="font-weight:600;color:var(--accent)" data-i18n="migrate.mode3.label">\u2462 Import first, generate later (flexible)</span><span data-i18n="migrate.mode3.desc"> — Import memories now, then come back anytime to start task/skill generation. You can pause the generation at any point and resume later — it will pick up where you left off, only processing sessions that haven't been handled yet.</span></div>
|
|
1032
|
+
</div>
|
|
1033
|
+
</div>
|
|
1034
|
+
|
|
1035
|
+
<div id="migrateConfigWarn" style="display:none;background:rgba(245,158,11,.08);border:1px solid rgba(245,158,11,.3);border-radius:10px;padding:14px 18px;margin-bottom:16px">
|
|
1036
|
+
<div style="font-size:12px;font-weight:600;color:#f59e0b;margin-bottom:6px">\u26A0 <span data-i18n="migrate.config.warn">Configuration Required</span></div>
|
|
1037
|
+
<div style="font-size:11px;color:var(--text-sec);line-height:1.5" data-i18n="migrate.config.warn.desc">Please configure both Embedding Model and Summarizer Model in Settings before importing. These are required for processing memories.</div>
|
|
1038
|
+
</div>
|
|
1039
|
+
|
|
1040
|
+
<div id="migrateScanResult" style="display:none;margin-bottom:16px">
|
|
1041
|
+
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px">
|
|
1042
|
+
<div style="background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:14px 18px">
|
|
1043
|
+
<div style="font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:6px" data-i18n="migrate.sqlite.label">Memory Index (SQLite)</div>
|
|
1044
|
+
<div style="font-size:22px;font-weight:700;color:var(--text)" id="migrateSqliteCount">0</div>
|
|
1045
|
+
<div style="font-size:10px;color:var(--text-muted);margin-top:2px" id="migrateSqliteFiles"></div>
|
|
1046
|
+
</div>
|
|
1047
|
+
<div style="background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:14px 18px">
|
|
1048
|
+
<div style="font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-bottom:6px" data-i18n="migrate.sessions.label">Conversation History</div>
|
|
1049
|
+
<div style="font-size:22px;font-weight:700;color:var(--text)" id="migrateSessionCount">0</div>
|
|
1050
|
+
<div style="font-size:10px;color:var(--text-muted);margin-top:2px" id="migrateSessionFiles"></div>
|
|
1051
|
+
</div>
|
|
1052
|
+
</div>
|
|
1053
|
+
</div>
|
|
1054
|
+
|
|
1055
|
+
<div id="migrateActions" style="display:flex;gap:12px;align-items:center;flex-wrap:wrap">
|
|
1056
|
+
<button class="btn btn-ghost" onclick="migrateScan()" id="migrateScanBtn" data-i18n="migrate.scan">Scan Data Sources</button>
|
|
1057
|
+
<button class="btn btn-primary" onclick="migrateStart()" id="migrateStartBtn" style="display:none" data-i18n="migrate.start">Start Import</button>
|
|
1058
|
+
<span id="migrateStatus" style="font-size:11px;color:var(--text-muted)"></span>
|
|
1059
|
+
</div>
|
|
1060
|
+
|
|
1061
|
+
<!-- Post-process section: shown after import completes -->
|
|
1062
|
+
<div id="postprocessSection" style="display:none;margin-top:16px">
|
|
1063
|
+
<div class="settings-section" style="border:1px solid var(--border)">
|
|
1064
|
+
<div style="font-size:14px;font-weight:700;color:var(--text);margin-bottom:6px" data-i18n="pp.title">\u{1F9E0} Optional: Generate Tasks & Skills</div>
|
|
1065
|
+
<div style="font-size:12px;color:var(--text-sec);margin-bottom:14px;line-height:1.6" data-i18n="pp.desc">This step is completely optional. The import above has already stored raw memory data. Here you can further analyze imported conversations to generate structured task summaries and evolve reusable skills. Processing is serial (one session at a time) and may take a while. You can stop at any time and resume later — it will only process sessions not yet handled.</div>
|
|
1066
|
+
<div style="display:flex;flex-direction:column;gap:8px;margin-bottom:14px">
|
|
1067
|
+
<label style="display:flex;align-items:flex-start;gap:8px;cursor:pointer">
|
|
1068
|
+
<input type="checkbox" id="ppEnableTasks" checked style="accent-color:var(--accent);margin-top:2px">
|
|
1069
|
+
<div>
|
|
1070
|
+
<div style="font-size:12px;font-weight:600;color:var(--text)" data-i18n="pp.tasks.label">Generate task summaries</div>
|
|
1071
|
+
<div style="font-size:11px;color:var(--text-sec);line-height:1.4" data-i18n="pp.tasks.hint">Group imported messages into tasks and generate a structured summary (title, goal, steps, result) for each one. Makes it easier to search and recall past work.</div>
|
|
1072
|
+
</div>
|
|
1073
|
+
</label>
|
|
1074
|
+
<label style="display:flex;align-items:flex-start;gap:8px;cursor:pointer">
|
|
1075
|
+
<input type="checkbox" id="ppEnableSkills" style="accent-color:var(--accent);margin-top:2px">
|
|
1076
|
+
<div>
|
|
1077
|
+
<div style="font-size:12px;font-weight:600;color:var(--text)" data-i18n="pp.skills.label">Trigger skill evolution</div>
|
|
1078
|
+
<div style="font-size:11px;color:var(--text-sec);line-height:1.4" data-i18n="pp.skills.hint">Analyze completed tasks and automatically create or upgrade reusable skills (SKILL.md). Requires task summaries to be enabled. May take longer due to LLM evaluation.</div>
|
|
1079
|
+
</div>
|
|
1080
|
+
</label>
|
|
1081
|
+
</div>
|
|
1082
|
+
<div style="display:flex;gap:10px;align-items:center">
|
|
1083
|
+
<button class="btn btn-primary" id="ppStartBtn" onclick="ppStart()" data-i18n="pp.start">Start Processing</button>
|
|
1084
|
+
<button class="btn btn-sm" id="ppStopBtn" onclick="ppStop()" style="display:none;background:rgba(239,68,68,.12);color:#ef4444;border:1px solid rgba(239,68,68,.3);font-size:12px;padding:5px 16px;font-weight:600" data-i18n="migrate.stop">\u25A0 Stop</button>
|
|
1085
|
+
<span id="ppStatus" style="font-size:11px;color:var(--text-muted)"></span>
|
|
1086
|
+
</div>
|
|
1087
|
+
<div id="ppProgress" style="display:none;margin-top:12px">
|
|
1088
|
+
<div style="display:flex;align-items:center;gap:12px;margin-bottom:8px">
|
|
1089
|
+
<div style="font-size:12px;font-weight:600;color:var(--text)" id="ppPhaseLabel"></div>
|
|
1090
|
+
<div style="font-size:11px;color:var(--text-muted);flex:1" id="ppCounter"></div>
|
|
1091
|
+
</div>
|
|
1092
|
+
<div style="position:relative;height:5px;background:var(--bg);border-radius:3px;overflow:hidden;margin-bottom:12px">
|
|
1093
|
+
<div id="ppBar" style="position:absolute;left:0;top:0;height:100%;width:0%;background:linear-gradient(90deg,#f59e0b,#fbbf24);border-radius:3px;transition:width .3s ease"></div>
|
|
1094
|
+
</div>
|
|
1095
|
+
<div style="display:flex;gap:16px;margin-bottom:12px" id="ppStatsRow">
|
|
1096
|
+
<div style="display:flex;align-items:center;gap:5px;font-size:11px">
|
|
1097
|
+
<span style="width:7px;height:7px;border-radius:50%;background:#22c55e;display:inline-block"></span>
|
|
1098
|
+
<span style="color:var(--text-sec)" data-i18n="pp.stat.tasks">Tasks</span>
|
|
1099
|
+
<span style="font-weight:700;color:var(--text)" id="ppStatTasks">0</span>
|
|
1100
|
+
</div>
|
|
1101
|
+
<div style="display:flex;align-items:center;gap:5px;font-size:11px">
|
|
1102
|
+
<span style="width:7px;height:7px;border-radius:50%;background:#8b5cf6;display:inline-block"></span>
|
|
1103
|
+
<span style="color:var(--text-sec)" data-i18n="pp.stat.skills">Skills</span>
|
|
1104
|
+
<span style="font-weight:700;color:var(--text)" id="ppStatSkills">0</span>
|
|
1105
|
+
</div>
|
|
1106
|
+
<div style="display:flex;align-items:center;gap:5px;font-size:11px">
|
|
1107
|
+
<span style="width:7px;height:7px;border-radius:50%;background:#ef4444;display:inline-block"></span>
|
|
1108
|
+
<span style="color:var(--text-sec)" data-i18n="pp.stat.errors">Errors</span>
|
|
1109
|
+
<span style="font-weight:700;color:var(--text)" id="ppStatErrors">0</span>
|
|
1110
|
+
</div>
|
|
1111
|
+
<div style="display:flex;align-items:center;gap:5px;font-size:11px" id="ppSkippedInfo" style="display:none">
|
|
1112
|
+
<span style="width:7px;height:7px;border-radius:50%;background:#3b82f6;display:inline-block"></span>
|
|
1113
|
+
<span style="color:var(--text-sec)" data-i18n="pp.stat.skipped">Skipped</span>
|
|
1114
|
+
<span style="font-weight:700;color:var(--text)" id="ppStatSkipped">0</span>
|
|
1115
|
+
</div>
|
|
1116
|
+
</div>
|
|
1117
|
+
<div id="ppLiveLog" style="background:var(--bg);border:1px solid var(--border);border-radius:8px;max-height:320px;overflow-y:auto;font-family:'SF Mono','Fira Code',monospace;font-size:11px;line-height:1.7;padding:0"></div>
|
|
1118
|
+
</div>
|
|
1119
|
+
<div id="ppDone" style="display:none;margin-top:12px;padding:10px 14px;border-radius:8px;font-size:12px;color:var(--text-sec);line-height:1.5"></div>
|
|
1120
|
+
</div>
|
|
1121
|
+
</div>
|
|
1122
|
+
</div>
|
|
1123
|
+
|
|
1124
|
+
<!-- Progress Area -->
|
|
1125
|
+
<div id="migrateProgress" style="display:none">
|
|
1126
|
+
<div class="settings-section">
|
|
1127
|
+
<div style="display:flex;align-items:center;gap:12px;margin-bottom:12px">
|
|
1128
|
+
<div style="font-size:13px;font-weight:600;color:var(--text)" id="migratePhaseLabel"></div>
|
|
1129
|
+
<div style="font-size:12px;color:var(--text-muted);flex:1" id="migrateCounter"></div>
|
|
1130
|
+
<button class="btn btn-sm" id="migrateStopBtn" onclick="migrateStop()" style="background:rgba(239,68,68,.12);color:#ef4444;border:1px solid rgba(239,68,68,.3);font-size:12px;padding:5px 16px;font-weight:600;cursor:pointer" data-i18n="migrate.stop">\u25A0 Stop</button>
|
|
1131
|
+
</div>
|
|
1132
|
+
|
|
1133
|
+
<div style="position:relative;height:6px;background:var(--bg);border-radius:3px;overflow:hidden;margin-bottom:16px">
|
|
1134
|
+
<div id="migrateBar" style="position:absolute;left:0;top:0;height:100%;width:0%;background:linear-gradient(90deg,#6366f1,#8b5cf6);border-radius:3px;transition:width .3s ease"></div>
|
|
1135
|
+
</div>
|
|
1136
|
+
|
|
1137
|
+
<div style="display:flex;gap:20px;margin-bottom:16px" id="migrateStatsRow">
|
|
1138
|
+
<div style="display:flex;align-items:center;gap:6px;font-size:12px">
|
|
1139
|
+
<span style="width:8px;height:8px;border-radius:50%;background:#22c55e;display:inline-block"></span>
|
|
1140
|
+
<span style="color:var(--text-sec)" data-i18n="migrate.stat.stored">Stored</span>
|
|
1141
|
+
<span style="font-weight:700;color:var(--text)" id="migrateStatStored">0</span>
|
|
1142
|
+
</div>
|
|
1143
|
+
<div style="display:flex;align-items:center;gap:6px;font-size:12px">
|
|
1144
|
+
<span style="width:8px;height:8px;border-radius:50%;background:#f59e0b;display:inline-block"></span>
|
|
1145
|
+
<span style="color:var(--text-sec)" data-i18n="migrate.stat.skipped">Skipped</span>
|
|
1146
|
+
<span style="font-weight:700;color:var(--text)" id="migrateStatSkipped">0</span>
|
|
1147
|
+
</div>
|
|
1148
|
+
<div style="display:flex;align-items:center;gap:6px;font-size:12px">
|
|
1149
|
+
<span style="width:8px;height:8px;border-radius:50%;background:#3b82f6;display:inline-block"></span>
|
|
1150
|
+
<span style="color:var(--text-sec)" data-i18n="migrate.stat.merged">Merged</span>
|
|
1151
|
+
<span style="font-weight:700;color:var(--text)" id="migrateStatMerged">0</span>
|
|
1152
|
+
</div>
|
|
1153
|
+
<div style="display:flex;align-items:center;gap:6px;font-size:12px">
|
|
1154
|
+
<span style="width:8px;height:8px;border-radius:50%;background:#ef4444;display:inline-block"></span>
|
|
1155
|
+
<span style="color:var(--text-sec)" data-i18n="migrate.stat.errors">Errors</span>
|
|
1156
|
+
<span style="font-weight:700;color:var(--text)" id="migrateStatErrors">0</span>
|
|
1157
|
+
</div>
|
|
1158
|
+
</div>
|
|
1159
|
+
|
|
1160
|
+
<div id="migrateLiveLog" style="background:var(--bg);border:1px solid var(--border);border-radius:10px;max-height:480px;overflow-y:auto;font-family:'SF Mono','Fira Code',monospace;font-size:11px;line-height:1.7;padding:0">
|
|
1161
|
+
</div>
|
|
1162
|
+
</div>
|
|
1163
|
+
</div>
|
|
1164
|
+
|
|
1165
|
+
<!-- Done Summary -->
|
|
1166
|
+
<div id="migrateDone" style="display:none">
|
|
1167
|
+
<div class="settings-section" style="background:rgba(34,197,94,.04);border:1px solid rgba(34,197,94,.2)">
|
|
1168
|
+
<div style="font-size:14px;font-weight:700;color:#22c55e;margin-bottom:8px">\u2705 <span data-i18n="migrate.done">Import Complete</span></div>
|
|
1169
|
+
<div id="migrateDoneSummary" style="font-size:12px;color:var(--text-sec);line-height:1.6"></div>
|
|
1170
|
+
</div>
|
|
1171
|
+
</div>
|
|
1172
|
+
</div>
|
|
1173
|
+
|
|
1020
1174
|
</div>
|
|
1021
1175
|
</div>
|
|
1022
1176
|
|
|
@@ -1189,6 +1343,7 @@ const I18N={
|
|
|
1189
1343
|
'logs.output':'OUTPUT',
|
|
1190
1344
|
'logs.empty':'No logs yet. Logs will appear here when tools are called.',
|
|
1191
1345
|
'logs.ago':'ago',
|
|
1346
|
+
'tab.import':'\u{1F4E5} Import',
|
|
1192
1347
|
'tab.settings':'\u2699 Settings',
|
|
1193
1348
|
'settings.embedding':'Embedding Model',
|
|
1194
1349
|
'settings.summarizer':'Summarizer Model',
|
|
@@ -1205,6 +1360,9 @@ const I18N={
|
|
|
1205
1360
|
'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.',
|
|
1206
1361
|
'settings.optional':'Optional',
|
|
1207
1362
|
'settings.skill.usemain':'Use Main Summarizer',
|
|
1363
|
+
'settings.telemetry':'Telemetry',
|
|
1364
|
+
'settings.telemetry.enabled':'Enable Anonymous Telemetry',
|
|
1365
|
+
'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.',
|
|
1208
1366
|
'settings.viewerport':'Viewer Port',
|
|
1209
1367
|
'settings.viewerport.hint':'Requires restart to take effect',
|
|
1210
1368
|
'settings.save':'Save Settings',
|
|
@@ -1212,6 +1370,65 @@ const I18N={
|
|
|
1212
1370
|
'settings.saved':'Saved',
|
|
1213
1371
|
'settings.restart.hint':'Some changes require restarting the OpenClaw gateway to take effect.',
|
|
1214
1372
|
'settings.save.fail':'Failed to save settings',
|
|
1373
|
+
'migrate.title':'Import OpenClaw Memory',
|
|
1374
|
+
'migrate.desc':'Migrate your existing OpenClaw built-in memories and conversation history into this plugin. The import process uses smart deduplication to avoid duplicates.',
|
|
1375
|
+
'migrate.modes.title':'Three ways to use:',
|
|
1376
|
+
'migrate.mode1.label':'\\u2460 Import memories only (fast)',
|
|
1377
|
+
'migrate.mode1.desc':' — Click "Start Import" to quickly migrate all memory chunks and conversations. No task/skill generation. Suitable when you just need the raw data.',
|
|
1378
|
+
'migrate.mode2.label':'\\u2461 Import + generate tasks & skills (slow, serial)',
|
|
1379
|
+
'migrate.mode2.desc':' — After importing memories, enable "Generate Tasks" and/or "Trigger Skill Evolution" below to analyze conversations one by one. This takes longer as each session is processed by LLM sequentially.',
|
|
1380
|
+
'migrate.mode3.label':'\\u2462 Import first, generate later (flexible)',
|
|
1381
|
+
'migrate.mode3.desc':' — Import memories now, then come back anytime to start task/skill generation. You can pause the generation at any point and resume later — it will pick up where you left off, only processing sessions that haven\\'t been handled yet.',
|
|
1382
|
+
'migrate.config.warn':'Configuration Required',
|
|
1383
|
+
'migrate.config.warn.desc':'Please configure both Embedding Model and Summarizer Model above before importing. These are required for processing memories.',
|
|
1384
|
+
'migrate.sqlite.label':'Memory Index (SQLite)',
|
|
1385
|
+
'migrate.sessions.label':'Conversation History',
|
|
1386
|
+
'migrate.scan':'Scan Data Sources',
|
|
1387
|
+
'migrate.start':'Start Import',
|
|
1388
|
+
'migrate.scanning':'Scanning...',
|
|
1389
|
+
'migrate.stat.stored':'Stored',
|
|
1390
|
+
'migrate.stat.skipped':'Skipped',
|
|
1391
|
+
'migrate.stat.merged':'Merged',
|
|
1392
|
+
'migrate.stat.errors':'Errors',
|
|
1393
|
+
'migrate.done':'Import Complete',
|
|
1394
|
+
'migrate.done.summary':'Processed {total} items: {stored} stored, {skipped} skipped, {merged} merged, {errors} errors.',
|
|
1395
|
+
'migrate.phase.sqlite':'Importing memory index...',
|
|
1396
|
+
'migrate.phase.sessions':'Importing conversation history...',
|
|
1397
|
+
'migrate.chunks':'chunks',
|
|
1398
|
+
'migrate.sessions.count':'sessions, {n} messages',
|
|
1399
|
+
'migrate.nodata':'No OpenClaw data found to import.',
|
|
1400
|
+
'migrate.running':'Import in progress...',
|
|
1401
|
+
'migrate.error.running':'A migration is already in progress.',
|
|
1402
|
+
'migrate.stop':'\\u25A0 Stop',
|
|
1403
|
+
'migrate.stopping':'Stopping...',
|
|
1404
|
+
'migrate.stopped':'Import Stopped',
|
|
1405
|
+
'migrate.stopped.hint':'Import was stopped. You can resume anytime — already imported items will be skipped automatically.',
|
|
1406
|
+
'migrate.resume':'Continue Import',
|
|
1407
|
+
'migrate.already.hint':'All data has been imported previously. No new items to process.',
|
|
1408
|
+
'pp.title':'\\u{1F9E0} Optional: Generate Tasks & Skills',
|
|
1409
|
+
'pp.desc':'This step is completely optional. The import above has already stored raw memory data. Here you can further analyze imported conversations to generate structured task summaries and evolve reusable skills. Processing is serial (one session at a time) and may take a while. You can stop at any time and resume later — it will only process sessions not yet handled.',
|
|
1410
|
+
'pp.tasks.label':'Generate task summaries',
|
|
1411
|
+
'pp.tasks.hint':'Group imported messages into tasks and generate a structured summary (title, goal, steps, result) for each one. Makes it easier to search and recall past work.',
|
|
1412
|
+
'pp.skills.label':'Trigger skill evolution',
|
|
1413
|
+
'pp.skills.hint':'Analyze completed tasks and automatically create or upgrade reusable skills (SKILL.md). Requires task summaries to be enabled. May take longer due to LLM evaluation.',
|
|
1414
|
+
'pp.start':'Start Processing',
|
|
1415
|
+
'pp.resume':'Resume Processing',
|
|
1416
|
+
'pp.running':'Processing',
|
|
1417
|
+
'pp.stopped':'Processing stopped. You can resume anytime.',
|
|
1418
|
+
'pp.failed':'Processing failed — see error message above.',
|
|
1419
|
+
'pp.done':'Task & skill generation complete!',
|
|
1420
|
+
'pp.select.warn':'Please select at least one option.',
|
|
1421
|
+
'pp.skill.created':'Skill created',
|
|
1422
|
+
'pp.stat.tasks':'Tasks',
|
|
1423
|
+
'pp.stat.skills':'Skills',
|
|
1424
|
+
'pp.stat.errors':'Errors',
|
|
1425
|
+
'pp.stat.skipped':'Skipped',
|
|
1426
|
+
'pp.info.skipped':'{n} sessions already processed, skipping.',
|
|
1427
|
+
'pp.info.pending':'Processing {n} sessions...',
|
|
1428
|
+
'pp.info.allDone':'All sessions have been processed already. Nothing to do.',
|
|
1429
|
+
'pp.action.full':'Task+Skill',
|
|
1430
|
+
'pp.action.skillOnly':'Skill only (task exists)',
|
|
1431
|
+
'card.imported':'OpenClaw Native',
|
|
1215
1432
|
'skills.draft':'Draft',
|
|
1216
1433
|
'skills.filter.active':'Active',
|
|
1217
1434
|
'skills.filter.draft':'Draft',
|
|
@@ -1390,6 +1607,7 @@ const I18N={
|
|
|
1390
1607
|
'logs.output':'输出',
|
|
1391
1608
|
'logs.empty':'暂无日志。当工具被调用时日志会显示在这里。',
|
|
1392
1609
|
'logs.ago':'前',
|
|
1610
|
+
'tab.import':'\u{1F4E5} 导入',
|
|
1393
1611
|
'tab.settings':'\u2699 设置',
|
|
1394
1612
|
'settings.embedding':'嵌入模型',
|
|
1395
1613
|
'settings.summarizer':'摘要模型',
|
|
@@ -1406,6 +1624,9 @@ const I18N={
|
|
|
1406
1624
|
'settings.skill.model.hint':'不配置时默认使用上方的摘要模型进行技能生成。如需更高质量的技能输出,可在此单独配置一个更强的模型。',
|
|
1407
1625
|
'settings.optional':'可选',
|
|
1408
1626
|
'settings.skill.usemain':'使用主摘要模型',
|
|
1627
|
+
'settings.telemetry':'数据统计',
|
|
1628
|
+
'settings.telemetry.enabled':'启用匿名数据统计',
|
|
1629
|
+
'settings.telemetry.hint':'匿名使用统计,帮助改进插件。仅发送工具名称、响应时间和版本信息,不会发送任何记忆内容、搜索查询或个人数据。',
|
|
1409
1630
|
'settings.viewerport':'Viewer 端口',
|
|
1410
1631
|
'settings.viewerport.hint':'修改后需重启网关生效',
|
|
1411
1632
|
'settings.save':'保存设置',
|
|
@@ -1413,6 +1634,65 @@ const I18N={
|
|
|
1413
1634
|
'settings.saved':'已保存',
|
|
1414
1635
|
'settings.restart.hint':'部分设置修改后需要重启 OpenClaw 网关才能生效。',
|
|
1415
1636
|
'settings.save.fail':'保存设置失败',
|
|
1637
|
+
'migrate.title':'导入 OpenClaw 记忆',
|
|
1638
|
+
'migrate.desc':'将 OpenClaw 内置的记忆数据和对话历史迁移到本插件中。导入过程使用智能去重,避免重复导入。',
|
|
1639
|
+
'migrate.modes.title':'三种使用方式:',
|
|
1640
|
+
'migrate.mode1.label':'\u2460 仅导入记忆(快速)',
|
|
1641
|
+
'migrate.mode1.desc':'——点击「开始导入」即可快速迁移所有记忆片段和对话历史,不进行任务/技能生成。适合只需要原始数据的场景。',
|
|
1642
|
+
'migrate.mode2.label':'\u2461 导入 + 生成任务与技能(较慢,串行)',
|
|
1643
|
+
'migrate.mode2.desc':'——导入记忆后,在下方勾选「生成任务摘要」和/或「触发技能进化」,系统会逐个会话分析。由于每个会话都需要 LLM 处理,耗时较长。',
|
|
1644
|
+
'migrate.mode3.label':'\u2462 先导入,随时再生成(灵活)',
|
|
1645
|
+
'migrate.mode3.desc':'——先导入记忆,之后随时可以回来开启任务/技能生成。生成过程可以随时暂停,下次继续时会从上次停下的地方接着处理,已处理的会话会自动跳过。',
|
|
1646
|
+
'migrate.config.warn':'需要配置',
|
|
1647
|
+
'migrate.config.warn.desc':'请先在上方配置好 Embedding 模型和 Summarizer 模型,这两项是处理记忆所必需的。',
|
|
1648
|
+
'migrate.sqlite.label':'记忆索引 (SQLite)',
|
|
1649
|
+
'migrate.sessions.label':'对话历史',
|
|
1650
|
+
'migrate.scan':'扫描数据源',
|
|
1651
|
+
'migrate.start':'开始导入',
|
|
1652
|
+
'migrate.scanning':'扫描中...',
|
|
1653
|
+
'migrate.stat.stored':'已存储',
|
|
1654
|
+
'migrate.stat.skipped':'已跳过',
|
|
1655
|
+
'migrate.stat.merged':'已合并',
|
|
1656
|
+
'migrate.stat.errors':'错误',
|
|
1657
|
+
'migrate.done':'导入完成',
|
|
1658
|
+
'migrate.done.summary':'共处理 {total} 条:{stored} 条存储,{skipped} 条跳过,{merged} 条合并,{errors} 条错误。',
|
|
1659
|
+
'migrate.phase.sqlite':'正在导入记忆索引...',
|
|
1660
|
+
'migrate.phase.sessions':'正在导入对话历史...',
|
|
1661
|
+
'migrate.chunks':'条记忆',
|
|
1662
|
+
'migrate.sessions.count':'个会话,{n} 条消息',
|
|
1663
|
+
'migrate.nodata':'未找到可导入的 OpenClaw 数据。',
|
|
1664
|
+
'migrate.running':'导入进行中...',
|
|
1665
|
+
'migrate.error.running':'已有迁移任务正在进行。',
|
|
1666
|
+
'migrate.stop':'\\u25A0 停止',
|
|
1667
|
+
'migrate.stopping':'正在停止...',
|
|
1668
|
+
'migrate.stopped':'导入已停止',
|
|
1669
|
+
'migrate.stopped.hint':'导入已停止。你可以随时继续——已导入的内容会自动跳过。',
|
|
1670
|
+
'migrate.resume':'继续导入',
|
|
1671
|
+
'migrate.already.hint':'所有数据已在之前导入过,没有新内容需要处理。',
|
|
1672
|
+
'pp.title':'\\u{1F9E0} 可选:生成任务与技能',
|
|
1673
|
+
'pp.desc':'此步骤完全可选。上面的导入已经存储了原始记忆数据。在这里可以进一步分析已导入的对话,生成结构化的任务摘要或进化可复用的技能。处理过程是串行的(逐个会话),可能需要较长时间。你可以随时停止,下次继续时只会处理尚未完成的会话。',
|
|
1674
|
+
'pp.tasks.label':'生成任务摘要',
|
|
1675
|
+
'pp.tasks.hint':'将导入的消息按任务分组,为每个任务生成结构化摘要(标题、目标、步骤、结果),方便日后搜索和回忆。',
|
|
1676
|
+
'pp.skills.label':'触发技能进化',
|
|
1677
|
+
'pp.skills.hint':'分析已完成的任务,自动创建或升级可复用的技能(SKILL.md)。需要先启用任务摘要。由于需要 LLM 评估,耗时较长。',
|
|
1678
|
+
'pp.start':'开始处理',
|
|
1679
|
+
'pp.resume':'继续处理',
|
|
1680
|
+
'pp.running':'正在处理',
|
|
1681
|
+
'pp.stopped':'处理已停止,你可以随时继续。',
|
|
1682
|
+
'pp.failed':'处理失败,请查看上方的错误提示。',
|
|
1683
|
+
'pp.done':'任务与技能生成完成!',
|
|
1684
|
+
'pp.select.warn':'请至少选择一个选项。',
|
|
1685
|
+
'pp.skill.created':'技能已创建',
|
|
1686
|
+
'pp.stat.tasks':'任务',
|
|
1687
|
+
'pp.stat.skills':'技能',
|
|
1688
|
+
'pp.stat.errors':'错误',
|
|
1689
|
+
'pp.stat.skipped':'已跳过',
|
|
1690
|
+
'pp.info.skipped':'已有 {n} 个会话处理过,自动跳过。',
|
|
1691
|
+
'pp.info.pending':'正在处理 {n} 个会话...',
|
|
1692
|
+
'pp.info.allDone':'所有会话均已处理过,无需重复处理。',
|
|
1693
|
+
'pp.action.full':'任务+技能',
|
|
1694
|
+
'pp.action.skillOnly':'仅技能(任务已存在)',
|
|
1695
|
+
'card.imported':'OpenClaw 原生记忆',
|
|
1416
1696
|
'skills.draft':'草稿',
|
|
1417
1697
|
'skills.filter.active':'生效中',
|
|
1418
1698
|
'skills.filter.draft':'草稿',
|
|
@@ -1558,12 +1838,14 @@ function switchView(view){
|
|
|
1558
1838
|
const skillsView=document.getElementById('skillsView');
|
|
1559
1839
|
const logsView=document.getElementById('logsView');
|
|
1560
1840
|
const settingsView=document.getElementById('settingsView');
|
|
1841
|
+
const migrateView=document.getElementById('migrateView');
|
|
1561
1842
|
feedWrap.classList.add('hide');
|
|
1562
1843
|
analyticsView.classList.remove('show');
|
|
1563
1844
|
tasksView.classList.remove('show');
|
|
1564
1845
|
skillsView.classList.remove('show');
|
|
1565
1846
|
logsView.classList.remove('show');
|
|
1566
1847
|
settingsView.classList.remove('show');
|
|
1848
|
+
migrateView.classList.remove('show');
|
|
1567
1849
|
if(view==='analytics'){
|
|
1568
1850
|
analyticsView.classList.add('show');
|
|
1569
1851
|
loadMetrics();
|
|
@@ -1579,6 +1861,9 @@ function switchView(view){
|
|
|
1579
1861
|
} else if(view==='settings'){
|
|
1580
1862
|
settingsView.classList.add('show');
|
|
1581
1863
|
loadConfig();
|
|
1864
|
+
} else if(view==='import'){
|
|
1865
|
+
migrateView.classList.add('show');
|
|
1866
|
+
if(!window._migrateRunning) migrateScan();
|
|
1582
1867
|
} else {
|
|
1583
1868
|
feedWrap.classList.remove('hide');
|
|
1584
1869
|
}
|
|
@@ -2180,15 +2465,10 @@ async function loadConfig(){
|
|
|
2180
2465
|
document.getElementById('cfgSkillConfidence').value=sk.minConfidence||'';
|
|
2181
2466
|
document.getElementById('cfgSkillMinChunks').value=sk.minChunksForEval||'';
|
|
2182
2467
|
|
|
2183
|
-
const skSum=sk.summarizer||{};
|
|
2184
|
-
document.getElementById('cfgSkillProviderDefault').textContent='\u2014 '+t('settings.skill.usemain');
|
|
2185
|
-
document.getElementById('cfgSkillProvider').value=skSum.provider||'';
|
|
2186
|
-
document.getElementById('cfgSkillModel').value=skSum.model||'';
|
|
2187
|
-
document.getElementById('cfgSkillEndpoint').value=skSum.endpoint||'';
|
|
2188
|
-
document.getElementById('cfgSkillApiKey').value=skSum.apiKey||'';
|
|
2189
|
-
document.getElementById('cfgSkillTemp').value=skSum.temperature!=null?skSum.temperature:'';
|
|
2190
|
-
|
|
2191
2468
|
document.getElementById('cfgViewerPort').value=cfg.viewerPort||'';
|
|
2469
|
+
|
|
2470
|
+
const tel=cfg.telemetry||{};
|
|
2471
|
+
document.getElementById('cfgTelemetryEnabled').checked=tel.enabled!==false;
|
|
2192
2472
|
}catch(e){
|
|
2193
2473
|
console.error('loadConfig error',e);
|
|
2194
2474
|
}
|
|
@@ -2218,18 +2498,13 @@ async function saveConfig(){
|
|
|
2218
2498
|
const mc=document.getElementById('cfgSkillConfidence').value.trim();if(mc) cfg.skillEvolution.minConfidence=Number(mc);
|
|
2219
2499
|
const mk=document.getElementById('cfgSkillMinChunks').value.trim();if(mk) cfg.skillEvolution.minChunksForEval=Number(mk);
|
|
2220
2500
|
|
|
2221
|
-
const skP=document.getElementById('cfgSkillProvider').value;
|
|
2222
|
-
if(skP){
|
|
2223
|
-
cfg.skillEvolution.summarizer={provider:skP};
|
|
2224
|
-
const v=document.getElementById('cfgSkillModel').value.trim();if(v) cfg.skillEvolution.summarizer.model=v;
|
|
2225
|
-
const e=document.getElementById('cfgSkillEndpoint').value.trim();if(e) cfg.skillEvolution.summarizer.endpoint=e;
|
|
2226
|
-
const k=document.getElementById('cfgSkillApiKey').value.trim();if(k) cfg.skillEvolution.summarizer.apiKey=k;
|
|
2227
|
-
const tp=document.getElementById('cfgSkillTemp').value.trim();if(tp!=='') cfg.skillEvolution.summarizer.temperature=Number(tp);
|
|
2228
|
-
}
|
|
2229
|
-
|
|
2230
2501
|
const vp=document.getElementById('cfgViewerPort').value.trim();
|
|
2231
2502
|
if(vp) cfg.viewerPort=Number(vp);
|
|
2232
2503
|
|
|
2504
|
+
cfg.telemetry={
|
|
2505
|
+
enabled:document.getElementById('cfgTelemetryEnabled').checked
|
|
2506
|
+
};
|
|
2507
|
+
|
|
2233
2508
|
try{
|
|
2234
2509
|
const r=await fetch('/api/config',{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(cfg)});
|
|
2235
2510
|
if(!r.ok) throw new Error(await r.text());
|
|
@@ -2550,6 +2825,8 @@ function renderBreakdown(obj,containerId){
|
|
|
2550
2825
|
/* ─── Data loading ─── */
|
|
2551
2826
|
async function loadAll(){
|
|
2552
2827
|
await Promise.all([loadStats(),loadMemories()]);
|
|
2828
|
+
checkMigrateStatus();
|
|
2829
|
+
connectPPSSE();
|
|
2553
2830
|
}
|
|
2554
2831
|
|
|
2555
2832
|
async function loadStats(){
|
|
@@ -2689,6 +2966,8 @@ function renderMemories(items){
|
|
|
2689
2966
|
const ds=m.dedup_status||'active';
|
|
2690
2967
|
const isInactive=ds==='duplicate'||ds==='merged';
|
|
2691
2968
|
const dedupBadge=ds==='duplicate'?'<span class="dedup-badge duplicate">'+t('card.dedupDuplicate')+'</span>':ds==='merged'?'<span class="dedup-badge merged">'+t('card.dedupMerged')+'</span>':'';
|
|
2969
|
+
const isImported=sid.startsWith('openclaw-import-')||sid.startsWith('openclaw-session-');
|
|
2970
|
+
const importBadge=isImported?'<span class="import-badge">\u{1F990} '+t('card.imported')+'</span>':'';
|
|
2692
2971
|
let dedupInfo='';
|
|
2693
2972
|
if(isInactive){
|
|
2694
2973
|
const reason=m.dedup_reason?'<span style="font-size:11px;color:var(--text-muted)">'+t('card.dedupReason')+esc(m.dedup_reason)+'</span>':'';
|
|
@@ -2713,7 +2992,7 @@ function renderMemories(items){
|
|
|
2713
2992
|
}catch(e){}
|
|
2714
2993
|
}
|
|
2715
2994
|
return '<div class="memory-card'+(isInactive?' dedup-inactive':'')+'">'+
|
|
2716
|
-
'<div class="card-header"><div class="meta"><span class="role-tag '+role+'">'+role+'</span><span class="kind-tag">'+kind+'</span>'+dedupBadge+mergeBadge+'</div><span class="card-time"><span class="session-tag" title="'+esc(sid)+'">'+esc(sidShort)+'</span> '+time+updatedAt+'</span></div>'+
|
|
2995
|
+
'<div class="card-header"><div class="meta"><span class="role-tag '+role+'">'+role+'</span><span class="kind-tag">'+kind+'</span>'+importBadge+dedupBadge+mergeBadge+'</div><span class="card-time"><span class="session-tag" title="'+esc(sid)+'">'+esc(sidShort)+'</span> '+time+updatedAt+'</span></div>'+
|
|
2717
2996
|
'<div class="card-summary">'+summary+'</div>'+
|
|
2718
2997
|
dedupInfo+
|
|
2719
2998
|
'<div class="card-content" id="content-'+id+'"><pre>'+content+'</pre></div>'+
|
|
@@ -2919,6 +3198,503 @@ async function clearAll(){
|
|
|
2919
3198
|
else{toast(t('toast.clearfail'),'error')}
|
|
2920
3199
|
}
|
|
2921
3200
|
|
|
3201
|
+
/* ─── Migration ─── */
|
|
3202
|
+
let migrateScanData=null;
|
|
3203
|
+
let migrateStats={stored:0,skipped:0,merged:0,errors:0};
|
|
3204
|
+
|
|
3205
|
+
async function migrateScan(){
|
|
3206
|
+
const btn=document.getElementById('migrateScanBtn');
|
|
3207
|
+
btn.disabled=true;
|
|
3208
|
+
btn.textContent=t('migrate.scanning');
|
|
3209
|
+
document.getElementById('migrateStartBtn').style.display='none';
|
|
3210
|
+
document.getElementById('migrateScanResult').style.display='none';
|
|
3211
|
+
document.getElementById('migrateConfigWarn').style.display='none';
|
|
3212
|
+
document.getElementById('migrateProgress').style.display='none';
|
|
3213
|
+
document.getElementById('migrateDone').style.display='none';
|
|
3214
|
+
|
|
3215
|
+
try{
|
|
3216
|
+
const r=await fetch('/api/migrate/scan');
|
|
3217
|
+
const d=await r.json();
|
|
3218
|
+
migrateScanData=d;
|
|
3219
|
+
|
|
3220
|
+
const sqliteTotal=d.sqliteFiles.reduce((s,f)=>s+f.chunks,0);
|
|
3221
|
+
document.getElementById('migrateSqliteCount').textContent=sqliteTotal;
|
|
3222
|
+
document.getElementById('migrateSqliteFiles').textContent=d.sqliteFiles.map(f=>f.file+' ('+f.chunks+')').join(', ')||'—';
|
|
3223
|
+
document.getElementById('migrateSessionCount').textContent=d.sessions.messages;
|
|
3224
|
+
document.getElementById('migrateSessionFiles').textContent=d.sessions.count+' '+t('migrate.sessions.count').replace('{n}',d.sessions.messages);
|
|
3225
|
+
document.getElementById('migrateScanResult').style.display='block';
|
|
3226
|
+
|
|
3227
|
+
if(!d.configReady){
|
|
3228
|
+
document.getElementById('migrateConfigWarn').style.display='block';
|
|
3229
|
+
const parts=[];
|
|
3230
|
+
if(!d.hasEmbedding) parts.push('Embedding');
|
|
3231
|
+
if(!d.hasSummarizer) parts.push('Summarizer');
|
|
3232
|
+
document.getElementById('migrateConfigWarn').querySelector('div:last-child').textContent=
|
|
3233
|
+
t('migrate.config.warn.desc')+' ('+parts.join(', ')+')';
|
|
3234
|
+
}
|
|
3235
|
+
|
|
3236
|
+
if(d.totalItems>0 && d.configReady){
|
|
3237
|
+
document.getElementById('migrateStartBtn').style.display='inline-flex';
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
if(d.totalItems===0){
|
|
3241
|
+
document.getElementById('migrateStatus').textContent=t('migrate.nodata');
|
|
3242
|
+
}
|
|
3243
|
+
|
|
3244
|
+
if(d.hasImportedData){
|
|
3245
|
+
document.getElementById('postprocessSection').style.display='block';
|
|
3246
|
+
}
|
|
3247
|
+
}catch(e){
|
|
3248
|
+
toast('Scan failed: '+e.message,'error');
|
|
3249
|
+
}finally{
|
|
3250
|
+
btn.disabled=false;
|
|
3251
|
+
btn.textContent=t('migrate.scan');
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3255
|
+
function migrateStart(){
|
|
3256
|
+
if(!migrateScanData||!migrateScanData.configReady)return;
|
|
3257
|
+
if(!confirm(t('migrate.start')+'?'))return;
|
|
3258
|
+
|
|
3259
|
+
window._migrateRunning=true;
|
|
3260
|
+
_migrateStatusChecked=false;
|
|
3261
|
+
document.getElementById('migrateStartBtn').style.display='none';
|
|
3262
|
+
document.getElementById('migrateScanBtn').disabled=true;
|
|
3263
|
+
document.getElementById('migrateProgress').style.display='block';
|
|
3264
|
+
document.getElementById('migrateDone').style.display='none';
|
|
3265
|
+
document.getElementById('migrateLiveLog').innerHTML='';
|
|
3266
|
+
migrateStats={stored:0,skipped:0,merged:0,errors:0};
|
|
3267
|
+
updateMigrateStats();
|
|
3268
|
+
|
|
3269
|
+
document.getElementById('migrateStopBtn').disabled=false;
|
|
3270
|
+
document.getElementById('migrateBar').style.background='linear-gradient(90deg,#6366f1,#8b5cf6)';
|
|
3271
|
+
const body=JSON.stringify({sources:['sqlite','sessions']});
|
|
3272
|
+
connectMigrateSSE('/api/migrate/start','POST',body);
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3275
|
+
async function migrateStop(){
|
|
3276
|
+
const btn=document.getElementById('migrateStopBtn');
|
|
3277
|
+
btn.disabled=true;
|
|
3278
|
+
btn.textContent=t('migrate.stopping');
|
|
3279
|
+
try{
|
|
3280
|
+
await fetch('/api/migrate/stop',{method:'POST'});
|
|
3281
|
+
}catch(e){
|
|
3282
|
+
toast('Stop failed: '+e.message,'error');
|
|
3283
|
+
btn.disabled=false;
|
|
3284
|
+
btn.textContent=t('migrate.stop');
|
|
3285
|
+
}
|
|
3286
|
+
}
|
|
3287
|
+
|
|
3288
|
+
function connectMigrateSSE(url,method,body){
|
|
3289
|
+
const opts={method:method||'GET'};
|
|
3290
|
+
if(body){opts.headers={'Content-Type':'application/json'};opts.body=body;}
|
|
3291
|
+
fetch(url,opts)
|
|
3292
|
+
.then(r=>{
|
|
3293
|
+
if(!r.ok){toast('Migration request failed: '+r.status,'error');onMigrateDone(false);return;}
|
|
3294
|
+
readSSEStream(r);
|
|
3295
|
+
})
|
|
3296
|
+
.catch(e=>{toast('Migration failed: '+e.message,'error');onMigrateDone(false);});
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
function readSSEStream(r){
|
|
3300
|
+
const reader=r.body.getReader();
|
|
3301
|
+
const decoder=new TextDecoder();
|
|
3302
|
+
let buf='';
|
|
3303
|
+
let migrateDoneCalled=false;
|
|
3304
|
+
const NL=String.fromCharCode(10);
|
|
3305
|
+
function pump(){
|
|
3306
|
+
reader.read().then(({done,value})=>{
|
|
3307
|
+
if(done){if(!migrateDoneCalled)onMigrateDone(false);return;}
|
|
3308
|
+
buf+=decoder.decode(value,{stream:true});
|
|
3309
|
+
const lines=buf.split(NL);
|
|
3310
|
+
buf=lines.pop()||'';
|
|
3311
|
+
let evtType='';
|
|
3312
|
+
for(const line of lines){
|
|
3313
|
+
if(line.startsWith('event: ')){evtType=line.slice(7).trim();}
|
|
3314
|
+
else if(line.startsWith('data: ')){
|
|
3315
|
+
try{
|
|
3316
|
+
const data=JSON.parse(line.slice(6));
|
|
3317
|
+
if(evtType==='done'||evtType==='stopped') migrateDoneCalled=true;
|
|
3318
|
+
handleMigrateEvent(evtType,data);
|
|
3319
|
+
}catch{}
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
pump();
|
|
3323
|
+
});
|
|
3324
|
+
}
|
|
3325
|
+
pump();
|
|
3326
|
+
}
|
|
3327
|
+
|
|
3328
|
+
var _migrateStatusChecked=false;
|
|
3329
|
+
async function checkMigrateStatus(){
|
|
3330
|
+
if(_migrateStatusChecked) return;
|
|
3331
|
+
_migrateStatusChecked=true;
|
|
3332
|
+
try{
|
|
3333
|
+
const r=await fetch('/api/migrate/status');
|
|
3334
|
+
if(!r.ok)return;
|
|
3335
|
+
const s=await r.json();
|
|
3336
|
+
if(s.running){
|
|
3337
|
+
window._migrateRunning=true;
|
|
3338
|
+
switchView('import');
|
|
3339
|
+
migrateStats={stored:s.stored,skipped:s.skipped,merged:s.merged,errors:s.errors};
|
|
3340
|
+
updateMigrateStats();
|
|
3341
|
+
document.getElementById('migrateProgress').style.display='block';
|
|
3342
|
+
document.getElementById('migrateStartBtn').style.display='none';
|
|
3343
|
+
document.getElementById('migrateScanBtn').disabled=true;
|
|
3344
|
+
document.getElementById('migrateStopBtn').disabled=false;
|
|
3345
|
+
const pct=s.total>0?Math.round((s.processed/s.total)*100):0;
|
|
3346
|
+
document.getElementById('migrateBar').style.width=pct+'%';
|
|
3347
|
+
document.getElementById('migrateCounter').textContent=s.processed+' / '+s.total+' ('+pct+'%)';
|
|
3348
|
+
const label=s.phase==='sqlite'?t('migrate.phase.sqlite'):t('migrate.phase.sessions');
|
|
3349
|
+
document.getElementById('migratePhaseLabel').textContent=label;
|
|
3350
|
+
connectMigrateSSE('/api/migrate/stream','GET',null);
|
|
3351
|
+
}else if(s.done&&(s.stored>0||s.skipped>0||s.stopped)){
|
|
3352
|
+
migrateStats={stored:s.stored,skipped:s.skipped,merged:s.merged,errors:s.errors};
|
|
3353
|
+
updateMigrateStats();
|
|
3354
|
+
document.getElementById('migrateProgress').style.display='block';
|
|
3355
|
+
const pct=s.total>0?Math.round((s.processed/s.total)*100):0;
|
|
3356
|
+
document.getElementById('migrateBar').style.width=pct+'%';
|
|
3357
|
+
document.getElementById('migrateCounter').textContent=s.processed+' / '+s.total+' ('+pct+'%)';
|
|
3358
|
+
onMigrateDone(!!s.stopped,true);
|
|
3359
|
+
}
|
|
3360
|
+
}catch(e){console.log('checkMigrateStatus error',e);}
|
|
3361
|
+
}
|
|
3362
|
+
|
|
3363
|
+
function handleMigrateEvent(evtType,data){
|
|
3364
|
+
if(evtType==='phase'){
|
|
3365
|
+
const label=data.phase==='sqlite'?t('migrate.phase.sqlite'):t('migrate.phase.sessions');
|
|
3366
|
+
document.getElementById('migratePhaseLabel').textContent=label;
|
|
3367
|
+
}
|
|
3368
|
+
else if(evtType==='progress'){
|
|
3369
|
+
document.getElementById('migrateCounter').textContent=data.processed+' / '+data.total;
|
|
3370
|
+
}
|
|
3371
|
+
else if(evtType==='item'){
|
|
3372
|
+
if(data.status==='stored')migrateStats.stored++;
|
|
3373
|
+
else if(data.status==='skipped'||data.status==='duplicate')migrateStats.skipped++;
|
|
3374
|
+
else if(data.status==='merged')migrateStats.merged++;
|
|
3375
|
+
else if(data.status==='error')migrateStats.errors++;
|
|
3376
|
+
updateMigrateStats();
|
|
3377
|
+
|
|
3378
|
+
const pct=data.total>0?Math.round((data.index/data.total)*100):0;
|
|
3379
|
+
document.getElementById('migrateBar').style.width=pct+'%';
|
|
3380
|
+
document.getElementById('migrateCounter').textContent=data.index+' / '+data.total+' ('+pct+'%)';
|
|
3381
|
+
|
|
3382
|
+
appendMigrateLogItem(data);
|
|
3383
|
+
}
|
|
3384
|
+
else if(evtType==='error'){
|
|
3385
|
+
migrateStats.errors++;
|
|
3386
|
+
updateMigrateStats();
|
|
3387
|
+
appendMigrateLogItem({status:'error',preview:data.error||data.file,source:data.file});
|
|
3388
|
+
}
|
|
3389
|
+
else if(evtType==='summary'){
|
|
3390
|
+
document.getElementById('migrateBar').style.width='100%';
|
|
3391
|
+
}
|
|
3392
|
+
else if(evtType==='done'){
|
|
3393
|
+
onMigrateDone(false);
|
|
3394
|
+
}
|
|
3395
|
+
else if(evtType==='stopped'){
|
|
3396
|
+
onMigrateDone(true);
|
|
3397
|
+
}
|
|
3398
|
+
else if(evtType==='state'){
|
|
3399
|
+
migrateStats={stored:data.stored||0,skipped:data.skipped||0,merged:data.merged||0,errors:data.errors||0};
|
|
3400
|
+
updateMigrateStats();
|
|
3401
|
+
const pct=data.total>0?Math.round((data.processed/data.total)*100):0;
|
|
3402
|
+
document.getElementById('migrateBar').style.width=pct+'%';
|
|
3403
|
+
document.getElementById('migrateCounter').textContent=data.processed+' / '+data.total+' ('+pct+'%)';
|
|
3404
|
+
if(data.phase){
|
|
3405
|
+
const label=data.phase==='sqlite'?t('migrate.phase.sqlite'):t('migrate.phase.sessions');
|
|
3406
|
+
document.getElementById('migratePhaseLabel').textContent=label;
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
|
|
3411
|
+
function updateMigrateStats(){
|
|
3412
|
+
document.getElementById('migrateStatStored').textContent=migrateStats.stored;
|
|
3413
|
+
document.getElementById('migrateStatSkipped').textContent=migrateStats.skipped;
|
|
3414
|
+
document.getElementById('migrateStatMerged').textContent=migrateStats.merged;
|
|
3415
|
+
document.getElementById('migrateStatErrors').textContent=migrateStats.errors;
|
|
3416
|
+
}
|
|
3417
|
+
|
|
3418
|
+
function appendMigrateLogItem(data){
|
|
3419
|
+
const log=document.getElementById('migrateLiveLog');
|
|
3420
|
+
const icons={stored:'\\u2705',skipped:'\\u23ED',merged:'\\u{1F500}',error:'\\u274C',duplicate:'\\u23ED'};
|
|
3421
|
+
const statusClass=data.status==='duplicate'?'skipped':data.status;
|
|
3422
|
+
const el=document.createElement('div');
|
|
3423
|
+
el.className='migrate-log-item';
|
|
3424
|
+
el.innerHTML=
|
|
3425
|
+
'<div class="log-icon '+statusClass+'">'+( icons[data.status]||'\\u2022')+'</div>'+
|
|
3426
|
+
'<div class="log-body">'+
|
|
3427
|
+
'<div class="log-preview">'+esc(data.preview||'')+'</div>'+
|
|
3428
|
+
'<div class="log-meta">'+
|
|
3429
|
+
'<span class="tag '+statusClass+'">'+(data.status||'').toUpperCase()+'</span>'+
|
|
3430
|
+
(data.source?'<span>'+esc(data.source)+'</span>':'')+
|
|
3431
|
+
(data.role?'<span>'+data.role+'</span>':'')+
|
|
3432
|
+
(data.summary?'<span style="opacity:.7">'+esc(data.summary)+'</span>':'')+
|
|
3433
|
+
'</div>'+
|
|
3434
|
+
'</div>';
|
|
3435
|
+
log.appendChild(el);
|
|
3436
|
+
log.scrollTop=log.scrollHeight;
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
function onMigrateDone(wasStopped,skipReload){
|
|
3440
|
+
window._migrateRunning=false;
|
|
3441
|
+
document.getElementById('migrateScanBtn').disabled=false;
|
|
3442
|
+
document.getElementById('migrateStopBtn').disabled=true;
|
|
3443
|
+
document.getElementById('migrateStopBtn').textContent=t('migrate.stop');
|
|
3444
|
+
const doneEl=document.getElementById('migrateDone');
|
|
3445
|
+
doneEl.style.display='block';
|
|
3446
|
+
const total=migrateStats.stored+migrateStats.skipped+migrateStats.merged+migrateStats.errors;
|
|
3447
|
+
const allSkipped=migrateStats.stored===0&&migrateStats.merged===0&&migrateStats.skipped>0&&migrateStats.errors===0;
|
|
3448
|
+
const tmpl=t('migrate.done.summary');
|
|
3449
|
+
let summaryText=tmpl
|
|
3450
|
+
.replace('{total}',total)
|
|
3451
|
+
.replace('{stored}',migrateStats.stored)
|
|
3452
|
+
.replace('{skipped}',migrateStats.skipped)
|
|
3453
|
+
.replace('{merged}',migrateStats.merged)
|
|
3454
|
+
.replace('{errors}',migrateStats.errors);
|
|
3455
|
+
if(wasStopped){
|
|
3456
|
+
summaryText+=' '+t('migrate.stopped.hint');
|
|
3457
|
+
doneEl.querySelector('.settings-section').style.background='rgba(245,158,11,.04)';
|
|
3458
|
+
doneEl.querySelector('.settings-section').style.borderColor='rgba(245,158,11,.2)';
|
|
3459
|
+
doneEl.querySelector('div div:first-child').innerHTML='\u23F8 <span>'+t('migrate.stopped')+'</span>';
|
|
3460
|
+
doneEl.querySelector('div div:first-child').style.color='#f59e0b';
|
|
3461
|
+
document.getElementById('migrateStartBtn').style.display='inline-flex';
|
|
3462
|
+
document.getElementById('migrateStartBtn').textContent=t('migrate.resume');
|
|
3463
|
+
}else if(allSkipped){
|
|
3464
|
+
summaryText+=' '+t('migrate.already.hint');
|
|
3465
|
+
doneEl.querySelector('.settings-section').style.background='rgba(59,130,246,.04)';
|
|
3466
|
+
doneEl.querySelector('.settings-section').style.borderColor='rgba(59,130,246,.2)';
|
|
3467
|
+
doneEl.querySelector('div div:first-child').innerHTML='\u{1F4AD} <span>'+t('migrate.done')+'</span>';
|
|
3468
|
+
doneEl.querySelector('div div:first-child').style.color='#3b82f6';
|
|
3469
|
+
}else{
|
|
3470
|
+
doneEl.querySelector('.settings-section').style.background='rgba(34,197,94,.04)';
|
|
3471
|
+
doneEl.querySelector('.settings-section').style.borderColor='rgba(34,197,94,.2)';
|
|
3472
|
+
doneEl.querySelector('div div:first-child').innerHTML='\u2705 <span>'+t('migrate.done')+'</span>';
|
|
3473
|
+
doneEl.querySelector('div div:first-child').style.color='#22c55e';
|
|
3474
|
+
}
|
|
3475
|
+
document.getElementById('migrateDoneSummary').textContent=summaryText;
|
|
3476
|
+
if(!wasStopped){
|
|
3477
|
+
document.getElementById('migrateBar').style.width='100%';
|
|
3478
|
+
document.getElementById('migrateBar').style.background=allSkipped?'linear-gradient(90deg,#3b82f6,#60a5fa)':'linear-gradient(90deg,#22c55e,#16a34a)';
|
|
3479
|
+
}else{
|
|
3480
|
+
document.getElementById('migrateBar').style.background='linear-gradient(90deg,#f59e0b,#fbbf24)';
|
|
3481
|
+
}
|
|
3482
|
+
fetch('/api/migrate/scan').then(r=>r.json()).then(d=>{
|
|
3483
|
+
if(d.hasImportedData) document.getElementById('postprocessSection').style.display='block';
|
|
3484
|
+
}).catch(()=>{});
|
|
3485
|
+
if(!skipReload) loadAll();
|
|
3486
|
+
}
|
|
3487
|
+
|
|
3488
|
+
/* ─── Post-processing: tasks & skills ─── */
|
|
3489
|
+
|
|
3490
|
+
var ppStats={tasks:0,skills:0,errors:0,skipped:0};
|
|
3491
|
+
window._ppRunning=false;
|
|
3492
|
+
|
|
3493
|
+
function ppStart(){
|
|
3494
|
+
var enableTasks=document.getElementById('ppEnableTasks').checked;
|
|
3495
|
+
var enableSkills=document.getElementById('ppEnableSkills').checked;
|
|
3496
|
+
if(!enableTasks&&!enableSkills){toast(t('pp.select.warn'),'error');return;}
|
|
3497
|
+
|
|
3498
|
+
window._ppRunning=true;
|
|
3499
|
+
_ppSSEConnected=false;
|
|
3500
|
+
ppStats={tasks:0,skills:0,errors:0,skipped:0};
|
|
3501
|
+
document.getElementById('ppStartBtn').style.display='none';
|
|
3502
|
+
document.getElementById('ppStopBtn').style.display='inline-flex';
|
|
3503
|
+
document.getElementById('ppStopBtn').disabled=false;
|
|
3504
|
+
document.getElementById('ppStopBtn').textContent=t('migrate.stop');
|
|
3505
|
+
document.getElementById('ppProgress').style.display='block';
|
|
3506
|
+
document.getElementById('ppDone').style.display='none';
|
|
3507
|
+
document.getElementById('ppBar').style.width='0%';
|
|
3508
|
+
document.getElementById('ppBar').style.background='linear-gradient(90deg,#f59e0b,#fbbf24)';
|
|
3509
|
+
document.getElementById('ppPhaseLabel').textContent=t('pp.running');
|
|
3510
|
+
document.getElementById('ppCounter').textContent='';
|
|
3511
|
+
document.getElementById('ppLiveLog').innerHTML='';
|
|
3512
|
+
updatePPStats();
|
|
3513
|
+
|
|
3514
|
+
var body=JSON.stringify({enableTasks:enableTasks,enableSkills:enableSkills});
|
|
3515
|
+
fetch('/api/migrate/postprocess',{method:'POST',headers:{'Content-Type':'application/json'},body:body})
|
|
3516
|
+
.then(function(r){
|
|
3517
|
+
if(!r.ok){
|
|
3518
|
+
r.json().then(function(j){toast(j.error||('Postprocess failed: '+r.status),'error');}).catch(function(){toast('Postprocess failed: '+r.status,'error');});
|
|
3519
|
+
ppDone(false,true);
|
|
3520
|
+
return;
|
|
3521
|
+
}
|
|
3522
|
+
readPPStream(r.body.getReader());
|
|
3523
|
+
})
|
|
3524
|
+
.catch(function(e){toast('Postprocess failed: '+e.message,'error');ppDone(false,true);});
|
|
3525
|
+
}
|
|
3526
|
+
|
|
3527
|
+
function updatePPStats(){
|
|
3528
|
+
document.getElementById('ppStatTasks').textContent=ppStats.tasks;
|
|
3529
|
+
document.getElementById('ppStatSkills').textContent=ppStats.skills;
|
|
3530
|
+
document.getElementById('ppStatErrors').textContent=ppStats.errors;
|
|
3531
|
+
document.getElementById('ppStatSkipped').textContent=ppStats.skipped;
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
function appendPPLogItem(data){
|
|
3535
|
+
var log=document.getElementById('ppLiveLog');
|
|
3536
|
+
var el=document.createElement('div');
|
|
3537
|
+
el.style.cssText='display:flex;align-items:flex-start;gap:8px;padding:6px 12px;border-bottom:1px solid var(--border)';
|
|
3538
|
+
var icon='\\u2022';var color='var(--text-muted)';
|
|
3539
|
+
if(data.step==='done'){icon='\\u2705';color='#22c55e';}
|
|
3540
|
+
else if(data.step==='error'){icon='\\u274C';color='#ef4444';}
|
|
3541
|
+
else if(data.step==='processing'){icon='\\u23F3';color='#f59e0b';}
|
|
3542
|
+
else if(data.step==='skipped'){icon='\\u23ED';color='#3b82f6';}
|
|
3543
|
+
else if(data.step==='skill'){icon='\\u{1F9E0}';color='#8b5cf6';}
|
|
3544
|
+
var label=data.taskTitle||data.session||data.title||'';
|
|
3545
|
+
if(label.length>60)label=label.slice(0,57)+'...';
|
|
3546
|
+
el.innerHTML='<span style="color:'+color+';min-width:18px">'+icon+'</span>'+
|
|
3547
|
+
'<span style="flex:1;color:var(--text-sec)">'+esc(label)+'</span>'+
|
|
3548
|
+
'<span style="color:var(--text-muted);font-size:10px">'+(data.index||'')+' / '+(data.total||'')+'</span>';
|
|
3549
|
+
if(data.error) el.innerHTML+='<span style="color:#ef4444;font-size:10px">'+esc(data.error)+'</span>';
|
|
3550
|
+
log.appendChild(el);
|
|
3551
|
+
log.scrollTop=log.scrollHeight;
|
|
3552
|
+
}
|
|
3553
|
+
|
|
3554
|
+
function readPPStream(reader){
|
|
3555
|
+
var NL=String.fromCharCode(10);
|
|
3556
|
+
var dec=new TextDecoder();
|
|
3557
|
+
var buf='';
|
|
3558
|
+
var ppDoneCalled=false;
|
|
3559
|
+
function pump(){
|
|
3560
|
+
reader.read().then(function(result){
|
|
3561
|
+
if(result.done){if(!ppDoneCalled)ppDone(false);return;}
|
|
3562
|
+
buf+=dec.decode(result.value,{stream:true});
|
|
3563
|
+
var lines=buf.split(NL);
|
|
3564
|
+
buf=lines.pop()||'';
|
|
3565
|
+
var evtType='';
|
|
3566
|
+
for(var i=0;i<lines.length;i++){
|
|
3567
|
+
var line=lines[i];
|
|
3568
|
+
if(line.startsWith('event: '))evtType=line.slice(7).trim();
|
|
3569
|
+
else if(line.startsWith('data: ')&&evtType){
|
|
3570
|
+
try{
|
|
3571
|
+
if(evtType==='done'||evtType==='stopped')ppDoneCalled=true;
|
|
3572
|
+
handlePPEvent(evtType,JSON.parse(line.slice(6)));
|
|
3573
|
+
}catch(e){}
|
|
3574
|
+
evtType='';
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
pump();
|
|
3578
|
+
}).catch(function(){if(!ppDoneCalled)ppDone(false);});
|
|
3579
|
+
}
|
|
3580
|
+
pump();
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3583
|
+
var _ppSSEConnected=false;
|
|
3584
|
+
function connectPPSSE(){
|
|
3585
|
+
if(_ppSSEConnected) return;
|
|
3586
|
+
_ppSSEConnected=true;
|
|
3587
|
+
fetch('/api/migrate/postprocess/status').then(function(r){return r.json();}).then(function(s){
|
|
3588
|
+
if(s.running){
|
|
3589
|
+
window._ppRunning=true;
|
|
3590
|
+
document.getElementById('postprocessSection').style.display='block';
|
|
3591
|
+
document.getElementById('ppStartBtn').style.display='none';
|
|
3592
|
+
document.getElementById('ppStopBtn').style.display='inline-flex';
|
|
3593
|
+
document.getElementById('ppStopBtn').disabled=false;
|
|
3594
|
+
document.getElementById('ppStopBtn').textContent=t('migrate.stop');
|
|
3595
|
+
document.getElementById('ppProgress').style.display='block';
|
|
3596
|
+
document.getElementById('ppDone').style.display='none';
|
|
3597
|
+
ppStats={tasks:s.tasksCreated||0,skills:s.skillsCreated||0,errors:s.errors||0,skipped:0};
|
|
3598
|
+
updatePPStats();
|
|
3599
|
+
var pct=s.total>0?Math.round((s.processed/s.total)*100):0;
|
|
3600
|
+
document.getElementById('ppBar').style.width=pct+'%';
|
|
3601
|
+
document.getElementById('ppCounter').textContent=s.processed+' / '+s.total+' ('+pct+'%)';
|
|
3602
|
+
document.getElementById('ppPhaseLabel').textContent=t('pp.running');
|
|
3603
|
+
fetch('/api/migrate/postprocess/stream',{method:'GET'}).then(function(r){
|
|
3604
|
+
if(r.ok&&r.body)readPPStream(r.body.getReader());
|
|
3605
|
+
}).catch(function(){});
|
|
3606
|
+
}else if(s.done){
|
|
3607
|
+
document.getElementById('postprocessSection').style.display='block';
|
|
3608
|
+
ppStats={tasks:s.tasksCreated||0,skills:s.skillsCreated||0,errors:s.errors||0,skipped:0};
|
|
3609
|
+
updatePPStats();
|
|
3610
|
+
document.getElementById('ppProgress').style.display='block';
|
|
3611
|
+
var pct2=s.total>0?Math.round((s.processed/s.total)*100):0;
|
|
3612
|
+
document.getElementById('ppBar').style.width=pct2+'%';
|
|
3613
|
+
document.getElementById('ppCounter').textContent=s.processed+' / '+s.total+' ('+pct2+'%)';
|
|
3614
|
+
ppDone(!!s.stopped,false,true);
|
|
3615
|
+
}
|
|
3616
|
+
}).catch(function(){});
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3619
|
+
function handlePPEvent(evtType,data){
|
|
3620
|
+
if(evtType==='progress'){
|
|
3621
|
+
var pct=data.total>0?Math.round((data.processed/data.total)*100):0;
|
|
3622
|
+
document.getElementById('ppBar').style.width=pct+'%';
|
|
3623
|
+
document.getElementById('ppCounter').textContent=data.processed+' / '+data.total+' ('+pct+'%)';
|
|
3624
|
+
}else if(evtType==='info'){
|
|
3625
|
+
if(data.alreadyProcessed>0){
|
|
3626
|
+
ppStats.skipped=data.alreadyProcessed;
|
|
3627
|
+
updatePPStats();
|
|
3628
|
+
appendPPLogItem({step:'skipped',session:t('pp.info.skipped').replace('{n}',data.alreadyProcessed),index:'',total:''});
|
|
3629
|
+
}
|
|
3630
|
+
if(data.pending===0){
|
|
3631
|
+
appendPPLogItem({step:'done',session:t('pp.info.allDone'),index:'',total:''});
|
|
3632
|
+
}else{
|
|
3633
|
+
document.getElementById('ppPhaseLabel').textContent=t('pp.info.pending').replace('{n}',data.pending);
|
|
3634
|
+
}
|
|
3635
|
+
}else if(evtType==='item'){
|
|
3636
|
+
var label=data.session||'';
|
|
3637
|
+
if(label.length>40)label=label.slice(0,37)+'...';
|
|
3638
|
+
if(data.step==='processing'){
|
|
3639
|
+
var actionLabel=data.action==='skill-only'?t('pp.action.skillOnly'):t('pp.action.full');
|
|
3640
|
+
document.getElementById('ppPhaseLabel').textContent=t('pp.running')+' — '+actionLabel+' — '+label;
|
|
3641
|
+
}
|
|
3642
|
+
if(data.step==='done'){
|
|
3643
|
+
if(data.action==='skill-only'){
|
|
3644
|
+
ppStats.skills++;
|
|
3645
|
+
}else{
|
|
3646
|
+
ppStats.tasks++;
|
|
3647
|
+
}
|
|
3648
|
+
updatePPStats();
|
|
3649
|
+
}else if(data.step==='error'){
|
|
3650
|
+
ppStats.errors++;
|
|
3651
|
+
updatePPStats();
|
|
3652
|
+
}
|
|
3653
|
+
appendPPLogItem(data);
|
|
3654
|
+
}else if(evtType==='skill'){
|
|
3655
|
+
ppStats.skills++;
|
|
3656
|
+
updatePPStats();
|
|
3657
|
+
appendPPLogItem({step:'skill',title:data.title,index:'',total:''});
|
|
3658
|
+
}else if(evtType==='done'){
|
|
3659
|
+
ppDone(false);
|
|
3660
|
+
}else if(evtType==='stopped'){
|
|
3661
|
+
ppDone(true);
|
|
3662
|
+
}
|
|
3663
|
+
}
|
|
3664
|
+
|
|
3665
|
+
function ppStop(){
|
|
3666
|
+
document.getElementById('ppStopBtn').disabled=true;
|
|
3667
|
+
document.getElementById('ppStopBtn').textContent=t('migrate.stopping');
|
|
3668
|
+
fetch('/api/migrate/postprocess/stop',{method:'POST'}).catch(function(){});
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3671
|
+
function ppDone(wasStopped,wasFailed,skipReload){
|
|
3672
|
+
window._ppRunning=false;
|
|
3673
|
+
document.getElementById('ppStopBtn').style.display='none';
|
|
3674
|
+
document.getElementById('ppStartBtn').style.display='inline-flex';
|
|
3675
|
+
document.getElementById('ppStartBtn').textContent=wasStopped?t('pp.resume'):t('pp.start');
|
|
3676
|
+
var doneEl=document.getElementById('ppDone');
|
|
3677
|
+
doneEl.style.display='block';
|
|
3678
|
+
if(wasFailed){
|
|
3679
|
+
doneEl.style.background='rgba(239,68,68,.06)';
|
|
3680
|
+
doneEl.style.color='#ef4444';
|
|
3681
|
+
doneEl.textContent=t('pp.failed')||'Processing failed — check error above';
|
|
3682
|
+
document.getElementById('ppBar').style.background='linear-gradient(90deg,#ef4444,#dc2626)';
|
|
3683
|
+
}else if(wasStopped){
|
|
3684
|
+
doneEl.style.background='rgba(245,158,11,.06)';
|
|
3685
|
+
doneEl.style.color='#f59e0b';
|
|
3686
|
+
doneEl.textContent=t('pp.stopped');
|
|
3687
|
+
document.getElementById('ppBar').style.background='linear-gradient(90deg,#f59e0b,#fbbf24)';
|
|
3688
|
+
}else{
|
|
3689
|
+
doneEl.style.background='rgba(34,197,94,.06)';
|
|
3690
|
+
doneEl.style.color='#22c55e';
|
|
3691
|
+
doneEl.textContent=t('pp.done')+' ('+t('pp.stat.tasks')+': '+ppStats.tasks+', '+t('pp.stat.skills')+': '+ppStats.skills+')';
|
|
3692
|
+
document.getElementById('ppBar').style.width='100%';
|
|
3693
|
+
document.getElementById('ppBar').style.background='linear-gradient(90deg,#22c55e,#16a34a)';
|
|
3694
|
+
}
|
|
3695
|
+
if(!skipReload) loadAll();
|
|
3696
|
+
}
|
|
3697
|
+
|
|
2922
3698
|
/* ─── Toast ─── */
|
|
2923
3699
|
function toast(msg,type='info'){
|
|
2924
3700
|
const c=document.getElementById('toasts');
|