@unson/brainbase-mcp 0.10.3 → 0.10.4
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/project-workspace.js +101 -52
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unson/brainbase-mcp",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.4",
|
|
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",
|
|
@@ -336,5 +336,5 @@
|
|
|
336
336
|
"engines": {
|
|
337
337
|
"node": ">=20"
|
|
338
338
|
},
|
|
339
|
-
"gitHead": "
|
|
339
|
+
"gitHead": "84863f09b8274b738b16e15d2550ece19ac51124"
|
|
340
340
|
}
|
package/ui/project-workspace.js
CHANGED
|
@@ -325,16 +325,62 @@ function contextSectionSkeleton(doc, { title = null, message = null } = {}) {
|
|
|
325
325
|
return group;
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
function renderProjectContextGroup(doc, item) {
|
|
329
|
+
const group = makeElement(doc, 'section', {
|
|
330
|
+
className: `bb-pkw-context-group${item.state === 'loading' ? ' bb-pkw-context-group-loading' : ''}`,
|
|
331
|
+
attrs: { 'aria-label': item.title, ...(item.state === 'loading' ? { 'aria-busy': 'true' } : {}) },
|
|
332
|
+
});
|
|
333
|
+
const heading = makeElement(doc, 'div', { className: 'bb-pkw-context-heading' });
|
|
334
|
+
heading.append(makeElement(doc, 'h4', { text: item.title }), badge(doc, item.state === 'ok' ? '利用可能' : item.state === 'loading' ? '読み込み中' : item.state === 'failed' ? '読み取り失敗' : '未接続', item.state === 'ok' ? 'success' : item.state === 'failed' ? 'danger' : 'muted'));
|
|
335
|
+
group.append(heading);
|
|
336
|
+
if (item.message && !['failed', 'unavailable'].includes(item.state)) group.append(makeElement(doc, 'p', { className: 'bb-pkw-muted', text: item.message }));
|
|
337
|
+
if (item.asOf) group.append(makeElement(doc, 'small', { className: 'bb-pkw-muted', text: `読み取った時点: ${formatDateTime(item.asOf)}` }));
|
|
338
|
+
if (item.state === 'loading') {
|
|
339
|
+
group.append(skeletonBars(doc));
|
|
340
|
+
} else if (item.state === 'failed') {
|
|
341
|
+
group.append(workspaceNotice(doc, { label: '読み取り失敗', text: item.message ?? 'このセクションを読み取れませんでした。', tone: 'danger', role: 'alert' }));
|
|
342
|
+
} else if (item.state === 'unavailable') {
|
|
343
|
+
group.append(workspaceNotice(doc, { label: '未接続', text: item.message ?? 'このセクションは接続されていません。', tone: 'warning' }));
|
|
344
|
+
} else if (item.items.length > 0) {
|
|
345
|
+
const list = makeElement(doc, 'ul', { className: 'bb-pkw-context-list' });
|
|
346
|
+
for (const entry of item.items) {
|
|
347
|
+
const row = makeElement(doc, 'li');
|
|
348
|
+
row.append(makeElement(doc, 'strong', { text: entry.title }));
|
|
349
|
+
if (entry.status) row.append(badge(doc, entry.status, 'muted'));
|
|
350
|
+
const facts = [entry.summary, entry.owner ? `担当: ${entry.owner}` : null, entry.dueAt ? `期限: ${entry.dueAt}` : null, entry.updatedAt ? `更新: ${entry.updatedAt}` : null, entry.source ? `出典: ${entry.source}` : null].filter(Boolean);
|
|
351
|
+
if (facts.length > 0) row.append(makeElement(doc, 'p', { className: 'bb-pkw-muted', text: facts.join(' · ') }));
|
|
352
|
+
list.append(row);
|
|
353
|
+
}
|
|
354
|
+
group.append(list);
|
|
355
|
+
} else if (item.state === 'ok') {
|
|
356
|
+
group.append(makeElement(doc, 'p', { className: 'bb-pkw-muted', text: 'このセクションに表示できる記録はありません。' }));
|
|
357
|
+
}
|
|
358
|
+
return group;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function projectContextInsertionAnchor(doc) {
|
|
362
|
+
return makeElement(doc, 'span', {
|
|
363
|
+
className: 'bb-pkw-context-anchor',
|
|
364
|
+
attrs: { 'aria-hidden': 'true', hidden: 'true' },
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
328
368
|
/** Renders supplementary context while preserving each section's own state. */
|
|
329
|
-
export function renderProjectContext(doc, context
|
|
369
|
+
export function renderProjectContext(doc, context, {
|
|
370
|
+
sections: selectedSections = null,
|
|
371
|
+
includeStatus = true,
|
|
372
|
+
includeHeading = true,
|
|
373
|
+
} = {}) {
|
|
330
374
|
if (!context) return null;
|
|
331
|
-
const sections = Array.isArray(
|
|
375
|
+
const sections = Array.isArray(selectedSections)
|
|
376
|
+
? selectedSections
|
|
377
|
+
: Array.isArray(context.sections) ? context.sections : [];
|
|
332
378
|
const section = makeElement(doc, 'section', {
|
|
333
379
|
className: 'bb-pkw-section bb-pkw-context',
|
|
334
380
|
attrs: { 'aria-label': '補足情報' },
|
|
335
381
|
});
|
|
336
|
-
section.append(makeElement(doc, 'h3', { text: '補足情報' }));
|
|
337
|
-
if (context.state !== 'ok') {
|
|
382
|
+
if (includeHeading) section.append(makeElement(doc, 'h3', { text: '補足情報' }));
|
|
383
|
+
if (includeStatus && context.state !== 'ok') {
|
|
338
384
|
if (context.state === 'loading') {
|
|
339
385
|
section.append(workspaceNotice(doc, { label: '読み込み中', text: context.message ?? '補足情報を読み込んでいます。', tone: 'info', role: 'status' }));
|
|
340
386
|
if (sections.length === 0) section.append(contextSectionSkeleton(doc));
|
|
@@ -342,42 +388,11 @@ export function renderProjectContext(doc, context) {
|
|
|
342
388
|
section.append(workspaceNotice(doc, { label: context.state === 'failed' ? '読み取り失敗' : '未接続', text: context.message ?? '補足情報を確認できません。', tone: context.state === 'failed' ? 'danger' : 'warning' }));
|
|
343
389
|
}
|
|
344
390
|
}
|
|
345
|
-
if (context.state === 'ok' && sections.length === 0) {
|
|
391
|
+
if (includeStatus && context.state === 'ok' && sections.length === 0) {
|
|
346
392
|
section.append(makeElement(doc, 'p', { className: 'bb-pkw-muted', text: '補足情報のセクションはありません。' }));
|
|
347
393
|
return section;
|
|
348
394
|
}
|
|
349
|
-
for (const item of sections)
|
|
350
|
-
const group = makeElement(doc, 'section', {
|
|
351
|
-
className: `bb-pkw-context-group${item.state === 'loading' ? ' bb-pkw-context-group-loading' : ''}`,
|
|
352
|
-
attrs: { 'aria-label': item.title, ...(item.state === 'loading' ? { 'aria-busy': 'true' } : {}) },
|
|
353
|
-
});
|
|
354
|
-
const heading = makeElement(doc, 'div', { className: 'bb-pkw-context-heading' });
|
|
355
|
-
heading.append(makeElement(doc, 'h4', { text: item.title }), badge(doc, item.state === 'ok' ? '利用可能' : item.state === 'loading' ? '読み込み中' : item.state === 'failed' ? '読み取り失敗' : '未接続', item.state === 'ok' ? 'success' : item.state === 'failed' ? 'danger' : 'muted'));
|
|
356
|
-
group.append(heading);
|
|
357
|
-
if (item.message && !['failed', 'unavailable'].includes(item.state)) group.append(makeElement(doc, 'p', { className: 'bb-pkw-muted', text: item.message }));
|
|
358
|
-
if (item.asOf) group.append(makeElement(doc, 'small', { className: 'bb-pkw-muted', text: `読み取った時点: ${formatDateTime(item.asOf)}` }));
|
|
359
|
-
if (item.state === 'loading') {
|
|
360
|
-
group.append(skeletonBars(doc));
|
|
361
|
-
} else if (item.state === 'failed') {
|
|
362
|
-
group.append(workspaceNotice(doc, { label: '読み取り失敗', text: item.message ?? 'このセクションを読み取れませんでした。', tone: 'danger', role: 'alert' }));
|
|
363
|
-
} else if (item.state === 'unavailable') {
|
|
364
|
-
group.append(workspaceNotice(doc, { label: '未接続', text: item.message ?? 'このセクションは接続されていません。', tone: 'warning' }));
|
|
365
|
-
} else if (item.items.length > 0) {
|
|
366
|
-
const list = makeElement(doc, 'ul', { className: 'bb-pkw-context-list' });
|
|
367
|
-
for (const entry of item.items) {
|
|
368
|
-
const row = makeElement(doc, 'li');
|
|
369
|
-
row.append(makeElement(doc, 'strong', { text: entry.title }));
|
|
370
|
-
if (entry.status) row.append(badge(doc, entry.status, 'muted'));
|
|
371
|
-
const facts = [entry.summary, entry.owner ? `担当: ${entry.owner}` : null, entry.dueAt ? `期限: ${entry.dueAt}` : null, entry.updatedAt ? `更新: ${entry.updatedAt}` : null, entry.source ? `出典: ${entry.source}` : null].filter(Boolean);
|
|
372
|
-
if (facts.length > 0) row.append(makeElement(doc, 'p', { className: 'bb-pkw-muted', text: facts.join(' · ') }));
|
|
373
|
-
list.append(row);
|
|
374
|
-
}
|
|
375
|
-
group.append(list);
|
|
376
|
-
} else if (item.state === 'ok') {
|
|
377
|
-
group.append(makeElement(doc, 'p', { className: 'bb-pkw-muted', text: 'このセクションに表示できる記録はありません。' }));
|
|
378
|
-
}
|
|
379
|
-
section.append(group);
|
|
380
|
-
}
|
|
395
|
+
for (const item of sections) section.append(renderProjectContextGroup(doc, item));
|
|
381
396
|
return section;
|
|
382
397
|
}
|
|
383
398
|
|
|
@@ -387,6 +402,12 @@ export function renderProjectKnowledgeSkeleton(doc, { context = null } = {}) {
|
|
|
387
402
|
className: 'bb-pkw-panel bb-pkw-overview bb-pkw-overview-loading',
|
|
388
403
|
attrs: { 'aria-label': '概要' },
|
|
389
404
|
});
|
|
405
|
+
const contextSections = Array.isArray(context?.sections) ? context.sections : [];
|
|
406
|
+
const readySections = contextSections.filter((item) => item?.state === 'ok' && Array.isArray(item.items) && item.items.length > 0);
|
|
407
|
+
const deferredSections = contextSections.filter((item) => !readySections.includes(item));
|
|
408
|
+
if (readySections.length > 0) {
|
|
409
|
+
panel.append(renderProjectContext(doc, context, { sections: readySections, includeStatus: false }));
|
|
410
|
+
}
|
|
390
411
|
const columns = makeElement(doc, 'div', { className: 'bb-pkw-columns' });
|
|
391
412
|
for (const title of ['目的と現在地', '関係者と役割']) {
|
|
392
413
|
const item = makeElement(doc, 'section', { className: 'bb-pkw-section bb-pkw-skeleton-section', attrs: { 'aria-label': title, 'aria-busy': 'true' } });
|
|
@@ -399,7 +420,9 @@ export function renderProjectKnowledgeSkeleton(doc, { context = null } = {}) {
|
|
|
399
420
|
item.append(makeElement(doc, 'h3', { text: title }), skeletonBars(doc, 2));
|
|
400
421
|
panel.append(item);
|
|
401
422
|
}
|
|
402
|
-
const contextBlock =
|
|
423
|
+
const contextBlock = readySections.length > 0
|
|
424
|
+
? (deferredSections.length > 0 ? renderProjectContext(doc, context, { sections: deferredSections, includeHeading: false }) : null)
|
|
425
|
+
: renderProjectContext(doc, context ?? { state: 'loading', sections: [] });
|
|
403
426
|
if (contextBlock) panel.append(contextBlock);
|
|
404
427
|
return panel;
|
|
405
428
|
}
|
|
@@ -439,6 +462,16 @@ function renderOverview(doc, detail, context, edges, entities, onSelect, onConte
|
|
|
439
462
|
columns.append(people);
|
|
440
463
|
panel.append(columns);
|
|
441
464
|
|
|
465
|
+
const contextBlock = renderProjectContext(doc, context);
|
|
466
|
+
if (contextBlock) {
|
|
467
|
+
panel.append(contextBlock);
|
|
468
|
+
if (typeof onContext === 'function') onContext(contextBlock, null);
|
|
469
|
+
} else {
|
|
470
|
+
const contextAnchor = projectContextInsertionAnchor(doc);
|
|
471
|
+
panel.append(contextAnchor);
|
|
472
|
+
if (typeof onContext === 'function') onContext(null, contextAnchor);
|
|
473
|
+
}
|
|
474
|
+
|
|
442
475
|
const decisions = makeElement(doc, 'section', { className: 'bb-pkw-section', attrs: { 'aria-label': '記録された判断' } });
|
|
443
476
|
decisions.append(makeElement(doc, 'h3', { text: '記録された判断' }));
|
|
444
477
|
const decisionEdges = edges.filter((edge) => entities.get(edge.source)?.type === 'decision' || entities.get(edge.target)?.type === 'decision');
|
|
@@ -493,11 +526,6 @@ function renderOverview(doc, detail, context, edges, entities, onSelect, onConte
|
|
|
493
526
|
missing.append(list);
|
|
494
527
|
panel.append(missing);
|
|
495
528
|
}
|
|
496
|
-
const contextBlock = renderProjectContext(doc, context);
|
|
497
|
-
if (contextBlock) {
|
|
498
|
-
panel.append(contextBlock);
|
|
499
|
-
if (typeof onContext === 'function') onContext(contextBlock);
|
|
500
|
-
}
|
|
501
529
|
return panel;
|
|
502
530
|
}
|
|
503
531
|
|
|
@@ -543,8 +571,16 @@ export function createProjectKnowledgeWorkspace({
|
|
|
543
571
|
let selectedPanel = null;
|
|
544
572
|
let overviewPanel = null;
|
|
545
573
|
let contextBlock = null;
|
|
546
|
-
|
|
547
|
-
|
|
574
|
+
let contextAnchor = null;
|
|
575
|
+
|
|
576
|
+
const root = makeElement(doc, 'section', {
|
|
577
|
+
className: 'bb-pkw',
|
|
578
|
+
attrs: {
|
|
579
|
+
'data-contract-version': PROJECT_WORKSPACE_CONTRACT_VERSION,
|
|
580
|
+
'data-project-id': cleanId(project.id),
|
|
581
|
+
'aria-label': 'プロジェクトの知識',
|
|
582
|
+
},
|
|
583
|
+
});
|
|
548
584
|
const body = makeElement(doc, 'div', { className: 'bb-pkw-body' });
|
|
549
585
|
const tabs = makeElement(doc, 'div', { className: 'bb-pkw-tabs', attrs: { role: 'tablist', 'aria-label': 'プロジェクト情報の表示' } });
|
|
550
586
|
const panels = makeElement(doc, 'div', { className: 'bb-pkw-panels' });
|
|
@@ -779,8 +815,15 @@ export function createProjectKnowledgeWorkspace({
|
|
|
779
815
|
if (destroyed) return;
|
|
780
816
|
const nextBlock = renderProjectContext(doc, currentContext);
|
|
781
817
|
if (!nextBlock) {
|
|
782
|
-
if (contextBlock?.parentNode
|
|
783
|
-
|
|
818
|
+
if (contextBlock?.parentNode && typeof contextBlock.parentNode.replaceChild === 'function') {
|
|
819
|
+
const nextAnchor = projectContextInsertionAnchor(doc);
|
|
820
|
+
contextBlock.parentNode.replaceChild(nextAnchor, contextBlock);
|
|
821
|
+
contextBlock = null;
|
|
822
|
+
contextAnchor = nextAnchor;
|
|
823
|
+
} else if (contextBlock?.parentNode?.removeChild) {
|
|
824
|
+
contextBlock.parentNode.removeChild(contextBlock);
|
|
825
|
+
contextBlock = null;
|
|
826
|
+
}
|
|
784
827
|
return;
|
|
785
828
|
}
|
|
786
829
|
if (contextBlock?.parentNode && typeof contextBlock.parentNode.replaceChild === 'function') {
|
|
@@ -788,14 +831,16 @@ export function createProjectKnowledgeWorkspace({
|
|
|
788
831
|
contextBlock = nextBlock;
|
|
789
832
|
return;
|
|
790
833
|
}
|
|
791
|
-
if (
|
|
792
|
-
|
|
834
|
+
if (contextAnchor?.parentNode && typeof contextAnchor.parentNode.replaceChild === 'function') {
|
|
835
|
+
contextAnchor.parentNode.replaceChild(nextBlock, contextAnchor);
|
|
793
836
|
contextBlock = nextBlock;
|
|
837
|
+
contextAnchor = null;
|
|
794
838
|
return;
|
|
795
839
|
}
|
|
796
|
-
if (
|
|
797
|
-
|
|
840
|
+
if (contextBlock?.replaceWith) {
|
|
841
|
+
contextBlock.replaceWith(nextBlock);
|
|
798
842
|
contextBlock = nextBlock;
|
|
843
|
+
return;
|
|
799
844
|
}
|
|
800
845
|
}
|
|
801
846
|
|
|
@@ -806,7 +851,11 @@ export function createProjectKnowledgeWorkspace({
|
|
|
806
851
|
tabs.replaceChildren(tabButton('概要', 'overview'), tabButton('情報を探す', 'graph'));
|
|
807
852
|
panels.replaceChildren();
|
|
808
853
|
contextBlock = null;
|
|
809
|
-
|
|
854
|
+
contextAnchor = null;
|
|
855
|
+
const overview = renderOverview(doc, payload, currentContext, overviewEdges, overviewEntities, selectAndExplore, (node, anchor) => {
|
|
856
|
+
contextBlock = node;
|
|
857
|
+
contextAnchor = anchor;
|
|
858
|
+
});
|
|
810
859
|
overview.id = 'bb-pkw-panel-overview';
|
|
811
860
|
overview.hidden = activeTab !== 'overview';
|
|
812
861
|
overviewPanel = overview;
|