@unson/brainbase-mcp 0.22.5 → 0.22.6
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/package.json +2 -2
- package/ui/foundation-overview.css +3 -0
- package/ui/foundation-overview.js +99 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unson/brainbase-mcp",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.6",
|
|
4
4
|
"description": "Local-first Brainbase judgment OS that lets supported AI agents reuse a user's approved goals, priorities, decisions, and judgment criteria.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -407,5 +407,5 @@
|
|
|
407
407
|
"engines": {
|
|
408
408
|
"node": ">=20"
|
|
409
409
|
},
|
|
410
|
-
"gitHead": "
|
|
410
|
+
"gitHead": "2a650ddc4aa96a2a2b8c1fa99eb231750fabbc57"
|
|
411
411
|
}
|
|
@@ -234,3 +234,6 @@
|
|
|
234
234
|
grid-template-columns: minmax(90px, .55fr) minmax(0, 1fr);
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
|
+
|
|
238
|
+
/* Catalog provenance is secondary to the topic, but remains visible on every card. */
|
|
239
|
+
.bb-fov-source { display: inline-block; margin: 0 0 12px; padding: 4px 10px; border-radius: 999px; background: var(--bb-surface-subtle, #f4f4f8); color: var(--bb-text-muted, #62626e); font-size: 12px; overflow-wrap: anywhere; }
|
|
@@ -415,7 +415,7 @@ function objectiveCard(doc, record, variableMap) {
|
|
|
415
415
|
return card;
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
-
function renderObjectives(doc, catalog, viewState, callbacks) {
|
|
418
|
+
function renderObjectives(doc, catalog, viewState, callbacks, recordContexts) {
|
|
419
419
|
const section = makeElement(doc, 'section', { className: 'bb-fov-section', attrs: { 'aria-label': '目的' } });
|
|
420
420
|
section.append(workspaceSectionTitle(doc, {
|
|
421
421
|
title: '目的',
|
|
@@ -429,7 +429,7 @@ function renderObjectives(doc, catalog, viewState, callbacks) {
|
|
|
429
429
|
const rows = catalog.objectives.map((record) => {
|
|
430
430
|
const definition = recordDefinition(record);
|
|
431
431
|
const details = detailsFor(record);
|
|
432
|
-
const key = `${definition.id}@${definition.revision}`;
|
|
432
|
+
const key = recordContexts?.get(record)?.key ?? `${definition.id}@${definition.revision}`;
|
|
433
433
|
return {
|
|
434
434
|
key,
|
|
435
435
|
selected: key === viewState.objectiveKey,
|
|
@@ -438,7 +438,7 @@ function renderObjectives(doc, catalog, viewState, callbacks) {
|
|
|
438
438
|
callbacks.render?.();
|
|
439
439
|
},
|
|
440
440
|
cells: [
|
|
441
|
-
{ primary: formatAny(firstValue(details, 'title')) ?? formatAny(definition.meaning) ?? definition.id, secondary: `${definition.id}@${definition.revision}` },
|
|
441
|
+
{ primary: formatAny(firstValue(details, 'title')) ?? formatAny(definition.meaning) ?? definition.id, secondary: recordContexts?.get(record)?.label ?? `${definition.id}@${definition.revision}` },
|
|
442
442
|
formatAny(definition.desiredState) ?? '目指す状態: 未記録',
|
|
443
443
|
formatAny(definition.adoptionState) ? (ADOPTION_LABELS[definition.adoptionState] ?? definition.adoptionState) : '状態未確認',
|
|
444
444
|
],
|
|
@@ -452,18 +452,21 @@ function renderObjectives(doc, catalog, viewState, callbacks) {
|
|
|
452
452
|
}));
|
|
453
453
|
const selected = catalog.objectives.find((record) => {
|
|
454
454
|
const definition = recordDefinition(record);
|
|
455
|
-
return `${definition.id}@${definition.revision}` === viewState.objectiveKey;
|
|
456
|
-
}) ?? catalog.objectives[0];
|
|
455
|
+
return (recordContexts?.get(record)?.key ?? `${definition.id}@${definition.revision}`) === viewState.objectiveKey;
|
|
456
|
+
}) ?? (recordContexts ? null : catalog.objectives[0]);
|
|
457
|
+
if (!selected && recordContexts) section.append(makeElement(doc, 'p', { className: 'bb-fov-recorded-notice', text: '目的の行を選ぶと、評価基準と記録上の現状を確認できます。' }));
|
|
457
458
|
if (selected) {
|
|
458
459
|
const selectedDefinition = recordDefinition(selected);
|
|
459
|
-
viewState.objectiveKey = `${selectedDefinition.id}@${selectedDefinition.revision}`;
|
|
460
|
+
viewState.objectiveKey = recordContexts?.get(selected)?.key ?? `${selectedDefinition.id}@${selectedDefinition.revision}`;
|
|
460
461
|
if (catalog.objectives.length > 1) {
|
|
461
462
|
section.append(workspaceNotice(doc, {
|
|
462
463
|
label: '詳細表示',
|
|
463
464
|
text: `目的${catalog.objectives.length}件のうち1件を選択して詳細を表示しています。`,
|
|
464
465
|
}));
|
|
465
466
|
}
|
|
466
|
-
|
|
467
|
+
const card = objectiveCard(doc, selected, recordContexts?.get(selected)?.variableMap ?? variableMap);
|
|
468
|
+
appendRecordSource(doc, card, selected, recordContexts);
|
|
469
|
+
section.append(card);
|
|
467
470
|
}
|
|
468
471
|
return section;
|
|
469
472
|
}
|
|
@@ -504,7 +507,7 @@ function philosophyCard(doc, record) {
|
|
|
504
507
|
return card;
|
|
505
508
|
}
|
|
506
509
|
|
|
507
|
-
function renderPhilosophies(doc, catalog) {
|
|
510
|
+
function renderPhilosophies(doc, catalog, recordContexts) {
|
|
508
511
|
const section = makeElement(doc, 'section', { className: 'bb-fov-section', attrs: { 'aria-label': '哲学' } });
|
|
509
512
|
section.append(workspaceSectionTitle(doc, {
|
|
510
513
|
title: '哲学',
|
|
@@ -515,7 +518,11 @@ function renderPhilosophies(doc, catalog) {
|
|
|
515
518
|
return section;
|
|
516
519
|
}
|
|
517
520
|
const grid = makeElement(doc, 'div', { className: 'bb-fov-philosophy-grid' });
|
|
518
|
-
for (const record of catalog.philosophies)
|
|
521
|
+
for (const record of catalog.philosophies) {
|
|
522
|
+
const card = philosophyCard(doc, record);
|
|
523
|
+
appendRecordSource(doc, card, record, recordContexts);
|
|
524
|
+
grid.append(card);
|
|
525
|
+
}
|
|
519
526
|
section.append(grid);
|
|
520
527
|
return section;
|
|
521
528
|
}
|
|
@@ -569,7 +576,7 @@ function modelCard(doc, record, variableMap) {
|
|
|
569
576
|
return card;
|
|
570
577
|
}
|
|
571
578
|
|
|
572
|
-
function renderModels(doc, catalog, viewState, callbacks) {
|
|
579
|
+
function renderModels(doc, catalog, viewState, callbacks, recordContexts) {
|
|
573
580
|
const section = makeElement(doc, 'section', { className: 'bb-fov-section', attrs: { 'aria-label': '世界モデル' } });
|
|
574
581
|
section.append(workspaceSectionTitle(doc, {
|
|
575
582
|
title: '世界モデル',
|
|
@@ -595,7 +602,7 @@ function renderModels(doc, catalog, viewState, callbacks) {
|
|
|
595
602
|
const renderResults = () => {
|
|
596
603
|
results.replaceChildren();
|
|
597
604
|
const query = viewState.query.trim().toLocaleLowerCase();
|
|
598
|
-
const filtered = query ? catalog.models.filter((record) => searchTextForModel(record).includes(query)) : catalog.models;
|
|
605
|
+
const filtered = query ? catalog.models.filter((record) => `${searchTextForModel(record)} ${recordContexts?.get(record)?.label ?? ""}`.toLocaleLowerCase().includes(query)) : catalog.models;
|
|
599
606
|
if (filtered.length === 0) {
|
|
600
607
|
results.append(workspaceNotice(doc, { label: '検索結果', text: query ? '条件に一致する世界モデルはありません。' : 'この対象範囲には登録された世界モデルがありません。' }));
|
|
601
608
|
return;
|
|
@@ -610,7 +617,11 @@ function renderModels(doc, catalog, viewState, callbacks) {
|
|
|
610
617
|
}));
|
|
611
618
|
const variableMap = new Map(catalog.variables.map((record) => [foundationKey(recordDefinition(record)), record]));
|
|
612
619
|
const cards = makeElement(doc, 'div', { className: 'bb-fov-model-grid' });
|
|
613
|
-
for (const record of pageItems)
|
|
620
|
+
for (const record of pageItems) {
|
|
621
|
+
const card = modelCard(doc, record, recordContexts?.get(record)?.variableMap ?? variableMap);
|
|
622
|
+
appendRecordSource(doc, card, record, recordContexts);
|
|
623
|
+
cards.append(card);
|
|
624
|
+
}
|
|
614
625
|
results.append(cards);
|
|
615
626
|
if (pages > 1) {
|
|
616
627
|
const pager = makeElement(doc, 'nav', { className: 'bb-fov-pager', attrs: { 'aria-label': '世界モデルのページ' } });
|
|
@@ -655,6 +666,8 @@ export function renderFoundationOverview(root, state, {
|
|
|
655
666
|
viewState = { query: '', page: 0 },
|
|
656
667
|
callbacks = {},
|
|
657
668
|
showHeader = true,
|
|
669
|
+
recordContexts,
|
|
670
|
+
partial = false,
|
|
658
671
|
} = {}) {
|
|
659
672
|
if (!root) throw new TypeError('root is required');
|
|
660
673
|
const doc = getDocument(explicitDocument);
|
|
@@ -671,7 +684,7 @@ export function renderFoundationOverview(root, state, {
|
|
|
671
684
|
source: `正本: ${scopeId}`,
|
|
672
685
|
}));
|
|
673
686
|
}
|
|
674
|
-
surface.append(workspaceNotice(doc, {
|
|
687
|
+
if (!recordContexts) surface.append(workspaceNotice(doc, {
|
|
675
688
|
label: '対象範囲',
|
|
676
689
|
text: scopeId,
|
|
677
690
|
}));
|
|
@@ -686,22 +699,85 @@ export function renderFoundationOverview(root, state, {
|
|
|
686
699
|
return surface;
|
|
687
700
|
}
|
|
688
701
|
const catalog = state.catalog;
|
|
689
|
-
surface.append(workspaceNotice(doc, {
|
|
690
|
-
|
|
691
|
-
text: '
|
|
692
|
-
|
|
702
|
+
if (partial) surface.append(workspaceNotice(doc, { label: '取得済みの範囲', text: '以下の件数・登録なし・検索結果は、取得できた記録だけを対象にしています。全体は未確認です。' }));
|
|
703
|
+
surface.append(recordContexts
|
|
704
|
+
? makeElement(doc, 'p', { className: 'bb-fov-recorded-notice', text: '記録上の現状は保存時点の記述です。登録状態と検証状態を分けて読みます。' })
|
|
705
|
+
: workspaceNotice(doc, { label: '読み方', text: '登録は達成・採用・検証済みを意味しません。記録上の現状は保存時点の記述です。' }));
|
|
693
706
|
surface.append(workspaceMetrics(doc, [
|
|
694
|
-
{ label: '目的', value: catalog.objectives.length, note: '登録された定義' },
|
|
695
|
-
{ label: '哲学', value: catalog.philosophies.length, note: '登録された版' },
|
|
696
|
-
{ label: '世界モデル', value: catalog.models.length, note: '検索対象' },
|
|
707
|
+
{ label: '目的', value: catalog.objectives.length, note: partial ? '取得済みの定義(全体は未確認)' : '登録された定義' },
|
|
708
|
+
{ label: '哲学', value: catalog.philosophies.length, note: partial ? '取得済みの版(全体は未確認)' : '登録された版' },
|
|
709
|
+
{ label: '世界モデル', value: catalog.models.length, note: partial ? '取得済みの検索対象(全体は未確認)' : '検索対象' },
|
|
697
710
|
], { ariaLabel: 'Foundationの登録数' }));
|
|
698
|
-
surface.append(renderObjectives(doc, catalog, viewState, callbacks));
|
|
699
|
-
surface.append(renderPhilosophies(doc, catalog));
|
|
700
|
-
surface.append(renderModels(doc, catalog, viewState, callbacks));
|
|
711
|
+
surface.append(renderObjectives(doc, catalog, viewState, callbacks, recordContexts));
|
|
712
|
+
surface.append(renderPhilosophies(doc, catalog, recordContexts));
|
|
713
|
+
surface.append(renderModels(doc, catalog, viewState, callbacks, recordContexts));
|
|
701
714
|
root.append(surface);
|
|
702
715
|
return surface;
|
|
703
716
|
}
|
|
704
717
|
|
|
718
|
+
function appendRecordSource(doc, card, record, contexts) {
|
|
719
|
+
const context = contexts?.get(record);
|
|
720
|
+
if (context) card.prepend(makeElement(doc, 'p', { className: 'bb-fov-source', text: context.label }));
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/** Compose independently validated catalogs by topic, preserving each reference's source context. */
|
|
724
|
+
export function renderFoundationCollectionOverview(root, sources, {
|
|
725
|
+
document: explicitDocument, viewState = { query: '', page: 0 }, callbacks = {}, scopeLabel = '全体',
|
|
726
|
+
} = {}) {
|
|
727
|
+
const doc = getDocument(explicitDocument);
|
|
728
|
+
root.replaceChildren();
|
|
729
|
+
const catalog = { objectives: [], variables: [], models: [], philosophies: [] };
|
|
730
|
+
const contexts = new WeakMap();
|
|
731
|
+
const seen = new Map();
|
|
732
|
+
let ready = 0;
|
|
733
|
+
for (const source of sources) {
|
|
734
|
+
if (source.state.status !== 'ready') {
|
|
735
|
+
const notice = workspaceNotice(doc, {
|
|
736
|
+
label: source.label,
|
|
737
|
+
text: source.state.status === 'loading' ? '目的・哲学・世界モデルを読み込んでいます。'
|
|
738
|
+
: `取得失敗: ${source.state.error?.message ?? 'この対象は未確認です。0件ではありません。'}`,
|
|
739
|
+
tone: source.state.status === 'loading' ? 'info' : 'danger',
|
|
740
|
+
});
|
|
741
|
+
notice.append(workspaceButton(doc, { text: '再試行', variant: 'quiet', onClick: callbacks.load }));
|
|
742
|
+
root.append(notice);
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
const value = normalizeFoundationCatalog(source.state.catalog, source.scopeId);
|
|
746
|
+
ready++;
|
|
747
|
+
const variableMap = new Map(value.variables.map((record) => [foundationKey(recordDefinition(record)), record]));
|
|
748
|
+
for (const kind of ['objectives', 'models', 'philosophies']) {
|
|
749
|
+
for (const original of value[kind]) {
|
|
750
|
+
const definition = original.definition ?? original;
|
|
751
|
+
const scope = original.scope ?? original.currentScope ?? definition.scope;
|
|
752
|
+
// Scope-less/project records remain tied to their authenticated catalog.
|
|
753
|
+
const shared = ['organization', 'organisation', 'company'].includes(scope?.type) && nonEmpty(scope?.id);
|
|
754
|
+
const key = JSON.stringify([kind, shared ? scope.type : 'project', shared ? scope.id : source.scopeId,
|
|
755
|
+
definition.id, definition.revision, original.digest]);
|
|
756
|
+
const existing = seen.get(key);
|
|
757
|
+
if (existing) {
|
|
758
|
+
const context = contexts.get(existing);
|
|
759
|
+
if (!context.sources.includes(source.label)) context.sources.push(source.label);
|
|
760
|
+
context.label = `${shared ? '組織共通 / ' : ''}${context.sources.join('・')}`;
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
const record = { ...original };
|
|
764
|
+
seen.set(key, record);
|
|
765
|
+
catalog[kind].push(record);
|
|
766
|
+
contexts.set(record, { key, variableMap, sources: [source.label], label: `${shared ? '組織共通 / ' : ''}${source.label}` });
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
if (ready) {
|
|
771
|
+
const mount = makeElement(doc, 'div');
|
|
772
|
+
renderFoundationOverview(mount, { status: 'ready', catalog }, {
|
|
773
|
+
document: doc, scopeId: scopeLabel, showHeader: false, viewState, callbacks,
|
|
774
|
+
recordContexts: contexts, partial: ready !== sources.length,
|
|
775
|
+
});
|
|
776
|
+
root.append(mount);
|
|
777
|
+
}
|
|
778
|
+
return root;
|
|
779
|
+
}
|
|
780
|
+
|
|
705
781
|
/** Mount the read-only overview and ignore responses from a destroyed generation. */
|
|
706
782
|
export function createFoundationOverview({ root, port, scopeId, document: explicitDocument, autoLoad = true, showHeader = true } = {}) {
|
|
707
783
|
if (!root) throw new TypeError('root is required');
|