@unson/brainbase-mcp 0.27.0 → 0.28.0

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.
@@ -0,0 +1,42 @@
1
+ export type KnowledgeAudience = 'personal' | 'team' | 'organization';
2
+ export type KnowledgeContentType = 'canonical_fact' | 'team_document' | 'source_document' | 'personal_knowledge' | 'operational_state' | 'unknown';
3
+ export type KnowledgeSourceClass = 'graph' | 'owning_repo' | 'team_drive' | 'personal_kg' | 'workspace_home';
4
+ type ExcludableSourceClass = KnowledgeSourceClass | 'wiki';
5
+ export interface KnowledgeResolutionInput {
6
+ intent?: unknown;
7
+ audience?: unknown;
8
+ content_type?: unknown;
9
+ project_code?: string | null;
10
+ [key: string]: unknown;
11
+ }
12
+ export interface KnowledgeResolutionReceipt {
13
+ resolution_id: string;
14
+ resolved_at: string;
15
+ project_code: string | null;
16
+ content_type: KnowledgeContentType;
17
+ searched_scope: string[];
18
+ absence_confirmed: false;
19
+ status: 'resolved' | 'unconfirmed';
20
+ source_class: KnowledgeSourceClass | null;
21
+ canonical_location: Record<string, unknown> | null;
22
+ retrieval_capability: string | null;
23
+ excluded_sources: Array<{
24
+ source_class: ExcludableSourceClass;
25
+ reason: string;
26
+ }>;
27
+ not_searched: KnowledgeSourceClass[];
28
+ next_route: KnowledgeSourceClass;
29
+ confidence: number;
30
+ rationale: string;
31
+ }
32
+ export interface KnowledgeResolutionServiceOptions {
33
+ now?: () => Date;
34
+ id?: () => string;
35
+ }
36
+ export declare class KnowledgeResolutionService {
37
+ readonly now: () => Date;
38
+ readonly id: () => string;
39
+ constructor({ now, id }?: KnowledgeResolutionServiceOptions);
40
+ resolve(rawInput?: KnowledgeResolutionInput): KnowledgeResolutionReceipt;
41
+ }
42
+ export {};
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Decides which canonical source a piece of knowledge should be searched in
3
+ * (Graph, owning repository, team Drive, personal KG, or the workspace) from
4
+ * its content type and audience, and returns a routing receipt. A receipt only
5
+ * says where to search; it never records a search or proves absence.
6
+ *
7
+ * Moved unchanged from brainbase-unson server/services/knowledge-resolution-service.js
8
+ * (story-knowledge-resolution-service-exit-v1).
9
+ */
10
+ import { randomUUID } from 'node:crypto';
11
+ const AUDIENCES = new Set(['personal', 'team', 'organization']);
12
+ const CONTENT_TYPES = new Set(['canonical_fact', 'team_document', 'source_document', 'personal_knowledge', 'operational_state', 'unknown']);
13
+ const ALLOWED_AUDIENCES = {
14
+ canonical_fact: new Set(['team', 'organization']),
15
+ team_document: new Set(['team', 'organization']),
16
+ source_document: new Set(['team', 'organization']),
17
+ personal_knowledge: new Set(['personal']),
18
+ operational_state: new Set(['personal', 'team', 'organization']),
19
+ unknown: AUDIENCES,
20
+ };
21
+ const ROUTES = {
22
+ canonical_fact: { source_class: 'graph', retrieval_capability: 'graph.search' },
23
+ team_document: { source_class: 'owning_repo', retrieval_capability: 'repository.read' },
24
+ source_document: { source_class: 'team_drive', retrieval_capability: 'drive.read' },
25
+ personal_knowledge: { source_class: 'personal_kg', retrieval_capability: 'personal_kg.search' },
26
+ operational_state: { source_class: 'workspace_home', retrieval_capability: 'workspace.inspect' },
27
+ };
28
+ function requiredString(value, name) {
29
+ if (typeof value !== 'string' || !value.trim())
30
+ throw new TypeError(`${name} is required`);
31
+ return value.trim();
32
+ }
33
+ function routeOrder(input) {
34
+ if (input.audience === 'personal')
35
+ return ['personal_kg', 'owning_repo', 'graph', 'team_drive'];
36
+ if (input.project_code)
37
+ return ['owning_repo', 'graph', 'team_drive'];
38
+ return ['graph', 'owning_repo', 'team_drive'];
39
+ }
40
+ function excludedSources(selected, audience) {
41
+ const reasons = {
42
+ wiki: 'Wiki is a migration compatibility surface, not a canonical destination.',
43
+ graph: 'Graph stores canonical entities, terms, and decisions rather than document bodies.',
44
+ owning_repo: 'Repository stores reviewed team documents, not raw source assets.',
45
+ team_drive: 'Drive stores source files and large assets, not reviewed team knowledge.',
46
+ personal_kg: audience === 'personal'
47
+ ? 'Personal KG is only selected for personal cognitive knowledge.'
48
+ : 'Personal KG is owner-only and cannot be the source of team knowledge.',
49
+ workspace_home: 'Workspace home is for runtime state, not durable knowledge.',
50
+ };
51
+ return Object.entries(reasons)
52
+ .filter(([source]) => source !== selected)
53
+ .map(([source_class, reason]) => ({ source_class, reason }));
54
+ }
55
+ function canonicalLocation(route, input) {
56
+ if (route.source_class === 'owning_repo') {
57
+ return {
58
+ repository: input.project_code ? `project:${input.project_code}` : null,
59
+ path: 'docs/',
60
+ };
61
+ }
62
+ if (route.source_class === 'graph')
63
+ return { scope: input.project_code || 'organization', entity_types: ['person', 'organization', 'project', 'term', 'decision'] };
64
+ if (route.source_class === 'team_drive')
65
+ return { drive_scope: input.project_code || 'organization', file_id: null };
66
+ if (route.source_class === 'personal_kg')
67
+ return { owner_scope: 'authenticated_owner' };
68
+ return { workspace_scope: input.project_code || 'current_project' };
69
+ }
70
+ export class KnowledgeResolutionService {
71
+ now;
72
+ id;
73
+ constructor({ now = () => new Date(), id = () => `kr_${randomUUID()}` } = {}) {
74
+ this.now = now;
75
+ this.id = id;
76
+ }
77
+ resolve(rawInput = {}) {
78
+ const input = {
79
+ ...rawInput,
80
+ intent: requiredString(rawInput.intent, 'intent'),
81
+ audience: requiredString(rawInput.audience, 'audience'),
82
+ content_type: requiredString(rawInput.content_type, 'content_type'),
83
+ };
84
+ if (!AUDIENCES.has(input.audience))
85
+ throw new TypeError(`audience must be one of: ${[...AUDIENCES].join(', ')}`);
86
+ if (!CONTENT_TYPES.has(input.content_type))
87
+ throw new TypeError(`content_type must be one of: ${[...CONTENT_TYPES].join(', ')}`);
88
+ const validated = input;
89
+ if (!ALLOWED_AUDIENCES[validated.content_type].has(validated.audience)) {
90
+ throw new TypeError(`content_type=${validated.content_type} is not valid for audience=${validated.audience}`);
91
+ }
92
+ const base = {
93
+ resolution_id: this.id(), resolved_at: this.now().toISOString(),
94
+ project_code: validated.project_code || null, content_type: validated.content_type,
95
+ searched_scope: [], absence_confirmed: false,
96
+ };
97
+ const route = ROUTES[validated.content_type];
98
+ if (!route) {
99
+ const candidates = routeOrder(validated);
100
+ return {
101
+ ...base, status: 'unconfirmed', source_class: null, canonical_location: null,
102
+ retrieval_capability: null, excluded_sources: excludedSources(null, validated.audience),
103
+ not_searched: candidates, next_route: candidates[0], confidence: 0,
104
+ rationale: 'The structured content type is unknown; no source was searched and absence is not confirmed.',
105
+ };
106
+ }
107
+ return {
108
+ ...base, status: 'resolved', source_class: route.source_class,
109
+ canonical_location: canonicalLocation(route, validated),
110
+ retrieval_capability: route.retrieval_capability,
111
+ excluded_sources: excludedSources(route.source_class, validated.audience),
112
+ not_searched: [], next_route: route.source_class, confidence: 0.95,
113
+ rationale: `content_type=${validated.content_type} deterministically maps to ${route.source_class}.`,
114
+ };
115
+ }
116
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unson/brainbase-mcp",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
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",
@@ -179,6 +179,10 @@
179
179
  "types": "./dist/decision-adapter.d.ts",
180
180
  "import": "./dist/decision-adapter.js"
181
181
  },
182
+ "./knowledge-resolution-service": {
183
+ "types": "./dist/knowledge-resolution-service.d.ts",
184
+ "import": "./dist/knowledge-resolution-service.js"
185
+ },
182
186
  "./knowledge-adapter": {
183
187
  "types": "./dist/knowledge-adapter.d.ts",
184
188
  "import": "./dist/knowledge-adapter.js"
@@ -435,5 +439,5 @@
435
439
  "engines": {
436
440
  "node": ">=20"
437
441
  },
438
- "gitHead": "bb3b1bde373d9cc1c12cac01b1b52528d162db85"
442
+ "gitHead": "b8d86d3e394b94cd77bcfe71e8cb6c8703abce4b"
439
443
  }
@@ -1,10 +1,13 @@
1
1
  /*
2
- * Brainbase shared visual tokens (color, type, radius, spacing, rail).
3
- * Common UI parts and hosts read only these names so that the personal and
4
- * organization editions look the same. The values are the organization
5
- * edition's design (brainbase-organization apps/web/public/styles.css, final
6
- * :root layer and the outcome workspace rules), which is the visual source of
7
- * truth for every Brainbase Web surface.
2
+ * Brainbase shared UI-token contract (color, type, radius, spacing, rail).
3
+ * Common OSS UI parts and compatible hosts read these token names. The values
4
+ * below remain this repository's current token defaults; they are not the
5
+ * Brainbase brand palette and do not require every host to adopt one theme.
6
+ * For the organization Web app, the effective visual source is
7
+ * brainbase-organization/apps/web/public/styles.css (final :root layer and
8
+ * outcome workspace overrides). The brand palette is documented separately
9
+ * in brainbase-organization/docs/design/brainbase-brand-palette.md.
10
+ * This boundary clarification intentionally does not change any token value.
8
11
  */
9
12
  :root {
10
13
  --bb-color-ink: #202124;