@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,439 @@
1
+ import { FoundationStoreError } from './foundation-store.js';
2
+ /**
3
+ * HTTP boundary shared by the OSS Objective UI and organization adapters.
4
+ *
5
+ * This module intentionally exposes a Fetch-style route handler instead of
6
+ * opening a listener. A local host can mount it beside Reservation,
7
+ * Decision, or another Company OS route on one server. Authentication,
8
+ * tenant scope, and CSRF are supplied by that host; none of them are read
9
+ * from a JSON request body.
10
+ */
11
+ export const FOUNDATION_HTTP_CONTRACT_VERSION = 'brainbase.foundation-http.v1';
12
+ export const FOUNDATION_HTTP_PREFIX = '/api/foundation';
13
+ export const FOUNDATION_OBJECTIVE_ROUTE_PREFIX = `${FOUNDATION_HTTP_PREFIX}/objectives`;
14
+ export const FOUNDATION_OBJECTIVE_ROUTES = Object.freeze([
15
+ 'GET /api/foundation/objectives',
16
+ 'GET /api/foundation/objectives/:id',
17
+ 'GET /api/foundation/objectives/:id/readiness',
18
+ 'GET /api/foundation/objectives/:id/constraints',
19
+ 'PUT /api/foundation/objectives/:id/constraints',
20
+ 'POST /api/foundation/objectives',
21
+ 'PUT /api/foundation/objectives/:id',
22
+ 'GET /api/foundation/stories/:id/objectives',
23
+ ]);
24
+ const DEFAULT_BODY_LIMIT_BYTES = 1024 * 1024;
25
+ const MUTATING_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
26
+ const AUTHORITY_FIELDS = new Set([
27
+ 'acl',
28
+ 'scope',
29
+ 'storage',
30
+ 'provenance',
31
+ 'authorizedUses',
32
+ 'authorized_uses',
33
+ 'ownerId',
34
+ 'owner_id',
35
+ 'userId',
36
+ 'user_id',
37
+ 'memberId',
38
+ 'member_id',
39
+ 'readerIds',
40
+ 'reader_ids',
41
+ 'writerIds',
42
+ 'writer_ids',
43
+ 'tenant',
44
+ 'subjectIds',
45
+ 'subject_ids',
46
+ 'tenantId',
47
+ 'tenant_id',
48
+ 'organization',
49
+ 'organization_id',
50
+ 'organizationId',
51
+ 'org',
52
+ 'orgId',
53
+ 'org_id',
54
+ 'workspace',
55
+ 'workspaceId',
56
+ 'workspace_id',
57
+ 'principal',
58
+ 'actor',
59
+ 'actorId',
60
+ 'actor_id',
61
+ 'role',
62
+ 'roles',
63
+ 'raci',
64
+ 'authorization',
65
+ 'permission',
66
+ 'permissions',
67
+ ]);
68
+ class FoundationHttpError extends Error {
69
+ status;
70
+ code;
71
+ currentRevision;
72
+ constructor(status, code, message, options = {}) {
73
+ super(message);
74
+ this.name = 'FoundationHttpError';
75
+ this.status = status;
76
+ this.code = code;
77
+ this.currentRevision = options.currentRevision;
78
+ }
79
+ }
80
+ /**
81
+ * Compose OSS Company OS routes under one local server boundary. The
82
+ * resolver is called only for a matching route and the resulting trusted
83
+ * context is passed to that route. Unknown routes remain an ordinary 404 so
84
+ * the host can mount this handler beside other app routes.
85
+ */
86
+ export function createFoundationHttpRouter(options) {
87
+ if (!options || typeof options.resolveContext !== 'function') {
88
+ throw new TypeError('resolveContext is required');
89
+ }
90
+ if (!Array.isArray(options.routes) || options.routes.length === 0) {
91
+ throw new TypeError('at least one Foundation HTTP route is required');
92
+ }
93
+ const bodyLimitBytes = options.bodyLimitBytes ?? DEFAULT_BODY_LIMIT_BYTES;
94
+ if (!Number.isInteger(bodyLimitBytes) || bodyLimitBytes <= 0) {
95
+ throw new TypeError('bodyLimitBytes must be a positive integer');
96
+ }
97
+ const routes = Object.freeze([...options.routes]);
98
+ return {
99
+ contractVersion: FOUNDATION_HTTP_CONTRACT_VERSION,
100
+ routes,
101
+ async handle(request) {
102
+ const route = routes.find((candidate) => candidate.matches(request));
103
+ if (!route)
104
+ return jsonResponse(404, { error: { code: 'not_found', message: 'Route not found' } });
105
+ let context;
106
+ try {
107
+ context = await options.resolveContext(request);
108
+ }
109
+ catch {
110
+ context = null;
111
+ }
112
+ if (!context)
113
+ return jsonResponse(401, { error: { code: 'authorization_required', message: 'A trusted context is required' } });
114
+ if (MUTATING_METHODS.has((request.method || 'GET').toUpperCase())) {
115
+ if (!options.csrf) {
116
+ return jsonResponse(501, { error: { code: 'csrf_unconfigured', message: 'A CSRF verifier is required for mutations' } });
117
+ }
118
+ try {
119
+ const verified = await options.csrf.verify(request, context);
120
+ if (verified === false) {
121
+ return jsonResponse(403, { error: { code: 'csrf_failed', message: 'CSRF verification failed' } });
122
+ }
123
+ }
124
+ catch {
125
+ return jsonResponse(403, { error: { code: 'csrf_failed', message: 'CSRF verification failed' } });
126
+ }
127
+ }
128
+ try {
129
+ return await route.handle(request, { context, request });
130
+ }
131
+ catch (error) {
132
+ return errorResponse(error);
133
+ }
134
+ },
135
+ };
136
+ }
137
+ /** Convenience constructor for a local/organization host with Objective routes only. */
138
+ export function createObjectiveFoundationHttpHandler(options) {
139
+ return createFoundationHttpRouter({
140
+ ...options,
141
+ bodyLimitBytes: options.bodyLimitBytes,
142
+ routes: [createObjectiveFoundationRoute(options)],
143
+ });
144
+ }
145
+ export function createObjectiveFoundationRoute(options) {
146
+ if (!options?.objectives)
147
+ throw new TypeError('objectives service is required');
148
+ const bodyLimitBytes = options.bodyLimitBytes ?? DEFAULT_BODY_LIMIT_BYTES;
149
+ if (!Number.isInteger(bodyLimitBytes) || bodyLimitBytes <= 0)
150
+ throw new TypeError('bodyLimitBytes must be a positive integer');
151
+ const route = {
152
+ name: 'foundation-objectives',
153
+ methods: FOUNDATION_OBJECTIVE_ROUTES.map((value) => value.split(' ', 1)[0]),
154
+ paths: FOUNDATION_OBJECTIVE_ROUTES,
155
+ matches(request) {
156
+ const path = requestUrl(request).pathname;
157
+ return path === FOUNDATION_OBJECTIVE_ROUTE_PREFIX
158
+ || path.startsWith(`${FOUNDATION_OBJECTIVE_ROUTE_PREFIX}/`)
159
+ || /^\/api\/foundation\/stories\/[^/]+\/objectives$/.test(path);
160
+ },
161
+ async handle(request, input) {
162
+ const url = requestUrl(request);
163
+ const path = url.pathname;
164
+ const method = (request.method || 'GET').toUpperCase();
165
+ if (path === FOUNDATION_OBJECTIVE_ROUTE_PREFIX) {
166
+ if (method === 'GET') {
167
+ const list = options.objectives.list;
168
+ if (!list)
169
+ throw new FoundationHttpError(501, 'api_unavailable', 'Objective list API is not configured');
170
+ const records = await list.call(options.objectives, 'objective', input.context);
171
+ return jsonResponse(200, { state: records.length ? 'ready' : 'empty', records, absence_confirmed: true });
172
+ }
173
+ if (method === 'POST') {
174
+ const body = await readJsonBody(request, bodyLimitBytes);
175
+ const definition = await buildObjectiveDefinition(options, body, {
176
+ operation: 'create',
177
+ context: input.context,
178
+ });
179
+ const reference = await options.objectives.createObjective(definition, input.context);
180
+ return jsonResponse(201, { state: 'saved_unverified', reference, ref: reference });
181
+ }
182
+ return methodNotAllowed(['GET', 'POST']);
183
+ }
184
+ const storyMatch = path.match(/^\/api\/foundation\/stories\/([^/]+)\/objectives$/);
185
+ if (storyMatch) {
186
+ if (method !== 'GET')
187
+ return methodNotAllowed(['GET']);
188
+ if (!options.listStoryObjectiveLinks)
189
+ throw new FoundationHttpError(501, 'api_unavailable', 'Story relation API is not configured');
190
+ const storyId = decodePathPart(storyMatch[1]);
191
+ const links = await options.listStoryObjectiveLinks(storyId, input.context);
192
+ return jsonResponse(200, normalizeCollectionPayload(links, 'links'));
193
+ }
194
+ const objectiveMatch = path.match(/^\/api\/foundation\/objectives\/([^/]+)(?:\/(readiness|constraints))?$/);
195
+ if (!objectiveMatch)
196
+ throw new FoundationHttpError(404, 'not_found', 'Route not found');
197
+ const id = decodePathPart(objectiveMatch[1]);
198
+ const suffix = objectiveMatch[2] ?? null;
199
+ const revision = positiveRevision(url.searchParams.get('revision') ?? undefined);
200
+ if (suffix === 'readiness') {
201
+ if (method !== 'GET')
202
+ return methodNotAllowed(['GET']);
203
+ const readiness = await options.objectives.checkObjectiveReadiness(id, input.context, revision);
204
+ return jsonResponse(200, readinessPayload(readiness));
205
+ }
206
+ if (suffix === 'constraints') {
207
+ const objectiveReference = await readObjectiveReference(options, id, revision, input.context);
208
+ if (method === 'GET') {
209
+ if (!options.listObjectiveConstraintRefs)
210
+ throw new FoundationHttpError(501, 'api_unavailable', 'Constraint relation API is not configured');
211
+ return jsonResponse(200, normalizeCollectionPayload(await options.listObjectiveConstraintRefs(objectiveReference, input.context), 'refs'));
212
+ }
213
+ if (method === 'PUT') {
214
+ if (!options.replaceObjectiveConstraintRefs)
215
+ throw new FoundationHttpError(501, 'api_unavailable', 'Constraint relation API is not configured');
216
+ const body = await readJsonBody(request, bodyLimitBytes);
217
+ // Validate the raw envelope before extracting `refs` so an
218
+ // authority field cannot hide beside an otherwise valid collection.
219
+ assertNoAuthorityFields(body);
220
+ const refs = parseConstraintReferences(body);
221
+ const result = await options.replaceObjectiveConstraintRefs(objectiveReference, refs, input.context);
222
+ return jsonResponse(200, { state: 'saved_unverified', reference: objectiveReference, refs: result ?? refs });
223
+ }
224
+ return methodNotAllowed(['GET', 'PUT']);
225
+ }
226
+ if (method === 'GET') {
227
+ const record = await options.objectives.readObjective(id, input.context, revision);
228
+ if (!record)
229
+ throw new FoundationHttpError(404, 'not_found', `Objective ${id} was not found`);
230
+ return jsonResponse(200, { state: 'ready', record, objective: record });
231
+ }
232
+ if (method === 'PUT') {
233
+ const current = await options.objectives.readObjective(id, input.context, revision);
234
+ if (!current || current.definition.type !== 'objective')
235
+ throw new FoundationHttpError(404, 'not_found', `Objective ${id} was not found`);
236
+ const body = await readJsonBody(request, bodyLimitBytes);
237
+ const parsed = parseUpdateBody(body, request);
238
+ const definition = await buildObjectiveDefinition(options, parsed.body, {
239
+ operation: 'update',
240
+ context: input.context,
241
+ current: current.definition,
242
+ expectedRevision: parsed.expectedRevision,
243
+ });
244
+ const reference = await options.objectives.updateObjective(id, parsed.expectedRevision, definition, input.context);
245
+ return jsonResponse(200, { state: 'saved_unverified', reference, ref: reference });
246
+ }
247
+ return methodNotAllowed(['GET', 'PUT']);
248
+ },
249
+ };
250
+ return route;
251
+ }
252
+ async function readObjectiveReference(options, id, revision, context) {
253
+ const record = await options.objectives.readObjective(id, context, revision);
254
+ if (!record || record.definition.type !== 'objective')
255
+ throw new FoundationHttpError(404, 'not_found', `Objective ${id} was not found`);
256
+ return {
257
+ id: record.definition.id,
258
+ type: 'objective',
259
+ revision: record.definition.revision,
260
+ digest: record.digest,
261
+ };
262
+ }
263
+ async function buildObjectiveDefinition(options, payload, input) {
264
+ if (!options.buildDefinition)
265
+ throw new FoundationHttpError(501, 'api_unavailable', 'Objective definition builder is not configured');
266
+ const body = sanitizeMutationBody(payload);
267
+ const definition = await options.buildDefinition({ ...input, body });
268
+ if (!definition || definition.type !== 'objective') {
269
+ throw new FoundationHttpError(400, 'invalid_input', 'Objective builder returned a non-Objective definition');
270
+ }
271
+ if (!definition.id || !definition.revision)
272
+ throw new FoundationHttpError(400, 'invalid_input', 'Objective definition identity is incomplete');
273
+ if (input.operation === 'update') {
274
+ if (!input.current || definition.id !== input.current.id || definition.type !== input.current.type) {
275
+ throw new FoundationHttpError(400, 'invalid_input', 'An Objective update cannot change its logical identity');
276
+ }
277
+ if (JSON.stringify(definition.acl) !== JSON.stringify(input.current.acl)
278
+ || JSON.stringify(definition.scope) !== JSON.stringify(input.current.scope)
279
+ || JSON.stringify(definition.storage) !== JSON.stringify(input.current.storage)
280
+ || JSON.stringify(definition.provenance) !== JSON.stringify(input.current.provenance)
281
+ || JSON.stringify(definition.authorizedUses) !== JSON.stringify(input.current.authorizedUses)) {
282
+ throw new FoundationHttpError(403, 'authority_field_change', 'Objective authority and provenance fields are host-controlled');
283
+ }
284
+ }
285
+ return definition;
286
+ }
287
+ function parseUpdateBody(payload, request) {
288
+ // A PUT may carry a CAS envelope (`{ expectedRevision, definition }`).
289
+ // Check the envelope itself before unwrapping it; otherwise an authority
290
+ // field beside `definition` would be silently ignored by the builder.
291
+ assertNoAuthorityFields(payload);
292
+ const object = asRecord(payload);
293
+ const expectedRevision = positiveRevision(firstString(object, 'expectedRevision', 'expected_revision')
294
+ ?? request.headers.get('if-match')?.replace(/^W\//, '').replace(/^"|"$/g, ''));
295
+ if (!expectedRevision)
296
+ throw new FoundationHttpError(400, 'invalid_input', 'expectedRevision or If-Match is required for a CAS update');
297
+ return { body: object?.definition ?? payload, expectedRevision };
298
+ }
299
+ function sanitizeMutationBody(payload) {
300
+ const object = asRecord(payload);
301
+ if (!object)
302
+ throw new FoundationHttpError(400, 'invalid_input', 'JSON object body is required');
303
+ assertNoAuthorityFields(object);
304
+ const definition = { ...object };
305
+ delete definition.revision;
306
+ delete definition.expectedRevision;
307
+ delete definition.expected_revision;
308
+ if (definition.type !== undefined && definition.type !== 'objective') {
309
+ throw new FoundationHttpError(400, 'invalid_input', 'Objective definition type must be objective');
310
+ }
311
+ return Object.freeze(definition);
312
+ }
313
+ function assertNoAuthorityFields(payload) {
314
+ const object = asRecord(payload);
315
+ if (!object)
316
+ return;
317
+ for (const key of Object.keys(object)) {
318
+ if (AUTHORITY_FIELDS.has(key)) {
319
+ throw new FoundationHttpError(400, 'authority_field_in_body', `Request body cannot set ${key}`);
320
+ }
321
+ }
322
+ }
323
+ function parseConstraintReferences(payload) {
324
+ const object = asRecord(payload);
325
+ const values = Array.isArray(payload) ? payload : object?.refs ?? object?.references;
326
+ if (!Array.isArray(values))
327
+ throw new FoundationHttpError(400, 'invalid_input', 'refs must be an array');
328
+ return values.map((value, index) => {
329
+ const ref = asRecord(value);
330
+ if (!ref || ref.type !== 'constraint' || typeof ref.id !== 'string' || !positiveRevision(ref.revision)) {
331
+ throw new FoundationHttpError(400, 'invalid_input', `refs[${index}] must be a Constraint revision reference`);
332
+ }
333
+ return { id: ref.id, type: 'constraint', revision: ref.revision };
334
+ });
335
+ }
336
+ function readinessPayload(readiness) {
337
+ return { state: 'ready', ready: readiness.ready, issues: readiness.issues };
338
+ }
339
+ function normalizeCollectionPayload(value, key) {
340
+ if (Array.isArray(value))
341
+ return { state: value.length ? 'ready' : 'empty', [key]: value, absence_confirmed: true };
342
+ const object = asRecord(value);
343
+ if (object && Object.prototype.hasOwnProperty.call(object, key) && Array.isArray(object[key])) {
344
+ return {
345
+ ...object,
346
+ [key]: object[key],
347
+ // A collection without an explicit absence claim is not a confirmed
348
+ // empty result. Preserve false/unknown instead of inventing true.
349
+ absence_confirmed: object.absence_confirmed === true,
350
+ };
351
+ }
352
+ throw new FoundationHttpError(500, 'readback_mismatch', `The ${key} adapter returned an invalid collection`);
353
+ }
354
+ function methodNotAllowed(allow) {
355
+ return jsonResponse(405, { error: { code: 'method_not_allowed', message: 'Method not allowed' } }, { Allow: allow.join(', ') });
356
+ }
357
+ function errorResponse(error) {
358
+ const normalized = normalizeHttpError(error);
359
+ const body = {
360
+ error: {
361
+ code: normalized.code,
362
+ message: normalized.message,
363
+ ...(normalized.currentRevision ? { currentRevision: normalized.currentRevision } : {}),
364
+ },
365
+ };
366
+ return jsonResponse(normalized.status, body);
367
+ }
368
+ function normalizeHttpError(error) {
369
+ if (error instanceof FoundationHttpError)
370
+ return error;
371
+ if (error instanceof FoundationStoreError) {
372
+ const status = error.code === 'authorization_denied' || error.code === 'scope_violation' ? 403
373
+ : error.code === 'not_found' ? 404
374
+ : error.code === 'revision_conflict' ? 409
375
+ : error.code === 'unsupported_graph' ? 503
376
+ : error.code === 'readback_mismatch' ? 500
377
+ : 400;
378
+ return new FoundationHttpError(status, error.code, error.message, { currentRevision: error.currentRevision });
379
+ }
380
+ if (error instanceof Error && error.name === 'FoundationHttpError') {
381
+ return new FoundationHttpError(500, 'internal_error', error.message);
382
+ }
383
+ return new FoundationHttpError(500, 'internal_error', 'Foundation request failed');
384
+ }
385
+ function jsonResponse(status, body, headers = {}) {
386
+ return new Response(JSON.stringify(body), {
387
+ status,
388
+ headers: {
389
+ 'Content-Type': 'application/json; charset=utf-8',
390
+ ...headers,
391
+ },
392
+ });
393
+ }
394
+ async function readJsonBody(request, limitBytes) {
395
+ const contentLength = Number(request.headers.get('content-length'));
396
+ if (Number.isFinite(contentLength) && contentLength > limitBytes) {
397
+ throw new FoundationHttpError(413, 'body_too_large', 'Request body exceeds the configured limit');
398
+ }
399
+ const text = await request.text();
400
+ if (!text)
401
+ throw new FoundationHttpError(400, 'invalid_json', 'A JSON body is required');
402
+ if (new TextEncoder().encode(text).byteLength > limitBytes) {
403
+ throw new FoundationHttpError(413, 'body_too_large', 'Request body exceeds the configured limit');
404
+ }
405
+ try {
406
+ return JSON.parse(text);
407
+ }
408
+ catch {
409
+ throw new FoundationHttpError(400, 'invalid_json', 'Request body is not valid JSON');
410
+ }
411
+ }
412
+ function requestUrl(request) {
413
+ return new URL(request.url, 'http://localhost');
414
+ }
415
+ function decodePathPart(value) {
416
+ try {
417
+ const decoded = decodeURIComponent(value);
418
+ if (!decoded)
419
+ throw new Error('empty');
420
+ return decoded;
421
+ }
422
+ catch {
423
+ throw new FoundationHttpError(400, 'invalid_input', 'Path identifier is not valid');
424
+ }
425
+ }
426
+ function positiveRevision(value) {
427
+ return typeof value === 'string' && /^[1-9]\d*$/.test(value) ? value : undefined;
428
+ }
429
+ function asRecord(value) {
430
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
431
+ }
432
+ function firstString(value, ...keys) {
433
+ if (!value)
434
+ return undefined;
435
+ for (const key of keys)
436
+ if (typeof value[key] === 'string')
437
+ return value[key];
438
+ return undefined;
439
+ }
@@ -0,0 +1,140 @@
1
+ import { type PhilosophyRevisionReader } from './philosophy-revision-reader.js';
2
+ import type { FoundationRevisionStore, FoundationStoreContext } from './foundation-store.js';
3
+ import { type JudgmentProblemReferenceProvider } from './judgment-problem-snapshot.js';
4
+ import type { FoundationHttpRoute } from './foundation-http.js';
5
+ export declare const FOUNDATION_PUBLIC_CONTRACT_VERSION: "foundation-public.v1";
6
+ /** The host owns canonical storage and authentication. No body can supply either. */
7
+ export declare function createFoundationPublicProvider(options: {
8
+ store: Pick<FoundationRevisionStore, 'read'>;
9
+ philosophyReader?: PhilosophyRevisionReader;
10
+ /** Canonical Observation/authority/etc. ports; cannot override Foundation or philosophy. */
11
+ resolveOther?: JudgmentProblemReferenceProvider['resolve'];
12
+ }): {
13
+ describe(): {
14
+ contractVersion: "foundation-public.v1";
15
+ foundation: import("./ontology-foundation.js").JudgmentFoundationContract;
16
+ connection: string;
17
+ storage: string;
18
+ philosophy: {
19
+ kind: string;
20
+ canonicalSource: string;
21
+ connected: boolean;
22
+ immutableRevisionRequired: boolean;
23
+ };
24
+ historicalRead: string;
25
+ executionPermission: string;
26
+ };
27
+ read(raw: unknown, context: FoundationStoreContext): Promise<import("./types.js").FoundationCatalogRecord | import("./philosophy-revision-reader.js").PhilosophyRevisionRecord>;
28
+ validate(raw: unknown, context: FoundationStoreContext): Promise<import("./judgment-problem-snapshot.js").JudgmentProblemReferenceResolution>;
29
+ validateProblem(raw: unknown, context: FoundationStoreContext): Promise<{
30
+ status: "resolved";
31
+ executionPermission: "none";
32
+ }>;
33
+ };
34
+ export type FoundationPublicProvider = ReturnType<typeof createFoundationPublicProvider>;
35
+ export interface FoundationPublicConnection {
36
+ provider: FoundationPublicProvider;
37
+ resolveContext(): FoundationStoreContext | null | Promise<FoundationStoreContext | null>;
38
+ }
39
+ export declare const foundationPublicToolDefinitions: readonly [{
40
+ readonly name: "foundation_describe";
41
+ readonly description: "Describe the connected versioned judgment foundation contract.";
42
+ readonly inputSchema: {
43
+ readonly type: "object";
44
+ readonly properties: {};
45
+ readonly additionalProperties: false;
46
+ };
47
+ }, {
48
+ readonly name: "foundation_read";
49
+ readonly description: "Read an exact canonical foundation revision under current access rights.";
50
+ readonly inputSchema: {
51
+ readonly type: "object";
52
+ readonly required: readonly ["type", "id", "revision"];
53
+ readonly additionalProperties: false;
54
+ readonly properties: {
55
+ readonly type: {
56
+ readonly type: "string";
57
+ readonly enum: readonly ["objective", "variable", "model", "constraint", "philosophy"];
58
+ };
59
+ readonly id: {
60
+ readonly type: "string";
61
+ };
62
+ readonly revision: {
63
+ readonly type: "string";
64
+ };
65
+ readonly digest: {
66
+ readonly type: "string";
67
+ };
68
+ };
69
+ };
70
+ }, {
71
+ readonly name: "foundation_validate_reference";
72
+ readonly description: "Validate an exact foundation or philosophy reference for judgment, including its dependencies.";
73
+ readonly inputSchema: {
74
+ readonly type: "object";
75
+ readonly required: readonly ["reference"];
76
+ readonly additionalProperties: false;
77
+ readonly properties: {
78
+ readonly reference: {
79
+ readonly type: "object";
80
+ readonly required: readonly ["kind", "id", "revision", "digest", "scope", "valid_from"];
81
+ readonly additionalProperties: false;
82
+ readonly properties: {
83
+ readonly kind: {
84
+ readonly type: "string";
85
+ readonly enum: readonly ["objective", "variable", "model", "constraint", "philosophy"];
86
+ };
87
+ readonly id: {
88
+ readonly type: "string";
89
+ };
90
+ readonly revision: {
91
+ readonly type: "string";
92
+ };
93
+ readonly digest: {
94
+ readonly type: "string";
95
+ };
96
+ readonly scope: {
97
+ readonly type: "object";
98
+ readonly required: readonly ["type", "id"];
99
+ readonly additionalProperties: false;
100
+ readonly properties: {
101
+ readonly type: {
102
+ readonly type: "string";
103
+ readonly enum: readonly ["personal", "project", "organization"];
104
+ };
105
+ readonly id: {
106
+ readonly type: "string";
107
+ };
108
+ };
109
+ };
110
+ readonly valid_from: {
111
+ readonly type: "string";
112
+ };
113
+ readonly valid_to: {
114
+ readonly type: readonly ["string", "null"];
115
+ };
116
+ };
117
+ };
118
+ readonly phase: {
119
+ readonly type: "string";
120
+ readonly enum: readonly ["read", "historical_read"];
121
+ };
122
+ };
123
+ };
124
+ }, {
125
+ readonly name: "foundation_validate_problem";
126
+ readonly description: "Validate a complete judgment snapshot and canonical observation measurement conditions. Grants no execution permission.";
127
+ readonly inputSchema: {
128
+ readonly type: "object";
129
+ readonly required: readonly ["snapshot"];
130
+ readonly properties: {
131
+ readonly snapshot: {
132
+ readonly type: "object";
133
+ };
134
+ };
135
+ readonly additionalProperties: false;
136
+ };
137
+ }];
138
+ export declare function callFoundationPublicTool(name: string, args: unknown, connection?: FoundationPublicConnection): Promise<unknown>;
139
+ /** Mounted with createFoundationHttpRouter, whose host resolves auth and CSRF. */
140
+ export declare function createFoundationPublicRoute(provider: FoundationPublicProvider): FoundationHttpRoute;