@unson/brainbase-mcp 0.23.3 → 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');
|
package/dist/judgment-frame.d.ts
CHANGED
|
@@ -18,6 +18,17 @@ export type JudgmentFrameRole = 'constraint' | 'criterion' | 'prediction';
|
|
|
18
18
|
export type JudgmentFrameConstraintVerdict = 'satisfied' | 'violated' | 'tension';
|
|
19
19
|
/** Each kind is used in exactly one way inside an option evaluation. */
|
|
20
20
|
export declare const JUDGMENT_FRAME_ROLE_BY_KIND: Readonly<Record<JudgmentFrameKind, JudgmentFrameRole>>;
|
|
21
|
+
/**
|
|
22
|
+
* A caller-provided summary that may be projected to an owner-only history.
|
|
23
|
+
* Core never derives this value from an answer, tool response, or body.
|
|
24
|
+
*/
|
|
25
|
+
export interface JudgmentFramePublicFrame {
|
|
26
|
+
readonly summary: string;
|
|
27
|
+
readonly reason: string;
|
|
28
|
+
}
|
|
29
|
+
export interface JudgmentFramePublicFrameResponse extends JudgmentFramePublicFrame {
|
|
30
|
+
readonly digest: `sha256:${string}`;
|
|
31
|
+
}
|
|
21
32
|
export interface JudgmentFrameSourceRecord {
|
|
22
33
|
readonly id: string;
|
|
23
34
|
readonly entity_type: string;
|
|
@@ -70,8 +81,10 @@ export interface JudgmentFrameRecord {
|
|
|
70
81
|
readonly none?: Partial<Record<JudgmentFrameKind, string>>;
|
|
71
82
|
readonly options: readonly JudgmentFrameOption[];
|
|
72
83
|
readonly chosen_option: string;
|
|
84
|
+
/** Explicit opt-in for the future owner-only public projection. */
|
|
85
|
+
readonly public_frame?: JudgmentFramePublicFrame;
|
|
73
86
|
}
|
|
74
|
-
export type JudgmentFrameIssueCode = 'frame_record_invalid' | 'frame_catalog_mismatch' | 'frame_ref_unknown' | 'frame_kind_mismatch' | 'frame_selection_duplicate' | 'frame_kind_unaddressed' | 'frame_kind_contradiction' | 'frame_use_unselected' | 'frame_role_mismatch' | 'frame_verdict_missing' | 'frame_selection_unused' | 'frame_chosen_unknown';
|
|
87
|
+
export type JudgmentFrameIssueCode = 'frame_record_invalid' | 'frame_catalog_mismatch' | 'frame_ref_unknown' | 'frame_kind_mismatch' | 'frame_selection_duplicate' | 'frame_kind_unaddressed' | 'frame_kind_contradiction' | 'frame_use_unselected' | 'frame_role_mismatch' | 'frame_verdict_missing' | 'frame_selection_unused' | 'frame_chosen_unknown' | 'frame_public_invalid';
|
|
75
88
|
export interface JudgmentFrameIssue {
|
|
76
89
|
readonly code: JudgmentFrameIssueCode;
|
|
77
90
|
readonly path: string;
|
|
@@ -88,6 +101,18 @@ export interface JudgmentFrameValidation {
|
|
|
88
101
|
readonly issues: readonly JudgmentFrameIssue[];
|
|
89
102
|
readonly escalations: readonly JudgmentFrameEscalation[];
|
|
90
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Compute the digest for the exact two-field public projection.
|
|
106
|
+
* The response adds this digest; it is intentionally separate from the
|
|
107
|
+
* full-record digest returned alongside the projection.
|
|
108
|
+
*/
|
|
109
|
+
export declare function judgmentFramePublicFrameDigest(value: JudgmentFramePublicFrame): `sha256:${string}`;
|
|
110
|
+
/**
|
|
111
|
+
* Compute the stable digest returned with an accepted frame record.
|
|
112
|
+
* The explicit public frame is part of the digest so a changed projection
|
|
113
|
+
* cannot be acknowledged as the same judgment.
|
|
114
|
+
*/
|
|
115
|
+
export declare function judgmentFrameRecordDigest(value: JudgmentFrameRecord): `sha256:${string}`;
|
|
91
116
|
/**
|
|
92
117
|
* Build the compact catalog shown to the model on a judgment-bearing turn.
|
|
93
118
|
* Excluded records are returned with a reason so a shrinking catalog is visible.
|
package/dist/judgment-frame.js
CHANGED
|
@@ -25,6 +25,7 @@ const MAX_NOTE = 2_000;
|
|
|
25
25
|
const MAX_SELECTIONS = 24;
|
|
26
26
|
const MAX_OPTIONS = 8;
|
|
27
27
|
const MAX_USES = 32;
|
|
28
|
+
const MAX_PUBLIC_FRAME_TEXT = 2_000;
|
|
28
29
|
const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
29
30
|
const text = (value) => typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
30
31
|
const nonEmpty = (value, max) => typeof value === 'string' && value.trim().length > 0 && value.length <= max;
|
|
@@ -40,6 +41,45 @@ function canonicalJson(value) {
|
|
|
40
41
|
}
|
|
41
42
|
return JSON.stringify(value);
|
|
42
43
|
}
|
|
44
|
+
const PUBLIC_FRAME_KEYS = ['summary', 'reason'];
|
|
45
|
+
const PUBLIC_FRAME_SECRET_PATTERNS = [
|
|
46
|
+
/(?:^|[\s([{])Bearer\s+[A-Za-z0-9._~+\/-]{8,}(?=$|[\s)\]}.,;])/iu,
|
|
47
|
+
/\b(?:sk-[A-Za-z0-9_-]{16,}|gh[pousr]_[A-Za-z0-9_-]{16,}|github_pat_[A-Za-z0-9_-]{16,}|xox[baprs]-[A-Za-z0-9-]{16,}|AIza[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16})\b/u,
|
|
48
|
+
/(?:access[_-]?token|refresh[_-]?token|api[_-]?key|client[_-]?secret|secret|password|credential|authorization|cookie)\s*(?:=|:)\s*[^\s&#;,]+/iu,
|
|
49
|
+
/\b[a-z][a-z0-9+.-]*:\/\/[^\s/?#:@]+:[^\s/@]+@/iu,
|
|
50
|
+
/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/u,
|
|
51
|
+
];
|
|
52
|
+
const PUBLIC_FRAME_CONTROL_CHARACTERS = /[\u0000-\u001f\u007f-\u009f]/u;
|
|
53
|
+
function containsPublicFrameCredential(value) {
|
|
54
|
+
return PUBLIC_FRAME_SECRET_PATTERNS.some((pattern) => pattern.test(value));
|
|
55
|
+
}
|
|
56
|
+
function publicFrameRecord(value) {
|
|
57
|
+
return {
|
|
58
|
+
record_version: value.record_version,
|
|
59
|
+
catalog_digest: value.catalog_digest,
|
|
60
|
+
selections: value.selections,
|
|
61
|
+
...(value.none === undefined ? {} : { none: value.none }),
|
|
62
|
+
options: value.options,
|
|
63
|
+
chosen_option: value.chosen_option,
|
|
64
|
+
...(value.public_frame === undefined ? {} : { public_frame: value.public_frame }),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Compute the digest for the exact two-field public projection.
|
|
69
|
+
* The response adds this digest; it is intentionally separate from the
|
|
70
|
+
* full-record digest returned alongside the projection.
|
|
71
|
+
*/
|
|
72
|
+
export function judgmentFramePublicFrameDigest(value) {
|
|
73
|
+
return `sha256:${createHash('sha256').update(canonicalJson({ summary: value.summary, reason: value.reason }), 'utf8').digest('hex')}`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Compute the stable digest returned with an accepted frame record.
|
|
77
|
+
* The explicit public frame is part of the digest so a changed projection
|
|
78
|
+
* cannot be acknowledged as the same judgment.
|
|
79
|
+
*/
|
|
80
|
+
export function judgmentFrameRecordDigest(value) {
|
|
81
|
+
return `sha256:${createHash('sha256').update(canonicalJson(publicFrameRecord(value)), 'utf8').digest('hex')}`;
|
|
82
|
+
}
|
|
43
83
|
function itemText(kind, payload) {
|
|
44
84
|
const foundation = isRecord(payload.foundation) ? payload.foundation : {};
|
|
45
85
|
if (kind === 'philosophy') {
|
|
@@ -146,6 +186,31 @@ export function validateJudgmentFrameRecord(value, catalog) {
|
|
|
146
186
|
issue('frame_record_invalid', '$', `record_version must be ${JUDGMENT_FRAME_RECORD_VERSION}`);
|
|
147
187
|
return { valid: false, issues, escalations: [] };
|
|
148
188
|
}
|
|
189
|
+
if (value.public_frame !== undefined) {
|
|
190
|
+
if (!isRecord(value.public_frame)) {
|
|
191
|
+
issue('frame_public_invalid', 'public_frame', 'public_frame must be an object with summary and reason');
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
for (const key of Object.keys(value.public_frame)) {
|
|
195
|
+
if (!PUBLIC_FRAME_KEYS.includes(key)) {
|
|
196
|
+
issue('frame_public_invalid', `public_frame.${key}`, 'public_frame contains an unknown field');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
for (const key of PUBLIC_FRAME_KEYS) {
|
|
200
|
+
const candidate = value.public_frame[key];
|
|
201
|
+
if (!nonEmpty(candidate, MAX_PUBLIC_FRAME_TEXT)) {
|
|
202
|
+
issue('frame_public_invalid', `public_frame.${key}`, `${key} must be a non-empty string of at most ${MAX_PUBLIC_FRAME_TEXT} characters`);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (PUBLIC_FRAME_CONTROL_CHARACTERS.test(candidate)) {
|
|
206
|
+
issue('frame_public_invalid', `public_frame.${key}`, `${key} contains control characters`);
|
|
207
|
+
}
|
|
208
|
+
if (containsPublicFrameCredential(candidate)) {
|
|
209
|
+
issue('frame_public_invalid', `public_frame.${key}`, `${key} contains a credential-like value`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
149
214
|
if (value.catalog_digest !== catalog.digest) {
|
|
150
215
|
issue('frame_catalog_mismatch', 'catalog_digest', 'catalog_digest does not match the catalog shown on this turn');
|
|
151
216
|
}
|
|
@@ -264,6 +329,15 @@ const frameUseSchema = {
|
|
|
264
329
|
},
|
|
265
330
|
required: ['ref', 'role', 'note'],
|
|
266
331
|
};
|
|
332
|
+
const publicFrameSchema = {
|
|
333
|
+
type: 'object',
|
|
334
|
+
additionalProperties: false,
|
|
335
|
+
properties: {
|
|
336
|
+
summary: { type: 'string', minLength: 1, maxLength: MAX_PUBLIC_FRAME_TEXT },
|
|
337
|
+
reason: { type: 'string', minLength: 1, maxLength: MAX_PUBLIC_FRAME_TEXT },
|
|
338
|
+
},
|
|
339
|
+
required: [...PUBLIC_FRAME_KEYS],
|
|
340
|
+
};
|
|
267
341
|
export const judgmentFrameTools = [{
|
|
268
342
|
name: 'brainbase_judgment_frame_catalog',
|
|
269
343
|
description: 'On a judgment-bearing turn, read the catalog of philosophy, objectives, and world models visible to you. Select only what bears on this decision. Status is a label (draft objectives and adopted_unverified models are still usable as hypotheses); it is not a reason to skip them. Then call brainbase_judgment_frame_record with the returned catalog_digest.',
|
|
@@ -271,7 +345,7 @@ export const judgmentFrameTools = [{
|
|
|
271
345
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
272
346
|
}, {
|
|
273
347
|
name: 'brainbase_judgment_frame_record',
|
|
274
|
-
description: 'Record the judgment frame: which catalog references you selected and why, and for each evaluated option how each selected reference was used. Philosophy is a constraint (give verdict satisfied, violated, or tension), an objective is a criterion, a world model is a prediction. Every selection must be used by at least one option. For a kind with no applicable reference, give the reason in none instead of selecting. Name the option you chose. The tool rejects references outside the catalog; it does not judge semantic quality. If escalations are returned, ask the human before acting on the chosen option.',
|
|
348
|
+
description: 'Record the judgment frame: which catalog references you selected and why, and for each evaluated option how each selected reference was used. Philosophy is a constraint (give verdict satisfied, violated, or tension), an objective is a criterion, a world model is a prediction. Every selection must be used by at least one option. For a kind with no applicable reference, give the reason in none instead of selecting. Name the option you chose. The tool rejects references outside the catalog; it does not judge semantic quality. If escalations are returned, ask the human before acting on the chosen option. Include public_frame only when the caller explicitly intends this exact summary and reason for the future owner-only projection; Core never derives it from an answer, tool response, or internal reasoning. public_frame accepts only non-empty safe summary and reason strings up to 2000 characters.',
|
|
275
349
|
inputSchema: {
|
|
276
350
|
type: 'object',
|
|
277
351
|
additionalProperties: false,
|
|
@@ -312,6 +386,7 @@ export const judgmentFrameTools = [{
|
|
|
312
386
|
},
|
|
313
387
|
},
|
|
314
388
|
chosen_option: { type: 'string', minLength: 1, maxLength: 400 },
|
|
389
|
+
public_frame: publicFrameSchema,
|
|
315
390
|
},
|
|
316
391
|
required: ['record_version', 'catalog_digest', 'selections', 'options', 'chosen_option'],
|
|
317
392
|
},
|
|
@@ -378,6 +453,13 @@ export async function handleJudgmentFrameToolCall(name, args, dependencies) {
|
|
|
378
453
|
option_count: args.options.length,
|
|
379
454
|
chosen_option: args.chosen_option,
|
|
380
455
|
escalations: validation.escalations,
|
|
456
|
+
...(args.public_frame === undefined ? {} : {
|
|
457
|
+
public_frame: {
|
|
458
|
+
...args.public_frame,
|
|
459
|
+
digest: judgmentFramePublicFrameDigest(args.public_frame),
|
|
460
|
+
},
|
|
461
|
+
}),
|
|
462
|
+
digest: judgmentFrameRecordDigest(args),
|
|
381
463
|
},
|
|
382
464
|
};
|
|
383
465
|
}
|
|
@@ -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.
|
|
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": "
|
|
426
|
+
"gitHead": "98835ea4b24370a96ea81e80716653b416bcd7c3"
|
|
423
427
|
}
|
package/ui/judgment-history.js
CHANGED
|
@@ -849,10 +849,27 @@ function appendReferenceList(doc, references) {
|
|
|
849
849
|
return list;
|
|
850
850
|
}
|
|
851
851
|
|
|
852
|
+
function evidenceIdentifier(entry) {
|
|
853
|
+
const direct = text(entry);
|
|
854
|
+
if (direct) return direct;
|
|
855
|
+
if (!isRecord(entry)) return '';
|
|
856
|
+
const label = text(entry.label);
|
|
857
|
+
const kind = text(entry.kind);
|
|
858
|
+
const reference = text(entry.ref);
|
|
859
|
+
const identity = [kind, reference].filter(Boolean).join(':');
|
|
860
|
+
if (label && identity) return `${label}(${identity})`;
|
|
861
|
+
return label || identity;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
function evidenceText(entry) {
|
|
865
|
+
const status = isRecord(entry) && entry.status === 'verified' ? '確認済み' : '未確認';
|
|
866
|
+
return `${evidenceIdentifier(entry) || '証拠の識別情報は未確認'}(${status})`;
|
|
867
|
+
}
|
|
868
|
+
|
|
852
869
|
function appendSupplement(doc, proof) {
|
|
853
870
|
const execution = isRecord(proof.execution) ? proof.execution : {};
|
|
854
871
|
const outcome = isRecord(proof.outcome) ? proof.outcome : {};
|
|
855
|
-
const evidence = Array.isArray(outcome.evidence_refs) ? outcome.evidence_refs.filter(Boolean).join('、') : '';
|
|
872
|
+
const evidence = Array.isArray(outcome.evidence_refs) ? outcome.evidence_refs.filter(Boolean).map(evidenceText).join('、') : '';
|
|
856
873
|
return workspaceDefinition(doc, [
|
|
857
874
|
['実行', [text(execution.status) || '未記録', text(execution.summary)]],
|
|
858
875
|
['結果', [text(outcome.status) || '未記録', text(outcome.summary), evidence ? `証拠: ${evidence}` : '']],
|