@unson/brainbase-mcp 0.21.2 → 0.22.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/local-web-fetch-bridge.js +1 -1
- package/dist/local-web-host.d.ts +59 -0
- package/dist/local-web-host.js +171 -4
- package/dist/meeting-minutes-http.d.ts +22 -0
- package/dist/meeting-minutes-http.js +252 -0
- package/dist/meeting-minutes-lineage-adapters.d.ts +157 -0
- package/dist/meeting-minutes-lineage-adapters.js +410 -0
- package/dist/meeting-minutes-lineage-http.d.ts +20 -0
- package/dist/meeting-minutes-lineage-http.js +221 -0
- package/dist/meeting-minutes-lineage-lifecycle.d.ts +58 -0
- package/dist/meeting-minutes-lineage-lifecycle.js +146 -0
- package/dist/meeting-minutes-lineage.d.ts +307 -0
- package/dist/meeting-minutes-lineage.js +1030 -0
- package/dist/meeting-minutes-storage-controller.d.ts +182 -0
- package/dist/meeting-minutes-storage-controller.js +366 -0
- package/dist/meeting-minutes-storage-http.d.ts +25 -0
- package/dist/meeting-minutes-storage-http.js +312 -0
- package/dist/meeting-minutes-storage.d.ts +169 -0
- package/dist/meeting-minutes-storage.js +402 -0
- package/dist/meeting-minutes.d.ts +223 -0
- package/dist/meeting-minutes.js +1172 -0
- package/package.json +46 -3
- package/ui/brainbase-tokens.css +35 -35
- package/ui/local-web-shell.css +20 -17
- package/ui/local-web-shell.js +34 -1
- package/ui/meeting-minutes-lineage-http.js +247 -0
- package/ui/meeting-minutes-lineage.css +177 -0
- package/ui/meeting-minutes-lineage.js +485 -0
- package/ui/meeting-minutes-storage.css +170 -0
- package/ui/meeting-minutes-storage.js +388 -0
- package/ui/meeting-minutes.css +215 -0
- package/ui/meeting-minutes.js +622 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unson/brainbase-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.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",
|
|
@@ -115,6 +115,22 @@
|
|
|
115
115
|
"types": "./dist/company-os-learning-adoption.d.ts",
|
|
116
116
|
"import": "./dist/company-os-learning-adoption.js"
|
|
117
117
|
},
|
|
118
|
+
"./meeting-minutes-lineage": {
|
|
119
|
+
"types": "./dist/meeting-minutes-lineage.d.ts",
|
|
120
|
+
"import": "./dist/meeting-minutes-lineage.js"
|
|
121
|
+
},
|
|
122
|
+
"./meeting-minutes-lineage-adapters": {
|
|
123
|
+
"types": "./dist/meeting-minutes-lineage-adapters.d.ts",
|
|
124
|
+
"import": "./dist/meeting-minutes-lineage-adapters.js"
|
|
125
|
+
},
|
|
126
|
+
"./meeting-minutes-lineage-http": {
|
|
127
|
+
"types": "./dist/meeting-minutes-lineage-http.d.ts",
|
|
128
|
+
"import": "./dist/meeting-minutes-lineage-http.js"
|
|
129
|
+
},
|
|
130
|
+
"./meeting-minutes-lineage-lifecycle": {
|
|
131
|
+
"types": "./dist/meeting-minutes-lineage-lifecycle.d.ts",
|
|
132
|
+
"import": "./dist/meeting-minutes-lineage-lifecycle.js"
|
|
133
|
+
},
|
|
118
134
|
"./constraint-resolution": {
|
|
119
135
|
"types": "./dist/constraint-resolution.d.ts",
|
|
120
136
|
"import": "./dist/constraint-resolution.js"
|
|
@@ -211,6 +227,22 @@
|
|
|
211
227
|
"types": "./dist/streamable-http.d.ts",
|
|
212
228
|
"import": "./dist/streamable-http.js"
|
|
213
229
|
},
|
|
230
|
+
"./meeting-minutes": {
|
|
231
|
+
"types": "./dist/meeting-minutes.d.ts",
|
|
232
|
+
"import": "./dist/meeting-minutes.js"
|
|
233
|
+
},
|
|
234
|
+
"./meeting-minutes-http": {
|
|
235
|
+
"types": "./dist/meeting-minutes-http.d.ts",
|
|
236
|
+
"import": "./dist/meeting-minutes-http.js"
|
|
237
|
+
},
|
|
238
|
+
"./meeting-minutes-storage": {
|
|
239
|
+
"types": "./dist/meeting-minutes-storage.d.ts",
|
|
240
|
+
"import": "./dist/meeting-minutes-storage.js"
|
|
241
|
+
},
|
|
242
|
+
"./meeting-minutes-storage-controller": {
|
|
243
|
+
"types": "./dist/meeting-minutes-storage-controller.d.ts",
|
|
244
|
+
"import": "./dist/meeting-minutes-storage-controller.js"
|
|
245
|
+
},
|
|
214
246
|
"./ui/outcome-knowledge": "./ui/outcome-knowledge.js",
|
|
215
247
|
"./ui/outcome-knowledge.css": "./ui/outcome-knowledge.css",
|
|
216
248
|
"./ui/judgment-view": "./ui/judgment-view.js",
|
|
@@ -221,6 +253,8 @@
|
|
|
221
253
|
"./ui/value-proof-review.css": "./ui/value-proof-review.css",
|
|
222
254
|
"./ui/judgment-history": "./ui/judgment-history.js",
|
|
223
255
|
"./ui/judgment-history.css": "./ui/judgment-history.css",
|
|
256
|
+
"./ui/meeting-minutes": "./ui/meeting-minutes.js",
|
|
257
|
+
"./ui/meeting-minutes.css": "./ui/meeting-minutes.css",
|
|
224
258
|
"./ui/objective-editor-http-port": "./ui/objective-editor-http-port.js",
|
|
225
259
|
"./ui/world-model-view": "./ui/world-model-view.js",
|
|
226
260
|
"./ui/world-model-view.css": "./ui/world-model-view.css",
|
|
@@ -238,7 +272,12 @@
|
|
|
238
272
|
"./ui/graph-projects-view.css": "./ui/graph-projects-view.css",
|
|
239
273
|
"./ui/graph-registry-view": "./ui/graph-registry-view.js",
|
|
240
274
|
"./ui/graph-registry-view.css": "./ui/graph-registry-view.css",
|
|
275
|
+
"./ui/meeting-minutes-storage": "./ui/meeting-minutes-storage.js",
|
|
276
|
+
"./ui/meeting-minutes-storage.css": "./ui/meeting-minutes-storage.css",
|
|
241
277
|
"./ui/brainbase-tokens.css": "./ui/brainbase-tokens.css",
|
|
278
|
+
"./ui/meeting-minutes-lineage": "./ui/meeting-minutes-lineage.js",
|
|
279
|
+
"./ui/meeting-minutes-lineage.css": "./ui/meeting-minutes-lineage.css",
|
|
280
|
+
"./ui/meeting-minutes-lineage-http": "./ui/meeting-minutes-lineage-http.js",
|
|
242
281
|
"./dist/*": "./dist/*",
|
|
243
282
|
"./contracts/judgment-dag/schema.json": "./contracts/judgment-dag/schema.json",
|
|
244
283
|
"./contracts/judgment-dag/fixture.json": "./contracts/judgment-dag/fixture.json",
|
|
@@ -292,7 +331,11 @@
|
|
|
292
331
|
"./ui/project-overview": "./ui/project-overview.js",
|
|
293
332
|
"./ui/project-graph": "./ui/project-graph.js",
|
|
294
333
|
"./ui/project-workspace.css": "./ui/project-workspace.css",
|
|
295
|
-
"./ui/project-graph-vendor.js": "./ui/project-graph-vendor.js"
|
|
334
|
+
"./ui/project-graph-vendor.js": "./ui/project-graph-vendor.js",
|
|
335
|
+
"./meeting-minutes-storage-http": {
|
|
336
|
+
"types": "./dist/meeting-minutes-storage-http.d.ts",
|
|
337
|
+
"import": "./dist/meeting-minutes-storage-http.js"
|
|
338
|
+
}
|
|
296
339
|
},
|
|
297
340
|
"bin": {
|
|
298
341
|
"brainbase-mcp": "dist/index.js",
|
|
@@ -364,5 +407,5 @@
|
|
|
364
407
|
"engines": {
|
|
365
408
|
"node": ">=20"
|
|
366
409
|
},
|
|
367
|
-
"gitHead": "
|
|
410
|
+
"gitHead": "4933fdd273d050d9fa76f46b5d3696c1657613eb"
|
|
368
411
|
}
|
package/ui/brainbase-tokens.css
CHANGED
|
@@ -7,47 +7,47 @@
|
|
|
7
7
|
* truth for every Brainbase Web surface.
|
|
8
8
|
*/
|
|
9
9
|
:root {
|
|
10
|
-
--bb-color-ink: #
|
|
11
|
-
--bb-color-muted: #
|
|
12
|
-
--bb-color-quiet: #
|
|
13
|
-
--bb-color-border: #
|
|
14
|
-
--bb-color-border-strong: #
|
|
15
|
-
--bb-color-control-border: #
|
|
16
|
-
--bb-color-paper: #
|
|
17
|
-
--bb-color-canvas: #
|
|
10
|
+
--bb-color-ink: #202124;
|
|
11
|
+
--bb-color-muted: #6b6b73;
|
|
12
|
+
--bb-color-quiet: #76767f;
|
|
13
|
+
--bb-color-border: #e5e5e9;
|
|
14
|
+
--bb-color-border-strong: #c9c9d1;
|
|
15
|
+
--bb-color-control-border: #d7d7de;
|
|
16
|
+
--bb-color-paper: #ffffff;
|
|
17
|
+
--bb-color-canvas: #f6f6f8;
|
|
18
18
|
--bb-color-panel: #ffffff;
|
|
19
|
-
--bb-color-surface: #
|
|
20
|
-
--bb-color-header-start: #
|
|
21
|
-
--bb-color-header-end: #
|
|
22
|
-
--bb-color-eyebrow: #
|
|
23
|
-
--bb-color-accent: #
|
|
24
|
-
--bb-color-accent-soft: #
|
|
25
|
-
--bb-color-accent-strong: #
|
|
26
|
-
--bb-color-action: #
|
|
27
|
-
--bb-color-action-hover: #
|
|
19
|
+
--bb-color-surface: #f6f6f8;
|
|
20
|
+
--bb-color-header-start: #ffffff;
|
|
21
|
+
--bb-color-header-end: #f6f6f8;
|
|
22
|
+
--bb-color-eyebrow: #5b4bd8;
|
|
23
|
+
--bb-color-accent: #5b4bd8;
|
|
24
|
+
--bb-color-accent-soft: #efedff;
|
|
25
|
+
--bb-color-accent-strong: #4939b8;
|
|
26
|
+
--bb-color-action: #5b4bd8;
|
|
27
|
+
--bb-color-action-hover: #4939b8;
|
|
28
28
|
--bb-color-action-text: #ffffff;
|
|
29
|
-
--bb-color-focus: #
|
|
30
|
-
--bb-color-project-ink: #
|
|
31
|
-
--bb-color-project-muted: #
|
|
32
|
-
--bb-color-project-border: #
|
|
33
|
-
--bb-color-project-border-strong: #
|
|
34
|
-
--bb-color-project-accent: #
|
|
35
|
-
--bb-color-project-accent-strong: #
|
|
36
|
-
--bb-color-success: #
|
|
37
|
-
--bb-color-success-soft: #
|
|
29
|
+
--bb-color-focus: #5b4bd8;
|
|
30
|
+
--bb-color-project-ink: #202124;
|
|
31
|
+
--bb-color-project-muted: #6b6b73;
|
|
32
|
+
--bb-color-project-border: #e5e5e9;
|
|
33
|
+
--bb-color-project-border-strong: #c9c9d1;
|
|
34
|
+
--bb-color-project-accent: #5b4bd8;
|
|
35
|
+
--bb-color-project-accent-strong: #4939b8;
|
|
36
|
+
--bb-color-success: #18794e;
|
|
37
|
+
--bb-color-success-soft: #e4f5eb;
|
|
38
38
|
--bb-color-warning: #8a631d;
|
|
39
39
|
--bb-color-warning-soft: #fff0c7;
|
|
40
40
|
--bb-color-danger: #d92335;
|
|
41
41
|
--bb-color-danger-soft: #fde9eb;
|
|
42
|
-
--bb-color-rail: #
|
|
43
|
-
--bb-color-rail-border: #
|
|
44
|
-
--bb-color-rail-text: #
|
|
45
|
-
--bb-color-rail-muted: #
|
|
46
|
-
--bb-color-rail-hover: #
|
|
47
|
-
--bb-color-rail-active: #
|
|
48
|
-
--bb-color-rail-strong: #
|
|
49
|
-
--bb-color-overlay: rgb(
|
|
50
|
-
--bb-shadow: 0 16px 42px rgb(
|
|
42
|
+
--bb-color-rail: #ffffff;
|
|
43
|
+
--bb-color-rail-border: #e5e5e9;
|
|
44
|
+
--bb-color-rail-text: #202124;
|
|
45
|
+
--bb-color-rail-muted: #6b6b73;
|
|
46
|
+
--bb-color-rail-hover: #f6f6f8;
|
|
47
|
+
--bb-color-rail-active: #efedff;
|
|
48
|
+
--bb-color-rail-strong: #202124;
|
|
49
|
+
--bb-color-overlay: rgb(32 33 36 / 40%);
|
|
50
|
+
--bb-shadow: 0 16px 42px rgb(32 33 36 / 10%);
|
|
51
51
|
--bb-font-sans: Geist, "Noto Sans JP", "Hiragino Sans", system-ui, sans-serif;
|
|
52
52
|
--bb-font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
53
53
|
--bb-radius-sm: 7px;
|
package/ui/local-web-shell.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Shell of the local Web host, in the organization edition's layout: a
|
|
2
|
+
* Shell of the local Web host, in the organization edition's layout: a white
|
|
3
3
|
* left rail (brand, navigation, source) and a paper workspace. Uses only the
|
|
4
4
|
* shared tokens in brainbase-tokens.css.
|
|
5
5
|
*/
|
|
@@ -51,15 +51,15 @@ body {
|
|
|
51
51
|
flex-direction: column;
|
|
52
52
|
overflow: auto;
|
|
53
53
|
border-right: 1px solid var(--bb-color-rail-border);
|
|
54
|
-
padding:
|
|
54
|
+
padding: 18px 12px 14px;
|
|
55
55
|
background: var(--bb-color-rail);
|
|
56
56
|
color: var(--bb-color-rail-text);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
.bb-shell-brand {
|
|
60
|
-
padding: 0
|
|
60
|
+
padding: 0 10px 22px;
|
|
61
61
|
color: var(--bb-color-rail-strong);
|
|
62
|
-
font-size:
|
|
62
|
+
font-size: 19px;
|
|
63
63
|
font-weight: 780;
|
|
64
64
|
line-height: 1;
|
|
65
65
|
letter-spacing: -.035em;
|
|
@@ -67,17 +67,17 @@ body {
|
|
|
67
67
|
|
|
68
68
|
.bb-shell-nav {
|
|
69
69
|
display: grid;
|
|
70
|
-
gap:
|
|
70
|
+
gap: 2px;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
.bb-shell-nav-link {
|
|
74
|
-
min-height:
|
|
74
|
+
min-height: 38px;
|
|
75
75
|
display: flex;
|
|
76
76
|
align-items: center;
|
|
77
|
-
gap:
|
|
78
|
-
border-radius:
|
|
79
|
-
padding: 0
|
|
80
|
-
color: var(--bb-color-rail-
|
|
77
|
+
gap: 11px;
|
|
78
|
+
border-radius: 7px;
|
|
79
|
+
padding: 0 10px;
|
|
80
|
+
color: var(--bb-color-rail-muted);
|
|
81
81
|
font-size: 13px;
|
|
82
82
|
font-weight: 620;
|
|
83
83
|
text-decoration: none;
|
|
@@ -90,8 +90,8 @@ body {
|
|
|
90
90
|
|
|
91
91
|
.bb-shell-nav-link[aria-current="page"] {
|
|
92
92
|
background: var(--bb-color-rail-active);
|
|
93
|
-
color: var(--bb-color-
|
|
94
|
-
box-shadow:
|
|
93
|
+
color: var(--bb-color-accent);
|
|
94
|
+
box-shadow: none;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
.bb-shell-icon {
|
|
@@ -137,9 +137,12 @@ body {
|
|
|
137
137
|
font-size: 11px;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
.bb-shell-fact.is-warning .bb-shell-fact-value
|
|
140
|
+
.bb-shell-fact.is-warning .bb-shell-fact-value {
|
|
141
|
+
color: var(--bb-color-warning);
|
|
142
|
+
}
|
|
143
|
+
|
|
141
144
|
.bb-shell-source .is-danger {
|
|
142
|
-
color: var(--bb-color-
|
|
145
|
+
color: var(--bb-color-danger);
|
|
143
146
|
}
|
|
144
147
|
|
|
145
148
|
.bb-shell-source .bb-shell-link-button {
|
|
@@ -150,7 +153,7 @@ body {
|
|
|
150
153
|
|
|
151
154
|
/* Right detail rail (the organization edition's decision rail) */
|
|
152
155
|
.bb-shell.has-rail {
|
|
153
|
-
grid-template-columns: 240px minmax(0, 1fr)
|
|
156
|
+
grid-template-columns: 240px minmax(0, 1fr) 360px;
|
|
154
157
|
}
|
|
155
158
|
|
|
156
159
|
.bb-shell-rail {
|
|
@@ -160,7 +163,7 @@ body {
|
|
|
160
163
|
min-width: 0;
|
|
161
164
|
overflow: auto;
|
|
162
165
|
border-left: 1px solid var(--bb-color-border);
|
|
163
|
-
padding:
|
|
166
|
+
padding: 28px 22px 36px;
|
|
164
167
|
background: var(--bb-color-surface);
|
|
165
168
|
}
|
|
166
169
|
|
|
@@ -194,7 +197,7 @@ body {
|
|
|
194
197
|
max-width: 1440px;
|
|
195
198
|
min-width: 0;
|
|
196
199
|
margin: 0 auto;
|
|
197
|
-
padding:
|
|
200
|
+
padding: 20px 24px 52px;
|
|
198
201
|
}
|
|
199
202
|
|
|
200
203
|
.bb-shell-objectives,
|
package/ui/local-web-shell.js
CHANGED
|
@@ -20,6 +20,9 @@ import { createGraphRegistryView } from './graph-registry-view.js';
|
|
|
20
20
|
import { createObjectiveEditorController } from './objective-editor.js';
|
|
21
21
|
import { createObjectiveEditorHttpPort } from './objective-editor-http-port.js';
|
|
22
22
|
import { createJudgmentHistoryUI } from './judgment-history.js';
|
|
23
|
+
import { createMeetingMinutesUI } from './meeting-minutes.js';
|
|
24
|
+
import { createMeetingMinutesStorageExtension } from './meeting-minutes-storage.js';
|
|
25
|
+
import { createMeetingMinutesLineageExtension } from './meeting-minutes-lineage-http.js';
|
|
23
26
|
import { createWorldModelView } from './world-model-view.js';
|
|
24
27
|
import { createGraphClient } from './graph-view-shared.js';
|
|
25
28
|
|
|
@@ -43,6 +46,7 @@ const NAV_ICON_PATHS = Object.freeze({
|
|
|
43
46
|
objectives: ['M12 4 3 20h18z', 'M12 9v5m0 3h.01'],
|
|
44
47
|
projects: ['M3 6.5h7l2 2h9v10H3z', 'M3 6.5v-2h7l2 2'],
|
|
45
48
|
graph: ['M10 13a5 5 0 0 0 7.5.5l2-2a5 5 0 0 0-7-7l-1.2 1.2', 'M14 11a5 5 0 0 0-7.5-.5l-2 2a5 5 0 0 0 7 7l1.2-1.2'],
|
|
49
|
+
minutes: ['M6 3.5h9l3 3V20.5H6z', 'M15 3.5v4h3', 'M9 12h6m-6 3h6'],
|
|
46
50
|
// World view (extension id `world`, ledger P17).
|
|
47
51
|
world: ['M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18z', 'M3 12h18', 'M12 3c2.5 2.6 3.8 5.6 3.8 9s-1.3 6.4-3.8 9c-2.5-2.6-3.8-5.6-3.8-9S9.5 5.6 12 3z'],
|
|
48
52
|
});
|
|
@@ -156,6 +160,32 @@ function mountToday(container, context) {
|
|
|
156
160
|
});
|
|
157
161
|
}
|
|
158
162
|
|
|
163
|
+
function mountMeetingMinutes(container, context) {
|
|
164
|
+
const versionActionExtensions = [];
|
|
165
|
+
if (context.meetingMinutesStorage) versionActionExtensions.push(createMeetingMinutesStorageExtension({
|
|
166
|
+
fetcher: context.fetcher,
|
|
167
|
+
token: context.token,
|
|
168
|
+
basePath: '/api/meeting-minutes',
|
|
169
|
+
defaultExternal: context.meetingMinutesStorage.defaultExternal,
|
|
170
|
+
}));
|
|
171
|
+
if (context.meetingMinutesLineage) versionActionExtensions.push(createMeetingMinutesLineageExtension({
|
|
172
|
+
fetcher: context.fetcher,
|
|
173
|
+
token: context.token,
|
|
174
|
+
basePath: '/api/meeting-minutes-lineage',
|
|
175
|
+
candidateDefaults: context.meetingMinutesLineage.candidateDefaults,
|
|
176
|
+
}));
|
|
177
|
+
return createMeetingMinutesUI({
|
|
178
|
+
root: makePage(container, context),
|
|
179
|
+
rail: context.rail,
|
|
180
|
+
page: context.page,
|
|
181
|
+
document: context.document,
|
|
182
|
+
fetcher: context.fetcher,
|
|
183
|
+
token: context.token,
|
|
184
|
+
basePath: '/api/meeting-minutes',
|
|
185
|
+
versionActionExtensions,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
159
189
|
function renderUnreadableObjectives(doc, slot, payload) {
|
|
160
190
|
slot.replaceChildren();
|
|
161
191
|
const count = Number.isInteger(payload?.unreadable?.count) ? payload.unreadable.count : 0;
|
|
@@ -221,6 +251,7 @@ function mountGraphScreen(screenId, createView) {
|
|
|
221
251
|
|
|
222
252
|
export const LOCAL_WEB_SCREENS = Object.freeze([
|
|
223
253
|
Object.freeze({ id: 'today', label: '今日', usesGraph: false, rail: true, source: '判断の記録', mount: mountToday }),
|
|
254
|
+
Object.freeze({ id: 'minutes', label: '議事録', usesGraph: false, rail: true, source: '正本の議事録', mount: mountMeetingMinutes }),
|
|
224
255
|
Object.freeze({ id: 'objectives', label: '目的と現状', usesGraph: true, rail: true, source: '手元のGraph', mount: mountObjectives }),
|
|
225
256
|
Object.freeze({ id: 'projects', label: 'プロジェクトと関係者', usesGraph: true, rail: true, source: '手元のGraph', mount: mountGraphScreen('projects', createGraphProjectsView) }),
|
|
226
257
|
Object.freeze({ id: 'graph', label: '情報と関係', usesGraph: true, rail: true, source: '手元のGraph', mount: mountGraphScreen('graph', createGraphRegistryView) }),
|
|
@@ -305,6 +336,8 @@ export function createLocalWebShell({
|
|
|
305
336
|
statusPath = '/api/local/status',
|
|
306
337
|
screens = LOCAL_WEB_SCREENS,
|
|
307
338
|
initialScreen,
|
|
339
|
+
meetingMinutesStorage = null,
|
|
340
|
+
meetingMinutesLineage = null,
|
|
308
341
|
} = {}) {
|
|
309
342
|
if (!root) throw new TypeError('root is required');
|
|
310
343
|
const doc = explicitDocument ?? (typeof document === 'undefined' ? null : document);
|
|
@@ -312,7 +345,7 @@ export function createLocalWebShell({
|
|
|
312
345
|
const request = typeof fetcher === 'function'
|
|
313
346
|
? fetcher
|
|
314
347
|
: typeof globalThis.fetch === 'function' ? (path, init) => globalThis.fetch(path, init) : null;
|
|
315
|
-
const context = Object.freeze({ document: doc, fetcher: request, token });
|
|
348
|
+
const context = Object.freeze({ document: doc, fetcher: request, token, meetingMinutesStorage, meetingMinutesLineage });
|
|
316
349
|
|
|
317
350
|
const status = { phase: 'loading', data: null, error: null };
|
|
318
351
|
const mounted = new Map();
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { createMeetingMinutesLineageView } from './meeting-minutes-lineage.js';
|
|
2
|
+
|
|
3
|
+
/** Browser-side transport and host action-slot bridge for the lineage screen. */
|
|
4
|
+
export const MEETING_MINUTES_LINEAGE_HTTP_UI_CONTRACT_VERSION = 'brainbase.meeting-minutes-lineage-http-ui.v1';
|
|
5
|
+
|
|
6
|
+
export function createMeetingMinutesLineageHttpActions({
|
|
7
|
+
reference,
|
|
8
|
+
basePath = '/api/meeting-minutes-lineage',
|
|
9
|
+
fetcher = globalThis.fetch,
|
|
10
|
+
token,
|
|
11
|
+
actorFor,
|
|
12
|
+
idFor,
|
|
13
|
+
idempotencyKeyFor,
|
|
14
|
+
} = {}) {
|
|
15
|
+
if (!reference || typeof reference !== 'object') throw new TypeError('reference is required');
|
|
16
|
+
if (typeof fetcher !== 'function') throw new TypeError('fetcher is required');
|
|
17
|
+
const auditActorFor = typeof actorFor === 'function' ? actorFor : () => ({ type: 'person', id: 'browser-ui' });
|
|
18
|
+
const operationIds = new Map();
|
|
19
|
+
const operationId = (candidate, action) => {
|
|
20
|
+
const stable = candidate && typeof candidate === 'object'
|
|
21
|
+
? (candidate.draftId ?? candidate.id ?? candidate.candidateId ?? candidate.candidate?.id)
|
|
22
|
+
: null;
|
|
23
|
+
const key = `${action}:${typeof stable === 'string' && stable ? stable : 'operation'}`;
|
|
24
|
+
let id = operationIds.get(key);
|
|
25
|
+
if (!id) {
|
|
26
|
+
id = typeof globalThis.crypto?.randomUUID === 'function'
|
|
27
|
+
? globalThis.crypto.randomUUID()
|
|
28
|
+
: `lineage-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
29
|
+
operationIds.set(key, id);
|
|
30
|
+
}
|
|
31
|
+
return id;
|
|
32
|
+
};
|
|
33
|
+
const operationIdFor = typeof idFor === 'function'
|
|
34
|
+
? ({ candidate, action }) => {
|
|
35
|
+
const key = `${action}:${operationId(candidate, action)}`;
|
|
36
|
+
if (!operationIds.has(`id:${key}`)) operationIds.set(`id:${key}`, idFor({ candidate, action }));
|
|
37
|
+
return operationIds.get(`id:${key}`);
|
|
38
|
+
}
|
|
39
|
+
: ({ candidate, action }) => operationId(candidate, action);
|
|
40
|
+
const operationKeyFor = typeof idempotencyKeyFor === 'function'
|
|
41
|
+
? ({ candidate, action }) => {
|
|
42
|
+
const key = `${action}:${operationId(candidate, action)}`;
|
|
43
|
+
if (!operationIds.has(`key:${key}`)) operationIds.set(`key:${key}`, idempotencyKeyFor({ candidate, action }));
|
|
44
|
+
return operationIds.get(`key:${key}`);
|
|
45
|
+
}
|
|
46
|
+
: ({ candidate, action }) => `meeting-minutes-lineage:${operationId(candidate, action)}`;
|
|
47
|
+
const prefix = String(basePath).replace(/\/+$/u, '');
|
|
48
|
+
const requestJson = async (path, body) => {
|
|
49
|
+
const headers = { 'Content-Type': 'application/json', Accept: 'application/json' };
|
|
50
|
+
if (token) headers['X-Brainbase-Review-Token'] = token;
|
|
51
|
+
const response = await fetcher(`${prefix}${path}`, {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers,
|
|
54
|
+
body: JSON.stringify(body),
|
|
55
|
+
});
|
|
56
|
+
// The local shell's request helper returns parsed JSON, while a direct
|
|
57
|
+
// fetcher returns a Response. Support both so the extension remains a
|
|
58
|
+
// usable host action slot outside the default shell.
|
|
59
|
+
if (!response || typeof response.json !== 'function') {
|
|
60
|
+
if (response?.ok === false) {
|
|
61
|
+
const failure = new Error(`Lineage request failed (${response.status ?? 'unknown'})`);
|
|
62
|
+
failure.code = 'lineage_unavailable';
|
|
63
|
+
failure.status = response.status;
|
|
64
|
+
throw failure;
|
|
65
|
+
}
|
|
66
|
+
return response;
|
|
67
|
+
}
|
|
68
|
+
let payload = null;
|
|
69
|
+
try {
|
|
70
|
+
payload = await response.json();
|
|
71
|
+
} catch {
|
|
72
|
+
payload = null;
|
|
73
|
+
}
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
const error = payload?.error;
|
|
76
|
+
const failure = new Error(typeof error?.message === 'string' ? error.message : `Lineage request failed (${response.status})`);
|
|
77
|
+
failure.code = typeof error?.code === 'string' ? error.code : 'lineage_unavailable';
|
|
78
|
+
failure.status = response.status;
|
|
79
|
+
throw failure;
|
|
80
|
+
}
|
|
81
|
+
return payload;
|
|
82
|
+
};
|
|
83
|
+
const requestMutation = (candidate, action, path, extra = {}) => requestJson(path, {
|
|
84
|
+
id: operationIdFor({ candidate, action }),
|
|
85
|
+
idempotencyKey: operationKeyFor({ candidate, action }),
|
|
86
|
+
// This is retained as an audit hint only. The host resolves the actor
|
|
87
|
+
// from its verified context and ignores this field for authority.
|
|
88
|
+
actor: auditActorFor({ candidate, action }),
|
|
89
|
+
...extra,
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
load: () => requestJson('/by-version', { reference }),
|
|
93
|
+
actions: {
|
|
94
|
+
createCandidate: (input) => {
|
|
95
|
+
if (!input || (input.kind !== 'judgment' && input.kind !== 'task')) {
|
|
96
|
+
return Promise.reject(Object.assign(new Error('候補の種類を選んでください。'), { code: 'invalid_input' }));
|
|
97
|
+
}
|
|
98
|
+
const candidate = { ...input, draftId: input.draftId ?? operationId(input, 'create') };
|
|
99
|
+
return requestMutation(candidate, 'create', '/candidates', {
|
|
100
|
+
evidence: reference,
|
|
101
|
+
kind: candidate.kind,
|
|
102
|
+
proposal: candidate.proposal,
|
|
103
|
+
epistemicStatus: candidate.epistemicStatus ?? 'inferred',
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
confirmCandidate: (candidate) => requestMutation(candidate, 'confirm', `/candidates/${encodeURIComponent(candidate.id)}/confirm`, {
|
|
107
|
+
evidenceDigest: candidate.evidenceDigest,
|
|
108
|
+
}),
|
|
109
|
+
adoptJudgment: (candidate) => requestMutation(candidate, 'adopt_judgment', `/candidates/${encodeURIComponent(candidate.id)}/adopt/judgment`),
|
|
110
|
+
adoptTask: (candidate) => requestMutation(candidate, 'adopt_task', `/candidates/${encodeURIComponent(candidate.id)}/adopt/task`),
|
|
111
|
+
// Corrections are intentionally host-owned because they require an
|
|
112
|
+
// explicit replacement version and a human supplied reason.
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Connect a host-owned shared UI action slot to the real HTTP loader/actions.
|
|
119
|
+
* The slot must mount the returned view; an absent slot is a wiring error,
|
|
120
|
+
* never a successful no-op.
|
|
121
|
+
*/
|
|
122
|
+
export function connectMeetingMinutesLineageActionSlot({
|
|
123
|
+
slot,
|
|
124
|
+
root,
|
|
125
|
+
reference,
|
|
126
|
+
basePath,
|
|
127
|
+
fetcher,
|
|
128
|
+
token,
|
|
129
|
+
actorFor,
|
|
130
|
+
idFor,
|
|
131
|
+
idempotencyKeyFor,
|
|
132
|
+
candidateDefaults,
|
|
133
|
+
documentRef = globalThis.document,
|
|
134
|
+
} = {}) {
|
|
135
|
+
if (!slot || typeof slot.mount !== 'function') throw new TypeError('a host action slot with mount(view) is required');
|
|
136
|
+
const transport = createMeetingMinutesLineageHttpActions({
|
|
137
|
+
reference,
|
|
138
|
+
basePath,
|
|
139
|
+
fetcher,
|
|
140
|
+
token,
|
|
141
|
+
actorFor,
|
|
142
|
+
idFor,
|
|
143
|
+
idempotencyKeyFor,
|
|
144
|
+
});
|
|
145
|
+
const view = createMeetingMinutesLineageView({
|
|
146
|
+
root,
|
|
147
|
+
load: transport.load,
|
|
148
|
+
actions: transport.actions,
|
|
149
|
+
candidateDefaults,
|
|
150
|
+
documentRef,
|
|
151
|
+
});
|
|
152
|
+
slot.mount(view);
|
|
153
|
+
return view;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function text(value) {
|
|
157
|
+
return typeof value === 'string' && value.trim() ? value.trim() : null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function exactVersionReference(version, detail, documentRecord) {
|
|
161
|
+
if (!version || !detail?.meeting?.meeting_id || !documentRecord?.minutes_id || !version.version_id) return null;
|
|
162
|
+
const source = version.source_ref;
|
|
163
|
+
if (source && text(source.provider) && text(source.locator) && text(source.revision) && text(source.digest)) {
|
|
164
|
+
return {
|
|
165
|
+
meetingId: detail.meeting.meeting_id,
|
|
166
|
+
minutesId: documentRecord.minutes_id,
|
|
167
|
+
versionId: version.version_id,
|
|
168
|
+
contentDigest: source.digest,
|
|
169
|
+
locator: source.locator,
|
|
170
|
+
provenance: {
|
|
171
|
+
providerKind: source.provider,
|
|
172
|
+
providerId: source.locator,
|
|
173
|
+
revision: source.revision,
|
|
174
|
+
digest: source.digest,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
meetingId: detail.meeting.meeting_id,
|
|
180
|
+
minutesId: documentRecord.minutes_id,
|
|
181
|
+
versionId: version.version_id,
|
|
182
|
+
contentDigest: text(version.body_digest),
|
|
183
|
+
locator: `${detail.meeting.meeting_id}/${documentRecord.minutes_id}/${version.version_id}`,
|
|
184
|
+
provenance: {
|
|
185
|
+
providerKind: 'brainbase.native',
|
|
186
|
+
providerId: `${detail.meeting.meeting_id}/${documentRecord.minutes_id}`,
|
|
187
|
+
revision: version.version_id,
|
|
188
|
+
...(text(version.body_digest) ? { digest: text(version.body_digest) } : {}),
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Add the real lineage transport/view to the same selected-version action slot. */
|
|
194
|
+
export function createMeetingMinutesLineageExtension({
|
|
195
|
+
basePath = '/api/meeting-minutes-lineage',
|
|
196
|
+
fetcher,
|
|
197
|
+
token,
|
|
198
|
+
actorFor,
|
|
199
|
+
idFor,
|
|
200
|
+
idempotencyKeyFor,
|
|
201
|
+
candidateDefaults = null,
|
|
202
|
+
} = {}) {
|
|
203
|
+
return Object.freeze({
|
|
204
|
+
id: 'meeting-minutes-lineage',
|
|
205
|
+
mount({ root, document: documentRef, detail, documentRecord, version, request, setStatus }) {
|
|
206
|
+
const reference = exactVersionReference(version, detail, documentRecord);
|
|
207
|
+
if (!reference) {
|
|
208
|
+
root.replaceChildren();
|
|
209
|
+
const notice = documentRef.createElement('p');
|
|
210
|
+
notice.className = 'bb-mml-notice';
|
|
211
|
+
notice.textContent = '選択した議事録版の根拠を確認できないため、判断・Taskを操作できません。';
|
|
212
|
+
root.appendChild(notice);
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
let view;
|
|
216
|
+
const slot = { mount(next) { view = next; } };
|
|
217
|
+
connectMeetingMinutesLineageActionSlot({
|
|
218
|
+
slot,
|
|
219
|
+
root,
|
|
220
|
+
reference,
|
|
221
|
+
basePath,
|
|
222
|
+
fetcher: fetcher ?? request,
|
|
223
|
+
token,
|
|
224
|
+
actorFor,
|
|
225
|
+
idFor,
|
|
226
|
+
idempotencyKeyFor,
|
|
227
|
+
documentRef,
|
|
228
|
+
candidateDefaults,
|
|
229
|
+
});
|
|
230
|
+
// `connect...` owns the view, while this extension owns the initial
|
|
231
|
+
// refresh and shares the core's status line for transport failures.
|
|
232
|
+
if (view) {
|
|
233
|
+
const originalRefresh = view.refresh;
|
|
234
|
+
view.refresh = async (...args) => {
|
|
235
|
+
try {
|
|
236
|
+
return await originalRefresh(...args);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
setStatus?.(error instanceof Error ? error.message : '判断履歴を読み取れません。', 'error');
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
void view.refresh();
|
|
243
|
+
}
|
|
244
|
+
return view;
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
}
|