dsh-mesh-ui 0.0.11 → 0.0.12
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/lib/client.js +51 -10
- package/lib/collect.js +14 -3
- package/package.json +5 -2
package/lib/client.js
CHANGED
|
@@ -678,7 +678,7 @@ body.light .dm-edge-label { stroke: rgba(255,255,255,.92); }
|
|
|
678
678
|
h('span', null, '⋯')
|
|
679
679
|
)
|
|
680
680
|
),
|
|
681
|
-
h('div', { className: 'dm-hint' }, '拓扑
|
|
681
|
+
h('div', { className: 'dm-hint' }, '拓扑 v23 · 内容 ' + Math.round(layout.W) + '×' + Math.round(layout.H) + 'px · 卡 ' + Math.round(layout.cardW) + '×' + Math.round(layout.cardH) + ' · 缩放 ' + Math.round(view.scale * 100) + '% · 滚轮缩放 / 拖拽平移')
|
|
682
682
|
)
|
|
683
683
|
}
|
|
684
684
|
|
|
@@ -1453,6 +1453,9 @@ function deviceLinkState(data, peer, lanMap) {
|
|
|
1453
1453
|
// 2026-11-10:真刷新 —— 点击后等待后台采集完成再渲染;本地冷却 + 忙锁防止连点刷爆请求
|
|
1454
1454
|
var s6 = useState(""); var refreshHint = s6[0]; var setRefreshHint = s6[1]
|
|
1455
1455
|
var forceRef = useRef({ at: 0, busy: false })
|
|
1456
|
+
// 2026-11-10:verdict 防抖 —— 单次探测失败(远端忙/超时)只显示 degraded,连续 2 次才显示 down
|
|
1457
|
+
var verdictState = useState(''); var verdictShown = verdictState[0]; var setVerdictShown = verdictState[1]
|
|
1458
|
+
var verdictRef = useRef({ raw: '', streak: 0 })
|
|
1456
1459
|
var s5 = useState('local'); var selectedKey = s5[0]; var setSelectedKey = s5[1]
|
|
1457
1460
|
|
|
1458
1461
|
function load(force) {
|
|
@@ -1515,6 +1518,24 @@ function deviceLinkState(data, peer, lanMap) {
|
|
|
1515
1518
|
}, [])
|
|
1516
1519
|
|
|
1517
1520
|
useEffect(function () { if (tick > 0 && !forceRef.current.busy) load(false) }, [tick])
|
|
1521
|
+
useEffect(function () {
|
|
1522
|
+
var raw = String((data && data.verdict) || '')
|
|
1523
|
+
if (!raw) return
|
|
1524
|
+
var st = verdictRef.current
|
|
1525
|
+
var at = String((data && data.at) || '')
|
|
1526
|
+
var fresh = Boolean(at) && at !== st.lastAt
|
|
1527
|
+
if (raw === 'down') {
|
|
1528
|
+
if (fresh && !st.downAt) st.downAt = Date.now()
|
|
1529
|
+
st.lastAt = at
|
|
1530
|
+
var persisted = Boolean(st.downAt) && Date.now() - st.downAt >= 15000
|
|
1531
|
+
setVerdictShown(persisted ? 'down' : 'degraded')
|
|
1532
|
+
} else {
|
|
1533
|
+
st.downAt = 0
|
|
1534
|
+
st.lastAt = at
|
|
1535
|
+
setVerdictShown(raw)
|
|
1536
|
+
}
|
|
1537
|
+
st.raw = raw
|
|
1538
|
+
}, [data])
|
|
1518
1539
|
|
|
1519
1540
|
function copyJson() {
|
|
1520
1541
|
var text = JSON.stringify(data || {}, null, 2)
|
|
@@ -1540,7 +1561,11 @@ function deviceLinkState(data, peer, lanMap) {
|
|
|
1540
1561
|
h('style', null, CSS),
|
|
1541
1562
|
h('div', { className: 'dm-head' },
|
|
1542
1563
|
h('span', { className: 'dm-title' }, 'AI 网络 · dsh-mesh'),
|
|
1543
|
-
h('span', {
|
|
1564
|
+
h('span', {
|
|
1565
|
+
className: 'dm-pill ' + (data.warming ? 'muted' : tone(verdictShown || data.verdict)),
|
|
1566
|
+
title: data.warming ? '' : (verdictShown === 'degraded' ? '探测波动:需持续 ≥15s 且新快照仍 down 才显示 down' : ''),
|
|
1567
|
+
style: verdictShown === 'degraded' ? { opacity: 0.75 } : undefined
|
|
1568
|
+
}, data.warming ? '预热中' : (verdictShown || data.verdict || '?')),
|
|
1544
1569
|
h('span', { className: 'dm-sub' }, (data.meshVersion ? 'mesh ' + data.meshVersion + ' · ' : '') + (data.at ? ago(data.at) : '')),
|
|
1545
1570
|
h('span', { style: { flex: 1 } }),
|
|
1546
1571
|
h('a', { className: 'dm-btn', href: API, target: '_blank', rel: 'noreferrer', style: { textDecoration: 'none' } }, '原始 JSON'),
|
|
@@ -2265,12 +2290,22 @@ body[data-ds-dark-theme] .dm-dg-fs-item.active { background:rgba(88,166,255,.28)
|
|
|
2265
2290
|
var button = buttons[i]
|
|
2266
2291
|
var text = (button.textContent || '').trim()
|
|
2267
2292
|
if (text !== 'AI 网络' && text !== 'AI 网络(dsh-mesh)') continue
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
var
|
|
2271
|
-
var
|
|
2272
|
-
|
|
2273
|
-
|
|
2293
|
+
// 0.2.2 的默认图标可能包在 span 里;在默认图标的父容器里原地替换,
|
|
2294
|
+
// 保留间距/对齐,并清掉所有旧 SVG,避免齿轮 + 自绘图标双图标。
|
|
2295
|
+
var existingIcon = button.querySelector('svg[data-dsh-mesh-nav-icon]')
|
|
2296
|
+
var old = []
|
|
2297
|
+
var all = button.querySelectorAll('svg')
|
|
2298
|
+
for (var j = 0; j < all.length; j++) if (all[j] !== existingIcon) old.push(all[j])
|
|
2299
|
+
var reference = old[0] || null
|
|
2300
|
+
var parent = reference ? reference.parentNode : button
|
|
2301
|
+
var className = reference ? reference.getAttribute('class') || '' : ''
|
|
2302
|
+
if (!existingIcon) {
|
|
2303
|
+
var icon = navMeshIconDom(className)
|
|
2304
|
+
if (reference) parent.insertBefore(icon, reference)
|
|
2305
|
+
else if (button.firstChild) button.insertBefore(icon, button.firstChild)
|
|
2306
|
+
else button.appendChild(icon)
|
|
2307
|
+
}
|
|
2308
|
+
for (var k = 0; k < old.length; k++) if (old[k].parentNode) old[k].parentNode.removeChild(old[k])
|
|
2274
2309
|
}
|
|
2275
2310
|
} catch (error) {
|
|
2276
2311
|
/* ignore */
|
|
@@ -2279,10 +2314,16 @@ body[data-ds-dark-theme] .dm-dg-fs-item.active { background:rgba(88,166,255,.28)
|
|
|
2279
2314
|
|
|
2280
2315
|
function apply(ctx) {
|
|
2281
2316
|
var disposers = []
|
|
2317
|
+
// 2026-11-10:AI 网络从「设置」迁到左侧栏独立页面,使用更大的主区域。
|
|
2282
2318
|
try {
|
|
2283
|
-
disposers.push(ctx.slots.inject('
|
|
2319
|
+
disposers.push(ctx.slots.inject('sidebar.panellist', function () {
|
|
2320
|
+
return ctx.slots.register({ name: 'sidebar.panellist', id: 'mesh-network', order: 54, label: function () { return 'AI 网络' } }, meshPanelIcon)
|
|
2321
|
+
}))
|
|
2322
|
+
disposers.push(ctx.slots.inject('main', function () {
|
|
2323
|
+
return ctx.slots.register({ name: 'main', key: 'mesh-network', inject: function () { return {} } }, MeshStatusSection)
|
|
2324
|
+
}))
|
|
2284
2325
|
} catch (error) {
|
|
2285
|
-
console.warn('[dsh-mesh-ui]
|
|
2326
|
+
console.warn('[dsh-mesh-ui] sidebar network page registration failed:', error)
|
|
2286
2327
|
}
|
|
2287
2328
|
// 2026-11-07 方案 A:左侧栏「委托」面板(sidebar.panellist + main)
|
|
2288
2329
|
try {
|
package/lib/collect.js
CHANGED
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
|
|
16
16
|
import { execFile } from 'node:child_process'
|
|
17
17
|
import { existsSync, readdirSync, readFileSync, statfsSync, writeFileSync } from 'node:fs'
|
|
18
|
+
import { createRequire } from 'node:module'
|
|
18
19
|
import { lookup as dnsLookup } from 'node:dns/promises'
|
|
19
20
|
import { connect as netConnect } from 'node:net'
|
|
20
21
|
import { arch as osArch, cpus as osCpus, freemem as osFreemem, homedir, platform as osPlatform, release as osRelease, totalmem as osTotalmem } from 'node:os'
|
|
21
|
-
import { join } from 'node:path'
|
|
22
|
+
import { dirname, join } from 'node:path'
|
|
22
23
|
|
|
23
24
|
const CLI_TIMEOUT_MS = 25_000
|
|
24
25
|
const ALERT_HISTORY_MAX = 12
|
|
@@ -29,9 +30,19 @@ export function meshHome() {
|
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export function resolveRepo() {
|
|
33
|
+
// 1) 显式 DSH_MESH_REPO / 常见开发目录(源码/本地仓库)
|
|
32
34
|
const candidates = [process.env.DSH_MESH_REPO, join(homedir(), 'Code', 'dsh-mesh'), join(homedir(), 'Desktop', 'dsh-mesh')].filter(Boolean)
|
|
33
35
|
for (const candidate of candidates) {
|
|
34
|
-
if (existsSync(join(candidate, 'scripts', 'mesh-health.mjs'))) return candidate
|
|
36
|
+
if (existsSync(join(candidate, 'scripts', 'mesh-health.mjs')) && existsSync(join(candidate, 'src', 'cli.js'))) return candidate
|
|
37
|
+
}
|
|
38
|
+
// 2) 用户正常安装路径:dsh-mesh-ui 声明了 dsh-mesh-node 依赖,
|
|
39
|
+
// 直接解析已安装的 npm 包(随包带 scripts/mesh-health.mjs)。
|
|
40
|
+
try {
|
|
41
|
+
const requireFromPlugin = createRequire(import.meta.url)
|
|
42
|
+
const nodeRoot = dirname(requireFromPlugin.resolve('dsh-mesh-node/package.json'))
|
|
43
|
+
if (existsSync(join(nodeRoot, 'scripts', 'mesh-health.mjs')) && existsSync(join(nodeRoot, 'src', 'cli.js'))) return nodeRoot
|
|
44
|
+
} catch {
|
|
45
|
+
/* package not installed next to this plugin */
|
|
35
46
|
}
|
|
36
47
|
return null
|
|
37
48
|
}
|
|
@@ -391,7 +402,7 @@ async function overviewData(repo, force = false) {
|
|
|
391
402
|
*/
|
|
392
403
|
export async function collect(repo) {
|
|
393
404
|
const generatedAt = new Date().toISOString()
|
|
394
|
-
if (!repo) return { ok: false, error: 'dsh-mesh
|
|
405
|
+
if (!repo) return { ok: false, error: 'dsh-mesh-node is not installed for dsh-mesh-ui (install it with `npm i -g dsh-mesh-node`, or set DSH_MESH_REPO to a dsh-mesh checkout)', generatedAt }
|
|
395
406
|
|
|
396
407
|
const meshPromise = meshHealthJson(repo)
|
|
397
408
|
const overviewPromise = overviewData(repo)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-mesh-ui",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "DSH
|
|
3
|
+
"version": "0.0.12",
|
|
4
|
+
"description": "DSH sidebar page for dsh-mesh: AI network topology, peer health, and delegation panel. Read-only; data is collected from the installed dsh-mesh-node package.",
|
|
5
5
|
"icon": "icon.svg",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
"platform": "web"
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"dsh-mesh-node": "0.0.12"
|
|
32
|
+
},
|
|
30
33
|
"peerDependencies": {
|
|
31
34
|
"@deepseek-ai/dsh": ">=0.2.0-rc.2 <0.3.0",
|
|
32
35
|
"react": "^18.2.0",
|