@jiugeqqqqq/dsh-house2 0.2.2 → 0.3.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/CHANGELOG.md +5 -0
- package/lib/client.js +268 -1
- package/lib/host/index.js +25 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
> 每次发版都必须在这里写一条:改了什么、为什么改、别人要不要跟着动。
|
|
4
4
|
> 版本号跟 `package.json` 走,`npm i` 的人看这里就知道升了什么。
|
|
5
5
|
|
|
6
|
+
## 0.3.0 — 2026-10-30
|
|
7
|
+
|
|
8
|
+
- 新视图「识海」:房子页顶部切「房子 | 识海」。3D 星图——原意识在中心、记忆按时间沉底(越老越暗)、24 小时内的「心光」发光、点一条记忆亮起它牵出的念头链(心流),右侧看详情。
|
|
9
|
+
- 数据走 host 的 `sea` 接口(读 `sea-graph.json`,由 `scripts/sea-graph.mjs` 生成);路径可用 `seaGraphPath` 配,默认 `<DSH_HOME>/sea-graph.json`。
|
|
10
|
+
|
|
6
11
|
## 0.2.2 — 2026-10-30
|
|
7
12
|
|
|
8
13
|
- 压缩改成**按 token 触发**(不再挂在「任务完成」上):house2 自己统计累计 token(口径同 dsh-session-rotate,监听 `assistant/message` 的 `usage`),到阈值 80% 就在注入里提醒「该准备交接/换会话」。阈值 `thresholdTokens`,默认 1 亿。
|
package/lib/client.js
CHANGED
|
@@ -80,6 +80,16 @@ window.__ModuleLoader__.load({
|
|
|
80
80
|
},
|
|
81
81
|
err: { fontSize: '13px', color: 'var(--dsw-alias-state-error-primary,#e5534b)' },
|
|
82
82
|
note: { fontSize: '12px', opacity: 0.65 },
|
|
83
|
+
// 2026-10-30:识海视图的切换 tab
|
|
84
|
+
tab: {
|
|
85
|
+
padding: '5px 14px', borderRadius: '999px', cursor: 'pointer', fontSize: '13px',
|
|
86
|
+
border: '1px solid var(--dsw-alias-border-l2,#3a3a3a)', background: 'transparent', color: 'inherit', opacity: 0.7,
|
|
87
|
+
},
|
|
88
|
+
tabOn: {
|
|
89
|
+
padding: '5px 14px', borderRadius: '999px', cursor: 'pointer', fontSize: '13px',
|
|
90
|
+
border: '1px solid var(--dsw-alias-brand-primary,#4d6bfe)', background: 'rgba(77,107,254,0.16)',
|
|
91
|
+
color: 'var(--dsw-alias-brand-primary,#8fa8ff)', fontWeight: 600,
|
|
92
|
+
},
|
|
83
93
|
};
|
|
84
94
|
|
|
85
95
|
function HousePage() {
|
|
@@ -136,6 +146,11 @@ window.__ModuleLoader__.load({
|
|
|
136
146
|
var isBusy = busy[0];
|
|
137
147
|
var setBusy = busy[1];
|
|
138
148
|
|
|
149
|
+
// 2026-10-30:房子 / 识海 两个视图
|
|
150
|
+
var view = React.useState('house');
|
|
151
|
+
var currentView = view[0];
|
|
152
|
+
var setView = view[1];
|
|
153
|
+
|
|
139
154
|
// 搜历史原话:压缩掉的旧对话还在会话存档里,按关键词翻回去
|
|
140
155
|
var histQ = React.useState('');
|
|
141
156
|
var histQuery = histQ[0];
|
|
@@ -430,7 +445,259 @@ window.__ModuleLoader__.load({
|
|
|
430
445
|
children.push(React.createElement('div', { key: 'path', style: styles.note }, s.data.path));
|
|
431
446
|
}
|
|
432
447
|
|
|
433
|
-
|
|
448
|
+
var tabs = React.createElement(
|
|
449
|
+
'div', { key: 'tabs', style: { display: 'flex', gap: '8px' } },
|
|
450
|
+
React.createElement('button', { style: currentView === 'house' ? styles.tabOn : styles.tab, onClick: function () { setView('house'); } }, '房子'),
|
|
451
|
+
React.createElement('button', { style: currentView === 'sea' ? styles.tabOn : styles.tab, onClick: function () { setView('sea'); } }, '识海'),
|
|
452
|
+
);
|
|
453
|
+
if (currentView === 'sea') {
|
|
454
|
+
return React.createElement('div', { style: styles.wrap }, [tabs, React.createElement(SeaView, { key: 'sea' })]);
|
|
455
|
+
}
|
|
456
|
+
return React.createElement('div', { style: styles.wrap }, [tabs].concat(children));
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// ── 识海 3D 星图(2026-10-30)────────────────────────────────────
|
|
460
|
+
// 数据来自 host 的 sea 接口(sea-graph.json):
|
|
461
|
+
// 原意识在中心、记忆按时间沉底、24h 内的「心光」发光、
|
|
462
|
+
// 点一个记忆亮起它牵出的念头链(心流)。
|
|
463
|
+
function startSea(canvas, panelEl, DATA) {
|
|
464
|
+
var ctx = canvas.getContext('2d');
|
|
465
|
+
var DPR = Math.min(2, window.devicePixelRatio || 1);
|
|
466
|
+
var W = 0, H = 0;
|
|
467
|
+
function measure() {
|
|
468
|
+
var pe = canvas.parentElement;
|
|
469
|
+
var w = pe ? pe.clientWidth : 800;
|
|
470
|
+
var h = pe ? pe.clientHeight : 500;
|
|
471
|
+
W = canvas.width = Math.max(320, w) * DPR;
|
|
472
|
+
H = canvas.height = Math.max(320, h) * DPR;
|
|
473
|
+
}
|
|
474
|
+
measure();
|
|
475
|
+
var ro = null;
|
|
476
|
+
if (typeof ResizeObserver !== 'undefined' && canvas.parentElement) {
|
|
477
|
+
ro = new ResizeObserver(measure);
|
|
478
|
+
ro.observe(canvas.parentElement);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
var NOW = Date.now(), DAY = 86400000;
|
|
482
|
+
var COLOR = { memory: '#ff7ad9', vault: '#7fd7ff', ability: '#ffd166', tag: '#9b8cff', person: '#5dffc0' };
|
|
483
|
+
function ageDays(at) {
|
|
484
|
+
var t = Date.parse(at || '');
|
|
485
|
+
if (!t || isNaN(t)) return 45;
|
|
486
|
+
return Math.max(0, (NOW - t) / DAY);
|
|
487
|
+
}
|
|
488
|
+
var nodes = [], i, n;
|
|
489
|
+
var src = (DATA.nodes || []);
|
|
490
|
+
for (i = 0; i < src.length; i++) {
|
|
491
|
+
n = src[i];
|
|
492
|
+
if (n.type === 'tag' || n.type === 'person') continue;
|
|
493
|
+
var a = ageDays(n.at);
|
|
494
|
+
var ang = (i * 2.399963) % (Math.PI * 2);
|
|
495
|
+
var rad = 140 + Math.min(420, a * 3) + Math.random() * 60;
|
|
496
|
+
nodes.push({
|
|
497
|
+
id: n.id, type: n.type, label: n.label, text: n.text, at: n.at, source: n.source,
|
|
498
|
+
importance: n.importance, group: n.group, ageDays: a,
|
|
499
|
+
x: Math.cos(ang) * rad,
|
|
500
|
+
y: n.type === 'memory' ? -Math.min(460, a * 2.8) : (n.type === 'vault' ? -40 - Math.random() * 320 : -140 - Math.random() * 260),
|
|
501
|
+
z: Math.sin(ang) * rad,
|
|
502
|
+
color: COLOR[n.type] || '#8899aa',
|
|
503
|
+
size: (n.type === 'memory' ? 3.2 : 2.2) + Math.min(4, (Number(n.importance) || 0.5) * 4),
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
var core = { id: 'core', type: 'core', label: '原意识', x: 0, y: 20, z: 0, color: '#bfe3ff', size: 12 };
|
|
507
|
+
var byId = new Map();
|
|
508
|
+
for (i = 0; i < nodes.length; i++) byId.set(nodes[i].id, nodes[i]);
|
|
509
|
+
byId.set('core', core);
|
|
510
|
+
|
|
511
|
+
var edges = [];
|
|
512
|
+
for (i = 0; i < nodes.length; i++) edges.push({ source: nodes[i].id, target: 'core', kind: 'origin' });
|
|
513
|
+
var se = DATA.edges || [];
|
|
514
|
+
for (i = 0; i < se.length; i++) {
|
|
515
|
+
if (byId.has(se[i].source) && byId.has(se[i].target)) edges.push(se[i]);
|
|
516
|
+
}
|
|
517
|
+
var adj = new Map();
|
|
518
|
+
for (i = 0; i < edges.length; i++) {
|
|
519
|
+
var e = edges[i];
|
|
520
|
+
if (!adj.has(e.source)) adj.set(e.source, []);
|
|
521
|
+
if (!adj.has(e.target)) adj.set(e.target, []);
|
|
522
|
+
adj.get(e.source).push(e.target);
|
|
523
|
+
adj.get(e.target).push(e.source);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
var yaw = 0.5, pitch = -0.18, zoom = 1, dragging = false, lx = 0, ly = 0;
|
|
527
|
+
var active = null, chain = new Set();
|
|
528
|
+
|
|
529
|
+
function onDown(ev) { dragging = true; lx = ev.clientX; ly = ev.clientY; }
|
|
530
|
+
function onUp() { dragging = false; }
|
|
531
|
+
function onMove(ev) {
|
|
532
|
+
if (!dragging) return;
|
|
533
|
+
yaw += (ev.clientX - lx) * 0.0045;
|
|
534
|
+
pitch += (ev.clientY - ly) * 0.0045;
|
|
535
|
+
pitch = Math.max(-1.35, Math.min(1.35, pitch));
|
|
536
|
+
lx = ev.clientX; ly = ev.clientY;
|
|
537
|
+
}
|
|
538
|
+
function onWheel(ev) {
|
|
539
|
+
zoom *= ev.deltaY > 0 ? 1.07 : 0.93;
|
|
540
|
+
zoom = Math.max(0.35, Math.min(3.2, zoom));
|
|
541
|
+
}
|
|
542
|
+
function bfs(start, depth) {
|
|
543
|
+
var seen = new Set([start]), q = [[start, 0]], k;
|
|
544
|
+
while (q.length) {
|
|
545
|
+
var cur = q.shift();
|
|
546
|
+
if (cur[1] >= depth) continue;
|
|
547
|
+
var list = adj.get(cur[0]) || [];
|
|
548
|
+
for (k = 0; k < list.length; k++) {
|
|
549
|
+
if (!seen.has(list[k])) { seen.add(list[k]); q.push([list[k], cur[1] + 1]); }
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return seen;
|
|
553
|
+
}
|
|
554
|
+
function esc(s) {
|
|
555
|
+
return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) {
|
|
556
|
+
return { '&': '&', '<': '<', '>': '>', '"': '"' }[c];
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
function renderPanel(node) {
|
|
560
|
+
if (!panelEl) return;
|
|
561
|
+
var rows = [];
|
|
562
|
+
function add(k, v) { if (v !== undefined && v !== '') rows.push('<div><span style="color:#6e89ab">' + k + ':</span><span style="color:#e6f2ff">' + esc(v) + '</span></div>'); }
|
|
563
|
+
add('类型', { memory: '记忆', vault: '记忆库', ability: '能力' }[node.type] || node.type);
|
|
564
|
+
add('来源', node.source);
|
|
565
|
+
add('时间', node.at);
|
|
566
|
+
add('重要度', node.importance);
|
|
567
|
+
add('多少天前', node.ageDays !== undefined ? Math.round(node.ageDays) + ' 天' : '');
|
|
568
|
+
if (node.text) rows.push('<div style="margin-top:8px;opacity:.9">' + esc(String(node.text).slice(0, 260)) + '</div>');
|
|
569
|
+
var rel = [];
|
|
570
|
+
chain.forEach(function (id) {
|
|
571
|
+
if (id === 'core' || id === node.id) return;
|
|
572
|
+
var t = byId.get(id);
|
|
573
|
+
if (t) rel.push(t.label);
|
|
574
|
+
});
|
|
575
|
+
if (rel.length) rows.push('<div style="margin-top:10px;color:#6e89ab">牵着:</div><div style="line-height:1.8;opacity:.9">' + rel.slice(0, 12).map(esc).join(' · ') + '</div>');
|
|
576
|
+
panelEl.innerHTML = '<div style="font-size:14px;color:#a8d6ff;margin-bottom:8px;font-weight:600">' + esc(node.label) + '</div>' + rows.join('');
|
|
577
|
+
panelEl.style.display = 'block';
|
|
578
|
+
}
|
|
579
|
+
function onClick(ev) {
|
|
580
|
+
var r = canvas.getBoundingClientRect();
|
|
581
|
+
var mx = (ev.clientX - r.left) * DPR, my = (ev.clientY - r.top) * DPR;
|
|
582
|
+
var best = null, bd = 20 * DPR;
|
|
583
|
+
for (var k = 0; k < nodes.length; k++) {
|
|
584
|
+
var nn = nodes[k];
|
|
585
|
+
if (nn._sx === undefined) continue;
|
|
586
|
+
var d = Math.sqrt((nn._sx - mx) * (nn._sx - mx) + (nn._sy - my) * (nn._sy - my));
|
|
587
|
+
if (d < bd) { bd = d; best = nn; }
|
|
588
|
+
}
|
|
589
|
+
if (best) { active = best; chain = bfs(best.id, 2); renderPanel(best); }
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
canvas.addEventListener('pointerdown', onDown);
|
|
593
|
+
canvas.addEventListener('pointerup', onUp);
|
|
594
|
+
canvas.addEventListener('pointermove', onMove);
|
|
595
|
+
canvas.addEventListener('wheel', onWheel, { passive: true });
|
|
596
|
+
canvas.addEventListener('click', onClick);
|
|
597
|
+
|
|
598
|
+
var raf = 0;
|
|
599
|
+
function frame() {
|
|
600
|
+
raf = requestAnimationFrame(frame);
|
|
601
|
+
ctx.fillStyle = 'rgba(3,5,10,0.24)';
|
|
602
|
+
ctx.fillRect(0, 0, W, H);
|
|
603
|
+
var cy = Math.cos(yaw), sy = Math.sin(yaw), cp = Math.cos(pitch), sp = Math.sin(pitch);
|
|
604
|
+
var fov = 1100 * zoom, cx = W / 2, cyy = H / 2 + 40;
|
|
605
|
+
var all = [core].concat(nodes), k, nn;
|
|
606
|
+
for (k = 0; k < all.length; k++) {
|
|
607
|
+
nn = all[k];
|
|
608
|
+
var x1 = nn.x * cy - nn.z * sy, z1 = nn.x * sy + nn.z * cy;
|
|
609
|
+
var y1 = nn.y * cp - z1 * sp, z2 = nn.y * sp + z1 * cp;
|
|
610
|
+
var sc = fov / (fov + z2 + 700);
|
|
611
|
+
nn._sx = cx + x1 * sc; nn._sy = cyy + y1 * sc; nn._s = sc; nn._z = z2;
|
|
612
|
+
}
|
|
613
|
+
// 原意识光晕
|
|
614
|
+
var gs = ctx.createRadialGradient(core._sx, core._sy, 0, core._sx, core._sy, 150 * core._s);
|
|
615
|
+
gs.addColorStop(0, 'rgba(160,220,255,0.32)');
|
|
616
|
+
gs.addColorStop(0.45, 'rgba(90,160,255,0.09)');
|
|
617
|
+
gs.addColorStop(1, 'rgba(0,0,0,0)');
|
|
618
|
+
ctx.fillStyle = gs;
|
|
619
|
+
ctx.beginPath(); ctx.arc(core._sx, core._sy, 150 * core._s, 0, Math.PI * 2); ctx.fill();
|
|
620
|
+
// 边
|
|
621
|
+
for (k = 0; k < edges.length; k++) {
|
|
622
|
+
var ed = edges[k], a = byId.get(ed.source), b = byId.get(ed.target);
|
|
623
|
+
if (!a || !b || a._sx === undefined || b._sx === undefined) continue;
|
|
624
|
+
var lit = chain.has(a.id) || chain.has(b.id);
|
|
625
|
+
var depth = (a._s + b._s) / 2;
|
|
626
|
+
if (ed.kind === 'origin') {
|
|
627
|
+
ctx.strokeStyle = lit ? 'rgba(255,120,220,' + (0.26 * depth) + ')' : 'rgba(70,120,200,' + (0.045 * depth) + ')';
|
|
628
|
+
ctx.lineWidth = lit ? 1.1 : 0.4;
|
|
629
|
+
} else {
|
|
630
|
+
ctx.strokeStyle = lit ? 'rgba(255,140,230,' + (0.5 * depth) + ')' : 'rgba(80,130,200,' + (0.12 * depth) + ')';
|
|
631
|
+
ctx.lineWidth = lit ? 1.3 : 0.6;
|
|
632
|
+
}
|
|
633
|
+
ctx.beginPath(); ctx.moveTo(a._sx, a._sy); ctx.lineTo(b._sx, b._sy); ctx.stroke();
|
|
634
|
+
}
|
|
635
|
+
// 节点
|
|
636
|
+
nodes.sort(function (x, y2) { return y2._z - x._z; });
|
|
637
|
+
for (k = 0; k < nodes.length; k++) {
|
|
638
|
+
nn = nodes[k];
|
|
639
|
+
var isLit = !active || chain.has(nn.id);
|
|
640
|
+
var recency = Math.max(0.12, Math.min(1, 1.15 - nn.ageDays / 150));
|
|
641
|
+
ctx.globalAlpha = (isLit ? 0.95 : 0.16) * recency * Math.max(0.3, nn._s);
|
|
642
|
+
var r = Math.max(1.4, nn.size * nn._s * 2.1);
|
|
643
|
+
if (nn.ageDays < 1 || (active && chain.has(nn.id))) {
|
|
644
|
+
var gg = ctx.createRadialGradient(nn._sx, nn._sy, 0, nn._sx, nn._sy, r * 4);
|
|
645
|
+
gg.addColorStop(0, nn.color + 'aa');
|
|
646
|
+
gg.addColorStop(1, 'rgba(0,0,0,0)');
|
|
647
|
+
ctx.fillStyle = gg;
|
|
648
|
+
ctx.beginPath(); ctx.arc(nn._sx, nn._sy, r * 4, 0, Math.PI * 2); ctx.fill();
|
|
649
|
+
}
|
|
650
|
+
ctx.fillStyle = nn.color;
|
|
651
|
+
ctx.beginPath(); ctx.arc(nn._sx, nn._sy, r, 0, Math.PI * 2); ctx.fill();
|
|
652
|
+
if (nn === active) { ctx.strokeStyle = '#fff'; ctx.lineWidth = 1.6; ctx.stroke(); }
|
|
653
|
+
}
|
|
654
|
+
ctx.globalAlpha = 1;
|
|
655
|
+
ctx.fillStyle = '#e8f6ff';
|
|
656
|
+
ctx.beginPath(); ctx.arc(core._sx, core._sy, 7 * core._s, 0, Math.PI * 2); ctx.fill();
|
|
657
|
+
}
|
|
658
|
+
frame();
|
|
659
|
+
|
|
660
|
+
return function stop() {
|
|
661
|
+
cancelAnimationFrame(raf);
|
|
662
|
+
canvas.removeEventListener('pointerdown', onDown);
|
|
663
|
+
canvas.removeEventListener('pointerup', onUp);
|
|
664
|
+
canvas.removeEventListener('pointermove', onMove);
|
|
665
|
+
canvas.removeEventListener('wheel', onWheel);
|
|
666
|
+
canvas.removeEventListener('click', onClick);
|
|
667
|
+
if (ro) ro.disconnect();
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
function SeaView() {
|
|
672
|
+
var canvasRef = React.useRef(null);
|
|
673
|
+
var panelRef = React.useRef(null);
|
|
674
|
+
var st = React.useState({ loading: true, error: null, data: null });
|
|
675
|
+
var s = st[0], setS = st[1];
|
|
676
|
+
React.useEffect(function () {
|
|
677
|
+
call('sea').then(function (res) {
|
|
678
|
+
if (!res || res.ok !== true) {
|
|
679
|
+
setS({ loading: false, error: (res && res.error && res.error.message) || '读不到识海数据', data: null });
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
setS({ loading: false, error: null, data: res.data });
|
|
683
|
+
}).catch(function (err) {
|
|
684
|
+
setS({ loading: false, error: String(err && err.message ? err.message : err), data: null });
|
|
685
|
+
});
|
|
686
|
+
}, []);
|
|
687
|
+
React.useEffect(function () {
|
|
688
|
+
if (!s.data || !canvasRef.current) return;
|
|
689
|
+
var stop = startSea(canvasRef.current, panelRef.current, s.data);
|
|
690
|
+
return function () { if (stop) stop(); };
|
|
691
|
+
}, [s.data]);
|
|
692
|
+
var over = 'position:absolute;left:12px;top:10px;font-size:12px;opacity:.65;color:#cfe3ff';
|
|
693
|
+
return React.createElement(
|
|
694
|
+
'div', { style: { position: 'relative', flex: '1 1 auto', minHeight: '460px', background: '#05070d', borderRadius: '10px', overflow: 'hidden' } },
|
|
695
|
+
React.createElement('canvas', { ref: canvasRef, style: { display: 'block', width: '100%', height: '100%' } }),
|
|
696
|
+
s.loading ? React.createElement('div', { style: { padding: '16px', opacity: 0.7, color: '#cfe3ff' } }, '正在读识海…') : null,
|
|
697
|
+
s.error ? React.createElement('div', { style: { padding: '16px', color: '#ff8f8f', fontSize: '13px' } }, s.error) : null,
|
|
698
|
+
s.data && s.data.stats ? React.createElement('div', { style: over }, '原意识 · ' + s.data.stats.nodes + ' 段 · ' + s.data.stats.edges + ' 条连线 · 拖拽旋转 / 滚轮缩放 / 点记忆看念头') : null,
|
|
699
|
+
React.createElement('div', { ref: panelRef, style: { position: 'absolute', right: '12px', top: '12px', width: '270px', maxHeight: '72%', overflow: 'auto', background: 'rgba(8,14,26,.94)', border: '1px solid #23456b', borderRadius: '10px', padding: '12px', fontSize: '12px', lineHeight: 1.7, display: 'none' } }),
|
|
700
|
+
);
|
|
434
701
|
}
|
|
435
702
|
|
|
436
703
|
var inject = ['slots'];
|
package/lib/host/index.js
CHANGED
|
@@ -118,6 +118,12 @@ export function apply(ctx, config = {}) {
|
|
|
118
118
|
typeof config.stagesPath === 'string' && config.stagesPath.length > 0
|
|
119
119
|
? config.stagesPath
|
|
120
120
|
: path.join(dshHome, 'stages.md');
|
|
121
|
+
|
|
122
|
+
// 识海(3D 星图)的数据文件:scripts/sea-graph.mjs 生成,页面只读。
|
|
123
|
+
const seaGraphPath =
|
|
124
|
+
typeof config.seaGraphPath === 'string' && config.seaGraphPath.length > 0
|
|
125
|
+
? config.seaGraphPath
|
|
126
|
+
: path.join(dshHome, 'sea-graph.json');
|
|
121
127
|
const stages = createStages({
|
|
122
128
|
filePath: stagesPath,
|
|
123
129
|
log: (m) => ctx.logger?.info('dsh-house2: ' + m),
|
|
@@ -961,7 +967,25 @@ export function apply(ctx, config = {}) {
|
|
|
961
967
|
return;
|
|
962
968
|
}
|
|
963
969
|
if (method === 'meta') {
|
|
964
|
-
writeJson(response, 200, { ok: true, data: { assetsPath, knowledgeDir, sessionsDir } });
|
|
970
|
+
writeJson(response, 200, { ok: true, data: { assetsPath, knowledgeDir, sessionsDir, stagesPath, seaGraphPath } });
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// 识海数据:3D 星图用的节点+边(由 scripts/sea-graph.mjs 生成)
|
|
975
|
+
if (method === 'sea') {
|
|
976
|
+
try {
|
|
977
|
+
const raw = await readFile(seaGraphPath, 'utf8');
|
|
978
|
+
const j = JSON.parse(raw);
|
|
979
|
+
writeJson(response, 200, { ok: true, data: { stats: j.stats, nodes: j.nodes, edges: j.edges, path: seaGraphPath } });
|
|
980
|
+
} catch (error) {
|
|
981
|
+
writeJson(response, 200, {
|
|
982
|
+
ok: false,
|
|
983
|
+
error: {
|
|
984
|
+
code: 'missing',
|
|
985
|
+
message: `读不到识海数据:${seaGraphPath}(先在电脑上跑 scripts/sea-graph.mjs 生成)`,
|
|
986
|
+
},
|
|
987
|
+
});
|
|
988
|
+
}
|
|
965
989
|
return;
|
|
966
990
|
}
|
|
967
991
|
|