@unson/brainbase-mcp 0.10.8 → 0.10.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unson/brainbase-mcp",
3
- "version": "0.10.8",
3
+ "version": "0.10.9",
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": "0c5238559b78d31ea5c3dc7f2b27361b8d8b03c4"
339
+ "gitHead": "56b00ab769c11319de73f799e8be90a95a81b7f0"
340
340
  }
@@ -218,6 +218,120 @@
218
218
  flex-basis: 100%;
219
219
  }
220
220
 
221
+ .bb-pkw-context-task-list {
222
+ gap: 0;
223
+ border-top: 1px solid var(--bb-color-border);
224
+ }
225
+
226
+ .bb-pkw-context-list .bb-pkw-context-task-row {
227
+ display: grid;
228
+ grid-template-columns: 28px minmax(0, 2.4fr) minmax(112px, .75fr) 92px minmax(100px, .9fr);
229
+ align-items: center;
230
+ gap: 0;
231
+ min-height: 54px;
232
+ border-bottom: 1px solid var(--bb-color-border);
233
+ padding: 0;
234
+ font-size: 12px;
235
+ }
236
+
237
+ .bb-pkw-context-list .bb-pkw-context-task-row:last-child {
238
+ border-bottom: 1px solid var(--bb-color-border);
239
+ }
240
+
241
+ .bb-pkw-context-task-row > * {
242
+ min-width: 0;
243
+ padding: 8px 10px;
244
+ }
245
+
246
+ .bb-pkw-context-task-row .bb-pkw-context-task-state {
247
+ width: 9px;
248
+ height: 9px;
249
+ margin: auto;
250
+ padding: 0;
251
+ border: 1.5px solid var(--bb-color-muted);
252
+ border-radius: 50%;
253
+ }
254
+
255
+ .bb-pkw-context-task-row .bb-pkw-context-task-state.bb-pkw-context-task-wait {
256
+ border-color: var(--bb-color-warning);
257
+ background: var(--bb-color-warning);
258
+ }
259
+
260
+ .bb-pkw-context-task-row .bb-pkw-context-task-state.bb-pkw-context-task-fail {
261
+ border-color: var(--bb-color-danger);
262
+ background: var(--bb-color-danger);
263
+ }
264
+
265
+ .bb-pkw-context-task-row .bb-pkw-context-task-state.bb-pkw-context-task-ok {
266
+ border-color: var(--bb-color-accent);
267
+ background: var(--bb-color-accent);
268
+ }
269
+
270
+ .bb-pkw-context-task-row .bb-pkw-context-task-title {
271
+ width: 100%;
272
+ overflow: hidden;
273
+ border: 0;
274
+ background: transparent;
275
+ color: var(--bb-color-ink);
276
+ font: inherit;
277
+ font-size: 14px;
278
+ font-weight: 690;
279
+ text-align: left;
280
+ text-overflow: ellipsis;
281
+ white-space: nowrap;
282
+ }
283
+
284
+ button.bb-pkw-context-task-title { cursor: pointer; }
285
+ button.bb-pkw-context-task-title:hover { color: var(--bb-color-accent-strong); text-decoration: underline; }
286
+ button.bb-pkw-context-task-title:focus-visible { outline: 3px solid var(--bb-color-focus); outline-offset: -2px; }
287
+
288
+ .bb-pkw-context-task-owner {
289
+ color: var(--bb-color-muted);
290
+ overflow-wrap: anywhere;
291
+ }
292
+
293
+ .bb-pkw-context-task-due {
294
+ white-space: nowrap;
295
+ }
296
+
297
+ .bb-pkw-context-task-due.bb-pkw-context-task-overdue {
298
+ color: var(--bb-color-danger);
299
+ font-weight: 740;
300
+ }
301
+
302
+ .bb-pkw-context-task-stage {
303
+ display: flex;
304
+ align-items: center;
305
+ gap: 7px;
306
+ color: var(--bb-color-muted);
307
+ }
308
+
309
+ .bb-pkw-context-task-stage::before {
310
+ width: 6px;
311
+ height: 6px;
312
+ flex: 0 0 auto;
313
+ border-radius: 50%;
314
+ background: var(--bb-color-muted);
315
+ content: '';
316
+ }
317
+
318
+ .bb-pkw-context-task-stage.bb-pkw-context-task-wait::before { background: var(--bb-color-warning); }
319
+ .bb-pkw-context-task-stage.bb-pkw-context-task-fail::before { background: var(--bb-color-danger); }
320
+ .bb-pkw-context-task-stage.bb-pkw-context-task-ok::before { background: var(--bb-color-accent); }
321
+
322
+ @media (max-width: 760px) {
323
+ .bb-pkw-context-list .bb-pkw-context-task-row {
324
+ grid-template-columns: 28px minmax(0, 1fr) auto;
325
+ grid-template-areas: 'state title stage' '. owner due';
326
+ }
327
+
328
+ .bb-pkw-context-task-state { grid-area: state; }
329
+ .bb-pkw-context-task-title { grid-area: title; }
330
+ .bb-pkw-context-task-owner { grid-area: owner; }
331
+ .bb-pkw-context-task-due { grid-area: due; }
332
+ .bb-pkw-context-task-stage { grid-area: stage; }
333
+ }
334
+
221
335
  .bb-pkw-info-grid {
222
336
  display: grid;
223
337
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
@@ -62,7 +62,7 @@ function normalizeContextItem(item) {
62
62
  const title = cleanName(item.title, item.name);
63
63
  if (!id || !title) return null;
64
64
  const normalized = { id, title };
65
- for (const key of ['kind', 'status', 'priority', 'summary', 'owner', 'assignee', 'dueAt', 'updatedAt', 'eventAt', 'body', 'description', 'sourceRecordId', 'relatedRecordId', 'relatedTaskId', 'sourcePath', 'provenance']) {
65
+ for (const key of ['kind', 'status', 'statusKind', 'priority', 'summary', 'owner', 'assignee', 'dueAt', 'updatedAt', 'eventAt', 'body', 'description', 'sourceRecordId', 'relatedRecordId', 'relatedTaskId', 'sourcePath', 'provenance']) {
66
66
  const value = textOrNull(item[key]);
67
67
  if (value) normalized[key] = value;
68
68
  }
@@ -338,7 +338,46 @@ function contextSectionSkeleton(doc, { title = null, message = null } = {}) {
338
338
  return group;
339
339
  }
340
340
 
341
- function renderProjectContextGroup(doc, item) {
341
+ function contextTaskDue(value) {
342
+ if (!value) return '未確認';
343
+ const date = new Date(value);
344
+ return Number.isNaN(date.getTime())
345
+ ? value
346
+ : new Intl.DateTimeFormat('ja-JP', { month: 'numeric', day: 'numeric' }).format(date);
347
+ }
348
+
349
+ function contextTaskOverdue(value, statusKind) {
350
+ if (!value || ['ok', 'fail'].includes(statusKind)) return false;
351
+ const date = new Date(value);
352
+ if (Number.isNaN(date.getTime())) return false;
353
+ const today = new Date();
354
+ date.setHours(0, 0, 0, 0);
355
+ today.setHours(0, 0, 0, 0);
356
+ return date < today;
357
+ }
358
+
359
+ function renderProjectContextTaskRow(doc, entry, onTaskOpen) {
360
+ const status = entry.status ?? '未確認';
361
+ const kind = ['ok', 'wait', 'fail'].includes(entry.statusKind) ? entry.statusKind : '';
362
+ const row = makeElement(doc, 'li', { className: 'bb-pkw-context-task-row' });
363
+ row.append(makeElement(doc, 'span', {
364
+ className: `bb-pkw-context-task-state${kind ? ` bb-pkw-context-task-${kind}` : ''}`,
365
+ attrs: { 'aria-hidden': 'true' },
366
+ }));
367
+ row.append(typeof onTaskOpen === 'function'
368
+ ? denseButton(doc, entry.title, 'bb-pkw-context-task-title', () => onTaskOpen(entry.id), { title: entry.title, 'data-item-id': entry.id })
369
+ : makeElement(doc, 'strong', { className: 'bb-pkw-context-task-title', text: entry.title, attrs: { title: entry.title } }));
370
+ row.append(makeElement(doc, 'span', { className: 'bb-pkw-context-task-owner', text: entry.owner ?? entry.assignee ?? '担当者を確認できていない' }));
371
+ row.append(makeElement(doc, 'time', {
372
+ className: `bb-pkw-context-task-due${contextTaskOverdue(entry.dueAt, kind) ? ' bb-pkw-context-task-overdue' : ''}`,
373
+ text: contextTaskDue(entry.dueAt),
374
+ attrs: entry.dueAt ? { datetime: entry.dueAt } : {},
375
+ }));
376
+ row.append(makeElement(doc, 'span', { className: `bb-pkw-context-task-stage${kind ? ` bb-pkw-context-task-${kind}` : ''}`, text: status }));
377
+ return row;
378
+ }
379
+
380
+ function renderProjectContextGroup(doc, item, onTaskOpen) {
342
381
  const group = makeElement(doc, 'section', {
343
382
  className: `bb-pkw-context-group${item.state === 'loading' ? ' bb-pkw-context-group-loading' : ''}`,
344
383
  attrs: { 'aria-label': item.title, ...(item.state === 'loading' ? { 'aria-busy': 'true' } : {}) },
@@ -357,8 +396,13 @@ function renderProjectContextGroup(doc, item) {
357
396
  } else if (item.state === 'unknown') {
358
397
  group.append(workspaceNotice(doc, { label: '未確認', text: item.message ?? 'このセクションの取得状態は確認できません。', tone: 'warning' }));
359
398
  } else if (item.items.length > 0) {
360
- const list = makeElement(doc, 'ul', { className: 'bb-pkw-context-list' });
399
+ const taskList = item.items.every((entry) => entry.kind === 'task');
400
+ const list = makeElement(doc, 'ul', { className: `bb-pkw-context-list${taskList ? ' bb-pkw-context-task-list' : ''}` });
361
401
  for (const entry of item.items) {
402
+ if (entry.kind === 'task') {
403
+ list.append(renderProjectContextTaskRow(doc, entry, onTaskOpen));
404
+ continue;
405
+ }
362
406
  const row = makeElement(doc, 'li');
363
407
  row.append(makeElement(doc, 'strong', { text: entry.title }));
364
408
  if (entry.status) row.append(badge(doc, entry.status, 'muted'));
@@ -385,6 +429,7 @@ export function renderProjectContext(doc, context, {
385
429
  sections: selectedSections = null,
386
430
  includeStatus = true,
387
431
  includeHeading = true,
432
+ onTaskOpen = null,
388
433
  } = {}) {
389
434
  if (!context) return null;
390
435
  const sections = Array.isArray(selectedSections)
@@ -407,7 +452,7 @@ export function renderProjectContext(doc, context, {
407
452
  section.append(makeElement(doc, 'p', { className: 'bb-pkw-muted', text: '補足情報のセクションはありません。' }));
408
453
  return section;
409
454
  }
410
- for (const item of sections) section.append(renderProjectContextGroup(doc, item));
455
+ for (const item of sections) section.append(renderProjectContextGroup(doc, item, onTaskOpen));
411
456
  return section;
412
457
  }
413
458
 
@@ -850,7 +895,7 @@ function renderOverview(doc, detail, context, edges, entities, onSelect, onConte
850
895
  columns.append(people);
851
896
  panel.append(columns);
852
897
 
853
- const contextBlock = renderProjectContext(doc, context);
898
+ const contextBlock = renderProjectContext(doc, context, { onTaskOpen: actions.openWorkDetail });
854
899
  if (contextBlock) {
855
900
  panel.append(contextBlock);
856
901
  if (typeof onContext === 'function') onContext(contextBlock, null);
@@ -1250,7 +1295,7 @@ export function createProjectKnowledgeWorkspace({
1250
1295
  render();
1251
1296
  return;
1252
1297
  }
1253
- const nextBlock = renderProjectContext(doc, currentContext);
1298
+ const nextBlock = renderProjectContext(doc, currentContext, { onTaskOpen: openWorkDetail });
1254
1299
  if (!nextBlock) {
1255
1300
  if (contextBlock?.parentNode && typeof contextBlock.parentNode.replaceChild === 'function') {
1256
1301
  const nextAnchor = projectContextInsertionAnchor(doc);