@unson/brainbase-mcp 0.6.0 → 0.8.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.
Files changed (148) hide show
  1. package/contracts/foundation/graph-history.sql +634 -0
  2. package/contracts/judgment-value-proof/schema.json +43 -1
  3. package/dist/canonical-task-contract.d.ts +9 -0
  4. package/dist/canonical-task-contract.js +39 -0
  5. package/dist/canonical-task-principal.d.ts +16 -0
  6. package/dist/canonical-task-principal.js +36 -0
  7. package/dist/canonical-task-service.d.ts +251 -0
  8. package/dist/canonical-task-service.js +820 -0
  9. package/dist/cli.d.ts +2 -0
  10. package/dist/cli.js +107 -0
  11. package/dist/company-os-evaluation.d.ts +193 -0
  12. package/dist/company-os-evaluation.js +1150 -0
  13. package/dist/company-os-impact-review.d.ts +248 -0
  14. package/dist/company-os-impact-review.js +663 -0
  15. package/dist/company-os-learning-adoption.d.ts +288 -0
  16. package/dist/company-os-learning-adoption.js +944 -0
  17. package/dist/company-os-objectives.d.ts +63 -0
  18. package/dist/company-os-objectives.js +234 -0
  19. package/dist/company-os-receipt-adapter.d.ts +109 -0
  20. package/dist/company-os-receipt-adapter.js +636 -0
  21. package/dist/constraint-exception-store.d.ts +23 -0
  22. package/dist/constraint-exception-store.js +108 -0
  23. package/dist/constraint-resolution.d.ts +175 -0
  24. package/dist/constraint-resolution.js +922 -0
  25. package/dist/decision-adapter.d.ts +145 -0
  26. package/dist/decision-adapter.js +586 -0
  27. package/dist/durable-wait-http.d.ts +51 -0
  28. package/dist/durable-wait-http.js +497 -0
  29. package/dist/durable-waits.d.ts +234 -0
  30. package/dist/durable-waits.js +944 -0
  31. package/dist/execution-authority-http.d.ts +28 -0
  32. package/dist/execution-authority-http.js +359 -0
  33. package/dist/execution-authority.d.ts +201 -0
  34. package/dist/execution-authority.js +634 -0
  35. package/dist/foundation-authenticated-tools.d.ts +56 -0
  36. package/dist/foundation-authenticated-tools.js +347 -0
  37. package/dist/foundation-catalog.d.ts +26 -0
  38. package/dist/foundation-catalog.js +206 -0
  39. package/dist/foundation-constraint-store.d.ts +50 -0
  40. package/dist/foundation-constraint-store.js +215 -0
  41. package/dist/foundation-graph-http.d.ts +43 -0
  42. package/dist/foundation-graph-http.js +243 -0
  43. package/dist/foundation-graph-write.d.ts +90 -0
  44. package/dist/foundation-graph-write.js +447 -0
  45. package/dist/foundation-http.d.ts +90 -0
  46. package/dist/foundation-http.js +439 -0
  47. package/dist/foundation-public-provider.d.ts +140 -0
  48. package/dist/foundation-public-provider.js +192 -0
  49. package/dist/foundation-store.d.ts +132 -0
  50. package/dist/foundation-store.js +654 -0
  51. package/dist/graph-corrections.d.ts +157 -0
  52. package/dist/graph-corrections.js +620 -0
  53. package/dist/graph-foundation-reader.d.ts +60 -0
  54. package/dist/graph-foundation-reader.js +494 -0
  55. package/dist/graph-retrieval.d.ts +6 -1
  56. package/dist/graph-revision-reader.d.ts +80 -0
  57. package/dist/graph-revision-reader.js +246 -0
  58. package/dist/graph-web-http.d.ts +26 -0
  59. package/dist/graph-web-http.js +215 -0
  60. package/dist/graph-web.d.ts +364 -0
  61. package/dist/graph-web.js +639 -0
  62. package/dist/judgment-dag-composition.d.ts +224 -0
  63. package/dist/judgment-dag-composition.js +731 -0
  64. package/dist/judgment-dag.d.ts +2 -0
  65. package/dist/judgment-dag.js +1 -0
  66. package/dist/judgment-problem-snapshot.d.ts +213 -0
  67. package/dist/judgment-problem-snapshot.js +1073 -0
  68. package/dist/judgment-value-proof-review.d.ts +166 -0
  69. package/dist/judgment-value-proof-review.js +437 -0
  70. package/dist/judgment-value-proof.d.ts +28 -1
  71. package/dist/judgment-value-proof.js +53 -8
  72. package/dist/judgment-view-http.d.ts +22 -0
  73. package/dist/judgment-view-http.js +128 -0
  74. package/dist/judgment-view.d.ts +222 -0
  75. package/dist/judgment-view.js +627 -0
  76. package/dist/knowledge-adapter.d.ts +112 -0
  77. package/dist/knowledge-adapter.js +691 -0
  78. package/dist/knowledge-continuation.d.ts +127 -0
  79. package/dist/knowledge-continuation.js +446 -0
  80. package/dist/knowledge-lookup.d.ts +178 -0
  81. package/dist/knowledge-lookup.js +758 -0
  82. package/dist/local-web-fetch-bridge.d.ts +5 -0
  83. package/dist/local-web-fetch-bridge.js +37 -0
  84. package/dist/local-web-host.d.ts +109 -0
  85. package/dist/local-web-host.js +688 -0
  86. package/dist/local-web-security.d.ts +25 -0
  87. package/dist/local-web-security.js +95 -0
  88. package/dist/ontology-foundation.d.ts +209 -0
  89. package/dist/ontology-foundation.js +1000 -0
  90. package/dist/ontology.d.ts +13 -0
  91. package/dist/ontology.js +14 -0
  92. package/dist/organization-connection.d.ts +164 -0
  93. package/dist/organization-connection.js +428 -0
  94. package/dist/organization-graph.d.ts +15 -0
  95. package/dist/organization-graph.js +24 -4
  96. package/dist/personal-knowledge.d.ts +132 -0
  97. package/dist/personal-knowledge.js +779 -0
  98. package/dist/personal-memory-handover.d.ts +108 -0
  99. package/dist/personal-memory-handover.js +369 -0
  100. package/dist/philosophy-revision-reader.d.ts +85 -0
  101. package/dist/philosophy-revision-reader.js +241 -0
  102. package/dist/portable-graph.d.ts +24 -0
  103. package/dist/portable-graph.js +77 -0
  104. package/dist/problem-candidates.d.ts +149 -0
  105. package/dist/problem-candidates.js +898 -0
  106. package/dist/problem-selection.d.ts +238 -0
  107. package/dist/problem-selection.js +995 -0
  108. package/dist/resource-reservation-http.d.ts +31 -0
  109. package/dist/resource-reservation-http.js +371 -0
  110. package/dist/resource-reservations.d.ts +221 -0
  111. package/dist/resource-reservations.js +577 -0
  112. package/dist/server.d.ts +104 -2
  113. package/dist/server.js +186 -4
  114. package/dist/ssot.d.ts +6 -1
  115. package/dist/ssot.js +63 -5
  116. package/dist/streamable-http.d.ts +42 -0
  117. package/dist/streamable-http.js +288 -0
  118. package/dist/types.d.ts +20 -0
  119. package/dist/value-proof-review-http.d.ts +25 -0
  120. package/dist/value-proof-review-http.js +185 -0
  121. package/dist/world-model.d.ts +199 -0
  122. package/dist/world-model.js +955 -0
  123. package/package.json +230 -3
  124. package/ui/brainbase-tokens.css +56 -0
  125. package/ui/graph-own-share.js +367 -0
  126. package/ui/graph-projects-view.css +23 -0
  127. package/ui/graph-projects-view.js +730 -0
  128. package/ui/graph-registry-view.css +101 -0
  129. package/ui/graph-registry-view.js +804 -0
  130. package/ui/graph-view-shared.css +522 -0
  131. package/ui/graph-view-shared.js +1227 -0
  132. package/ui/judgment-view.css +312 -0
  133. package/ui/judgment-view.js +508 -0
  134. package/ui/local-web-shell.css +396 -0
  135. package/ui/local-web-shell.js +378 -0
  136. package/ui/objective-editor-http-port.js +154 -0
  137. package/ui/objective-editor.css +286 -0
  138. package/ui/objective-editor.js +1586 -0
  139. package/ui/outcome-knowledge.css +50 -14
  140. package/ui/outcome-knowledge.js +15 -1
  141. package/ui/outcome-mana.css +91 -14
  142. package/ui/outcome-mana.js +958 -61
  143. package/ui/value-proof-review.css +504 -0
  144. package/ui/value-proof-review.js +1104 -0
  145. package/ui/workspace-kit.css +485 -0
  146. package/ui/workspace-kit.js +229 -0
  147. package/ui/world-model-view.css +188 -0
  148. package/ui/world-model-view.js +486 -0
@@ -0,0 +1,367 @@
1
+ /*
2
+ * 「引き継いだ自分の分」: the owner's own Graph snapshot that a host keeps for
3
+ * them (an OSS Personal OS sent with `brainbase graph:upgrade`), shown next to
4
+ * the host's own Graph and never mixed into it.
5
+ *
6
+ * A host that has such a snapshot passes `ownShare: { basePath }` to
7
+ * 「プロジェクトと関係者」 and 「情報と関係」, and mounts
8
+ * `createOwnObjectivesView` for the objectives. The section is read-only,
9
+ * has its own label, and reads its own routes with a second client:
10
+ *
11
+ * - `GET {basePath}/projects`, `/projects/:id`, `/search`, `/entities/:id` and
12
+ * `/objectives` answer the local Graph route shapes (`openOwnerPrivateGraph`
13
+ * in `graph-web`), with `source.authority: 'owner_private'` and
14
+ * `handover: { graphId, projectCode, digest, createdAt }` for the snapshot.
15
+ * - `{ status: 'not_handed_over' }` when the owner has sent nothing: the
16
+ * section says so and shows the commands that send it.
17
+ * - A failed read is shown in this section only. The host's own Graph keeps
18
+ * working, and a failure there does not hide this section.
19
+ *
20
+ * Without `ownShare` nothing here is drawn or read (the local host).
21
+ */
22
+
23
+ import {
24
+ activityBadge,
25
+ badge,
26
+ button,
27
+ createGraphClient,
28
+ formatDateTime,
29
+ formatDay,
30
+ graphCommandList,
31
+ graphStateNotice,
32
+ isRecord,
33
+ makeElement,
34
+ ownLabel,
35
+ readOnlyGraphClient,
36
+ recordDetails,
37
+ relationLabel,
38
+ textOrNull,
39
+ typeLabel,
40
+ validityText,
41
+ GRAPH_RELATION_LABELS,
42
+ } from './graph-view-shared.js';
43
+ import {
44
+ workspaceDefinition,
45
+ workspaceLedger,
46
+ workspaceNotice,
47
+ workspaceRailBlock,
48
+ workspaceRailHead,
49
+ workspaceSectionTitle,
50
+ } from './workspace-kit.js';
51
+
52
+ export const GRAPH_OWN_SHARE_CONTRACT_VERSION = 'brainbase.graph-own-share.v1';
53
+ export const GRAPH_OWN_SHARE_LABEL = '引き継いだ自分の分(組織には未反映)';
54
+ export const GRAPH_OWN_OBJECTIVES_LABEL = '引き継いだ自分の目的';
55
+ /** Sends the local Graph (`graph:upgrade`) and lists what was sent (`graph:bundles`). */
56
+ export const GRAPH_OWN_SHARE_COMMANDS = Object.freeze(['brainbase graph:upgrade', 'brainbase graph:bundles']);
57
+ export const GRAPH_OWN_OBJECTIVE_LEDGER_COLUMNS = Object.freeze(['目的', '状態', '評価期間', '責任を持つ人', '基準']);
58
+
59
+ const OWN_LEAD = '手元のOSSから送った最新の束です。組織の記録ではなく、あなたにだけ表示しています。読み取りのみで、ここでは直せません。';
60
+ const OBJECTIVES_LEAD = '手元のOSSから送った最新の束にある目的の定義です。組織の目的ではなく、あなたにだけ表示しています。読み取りのみで、組織の目的には反映しません。';
61
+ const PARTICIPATION = Object.freeze({ participates_in: '参加', accountable_for: '責任' });
62
+ const ADOPTION_LABELS = Object.freeze({ draft: '下書き', proposed: '提案中', approved: '承認済み', retired: '終了' });
63
+ const VISIBILITY_LABELS = Object.freeze({ private: '本人だけ', project: 'プロジェクト', organization: '組織', public: '公開' });
64
+ const INVALID = Object.freeze({ state: 'invalid', reason: '応答の形式が不正です' });
65
+
66
+ /**
67
+ * The host's owner-private source, or null without one: a read-only client
68
+ * for `basePath` (with the part's fetcher unless the option has its own) and
69
+ * the section label.
70
+ */
71
+ export function graphOwnShareSource(option, { fetcher } = {}) {
72
+ if (!isRecord(option) || !textOrNull(option.basePath)) return null;
73
+ return Object.freeze({
74
+ client: readOnlyGraphClient(createGraphClient({ fetcher: option.fetcher ?? fetcher, basePath: option.basePath })),
75
+ label: textOrNull(option.label) ?? GRAPH_OWN_SHARE_LABEL,
76
+ });
77
+ }
78
+
79
+ /** What the owner sent: the snapshot ID, where it is kept and when it was sent. */
80
+ export function ownShareHandoverText(handover) {
81
+ if (!isRecord(handover) || !textOrNull(handover.graphId)) return null;
82
+ const where = textOrNull(handover.projectCode);
83
+ return `束 ${handover.graphId}(${where ? `置き場所 ${where}、` : ''}${formatDateTime(handover.createdAt)} に送信)`;
84
+ }
85
+
86
+ /**
87
+ * A read state of the own section as a notice, or null when the payload should
88
+ * be drawn. Not handed over yet shows the commands that send it; a failure is
89
+ * never shown as zero items.
90
+ */
91
+ export function ownShareStateNotice(doc, readState, { onRetry, loadingText } = {}) {
92
+ if (readState?.state === 'not_handed_over') {
93
+ const body = makeElement(doc, 'div', { className: 'bb-graph-notice-body' });
94
+ body.append(
95
+ makeElement(doc, 'p', { text: 'まだ引き継いでいません。手元のOSSのGraphを次のコマンドで送ると、ここにあなたにだけ表示されます。送る前に、接続先の設定(BRAINBASE_ORGANIZATION_URL・_TOKEN・_PROJECT・_GRAPH_ID)が要ります。2つ目のコマンドで、送った束を確かめられます。' }),
96
+ graphCommandList(doc, GRAPH_OWN_SHARE_COMMANDS),
97
+ );
98
+ return workspaceNotice(doc, { label: 'まだ引き継いでいません', text: body, tone: 'info', role: 'status' });
99
+ }
100
+ return graphStateNotice(doc, readState, { onRetry, loadingText });
101
+ }
102
+
103
+ /** The section that holds everything of the owner's own share; never part of the host's ledgers. */
104
+ export function ownShareSection(doc, { label, lead = OWN_LEAD, handover, children = [], className = '' } = {}) {
105
+ const section = makeElement(doc, 'section', {
106
+ className: `bb-graph-own${className ? ` ${className}` : ''}`,
107
+ attrs: { 'aria-label': label, 'data-contract-version': GRAPH_OWN_SHARE_CONTRACT_VERSION, 'data-authority': 'owner_private' },
108
+ });
109
+ section.append(workspaceSectionTitle(doc, { title: label, lead }));
110
+ const facts = makeElement(doc, 'p', { className: 'bb-graph-own-facts' });
111
+ facts.append(badge(doc, '読み取りのみ', 'muted'));
112
+ const sent = ownShareHandoverText(handover);
113
+ if (sent) facts.append(makeElement(doc, 'span', { text: sent }));
114
+ section.append(facts);
115
+ for (const child of children) if (child) section.append(child);
116
+ return section;
117
+ }
118
+
119
+ function closeButton(doc, onClose) {
120
+ return typeof onClose === 'function' ? button(doc, '閉じる', () => onClose(), { className: 'bb-graph-link bb-graph-own-close' }) : null;
121
+ }
122
+
123
+ function relationItem(doc, edge, asOf, { onOpen, participation = false } = {}) {
124
+ const item = makeElement(doc, 'li', { className: `bb-graph-compact${edge.active ? '' : ' is-ended'}` });
125
+ const head = makeElement(doc, 'div', { className: 'bb-graph-compact-head' });
126
+ const name = typeof onOpen === 'function'
127
+ ? button(doc, edge.counterpart.name, () => onOpen(edge.counterpart.id), { className: 'bb-graph-link' })
128
+ : makeElement(doc, 'strong', { className: 'bb-graph-compact-title', text: edge.counterpart.name });
129
+ const labels = ownLabel(GRAPH_RELATION_LABELS, edge.relation);
130
+ const how = participation ? ownLabel(PARTICIPATION, edge.relation) : null;
131
+ head.append(
132
+ badge(doc, how ?? relationLabel(edge.relation), edge.relation === 'accountable_for' ? 'accent' : ''),
133
+ name,
134
+ makeElement(doc, 'span', { text: how ? '' : labels ? (edge.direction === 'outgoing' ? labels.outgoing : labels.incoming) : '' }),
135
+ activityBadge(doc, edge, asOf),
136
+ );
137
+ item.append(head, workspaceDefinition(doc, [
138
+ ['役割', textOrNull(edge.role)],
139
+ ...(textOrNull(edge.context) ? [['文脈', edge.context]] : []),
140
+ ['有効期間', validityText(edge.validFrom, edge.validTo)],
141
+ ]));
142
+ item.append(recordDetails(doc, [['関係ID', edge.id], ['相手のID', edge.counterpart.id], ['出典ID', edge.provenance?.sourceId ?? null]]));
143
+ return item;
144
+ }
145
+
146
+ function relationList(doc, edges, asOf, options) {
147
+ const list = makeElement(doc, 'ul', { className: 'bb-graph-compact-list' });
148
+ for (const edge of edges) list.append(relationItem(doc, edge, asOf, options));
149
+ return list;
150
+ }
151
+
152
+ /** A selected project of the own share, below its ledger (not in the host's rail). */
153
+ export function ownProjectDetail(doc, detail, { onClose, onRetry } = {}) {
154
+ const wrap = makeElement(doc, 'div', { className: 'bb-graph-own-detail', attrs: { 'aria-label': '選んだプロジェクト(引き継いだ自分の分)' } });
155
+ const project = detail?.state === 'ok' ? detail.payload.project : { name: detail?.id ?? '', id: detail?.id ?? '' };
156
+ wrap.append(workspaceRailHead(doc, { kicker: 'プロジェクト(引き継いだ自分の分)', title: project.name, sub: project.id }), closeButton(doc, onClose));
157
+ if (detail?.state !== 'ok') {
158
+ wrap.append(graphStateNotice(doc, detail ?? { state: 'loading' }, { onRetry, loadingText: 'このプロジェクトを読み込んでいます。' }));
159
+ return wrap;
160
+ }
161
+ const { payload } = detail;
162
+ const principles = Array.isArray(project.decisionPrinciples) ? project.decisionPrinciples.filter((item) => textOrNull(item)) : [];
163
+ wrap.append(workspaceRailBlock(doc, {
164
+ title: '概要',
165
+ content: workspaceDefinition(doc, [
166
+ ['状態', textOrNull(project.status)],
167
+ ['目的', textOrNull(project.goal)],
168
+ ['判断の原則', principles.length > 0 ? principles.join('、') : null],
169
+ ['有効期間', validityText(project.validFrom, project.validTo)],
170
+ ]),
171
+ }));
172
+ wrap.append(workspaceRailBlock(doc, {
173
+ title: '関係者',
174
+ content: payload.participants.length === 0
175
+ ? makeElement(doc, 'p', { className: 'bb-graph-empty', text: 'この束には、このプロジェクトの関係者の記録がありません。' })
176
+ : relationList(doc, payload.participants, payload.asOf, { participation: true }),
177
+ }));
178
+ const relations = Array.isArray(payload.relations) ? payload.relations : [];
179
+ if (relations.length > 0) wrap.append(workspaceRailBlock(doc, { title: 'そのほかの関係', content: relationList(doc, relations, payload.asOf) }));
180
+ return wrap;
181
+ }
182
+
183
+ function decisionRecordBlock(doc, entity, record) {
184
+ if (entity.type !== 'decision' || record === undefined) return null;
185
+ if (record === null) {
186
+ return workspaceRailBlock(doc, { title: '判断根拠', content: makeElement(doc, 'p', { className: 'bb-graph-empty', text: 'この束には、この判断の根拠の記録がありません。' }) });
187
+ }
188
+ return workspaceRailBlock(doc, {
189
+ title: '判断根拠',
190
+ content: workspaceDefinition(doc, [
191
+ ['判断', textOrNull(record.decision)],
192
+ ['理由', textOrNull(record.rationale)],
193
+ ['論点', textOrNull(record.topic)],
194
+ ['有効になった日', formatDay(record.effectiveAt)],
195
+ ...(Array.isArray(record.supersedes) && record.supersedes.length > 0 ? [['置き換えた判断', record.supersedes.join('、')]] : []),
196
+ ]),
197
+ });
198
+ }
199
+
200
+ /** A selected record of the own share, below its results (not in the host's rail). */
201
+ export function ownEntityDetail(doc, detail, { onClose, onRetry, onOpen } = {}) {
202
+ const wrap = makeElement(doc, 'div', { className: 'bb-graph-own-detail', attrs: { 'aria-label': '選んだ記録(引き継いだ自分の分)' } });
203
+ const loaded = detail?.state === 'ok' ? detail.payload : null;
204
+ const entity = loaded?.entity ?? detail?.pending ?? { id: detail?.id ?? '', name: detail?.id ?? '', type: null };
205
+ wrap.append(workspaceRailHead(doc, { kicker: `${entity.type ? typeLabel(entity.type) : '記録'}(引き継いだ自分の分)`, title: entity.name, sub: entity.id }), closeButton(doc, onClose));
206
+ if (!loaded) {
207
+ wrap.append(graphStateNotice(doc, detail ?? { state: 'loading' }, { onRetry, loadingText: 'この記録を読み込んでいます。' }));
208
+ return wrap;
209
+ }
210
+ wrap.append(workspaceRailBlock(doc, {
211
+ title: '概要',
212
+ content: workspaceDefinition(doc, [
213
+ ['別名', entity.aliases.length > 0 ? entity.aliases.join('、') : null],
214
+ ['要約', textOrNull(entity.summary)],
215
+ ['有効期間', validityText(entity.validFrom, entity.validTo)],
216
+ ...(entity.type === 'project' ? [['目的', textOrNull(entity.goal)], ['状態', textOrNull(entity.status)]] : []),
217
+ ]),
218
+ }));
219
+ wrap.append(decisionRecordBlock(doc, entity, loaded.decisionRecord));
220
+ for (const [key, title, empty] of [['outgoing', '出る関係', 'この記録から出る関係はありません。'], ['incoming', '入る関係', 'この記録へ入る関係はありません。']]) {
221
+ const edges = Array.isArray(loaded[key]) ? loaded[key] : [];
222
+ wrap.append(workspaceRailBlock(doc, {
223
+ title,
224
+ content: edges.length === 0 ? makeElement(doc, 'p', { className: 'bb-graph-empty', text: empty }) : relationList(doc, edges, loaded.asOf, { onOpen }),
225
+ }));
226
+ }
227
+ return wrap;
228
+ }
229
+
230
+ // ---------------------------------------------------------------------------
231
+ // 引き継いだ自分の目的
232
+
233
+ function isObjectiveView(value) {
234
+ return isRecord(value) && typeof value.id === 'string' && typeof value.meaning === 'string'
235
+ && Array.isArray(value.criteria) && Array.isArray(value.beneficiaries);
236
+ }
237
+
238
+ export function normalizeOwnObjectives(result) {
239
+ if (result?.state !== 'ok') return result ?? INVALID;
240
+ const payload = result.payload;
241
+ if (!Array.isArray(payload.objectives) || !payload.objectives.every(isObjectiveView)) return INVALID;
242
+ if (payload.objectives.length === 0 && payload.absenceConfirmed !== true) return { state: 'unknown' };
243
+ return { state: 'ok', payload };
244
+ }
245
+
246
+ function personText(person) {
247
+ return person ? textOrNull(person.name) ?? person.id : null;
248
+ }
249
+
250
+ function criterionText(criterion) {
251
+ const variable = textOrNull(criterion.variable?.meaning) ?? criterion.variable?.id ?? '変数';
252
+ if (criterion.target === null || criterion.target === undefined) return `${variable}(目標値なし)`;
253
+ const value = `${String(criterion.target)}${textOrNull(criterion.variable?.unit) ? ` ${criterion.variable.unit}` : ''}`;
254
+ if (criterion.operator === 'at_least') return `${variable}: ${value}以上`;
255
+ if (criterion.operator === 'at_most') return `${variable}: ${value}以下`;
256
+ return `${variable}: ${value}`;
257
+ }
258
+
259
+ function periodText(period) {
260
+ return `${formatDay(period?.from) ?? '開始日不明'} 〜 ${formatDay(period?.until) ?? '終了日不明'}`;
261
+ }
262
+
263
+ /**
264
+ * Mounts 「引き継いだ自分の目的」: the objectives of the owner's latest
265
+ * snapshot, read-only, from `GET {basePath}/objectives`.
266
+ *
267
+ * @param {object} options
268
+ * @param {Element} options.root Where the section is drawn.
269
+ * @param {Document} [options.document]
270
+ * @param {Function} [options.fetcher] `fetch`-compatible function.
271
+ * @param {string} [options.basePath='/api/graph/own'] The host's owner-private routes.
272
+ * @param {string} [options.label] The section label (default 引き継いだ自分の目的).
273
+ * @param {boolean} [options.autoLoad=true]
274
+ * @returns The controller: `state`, `render()`, `load()`, `select(id)`.
275
+ */
276
+ export function createOwnObjectivesView({
277
+ root,
278
+ document: explicitDocument,
279
+ fetcher,
280
+ basePath = '/api/graph/own',
281
+ label = GRAPH_OWN_OBJECTIVES_LABEL,
282
+ autoLoad = true,
283
+ } = {}) {
284
+ if (!root) throw new TypeError('root is required');
285
+ const doc = explicitDocument ?? globalThis.document;
286
+ const source = graphOwnShareSource({ basePath, label }, { fetcher });
287
+ const state = { list: { state: 'loading' }, selectedId: null };
288
+
289
+ function detail(objective) {
290
+ const wrap = makeElement(doc, 'div', { className: 'bb-graph-own-detail', attrs: { 'aria-label': '選んだ目的(引き継いだ自分の分)' } });
291
+ wrap.append(
292
+ workspaceRailHead(doc, { kicker: '目的(引き継いだ自分の分)', title: objective.meaning, sub: objective.id }),
293
+ closeButton(doc, () => controller.select(null)),
294
+ );
295
+ const criteria = makeElement(doc, 'ul', { className: 'bb-graph-plain-list' });
296
+ for (const criterion of objective.criteria) criteria.append(makeElement(doc, 'li', { text: criterionText(criterion) }));
297
+ wrap.append(workspaceRailBlock(doc, {
298
+ title: '概要',
299
+ content: [
300
+ workspaceDefinition(doc, [
301
+ ['目指す状態', textOrNull(objective.desiredState)],
302
+ ['評価基準', objective.criteria.length > 0 ? criteria : null],
303
+ ['評価期間', periodText(objective.evaluationPeriod)],
304
+ ['責任を持つ人', personText(objective.accountable)],
305
+ ['受益者', objective.beneficiaries.length > 0 ? objective.beneficiaries.map(personText).join('、') : null],
306
+ ['状態', ownLabel(ADOPTION_LABELS, objective.adoptionState) ?? textOrNull(objective.adoptionState)],
307
+ ['公開範囲(手元での設定)', ownLabel(VISIBILITY_LABELS, objective.visibility) ?? textOrNull(objective.visibility)],
308
+ ]),
309
+ recordDetails(doc, [['目的ID', objective.id], ['版', objective.revision]]),
310
+ ],
311
+ }));
312
+ return wrap;
313
+ }
314
+
315
+ function body() {
316
+ const notice = ownShareStateNotice(doc, state.list, { onRetry: () => controller.load(), loadingText: '引き継いだ自分の目的を読み込んでいます。' });
317
+ if (notice) return [notice];
318
+ const { payload } = state.list;
319
+ if (payload.objectives.length === 0) {
320
+ return [makeElement(doc, 'p', { className: 'bb-graph-empty', text: payload.foundation === 'none' ? 'この束には、目的の定義がありません。' : 'この束には、目的がありません。' })];
321
+ }
322
+ const children = [workspaceLedger(doc, {
323
+ className: 'bb-graph-own-ledger bb-graph-own-objective-ledger',
324
+ ariaLabel: `${label}の一覧`,
325
+ columns: GRAPH_OWN_OBJECTIVE_LEDGER_COLUMNS,
326
+ rows: payload.objectives.map((objective) => ({
327
+ key: objective.id,
328
+ selected: objective.id === state.selectedId,
329
+ onSelect: (id) => controller.select(id),
330
+ cells: [
331
+ { primary: objective.meaning, secondary: objective.id },
332
+ ownLabel(ADOPTION_LABELS, objective.adoptionState) ?? String(objective.adoptionState ?? ''),
333
+ periodText(objective.evaluationPeriod),
334
+ personText(objective.accountable) ?? { text: '未登録', className: 'is-unresolved' },
335
+ objective.criteria.length > 0 ? `${objective.criteria.length}件` : { text: 'なし', className: 'is-unresolved' },
336
+ ],
337
+ })),
338
+ })];
339
+ const selected = payload.objectives.find((objective) => objective.id === state.selectedId);
340
+ if (selected) children.push(detail(selected));
341
+ return children;
342
+ }
343
+
344
+ const controller = {
345
+ get state() { return state; },
346
+ render() {
347
+ const handover = state.list.state === 'ok' ? state.list.payload.handover : null;
348
+ root.replaceChildren(ownShareSection(doc, { label: source.label, lead: OBJECTIVES_LEAD, handover, children: body(), className: 'bb-graph-own-objectives' }));
349
+ return controller;
350
+ },
351
+ async load() {
352
+ state.list = { state: 'loading' };
353
+ controller.render();
354
+ state.list = normalizeOwnObjectives(await source.client.read('/objectives'));
355
+ if (state.list.state !== 'ok' || !state.list.payload.objectives.some((objective) => objective.id === state.selectedId)) state.selectedId = null;
356
+ controller.render();
357
+ return state.list;
358
+ },
359
+ select(id) {
360
+ state.selectedId = textOrNull(id);
361
+ return controller.render();
362
+ },
363
+ };
364
+ controller.render();
365
+ if (autoLoad) void controller.load();
366
+ return controller;
367
+ }
@@ -0,0 +1,23 @@
1
+ /*
2
+ * 「プロジェクトと関係者」. Load after workspace-kit.css and graph-view-shared.css.
3
+ * The project ledger's columns follow the organization edition's project
4
+ * ledger; at 760px and below it keeps プロジェクト・目的・状態. Flexible
5
+ * columns have no fixed minimum, so a narrow workspace truncates a cell
6
+ * instead of scrolling the page sideways.
7
+ * Uses only the shared tokens in brainbase-tokens.css.
8
+ */
9
+ .bb-graph-project-ledger .bb-ws-ledger-row {
10
+ grid-template-columns: minmax(0, 1.3fr) minmax(0, 1.2fr) minmax(0, .8fr) minmax(0, .6fr) 64px minmax(0, 1.2fr);
11
+ }
12
+
13
+ @media (max-width: 760px) {
14
+ .bb-graph-project-ledger .bb-ws-ledger-row {
15
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr) 68px;
16
+ }
17
+
18
+ .bb-graph-project-ledger .bb-ws-ledger-row > :nth-child(3),
19
+ .bb-graph-project-ledger .bb-ws-ledger-row > :nth-child(5),
20
+ .bb-graph-project-ledger .bb-ws-ledger-row > :nth-child(6) {
21
+ display: none;
22
+ }
23
+ }