@unson/brainbase-mcp 0.46.0 → 0.46.1

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.
@@ -3,6 +3,8 @@ import type { AuthorizationServerMetadata, OAuthClientInformationMixed, OAuthTok
3
3
  import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
4
4
  import { type MeetingSourceAccessDetail, type MeetingSourceCallTool, type MeetingSourceFailure, type MeetingSourceFailureReason, type MeetingSourceMeeting, type MeetingSourceProvider, type MeetingSourceSegment, type TactiqTranscriptBudget, type TactiqTranscriptRead } from './meeting-source-reader.js';
5
5
  import type { OrganizationConnectionBinding, OrganizationConnectionProviderAdapter } from './organization-connection.js';
6
+ export declare const MEETING_SOURCE_LIST_REVISION = 2;
7
+ export declare const MEETING_SOURCE_RELIST_LOOKBACK_MS: number;
6
8
  export type MeetingSourceCapability = 'meetings:list' | 'transcript:read';
7
9
  export type MeetingSourceConnectionStatus = 'pending' | 'connected' | 'reauth_required' | 'disabled' | 'revoked';
8
10
  export interface MeetingSourceConnectionRecord {
@@ -156,6 +158,8 @@ export interface MeetingSourceSyncState {
156
158
  provider: MeetingSourceProvider;
157
159
  syncEnabled: boolean;
158
160
  listedThrough: string | null;
161
+ /** List-reader revision that produced listedThrough; older cursors are re-listed once. */
162
+ listRevision?: number;
159
163
  pending: MeetingSourcePendingMeeting[];
160
164
  unobtainable: Array<{
161
165
  meetingId: string;
@@ -12,6 +12,8 @@ import { createTactiqTranscriptBudget, listMeetings, probeTranscript, readTransc
12
12
  */
13
13
  const HOUR_MS = 60 * 60 * 1000;
14
14
  const DAY_MS = 24 * HOUR_MS;
15
+ export const MEETING_SOURCE_LIST_REVISION = 2;
16
+ export const MEETING_SOURCE_RELIST_LOOKBACK_MS = 30 * DAY_MS;
15
17
  const PROVIDERS = ['plaud', 'tactiq'];
16
18
  const CAPABILITIES = ['meetings:list', 'transcript:read'];
17
19
  const STATUSES = ['pending', 'connected', 'reauth_required', 'disabled', 'revoked'];
@@ -405,11 +407,15 @@ export async function syncMeetingSourceConnection(input) {
405
407
  state.lastAttemptAt = started.toISOString();
406
408
  const callTool = (name, args) => input.runtime.callTool(connection, name, args);
407
409
  const until = input.window ? input.window.until : started.toISOString();
408
- const since = input.window
409
- ? input.window.since
410
- : state.listedThrough
411
- ? new Date(Date.parse(state.listedThrough) - (input.overlapMs ?? DAY_MS)).toISOString()
412
- : new Date(started.getTime() - (input.initialLookbackMs ?? 7 * DAY_MS)).toISOString();
410
+ const normalSince = state.listedThrough
411
+ ? Date.parse(state.listedThrough) - (input.overlapMs ?? DAY_MS)
412
+ : started.getTime() - (input.initialLookbackMs ?? 7 * DAY_MS);
413
+ const sinceMs = !input.window
414
+ && state.listedThrough
415
+ && (state.listRevision ?? 1) < MEETING_SOURCE_LIST_REVISION
416
+ ? Math.min(normalSince, started.getTime() - MEETING_SOURCE_RELIST_LOOKBACK_MS)
417
+ : normalSince;
418
+ const since = input.window ? input.window.since : new Date(sinceMs).toISOString();
413
419
  const finish = async (failure, delivered) => {
414
420
  if (failure) {
415
421
  state.lastError = { ...failure, at: now().toISOString() };
@@ -529,8 +535,11 @@ export async function syncMeetingSourceConnection(input) {
529
535
  if (!listed.complete) {
530
536
  failure ??= { reason: 'incomplete', message: 'The meeting list could not be read completely for the period' };
531
537
  }
532
- else if (!input.window && (!state.listedThrough || Date.parse(until) > Date.parse(state.listedThrough))) {
533
- state.listedThrough = until;
538
+ else if (!input.window) {
539
+ if (!state.listedThrough || Date.parse(until) > Date.parse(state.listedThrough)) {
540
+ state.listedThrough = until;
541
+ }
542
+ state.listRevision = MEETING_SOURCE_LIST_REVISION;
534
543
  }
535
544
  return finish(failure, delivered);
536
545
  }
@@ -153,7 +153,7 @@ async function listPlaud(callTool, since, until, utcOffsetMinutes, pageSize) {
153
153
  const meetings = [];
154
154
  let complete = false;
155
155
  for (let page = 1; page <= MAX_PAGES; page += 1) {
156
- const items = extractList(await invoke(callTool, 'list_files', { date_from: dateFrom, date_to: dateTo, page, page_size: pageSize }));
156
+ const items = plaudListItems(await invoke(callTool, 'list_files', { date_from: dateFrom, date_to: dateTo, page, page_size: pageSize }));
157
157
  for (const item of items) {
158
158
  const meeting = plaudMeeting(item, utcOffsetMinutes);
159
159
  if (!meeting)
@@ -401,10 +401,25 @@ function payloadOf(result) {
401
401
  return record.structuredContent;
402
402
  if (Array.isArray(record.content)) {
403
403
  const text = contentText(record);
404
- return parseJson(text) ?? text;
404
+ const parsed = parseJson(text);
405
+ if (parsed !== null)
406
+ return parsed;
407
+ const wrapped = unwrapUntrustedUserData(text);
408
+ return wrapped.found ? wrapped.value : text;
405
409
  }
406
410
  return result;
407
411
  }
412
+ function unwrapUntrustedUserData(text) {
413
+ const opening = /<(untrusted-user-data-[0-9a-f]+)\s+source="[^"]*">/.exec(text);
414
+ if (!opening)
415
+ return { found: false };
416
+ const start = opening.index + opening[0].length;
417
+ const end = text.lastIndexOf(`</${opening[1]}>`);
418
+ if (end < start)
419
+ return { found: false };
420
+ const inner = text.slice(start, end).trim();
421
+ return { found: true, value: parseJson(inner) ?? inner };
422
+ }
408
423
  function contentText(record) {
409
424
  if (!Array.isArray(record.content))
410
425
  return '';
@@ -414,6 +429,18 @@ function contentText(record) {
414
429
  .map((item) => item.text)
415
430
  .join('\n');
416
431
  }
432
+ function plaudListItems(payload) {
433
+ if (Array.isArray(payload))
434
+ return payload;
435
+ const record = asRecord(payload);
436
+ if (record) {
437
+ for (const key of ['data', 'files', 'items', 'results', 'records', 'recordings']) {
438
+ if (Array.isArray(record[key]))
439
+ return record[key];
440
+ }
441
+ }
442
+ throw new UnexpectedShapeError('Plaud list_files returned a response in an unknown shape');
443
+ }
417
444
  function extractList(payload) {
418
445
  if (Array.isArray(payload))
419
446
  return payload;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unson/brainbase-mcp",
3
- "version": "0.46.0",
3
+ "version": "0.46.1",
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",
@@ -586,7 +586,7 @@
586
586
  "build:world": "node scripts/build-world-vendor.mjs"
587
587
  },
588
588
  "dependencies": {
589
- "@modelcontextprotocol/sdk": "^1.31.0",
589
+ "@modelcontextprotocol/sdk": "^1.32.0",
590
590
  "graphology": "0.26.0",
591
591
  "js-yaml": "^4.1.1",
592
592
  "sigma": "3.0.3",
@@ -620,5 +620,5 @@
620
620
  "url": "https://github.com/Unson-LLC/brainbase/issues"
621
621
  },
622
622
  "homepage": "https://github.com/Unson-LLC/brainbase#readme",
623
- "gitHead": "955bf4ef5249f607c4983f86c05ecae10ce7a67c"
623
+ "gitHead": "514e31c00aeb6906c01cb5df51cf9bea0f62eee2"
624
624
  }