@unson/brainbase-mcp 0.41.9 → 0.41.11
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/canonical-task-service.d.ts +6 -0
- package/dist/canonical-task-service.js +18 -1
- package/dist/judgment-history.js +76 -3
- package/dist/meeting-minutes-http.js +19 -0
- package/dist/meeting-minutes.js +4 -0
- package/package.json +2 -2
- package/ui/judgment-history.css +155 -2
- package/ui/judgment-history.js +649 -241
- package/ui/local-web-shell.js +16 -0
- package/ui/meeting-minutes.css +238 -5
- package/ui/meeting-minutes.js +691 -124
|
@@ -31,6 +31,8 @@ export interface CanonicalTaskRecord extends JsonRecord {
|
|
|
31
31
|
assignee_display_name?: string | null;
|
|
32
32
|
due_at?: string | null;
|
|
33
33
|
waiting_on?: string | null;
|
|
34
|
+
/** The Graph person a waiting task waits on; null when it waits on a condition or nobody in particular. */
|
|
35
|
+
waiting_on_person_id?: string | null;
|
|
34
36
|
review_at?: string | null;
|
|
35
37
|
completed_at?: string | null;
|
|
36
38
|
source_refs?: unknown[];
|
|
@@ -50,6 +52,7 @@ export interface CanonicalTaskCreateInput extends JsonRecord {
|
|
|
50
52
|
assignee_person_id?: string | null;
|
|
51
53
|
due_at?: string | null;
|
|
52
54
|
waiting_on?: string | null;
|
|
55
|
+
waiting_on_person_id?: string | null;
|
|
53
56
|
review_at?: string | null;
|
|
54
57
|
source_refs?: unknown[];
|
|
55
58
|
project_codes?: unknown;
|
|
@@ -63,6 +66,7 @@ export interface CanonicalTaskUpdateInput extends JsonRecord {
|
|
|
63
66
|
assignee_person_id?: string | null;
|
|
64
67
|
due_at?: string | null;
|
|
65
68
|
waiting_on?: string | null;
|
|
69
|
+
waiting_on_person_id?: string | null;
|
|
66
70
|
review_at?: string | null;
|
|
67
71
|
source_refs?: unknown[];
|
|
68
72
|
source_refs_append?: unknown[];
|
|
@@ -231,12 +235,14 @@ export declare class CanonicalTaskService {
|
|
|
231
235
|
}, context: CanonicalTaskContext): Promise<CanonicalTaskRecord>;
|
|
232
236
|
transitionTask(taskId: string, status: unknown, expectedVersion: number, context: CanonicalTaskContext, input?: {
|
|
233
237
|
waitingOn?: unknown;
|
|
238
|
+
waitingOnPersonId?: unknown;
|
|
234
239
|
reviewAt?: unknown;
|
|
235
240
|
}): Promise<CanonicalTaskRecord>;
|
|
236
241
|
transitionTask(taskId: string, input: {
|
|
237
242
|
to_status?: unknown;
|
|
238
243
|
expected_version?: number;
|
|
239
244
|
waiting_on?: unknown;
|
|
245
|
+
waiting_on_person_id?: unknown;
|
|
240
246
|
review_at?: unknown;
|
|
241
247
|
}, context: CanonicalTaskContext): Promise<CanonicalTaskRecord>;
|
|
242
248
|
deleteTask(taskId: string, expectedVersion: number, context: CanonicalTaskContext): Promise<{
|
|
@@ -34,6 +34,7 @@ const CREATE_FIELDS = new Set([
|
|
|
34
34
|
'assignee_person_id',
|
|
35
35
|
'due_at',
|
|
36
36
|
'waiting_on',
|
|
37
|
+
'waiting_on_person_id',
|
|
37
38
|
'review_at',
|
|
38
39
|
'source_refs',
|
|
39
40
|
'project_codes',
|
|
@@ -48,6 +49,7 @@ const MUTABLE_FIELDS = new Set([
|
|
|
48
49
|
'assignee_person_id',
|
|
49
50
|
'due_at',
|
|
50
51
|
'waiting_on',
|
|
52
|
+
'waiting_on_person_id',
|
|
51
53
|
'review_at',
|
|
52
54
|
'source_refs',
|
|
53
55
|
'source_refs_append',
|
|
@@ -78,6 +80,10 @@ function normalizeString(value, field, options = {}) {
|
|
|
78
80
|
}
|
|
79
81
|
return normalized;
|
|
80
82
|
}
|
|
83
|
+
/** A Graph person ID, as for the assignee; empty or null means no person. */
|
|
84
|
+
function normalizeWaitingOnPersonId(value) {
|
|
85
|
+
return normalizeString(value, 'waiting_on_person_id', { max: 200 });
|
|
86
|
+
}
|
|
81
87
|
/** A purpose label: a single line of at most 30 characters; empty or null clears it. */
|
|
82
88
|
const MAX_PURPOSE_LABEL_LENGTH = 30;
|
|
83
89
|
function normalizePurposeLabel(value) {
|
|
@@ -511,7 +517,7 @@ export class CanonicalTaskService {
|
|
|
511
517
|
const expectedVersion = legacyInput ? legacyInput.expected_version : expectedVersionOrContext;
|
|
512
518
|
const context = legacyInput ? expectedVersionOrContext : maybeContext;
|
|
513
519
|
const input = legacyInput
|
|
514
|
-
? { waitingOn: legacyInput.waiting_on, reviewAt: legacyInput.review_at }
|
|
520
|
+
? { waitingOn: legacyInput.waiting_on, waitingOnPersonId: legacyInput.waiting_on_person_id, reviewAt: legacyInput.review_at }
|
|
515
521
|
: maybeInput;
|
|
516
522
|
const normalizedContext = await this.normalizeContext(context);
|
|
517
523
|
const expected = this.requireExpectedVersion(expectedVersion);
|
|
@@ -523,10 +529,13 @@ export class CanonicalTaskService {
|
|
|
523
529
|
failValidation({ waiting_on: ['required_for_waiting'] });
|
|
524
530
|
}
|
|
525
531
|
patch.waiting_on = normalizeString(input.waitingOn, 'waiting_on', { required: true, max: 500 });
|
|
532
|
+
// The person is optional and always replaced, so waiting on a condition clears an earlier person.
|
|
533
|
+
patch.waiting_on_person_id = normalizeWaitingOnPersonId(input.waitingOnPersonId);
|
|
526
534
|
patch.review_at = normalizeIsoDate(input.reviewAt, 'review_at');
|
|
527
535
|
}
|
|
528
536
|
else {
|
|
529
537
|
patch.waiting_on = input.waitingOn === undefined ? null : normalizeString(input.waitingOn, 'waiting_on', { max: 500 });
|
|
538
|
+
patch.waiting_on_person_id = input.waitingOnPersonId === undefined ? null : normalizeWaitingOnPersonId(input.waitingOnPersonId);
|
|
530
539
|
patch.review_at = input.reviewAt === undefined ? null : normalizeIsoDate(input.reviewAt, 'review_at');
|
|
531
540
|
}
|
|
532
541
|
return this.versionedMutation({
|
|
@@ -801,6 +810,7 @@ export class CanonicalTaskService {
|
|
|
801
810
|
transition: {
|
|
802
811
|
to_status: input.transitionStatus,
|
|
803
812
|
...(input.patch.waiting_on !== undefined ? { waiting_on: input.patch.waiting_on } : {}),
|
|
813
|
+
...(input.patch.waiting_on_person_id !== undefined ? { waiting_on_person_id: input.patch.waiting_on_person_id } : {}),
|
|
804
814
|
...(input.patch.review_at !== undefined ? { review_at: input.patch.review_at } : {}),
|
|
805
815
|
},
|
|
806
816
|
};
|
|
@@ -818,6 +828,7 @@ export class CanonicalTaskService {
|
|
|
818
828
|
if (!isCanonicalTaskPriority(priority))
|
|
819
829
|
fail('validation_error', 'priority is invalid', 400, { field: 'priority' });
|
|
820
830
|
const purposeLabel = normalizePurposeLabel(input.purpose_label);
|
|
831
|
+
const waitingOnPersonId = normalizeWaitingOnPersonId(input.waiting_on_person_id);
|
|
821
832
|
const completionContract = normalizeCompletionContract(input.completion_contract);
|
|
822
833
|
return {
|
|
823
834
|
...(completionContract ? { completion_contract: completionContract } : {}),
|
|
@@ -832,6 +843,8 @@ export class CanonicalTaskService {
|
|
|
832
843
|
project_codes: normalizeProjectCodes(input.project_codes) ?? [],
|
|
833
844
|
// Only a label that is there is written, so a store without the column still accepts unlabelled work.
|
|
834
845
|
...(purposeLabel ? { purpose_label: purposeLabel } : {}),
|
|
846
|
+
// Likewise only a person that is there is written.
|
|
847
|
+
...(waitingOnPersonId ? { waiting_on_person_id: waitingOnPersonId } : {}),
|
|
835
848
|
};
|
|
836
849
|
}
|
|
837
850
|
normalizeUpdateInput(input) {
|
|
@@ -866,6 +879,8 @@ export class CanonicalTaskService {
|
|
|
866
879
|
patch.due_at = normalizeIsoDate(input.due_at, 'due_at');
|
|
867
880
|
if ('waiting_on' in input)
|
|
868
881
|
patch.waiting_on = normalizeString(input.waiting_on, 'waiting_on', { max: 500 });
|
|
882
|
+
if ('waiting_on_person_id' in input)
|
|
883
|
+
patch.waiting_on_person_id = normalizeWaitingOnPersonId(input.waiting_on_person_id);
|
|
869
884
|
if ('review_at' in input)
|
|
870
885
|
patch.review_at = normalizeIsoDate(input.review_at, 'review_at');
|
|
871
886
|
if ('source_refs' in input && hasSourceRefsAppend) {
|
|
@@ -1052,6 +1067,8 @@ export class CanonicalTaskService {
|
|
|
1052
1067
|
response.due_at = null;
|
|
1053
1068
|
if (response.waiting_on === undefined)
|
|
1054
1069
|
response.waiting_on = null;
|
|
1070
|
+
if (response.waiting_on_person_id === undefined)
|
|
1071
|
+
response.waiting_on_person_id = null;
|
|
1055
1072
|
if (response.review_at === undefined)
|
|
1056
1073
|
response.review_at = null;
|
|
1057
1074
|
if (response.completed_at === undefined)
|
package/dist/judgment-history.js
CHANGED
|
@@ -793,6 +793,79 @@ function groupFor(groups, sessionRef, key) {
|
|
|
793
793
|
groups.set(groupKey, group);
|
|
794
794
|
return group;
|
|
795
795
|
}
|
|
796
|
+
const FRAME_USE_ROLES = new Set(['constraint', 'criterion', 'prediction']);
|
|
797
|
+
const FRAME_USE_VERDICTS = new Set(['satisfied', 'violated', 'tension']);
|
|
798
|
+
const FRAME_PREDICTION_CHECKS = new Set(['held', 'failed', 'unchecked']);
|
|
799
|
+
/**
|
|
800
|
+
* The usage value shared by every writer of judgment history references
|
|
801
|
+
* (docs/specs/judgment-history-frame-basis.md): the role in the chosen option,
|
|
802
|
+
* then the constraint verdict or the prediction check.
|
|
803
|
+
*/
|
|
804
|
+
function frameUseUsage(use) {
|
|
805
|
+
const role = text(use.role);
|
|
806
|
+
if (!role || !FRAME_USE_ROLES.has(role))
|
|
807
|
+
return null;
|
|
808
|
+
if (role === 'prediction') {
|
|
809
|
+
const check = isObject(use.check) ? text(use.check.status) : null;
|
|
810
|
+
return `prediction:${check && FRAME_PREDICTION_CHECKS.has(check) ? check : 'unchecked'}`;
|
|
811
|
+
}
|
|
812
|
+
const verdict = text(use.verdict);
|
|
813
|
+
if (role === 'constraint')
|
|
814
|
+
return verdict && FRAME_USE_VERDICTS.has(verdict) ? `constraint:${verdict}` : null;
|
|
815
|
+
return verdict && FRAME_USE_VERDICTS.has(verdict) ? `criterion:${verdict}` : 'criterion';
|
|
816
|
+
}
|
|
817
|
+
/** Carry how the chosen option used each selected reference; rejected options never leak in. */
|
|
818
|
+
function frameReferencesWithUsage(frame) {
|
|
819
|
+
const references = frame.selected_references;
|
|
820
|
+
if (!Array.isArray(references))
|
|
821
|
+
return references;
|
|
822
|
+
const chosenLabel = text(frame.chosen_option);
|
|
823
|
+
const chosen = Array.isArray(frame.alternatives)
|
|
824
|
+
? frame.alternatives.find((option) => isObject(option) && chosenLabel !== null && option.label === chosenLabel)
|
|
825
|
+
: null;
|
|
826
|
+
const uses = isObject(chosen) && Array.isArray(chosen.uses) ? chosen.uses.filter(isObject) : [];
|
|
827
|
+
return references.map((reference) => {
|
|
828
|
+
if (!isObject(reference))
|
|
829
|
+
return reference;
|
|
830
|
+
const ref = text(reference.ref);
|
|
831
|
+
const use = ref ? uses.find((candidate) => text(candidate.ref) === ref) : undefined;
|
|
832
|
+
const usage = use ? frameUseUsage(use) : null;
|
|
833
|
+
return usage && reference.usage === undefined ? { ...reference, usage } : reference;
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Personal KG records the owner's answer applied in this turn. Only resolved
|
|
838
|
+
* answers count; their content never enters the history record.
|
|
839
|
+
*/
|
|
840
|
+
function personalKnowledgeReferences(events) {
|
|
841
|
+
const references = [];
|
|
842
|
+
const seen = new Set();
|
|
843
|
+
for (const event of events) {
|
|
844
|
+
if (event.success !== true || text(event.event_kind) !== 'personal_answer')
|
|
845
|
+
continue;
|
|
846
|
+
const metadata = isObject(event.safe_metadata) ? event.safe_metadata : null;
|
|
847
|
+
const answer = metadata && isObject(metadata.personal_answer) ? metadata.personal_answer : null;
|
|
848
|
+
if (!answer || text(answer.status) !== 'resolved' || !Array.isArray(answer.reference_ids))
|
|
849
|
+
continue;
|
|
850
|
+
for (const value of answer.reference_ids) {
|
|
851
|
+
const ref = safeId(value);
|
|
852
|
+
if (!ref || seen.has(ref))
|
|
853
|
+
continue;
|
|
854
|
+
seen.add(ref);
|
|
855
|
+
references.push({ ref, kind: 'personal_knowledge', version: null, digest: null, why: null, usage: 'applied', availability: 'unknown' });
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return references;
|
|
859
|
+
}
|
|
860
|
+
function withPersonalKnowledge(judgment, events) {
|
|
861
|
+
const personal = personalKnowledgeReferences(events);
|
|
862
|
+
if (personal.length === 0)
|
|
863
|
+
return judgment;
|
|
864
|
+
const existing = judgment.selected_references ?? [];
|
|
865
|
+
const known = new Set(existing.map((reference) => `${reference.kind ?? ''}\u0000${reference.ref}`));
|
|
866
|
+
const added = personal.filter((reference) => !known.has(`${reference.kind}\u0000${reference.ref}`));
|
|
867
|
+
return added.length === 0 ? judgment : { ...judgment, selected_references: [...existing, ...added] };
|
|
868
|
+
}
|
|
796
869
|
function sourceBlocks(value) {
|
|
797
870
|
if (!value)
|
|
798
871
|
return [];
|
|
@@ -808,7 +881,7 @@ function sourceBlocks(value) {
|
|
|
808
881
|
const frame = isObject(metadata.judgment_frame) ? metadata.judgment_frame : null;
|
|
809
882
|
if (frame)
|
|
810
883
|
blocks.push({
|
|
811
|
-
selected_references: frame
|
|
884
|
+
selected_references: frameReferencesWithUsage(frame),
|
|
812
885
|
alternatives: Array.isArray(frame.alternatives) ? frame.alternatives.map((option) => isObject(option) ? {
|
|
813
886
|
label: option.label,
|
|
814
887
|
evaluation: null,
|
|
@@ -1018,7 +1091,7 @@ function normalizeFinalRecord(final, sessionRef, key, configuredEntrypoint, turn
|
|
|
1018
1091
|
recorded_at: recordedAt,
|
|
1019
1092
|
project_code: projectCode,
|
|
1020
1093
|
turn_ref: `${sessionRef}/${sha256(turnId)}`,
|
|
1021
|
-
judgment: mergeJudgment(judgment, blocks, field(blocks[0] ?? null, 'missing_fields')),
|
|
1094
|
+
judgment: withPersonalKnowledge(mergeJudgment(judgment, blocks, field(blocks[0] ?? null, 'missing_fields')), events),
|
|
1022
1095
|
execution: mergeExecution({ ...execution, status: finalExecutionStatus }, [...executionBlocks(final), ...events.flatMap((event) => executionBlocks(event)).reverse()], completed)
|
|
1023
1096
|
};
|
|
1024
1097
|
return { ...baseRecord, missing_fields: missingFields(baseRecord, firstPresent(blocks, 'missing_fields')) };
|
|
@@ -1034,7 +1107,7 @@ function mergeRecordWithFinal(adoptionRecord, final, sessionRef, key, turnInput,
|
|
|
1034
1107
|
recorded_at: projected.recorded_at,
|
|
1035
1108
|
project_code: adoptionRecord.project_code ?? projected.project_code,
|
|
1036
1109
|
entrypoint: adoptionRecord.entrypoint === 'unknown' ? projected.entrypoint : adoptionRecord.entrypoint,
|
|
1037
|
-
judgment: mergeJudgment(adoptionRecord.judgment, blocks, undefined),
|
|
1110
|
+
judgment: withPersonalKnowledge(mergeJudgment(adoptionRecord.judgment, blocks, undefined), events),
|
|
1038
1111
|
execution
|
|
1039
1112
|
};
|
|
1040
1113
|
return { ...baseRecord, missing_fields: missingFields(baseRecord, firstPresent(blocks, 'missing_fields')) };
|
|
@@ -44,6 +44,9 @@ function routeFor(pathname, basePath) {
|
|
|
44
44
|
if (segments.length === 4 && noun === 'minutes' && minutesId && action === 'confirm') {
|
|
45
45
|
return { kind: 'confirm', meetingId, minutesId };
|
|
46
46
|
}
|
|
47
|
+
if (segments.length === 4 && noun === 'minutes' && minutesId && action === 'withdraw') {
|
|
48
|
+
return { kind: 'withdraw', meetingId, minutesId };
|
|
49
|
+
}
|
|
47
50
|
if (segments.length === 5 && noun === 'minutes' && minutesId && action === 'versions' && versionId) {
|
|
48
51
|
return { kind: 'version', meetingId, minutesId, versionId };
|
|
49
52
|
}
|
|
@@ -157,6 +160,13 @@ function confirmInput(body, minutesId, key, fingerprint) {
|
|
|
157
160
|
...idempotencyFields(key, fingerprint)
|
|
158
161
|
};
|
|
159
162
|
}
|
|
163
|
+
function withdrawInput(body, minutesId, key, fingerprint) {
|
|
164
|
+
return {
|
|
165
|
+
minutes_id: minutesId,
|
|
166
|
+
expected_revision: body.expected_revision,
|
|
167
|
+
...idempotencyFields(key, fingerprint)
|
|
168
|
+
};
|
|
169
|
+
}
|
|
160
170
|
export function createMeetingMinutesHttpHandler(options) {
|
|
161
171
|
if (!options || !options.store || typeof options.resolveContext !== 'function') {
|
|
162
172
|
throw new TypeError('store and resolveContext are required');
|
|
@@ -202,6 +212,15 @@ export function createMeetingMinutesHttpHandler(options) {
|
|
|
202
212
|
}
|
|
203
213
|
return { statusCode: 200, body: await options.store.confirm_version(confirmInput(body, document.minutes_id, key, fingerprint), context) };
|
|
204
214
|
}
|
|
215
|
+
case 'withdraw': {
|
|
216
|
+
if (body === undefined)
|
|
217
|
+
throw new MeetingMinutesError('invalid_input', 'Request body is required');
|
|
218
|
+
const detail = await options.store.get_meeting(route.meetingId ?? '', context);
|
|
219
|
+
const document = detail.minutes.find((candidate) => candidate.minutes_id === route.minutesId);
|
|
220
|
+
if (!document)
|
|
221
|
+
throw new MeetingMinutesError('not_found', `Minutes document ${route.minutesId} was not found`);
|
|
222
|
+
return { statusCode: 200, body: await options.store.withdraw_minutes(withdrawInput(body, document.minutes_id, key, fingerprint), context) };
|
|
223
|
+
}
|
|
205
224
|
case 'version':
|
|
206
225
|
return {
|
|
207
226
|
statusCode: 200,
|
package/dist/meeting-minutes.js
CHANGED
|
@@ -1132,6 +1132,10 @@ export function createMeetingMinutesStore(options) {
|
|
|
1132
1132
|
const meeting = findMeeting(snapshot, document.meeting_id);
|
|
1133
1133
|
await authorized(authorizer, 'write', meeting, context);
|
|
1134
1134
|
await authorized(authorizer, 'write', document, context);
|
|
1135
|
+
// Only the person who made the document takes it back (story-meeting-minutes-edit-and-withdraw-ui-v1).
|
|
1136
|
+
if (document.created_actor_id !== principal) {
|
|
1137
|
+
throw new MeetingMinutesError('authorization_denied', 'Only the person who made this minutes document can withdraw it');
|
|
1138
|
+
}
|
|
1135
1139
|
// Withdrawing twice keeps the first record; a retry is not a second withdrawal.
|
|
1136
1140
|
if (document.withdrawal && !idempotency.token)
|
|
1137
1141
|
return detailForCaller(snapshot, meeting, context);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unson/brainbase-mcp",
|
|
3
|
-
"version": "0.41.
|
|
3
|
+
"version": "0.41.11",
|
|
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",
|
|
@@ -483,5 +483,5 @@
|
|
|
483
483
|
"engines": {
|
|
484
484
|
"node": ">=20"
|
|
485
485
|
},
|
|
486
|
-
"gitHead": "
|
|
486
|
+
"gitHead": "3849d107c129672e91d6c28cfa3b8b5053d7f53a"
|
|
487
487
|
}
|
package/ui/judgment-history.css
CHANGED
|
@@ -292,7 +292,7 @@
|
|
|
292
292
|
}
|
|
293
293
|
|
|
294
294
|
.bb-jh-ledger .bb-ws-ledger-row {
|
|
295
|
-
grid-template-columns: 92px minmax(0, 1fr) 250px
|
|
295
|
+
grid-template-columns: 92px minmax(0, 1fr) 250px 120px;
|
|
296
296
|
align-items: center;
|
|
297
297
|
min-height: 52px;
|
|
298
298
|
}
|
|
@@ -581,7 +581,7 @@
|
|
|
581
581
|
.bb-jh-ledger .bb-ws-ledger-row > span:nth-child(1)::before { content: '日時'; }
|
|
582
582
|
.bb-jh-ledger .bb-ws-ledger-row > span:nth-child(2)::before { content: '行った判断'; }
|
|
583
583
|
.bb-jh-ledger .bb-ws-ledger-row > span:nth-child(3)::before { content: '使った参照'; }
|
|
584
|
-
.bb-jh-ledger .bb-ws-ledger-row > span:nth-child(4)::before { content: '
|
|
584
|
+
.bb-jh-ledger .bb-ws-ledger-row > span:nth-child(4)::before { content: '判断したAI'; }
|
|
585
585
|
}
|
|
586
586
|
|
|
587
587
|
/* Compact workspace header, search controls and shared floating notifications. */
|
|
@@ -617,3 +617,156 @@
|
|
|
617
617
|
}
|
|
618
618
|
.bb-jh-notifications .bb-jh-banner.is-danger { border-left-color: var(--bb-color-notice-danger); }
|
|
619
619
|
.bb-jh-notifications .bb-jh-banner-sources > span { white-space: normal; }
|
|
620
|
+
|
|
621
|
+
/* Loading stays in the page, like the other workspace screens. */
|
|
622
|
+
.bb-jh-loading { color: var(--bb-color-muted); }
|
|
623
|
+
.bb-jh-summary-note { font-size: 11.5px; }
|
|
624
|
+
.bb-jh-entrypoint { display: grid; gap: 2px; }
|
|
625
|
+
.bb-jh-entrypoint small.bb-jh-waiting { color: var(--bb-color-warning-strong, var(--bb-color-accent-strong)); font-size: 11px; font-weight: 600; }
|
|
626
|
+
.bb-jh-filter-fields .bb-jh-filter .bb-ws-combobox { width: 100%; }
|
|
627
|
+
|
|
628
|
+
/* Detail: references that only have an id, the one question, and the record details. */
|
|
629
|
+
.bb-jh-references { display: grid; gap: 8px; }
|
|
630
|
+
.bb-jh-reference-list small { color: var(--bb-color-quiet); font-size: 11px; }
|
|
631
|
+
.bb-jh-reference-kinds { margin: 0; color: var(--bb-color-ink); font-size: 13px; font-weight: 600; }
|
|
632
|
+
.bb-jh-references .bb-jh-reference-note,
|
|
633
|
+
.bb-jh-handoff .bb-jh-reference-note { margin: 0; }
|
|
634
|
+
.bb-jh-feedback { display: grid; gap: 12px; }
|
|
635
|
+
.bb-jh-feedback-events { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; }
|
|
636
|
+
.bb-jh-feedback-answers { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
637
|
+
.bb-jh-feedback-composer > .bb-ws-button { justify-self: start; }
|
|
638
|
+
.bb-jh-record-details { margin-top: 10px; }
|
|
639
|
+
.bb-jh-record-details > summary { color: var(--bb-color-muted); font-size: 12px; cursor: pointer; }
|
|
640
|
+
.bb-jh-record-details[open] > summary { margin-bottom: 8px; }
|
|
641
|
+
.bb-jh-record-details .bb-ws-definition dd { overflow-wrap: anywhere; }
|
|
642
|
+
.bb-jh-id-list { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; font-family: var(--bb-font-mono); font-size: 10.5px; color: var(--bb-color-quiet); overflow-wrap: anywhere; }
|
|
643
|
+
.bb-jh-handoff { display: grid; gap: 6px; margin-top: 14px; }
|
|
644
|
+
.bb-jh-handoff h4 { margin: 0; font-size: 12.5px; color: var(--bb-color-ink); }
|
|
645
|
+
.bb-jh-feedback-answers .bb-ws-button[aria-pressed="true"] { border-color: var(--bb-color-accent); background: var(--bb-color-accent-soft, #eeebfd); color: var(--bb-color-accent-strong, var(--bb-color-accent)); }
|
|
646
|
+
.bb-jh-feedback-composer [data-action="submit-judgment-feedback"] { border-color: var(--bb-color-accent); background: var(--bb-color-accent); color: #fff; }
|
|
647
|
+
.bb-jh-feedback-composer [data-action="submit-judgment-feedback"]:disabled { opacity: .55; cursor: default; }
|
|
648
|
+
.bb-jh-feedback-composer textarea,
|
|
649
|
+
.bb-jh-reference-export textarea { box-sizing: border-box; }
|
|
650
|
+
|
|
651
|
+
/* 判断の根拠と本人の考え (story-judgment-history-frame-basis-v1) */
|
|
652
|
+
.bb-jh-basis {
|
|
653
|
+
display: grid;
|
|
654
|
+
gap: 14px;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.bb-jh-basis-group {
|
|
658
|
+
display: grid;
|
|
659
|
+
gap: 6px;
|
|
660
|
+
min-width: 0;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
.bb-jh-basis-group h4 {
|
|
664
|
+
margin: 0;
|
|
665
|
+
color: var(--bb-color-muted);
|
|
666
|
+
font-size: 11px;
|
|
667
|
+
font-weight: 680;
|
|
668
|
+
letter-spacing: 0.04em;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.bb-jh-basis-list {
|
|
672
|
+
display: grid;
|
|
673
|
+
gap: 10px;
|
|
674
|
+
margin: 0;
|
|
675
|
+
padding: 0;
|
|
676
|
+
list-style: none;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
.bb-jh-basis-list li {
|
|
680
|
+
display: grid;
|
|
681
|
+
gap: 3px;
|
|
682
|
+
min-width: 0;
|
|
683
|
+
padding-left: 10px;
|
|
684
|
+
border-left: 2px solid var(--bb-color-border);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
.bb-jh-basis-list strong {
|
|
688
|
+
color: var(--bb-color-ink);
|
|
689
|
+
font-size: 13px;
|
|
690
|
+
line-height: 1.45;
|
|
691
|
+
overflow-wrap: anywhere;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.bb-jh-basis-list strong.bb-jh-unrecorded {
|
|
695
|
+
color: var(--bb-color-quiet);
|
|
696
|
+
font-weight: 500;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
.bb-jh-basis-usage {
|
|
700
|
+
color: var(--bb-color-muted);
|
|
701
|
+
font-size: 12px;
|
|
702
|
+
line-height: 1.5;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
.bb-jh-basis-usage.is-violated,
|
|
706
|
+
.bb-jh-basis-usage.is-failed {
|
|
707
|
+
color: var(--bb-color-danger);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.bb-jh-basis-usage.is-tension {
|
|
711
|
+
color: var(--bb-color-warning);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
.bb-jh-basis-usage.is-unrecorded {
|
|
715
|
+
color: var(--bb-color-quiet);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
.bb-jh-basis-why {
|
|
719
|
+
color: var(--bb-color-muted);
|
|
720
|
+
font-size: 12px;
|
|
721
|
+
line-height: 1.5;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.bb-jh-basis-list small {
|
|
725
|
+
color: var(--bb-color-quiet);
|
|
726
|
+
font-size: 11px;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
.bb-jh-owner {
|
|
730
|
+
display: grid;
|
|
731
|
+
gap: 4px;
|
|
732
|
+
padding: 10px 12px;
|
|
733
|
+
border: 1px solid var(--bb-color-border);
|
|
734
|
+
border-radius: var(--bb-radius-sm);
|
|
735
|
+
background: var(--bb-color-panel);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
.bb-jh-owner.is-applied {
|
|
739
|
+
border-color: var(--bb-color-accent);
|
|
740
|
+
background: var(--bb-color-accent-soft);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.bb-jh-owner strong {
|
|
744
|
+
color: var(--bb-color-ink);
|
|
745
|
+
font-size: 13px;
|
|
746
|
+
line-height: 1.5;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
.bb-jh-owner p {
|
|
750
|
+
margin: 0;
|
|
751
|
+
color: var(--bb-color-muted);
|
|
752
|
+
font-size: 12px;
|
|
753
|
+
line-height: 1.5;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
.bb-jh-owner-badge {
|
|
757
|
+
width: fit-content;
|
|
758
|
+
padding: 1px 7px;
|
|
759
|
+
border: 1px solid var(--bb-color-border);
|
|
760
|
+
border-radius: 999px;
|
|
761
|
+
color: var(--bb-color-quiet);
|
|
762
|
+
font-size: 11px;
|
|
763
|
+
line-height: 1.6;
|
|
764
|
+
white-space: nowrap;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
.bb-jh-owner-badge.is-applied {
|
|
768
|
+
border-color: var(--bb-color-accent);
|
|
769
|
+
background: var(--bb-color-accent-soft);
|
|
770
|
+
color: var(--bb-color-accent-strong);
|
|
771
|
+
font-weight: 680;
|
|
772
|
+
}
|