@mingmaple/dsh-handover 0.9.6 → 0.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -17
- package/docs/migrate.md +1 -1
- package/docs/releases/0.9.12.md +28 -0
- package/docs/releases/0.9.13.md +30 -0
- package/docs/troubleshoot.md +43 -6
- package/package.json +70 -57
- package/scripts/blank-dsh.mjs +6 -5
- package/scripts/blank-smoke.mjs +268 -58
- package/scripts/build.mjs +3 -0
- package/scripts/check-docs.mjs +23 -2
- package/scripts/office.mjs +81 -0
- package/src/client.js +92 -23
- package/src/index.mjs +264 -145
- package/src/lib/api.mjs +67 -9
- package/src/lib/config.mjs +4 -3
- package/src/lib/consent.mjs +59 -20
- package/src/lib/facts.mjs +5 -4
- package/src/lib/guide.mjs +14 -7
- package/src/lib/handover-io.mjs +20 -0
- package/src/lib/manual.mjs +23 -12
- package/src/lib/names.mjs +2 -2
- package/src/lib/office.mjs +272 -0
- package/src/lib/pack-ops.mjs +3 -0
- package/src/lib/phase.mjs +6 -4
- package/src/lib/prompt.mjs +18 -0
- package/src/lib/role.mjs +52 -18
- package/src/lib/schedule.mjs +10 -14
- package/src/lib/session-create.mjs +42 -0
- package/src/lib/session-ops.mjs +183 -79
- package/src/lib/sessions.mjs +9 -8
- package/src/lib/status.mjs +8 -2
- package/src/lib/succession.mjs +244 -0
- package/src/lib/text.mjs +27 -0
- package/src/lib/webroute.mjs +1 -1
- package/src/lib/workspace.mjs +1 -1
- package/src/selftest.mjs +15 -0
- package/src/templates/Charter.skeleton.md +1 -1
- package/src/templates/Prompt_Templates.md +9 -17
- package/src/templates/Runtime_Manual.md +17 -14
- package/src/templates/rules/Handover_Rules.md +3 -2
- package/src/templates/rules/Misc_Task_Standard.md +3 -3
- package/src/tools/ho_checkpoint.mjs +11 -4
- package/src/tools/ho_diag.mjs +5 -3
- package/src/tools/ho_handover.mjs +7 -6
- package/src/tools/ho_office.mjs +59 -0
- package/src/tools/ho_profile.mjs +10 -2
- package/src/tools/ho_sessions.mjs +3 -2
- package/src/tools/ho_snapshot.mjs +2 -1
- package/src/tools/ho_succeed.mjs +24 -0
- package/src/tools/ho_workspace.mjs +7 -3
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 命令行查在任登记表:`node scripts/office.mjs 全局 全局3 Mingent`
|
|
4
|
+
*
|
|
5
|
+
* 与工具 ho_office 同一份实现、同一份记录(_Control_Center/records/Office.json),
|
|
6
|
+
* 区别只是不起会话也能查。工作区根按 --root → DSH_OFFICE_ROOT → 从 cwd 向上找 _Control_Center 的顺序解析。
|
|
7
|
+
*/
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { isDir } from '../src/lib/text.mjs';
|
|
10
|
+
import { loadOffice, resolveOffice, rowsOf, formatRow, officePath, KIND_LABEL } from '../src/lib/office.mjs';
|
|
11
|
+
|
|
12
|
+
function walkUp(start) {
|
|
13
|
+
let cur = path.resolve(start);
|
|
14
|
+
for (let i = 0; i < 8 && cur; i++) {
|
|
15
|
+
if (isDir(path.join(cur, '_Control_Center'))) return cur;
|
|
16
|
+
const up = path.dirname(cur);
|
|
17
|
+
if (up === cur) break;
|
|
18
|
+
cur = up;
|
|
19
|
+
}
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const argv = process.argv.slice(2);
|
|
24
|
+
let root = process.env.DSH_OFFICE_ROOT || process.env.DSH_HANDOVER_ROOT || '';
|
|
25
|
+
let json = false;
|
|
26
|
+
let all = false;
|
|
27
|
+
const queries = [];
|
|
28
|
+
for (let i = 0; i < argv.length; i++) {
|
|
29
|
+
const a = argv[i];
|
|
30
|
+
if (a === '--root') { root = argv[++i] || ''; continue; }
|
|
31
|
+
if (a === '--json') { json = true; continue; }
|
|
32
|
+
if (a === '--all' || a === '-a') { all = true; continue; }
|
|
33
|
+
if (a === '-h' || a === '--help') {
|
|
34
|
+
console.log('用法:node scripts/office.mjs [查询…] [--all] [--json] [--root <工作区根>]');
|
|
35
|
+
console.log('示例:node scripts/office.mjs 全局 全局3 Mingent');
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
queries.push(a);
|
|
39
|
+
}
|
|
40
|
+
if (!root) root = walkUp(process.cwd());
|
|
41
|
+
if (!root) {
|
|
42
|
+
console.error('找不到工作区根(没有 _Control_Center):用 --root 指定,例如 --root E:\\_Project_Mate\\_Workspace');
|
|
43
|
+
process.exit(2);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const store = loadOffice(root);
|
|
47
|
+
const rows = rowsOf(store);
|
|
48
|
+
if (!rows.length) {
|
|
49
|
+
console.error('在任登记表是空的:' + officePath(root));
|
|
50
|
+
console.log('提示:由全局会话用 ho_sessions / 换任流程登记一次在任会话,登记表随之生成。');
|
|
51
|
+
process.exit(2);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (all || !queries.length) {
|
|
55
|
+
if (json) {
|
|
56
|
+
console.log(JSON.stringify({ updatedAt: store.updatedAt || '', rows }, null, 2));
|
|
57
|
+
} else {
|
|
58
|
+
let lastKind = '';
|
|
59
|
+
for (const r of rows) {
|
|
60
|
+
if (r.kind !== lastKind) {
|
|
61
|
+
console.log((lastKind ? '\n' : '') + '【' + (KIND_LABEL[r.kind] || r.kind) + '】');
|
|
62
|
+
lastKind = r.kind;
|
|
63
|
+
}
|
|
64
|
+
console.log(formatRow(r));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let miss = 0;
|
|
71
|
+
const hits = [];
|
|
72
|
+
for (const q of queries) {
|
|
73
|
+
const r = resolveOffice(store, q);
|
|
74
|
+
if (!r.ok) { console.log(q + ' — ' + r.reason); miss++; continue; }
|
|
75
|
+
if (r.vacant) { console.log(q + ' — 类别「' + r.key + '」当前空缺(无人在任)'); continue; }
|
|
76
|
+
const row = { key: r.key, kind: r.lineage.kind, project: r.lineage.project, task: r.lineage.task, current: r.lineage.current };
|
|
77
|
+
if (!json) console.log(formatRow(row, q));
|
|
78
|
+
hits.push({ askedAs: q, via: r.via, key: r.key, kind: r.lineage.kind, name: r.lineage.current.name, sessionId: r.lineage.current.sessionId });
|
|
79
|
+
}
|
|
80
|
+
if (json) console.log(JSON.stringify({ updatedAt: store.updatedAt || '', hits }, null, 2));
|
|
81
|
+
process.exit(miss ? 1 : 0);
|
package/src/client.js
CHANGED
|
@@ -263,6 +263,9 @@ window.__ModuleLoader__.load({
|
|
|
263
263
|
const [created, setCreated] = React.useState("");
|
|
264
264
|
const [setupMsg, setSetupMsg] = React.useState("");
|
|
265
265
|
const [setupBad, setSetupBad] = React.useState(false);
|
|
266
|
+
const [deployInfo, setDeployInfo] = React.useState(null);
|
|
267
|
+
const [globalMsg, setGlobalMsg] = React.useState("");
|
|
268
|
+
const [globalBad, setGlobalBad] = React.useState(false);
|
|
266
269
|
const [working, setWorking] = React.useState(false);
|
|
267
270
|
// 追加系统提示词
|
|
268
271
|
const [extra, setExtra] = React.useState("");
|
|
@@ -332,13 +335,54 @@ window.__ModuleLoader__.load({
|
|
|
332
335
|
setWorking(true); setSetupBad(false); setSetupMsg("");
|
|
333
336
|
post("register", { path: created, title: "全局" }, 20000)
|
|
334
337
|
.then((r) => {
|
|
335
|
-
if (r && r.ok) setSetupMsg("已注册工作区:" + (r.title || "全局") + "(" + (r.id || "?") + "
|
|
338
|
+
if (r && r.ok) setSetupMsg("已注册工作区:" + (r.title || "全局") + "(" + (r.id || "?") + ")。点「刷新」后可继续。");
|
|
336
339
|
else { setSetupBad(true); setSetupMsg(((r && r.error) || "注册失败") + (r && r.hint ? ";" + r.hint : "")); }
|
|
337
340
|
})
|
|
338
341
|
.catch((e) => { setSetupBad(true); setSetupMsg("请求未完成:" + (e && e.message ? e.message : String(e))); })
|
|
339
342
|
.then(() => setWorking(false));
|
|
340
343
|
}, [created]);
|
|
341
344
|
|
|
345
|
+
// 一键部署:建文件体系、注册「全局」工作区、建「全局」会话,一次做完。
|
|
346
|
+
const deployAll = React.useCallback(() => {
|
|
347
|
+
setWorking(true); setDeployInfo(null); setSetupBad(false); setSetupMsg("");
|
|
348
|
+
post("deploy", { parent: parent }, 180000)
|
|
349
|
+
.then((r) => {
|
|
350
|
+
if (!r || !r.ok) {
|
|
351
|
+
setSetupBad(true);
|
|
352
|
+
setSetupMsg((r && r.error) || "部署失败");
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const parts = [];
|
|
356
|
+
parts.push("文件体系:" + r.root);
|
|
357
|
+
if (r.workspace) parts.push("工作区:「" + r.workspace.title + "」(" + r.workspace.path + ")");
|
|
358
|
+
else if (r.workspaceError) parts.push("工作区未注册:" + r.workspaceError);
|
|
359
|
+
if (r.sessionId) parts.push("全局会话:" + r.sessionId + "。在左侧「" + (r.workspace ? r.workspace.title : "全局") + "」工作区打开它即可开始。");
|
|
360
|
+
else if (r.sessionError) parts.push("会话未创建:" + r.sessionError);
|
|
361
|
+
setCreated(r.root || "");
|
|
362
|
+
setDeployInfo({ text: parts.join(";"), bad: false });
|
|
363
|
+
load();
|
|
364
|
+
})
|
|
365
|
+
.catch((e) => { setSetupBad(true); setSetupMsg("请求未完成:" + (e && e.message ? e.message : String(e))); })
|
|
366
|
+
.then(() => setWorking(false));
|
|
367
|
+
}, [parent, load]);
|
|
368
|
+
|
|
369
|
+
// 工作区已接入但没有全局会话时,补建一个。
|
|
370
|
+
const makeGlobalSession = React.useCallback(() => {
|
|
371
|
+
setWorking(true); setGlobalBad(false); setGlobalMsg("");
|
|
372
|
+
post("global-session", {}, 60000)
|
|
373
|
+
.then((r) => {
|
|
374
|
+
if (r && r.ok) {
|
|
375
|
+
setGlobalMsg("已创建全局会话 " + r.sessionId + ",在左侧工作区打开它即可开始。");
|
|
376
|
+
load();
|
|
377
|
+
} else {
|
|
378
|
+
setGlobalBad(true);
|
|
379
|
+
setGlobalMsg((r && r.error) || "创建失败");
|
|
380
|
+
}
|
|
381
|
+
})
|
|
382
|
+
.catch((e) => { setGlobalBad(true); setGlobalMsg("请求未完成:" + (e && e.message ? e.message : String(e))); })
|
|
383
|
+
.then(() => setWorking(false));
|
|
384
|
+
}, [load]);
|
|
385
|
+
|
|
342
386
|
const saveExtra = React.useCallback(() => {
|
|
343
387
|
setWorking(true); setExtraBad(false); setExtraMsg("");
|
|
344
388
|
post("extra-prompt", { text: extra }, 20000)
|
|
@@ -444,31 +488,31 @@ window.__ModuleLoader__.load({
|
|
|
444
488
|
// 压缩授权:只有用户在这里点一下,压缩才排得进去(AI 不能自己批)
|
|
445
489
|
const [csSid, setCsSid] = React.useState("");
|
|
446
490
|
const [csMsg, setCsMsg] = React.useState("");
|
|
447
|
-
const doGrant = React.useCallback(() => {
|
|
491
|
+
const doGrant = React.useCallback((kind) => {
|
|
448
492
|
setWorking(true); setCsMsg("");
|
|
449
|
-
post("consent.grant", { session_id: csSid }, 15000)
|
|
493
|
+
post("consent.grant", { session_id: csSid, kind: kind === "succeed" ? "succeed" : "compact" }, 15000)
|
|
450
494
|
.then((r) => {
|
|
451
|
-
if (r && r.ok) { setCsMsg("已授权会话 " + r.sessionId + ",5
|
|
495
|
+
if (r && r.ok) { setCsMsg("已授权会话 " + r.sessionId + ",5 分钟内可" + (r.kind === "succeed" ? "换任" : "压缩") + "一次,用后失效。"); load(); }
|
|
452
496
|
else setCsMsg("授权未完成:" + ((r && r.error) || "原因未知"));
|
|
453
497
|
})
|
|
454
498
|
.catch((e) => setCsMsg("请求未完成:" + (e && e.message ? e.message : String(e))))
|
|
455
499
|
.then(() => setWorking(false));
|
|
456
500
|
}, [csSid, load]);
|
|
457
|
-
const doGrantSid = React.useCallback((sid) => {
|
|
501
|
+
const doGrantSid = React.useCallback((sid, kind) => {
|
|
458
502
|
setWorking(true); setCsMsg("");
|
|
459
|
-
post("consent.grant", { session_id: sid }, 15000)
|
|
503
|
+
post("consent.grant", { session_id: sid, kind: kind === "succeed" ? "succeed" : "compact" }, 15000)
|
|
460
504
|
.then((r) => {
|
|
461
|
-
if (r && r.ok) { setCsMsg("已授权会话 " + r.sessionId + ",5
|
|
505
|
+
if (r && r.ok) { setCsMsg("已授权会话 " + r.sessionId + ",5 分钟内可" + (r.kind === "succeed" ? "换任" : "压缩") + "一次,用后失效。"); load(); }
|
|
462
506
|
else setCsMsg("授权未完成:" + ((r && r.error) || "原因未知"));
|
|
463
507
|
})
|
|
464
508
|
.catch((e) => setCsMsg("请求未完成:" + (e && e.message ? e.message : String(e))))
|
|
465
509
|
.then(() => setWorking(false));
|
|
466
510
|
}, [load]);
|
|
467
511
|
|
|
468
|
-
const doRevoke = React.useCallback((sid) => {
|
|
512
|
+
const doRevoke = React.useCallback((sid, kind) => {
|
|
469
513
|
setWorking(true); setCsMsg("");
|
|
470
|
-
post("consent.revoke", { session_id: sid }, 15000)
|
|
471
|
-
.then(() => { setCsMsg("已撤销 " + sid + "
|
|
514
|
+
post("consent.revoke", { session_id: sid, kind: kind === "succeed" ? "succeed" : "compact" }, 15000)
|
|
515
|
+
.then(() => { setCsMsg("已撤销 " + sid + " 的" + (kind === "succeed" ? "换任" : "压缩") + "授权。"); load(); })
|
|
472
516
|
.catch(() => { /* 撤销失败不影响别的 */ })
|
|
473
517
|
.then(() => setWorking(false));
|
|
474
518
|
}, [load]);
|
|
@@ -536,30 +580,44 @@ window.__ModuleLoader__.load({
|
|
|
536
580
|
// 排序原则:进来大概率要做的事在前,只读数据居中,说明文字最后。
|
|
537
581
|
const sections = [];
|
|
538
582
|
|
|
539
|
-
//
|
|
583
|
+
// 一、首次安装与全局会话:未接入时给一键部署;已接入但还没有全局会话时给补建入口。
|
|
540
584
|
const setup = data.setup;
|
|
541
585
|
const notReady = !ws || ws.found === false;
|
|
542
|
-
|
|
586
|
+
const globalCount = Number(data.globalSessions || 0);
|
|
587
|
+
if (deployInfo) {
|
|
588
|
+
sections.push(card("部署结果", h("div", { className: deployInfo.bad ? "dshh-bad" : "dshh-ok" }, deployInfo.text)));
|
|
589
|
+
}
|
|
590
|
+
if (notReady) {
|
|
543
591
|
const msg = setupMsg ? h("div", { className: setupBad ? "dshh-bad" : "dshh-ok" }, setupMsg) : null;
|
|
592
|
+
const steps = (setup && setup.steps) || [];
|
|
544
593
|
sections.push(card("首次安装",
|
|
545
594
|
h("div", null,
|
|
546
595
|
h("div", { className: "dshh-muted" }, "插件已加载,工具与本页可用;闸门、交接体检与会话水位在接入工作区后显示。"),
|
|
547
|
-
h("ol", { className: "dshh-list" },
|
|
596
|
+
h("ol", { className: "dshh-list" }, steps.map((s, i) => h("li", { key: i }, s))),
|
|
548
597
|
h("input", {
|
|
549
598
|
className: "dshh-input",
|
|
550
599
|
type: "text",
|
|
551
600
|
value: parent,
|
|
552
|
-
placeholder: "
|
|
601
|
+
placeholder: "粘贴一个绝对路径:全局根 _Workspace 会建在它里面",
|
|
553
602
|
onChange: (e) => setParent(e.target.value),
|
|
554
603
|
}),
|
|
555
604
|
h("div", { className: "dshh-row" },
|
|
556
|
-
h("button", { className: "dshh-btn", type: "button", disabled: working || !parent, onClick:
|
|
605
|
+
h("button", { className: "dshh-btn", type: "button", disabled: working || !parent, onClick: deployAll }, working ? "正在部署" : "一键部署"),
|
|
606
|
+
h("button", { className: "dshh-btn", type: "button", disabled: working || !parent, onClick: buildTree }, working ? "正在建立" : "仅建立文件体系"),
|
|
557
607
|
created ? h("button", { className: "dshh-btn", type: "button", disabled: working, onClick: registerWs }, "注册为工作区") : null),
|
|
558
608
|
created ? h("div", { className: "dshh-code" }, created) : null,
|
|
559
609
|
msg)));
|
|
610
|
+
} else if (globalCount === 0) {
|
|
611
|
+
sections.push(card("全局会话",
|
|
612
|
+
h("div", null,
|
|
613
|
+
h("div", { className: "dshh-muted" }, "工作区已接入,但还没有「全局」会话。点下面的按钮新建一个,插件会把它登记为全局角色。"),
|
|
614
|
+
h("div", { className: "dshh-muted" }, "全局根:" + (ws.root || "")),
|
|
615
|
+
h("div", { className: "dshh-row" },
|
|
616
|
+
h("button", { className: "dshh-btn", type: "button", disabled: working, onClick: makeGlobalSession }, working ? "正在创建" : "创建全局会话")),
|
|
617
|
+
globalMsg ? h("div", { className: globalBad ? "dshh-bad" : "dshh-ok" }, globalMsg) : null)));
|
|
560
618
|
}
|
|
561
619
|
|
|
562
|
-
//
|
|
620
|
+
// 二、压缩与换任授权:唯一合法的「用户同意」入口,置顶。
|
|
563
621
|
const consentRows = Array.isArray(data.consent) ? data.consent : [];
|
|
564
622
|
sections.push(card("压缩授权",
|
|
565
623
|
h("div", null,
|
|
@@ -571,8 +629,18 @@ window.__ModuleLoader__.load({
|
|
|
571
629
|
key: i,
|
|
572
630
|
disabled: working,
|
|
573
631
|
title: r.title || r.sid,
|
|
574
|
-
onClick: () => doGrantSid(r.sid),
|
|
632
|
+
onClick: () => doGrantSid(r.sid, "compact"),
|
|
575
633
|
}, "允许 " + shortSid(r.sid)))),
|
|
634
|
+
h("div", { className: "dshh-muted" }, "换任由在任会话自己执行,同样须由你授权:点「允许换任」后,该会话可在 5 分钟内换任一次。也可在对话中发送 /allow-succeed。"),
|
|
635
|
+
h("div", { className: "dshh-pick" },
|
|
636
|
+
byActivity.slice(0, 10).map((r, i) => h("button", {
|
|
637
|
+
className: "dshh-btn",
|
|
638
|
+
type: "button",
|
|
639
|
+
key: i,
|
|
640
|
+
disabled: working,
|
|
641
|
+
title: r.title || r.sid,
|
|
642
|
+
onClick: () => doGrantSid(r.sid, "succeed"),
|
|
643
|
+
}, "允许换任 " + shortSid(r.sid)))),
|
|
576
644
|
h("div", { className: "dshh-row" },
|
|
577
645
|
h("input", {
|
|
578
646
|
className: "dshh-inputSm",
|
|
@@ -581,15 +649,16 @@ window.__ModuleLoader__.load({
|
|
|
581
649
|
placeholder: "或输入会话 id 或 8 位短号",
|
|
582
650
|
onChange: (e) => setCsSid(e.target.value),
|
|
583
651
|
}),
|
|
584
|
-
h("button", { className: "dshh-btn", type: "button", disabled: working || !csSid, onClick: doGrant }, working ? "正在授权" : "授权")
|
|
652
|
+
h("button", { className: "dshh-btn", type: "button", disabled: working || !csSid, onClick: () => doGrant("compact") }, working ? "正在授权" : "授权"),
|
|
653
|
+
h("button", { className: "dshh-btn", type: "button", disabled: working || !csSid, onClick: () => doGrant("succeed") }, "授权换任")),
|
|
585
654
|
consentRows.length
|
|
586
655
|
? h("table", { className: "dshh-table" },
|
|
587
656
|
h("colgroup", null, h("col", { style: { width: "62%" } }), h("col", { style: { width: "18%" } }), h("col", { style: { width: "20%" } })),
|
|
588
657
|
h("thead", null, h("tr", null, h("th", null, "已授权会话"), h("th", null, "剩余"), h("th", null, "操作"))),
|
|
589
658
|
h("tbody", null, consentRows.map((r, i) => h("tr", { key: i },
|
|
590
|
-
h("td", { className: "dshh-code", title: r.sessionId }, shortSid(r.sessionId)),
|
|
659
|
+
h("td", { className: "dshh-code", title: r.sessionId }, shortSid(r.sessionId) + (r.kind === "succeed" ? " · 换任" : " · 压缩")),
|
|
591
660
|
h("td", { className: "dshh-num" }, Math.round((r.leftMs || 0) / 1000) + " 秒"),
|
|
592
|
-
h("td", null, h("button", { className: "dshh-btn", type: "button", disabled: working, onClick: () => doRevoke(r.sessionId) }, "撤销"))))))
|
|
661
|
+
h("td", null, h("button", { className: "dshh-btn", type: "button", disabled: working, onClick: () => doRevoke(r.sessionId, r.kind) }, "撤销"))))))
|
|
593
662
|
: h("div", { className: "dshh-muted" }, "当前无有效授权。"),
|
|
594
663
|
csMsg ? h("div", { className: "dshh-ok" }, csMsg) : null)));
|
|
595
664
|
|
|
@@ -825,16 +894,16 @@ window.__ModuleLoader__.load({
|
|
|
825
894
|
["工作区", ws.found ? h("span", { className: "dshh-code" }, ws.root) : verdict("未接入(未找到 _Control_Center)", false)],
|
|
826
895
|
])));
|
|
827
896
|
|
|
828
|
-
//
|
|
897
|
+
// 十、会话间通信守卫
|
|
829
898
|
const g = data.guardLast;
|
|
830
|
-
sections.push(card("
|
|
899
|
+
sections.push(card("会话间通信守卫",
|
|
831
900
|
g
|
|
832
901
|
? kv([
|
|
833
902
|
["结论", g.allow ? verdict("允许", true) : verdict("拒绝", false)],
|
|
834
903
|
["依据", g.source + (g.title ? ";会话标题 " + g.title : "")],
|
|
835
904
|
["会话", h("span", { className: "dshh-code" }, g.sid || "-")],
|
|
836
905
|
])
|
|
837
|
-
: h("div", { className: "dshh-muted" }, "
|
|
906
|
+
: h("div", { className: "dshh-muted" }, "本进程尚未收到会话间通信请求,暂无判定。")));
|
|
838
907
|
|
|
839
908
|
if ((data.notes || []).length) {
|
|
840
909
|
sections.push(card("待处理", h("ul", { className: "dshh-list" }, data.notes.map((n, i) => h("li", { key: i }, n)))));
|