@unson/brainbase-mcp 0.23.4 → 0.23.5

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.
@@ -1,3 +1,4 @@
1
+ import { assertPrivatePhilosophyRead, privatePhilosophyAcl } from './private-philosophy-graph.js';
1
2
  import { cloneFoundationDefinition, digestFoundationDefinition } from './foundation-catalog.js';
2
3
  import { canonicalPortableJson } from './portable-graph.js';
3
4
  import { FoundationStoreError } from './foundation-store.js';
@@ -295,7 +296,7 @@ function createPhilosophyRevisionRecord(validated, id, revision, principal) {
295
296
  applicability: validated.history.applicability,
296
297
  // This is a read-time projection of the current Graph permission. It
297
298
  // does not mutate the canonical philosophy payload or Graph ACL.
298
- currentAcl: privateCurrentAcl(principal),
299
+ currentAcl: privatePhilosophyAcl(validated.current.payload) ?? privateCurrentAcl(principal),
299
300
  currentScope: cloneJudgmentScope(validated.history.applicability.scope)
300
301
  };
301
302
  }
@@ -337,7 +338,7 @@ async function readCanonicalPhilosophyRevision(input, trustedContext, query) {
337
338
  applicability: validated.history.applicability,
338
339
  // This is a read-time projection of the current Graph permission. It
339
340
  // does not mutate the canonical philosophy payload or Graph ACL.
340
- currentAcl: privateCurrentAcl(trustedContext.principal),
341
+ currentAcl: privatePhilosophyAcl(validated.current.payload) ?? privateCurrentAcl(trustedContext.principal),
341
342
  currentScope: cloneJudgmentScope(validated.history.applicability.scope)
342
343
  }
343
344
  };
@@ -398,7 +399,7 @@ async function readPhilosophyRevision(input, trustedContext, query) {
398
399
  applicability: validated.history.applicability,
399
400
  // This is a read-time projection of the current Graph permission. It
400
401
  // does not mutate the canonical philosophy payload or Graph ACL.
401
- currentAcl: privateCurrentAcl(trustedContext.principal),
402
+ currentAcl: privatePhilosophyAcl(validated.current.payload) ?? privateCurrentAcl(trustedContext.principal),
402
403
  currentScope: cloneJudgmentScope(reference.scope)
403
404
  }
404
405
  };
@@ -414,6 +415,10 @@ async function readPhilosophyRevision(input, trustedContext, query) {
414
415
  function validatePhilosophyHistoryAccess(row, id, revision, trustedContext) {
415
416
  const history = validatePhilosophyHistoryRow(row, { id, revision });
416
417
  const current = validateCurrentRow(row, id, 'philosophy');
418
+ const historicalAcl = assertPrivatePhilosophyRead(history.payload, trustedContext.principal);
419
+ const currentAcl = assertPrivatePhilosophyRead(current.payload, trustedContext.principal);
420
+ if (historicalAcl && !currentAcl)
421
+ throw new FoundationStoreError('authorization_denied', 'Private philosophy history cannot become legacy');
417
422
  const philosophy = current.philosophy;
418
423
  if (!philosophy) {
419
424
  throw corrupt('Current Graph philosophy applicability is missing');
@@ -0,0 +1,13 @@
1
+ import type { FoundationAcl } from './ontology-foundation.js';
2
+ /** An explicit ACL opts a philosophy into owner-only storage; absence is legacy. */
3
+ export declare function privatePhilosophyAcl(payload: unknown): FoundationAcl | undefined;
4
+ export declare function assertPrivatePhilosophyRead(payload: unknown, principal: string): FoundationAcl | undefined;
5
+ /** Validate the existing Graph writer, without changing legacy organization philosophy. */
6
+ export declare function assertPrivatePhilosophyWrite(input: {
7
+ payload: Record<string, unknown>;
8
+ currentPayload?: Record<string, unknown>;
9
+ principal: string;
10
+ projectCode: string;
11
+ currentVersion: number;
12
+ expectedVersion?: number;
13
+ }): void;
@@ -0,0 +1,60 @@
1
+ import { FoundationStoreError } from './foundation-store.js';
2
+ import { canonicalPortableJson } from './portable-graph.js';
3
+ import { philosophyRevisionDigest } from './philosophy-revision-reader.js';
4
+ const record = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
5
+ const present = (value) => Object.hasOwn(value, 'acl');
6
+ const fail = (code, message) => {
7
+ throw new FoundationStoreError(code, message);
8
+ };
9
+ /** An explicit ACL opts a philosophy into owner-only storage; absence is legacy. */
10
+ export function privatePhilosophyAcl(payload) {
11
+ if (!record(payload))
12
+ return fail('invalid_input', 'Philosophy payload must be an object');
13
+ if (!present(payload))
14
+ return undefined;
15
+ const acl = payload.acl;
16
+ if (!record(acl) || typeof acl.ownerId !== 'string' || !acl.ownerId.trim()
17
+ || acl.visibility !== 'private' || !Array.isArray(acl.readerIds) || acl.readerIds.length !== 0
18
+ || !Array.isArray(acl.writerIds) || acl.writerIds.length !== 0) {
19
+ return fail('invalid_input', 'Private philosophy requires one owner and no additional readers or writers');
20
+ }
21
+ return { ownerId: acl.ownerId, visibility: 'private', readerIds: [], writerIds: [] };
22
+ }
23
+ export function assertPrivatePhilosophyRead(payload, principal) {
24
+ const acl = privatePhilosophyAcl(payload);
25
+ if (acl && acl.ownerId !== principal)
26
+ fail('authorization_denied', 'Private philosophy is owner-only');
27
+ return acl;
28
+ }
29
+ /** Validate the existing Graph writer, without changing legacy organization philosophy. */
30
+ export function assertPrivatePhilosophyWrite(input) {
31
+ const currentAcl = input.currentPayload ? privatePhilosophyAcl(input.currentPayload) : undefined;
32
+ const nextAcl = privatePhilosophyAcl(input.payload);
33
+ if (!currentAcl && !nextAcl)
34
+ return;
35
+ if (!nextAcl || (currentAcl && currentAcl.ownerId !== input.principal)
36
+ || nextAcl.ownerId !== input.principal)
37
+ fail('authorization_denied', 'Private philosophy owner cannot change');
38
+ if (!Number.isSafeInteger(input.expectedVersion) || input.expectedVersion !== input.currentVersion) {
39
+ fail('revision_conflict', 'Private philosophy requires the exact current Graph version');
40
+ }
41
+ if (currentAcl && canonicalPortableJson(currentAcl) !== canonicalPortableJson(nextAcl)) {
42
+ fail('authorization_denied', 'Private philosophy ACL cannot change');
43
+ }
44
+ if (typeof input.payload.statement !== 'string' || !input.payload.statement.trim()) {
45
+ fail('invalid_input', 'Private philosophy statement is required');
46
+ }
47
+ const applicability = input.payload.judgmentApplicability;
48
+ if (!record(applicability) || !record(applicability.scope)
49
+ || applicability.scope.type !== 'project' || applicability.scope.id !== input.projectCode) {
50
+ fail('authorization_denied', 'Private philosophy must remain in its authenticated project');
51
+ }
52
+ // Reuse the immutable revision reader's strict applicability/date contract.
53
+ philosophyRevisionDigest({ kind: 'philosophy', id: 'private-philosophy-validation', revision: '1',
54
+ payload: input.payload, applicability: applicability });
55
+ if (currentAcl && canonicalPortableJson(input.currentPayload.judgmentApplicability)
56
+ !== canonicalPortableJson(applicability))
57
+ fail('authorization_denied', 'Private philosophy scope cannot change');
58
+ if (input.currentPayload && !currentAcl)
59
+ fail('authorization_denied', 'Legacy philosophy privacy requires a reviewed migration');
60
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unson/brainbase-mcp",
3
- "version": "0.23.4",
3
+ "version": "0.23.5",
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",
@@ -347,6 +347,10 @@
347
347
  "./meeting-minutes-storage-http": {
348
348
  "types": "./dist/meeting-minutes-storage-http.d.ts",
349
349
  "import": "./dist/meeting-minutes-storage-http.js"
350
+ },
351
+ "./private-philosophy-graph": {
352
+ "types": "./dist/private-philosophy-graph.d.ts",
353
+ "import": "./dist/private-philosophy-graph.js"
350
354
  }
351
355
  },
352
356
  "bin": {
@@ -419,5 +423,5 @@
419
423
  "engines": {
420
424
  "node": ">=20"
421
425
  },
422
- "gitHead": "985c9ff2304a73b0010f86049d3420429cb2e50d"
426
+ "gitHead": "98835ea4b24370a96ea81e80716653b416bcd7c3"
423
427
  }