@unson/brainbase-mcp 0.41.11 → 0.42.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/README.md +1 -1
- package/contracts/judgment-dag/digest.json +2 -2
- package/dist/local-web-host.d.ts +6 -0
- package/dist/local-web-host.js +54 -3
- package/dist/personal-memory.d.ts +101 -0
- package/dist/personal-memory.js +204 -0
- package/dist/ssot.d.ts +3 -1
- package/dist/ssot.js +4 -0
- package/package.json +13 -2
- package/ui/area-nav.css +79 -0
- package/ui/area-nav.js +249 -0
- package/ui/foundation-overview.css +9 -0
- package/ui/foundation-overview.js +75 -5
- package/ui/graph-ontology-view.css +88 -0
- package/ui/graph-ontology-view.js +248 -0
- package/ui/graph-own-share.js +167 -0
- package/ui/graph-registry-view.css +272 -50
- package/ui/graph-registry-view.js +539 -456
- package/ui/graph-view-shared.css +32 -0
- package/ui/graph-view-shared.js +191 -12
- package/ui/judgment-history.js +74 -3
- package/ui/local-web-shell.css +1 -13
- package/ui/local-web-shell.js +119 -41
- package/ui/outcome-knowledge.js +6 -2
- package/ui/people-and-companies-view.css +166 -15
- package/ui/people-and-companies-view.js +307 -93
- package/ui/personal-memory-http-port.js +72 -0
- package/ui/personal-memory.css +254 -0
- package/ui/personal-memory.js +677 -0
- package/ui/world/world-canvas-notes.js +3 -2
- package/ui/world/world-view.css +19 -0
- package/ui/world/world-view.js +52 -10
- package/ui/world/world-work-rail.js +114 -8
package/ui/graph-view-shared.css
CHANGED
|
@@ -364,6 +364,38 @@
|
|
|
364
364
|
margin-top: 14px;
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
/* 根拠と履歴: one fold per record, after its relations (ledger D14). */
|
|
368
|
+
.bb-graph-rail > .bb-graph-evidence {
|
|
369
|
+
border-bottom: 1px solid var(--bb-color-border);
|
|
370
|
+
padding-block: 18px;
|
|
371
|
+
font-size: 13px;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.bb-graph-evidence > summary {
|
|
375
|
+
display: flex;
|
|
376
|
+
align-items: center;
|
|
377
|
+
gap: var(--bb-space-2);
|
|
378
|
+
color: var(--bb-color-ink);
|
|
379
|
+
font-weight: 690;
|
|
380
|
+
cursor: pointer;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.bb-graph-evidence-part {
|
|
384
|
+
margin-top: var(--bb-space-3);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.bb-graph-evidence-part > h4 {
|
|
388
|
+
margin: 0 0 var(--bb-space-1);
|
|
389
|
+
color: var(--bb-color-muted);
|
|
390
|
+
font-size: 12px;
|
|
391
|
+
font-weight: 690;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.bb-graph-evidence-part > p {
|
|
395
|
+
margin: 0 0 var(--bb-space-1);
|
|
396
|
+
overflow-wrap: anywhere;
|
|
397
|
+
}
|
|
398
|
+
|
|
367
399
|
.bb-graph-rail > .bb-graph-history {
|
|
368
400
|
border-bottom: 1px solid var(--bb-color-border);
|
|
369
401
|
padding-block: 18px;
|
package/ui/graph-view-shared.js
CHANGED
|
@@ -38,6 +38,45 @@ export const GRAPH_ENTITY_TYPE_LABELS = Object.freeze({
|
|
|
38
38
|
org: '組織',
|
|
39
39
|
project: 'プロジェクト',
|
|
40
40
|
decision: '判断',
|
|
41
|
+
// The kinds an organization's Graph defines on top of the local four, so the
|
|
42
|
+
// screens never show an internal type id (ledger D14).
|
|
43
|
+
app: 'アプリ',
|
|
44
|
+
product: 'プロダクト',
|
|
45
|
+
brand: 'ブランド',
|
|
46
|
+
customer: '顧客',
|
|
47
|
+
partner: '協業先',
|
|
48
|
+
contact: '名刺の連絡先',
|
|
49
|
+
raci: '責任分担表',
|
|
50
|
+
raci_assignment: '責任の割り当て',
|
|
51
|
+
role_assignment: '役割',
|
|
52
|
+
glossary_term: '用語',
|
|
53
|
+
document: '文書',
|
|
54
|
+
frame: '考え方の枠組み',
|
|
55
|
+
story: 'ストーリー',
|
|
56
|
+
infrastructure_environment: '稼働環境',
|
|
57
|
+
speaking: '登壇',
|
|
58
|
+
media_appearance: 'メディア出演',
|
|
59
|
+
publication: '出版物',
|
|
60
|
+
press_mention: '報道',
|
|
61
|
+
initiative: '施策',
|
|
62
|
+
ai_query: 'AIへの問い合わせ',
|
|
63
|
+
ai_decision: 'AIを使った判断',
|
|
64
|
+
philosophy: '哲学',
|
|
65
|
+
capital: '資本',
|
|
66
|
+
contract: '契約',
|
|
67
|
+
database: 'データベース',
|
|
68
|
+
database_cluster: 'データベースのクラスタ',
|
|
69
|
+
diagnosis: '診断',
|
|
70
|
+
finance: '財務',
|
|
71
|
+
finance_account: '財務の口座',
|
|
72
|
+
org_alias: '組織の別名',
|
|
73
|
+
organization: '組織(旧い形式)',
|
|
74
|
+
person_alias: '人物の別名',
|
|
75
|
+
push_case: '推進案件',
|
|
76
|
+
objective: '目的',
|
|
77
|
+
variable: '変数',
|
|
78
|
+
model: '世界モデル',
|
|
79
|
+
constraint: '制約',
|
|
41
80
|
});
|
|
42
81
|
|
|
43
82
|
export const GRAPH_ENTITY_TYPE_MEANINGS = Object.freeze({
|
|
@@ -51,14 +90,72 @@ export const GRAPH_ENTITY_TYPE_MEANINGS = Object.freeze({
|
|
|
51
90
|
* `outgoing` follows the counterpart name when this record is the start of the
|
|
52
91
|
* relation; `incoming` follows it when this record is the end.
|
|
53
92
|
*/
|
|
93
|
+
const relation = (label, meaning, outgoing, incoming) => Object.freeze({ label, meaning, outgoing, incoming });
|
|
94
|
+
|
|
95
|
+
/*
|
|
96
|
+
* Every relation of the local Graph and of an organization's Graph has a plain
|
|
97
|
+
* Japanese name (ledger D14); a relation id is shown only in the details.
|
|
98
|
+
* Relations that mean the same to a reader share one name (所有 for owns and
|
|
99
|
+
* owned_by, 所属 for member_of and belongs_to), and a list of relation kinds
|
|
100
|
+
* shows them as one row (`groupRelationKinds`).
|
|
101
|
+
*/
|
|
54
102
|
export const GRAPH_RELATION_LABELS = Object.freeze({
|
|
55
|
-
member_of:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
103
|
+
member_of: relation('所属', '人物が組織やプロジェクトに所属している', 'に所属', 'が所属'),
|
|
104
|
+
belongs_to: relation('所属', '記録が組織・プロダクト・ブランド・プロジェクトに含まれる', 'に所属', 'が所属'),
|
|
105
|
+
belongs_to_project: relation('所属', '記録がプロジェクトに含まれる', 'に所属', 'が所属'),
|
|
106
|
+
participates_in: relation('参加', '人物がプロジェクトに参加している', 'に参加', 'が参加'),
|
|
107
|
+
accountable_for: relation('責任', '人物や組織が成果や判断に最終的な責任を持つ', 'に責任を持つ', 'が責任を持つ'),
|
|
108
|
+
owned_by: relation('所有', 'プロジェクトなどを組織や人が所有している', 'が所有', 'を所有'),
|
|
109
|
+
owns: relation('所有', '組織がアプリ・プロダクト・ブランド・プロジェクトを所有している', 'を所有', 'が所有'),
|
|
110
|
+
owns_app: relation('所有', 'プロジェクトがアプリを持っている(旧い形式)', 'を所有', 'が所有'),
|
|
111
|
+
related_to: relation('関わる', '会社が顧客・協業先などとしてプロジェクトに関わっている', 'に関わる', 'が関わる'),
|
|
112
|
+
governs: relation('進め方を決める', '判断や原則が、対象の進め方を決める', 'の進め方を決める', 'が進め方を決める'),
|
|
113
|
+
governed_by: relation('従う原則', '推進案件が従う原則', 'に従う', 'が従う'),
|
|
114
|
+
supersedes: relation('置き換え', '判断が以前の判断を置き換える', 'を置き換える', 'に置き換えられた'),
|
|
115
|
+
superseded_by: relation('同一人物に統合', '古い人物の記録を、正しい人物の記録へまとめた', 'へ統合', 'を統合'),
|
|
116
|
+
derived_from: relation('由来', '記録が別の記録をもとにしている', 'に由来', 'が由来とする'),
|
|
117
|
+
depends_on: relation('依存', '稼働や成果が別の記録に依存している', 'に依存', 'が依存'),
|
|
118
|
+
assigned_to: relation('責任の割り当て', '責任分担で、人や組織に責任を割り当てている', 'に割り当て', 'で割り当て'),
|
|
119
|
+
requested_by: relation('問い合わせた人', 'AIへの問い合わせをした人', 'が問い合わせた', 'を問い合わせた'),
|
|
120
|
+
made_by: relation('判断した人', '判断をした人', 'が判断した', 'を判断した'),
|
|
121
|
+
references: relation('根拠として参照', '判断や問い合わせが、根拠として別の記録を参照している', 'を参照', 'が参照'),
|
|
122
|
+
evidenced_by: relation('根拠の文書', '判断の根拠になった文書', 'を根拠にする', 'が根拠にする'),
|
|
123
|
+
informs: relation('判断材料', '文書がプロジェクトの判断材料になる', 'の判断材料', 'が判断材料'),
|
|
124
|
+
mentions: relation('言及', '判断が協業先やプロダクトに言及している', 'に言及', 'が言及'),
|
|
125
|
+
alias_of: relation('別名', '人や組織の別の呼び名', 'の別名', 'が別名'),
|
|
126
|
+
applies_to: relation('適用先', '文書が適用される組織', 'に適用', 'が適用'),
|
|
127
|
+
describes: relation('説明', '文書が組織を説明している', 'を説明', 'が説明'),
|
|
128
|
+
brand_of: relation('ブランドの対象', 'ブランドが表す組織やプロジェクト', 'のブランド', 'がブランド'),
|
|
129
|
+
sub_brand_of: relation('上位ブランド', 'ブランドの上位にあるブランド', 'の下位ブランド', 'が下位ブランド'),
|
|
130
|
+
operates: relation('運営', '組織が運営している', 'を運営', 'が運営'),
|
|
131
|
+
operated_by: relation('運営', '組織が運営している', 'が運営', 'を運営'),
|
|
132
|
+
covers_engagement: relation('責任分担の対象', '責任分担表が対象とする組織や案件', 'の責任分担', 'が責任分担を示す'),
|
|
133
|
+
describes_org: relation('責任分担の対象', '責任分担表が対象とする組織や案件', 'の責任分担', 'が責任分担を示す'),
|
|
134
|
+
has_raci: relation('責任分担表', '組織やプロジェクトが持つ責任分担表', 'を持つ', 'が持つ'),
|
|
135
|
+
has_project: relation('含む', 'プロジェクトが子プロジェクト・案件・施策を含む', 'を含む', 'に含まれる'),
|
|
136
|
+
has_engagement: relation('含む', 'プロジェクトが子プロジェクト・案件・施策を含む', 'を含む', 'に含まれる'),
|
|
137
|
+
has_initiative: relation('含む', 'プロジェクトが子プロジェクト・案件・施策を含む', 'を含む', 'に含まれる'),
|
|
138
|
+
relates_to_project: relation('関連', 'プロジェクトどうしが関連している', 'と関連', 'と関連'),
|
|
139
|
+
serves_customer: relation('価値を届ける顧客', 'プロジェクトが価値を届ける顧客', 'に価値を届ける', 'が価値を届ける'),
|
|
140
|
+
org_unit_of: relation('上位の顧客', '部署が属する顧客の会社', 'の部署', 'が部署'),
|
|
141
|
+
supports_project: relation('支援', '協業先がプロジェクトを運営する組織を支援している', 'を支援', 'が支援'),
|
|
142
|
+
key_contact_for: relation('主な窓口', 'ブランドや推進案件の主な窓口', 'の主な窓口', 'が主な窓口'),
|
|
143
|
+
primary_contact_for: relation('主な窓口', 'ブランドや推進案件の主な窓口', 'の主な窓口', 'が主な窓口'),
|
|
144
|
+
has_push_case: relation('推進案件', '顧客について進めている推進案件', 'を推進案件に持つ', 'の推進案件'),
|
|
145
|
+
has_diagnosis: relation('診断', '推進案件についての診断', 'を持つ', 'が持つ'),
|
|
146
|
+
role_at: relation('役割', '人物の役割と、その役割の所属先', 'での役割', 'がある'),
|
|
147
|
+
holds_role: relation('役割', '人物の役割と、その役割の所属先', 'を持つ', 'が持つ'),
|
|
148
|
+
uses_app: relation('利用', 'プロジェクトやアプリが、アプリやデータベースを使う', 'を使う', 'が使う'),
|
|
149
|
+
uses_database: relation('利用', 'プロジェクトやアプリが、アプリやデータベースを使う', 'を使う', 'が使う'),
|
|
150
|
+
has_environment: relation('稼働環境', 'プロジェクトが稼働環境として持つアプリ', 'を稼働環境に持つ', 'の稼働環境'),
|
|
151
|
+
hosted_on: relation('置き場所', 'データベースが置かれているクラスタ', 'に置かれている', 'が置かれている'),
|
|
152
|
+
uses_secret_store: relation('秘密情報の保管先', 'アプリが使う(または使うべき)秘密情報の保管先', 'を保管先に使う', 'が保管先に使う'),
|
|
153
|
+
should_use_secret_store: relation('秘密情報の保管先', 'アプリが使う(または使うべき)秘密情報の保管先', 'を保管先に使うべき', 'が保管先に使うべき'),
|
|
154
|
+
created: relation('生み出した', '人物がプロダクトを生み出した', 'を生み出した', 'が生み出した'),
|
|
155
|
+
authored: relation('著作', '人物が出版物を著した', 'を著した', 'が著した'),
|
|
156
|
+
spoke_at: relation('登壇', '人物が登壇した', 'で登壇', 'が登壇'),
|
|
157
|
+
appeared_in: relation('出演', '人物がメディアに出演した', 'に出演', 'が出演'),
|
|
158
|
+
mentioned_in: relation('掲載', '人物が報道に掲載された', 'に掲載', 'が掲載'),
|
|
62
159
|
});
|
|
63
160
|
|
|
64
161
|
/** Relations a correction may add (the host refuses any other). */
|
|
@@ -213,9 +310,9 @@ export function facts(doc, rows, className = 'bb-graph-facts') {
|
|
|
213
310
|
}
|
|
214
311
|
|
|
215
312
|
/** Ids and digests stay in this disclosure, never in the visible copy. */
|
|
216
|
-
export function recordDetails(doc, rows) {
|
|
313
|
+
export function recordDetails(doc, rows, { title = '記録の詳細' } = {}) {
|
|
217
314
|
const details = makeElement(doc, 'details', { className: 'bb-graph-audit' });
|
|
218
|
-
details.append(makeElement(doc, 'summary', { text:
|
|
315
|
+
details.append(makeElement(doc, 'summary', { text: title }), facts(doc, rows, 'bb-graph-facts is-mono'));
|
|
219
316
|
return details;
|
|
220
317
|
}
|
|
221
318
|
|
|
@@ -307,9 +404,33 @@ export function ownLabel(table, key) {
|
|
|
307
404
|
return typeof key === 'string' && Object.hasOwn(table, key) ? table[key] : undefined;
|
|
308
405
|
}
|
|
309
406
|
|
|
310
|
-
/**
|
|
311
|
-
|
|
312
|
-
|
|
407
|
+
/**
|
|
408
|
+
* A relation's plain label. An unknown relation shows the meaning its host
|
|
409
|
+
* gave (when there is one) rather than its raw id.
|
|
410
|
+
*/
|
|
411
|
+
export function relationLabel(relation, meaning) {
|
|
412
|
+
return ownLabel(GRAPH_RELATION_LABELS, relation)?.label ?? textOrNull(meaning) ?? relation;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* The relation kinds of an ontology answer as rows a reader can tell apart:
|
|
417
|
+
* kinds with the same plain name are one row (所有 for owns, owned_by and
|
|
418
|
+
* owns_app), and each row keeps every kind with its start and end kinds. Rows
|
|
419
|
+
* keep the order in which their first kind appears.
|
|
420
|
+
*/
|
|
421
|
+
export function groupRelationKinds(relations) {
|
|
422
|
+
const rows = new Map();
|
|
423
|
+
for (const item of Array.isArray(relations) ? relations : []) {
|
|
424
|
+
if (!isRecord(item) || typeof item.id !== 'string') continue;
|
|
425
|
+
const known = ownLabel(GRAPH_RELATION_LABELS, item.id);
|
|
426
|
+
const label = relationLabel(item.id, item.meaning);
|
|
427
|
+
const row = rows.get(label) ?? { label, meanings: [], kinds: [] };
|
|
428
|
+
const meaning = known?.meaning ?? textOrNull(item.meaning);
|
|
429
|
+
if (meaning && !row.meanings.includes(meaning)) row.meanings.push(meaning);
|
|
430
|
+
row.kinds.push(item);
|
|
431
|
+
rows.set(label, row);
|
|
432
|
+
}
|
|
433
|
+
return [...rows.values()];
|
|
313
434
|
}
|
|
314
435
|
|
|
315
436
|
/** A type's plain label; an unknown type (from another host's Graph) shows its raw id. */
|
|
@@ -620,6 +741,59 @@ export function renderGraphIssues(doc, issues) {
|
|
|
620
741
|
});
|
|
621
742
|
}
|
|
622
743
|
|
|
744
|
+
/**
|
|
745
|
+
* 根拠と履歴 of one record, folded: where the record came from (the host's 出典
|
|
746
|
+
* notice, which may carry its authorization), the source or correction records
|
|
747
|
+
* that could not be read, and the corrections made. None of these is a notice
|
|
748
|
+
* for the whole screen (ledger D14); records that could not be read are counted
|
|
749
|
+
* on the fold itself so they are not hidden.
|
|
750
|
+
*
|
|
751
|
+
* @param {Document} doc
|
|
752
|
+
* @param {{ source?: string | Element | null, issues?: unknown[], history?: unknown[] }} parts
|
|
753
|
+
*/
|
|
754
|
+
export function renderEvidenceAndHistory(doc, { source = null, issues = [], history = [] } = {}) {
|
|
755
|
+
const unreadable = (Array.isArray(issues) ? issues : []).filter(isRecord);
|
|
756
|
+
const corrections = (Array.isArray(history) ? history : []).filter(isRecord);
|
|
757
|
+
const details = makeElement(doc, 'details', { className: 'bb-graph-evidence' });
|
|
758
|
+
const summary = makeElement(doc, 'summary', { text: '根拠と履歴' });
|
|
759
|
+
if (unreadable.length > 0) summary.append(badge(doc, `読めない記録 ${unreadable.length}件`, 'warning'));
|
|
760
|
+
details.append(summary);
|
|
761
|
+
const section = (title, ...children) => {
|
|
762
|
+
const block = makeElement(doc, 'section', { className: 'bb-graph-evidence-part' });
|
|
763
|
+
block.append(makeElement(doc, 'h4', { text: title }), ...children.filter(Boolean));
|
|
764
|
+
details.append(block);
|
|
765
|
+
};
|
|
766
|
+
if (source) {
|
|
767
|
+
const body = typeof source === 'object' && typeof source.tagName === 'string' ? source : makeElement(doc, 'p', { text: String(source) });
|
|
768
|
+
section('出どころ', body);
|
|
769
|
+
}
|
|
770
|
+
if (unreadable.length > 0) {
|
|
771
|
+
const list = makeElement(doc, 'ul', { className: 'bb-graph-issue-list' });
|
|
772
|
+
for (const issue of unreadable) {
|
|
773
|
+
const where = `${String(issue.file ?? '不明')}${Number.isInteger(issue.line) ? `(${issue.line}行目)` : ''}`;
|
|
774
|
+
list.append(makeElement(doc, 'li', { text: `${where}: ${String(issue.reason ?? '理由不明')}` }));
|
|
775
|
+
}
|
|
776
|
+
section(
|
|
777
|
+
'読めない記録',
|
|
778
|
+
makeElement(doc, 'p', { text: `この記録の出典や訂正の履歴のうち、壊れていて読めない記録が${unreadable.length}件あります。表示している内容は読めた記録だけから作っているため、最後の訂正や出典が抜けているかもしれません。` }),
|
|
779
|
+
list,
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
if (corrections.length > 0) {
|
|
783
|
+
const list = makeElement(doc, 'ol', { className: 'bb-graph-history-list' });
|
|
784
|
+
for (const record of corrections) {
|
|
785
|
+
const fields = Array.isArray(record.changedFields) ? record.changedFields.map((field) => FIELD_LABELS[field] ?? field).join('・') : '';
|
|
786
|
+
list.append(makeElement(doc, 'li', {
|
|
787
|
+
text: `${formatDateTime(record.at)} ${CORRECTION_KIND_LABELS[record.kind] ?? '直した'}${fields ? `(${fields})` : ''}。理由: ${String(record.reason ?? '')}`,
|
|
788
|
+
}));
|
|
789
|
+
}
|
|
790
|
+
section(`訂正の履歴(${corrections.length}件)`, list);
|
|
791
|
+
} else if (Array.isArray(history)) {
|
|
792
|
+
section('訂正の履歴', makeElement(doc, 'p', { className: 'bb-graph-empty', text: 'この記録は、まだ訂正されていません。' }));
|
|
793
|
+
}
|
|
794
|
+
return details;
|
|
795
|
+
}
|
|
796
|
+
|
|
623
797
|
// ---------------------------------------------------------------------------
|
|
624
798
|
// Layout
|
|
625
799
|
|
|
@@ -662,6 +836,11 @@ export function createGraphLayout(doc, { root, rail, label, className, contractV
|
|
|
662
836
|
surface.append(...workspaceChildren.filter(Boolean));
|
|
663
837
|
const detail = makeElement(doc, 'div', { className: `bb-graph-rail ${className}-rail` });
|
|
664
838
|
detail.append(...railChildren.filter(Boolean));
|
|
839
|
+
// A view with nothing for the rail (its detail is inside the workspace) draws no inline rail.
|
|
840
|
+
if (!rail && !railChildren.some(Boolean)) {
|
|
841
|
+
root.replaceChildren(surface);
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
665
844
|
if (rail) {
|
|
666
845
|
root.replaceChildren(surface);
|
|
667
846
|
rail.replaceChildren(detail);
|
package/ui/judgment-history.js
CHANGED
|
@@ -1148,12 +1148,45 @@ function appendJudgmentBasis(doc, references, labels) {
|
|
|
1148
1148
|
return wrap;
|
|
1149
1149
|
}
|
|
1150
1150
|
|
|
1151
|
-
function
|
|
1151
|
+
function personalMemoryExcerpt(value) {
|
|
1152
|
+
const body = String(value ?? '').replace(/\s+/gu, ' ').trim();
|
|
1153
|
+
return body.length > 60 ? `${body.slice(0, 60)}…` : body;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
/**
|
|
1157
|
+
* The used memories the host resolved for this viewer: an opening and a link
|
|
1158
|
+
* to あなたの記憶. Only the owner's host resolves them; without that, or when
|
|
1159
|
+
* the lookup failed, this stays the count only.
|
|
1160
|
+
*/
|
|
1161
|
+
function ownerMemoryLinks(doc, references, memories) {
|
|
1162
|
+
if (!(memories instanceof Map)) return null;
|
|
1163
|
+
const found = [];
|
|
1164
|
+
for (const reference of Array.isArray(references) ? references : []) {
|
|
1165
|
+
if (judgmentReferenceKind(reference) !== PERSONAL_KNOWLEDGE_KIND) continue;
|
|
1166
|
+
const entry = memories.get(text(reference?.ref));
|
|
1167
|
+
if (entry?.status === 'found') found.push(entry);
|
|
1168
|
+
}
|
|
1169
|
+
if (found.length === 0) return null;
|
|
1170
|
+
const list = makeWorkspaceElement(doc, 'ul', { className: 'bb-jh-owner-memories', attrs: { 'aria-label': '使った記憶' } });
|
|
1171
|
+
for (const entry of found) {
|
|
1172
|
+
const item = makeWorkspaceElement(doc, 'li');
|
|
1173
|
+
item.append(makeWorkspaceElement(doc, 'a', { text: entry.excerpt, attrs: { href: entry.href } }));
|
|
1174
|
+
list.append(item);
|
|
1175
|
+
}
|
|
1176
|
+
return list;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
function appendOwnerJudgment(doc, references, memories = null) {
|
|
1152
1180
|
const { owner } = describeJudgmentBasis(references);
|
|
1153
1181
|
const wrap = makeWorkspaceElement(doc, 'div', { className: `bb-jh-owner is-${owner.state}` });
|
|
1154
1182
|
if (owner.state === 'applied') {
|
|
1155
1183
|
wrap.append(makeWorkspaceElement(doc, 'strong', { text: `あなたの判断の材料(個人KG)を${owner.count}件使いました。` }));
|
|
1156
|
-
|
|
1184
|
+
const links = ownerMemoryLinks(doc, references, memories);
|
|
1185
|
+
if (links) {
|
|
1186
|
+
wrap.append(makeWorkspaceElement(doc, 'p', { text: 'この判断には、あなたの考えが入っています。使った記憶はあなたにだけ見えています。' }), links);
|
|
1187
|
+
} else {
|
|
1188
|
+
wrap.append(makeWorkspaceElement(doc, 'p', { text: 'この判断には、あなたの考えが入っています。個人KGの中身はここには出しません。' }));
|
|
1189
|
+
}
|
|
1157
1190
|
} else if (owner.state === 'not_applied') {
|
|
1158
1191
|
wrap.append(makeWorkspaceElement(doc, 'strong', { text: 'あなたの判断の材料(個人KG)は使っていません。' }));
|
|
1159
1192
|
wrap.append(makeWorkspaceElement(doc, 'p', { text: 'Graphの哲学・目的・世界モデルと、AIの判断で進めました。' }));
|
|
@@ -1467,7 +1500,7 @@ function renderNormalRail(doc, rail, row, detail, onClose, options = {}) {
|
|
|
1467
1500
|
}));
|
|
1468
1501
|
rail.append(workspaceRailBlock(doc, {
|
|
1469
1502
|
title: '本人の考え',
|
|
1470
|
-
content: appendOwnerJudgment(doc, record.selectedReferences),
|
|
1503
|
+
content: appendOwnerJudgment(doc, record.selectedReferences, options.personalMemories),
|
|
1471
1504
|
}));
|
|
1472
1505
|
rail.append(workspaceRailBlock(doc, {
|
|
1473
1506
|
title: '判断の理由',
|
|
@@ -1907,6 +1940,10 @@ export function createJudgmentHistoryUI({
|
|
|
1907
1940
|
// Optional host port: (references: {ref, kind}[]) => Promise<Map|object of ref -> name>.
|
|
1908
1941
|
// The host resolves names under the viewer's current permission.
|
|
1909
1942
|
resolveReferenceLabels = null,
|
|
1943
|
+
// Optional owner-only port: (refs: string[]) => Promise<Map|object of ref -> { excerpt, href }>.
|
|
1944
|
+
// A host passes it only to the owner; the 本人の考え block then shows the
|
|
1945
|
+
// opening of each used memory with a link to あなたの記憶.
|
|
1946
|
+
resolvePersonalMemory = null,
|
|
1910
1947
|
} = {}) {
|
|
1911
1948
|
if (!root) throw new TypeError('root is required');
|
|
1912
1949
|
const doc = safeDocument(explicitDocument);
|
|
@@ -1946,6 +1983,7 @@ export function createJudgmentHistoryUI({
|
|
|
1946
1983
|
skeletonTimer: null,
|
|
1947
1984
|
slowTimer: null,
|
|
1948
1985
|
labels: new Map(),
|
|
1986
|
+
personalMemories: new Map(),
|
|
1949
1987
|
};
|
|
1950
1988
|
|
|
1951
1989
|
let filterPopover = null;
|
|
@@ -2254,6 +2292,37 @@ export function createJudgmentHistoryUI({
|
|
|
2254
2292
|
void load({ append: false });
|
|
2255
2293
|
}
|
|
2256
2294
|
|
|
2295
|
+
function requestPersonalMemories(rows) {
|
|
2296
|
+
if (typeof resolvePersonalMemory !== 'function') return;
|
|
2297
|
+
const pending = [];
|
|
2298
|
+
for (const row of rows) {
|
|
2299
|
+
if (row.mode !== 'normal' || !Array.isArray(row.references)) continue;
|
|
2300
|
+
for (const reference of row.references) {
|
|
2301
|
+
const ref = text(reference?.ref);
|
|
2302
|
+
if (!ref || judgmentReferenceKind(reference) !== PERSONAL_KNOWLEDGE_KIND || state.personalMemories.has(ref)) continue;
|
|
2303
|
+
state.personalMemories.set(ref, { status: 'loading' });
|
|
2304
|
+
pending.push(ref);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
if (!pending.length) return;
|
|
2308
|
+
const settle = (resolved) => {
|
|
2309
|
+
if (state.disposed) return;
|
|
2310
|
+
const lookup = resolved instanceof Map
|
|
2311
|
+
? (ref) => resolved.get(ref)
|
|
2312
|
+
: isRecord(resolved) ? (ref) => resolved[ref] : () => null;
|
|
2313
|
+
for (const ref of pending) {
|
|
2314
|
+
const entry = lookup(ref);
|
|
2315
|
+
const excerpt = isRecord(entry) ? personalMemoryExcerpt(entry.excerpt) : '';
|
|
2316
|
+
const href = isRecord(entry) ? text(entry.href) : '';
|
|
2317
|
+
state.personalMemories.set(ref, excerpt && href ? { status: 'found', excerpt, href } : { status: 'missing' });
|
|
2318
|
+
}
|
|
2319
|
+
render();
|
|
2320
|
+
};
|
|
2321
|
+
Promise.resolve()
|
|
2322
|
+
.then(() => resolvePersonalMemory([...pending]))
|
|
2323
|
+
.then(settle, () => settle(null));
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2257
2326
|
function requestReferenceLabels(rows) {
|
|
2258
2327
|
const pending = [];
|
|
2259
2328
|
for (const row of rows) {
|
|
@@ -2440,6 +2509,7 @@ export function createJudgmentHistoryUI({
|
|
|
2440
2509
|
? 'この期間に取得できた判断履歴はありません。全件数が未確認のため0件とは確認できません。'
|
|
2441
2510
|
: 'この期間の判断履歴はありません。';
|
|
2442
2511
|
requestReferenceLabels(aggregate.rows);
|
|
2512
|
+
requestPersonalMemories(aggregate.rows);
|
|
2443
2513
|
const dataRows = makeRows(doc, aggregate, state.selectedKey, (key) => {
|
|
2444
2514
|
state.lastFocusedKey = key;
|
|
2445
2515
|
state.selectedKey = key;
|
|
@@ -2507,6 +2577,7 @@ export function createJudgmentHistoryUI({
|
|
|
2507
2577
|
onSubmitFeedback: (controls) => void submitFeedback(selected, controls),
|
|
2508
2578
|
onCopyReference: (payload) => void copyReference(payload),
|
|
2509
2579
|
labels: state.labels,
|
|
2580
|
+
personalMemories: state.personalMemories,
|
|
2510
2581
|
}
|
|
2511
2582
|
: {};
|
|
2512
2583
|
if (nativeDrawer) {
|
package/ui/local-web-shell.css
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@import './native-scrollbars.css';
|
|
2
|
+
@import './area-nav.css';
|
|
2
3
|
/*
|
|
3
4
|
* Shell of the local Web host, in the organization edition's layout: a white
|
|
4
5
|
* left rail (brand, navigation, source) and a paper workspace. Uses only the
|
|
@@ -71,19 +72,6 @@ body {
|
|
|
71
72
|
gap: 2px;
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
.bb-shell-nav-group {
|
|
75
|
-
display: grid;
|
|
76
|
-
gap: 2px;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.bb-shell-nav-group-head {
|
|
80
|
-
margin: 14px 10px 4px;
|
|
81
|
-
color: var(--bb-color-rail-muted);
|
|
82
|
-
font-size: 11px;
|
|
83
|
-
font-weight: 700;
|
|
84
|
-
letter-spacing: .04em;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
75
|
.bb-shell-nav-link {
|
|
88
76
|
min-height: 38px;
|
|
89
77
|
display: flex;
|