@monoes/monomindcli 2.7.4 → 2.7.5
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/bin/cli.js +17 -1
- package/dist/src/commands/doctor-project-checks.d.ts +3 -0
- package/dist/src/commands/doctor-project-checks.d.ts.map +1 -1
- package/dist/src/commands/doctor-project-checks.js +81 -8
- package/dist/src/commands/doctor-project-checks.js.map +1 -1
- package/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +16 -2
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/memory-crud.d.ts.map +1 -1
- package/dist/src/commands/memory-crud.js +15 -5
- package/dist/src/commands/memory-crud.js.map +1 -1
- package/dist/src/commands/security-misc.d.ts.map +1 -1
- package/dist/src/commands/security-misc.js +7 -2
- package/dist/src/commands/security-misc.js.map +1 -1
- package/dist/src/init/helpers-generator.d.ts.map +1 -1
- package/dist/src/init/helpers-generator.js +5 -0
- package/dist/src/init/helpers-generator.js.map +1 -1
- package/dist/src/mcp-client.d.ts.map +1 -1
- package/dist/src/mcp-client.js +0 -2
- package/dist/src/mcp-client.js.map +1 -1
- package/dist/src/mcp-tools/agent-tools.js +1 -1
- package/dist/src/mcp-tools/agent-tools.js.map +1 -1
- package/dist/src/mcp-tools/embeddings-tools.d.ts +2 -0
- package/dist/src/mcp-tools/embeddings-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/embeddings-tools.js +11 -1
- package/dist/src/mcp-tools/embeddings-tools.js.map +1 -1
- package/dist/src/mcp-tools/guidance-tools.js +17 -17
- package/dist/src/mcp-tools/guidance-tools.js.map +1 -1
- package/dist/src/mcp-tools/hive-mind-tools.d.ts +2 -0
- package/dist/src/mcp-tools/hive-mind-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/hive-mind-tools.js +14 -2
- package/dist/src/mcp-tools/hive-mind-tools.js.map +1 -1
- package/dist/src/mcp-tools/index.d.ts +0 -1
- package/dist/src/mcp-tools/index.d.ts.map +1 -1
- package/dist/src/mcp-tools/index.js +0 -1
- package/dist/src/mcp-tools/index.js.map +1 -1
- package/dist/src/mcp-tools/monograph-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/monograph-tools.js +1 -2
- package/dist/src/mcp-tools/monograph-tools.js.map +1 -1
- package/dist/src/mcp-tools/neural-tools.js +1 -1
- package/dist/src/mcp-tools/neural-tools.js.map +1 -1
- package/dist/src/mcp-tools/swarm-tools.js +2 -2
- package/dist/src/mcp-tools/swarm-tools.js.map +1 -1
- package/dist/src/mcp-tools/transfer-tools.d.ts +2 -0
- package/dist/src/mcp-tools/transfer-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/transfer-tools.js +11 -1
- package/dist/src/mcp-tools/transfer-tools.js.map +1 -1
- package/dist/src/ui/dashboard.html +44 -618
- package/dist/src/ui/server.mjs +0 -275
- package/dist/src/utils/cosine-similarity.d.ts +2 -2
- package/dist/src/utils/cosine-similarity.js +2 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/src/mcp-tools/coherence/causal-infer.d.ts +0 -15
- package/dist/src/mcp-tools/coherence/causal-infer.d.ts.map +0 -1
- package/dist/src/mcp-tools/coherence/causal-infer.js +0 -333
- package/dist/src/mcp-tools/coherence/causal-infer.js.map +0 -1
- package/dist/src/mcp-tools/coherence/coherence-check.d.ts +0 -15
- package/dist/src/mcp-tools/coherence/coherence-check.d.ts.map +0 -1
- package/dist/src/mcp-tools/coherence/coherence-check.js +0 -188
- package/dist/src/mcp-tools/coherence/coherence-check.js.map +0 -1
- package/dist/src/mcp-tools/coherence/consensus-verify.d.ts +0 -14
- package/dist/src/mcp-tools/coherence/consensus-verify.d.ts.map +0 -1
- package/dist/src/mcp-tools/coherence/consensus-verify.js +0 -305
- package/dist/src/mcp-tools/coherence/consensus-verify.js.map +0 -1
- package/dist/src/mcp-tools/coherence/memory-gate.d.ts +0 -16
- package/dist/src/mcp-tools/coherence/memory-gate.d.ts.map +0 -1
- package/dist/src/mcp-tools/coherence/memory-gate.js +0 -279
- package/dist/src/mcp-tools/coherence/memory-gate.js.map +0 -1
- package/dist/src/mcp-tools/coherence/quantum-topology.d.ts +0 -15
- package/dist/src/mcp-tools/coherence/quantum-topology.d.ts.map +0 -1
- package/dist/src/mcp-tools/coherence/quantum-topology.js +0 -400
- package/dist/src/mcp-tools/coherence/quantum-topology.js.map +0 -1
- package/dist/src/mcp-tools/coherence/spectral-analyze.d.ts +0 -14
- package/dist/src/mcp-tools/coherence/spectral-analyze.d.ts.map +0 -1
- package/dist/src/mcp-tools/coherence/spectral-analyze.js +0 -312
- package/dist/src/mcp-tools/coherence/spectral-analyze.js.map +0 -1
- package/dist/src/mcp-tools/coherence/types.d.ts +0 -430
- package/dist/src/mcp-tools/coherence/types.d.ts.map +0 -1
- package/dist/src/mcp-tools/coherence/types.js +0 -144
- package/dist/src/mcp-tools/coherence/types.js.map +0 -1
- package/dist/src/mcp-tools/coherence-tools.d.ts +0 -9
- package/dist/src/mcp-tools/coherence-tools.d.ts.map +0 -1
- package/dist/src/mcp-tools/coherence-tools.js +0 -25
- package/dist/src/mcp-tools/coherence-tools.js.map +0 -1
- package/dist/src/mcp-tools/daa-tools.d.ts +0 -13
- package/dist/src/mcp-tools/daa-tools.d.ts.map +0 -1
- package/dist/src/mcp-tools/daa-tools.js +0 -553
- package/dist/src/mcp-tools/daa-tools.js.map +0 -1
|
@@ -234,58 +234,6 @@ html, body { height: 100%; background: var(--bg); color: var(--text-hi); font-fa
|
|
|
234
234
|
.chunk-excerpt { font-size: 12px; color: var(--text-hi); line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
|
|
235
235
|
.chunk-footer { display: flex; align-items: center; gap: 8px; margin-top: 7px; }
|
|
236
236
|
.chunk-ns { font-size: 10px; padding: 1px 6px; border-radius: 8px; background: var(--surface-hi); color: var(--text-lo); }
|
|
237
|
-
/* injection analytics */
|
|
238
|
-
.sb-analytics { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; margin-bottom: 14px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
|
|
239
|
-
.sb-metric { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; display: flex; flex-direction: column; gap: 3px; }
|
|
240
|
-
.sb-metric-val { font-size: 20px; font-weight: 700; color: var(--text-hi); font-family: var(--mono); }
|
|
241
|
-
.sb-metric-lbl { font-size: 10px; color: var(--text-lo); text-transform: uppercase; letter-spacing: 0.07em; }
|
|
242
|
-
.sb-metric-sub { font-size: 10px; color: var(--text-xs); font-family: var(--mono); }
|
|
243
|
-
.sb-sparkline { display: flex; align-items: flex-end; gap: 2px; height: 32px; }
|
|
244
|
-
.sb-spark-bar { min-width: 4px; flex: 1; border-radius: 2px 2px 0 0; transition: height 0.2s; }
|
|
245
|
-
.sb-spark-bar.hit { background: oklch(72% 0.18 145); }
|
|
246
|
-
.sb-spark-bar.miss { background: oklch(55% 0.08 60 / 0.4); }
|
|
247
|
-
.sb-method-bar { display: flex; height: 8px; border-radius: 4px; overflow: hidden; margin-top: 4px; }
|
|
248
|
-
.sb-method-seg { transition: width 0.3s; }
|
|
249
|
-
.sb-score-dist { display: flex; align-items: flex-end; gap: 2px; height: 24px; }
|
|
250
|
-
.sb-score-bar { flex: 1; border-radius: 2px 2px 0 0; background: oklch(72% 0.18 75); min-width: 12px; }
|
|
251
|
-
/* document cards */
|
|
252
|
-
.sb-doc-card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; margin-bottom: 6px; display: flex; align-items: center; gap: 10px; }
|
|
253
|
-
.sb-doc-card:hover { border-color: oklch(72% 0.18 75 / 0.5); }
|
|
254
|
-
.sb-config-panel { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 12px 14px; margin-bottom: 12px; }
|
|
255
|
-
.sb-config-row { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
|
|
256
|
-
.sb-config-row:last-child { margin-bottom: 0; }
|
|
257
|
-
.sb-config-label { font-size: 11px; color: var(--text-lo); min-width: 120px; }
|
|
258
|
-
.sb-config-input { background: var(--bg); border: 1px solid var(--border); border-radius: 4px; padding: 3px 8px; font-size: 12px; color: var(--text-hi); font-family: var(--mono); width: 80px; }
|
|
259
|
-
.sb-config-hint { font-size: 10px; color: var(--text-xs); flex: 1; }
|
|
260
|
-
.sb-tune-badge { display: inline-block; font-size: 10px; padding: 2px 8px; border-radius: 10px; background: oklch(72% 0.18 145 / 0.12); color: oklch(72% 0.18 145); cursor: pointer; }
|
|
261
|
-
.sb-ingest-feed { max-height: 240px; overflow-y: auto; font-size: 11px; }
|
|
262
|
-
.sb-ingest-item { display: flex; align-items: center; gap: 8px; padding: 4px 8px; border-bottom: 1px solid var(--border); animation: sb-fade-in 0.3s ease; }
|
|
263
|
-
.sb-ingest-item.injection { background: oklch(72% 0.18 145 / 0.04); }
|
|
264
|
-
@keyframes sb-fade-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
|
|
265
|
-
.sb-ingest-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
|
|
266
|
-
.sb-ingest-dot.ingest { background: oklch(72% 0.18 200); }
|
|
267
|
-
.sb-ingest-dot.injection { background: oklch(72% 0.18 145); }
|
|
268
|
-
.sb-ingest-dot.miss { background: oklch(72% 0.18 25); }
|
|
269
|
-
.sb-ingest-time { font-size: 9px; color: var(--text-xs); font-family: var(--mono); min-width: 48px; }
|
|
270
|
-
.sb-live-badge { display: inline-flex; align-items: center; gap: 4px; font-size: 9px; color: oklch(72% 0.18 145); text-transform: uppercase; letter-spacing: 0.07em; }
|
|
271
|
-
.sb-live-dot { width: 5px; height: 5px; border-radius: 50%; background: oklch(72% 0.18 145); animation: sb-pulse 1.5s infinite; }
|
|
272
|
-
@keyframes sb-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
|
|
273
|
-
.sb-kg-triplet { display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-bottom: 1px solid var(--border); font-size: 12px; }
|
|
274
|
-
.sb-kg-triplet:hover { background: oklch(72% 0.02 200 / 0.05); }
|
|
275
|
-
.sb-kg-entity { padding: 2px 8px; border-radius: 10px; font-family: var(--mono); font-size: 11px; cursor: pointer; white-space: nowrap; }
|
|
276
|
-
.sb-kg-entity.subject { background: oklch(72% 0.18 200 / 0.12); color: oklch(72% 0.18 200); }
|
|
277
|
-
.sb-kg-entity.object { background: oklch(72% 0.18 145 / 0.12); color: oklch(72% 0.18 145); }
|
|
278
|
-
.sb-kg-rel { font-size: 10px; color: var(--text-lo); font-style: italic; min-width: 60px; text-align: center; }
|
|
279
|
-
.sb-kg-tag { display: inline-block; padding: 1px 6px; border-radius: 8px; font-size: 10px; cursor: pointer; background: var(--surface); border: 1px solid var(--border); color: var(--text-lo); }
|
|
280
|
-
.sb-kg-tag:hover { border-color: var(--accent); color: var(--accent); }
|
|
281
|
-
.sb-doc-icon { font-size: 18px; flex-shrink: 0; width: 28px; text-align: center; }
|
|
282
|
-
.sb-doc-info { flex: 1; min-width: 0; }
|
|
283
|
-
.sb-doc-name { font-size: 12px; font-weight: 600; color: var(--text-hi); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
284
|
-
.sb-doc-path { font-size: 10px; color: var(--text-lo); font-family: var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
285
|
-
.sb-doc-meta { display: flex; gap: 8px; margin-top: 3px; }
|
|
286
|
-
.sb-doc-badge { font-size: 10px; padding: 1px 6px; border-radius: 8px; background: var(--surface-hi); color: var(--text-lo); }
|
|
287
|
-
.sb-doc-badge.global { background: oklch(72% 0.12 200 / 0.15); color: oklch(72% 0.12 200); }
|
|
288
|
-
.sb-doc-badge.missing { background: oklch(60% 0.18 25 / 0.15); color: oklch(60% 0.18 25); }
|
|
289
237
|
/* chunk edit modal */
|
|
290
238
|
#chunk-modal { display: none; position: fixed; inset: 0; z-index: 3000; background: oklch(0% 0 0 / 0.65); align-items: center; justify-content: center; }
|
|
291
239
|
#chunk-modal.open { display: flex; }
|
|
@@ -1955,7 +1903,6 @@ select.pb-cfg-inp { padding: 4px 7px; cursor: pointer; }
|
|
|
1955
1903
|
<canvas id="tok-chart" height="100" style="width:100%;display:block"></canvas>
|
|
1956
1904
|
</div>
|
|
1957
1905
|
<div id="tok-table" style="margin-top:18px"></div>
|
|
1958
|
-
<div id="tok-usage-breakdown" style="margin-top:18px"></div>
|
|
1959
1906
|
</div>
|
|
1960
1907
|
</div>
|
|
1961
1908
|
|
|
@@ -1966,8 +1913,12 @@ select.pb-cfg-inp { padding: 4px 7px; cursor: pointer; }
|
|
|
1966
1913
|
<div class="pg-sub">Knowledge palace — stored facts, graph, identity</div>
|
|
1967
1914
|
<div class="mem-tab-bar" style="display:flex;gap:4px;margin-bottom:14px;border-bottom:1px solid var(--border);padding-bottom:6px">
|
|
1968
1915
|
<button class="odt-btn active" data-memtab="memories" onclick="switchMemTab('memories')">Memories</button>
|
|
1916
|
+
<button class="odt-btn" data-memtab="routing" onclick="switchMemTab('routing')">Routing</button>
|
|
1917
|
+
<button class="odt-btn" data-memtab="usage" onclick="switchMemTab('usage')">Usage</button>
|
|
1969
1918
|
<button class="odt-btn" data-memtab="adrs" onclick="switchMemTab('adrs')">ADRs</button>
|
|
1919
|
+
<button class="odt-btn" data-memtab="swarm" onclick="switchMemTab('swarm')">Swarm</button>
|
|
1970
1920
|
<button class="odt-btn" data-memtab="chunks" onclick="switchMemTab('chunks')">Chunks</button>
|
|
1921
|
+
<button class="odt-btn" data-memtab="agent-graph" onclick="switchMemTab('agent-graph')">Agent Graph</button>
|
|
1971
1922
|
</div>
|
|
1972
1923
|
<div id="mem-tab-memories">
|
|
1973
1924
|
<div class="mem-split" id="mem-split">
|
|
@@ -1980,52 +1931,28 @@ select.pb-cfg-inp { padding: 4px 7px; cursor: pointer; }
|
|
|
1980
1931
|
</div>
|
|
1981
1932
|
<div style="margin-top:10px"><button class="btn" onclick="openNewMemModal()">+ New Memory</button></div>
|
|
1982
1933
|
</div>
|
|
1934
|
+
<div id="mem-tab-routing" style="display:none"><div class="loading-txt">Loading…</div></div>
|
|
1935
|
+
<div id="mem-tab-usage" style="display:none"><div class="loading-txt">Loading…</div></div>
|
|
1983
1936
|
<div id="mem-tab-adrs" style="display:none">
|
|
1984
1937
|
<div class="filter-bar" style="margin-bottom:10px">
|
|
1985
1938
|
<input class="filter-input" id="adr-filter" type="text" placeholder="Filter ADRs…" oninput="filterADRs(this.value)">
|
|
1986
1939
|
</div>
|
|
1987
|
-
<div
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1940
|
+
<div id="adr-content"><div class="loading-txt">Loading…</div></div>
|
|
1941
|
+
</div>
|
|
1942
|
+
<div id="mem-tab-swarm" style="display:none">
|
|
1943
|
+
<div style="display:flex;height:380px;gap:0">
|
|
1944
|
+
<div id="swarm-run-list" style="width:200px;flex-shrink:0;border-right:1px solid var(--border);overflow-y:auto;padding:6px"></div>
|
|
1945
|
+
<div id="swarm-run-detail" style="flex:1;padding:14px;overflow-y:auto">
|
|
1946
|
+
<div style="color:var(--text-lo);font-size:13px">Select a swarm run</div>
|
|
1991
1947
|
</div>
|
|
1992
1948
|
</div>
|
|
1949
|
+
<button class="btn" style="margin-top:10px;color:var(--red);border-color:var(--red)" onclick="cleanSwarmData()">⌫ Clean Data</button>
|
|
1993
1950
|
</div>
|
|
1994
1951
|
<div id="mem-tab-chunks" style="display:none">
|
|
1995
|
-
<div id="sb-analytics" class="sb-analytics" style="display:none">
|
|
1996
|
-
<div class="sb-metric">
|
|
1997
|
-
<div class="sb-metric-val" id="sb-hit-rate">—</div>
|
|
1998
|
-
<div class="sb-metric-lbl">Hit Rate</div>
|
|
1999
|
-
<div class="sb-metric-sub" id="sb-hit-detail"></div>
|
|
2000
|
-
</div>
|
|
2001
|
-
<div class="sb-metric">
|
|
2002
|
-
<div class="sb-metric-val" id="sb-method-val">—</div>
|
|
2003
|
-
<div class="sb-metric-lbl">Method</div>
|
|
2004
|
-
<div class="sb-method-bar" id="sb-method-bar"></div>
|
|
2005
|
-
<div class="sb-metric-sub" id="sb-method-detail"></div>
|
|
2006
|
-
</div>
|
|
2007
|
-
<div class="sb-metric">
|
|
2008
|
-
<div class="sb-metric-val" id="sb-avg-score">—</div>
|
|
2009
|
-
<div class="sb-metric-lbl">Avg Relevance</div>
|
|
2010
|
-
<div class="sb-score-dist" id="sb-score-dist"></div>
|
|
2011
|
-
</div>
|
|
2012
|
-
<div class="sb-metric">
|
|
2013
|
-
<div class="sb-metric-lbl" style="margin-bottom:2px">Injections (24h)</div>
|
|
2014
|
-
<div class="sb-sparkline" id="sb-sparkline"></div>
|
|
2015
|
-
<div class="sb-metric-sub" id="sb-spark-detail"></div>
|
|
2016
|
-
</div>
|
|
2017
|
-
<div class="sb-metric" id="sb-overrides-card" style="display:none">
|
|
2018
|
-
<div class="sb-metric-val" id="sb-overrides-val">0</div>
|
|
2019
|
-
<div class="sb-metric-lbl">Misroutes</div>
|
|
2020
|
-
<div class="sb-metric-sub" id="sb-overrides-detail"></div>
|
|
2021
|
-
</div>
|
|
2022
|
-
</div>
|
|
2023
1952
|
<div class="chunk-stats-bar" id="chunk-stats-bar">
|
|
2024
1953
|
<div class="chunk-stat"><div class="chunk-stat-val" id="chunk-count-val">—</div><div class="chunk-stat-lbl">Chunks</div></div>
|
|
2025
1954
|
<div class="chunk-stat"><div class="chunk-stat-val" id="chunk-skills-val">—</div><div class="chunk-stat-lbl">Skills</div></div>
|
|
2026
1955
|
<div class="chunk-stat"><div class="chunk-stat-val" id="chunk-ns-val">—</div><div class="chunk-stat-lbl">Namespaces</div></div>
|
|
2027
|
-
<div class="chunk-stat"><div class="chunk-stat-val" id="chunk-global-val">—</div><div class="chunk-stat-lbl">Global Brain</div></div>
|
|
2028
|
-
<div class="chunk-stat"><div class="chunk-stat-val" id="chunk-docs-val">—</div><div class="chunk-stat-lbl">Documents</div></div>
|
|
2029
1956
|
<button class="btn chunk-build-btn" id="btn-build-docs" onclick="buildKnowledgeDocs()" title="Index .md/.mdx/.txt/.rst files">⊕ Build Docs</button>
|
|
2030
1957
|
<span class="chunk-build-status" id="chunk-build-status"></span>
|
|
2031
1958
|
</div>
|
|
@@ -2040,73 +1967,19 @@ select.pb-cfg-inp { padding: 4px 7px; cursor: pointer; }
|
|
|
2040
1967
|
<button class="btn" onclick="secondBrainSearch()" title="Semantic search (warm local model)">⌕ Search</button>
|
|
2041
1968
|
</div>
|
|
2042
1969
|
<div id="sb-search-results" style="display:none;margin-bottom:12px"></div>
|
|
2043
|
-
<div
|
|
2044
|
-
<
|
|
2045
|
-
<button class="btn"
|
|
2046
|
-
<button class="btn" id="sb-view-monitor" onclick="switchSBView('monitor')" style="font-size:11px;opacity:0.6">Live Monitor</button>
|
|
2047
|
-
<button class="btn" id="sb-view-config" onclick="switchSBView('config')" style="font-size:11px;opacity:0.6">Config</button>
|
|
2048
|
-
<button class="btn" id="sb-view-kg" onclick="switchSBView('kg')" style="font-size:11px;opacity:0.6">Knowledge Graph</button>
|
|
2049
|
-
</div>
|
|
2050
|
-
<div id="sb-view-chunks-pane">
|
|
2051
|
-
<div class="filter-bar">
|
|
2052
|
-
<input class="filter-input" type="text" placeholder="Filter chunks…" oninput="filterChunks(this.value)">
|
|
2053
|
-
<button class="btn" onclick="_chunksLoaded=false;loadChunksTab()" title="Refresh">↺</button>
|
|
2054
|
-
</div>
|
|
2055
|
-
<div id="chunks-grid"></div>
|
|
2056
|
-
</div>
|
|
2057
|
-
<div id="sb-view-docs-pane" style="display:none">
|
|
2058
|
-
<div class="filter-bar" style="margin-bottom:8px">
|
|
2059
|
-
<input class="filter-input" id="sb-docs-filter" type="text" placeholder="Filter documents…" oninput="filterSBDocs(this.value)">
|
|
2060
|
-
<button class="btn" onclick="_sbDocsLoaded=false;loadSBDocs()" title="Refresh">↺</button>
|
|
2061
|
-
</div>
|
|
2062
|
-
<div id="sb-docs-grid"></div>
|
|
2063
|
-
</div>
|
|
2064
|
-
<div id="sb-view-monitor-pane" style="display:none">
|
|
2065
|
-
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
|
|
2066
|
-
<span class="sb-live-badge" id="sb-live-badge"><span class="sb-live-dot"></span> connecting…</span>
|
|
2067
|
-
<span style="font-size:10px;color:var(--text-xs)" id="sb-monitor-count">0 events</span>
|
|
2068
|
-
<button class="btn" style="margin-left:auto;font-size:10px;padding:2px 8px" onclick="clearIngestFeed()">Clear</button>
|
|
2069
|
-
</div>
|
|
2070
|
-
<div class="sb-ingest-feed" id="sb-ingest-feed">
|
|
2071
|
-
<div style="color:var(--text-xs);font-size:11px;padding:12px;text-align:center">Waiting for ingest or injection events…</div>
|
|
2072
|
-
</div>
|
|
2073
|
-
</div>
|
|
2074
|
-
<div id="sb-view-config-pane" style="display:none">
|
|
2075
|
-
<div class="sb-config-panel">
|
|
2076
|
-
<div style="font-size:12px;font-weight:600;color:var(--text-hi);margin-bottom:10px">Second Brain Configuration</div>
|
|
2077
|
-
<div class="sb-config-row">
|
|
2078
|
-
<span class="sb-config-label">Relevance Floor</span>
|
|
2079
|
-
<input class="sb-config-input" id="sb-cfg-floor" type="number" step="0.05" min="0" max="1" value="0.35">
|
|
2080
|
-
<span class="sb-config-hint">Minimum score for injection (0–1). Lower = more results, higher = stricter.</span>
|
|
2081
|
-
</div>
|
|
2082
|
-
<div class="sb-config-row">
|
|
2083
|
-
<span class="sb-config-label">Injection Limit</span>
|
|
2084
|
-
<input class="sb-config-input" id="sb-cfg-limit" type="number" step="1" min="1" max="20" value="3">
|
|
2085
|
-
<span class="sb-config-hint">Max chunks injected per prompt.</span>
|
|
2086
|
-
</div>
|
|
2087
|
-
<div class="sb-config-row">
|
|
2088
|
-
<button class="btn" onclick="saveSBConfig()" style="font-size:11px">Save</button>
|
|
2089
|
-
<span id="sb-cfg-status" style="font-size:10px;color:var(--text-xs)"></span>
|
|
2090
|
-
<span id="sb-cfg-suggestion" style="margin-left:auto"></span>
|
|
2091
|
-
</div>
|
|
2092
|
-
</div>
|
|
2093
|
-
<div class="sb-config-panel" style="margin-top:10px">
|
|
2094
|
-
<div style="font-size:12px;font-weight:600;color:var(--text-hi);margin-bottom:6px">Auto-Tune</div>
|
|
2095
|
-
<div style="font-size:11px;color:var(--text-lo);margin-bottom:8px">Based on telemetry analysis of your injection history.</div>
|
|
2096
|
-
<div id="sb-tune-result" style="font-size:11px;color:var(--text-xs)">Loading…</div>
|
|
2097
|
-
</div>
|
|
1970
|
+
<div class="filter-bar">
|
|
1971
|
+
<input class="filter-input" type="text" placeholder="Filter chunks…" oninput="filterChunks(this.value)">
|
|
1972
|
+
<button class="btn" onclick="_chunksLoaded=false;loadChunksTab()" title="Refresh">↺</button>
|
|
2098
1973
|
</div>
|
|
2099
|
-
<div id="
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
<
|
|
1974
|
+
<div id="chunks-grid"></div>
|
|
1975
|
+
</div>
|
|
1976
|
+
<div id="mem-tab-agent-graph" style="display:none">
|
|
1977
|
+
<div id="ag-summary-bar" style="display:flex;gap:20px;flex-wrap:wrap;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid var(--border)"></div>
|
|
1978
|
+
<div style="display:flex;gap:0;min-height:280px">
|
|
1979
|
+
<div id="ag-sess-list" style="width:190px;flex-shrink:0;overflow-y:auto;border-right:1px solid var(--border);padding-right:8px"></div>
|
|
1980
|
+
<div id="ag-detail" style="flex:1;padding:0 14px;overflow-y:auto">
|
|
1981
|
+
<div style="color:var(--text-lo);font-size:13px;padding:20px 0">Select a session</div>
|
|
2107
1982
|
</div>
|
|
2108
|
-
<div id="sb-kg-glossary" style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px"></div>
|
|
2109
|
-
<div id="sb-kg-triplets" style="max-height:360px;overflow-y:auto"><div class="loading-txt">Loading…</div></div>
|
|
2110
1983
|
</div>
|
|
2111
1984
|
</div>
|
|
2112
1985
|
</div>
|
|
@@ -3341,59 +3214,11 @@ async function loadTokensView() {
|
|
|
3341
3214
|
'</tbody></table></div>';
|
|
3342
3215
|
} else { table.innerHTML = ''; }
|
|
3343
3216
|
markLiveGlow('view-tokens');
|
|
3344
|
-
loadTokenUsageBreakdown('today');
|
|
3345
3217
|
} catch (_) {
|
|
3346
3218
|
cards.innerHTML = '<div class="loading-txt" style="color:var(--text-lo)">No token data available</div>';
|
|
3347
3219
|
}
|
|
3348
3220
|
}
|
|
3349
3221
|
|
|
3350
|
-
async function loadTokenUsageBreakdown(period) {
|
|
3351
|
-
var el = document.getElementById('tok-usage-breakdown');
|
|
3352
|
-
if (!el) return;
|
|
3353
|
-
try {
|
|
3354
|
-
var data = await apiFetch('/api/token-usage?period=' + enc(period || 'today') + '&dir=' + enc(DIR));
|
|
3355
|
-
var s = data?.summary || data?.tokens?.summary || {};
|
|
3356
|
-
var models = Array.isArray(data?.models) ? data.models : (data?.byModel || []);
|
|
3357
|
-
var tools = Array.isArray(data?.tools) ? data.tools : (data?.topTools || []);
|
|
3358
|
-
var mcps = Array.isArray(data?.mcpServers) ? data.mcpServers : (data?.mcp || []);
|
|
3359
|
-
var categories = Array.isArray(data?.categories) ? data.categories : (data?.activity || []);
|
|
3360
|
-
var projects = Array.isArray(data?.projects) ? data.projects : (data?.topProjects || []);
|
|
3361
|
-
var projRows = projects.map(function(p) {
|
|
3362
|
-
var raw = (p.project && p.project !== '?') ? p.project : (p.name && p.name !== '?' ? p.name : '');
|
|
3363
|
-
var base = String(p.dir || p.path || '').split('/').filter(Boolean).pop() || '';
|
|
3364
|
-
return Object.assign({}, p, { project: raw || base || 'unknown' });
|
|
3365
|
-
});
|
|
3366
|
-
function usageBar(items, valKey, labelKey, color, maxItems) {
|
|
3367
|
-
if (!items.length) return '';
|
|
3368
|
-
var maxVal = Math.max.apply(null, items.slice(0, maxItems).map(function(x) { return Number(x[valKey] || 0); }).concat([0.0001]));
|
|
3369
|
-
return items.slice(0, maxItems).map(function(item) {
|
|
3370
|
-
var pct = Math.round((Number(item[valKey] || 0) / maxVal) * 100);
|
|
3371
|
-
var label = esc(String(item[labelKey] || '—').slice(0, 24));
|
|
3372
|
-
var val = typeof item[valKey] === 'number' && valKey === 'cost' ? '$' + Number(item[valKey]).toFixed(4) : String(item[valKey] || 0);
|
|
3373
|
-
return '<div style="display:flex;align-items:center;gap:8px;padding:3px 0;font-size:12px">' +
|
|
3374
|
-
'<div style="width:130px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-hi);font-family:var(--mono);font-size:11px">' + label + '</div>' +
|
|
3375
|
-
'<div style="flex:1;height:7px;background:var(--border);border-radius:2px;overflow:hidden"><div style="width:' + pct + '%;height:100%;background:' + color + ';border-radius:2px"></div></div>' +
|
|
3376
|
-
'<div style="width:60px;text-align:right;color:var(--text-lo);font-size:11px;font-family:var(--mono)">' + esc(val) + '</div></div>';
|
|
3377
|
-
}).join('');
|
|
3378
|
-
}
|
|
3379
|
-
var cacheEff = s.cacheTokens ? Math.min(100, Math.round(s.cacheTokens / (s.cacheTokens + (Number(s.totalTokensIn) || 0)) * 100)) : null;
|
|
3380
|
-
var html = '';
|
|
3381
|
-
if (cacheEff !== null || s.totalTokensIn != null) {
|
|
3382
|
-
html += '<div style="display:flex;gap:16px;flex-wrap:wrap;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid var(--border)">';
|
|
3383
|
-
if (s.totalTokensIn != null) html += '<div class="chunk-stat"><div class="chunk-stat-val">' + Number(s.totalTokensIn).toLocaleString() + '</div><div class="chunk-stat-lbl">Tokens In</div></div>';
|
|
3384
|
-
if (s.totalTokensOut != null) html += '<div class="chunk-stat"><div class="chunk-stat-val">' + Number(s.totalTokensOut).toLocaleString() + '</div><div class="chunk-stat-lbl">Tokens Out</div></div>';
|
|
3385
|
-
if (cacheEff !== null) html += '<div class="chunk-stat"><div class="chunk-stat-val" style="color:var(--green)">' + cacheEff + '%</div><div class="chunk-stat-lbl">Cache Eff.</div></div>';
|
|
3386
|
-
html += '</div>';
|
|
3387
|
-
}
|
|
3388
|
-
if (models.length) html += '<div class="m-group-title" style="margin-bottom:6px">Models</div><div style="margin-bottom:14px">' + usageBar(models, 'cost', 'model', 'oklch(65% 0.13 290)', 8) + '</div>';
|
|
3389
|
-
if (categories.length) html += '<div class="m-group-title" style="margin-bottom:6px">Activity</div><div style="margin-bottom:14px">' + usageBar(categories, 'turns', 'category', 'var(--accent)', 8) + '</div>';
|
|
3390
|
-
if (tools.length) html += '<div class="m-group-title" style="margin-bottom:6px">Top Tools</div><div style="margin-bottom:14px">' + usageBar(tools, 'count', 'tool', 'oklch(72% 0.18 75)', 10) + '</div>';
|
|
3391
|
-
if (mcps.length) html += '<div class="m-group-title" style="margin-bottom:6px">MCP Servers</div><div style="margin-bottom:14px">' + usageBar(mcps, 'count', 'server', 'oklch(70% 0.18 60)', 8) + '</div>';
|
|
3392
|
-
if (projRows.length) html += '<div class="m-group-title" style="margin-bottom:6px">Projects</div><div style="margin-bottom:14px">' + usageBar(projRows, 'cost', 'project', 'oklch(65% 0.15 150)', 5) + '</div>';
|
|
3393
|
-
el.innerHTML = html || '';
|
|
3394
|
-
} catch (_) { el.innerHTML = ''; }
|
|
3395
|
-
}
|
|
3396
|
-
|
|
3397
3222
|
function renderTokChart(daily, animated = true) {
|
|
3398
3223
|
const canvas = document.getElementById('tok-chart');
|
|
3399
3224
|
if (!canvas || !daily.length) return;
|
|
@@ -3519,7 +3344,6 @@ async function setTokPeriod(btn, period) {
|
|
|
3519
3344
|
'</tbody></table></div>';
|
|
3520
3345
|
} else if (table) { table.innerHTML = ''; }
|
|
3521
3346
|
markLiveGlow('view-tokens');
|
|
3522
|
-
loadTokenUsageBreakdown(period);
|
|
3523
3347
|
// Update topbar badge when showing today's data
|
|
3524
3348
|
if (period === 'today') {
|
|
3525
3349
|
const badge = document.getElementById('topbar-cost');
|
|
@@ -3546,13 +3370,17 @@ function switchMemTab(tab) {
|
|
|
3546
3370
|
_currentMemTab = tab;
|
|
3547
3371
|
document.querySelectorAll('.mem-tab-bar .odt-btn').forEach(b =>
|
|
3548
3372
|
b.classList.toggle('active', b.dataset.memtab === tab));
|
|
3549
|
-
['memories','adrs','chunks'].forEach(t => {
|
|
3373
|
+
['memories','routing','usage','adrs','swarm','chunks','agent-graph'].forEach(t => {
|
|
3550
3374
|
const el = document.getElementById('mem-tab-' + t);
|
|
3551
3375
|
if (el) el.style.display = t === tab ? '' : 'none';
|
|
3552
3376
|
});
|
|
3553
3377
|
if (tab === 'memories') loadMemoriesTab();
|
|
3378
|
+
else if (tab === 'routing') loadMemRouting();
|
|
3379
|
+
else if (tab === 'usage') loadMemUsage();
|
|
3554
3380
|
else if (tab === 'adrs') loadMemADRs();
|
|
3381
|
+
else if (tab === 'swarm') loadSwarmTab();
|
|
3555
3382
|
else if (tab === 'chunks') loadChunksTab();
|
|
3383
|
+
else if (tab === 'agent-graph') loadAgentGraphTab();
|
|
3556
3384
|
}
|
|
3557
3385
|
|
|
3558
3386
|
async function loadMemRouting() {
|
|
@@ -3714,12 +3542,12 @@ function renderADRs(list) {
|
|
|
3714
3542
|
const pane = document.getElementById('adr-content');
|
|
3715
3543
|
if (!pane) return;
|
|
3716
3544
|
if (!list.length) { pane.innerHTML = '<div class="empty">No ADRs found</div>'; return; }
|
|
3717
|
-
pane.innerHTML = list.slice(0, 50).map(
|
|
3545
|
+
pane.innerHTML = list.slice(0, 50).map(a => `<div style="padding:8px 0;border-bottom:1px solid var(--border)">
|
|
3718
3546
|
<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:3px">
|
|
3719
|
-
<span style="color:var(--text-hi);font-size:
|
|
3720
|
-
<span class="ss-pill ${a.status === 'accepted'
|
|
3547
|
+
<span style="color:var(--text-hi);font-size:12px;font-family:monospace">${esc(a.id || a.title || '—')}</span>
|
|
3548
|
+
<span class="ss-pill ${a.status === 'accepted' ? 'on' : a.status === 'deprecated' ? 'warn' : ''}">${esc(a.status || '?')}</span>
|
|
3721
3549
|
</div>
|
|
3722
|
-
<div style="font-size:
|
|
3550
|
+
<div style="font-size:11px;color:var(--text-lo)">${esc((a.context || a.summary || '').slice(0, 120))}</div>
|
|
3723
3551
|
</div>`).join('');
|
|
3724
3552
|
}
|
|
3725
3553
|
|
|
@@ -3733,65 +3561,6 @@ function filterADRs(q) {
|
|
|
3733
3561
|
renderADRs(filtered);
|
|
3734
3562
|
}
|
|
3735
3563
|
|
|
3736
|
-
async function viewADR(idx) {
|
|
3737
|
-
var adr = _allADRs[idx];
|
|
3738
|
-
if (!adr || !adr.file) return;
|
|
3739
|
-
var viewer = document.getElementById('adr-viewer');
|
|
3740
|
-
if (!viewer) return;
|
|
3741
|
-
viewer.innerHTML = '<div class="loading-txt">Loading…</div>';
|
|
3742
|
-
// Highlight selected
|
|
3743
|
-
document.querySelectorAll('#adr-content .adr-item').forEach(function(el, i) {
|
|
3744
|
-
el.style.background = i === idx ? 'oklch(72% 0.02 200 / 0.08)' : '';
|
|
3745
|
-
el.style.borderLeft = i === idx ? '2px solid var(--accent)' : '';
|
|
3746
|
-
});
|
|
3747
|
-
try {
|
|
3748
|
-
var data = await apiFetch('/api/adr-file?file=' + enc(adr.file) + '&dir=' + enc(DIR));
|
|
3749
|
-
var md = data.content || '';
|
|
3750
|
-
viewer.innerHTML = '<div style="font-family:var(--mono);font-size:12px;line-height:1.7;white-space:pre-wrap;color:var(--text-hi);overflow-x:auto">' + _renderMd(md) + '</div>';
|
|
3751
|
-
} catch (e) {
|
|
3752
|
-
viewer.innerHTML = '<div class="empty">Failed: ' + esc(e.message) + '</div>';
|
|
3753
|
-
}
|
|
3754
|
-
}
|
|
3755
|
-
|
|
3756
|
-
function _renderMd(md) {
|
|
3757
|
-
var lines = md.split('\n');
|
|
3758
|
-
var html = [];
|
|
3759
|
-
var inCode = false, codeLang = '';
|
|
3760
|
-
for (var i = 0; i < lines.length; i++) {
|
|
3761
|
-
var line = lines[i];
|
|
3762
|
-
if (line.startsWith('```')) {
|
|
3763
|
-
if (!inCode) { inCode = true; codeLang = line.slice(3).trim(); html.push('<div style="background:var(--bg);border:1px solid var(--border);border-radius:4px;padding:8px 10px;margin:6px 0;overflow-x:auto;font-size:11px">'); continue; }
|
|
3764
|
-
else { inCode = false; html.push('</div>'); continue; }
|
|
3765
|
-
}
|
|
3766
|
-
if (inCode) { html.push(esc(line) + '\n'); continue; }
|
|
3767
|
-
if (/^#{1,6}\s/.test(line)) {
|
|
3768
|
-
var lvl = line.match(/^(#{1,6})/)[1].length;
|
|
3769
|
-
var text = line.replace(/^#{1,6}\s+/, '');
|
|
3770
|
-
var sizes = { 1: '16px', 2: '14px', 3: '13px', 4: '12px', 5: '12px', 6: '11px' };
|
|
3771
|
-
html.push('<div style="font-size:' + (sizes[lvl] || '12px') + ';font-weight:700;color:var(--accent);margin:' + (lvl <= 2 ? '16px' : '10px') + ' 0 4px 0">' + esc(text) + '</div>');
|
|
3772
|
-
} else if (/^\|/.test(line)) {
|
|
3773
|
-
if (/^\|[\s-:|]+\|$/.test(line)) continue;
|
|
3774
|
-
var cells = line.split('|').slice(1, -1).map(function(c) { return c.trim(); });
|
|
3775
|
-
html.push('<div style="display:flex;gap:0;border-bottom:1px solid var(--border)">' + cells.map(function(c) {
|
|
3776
|
-
return '<div style="flex:1;padding:2px 6px;font-size:11px">' + esc(c) + '</div>';
|
|
3777
|
-
}).join('') + '</div>');
|
|
3778
|
-
} else if (/^[-*]\s/.test(line)) {
|
|
3779
|
-
var indent = line.match(/^(\s*)/)[1].length;
|
|
3780
|
-
html.push('<div style="padding-left:' + (indent + 12) + 'px;position:relative"><span style="position:absolute;left:' + indent + 'px;color:var(--text-xs)">•</span>' + esc(line.replace(/^\s*[-*]\s/, '')) + '</div>');
|
|
3781
|
-
} else if (/^\d+\.\s/.test(line)) {
|
|
3782
|
-
var num = line.match(/^(\d+)\./)[1];
|
|
3783
|
-
html.push('<div style="padding-left:16px;position:relative"><span style="position:absolute;left:0;color:var(--text-xs)">' + num + '.</span>' + esc(line.replace(/^\d+\.\s/, '')) + '</div>');
|
|
3784
|
-
} else if (line.trim() === '') {
|
|
3785
|
-
html.push('<div style="height:6px"></div>');
|
|
3786
|
-
} else {
|
|
3787
|
-
var styled = esc(line).replace(/\*\*([^*]+)\*\*/g, '<b style="color:var(--text-hi)">$1</b>').replace(/`([^`]+)`/g, '<code style="background:var(--bg);padding:1px 4px;border-radius:3px;font-size:11px">$1</code>');
|
|
3788
|
-
html.push('<div>' + styled + '</div>');
|
|
3789
|
-
}
|
|
3790
|
-
}
|
|
3791
|
-
if (inCode) html.push('</div>');
|
|
3792
|
-
return html.join('\n');
|
|
3793
|
-
}
|
|
3794
|
-
|
|
3795
3564
|
function renderMiniSessions(sessions) {
|
|
3796
3565
|
if (!sessions.length) return;
|
|
3797
3566
|
const items = sessions.map((s, i) => `
|
|
@@ -13622,55 +13391,27 @@ async function secondBrainSearch() {
|
|
|
13622
13391
|
box.innerHTML = '<div class="loading-txt">Searching…</div>';
|
|
13623
13392
|
try {
|
|
13624
13393
|
const scopeSel = document.getElementById('sb-search-scope');
|
|
13625
|
-
const
|
|
13626
|
-
|
|
13627
|
-
|
|
13628
|
-
|
|
13629
|
-
|
|
13630
|
-
}),
|
|
13631
|
-
fetch('/api/second-brain-route', {
|
|
13632
|
-
method: 'POST',
|
|
13633
|
-
headers: { 'Content-Type': 'application/json' },
|
|
13634
|
-
body: JSON.stringify({ query: q }),
|
|
13635
|
-
}).catch(function() { return null; }),
|
|
13636
|
-
]);
|
|
13394
|
+
const r = await fetch('/api/knowledge/search', {
|
|
13395
|
+
method: 'POST',
|
|
13396
|
+
headers: { 'Content-Type': 'application/json' },
|
|
13397
|
+
body: JSON.stringify({ query: q, limit: 5, scope: scopeSel ? scopeSel.value : 'all' }),
|
|
13398
|
+
});
|
|
13637
13399
|
if (!r.ok) throw new Error('HTTP ' + r.status);
|
|
13638
13400
|
const data = await r.json();
|
|
13639
|
-
var routeData = null;
|
|
13640
|
-
if (routeR && routeR.ok) { try { routeData = await routeR.json(); } catch(_) {} }
|
|
13641
13401
|
const results = data.results || [];
|
|
13642
|
-
// Route inspector bar
|
|
13643
|
-
var routeHtml = '';
|
|
13644
|
-
if (routeData && routeData.route) {
|
|
13645
|
-
var rd = routeData.route;
|
|
13646
|
-
var surfaces = ['chunks', 'kg', 'rules', 'memory'];
|
|
13647
|
-
var surfaceColors = { chunks: 'oklch(72% 0.18 145)', kg: 'oklch(72% 0.18 280)', rules: 'oklch(72% 0.18 75)', memory: 'oklch(72% 0.18 30)' };
|
|
13648
|
-
routeHtml = '<div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:8px 10px;margin-bottom:8px">' +
|
|
13649
|
-
'<div style="font-size:10px;letter-spacing:0.07em;text-transform:uppercase;color:var(--text-xs);margin-bottom:5px">Route Decision' +
|
|
13650
|
-
(rd.confident ? ' <span style="color:oklch(72% 0.18 145)">confident</span>' : ' <span style="color:oklch(72% 0.18 75)">low-confidence (all surfaces queried)</span>') +
|
|
13651
|
-
'</div>' +
|
|
13652
|
-
'<div style="display:flex;gap:8px;flex-wrap:wrap">' +
|
|
13653
|
-
surfaces.map(function(s) {
|
|
13654
|
-
var score = rd.scores[s] || 0;
|
|
13655
|
-
var active = rd.surfaces.indexOf(s) !== -1;
|
|
13656
|
-
return '<div style="font-size:11px;padding:3px 8px;border-radius:6px;border:1px solid ' +
|
|
13657
|
-
(active ? surfaceColors[s] : 'var(--border)') + ';color:' +
|
|
13658
|
-
(active ? surfaceColors[s] : 'var(--text-lo)') + ';background:' +
|
|
13659
|
-
(active ? surfaceColors[s].replace(')', ' / 0.1)') : 'transparent') + '">' +
|
|
13660
|
-
s + ' <span style="font-family:var(--mono);font-weight:600">' + score.toFixed(1) + '</span></div>';
|
|
13661
|
-
}).join('') +
|
|
13662
|
-
'</div></div>';
|
|
13663
|
-
}
|
|
13664
13402
|
if (!results.length) {
|
|
13665
|
-
box.innerHTML =
|
|
13403
|
+
box.innerHTML = '<div class="empty" style="padding:10px">No matches (' + esc(data.method || '?') + '). Ingest documents with: <code>monomind doc ingest ./path</code></div>';
|
|
13666
13404
|
return;
|
|
13667
13405
|
}
|
|
13668
|
-
box.innerHTML =
|
|
13406
|
+
box.innerHTML =
|
|
13669
13407
|
'<div style="font-size:10px;letter-spacing:0.07em;text-transform:uppercase;color:var(--text-xs);margin-bottom:6px">' +
|
|
13670
13408
|
results.length + ' result(s) · ' + esc(data.method || '') + '</div>' +
|
|
13671
13409
|
results.map(function (res) {
|
|
13672
13410
|
var srcTag = (res.tags || []).find(function (t) { return t.indexOf('src:') === 0; });
|
|
13673
13411
|
var label = srcTag ? srcTag.slice(4).split('/').slice(-2).join('/') : (res.key || '');
|
|
13412
|
+
// Surface badge: the endpoint fuses chunks + KG triplets + rules +
|
|
13413
|
+
// pattern memories (RRF); show non-chunk kinds so users see where a
|
|
13414
|
+
// hit came from.
|
|
13674
13415
|
var kindBadge = res.triplet ? 'kg' : (res.rule ? 'rule' : (res.memory ? 'memory' : ''));
|
|
13675
13416
|
return '<div style="border:1px solid var(--border);border-radius:8px;padding:8px 10px;margin-bottom:6px">' +
|
|
13676
13417
|
'<div style="font-size:10px;color:var(--text-lo);margin-bottom:3px">' + esc(label) +
|
|
@@ -13690,7 +13431,6 @@ async function loadChunksTab() {
|
|
|
13690
13431
|
const grid = document.getElementById('chunks-grid');
|
|
13691
13432
|
if (!grid) return;
|
|
13692
13433
|
grid.innerHTML = '<div class="loading-txt">Loading…</div>';
|
|
13693
|
-
loadSBAnalytics();
|
|
13694
13434
|
try {
|
|
13695
13435
|
const data = await apiFetch('/api/section?name=knowledge&full=1&dir=' + enc(DIR));
|
|
13696
13436
|
// /api/section returns {"knowledge":{"chunks":N,"allChunks":[...]}} — extract the array
|
|
@@ -13706,310 +13446,6 @@ async function loadChunksTab() {
|
|
|
13706
13446
|
}
|
|
13707
13447
|
}
|
|
13708
13448
|
|
|
13709
|
-
async function loadSBAnalytics() {
|
|
13710
|
-
// Populate global brain & doc counts in parallel
|
|
13711
|
-
try {
|
|
13712
|
-
var docsData = await apiFetch('/api/second-brain-docs');
|
|
13713
|
-
var gEl = document.getElementById('chunk-global-val');
|
|
13714
|
-
var dEl = document.getElementById('chunk-docs-val');
|
|
13715
|
-
if (gEl) gEl.textContent = (docsData.globalCount || 0).toLocaleString();
|
|
13716
|
-
if (dEl) dEl.textContent = (docsData.totalDocs || 0).toLocaleString();
|
|
13717
|
-
} catch (_) {}
|
|
13718
|
-
try {
|
|
13719
|
-
const data = await apiFetch('/api/second-brain-metrics');
|
|
13720
|
-
if (!data || data.total === 0) return;
|
|
13721
|
-
const el = document.getElementById('sb-analytics');
|
|
13722
|
-
if (el) el.style.display = '';
|
|
13723
|
-
// Hit rate
|
|
13724
|
-
const hrEl = document.getElementById('sb-hit-rate');
|
|
13725
|
-
if (hrEl) hrEl.textContent = (data.hitRate * 100).toFixed(1) + '%';
|
|
13726
|
-
const hdEl = document.getElementById('sb-hit-detail');
|
|
13727
|
-
if (hdEl) hdEl.textContent = data.injected + '/' + data.total + ' prompts';
|
|
13728
|
-
// Method distribution
|
|
13729
|
-
const mvEl = document.getElementById('sb-method-val');
|
|
13730
|
-
const mbEl = document.getElementById('sb-method-bar');
|
|
13731
|
-
const mdEl = document.getElementById('sb-method-detail');
|
|
13732
|
-
const methods = data.methods || {};
|
|
13733
|
-
const semCount = methods.semantic || 0;
|
|
13734
|
-
const kwCount = methods.keyword || 0;
|
|
13735
|
-
const totalMethods = semCount + kwCount + (methods.unknown || 0) + (methods.mixed || 0);
|
|
13736
|
-
if (mvEl) mvEl.textContent = totalMethods > 0 && semCount > kwCount ? 'Semantic' : (kwCount > 0 ? 'Keyword' : '—');
|
|
13737
|
-
if (mbEl && totalMethods > 0) {
|
|
13738
|
-
const semPct = (semCount / totalMethods * 100).toFixed(0);
|
|
13739
|
-
const kwPct = (kwCount / totalMethods * 100).toFixed(0);
|
|
13740
|
-
mbEl.innerHTML = '<div class="sb-method-seg" style="width:' + semPct + '%;background:oklch(72% 0.18 145)" title="Semantic ' + semPct + '%"></div>' +
|
|
13741
|
-
'<div class="sb-method-seg" style="width:' + kwPct + '%;background:oklch(72% 0.18 75)" title="Keyword ' + kwPct + '%"></div>';
|
|
13742
|
-
}
|
|
13743
|
-
if (mdEl) mdEl.textContent = semCount + ' semantic · ' + kwCount + ' keyword';
|
|
13744
|
-
// Average score
|
|
13745
|
-
const asEl = document.getElementById('sb-avg-score');
|
|
13746
|
-
if (asEl) asEl.textContent = data.avgScore > 0 ? data.avgScore.toFixed(2) : '—';
|
|
13747
|
-
// Score distribution
|
|
13748
|
-
const sdEl = document.getElementById('sb-score-dist');
|
|
13749
|
-
if (sdEl && data.scoreBuckets) {
|
|
13750
|
-
const maxB = Math.max(...data.scoreBuckets, 1);
|
|
13751
|
-
const labels = ['<0.3', '0.3–0.5', '0.5–0.7', '0.7–0.9', '0.9+'];
|
|
13752
|
-
sdEl.innerHTML = data.scoreBuckets.map(function(v, i) {
|
|
13753
|
-
return '<div class="sb-score-bar" style="height:' + Math.max(2, v / maxB * 24) + 'px" title="' + labels[i] + ': ' + v + '"></div>';
|
|
13754
|
-
}).join('');
|
|
13755
|
-
}
|
|
13756
|
-
// Sparkline
|
|
13757
|
-
const slEl = document.getElementById('sb-sparkline');
|
|
13758
|
-
if (slEl && data.sparkline && data.sparkline.length > 0) {
|
|
13759
|
-
const maxS = Math.max(...data.sparkline.map(function(b) { return b.total; }), 1);
|
|
13760
|
-
slEl.innerHTML = data.sparkline.map(function(b) {
|
|
13761
|
-
if (b.total === 0) return '<div class="sb-spark-bar" style="height:1px;background:var(--border)"></div>';
|
|
13762
|
-
var hitH = Math.max(2, b.injected / maxS * 32);
|
|
13763
|
-
var missH = Math.max(0, (b.total - b.injected) / maxS * 32);
|
|
13764
|
-
return '<div style="display:flex;flex-direction:column;gap:1px;flex:1;align-items:stretch">' +
|
|
13765
|
-
(missH > 0 ? '<div class="sb-spark-bar miss" style="height:' + missH + 'px"></div>' : '') +
|
|
13766
|
-
'<div class="sb-spark-bar hit" style="height:' + hitH + 'px"></div></div>';
|
|
13767
|
-
}).join('');
|
|
13768
|
-
}
|
|
13769
|
-
const spEl = document.getElementById('sb-spark-detail');
|
|
13770
|
-
if (spEl) {
|
|
13771
|
-
var recent24 = data.sparkline ? data.sparkline.reduce(function(a, b) { return { total: a.total + b.total, injected: a.injected + b.injected }; }, { total: 0, injected: 0 }) : { total: 0, injected: 0 };
|
|
13772
|
-
spEl.textContent = recent24.injected + ' hits / ' + recent24.total + ' queries';
|
|
13773
|
-
}
|
|
13774
|
-
// Route overrides (misroutes)
|
|
13775
|
-
var overrides = data.routeOverrides || {};
|
|
13776
|
-
var overrideKeys = Object.keys(overrides);
|
|
13777
|
-
if (overrideKeys.length > 0) {
|
|
13778
|
-
var ocEl = document.getElementById('sb-overrides-card');
|
|
13779
|
-
var ovEl = document.getElementById('sb-overrides-val');
|
|
13780
|
-
var odEl = document.getElementById('sb-overrides-detail');
|
|
13781
|
-
if (ocEl) ocEl.style.display = '';
|
|
13782
|
-
var totalOverrides = overrideKeys.reduce(function(s, k) { return s + overrides[k]; }, 0);
|
|
13783
|
-
if (ovEl) ovEl.textContent = totalOverrides;
|
|
13784
|
-
if (odEl) odEl.textContent = overrideKeys.slice(0, 3).map(function(k) { return k + ': ' + overrides[k]; }).join(', ');
|
|
13785
|
-
}
|
|
13786
|
-
} catch (_) {}
|
|
13787
|
-
}
|
|
13788
|
-
|
|
13789
|
-
var _sbDocsLoaded = false;
|
|
13790
|
-
var _sbDocs = [];
|
|
13791
|
-
function switchSBView(view) {
|
|
13792
|
-
var panes = ['chunks', 'docs', 'monitor', 'config', 'kg'];
|
|
13793
|
-
panes.forEach(function(p) {
|
|
13794
|
-
var pane = document.getElementById('sb-view-' + p + '-pane');
|
|
13795
|
-
var btn = document.getElementById('sb-view-' + p);
|
|
13796
|
-
if (pane) pane.style.display = p === view ? '' : 'none';
|
|
13797
|
-
if (btn) {
|
|
13798
|
-
if (p === view) { btn.style.borderColor = 'var(--accent)'; btn.style.color = 'var(--accent)'; btn.style.opacity = '1'; btn.style.fontWeight = '600'; }
|
|
13799
|
-
else { btn.style.borderColor = ''; btn.style.color = ''; btn.style.opacity = '0.6'; btn.style.fontWeight = ''; }
|
|
13800
|
-
}
|
|
13801
|
-
});
|
|
13802
|
-
if (view === 'docs') loadSBDocs();
|
|
13803
|
-
if (view === 'monitor') startIngestStream();
|
|
13804
|
-
if (view === 'config') loadSBConfig();
|
|
13805
|
-
if (view === 'kg') loadSBKnowledgeGraph();
|
|
13806
|
-
}
|
|
13807
|
-
|
|
13808
|
-
async function loadSBDocs() {
|
|
13809
|
-
if (_sbDocsLoaded) return;
|
|
13810
|
-
var grid = document.getElementById('sb-docs-grid');
|
|
13811
|
-
if (!grid) return;
|
|
13812
|
-
grid.innerHTML = '<div class="loading-txt">Loading…</div>';
|
|
13813
|
-
try {
|
|
13814
|
-
var data = await apiFetch('/api/second-brain-docs');
|
|
13815
|
-
_sbDocs = data.docs || [];
|
|
13816
|
-
_sbDocsLoaded = true;
|
|
13817
|
-
_renderSBDocs(_sbDocs);
|
|
13818
|
-
} catch (e) {
|
|
13819
|
-
grid.innerHTML = '<div class="empty">Failed: ' + esc(e.message) + '</div>';
|
|
13820
|
-
}
|
|
13821
|
-
}
|
|
13822
|
-
|
|
13823
|
-
function _renderSBDocs(list) {
|
|
13824
|
-
var grid = document.getElementById('sb-docs-grid');
|
|
13825
|
-
if (!grid) return;
|
|
13826
|
-
if (!list.length) {
|
|
13827
|
-
grid.innerHTML = '<div class="empty">No documents indexed.<br><span style="font-size:11px;color:var(--text-xs)">Run <code>monomind doc ingest ./path</code> to add documents.</span></div>';
|
|
13828
|
-
return;
|
|
13829
|
-
}
|
|
13830
|
-
var extIcons = { '.pdf': '\u{1F4C4}', '.md': '\u{1F4DD}', '.txt': '\u{1F4C3}', '.docx': '\u{1F4D1}', '.mdx': '\u{1F4DD}', '.rst': '\u{1F4C3}' };
|
|
13831
|
-
grid.innerHTML = '<div style="font-size:10px;letter-spacing:0.07em;text-transform:uppercase;color:var(--text-xs);margin-bottom:6px">' + list.length + ' document(s)</div>' +
|
|
13832
|
-
list.map(function(d) {
|
|
13833
|
-
var ext = (d.filePath || '').split('.').pop();
|
|
13834
|
-
var icon = extIcons['.' + ext] || '\u{1F4C4}';
|
|
13835
|
-
var size = d.size > 1048576 ? (d.size / 1048576).toFixed(1) + ' MB' : (d.size > 1024 ? (d.size / 1024).toFixed(0) + ' KB' : d.size + ' B');
|
|
13836
|
-
var ago = d.indexedAt ? _timeAgo(d.indexedAt) : '';
|
|
13837
|
-
return '<div class="sb-doc-card" data-search="' + esc((d.name + ' ' + d.filePath).toLowerCase()) + '">' +
|
|
13838
|
-
'<div class="sb-doc-icon">' + icon + '</div>' +
|
|
13839
|
-
'<div class="sb-doc-info">' +
|
|
13840
|
-
'<div class="sb-doc-name">' + esc(d.name || '—') + '</div>' +
|
|
13841
|
-
'<div class="sb-doc-path">' + esc(d.filePath || '') + '</div>' +
|
|
13842
|
-
'<div class="sb-doc-meta">' +
|
|
13843
|
-
'<span class="sb-doc-badge">' + d.chunkCount + ' chunks</span>' +
|
|
13844
|
-
'<span class="sb-doc-badge">' + size + '</span>' +
|
|
13845
|
-
(d.brainScope === 'global' ? '<span class="sb-doc-badge global">global</span>' : '') +
|
|
13846
|
-
(!d.exists ? '<span class="sb-doc-badge missing">file missing</span>' : '') +
|
|
13847
|
-
(ago ? '<span class="sb-doc-badge">' + ago + '</span>' : '') +
|
|
13848
|
-
'</div>' +
|
|
13849
|
-
'</div></div>';
|
|
13850
|
-
}).join('');
|
|
13851
|
-
}
|
|
13852
|
-
|
|
13853
|
-
function _timeAgo(iso) {
|
|
13854
|
-
var diff = Date.now() - new Date(iso).getTime();
|
|
13855
|
-
if (diff < 3600000) return Math.floor(diff / 60000) + 'm ago';
|
|
13856
|
-
if (diff < 86400000) return Math.floor(diff / 3600000) + 'h ago';
|
|
13857
|
-
return Math.floor(diff / 86400000) + 'd ago';
|
|
13858
|
-
}
|
|
13859
|
-
|
|
13860
|
-
function filterSBDocs(val) {
|
|
13861
|
-
var cards = document.querySelectorAll('#sb-docs-grid .sb-doc-card');
|
|
13862
|
-
var q = (val || '').toLowerCase();
|
|
13863
|
-
cards.forEach(function(c) { c.style.display = !q || (c.dataset.search || '').includes(q) ? '' : 'none'; });
|
|
13864
|
-
}
|
|
13865
|
-
|
|
13866
|
-
// --- Live Ingest Monitor (SSE) ---
|
|
13867
|
-
var _ingestStream = null;
|
|
13868
|
-
var _ingestEventCount = 0;
|
|
13869
|
-
function startIngestStream() {
|
|
13870
|
-
if (_ingestStream) return;
|
|
13871
|
-
var badge = document.getElementById('sb-live-badge');
|
|
13872
|
-
try {
|
|
13873
|
-
_ingestStream = window.mmEventSource ? window.mmEventSource('/api/second-brain-ingest-stream') : new EventSource('/api/second-brain-ingest-stream');
|
|
13874
|
-
_ingestStream.onopen = function() { if (badge) badge.innerHTML = '<span class="sb-live-dot"></span> live'; };
|
|
13875
|
-
_ingestStream.onmessage = function(ev) {
|
|
13876
|
-
try {
|
|
13877
|
-
var d = JSON.parse(ev.data);
|
|
13878
|
-
if (d.type === 'connected') { if (badge) badge.innerHTML = '<span class="sb-live-dot"></span> live'; return; }
|
|
13879
|
-
_ingestEventCount++;
|
|
13880
|
-
var countEl = document.getElementById('sb-monitor-count');
|
|
13881
|
-
if (countEl) countEl.textContent = _ingestEventCount + ' events';
|
|
13882
|
-
var feed = document.getElementById('sb-ingest-feed');
|
|
13883
|
-
if (!feed) return;
|
|
13884
|
-
if (_ingestEventCount === 1) feed.innerHTML = '';
|
|
13885
|
-
var item = document.createElement('div');
|
|
13886
|
-
item.className = 'sb-ingest-item' + (d.type === 'injection' ? ' injection' : '');
|
|
13887
|
-
var now = new Date();
|
|
13888
|
-
var timeStr = now.getHours().toString().padStart(2, '0') + ':' + now.getMinutes().toString().padStart(2, '0') + ':' + now.getSeconds().toString().padStart(2, '0');
|
|
13889
|
-
if (d.type === 'ingest') {
|
|
13890
|
-
item.innerHTML = '<span class="sb-ingest-dot ingest"></span><span class="sb-ingest-time">' + timeStr + '</span>' +
|
|
13891
|
-
'<span style="flex:1">' + esc(d.doc.name || '—') + ' <span style="color:var(--text-xs)">' + (d.doc.chunkCount || '?') + ' chunks</span></span>' +
|
|
13892
|
-
(d.doc.brainScope === 'global' ? '<span class="sb-doc-badge global" style="font-size:9px">global</span>' : '');
|
|
13893
|
-
} else if (d.type === 'injection') {
|
|
13894
|
-
var iev = d.event || {};
|
|
13895
|
-
item.innerHTML = '<span class="sb-ingest-dot ' + (iev.injected ? 'injection' : 'miss') + '"></span><span class="sb-ingest-time">' + timeStr + '</span>' +
|
|
13896
|
-
'<span style="flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + (iev.injected ? 'Injected' : 'Miss') + ' — ' + esc((iev.terms || []).join(' ').slice(0, 60)) + '</span>' +
|
|
13897
|
-
'<span style="font-family:var(--mono);font-size:10px;color:var(--text-xs)">' + (iev.topScore != null ? iev.topScore.toFixed(2) : '—') + '</span>' +
|
|
13898
|
-
'<span style="font-size:9px;padding:1px 5px;border-radius:8px;background:oklch(72% 0.18 ' + (iev.method === 'semantic' ? '145' : '75') + ' / 0.1);color:oklch(72% 0.18 ' + (iev.method === 'semantic' ? '145' : '75') + ')">' + (iev.method || '?') + '</span>';
|
|
13899
|
-
}
|
|
13900
|
-
feed.prepend(item);
|
|
13901
|
-
while (feed.children.length > 100) feed.removeChild(feed.lastChild);
|
|
13902
|
-
} catch (_) {}
|
|
13903
|
-
};
|
|
13904
|
-
_ingestStream.onerror = function() { if (badge) badge.innerHTML = '<span class="sb-live-dot" style="background:oklch(72% 0.18 25)"></span> disconnected'; };
|
|
13905
|
-
} catch (_) { if (badge) badge.innerHTML = 'unavailable'; }
|
|
13906
|
-
}
|
|
13907
|
-
function clearIngestFeed() {
|
|
13908
|
-
_ingestEventCount = 0;
|
|
13909
|
-
var feed = document.getElementById('sb-ingest-feed');
|
|
13910
|
-
if (feed) feed.innerHTML = '<div style="color:var(--text-xs);font-size:11px;padding:12px;text-align:center">Waiting for ingest or injection events…</div>';
|
|
13911
|
-
var countEl = document.getElementById('sb-monitor-count');
|
|
13912
|
-
if (countEl) countEl.textContent = '0 events';
|
|
13913
|
-
}
|
|
13914
|
-
|
|
13915
|
-
// --- Config / Auto-Tune Panel ---
|
|
13916
|
-
var _sbConfigLoaded = false;
|
|
13917
|
-
async function loadSBConfig() {
|
|
13918
|
-
if (_sbConfigLoaded) return;
|
|
13919
|
-
try {
|
|
13920
|
-
var data = await apiFetch('/api/second-brain-config');
|
|
13921
|
-
_sbConfigLoaded = true;
|
|
13922
|
-
var cfg = data.config || {};
|
|
13923
|
-
var floorEl = document.getElementById('sb-cfg-floor');
|
|
13924
|
-
var limitEl = document.getElementById('sb-cfg-limit');
|
|
13925
|
-
if (floorEl) floorEl.value = cfg.relevanceFloor != null ? cfg.relevanceFloor : 0.35;
|
|
13926
|
-
if (limitEl) limitEl.value = cfg.injectionLimit != null ? cfg.injectionLimit : 5;
|
|
13927
|
-
var tuneEl = document.getElementById('sb-tune-result');
|
|
13928
|
-
if (data.suggestion) {
|
|
13929
|
-
var s = data.suggestion;
|
|
13930
|
-
if (tuneEl) tuneEl.innerHTML = '<span class="sb-tune-badge" onclick="applySBSuggestion(' + s.floor + ')" title="Click to apply">Suggested floor: ' + s.floor + '</span> ' +
|
|
13931
|
-
'<span style="color:var(--text-lo);margin-left:6px">' + esc(s.reason) + '</span>';
|
|
13932
|
-
} else {
|
|
13933
|
-
if (tuneEl) tuneEl.textContent = 'Not enough data for a suggestion (need 20+ entries) or current settings are optimal.';
|
|
13934
|
-
}
|
|
13935
|
-
} catch (e) {
|
|
13936
|
-
var tuneErr = document.getElementById('sb-tune-result');
|
|
13937
|
-
if (tuneErr) tuneErr.textContent = 'Failed: ' + e.message;
|
|
13938
|
-
}
|
|
13939
|
-
}
|
|
13940
|
-
function applySBSuggestion(floor) {
|
|
13941
|
-
var el = document.getElementById('sb-cfg-floor');
|
|
13942
|
-
if (el) el.value = floor;
|
|
13943
|
-
saveSBConfig();
|
|
13944
|
-
}
|
|
13945
|
-
async function saveSBConfig() {
|
|
13946
|
-
var statusEl = document.getElementById('sb-cfg-status');
|
|
13947
|
-
var floor = parseFloat(document.getElementById('sb-cfg-floor').value);
|
|
13948
|
-
var limit = parseInt(document.getElementById('sb-cfg-limit').value, 10);
|
|
13949
|
-
if (isNaN(floor) || floor < 0 || floor > 1) { if (statusEl) statusEl.textContent = 'Invalid floor (0–1)'; return; }
|
|
13950
|
-
if (isNaN(limit) || limit < 1) { if (statusEl) statusEl.textContent = 'Invalid limit'; return; }
|
|
13951
|
-
try {
|
|
13952
|
-
if (statusEl) statusEl.textContent = 'Saving…';
|
|
13953
|
-
var resp = await fetch('/api/second-brain-config', {
|
|
13954
|
-
method: 'PUT',
|
|
13955
|
-
headers: { 'Content-Type': 'application/json' },
|
|
13956
|
-
body: JSON.stringify({ relevanceFloor: floor, injectionLimit: limit })
|
|
13957
|
-
});
|
|
13958
|
-
if (!resp.ok) throw new Error('HTTP ' + resp.status);
|
|
13959
|
-
if (statusEl) statusEl.textContent = 'Saved ✓';
|
|
13960
|
-
_sbConfigLoaded = false;
|
|
13961
|
-
setTimeout(function() { if (statusEl) statusEl.textContent = ''; }, 2000);
|
|
13962
|
-
} catch (e) {
|
|
13963
|
-
if (statusEl) statusEl.textContent = 'Error: ' + e.message;
|
|
13964
|
-
}
|
|
13965
|
-
}
|
|
13966
|
-
|
|
13967
|
-
// --- Knowledge Graph Explorer ---
|
|
13968
|
-
async function loadSBKnowledgeGraph(query) {
|
|
13969
|
-
var tripletsEl = document.getElementById('sb-kg-triplets');
|
|
13970
|
-
if (!tripletsEl) return;
|
|
13971
|
-
tripletsEl.innerHTML = '<div class="loading-txt">Loading…</div>';
|
|
13972
|
-
try {
|
|
13973
|
-
var url = '/api/second-brain-kg?limit=100';
|
|
13974
|
-
if (query) url += '&q=' + encodeURIComponent(query);
|
|
13975
|
-
var data = await apiFetch(url);
|
|
13976
|
-
var nodesEl = document.getElementById('sb-kg-nodes');
|
|
13977
|
-
var edgesEl = document.getElementById('sb-kg-edges');
|
|
13978
|
-
if (nodesEl) nodesEl.textContent = (data.stats.nodes || 0).toLocaleString();
|
|
13979
|
-
if (edgesEl) edgesEl.textContent = (data.stats.edges || 0).toLocaleString();
|
|
13980
|
-
// Glossary tags
|
|
13981
|
-
var glossEl = document.getElementById('sb-kg-glossary');
|
|
13982
|
-
if (glossEl && data.glossary && data.glossary.length > 0) {
|
|
13983
|
-
glossEl.innerHTML = data.glossary.map(function(g) {
|
|
13984
|
-
var name = typeof g === 'string' ? g : (g.name || g.entity || '');
|
|
13985
|
-
var safe = esc(JSON.stringify(name));
|
|
13986
|
-
return '<span class="sb-kg-tag" onclick="var n=' + safe + ';document.getElementById(\'sb-kg-search\').value=n;loadSBKnowledgeGraph(n)">' + esc(name) + '</span>';
|
|
13987
|
-
}).join('');
|
|
13988
|
-
}
|
|
13989
|
-
// Triplets
|
|
13990
|
-
var triplets = data.triplets || [];
|
|
13991
|
-
if (!triplets.length) {
|
|
13992
|
-
tripletsEl.innerHTML = '<div class="empty">No triplets found.' + (query ? ' Try a different search.' : ' Ingest documents to build the knowledge graph.') + '</div>';
|
|
13993
|
-
return;
|
|
13994
|
-
}
|
|
13995
|
-
tripletsEl.innerHTML = triplets.map(function(t) {
|
|
13996
|
-
var s = t.subject || t.s || t.head || '?';
|
|
13997
|
-
var r = t.predicate || t.relation || t.p || t.rel || '→';
|
|
13998
|
-
var o = t.object || t.o || t.tail || '?';
|
|
13999
|
-
var safeS = esc(JSON.stringify(s));
|
|
14000
|
-
var safeO = esc(JSON.stringify(o));
|
|
14001
|
-
return '<div class="sb-kg-triplet">' +
|
|
14002
|
-
'<span class="sb-kg-entity subject" onclick="var n=' + safeS + ';document.getElementById(\'sb-kg-search\').value=n;loadSBKnowledgeGraph(n)">' + esc(s) + '</span>' +
|
|
14003
|
-
'<span class="sb-kg-rel">' + esc(r) + '</span>' +
|
|
14004
|
-
'<span class="sb-kg-entity object" onclick="var n=' + safeO + ';document.getElementById(\'sb-kg-search\').value=n;loadSBKnowledgeGraph(n)">' + esc(o) + '</span>' +
|
|
14005
|
-
(t.confidence ? '<span style="font-size:9px;color:var(--text-xs);margin-left:auto;font-family:var(--mono)">' + (t.confidence * 100).toFixed(0) + '%</span>' : '') +
|
|
14006
|
-
'</div>';
|
|
14007
|
-
}).join('');
|
|
14008
|
-
} catch (e) {
|
|
14009
|
-
tripletsEl.innerHTML = '<div class="empty">Failed: ' + esc(e.message) + '</div>';
|
|
14010
|
-
}
|
|
14011
|
-
}
|
|
14012
|
-
|
|
14013
13449
|
function _renderChunkStats(list) {
|
|
14014
13450
|
const countEl = document.getElementById('chunk-count-val');
|
|
14015
13451
|
const skillsEl = document.getElementById('chunk-skills-val');
|
|
@@ -14037,25 +13473,15 @@ function _renderChunks(list) {
|
|
|
14037
13473
|
// leaked markup) whenever the text contained quotes.
|
|
14038
13474
|
const shown = list.slice(0, 200);
|
|
14039
13475
|
window._chunksShown = shown;
|
|
14040
|
-
// Compute chunk size distribution for quality signals
|
|
14041
|
-
var sizes = shown.map(function(c) { return (c.content || c.text || c.body || '').length; });
|
|
14042
|
-
var avgSize = sizes.length > 0 ? sizes.reduce(function(a, b) { return a + b; }, 0) / sizes.length : 0;
|
|
14043
13476
|
grid.innerHTML = shown.map((c, i) => {
|
|
14044
13477
|
const src = (c.source || c.file || '').split('/').slice(-2).join('/');
|
|
14045
13478
|
const excerpt = (c.content || c.text || c.body || '').slice(0, 220);
|
|
14046
13479
|
const ns = c.namespace || c.type || '';
|
|
14047
|
-
const cLen = (c.content || c.text || c.body || '').length;
|
|
14048
|
-
var sizeNote = '';
|
|
14049
|
-
if (cLen < 50) sizeNote = '<span class="chunk-ns" style="color:oklch(72% 0.18 75);background:oklch(72% 0.18 75 / 0.1)" title="Very short chunk — may be noise">tiny</span>';
|
|
14050
|
-
else if (cLen > 4000) sizeNote = '<span class="chunk-ns" style="color:oklch(72% 0.18 280);background:oklch(72% 0.18 280 / 0.1)" title="Large chunk — may be imprecise for retrieval">large</span>';
|
|
14051
|
-
var idxNote = typeof c.chunkIndex === 'number' ? '<span class="chunk-ns" title="Chunk index within document">#' + c.chunkIndex + '</span>' : '';
|
|
14052
13480
|
return '<div class="chunk-card" data-search="' + esc((src + ' ' + excerpt + ' ' + ns).toLowerCase()) + '">' +
|
|
14053
13481
|
'<div class="chunk-src">' + esc(src || '—') + '</div>' +
|
|
14054
13482
|
'<div class="chunk-excerpt">' + esc(excerpt) + '</div>' +
|
|
14055
13483
|
'<div class="chunk-footer">' +
|
|
14056
13484
|
(ns ? '<span class="chunk-ns">' + esc(ns) + '</span>' : '') +
|
|
14057
|
-
idxNote + sizeNote +
|
|
14058
|
-
'<span class="chunk-ns" style="opacity:0.5" title="Character count">' + cLen + ' chars</span>' +
|
|
14059
13485
|
'<button class="btn" style="margin-left:auto;font-size:10px;padding:1px 7px" onclick="openChunkEditAt(' + i + ')">✎ Edit</button>' +
|
|
14060
13486
|
'<button class="btn" style="font-size:10px;padding:1px 7px;color:var(--red);border-color:var(--red)" onclick="deleteChunkAt(' + i + ')">✕</button>' +
|
|
14061
13487
|
'</div>' +
|