@unson/brainbase-mcp 0.32.0 → 0.34.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.
- package/dist/graph-maintenance-engine.d.ts +44 -0
- package/dist/graph-maintenance-engine.js +804 -0
- package/dist/memory-scope-policy.d.ts +43 -0
- package/dist/memory-scope-policy.js +159 -0
- package/dist/ontology-kernel.d.ts +102 -0
- package/dist/ontology-kernel.js +681 -0
- package/dist/ontology-publication.d.ts +6 -0
- package/dist/ontology-publication.js +44 -0
- package/dist/ontology-registry.d.ts +32 -0
- package/dist/ontology-registry.js +202 -0
- package/dist/ontology-release-trust.d.ts +4 -0
- package/dist/ontology-release-trust.js +121 -0
- package/package.json +26 -2
- package/ui/world/world-view.js +24 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type MemoryRecordInput = Record<string, any> | null | undefined;
|
|
2
|
+
export type MemoryAccessContextInput = Record<string, any>;
|
|
3
|
+
export type MemoryAccessContext = {
|
|
4
|
+
person_id: string | null;
|
|
5
|
+
workspace: string | null;
|
|
6
|
+
channel_id: string | null;
|
|
7
|
+
session_id: string | null;
|
|
8
|
+
roles: string[];
|
|
9
|
+
role_rank: number;
|
|
10
|
+
project_codes: string[];
|
|
11
|
+
clearance: string[];
|
|
12
|
+
};
|
|
13
|
+
export type NormalizedMemoryRecord = {
|
|
14
|
+
id: string | null;
|
|
15
|
+
visibility: string;
|
|
16
|
+
owner_person_id: string | null;
|
|
17
|
+
workspace: string | null;
|
|
18
|
+
channel_id: string | null;
|
|
19
|
+
project_code: string | null;
|
|
20
|
+
role_min: string;
|
|
21
|
+
sensitivity: string;
|
|
22
|
+
};
|
|
23
|
+
export type MemoryScopeEvaluation = {
|
|
24
|
+
id: string | null;
|
|
25
|
+
visibility: string;
|
|
26
|
+
reason: string | null;
|
|
27
|
+
allowed: boolean;
|
|
28
|
+
};
|
|
29
|
+
export type ScopedMemoryResult<T> = {
|
|
30
|
+
mode: 'deny_by_default';
|
|
31
|
+
records: T[];
|
|
32
|
+
denied: MemoryScopeEvaluation[];
|
|
33
|
+
meta: {
|
|
34
|
+
evaluated_count: number;
|
|
35
|
+
returned_count: number;
|
|
36
|
+
denied_count: number;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export declare function normalizeMemoryAccessContext(input?: MemoryAccessContextInput): MemoryAccessContext;
|
|
40
|
+
export declare function normalizeMemoryRecord(record: MemoryRecordInput): NormalizedMemoryRecord;
|
|
41
|
+
export declare function evaluateMemoryScope(record: MemoryRecordInput, rawContext?: MemoryAccessContextInput): MemoryScopeEvaluation;
|
|
42
|
+
export declare function buildScopedMemoryResult<T extends MemoryRecordInput>(records?: T[], context?: MemoryAccessContextInput): ScopedMemoryResult<T>;
|
|
43
|
+
export declare function filterScopedMemoryRecords<T extends MemoryRecordInput>(records?: T[], context?: MemoryAccessContextInput): T[];
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// Moved from brainbase-unson server/services/memory-scope-policy.js without changing behavior.
|
|
2
|
+
// Only type annotations were added; memory records stay open JSON objects as in the original.
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
+
const ROLE_RANK = {
|
|
5
|
+
member: 1,
|
|
6
|
+
gm: 2,
|
|
7
|
+
ceo: 3
|
|
8
|
+
};
|
|
9
|
+
function toList(value) {
|
|
10
|
+
if (Array.isArray(value)) {
|
|
11
|
+
return value.map(item => String(item).trim()).filter(Boolean);
|
|
12
|
+
}
|
|
13
|
+
if (typeof value === 'string') {
|
|
14
|
+
return value.split(',').map(item => item.trim()).filter(Boolean);
|
|
15
|
+
}
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
function firstString(...values) {
|
|
19
|
+
for (const value of values) {
|
|
20
|
+
if (typeof value === 'string' && value.trim())
|
|
21
|
+
return value.trim();
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
function parsePayload(record) {
|
|
26
|
+
if (!record || typeof record !== 'object')
|
|
27
|
+
return {};
|
|
28
|
+
const payload = record.payload;
|
|
29
|
+
if (typeof payload === 'string') {
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(payload);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (payload && typeof payload === 'object') {
|
|
38
|
+
return payload;
|
|
39
|
+
}
|
|
40
|
+
return record;
|
|
41
|
+
}
|
|
42
|
+
function normalizeRole(role) {
|
|
43
|
+
return typeof role === 'string' ? role.trim().toLowerCase() : '';
|
|
44
|
+
}
|
|
45
|
+
function maxRoleRank(roles) {
|
|
46
|
+
return roles.reduce((rank, role) => Math.max(rank, ROLE_RANK[normalizeRole(role)] || 0), 0);
|
|
47
|
+
}
|
|
48
|
+
export function normalizeMemoryAccessContext(input = {}) {
|
|
49
|
+
const roles = [
|
|
50
|
+
...toList(input.roles),
|
|
51
|
+
...toList(input.role)
|
|
52
|
+
].map(normalizeRole).filter(Boolean);
|
|
53
|
+
const projectCodes = [
|
|
54
|
+
...toList(input.project_codes),
|
|
55
|
+
...toList(input.projectCodes)
|
|
56
|
+
];
|
|
57
|
+
const clearance = [
|
|
58
|
+
...toList(input.clearance),
|
|
59
|
+
...toList(input.sensitivities),
|
|
60
|
+
...toList(input.sensitivity)
|
|
61
|
+
].map(item => item.toLowerCase());
|
|
62
|
+
return {
|
|
63
|
+
person_id: firstString(input.person_id, input.personId),
|
|
64
|
+
workspace: firstString(input.workspace),
|
|
65
|
+
channel_id: firstString(input.channel_id, input.channelId),
|
|
66
|
+
session_id: firstString(input.session_id, input.sessionId),
|
|
67
|
+
roles,
|
|
68
|
+
role_rank: maxRoleRank(roles),
|
|
69
|
+
project_codes: Array.from(new Set(projectCodes)),
|
|
70
|
+
clearance: Array.from(new Set(clearance))
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export function normalizeMemoryRecord(record) {
|
|
74
|
+
const payload = parsePayload(record);
|
|
75
|
+
return {
|
|
76
|
+
id: firstString(payload.memory_candidate_id, payload.candidate_id, record?.id),
|
|
77
|
+
visibility: firstString(payload.visibility) || 'unknown',
|
|
78
|
+
owner_person_id: firstString(payload.owner_person_id, payload.ownerPersonId),
|
|
79
|
+
workspace: firstString(payload.workspace, record?.workspace),
|
|
80
|
+
channel_id: firstString(payload.channel_id, payload.channelId, record?.channel_id, record?.channelId),
|
|
81
|
+
project_code: firstString(payload.project_code, payload.projectCode, record?.project_code, record?.projectCode),
|
|
82
|
+
role_min: normalizeRole(firstString(payload.role_min, payload.roleMin, record?.role_min, record?.roleMin) || 'member'),
|
|
83
|
+
sensitivity: firstString(payload.sensitivity, record?.sensitivity) || 'internal'
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function hasRequiredPolicy(context) {
|
|
87
|
+
return Boolean(context.person_id
|
|
88
|
+
&& context.roles.length > 0
|
|
89
|
+
&& context.project_codes.length > 0
|
|
90
|
+
&& context.clearance.length > 0);
|
|
91
|
+
}
|
|
92
|
+
export function evaluateMemoryScope(record, rawContext = {}) {
|
|
93
|
+
const context = normalizeMemoryAccessContext(rawContext);
|
|
94
|
+
const memory = normalizeMemoryRecord(record);
|
|
95
|
+
const resultBase = {
|
|
96
|
+
id: memory.id,
|
|
97
|
+
visibility: memory.visibility,
|
|
98
|
+
reason: null
|
|
99
|
+
};
|
|
100
|
+
if (!hasRequiredPolicy(context)) {
|
|
101
|
+
return { ...resultBase, allowed: false, reason: 'missing_access_policy' };
|
|
102
|
+
}
|
|
103
|
+
if (!memory.id || memory.visibility === 'unknown') {
|
|
104
|
+
return { ...resultBase, allowed: false, reason: 'invalid_memory_record' };
|
|
105
|
+
}
|
|
106
|
+
if (memory.workspace && context.workspace && memory.workspace !== context.workspace) {
|
|
107
|
+
return { ...resultBase, allowed: false, reason: 'workspace_mismatch' };
|
|
108
|
+
}
|
|
109
|
+
if (memory.project_code && !context.project_codes.includes(memory.project_code)) {
|
|
110
|
+
return { ...resultBase, allowed: false, reason: 'project_mismatch' };
|
|
111
|
+
}
|
|
112
|
+
if (memory.channel_id && context.channel_id && memory.channel_id !== context.channel_id) {
|
|
113
|
+
return { ...resultBase, allowed: false, reason: 'channel_mismatch' };
|
|
114
|
+
}
|
|
115
|
+
const sensitivity = memory.sensitivity.toLowerCase();
|
|
116
|
+
if (!context.clearance.includes(sensitivity)) {
|
|
117
|
+
return { ...resultBase, allowed: false, reason: 'sensitivity_denied' };
|
|
118
|
+
}
|
|
119
|
+
if (context.role_rank < (ROLE_RANK[memory.role_min] || ROLE_RANK.member)) {
|
|
120
|
+
return { ...resultBase, allowed: false, reason: 'role_denied' };
|
|
121
|
+
}
|
|
122
|
+
if (memory.visibility === 'private' || memory.visibility === 'owner') {
|
|
123
|
+
const elevatedContext = context.roles.includes('gm') || context.roles.includes('ceo');
|
|
124
|
+
if (memory.owner_person_id !== context.person_id || elevatedContext) {
|
|
125
|
+
return { ...resultBase, allowed: false, reason: 'private_scope_denied' };
|
|
126
|
+
}
|
|
127
|
+
return { ...resultBase, allowed: true };
|
|
128
|
+
}
|
|
129
|
+
if (memory.visibility === 'project' || memory.visibility === 'role' || memory.visibility === 'team' || memory.visibility === 'org' || memory.visibility === 'public') {
|
|
130
|
+
return { ...resultBase, allowed: true };
|
|
131
|
+
}
|
|
132
|
+
return { ...resultBase, allowed: false, reason: 'visibility_denied' };
|
|
133
|
+
}
|
|
134
|
+
export function buildScopedMemoryResult(records = [], context = {}) {
|
|
135
|
+
const allowed = [];
|
|
136
|
+
const denied = [];
|
|
137
|
+
for (const record of records) {
|
|
138
|
+
const evaluation = evaluateMemoryScope(record, context);
|
|
139
|
+
if (evaluation.allowed) {
|
|
140
|
+
allowed.push(record);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
denied.push(evaluation);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
mode: 'deny_by_default',
|
|
148
|
+
records: allowed,
|
|
149
|
+
denied,
|
|
150
|
+
meta: {
|
|
151
|
+
evaluated_count: records.length,
|
|
152
|
+
returned_count: allowed.length,
|
|
153
|
+
denied_count: denied.length
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
export function filterScopedMemoryRecords(records = [], context = {}) {
|
|
158
|
+
return buildScopedMemoryResult(records, context).records;
|
|
159
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export declare const DECISION_STATUS_RULE_ID = "CON-DECISION-STATUS-001";
|
|
2
|
+
export declare class OntologyError extends Error {
|
|
3
|
+
[key: string]: any;
|
|
4
|
+
constructor(code: any, message: any, details?: any);
|
|
5
|
+
}
|
|
6
|
+
export declare class OntologyKernel {
|
|
7
|
+
[key: string]: any;
|
|
8
|
+
constructor({ manifest, status }: any);
|
|
9
|
+
get version(): any;
|
|
10
|
+
describe(): any;
|
|
11
|
+
getType(type: any): any;
|
|
12
|
+
getRelation(relation: any): any;
|
|
13
|
+
validateEntity(entity: any, { deferRequiredRelations }?: any): {
|
|
14
|
+
valid: boolean;
|
|
15
|
+
ontology_version: any;
|
|
16
|
+
violations: any[];
|
|
17
|
+
};
|
|
18
|
+
validateEdge(edge: any): {
|
|
19
|
+
valid: any;
|
|
20
|
+
ontology_version: any;
|
|
21
|
+
violations: any[];
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Which persisted edges validateSnapshot needs in order to judge a
|
|
25
|
+
* mutation. Only two rules read existing edges: relation cardinality
|
|
26
|
+
* (same relation, same constrained endpoint as a mutation edge) and
|
|
27
|
+
* required relations (the listed relations, in their direction, from a
|
|
28
|
+
* validated entity of the rule's target type). Every other persisted
|
|
29
|
+
* edge cannot change the verdict for this mutation.
|
|
30
|
+
*
|
|
31
|
+
* @returns {{ relation: string, endpoint: 'from_id'|'to_id', ids: string[] }[]}
|
|
32
|
+
*/
|
|
33
|
+
mutationEdgeScope({ mutationEdges, validationEntities }?: any): any[];
|
|
34
|
+
validateSnapshot(snapshot: any, _adapters?: any): {
|
|
35
|
+
valid: boolean;
|
|
36
|
+
verification: string;
|
|
37
|
+
ontology_version: any;
|
|
38
|
+
violations: any;
|
|
39
|
+
};
|
|
40
|
+
inferDecisions(snapshot: any, { derivedAt }?: any): {
|
|
41
|
+
ontology_version: any;
|
|
42
|
+
as_of: any;
|
|
43
|
+
derived_at: any;
|
|
44
|
+
decisions: {
|
|
45
|
+
[k: string]: any;
|
|
46
|
+
};
|
|
47
|
+
evidence: ({
|
|
48
|
+
rule_id: any;
|
|
49
|
+
from_id: any;
|
|
50
|
+
to_id: any;
|
|
51
|
+
decision_ids?: undefined;
|
|
52
|
+
} | {
|
|
53
|
+
rule_id: string;
|
|
54
|
+
decision_ids: any[];
|
|
55
|
+
from_id?: undefined;
|
|
56
|
+
to_id?: undefined;
|
|
57
|
+
})[];
|
|
58
|
+
explanation: string;
|
|
59
|
+
};
|
|
60
|
+
impact({ change, snapshot }: any): {
|
|
61
|
+
ontology_version: any;
|
|
62
|
+
semver: any;
|
|
63
|
+
verification: string;
|
|
64
|
+
match_count: any;
|
|
65
|
+
representative_ids: any;
|
|
66
|
+
affected_apis: any;
|
|
67
|
+
affected_agents: any;
|
|
68
|
+
migration_required: boolean;
|
|
69
|
+
history_required: any;
|
|
70
|
+
};
|
|
71
|
+
planEvolution(change?: any): {
|
|
72
|
+
event_id: any;
|
|
73
|
+
event_type: string;
|
|
74
|
+
ontology_version: any;
|
|
75
|
+
canonical_id: any;
|
|
76
|
+
source_ids: unknown[];
|
|
77
|
+
aliases: unknown[];
|
|
78
|
+
provenance: any;
|
|
79
|
+
effective_at: any;
|
|
80
|
+
conflict_policy: any;
|
|
81
|
+
};
|
|
82
|
+
interpretHistory(snapshot?: any, { asOf }?: any): {
|
|
83
|
+
ontology_version: any;
|
|
84
|
+
as_of: any;
|
|
85
|
+
applied_event_ids: any;
|
|
86
|
+
entities: any;
|
|
87
|
+
edges: any;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Build an immutable Ontology release candidate from a base release and a
|
|
92
|
+
* change set. The result is a dry-run artifact: it is never written here and
|
|
93
|
+
* becomes current only through the RACI-authorized publisher (ADR-021).
|
|
94
|
+
*/
|
|
95
|
+
export declare function buildOntologyReleaseCandidate(baseManifest: any, proposal?: any): {
|
|
96
|
+
candidate: any;
|
|
97
|
+
required_bump: string;
|
|
98
|
+
declared_bump: string | null;
|
|
99
|
+
semver_ok: boolean;
|
|
100
|
+
change_classification: any[];
|
|
101
|
+
consistency_violations: any[];
|
|
102
|
+
};
|